mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
- 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:
parent
912704ceb8
commit
af01479fbf
7 changed files with 1086 additions and 24 deletions
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue