Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273/* * PROJECT: ReactOS PCI Bus Driver * LICENSE: BSD - See COPYING.ARM in the top level directory * FILE: drivers/bus/pci/enum.c * PURPOSE: PCI Bus/Device Enumeration * PROGRAMMERS: ReactOS Portable Systems Group */
/* INCLUDES *******************************************************************/
#include <pci.h>
#define NDEBUG#include <debug.h>
/* GLOBALS ********************************************************************/
PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements;
PCI_CONFIGURATOR PciConfigurators[] ={ { Device_MassageHeaderForLimitsDetermination, Device_RestoreCurrent, Device_SaveLimits, Device_SaveCurrentSettings, Device_ChangeResourceSettings, Device_GetAdditionalResourceDescriptors, Device_ResetDevice }, { PPBridge_MassageHeaderForLimitsDetermination, PPBridge_RestoreCurrent, PPBridge_SaveLimits, PPBridge_SaveCurrentSettings, PPBridge_ChangeResourceSettings, PPBridge_GetAdditionalResourceDescriptors, PPBridge_ResetDevice }, { Cardbus_MassageHeaderForLimitsDetermination, Cardbus_RestoreCurrent, Cardbus_SaveLimits, Cardbus_SaveCurrentSettings, Cardbus_ChangeResourceSettings, Cardbus_GetAdditionalResourceDescriptors, Cardbus_ResetDevice }};
/* FUNCTIONS ******************************************************************/
BOOLEANNTAPIPciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension, IN PCM_RESOURCE_LIST ResourceList){ PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, InterruptResource; PCM_PARTIAL_RESOURCE_DESCRIPTOR BaseResource, CurrentDescriptor; PCM_PARTIAL_RESOURCE_DESCRIPTOR PreviousDescriptor; CM_PARTIAL_RESOURCE_DESCRIPTOR ResourceArray[7]; PCM_FULL_RESOURCE_DESCRIPTOR FullList; BOOLEAN DrainPartial, RangeChange; ULONG i, j; PPCI_FUNCTION_RESOURCES PciResources; PAGED_CODE();
/* Make sure we have either no resources, or at least one */ ASSERT((ResourceList == NULL) || (ResourceList->Count == 1));
/* Initialize no partial, interrupt descriptor, or range change */ Partial = NULL; InterruptResource = NULL; RangeChange = FALSE;
/* Check if there's not actually any resources */ if (!(ResourceList) || !(ResourceList->Count)) { /* Then just return the hardware update state */ return PdoExtension->UpdateHardware; }
/* Print the new specified resource list */ PciDebugPrintCmResList(ResourceList);
/* Clear the temporary resource array */ for (i = 0; i < 7; i++) ResourceArray[i].Type = CmResourceTypeNull;
/* Loop the full resource descriptor */ FullList = ResourceList->List; for (i = 0; i < ResourceList->Count; i++) { /* Initialize loop variables */ DrainPartial = FALSE; BaseResource = NULL;
/* Loop the partial descriptors */ Partial = FullList->PartialResourceList.PartialDescriptors; for (j = 0; j < FullList->PartialResourceList.Count; j++) { /* Check if we were supposed to drain a partial due to device data */ if (DrainPartial) { /* Draining complete, move on to the next descriptor then */ DrainPartial--; continue; }
/* Check what kind of descriptor this was */ switch (Partial->Type) { /* Base BAR resources */ case CmResourceTypePort: case CmResourceTypeMemory:
/* Set it as the base */ ASSERT(BaseResource == NULL); BaseResource = Partial; break;
/* Interrupt resource */ case CmResourceTypeInterrupt:
/* Make sure it's a compatible (and the only) PCI interrupt */ ASSERT(InterruptResource == NULL); ASSERT(Partial->u.Interrupt.Level == Partial->u.Interrupt.Vector); InterruptResource = Partial;
/* Only 255 interrupts on x86/x64 hardware */ if (Partial->u.Interrupt.Level < 256) { /* Use the passed interrupt line */ PdoExtension->AdjustedInterruptLine = Partial->u.Interrupt.Level; } else { /* Invalid vector, so ignore it */ PdoExtension->AdjustedInterruptLine = 0; }
break;
/* Check for specific device data */ case CmResourceTypeDevicePrivate:
/* Check what kind of data this was */ switch (Partial->u.DevicePrivate.Data[0]) { /* Not used in the driver yet */ case 1: UNIMPLEMENTED_DBGBREAK(); break;
/* Not used in the driver yet */ case 2: UNIMPLEMENTED_DBGBREAK(); break;
/* A drain request */ case 3: /* Shouldn't be a base resource, this is a drain */ ASSERT(BaseResource == NULL); DrainPartial = Partial->u.DevicePrivate.Data[1]; ASSERT(DrainPartial == TRUE); break; } break; }
/* Move to the next descriptor */ Partial = CmiGetNextPartialDescriptor(Partial); }
/* We should be starting a new list now */ ASSERT(BaseResource == NULL); FullList = (PVOID)Partial; }
/* Check the current assigned PCI resources */ PciResources = PdoExtension->Resources; if (!PciResources) return FALSE;
//if... // MISSING CODE UNIMPLEMENTED; DPRINT1("Missing sanity checking code!\n");
/* Loop all the PCI function resources */ for (i = 0; i < 7; i++) { /* Get the current function resource descriptor, and the new one */ CurrentDescriptor = &PciResources->Current[i]; Partial = &ResourceArray[i];
/* Previous is current during the first loop iteration */ PreviousDescriptor = &PciResources->Current[(i == 0) ? (0) : (i - 1)];
/* Check if this new descriptor is different than the old one */ if (((Partial->Type != CurrentDescriptor->Type) || (Partial->Type != CmResourceTypeNull)) && ((Partial->u.Generic.Start.QuadPart != CurrentDescriptor->u.Generic.Start.QuadPart) || (Partial->u.Generic.Length != CurrentDescriptor->u.Generic.Length))) { /* Record a change */ RangeChange = TRUE;
/* Was there a range before? */ if (CurrentDescriptor->Type != CmResourceTypeNull) { /* Print it */ DbgPrint(" Old range-\n"); PciDebugPrintPartialResource(CurrentDescriptor); } else { /* There was no range */ DbgPrint(" Previously unset range\n"); }
/* Print new one */ DbgPrint(" changed to\n"); PciDebugPrintPartialResource(Partial);
/* Update to new range */ CurrentDescriptor->Type = Partial->Type; PreviousDescriptor->u.Generic.Start = Partial->u.Generic.Start; PreviousDescriptor->u.Generic.Length = Partial->u.Generic.Length; CurrentDescriptor = PreviousDescriptor; } }
/* Either the hardware was updated, or a resource range changed */ return ((RangeChange) || (PdoExtension->UpdateHardware));}
VOIDNTAPIPcipUpdateHardware(IN PVOID Context, IN PVOID Context2){ PPCI_PDO_EXTENSION PdoExtension = Context; PPCI_COMMON_HEADER PciData = Context2;
/* Check if we're allowed to disable decodes */ PciData->Command = PdoExtension->CommandEnables; if (!(PdoExtension->HackFlags & PCI_HACK_PRESERVE_COMMAND)) { /* Disable all decodes */ PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER | PCI_ENABLE_WRITE_AND_INVALIDATE); }
/* Update the device configuration */ PciData->Status = 0; PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
/* Turn decodes back on */ PciDecodeEnable(PdoExtension, TRUE, &PdoExtension->CommandEnables);}
VOIDNTAPIPciUpdateHardware(IN PPCI_PDO_EXTENSION PdoExtension, IN PPCI_COMMON_HEADER PciData){ PCI_IPI_CONTEXT Context;
/* Check for critical devices and PCI Debugging devices */ if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) || (PdoExtension->OnDebugPath)) { /* Build the context and send an IPI */ Context.RunCount = 1; Context.Barrier = 1; Context.Context = PciData; Context.Function = PcipUpdateHardware; Context.DeviceExtension = PdoExtension; KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&Context); } else { /* Just to the update inline */ PcipUpdateHardware(PdoExtension, PciData); }}
PIO_RESOURCE_REQUIREMENTS_LISTNTAPIPciAllocateIoRequirementsList(IN ULONG Count, IN ULONG BusNumber, IN ULONG SlotNumber){ SIZE_T Size; PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
/* Calculate the final size of the list, including each descriptor */ Size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); if (Count > 1) Size = sizeof(IO_RESOURCE_DESCRIPTOR) * (Count - 1) + sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
/* Allocate the list */ RequirementsList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP'); if (!RequirementsList) return NULL;
/* Initialize it */ RtlZeroMemory(RequirementsList, Size); RequirementsList->AlternativeLists = 1; RequirementsList->BusNumber = BusNumber; RequirementsList->SlotNumber = SlotNumber; RequirementsList->InterfaceType = PCIBus; RequirementsList->ListSize = Size; RequirementsList->List[0].Count = Count; RequirementsList->List[0].Version = 1; RequirementsList->List[0].Revision = 1;
/* Return it */ return RequirementsList;}
PCM_RESOURCE_LISTNTAPIPciAllocateCmResourceList(IN ULONG Count, IN ULONG BusNumber){ SIZE_T Size; PCM_RESOURCE_LIST ResourceList;
/* Calculate the final size of the list, including each descriptor */ Size = sizeof(CM_RESOURCE_LIST); if (Count > 1) Size = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count - 1) + sizeof(CM_RESOURCE_LIST);
/* Allocate the list */ ResourceList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP'); if (!ResourceList) return NULL;
/* Initialize it */ RtlZeroMemory(ResourceList, Size); ResourceList->Count = 1; ResourceList->List[0].BusNumber = BusNumber; ResourceList->List[0].InterfaceType = PCIBus; ResourceList->List[0].PartialResourceList.Version = 1; ResourceList->List[0].PartialResourceList.Revision = 1; ResourceList->List[0].PartialResourceList.Count = Count;
/* Return it */ return ResourceList;}
NTSTATUSNTAPIPciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension, OUT PCM_RESOURCE_LIST *Buffer){ PPCI_FUNCTION_RESOURCES PciResources; BOOLEAN HaveVga, HaveMemSpace, HaveIoSpace; USHORT BridgeControl, PciCommand; ULONG Count, i; PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, Resource, LastResource; PCM_RESOURCE_LIST ResourceList; UCHAR InterruptLine; PAGED_CODE();
/* Assume failure */ Count = 0; HaveVga = FALSE; *Buffer = NULL;
/* Make sure there's some resources to query */ PciResources = PdoExtension->Resources; if (!PciResources) return STATUS_SUCCESS;
/* Read the decodes */ PciReadDeviceConfig(PdoExtension, &PciCommand, FIELD_OFFSET(PCI_COMMON_HEADER, Command), sizeof(USHORT));
/* Check which ones are turned on */ HaveIoSpace = PciCommand & PCI_ENABLE_IO_SPACE; HaveMemSpace = PciCommand & PCI_ENABLE_MEMORY_SPACE;
/* Loop maximum possible descriptors */ for (i = 0; i < 7; i++) { /* Check if the decode for this descriptor is actually turned on */ Partial = &PciResources->Current[i]; if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) || ((HaveIoSpace) && (Partial->Type == CmResourceTypePort))) { /* One more fully active descriptor */ Count++; } }
/* If there's an interrupt pin associated, check at least one decode is on */ if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace))) { /* Read the interrupt line for the pin, add a descriptor if it's valid */ InterruptLine = PdoExtension->AdjustedInterruptLine; if ((InterruptLine) && (InterruptLine != -1)) Count++; }
/* Check for PCI bridge */ if (PdoExtension->HeaderType == PCI_BRIDGE_TYPE) { /* Read bridge settings, check if VGA is present */ PciReadDeviceConfig(PdoExtension, &BridgeControl, FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BridgeControl), sizeof(USHORT)); if (BridgeControl & PCI_ENABLE_BRIDGE_VGA) { /* Remember for later */ HaveVga = TRUE;
/* One memory descriptor for 0xA0000, plus the two I/O port ranges */ if (HaveMemSpace) Count++; if (HaveIoSpace) Count += 2; } }
/* If there's no descriptors in use, there's no resources, so return */ if (!Count) return STATUS_SUCCESS;
/* Allocate a resource list to hold the resources */ ResourceList = PciAllocateCmResourceList(Count, PdoExtension->ParentFdoExtension->BaseBus); if (!ResourceList) return STATUS_INSUFFICIENT_RESOURCES;
/* This is where the descriptors will be copied into */ Resource = ResourceList->List[0].PartialResourceList.PartialDescriptors; LastResource = Resource + Count + 1;
/* Loop maximum possible descriptors */ for (i = 0; i < 7; i++) { /* Check if the decode for this descriptor is actually turned on */ Partial = &PciResources->Current[i]; if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) || ((HaveIoSpace) && (Partial->Type == CmResourceTypePort))) { /* Copy the descriptor into the resource list */ *Resource++ = *Partial; } }
/* Check if earlier the code detected this was a PCI bridge with VGA on it */ if (HaveVga) { /* Are the memory decodes enabled? */ if (HaveMemSpace) { /* Build a memory descriptor for a 128KB framebuffer at 0xA0000 */ Resource->Flags = CM_RESOURCE_MEMORY_READ_WRITE; Resource->u.Generic.Start.HighPart = 0; Resource->Type = CmResourceTypeMemory; Resource->u.Generic.Start.LowPart = 0xA0000; Resource->u.Generic.Length = 0x20000; Resource++; }
/* Are the I/O decodes enabled? */ if (HaveIoSpace) { /* Build an I/O descriptor for the graphic ports at 0x3B0 */ Resource->Type = CmResourceTypePort; Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE; Resource->u.Port.Start.QuadPart = 0x3B0u; Resource->u.Port.Length = 0xC; Resource++;
/* Build an I/O descriptor for the graphic ports at 0x3C0 */ Resource->Type = CmResourceTypePort; Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE; Resource->u.Port.Start.QuadPart = 0x3C0u; Resource->u.Port.Length = 0x20; Resource++; } }
/* If there's an interrupt pin associated, check at least one decode is on */ if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace))) { /* Read the interrupt line for the pin, check if it's valid */ InterruptLine = PdoExtension->AdjustedInterruptLine; if ((InterruptLine) && (InterruptLine != -1)) { /* Make sure there's still space */ ASSERT(Resource < LastResource);
/* Add the interrupt descriptor */ Resource->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; Resource->Type = CmResourceTypeInterrupt; Resource->ShareDisposition = CmResourceShareShared; Resource->u.Interrupt.Affinity = -1; Resource->u.Interrupt.Level = InterruptLine; Resource->u.Interrupt.Vector = InterruptLine; } }
/* Return the resource list */ *Buffer = ResourceList; return STATUS_SUCCESS;}
NTSTATUSNTAPIPciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension, IN OUT PDEVICE_RELATIONS *pDeviceRelations){ PDEVICE_RELATIONS DeviceRelations; PAGED_CODE();
/* If there were existing relations, free them */ if (*pDeviceRelations) ExFreePoolWithTag(*pDeviceRelations, 0);
/* Allocate a new structure for the relations */ DeviceRelations = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_RELATIONS), 'BicP'); if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES;
/* Only one relation: the PDO */ DeviceRelations->Count = 1; DeviceRelations->Objects[0] = PdoExtension->PhysicalDeviceObject; ObReferenceObject(DeviceRelations->Objects[0]);
/* Return the new relations */ *pDeviceRelations = DeviceRelations; return STATUS_SUCCESS;}
NTSTATUSNTAPIPciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension, IN OUT PDEVICE_RELATIONS *pDeviceRelations){ UNREFERENCED_PARAMETER(PdoExtension); UNREFERENCED_PARAMETER(pDeviceRelations);
/* Not yet implemented */ UNIMPLEMENTED_DBGBREAK(); return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPIPciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension, IN PPCI_COMMON_HEADER PciData, OUT PIO_RESOURCE_REQUIREMENTS_LIST* Buffer){ PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
UNREFERENCED_PARAMETER(PdoExtension); UNREFERENCED_PARAMETER(PciData);
{ /* There aren't, so use the zero descriptor */ RequirementsList = PciZeroIoResourceRequirements;
/* Does it actually exist yet? */ if (!PciZeroIoResourceRequirements) { /* Allocate it, and use it for future use */ RequirementsList = PciAllocateIoRequirementsList(0, 0, 0); PciZeroIoResourceRequirements = RequirementsList; if (!PciZeroIoResourceRequirements) return STATUS_INSUFFICIENT_RESOURCES; }
/* Return the zero requirements list to the caller */ *Buffer = RequirementsList; DPRINT1("PCI - build resource reqs - early out, 0 resources\n"); return STATUS_SUCCESS; } return STATUS_SUCCESS;}
NTSTATUSNTAPIPciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension, IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList){ NTSTATUS Status; PCI_COMMON_HEADER PciHeader; PAGED_CODE();
/* Check if the PDO has any resources, or at least an interrupt pin */ if ((PdoExtension->Resources) || (PdoExtension->InterruptPin)) { /* Read the current PCI header */ PciReadDeviceConfig(PdoExtension, &PciHeader, 0, PCI_COMMON_HDR_LENGTH);
/* Use it to build a list of requirements */ Status = PciBuildRequirementsList(PdoExtension, &PciHeader, RequirementsList); if (!NT_SUCCESS(Status)) return Status;
/* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */ if ((PciHeader.VendorID == 0xE11) && (PciHeader.DeviceID == 0xA0F7) && (PciHeader.RevisionID == 17) && (ExIsProcessorFeaturePresent(PF_PAE_ENABLED))) { /* Have not tested this on eVb's machine yet */ UNIMPLEMENTED_DBGBREAK(); }
/* Check if the requirements are actually the zero list */ if (*RequirementsList == PciZeroIoResourceRequirements) { /* A simple NULL will suffice for the PnP Manager */ *RequirementsList = NULL; DPRINT1("Returning NULL requirements list\n"); } else { /* Otherwise, print out the requirements list */ PciDebugPrintIoResReqList(*RequirementsList); } } else { /* There aren't any resources, so simply return NULL */ DPRINT1("PciQueryRequirements returning NULL requirements list\n"); *RequirementsList = NULL; }
/* This call always succeeds (but maybe with no requirements) */ return STATUS_SUCCESS;}
/* * 7. The IO/MEM/Busmaster decodes are disabled for the device. * 8. The PCI bus driver sets the operating mode bits of the Programming * Interface byte to switch the controller to native mode. * * Important: When the controller is set to native mode, it must quiet itself * and must not decode I/O resources or generate interrupts until the operating * system has enabled the ports in the PCI configuration header. * The IO/MEM/BusMaster bits will be disabled before the mode change, but it * is not possible to disable interrupts on the device. The device must not * generate interrupts (either legacy or native mode) while the decodes are * disabled in the command register. * * This operation is expected to be instantaneous and the operating system does * not stall afterward. It is also expected that the interrupt pin register in * the PCI Configuration space for this device is accurate. The operating system * re-reads this data after previously ignoring it. */BOOLEANNTAPIPciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension, IN PPCI_COMMON_HEADER PciData, IN BOOLEAN Initial){ UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf; BOOLEAN Switched; USHORT Command;
/* Assume it won't work */ Switched = FALSE;
/* Get master and slave current settings, and programmability flag */ ProgIf = PciData->ProgIf; MasterMode = (ProgIf & 1) == 1; MasterFixed = (ProgIf & 2) == 0; SlaveMode = (ProgIf & 4) == 4; SlaveFixed = (ProgIf & 8) == 0;
/* * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA * ATA controller from compatible mode to native mode, the following must be * true: * * - The controller must indicate in its programming interface that both channels * can be switched to native mode. Windows XP SP1 and Windows Server 2003 do * not support switching only one IDE channel to native mode. See the PCI IDE * Controller Specification Revision 1.0 for details. */ if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed)) { /* Windows does not support this configuration, fail */ DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!", PdoExtension->VendorId, PdoExtension->DeviceId); return Switched; }
/* Check if the controller is already in native mode */ if ((MasterMode) && (SlaveMode)) { /* Check if I/O decodes should be disabled */ if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl)) { /* Read the current command */ PciReadDeviceConfig(PdoExtension, &Command, FIELD_OFFSET(PCI_COMMON_HEADER, Command), sizeof(USHORT));
/* Disable I/O space decode */ Command &= ~PCI_ENABLE_IO_SPACE;
/* Update new command in PCI IDE controller */ PciWriteDeviceConfig(PdoExtension, &Command, FIELD_OFFSET(PCI_COMMON_HEADER, Command), sizeof(USHORT));
/* Save updated command value */ PciData->Command = Command; }
/* The controller is now in native mode */ Switched = TRUE; } else if (!(MasterFixed) && !(SlaveFixed) && (PdoExtension->BIOSAllowsIDESwitchToNativeMode) && !(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE)) { /* Turn off decodes */ PciDecodeEnable(PdoExtension, FALSE, NULL);
/* Update the current command */ PciReadDeviceConfig(PdoExtension, &PciData->Command, FIELD_OFFSET(PCI_COMMON_HEADER, Command), sizeof(USHORT));
/* Enable native mode */ ProgIf = PciData->ProgIf | 5; PciWriteDeviceConfig(PdoExtension, &ProgIf, FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf), sizeof(UCHAR));
/* Verify the setting "stuck" */ PciReadDeviceConfig(PdoExtension, &NewProgIf, FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf), sizeof(UCHAR)); if (NewProgIf == ProgIf) { /* Update the header and PDO data with the new programming mode */ PciData->ProgIf = ProgIf; PdoExtension->ProgIf = NewProgIf;
/* Clear the first four BARs to reset current BAR settings */ PciData->u.type0.BaseAddresses[0] = 0; PciData->u.type0.BaseAddresses[1] = 0; PciData->u.type0.BaseAddresses[2] = 0; PciData->u.type0.BaseAddresses[3] = 0; PciWriteDeviceConfig(PdoExtension, PciData->u.type0.BaseAddresses, FIELD_OFFSET(PCI_COMMON_HEADER, u.type0.BaseAddresses), 4 * sizeof(ULONG));
/* Re-read the BARs to have the latest data for native mode IDE */ PciReadDeviceConfig(PdoExtension, PciData->u.type0.BaseAddresses, FIELD_OFFSET(PCI_COMMON_HEADER, u.type0.BaseAddresses), 4 * sizeof(ULONG));
/* Re-read the interrupt pin used for native mode IDE */ PciReadDeviceConfig(PdoExtension, &PciData->u.type0.InterruptPin, FIELD_OFFSET(PCI_COMMON_HEADER, u.type0.InterruptPin), sizeof(UCHAR));
/* The IDE Controller is now in native mode */ Switched = TRUE; } else { /* Settings did not work, fail */ DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!", PciData->VendorID, PciData->DeviceID); } }
/* Return whether or not native mode was enabled on the IDE controller */ return Switched;}
VOIDNTAPIPciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension, IN PPCI_COMMON_HEADER PciData, IN PCI_SLOT_NUMBER SlotNumber, IN ULONG OperationType, PPCI_PDO_EXTENSION PdoExtension){ ULONG LegacyBaseAddress; USHORT Command; UCHAR RegValue;
UNREFERENCED_PARAMETER(SlotNumber);
/* Check what kind of hack operation this is */ switch (OperationType) { /* * This is mostly concerned with fixing up incorrect class data that can * exist on certain PCI hardware before the 2.0 spec was ratified. */ case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
/* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices * and appear as non-classified, so their correct class/subclass data * is written here instead. */ if ((PciData->VendorID == 0x8086) && ((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484))) { /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */ PciData->SubClass = PciData->DeviceID == 0x482 ? PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA; PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
/* * Because the software is modifying the actual header data from * the BIOS, this flag tells the driver to ignore failures when * comparing the original BIOS data with the PCI data. */ if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE; }
/* Note that in this case, an immediate return is issued */ return;
/* * This is concerned with setting up interrupts correctly for native IDE * mode, but will also handle broken VGA decoding on older bridges as * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers. */ case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
/* There should always be a PDO extension passed in */ ASSERT(PdoExtension);
/* * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA * and FreeBSD bug reports indicate that the system crashes when the * feature is enabled (so it's disabled on that OS as well). In the * NT PCI Bus Driver, it seems Microsoft too, completely disables * Native IDE functionality on this controller, so it would seem OPTi * simply frelled up this controller. */ if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621)) { /* Disable native mode */ PciData->ProgIf &= ~5; PciData->u.type0.InterruptPin = 0;
/* * Because the software is modifying the actual header data from * the BIOS, this flag tells the driver to ignore failures when * comparing the original BIOS data with the PCI data. */ PdoExtension->ExpectedWritebackFailure = TRUE; } else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) && (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR)) { /* For other IDE controllers, start out in compatible mode */ PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
/* * Registry must have enabled native mode (typically as a result * of an INF file directive part of the IDE controller's driver) * and the system must not be booted in Safe Mode. If that checks * out, then evaluate the ACPI NATA method to see if the platform * supports this. See the section "BIOS and Platform Prerequisites * for Switching a Native-Mode-Capable Controller" in the Storage * section of the Windows Driver Kit for more details: * * 5. For each ATA controller enumerated, the PCI bus driver checks * the Programming Interface register of the IDE controller to * see if it supports switching both channels to native mode. * 6. The PCI bus driver checks whether the BIOS/platform supports * switching the controller by checking the NATA method described * earlier in this article. * * If an ATA controller does not indicate that it is native * mode-capable, or if the BIOS NATA control method is missing * or does not list that device, the PCI bus driver does not * switch the controller and it is assigned legacy resources. * * If both the controller and the BIOS indicate that the controller * can be switched, the process of switching the controller begins * with the next step. */ if ((PciEnableNativeModeATA) && !(InitSafeBootMode) && (PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN'))) { /* The platform supports it, remember that */ PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
/* * Now switch the controller into native mode if both channels * support native IDE mode. See "How Windows Switches an ATA * Controller to Native Mode" in the Storage section of the * Windows Driver Kit for more details. */ PdoExtension->IDEInNativeMode = PciConfigureIdeController(PdoExtension, PciData, TRUE); }
/* Is native mode enabled after all? */ if ((PciData->ProgIf & 5) != 5) { /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */ PciData->u.type0.InterruptPin = 0; } }
/* Is this a PCI device with legacy VGA card decodes on the root bus? */ if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) && (PCI_IS_ROOT_FDO(DeviceExtension)) && !(DeviceExtension->BrokenVideoHackApplied)) { /* Tell the arbiter to apply a hack for these older devices */ ario_ApplyBrokenVideoHack(DeviceExtension); }
/* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */ if ((PciData->VendorID == 0xE11) && (PciData->DeviceID == 0xA0F7) && (PciData->RevisionID == 17) && (ExIsProcessorFeaturePresent(PF_PAE_ENABLED))) { /* Turn off the decodes immediately */ PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER); PciWriteDeviceConfig(PdoExtension, &PciData->Command, FIELD_OFFSET(PCI_COMMON_HEADER, Command), sizeof(USHORT));
/* Do not EVER turn them on again, this will blow up the system */ PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER); PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND; } break;
/* * This is called whenever resources are changed and hardware needs to be * updated. It is concerned with two highly specific erratas on an IBM * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's * ICH PCI Bridges. */ case PCI_HACK_FIXUP_BEFORE_UPDATE:
/* There should always be a PDO extension passed in */ ASSERT(PdoExtension);
/* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */ if ((PdoExtension->VendorId == 0x1014) && (PdoExtension->DeviceId == 0x95)) { /* Read the current command */ PciReadDeviceConfig(PdoExtension, &Command, FIELD_OFFSET(PCI_COMMON_HEADER, Command), sizeof(USHORT));
/* Turn off the decodes */ PciDecodeEnable(PdoExtension, FALSE, &Command);
/* Apply the required IBM workaround */ PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR)); RegValue &= ~2; RegValue |= 1; PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
/* Restore the command to its original value */ PciWriteDeviceConfig(PdoExtension, &Command, FIELD_OFFSET(PCI_COMMON_HEADER, Command), sizeof(USHORT));
}
/* * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810, * i820, i840, i845 Chipsets) that have subtractive decode enabled, * and whose hack flags do not specify that this support is broken. */ if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) && (PdoExtension->Dependent.type1.SubtractiveDecode) && ((PdoExtension->VendorId == 0x8086) && ((PdoExtension->DeviceId == 0x2418) || (PdoExtension->DeviceId == 0x2428) || (PdoExtension->DeviceId == 0x244E) || (PdoExtension->DeviceId == 0x2448))) && !(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE)) { /* * The positive decode window shouldn't be used, these values are * normally all read-only or initialized to 0 by the BIOS, but * it appears Intel doesn't do this, so the PCI Bus Driver will * do it in software instead. Note that this is used to prevent * certain non-compliant PCI devices from breaking down due to the * fact that these ICH bridges have a known "quirk" (which Intel * documents as a known "erratum", although it's not not really * an ICH bug since the PCI specification does allow for it) in * that they will sometimes send non-zero addresses during special * cycles (ie: non-zero data during the address phase). These * broken PCI cards will mistakenly attempt to claim the special * cycle and corrupt their I/O and RAM ranges. Again, in Intel's * defense, the PCI specification only requires stable data, not * necessarily zero data, during the address phase. */ PciData->u.type1.MemoryBase = 0xFFFF; PciData->u.type1.PrefetchBase = 0xFFFF; PciData->u.type1.IOBase = 0xFF; PciData->u.type1.IOLimit = 0; PciData->u.type1.MemoryLimit = 0; PciData->u.type1.PrefetchLimit = 0; PciData->u.type1.PrefetchBaseUpper32 = 0; PciData->u.type1.PrefetchLimitUpper32 = 0; PciData->u.type1.IOBaseUpper16 = 0; PciData->u.type1.IOLimitUpper16 = 0; } break;
default: return; }
/* Finally, also check if this is this a CardBUS device? */ if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE) { /* * At offset 44h the LegacyBaseAddress is stored, which is cleared by * ACPI-aware versions of Windows, to disable legacy-mode I/O access to * CardBus controllers. For more information, see "Supporting CardBus * Controllers under ACPI" in the "CardBus Controllers and Windows" * Whitepaper on WHDC. */ LegacyBaseAddress = 0; PciWriteDeviceConfig(PdoExtension, &LegacyBaseAddress, sizeof(PCI_COMMON_HEADER) + sizeof(ULONG), sizeof(ULONG)); }}
BOOLEANNTAPIPcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension, IN PPCI_COMMON_HEADER PciData){ BOOLEAN IdMatch, RevMatch, SubsysMatch; ULONGLONG HackFlags = DeviceExtension->HackFlags;
/* Check if the IDs match */ IdMatch = (PciData->VendorID == DeviceExtension->VendorId) && (PciData->DeviceID == DeviceExtension->DeviceId); if (!IdMatch) return FALSE;
/* If the device has a valid revision, check if it matches */ RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) || (PciData->RevisionID == DeviceExtension->RevisionId); if (!RevMatch) return FALSE;
/* For multifunction devices, this is enough to assume they're the same */ if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
/* For bridge devices, there's also nothing else that can be checked */ if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
/* Devices, on the other hand, have subsystem data that can be compared */ SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM | PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) || ((DeviceExtension->SubsystemVendorId == PciData->u.type0.SubVendorID) && (DeviceExtension->SubsystemId == PciData->u.type0.SubSystemID)); return SubsysMatch;}
BOOLEANNTAPIPciSkipThisFunction(IN PPCI_COMMON_HEADER PciData, IN PCI_SLOT_NUMBER Slot, IN UCHAR OperationType, IN ULONGLONG HackFlags){ do { /* Check if this is device enumeration */ if (OperationType == PCI_SKIP_DEVICE_ENUMERATION) { /* Check if there's a hackflag saying not to enumerate this device */ if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
/* Check if this is the high end of a double decker device */ if ((HackFlags & PCI_HACK_DOUBLE_DECKER) && (Slot.u.bits.DeviceNumber >= 16)) { /* It belongs to the same device, so skip it */ DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n", PciData->VendorID, PciData->DeviceID, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); break; } } else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION) { /* Resource enumeration, check for a hackflag saying not to do it */ if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break; } else { /* Logic error in the driver */ ASSERTMSG("PCI Skip Function - Operation type unknown.\n", FALSE); }
/* Check for legacy bridges during resource enumeration */ if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) && (PciData->SubClass <= PCI_SUBCLASS_BR_MCA) && (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)) { /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */ break; } else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED) { /* Undefined base class (usually a PCI BIOS/ROM bug) */ DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n", PciData->VendorID, PciData->DeviceID);
/* * The Alder has an Intel Extended Express System Support Controller * which presents apparently spurious BARs. When the PCI resource * code tries to reassign these BARs, the second IO-APIC gets * disabled (with disastrous consequences). The first BAR is the * actual IO-APIC, the remaining five bars seem to be spurious * resources, so ignore this device completely. */ if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break; }
/* Other normal PCI cards and bridges are enumerated */ if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE; } while (FALSE);
/* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */ DPRINT1(" Device skipped (not enumerated).\n"); return TRUE;}
VOIDNTAPIPciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension, IN PPCI_COMMON_HEADER PciData){ ULONG HeaderType, CapPtr, TargetAgpCapabilityId; DEVICE_POWER_STATE WakeLevel; PCI_CAPABILITIES_HEADER AgpCapability; PCI_PM_CAPABILITY PowerCapabilities; PAGED_CODE();
/* Assume no known wake level */ PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
/* Make sure the device has capabilities */ if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST)) { /* If it doesn't, there will be no power management */ PdoExtension->CapabilitiesPtr = 0; PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS; } else { /* There's capabilities, need to figure out where to get the offset */ HeaderType = PCI_CONFIGURATION_TYPE(PciData); if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE) { /* Use the bridge's header */ CapPtr = PciData->u.type2.CapabilitiesPtr; } else { /* Use the device header */ ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE); CapPtr = PciData->u.type0.CapabilitiesPtr; }
/* Skip garbage capabilities pointer */ if (((CapPtr & 0x3) != 0) || (CapPtr < PCI_COMMON_HDR_LENGTH)) { /* Report no extended capabilities */ PdoExtension->CapabilitiesPtr = 0; PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS; } else { DPRINT1("Device has capabilities at: %lx\n", CapPtr); PdoExtension->CapabilitiesPtr = CapPtr;
/* Check for PCI-to-PCI Bridges and AGP bridges */ if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) && ((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) || (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI))) { /* Query either the raw AGP capabilitity, or the Target AGP one */ TargetAgpCapabilityId = (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ? PCI_CAPABILITY_ID_AGP_TARGET : PCI_CAPABILITY_ID_AGP; if (PciReadDeviceCapability(PdoExtension, PdoExtension->CapabilitiesPtr, TargetAgpCapabilityId, &AgpCapability, sizeof(PCI_CAPABILITIES_HEADER))) { /* AGP target ID was found, store it */ DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId); PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId; } }
/* Check for devices that are known not to have proper power management */ if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)) { /* Query if this device supports power management */ if (!PciReadDeviceCapability(PdoExtension, PdoExtension->CapabilitiesPtr, PCI_CAPABILITY_ID_POWER_MANAGEMENT, &PowerCapabilities.Header, sizeof(PCI_PM_CAPABILITY))) { /* No power management, so act as if it had the hackflag set */ DPRINT1("No PM caps, disabling PM\n"); PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS; } else { /* Otherwise, pick the highest wake level that is supported */ WakeLevel = PowerDeviceUnspecified; if (PowerCapabilities.PMC.Capabilities.Support.PMED0) WakeLevel = PowerDeviceD0; if (PowerCapabilities.PMC.Capabilities.Support.PMED1) WakeLevel = PowerDeviceD1; if (PowerCapabilities.PMC.Capabilities.Support.PMED2) WakeLevel = PowerDeviceD2; if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot) WakeLevel = PowerDeviceD3; if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold) WakeLevel = PowerDeviceD3; PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
/* Convert the PCI power state to the NT power state */ PdoExtension->PowerState.CurrentDeviceState = PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
/* Save all the power capabilities */ PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities; DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n", WakeLevel, PdoExtension->PowerState.CurrentDeviceState); } } } }
/* At the very end of all this, does this device not have power management? */ if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS) { /* Then guess the current state based on whether the decodes are on */ PdoExtension->PowerState.CurrentDeviceState = PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER) ? PowerDeviceD0: PowerDeviceD3; DPRINT1("PM is off, so assumed device is: %d based on enables\n", PdoExtension->PowerState.CurrentDeviceState); }}
VOIDNTAPIPciWriteLimitsAndRestoreCurrent(IN PVOID Reserved, IN PVOID Context2){ PPCI_CONFIGURATOR_CONTEXT Context = Context2; PPCI_COMMON_HEADER PciData, Current; PPCI_PDO_EXTENSION PdoExtension;
UNREFERENCED_PARAMETER(Reserved);
/* Grab all parameters from the context */ PdoExtension = Context->PdoExtension; Current = Context->Current; PciData = Context->PciData;
/* Write the limit discovery header */ PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
/* Now read what the device indicated the limits are */ PciReadDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
/* Then write back the original configuration header */ PciWriteDeviceConfig(PdoExtension, Current, 0, PCI_COMMON_HDR_LENGTH);
/* Copy back the original command that was saved in the context */ Current->Command = Context->Command; if (Context->Command) { /* Program it back into the device */ PciWriteDeviceConfig(PdoExtension, &Context->Command, FIELD_OFFSET(PCI_COMMON_HEADER, Command), sizeof(USHORT)); }
/* Copy back the original status that was saved as well */ Current->Status = Context->Status;
/* Call the configurator to restore any other data that might've changed */ Context->Configurator->RestoreCurrent(Context);}
NTSTATUSNTAPIPcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context){ PPCI_CONFIGURATOR Configurator; PPCI_COMMON_HEADER PciData, Current; PPCI_PDO_EXTENSION PdoExtension; PCI_IPI_CONTEXT IpiContext; PIO_RESOURCE_DESCRIPTOR IoDescriptor; ULONG Offset; PAGED_CODE();
/* Grab all parameters from the context */ PdoExtension = Context->PdoExtension; Current = Context->Current; PciData = Context->PciData;
/* Save the current PCI Command and Status word */ Context->Status = Current->Status; Context->Command = Current->Command;
/* Now that they're saved, clear the status, and disable all decodes */ Current->Status = 0; Current->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER);
/* Make a copy of the current PCI configuration header (with decodes off) */ RtlCopyMemory(PciData, Current, PCI_COMMON_HDR_LENGTH);
/* Locate the correct resource configurator for this type of device */ Configurator = &PciConfigurators[PdoExtension->HeaderType]; Context->Configurator = Configurator;
/* Initialize it, which will typically setup the BARs for limit discovery */ Configurator->Initialize(Context);
/* Check for critical devices and PCI Debugging devices */ if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) || (PdoExtension->OnDebugPath)) { /* Specifically check for a PCI Debugging device */ if (PdoExtension->OnDebugPath) { /* Was it enabled for bus mastering? */ if (Context->Command & PCI_ENABLE_BUS_MASTER) { /* This decode needs to be re-enabled so debugging can work */ PciData->Command |= PCI_ENABLE_BUS_MASTER; Current->Command |= PCI_ENABLE_BUS_MASTER; }
/* Disable the debugger while the discovery is happening */ KdDisableDebugger(); }
/* For these devices, an IPI must be sent to force high-IRQL discovery */ IpiContext.Barrier = 1; IpiContext.RunCount = 1; IpiContext.DeviceExtension = PdoExtension; IpiContext.Function = PciWriteLimitsAndRestoreCurrent; IpiContext.Context = Context; KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&IpiContext);
/* Re-enable the debugger if this was a PCI Debugging Device */ if (PdoExtension->OnDebugPath) KdEnableDebugger(); } else { /* Otherwise, it's safe to do this in-line at low IRQL */ PciWriteLimitsAndRestoreCurrent(PdoExtension, Context); }
/* * Check if it's valid to compare the headers to see if limit discovery mode * has properly exited (the expected case is that the PCI header would now * be equal to what it was before). In some cases, it is known that this will * fail, because during PciApplyHacks (among other places), software hacks * had to be applied to the header, which the hardware-side will not see, and * thus the headers would appear "different". */ if (!PdoExtension->ExpectedWritebackFailure) { /* Read the current PCI header now, after discovery has completed */ PciReadDeviceConfig(PdoExtension, PciData + 1, 0, PCI_COMMON_HDR_LENGTH);
/* Check if the current header at entry, is equal to the header now */ Offset = RtlCompareMemory(PciData + 1, Current, PCI_COMMON_HDR_LENGTH); if (Offset != PCI_COMMON_HDR_LENGTH) { /* It's not, which means configuration somehow changed, dump this */ DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset); PciDebugDumpCommonConfig(PciData + 1); DPRINT1("----------\n"); PciDebugDumpCommonConfig(Current); } }
/* This PDO should not already have resources, since this is only done once */ ASSERT(PdoExtension->Resources == NULL);
/* Allocate the structure that will hold the discovered resources and limits */ PdoExtension->Resources = ExAllocatePoolWithTag(NonPagedPool, sizeof(PCI_FUNCTION_RESOURCES), 'BicP'); if (!PdoExtension->Resources) return STATUS_INSUFFICIENT_RESOURCES;
/* Clear it out for now */ RtlZeroMemory(PdoExtension->Resources, sizeof(PCI_FUNCTION_RESOURCES));
/* Now call the configurator, which will first store the limits... */ Configurator->SaveLimits(Context);
/* ...and then store the current resources being used */ Configurator->SaveCurrentSettings(Context);
/* Loop all the limit descriptors backwards */ IoDescriptor = &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1]; while (TRUE) { /* Keep going until a non-null descriptor is found */ IoDescriptor--; if (IoDescriptor->Type != CmResourceTypeNull) break;
/* This is a null descriptor, is it the last one? */ if (IoDescriptor == &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1]) { /* This means the descriptor is NULL, which means discovery failed */ DPRINT1("PCI Resources fail!\n");
/* No resources will be assigned for the device */ ExFreePoolWithTag(PdoExtension->Resources, 0); PdoExtension->Resources = NULL; break; } }
/* Return success here, even if the device has no assigned resources */ return STATUS_SUCCESS;}
NTSTATUSNTAPIPciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension, IN PPCI_COMMON_HEADER Current, IN ULONGLONG HackFlags){ NTSTATUS Status; PPCI_COMMON_HEADER PciData; PCI_CONFIGURATOR_CONTEXT Context; PAGED_CODE();
/* Do the hackflags indicate this device should be skipped? */ if (PciSkipThisFunction(Current, PdoExtension->Slot, PCI_SKIP_RESOURCE_ENUMERATION, HackFlags)) { /* Do not process its resources */ return STATUS_SUCCESS; }
/* Allocate a buffer to hold two PCI configuration headers */ PciData = ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH, 'BicP'); if (!PciData) return STATUS_INSUFFICIENT_RESOURCES;
/* Set up the context for the resource enumeration, and do it */ Context.Current = Current; Context.PciData = PciData; Context.PdoExtension = PdoExtension; Status = PcipGetFunctionLimits(&Context);
/* Enumeration is completed, free the PCI headers and return the status */ ExFreePoolWithTag(PciData, 0); return Status;}
VOIDNTAPIPciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension){ PPCI_PDO_EXTENSION PdoExtension; PDEVICE_OBJECT PhysicalDeviceObject; PAGED_CODE();
/* Get the PDO Extension */ PhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject; PdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
/* Cheeck if this is the root bus */ if (!PCI_IS_ROOT_FDO(DeviceExtension)) { /* Not really handling this year */ UNIMPLEMENTED_DBGBREAK();
/* Check for PCI bridges with the ISA bit set, or required */ if ((PdoExtension) && (PciClassifyDeviceType(PdoExtension) == PciTypePciBridge) && ((PdoExtension->Dependent.type1.IsaBitRequired) || (PdoExtension->Dependent.type1.IsaBitSet))) { /* We'll need to do some legacy support */ UNIMPLEMENTED_DBGBREAK(); } } else { /* Scan all of the root bus' children bridges */ for (PdoExtension = DeviceExtension->ChildBridgePdoList; PdoExtension; PdoExtension = PdoExtension->NextBridge) { /* Find any that have the VGA decode bit on */ if (PdoExtension->Dependent.type1.VgaBitSet) { /* Again, some more legacy support we'll have to do */ UNIMPLEMENTED_DBGBREAK(); } } }
/* Check for ACPI systems where the OS assigns bus numbers */ if (PciAssignBusNumbers) { /* Not yet supported */ UNIMPLEMENTED_DBGBREAK(); }}
NTSTATUSNTAPIPciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension){ ULONG MaxDevice = PCI_MAX_DEVICES; BOOLEAN ProcessFlag = FALSE; ULONG i, j, k, Size; USHORT CapOffset, TempOffset; LONGLONG HackFlags; PDEVICE_OBJECT DeviceObject; UCHAR Buffer[PCI_COMMON_HDR_LENGTH]; UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH]; PPCI_COMMON_HEADER PciData = (PVOID)Buffer; PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer; PCI_SLOT_NUMBER PciSlot; PCHAR Name; NTSTATUS Status; PPCI_PDO_EXTENSION PdoExtension, NewExtension; PPCI_PDO_EXTENSION* BridgeExtension; PWCHAR DescriptionText; USHORT SubVendorId, SubSystemId; PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader; UCHAR SecondaryBus; DPRINT1("PCI Scan Bus: FDO Extension @ 0x%p, Base Bus = 0x%x\n", DeviceExtension, DeviceExtension->BaseBus);
/* Is this the root FDO? */ if (!PCI_IS_ROOT_FDO(DeviceExtension)) { /* Get the PDO for the child bus */ PdoExtension = DeviceExtension->PhysicalDeviceObject->DeviceExtension; ASSERT_PDO(PdoExtension);
/* Check for hack which only allows bus to have one child device */ if (PdoExtension->HackFlags & PCI_HACK_ONE_CHILD) MaxDevice = 1;
/* Check if the secondary bus number has changed */ PciReadDeviceConfig(PdoExtension, &SecondaryBus, FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.SecondaryBus), sizeof(UCHAR)); if (SecondaryBus != PdoExtension->Dependent.type1.SecondaryBus) { UNIMPLEMENTED_DBGBREAK("PCI: Bus numbers have been changed! Restoring originals.\n"); } }
/* Loop every device on the bus */ PciSlot.u.bits.Reserved = 0; i = DeviceExtension->BaseBus; for (j = 0; j < MaxDevice; j++) { /* Loop every function of each device */ PciSlot.u.bits.DeviceNumber = j; for (k = 0; k < PCI_MAX_FUNCTION; k++) { /* Build the final slot structure */ PciSlot.u.bits.FunctionNumber = k;
/* Read the vendor for this slot */ PciReadSlotConfig(DeviceExtension, PciSlot, PciData, 0, sizeof(USHORT));
/* Skip invalid device */ if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
/* Now read the whole header */ PciReadSlotConfig(DeviceExtension, PciSlot, &PciData->DeviceID, sizeof(USHORT), PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
/* Apply any hacks before even analyzing the configuration header */ PciApplyHacks(DeviceExtension, PciData, PciSlot, PCI_HACK_FIXUP_BEFORE_CONFIGURATION, NULL);
/* Dump device that was found */ DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n", PciSlot.u.AsULONG, i, j, k);
/* Dump the device's header */ PciDebugDumpCommonConfig(PciData);
/* Find description for this device for the debugger's sake */ DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass, PciData->SubClass); DPRINT1("Device Description \"%S\".\n", DescriptionText ? DescriptionText : L"(NULL)"); if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
/* Check if there is an ACPI Watchdog Table */ if (WdTable) { /* Check if this PCI device is the ACPI Watchdog Device... */ UNIMPLEMENTED_DBGBREAK(); }
/* Check for non-simple devices */ if ((PCI_MULTIFUNCTION_DEVICE(PciData)) || (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV)) { /* No subsystem data defined for these kinds of bridges */ SubVendorId = 0; SubSystemId = 0; } else { /* Read the subsystem information from the PCI header */ SubVendorId = PciData->u.type0.SubVendorID; SubSystemId = PciData->u.type0.SubSystemID; }
/* Get any hack flags for this device */ HackFlags = PciGetHackFlags(PciData->VendorID, PciData->DeviceID, SubVendorId, SubSystemId, PciData->RevisionID);
/* Check if this device is considered critical by the OS */ if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass)) { /* Check if normally the decodes would be disabled */ if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES)) { /* Because this device is critical, don't disable them */ DPRINT1("Not allowing PM Because device is critical\n"); HackFlags |= PCI_HACK_CRITICAL_DEVICE; } }
/* PCI bridges with a VGA card are also considered critical */ if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) && (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) && (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) && !(HackFlags & PCI_HACK_DONT_DISABLE_DECODES)) { /* Do not disable their decodes either */ DPRINT1("Not allowing PM because device is VGA\n"); HackFlags |= PCI_HACK_CRITICAL_DEVICE; }
/* Check if the device should be skipped for whatever reason */ if (PciSkipThisFunction(PciData, PciSlot, PCI_SKIP_DEVICE_ENUMERATION, HackFlags)) { /* Skip this device */ continue; }
/* Check if a PDO has already been created for this device */ PdoExtension = PciFindPdoByFunction(DeviceExtension, PciSlot.u.AsULONG, PciData); if (PdoExtension) { /* Rescan scenarios are not yet implemented */ UNIMPLEMENTED_DBGBREAK(); }
/* Bus processing will need to happen */ ProcessFlag = TRUE;
/* Create the PDO for this device */ Status = PciPdoCreate(DeviceExtension, PciSlot, &DeviceObject); ASSERT(NT_SUCCESS(Status)); NewExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
/* Check for broken devices with wrong/no class codes */ if (HackFlags & PCI_HACK_FAKE_CLASS_CODE) { /* Setup a default one */ PciData->BaseClass = PCI_CLASS_BASE_SYSTEM_DEV; PciData->SubClass = PCI_SUBCLASS_SYS_OTHER;
/* Device will behave erratically when reading back data */ NewExtension->ExpectedWritebackFailure = TRUE; }
/* Clone all the information from the header */ NewExtension->VendorId = PciData->VendorID; NewExtension->DeviceId = PciData->DeviceID; NewExtension->RevisionId = PciData->RevisionID; NewExtension->ProgIf = PciData->ProgIf; NewExtension->SubClass = PciData->SubClass; NewExtension->BaseClass = PciData->BaseClass; NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
/* Check for modern bridge types, which are managed by the driver */ if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) && ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) || (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS))) { /* Acquire this device's lock */ KeEnterCriticalRegion(); KeWaitForSingleObject(&DeviceExtension->ChildListLock, Executive, KernelMode, FALSE, NULL);
/* Scan the bridge list until the first free entry */ for (BridgeExtension = &DeviceExtension->ChildBridgePdoList; *BridgeExtension; BridgeExtension = &(*BridgeExtension)->NextBridge);
/* Add this PDO as a bridge */ *BridgeExtension = NewExtension; ASSERT(NewExtension->NextBridge == NULL);
/* Release this device's lock */ KeSetEvent(&DeviceExtension->ChildListLock, IO_NO_INCREMENT, FALSE); KeLeaveCriticalRegion(); }
/* Get the PCI BIOS configuration saved in the registry */ Status = PciGetBiosConfig(NewExtension, BiosData); if (NT_SUCCESS(Status)) { /* This path has not yet been fully tested by eVb */ DPRINT1("Have BIOS configuration!\n"); UNIMPLEMENTED;
/* Check if the PCI BIOS configuration has changed */ if (!PcipIsSameDevice(NewExtension, BiosData)) { /* This is considered failure, and new data will be saved */ Status = STATUS_UNSUCCESSFUL; } else { /* Data is still correct, check for interrupt line change */ if (BiosData->u.type0.InterruptLine != PciData->u.type0.InterruptLine) { /* Update the current BIOS with the saved interrupt line */ PciWriteDeviceConfig(NewExtension, &BiosData->u.type0.InterruptLine, FIELD_OFFSET(PCI_COMMON_HEADER, u.type0.InterruptLine), sizeof(UCHAR)); }
/* Save the BIOS interrupt line and the initial command */ NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine; NewExtension->InitialCommand = BiosData->Command; } }
/* Check if no saved data was present or if it was a mismatch */ if (!NT_SUCCESS(Status)) { /* Save the new data */ Status = PciSaveBiosConfig(NewExtension, PciData); ASSERT(NT_SUCCESS(Status));
/* Save the interrupt line and command from the device */ NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine; NewExtension->InitialCommand = PciData->Command; }
/* Save original command from the device and hack flags */ NewExtension->CommandEnables = PciData->Command; NewExtension->HackFlags = HackFlags;
/* Get power, AGP, and other capability data */ PciGetEnhancedCapabilities(NewExtension, PciData);
/* Now configure the BARs */ Status = PciGetFunctionLimits(NewExtension, PciData, HackFlags);
/* Power up the device */ PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
/* Apply any device hacks required for enumeration */ PciApplyHacks(DeviceExtension, PciData, PciSlot, PCI_HACK_FIXUP_AFTER_CONFIGURATION, NewExtension);
/* Save interrupt pin */ NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
/* * Use either this device's actual IRQ line or, if it's connected on * a master bus whose IRQ line is actually connected to the host, use * the HAL to query the bus' IRQ line and store that as the adjusted * interrupt line instead */ NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
/* Check if this device is used for PCI debugger cards */ NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
/* Check for devices with invalid/bogus subsystem data */ if (HackFlags & PCI_HACK_NO_SUBSYSTEM) { /* Set the subsystem information to zero instead */ NewExtension->SubsystemVendorId = 0; NewExtension->SubsystemId = 0; }
/* Scan all capabilities */ CapOffset = NewExtension->CapabilitiesPtr; while (CapOffset) { /* Read this header */ TempOffset = PciReadDeviceCapability(NewExtension, CapOffset, 0, &CapHeader, sizeof(PCI_CAPABILITIES_HEADER)); if (TempOffset != CapOffset) { /* This is a strange issue that shouldn't happen normally */ DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n", CapOffset); ASSERT(TempOffset == CapOffset); }
/* Check for capabilities that this driver cares about */ switch (CapHeader.CapabilityID) { /* Power management capability is heavily used by the bus */ case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
/* Dump the capability */ Name = "POWER"; Size = sizeof(PCI_PM_CAPABILITY); break;
/* AGP capability is required for AGP bus functionality */ case PCI_CAPABILITY_ID_AGP:
/* Dump the capability */ Name = "AGP"; Size = sizeof(PCI_AGP_CAPABILITY); break;
/* This driver doesn't really use anything other than that */ default:
/* Windows prints this, we could do a translation later */ Name = "UNKNOWN CAPABILITY"; Size = 0; break; }
/* Check if this is a capability that should be dumped */ if (Size) { /* Read the whole capability data */ TempOffset = PciReadDeviceCapability(NewExtension, CapOffset, CapHeader.CapabilityID, &CapHeader, Size);
if (TempOffset != CapOffset) { /* Again, a strange issue that shouldn't be seen */ DPRINT1("- Failed to read capability data. ***\n"); ASSERT(TempOffset == CapOffset); } }
/* Dump this capability */ DPRINT1("CAP @%02x ID %02x (%s)\n", CapOffset, CapHeader.CapabilityID, Name); for (i = 0; i < Size; i += 2) DPRINT1(" %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i)); DPRINT1("\n");
/* Check the next capability */ CapOffset = CapHeader.Next; }
/* Check for IDE controllers */ if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) && (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR)) { /* Do not allow them to power down completely */ NewExtension->DisablePowerDown = TRUE; }
/* * Check if this is a legacy bridge. Note that the i82375 PCI/EISA * bridge that is present on certain NT Alpha machines appears as * non-classified so detect it manually by scanning for its VID/PID. */ if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) && ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) || (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) || (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) || ((NewExtension->VendorId == 0x8086) && (NewExtension->DeviceId == 0x482))) { /* Do not allow these legacy bridges to be powered down */ NewExtension->DisablePowerDown = TRUE; }
/* Check if the BIOS did not configure a cache line size */ if (!PciData->CacheLineSize) { /* Check if the device is disabled */ if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER))) { /* Check if this is a PCI-X device*/ TempOffset = PciReadDeviceCapability(NewExtension, NewExtension->CapabilitiesPtr, PCI_CAPABILITY_ID_PCIX, &PcixCapHeader, sizeof(PCI_CAPABILITIES_HEADER));
/* * A device with default cache line size and latency timer * settings is considered to be unconfigured. Note that on * PCI-X, the reset value of the latency timer field in the * header is 64, not 0, hence why the check for PCI-X caps * was required, and the value used here below. */ if (!(PciData->LatencyTimer) || ((TempOffset) && (PciData->LatencyTimer == 64))) { /* Keep track of the fact that it needs configuration */ DPRINT1("PCI - ScanBus, PDOx %p found unconfigured\n", NewExtension); NewExtension->NeedsHotPlugConfiguration = TRUE; } } }
/* Save latency and cache size information */ NewExtension->SavedLatencyTimer = PciData->LatencyTimer; NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
/* The PDO is now ready to go */ DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; } }
/* Enumeration completed, do a final pass now that all devices are found */ if (ProcessFlag) PciProcessBus(DeviceExtension); return STATUS_SUCCESS;}
NTSTATUSNTAPIPciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension, IN OUT PDEVICE_RELATIONS *pDeviceRelations){ NTSTATUS Status; PPCI_PDO_EXTENSION PdoExtension; ULONG PdoCount = 0; PDEVICE_RELATIONS DeviceRelations, NewRelations; SIZE_T Size; PDEVICE_OBJECT DeviceObject, *ObjectArray; PAGED_CODE();
/* Make sure the FDO is started */ ASSERT(DeviceExtension->DeviceState == PciStarted);
/* Synchronize while we enumerate the bus */ Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation); if (!NT_SUCCESS(Status)) return Status;
/* Scan all children PDO */ for (PdoExtension = DeviceExtension->ChildPdoList; PdoExtension; PdoExtension = PdoExtension->Next) { /* Invalidate them */ PdoExtension->NotPresent = TRUE; }
/* Scan the PCI Bus */ Status = PciScanBus(DeviceExtension); ASSERT(NT_SUCCESS(Status));
/* Enumerate all children PDO again */ for (PdoExtension = DeviceExtension->ChildPdoList; PdoExtension; PdoExtension = PdoExtension->Next) { /* Check for PDOs that are still invalidated */ if (PdoExtension->NotPresent) { /* This means this PDO existed before, but not anymore */ PdoExtension->ReportedMissing = TRUE; DPRINT1("PCI - Old device (pdox) %p not found on rescan.\n", PdoExtension); } else { /* Increase count of detected PDOs */ PdoCount++; } }
/* Read the current relations and add the newly discovered relations */ DeviceRelations = *pDeviceRelations; Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + PdoCount * sizeof(PDEVICE_OBJECT); if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
/* Allocate the device relations */ NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP'); if (!NewRelations) { /* Out of space, cancel the operation */ PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation); return STATUS_INSUFFICIENT_RESOURCES; }
/* Check if there were any older relations */ NewRelations->Count = 0; if (DeviceRelations) { /* Copy the old relations into the new buffer, then free the old one */ RtlCopyMemory(NewRelations, DeviceRelations, FIELD_OFFSET(DEVICE_RELATIONS, Objects) + DeviceRelations->Count * sizeof(PDEVICE_OBJECT)); ExFreePoolWithTag(DeviceRelations, 0); }
/* Print out that we're ready to dump relations */ DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %p (bus 0x%02x)\n", DeviceExtension, DeviceExtension->BaseBus);
/* Loop the current PDO children and the device relation object array */ PdoExtension = DeviceExtension->ChildPdoList; ObjectArray = &NewRelations->Objects[NewRelations->Count]; while (PdoExtension) { /* Dump this relation */ DPRINT1(" QDR PDO %p (x %p)%s\n", PdoExtension->PhysicalDeviceObject, PdoExtension, PdoExtension->NotPresent ? "<Omitted, device flaged not present>" : "");
/* Is this PDO present? */ if (!PdoExtension->NotPresent) { /* Reference it and add it to the array */ DeviceObject = PdoExtension->PhysicalDeviceObject; ObReferenceObject(DeviceObject); *ObjectArray++ = DeviceObject; }
/* Go to the next PDO */ PdoExtension = PdoExtension->Next; }
/* Terminate dumping the relations */ DPRINT1(" QDR Total PDO count = %u (%u already in list)\n", NewRelations->Count + PdoCount, NewRelations->Count);
/* Return the final count and the new buffer */ NewRelations->Count += PdoCount; *pDeviceRelations = NewRelations; return STATUS_SUCCESS;}
NTSTATUSNTAPIPciSetResources(IN PPCI_PDO_EXTENSION PdoExtension, IN BOOLEAN DoReset, IN BOOLEAN SomethingSomethingDarkSide){ PPCI_FDO_EXTENSION FdoExtension; UCHAR NewCacheLineSize, NewLatencyTimer; PCI_COMMON_HEADER PciData; BOOLEAN Native; PPCI_CONFIGURATOR Configurator;
UNREFERENCED_PARAMETER(SomethingSomethingDarkSide);
/* Get the FDO and read the configuration data */ FdoExtension = PdoExtension->ParentFdoExtension; PciReadDeviceConfig(PdoExtension, &PciData, 0, PCI_COMMON_HDR_LENGTH);
/* Make sure this is still the same device */ if (!PcipIsSameDevice(PdoExtension, &PciData)) { /* Fail */ ASSERTMSG("PCI Set resources - not same device.\n", FALSE); return STATUS_DEVICE_DOES_NOT_EXIST; }
/* Nothing to set for a host bridge */ if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) && (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST)) { /* Fake success */ return STATUS_SUCCESS; }
/* Check if an IDE controller is being reset */ if ((DoReset) && (PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) && (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR)) { /* Turn off native mode */ Native = PciConfigureIdeController(PdoExtension, &PciData, FALSE); ASSERT(Native == PdoExtension->IDEInNativeMode); }
/* Check for update of a hotplug device, or first configuration of one */ if ((PdoExtension->NeedsHotPlugConfiguration) && (FdoExtension->HotPlugParameters.Acquired)) { /* Don't have hotplug devices to test with yet, QEMU 0.14 should */ UNIMPLEMENTED_DBGBREAK(); }
/* Locate the correct resource configurator for this type of device */ Configurator = &PciConfigurators[PdoExtension->HeaderType];
/* Apply the settings change */ Configurator->ChangeResourceSettings(PdoExtension, &PciData);
/* Assume no update needed */ PdoExtension->UpdateHardware = FALSE;
/* Check if a reset is needed */ if (DoReset) { /* Reset resources */ Configurator->ResetDevice(PdoExtension, &PciData); PciData.u.type0.InterruptLine = PdoExtension->RawInterruptLine; }
/* Check if the latency timer changed */ NewLatencyTimer = PdoExtension->SavedLatencyTimer; if (PciData.LatencyTimer != NewLatencyTimer) { /* Debug notification */ DPRINT1("PCI (pdox %p) changing latency from %02x to %02x.\n", PdoExtension, PciData.LatencyTimer, NewLatencyTimer); }
/* Check if the cache line changed */ NewCacheLineSize = PdoExtension->SavedCacheLineSize; if (PciData.CacheLineSize != NewCacheLineSize) { /* Debug notification */ DPRINT1("PCI (pdox %p) changing cache line size from %02x to %02x.\n", PdoExtension, PciData.CacheLineSize, NewCacheLineSize); }
/* Inherit data from PDO extension */ PciData.LatencyTimer = PdoExtension->SavedLatencyTimer; PciData.CacheLineSize = PdoExtension->SavedCacheLineSize; PciData.u.type0.InterruptLine = PdoExtension->RawInterruptLine;
/* Apply any resource hacks required */ PciApplyHacks(FdoExtension, &PciData, PdoExtension->Slot, PCI_HACK_FIXUP_BEFORE_UPDATE, PdoExtension);
/* Check if I/O space was disabled by administrator or driver */ if (PdoExtension->IoSpaceNotRequired) { /* Don't turn on the decode */ PdoExtension->CommandEnables &= ~PCI_ENABLE_IO_SPACE; }
/* Update the device with the new settings */ PciUpdateHardware(PdoExtension, &PciData);
/* Update complete */ PdoExtension->RawInterruptLine = PciData.u.type0.InterruptLine; PdoExtension->NeedsHotPlugConfiguration = FALSE; return STATUS_SUCCESS;}
/* EOF */