ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

enum.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS PCI Bus Driver
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            drivers/bus/pci/enum.c
00005  * PURPOSE:         PCI Bus/Device Enumeration
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <pci.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* GLOBALS ********************************************************************/
00016 
00017 PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements;
00018 
00019 PCI_CONFIGURATOR PciConfigurators[] =
00020 {
00021     {
00022         Device_MassageHeaderForLimitsDetermination,
00023         Device_RestoreCurrent,
00024         Device_SaveLimits,
00025         Device_SaveCurrentSettings,
00026         Device_ChangeResourceSettings,
00027         Device_GetAdditionalResourceDescriptors,
00028         Device_ResetDevice
00029     },
00030     {
00031         PPBridge_MassageHeaderForLimitsDetermination,
00032         PPBridge_RestoreCurrent,
00033         PPBridge_SaveLimits,
00034         PPBridge_SaveCurrentSettings,
00035         PPBridge_ChangeResourceSettings,
00036         PPBridge_GetAdditionalResourceDescriptors,
00037         PPBridge_ResetDevice
00038     },
00039     {
00040         Cardbus_MassageHeaderForLimitsDetermination,
00041         Cardbus_RestoreCurrent,
00042         Cardbus_SaveLimits,
00043         Cardbus_SaveCurrentSettings,
00044         Cardbus_ChangeResourceSettings,
00045         Cardbus_GetAdditionalResourceDescriptors,
00046         Cardbus_ResetDevice
00047     }
00048 };
00049 
00050 /* FUNCTIONS ******************************************************************/
00051 
00052 BOOLEAN
00053 NTAPI
00054 PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
00055                              IN PCM_RESOURCE_LIST ResourceList)
00056 {
00057     PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, InterruptResource;
00058     PCM_PARTIAL_RESOURCE_DESCRIPTOR BaseResource, CurrentDescriptor;
00059     PCM_PARTIAL_RESOURCE_DESCRIPTOR PreviousDescriptor;
00060     CM_PARTIAL_RESOURCE_DESCRIPTOR ResourceArray[7];
00061     PCM_FULL_RESOURCE_DESCRIPTOR FullList;
00062     BOOLEAN DrainPartial, RangeChange;
00063     ULONG i, j;
00064     PPCI_FUNCTION_RESOURCES PciResources;
00065     PAGED_CODE();
00066 
00067     /* Make sure we have either no resources, or at least one */
00068     ASSERT((ResourceList == NULL) || (ResourceList->Count == 1));
00069 
00070     /* Initialize no partial, interrupt descriptor, or range change */
00071     Partial = NULL;
00072     InterruptResource = NULL;
00073     RangeChange = FALSE;
00074 
00075     /* Check if there's not actually any resources */
00076     if (!(ResourceList) || !(ResourceList->Count))
00077     {
00078         /* Then just return the hardware update state */
00079         return PdoExtension->UpdateHardware;
00080     }
00081 
00082     /* Print the new specified resource list */
00083     PciDebugPrintCmResList(ResourceList);
00084 
00085     /* Clear the temporary resource array */
00086     for (i = 0; i < 7; i++) ResourceArray[i].Type = CmResourceTypeNull;
00087 
00088     /* Loop the full resource descriptor */
00089     FullList = ResourceList->List;
00090     for (i = 0; i < ResourceList->Count; i++)
00091     {
00092         /* Initialize loop variables */
00093         DrainPartial = FALSE;
00094         BaseResource = NULL;
00095 
00096         /* Loop the partial descriptors */
00097         Partial = FullList->PartialResourceList.PartialDescriptors;
00098         for (j = 0; j < FullList->PartialResourceList.Count; j++)
00099         {
00100             /* Check if we were supposed to drain a partial due to device data */
00101             if (DrainPartial)
00102             {
00103                 /* Draining complete, move on to the next descriptor then */
00104                 DrainPartial--;
00105                 continue;
00106             }
00107 
00108             /* Check what kind of descriptor this was */
00109             switch (Partial->Type)
00110             {
00111                 /* Base BAR resources */
00112                 case CmResourceTypePort:
00113                 case CmResourceTypeMemory:
00114 
00115                     /* Set it as the base */
00116                     ASSERT(BaseResource == NULL);
00117                     BaseResource = Partial;
00118                     break;
00119 
00120                 /* Interrupt resource */
00121                 case CmResourceTypeInterrupt:
00122 
00123                     /* Make sure it's a compatible (and the only) PCI interrupt */
00124                     ASSERT(InterruptResource == NULL);
00125                     ASSERT(Partial->u.Interrupt.Level == Partial->u.Interrupt.Vector);
00126                     InterruptResource = Partial;
00127 
00128                     /* Only 255 interrupts on x86/x64 hardware */
00129                     if (Partial->u.Interrupt.Level < 256)
00130                     {
00131                         /* Use the passed interrupt line */
00132                         PdoExtension->AdjustedInterruptLine = Partial->u.Interrupt.Level;
00133                     }
00134                     else
00135                     {
00136                         /* Invalid vector, so ignore it */
00137                         PdoExtension->AdjustedInterruptLine = 0;
00138                     }
00139 
00140                     break;
00141 
00142                 /* Check for specific device data */
00143                 case CmResourceTypeDevicePrivate:
00144 
00145                     /* Check what kind of data this was */
00146                     switch (Partial->u.DevicePrivate.Data[0])
00147                     {
00148                         /* Not used in the driver yet */
00149                         case 1:
00150                             UNIMPLEMENTED;
00151                             while (TRUE);
00152                             break;
00153 
00154                         /* Not used in the driver yet */
00155                         case 2:
00156                             UNIMPLEMENTED;
00157                             while (TRUE);
00158                             break;
00159 
00160                         /* A drain request */
00161                         case 3:
00162                             /* Shouldn't be a base resource, this is a drain */
00163                             ASSERT(BaseResource == NULL);
00164                             DrainPartial = Partial->u.DevicePrivate.Data[1];
00165                             ASSERT(DrainPartial == TRUE);
00166                             break;
00167                     }
00168                     break;
00169             }
00170 
00171             /* Move to the next descriptor */
00172             Partial = PciNextPartialDescriptor(Partial);
00173         }
00174 
00175         /* We should be starting a new list now */
00176         ASSERT(BaseResource == NULL);
00177         FullList = (PVOID)Partial;
00178     }
00179 
00180     /* Check the current assigned PCI resources */
00181     PciResources = PdoExtension->Resources;
00182     if (!PciResources) return FALSE;
00183 
00184     //if... // MISSING CODE
00185     UNIMPLEMENTED;
00186     DPRINT1("Missing sanity checking code!\n");
00187 
00188     /* Loop all the PCI function resources */
00189     for (i = 0; i < 7; i++)
00190     {
00191         /* Get the current function resource descriptor, and the new one */
00192         CurrentDescriptor = &PciResources->Current[i];
00193         Partial = &ResourceArray[i];
00194 
00195         /* Previous is current during the first loop iteration */
00196         PreviousDescriptor = &PciResources->Current[(i == 0) ? (0) : (i - 1)];
00197 
00198         /* Check if this new descriptor is different than the old one */
00199         if (((Partial->Type != CurrentDescriptor->Type) ||
00200              (Partial->Type != CmResourceTypeNull)) &&
00201             ((Partial->u.Generic.Start.QuadPart !=
00202               CurrentDescriptor->u.Generic.Start.QuadPart) ||
00203              (Partial->u.Generic.Length != CurrentDescriptor->u.Generic.Length)))
00204         {
00205             /* Record a change */
00206             RangeChange = TRUE;
00207 
00208             /* Was there a range before? */
00209             if (CurrentDescriptor->Type != CmResourceTypeNull)
00210             {
00211                 /* Print it */
00212                 DbgPrint("      Old range-\n");
00213                 PciDebugPrintPartialResource(CurrentDescriptor);
00214             }
00215             else
00216             {
00217                 /* There was no range */
00218                 DbgPrint("      Previously unset range\n");
00219             }
00220 
00221             /* Print new one */
00222             DbgPrint("      changed to\n");
00223             PciDebugPrintPartialResource(Partial);
00224 
00225             /* Update to new range */
00226             CurrentDescriptor->Type = Partial->Type;
00227             PreviousDescriptor->u.Generic.Start = Partial->u.Generic.Start;
00228             PreviousDescriptor->u.Generic.Length = Partial->u.Generic.Length;
00229             CurrentDescriptor = PreviousDescriptor;
00230         }
00231     }
00232 
00233     /* Either the hardware was updated, or a resource range changed */
00234     return ((RangeChange) || (PdoExtension->UpdateHardware));
00235 }
00236 
00237 VOID
00238 NTAPI
00239 PcipUpdateHardware(IN PVOID Context,
00240                    IN PVOID Context2)
00241 {
00242     PPCI_PDO_EXTENSION PdoExtension = Context;
00243     PPCI_COMMON_HEADER PciData = Context2;
00244 
00245     /* Check if we're allowed to disable decodes */
00246     PciData->Command = PdoExtension->CommandEnables;
00247     if (!(PdoExtension->HackFlags & PCI_HACK_PRESERVE_COMMAND))
00248     {
00249         /* Disable all decodes */
00250         PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
00251                               PCI_ENABLE_MEMORY_SPACE |
00252                               PCI_ENABLE_BUS_MASTER |
00253                               PCI_ENABLE_WRITE_AND_INVALIDATE);
00254     }
00255 
00256     /* Update the device configuration */
00257     PciData->Status = 0;
00258     PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
00259 
00260     /* Turn decodes back on */
00261     PciDecodeEnable(PdoExtension, TRUE, &PdoExtension->CommandEnables);
00262 }
00263 
00264 VOID
00265 NTAPI
00266 PciUpdateHardware(IN PPCI_PDO_EXTENSION PdoExtension,
00267                   IN PPCI_COMMON_HEADER PciData)
00268 {
00269     PCI_IPI_CONTEXT Context;
00270 
00271     /* Check for critical devices and PCI Debugging devices */
00272     if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
00273         (PdoExtension->OnDebugPath))
00274     {
00275         /* Build the context and send an IPI */
00276         Context.RunCount = 1;
00277         Context.Barrier = 1;
00278         Context.Context = PciData;
00279         Context.Function = PcipUpdateHardware;
00280         Context.DeviceExtension = PdoExtension;
00281         KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&Context);
00282     }
00283     else
00284     {
00285         /* Just to the update inline */
00286         PcipUpdateHardware(PdoExtension, PciData);
00287     }
00288 }
00289 
00290 PIO_RESOURCE_REQUIREMENTS_LIST
00291 NTAPI
00292 PciAllocateIoRequirementsList(IN ULONG Count,
00293                               IN ULONG BusNumber,
00294                               IN ULONG SlotNumber)
00295 {
00296     SIZE_T Size;
00297     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
00298 
00299     /* Calculate the final size of the list, including each descriptor */
00300     Size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
00301     if (Count > 1) Size = sizeof(IO_RESOURCE_DESCRIPTOR) * (Count - 1) +
00302                           sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
00303 
00304     /* Allocate the list */
00305     RequirementsList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
00306     if (!RequirementsList) return NULL;
00307 
00308     /* Initialize it */
00309     RtlZeroMemory(RequirementsList, Size);
00310     RequirementsList->AlternativeLists = 1;
00311     RequirementsList->BusNumber = BusNumber;
00312     RequirementsList->SlotNumber = SlotNumber;
00313     RequirementsList->InterfaceType = PCIBus;
00314     RequirementsList->ListSize = Size;
00315     RequirementsList->List[0].Count = Count;
00316     RequirementsList->List[0].Version = 1;
00317     RequirementsList->List[0].Revision = 1;
00318 
00319     /* Return it */
00320     return RequirementsList;
00321 }
00322 
00323 PCM_RESOURCE_LIST
00324 NTAPI
00325 PciAllocateCmResourceList(IN ULONG Count,
00326                           IN ULONG BusNumber)
00327 {
00328     SIZE_T Size;
00329     PCM_RESOURCE_LIST ResourceList;
00330 
00331     /* Calculate the final size of the list, including each descriptor */
00332     Size = sizeof(CM_RESOURCE_LIST);
00333     if (Count > 1) Size = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count - 1) +
00334                           sizeof(CM_RESOURCE_LIST);
00335 
00336     /* Allocate the list */
00337     ResourceList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
00338     if (!ResourceList) return NULL;
00339 
00340     /* Initialize it */
00341     RtlZeroMemory(ResourceList, Size);
00342     ResourceList->Count = 1;
00343     ResourceList->List[0].BusNumber = BusNumber;
00344     ResourceList->List[0].InterfaceType = PCIBus;
00345     ResourceList->List[0].PartialResourceList.Version = 1;
00346     ResourceList->List[0].PartialResourceList.Revision = 1;
00347     ResourceList->List[0].PartialResourceList.Count = Count;
00348 
00349     /* Return it */
00350     return ResourceList;
00351 }
00352 
00353 NTSTATUS
00354 NTAPI
00355 PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension,
00356                   OUT PCM_RESOURCE_LIST *Buffer)
00357 {
00358     PPCI_FUNCTION_RESOURCES PciResources;
00359     BOOLEAN HaveVga, HaveMemSpace, HaveIoSpace;
00360     USHORT BridgeControl, PciCommand;
00361     ULONG Count, i;
00362     PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, Resource, LastResource;
00363     PCM_RESOURCE_LIST ResourceList;
00364     UCHAR InterruptLine;
00365     PAGED_CODE();
00366 
00367     /* Assume failure */
00368     Count = 0;
00369     HaveVga = FALSE;
00370     *Buffer = NULL;
00371 
00372     /* Make sure there's some resources to query */
00373     PciResources = PdoExtension->Resources;
00374     if (!PciResources) return STATUS_SUCCESS;
00375 
00376     /* Read the decodes */
00377     PciReadDeviceConfig(PdoExtension,
00378                         &PciCommand,
00379                         FIELD_OFFSET(PCI_COMMON_HEADER, Command),
00380                         sizeof(USHORT));
00381 
00382     /* Check which ones are turned on */
00383     HaveIoSpace = PciCommand & PCI_ENABLE_IO_SPACE;
00384     HaveMemSpace = PciCommand & PCI_ENABLE_MEMORY_SPACE;
00385 
00386     /* Loop maximum possible descriptors */
00387     for (i = 0; i < 7; i++)
00388     {
00389         /* Check if the decode for this descriptor is actually turned on */
00390         Partial = &PciResources->Current[i];
00391         if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
00392             ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
00393         {
00394             /* One more fully active descriptor */
00395             Count++;
00396         }
00397     }
00398 
00399     /* If there's an interrupt pin associated, check at least one decode is on */
00400     if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
00401     {
00402         /* Read the interrupt line for the pin, add a descriptor if it's valid */
00403         InterruptLine = PdoExtension->AdjustedInterruptLine;
00404         if ((InterruptLine) && (InterruptLine != -1)) Count++;
00405     }
00406 
00407     /* Check for PCI bridge */
00408     if (PdoExtension->HeaderType == PCI_BRIDGE_TYPE)
00409     {
00410         /* Read bridge settings, check if VGA is present */
00411         PciReadDeviceConfig(PdoExtension,
00412                             &BridgeControl,
00413                             FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BridgeControl),
00414                             sizeof(USHORT));
00415         if (BridgeControl & PCI_ENABLE_BRIDGE_VGA)
00416         {
00417             /* Remember for later */
00418             HaveVga = TRUE;
00419 
00420             /* One memory descriptor for 0xA0000, plus the two I/O port ranges */
00421             if (HaveMemSpace) Count++;
00422             if (HaveIoSpace) Count += 2;
00423         }
00424     }
00425 
00426     /* If there's no descriptors in use, there's no resources, so return */
00427     if (!Count) return STATUS_SUCCESS;
00428 
00429     /* Allocate a resource list to hold the resources */
00430     ResourceList = PciAllocateCmResourceList(Count,
00431                                              PdoExtension->ParentFdoExtension->BaseBus);
00432     if (!ResourceList) return STATUS_INSUFFICIENT_RESOURCES;
00433 
00434     /* This is where the descriptors will be copied into */
00435     Resource = ResourceList->List[0].PartialResourceList.PartialDescriptors;
00436     LastResource = Resource + Count + 1;
00437 
00438     /* Loop maximum possible descriptors */
00439     for (i = 0; i < 7; i++)
00440     {
00441         /* Check if the decode for this descriptor is actually turned on */
00442         Partial = &PciResources->Current[i];
00443         if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
00444             ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
00445         {
00446             /* Copy the descriptor into the resource list */
00447             *Resource++ = *Partial;
00448         }
00449     }
00450 
00451     /* Check if earlier the code detected this was a PCI bridge with VGA on it */
00452     if (HaveVga)
00453     {
00454         /* Are the memory decodes enabled? */
00455         if (HaveMemSpace)
00456         {
00457             /* Build a memory descriptor for a 128KB framebuffer at 0xA0000 */
00458             Resource->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
00459             Resource->u.Generic.Start.HighPart = 0;
00460             Resource->Type = CmResourceTypeMemory;
00461             Resource->u.Generic.Start.LowPart = 0xA0000;
00462             Resource->u.Generic.Length = 0x20000;
00463             Resource++;
00464         }
00465 
00466         /* Are the I/O decodes enabled? */
00467         if (HaveIoSpace)
00468         {
00469             /* Build an I/O descriptor for the graphic ports at 0x3B0 */
00470             Resource->Type = CmResourceTypePort;
00471             Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
00472             Resource->u.Port.Start.QuadPart = 0x3B0u;
00473             Resource->u.Port.Length = 0xC;
00474             Resource++;
00475 
00476             /* Build an I/O descriptor for the graphic ports at 0x3C0 */
00477             Resource->Type = CmResourceTypePort;
00478             Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
00479             Resource->u.Port.Start.QuadPart = 0x3C0u;
00480             Resource->u.Port.Length = 0x20;
00481             Resource++;
00482         }
00483     }
00484 
00485     /* If there's an interrupt pin associated, check at least one decode is on */
00486     if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
00487     {
00488          /* Read the interrupt line for the pin, check if it's valid */
00489          InterruptLine = PdoExtension->AdjustedInterruptLine;
00490          if ((InterruptLine) && (InterruptLine != -1))
00491          {
00492              /* Make sure there's still space */
00493              ASSERT(Resource < LastResource);
00494 
00495              /* Add the interrupt descriptor */
00496              Resource->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
00497              Resource->Type = CmResourceTypeInterrupt;
00498              Resource->ShareDisposition = CmResourceShareShared;
00499              Resource->u.Interrupt.Affinity = -1;
00500              Resource->u.Interrupt.Level = InterruptLine;
00501              Resource->u.Interrupt.Vector = InterruptLine;
00502         }
00503     }
00504 
00505     /* Return the resouce list */
00506     *Buffer = ResourceList;
00507     return STATUS_SUCCESS;
00508 }
00509 
00510 NTSTATUS
00511 NTAPI
00512 PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension,
00513                               IN OUT PDEVICE_RELATIONS *pDeviceRelations)
00514 {
00515     PDEVICE_RELATIONS DeviceRelations;
00516     PAGED_CODE();
00517 
00518     /* If there were existing relations, free them */
00519     if (*pDeviceRelations) ExFreePoolWithTag(*pDeviceRelations, 0);
00520 
00521     /* Allocate a new structure for the relations */
00522     DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
00523                                             sizeof(DEVICE_RELATIONS),
00524                                             'BicP');
00525     if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES;
00526 
00527     /* Only one relation: the PDO */
00528     DeviceRelations->Count = 1;
00529     DeviceRelations->Objects[0] = PdoExtension->PhysicalDeviceObject;
00530     ObReferenceObject(DeviceRelations->Objects[0]);
00531 
00532     /* Return the new relations */
00533     *pDeviceRelations = DeviceRelations;
00534     return STATUS_SUCCESS;
00535 }
00536 
00537 NTSTATUS
00538 NTAPI
00539 PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension,
00540                           IN OUT PDEVICE_RELATIONS *pDeviceRelations)
00541 {
00542     /* Not yet implemented */
00543     UNIMPLEMENTED;
00544     while (TRUE);
00545 }
00546 
00547 NTSTATUS
00548 NTAPI
00549 PciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension,
00550                          IN PPCI_COMMON_HEADER PciData,
00551                          OUT PIO_RESOURCE_REQUIREMENTS_LIST* Buffer)
00552 {
00553     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
00554     {
00555         /* There aren't, so use the zero descriptor */
00556         RequirementsList = PciZeroIoResourceRequirements;
00557 
00558         /* Does it actually exist yet? */
00559         if (!PciZeroIoResourceRequirements)
00560         {
00561             /* Allocate it, and use it for future use */
00562             RequirementsList = PciAllocateIoRequirementsList(0, 0, 0);
00563             PciZeroIoResourceRequirements = RequirementsList;
00564             if (!PciZeroIoResourceRequirements) return STATUS_INSUFFICIENT_RESOURCES;
00565         }
00566 
00567         /* Return the zero requirements list to the caller */
00568         *Buffer = RequirementsList;
00569         DPRINT1("PCI - build resource reqs - early out, 0 resources\n");
00570         return STATUS_SUCCESS;
00571     }
00572     return STATUS_SUCCESS;
00573 }
00574 
00575 NTSTATUS
00576 NTAPI
00577 PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension,
00578                      IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList)
00579 {
00580     NTSTATUS Status;
00581     PCI_COMMON_HEADER PciHeader;
00582     PAGED_CODE();
00583 
00584     /* Check if the PDO has any resources, or at least an interrupt pin */
00585     if ((PdoExtension->Resources) || (PdoExtension->InterruptPin))
00586     {
00587         /* Read the current PCI header */
00588         PciReadDeviceConfig(PdoExtension, &PciHeader, 0, PCI_COMMON_HDR_LENGTH);
00589 
00590         /* Use it to build a list of requirements */
00591         Status = PciBuildRequirementsList(PdoExtension, &PciHeader, RequirementsList);
00592         if (!NT_SUCCESS(Status)) return Status;
00593 
00594         /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
00595         if ((PciHeader.VendorID == 0xE11) &&
00596             (PciHeader.DeviceID == 0xA0F7) &&
00597             (PciHeader.RevisionID == 17) &&
00598             (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
00599         {
00600             /* Have not tested this on eVb's machine yet */
00601             UNIMPLEMENTED;
00602             while (TRUE);
00603         }
00604 
00605         /* Check if the requirements are actually the zero list */
00606         if (*RequirementsList == PciZeroIoResourceRequirements)
00607         {
00608             /* A simple NULL will sufficie for the PnP Manager */
00609             *RequirementsList = NULL;
00610             DPRINT1("Returning NULL requirements list\n");
00611         }
00612         else
00613         {
00614             /* Otherwise, print out the requirements list */
00615             PciDebugPrintIoResReqList(*RequirementsList);
00616         }
00617     }
00618     else
00619     {
00620         /* There aren't any resources, so simply return NULL */
00621         DPRINT1("PciQueryRequirements returning NULL requirements list\n");
00622         *RequirementsList = NULL;
00623     }
00624 
00625     /* This call always succeeds (but maybe with no requirements) */
00626     return STATUS_SUCCESS;
00627 }
00628 
00629 /*
00630  * 7. The IO/MEM/Busmaster decodes are disabled for the device.
00631  * 8. The PCI bus driver sets the operating mode bits of the Programming
00632  *    Interface byte to switch the controller to native mode.
00633  *
00634  *    Important: When the controller is set to native mode, it must quiet itself
00635  *    and must not decode I/O resources or generate interrupts until the operating
00636  *    system has enabled the ports in the PCI configuration header.
00637  *    The IO/MEM/BusMaster bits will be disabled before the mode change, but it
00638  *    is not possible to disable interrupts on the device. The device must not
00639  *    generate interrupts (either legacy or native mode) while the decodes are
00640  *    disabled in the command register.
00641  *
00642  *    This operation is expected to be instantaneous and the operating system does
00643  *    not stall afterward. It is also expected that the interrupt pin register in
00644  *    the PCI Configuration space for this device is accurate. The operating system
00645  *    re-reads this data after previously ignoring it.
00646  */
00647 BOOLEAN
00648 NTAPI
00649 PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,
00650                           IN PPCI_COMMON_HEADER PciData,
00651                           IN BOOLEAN Initial)
00652 {
00653     UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf;
00654     BOOLEAN Switched;
00655     USHORT Command;
00656 
00657     /* Assume it won't work */
00658     Switched = FALSE;
00659 
00660     /* Get master and slave current settings, and programmability flag */
00661     ProgIf = PciData->ProgIf;
00662     MasterMode = (ProgIf & 1) == 1;
00663     MasterFixed = (ProgIf & 2) == 0;
00664     SlaveMode = (ProgIf & 4) == 4;
00665     SlaveFixed = (ProgIf & 8) == 0;
00666 
00667     /*
00668      * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
00669      * ATA controller from compatible mode to native mode, the following must be
00670      * true:
00671      *
00672      * - The controller must indicate in its programming interface that both channels
00673      *   can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
00674      *   not support switching only one IDE channel to native mode. See the PCI IDE
00675      *   Controller Specification Revision 1.0 for details.
00676      */
00677     if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed))
00678     {
00679         /* Windows does not support this configuration, fail */
00680         DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
00681                 PdoExtension->VendorId,
00682                 PdoExtension->DeviceId);
00683         return Switched;
00684     }
00685 
00686     /* Check if the controller is already in native mode */
00687     if ((MasterMode) && (SlaveMode))
00688     {
00689         /* Check if I/O decodes should be disabled */
00690         if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl))
00691         {
00692             /* Read the current command */
00693             PciReadDeviceConfig(PdoExtension,
00694                                 &Command,
00695                                 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
00696                                 sizeof(USHORT));
00697 
00698             /* Disable I/O space decode */
00699             Command &= ~PCI_ENABLE_IO_SPACE;
00700 
00701             /* Update new command in PCI IDE controller */
00702             PciWriteDeviceConfig(PdoExtension,
00703                                  &Command,
00704                                  FIELD_OFFSET(PCI_COMMON_HEADER, Command),
00705                                  sizeof(USHORT));
00706 
00707             /* Save updated command value */
00708             PciData->Command = Command;
00709         }
00710 
00711         /* The controller is now in native mode */
00712         Switched = TRUE;
00713     }
00714     else if (!(MasterFixed) &&
00715              !(SlaveFixed) &&
00716              (PdoExtension->BIOSAllowsIDESwitchToNativeMode) &&
00717              !(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE))
00718     {
00719         /* Turn off decodes */
00720         PciDecodeEnable(PdoExtension, FALSE, NULL);
00721 
00722         /* Update the current command */
00723         PciReadDeviceConfig(PdoExtension,
00724                             &PciData->Command,
00725                             FIELD_OFFSET(PCI_COMMON_HEADER, Command),
00726                             sizeof(USHORT));
00727 
00728         /* Enable native mode */
00729         ProgIf = PciData->ProgIf | 5;
00730         PciWriteDeviceConfig(PdoExtension,
00731                              &ProgIf,
00732                              FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
00733                              sizeof(UCHAR));
00734 
00735         /* Verify the setting "stuck" */
00736         PciReadDeviceConfig(PdoExtension,
00737                             &NewProgIf,
00738                             FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
00739                             sizeof(UCHAR));
00740         if (NewProgIf == ProgIf)
00741         {
00742             /* Update the header and PDO data with the new programming mode */
00743             PciData->ProgIf = ProgIf;
00744             PdoExtension->ProgIf = NewProgIf;
00745 
00746             /* Clear the first four BARs to reset current BAR setttings */
00747             PciData->u.type0.BaseAddresses[0] = 0;
00748             PciData->u.type0.BaseAddresses[1] = 0;
00749             PciData->u.type0.BaseAddresses[2] = 0;
00750             PciData->u.type0.BaseAddresses[3] = 0;
00751             PciWriteDeviceConfig(PdoExtension,
00752                                  PciData->u.type0.BaseAddresses,
00753                                  FIELD_OFFSET(PCI_COMMON_HEADER,
00754                                               u.type0.BaseAddresses),
00755                                  4 * sizeof(ULONG));
00756 
00757             /* Re-read the BARs to have the latest data for native mode IDE */
00758             PciReadDeviceConfig(PdoExtension,
00759                                 PciData->u.type0.BaseAddresses,
00760                                 FIELD_OFFSET(PCI_COMMON_HEADER,
00761                                              u.type0.BaseAddresses),
00762                                 4 * sizeof(ULONG));
00763 
00764             /* Re-read the interrupt pin used for native mode IDE */
00765             PciReadDeviceConfig(PdoExtension,
00766                                 &PciData->u.type0.InterruptPin,
00767                                 FIELD_OFFSET(PCI_COMMON_HEADER,
00768                                              u.type0.InterruptPin),
00769                                 sizeof(UCHAR));
00770 
00771             /* The IDE Controller is now in native mode */
00772             Switched = TRUE;
00773         }
00774         else
00775         {
00776             /* Settings did not work, fail */
00777             DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
00778                     PciData->VendorID,
00779                     PciData->DeviceID);
00780         }
00781    }
00782 
00783    /* Return whether or not native mode was enabled on the IDE controller */
00784    return Switched;
00785 }
00786 
00787 VOID
00788 NTAPI
00789 PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,
00790               IN PPCI_COMMON_HEADER PciData,
00791               IN PCI_SLOT_NUMBER SlotNumber,
00792               IN ULONG OperationType,
00793               PPCI_PDO_EXTENSION PdoExtension)
00794 {
00795     ULONG LegacyBaseAddress;
00796     USHORT Command;
00797     UCHAR RegValue;
00798 
00799     /* Check what kind of hack operation this is */
00800     switch (OperationType)
00801     {
00802         /*
00803          * This is mostly concerned with fixing up incorrect class data that can
00804          * exist on certain PCI hardware before the 2.0 spec was ratified.
00805          */
00806         case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
00807 
00808             /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
00809              * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
00810              * and appear as non-classified, so their correct class/subclass data
00811              * is written here instead.
00812              */
00813             if ((PciData->VendorID == 0x8086) &&
00814                 ((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484)))
00815             {
00816                 /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
00817                 PciData->SubClass = PciData->DeviceID == 0x482 ?
00818                                     PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA;
00819                 PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
00820 
00821                 /*
00822                  * Because the software is modifying the actual header data from
00823                  * the BIOS, this flag tells the driver to ignore failures when
00824                  * comparing the original BIOS data with the PCI data.
00825                  */
00826                 if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE;
00827             }
00828 
00829             /* Note that in this case, an immediate return is issued */
00830             return;
00831 
00832         /*
00833          * This is concerned with setting up interrupts correctly for native IDE
00834          * mode, but will also handle broken VGA decoding on older bridges as
00835          * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
00836          */
00837         case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
00838 
00839             /* There should always be a PDO extension passed in */
00840             ASSERT(PdoExtension);
00841 
00842             /*
00843              * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
00844              * and FreeBSD bug reports indicate that the system crashes when the
00845              * feature is enabled (so it's disabled on that OS as well). In the
00846              * NT PCI Bus Driver, it seems Microsoft too, completely disables
00847              * Native IDE functionality on this controller, so it would seem OPTi
00848              * simply frelled up this controller.
00849              */
00850             if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621))
00851             {
00852                 /* Disable native mode */
00853                 PciData->ProgIf &= ~5;
00854                 PciData->u.type0.InterruptPin = 0;
00855 
00856                 /*
00857                  * Because the software is modifying the actual header data from
00858                  * the BIOS, this flag tells the driver to ignore failures when
00859                  * comparing the original BIOS data with the PCI data.
00860                  */
00861                 PdoExtension->ExpectedWritebackFailure = TRUE;
00862             }
00863             else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
00864                     (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
00865             {
00866                 /* For other IDE controllers, start out in compatible mode */
00867                 PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
00868 
00869                 /*
00870                  * Registry must have enabled native mode (typically as a result
00871                  * of an INF file directive part of the IDE controller's driver)
00872                  * and the system must not be booted in Safe Mode. If that checks
00873                  * out, then evaluate the ACPI NATA method to see if the platform
00874                  * supports this. See the section "BIOS and Platform Prerequisites
00875                  * for Switching a Native-Mode-Capable Controller" in the Storage
00876                  * section of the Windows Driver Kit for more details:
00877                  *
00878                  * 5. For each ATA controller enumerated, the PCI bus driver checks
00879                  *    the Programming Interface register of the IDE controller to
00880                  *    see if it supports switching both channels to native mode.
00881                  * 6. The PCI bus driver checks whether the BIOS/platform supports
00882                  *    switching the controller by checking the NATA method described
00883                  *    earlier in this article.
00884                  *
00885                  *    If an ATA controller does not indicate that it is native
00886                  *    mode-capable, or if the BIOS NATA control method is missing
00887                  *    or does not list that device, the PCI bus driver does not
00888                  *    switch the controller and it is assigned legacy resources.
00889                  *
00890                  *  If both the controller and the BIOS indicate that the controller
00891                  *  can be switched, the process of switching the controller begins
00892                  *  with the next step.
00893                  */
00894                 if ((PciEnableNativeModeATA) &&
00895                     !(InitSafeBootMode) &&
00896                     (PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN')))
00897                 {
00898                     /* The platform supports it, remember that */
00899                     PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
00900 
00901                     /*
00902                      * Now switch the controller into native mode if both channels
00903                      * support native IDE mode. See "How Windows Switches an ATA
00904                      * Controller to Native Mode" in the Storage section of the
00905                      * Windows Driver Kit for more details.
00906                      */
00907                     PdoExtension->IDEInNativeMode =
00908                         PciConfigureIdeController(PdoExtension, PciData, TRUE);
00909                 }
00910 
00911                 /* Is native mode enabled after all? */
00912                 if ((PciData->ProgIf & 5) != 5)
00913                 {
00914                     /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
00915                     PciData->u.type0.InterruptPin = 0;
00916                 }
00917             }
00918 
00919             /* Is this a PCI device with legacy VGA card decodes on the root bus? */
00920             if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) &&
00921                 (PCI_IS_ROOT_FDO(DeviceExtension)) &&
00922                 !(DeviceExtension->BrokenVideoHackApplied))
00923             {
00924                 /* Tell the arbiter to apply a hack for these older devices */
00925                 ario_ApplyBrokenVideoHack(DeviceExtension);
00926             }
00927 
00928             /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
00929             if ((PciData->VendorID == 0xE11) &&
00930                 (PciData->DeviceID == 0xA0F7) &&
00931                 (PciData->RevisionID == 17) &&
00932                 (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
00933             {
00934                 /* Turn off the decodes immediately */
00935                 PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
00936                                       PCI_ENABLE_MEMORY_SPACE |
00937                                       PCI_ENABLE_BUS_MASTER);
00938                 PciWriteDeviceConfig(PdoExtension,
00939                                      &PciData->Command,
00940                                      FIELD_OFFSET(PCI_COMMON_HEADER, Command),
00941                                      sizeof(USHORT));
00942 
00943                 /* Do not EVER turn them on again, this will blow up the system */
00944                 PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE |
00945                                                   PCI_ENABLE_MEMORY_SPACE |
00946                                                   PCI_ENABLE_BUS_MASTER);
00947                 PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND;
00948             }
00949             break;
00950 
00951         /*
00952          * This is called whenever resources are changed and hardware needs to be
00953          * updated. It is concerned with two highly specific erratas on an IBM
00954          * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
00955          * ICH PCI Bridges.
00956          */
00957         case PCI_HACK_FIXUP_BEFORE_UPDATE:
00958 
00959             /* There should always be a PDO extension passed in */
00960             ASSERT(PdoExtension);
00961 
00962             /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
00963             if ((PdoExtension->VendorId == 0x1014) &&
00964                 (PdoExtension->DeviceId == 0x95))
00965             {
00966                 /* Read the current command */
00967                 PciReadDeviceConfig(PdoExtension,
00968                                     &Command,
00969                                     FIELD_OFFSET(PCI_COMMON_HEADER, Command),
00970                                     sizeof(USHORT));
00971 
00972                 /* Turn off the decodes */
00973                 PciDecodeEnable(PdoExtension, FALSE, &Command);
00974 
00975                 /* Apply the required IBM workaround */
00976                 PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
00977                 RegValue &= ~2;
00978                 RegValue |= 1;
00979                 PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
00980 
00981                 /* Restore the command to its original value */
00982                 PciWriteDeviceConfig(PdoExtension,
00983                                      &Command,
00984                                      FIELD_OFFSET(PCI_COMMON_HEADER, Command),
00985                                      sizeof(USHORT));
00986 
00987             }
00988 
00989             /*
00990              * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
00991              * i820, i840, i845 Chipsets) that have subtractive decode enabled,
00992              * and whose hack flags do not specifiy that this support is broken.
00993              */
00994             if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) &&
00995                 (PdoExtension->Dependent.type1.SubtractiveDecode) &&
00996                 ((PdoExtension->VendorId == 0x8086) &&
00997                  ((PdoExtension->DeviceId == 0x2418) ||
00998                   (PdoExtension->DeviceId == 0x2428) ||
00999                   (PdoExtension->DeviceId == 0x244E) ||
01000                   (PdoExtension->DeviceId == 0x2448))) &&
01001                !(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
01002             {
01003                 /*
01004                  * The positive decode window shouldn't be used, these values are
01005                  * normally all read-only or initialized to 0 by the BIOS, but
01006                  * it appears Intel doesn't do this, so the PCI Bus Driver will
01007                  * do it in software instead. Note that this is used to prevent
01008                  * certain non-compliant PCI devices from breaking down due to the
01009                  * fact that these ICH bridges have a known "quirk" (which Intel
01010                  * documents as a known "erratum", although it's not not really
01011                  * an ICH bug since the PCI specification does allow for it) in
01012                  * that they will sometimes send non-zero addresses during special
01013                  * cycles (ie: non-zero data during the address phase). These
01014                  * broken PCI cards will mistakenly attempt to claim the special
01015                  * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
01016                  * defense, the PCI specification only requires stable data, not
01017                  * necessarily zero data, during the address phase.
01018                  */
01019                 PciData->u.type1.MemoryBase = 0xFFFF;
01020                 PciData->u.type1.PrefetchBase = 0xFFFF;
01021                 PciData->u.type1.IOBase = 0xFF;
01022                 PciData->u.type1.IOLimit = 0;
01023                 PciData->u.type1.MemoryLimit = 0;
01024                 PciData->u.type1.PrefetchLimit = 0;
01025                 PciData->u.type1.PrefetchBaseUpper32 = 0;
01026                 PciData->u.type1.PrefetchLimitUpper32 = 0;
01027                 PciData->u.type1.IOBaseUpper16 = 0;
01028                 PciData->u.type1.IOLimitUpper16 = 0;
01029             }
01030             break;
01031 
01032         default:
01033             return;
01034     }
01035 
01036     /* Finally, also check if this is this a CardBUS device? */
01037     if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
01038     {
01039         /*
01040          * At offset 44h the LegacyBaseAddress is stored, which is cleared by
01041          * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
01042          * CardBus controllers. For more information, see "Supporting CardBus
01043          * Controllers under ACPI" in the "CardBus Controllers and Windows"
01044          * Whitepaper on WHDC.
01045          */
01046         LegacyBaseAddress = 0;
01047         PciWriteDeviceConfig(PdoExtension,
01048                              &LegacyBaseAddress,
01049                              sizeof(PCI_COMMON_HEADER) + sizeof(ULONG),
01050                              sizeof(ULONG));
01051     }
01052 }
01053 
01054 BOOLEAN
01055 NTAPI
01056 PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
01057                  IN PPCI_COMMON_HEADER PciData)
01058 {
01059     BOOLEAN IdMatch, RevMatch, SubsysMatch;
01060     ULONGLONG HackFlags = DeviceExtension->HackFlags;
01061 
01062     /* Check if the IDs match */
01063     IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
01064               (PciData->DeviceID == DeviceExtension->DeviceId);
01065     if (!IdMatch) return FALSE;
01066 
01067     /* If the device has a valid revision, check if it matches */
01068     RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
01069                (PciData->RevisionID == DeviceExtension->RevisionId);
01070     if (!RevMatch) return FALSE;
01071 
01072     /* For multifunction devices, this is enough to assume they're the same */
01073     if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
01074 
01075     /* For bridge devices, there's also nothing else that can be checked */
01076     if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
01077 
01078     /* Devices, on the other hand, have subsystem data that can be compared */
01079     SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
01080                                 PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
01081                   ((DeviceExtension->SubsystemVendorId ==
01082                     PciData->u.type0.SubVendorID) &&
01083                    (DeviceExtension->SubsystemId ==
01084                     PciData->u.type0.SubSystemID));
01085     return SubsysMatch;
01086 }
01087 
01088 BOOLEAN
01089 NTAPI
01090 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
01091                     IN PCI_SLOT_NUMBER Slot,
01092                     IN UCHAR OperationType,
01093                     IN ULONGLONG HackFlags)
01094 {
01095     do
01096     {
01097         /* Check if this is device enumeration */
01098         if (OperationType == PCI_SKIP_DEVICE_ENUMERATION)
01099         {
01100             /* Check if there's a hackflag saying not to enumerate this device */
01101             if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
01102 
01103             /* Check if this is the high end of a double decker device */
01104             if ((HackFlags & PCI_HACK_DOUBLE_DECKER) &&
01105                 (Slot.u.bits.DeviceNumber >= 16))
01106             {
01107                 /* It belongs to the same device, so skip it */
01108                 DPRINT1("    Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
01109                         PciData->VendorID,
01110                         PciData->DeviceID,
01111                         Slot.u.bits.DeviceNumber,
01112                         Slot.u.bits.FunctionNumber);
01113                 break;
01114             }
01115         }
01116         else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)
01117         {
01118             /* Resource enumeration, check for a hackflag saying not to do it */
01119             if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break;
01120         }
01121         else
01122         {
01123             /* Logic error in the driver */
01124             ASSERTMSG(FALSE, "PCI Skip Function - Operation type unknown.");
01125         }
01126 
01127         /* Check for legacy bridges during resource enumeration */
01128         if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
01129             (PciData->SubClass <= PCI_SUBCLASS_BR_MCA) &&
01130             (OperationType == PCI_SKIP_RESOURCE_ENUMERATION))
01131         {
01132             /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
01133             break;
01134         }
01135         else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED)
01136         {
01137             /* Undefined base class (usually a PCI BIOS/ROM bug) */
01138             DPRINT1("    Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
01139                     PciData->VendorID,
01140                     PciData->DeviceID);
01141 
01142             /*
01143              * The Alder has an Intel Extended Express System Support Controller
01144              * which presents apparently spurious BARs. When the PCI resource
01145              * code tries to reassign these BARs, the second IO-APIC gets
01146              * disabled (with disastrous consequences). The first BAR is the
01147              * actual IO-APIC, the remaining five bars seem to be spurious
01148              * resources, so ignore this device completely.
01149              */
01150             if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break;
01151         }
01152 
01153         /* Other normal PCI cards and bridges are enumerated */
01154         if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE;
01155     } while (FALSE);
01156 
01157     /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
01158     DPRINT1("   Device skipped (not enumerated).\n");
01159     return TRUE;
01160 }
01161 
01162 VOID
01163 NTAPI
01164 PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
01165                            IN PPCI_COMMON_HEADER PciData)
01166 {
01167     ULONG HeaderType, CapPtr, TargetAgpCapabilityId;
01168     DEVICE_POWER_STATE WakeLevel;
01169     PCI_CAPABILITIES_HEADER AgpCapability;
01170     PCI_PM_CAPABILITY PowerCapabilities;
01171     PAGED_CODE();
01172 
01173     /* Assume no known wake level */
01174     PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
01175 
01176     /* Make sure the device has capabilities */
01177     if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST))
01178     {
01179         /* If it doesn't, there will be no power management */
01180         PdoExtension->CapabilitiesPtr = 0;
01181         PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
01182     }
01183     else
01184     {
01185         /* There's capabilities, need to figure out where to get the offset */
01186         HeaderType = PCI_CONFIGURATION_TYPE(PciData);
01187         if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE)
01188         {
01189             /* Use the bridge's header */
01190             CapPtr = PciData->u.type2.CapabilitiesPtr;
01191         }
01192         else
01193         {
01194             /* Use the device header */
01195             ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE);
01196             CapPtr = PciData->u.type0.CapabilitiesPtr;
01197         }
01198 
01199         /* Skip garbage capabilities pointer */
01200         if (((CapPtr & 0x3) != 0) || (CapPtr < PCI_COMMON_HDR_LENGTH))
01201         {
01202             /* Report no extended capabilities */
01203             PdoExtension->CapabilitiesPtr = 0;
01204             PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
01205         }
01206         else
01207         {
01208             DPRINT1("Device has capabilities at: %lx\n", CapPtr);
01209             PdoExtension->CapabilitiesPtr = CapPtr;
01210 
01211             /* Check for PCI-to-PCI Bridges and AGP bridges */
01212             if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
01213                 ((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) ||
01214                  (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)))
01215             {
01216                 /* Query either the raw AGP capabilitity, or the Target AGP one */
01217                 TargetAgpCapabilityId = (PdoExtension->SubClass ==
01218                                          PCI_SUBCLASS_BR_PCI_TO_PCI) ?
01219                 PCI_CAPABILITY_ID_AGP_TARGET :
01220                 PCI_CAPABILITY_ID_AGP;
01221                 if (PciReadDeviceCapability(PdoExtension,
01222                                             PdoExtension->CapabilitiesPtr,
01223                                             TargetAgpCapabilityId,
01224                                             &AgpCapability,
01225                                             sizeof(PCI_CAPABILITIES_HEADER)))
01226                 {
01227                     /* AGP target ID was found, store it */
01228                     DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId);
01229                     PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId;
01230                 }
01231             }
01232 
01233             /* Check for devices that are known not to have proper power management */
01234             if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
01235             {
01236                 /* Query if this device supports power management */
01237                 if (!PciReadDeviceCapability(PdoExtension,
01238                                              PdoExtension->CapabilitiesPtr,
01239                                              PCI_CAPABILITY_ID_POWER_MANAGEMENT,
01240                                              &PowerCapabilities.Header,
01241                                              sizeof(PCI_PM_CAPABILITY)))
01242                 {
01243                     /* No power management, so act as if it had the hackflag set */
01244                     DPRINT1("No PM caps, disabling PM\n");
01245                     PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
01246                 }
01247                 else
01248                 {
01249                     /* Otherwise, pick the highest wake level that is supported */
01250                     WakeLevel = PowerDeviceUnspecified;
01251                     if (PowerCapabilities.PMC.Capabilities.Support.PMED0)
01252                         WakeLevel = PowerDeviceD0;
01253                     if (PowerCapabilities.PMC.Capabilities.Support.PMED1)
01254                         WakeLevel = PowerDeviceD1;
01255                     if (PowerCapabilities.PMC.Capabilities.Support.PMED2)
01256                         WakeLevel = PowerDeviceD2;
01257                     if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot)
01258                         WakeLevel = PowerDeviceD3;
01259                     if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold)
01260                         WakeLevel = PowerDeviceD3;
01261                     PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
01262 
01263                     /* Convert the PCI power state to the NT power state */
01264                     PdoExtension->PowerState.CurrentDeviceState =
01265                     PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
01266 
01267                     /* Save all the power capabilities */
01268                     PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities;
01269                     DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
01270                             WakeLevel, PdoExtension->PowerState.CurrentDeviceState);
01271                 }
01272             }
01273         }
01274     }
01275 
01276     /* At the very end of all this, does this device not have power management? */
01277     if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
01278     {
01279         /* Then guess the current state based on whether the decodes are on */
01280         PdoExtension->PowerState.CurrentDeviceState =
01281             PciData->Command & (PCI_ENABLE_IO_SPACE |
01282                                 PCI_ENABLE_MEMORY_SPACE |
01283                                 PCI_ENABLE_BUS_MASTER) ?
01284             PowerDeviceD0: PowerDeviceD3;
01285         DPRINT1("PM is off, so assumed device is: %d based on enables\n",
01286                 PdoExtension->PowerState.CurrentDeviceState);
01287     }
01288 }
01289 
01290 VOID
01291 NTAPI
01292 PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved,
01293                                 IN PVOID Context2)
01294 {
01295     PPCI_CONFIGURATOR_CONTEXT Context = Context2;
01296     PPCI_COMMON_HEADER PciData, Current;
01297     PPCI_PDO_EXTENSION PdoExtension;
01298 
01299     /* Grab all parameters from the context */
01300     PdoExtension = Context->PdoExtension;
01301     Current = Context->Current;
01302     PciData = Context->PciData;
01303 
01304     /* Write the limit discovery header */
01305     PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
01306 
01307     /* Now read what the device indicated the limits are */
01308     PciReadDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
01309 
01310     /* Then write back the original configuration header */
01311     PciWriteDeviceConfig(PdoExtension, Current, 0, PCI_COMMON_HDR_LENGTH);
01312 
01313     /* Copy back the original command that was saved in the context */
01314     Current->Command = Context->Command;
01315     if (Context->Command)
01316     {
01317         /* Program it back into the device */
01318         PciWriteDeviceConfig(PdoExtension,
01319                              &Context->Command,
01320                              FIELD_OFFSET(PCI_COMMON_HEADER, Command),
01321                              sizeof(USHORT));
01322     }
01323 
01324     /* Copy back the original status that was saved as well */
01325     Current->Status = Context->Status;
01326 
01327     /* Call the configurator to restore any other data that might've changed */
01328     Context->Configurator->RestoreCurrent(Context);
01329 }
01330 
01331 NTSTATUS
01332 NTAPI
01333 PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
01334 {
01335     PPCI_CONFIGURATOR Configurator;
01336     PPCI_COMMON_HEADER PciData, Current;
01337     PPCI_PDO_EXTENSION PdoExtension;
01338     PCI_IPI_CONTEXT IpiContext;
01339     PIO_RESOURCE_DESCRIPTOR IoDescriptor;
01340     ULONG Offset;
01341     PAGED_CODE();
01342 
01343     /* Grab all parameters from the context */
01344     PdoExtension = Context->PdoExtension;
01345     Current = Context->Current;
01346     PciData = Context->PciData;
01347 
01348     /* Save the current PCI Command and Status word */
01349     Context->Status = Current->Status;
01350     Context->Command = Current->Command;
01351 
01352     /* Now that they're saved, clear the status, and disable all decodes */
01353     Current->Status = 0;
01354     Current->Command &= ~(PCI_ENABLE_IO_SPACE |
01355                           PCI_ENABLE_MEMORY_SPACE |
01356                           PCI_ENABLE_BUS_MASTER);
01357 
01358     /* Make a copy of the current PCI configuration header (with decodes off) */
01359     RtlCopyMemory(PciData, Current, PCI_COMMON_HDR_LENGTH);
01360 
01361     /* Locate the correct resource configurator for this type of device */
01362     Configurator = &PciConfigurators[PdoExtension->HeaderType];
01363     Context->Configurator = Configurator;
01364 
01365     /* Initialize it, which will typically setup the BARs for limit discovery */
01366     Configurator->Initialize(Context);
01367 
01368     /* Check for critical devices and PCI Debugging devices */
01369     if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
01370         (PdoExtension->OnDebugPath))
01371     {
01372         /* Specifically check for a PCI Debugging device */
01373         if (PdoExtension->OnDebugPath)
01374         {
01375             /* Was it enabled for bus mastering? */
01376             if (Context->Command & PCI_ENABLE_BUS_MASTER)
01377             {
01378                 /* This decode needs to be re-enabled so debugging can work */
01379                 PciData->Command |= PCI_ENABLE_BUS_MASTER;
01380                 Current->Command |= PCI_ENABLE_BUS_MASTER;
01381             }
01382 
01383             /* Disable the debugger while the discovery is happening */
01384             KdDisableDebugger();
01385         }
01386 
01387         /* For these devices, an IPI must be sent to force high-IRQL discovery */
01388         IpiContext.Barrier = 1;
01389         IpiContext.RunCount = 1;
01390         IpiContext.DeviceExtension = PdoExtension;
01391         IpiContext.Function = PciWriteLimitsAndRestoreCurrent;
01392         IpiContext.Context = Context;
01393         KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&IpiContext);
01394 
01395         /* Re-enable the debugger if this was a PCI Debugging Device */
01396         if (PdoExtension->OnDebugPath) KdEnableDebugger();
01397     }
01398     else
01399     {
01400         /* Otherwise, it's safe to do this in-line at low IRQL */
01401         PciWriteLimitsAndRestoreCurrent(PdoExtension, Context);
01402     }
01403 
01404     /*
01405      * Check if it's valid to compare the headers to see if limit discovery mode
01406      * has properly exited (the expected case is that the PCI header would now
01407      * be equal to what it was before). In some cases, it is known that this will
01408      * fail, because during PciApplyHacks (among other places), software hacks
01409      * had to be applied to the header, which the hardware-side will not see, and
01410      * thus the headers would appear "different".
01411      */
01412     if (!PdoExtension->ExpectedWritebackFailure)
01413     {
01414         /* Read the current PCI header now, after discovery has completed */
01415         PciReadDeviceConfig(PdoExtension, PciData + 1, 0, PCI_COMMON_HDR_LENGTH);
01416 
01417         /* Check if the current header at entry, is equal to the header now */
01418         Offset = RtlCompareMemory(PciData + 1, Current, PCI_COMMON_HDR_LENGTH);
01419         if (Offset != PCI_COMMON_HDR_LENGTH)
01420         {
01421             /* It's not, which means configuration somehow changed, dump this */
01422             DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset);
01423             PciDebugDumpCommonConfig(PciData + 1);
01424             DPRINT1("----------\n");
01425             PciDebugDumpCommonConfig(Current);
01426         }
01427     }
01428 
01429     /* This PDO should not already have resources, since this is only done once */
01430     ASSERT(PdoExtension->Resources == NULL);
01431 
01432     /* Allocate the structure that will hold the discovered resources and limits */
01433     PdoExtension->Resources = ExAllocatePoolWithTag(NonPagedPool,
01434                                                     sizeof(PCI_FUNCTION_RESOURCES),
01435                                                     'BicP');
01436     if (!PdoExtension->Resources) return STATUS_INSUFFICIENT_RESOURCES;
01437 
01438     /* Clear it out for now */
01439     RtlZeroMemory(PdoExtension->Resources, sizeof(PCI_FUNCTION_RESOURCES));
01440 
01441     /* Now call the configurator, which will first store the limits... */
01442     Configurator->SaveLimits(Context);
01443 
01444     /* ...and then store the current resources being used */
01445     Configurator->SaveCurrentSettings(Context);
01446 
01447     /* Loop all the limit descriptors backwards */
01448     IoDescriptor = &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1];
01449     while (TRUE)
01450     {
01451         /* Keep going until a non-null descriptor is found */
01452         IoDescriptor--;
01453         if (IoDescriptor->Type != CmResourceTypeNull) break;
01454 
01455         /* This is a null descriptor, is it the last one? */
01456         if (IoDescriptor == &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1])
01457         {
01458             /* This means the descriptor is NULL, which means discovery failed */
01459             DPRINT1("PCI Resources fail!\n");
01460 
01461             /* No resources will be assigned for the device */
01462             ExFreePoolWithTag(PdoExtension->Resources, 0);
01463             PdoExtension->Resources = NULL;
01464             break;
01465         }
01466     }
01467 
01468     /* Return success here, even if the device has no assigned resources */
01469     return STATUS_SUCCESS;
01470 }
01471 
01472 NTSTATUS
01473 NTAPI
01474 PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension,
01475                      IN PPCI_COMMON_HEADER Current,
01476                      IN ULONGLONG HackFlags)
01477 {
01478     NTSTATUS Status;
01479     PPCI_COMMON_HEADER PciData;
01480     PCI_CONFIGURATOR_CONTEXT Context;
01481     PAGED_CODE();
01482 
01483     /* Do the hackflags indicate this device should be skipped? */
01484     if (PciSkipThisFunction(Current,
01485                             PdoExtension->Slot,
01486                             PCI_SKIP_RESOURCE_ENUMERATION,
01487                             HackFlags))
01488     {
01489         /* Do not process its resources */
01490         return STATUS_SUCCESS;
01491     }
01492 
01493     /* Allocate a buffer to hold two PCI configuration headers */
01494     PciData = ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH, 'BicP');
01495     if (!PciData) return STATUS_INSUFFICIENT_RESOURCES;
01496 
01497     /* Set up the context for the resource enumeration, and do it */
01498     Context.Current = Current;
01499     Context.PciData = PciData;
01500     Context.PdoExtension = PdoExtension;
01501     Status = PcipGetFunctionLimits(&Context);
01502 
01503     /* Enumeration is completed, free the PCI headers and return the status */
01504     ExFreePoolWithTag(PciData, 0);
01505     return Status;
01506 }
01507 
01508 VOID
01509 NTAPI
01510 PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension)
01511 {
01512     PPCI_PDO_EXTENSION PdoExtension;
01513     PDEVICE_OBJECT PhysicalDeviceObject;
01514     PAGED_CODE();
01515 
01516     /* Get the PDO Extension */
01517     PhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject;
01518     PdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
01519 
01520     /* Cheeck if this is the root bus */
01521     if (!PCI_IS_ROOT_FDO(DeviceExtension))
01522     {
01523         /* Not really handling this year */
01524         UNIMPLEMENTED;
01525         while (TRUE);
01526 
01527         /* Check for PCI bridges with the ISA bit set, or required */
01528         if ((PdoExtension) &&
01529             (PciClassifyDeviceType(PdoExtension) == PciTypePciBridge) &&
01530             ((PdoExtension->Dependent.type1.IsaBitRequired) ||
01531              (PdoExtension->Dependent.type1.IsaBitSet)))
01532         {
01533             /* We'll need to do some legacy support */
01534             UNIMPLEMENTED;
01535             while (TRUE);
01536         }
01537     }
01538     else
01539     {
01540         /* Scan all of the root bus' children bridges */
01541         for (PdoExtension = DeviceExtension->ChildBridgePdoList;
01542              PdoExtension;
01543              PdoExtension = PdoExtension->NextBridge)
01544         {
01545             /* Find any that have the VGA decode bit on */
01546             if (PdoExtension->Dependent.type1.VgaBitSet)
01547             {
01548                 /* Again, some more legacy support we'll have to do */
01549                 UNIMPLEMENTED;
01550                 while (TRUE);
01551             }
01552         }
01553     }
01554 
01555     /* Check for ACPI systems where the OS assigns bus numbers */
01556     if (PciAssignBusNumbers)
01557     {
01558         /* Not yet supported */
01559         UNIMPLEMENTED;
01560         while (TRUE);
01561     }
01562 }
01563 
01564 NTSTATUS
01565 NTAPI
01566 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
01567 {
01568     ULONG MaxDevice = PCI_MAX_DEVICES;
01569     BOOLEAN ProcessFlag = FALSE;
01570     ULONG i, j, k, Size;
01571     USHORT CapOffset, TempOffset;
01572     LONGLONG HackFlags;
01573     PDEVICE_OBJECT DeviceObject;
01574     UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
01575     UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
01576     PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
01577     PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
01578     PCI_SLOT_NUMBER PciSlot;
01579     PCHAR Name;
01580     NTSTATUS Status;
01581     PPCI_PDO_EXTENSION PdoExtension, NewExtension;
01582     PPCI_PDO_EXTENSION* BridgeExtension;
01583     PWCHAR DescriptionText;
01584     USHORT SubVendorId, SubSystemId;
01585     PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader;
01586     UCHAR SecondaryBus;
01587     DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
01588             DeviceExtension, DeviceExtension->BaseBus);
01589 
01590     /* Is this the root FDO? */
01591     if (!PCI_IS_ROOT_FDO(DeviceExtension))
01592     {
01593         /* Get the PDO for the child bus */
01594         PdoExtension = DeviceExtension->PhysicalDeviceObject->DeviceExtension;
01595         ASSERT_PDO(PdoExtension);
01596 
01597         /* Check for hack which only allows bus to have one child device */
01598         if (PdoExtension->HackFlags & PCI_HACK_ONE_CHILD) MaxDevice = 1;
01599       
01600         /* Check if the secondary bus number has changed */
01601         PciReadDeviceConfig(PdoExtension,
01602                             &SecondaryBus,
01603                             FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.SecondaryBus),
01604                             sizeof(UCHAR));
01605         if (SecondaryBus != PdoExtension->Dependent.type1.SecondaryBus)
01606         {
01607             DPRINT1("PCI: Bus numbers have been changed!  Restoring originals.\n");
01608             UNIMPLEMENTED;
01609             while (TRUE);
01610         }
01611     }
01612 
01613     /* Loop every device on the bus */
01614     PciSlot.u.bits.Reserved = 0;
01615     i = DeviceExtension->BaseBus;
01616     for (j = 0; j < MaxDevice; j++)
01617     {
01618         /* Loop every function of each device */
01619         PciSlot.u.bits.DeviceNumber = j;
01620         for (k = 0; k < PCI_MAX_FUNCTION; k++)
01621         {
01622             /* Build the final slot structure */
01623             PciSlot.u.bits.FunctionNumber = k;
01624 
01625             /* Read the vendor for this slot */
01626             PciReadSlotConfig(DeviceExtension,
01627                               PciSlot,
01628                               PciData,
01629                               0,
01630                               sizeof(USHORT));
01631 
01632             /* Skip invalid device */
01633             if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
01634 
01635             /* Now read the whole header */
01636             PciReadSlotConfig(DeviceExtension,
01637                               PciSlot,
01638                               &PciData->DeviceID,
01639                               sizeof(USHORT),
01640                               PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
01641 
01642             /* Apply any hacks before even analyzing the configuration header */
01643             PciApplyHacks(DeviceExtension,
01644                           PciData,
01645                           PciSlot,
01646                           PCI_HACK_FIXUP_BEFORE_CONFIGURATION,
01647                           NULL);
01648 
01649             /* Dump device that was found */
01650             DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
01651                     PciSlot.u.AsULONG,
01652                     i,
01653                     j,
01654                     k);
01655 
01656             /* Dump the device's header */
01657             PciDebugDumpCommonConfig(PciData);
01658 
01659             /* Find description for this device for the debugger's sake */
01660             DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
01661                                                              PciData->SubClass);
01662             DPRINT1("Device Description \"%S\".\n",
01663                     DescriptionText ? DescriptionText : L"(NULL)");
01664             if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
01665 
01666             /* Check if there is an ACPI Watchdog Table */
01667             if (WdTable)
01668             {
01669                 /* Check if this PCI device is the ACPI Watchdog Device... */
01670                 UNIMPLEMENTED;
01671                 while (TRUE);
01672             }
01673 
01674             /* Check for non-simple devices */
01675             if ((PCI_MULTIFUNCTION_DEVICE(PciData)) ||
01676                 (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV))
01677             {
01678                 /* No subsystem data defined for these kinds of bridges */
01679                 SubVendorId = 0;
01680                 SubSystemId = 0;
01681             }
01682             else
01683             {
01684                 /* Read the subsystem information from the PCI header */
01685                 SubVendorId = PciData->u.type0.SubVendorID;
01686                 SubSystemId = PciData->u.type0.SubSystemID;
01687             }
01688 
01689             /* Get any hack flags for this device */
01690             HackFlags = PciGetHackFlags(PciData->VendorID,
01691                                         PciData->DeviceID,
01692                                         SubVendorId,
01693                                         SubSystemId,
01694                                         PciData->RevisionID);
01695 
01696             /* Check if this device is considered critical by the OS */
01697             if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass))
01698             {
01699                 /* Check if normally the decodes would be disabled */
01700                 if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
01701                 {
01702                     /* Because this device is critical, don't disable them */
01703                     DPRINT1("Not allowing PM Because device is critical\n");
01704                     HackFlags |= PCI_HACK_CRITICAL_DEVICE;
01705                 }
01706             }
01707 
01708             /* PCI bridges with a VGA card are also considered critical */
01709             if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
01710                 (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) &&
01711                 (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) &&
01712                !(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
01713             {
01714                 /* Do not disable their decodes either */
01715                 DPRINT1("Not allowing PM because device is VGA\n");
01716                 HackFlags |= PCI_HACK_CRITICAL_DEVICE;
01717             }
01718 
01719             /* Check if the device should be skipped for whatever reason */
01720             if (PciSkipThisFunction(PciData,
01721                                     PciSlot,
01722                                     PCI_SKIP_DEVICE_ENUMERATION,
01723                                     HackFlags))
01724             {
01725                 /* Skip this device */
01726                 continue;
01727             }
01728 
01729             /* Check if a PDO has already been created for this device */
01730             PdoExtension = PciFindPdoByFunction(DeviceExtension,
01731                                                 PciSlot.u.AsULONG,
01732                                                 PciData);
01733             if (PdoExtension)
01734             {
01735                 /* Rescan scenarios are not yet implemented */
01736                 UNIMPLEMENTED;
01737                 while (TRUE);
01738             }
01739 
01740             /* Bus processing will need to happen */
01741             ProcessFlag = TRUE;
01742 
01743             /* Create the PDO for this device */
01744             Status = PciPdoCreate(DeviceExtension, PciSlot, &DeviceObject);
01745             ASSERT(NT_SUCCESS(Status));
01746             NewExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
01747 
01748             /* Check for broken devices with wrong/no class codes */
01749             if (HackFlags & PCI_HACK_FAKE_CLASS_CODE)
01750             {
01751                 /* Setup a default one */
01752                 PciData->BaseClass = PCI_CLASS_BASE_SYSTEM_DEV;
01753                 PciData->SubClass = PCI_SUBCLASS_SYS_OTHER;
01754 
01755                 /* Device will behave erratically when reading back data */
01756                 NewExtension->ExpectedWritebackFailure = TRUE;
01757             }
01758 
01759             /* Clone all the information from the header */
01760             NewExtension->VendorId = PciData->VendorID;
01761             NewExtension->DeviceId = PciData->DeviceID;
01762             NewExtension->RevisionId = PciData->RevisionID;
01763             NewExtension->ProgIf = PciData->ProgIf;
01764             NewExtension->SubClass = PciData->SubClass;
01765             NewExtension->BaseClass = PciData->BaseClass;
01766             NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
01767 
01768             /* Check for modern bridge types, which are managed by the driver */
01769             if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
01770                 ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
01771                  (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
01772             {
01773                 /* Acquire this device's lock */
01774                 KeEnterCriticalRegion();
01775                 KeWaitForSingleObject(&DeviceExtension->ChildListLock,
01776                                       Executive,
01777                                       KernelMode,
01778                                       FALSE,
01779                                       NULL);
01780 
01781                 /* Scan the bridge list until the first free entry */
01782                 for (BridgeExtension = &DeviceExtension->ChildBridgePdoList;
01783                      *BridgeExtension;
01784                      BridgeExtension = &(*BridgeExtension)->NextBridge);
01785 
01786                 /* Add this PDO as a bridge */
01787                 *BridgeExtension = NewExtension;
01788                 ASSERT(NewExtension->NextBridge == NULL);
01789 
01790                 /* Release this device's lock */
01791                 KeSetEvent(&DeviceExtension->ChildListLock,
01792                            IO_NO_INCREMENT,
01793                            FALSE);
01794                 KeLeaveCriticalRegion();
01795             }
01796 
01797             /* Get the PCI BIOS configuration saved in the registry */
01798             Status = PciGetBiosConfig(NewExtension, BiosData);
01799             if (NT_SUCCESS(Status))
01800             {
01801                 /* This path has not yet been fully tested by eVb */
01802                 DPRINT1("Have BIOS configuration!\n");
01803                 UNIMPLEMENTED;
01804 
01805                 /* Check if the PCI BIOS configuration has changed */
01806                 if (!PcipIsSameDevice(NewExtension, BiosData))
01807                 {
01808                     /* This is considered failure, and new data will be saved */
01809                     Status = STATUS_UNSUCCESSFUL;
01810                 }
01811                 else
01812                 {
01813                     /* Data is still correct, check for interrupt line change */
01814                     if (BiosData->u.type0.InterruptLine !=
01815                         PciData->u.type0.InterruptLine)
01816                     {
01817                         /* Update the current BIOS with the saved interrupt line */
01818                         PciWriteDeviceConfig(NewExtension,
01819                                              &BiosData->u.type0.InterruptLine,
01820                                              FIELD_OFFSET(PCI_COMMON_HEADER,
01821                                                           u.type0.InterruptLine),
01822                                              sizeof(UCHAR));
01823                     }
01824 
01825                     /* Save the BIOS interrupt line and the initial command */
01826                     NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
01827                     NewExtension->InitialCommand = BiosData->Command;
01828                 }
01829             }
01830 
01831             /* Check if no saved data was present or if it was a mismatch */
01832             if (!NT_SUCCESS(Status))
01833             {
01834                 /* Save the new data */
01835                 Status = PciSaveBiosConfig(NewExtension, PciData);
01836                 ASSERT(NT_SUCCESS(Status));
01837 
01838                 /* Save the interrupt line and command from the device */
01839                 NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
01840                 NewExtension->InitialCommand = PciData->Command;
01841             }
01842 
01843             /* Save original command from the device and hack flags */
01844             NewExtension->CommandEnables = PciData->Command;
01845             NewExtension->HackFlags = HackFlags;
01846 
01847             /* Get power, AGP, and other capability data */
01848             PciGetEnhancedCapabilities(NewExtension, PciData);
01849 
01850             /* Now configure the BARs */
01851             Status = PciGetFunctionLimits(NewExtension, PciData, HackFlags);
01852 
01853             /* Power up the device */
01854             PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
01855 
01856             /* Apply any device hacks required for enumeration */
01857             PciApplyHacks(DeviceExtension,
01858                           PciData,
01859                           PciSlot,
01860                           PCI_HACK_FIXUP_AFTER_CONFIGURATION,
01861                           NewExtension);
01862 
01863             /* Save interrupt pin */
01864             NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
01865 
01866             /*
01867              * Use either this device's actual IRQ line or, if it's connected on
01868              * a master bus whose IRQ line is actually connected to the host, use
01869              * the HAL to query the bus' IRQ line and store that as the adjusted
01870              * interrupt line instead
01871              */
01872             NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
01873 
01874             /* Check if this device is used for PCI debugger cards */
01875             NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
01876 
01877             /* Check for devices with invalid/bogus subsystem data */
01878             if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
01879             {
01880                 /* Set the subsystem information to zero instead */
01881                 NewExtension->SubsystemVendorId = 0;
01882                 NewExtension->SubsystemId = 0;
01883             }
01884 
01885             /* Scan all capabilities */
01886             CapOffset = NewExtension->CapabilitiesPtr;
01887             while (CapOffset)
01888             {
01889                 /* Read this header */
01890                 TempOffset = PciReadDeviceCapability(NewExtension,
01891                                                      CapOffset,
01892                                                      0,
01893                                                      &CapHeader,
01894                                                      sizeof(PCI_CAPABILITIES_HEADER));
01895                 if (TempOffset != CapOffset)
01896                 {
01897                     /* This is a strange issue that shouldn't happen normally */
01898                     DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
01899                             CapOffset);
01900                     ASSERT(TempOffset == CapOffset);
01901                 }
01902 
01903                 /* Check for capabilities that this driver cares about */
01904                 switch (CapHeader.CapabilityID)
01905                 {
01906                     /* Power management capability is heavily used by the bus */
01907                     case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
01908 
01909                         /* Dump the capability */
01910                         Name = "POWER";
01911                         Size = sizeof(PCI_PM_CAPABILITY);
01912                         break;
01913 
01914                     /* AGP capability is required for AGP bus functionality */
01915                     case PCI_CAPABILITY_ID_AGP:
01916 
01917                         /* Dump the capability */
01918                         Name = "AGP";
01919                         Size = sizeof(PCI_AGP_CAPABILITY);
01920                         break;
01921 
01922                     /* This driver doesn't really use anything other than that */
01923                     default:
01924 
01925                         /* Windows prints this, we could do a translation later */
01926                         Name = "UNKNOWN CAPABILITY";
01927                         Size = 0;
01928                         break;
01929                 }
01930 
01931                 /* Check if this is a capability that should be dumped */
01932                 if (Size)
01933                 {
01934                     /* Read the whole capability data */
01935                     TempOffset = PciReadDeviceCapability(NewExtension,
01936                                                          CapOffset,
01937                                                          CapHeader.CapabilityID,
01938                                                          &CapHeader,
01939                                                          Size);
01940 
01941                     if (TempOffset != CapOffset)
01942                     {
01943                         /* Again, a strange issue that shouldn't be seen */
01944                         DPRINT1("- Failed to read capability data. ***\n");
01945                         ASSERT(TempOffset == CapOffset);
01946                     }
01947                 }
01948 
01949                 /* Dump this capability */
01950                 DPRINT1("CAP @%02x ID %02x (%s)\n",
01951                         CapOffset, CapHeader.CapabilityID, Name);
01952                 for (i = 0; i < Size; i += 2)
01953                     DPRINT1("  %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i));
01954                 DPRINT1("\n");
01955 
01956                 /* Check the next capability */
01957                 CapOffset = CapHeader.Next;
01958             }
01959 
01960             /* Check for IDE controllers */
01961             if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
01962                 (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
01963             {
01964                 /* Do not allow them to power down completely */
01965                 NewExtension->DisablePowerDown = TRUE;
01966             }
01967 
01968             /*
01969              * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
01970              * bridge that is present on certain NT Alpha machines appears as
01971              * non-classified so detect it manually by scanning for its VID/PID.
01972              */
01973             if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
01974                 ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
01975                  (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
01976                  (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
01977                 ((NewExtension->VendorId == 0x8086) &&
01978                  (NewExtension->DeviceId == 0x482)))
01979             {
01980                 /* Do not allow these legacy bridges to be powered down */
01981                 NewExtension->DisablePowerDown = TRUE;
01982             }
01983 
01984             /* Check if the BIOS did not configure a cache line size */
01985             if (!PciData->CacheLineSize)
01986             {
01987                 /* Check if the device is disabled */
01988                 if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE |
01989                                                       PCI_ENABLE_MEMORY_SPACE |
01990                                                       PCI_ENABLE_BUS_MASTER)))
01991                 {
01992                     /* Check if this is a PCI-X device*/
01993                     TempOffset = PciReadDeviceCapability(NewExtension,
01994                                                          NewExtension->CapabilitiesPtr,
01995                                                          PCI_CAPABILITY_ID_PCIX,
01996                                                          &PcixCapHeader,
01997                                                          sizeof(PCI_CAPABILITIES_HEADER));
01998 
01999                     /*
02000                      * A device with default cache line size and latency timer
02001                      * settings is considered to be unconfigured. Note that on
02002                      * PCI-X, the reset value of the latency timer field in the
02003                      * header is 64, not 0, hence why the check for PCI-X caps
02004                      * was required, and the value used here below.
02005                      */
02006                     if (!(PciData->LatencyTimer) ||
02007                         ((TempOffset) && (PciData->LatencyTimer == 64)))
02008                     {
02009                         /* Keep track of the fact that it needs configuration */
02010                         DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
02011                                 NewExtension);
02012                         NewExtension->NeedsHotPlugConfiguration = TRUE;
02013                     }
02014                 }
02015             }
02016 
02017             /* Save latency and cache size information */
02018             NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
02019             NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
02020 
02021             /* The PDO is now ready to go */
02022             DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
02023         }
02024     }
02025 
02026     /* Enumeration completed, do a final pass now that all devices are found */
02027     if (ProcessFlag) PciProcessBus(DeviceExtension);
02028     return STATUS_SUCCESS;
02029 }
02030 
02031 NTSTATUS
02032 NTAPI
02033 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,
02034                         IN OUT PDEVICE_RELATIONS *pDeviceRelations)
02035 {
02036     NTSTATUS Status;
02037     PPCI_PDO_EXTENSION PdoExtension;
02038     ULONG PdoCount = 0;
02039     PDEVICE_RELATIONS DeviceRelations, NewRelations;
02040     SIZE_T Size;
02041     PDEVICE_OBJECT DeviceObject, *ObjectArray;
02042     PAGED_CODE();
02043 
02044     /* Make sure the FDO is started */
02045     ASSERT(DeviceExtension->DeviceState == PciStarted);
02046 
02047     /* Synchronize while we enumerate the bus */
02048     Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation);
02049     if (!NT_SUCCESS(Status)) return Status;
02050 
02051     /* Scan all children PDO */
02052     for (PdoExtension = DeviceExtension->ChildPdoList;
02053          PdoExtension;
02054          PdoExtension = PdoExtension->Next)
02055     {
02056         /* Invalidate them */
02057         PdoExtension->NotPresent = TRUE;
02058     }
02059 
02060     /* Scan the PCI Bus */
02061     Status = PciScanBus(DeviceExtension);
02062     ASSERT(NT_SUCCESS(Status));
02063 
02064     /* Enumerate all children PDO again */
02065     for (PdoExtension = DeviceExtension->ChildPdoList;
02066          PdoExtension;
02067          PdoExtension = PdoExtension->Next)
02068     {
02069         /* Check for PDOs that are still invalidated */
02070         if (PdoExtension->NotPresent)
02071         {
02072             /* This means this PDO existed before, but not anymore */
02073             PdoExtension->ReportedMissing = TRUE;
02074             DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
02075                     PdoExtension);
02076         }
02077         else
02078         {
02079             /* Increase count of detected PDOs */
02080             PdoCount++;
02081         }
02082     }
02083 
02084     /* Read the current relations and add the newly discovered relations */
02085     DeviceRelations = *pDeviceRelations;
02086     Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
02087            PdoCount * sizeof(PDEVICE_OBJECT);
02088     if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
02089 
02090     /* Allocate the device relations */
02091     NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP');
02092     if (!NewRelations)
02093     {
02094         /* Out of space, cancel the operation */
02095         PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation);
02096         return STATUS_INSUFFICIENT_RESOURCES;
02097     }
02098 
02099     /* Check if there were any older relations */
02100     NewRelations->Count = 0;
02101     if (DeviceRelations)
02102     {
02103         /* Copy the old relations into the new buffer, then free the old one */
02104         RtlCopyMemory(NewRelations,
02105                       DeviceRelations,
02106                       FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
02107                       DeviceRelations->Count * sizeof(PDEVICE_OBJECT));
02108         ExFreePoolWithTag(DeviceRelations, 0);
02109     }
02110 
02111     /* Print out that we're ready to dump relations */
02112     DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
02113             DeviceExtension,
02114             DeviceExtension->BaseBus);
02115 
02116     /* Loop the current PDO children and the device relation object array */
02117     PdoExtension = DeviceExtension->ChildPdoList;
02118     ObjectArray = &NewRelations->Objects[NewRelations->Count];
02119     while (PdoExtension)
02120     {
02121         /* Dump this relation */
02122         DPRINT1("  QDR PDO %08x (x %08x)%s\n",
02123                 PdoExtension->PhysicalDeviceObject,
02124                 PdoExtension,
02125                 PdoExtension->NotPresent ?
02126                 "<Omitted, device flaged not present>" : "");
02127 
02128         /* Is this PDO present? */
02129         if (!PdoExtension->NotPresent)
02130         {
02131             /* Reference it and add it to the array */
02132             DeviceObject = PdoExtension->PhysicalDeviceObject;
02133             ObReferenceObject(DeviceObject);
02134             *ObjectArray++ = DeviceObject;
02135         }
02136 
02137         /* Go to the next PDO */
02138         PdoExtension = PdoExtension->Next;
02139     }
02140 
02141     /* Terminate dumping the relations */
02142     DPRINT1("  QDR Total PDO count = %d (%d already in list)\n",
02143             NewRelations->Count + PdoCount,
02144             NewRelations->Count);
02145 
02146     /* Return the final count and the new buffer */
02147     NewRelations->Count += PdoCount;
02148     *pDeviceRelations = NewRelations;
02149     return STATUS_SUCCESS;
02150 }
02151 
02152 NTSTATUS
02153 NTAPI
02154 PciSetResources(IN PPCI_PDO_EXTENSION PdoExtension,
02155                 IN BOOLEAN DoReset,
02156                 IN BOOLEAN SomethingSomethingDarkSide)
02157 {
02158     PPCI_FDO_EXTENSION FdoExtension;
02159     UCHAR NewCacheLineSize, NewLatencyTimer;
02160     PCI_COMMON_HEADER PciData;
02161     BOOLEAN Native;
02162     PPCI_CONFIGURATOR Configurator;
02163 
02164     /* Get the FDO and read the configuration data */
02165     FdoExtension = PdoExtension->ParentFdoExtension;
02166     PciReadDeviceConfig(PdoExtension, &PciData, 0, PCI_COMMON_HDR_LENGTH);
02167 
02168     /* Make sure this is still the same device */
02169     if (!PcipIsSameDevice(PdoExtension, &PciData))
02170     {
02171         /* Fail */
02172         ASSERTMSG(FALSE, "PCI Set resources - not same device");
02173         return STATUS_DEVICE_DOES_NOT_EXIST;
02174     }
02175 
02176     /* Nothing to set for a host bridge */
02177     if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
02178         (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST))
02179     {
02180         /* Fake success */
02181         return STATUS_SUCCESS;
02182     }
02183 
02184     /* Check if an IDE controller is being reset */
02185     if ((DoReset) &&
02186         (PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
02187         (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
02188     {
02189         /* Turn off native mode */
02190         Native = PciConfigureIdeController(PdoExtension, &PciData, FALSE);
02191         ASSERT(Native == PdoExtension->IDEInNativeMode);
02192     }
02193 
02194     /* Check for update of a hotplug device, or first configuration of one */
02195     if ((PdoExtension->NeedsHotPlugConfiguration) &&
02196         (FdoExtension->HotPlugParameters.Acquired))
02197     {
02198         /* Don't have hotplug devices to test with yet, QEMU 0.14 should */
02199         UNIMPLEMENTED;
02200         while (TRUE);
02201     }
02202 
02203     /* Locate the correct resource configurator for this type of device */
02204     Configurator = &PciConfigurators[PdoExtension->HeaderType];
02205 
02206     /* Apply the settings change */
02207     Configurator->ChangeResourceSettings(PdoExtension, &PciData);
02208 
02209     /* Assume no update needed */
02210     PdoExtension->UpdateHardware = FALSE;
02211 
02212     /* Check if a reset is needed */
02213     if (DoReset)
02214     {
02215         /* Reset resources */
02216         Configurator->ResetDevice(PdoExtension, &PciData);
02217         PciData.u.type0.InterruptLine = PdoExtension->RawInterruptLine;
02218     }
02219 
02220     /* Check if the latency timer changed */
02221     NewLatencyTimer = PdoExtension->SavedLatencyTimer;
02222     if (PciData.LatencyTimer != NewLatencyTimer)
02223     {
02224         /* Debug notification */
02225         DPRINT1("PCI (pdox %08x) changing latency from %02x to %02x.\n",
02226                 PdoExtension,
02227                 PciData.LatencyTimer,
02228                 NewLatencyTimer);
02229     }
02230 
02231     /* Check if the cache line changed */
02232     NewCacheLineSize = PdoExtension->SavedCacheLineSize;
02233     if (PciData.CacheLineSize != NewCacheLineSize)
02234     {
02235         /* Debug notification */
02236         DPRINT1("PCI (pdox %08x) changing cache line size from %02x to %02x.\n",
02237                 PdoExtension,
02238                 PciData.CacheLineSize,
02239                 NewCacheLineSize);
02240     }
02241 
02242     /* Inherit data from PDO extension */
02243     PciData.LatencyTimer = PdoExtension->SavedLatencyTimer;
02244     PciData.CacheLineSize = PdoExtension->SavedCacheLineSize;
02245     PciData.u.type0.InterruptLine = PdoExtension->RawInterruptLine;
02246 
02247     /* Apply any resource hacks required */
02248     PciApplyHacks(FdoExtension,
02249                   &PciData,
02250                   PdoExtension->Slot,
02251                   PCI_HACK_FIXUP_BEFORE_UPDATE,
02252                   PdoExtension);
02253 
02254     /* Check if I/O space was disabled by administrator or driver */
02255     if (PdoExtension->IoSpaceNotRequired)
02256     {
02257         /* Don't turn on the decode */
02258         PdoExtension->CommandEnables &= ~PCI_ENABLE_IO_SPACE;
02259     }
02260 
02261     /* Update the device with the new settings */
02262     PciUpdateHardware(PdoExtension, &PciData);
02263 
02264     /* Update complete */
02265     PdoExtension->RawInterruptLine = PciData.u.type0.InterruptLine;
02266     PdoExtension->NeedsHotPlugConfiguration = FALSE;
02267     return STATUS_SUCCESS;
02268 }
02269 
02270 /* EOF */

Generated on Sat May 26 2012 04:20:15 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.