Bus IO Programming Example
The following code fragment illustrates the Bus I/O calls in a PCI driver.
/*++
*
* Copyright (c) 1996-2008. IntervalZero, Inc. All rights reserved.
*
* Module Name:
* RtxLevelIntTest.c
*
* Abstract:
* Test code for processing level triggered interrupts
* using the PCI-DIO-96 card. Developed from the pci test
* and gmpt driver.
*
* Author:
*
* Environment:
*
* RTX RTSS application
*
* Revision History:
* Version 1 Jun 1 1998
--*/
#include <windows.h>
#include <stdio.h>
#include <rtapi.h>
//
// Get and Set Long value macros.
//
#define PTL(x) (*(PLONG)(x))
/* DO NOT CHANGE PARAMETERS BELOW THIS POINT */
#define BASE_ADDR _base_addr
/* PPI A */
#define PORTA_ADDR ((PUCHAR) BASE_ADDR + 0x00) // Port A (Port 0)
#define PORTB_ADDR ((PUCHAR) BASE_ADDR + 0x01) // Port B (Port 1)
#define PORTC_ADDR ((PUCHAR) BASE_ADDR + 0x02) // Port C (Port 2)
#define CNFG_ADDR ((PUCHAR) BASE_ADDR + 0x03) // Config Register
/* PPI B */
#define B_PORTA_ADDR ((PUCHAR) BASE_ADDR + 0x04) // PPI B Port A (Port 3)
#define B_PORTB_ADDR ((PUCHAR) BASE_ADDR + 0x05) // PPI B Port B (Port 4)
#define B_PORTC_ADDR ((PUCHAR) BASE_ADDR + 0x06) // PPI B Port C (Port 5)
#define B_CNFG_ADDR ((PUCHAR) BASE_ADDR + 0x07) // PPI B Config Port
/* PPI C */
#define C_PORTA_ADDR ((PUCHAR) BASE_ADDR + 0x08) // PPI C Port A (Port 6)
#define C_PORTB_ADDR ((PUCHAR) BASE_ADDR + 0x09) // PPI C Port B (Port 7)
#define C_PORTC_ADDR ((PUCHAR) BASE_ADDR + 0x0A) // PPI C Port C (Port 8)
#define C_CNFG_ADDR ((PUCHAR) BASE_ADDR + 0x0B) // PPI C Config Port
/* PPI D */
#define D_PORTA_ADDR ((PUCHAR) BASE_ADDR + 0x0C) // PPI D Port A (Port 9)
#define D_PORTB_ADDR ((PUCHAR) BASE_ADDR + 0x0D) // PPI D Port B (Port 10)
#define D_PORTC_ADDR ((PUCHAR) BASE_ADDR + 0x0E) // PPI D Port C (Port 11)
#define D_CNFG_ADDR ((PUCHAR) BASE_ADDR + 0x0F) // PPI D Config Port
/* Counter/Timer */
#define CLOCKA ((PUCHAR) BASE_ADDR + 0x10) // Clock or Counter 0
#define CLOCKB ((PUCHAR) BASE_ADDR + 0x11) // Clock or Counter 1
#define CLOCKC ((PUCHAR) BASE_ADDR + 0x12) // Clock or Counter 2
#define CLOCK_CTRL ((PUCHAR) BASE_ADDR + 0x13) // Clock or Counter Control
/* Interrupt control */
#define INTR_CTRL1 ((PUCHAR) BASE_ADDR + 0x14) // First interrupt control reg
#define INTR_CTRL2 ((PUCHAR) BASE_ADDR + 0x15) // Second interrupt control reg
#define INTR_CLEAR ((PUCHAR) BASE_ADDR + 0x16) // Interrupt Clear Register
//#define CNFG_VAL 0x80 // 1000 0000 - Port A Output Port B Output Port C Output
//#define CNFG_VAL 0x90 // p 6-10 - Port A Input Port B Output Port C Output
#define CNFG_VAL 0x15 // p 6-10 - Port A Input Port B Input Port C Input
// Note: Standard RTX time units are 100 ns long, or 10 units per microsecond.
#define STOP_TIME 5 // Minutes for shutdown handler to wait
// after stopping before terminating.
// 0 for indefinite.
#define BASE_ADDR _base_addr
/* respond: the interrupt handler */
void _stdcall respond(PVOID addr);
/* fail: utility routine for fatal errors. */
void fail(char *mesg);
/* shutdownh: the shutdown handler */
void _stdcall shutdownh(PVOID dummy, long cause);
PCHAR _base_addr;
PCI_SLOT_NUMBER SlotNumber;
PPCI_COMMON_CONFIG PciData;
UCHAR buffer[PCI_COMMON_HDR_LENGTH];
ULONG IntCountDown; // number of ints calls wait for clearing
ULONG IntCountTotal; // total int count
ULONG IntCountCLear; // total int cleared
BOOLEAN IntDone; // when we are done
void
main( int argc, PCHAR *argv )
{
ULONG i; // logical slot number for the PCI adapter
ULONG f; // function number on the specified adapter
ULONG bytesWritten; // return value from RtGetBusDataByOffset
ULONG bus; // bus number
BOOLEAN flag;
LARGE_INTEGER BAR0; // base port address of the MITE
LARGE_INTEGER BAR1; // base port address of the board registers
LARGE_INTEGER tBAR0, tBAR1; // translated base addresses (system
// mapped addresses) returned by RtMapMemory
ULONG AddressSpace = 0; // indicates memory space
ULONG window_data_value = 0; // not really needed...
PCHAR vBAR0=NULL, vBAR1 = NULL; // pointer virtual memory addresses
// returned by RtMapMemory
ULONG IrqLevel; // interrupt level
ULONG IrqVectr; // interrupt vector
PVOID ihr; // interrupt handler
ULONG intbusnumb; // Interrupt bus number
BAR0.QuadPart = 0;
BAR1.QuadPart = 0;
tBAR0.QuadPart = 0;
tBAR1.QuadPart = 0;
PciData = (PPCI_COMMON_CONFIG) buffer;
SlotNumber.u.bits.Reserved = 0;
flag = TRUE;
//
// Search for the PCI-DIO-96 card
//
for (bus = 0; flag; bus++)
{
for (i = 0; i < PCI_MAX_DEVICES && flag; i++)
{
SlotNumber.u.bits.DeviceNumber = i;
for (f = 0; f < PCI_MAX_FUNCTION; f++)
{
SlotNumber.u.bits.FunctionNumber = f;
bytesWritten = RtGetBusDataByOffset (
PCIConfiguration,
bus,
SlotNumber.u.AsULONG,
PciData,
0,
PCI_COMMON_HDR_LENGTH
);
if (bytesWritten == 0)
{
// out of PCI buses
flag = FALSE;
break;
}
if (PciData->VendorID == PCI_INVALID_VENDORID)
{
// no device at this slot number, skip to next slot
break;
}
//
// A device is found, if this is our card, then
// print out all the PCI configuration information
// and set the variables.
//
if ((PciData->VendorID == 0x1093) && (PciData->DeviceID == 0x0160))
{
// Set IRQ values for attaching interrupt below
IrqLevel = PciData->u.type0.InterruptLine; // interrupt level
IrqVectr = IrqLevel; // interrupt IRQ
// Put the BusAddresses into other variables
BAR0.QuadPart = PciData->u.type0.BaseAddresses[0];
// MITE address
BAR1.QuadPart = PciData->u.type0.BaseAddresses[1];
// new board address
intbusnumb = bus;
printf("\nPCI-DIO-96:\n");
printf("------------------------------------------\n");
printf("BusNumber:\t\t%d\n", bus);
printf("DeviceNumber:\t\t%d\n", i);
printf("FunctionNumber:\t\t%d\n", f);
printf("VendorID:\t\t0x%x\n", PciData->VendorID);
printf("DeviceID:\t\t0x%x\n", PciData->DeviceID);
printf("Command:\t\t0x%x\n", PciData->Command);
printf("Status:\t\t\t0x%x\n", PciData->Status);
printf("RevisionID:\t\t0x%x\n", PciData->RevisionID);
printf("ProgIf:\t\t\t0x%x\n", PciData->ProgIf);
printf("SubClass:\t\t0x%x\n", PciData->SubClass);
printf("BaseClass:\t\t0x%x\n", PciData->BaseClass);
printf("CacheLineSize:\t\t0x%x\n", PciData->CacheLineSize);
printf("LatencyTimer:\t\t0x%x\n", PciData->LatencyTimer);
printf("HeaderType:\t\t0x%x\n",PciData->HeaderType);
printf("BIST:\t\t\t0x%x\n", PciData->BIST);
printf("BaseAddresses[0]:\t0x%08x\n",PciData->u.type0.BaseAddresses[0]);
printf("BaseAddresses[1]:\t0x%08x\n",PciData->u.type0.BaseAddresses[1]);
printf("BaseAddresses[2]:\t0x%08x\n",PciData->u.type0.BaseAddresses[2]);
printf("BaseAddresses[3]:\t0x%08x\n",PciData->u.type0.BaseAddresses[3]);
printf("BaseAddresses[4]:\t0x%08x\n",PciData->u.type0.BaseAddresses[4]);
printf("BaseAddresses[5]:\t0x%08x\n",PciData->u.type0.BaseAddresses[5]);
printf("ROMBaseAddress:\t\t0x%08x\n",PciData->u.type0.ROMBaseAddress);
printf("InterruptLine:\t\t%d\n",PciData->u.type0.InterruptLine);
printf("InterruptPin:\t\t%d\n",PciData->u.type0.InterruptPin);
printf("MinimumGrant:\t\t%d\n",PciData->u.type0.MinimumGrant);
printf("MaximumLatency:\t\t%d\n",PciData->u.type0.MaximumLatency);
printf("\n");
printf(" BAR0: BusRelativeAddress: 0x%08x\n", BAR0.LowPart);
printf(" BAR1: BusRelativeAddress: 0x%08x\n", BAR1.LowPart);
//
// Translate the base port addresses to system mapped addresses.
//
if (! RtTranslateBusAddress(
PCIBus,
0,
BAR0,
&AddressSpace,
&tBAR0
))
{
fail ("tBAR0: RtTranslateBusAddress failed");
}
else
{
printf("tBAR0: SystemMappedAddress: 0x%08x\n", tBAR0.LowPart);
}
if (! RtTranslateBusAddress(PCIBus,
0,
BAR1,
&AddressSpace,
&tBAR1
))
{
fail ("tBAR1: RtTranslateBusAddress failed.");
}
else
{
printf("tBAR1: SystemMappedAddress: 0x%08x\n", tBAR1.LowPart);
}
//
// Map the addresses to virtual addresses the software can use
//
vBAR0=RtMapMemory( tBAR0, 4*1024, MmNonCached); // 4K, cache disabled
if (vBAR0 == 0)
{
printf(" BAR0: Failure on RtMapMemory\nError=%d\n", GetLastError());
}
else
{
printf(" BAR0: VirtualMemoryAddress: 0x%08x\n",vBAR0);
}
vBAR1=RtMapMemory( tBAR1, 4*1024, 0); // 4K, cache disabled
if (!vBAR1)
{
printf(" BAR1: Failure on RtMapMemory\nError=%d\n", GetLastError());
}
else
{
printf(" BAR1: VirtualMemoryAddress: 0x%08x\n", vBAR1);
}
//
// Set the command parameter so we can access the PCI device's
// control registers.
//
PciData->Command = (PCI_ENABLE_IO_SPACE |
PCI_ENABLE_MEMORY_SPACE |
PCI_ENABLE_BUS_MASTER |
PCI_ENABLE_WRITE_AND_INVALIDATE);
RtSetBusDataByOffset(PCIConfiguration,
bus,
SlotNumber.u.AsULONG,
PciData,
0,
PCI_COMMON_HDR_LENGTH);
//
// Initialize the card
// No 1 MB limit - no need to remap the memory.
// Note: You need to use the BusRelativeAddress to set the
// window_data_value.
//
window_data_value = ( (0xffffff00 &
(ULONG)BAR1.LowPart) | (0x00000080) );
PTL(vBAR0+0x000000c0) = window_data_value;
}// dio 96
} // max_function
} // max_devices
} // flag
//
// At this point the card has been found, memory mapped, so we go ahead
// and attempt to utilize the card for testing
//
_base_addr=vBAR1; // Memory already mapped
// Disable interrupts from I/O ports
*(INTR_CTRL1) = 0x00;
// Disable interrupts from counters
*(INTR_CTRL2) = 0x00;
//
// Attempt to attach to this interrupt, using data acquired above
//
ihr = RtAttachInterruptVector(NULL, // security attributes (default)
0, // stacksize (default)
respond, // interrupt handler
NULL, // context argument
RT_PRIORITY_MAX,
PCIBus, // interface type (PCI)
intbusnumb, // bus number
IrqLevel, // interrupt level
IrqVectr); // interrupt vector
}
See Also