xref: /reactos/hal/halx86/legacy/bus/pcibus.c (revision 279107d5)
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 BOOLEAN
315 NTAPI
316 HalpValidPCISlot(IN PBUS_HANDLER BusHandler,
317                  IN PCI_SLOT_NUMBER Slot)
318 {
319     PCI_SLOT_NUMBER MultiSlot;
320     PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
321     UCHAR HeaderType;
322     //ULONG Device;
323 
324     /* Simple validation */
325     if (Slot.u.bits.Reserved) return FALSE;
326     if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) return FALSE;
327 
328     /* Function 0 doesn't need checking */
329     if (!Slot.u.bits.FunctionNumber) return TRUE;
330 
331     /* Functions 0+ need Multi-Function support, so check the slot */
332     //Device = Slot.u.bits.DeviceNumber;
333     MultiSlot = Slot;
334     MultiSlot.u.bits.FunctionNumber = 0;
335 
336     /* Send function 0 request to get the header back */
337     HalpReadPCIConfig(BusHandler,
338                       MultiSlot,
339                       &HeaderType,
340                       FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType),
341                       sizeof(UCHAR));
342 
343     /* Now make sure the header is multi-function */
344     if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) return FALSE;
345     return TRUE;
346 }
347 
348 /* HAL PCI CALLBACKS *********************************************************/
349 
350 ULONG
351 NTAPI
352 HalpGetPCIData(IN PBUS_HANDLER BusHandler,
353                IN PBUS_HANDLER RootHandler,
354                IN ULONG SlotNumber,
355                IN PVOID Buffer,
356                IN ULONG Offset,
357                IN ULONG Length)
358 {
359     PCI_SLOT_NUMBER Slot;
360     UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH];
361     PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer;
362     ULONG Len = 0;
363 
364     Slot.u.AsULONG = SlotNumber;
365 #ifdef SARCH_XBOX
366     /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
367      * hang the Xbox. Also, the device number doesn't seem to be decoded for the
368      * video card, so it appears to be present on 1:0:0 - 1:31:0.
369      * We hack around these problems by indicating "device not present" for devices
370      * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
371     if ((0 == BusHandler->BusNumber && 0 == Slot.u.bits.DeviceNumber &&
372          (1 == Slot.u.bits.FunctionNumber || 2 == Slot.u.bits.FunctionNumber)) ||
373         (1 == BusHandler->BusNumber && 0 != Slot.u.bits.DeviceNumber))
374     {
375         DPRINT("Blacklisted PCI slot\n");
376         if (0 == Offset && sizeof(USHORT) <= Length)
377         {
378             *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
379             return sizeof(USHORT);
380         }
381         return 0;
382     }
383 #endif
384 
385     /* Normalize the length */
386     if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG);
387 
388     /* Check if this is a vendor-specific read */
389     if (Offset >= PCI_COMMON_HDR_LENGTH)
390     {
391         /* Read the header */
392         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG));
393 
394         /* Make sure the vendor is valid */
395         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
396     }
397     else
398     {
399         /* Read the entire header */
400         Len = PCI_COMMON_HDR_LENGTH;
401         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len);
402 
403         /* Validate the vendor ID */
404         if (PciConfig->VendorID == PCI_INVALID_VENDORID)
405         {
406             /* It's invalid, but we want to return this much */
407             Len = sizeof(USHORT);
408         }
409 
410         /* Now check if there's space left */
411         if (Len < Offset) return 0;
412 
413         /* There is, so return what's after the offset and normalize */
414         Len -= Offset;
415         if (Len > Length) Len = Length;
416 
417         /* Copy the data into the caller's buffer */
418         RtlMoveMemory(Buffer, PciBuffer + Offset, Len);
419 
420         /* Update buffer and offset, decrement total length */
421         Offset += Len;
422         Buffer = (PVOID)((ULONG_PTR)Buffer + Len);
423         Length -= Len;
424     }
425 
426     /* Now we still have something to copy */
427     if (Length)
428     {
429         /* Check if it's vendor-specific data */
430         if (Offset >= PCI_COMMON_HDR_LENGTH)
431         {
432             /* Read it now */
433             HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length);
434             Len += Length;
435         }
436     }
437 
438     /* Update the total length read */
439     return Len;
440 }
441 
442 ULONG
443 NTAPI
444 HalpSetPCIData(IN PBUS_HANDLER BusHandler,
445                IN PBUS_HANDLER RootHandler,
446                IN ULONG SlotNumber,
447                IN PVOID Buffer,
448                IN ULONG Offset,
449                IN ULONG Length)
450 {
451     PCI_SLOT_NUMBER Slot;
452     UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH];
453     PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer;
454     ULONG Len = 0;
455 
456     Slot.u.AsULONG = SlotNumber;
457 #ifdef SARCH_XBOX
458     /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
459      * hang the Xbox. Also, the device number doesn't seem to be decoded for the
460      * video card, so it appears to be present on 1:0:0 - 1:31:0.
461      * We hack around these problems by indicating "device not present" for devices
462      * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
463     if ((0 == BusHandler->BusNumber && 0 == Slot.u.bits.DeviceNumber &&
464          (1 == Slot.u.bits.FunctionNumber || 2 == Slot.u.bits.FunctionNumber)) ||
465         (1 == BusHandler->BusNumber && 0 != Slot.u.bits.DeviceNumber))
466     {
467         DPRINT1("Trying to set data on blacklisted PCI slot\n");
468         return 0;
469     }
470 #endif
471 
472     /* Normalize the length */
473     if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG);
474 
475     /* Check if this is a vendor-specific read */
476     if (Offset >= PCI_COMMON_HDR_LENGTH)
477     {
478         /* Read the header */
479         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG));
480 
481         /* Make sure the vendor is valid */
482         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
483     }
484     else
485     {
486         /* Read the entire header and validate the vendor ID */
487         Len = PCI_COMMON_HDR_LENGTH;
488         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len);
489         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
490 
491         /* Return what's after the offset and normalize */
492         Len -= Offset;
493         if (Len > Length) Len = Length;
494 
495         /* Copy the specific caller data */
496         RtlMoveMemory(PciBuffer + Offset, Buffer, Len);
497 
498         /* Write the actual configuration data */
499         HalpWritePCIConfig(BusHandler, Slot, PciBuffer + Offset, Offset, Len);
500 
501         /* Update buffer and offset, decrement total length */
502         Offset += Len;
503         Buffer = (PVOID)((ULONG_PTR)Buffer + Len);
504         Length -= Len;
505     }
506 
507     /* Now we still have something to copy */
508     if (Length)
509     {
510         /* Check if it's vendor-specific data */
511         if (Offset >= PCI_COMMON_HDR_LENGTH)
512         {
513             /* Read it now */
514             HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length);
515             Len += Length;
516         }
517     }
518 
519     /* Update the total length read */
520     return Len;
521 }
522 
523 ULONG
524 NTAPI
525 HalpGetPCIIntOnISABus(IN PBUS_HANDLER BusHandler,
526                       IN PBUS_HANDLER RootHandler,
527                       IN ULONG BusInterruptLevel,
528                       IN ULONG BusInterruptVector,
529                       OUT PKIRQL Irql,
530                       OUT PKAFFINITY Affinity)
531 {
532     /* Validate the level first */
533     if (BusInterruptLevel < 1) return 0;
534 
535     /* PCI has its IRQs on top of ISA IRQs, so pass it on to the ISA handler */
536     return HalGetInterruptVector(Isa,
537                                  0,
538                                  BusInterruptLevel,
539                                  0,
540                                  Irql,
541                                  Affinity);
542 }
543 
544 VOID
545 NTAPI
546 HalpPCIPin2ISALine(IN PBUS_HANDLER BusHandler,
547                    IN PBUS_HANDLER RootHandler,
548                    IN PCI_SLOT_NUMBER SlotNumber,
549                    IN PPCI_COMMON_CONFIG PciData)
550 {
551     UNIMPLEMENTED_DBGBREAK();
552 }
553 
554 VOID
555 NTAPI
556 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler,
557                    IN PBUS_HANDLER RootHandler,
558                    IN PCI_SLOT_NUMBER SlotNumber,
559                    IN PPCI_COMMON_CONFIG PciNewData,
560                    IN PPCI_COMMON_CONFIG PciOldData)
561 {
562     UNIMPLEMENTED_DBGBREAK();
563 }
564 
565 NTSTATUS
566 NTAPI
567 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler,
568                       IN PBUS_HANDLER RootHandler,
569                       IN PCI_SLOT_NUMBER PciSlot,
570                       OUT PSUPPORTED_RANGE *Range)
571 {
572     PCI_COMMON_HEADER PciData;
573 
574     /* Read PCI configuration data */
575     HalGetBusData(PCIConfiguration,
576                   BusHandler->BusNumber,
577                   PciSlot.u.AsULONG,
578                   &PciData,
579                   PCI_COMMON_HDR_LENGTH);
580 
581     /* Make sure it's a real device */
582     if (PciData.VendorID == PCI_INVALID_VENDORID) return STATUS_UNSUCCESSFUL;
583 
584     /* Allocate the supported range structure */
585     *Range = ExAllocatePoolWithTag(PagedPool, sizeof(SUPPORTED_RANGE), TAG_HAL);
586     if (!*Range) return STATUS_INSUFFICIENT_RESOURCES;
587 
588     /* Set it up */
589     RtlZeroMemory(*Range, sizeof(SUPPORTED_RANGE));
590     (*Range)->Base = 1;
591 
592     /* If the PCI device has no IRQ, nothing to do */
593     if (!PciData.u.type0.InterruptPin) return STATUS_SUCCESS;
594 
595     /* FIXME: The PCI IRQ Routing Miniport should be called */
596 
597     /* Also if the INT# seems bogus, nothing to do either */
598     if ((PciData.u.type0.InterruptLine == 0) ||
599         (PciData.u.type0.InterruptLine == 255))
600     {
601         /* Fake success */
602         return STATUS_SUCCESS;
603     }
604 
605     /* Otherwise, the INT# should be valid, return it to the caller */
606     (*Range)->Base = PciData.u.type0.InterruptLine;
607     (*Range)->Limit = PciData.u.type0.InterruptLine;
608     return STATUS_SUCCESS;
609 }
610 
611 INIT_FUNCTION
612 NTSTATUS
613 NTAPI
614 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock,
615                                IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
616 {
617     DPRINT1("Unimplemented!\n");
618     return STATUS_NOT_IMPLEMENTED;
619 }
620 
621 INIT_FUNCTION
622 NTSTATUS
623 NTAPI
624 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
625 {
626     DPRINT1("Unimplemented!\n");
627     return STATUS_NOT_IMPLEMENTED;
628 }
629 
630 INIT_FUNCTION
631 VOID
632 NTAPI
633 HalpRegisterPciDebuggingDeviceInfo(VOID)
634 {
635     BOOLEAN Found = FALSE;
636     ULONG i;
637     PAGED_CODE();
638 
639     /* Loop PCI debugging devices */
640     for (i = 0; i < 2; i++)
641     {
642         /* Reserved bit is set if we found one */
643         if (HalpPciDebuggingDevice[i].u.bits.Reserved1)
644         {
645             Found = TRUE;
646             break;
647         }
648     }
649 
650     /* Bail out if there aren't any */
651     if (!Found) return;
652 
653     /* FIXME: TODO */
654     UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI debugger"
655                            "devices, but you have forgotten to implement this routine\n");
656 }
657 
658 static ULONG NTAPI
659 PciSize(ULONG Base, ULONG Mask)
660 {
661     ULONG Size = Mask & Base; /* Find the significant bits */
662     Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */
663     return Size;
664 }
665 
666 NTSTATUS
667 NTAPI
668 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler,
669                           IN PBUS_HANDLER RootHandler,
670                           IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList)
671 {
672     PPCIPBUSDATA BusData;
673     PCI_SLOT_NUMBER SlotNumber;
674     PSUPPORTED_RANGE Interrupt;
675     NTSTATUS Status;
676 
677     /* Get PCI bus data */
678     BusData = BusHandler->BusData;
679     SlotNumber.u.AsULONG = (*pResourceList)->SlotNumber;
680 
681     /* Get the IRQ supported range */
682     Status = BusData->GetIrqRange(BusHandler, RootHandler, SlotNumber, &Interrupt);
683     if (!NT_SUCCESS(Status)) return Status;
684 #ifndef _MINIHAL_
685     /* Handle the /PCILOCK feature */
686     if (HalpPciLockSettings)
687     {
688         /* /PCILOCK is not yet supported */
689         UNIMPLEMENTED_DBGBREAK("/PCILOCK boot switch is not yet supported.");
690     }
691 #endif
692     /* Now create the correct resource list based on the supported bus ranges */
693 #if 0
694     Status = HaliAdjustResourceListRange(BusHandler->BusAddresses,
695                                          Interrupt,
696                                          pResourceList);
697 #else
698     DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n");
699     Status = STATUS_SUCCESS;
700 #endif
701 
702     /* Return to caller */
703     ExFreePool(Interrupt);
704     return Status;
705 }
706 
707 NTSTATUS
708 NTAPI
709 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler,
710                            IN PBUS_HANDLER RootHandler,
711                            IN PUNICODE_STRING RegistryPath,
712                            IN PUNICODE_STRING DriverClassName OPTIONAL,
713                            IN PDRIVER_OBJECT DriverObject,
714                            IN PDEVICE_OBJECT DeviceObject OPTIONAL,
715                            IN ULONG Slot,
716                            IN OUT PCM_RESOURCE_LIST *AllocatedResources)
717 {
718     PCI_COMMON_CONFIG PciConfig;
719     SIZE_T Address;
720     ULONG ResourceCount;
721     ULONG Size[PCI_TYPE0_ADDRESSES];
722     NTSTATUS Status = STATUS_SUCCESS;
723     UCHAR Offset;
724     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
725     PCI_SLOT_NUMBER SlotNumber;
726     ULONG WriteBuffer;
727     DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n");
728 
729     /* FIXME: Should handle 64-bit addresses */
730 
731     /* Read configuration data */
732     SlotNumber.u.AsULONG = Slot;
733     HalpReadPCIConfig(BusHandler, SlotNumber, &PciConfig, 0, PCI_COMMON_HDR_LENGTH);
734 
735     /* Check if we read it correctly */
736     if (PciConfig.VendorID == PCI_INVALID_VENDORID)
737         return STATUS_NO_SUCH_DEVICE;
738 
739     /* Read the PCI configuration space for the device and store base address and
740     size information in temporary storage. Count the number of valid base addresses */
741     ResourceCount = 0;
742     for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
743     {
744         if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address])
745             PciConfig.u.type0.BaseAddresses[Address] = 0;
746 
747         /* Memory resource */
748         if (0 != PciConfig.u.type0.BaseAddresses[Address])
749         {
750             ResourceCount++;
751 
752             Offset = (UCHAR)FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]);
753 
754             /* Write 0xFFFFFFFF there */
755             WriteBuffer = 0xffffffff;
756             HalpWritePCIConfig(BusHandler, SlotNumber, &WriteBuffer, Offset, sizeof(ULONG));
757 
758             /* Read that figure back from the config space */
759             HalpReadPCIConfig(BusHandler, SlotNumber, &Size[Address], Offset, sizeof(ULONG));
760 
761             /* Write back initial value */
762             HalpWritePCIConfig(BusHandler, SlotNumber, &PciConfig.u.type0.BaseAddresses[Address], Offset, sizeof(ULONG));
763         }
764     }
765 
766     /* Interrupt resource */
767     if (0 != PciConfig.u.type0.InterruptPin &&
768         0 != PciConfig.u.type0.InterruptLine &&
769         0xFF != PciConfig.u.type0.InterruptLine)
770         ResourceCount++;
771 
772     /* Allocate output buffer and initialize */
773     *AllocatedResources = ExAllocatePoolWithTag(
774         PagedPool,
775         sizeof(CM_RESOURCE_LIST) +
776         (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
777         TAG_HAL);
778 
779     if (NULL == *AllocatedResources)
780         return STATUS_NO_MEMORY;
781 
782     (*AllocatedResources)->Count = 1;
783     (*AllocatedResources)->List[0].InterfaceType = PCIBus;
784     (*AllocatedResources)->List[0].BusNumber = BusHandler->BusNumber;
785     (*AllocatedResources)->List[0].PartialResourceList.Version = 1;
786     (*AllocatedResources)->List[0].PartialResourceList.Revision = 1;
787     (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount;
788     Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors;
789 
790     /* Store configuration information */
791     for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
792     {
793         if (0 != PciConfig.u.type0.BaseAddresses[Address])
794         {
795             if (PCI_ADDRESS_MEMORY_SPACE ==
796                 (PciConfig.u.type0.BaseAddresses[Address] & 0x1))
797             {
798                 Descriptor->Type = CmResourceTypeMemory;
799                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
800                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;             /* FIXME Just a guess */
801                 Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_ADDRESS_MEMORY_ADDRESS_MASK);
802                 Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_ADDRESS_MEMORY_ADDRESS_MASK);
803             }
804             else if (PCI_ADDRESS_IO_SPACE ==
805                 (PciConfig.u.type0.BaseAddresses[Address] & 0x1))
806             {
807                 Descriptor->Type = CmResourceTypePort;
808                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
809                 Descriptor->Flags = CM_RESOURCE_PORT_IO;                       /* FIXME Just a guess */
810                 Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_ADDRESS_IO_ADDRESS_MASK;
811                 Descriptor->u.Port.Length = PciSize(Size[Address], PCI_ADDRESS_IO_ADDRESS_MASK & 0xffff);
812             }
813             else
814             {
815                 ASSERT(FALSE);
816                 return STATUS_UNSUCCESSFUL;
817             }
818             Descriptor++;
819         }
820     }
821 
822     if (0 != PciConfig.u.type0.InterruptPin &&
823         0 != PciConfig.u.type0.InterruptLine &&
824         0xFF != PciConfig.u.type0.InterruptLine)
825     {
826         Descriptor->Type = CmResourceTypeInterrupt;
827         Descriptor->ShareDisposition = CmResourceShareShared;          /* FIXME Just a guess */
828         Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;     /* FIXME Just a guess */
829         Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine;
830         Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine;
831         Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
832 
833         Descriptor++;
834     }
835 
836     ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount);
837 
838     /* FIXME: Should store the resources in the registry resource map */
839 
840     return Status;
841 }
842 
843 ULONG
844 NTAPI
845 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler,
846                            IN ULONG BusNumber,
847                            IN PCI_SLOT_NUMBER SlotNumber,
848                            IN PVOID Buffer,
849                            IN ULONG Offset,
850                            IN ULONG Length)
851 {
852     BUS_HANDLER BusHandler;
853 
854     /* Setup fake PCI Bus handler */
855     RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
856     BusHandler.BusNumber = BusNumber;
857 
858     /* Read configuration data */
859     HalpReadPCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length);
860 
861     /* Return length */
862     return Length;
863 }
864 
865 INIT_FUNCTION
866 PPCI_REGISTRY_INFO_INTERNAL
867 NTAPI
868 HalpQueryPciRegistryInfo(VOID)
869 {
870 #ifndef _MINIHAL_
871     WCHAR NameBuffer[8];
872     OBJECT_ATTRIBUTES  ObjectAttributes;
873     UNICODE_STRING KeyName, ConfigName, IdentName;
874     HANDLE KeyHandle, BusKeyHandle, CardListHandle;
875     NTSTATUS Status;
876     UCHAR KeyBuffer[sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + 100];
877     PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer;
878     UCHAR PartialKeyBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
879                            sizeof(PCI_CARD_DESCRIPTOR)];
880     PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo = (PVOID)PartialKeyBuffer;
881     KEY_FULL_INFORMATION KeyInformation;
882     ULONG ResultLength;
883     PWSTR Tag;
884     ULONG i, ElementCount;
885     PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
886     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
887     PPCI_REGISTRY_INFO PciRegInfo;
888     PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
889     PPCI_CARD_DESCRIPTOR CardDescriptor;
890 
891     /* Setup the object attributes for the key */
892     RtlInitUnicodeString(&KeyName,
893                          L"\\Registry\\Machine\\Hardware\\Description\\"
894                          L"System\\MultiFunctionAdapter");
895     InitializeObjectAttributes(&ObjectAttributes,
896                                &KeyName,
897                                OBJ_CASE_INSENSITIVE,
898                                NULL,
899                                NULL);
900 
901     /* Open the key */
902     Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
903     if (!NT_SUCCESS(Status)) return NULL;
904 
905     /* Setup the receiving string */
906     KeyName.Buffer = NameBuffer;
907     KeyName.MaximumLength = sizeof(NameBuffer);
908 
909     /* Setup the configuration and identifier key names */
910     RtlInitUnicodeString(&ConfigName, L"Configuration Data");
911     RtlInitUnicodeString(&IdentName, L"Identifier");
912 
913     /* Keep looping for each ID */
914     for (i = 0; TRUE; i++)
915     {
916         /* Setup the key name */
917         RtlIntegerToUnicodeString(i, 10, &KeyName);
918         InitializeObjectAttributes(&ObjectAttributes,
919                                    &KeyName,
920                                    OBJ_CASE_INSENSITIVE,
921                                    KeyHandle,
922                                    NULL);
923 
924         /* Open it */
925         Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes);
926         if (!NT_SUCCESS(Status))
927         {
928             /* None left, fail */
929             ZwClose(KeyHandle);
930             return NULL;
931         }
932 
933         /* Read the registry data */
934         Status = ZwQueryValueKey(BusKeyHandle,
935                                  &IdentName,
936                                  KeyValueFullInformation,
937                                  ValueInfo,
938                                  sizeof(KeyBuffer),
939                                  &ResultLength);
940         if (!NT_SUCCESS(Status))
941         {
942             /* Failed, try the next one */
943             ZwClose(BusKeyHandle);
944             continue;
945         }
946 
947         /* Get the PCI Tag and validate it */
948         Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
949         if ((Tag[0] != L'P') ||
950             (Tag[1] != L'C') ||
951             (Tag[2] != L'I') ||
952             (Tag[3]))
953         {
954             /* Not a valid PCI entry, skip it */
955             ZwClose(BusKeyHandle);
956             continue;
957         }
958 
959         /* Now read our PCI structure */
960         Status = ZwQueryValueKey(BusKeyHandle,
961                                  &ConfigName,
962                                  KeyValueFullInformation,
963                                  ValueInfo,
964                                  sizeof(KeyBuffer),
965                                  &ResultLength);
966         ZwClose(BusKeyHandle);
967         if (!NT_SUCCESS(Status)) continue;
968 
969         /* We read it OK! Get the actual resource descriptors */
970         FullDescriptor  = (PCM_FULL_RESOURCE_DESCRIPTOR)
971                           ((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
972         PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
973                             ((ULONG_PTR)FullDescriptor->
974                                         PartialResourceList.PartialDescriptors);
975 
976         /* Check if this is our PCI Registry Information */
977         if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
978         {
979             /* It is, stop searching */
980             break;
981         }
982     }
983 
984     /* Close the key */
985     ZwClose(KeyHandle);
986 
987     /* Save the PCI information for later */
988     PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1);
989 
990     /* Assume no Card List entries */
991     ElementCount = 0;
992 
993     /* Set up for checking the PCI Card List key */
994     RtlInitUnicodeString(&KeyName,
995                          L"\\Registry\\Machine\\System\\CurrentControlSet\\"
996                          L"Control\\PnP\\PCI\\CardList");
997     InitializeObjectAttributes(&ObjectAttributes,
998                                &KeyName,
999                                OBJ_CASE_INSENSITIVE,
1000                                NULL,
1001                                NULL);
1002 
1003     /* Attempt to open it */
1004     Status = ZwOpenKey(&CardListHandle, KEY_READ, &ObjectAttributes);
1005     if (NT_SUCCESS(Status))
1006     {
1007         /* It exists, so let's query it */
1008         Status = ZwQueryKey(CardListHandle,
1009                             KeyFullInformation,
1010                             &KeyInformation,
1011                             sizeof(KEY_FULL_INFORMATION),
1012                             &ResultLength);
1013         if (!NT_SUCCESS(Status))
1014         {
1015             /* Failed to query, so no info */
1016             PciRegistryInfo = NULL;
1017         }
1018         else
1019         {
1020             /* Allocate the full structure */
1021             PciRegistryInfo =
1022                 ExAllocatePoolWithTag(NonPagedPool,
1023                                       sizeof(PCI_REGISTRY_INFO_INTERNAL) +
1024                                       (KeyInformation.Values *
1025                                        sizeof(PCI_CARD_DESCRIPTOR)),
1026                                        TAG_HAL);
1027             if (PciRegistryInfo)
1028             {
1029                 /* Get the first card descriptor entry */
1030                 CardDescriptor = (PPCI_CARD_DESCRIPTOR)(PciRegistryInfo + 1);
1031 
1032                 /* Loop all the values */
1033                 for (i = 0; i < KeyInformation.Values; i++)
1034                 {
1035                     /* Attempt to get the value */
1036                     Status = ZwEnumerateValueKey(CardListHandle,
1037                                                  i,
1038                                                  KeyValuePartialInformation,
1039                                                  PartialValueInfo,
1040                                                  sizeof(PartialKeyBuffer),
1041                                                  &ResultLength);
1042                     if (!NT_SUCCESS(Status))
1043                     {
1044                         /* Something went wrong, stop the search */
1045                         break;
1046                     }
1047 
1048                     /* Make sure it is correctly sized */
1049                     if (PartialValueInfo->DataLength == sizeof(PCI_CARD_DESCRIPTOR))
1050                     {
1051                         /* Sure is, copy it over */
1052                         *CardDescriptor = *(PPCI_CARD_DESCRIPTOR)
1053                                            PartialValueInfo->Data;
1054 
1055                         /* One more Card List entry */
1056                         ElementCount++;
1057 
1058                         /* Move to the next descriptor */
1059                         CardDescriptor = (CardDescriptor + 1);
1060                     }
1061                 }
1062             }
1063         }
1064 
1065         /* Close the Card List key */
1066         ZwClose(CardListHandle);
1067     }
1068     else
1069     {
1070        /* No key, no Card List */
1071        PciRegistryInfo = NULL;
1072     }
1073 
1074     /* Check if we failed to get the full structure */
1075     if (!PciRegistryInfo)
1076     {
1077         /* Just allocate the basic structure then */
1078         PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool,
1079                                                 sizeof(PCI_REGISTRY_INFO_INTERNAL),
1080                                                 TAG_HAL);
1081         if (!PciRegistryInfo) return NULL;
1082     }
1083 
1084     /* Save the info we got */
1085     PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision;
1086     PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision;
1087     PciRegistryInfo->NoBuses = PciRegInfo->NoBuses;
1088     PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism;
1089     PciRegistryInfo->ElementCount = ElementCount;
1090 
1091     /* Return it */
1092     return PciRegistryInfo;
1093 #else
1094     return NULL;
1095 #endif
1096 }
1097 
1098 INIT_FUNCTION
1099 VOID
1100 NTAPI
1101 HalpInitializePciStubs(VOID)
1102 {
1103     PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
1104     UCHAR PciType;
1105     PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData;
1106     ULONG i;
1107     PCI_SLOT_NUMBER j;
1108     ULONG VendorId = 0;
1109     ULONG MaxPciBusNumber;
1110 
1111     /* Query registry information */
1112     PciRegistryInfo = HalpQueryPciRegistryInfo();
1113     if (!PciRegistryInfo)
1114     {
1115         /* Assume type 1 */
1116         PciType = 1;
1117 
1118         /* Force a manual bus scan later */
1119         MaxPciBusNumber = MAXULONG;
1120     }
1121     else
1122     {
1123         /* Get the PCI type */
1124         PciType = PciRegistryInfo->HardwareMechanism & 0xF;
1125 
1126         /* Get MaxPciBusNumber and make it 0-based */
1127         MaxPciBusNumber = PciRegistryInfo->NoBuses - 1;
1128 
1129         /* Free the info structure */
1130         ExFreePoolWithTag(PciRegistryInfo, TAG_HAL);
1131     }
1132 
1133     /* Initialize the PCI lock */
1134     KeInitializeSpinLock(&HalpPCIConfigLock);
1135 
1136     /* Check the type of PCI bus */
1137     switch (PciType)
1138     {
1139         /* Type 1 PCI Bus */
1140         case 1:
1141 
1142             /* Copy the Type 1 handler data */
1143             RtlCopyMemory(&PCIConfigHandler,
1144                           &PCIConfigHandlerType1,
1145                           sizeof(PCIConfigHandler));
1146 
1147             /* Set correct I/O Ports */
1148             BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT;
1149             BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
1150             break;
1151 
1152         /* Type 2 PCI Bus */
1153         case 2:
1154 
1155             /* Copy the Type 2 handler data */
1156             RtlCopyMemory(&PCIConfigHandler,
1157                           &PCIConfigHandlerType2,
1158                           sizeof (PCIConfigHandler));
1159 
1160             /* Set correct I/O Ports */
1161             BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
1162             BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
1163             BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
1164 
1165             /* Only 16 devices supported, not 32 */
1166             BusData->MaxDevice = 16;
1167             break;
1168 
1169         default:
1170 
1171             /* Invalid type */
1172             DbgPrint("HAL: Unknown PCI type\n");
1173     }
1174 
1175     /* Run a forced bus scan if needed */
1176     if (MaxPciBusNumber == MAXULONG)
1177     {
1178         /* Initialize the max bus number to 0xFF */
1179         HalpMaxPciBus = 0xFF;
1180 
1181         /* Initialize the counter */
1182         MaxPciBusNumber = 0;
1183 
1184         /* Loop all possible buses */
1185         for (i = 0; i < HalpMaxPciBus; i++)
1186         {
1187             /* Loop all devices */
1188             for (j.u.AsULONG = 0; j.u.AsULONG < BusData->MaxDevice; j.u.AsULONG++)
1189             {
1190                 /* Query the interface */
1191                 if (HaliPciInterfaceReadConfig(NULL,
1192                                                i,
1193                                                j,
1194                                                &VendorId,
1195                                                0,
1196                                                sizeof(ULONG)))
1197                 {
1198                     /* Validate the vendor ID */
1199                     if ((VendorId & 0xFFFF) != PCI_INVALID_VENDORID)
1200                     {
1201                         /* Set this as the maximum ID */
1202                         MaxPciBusNumber = i;
1203                         break;
1204                     }
1205                 }
1206             }
1207         }
1208     }
1209 
1210     /* Set the real max bus number */
1211     HalpMaxPciBus = MaxPciBusNumber;
1212 
1213     /* We're done */
1214     HalpPCIConfigInitialized = TRUE;
1215 }
1216 
1217 /* EOF */
1218 
1219