You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1224 lines
30 KiB
1224 lines
30 KiB
/*++
|
|
|
|
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);
|
|
}
|