- Add support for PnP IRP to PDO: IRP_MN_QUERY_BUS_INFORMATION (PciQueryBusInformation), IRP_MN_QUERY_ID (PciQueryId), IRP_MN_QUERY_DEVICE_TEXT (PciQueryDeviceText), IRP_MN_QUERY_CAPABILITIES (PciQueryCapabilities), IRP_MN_QUERY_DEVICE_RELATIONS (PciQueryTargetDeviceRelations implement, PciQueryEjectionRelations, stub)

- Stub support for PnP IRP to PDO: IRP_MN_QUERY_RESOURCE_REQUIREMENTS (PciQueryRequirements), IRP_MN_QUERY_RESOURCES(PciQueryResources)
- Add support for PnP IRP to FDO: IRP_MN_QUERY_CAPABILITIES (handle in PciFdoIrpQueryDeviceCapabilities)
- Build device capability UI number (PciDetermineSlotNumber), use PIR$ (seem support broken, need to check loader) or device property for bus not root
- Use parent attachee device and this PDO for build device/system wake states, latency, device/system power mappings
- PCI-ID manage support: PciInitIdBuffer, PciIdPrintf, PciIdPrintfAppend
- Debug helper: PciDebugDumpQueryCapabilities
- Thanks richard for advise + beer
PCI-X driver now pass 10000 codes lines!

svn path=/trunk/; revision=48548
This commit is contained in:
evb 2010-08-14 17:09:20 +00:00
parent 912704ceb8
commit af01479fbf
7 changed files with 1086 additions and 24 deletions

View file

@ -49,6 +49,26 @@ PCHAR PoCodes[] =
"QUERY_POWER",
};
PCHAR SystemPowerStates[] =
{
"Unspecified",
"Working",
"Sleeping1",
"Sleeping2",
"Sleeping3",
"Hibernate",
"Shutdown"
};
PCHAR DevicePowerStates[] =
{
"Unspecified",
"D0",
"D1",
"D2",
"D3"
};
ULONG PciBreakOnPdoPowerIrp, PciBreakOnFdoPowerIrp;
ULONG PciBreakOnPdoPnpIrp, PciBreakOnFdoPnpIrp;
@ -194,4 +214,41 @@ PciDebugDumpCommonConfig(IN PPCI_COMMON_HEADER PciData)
}
}
VOID
NTAPI
PciDebugDumpQueryCapabilities(IN PDEVICE_CAPABILITIES DeviceCaps)
{
ULONG i;
/* Dump the capabilities */
DPRINT1("Capabilities\n Lock:%d, Eject:%d, Remove:%d, Dock:%d, UniqueId:%d\n",
DeviceCaps->LockSupported,
DeviceCaps->EjectSupported,
DeviceCaps->Removable,
DeviceCaps->DockDevice,
DeviceCaps->UniqueID);
DbgPrint(" SilentInstall:%d, RawOk:%d, SurpriseOk:%d\n",
DeviceCaps->SilentInstall,
DeviceCaps->RawDeviceOK,
DeviceCaps->SurpriseRemovalOK);
DbgPrint(" Address %08x, UINumber %08x, Latencies D1 %d, D2 %d, D3 %d\n",
DeviceCaps->Address,
DeviceCaps->UINumber,
DeviceCaps->D1Latency,
DeviceCaps->D2Latency,
DeviceCaps->D3Latency);
/* Dump and convert the wake levels */
DbgPrint(" System Wake: %s, Device Wake: %s\n DeviceState[PowerState] [",
SystemPowerStates[min(DeviceCaps->SystemWake, PowerSystemMaximum)],
DevicePowerStates[min(DeviceCaps->DeviceWake, PowerDeviceMaximum)]);
/* Dump and convert the power state mappings */
for (i = PowerSystemWorking; i < PowerSystemMaximum; i++)
DbgPrint(" %s", DevicePowerStates[DeviceCaps->DeviceState[i]]);
/* Finish the dump */
DbgPrint(" ]\n");
}
/* EOF */

View file

@ -14,6 +14,8 @@
/* GLOBALS ********************************************************************/
PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements;
PCI_CONFIGURATOR PciConfigurators[] =
{
{
@ -47,6 +49,65 @@ PCI_CONFIGURATOR PciConfigurators[] =
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension,
OUT PCM_RESOURCE_LIST *Buffer)
{
/* Not yet implemented */
UNIMPLEMENTED;
while (TRUE);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension,
IN OUT PDEVICE_RELATIONS *pDeviceRelations)
{
PDEVICE_RELATIONS DeviceRelations;
PAGED_CODE();
/* If there were existing relations, free them */
if (*pDeviceRelations) ExFreePoolWithTag(*pDeviceRelations, 0);
/* Allocate a new structure for the relations */
DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
sizeof(DEVICE_RELATIONS),
'BicP');
if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES;
/* Only one relation: the PDO */
DeviceRelations->Count = 1;
DeviceRelations->Objects[0] = PdoExtension->PhysicalDeviceObject;
ObReferenceObject(DeviceRelations->Objects[0]);
/* Return the new relations */
*pDeviceRelations = DeviceRelations;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension,
IN OUT PDEVICE_RELATIONS *pDeviceRelations)
{
/* Not yet implemented */
UNIMPLEMENTED;
while (TRUE);
}
NTSTATUS
NTAPI
PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList)
{
/* Not yet implemented */
UNIMPLEMENTED;
while (TRUE);
return STATUS_SUCCESS;
}
/*
* 7. The IO/MEM/Busmaster decodes are disabled for the device.
* 8. The PCI bus driver sets the operating mode bits of the Programming

View file

@ -295,9 +295,23 @@ PciFdoIrpQueryCapabilities(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
PDEVICE_CAPABILITIES Capabilities;
PAGED_CODE();
ASSERT_FDO(DeviceExtension);
/* Get the capabilities */
Capabilities = IoStackLocation->Parameters.DeviceCapabilities.Capabilities;
/* Inherit wake levels and power mappings from the higher-up capabilities */
DeviceExtension->PowerState.SystemWakeLevel = Capabilities->SystemWake;
DeviceExtension->PowerState.DeviceWakeLevel = Capabilities->DeviceWake;
RtlCopyMemory(DeviceExtension->PowerState.SystemStateMapping,
Capabilities->DeviceState,
sizeof(DeviceExtension->PowerState.SystemStateMapping));
/* Dump the capabilities and return success */
PciDebugDumpQueryCapabilities(Capabilities);
return STATUS_SUCCESS;
}
NTSTATUS

View file

@ -79,6 +79,11 @@
//
#define PCI_VERIFIER_CODES 0x04
//
// PCI ID Buffer ANSI Strings
//
#define MAX_ANSI_STRINGS 0x08
//
// Device Extension, Interface, Translator and Arbiter Signatures
//
@ -410,6 +415,19 @@ typedef struct _PCI_VERIFIER_DATA
PCHAR DebuggerMessageText;
} PCI_VERIFIER_DATA, *PPCI_VERIFIER_DATA;
//
// PCI ID Buffer Descriptor
//
typedef struct _PCI_ID_BUFFER
{
ULONG Count;
ANSI_STRING Strings[MAX_ANSI_STRINGS];
ULONG StringSize[MAX_ANSI_STRINGS];
ULONG TotalLength;
PCHAR CharBuffer;
CHAR BufferData[256];
} PCI_ID_BUFFER, *PPCI_ID_BUFFER;
//
// PCI Configuration Callbacks
//
@ -1111,6 +1129,20 @@ PciDecodeEnable(
OUT PUSHORT Command
);
NTSTATUS
NTAPI
PciQueryBusInformation(
IN PPCI_PDO_EXTENSION PdoExtension,
IN PPNP_BUS_INFORMATION* Buffer
);
NTSTATUS
NTAPI
PciQueryCapabilities(
IN PPCI_PDO_EXTENSION PdoExtension,
IN OUT PDEVICE_CAPABILITIES DeviceCapability
);
//
// Configuration Routines
//
@ -1217,6 +1249,12 @@ PciDebugDumpCommonConfig(
IN PPCI_COMMON_HEADER PciData
);
VOID
NTAPI
PciDebugDumpQueryCapabilities(
IN PDEVICE_CAPABILITIES DeviceCaps
);
//
// Interface Support
//
@ -1452,6 +1490,34 @@ PciQueryDeviceRelations(
IN OUT PDEVICE_RELATIONS *pDeviceRelations
);
NTSTATUS
NTAPI
PciQueryResources(
IN PPCI_PDO_EXTENSION PdoExtension,
OUT PCM_RESOURCE_LIST *Buffer
);
NTSTATUS
NTAPI
PciQueryTargetDeviceRelations(
IN PPCI_PDO_EXTENSION PdoExtension,
IN OUT PDEVICE_RELATIONS *pDeviceRelations
);
NTSTATUS
NTAPI
PciQueryEjectionRelations(
IN PPCI_PDO_EXTENSION PdoExtension,
IN OUT PDEVICE_RELATIONS *pDeviceRelations
);
NTSTATUS
NTAPI
PciQueryRequirements(
IN PPCI_PDO_EXTENSION PdoExtension,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList
);
//
// Identification Functions
//
@ -1462,6 +1528,23 @@ PciGetDeviceDescriptionMessage(
IN UCHAR SubClass
);
NTSTATUS
NTAPI
PciQueryDeviceText(
IN PPCI_PDO_EXTENSION PdoExtension,
IN DEVICE_TEXT_TYPE QueryType,
IN ULONG Locale,
OUT PWCHAR *Buffer
);
NTSTATUS
NTAPI
PciQueryId(
IN PPCI_PDO_EXTENSION DeviceExtension,
IN BUS_QUERY_ID_TYPE QueryType,
OUT PWCHAR *Buffer
);
//
// CardBUS Support
//
@ -1627,6 +1710,8 @@ extern PWATCHDOG_TABLE WdTable;
extern PPCI_HACK_ENTRY PciHackTable;
extern BOOLEAN PciAssignBusNumbers;
extern BOOLEAN PciEnableNativeModeATA;
extern PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable;
extern BOOLEAN PciRunningDatacenter;
/* Exported by NTOS, should this go in the NDK? */
extern NTSYSAPI BOOLEAN InitSafeBootMode;

View file

@ -11,6 +11,7 @@
#include <pci.h>
#define NDEBUG
#include <debug.h>
#include "stdio.h"
/* GLOBALS ********************************************************************/
@ -107,4 +108,354 @@ PciGetDeviceDescriptionMessage(IN UCHAR BaseClass,
return Message;
}
VOID
NTAPI
PciInitIdBuffer(IN PPCI_ID_BUFFER IdBuffer)
{
/* Initialize the sizes to zero and the pointer to the start of the buffer */
IdBuffer->TotalLength = 0;
IdBuffer->Count = 0;
IdBuffer->CharBuffer = IdBuffer->BufferData;
}
ULONG
NTAPI
PciIdPrintf(IN PPCI_ID_BUFFER IdBuffer,
IN PCCH Format,
...)
{
ULONG Size, Length;
PANSI_STRING AnsiString;
va_list va;
va_start(va, Format);
ASSERT(IdBuffer->Count < MAX_ANSI_STRINGS);
/* Do the actual string formatting into the character buffer */
vsprintf(IdBuffer->CharBuffer, Format, va);
/* Initialize the ANSI_STRING that will hold this string buffer */
AnsiString = &IdBuffer->Strings[IdBuffer->Count];
RtlInitAnsiString(AnsiString, IdBuffer->CharBuffer);
/* Calculate the final size of the string, in Unicode */
Size = RtlAnsiStringToUnicodeSize(AnsiString);
/* Update hte buffer with the size,and update the character pointer */
IdBuffer->StringSize[IdBuffer->Count] = Size;
IdBuffer->TotalLength += Size;
Length = AnsiString->Length + sizeof(ANSI_NULL);
IdBuffer->CharBuffer += Length;
/* Move to the next string for next time */
IdBuffer->Count++;
/* Return the length */
return Length;
}
ULONG
NTAPI
PciIdPrintfAppend(IN PPCI_ID_BUFFER IdBuffer,
IN PCCH Format,
...)
{
ULONG NextId, Size, Length, MaxLength;
PANSI_STRING AnsiString;
va_list va;
va_start(va, Format);
ASSERT(IdBuffer->Count);
/* Choose the next static ANSI_STRING to use */
NextId = IdBuffer->Count - 1;
/* Max length is from the end of the buffer up until the current pointer */
MaxLength = (PCHAR)(IdBuffer + 1) - IdBuffer->CharBuffer;
/* Do the actual append, and return the length this string took */
Length = vsprintf(IdBuffer->CharBuffer - 1, Format, va);
ASSERT(Length < MaxLength);
/* Select the static ANSI_STRING, and update its length information */
AnsiString = &IdBuffer->Strings[NextId];
AnsiString->Length += Length;
AnsiString->MaximumLength += Length;
/* Calculate the final size of the string, in Unicode */
Size = RtlAnsiStringToUnicodeSize(AnsiString);
/* Update the buffer with the size, and update the character pointer */
IdBuffer->StringSize[NextId] = Size;
IdBuffer->TotalLength += Size;
IdBuffer->CharBuffer += Length;
/* Return the size */
return Size;
}
NTSTATUS
NTAPI
PciQueryId(IN PPCI_PDO_EXTENSION DeviceExtension,
IN BUS_QUERY_ID_TYPE QueryType,
OUT PWCHAR *Buffer)
{
ULONG SubsysId;
CHAR VendorString[22];
PPCI_PDO_EXTENSION PdoExtension;
PPCI_FDO_EXTENSION ParentExtension;
PWCHAR StringBuffer;
ULONG i, Size;
NTSTATUS Status;
PANSI_STRING NextString;
UNICODE_STRING DestinationString;
PCI_ID_BUFFER IdBuffer;
PAGED_CODE();
/* Assume failure */
Status = STATUS_SUCCESS;
*Buffer = NULL;
/* Start with the genric vendor string, which is the vendor ID + device ID */
sprintf(VendorString,
"PCI\\VEN_%04X&DEV_%04X",
DeviceExtension->VendorId,
DeviceExtension->DeviceId);
/* Initialize the PCI ID Buffer */
PciInitIdBuffer(&IdBuffer);
/* Build the subsystem ID as shown in PCI ID Strings */
SubsysId = DeviceExtension->SubsystemVendorId | (DeviceExtension->SubsystemId << 16);
/* Check what the caller is requesting */
switch (QueryType)
{
case BusQueryDeviceID:
/* A single ID, the vendor string + the revision ID */
PciIdPrintf(&IdBuffer,
"%s&SUBSYS_%08X&REV_%02X",
VendorString,
SubsysId,
DeviceExtension->RevisionId);
break;
case BusQueryHardwareIDs:
/* First the vendor string + the subsystem ID + the revision ID */
PciIdPrintf(&IdBuffer,
"%s&SUBSYS_%08X&REV_%02X",
VendorString,
SubsysId,
DeviceExtension->RevisionId);
/* Next, without the revision */
PciIdPrintf(&IdBuffer,
"%s&SUBSYS_%08X",
VendorString,
SubsysId);
/* Next, the vendor string + the base class + sub class + progif */
PciIdPrintf(&IdBuffer,
"%s&CC_%02X%02X%02X",
VendorString,
DeviceExtension->BaseClass,
DeviceExtension->SubClass,
DeviceExtension->ProgIf);
/* Next, without the progif */
PciIdPrintf(&IdBuffer,
"%s&CC_%02X%02X",
VendorString,
DeviceExtension->BaseClass,
DeviceExtension->SubClass);
/* And finally, a terminator */
PciIdPrintf(&IdBuffer, "\0");
break;
case BusQueryCompatibleIDs:
/* First, the vendor + revision ID only */
PciIdPrintf(&IdBuffer,
"%s&REV_%02X",
VendorString,
DeviceExtension->RevisionId);
/* Next, the vendor string alone */
PciIdPrintf(&IdBuffer, "%s", VendorString);
/* Next, the vendor ID + the base class + the sub class + progif */
PciIdPrintf(&IdBuffer,
"PCI\\VEN_%04X&CC_%02X%02X%02X",
DeviceExtension->VendorId,
DeviceExtension->BaseClass,
DeviceExtension->SubClass,
DeviceExtension->ProgIf);
/* Now without the progif */
PciIdPrintf(&IdBuffer,
"PCI\\VEN_%04X&CC_%02X%02X",
DeviceExtension->VendorId,
DeviceExtension->BaseClass,
DeviceExtension->SubClass);
/* And then just the vendor ID itself */
PciIdPrintf(&IdBuffer,
"PCI\\VEN_%04X",
DeviceExtension->VendorId);
/* Then the base class + subclass + progif, without any vendor */
PciIdPrintf(&IdBuffer,
"PCI\\CC_%02X%02X%02X",
DeviceExtension->BaseClass,
DeviceExtension->SubClass,
DeviceExtension->ProgIf);
/* Next, without the progif */
PciIdPrintf(&IdBuffer,
"PCI\\CC_%02X%02X",
DeviceExtension->BaseClass,
DeviceExtension->SubClass);
/* And finally, a terminator */
PciIdPrintf(&IdBuffer, "\0");
break;
case BusQueryInstanceID:
/* Start with a terminator */
PciIdPrintf(&IdBuffer, "\0");
/* And then encode the device and function number */
PciIdPrintfAppend(&IdBuffer,
"%02X",
(DeviceExtension->Slot.u.bits.DeviceNumber << 3) |
DeviceExtension->Slot.u.bits.FunctionNumber);
/* Loop every parent until the root */
ParentExtension = DeviceExtension->ParentFdoExtension;
while (!PCI_IS_ROOT_FDO(ParentExtension))
{
/* And encode the parent's device and function number as well */
PdoExtension = ParentExtension->PhysicalDeviceObject->DeviceExtension;
PciIdPrintfAppend(&IdBuffer,
"%02X",
(PdoExtension->Slot.u.bits.DeviceNumber << 3) |
PdoExtension->Slot.u.bits.FunctionNumber);
}
break;
default:
/* Unknown query type */
DPRINT1("PciQueryId expected ID type = %d\n", QueryType);
return STATUS_NOT_SUPPORTED;
}
/* Something should've been generated if this has been reached */
ASSERT(IdBuffer.Count > 0);
/* Allocate the final string buffer to hold the ID */
StringBuffer = ExAllocatePoolWithTag(PagedPool, IdBuffer.TotalLength, 'BicP');
if (!StringBuffer) return STATUS_INSUFFICIENT_RESOURCES;
/* Build the UNICODE_STRING structure for it */
DPRINT1("PciQueryId(%d)\n", QueryType);
DestinationString.Buffer = StringBuffer;
DestinationString.MaximumLength = IdBuffer.TotalLength;
/* Loop every ID in the buffer */
for (i = 0; i < IdBuffer.Count; i++)
{
/* Select the ANSI_STRING for the ID */
NextString = &IdBuffer.Strings[i];
DPRINT1(" <- \"%s\"\n", NextString->Buffer);
/* Convert it to a UNICODE_STRING */
Status = RtlAnsiStringToUnicodeString(&DestinationString, NextString, FALSE);
ASSERT(NT_SUCCESS(Status));
/* Add it into the final destination buffer */
Size = IdBuffer.StringSize[i];
DestinationString.MaximumLength -= Size;
DestinationString.Buffer += (Size / sizeof(WCHAR));
}
/* Return the buffer to the caller and return status (should be success) */
*Buffer = StringBuffer;
return Status;
}
NTSTATUS
NTAPI
PciQueryDeviceText(IN PPCI_PDO_EXTENSION PdoExtension,
IN DEVICE_TEXT_TYPE QueryType,
IN ULONG Locale,
OUT PWCHAR *Buffer)
{
PWCHAR MessageBuffer, LocationBuffer;
ULONG Length;
NTSTATUS Status;
/* Check what the caller is requesting */
switch (QueryType)
{
case DeviceTextDescription:
/* Get the message from the resource section */
MessageBuffer = PciGetDeviceDescriptionMessage(PdoExtension->BaseClass,
PdoExtension->SubClass);
/* Return it to the caller, and select proper status code */
*Buffer = MessageBuffer;
Status = MessageBuffer ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
break;
case DeviceTextLocationInformation:
/* Get the message from the resource section */
MessageBuffer = PciGetDescriptionMessage(0x10000, &Length);
if (!MessageBuffer)
{
/* It should be there, but fail if it wasn't found for some reason */
Status = STATUS_NOT_SUPPORTED;
break;
}
/* Add space for a null-terminator, and allocate the buffer */
Length += 2 * sizeof(UNICODE_NULL);
LocationBuffer = ExAllocatePoolWithTag(PagedPool,
Length * sizeof(WCHAR),
'BicP');
*Buffer = LocationBuffer;
/* Check if the allocation succeeded */
if (LocationBuffer)
{
/* Build the location string based on bus, function, and device */
swprintf(LocationBuffer,
MessageBuffer,
PdoExtension->ParentFdoExtension->BaseBus,
PdoExtension->Slot.u.bits.FunctionNumber,
PdoExtension->Slot.u.bits.DeviceNumber);
}
/* Free the original string from the resource section */
ExFreePoolWithTag(MessageBuffer, 0);
/* Select the correct status */
Status = LocationBuffer ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
break;
default:
/* Anything else is unsupported */
Status = STATUS_NOT_SUPPORTED;
break;
}
/* Return whether or not a device text string was indeed found */
return Status;
}
/* EOF */

View file

@ -200,9 +200,32 @@ PciPdoIrpQueryDeviceRelations(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_PDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
NTSTATUS Status;
PAGED_CODE();
/* Are ejection relations being queried? */
if (IoStackLocation->Parameters.QueryDeviceRelations.Type == EjectionRelations)
{
/* Call the worker function */
Status = PciQueryEjectionRelations(DeviceExtension,
(PDEVICE_RELATIONS*)&Irp->
IoStatus.Information);
}
else if (IoStackLocation->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
{
/* The only other relation supported is the target device relation */
Status = PciQueryTargetDeviceRelations(DeviceExtension,
(PDEVICE_RELATIONS*)&Irp->
IoStatus.Information);
}
else
{
/* All other relations are unsupported */
Status = STATUS_NOT_SUPPORTED;
}
/* Return either the result of the worker function, or unsupported status */
return Status;
}
NTSTATUS
@ -211,9 +234,12 @@ PciPdoIrpQueryCapabilities(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_PDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
PAGED_CODE();
/* Call the worker function */
return PciQueryCapabilities(DeviceExtension,
IoStackLocation->
Parameters.DeviceCapabilities.Capabilities);
}
NTSTATUS
@ -222,9 +248,11 @@ PciPdoIrpQueryResources(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_PDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
PAGED_CODE();
/* Call the worker function */
return PciQueryResources(DeviceExtension,
(PCM_RESOURCE_LIST*)&Irp->IoStatus.Information);
}
NTSTATUS
@ -233,9 +261,12 @@ PciPdoIrpQueryResourceRequirements(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_PDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
PAGED_CODE();
/* Call the worker function */
return PciQueryRequirements(DeviceExtension,
(PIO_RESOURCE_REQUIREMENTS_LIST*)&Irp->
IoStatus.Information);
}
NTSTATUS
@ -244,9 +275,15 @@ PciPdoIrpQueryDeviceText(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_PDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
PAGED_CODE();
/* Call the worker function */
return PciQueryDeviceText(DeviceExtension,
IoStackLocation->
Parameters.QueryDeviceText.DeviceTextType,
IoStackLocation->
Parameters.QueryDeviceText.LocaleId,
(PWCHAR*)&Irp->IoStatus.Information);
}
NTSTATUS
@ -255,9 +292,12 @@ PciPdoIrpQueryId(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_PDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
PAGED_CODE();
/* Call the worker function */
return PciQueryId(DeviceExtension,
IoStackLocation->Parameters.QueryId.IdType,
(PWCHAR*)&Irp->IoStatus.Information);
}
NTSTATUS
@ -266,9 +306,12 @@ PciPdoIrpQueryBusInformation(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_PDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
PAGED_CODE();
/* Call the worker function */
return PciQueryBusInformation(DeviceExtension,
(PPNP_BUS_INFORMATION*)&Irp->
IoStatus.Information);
}
NTSTATUS

View file

@ -1306,4 +1306,455 @@ PciDecodeEnable(IN PPCI_PDO_EXTENSION PdoExtension,
}
}
NTSTATUS
NTAPI
PciQueryBusInformation(IN PPCI_PDO_EXTENSION PdoExtension,
IN PPNP_BUS_INFORMATION* Buffer)
{
PPNP_BUS_INFORMATION BusInfo;
/* Allocate a structure for the bus information */
BusInfo = ExAllocatePoolWithTag(PagedPool,
sizeof(PNP_BUS_INFORMATION),
'BicP');
if (!BusInfo) return STATUS_INSUFFICIENT_RESOURCES;
/* Write the correct GUID and bus type identifier, and fill the bus number */
BusInfo->BusTypeGuid = GUID_BUS_TYPE_PCI;
BusInfo->LegacyBusType = PCIBus;
BusInfo->BusNumber = PdoExtension->ParentFdoExtension->BaseBus;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PciDetermineSlotNumber(IN PPCI_PDO_EXTENSION PdoExtension,
OUT PULONG SlotNumber)
{
PPCI_FDO_EXTENSION ParentExtension;
ULONG ResultLength;
NTSTATUS Status;
PSLOT_INFO SlotInfo;
/* Check if a $PIR from the BIOS is used (legacy IRQ routing) */
ParentExtension = PdoExtension->ParentFdoExtension;
DPRINT1("Slot lookup for %d.%d.%d\n",
ParentExtension ? ParentExtension->BaseBus : -1,
PdoExtension->Slot.u.bits.DeviceNumber,
PdoExtension->Slot.u.bits.FunctionNumber);
if ((PciIrqRoutingTable) && (ParentExtension))
{
/* Read every slot information entry */
SlotInfo = &PciIrqRoutingTable->Slot[0];
DPRINT1("PIR$ %p is %lx bytes, slot 0 is at: %lx\n",
PciIrqRoutingTable, PciIrqRoutingTable->TableSize, SlotInfo);
while (SlotInfo < (PSLOT_INFO)((ULONG_PTR)PciIrqRoutingTable +
PciIrqRoutingTable->TableSize))
{
DPRINT1("Slot Info: %d.%d->#%d\n",
SlotInfo->BusNumber,
SlotInfo->DeviceNumber,
SlotInfo->SlotNumber);
/* Check if this slot information matches the PDO being queried */
if ((ParentExtension->BaseBus == SlotInfo->BusNumber) &&
(PdoExtension->Slot.u.bits.DeviceNumber == SlotInfo->DeviceNumber >> 3) &&
(SlotInfo->SlotNumber))
{
/* We found it, return it and return success */
*SlotNumber = SlotInfo->SlotNumber;
return STATUS_SUCCESS;
}
/* Try the next slot */
SlotInfo++;
}
}
/* Otherwise, grab the parent FDO and check if it's the root */
if (PCI_IS_ROOT_FDO(ParentExtension))
{
/* The root FDO doesn't have a slot number */
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* Otherwise, query the slot/UI address/number as a device property */
Status = IoGetDeviceProperty(ParentExtension->PhysicalDeviceObject,
DevicePropertyUINumber,
sizeof(ULONG),
SlotNumber,
&ResultLength);
}
/* Return the status of this endeavour */
return Status;
}
NTSTATUS
NTAPI
PciGetDeviceCapabilities(IN PDEVICE_OBJECT DeviceObject,
IN OUT PDEVICE_CAPABILITIES DeviceCapability)
{
PIRP Irp;
NTSTATUS Status;
KEVENT Event;
PDEVICE_OBJECT AttachedDevice;
PIO_STACK_LOCATION IoStackLocation;
IO_STATUS_BLOCK IoStatusBlock;
PAGED_CODE();
/* Zero out capabilities and set undefined values to start with */
RtlZeroMemory(DeviceCapability, sizeof(DEVICE_CAPABILITIES));
DeviceCapability->Size = sizeof(DEVICE_CAPABILITIES);
DeviceCapability->Version = 1;
DeviceCapability->Address = -1;
DeviceCapability->UINumber = -1;
/* Build the wait event for the IOCTL */
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
/* Find the device the PDO is attached to */
AttachedDevice = IoGetAttachedDeviceReference(DeviceObject);
/* And build an IRP for it */
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
AttachedDevice,
NULL,
0,
NULL,
&Event,
&IoStatusBlock);
if (!Irp)
{
/* The IRP failed, fail the request as well */
ObDereferenceObject(AttachedDevice);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Set default status */
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
/* Get a stack location in this IRP */
IoStackLocation = IoGetNextIrpStackLocation(Irp);
ASSERT(IoStackLocation);
/* Initialize it as a query capabilities IRP, with no completion routine */
RtlZeroMemory(IoStackLocation, sizeof(IO_STACK_LOCATION));
IoStackLocation->MajorFunction = IRP_MJ_PNP;
IoStackLocation->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
IoStackLocation->Parameters.DeviceCapabilities.Capabilities = DeviceCapability;
IoSetCompletionRoutine(Irp, NULL, NULL, FALSE, FALSE, FALSE);
/* Send the IOCTL to the driver */
Status = IoCallDriver(AttachedDevice, Irp);
if (Status == STATUS_PENDING)
{
/* Wait for a response and update the actual status */
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = Irp->IoStatus.Status;
}
/* Done, dereference the attached device and return the final result */
ObDereferenceObject(AttachedDevice);
return Status;
}
NTSTATUS
NTAPI
PciQueryPowerCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
IN PDEVICE_CAPABILITIES DeviceCapability)
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status;
DEVICE_CAPABILITIES AttachedCaps;
DEVICE_POWER_STATE NewPowerState, DevicePowerState, DeviceWakeLevel, DeviceWakeState;
SYSTEM_POWER_STATE SystemWakeState, DeepestWakeState, CurrentState;
/* Nothing is known at first */
DeviceWakeState = PowerDeviceUnspecified;
SystemWakeState = DeepestWakeState = PowerSystemUnspecified;
/* Get the PCI capabilities for the parent PDO */
DeviceObject = PdoExtension->ParentFdoExtension->PhysicalDeviceObject;
Status = PciGetDeviceCapabilities(DeviceObject, &AttachedCaps);
ASSERT(NT_SUCCESS(Status));
if (!NT_SUCCESS(Status)) return Status;
/* Check if there's not an existing device state for S0 */
if (!AttachedCaps.DeviceState[PowerSystemWorking])
{
/* Set D0<->S0 mapping */
AttachedCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0;
}
/* Check if there's not an existing device state for S3 */
if (!AttachedCaps.DeviceState[PowerSystemShutdown])
{
/* Set D3<->S3 mapping */
AttachedCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
}
/* Check for a PDO with broken, or no, power capabilities */
if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
{
/* Unknown wake device states */
DeviceCapability->DeviceWake = PowerDeviceUnspecified;
DeviceCapability->SystemWake = PowerSystemUnspecified;
/* No device state support */
DeviceCapability->DeviceD1 = FALSE;
DeviceCapability->DeviceD2 = FALSE;
/* No waking from any low-power device state is supported */
DeviceCapability->WakeFromD0 = FALSE;
DeviceCapability->WakeFromD1 = FALSE;
DeviceCapability->WakeFromD2 = FALSE;
DeviceCapability->WakeFromD3 = FALSE;
/* For the rest, copy whatever the parent PDO had */
RtlCopyMemory(DeviceCapability->DeviceState,
AttachedCaps.DeviceState,
sizeof(DeviceCapability->DeviceState));
return STATUS_SUCCESS;
}
/* The PCI Device has power capabilities, so read which ones are supported */
DeviceCapability->DeviceD1 = PdoExtension->PowerCapabilities.Support.D1;
DeviceCapability->DeviceD2 = PdoExtension->PowerCapabilities.Support.D2;
DeviceCapability->WakeFromD0 = PdoExtension->PowerCapabilities.Support.PMED0;
DeviceCapability->WakeFromD1 = PdoExtension->PowerCapabilities.Support.PMED1;
DeviceCapability->WakeFromD2 = PdoExtension->PowerCapabilities.Support.PMED2;
/* Can the attached device wake from D3? */
if (AttachedCaps.DeviceWake != PowerDeviceD3)
{
/* It can't, so check if this PDO supports hot D3 wake */
DeviceCapability->WakeFromD3 = PdoExtension->PowerCapabilities.Support.PMED3Hot;
}
else
{
/* It can, is this the root bus? */
if (PCI_IS_ROOT_FDO(PdoExtension->ParentFdoExtension))
{
/* This is the root bus, so just check if it supports hot D3 wake */
DeviceCapability->WakeFromD3 = PdoExtension->PowerCapabilities.Support.PMED3Hot;
}
else
{
/* Take the minimums? -- need to check with briang at work */
UNIMPLEMENTED;
}
}
/* Now loop each system power state to determine its device state mapping */
for (CurrentState = PowerSystemWorking;
CurrentState < PowerSystemMaximum;
CurrentState++)
{
/* Read the current mapping from the attached device */
DevicePowerState = AttachedCaps.DeviceState[CurrentState];
NewPowerState = DevicePowerState;
/* The attachee suports D1, but this PDO does not */
if ((NewPowerState == PowerDeviceD1) &&
!(PdoExtension->PowerCapabilities.Support.D1))
{
/* Fall back to D2 */
NewPowerState = PowerDeviceD2;
}
/* The attachee supports D2, but this PDO does not */
if ((NewPowerState == PowerDeviceD2) &&
!(PdoExtension->PowerCapabilities.Support.D2))
{
/* Fall back to D3 */
NewPowerState = PowerDeviceD3;
}
/* Set the mapping based on the best state supported */
DeviceCapability->DeviceState[CurrentState] = NewPowerState;
/* Check if sleep states are being processed, and a mapping was found */
if ((CurrentState < PowerSystemHibernate) &&
(NewPowerState != PowerDeviceUnspecified))
{
/* Save this state as being the deepest one found until now */
DeepestWakeState = CurrentState;
}
/*
* Finally, check if the computed sleep state is within the states that
* this device can wake the system from, and if it's higher or equal to
* the sleep state mapping that came from the attachee, assuming that it
* had a valid mapping to begin with.
*
* It this is the case, then make sure that the computed sleep state is
* matched by the device's ability to actually wake from that state.
*
* For devices that support D3, the PCI device only needs Hot D3 as long
* as the attachee's state is less than D3. Otherwise, if the attachee
* might also be at D3, this would require a Cold D3 wake, so check that
* the device actually support this.
*/
if ((CurrentState < AttachedCaps.SystemWake) &&
(NewPowerState >= DevicePowerState) &&
(DevicePowerState != PowerDeviceUnspecified) &&
(((NewPowerState == PowerDeviceD0) && (DeviceCapability->WakeFromD0)) ||
((NewPowerState == PowerDeviceD1) && (DeviceCapability->WakeFromD1)) ||
((NewPowerState == PowerDeviceD2) && (DeviceCapability->WakeFromD2)) ||
((NewPowerState == PowerDeviceD3) &&
(PdoExtension->PowerCapabilities.Support.PMED3Hot) &&
((DevicePowerState < PowerDeviceD3) ||
(PdoExtension->PowerCapabilities.Support.PMED3Cold)))))
{
/* The mapping is valid, so this will be the lowest wake state */
SystemWakeState = CurrentState;
DeviceWakeState = NewPowerState;
}
}
/* Read the current wake level */
DeviceWakeLevel = PdoExtension->PowerState.DeviceWakeLevel;
/* Check if the attachee's wake levels are valid, and the PDO's is higher */
if ((AttachedCaps.SystemWake != PowerSystemUnspecified) &&
(AttachedCaps.DeviceWake != PowerDeviceUnspecified) &&
(DeviceWakeLevel != PowerDeviceUnspecified) &&
(DeviceWakeLevel >= AttachedCaps.DeviceWake))
{
/* Inherit the system wake from the attachee, and this PDO's wake level */
DeviceCapability->SystemWake = AttachedCaps.SystemWake;
DeviceCapability->DeviceWake = DeviceWakeLevel;
/* Now check if the wake level is D0, but the PDO doesn't support it */
if ((DeviceCapability->DeviceWake == PowerDeviceD0) &&
!(DeviceCapability->WakeFromD0))
{
/* Bump to D1 */
DeviceCapability->DeviceWake = PowerDeviceD1;
}
/* Now check if the wake level is D1, but the PDO doesn't support it */
if ((DeviceCapability->DeviceWake == PowerDeviceD1) &&
!(DeviceCapability->WakeFromD1))
{
/* Bump to D2 */
DeviceCapability->DeviceWake = PowerDeviceD2;
}
/* Now check if the wake level is D2, but the PDO doesn't support it */
if ((DeviceCapability->DeviceWake == PowerDeviceD2) &&
!(DeviceCapability->WakeFromD2))
{
/* Bump it to D3 */
DeviceCapability->DeviceWake = PowerDeviceD3;
}
/* Now check if the wake level is D3, but the PDO doesn't support it */
if ((DeviceCapability->DeviceWake == PowerDeviceD3) &&
!(DeviceCapability->WakeFromD3))
{
/* Then no valid wake state exists */
DeviceCapability->DeviceWake = PowerDeviceUnspecified;
DeviceCapability->SystemWake = PowerSystemUnspecified;
}
/* Check if no valid wake state was found */
if ((DeviceCapability->DeviceWake == PowerDeviceUnspecified) ||
(DeviceCapability->SystemWake == PowerSystemUnspecified))
{
/* Check if one was computed earlier */
if ((SystemWakeState != PowerSystemUnspecified) &&
(DeviceWakeState != PowerDeviceUnspecified))
{
/* Use the wake state that had been computed earlier */
DeviceCapability->DeviceWake = DeviceWakeState;
DeviceCapability->SystemWake = SystemWakeState;
/* If that state was D3, then the device supports Hot/Cold D3 */
if (DeviceWakeState == PowerDeviceD3) DeviceCapability->WakeFromD3 = TRUE;
}
}
/*
* Finally, check for off states (lower than S3, such as hibernate) and
* make sure that the device both supports waking from D3 as well as
* supports a Cold wake
*/
if ((DeviceCapability->SystemWake > PowerSystemSleeping3) &&
((DeviceCapability->DeviceWake != PowerDeviceD3) ||
!(PdoExtension->PowerCapabilities.Support.PMED3Cold)))
{
/* It doesn't, so pick the computed lowest wake state from earlier */
DeviceCapability->SystemWake = DeepestWakeState;
}
/* Set the PCI Specification mandated maximum latencies for transitions */
DeviceCapability->D1Latency = 0;
DeviceCapability->D2Latency = 2;
DeviceCapability->D3Latency = 100;
/* Sanity check */
ASSERT(DeviceCapability->DeviceState[PowerSystemWorking] == PowerDeviceD0);
}
else
{
/* No valid sleep states, no latencies to worry about */
DeviceCapability->D1Latency = 0;
DeviceCapability->D2Latency = 0;
DeviceCapability->D3Latency = 0;
}
/* This function always succeeds, even without power management support */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PciQueryCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
IN OUT PDEVICE_CAPABILITIES DeviceCapability)
{
NTSTATUS Status;
/* A PDO ID is never unique, and its address is its function and device */
DeviceCapability->UniqueID = FALSE;
DeviceCapability->Address = PdoExtension->Slot.u.bits.FunctionNumber |
(PdoExtension->Slot.u.bits.DeviceNumber << 16);
/* Check for host bridges */
if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
(PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST))
{
/* Raw device opens to a host bridge are acceptable */
DeviceCapability->RawDeviceOK = TRUE;
}
else
{
/* Otherwise, other PDOs cannot be directly opened */
DeviceCapability->RawDeviceOK = FALSE;
}
/* PCI PDOs are pretty fixed things */
DeviceCapability->LockSupported = FALSE;
DeviceCapability->EjectSupported = FALSE;
DeviceCapability->Removable = FALSE;
DeviceCapability->DockDevice = FALSE;
/* The slot number is stored as a device property, go query it */
PciDetermineSlotNumber(PdoExtension, &DeviceCapability->UINumber);
/* Finally, query and power capabilities and convert them for PnP usage */
Status = PciQueryPowerCapabilities(PdoExtension, DeviceCapability);
/* Dump the capabilities if it all worked, and return the status */
if (NT_SUCCESS(Status)) PciDebugDumpQueryCapabilities(DeviceCapability);
return Status;
}
/* EOF */