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