12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- pci.c
- Abstract:
- This module implements the PCI driver.
- Author:
- Evan Green 16-Sep-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "pci.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- PciAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- );
- VOID
- PciDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- PciDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- KSTATUS
- PcipReportChildren (
- PIRP QueryChildrenIrp,
- PPCI_DEVICE PciDevice
- );
- VOID
- PcipEnumerateChildren (
- PDEVICE Device,
- PPCI_DEVICE PciDevice
- );
- KSTATUS
- PcipQueryResourceRequirements (
- PDEVICE Device,
- PPCI_DEVICE DeviceObject,
- PIRP Irp
- );
- KSTATUS
- PcipQueryBridgeResourceRequirements (
- PDEVICE Device,
- PPCI_DEVICE DeviceObject,
- PIRP Irp
- );
- KSTATUS
- PcipSetDeviceResources (
- PPCI_DEVICE DeviceContext,
- PRESOURCE_ALLOCATION_LIST AllocationList
- );
- VOID
- PcipEnableDevice (
- PPCI_DEVICE DeviceContext
- );
- KSTATUS
- PcipSetBridgeDeviceResources (
- PPCI_DEVICE DeviceContext,
- PRESOURCE_ALLOCATION_LIST AllocationList
- );
- ULONG
- PcipFindDevice (
- PPCI_DEVICE ParentBus,
- UCHAR Device,
- UCHAR Function
- );
- ULONG
- PcipGetNewChildIndex (
- PPCI_DEVICE ParentBus
- );
- KSTATUS
- PcipQueryInterface (
- PIRP Irp,
- PPCI_DEVICE PciDevice
- );
- KSTATUS
- PcipInterfaceReadConfigSpace (
- PVOID DeviceToken,
- ULONG Offset,
- ULONG AccessSize,
- PULONGLONG Value
- );
- KSTATUS
- PcipInterfaceWriteConfigSpace (
- PVOID DeviceToken,
- ULONG Offset,
- ULONG AccessSize,
- ULONGLONG Value
- );
- KSTATUS
- PcipInterfaceReadSpecificConfigSpace (
- PVOID DeviceToken,
- ULONG BusNumber,
- ULONG DeviceNumber,
- ULONG FunctionNumber,
- ULONG Offset,
- ULONG AccessSize,
- PULONGLONG Value
- );
- KSTATUS
- PcipInterfaceWriteSpecificConfigSpace (
- PVOID DeviceToken,
- ULONG BusNumber,
- ULONG DeviceNumber,
- ULONG FunctionNumber,
- ULONG Offset,
- ULONG AccessSize,
- ULONGLONG Value
- );
- KSTATUS
- PcipStartBusDevice (
- PIRP StartIrp,
- PPCI_DEVICE DeviceContext
- );
- KSTATUS
- PcipCreateFunctionInterfaces (
- PDEVICE Device,
- PPCI_DEVICE PciDevice
- );
- KSTATUS
- PcipCreateBusInterfaces (
- PDEVICE Device,
- PPCI_DEVICE PciDevice
- );
- PSTR
- PcipGetClassId (
- ULONG ClassCode
- );
- KSTATUS
- PcipGetBusDriverDevice (
- PDEVICE OsDevice,
- PPCI_DEVICE *BusDriverDevice
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PDRIVER PciDriver = NULL;
- //
- // Store the UUID of PCI configuration space access.
- //
- UUID PciConfigSpaceUuid = UUID_PCI_CONFIG_ACCESS;
- //
- // Store the UUID of specific PCI configuration space access.
- //
- UUID PciSpecificConfigSpaceUuid = UUID_PCI_CONFIG_ACCESS_SPECIFIC;
- //
- // Store the UUID of the PCI MSI and MSI-X access.
- //
- UUID PciMessageSignaledInterruptsUuid = UUID_PCI_MESSAGE_SIGNALED_INTERRUPTS;
- //
- // Store the UUID of the ACPI bus number interface.
- //
- UUID PciAcpiBusAddressUuid = UUID_ACPI_BUS_ADDRESS;
- //
- // Store the UUID of the internal PCI interface for getting the bus driver's
- // PCI device structure.
- //
- UUID PciBusDriverDeviceUuid =
- {{0x73696D6F, 0x74207365, 0x656B206F, 0x61207066}};
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine is the entry point for the PCI driver. It registers its other
- dispatch functions, and performs driver-wide initialization.
- Arguments:
- Driver - Supplies a pointer to the driver object.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code on error.
- --*/
- {
- DRIVER_FUNCTION_TABLE FunctionTable;
- KSTATUS Status;
- PciDriver = Driver;
- RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
- FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
- FunctionTable.AddDevice = PciAddDevice;
- FunctionTable.DispatchStateChange = PciDispatchStateChange;
- FunctionTable.DispatchSystemControl = PciDispatchSystemControl;
- Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
- return Status;
- }
- KSTATUS
- PciAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- )
- /*++
- Routine Description:
- This routine is called when a PCI device is detected. PCI will attach
- itself to the driver stack.
- Arguments:
- Driver - Supplies a pointer to the driver being called.
- DeviceId - Supplies a pointer to a string with the device ID.
- ClassId - Supplies a pointer to a string containing the device's class ID.
- CompatibleIds - Supplies a pointer to a string containing device IDs
- that would be compatible with this device.
- DeviceToken - Supplies an opaque token that the driver can use to identify
- the device in the system. This token should be used when attaching to
- the stack.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_UNKNOWN_DEVICE if the device is not recognized by the driver. This
- usually a sign of misconfiguration (assigning PCI as a driver for something
- it does not own).
- Failure code if the driver was unsuccessful in attaching itself.
- --*/
- {
- PPCI_DEVICE Device;
- PCI_DEVICE_TYPE DeviceType;
- BOOL Match;
- KSTATUS Status;
- Device = NULL;
- DeviceType = PciDeviceInvalid;
- Status = STATUS_UNKNOWN_DEVICE;
- //
- // The PCI driver is the functional driver for the PCI Root device.
- //
- Match = IoAreDeviceIdsEqual(DeviceId, PCI_BUS_ID);
- if (Match == FALSE) {
- Match = IoAreDeviceIdsEqual(DeviceId, PCI_EXPRESS_BUS_ID);
- }
- if (Match != FALSE) {
- DeviceType = PciDeviceBus;
- } else {
- if ((Match == FALSE) && (ClassId != NULL)) {
- Match = RtlAreStringsEqual(ClassId,
- PCI_BRIDGE_CLASS_ID,
- sizeof(PCI_BRIDGE_CLASS_ID));
- }
- if ((Match == FALSE) && (ClassId != NULL)) {
- Match = RtlAreStringsEqual(ClassId,
- PCI_SUBTRACTIVE_BRIDGE_CLASS_ID,
- sizeof(PCI_SUBTRACTIVE_BRIDGE_CLASS_ID));
- }
- if (Match != FALSE) {
- DeviceType = PciDeviceBridge;
- }
- }
- //
- // If the device was not idenfified, then the system was misconfigured to
- // have PCI be the driver of some random device.
- //
- if (Match == FALSE) {
- Status = STATUS_UNKNOWN_DEVICE;
- goto AddDeviceEnd;
- }
- ASSERT(DeviceType != PciDeviceInvalid);
- Device = MmAllocateNonPagedPool(sizeof(PCI_DEVICE), PCI_ALLOCATION_TAG);
- if (Device == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddDeviceEnd;
- }
- RtlZeroMemory(Device, sizeof(PCI_DEVICE));
- Device->Type = DeviceType;
- Device->BusNumber = 0;
- if (DeviceType == PciDeviceBus) {
- Device->ReadConfig = PcipRootReadConfig;
- Device->WriteConfig = PcipRootWriteConfig;
- }
- Status = IoAttachDriverToDevice(Driver, DeviceToken, Device);
- if (!KSUCCESS(Status)) {
- goto AddDeviceEnd;
- }
- AddDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Device != NULL) {
- MmFreeNonPagedPool(Device);
- }
- }
- return Status;
- }
- VOID
- PciDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PPCI_DEVICE PciDevice;
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorStateChange);
- PciDevice = DeviceContext;
- //
- // The IRP is on its way down the stack. Do most processing here.
- //
- if (Irp->Direction == IrpDown) {
- Status = STATUS_NOT_SUPPORTED;
- switch (Irp->MinorCode) {
- //
- // If the device is a function (therefore PCI is acting as the bus
- // driver), then return the device's resources.
- //
- case IrpMinorQueryResources:
- if (PciDevice->Type == PciDeviceFunction) {
- if (PciDevice->DeviceIsBridge != FALSE) {
- Status = PcipQueryBridgeResourceRequirements(Irp->Device,
- PciDevice,
- Irp);
- } else {
- Status = PcipQueryResourceRequirements(Irp->Device,
- PciDevice,
- Irp);
- }
- IoCompleteIrp(PciDriver, Irp, Status);
- }
- break;
- //
- // Assume the device is already started. Expose the interface for
- // interacting with the device's PCI config space.
- //
- case IrpMinorStartDevice:
- if (PciDevice->Type == PciDeviceFunction) {
- //
- // Set the BARs and enable the device.
- //
- if (PciDevice->DeviceIsBridge != FALSE) {
- Status = PcipSetBridgeDeviceResources(
- DeviceContext,
- Irp->U.StartDevice.BusLocalResources);
- } else {
- Status = PcipSetDeviceResources(
- DeviceContext,
- Irp->U.StartDevice.BusLocalResources);
- }
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(PciDriver, Irp, Status);
- break;
- }
- //
- // Enable decoding on the device.
- //
- if (PciDevice->DeviceIsBridge == FALSE) {
- PcipEnableDevice(DeviceContext);
- }
- //
- // As the bus driver of a function, PCI completes the IRP.
- //
- IoCompleteIrp(PciDriver, Irp, Status);
- } else if ((PciDevice->Type == PciDeviceBus) ||
- (PciDevice->Type == PciDeviceBridge)) {
- Status = PcipStartBusDevice(Irp, PciDevice);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(PciDriver, Irp, Status);
- }
- Status = STATUS_SUCCESS;
- }
- break;
- //
- // Enumerate any children on the bus.
- //
- case IrpMinorQueryChildren:
- //
- // If the driver is acting as a bus driver for a function, there are
- // no children. Complete the IRP.
- //
- if (PciDevice->Type == PciDeviceFunction) {
- IoCompleteIrp(PciDriver, Irp, STATUS_SUCCESS);
- //
- // If PCI is acting as the functional driver, enumerate the
- // children, but don't complete the IRP.
- //
- } else {
- Status = PcipReportChildren(Irp, DeviceContext);
- }
- break;
- //
- // Process interface requests.
- //
- case IrpMinorQueryInterface:
- Status = PcipQueryInterface(Irp, DeviceContext);
- if (Status != STATUS_NO_INTERFACE) {
- IoCompleteIrp(PciDriver, Irp, Status);
- }
- break;
- case IrpMinorIdle:
- if (PciDevice->Type == PciDeviceFunction) {
- IoCompleteIrp(PciDriver, Irp, STATUS_SUCCESS);
- }
- break;
- case IrpMinorSuspend:
- if (PciDevice->Type == PciDeviceFunction) {
- IoCompleteIrp(PciDriver, Irp, STATUS_SUCCESS);
- }
- break;
- case IrpMinorResume:
- if (PciDevice->Type == PciDeviceFunction) {
- IoCompleteIrp(PciDriver, Irp, STATUS_SUCCESS);
- }
- break;
- //
- // If the IRP is unknown, don't touch it.
- //
- default:
- break;
- }
- } else {
- ASSERT(Irp->Direction == IrpUp);
- }
- return;
- }
- VOID
- PciDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles System Control IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- ASSERT(Irp->MajorCode == IrpMajorSystemControl);
- if (Irp->Direction == IrpDown) {
- IoCompleteIrp(PciDriver, Irp, STATUS_NOT_SUPPORTED);
- } else {
- ASSERT(Irp->Direction == IrpUp);
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- PcipReportChildren (
- PIRP QueryChildrenIrp,
- PPCI_DEVICE PciDevice
- )
- /*++
- Routine Description:
- This routine responds to a Query Children IRP.
- Arguments:
- QueryChildrenIrp - Supplies a pointer to the I/O request packet.
- PciDevice - Supplies a pointer to the PCI device context this IRP relates
- to.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INSUFFICIENT_RESOURCES if the array could not be allocated for the
- children.
- --*/
- {
- PDEVICE *Children;
- //
- // If the device is not a bus, it has no children.
- //
- if ((PciDevice->Type != PciDeviceBus) &&
- (PciDevice->Type != PciDeviceBridge)) {
- QueryChildrenIrp->U.QueryChildren.Children = NULL;
- QueryChildrenIrp->U.QueryChildren.ChildCount = 0;
- return STATUS_SUCCESS;
- }
- //
- // Scan the bus and pick up any changes.
- //
- PcipEnumerateChildren(QueryChildrenIrp->Device, PciDevice);
- if (PciDevice->ChildCount == 0) {
- QueryChildrenIrp->U.QueryChildren.Children = NULL;
- QueryChildrenIrp->U.QueryChildren.ChildCount = 0;
- return STATUS_SUCCESS;
- }
- //
- // Allocated paged pool for the array to return.
- //
- Children = MmAllocatePagedPool(sizeof(PDEVICE) * PciDevice->ChildCount,
- PCI_ALLOCATION_TAG);
- if (Children == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlCopyMemory(Children,
- PciDevice->Children,
- PciDevice->ChildCount * sizeof(PDEVICE));
- QueryChildrenIrp->U.QueryChildren.Children = Children;
- QueryChildrenIrp->U.QueryChildren.ChildCount = PciDevice->ChildCount;
- return STATUS_SUCCESS;
- }
- VOID
- PcipEnumerateChildren (
- PDEVICE Device,
- PPCI_DEVICE PciDevice
- )
- /*++
- Routine Description:
- This routine scans the given PCI bus, enumerating any new children and
- removing any missing ones.
- Arguments:
- Device - Supplies a pointer to the device.
- PciDevice - Supplies a pointer to the PCI device context relating to this
- device.
- Return Value:
- None.
- --*/
- {
- PPCI_CHILD Child;
- ULONG ChildIndex;
- ULONG ClassCode;
- PSTR ClassCodeString;
- ULONG DeviceId;
- UCHAR DeviceNumber;
- UCHAR Function;
- ULONG HeaderType;
- ULONG Id;
- UCHAR MaxFunction;
- CHAR NewDeviceId[PCI_DEVICE_ID_SIZE];
- PPCI_DEVICE NewPciDevice;
- KSTATUS Status;
- ULONG VendorId;
- //
- // If the device is not a bus, it has no children.
- //
- if ((PciDevice->Type != PciDeviceBus) &&
- (PciDevice->Type != PciDeviceBridge)) {
- return;
- }
- //
- // Scan through all functions and all devices on this bus.
- //
- for (DeviceNumber = 0; DeviceNumber < MAX_PCI_DEVICE; DeviceNumber += 1) {
- //
- // Read configuration space to get the vendor and device ID.
- //
- Id = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- DeviceNumber,
- 0,
- PCI_ID_OFFSET,
- sizeof(ULONG));
- DeviceId = (Id & PCI_DEVICE_ID_MASK) >> PCI_DEVICE_ID_SHIFT;
- VendorId = Id & PCI_VENDOR_ID_MASK;
- if ((VendorId == 0) || (VendorId == PCI_INVALID_VENDOR_ID)) {
- continue;
- }
- //
- // Determine the total number of functions that need to be scanned for
- // this device by looking at the header type's multi-function flag.
- //
- HeaderType = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- DeviceNumber,
- 0,
- PCI_HEADER_TYPE_OFFSET,
- sizeof(ULONG));
- HeaderType = (HeaderType & PCI_HEADER_TYPE_MASK) >>
- PCI_HEADER_TYPE_SHIFT;
- if ((HeaderType & PCI_HEADER_TYPE_FLAG_MULTIPLE_FUNCTIONS) != 0) {
- MaxFunction = MAX_PCI_FUNCTION;
- } else {
- MaxFunction = 0;
- }
- for (Function = 0; Function <= MaxFunction; Function += 1) {
- //
- // Read configuration space to get the vendor and device ID if it
- // has not already been read.
- //
- if (Function != 0) {
- Id = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- DeviceNumber,
- Function,
- PCI_ID_OFFSET,
- sizeof(ULONG));
- DeviceId = (Id & PCI_DEVICE_ID_MASK) >> PCI_DEVICE_ID_SHIFT;
- VendorId = Id & PCI_VENDOR_ID_MASK;
- }
- //
- // Attempt to find a previously enumerated child for this device
- // and function.
- //
- ChildIndex = PcipFindDevice(PciDevice, DeviceNumber, Function);
- //
- // If there was a device here and it seems to have disappeared,
- // free the device and swap it out for the last one.
- //
- if (ChildIndex != MAX_ULONG) {
- Child = PciDevice->ChildrenData[ChildIndex];
- if ((VendorId == Child->VendorId) &&
- (DeviceId == Child->DeviceId)) {
- continue;
- }
- //
- // Devices shouldn't just come and go like this. If they really
- // do, then completely remove the old device and add a new
- // different one in its place, rather than this bizarre
- // switcharoo.
- //
- ASSERT(FALSE);
- ASSERT(PciDevice->ChildCount != 0);
- PciDevice->Children[ChildIndex] =
- PciDevice->Children[PciDevice->ChildCount - 1];
- MmFreePagedPool(PciDevice->ChildrenData[ChildIndex]);
- PciDevice->ChildrenData[ChildIndex] =
- PciDevice->ChildrenData[PciDevice->ChildCount - 1];
- PciDevice->Children[PciDevice->ChildCount - 1] = NULL;
- PciDevice->ChildrenData[PciDevice->ChildCount - 1] = NULL;
- PciDevice->ChildCount -= 1;
- //
- // There was no child there before.
- //
- } else {
- //
- // If the vendor ID is invalid, skip this function.
- //
- if ((VendorId == 0) || (VendorId == PCI_INVALID_VENDOR_ID)) {
- continue;
- }
- //
- // There's a child now where there didn't used to be, kick out
- // a new device. Start by getting an index where the child will
- // go in the array. This also allocates the new child structure.
- //
- ChildIndex = PcipGetNewChildIndex(PciDevice);
- if (ChildIndex == MAX_ULONG) {
- continue;
- }
- //
- // Create the new device ID string. This only needs to be
- // temporary, which is why the buffer is stack allocated.
- //
- RtlPrintToString(NewDeviceId,
- PCI_DEVICE_ID_SIZE,
- CharacterEncodingDefault,
- PCI_DEVICE_ID_FORMAT,
- VendorId,
- DeviceId);
- //
- // Read the class code and create a string from it.
- //
- ClassCode = (ULONG)PciDevice->ReadConfig(PciDevice->BusNumber,
- DeviceNumber,
- Function,
- PCI_CLASS_CODE_OFFSET,
- sizeof(ULONG));
- ClassCode &= PCI_CLASS_CODE_MASK;
- ClassCodeString = PcipGetClassId(ClassCode);
- //
- // Create the driver context for the new child.
- //
- NewPciDevice = MmAllocateNonPagedPool(sizeof(PCI_DEVICE),
- PCI_ALLOCATION_TAG);
- if (NewPciDevice == NULL) {
- continue;
- }
- RtlZeroMemory(NewPciDevice, sizeof(PCI_DEVICE));
- NewPciDevice->Type = PciDeviceFunction;
- NewPciDevice->BusNumber = PciDevice->BusNumber;
- NewPciDevice->DeviceNumber = DeviceNumber;
- NewPciDevice->FunctionNumber = Function;
- NewPciDevice->ClassCode = ClassCode;
- if ((ClassCode == PCI_SUBTRACTIVE_BRIDGE_CLASS_CODE) ||
- (ClassCode == PCI_BRIDGE_CLASS_CODE)) {
- NewPciDevice->DeviceIsBridge = TRUE;
- }
- NewPciDevice->ReadConfig = PciDevice->ReadConfig;
- NewPciDevice->WriteConfig = PciDevice->WriteConfig;
- Status = PcipGetBusDriverDevice(Device,
- &(NewPciDevice->Parent));
- if (!KSUCCESS(Status)) {
- ASSERT(FALSE);
- MmFreeNonPagedPool(NewPciDevice);
- }
- //
- // Create the child device and fill out the accounting
- // structures.
- //
- Status = IoCreateDevice(PciDriver,
- NewPciDevice,
- Device,
- NewDeviceId,
- ClassCodeString,
- NULL,
- &(PciDevice->Children[ChildIndex]));
- if (!KSUCCESS(Status)) {
- MmFreeNonPagedPool(NewPciDevice);
- continue;
- }
- Child = PciDevice->ChildrenData[ChildIndex];
- Child->DeviceNumber = DeviceNumber;
- Child->Function = Function;
- Child->VendorId = VendorId;
- Child->DeviceId = DeviceId;
- PciDevice->ChildCount += 1;
- PcipCreateFunctionInterfaces(PciDevice->Children[ChildIndex],
- NewPciDevice);
- }
- }
- }
- return;
- }
- KSTATUS
- PcipQueryResourceRequirements (
- PDEVICE Device,
- PPCI_DEVICE DeviceObject,
- PIRP Irp
- )
- /*++
- Routine Description:
- This routine determines the resource requirements of the given device.
- Arguments:
- Device - Supplies a pointer to the device to query.
- DeviceObject - Supplies a pointer to the PCI information associated with
- the system device.
- Irp - Supplies a pointer to the query resources IRP.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG AddressDecode;
- RESOURCE_ALLOCATION Allocation;
- ULONG BarIndex;
- ULONGLONG BarLength[PCI_BAR_COUNT];
- ULONG BitNumber;
- PRESOURCE_ALLOCATION_LIST BootAllocations;
- UCHAR Bus;
- PRESOURCE_CONFIGURATION_LIST ConfigurationList;
- USHORT ControlRegister;
- UCHAR DeviceNumber;
- UCHAR Function;
- ULONG InterruptPin;
- ULONGLONG Maximum;
- UCHAR Offset;
- PPCI_READ_CONFIG ReadConfig;
- RESOURCE_REQUIREMENT Requirement;
- PRESOURCE_REQUIREMENT_LIST RequirementList;
- KSTATUS Status;
- ULONG Value;
- PPCI_WRITE_CONFIG WriteConfig;
- ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
- (Irp->MinorCode == IrpMinorQueryResources));
- //
- // Bridges are not handled in this function.
- //
- ASSERT((DeviceObject->Type == PciDeviceFunction) &&
- (DeviceObject->DeviceIsBridge == FALSE));
- BootAllocations = NULL;
- Bus = DeviceObject->BusNumber;
- ConfigurationList = NULL;
- DeviceNumber = DeviceObject->DeviceNumber;
- Function = DeviceObject->FunctionNumber;
- ReadConfig = DeviceObject->ReadConfig;
- RequirementList = NULL;
- WriteConfig = DeviceObject->WriteConfig;
- //
- // If the BARs have not been read yet from boot, see if the BIOS has
- // this device enabled, and read the BARs if so.
- //
- if (DeviceObject->BarsRead == FALSE) {
- DeviceObject->BarsRead = TRUE;
- //
- // If decoding is enabled, read the BARs.
- //
- ControlRegister = (USHORT)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT));
- DeviceObject->BootControlRegister = ControlRegister;
- if (((ControlRegister & PCI_CONTROL_IO_DECODE_ENABLED) != 0) ||
- ((ControlRegister & PCI_CONTROL_MEMORY_DECODE_ENABLED) != 0)) {
- for (BarIndex = 0; BarIndex < PCI_BAR_COUNT; BarIndex += 1) {
- Offset = PCI_BAR_OFFSET + (BarIndex * sizeof(ULONG));
- Value = (ULONG)ReadConfig(Bus,
- DeviceNumber,
- Function,
- Offset,
- sizeof(ULONG));
- DeviceObject->BootConfiguration.U.Bar32[BarIndex] = Value;
- }
- }
- InterruptPin = (USHORT)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_INTERRUPT_LINE_OFFSET,
- sizeof(USHORT));
- InterruptPin = (UCHAR)(InterruptPin >> BITS_PER_BYTE);
- DeviceObject->InterruptPin = InterruptPin;
- if (DeviceObject->InterruptPin > 4) {
- ASSERT(FALSE);
- DeviceObject->InterruptPin = 0;
- }
- //
- // Disable all decoding in preparation for the BAR test.
- //
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT),
- 0);
- //
- // The technique to determine how many resources a device needs is to
- // write all ones to each BAR, and then read them back to see which ones
- // stick, and therefore which addresses the device decodes. Write all
- // ones here.
- //
- for (BarIndex = 0; BarIndex < PCI_BAR_COUNT; BarIndex += 1) {
- Offset = PCI_BAR_OFFSET + (BarIndex * sizeof(ULONG));
- WriteConfig(Bus, DeviceNumber, Function, Offset, sizeof(ULONG), -1);
- }
- //
- // Now read them back.
- //
- for (BarIndex = 0; BarIndex < PCI_BAR_COUNT; BarIndex += 1) {
- Offset = PCI_BAR_OFFSET + (BarIndex * sizeof(ULONG));
- Value = (ULONG)ReadConfig(Bus,
- DeviceNumber,
- Function,
- Offset,
- sizeof(ULONG));
- if (Value != 0) {
- DeviceObject->BarCount = BarIndex + 1;
- }
- DeviceObject->AddressDecodeBits.U.Bar32[BarIndex] = Value;
- }
- //
- // For the safest feeling possible, restore the BARs and control
- // register to what it was before.
- //
- for (BarIndex = 0; BarIndex < PCI_BAR_COUNT; BarIndex += 1) {
- Offset = PCI_BAR_OFFSET + (BarIndex * sizeof(ULONG));
- Value = DeviceObject->BootConfiguration.U.Bar32[BarIndex];
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- Offset,
- sizeof(ULONG),
- Value);
- }
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT),
- ControlRegister);
- }
- RtlZeroMemory(&Requirement, sizeof(RESOURCE_REQUIREMENT));
- //
- // Create a new resource requirement list.
- //
- RequirementList = IoCreateResourceRequirementList();
- if (RequirementList == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto QueryResourceRequirementsEnd;
- }
- RtlZeroMemory(BarLength, sizeof(BarLength));
- //
- // Loop through the BARs to determine the resource requirements.
- //
- for (BarIndex = 0; BarIndex < DeviceObject->BarCount; BarIndex += 1) {
- Value = DeviceObject->AddressDecodeBits.U.Bar32[BarIndex];
- //
- // Create an I/O or memory space requirement.
- //
- if ((Value & PCI_BAR_IO_SPACE) != 0) {
- Requirement.Type = ResourceTypeIoPort;
- Requirement.Flags |= RESOURCE_FLAG_NOT_SHAREABLE;
- //
- // The value has 1 bit set for everything it decodes. Start from the
- // high order bits and find the maximum that it does decode.
- //
- if ((Value & (~PCI_BAR_IO_FLAGS_MASK)) == 0) {
- Maximum = 0;
- AddressDecode = 0;
- } else {
- BitNumber = 31;
- Maximum = 1 << BitNumber;
- while ((Maximum & Value) == 0) {
- BitNumber -= 1;
- Maximum = 1 << BitNumber;
- }
- //
- // Back up a smidge, the loop went one too far.
- //
- BitNumber += 1;
- Maximum = 1ULL << BitNumber;
- //
- // To get the needed size, OR in the empty bits on the right
- // (so the whole thing eventually rolls over), then mask off
- // the flags bits so they would be zero. Negate the whole
- // thing, and add 1 to roll over to a power of 2 that
- // represents the required size.
- //
- AddressDecode =
- (~((Value | ~(Maximum - 1)) & ~PCI_BAR_IO_FLAGS_MASK)) + 1;
- }
- Requirement.Minimum = 0;
- Requirement.Maximum = Maximum;
- Requirement.Length = AddressDecode;
- Requirement.Alignment = AddressDecode;
- Requirement.Characteristics = 0;
- if ((Value & PCI_BAR_MEMORY_PREFETCHABLE) != 0) {
- Requirement.Characteristics |=
- MEMORY_CHARACTERISTIC_PREFETCHABLE;
- }
- BarLength[BarIndex] = AddressDecode;
- //
- // Create a memory space requirement.
- //
- } else {
- Requirement.Type = ResourceTypePhysicalAddressSpace;
- Requirement.Flags |= RESOURCE_FLAG_NOT_SHAREABLE;
- AddressDecode = Value & (~PCI_BAR_MEMORY_FLAGS_MASK);
- Requirement.Minimum = 0;
- //
- // Set the minimum and maximum based on the BAR limits.
- //
- switch (Value & PCI_BAR_MEMORY_SIZE_MASK) {
- case PCI_BAR_MEMORY_32_BIT:
- BitNumber = 31;
- break;
- case PCI_BAR_MEMORY_1MB:
- BitNumber = 20;
- break;
- case PCI_BAR_MEMORY_64_BIT:
- ASSERT((BarIndex & 0x1) == 0);
- AddressDecode =
- DeviceObject->AddressDecodeBits.U.Bar64[BarIndex / 2] &
- (~PCI_BAR_MEMORY_FLAGS_MASK);
- BitNumber = 63;
- break;
- default:
- ASSERT(FALSE);
- BitNumber = 0;
- break;
- }
- //
- // Just like the I/O bars above, find the unset bits on the left
- // to get the maximum address.
- //
- if ((AddressDecode & (~PCI_BAR_MEMORY_FLAGS_MASK)) == 0) {
- Maximum = 0;
- AddressDecode = 0;
- } else {
- Maximum = 1ULL << BitNumber;
- while ((Maximum & AddressDecode) == 0) {
- BitNumber -= 1;
- Maximum = 1ULL << BitNumber;
- }
- //
- // Back up a smidge, the loop went too far.
- //
- BitNumber += 1;
- Maximum = 1ULL << BitNumber;
- //
- // Get the size needed for this BAR. Again this is done by
- // ORing in the unsupported bits on the left masking out the
- // flags, negating the whole thing, and adding one. Remember
- // that the flags were masked out already above.
- //
- if (BitNumber == 64) {
- AddressDecode = ~AddressDecode + 1;
- Maximum = MAX_ULONGLONG;
- } else {
- AddressDecode = (~(AddressDecode | ~(Maximum - 1))) + 1;
- }
- }
- Requirement.Length = AddressDecode;
- Requirement.Alignment = AddressDecode;
- Requirement.Maximum = Maximum;
- Requirement.Characteristics = 0;
- BarLength[BarIndex] = AddressDecode;
- //
- // 64 bit BARs take up two of the regular size BARs, so advance
- // past the second one.
- //
- if ((Value & PCI_BAR_MEMORY_SIZE_MASK) == PCI_BAR_MEMORY_64_BIT) {
- BarIndex += 1;
- }
- }
- //
- // Create and add the requirement to the list.
- //
- Status = IoCreateAndAddResourceRequirement(&Requirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto QueryResourceRequirementsEnd;
- }
- }
- //
- // If the interrupt pin is not zero, then request an interrupt line
- // resource as well. By default PCI interrupts are level triggered active
- // low, and shareable.
- //
- InterruptPin = DeviceObject->InterruptPin;
- if (InterruptPin != 0) {
- Requirement.Type = ResourceTypeInterruptLine;
- Requirement.Flags &= ~RESOURCE_FLAG_NOT_SHAREABLE;
- Requirement.Length = 1;
- Requirement.Characteristics = INTERRUPT_LINE_ACTIVE_LOW;
- Requirement.Flags = 0;
- Requirement.Alignment = 1;
- Requirement.Minimum = InterruptPin;
- Requirement.Maximum = InterruptPin + 1;
- Status = IoCreateAndAddResourceRequirement(&Requirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto QueryResourceRequirementsEnd;
- }
- }
- //
- // Create the resource configuration list.
- //
- ConfigurationList = IoCreateResourceConfigurationList(RequirementList);
- if (ConfigurationList == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto QueryResourceRequirementsEnd;
- }
- RequirementList = NULL;
- //
- // Create the boot configuration.
- //
- BootAllocations = IoCreateResourceAllocationList();
- if (BootAllocations == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto QueryResourceRequirementsEnd;
- }
- RtlZeroMemory(&Allocation, sizeof(RESOURCE_ALLOCATION));
- for (BarIndex = 0; BarIndex < DeviceObject->BarCount; BarIndex += 1) {
- Value = DeviceObject->BootConfiguration.U.Bar32[BarIndex];
- //
- // Create an I/O or memory space allocation.
- //
- if ((Value & PCI_BAR_IO_SPACE) != 0) {
- Allocation.Type = ResourceTypeIoPort;
- Allocation.Allocation = Value & (~PCI_BAR_IO_FLAGS_MASK);
- Allocation.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- Allocation.Length = 0;
- if ((DeviceObject->BootControlRegister &
- PCI_CONTROL_IO_DECODE_ENABLED) != 0) {
- Allocation.Length = BarLength[BarIndex];
- }
- //
- // Create a memory space allocation.
- //
- } else {
- Allocation.Type = ResourceTypePhysicalAddressSpace;
- Allocation.Allocation = Value & (~PCI_BAR_MEMORY_FLAGS_MASK);
- Allocation.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- Allocation.Length = 0;
- if ((DeviceObject->BootControlRegister &
- PCI_CONTROL_MEMORY_DECODE_ENABLED) != 0) {
- Allocation.Length = BarLength[BarIndex];
- if ((Value & PCI_BAR_MEMORY_SIZE_MASK) ==
- PCI_BAR_MEMORY_64_BIT) {
- ASSERT((BarIndex & 0x1) == 0);
- Allocation.Allocation =
- DeviceObject->BootConfiguration.U.Bar64[BarIndex / 2] &
- (~PCI_BAR_MEMORY_FLAGS_MASK);
- BarIndex += 1;
- }
- }
- }
- //
- // Create and add the allocation to the list.
- //
- Status = IoCreateAndAddResourceAllocation(&Allocation, BootAllocations);
- if (!KSUCCESS(Status)) {
- goto QueryResourceRequirementsEnd;
- }
- }
- //
- // Add the interrupt pin to the boot configuration.
- //
- if (InterruptPin != 0) {
- Allocation.Type = ResourceTypeInterruptLine;
- Allocation.Allocation = InterruptPin;
- Allocation.Length = 1;
- Allocation.Flags = 0;
- Allocation.Characteristics = INTERRUPT_LINE_ACTIVE_LOW;
- Status = IoCreateAndAddResourceAllocation(&Allocation, BootAllocations);
- if (!KSUCCESS(Status)) {
- goto QueryResourceRequirementsEnd;
- }
- }
- Status = STATUS_SUCCESS;
- QueryResourceRequirementsEnd:
- if (!KSUCCESS(Status)) {
- if (RequirementList != NULL) {
- IoDestroyResourceRequirementList(RequirementList);
- }
- if (ConfigurationList != NULL) {
- IoDestroyResourceConfigurationList(ConfigurationList);
- ConfigurationList = NULL;
- }
- if (BootAllocations != NULL) {
- IoDestroyResourceAllocationList(BootAllocations);
- BootAllocations = NULL;
- }
- }
- Irp->U.QueryResources.ResourceRequirements = ConfigurationList;
- Irp->U.QueryResources.BootAllocation = BootAllocations;
- return Status;
- }
- KSTATUS
- PcipQueryBridgeResourceRequirements (
- PDEVICE Device,
- PPCI_DEVICE DeviceObject,
- PIRP Irp
- )
- /*++
- Routine Description:
- This routine determines the resource requirements of the given PCI bridge.
- For the confused, this routine is called by PCI acting as the bus driver,
- not the function driver.
- Arguments:
- Device - Supplies a pointer to the device to query.
- DeviceObject - Supplies a pointer to the PCI information associated with
- the system device.
- Irp - Supplies a pointer to the query resources IRP.
- Return Value:
- Status code.
- --*/
- {
- RESOURCE_ALLOCATION Allocation;
- BOOL BarsRead;
- PRESOURCE_ALLOCATION_LIST BootAllocations;
- UCHAR Bus;
- PRESOURCE_CONFIGURATION_LIST ConfigurationList;
- UCHAR DeviceNumber;
- UCHAR Function;
- UCHAR InterruptPin;
- ULONG IoDecodeBase;
- ULONG IoDecodeLimit;
- BOOL IoDecodeUpperBaseValid;
- BOOL IoDecodeUpperLimitValid;
- ULONG MemoryDecodeBase;
- ULONG MemoryDecodeLimit;
- ULONGLONG PrefetchableMemoryDecodeBase;
- ULONGLONG PrefetchableMemoryDecodeLimit;
- BOOL PrefetchableMemoryUpperBaseValid;
- BOOL PrefetchableMemoryUpperLimitValid;
- PPCI_READ_CONFIG ReadConfig;
- RESOURCE_REQUIREMENT Requirement;
- PRESOURCE_REQUIREMENT_LIST RequirementList;
- UCHAR SecondaryBusNumber;
- KSTATUS Status;
- ULONG Value;
- ULONG ValueHigh;
- ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
- (Irp->MinorCode == IrpMinorQueryResources));
- //
- // Only bridges are handled in this function.
- //
- ASSERT((DeviceObject->Type == PciDeviceFunction) &&
- (DeviceObject->DeviceIsBridge != FALSE));
- BarsRead = FALSE;
- BootAllocations = NULL;
- Bus = DeviceObject->BusNumber;
- ConfigurationList = NULL;
- DeviceNumber = DeviceObject->DeviceNumber;
- Function = DeviceObject->FunctionNumber;
- IoDecodeBase = MAX_USHORT;
- IoDecodeLimit = 0;
- MemoryDecodeBase = MAX_ULONG;
- MemoryDecodeLimit = 0;
- PrefetchableMemoryDecodeBase = MAX_ULONGLONG;
- PrefetchableMemoryDecodeLimit = 0;
- ReadConfig = DeviceObject->ReadConfig;
- RequirementList = NULL;
- SecondaryBusNumber = 0xFF;
- //
- // If the BARs have not been read yet from boot, see if the BIOS has
- // this device enabled, and read the BARs if so.
- //
- if (DeviceObject->BarsRead == FALSE) {
- DeviceObject->BarsRead = TRUE;
- BarsRead = TRUE;
- //
- // Read the bus number BAR to see how the BIOS configured it.
- //
- Value = (ULONG)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_BUS_NUMBERS_OFFSET,
- sizeof(ULONG));
- SecondaryBusNumber = (UCHAR)(Value >> PCI_BRIDGE_SECONDARY_BUS_SHIFT);
- //
- // Read the value set by the BIOS for the I/O decode region.
- //
- IoDecodeUpperBaseValid = FALSE;
- IoDecodeUpperLimitValid = FALSE;
- Value = (USHORT)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_IO_BAR_OFFSET,
- sizeof(USHORT));
- if ((Value & PCI_BRIDGE_IO_BASE_DECODE_MASK) ==
- PCI_BRIDGE_IO_BASE_DECODE_32_BIT) {
- IoDecodeUpperBaseValid = TRUE;
- }
- if ((Value & PCI_BRIDGE_IO_LIMIT_DECODE_MASK) ==
- PCI_BRIDGE_IO_LIMIT_DECODE_32_BIT) {
- IoDecodeUpperLimitValid = TRUE;
- }
- IoDecodeBase = (Value & PCI_BRIDGE_IO_BASE_MASK) <<
- PCI_BRIDGE_IO_BASE_ADDRESS_SHIFT;
- IoDecodeLimit = Value & PCI_BRIDGE_IO_LIMIT_MASK;
- if ((IoDecodeUpperBaseValid != FALSE) ||
- (IoDecodeUpperLimitValid != FALSE)) {
- ValueHigh = (USHORT)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_IO_HIGH_BAR_OFFSET,
- sizeof(ULONG));
- if (IoDecodeUpperBaseValid != FALSE) {
- IoDecodeBase |= (ValueHigh &
- PCI_BRIDGE_IO_BASE_HIGH_MASK) <<
- PCI_BRIDGE_IO_BASE_HIGH_ADDRESS_SHIFT;
- }
- if (IoDecodeUpperLimitValid != FALSE) {
- IoDecodeLimit |= ValueHigh & PCI_BRIDGE_IO_LIMIT_HIGH_MASK;
- }
- }
- //
- // Read the value set by the BIOS for the memory decode region.
- //
- Value = (ULONG)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_MEMORY_BAR_OFFSET,
- sizeof(ULONG));
- MemoryDecodeBase = (Value & PCI_BRIDGE_MEMORY_BASE_MASK) <<
- PCI_BRIDGE_MEMORY_BASE_ADDRESS_SHIFT;
- MemoryDecodeLimit = Value & PCI_BRIDGE_MEMORY_LIMIT_MASK;
- //
- // Read the prefetchable memory range as well.
- //
- PrefetchableMemoryUpperBaseValid = FALSE;
- PrefetchableMemoryUpperLimitValid = FALSE;
- Value = (ULONG)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BAR_OFFSET,
- sizeof(ULONG));
- if ((Value & PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_DECODE_MASK) ==
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_DECODE_64_BIT) {
- PrefetchableMemoryUpperBaseValid = TRUE;
- }
- if ((Value & PCI_BRIDGE_PREFETCHABLE_MEMORY_LIMIT_DECODE_MASK) ==
- PCI_BRIDGE_PREFETCHABLE_MEMORY_LIMIT_DECODE_64_BIT) {
- PrefetchableMemoryUpperLimitValid = TRUE;
- }
- PrefetchableMemoryDecodeBase =
- (Value & PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_MASK) <<
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_ADDRESS_SHIFT;
- PrefetchableMemoryDecodeLimit =
- Value & PCI_BRIDGE_PREFETCHABLE_MEMORY_LIMIT_MASK;
- if (PrefetchableMemoryUpperBaseValid != FALSE) {
- ValueHigh = (ULONG)ReadConfig(
- Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_HIGH_OFFSET,
- sizeof(ULONG));
- PrefetchableMemoryDecodeBase |=
- (ULONGLONG)ValueHigh <<
- PCI_BRIDGE_PREFETCHABLE_MEMORY_HIGH_ADDRESS_SHIFT;
- }
- if (PrefetchableMemoryUpperLimitValid != FALSE) {
- ValueHigh = (ULONG)ReadConfig(
- Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_PREFETCHABLE_MEMORY_LIMIT_HIGH_OFFSET,
- sizeof(ULONG));
- PrefetchableMemoryDecodeLimit |=
- (ULONGLONG)ValueHigh <<
- PCI_BRIDGE_PREFETCHABLE_MEMORY_HIGH_ADDRESS_SHIFT;
- }
- InterruptPin = (USHORT)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_INTERRUPT_LINE_OFFSET,
- sizeof(USHORT));
- InterruptPin = (UCHAR)(InterruptPin >> BITS_PER_BYTE);
- DeviceObject->InterruptPin = InterruptPin;
- if (DeviceObject->InterruptPin > 4) {
- ASSERT(FALSE);
- DeviceObject->InterruptPin = 0;
- }
- }
- RtlZeroMemory(&Requirement, sizeof(RESOURCE_REQUIREMENT));
- //
- // Create a new resource requirement list and add the bus number
- // requirement.
- //
- RequirementList = IoCreateResourceRequirementList();
- if (RequirementList == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto QueryBridgeResourceRequirementsEnd;
- }
- Requirement.Type = ResourceTypeBusNumber;
- Requirement.Minimum = 0;
- Requirement.Maximum = (UCHAR)-1;
- Requirement.Length = 1;
- Requirement.Characteristics = 0;
- Requirement.Alignment = 0;
- Requirement.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- Status = IoCreateAndAddResourceRequirement(&Requirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto QueryBridgeResourceRequirementsEnd;
- }
- //
- // Add empty requirements for the windows.
- //
- Requirement.Type = ResourceTypeIoPort;
- Requirement.Minimum = 0;
- Requirement.Maximum = MAX_ULONG;
- Requirement.Length = 0;
- Requirement.Characteristics = 0;
- Requirement.Alignment = PCI_BRIDGE_IO_GRANULARITY;
- Status = IoCreateAndAddResourceRequirement(&Requirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto QueryBridgeResourceRequirementsEnd;
- }
- Requirement.Type = ResourceTypePhysicalAddressSpace;
- Requirement.Minimum = 0;
- Requirement.Maximum = MAX_ULONG;
- Requirement.Length = 0;
- Requirement.Characteristics = 0;
- Requirement.Alignment = PCI_BRIDGE_MEMORY_GRANULARITY;
- Status = IoCreateAndAddResourceRequirement(&Requirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto QueryBridgeResourceRequirementsEnd;
- }
- //
- // The prefetchable memory window is the same as the MMIO region, but is
- // 64-bit capable.
- //
- Requirement.Maximum = MAX_ULONGLONG;
- Requirement.Characteristics = MEMORY_CHARACTERISTIC_PREFETCHABLE;
- Status = IoCreateAndAddResourceRequirement(&Requirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto QueryBridgeResourceRequirementsEnd;
- }
- //
- // Create the resource configuration list.
- //
- ConfigurationList = IoCreateResourceConfigurationList(RequirementList);
- if (ConfigurationList == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto QueryBridgeResourceRequirementsEnd;
- }
- RequirementList = NULL;
- //
- // Create the boot configuration.
- //
- BootAllocations = IoCreateResourceAllocationList();
- if (BootAllocations == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto QueryBridgeResourceRequirementsEnd;
- }
- RtlZeroMemory(&Allocation, sizeof(RESOURCE_ALLOCATION));
- if (BarsRead != FALSE) {
- if (SecondaryBusNumber != 0xFF) {
- Allocation.Type = ResourceTypeBusNumber;
- Allocation.Allocation = SecondaryBusNumber;
- Allocation.Length = 1;
- Allocation.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- Status = IoCreateAndAddResourceAllocation(&Allocation,
- BootAllocations);
- if (!KSUCCESS(Status)) {
- goto QueryBridgeResourceRequirementsEnd;
- }
- Allocation.Type = ResourceTypeIoPort;
- Allocation.Allocation = IoDecodeBase;
- if (IoDecodeLimit >= IoDecodeBase) {
- Allocation.Length =
- (IoDecodeLimit + PCI_BRIDGE_IO_GRANULARITY) - IoDecodeBase;
- } else {
- Allocation.Length = 0;
- }
- Allocation.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- Status = IoCreateAndAddResourceAllocation(&Allocation,
- BootAllocations);
- if (!KSUCCESS(Status)) {
- goto QueryBridgeResourceRequirementsEnd;
- }
- Allocation.Type = ResourceTypePhysicalAddressSpace;
- Allocation.Allocation = MemoryDecodeBase;
- if (MemoryDecodeLimit >= MemoryDecodeBase) {
- Allocation.Length = (MemoryDecodeLimit +
- PCI_BRIDGE_MEMORY_GRANULARITY) -
- MemoryDecodeBase;
- } else {
- Allocation.Length = 0;
- }
- Allocation.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- Status = IoCreateAndAddResourceAllocation(&Allocation,
- BootAllocations);
- if (!KSUCCESS(Status)) {
- goto QueryBridgeResourceRequirementsEnd;
- }
- Allocation.Type = ResourceTypePhysicalAddressSpace;
- Allocation.Allocation = PrefetchableMemoryDecodeBase;
- if (PrefetchableMemoryDecodeLimit >= PrefetchableMemoryDecodeBase) {
- Allocation.Length = (PrefetchableMemoryDecodeLimit +
- PCI_BRIDGE_MEMORY_GRANULARITY) -
- PrefetchableMemoryDecodeBase;
- } else {
- Allocation.Length = 0;
- }
- Allocation.Characteristics = MEMORY_CHARACTERISTIC_PREFETCHABLE;
- Allocation.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- Status = IoCreateAndAddResourceAllocation(&Allocation,
- BootAllocations);
- if (!KSUCCESS(Status)) {
- goto QueryBridgeResourceRequirementsEnd;
- }
- }
- }
- Status = STATUS_SUCCESS;
- QueryBridgeResourceRequirementsEnd:
- if (!KSUCCESS(Status)) {
- if (RequirementList != NULL) {
- IoDestroyResourceRequirementList(RequirementList);
- }
- if (ConfigurationList != NULL) {
- IoDestroyResourceConfigurationList(ConfigurationList);
- ConfigurationList = NULL;
- }
- if (BootAllocations != NULL) {
- IoDestroyResourceAllocationList(BootAllocations);
- BootAllocations = NULL;
- }
- }
- Irp->U.QueryResources.ResourceRequirements = ConfigurationList;
- Irp->U.QueryResources.BootAllocation = BootAllocations;
- return Status;
- }
- KSTATUS
- PcipSetDeviceResources (
- PPCI_DEVICE DeviceContext,
- PRESOURCE_ALLOCATION_LIST AllocationList
- )
- /*++
- Routine Description:
- This routine sets the assigned resources in the PCI BARs.
- Arguments:
- DeviceContext - Supplies a pointer to the device to set.
- AllocationList - Supplies a pointer to the resource allocation list
- containing the device's resource assignment.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG AddressDecode;
- PRESOURCE_ALLOCATION Allocation;
- ULONG BarIndex;
- ULONG BarSize;
- UCHAR Bus;
- USHORT ControlRegister;
- UCHAR DeviceNumber;
- UCHAR Function;
- PPCI_MSI_CONTEXT MsiContext;
- UCHAR Offset;
- ULONG PendingArrayIndex;
- ULONG PendingArrayOffset;
- PPCI_READ_CONFIG ReadConfig;
- RESOURCE_TYPE ResourceType;
- KSTATUS Status;
- ULONGLONG Value;
- ULONG VectorTableIndex;
- ULONG VectorTableOffset;
- PPCI_WRITE_CONFIG WriteConfig;
- //
- // This routine only handles functions, not bridges.
- //
- ASSERT((DeviceContext->Type == PciDeviceFunction) &&
- (DeviceContext->DeviceIsBridge == FALSE));
- if (AllocationList == NULL) {
- Status = STATUS_SUCCESS;
- goto SetDeviceResourcesEnd;
- }
- Bus = DeviceContext->BusNumber;
- DeviceNumber = DeviceContext->DeviceNumber;
- Function = DeviceContext->FunctionNumber;
- ReadConfig = DeviceContext->ReadConfig;
- WriteConfig = DeviceContext->WriteConfig;
- //
- // If MSI-X is available on the device then prepare to squirrel away the
- // physical address of the table and pending array.
- //
- MsiContext = DeviceContext->MsiContext;
- if ((MsiContext != NULL) && (MsiContext->MsiXOffset != 0)) {
- PcipGetMsiXBarInformation(DeviceContext,
- &VectorTableIndex,
- &VectorTableOffset,
- &PendingArrayIndex,
- &PendingArrayOffset);
- }
- //
- // Read the control register.
- //
- ControlRegister = (USHORT)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT));
- //
- // Disable all decoding in preparation for setting the BARs.
- //
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT),
- 0);
- //
- // Loop through the BARs and assign resources to each one.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- for (BarIndex = 0; BarIndex < DeviceContext->BarCount; BarIndex += 1) {
- AddressDecode = DeviceContext->AddressDecodeBits.U.Bar32[BarIndex];
- //
- // Get the resource type for this BAR.
- //
- ResourceType = ResourceTypePhysicalAddressSpace;
- if ((AddressDecode & PCI_BAR_IO_SPACE) != 0) {
- ResourceType = ResourceTypeIoPort;
- }
- //
- // Find the next resource of that type.
- //
- while (Allocation->Type != ResourceType) {
- Allocation =
- IoGetNextResourceAllocation(AllocationList, Allocation);
- if (Allocation == NULL) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto SetDeviceResourcesEnd;
- }
- }
- //
- // Skip it if it's zero length.
- //
- if (AddressDecode == 0) {
- ASSERT(Allocation->Length == 0);
- Allocation = IoGetNextResourceAllocation(AllocationList,
- Allocation);
- continue;
- }
- //
- // See if this is a 64 bit bar.
- //
- BarSize = sizeof(ULONG);
- if ((ResourceType == ResourceTypePhysicalAddressSpace) &&
- ((AddressDecode & PCI_BAR_MEMORY_SIZE_MASK) ==
- PCI_BAR_MEMORY_64_BIT)) {
- BarSize = sizeof(ULONGLONG);
- }
- Value = Allocation->Allocation;
- if (ResourceType == ResourceTypePhysicalAddressSpace) {
- ASSERT((Value & PCI_BAR_MEMORY_FLAGS_MASK) == 0);
- ControlRegister |= PCI_CONTROL_MEMORY_DECODE_ENABLED;
- } else {
- ASSERT(ResourceType == ResourceTypeIoPort);
- ASSERT((Value & PCI_BAR_IO_FLAGS_MASK) == 0);
- ControlRegister |= PCI_CONTROL_IO_DECODE_ENABLED;
- Value |= PCI_BAR_IO_SPACE;
- }
- //
- // Write out the BAR.
- //
- Offset = PCI_BAR_OFFSET + (BarIndex * sizeof(ULONG));
- WriteConfig(Bus, DeviceNumber, Function, Offset, BarSize, Value);
- //
- // If MSI-X is available then check to see if this is the BAR for
- // either the vector table or pending bit array. They could be in the
- // same BAR.
- //
- if ((MsiContext != NULL) && (MsiContext->MsiXOffset != 0)) {
- if (VectorTableIndex == BarIndex) {
- ASSERT(MsiContext->MsiXTablePhysicalAddress ==
- INVALID_PHYSICAL_ADDRESS);
- MsiContext->MsiXTablePhysicalAddress = Value +
- VectorTableOffset;
- }
- if (PendingArrayIndex == BarIndex) {
- ASSERT(MsiContext->MsiXPendingArrayPhysicalAddress ==
- INVALID_PHYSICAL_ADDRESS);
- MsiContext->MsiXPendingArrayPhysicalAddress =
- Value + PendingArrayOffset;
- }
- }
- //
- // Skip over the next BAR if this one was a 64-bit BAR.
- //
- if ((ResourceType == ResourceTypePhysicalAddressSpace) &&
- ((AddressDecode & PCI_BAR_MEMORY_SIZE_MASK) ==
- PCI_BAR_MEMORY_64_BIT)) {
- BarIndex += 1;
- }
- //
- // Move on to the next allocation.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- //
- // Write out the control register to enable the device.
- //
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT),
- ControlRegister);
- Status = STATUS_SUCCESS;
- SetDeviceResourcesEnd:
- return Status;
- }
- VOID
- PcipEnableDevice (
- PPCI_DEVICE DeviceContext
- )
- /*++
- Routine Description:
- This routine enables the I/O space, memory space, and Bus master bits in
- the PCI device.
- Arguments:
- DeviceContext - Supplies a pointer to the device to set.
- Return Value:
- None.
- --*/
- {
- UCHAR Bus;
- USHORT CommandRegister;
- UCHAR DeviceNumber;
- UCHAR Function;
- PPCI_READ_CONFIG ReadConfig;
- PPCI_WRITE_CONFIG WriteConfig;
- //
- // This routine only handles functions, not bridges.
- //
- ASSERT((DeviceContext->Type == PciDeviceFunction) &&
- (DeviceContext->DeviceIsBridge == FALSE));
- Bus = DeviceContext->BusNumber;
- DeviceNumber = DeviceContext->DeviceNumber;
- Function = DeviceContext->FunctionNumber;
- ReadConfig = DeviceContext->ReadConfig;
- WriteConfig = DeviceContext->WriteConfig;
- //
- // Read the command register, and enable some bits.
- //
- CommandRegister = (USHORT)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT));
- CommandRegister |= PCI_CONTROL_IO_DECODE_ENABLED |
- PCI_CONTROL_MEMORY_DECODE_ENABLED |
- PCI_CONTROL_WRITE_INVALIDATE_ENABLED |
- PCI_CONTROL_BUS_MASTER_ENABLED;
- //
- // Disable all decoding in preparation for setting the BARs.
- //
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT),
- CommandRegister);
- return;
- }
- KSTATUS
- PcipSetBridgeDeviceResources (
- PPCI_DEVICE DeviceContext,
- PRESOURCE_ALLOCATION_LIST AllocationList
- )
- /*++
- Routine Description:
- This routine sets the assigned resource window into the given bridge.
- Arguments:
- DeviceContext - Supplies a pointer to the device to set.
- AllocationList - Supplies a pointer to the resource allocation list
- containing the device's resource assignment.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- UCHAR Bus;
- ULONG BusRegister;
- USHORT ControlRegister;
- UCHAR DeviceNumber;
- UCHAR Function;
- ULONG IoPortHigh;
- USHORT IoPortRegister;
- ULONGLONG Limit;
- ULONG MemoryRegister;
- UCHAR OriginalSecondaryBusNumber;
- ULONG PrefetchableMemoryBaseHigh;
- ULONG PrefetchableMemoryLimitHigh;
- ULONG PrefetchableMemoryLow;
- UCHAR PrimaryBusNumber;
- PPCI_READ_CONFIG ReadConfig;
- UCHAR SecondaryBusNumber;
- KSTATUS Status;
- UCHAR SubordinateBusNumber;
- PPCI_WRITE_CONFIG WriteConfig;
- //
- // This routine only handles bridges.
- //
- ASSERT((DeviceContext->Type == PciDeviceFunction) &&
- (DeviceContext->DeviceIsBridge != FALSE));
- if (AllocationList == NULL) {
- Status = STATUS_SUCCESS;
- goto SetBridgeDeviceResourcesEnd;
- }
- //
- // Initialize the locals. Set the window registers up so that the base is
- // higher than the limit, a safe default if no resources were given for that
- // window.
- //
- Bus = DeviceContext->BusNumber;
- DeviceNumber = DeviceContext->DeviceNumber;
- Function = DeviceContext->FunctionNumber;
- IoPortRegister = ((MAX_USHORT >> PCI_BRIDGE_IO_BASE_ADDRESS_SHIFT) &
- PCI_BRIDGE_IO_BASE_MASK) |
- (0 & PCI_BRIDGE_IO_LIMIT_MASK);
- IoPortHigh = 0;
- MemoryRegister = ((MAX_ULONG >> PCI_BRIDGE_MEMORY_BASE_ADDRESS_SHIFT) &
- PCI_BRIDGE_MEMORY_BASE_MASK) |
- (0 & PCI_BRIDGE_MEMORY_LIMIT_MASK);
- PrimaryBusNumber = Bus;
- PrefetchableMemoryLow =
- ((MAX_ULONG >> PCI_BRIDGE_MEMORY_BASE_ADDRESS_SHIFT) &
- PCI_BRIDGE_MEMORY_BASE_MASK) |
- (0 & PCI_BRIDGE_MEMORY_LIMIT_MASK);
- PrefetchableMemoryBaseHigh = MAX_ULONG;
- PrefetchableMemoryLimitHigh = 0;
- SecondaryBusNumber = Bus;
- ReadConfig = DeviceContext->ReadConfig;
- WriteConfig = DeviceContext->WriteConfig;
- BusRegister = (ULONG)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_BUS_NUMBERS_OFFSET,
- sizeof(ULONG));
- //
- // Save the secondary and subordinate bus numbers that were programmed by
- // the firmware. The final secondary bus number will be retrieved from the
- // allocated resources; they should match. The subordinate bus number is
- // the highest bus number underneath this bridge and all bus numbers
- // beneath a given bridge must be contiguous. A depth-first search would
- // need to be performed before the system enumerates the bridges in order
- // to correctly calculate the subordinate bus numbers. For now, rely on the
- // firmware to have done the work.
- //
- OriginalSecondaryBusNumber = (BusRegister &
- PCI_BRIDGE_SECONDARY_BUS_MASK) >>
- PCI_BRIDGE_SECONDARY_BUS_SHIFT;
- SubordinateBusNumber = (BusRegister & PCI_BRIDGE_SUBORDINATE_BUS_MASK) >>
- PCI_BRIDGE_SUBORDINATE_BUS_SHIFT;
- //
- // Read the control register.
- //
- ControlRegister = (USHORT)ReadConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT));
- ControlRegister |= PCI_CONTROL_BUS_MASTER_ENABLED |
- PCI_CONTROL_SPECIAL_CYCLES_ENABLED |
- PCI_CONTROL_WRITE_INVALIDATE_ENABLED |
- PCI_CONTROL_SERR_ENABLED;
- //
- // Disable all decoding in preparation for setting the BARs.
- //
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT),
- 0);
- //
- // Loop over all the given resources, and extract the necessary items.
- // Don't program anything in until everything's retrieved.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- while (Allocation != NULL) {
- //
- // Skip zero length allocations.
- //
- if (Allocation->Length == 0) {
- Allocation = IoGetNextResourceAllocation(AllocationList,
- Allocation);
- continue;
- }
- //
- // Save the bus number.
- //
- if (Allocation->Type == ResourceTypeBusNumber) {
- ASSERT((UCHAR)Allocation->Allocation == Allocation->Allocation);
- ASSERT(Allocation->Length == 1);
- BusRegister &= PCI_BRIDGE_SECONDARY_LATENCY_TIMER_MASK;
- SecondaryBusNumber = (UCHAR)Allocation->Allocation;
- //
- // Save the I/O port window.
- //
- } else if (Allocation->Type == ResourceTypeIoPort) {
- ControlRegister |= PCI_CONTROL_IO_DECODE_ENABLED;
- Limit = Allocation->Allocation + Allocation->Length -
- PCI_BRIDGE_IO_GRANULARITY;
- IoPortRegister = (USHORT)(((Allocation->Allocation >>
- PCI_BRIDGE_IO_BASE_ADDRESS_SHIFT) &
- PCI_BRIDGE_IO_BASE_MASK) |
- (Limit & PCI_BRIDGE_IO_LIMIT_MASK));
- IoPortHigh = (ULONG)((Allocation->Allocation >>
- PCI_BRIDGE_IO_BASE_HIGH_ADDRESS_SHIFT) &
- PCI_BRIDGE_IO_BASE_HIGH_MASK);
- if (IoPortHigh != 0) {
- IoPortRegister |= PCI_BRIDGE_IO_BASE_DECODE_32_BIT;
- }
- if ((ULONG)(Limit & PCI_BRIDGE_IO_LIMIT_HIGH_MASK) != 0) {
- IoPortRegister |= PCI_BRIDGE_IO_LIMIT_DECODE_32_BIT;
- }
- IoPortHigh |= (ULONG)(Limit & PCI_BRIDGE_IO_LIMIT_HIGH_MASK);
- //
- // Save the non-prefetchable (MMIO) memory window.
- //
- } else if ((Allocation->Type == ResourceTypePhysicalAddressSpace) &&
- ((Allocation->Characteristics &
- MEMORY_CHARACTERISTIC_PREFETCHABLE) == 0)) {
- ControlRegister |= PCI_CONTROL_MEMORY_DECODE_ENABLED;
- Limit = Allocation->Allocation + Allocation->Length -
- PCI_BRIDGE_MEMORY_GRANULARITY;
- MemoryRegister = (ULONG)(((Allocation->Allocation >>
- PCI_BRIDGE_MEMORY_BASE_ADDRESS_SHIFT) &
- PCI_BRIDGE_MEMORY_BASE_MASK) |
- (Limit & PCI_BRIDGE_MEMORY_LIMIT_MASK));
- //
- // Save the prefetchable memory window.
- //
- } else if ((Allocation->Type == ResourceTypePhysicalAddressSpace) &&
- ((Allocation->Characteristics &
- MEMORY_CHARACTERISTIC_PREFETCHABLE) != 0)) {
- ControlRegister |= PCI_CONTROL_MEMORY_DECODE_ENABLED;
- Limit = Allocation->Allocation + Allocation->Length -
- PCI_BRIDGE_MEMORY_GRANULARITY;
- PrefetchableMemoryLow =
- (ULONG)(((Allocation->Allocation >>
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_ADDRESS_SHIFT) &
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_MASK) |
- (Limit & PCI_BRIDGE_PREFETCHABLE_MEMORY_LIMIT_MASK));
- PrefetchableMemoryBaseHigh =
- (ULONG)(Allocation->Allocation >>
- PCI_BRIDGE_PREFETCHABLE_MEMORY_HIGH_ADDRESS_SHIFT);
- if (PrefetchableMemoryBaseHigh != 0) {
- PrefetchableMemoryLow |=
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_DECODE_64_BIT;
- }
- PrefetchableMemoryLimitHigh =
- (ULONG)(Limit >>
- PCI_BRIDGE_PREFETCHABLE_MEMORY_HIGH_ADDRESS_SHIFT);
- if (PrefetchableMemoryLimitHigh != 0) {
- PrefetchableMemoryLow |=
- PCI_BRIDGE_PREFETCHABLE_MEMORY_LIMIT_DECODE_64_BIT;
- }
- }
- //
- // Loop on to the next allocation.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- //
- // The secondary bus number that was allocated for this bridge should be
- // equal to the number allocated by the firmware at boot. This dependency
- // is taken to avoid doing a depth-first search to determine the correct
- // subordinate bus number for each bridge.
- //
- ASSERT(SecondaryBusNumber == OriginalSecondaryBusNumber);
- //
- // Set up the bus number register value now that the information has been
- // extracted.
- //
- BusRegister |= PrimaryBusNumber |
- (SecondaryBusNumber << PCI_BRIDGE_SECONDARY_BUS_SHIFT) |
- (SubordinateBusNumber << PCI_BRIDGE_SUBORDINATE_BUS_SHIFT);
- //
- // Okay, everything's accounted for. Write the values into the bridge.
- //
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_BUS_NUMBERS_OFFSET,
- sizeof(ULONG),
- BusRegister);
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_IO_BAR_OFFSET,
- sizeof(USHORT),
- IoPortRegister);
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_IO_HIGH_BAR_OFFSET,
- sizeof(ULONG),
- IoPortHigh);
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_MEMORY_BAR_OFFSET,
- sizeof(ULONG),
- MemoryRegister);
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BAR_OFFSET,
- sizeof(ULONG),
- PrefetchableMemoryLow);
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_PREFETCHABLE_MEMORY_BASE_HIGH_OFFSET,
- sizeof(ULONG),
- PrefetchableMemoryBaseHigh);
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_BRIDGE_PREFETCHABLE_MEMORY_LIMIT_HIGH_OFFSET,
- sizeof(ULONG),
- PrefetchableMemoryLimitHigh);
- //
- // Write out the control register to enable address decoding.
- //
- WriteConfig(Bus,
- DeviceNumber,
- Function,
- PCI_CONTROL_OFFSET,
- sizeof(USHORT),
- ControlRegister);
- Status = STATUS_SUCCESS;
- SetBridgeDeviceResourcesEnd:
- return Status;
- }
- ULONG
- PcipFindDevice (
- PPCI_DEVICE ParentBus,
- UCHAR Device,
- UCHAR Function
- )
- /*++
- Routine Description:
- This routine searches for a PCI device matching the given device and
- function in the child list of another device.
- Arguments:
- ParentBus - Supplies a pointer to the PCI device whose children should be
- searched.
- Device - Supplies the PCI device slot number to search for.
- Function - Supplies the function number to search for.
- Return Value:
- Returns the index of the child in the device's child array, or MAX_ULONG
- if the device could not be found.
- --*/
- {
- ULONG ChildIndex;
- for (ChildIndex = 0; ChildIndex < ParentBus->ChildCount; ChildIndex += 1) {
- if ((ParentBus->ChildrenData[ChildIndex]->DeviceNumber == Device) &&
- (ParentBus->ChildrenData[ChildIndex]->Function == Function)) {
- return ChildIndex;
- }
- }
- return MAX_ULONG;
- }
- ULONG
- PcipGetNewChildIndex (
- PPCI_DEVICE ParentBus
- )
- /*++
- Routine Description:
- This routine allocates space in the list of child devices, and also
- allocates space for the child information.
- Arguments:
- ParentBus - Supplies a pointer to the parent bus device where a new device
- is about to be added.
- Return Value:
- Returns an index into the child array where the new child device should be
- placed, and where the child device information buffer is stored.
- MAX_ULONG on error.
- --*/
- {
- ULONG AllocationCount;
- ULONG AllocationSize;
- PDEVICE *NewChildren;
- PPCI_CHILD *NewChildrenData;
- ULONG NewIndex;
- NewChildren = NULL;
- NewChildrenData = NULL;
- NewIndex = MAX_ULONG;
- ASSERT(ParentBus->ChildCount < MAX_PCI_DEVICES);
- if (ParentBus->ChildCount >= MAX_PCI_DEVICES) {
- goto GetNewChildIndexEnd;
- }
- //
- // If there's room in the array, simply use that.
- //
- if (ParentBus->ChildCount < ParentBus->ChildSize) {
- NewIndex = ParentBus->ChildCount;
- //
- // There's no room in the array. Allocate a new array, copy the old
- // contents in, and free the old array.
- //
- } else {
- AllocationCount = ParentBus->ChildSize * 2;
- if (AllocationCount < PCI_INITIAL_CHILD_COUNT) {
- AllocationCount = PCI_INITIAL_CHILD_COUNT;
- }
- if (AllocationCount > MAX_PCI_DEVICES) {
- AllocationCount = MAX_PCI_DEVICES;
- }
- //
- // Allocate the new array.
- //
- AllocationSize = (sizeof(PDEVICE) + sizeof(PPCI_CHILD)) *
- AllocationCount;
- NewChildren = MmAllocatePagedPool(AllocationSize, PCI_ALLOCATION_TAG);
- if (NewChildren == NULL) {
- goto GetNewChildIndexEnd;
- }
- NewChildrenData = (PPCI_CHILD *)(NewChildren + AllocationCount);
- if (ParentBus->Children != NULL) {
- //
- // Copy the old contents over.
- //
- RtlCopyMemory(NewChildren,
- ParentBus->Children,
- sizeof(PDEVICE) * ParentBus->ChildCount);
- RtlCopyMemory(NewChildrenData,
- ParentBus->ChildrenData,
- sizeof(PPCI_DEVICE) * ParentBus->ChildCount);
- //
- // Free the old contents and update the pointers.
- //
- MmFreePagedPool(ParentBus->Children);
- }
- ParentBus->Children = NewChildren;
- ParentBus->ChildrenData = NewChildrenData;
- ParentBus->ChildSize = AllocationCount;
- NewIndex = ParentBus->ChildCount;
- NewChildren = NULL;
- }
- //
- // Allocate a new PCI child structure.
- //
- ParentBus->ChildrenData[NewIndex] =
- MmAllocatePagedPool(sizeof(PCI_CHILD), PCI_ALLOCATION_TAG);
- if (ParentBus->ChildrenData[NewIndex] == NULL) {
- NewIndex = MAX_ULONG;
- goto GetNewChildIndexEnd;
- }
- RtlZeroMemory(ParentBus->ChildrenData[NewIndex], sizeof(PCI_CHILD));
- GetNewChildIndexEnd:
- if (NewChildren != NULL) {
- MmFreePagedPool(NewChildren);
- }
- return NewIndex;
- }
- KSTATUS
- PcipQueryInterface (
- PIRP Irp,
- PPCI_DEVICE PciDevice
- )
- /*++
- Routine Description:
- This routine responds to interface requests.
- Arguments:
- Irp - Supplies a pointer to the Query Interface IRP.
- PciDevice - Supplies a pointer to the PCI device context relating to this
- device.
- Return Value:
- Status code.
- --*/
- {
- PINTERFACE_ACPI_BUS_ADDRESS BusAddressInterface;
- PINTERFACE_PCI_BUS_DEVICE BusDeviceInterface;
- BOOL Match;
- PINTERFACE_PCI_CONFIG_ACCESS PciConfigInterface;
- PINTERFACE_SPECIFIC_PCI_CONFIG_ACCESS SpecificPciConfigInterface;
- KSTATUS Status;
- ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
- (Irp->MinorCode == IrpMinorQueryInterface));
- if (Irp->U.QueryInterface.Interface == NULL) {
- return STATUS_INVALID_PARAMETER;
- }
- Status = STATUS_SUCCESS;
- //
- // Handle PCI config access interface requests.
- //
- Match = RtlAreUuidsEqual(&PciConfigSpaceUuid,
- Irp->U.QueryInterface.Interface);
- if (Match != FALSE) {
- if (Irp->U.QueryInterface.InterfaceBuffer != NULL) {
- //
- // Copy the interface into the buffer, assuming its big enough.
- //
- if (Irp->U.QueryInterface.InterfaceBufferSize !=
- sizeof(INTERFACE_PCI_CONFIG_ACCESS)) {
- Status = STATUS_INCORRECT_BUFFER_SIZE;
- Irp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_PCI_CONFIG_ACCESS);
- goto QueryInterfaceEnd;
- }
- PciConfigInterface = Irp->U.QueryInterface.InterfaceBuffer;
- PciConfigInterface->ReadPciConfig = PcipInterfaceReadConfigSpace;
- PciConfigInterface->WritePciConfig = PcipInterfaceWriteConfigSpace;
- PciConfigInterface->DeviceToken = PciDevice;
- //
- // The buffer is NULL, indicating the caller just wanted to know if the
- // interface was out there. Fill out the size and return success.
- //
- } else {
- Irp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_PCI_CONFIG_ACCESS);
- }
- goto QueryInterfaceEnd;
- }
- //
- // Handle specific PCI config access interface requests.
- //
- Match = RtlAreUuidsEqual(&PciSpecificConfigSpaceUuid,
- Irp->U.QueryInterface.Interface);
- if (Match != FALSE) {
- ASSERT((PciDevice->Type == PciDeviceBus) ||
- (PciDevice->Type == PciDeviceBridge));
- if (Irp->U.QueryInterface.InterfaceBuffer != NULL) {
- //
- // Copy the interface into the buffer, assuming its big enough.
- //
- if (Irp->U.QueryInterface.InterfaceBufferSize !=
- sizeof(INTERFACE_SPECIFIC_PCI_CONFIG_ACCESS)) {
- Status = STATUS_INCORRECT_BUFFER_SIZE;
- Irp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_SPECIFIC_PCI_CONFIG_ACCESS);
- goto QueryInterfaceEnd;
- }
- SpecificPciConfigInterface = Irp->U.QueryInterface.InterfaceBuffer;
- SpecificPciConfigInterface->ReadPciConfig =
- PcipInterfaceReadSpecificConfigSpace;
- SpecificPciConfigInterface->WritePciConfig =
- PcipInterfaceWriteSpecificConfigSpace;
- SpecificPciConfigInterface->DeviceToken = PciDevice;
- //
- // The buffer is NULL, indicating the caller just wanted to know if the
- // interface was out there. Fill out the size and return success.
- //
- } else {
- Irp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_SPECIFIC_PCI_CONFIG_ACCESS);
- }
- goto QueryInterfaceEnd;
- }
- //
- // Handle ACPI bus address interface requests.
- //
- if (PciDevice->Type == PciDeviceFunction) {
- Match = RtlAreUuidsEqual(&PciAcpiBusAddressUuid,
- Irp->U.QueryInterface.Interface);
- if (Match != FALSE) {
- ASSERT(PciDevice->Type == PciDeviceFunction);
- if (Irp->U.QueryInterface.InterfaceBuffer != NULL) {
- //
- // Copy the interface into the buffer, assuming its big enough.
- //
- if (Irp->U.QueryInterface.InterfaceBufferSize !=
- sizeof(INTERFACE_ACPI_BUS_ADDRESS)) {
- Status = STATUS_INCORRECT_BUFFER_SIZE;
- Irp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_ACPI_BUS_ADDRESS);
- goto QueryInterfaceEnd;
- }
- BusAddressInterface = Irp->U.QueryInterface.InterfaceBuffer;
- BusAddressInterface->BusAddress =
- (PciDevice->DeviceNumber << 16) |
- PciDevice->FunctionNumber;
- //
- // The buffer is NULL, indicating the caller just wanted to know if
- // the interface was out there. Fill out the size and return
- // success.
- //
- } else {
- Irp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_ACPI_BUS_ADDRESS);
- }
- goto QueryInterfaceEnd;
- }
- }
- //
- // Handle internal PCI bus driver context requests. The function driver for
- // bridges should not respond to this, leave it for the root bus function
- // driver or a PCI bus driver.
- //
- if ((PciDevice->Type == PciDeviceBus) ||
- (PciDevice->Type == PciDeviceFunction)) {
- Match = RtlAreUuidsEqual(&PciBusDriverDeviceUuid,
- Irp->U.QueryInterface.Interface);
- if (Match != FALSE) {
- if (Irp->U.QueryInterface.InterfaceBuffer != NULL) {
- //
- // Copy the interface into the buffer, assuming its big enough.
- //
- if (Irp->U.QueryInterface.InterfaceBufferSize !=
- sizeof(INTERFACE_PCI_BUS_DEVICE)) {
- ASSERT(FALSE);
- Status = STATUS_INCORRECT_BUFFER_SIZE;
- Irp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_PCI_BUS_DEVICE);
- goto QueryInterfaceEnd;
- }
- BusDeviceInterface = Irp->U.QueryInterface.InterfaceBuffer;
- BusDeviceInterface->BusDevice = PciDevice;
- //
- // The buffer is NULL, indicating the caller just wanted to know if
- // the interface was out there. Fill out the size and return
- // success.
- //
- } else {
- Irp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_PCI_BUS_DEVICE);
- }
- goto QueryInterfaceEnd;
- }
- }
- //
- // The interface is not exposed by this PCI device.
- //
- Status = STATUS_NO_INTERFACE;
- QueryInterfaceEnd:
- return Status;
- }
- KSTATUS
- PcipInterfaceReadConfigSpace (
- PVOID DeviceToken,
- ULONG Offset,
- ULONG AccessSize,
- PULONGLONG Value
- )
- /*++
- Routine Description:
- This routine reads from a device's PCI configuration space.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- Offset - Supplies the offset in bytes into the PCI configuration space to
- read.
- AccessSize - Supplies the size of the access to make. Valid values are 1,
- 2, 4, and 8.
- Value - Supplies a pointer where the value read from PCI configuration
- space will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG DataRead;
- PPCI_DEVICE PciDevice;
- if (Offset > 0xFF) {
- return STATUS_NOT_SUPPORTED;
- }
- PciDevice = DeviceToken;
- DataRead = PciDevice->ReadConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- AccessSize);
- *Value = DataRead;
- return STATUS_SUCCESS;
- }
- KSTATUS
- PcipInterfaceWriteConfigSpace (
- PVOID DeviceToken,
- ULONG Offset,
- ULONG AccessSize,
- ULONGLONG Value
- )
- /*++
- Routine Description:
- This routine writes to a device's PCI configuration space.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- AccessSize - Supplies the size of the access to make. Valid values are 1,
- 2, 4, and 8.
- Offset - Supplies the offset in bytes into the PCI configuration space to
- write.
- Value - Supplies the value to write into PCI configuration space.
- Return Value:
- Status code.
- --*/
- {
- PPCI_DEVICE PciDevice;
- if (Offset > 0xFF) {
- return STATUS_NOT_SUPPORTED;
- }
- PciDevice = DeviceToken;
- PciDevice->WriteConfig(PciDevice->BusNumber,
- PciDevice->DeviceNumber,
- PciDevice->FunctionNumber,
- Offset,
- AccessSize,
- Value);
- return STATUS_SUCCESS;
- }
- KSTATUS
- PcipInterfaceReadSpecificConfigSpace (
- PVOID DeviceToken,
- ULONG BusNumber,
- ULONG DeviceNumber,
- ULONG FunctionNumber,
- ULONG Offset,
- ULONG AccessSize,
- PULONGLONG Value
- )
- /*++
- Routine Description:
- This routine reads from a specific device's PCI configuration space.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- BusNumber - Supplies the bus number of the device whose PCI configuration
- space should be read from.
- DeviceNumber - Supplies the device number of the device whose PCI
- configuration space should be read from.
- FunctionNumber - Supplies the function number of the device whose PCI
- configuration space should be read from.
- Offset - Supplies the offset in bytes into the PCI configuration space to
- read.
- AccessSize - Supplies the size of the access to make. Valid values are 1,
- 2, 4, and 8.
- Value - Supplies a pointer where the value read from PCI configuration
- space will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG DataRead;
- PPCI_DEVICE PciDevice;
- if (Offset > 0xFF) {
- return STATUS_NOT_SUPPORTED;
- }
- PciDevice = DeviceToken;
- ASSERT((PciDevice->Type == PciDeviceBus) ||
- (PciDevice->Type == PciDeviceBridge));
- DataRead = PciDevice->ReadConfig(BusNumber,
- DeviceNumber,
- FunctionNumber,
- Offset,
- AccessSize);
- *Value = DataRead;
- return STATUS_SUCCESS;
- }
- KSTATUS
- PcipInterfaceWriteSpecificConfigSpace (
- PVOID DeviceToken,
- ULONG BusNumber,
- ULONG DeviceNumber,
- ULONG FunctionNumber,
- ULONG Offset,
- ULONG AccessSize,
- ULONGLONG Value
- )
- /*++
- Routine Description:
- This routine writes to a specific device's PCI configuration space.
- Arguments:
- DeviceToken - Supplies the device token supplied when the interface was
- acquired.
- BusNumber - Supplies the bus number of the device whose PCI configuration
- space should be written to.
- DeviceNumber - Supplies the device number of the device whose PCI
- configuration space should be written to.
- FunctionNumber - Supplies the function number of the device whose PCI
- configuration space should be written to.
- Offset - Supplies the offset in bytes into the PCI configuration space to
- write.
- AccessSize - Supplies the size of the access to make. Valid values are 1,
- 2, 4, and 8.
- Value - Supplies the value to write into PCI configuration space.
- Return Value:
- Status code.
- --*/
- {
- PPCI_DEVICE PciDevice;
- if (Offset > 0xFF) {
- return STATUS_NOT_SUPPORTED;
- }
- PciDevice = DeviceToken;
- ASSERT((PciDevice->Type == PciDeviceBus) ||
- (PciDevice->Type == PciDeviceBridge));
- PciDevice->WriteConfig(BusNumber,
- DeviceNumber,
- FunctionNumber,
- Offset,
- AccessSize,
- Value);
- return STATUS_SUCCESS;
- }
- KSTATUS
- PcipStartBusDevice (
- PIRP StartIrp,
- PPCI_DEVICE DeviceContext
- )
- /*++
- Routine Description:
- This routine starts a PCI bus.
- Arguments:
- StartIrp - Supplies a pointer to the start IRP.
- DeviceContext - Supplies a pointer to the PCI bus or bridge.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- PRESOURCE_ALLOCATION_LIST AllocationList;
- BOOL BusNumberArbiterCreated;
- BOOL IoPortArbiterCreated;
- BOOL MemoryArbiterCreated;
- PPCI_DEVICE Parent;
- KSTATUS Status;
- ASSERT(StartIrp->MinorCode == IrpMinorStartDevice);
- ASSERT((DeviceContext->Type == PciDeviceBus) ||
- (DeviceContext->Type == PciDeviceBridge));
- //
- // Bridges need to query the interface of the bus driver to get
- // configuration space access.
- //
- if (DeviceContext->ReadConfig == NULL) {
- ASSERT(DeviceContext->Type == PciDeviceBridge);
- Status = PcipGetBusDriverDevice(StartIrp->Device, &Parent);
- if (!KSUCCESS(Status)) {
- goto StartBusDeviceEnd;
- }
- DeviceContext->ReadConfig = Parent->ReadConfig;
- DeviceContext->WriteConfig = Parent->WriteConfig;
- }
- ASSERT((DeviceContext->ReadConfig != NULL) &&
- (DeviceContext->WriteConfig != NULL));
- //
- // Create the "specific PCI Config Space" access interface.
- //
- Status = PcipCreateBusInterfaces(StartIrp->Device, DeviceContext);
- if (!KSUCCESS(Status)) {
- goto StartBusDeviceEnd;
- }
- BusNumberArbiterCreated = FALSE;
- IoPortArbiterCreated = FALSE;
- MemoryArbiterCreated = FALSE;
- Status = STATUS_SUCCESS;
- //
- // Loop through every resource given to the bus/bridge, and expose an
- // arbiter for child devices.
- //
- AllocationList = StartIrp->U.StartDevice.ProcessorLocalResources;
- if (AllocationList == NULL) {
- goto StartBusDeviceEnd;
- }
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- while (Allocation != NULL) {
- //
- // Only create arbiters for expected types.
- //
- switch (Allocation->Type) {
- case ResourceTypeBusNumber:
- //
- // Create a bus number arbiter if one hasn't been created yet and
- // more than one bus number was doled out. Keep the first bus
- // number for this bus itself.
- //
- if (Allocation->Length > 1) {
- ASSERT(Allocation->Allocation == DeviceContext->BusNumber);
- if (BusNumberArbiterCreated == FALSE) {
- Status = IoCreateResourceArbiter(StartIrp->Device,
- Allocation->Type);
- if (!KSUCCESS(Status)) {
- goto StartBusDeviceEnd;
- }
- BusNumberArbiterCreated = TRUE;
- }
- Status = IoAddFreeSpaceToArbiter(StartIrp->Device,
- Allocation->Type,
- Allocation->Allocation + 1,
- Allocation->Length - 1,
- Allocation->Characteristics,
- Allocation,
- 0);
- //
- // If only one bus number was handed out, this must be a bridge.
- // Save that bus number for downstream config accesses later.
- //
- } else {
- ASSERT(Allocation->Length == 1);
- ASSERT((UCHAR)Allocation->Allocation == Allocation->Allocation);
- DeviceContext->BusNumber = (UCHAR)(Allocation->Allocation);
- }
- break;
- case ResourceTypePhysicalAddressSpace:
- //
- // Create an address space arbiter if one hasn't been created yet.
- //
- if (MemoryArbiterCreated == FALSE) {
- Status = IoCreateResourceArbiter(StartIrp->Device,
- Allocation->Type);
- if (!KSUCCESS(Status)) {
- goto StartBusDeviceEnd;
- }
- MemoryArbiterCreated = TRUE;
- }
- Status = IoAddFreeSpaceToArbiter(StartIrp->Device,
- Allocation->Type,
- Allocation->Allocation,
- Allocation->Length,
- Allocation->Characteristics,
- Allocation,
- 0);
- break;
- case ResourceTypeIoPort:
- //
- // Create an I/O port arbiter if one hasn't been created yet.
- //
- if (IoPortArbiterCreated == FALSE) {
- Status = IoCreateResourceArbiter(StartIrp->Device,
- Allocation->Type);
- if (!KSUCCESS(Status)) {
- goto StartBusDeviceEnd;
- }
- IoPortArbiterCreated = TRUE;
- }
- Status = IoAddFreeSpaceToArbiter(StartIrp->Device,
- Allocation->Type,
- Allocation->Allocation,
- Allocation->Length,
- Allocation->Characteristics,
- Allocation,
- 0);
- break;
- default:
- break;
- }
- if (!KSUCCESS(Status)) {
- goto StartBusDeviceEnd;
- }
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- StartBusDeviceEnd:
- return Status;
- }
- KSTATUS
- PcipCreateFunctionInterfaces (
- PDEVICE Device,
- PPCI_DEVICE PciDevice
- )
- /*++
- Routine Description:
- This routine creates the exposed interfaces for a PCI device.
- Arguments:
- Device - Supplies a pointer to the device to create interfaces for.
- PciDevice - Supplies a pointer to the PCI device context.
- Return Value:
- Status code.
- --*/
- {
- PINTERFACE_ACPI_BUS_ADDRESS BusAddressInterface;
- PINTERFACE_PCI_CONFIG_ACCESS PciConfigInterface;
- KSTATUS Status;
- BusAddressInterface = NULL;
- //
- // Create the PCI config access interface.
- //
- PciConfigInterface = MmAllocateNonPagedPool(
- sizeof(INTERFACE_PCI_CONFIG_ACCESS),
- PCI_ALLOCATION_TAG);
- if (PciConfigInterface == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateFunctionInterfacesEnd;
- }
- RtlZeroMemory(PciConfigInterface, sizeof(INTERFACE_PCI_CONFIG_ACCESS));
- PciConfigInterface->ReadPciConfig = PcipInterfaceReadConfigSpace;
- PciConfigInterface->WritePciConfig = PcipInterfaceWriteConfigSpace;
- PciConfigInterface->DeviceToken = PciDevice;
- PciDevice->PciConfigInterface = PciConfigInterface;
- //
- // Create the ACPI bus address interface.
- //
- BusAddressInterface = MmAllocateNonPagedPool(
- sizeof(INTERFACE_ACPI_BUS_ADDRESS),
- PCI_ALLOCATION_TAG);
- if (BusAddressInterface == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateFunctionInterfacesEnd;
- }
- RtlZeroMemory(BusAddressInterface, sizeof(INTERFACE_ACPI_BUS_ADDRESS));
- BusAddressInterface->BusAddress = (PciDevice->DeviceNumber << 16) |
- PciDevice->FunctionNumber;
- PciDevice->AcpiBusAddressInterface = BusAddressInterface;
- //
- // Enumerate the devices to the system.
- //
- Status = IoCreateInterface(&PciConfigSpaceUuid,
- Device,
- PciConfigInterface,
- sizeof(INTERFACE_PCI_CONFIG_ACCESS));
- if (!KSUCCESS(Status)) {
- //
- // Allow this to fail with a duplicate entry if the device is a bridge,
- // as the bridge's functional driver will have already created this
- // interface.
- //
- if ((Status != STATUS_DUPLICATE_ENTRY) ||
- (PciDevice->DeviceIsBridge == FALSE)) {
- goto CreateFunctionInterfacesEnd;
- }
- }
- Status = IoCreateInterface(&PciAcpiBusAddressUuid,
- Device,
- BusAddressInterface,
- sizeof(INTERFACE_ACPI_BUS_ADDRESS));
- if (!KSUCCESS(Status)) {
- IoDestroyInterface(&PciConfigSpaceUuid, Device, PciConfigInterface);
- goto CreateFunctionInterfacesEnd;
- }
- //
- // Attempt to create the MSI/MSI-X context and interface for this function
- // device.
- //
- Status = PcipMsiCreateContextAndInterface(Device, PciDevice);
- if (!KSUCCESS(Status)) {
- IoDestroyInterface(&PciConfigSpaceUuid, Device, PciConfigInterface);
- IoDestroyInterface(&PciAcpiBusAddressUuid, Device, BusAddressInterface);
- goto CreateFunctionInterfacesEnd;
- }
- Status = STATUS_SUCCESS;
- CreateFunctionInterfacesEnd:
- if (!KSUCCESS(Status)) {
- if (PciConfigInterface != NULL) {
- MmFreeNonPagedPool(PciConfigInterface);
- }
- if (BusAddressInterface != NULL) {
- MmFreeNonPagedPool(BusAddressInterface);
- }
- PciDevice->PciConfigInterface = NULL;
- PciDevice->AcpiBusAddressInterface = NULL;
- if (PciDevice->MsiContext != NULL) {
- PcipMsiDestroyContextAndInterface(Device, PciDevice);
- }
- }
- return Status;
- }
- KSTATUS
- PcipCreateBusInterfaces (
- PDEVICE Device,
- PPCI_DEVICE PciDevice
- )
- /*++
- Routine Description:
- This routine creates the exposed interfaces for a PCI device.
- Arguments:
- Device - Supplies a pointer to the device to create interfaces for.
- PciDevice - Supplies a pointer to the PCI device context.
- Return Value:
- Status code.
- --*/
- {
- PINTERFACE_SPECIFIC_PCI_CONFIG_ACCESS SpecificPciConfigInterface;
- KSTATUS Status;
- //
- // Create the specific PCI config access interface.
- //
- SpecificPciConfigInterface = MmAllocateNonPagedPool(
- sizeof(INTERFACE_SPECIFIC_PCI_CONFIG_ACCESS),
- PCI_ALLOCATION_TAG);
- if (SpecificPciConfigInterface == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateInterfacesEnd;
- }
- RtlZeroMemory(SpecificPciConfigInterface,
- sizeof(INTERFACE_SPECIFIC_PCI_CONFIG_ACCESS));
- SpecificPciConfigInterface->ReadPciConfig =
- PcipInterfaceReadSpecificConfigSpace;
- SpecificPciConfigInterface->WritePciConfig =
- PcipInterfaceWriteSpecificConfigSpace;
- SpecificPciConfigInterface->DeviceToken = PciDevice;
- //
- // Expose the interface to the system.
- //
- Status = IoCreateInterface(&PciSpecificConfigSpaceUuid,
- Device,
- SpecificPciConfigInterface,
- sizeof(INTERFACE_SPECIFIC_PCI_CONFIG_ACCESS));
- if (!KSUCCESS(Status)) {
- goto CreateInterfacesEnd;
- }
- PciDevice->SpecificPciConfigInterface = SpecificPciConfigInterface;
- Status = STATUS_SUCCESS;
- CreateInterfacesEnd:
- if (!KSUCCESS(Status)) {
- if (SpecificPciConfigInterface != NULL) {
- MmFreeNonPagedPool(SpecificPciConfigInterface);
- }
- PciDevice->SpecificPciConfigInterface = NULL;
- }
- return Status;
- }
- PSTR
- PcipGetClassId (
- ULONG ClassCode
- )
- /*++
- Routine Description:
- This routine returns the class string for the given PCI class code.
- Arguments:
- ClassCode - Supplies the class code.
- Return Value:
- Returns a pointer to a string describing the class.
- NULL if no class could be determined.
- --*/
- {
- UCHAR Class;
- USHORT Subclass;
- Class = PCI_CLASS_CODE(ClassCode);
- Subclass = PCI_SUBCLASS_AND_INTERFACE(ClassCode);
- switch (Class) {
- //
- // Unimplemented or unknown class codes.
- //
- case PCI_CLASS_UNKNOWN:
- if (Subclass == PCI_CLASS_UNKNOWN_VGA) {
- return "VGA";
- }
- break;
- case PCI_CLASS_MASS_STORAGE:
- if ((Subclass & PCI_CLASS_MASS_STORAGE_IDE_MASK) ==
- PCI_CLASS_MASS_STORAGE_IDE) {
- return "IDE";
- }
- break;
- case PCI_CLASS_BRIDGE:
- switch (Subclass) {
- case PCI_CLASS_BRIDGE_ISA:
- return "ISA";
- case PCI_CLASS_BRIDGE_PCI:
- return PCI_BRIDGE_CLASS_ID;
- case PCI_CLASS_BRIDGE_PCI_SUBTRACTIVE:
- return PCI_SUBTRACTIVE_BRIDGE_CLASS_ID;
- default:
- break;
- }
- break;
- case PCI_CLASS_SERIAL_BUS:
- switch (Subclass) {
- case PCI_CLASS_SERIAL_BUS_USB_UHCI:
- return "UHCI";
- case PCI_CLASS_SERIAL_BUS_USB_OHCI:
- return "OHCI";
- case PCI_CLASS_SERIAL_BUS_USB_EHCI:
- return "EHCI";
- default:
- break;
- }
- break;
- case PCI_CLASS_NETWORK:
- case PCI_CLASS_DISPLAY:
- case PCI_CLASS_MULTIMEDIA:
- case PCI_CLASS_MEMORY:
- break;
- case PCI_CLASS_SIMPLE_COMMUNICATION:
- switch (Subclass) {
- case PCI_CLASS_SIMPLE_COMMUNICATION_XT_UART:
- case PCI_CLASS_SIMPLE_COMMUNICATION_16450:
- case PCI_CLASS_SIMPLE_COMMUNICATION_16550:
- return "Serial16550";
- }
- break;
- case PCI_CLASS_GENERAL_PERIPHERAL:
- switch (Subclass) {
- case PCI_CLASS_GENERAL_SD_HOST_NO_DMA:
- return "SdHostPio";
- case PCI_CLASS_GENERAL_SD_HOST:
- return "SdHost";
- default:
- break;
- }
- break;
- case PCI_CLASS_INPUT:
- case PCI_CLASS_DOCKING_STATION:
- case PCI_CLASS_PROCESSOR:
- case PCI_CLASS_WIRELESS:
- case PCI_CLASS_INTELLIGENT_IO:
- case PCI_CLASS_SATELLITE_COMMUNICATION:
- case PCI_CLASS_ENCRYPTION:
- case PCI_CLASS_DATA_ACQUISITION:
- case PCI_CLASS_VENDOR:
- break;
- }
- return NULL;
- }
- KSTATUS
- PcipGetBusDriverDevice (
- PDEVICE OsDevice,
- PPCI_DEVICE *BusDriverDevice
- )
- /*++
- Routine Description:
- This routine returns the bus driver's PCI device structure.
- Arguments:
- OsDevice - Supplies a pointer to the OS device.
- BusDriverDevice - Supplies a pointer where a pointer to the bus driver's
- device will be returned on success.
- Return Value:
- Status code.
- --*/
- {
- INTERFACE_PCI_BUS_DEVICE Interface;
- PIRP QueryInterfaceIrp;
- KSTATUS Status;
- *BusDriverDevice = NULL;
- //
- // Allocate and send an IRP to the bus driver requesting access
- // to the PCI config interface.
- //
- QueryInterfaceIrp = IoCreateIrp(OsDevice, IrpMajorStateChange, 0);
- if (QueryInterfaceIrp == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GetBusDriverDeviceEnd;
- }
- QueryInterfaceIrp->MinorCode = IrpMinorQueryInterface;
- QueryInterfaceIrp->U.QueryInterface.Interface = &PciBusDriverDeviceUuid;
- QueryInterfaceIrp->U.QueryInterface.InterfaceBuffer = &Interface;
- QueryInterfaceIrp->U.QueryInterface.InterfaceBufferSize =
- sizeof(INTERFACE_PCI_BUS_DEVICE);
- Status = IoSendSynchronousIrp(QueryInterfaceIrp);
- if (!KSUCCESS(Status)) {
- goto GetBusDriverDeviceEnd;
- }
- Status = IoGetIrpStatus(QueryInterfaceIrp);
- if (!KSUCCESS(Status)) {
- goto GetBusDriverDeviceEnd;
- }
- *BusDriverDevice = Interface.BusDevice;
- GetBusDriverDeviceEnd:
- if (QueryInterfaceIrp != NULL) {
- IoDestroyIrp(QueryInterfaceIrp);
- }
- return Status;
- }
|