📄 pci_sample.c
字号:
#endif
//
// Clean up the mess
//
OsrReturnPool(configInfo, deviceDescription, resources);
OsrUnload(DriverObj);
//
// Indicate load failure to the I/O manager
//
return(code);
}
#if DBG
//
// For curiosity and debugging purposes, display the resources that were
// allocated for our use.
//
OsrPrintResourceList(resources);
portStart.LowPart = 0;
portLength = 0;
interruptLevel = 0;
interruptVector = 0;
#endif
//
// Decode the returned resources
//
// For our device, we know to expect an interrupt resource, and ONE set
// I/O space port resources. We expect, and we attempt to handle, no
// other resources.
//
for (index = 0; index < resources->Count; index++) {
ULONG index2;
for (index2 = 0;
index2 < resources->List[index].PartialResourceList.Count;
index2++) {
PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
prd = &resources->List[index].PartialResourceList.PartialDescriptors[index2];
switch (prd->Type) {
case CmResourceTypePort:
//
// Our port resources are in I/O space. And our port
// space is 64. bytes long.
//
ASSERT(prd->Flags == CM_RESOURCE_PORT_IO);
ASSERT(prd->u.Port.Length == 64);
portStart.HighPart = 0;
portStart.LowPart = prd->u.Port.Start.LowPart;
portLength = prd->u.Port.Length;
break;
case CmResourceTypeInterrupt:
//
// PCI interrupts are level sensitive
//
ASSERT(prd->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE);
interruptLevel = prd->u.Interrupt.Level;
interruptVector = prd->u.Interrupt.Vector;
break;
#if DBG
case CmResourceTypeMemory:
DbgPrint("...Unexpected memory resource!\n");
break;
case CmResourceTypeDma:
DbgPrint("...Unexpected DMA resource!\n");
break;
case CmResourceTypeDeviceSpecific:
DbgPrint("...Unexpected device specific resource!\n");
break;
#endif
default:
DbgPrint("Unexpected and unknown resource type\n");
break;
}
}
}
//
// We NEED the interrupt info AND one port
//
ASSERT(interruptLevel && interruptVector && portStart.LowPart && portLength);
//
// Indciate that the resigsters are in port space on this card
//
addressSpace = 0x01;
//
// Get the HAL to translate our bus-relative port base address, to an
// unambiguous address to be used for device access. If we're returned
// FALSE, the call failed.
//
if (!HalTranslateBusAddress(PCIBus,
devExt->BusNumber,
portStart,
&addressSpace,
&address)) {
//
// Print an appropriate error string.
//
#if DBG
DbgPrint("HalAssignSlotResourced failed\n");
#endif
//
// Clean up the mess
//
OsrReturnPool(configInfo, deviceDescription, resources);
OsrUnload(DriverObj);
//
//
return(STATUS_UNSUCCESSFUL);
}
//
// If this card's I/O space registers actually appear in memory space on
// this processor, we need to map them with some kernel virtual addresses
// so we can access them. This may be the case on, for example, some RISC
// processors. NOTE HOWEVER, that regardless of the addressSpace returned,
// since the registers on the card are in PORT I/O space, we will ALWAYS
// access them in the driver using WRITE_PORT_xxx and READ_PORT_xxx.
//
if (addressSpace == 0x0) {
ULONG lengthInBytes;
#if DBG
DbgPrint("Address space for port is MEMORY\n");
#endif
lengthInBytes =
resources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Length;
//
// Maps a potentially 64 bit physical address to a 32 bit virtual address.
//
devExt->AmccBaseRegisterAddress = MmMapIoSpace(address,
lengthInBytes,
FALSE);
} else {
ASSERT(addressSpace == 0x01);
#if DBG
DbgPrint("Address space is port\n");
#endif
//
// Port I/O space is only 16 bits long, so we can grab the low 32 bits
// of the address only.
//
devExt->AmccBaseRegisterAddress = (PULONG)address.LowPart;
}
#if DBG
DbgPrint("OSRPCI Registers start at 0x%x", devExt->AmccBaseRegisterAddress);
#endif
//
// Register our DpcforISR routine. This is the routine which will
// be used to complete our interrupt processing.
//
IoInitializeDpcRequest(devObj, OsrDpcForIsr);
//
// Like port and memory addresses, interrupts also have to be "translated"
// from bus-specific values.
//
mappedSystemVector = HalGetInterruptVector(PCIBus,
devExt->BusNumber,
interruptLevel,
interruptVector,
&irql,
&affinity);
#if DBG
DbgPrint("HalGetInterruptVector returned vector 0x%x, IRQL 0x%0x, Affinity 0x%0x\n",
mappedSystemVector,
irql,
affinity);
#endif
//
// Connect to interrupt from the device. After this call,
// interrupts from the device will result in calls to our OsrHandleInterrupt
// function.
//
code = IoConnectInterrupt(&devExt->InterruptObject,
OsrHandleInterrupt,
devExt,
NULL,
mappedSystemVector,
irql,
irql,
LevelSensitive,
TRUE,
affinity,
FALSE);
if (!NT_SUCCESS(code)) {
#if DBG
DbgPrint("IoConnectInterrupt failed with error 0x%x", code);
#endif
//
// Clean up the mess
//
OsrReturnPool(configInfo, deviceDescription, resources);
OsrUnload(DriverObj);
//
// Indicate load failure to the I/O manager; driver image is deleted...
//
return(code);
}
//
// Now we reset the adapter card.
//
OsrResetAdapter(devObj, FALSE);
//
// Finally, we get our adapter objects from the HAL. When we do this,
// we describe out device to the HAL in pretty gory detail. In return,
// he gives us a pointer to our adapter object, and tells us the maximum
// number of mapping registers we should ever use. This is based on
// the maximum transfer size that we support, yet limited by the number
// of available map registers on HALs where real map registers are used.
//
// Note that since this device is capable of performing reads and writes
// in parallel we allocate TWO ADAPTER OBJECTS. We use the same device
// description structure for both, since the device's READ DMA ability is
// identical to its WRITE DMA ability.
//
deviceDescription = ExAllocatePoolWithTag(PagedPool,
sizeof(DEVICE_DESCRIPTION), 'dRSO');
//
// Important: Zero out the entire structure first!
//
RtlZeroMemory(deviceDescription, sizeof(DEVICE_DESCRIPTION));
deviceDescription->Version = DEVICE_DESCRIPTION_VERSION;
deviceDescription->Master = TRUE;
deviceDescription->ScatterGather = FALSE;
deviceDescription->Dma32BitAddresses = TRUE;
deviceDescription->BusNumber = devExt->BusNumber;
deviceDescription->InterfaceType = PCIBus;
//
// Maximum size of transfer that we support on this device.
//
deviceDescription->MaximumLength = OSR_PCI_MAX_TXFER;
devExt->ReadAdapter = HalGetAdapter(deviceDescription, &devExt->ReadMapRegsGot);
if(!devExt->ReadAdapter) {
#if DBG
DbgPrint("HalGetAdapter for READ FAILED!!\n");
#endif
//
// Clean up the mess
//
OsrReturnPool(configInfo, deviceDescription, resources);
OsrUnload(DriverObj);
return(STATUS_UNSUCCESSFUL);
}
#if DBG
DbgPrint("Map Registers got for read = %d.\n", devExt->ReadMapRegsGot);
#endif
//
// Get ANOTHER Adapter Object for use with WRITE transfers
//
devExt->WriteAdapter = HalGetAdapter(deviceDescription, &devExt->WriteMapRegsGot);
if(!devExt->WriteAdapter) {
#if DBG
DbgPrint("HalGetAdapter for WRITE FAILED!!\n");
#endif
//
// Clean up the mess
//
OsrReturnPool(configInfo, deviceDescription, resources);
OsrUnload(DriverObj);
return(STATUS_UNSUCCESSFUL);
}
#if DBG
DbgPrint("Map Registers got for write = %d.\n", devExt->WriteMapRegsGot);
#endif
//
// Initialize the watchdog timer. This timer causes a "soft reset"
// on the device, in a particular direction, if an in-progress IRP
// hangs around too long.
//
IoInitializeTimer(devObj, OsrWatchdogTimer, NULL);
IoStartTimer(devObj);
//
// Return the memory allocated from pool during initialization
//
ExFreePool(configInfo);
ExFreePool(deviceDescription);
//
// Don't forget to free the CM_RESOURCE_LIST structure!
// Even though HalAssignSlotResources(...) allocated it, we're
// responsible for freeing it!!
//
ExFreePool(resources);
#if DBG
DbgPrint("DriverEntry: done\n");
#endif
return(STATUS_SUCCESS);
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrUnload
//
// This routine is our dynamic unload entry point. We are called here when
// the OS wants to unload our driver. It is our responsibility to release any
// resources we allocated.
//
// INPUTS:
//
// DriverObj - Address of our DRIVER_OBJECT.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL_PASSIVE_LEVEL.
//
// NOTES:
//
// No doubt we pool leak at this entry point by not properly returning everything.
//
///////////////////////////////////////////////////////////////////////////////
static VOID
OsrUnload(PDRIVER_OBJECT DriverObject)
{
POSR_DEVICE_EXT devExt;
PDEVICE_OBJECT devObj;
IO_RESOURCE_REQUIREMENTS_LIST reqList;
NTSTATUS code;
UNICODE_STRING linkName;
CM_RESOURCE_LIST returnResources;
BOOLEAN conflictDetected;
#if DBG
DbgPrint("SAMPLE-PCI: UNLOAD called.\n");
#endif
//
// For THIS driver, there will only ever be a single device object.
// Because of this, we just get it from the DriverObj. If this were
// a multiple device driver, we would do this in a while loop...
//
devObj = DriverObject->DeviceObject;
if (!devObj) {
return;
}
devExt= (POSR_DEVICE_EXT)devObj->DeviceExtension;
RtlInitUnicodeString(&linkName, L"\\??\\OSRPCI");
IoDeleteSymbolicLink(&linkName);
//
// Reset the adapter card
//
OsrResetAdapter(devObj, FALSE);
if (devExt->InterruptObject) {
//
// Disconnect the interrupt.
//
IoDisconnectInterrupt(devExt->InterruptObject);
}
//
// Set up a "special" reasource list, that indicates NO RESOURCES.
// This will result in our resouces being returned.
//
returnResources.Count = 0;
code = IoReportResourceUsage(NULL,
DriverObject,
NULL,
0,
devObj,
&returnResources,
sizeof(returnResources),
FALSE,
&conflictDetected);
if(!NT_SUCCESS(code)) {
#if DBG
DbgPrint("UNLOAD: IoReportResourceUsage failed. Status = 0x%0x\n",
code);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -