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