xref: /reactos/hal/halx86/legacy/bus/pcibus.c (revision e419195d)
1 /*
2  * PROJECT:         ReactOS HAL
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            hal/halx86/legacy/bus/pcibus.c
5  * PURPOSE:         PCI Bus Support (Configuration Space, Resource Allocation)
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_)
16 #pragma alloc_text(INIT, HalpInitializePciStubs)
17 #pragma alloc_text(INIT, HalpQueryPciRegistryInfo)
18 #pragma alloc_text(INIT, HalpRegisterPciDebuggingDeviceInfo)
19 #pragma alloc_text(INIT, HalpReleasePciDeviceForDebugging)
20 #pragma alloc_text(INIT, HalpSetupPciDeviceForDebugging)
21 #endif
22 
23 /* GLOBALS *******************************************************************/
24 
25 extern BOOLEAN HalpPciLockSettings;
26 ULONG HalpBusType;
27 
28 PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice[2] = {{{{0}}}};
29 
30 BOOLEAN HalpPCIConfigInitialized;
31 ULONG HalpMinPciBus, HalpMaxPciBus;
32 KSPIN_LOCK HalpPCIConfigLock;
33 PCI_CONFIG_HANDLER PCIConfigHandler;
34 
35 /* PCI Operation Matrix */
36 UCHAR PCIDeref[4][4] =
37 {
38     {0, 1, 2, 2},   // ULONG-aligned offset
39     {1, 1, 1, 1},   // UCHAR-aligned offset
40     {2, 1, 2, 2},   // USHORT-aligned offset
41     {1, 1, 1, 1}    // UCHAR-aligned offset
42 };
43 
44 /* Type 1 PCI Bus */
45 PCI_CONFIG_HANDLER PCIConfigHandlerType1 =
46 {
47     /* Synchronization */
48     (FncSync)HalpPCISynchronizeType1,
49     (FncReleaseSync)HalpPCIReleaseSynchronzationType1,
50 
51     /* Read */
52     {
53         (FncConfigIO)HalpPCIReadUlongType1,
54         (FncConfigIO)HalpPCIReadUcharType1,
55         (FncConfigIO)HalpPCIReadUshortType1
56     },
57 
58     /* Write */
59     {
60         (FncConfigIO)HalpPCIWriteUlongType1,
61         (FncConfigIO)HalpPCIWriteUcharType1,
62         (FncConfigIO)HalpPCIWriteUshortType1
63     }
64 };
65 
66 /* Type 2 PCI Bus */
67 PCI_CONFIG_HANDLER PCIConfigHandlerType2 =
68 {
69     /* Synchronization */
70     (FncSync)HalpPCISynchronizeType2,
71     (FncReleaseSync)HalpPCIReleaseSynchronizationType2,
72 
73     /* Read */
74     {
75         (FncConfigIO)HalpPCIReadUlongType2,
76         (FncConfigIO)HalpPCIReadUcharType2,
77         (FncConfigIO)HalpPCIReadUshortType2
78     },
79 
80     /* Write */
81     {
82         (FncConfigIO)HalpPCIWriteUlongType2,
83         (FncConfigIO)HalpPCIWriteUcharType2,
84         (FncConfigIO)HalpPCIWriteUshortType2
85     }
86 };
87 
88 PCIPBUSDATA HalpFakePciBusData =
89 {
90     {
91         PCI_DATA_TAG,
92         PCI_DATA_VERSION,
93         HalpReadPCIConfig,
94         HalpWritePCIConfig,
95         NULL,
96         NULL,
97         {{{0, 0, 0}}},
98         {0, 0, 0, 0}
99     },
100     {{0, 0}},
101     32,
102 };
103 
104 BUS_HANDLER HalpFakePciBusHandler =
105 {
106     1,
107     PCIBus,
108     PCIConfiguration,
109     0,
110     NULL,
111     NULL,
112     &HalpFakePciBusData,
113     0,
114     NULL,
115     {0, 0, 0, 0},
116     (PGETSETBUSDATA)HalpGetPCIData,
117     (PGETSETBUSDATA)HalpSetPCIData,
118     NULL,
119     HalpAssignPCISlotResources,
120     NULL,
121     NULL
122 };
123 
124 /* TYPE 1 FUNCTIONS **********************************************************/
125 
126 VOID
127 NTAPI
128 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler,
129                         IN PCI_SLOT_NUMBER Slot,
130                         IN PKIRQL Irql,
131                         IN PPCI_TYPE1_CFG_BITS PciCfg1)
132 {
133     /* Setup the PCI Configuration Register */
134     PciCfg1->u.AsULONG = 0;
135     PciCfg1->u.bits.BusNumber = BusHandler->BusNumber;
136     PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber;
137     PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber;
138     PciCfg1->u.bits.Enable = TRUE;
139 
140     /* Acquire the lock */
141     KeRaiseIrql(HIGH_LEVEL, Irql);
142     KiAcquireSpinLock(&HalpPCIConfigLock);
143 }
144 
145 VOID
146 NTAPI
147 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler,
148                                   IN KIRQL Irql)
149 {
150     PCI_TYPE1_CFG_BITS PciCfg1;
151 
152     /* Clear the PCI Configuration Register */
153     PciCfg1.u.AsULONG = 0;
154     WRITE_PORT_ULONG(((PPCIPBUSDATA)BusHandler->BusData)->Config.Type1.Address,
155                      PciCfg1.u.AsULONG);
156 
157     /* Release the lock */
158     KiReleaseSpinLock(&HalpPCIConfigLock);
159     KeLowerIrql(Irql);
160 }
161 
162 TYPE1_READ(HalpPCIReadUcharType1, UCHAR)
163 TYPE1_READ(HalpPCIReadUshortType1, USHORT)
164 TYPE1_READ(HalpPCIReadUlongType1, ULONG)
165 TYPE1_WRITE(HalpPCIWriteUcharType1, UCHAR)
166 TYPE1_WRITE(HalpPCIWriteUshortType1, USHORT)
167 TYPE1_WRITE(HalpPCIWriteUlongType1, ULONG)
168 
169 /* TYPE 2 FUNCTIONS **********************************************************/
170 
171 VOID
172 NTAPI
173 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler,
174                         IN PCI_SLOT_NUMBER Slot,
175                         IN PKIRQL Irql,
176                         IN PPCI_TYPE2_ADDRESS_BITS PciCfg)
177 {
178     PCI_TYPE2_CSE_BITS PciCfg2Cse;
179     PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
180 
181     /* Setup the configuration register */
182     PciCfg->u.AsUSHORT = 0;
183     PciCfg->u.bits.Agent = (USHORT)Slot.u.bits.DeviceNumber;
184     PciCfg->u.bits.AddressBase = (USHORT)BusData->Config.Type2.Base;
185 
186     /* Acquire the lock */
187     KeRaiseIrql(HIGH_LEVEL, Irql);
188     KiAcquireSpinLock(&HalpPCIConfigLock);
189 
190     /* Setup the CSE Register */
191     PciCfg2Cse.u.AsUCHAR = 0;
192     PciCfg2Cse.u.bits.Enable = TRUE;
193     PciCfg2Cse.u.bits.FunctionNumber = (UCHAR)Slot.u.bits.FunctionNumber;
194     PciCfg2Cse.u.bits.Key = -1;
195 
196     /* Write the bus number and CSE */
197     WRITE_PORT_UCHAR(BusData->Config.Type2.Forward,
198                      (UCHAR)BusHandler->BusNumber);
199     WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
200 }
201 
202 VOID
203 NTAPI
204 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler,
205                                    IN KIRQL Irql)
206 {
207     PCI_TYPE2_CSE_BITS PciCfg2Cse;
208     PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
209 
210     /* Clear CSE and bus number */
211     PciCfg2Cse.u.AsUCHAR = 0;
212     WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
213     WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, 0);
214 
215     /* Release the lock */
216     KiReleaseSpinLock(&HalpPCIConfigLock);
217     KeLowerIrql(Irql);
218 }
219 
220 TYPE2_READ(HalpPCIReadUcharType2, UCHAR)
221 TYPE2_READ(HalpPCIReadUshortType2, USHORT)
222 TYPE2_READ(HalpPCIReadUlongType2, ULONG)
223 TYPE2_WRITE(HalpPCIWriteUcharType2, UCHAR)
224 TYPE2_WRITE(HalpPCIWriteUshortType2, USHORT)
225 TYPE2_WRITE(HalpPCIWriteUlongType2, ULONG)
226 
227 /* PCI CONFIGURATION SPACE ***************************************************/
228 
229 VOID
230 NTAPI
231 HalpPCIConfig(IN PBUS_HANDLER BusHandler,
232               IN PCI_SLOT_NUMBER Slot,
233               IN PUCHAR Buffer,
234               IN ULONG Offset,
235               IN ULONG Length,
236               IN FncConfigIO *ConfigIO)
237 {
238     KIRQL OldIrql;
239     ULONG i;
240     UCHAR State[20];
241 
242     /* Synchronize the operation */
243     PCIConfigHandler.Synchronize(BusHandler, Slot, &OldIrql, State);
244 
245     /* Loop every increment */
246     while (Length)
247     {
248         /* Find out the type of read/write we need to do */
249         i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
250 
251         /* Do the read/write and return the number of bytes */
252         i = ConfigIO[i]((PPCIPBUSDATA)BusHandler->BusData,
253                         State,
254                         Buffer,
255                         Offset);
256 
257         /* Increment the buffer position and offset, and decrease the length */
258         Offset += i;
259         Buffer += i;
260         Length -= i;
261     }
262 
263     /* Release the lock and PCI bus */
264     PCIConfigHandler.ReleaseSynchronzation(BusHandler, OldIrql);
265 }
266 
267 VOID
268 NTAPI
269 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler,
270                   IN PCI_SLOT_NUMBER Slot,
271                   IN PVOID Buffer,
272                   IN ULONG Offset,
273                   IN ULONG Length)
274 {
275     /* Validate the PCI Slot */
276     if (!HalpValidPCISlot(BusHandler, Slot))
277     {
278         /* Fill the buffer with invalid data */
279         RtlFillMemory(Buffer, Length, -1);
280     }
281     else
282     {
283         /* Send the request */
284         HalpPCIConfig(BusHandler,
285                       Slot,
286                       Buffer,
287                       Offset,
288                       Length,
289                       PCIConfigHandler.ConfigRead);
290     }
291 }
292 
293 VOID
294 NTAPI
295 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler,
296                    IN PCI_SLOT_NUMBER Slot,
297                    IN PVOID Buffer,
298                    IN ULONG Offset,
299                    IN ULONG Length)
300 {
301     /* Validate the PCI Slot */
302     if (HalpValidPCISlot(BusHandler, Slot))
303     {
304         /* Send the request */
305         HalpPCIConfig(BusHandler,
306                       Slot,
307                       Buffer,
308                       Offset,
309                       Length,
310                       PCIConfigHandler.ConfigWrite);
311     }
312 }
313 
314 #ifdef SARCH_XBOX
315 BOOLEAN
316 NTAPI
317 HalpXboxBlacklistedPCISlot(IN PBUS_HANDLER BusHandler,
318                            IN PCI_SLOT_NUMBER Slot)
319 {
320     /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
321      * hang the Xbox. Also, the device number doesn't seem to be decoded for the
322      * video card, so it appears to be present on 1:0:0 - 1:31:0.
323      * We hack around these problems by indicating "device not present" for devices
324      * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
325     if ((BusHandler->BusNumber == 0 && Slot.u.bits.DeviceNumber == 0 &&
326         (Slot.u.bits.FunctionNumber == 1 || Slot.u.bits.FunctionNumber == 2)) ||
327         (BusHandler->BusNumber == 1 && Slot.u.bits.DeviceNumber != 0))
328     {
329         DPRINT("Blacklisted PCI slot (%d:%d:%d)\n", BusHandler->BusNumber, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
330         return TRUE;
331     }
332 
333     /* Temporary hack to avoid stack overflow in kernel, see CORE-16319 */
334     if (BusHandler->BusNumber == 0 && Slot.u.bits.DeviceNumber == 8 && Slot.u.bits.FunctionNumber == 0)
335     {
336         DPRINT("Blacklisted PCI-to-PCI bridge (00:08.0 - PCI\\VEN_10DE&DEV_01B8, see CORE-16319)\n");
337         return TRUE;
338     }
339 
340     return FALSE;
341 }
342 #endif
343 
344 BOOLEAN
345 NTAPI
346 HalpValidPCISlot(IN PBUS_HANDLER BusHandler,
347                  IN PCI_SLOT_NUMBER Slot)
348 {
349     PCI_SLOT_NUMBER MultiSlot;
350     PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
351     UCHAR HeaderType;
352     //ULONG Device;
353 
354     /* Simple validation */
355     if (Slot.u.bits.Reserved) return FALSE;
356     if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) return FALSE;
357 
358 #ifdef SARCH_XBOX
359     if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) return FALSE;
360 #endif
361 
362     /* Function 0 doesn't need checking */
363     if (!Slot.u.bits.FunctionNumber) return TRUE;
364 
365     /* Functions 0+ need Multi-Function support, so check the slot */
366     //Device = Slot.u.bits.DeviceNumber;
367     MultiSlot = Slot;
368     MultiSlot.u.bits.FunctionNumber = 0;
369 
370     /* Send function 0 request to get the header back */
371     HalpReadPCIConfig(BusHandler,
372                       MultiSlot,
373                       &HeaderType,
374                       FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType),
375                       sizeof(UCHAR));
376 
377     /* Now make sure the header is multi-function */
378     if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) return FALSE;
379     return TRUE;
380 }
381 
382 /* HAL PCI CALLBACKS *********************************************************/
383 
384 ULONG
385 NTAPI
386 HalpGetPCIData(IN PBUS_HANDLER BusHandler,
387                IN PBUS_HANDLER RootHandler,
388                IN ULONG SlotNumber,
389                IN PVOID Buffer,
390                IN ULONG Offset,
391                IN ULONG Length)
392 {
393     PCI_SLOT_NUMBER Slot;
394     UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH];
395     PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer;
396     ULONG Len = 0;
397 
398     Slot.u.AsULONG = SlotNumber;
399 #ifdef SARCH_XBOX
400     if (HalpXboxBlacklistedPCISlot(BusHandler, Slot))
401     {
402         if (Offset == 0 && Length >= sizeof(USHORT))
403         {
404             *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
405             return sizeof(USHORT);
406         }
407         return 0;
408     }
409 #endif
410 
411     /* Normalize the length */
412     if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG);
413 
414     /* Check if this is a vendor-specific read */
415     if (Offset >= PCI_COMMON_HDR_LENGTH)
416     {
417         /* Read the header */
418         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG));
419 
420         /* Make sure the vendor is valid */
421         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
422     }
423     else
424     {
425         /* Read the entire header */
426         Len = PCI_COMMON_HDR_LENGTH;
427         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len);
428 
429         /* Validate the vendor ID */
430         if (PciConfig->VendorID == PCI_INVALID_VENDORID)
431         {
432             /* It's invalid, but we want to return this much */
433             Len = sizeof(USHORT);
434         }
435 
436         /* Now check if there's space left */
437         if (Len < Offset) return 0;
438 
439         /* There is, so return what's after the offset and normalize */
440         Len -= Offset;
441         if (Len > Length) Len = Length;
442 
443         /* Copy the data into the caller's buffer */
444         RtlMoveMemory(Buffer, PciBuffer + Offset, Len);
445 
446         /* Update buffer and offset, decrement total length */
447         Offset += Len;
448         Buffer = (PVOID)((ULONG_PTR)Buffer + Len);
449         Length -= Len;
450     }
451 
452     /* Now we still have something to copy */
453     if (Length)
454     {
455         /* Check if it's vendor-specific data */
456         if (Offset >= PCI_COMMON_HDR_LENGTH)
457         {
458             /* Read it now */
459             HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length);
460             Len += Length;
461         }
462     }
463 
464     /* Update the total length read */
465     return Len;
466 }
467 
468 ULONG
469 NTAPI
470 HalpSetPCIData(IN PBUS_HANDLER BusHandler,
471                IN PBUS_HANDLER RootHandler,
472                IN ULONG SlotNumber,
473                IN PVOID Buffer,
474                IN ULONG Offset,
475                IN ULONG Length)
476 {
477     PCI_SLOT_NUMBER Slot;
478     UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH];
479     PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer;
480     ULONG Len = 0;
481 
482     Slot.u.AsULONG = SlotNumber;
483 #ifdef SARCH_XBOX
484     if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) return 0;
485 #endif
486 
487     /* Normalize the length */
488     if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG);
489 
490     /* Check if this is a vendor-specific read */
491     if (Offset >= PCI_COMMON_HDR_LENGTH)
492     {
493         /* Read the header */
494         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG));
495 
496         /* Make sure the vendor is valid */
497         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
498     }
499     else
500     {
501         /* Read the entire header and validate the vendor ID */
502         Len = PCI_COMMON_HDR_LENGTH;
503         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len);
504         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
505 
506         /* Return what's after the offset and normalize */
507         Len -= Offset;
508         if (Len > Length) Len = Length;
509 
510         /* Copy the specific caller data */
511         RtlMoveMemory(PciBuffer + Offset, Buffer, Len);
512 
513         /* Write the actual configuration data */
514         HalpWritePCIConfig(BusHandler, Slot, PciBuffer + Offset, Offset, Len);
515 
516         /* Update buffer and offset, decrement total length */
517         Offset += Len;
518         Buffer = (PVOID)((ULONG_PTR)Buffer + Len);
519         Length -= Len;
520     }
521 
522     /* Now we still have something to copy */
523     if (Length)
524     {
525         /* Check if it's vendor-specific data */
526         if (Offset >= PCI_COMMON_HDR_LENGTH)
527         {
528             /* Read it now */
529             HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length);
530             Len += Length;
531         }
532     }
533 
534     /* Update the total length read */
535     return Len;
536 }
537 
538 ULONG
539 NTAPI
540 HalpGetPCIIntOnISABus(IN PBUS_HANDLER BusHandler,
541                       IN PBUS_HANDLER RootHandler,
542                       IN ULONG BusInterruptLevel,
543                       IN ULONG BusInterruptVector,
544                       OUT PKIRQL Irql,
545                       OUT PKAFFINITY Affinity)
546 {
547     /* Validate the level first */
548     if (BusInterruptLevel < 1) return 0;
549 
550     /* PCI has its IRQs on top of ISA IRQs, so pass it on to the ISA handler */
551     return HalGetInterruptVector(Isa,
552                                  0,
553                                  BusInterruptLevel,
554                                  0,
555                                  Irql,
556                                  Affinity);
557 }
558 
559 VOID
560 NTAPI
561 HalpPCIPin2ISALine(IN PBUS_HANDLER BusHandler,
562                    IN PBUS_HANDLER RootHandler,
563                    IN PCI_SLOT_NUMBER SlotNumber,
564                    IN PPCI_COMMON_CONFIG PciData)
565 {
566     UNIMPLEMENTED_DBGBREAK();
567 }
568 
569 VOID
570 NTAPI
571 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler,
572                    IN PBUS_HANDLER RootHandler,
573                    IN PCI_SLOT_NUMBER SlotNumber,
574                    IN PPCI_COMMON_CONFIG PciNewData,
575                    IN PPCI_COMMON_CONFIG PciOldData)
576 {
577     UNIMPLEMENTED_DBGBREAK();
578 }
579 
580 NTSTATUS
581 NTAPI
582 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler,
583                       IN PBUS_HANDLER RootHandler,
584                       IN PCI_SLOT_NUMBER PciSlot,
585                       OUT PSUPPORTED_RANGE *Range)
586 {
587     PCI_COMMON_HEADER PciData;
588 
589     /* Read PCI configuration data */
590     HalGetBusData(PCIConfiguration,
591                   BusHandler->BusNumber,
592                   PciSlot.u.AsULONG,
593                   &PciData,
594                   PCI_COMMON_HDR_LENGTH);
595 
596     /* Make sure it's a real device */
597     if (PciData.VendorID == PCI_INVALID_VENDORID) return STATUS_UNSUCCESSFUL;
598 
599     /* Allocate the supported range structure */
600     *Range = ExAllocatePoolWithTag(PagedPool, sizeof(SUPPORTED_RANGE), TAG_HAL);
601     if (!*Range) return STATUS_INSUFFICIENT_RESOURCES;
602 
603     /* Set it up */
604     RtlZeroMemory(*Range, sizeof(SUPPORTED_RANGE));
605     (*Range)->Base = 1;
606 
607     /* If the PCI device has no IRQ, nothing to do */
608     if (!PciData.u.type0.InterruptPin) return STATUS_SUCCESS;
609 
610     /* FIXME: The PCI IRQ Routing Miniport should be called */
611 
612     /* Also if the INT# seems bogus, nothing to do either */
613     if ((PciData.u.type0.InterruptLine == 0) ||
614         (PciData.u.type0.InterruptLine == 255))
615     {
616         /* Fake success */
617         return STATUS_SUCCESS;
618     }
619 
620     /* Otherwise, the INT# should be valid, return it to the caller */
621     (*Range)->Base = PciData.u.type0.InterruptLine;
622     (*Range)->Limit = PciData.u.type0.InterruptLine;
623     return STATUS_SUCCESS;
624 }
625 
626 INIT_FUNCTION
627 NTSTATUS
628 NTAPI
629 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock,
630                                IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
631 {
632     DPRINT1("Unimplemented!\n");
633     return STATUS_NOT_IMPLEMENTED;
634 }
635 
636 INIT_FUNCTION
637 NTSTATUS
638 NTAPI
639 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
640 {
641     DPRINT1("Unimplemented!\n");
642     return STATUS_NOT_IMPLEMENTED;
643 }
644 
645 INIT_FUNCTION
646 VOID
647 NTAPI
648 HalpRegisterPciDebuggingDeviceInfo(VOID)
649 {
650     BOOLEAN Found = FALSE;
651     ULONG i;
652     PAGED_CODE();
653 
654     /* Loop PCI debugging devices */
655     for (i = 0; i < 2; i++)
656     {
657         /* Reserved bit is set if we found one */
658         if (HalpPciDebuggingDevice[i].u.bits.Reserved1)
659         {
660             Found = TRUE;
661             break;
662         }
663     }
664 
665     /* Bail out if there aren't any */
666     if (!Found) return;
667 
668     /* FIXME: TODO */
669     UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI debugger"
670                            "devices, but you have forgotten to implement this routine\n");
671 }
672 
673 static ULONG NTAPI
674 PciSize(ULONG Base, ULONG Mask)
675 {
676     ULONG Size = Mask & Base; /* Find the significant bits */
677     Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */
678     return Size;
679 }
680 
681 NTSTATUS
682 NTAPI
683 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler,
684                           IN PBUS_HANDLER RootHandler,
685                           IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList)
686 {
687     PPCIPBUSDATA BusData;
688     PCI_SLOT_NUMBER SlotNumber;
689     PSUPPORTED_RANGE Interrupt;
690     NTSTATUS Status;
691 
692     /* Get PCI bus data */
693     BusData = BusHandler->BusData;
694     SlotNumber.u.AsULONG = (*pResourceList)->SlotNumber;
695 
696     /* Get the IRQ supported range */
697     Status = BusData->GetIrqRange(BusHandler, RootHandler, SlotNumber, &Interrupt);
698     if (!NT_SUCCESS(Status)) return Status;
699 #ifndef _MINIHAL_
700     /* Handle the /PCILOCK feature */
701     if (HalpPciLockSettings)
702     {
703         /* /PCILOCK is not yet supported */
704         UNIMPLEMENTED_DBGBREAK("/PCILOCK boot switch is not yet supported.");
705     }
706 #endif
707     /* Now create the correct resource list based on the supported bus ranges */
708 #if 0
709     Status = HaliAdjustResourceListRange(BusHandler->BusAddresses,
710                                          Interrupt,
711                                          pResourceList);
712 #else
713     DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n");
714     Status = STATUS_SUCCESS;
715 #endif
716 
717     /* Return to caller */
718     ExFreePool(Interrupt);
719     return Status;
720 }
721 
722 NTSTATUS
723 NTAPI
724 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler,
725                            IN PBUS_HANDLER RootHandler,
726                            IN PUNICODE_STRING RegistryPath,
727                            IN PUNICODE_STRING DriverClassName OPTIONAL,
728                            IN PDRIVER_OBJECT DriverObject,
729                            IN PDEVICE_OBJECT DeviceObject OPTIONAL,
730                            IN ULONG Slot,
731                            IN OUT PCM_RESOURCE_LIST *AllocatedResources)
732 {
733     PCI_COMMON_CONFIG PciConfig;
734     SIZE_T Address;
735     ULONG ResourceCount;
736     ULONG Size[PCI_TYPE0_ADDRESSES];
737     NTSTATUS Status = STATUS_SUCCESS;
738     UCHAR Offset;
739     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
740     PCI_SLOT_NUMBER SlotNumber;
741     ULONG WriteBuffer;
742     DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n");
743 
744     /* FIXME: Should handle 64-bit addresses */
745 
746     /* Read configuration data */
747     SlotNumber.u.AsULONG = Slot;
748     HalpReadPCIConfig(BusHandler, SlotNumber, &PciConfig, 0, PCI_COMMON_HDR_LENGTH);
749 
750     /* Check if we read it correctly */
751     if (PciConfig.VendorID == PCI_INVALID_VENDORID)
752         return STATUS_NO_SUCH_DEVICE;
753 
754     /* Read the PCI configuration space for the device and store base address and
755     size information in temporary storage. Count the number of valid base addresses */
756     ResourceCount = 0;
757     for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
758     {
759         if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address])
760             PciConfig.u.type0.BaseAddresses[Address] = 0;
761 
762         /* Memory resource */
763         if (0 != PciConfig.u.type0.BaseAddresses[Address])
764         {
765             ResourceCount++;
766 
767             Offset = (UCHAR)FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]);
768 
769             /* Write 0xFFFFFFFF there */
770             WriteBuffer = 0xffffffff;
771             HalpWritePCIConfig(BusHandler, SlotNumber, &WriteBuffer, Offset, sizeof(ULONG));
772 
773             /* Read that figure back from the config space */
774             HalpReadPCIConfig(BusHandler, SlotNumber, &Size[Address], Offset, sizeof(ULONG));
775 
776             /* Write back initial value */
777             HalpWritePCIConfig(BusHandler, SlotNumber, &PciConfig.u.type0.BaseAddresses[Address], Offset, sizeof(ULONG));
778         }
779     }
780 
781     /* Interrupt resource */
782     if (0 != PciConfig.u.type0.InterruptPin &&
783         0 != PciConfig.u.type0.InterruptLine &&
784         0xFF != PciConfig.u.type0.InterruptLine)
785         ResourceCount++;
786 
787     /* Allocate output buffer and initialize */
788     *AllocatedResources = ExAllocatePoolWithTag(
789         PagedPool,
790         sizeof(CM_RESOURCE_LIST) +
791         (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
792         TAG_HAL);
793 
794     if (NULL == *AllocatedResources)
795         return STATUS_NO_MEMORY;
796 
797     (*AllocatedResources)->Count = 1;
798     (*AllocatedResources)->List[0].InterfaceType = PCIBus;
799     (*AllocatedResources)->List[0].BusNumber = BusHandler->BusNumber;
800     (*AllocatedResources)->List[0].PartialResourceList.Version = 1;
801     (*AllocatedResources)->List[0].PartialResourceList.Revision = 1;
802     (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount;
803     Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors;
804 
805     /* Store configuration information */
806     for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
807     {
808         if (0 != PciConfig.u.type0.BaseAddresses[Address])
809         {
810             if (PCI_ADDRESS_MEMORY_SPACE ==
811                 (PciConfig.u.type0.BaseAddresses[Address] & 0x1))
812             {
813                 Descriptor->Type = CmResourceTypeMemory;
814                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
815                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;             /* FIXME Just a guess */
816                 Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_ADDRESS_MEMORY_ADDRESS_MASK);
817                 Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_ADDRESS_MEMORY_ADDRESS_MASK);
818             }
819             else if (PCI_ADDRESS_IO_SPACE ==
820                 (PciConfig.u.type0.BaseAddresses[Address] & 0x1))
821             {
822                 Descriptor->Type = CmResourceTypePort;
823                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
824                 Descriptor->Flags = CM_RESOURCE_PORT_IO;                       /* FIXME Just a guess */
825                 Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_ADDRESS_IO_ADDRESS_MASK;
826                 Descriptor->u.Port.Length = PciSize(Size[Address], PCI_ADDRESS_IO_ADDRESS_MASK & 0xffff);
827             }
828             else
829             {
830                 ASSERT(FALSE);
831                 return STATUS_UNSUCCESSFUL;
832             }
833             Descriptor++;
834         }
835     }
836 
837     if (0 != PciConfig.u.type0.InterruptPin &&
838         0 != PciConfig.u.type0.InterruptLine &&
839         0xFF != PciConfig.u.type0.InterruptLine)
840     {
841         Descriptor->Type = CmResourceTypeInterrupt;
842         Descriptor->ShareDisposition = CmResourceShareShared;          /* FIXME Just a guess */
843         Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;     /* FIXME Just a guess */
844         Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine;
845         Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine;
846         Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
847 
848         Descriptor++;
849     }
850 
851     ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount);
852 
853     /* FIXME: Should store the resources in the registry resource map */
854 
855     return Status;
856 }
857 
858 ULONG
859 NTAPI
860 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler,
861                            IN ULONG BusNumber,
862                            IN PCI_SLOT_NUMBER SlotNumber,
863                            IN PVOID Buffer,
864                            IN ULONG Offset,
865                            IN ULONG Length)
866 {
867     BUS_HANDLER BusHandler;
868 
869     /* Setup fake PCI Bus handler */
870     RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
871     BusHandler.BusNumber = BusNumber;
872 
873     /* Read configuration data */
874     HalpReadPCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length);
875 
876     /* Return length */
877     return Length;
878 }
879 
880 INIT_FUNCTION
881 PPCI_REGISTRY_INFO_INTERNAL
882 NTAPI
883 HalpQueryPciRegistryInfo(VOID)
884 {
885 #ifndef _MINIHAL_
886     WCHAR NameBuffer[8];
887     OBJECT_ATTRIBUTES  ObjectAttributes;
888     UNICODE_STRING KeyName, ConfigName, IdentName;
889     HANDLE KeyHandle, BusKeyHandle, CardListHandle;
890     NTSTATUS Status;
891     UCHAR KeyBuffer[sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + 100];
892     PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer;
893     UCHAR PartialKeyBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
894                            sizeof(PCI_CARD_DESCRIPTOR)];
895     PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo = (PVOID)PartialKeyBuffer;
896     KEY_FULL_INFORMATION KeyInformation;
897     ULONG ResultLength;
898     PWSTR Tag;
899     ULONG i, ElementCount;
900     PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
901     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
902     PPCI_REGISTRY_INFO PciRegInfo;
903     PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
904     PPCI_CARD_DESCRIPTOR CardDescriptor;
905 
906     /* Setup the object attributes for the key */
907     RtlInitUnicodeString(&KeyName,
908                          L"\\Registry\\Machine\\Hardware\\Description\\"
909                          L"System\\MultiFunctionAdapter");
910     InitializeObjectAttributes(&ObjectAttributes,
911                                &KeyName,
912                                OBJ_CASE_INSENSITIVE,
913                                NULL,
914                                NULL);
915 
916     /* Open the key */
917     Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
918     if (!NT_SUCCESS(Status)) return NULL;
919 
920     /* Setup the receiving string */
921     KeyName.Buffer = NameBuffer;
922     KeyName.MaximumLength = sizeof(NameBuffer);
923 
924     /* Setup the configuration and identifier key names */
925     RtlInitUnicodeString(&ConfigName, L"Configuration Data");
926     RtlInitUnicodeString(&IdentName, L"Identifier");
927 
928     /* Keep looping for each ID */
929     for (i = 0; TRUE; i++)
930     {
931         /* Setup the key name */
932         RtlIntegerToUnicodeString(i, 10, &KeyName);
933         InitializeObjectAttributes(&ObjectAttributes,
934                                    &KeyName,
935                                    OBJ_CASE_INSENSITIVE,
936                                    KeyHandle,
937                                    NULL);
938 
939         /* Open it */
940         Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes);
941         if (!NT_SUCCESS(Status))
942         {
943             /* None left, fail */
944             ZwClose(KeyHandle);
945             return NULL;
946         }
947 
948         /* Read the registry data */
949         Status = ZwQueryValueKey(BusKeyHandle,
950                                  &IdentName,
951                                  KeyValueFullInformation,
952                                  ValueInfo,
953                                  sizeof(KeyBuffer),
954                                  &ResultLength);
955         if (!NT_SUCCESS(Status))
956         {
957             /* Failed, try the next one */
958             ZwClose(BusKeyHandle);
959             continue;
960         }
961 
962         /* Get the PCI Tag and validate it */
963         Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
964         if ((Tag[0] != L'P') ||
965             (Tag[1] != L'C') ||
966             (Tag[2] != L'I') ||
967             (Tag[3]))
968         {
969             /* Not a valid PCI entry, skip it */
970             ZwClose(BusKeyHandle);
971             continue;
972         }
973 
974         /* Now read our PCI structure */
975         Status = ZwQueryValueKey(BusKeyHandle,
976                                  &ConfigName,
977                                  KeyValueFullInformation,
978                                  ValueInfo,
979                                  sizeof(KeyBuffer),
980                                  &ResultLength);
981         ZwClose(BusKeyHandle);
982         if (!NT_SUCCESS(Status)) continue;
983 
984         /* We read it OK! Get the actual resource descriptors */
985         FullDescriptor  = (PCM_FULL_RESOURCE_DESCRIPTOR)
986                           ((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
987         PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
988                             ((ULONG_PTR)FullDescriptor->
989                                         PartialResourceList.PartialDescriptors);
990 
991         /* Check if this is our PCI Registry Information */
992         if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
993         {
994             /* It is, stop searching */
995             break;
996         }
997     }
998 
999     /* Close the key */
1000     ZwClose(KeyHandle);
1001 
1002     /* Save the PCI information for later */
1003     PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1);
1004 
1005     /* Assume no Card List entries */
1006     ElementCount = 0;
1007 
1008     /* Set up for checking the PCI Card List key */
1009     RtlInitUnicodeString(&KeyName,
1010                          L"\\Registry\\Machine\\System\\CurrentControlSet\\"
1011                          L"Control\\PnP\\PCI\\CardList");
1012     InitializeObjectAttributes(&ObjectAttributes,
1013                                &KeyName,
1014                                OBJ_CASE_INSENSITIVE,
1015                                NULL,
1016                                NULL);
1017 
1018     /* Attempt to open it */
1019     Status = ZwOpenKey(&CardListHandle, KEY_READ, &ObjectAttributes);
1020     if (NT_SUCCESS(Status))
1021     {
1022         /* It exists, so let's query it */
1023         Status = ZwQueryKey(CardListHandle,
1024                             KeyFullInformation,
1025                             &KeyInformation,
1026                             sizeof(KEY_FULL_INFORMATION),
1027                             &ResultLength);
1028         if (!NT_SUCCESS(Status))
1029         {
1030             /* Failed to query, so no info */
1031             PciRegistryInfo = NULL;
1032         }
1033         else
1034         {
1035             /* Allocate the full structure */
1036             PciRegistryInfo =
1037                 ExAllocatePoolWithTag(NonPagedPool,
1038                                       sizeof(PCI_REGISTRY_INFO_INTERNAL) +
1039                                       (KeyInformation.Values *
1040                                        sizeof(PCI_CARD_DESCRIPTOR)),
1041                                        TAG_HAL);
1042             if (PciRegistryInfo)
1043             {
1044                 /* Get the first card descriptor entry */
1045                 CardDescriptor = (PPCI_CARD_DESCRIPTOR)(PciRegistryInfo + 1);
1046 
1047                 /* Loop all the values */
1048                 for (i = 0; i < KeyInformation.Values; i++)
1049                 {
1050                     /* Attempt to get the value */
1051                     Status = ZwEnumerateValueKey(CardListHandle,
1052                                                  i,
1053                                                  KeyValuePartialInformation,
1054                                                  PartialValueInfo,
1055                                                  sizeof(PartialKeyBuffer),
1056                                                  &ResultLength);
1057                     if (!NT_SUCCESS(Status))
1058                     {
1059                         /* Something went wrong, stop the search */
1060                         break;
1061                     }
1062 
1063                     /* Make sure it is correctly sized */
1064                     if (PartialValueInfo->DataLength == sizeof(PCI_CARD_DESCRIPTOR))
1065                     {
1066                         /* Sure is, copy it over */
1067                         *CardDescriptor = *(PPCI_CARD_DESCRIPTOR)
1068                                            PartialValueInfo->Data;
1069 
1070                         /* One more Card List entry */
1071                         ElementCount++;
1072 
1073                         /* Move to the next descriptor */
1074                         CardDescriptor = (CardDescriptor + 1);
1075                     }
1076                 }
1077             }
1078         }
1079 
1080         /* Close the Card List key */
1081         ZwClose(CardListHandle);
1082     }
1083     else
1084     {
1085        /* No key, no Card List */
1086        PciRegistryInfo = NULL;
1087     }
1088 
1089     /* Check if we failed to get the full structure */
1090     if (!PciRegistryInfo)
1091     {
1092         /* Just allocate the basic structure then */
1093         PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool,
1094                                                 sizeof(PCI_REGISTRY_INFO_INTERNAL),
1095                                                 TAG_HAL);
1096         if (!PciRegistryInfo) return NULL;
1097     }
1098 
1099     /* Save the info we got */
1100     PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision;
1101     PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision;
1102     PciRegistryInfo->NoBuses = PciRegInfo->NoBuses;
1103     PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism;
1104     PciRegistryInfo->ElementCount = ElementCount;
1105 
1106     /* Return it */
1107     return PciRegistryInfo;
1108 #else
1109     return NULL;
1110 #endif
1111 }
1112 
1113 INIT_FUNCTION
1114 VOID
1115 NTAPI
1116 HalpInitializePciStubs(VOID)
1117 {
1118     PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
1119     UCHAR PciType;
1120     PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData;
1121     ULONG i;
1122     PCI_SLOT_NUMBER j;
1123     ULONG VendorId = 0;
1124     ULONG MaxPciBusNumber;
1125 
1126     /* Query registry information */
1127     PciRegistryInfo = HalpQueryPciRegistryInfo();
1128     if (!PciRegistryInfo)
1129     {
1130         /* Assume type 1 */
1131         PciType = 1;
1132 
1133         /* Force a manual bus scan later */
1134         MaxPciBusNumber = MAXULONG;
1135     }
1136     else
1137     {
1138         /* Get the PCI type */
1139         PciType = PciRegistryInfo->HardwareMechanism & 0xF;
1140 
1141         /* Get MaxPciBusNumber and make it 0-based */
1142         MaxPciBusNumber = PciRegistryInfo->NoBuses - 1;
1143 
1144         /* Free the info structure */
1145         ExFreePoolWithTag(PciRegistryInfo, TAG_HAL);
1146     }
1147 
1148     /* Initialize the PCI lock */
1149     KeInitializeSpinLock(&HalpPCIConfigLock);
1150 
1151     /* Check the type of PCI bus */
1152     switch (PciType)
1153     {
1154         /* Type 1 PCI Bus */
1155         case 1:
1156 
1157             /* Copy the Type 1 handler data */
1158             RtlCopyMemory(&PCIConfigHandler,
1159                           &PCIConfigHandlerType1,
1160                           sizeof(PCIConfigHandler));
1161 
1162             /* Set correct I/O Ports */
1163             BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT;
1164             BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
1165             break;
1166 
1167         /* Type 2 PCI Bus */
1168         case 2:
1169 
1170             /* Copy the Type 2 handler data */
1171             RtlCopyMemory(&PCIConfigHandler,
1172                           &PCIConfigHandlerType2,
1173                           sizeof (PCIConfigHandler));
1174 
1175             /* Set correct I/O Ports */
1176             BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
1177             BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
1178             BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
1179 
1180             /* Only 16 devices supported, not 32 */
1181             BusData->MaxDevice = 16;
1182             break;
1183 
1184         default:
1185 
1186             /* Invalid type */
1187             DbgPrint("HAL: Unknown PCI type\n");
1188     }
1189 
1190     /* Run a forced bus scan if needed */
1191     if (MaxPciBusNumber == MAXULONG)
1192     {
1193         /* Initialize the max bus number to 0xFF */
1194         HalpMaxPciBus = 0xFF;
1195 
1196         /* Initialize the counter */
1197         MaxPciBusNumber = 0;
1198 
1199         /* Loop all possible buses */
1200         for (i = 0; i < HalpMaxPciBus; i++)
1201         {
1202             /* Loop all devices */
1203             for (j.u.AsULONG = 0; j.u.AsULONG < BusData->MaxDevice; j.u.AsULONG++)
1204             {
1205                 /* Query the interface */
1206                 if (HaliPciInterfaceReadConfig(NULL,
1207                                                i,
1208                                                j,
1209                                                &VendorId,
1210                                                0,
1211                                                sizeof(ULONG)))
1212                 {
1213                     /* Validate the vendor ID */
1214                     if ((VendorId & 0xFFFF) != PCI_INVALID_VENDORID)
1215                     {
1216                         /* Set this as the maximum ID */
1217                         MaxPciBusNumber = i;
1218                         break;
1219                     }
1220                 }
1221             }
1222         }
1223     }
1224 
1225     /* Set the real max bus number */
1226     HalpMaxPciBus = MaxPciBusNumber;
1227 
1228     /* We're done */
1229     HalpPCIConfigInitialized = TRUE;
1230 }
1231 
1232 /* EOF */
1233 
1234