Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[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 UNREFERENCED_PARAMETER(DebugKey);
681 /* This function is not yet implemented */
682 UNIMPLEMENTED_DBGBREAK();
683 return STATUS_SUCCESS;
684 }
685
686 DRIVER_UNLOAD PciDriverUnload;
687
688 VOID
689 NTAPI
690 PciDriverUnload(IN PDRIVER_OBJECT DriverObject)
691 {
692 UNREFERENCED_PARAMETER(DriverObject);
693 /* This function is not yet implemented */
694 UNIMPLEMENTED_DBGBREAK("PCI: Unload\n");
695 }
696
697 NTSTATUS
698 NTAPI
699 DriverEntry(IN PDRIVER_OBJECT DriverObject,
700 IN PUNICODE_STRING RegistryPath)
701 {
702 HANDLE KeyHandle, ParametersKey, DebugKey, ControlSetKey;
703 BOOLEAN Result;
704 OBJECT_ATTRIBUTES ObjectAttributes;
705 ULONG ResultLength;
706 PULONG Value;
707 PWCHAR StartOptions;
708 UNICODE_STRING OptionString, PciLockString;
709 NTSTATUS Status;
710 DPRINT1("PCI: DriverEntry!\n");
711
712 /* Setup initial loop variables */
713 KeyHandle = NULL;
714 ParametersKey = NULL;
715 DebugKey = NULL;
716 ControlSetKey = NULL;
717 do
718 {
719 /* Remember our object so we can get it to it later */
720 PciDriverObject = DriverObject;
721
722 /* Setup the IRP dispatcher */
723 DriverObject->MajorFunction[IRP_MJ_POWER] = PciDispatchIrp;
724 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchIrp;
725 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciDispatchIrp;
726 DriverObject->MajorFunction[IRP_MJ_PNP] = PciDispatchIrp;
727 DriverObject->DriverUnload = PciDriverUnload;
728
729 /* This is how we'll detect a new PCI bus */
730 DriverObject->DriverExtension->AddDevice = PciAddDevice;
731
732 /* Open the PCI key */
733 InitializeObjectAttributes(&ObjectAttributes,
734 RegistryPath,
735 OBJ_CASE_INSENSITIVE,
736 NULL,
737 NULL);
738 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
739 if (!NT_SUCCESS(Status)) break;
740
741 /* Open the Parameters subkey */
742 Result = PciOpenKey(L"Parameters",
743 KeyHandle,
744 KEY_QUERY_VALUE,
745 &ParametersKey,
746 &Status);
747 //if (!Result) break;
748
749 /* Build the list of all known PCI erratas */
750 Status = PciBuildHackTable(ParametersKey);
751 //if (!NT_SUCCESS(Status)) break;
752
753 /* Open the debug key, if it exists */
754 Result = PciOpenKey(L"Debug",
755 KeyHandle,
756 KEY_QUERY_VALUE,
757 &DebugKey,
758 &Status);
759 if (Result)
760 {
761 /* There are PCI debug devices, go discover them */
762 Status = PciGetDebugPorts(DebugKey);
763 if (!NT_SUCCESS(Status)) break;
764 }
765
766 /* Initialize the synchronization locks */
767 KeInitializeEvent(&PciGlobalLock, SynchronizationEvent, TRUE);
768 KeInitializeEvent(&PciBusLock, SynchronizationEvent, TRUE);
769 KeInitializeEvent(&PciLegacyDescriptionLock, SynchronizationEvent, TRUE);
770
771 /* Open the control set key */
772 Result = PciOpenKey(L"\\Registry\\Machine\\System\\CurrentControlSet",
773 NULL,
774 KEY_QUERY_VALUE,
775 &ControlSetKey,
776 &Status);
777 if (!Result) break;
778
779 /* Read the command line */
780 Status = PciGetRegistryValue(L"SystemStartOptions",
781 L"Control",
782 ControlSetKey,
783 REG_SZ,
784 (PVOID*)&StartOptions,
785 &ResultLength);
786 if (NT_SUCCESS(Status))
787 {
788 /* Initialize the command-line as a string */
789 OptionString.Buffer = StartOptions;
790 OptionString.MaximumLength = OptionString.Length = ResultLength;
791
792 /* Check if the command-line has the PCILOCK argument */
793 RtlInitUnicodeString(&PciLockString, L"PCILOCK");
794 if (PciUnicodeStringStrStr(&OptionString, &PciLockString, TRUE))
795 {
796 /* The PCI Bus driver will keep the BIOS-assigned resources */
797 PciLockDeviceResources = TRUE;
798 }
799
800 /* This data isn't needed anymore */
801 ExFreePoolWithTag(StartOptions, 0);
802 }
803
804 /* The PCILOCK feature can also be enabled per-system in the registry */
805 Status = PciGetRegistryValue(L"PCILock",
806 L"Control\\BiosInfo\\PCI",
807 ControlSetKey,
808 REG_DWORD,
809 (PVOID*)&Value,
810 &ResultLength);
811 if (NT_SUCCESS(Status))
812 {
813 /* Read the value it's been set to. This overrides /PCILOCK */
814 if (ResultLength == sizeof(ULONG)) PciLockDeviceResources = *Value;
815 ExFreePoolWithTag(Value, 0);
816 }
817
818 /* The system can have global PCI erratas in the registry */
819 Status = PciGetRegistryValue(L"HackFlags",
820 L"Control\\PnP\\PCI",
821 ControlSetKey,
822 REG_DWORD,
823 (PVOID*)&Value,
824 &ResultLength);
825 if (NT_SUCCESS(Status))
826 {
827 /* Read them in */
828 if (ResultLength == sizeof(ULONG)) PciSystemWideHackFlags = *Value;
829 ExFreePoolWithTag(Value, 0);
830 }
831
832 /* Check if the system should allow native ATA support */
833 Status = PciGetRegistryValue(L"EnableNativeModeATA",
834 L"Control\\PnP\\PCI",
835 ControlSetKey,
836 REG_DWORD,
837 (PVOID*)&Value,
838 &ResultLength);
839 if (NT_SUCCESS(Status))
840 {
841 /* This key is typically set by drivers, but users can force it */
842 if (ResultLength == sizeof(ULONG)) PciEnableNativeModeATA = *Value;
843 ExFreePoolWithTag(Value, 0);
844 }
845
846 /* Build the range lists for all the excluded resource areas */
847 Status = PciBuildDefaultExclusionLists();
848 if (!NT_SUCCESS(Status)) break;
849
850 /* Read the PCI IRQ Routing Table that the loader put in the registry */
851 PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable);
852
853 /* Take over the HAL's default PCI Bus Handler routines */
854 PciHookHal();
855
856 /* Initialize verification of PCI BIOS and devices, if requested */
857 PciVerifierInit(DriverObject);
858
859 /* Check if this is a Datacenter SKU, which impacts IRQ alignment */
860 PciRunningDatacenter = PciIsDatacenter();
861 if (PciRunningDatacenter) DPRINT1("PCI running on datacenter build\n");
862
863 /* Check if the system has an ACPI Hardware Watchdog Timer */
864 //WdTable = PciGetAcpiTable(WDRT_SIGNATURE);
865 Status = STATUS_SUCCESS;
866 } while (FALSE);
867
868 /* Close all opened keys, return driver status to PnP Manager */
869 if (KeyHandle) ZwClose(KeyHandle);
870 if (ControlSetKey) ZwClose(ControlSetKey);
871 if (ParametersKey) ZwClose(ParametersKey);
872 if (DebugKey) ZwClose(DebugKey);
873 return Status;
874 }
875
876 /* EOF */