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