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