Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenutils.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
1.7.6.1
|