/*++ Copyright (c) 1999-2000 Microsoft Corporation Module Name: device.c Abstract: This module contains functions for handling Read/Write to Config Space. Author: Nicholas Owens (Nichow) Revision History: BrandonA - Feb. 2000 - Updated to support Read/Write from PCI_COMMON_CONFIG instead of private headers. --*/ #include "pch.h" BOOLEAN SoftPCIValidSlot( IN PSOFTPCI_DEVICE FirstDevice, IN PSOFTPCI_SLOT Slot ); VOID WriteByte( IN PSOFTPCI_DEVICE device, IN ULONG Register, IN UCHAR Data ); VOID WriteByte( IN PSOFTPCI_DEVICE Device, IN ULONG Register, IN UCHAR Data ) { PSOFTPCI_DEVICE child; PUCHAR config; PUCHAR mask; ASSERT(Register < sizeof(PCI_COMMON_CONFIG)); config = (PUCHAR)&Device->Config.Current; mask = (PUCHAR)&Device->Config.Mask; if (Register < sizeof(PCI_COMMON_CONFIG)) { config += Register; mask += Register; // // If we are writing to a SoftPCI-PCI Bridge lets check and see it // it happens to be the SecondaryBusNumber Register. // if (IS_BRIDGE(Device)) { if (Register == (UCHAR) FIELD_OFFSET(PCI_COMMON_CONFIG, u.type1.SecondaryBus)) { SoftPCIDbgPrint( SOFTPCI_BUS_NUM, "SOFTPCI: Assigning DEV_%02x&FUN_%02x Bus #%02x\n", Device->Slot.Device, Device->Slot.Function, Data ); // // If we have children update thier bus numbers as well. // child = Device->Child; while(child){ child->Bus = Data; child = child->Sibling; } } } // // Preserve the read-only bits first // *config &= ~(*mask); // // Verify the bits trying to be written are allowed. // Data &= *mask; // // Update the register with the new value if any // *config |= Data; } } NTSTATUS SoftPCIAddNewDevice( IN PSOFTPCI_DEVICE NewDevice ) /*++ Routine Description: This function is called by SoftPciAddDeviceIoctl when and ADDDEVICE IOCTL is send from our user mode app. Here we create a new SoftPCI device and attach it to our tree. Arguments: DeviceExtension - Device Extension for our BUS 0 (or first root bus) Filter DO. NewDevice - SoftPCI device to create Return Value: NT status. --*/ { NTSTATUS status; PSOFTPCI_DEVICE device; PSOFTPCI_DEVICE currentDevice; KIRQL irql; status = STATUS_UNSUCCESSFUL; // // Allocate some NonPagedPool for our new device // device = ExAllocatePool(NonPagedPool, sizeof(SOFTPCI_DEVICE)); if (device) { RtlZeroMemory(device, sizeof(SOFTPCI_DEVICE)); RtlCopyMemory(device, NewDevice, sizeof(SOFTPCI_DEVICE)); SoftPCIDbgPrint( SOFTPCI_INFO, "SOFTPCI: AddNewDevice - New Device! BUS_%02x&DEV_%02x&FUN_%02x (%p)\n", device->Bus, device->Slot.Device, device->Slot.Function, device ); // // Grab our lock // SoftPCILockDeviceTree(&irql); currentDevice = SoftPciTree.RootDevice; if (currentDevice == NULL) { // // We found our first root bus // SoftPciTree.RootDevice = device; SoftPciTree.DeviceCount++; status = STATUS_SUCCESS; } else { // // Not on bus zero (or fist root bus) so lets see if we can find it. // while(currentDevice){ if (IS_ROOTBUS(device)) { SoftPCIDbgPrint( SOFTPCI_INFO, "SOFTPCI: AddNewDevice - New Device is a PlaceHolder device\n" ); // // A root bus. // while (currentDevice->Sibling) { currentDevice = currentDevice->Sibling; } currentDevice->Sibling = device; SoftPciTree.DeviceCount++; status = STATUS_SUCCESS; break; } // // Don't forget that we pretend that each root bus we have are bridges.... // if (IS_BRIDGE(currentDevice) && currentDevice->Config.Current.u.type1.SecondaryBus == device->Bus) { SoftPCIDbgPrint( SOFTPCI_INFO, "SOFTPCI: AddNewDevice - New Device is on bus 0x%02x\n", currentDevice->Config.Current.u.type1.SecondaryBus ); // // Found it. Update the tree. // device->Sibling = currentDevice->Child; currentDevice->Child = device; device->Parent = currentDevice; device->Child = NULL; SoftPciTree.DeviceCount++; status = STATUS_SUCCESS; break; }else if (IS_BRIDGE(currentDevice) && device->Bus >= currentDevice->Config.Current.u.type1.SecondaryBus && device->Bus <= currentDevice->Config.Current.u.type1.SubordinateBus) { if (currentDevice->Child) { currentDevice = currentDevice->Child; } else { // // There is no device to attach too. // SoftPCIDbgPrint( SOFTPCI_ERROR, "SOFTPCI: AddNewDevice - Failed to find a device to attach to!\n" ); } } else { currentDevice = currentDevice->Sibling; } } } SoftPCIUnlockDeviceTree(irql); } else { status = STATUS_INSUFFICIENT_RESOURCES; } if (!NT_SUCCESS(status)) { SoftPCIDbgPrint( SOFTPCI_ERROR, "SOFTPCI: AddNewDevice - Failed to attach device! status = (0x%x)\n", status ); ExFreePool(device); }else{ // // Cause a rescan of PCI if this is a new fake device // if (!device->Config.PlaceHolder) { SoftPCIEnumerateTree(); } } return status; } NTSTATUS SoftPCIAddNewDeviceByPath( IN PSOFTPCI_SCRIPT_DEVICE ScriptDevice ) /*++ Routine Description: This function is called by SoftPciAddDeviceIoctl when to add a device via a specified PCI device path. Here we create a new SoftPCI device and attach it to our tree. Arguments: ScriptDevice - Contains the device and path used for installing the device Return Value: NT status. --*/ { PSOFTPCI_DEVICE parentDevice; PSOFTPCI_DEVICE currentDevice; PSOFTPCI_DEVICE newDevice; parentDevice = SoftPCIFindDeviceByPath((PWCHAR)&ScriptDevice->ParentPath); if (parentDevice) { SoftPCIDbgPrint( SOFTPCI_ADD_DEVICE, "SOFTPCI: AddNewDeviceByPath - Found parent device! (%p)\n", parentDevice ); // // Found our parent. Allocate a new child // newDevice = ExAllocatePool(NonPagedPool, sizeof(SOFTPCI_DEVICE)); if (!newDevice) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(newDevice, &ScriptDevice->SoftPciDevice, sizeof(SOFTPCI_DEVICE)); newDevice->Parent = parentDevice; newDevice->Bus = parentDevice->Config.Current.u.type1.SecondaryBus; if (parentDevice->Child) { currentDevice = parentDevice->Child; if (SoftPCIRealHardwarePresent(newDevice) || !SoftPCIValidSlot(currentDevice, &newDevice->Slot)) { // // Either real hardware is present or we already have a fake one. // SoftPCIDbgPrint( SOFTPCI_ADD_DEVICE, "SOFTPCI: AddNewDeviceByPath - Cannot add device at specified Slot (%04x)!\n", newDevice->Slot.AsUSHORT ); ExFreePool(newDevice); return STATUS_ACCESS_DENIED; } while (currentDevice->Sibling) { currentDevice = currentDevice->Sibling; } currentDevice->Sibling = newDevice; }else{ parentDevice->Child = newDevice; } SoftPciTree.DeviceCount++; // // New device is in our tree, re-enum // SoftPCIEnumerateTree(); }else{ return STATUS_NO_SUCH_DEVICE; } return STATUS_SUCCESS; } PSOFTPCI_DEVICE SoftPCIFindDevice( IN UCHAR Bus, IN USHORT Slot, OUT PSOFTPCI_DEVICE *PreviousSibling OPTIONAL, IN BOOLEAN ReturnAll ) /*++ Routine Description: This routine searches our tree of SoftPci devices looking for the specified device. It requires that SoftPCILockDeviceTree() has been previously called to lock the device tree. Arguments: Bus - Bus number of device we are searching for Device - Device number of device we are searching for Function - Function of device we are searching for Return Value: Returns the softpci device we are looking for. NULL otherwise. --*/ { PSOFTPCI_DEVICE currentDevice; PSOFTPCI_DEVICE previousDevice; PSOFTPCI_DEVICE deviceFound; SOFTPCI_SLOT slot; currentDevice = SoftPciTree.RootDevice; previousDevice = SoftPciTree.RootDevice;; deviceFound = NULL; slot.AsUSHORT = Slot; SoftPCIDbgPrint( SOFTPCI_FIND_DEVICE, "SOFTPCI: FindDevice - Searching for BUS_%02x&DEV_%02x&FUN_%02x\n", Bus, slot.Device, slot.Function ); while (currentDevice) { SoftPCIDbgPrint( SOFTPCI_FIND_DEVICE, "SOFTPCI: FindDevice - Does %02x.%02x.%02x = %02x.%02x.%02x ?\n", Bus, slot.Device, slot.Function, currentDevice->Bus, currentDevice->Slot.Device, currentDevice->Slot.Function ); if (currentDevice->Bus == Bus && currentDevice->Slot.AsUSHORT == Slot) { // // Found it! Only return it if caller specified ReturnAll // if (!currentDevice->Config.PlaceHolder || ReturnAll) { if (PreviousSibling) { *PreviousSibling = previousDevice; } SoftPCIDbgPrint( SOFTPCI_FIND_DEVICE, "SOFTPCI: FindDevice - Found Device! (0x%p)\n", currentDevice); deviceFound = currentDevice; } break; }else if ((IS_BRIDGE(currentDevice)) && (Bus >= currentDevice->Config.Current.u.type1.SecondaryBus) && (Bus <= currentDevice->Config.Current.u.type1.SubordinateBus)) { SoftPCIDbgPrint( SOFTPCI_FIND_DEVICE, "SOFTPCI: FindDevice - 0x%p exposes bus %02x-%02x\n", currentDevice, currentDevice->Config.Current.u.type1.SecondaryBus, currentDevice->Config.Current.u.type1.SubordinateBus ); if (!(currentDevice->Config.PlaceHolder) && !(currentDevice->Config.Current.u.type1.SecondaryBus) && !(currentDevice->Config.Current.u.type1.SubordinateBus)){ // // We have a bridge but it hasnt been given its bus numbers // yet. Therefore cant have children. // SoftPCIDbgPrint( SOFTPCI_FIND_DEVICE, "SOFTPCI: FindDevice - Skipping unconfigured bridge (0x%p)\n", currentDevice ); previousDevice = currentDevice; currentDevice = currentDevice->Sibling; }else{ // // Our bus is behind this bridge. Keep looking // previousDevice = NULL; currentDevice = currentDevice->Child; } }else{ // // Not a bridge, check our sibling // previousDevice = currentDevice; currentDevice = currentDevice->Sibling; } } return deviceFound; } PSOFTPCI_DEVICE SoftPCIFindDeviceByPath( IN PWCHAR PciPath ) /*++ Routine Description: This function will take a given PCIPATH and return the device located at that path. Arguments: PciPath - Path to device. Syntax is FFXX\DEVFUNC\DEVFUNC\.... Return Value: SoftPCI device located at path --*/ { PWCHAR nextSlotStart; SOFTPCI_SLOT currentSlot; PSOFTPCI_DEVICE currentDevice; currentSlot.AsUSHORT = 0; currentDevice = SoftPciTree.RootDevice; nextSlotStart = PciPath; while (nextSlotStart) { nextSlotStart = SoftPCIGetNextSlotFromPath(nextSlotStart, ¤tSlot); SoftPCIDbgPrint( SOFTPCI_FIND_DEVICE, "SOFTPCI: FindDeviceByPath - nextSlotStart = %ws\n", nextSlotStart ); while(currentDevice){ SoftPCIDbgPrint( SOFTPCI_FIND_DEVICE, "SOFTPCI: FindDeviceByPath - currentDevice.Slot = %04x, currentSlot.Slot = %04x\n", currentDevice->Slot.AsUSHORT, currentSlot.AsUSHORT ); if (currentDevice->Slot.AsUSHORT == currentSlot.AsUSHORT) { // // This device is in our path // if (nextSlotStart && (!(IS_BRIDGE(currentDevice)))){ // // This device is in our path but since it isnt a bridge it // cannot have children! // SoftPCIDbgPrint( SOFTPCI_FIND_DEVICE, "SOFTPCI: FindDeviceByPath - ERROR! Path contains a parent that isnt a bridge!\n" ); return NULL; } if (currentDevice->Child && nextSlotStart) { currentDevice = currentDevice->Child; } break; }else{ // // Not in our path, look at our next sibling // currentDevice = currentDevice->Sibling; } } } #if 0 if (currentDevice) { // // looks like we found it // *TargetDevice = currentDevice; return STATUS_SUCCESS; } #endif return currentDevice; } BOOLEAN SoftPCIRealHardwarePresent( IN PSOFTPCI_DEVICE Device ) /*++ Routine Description: This function does a quick check to see if real hardware exists at the bus/slot specified in the provided SOFTPCI_DEVICE Arguments: Device - Contains the Bus / Slot we want to check for Return Value: TRUE if real hardware is present --*/ { ULONG bytesRead; USHORT vendorID; PCI_SLOT_NUMBER slot; PSOFTPCI_PCIBUS_INTERFACE busInterface; busInterface = SoftPciTree.BusInterface; ASSERT((busInterface->ReadConfig != NULL) || (busInterface->WriteConfig != NULL)); slot.u.AsULONG = 0; slot.u.bits.DeviceNumber = ((ULONG)Device->Slot.Device & 0xff); slot.u.bits.FunctionNumber = ((ULONG)Device->Slot.Function & 0xff); vendorID = 0; bytesRead = busInterface->ReadConfig( busInterface->Context, Device->Bus, slot.u.AsULONG, &vendorID, 0, sizeof(USHORT) ); if (bytesRead == sizeof(USHORT)) { if (vendorID == 0xFFFF || vendorID == 0) { return FALSE; } }else{ ASSERT(FALSE); } // // Play it safe and assume there is hardware present // return TRUE; } NTSTATUS SoftPCIRemoveDevice( IN PSOFTPCI_DEVICE Device ) /*++ Routine Description: This routine is called to remove/delete a specified SoftPCI device Arguments: DeviceExtension - Return Value: Returns a count of bytes written. --*/ { NTSTATUS status = STATUS_SUCCESS; PSOFTPCI_DEVICE device; PSOFTPCI_DEVICE previous; PSOFTPCI_DEVICE current; PSOFTPCI_DEVICE end; KIRQL irql; // // Lock the tree while we remove our device from the tree // SoftPCILockDeviceTree(&irql); previous = NULL; device = SoftPCIFindDevice( Device->Bus, Device->Slot.AsUSHORT, &previous, FALSE ); // // We should never get back our root node // ASSERT(device != SoftPciTree.RootDevice); if (device) { // // We found the device we want to delete. // SoftPCIDbgPrint( SOFTPCI_REMOVE_DEVICE, "SOFTPCI: RemoveDevice - Removing BUS_%02x&DEV_%02x&FUN_%02x and all its children\n", device->Bus, device->Slot.Device, device->Slot.Function ); if (previous){ // // Patch the link between our previous and next if any // previous->Sibling = device->Sibling; }else{ // // Update our parent // device->Parent->Child = device->Sibling; } // // Release the tree lock now that we have severed the link // between the device and the tree // SoftPCIUnlockDeviceTree(irql); if (device->Child) { // // We have at least one child. Traverse and free everything. // current = device; while (current) { // // Find the last Child. // while (current->Child) { previous = current; current=current->Child; } // // We have a sibling. Free our current node and // set the previous parent node's child to our // sibling (if any) and restart the list. // end = current; previous->Child = current->Sibling; current = device; SoftPCIDbgPrint( SOFTPCI_REMOVE_DEVICE, "SOFTPCI: RemoveDevice - Freeing BUS_%02x&DEV_%02x&FUN_%02x\n", end->Bus, end->Slot.Device, end->Slot.Function ); ExFreePool(end); if (device->Child == NULL) { // // All our children are now gone. Free the requested device. // SoftPCIDbgPrint( SOFTPCI_REMOVE_DEVICE, "SOFTPCI: RemoveDevice - Freeing BUS_%02x&DEV_%02x&FUN_%02x\n", device->Bus, device->Slot.Device, device->Slot.Function ); ExFreePool(device); break; } } }else{ // // Cool, no children. Free the device. // SoftPCIDbgPrint( SOFTPCI_REMOVE_DEVICE, "SOFTPCI: RemoveDevice - Freeing BUS_%02x&DEV_%02x&FUN_%02x\n", device->Bus, device->Slot.Device, device->Slot.Function ); ExFreePool(device); } }else{ // // We cant delete one if we dont have one. // SoftPCIDbgPrint( SOFTPCI_REMOVE_DEVICE, "SOFTPCI: RemoveDevice - No device at BUS_%02x&DEV_%02x&FUN_%02x\n", Device->Bus, Device->Slot.Device, Device->Slot.Function ); SoftPCIUnlockDeviceTree(irql); } if (NT_SUCCESS(status)) { SoftPciTree.DeviceCount--; ASSERT(SoftPciTree.DeviceCount != 0); // // If we changed the tree, queue an enum // SoftPCIEnumerateTree(); } return status; } ULONG SoftPCIReadConfigSpace( IN PSOFTPCI_PCIBUS_INTERFACE BusInterface, IN UCHAR BusOffset, IN ULONG Slot, OUT PVOID Buffer, IN ULONG Offset, IN ULONG Length ) /*++ Routine Description: This routine is called by the PCI driver in place of the normal interface call to the HAL. Arguments: BusInterface - Interface contexts we gave PCI during the query for PCI_BUS_INTERFACE_STANDARD. BusOffset - BusOffset provided by PCI Slot - Slot provided by PCI Buffer - Buffer for returned data Offset - Configspace Offset to Read from Length - Length of requested read. Return Value: Returns a count of bytes read.. --*/ { PCI_SLOT_NUMBER slotNum; SOFTPCI_SLOT softSlot; PSOFTPCI_DEVICE device; PSOFTPCI_CONFIG config; ULONG count; PUCHAR softConfig = NULL; KIRQL irql; slotNum.u.AsULONG = Slot; softSlot.Device = (UCHAR) slotNum.u.bits.DeviceNumber; softSlot.Function = (UCHAR) slotNum.u.bits.FunctionNumber; SoftPCILockDeviceTree(&irql); // // First look for a matching fake device // device = SoftPCIFindDevice( BusOffset, softSlot.AsUSHORT, NULL, FALSE ); SoftPCIUnlockDeviceTree(irql); // // If we found a device, then read it's config space. // if (device) { config = &device->Config; SoftPCIDbgPrint(SOFTPCI_INFO, "SOFTPCI: ReadConfig - SoftConfigSpace for VEN_%04x&DEV_%04x, HeaderType = 0x%02x\n", config->Current.VendorID, config->Current.DeviceID, config->Current.HeaderType); ASSERT(Offset <= sizeof(PCI_COMMON_CONFIG)); ASSERT(Length <= (sizeof(PCI_COMMON_CONFIG) - Offset)); softConfig = (PUCHAR) &config->Current; softConfig += (UCHAR)Offset; RtlCopyMemory((PUCHAR)Buffer, softConfig, Length); // // We assume everything copied ok. Set count to Length. // count = Length; } else { // // We don't have a softdevice so see if we have a real one. // count = BusInterface->ReadConfig( BusInterface->Context, BusOffset, Slot, Buffer, Offset, Length ); // // Here we snoop the config space header reads // and if we find a bridge we make sure we have // it in our tree. // if ((Offset == 0) && (Length == PCI_COMMON_HDR_LENGTH) && ((PCI_CONFIGURATION_TYPE((PPCI_COMMON_CONFIG)Buffer)) == PCI_BRIDGE_TYPE)) { // // OK, look one more time, only this time we want placeholders as well // SoftPCILockDeviceTree(&irql); device = SoftPCIFindDevice( BusOffset, softSlot.AsUSHORT, NULL, TRUE ); SoftPCIUnlockDeviceTree(irql); if (!device) { // // This real bridge doesnt exist in our tree, add it. // device = (PSOFTPCI_DEVICE) ExAllocatePool(NonPagedPool, sizeof(SOFTPCI_DEVICE)); if (device) { RtlZeroMemory(device, sizeof(SOFTPCI_DEVICE)); device->Bus = BusOffset; device->Slot.AsUSHORT = softSlot.AsUSHORT; device->Config.PlaceHolder = TRUE; RtlCopyMemory(&device->Config.Current, Buffer, Length); if (!NT_SUCCESS(SoftPCIAddNewDevice(device))){ SoftPCIDbgPrint( SOFTPCI_INFO, "SOFTPCI: ReadConfig - Failed to add new PlaceHolder Device! VEN_%04x&DEV_%04x", device->Config.Current.VendorID, device->Config.Current.DeviceID ); } }else{ SoftPCIDbgPrint( SOFTPCI_INFO, "SOFTPCI: ReadConfig - Failed to allocate memory for new placeholder!\n" ); } } } } return count; } ULONG SoftPCIWriteConfigSpace( IN PSOFTPCI_PCIBUS_INTERFACE BusInterface, IN UCHAR BusOffset, IN ULONG Slot, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length ) /*++ Routine Description: This routine is called by the PCI driver in place of the normal interface call to the HAL. Arguments: Context - Interface contexts we gave PCI during the query for PCI_BUS_INTERFACE_STANDARD. BusOffset - BusOffset provided by PCI Slot - Slot provided by PCI Buffer - Data to be written to configspace Offset - Configspace Offset to start writting Length - Length of requested write. Return Value: Returns a count of bytes written. --*/ { PCI_SLOT_NUMBER slotNum; SOFTPCI_SLOT softSlot; PSOFTPCI_DEVICE device; ULONG count = 0; KIRQL irql; PPCI_COMMON_CONFIG bridgeConfig; PUCHAR bridgeOffset; slotNum.u.AsULONG = Slot; softSlot.Device = (UCHAR) slotNum.u.bits.DeviceNumber; softSlot.Function = (UCHAR) slotNum.u.bits.FunctionNumber; SoftPCILockDeviceTree(&irql); // // First look for a matching fake or placeholder device // device = SoftPCIFindDevice( BusOffset, softSlot.AsUSHORT, NULL, TRUE ); // // If we found a device, then write to it's config space. // if (device && (!device->Config.PlaceHolder)) { ULONG reg; PUCHAR value = (PUCHAR) Buffer; for (reg = Offset; reg < Offset + Length; reg ++) { WriteByte(device, reg, *value); value++; count++; } } else { if (device && (IS_BRIDGE(device))) { ASSERT(device->Config.PlaceHolder == TRUE); // // We have a place holder to update as well as real hardware // bridgeConfig = &device->Config.Current; bridgeOffset = (PUCHAR) bridgeConfig; bridgeOffset += Offset; RtlCopyMemory(bridgeOffset, Buffer, Length); } // // We don't have a softdevice so write to the real one. // count = BusInterface->WriteConfig( BusInterface->Context, BusOffset, Slot, Buffer, Offset, Length ); } SoftPCIUnlockDeviceTree(irql); return count; } BOOLEAN SoftPCIValidSlot( IN PSOFTPCI_DEVICE FirstDevice, IN PSOFTPCI_SLOT Slot ) /*++ Routine Description: This function makes sure that there isnt already a device at the specified Slot Arguments: FirstDevice - First device we will compare against. We will then only check siblings. Return Value: TRUE if the Slot is valid --*/ { PSOFTPCI_DEVICE currentDevice; SOFTPCI_SLOT mfSlot; BOOLEAN mfSlotRequired; BOOLEAN mfSlotFound; RtlZeroMemory(&mfSlot, sizeof(SOFTPCI_SLOT)); mfSlotRequired = FALSE; mfSlotFound = FALSE; if (Slot->Function) { // // We have a multi-function slot. Make sure function 0 // is present or we must fail // mfSlot.AsUSHORT = 0; mfSlot.Device = Slot->Device; mfSlotRequired = TRUE; } currentDevice = FirstDevice; while (currentDevice) { if (currentDevice->Slot.AsUSHORT == mfSlot.AsUSHORT) { mfSlotFound = TRUE; } if (currentDevice->Slot.AsUSHORT == Slot->AsUSHORT) { return FALSE; } currentDevice = currentDevice->Sibling; } if (mfSlotRequired && !mfSlotFound) { // // Didnt find function 0 // SoftPCIDbgPrint( SOFTPCI_ERROR, "SOFTPCI: VerifyValidSlot - Multi-function slot (%04x) without function 0 !\n", Slot->AsUSHORT ); return FALSE; } return TRUE; } VOID SoftPCILockDeviceTree( IN PKIRQL OldIrql ) { KeRaiseIrql(HIGH_LEVEL, OldIrql ); KeAcquireSpinLockAtDpcLevel(&SoftPciTree.TreeLock); } VOID SoftPCIUnlockDeviceTree( IN KIRQL NewIrql ) { KeReleaseSpinLockFromDpcLevel(&SoftPciTree.TreeLock); KeLowerIrql(NewIrql); }