[HAL]: Implement HalpGetPciBridgeConfig to detect PCI-to-PCI/CardBus bridges, warn...
[reactos.git] / reactos / hal / halx86 / generic / legacy / bussupp.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: hal/halx86/generic/legacy/bussupp.c
5 * PURPOSE: HAL Legacy Bus Support Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 extern KSPIN_LOCK HalpPCIConfigLock;
18 ULONG HalpPciIrqMask;
19
20 /* PRIVATE FUNCTIONS **********************************************************/
21
22 PBUS_HANDLER
23 NTAPI
24 HalpAllocateBusHandler(IN INTERFACE_TYPE InterfaceType,
25 IN BUS_DATA_TYPE BusDataType,
26 IN ULONG BusNumber,
27 IN INTERFACE_TYPE ParentBusInterfaceType,
28 IN ULONG ParentBusNumber,
29 IN ULONG BusSpecificData)
30 {
31 PBUS_HANDLER Bus;
32
33 /* Register the bus handler */
34 HalRegisterBusHandler(InterfaceType,
35 BusDataType,
36 BusNumber,
37 ParentBusInterfaceType,
38 ParentBusNumber,
39 BusSpecificData,
40 NULL,
41 &Bus);
42 if (!Bus) return NULL;
43
44 /* Check for a valid interface */
45 if (InterfaceType != InterfaceTypeUndefined)
46 {
47 /* Allocate address ranges and zero them out */
48 Bus->BusAddresses = ExAllocatePoolWithTag(NonPagedPool,
49 sizeof(SUPPORTED_RANGES),
50 ' laH');
51 RtlZeroMemory(Bus->BusAddresses, sizeof(SUPPORTED_RANGES));
52
53 /* Build the data structure */
54 Bus->BusAddresses->Version = HAL_SUPPORTED_RANGE_VERSION;
55 Bus->BusAddresses->Dma.Limit = 7;
56 Bus->BusAddresses->Memory.Limit = 0xFFFFFFFF;
57 Bus->BusAddresses->IO.Limit = 0xFFFF;
58 Bus->BusAddresses->IO.SystemAddressSpace = 1;
59 Bus->BusAddresses->PrefetchMemory.Base = 1;
60 }
61
62 /* Return the bus address */
63 return Bus;
64 }
65
66 VOID
67 NTAPI
68 HalpRegisterInternalBusHandlers(VOID)
69 {
70 PBUS_HANDLER Bus;
71
72 /* Only do processor 1 */
73 if (KeGetCurrentPrcb()->Number) return;
74
75 /* Register root support */
76 HalpInitBusHandler();
77
78 /* Allocate the system bus */
79 Bus = HalpAllocateBusHandler(Internal,
80 ConfigurationSpaceUndefined,
81 0,
82 InterfaceTypeUndefined,
83 0,
84 0);
85 DPRINT1("Registering Internal Bus: %p\n", Bus);
86 if (Bus)
87 {
88 /* Set it up */
89 Bus->GetInterruptVector = HalpGetSystemInterruptVector;
90 Bus->TranslateBusAddress = HalpTranslateSystemBusAddress;
91 }
92
93 /* Allocate the CMOS bus */
94 Bus = HalpAllocateBusHandler(InterfaceTypeUndefined,
95 Cmos,
96 0,
97 InterfaceTypeUndefined,
98 0,
99 0);
100 DPRINT1("Registering CMOS Bus: %p\n", Bus);
101 if (Bus)
102 {
103 /* Set it up */
104 Bus->GetBusData = HalpcGetCmosData;
105 Bus->SetBusData = HalpcSetCmosData;
106 }
107
108 /* Allocate the CMOS bus */
109 Bus = HalpAllocateBusHandler(InterfaceTypeUndefined,
110 Cmos,
111 1,
112 InterfaceTypeUndefined,
113 0,
114 0);
115 DPRINT1("Registering CMOS Bus: %p\n", Bus);
116 if (Bus)
117 {
118 /* Set it up */
119 Bus->GetBusData = HalpcGetCmosData;
120 Bus->SetBusData = HalpcSetCmosData;
121 }
122
123 /* Allocate ISA bus */
124 Bus = HalpAllocateBusHandler(Isa,
125 ConfigurationSpaceUndefined,
126 0,
127 Internal,
128 0,
129 0);
130 DPRINT1("Registering ISA Bus: %p\n", Bus);
131 if (Bus)
132 {
133 /* Set it up */
134 Bus->GetBusData = HalpNoBusData;
135 Bus->BusAddresses->Memory.Limit = 0xFFFFFF;
136 Bus->TranslateBusAddress = HalpTranslateIsaBusAddress;
137 }
138
139 /* No support for EISA or MCA */
140 ASSERT(HalpBusType == MACHINE_TYPE_ISA);
141 }
142
143 #ifndef _MINIHAL_
144 NTSTATUS
145 NTAPI
146 HalpMarkChipsetDecode(BOOLEAN OverrideEnable)
147 {
148 NTSTATUS Status;
149 UNICODE_STRING KeyString;
150 ULONG Data = OverrideEnable;
151 HANDLE KeyHandle, Handle;
152
153 /* Open CCS key */
154 RtlInitUnicodeString(&KeyString,
155 L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
156 Status = HalpOpenRegistryKey(&Handle, 0, &KeyString, KEY_ALL_ACCESS, FALSE);
157 if (NT_SUCCESS(Status))
158 {
159 /* Open PNP Bios key */
160 RtlInitUnicodeString(&KeyString, L"Control\\Biosinfo\\PNPBios");
161 Status = HalpOpenRegistryKey(&KeyHandle,
162 Handle,
163 &KeyString,
164 KEY_ALL_ACCESS,
165 TRUE);
166
167 /* Close root key */
168 ZwClose(Handle);
169
170 /* Check if PNP BIOS key exists */
171 if (NT_SUCCESS(Status))
172 {
173 /* Set the override value */
174 RtlInitUnicodeString(&KeyString, L"FullDecodeChipsetOverride");
175 Status = ZwSetValueKey(KeyHandle,
176 &KeyString,
177 0,
178 REG_DWORD,
179 &Data,
180 sizeof(Data));
181
182 /* Close subkey */
183 ZwClose(KeyHandle);
184 }
185 }
186
187 /* Return status */
188 return Status;
189 }
190
191 PBUS_HANDLER
192 NTAPI
193 HalpAllocateAndInitPciBusHandler(IN ULONG PciType,
194 IN ULONG BusNo,
195 IN BOOLEAN TestAllocation)
196 {
197 PBUS_HANDLER Bus;
198 PPCIPBUSDATA BusData;
199
200 /* Allocate the bus handler */
201 Bus = HalpAllocateBusHandler(PCIBus,
202 PCIConfiguration,
203 BusNo,
204 Internal,
205 0,
206 sizeof(PCIPBUSDATA));
207
208 /* Set it up */
209 Bus->GetBusData = (PGETSETBUSDATA)HalpGetPCIData;
210 Bus->SetBusData = (PGETSETBUSDATA)HalpSetPCIData;
211 Bus->GetInterruptVector = (PGETINTERRUPTVECTOR)HalpGetPCIIntOnISABus;
212 Bus->AdjustResourceList = (PADJUSTRESOURCELIST)HalpAdjustPCIResourceList;
213 Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES)HalpAssignPCISlotResources;
214 Bus->BusAddresses->Dma.Limit = 0;
215
216 /* Get our custom bus data */
217 BusData = (PPCIPBUSDATA)Bus->BusData;
218
219 /* Setup custom bus data */
220 BusData->CommonData.Tag = PCI_DATA_TAG;
221 BusData->CommonData.Version = PCI_DATA_VERSION;
222 BusData->CommonData.ReadConfig = (PciReadWriteConfig)HalpReadPCIConfig;
223 BusData->CommonData.WriteConfig = (PciReadWriteConfig)HalpWritePCIConfig;
224 BusData->CommonData.Pin2Line = (PciPin2Line)HalpPCIPin2ISALine;
225 BusData->CommonData.Line2Pin = (PciLine2Pin)HalpPCIISALine2Pin;
226 BusData->MaxDevice = PCI_MAX_DEVICES;
227 BusData->GetIrqRange = (PciIrqRange)HalpGetISAFixedPCIIrq;
228
229 /* Initialize the bitmap */
230 RtlInitializeBitMap(&BusData->DeviceConfigured, BusData->ConfiguredBits, 256);
231
232 /* Check the type of PCI bus */
233 switch (PciType)
234 {
235 /* Type 1 PCI Bus */
236 case 1:
237
238 /* Copy the Type 1 handler data */
239 RtlCopyMemory(&PCIConfigHandler,
240 &PCIConfigHandlerType1,
241 sizeof(PCIConfigHandler));
242
243 /* Set correct I/O Ports */
244 BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT;
245 BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
246 break;
247
248 /* Type 2 PCI Bus */
249 case 2:
250
251 /* Copy the Type 1 handler data */
252 RtlCopyMemory(&PCIConfigHandler,
253 &PCIConfigHandlerType2,
254 sizeof (PCIConfigHandler));
255
256 /* Set correct I/O Ports */
257 BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
258 BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
259 BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
260
261 /* Only 16 devices supported, not 32 */
262 BusData->MaxDevice = 16;
263 break;
264
265 default:
266
267 /* Invalid type */
268 DbgPrint("HAL: Unnkown PCI type\n");
269 }
270
271 /* Return the bus handler */
272 return Bus;
273 }
274
275 BOOLEAN
276 NTAPI
277 HalpIsValidPCIDevice(IN PBUS_HANDLER BusHandler,
278 IN PCI_SLOT_NUMBER Slot)
279 {
280 UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH];
281 PPCI_COMMON_CONFIG PciHeader = (PVOID)DataBuffer;
282 ULONG i;
283 ULONG_PTR Address;
284
285 /* Read the PCI header */
286 HalpReadPCIConfig(BusHandler, Slot, PciHeader, 0, PCI_COMMON_HDR_LENGTH);
287
288 /* Make sure it's a valid device */
289 if ((PciHeader->VendorID == PCI_INVALID_VENDORID) ||
290 (PCI_CONFIGURATION_TYPE(PciHeader) != PCI_DEVICE_TYPE))
291 {
292 /* Bail out */
293 return FALSE;
294 }
295
296 /* Make sure interrupt numbers make sense */
297 if (((PciHeader->u.type0.InterruptPin) &&
298 (PciHeader->u.type0.InterruptPin > 4)) ||
299 (PciHeader->u.type0.InterruptLine & 0x70))
300 {
301 /* Bail out */
302 return FALSE;
303 }
304
305 /* Now scan PCI BARs */
306 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
307 {
308 /* Check what kind of address it is */
309 Address = PciHeader->u.type0.BaseAddresses[i];
310 if (Address & PCI_ADDRESS_IO_SPACE)
311 {
312 /* Highest I/O port is 65535 */
313 if (Address > 0xFFFF) return FALSE;
314 }
315 else
316 {
317 /* MMIO should be higher than 0x80000 */
318 if ((Address > 0xF) && (Address < 0x80000)) return FALSE;
319 }
320
321 /* Is this a 64-bit address? */
322 if (!(Address & PCI_ADDRESS_IO_SPACE) &&
323 ((Address & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT))
324 {
325 /* Check the next-next entry, since this one 64-bits wide */
326 i++;
327 }
328 }
329
330 /* Header, interrupt and address data all make sense */
331 return TRUE;
332 }
333
334 static BOOLEAN WarningsGiven[5];
335
336 NTSTATUS
337 NTAPI
338 HalpGetChipHacks(IN USHORT VendorId,
339 IN USHORT DeviceId,
340 IN UCHAR RevisionId,
341 IN PULONG HackFlags)
342 {
343 UNICODE_STRING KeyName, ValueName;
344 NTSTATUS Status;
345 OBJECT_ATTRIBUTES ObjectAttributes;
346 HANDLE KeyHandle;
347 WCHAR Buffer[32];
348 KEY_VALUE_PARTIAL_INFORMATION PartialInfo;
349 ULONG ResultLength;
350
351 /* Setup the object attributes for the key */
352 RtlInitUnicodeString(&KeyName,
353 L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\"
354 L"Control\\HAL");
355 InitializeObjectAttributes(&ObjectAttributes,
356 &KeyName,
357 OBJ_CASE_INSENSITIVE,
358 NULL,
359 NULL);
360
361 /* Open the key */
362 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
363 if (!NT_SUCCESS(Status)) return Status;
364
365 /* Query value */
366 swprintf(Buffer, L"%04X%04X", VendorId, DeviceId);
367 RtlInitUnicodeString(&ValueName, Buffer);
368 Status = ZwQueryValueKey(KeyHandle,
369 &ValueName,
370 KeyValuePartialInformation,
371 &PartialInfo,
372 sizeof(PartialInfo),
373 &ResultLength);
374 if (NT_SUCCESS(Status))
375 {
376 /* Return the flags */
377 DPRINT1("Found HackFlags for your %lx:%lx device\n", VendorId, DeviceId);
378 *HackFlags = *(PULONG)PartialInfo.Data;
379 DPRINT1("Hack Flags: %lx (Hack Revision: %lx\tYour Revision: %lx)\n",
380 *HackFlags, HALP_REVISION_FROM_HACK_FLAGS(*HackFlags), RevisionId);
381
382 /* Does it apply to this revision? */
383 if ((RevisionId) && (RevisionId >= (HALP_REVISION_FROM_HACK_FLAGS(*HackFlags))))
384 {
385 /* Read the revision flags */
386 *HackFlags = HALP_REVISION_HACK_FLAGS(*HackFlags);
387 }
388
389 /* Throw out revision data */
390 *HackFlags = HALP_HACK_FLAGS(*HackFlags);
391 }
392
393 /* Close the handle and return */
394 ZwClose(KeyHandle);
395 return Status;
396 }
397
398 BOOLEAN
399 NTAPI
400 HalpIsRecognizedCard(IN PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo,
401 IN PPCI_COMMON_CONFIG PciData,
402 IN ULONG Flags)
403 {
404 ULONG ElementCount, i;
405 PPCI_CARD_DESCRIPTOR CardDescriptor;
406
407 /* How many PCI Cards that we know about? */
408 ElementCount = PciRegistryInfo->ElementCount;
409 if (!ElementCount) return FALSE;
410
411 /* Loop all descriptors */
412 CardDescriptor = &PciRegistryInfo->CardList[0];
413 for (i = 0; i < ElementCount; i++, CardDescriptor++)
414 {
415 /* Check for flag match */
416 if (CardDescriptor->Flags != Flags) continue;
417
418 /* Check for VID-PID match */
419 if ((CardDescriptor->VendorID != PciData->VendorID) ||
420 (CardDescriptor->DeviceID != PciData->DeviceID))
421 {
422 /* Skip */
423 continue;
424 }
425
426 /* Check for revision match, if requested */
427 if ((CardDescriptor->Flags & HALP_CHECK_CARD_REVISION_ID) &&
428 (CardDescriptor->RevisionID != PciData->RevisionID))
429 {
430 /* Skip */
431 continue;
432 }
433
434 /* Check what kind of device this is */
435 switch (PCI_CONFIGURATION_TYPE(PciData))
436 {
437 /* CardBUS Bridge */
438 case PCI_CARDBUS_BRIDGE_TYPE:
439
440 /* This means the real device header is in the device-specific data */
441 PciData = (PPCI_COMMON_CONFIG)PciData->DeviceSpecific;
442
443 /* Normal PCI device */
444 case PCI_DEVICE_TYPE:
445
446 /* Check for subvendor match, if requested */
447 if ((CardDescriptor->Flags & HALP_CHECK_CARD_SUBVENDOR_ID) &&
448 (CardDescriptor->SubsystemVendorID != PciData->u.type0.SubVendorID))
449 {
450 /* Skip */
451 continue;
452 }
453
454 /* Check for subsystem match, if requested */
455 if ((CardDescriptor->Flags & HALP_CHECK_CARD_SUBSYSTEM_ID) &&
456 (CardDescriptor->SubsystemID != PciData->u.type0.SubSystemID))
457 {
458 /* Skip */
459 continue;
460 }
461
462 /* You made it! */
463 return TRUE;
464
465 /* PCI Bridge -- don't bother */
466 case PCI_BRIDGE_TYPE:
467 default:
468
469 /* Recognize it */
470 return TRUE;
471 }
472 }
473
474 /* This means the card isn't recognized */
475 return FALSE;
476 }
477
478 BOOLEAN
479 NTAPI
480 HalpIsIdeDevice(IN PPCI_COMMON_CONFIG PciData)
481 {
482 /* Simple test first */
483 if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
484 (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
485 {
486 /* The device is nice enough to admit it */
487 return TRUE;
488 }
489
490 /* Symphony 82C101 */
491 if (PciData->VendorID == 0x1C1C) return TRUE;
492
493 /* ALi MS4803 or M5219 */
494 if ((PciData->VendorID == 0x10B9) &&
495 ((PciData->DeviceID == 0x5215) || (PciData->DeviceID == 0x5219)))
496 {
497 return TRUE;
498 }
499
500 /* Appian Technology */
501 if ((PciData->VendorID == 0x1097) && (PciData->DeviceID == 0x38)) return TRUE;
502
503 /* Compaq Triflex Dual EIDE Controller */
504 if ((PciData->VendorID == 0xE11) && (PciData->DeviceID == 0xAE33)) return TRUE;
505
506 /* Micron PC Tech RZ1000 */
507 if ((PciData->VendorID == 0x1042) && (PciData->DeviceID == 0x1000)) return TRUE;
508
509 /* SiS 85C601 or 5513 [IDE] */
510 if ((PciData->VendorID == 0x1039) &&
511 ((PciData->DeviceID == 0x601) || (PciData->DeviceID == 0x5513)))
512 {
513 return TRUE;
514 }
515
516 /* Symphony Labs W83769F */
517 if ((PciData->VendorID == 0x10AD) &&
518 ((PciData->DeviceID == 0x1) || (PciData->DeviceID == 0x150)))
519 {
520 return TRUE;
521 }
522
523 /* UMC UM8673F */
524 if ((PciData->VendorID == 0x1060) && (PciData->DeviceID == 0x101)) return TRUE;
525
526 /* You've survived */
527 return FALSE;
528 }
529
530 BOOLEAN
531 NTAPI
532 HalpIsBridgeDevice(IN PPCI_COMMON_CONFIG PciData)
533 {
534 /* Either this is a PCI-to-PCI Bridge, or a CardBUS Bridge */
535 return (((PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE) &&
536 (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
537 (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)) ||
538 ((PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE) &&
539 (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
540 (PciData->SubClass == PCI_SUBCLASS_BR_CARDBUS)));
541 }
542
543 BOOLEAN
544 NTAPI
545 HalpGetPciBridgeConfig(IN ULONG PciType,
546 IN PUCHAR BusCount)
547 {
548 PCI_SLOT_NUMBER PciSlot;
549 ULONG i, j, k;
550 UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH];
551 PPCI_COMMON_CONFIG PciData = (PPCI_COMMON_CONFIG)DataBuffer;
552 PBUS_HANDLER BusHandler;
553
554 /* Loop PCI buses */
555 PciSlot.u.bits.Reserved = 0;
556 for (i = 0; i < *BusCount; i++)
557 {
558 /* Get the bus handler */
559 BusHandler = HalHandlerForBus(PCIBus, i);
560
561 /* Loop every device */
562 for (j = 0; j < PCI_MAX_DEVICES; j++)
563 {
564 /* Loop every function */
565 PciSlot.u.bits.DeviceNumber = j;
566 for (k = 0; k < PCI_MAX_FUNCTION; k++)
567 {
568 /* Build the final slot structure */
569 PciSlot.u.bits.FunctionNumber = k;
570
571 /* Read the configuration information */
572 HalpReadPCIConfig(BusHandler,
573 PciSlot,
574 PciData,
575 0,
576 PCI_COMMON_HDR_LENGTH);
577
578 /* Skip if this is an invalid function */
579 if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
580
581 /* Make sure that this is a PCI bridge or a cardbus bridge */
582 if (!HalpIsBridgeDevice(PciData)) continue;
583
584 /* Not supported */
585 if (!WarningsGiven[2]++) DPRINT1("Your machine has a PCI-to-PCI or CardBUS Bridge. PCI devices may fail!\n");
586 continue;
587 }
588 }
589 }
590
591 /* If we exited the loop, then there's no bridge to worry about */
592 return FALSE;
593 }
594
595 VOID
596 NTAPI
597 HalpFixupPciSupportedRanges(IN ULONG BusCount)
598 {
599 ULONG i;
600 PBUS_HANDLER Bus, ParentBus;
601
602 /* Loop all buses */
603 for (i = 0; i < BusCount; i++)
604 {
605 /* Get PCI bus handler */
606 Bus = HalHandlerForBus(PCIBus, i);
607
608 /* Loop all parent buses */
609 ParentBus = Bus->ParentHandler;
610 while (ParentBus)
611 {
612 /* Should merge addresses */
613 if (!WarningsGiven[0]++) DPRINT1("Found parent bus (indicating PCI Bridge). PCI devices may fail!\n");
614
615 /* Check the next parent */
616 ParentBus = ParentBus->ParentHandler;
617 }
618 }
619
620 /* Loop all buses again */
621 for (i = 0; i < BusCount; i++)
622 {
623 /* Get PCI bus handler */
624 Bus = HalHandlerForBus(PCIBus, i);
625
626 /* Check if this is a PCI 2.2 Bus with Subtractive Decode */
627 if (!((PPCIPBUSDATA)Bus->BusData)->Subtractive)
628 {
629 /* Loop all parent buses */
630 ParentBus = Bus->ParentHandler;
631 while (ParentBus)
632 {
633 /* But check only PCI parent buses specifically */
634 if (ParentBus->InterfaceType == PCIBus)
635 {
636 /* Should trim addresses */
637 if (!WarningsGiven[1]++) DPRINT1("Found parent PCI Bus (indicating PCI-to-PCI Bridge). PCI devices may fail!\n");
638 }
639
640 /* Check the next parent */
641 ParentBus = ParentBus->ParentHandler;
642 }
643 }
644 }
645
646 /* Loop buses one last time */
647 for (i = 0; i < BusCount; i++)
648 {
649 /* Get the PCI bus handler */
650 Bus = HalHandlerForBus(PCIBus, i);
651
652 /* Sort and combine (trim) bus address range information */
653 DPRINT("Warning: Bus addresses not being optimized!\n");
654 }
655 }
656 #endif
657
658 VOID
659 NTAPI
660 HalpInitializePciBus(VOID)
661 {
662 #ifndef _MINIHAL_
663 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
664 UCHAR PciType;
665 PCI_SLOT_NUMBER PciSlot;
666 ULONG i, j, k;
667 UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH];
668 PPCI_COMMON_CONFIG PciData = (PPCI_COMMON_CONFIG)DataBuffer;
669 PBUS_HANDLER BusHandler;
670 ULONG HackFlags;
671 BOOLEAN ExtendedAddressDecoding = FALSE;
672 NTSTATUS Status;
673
674 /* Query registry information */
675 PciRegistryInfo = HalpQueryPciRegistryInfo();
676 if (!PciRegistryInfo) return;
677
678 /* Initialize the PCI configuration lock */
679 KeInitializeSpinLock(&HalpPCIConfigLock);
680
681 /* Get the type and free the info structure */
682 PciType = PciRegistryInfo->HardwareMechanism & 0xF;
683
684 /* Check if this is a type 2 PCI bus with at least one bus */
685 if ((PciRegistryInfo->NoBuses) && (PciType == 2))
686 {
687 /* Setup the PCI slot */
688 PciSlot.u.bits.Reserved = 0;
689 PciSlot.u.bits.FunctionNumber = 0;
690
691 /* Loop all slots */
692 for (i = 0; i < 32; i++)
693 {
694 /* Try to setup a Type 2 PCI slot */
695 PciType = 2;
696 BusHandler = HalpAllocateAndInitPciBusHandler(2, 0, TRUE);
697 if (!BusHandler) break;
698
699 /* Now check if it's valid */
700 if (HalpIsValidPCIDevice(BusHandler, PciSlot)) break;
701
702 /* Heh, the BIOS lied... try Type 1 */
703 PciType = 1;
704 BusHandler = HalpAllocateAndInitPciBusHandler(1, 0, TRUE);
705 if (!BusHandler) break;
706
707 /* Now check if it's valid */
708 if (HalpIsValidPCIDevice(BusHandler, PciSlot)) break;
709
710 /* Keep trying */
711 PciType = 2;
712 }
713
714 /* Now allocate the correct kind of handler */
715 HalpAllocateAndInitPciBusHandler(PciType, 0, FALSE);
716 }
717
718 /* Okay, now loop all PCI bridges */
719 do
720 {
721 /* Loop all PCI buses */
722 for (i = 0; i < PciRegistryInfo->NoBuses; i++)
723 {
724 /* Check if we have a handler for it */
725 if (!HalHandlerForBus(PCIBus, i))
726 {
727 /* Allocate it */
728 HalpAllocateAndInitPciBusHandler(PciType, i, FALSE);
729 }
730 }
731 /* Go to the next bridge */
732 } while (HalpGetPciBridgeConfig(PciType, &PciRegistryInfo->NoBuses));
733
734 /* Now build correct address range informaiton */
735 HalpFixupPciSupportedRanges(PciRegistryInfo->NoBuses);
736
737 /* Loop every bus */
738 PciSlot.u.bits.Reserved = 0;
739 for (i = 0; i < PciRegistryInfo->NoBuses; i++)
740 {
741 /* Get the bus handler */
742 BusHandler = HalHandlerForBus(PCIBus, i);
743
744 /* Loop every device */
745 for (j = 0; j < 32; j++)
746 {
747 /* Loop every function */
748 PciSlot.u.bits.DeviceNumber = j;
749 for (k = 0; k < 8; k++)
750 {
751 /* Build the final slot structure */
752 PciSlot.u.bits.FunctionNumber = k;
753
754 /* Read the configuration information */
755 HalpReadPCIConfig(BusHandler,
756 PciSlot,
757 PciData,
758 0,
759 PCI_COMMON_HDR_LENGTH);
760
761 /* Skip if this is an invalid function */
762 if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
763
764 /* Check if this is a Cardbus bridge */
765 if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
766 {
767 /* Not supported */
768 DPRINT1("Your machine has a PCI Cardbus Bridge. This device will not work!\n");
769 continue;
770 }
771
772 /* Check if this is a PCI device */
773 if (PCI_CONFIGURATION_TYPE(PciData) != PCI_BRIDGE_TYPE)
774 {
775 /* Check if it has an interrupt pin and line registered */
776 if ((PciData->u.type1.InterruptPin) &&
777 (PciData->u.type1.InterruptLine))
778 {
779 /* Check if this interrupt line is connected to the bus */
780 if (PciData->u.type1.InterruptLine < 16)
781 {
782 /* Is this an IDE device? */
783 if (!HalpIsIdeDevice(PciData))
784 {
785 /* We'll mask out this interrupt then */
786 DPRINT1("Device %lx:%lx is using IRQ %d! ISA Cards using that IRQ may fail!\n",
787 PciData->VendorID, PciData->DeviceID,
788 PciData->u.type1.InterruptLine);
789 HalpPciIrqMask |= (1 << PciData->u.type1.InterruptLine);
790 }
791 }
792 }
793 }
794
795 /* Check for broken Intel chips */
796 if (PciData->VendorID == 0x8086)
797 {
798 /* Check for broken 82830 PCI controller */
799 if ((PciData->DeviceID == 0x04A3) &&
800 (PciData->RevisionID < 0x11))
801 {
802 /* Skip */
803 DPRINT1("Your machine has a broken Intel 82430 PCI Controller. This device will not work!\n");
804 continue;
805 }
806
807 /* Check for broken 82378 PCI-to-ISA Bridge */
808 if ((PciData->DeviceID == 0x0484) &&
809 (PciData->RevisionID <= 3))
810 {
811 /* Skip */
812 DPRINT1("Your machine has a broken Intel 82378 PCI-to-ISA Bridge. This device will not work!\n");
813 continue;
814 }
815
816 /* Check for broken 82450 PCI Bridge */
817 if ((PciData->DeviceID == 0x84C4) &&
818 (PciData->RevisionID <= 4))
819 {
820 DPRINT1("Your machine has an Intel Orion 82450 PCI Bridge. This device will not work!\n");
821 continue;
822 }
823 }
824
825 /* Do we know this card? */
826 if (!ExtendedAddressDecoding)
827 {
828 /* Check for it */
829 if (HalpIsRecognizedCard(PciRegistryInfo,
830 PciData,
831 HALP_CARD_FEATURE_FULL_DECODE))
832 {
833 /* We'll do chipset checks later */
834 DPRINT1("Your %lx:%lx PCI device has Extended Address Decoding. This device may fail to work on older BIOSes!\n",
835 PciData->VendorID, PciData->DeviceID);
836 ExtendedAddressDecoding = TRUE;
837 }
838 }
839
840 /* Check if this is a USB controller */
841 if ((PciData->BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
842 (PciData->SubClass == PCI_SUBCLASS_SB_USB))
843 {
844 /* Check if this is an OHCI controller */
845 if (PciData->ProgIf == 0x10)
846 {
847 DPRINT1("Your machine has an OHCI (USB) PCI Expansion Card. Turn off Legacy USB in your BIOS!\n");
848 continue;
849 }
850
851 /* Check for Intel UHCI controller */
852 if (PciData->VendorID == 0x8086)
853 {
854 DPRINT1("Your machine has an Intel UHCI (USB) Controller. Turn off Legacy USB in your BIOS!\n");
855 continue;
856 }
857
858 /* Check for VIA UHCI controller */
859 if (PciData->VendorID == 0x1106)
860 {
861 DPRINT1("Your machine has a VIA UHCI (USB) Controller. Turn off Legacy USB in your BIOS!\n");
862 continue;
863 }
864 }
865
866 /* Now check the registry for chipset hacks */
867 Status = HalpGetChipHacks(PciData->VendorID,
868 PciData->DeviceID,
869 PciData->RevisionID,
870 &HackFlags);
871 if (NT_SUCCESS(Status))
872 {
873 /* Check for broken ACPI routing */
874 if (HackFlags & HAL_PCI_CHIP_HACK_DISABLE_ACPI_IRQ_ROUTING)
875 {
876 DPRINT1("Your hardware has broken ACPI IRQ Routing! Be aware!\n");
877 continue;
878 }
879
880 /* Check for broken ACPI timer */
881 if (HackFlags & HAL_PCI_CHIP_HACK_BROKEN_ACPI_TIMER)
882 {
883 DPRINT1("Your hardware has a broken ACPI timer! Be aware!\n");
884 continue;
885 }
886
887 /* Check for hibernate-disable */
888 if (HackFlags & HAL_PCI_CHIP_HACK_DISABLE_HIBERNATE)
889 {
890 DPRINT1("Your machine has a broken PCI device which is incompatible with hibernation. Be aware!\n");
891 continue;
892 }
893
894 /* Check for USB controllers that generate SMIs */
895 if (HackFlags & HAL_PCI_CHIP_HACK_USB_SMI_DISABLE)
896 {
897 DPRINT1("Your machine has a USB controller which generates SMIs. ReactOS will likely fail to boot!\n");
898 continue;
899 }
900 }
901 }
902 }
903 }
904
905 /* Initialize NMI Crash Flag */
906 HalpGetNMICrashFlag();
907
908 /* Free the registry data */
909 ExFreePool(PciRegistryInfo);
910
911 /* Tell PnP if this hard supports correct decoding */
912 HalpMarkChipsetDecode(ExtendedAddressDecoding);
913 DPRINT1("PCI BUS Setup complete\n");
914 #endif
915 }
916
917 VOID
918 NTAPI
919 HalpInitBusHandlers(VOID)
920 {
921 /* Register the HAL Bus Handler support */
922 HalpRegisterInternalBusHandlers();
923 }
924
925 VOID
926 NTAPI
927 HalpRegisterKdSupportFunctions(VOID)
928 {
929 /* Register PCI Device Functions */
930 KdSetupPciDeviceForDebugging = HalpSetupPciDeviceForDebugging;
931 KdReleasePciDeviceforDebugging = HalpReleasePciDeviceForDebugging;
932
933 /* Register memory functions */
934 #ifndef _MINIHAL_
935 KdMapPhysicalMemory64 = HalpMapPhysicalMemory64;
936 KdUnmapVirtualAddress = HalpUnmapVirtualAddress;
937 #endif
938
939 /* Register ACPI stub */
940 KdCheckPowerButton = HalpCheckPowerButton;
941 }
942
943 NTSTATUS
944 NTAPI
945 HalpAssignSlotResources(IN PUNICODE_STRING RegistryPath,
946 IN PUNICODE_STRING DriverClassName,
947 IN PDRIVER_OBJECT DriverObject,
948 IN PDEVICE_OBJECT DeviceObject,
949 IN INTERFACE_TYPE BusType,
950 IN ULONG BusNumber,
951 IN ULONG SlotNumber,
952 IN OUT PCM_RESOURCE_LIST *AllocatedResources)
953 {
954 BUS_HANDLER BusHandler;
955 PAGED_CODE();
956
957 /* Only PCI is supported */
958 if (BusType != PCIBus) return STATUS_NOT_IMPLEMENTED;
959
960 /* Setup fake PCI Bus handler */
961 RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
962 BusHandler.BusNumber = BusNumber;
963
964 /* Call the PCI function */
965 return HalpAssignPCISlotResources(&BusHandler,
966 &BusHandler,
967 RegistryPath,
968 DriverClassName,
969 DriverObject,
970 DeviceObject,
971 SlotNumber,
972 AllocatedResources);
973 }
974
975 BOOLEAN
976 NTAPI
977 HalpTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
978 IN ULONG BusNumber,
979 IN PHYSICAL_ADDRESS BusAddress,
980 IN OUT PULONG AddressSpace,
981 OUT PPHYSICAL_ADDRESS TranslatedAddress)
982 {
983 /* Translation is easy */
984 TranslatedAddress->QuadPart = BusAddress.QuadPart;
985 return TRUE;
986 }
987
988 ULONG
989 NTAPI
990 HalpGetSystemInterruptVector_Acpi(IN ULONG BusNumber,
991 IN ULONG BusInterruptLevel,
992 IN ULONG BusInterruptVector,
993 OUT PKIRQL Irql,
994 OUT PKAFFINITY Affinity)
995 {
996 ULONG Vector = IRQ2VECTOR(BusInterruptLevel);
997 *Irql = (KIRQL)VECTOR2IRQL(Vector);
998 *Affinity = 0xFFFFFFFF;
999 return Vector;
1000 }
1001
1002 BOOLEAN
1003 NTAPI
1004 HalpFindBusAddressTranslation(IN PHYSICAL_ADDRESS BusAddress,
1005 IN OUT PULONG AddressSpace,
1006 OUT PPHYSICAL_ADDRESS TranslatedAddress,
1007 IN OUT PULONG_PTR Context,
1008 IN BOOLEAN NextBus)
1009 {
1010 /* Make sure we have a context */
1011 if (!Context) return FALSE;
1012
1013 /* If we have data in the context, then this shouldn't be a new lookup */
1014 if ((*Context) && (NextBus == TRUE)) return FALSE;
1015
1016 /* Return bus data */
1017 TranslatedAddress->QuadPart = BusAddress.QuadPart;
1018
1019 /* Set context value and return success */
1020 *Context = 1;
1021 return TRUE;
1022 }
1023
1024 /* PUBLIC FUNCTIONS **********************************************************/
1025
1026 /*
1027 * @implemented
1028 */
1029 NTSTATUS
1030 NTAPI
1031 HalAdjustResourceList(IN PCM_RESOURCE_LIST Resources)
1032 {
1033 /* Deprecated, return success */
1034 return STATUS_SUCCESS;
1035 }
1036
1037 /*
1038 * @implemented
1039 */
1040 NTSTATUS
1041 NTAPI
1042 HalAssignSlotResources(IN PUNICODE_STRING RegistryPath,
1043 IN PUNICODE_STRING DriverClassName,
1044 IN PDRIVER_OBJECT DriverObject,
1045 IN PDEVICE_OBJECT DeviceObject,
1046 IN INTERFACE_TYPE BusType,
1047 IN ULONG BusNumber,
1048 IN ULONG SlotNumber,
1049 IN OUT PCM_RESOURCE_LIST *AllocatedResources)
1050 {
1051 /* Check the bus type */
1052 if (BusType != PCIBus)
1053 {
1054 /* Call our internal handler */
1055 return HalpAssignSlotResources(RegistryPath,
1056 DriverClassName,
1057 DriverObject,
1058 DeviceObject,
1059 BusType,
1060 BusNumber,
1061 SlotNumber,
1062 AllocatedResources);
1063 }
1064 else
1065 {
1066 /* Call the PCI registered function */
1067 return HalPciAssignSlotResources(RegistryPath,
1068 DriverClassName,
1069 DriverObject,
1070 DeviceObject,
1071 PCIBus,
1072 BusNumber,
1073 SlotNumber,
1074 AllocatedResources);
1075 }
1076 }
1077
1078 /*
1079 * @implemented
1080 */
1081 ULONG
1082 NTAPI
1083 HalGetBusData(IN BUS_DATA_TYPE BusDataType,
1084 IN ULONG BusNumber,
1085 IN ULONG SlotNumber,
1086 IN PVOID Buffer,
1087 IN ULONG Length)
1088 {
1089 /* Call the extended function */
1090 return HalGetBusDataByOffset(BusDataType,
1091 BusNumber,
1092 SlotNumber,
1093 Buffer,
1094 0,
1095 Length);
1096 }
1097
1098 /*
1099 * @implemented
1100 */
1101 ULONG
1102 NTAPI
1103 HalGetBusDataByOffset(IN BUS_DATA_TYPE BusDataType,
1104 IN ULONG BusNumber,
1105 IN ULONG SlotNumber,
1106 IN PVOID Buffer,
1107 IN ULONG Offset,
1108 IN ULONG Length)
1109 {
1110 BUS_HANDLER BusHandler;
1111
1112 /* Look as the bus type */
1113 if (BusDataType == Cmos)
1114 {
1115 /* Call CMOS Function */
1116 return HalpGetCmosData(0, SlotNumber, Buffer, Length);
1117 }
1118 else if (BusDataType == EisaConfiguration)
1119 {
1120 /* FIXME: TODO */
1121 ASSERT(FALSE);
1122 }
1123 else if ((BusDataType == PCIConfiguration) &&
1124 (HalpPCIConfigInitialized) &&
1125 ((BusNumber >= HalpMinPciBus) && (BusNumber <= HalpMaxPciBus)))
1126 {
1127 /* Setup fake PCI Bus handler */
1128 RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
1129 BusHandler.BusNumber = BusNumber;
1130
1131 /* Call PCI function */
1132 return HalpGetPCIData(&BusHandler,
1133 &BusHandler,
1134 *(PPCI_SLOT_NUMBER)&SlotNumber,
1135 Buffer,
1136 Offset,
1137 Length);
1138 }
1139
1140 /* Invalid bus */
1141 return 0;
1142 }
1143
1144 /*
1145 * @implemented
1146 */
1147 ULONG
1148 NTAPI
1149 HalGetInterruptVector(IN INTERFACE_TYPE InterfaceType,
1150 IN ULONG BusNumber,
1151 IN ULONG BusInterruptLevel,
1152 IN ULONG BusInterruptVector,
1153 OUT PKIRQL Irql,
1154 OUT PKAFFINITY Affinity)
1155 {
1156 /* Call the system bus translator */
1157 return HalpGetSystemInterruptVector_Acpi(BusNumber,
1158 BusInterruptLevel,
1159 BusInterruptVector,
1160 Irql,
1161 Affinity);
1162 }
1163
1164 /*
1165 * @implemented
1166 */
1167 ULONG
1168 NTAPI
1169 HalSetBusData(IN BUS_DATA_TYPE BusDataType,
1170 IN ULONG BusNumber,
1171 IN ULONG SlotNumber,
1172 IN PVOID Buffer,
1173 IN ULONG Length)
1174 {
1175 /* Call the extended function */
1176 return HalSetBusDataByOffset(BusDataType,
1177 BusNumber,
1178 SlotNumber,
1179 Buffer,
1180 0,
1181 Length);
1182 }
1183
1184 /*
1185 * @implemented
1186 */
1187 ULONG
1188 NTAPI
1189 HalSetBusDataByOffset(IN BUS_DATA_TYPE BusDataType,
1190 IN ULONG BusNumber,
1191 IN ULONG SlotNumber,
1192 IN PVOID Buffer,
1193 IN ULONG Offset,
1194 IN ULONG Length)
1195 {
1196 BUS_HANDLER BusHandler;
1197
1198 /* Look as the bus type */
1199 if (BusDataType == Cmos)
1200 {
1201 /* Call CMOS Function */
1202 return HalpSetCmosData(0, SlotNumber, Buffer, Length);
1203 }
1204 else if ((BusDataType == PCIConfiguration) && (HalpPCIConfigInitialized))
1205 {
1206 /* Setup fake PCI Bus handler */
1207 RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
1208 BusHandler.BusNumber = BusNumber;
1209
1210 /* Call PCI function */
1211 return HalpSetPCIData(&BusHandler,
1212 &BusHandler,
1213 *(PPCI_SLOT_NUMBER)&SlotNumber,
1214 Buffer,
1215 Offset,
1216 Length);
1217 }
1218
1219 /* Invalid bus */
1220 return 0;
1221 }
1222
1223 /*
1224 * @implemented
1225 */
1226 BOOLEAN
1227 NTAPI
1228 HalTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
1229 IN ULONG BusNumber,
1230 IN PHYSICAL_ADDRESS BusAddress,
1231 IN OUT PULONG AddressSpace,
1232 OUT PPHYSICAL_ADDRESS TranslatedAddress)
1233 {
1234 /* Look as the bus type */
1235 if (InterfaceType == PCIBus)
1236 {
1237 /* Call the PCI registered function */
1238 return HalPciTranslateBusAddress(PCIBus,
1239 BusNumber,
1240 BusAddress,
1241 AddressSpace,
1242 TranslatedAddress);
1243 }
1244 else
1245 {
1246 /* Translation is easy */
1247 TranslatedAddress->QuadPart = BusAddress.QuadPart;
1248 return TRUE;
1249 }
1250 }
1251
1252 /* EOF */