03b95af9ee41a3cbf4134ea0fac0868ec9979bb4
[reactos.git] / reactos / drivers / bus / pcix / init.c
1 /*
2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/init.c
5 * PURPOSE: Driver Initialization
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 BOOLEAN PciRunningDatacenter;
18 PDRIVER_OBJECT PciDriverObject;
19 KEVENT PciGlobalLock;
20 KEVENT PciBusLock;
21 KEVENT PciLegacyDescriptionLock;
22 BOOLEAN PciLockDeviceResources;
23 BOOLEAN PciEnableNativeModeATA;
24 ULONG PciSystemWideHackFlags;
25 PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable;
26 PWATCHDOG_TABLE WdTable;
27 PPCI_HACK_ENTRY PciHackTable;
28
29 /* FUNCTIONS ******************************************************************/
30
31 NTSTATUS
32 NTAPI
33 PciAcpiFindRsdt(OUT PACPI_BIOS_MULTI_NODE *AcpiMultiNode)
34 {
35 BOOLEAN Result;
36 NTSTATUS Status;
37 HANDLE KeyHandle, SubKey;
38 ULONG NumberOfBytes, i, Length;
39 PKEY_FULL_INFORMATION FullInfo;
40 PKEY_VALUE_BASIC_INFORMATION KeyInfo;
41 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
42 PACPI_BIOS_MULTI_NODE NodeData;
43 UNICODE_STRING ValueName;
44 struct
45 {
46 CM_FULL_RESOURCE_DESCRIPTOR Descriptor;
47 ACPI_BIOS_MULTI_NODE Node;
48 } *Package;
49
50 /* So we know what to free at the end of the body */
51 ValueInfo = NULL;
52 KeyInfo = NULL;
53 KeyHandle = NULL;
54 FullInfo = NULL;
55 Package = NULL;
56 do
57 {
58 /* Open the ACPI BIOS key */
59 Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\"
60 L"System\\MultiFunctionAdapter",
61 NULL,
62 KEY_QUERY_VALUE,
63 &KeyHandle,
64 &Status);
65 if (!Result) break;
66
67 /* Query how much space should be allocated for the key information */
68 Status = ZwQueryKey(KeyHandle,
69 KeyFullInformation,
70 NULL,
71 sizeof(ULONG),
72 &NumberOfBytes);
73 if (Status != STATUS_BUFFER_TOO_SMALL) break;
74
75 /* Allocate the space required */
76 Status = STATUS_INSUFFICIENT_RESOURCES;
77 FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG);
78 if ( !FullInfo ) break;
79
80 /* Now query the key information that's needed */
81 Status = ZwQueryKey(KeyHandle,
82 KeyFullInformation,
83 FullInfo,
84 NumberOfBytes,
85 &NumberOfBytes);
86 if (!NT_SUCCESS(Status)) break;
87
88 /* Allocate enough space to hold the value information plus the name */
89 Status = STATUS_INSUFFICIENT_RESOURCES;
90 Length = FullInfo->MaxNameLen + 26;
91 KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
92 if ( !KeyInfo ) break;
93
94 /* Allocate the value information and name we expect to find */
95 ValueInfo = ExAllocatePoolWithTag(PagedPool,
96 sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
97 sizeof(L"ACPI BIOS"),
98 PCI_POOL_TAG);
99 if (!ValueInfo) break;
100
101 /* Query each sub-key */
102 Status = ZwEnumerateKey(KeyHandle,
103 0,
104 KeyValueBasicInformation,
105 KeyInfo,
106 Length,
107 &NumberOfBytes);
108 for (i = 0; Status != STATUS_NO_MORE_ENTRIES; i++)
109 {
110 /* Null-terminate the keyname, because the kernel does not */
111 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
112
113 /* Open this subkey */
114 Result = PciOpenKey(KeyInfo->Name,
115 KeyHandle,
116 KEY_QUERY_VALUE,
117 &SubKey,
118 &Status);
119 if (Result)
120 {
121 /* Query the identifier value for this subkey */
122 RtlInitUnicodeString(&ValueName, L"Identifier");
123 Status = ZwQueryValueKey(SubKey,
124 &ValueName,
125 KeyValuePartialInformation,
126 ValueInfo,
127 sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
128 sizeof(L"ACPI BIOS"),
129 &NumberOfBytes);
130 if (NT_SUCCESS(Status))
131 {
132 /* Check if this is the PCI BIOS subkey */
133 if (!wcsncmp((PWCHAR)ValueInfo->Data,
134 L"ACPI BIOS",
135 ValueInfo->DataLength))
136 {
137 /* It is, proceed to query the PCI IRQ routing table */
138 Status = PciGetRegistryValue(L"Configuration Data",
139 KeyInfo->Name,
140 KeyHandle,
141 REG_FULL_RESOURCE_DESCRIPTOR,
142 (PVOID*)&Package,
143 &NumberOfBytes);
144 ZwClose(SubKey);
145 break;
146 }
147 }
148
149 /* Close the subkey and try the next one */
150 ZwClose(SubKey);
151 }
152 }
153
154 /* Check if we got here because the routing table was found */
155 if (!NT_SUCCESS(Status))
156 {
157 /* This should only fail if we're out of entries */
158 ASSERT(Status == STATUS_NO_MORE_ENTRIES);
159 break;
160 }
161
162 /* Check if a descriptor was found */
163 if (!Package) break;
164
165 /* The configuration data is a resource list, and the BIOS node follows */
166 NodeData = &Package->Node;
167
168 /* How many E820 memory entries are there? */
169 Length = sizeof(ACPI_BIOS_MULTI_NODE) +
170 (NodeData->Count - 1) * sizeof(ACPI_E820_ENTRY);
171
172 /* Allocate the buffer needed to copy the information */
173 Status = STATUS_INSUFFICIENT_RESOURCES;
174 *AcpiMultiNode = ExAllocatePoolWithTag(NonPagedPool, Length, PCI_POOL_TAG);
175 if (!*AcpiMultiNode) break;
176
177 /* Copy the data */
178 RtlCopyMemory(*AcpiMultiNode, NodeData, Length);
179 } while (FALSE);
180
181 /* Close any opened keys, free temporary allocations, and return status */
182 if (Package) ExFreePoolWithTag(Package, 0);
183 if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0);
184 if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0);
185 if (FullInfo) ExFreePoolWithTag(FullInfo, 0);
186 if (KeyHandle) ZwClose(KeyHandle);
187 return Status;
188 }
189
190 PVOID
191 NTAPI
192 PciGetAcpiTable(IN ULONG TableCode)
193 {
194 PDESCRIPTION_HEADER Header;
195 PACPI_BIOS_MULTI_NODE AcpiMultiNode;
196 PRSDT Rsdt;
197 PXSDT Xsdt;
198 ULONG EntryCount, TableLength, Offset, CurrentEntry;
199 PVOID TableBuffer, MappedAddress;
200 PHYSICAL_ADDRESS PhysicalAddress;
201 NTSTATUS Status;
202
203 /* Try to find the RSDT or XSDT */
204 Status = PciAcpiFindRsdt(&AcpiMultiNode);
205 if (NT_SUCCESS(Status))
206 {
207 /* No ACPI on the machine */
208 DPRINT1("AcpiFindRsdt() Failed!\n");
209 return NULL;
210 }
211
212 /* Map the RSDT with the minimum size allowed */
213 MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress,
214 sizeof(DESCRIPTION_HEADER),
215 MmNonCached);
216 Header = MappedAddress;
217 if (!Header) return NULL;
218
219 /* Check how big the table really is and get rid of the temporary header */
220 TableLength = Header->Length;
221 MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
222 Header = NULL;
223
224 /* Map its true size */
225 MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress,
226 TableLength,
227 MmNonCached);
228 Rsdt = MappedAddress;
229 Xsdt = MappedAddress;
230 ExFreePoolWithTag(AcpiMultiNode, 0);
231 if (!Rsdt) return NULL;
232
233 /* Validate the table's signature */
234 DPRINT1("ACPI RSDT/XSDT at 0x%p\n", Rsdt);
235 if ((Rsdt->Header.Signature != RSDT_SIGNATURE) &&
236 (Rsdt->Header.Signature != XSDT_SIGNATURE))
237 {
238 /* Very bad: crash */
239 HalDisplayString("RSDT table contains invalid signature\n");
240 MmUnmapIoSpace(Rsdt, TableLength);
241 return NULL;
242 }
243
244 /* Smallest RSDT/XSDT is one without table entries */
245 Offset = FIELD_OFFSET(RSDT, Tables);
246 if (Rsdt->Header.Signature == XSDT_SIGNATURE)
247 {
248 /* Figure out total size of table and the offset */
249 TableLength = Xsdt->Header.Length;
250 if (TableLength < Offset) Offset = Xsdt->Header.Length;
251
252 /* The entries are each 64-bits, so count them */
253 EntryCount = (TableLength - Offset) / sizeof(PHYSICAL_ADDRESS);
254 }
255 else
256 {
257 /* Figure out total size of table and the offset */
258 TableLength = Rsdt->Header.Length;
259 if (TableLength < Offset) Offset = Rsdt->Header.Length;
260
261 /* The entries are each 32-bits, so count them */
262 EntryCount = (TableLength - Offset) / sizeof(ULONG);
263 }
264
265 /* Start at the beginning of the array and loop it */
266 for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++)
267 {
268 /* Are we using the XSDT? */
269 if (Rsdt->Header.Signature != XSDT_SIGNATURE)
270 {
271 /* Read the 32-bit physical address */
272 PhysicalAddress.LowPart = Rsdt->Tables[CurrentEntry];
273 }
274 else
275 {
276 /* Read the 64-bit physical address */
277 PhysicalAddress = Xsdt->Tables[CurrentEntry];
278 }
279
280 /* Map this table */
281 Header = MmMapIoSpace(PhysicalAddress,
282 sizeof(DESCRIPTION_HEADER),
283 MmNonCached);
284 if (!Header) break;
285
286 /* Check if this is the table that's being asked for */
287 if (Header->Signature == TableCode)
288 {
289 /* Allocate a buffer for it */
290 TableBuffer = ExAllocatePoolWithTag(PagedPool,
291 Header->Length,
292 PCI_POOL_TAG);
293 if (!TableBuffer) break;
294
295 /* Copy the table into the buffer */
296 RtlCopyMemory(TableBuffer, Header, Header->Length);
297 }
298
299 /* Done with this table, keep going */
300 MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
301 }
302
303 if (Header) MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
304 return NULL;
305 }
306
307 NTSTATUS
308 NTAPI
309 PciGetIrqRoutingTableFromRegistry(OUT PPCI_IRQ_ROUTING_TABLE *PciRoutingTable)
310 {
311 BOOLEAN Result;
312 NTSTATUS Status;
313 HANDLE KeyHandle, SubKey;
314 ULONG NumberOfBytes, i, Length;
315 PKEY_FULL_INFORMATION FullInfo;
316 PKEY_VALUE_BASIC_INFORMATION KeyInfo;
317 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
318 UNICODE_STRING ValueName;
319 struct
320 {
321 CM_FULL_RESOURCE_DESCRIPTOR Descriptor;
322 PCI_IRQ_ROUTING_TABLE Table;
323 } *Package;
324
325 /* So we know what to free at the end of the body */
326 Package = NULL;
327 ValueInfo = NULL;
328 KeyInfo = NULL;
329 KeyHandle = NULL;
330 FullInfo = NULL;
331 do
332 {
333 /* Open the BIOS key */
334 Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\"
335 L"System\\MultiFunctionAdapter",
336 NULL,
337 KEY_QUERY_VALUE,
338 &KeyHandle,
339 &Status);
340 if (!Result) break;
341
342 /* Query how much space should be allocated for the key information */
343 Status = ZwQueryKey(KeyHandle,
344 KeyFullInformation,
345 NULL,
346 sizeof(ULONG),
347 &NumberOfBytes);
348 if (Status != STATUS_BUFFER_TOO_SMALL) break;
349
350 /* Allocate the space required */
351 Status = STATUS_INSUFFICIENT_RESOURCES;
352 FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG);
353 if ( !FullInfo ) break;
354
355 /* Now query the key information that's needed */
356 Status = ZwQueryKey(KeyHandle,
357 KeyFullInformation,
358 FullInfo,
359 NumberOfBytes,
360 &NumberOfBytes);
361 if (!NT_SUCCESS(Status)) break;
362
363 /* Allocate enough space to hold the value information plus the name */
364 Status = STATUS_INSUFFICIENT_RESOURCES;
365 Length = FullInfo->MaxNameLen + 26;
366 KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
367 if ( !KeyInfo ) break;
368
369 /* Allocate the value information and name we expect to find */
370 ValueInfo = ExAllocatePoolWithTag(PagedPool,
371 sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
372 sizeof(L"PCI BIOS"),
373 PCI_POOL_TAG);
374 if ( !ValueInfo ) break;
375
376 /* Query each sub-key */
377 Status = ZwEnumerateKey(KeyHandle,
378 0,
379 KeyValueBasicInformation,
380 KeyInfo,
381 Length,
382 &NumberOfBytes);
383 for (i = 0; Status != STATUS_NO_MORE_ENTRIES; i++)
384 {
385 /* Null-terminate the keyname, because the kernel does not */
386 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
387
388 /* Open this subkey */
389 Result = PciOpenKey(KeyInfo->Name,
390 KeyHandle,
391 KEY_QUERY_VALUE,
392 &SubKey,
393 &Status);
394 if (Result)
395 {
396 /* Query the identifier value for this subkey */
397 RtlInitUnicodeString(&ValueName, L"Identifier");
398 Status = ZwQueryValueKey(SubKey,
399 &ValueName,
400 KeyValuePartialInformation,
401 ValueInfo,
402 sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
403 sizeof(L"PCI BIOS"),
404 &NumberOfBytes);
405 if (NT_SUCCESS(Status))
406 {
407 /* Check if this is the PCI BIOS subkey */
408 if (!wcsncmp((PWCHAR)ValueInfo->Data,
409 L"PCI BIOS",
410 ValueInfo->DataLength))
411 {
412 /* It is, proceed to query the PCI IRQ routing table */
413 Status = PciGetRegistryValue(L"Configuration Data",
414 L"RealModeIrqRoutingTable"
415 L"\\0",
416 SubKey,
417 REG_FULL_RESOURCE_DESCRIPTOR,
418 (PVOID*)&Package,
419 &NumberOfBytes);
420 ZwClose(SubKey);
421 break;
422 }
423 }
424
425 /* Close the subkey and try the next one */
426 ZwClose(SubKey);
427 }
428 }
429
430 /* Check if we got here because the routing table was found */
431 if (!NT_SUCCESS(Status)) break;
432
433 /* Check if a descriptor was found */
434 if (!Package) break;
435
436 /* Make sure the buffer is large enough to hold the table */
437 if ((NumberOfBytes < sizeof(*Package)) ||
438 (Package->Table.TableSize >
439 (NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR))))
440 {
441 /* Invalid package size */
442 Status = STATUS_UNSUCCESSFUL;
443 break;
444 }
445
446 /* Allocate space for the table */
447 Status = STATUS_INSUFFICIENT_RESOURCES;
448 *PciRoutingTable = ExAllocatePoolWithTag(PagedPool,
449 NumberOfBytes,
450 PCI_POOL_TAG);
451 if (!*PciRoutingTable) break;
452
453 /* Copy the registry data */
454 RtlCopyMemory(*PciRoutingTable,
455 &Package->Table,
456 NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
457 Status = STATUS_SUCCESS;
458 } while (FALSE);
459
460 /* Close any opened keys, free temporary allocations, and return status */
461 if (Package) ExFreePoolWithTag(Package, 0);
462 if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0);
463 if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0);
464 if (FullInfo) ExFreePoolWithTag(FullInfo, 0);
465 if (KeyHandle) ZwClose(KeyHandle);
466 return Status;
467 }
468
469 NTSTATUS
470 NTAPI
471 PciBuildHackTable(IN HANDLE KeyHandle)
472 {
473 PKEY_FULL_INFORMATION FullInfo;
474 ULONG i, HackCount;
475 PKEY_VALUE_FULL_INFORMATION ValueInfo;
476 PPCI_HACK_ENTRY Entry;
477 NTSTATUS Status;
478 ULONG NameLength, ResultLength;
479 ULONGLONG HackFlags;
480
481 /* So we know what to free at the end of the body */
482 FullInfo = NULL;
483 ValueInfo = NULL;
484 do
485 {
486 /* Query the size required for full key information */
487 Status = ZwQueryKey(KeyHandle,
488 KeyFullInformation,
489 NULL,
490 0,
491 &ResultLength);
492 if (Status != STATUS_BUFFER_TOO_SMALL) break;
493
494 /* Allocate the space required to hold the full key information */
495 Status = STATUS_INSUFFICIENT_RESOURCES;
496 ASSERT(ResultLength > 0);
497 FullInfo = ExAllocatePoolWithTag(PagedPool, ResultLength, PCI_POOL_TAG);
498 if (!FullInfo) break;
499
500 /* Go ahead and query the key information */
501 Status = ZwQueryKey(KeyHandle,
502 KeyFullInformation,
503 FullInfo,
504 ResultLength,
505 &ResultLength);
506 if (!NT_SUCCESS(Status)) break;
507
508 /* The only piece of information that's needed is the count of values */
509 HackCount = FullInfo->Values;
510
511 /* Free the structure now */
512 ExFreePoolWithTag(FullInfo, 0);
513 FullInfo = NULL;
514
515 /* Allocate the hack table, now that the number of entries is known */
516 Status = STATUS_INSUFFICIENT_RESOURCES;
517 ResultLength = sizeof(PCI_HACK_ENTRY) * HackCount;
518 PciHackTable = ExAllocatePoolWithTag(NonPagedPool,
519 ResultLength +
520 sizeof(PCI_HACK_ENTRY),
521 PCI_POOL_TAG);
522 if (!PciHackTable) break;
523
524 /* Allocate the space needed to hold the full value information */
525 ValueInfo = ExAllocatePoolWithTag(NonPagedPool,
526 sizeof(KEY_VALUE_FULL_INFORMATION) +
527 PCI_HACK_ENTRY_FULL_SIZE,
528 PCI_POOL_TAG);
529 if (!PciHackTable) break;
530
531 /* Loop each value in the registry */
532 Entry = &PciHackTable[0];
533 for (i = 0; i < HackCount; i++)
534 {
535 /* Get the entry for this value */
536 Entry = &PciHackTable[i];
537
538 /* Query the value in the key */
539 Status = ZwEnumerateValueKey(KeyHandle,
540 i,
541 KeyValueFullInformation,
542 ValueInfo,
543 sizeof(KEY_VALUE_FULL_INFORMATION) +
544 PCI_HACK_ENTRY_FULL_SIZE,
545 &ResultLength);
546 if (!NT_SUCCESS(Status))
547 {
548 /* Check why the call failed */
549 if ((Status != STATUS_BUFFER_OVERFLOW) &&
550 (Status != STATUS_BUFFER_TOO_SMALL))
551 {
552 /* The call failed due to an unknown error, bail out */
553 break;
554 }
555
556 /* The data seems to mismatch, try the next key in the list */
557 continue;
558 }
559
560 /* Check if the value data matches what's expected */
561 if ((ValueInfo->Type != REG_BINARY) ||
562 (ValueInfo->DataLength != sizeof(ULONGLONG)))
563 {
564 /* It doesn't, try the next key in the list */
565 continue;
566 }
567
568 /* Read the actual hack flags */
569 HackFlags = *(PULONGLONG)((ULONG_PTR)ValueInfo +
570 ValueInfo->DataOffset);
571
572 /* Check what kind of errata entry this is, based on the name */
573 NameLength = ValueInfo->NameLength;
574 if ((NameLength != PCI_HACK_ENTRY_SIZE) &&
575 (NameLength != PCI_HACK_ENTRY_REV_SIZE) &&
576 (NameLength != PCI_HACK_ENTRY_SUBSYS_SIZE) &&
577 (NameLength != PCI_HACK_ENTRY_FULL_SIZE))
578 {
579 DPRINT1("Skipping hack entry with invalid length name\n");
580 }
581
582 /* Initialize the entry */
583 RtlZeroMemory(Entry, sizeof(PCI_HACK_ENTRY));
584
585 /* Get the vendor and device data */
586 if (!(PciStringToUSHORT(ValueInfo->Name, &Entry->VendorID)) ||
587 !(PciStringToUSHORT(&ValueInfo->Name[4], &Entry->DeviceID)))
588 {
589 /* This failed, try the next entry */
590 continue;
591 }
592
593 /* Check if the entry contains subsystem information */
594 if ((NameLength == PCI_HACK_ENTRY_SUBSYS_SIZE) ||
595 (NameLength == PCI_HACK_ENTRY_FULL_SIZE))
596 {
597 /* Get the data */
598 if (!(PciStringToUSHORT(&ValueInfo->Name[8],
599 &Entry->SubVendorID)) ||
600 !(PciStringToUSHORT(&ValueInfo->Name[12],
601 &Entry->SubSystemID)))
602 {
603 /* This failed, try the next entry */
604 continue;
605 }
606
607 /* Save the fact this entry has finer controls */
608 Entry->Flags |= PCI_HACK_HAS_SUBSYSTEM_INFO;
609 }
610
611 /* Check if the entry contains revision information */
612 if ((NameLength == PCI_HACK_ENTRY_REV_SIZE) ||
613 (NameLength == PCI_HACK_ENTRY_FULL_SIZE))
614 {
615 /* Get the data */
616 if (!PciStringToUSHORT(&ValueInfo->Name[16],
617 &Entry->RevisionID))
618 {
619 /* This failed, try the next entry */
620 continue;
621 }
622
623 /* Save the fact this entry has finer controls */
624 Entry->Flags |= PCI_HACK_HAS_REVISION_INFO;
625 }
626
627 /* Only the last entry should have this set */
628 ASSERT(Entry->VendorID != PCI_INVALID_VENDORID);
629
630 /* Save the actual hack flags */
631 Entry->HackFlags = HackFlags;
632
633 /* Print out for the debugger's sake */
634 DPRINT1("Adding Hack entry for Vendor:0x%04x Device:0x%04x ",
635 Entry->VendorID, Entry->DeviceID);
636 if (Entry->Flags & PCI_HACK_HAS_SUBSYSTEM_INFO)
637 DPRINT1("SybSys:0x%04x SubVendor:0x%04x ",
638 Entry->SubSystemID, Entry->SubVendorID);
639 if (Entry->Flags & PCI_HACK_HAS_REVISION_INFO)
640 DPRINT1("Revision:0x%02x", Entry->RevisionID);
641 DPRINT1(" = 0x%I64x\n", Entry->HackFlags);
642 }
643
644 /* Bail out in case of failure */
645 if (!NT_SUCCESS(Status)) break;
646
647 /* Terminate the table with an invalid entry */
648 ASSERT(Entry < (PciHackTable + HackCount + 1));
649 Entry->VendorID = PCI_INVALID_VENDORID;
650
651 /* Success path, free the temporary registry data */
652 ExFreePoolWithTag(ValueInfo, 0);
653 return STATUS_SUCCESS;
654 } while (TRUE);
655
656 /* Failure path, free temporary allocations and return failure code */
657 ASSERT(!NT_SUCCESS(Status));
658 if (FullInfo) ExFreePool(FullInfo);
659 if (ValueInfo) ExFreePool(ValueInfo);
660 if (PciHackTable) ExFreePool(PciHackTable);
661 return Status;
662 }
663
664 NTSTATUS
665 NTAPI
666 PciGetDebugPorts(IN HANDLE DebugKey)
667 {
668 /* This function is not yet implemented */
669 UNIMPLEMENTED;
670 while (TRUE);
671 return STATUS_SUCCESS;
672 }
673
674 VOID
675 NTAPI
676 PciDriverUnload(IN PDRIVER_OBJECT DriverObject)
677 {
678 /* This function is not yet implemented */
679 DPRINT1("PCI: Unload\n");
680 UNIMPLEMENTED;
681 while (TRUE);
682 }
683
684 NTSTATUS
685 NTAPI
686 DriverEntry(IN PDRIVER_OBJECT DriverObject,
687 IN PUNICODE_STRING RegistryPath)
688 {
689 HANDLE KeyHandle, ParametersKey, DebugKey, ControlSetKey;
690 BOOLEAN Result;
691 OBJECT_ATTRIBUTES ObjectAttributes;
692 ULONG ResultLength;
693 PULONG Value;
694 PWCHAR StartOptions;
695 UNICODE_STRING OptionString, PciLockString;
696 NTSTATUS Status;
697 DPRINT1("PCI: DriverEntry!\n");
698 do
699 {
700 /* Remember our object so we can get it to it later */
701 PciDriverObject = DriverObject;
702
703 /* Setup the IRP dispatcher */
704 DriverObject->MajorFunction[IRP_MJ_POWER] = PciDispatchIrp;
705 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchIrp;
706 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciDispatchIrp;
707 DriverObject->MajorFunction[IRP_MJ_PNP] = PciDispatchIrp;
708 DriverObject->DriverUnload = PciDriverUnload;
709
710 /* This is how we'll detect a new PCI bus */
711 DriverObject->DriverExtension->AddDevice = PciAddDevice;
712
713 /* Open the PCI key */
714 InitializeObjectAttributes(&ObjectAttributes,
715 RegistryPath,
716 OBJ_CASE_INSENSITIVE,
717 NULL,
718 NULL);
719 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
720 if (!NT_SUCCESS(Status)) break;
721
722 /* Open the Parameters subkey */
723 Result = PciOpenKey(L"Parameters",
724 KeyHandle,
725 KEY_QUERY_VALUE,
726 &ParametersKey,
727 &Status);
728 if (!Result) break;
729
730 /* Build the list of all known PCI erratas */
731 Status = PciBuildHackTable(ParametersKey);
732 if (!NT_SUCCESS(Status)) break;
733
734 /* Open the debug key, if it exists */
735 Result = PciOpenKey(L"Debug",
736 KeyHandle,
737 KEY_QUERY_VALUE,
738 &DebugKey,
739 &Status);
740 if (Result)
741 {
742 /* There are PCI debug devices, go discover them */
743 Status = PciGetDebugPorts(DebugKey);
744 if (!NT_SUCCESS(Status)) break;
745 }
746
747 /* Initialize the synchronization locks */
748 KeInitializeEvent(&PciGlobalLock, SynchronizationEvent, TRUE);
749 KeInitializeEvent(&PciBusLock, SynchronizationEvent, TRUE);
750 KeInitializeEvent(&PciLegacyDescriptionLock, SynchronizationEvent, TRUE);
751
752 /* Open the control set key */
753 Status = PciOpenKey(L"\\Registry\\Machine\\System\\CurrentControlSet",
754 NULL,
755 KEY_QUERY_VALUE,
756 &ControlSetKey,
757 &Status);
758 if (!NT_SUCCESS(Status)) break;
759
760 /* Read the command line */
761 Status = PciGetRegistryValue(L"SystemStartOptions",
762 L"Control",
763 ControlSetKey,
764 REG_SZ,
765 (PVOID*)&StartOptions,
766 &ResultLength);
767 if (NT_SUCCESS(Status))
768 {
769 /* Initialize the command-line as a string */
770 OptionString.Buffer = StartOptions;
771 OptionString.MaximumLength = OptionString.Length = ResultLength;
772
773 /* Check if the command-line has the PCILOCK argument */
774 RtlInitUnicodeString(&PciLockString, L"PCILOCK");
775 if (PciUnicodeStringStrStr(&OptionString, &PciLockString, TRUE))
776 {
777 /* The PCI Bus driver will keep the BIOS-assigned resources */
778 PciLockDeviceResources = TRUE;
779 }
780
781 /* This data isn't needed anymore */
782 ExFreePoolWithTag(StartOptions, 0);
783 }
784
785 /* The PCILOCK feature can also be enabled per-system in the registry */
786 Status = PciGetRegistryValue(L"PCILock",
787 L"Control\\BiosInfo\\PCI",
788 ControlSetKey,
789 REG_DWORD,
790 (PVOID*)&Value,
791 &ResultLength);
792 if (NT_SUCCESS(Status))
793 {
794 /* Read the value it's been set to. This overrides /PCILOCK */
795 if (ResultLength == sizeof(ULONG)) PciLockDeviceResources = *Value;
796 ExFreePoolWithTag(Value, 0);
797 }
798
799 /* The system can have global PCI erratas in the registry */
800 Status = PciGetRegistryValue(L"HackFlags",
801 L"Control\\PnP\\PCI",
802 ControlSetKey,
803 REG_DWORD,
804 (PVOID*)&Value,
805 &ResultLength);
806 if (NT_SUCCESS(Status))
807 {
808 /* Read them in */
809 if (ResultLength == sizeof(ULONG)) PciSystemWideHackFlags = *Value;
810 ExFreePoolWithTag(Value, 0);
811 }
812
813 /* Check if the system should allow native ATA support */
814 Status = PciGetRegistryValue(L"EnableNativeModeATA",
815 L"Control\\PnP\\PCI",
816 ControlSetKey,
817 REG_DWORD,
818 (PVOID*)&Value,
819 &ResultLength);
820 if (NT_SUCCESS(Status))
821 {
822 /* This key is typically set by drivers, but users can force it */
823 if (ResultLength == sizeof(ULONG)) PciEnableNativeModeATA = *Value;
824 ExFreePoolWithTag(Value, 0);
825 }
826
827 /* Build the range lists for all the excluded resource areas */
828 Status = PciBuildDefaultExclusionLists();
829 if (!NT_SUCCESS(Status)) break;
830
831 /* Read the PCI IRQ Routing Table that the loader put in the registry */
832 PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable);
833
834 /* Take over the HAL's default PCI Bus Handler routines */
835 PciHookHal();
836
837 /* Initialize verification of PCI BIOS and devices, if requested */
838 PciVerifierInit(DriverObject);
839
840 /* Check if this is a Datacenter SKU, which impacts IRQ alignment */
841 PciRunningDatacenter = PciIsDatacenter();
842 if (PciRunningDatacenter) DPRINT1("PCI running on datacenter build\n");
843
844 /* Check if the system has an ACPI Hardware Watchdog Timer */
845 WdTable = PciGetAcpiTable(WDRT_SIGNATURE);
846 } while (FALSE);
847
848 /* Close all opened keys, return driver status to PnP Manager */
849 if (KeyHandle) ZwClose(KeyHandle);
850 if (ControlSetKey) ZwClose(ControlSetKey);
851 if (ParametersKey) ZwClose(ParametersKey);
852 if (DebugKey) ZwClose(DebugKey);
853 return Status;
854 }
855
856 /* EOF */