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.
1478 lines
44 KiB
1478 lines
44 KiB
#include "pch.h"
|
|
|
|
BOOL
|
|
SoftPCI_GetSlotPathList(
|
|
IN PPCI_DN Pdn,
|
|
OUT PULONG SlotCount,
|
|
OUT PLIST_ENTRY SlotPathList
|
|
)
|
|
{
|
|
PPCI_DN currentPdn = Pdn;
|
|
PSLOT_PATH_ENTRY currentSlot;
|
|
|
|
while (currentPdn) {
|
|
|
|
currentSlot = calloc(1, sizeof(SLOT_PATH_ENTRY));
|
|
if (currentSlot == NULL) {
|
|
return FALSE;
|
|
}
|
|
currentSlot->Slot.AsUSHORT = currentPdn->Slot.AsUSHORT;
|
|
InsertHeadList(SlotPathList, ¤tSlot->ListEntry);
|
|
(*SlotCount)++;
|
|
currentPdn = currentPdn->Parent;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_DestroySlotPathList(
|
|
PLIST_ENTRY SlotPathList
|
|
)
|
|
{
|
|
|
|
PLIST_ENTRY listEntry;
|
|
PLIST_ENTRY nextEntry;
|
|
PSLOT_PATH_ENTRY currentSlotEntry;
|
|
|
|
listEntry = SlotPathList->Flink;
|
|
while (listEntry != SlotPathList) {
|
|
|
|
nextEntry = listEntry->Flink;
|
|
currentSlotEntry = CONTAINING_RECORD(listEntry,
|
|
SLOT_PATH_ENTRY,
|
|
ListEntry
|
|
);
|
|
free(currentSlotEntry);
|
|
listEntry = nextEntry;
|
|
}
|
|
|
|
InitializeListHead(SlotPathList);
|
|
}
|
|
|
|
BOOL
|
|
SoftPCI_GetDevicePathList(
|
|
IN PPCI_DN Pdn,
|
|
OUT PLIST_ENTRY DevicePathList
|
|
)
|
|
{
|
|
|
|
PPCI_DN currentPdn = Pdn;
|
|
|
|
while (currentPdn) {
|
|
InsertHeadList(DevicePathList, ¤tPdn->ListEntry);
|
|
currentPdn = currentPdn->Parent;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
PWCHAR
|
|
SoftPCI_GetPciPathFromDn(
|
|
IN PPCI_DN Pdn
|
|
)
|
|
{
|
|
|
|
PWCHAR pciPath;
|
|
WCHAR currentSlot[25];
|
|
ULONG pathCount, bufferSize;
|
|
PSLOT_PATH_ENTRY currentSlotEntry;
|
|
LIST_ENTRY slotList;
|
|
PLIST_ENTRY listEntry = NULL;
|
|
|
|
InitializeListHead(&slotList);
|
|
|
|
//
|
|
// First figure out how many parents we have and tag them
|
|
//
|
|
pathCount = 0;
|
|
if (!SoftPCI_GetSlotPathList(Pdn, &pathCount, &slotList)){
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Add in the size of each slot path + size for each "\" and
|
|
// one NULL terminator
|
|
//
|
|
bufferSize = (wcslen(L"XXXX") * pathCount) + pathCount + 1;;
|
|
|
|
//
|
|
// Now convert it to WCHARs
|
|
//
|
|
bufferSize *= sizeof(WCHAR);
|
|
|
|
//
|
|
// Now allocate our path
|
|
//
|
|
pciPath = (PWCHAR) calloc(1, bufferSize);
|
|
|
|
if (pciPath == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// We now have a list that starts with our root. Build out pcipath
|
|
//
|
|
for (listEntry = slotList.Flink;
|
|
listEntry != &slotList;
|
|
listEntry = listEntry->Flink) {
|
|
|
|
currentSlotEntry = CONTAINING_RECORD(listEntry,
|
|
SLOT_PATH_ENTRY,
|
|
ListEntry
|
|
);
|
|
|
|
wsprintf(currentSlot, L"%04x", currentSlotEntry->Slot.AsUSHORT);
|
|
|
|
#if 0
|
|
{
|
|
USHORT testValue = 0;
|
|
testValue = SoftPCIStringToUSHORT(currentSlot);
|
|
SoftPCI_Debug(SoftPciAlways, L"testValue = %04x\n", testValue);
|
|
}
|
|
#endif
|
|
|
|
wcscat(pciPath, currentSlot);
|
|
|
|
if (listEntry->Flink != &slotList) {
|
|
wcscat(pciPath, L"\\");
|
|
}
|
|
}
|
|
|
|
SoftPCI_DestroySlotPathList(&slotList);
|
|
|
|
return pciPath;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SoftPCI_EnumerateDevices(
|
|
IN PPCI_TREE PciTree,
|
|
IN PPCI_DN *Pdn,
|
|
IN DEVNODE Dn,
|
|
IN PPCI_DN Parent
|
|
)
|
|
{
|
|
|
|
PPCI_DN pdn = NULL;
|
|
DEVNODE dnNew = Dn;
|
|
BOOL isValid = FALSE;
|
|
BOOL skipChildEnum;
|
|
HPS_HWINIT_DESCRIPTOR hpData;
|
|
|
|
isValid = SoftPCI_IsDevnodePCIRoot(Dn, TRUE);
|
|
skipChildEnum = FALSE;
|
|
|
|
if (isValid) {
|
|
|
|
SoftPCI_Debug(SoftPciDevice, L"SoftPCI_EnumerateDevices() - Found valid PCI Device!\n");
|
|
|
|
pdn = (PPCI_DN) calloc(1, sizeof(PCI_DN));
|
|
if (!pdn) return;
|
|
*Pdn = pdn;
|
|
pdn->PciTree = PciTree;
|
|
pdn->Parent = Parent;
|
|
pdn->DevNode = Dn;
|
|
SoftPCI_CompletePciDevNode(pdn);
|
|
|
|
//
|
|
// We have special enumeration for hotplug bridges.
|
|
// See if this device supports this special enumeration. If this device
|
|
// doesn't support the required WMI goop to do this, it'll return FALSE
|
|
// and we will fall back to the default enumeration mechanism.
|
|
//
|
|
skipChildEnum = SoftPCI_EnumerateHotplugDevices(PciTree,
|
|
pdn
|
|
);
|
|
}
|
|
|
|
if (!skipChildEnum) {
|
|
|
|
if ((CM_Get_Child(&dnNew, Dn, 0) == CR_SUCCESS)){
|
|
|
|
//
|
|
// Get the next child
|
|
//
|
|
SoftPCI_EnumerateDevices(PciTree,
|
|
(isValid ? &(pdn->Child) : Pdn),
|
|
dnNew,
|
|
pdn
|
|
);
|
|
}
|
|
}
|
|
|
|
if ((CM_Get_Sibling(&dnNew, Dn, 0) == CR_SUCCESS)){
|
|
|
|
//
|
|
// Get the next sibling
|
|
//
|
|
SoftPCI_EnumerateDevices(PciTree,
|
|
(isValid ? &(pdn->Sibling) : Pdn),
|
|
dnNew,
|
|
Parent
|
|
);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_CompletePciDevNode(
|
|
IN PPCI_DN Pdn
|
|
)
|
|
{
|
|
|
|
ULONG bytesReturned = 0;
|
|
DEVNODE childNode = 0;
|
|
PSOFTPCI_DEVICE device = NULL;
|
|
SP_DEVINFO_DATA devInfoData;
|
|
|
|
Pdn->Child = NULL;
|
|
Pdn->Sibling = NULL;
|
|
|
|
if ((CM_Get_Device_ID(Pdn->DevNode, Pdn->DevId, MAX_PATH, 0)) != CR_SUCCESS) {
|
|
|
|
wcscpy(Pdn->DevId, L"Failed to get DevID...");
|
|
SoftPCI_Debug(SoftPciDevice, L"CompletePciDevNode - Failed to retrieve DevID\n");
|
|
}
|
|
|
|
SoftPCI_Debug(SoftPciDevice, L"CompletePciDevNode - DevID - %s\n", Pdn->DevId);
|
|
|
|
SOFTPCI_ASSERT(Pdn->PciTree->DevInfoSet != INVALID_HANDLE_VALUE);
|
|
|
|
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
|
|
if (SetupDiOpenDeviceInfo(Pdn->PciTree->DevInfoSet, Pdn->DevId, NULL, 0, &devInfoData)){
|
|
|
|
if (Pdn->DevNode == devInfoData.DevInst){
|
|
Pdn->DevInfoData = devInfoData;
|
|
}
|
|
}
|
|
|
|
SoftPCI_AllocWmiInstanceName(Pdn->WmiId,
|
|
Pdn->DevId
|
|
);
|
|
|
|
SoftPCI_Debug(SoftPciHotPlug, L"CompletePciDevNode - WmiID - %s\n", Pdn->WmiId);
|
|
|
|
//
|
|
// Now we need to see if this is a root bus as getting its bus number
|
|
// is not quite as easy as a PCI device
|
|
//
|
|
if (SoftPCI_IsDevnodePCIRoot(Pdn->DevNode, FALSE)) {
|
|
|
|
if (!SoftPCI_GetPciRootBusNumber(Pdn->DevNode, &Pdn->Bus)){
|
|
//
|
|
// Not sure what I should do in this case.....should probably disable this device (if a bridge)
|
|
// from allowing devices behind it.....
|
|
//
|
|
}
|
|
|
|
//
|
|
// Setup our root Slot info
|
|
//
|
|
Pdn->Slot.Device = 0xff;
|
|
Pdn->Slot.Function = (UCHAR)Pdn->Bus;
|
|
|
|
}else{
|
|
|
|
if (!SoftPCI_GetBusDevFuncFromDevnode(Pdn->DevNode, &Pdn->Bus, &Pdn->Slot)) {
|
|
//
|
|
// Not sure what I should do in this case.....should probably disable this device (if a bridge)
|
|
// from allowing devices behind it.....
|
|
//
|
|
}
|
|
|
|
}
|
|
|
|
if (!SoftPCI_GetFriendlyNameFromDevNode(Pdn->DevNode, Pdn->FriendlyName)) {
|
|
|
|
//
|
|
// Not sure what I should do in this case.....
|
|
//
|
|
wcscpy(Pdn->FriendlyName, L"Failed to get friendly name...");
|
|
}
|
|
|
|
|
|
if ((Pdn->Parent) &&
|
|
((Pdn->Parent->Bus == Pdn->Bus) &&
|
|
(Pdn->Parent->Slot.AsUSHORT == Pdn->Slot.AsUSHORT))){
|
|
//
|
|
// Our parent (probably a root bus) matches us. We dont want dupes.
|
|
//
|
|
return;
|
|
}
|
|
|
|
if (g_DriverHandle){
|
|
|
|
//
|
|
// Grab any softPCI device information there may be
|
|
//
|
|
device = (PSOFTPCI_DEVICE) calloc(1, sizeof(SOFTPCI_DEVICE));
|
|
|
|
if (device) {
|
|
|
|
device->Bus = (UCHAR)Pdn->Bus;
|
|
device->Slot.AsUSHORT = Pdn->Slot.AsUSHORT;
|
|
|
|
if (!DeviceIoControl(g_DriverHandle,
|
|
(DWORD) SOFTPCI_IOCTL_GET_DEVICE,
|
|
device,
|
|
sizeof(SOFTPCI_DEVICE),
|
|
device,
|
|
sizeof(SOFTPCI_DEVICE),
|
|
&bytesReturned,
|
|
NULL
|
|
)){
|
|
|
|
SoftPCI_Debug(SoftPciDeviceVerbose,
|
|
L"CompletePciDevNode - Failed to get SoftPCI device info (bus %02x dev %02x func %02x)\n",
|
|
Pdn->Bus, Pdn->Slot.Device, Pdn->Slot.Function);
|
|
|
|
free(device);
|
|
|
|
}else{
|
|
Pdn->SoftDev = device;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOL
|
|
SoftPCI_EnumerateHotplugDevices(
|
|
IN PPCI_TREE PciTree,
|
|
IN PPCI_DN Pdn
|
|
)
|
|
{
|
|
HPS_HWINIT_DESCRIPTOR hpData;
|
|
PPCI_DN deviceTable[PCI_MAX_DEVICES];
|
|
PPCI_DN newPdn, currentPdn, slotHeadPdn;
|
|
DEVNODE devNode, childDn;
|
|
UCHAR slotNum, devNum;
|
|
ULONG slotLabelNum, slotsMask;
|
|
CONFIGRET configRet;
|
|
BOOL status, skipChildEnum;
|
|
PSOFTPCI_DEVICE softDevice;
|
|
|
|
if (!SoftPCI_SetEventContext(Pdn)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!SoftPCI_GetHotplugData(Pdn,
|
|
&hpData
|
|
)) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// This device is actually a hotplug controller. Mark it as such for the future.
|
|
//
|
|
Pdn->Flags |= SOFTPCI_HOTPLUG_CONTROLLER;
|
|
SoftPCI_Debug(SoftPciDevice, L"SoftPCI_EnumerateDevices() - Found HOTPLUG PCI Bridge!\n");
|
|
|
|
//SoftPCI_CompleteCommand(Pdn);
|
|
|
|
currentPdn = NULL;
|
|
slotLabelNum = hpData.FirstSlotLabelNumber;
|
|
RtlZeroMemory(deviceTable,sizeof(deviceTable));
|
|
|
|
//
|
|
// First create slot objects for each slot and add them
|
|
// to the tree.
|
|
//
|
|
for (slotNum=0; slotNum < hpData.NumSlots; slotNum++) {
|
|
|
|
devNum = slotNum + hpData.FirstDeviceID;
|
|
|
|
newPdn = (PPCI_DN) calloc(1, sizeof(PCI_DN));
|
|
if (!newPdn) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// For slots, we co-opt the Function field to be
|
|
// the slot number.
|
|
//
|
|
newPdn->Slot.Device = devNum;
|
|
newPdn->Slot.Function = slotNum;
|
|
|
|
newPdn->PciTree = PciTree;
|
|
newPdn->Parent = Pdn;
|
|
newPdn->Flags = SOFTPCI_HOTPLUG_SLOT;
|
|
|
|
if (currentPdn) {
|
|
currentPdn->Sibling = newPdn;
|
|
} else {
|
|
slotHeadPdn = newPdn;
|
|
}
|
|
|
|
wsprintf(newPdn->FriendlyName,L"Slot %d",slotLabelNum);
|
|
RtlZeroMemory(newPdn->WmiId,MAX_PATH);
|
|
|
|
SOFTPCI_ASSERT(devNum < PCI_MAX_DEVICES);
|
|
|
|
//
|
|
// Add this slot to the table that maps slot objects to the
|
|
// PCI device numbers that they correspond to.
|
|
//
|
|
if (devNum < PCI_MAX_DEVICES) {
|
|
|
|
deviceTable[devNum] = newPdn;
|
|
|
|
} else {
|
|
|
|
free(newPdn);
|
|
break;
|
|
}
|
|
|
|
currentPdn = newPdn;
|
|
if (hpData.UpDown) {
|
|
slotLabelNum++;
|
|
|
|
} else {
|
|
slotLabelNum--;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now enumerate all the devices and put them underneath the
|
|
// appropriate slots.
|
|
//
|
|
configRet = CM_Get_Child(&devNode, Pdn->DevNode, 0);
|
|
|
|
while (configRet == CR_SUCCESS){
|
|
|
|
//
|
|
// The controller has a child. Create the PCI_DN for it.
|
|
//
|
|
newPdn = (PPCI_DN) calloc(1, sizeof(PCI_DN));
|
|
if (!newPdn) {
|
|
break;
|
|
}
|
|
|
|
newPdn->PciTree = PciTree;
|
|
newPdn->DevNode = devNode;
|
|
SoftPCI_CompletePciDevNode(newPdn);
|
|
|
|
SOFTPCI_ASSERT(newPdn->Slot.Device < PCI_MAX_DEVICES);
|
|
if (newPdn->Slot.Device < PCI_MAX_DEVICES) {
|
|
//
|
|
// Add this PCI_DN to the tree underneath the
|
|
// slot object for the appropriate slot.
|
|
// If there is no corresponding slot, add it
|
|
// directly underneat the controller.
|
|
//
|
|
if (deviceTable[newPdn->Slot.Device]) {
|
|
SoftPCI_AddChild(deviceTable[newPdn->Slot.Device],
|
|
newPdn
|
|
);
|
|
} else {
|
|
SoftPCI_AddChild(Pdn,
|
|
newPdn
|
|
);
|
|
}
|
|
|
|
skipChildEnum = SoftPCI_EnumerateHotplugDevices(PciTree,
|
|
newPdn
|
|
);
|
|
//
|
|
// We've done the hotplug specific enumeration.
|
|
// If there are more devices underneath this one
|
|
// (there is a bridge in the hotplug slot), return
|
|
// to the default enumeration
|
|
//
|
|
if (!skipChildEnum &&
|
|
(CM_Get_Child(&childDn,devNode,0) == CR_SUCCESS)) {
|
|
SoftPCI_EnumerateDevices(PciTree,
|
|
&newPdn->Child,
|
|
childDn,
|
|
newPdn
|
|
);
|
|
}
|
|
} else {
|
|
|
|
free(newPdn);
|
|
}
|
|
|
|
//
|
|
// After enumerating the first child of the controller, get the
|
|
// rest of the devices by getting the first child's sibling.
|
|
//
|
|
configRet = CM_Get_Sibling(&devNode, devNode, 0);
|
|
}
|
|
|
|
//
|
|
// Next run through all the slots again and if they don't have real
|
|
// children, call GetDevice to get the unenumerated device from hpsim.
|
|
//
|
|
for (slotNum=0; slotNum < hpData.NumSlots; slotNum++) {
|
|
devNum = slotNum + hpData.FirstDeviceID;
|
|
if (deviceTable[devNum] && !deviceTable[devNum]->Child) {
|
|
|
|
softDevice = (PSOFTPCI_DEVICE)malloc(sizeof(SOFTPCI_DEVICE));
|
|
if (!softDevice) {
|
|
|
|
break;
|
|
}
|
|
status = SoftPCI_GetHotplugDevice(Pdn,
|
|
slotNum,
|
|
softDevice
|
|
);
|
|
if (status == FALSE) {
|
|
|
|
SoftPCI_Debug(SoftPciHotPlug, L"EnumerateHotplugDevices - Couldn't get device for slot %d\n", slotNum);
|
|
free(softDevice);
|
|
continue;
|
|
}
|
|
|
|
newPdn = (PPCI_DN) calloc(1, sizeof(PCI_DN));
|
|
if (!newPdn) {
|
|
free(softDevice);
|
|
break;
|
|
}
|
|
|
|
newPdn->PciTree = PciTree;
|
|
newPdn->Parent = deviceTable[devNum];
|
|
newPdn->Bus = newPdn->Parent->Bus;
|
|
newPdn->Slot.AsUSHORT = softDevice->Slot.AsUSHORT;
|
|
newPdn->SoftDev = softDevice;
|
|
newPdn->Flags = SOFTPCI_UNENUMERATED_DEVICE;
|
|
|
|
wcscpy(newPdn->FriendlyName, L"Unpowered Device");
|
|
RtlZeroMemory(newPdn->WmiId,MAX_PATH);
|
|
|
|
deviceTable[devNum]->Child = newPdn;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now add the slot objects to the tree, along with whatever's been added
|
|
// beneath them. Do this now so that they show up at the end of the list
|
|
// rather than at the top.
|
|
//
|
|
currentPdn = Pdn->Child;
|
|
|
|
if (currentPdn == NULL) {
|
|
Pdn->Child = slotHeadPdn;
|
|
|
|
} else {
|
|
while (currentPdn->Sibling != NULL) {
|
|
currentPdn = currentPdn->Sibling;
|
|
}
|
|
currentPdn->Sibling = slotHeadPdn;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_BringHotplugDeviceOnline(
|
|
IN PPCI_DN PciDn,
|
|
IN UCHAR SlotNumber
|
|
)
|
|
{
|
|
BOOL status;
|
|
SOFTPCI_DEVICE softDevice;
|
|
|
|
SoftPCI_Debug(SoftPciHotPlug, L"Bringing slot %d online\n", SlotNumber);
|
|
|
|
status = SoftPCI_GetHotplugDevice(PciDn,
|
|
SlotNumber,
|
|
&softDevice
|
|
);
|
|
if (status == FALSE) {
|
|
|
|
SoftPCI_Debug(SoftPciHotPlug, L"Couldn't get device for slot\n");
|
|
return;
|
|
}
|
|
|
|
if (!SoftPCI_CreateDevice(&softDevice,
|
|
1<<softDevice.Slot.Device,
|
|
FALSE
|
|
)){
|
|
SoftPCI_Debug(SoftPciHotPlug, L"Failed to bring device at slot %d online\n", SlotNumber);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_TakeHotplugDeviceOffline(
|
|
IN PPCI_DN PciDn,
|
|
IN UCHAR SlotNumber
|
|
)
|
|
{
|
|
SOFTPCI_DEVICE softDevice;
|
|
BOOL status;
|
|
|
|
SoftPCI_Debug(SoftPciHotPlug, L"Taking slot %d offline\n", SlotNumber);
|
|
|
|
status = SoftPCI_GetHotplugDevice(PciDn,
|
|
SlotNumber,
|
|
&softDevice
|
|
);
|
|
if (status == FALSE) {
|
|
SoftPCI_Debug(SoftPciHotPlug, L"Couldn't get device for slot\n");
|
|
return;
|
|
}
|
|
|
|
status = SoftPCI_DeleteDevice(&softDevice);
|
|
if (status == FALSE) {
|
|
SoftPCI_Debug(SoftPciHotPlug, L"Couldn't delete device\n");
|
|
|
|
} else {
|
|
SoftPCI_Debug(SoftPciHotPlug, L"Slot %d offline\n", SlotNumber);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_AddChild(
|
|
IN PPCI_DN Parent,
|
|
IN PPCI_DN Child
|
|
)
|
|
{
|
|
PPCI_DN sibling;
|
|
|
|
Child->Parent = Parent;
|
|
|
|
if (Parent->Child == NULL) {
|
|
Parent->Child = Child;
|
|
|
|
} else {
|
|
|
|
sibling = Parent->Child;
|
|
while (sibling->Sibling != NULL) {
|
|
sibling = sibling->Sibling;
|
|
}
|
|
sibling->Sibling = Child;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
SoftPCI_IsBridgeDevice(
|
|
IN PPCI_DN Pdn
|
|
)
|
|
{
|
|
// ISSUE: BrandonA - This should probably just be a macro
|
|
if ((Pdn->SoftDev != NULL) &&
|
|
(IS_BRIDGE(Pdn->SoftDev))) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
SoftPCI_IsSoftPCIDevice(
|
|
IN PPCI_DN Pdn
|
|
)
|
|
{
|
|
// ISSUE: BrandonA - This should probably just be a macro
|
|
if ((Pdn->SoftDev) &&
|
|
!(Pdn->SoftDev->Config.PlaceHolder)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
SoftPCI_IsDevnodePCIRoot(
|
|
IN DEVNODE Dn,
|
|
IN BOOL ValidateAll
|
|
)
|
|
{
|
|
|
|
WCHAR devId[MAX_PATH];
|
|
ULONG size = 0;
|
|
PWCHAR p = NULL, idList = NULL, id = NULL;
|
|
|
|
if ((CM_Get_Device_ID(Dn, devId, MAX_PATH, 0))==CR_SUCCESS){
|
|
|
|
if (ValidateAll &&
|
|
((p = wcsstr(devId, L"PCI\\VEN")) != NULL)){
|
|
return TRUE;
|
|
}
|
|
|
|
if ((p = wcsstr(devId, L"PNP0A03")) != NULL){
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check our compat ids as well
|
|
//
|
|
if ((CM_Get_DevNode_Registry_Property(Dn, CM_DRP_COMPATIBLEIDS, NULL, NULL, &size, 0)) == CR_BUFFER_SMALL){
|
|
|
|
idList = (PWCHAR) calloc(1, size);
|
|
|
|
if (!idList) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((CM_Get_DevNode_Registry_Property(Dn,
|
|
CM_DRP_COMPATIBLEIDS,
|
|
NULL,
|
|
idList,
|
|
&size,
|
|
0)) == CR_SUCCESS){
|
|
|
|
|
|
for (id = idList; *id; id+=wcslen(id)+1) {
|
|
|
|
if ((p = wcsstr(id, L"PNP0A03")) != NULL){
|
|
free(idList);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
SoftPCI_UpdateDeviceFriendlyName(
|
|
IN DEVNODE DeviceNode,
|
|
IN PWCHAR NewName
|
|
)
|
|
|
|
{
|
|
|
|
WCHAR friendlyName[MAX_PATH];
|
|
ULONG length = 0;
|
|
|
|
//
|
|
// If we are updating a root bus we append to the current name
|
|
//
|
|
if (wcscmp(NewName, SOFTPCI_BUS_DESC) == 0) {
|
|
|
|
if (!SoftPCI_GetFriendlyNameFromDevNode(DeviceNode, friendlyName)){
|
|
return FALSE;
|
|
}
|
|
|
|
length = (wcslen(friendlyName) + 1) + (wcslen(NewName) + 1);
|
|
|
|
//
|
|
// Make sure there is enough room
|
|
//
|
|
if (length < MAX_PATH) {
|
|
|
|
wcscat(friendlyName, NewName);
|
|
}
|
|
|
|
}else{
|
|
|
|
//
|
|
// Otherwise, we replace the name entirely
|
|
//
|
|
wcscpy(friendlyName, NewName);
|
|
|
|
length = wcslen(friendlyName) + 1;
|
|
}
|
|
|
|
length *= sizeof(WCHAR);
|
|
|
|
if ((CM_Set_DevNode_Registry_Property(DeviceNode,
|
|
CM_DRP_DEVICEDESC,
|
|
(PVOID)friendlyName,
|
|
length,
|
|
0
|
|
)) != CR_SUCCESS){
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
HANDLE
|
|
SoftPCI_OpenHandleToDriver(VOID)
|
|
{
|
|
|
|
HANDLE hFile = NULL;
|
|
BOOL success = TRUE;
|
|
ULONG requiredSize, error;
|
|
HDEVINFO deviceInfoSet;
|
|
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData;
|
|
|
|
|
|
deviceInfoSet = SetupDiGetClassDevs((LPGUID)&GUID_SOFTPCI_INTERFACE,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
|
|
);
|
|
|
|
if (deviceInfoSet == INVALID_HANDLE_VALUE) {
|
|
|
|
SoftPCI_Debug(SoftPciAlways,
|
|
L"OpenHandleToDriver() - SetupDiGetClassDevs failed! Error - \"%s\"\n",
|
|
SoftPCI_GetLastError());
|
|
return NULL;
|
|
}
|
|
|
|
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
|
|
success = SetupDiEnumDeviceInterfaces(deviceInfoSet,
|
|
NULL,
|
|
(LPGUID)&GUID_SOFTPCI_INTERFACE,
|
|
0,
|
|
&deviceInterfaceData
|
|
);
|
|
if (success) {
|
|
|
|
//
|
|
// Call it once to find out how big the buffer needs to be.
|
|
//
|
|
SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
|
|
&deviceInterfaceData,
|
|
NULL,
|
|
0,
|
|
&requiredSize,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Allocate the required size for the buffer
|
|
// and initialize the buffer.
|
|
//
|
|
deviceInterfaceDetailData = malloc(requiredSize);
|
|
|
|
if (deviceInterfaceDetailData) {
|
|
|
|
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
|
|
success = SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
|
|
&deviceInterfaceData,
|
|
deviceInterfaceDetailData,
|
|
requiredSize,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (success) {
|
|
|
|
hFile = CreateFile(deviceInterfaceDetailData->DevicePath,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
|
|
SoftPCI_Debug(SoftPciAlways,
|
|
L"OpenHandleToDriver() - CreateFile failed! Error - \"%s\"\n",
|
|
SoftPCI_GetLastError());
|
|
|
|
SOFTPCI_ASSERT(FALSE);
|
|
|
|
hFile = NULL;
|
|
}
|
|
} else {
|
|
|
|
SoftPCI_Debug(SoftPciAlways,
|
|
L"OpenHandleToDriver() - SetupDiGetDeviceInterfaceDetail() failed! Error - \"%s\"\n",
|
|
SoftPCI_GetLastError());
|
|
|
|
SOFTPCI_ASSERT(FALSE);
|
|
}
|
|
|
|
free(deviceInterfaceDetailData);
|
|
}
|
|
} else {
|
|
|
|
SoftPCI_Debug(SoftPciAlways,
|
|
L"OpenHandleToDriver() - SetupDiEnumDeviceInterfaces() failed! Error - \"%s\"\n",
|
|
SoftPCI_GetLastError());
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
|
|
return hFile;
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_InstallScriptDevices(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG deviceMask;
|
|
PSINGLE_LIST_ENTRY listEntry;
|
|
PSOFTPCI_SCRIPT_DEVICE installDevice;
|
|
|
|
if (g_DriverHandle) {
|
|
|
|
//
|
|
// We have a handle to our driver. Drain our script queue if we have one.
|
|
//
|
|
listEntry = g_NewDeviceList.Next;
|
|
while (listEntry) {
|
|
|
|
installDevice = NULL;
|
|
installDevice = CONTAINING_RECORD(listEntry, SOFTPCI_SCRIPT_DEVICE, ListEntry);
|
|
listEntry = listEntry->Next;
|
|
|
|
deviceMask = (ULONG) -1;
|
|
if (installDevice->SlotSpecified) {
|
|
deviceMask = (1 << installDevice->SoftPciDevice.Slot.Device);
|
|
}
|
|
|
|
if (!SoftPCI_CreateDevice(installDevice,
|
|
deviceMask,
|
|
TRUE)){
|
|
SoftPCI_Debug(SoftPciAlways, L"Failed to install scriptdevice");
|
|
}
|
|
|
|
//
|
|
// We no longer need this memory so free it
|
|
//
|
|
free(installDevice);
|
|
}
|
|
g_NewDeviceList.Next = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
SoftPCI_CreateDevice(
|
|
IN PVOID CreateDevice,
|
|
IN ULONG PossibleDeviceMask,
|
|
IN BOOL ScriptDevice
|
|
)
|
|
{
|
|
|
|
BOOL success = FALSE, status = FALSE;
|
|
ULONG error, bytesReturned, type;
|
|
ULONG newDeviceSize;
|
|
PVOID newDevice;
|
|
PSOFTPCI_SCRIPT_DEVICE scriptDevice;
|
|
PSOFTPCI_SLOT softPciSlot;
|
|
|
|
newDevice = CreateDevice;
|
|
newDeviceSize = sizeof(SOFTPCI_DEVICE);
|
|
scriptDevice = NULL;
|
|
softPciSlot = NULL;
|
|
|
|
if (ScriptDevice) {
|
|
|
|
scriptDevice = (PSOFTPCI_SCRIPT_DEVICE) CreateDevice;
|
|
softPciSlot = &scriptDevice->SoftPciDevice.Slot;
|
|
|
|
if (scriptDevice->ParentPathLength) {
|
|
|
|
SOFTPCI_ASSERT(scriptDevice->ParentPath != NULL);
|
|
newDeviceSize = sizeof(SOFTPCI_SCRIPT_DEVICE) + scriptDevice->ParentPathLength;
|
|
|
|
}else{
|
|
|
|
newDevice = (PVOID)&scriptDevice->SoftPciDevice;
|
|
}
|
|
|
|
}else{
|
|
|
|
softPciSlot = &((PSOFTPCI_DEVICE)CreateDevice)->Slot;
|
|
}
|
|
|
|
softPciSlot->Device = 0;
|
|
bytesReturned = 0;
|
|
while (PossibleDeviceMask != 0) {
|
|
|
|
if (PossibleDeviceMask & 0x1) {
|
|
status = DeviceIoControl(g_DriverHandle,
|
|
(DWORD) SOFTPCI_IOCTL_CREATE_DEVICE,
|
|
newDevice,
|
|
newDeviceSize,
|
|
&success,
|
|
sizeof (BOOLEAN),
|
|
&bytesReturned,
|
|
NULL
|
|
);
|
|
|
|
if ((status == TRUE) ||
|
|
(softPciSlot->Device == PCI_MAX_DEVICES)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
softPciSlot->Device++;
|
|
PossibleDeviceMask >>= 1;
|
|
|
|
}
|
|
|
|
if ((bytesReturned < sizeof(BOOLEAN)) || !status){
|
|
|
|
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
|
|
|
MessageBox(NULL, L"A device exists at the location (slot) specified!", NULL, MB_OK);
|
|
|
|
}else{
|
|
|
|
SoftPCI_Debug(SoftPciAlways, L"CreateDevice - Failed! (%d) - \"%s\"\n",
|
|
GetLastError(),
|
|
SoftPCI_GetLastError());
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SoftPCI_DeleteDevice(
|
|
IN PSOFTPCI_DEVICE Device
|
|
)
|
|
{
|
|
|
|
|
|
BOOL success, status = TRUE;
|
|
ULONG error, bytesReturned;
|
|
|
|
|
|
SOFTPCI_ASSERT((g_DriverHandle != NULL) &&
|
|
(g_DriverHandle != INVALID_HANDLE_VALUE));
|
|
|
|
//
|
|
// Tell our driver to delete the device.
|
|
//
|
|
status = DeviceIoControl(g_DriverHandle,
|
|
(DWORD) SOFTPCI_IOCTL_DELETE_DEVICE,
|
|
Device,
|
|
sizeof(SOFTPCI_DEVICE),
|
|
&success, //ISSUE do I need a result here?
|
|
sizeof (BOOLEAN),
|
|
&bytesReturned,
|
|
NULL
|
|
);
|
|
|
|
if (!success || !status){
|
|
|
|
MessageBox(NULL, L"Failed to delete specified device or one of its children", NULL, MB_OK);
|
|
SoftPCI_Debug(SoftPciAlways, L"DeleteDevice - IOCTL failed! Error - \"%s\"\n",
|
|
SoftPCI_GetLastError());
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
VOID
|
|
SoftPCI_InitializeDevice(
|
|
IN PSOFTPCI_DEVICE Device,
|
|
IN SOFTPCI_DEV_TYPE Type
|
|
)
|
|
{
|
|
|
|
PSOFTPCI_CONFIG config;
|
|
PPCI_COMMON_CONFIG commonConfig;
|
|
|
|
//
|
|
// Set the type of the device
|
|
//
|
|
Device->DevType = Type;
|
|
|
|
config = &Device->Config;
|
|
commonConfig = &config->Current;
|
|
|
|
switch (Type) {
|
|
|
|
case TYPE_DEVICE:
|
|
|
|
commonConfig->VendorID = 0xABCD;
|
|
commonConfig->DeviceID = 0xDCBA;
|
|
//commonConfig->Command = 0;
|
|
commonConfig->Status = 0x0200;
|
|
commonConfig->RevisionID = 0x0;
|
|
//commonConfig->ProgIf = 0x00;
|
|
commonConfig->SubClass = 0x80;
|
|
commonConfig->BaseClass = 0x04;
|
|
commonConfig->CacheLineSize = 0x11;
|
|
commonConfig->LatencyTimer = 0x99;
|
|
commonConfig->HeaderType= 0x80;
|
|
//commonConfig->BIST = 0x0;
|
|
//commonConfig->u.type0.BaseAddresses[0] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[1] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[2] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[3] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[4] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[5] = 0;
|
|
//commonConfig->u.type0.CIS = 0x0;
|
|
commonConfig->u.type0.SubVendorID = 0xABCD;
|
|
commonConfig->u.type0.SubSystemID = 0xDCBA;
|
|
//commonConfig->u.type0.ROMBaseAddress = 0;
|
|
//commonConfig->u.type0.CapabilitiesPtr = 0x0;
|
|
//commonConfig->u.type0.Reserved1[0] = 0x0;
|
|
//commonConfig->u.type0.Reserved1[1] = 0x0;
|
|
//commonConfig->u.type0.Reserved1[2] = 0x0;
|
|
//commonConfig->u.type0.Reserved2 = 0x0;
|
|
//commonConfig->u.type0.InterruptLine = 0xFF;
|
|
//commonConfig->u.type0.InterruptPin = 0;
|
|
//commonConfig->u.type0.MinimumGrant = 0x0;
|
|
//commonConfig->u.type0.MaximumLatency = 0x0;
|
|
|
|
|
|
//
|
|
// Now set the Mask
|
|
//
|
|
commonConfig = &config->Mask;
|
|
|
|
//commonConfig->VendorID = 0;
|
|
//commonConfig->DeviceID = 0;
|
|
commonConfig->Command = 0x143;
|
|
commonConfig->Status = 0x0200;
|
|
//commonConfig->RevisionID = 0x0;
|
|
//commonConfig->ProgIf = 0x00;
|
|
commonConfig->SubClass = 0x80;
|
|
commonConfig->BaseClass = 0x04;
|
|
commonConfig->CacheLineSize = 0xff;
|
|
commonConfig->LatencyTimer = 0xff;
|
|
//commonConfig->HeaderType= 0x80;
|
|
//commonConfig->BIST = 0x0;
|
|
//commonConfig->u.type0.BaseAddresses[0] = 0;//0xffff0000;
|
|
//commonConfig->u.type0.BaseAddresses[1] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[2] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[3] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[4] = 0;
|
|
//commonConfig->u.type0.BaseAddresses[5] = 0;
|
|
//commonConfig->u.type0.CIS = 0x0;
|
|
//commonConfig->u.type0.SubVendorID = 0xABCD;
|
|
//commonConfig->u.type0.SubSystemID = 0xDCBA;
|
|
//commonConfig->u.type0.ROMBaseAddress = 0;
|
|
//commonConfig->u.type0.CapabilitiesPtr = 0x0;
|
|
//commonConfig->u.type0.Reserved1[0] = 0x0;
|
|
//commonConfig->u.type0.Reserved1[1] = 0x0;
|
|
//commonConfig->u.type0.Reserved1[2] = 0x0;
|
|
//commonConfig->u.type0.Reserved2 = 0x0;
|
|
commonConfig->u.type0.InterruptLine = 0xFF;
|
|
//commonConfig->u.type0.InterruptPin = 0;
|
|
//commonConfig->u.type0.MinimumGrant = 0x0;
|
|
//commonConfig->u.type0.MaximumLatency = 0x0;
|
|
break;
|
|
|
|
case TYPE_PCI_BRIDGE:
|
|
case TYPE_HOTPLUG_BRIDGE:
|
|
|
|
if (Type == TYPE_PCI_BRIDGE) {
|
|
commonConfig->VendorID = 0xABCD;
|
|
commonConfig->DeviceID = 0xDCBB;
|
|
|
|
commonConfig->Status = 0x0400;
|
|
}else{
|
|
commonConfig->VendorID = 0xABCD;
|
|
commonConfig->DeviceID = 0xDCBC;
|
|
|
|
commonConfig->Status = 0x0410;
|
|
|
|
commonConfig->u.type1.CapabilitiesPtr = 0x40;
|
|
|
|
commonConfig->DeviceSpecific[0] = 0xc; //CapID
|
|
commonConfig->DeviceSpecific[1] = 0x48; //Next Cap
|
|
|
|
commonConfig->DeviceSpecific[8] = 0xd; //CapID for hwinit
|
|
commonConfig->DeviceSpecific[9] = 0; //Next Cap
|
|
|
|
}
|
|
|
|
commonConfig->Command = 0x80;
|
|
|
|
//commonConfig->RevisionhpsinitOffsetID = 0x0;
|
|
commonConfig->ProgIf = 0x80;
|
|
commonConfig->SubClass = 0x04;
|
|
commonConfig->BaseClass = 0x06;
|
|
commonConfig->CacheLineSize = 0x8;
|
|
//commonConfig->LatencyTimer = 0x00;
|
|
commonConfig->HeaderType= 0x81;
|
|
//commonConfig->BIST = 0x0;
|
|
//commonConfig->u.type1.BaseAddresses[0] = 0;
|
|
//commonConfig->u.type1.BaseAddresses[1] = 0;
|
|
//commonConfig->u.type1.PrimaryBus = 0x0;
|
|
//commonConfig->u.type1.SecondaryBus = 0x0;
|
|
//commonConfig->u.type1.SubordinateBus = 0x0;
|
|
//commonConfig->u.type1.SecondaryLatency = 0;
|
|
//commonConfig->u.type1.CapabilitiesPtr = 0;
|
|
//commonConfig->u.type1.IOBase = 0;
|
|
//commonConfig->u.type1.IOLimit = 0;
|
|
//commonConfig->u.type1.SecondaryStatus = 0x0;
|
|
//commonConfig->u.type1.MemoryBase = 0x0;
|
|
//commonConfig->u.type1.MemoryLimit = 0;
|
|
//commonConfig->u.type1.PrefetchBase = 0;
|
|
//commonConfig->u.type1.MemoryLimit = 0x0;
|
|
//commonConfig->u.type1.PrefetchBaseUpper32 = 0x0;
|
|
//commonConfig->u.type1.IOBaseUpper16 = 0x0;
|
|
//commonConfig->u.type1.IOLimitUpper16 = 0x0;
|
|
//commonConfig->u.type1.CapabilitiesPtr = 0x0;
|
|
//commonConfig->u.type1.Reserved1[0] = 0x0;
|
|
//commonConfig->u.type1.Reserved1[1] = 0x0;
|
|
//commonConfig->u.type1.Reserved1[2] = 0x0;
|
|
//commonConfig->u.type1.ROMBaseAddress = 0x0;
|
|
//commonConfig->u.type1.InterruptLine = 0x0;
|
|
//commonConfig->u.type1.InterruptPin = 0x0;
|
|
//commonConfig->u.type1.BridgeControl = 0x0;
|
|
|
|
|
|
//
|
|
// Now set the Mask
|
|
//
|
|
commonConfig = &config->Mask;
|
|
|
|
//commonConfig->VendorID = 0x0;
|
|
//commonConfig->DeviceID = 0x0;
|
|
commonConfig->Command = 0xff;
|
|
//commonConfig->Status = 0x0;
|
|
//commonConfig->RevisionID = 0x0;
|
|
//commonConfig->ProgIf = 0x0;
|
|
//commonConfig->SubClass = 0x0;
|
|
//commonConfig->BaseClass = 0x0;
|
|
//commonConfig->CacheLineSize = 0;
|
|
//commonConfig->LatencyTimer = 0;
|
|
//commonConfig->HeaderType= 0;
|
|
//commonConfig->BIST = 0x0;
|
|
//commonConfig->u.type1.BaseAddresses[0] = 0;
|
|
//commonConfig->u.type1.BaseAddresses[1] = 0;
|
|
commonConfig->u.type1.PrimaryBus = 0xff;
|
|
commonConfig->u.type1.SecondaryBus = 0xff;
|
|
commonConfig->u.type1.SubordinateBus = 0xff;
|
|
//commonConfig->u.type1.SecondaryLatency = 0;
|
|
//commonConfig->u.type1.CapabilitiesPtr = 0;
|
|
commonConfig->u.type1.IOBase = 0xf0;
|
|
commonConfig->u.type1.IOLimit = 0xf0;
|
|
//commonConfig->u.type1.SecondaryStatus = 0x0;
|
|
commonConfig->u.type1.MemoryBase = 0xfff0;
|
|
commonConfig->u.type1.MemoryLimit = 0xfff0;
|
|
commonConfig->u.type1.PrefetchBase = 0xfff0;
|
|
commonConfig->u.type1.PrefetchLimit = 0xfff0;
|
|
//commonConfig->u.type1.PrefetchBaseUpper32 = 0xffffffff;
|
|
//commonConfig->u.type1.PrefetchLimitUpper32 = 0xffffffff;
|
|
//commonConfig->u.type1.IOBaseUpper16 = 0;
|
|
//commonConfig->u.type1.IOLimitUpper16 = 0;
|
|
//commonConfig->u.type1.CapabilitiesPtr = 0x0;
|
|
//commonConfig->u.type1.Reserved1[0] = 0x0;
|
|
//commonConfig->u.type1.Reserved1[1] = 0x0;
|
|
//commonConfig->u.type1.Reserved1[2] = 0x0;
|
|
//commonConfig->u.type1.ROMBaseAddress = 0x0;
|
|
//commonConfig->u.type1.InterruptLine = 0x0;
|
|
//commonConfig->u.type1.InterruptPin = 0x0;
|
|
//commonConfig->u.type1.BridgeControl = 0x0;
|
|
|
|
//
|
|
// For a hotplug bridge, the pending byte is not a read/write
|
|
// register, but it has to be in softpci because the hotplug
|
|
// simulator needs to write to it.
|
|
//
|
|
if (Type == TYPE_HOTPLUG_BRIDGE) {
|
|
commonConfig->DeviceSpecific[2] = 0xff; // DWORD Select
|
|
commonConfig->DeviceSpecific[3] = 0xff; // Pending
|
|
commonConfig->DeviceSpecific[4] = 0xff; // Data
|
|
commonConfig->DeviceSpecific[5] = 0xff;
|
|
commonConfig->DeviceSpecific[6] = 0xff;
|
|
commonConfig->DeviceSpecific[7] = 0xff;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Now set our default config
|
|
//
|
|
RtlCopyMemory(&config->Default, &config->Current, sizeof(PCI_COMMON_CONFIG));
|
|
|
|
|
|
}
|
|
|
|
ULONGLONG
|
|
SoftPCI_GetLengthFromBar(
|
|
ULONGLONG BaseAddressRegister
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
STOLEN FROM PCI.SYS and modified to support 64 bit bars
|
|
|
|
Given the contents of a PCI Base Address Register, after it
|
|
has been written with all ones, this routine calculates the
|
|
length (and alignment) requirement for this BAR.
|
|
|
|
This method for determining requirements is described in
|
|
section 6.2.5.1 of the PCI Specification (Rev 2.1).
|
|
|
|
Arguments:
|
|
|
|
BaseAddressRegister contains something.
|
|
|
|
Return Value:
|
|
|
|
Returns the length of the resource requirement. This will be a number
|
|
in the range 0 thru 0x80000000 (0 thru 0x8000000000000000 on 64bit bar).
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONGLONG Length;
|
|
|
|
//
|
|
// A number of least significant bits should be ignored in the
|
|
// determination of the length. These are flag bits, the number
|
|
// of bits is dependent on the type of the resource.
|
|
//
|
|
|
|
if (BaseAddressRegister & PCI_ADDRESS_IO_SPACE) {
|
|
|
|
//
|
|
// PCI IO space.
|
|
//
|
|
BaseAddressRegister &= PCI_ADDRESS_IO_ADDRESS_MASK;
|
|
|
|
} else {
|
|
|
|
//
|
|
// PCI Memory space.
|
|
//
|
|
//BaseAddressRegister &= PCI_ADDRESS_MEMORY_ADDRESS_MASK;
|
|
BaseAddressRegister &= 0xfffffffffffffff0;
|
|
}
|
|
|
|
//
|
|
// BaseAddressRegister now contains the maximum base address
|
|
// this device can reside at and still exist below the top of
|
|
// memory.
|
|
//
|
|
// The value 0xffffffff was written to the BAR. The device will
|
|
// have adjusted this value to the maximum it can really use.
|
|
//
|
|
// Length MUST be a power of 2.
|
|
//
|
|
// For most devices, h/w will simply have cleared bits from the
|
|
// least significant bit positions so that the address 0xffffffff
|
|
// is adjusted to accomodate the length. eg: if the new value is
|
|
// 0xffffff00, the device requires 256 bytes.
|
|
//
|
|
// The difference between the original and new values is the length (-1).
|
|
//
|
|
// For example, if the value fead back from the BAR is 0xffff0000,
|
|
// the length of this resource is
|
|
//
|
|
// 0xffffffff - 0xffff0000 + 1
|
|
// = 0x0000ffff + 1
|
|
// = 0x00010000
|
|
//
|
|
// ie 64KB.
|
|
//
|
|
// Some devices cannot reside at the top of PCI address space. These
|
|
// devices will have adjusted the value such that length bytes are
|
|
// accomodated below the highest address. For example, if a device
|
|
// must reside below 1MB, and occupies 256 bytes, the value will now
|
|
// be 0x000fff00.
|
|
//
|
|
// In the first case, length can be calculated as-
|
|
//
|
|
|
|
|
|
Length = (0xffffffffffffffff - BaseAddressRegister) + 1;
|
|
|
|
if (((Length - 1) & Length) != 0) {
|
|
|
|
//
|
|
// We didn't end up with a power of two, must be the latter
|
|
// case, we will have to scan for it.
|
|
//
|
|
|
|
Length = 4; // start with minimum possible
|
|
|
|
while ((Length | BaseAddressRegister) != BaseAddressRegister) {
|
|
|
|
//
|
|
// Length *= 2, note we will eventually drop out of this
|
|
// loop for one of two reasons (a) because we found the
|
|
// length, or (b) because Length left shifted off the end
|
|
// and became 0.
|
|
//
|
|
|
|
Length <<= 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check that we got something.
|
|
//
|
|
return Length;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SoftPCI_ReadWriteConfigSpace(
|
|
IN PPCI_DN Device,
|
|
IN ULONG Offset,
|
|
IN ULONG Length,
|
|
IN OUT PVOID Buffer,
|
|
IN BOOL WriteConfig
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
This is the function used to send an IOCTL telling the PCIDRV driver to read or write config space.
|
|
|
|
Arguments:
|
|
|
|
Device - device we are going to mess with
|
|
Offset - offset in config space to start at
|
|
Length - length of the read or write
|
|
Buffer - pointer to data to be written, or location to store value read
|
|
WriteConfig - boolean value indicating write if true, or read if false
|
|
|
|
Return Value:
|
|
|
|
TRUE if success
|
|
FALSE if not
|
|
|
|
--*/
|
|
|
|
|
|
BOOL status = FALSE, success = FALSE;
|
|
ULONG bytesReturned = 0;
|
|
SOFTPCI_RW_CONTEXT context;
|
|
|
|
|
|
context.WriteConfig = ((WriteConfig == TRUE) ? SoftPciWriteConfig : SoftPciReadConfig);
|
|
context.Bus = Device->Bus;
|
|
context.Slot.AsUSHORT = Device->Slot.AsUSHORT;
|
|
context.Offset = Offset;
|
|
context.Data = Buffer;
|
|
|
|
|
|
//
|
|
// Call our driver
|
|
//
|
|
status = DeviceIoControl(g_DriverHandle,
|
|
(DWORD) SOFTPCI_IOCTL_RW_CONFIG,
|
|
&context,
|
|
sizeof(SOFTPCI_RW_CONTEXT),
|
|
Buffer,
|
|
Length,
|
|
&bytesReturned,
|
|
NULL
|
|
);
|
|
|
|
if (!status) {
|
|
//
|
|
// Something failed
|
|
//
|
|
wprintf(TEXT("DeviceIoControl() Failed! 0x%x\n"), GetLastError());
|
|
}
|
|
|
|
return status;
|
|
}
|