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