ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

utils.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS PCI Bus Driver
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            drivers/bus/pci/utils.c
00005  * PURPOSE:         Utility/Helper Support Code
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <pci.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* GLOBALS ********************************************************************/
00016 
00017 ULONG PciDebugPortsCount;
00018 
00019 RTL_RANGE_LIST PciIsaBitExclusionList;
00020 RTL_RANGE_LIST PciVgaAndIsaBitExclusionList;
00021 
00022 /* FUNCTIONS ******************************************************************/
00023 
00024 BOOLEAN
00025 NTAPI
00026 PciUnicodeStringStrStr(IN PUNICODE_STRING InputString,
00027                        IN PCUNICODE_STRING EqualString,
00028                        IN BOOLEAN CaseInSensitive)
00029 {
00030     UNICODE_STRING PartialString;
00031     LONG EqualChars, TotalChars;
00032 
00033     /* Build a partial string with the smaller substring */
00034     PartialString.Length = EqualString->Length;
00035     PartialString.MaximumLength = InputString->MaximumLength;;
00036     PartialString.Buffer = InputString->Buffer;
00037 
00038     /* Check how many characters that need comparing */
00039     EqualChars = 0;
00040     TotalChars = (InputString->Length - EqualString->Length) / sizeof(WCHAR);
00041 
00042     /* If the substring is bigger, just fail immediately */
00043     if (TotalChars < 0) return FALSE;
00044 
00045     /* Keep checking each character */
00046     while (!RtlEqualUnicodeString(EqualString, &PartialString, CaseInSensitive))
00047     {
00048         /* Continue checking until all the required characters are equal */
00049         PartialString.Buffer++;
00050         PartialString.MaximumLength -= sizeof(WCHAR);
00051         if (++EqualChars > TotalChars) return FALSE;
00052     }
00053 
00054     /* The string is equal */
00055     return TRUE;
00056 }
00057 
00058 BOOLEAN
00059 NTAPI
00060 PciStringToUSHORT(IN PWCHAR String,
00061                   OUT PUSHORT Value)
00062 {
00063     USHORT Short;
00064     ULONG Low, High, Length;
00065     WCHAR Char;
00066 
00067     /* Initialize everything to zero */
00068     Short = 0;
00069     Length = 0;
00070     while (TRUE)
00071     {
00072         /* Get the character and set the high byte based on the previous one */
00073         Char = *String++;
00074         High = 16 * Short;
00075 
00076         /* Check for numbers */
00077         if ( Char >= '0' && Char <= '9' )
00078         {
00079             /* Convert them to a byte */
00080             Low = Char - '0';
00081         }
00082         else if ( Char >= 'A' && Char <= 'F' )
00083         {
00084             /* Convert upper-case hex letters into a byte */
00085             Low = Char - '7';
00086         }
00087         else if ( Char >= 'a' && Char <= 'f' )
00088         {
00089             /* Convert lower-case hex letters into a byte */
00090             Low = Char - 'W';
00091         }
00092         else
00093         {
00094             /* Invalid string, fail the conversion */
00095             return FALSE;
00096         }
00097 
00098         /* Combine the high and low byte */
00099         Short = High | Low;
00100 
00101         /* If 4 letters have been reached, the 16-bit integer should exist */
00102         if (++Length >= 4)
00103         {
00104             /* Return it to the caller */
00105             *Value = Short;
00106             return TRUE;
00107         }
00108     }
00109 }
00110 
00111 BOOLEAN
00112 NTAPI
00113 PciIsSuiteVersion(IN USHORT SuiteMask)
00114 {
00115     ULONGLONG Mask = 0;
00116     RTL_OSVERSIONINFOEXW VersionInfo;
00117 
00118     /* Initialize the version information */
00119     RtlZeroMemory(&VersionInfo, sizeof(RTL_OSVERSIONINFOEXW));
00120     VersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
00121     VersionInfo.wSuiteMask = SuiteMask;
00122 
00123     /* Set the comparison mask and return if the passed suite mask matches */
00124     VER_SET_CONDITION(Mask, VER_SUITENAME, VER_AND);
00125     return NT_SUCCESS(RtlVerifyVersionInfo(&VersionInfo, VER_SUITENAME, Mask));
00126 }
00127 
00128 BOOLEAN
00129 NTAPI
00130 PciIsDatacenter(VOID)
00131 {
00132     BOOLEAN Result;
00133     PVOID Value;
00134     ULONG ResultLength;
00135     NTSTATUS Status;
00136 
00137     /* Assume this isn't Datacenter */
00138     Result = FALSE;
00139 
00140     /* First, try opening the setup key */
00141     Status = PciGetRegistryValue(L"",
00142                                  L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\setupdd",
00143                                  0,
00144                                  REG_BINARY,
00145                                  &Value,
00146                                  &ResultLength);
00147     if (!NT_SUCCESS(Status))
00148     {
00149         /* This is not an in-progress Setup boot, so query the suite version */
00150         Result = PciIsSuiteVersion(VER_SUITE_DATACENTER);
00151     }
00152     else
00153     {
00154         /* This scenario shouldn't happen yet, since SetupDD isn't used */
00155         UNIMPLEMENTED;
00156         while (TRUE);
00157     }
00158 
00159     /* Return if this is Datacenter or not */
00160     return Result;
00161 }
00162 
00163 BOOLEAN
00164 NTAPI
00165 PciOpenKey(IN PWCHAR KeyName,
00166            IN HANDLE RootKey,
00167            IN ACCESS_MASK DesiredAccess,
00168            OUT PHANDLE KeyHandle,
00169            OUT PNTSTATUS KeyStatus)
00170 {
00171     NTSTATUS Status;
00172     OBJECT_ATTRIBUTES ObjectAttributes;
00173     UNICODE_STRING KeyString;
00174     PAGED_CODE();
00175 
00176     /* Initialize the object attributes */
00177     RtlInitUnicodeString(&KeyString, KeyName);
00178     InitializeObjectAttributes(&ObjectAttributes,
00179                                &KeyString,
00180                                OBJ_CASE_INSENSITIVE,
00181                                RootKey,
00182                                NULL);
00183 
00184     /* Open the key, returning a boolean, and the status, if requested */
00185     Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
00186     if (KeyStatus) *KeyStatus = Status;
00187     return NT_SUCCESS(Status);
00188 }
00189 
00190 NTSTATUS
00191 NTAPI
00192 PciGetRegistryValue(IN PWCHAR ValueName,
00193                     IN PWCHAR KeyName,
00194                     IN HANDLE RootHandle,
00195                     IN ULONG Type,
00196                     OUT PVOID *OutputBuffer,
00197                     OUT PULONG OutputLength)
00198 {
00199     NTSTATUS Status;
00200     PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
00201     ULONG NeededLength, ActualLength;
00202     UNICODE_STRING ValueString;
00203     HANDLE KeyHandle;
00204     BOOLEAN Result;
00205 
00206     /* So we know what to free at the end of the body */
00207     PartialInfo = NULL;
00208     KeyHandle = NULL;
00209     do
00210     {
00211         /* Open the key by name, rooted off the handle passed */
00212         Result = PciOpenKey(KeyName,
00213                             RootHandle,
00214                             KEY_QUERY_VALUE,
00215                             &KeyHandle,
00216                             &Status);
00217         if (!Result) break;
00218 
00219         /* Query for the size that's needed for the value that was passed in */
00220         RtlInitUnicodeString(&ValueString, ValueName);
00221         Status = ZwQueryValueKey(KeyHandle,
00222                                  &ValueString,
00223                                  KeyValuePartialInformation,
00224                                  NULL,
00225                                  0,
00226                                  &NeededLength);
00227         ASSERT(!NT_SUCCESS(Status));
00228         if (Status != STATUS_BUFFER_TOO_SMALL) break;
00229 
00230         /* Allocate an appropriate buffer for the size that was returned */
00231         ASSERT(NeededLength != 0);
00232         Status = STATUS_INSUFFICIENT_RESOURCES;
00233         PartialInfo = ExAllocatePoolWithTag(PagedPool,
00234                                             NeededLength,
00235                                             PCI_POOL_TAG);
00236         if (!PartialInfo) break;
00237 
00238         /* Query the actual value information now that the size is known */
00239         Status = ZwQueryValueKey(KeyHandle,
00240                                  &ValueString,
00241                                  KeyValuePartialInformation,
00242                                  PartialInfo,
00243                                  NeededLength,
00244                                  &ActualLength);
00245         if (!NT_SUCCESS(Status)) break;
00246 
00247         /* Make sure it's of the type that the caller expects */
00248         Status = STATUS_INVALID_PARAMETER;
00249         if (PartialInfo->Type != Type) break;
00250 
00251         /* Subtract the registry-specific header, to get the data size */
00252         ASSERT(NeededLength == ActualLength);
00253         NeededLength -= sizeof(KEY_VALUE_PARTIAL_INFORMATION);
00254 
00255         /* Allocate a buffer to hold the data and return it to the caller */
00256         Status = STATUS_INSUFFICIENT_RESOURCES;
00257         *OutputBuffer = ExAllocatePoolWithTag(PagedPool,
00258                                               NeededLength,
00259                                               PCI_POOL_TAG);
00260         if (!*OutputBuffer) break;
00261 
00262         /* Copy the data into the buffer and return its length to the caller */
00263         RtlCopyMemory(*OutputBuffer, PartialInfo->Data, NeededLength);
00264         if (OutputLength) *OutputLength = NeededLength;
00265         Status = STATUS_SUCCESS;
00266     } while (0);
00267 
00268     /* Close any opened keys and free temporary allocations */
00269     if (KeyHandle) ZwClose(KeyHandle);
00270     if (PartialInfo) ExFreePoolWithTag(PartialInfo, 0);
00271     return Status;
00272 }
00273 
00274 NTSTATUS
00275 NTAPI
00276 PciBuildDefaultExclusionLists(VOID)
00277 {
00278     ULONG Start;
00279     NTSTATUS Status;
00280     ASSERT(PciIsaBitExclusionList.Count == 0);
00281     ASSERT(PciVgaAndIsaBitExclusionList.Count == 0);
00282 
00283     /* Initialize the range lists */
00284     RtlInitializeRangeList(&PciIsaBitExclusionList);
00285     RtlInitializeRangeList(&PciVgaAndIsaBitExclusionList);
00286 
00287     /* Loop x86 I/O ranges */
00288     for (Start = 0x100; Start <= 0xFEFF; Start += 0x400)
00289     {
00290         /* Add the ISA I/O ranges */
00291         Status = RtlAddRange(&PciIsaBitExclusionList,
00292                              Start,
00293                              Start + 0x2FF,
00294                              0,
00295                              RTL_RANGE_LIST_ADD_IF_CONFLICT,
00296                              NULL,
00297                              NULL);
00298         if (!NT_SUCCESS(Status)) break;
00299 
00300         /* Add the ISA I/O ranges */
00301         Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
00302                              Start,
00303                              Start + 0x2AF,
00304                              0,
00305                              RTL_RANGE_LIST_ADD_IF_CONFLICT,
00306                              NULL,
00307                              NULL);
00308         if (!NT_SUCCESS(Status)) break;
00309 
00310         /* Add the VGA I/O range for Monochrome Video */
00311         Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
00312                              Start + 0x2BC,
00313                              Start + 0x2BF,
00314                              0,
00315                              RTL_RANGE_LIST_ADD_IF_CONFLICT,
00316                              NULL,
00317                              NULL);
00318         if (!NT_SUCCESS(Status)) break;
00319 
00320         /* Add the VGA I/O range for certain CGA adapters */
00321         Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
00322                              Start + 0x2E0,
00323                              Start + 0x2FF,
00324                              0,
00325                              RTL_RANGE_LIST_ADD_IF_CONFLICT,
00326                              NULL,
00327                              NULL);
00328         if (!NT_SUCCESS(Status)) break;
00329 
00330         /* Success, ranges added done */
00331     };
00332 
00333     RtlFreeRangeList(&PciIsaBitExclusionList);
00334     RtlFreeRangeList(&PciVgaAndIsaBitExclusionList);
00335     return Status;
00336 }
00337 
00338 PPCI_FDO_EXTENSION
00339 NTAPI
00340 PciFindParentPciFdoExtension(IN PDEVICE_OBJECT DeviceObject,
00341                              IN PKEVENT Lock)
00342 {
00343     PPCI_FDO_EXTENSION DeviceExtension;
00344     PPCI_PDO_EXTENSION SearchExtension, FoundExtension;
00345 
00346     /* Assume we'll find nothing */
00347     SearchExtension = DeviceObject->DeviceExtension;
00348     FoundExtension = NULL;
00349 
00350     /* Check if a lock was specified */
00351     if (Lock)
00352     {
00353         /* Wait for the lock to be released */
00354         KeEnterCriticalRegion();
00355         KeWaitForSingleObject(Lock, Executive, KernelMode, FALSE, NULL);
00356     }
00357 
00358     /* Now search for the extension */
00359     DeviceExtension = (PPCI_FDO_EXTENSION)PciFdoExtensionListHead.Next;
00360     while (DeviceExtension)
00361     {
00362         /* Acquire this device's lock */
00363         KeEnterCriticalRegion();
00364         KeWaitForSingleObject(&DeviceExtension->ChildListLock,
00365                               Executive,
00366                               KernelMode,
00367                               FALSE,
00368                               NULL);
00369 
00370         /* Scan all children PDO, stop when no more PDOs, or found it */
00371         for (FoundExtension = DeviceExtension->ChildPdoList;
00372              ((FoundExtension) && (FoundExtension != SearchExtension));
00373              FoundExtension = FoundExtension->Next);
00374 
00375         /* Release this device's lock */
00376         KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE);
00377         KeLeaveCriticalRegion();
00378 
00379         /* If we found it, break out */
00380         if (FoundExtension) break;
00381 
00382         /* Move to the next device */
00383         DeviceExtension = (PPCI_FDO_EXTENSION)DeviceExtension->List.Next;
00384     }
00385 
00386     /* Check if we had acquired a lock previously */
00387     if (Lock)
00388     {
00389         /* Release it */
00390         KeSetEvent(Lock, IO_NO_INCREMENT, FALSE);
00391         KeLeaveCriticalRegion();
00392     }
00393 
00394     /* Return which extension was found, if any */
00395     return DeviceExtension;
00396 }
00397 
00398 VOID
00399 NTAPI
00400 PciInsertEntryAtTail(IN PSINGLE_LIST_ENTRY ListHead,
00401                      IN PPCI_FDO_EXTENSION DeviceExtension,
00402                      IN PKEVENT Lock)
00403 {
00404     PSINGLE_LIST_ENTRY NextEntry;
00405     PAGED_CODE();
00406 
00407     /* Check if a lock was specified */
00408     if (Lock)
00409     {
00410         /* Wait for the lock to be released */
00411         KeEnterCriticalRegion();
00412         KeWaitForSingleObject(Lock, Executive, KernelMode, FALSE, NULL);
00413     }
00414 
00415     /* Loop the list until we get to the end, then insert this entry there */
00416     for (NextEntry = ListHead; NextEntry->Next; NextEntry = NextEntry->Next);
00417     NextEntry->Next = &DeviceExtension->List;
00418 
00419     /* Check if we had acquired a lock previously */
00420     if (Lock)
00421     {
00422         /* Release it */
00423         KeSetEvent(Lock, IO_NO_INCREMENT, FALSE);
00424         KeLeaveCriticalRegion();
00425     }
00426 }
00427 
00428 VOID
00429 NTAPI
00430 PciInsertEntryAtHead(IN PSINGLE_LIST_ENTRY ListHead,
00431                      IN PSINGLE_LIST_ENTRY Entry,
00432                      IN PKEVENT Lock)
00433 {
00434     PAGED_CODE();
00435 
00436     /* Check if a lock was specified */
00437     if (Lock)
00438     {
00439         /* Wait for the lock to be released */
00440         KeEnterCriticalRegion();
00441         KeWaitForSingleObject(Lock, Executive, KernelMode, FALSE, NULL);
00442     }
00443 
00444     /* Make the entry point to the current head and make the head point to it */
00445     Entry->Next = ListHead->Next;
00446     ListHead->Next = Entry;
00447 
00448     /* Check if we had acquired a lock previously */
00449     if (Lock)
00450     {
00451         /* Release it */
00452         KeSetEvent(Lock, IO_NO_INCREMENT, FALSE);
00453         KeLeaveCriticalRegion();
00454     }
00455 }
00456 
00457 VOID
00458 NTAPI
00459 PcipLinkSecondaryExtension(IN PSINGLE_LIST_ENTRY List,
00460                            IN PVOID Lock,
00461                            IN PPCI_SECONDARY_EXTENSION SecondaryExtension,
00462                            IN PCI_SIGNATURE ExtensionType,
00463                            IN PVOID Destructor)
00464 {
00465     PAGED_CODE();
00466 
00467     /* Setup the extension data, and insert it into the primary's list */
00468     SecondaryExtension->ExtensionType = ExtensionType;
00469     SecondaryExtension->Destructor = Destructor;
00470     PciInsertEntryAtHead(List, &SecondaryExtension->List, Lock);
00471 }
00472 
00473 NTSTATUS
00474 NTAPI
00475 PciGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
00476                      IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
00477                      OUT PVOID *OutputBuffer)
00478 {
00479     NTSTATUS Status;
00480     ULONG BufferLength, ResultLength;
00481     PVOID Buffer;
00482     do
00483     {
00484         /* Query the requested property size */
00485         Status = IoGetDeviceProperty(DeviceObject,
00486                                      DeviceProperty,
00487                                      0,
00488                                      NULL,
00489                                      &BufferLength);
00490         if (Status != STATUS_BUFFER_TOO_SMALL)
00491         {
00492             /* Call should've failed with buffer too small! */
00493             DPRINT1("PCI - Unexpected status from GetDeviceProperty, saw %08X, expected %08X.\n",
00494                     Status,
00495                     STATUS_BUFFER_TOO_SMALL);
00496             *OutputBuffer = NULL;
00497             ASSERTMSG(FALSE, "PCI Successfully did the impossible!");
00498             break;
00499         }
00500 
00501         /* Allocate the required buffer */
00502         Buffer = ExAllocatePoolWithTag(PagedPool, BufferLength, 'BicP');
00503         if (!Buffer)
00504         {
00505             /* No memory, fail the request */
00506             DPRINT1("PCI - Failed to allocate DeviceProperty buffer (%d bytes).\n", BufferLength);
00507             Status = STATUS_INSUFFICIENT_RESOURCES;
00508             break;
00509         }
00510 
00511         /* Do the actual property query call */
00512         Status = IoGetDeviceProperty(DeviceObject,
00513                                      DeviceProperty,
00514                                      BufferLength,
00515                                      Buffer,
00516                                      &ResultLength);
00517         if (!NT_SUCCESS(Status)) break;
00518 
00519         /* Return the buffer to the caller */
00520         ASSERT(BufferLength == ResultLength);
00521         *OutputBuffer = Buffer;
00522         return STATUS_SUCCESS;
00523     } while (FALSE);
00524 
00525     /* Failure path */
00526     return STATUS_UNSUCCESSFUL;
00527 }
00528 
00529 NTSTATUS
00530 NTAPI
00531 PciSendIoctl(IN PDEVICE_OBJECT DeviceObject,
00532              IN ULONG IoControlCode,
00533              IN PVOID InputBuffer,
00534              IN ULONG InputBufferLength,
00535              IN PVOID OutputBuffer,
00536              IN ULONG OutputBufferLength)
00537 {
00538     PIRP Irp;
00539     NTSTATUS Status;
00540     KEVENT Event;
00541     IO_STATUS_BLOCK IoStatusBlock;
00542     PDEVICE_OBJECT AttachedDevice;
00543     PAGED_CODE();
00544 
00545     /* Initialize the pending IRP event */
00546     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
00547 
00548     /* Get a reference to the root PDO (ACPI) */
00549     AttachedDevice = IoGetAttachedDeviceReference(DeviceObject);
00550     if (!AttachedDevice) return STATUS_INVALID_PARAMETER;
00551 
00552     /* Build the requested IOCTL IRP */
00553     Irp = IoBuildDeviceIoControlRequest(IoControlCode,
00554                                         AttachedDevice,
00555                                         InputBuffer,
00556                                         InputBufferLength,
00557                                         OutputBuffer,
00558                                         OutputBufferLength,
00559                                         0,
00560                                         &Event,
00561                                         &IoStatusBlock);
00562     if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
00563 
00564     /* Send the IOCTL to the driver */
00565     Status = IoCallDriver(AttachedDevice, Irp);
00566     if (Status == STATUS_PENDING)
00567     {
00568         /* Wait for a response */
00569         KeWaitForSingleObject(&Event,
00570                               Executive,
00571                               KernelMode,
00572                               FALSE,
00573                               NULL);
00574         Status = Irp->IoStatus.Status;
00575     }
00576 
00577     /* Take away the reference we took and return the result to the caller */
00578     ObDereferenceObject(AttachedDevice);
00579     return Status;
00580 }
00581 
00582 PPCI_SECONDARY_EXTENSION
00583 NTAPI
00584 PciFindNextSecondaryExtension(IN PSINGLE_LIST_ENTRY ListHead,
00585                               IN PCI_SIGNATURE ExtensionType)
00586 {
00587     PSINGLE_LIST_ENTRY NextEntry;
00588     PPCI_SECONDARY_EXTENSION Extension;
00589 
00590     /* Scan the list */
00591     for (NextEntry = ListHead; NextEntry; NextEntry = NextEntry->Next)
00592     {
00593         /* Grab each extension and check if it's the one requested */
00594         Extension = CONTAINING_RECORD(NextEntry, PCI_SECONDARY_EXTENSION, List);
00595         if (Extension->ExtensionType == ExtensionType) return Extension;
00596     }
00597 
00598     /* Nothing was found */
00599     return NULL;
00600 }
00601 
00602 ULONGLONG
00603 NTAPI
00604 PciGetHackFlags(IN USHORT VendorId,
00605                 IN USHORT DeviceId,
00606                 IN USHORT SubVendorId,
00607                 IN USHORT SubSystemId,
00608                 IN UCHAR RevisionId)
00609 {
00610     PPCI_HACK_ENTRY HackEntry;
00611     ULONGLONG HackFlags;
00612     ULONG LastWeight, MatchWeight;
00613     ULONG EntryFlags;
00614     
00615     /* ReactOS SetupLDR Hack */
00616     if (!PciHackTable) return 0;
00617 
00618     /* Initialize the variables before looping */
00619     LastWeight = 0;
00620     HackFlags = 0;
00621     ASSERT(PciHackTable);
00622 
00623     /* Scan the hack table */
00624     for (HackEntry = PciHackTable;
00625          HackEntry->VendorID != PCI_INVALID_VENDORID;
00626          ++HackEntry)
00627     {
00628         /* Check if there's an entry for this device */
00629         if ((HackEntry->DeviceID == DeviceId) &&
00630             (HackEntry->VendorID == VendorId))
00631         {
00632             /* This is a basic match */
00633             EntryFlags = HackEntry->Flags;
00634             MatchWeight = 1;
00635 
00636             /* Does the entry have revision information? */
00637             if (EntryFlags & PCI_HACK_HAS_REVISION_INFO)
00638             {
00639                 /* Check if the revision matches, if so, this is a better match */
00640                 if (HackEntry->RevisionID != RevisionId) continue;
00641                 MatchWeight = 3;
00642             }
00643 
00644             /* Does the netry have subsystem information? */
00645             if (EntryFlags & PCI_HACK_HAS_SUBSYSTEM_INFO)
00646             {
00647                 /* Check if it matches, if so, this is the best possible match */
00648                 if ((HackEntry->SubVendorID != SubVendorId) ||
00649                     (HackEntry->SubSystemID != SubSystemId))
00650                 {
00651                     continue;
00652                 }
00653                 MatchWeight += 4;
00654             }
00655 
00656             /* Is this the best match yet? */
00657             if (MatchWeight > LastWeight)
00658             {
00659                 /* This is the best match for now, use this as the hack flags */
00660                 HackFlags = HackEntry->HackFlags;
00661                 LastWeight = MatchWeight;
00662             }
00663         }
00664     }
00665 
00666     /* Return the best match */
00667     return HackFlags;
00668 }
00669 
00670 BOOLEAN
00671 NTAPI
00672 PciIsCriticalDeviceClass(IN UCHAR BaseClass,
00673                          IN UCHAR SubClass)
00674 {
00675     /* Check for system or bridge devices */
00676     if (BaseClass == PCI_CLASS_BASE_SYSTEM_DEV)
00677     {
00678         /* Interrupt controlers are critical */
00679         return SubClass == PCI_SUBCLASS_SYS_INTERRUPT_CTLR;
00680     }
00681     else if (BaseClass == PCI_CLASS_BRIDGE_DEV)
00682     {
00683         /* ISA Bridges are critical */
00684         return SubClass == PCI_SUBCLASS_BR_ISA;
00685     }
00686     else
00687     {
00688         /* All display controllers are critical */
00689         return BaseClass == PCI_CLASS_DISPLAY_CTLR;
00690     }
00691 }
00692 
00693 PPCI_PDO_EXTENSION
00694 NTAPI
00695 PciFindPdoByFunction(IN PPCI_FDO_EXTENSION DeviceExtension,
00696                      IN ULONG FunctionNumber,
00697                      IN PPCI_COMMON_HEADER PciData)
00698 {
00699     KIRQL Irql;
00700     PPCI_PDO_EXTENSION PdoExtension;
00701 
00702     /* Get the current IRQL when this call was made */
00703     Irql = KeGetCurrentIrql();
00704 
00705     /* Is this a low-IRQL call? */
00706     if (Irql < DISPATCH_LEVEL)
00707     {
00708         /* Acquire this device's lock */
00709         KeEnterCriticalRegion();
00710         KeWaitForSingleObject(&DeviceExtension->ChildListLock,
00711                               Executive,
00712                               KernelMode,
00713                               FALSE,
00714                               NULL);
00715     }
00716 
00717     /* Loop every child PDO */
00718     for (PdoExtension = DeviceExtension->ChildPdoList;
00719          PdoExtension;
00720          PdoExtension = PdoExtension->Next)
00721     {
00722         /* Find only enumerated PDOs */
00723         if (!PdoExtension->ReportedMissing)
00724         {
00725             /* Check if the function number and header data matches */
00726             if ((FunctionNumber == PdoExtension->Slot.u.AsULONG) &&
00727                 (PdoExtension->VendorId == PciData->VendorID) &&
00728                 (PdoExtension->DeviceId == PciData->DeviceID) &&
00729                 (PdoExtension->RevisionId == PciData->RevisionID))
00730             {
00731                 /* This is considered to be the same PDO */
00732                 break;
00733             }
00734         }
00735     }
00736 
00737     /* Was this a low-IRQL call? */
00738     if (Irql < DISPATCH_LEVEL)
00739     {
00740         /* Release this device's lock */
00741         KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE);
00742         KeLeaveCriticalRegion();
00743     }
00744 
00745     /* If the search found something, this is non-NULL, otherwise it's NULL */
00746     return PdoExtension;
00747 }
00748 
00749 BOOLEAN
00750 NTAPI
00751 PciIsDeviceOnDebugPath(IN PPCI_PDO_EXTENSION DeviceExtension)
00752 {
00753     PAGED_CODE();
00754 
00755     /* Check for too many, or no, debug ports */
00756     ASSERT(PciDebugPortsCount <= MAX_DEBUGGING_DEVICES_SUPPORTED);
00757     if (!PciDebugPortsCount) return FALSE;
00758 
00759     /* eVb has not been able to test such devices yet */
00760     UNIMPLEMENTED;
00761     while (TRUE);
00762 }
00763 
00764 NTSTATUS
00765 NTAPI
00766 PciGetBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
00767                  OUT PPCI_COMMON_HEADER PciData)
00768 {
00769     HANDLE KeyHandle, SubKeyHandle;
00770     OBJECT_ATTRIBUTES ObjectAttributes;
00771     UNICODE_STRING KeyName, KeyValue;
00772     WCHAR Buffer[32];
00773     WCHAR DataBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + PCI_COMMON_HDR_LENGTH];
00774     PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)DataBuffer;
00775     NTSTATUS Status;
00776     ULONG ResultLength;
00777     PAGED_CODE();
00778 
00779     /* Open the PCI key */
00780     Status = IoOpenDeviceRegistryKey(DeviceExtension->ParentFdoExtension->
00781                                      PhysicalDeviceObject,
00782                                      TRUE,
00783                                      KEY_ALL_ACCESS,
00784                                      &KeyHandle);
00785     if (!NT_SUCCESS(Status)) return Status;
00786 
00787     /* Create a volatile BIOS configuration key */
00788     RtlInitUnicodeString(&KeyName, L"BiosConfig");
00789     InitializeObjectAttributes(&ObjectAttributes,
00790                                &KeyName,
00791                                OBJ_KERNEL_HANDLE,
00792                                KeyHandle,
00793                                NULL);
00794     Status = ZwCreateKey(&SubKeyHandle,
00795                          KEY_READ,
00796                          &ObjectAttributes,
00797                          0,
00798                          NULL,
00799                          REG_OPTION_VOLATILE,
00800                          NULL);
00801     ZwClose(KeyHandle);
00802     if (!NT_SUCCESS(Status)) return Status;
00803 
00804     /* Create the key value based on the device and function number */
00805     swprintf(Buffer,
00806              L"DEV_%02x&FUN_%02x",
00807              DeviceExtension->Slot.u.bits.DeviceNumber,
00808              DeviceExtension->Slot.u.bits.FunctionNumber);
00809     RtlInitUnicodeString(&KeyValue, Buffer);
00810 
00811     /* Query the value information (PCI BIOS configuration header) */
00812     Status = ZwQueryValueKey(SubKeyHandle,
00813                              &KeyValue,
00814                              KeyValuePartialInformation,
00815                              PartialInfo,
00816                              sizeof(DataBuffer),
00817                              &ResultLength);
00818     ZwClose(SubKeyHandle);
00819     if (!NT_SUCCESS(Status)) return Status;
00820 
00821     /* If any information was returned, go ahead and copy its data */
00822     ASSERT(PartialInfo->DataLength == PCI_COMMON_HDR_LENGTH);
00823     RtlCopyMemory(PciData, PartialInfo->Data, PCI_COMMON_HDR_LENGTH);
00824     return Status;
00825 }
00826 
00827 NTSTATUS
00828 NTAPI
00829 PciSaveBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
00830                   IN PPCI_COMMON_HEADER PciData)
00831 {
00832     HANDLE KeyHandle, SubKeyHandle;
00833     OBJECT_ATTRIBUTES ObjectAttributes;
00834     UNICODE_STRING KeyName, KeyValue;
00835     WCHAR Buffer[32];
00836     NTSTATUS Status;
00837     PAGED_CODE();
00838 
00839     /* Open the PCI key */
00840     Status = IoOpenDeviceRegistryKey(DeviceExtension->ParentFdoExtension->
00841                                      PhysicalDeviceObject,
00842                                      TRUE,
00843                                      KEY_READ | KEY_WRITE,
00844                                      &KeyHandle);
00845     if (!NT_SUCCESS(Status)) return Status;
00846 
00847     /* Create a volatile BIOS configuration key */
00848     RtlInitUnicodeString(&KeyName, L"BiosConfig");
00849     InitializeObjectAttributes(&ObjectAttributes,
00850                                &KeyName,
00851                                OBJ_KERNEL_HANDLE,
00852                                KeyHandle,
00853                                NULL);
00854     Status = ZwCreateKey(&SubKeyHandle,
00855                          KEY_READ | KEY_WRITE,
00856                          &ObjectAttributes,
00857                          0,
00858                          NULL,
00859                          REG_OPTION_VOLATILE,
00860                          NULL);
00861     ZwClose(KeyHandle);
00862     if (!NT_SUCCESS(Status)) return Status;
00863 
00864     /* Create the key value based on the device and function number */
00865     swprintf(Buffer,
00866              L"DEV_%02x&FUN_%02x",
00867              DeviceExtension->Slot.u.bits.DeviceNumber,
00868              DeviceExtension->Slot.u.bits.FunctionNumber);
00869     RtlInitUnicodeString(&KeyValue, Buffer);
00870 
00871     /* Set the value data (the PCI BIOS configuration header) */
00872     Status = ZwSetValueKey(SubKeyHandle,
00873                            &KeyValue,
00874                            0,
00875                            REG_BINARY,
00876                            PciData,
00877                            PCI_COMMON_HDR_LENGTH);
00878     ZwClose(SubKeyHandle);
00879     return Status;
00880 }
00881 
00882 UCHAR
00883 NTAPI
00884 PciReadDeviceCapability(IN PPCI_PDO_EXTENSION DeviceExtension,
00885                         IN UCHAR Offset,
00886                         IN ULONG CapabilityId,
00887                         OUT PPCI_CAPABILITIES_HEADER Buffer,
00888                         IN ULONG Length)
00889 {
00890     ULONG CapabilityCount = 0;
00891 
00892     /* If the device has no capabilility list, fail */
00893     if (!Offset) return 0;
00894 
00895     /* Validate a PDO with capabilities, a valid buffer, and a valid length */
00896     ASSERT(DeviceExtension->ExtensionType == PciPdoExtensionType);
00897     ASSERT(DeviceExtension->CapabilitiesPtr != 0);
00898     ASSERT(Buffer);
00899     ASSERT(Length >= sizeof(PCI_CAPABILITIES_HEADER));
00900 
00901     /* Loop all capabilities */
00902     while (Offset)
00903     {
00904         /* Make sure the pointer is spec-aligned and spec-sized */
00905         ASSERT((Offset >= PCI_COMMON_HDR_LENGTH) && ((Offset & 0x3) == 0));
00906 
00907         /* Read the capability header */
00908         PciReadDeviceConfig(DeviceExtension,
00909                             Buffer,
00910                             Offset,
00911                             sizeof(PCI_CAPABILITIES_HEADER));
00912 
00913         /* Check if this is the capability being looked up */
00914         if ((Buffer->CapabilityID == CapabilityId) || !(CapabilityId))
00915         {
00916             /* Check if was at a valid offset and length */
00917             if ((Offset) && (Length > sizeof(PCI_CAPABILITIES_HEADER)))
00918             {
00919                 /* Sanity check */
00920                 ASSERT(Length <= (sizeof(PCI_COMMON_CONFIG) - Offset));
00921 
00922                 /* Now read the whole capability data into the buffer */
00923                 PciReadDeviceConfig(DeviceExtension,
00924                                     (PVOID)((ULONG_PTR)Buffer +
00925                                     sizeof(PCI_CAPABILITIES_HEADER)),
00926                                     Offset + sizeof(PCI_CAPABILITIES_HEADER),
00927                                     Length - sizeof(PCI_CAPABILITIES_HEADER));
00928             }
00929 
00930             /* Return the offset where the capability was found */
00931             return Offset;
00932         }
00933 
00934         /* Try the next capability instead */
00935         CapabilityCount++;
00936         Offset = Buffer->Next;
00937 
00938         /* There can't be more than 48 capabilities (256 bytes max) */
00939         if (CapabilityCount > 48)
00940         {
00941             /* Fail, since this is basically a broken PCI device */
00942             DPRINT1("PCI device %p capabilities list is broken.\n", DeviceExtension);
00943             return 0;
00944         }
00945     }
00946 
00947     /* Capability wasn't found, fail */
00948     return 0;
00949 }
00950 
00951 BOOLEAN
00952 NTAPI
00953 PciCanDisableDecodes(IN PPCI_PDO_EXTENSION DeviceExtension,
00954                      IN PPCI_COMMON_HEADER Config,
00955                      IN ULONGLONG HackFlags,
00956                      IN BOOLEAN ForPowerDown)
00957 {
00958     UCHAR BaseClass, SubClass;
00959     BOOLEAN IsVga;
00960 
00961     /* Is there a device extension or should the PCI header be used? */
00962     if (DeviceExtension)
00963     {
00964         /* Never disable decodes for a debug PCI Device */
00965         if (DeviceExtension->OnDebugPath) return FALSE;
00966 
00967         /* Hack flags will be obtained from the extension, not the caller */
00968         ASSERT(HackFlags == 0);
00969 
00970         /* Get hacks and classification from the device extension */
00971         HackFlags = DeviceExtension->HackFlags;
00972         SubClass = DeviceExtension->SubClass;
00973         BaseClass = DeviceExtension->BaseClass;
00974     }
00975     else
00976     {
00977         /* There must be a PCI header, go read the classification information */
00978         ASSERT(Config != NULL);
00979         BaseClass = Config->BaseClass;
00980         SubClass = Config->SubClass;
00981     }
00982 
00983     /* Check for hack flags that prevent disabling the decodes */
00984     if (HackFlags & (PCI_HACK_PRESERVE_COMMAND |
00985                      PCI_HACK_CB_SHARE_CMD_BITS |
00986                      PCI_HACK_DONT_DISABLE_DECODES))
00987     {
00988         /* Don't do it */
00989         return FALSE;
00990     }
00991 
00992     /* Is this a VGA adapter? */
00993     if ((BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
00994         (SubClass == PCI_SUBCLASS_VID_VGA_CTLR))
00995     {
00996         /* Never disable decodes if this is for power down */
00997         return ForPowerDown;
00998     }
00999 
01000     /* Check for legacy devices */
01001     if (BaseClass == PCI_CLASS_PRE_20)
01002     {
01003         /* Never disable video adapter cards if this is for power down */
01004         if (SubClass == PCI_SUBCLASS_PRE_20_VGA) return ForPowerDown;
01005     }
01006     else if (BaseClass == PCI_CLASS_DISPLAY_CTLR)
01007     {
01008         /* Never disable VGA adapters if this is for power down */
01009         if (SubClass == PCI_SUBCLASS_VID_VGA_CTLR) return ForPowerDown;
01010     }
01011     else if (BaseClass == PCI_CLASS_BRIDGE_DEV)
01012     {
01013         /* Check for legacy bridges */
01014         if ((SubClass == PCI_SUBCLASS_BR_ISA) ||
01015             (SubClass == PCI_SUBCLASS_BR_EISA) ||
01016             (SubClass == PCI_SUBCLASS_BR_MCA) ||
01017             (SubClass == PCI_SUBCLASS_BR_HOST) ||
01018             (SubClass == PCI_SUBCLASS_BR_OTHER))
01019         {
01020             /* Never disable these */
01021             return FALSE;
01022         }
01023         else if ((SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
01024                  (SubClass == PCI_SUBCLASS_BR_CARDBUS))
01025         {
01026             /* This is a supported bridge, but does it have a VGA card? */
01027             if (!DeviceExtension)
01028             {
01029                 /* Read the bridge control flag from the PCI header */
01030                 IsVga = Config->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA;
01031             }
01032             else
01033             {
01034                 /* Read the cached flag in the device extension */
01035                 IsVga = DeviceExtension->Dependent.type1.VgaBitSet;
01036             }
01037 
01038             /* Never disable VGA adapters if this is for power down */
01039             if (IsVga) return ForPowerDown;
01040         }
01041     }
01042 
01043     /* Finally, never disable decodes if there's no power management */
01044     return !(HackFlags & PCI_HACK_NO_PM_CAPS);
01045 }
01046 
01047 PCI_DEVICE_TYPES
01048 NTAPI
01049 PciClassifyDeviceType(IN PPCI_PDO_EXTENSION PdoExtension)
01050 {
01051     ASSERT(PdoExtension->ExtensionType == PciPdoExtensionType);
01052 
01053     /* Differenriate between devices and bridges */
01054     if (PdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) return PciTypeDevice;
01055 
01056     /* The PCI Bus driver handles only CardBus and PCI bridges (plus host) */
01057     if (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) return PciTypeHostBridge;
01058     if (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) return PciTypePciBridge;
01059     if (PdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS) return PciTypeCardbusBridge;
01060 
01061     /* Any other kind of bridge is treated like a device */
01062     return PciTypeDevice;
01063 }
01064 
01065 ULONG_PTR
01066 NTAPI
01067 PciExecuteCriticalSystemRoutine(IN ULONG_PTR IpiContext)
01068 {
01069     PPCI_IPI_CONTEXT Context = (PPCI_IPI_CONTEXT)IpiContext;
01070 
01071     /* Check if the IPI is already running */
01072     if (!InterlockedDecrement(&Context->RunCount))
01073     {
01074         /* Nope, this is the first instance, so execute the IPI function */
01075         Context->Function(Context->DeviceExtension, Context->Context);
01076 
01077         /* Notify anyone that was spinning that they can stop now */
01078         Context->Barrier = 0;
01079     }
01080     else
01081     {
01082         /* Spin until it has finished running */
01083         while (Context->Barrier);
01084     }
01085 
01086     /* Done */
01087     return 0;
01088 }
01089 
01090 BOOLEAN
01091 NTAPI
01092 PciIsSlotPresentInParentMethod(IN PPCI_PDO_EXTENSION PdoExtension,
01093                                IN ULONG Method)
01094 {
01095     BOOLEAN FoundSlot;
01096     PACPI_METHOD_ARGUMENT Argument;
01097     ACPI_EVAL_INPUT_BUFFER InputBuffer;
01098     PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
01099     ULONG i, Length;
01100     NTSTATUS Status;
01101     PAGED_CODE();
01102 
01103     /* Assume slot is not part of the parent method */
01104     FoundSlot = FALSE;
01105 
01106     /* Allocate a 2KB buffer for the method return parameters */
01107     Length = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 2048;
01108     OutputBuffer = ExAllocatePoolWithTag(PagedPool, Length, 'BicP');
01109     if (OutputBuffer)
01110     {
01111         /* Clear out the output buffer */
01112         RtlZeroMemory(OutputBuffer, Length);
01113 
01114         /* Initialize the input buffer with the method requested */
01115         InputBuffer.Signature = 0;
01116         *(PULONG)InputBuffer.MethodName = Method;
01117         InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
01118 
01119         /* Send it to the ACPI driver */
01120         Status = PciSendIoctl(PdoExtension->ParentFdoExtension->PhysicalDeviceObject,
01121                               IOCTL_ACPI_EVAL_METHOD,
01122                               &InputBuffer,
01123                               sizeof(ACPI_EVAL_INPUT_BUFFER),
01124                               OutputBuffer,
01125                               Length);
01126         if (NT_SUCCESS(Status))
01127         {
01128             /* Scan all output arguments */
01129             for (i = 0; i < OutputBuffer->Count; i++)
01130             {
01131                 /* Make sure it's an integer */
01132                 Argument = &OutputBuffer->Argument[i];
01133                 if (Argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) continue;
01134 
01135                 /* Check if the argument matches this PCI slot structure */
01136                 if (Argument->Argument == ((PdoExtension->Slot.u.bits.DeviceNumber) |
01137                                            ((PdoExtension->Slot.u.bits.FunctionNumber) << 16)))
01138                 {
01139                     /* This slot has been found, return it */
01140                     FoundSlot = TRUE;
01141                     break;
01142                 }
01143             }
01144         }
01145 
01146         /* Finished with the buffer, free it */
01147         ExFreePoolWithTag(OutputBuffer, 0);
01148     }
01149 
01150     /* Return if the slot was found */
01151     return FoundSlot;
01152 }
01153 
01154 ULONG
01155 NTAPI
01156 PciGetLengthFromBar(IN ULONG Bar)
01157 {
01158     ULONG Length;
01159 
01160     /* I/O addresses vs. memory addresses start differently due to alignment */
01161     Length = 1 << ((Bar & PCI_ADDRESS_IO_SPACE) ? 2 : 4);
01162 
01163     /* Keep going until a set bit */
01164     while (!(Length & Bar) && (Length)) Length <<= 1;
01165 
01166     /* Return the length (might be 0 on 64-bit because it's the low-word) */
01167     if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) != PCI_TYPE_64BIT) ASSERT(Length);
01168     return Length;
01169 }
01170 
01171 BOOLEAN
01172 NTAPI
01173 PciCreateIoDescriptorFromBarLimit(PIO_RESOURCE_DESCRIPTOR ResourceDescriptor,
01174                                   IN PULONG BarArray,
01175                                   IN BOOLEAN Rom)
01176 {
01177     ULONG CurrentBar, BarLength, BarMask;
01178     BOOLEAN Is64BitBar = FALSE;
01179 
01180     /* Check if the BAR is nor I/O nor memory */
01181     CurrentBar = BarArray[0];
01182     if (!(CurrentBar & ~PCI_ADDRESS_IO_SPACE))
01183     {
01184         /* Fail this descriptor */
01185         ResourceDescriptor->Type = CmResourceTypeNull;
01186         return FALSE;
01187     }
01188 
01189     /* Set default flag and clear high words */
01190     ResourceDescriptor->Flags = 0;
01191     ResourceDescriptor->u.Generic.MaximumAddress.HighPart = 0;
01192     ResourceDescriptor->u.Generic.MinimumAddress.LowPart = 0;
01193     ResourceDescriptor->u.Generic.MinimumAddress.HighPart = 0;
01194 
01195     /* Check for ROM Address */
01196     if (Rom)
01197     {
01198         /* Clean up the BAR to get just the address */
01199         CurrentBar &= PCI_ADDRESS_ROM_ADDRESS_MASK;
01200         if (!CurrentBar)
01201         {
01202             /* Invalid ar, fail this descriptor */
01203             ResourceDescriptor->Type = CmResourceTypeNull;
01204             return FALSE;
01205         }
01206 
01207         /* ROM Addresses are always read only */
01208         ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
01209     }
01210 
01211     /* Compute the length, assume it's the alignment for now */
01212     BarLength = PciGetLengthFromBar(CurrentBar);
01213     ResourceDescriptor->u.Generic.Length = BarLength;
01214     ResourceDescriptor->u.Generic.Alignment = BarLength;
01215 
01216     /* Check what kind of BAR this is */
01217     if (CurrentBar & PCI_ADDRESS_IO_SPACE)
01218     {
01219         /* Use correct mask to decode the address */
01220         BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
01221 
01222         /* Set this as an I/O Port descriptor */
01223         ResourceDescriptor->Type = CmResourceTypePort;
01224         ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
01225     }
01226     else
01227     {
01228         /* Use correct mask to decode the address */
01229         BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
01230 
01231         /* Set this as a memory descriptor */
01232         ResourceDescriptor->Type = CmResourceTypeMemory;
01233 
01234         /* Check if it's 64-bit or 20-bit decode */
01235         if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
01236         {
01237             /* The next BAR has the high word, read it */
01238             ResourceDescriptor->u.Port.MaximumAddress.HighPart = BarArray[1];
01239             Is64BitBar = TRUE;
01240         }
01241         else if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT)
01242         {
01243             /* Use the correct mask to decode the address */
01244             BarMask = ~0xFFF0000F;
01245         }
01246 
01247         /* Check if the BAR is listed as prefetchable memory */
01248         if (CurrentBar & PCI_ADDRESS_MEMORY_PREFETCHABLE)
01249         {
01250             /* Mark the descriptor in the same way */
01251             ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
01252         }
01253     }
01254 
01255     /* Now write down the maximum address based on the base + length */
01256     ResourceDescriptor->u.Port.MaximumAddress.QuadPart = (CurrentBar & BarMask) +
01257                                                          BarLength - 1;
01258 
01259     /* Return if this is a 64-bit BAR, so the loop code knows to skip the next one */
01260     return Is64BitBar;
01261 }
01262 
01263 VOID
01264 NTAPI
01265 PciDecodeEnable(IN PPCI_PDO_EXTENSION PdoExtension,
01266                 IN BOOLEAN Enable,
01267                 OUT PUSHORT Command)
01268 {
01269     USHORT CommandValue;
01270 
01271     /*
01272      * If decodes are being disabled, make sure it's allowed, and in both cases,
01273      * make sure that a hackflag isn't preventing touching the decodes at all.
01274      */
01275     if (((Enable) || (PciCanDisableDecodes(PdoExtension, 0, 0, 0))) &&
01276         !(PdoExtension->HackFlags & PCI_HACK_PRESERVE_COMMAND))
01277     {
01278         /* Did the caller already have a command word? */
01279         if (Command)
01280         {
01281             /* Use the caller's */
01282             CommandValue = *Command;
01283         }
01284         else
01285         {
01286             /* Otherwise, read the current command */
01287             PciReadDeviceConfig(PdoExtension,
01288                                 &Command,
01289                                 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
01290                                 sizeof(USHORT));
01291         }
01292 
01293         /* Turn off decodes by default */
01294         CommandValue &= ~(PCI_ENABLE_IO_SPACE |
01295                           PCI_ENABLE_MEMORY_SPACE |
01296                           PCI_ENABLE_BUS_MASTER);
01297 
01298         /* If requested, enable the decodes that were enabled at init time */
01299         if (Enable) CommandValue |= PdoExtension->CommandEnables &
01300                                     (PCI_ENABLE_IO_SPACE |
01301                                      PCI_ENABLE_MEMORY_SPACE |
01302                                      PCI_ENABLE_BUS_MASTER);
01303 
01304         /* Update the command word */
01305         PciWriteDeviceConfig(PdoExtension,
01306                              &CommandValue,
01307                              FIELD_OFFSET(PCI_COMMON_HEADER, Command),
01308                              sizeof(USHORT));
01309     }
01310 }
01311 
01312 NTSTATUS
01313 NTAPI
01314 PciQueryBusInformation(IN PPCI_PDO_EXTENSION PdoExtension,
01315                        IN PPNP_BUS_INFORMATION* Buffer)
01316 {
01317     PPNP_BUS_INFORMATION BusInfo;
01318 
01319     /* Allocate a structure for the bus information */
01320     BusInfo = ExAllocatePoolWithTag(PagedPool,
01321                                     sizeof(PNP_BUS_INFORMATION),
01322                                     'BicP');
01323     if (!BusInfo) return STATUS_INSUFFICIENT_RESOURCES;
01324 
01325     /* Write the correct GUID and bus type identifier, and fill the bus number */
01326     BusInfo->BusTypeGuid = GUID_BUS_TYPE_PCI;
01327     BusInfo->LegacyBusType = PCIBus;
01328     BusInfo->BusNumber = PdoExtension->ParentFdoExtension->BaseBus;
01329     return STATUS_SUCCESS;
01330 }
01331 
01332 NTSTATUS
01333 NTAPI
01334 PciDetermineSlotNumber(IN PPCI_PDO_EXTENSION PdoExtension,
01335                        OUT PULONG SlotNumber)
01336 {
01337     PPCI_FDO_EXTENSION ParentExtension;
01338     ULONG ResultLength;
01339     NTSTATUS Status;
01340     PSLOT_INFO SlotInfo;
01341 
01342     /* Check if a $PIR from the BIOS is used (legacy IRQ routing) */
01343     ParentExtension = PdoExtension->ParentFdoExtension;
01344     DPRINT1("Slot lookup for %d.%d.%d\n",
01345             ParentExtension ? ParentExtension->BaseBus : -1,
01346             PdoExtension->Slot.u.bits.DeviceNumber,
01347             PdoExtension->Slot.u.bits.FunctionNumber);
01348     if ((PciIrqRoutingTable) && (ParentExtension))
01349     {
01350         /* Read every slot information entry */
01351         SlotInfo = &PciIrqRoutingTable->Slot[0];
01352         DPRINT1("PIR$ %p is %lx bytes, slot 0 is at: %lx\n",
01353                 PciIrqRoutingTable, PciIrqRoutingTable->TableSize, SlotInfo);
01354         while (SlotInfo < (PSLOT_INFO)((ULONG_PTR)PciIrqRoutingTable +
01355                                        PciIrqRoutingTable->TableSize))
01356         {
01357             DPRINT1("Slot Info: %d.%d->#%d\n",
01358                     SlotInfo->BusNumber,
01359                     SlotInfo->DeviceNumber,
01360                     SlotInfo->SlotNumber);
01361 
01362             /* Check if this slot information matches the PDO being queried */
01363             if ((ParentExtension->BaseBus == SlotInfo->BusNumber) &&
01364                 (PdoExtension->Slot.u.bits.DeviceNumber == SlotInfo->DeviceNumber >> 3) &&
01365                 (SlotInfo->SlotNumber))
01366             {
01367                 /* We found it, return it and return success */
01368                 *SlotNumber = SlotInfo->SlotNumber;
01369                 return STATUS_SUCCESS;
01370             }
01371 
01372             /* Try the next slot */
01373             SlotInfo++;
01374         }
01375     }
01376 
01377     /* Otherwise, grab the parent FDO and check if it's the root */
01378     if (PCI_IS_ROOT_FDO(ParentExtension))
01379     {
01380         /* The root FDO doesn't have a slot number */
01381         Status = STATUS_UNSUCCESSFUL;
01382     }
01383     else
01384     {
01385         /* Otherwise, query the slot/UI address/number as a device property */
01386         Status = IoGetDeviceProperty(ParentExtension->PhysicalDeviceObject,
01387                                      DevicePropertyUINumber,
01388                                      sizeof(ULONG),
01389                                      SlotNumber,
01390                                      &ResultLength);
01391     }
01392 
01393     /* Return the status of this endeavour */
01394     return Status;
01395 }
01396 
01397 NTSTATUS
01398 NTAPI
01399 PciGetDeviceCapabilities(IN PDEVICE_OBJECT DeviceObject,
01400                          IN OUT PDEVICE_CAPABILITIES DeviceCapability)
01401 {
01402     PIRP Irp;
01403     NTSTATUS Status;
01404     KEVENT Event;
01405     PDEVICE_OBJECT AttachedDevice;
01406     PIO_STACK_LOCATION IoStackLocation;
01407     IO_STATUS_BLOCK IoStatusBlock;
01408     PAGED_CODE();
01409 
01410     /* Zero out capabilities and set undefined values to start with */
01411     RtlZeroMemory(DeviceCapability, sizeof(DEVICE_CAPABILITIES));
01412     DeviceCapability->Size = sizeof(DEVICE_CAPABILITIES);
01413     DeviceCapability->Version = 1;
01414     DeviceCapability->Address = -1;
01415     DeviceCapability->UINumber = -1;
01416 
01417     /* Build the wait event for the IOCTL */
01418     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
01419 
01420     /* Find the device the PDO is attached to */
01421     AttachedDevice = IoGetAttachedDeviceReference(DeviceObject);
01422 
01423     /* And build an IRP for it */
01424     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
01425                                        AttachedDevice,
01426                                        NULL,
01427                                        0,
01428                                        NULL,
01429                                        &Event,
01430                                        &IoStatusBlock);
01431     if (!Irp)
01432     {
01433         /* The IRP failed, fail the request as well */
01434         ObDereferenceObject(AttachedDevice);
01435         return STATUS_INSUFFICIENT_RESOURCES;
01436     }
01437 
01438     /* Set default status */
01439     Irp->IoStatus.Information = 0;
01440     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
01441 
01442     /* Get a stack location in this IRP */
01443     IoStackLocation = IoGetNextIrpStackLocation(Irp);
01444     ASSERT(IoStackLocation);
01445 
01446     /* Initialize it as a query capabilities IRP, with no completion routine */
01447     RtlZeroMemory(IoStackLocation, sizeof(IO_STACK_LOCATION));
01448     IoStackLocation->MajorFunction = IRP_MJ_PNP;
01449     IoStackLocation->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
01450     IoStackLocation->Parameters.DeviceCapabilities.Capabilities = DeviceCapability;
01451     IoSetCompletionRoutine(Irp, NULL, NULL, FALSE, FALSE, FALSE);
01452 
01453     /* Send the IOCTL to the driver */
01454     Status = IoCallDriver(AttachedDevice, Irp);
01455     if (Status == STATUS_PENDING)
01456     {
01457         /* Wait for a response and update the actual status */
01458         KeWaitForSingleObject(&Event,
01459                               Executive,
01460                               KernelMode,
01461                               FALSE,
01462                               NULL);
01463         Status = Irp->IoStatus.Status;
01464     }
01465 
01466     /* Done, dereference the attached device and return the final result */
01467     ObDereferenceObject(AttachedDevice);
01468     return Status;
01469 }
01470 
01471 NTSTATUS
01472 NTAPI
01473 PciQueryPowerCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
01474                           IN PDEVICE_CAPABILITIES DeviceCapability)
01475 {
01476     PDEVICE_OBJECT DeviceObject;
01477     NTSTATUS Status;
01478     DEVICE_CAPABILITIES AttachedCaps;
01479     DEVICE_POWER_STATE NewPowerState, DevicePowerState, DeviceWakeLevel, DeviceWakeState;
01480     SYSTEM_POWER_STATE SystemWakeState, DeepestWakeState, CurrentState;
01481 
01482     /* Nothing is known at first */
01483     DeviceWakeState = PowerDeviceUnspecified;
01484     SystemWakeState = DeepestWakeState = PowerSystemUnspecified;
01485 
01486     /* Get the PCI capabilities for the parent PDO */
01487     DeviceObject = PdoExtension->ParentFdoExtension->PhysicalDeviceObject;
01488     Status = PciGetDeviceCapabilities(DeviceObject, &AttachedCaps);
01489     ASSERT(NT_SUCCESS(Status));
01490     if (!NT_SUCCESS(Status)) return Status;
01491 
01492     /* Check if there's not an existing device state for S0 */
01493     if (!AttachedCaps.DeviceState[PowerSystemWorking])
01494     {
01495         /* Set D0<->S0 mapping */
01496         AttachedCaps.DeviceState[PowerSystemWorking] = PowerDeviceD0;
01497     }
01498 
01499     /* Check if there's not an existing device state for S3 */
01500     if (!AttachedCaps.DeviceState[PowerSystemShutdown])
01501     {
01502         /* Set D3<->S3 mapping */
01503         AttachedCaps.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
01504     }
01505 
01506     /* Check for a PDO with broken, or no, power capabilities */
01507     if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
01508     {
01509         /* Unknown wake device states */
01510         DeviceCapability->DeviceWake = PowerDeviceUnspecified;
01511         DeviceCapability->SystemWake = PowerSystemUnspecified;
01512 
01513         /* No device state support */
01514         DeviceCapability->DeviceD1 = FALSE;
01515         DeviceCapability->DeviceD2 = FALSE;
01516 
01517         /* No waking from any low-power device state is supported */
01518         DeviceCapability->WakeFromD0 = FALSE;
01519         DeviceCapability->WakeFromD1 = FALSE;
01520         DeviceCapability->WakeFromD2 = FALSE;
01521         DeviceCapability->WakeFromD3 = FALSE;
01522 
01523         /* For the rest, copy whatever the parent PDO had */
01524         RtlCopyMemory(DeviceCapability->DeviceState,
01525                       AttachedCaps.DeviceState,
01526                       sizeof(DeviceCapability->DeviceState));
01527         return STATUS_SUCCESS;
01528     }
01529 
01530     /* The PCI Device has power capabilities, so read which ones are supported */
01531     DeviceCapability->DeviceD1 = PdoExtension->PowerCapabilities.Support.D1;
01532     DeviceCapability->DeviceD2 = PdoExtension->PowerCapabilities.Support.D2;
01533     DeviceCapability->WakeFromD0 = PdoExtension->PowerCapabilities.Support.PMED0;
01534     DeviceCapability->WakeFromD1 = PdoExtension->PowerCapabilities.Support.PMED1;
01535     DeviceCapability->WakeFromD2 = PdoExtension->PowerCapabilities.Support.PMED2;
01536 
01537     /* Can the attached device wake from D3? */
01538     if (AttachedCaps.DeviceWake != PowerDeviceD3)
01539     {
01540         /* It can't, so check if this PDO supports hot D3 wake */
01541         DeviceCapability->WakeFromD3 = PdoExtension->PowerCapabilities.Support.PMED3Hot;
01542     }
01543     else
01544     {
01545         /* It can, is this the root bus? */
01546         if (PCI_IS_ROOT_FDO(PdoExtension->ParentFdoExtension))
01547         {
01548             /* This is the root bus, so just check if it supports hot D3 wake */
01549             DeviceCapability->WakeFromD3 = PdoExtension->PowerCapabilities.Support.PMED3Hot;
01550         }
01551         else
01552         {
01553             /* Take the minimums? -- need to check with briang at work */
01554             UNIMPLEMENTED;
01555         }
01556     }
01557 
01558     /* Now loop each system power state to determine its device state mapping */
01559     for (CurrentState = PowerSystemWorking;
01560          CurrentState < PowerSystemMaximum;
01561          CurrentState++)
01562     {
01563         /* Read the current mapping from the attached device */
01564         DevicePowerState = AttachedCaps.DeviceState[CurrentState];
01565         NewPowerState = DevicePowerState;
01566 
01567         /* The attachee suports D1, but this PDO does not */
01568         if ((NewPowerState == PowerDeviceD1) &&
01569             !(PdoExtension->PowerCapabilities.Support.D1))
01570         {
01571             /* Fall back to D2 */
01572             NewPowerState = PowerDeviceD2;
01573         }
01574 
01575         /* The attachee supports D2, but this PDO does not */
01576         if ((NewPowerState == PowerDeviceD2) &&
01577             !(PdoExtension->PowerCapabilities.Support.D2))
01578         {
01579             /* Fall back to D3 */
01580             NewPowerState = PowerDeviceD3;
01581         }
01582 
01583         /* Set the mapping based on the best state supported */
01584         DeviceCapability->DeviceState[CurrentState] = NewPowerState;
01585 
01586         /* Check if sleep states are being processed, and a mapping was found */
01587         if ((CurrentState < PowerSystemHibernate) &&
01588             (NewPowerState != PowerDeviceUnspecified))
01589         {
01590             /* Save this state as being the deepest one found until now */
01591             DeepestWakeState = CurrentState;
01592         }
01593 
01594         /*
01595          * Finally, check if the computed sleep state is within the states that
01596          * this device can wake the system from, and if it's higher or equal to
01597          * the sleep state mapping that came from the attachee, assuming that it
01598          * had a valid mapping to begin with.
01599          *
01600          * It this is the case, then make sure that the computed sleep state is
01601          * matched by the device's ability to actually wake from that state.
01602          *
01603          * For devices that support D3, the PCI device only needs Hot D3 as long
01604          * as the attachee's state is less than D3. Otherwise, if the attachee
01605          * might also be at D3, this would require a Cold D3 wake, so check that
01606          * the device actually support this.
01607          */
01608         if ((CurrentState < AttachedCaps.SystemWake) &&
01609             (NewPowerState >= DevicePowerState) &&
01610             (DevicePowerState != PowerDeviceUnspecified) &&
01611             (((NewPowerState == PowerDeviceD0) && (DeviceCapability->WakeFromD0)) ||
01612              ((NewPowerState == PowerDeviceD1) && (DeviceCapability->WakeFromD1)) ||
01613              ((NewPowerState == PowerDeviceD2) && (DeviceCapability->WakeFromD2)) ||
01614              ((NewPowerState == PowerDeviceD3) &&
01615               (PdoExtension->PowerCapabilities.Support.PMED3Hot) &&
01616               ((DevicePowerState < PowerDeviceD3) ||
01617                (PdoExtension->PowerCapabilities.Support.PMED3Cold)))))
01618         {
01619             /* The mapping is valid, so this will be the lowest wake state */
01620             SystemWakeState = CurrentState;
01621             DeviceWakeState = NewPowerState;
01622         }
01623     }
01624 
01625     /* Read the current wake level */
01626     DeviceWakeLevel = PdoExtension->PowerState.DeviceWakeLevel;
01627 
01628     /* Check if the attachee's wake levels are valid, and the PDO's is higher */
01629     if ((AttachedCaps.SystemWake != PowerSystemUnspecified) &&
01630         (AttachedCaps.DeviceWake != PowerDeviceUnspecified) &&
01631         (DeviceWakeLevel != PowerDeviceUnspecified) &&
01632         (DeviceWakeLevel >= AttachedCaps.DeviceWake))
01633     {
01634         /* Inherit the system wake from the attachee, and this PDO's wake level */
01635         DeviceCapability->SystemWake = AttachedCaps.SystemWake;
01636         DeviceCapability->DeviceWake = DeviceWakeLevel;
01637 
01638         /* Now check if the wake level is D0, but the PDO doesn't support it */
01639         if ((DeviceCapability->DeviceWake == PowerDeviceD0) &&
01640             !(DeviceCapability->WakeFromD0))
01641         {
01642             /* Bump to D1 */
01643             DeviceCapability->DeviceWake = PowerDeviceD1;
01644         }
01645 
01646         /* Now check if the wake level is D1, but the PDO doesn't support it */
01647         if ((DeviceCapability->DeviceWake == PowerDeviceD1) &&
01648             !(DeviceCapability->WakeFromD1))
01649         {
01650             /* Bump to D2 */
01651             DeviceCapability->DeviceWake = PowerDeviceD2;
01652         }
01653 
01654         /* Now check if the wake level is D2, but the PDO doesn't support it */
01655         if ((DeviceCapability->DeviceWake == PowerDeviceD2) &&
01656             !(DeviceCapability->WakeFromD2))
01657         {
01658             /* Bump it to D3 */
01659             DeviceCapability->DeviceWake = PowerDeviceD3;
01660         }
01661 
01662         /* Now check if the wake level is D3, but the PDO doesn't support it */
01663         if ((DeviceCapability->DeviceWake == PowerDeviceD3) &&
01664             !(DeviceCapability->WakeFromD3))
01665         {
01666             /* Then no valid wake state exists */
01667             DeviceCapability->DeviceWake = PowerDeviceUnspecified;
01668             DeviceCapability->SystemWake = PowerSystemUnspecified;
01669         }
01670 
01671         /* Check if no valid wake state was found */
01672         if ((DeviceCapability->DeviceWake == PowerDeviceUnspecified) ||
01673             (DeviceCapability->SystemWake == PowerSystemUnspecified))
01674         {
01675             /* Check if one was computed earlier */
01676             if ((SystemWakeState != PowerSystemUnspecified) &&
01677                 (DeviceWakeState != PowerDeviceUnspecified))
01678             {
01679                 /* Use the wake state that had been computed earlier */
01680                 DeviceCapability->DeviceWake = DeviceWakeState;
01681                 DeviceCapability->SystemWake = SystemWakeState;
01682 
01683                 /* If that state was D3, then the device supports Hot/Cold D3 */
01684                 if (DeviceWakeState == PowerDeviceD3) DeviceCapability->WakeFromD3 = TRUE;
01685             }
01686         }
01687 
01688         /*
01689          * Finally, check for off states (lower than S3, such as hibernate) and
01690          * make sure that the device both supports waking from D3 as well as
01691          * supports a Cold wake
01692          */
01693         if ((DeviceCapability->SystemWake > PowerSystemSleeping3) &&
01694             ((DeviceCapability->DeviceWake != PowerDeviceD3) ||
01695              !(PdoExtension->PowerCapabilities.Support.PMED3Cold)))
01696         {
01697             /* It doesn't, so pick the computed lowest wake state from earlier */
01698             DeviceCapability->SystemWake = DeepestWakeState;
01699         }
01700 
01701         /* Set the PCI Specification mandated maximum latencies for transitions */
01702         DeviceCapability->D1Latency = 0;
01703         DeviceCapability->D2Latency = 2;
01704         DeviceCapability->D3Latency = 100;
01705 
01706         /* Sanity check */
01707         ASSERT(DeviceCapability->DeviceState[PowerSystemWorking] == PowerDeviceD0);
01708     }
01709     else
01710     {
01711         /* No valid sleep states, no latencies to worry about */
01712         DeviceCapability->D1Latency = 0;
01713         DeviceCapability->D2Latency = 0;
01714         DeviceCapability->D3Latency = 0;
01715     }
01716 
01717     /* This function always succeeds, even without power management support */
01718     return STATUS_SUCCESS;
01719 }
01720 
01721 NTSTATUS
01722 NTAPI
01723 PciQueryCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
01724                      IN OUT PDEVICE_CAPABILITIES DeviceCapability)
01725 {
01726     NTSTATUS Status;
01727 
01728     /* A PDO ID is never unique, and its address is its function and device */
01729     DeviceCapability->UniqueID = FALSE;
01730     DeviceCapability->Address = PdoExtension->Slot.u.bits.FunctionNumber |
01731                                 (PdoExtension->Slot.u.bits.DeviceNumber << 16);
01732 
01733     /* Check for host bridges */
01734     if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
01735         (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST))
01736     {
01737         /* Raw device opens to a host bridge are acceptable */
01738         DeviceCapability->RawDeviceOK = TRUE;
01739     }
01740     else
01741     {
01742         /* Otherwise, other PDOs cannot be directly opened */
01743         DeviceCapability->RawDeviceOK = FALSE;
01744     }
01745 
01746     /* PCI PDOs are pretty fixed things */
01747     DeviceCapability->LockSupported = FALSE;
01748     DeviceCapability->EjectSupported = FALSE;
01749     DeviceCapability->Removable = FALSE;
01750     DeviceCapability->DockDevice = FALSE;
01751 
01752     /* The slot number is stored as a device property, go query it */
01753     PciDetermineSlotNumber(PdoExtension, &DeviceCapability->UINumber);
01754 
01755     /* Finally, query and power capabilities and convert them for PnP usage */
01756     Status = PciQueryPowerCapabilities(PdoExtension, DeviceCapability);
01757 
01758     /* Dump the capabilities if it all worked, and return the status */
01759     if (NT_SUCCESS(Status)) PciDebugDumpQueryCapabilities(DeviceCapability);
01760     return Status;
01761 }
01762 
01763 PCM_PARTIAL_RESOURCE_DESCRIPTOR
01764 NTAPI
01765 PciNextPartialDescriptor(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor)
01766 {
01767     PCM_PARTIAL_RESOURCE_DESCRIPTOR NextDescriptor;
01768 
01769     /* Assume the descriptors are the fixed size ones */
01770     NextDescriptor = CmDescriptor + 1;
01771 
01772     /* But check if this is actually a variable-sized descriptor */
01773     if (CmDescriptor->Type == CmResourceTypeDeviceSpecific)
01774     {
01775         /* Add the size of the variable section as well */
01776         NextDescriptor = (PVOID)((ULONG_PTR)NextDescriptor +
01777                                  CmDescriptor->u.DeviceSpecificData.DataSize);
01778     }
01779 
01780     /* Now the correct pointer has been computed, return it */
01781     return NextDescriptor;
01782 }
01783 
01784 /* EOF */

Generated on Sun May 27 2012 04:22:16 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.