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