50f1add18d8183ed3badc799c52750e3551fb7c1
[reactos.git] / 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 KeRaiseIrql(HIGH_LEVEL, Irql);
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 KeLowerIrql(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 KeRaiseIrql(HIGH_LEVEL, Irql);
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 KeLowerIrql(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_ADDRESS_MEMORY_SPACE ==
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 #ifndef _MINIHAL_
706 WCHAR NameBuffer[8];
707 OBJECT_ATTRIBUTES ObjectAttributes;
708 UNICODE_STRING KeyName, ConfigName, IdentName;
709 HANDLE KeyHandle, BusKeyHandle, CardListHandle;
710 NTSTATUS Status;
711 UCHAR KeyBuffer[sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + 100];
712 PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer;
713 UCHAR PartialKeyBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
714 sizeof(PCI_CARD_DESCRIPTOR)];
715 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo = (PVOID)PartialKeyBuffer;
716 KEY_FULL_INFORMATION KeyInformation;
717 ULONG ResultLength;
718 PWSTR Tag;
719 ULONG i, ElementCount;
720 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
721 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
722 PPCI_REGISTRY_INFO PciRegInfo;
723 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
724 PPCI_CARD_DESCRIPTOR CardDescriptor;
725
726 /* Setup the object attributes for the key */
727 RtlInitUnicodeString(&KeyName,
728 L"\\Registry\\Machine\\Hardware\\Description\\"
729 L"System\\MultiFunctionAdapter");
730 InitializeObjectAttributes(&ObjectAttributes,
731 &KeyName,
732 OBJ_CASE_INSENSITIVE,
733 NULL,
734 NULL);
735
736 /* Open the key */
737 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
738 if (!NT_SUCCESS(Status)) return NULL;
739
740 /* Setup the receiving string */
741 KeyName.Buffer = NameBuffer;
742 KeyName.MaximumLength = sizeof(NameBuffer);
743
744 /* Setup the configuration and identifier key names */
745 RtlInitUnicodeString(&ConfigName, L"Configuration Data");
746 RtlInitUnicodeString(&IdentName, L"Identifier");
747
748 /* Keep looping for each ID */
749 for (i = 0; TRUE; i++)
750 {
751 /* Setup the key name */
752 RtlIntegerToUnicodeString(i, 10, &KeyName);
753 InitializeObjectAttributes(&ObjectAttributes,
754 &KeyName,
755 OBJ_CASE_INSENSITIVE,
756 KeyHandle,
757 NULL);
758
759 /* Open it */
760 Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes);
761 if (!NT_SUCCESS(Status))
762 {
763 /* None left, fail */
764 ZwClose(KeyHandle);
765 return NULL;
766 }
767
768 /* Read the registry data */
769 Status = ZwQueryValueKey(BusKeyHandle,
770 &IdentName,
771 KeyValueFullInformation,
772 ValueInfo,
773 sizeof(KeyBuffer),
774 &ResultLength);
775 if (!NT_SUCCESS(Status))
776 {
777 /* Failed, try the next one */
778 ZwClose(BusKeyHandle);
779 continue;
780 }
781
782 /* Get the PCI Tag and validate it */
783 Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
784 if ((Tag[0] != L'P') ||
785 (Tag[1] != L'C') ||
786 (Tag[2] != L'I') ||
787 (Tag[3]))
788 {
789 /* Not a valid PCI entry, skip it */
790 ZwClose(BusKeyHandle);
791 continue;
792 }
793
794 /* Now read our PCI structure */
795 Status = ZwQueryValueKey(BusKeyHandle,
796 &ConfigName,
797 KeyValueFullInformation,
798 ValueInfo,
799 sizeof(KeyBuffer),
800 &ResultLength);
801 ZwClose(BusKeyHandle);
802 if (!NT_SUCCESS(Status)) continue;
803
804 /* We read it OK! Get the actual resource descriptors */
805 FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
806 ((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
807 PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
808 ((ULONG_PTR)FullDescriptor->
809 PartialResourceList.PartialDescriptors);
810
811 /* Check if this is our PCI Registry Information */
812 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
813 {
814 /* It is, stop searching */
815 break;
816 }
817 }
818
819 /* Close the key */
820 ZwClose(KeyHandle);
821
822 /* Save the PCI information for later */
823 PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1);
824
825 /* Assume no Card List entries */
826 ElementCount = 0;
827
828 /* Set up for checking the PCI Card List key */
829 RtlInitUnicodeString(&KeyName,
830 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
831 L"Control\\PnP\\PCI\\CardList");
832 InitializeObjectAttributes(&ObjectAttributes,
833 &KeyName,
834 OBJ_CASE_INSENSITIVE,
835 NULL,
836 NULL);
837
838 /* Attempt to open it */
839 Status = ZwOpenKey(&CardListHandle, KEY_READ, &ObjectAttributes);
840 if (NT_SUCCESS(Status))
841 {
842 /* It exists, so let's query it */
843 Status = ZwQueryKey(CardListHandle,
844 KeyFullInformation,
845 &KeyInformation,
846 sizeof(KEY_FULL_INFORMATION),
847 &ResultLength);
848 if (!NT_SUCCESS(Status))
849 {
850 /* Failed to query, so no info */
851 PciRegistryInfo = NULL;
852 }
853 else
854 {
855 /* Allocate the full structure */
856 PciRegistryInfo =
857 ExAllocatePoolWithTag(NonPagedPool,
858 sizeof(PCI_REGISTRY_INFO_INTERNAL) +
859 (KeyInformation.Values *
860 sizeof(PCI_CARD_DESCRIPTOR)),
861 ' laH');
862 if (PciRegistryInfo)
863 {
864 /* Get the first card descriptor entry */
865 CardDescriptor = (PPCI_CARD_DESCRIPTOR)(PciRegistryInfo + 1);
866
867 /* Loop all the values */
868 for (i = 0; i < KeyInformation.Values; i++)
869 {
870 /* Attempt to get the value */
871 Status = ZwEnumerateValueKey(CardListHandle,
872 i,
873 KeyValuePartialInformation,
874 PartialValueInfo,
875 sizeof(PartialKeyBuffer),
876 &ResultLength);
877 if (!NT_SUCCESS(Status))
878 {
879 /* Something went wrong, stop the search */
880 break;
881 }
882
883 /* Make sure it is correctly sized */
884 if (PartialValueInfo->DataLength == sizeof(PCI_CARD_DESCRIPTOR))
885 {
886 /* Sure is, copy it over */
887 *CardDescriptor = *(PPCI_CARD_DESCRIPTOR)
888 PartialValueInfo->Data;
889
890 /* One more Card List entry */
891 ElementCount++;
892
893 /* Move to the next descriptor */
894 CardDescriptor = (CardDescriptor + 1);
895 }
896 }
897 }
898 }
899
900 /* Close the Card List key */
901 ZwClose(CardListHandle);
902 }
903 else
904 {
905 /* No key, no Card List */
906 PciRegistryInfo = NULL;
907 }
908
909 /* Check if we failed to get the full structure */
910 if (!PciRegistryInfo)
911 {
912 /* Just allocate the basic structure then */
913 PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool,
914 sizeof(PCI_REGISTRY_INFO_INTERNAL),
915 ' laH');
916 if (!PciRegistryInfo) return NULL;
917 }
918
919 /* Save the info we got */
920 PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision;
921 PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision;
922 PciRegistryInfo->NoBuses = PciRegInfo->NoBuses;
923 PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism;
924 PciRegistryInfo->ElementCount = ElementCount;
925
926 /* Return it */
927 return PciRegistryInfo;
928 #else
929 return NULL;
930 #endif
931 }
932
933 VOID
934 NTAPI
935 HalpInitializePciStubs(VOID)
936 {
937 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
938 UCHAR PciType;
939 PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData;
940 ULONG i;
941 PCI_SLOT_NUMBER j;
942 ULONG VendorId = 0;
943
944 /* Query registry information */
945 PciRegistryInfo = HalpQueryPciRegistryInfo();
946 if (!PciRegistryInfo)
947 {
948 /* Assume type 1 */
949 PciType = 1;
950 }
951 else
952 {
953 /* Get the type and free the info structure */
954 PciType = PciRegistryInfo->HardwareMechanism & 0xF;
955 ExFreePool(PciRegistryInfo);
956 }
957
958 /* Initialize the PCI lock */
959 KeInitializeSpinLock(&HalpPCIConfigLock);
960
961 /* Check the type of PCI bus */
962 switch (PciType)
963 {
964 /* Type 1 PCI Bus */
965 case 1:
966
967 /* Copy the Type 1 handler data */
968 RtlCopyMemory(&PCIConfigHandler,
969 &PCIConfigHandlerType1,
970 sizeof(PCIConfigHandler));
971
972 /* Set correct I/O Ports */
973 BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT;
974 BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
975 break;
976
977 /* Type 2 PCI Bus */
978 case 2:
979
980 /* Copy the Type 1 handler data */
981 RtlCopyMemory(&PCIConfigHandler,
982 &PCIConfigHandlerType2,
983 sizeof (PCIConfigHandler));
984
985 /* Set correct I/O Ports */
986 BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
987 BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
988 BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
989
990 /* Only 16 devices supported, not 32 */
991 BusData->MaxDevice = 16;
992 break;
993
994 default:
995
996 /* Invalid type */
997 DbgPrint("HAL: Unknown PCI type\n");
998 }
999
1000 /* Loop all possible buses */
1001 for (i = 0; i < 256; i++)
1002 {
1003 /* Loop all devices */
1004 for (j.u.AsULONG = 0; j.u.AsULONG < 32; j.u.AsULONG++)
1005 {
1006 /* Query the interface */
1007 if (HaliPciInterfaceReadConfig(NULL,
1008 i,
1009 j,
1010 &VendorId,
1011 0,
1012 sizeof(ULONG)))
1013 {
1014 /* Validate the vendor ID */
1015 if ((USHORT)VendorId != PCI_INVALID_VENDORID)
1016 {
1017 /* Set this as the maximum ID */
1018 HalpMaxPciBus = i;
1019 break;
1020 }
1021 }
1022 }
1023 }
1024
1025 /* We're done */
1026 HalpPCIConfigInitialized = TRUE;
1027 }
1028
1029 VOID
1030 NTAPI
1031 HalpInitializePciBus(VOID)
1032 {
1033 /* FIXME: Initialize NMI Crash Flag */
1034 }