- Restructure HAL bus routines a bit.
[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;
709 NTSTATUS Status;
710 UCHAR KeyBuffer[sizeof(PPCI_REGISTRY_INFO) + 100];
711 PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer;
712 ULONG ResultLength;
713 PWSTR Tag;
714 ULONG i;
715 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
716 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
717 PPCI_REGISTRY_INFO PciRegInfo;
718 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
719
720 /* Setup the object attributes for the key */
721 RtlInitUnicodeString(&KeyName,
722 L"\\Registry\\Machine\\Hardware\\Description\\"
723 L"System\\MultiFunctionAdapter");
724 InitializeObjectAttributes(&ObjectAttributes,
725 &KeyName,
726 OBJ_CASE_INSENSITIVE,
727 NULL,
728 NULL);
729
730 /* Open the key */
731 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
732 if (!NT_SUCCESS(Status)) return NULL;
733
734 /* Setup the receiving string */
735 KeyName.Buffer = NameBuffer;
736 KeyName.MaximumLength = sizeof(NameBuffer);
737
738 /* Setup the configuration and identifier key names */
739 RtlInitUnicodeString(&ConfigName, L"ConfigurationData");
740 RtlInitUnicodeString(&IdentName, L"Identifier");
741
742 /* Keep looping for each ID */
743 for (i = 0; TRUE; i++)
744 {
745 /* Setup the key name */
746 RtlIntegerToUnicodeString(i, 10, &KeyName);
747 InitializeObjectAttributes(&ObjectAttributes,
748 &KeyName,
749 OBJ_CASE_INSENSITIVE,
750 KeyHandle,
751 NULL);
752
753 /* Open it */
754 Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes);
755 if (!NT_SUCCESS(Status))
756 {
757 /* None left, fail */
758 ZwClose(KeyHandle);
759 return NULL;
760 }
761
762 /* Read the registry data */
763 Status = ZwQueryValueKey(BusKeyHandle,
764 &IdentName,
765 KeyValueFullInformation,
766 ValueInfo,
767 sizeof(KeyBuffer),
768 &ResultLength);
769 if (!NT_SUCCESS(Status))
770 {
771 /* Failed, try the next one */
772 ZwClose(BusKeyHandle);
773 continue;
774 }
775
776 /* Get the PCI Tag and validate it */
777 Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
778 if ((Tag[0] != L'P') ||
779 (Tag[1] != L'C') ||
780 (Tag[2] != L'I') ||
781 (Tag[3]))
782 {
783 /* Not a valid PCI entry, skip it */
784 ZwClose(BusKeyHandle);
785 continue;
786 }
787
788 /* Now read our PCI structure */
789 Status = ZwQueryValueKey(BusKeyHandle,
790 &ConfigName,
791 KeyValueFullInformation,
792 ValueInfo,
793 sizeof(KeyBuffer),
794 &ResultLength);
795 ZwClose(BusKeyHandle);
796 if (!NT_SUCCESS(Status)) continue;
797
798 /* We read it OK! Get the actual resource descriptors */
799 FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
800 ((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
801 PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
802 ((ULONG_PTR)FullDescriptor->
803 PartialResourceList.PartialDescriptors);
804
805 /* Check if this is our PCI Registry Information */
806 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
807 {
808 /* Close the key */
809 ZwClose(KeyHandle);
810
811 /* FIXME: Check PnP\PCI\CardList */
812
813 /* Get the PCI information */
814 PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1);
815
816 /* Allocate the return structure */
817 PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool,
818 sizeof(PCI_REGISTRY_INFO_INTERNAL),
819 ' laH');
820 if (!PciRegistryInfo) return NULL;
821
822 /* Fill it out */
823 PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism;
824 PciRegistryInfo->NoBuses = PciRegInfo->NoBuses;
825 PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision;
826 PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision;
827 PciRegistryInfo->ElementCount = 0;
828 }
829 }
830 }
831
832 VOID
833 NTAPI
834 HalpInitializePciStubs(VOID)
835 {
836 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
837 UCHAR PciType;
838 PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData;
839 ULONG i;
840 PCI_SLOT_NUMBER j;
841 ULONG VendorId = 0;
842
843 /* Query registry information */
844 PciRegistryInfo = HalpQueryPciRegistryInfo();
845 if (!PciRegistryInfo)
846 {
847 /* Assume type 1 */
848 PciType = 1;
849 }
850 else
851 {
852 /* Get the type and free the info structure */
853 PciType = PciRegistryInfo->HardwareMechanism & 0xF;
854 ExFreePool(PciRegistryInfo);
855 }
856
857 /* Initialize the PCI lock */
858 KeInitializeSpinLock(&HalpPCIConfigLock);
859
860 /* Check the type of PCI bus */
861 switch (PciType)
862 {
863 /* Type 1 PCI Bus */
864 case 1:
865
866 /* Copy the Type 1 handler data */
867 RtlCopyMemory(&PCIConfigHandler,
868 &PCIConfigHandlerType1,
869 sizeof(PCIConfigHandler));
870
871 /* Set correct I/O Ports */
872 BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT;
873 BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
874 break;
875
876 /* Type 2 PCI Bus */
877 case 2:
878
879 /* Copy the Type 1 handler data */
880 RtlCopyMemory(&PCIConfigHandler,
881 &PCIConfigHandlerType2,
882 sizeof (PCIConfigHandler));
883
884 /* Set correct I/O Ports */
885 BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
886 BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
887 BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
888
889 /* Only 16 devices supported, not 32 */
890 BusData->MaxDevice = 16;
891 break;
892
893 default:
894
895 /* Invalid type */
896 DbgPrint("HAL: Unnkown PCI type\n");
897 }
898
899 /* Loop all possible buses */
900 for (i = 0; i < 256; i++)
901 {
902 /* Loop all devices */
903 for (j.u.AsULONG = 0; j.u.AsULONG < 32; j.u.AsULONG++)
904 {
905 /* Query the interface */
906 if (HaliPciInterfaceReadConfig(NULL,
907 i,
908 j,
909 &VendorId,
910 0,
911 sizeof(ULONG)))
912 {
913 /* Validate the vendor ID */
914 if ((USHORT)VendorId != PCI_INVALID_VENDORID)
915 {
916 /* Set this as the maximum ID */
917 HalpMaxPciBus = i;
918 break;
919 }
920 }
921 }
922 }
923
924 /* We're done */
925 HalpPCIConfigInitialized = TRUE;
926 }
927
928 VOID
929 NTAPI
930 HalpInitializePciBus(VOID)
931 {
932 /* Initialize the stubs */
933 HalpInitializePciStubs();
934
935 /* FIXME: Initialize NMI Crash Flag */
936 }
937
938 /* EOF */