xref: /reactos/drivers/bus/pcix/enum.c (revision 34593d93)
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 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements;
19 
20 PCI_CONFIGURATOR PciConfigurators[] =
21 {
22     {
23         Device_MassageHeaderForLimitsDetermination,
24         Device_RestoreCurrent,
25         Device_SaveLimits,
26         Device_SaveCurrentSettings,
27         Device_ChangeResourceSettings,
28         Device_GetAdditionalResourceDescriptors,
29         Device_ResetDevice
30     },
31     {
32         PPBridge_MassageHeaderForLimitsDetermination,
33         PPBridge_RestoreCurrent,
34         PPBridge_SaveLimits,
35         PPBridge_SaveCurrentSettings,
36         PPBridge_ChangeResourceSettings,
37         PPBridge_GetAdditionalResourceDescriptors,
38         PPBridge_ResetDevice
39     },
40     {
41         Cardbus_MassageHeaderForLimitsDetermination,
42         Cardbus_RestoreCurrent,
43         Cardbus_SaveLimits,
44         Cardbus_SaveCurrentSettings,
45         Cardbus_ChangeResourceSettings,
46         Cardbus_GetAdditionalResourceDescriptors,
47         Cardbus_ResetDevice
48     }
49 };
50 
51 /* FUNCTIONS ******************************************************************/
52 
53 BOOLEAN
54 NTAPI
PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,IN PCM_RESOURCE_LIST ResourceList)55 PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
56                              IN PCM_RESOURCE_LIST ResourceList)
57 {
58     PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, InterruptResource;
59     PCM_PARTIAL_RESOURCE_DESCRIPTOR BaseResource, CurrentDescriptor;
60     PCM_PARTIAL_RESOURCE_DESCRIPTOR PreviousDescriptor;
61     CM_PARTIAL_RESOURCE_DESCRIPTOR ResourceArray[7];
62     PCM_FULL_RESOURCE_DESCRIPTOR FullList;
63     BOOLEAN DrainPartial, RangeChange;
64     ULONG i, j;
65     PPCI_FUNCTION_RESOURCES PciResources;
66     PAGED_CODE();
67 
68     /* Make sure we have either no resources, or at least one */
69     ASSERT((ResourceList == NULL) || (ResourceList->Count == 1));
70 
71     /* Initialize no partial, interrupt descriptor, or range change */
72     Partial = NULL;
73     InterruptResource = NULL;
74     RangeChange = FALSE;
75 
76     /* Check if there's not actually any resources */
77     if (!(ResourceList) || !(ResourceList->Count))
78     {
79         /* Then just return the hardware update state */
80         return PdoExtension->UpdateHardware;
81     }
82 
83     /* Print the new specified resource list */
84     PciDebugPrintCmResList(ResourceList);
85 
86     /* Clear the temporary resource array */
87     for (i = 0; i < 7; i++) ResourceArray[i].Type = CmResourceTypeNull;
88 
89     /* Loop the full resource descriptor */
90     FullList = ResourceList->List;
91     for (i = 0; i < ResourceList->Count; i++)
92     {
93         /* Initialize loop variables */
94         DrainPartial = FALSE;
95         BaseResource = NULL;
96 
97         /* Loop the partial descriptors */
98         Partial = FullList->PartialResourceList.PartialDescriptors;
99         for (j = 0; j < FullList->PartialResourceList.Count; j++)
100         {
101             /* Check if we were supposed to drain a partial due to device data */
102             if (DrainPartial)
103             {
104                 /* Draining complete, move on to the next descriptor then */
105                 DrainPartial--;
106                 continue;
107             }
108 
109             /* Check what kind of descriptor this was */
110             switch (Partial->Type)
111             {
112                 /* Base BAR resources */
113                 case CmResourceTypePort:
114                 case CmResourceTypeMemory:
115 
116                     /* Set it as the base */
117                     ASSERT(BaseResource == NULL);
118                     BaseResource = Partial;
119                     break;
120 
121                 /* Interrupt resource */
122                 case CmResourceTypeInterrupt:
123 
124                     /* Make sure it's a compatible (and the only) PCI interrupt */
125                     ASSERT(InterruptResource == NULL);
126                     ASSERT(Partial->u.Interrupt.Level == Partial->u.Interrupt.Vector);
127                     InterruptResource = Partial;
128 
129                     /* Only 255 interrupts on x86/x64 hardware */
130                     if (Partial->u.Interrupt.Level < 256)
131                     {
132                         /* Use the passed interrupt line */
133                         PdoExtension->AdjustedInterruptLine = Partial->u.Interrupt.Level;
134                     }
135                     else
136                     {
137                         /* Invalid vector, so ignore it */
138                         PdoExtension->AdjustedInterruptLine = 0;
139                     }
140 
141                     break;
142 
143                 /* Check for specific device data */
144                 case CmResourceTypeDevicePrivate:
145 
146                     /* Check what kind of data this was */
147                     switch (Partial->u.DevicePrivate.Data[0])
148                     {
149                         /* Not used in the driver yet */
150                         case 1:
151                             UNIMPLEMENTED_DBGBREAK();
152                             break;
153 
154                         /* Not used in the driver yet */
155                         case 2:
156                             UNIMPLEMENTED_DBGBREAK();
157                             break;
158 
159                         /* A drain request */
160                         case 3:
161                             /* Shouldn't be a base resource, this is a drain */
162                             ASSERT(BaseResource == NULL);
163                             DrainPartial = Partial->u.DevicePrivate.Data[1];
164                             ASSERT(DrainPartial == TRUE);
165                             break;
166                     }
167                     break;
168             }
169 
170             /* Move to the next descriptor */
171             Partial = CmiGetNextPartialDescriptor(Partial);
172         }
173 
174         /* We should be starting a new list now */
175         ASSERT(BaseResource == NULL);
176         FullList = (PVOID)Partial;
177     }
178 
179     /* Check the current assigned PCI resources */
180     PciResources = PdoExtension->Resources;
181     if (!PciResources) return FALSE;
182 
183     //if... // MISSING CODE
184     UNIMPLEMENTED;
185     DPRINT1("Missing sanity checking code!\n");
186 
187     /* Loop all the PCI function resources */
188     for (i = 0; i < 7; i++)
189     {
190         /* Get the current function resource descriptor, and the new one */
191         CurrentDescriptor = &PciResources->Current[i];
192         Partial = &ResourceArray[i];
193 
194         /* Previous is current during the first loop iteration */
195         PreviousDescriptor = &PciResources->Current[(i == 0) ? (0) : (i - 1)];
196 
197         /* Check if this new descriptor is different than the old one */
198         if (((Partial->Type != CurrentDescriptor->Type) ||
199              (Partial->Type != CmResourceTypeNull)) &&
200             ((Partial->u.Generic.Start.QuadPart !=
201               CurrentDescriptor->u.Generic.Start.QuadPart) ||
202              (Partial->u.Generic.Length != CurrentDescriptor->u.Generic.Length)))
203         {
204             /* Record a change */
205             RangeChange = TRUE;
206 
207             /* Was there a range before? */
208             if (CurrentDescriptor->Type != CmResourceTypeNull)
209             {
210                 /* Print it */
211                 DbgPrint("      Old range-\n");
212                 PciDebugPrintPartialResource(CurrentDescriptor);
213             }
214             else
215             {
216                 /* There was no range */
217                 DbgPrint("      Previously unset range\n");
218             }
219 
220             /* Print new one */
221             DbgPrint("      changed to\n");
222             PciDebugPrintPartialResource(Partial);
223 
224             /* Update to new range */
225             CurrentDescriptor->Type = Partial->Type;
226             PreviousDescriptor->u.Generic.Start = Partial->u.Generic.Start;
227             PreviousDescriptor->u.Generic.Length = Partial->u.Generic.Length;
228             CurrentDescriptor = PreviousDescriptor;
229         }
230     }
231 
232     /* Either the hardware was updated, or a resource range changed */
233     return ((RangeChange) || (PdoExtension->UpdateHardware));
234 }
235 
236 VOID
237 NTAPI
PcipUpdateHardware(IN PVOID Context,IN PVOID Context2)238 PcipUpdateHardware(IN PVOID Context,
239                    IN PVOID Context2)
240 {
241     PPCI_PDO_EXTENSION PdoExtension = Context;
242     PPCI_COMMON_HEADER PciData = Context2;
243 
244     /* Check if we're allowed to disable decodes */
245     PciData->Command = PdoExtension->CommandEnables;
246     if (!(PdoExtension->HackFlags & PCI_HACK_PRESERVE_COMMAND))
247     {
248         /* Disable all decodes */
249         PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
250                               PCI_ENABLE_MEMORY_SPACE |
251                               PCI_ENABLE_BUS_MASTER |
252                               PCI_ENABLE_WRITE_AND_INVALIDATE);
253     }
254 
255     /* Update the device configuration */
256     PciData->Status = 0;
257     PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
258 
259     /* Turn decodes back on */
260     PciDecodeEnable(PdoExtension, TRUE, &PdoExtension->CommandEnables);
261 }
262 
263 VOID
264 NTAPI
PciUpdateHardware(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER PciData)265 PciUpdateHardware(IN PPCI_PDO_EXTENSION PdoExtension,
266                   IN PPCI_COMMON_HEADER PciData)
267 {
268     PCI_IPI_CONTEXT Context;
269 
270     /* Check for critical devices and PCI Debugging devices */
271     if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
272         (PdoExtension->OnDebugPath))
273     {
274         /* Build the context and send an IPI */
275         Context.RunCount = 1;
276         Context.Barrier = 1;
277         Context.Context = PciData;
278         Context.Function = PcipUpdateHardware;
279         Context.DeviceExtension = PdoExtension;
280         KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&Context);
281     }
282     else
283     {
284         /* Just to the update inline */
285         PcipUpdateHardware(PdoExtension, PciData);
286     }
287 }
288 
289 PIO_RESOURCE_REQUIREMENTS_LIST
290 NTAPI
PciAllocateIoRequirementsList(IN ULONG Count,IN ULONG BusNumber,IN ULONG SlotNumber)291 PciAllocateIoRequirementsList(IN ULONG Count,
292                               IN ULONG BusNumber,
293                               IN ULONG SlotNumber)
294 {
295     SIZE_T Size;
296     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
297 
298     /* Calculate the final size of the list, including each descriptor */
299     Size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
300     if (Count > 1) Size = sizeof(IO_RESOURCE_DESCRIPTOR) * (Count - 1) +
301                           sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
302 
303     /* Allocate the list */
304     RequirementsList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
305     if (!RequirementsList) return NULL;
306 
307     /* Initialize it */
308     RtlZeroMemory(RequirementsList, Size);
309     RequirementsList->AlternativeLists = 1;
310     RequirementsList->BusNumber = BusNumber;
311     RequirementsList->SlotNumber = SlotNumber;
312     RequirementsList->InterfaceType = PCIBus;
313     RequirementsList->ListSize = Size;
314     RequirementsList->List[0].Count = Count;
315     RequirementsList->List[0].Version = 1;
316     RequirementsList->List[0].Revision = 1;
317 
318     /* Return it */
319     return RequirementsList;
320 }
321 
322 PCM_RESOURCE_LIST
323 NTAPI
PciAllocateCmResourceList(IN ULONG Count,IN ULONG BusNumber)324 PciAllocateCmResourceList(IN ULONG Count,
325                           IN ULONG BusNumber)
326 {
327     SIZE_T Size;
328     PCM_RESOURCE_LIST ResourceList;
329 
330     /* Calculate the final size of the list, including each descriptor */
331     Size = sizeof(CM_RESOURCE_LIST);
332     if (Count > 1) Size = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count - 1) +
333                           sizeof(CM_RESOURCE_LIST);
334 
335     /* Allocate the list */
336     ResourceList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
337     if (!ResourceList) return NULL;
338 
339     /* Initialize it */
340     RtlZeroMemory(ResourceList, Size);
341     ResourceList->Count = 1;
342     ResourceList->List[0].BusNumber = BusNumber;
343     ResourceList->List[0].InterfaceType = PCIBus;
344     ResourceList->List[0].PartialResourceList.Version = 1;
345     ResourceList->List[0].PartialResourceList.Revision = 1;
346     ResourceList->List[0].PartialResourceList.Count = Count;
347 
348     /* Return it */
349     return ResourceList;
350 }
351 
352 NTSTATUS
353 NTAPI
PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension,OUT PCM_RESOURCE_LIST * Buffer)354 PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension,
355                   OUT PCM_RESOURCE_LIST *Buffer)
356 {
357     PPCI_FUNCTION_RESOURCES PciResources;
358     BOOLEAN HaveVga, HaveMemSpace, HaveIoSpace;
359     USHORT BridgeControl, PciCommand;
360     ULONG Count, i;
361     PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, Resource, LastResource;
362     PCM_RESOURCE_LIST ResourceList;
363     UCHAR InterruptLine;
364     PAGED_CODE();
365 
366     /* Assume failure */
367     Count = 0;
368     HaveVga = FALSE;
369     *Buffer = NULL;
370 
371     /* Make sure there's some resources to query */
372     PciResources = PdoExtension->Resources;
373     if (!PciResources) return STATUS_SUCCESS;
374 
375     /* Read the decodes */
376     PciReadDeviceConfig(PdoExtension,
377                         &PciCommand,
378                         FIELD_OFFSET(PCI_COMMON_HEADER, Command),
379                         sizeof(USHORT));
380 
381     /* Check which ones are turned on */
382     HaveIoSpace = PciCommand & PCI_ENABLE_IO_SPACE;
383     HaveMemSpace = PciCommand & PCI_ENABLE_MEMORY_SPACE;
384 
385     /* Loop maximum possible descriptors */
386     for (i = 0; i < 7; i++)
387     {
388         /* Check if the decode for this descriptor is actually turned on */
389         Partial = &PciResources->Current[i];
390         if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
391             ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
392         {
393             /* One more fully active descriptor */
394             Count++;
395         }
396     }
397 
398     /* If there's an interrupt pin associated, check at least one decode is on */
399     if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
400     {
401         /* Read the interrupt line for the pin, add a descriptor if it's valid */
402         InterruptLine = PdoExtension->AdjustedInterruptLine;
403         if ((InterruptLine) && (InterruptLine != -1)) Count++;
404     }
405 
406     /* Check for PCI bridge */
407     if (PdoExtension->HeaderType == PCI_BRIDGE_TYPE)
408     {
409         /* Read bridge settings, check if VGA is present */
410         PciReadDeviceConfig(PdoExtension,
411                             &BridgeControl,
412                             FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BridgeControl),
413                             sizeof(USHORT));
414         if (BridgeControl & PCI_ENABLE_BRIDGE_VGA)
415         {
416             /* Remember for later */
417             HaveVga = TRUE;
418 
419             /* One memory descriptor for 0xA0000, plus the two I/O port ranges */
420             if (HaveMemSpace) Count++;
421             if (HaveIoSpace) Count += 2;
422         }
423     }
424 
425     /* If there's no descriptors in use, there's no resources, so return */
426     if (!Count) return STATUS_SUCCESS;
427 
428     /* Allocate a resource list to hold the resources */
429     ResourceList = PciAllocateCmResourceList(Count,
430                                              PdoExtension->ParentFdoExtension->BaseBus);
431     if (!ResourceList) return STATUS_INSUFFICIENT_RESOURCES;
432 
433     /* This is where the descriptors will be copied into */
434     Resource = ResourceList->List[0].PartialResourceList.PartialDescriptors;
435     LastResource = Resource + Count + 1;
436 
437     /* Loop maximum possible descriptors */
438     for (i = 0; i < 7; i++)
439     {
440         /* Check if the decode for this descriptor is actually turned on */
441         Partial = &PciResources->Current[i];
442         if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
443             ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
444         {
445             /* Copy the descriptor into the resource list */
446             *Resource++ = *Partial;
447         }
448     }
449 
450     /* Check if earlier the code detected this was a PCI bridge with VGA on it */
451     if (HaveVga)
452     {
453         /* Are the memory decodes enabled? */
454         if (HaveMemSpace)
455         {
456             /* Build a memory descriptor for a 128KB framebuffer at 0xA0000 */
457             Resource->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
458             Resource->u.Generic.Start.HighPart = 0;
459             Resource->Type = CmResourceTypeMemory;
460             Resource->u.Generic.Start.LowPart = 0xA0000;
461             Resource->u.Generic.Length = 0x20000;
462             Resource++;
463         }
464 
465         /* Are the I/O decodes enabled? */
466         if (HaveIoSpace)
467         {
468             /* Build an I/O descriptor for the graphic ports at 0x3B0 */
469             Resource->Type = CmResourceTypePort;
470             Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
471             Resource->u.Port.Start.QuadPart = 0x3B0u;
472             Resource->u.Port.Length = 0xC;
473             Resource++;
474 
475             /* Build an I/O descriptor for the graphic ports at 0x3C0 */
476             Resource->Type = CmResourceTypePort;
477             Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
478             Resource->u.Port.Start.QuadPart = 0x3C0u;
479             Resource->u.Port.Length = 0x20;
480             Resource++;
481         }
482     }
483 
484     /* If there's an interrupt pin associated, check at least one decode is on */
485     if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
486     {
487          /* Read the interrupt line for the pin, check if it's valid */
488          InterruptLine = PdoExtension->AdjustedInterruptLine;
489          if ((InterruptLine) && (InterruptLine != -1))
490          {
491              /* Make sure there's still space */
492              ASSERT(Resource < LastResource);
493 
494              /* Add the interrupt descriptor */
495              Resource->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
496              Resource->Type = CmResourceTypeInterrupt;
497              Resource->ShareDisposition = CmResourceShareShared;
498              Resource->u.Interrupt.Affinity = -1;
499              Resource->u.Interrupt.Level = InterruptLine;
500              Resource->u.Interrupt.Vector = InterruptLine;
501         }
502     }
503 
504     /* Return the resource list */
505     *Buffer = ResourceList;
506     return STATUS_SUCCESS;
507 }
508 
509 NTSTATUS
510 NTAPI
PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension,IN OUT PDEVICE_RELATIONS * pDeviceRelations)511 PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension,
512                               IN OUT PDEVICE_RELATIONS *pDeviceRelations)
513 {
514     PDEVICE_RELATIONS DeviceRelations;
515     PAGED_CODE();
516 
517     /* If there were existing relations, free them */
518     if (*pDeviceRelations) ExFreePoolWithTag(*pDeviceRelations, 0);
519 
520     /* Allocate a new structure for the relations */
521     DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
522                                             sizeof(DEVICE_RELATIONS),
523                                             'BicP');
524     if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES;
525 
526     /* Only one relation: the PDO */
527     DeviceRelations->Count = 1;
528     DeviceRelations->Objects[0] = PdoExtension->PhysicalDeviceObject;
529     ObReferenceObject(DeviceRelations->Objects[0]);
530 
531     /* Return the new relations */
532     *pDeviceRelations = DeviceRelations;
533     return STATUS_SUCCESS;
534 }
535 
536 NTSTATUS
537 NTAPI
PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension,IN OUT PDEVICE_RELATIONS * pDeviceRelations)538 PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension,
539                           IN OUT PDEVICE_RELATIONS *pDeviceRelations)
540 {
541     UNREFERENCED_PARAMETER(PdoExtension);
542     UNREFERENCED_PARAMETER(pDeviceRelations);
543 
544     /* Not yet implemented */
545     UNIMPLEMENTED_DBGBREAK();
546     return STATUS_NOT_IMPLEMENTED;
547 }
548 
549 NTSTATUS
550 NTAPI
PciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER PciData,OUT PIO_RESOURCE_REQUIREMENTS_LIST * Buffer)551 PciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension,
552                          IN PPCI_COMMON_HEADER PciData,
553                          OUT PIO_RESOURCE_REQUIREMENTS_LIST* Buffer)
554 {
555     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
556 
557     UNREFERENCED_PARAMETER(PdoExtension);
558     UNREFERENCED_PARAMETER(PciData);
559 
560     {
561         /* There aren't, so use the zero descriptor */
562         RequirementsList = PciZeroIoResourceRequirements;
563 
564         /* Does it actually exist yet? */
565         if (!PciZeroIoResourceRequirements)
566         {
567             /* Allocate it, and use it for future use */
568             RequirementsList = PciAllocateIoRequirementsList(0, 0, 0);
569             PciZeroIoResourceRequirements = RequirementsList;
570             if (!PciZeroIoResourceRequirements) return STATUS_INSUFFICIENT_RESOURCES;
571         }
572 
573         /* Return the zero requirements list to the caller */
574         *Buffer = RequirementsList;
575         DPRINT1("PCI - build resource reqs - early out, 0 resources\n");
576         return STATUS_SUCCESS;
577     }
578     return STATUS_SUCCESS;
579 }
580 
581 NTSTATUS
582 NTAPI
PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension,IN OUT PIO_RESOURCE_REQUIREMENTS_LIST * RequirementsList)583 PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension,
584                      IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList)
585 {
586     NTSTATUS Status;
587     PCI_COMMON_HEADER PciHeader;
588     PAGED_CODE();
589 
590     /* Check if the PDO has any resources, or at least an interrupt pin */
591     if ((PdoExtension->Resources) || (PdoExtension->InterruptPin))
592     {
593         /* Read the current PCI header */
594         PciReadDeviceConfig(PdoExtension, &PciHeader, 0, PCI_COMMON_HDR_LENGTH);
595 
596         /* Use it to build a list of requirements */
597         Status = PciBuildRequirementsList(PdoExtension, &PciHeader, RequirementsList);
598         if (!NT_SUCCESS(Status)) return Status;
599 
600         /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
601         if ((PciHeader.VendorID == 0xE11) &&
602             (PciHeader.DeviceID == 0xA0F7) &&
603             (PciHeader.RevisionID == 17) &&
604             (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
605         {
606             /* Have not tested this on eVb's machine yet */
607             UNIMPLEMENTED_DBGBREAK();
608         }
609 
610         /* Check if the requirements are actually the zero list */
611         if (*RequirementsList == PciZeroIoResourceRequirements)
612         {
613             /* A simple NULL will suffice for the PnP Manager */
614             *RequirementsList = NULL;
615             DPRINT1("Returning NULL requirements list\n");
616         }
617         else
618         {
619             /* Otherwise, print out the requirements list */
620             PciDebugPrintIoResReqList(*RequirementsList);
621         }
622     }
623     else
624     {
625         /* There aren't any resources, so simply return NULL */
626         DPRINT1("PciQueryRequirements returning NULL requirements list\n");
627         *RequirementsList = NULL;
628     }
629 
630     /* This call always succeeds (but maybe with no requirements) */
631     return STATUS_SUCCESS;
632 }
633 
634 /*
635  * 7. The IO/MEM/Busmaster decodes are disabled for the device.
636  * 8. The PCI bus driver sets the operating mode bits of the Programming
637  *    Interface byte to switch the controller to native mode.
638  *
639  *    Important: When the controller is set to native mode, it must quiet itself
640  *    and must not decode I/O resources or generate interrupts until the operating
641  *    system has enabled the ports in the PCI configuration header.
642  *    The IO/MEM/BusMaster bits will be disabled before the mode change, but it
643  *    is not possible to disable interrupts on the device. The device must not
644  *    generate interrupts (either legacy or native mode) while the decodes are
645  *    disabled in the command register.
646  *
647  *    This operation is expected to be instantaneous and the operating system does
648  *    not stall afterward. It is also expected that the interrupt pin register in
649  *    the PCI Configuration space for this device is accurate. The operating system
650  *    re-reads this data after previously ignoring it.
651  */
652 BOOLEAN
653 NTAPI
PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER PciData,IN BOOLEAN Initial)654 PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,
655                           IN PPCI_COMMON_HEADER PciData,
656                           IN BOOLEAN Initial)
657 {
658     UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf;
659     BOOLEAN Switched;
660     USHORT Command;
661 
662     /* Assume it won't work */
663     Switched = FALSE;
664 
665     /* Get master and slave current settings, and programmability flag */
666     ProgIf = PciData->ProgIf;
667     MasterMode = (ProgIf & 1) == 1;
668     MasterFixed = (ProgIf & 2) == 0;
669     SlaveMode = (ProgIf & 4) == 4;
670     SlaveFixed = (ProgIf & 8) == 0;
671 
672     /*
673      * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
674      * ATA controller from compatible mode to native mode, the following must be
675      * true:
676      *
677      * - The controller must indicate in its programming interface that both channels
678      *   can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
679      *   not support switching only one IDE channel to native mode. See the PCI IDE
680      *   Controller Specification Revision 1.0 for details.
681      */
682     if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed))
683     {
684         /* Windows does not support this configuration, fail */
685         DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
686                 PdoExtension->VendorId,
687                 PdoExtension->DeviceId);
688         return Switched;
689     }
690 
691     /* Check if the controller is already in native mode */
692     if ((MasterMode) && (SlaveMode))
693     {
694         /* Check if I/O decodes should be disabled */
695         if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl))
696         {
697             /* Read the current command */
698             PciReadDeviceConfig(PdoExtension,
699                                 &Command,
700                                 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
701                                 sizeof(USHORT));
702 
703             /* Disable I/O space decode */
704             Command &= ~PCI_ENABLE_IO_SPACE;
705 
706             /* Update new command in PCI IDE controller */
707             PciWriteDeviceConfig(PdoExtension,
708                                  &Command,
709                                  FIELD_OFFSET(PCI_COMMON_HEADER, Command),
710                                  sizeof(USHORT));
711 
712             /* Save updated command value */
713             PciData->Command = Command;
714         }
715 
716         /* The controller is now in native mode */
717         Switched = TRUE;
718     }
719     else if (!(MasterFixed) &&
720              !(SlaveFixed) &&
721              (PdoExtension->BIOSAllowsIDESwitchToNativeMode) &&
722              !(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE))
723     {
724         /* Turn off decodes */
725         PciDecodeEnable(PdoExtension, FALSE, NULL);
726 
727         /* Update the current command */
728         PciReadDeviceConfig(PdoExtension,
729                             &PciData->Command,
730                             FIELD_OFFSET(PCI_COMMON_HEADER, Command),
731                             sizeof(USHORT));
732 
733         /* Enable native mode */
734         ProgIf = PciData->ProgIf | 5;
735         PciWriteDeviceConfig(PdoExtension,
736                              &ProgIf,
737                              FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
738                              sizeof(UCHAR));
739 
740         /* Verify the setting "stuck" */
741         PciReadDeviceConfig(PdoExtension,
742                             &NewProgIf,
743                             FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
744                             sizeof(UCHAR));
745         if (NewProgIf == ProgIf)
746         {
747             /* Update the header and PDO data with the new programming mode */
748             PciData->ProgIf = ProgIf;
749             PdoExtension->ProgIf = NewProgIf;
750 
751             /* Clear the first four BARs to reset current BAR settings */
752             PciData->u.type0.BaseAddresses[0] = 0;
753             PciData->u.type0.BaseAddresses[1] = 0;
754             PciData->u.type0.BaseAddresses[2] = 0;
755             PciData->u.type0.BaseAddresses[3] = 0;
756             PciWriteDeviceConfig(PdoExtension,
757                                  PciData->u.type0.BaseAddresses,
758                                  FIELD_OFFSET(PCI_COMMON_HEADER,
759                                               u.type0.BaseAddresses),
760                                  4 * sizeof(ULONG));
761 
762             /* Re-read the BARs to have the latest data for native mode IDE */
763             PciReadDeviceConfig(PdoExtension,
764                                 PciData->u.type0.BaseAddresses,
765                                 FIELD_OFFSET(PCI_COMMON_HEADER,
766                                              u.type0.BaseAddresses),
767                                 4 * sizeof(ULONG));
768 
769             /* Re-read the interrupt pin used for native mode IDE */
770             PciReadDeviceConfig(PdoExtension,
771                                 &PciData->u.type0.InterruptPin,
772                                 FIELD_OFFSET(PCI_COMMON_HEADER,
773                                              u.type0.InterruptPin),
774                                 sizeof(UCHAR));
775 
776             /* The IDE Controller is now in native mode */
777             Switched = TRUE;
778         }
779         else
780         {
781             /* Settings did not work, fail */
782             DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
783                     PciData->VendorID,
784                     PciData->DeviceID);
785         }
786    }
787 
788    /* Return whether or not native mode was enabled on the IDE controller */
789    return Switched;
790 }
791 
792 VOID
793 NTAPI
PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,IN PPCI_COMMON_HEADER PciData,IN PCI_SLOT_NUMBER SlotNumber,IN ULONG OperationType,PPCI_PDO_EXTENSION PdoExtension)794 PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,
795               IN PPCI_COMMON_HEADER PciData,
796               IN PCI_SLOT_NUMBER SlotNumber,
797               IN ULONG OperationType,
798               PPCI_PDO_EXTENSION PdoExtension)
799 {
800     ULONG LegacyBaseAddress;
801     USHORT Command;
802     UCHAR RegValue;
803 
804     UNREFERENCED_PARAMETER(SlotNumber);
805 
806     /* Check what kind of hack operation this is */
807     switch (OperationType)
808     {
809         /*
810          * This is mostly concerned with fixing up incorrect class data that can
811          * exist on certain PCI hardware before the 2.0 spec was ratified.
812          */
813         case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
814 
815             /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
816              * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
817              * and appear as non-classified, so their correct class/subclass data
818              * is written here instead.
819              */
820             if ((PciData->VendorID == 0x8086) &&
821                 ((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484)))
822             {
823                 /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
824                 PciData->SubClass = PciData->DeviceID == 0x482 ?
825                                     PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA;
826                 PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
827 
828                 /*
829                  * Because the software is modifying the actual header data from
830                  * the BIOS, this flag tells the driver to ignore failures when
831                  * comparing the original BIOS data with the PCI data.
832                  */
833                 if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE;
834             }
835 
836             /* Note that in this case, an immediate return is issued */
837             return;
838 
839         /*
840          * This is concerned with setting up interrupts correctly for native IDE
841          * mode, but will also handle broken VGA decoding on older bridges as
842          * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
843          */
844         case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
845 
846             /* There should always be a PDO extension passed in */
847             ASSERT(PdoExtension);
848 
849             /*
850              * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
851              * and FreeBSD bug reports indicate that the system crashes when the
852              * feature is enabled (so it's disabled on that OS as well). In the
853              * NT PCI Bus Driver, it seems Microsoft too, completely disables
854              * Native IDE functionality on this controller, so it would seem OPTi
855              * simply frelled up this controller.
856              */
857             if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621))
858             {
859                 /* Disable native mode */
860                 PciData->ProgIf &= ~5;
861                 PciData->u.type0.InterruptPin = 0;
862 
863                 /*
864                  * Because the software is modifying the actual header data from
865                  * the BIOS, this flag tells the driver to ignore failures when
866                  * comparing the original BIOS data with the PCI data.
867                  */
868                 PdoExtension->ExpectedWritebackFailure = TRUE;
869             }
870             else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
871                     (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
872             {
873                 /* For other IDE controllers, start out in compatible mode */
874                 PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
875 
876                 /*
877                  * Registry must have enabled native mode (typically as a result
878                  * of an INF file directive part of the IDE controller's driver)
879                  * and the system must not be booted in Safe Mode. If that checks
880                  * out, then evaluate the ACPI NATA method to see if the platform
881                  * supports this. See the section "BIOS and Platform Prerequisites
882                  * for Switching a Native-Mode-Capable Controller" in the Storage
883                  * section of the Windows Driver Kit for more details:
884                  *
885                  * 5. For each ATA controller enumerated, the PCI bus driver checks
886                  *    the Programming Interface register of the IDE controller to
887                  *    see if it supports switching both channels to native mode.
888                  * 6. The PCI bus driver checks whether the BIOS/platform supports
889                  *    switching the controller by checking the NATA method described
890                  *    earlier in this article.
891                  *
892                  *    If an ATA controller does not indicate that it is native
893                  *    mode-capable, or if the BIOS NATA control method is missing
894                  *    or does not list that device, the PCI bus driver does not
895                  *    switch the controller and it is assigned legacy resources.
896                  *
897                  *  If both the controller and the BIOS indicate that the controller
898                  *  can be switched, the process of switching the controller begins
899                  *  with the next step.
900                  */
901                 if ((PciEnableNativeModeATA) &&
902                     !(InitSafeBootMode) &&
903                     (PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN')))
904                 {
905                     /* The platform supports it, remember that */
906                     PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
907 
908                     /*
909                      * Now switch the controller into native mode if both channels
910                      * support native IDE mode. See "How Windows Switches an ATA
911                      * Controller to Native Mode" in the Storage section of the
912                      * Windows Driver Kit for more details.
913                      */
914                     PdoExtension->IDEInNativeMode =
915                         PciConfigureIdeController(PdoExtension, PciData, TRUE);
916                 }
917 
918                 /* Is native mode enabled after all? */
919                 if ((PciData->ProgIf & 5) != 5)
920                 {
921                     /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
922                     PciData->u.type0.InterruptPin = 0;
923                 }
924             }
925 
926             /* Is this a PCI device with legacy VGA card decodes on the root bus? */
927             if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) &&
928                 (PCI_IS_ROOT_FDO(DeviceExtension)) &&
929                 !(DeviceExtension->BrokenVideoHackApplied))
930             {
931                 /* Tell the arbiter to apply a hack for these older devices */
932                 ario_ApplyBrokenVideoHack(DeviceExtension);
933             }
934 
935             /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
936             if ((PciData->VendorID == 0xE11) &&
937                 (PciData->DeviceID == 0xA0F7) &&
938                 (PciData->RevisionID == 17) &&
939                 (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
940             {
941                 /* Turn off the decodes immediately */
942                 PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
943                                       PCI_ENABLE_MEMORY_SPACE |
944                                       PCI_ENABLE_BUS_MASTER);
945                 PciWriteDeviceConfig(PdoExtension,
946                                      &PciData->Command,
947                                      FIELD_OFFSET(PCI_COMMON_HEADER, Command),
948                                      sizeof(USHORT));
949 
950                 /* Do not EVER turn them on again, this will blow up the system */
951                 PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE |
952                                                   PCI_ENABLE_MEMORY_SPACE |
953                                                   PCI_ENABLE_BUS_MASTER);
954                 PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND;
955             }
956             break;
957 
958         /*
959          * This is called whenever resources are changed and hardware needs to be
960          * updated. It is concerned with two highly specific erratas on an IBM
961          * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
962          * ICH PCI Bridges.
963          */
964         case PCI_HACK_FIXUP_BEFORE_UPDATE:
965 
966             /* There should always be a PDO extension passed in */
967             ASSERT(PdoExtension);
968 
969             /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
970             if ((PdoExtension->VendorId == 0x1014) &&
971                 (PdoExtension->DeviceId == 0x95))
972             {
973                 /* Read the current command */
974                 PciReadDeviceConfig(PdoExtension,
975                                     &Command,
976                                     FIELD_OFFSET(PCI_COMMON_HEADER, Command),
977                                     sizeof(USHORT));
978 
979                 /* Turn off the decodes */
980                 PciDecodeEnable(PdoExtension, FALSE, &Command);
981 
982                 /* Apply the required IBM workaround */
983                 PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
984                 RegValue &= ~2;
985                 RegValue |= 1;
986                 PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
987 
988                 /* Restore the command to its original value */
989                 PciWriteDeviceConfig(PdoExtension,
990                                      &Command,
991                                      FIELD_OFFSET(PCI_COMMON_HEADER, Command),
992                                      sizeof(USHORT));
993 
994             }
995 
996             /*
997              * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
998              * i820, i840, i845 Chipsets) that have subtractive decode enabled,
999              * and whose hack flags do not specify that this support is broken.
1000              */
1001             if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) &&
1002                 (PdoExtension->Dependent.type1.SubtractiveDecode) &&
1003                 ((PdoExtension->VendorId == 0x8086) &&
1004                  ((PdoExtension->DeviceId == 0x2418) ||
1005                   (PdoExtension->DeviceId == 0x2428) ||
1006                   (PdoExtension->DeviceId == 0x244E) ||
1007                   (PdoExtension->DeviceId == 0x2448))) &&
1008                !(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
1009             {
1010                 /*
1011                  * The positive decode window shouldn't be used, these values are
1012                  * normally all read-only or initialized to 0 by the BIOS, but
1013                  * it appears Intel doesn't do this, so the PCI Bus Driver will
1014                  * do it in software instead. Note that this is used to prevent
1015                  * certain non-compliant PCI devices from breaking down due to the
1016                  * fact that these ICH bridges have a known "quirk" (which Intel
1017                  * documents as a known "erratum", although it's not not really
1018                  * an ICH bug since the PCI specification does allow for it) in
1019                  * that they will sometimes send non-zero addresses during special
1020                  * cycles (ie: non-zero data during the address phase). These
1021                  * broken PCI cards will mistakenly attempt to claim the special
1022                  * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
1023                  * defense, the PCI specification only requires stable data, not
1024                  * necessarily zero data, during the address phase.
1025                  */
1026                 PciData->u.type1.MemoryBase = 0xFFFF;
1027                 PciData->u.type1.PrefetchBase = 0xFFFF;
1028                 PciData->u.type1.IOBase = 0xFF;
1029                 PciData->u.type1.IOLimit = 0;
1030                 PciData->u.type1.MemoryLimit = 0;
1031                 PciData->u.type1.PrefetchLimit = 0;
1032                 PciData->u.type1.PrefetchBaseUpper32 = 0;
1033                 PciData->u.type1.PrefetchLimitUpper32 = 0;
1034                 PciData->u.type1.IOBaseUpper16 = 0;
1035                 PciData->u.type1.IOLimitUpper16 = 0;
1036             }
1037             break;
1038 
1039         default:
1040             return;
1041     }
1042 
1043     /* Finally, also check if this is this a CardBUS device? */
1044     if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
1045     {
1046         /*
1047          * At offset 44h the LegacyBaseAddress is stored, which is cleared by
1048          * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
1049          * CardBus controllers. For more information, see "Supporting CardBus
1050          * Controllers under ACPI" in the "CardBus Controllers and Windows"
1051          * Whitepaper on WHDC.
1052          */
1053         LegacyBaseAddress = 0;
1054         PciWriteDeviceConfig(PdoExtension,
1055                              &LegacyBaseAddress,
1056                              sizeof(PCI_COMMON_HEADER) + sizeof(ULONG),
1057                              sizeof(ULONG));
1058     }
1059 }
1060 
1061 BOOLEAN
1062 NTAPI
PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,IN PPCI_COMMON_HEADER PciData)1063 PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
1064                  IN PPCI_COMMON_HEADER PciData)
1065 {
1066     BOOLEAN IdMatch, RevMatch, SubsysMatch;
1067     ULONGLONG HackFlags = DeviceExtension->HackFlags;
1068 
1069     /* Check if the IDs match */
1070     IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
1071               (PciData->DeviceID == DeviceExtension->DeviceId);
1072     if (!IdMatch) return FALSE;
1073 
1074     /* If the device has a valid revision, check if it matches */
1075     RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
1076                (PciData->RevisionID == DeviceExtension->RevisionId);
1077     if (!RevMatch) return FALSE;
1078 
1079     /* For multifunction devices, this is enough to assume they're the same */
1080     if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
1081 
1082     /* For bridge devices, there's also nothing else that can be checked */
1083     if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
1084 
1085     /* Devices, on the other hand, have subsystem data that can be compared */
1086     SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
1087                                 PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
1088                   ((DeviceExtension->SubsystemVendorId ==
1089                     PciData->u.type0.SubVendorID) &&
1090                    (DeviceExtension->SubsystemId ==
1091                     PciData->u.type0.SubSystemID));
1092     return SubsysMatch;
1093 }
1094 
1095 BOOLEAN
1096 NTAPI
PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,IN PCI_SLOT_NUMBER Slot,IN UCHAR OperationType,IN ULONGLONG HackFlags)1097 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
1098                     IN PCI_SLOT_NUMBER Slot,
1099                     IN UCHAR OperationType,
1100                     IN ULONGLONG HackFlags)
1101 {
1102     do
1103     {
1104         /* Check if this is device enumeration */
1105         if (OperationType == PCI_SKIP_DEVICE_ENUMERATION)
1106         {
1107             /* Check if there's a hackflag saying not to enumerate this device */
1108             if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
1109 
1110             /* Check if this is the high end of a double decker device */
1111             if ((HackFlags & PCI_HACK_DOUBLE_DECKER) &&
1112                 (Slot.u.bits.DeviceNumber >= 16))
1113             {
1114                 /* It belongs to the same device, so skip it */
1115                 DPRINT1("    Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
1116                         PciData->VendorID,
1117                         PciData->DeviceID,
1118                         Slot.u.bits.DeviceNumber,
1119                         Slot.u.bits.FunctionNumber);
1120                 break;
1121             }
1122         }
1123         else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)
1124         {
1125             /* Resource enumeration, check for a hackflag saying not to do it */
1126             if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break;
1127         }
1128         else
1129         {
1130             /* Logic error in the driver */
1131             ASSERTMSG("PCI Skip Function - Operation type unknown.\n", FALSE);
1132         }
1133 
1134         /* Check for legacy bridges during resource enumeration */
1135         if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1136             (PciData->SubClass <= PCI_SUBCLASS_BR_MCA) &&
1137             (OperationType == PCI_SKIP_RESOURCE_ENUMERATION))
1138         {
1139             /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
1140             break;
1141         }
1142         else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED)
1143         {
1144             /* Undefined base class (usually a PCI BIOS/ROM bug) */
1145             DPRINT1("    Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
1146                     PciData->VendorID,
1147                     PciData->DeviceID);
1148 
1149             /*
1150              * The Alder has an Intel Extended Express System Support Controller
1151              * which presents apparently spurious BARs. When the PCI resource
1152              * code tries to reassign these BARs, the second IO-APIC gets
1153              * disabled (with disastrous consequences). The first BAR is the
1154              * actual IO-APIC, the remaining five bars seem to be spurious
1155              * resources, so ignore this device completely.
1156              */
1157             if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break;
1158         }
1159 
1160         /* Other normal PCI cards and bridges are enumerated */
1161         if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE;
1162     } while (FALSE);
1163 
1164     /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
1165     DPRINT1("   Device skipped (not enumerated).\n");
1166     return TRUE;
1167 }
1168 
1169 VOID
1170 NTAPI
PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER PciData)1171 PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
1172                            IN PPCI_COMMON_HEADER PciData)
1173 {
1174     ULONG HeaderType, CapPtr, TargetAgpCapabilityId;
1175     DEVICE_POWER_STATE WakeLevel;
1176     PCI_CAPABILITIES_HEADER AgpCapability;
1177     PCI_PM_CAPABILITY PowerCapabilities;
1178     PAGED_CODE();
1179 
1180     /* Assume no known wake level */
1181     PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
1182 
1183     /* Make sure the device has capabilities */
1184     if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST))
1185     {
1186         /* If it doesn't, there will be no power management */
1187         PdoExtension->CapabilitiesPtr = 0;
1188         PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
1189     }
1190     else
1191     {
1192         /* There's capabilities, need to figure out where to get the offset */
1193         HeaderType = PCI_CONFIGURATION_TYPE(PciData);
1194         if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE)
1195         {
1196             /* Use the bridge's header */
1197             CapPtr = PciData->u.type2.CapabilitiesPtr;
1198         }
1199         else
1200         {
1201             /* Use the device header */
1202             ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE);
1203             CapPtr = PciData->u.type0.CapabilitiesPtr;
1204         }
1205 
1206         /* Skip garbage capabilities pointer */
1207         if (((CapPtr & 0x3) != 0) || (CapPtr < PCI_COMMON_HDR_LENGTH))
1208         {
1209             /* Report no extended capabilities */
1210             PdoExtension->CapabilitiesPtr = 0;
1211             PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
1212         }
1213         else
1214         {
1215             DPRINT1("Device has capabilities at: %lx\n", CapPtr);
1216             PdoExtension->CapabilitiesPtr = CapPtr;
1217 
1218             /* Check for PCI-to-PCI Bridges and AGP bridges */
1219             if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1220                 ((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) ||
1221                  (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)))
1222             {
1223                 /* Query either the raw AGP capabilitity, or the Target AGP one */
1224                 TargetAgpCapabilityId = (PdoExtension->SubClass ==
1225                                          PCI_SUBCLASS_BR_PCI_TO_PCI) ?
1226                 PCI_CAPABILITY_ID_AGP_TARGET :
1227                 PCI_CAPABILITY_ID_AGP;
1228                 if (PciReadDeviceCapability(PdoExtension,
1229                                             PdoExtension->CapabilitiesPtr,
1230                                             TargetAgpCapabilityId,
1231                                             &AgpCapability,
1232                                             sizeof(PCI_CAPABILITIES_HEADER)))
1233                 {
1234                     /* AGP target ID was found, store it */
1235                     DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId);
1236                     PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId;
1237                 }
1238             }
1239 
1240             /* Check for devices that are known not to have proper power management */
1241             if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
1242             {
1243                 /* Query if this device supports power management */
1244                 if (!PciReadDeviceCapability(PdoExtension,
1245                                              PdoExtension->CapabilitiesPtr,
1246                                              PCI_CAPABILITY_ID_POWER_MANAGEMENT,
1247                                              &PowerCapabilities.Header,
1248                                              sizeof(PCI_PM_CAPABILITY)))
1249                 {
1250                     /* No power management, so act as if it had the hackflag set */
1251                     DPRINT1("No PM caps, disabling PM\n");
1252                     PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
1253                 }
1254                 else
1255                 {
1256                     /* Otherwise, pick the highest wake level that is supported */
1257                     WakeLevel = PowerDeviceUnspecified;
1258                     if (PowerCapabilities.PMC.Capabilities.Support.PMED0)
1259                         WakeLevel = PowerDeviceD0;
1260                     if (PowerCapabilities.PMC.Capabilities.Support.PMED1)
1261                         WakeLevel = PowerDeviceD1;
1262                     if (PowerCapabilities.PMC.Capabilities.Support.PMED2)
1263                         WakeLevel = PowerDeviceD2;
1264                     if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot)
1265                         WakeLevel = PowerDeviceD3;
1266                     if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold)
1267                         WakeLevel = PowerDeviceD3;
1268                     PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
1269 
1270                     /* Convert the PCI power state to the NT power state */
1271                     PdoExtension->PowerState.CurrentDeviceState =
1272                     PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
1273 
1274                     /* Save all the power capabilities */
1275                     PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities;
1276                     DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
1277                             WakeLevel, PdoExtension->PowerState.CurrentDeviceState);
1278                 }
1279             }
1280         }
1281     }
1282 
1283     /* At the very end of all this, does this device not have power management? */
1284     if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
1285     {
1286         /* Then guess the current state based on whether the decodes are on */
1287         PdoExtension->PowerState.CurrentDeviceState =
1288             PciData->Command & (PCI_ENABLE_IO_SPACE |
1289                                 PCI_ENABLE_MEMORY_SPACE |
1290                                 PCI_ENABLE_BUS_MASTER) ?
1291             PowerDeviceD0: PowerDeviceD3;
1292         DPRINT1("PM is off, so assumed device is: %d based on enables\n",
1293                 PdoExtension->PowerState.CurrentDeviceState);
1294     }
1295 }
1296 
1297 VOID
1298 NTAPI
PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved,IN PVOID Context2)1299 PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved,
1300                                 IN PVOID Context2)
1301 {
1302     PPCI_CONFIGURATOR_CONTEXT Context = Context2;
1303     PPCI_COMMON_HEADER PciData, Current;
1304     PPCI_PDO_EXTENSION PdoExtension;
1305 
1306     UNREFERENCED_PARAMETER(Reserved);
1307 
1308     /* Grab all parameters from the context */
1309     PdoExtension = Context->PdoExtension;
1310     Current = Context->Current;
1311     PciData = Context->PciData;
1312 
1313     /* Write the limit discovery header */
1314     PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
1315 
1316     /* Now read what the device indicated the limits are */
1317     PciReadDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
1318 
1319     /* Then write back the original configuration header */
1320     PciWriteDeviceConfig(PdoExtension, Current, 0, PCI_COMMON_HDR_LENGTH);
1321 
1322     /* Copy back the original command that was saved in the context */
1323     Current->Command = Context->Command;
1324     if (Context->Command)
1325     {
1326         /* Program it back into the device */
1327         PciWriteDeviceConfig(PdoExtension,
1328                              &Context->Command,
1329                              FIELD_OFFSET(PCI_COMMON_HEADER, Command),
1330                              sizeof(USHORT));
1331     }
1332 
1333     /* Copy back the original status that was saved as well */
1334     Current->Status = Context->Status;
1335 
1336     /* Call the configurator to restore any other data that might've changed */
1337     Context->Configurator->RestoreCurrent(Context);
1338 }
1339 
1340 NTSTATUS
1341 NTAPI
PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)1342 PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
1343 {
1344     PPCI_CONFIGURATOR Configurator;
1345     PPCI_COMMON_HEADER PciData, Current;
1346     PPCI_PDO_EXTENSION PdoExtension;
1347     PCI_IPI_CONTEXT IpiContext;
1348     PIO_RESOURCE_DESCRIPTOR IoDescriptor;
1349     ULONG Offset;
1350     PAGED_CODE();
1351 
1352     /* Grab all parameters from the context */
1353     PdoExtension = Context->PdoExtension;
1354     Current = Context->Current;
1355     PciData = Context->PciData;
1356 
1357     /* Save the current PCI Command and Status word */
1358     Context->Status = Current->Status;
1359     Context->Command = Current->Command;
1360 
1361     /* Now that they're saved, clear the status, and disable all decodes */
1362     Current->Status = 0;
1363     Current->Command &= ~(PCI_ENABLE_IO_SPACE |
1364                           PCI_ENABLE_MEMORY_SPACE |
1365                           PCI_ENABLE_BUS_MASTER);
1366 
1367     /* Make a copy of the current PCI configuration header (with decodes off) */
1368     RtlCopyMemory(PciData, Current, PCI_COMMON_HDR_LENGTH);
1369 
1370     /* Locate the correct resource configurator for this type of device */
1371     Configurator = &PciConfigurators[PdoExtension->HeaderType];
1372     Context->Configurator = Configurator;
1373 
1374     /* Initialize it, which will typically setup the BARs for limit discovery */
1375     Configurator->Initialize(Context);
1376 
1377     /* Check for critical devices and PCI Debugging devices */
1378     if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
1379         (PdoExtension->OnDebugPath))
1380     {
1381         /* Specifically check for a PCI Debugging device */
1382         if (PdoExtension->OnDebugPath)
1383         {
1384             /* Was it enabled for bus mastering? */
1385             if (Context->Command & PCI_ENABLE_BUS_MASTER)
1386             {
1387                 /* This decode needs to be re-enabled so debugging can work */
1388                 PciData->Command |= PCI_ENABLE_BUS_MASTER;
1389                 Current->Command |= PCI_ENABLE_BUS_MASTER;
1390             }
1391 
1392             /* Disable the debugger while the discovery is happening */
1393             KdDisableDebugger();
1394         }
1395 
1396         /* For these devices, an IPI must be sent to force high-IRQL discovery */
1397         IpiContext.Barrier = 1;
1398         IpiContext.RunCount = 1;
1399         IpiContext.DeviceExtension = PdoExtension;
1400         IpiContext.Function = PciWriteLimitsAndRestoreCurrent;
1401         IpiContext.Context = Context;
1402         KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&IpiContext);
1403 
1404         /* Re-enable the debugger if this was a PCI Debugging Device */
1405         if (PdoExtension->OnDebugPath) KdEnableDebugger();
1406     }
1407     else
1408     {
1409         /* Otherwise, it's safe to do this in-line at low IRQL */
1410         PciWriteLimitsAndRestoreCurrent(PdoExtension, Context);
1411     }
1412 
1413     /*
1414      * Check if it's valid to compare the headers to see if limit discovery mode
1415      * has properly exited (the expected case is that the PCI header would now
1416      * be equal to what it was before). In some cases, it is known that this will
1417      * fail, because during PciApplyHacks (among other places), software hacks
1418      * had to be applied to the header, which the hardware-side will not see, and
1419      * thus the headers would appear "different".
1420      */
1421     if (!PdoExtension->ExpectedWritebackFailure)
1422     {
1423         /* Read the current PCI header now, after discovery has completed */
1424         PciReadDeviceConfig(PdoExtension, PciData + 1, 0, PCI_COMMON_HDR_LENGTH);
1425 
1426         /* Check if the current header at entry, is equal to the header now */
1427         Offset = RtlCompareMemory(PciData + 1, Current, PCI_COMMON_HDR_LENGTH);
1428         if (Offset != PCI_COMMON_HDR_LENGTH)
1429         {
1430             /* It's not, which means configuration somehow changed, dump this */
1431             DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset);
1432             PciDebugDumpCommonConfig(PciData + 1);
1433             DPRINT1("----------\n");
1434             PciDebugDumpCommonConfig(Current);
1435         }
1436     }
1437 
1438     /* This PDO should not already have resources, since this is only done once */
1439     ASSERT(PdoExtension->Resources == NULL);
1440 
1441     /* Allocate the structure that will hold the discovered resources and limits */
1442     PdoExtension->Resources = ExAllocatePoolWithTag(NonPagedPool,
1443                                                     sizeof(PCI_FUNCTION_RESOURCES),
1444                                                     'BicP');
1445     if (!PdoExtension->Resources) return STATUS_INSUFFICIENT_RESOURCES;
1446 
1447     /* Clear it out for now */
1448     RtlZeroMemory(PdoExtension->Resources, sizeof(PCI_FUNCTION_RESOURCES));
1449 
1450     /* Now call the configurator, which will first store the limits... */
1451     Configurator->SaveLimits(Context);
1452 
1453     /* ...and then store the current resources being used */
1454     Configurator->SaveCurrentSettings(Context);
1455 
1456     /* Loop all the limit descriptors backwards */
1457     IoDescriptor = &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1];
1458     while (TRUE)
1459     {
1460         /* Keep going until a non-null descriptor is found */
1461         IoDescriptor--;
1462         if (IoDescriptor->Type != CmResourceTypeNull) break;
1463 
1464         /* This is a null descriptor, is it the last one? */
1465         if (IoDescriptor == &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1])
1466         {
1467             /* This means the descriptor is NULL, which means discovery failed */
1468             DPRINT1("PCI Resources fail!\n");
1469 
1470             /* No resources will be assigned for the device */
1471             ExFreePoolWithTag(PdoExtension->Resources, 0);
1472             PdoExtension->Resources = NULL;
1473             break;
1474         }
1475     }
1476 
1477     /* Return success here, even if the device has no assigned resources */
1478     return STATUS_SUCCESS;
1479 }
1480 
1481 NTSTATUS
1482 NTAPI
PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER Current,IN ULONGLONG HackFlags)1483 PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension,
1484                      IN PPCI_COMMON_HEADER Current,
1485                      IN ULONGLONG HackFlags)
1486 {
1487     NTSTATUS Status;
1488     PPCI_COMMON_HEADER PciData;
1489     PCI_CONFIGURATOR_CONTEXT Context;
1490     PAGED_CODE();
1491 
1492     /* Do the hackflags indicate this device should be skipped? */
1493     if (PciSkipThisFunction(Current,
1494                             PdoExtension->Slot,
1495                             PCI_SKIP_RESOURCE_ENUMERATION,
1496                             HackFlags))
1497     {
1498         /* Do not process its resources */
1499         return STATUS_SUCCESS;
1500     }
1501 
1502     /* Allocate a buffer to hold two PCI configuration headers */
1503     PciData = ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH, 'BicP');
1504     if (!PciData) return STATUS_INSUFFICIENT_RESOURCES;
1505 
1506     /* Set up the context for the resource enumeration, and do it */
1507     Context.Current = Current;
1508     Context.PciData = PciData;
1509     Context.PdoExtension = PdoExtension;
1510     Status = PcipGetFunctionLimits(&Context);
1511 
1512     /* Enumeration is completed, free the PCI headers and return the status */
1513     ExFreePoolWithTag(PciData, 0);
1514     return Status;
1515 }
1516 
1517 VOID
1518 NTAPI
PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension)1519 PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension)
1520 {
1521     PPCI_PDO_EXTENSION PdoExtension;
1522     PDEVICE_OBJECT PhysicalDeviceObject;
1523     PAGED_CODE();
1524 
1525     /* Get the PDO Extension */
1526     PhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject;
1527     PdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
1528 
1529     /* Cheeck if this is the root bus */
1530     if (!PCI_IS_ROOT_FDO(DeviceExtension))
1531     {
1532         /* Not really handling this year */
1533         UNIMPLEMENTED_DBGBREAK();
1534 
1535         /* Check for PCI bridges with the ISA bit set, or required */
1536         if ((PdoExtension) &&
1537             (PciClassifyDeviceType(PdoExtension) == PciTypePciBridge) &&
1538             ((PdoExtension->Dependent.type1.IsaBitRequired) ||
1539              (PdoExtension->Dependent.type1.IsaBitSet)))
1540         {
1541             /* We'll need to do some legacy support */
1542             UNIMPLEMENTED_DBGBREAK();
1543         }
1544     }
1545     else
1546     {
1547         /* Scan all of the root bus' children bridges */
1548         for (PdoExtension = DeviceExtension->ChildBridgePdoList;
1549              PdoExtension;
1550              PdoExtension = PdoExtension->NextBridge)
1551         {
1552             /* Find any that have the VGA decode bit on */
1553             if (PdoExtension->Dependent.type1.VgaBitSet)
1554             {
1555                 /* Again, some more legacy support we'll have to do */
1556                 UNIMPLEMENTED_DBGBREAK();
1557             }
1558         }
1559     }
1560 
1561     /* Check for ACPI systems where the OS assigns bus numbers */
1562     if (PciAssignBusNumbers)
1563     {
1564         /* Not yet supported */
1565         UNIMPLEMENTED_DBGBREAK();
1566     }
1567 }
1568 
1569 NTSTATUS
1570 NTAPI
PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)1571 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
1572 {
1573     ULONG MaxDevice = PCI_MAX_DEVICES;
1574     BOOLEAN ProcessFlag = FALSE;
1575     ULONG i, j, k, Size;
1576     USHORT CapOffset, TempOffset;
1577     LONGLONG HackFlags;
1578     PDEVICE_OBJECT DeviceObject;
1579     UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
1580     UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
1581     PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
1582     PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
1583     PCI_SLOT_NUMBER PciSlot;
1584     PCHAR Name;
1585     NTSTATUS Status;
1586     PPCI_PDO_EXTENSION PdoExtension, NewExtension;
1587     PPCI_PDO_EXTENSION* BridgeExtension;
1588     PWCHAR DescriptionText;
1589     USHORT SubVendorId, SubSystemId;
1590     PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader;
1591     UCHAR SecondaryBus;
1592     DPRINT1("PCI Scan Bus: FDO Extension @ 0x%p, Base Bus = 0x%x\n",
1593             DeviceExtension, DeviceExtension->BaseBus);
1594 
1595     /* Is this the root FDO? */
1596     if (!PCI_IS_ROOT_FDO(DeviceExtension))
1597     {
1598         /* Get the PDO for the child bus */
1599         PdoExtension = DeviceExtension->PhysicalDeviceObject->DeviceExtension;
1600         ASSERT_PDO(PdoExtension);
1601 
1602         /* Check for hack which only allows bus to have one child device */
1603         if (PdoExtension->HackFlags & PCI_HACK_ONE_CHILD) MaxDevice = 1;
1604 
1605         /* Check if the secondary bus number has changed */
1606         PciReadDeviceConfig(PdoExtension,
1607                             &SecondaryBus,
1608                             FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.SecondaryBus),
1609                             sizeof(UCHAR));
1610         if (SecondaryBus != PdoExtension->Dependent.type1.SecondaryBus)
1611         {
1612             UNIMPLEMENTED_DBGBREAK("PCI: Bus numbers have been changed!  Restoring originals.\n");
1613         }
1614     }
1615 
1616     /* Loop every device on the bus */
1617     PciSlot.u.bits.Reserved = 0;
1618     i = DeviceExtension->BaseBus;
1619     for (j = 0; j < MaxDevice; j++)
1620     {
1621         /* Loop every function of each device */
1622         PciSlot.u.bits.DeviceNumber = j;
1623         for (k = 0; k < PCI_MAX_FUNCTION; k++)
1624         {
1625             /* Build the final slot structure */
1626             PciSlot.u.bits.FunctionNumber = k;
1627 
1628             /* Read the vendor for this slot */
1629             PciReadSlotConfig(DeviceExtension,
1630                               PciSlot,
1631                               PciData,
1632                               0,
1633                               sizeof(USHORT));
1634 
1635             /* Skip invalid device */
1636             if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
1637 
1638             /* Now read the whole header */
1639             PciReadSlotConfig(DeviceExtension,
1640                               PciSlot,
1641                               &PciData->DeviceID,
1642                               sizeof(USHORT),
1643                               PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
1644 
1645             /* Apply any hacks before even analyzing the configuration header */
1646             PciApplyHacks(DeviceExtension,
1647                           PciData,
1648                           PciSlot,
1649                           PCI_HACK_FIXUP_BEFORE_CONFIGURATION,
1650                           NULL);
1651 
1652             /* Dump device that was found */
1653             DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
1654                     PciSlot.u.AsULONG,
1655                     i,
1656                     j,
1657                     k);
1658 
1659             /* Dump the device's header */
1660             PciDebugDumpCommonConfig(PciData);
1661 
1662             /* Find description for this device for the debugger's sake */
1663             DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
1664                                                              PciData->SubClass);
1665             DPRINT1("Device Description \"%S\".\n",
1666                     DescriptionText ? DescriptionText : L"(NULL)");
1667             if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
1668 
1669             /* Check if there is an ACPI Watchdog Table */
1670             if (WdTable)
1671             {
1672                 /* Check if this PCI device is the ACPI Watchdog Device... */
1673                 UNIMPLEMENTED_DBGBREAK();
1674             }
1675 
1676             /* Check for non-simple devices */
1677             if ((PCI_MULTIFUNCTION_DEVICE(PciData)) ||
1678                 (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV))
1679             {
1680                 /* No subsystem data defined for these kinds of bridges */
1681                 SubVendorId = 0;
1682                 SubSystemId = 0;
1683             }
1684             else
1685             {
1686                 /* Read the subsystem information from the PCI header */
1687                 SubVendorId = PciData->u.type0.SubVendorID;
1688                 SubSystemId = PciData->u.type0.SubSystemID;
1689             }
1690 
1691             /* Get any hack flags for this device */
1692             HackFlags = PciGetHackFlags(PciData->VendorID,
1693                                         PciData->DeviceID,
1694                                         SubVendorId,
1695                                         SubSystemId,
1696                                         PciData->RevisionID);
1697 
1698             /* Check if this device is considered critical by the OS */
1699             if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass))
1700             {
1701                 /* Check if normally the decodes would be disabled */
1702                 if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
1703                 {
1704                     /* Because this device is critical, don't disable them */
1705                     DPRINT1("Not allowing PM Because device is critical\n");
1706                     HackFlags |= PCI_HACK_CRITICAL_DEVICE;
1707                 }
1708             }
1709 
1710             /* PCI bridges with a VGA card are also considered critical */
1711             if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1712                 (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) &&
1713                 (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) &&
1714                !(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
1715             {
1716                 /* Do not disable their decodes either */
1717                 DPRINT1("Not allowing PM because device is VGA\n");
1718                 HackFlags |= PCI_HACK_CRITICAL_DEVICE;
1719             }
1720 
1721             /* Check if the device should be skipped for whatever reason */
1722             if (PciSkipThisFunction(PciData,
1723                                     PciSlot,
1724                                     PCI_SKIP_DEVICE_ENUMERATION,
1725                                     HackFlags))
1726             {
1727                 /* Skip this device */
1728                 continue;
1729             }
1730 
1731             /* Check if a PDO has already been created for this device */
1732             PdoExtension = PciFindPdoByFunction(DeviceExtension,
1733                                                 PciSlot.u.AsULONG,
1734                                                 PciData);
1735             if (PdoExtension)
1736             {
1737                 /* Rescan scenarios are not yet implemented */
1738                 UNIMPLEMENTED_DBGBREAK();
1739             }
1740 
1741             /* Bus processing will need to happen */
1742             ProcessFlag = TRUE;
1743 
1744             /* Create the PDO for this device */
1745             Status = PciPdoCreate(DeviceExtension, PciSlot, &DeviceObject);
1746             ASSERT(NT_SUCCESS(Status));
1747             NewExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
1748 
1749             /* Check for broken devices with wrong/no class codes */
1750             if (HackFlags & PCI_HACK_FAKE_CLASS_CODE)
1751             {
1752                 /* Setup a default one */
1753                 PciData->BaseClass = PCI_CLASS_BASE_SYSTEM_DEV;
1754                 PciData->SubClass = PCI_SUBCLASS_SYS_OTHER;
1755 
1756                 /* Device will behave erratically when reading back data */
1757                 NewExtension->ExpectedWritebackFailure = TRUE;
1758             }
1759 
1760             /* Clone all the information from the header */
1761             NewExtension->VendorId = PciData->VendorID;
1762             NewExtension->DeviceId = PciData->DeviceID;
1763             NewExtension->RevisionId = PciData->RevisionID;
1764             NewExtension->ProgIf = PciData->ProgIf;
1765             NewExtension->SubClass = PciData->SubClass;
1766             NewExtension->BaseClass = PciData->BaseClass;
1767             NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
1768 
1769             /* Check for modern bridge types, which are managed by the driver */
1770             if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1771                 ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
1772                  (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
1773             {
1774                 /* Acquire this device's lock */
1775                 KeEnterCriticalRegion();
1776                 KeWaitForSingleObject(&DeviceExtension->ChildListLock,
1777                                       Executive,
1778                                       KernelMode,
1779                                       FALSE,
1780                                       NULL);
1781 
1782                 /* Scan the bridge list until the first free entry */
1783                 for (BridgeExtension = &DeviceExtension->ChildBridgePdoList;
1784                      *BridgeExtension;
1785                      BridgeExtension = &(*BridgeExtension)->NextBridge);
1786 
1787                 /* Add this PDO as a bridge */
1788                 *BridgeExtension = NewExtension;
1789                 ASSERT(NewExtension->NextBridge == NULL);
1790 
1791                 /* Release this device's lock */
1792                 KeSetEvent(&DeviceExtension->ChildListLock,
1793                            IO_NO_INCREMENT,
1794                            FALSE);
1795                 KeLeaveCriticalRegion();
1796             }
1797 
1798             /* Get the PCI BIOS configuration saved in the registry */
1799             Status = PciGetBiosConfig(NewExtension, BiosData);
1800             if (NT_SUCCESS(Status))
1801             {
1802                 /* This path has not yet been fully tested by eVb */
1803                 DPRINT1("Have BIOS configuration!\n");
1804                 UNIMPLEMENTED;
1805 
1806                 /* Check if the PCI BIOS configuration has changed */
1807                 if (!PcipIsSameDevice(NewExtension, BiosData))
1808                 {
1809                     /* This is considered failure, and new data will be saved */
1810                     Status = STATUS_UNSUCCESSFUL;
1811                 }
1812                 else
1813                 {
1814                     /* Data is still correct, check for interrupt line change */
1815                     if (BiosData->u.type0.InterruptLine !=
1816                         PciData->u.type0.InterruptLine)
1817                     {
1818                         /* Update the current BIOS with the saved interrupt line */
1819                         PciWriteDeviceConfig(NewExtension,
1820                                              &BiosData->u.type0.InterruptLine,
1821                                              FIELD_OFFSET(PCI_COMMON_HEADER,
1822                                                           u.type0.InterruptLine),
1823                                              sizeof(UCHAR));
1824                     }
1825 
1826                     /* Save the BIOS interrupt line and the initial command */
1827                     NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
1828                     NewExtension->InitialCommand = BiosData->Command;
1829                 }
1830             }
1831 
1832             /* Check if no saved data was present or if it was a mismatch */
1833             if (!NT_SUCCESS(Status))
1834             {
1835                 /* Save the new data */
1836                 Status = PciSaveBiosConfig(NewExtension, PciData);
1837                 ASSERT(NT_SUCCESS(Status));
1838 
1839                 /* Save the interrupt line and command from the device */
1840                 NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
1841                 NewExtension->InitialCommand = PciData->Command;
1842             }
1843 
1844             /* Save original command from the device and hack flags */
1845             NewExtension->CommandEnables = PciData->Command;
1846             NewExtension->HackFlags = HackFlags;
1847 
1848             /* Get power, AGP, and other capability data */
1849             PciGetEnhancedCapabilities(NewExtension, PciData);
1850 
1851             /* Now configure the BARs */
1852             Status = PciGetFunctionLimits(NewExtension, PciData, HackFlags);
1853 
1854             /* Power up the device */
1855             PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
1856 
1857             /* Apply any device hacks required for enumeration */
1858             PciApplyHacks(DeviceExtension,
1859                           PciData,
1860                           PciSlot,
1861                           PCI_HACK_FIXUP_AFTER_CONFIGURATION,
1862                           NewExtension);
1863 
1864             /* Save interrupt pin */
1865             NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
1866 
1867             /*
1868              * Use either this device's actual IRQ line or, if it's connected on
1869              * a master bus whose IRQ line is actually connected to the host, use
1870              * the HAL to query the bus' IRQ line and store that as the adjusted
1871              * interrupt line instead
1872              */
1873             NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
1874 
1875             /* Check if this device is used for PCI debugger cards */
1876             NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
1877 
1878             /* Check for devices with invalid/bogus subsystem data */
1879             if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
1880             {
1881                 /* Set the subsystem information to zero instead */
1882                 NewExtension->SubsystemVendorId = 0;
1883                 NewExtension->SubsystemId = 0;
1884             }
1885 
1886             /* Scan all capabilities */
1887             CapOffset = NewExtension->CapabilitiesPtr;
1888             while (CapOffset)
1889             {
1890                 /* Read this header */
1891                 TempOffset = PciReadDeviceCapability(NewExtension,
1892                                                      CapOffset,
1893                                                      0,
1894                                                      &CapHeader,
1895                                                      sizeof(PCI_CAPABILITIES_HEADER));
1896                 if (TempOffset != CapOffset)
1897                 {
1898                     /* This is a strange issue that shouldn't happen normally */
1899                     DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
1900                             CapOffset);
1901                     ASSERT(TempOffset == CapOffset);
1902                 }
1903 
1904                 /* Check for capabilities that this driver cares about */
1905                 switch (CapHeader.CapabilityID)
1906                 {
1907                     /* Power management capability is heavily used by the bus */
1908                     case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
1909 
1910                         /* Dump the capability */
1911                         Name = "POWER";
1912                         Size = sizeof(PCI_PM_CAPABILITY);
1913                         break;
1914 
1915                     /* AGP capability is required for AGP bus functionality */
1916                     case PCI_CAPABILITY_ID_AGP:
1917 
1918                         /* Dump the capability */
1919                         Name = "AGP";
1920                         Size = sizeof(PCI_AGP_CAPABILITY);
1921                         break;
1922 
1923                     /* This driver doesn't really use anything other than that */
1924                     default:
1925 
1926                         /* Windows prints this, we could do a translation later */
1927                         Name = "UNKNOWN CAPABILITY";
1928                         Size = 0;
1929                         break;
1930                 }
1931 
1932                 /* Check if this is a capability that should be dumped */
1933                 if (Size)
1934                 {
1935                     /* Read the whole capability data */
1936                     TempOffset = PciReadDeviceCapability(NewExtension,
1937                                                          CapOffset,
1938                                                          CapHeader.CapabilityID,
1939                                                          &CapHeader,
1940                                                          Size);
1941 
1942                     if (TempOffset != CapOffset)
1943                     {
1944                         /* Again, a strange issue that shouldn't be seen */
1945                         DPRINT1("- Failed to read capability data. ***\n");
1946                         ASSERT(TempOffset == CapOffset);
1947                     }
1948                 }
1949 
1950                 /* Dump this capability */
1951                 DPRINT1("CAP @%02x ID %02x (%s)\n",
1952                         CapOffset, CapHeader.CapabilityID, Name);
1953                 for (i = 0; i < Size; i += 2)
1954                     DPRINT1("  %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i));
1955                 DPRINT1("\n");
1956 
1957                 /* Check the next capability */
1958                 CapOffset = CapHeader.Next;
1959             }
1960 
1961             /* Check for IDE controllers */
1962             if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
1963                 (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
1964             {
1965                 /* Do not allow them to power down completely */
1966                 NewExtension->DisablePowerDown = TRUE;
1967             }
1968 
1969             /*
1970              * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
1971              * bridge that is present on certain NT Alpha machines appears as
1972              * non-classified so detect it manually by scanning for its VID/PID.
1973              */
1974             if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1975                 ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
1976                  (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
1977                  (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
1978                 ((NewExtension->VendorId == 0x8086) &&
1979                  (NewExtension->DeviceId == 0x482)))
1980             {
1981                 /* Do not allow these legacy bridges to be powered down */
1982                 NewExtension->DisablePowerDown = TRUE;
1983             }
1984 
1985             /* Check if the BIOS did not configure a cache line size */
1986             if (!PciData->CacheLineSize)
1987             {
1988                 /* Check if the device is disabled */
1989                 if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE |
1990                                                       PCI_ENABLE_MEMORY_SPACE |
1991                                                       PCI_ENABLE_BUS_MASTER)))
1992                 {
1993                     /* Check if this is a PCI-X device*/
1994                     TempOffset = PciReadDeviceCapability(NewExtension,
1995                                                          NewExtension->CapabilitiesPtr,
1996                                                          PCI_CAPABILITY_ID_PCIX,
1997                                                          &PcixCapHeader,
1998                                                          sizeof(PCI_CAPABILITIES_HEADER));
1999 
2000                     /*
2001                      * A device with default cache line size and latency timer
2002                      * settings is considered to be unconfigured. Note that on
2003                      * PCI-X, the reset value of the latency timer field in the
2004                      * header is 64, not 0, hence why the check for PCI-X caps
2005                      * was required, and the value used here below.
2006                      */
2007                     if (!(PciData->LatencyTimer) ||
2008                         ((TempOffset) && (PciData->LatencyTimer == 64)))
2009                     {
2010                         /* Keep track of the fact that it needs configuration */
2011                         DPRINT1("PCI - ScanBus, PDOx %p found unconfigured\n",
2012                                 NewExtension);
2013                         NewExtension->NeedsHotPlugConfiguration = TRUE;
2014                     }
2015                 }
2016             }
2017 
2018             /* Save latency and cache size information */
2019             NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
2020             NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
2021 
2022             /* The PDO is now ready to go */
2023             DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
2024         }
2025     }
2026 
2027     /* Enumeration completed, do a final pass now that all devices are found */
2028     if (ProcessFlag) PciProcessBus(DeviceExtension);
2029     return STATUS_SUCCESS;
2030 }
2031 
2032 NTSTATUS
2033 NTAPI
PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,IN OUT PDEVICE_RELATIONS * pDeviceRelations)2034 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,
2035                         IN OUT PDEVICE_RELATIONS *pDeviceRelations)
2036 {
2037     NTSTATUS Status;
2038     PPCI_PDO_EXTENSION PdoExtension;
2039     ULONG PdoCount = 0;
2040     PDEVICE_RELATIONS DeviceRelations, NewRelations;
2041     SIZE_T Size;
2042     PDEVICE_OBJECT DeviceObject, *ObjectArray;
2043     PAGED_CODE();
2044 
2045     /* Make sure the FDO is started */
2046     ASSERT(DeviceExtension->DeviceState == PciStarted);
2047 
2048     /* Synchronize while we enumerate the bus */
2049     Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation);
2050     if (!NT_SUCCESS(Status)) return Status;
2051 
2052     /* Scan all children PDO */
2053     for (PdoExtension = DeviceExtension->ChildPdoList;
2054          PdoExtension;
2055          PdoExtension = PdoExtension->Next)
2056     {
2057         /* Invalidate them */
2058         PdoExtension->NotPresent = TRUE;
2059     }
2060 
2061     /* Scan the PCI Bus */
2062     Status = PciScanBus(DeviceExtension);
2063     ASSERT(NT_SUCCESS(Status));
2064 
2065     /* Enumerate all children PDO again */
2066     for (PdoExtension = DeviceExtension->ChildPdoList;
2067          PdoExtension;
2068          PdoExtension = PdoExtension->Next)
2069     {
2070         /* Check for PDOs that are still invalidated */
2071         if (PdoExtension->NotPresent)
2072         {
2073             /* This means this PDO existed before, but not anymore */
2074             PdoExtension->ReportedMissing = TRUE;
2075             DPRINT1("PCI - Old device (pdox) %p not found on rescan.\n",
2076                     PdoExtension);
2077         }
2078         else
2079         {
2080             /* Increase count of detected PDOs */
2081             PdoCount++;
2082         }
2083     }
2084 
2085     /* Read the current relations and add the newly discovered relations */
2086     DeviceRelations = *pDeviceRelations;
2087     Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
2088            PdoCount * sizeof(PDEVICE_OBJECT);
2089     if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
2090 
2091     /* Allocate the device relations */
2092     NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP');
2093     if (!NewRelations)
2094     {
2095         /* Out of space, cancel the operation */
2096         PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation);
2097         return STATUS_INSUFFICIENT_RESOURCES;
2098     }
2099 
2100     /* Check if there were any older relations */
2101     NewRelations->Count = 0;
2102     if (DeviceRelations)
2103     {
2104         /* Copy the old relations into the new buffer, then free the old one */
2105         RtlCopyMemory(NewRelations,
2106                       DeviceRelations,
2107                       FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
2108                       DeviceRelations->Count * sizeof(PDEVICE_OBJECT));
2109         ExFreePoolWithTag(DeviceRelations, 0);
2110     }
2111 
2112     /* Print out that we're ready to dump relations */
2113     DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %p (bus 0x%02x)\n",
2114             DeviceExtension,
2115             DeviceExtension->BaseBus);
2116 
2117     /* Loop the current PDO children and the device relation object array */
2118     PdoExtension = DeviceExtension->ChildPdoList;
2119     ObjectArray = &NewRelations->Objects[NewRelations->Count];
2120     while (PdoExtension)
2121     {
2122         /* Dump this relation */
2123         DPRINT1("  QDR PDO %p (x %p)%s\n",
2124                 PdoExtension->PhysicalDeviceObject,
2125                 PdoExtension,
2126                 PdoExtension->NotPresent ?
2127                 "<Omitted, device flaged not present>" : "");
2128 
2129         /* Is this PDO present? */
2130         if (!PdoExtension->NotPresent)
2131         {
2132             /* Reference it and add it to the array */
2133             DeviceObject = PdoExtension->PhysicalDeviceObject;
2134             ObReferenceObject(DeviceObject);
2135             *ObjectArray++ = DeviceObject;
2136         }
2137 
2138         /* Go to the next PDO */
2139         PdoExtension = PdoExtension->Next;
2140     }
2141 
2142     /* Terminate dumping the relations */
2143     DPRINT1("  QDR Total PDO count = %u (%u already in list)\n",
2144             NewRelations->Count + PdoCount,
2145             NewRelations->Count);
2146 
2147     /* Return the final count and the new buffer */
2148     NewRelations->Count += PdoCount;
2149     *pDeviceRelations = NewRelations;
2150     return STATUS_SUCCESS;
2151 }
2152 
2153 NTSTATUS
2154 NTAPI
PciSetResources(IN PPCI_PDO_EXTENSION PdoExtension,IN BOOLEAN DoReset,IN BOOLEAN SomethingSomethingDarkSide)2155 PciSetResources(IN PPCI_PDO_EXTENSION PdoExtension,
2156                 IN BOOLEAN DoReset,
2157                 IN BOOLEAN SomethingSomethingDarkSide)
2158 {
2159     PPCI_FDO_EXTENSION FdoExtension;
2160     UCHAR NewCacheLineSize, NewLatencyTimer;
2161     PCI_COMMON_HEADER PciData;
2162     BOOLEAN Native;
2163     PPCI_CONFIGURATOR Configurator;
2164 
2165     UNREFERENCED_PARAMETER(SomethingSomethingDarkSide);
2166 
2167     /* Get the FDO and read the configuration data */
2168     FdoExtension = PdoExtension->ParentFdoExtension;
2169     PciReadDeviceConfig(PdoExtension, &PciData, 0, PCI_COMMON_HDR_LENGTH);
2170 
2171     /* Make sure this is still the same device */
2172     if (!PcipIsSameDevice(PdoExtension, &PciData))
2173     {
2174         /* Fail */
2175         ASSERTMSG("PCI Set resources - not same device.\n", FALSE);
2176         return STATUS_DEVICE_DOES_NOT_EXIST;
2177     }
2178 
2179     /* Nothing to set for a host bridge */
2180     if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
2181         (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST))
2182     {
2183         /* Fake success */
2184         return STATUS_SUCCESS;
2185     }
2186 
2187     /* Check if an IDE controller is being reset */
2188     if ((DoReset) &&
2189         (PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
2190         (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
2191     {
2192         /* Turn off native mode */
2193         Native = PciConfigureIdeController(PdoExtension, &PciData, FALSE);
2194         ASSERT(Native == PdoExtension->IDEInNativeMode);
2195     }
2196 
2197     /* Check for update of a hotplug device, or first configuration of one */
2198     if ((PdoExtension->NeedsHotPlugConfiguration) &&
2199         (FdoExtension->HotPlugParameters.Acquired))
2200     {
2201         /* Don't have hotplug devices to test with yet, QEMU 0.14 should */
2202         UNIMPLEMENTED_DBGBREAK();
2203     }
2204 
2205     /* Locate the correct resource configurator for this type of device */
2206     Configurator = &PciConfigurators[PdoExtension->HeaderType];
2207 
2208     /* Apply the settings change */
2209     Configurator->ChangeResourceSettings(PdoExtension, &PciData);
2210 
2211     /* Assume no update needed */
2212     PdoExtension->UpdateHardware = FALSE;
2213 
2214     /* Check if a reset is needed */
2215     if (DoReset)
2216     {
2217         /* Reset resources */
2218         Configurator->ResetDevice(PdoExtension, &PciData);
2219         PciData.u.type0.InterruptLine = PdoExtension->RawInterruptLine;
2220     }
2221 
2222     /* Check if the latency timer changed */
2223     NewLatencyTimer = PdoExtension->SavedLatencyTimer;
2224     if (PciData.LatencyTimer != NewLatencyTimer)
2225     {
2226         /* Debug notification */
2227         DPRINT1("PCI (pdox %p) changing latency from %02x to %02x.\n",
2228                 PdoExtension,
2229                 PciData.LatencyTimer,
2230                 NewLatencyTimer);
2231     }
2232 
2233     /* Check if the cache line changed */
2234     NewCacheLineSize = PdoExtension->SavedCacheLineSize;
2235     if (PciData.CacheLineSize != NewCacheLineSize)
2236     {
2237         /* Debug notification */
2238         DPRINT1("PCI (pdox %p) changing cache line size from %02x to %02x.\n",
2239                 PdoExtension,
2240                 PciData.CacheLineSize,
2241                 NewCacheLineSize);
2242     }
2243 
2244     /* Inherit data from PDO extension */
2245     PciData.LatencyTimer = PdoExtension->SavedLatencyTimer;
2246     PciData.CacheLineSize = PdoExtension->SavedCacheLineSize;
2247     PciData.u.type0.InterruptLine = PdoExtension->RawInterruptLine;
2248 
2249     /* Apply any resource hacks required */
2250     PciApplyHacks(FdoExtension,
2251                   &PciData,
2252                   PdoExtension->Slot,
2253                   PCI_HACK_FIXUP_BEFORE_UPDATE,
2254                   PdoExtension);
2255 
2256     /* Check if I/O space was disabled by administrator or driver */
2257     if (PdoExtension->IoSpaceNotRequired)
2258     {
2259         /* Don't turn on the decode */
2260         PdoExtension->CommandEnables &= ~PCI_ENABLE_IO_SPACE;
2261     }
2262 
2263     /* Update the device with the new settings */
2264     PciUpdateHardware(PdoExtension, &PciData);
2265 
2266     /* Update complete */
2267     PdoExtension->RawInterruptLine = PciData.u.type0.InterruptLine;
2268     PdoExtension->NeedsHotPlugConfiguration = FALSE;
2269     return STATUS_SUCCESS;
2270 }
2271 
2272 /* EOF */
2273