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