Synchronize up to trunk's revision r57756.
[reactos.git] / 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 /* 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), TAG_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 INIT_FUNCTION
604 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock,
605 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
606 {
607 DPRINT1("Unimplemented!\n");
608 return STATUS_NOT_IMPLEMENTED;
609 }
610
611 NTSTATUS
612 NTAPI
613 INIT_FUNCTION
614 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
615 {
616 DPRINT1("Unimplemented!\n");
617 return STATUS_NOT_IMPLEMENTED;
618 }
619
620 VOID
621 NTAPI
622 INIT_FUNCTION
623 HalpRegisterPciDebuggingDeviceInfo(VOID)
624 {
625 BOOLEAN Found = FALSE;
626 ULONG i;
627 PAGED_CODE();
628
629 /* Loop PCI debugging devices */
630 for (i = 0; i < 2; i++)
631 {
632 /* Reserved bit is set if we found one */
633 if (HalpPciDebuggingDevice[i].u.bits.Reserved1)
634 {
635 Found = TRUE;
636 break;
637 }
638 }
639
640 /* Bail out if there aren't any */
641 if (!Found) return;
642
643 /* FIXME: TODO */
644 DPRINT1("You have implemented the KD routines for searching PCI debugger"
645 "devices, but you have forgotten to implement this routine\n");
646 while (TRUE);
647 }
648
649 static ULONG NTAPI
650 PciSize(ULONG Base, ULONG Mask)
651 {
652 ULONG Size = Mask & Base; /* Find the significant bits */
653 Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */
654 return Size;
655 }
656
657 NTSTATUS
658 NTAPI
659 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler,
660 IN PBUS_HANDLER RootHandler,
661 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList)
662 {
663 PPCIPBUSDATA BusData;
664 PCI_SLOT_NUMBER SlotNumber;
665 PSUPPORTED_RANGE Interrupt;
666 NTSTATUS Status;
667
668 /* Get PCI bus data */
669 BusData = BusHandler->BusData;
670 SlotNumber.u.AsULONG = (*pResourceList)->SlotNumber;
671
672 /* Get the IRQ supported range */
673 Status = BusData->GetIrqRange(BusHandler, RootHandler, SlotNumber, &Interrupt);
674 if (!NT_SUCCESS(Status)) return Status;
675 #ifndef _MINIHAL_
676 /* Handle the /PCILOCK feature */
677 if (HalpPciLockSettings)
678 {
679 /* /PCILOCK is not yet supported */
680 UNIMPLEMENTED;
681 while (TRUE);
682 }
683 #endif
684 /* Now create the correct resource list based on the supported bus ranges */
685 #if 0
686 Status = HaliAdjustResourceListRange(BusHandler->BusAddresses,
687 Interrupt,
688 pResourceList);
689 #else
690 DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n");
691 Status = STATUS_SUCCESS;
692 #endif
693
694 /* Return to caller */
695 ExFreePool(Interrupt);
696 return Status;
697 }
698
699 NTSTATUS
700 NTAPI
701 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler,
702 IN PBUS_HANDLER RootHandler,
703 IN PUNICODE_STRING RegistryPath,
704 IN PUNICODE_STRING DriverClassName OPTIONAL,
705 IN PDRIVER_OBJECT DriverObject,
706 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
707 IN ULONG Slot,
708 IN OUT PCM_RESOURCE_LIST *AllocatedResources)
709 {
710 PCI_COMMON_CONFIG PciConfig;
711 SIZE_T Address;
712 ULONG ResourceCount;
713 ULONG Size[PCI_TYPE0_ADDRESSES];
714 NTSTATUS Status = STATUS_SUCCESS;
715 UCHAR Offset;
716 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
717 PCI_SLOT_NUMBER SlotNumber;
718 ULONG WriteBuffer;
719 DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n");
720
721 /* FIXME: Should handle 64-bit addresses */
722
723 /* Read configuration data */
724 SlotNumber.u.AsULONG = Slot;
725 HalpReadPCIConfig(BusHandler, SlotNumber, &PciConfig, 0, PCI_COMMON_HDR_LENGTH);
726
727 /* Check if we read it correctly */
728 if (PciConfig.VendorID == PCI_INVALID_VENDORID)
729 return STATUS_NO_SUCH_DEVICE;
730
731 /* Read the PCI configuration space for the device and store base address and
732 size information in temporary storage. Count the number of valid base addresses */
733 ResourceCount = 0;
734 for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
735 {
736 if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address])
737 PciConfig.u.type0.BaseAddresses[Address] = 0;
738
739 /* Memory resource */
740 if (0 != PciConfig.u.type0.BaseAddresses[Address])
741 {
742 ResourceCount++;
743
744 Offset = (UCHAR)FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]);
745
746 /* Write 0xFFFFFFFF there */
747 WriteBuffer = 0xffffffff;
748 HalpWritePCIConfig(BusHandler, SlotNumber, &WriteBuffer, Offset, sizeof(ULONG));
749
750 /* Read that figure back from the config space */
751 HalpReadPCIConfig(BusHandler, SlotNumber, &Size[Address], Offset, sizeof(ULONG));
752
753 /* Write back initial value */
754 HalpWritePCIConfig(BusHandler, SlotNumber, &PciConfig.u.type0.BaseAddresses[Address], Offset, sizeof(ULONG));
755 }
756 }
757
758 /* Interrupt resource */
759 if (0 != PciConfig.u.type0.InterruptPin &&
760 0 != PciConfig.u.type0.InterruptLine &&
761 0xFF != PciConfig.u.type0.InterruptLine)
762 ResourceCount++;
763
764 /* Allocate output buffer and initialize */
765 *AllocatedResources = ExAllocatePoolWithTag(
766 PagedPool,
767 sizeof(CM_RESOURCE_LIST) +
768 (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
769 TAG_HAL);
770
771 if (NULL == *AllocatedResources)
772 return STATUS_NO_MEMORY;
773
774 (*AllocatedResources)->Count = 1;
775 (*AllocatedResources)->List[0].InterfaceType = PCIBus;
776 (*AllocatedResources)->List[0].BusNumber = BusHandler->BusNumber;
777 (*AllocatedResources)->List[0].PartialResourceList.Version = 1;
778 (*AllocatedResources)->List[0].PartialResourceList.Revision = 1;
779 (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount;
780 Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors;
781
782 /* Store configuration information */
783 for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
784 {
785 if (0 != PciConfig.u.type0.BaseAddresses[Address])
786 {
787 if (PCI_ADDRESS_MEMORY_SPACE ==
788 (PciConfig.u.type0.BaseAddresses[Address] & 0x1))
789 {
790 Descriptor->Type = CmResourceTypeMemory;
791 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
792 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; /* FIXME Just a guess */
793 Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_ADDRESS_MEMORY_ADDRESS_MASK);
794 Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_ADDRESS_MEMORY_ADDRESS_MASK);
795 }
796 else if (PCI_ADDRESS_IO_SPACE ==
797 (PciConfig.u.type0.BaseAddresses[Address] & 0x1))
798 {
799 Descriptor->Type = CmResourceTypePort;
800 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
801 Descriptor->Flags = CM_RESOURCE_PORT_IO; /* FIXME Just a guess */
802 Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_ADDRESS_IO_ADDRESS_MASK;
803 Descriptor->u.Port.Length = PciSize(Size[Address], PCI_ADDRESS_IO_ADDRESS_MASK & 0xffff);
804 }
805 else
806 {
807 ASSERT(FALSE);
808 return STATUS_UNSUCCESSFUL;
809 }
810 Descriptor++;
811 }
812 }
813
814 if (0 != PciConfig.u.type0.InterruptPin &&
815 0 != PciConfig.u.type0.InterruptLine &&
816 0xFF != PciConfig.u.type0.InterruptLine)
817 {
818 Descriptor->Type = CmResourceTypeInterrupt;
819 Descriptor->ShareDisposition = CmResourceShareShared; /* FIXME Just a guess */
820 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; /* FIXME Just a guess */
821 Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine;
822 Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine;
823 Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
824
825 Descriptor++;
826 }
827
828 ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount);
829
830 /* FIXME: Should store the resources in the registry resource map */
831
832 return Status;
833 }
834
835 ULONG
836 NTAPI
837 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler,
838 IN ULONG BusNumber,
839 IN PCI_SLOT_NUMBER SlotNumber,
840 IN PVOID Buffer,
841 IN ULONG Offset,
842 IN ULONG Length)
843 {
844 BUS_HANDLER BusHandler;
845
846 /* Setup fake PCI Bus handler */
847 RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
848 BusHandler.BusNumber = BusNumber;
849
850 /* Read configuration data */
851 HalpReadPCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length);
852
853 /* Return length */
854 return Length;
855 }
856
857 PPCI_REGISTRY_INFO_INTERNAL
858 NTAPI
859 INIT_FUNCTION
860 HalpQueryPciRegistryInfo(VOID)
861 {
862 #ifndef _MINIHAL_
863 WCHAR NameBuffer[8];
864 OBJECT_ATTRIBUTES ObjectAttributes;
865 UNICODE_STRING KeyName, ConfigName, IdentName;
866 HANDLE KeyHandle, BusKeyHandle, CardListHandle;
867 NTSTATUS Status;
868 UCHAR KeyBuffer[sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + 100];
869 PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer;
870 UCHAR PartialKeyBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
871 sizeof(PCI_CARD_DESCRIPTOR)];
872 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo = (PVOID)PartialKeyBuffer;
873 KEY_FULL_INFORMATION KeyInformation;
874 ULONG ResultLength;
875 PWSTR Tag;
876 ULONG i, ElementCount;
877 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
878 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
879 PPCI_REGISTRY_INFO PciRegInfo;
880 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
881 PPCI_CARD_DESCRIPTOR CardDescriptor;
882
883 /* Setup the object attributes for the key */
884 RtlInitUnicodeString(&KeyName,
885 L"\\Registry\\Machine\\Hardware\\Description\\"
886 L"System\\MultiFunctionAdapter");
887 InitializeObjectAttributes(&ObjectAttributes,
888 &KeyName,
889 OBJ_CASE_INSENSITIVE,
890 NULL,
891 NULL);
892
893 /* Open the key */
894 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
895 if (!NT_SUCCESS(Status)) return NULL;
896
897 /* Setup the receiving string */
898 KeyName.Buffer = NameBuffer;
899 KeyName.MaximumLength = sizeof(NameBuffer);
900
901 /* Setup the configuration and identifier key names */
902 RtlInitUnicodeString(&ConfigName, L"Configuration Data");
903 RtlInitUnicodeString(&IdentName, L"Identifier");
904
905 /* Keep looping for each ID */
906 for (i = 0; TRUE; i++)
907 {
908 /* Setup the key name */
909 RtlIntegerToUnicodeString(i, 10, &KeyName);
910 InitializeObjectAttributes(&ObjectAttributes,
911 &KeyName,
912 OBJ_CASE_INSENSITIVE,
913 KeyHandle,
914 NULL);
915
916 /* Open it */
917 Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes);
918 if (!NT_SUCCESS(Status))
919 {
920 /* None left, fail */
921 ZwClose(KeyHandle);
922 return NULL;
923 }
924
925 /* Read the registry data */
926 Status = ZwQueryValueKey(BusKeyHandle,
927 &IdentName,
928 KeyValueFullInformation,
929 ValueInfo,
930 sizeof(KeyBuffer),
931 &ResultLength);
932 if (!NT_SUCCESS(Status))
933 {
934 /* Failed, try the next one */
935 ZwClose(BusKeyHandle);
936 continue;
937 }
938
939 /* Get the PCI Tag and validate it */
940 Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
941 if ((Tag[0] != L'P') ||
942 (Tag[1] != L'C') ||
943 (Tag[2] != L'I') ||
944 (Tag[3]))
945 {
946 /* Not a valid PCI entry, skip it */
947 ZwClose(BusKeyHandle);
948 continue;
949 }
950
951 /* Now read our PCI structure */
952 Status = ZwQueryValueKey(BusKeyHandle,
953 &ConfigName,
954 KeyValueFullInformation,
955 ValueInfo,
956 sizeof(KeyBuffer),
957 &ResultLength);
958 ZwClose(BusKeyHandle);
959 if (!NT_SUCCESS(Status)) continue;
960
961 /* We read it OK! Get the actual resource descriptors */
962 FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
963 ((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
964 PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
965 ((ULONG_PTR)FullDescriptor->
966 PartialResourceList.PartialDescriptors);
967
968 /* Check if this is our PCI Registry Information */
969 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
970 {
971 /* It is, stop searching */
972 break;
973 }
974 }
975
976 /* Close the key */
977 ZwClose(KeyHandle);
978
979 /* Save the PCI information for later */
980 PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1);
981
982 /* Assume no Card List entries */
983 ElementCount = 0;
984
985 /* Set up for checking the PCI Card List key */
986 RtlInitUnicodeString(&KeyName,
987 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
988 L"Control\\PnP\\PCI\\CardList");
989 InitializeObjectAttributes(&ObjectAttributes,
990 &KeyName,
991 OBJ_CASE_INSENSITIVE,
992 NULL,
993 NULL);
994
995 /* Attempt to open it */
996 Status = ZwOpenKey(&CardListHandle, KEY_READ, &ObjectAttributes);
997 if (NT_SUCCESS(Status))
998 {
999 /* It exists, so let's query it */
1000 Status = ZwQueryKey(CardListHandle,
1001 KeyFullInformation,
1002 &KeyInformation,
1003 sizeof(KEY_FULL_INFORMATION),
1004 &ResultLength);
1005 if (!NT_SUCCESS(Status))
1006 {
1007 /* Failed to query, so no info */
1008 PciRegistryInfo = NULL;
1009 }
1010 else
1011 {
1012 /* Allocate the full structure */
1013 PciRegistryInfo =
1014 ExAllocatePoolWithTag(NonPagedPool,
1015 sizeof(PCI_REGISTRY_INFO_INTERNAL) +
1016 (KeyInformation.Values *
1017 sizeof(PCI_CARD_DESCRIPTOR)),
1018 TAG_HAL);
1019 if (PciRegistryInfo)
1020 {
1021 /* Get the first card descriptor entry */
1022 CardDescriptor = (PPCI_CARD_DESCRIPTOR)(PciRegistryInfo + 1);
1023
1024 /* Loop all the values */
1025 for (i = 0; i < KeyInformation.Values; i++)
1026 {
1027 /* Attempt to get the value */
1028 Status = ZwEnumerateValueKey(CardListHandle,
1029 i,
1030 KeyValuePartialInformation,
1031 PartialValueInfo,
1032 sizeof(PartialKeyBuffer),
1033 &ResultLength);
1034 if (!NT_SUCCESS(Status))
1035 {
1036 /* Something went wrong, stop the search */
1037 break;
1038 }
1039
1040 /* Make sure it is correctly sized */
1041 if (PartialValueInfo->DataLength == sizeof(PCI_CARD_DESCRIPTOR))
1042 {
1043 /* Sure is, copy it over */
1044 *CardDescriptor = *(PPCI_CARD_DESCRIPTOR)
1045 PartialValueInfo->Data;
1046
1047 /* One more Card List entry */
1048 ElementCount++;
1049
1050 /* Move to the next descriptor */
1051 CardDescriptor = (CardDescriptor + 1);
1052 }
1053 }
1054 }
1055 }
1056
1057 /* Close the Card List key */
1058 ZwClose(CardListHandle);
1059 }
1060 else
1061 {
1062 /* No key, no Card List */
1063 PciRegistryInfo = NULL;
1064 }
1065
1066 /* Check if we failed to get the full structure */
1067 if (!PciRegistryInfo)
1068 {
1069 /* Just allocate the basic structure then */
1070 PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool,
1071 sizeof(PCI_REGISTRY_INFO_INTERNAL),
1072 TAG_HAL);
1073 if (!PciRegistryInfo) return NULL;
1074 }
1075
1076 /* Save the info we got */
1077 PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision;
1078 PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision;
1079 PciRegistryInfo->NoBuses = PciRegInfo->NoBuses;
1080 PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism;
1081 PciRegistryInfo->ElementCount = ElementCount;
1082
1083 /* Return it */
1084 return PciRegistryInfo;
1085 #else
1086 return NULL;
1087 #endif
1088 }
1089
1090 VOID
1091 NTAPI
1092 INIT_FUNCTION
1093 HalpInitializePciStubs(VOID)
1094 {
1095 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
1096 UCHAR PciType;
1097 PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData;
1098 ULONG i;
1099 PCI_SLOT_NUMBER j;
1100 ULONG VendorId = 0;
1101 ULONG MaxPciBusNumber;
1102
1103 /* Query registry information */
1104 PciRegistryInfo = HalpQueryPciRegistryInfo();
1105 if (!PciRegistryInfo)
1106 {
1107 /* Assume type 1 */
1108 PciType = 1;
1109
1110 /* Force a manual bus scan later */
1111 MaxPciBusNumber = MAXULONG;
1112 }
1113 else
1114 {
1115 /* Get the PCI type */
1116 PciType = PciRegistryInfo->HardwareMechanism & 0xF;
1117
1118 /* Get MaxPciBusNumber and make it 0-based */
1119 MaxPciBusNumber = PciRegistryInfo->NoBuses - 1;
1120
1121 /* Free the info structure */
1122 ExFreePoolWithTag(PciRegistryInfo, TAG_HAL);
1123 }
1124
1125 /* Initialize the PCI lock */
1126 KeInitializeSpinLock(&HalpPCIConfigLock);
1127
1128 /* Check the type of PCI bus */
1129 switch (PciType)
1130 {
1131 /* Type 1 PCI Bus */
1132 case 1:
1133
1134 /* Copy the Type 1 handler data */
1135 RtlCopyMemory(&PCIConfigHandler,
1136 &PCIConfigHandlerType1,
1137 sizeof(PCIConfigHandler));
1138
1139 /* Set correct I/O Ports */
1140 BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT;
1141 BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
1142 break;
1143
1144 /* Type 2 PCI Bus */
1145 case 2:
1146
1147 /* Copy the Type 2 handler data */
1148 RtlCopyMemory(&PCIConfigHandler,
1149 &PCIConfigHandlerType2,
1150 sizeof (PCIConfigHandler));
1151
1152 /* Set correct I/O Ports */
1153 BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
1154 BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
1155 BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
1156
1157 /* Only 16 devices supported, not 32 */
1158 BusData->MaxDevice = 16;
1159 break;
1160
1161 default:
1162
1163 /* Invalid type */
1164 DbgPrint("HAL: Unknown PCI type\n");
1165 }
1166
1167 /* Run a forced bus scan if needed */
1168 if (MaxPciBusNumber == MAXULONG)
1169 {
1170 /* Initialize the max bus number to 0xFF */
1171 HalpMaxPciBus = 0xFF;
1172
1173 /* Initialize the counter */
1174 MaxPciBusNumber = 0;
1175
1176 /* Loop all possible buses */
1177 for (i = 0; i < HalpMaxPciBus; i++)
1178 {
1179 /* Loop all devices */
1180 for (j.u.AsULONG = 0; j.u.AsULONG < BusData->MaxDevice; j.u.AsULONG++)
1181 {
1182 /* Query the interface */
1183 if (HaliPciInterfaceReadConfig(NULL,
1184 i,
1185 j,
1186 &VendorId,
1187 0,
1188 sizeof(ULONG)))
1189 {
1190 /* Validate the vendor ID */
1191 if ((VendorId & 0xFFFF) != PCI_INVALID_VENDORID)
1192 {
1193 /* Set this as the maximum ID */
1194 MaxPciBusNumber = i;
1195 break;
1196 }
1197 }
1198 }
1199 }
1200 }
1201
1202 /* Set the real max bus number */
1203 HalpMaxPciBus = MaxPciBusNumber;
1204
1205 /* We're done */
1206 HalpPCIConfigInitialized = TRUE;
1207 }
1208
1209 /* EOF */
1210