www.pudn.com > PCIÇý¶¯ÊµÀý.zip > PCI_SAMPLE.C
/////////////////////////////////////////////////////////////////////////////// // // (C) Copyright 1995 - 1997 OSR Open Systems Resources, Inc. // All Rights Reserved // // This sofware is supplied for instructional purposes only. // // OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty // for this software. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY // OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, // THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE. THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS // WITH YOU. OSR's entire liability and your exclusive remedy shall not // exceed the price paid for this material. In no event shall OSR or its // suppliers be liable for any damages whatsoever (including, without // limitation, damages for loss of business profit, business interruption, // loss of business information, or any other pecuniary loss) arising out // of the use or inability to use this software, even if OSR has been // advised of the possibility of such damages. Because some states/ // jurisdictions do not allow the exclusion or limitation of liability for // consequential or incidental damages, the above limitation may not apply // to you. // // OSR Open Systems Resources, Inc. // 105 Route 101A Suite 19 // Amherst, NH 03031 (603) 595-6500 FAX: (603) 595-6503 // email bugs to: bugs@osr.com // // // This driver is the example Busmaster DMA device driver that // accompanies the book Windows NT Device Driver Development, by // Peter Viscarola and W. Anthony Mason, (c) 1998 OSR Open Systems // Resources, Inc. and published by MacMillan Technical Publishing // ISBN 1578700582. // // MODULE: // // PCI_SAMPLE.C // // ABSTRACT: // // This file contains the initial entry point for the OSR Sample // PCI Busmaster DMA device driver for the AMCC 5933 chip. // // AUTHOR(S): // // OSR Open Systems Resources, Inc. // // REVISION: // // V1.1 Fix to typo in OsrWrite() to correctly set cancel // routine to NULL when completing a request that's // been cancelled very early in its processing. // // /////////////////////////////////////////////////////////////////////////////// //#include#include "osr-pci.h" // // Forward Declarations // NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath); static VOID OsrUnload(PDRIVER_OBJECT DriverObject); static VOID OsrReturnPool(PPCI_COMMON_CONFIG configInfo, PDEVICE_DESCRIPTION deviceDescription, PCM_RESOURCE_LIST resources); #if DBG static VOID OsrPrintResourceList(PCM_RESOURCE_LIST); static VOID OsrPrintConfig(PPCI_COMMON_CONFIG configInfo); #endif // // The following pragma allows the DriverEntry code to be discarded once // initialization is completed // #pragma alloc_text(INIT,DriverEntry) /////////////////////////////////////////////////////////////////////////////// // // DriverEntry // // This routine is called by NT when the driver is first loaded. It is the // responsibility of this routine to find it's device and create whatever // device objects it needs. // // INPUTS: // // DriverObj - Address of the DRIVER_OBJECT created by NT for this driver. // // RegistryPath - UNICODE_STRING which represents this drivers KEY in the // Registry. // // OUTPUTS: // // None. // // RETURNS: // // STATUS_SUCCESS. Otherwise an error indicating why the driver could not // Load. // // IRQL: // // This routine is called at IRQL_PASSIVE_LEVEL. // // NOTES: // // /////////////////////////////////////////////////////////////////////////////// NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath) { NTSTATUS code; PPCI_COMMON_CONFIG configInfo = NULL; ULONG busNumber; ULONG deviceNumber; ULONG AddressSpace; PCI_SLOT_NUMBER slotNumber; ULONG length; BOOLEAN moreBuses; BOOLEAN adapterFound; ULONG index; ULONG addressSpace; PHYSICAL_ADDRESS address; POSR_DEVICE_EXT devExt; PDEVICE_OBJECT devObj; UNICODE_STRING devName, linkName; PDEVICE_DESCRIPTION deviceDescription = NULL; PCM_RESOURCE_LIST resources = NULL; ULONG interruptLevel; ULONG interruptVector; ULONG mappedSystemVector; PHYSICAL_ADDRESS portStart; ULONG portLength; KIRQL irql; KAFFINITY affinity; DbgPrint("\nOSR PCI Sample Driver -- Compiled %s %s\n",__DATE__, __TIME__); DbgPrint("(c) 1997 OSR Open Systems Resources, Inc.\n\n"); // // Establish dispatch entry points for the functions we support // DriverObj->MajorFunction[IRP_MJ_CREATE] = OsrCreateClose; DriverObj->MajorFunction[IRP_MJ_CLOSE] = OsrCreateClose; DriverObj->MajorFunction[IRP_MJ_READ] = OsrRead; DriverObj->MajorFunction[IRP_MJ_WRITE] = OsrWrite; DriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = OsrDeviceControl; // // Unload function // DriverObj->DriverUnload = OsrUnload; // // Allocate space for a configuration information structure // configInfo = ExAllocatePoolWithTag(PagedPool, sizeof(PCI_COMMON_CONFIG), 'pRSO'); if (!configInfo) { // // Clean up the mess // OsrReturnPool(configInfo, deviceDescription, resources); // // Indicate load failure to the I/O manager // return(STATUS_INSUFFICIENT_RESOURCES); } // // Search for our device on all the PCI busses in the system // // We do this by ennumerating the configuration information for each // slot on each PCI bus in the system, until we find a device with // our Vendor ID and Device ID. // // Since this sample driver supports only a single card, we stop looking as // soon as we find one device. Drivers that support multiple cards would // ennumerate all the busses and slots, finding as many devices as exist. // // Since our device is not a PCI "multifunction" device, we don't search // each function in each slot. // // adapterFound = FALSE; moreBuses = TRUE; for (busNumber = 0; !adapterFound && moreBuses; busNumber++) { // // Ennumerate all the devices on this bus // for (deviceNumber = 0; !adapterFound && deviceNumber < PCI_MAX_DEVICES; deviceNumber++) { // // For PCI buses, the logical slot number is a PCI_SLOT_NUMBER // structure, comprising a combination of the device number and the // function number on the card. The Reserved section MUST be set // to zero. // // Note that since we're not a multifunction device, we only look // at FunctionNumber 0 in each slot. // slotNumber.u.bits.Reserved = 0; slotNumber.u.bits.DeviceNumber = deviceNumber; slotNumber.u.bits.FunctionNumber = 0; // // Get the configuration space for the adapter in this slot // length = HalGetBusData(PCIConfiguration, busNumber, slotNumber.u.AsULONG, configInfo, sizeof(PCI_COMMON_CONFIG) ); // // A return value of zero indicates no more PCI buses on the system // if (length == 0) { #if DBG DbgPrint("Reached end of PCI bus list\n"); #endif moreBuses = FALSE; break; } // // If there's nothing in this slot, PCI_INVALID_VENDORID is returned // as the vendor ID. If this is the case, just continue running // the bus. // if (configInfo->VendorID == PCI_INVALID_VENDORID) { continue; } // // Dump out information about the device found. // #if DBG DbgPrint("Found a PCI device at Bus %d. Device %d.\n", busNumber, deviceNumber); DbgPrint("Vendor id = 0x%0x, Device id = 0x%0x\n", (int)configInfo->VendorID, (int)configInfo->DeviceID); #endif // DBG // // Is this the PCI device for which we've been searching? It is // if both the vendor and device ID match // if ( (configInfo->VendorID == OSR_PCI_VID) && (configInfo->DeviceID == OSR_PCI_DID) ) { ULONG index; // // FOUND IT! No need to keep searching. We support only // one device. // adapterFound = TRUE; #if DBG DbgPrint("*** Found OUR PCI ADAPTER ***"); // // Just for the sake of interest, let's dump some of the // configuration information for our device. // OsrPrintConfig(configInfo); #endif } } } // // If we didn't find our adapter, we bail out here, thereby aborting // the driver load process. The I/O Manager will delete our driver // object. // if (!adapterFound) { #if DBG DbgPrint("OSR PCI Sample device was not found!? -- EXITING.\n"); #endif // // Clean up the mess // OsrReturnPool(configInfo, deviceDescription, resources); // // Indicate load failure to the I/O manager; driver image is deleted... // return(STATUS_NO_SUCH_DEVICE); } // // *************************************************************** // // Hooray! We've found our device! // // Lets create a device object for it // // // Initialize the UNICODE device name. This will be the "native NT" name // for our device. // RtlInitUnicodeString(&devName, L"\\Device\\OSRPCI"); // // Ask the I/O Manager to create the device object and // device extension // code = IoCreateDevice(DriverObj, sizeof(OSR_DEVICE_EXT), &devName, FILE_DEVICE_OSR, 0, FALSE, &devObj); if(!NT_SUCCESS(code)) { #if DBG DbgPrint("IoCreateDevice failed. Status = 0x%0x\n", code); #endif return(STATUS_UNSUCCESSFUL); } // // Get a pointer to our device extension // devExt = (POSR_DEVICE_EXT)devObj->DeviceExtension; // // Zero out the device extension. While not strictly necessary // (the documentation says the device extension is zeroed) it's // better to be safe. // RtlZeroMemory(devExt, sizeof(OSR_DEVICE_EXT)); // // Save the device object pointer away for future reference // devExt->DeviceObject = devObj; // // Store the bus and slot number away for the device we found // devExt->BusNumber = busNumber-1; devExt->SlotNumber = slotNumber; // // Next, make the device accessible from user-mode applications. // Note that this name can be either the same or different from // the native "kernel mode" name of the device object, given above. // RtlInitUnicodeString(&linkName, L"\\??\\OSRPCI"); code = IoCreateSymbolicLink(&linkName, &devName); if (!NT_SUCCESS(code)) { #if DBG DbgPrint("IoCreateSymbolicLink failed. Status = 0x%x\n", 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); } // // Initialize our IRP queues // InitializeListHead(&devExt->ReadQueue); InitializeListHead(&devExt->WriteQueue); // // Initialize our Spin Locks // KeInitializeSpinLock(&devExt->ReadQueueLock); KeInitializeSpinLock(&devExt->WriteQueueLock); // // Ask the I/O Manager to use describe user read/write buffers using MDLs // devObj->Flags |= DO_DIRECT_IO; // // Next, get the HAL to tell us about the resources the device will use. // These resources include ports, shared memory regions, interrupts, and // the like. The resources will be resevered for us in the registry (so // we do not have to call either IoReportResourceUsage or IoAssignResources). // code = HalAssignSlotResources(RegistryPath, NULL, DriverObj, devObj, PCIBus, devExt->BusNumber, devExt->SlotNumber.u.AsULONG, &resources); // // On return from this call, all resources are identified and assigned for // use by our device. // if (!NT_SUCCESS(code)) { // // log an appropriate error string. // #if DBG DbgPrint("HalAssignSlotResourced failed! Status = 0x%0x", code); #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 } // // Stop the watchdog timer // IoStopTimer(devObj); // // Delete the device object // IoDeleteDevice(devObj); } #if DBG /////////////////////////////////////////////////////////////////////////////// // // OsrPrintConfig // // This routine is called to print out the PCI configuration information for // our device. // // INPUTS: // // configInfo - Address of the PCI_COMMON_CONFIG information for our device. // // OUTPUTS: // // None. // // RETURNS: // // None. // // IRQL: // // This routine is called at IRQL_PASSIVE_LEVEL. // // NOTES: // // We only use this for debugging purposes. // /////////////////////////////////////////////////////////////////////////////// static VOID OsrPrintConfig(PPCI_COMMON_CONFIG configInfo) { ULONG index; DbgPrint("Displaying PCI Configuration Information\n"); DbgPrint("\tRevisionID is 0x%x\n", (int)configInfo->RevisionID); DbgPrint("\tProgIf is 0x%x\n", (int) configInfo->ProgIf); DbgPrint("\tSubClass is 0x%x\n", (int) configInfo->SubClass); DbgPrint("\tBaseClass is 0x%x\n", (int) configInfo->BaseClass); DbgPrint("\tCacheLineSize is 0x%x\n", (int) configInfo->CacheLineSize); DbgPrint("\tLatencyTimer is 0x%x\n", (int) configInfo->LatencyTimer); DbgPrint("\tHeaderType is 0x%x\n", (int) configInfo->HeaderType); DbgPrint("\tBIST is 0x%x\n", (int) configInfo->HeaderType); for (index = 0; index < PCI_TYPE0_ADDRESSES; index++) { DbgPrint("\tBaseAddresses[%d] is 0x%x\n",index, configInfo->u.type0.BaseAddresses[index]); } DbgPrint("\tROMBaseAddress is 0x%x\n", configInfo->u.type0.ROMBaseAddress); DbgPrint("\tInterruptLine is 0x%x\n", configInfo->u.type0.InterruptLine); DbgPrint("\tInterruptPin is 0x%x\n", configInfo->u.type0.InterruptPin); DbgPrint("****************************\n"); } // // Some static string tables we use as part of debugging // static PSTR CmResourceTypeStrings[] = { "CmResourceTypeNull", "CmResourceTypePort", "CmResourceTypeInterrupt", "CmResourceTypeMemory", "CmResourceTypeDma", "CmResourceTypeDeviceSpecific", "CmResourceTypeMaximum" }; static PSTR CmShareDispositionStrings[] = { "CmResourceShareUndetermined", "CmResourceShareDeviceExclusive", "CmResourceShareDriverExclusive", "CmResourceShareShared" }; /////////////////////////////////////////////////////////////////////////////// // // OsrPrintResourceList // // This routine is called to print out the Resource descriptor list containing // the resources allocated for our device by NT. // // INPUTS: // // Resources - Address of the CM_RESOURCE_LIST information for our device. // // OUTPUTS: // // None. // // RETURNS: // // None. // // IRQL: // // This routine is called at IRQL_PASSIVE_LEVEL. // // NOTES: // // We only use this for debugging purposes. // /////////////////////////////////////////////////////////////////////////////// static VOID OsrPrintResourceList(PCM_RESOURCE_LIST Resources) { ULONG index, index2; DbgPrint("%d. resource descriptor list(s) returned\n", Resources->Count); for (index = 0; index < Resources->Count; index++) { DbgPrint("\t[%d] Interface Type 0x%x\n", index, Resources->List[index].InterfaceType); DbgPrint("\t[%d] BusNumber 0x%x\n", index, Resources->List[index].BusNumber); DbgPrint("\t[%d] Version 0x%x\n", index, Resources->List[index].PartialResourceList.Version); DbgPrint("\t[%d] Revision 0x%x\n", index, Resources->List[index].PartialResourceList.Revision); DbgPrint("\t[%d] Partial Resource Descriptors %d.\n", index, Resources->List[index].PartialResourceList.Count); for (index2 = 0; index2 < Resources->List[index].PartialResourceList.Count; index2++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR prd; // Too much to type! prd = &Resources->List[index].PartialResourceList.PartialDescriptors[index2]; DbgPrint("\t\t[%d] Type 0x%x (%s)\n", index2, prd->Type, CmResourceTypeStrings[prd->Type]); DbgPrint("\t\t[%d] Share Disposition 0x%x (%s)\n", index2, prd->ShareDisposition, CmShareDispositionStrings[prd->ShareDisposition]); DbgPrint("\t\t[%d] Flags 0x%x\n", index2, prd->Flags); DbgPrint("\t\t[%d] Raw 0x%x %x %x\n", index2, prd->u.DeviceSpecificData.DataSize, prd->u.DeviceSpecificData.Reserved1, prd->u.DeviceSpecificData.Reserved2); switch (prd->Type) { case CmResourceTypePort: if (prd->Flags == CM_RESOURCE_PORT_MEMORY) DbgPrint("\t\t[%d] port memory starting at 0x%x length 0x%x\n", index2, prd->u.Port.Start.LowPart, prd->u.Port.Length); if (prd->Flags == CM_RESOURCE_PORT_IO) DbgPrint("\t\t[%d] port i/o starting at 0x%x length 0x%x\n", index2, prd->u.Port.Start.LowPart, prd->u.Port.Length); break; case CmResourceTypeInterrupt: if (prd->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) DbgPrint("\t\t[%d] level interrupt at lvl 0x%x vector 0x%x affinity 0x%x\n", index2, prd->u.Interrupt.Level, prd->u.Interrupt.Vector, prd->u.Interrupt.Affinity); if (prd->Flags == CM_RESOURCE_INTERRUPT_LATCHED) DbgPrint("\t\t[%d] latched interrupt at lvl 0x%x vector 0x%x affinity 0x%x\n", index2, prd->u.Interrupt.Level, prd->u.Interrupt.Vector, prd->u.Interrupt.Affinity); break; case CmResourceTypeMemory: if (prd->Flags == CM_RESOURCE_MEMORY_READ_WRITE) DbgPrint("\t\t[%d] r/w memory starting at 0x%x length 0x%x\n", index2, prd->u.Memory.Start.LowPart, prd->u.Memory.Length); if (prd->Flags & CM_RESOURCE_MEMORY_READ_ONLY) DbgPrint("\t\t[%d] r/o memory starting at 0x%x length 0x%x\n", index2, prd->u.Memory.Start.LowPart, prd->u.Memory.Length); if (prd->Flags & CM_RESOURCE_MEMORY_WRITE_ONLY) DbgPrint("\t\t[%d] w/o memory starting at 0x%x length 0x%x\n", index2, prd->u.Memory.Start.LowPart, prd->u.Memory.Length); break; case CmResourceTypeDma: DbgPrint("\t\t[%d] DMA on channel 0x%x\n", index2, prd->u.Dma.Channel); break; case CmResourceTypeDeviceSpecific: DbgPrint("\t\t[%d] Device specific data at 0x%x length 0x%x\n", index2, ((ULONG) &prd->u.DeviceSpecificData.Reserved2) + (ULONG)sizeof(ULONG), prd->u.DeviceSpecificData.DataSize); break; default: // // Say what?!! Unknown resource type. Something is pretty wierd here. // DbgPrint("Unknown resource type 0x%x\n", prd->Type); break; } } DbgPrint("\t[%d] ***** End dump ******\n", index); } } /////////////////////////////////////////////////////////////////////////////// // // OsrPrintIntcsr // // This routine is called to print out a descriptive view of the bits set // in the IntCsr register. // // INPUTS: // // Intcsr - Contents of the IntCsr register. // // OUTPUTS: // // None. // // RETURNS: // // None. // // IRQL: // // This routine is called at IRQL >= IRQL_PASSIVE_LEVEL. // // NOTES: // // We only use this for debugging purposes. It is called by the ISR as well // as by the read and write paths. // /////////////////////////////////////////////////////////////////////////////// VOID OsrPrintIntcsr(ULONG Intcsr) { if(Intcsr & AMCC_INT_OUT_FIFO_CTRL) { DbgPrint("\tOut FIFO Ctrl\n"); } if(Intcsr & AMCC_INT_IN_FIFO_CTRL) { DbgPrint("\tIn FIFO Ctrl\n"); } if(Intcsr & AMCC_INT_FIFO_ADVA_BYTE0) { DbgPrint("\tADVA BYTE0\n"); } if(Intcsr & AMCC_INT_FIFO_ADVA_BYTE1) { DbgPrint("\tADVA BYTE1\n"); } if(Intcsr & AMCC_INT_FIFO_ADVA_BYTE2) { DbgPrint("\tADVA BYTE2\n"); } if(Intcsr & AMCC_INT_FIFO_ADVA_BYTE3) { DbgPrint("\tADVA BYTE3\n"); } if(Intcsr & AMCC_INT_FIFO_ADVP_BYTE0) { DbgPrint("\tADVP BYTE0\n"); } if(Intcsr & AMCC_INT_FIFO_ADVP_BYTE1) { DbgPrint("\tADVP BYTE1\n"); } if(Intcsr & AMCC_INT_FIFO_ADVP_BYTE2) { DbgPrint("\tADVP BYTE2\n"); } if(Intcsr & AMCC_INT_FIFO_ADVP_BYTE3) { DbgPrint("\tADVP BYTE3\n"); } if(Intcsr & AMCC_INT_ENDIAN_16BIT) { DbgPrint("\tENDIAN 16BIT\n"); } if(Intcsr & AMCC_INT_ENDIAN_32BIT) { DbgPrint("\tENDIAN 32BIT\n"); } if(Intcsr & AMCC_INT_ENDIAN_64BIT) { DbgPrint("\tENDIAN 64BIT\n"); } if(Intcsr & AMCC_INT_INTERRUPTED) { DbgPrint("\tINTERRUPTED\n"); } if(Intcsr & AMCC_INT_RESERVED22) { DbgPrint("\tRESERVED 22\n"); } if(Intcsr & AMCC_INT_TARG_ABORT) { DbgPrint("\tTARG_ABORT\n"); } if(Intcsr & AMCC_INT_MAST_ABORT) { DbgPrint("\tMAST_ABORT\n"); } if(Intcsr & AMCC_INT_READ_COMP) { DbgPrint("\tREAD_COMP\n"); } if(Intcsr & AMCC_INT_WRITE_COMP) { DbgPrint("\tWRITE_COMP\n"); } if(Intcsr & AMCC_INT_INMBX_ACK) { DbgPrint("\tINMBX_ACK\n"); } if(Intcsr & AMCC_INT_OUTMBX_ACK) { DbgPrint("\tOUTMBX_ACK\n"); } if(Intcsr & AMCC_INT_INT_ON_READ) { DbgPrint("\tINT_ON_READ\n"); } if(Intcsr & AMCC_INT_INT_ON_WRITE) { DbgPrint("\tINT_ON_WRITE\n"); } if(Intcsr & AMCC_INT_RESERVED13) { DbgPrint("\tRESERVED13\n"); } if(Intcsr & AMCC_INT_ENABLE_OUTMBX_INT) { DbgPrint("\tENABLE_OUTMBX_INT\n"); } if(Intcsr & AMCC_INT_ENABLE_INMBX_INT) { DbgPrint("\tENABLE_INMBX_INT\n"); } } #endif // DBG /////////////////////////////////////////////////////////////////////////////// // // OsrReturnPool // // This routine is called to delete the memory assiged to the Driver for // configInfo, DeviceDescription and Resources. // // INPUTS: // // ConfigInfo - Address of the PCI_COMMON_CONFIG information to delete. // // DeviceDescription - Address of the DEVICE_DESCRIPTION information to delete. // // Resources - Address of the CM_RESOURCE_LIST to delete. // // OUTPUTS: // // None. // // RETURNS: // // None. // // IRQL: // // This routine is called at IRQL >= IRQL_PASSIVE_LEVEL. // // NOTES: // /////////////////////////////////////////////////////////////////////////////// static VOID OsrReturnPool(PPCI_COMMON_CONFIG ConfigInfo, PDEVICE_DESCRIPTION DeviceDescription, PCM_RESOURCE_LIST Resources) { if(ConfigInfo) ExFreePool(ConfigInfo); if(DeviceDescription) ExFreePool(DeviceDescription); if(Resources) ExFreePool(Resources); }