2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/utils.c
5 * PURPOSE: Utility/Helper Support Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 ULONG PciDebugPortsCount
;
19 RTL_RANGE_LIST PciIsaBitExclusionList
;
20 RTL_RANGE_LIST PciVgaAndIsaBitExclusionList
;
22 /* FUNCTIONS ******************************************************************/
26 PciUnicodeStringStrStr(IN PUNICODE_STRING InputString
,
27 IN PCUNICODE_STRING EqualString
,
28 IN BOOLEAN CaseInSensitive
)
30 UNICODE_STRING PartialString
;
31 LONG EqualChars
, TotalChars
;
33 /* Build a partial string with the smaller substring */
34 PartialString
.Length
= EqualString
->Length
;
35 PartialString
.MaximumLength
= InputString
->MaximumLength
;;
36 PartialString
.Buffer
= InputString
->Buffer
;
38 /* Check how many characters that need comparing */
40 TotalChars
= (InputString
->Length
- EqualString
->Length
) / sizeof(WCHAR
);
42 /* If the substring is bigger, just fail immediately */
43 if (TotalChars
< 0) return FALSE
;
45 /* Keep checking each character */
46 while (!RtlEqualUnicodeString(EqualString
, &PartialString
, CaseInSensitive
))
48 /* Continue checking until all the required characters are equal */
49 PartialString
.Buffer
++;
50 PartialString
.MaximumLength
-= sizeof(WCHAR
);
51 if (++EqualChars
> TotalChars
) return FALSE
;
54 /* The string is equal */
60 PciStringToUSHORT(IN PWCHAR String
,
64 ULONG Low
, High
, Length
;
67 /* Initialize everything to zero */
72 /* Get the character and set the high byte based on the previous one */
76 /* Check for numbers */
77 if ( Char
>= '0' && Char
<= '9' )
79 /* Convert them to a byte */
82 else if ( Char
>= 'A' && Char
<= 'F' )
84 /* Convert upper-case hex letters into a byte */
87 else if ( Char
>= 'a' && Char
<= 'f' )
89 /* Convert lower-case hex letters into a byte */
94 /* Invalid string, fail the conversion */
98 /* Combine the high and low byte */
101 /* If 4 letters have been reached, the 16-bit integer should exist */
104 /* Return it to the caller */
113 PciIsSuiteVersion(IN USHORT SuiteMask
)
116 RTL_OSVERSIONINFOEXW VersionInfo
;
118 /* Initialize the version information */
119 RtlZeroMemory(&VersionInfo
, sizeof(RTL_OSVERSIONINFOEXW
));
120 VersionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
121 VersionInfo
.wSuiteMask
= SuiteMask
;
123 /* Set the comparison mask and return if the passed suite mask matches */
124 VER_SET_CONDITION(Mask
, VER_SUITENAME
, VER_AND
);
125 return NT_SUCCESS(RtlVerifyVersionInfo(&VersionInfo
, VER_SUITENAME
, Mask
));
130 PciIsDatacenter(VOID
)
137 /* Assume this isn't Datacenter */
140 /* First, try opening the setup key */
141 Status
= PciGetRegistryValue(L
"",
142 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\setupdd",
147 if (!NT_SUCCESS(Status
))
149 /* This is not an in-progress Setup boot, so query the suite version */
150 Result
= PciIsSuiteVersion(VER_SUITE_DATACENTER
);
154 /* This scenario shouldn't happen yet, since SetupDD isn't used */
155 UNIMPLEMENTED_FATAL("ReactOS doesn't use SetupDD for its installation program. Therefore this scenario must not happen!\n");
158 /* Return if this is Datacenter or not */
164 PciOpenKey(IN PWCHAR KeyName
,
166 IN ACCESS_MASK DesiredAccess
,
167 OUT PHANDLE KeyHandle
,
168 OUT PNTSTATUS KeyStatus
)
171 OBJECT_ATTRIBUTES ObjectAttributes
;
172 UNICODE_STRING KeyString
;
175 /* Initialize the object attributes */
176 RtlInitUnicodeString(&KeyString
, KeyName
);
177 InitializeObjectAttributes(&ObjectAttributes
,
179 OBJ_CASE_INSENSITIVE
,
183 /* Open the key, returning a boolean, and the status, if requested */
184 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
185 if (KeyStatus
) *KeyStatus
= Status
;
186 return NT_SUCCESS(Status
);
191 PciGetRegistryValue(IN PWCHAR ValueName
,
193 IN HANDLE RootHandle
,
195 OUT PVOID
*OutputBuffer
,
196 OUT PULONG OutputLength
)
199 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
200 ULONG NeededLength
, ActualLength
;
201 UNICODE_STRING ValueString
;
205 /* So we know what to free at the end of the body */
210 /* Open the key by name, rooted off the handle passed */
211 Result
= PciOpenKey(KeyName
,
218 /* Query for the size that's needed for the value that was passed in */
219 RtlInitUnicodeString(&ValueString
, ValueName
);
220 Status
= ZwQueryValueKey(KeyHandle
,
222 KeyValuePartialInformation
,
226 ASSERT(!NT_SUCCESS(Status
));
227 if (Status
!= STATUS_BUFFER_TOO_SMALL
) break;
229 /* Allocate an appropriate buffer for the size that was returned */
230 ASSERT(NeededLength
!= 0);
231 Status
= STATUS_INSUFFICIENT_RESOURCES
;
232 PartialInfo
= ExAllocatePoolWithTag(PagedPool
,
235 if (!PartialInfo
) break;
237 /* Query the actual value information now that the size is known */
238 Status
= ZwQueryValueKey(KeyHandle
,
240 KeyValuePartialInformation
,
244 if (!NT_SUCCESS(Status
)) break;
246 /* Make sure it's of the type that the caller expects */
247 Status
= STATUS_INVALID_PARAMETER
;
248 if (PartialInfo
->Type
!= Type
) break;
250 /* Subtract the registry-specific header, to get the data size */
251 ASSERT(NeededLength
== ActualLength
);
252 NeededLength
-= sizeof(KEY_VALUE_PARTIAL_INFORMATION
);
254 /* Allocate a buffer to hold the data and return it to the caller */
255 Status
= STATUS_INSUFFICIENT_RESOURCES
;
256 *OutputBuffer
= ExAllocatePoolWithTag(PagedPool
,
259 if (!*OutputBuffer
) break;
261 /* Copy the data into the buffer and return its length to the caller */
262 RtlCopyMemory(*OutputBuffer
, PartialInfo
->Data
, NeededLength
);
263 if (OutputLength
) *OutputLength
= NeededLength
;
264 Status
= STATUS_SUCCESS
;
267 /* Close any opened keys and free temporary allocations */
268 if (KeyHandle
) ZwClose(KeyHandle
);
269 if (PartialInfo
) ExFreePoolWithTag(PartialInfo
, 0);
275 PciBuildDefaultExclusionLists(VOID
)
279 ASSERT(PciIsaBitExclusionList
.Count
== 0);
280 ASSERT(PciVgaAndIsaBitExclusionList
.Count
== 0);
282 /* Initialize the range lists */
283 RtlInitializeRangeList(&PciIsaBitExclusionList
);
284 RtlInitializeRangeList(&PciVgaAndIsaBitExclusionList
);
286 /* Loop x86 I/O ranges */
287 for (Start
= 0x100; Start
<= 0xFEFF; Start
+= 0x400)
289 /* Add the ISA I/O ranges */
290 Status
= RtlAddRange(&PciIsaBitExclusionList
,
294 RTL_RANGE_LIST_ADD_IF_CONFLICT
,
297 if (!NT_SUCCESS(Status
)) break;
299 /* Add the ISA I/O ranges */
300 Status
= RtlAddRange(&PciVgaAndIsaBitExclusionList
,
304 RTL_RANGE_LIST_ADD_IF_CONFLICT
,
307 if (!NT_SUCCESS(Status
)) break;
309 /* Add the VGA I/O range for Monochrome Video */
310 Status
= RtlAddRange(&PciVgaAndIsaBitExclusionList
,
314 RTL_RANGE_LIST_ADD_IF_CONFLICT
,
317 if (!NT_SUCCESS(Status
)) break;
319 /* Add the VGA I/O range for certain CGA adapters */
320 Status
= RtlAddRange(&PciVgaAndIsaBitExclusionList
,
324 RTL_RANGE_LIST_ADD_IF_CONFLICT
,
327 if (!NT_SUCCESS(Status
)) break;
329 /* Success, ranges added done */
332 RtlFreeRangeList(&PciIsaBitExclusionList
);
333 RtlFreeRangeList(&PciVgaAndIsaBitExclusionList
);
339 PciFindParentPciFdoExtension(IN PDEVICE_OBJECT DeviceObject
,
342 PPCI_FDO_EXTENSION DeviceExtension
;
343 PPCI_PDO_EXTENSION SearchExtension
, FoundExtension
;
345 /* Assume we'll find nothing */
346 SearchExtension
= DeviceObject
->DeviceExtension
;
347 FoundExtension
= NULL
;
349 /* Check if a lock was specified */
352 /* Wait for the lock to be released */
353 KeEnterCriticalRegion();
354 KeWaitForSingleObject(Lock
, Executive
, KernelMode
, FALSE
, NULL
);
357 /* Now search for the extension */
358 DeviceExtension
= (PPCI_FDO_EXTENSION
)PciFdoExtensionListHead
.Next
;
359 while (DeviceExtension
)
361 /* Acquire this device's lock */
362 KeEnterCriticalRegion();
363 KeWaitForSingleObject(&DeviceExtension
->ChildListLock
,
369 /* Scan all children PDO, stop when no more PDOs, or found it */
370 for (FoundExtension
= DeviceExtension
->ChildPdoList
;
371 ((FoundExtension
) && (FoundExtension
!= SearchExtension
));
372 FoundExtension
= FoundExtension
->Next
);
374 /* Release this device's lock */
375 KeSetEvent(&DeviceExtension
->ChildListLock
, IO_NO_INCREMENT
, FALSE
);
376 KeLeaveCriticalRegion();
378 /* If we found it, break out */
379 if (FoundExtension
) break;
381 /* Move to the next device */
382 DeviceExtension
= (PPCI_FDO_EXTENSION
)DeviceExtension
->List
.Next
;
385 /* Check if we had acquired a lock previously */
389 KeSetEvent(Lock
, IO_NO_INCREMENT
, FALSE
);
390 KeLeaveCriticalRegion();
393 /* Return which extension was found, if any */
394 return DeviceExtension
;
399 PciInsertEntryAtTail(IN PSINGLE_LIST_ENTRY ListHead
,
400 IN PPCI_FDO_EXTENSION DeviceExtension
,
403 PSINGLE_LIST_ENTRY NextEntry
;
406 /* Check if a lock was specified */
409 /* Wait for the lock to be released */
410 KeEnterCriticalRegion();
411 KeWaitForSingleObject(Lock
, Executive
, KernelMode
, FALSE
, NULL
);
414 /* Loop the list until we get to the end, then insert this entry there */
415 for (NextEntry
= ListHead
; NextEntry
->Next
; NextEntry
= NextEntry
->Next
);
416 NextEntry
->Next
= &DeviceExtension
->List
;
418 /* Check if we had acquired a lock previously */
422 KeSetEvent(Lock
, IO_NO_INCREMENT
, FALSE
);
423 KeLeaveCriticalRegion();
429 PciInsertEntryAtHead(IN PSINGLE_LIST_ENTRY ListHead
,
430 IN PSINGLE_LIST_ENTRY Entry
,
435 /* Check if a lock was specified */
438 /* Wait for the lock to be released */
439 KeEnterCriticalRegion();
440 KeWaitForSingleObject(Lock
, Executive
, KernelMode
, FALSE
, NULL
);
443 /* Make the entry point to the current head and make the head point to it */
444 Entry
->Next
= ListHead
->Next
;
445 ListHead
->Next
= Entry
;
447 /* Check if we had acquired a lock previously */
451 KeSetEvent(Lock
, IO_NO_INCREMENT
, FALSE
);
452 KeLeaveCriticalRegion();
458 PcipLinkSecondaryExtension(IN PSINGLE_LIST_ENTRY List
,
460 IN PPCI_SECONDARY_EXTENSION SecondaryExtension
,
461 IN PCI_SIGNATURE ExtensionType
,
466 /* Setup the extension data, and insert it into the primary's list */
467 SecondaryExtension
->ExtensionType
= ExtensionType
;
468 SecondaryExtension
->Destructor
= Destructor
;
469 PciInsertEntryAtHead(List
, &SecondaryExtension
->List
, Lock
);
474 PciGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
475 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
476 OUT PVOID
*OutputBuffer
)
479 ULONG BufferLength
, ResultLength
;
483 /* Query the requested property size */
484 Status
= IoGetDeviceProperty(DeviceObject
,
489 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
491 /* Call should've failed with buffer too small! */
492 DPRINT1("PCI - Unexpected status from GetDeviceProperty, saw %08X, expected %08X.\n",
494 STATUS_BUFFER_TOO_SMALL
);
495 *OutputBuffer
= NULL
;
496 ASSERTMSG("PCI Successfully did the impossible!", FALSE
);
500 /* Allocate the required buffer */
501 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferLength
, 'BicP');
504 /* No memory, fail the request */
505 DPRINT1("PCI - Failed to allocate DeviceProperty buffer (%u bytes).\n", BufferLength
);
506 Status
= STATUS_INSUFFICIENT_RESOURCES
;
510 /* Do the actual property query call */
511 Status
= IoGetDeviceProperty(DeviceObject
,
516 if (!NT_SUCCESS(Status
)) break;
518 /* Return the buffer to the caller */
519 ASSERT(BufferLength
== ResultLength
);
520 *OutputBuffer
= Buffer
;
521 return STATUS_SUCCESS
;
525 return STATUS_UNSUCCESSFUL
;
530 PciSendIoctl(IN PDEVICE_OBJECT DeviceObject
,
531 IN ULONG IoControlCode
,
532 IN PVOID InputBuffer
,
533 IN ULONG InputBufferLength
,
534 IN PVOID OutputBuffer
,
535 IN ULONG OutputBufferLength
)
540 IO_STATUS_BLOCK IoStatusBlock
;
541 PDEVICE_OBJECT AttachedDevice
;
544 /* Initialize the pending IRP event */
545 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
547 /* Get a reference to the root PDO (ACPI) */
548 AttachedDevice
= IoGetAttachedDeviceReference(DeviceObject
);
549 if (!AttachedDevice
) return STATUS_INVALID_PARAMETER
;
551 /* Build the requested IOCTL IRP */
552 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
,
561 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
563 /* Send the IOCTL to the driver */
564 Status
= IoCallDriver(AttachedDevice
, Irp
);
565 if (Status
== STATUS_PENDING
)
567 /* Wait for a response */
568 KeWaitForSingleObject(&Event
,
573 Status
= Irp
->IoStatus
.Status
;
576 /* Take away the reference we took and return the result to the caller */
577 ObDereferenceObject(AttachedDevice
);
581 PPCI_SECONDARY_EXTENSION
583 PciFindNextSecondaryExtension(IN PSINGLE_LIST_ENTRY ListHead
,
584 IN PCI_SIGNATURE ExtensionType
)
586 PSINGLE_LIST_ENTRY NextEntry
;
587 PPCI_SECONDARY_EXTENSION Extension
;
590 for (NextEntry
= ListHead
; NextEntry
; NextEntry
= NextEntry
->Next
)
592 /* Grab each extension and check if it's the one requested */
593 Extension
= CONTAINING_RECORD(NextEntry
, PCI_SECONDARY_EXTENSION
, List
);
594 if (Extension
->ExtensionType
== ExtensionType
) return Extension
;
597 /* Nothing was found */
603 PciGetHackFlags(IN USHORT VendorId
,
605 IN USHORT SubVendorId
,
606 IN USHORT SubSystemId
,
609 PPCI_HACK_ENTRY HackEntry
;
611 ULONG LastWeight
, MatchWeight
;
614 /* ReactOS SetupLDR Hack */
615 if (!PciHackTable
) return 0;
617 /* Initialize the variables before looping */
620 ASSERT(PciHackTable
);
622 /* Scan the hack table */
623 for (HackEntry
= PciHackTable
;
624 HackEntry
->VendorID
!= PCI_INVALID_VENDORID
;
627 /* Check if there's an entry for this device */
628 if ((HackEntry
->DeviceID
== DeviceId
) &&
629 (HackEntry
->VendorID
== VendorId
))
631 /* This is a basic match */
632 EntryFlags
= HackEntry
->Flags
;
635 /* Does the entry have revision information? */
636 if (EntryFlags
& PCI_HACK_HAS_REVISION_INFO
)
638 /* Check if the revision matches, if so, this is a better match */
639 if (HackEntry
->RevisionID
!= RevisionId
) continue;
643 /* Does the netry have subsystem information? */
644 if (EntryFlags
& PCI_HACK_HAS_SUBSYSTEM_INFO
)
646 /* Check if it matches, if so, this is the best possible match */
647 if ((HackEntry
->SubVendorID
!= SubVendorId
) ||
648 (HackEntry
->SubSystemID
!= SubSystemId
))
655 /* Is this the best match yet? */
656 if (MatchWeight
> LastWeight
)
658 /* This is the best match for now, use this as the hack flags */
659 HackFlags
= HackEntry
->HackFlags
;
660 LastWeight
= MatchWeight
;
665 /* Return the best match */
671 PciIsCriticalDeviceClass(IN UCHAR BaseClass
,
674 /* Check for system or bridge devices */
675 if (BaseClass
== PCI_CLASS_BASE_SYSTEM_DEV
)
677 /* Interrupt controlers are critical */
678 return SubClass
== PCI_SUBCLASS_SYS_INTERRUPT_CTLR
;
680 else if (BaseClass
== PCI_CLASS_BRIDGE_DEV
)
682 /* ISA Bridges are critical */
683 return SubClass
== PCI_SUBCLASS_BR_ISA
;
687 /* All display controllers are critical */
688 return BaseClass
== PCI_CLASS_DISPLAY_CTLR
;
694 PciFindPdoByFunction(IN PPCI_FDO_EXTENSION DeviceExtension
,
695 IN ULONG FunctionNumber
,
696 IN PPCI_COMMON_HEADER PciData
)
699 PPCI_PDO_EXTENSION PdoExtension
;
701 /* Get the current IRQL when this call was made */
702 Irql
= KeGetCurrentIrql();
704 /* Is this a low-IRQL call? */
705 if (Irql
< DISPATCH_LEVEL
)
707 /* Acquire this device's lock */
708 KeEnterCriticalRegion();
709 KeWaitForSingleObject(&DeviceExtension
->ChildListLock
,
716 /* Loop every child PDO */
717 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
719 PdoExtension
= PdoExtension
->Next
)
721 /* Find only enumerated PDOs */
722 if (!PdoExtension
->ReportedMissing
)
724 /* Check if the function number and header data matches */
725 if ((FunctionNumber
== PdoExtension
->Slot
.u
.AsULONG
) &&
726 (PdoExtension
->VendorId
== PciData
->VendorID
) &&
727 (PdoExtension
->DeviceId
== PciData
->DeviceID
) &&
728 (PdoExtension
->RevisionId
== PciData
->RevisionID
))
730 /* This is considered to be the same PDO */
736 /* Was this a low-IRQL call? */
737 if (Irql
< DISPATCH_LEVEL
)
739 /* Release this device's lock */
740 KeSetEvent(&DeviceExtension
->ChildListLock
, IO_NO_INCREMENT
, FALSE
);
741 KeLeaveCriticalRegion();
744 /* If the search found something, this is non-NULL, otherwise it's NULL */
750 PciIsDeviceOnDebugPath(IN PPCI_PDO_EXTENSION DeviceExtension
)
754 UNREFERENCED_PARAMETER(DeviceExtension
);
756 /* Check for too many, or no, debug ports */
757 ASSERT(PciDebugPortsCount
<= MAX_DEBUGGING_DEVICES_SUPPORTED
);
758 if (!PciDebugPortsCount
) return FALSE
;
760 /* eVb has not been able to test such devices yet */
761 UNIMPLEMENTED_DBGBREAK();
767 PciGetBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension
,
768 OUT PPCI_COMMON_HEADER PciData
)
770 HANDLE KeyHandle
, SubKeyHandle
;
771 OBJECT_ATTRIBUTES ObjectAttributes
;
772 UNICODE_STRING KeyName
, KeyValue
;
774 WCHAR DataBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + PCI_COMMON_HDR_LENGTH
];
775 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)DataBuffer
;
780 /* Open the PCI key */
781 Status
= IoOpenDeviceRegistryKey(DeviceExtension
->ParentFdoExtension
->
782 PhysicalDeviceObject
,
786 if (!NT_SUCCESS(Status
)) return Status
;
788 /* Create a volatile BIOS configuration key */
789 RtlInitUnicodeString(&KeyName
, L
"BiosConfig");
790 InitializeObjectAttributes(&ObjectAttributes
,
795 Status
= ZwCreateKey(&SubKeyHandle
,
803 if (!NT_SUCCESS(Status
)) return Status
;
805 /* Create the key value based on the device and function number */
807 L
"DEV_%02x&FUN_%02x",
808 DeviceExtension
->Slot
.u
.bits
.DeviceNumber
,
809 DeviceExtension
->Slot
.u
.bits
.FunctionNumber
);
810 RtlInitUnicodeString(&KeyValue
, Buffer
);
812 /* Query the value information (PCI BIOS configuration header) */
813 Status
= ZwQueryValueKey(SubKeyHandle
,
815 KeyValuePartialInformation
,
819 ZwClose(SubKeyHandle
);
820 if (!NT_SUCCESS(Status
)) return Status
;
822 /* If any information was returned, go ahead and copy its data */
823 ASSERT(PartialInfo
->DataLength
== PCI_COMMON_HDR_LENGTH
);
824 RtlCopyMemory(PciData
, PartialInfo
->Data
, PCI_COMMON_HDR_LENGTH
);
830 PciSaveBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension
,
831 IN PPCI_COMMON_HEADER PciData
)
833 HANDLE KeyHandle
, SubKeyHandle
;
834 OBJECT_ATTRIBUTES ObjectAttributes
;
835 UNICODE_STRING KeyName
, KeyValue
;
840 /* Open the PCI key */
841 Status
= IoOpenDeviceRegistryKey(DeviceExtension
->ParentFdoExtension
->
842 PhysicalDeviceObject
,
844 KEY_READ
| KEY_WRITE
,
846 if (!NT_SUCCESS(Status
)) return Status
;
848 /* Create a volatile BIOS configuration key */
849 RtlInitUnicodeString(&KeyName
, L
"BiosConfig");
850 InitializeObjectAttributes(&ObjectAttributes
,
855 Status
= ZwCreateKey(&SubKeyHandle
,
856 KEY_READ
| KEY_WRITE
,
863 if (!NT_SUCCESS(Status
)) return Status
;
865 /* Create the key value based on the device and function number */
867 L
"DEV_%02x&FUN_%02x",
868 DeviceExtension
->Slot
.u
.bits
.DeviceNumber
,
869 DeviceExtension
->Slot
.u
.bits
.FunctionNumber
);
870 RtlInitUnicodeString(&KeyValue
, Buffer
);
872 /* Set the value data (the PCI BIOS configuration header) */
873 Status
= ZwSetValueKey(SubKeyHandle
,
878 PCI_COMMON_HDR_LENGTH
);
879 ZwClose(SubKeyHandle
);
885 PciReadDeviceCapability(IN PPCI_PDO_EXTENSION DeviceExtension
,
887 IN ULONG CapabilityId
,
888 OUT PPCI_CAPABILITIES_HEADER Buffer
,
891 ULONG CapabilityCount
= 0;
893 /* If the device has no capabilility list, fail */
894 if (!Offset
) return 0;
896 /* Validate a PDO with capabilities, a valid buffer, and a valid length */
897 ASSERT(DeviceExtension
->ExtensionType
== PciPdoExtensionType
);
898 ASSERT(DeviceExtension
->CapabilitiesPtr
!= 0);
900 ASSERT(Length
>= sizeof(PCI_CAPABILITIES_HEADER
));
902 /* Loop all capabilities */
905 /* Make sure the pointer is spec-aligned and spec-sized */
906 ASSERT((Offset
>= PCI_COMMON_HDR_LENGTH
) && ((Offset
& 0x3) == 0));
908 /* Read the capability header */
909 PciReadDeviceConfig(DeviceExtension
,
912 sizeof(PCI_CAPABILITIES_HEADER
));
914 /* Check if this is the capability being looked up */
915 if ((Buffer
->CapabilityID
== CapabilityId
) || !(CapabilityId
))
917 /* Check if was at a valid offset and length */
918 if ((Offset
) && (Length
> sizeof(PCI_CAPABILITIES_HEADER
)))
921 ASSERT(Length
<= (sizeof(PCI_COMMON_CONFIG
) - Offset
));
923 /* Now read the whole capability data into the buffer */
924 PciReadDeviceConfig(DeviceExtension
,
925 (PVOID
)((ULONG_PTR
)Buffer
+
926 sizeof(PCI_CAPABILITIES_HEADER
)),
927 Offset
+ sizeof(PCI_CAPABILITIES_HEADER
),
928 Length
- sizeof(PCI_CAPABILITIES_HEADER
));
931 /* Return the offset where the capability was found */
935 /* Try the next capability instead */
937 Offset
= Buffer
->Next
;
939 /* There can't be more than 48 capabilities (256 bytes max) */
940 if (CapabilityCount
> 48)
942 /* Fail, since this is basically a broken PCI device */
943 DPRINT1("PCI device %p capabilities list is broken.\n", DeviceExtension
);
948 /* Capability wasn't found, fail */
954 PciCanDisableDecodes(IN PPCI_PDO_EXTENSION DeviceExtension
,
955 IN PPCI_COMMON_HEADER Config
,
956 IN ULONGLONG HackFlags
,
957 IN BOOLEAN ForPowerDown
)
959 UCHAR BaseClass
, SubClass
;
962 /* Is there a device extension or should the PCI header be used? */
965 /* Never disable decodes for a debug PCI Device */
966 if (DeviceExtension
->OnDebugPath
) return FALSE
;
968 /* Hack flags will be obtained from the extension, not the caller */
969 ASSERT(HackFlags
== 0);
971 /* Get hacks and classification from the device extension */
972 HackFlags
= DeviceExtension
->HackFlags
;
973 SubClass
= DeviceExtension
->SubClass
;
974 BaseClass
= DeviceExtension
->BaseClass
;
978 /* There must be a PCI header, go read the classification information */
979 ASSERT(Config
!= NULL
);
980 BaseClass
= Config
->BaseClass
;
981 SubClass
= Config
->SubClass
;
984 /* Check for hack flags that prevent disabling the decodes */
985 if (HackFlags
& (PCI_HACK_PRESERVE_COMMAND
|
986 PCI_HACK_CB_SHARE_CMD_BITS
|
987 PCI_HACK_DONT_DISABLE_DECODES
))
993 /* Is this a VGA adapter? */
994 if ((BaseClass
== PCI_CLASS_DISPLAY_CTLR
) &&
995 (SubClass
== PCI_SUBCLASS_VID_VGA_CTLR
))
997 /* Never disable decodes if this is for power down */
1001 /* Check for legacy devices */
1002 if (BaseClass
== PCI_CLASS_PRE_20
)
1004 /* Never disable video adapter cards if this is for power down */
1005 if (SubClass
== PCI_SUBCLASS_PRE_20_VGA
) return ForPowerDown
;
1007 else if (BaseClass
== PCI_CLASS_DISPLAY_CTLR
)
1009 /* Never disable VGA adapters if this is for power down */
1010 if (SubClass
== PCI_SUBCLASS_VID_VGA_CTLR
) return ForPowerDown
;
1012 else if (BaseClass
== PCI_CLASS_BRIDGE_DEV
)
1014 /* Check for legacy bridges */
1015 if ((SubClass
== PCI_SUBCLASS_BR_ISA
) ||
1016 (SubClass
== PCI_SUBCLASS_BR_EISA
) ||
1017 (SubClass
== PCI_SUBCLASS_BR_MCA
) ||
1018 (SubClass
== PCI_SUBCLASS_BR_HOST
) ||
1019 (SubClass
== PCI_SUBCLASS_BR_OTHER
))
1021 /* Never disable these */
1024 else if ((SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
) ||
1025 (SubClass
== PCI_SUBCLASS_BR_CARDBUS
))
1027 /* This is a supported bridge, but does it have a VGA card? */
1028 if (!DeviceExtension
)
1030 /* Read the bridge control flag from the PCI header */
1031 IsVga
= Config
->u
.type1
.BridgeControl
& PCI_ENABLE_BRIDGE_VGA
;
1035 /* Read the cached flag in the device extension */
1036 IsVga
= DeviceExtension
->Dependent
.type1
.VgaBitSet
;
1039 /* Never disable VGA adapters if this is for power down */
1040 if (IsVga
) return ForPowerDown
;
1044 /* Finally, never disable decodes if there's no power management */
1045 return !(HackFlags
& PCI_HACK_NO_PM_CAPS
);
1050 PciClassifyDeviceType(IN PPCI_PDO_EXTENSION PdoExtension
)
1052 ASSERT(PdoExtension
->ExtensionType
== PciPdoExtensionType
);
1054 /* Differenriate between devices and bridges */
1055 if (PdoExtension
->BaseClass
!= PCI_CLASS_BRIDGE_DEV
) return PciTypeDevice
;
1057 /* The PCI Bus driver handles only CardBus and PCI bridges (plus host) */
1058 if (PdoExtension
->SubClass
== PCI_SUBCLASS_BR_HOST
) return PciTypeHostBridge
;
1059 if (PdoExtension
->SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
) return PciTypePciBridge
;
1060 if (PdoExtension
->SubClass
== PCI_SUBCLASS_BR_CARDBUS
) return PciTypeCardbusBridge
;
1062 /* Any other kind of bridge is treated like a device */
1063 return PciTypeDevice
;
1068 PciExecuteCriticalSystemRoutine(IN ULONG_PTR IpiContext
)
1070 PPCI_IPI_CONTEXT Context
= (PPCI_IPI_CONTEXT
)IpiContext
;
1072 /* Check if the IPI is already running */
1073 if (!InterlockedDecrement(&Context
->RunCount
))
1075 /* Nope, this is the first instance, so execute the IPI function */
1076 Context
->Function(Context
->DeviceExtension
, Context
->Context
);
1078 /* Notify anyone that was spinning that they can stop now */
1079 Context
->Barrier
= 0;
1083 /* Spin until it has finished running */
1084 while (Context
->Barrier
);
1093 PciIsSlotPresentInParentMethod(IN PPCI_PDO_EXTENSION PdoExtension
,
1097 PACPI_METHOD_ARGUMENT Argument
;
1098 ACPI_EVAL_INPUT_BUFFER InputBuffer
;
1099 PACPI_EVAL_OUTPUT_BUFFER OutputBuffer
;
1104 /* Assume slot is not part of the parent method */
1107 /* Allocate a 2KB buffer for the method return parameters */
1108 Length
= sizeof(ACPI_EVAL_OUTPUT_BUFFER
) + 2048;
1109 OutputBuffer
= ExAllocatePoolWithTag(PagedPool
, Length
, 'BicP');
1112 /* Clear out the output buffer */
1113 RtlZeroMemory(OutputBuffer
, Length
);
1115 /* Initialize the input buffer with the method requested */
1116 InputBuffer
.Signature
= 0;
1117 *(PULONG
)InputBuffer
.MethodName
= Method
;
1118 InputBuffer
.Signature
= ACPI_EVAL_INPUT_BUFFER_SIGNATURE
;
1120 /* Send it to the ACPI driver */
1121 Status
= PciSendIoctl(PdoExtension
->ParentFdoExtension
->PhysicalDeviceObject
,
1122 IOCTL_ACPI_EVAL_METHOD
,
1124 sizeof(ACPI_EVAL_INPUT_BUFFER
),
1127 if (NT_SUCCESS(Status
))
1129 /* Scan all output arguments */
1130 for (i
= 0; i
< OutputBuffer
->Count
; i
++)
1132 /* Make sure it's an integer */
1133 Argument
= &OutputBuffer
->Argument
[i
];
1134 if (Argument
->Type
!= ACPI_METHOD_ARGUMENT_INTEGER
) continue;
1136 /* Check if the argument matches this PCI slot structure */
1137 if (Argument
->Argument
== ((PdoExtension
->Slot
.u
.bits
.DeviceNumber
) |
1138 ((PdoExtension
->Slot
.u
.bits
.FunctionNumber
) << 16)))
1140 /* This slot has been found, return it */
1147 /* Finished with the buffer, free it */
1148 ExFreePoolWithTag(OutputBuffer
, 0);
1151 /* Return if the slot was found */
1157 PciGetLengthFromBar(IN ULONG Bar
)
1161 /* I/O addresses vs. memory addresses start differently due to alignment */
1162 Length
= 1 << ((Bar
& PCI_ADDRESS_IO_SPACE
) ? 2 : 4);
1164 /* Keep going until a set bit */
1165 while (!(Length
& Bar
) && (Length
)) Length
<<= 1;
1167 /* Return the length (might be 0 on 64-bit because it's the low-word) */
1168 if ((Bar
& PCI_ADDRESS_MEMORY_TYPE_MASK
) != PCI_TYPE_64BIT
) ASSERT(Length
);
1174 PciCreateIoDescriptorFromBarLimit(PIO_RESOURCE_DESCRIPTOR ResourceDescriptor
,
1178 ULONG CurrentBar
, BarLength
, BarMask
;
1179 BOOLEAN Is64BitBar
= FALSE
;
1181 /* Check if the BAR is nor I/O nor memory */
1182 CurrentBar
= BarArray
[0];
1183 if (!(CurrentBar
& ~PCI_ADDRESS_IO_SPACE
))
1185 /* Fail this descriptor */
1186 ResourceDescriptor
->Type
= CmResourceTypeNull
;
1190 /* Set default flag and clear high words */
1191 ResourceDescriptor
->Flags
= 0;
1192 ResourceDescriptor
->u
.Generic
.MaximumAddress
.HighPart
= 0;
1193 ResourceDescriptor
->u
.Generic
.MinimumAddress
.LowPart
= 0;
1194 ResourceDescriptor
->u
.Generic
.MinimumAddress
.HighPart
= 0;
1196 /* Check for ROM Address */
1199 /* Clean up the BAR to get just the address */
1200 CurrentBar
&= PCI_ADDRESS_ROM_ADDRESS_MASK
;
1203 /* Invalid ar, fail this descriptor */
1204 ResourceDescriptor
->Type
= CmResourceTypeNull
;
1208 /* ROM Addresses are always read only */
1209 ResourceDescriptor
->Flags
= CM_RESOURCE_MEMORY_READ_ONLY
;
1212 /* Compute the length, assume it's the alignment for now */
1213 BarLength
= PciGetLengthFromBar(CurrentBar
);
1214 ResourceDescriptor
->u
.Generic
.Length
= BarLength
;
1215 ResourceDescriptor
->u
.Generic
.Alignment
= BarLength
;
1217 /* Check what kind of BAR this is */
1218 if (CurrentBar
& PCI_ADDRESS_IO_SPACE
)
1220 /* Use correct mask to decode the address */
1221 BarMask
= PCI_ADDRESS_IO_ADDRESS_MASK
;
1223 /* Set this as an I/O Port descriptor */
1224 ResourceDescriptor
->Type
= CmResourceTypePort
;
1225 ResourceDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
1229 /* Use correct mask to decode the address */
1230 BarMask
= PCI_ADDRESS_MEMORY_ADDRESS_MASK
;
1232 /* Set this as a memory descriptor */
1233 ResourceDescriptor
->Type
= CmResourceTypeMemory
;
1235 /* Check if it's 64-bit or 20-bit decode */
1236 if ((CurrentBar
& PCI_ADDRESS_MEMORY_TYPE_MASK
) == PCI_TYPE_64BIT
)
1238 /* The next BAR has the high word, read it */
1239 ResourceDescriptor
->u
.Port
.MaximumAddress
.HighPart
= BarArray
[1];
1242 else if ((CurrentBar
& PCI_ADDRESS_MEMORY_TYPE_MASK
) == PCI_TYPE_20BIT
)
1244 /* Use the correct mask to decode the address */
1245 BarMask
= ~0xFFF0000F;
1248 /* Check if the BAR is listed as prefetchable memory */
1249 if (CurrentBar
& PCI_ADDRESS_MEMORY_PREFETCHABLE
)
1251 /* Mark the descriptor in the same way */
1252 ResourceDescriptor
->Flags
|= CM_RESOURCE_MEMORY_PREFETCHABLE
;
1256 /* Now write down the maximum address based on the base + length */
1257 ResourceDescriptor
->u
.Port
.MaximumAddress
.QuadPart
= (CurrentBar
& BarMask
) +
1260 /* Return if this is a 64-bit BAR, so the loop code knows to skip the next one */
1266 PciDecodeEnable(IN PPCI_PDO_EXTENSION PdoExtension
,
1268 OUT PUSHORT Command
)
1270 USHORT CommandValue
;
1273 * If decodes are being disabled, make sure it's allowed, and in both cases,
1274 * make sure that a hackflag isn't preventing touching the decodes at all.
1276 if (((Enable
) || (PciCanDisableDecodes(PdoExtension
, 0, 0, 0))) &&
1277 !(PdoExtension
->HackFlags
& PCI_HACK_PRESERVE_COMMAND
))
1279 /* Did the caller already have a command word? */
1282 /* Use the caller's */
1283 CommandValue
= *Command
;
1287 /* Otherwise, read the current command */
1288 PciReadDeviceConfig(PdoExtension
,
1290 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
1294 /* Turn off decodes by default */
1295 CommandValue
&= ~(PCI_ENABLE_IO_SPACE
|
1296 PCI_ENABLE_MEMORY_SPACE
|
1297 PCI_ENABLE_BUS_MASTER
);
1299 /* If requested, enable the decodes that were enabled at init time */
1300 if (Enable
) CommandValue
|= PdoExtension
->CommandEnables
&
1301 (PCI_ENABLE_IO_SPACE
|
1302 PCI_ENABLE_MEMORY_SPACE
|
1303 PCI_ENABLE_BUS_MASTER
);
1305 /* Update the command word */
1306 PciWriteDeviceConfig(PdoExtension
,
1308 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
1315 PciQueryBusInformation(IN PPCI_PDO_EXTENSION PdoExtension
,
1316 IN PPNP_BUS_INFORMATION
* Buffer
)
1318 PPNP_BUS_INFORMATION BusInfo
;
1320 UNREFERENCED_PARAMETER(Buffer
);
1322 /* Allocate a structure for the bus information */
1323 BusInfo
= ExAllocatePoolWithTag(PagedPool
,
1324 sizeof(PNP_BUS_INFORMATION
),
1326 if (!BusInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
1328 /* Write the correct GUID and bus type identifier, and fill the bus number */
1329 BusInfo
->BusTypeGuid
= GUID_BUS_TYPE_PCI
;
1330 BusInfo
->LegacyBusType
= PCIBus
;
1331 BusInfo
->BusNumber
= PdoExtension
->ParentFdoExtension
->BaseBus
;
1332 return STATUS_SUCCESS
;
1337 PciDetermineSlotNumber(IN PPCI_PDO_EXTENSION PdoExtension
,
1338 OUT PULONG SlotNumber
)
1340 PPCI_FDO_EXTENSION ParentExtension
;
1343 PSLOT_INFO SlotInfo
;
1345 /* Check if a $PIR from the BIOS is used (legacy IRQ routing) */
1346 ParentExtension
= PdoExtension
->ParentFdoExtension
;
1347 DPRINT1("Slot lookup for %d.%u.%u\n",
1348 ParentExtension
? ParentExtension
->BaseBus
: -1,
1349 PdoExtension
->Slot
.u
.bits
.DeviceNumber
,
1350 PdoExtension
->Slot
.u
.bits
.FunctionNumber
);
1351 if ((PciIrqRoutingTable
) && (ParentExtension
))
1353 /* Read every slot information entry */
1354 SlotInfo
= &PciIrqRoutingTable
->Slot
[0];
1355 DPRINT1("PIR$ %p is %lx bytes, slot 0 is at: %p\n",
1356 PciIrqRoutingTable
, PciIrqRoutingTable
->TableSize
, SlotInfo
);
1357 while (SlotInfo
< (PSLOT_INFO
)((ULONG_PTR
)PciIrqRoutingTable
+
1358 PciIrqRoutingTable
->TableSize
))
1360 DPRINT1("Slot Info: %u.%u->#%u\n",
1361 SlotInfo
->BusNumber
,
1362 SlotInfo
->DeviceNumber
,
1363 SlotInfo
->SlotNumber
);
1365 /* Check if this slot information matches the PDO being queried */
1366 if ((ParentExtension
->BaseBus
== SlotInfo
->BusNumber
) &&
1367 (PdoExtension
->Slot
.u
.bits
.DeviceNumber
== SlotInfo
->DeviceNumber
>> 3) &&
1368 (SlotInfo
->SlotNumber
))
1370 /* We found it, return it and return success */
1371 *SlotNumber
= SlotInfo
->SlotNumber
;
1372 return STATUS_SUCCESS
;
1375 /* Try the next slot */
1380 /* Otherwise, grab the parent FDO and check if it's the root */
1381 if (PCI_IS_ROOT_FDO(ParentExtension
))
1383 /* The root FDO doesn't have a slot number */
1384 Status
= STATUS_UNSUCCESSFUL
;
1388 /* Otherwise, query the slot/UI address/number as a device property */
1389 Status
= IoGetDeviceProperty(ParentExtension
->PhysicalDeviceObject
,
1390 DevicePropertyUINumber
,
1396 /* Return the status of this endeavour */
1402 PciGetDeviceCapabilities(IN PDEVICE_OBJECT DeviceObject
,
1403 IN OUT PDEVICE_CAPABILITIES DeviceCapability
)
1408 PDEVICE_OBJECT AttachedDevice
;
1409 PIO_STACK_LOCATION IoStackLocation
;
1410 IO_STATUS_BLOCK IoStatusBlock
;
1413 /* Zero out capabilities and set undefined values to start with */
1414 RtlZeroMemory(DeviceCapability
, sizeof(DEVICE_CAPABILITIES
));
1415 DeviceCapability
->Size
= sizeof(DEVICE_CAPABILITIES
);
1416 DeviceCapability
->Version
= 1;
1417 DeviceCapability
->Address
= -1;
1418 DeviceCapability
->UINumber
= -1;
1420 /* Build the wait event for the IOCTL */
1421 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1423 /* Find the device the PDO is attached to */
1424 AttachedDevice
= IoGetAttachedDeviceReference(DeviceObject
);
1426 /* And build an IRP for it */
1427 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_PNP
,
1436 /* The IRP failed, fail the request as well */
1437 ObDereferenceObject(AttachedDevice
);
1438 return STATUS_INSUFFICIENT_RESOURCES
;
1441 /* Set default status */
1442 Irp
->IoStatus
.Information
= 0;
1443 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1445 /* Get a stack location in this IRP */
1446 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1447 ASSERT(IoStackLocation
);
1449 /* Initialize it as a query capabilities IRP, with no completion routine */
1450 RtlZeroMemory(IoStackLocation
, sizeof(IO_STACK_LOCATION
));
1451 IoStackLocation
->MajorFunction
= IRP_MJ_PNP
;
1452 IoStackLocation
->MinorFunction
= IRP_MN_QUERY_CAPABILITIES
;
1453 IoStackLocation
->Parameters
.DeviceCapabilities
.Capabilities
= DeviceCapability
;
1454 IoSetCompletionRoutine(Irp
, NULL
, NULL
, FALSE
, FALSE
, FALSE
);
1456 /* Send the IOCTL to the driver */
1457 Status
= IoCallDriver(AttachedDevice
, Irp
);
1458 if (Status
== STATUS_PENDING
)
1460 /* Wait for a response and update the actual status */
1461 KeWaitForSingleObject(&Event
,
1466 Status
= Irp
->IoStatus
.Status
;
1469 /* Done, dereference the attached device and return the final result */
1470 ObDereferenceObject(AttachedDevice
);
1476 PciQueryPowerCapabilities(IN PPCI_PDO_EXTENSION PdoExtension
,
1477 IN PDEVICE_CAPABILITIES DeviceCapability
)
1479 PDEVICE_OBJECT DeviceObject
;
1481 DEVICE_CAPABILITIES AttachedCaps
;
1482 DEVICE_POWER_STATE NewPowerState
, DevicePowerState
, DeviceWakeLevel
, DeviceWakeState
;
1483 SYSTEM_POWER_STATE SystemWakeState
, DeepestWakeState
, CurrentState
;
1485 /* Nothing is known at first */
1486 DeviceWakeState
= PowerDeviceUnspecified
;
1487 SystemWakeState
= DeepestWakeState
= PowerSystemUnspecified
;
1489 /* Get the PCI capabilities for the parent PDO */
1490 DeviceObject
= PdoExtension
->ParentFdoExtension
->PhysicalDeviceObject
;
1491 Status
= PciGetDeviceCapabilities(DeviceObject
, &AttachedCaps
);
1492 ASSERT(NT_SUCCESS(Status
));
1493 if (!NT_SUCCESS(Status
)) return Status
;
1495 /* Check if there's not an existing device state for S0 */
1496 if (!AttachedCaps
.DeviceState
[PowerSystemWorking
])
1498 /* Set D0<->S0 mapping */
1499 AttachedCaps
.DeviceState
[PowerSystemWorking
] = PowerDeviceD0
;
1502 /* Check if there's not an existing device state for S3 */
1503 if (!AttachedCaps
.DeviceState
[PowerSystemShutdown
])
1505 /* Set D3<->S3 mapping */
1506 AttachedCaps
.DeviceState
[PowerSystemShutdown
] = PowerDeviceD3
;
1509 /* Check for a PDO with broken, or no, power capabilities */
1510 if (PdoExtension
->HackFlags
& PCI_HACK_NO_PM_CAPS
)
1512 /* Unknown wake device states */
1513 DeviceCapability
->DeviceWake
= PowerDeviceUnspecified
;
1514 DeviceCapability
->SystemWake
= PowerSystemUnspecified
;
1516 /* No device state support */
1517 DeviceCapability
->DeviceD1
= FALSE
;
1518 DeviceCapability
->DeviceD2
= FALSE
;
1520 /* No waking from any low-power device state is supported */
1521 DeviceCapability
->WakeFromD0
= FALSE
;
1522 DeviceCapability
->WakeFromD1
= FALSE
;
1523 DeviceCapability
->WakeFromD2
= FALSE
;
1524 DeviceCapability
->WakeFromD3
= FALSE
;
1526 /* For the rest, copy whatever the parent PDO had */
1527 RtlCopyMemory(DeviceCapability
->DeviceState
,
1528 AttachedCaps
.DeviceState
,
1529 sizeof(DeviceCapability
->DeviceState
));
1530 return STATUS_SUCCESS
;
1533 /* The PCI Device has power capabilities, so read which ones are supported */
1534 DeviceCapability
->DeviceD1
= PdoExtension
->PowerCapabilities
.Support
.D1
;
1535 DeviceCapability
->DeviceD2
= PdoExtension
->PowerCapabilities
.Support
.D2
;
1536 DeviceCapability
->WakeFromD0
= PdoExtension
->PowerCapabilities
.Support
.PMED0
;
1537 DeviceCapability
->WakeFromD1
= PdoExtension
->PowerCapabilities
.Support
.PMED1
;
1538 DeviceCapability
->WakeFromD2
= PdoExtension
->PowerCapabilities
.Support
.PMED2
;
1540 /* Can the attached device wake from D3? */
1541 if (AttachedCaps
.DeviceWake
!= PowerDeviceD3
)
1543 /* It can't, so check if this PDO supports hot D3 wake */
1544 DeviceCapability
->WakeFromD3
= PdoExtension
->PowerCapabilities
.Support
.PMED3Hot
;
1548 /* It can, is this the root bus? */
1549 if (PCI_IS_ROOT_FDO(PdoExtension
->ParentFdoExtension
))
1551 /* This is the root bus, so just check if it supports hot D3 wake */
1552 DeviceCapability
->WakeFromD3
= PdoExtension
->PowerCapabilities
.Support
.PMED3Hot
;
1556 /* Take the minimums? -- need to check with briang at work */
1561 /* Now loop each system power state to determine its device state mapping */
1562 for (CurrentState
= PowerSystemWorking
;
1563 CurrentState
< PowerSystemMaximum
;
1566 /* Read the current mapping from the attached device */
1567 DevicePowerState
= AttachedCaps
.DeviceState
[CurrentState
];
1568 NewPowerState
= DevicePowerState
;
1570 /* The attachee suports D1, but this PDO does not */
1571 if ((NewPowerState
== PowerDeviceD1
) &&
1572 !(PdoExtension
->PowerCapabilities
.Support
.D1
))
1574 /* Fall back to D2 */
1575 NewPowerState
= PowerDeviceD2
;
1578 /* The attachee supports D2, but this PDO does not */
1579 if ((NewPowerState
== PowerDeviceD2
) &&
1580 !(PdoExtension
->PowerCapabilities
.Support
.D2
))
1582 /* Fall back to D3 */
1583 NewPowerState
= PowerDeviceD3
;
1586 /* Set the mapping based on the best state supported */
1587 DeviceCapability
->DeviceState
[CurrentState
] = NewPowerState
;
1589 /* Check if sleep states are being processed, and a mapping was found */
1590 if ((CurrentState
< PowerSystemHibernate
) &&
1591 (NewPowerState
!= PowerDeviceUnspecified
))
1593 /* Save this state as being the deepest one found until now */
1594 DeepestWakeState
= CurrentState
;
1598 * Finally, check if the computed sleep state is within the states that
1599 * this device can wake the system from, and if it's higher or equal to
1600 * the sleep state mapping that came from the attachee, assuming that it
1601 * had a valid mapping to begin with.
1603 * It this is the case, then make sure that the computed sleep state is
1604 * matched by the device's ability to actually wake from that state.
1606 * For devices that support D3, the PCI device only needs Hot D3 as long
1607 * as the attachee's state is less than D3. Otherwise, if the attachee
1608 * might also be at D3, this would require a Cold D3 wake, so check that
1609 * the device actually support this.
1611 if ((CurrentState
< AttachedCaps
.SystemWake
) &&
1612 (NewPowerState
>= DevicePowerState
) &&
1613 (DevicePowerState
!= PowerDeviceUnspecified
) &&
1614 (((NewPowerState
== PowerDeviceD0
) && (DeviceCapability
->WakeFromD0
)) ||
1615 ((NewPowerState
== PowerDeviceD1
) && (DeviceCapability
->WakeFromD1
)) ||
1616 ((NewPowerState
== PowerDeviceD2
) && (DeviceCapability
->WakeFromD2
)) ||
1617 ((NewPowerState
== PowerDeviceD3
) &&
1618 (PdoExtension
->PowerCapabilities
.Support
.PMED3Hot
) &&
1619 ((DevicePowerState
< PowerDeviceD3
) ||
1620 (PdoExtension
->PowerCapabilities
.Support
.PMED3Cold
)))))
1622 /* The mapping is valid, so this will be the lowest wake state */
1623 SystemWakeState
= CurrentState
;
1624 DeviceWakeState
= NewPowerState
;
1628 /* Read the current wake level */
1629 DeviceWakeLevel
= PdoExtension
->PowerState
.DeviceWakeLevel
;
1631 /* Check if the attachee's wake levels are valid, and the PDO's is higher */
1632 if ((AttachedCaps
.SystemWake
!= PowerSystemUnspecified
) &&
1633 (AttachedCaps
.DeviceWake
!= PowerDeviceUnspecified
) &&
1634 (DeviceWakeLevel
!= PowerDeviceUnspecified
) &&
1635 (DeviceWakeLevel
>= AttachedCaps
.DeviceWake
))
1637 /* Inherit the system wake from the attachee, and this PDO's wake level */
1638 DeviceCapability
->SystemWake
= AttachedCaps
.SystemWake
;
1639 DeviceCapability
->DeviceWake
= DeviceWakeLevel
;
1641 /* Now check if the wake level is D0, but the PDO doesn't support it */
1642 if ((DeviceCapability
->DeviceWake
== PowerDeviceD0
) &&
1643 !(DeviceCapability
->WakeFromD0
))
1646 DeviceCapability
->DeviceWake
= PowerDeviceD1
;
1649 /* Now check if the wake level is D1, but the PDO doesn't support it */
1650 if ((DeviceCapability
->DeviceWake
== PowerDeviceD1
) &&
1651 !(DeviceCapability
->WakeFromD1
))
1654 DeviceCapability
->DeviceWake
= PowerDeviceD2
;
1657 /* Now check if the wake level is D2, but the PDO doesn't support it */
1658 if ((DeviceCapability
->DeviceWake
== PowerDeviceD2
) &&
1659 !(DeviceCapability
->WakeFromD2
))
1662 DeviceCapability
->DeviceWake
= PowerDeviceD3
;
1665 /* Now check if the wake level is D3, but the PDO doesn't support it */
1666 if ((DeviceCapability
->DeviceWake
== PowerDeviceD3
) &&
1667 !(DeviceCapability
->WakeFromD3
))
1669 /* Then no valid wake state exists */
1670 DeviceCapability
->DeviceWake
= PowerDeviceUnspecified
;
1671 DeviceCapability
->SystemWake
= PowerSystemUnspecified
;
1674 /* Check if no valid wake state was found */
1675 if ((DeviceCapability
->DeviceWake
== PowerDeviceUnspecified
) ||
1676 (DeviceCapability
->SystemWake
== PowerSystemUnspecified
))
1678 /* Check if one was computed earlier */
1679 if ((SystemWakeState
!= PowerSystemUnspecified
) &&
1680 (DeviceWakeState
!= PowerDeviceUnspecified
))
1682 /* Use the wake state that had been computed earlier */
1683 DeviceCapability
->DeviceWake
= DeviceWakeState
;
1684 DeviceCapability
->SystemWake
= SystemWakeState
;
1686 /* If that state was D3, then the device supports Hot/Cold D3 */
1687 if (DeviceWakeState
== PowerDeviceD3
) DeviceCapability
->WakeFromD3
= TRUE
;
1692 * Finally, check for off states (lower than S3, such as hibernate) and
1693 * make sure that the device both supports waking from D3 as well as
1694 * supports a Cold wake
1696 if ((DeviceCapability
->SystemWake
> PowerSystemSleeping3
) &&
1697 ((DeviceCapability
->DeviceWake
!= PowerDeviceD3
) ||
1698 !(PdoExtension
->PowerCapabilities
.Support
.PMED3Cold
)))
1700 /* It doesn't, so pick the computed lowest wake state from earlier */
1701 DeviceCapability
->SystemWake
= DeepestWakeState
;
1704 /* Set the PCI Specification mandated maximum latencies for transitions */
1705 DeviceCapability
->D1Latency
= 0;
1706 DeviceCapability
->D2Latency
= 2;
1707 DeviceCapability
->D3Latency
= 100;
1710 ASSERT(DeviceCapability
->DeviceState
[PowerSystemWorking
] == PowerDeviceD0
);
1714 /* No valid sleep states, no latencies to worry about */
1715 DeviceCapability
->D1Latency
= 0;
1716 DeviceCapability
->D2Latency
= 0;
1717 DeviceCapability
->D3Latency
= 0;
1720 /* This function always succeeds, even without power management support */
1721 return STATUS_SUCCESS
;
1726 PciQueryCapabilities(IN PPCI_PDO_EXTENSION PdoExtension
,
1727 IN OUT PDEVICE_CAPABILITIES DeviceCapability
)
1731 /* A PDO ID is never unique, and its address is its function and device */
1732 DeviceCapability
->UniqueID
= FALSE
;
1733 DeviceCapability
->Address
= PdoExtension
->Slot
.u
.bits
.FunctionNumber
|
1734 (PdoExtension
->Slot
.u
.bits
.DeviceNumber
<< 16);
1736 /* Check for host bridges */
1737 if ((PdoExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1738 (PdoExtension
->SubClass
== PCI_SUBCLASS_BR_HOST
))
1740 /* Raw device opens to a host bridge are acceptable */
1741 DeviceCapability
->RawDeviceOK
= TRUE
;
1745 /* Otherwise, other PDOs cannot be directly opened */
1746 DeviceCapability
->RawDeviceOK
= FALSE
;
1749 /* PCI PDOs are pretty fixed things */
1750 DeviceCapability
->LockSupported
= FALSE
;
1751 DeviceCapability
->EjectSupported
= FALSE
;
1752 DeviceCapability
->Removable
= FALSE
;
1753 DeviceCapability
->DockDevice
= FALSE
;
1755 /* The slot number is stored as a device property, go query it */
1756 PciDetermineSlotNumber(PdoExtension
, &DeviceCapability
->UINumber
);
1758 /* Finally, query and power capabilities and convert them for PnP usage */
1759 Status
= PciQueryPowerCapabilities(PdoExtension
, DeviceCapability
);
1761 /* Dump the capabilities if it all worked, and return the status */
1762 if (NT_SUCCESS(Status
)) PciDebugDumpQueryCapabilities(DeviceCapability
);
1766 PCM_PARTIAL_RESOURCE_DESCRIPTOR
1768 PciNextPartialDescriptor(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor
)
1770 PCM_PARTIAL_RESOURCE_DESCRIPTOR NextDescriptor
;
1772 /* Assume the descriptors are the fixed size ones */
1773 NextDescriptor
= CmDescriptor
+ 1;
1775 /* But check if this is actually a variable-sized descriptor */
1776 if (CmDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
1778 /* Add the size of the variable section as well */
1779 NextDescriptor
= (PVOID
)((ULONG_PTR
)NextDescriptor
+
1780 CmDescriptor
->u
.DeviceSpecificData
.DataSize
);
1783 /* Now the correct pointer has been computed, return it */
1784 return NextDescriptor
;