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