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 RTL_RANGE_LIST PciIsaBitExclusionList
;
18 RTL_RANGE_LIST PciVgaAndIsaBitExclusionList
;
20 /* FUNCTIONS ******************************************************************/
24 PciUnicodeStringStrStr(IN PUNICODE_STRING InputString
,
25 IN PCUNICODE_STRING EqualString
,
26 IN BOOLEAN CaseInSensitive
)
28 UNICODE_STRING PartialString
;
29 LONG EqualChars
, TotalChars
;
31 /* Build a partial string with the smaller substring */
32 PartialString
.Length
= EqualString
->Length
;
33 PartialString
.MaximumLength
= InputString
->MaximumLength
;;
34 PartialString
.Buffer
= InputString
->Buffer
;
36 /* Check how many characters that need comparing */
38 TotalChars
= (InputString
->Length
- EqualString
->Length
) / sizeof(WCHAR
);
40 /* If the substring is bigger, just fail immediately */
41 if (TotalChars
< 0) return FALSE
;
43 /* Keep checking each character */
44 while (!RtlEqualUnicodeString(EqualString
, &PartialString
, CaseInSensitive
))
46 /* Continue checking until all the required characters are equal */
47 PartialString
.Buffer
++;
48 PartialString
.MaximumLength
-= sizeof(WCHAR
);
49 if (++EqualChars
> TotalChars
) return FALSE
;
52 /* The string is equal */
58 PciStringToUSHORT(IN PWCHAR String
,
62 ULONG Low
, High
, Length
;
65 /* Initialize everything to zero */
70 /* Get the character and set the high byte based on the previous one */
74 /* Check for numbers */
75 if ( Char
>= '0' && Char
<= '9' )
77 /* Convert them to a byte */
80 else if ( Char
>= 'A' && Char
<= 'F' )
82 /* Convert upper-case hex letters into a byte */
85 else if ( Char
>= 'a' && Char
<= 'f' )
87 /* Convert lower-case hex letters into a byte */
92 /* Invalid string, fail the conversion */
96 /* Combine the high and low byte */
99 /* If 4 letters have been reached, the 16-bit integer should exist */
102 /* Return it to the caller */
111 PciIsSuiteVersion(IN USHORT SuiteMask
)
114 RTL_OSVERSIONINFOEXW VersionInfo
;
116 /* Initialize the version information */
117 RtlZeroMemory(&VersionInfo
, sizeof(RTL_OSVERSIONINFOEXW
));
118 VersionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
119 VersionInfo
.wSuiteMask
= SuiteMask
;
121 /* Set the comparison mask and return if the passed suite mask matches */
122 VER_SET_CONDITION(Mask
, VER_SUITENAME
, VER_AND
);
123 return NT_SUCCESS(RtlVerifyVersionInfo(&VersionInfo
, VER_SUITENAME
, Mask
));
128 PciIsDatacenter(VOID
)
135 /* Assume this isn't Datacenter */
138 /* First, try opening the setup key */
139 Status
= PciGetRegistryValue(L
"",
140 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\setupdd",
145 if (!NT_SUCCESS(Status
))
147 /* This is not an in-progress Setup boot, so query the suite version */
148 Result
= PciIsSuiteVersion(VER_SUITE_DATACENTER
);
152 /* This scenario shouldn't happen yet, since SetupDD isn't used */
157 /* Return if this is Datacenter or not */
163 PciOpenKey(IN PWCHAR KeyName
,
165 IN ACCESS_MASK DesiredAccess
,
166 OUT PHANDLE KeyHandle
,
167 OUT PNTSTATUS KeyStatus
)
170 OBJECT_ATTRIBUTES ObjectAttributes
;
171 UNICODE_STRING KeyString
;
174 /* Initialize the object attributes */
175 RtlInitUnicodeString(&KeyString
, KeyName
);
176 InitializeObjectAttributes(&ObjectAttributes
,
178 OBJ_CASE_INSENSITIVE
,
182 /* Open the key, returning a boolean, and the status, if requested */
183 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
184 if (KeyStatus
) *KeyStatus
= Status
;
185 return NT_SUCCESS(Status
);
190 PciGetRegistryValue(IN PWCHAR ValueName
,
192 IN HANDLE RootHandle
,
194 OUT PVOID
*OutputBuffer
,
195 OUT PULONG OutputLength
)
198 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
199 ULONG NeededLength
, ActualLength
;
200 UNICODE_STRING ValueString
;
204 /* So we know what to free at the end of the body */
209 /* Open the key by name, rooted off the handle passed */
210 Result
= PciOpenKey(KeyName
,
217 /* Query for the size that's needed for the value that was passed in */
218 RtlInitUnicodeString(&ValueString
, ValueName
);
219 Status
= ZwQueryValueKey(KeyHandle
,
221 KeyValuePartialInformation
,
225 ASSERT(!NT_SUCCESS(Status
));
226 if (Status
!= STATUS_BUFFER_TOO_SMALL
) break;
228 /* Allocate an appropriate buffer for the size that was returned */
229 ASSERT(NeededLength
!= 0);
230 Status
= STATUS_INSUFFICIENT_RESOURCES
;
231 PartialInfo
= ExAllocatePoolWithTag(PagedPool
,
234 if (!PartialInfo
) break;
236 /* Query the actual value information now that the size is known */
237 Status
= ZwQueryValueKey(KeyHandle
,
239 KeyValuePartialInformation
,
243 if (!NT_SUCCESS(Status
)) break;
245 /* Make sure it's of the type that the caller expects */
246 Status
= STATUS_INVALID_PARAMETER
;
247 if (PartialInfo
->Type
!= Type
) break;
249 /* Subtract the registry-specific header, to get the data size */
250 ASSERT(NeededLength
== ActualLength
);
251 NeededLength
-= sizeof(KEY_VALUE_PARTIAL_INFORMATION
);
253 /* Allocate a buffer to hold the data and return it to the caller */
254 Status
= STATUS_INSUFFICIENT_RESOURCES
;
255 *OutputBuffer
= ExAllocatePoolWithTag(PagedPool
,
258 if (!*OutputBuffer
) break;
260 /* Copy the data into the buffer and return its length to the caller */
261 RtlCopyMemory(*OutputBuffer
, PartialInfo
->Data
, NeededLength
);
262 if (OutputLength
) *OutputLength
= NeededLength
;
263 Status
= STATUS_SUCCESS
;
266 /* Close any opened keys and free temporary allocations */
267 if (KeyHandle
) ZwClose(KeyHandle
);
268 if (PartialInfo
) ExFreePoolWithTag(PartialInfo
, 0);
274 PciBuildDefaultExclusionLists(VOID
)
278 ASSERT(PciIsaBitExclusionList
.Count
== 0);
279 ASSERT(PciVgaAndIsaBitExclusionList
.Count
== 0);
281 /* Initialize the range lists */
282 RtlInitializeRangeList(&PciIsaBitExclusionList
);
283 RtlInitializeRangeList(&PciVgaAndIsaBitExclusionList
);
285 /* Loop x86 I/O ranges */
286 for (Start
= 0x100; Start
<= 0xFEFF; Start
+= 0x400)
288 /* Add the ISA I/O ranges */
289 Status
= RtlAddRange(&PciIsaBitExclusionList
,
293 RTL_RANGE_LIST_ADD_IF_CONFLICT
,
296 if (!NT_SUCCESS(Status
)) break;
298 /* Add the ISA I/O ranges */
299 Status
= RtlAddRange(&PciVgaAndIsaBitExclusionList
,
303 RTL_RANGE_LIST_ADD_IF_CONFLICT
,
306 if (!NT_SUCCESS(Status
)) break;
308 /* Add the VGA I/O range for Monochrome Video */
309 Status
= RtlAddRange(&PciVgaAndIsaBitExclusionList
,
313 RTL_RANGE_LIST_ADD_IF_CONFLICT
,
316 if (!NT_SUCCESS(Status
)) break;
318 /* Add the VGA I/O range for certain CGA adapters */
319 Status
= RtlAddRange(&PciVgaAndIsaBitExclusionList
,
323 RTL_RANGE_LIST_ADD_IF_CONFLICT
,
326 if (!NT_SUCCESS(Status
)) break;
328 /* Success, ranges added done */
331 RtlFreeRangeList(&PciIsaBitExclusionList
);
332 RtlFreeRangeList(&PciVgaAndIsaBitExclusionList
);
338 PciFindParentPciFdoExtension(IN PDEVICE_OBJECT DeviceObject
,
341 PPCI_FDO_EXTENSION FoundExtension
;
343 /* Assume we'll find nothing */
344 FoundExtension
= NULL
;
346 /* Check if a lock was specified */
349 /* Wait for the lock to be released */
350 KeEnterCriticalRegion();
351 KeWaitForSingleObject(Lock
, Executive
, KernelMode
, FALSE
, NULL
);
354 /* Now search for the extension */
355 if (PciFdoExtensionListHead
.Next
)
357 /* This case should not be hit yet */
362 /* Check if we had acquired a lock previously */
366 KeSetEvent(Lock
, IO_NO_INCREMENT
, FALSE
);
367 KeLeaveCriticalRegion();
370 /* Return which extension was found, if any */
371 return FoundExtension
;
376 PciInsertEntryAtTail(IN PSINGLE_LIST_ENTRY ListHead
,
377 IN PPCI_FDO_EXTENSION DeviceExtension
,
380 PSINGLE_LIST_ENTRY NextEntry
;
383 /* Check if a lock was specified */
386 /* Wait for the lock to be released */
387 KeEnterCriticalRegion();
388 KeWaitForSingleObject(Lock
, Executive
, KernelMode
, FALSE
, NULL
);
391 /* Loop the list until we get to the end, then insert this entry there */
392 for (NextEntry
= ListHead
; NextEntry
->Next
; NextEntry
= NextEntry
->Next
);
393 NextEntry
->Next
= &DeviceExtension
->List
;
395 /* Check if we had acquired a lock previously */
399 KeSetEvent(Lock
, IO_NO_INCREMENT
, FALSE
);
400 KeLeaveCriticalRegion();
406 PciInsertEntryAtHead(IN PSINGLE_LIST_ENTRY ListHead
,
407 IN PSINGLE_LIST_ENTRY Entry
,
412 /* Check if a lock was specified */
415 /* Wait for the lock to be released */
416 KeEnterCriticalRegion();
417 KeWaitForSingleObject(Lock
, Executive
, KernelMode
, FALSE
, NULL
);
420 /* Make the entry point to the current head and make the head point to it */
421 Entry
->Next
= ListHead
->Next
;
422 ListHead
->Next
= Entry
;
424 /* Check if we had acquired a lock previously */
428 KeSetEvent(Lock
, IO_NO_INCREMENT
, FALSE
);
429 KeLeaveCriticalRegion();
435 PcipLinkSecondaryExtension(IN PSINGLE_LIST_ENTRY List
,
437 IN PPCI_SECONDARY_EXTENSION SecondaryExtension
,
438 IN PCI_SIGNATURE ExtensionType
,
443 /* Setup the extension data, and insert it into the primary's list */
444 SecondaryExtension
->ExtensionType
= ExtensionType
;
445 SecondaryExtension
->Destructor
= Destructor
;
446 PciInsertEntryAtHead(List
, &SecondaryExtension
->List
, Lock
);
451 PciGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
452 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
453 OUT PVOID
*OutputBuffer
)
456 ULONG BufferLength
, ResultLength
;
460 /* Query the requested property size */
461 Status
= IoGetDeviceProperty(DeviceObject
,
466 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
468 /* Call should've failed with buffer too small! */
469 DPRINT1("PCI - Unexpected status from GetDeviceProperty, saw %08X, expected %08X.\n",
471 STATUS_BUFFER_TOO_SMALL
);
472 *OutputBuffer
= NULL
;
473 ASSERTMSG(FALSE
, "PCI Successfully did the impossible!");
477 /* Allocate the required buffer */
478 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferLength
, 'BicP');
481 /* No memory, fail the request */
482 DPRINT1("PCI - Failed to allocate DeviceProperty buffer (%d bytes).\n", BufferLength
);
483 Status
= STATUS_INSUFFICIENT_RESOURCES
;
487 /* Do the actual property query call */
488 Status
= IoGetDeviceProperty(DeviceObject
,
493 if (!NT_SUCCESS(Status
)) break;
495 /* Return the buffer to the caller */
496 ASSERT(BufferLength
== ResultLength
);
497 *OutputBuffer
= Buffer
;
498 return STATUS_SUCCESS
;
502 return STATUS_UNSUCCESSFUL
;
507 PciSendIoctl(IN PDEVICE_OBJECT DeviceObject
,
508 IN ULONG IoControlCode
,
509 IN PVOID InputBuffer
,
510 IN ULONG InputBufferLength
,
511 IN PVOID OutputBuffer
,
512 IN ULONG OutputBufferLength
)
517 IO_STATUS_BLOCK IoStatusBlock
;
518 PDEVICE_OBJECT AttachedDevice
;
521 /* Initialize the pending IRP event */
522 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
524 /* Get a reference to the root PDO (ACPI) */
525 AttachedDevice
= IoGetAttachedDeviceReference(DeviceObject
);
526 if (!AttachedDevice
) return STATUS_INVALID_PARAMETER
;
528 /* Build the requested IOCTL IRP */
529 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
,
538 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
540 /* Send the IOCTL to the driver */
541 Status
= IoCallDriver(AttachedDevice
, Irp
);
542 if (Status
== STATUS_PENDING
)
544 /* Wait for a response */
545 KeWaitForSingleObject(&Event
,
550 Status
= Irp
->IoStatus
.Status
;
553 /* Take away the reference we took and return the result to the caller */
554 ObDereferenceObject(AttachedDevice
);