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