f45d66b0bae33fed34e88f1cbecf91a2881cf71d
[reactos.git] / reactos / hal / halx86 / legacy / bus / pcibus.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/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_SECTION
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_SECTION
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_SECTION
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_SECTION
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_SECTION
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