ed60cb5597393307ff941b35bd8602b78b71580d
[reactos.git] / reactos / drivers / bus / pcix / utils.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 RTL_RANGE_LIST PciIsaBitExclusionList;
18 RTL_RANGE_LIST PciVgaAndIsaBitExclusionList;
19
20 /* FUNCTIONS ******************************************************************/
21
22 BOOLEAN
23 NTAPI
24 PciUnicodeStringStrStr(IN PUNICODE_STRING InputString,
25 IN PCUNICODE_STRING EqualString,
26 IN BOOLEAN CaseInSensitive)
27 {
28 UNICODE_STRING PartialString;
29 LONG EqualChars, TotalChars;
30
31 /* Build a partial string with the smaller substring */
32 PartialString.Length = EqualString->Length;
33 PartialString.MaximumLength = InputString->MaximumLength;;
34 PartialString.Buffer = InputString->Buffer;
35
36 /* Check how many characters that need comparing */
37 EqualChars = 0;
38 TotalChars = (InputString->Length - EqualString->Length) / sizeof(WCHAR);
39
40 /* If the substring is bigger, just fail immediately */
41 if (TotalChars < 0) return FALSE;
42
43 /* Keep checking each character */
44 while (!RtlEqualUnicodeString(EqualString, &PartialString, CaseInSensitive))
45 {
46 /* Continue checking until all the required characters are equal */
47 PartialString.Buffer++;
48 PartialString.MaximumLength -= sizeof(WCHAR);
49 if (++EqualChars > TotalChars) return FALSE;
50 }
51
52 /* The string is equal */
53 return TRUE;
54 }
55
56 BOOLEAN
57 NTAPI
58 PciStringToUSHORT(IN PWCHAR String,
59 OUT PUSHORT Value)
60 {
61 USHORT Short;
62 ULONG Low, High, Length;
63 WCHAR Char;
64
65 /* Initialize everything to zero */
66 Short = 0;
67 Length = 0;
68 while (TRUE)
69 {
70 /* Get the character and set the high byte based on the previous one */
71 Char = *String++;
72 High = 16 * Short;
73
74 /* Check for numbers */
75 if ( Char >= '0' && Char <= '9' )
76 {
77 /* Convert them to a byte */
78 Low = Char - '0';
79 }
80 else if ( Char >= 'A' && Char <= 'F' )
81 {
82 /* Convert upper-case hex letters into a byte */
83 Low = Char - '7';
84 }
85 else if ( Char >= 'a' && Char <= 'f' )
86 {
87 /* Convert lower-case hex letters into a byte */
88 Low = Char - 'W';
89 }
90 else
91 {
92 /* Invalid string, fail the conversion */
93 return FALSE;
94 }
95
96 /* Combine the high and low byte */
97 Short = High | Low;
98
99 /* If 4 letters have been reached, the 16-bit integer should exist */
100 if (++Length >= 4)
101 {
102 /* Return it to the caller */
103 *Value = Short;
104 return TRUE;
105 }
106 }
107 }
108
109 BOOLEAN
110 NTAPI
111 PciIsSuiteVersion(IN USHORT SuiteMask)
112 {
113 ULONGLONG Mask = 0;
114 RTL_OSVERSIONINFOEXW VersionInfo;
115
116 /* Initialize the version information */
117 RtlZeroMemory(&VersionInfo, sizeof(RTL_OSVERSIONINFOEXW));
118 VersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
119 VersionInfo.wSuiteMask = SuiteMask;
120
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));
124 }
125
126 BOOLEAN
127 NTAPI
128 PciIsDatacenter(VOID)
129 {
130 BOOLEAN Result;
131 PVOID Value;
132 ULONG ResultLength;
133 NTSTATUS Status;
134
135 /* Assume this isn't Datacenter */
136 Result = FALSE;
137
138 /* First, try opening the setup key */
139 Status = PciGetRegistryValue(L"",
140 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\setupdd",
141 0,
142 REG_BINARY,
143 &Value,
144 &ResultLength);
145 if (!NT_SUCCESS(Status))
146 {
147 /* This is not an in-progress Setup boot, so query the suite version */
148 Result = PciIsSuiteVersion(VER_SUITE_DATACENTER);
149 }
150 else
151 {
152 /* This scenario shouldn't happen yet, since SetupDD isn't used */
153 UNIMPLEMENTED;
154 while (TRUE);
155 }
156
157 /* Return if this is Datacenter or not */
158 return Result;
159 }
160
161 BOOLEAN
162 NTAPI
163 PciOpenKey(IN PWCHAR KeyName,
164 IN HANDLE RootKey,
165 IN ACCESS_MASK DesiredAccess,
166 OUT PHANDLE KeyHandle,
167 OUT PNTSTATUS KeyStatus)
168 {
169 NTSTATUS Status;
170 OBJECT_ATTRIBUTES ObjectAttributes;
171 UNICODE_STRING KeyString;
172 PAGED_CODE();
173
174 /* Initialize the object attributes */
175 RtlInitUnicodeString(&KeyString, KeyName);
176 InitializeObjectAttributes(&ObjectAttributes,
177 &KeyString,
178 OBJ_CASE_INSENSITIVE,
179 RootKey,
180 NULL);
181
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);
186 }
187
188 NTSTATUS
189 NTAPI
190 PciGetRegistryValue(IN PWCHAR ValueName,
191 IN PWCHAR KeyName,
192 IN HANDLE RootHandle,
193 IN ULONG Type,
194 OUT PVOID *OutputBuffer,
195 OUT PULONG OutputLength)
196 {
197 NTSTATUS Status;
198 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
199 ULONG NeededLength, ActualLength;
200 UNICODE_STRING ValueString;
201 HANDLE KeyHandle;
202 BOOLEAN Result;
203
204 /* So we know what to free at the end of the body */
205 PartialInfo = NULL;
206 KeyHandle = NULL;
207 do
208 {
209 /* Open the key by name, rooted off the handle passed */
210 Result = PciOpenKey(KeyName,
211 RootHandle,
212 KEY_QUERY_VALUE,
213 &KeyHandle,
214 &Status);
215 if (!Result) break;
216
217 /* Query for the size that's needed for the value that was passed in */
218 RtlInitUnicodeString(&ValueString, ValueName);
219 Status = ZwQueryValueKey(KeyHandle,
220 &ValueString,
221 KeyValuePartialInformation,
222 NULL,
223 0,
224 &NeededLength);
225 ASSERT(!NT_SUCCESS(Status));
226 if (Status != STATUS_BUFFER_TOO_SMALL) break;
227
228 /* Allocate an appropriate buffer for the size that was returned */
229 ASSERT(NeededLength != 0);
230 Status = STATUS_INSUFFICIENT_RESOURCES;
231 PartialInfo = ExAllocatePoolWithTag(PagedPool,
232 NeededLength,
233 PCI_POOL_TAG);
234 if (!PartialInfo) break;
235
236 /* Query the actual value information now that the size is known */
237 Status = ZwQueryValueKey(KeyHandle,
238 &ValueString,
239 KeyValuePartialInformation,
240 PartialInfo,
241 NeededLength,
242 &ActualLength);
243 if (!NT_SUCCESS(Status)) break;
244
245 /* Make sure it's of the type that the caller expects */
246 Status = STATUS_INVALID_PARAMETER;
247 if (PartialInfo->Type != Type) break;
248
249 /* Subtract the registry-specific header, to get the data size */
250 ASSERT(NeededLength == ActualLength);
251 NeededLength -= sizeof(KEY_VALUE_PARTIAL_INFORMATION);
252
253 /* Allocate a buffer to hold the data and return it to the caller */
254 Status = STATUS_INSUFFICIENT_RESOURCES;
255 *OutputBuffer = ExAllocatePoolWithTag(PagedPool,
256 NeededLength,
257 PCI_POOL_TAG);
258 if (!*OutputBuffer) break;
259
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;
264 } while (0);
265
266 /* Close any opened keys and free temporary allocations */
267 if (KeyHandle) ZwClose(KeyHandle);
268 if (PartialInfo) ExFreePoolWithTag(PartialInfo, 0);
269 return Status;
270 }
271
272 NTSTATUS
273 NTAPI
274 PciBuildDefaultExclusionLists(VOID)
275 {
276 ULONG Start;
277 NTSTATUS Status;
278 ASSERT(PciIsaBitExclusionList.Count == 0);
279 ASSERT(PciVgaAndIsaBitExclusionList.Count == 0);
280
281 /* Initialize the range lists */
282 RtlInitializeRangeList(&PciIsaBitExclusionList);
283 RtlInitializeRangeList(&PciVgaAndIsaBitExclusionList);
284
285 /* Loop x86 I/O ranges */
286 for (Start = 0x100; Start <= 0xFEFF; Start += 0x400)
287 {
288 /* Add the ISA I/O ranges */
289 Status = RtlAddRange(&PciIsaBitExclusionList,
290 Start,
291 Start + 0x2FF,
292 0,
293 RTL_RANGE_LIST_ADD_IF_CONFLICT,
294 NULL,
295 NULL);
296 if (!NT_SUCCESS(Status)) break;
297
298 /* Add the ISA I/O ranges */
299 Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
300 Start,
301 Start + 0x2AF,
302 0,
303 RTL_RANGE_LIST_ADD_IF_CONFLICT,
304 NULL,
305 NULL);
306 if (!NT_SUCCESS(Status)) break;
307
308 /* Add the VGA I/O range for Monochrome Video */
309 Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
310 Start + 0x2BC,
311 Start + 0x2BF,
312 0,
313 RTL_RANGE_LIST_ADD_IF_CONFLICT,
314 NULL,
315 NULL);
316 if (!NT_SUCCESS(Status)) break;
317
318 /* Add the VGA I/O range for certain CGA adapters */
319 Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
320 Start + 0x2E0,
321 Start + 0x2FF,
322 0,
323 RTL_RANGE_LIST_ADD_IF_CONFLICT,
324 NULL,
325 NULL);
326 if (!NT_SUCCESS(Status)) break;
327
328 /* Success, ranges added done */
329 };
330
331 RtlFreeRangeList(&PciIsaBitExclusionList);
332 RtlFreeRangeList(&PciVgaAndIsaBitExclusionList);
333 return Status;
334 }
335
336 PPCI_FDO_EXTENSION
337 NTAPI
338 PciFindParentPciFdoExtension(IN PDEVICE_OBJECT DeviceObject,
339 IN PKEVENT Lock)
340 {
341 PPCI_FDO_EXTENSION DeviceExtension;
342 PPCI_PDO_EXTENSION SearchExtension, FoundExtension;
343
344 /* Assume we'll find nothing */
345 SearchExtension = DeviceObject->DeviceExtension;
346 FoundExtension = NULL;
347
348 /* Check if a lock was specified */
349 if (Lock)
350 {
351 /* Wait for the lock to be released */
352 KeEnterCriticalRegion();
353 KeWaitForSingleObject(Lock, Executive, KernelMode, FALSE, NULL);
354 }
355
356 /* Now search for the extension */
357 DeviceExtension = (PPCI_FDO_EXTENSION)PciFdoExtensionListHead.Next;
358 while (DeviceExtension)
359 {
360 /* Acquire this device's lock */
361 KeEnterCriticalRegion();
362 KeWaitForSingleObject(&DeviceExtension->ChildListLock,
363 Executive,
364 KernelMode,
365 FALSE,
366 NULL);
367
368 /* Scan all children PDO, stop when no more PDOs, or found it */
369 for (FoundExtension = DeviceExtension->ChildPdoList;
370 FoundExtension && (FoundExtension != SearchExtension);
371 FoundExtension = FoundExtension->Next);
372
373 /* If we found it, break out */
374 if (FoundExtension) break;
375
376 /* Release this device's lock */
377 KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE);
378 KeLeaveCriticalRegion();
379
380 /* Move to the next device */
381 DeviceExtension = (PPCI_FDO_EXTENSION)DeviceExtension->List.Next;
382 }
383
384 /* Check if we had acquired a lock previously */
385 if (Lock)
386 {
387 /* Release it */
388 KeSetEvent(Lock, IO_NO_INCREMENT, FALSE);
389 KeLeaveCriticalRegion();
390 }
391
392 /* Return which extension was found, if any */
393 return DeviceExtension;
394 }
395
396 VOID
397 NTAPI
398 PciInsertEntryAtTail(IN PSINGLE_LIST_ENTRY ListHead,
399 IN PPCI_FDO_EXTENSION DeviceExtension,
400 IN PKEVENT Lock)
401 {
402 PSINGLE_LIST_ENTRY NextEntry;
403 PAGED_CODE();
404
405 /* Check if a lock was specified */
406 if (Lock)
407 {
408 /* Wait for the lock to be released */
409 KeEnterCriticalRegion();
410 KeWaitForSingleObject(Lock, Executive, KernelMode, FALSE, NULL);
411 }
412
413 /* Loop the list until we get to the end, then insert this entry there */
414 for (NextEntry = ListHead; NextEntry->Next; NextEntry = NextEntry->Next);
415 NextEntry->Next = &DeviceExtension->List;
416
417 /* Check if we had acquired a lock previously */
418 if (Lock)
419 {
420 /* Release it */
421 KeSetEvent(Lock, IO_NO_INCREMENT, FALSE);
422 KeLeaveCriticalRegion();
423 }
424 }
425
426 VOID
427 NTAPI
428 PciInsertEntryAtHead(IN PSINGLE_LIST_ENTRY ListHead,
429 IN PSINGLE_LIST_ENTRY Entry,
430 IN PKEVENT Lock)
431 {
432 PAGED_CODE();
433
434 /* Check if a lock was specified */
435 if (Lock)
436 {
437 /* Wait for the lock to be released */
438 KeEnterCriticalRegion();
439 KeWaitForSingleObject(Lock, Executive, KernelMode, FALSE, NULL);
440 }
441
442 /* Make the entry point to the current head and make the head point to it */
443 Entry->Next = ListHead->Next;
444 ListHead->Next = Entry;
445
446 /* Check if we had acquired a lock previously */
447 if (Lock)
448 {
449 /* Release it */
450 KeSetEvent(Lock, IO_NO_INCREMENT, FALSE);
451 KeLeaveCriticalRegion();
452 }
453 }
454
455 VOID
456 NTAPI
457 PcipLinkSecondaryExtension(IN PSINGLE_LIST_ENTRY List,
458 IN PVOID Lock,
459 IN PPCI_SECONDARY_EXTENSION SecondaryExtension,
460 IN PCI_SIGNATURE ExtensionType,
461 IN PVOID Destructor)
462 {
463 PAGED_CODE();
464
465 /* Setup the extension data, and insert it into the primary's list */
466 SecondaryExtension->ExtensionType = ExtensionType;
467 SecondaryExtension->Destructor = Destructor;
468 PciInsertEntryAtHead(List, &SecondaryExtension->List, Lock);
469 }
470
471 NTSTATUS
472 NTAPI
473 PciGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
474 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
475 OUT PVOID *OutputBuffer)
476 {
477 NTSTATUS Status;
478 ULONG BufferLength, ResultLength;
479 PVOID Buffer;
480 do
481 {
482 /* Query the requested property size */
483 Status = IoGetDeviceProperty(DeviceObject,
484 DeviceProperty,
485 0,
486 NULL,
487 &BufferLength);
488 if (Status != STATUS_BUFFER_TOO_SMALL)
489 {
490 /* Call should've failed with buffer too small! */
491 DPRINT1("PCI - Unexpected status from GetDeviceProperty, saw %08X, expected %08X.\n",
492 Status,
493 STATUS_BUFFER_TOO_SMALL);
494 *OutputBuffer = NULL;
495 ASSERTMSG(FALSE, "PCI Successfully did the impossible!");
496 break;
497 }
498
499 /* Allocate the required buffer */
500 Buffer = ExAllocatePoolWithTag(PagedPool, BufferLength, 'BicP');
501 if (!Buffer)
502 {
503 /* No memory, fail the request */
504 DPRINT1("PCI - Failed to allocate DeviceProperty buffer (%d bytes).\n", BufferLength);
505 Status = STATUS_INSUFFICIENT_RESOURCES;
506 break;
507 }
508
509 /* Do the actual property query call */
510 Status = IoGetDeviceProperty(DeviceObject,
511 DeviceProperty,
512 BufferLength,
513 Buffer,
514 &ResultLength);
515 if (!NT_SUCCESS(Status)) break;
516
517 /* Return the buffer to the caller */
518 ASSERT(BufferLength == ResultLength);
519 *OutputBuffer = Buffer;
520 return STATUS_SUCCESS;
521 } while (FALSE);
522
523 /* Failure path */
524 return STATUS_UNSUCCESSFUL;
525 }
526
527 NTSTATUS
528 NTAPI
529 PciSendIoctl(IN PDEVICE_OBJECT DeviceObject,
530 IN ULONG IoControlCode,
531 IN PVOID InputBuffer,
532 IN ULONG InputBufferLength,
533 IN PVOID OutputBuffer,
534 IN ULONG OutputBufferLength)
535 {
536 PIRP Irp;
537 NTSTATUS Status;
538 KEVENT Event;
539 IO_STATUS_BLOCK IoStatusBlock;
540 PDEVICE_OBJECT AttachedDevice;
541 PAGED_CODE();
542
543 /* Initialize the pending IRP event */
544 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
545
546 /* Get a reference to the root PDO (ACPI) */
547 AttachedDevice = IoGetAttachedDeviceReference(DeviceObject);
548 if (!AttachedDevice) return STATUS_INVALID_PARAMETER;
549
550 /* Build the requested IOCTL IRP */
551 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
552 AttachedDevice,
553 InputBuffer,
554 InputBufferLength,
555 OutputBuffer,
556 OutputBufferLength,
557 0,
558 &Event,
559 &IoStatusBlock);
560 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
561
562 /* Send the IOCTL to the driver */
563 Status = IoCallDriver(AttachedDevice, Irp);
564 if (Status == STATUS_PENDING)
565 {
566 /* Wait for a response */
567 KeWaitForSingleObject(&Event,
568 Executive,
569 KernelMode,
570 FALSE,
571 NULL);
572 Status = Irp->IoStatus.Status;
573 }
574
575 /* Take away the reference we took and return the result to the caller */
576 ObDereferenceObject(AttachedDevice);
577 return Status;
578 }
579
580 PPCI_SECONDARY_EXTENSION
581 NTAPI
582 PciFindNextSecondaryExtension(IN PSINGLE_LIST_ENTRY ListHead,
583 IN PCI_SIGNATURE ExtensionType)
584 {
585 PSINGLE_LIST_ENTRY NextEntry;
586 PPCI_SECONDARY_EXTENSION Extension;
587
588 /* Scan the list */
589 for (NextEntry = ListHead; NextEntry; NextEntry = NextEntry->Next)
590 {
591 /* Grab each extension and check if it's the one requested */
592 Extension = CONTAINING_RECORD(NextEntry, PCI_SECONDARY_EXTENSION, List);
593 if (Extension->ExtensionType == ExtensionType) return Extension;
594 }
595
596 /* Nothing was found */
597 return NULL;
598 }
599
600 ULONGLONG
601 NTAPI
602 PciGetHackFlags(IN USHORT VendorId,
603 IN USHORT DeviceId,
604 IN USHORT SubVendorId,
605 IN USHORT SubSystemId,
606 IN UCHAR RevisionId)
607 {
608 PPCI_HACK_ENTRY HackEntry;
609 ULONGLONG HackFlags;
610 ULONG LastWeight, MatchWeight;
611 ULONG EntryFlags;
612
613 /* Initialize the variables before looping */
614 LastWeight = 0;
615 HackFlags = 0;
616 ASSERT(PciHackTable);
617
618 /* Scan the hack table */
619 for (HackEntry = PciHackTable;
620 HackEntry->VendorID != PCI_INVALID_VENDORID;
621 ++HackEntry)
622 {
623 /* Check if there's an entry for this device */
624 if ((HackEntry->DeviceID == DeviceId) &&
625 (HackEntry->VendorID == VendorId))
626 {
627 /* This is a basic match */
628 EntryFlags = HackEntry->Flags;
629 MatchWeight = 1;
630
631 /* Does the entry have revision information? */
632 if (EntryFlags & PCI_HACK_HAS_REVISION_INFO)
633 {
634 /* Check if the revision matches, if so, this is a better match */
635 if (HackEntry->RevisionID != RevisionId) continue;
636 MatchWeight = 3;
637 }
638
639 /* Does the netry have subsystem information? */
640 if (EntryFlags & PCI_HACK_HAS_SUBSYSTEM_INFO)
641 {
642 /* Check if it matches, if so, this is the best possible match */
643 if ((HackEntry->SubVendorID != SubVendorId) ||
644 (HackEntry->SubSystemID != SubSystemId))
645 {
646 continue;
647 }
648 MatchWeight += 4;
649 }
650
651 /* Is this the best match yet? */
652 if (MatchWeight > LastWeight)
653 {
654 /* This is the best match for now, use this as the hack flags */
655 HackFlags = HackEntry->HackFlags;
656 LastWeight = MatchWeight;
657 }
658 }
659 }
660
661 /* Return the best match */
662 return HackFlags;
663 }
664
665 BOOLEAN
666 NTAPI
667 PciIsCriticalDeviceClass(IN UCHAR BaseClass,
668 IN UCHAR SubClass)
669 {
670 /* Check for system or bridge devices */
671 if (BaseClass == PCI_CLASS_BASE_SYSTEM_DEV)
672 {
673 /* Interrupt controlers are critical */
674 return SubClass == PCI_SUBCLASS_SYS_INTERRUPT_CTLR;
675 }
676 else if (BaseClass == PCI_CLASS_BRIDGE_DEV)
677 {
678 /* ISA Bridges are critical */
679 return SubClass == PCI_SUBCLASS_BR_ISA;
680 }
681 else
682 {
683 /* All display controllers are critical */
684 return BaseClass == PCI_CLASS_DISPLAY_CTLR;
685 }
686 }
687
688 PPCI_PDO_EXTENSION
689 NTAPI
690 PciFindPdoByFunction(IN PPCI_FDO_EXTENSION DeviceExtension,
691 IN ULONG FunctionNumber,
692 IN PPCI_COMMON_HEADER PciData)
693 {
694 KIRQL Irql;
695 PPCI_PDO_EXTENSION PdoExtension;
696
697 /* Get the current IRQL when this call was made */
698 Irql = KeGetCurrentIrql();
699
700 /* Is this a low-IRQL call? */
701 if (Irql < DISPATCH_LEVEL)
702 {
703 /* Acquire this device's lock */
704 KeEnterCriticalRegion();
705 KeWaitForSingleObject(&DeviceExtension->ChildListLock,
706 Executive,
707 KernelMode,
708 FALSE,
709 NULL);
710 }
711
712 /* Loop every child PDO */
713 for (PdoExtension = DeviceExtension->ChildPdoList;
714 PdoExtension;
715 PdoExtension = PdoExtension->Next)
716 {
717 /* Find only enumerated PDOs */
718 if (!PdoExtension->ReportedMissing)
719 {
720 /* Check if the function number and header data matches */
721 if ((FunctionNumber == PdoExtension->Slot.u.AsULONG) &&
722 (PdoExtension->VendorId == PciData->VendorID) &&
723 (PdoExtension->DeviceId == PciData->DeviceID) &&
724 (PdoExtension->RevisionId == PciData->RevisionID))
725 {
726 /* This is considered to be the same PDO */
727 break;
728 }
729 }
730 }
731
732 /* Was this a low-IRQL call? */
733 if (Irql < DISPATCH_LEVEL)
734 {
735 /* Release this device's lock */
736 KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE);
737 KeLeaveCriticalRegion();
738 }
739
740 /* If the search found something, this is non-NULL, otherwise it's NULL */
741 return PdoExtension;
742 }
743
744 /* EOF */