- Add support for PnP IRP to PDO: IRP_MN_QUERY_BUS_INFORMATION (PciQueryBusInformatio...
[reactos.git] / reactos / drivers / bus / pcix / enum.c
1 /*
2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/enum.c
5 * PURPOSE: PCI Bus/Device Enumeration
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements;
18
19 PCI_CONFIGURATOR PciConfigurators[] =
20 {
21 {
22 Device_MassageHeaderForLimitsDetermination,
23 Device_RestoreCurrent,
24 Device_SaveLimits,
25 Device_SaveCurrentSettings,
26 Device_ChangeResourceSettings,
27 Device_GetAdditionalResourceDescriptors,
28 Device_ResetDevice
29 },
30 {
31 PPBridge_MassageHeaderForLimitsDetermination,
32 PPBridge_RestoreCurrent,
33 PPBridge_SaveLimits,
34 PPBridge_SaveCurrentSettings,
35 PPBridge_ChangeResourceSettings,
36 PPBridge_GetAdditionalResourceDescriptors,
37 PPBridge_ResetDevice
38 },
39 {
40 Cardbus_MassageHeaderForLimitsDetermination,
41 Cardbus_RestoreCurrent,
42 Cardbus_SaveLimits,
43 Cardbus_SaveCurrentSettings,
44 Cardbus_ChangeResourceSettings,
45 Cardbus_GetAdditionalResourceDescriptors,
46 Cardbus_ResetDevice
47 }
48 };
49
50 /* FUNCTIONS ******************************************************************/
51
52 NTSTATUS
53 NTAPI
54 PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension,
55 OUT PCM_RESOURCE_LIST *Buffer)
56 {
57 /* Not yet implemented */
58 UNIMPLEMENTED;
59 while (TRUE);
60 return STATUS_SUCCESS;
61 }
62
63 NTSTATUS
64 NTAPI
65 PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension,
66 IN OUT PDEVICE_RELATIONS *pDeviceRelations)
67 {
68 PDEVICE_RELATIONS DeviceRelations;
69 PAGED_CODE();
70
71 /* If there were existing relations, free them */
72 if (*pDeviceRelations) ExFreePoolWithTag(*pDeviceRelations, 0);
73
74 /* Allocate a new structure for the relations */
75 DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
76 sizeof(DEVICE_RELATIONS),
77 'BicP');
78 if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES;
79
80 /* Only one relation: the PDO */
81 DeviceRelations->Count = 1;
82 DeviceRelations->Objects[0] = PdoExtension->PhysicalDeviceObject;
83 ObReferenceObject(DeviceRelations->Objects[0]);
84
85 /* Return the new relations */
86 *pDeviceRelations = DeviceRelations;
87 return STATUS_SUCCESS;
88 }
89
90 NTSTATUS
91 NTAPI
92 PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension,
93 IN OUT PDEVICE_RELATIONS *pDeviceRelations)
94 {
95 /* Not yet implemented */
96 UNIMPLEMENTED;
97 while (TRUE);
98 }
99
100 NTSTATUS
101 NTAPI
102 PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension,
103 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList)
104 {
105 /* Not yet implemented */
106 UNIMPLEMENTED;
107 while (TRUE);
108 return STATUS_SUCCESS;
109 }
110
111 /*
112 * 7. The IO/MEM/Busmaster decodes are disabled for the device.
113 * 8. The PCI bus driver sets the operating mode bits of the Programming
114 * Interface byte to switch the controller to native mode.
115 *
116 * Important: When the controller is set to native mode, it must quiet itself
117 * and must not decode I/O resources or generate interrupts until the operating
118 * system has enabled the ports in the PCI configuration header.
119 * The IO/MEM/BusMaster bits will be disabled before the mode change, but it
120 * is not possible to disable interrupts on the device. The device must not
121 * generate interrupts (either legacy or native mode) while the decodes are
122 * disabled in the command register.
123 *
124 * This operation is expected to be instantaneous and the operating system does
125 * not stall afterward. It is also expected that the interrupt pin register in
126 * the PCI Configuration space for this device is accurate. The operating system
127 * re-reads this data after previously ignoring it.
128 */
129 BOOLEAN
130 NTAPI
131 PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,
132 IN PPCI_COMMON_HEADER PciData,
133 IN BOOLEAN Initial)
134 {
135 UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf;
136 BOOLEAN Switched;
137 USHORT Command;
138
139 /* Assume it won't work */
140 Switched = FALSE;
141
142 /* Get master and slave current settings, and programmability flag */
143 ProgIf = PciData->ProgIf;
144 MasterMode = (ProgIf & 1) == 1;
145 MasterFixed = (ProgIf & 2) == 0;
146 SlaveMode = (ProgIf & 4) == 4;
147 SlaveFixed = (ProgIf & 8) == 0;
148
149 /*
150 * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
151 * ATA controller from compatible mode to native mode, the following must be
152 * true:
153 *
154 * - The controller must indicate in its programming interface that both channels
155 * can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
156 * not support switching only one IDE channel to native mode. See the PCI IDE
157 * Controller Specification Revision 1.0 for details.
158 */
159 if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed))
160 {
161 /* Windows does not support this configuration, fail */
162 DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
163 PdoExtension->VendorId,
164 PdoExtension->DeviceId);
165 return Switched;
166 }
167
168 /* Check if the controller is already in native mode */
169 if ((MasterMode) && (SlaveMode))
170 {
171 /* Check if I/O decodes should be disabled */
172 if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl))
173 {
174 /* Read the current command */
175 PciReadDeviceConfig(PdoExtension,
176 &Command,
177 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
178 sizeof(USHORT));
179
180 /* Disable I/O space decode */
181 Command &= ~PCI_ENABLE_IO_SPACE;
182
183 /* Update new command in PCI IDE controller */
184 PciWriteDeviceConfig(PdoExtension,
185 &Command,
186 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
187 sizeof(USHORT));
188
189 /* Save updated command value */
190 PciData->Command = Command;
191 }
192
193 /* The controller is now in native mode */
194 Switched = TRUE;
195 }
196 else if (!(MasterFixed) &&
197 !(SlaveFixed) &&
198 (PdoExtension->BIOSAllowsIDESwitchToNativeMode) &&
199 !(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE))
200 {
201 /* Turn off decodes */
202 PciDecodeEnable(PdoExtension, FALSE, NULL);
203
204 /* Update the current command */
205 PciReadDeviceConfig(PdoExtension,
206 &PciData->Command,
207 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
208 sizeof(USHORT));
209
210 /* Enable native mode */
211 ProgIf = PciData->ProgIf | 5;
212 PciWriteDeviceConfig(PdoExtension,
213 &ProgIf,
214 FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
215 sizeof(UCHAR));
216
217 /* Verify the setting "stuck" */
218 PciReadDeviceConfig(PdoExtension,
219 &NewProgIf,
220 FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
221 sizeof(UCHAR));
222 if (NewProgIf == ProgIf)
223 {
224 /* Update the header and PDO data with the new programming mode */
225 PciData->ProgIf = ProgIf;
226 PdoExtension->ProgIf = NewProgIf;
227
228 /* Clear the first four BARs to reset current BAR setttings */
229 PciData->u.type0.BaseAddresses[0] = 0;
230 PciData->u.type0.BaseAddresses[1] = 0;
231 PciData->u.type0.BaseAddresses[2] = 0;
232 PciData->u.type0.BaseAddresses[3] = 0;
233 PciWriteDeviceConfig(PdoExtension,
234 PciData->u.type0.BaseAddresses,
235 FIELD_OFFSET(PCI_COMMON_HEADER,
236 u.type0.BaseAddresses),
237 4 * sizeof(ULONG));
238
239 /* Re-read the BARs to have the latest data for native mode IDE */
240 PciReadDeviceConfig(PdoExtension,
241 PciData->u.type0.BaseAddresses,
242 FIELD_OFFSET(PCI_COMMON_HEADER,
243 u.type0.BaseAddresses),
244 4 * sizeof(ULONG));
245
246 /* Re-read the interrupt pin used for native mode IDE */
247 PciReadDeviceConfig(PdoExtension,
248 &PciData->u.type0.InterruptPin,
249 FIELD_OFFSET(PCI_COMMON_HEADER,
250 u.type0.InterruptPin),
251 sizeof(UCHAR));
252
253 /* The IDE Controller is now in native mode */
254 Switched = TRUE;
255 }
256 else
257 {
258 /* Settings did not work, fail */
259 DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
260 PciData->VendorID,
261 PciData->DeviceID);
262 }
263 }
264
265 /* Return whether or not native mode was enabled on the IDE controller */
266 return Switched;
267 }
268
269 VOID
270 NTAPI
271 PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,
272 IN PPCI_COMMON_HEADER PciData,
273 IN PCI_SLOT_NUMBER SlotNumber,
274 IN ULONG OperationType,
275 PPCI_PDO_EXTENSION PdoExtension)
276 {
277 ULONG LegacyBaseAddress;
278 USHORT Command;
279 UCHAR RegValue;
280
281 /* Check what kind of hack operation this is */
282 switch (OperationType)
283 {
284 /*
285 * This is mostly concerned with fixing up incorrect class data that can
286 * exist on certain PCI hardware before the 2.0 spec was ratified.
287 */
288 case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
289
290 /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
291 * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
292 * and appear as non-classified, so their correct class/subclass data
293 * is written here instead.
294 */
295 if ((PciData->VendorID == 0x8086) &&
296 ((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484)))
297 {
298 /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
299 PciData->SubClass = PciData->DeviceID == 0x482 ?
300 PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA;
301 PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
302
303 /*
304 * Because the software is modifying the actual header data from
305 * the BIOS, this flag tells the driver to ignore failures when
306 * comparing the original BIOS data with the PCI data.
307 */
308 if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE;
309 }
310
311 /* Note that in this case, an immediate return is issued */
312 return;
313
314 /*
315 * This is concerned with setting up interrupts correctly for native IDE
316 * mode, but will also handle broken VGA decoding on older bridges as
317 * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
318 */
319 case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
320
321 /* There should always be a PDO extension passed in */
322 ASSERT(PdoExtension);
323
324 /*
325 * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
326 * and FreeBSD bug reports indicate that the system crashes when the
327 * feature is enabled (so it's disabled on that OS as well). In the
328 * NT PCI Bus Driver, it seems Microsoft too, completely disables
329 * Native IDE functionality on this controller, so it would seem OPTi
330 * simply frelled up this controller.
331 */
332 if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621))
333 {
334 /* Disable native mode */
335 PciData->ProgIf &= ~5;
336 PciData->u.type0.InterruptPin = 0;
337
338 /*
339 * Because the software is modifying the actual header data from
340 * the BIOS, this flag tells the driver to ignore failures when
341 * comparing the original BIOS data with the PCI data.
342 */
343 PdoExtension->ExpectedWritebackFailure = TRUE;
344 }
345 else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
346 (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
347 {
348 /* For other IDE controllers, start out in compatible mode */
349 PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
350
351 /*
352 * Registry must have enabled native mode (typically as a result
353 * of an INF file directive part of the IDE controller's driver)
354 * and the system must not be booted in Safe Mode. If that checks
355 * out, then evaluate the ACPI NATA method to see if the platform
356 * supports this. See the section "BIOS and Platform Prerequisites
357 * for Switching a Native-Mode-Capable Controller" in the Storage
358 * section of the Windows Driver Kit for more details:
359 *
360 * 5. For each ATA controller enumerated, the PCI bus driver checks
361 * the Programming Interface register of the IDE controller to
362 * see if it supports switching both channels to native mode.
363 * 6. The PCI bus driver checks whether the BIOS/platform supports
364 * switching the controller by checking the NATA method described
365 * earlier in this article.
366 *
367 * If an ATA controller does not indicate that it is native
368 * mode-capable, or if the BIOS NATA control method is missing
369 * or does not list that device, the PCI bus driver does not
370 * switch the controller and it is assigned legacy resources.
371 *
372 * If both the controller and the BIOS indicate that the controller
373 * can be switched, the process of switching the controller begins
374 * with the next step.
375 */
376 if ((PciEnableNativeModeATA) &&
377 !(InitSafeBootMode) &&
378 (PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN')))
379 {
380 /* The platform supports it, remember that */
381 PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
382
383 /*
384 * Now switch the controller into native mode if both channels
385 * support native IDE mode. See "How Windows Switches an ATA
386 * Controller to Native Mode" in the Storage section of the
387 * Windows Driver Kit for more details.
388 */
389 PdoExtension->SwitchedIDEToNativeMode =
390 PciConfigureIdeController(PdoExtension, PciData, 1);
391 }
392
393 /* Is native mode enabled after all? */
394 if ((PciData->ProgIf & 5) != 5)
395 {
396 /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
397 PciData->u.type0.InterruptPin = 0;
398 }
399 }
400
401 /* Is this a PCI device with legacy VGA card decodes on the root bus? */
402 if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) &&
403 (PCI_IS_ROOT_FDO(DeviceExtension)) &&
404 !(DeviceExtension->BrokenVideoHackApplied))
405 {
406 /* Tell the arbiter to apply a hack for these older devices */
407 ario_ApplyBrokenVideoHack(DeviceExtension);
408 }
409
410 /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
411 if ((PciData->VendorID == 0xE11) &&
412 (PciData->DeviceID == 0xA0F7) &&
413 (PciData->RevisionID == 17) &&
414 (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
415 {
416 /* Turn off the decodes immediately */
417 PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
418 PCI_ENABLE_MEMORY_SPACE |
419 PCI_ENABLE_BUS_MASTER);
420 PciWriteDeviceConfig(PdoExtension,
421 &PciData->Command,
422 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
423 sizeof(USHORT));
424
425 /* Do not EVER turn them on again, this will blow up the system */
426 PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE |
427 PCI_ENABLE_MEMORY_SPACE |
428 PCI_ENABLE_BUS_MASTER);
429 PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND;
430 }
431 break;
432
433 /*
434 * This is called whenever resources are changed and hardware needs to be
435 * updated. It is concerned with two highly specific erratas on an IBM
436 * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
437 * ICH PCI Bridges.
438 */
439 case PCI_HACK_FIXUP_BEFORE_UPDATE:
440
441 /* There should always be a PDO extension passed in */
442 ASSERT(PdoExtension);
443
444 /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
445 if ((PdoExtension->VendorId == 0x1014) &&
446 (PdoExtension->DeviceId == 0x95))
447 {
448 /* Read the current command */
449 PciReadDeviceConfig(PdoExtension,
450 &Command,
451 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
452 sizeof(USHORT));
453
454 /* Turn off the decodes */
455 PciDecodeEnable(PdoExtension, FALSE, &Command);
456
457 /* Apply the required IBM workaround */
458 PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
459 RegValue &= ~2;
460 RegValue |= 1;
461 PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
462
463 /* Restore the command to its original value */
464 PciWriteDeviceConfig(PdoExtension,
465 &Command,
466 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
467 sizeof(USHORT));
468
469 }
470
471 /*
472 * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
473 * i820, i840, i845 Chipsets) that have subtractive decode enabled,
474 * and whose hack flags do not specifiy that this support is broken.
475 */
476 if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) &&
477 (PdoExtension->Dependent.type1.SubtractiveDecode) &&
478 ((PdoExtension->VendorId == 0x8086) &&
479 ((PdoExtension->DeviceId == 0x2418) ||
480 (PdoExtension->DeviceId == 0x2428) ||
481 (PdoExtension->DeviceId == 0x244E) ||
482 (PdoExtension->DeviceId == 0x2448))) &&
483 !(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
484 {
485 /*
486 * The positive decode window shouldn't be used, these values are
487 * normally all read-only or initialized to 0 by the BIOS, but
488 * it appears Intel doesn't do this, so the PCI Bus Driver will
489 * do it in software instead. Note that this is used to prevent
490 * certain non-compliant PCI devices from breaking down due to the
491 * fact that these ICH bridges have a known "quirk" (which Intel
492 * documents as a known "erratum", although it's not not really
493 * an ICH bug since the PCI specification does allow for it) in
494 * that they will sometimes send non-zero addresses during special
495 * cycles (ie: non-zero data during the address phase). These
496 * broken PCI cards will mistakenly attempt to claim the special
497 * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
498 * defense, the PCI specification only requires stable data, not
499 * necessarily zero data, during the address phase.
500 */
501 PciData->u.type1.MemoryBase = 0xFFFF;
502 PciData->u.type1.PrefetchBase = 0xFFFF;
503 PciData->u.type1.IOBase = 0xFF;
504 PciData->u.type1.IOLimit = 0;
505 PciData->u.type1.MemoryLimit = 0;
506 PciData->u.type1.PrefetchLimit = 0;
507 PciData->u.type1.PrefetchBaseUpper32 = 0;
508 PciData->u.type1.PrefetchLimitUpper32 = 0;
509 PciData->u.type1.IOBaseUpper16 = 0;
510 PciData->u.type1.IOLimitUpper16 = 0;
511 }
512 break;
513
514 default:
515 return;
516 }
517
518 /* Finally, also check if this is this a CardBUS device? */
519 if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
520 {
521 /*
522 * At offset 44h the LegacyBaseAddress is stored, which is cleared by
523 * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
524 * CardBus controllers. For more information, see "Supporting CardBus
525 * Controllers under ACPI" in the "CardBus Controllers and Windows"
526 * Whitepaper on WHDC.
527 */
528 LegacyBaseAddress = 0;
529 PciWriteDeviceConfig(PdoExtension,
530 &LegacyBaseAddress,
531 sizeof(PCI_COMMON_HEADER) + sizeof(ULONG),
532 sizeof(ULONG));
533 }
534 }
535
536 BOOLEAN
537 NTAPI
538 PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
539 IN PPCI_COMMON_HEADER PciData)
540 {
541 BOOLEAN IdMatch, RevMatch, SubsysMatch;
542 ULONGLONG HackFlags = DeviceExtension->HackFlags;
543
544 /* Check if the IDs match */
545 IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
546 (PciData->DeviceID == DeviceExtension->DeviceId);
547 if (!IdMatch) return FALSE;
548
549 /* If the device has a valid revision, check if it matches */
550 RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
551 (PciData->RevisionID == DeviceExtension->RevisionId);
552 if (!RevMatch) return FALSE;
553
554 /* For multifunction devices, this is enough to assume they're the same */
555 if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
556
557 /* For bridge devices, there's also nothing else that can be checked */
558 if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
559
560 /* Devices, on the other hand, have subsystem data that can be compared */
561 SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
562 PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
563 ((DeviceExtension->SubsystemVendorId ==
564 PciData->u.type0.SubVendorID) &&
565 (DeviceExtension->SubsystemId ==
566 PciData->u.type0.SubSystemID));
567 return SubsysMatch;
568 }
569
570 BOOLEAN
571 NTAPI
572 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
573 IN PCI_SLOT_NUMBER Slot,
574 IN UCHAR OperationType,
575 IN ULONGLONG HackFlags)
576 {
577 do
578 {
579 /* Check if this is device enumeration */
580 if (OperationType == PCI_SKIP_DEVICE_ENUMERATION)
581 {
582 /* Check if there's a hackflag saying not to enumerate this device */
583 if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
584
585 /* Check if this is the high end of a double decker device */
586 if ((HackFlags & PCI_HACK_DOUBLE_DECKER) &&
587 (Slot.u.bits.DeviceNumber >= 16))
588 {
589 /* It belongs to the same device, so skip it */
590 DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
591 PciData->VendorID,
592 PciData->DeviceID,
593 Slot.u.bits.DeviceNumber,
594 Slot.u.bits.FunctionNumber);
595 break;
596 }
597 }
598 else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)
599 {
600 /* Resource enumeration, check for a hackflag saying not to do it */
601 if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break;
602 }
603 else
604 {
605 /* Logic error in the driver */
606 ASSERTMSG(FALSE, "PCI Skip Function - Operation type unknown.");
607 }
608
609 /* Check for legacy bridges during resource enumeration */
610 if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
611 (PciData->SubClass <= PCI_SUBCLASS_BR_MCA) &&
612 (OperationType == PCI_SKIP_RESOURCE_ENUMERATION))
613 {
614 /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
615 break;
616 }
617 else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED)
618 {
619 /* Undefined base class (usually a PCI BIOS/ROM bug) */
620 DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
621 PciData->VendorID,
622 PciData->DeviceID);
623
624 /*
625 * The Alder has an Intel Extended Express System Support Controller
626 * which presents apparently spurious BARs. When the PCI resource
627 * code tries to reassign these BARs, the second IO-APIC gets
628 * disabled (with disastrous consequences). The first BAR is the
629 * actual IO-APIC, the remaining five bars seem to be spurious
630 * resources, so ignore this device completely.
631 */
632 if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break;
633 }
634
635 /* Other normal PCI cards and bridges are enumerated */
636 if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE;
637 } while (FALSE);
638
639 /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
640 DPRINT1(" Device skipped (not enumerated).\n");
641 return TRUE;
642 }
643
644 VOID
645 NTAPI
646 PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
647 IN PPCI_COMMON_HEADER PciData)
648 {
649 ULONG HeaderType, CapPtr, TargetAgpCapabilityId;
650 DEVICE_POWER_STATE WakeLevel;
651 PCI_CAPABILITIES_HEADER AgpCapability;
652 PCI_PM_CAPABILITY PowerCapabilities;
653 PAGED_CODE();
654
655 /* Assume no known wake level */
656 PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
657
658 /* Make sure the device has capabilities */
659 if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST))
660 {
661 /* If it doesn't, there will be no power management */
662 PdoExtension->CapabilitiesPtr = 0;
663 PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
664 }
665 else
666 {
667 /* There's capabilities, need to figure out where to get the offset */
668 HeaderType = PCI_CONFIGURATION_TYPE(PciData);
669 if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE)
670 {
671 /* Use the bridge's header */
672 CapPtr = PciData->u.type2.CapabilitiesPtr;
673 }
674 else
675 {
676 /* Use the device header */
677 ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE);
678 CapPtr = PciData->u.type0.CapabilitiesPtr;
679 }
680
681 /* Make sure the pointer is spec-aligned and located, and save it */
682 DPRINT1("Device has capabilities at: %lx\n", CapPtr);
683 ASSERT(((CapPtr & 0x3) == 0) && (CapPtr >= PCI_COMMON_HDR_LENGTH));
684 PdoExtension->CapabilitiesPtr = CapPtr;
685
686 /* Check for PCI-to-PCI Bridges and AGP bridges */
687 if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
688 ((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) ||
689 (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)))
690 {
691 /* Query either the raw AGP capabilitity, or the Target AGP one */
692 TargetAgpCapabilityId = (PdoExtension->SubClass ==
693 PCI_SUBCLASS_BR_PCI_TO_PCI) ?
694 PCI_CAPABILITY_ID_AGP_TARGET :
695 PCI_CAPABILITY_ID_AGP;
696 if (PciReadDeviceCapability(PdoExtension,
697 PdoExtension->CapabilitiesPtr,
698 TargetAgpCapabilityId,
699 &AgpCapability,
700 sizeof(PCI_CAPABILITIES_HEADER)))
701 {
702 /* AGP target ID was found, store it */
703 DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId);
704 PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId;
705 }
706 }
707
708 /* Check for devices that are known not to have proper power management */
709 if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
710 {
711 /* Query if this device supports power management */
712 if (!PciReadDeviceCapability(PdoExtension,
713 PdoExtension->CapabilitiesPtr,
714 PCI_CAPABILITY_ID_POWER_MANAGEMENT,
715 &PowerCapabilities.Header,
716 sizeof(PCI_PM_CAPABILITY)))
717 {
718 /* No power management, so act as if it had the hackflag set */
719 DPRINT1("No PM caps, disabling PM\n");
720 PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
721 }
722 else
723 {
724 /* Otherwise, pick the highest wake level that is supported */
725 WakeLevel = PowerDeviceUnspecified;
726 if (PowerCapabilities.PMC.Capabilities.Support.PMED0)
727 WakeLevel = PowerDeviceD0;
728 if (PowerCapabilities.PMC.Capabilities.Support.PMED1)
729 WakeLevel = PowerDeviceD1;
730 if (PowerCapabilities.PMC.Capabilities.Support.PMED2)
731 WakeLevel = PowerDeviceD2;
732 if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot)
733 WakeLevel = PowerDeviceD3;
734 if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold)
735 WakeLevel = PowerDeviceD3;
736 PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
737
738 /* Convert the PCI power state to the NT power state */
739 PdoExtension->PowerState.CurrentDeviceState =
740 PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
741
742 /* Save all the power capabilities */
743 PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities;
744 DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
745 WakeLevel, PdoExtension->PowerState.CurrentDeviceState);
746 }
747 }
748 }
749
750 /* At the very end of all this, does this device not have power management? */
751 if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
752 {
753 /* Then guess the current state based on whether the decodes are on */
754 PdoExtension->PowerState.CurrentDeviceState =
755 PciData->Command & (PCI_ENABLE_IO_SPACE |
756 PCI_ENABLE_MEMORY_SPACE |
757 PCI_ENABLE_BUS_MASTER) ?
758 PowerDeviceD0: PowerDeviceD3;
759 DPRINT1("PM is off, so assumed device is: %d based on enables\n",
760 PdoExtension->PowerState.CurrentDeviceState);
761 }
762 }
763
764 VOID
765 NTAPI
766 PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved,
767 IN PPCI_CONFIGURATOR_CONTEXT Context)
768 {
769 PPCI_COMMON_HEADER PciData, Current;
770 PPCI_PDO_EXTENSION PdoExtension;
771
772 /* Grab all parameters from the context */
773 PdoExtension = Context->PdoExtension;
774 Current = Context->Current;
775 PciData = Context->PciData;
776
777 /* Write the limit discovery header */
778 PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
779
780 /* Now read what the device indicated the limits are */
781 PciReadDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
782
783 /* Then write back the original configuration header */
784 PciWriteDeviceConfig(PdoExtension, Current, 0, PCI_COMMON_HDR_LENGTH);
785
786 /* Copy back the original command that was saved in the context */
787 Current->Command = Context->Command;
788 if (Context->Command)
789 {
790 /* Program it back into the device */
791 PciWriteDeviceConfig(PdoExtension,
792 &Context->Command,
793 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
794 sizeof(USHORT));
795 }
796
797 /* Copy back the original status that was saved as well */
798 Current->Status = Context->Status;
799
800 /* Call the configurator to restore any other data that might've changed */
801 Context->Configurator->RestoreCurrent(Context);
802 }
803
804 NTSTATUS
805 NTAPI
806 PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
807 {
808 PPCI_CONFIGURATOR Configurator;
809 PPCI_COMMON_HEADER PciData, Current;
810 PPCI_PDO_EXTENSION PdoExtension;
811 PCI_IPI_CONTEXT IpiContext;
812 PIO_RESOURCE_DESCRIPTOR IoDescriptor;
813 ULONG Offset;
814 PAGED_CODE();
815
816 /* Grab all parameters from the context */
817 PdoExtension = Context->PdoExtension;
818 Current = Context->Current;
819 PciData = Context->PciData;
820
821 /* Save the current PCI Command and Status word */
822 Context->Status = Current->Status;
823 Context->Command = Current->Command;
824
825 /* Now that they're saved, clear the status, and disable all decodes */
826 Current->Status = 0;
827 Current->Command &= ~(PCI_ENABLE_IO_SPACE |
828 PCI_ENABLE_MEMORY_SPACE |
829 PCI_ENABLE_BUS_MASTER);
830
831 /* Make a copy of the current PCI configuration header (with decodes off) */
832 RtlCopyMemory(PciData, Current, PCI_COMMON_HDR_LENGTH);
833
834 /* Locate the correct resource configurator for this type of device */
835 Configurator = &PciConfigurators[PdoExtension->HeaderType];
836 Context->Configurator = Configurator;
837
838 /* Initialize it, which will typically setup the BARs for limit discovery */
839 Configurator->Initialize(Context);
840
841 /* Check for critical devices and PCI Debugging devices */
842 if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
843 (PdoExtension->OnDebugPath))
844 {
845 /* Specifically check for a PCI Debugging device */
846 if (PdoExtension->OnDebugPath)
847 {
848 /* Was it enabled for bus mastering? */
849 if (Context->Command & PCI_ENABLE_BUS_MASTER)
850 {
851 /* This decode needs to be re-enabled so debugging can work */
852 PciData->Command |= PCI_ENABLE_BUS_MASTER;
853 Current->Command |= PCI_ENABLE_BUS_MASTER;
854 }
855
856 /* Disable the debugger while the discovery is happening */
857 KdDisableDebugger();
858 }
859
860 /* For these devices, an IPI must be sent to force high-IRQL discovery */
861 IpiContext.Barrier = 1;
862 IpiContext.RunCount = 1;
863 IpiContext.PdoExtension = PdoExtension;
864 IpiContext.Function = PciWriteLimitsAndRestoreCurrent;
865 IpiContext.Context = Context;
866 KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&IpiContext);
867
868 /* Re-enable the debugger if this was a PCI Debugging Device */
869 if (PdoExtension->OnDebugPath) KdEnableDebugger();
870 }
871 else
872 {
873 /* Otherwise, it's safe to do this in-line at low IRQL */
874 PciWriteLimitsAndRestoreCurrent(PdoExtension, Context);
875 }
876
877 /*
878 * Check if it's valid to compare the headers to see if limit discovery mode
879 * has properly exited (the expected case is that the PCI header would now
880 * be equal to what it was before). In some cases, it is known that this will
881 * fail, because during PciApplyHacks (among other places), software hacks
882 * had to be applied to the header, which the hardware-side will not see, and
883 * thus the headers would appear "different".
884 */
885 if (!PdoExtension->ExpectedWritebackFailure)
886 {
887 /* Read the current PCI header now, after discovery has completed */
888 PciReadDeviceConfig(PdoExtension, PciData + 1, 0, PCI_COMMON_HDR_LENGTH);
889
890 /* Check if the current header at entry, is equal to the header now */
891 Offset = RtlCompareMemory(PciData + 1, Current, PCI_COMMON_HDR_LENGTH);
892 if (Offset != PCI_COMMON_HDR_LENGTH)
893 {
894 /* It's not, which means configuration somehow changed, dump this */
895 DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset);
896 PciDebugDumpCommonConfig(PciData + 1);
897 DPRINT1("----------\n");
898 PciDebugDumpCommonConfig(Current);
899 }
900 }
901
902 /* This PDO should not already have resources, since this is only done once */
903 ASSERT(PdoExtension->Resources == NULL);
904
905 /* Allocate the structure that will hold the discovered resources and limits */
906 PdoExtension->Resources = ExAllocatePoolWithTag(NonPagedPool,
907 sizeof(PCI_FUNCTION_RESOURCES),
908 'BicP');
909 if (!PdoExtension->Resources) return STATUS_INSUFFICIENT_RESOURCES;
910
911 /* Clear it out for now */
912 RtlZeroMemory(PdoExtension->Resources, sizeof(PCI_FUNCTION_RESOURCES));
913
914 /* Now call the configurator, which will first store the limits... */
915 Configurator->SaveLimits(Context);
916
917 /* ...and then store the current resources being used */
918 Configurator->SaveCurrentSettings(Context);
919
920 /* Loop all the limit descriptors backwards */
921 IoDescriptor = &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1];
922 while (TRUE)
923 {
924 /* Keep going until a non-null descriptor is found */
925 IoDescriptor--;
926 if (IoDescriptor->Type != CmResourceTypeNull) break;
927
928 /* This is a null descriptor, is it the last one? */
929 if (IoDescriptor == &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1])
930 {
931 /* This means the descriptor is NULL, which means discovery failed */
932 DPRINT1("PCI Resources fail!\n");
933
934 /* No resources will be assigned for the device */
935 ExFreePoolWithTag(PdoExtension->Resources, 0);
936 PdoExtension->Resources = NULL;
937 break;
938 }
939 }
940
941 /* Return success here, even if the device has no assigned resources */
942 return STATUS_SUCCESS;
943 }
944
945 NTSTATUS
946 NTAPI
947 PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension,
948 IN PPCI_COMMON_HEADER Current,
949 IN ULONGLONG HackFlags)
950 {
951 NTSTATUS Status;
952 PPCI_COMMON_HEADER PciData;
953 PCI_CONFIGURATOR_CONTEXT Context;
954 PAGED_CODE();
955
956 /* Do the hackflags indicate this device should be skipped? */
957 if (PciSkipThisFunction(Current,
958 PdoExtension->Slot,
959 PCI_SKIP_RESOURCE_ENUMERATION,
960 HackFlags))
961 {
962 /* Do not process its resources */
963 return STATUS_SUCCESS;
964 }
965
966 /* Allocate a buffer to hold two PCI configuration headers */
967 PciData = ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH, 'BicP');
968 if (!PciData) return STATUS_INSUFFICIENT_RESOURCES;
969
970 /* Set up the context for the resource enumeration, and do it */
971 Context.Current = Current;
972 Context.PciData = PciData;
973 Context.PdoExtension = PdoExtension;
974 Status = PcipGetFunctionLimits(&Context);
975
976 /* Enumeration is completed, free the PCI headers and return the status */
977 ExFreePoolWithTag(PciData, 0);
978 return Status;
979 }
980
981 VOID
982 NTAPI
983 PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension)
984 {
985 PPCI_PDO_EXTENSION PdoExtension;
986 PDEVICE_OBJECT PhysicalDeviceObject;
987 PAGED_CODE();
988
989 /* Get the PDO Extension */
990 PhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject;
991 PdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
992
993 /* Cheeck if this is the root bus */
994 if (!PCI_IS_ROOT_FDO(DeviceExtension))
995 {
996 /* Not really handling this year */
997 UNIMPLEMENTED;
998 while (TRUE);
999
1000 /* Check for PCI bridges with the ISA bit set, or required */
1001 if ((PdoExtension) &&
1002 (PciClassifyDeviceType(PdoExtension) == PciTypePciBridge) &&
1003 ((PdoExtension->Dependent.type1.IsaBitRequired) ||
1004 (PdoExtension->Dependent.type1.IsaBitSet)))
1005 {
1006 /* We'll need to do some legacy support */
1007 UNIMPLEMENTED;
1008 while (TRUE);
1009 }
1010 }
1011 else
1012 {
1013 /* Scan all of the root bus' children bridges */
1014 for (PdoExtension = DeviceExtension->ChildBridgePdoList;
1015 PdoExtension;
1016 PdoExtension = PdoExtension->NextBridge)
1017 {
1018 /* Find any that have the VGA decode bit on */
1019 if (PdoExtension->Dependent.type1.VgaBitSet)
1020 {
1021 /* Again, some more legacy support we'll have to do */
1022 UNIMPLEMENTED;
1023 while (TRUE);
1024 }
1025 }
1026 }
1027
1028 /* Check for ACPI systems where the OS assigns bus numbers */
1029 if (PciAssignBusNumbers)
1030 {
1031 /* Not yet supported */
1032 UNIMPLEMENTED;
1033 while (TRUE);
1034 }
1035 }
1036
1037 NTSTATUS
1038 NTAPI
1039 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
1040 {
1041 ULONG MaxDevice = PCI_MAX_DEVICES;
1042 BOOLEAN ProcessFlag = FALSE;
1043 ULONG i, j, k, Size;
1044 USHORT CapOffset, TempOffset;
1045 LONGLONG HackFlags;
1046 PDEVICE_OBJECT DeviceObject;
1047 UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
1048 UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
1049 PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
1050 PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
1051 PCI_SLOT_NUMBER PciSlot;
1052 PCHAR Name;
1053 NTSTATUS Status;
1054 PPCI_PDO_EXTENSION PdoExtension, NewExtension;
1055 PPCI_PDO_EXTENSION* BridgeExtension;
1056 PWCHAR DescriptionText;
1057 USHORT SubVendorId, SubSystemId;
1058 PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader;
1059 DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
1060 DeviceExtension, DeviceExtension->BaseBus);
1061
1062 /* Is this the root FDO? */
1063 if (!PCI_IS_ROOT_FDO(DeviceExtension))
1064 {
1065 /* Other FDOs are not currently supported */
1066 UNIMPLEMENTED;
1067 while (TRUE);
1068 }
1069
1070 /* Loop every device on the bus */
1071 PciSlot.u.bits.Reserved = 0;
1072 i = DeviceExtension->BaseBus;
1073 for (j = 0; j < MaxDevice; j++)
1074 {
1075 /* Loop every function of each device */
1076 PciSlot.u.bits.DeviceNumber = j;
1077 for (k = 0; k < PCI_MAX_FUNCTION; k++)
1078 {
1079 /* Build the final slot structure */
1080 PciSlot.u.bits.FunctionNumber = k;
1081
1082 /* Read the vendor for this slot */
1083 PciReadSlotConfig(DeviceExtension,
1084 PciSlot,
1085 PciData,
1086 0,
1087 sizeof(USHORT));
1088
1089 /* Skip invalid device */
1090 if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
1091
1092 /* Now read the whole header */
1093 PciReadSlotConfig(DeviceExtension,
1094 PciSlot,
1095 &PciData->DeviceID,
1096 sizeof(USHORT),
1097 PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
1098
1099 /* Apply any hacks before even analyzing the configuration header */
1100 PciApplyHacks(DeviceExtension,
1101 PciData,
1102 PciSlot,
1103 PCI_HACK_FIXUP_BEFORE_CONFIGURATION,
1104 NULL);
1105
1106 /* Dump device that was found */
1107 DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
1108 PciSlot.u.AsULONG,
1109 i,
1110 j,
1111 k);
1112
1113 /* Dump the device's header */
1114 PciDebugDumpCommonConfig(PciData);
1115
1116 /* Find description for this device for the debugger's sake */
1117 DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
1118 PciData->SubClass);
1119 DPRINT1("Device Description \"%S\".\n",
1120 DescriptionText ? DescriptionText : L"(NULL)");
1121 if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
1122
1123 /* Check if there is an ACPI Watchdog Table */
1124 if (WdTable)
1125 {
1126 /* Check if this PCI device is the ACPI Watchdog Device... */
1127 UNIMPLEMENTED;
1128 while (TRUE);
1129 }
1130
1131 /* Check for non-simple devices */
1132 if ((PCI_MULTIFUNCTION_DEVICE(PciData)) ||
1133 (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV))
1134 {
1135 /* No subsystem data defined for these kinds of bridges */
1136 SubVendorId = 0;
1137 SubSystemId = 0;
1138 }
1139 else
1140 {
1141 /* Read the subsystem information from the PCI header */
1142 SubVendorId = PciData->u.type0.SubVendorID;
1143 SubSystemId = PciData->u.type0.SubSystemID;
1144 }
1145
1146 /* Get any hack flags for this device */
1147 HackFlags = PciGetHackFlags(PciData->VendorID,
1148 PciData->DeviceID,
1149 SubVendorId,
1150 SubSystemId,
1151 PciData->RevisionID);
1152
1153 /* Check if this device is considered critical by the OS */
1154 if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass))
1155 {
1156 /* Check if normally the decodes would be disabled */
1157 if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
1158 {
1159 /* Because this device is critical, don't disable them */
1160 DPRINT1("Not allowing PM Because device is critical\n");
1161 HackFlags |= PCI_HACK_CRITICAL_DEVICE;
1162 }
1163 }
1164
1165 /* PCI bridges with a VGA card are also considered critical */
1166 if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1167 (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) &&
1168 (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) &&
1169 !(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
1170 {
1171 /* Do not disable their decodes either */
1172 DPRINT1("Not allowing PM because device is VGA\n");
1173 HackFlags |= PCI_HACK_CRITICAL_DEVICE;
1174 }
1175
1176 /* Check if the device should be skipped for whatever reason */
1177 if (PciSkipThisFunction(PciData,
1178 PciSlot,
1179 PCI_SKIP_DEVICE_ENUMERATION,
1180 HackFlags))
1181 {
1182 /* Skip this device */
1183 continue;
1184 }
1185
1186 /* Check if a PDO has already been created for this device */
1187 PdoExtension = PciFindPdoByFunction(DeviceExtension,
1188 PciSlot.u.AsULONG,
1189 PciData);
1190 if (PdoExtension)
1191 {
1192 /* Rescan scenarios are not yet implemented */
1193 UNIMPLEMENTED;
1194 while (TRUE);
1195 }
1196
1197 /* Bus processing will need to happen */
1198 ProcessFlag = TRUE;
1199
1200 /* Create the PDO for this device */
1201 Status = PciPdoCreate(DeviceExtension, PciSlot, &DeviceObject);
1202 ASSERT(NT_SUCCESS(Status));
1203 NewExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
1204
1205 /* Check for broken devices with wrong/no class codes */
1206 if (HackFlags & PCI_HACK_FAKE_CLASS_CODE)
1207 {
1208 /* Setup a default one */
1209 PciData->BaseClass = PCI_CLASS_BASE_SYSTEM_DEV;
1210 PciData->SubClass = PCI_SUBCLASS_SYS_OTHER;
1211
1212 /* Device will behave erratically when reading back data */
1213 NewExtension->ExpectedWritebackFailure = TRUE;
1214 }
1215
1216 /* Clone all the information from the header */
1217 NewExtension->VendorId = PciData->VendorID;
1218 NewExtension->DeviceId = PciData->DeviceID;
1219 NewExtension->RevisionId = PciData->RevisionID;
1220 NewExtension->ProgIf = PciData->ProgIf;
1221 NewExtension->SubClass = PciData->SubClass;
1222 NewExtension->BaseClass = PciData->BaseClass;
1223 NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
1224
1225 /* Check for modern bridge types, which are managed by the driver */
1226 if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1227 ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
1228 (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
1229 {
1230 /* Acquire this device's lock */
1231 KeEnterCriticalRegion();
1232 KeWaitForSingleObject(&DeviceExtension->ChildListLock,
1233 Executive,
1234 KernelMode,
1235 FALSE,
1236 NULL);
1237
1238 /* Scan the bridge list until the first free entry */
1239 for (BridgeExtension = &DeviceExtension->ChildBridgePdoList;
1240 *BridgeExtension;
1241 BridgeExtension = &(*BridgeExtension)->NextBridge);
1242
1243 /* Add this PDO as a bridge */
1244 *BridgeExtension = NewExtension;
1245 ASSERT(NewExtension->NextBridge == NULL);
1246
1247 /* Release this device's lock */
1248 KeSetEvent(&DeviceExtension->ChildListLock,
1249 IO_NO_INCREMENT,
1250 FALSE);
1251 KeLeaveCriticalRegion();
1252 }
1253
1254 /* Get the PCI BIOS configuration saved in the registry */
1255 Status = PciGetBiosConfig(NewExtension, BiosData);
1256 if (NT_SUCCESS(Status))
1257 {
1258 /* This path has not yet been fully tested by eVb */
1259 DPRINT1("Have BIOS configuration!\n");
1260 UNIMPLEMENTED;
1261
1262 /* Check if the PCI BIOS configuration has changed */
1263 if (!PcipIsSameDevice(NewExtension, BiosData))
1264 {
1265 /* This is considered failure, and new data will be saved */
1266 Status = STATUS_UNSUCCESSFUL;
1267 }
1268 else
1269 {
1270 /* Data is still correct, check for interrupt line change */
1271 if (BiosData->u.type0.InterruptLine !=
1272 PciData->u.type0.InterruptLine)
1273 {
1274 /* Update the current BIOS with the saved interrupt line */
1275 PciWriteDeviceConfig(NewExtension,
1276 &BiosData->u.type0.InterruptLine,
1277 FIELD_OFFSET(PCI_COMMON_HEADER,
1278 u.type0.InterruptLine),
1279 sizeof(UCHAR));
1280 }
1281
1282 /* Save the BIOS interrupt line and the initial command */
1283 NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
1284 NewExtension->InitialCommand = BiosData->Command;
1285 }
1286 }
1287
1288 /* Check if no saved data was present or if it was a mismatch */
1289 if (!NT_SUCCESS(Status))
1290 {
1291 /* Save the new data */
1292 Status = PciSaveBiosConfig(NewExtension, PciData);
1293 ASSERT(NT_SUCCESS(Status));
1294
1295 /* Save the interrupt line and command from the device */
1296 NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
1297 NewExtension->InitialCommand = PciData->Command;
1298 }
1299
1300 /* Save original command from the device and hack flags */
1301 NewExtension->CommandEnables = PciData->Command;
1302 NewExtension->HackFlags = HackFlags;
1303
1304 /* Get power, AGP, and other capability data */
1305 PciGetEnhancedCapabilities(NewExtension, PciData);
1306
1307 /* Now configure the BARs */
1308 Status = PciGetFunctionLimits(NewExtension, PciData, HackFlags);
1309
1310 /* Power up the device */
1311 PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
1312
1313 /* Apply any device hacks required for enumeration */
1314 PciApplyHacks(DeviceExtension,
1315 PciData,
1316 PciSlot,
1317 PCI_HACK_FIXUP_AFTER_CONFIGURATION,
1318 NewExtension);
1319
1320 /* Save interrupt pin */
1321 NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
1322
1323 /*
1324 * Use either this device's actual IRQ line or, if it's connected on
1325 * a master bus whose IRQ line is actually connected to the host, use
1326 * the HAL to query the bus' IRQ line and store that as the adjusted
1327 * interrupt line instead
1328 */
1329 NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
1330
1331 /* Check if this device is used for PCI debugger cards */
1332 NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
1333
1334 /* Check for devices with invalid/bogus subsystem data */
1335 if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
1336 {
1337 /* Set the subsystem information to zero instead */
1338 NewExtension->SubsystemVendorId = 0;
1339 NewExtension->SubsystemId = 0;
1340 }
1341
1342 /* Scan all capabilities */
1343 CapOffset = NewExtension->CapabilitiesPtr;
1344 while (CapOffset)
1345 {
1346 /* Read this header */
1347 TempOffset = PciReadDeviceCapability(NewExtension,
1348 CapOffset,
1349 0,
1350 &CapHeader,
1351 sizeof(PCI_CAPABILITIES_HEADER));
1352 if (TempOffset != CapOffset)
1353 {
1354 /* This is a strange issue that shouldn't happen normally */
1355 DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
1356 CapOffset);
1357 ASSERT(TempOffset == CapOffset);
1358 }
1359
1360 /* Check for capabilities that this driver cares about */
1361 switch (CapHeader.CapabilityID)
1362 {
1363 /* Power management capability is heavily used by the bus */
1364 case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
1365
1366 /* Dump the capability */
1367 Name = "POWER";
1368 Size = sizeof(PCI_PM_CAPABILITY);
1369 break;
1370
1371 /* AGP capability is required for AGP bus functionality */
1372 case PCI_CAPABILITY_ID_AGP:
1373
1374 /* Dump the capability */
1375 Name = "AGP";
1376 Size = sizeof(PCI_AGP_CAPABILITY);
1377 break;
1378
1379 /* This driver doesn't really use anything other than that */
1380 default:
1381
1382 /* Windows prints this, we could do a translation later */
1383 Name = "UNKNOWN CAPABILITY";
1384 Size = 0;
1385 break;
1386 }
1387
1388 /* Check if this is a capability that should be dumped */
1389 if (Size)
1390 {
1391 /* Read the whole capability data */
1392 TempOffset = PciReadDeviceCapability(NewExtension,
1393 CapOffset,
1394 CapHeader.CapabilityID,
1395 &CapHeader,
1396 Size);
1397
1398 if (TempOffset != CapOffset)
1399 {
1400 /* Again, a strange issue that shouldn't be seen */
1401 DPRINT1("- Failed to read capability data. ***\n");
1402 ASSERT(TempOffset == CapOffset);
1403 }
1404 }
1405
1406 /* Dump this capability */
1407 DPRINT1("CAP @%02x ID %02x (%s)\n",
1408 CapOffset, CapHeader.CapabilityID, Name);
1409 for (i = 0; i < Size; i += 2)
1410 DPRINT1(" %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i));
1411 DPRINT1("\n");
1412
1413 /* Check the next capability */
1414 CapOffset = CapHeader.Next;
1415 }
1416
1417 /* Check for IDE controllers */
1418 if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
1419 (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
1420 {
1421 /* Do not allow them to power down completely */
1422 NewExtension->DisablePowerDown = TRUE;
1423 }
1424
1425 /*
1426 * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
1427 * bridge that is present on certain NT Alpha machines appears as
1428 * non-classified so detect it manually by scanning for its VID/PID.
1429 */
1430 if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1431 ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
1432 (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
1433 (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
1434 ((NewExtension->VendorId == 0x8086) &&
1435 (NewExtension->DeviceId == 0x482)))
1436 {
1437 /* Do not allow these legacy bridges to be powered down */
1438 NewExtension->DisablePowerDown = TRUE;
1439 }
1440
1441 /* Check if the BIOS did not configure a cache line size */
1442 if (!PciData->CacheLineSize)
1443 {
1444 /* Check if the device is disabled */
1445 if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE |
1446 PCI_ENABLE_MEMORY_SPACE |
1447 PCI_ENABLE_BUS_MASTER)))
1448 {
1449 /* Check if this is a PCI-X device*/
1450 TempOffset = PciReadDeviceCapability(NewExtension,
1451 NewExtension->CapabilitiesPtr,
1452 PCI_CAPABILITY_ID_PCIX,
1453 &PcixCapHeader,
1454 sizeof(PCI_CAPABILITIES_HEADER));
1455
1456 /*
1457 * A device with default cache line size and latency timer
1458 * settings is considered to be unconfigured. Note that on
1459 * PCI-X, the reset value of the latency timer field in the
1460 * header is 64, not 0, hence why the check for PCI-X caps
1461 * was required, and the value used here below.
1462 */
1463 if (!(PciData->LatencyTimer) ||
1464 ((TempOffset) && (PciData->LatencyTimer == 64)))
1465 {
1466 /* Keep track of the fact that it needs configuration */
1467 DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
1468 NewExtension);
1469 NewExtension->NeedsHotPlugConfiguration = TRUE;
1470 }
1471 }
1472 }
1473
1474 /* Save latency and cache size information */
1475 NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
1476 NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
1477
1478 /* The PDO is now ready to go */
1479 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1480 }
1481 }
1482
1483 /* Enumeration completed, do a final pass now that all devices are found */
1484 if (ProcessFlag) PciProcessBus(DeviceExtension);
1485 return STATUS_SUCCESS;
1486 }
1487
1488 NTSTATUS
1489 NTAPI
1490 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,
1491 IN OUT PDEVICE_RELATIONS *pDeviceRelations)
1492 {
1493 NTSTATUS Status;
1494 PPCI_PDO_EXTENSION PdoExtension;
1495 ULONG PdoCount = 0;
1496 PDEVICE_RELATIONS DeviceRelations, NewRelations;
1497 SIZE_T Size;
1498 PDEVICE_OBJECT DeviceObject, *ObjectArray;
1499 PAGED_CODE();
1500
1501 /* Make sure the FDO is started */
1502 ASSERT(DeviceExtension->DeviceState == PciStarted);
1503
1504 /* Synchronize while we enumerate the bus */
1505 Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation);
1506 if (!NT_SUCCESS(Status)) return Status;
1507
1508 /* Scan all children PDO */
1509 for (PdoExtension = DeviceExtension->ChildPdoList;
1510 PdoExtension;
1511 PdoExtension = PdoExtension->Next)
1512 {
1513 /* Invalidate them */
1514 PdoExtension->NotPresent = TRUE;
1515 }
1516
1517 /* Scan the PCI Bus */
1518 Status = PciScanBus(DeviceExtension);
1519 ASSERT(NT_SUCCESS(Status));
1520
1521 /* Enumerate all children PDO again */
1522 for (PdoExtension = DeviceExtension->ChildPdoList;
1523 PdoExtension;
1524 PdoExtension = PdoExtension->Next)
1525 {
1526 /* Check for PDOs that are still invalidated */
1527 if (PdoExtension->NotPresent)
1528 {
1529 /* This means this PDO existed before, but not anymore */
1530 PdoExtension->ReportedMissing = TRUE;
1531 DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
1532 PdoExtension);
1533 }
1534 else
1535 {
1536 /* Increase count of detected PDOs */
1537 PdoCount++;
1538 }
1539 }
1540
1541 /* Read the current relations and add the newly discovered relations */
1542 DeviceRelations = *pDeviceRelations;
1543 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
1544 PdoCount * sizeof(PDEVICE_OBJECT);
1545 if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
1546
1547 /* Allocate the device relations */
1548 NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP');
1549 if (!NewRelations)
1550 {
1551 /* Out of space, cancel the operation */
1552 PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation);
1553 return STATUS_INSUFFICIENT_RESOURCES;
1554 }
1555
1556 /* Check if there were any older relations */
1557 NewRelations->Count = 0;
1558 if (DeviceRelations)
1559 {
1560 /* Copy the old relations into the new buffer, then free the old one */
1561 RtlCopyMemory(NewRelations,
1562 DeviceRelations,
1563 FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
1564 DeviceRelations->Count * sizeof(PDEVICE_OBJECT));
1565 ExFreePoolWithTag(DeviceRelations, 0);
1566 }
1567
1568 /* Print out that we're ready to dump relations */
1569 DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
1570 DeviceExtension,
1571 DeviceExtension->BaseBus);
1572
1573 /* Loop the current PDO children and the device relation object array */
1574 PdoExtension = DeviceExtension->ChildPdoList;
1575 ObjectArray = &NewRelations->Objects[NewRelations->Count];
1576 while (PdoExtension)
1577 {
1578 /* Dump this relation */
1579 DPRINT1(" QDR PDO %08x (x %08x)%s\n",
1580 PdoExtension->PhysicalDeviceObject,
1581 PdoExtension,
1582 PdoExtension->NotPresent ?
1583 "<Omitted, device flaged not present>" : "");
1584
1585 /* Is this PDO present? */
1586 if (!PdoExtension->NotPresent)
1587 {
1588 /* Reference it and add it to the array */
1589 DeviceObject = PdoExtension->PhysicalDeviceObject;
1590 ObfReferenceObject(DeviceObject);
1591 *ObjectArray++ = DeviceObject;
1592 }
1593
1594 /* Go to the next PDO */
1595 PdoExtension = PdoExtension->Next;
1596 }
1597
1598 /* Terminate dumping the relations */
1599 DPRINT1(" QDR Total PDO count = %d (%d already in list)\n",
1600 NewRelations->Count + PdoCount,
1601 NewRelations->Count);
1602
1603 /* Return the final count and the new buffer */
1604 NewRelations->Count += PdoCount;
1605 *pDeviceRelations = NewRelations;
1606 return STATUS_SUCCESS;
1607 }
1608
1609 /* EOF */