123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- musb.c
- Abstract:
- This module implements support for the Mentor Graphics USB 2.0 OTG
- controller.
- Author:
- Evan Green 11-Sep-2015
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/usb/usbhost.h>
- #include "musb.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- #define MUSB_READ8(_Controller, _Register) \
- HlReadRegister8((_Controller)->ControllerBase + (_Register))
- #define MUSB_WRITE8(_Controller, _Register, _Value) \
- HlWriteRegister8((_Controller)->ControllerBase + (_Register), (_Value))
- #define MUSB_READ16(_Controller, _Register) \
- HlReadRegister16((_Controller)->ControllerBase + (_Register))
- #define MUSB_WRITE16(_Controller, _Register, _Value) \
- HlWriteRegister16((_Controller)->ControllerBase + (_Register), (_Value))
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- MusbpCppiDmaCompletionCallback (
- PVOID Context,
- ULONG DmaEndpoint,
- BOOL Transmit
- );
- KSTATUS
- MusbpCreateEndpoint (
- PVOID HostControllerContext,
- PUSB_HOST_ENDPOINT_CREATION_REQUEST Endpoint,
- PVOID *EndpointContext
- );
- VOID
- MusbpResetEndpoint (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- ULONG MaxPacketSize
- );
- KSTATUS
- MusbpFlushEndpoint (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PULONG TransferCount
- );
- VOID
- MusbpDestroyEndpoint (
- PVOID HostControllerContext,
- PVOID EndpointContext
- );
- KSTATUS
- MusbpCreateTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- ULONG Flags,
- ULONG MaxBufferSize,
- PVOID *TransferContext
- );
- VOID
- MusbpDestroyTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PVOID TransferContext
- );
- KSTATUS
- MusbpSubmitTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PUSB_TRANSFER_INTERNAL Transfer,
- PVOID TransferContext
- );
- KSTATUS
- MusbpSubmitPolledTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PUSB_TRANSFER_INTERNAL Transfer,
- PVOID TransferContext
- );
- KSTATUS
- MusbpCancelTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PUSB_TRANSFER_INTERNAL Transfer,
- PVOID TransferContext
- );
- KSTATUS
- MusbpGetRootHubStatus (
- PVOID HostControllerContext,
- PUSB_HUB_STATUS HubStatus
- );
- KSTATUS
- MusbpSetRootHubStatus (
- PVOID HostControllerContext,
- PUSB_HUB_STATUS HubStatus
- );
- VOID
- MusbpProcessUsbInterrupts (
- PMUSB_CONTROLLER Controller,
- UCHAR UsbInterrupts
- );
- VOID
- MusbpProcessEndpointInterrupts (
- PMUSB_CONTROLLER Controller,
- ULONG EndpointInterrupts
- );
- KSTATUS
- MusbpInitializeTransfer (
- PMUSB_CONTROLLER Controller,
- PMUSB_SOFT_ENDPOINT SoftEndpoint,
- PUSB_TRANSFER_INTERNAL Transfer,
- PMUSB_TRANSFER_SET TransferSet
- );
- VOID
- MusbpExecuteNextTransfer (
- PMUSB_CONTROLLER Controller,
- PMUSB_HARD_ENDPOINT HardEndpoint
- );
- PMUSB_TRANSFER_SET
- MusbpProcessCompletedTransfer (
- PMUSB_CONTROLLER Controller,
- UCHAR HardwareIndex,
- PBOOL TransferCompleted
- );
- VOID
- MusbpFailAllTransfers (
- PMUSB_CONTROLLER Controller
- );
- VOID
- MusbpConfigureFifo (
- PMUSB_CONTROLLER Controller,
- PMUSB_FIFO_CONFIGURATION Configuration,
- PULONG Offset
- );
- VOID
- MusbpAbortTransfer (
- PMUSB_CONTROLLER Controller,
- UCHAR HardwareIndex,
- PMUSB_TRANSFER Transfer
- );
- VOID
- MusbpConfigureHardwareEndpoint (
- PMUSB_CONTROLLER Controller,
- PMUSB_SOFT_ENDPOINT SoftEndpoint
- );
- VOID
- MusbpUpdateDataToggle (
- PMUSB_CONTROLLER Controller,
- PMUSB_TRANSFER_SET TransferSet
- );
- VOID
- MusbpWriteFifo (
- PMUSB_CONTROLLER Controller,
- UCHAR EndpointIndex,
- PVOID Buffer,
- ULONG Size
- );
- VOID
- MusbpReadFifo (
- PMUSB_CONTROLLER Controller,
- UCHAR EndpointIndex,
- PVOID Buffer,
- ULONG BufferSize
- );
- VOID
- MusbpFlushFifo (
- PMUSB_CONTROLLER Controller,
- UCHAR HardwareIndex,
- BOOL HostOut
- );
- VOID
- MusbpAssignEndpoint (
- PMUSB_CONTROLLER Controller,
- PMUSB_SOFT_ENDPOINT SoftEndpoint
- );
- UCHAR
- MusbpReadIndexed8 (
- PMUSB_CONTROLLER Controller,
- UCHAR Index,
- MUSB_INDEXED_REGISTER Register
- );
- UCHAR
- MusbpReadIndexed16 (
- PMUSB_CONTROLLER Controller,
- UCHAR Index,
- MUSB_INDEXED_REGISTER Register
- );
- VOID
- MusbpWriteIndexed8 (
- PMUSB_CONTROLLER Controller,
- UCHAR Index,
- MUSB_INDEXED_REGISTER Register,
- UCHAR Value
- );
- VOID
- MusbpWriteIndexed16 (
- PMUSB_CONTROLLER Controller,
- UCHAR Index,
- MUSB_INDEXED_REGISTER Register,
- USHORT Value
- );
- VOID
- MusbpAcquireLock (
- PMUSB_CONTROLLER Controller
- );
- VOID
- MusbpReleaseLock (
- PMUSB_CONTROLLER Controller
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Set this boolean to disable DMA. This must be set before endpoint creation.
- //
- BOOL MusbDisableDma = FALSE;
- USB_HOST_CONTROLLER_INTERFACE MusbUsbHostInterfaceTemplate = {
- USB_HOST_CONTROLLER_INTERFACE_VERSION,
- NULL,
- NULL,
- NULL,
- 0,
- -1,
- UsbDeviceSpeedHigh,
- 1,
- MusbpCreateEndpoint,
- MusbpResetEndpoint,
- MusbpFlushEndpoint,
- MusbpDestroyEndpoint,
- MusbpCreateTransfer,
- MusbpDestroyTransfer,
- MusbpSubmitTransfer,
- MusbpSubmitPolledTransfer,
- MusbpCancelTransfer,
- MusbpGetRootHubStatus,
- MusbpSetRootHubStatus
- };
- MUSB_FIFO_CONFIGURATION MusbFifoConfiguration[] = {
- {1, MusbEndpointTx, 512},
- {1, MusbEndpointRx, 512},
- {2, MusbEndpointTx, 512},
- {2, MusbEndpointRx, 512},
- {3, MusbEndpointTx, 512},
- {3, MusbEndpointRx, 512},
- {4, MusbEndpointTx, 512},
- {4, MusbEndpointRx, 512},
- {5, MusbEndpointTx, 512},
- {5, MusbEndpointRx, 512},
- {6, MusbEndpointTx, 512},
- {6, MusbEndpointRx, 512},
- {7, MusbEndpointTx, 512},
- {7, MusbEndpointRx, 512},
- {8, MusbEndpointTx, 512},
- {8, MusbEndpointRx, 512},
- {9, MusbEndpointTx, 512},
- {9, MusbEndpointRx, 512},
- {10, MusbEndpointTx, 256},
- {10, MusbEndpointRx, 64},
- {11, MusbEndpointTx, 256},
- {11, MusbEndpointRx, 64},
- {12, MusbEndpointTx, 256},
- {12, MusbEndpointRx, 64},
- {13, MusbEndpointTx, 4096},
- {14, MusbEndpointRx, 1024},
- {15, MusbEndpointTx, 1024},
- {0, 0, 0}
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- MusbInitializeControllerState (
- PMUSB_CONTROLLER Controller,
- PVOID RegisterBase,
- PDRIVER Driver,
- PHYSICAL_ADDRESS PhysicalBase,
- PCPPI_DMA_CONTROLLER DmaController,
- UCHAR Instance
- )
- /*++
- Routine Description:
- This routine initializes data structures for the Mentor USB controller.
- It's assumed the controller structure has already been properly zeroed.
- Arguments:
- Controller - Supplies a pointer to the controller structure, which has
- already been zeroed.
- RegisterBase - Supplies the virtual address of the registers for the
- device.
- Driver - Supplies a pointer to the driver that owns this device.
- PhysicalBase - Supplies the physical address of the controller.
- DmaController - Supplies an optional pointer to the DMA controller to use.
- Instance - Supplies the instance ID to pass into the potentially shared
- DMA controller.
- Return Value:
- Status code.
- --*/
- {
- PMUSB_HARD_ENDPOINT Endpoint;
- ULONG Index;
- KSTATUS Status;
- Controller->ControllerBase = RegisterBase;
- Controller->Driver = Driver;
- Controller->PhysicalBase = PhysicalBase;
- Controller->NextEndpointAssignment = 1;
- Controller->CppiDma = DmaController;
- Controller->Instance = Instance;
- KeInitializeSpinLock(&(Controller->Lock));
- for (Index = 0; Index < MUSB_MAX_ENDPOINTS; Index += 1) {
- Endpoint = &(Controller->Endpoints[Index]);
- INITIALIZE_LIST_HEAD(&(Endpoint->TransferList));
- Endpoint->CurrentEndpoint = NULL;
- }
- if (DmaController != NULL) {
- CppiRegisterCompletionCallback(DmaController,
- Instance,
- MusbpCppiDmaCompletionCallback,
- Controller);
- }
- Status = STATUS_SUCCESS;
- if (!KSUCCESS(Status)) {
- MusbDestroyControllerState(Controller);
- }
- return STATUS_SUCCESS;
- }
- KSTATUS
- MusbDestroyControllerState (
- PMUSB_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine destroys the given Mentor USB controller structure, freeing
- all resources associated with the controller except the controller
- structure itself and the register base, which were passed in on initialize.
- Arguments:
- Controller - Supplies a pointer to the controller to destroy.
- Return Value:
- Status code.
- --*/
- {
- Controller->ControllerBase = NULL;
- return STATUS_SUCCESS;
- }
- KSTATUS
- MusbResetController (
- PMUSB_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine resets and reinitializes the given controller.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Return Value:
- Status code.
- --*/
- {
- PMUSB_FIFO_CONFIGURATION Configuration;
- UCHAR DeviceControl;
- UCHAR EndpointCount;
- ULONG Offset;
- UCHAR UsbInterrupts;
- MUSB_WRITE8(Controller, MusbSoftReset, MUSB_SOFT_RESET_SOFT_RESET);
- EndpointCount = MUSB_READ8(Controller, MusbEndpointInfo);
- //
- // Determine the number of hardware endpoints.
- //
- Controller->EndpointCount =
- EndpointCount & MUSB_ENDPOINT_INFO_TX_COUNT_MASK;
- ASSERT(((EndpointCount &
- MUSB_ENDPOINT_INFO_RX_COUNT_MASK) >>
- MUSB_ENDPOINT_INFO_RX_COUNT_SHIFT) == Controller->EndpointCount);
- //
- // Program the FIFO configuration for the endpoints. Endpoint 0 always gets
- // the first 64 bytes.
- //
- Offset = 64;
- Configuration = MusbFifoConfiguration;
- while (Configuration->MaxPacketSize != 0) {
- if (Configuration->Endpoint < Controller->EndpointCount) {
- MusbpConfigureFifo(Controller, Configuration, &Offset);
- }
- Configuration += 1;
- }
- //
- // Enable all endpoint interrupts, and all USB interrupts except start of
- // frame.
- //
- MUSB_WRITE16(Controller, MusbInterruptEnableTx, 0xFFFF);
- MUSB_WRITE16(Controller, MusbInterruptEnableRx, 0xFFFF);
- UsbInterrupts = MUSB_USB_INTERRUPT_SUSPEND |
- MUSB_USB_INTERRUPT_RESUME |
- MUSB_USB_INTERRUPT_RESET_BABBLE |
- MUSB_USB_INTERRUPT_CONNECT |
- MUSB_USB_INTERRUPT_DISCONNECT |
- MUSB_USB_INTERRUPT_SESSION |
- MUSB_USB_INTERRUPT_VBUS_ERROR;
- Controller->UsbInterruptEnable = UsbInterrupts;
- MUSB_WRITE8(Controller, MusbInterruptEnableUsb, UsbInterrupts);
- //
- // Enable a session.
- //
- DeviceControl = MUSB_READ8(Controller, MusbDeviceControl);
- DeviceControl |= MUSB_DEVICE_CONTROL_SESSION;
- MUSB_WRITE8(Controller, MusbDeviceControl, DeviceControl);
- return STATUS_SUCCESS;
- }
- KSTATUS
- MusbRegisterController (
- PMUSB_CONTROLLER Controller,
- PDEVICE Device
- )
- /*++
- Routine Description:
- This routine registers the started Mentor USB controller with the core USB
- library.
- Arguments:
- Controller - Supplies a pointer to the state of the controller to register.
- Device - Supplies a pointer to the device object.
- Return Value:
- Status code.
- --*/
- {
- USB_HOST_CONTROLLER_INTERFACE Interface;
- KSTATUS Status;
- //
- // Fill out the functions that the USB core library will use to control
- // the host controller.
- //
- RtlCopyMemory(&Interface,
- &MusbUsbHostInterfaceTemplate,
- sizeof(USB_HOST_CONTROLLER_INTERFACE));
- Interface.DriverObject = Controller->Driver;
- Interface.DeviceObject = Device;
- Interface.HostControllerContext = Controller;
- Interface.Identifier = Controller->PhysicalBase;
- Status = UsbHostRegisterController(&Interface,
- &(Controller->UsbCoreHandle));
- if (!KSUCCESS(Status)) {
- goto RegisterControllerEnd;
- }
- RegisterControllerEnd:
- return Status;
- }
- INTERRUPT_STATUS
- MusbInterruptService (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements the MUSB interrupt service routine.
- Arguments:
- Context - Supplies the context pointer given to the system when the
- interrupt was connected. In this case, this points to the controller.
- Return Value:
- Interrupt status.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- ULONG EndpointStatus;
- INTERRUPT_STATUS InterruptStatus;
- USHORT RxStatus;
- USHORT TxStatus;
- USHORT UsbStatus;
- Controller = (PMUSB_CONTROLLER)Context;
- InterruptStatus = InterruptStatusNotClaimed;
- //
- // Read the status register. If it's non-zero, this is USB's interrupt.
- //
- UsbStatus = MUSB_READ8(Controller, MusbInterruptUsb) &
- Controller->UsbInterruptEnable;
- if (UsbStatus != 0) {
- InterruptStatus = InterruptStatusClaimed;
- RtlAtomicOr32(&(Controller->PendingUsbInterrupts), UsbStatus);
- //
- // Clear the bits in the status register to acknowledge the interrupt.
- //
- MUSB_WRITE8(Controller, MusbInterruptUsb, UsbStatus);
- }
- RxStatus = MUSB_READ16(Controller, MusbInterruptRx);
- TxStatus = MUSB_READ16(Controller, MusbInterruptTx);
- EndpointStatus = (RxStatus << 16) | TxStatus;
- if (EndpointStatus != 0) {
- InterruptStatus = InterruptStatusClaimed;
- RtlAtomicOr32(&(Controller->PendingEndpointInterrupts), EndpointStatus);
- if (RxStatus != 0) {
- MUSB_WRITE16(Controller, MusbInterruptRx, RxStatus);
- }
- if (TxStatus != 0) {
- MUSB_WRITE16(Controller, MusbInterruptTx, TxStatus);
- }
- }
- return InterruptStatus;
- }
- INTERRUPT_STATUS
- MusbInterruptServiceDpc (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine implements the MUSB dispatch level interrupt service.
- Arguments:
- Parameter - Supplies the context, in this case the controller structure.
- Return Value:
- None.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- ULONG EndpointInterrupts;
- ULONG UsbInterrupts;
- Controller = Parameter;
- UsbInterrupts = RtlAtomicExchange32(&(Controller->PendingUsbInterrupts), 0);
- EndpointInterrupts =
- RtlAtomicExchange32(&(Controller->PendingEndpointInterrupts), 0);
- if ((UsbInterrupts == 0) && (EndpointInterrupts == 0)) {
- return InterruptStatusNotClaimed;
- }
- if (UsbInterrupts != 0) {
- MusbpProcessUsbInterrupts(Controller, UsbInterrupts);
- }
- if (EndpointInterrupts != 0) {
- MusbpProcessEndpointInterrupts(Controller, EndpointInterrupts);
- }
- return InterruptStatusClaimed;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- MusbpCppiDmaCompletionCallback (
- PVOID Context,
- ULONG DmaEndpoint,
- BOOL Transmit
- )
- /*++
- Routine Description:
- This routine is called when CPPI receives an interrupt telling it that a
- queue completion occurred.
- Arguments:
- Context - Supplies an opaque pointer's worth of context for the callback
- routine.
- DmaEndpoint - Supplies the zero-based DMA endpoint number. Add 1 to get
- to a USB endpoint number.
- Transmit - Supplies a boolean indicating if this is a transmit completion
- (TRUE) or a receive completion (FALSE).
- Return Value:
- None.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- ULONG Endpoint;
- ULONG Mask;
- Controller = Context;
- Endpoint = CPPI_DMA_ENDPOINT_TO_USB(DmaEndpoint);
- Mask = 1 << Endpoint;
- if (Transmit == FALSE) {
- Mask <<= 16;
- }
- MusbpProcessEndpointInterrupts(Controller, Mask);
- return;
- }
- KSTATUS
- MusbpCreateEndpoint (
- PVOID HostControllerContext,
- PUSB_HOST_ENDPOINT_CREATION_REQUEST Endpoint,
- PVOID *EndpointContext
- )
- /*++
- Routine Description:
- This routine is called by the USB core when a new endpoint is being opened.
- It allows the host controller to create and store any context needed to
- support a new endpoint (such as a queue head).
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- Endpoint - Supplies a pointer containing information about the endpoint
- being created. The host controller cannot count on this buffer sticking
- around after the function returns. If it needs this information it
- should make a copy of it.
- EndpointContext - Supplies a pointer where the host controller can store a
- context pointer identifying the endpoint created.
- Return Value:
- STATUS_SUCCESS if the endpoint can be successfully accommodated.
- Failing status code if the endpoint cannot be opened.
- --*/
- {
- USHORT Control;
- PMUSB_CONTROLLER Controller;
- USHORT PollRate;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- KSTATUS Status;
- UCHAR Type;
- Controller = HostControllerContext;
- PollRate = Endpoint->PollRate;
- //
- // For high speed endpoints, the interval is 2^(Interval - 1). This is
- // also true for full speed isochronous and full speed bulk (NAK count).
- // For other full/low speed endpoints, it's just a frame count.
- //
- if ((Endpoint->Speed == UsbDeviceSpeedHigh) ||
- ((Endpoint->Speed == UsbDeviceSpeedFull) &&
- ((Endpoint->Type == UsbTransferTypeIsochronous) ||
- (Endpoint->Type == UsbTransferTypeBulk)))) {
- if (PollRate != 0) {
- PollRate = RtlCountTrailingZeros32(PollRate) + 1;
- if (PollRate > 16) {
- PollRate = 16;
- }
- }
- }
- SoftEndpoint = MmAllocateNonPagedPool(sizeof(MUSB_SOFT_ENDPOINT),
- MUSB_ALLOCATION_TAG);
- if (SoftEndpoint == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateEndpointEnd;
- }
- RtlZeroMemory(SoftEndpoint, sizeof(MUSB_SOFT_ENDPOINT));
- SoftEndpoint->MaxPayload = Endpoint->MaxPacketSize;
- SoftEndpoint->HubAddress = Endpoint->HubAddress;
- SoftEndpoint->HubPort = Endpoint->HubPortNumber;
- SoftEndpoint->EndpointNumber = Endpoint->EndpointNumber;
- Type = Endpoint->EndpointNumber & MUSB_TXTYPE_TARGET_ENDPOINT_MASK;
- switch (Endpoint->Speed) {
- case UsbDeviceSpeedLow:
- Type |= MUSB_TXTYPE_SPEED_LOW;
- break;
- case UsbDeviceSpeedFull:
- Type |= MUSB_TXTYPE_SPEED_FULL;
- break;
- case UsbDeviceSpeedHigh:
- Type |= MUSB_TXTYPE_SPEED_HIGH;
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_PARAMETER;
- goto CreateEndpointEnd;
- }
- SoftEndpoint->Interval = PollRate;
- switch (Endpoint->Type) {
- case UsbTransferTypeControl:
- Type |= MUSB_TXTYPE_PROTOCOL_CONTROL;
- SoftEndpoint->HardwareIndex = 0;
- SoftEndpoint->Interval = 0;
- break;
- case UsbTransferTypeInterrupt:
- Type |= MUSB_TXTYPE_PROTOCOL_INTERRUPT;
- break;
- case UsbTransferTypeBulk:
- Type |= MUSB_TXTYPE_PROTOCOL_BULK;
- break;
- case UsbTransferTypeIsochronous:
- Type |= MUSB_TXTYPE_PROTOCOL_ISOCHRONOUS;
- break;
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_PARAMETER;
- goto CreateEndpointEnd;
- }
- SoftEndpoint->Type = Type;
- SoftEndpoint->Direction = Endpoint->Direction;
- //
- // All control endpoints use hardware endpoint 0, and cannot use DMA. For
- // any other type, assign it a hard endpoint/channel.
- //
- if (Endpoint->Type == UsbTransferTypeControl) {
- //
- // Set the control endpoint direction to "out" so that the TX
- // control/status register is always used, which is required for
- // hardware endpoint 0.
- //
- SoftEndpoint->Direction = UsbTransferDirectionOut;
- } else {
- if ((MusbDisableDma == FALSE) && (Controller->CppiDma != NULL)) {
- Control = 0;
- if (Endpoint->Direction == UsbTransferDirectionOut) {
- Control |= MUSB_TX_CONTROL_DMA_ENABLE |
- MUSB_TX_CONTROL_DMA_MODE;
- } else {
- ASSERT(Endpoint->Direction == UsbTransferDirectionIn);
- Control |= MUSB_RX_CONTROL_DMA_ENABLE;
- }
- SoftEndpoint->Control = Control;
- }
- //
- // Find an initial hardware endpoint for this software endpoint.
- //
- MusbpAcquireLock(Controller);
- MusbpAssignEndpoint(Controller, SoftEndpoint);
- MusbpReleaseLock(Controller);
- }
- *EndpointContext = SoftEndpoint;
- Status = STATUS_SUCCESS;
- CreateEndpointEnd:
- if (!KSUCCESS(Status)) {
- if (SoftEndpoint != NULL) {
- MmFreePagedPool(SoftEndpoint);
- }
- }
- return Status;
- }
- VOID
- MusbpResetEndpoint (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- ULONG MaxPacketSize
- )
- /*++
- Routine Description:
- This routine is called by the USB core when an endpoint needs to be reset.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- EndpointContext - Supplies a pointer to the context returned by the host
- controller when the endpoint was created.
- MaxPacketSize - Supplies the maximum transfer size of the endpoint.
- Return Value:
- None.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- ULONG Register;
- RUNLEVEL RunLevel;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- USHORT Value;
- Controller = HostControllerContext;
- SoftEndpoint = EndpointContext;
- //
- // Only control endpoints are expected to change max packet sizes.
- //
- ASSERT((SoftEndpoint->HardwareIndex == 0) ||
- (MaxPacketSize == SoftEndpoint->MaxPayload));
- SoftEndpoint->MaxPayload = MaxPacketSize;
- //
- // This needs to acquire the lock in normal mode. In crash dump mode, skip
- // that.
- //
- RunLevel = KeGetRunLevel();
- if (RunLevel != RunLevelHigh) {
- MusbpAcquireLock(Controller);
- }
- //
- // Clear the data toggle bit.
- //
- if (SoftEndpoint->HardwareIndex == 0) {
- SoftEndpoint->Control &= ~MUSB_EP0_CONTROL_DATA_TOGGLE;
- } else if (SoftEndpoint->Direction == UsbTransferDirectionIn) {
- SoftEndpoint->Control &= ~MUSB_RX_CONTROL_DATA_TOGGLE;
- } else {
- ASSERT(SoftEndpoint->Direction == UsbTransferDirectionOut);
- SoftEndpoint->Control &= ~MUSB_TX_CONTROL_DATA_TOGGLE;
- }
- //
- // If this software endpoint is currently programmed in the hardware
- // channel, clear the data toggle in the hardware too.
- //
- HardEndpoint = &(Controller->Endpoints[SoftEndpoint->HardwareIndex]);
- if (HardEndpoint->CurrentEndpoint == SoftEndpoint) {
- if (SoftEndpoint->HardwareIndex == 0) {
- ASSERT(MaxPacketSize <= 64);
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus, 0);
- Value = SoftEndpoint->Control | MUSB_EP0_CONTROL_DATA_TOGGLE_WRITE;
- MUSB_WRITE16(Controller, Register, Value);
- Value = SoftEndpoint->MaxPayload;
- Register = MUSB_ENDPOINT_CONTROL(MusbTxMaxPacketSize, 0);
- MUSB_WRITE16(Controller, Register, Value);
- } else if (SoftEndpoint->Direction == UsbTransferDirectionIn) {
- Register = MUSB_ENDPOINT_CONTROL(MusbRxControlStatus,
- SoftEndpoint->HardwareIndex);
- Value = SoftEndpoint->Control | MUSB_RX_CONTROL_CLEAR_TOGGLE;
- MUSB_WRITE16(Controller, Register, Value);
- } else {
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus,
- SoftEndpoint->HardwareIndex);
- Value = SoftEndpoint->Control | MUSB_TX_CONTROL_CLEAR_TOGGLE;
- MUSB_WRITE16(Controller, Register, Value);
- }
- }
- if (RunLevel != RunLevelHigh) {
- MusbpReleaseLock(Controller);
- }
- return;
- }
- KSTATUS
- MusbpFlushEndpoint (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PULONG TransferCount
- )
- /*++
- Routine Description:
- This routine flushes all the active transfers from an endpoint. It does so
- by polling for completion status and does not return until all transfers
- are completed. This must be called at high run level.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- EndpointContext - Supplies a pointer to the context returned by the host
- controller when the endpoint was created.
- TransferCount - Supplies a pointer to a boolean that receives the number
- of transfers that were flushed.
- Return Value:
- Status code.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- ULONG Count;
- USHORT EndpointInterrupts;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- UCHAR HardwareIndex;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- BOOL StartNextTransfer;
- KSTATUS Status;
- ULONGLONG Timeout;
- PMUSB_TRANSFER_SET TransferSet;
- Controller = HostControllerContext;
- SoftEndpoint = EndpointContext;
- Count = 0;
- HardwareIndex = SoftEndpoint->HardwareIndex;
- HardEndpoint = &(Controller->Endpoints[HardwareIndex]);
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- Timeout = HlQueryTimeCounter() + (10 * HlQueryTimeCounterFrequency());
- while (!LIST_EMPTY(&(HardEndpoint->TransferList))) {
- //
- // Read the endpoint interrupt status, and wait for this endpoint to
- // arrive.
- //
- EndpointInterrupts = MUSB_READ16(Controller, MusbInterruptRx) |
- MUSB_READ16(Controller, MusbInterruptTx);
- if ((EndpointInterrupts & (1 << HardwareIndex)) == 0) {
- if (HlQueryTimeCounter() >= Timeout) {
- Status = STATUS_TIMEOUT;
- goto FlushEndpointEnd;
- }
- }
- //
- // Clear the endpoint interrupt.
- //
- MUSB_WRITE8(Controller, MusbInterruptRx, 1 << HardwareIndex);
- MUSB_WRITE8(Controller, MusbInterruptTx, 1 << HardwareIndex);
- //
- // Process a completed transfer.
- //
- TransferSet = MusbpProcessCompletedTransfer(Controller,
- HardwareIndex,
- &StartNextTransfer);
- if (TransferSet != NULL) {
- Count += 1;
- }
- //
- // Pump the next transfer through.
- //
- if (StartNextTransfer != FALSE) {
- MusbpExecuteNextTransfer(Controller, HardEndpoint);
- }
- }
- Status = STATUS_SUCCESS;
- FlushEndpointEnd:
- *TransferCount = Count;
- return Status;
- }
- VOID
- MusbpDestroyEndpoint (
- PVOID HostControllerContext,
- PVOID EndpointContext
- )
- /*++
- Routine Description:
- This routine tears down and destroys an endpoint created with the endpoint
- creation routine.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- EndpointContext - Supplies a pointer to the context returned by the host
- controller when the endpoint was created.
- Return Value:
- None.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- SoftEndpoint = EndpointContext;
- Controller = HostControllerContext;
- HardEndpoint = &(Controller->Endpoints[SoftEndpoint->HardwareIndex]);
- if (HardEndpoint->CurrentEndpoint == SoftEndpoint) {
- MusbpAcquireLock(Controller);
- if (HardEndpoint->CurrentEndpoint == SoftEndpoint) {
- HardEndpoint->CurrentEndpoint = NULL;
- }
- MusbpReleaseLock(Controller);
- }
- MmFreeNonPagedPool(SoftEndpoint);
- return;
- }
- KSTATUS
- MusbpCreateTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- ULONG MaxBufferSize,
- ULONG Flags,
- PVOID *TransferContext
- )
- /*++
- Routine Description:
- This routine allocates structures needed for the USB host controller to
- support a transfer.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- EndpointContext - Supplies a pointer to the host controller's context of
- the endpoint that this transfer will eventually be submitted to.
- MaxBufferSize - Supplies the maximum buffer length, in bytes, of the
- transfer when it is submitted. It is assumed that the host controller
- will set up as many transfer descriptors as are needed to support a
- transfer of this size.
- Flags - Supplies a bitfield of flags regarding the transaction. See
- USB_TRANSFER_FLAG_* definitions.
- TransferContext - Supplies a pointer where the host controller can store a
- context pointer containing any needed structures for the transfer.
- Return Value:
- None.
- --*/
- {
- UINTN AllocationSize;
- PMUSB_CONTROLLER Controller;
- BOOL ForceShortTransfer;
- ULONG Index;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- KSTATUS Status;
- PMUSB_TRANSFER Transfer;
- ULONG TransferCount;
- PMUSB_TRANSFER_SET TransferSet;
- Controller = HostControllerContext;
- SoftEndpoint = EndpointContext;
- TransferCount = 0;
- ForceShortTransfer = FALSE;
- if ((Flags & USB_TRANSFER_FLAG_FORCE_SHORT_TRANSFER) != 0) {
- ForceShortTransfer = TRUE;
- }
- //
- // Control transfers need at least 2 transfers: the setup packet (which
- // burns the first 8 bytes), zero or more data transfers, and a status
- // transfer.
- //
- if (SoftEndpoint->HardwareIndex == 0) {
- ASSERT(MaxBufferSize >= sizeof(USB_SETUP_PACKET));
- MaxBufferSize -= sizeof(USB_SETUP_PACKET);
- TransferCount += 2;
- }
- if (MaxBufferSize != 0) {
- TransferCount += (MaxBufferSize + (SoftEndpoint->MaxPayload - 1)) /
- SoftEndpoint->MaxPayload;
- //
- // If it's possible for the transfer to send a multiple of the max
- // payload size and a short transfer needs to be forced, add an another
- // transfer.
- //
- if ((ForceShortTransfer != FALSE) &&
- (MaxBufferSize >= SoftEndpoint->MaxPayload)) {
- TransferCount += 1;
- }
- //
- // Account for a USB transfer that will only send zero length packets and
- // for control transfers that need to force a zero length packet in the
- // data phase.
- //
- } else if ((ForceShortTransfer != FALSE) ||
- (SoftEndpoint->HardwareIndex != 0)) {
- TransferCount += 1;
- }
- AllocationSize = sizeof(MUSB_TRANSFER_SET) +
- (TransferCount * sizeof(MUSB_TRANSFER));
- TransferSet = MmAllocateNonPagedPool(AllocationSize, MUSB_ALLOCATION_TAG);
- if (TransferSet == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateTransferEnd;
- }
- RtlZeroMemory(TransferSet, AllocationSize);
- TransferSet->MaxCount = TransferCount;
- TransferSet->Transfers = (PMUSB_TRANSFER)(TransferSet + 1);
- if ((SoftEndpoint->HardwareIndex != 0) &&
- (MusbDisableDma == FALSE) &&
- (Controller->CppiDma != NULL)) {
- Transfer = TransferSet->Transfers;
- for (Index = 0; Index < TransferCount; Index += 1) {
- Status = CppiCreateDescriptor(Controller->CppiDma,
- Controller->Instance,
- &(Transfer->DmaData));
- if (!KSUCCESS(Status)) {
- goto CreateTransferEnd;
- }
- Transfer += 1;
- }
- }
- Status = STATUS_SUCCESS;
- CreateTransferEnd:
- if (!KSUCCESS(Status)) {
- if (TransferSet != NULL) {
- Transfer = TransferSet->Transfers;
- for (Index = 0; Index < TransferCount; Index += 1) {
- if (Transfer->DmaData.Descriptor != NULL) {
- CppiDestroyDescriptor(Controller->CppiDma,
- &(Transfer->DmaData));
- }
- Transfer += 1;
- }
- MmFreeNonPagedPool(TransferSet);
- TransferSet = NULL;
- }
- }
- *TransferContext = TransferSet;
- return Status;
- }
- VOID
- MusbpDestroyTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PVOID TransferContext
- )
- /*++
- Routine Description:
- This routine destroys host controller structures associated with a USB
- transfer.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- EndpointContext - Supplies a pointer to the host controller context for the
- endpoint this transfer belonged to.
- TransferContext - Supplies the pointer provided to the USB core by the host
- controller when the transfer was created.
- Return Value:
- None.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- ULONG Index;
- PMUSB_TRANSFER Transfer;
- ULONG TransferCount;
- PMUSB_TRANSFER_SET TransferSet;
- Controller = HostControllerContext;
- TransferSet = TransferContext;
- TransferCount = TransferSet->MaxCount;
- Transfer = TransferSet->Transfers;
- for (Index = 0; Index < TransferCount; Index += 1) {
- if (Transfer->DmaData.Descriptor != NULL) {
- CppiDestroyDescriptor(Controller->CppiDma, &(Transfer->DmaData));
- }
- Transfer += 1;
- }
- MmFreeNonPagedPool(TransferSet);
- return;
- }
- KSTATUS
- MusbpSubmitTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PUSB_TRANSFER_INTERNAL Transfer,
- PVOID TransferContext
- )
- /*++
- Routine Description:
- This routine submits a transfer to the USB host controller for execution.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- EndpointContext - Supplies the context pointer provided to the USB core by
- the host controller when the endpoint was created.
- Transfer - Supplies a pointer to the USB transfer to execute.
- TransferContext - Supplies the pointer provided to the USB core by the host
- controller when the transfer was created.
- Return Value:
- STATUS_SUCCESS if the transfer was successfully added to the hardware queue.
- Failure codes if the transfer could not be added.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- KSTATUS Status;
- PMUSB_TRANSFER_SET TransferSet;
- Controller = HostControllerContext;
- SoftEndpoint = EndpointContext;
- TransferSet = TransferContext;
- MusbpAcquireLock(Controller);
- if (Controller->Connected == FALSE) {
- Status = STATUS_DEVICE_NOT_CONNECTED;
- goto SubmitTransferEnd;
- }
- //
- // Assign a hardware endpoint and fill out all the descriptors.
- //
- MusbpAssignEndpoint(Controller, SoftEndpoint);
- Status = MusbpInitializeTransfer(Controller,
- SoftEndpoint,
- Transfer,
- TransferSet);
- if (!KSUCCESS(Status)) {
- goto SubmitTransferEnd;
- }
- HardEndpoint = &(Controller->Endpoints[SoftEndpoint->HardwareIndex]);
- if (Transfer->DeviceAddress != SoftEndpoint->Device) {
- ASSERT((SoftEndpoint->Device == 0) && (Transfer->DeviceAddress != 0));
- SoftEndpoint->Device = Transfer->DeviceAddress;
- //
- // The device ID changed so the endpoint will require reconfiguration.
- //
- HardEndpoint->CurrentEndpoint = NULL;
- }
- //
- // If there are no transfers pending, kick this one off.
- //
- INSERT_BEFORE(&(TransferSet->ListEntry), &(HardEndpoint->TransferList));
- SoftEndpoint->InFlight += 1;
- if (HardEndpoint->TransferList.Next == &(TransferSet->ListEntry)) {
- ASSERT(SoftEndpoint->InFlight == 1);
- MusbpExecuteNextTransfer(Controller, HardEndpoint);
- }
- Status = STATUS_SUCCESS;
- SubmitTransferEnd:
- MusbpReleaseLock(Controller);
- return Status;
- }
- KSTATUS
- MusbpSubmitPolledTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PUSB_TRANSFER_INTERNAL Transfer,
- PVOID TransferContext
- )
- /*++
- Routine Description:
- This routine submits a transfer to the USB host controller for execution
- and busy waits for it to complete. This routine is meant for crash dump
- support to allow USB transfers when the system is fragile. As a result, it
- forgoes acquiring the normal sequence of locks.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- EndpointContext - Supplies the context pointer provided to the USB core by
- the host controller when the endpoint was created.
- Transfer - Supplies a pointer to the USB transfer to execute.
- TransferContext - Supplies the pointer provided to the USB core by the host
- controller when the transfer was created.
- Return Value:
- STATUS_SUCCESS if the transfer was successfully added to the hardware queue.
- Failure codes if the transfer could not be added.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- KSTATUS Status;
- ULONG TransferCount;
- PMUSB_TRANSFER_SET TransferSet;
- Controller = HostControllerContext;
- SoftEndpoint = EndpointContext;
- HardEndpoint = &(Controller->Endpoints[SoftEndpoint->HardwareIndex]);
- TransferSet = TransferContext;
- //
- // Clear the DMA flag on the endpoint.
- //
- if (SoftEndpoint->HardwareIndex != 0) {
- if (SoftEndpoint->Direction == UsbTransferDirectionOut) {
- SoftEndpoint->Control &= ~MUSB_TX_CONTROL_DMA_ENABLE;
- } else {
- SoftEndpoint->Control &= ~MUSB_RX_CONTROL_DMA_ENABLE;
- }
- }
- MusbpAssignEndpoint(Controller, SoftEndpoint);
- Status = MusbpInitializeTransfer(Controller,
- SoftEndpoint,
- Transfer,
- TransferSet);
- if (!KSUCCESS(Status)) {
- goto SubmitPolledTransferEnd;
- }
- //
- // Stick this transfer on the head of the list, and then work through it.
- //
- INSERT_AFTER(&(TransferSet->ListEntry), &(HardEndpoint->TransferList));
- SoftEndpoint->InFlight += 1;
- HardEndpoint->CurrentEndpoint = NULL;
- MusbpExecuteNextTransfer(Controller, HardEndpoint);
- Status = MusbpFlushEndpoint(Controller, SoftEndpoint, &TransferCount);
- if (!KSUCCESS(Status)) {
- goto SubmitPolledTransferEnd;
- }
- if (TransferCount != 1) {
- Status = STATUS_DEVICE_IO_ERROR;
- goto SubmitPolledTransferEnd;
- }
- SubmitPolledTransferEnd:
- return Status;
- }
- KSTATUS
- MusbpCancelTransfer (
- PVOID HostControllerContext,
- PVOID EndpointContext,
- PUSB_TRANSFER_INTERNAL Transfer,
- PVOID TransferContext
- )
- /*++
- Routine Description:
- This routine submits attempts to cancel a transfer that was previously
- submitted for execution.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- EndpointContext - Supplies the context pointer provided to the USB core by
- the host controller when the endpoint was created.
- Transfer - Supplies a pointer to the USB transfer to execute.
- TransferContext - Supplies the pointer provided to the USB core by the host
- controller when the transfer was created.
- Return Value:
- STATUS_SUCCESS if the transfer was successfully removed from the hardware
- queue.
- STATUS_TOO_LATE if the transfer had already completed.
- Other failure codes if the transfer could not be cancelled but has not yet
- completed.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- UCHAR HardwareIndex;
- PMUSB_TRANSFER MusbTransfer;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- KSTATUS Status;
- PMUSB_TRANSFER_SET TransferSet;
- Controller = HostControllerContext;
- SoftEndpoint = EndpointContext;
- TransferSet = TransferContext;
- MusbpAcquireLock(Controller);
- HardwareIndex = SoftEndpoint->HardwareIndex;
- HardEndpoint = &(Controller->Endpoints[HardwareIndex]);
- if (TransferSet->ListEntry.Next == NULL) {
- Status = STATUS_TOO_LATE;
- goto CancelTransferEnd;
- }
- //
- // If the transfer hasn't even started yet, then this is super easy.
- //
- ASSERT(TransferSet->ListEntry.Next != NULL);
- if (HardEndpoint->TransferList.Next != &(TransferSet->ListEntry)) {
- ASSERT(TransferSet->CurrentIndex == 0);
- } else {
- ASSERT(TransferSet->CurrentIndex < TransferSet->Count);
- MusbTransfer = &(TransferSet->Transfers[TransferSet->CurrentIndex]);
- MusbpAbortTransfer(Controller, HardwareIndex, MusbTransfer);
- MusbpUpdateDataToggle(Controller, TransferSet);
- }
- LIST_REMOVE(&(TransferSet->ListEntry));
- TransferSet->ListEntry.Next = NULL;
- ASSERT(SoftEndpoint->InFlight != 0);
- SoftEndpoint->InFlight -= 1;
- //
- // If the hardware endpoint has another transfer to do, kick that off now.
- //
- if (!LIST_EMPTY(&(HardEndpoint->TransferList))) {
- MusbpExecuteNextTransfer(Controller, HardEndpoint);
- }
- Status = STATUS_SUCCESS;
- CancelTransferEnd:
- if (KSUCCESS(Status)) {
- Transfer->Public.Status = STATUS_OPERATION_CANCELLED;
- Transfer->Public.Error = UsbErrorTransferCancelled;
- UsbHostProcessCompletedTransfer(TransferSet->UsbTransfer);
- }
- MusbpReleaseLock(Controller);
- return Status;
- }
- KSTATUS
- MusbpGetRootHubStatus (
- PVOID HostControllerContext,
- PUSB_HUB_STATUS HubStatus
- )
- /*++
- Routine Description:
- This routine queries the host controller for the status of the root hub.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- HubStatus - Supplies a pointer where the host controller should fill out
- the root hub status.
- Return Value:
- STATUS_SUCCESS if the hub status was successfully queried.
- Failure codes if the status could not be queried.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- PUSB_PORT_STATUS PortStatus;
- USHORT SoftwareStatus;
- USHORT Value;
- Controller = HostControllerContext;
- PortStatus = &(HubStatus->PortStatus[0]);
- SoftwareStatus = 0;
- Value = MUSB_READ8(Controller, MusbPower);
- if ((Value & MUSB_POWER_HIGH_SPEED) != 0) {
- SoftwareStatus = USB_PORT_STATUS_ENABLED | USB_PORT_STATUS_CONNECTED;
- HubStatus->PortDeviceSpeed[0] = UsbDeviceSpeedHigh;
- } else {
- Value = MUSB_READ8(Controller, MusbDeviceControl);
- if ((Value & MUSB_DEVICE_CONTROL_FULL_SPEED) != 0) {
- SoftwareStatus = USB_PORT_STATUS_ENABLED |
- USB_PORT_STATUS_CONNECTED;
- HubStatus->PortDeviceSpeed[0] = UsbDeviceSpeedFull;
- } else if ((Value & MUSB_DEVICE_CONTROL_LOW_SPEED) != 0) {
- SoftwareStatus = USB_PORT_STATUS_ENABLED |
- USB_PORT_STATUS_CONNECTED;
- HubStatus->PortDeviceSpeed[0] = UsbDeviceSpeedLow;
- }
- }
- PortStatus->Change |= SoftwareStatus ^ PortStatus->Status;
- PortStatus->Status = SoftwareStatus;
- return STATUS_SUCCESS;
- }
- KSTATUS
- MusbpSetRootHubStatus (
- PVOID HostControllerContext,
- PUSB_HUB_STATUS HubStatus
- )
- /*++
- Routine Description:
- This routine sets the state of the root hub in the USB host controller. It
- looks at the status change bits for each port in order to determine what
- needs to be set.
- Arguments:
- HostControllerContext - Supplies the context pointer passed to the USB core
- when the controller was created. This is used to identify the USB host
- controller to the host controller driver.
- HubStatus - Supplies a pointer to the status that should be set in the root
- hub.
- Return Value:
- STATUS_SUCCESS if the hub state was successfully programmed into the device.
- Failure codes if the status could not be set.
- --*/
- {
- PMUSB_CONTROLLER Controller;
- PUSB_PORT_STATUS PortStatus;
- UCHAR Power;
- Controller = HostControllerContext;
- PortStatus = &(HubStatus->PortStatus[0]);
- if ((PortStatus->Change & USB_PORT_STATUS_CHANGE_ENABLED) != 0) {
- PortStatus->Change &= ~USB_PORT_STATUS_CHANGE_ENABLED;
- }
- if ((PortStatus->Change & USB_PORT_STATUS_CHANGE_RESET) != 0) {
- if ((PortStatus->Status & USB_HUB_PORT_STATUS_RESET) != 0) {
- Power = MUSB_READ8(Controller, MusbPower);
- Power |= MUSB_POWER_RESET;
- MUSB_WRITE8(Controller, MusbPower, Power);
- HlBusySpin(20 * 1000);
- Power &= ~MUSB_POWER_RESET;
- MUSB_WRITE8(Controller, MusbPower, Power);
- }
- PortStatus->Change &= ~USB_PORT_STATUS_CHANGE_RESET;
- }
- return STATUS_SUCCESS;
- }
- VOID
- MusbpProcessUsbInterrupts (
- PMUSB_CONTROLLER Controller,
- UCHAR UsbInterrupts
- )
- /*++
- Routine Description:
- This routine handles incoming general USB interrupts.
- Arguments:
- Controller - Supplies a pointer to the controller.
- UsbInterrupts - Supplies the USB interrupts that occurred.
- Return Value:
- None.
- --*/
- {
- UCHAR DeviceControl;
- ASSERT(KeGetRunLevel() == RunLevelDispatch);
- MusbpAcquireLock(Controller);
- if ((UsbInterrupts & MUSB_USB_INTERRUPT_DISCONNECT) != 0) {
- Controller->Connected = FALSE;
- MusbpFailAllTransfers(Controller);
- UsbHostNotifyPortChange(Controller->UsbCoreHandle);
- }
- if ((UsbInterrupts & MUSB_USB_INTERRUPT_CONNECT) != 0) {
- Controller->Connected = TRUE;
- UsbHostNotifyPortChange(Controller->UsbCoreHandle);
- }
- //
- // If there was a VBUS error, just try to power the session back up.
- //
- if ((UsbInterrupts & MUSB_USB_INTERRUPT_VBUS_ERROR) != 0) {
- DeviceControl = MUSB_READ8(Controller, MusbDeviceControl);
- DeviceControl |= MUSB_DEVICE_CONTROL_SESSION;
- MUSB_WRITE8(Controller, MusbDeviceControl, DeviceControl);
- }
- MusbpReleaseLock(Controller);
- return;
- }
- VOID
- MusbpProcessEndpointInterrupts (
- PMUSB_CONTROLLER Controller,
- ULONG EndpointInterrupts
- )
- /*++
- Routine Description:
- This routine handles incoming USB endpoint interrupts.
- Arguments:
- Controller - Supplies a pointer to the controller.
- EndpointInterrupts - Supplies the endpoint interrupts that occurred.
- Return Value:
- None.
- --*/
- {
- PMUSB_HARD_ENDPOINT HardEndpoint;
- UCHAR HardwareIndex;
- USHORT Interrupts;
- BOOL StartNextTransfer;
- PMUSB_TRANSFER_SET TransferSet;
- //
- // Combine the TX and RX interrupts into one.
- //
- Interrupts = (EndpointInterrupts >> 16) | EndpointInterrupts;
- MusbpAcquireLock(Controller);
- while (Interrupts != 0) {
- HardwareIndex = RtlCountTrailingZeros32(Interrupts);
- Interrupts &= ~(1 << HardwareIndex);
- HardEndpoint = &(Controller->Endpoints[HardwareIndex]);
- //
- // Process a completed transfer. If this caused the entire set to
- // complete, then send the transfer back to USB core.
- //
- if (!LIST_EMPTY(&(HardEndpoint->TransferList))) {
- TransferSet = MusbpProcessCompletedTransfer(Controller,
- HardwareIndex,
- &StartNextTransfer);
- if (TransferSet != NULL) {
- UsbHostProcessCompletedTransfer(TransferSet->UsbTransfer);
- }
- //
- // Kick off the next thing to do on this endpoint.
- //
- if (StartNextTransfer != FALSE) {
- MusbpExecuteNextTransfer(Controller, HardEndpoint);
- }
- }
- }
- MusbpReleaseLock(Controller);
- return;
- }
- KSTATUS
- MusbpInitializeTransfer (
- PMUSB_CONTROLLER Controller,
- PMUSB_SOFT_ENDPOINT SoftEndpoint,
- PUSB_TRANSFER_INTERNAL Transfer,
- PMUSB_TRANSFER_SET TransferSet
- )
- /*++
- Routine Description:
- This routine initializes the necessary transfer structures in preparation
- for executing a new USB transfer. The hardware endpoint must be assigned
- prior to this routine.
- Arguments:
- Controller - Supplies a pointer to the controller.
- SoftEndpoint - Supplies a pointer to the endpoint.
- Transfer - Supplies a pointer to the USB transfer to execute.
- TransferSet - Supplies a pointer to the MUSB transfer set.
- Return Value:
- Status code.
- --*/
- {
- ULONG BufferOffset;
- ULONG DmaEndpoint;
- BOOL ForceShortTransfer;
- PMUSB_TRANSFER MusbTransfer;
- BOOL ShortTransfer;
- ULONG TransferIndex;
- ULONG TransferSize;
- BOOL Transmit;
- ASSERT(((Transfer->Type == UsbTransferTypeControl) &&
- (SoftEndpoint->HardwareIndex == 0)) ||
- ((Transfer->Type != UsbTransferTypeControl) &&
- (SoftEndpoint->HardwareIndex != 0)));
- ASSERT(Transfer->EndpointNumber == SoftEndpoint->EndpointNumber);
- Transmit = TRUE;
- Transfer->Public.Status = STATUS_SUCCESS;
- Transfer->Public.Error = UsbErrorNone;
- TransferSet->SoftEndpoint = SoftEndpoint;
- TransferSet->CurrentIndex = 0;
- DmaEndpoint = CPPI_USB_ENDPOINT_TO_DMA(SoftEndpoint->HardwareIndex);
- ForceShortTransfer = FALSE;
- if ((Transfer->Public.Flags &
- USB_TRANSFER_FLAG_FORCE_SHORT_TRANSFER) != 0) {
- ForceShortTransfer = TRUE;
- }
- //
- // Go around and fill out the transfers. Make sure the data transfer end
- // with a short transfer if required and that zero-length transfers are
- // allowed.
- //
- ShortTransfer = FALSE;
- TransferIndex = 0;
- BufferOffset = 0;
- MusbTransfer = &(TransferSet->Transfers[0]);
- while ((BufferOffset < Transfer->Public.Length) ||
- ((ShortTransfer == FALSE) &&
- ((Transfer->Public.Length == 0) ||
- (ForceShortTransfer != FALSE)))) {
- //
- // If this is a control transfer on the first packet, it's a setup
- // packet.
- //
- if ((BufferOffset == 0) && (SoftEndpoint->HardwareIndex == 0)) {
- ASSERT(Transfer->Public.Length >= sizeof(USB_SETUP_PACKET));
- MusbTransfer->Flags = MUSB_TRANSFER_OUT | MUSB_TRANSFER_SETUP;
- MusbTransfer->Size = sizeof(USB_SETUP_PACKET);
- } else {
- TransferSize = Transfer->Public.Length - BufferOffset;
- if (TransferSize < SoftEndpoint->MaxPayload) {
- ShortTransfer = TRUE;
- } else {
- TransferSize = SoftEndpoint->MaxPayload;
- }
- MusbTransfer->Size = TransferSize;
- MusbTransfer->Flags = 0;
- if (Transfer->Public.Direction == UsbTransferDirectionOut) {
- MusbTransfer->Flags |= MUSB_TRANSFER_OUT;
- Transmit = TRUE;
- if ((SoftEndpoint->Control & MUSB_TX_CONTROL_DMA_ENABLE) != 0) {
- MusbTransfer->Flags |= MUSB_TRANSFER_DMA;
- }
- } else {
- Transmit = FALSE;
- if ((SoftEndpoint->Control & MUSB_RX_CONTROL_DMA_ENABLE) != 0) {
- MusbTransfer->Flags |= MUSB_TRANSFER_DMA;
- }
- }
- }
- if (MusbTransfer->Size != 0) {
- MusbTransfer->BufferVirtual = Transfer->Public.Buffer +
- BufferOffset;
- MusbTransfer->BufferPhysical =
- Transfer->Public.BufferPhysicalAddress +
- BufferOffset;
- } else {
- MusbTransfer->BufferVirtual = NULL;
- MusbTransfer->BufferPhysical = 0;
- }
- //
- // Initialize the DMA descriptor if there is one.
- //
- if (MusbTransfer->DmaData.Descriptor != NULL) {
- ASSERT(SoftEndpoint->HardwareIndex != 0);
- CppiInitializeDescriptor(Controller->CppiDma,
- &(MusbTransfer->DmaData),
- DmaEndpoint,
- Transmit,
- MusbTransfer->BufferPhysical,
- MusbTransfer->Size);
- }
- BufferOffset += MusbTransfer->Size;
- MusbTransfer += 1;
- TransferIndex += 1;
- }
- //
- // Add the status phase if needed. The status phase always has the opposite
- // direction of the data phase.
- //
- if (SoftEndpoint->HardwareIndex == 0) {
- MusbTransfer->Flags = MUSB_TRANSFER_STATUS;
- if (Transfer->Public.Direction == UsbTransferDirectionIn) {
- MusbTransfer->Flags |= MUSB_TRANSFER_OUT;
- }
- MusbTransfer->Size = 0;
- MusbTransfer->BufferVirtual = NULL;
- MusbTransfer->BufferPhysical = 0;
- TransferIndex += 1;
- }
- ASSERT(TransferIndex <= TransferSet->MaxCount);
- TransferSet->Count = TransferIndex;
- TransferSet->UsbTransfer = Transfer;
- return STATUS_SUCCESS;
- }
- VOID
- MusbpExecuteNextTransfer (
- PMUSB_CONTROLLER Controller,
- PMUSB_HARD_ENDPOINT HardEndpoint
- )
- /*++
- Routine Description:
- This routine begins the next transfer on the given endpoint. This routine
- assumes the controller lock is already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- HardEndpoint - Supplies a pointer to the endpoint to execute a transfer on.
- Return Value:
- None.
- --*/
- {
- USHORT Control;
- UCHAR HardwareIndex;
- ULONG Register;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- PMUSB_TRANSFER Transfer;
- PMUSB_TRANSFER_SET TransferSet;
- if (LIST_EMPTY(&(HardEndpoint->TransferList))) {
- return;
- }
- TransferSet = LIST_VALUE(HardEndpoint->TransferList.Next,
- MUSB_TRANSFER_SET,
- ListEntry);
- SoftEndpoint = TransferSet->SoftEndpoint;
- HardwareIndex = SoftEndpoint->HardwareIndex;
- MusbpConfigureHardwareEndpoint(Controller, SoftEndpoint);
- Transfer = &(TransferSet->Transfers[TransferSet->CurrentIndex]);
- //
- // In DMA mode, enqueue the packet into the DMA controller. This actually
- // kicks off the DMA.
- //
- if ((Transfer->Flags & MUSB_TRANSFER_DMA) != 0) {
- ASSERT(Transfer->DmaData.Descriptor != NULL);
- CppiSubmitDescriptor(Controller->CppiDma, &(Transfer->DmaData));
- } else {
- //
- // If this is an out transfer, fill the FIFO with the data.
- //
- if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- MusbpWriteFifo(Controller,
- HardwareIndex,
- Transfer->BufferVirtual,
- Transfer->Size);
- }
- }
- //
- // Enable interrupts.
- //
- if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- Controller->TxInterruptEnable |= 1 << HardwareIndex;
- MUSB_WRITE16(Controller,
- MusbInterruptEnableTx,
- Controller->TxInterruptEnable);
- } else {
- Controller->RxInterruptEnable |= 1 << HardwareIndex;
- MUSB_WRITE16(Controller,
- MusbInterruptEnableRx,
- Controller->RxInterruptEnable);
- }
- //
- // For outbound DMA transfers, there's no need to write the TX ready bit,
- // so just return.
- //
- if ((Transfer->Flags & (MUSB_TRANSFER_OUT | MUSB_TRANSFER_DMA)) ==
- (MUSB_TRANSFER_OUT | MUSB_TRANSFER_DMA)) {
- return;
- }
- //
- // Kick off the transfer by writing to the control register.
- //
- Control = SoftEndpoint->Control;
- if (HardwareIndex == 0) {
- if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- Control |= MUSB_EP0_CONTROL_TX_PACKET_READY;
- } else {
- Control |= MUSB_EP0_CONTROL_REQUEST_PACKET;
- }
- if ((Transfer->Flags & MUSB_TRANSFER_SETUP) != 0) {
- Control |= MUSB_EP0_CONTROL_SETUP_PACKET;
- } else if ((Transfer->Flags & MUSB_TRANSFER_STATUS) != 0) {
- Control |= MUSB_EP0_CONTROL_STATUS_PACKET;
- }
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus, 0);
- } else if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- Control |= MUSB_TX_CONTROL_PACKET_READY;
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus, HardwareIndex);
- } else {
- Control |= MUSB_RX_CONTROL_REQUEST_PACKET;
- Register = MUSB_ENDPOINT_CONTROL(MusbRxControlStatus, HardwareIndex);
- }
- //
- // Only write the low byte of control.
- //
- MUSB_WRITE8(Controller, Register, Control);
- return;
- }
- PMUSB_TRANSFER_SET
- MusbpProcessCompletedTransfer (
- PMUSB_CONTROLLER Controller,
- UCHAR HardwareIndex,
- PBOOL TransferCompleted
- )
- /*++
- Routine Description:
- This routine processes a completed USB transfer on a hardware endpoint.
- This routine assumes the controller lock is already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- HardwareIndex - Supplies the hardware endpoint index of the transfer that
- completed.
- TransferCompleted - Supplies a pointer where a boolean will be returned
- indicating if this transfer actually completed (TRUE) and the next
- transfer should be executed, or if this transfer is still going (FALSE).
- Return Value:
- Returns a pointer to the transfer set that just completed and was removed.
- NULL if the current transfer is still in progress.
- --*/
- {
- BOOL CompleteSet;
- USHORT Control;
- ULONG ControlRegister;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- ULONG Register;
- ULONG RxCount;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- PMUSB_TRANSFER Transfer;
- PMUSB_TRANSFER_SET TransferSet;
- PUSB_TRANSFER UsbTransfer;
- *TransferCompleted = FALSE;
- CompleteSet = FALSE;
- HardEndpoint = &(Controller->Endpoints[HardwareIndex]);
- ASSERT(!LIST_EMPTY(&(HardEndpoint->TransferList)));
- TransferSet = LIST_VALUE(HardEndpoint->TransferList.Next,
- MUSB_TRANSFER_SET,
- ListEntry);
- ASSERT(TransferSet->CurrentIndex < TransferSet->Count);
- SoftEndpoint = TransferSet->SoftEndpoint;
- Transfer = &(TransferSet->Transfers[TransferSet->CurrentIndex]);
- UsbTransfer = &(TransferSet->UsbTransfer->Public);
- //
- // Handle a completed control transfer if this is endpoint zero.
- //
- if (HardwareIndex == 0) {
- ControlRegister = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus,
- HardwareIndex);
- Control = MUSB_READ16(Controller, ControlRegister);
- //
- // If the transfer's not actually finished, the interrupt was spurious
- // or stale.
- //
- if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- if ((Control & MUSB_EP0_CONTROL_TX_PACKET_READY) != 0) {
- return NULL;
- }
- } else {
- if ((Control &
- (MUSB_EP0_CONTROL_RX_PACKET_READY |
- MUSB_EP0_CONTROL_ERROR_MASK)) == 0) {
- return NULL;
- }
- }
- //
- // For IN transfers, read the data from the FIFO.
- //
- if (((Transfer->Flags & MUSB_TRANSFER_OUT) == 0) &&
- ((Control & MUSB_EP0_CONTROL_RX_PACKET_READY) != 0)) {
- Register = MUSB_ENDPOINT_CONTROL(MusbCount, HardwareIndex);
- RxCount = MUSB_READ16(Controller, Register);
- ASSERT(RxCount <= Transfer->Size);
- if (RxCount >= Transfer->Size) {
- RxCount = Transfer->Size;
- }
- UsbTransfer->LengthTransferred += RxCount;
- MusbpReadFifo(Controller,
- HardwareIndex,
- Transfer->BufferVirtual,
- RxCount);
- //
- // Handle a shorted transfer.
- //
- if (RxCount < Transfer->Size) {
- if ((UsbTransfer->Flags &
- USB_TRANSFER_FLAG_NO_SHORT_TRANSFERS) != 0) {
- if (KSUCCESS(UsbTransfer->Status)) {
- UsbTransfer->Status = STATUS_DATA_LENGTH_MISMATCH;
- UsbTransfer->Error = UsbErrorShortPacket;
- }
- }
- //
- // Move to the status phase (or one before to account for the
- // increment at the end of the function).
- //
- ASSERT(TransferSet->CurrentIndex < TransferSet->Count - 1);
- TransferSet->CurrentIndex = TransferSet->Count - 2;
- }
- }
- //
- // Fail the transfer if there was an error.
- //
- if ((Control & MUSB_EP0_CONTROL_ERROR_MASK) != 0) {
- CompleteSet = TRUE;
- UsbTransfer->Status = STATUS_DEVICE_IO_ERROR;
- //
- // Write those error bits to clear them, and perform any FIFO
- // cleanup needed.
- //
- MUSB_WRITE16(Controller, ControlRegister, Control);
- MusbpAbortTransfer(Controller, HardwareIndex, Transfer);
- if ((Control & MUSB_EP0_CONTROL_ERROR) != 0) {
- UsbTransfer->Error = UsbErrorTransferCrcOrTimeoutError;
- } else if ((Control & MUSB_EP0_CONTROL_RX_STALL) != 0) {
- UsbTransfer->Error = UsbErrorTransferStalled;
- } else if ((Control & MUSB_EP0_CONTROL_NAK_TIMEOUT) != 0) {
- UsbTransfer->Error = UsbErrorTransferNakReceived;
- } else {
- ASSERT(FALSE);
- }
- } else {
- if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- UsbTransfer->LengthTransferred += Transfer->Size;
- }
- }
- //
- // The data toggle bit in the soft endpoint does not need updating
- // because it will never migrate to another hardware endpoint, and
- // a control transfer is never broken up by other requests.
- //
- //
- // Handle a completed OUT transfer.
- //
- } else if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- ControlRegister = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus,
- HardwareIndex);
- Control = MUSB_READ16(Controller, ControlRegister);
- //
- // In DMA mode, the packet ready and FIFO full bits might still be set
- // (even though the DMA transfer supposedly completed). The original
- // code spun here waiting for those bits to clear, but that turned out
- // to be a very significant portion of time. Instead it seems to be
- // okay to clear the control register, and then spin on seeing the
- // descriptor show up in the CPPI completion queue.
- //
- //
- // In non-DMA mode, there's a FIFO empty interrupt, so if the FIFO is
- // not currently empty just wait for that.
- //
- if ((Transfer->Flags & MUSB_TRANSFER_DMA) == 0) {
- if ((Control & MUSB_TX_CONTROL_PACKET_READY) != 0) {
- return NULL;
- }
- }
- if ((Control & MUSB_TX_CONTROL_ERROR_MASK) != 0) {
- CompleteSet = TRUE;
- UsbTransfer->Status = STATUS_DEVICE_IO_ERROR;
- //
- // Write those error bits to clear them, and perform any FIFO
- // cleanup needed.
- //
- MUSB_WRITE16(Controller, ControlRegister, Control);
- MusbpAbortTransfer(Controller, HardwareIndex, Transfer);
- if ((Control & MUSB_TX_CONTROL_ERROR) != 0) {
- UsbTransfer->Error = UsbErrorTransferCrcOrTimeoutError;
- } else if ((Control & MUSB_TX_CONTROL_RX_STALL) != 0) {
- UsbTransfer->Error = UsbErrorTransferStalled;
- } else if ((Control & MUSB_TX_CONTROL_NAK_TIMEOUT) != 0) {
- UsbTransfer->Error = UsbErrorTransferNakReceived;
- } else {
- ASSERT(FALSE);
- }
- } else {
- UsbTransfer->LengthTransferred += Transfer->Size;
- if ((Transfer->Flags & MUSB_TRANSFER_DMA) != 0) {
- CppiReapCompletedDescriptor(Controller->CppiDma,
- &(Transfer->DmaData),
- NULL);
- }
- }
- //
- // Update the data toggle bit.
- //
- SoftEndpoint->Control = (SoftEndpoint->Control &
- ~MUSB_TX_CONTROL_DATA_TOGGLE) |
- (Control & MUSB_TX_CONTROL_DATA_TOGGLE);
- //
- // Handle a completed IN transfer.
- //
- } else {
- ControlRegister = MUSB_ENDPOINT_CONTROL(MusbRxControlStatus,
- HardwareIndex);
- Control = MUSB_READ16(Controller, ControlRegister);
- //
- // Incoming NAK timeouts aren't actually errors (except on isochronous
- // channels.
- //
- if ((Control & MUSB_RX_CONTROL_DATA_ERROR_NAK_TIMEOUT) != 0) {
- if ((TransferSet->UsbTransfer->Type !=
- UsbTransferTypeIsochronous) &&
- (SoftEndpoint->Interval == 0)) {
- Control &= ~MUSB_RX_CONTROL_DATA_ERROR_NAK_TIMEOUT;
- MUSB_WRITE16(Controller, ControlRegister, Control);
- return NULL;
- }
- }
- //
- // Handle errors first.
- //
- if ((Control & MUSB_RX_CONTROL_ERROR_MASK) != 0) {
- CompleteSet = TRUE;
- UsbTransfer->Status = STATUS_DEVICE_IO_ERROR;
- //
- // Write those error bits to clear them, and perform any FIFO
- // cleanup needed.
- //
- MUSB_WRITE16(Controller, ControlRegister, Control);
- MusbpAbortTransfer(Controller, HardwareIndex, Transfer);
- if ((Control & MUSB_RX_CONTROL_ERROR) != 0) {
- UsbTransfer->Error = UsbErrorTransferCrcOrTimeoutError;
- } else if ((Control & MUSB_RX_CONTROL_RX_STALL) != 0) {
- UsbTransfer->Error = UsbErrorTransferStalled;
- } else if ((Control &
- MUSB_RX_CONTROL_DATA_ERROR_NAK_TIMEOUT) != 0) {
- if (TransferSet->UsbTransfer->Type ==
- UsbTransferTypeIsochronous) {
- UsbTransfer->Error = UsbErrorTransferCrcOrTimeoutError;
- } else {
- UsbTransfer->Error = UsbErrorTransferNakReceived;
- }
- } else {
- ASSERT(FALSE);
- }
- //
- // There are no errors. If the request packet flag is clear and either
- // this is DMA or the packet ready flag is set, go get the data.
- //
- } else if (((Control & MUSB_RX_CONTROL_REQUEST_PACKET) == 0) &&
- (((Transfer->Flags & MUSB_TRANSFER_DMA) != 0) ||
- ((Control & MUSB_RX_CONTROL_PACKET_READY) != 0))) {
- Register = MUSB_ENDPOINT_CONTROL(MusbCount, HardwareIndex);
- if ((Transfer->Flags & MUSB_TRANSFER_DMA) != 0) {
- CppiReapCompletedDescriptor(Controller->CppiDma,
- &(Transfer->DmaData),
- &RxCount);
- ASSERT(RxCount <= Transfer->Size);
- } else {
- RxCount = MUSB_READ16(Controller, Register);
- //
- // If the RX count is more than the transfer size, then it means
- // the RX max packet size was programmed incorrectly.
- //
- ASSERT(RxCount <= Transfer->Size);
- if (RxCount >= Transfer->Size) {
- RxCount = Transfer->Size;
- }
- MusbpReadFifo(Controller,
- HardwareIndex,
- Transfer->BufferVirtual,
- RxCount);
- }
- UsbTransfer->LengthTransferred += RxCount;
- //
- // Account for a shorted transfer.
- //
- if (RxCount < Transfer->Size) {
- CompleteSet = TRUE;
- if ((UsbTransfer->Flags &
- USB_TRANSFER_FLAG_NO_SHORT_TRANSFERS) != 0) {
- UsbTransfer->Status = STATUS_DATA_LENGTH_MISMATCH;
- UsbTransfer->Error = UsbErrorShortPacket;
- }
- }
- }
- //
- // Update the data toggle bit.
- //
- SoftEndpoint->Control = (SoftEndpoint->Control &
- ~MUSB_RX_CONTROL_DATA_TOGGLE) |
- (Control & MUSB_RX_CONTROL_DATA_TOGGLE);
- }
- MUSB_WRITE16(Controller, ControlRegister, 0);
- *TransferCompleted = TRUE;
- TransferSet->CurrentIndex += 1;
- if (TransferSet->CurrentIndex == TransferSet->Count) {
- CompleteSet = TRUE;
- }
- if (CompleteSet != FALSE) {
- LIST_REMOVE(&(TransferSet->ListEntry));
- TransferSet->ListEntry.Next = NULL;
- ASSERT(SoftEndpoint->InFlight != 0);
- SoftEndpoint->InFlight -= 1;
- } else {
- TransferSet = NULL;
- }
- return TransferSet;
- }
- VOID
- MusbpFailAllTransfers (
- PMUSB_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine completes all pending USB transfers, failing everything with
- a device not connected error. This routine assumes the controller lock is
- already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Return Value:
- None.
- --*/
- {
- PMUSB_HARD_ENDPOINT HardEndpoint;
- ULONG HardwareIndex;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- PMUSB_TRANSFER Transfer;
- PMUSB_TRANSFER_SET TransferSet;
- PUSB_TRANSFER_INTERNAL UsbTransfer;
- for (HardwareIndex = 0;
- HardwareIndex < Controller->EndpointCount;
- HardwareIndex += 1) {
- HardEndpoint = &(Controller->Endpoints[HardwareIndex]);
- if (LIST_EMPTY(&(HardEndpoint->TransferList))) {
- continue;
- }
- //
- // Kill the first transfer, which is the tricky one since it's in the
- // hardware.
- //
- TransferSet = LIST_VALUE(HardEndpoint->TransferList.Next,
- MUSB_TRANSFER_SET,
- ListEntry);
- SoftEndpoint = TransferSet->SoftEndpoint;
- Transfer = &(TransferSet->Transfers[TransferSet->CurrentIndex]);
- MusbpAbortTransfer(Controller, HardwareIndex, Transfer);
- MusbpUpdateDataToggle(Controller, TransferSet);
- UsbTransfer = TransferSet->UsbTransfer;
- UsbTransfer->Public.Status = STATUS_DEVICE_IO_ERROR;
- UsbTransfer->Public.Error = UsbErrorTransferDeviceNotConnected;
- LIST_REMOVE(&(TransferSet->ListEntry));
- TransferSet->ListEntry.Next = NULL;
- ASSERT(SoftEndpoint->InFlight != 0);
- SoftEndpoint->InFlight -= 1;
- UsbHostProcessCompletedTransfer(UsbTransfer);
- //
- // Now process all the other transfers, which were never even started.
- //
- while (!LIST_EMPTY(&(HardEndpoint->TransferList))) {
- TransferSet = LIST_VALUE(HardEndpoint->TransferList.Next,
- MUSB_TRANSFER_SET,
- ListEntry);
- UsbTransfer = TransferSet->UsbTransfer;
- UsbTransfer->Public.Status = STATUS_DEVICE_IO_ERROR;
- UsbTransfer->Public.Error = UsbErrorTransferDeviceNotConnected;
- LIST_REMOVE(&(TransferSet->ListEntry));
- TransferSet->ListEntry.Next = NULL;
- ASSERT(SoftEndpoint->InFlight != 0);
- SoftEndpoint->InFlight -= 1;
- UsbHostProcessCompletedTransfer(UsbTransfer);
- }
- }
- return;
- }
- VOID
- MusbpConfigureFifo (
- PMUSB_CONTROLLER Controller,
- PMUSB_FIFO_CONFIGURATION Configuration,
- PULONG Offset
- )
- /*++
- Routine Description:
- This routine configures a hardware endpoint FIFO.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Configuration - Supplies the configuration to set.
- Offset - Supplies the current FIFO region offset. On output, this will be
- advanced.
- Return Value:
- None.
- --*/
- {
- ULONG CurrentOffset;
- UCHAR Endpoint;
- UCHAR SizeValue;
- ASSERT(Configuration->Endpoint != 0);
- CurrentOffset = *Offset;
- Endpoint = Configuration->Endpoint;
- *Offset += Configuration->MaxPacketSize;
- //
- // The size register is logarithmic, with the max packet size being
- // 2^(sz+3) for single buffer mode, and 2^(sz+4) for double buffer
- // mode.
- //
- SizeValue = RtlCountTrailingZeros32(Configuration->MaxPacketSize) - 3;
- if ((Configuration->Direction == MusbEndpointTx) ||
- (Configuration->Direction == MusbEndpointTxRx)) {
- ASSERT(Controller->Endpoints[Endpoint].TxFifoSize == 0);
- Controller->Endpoints[Endpoint].TxFifoSize =
- Configuration->MaxPacketSize;
- MusbpWriteIndexed8(Controller, Endpoint, MusbTxFifoSize, SizeValue);
- //
- // The FIFO address register is in units of 8 bytes.
- //
- MusbpWriteIndexed16(Controller,
- Endpoint,
- MusbTxFifoAddress,
- CurrentOffset >> 3);
- }
- if ((Configuration->Direction == MusbEndpointRx) ||
- (Configuration->Direction == MusbEndpointTxRx)) {
- ASSERT(Controller->Endpoints[Endpoint].RxFifoSize == 0);
- Controller->Endpoints[Endpoint].RxFifoSize =
- Configuration->MaxPacketSize;
- MusbpWriteIndexed8(Controller, Endpoint, MusbRxFifoSize, SizeValue);
- MusbpWriteIndexed16(Controller,
- Endpoint,
- MusbRxFifoAddress,
- CurrentOffset >> 3);
- }
- return;
- }
- VOID
- MusbpAbortTransfer (
- PMUSB_CONTROLLER Controller,
- UCHAR HardwareIndex,
- PMUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine aborts a transmit operation by flushing FIFOs and DMA.
- Arguments:
- Controller - Supplies a pointer to the controller.
- HardwareIndex - Supplies the hardware endpoint index to abort.
- Transfer - Supplies the transfer that's stuck in there.
- Return Value:
- None.
- --*/
- {
- USHORT Control;
- ULONG ControlRegister;
- KSTATUS Status;
- if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- //
- // Flush twice as required for double buffering.
- //
- MusbpFlushFifo(Controller, HardwareIndex, TRUE);
- MusbpFlushFifo(Controller, HardwareIndex, TRUE);
- if ((Transfer->Flags & MUSB_TRANSFER_DMA) != 0) {
- ControlRegister = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus,
- HardwareIndex);
- Control = MUSB_READ16(Controller, ControlRegister);
- Control &= ~MUSB_TX_CONTROL_DMA_ENABLE;
- MUSB_WRITE16(Controller, ControlRegister, Control);
- ASSERT(Transfer->DmaData.Descriptor != NULL);
- Status = CppiTearDownDescriptor(Controller->CppiDma,
- &(Transfer->DmaData));
- ASSERT(KSUCCESS(Status));
- }
- } else {
- if (HardwareIndex == 0) {
- ControlRegister = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus, 0);
- } else {
- ControlRegister = MUSB_ENDPOINT_CONTROL(MusbRxControlStatus,
- HardwareIndex);
- }
- //
- // Clear the auto request flag from the high byte of the control
- // register.
- //
- Control = MUSB_READ8(Controller, ControlRegister + 1);
- Control &= ~(MUSB_RX_CONTROL_AUTO_REQUEST >> BITS_PER_BYTE);
- MUSB_WRITE8(Controller, ControlRegister + 1, Control);
- if ((Transfer->Flags & MUSB_TRANSFER_DMA) != 0) {
- //
- // Clear the request packet and DMA enable flags. If a packet
- // squeaked in, flush the FIFO. Then tear down the DMA descriptor.
- //
- Control = MUSB_READ16(Controller, ControlRegister);
- Control &= ~(MUSB_RX_CONTROL_REQUEST_PACKET |
- MUSB_RX_CONTROL_DMA_ENABLE);
- MUSB_WRITE16(Controller, ControlRegister, Control);
- HlBusySpin(250);
- Control = MUSB_READ16(Controller, ControlRegister);
- if ((Control & MUSB_RX_CONTROL_PACKET_READY) != 0) {
- Control |= MUSB_RX_CONTROL_FLUSH_FIFO;
- }
- Control |= MUSB_RX_CONTROL_ERROR_MASK;
- MUSB_WRITE16(Controller, ControlRegister, Control);
- Status = CppiTearDownDescriptor(Controller->CppiDma,
- &(Transfer->DmaData));
- ASSERT(KSUCCESS(Status));
- //
- // Abort a non-DMA transfer.
- //
- } else {
- Control = MUSB_READ8(Controller, ControlRegister);
- Control &= ~MUSB_RX_CONTROL_REQUEST_PACKET;
- MUSB_WRITE8(Controller, ControlRegister, Control);
- HlBusySpin(250);
- MusbpFlushFifo(Controller, HardwareIndex, FALSE);
- MusbpFlushFifo(Controller, HardwareIndex, FALSE);
- MUSB_WRITE16(Controller, ControlRegister, 0);
- }
- }
- return;
- }
- VOID
- MusbpConfigureHardwareEndpoint (
- PMUSB_CONTROLLER Controller,
- PMUSB_SOFT_ENDPOINT SoftEndpoint
- )
- /*++
- Routine Description:
- This routine sets up the hardware endpoint associated with the given
- software endpoint in preparation for transfer submission. This routine
- assumes the controller lock is already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- SoftEndpoint - Supplies a pointer to the software endpoint structure.
- Return Value:
- None.
- --*/
- {
- USHORT Control;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- UCHAR HardIndex;
- ULONG Register;
- HardIndex = SoftEndpoint->HardwareIndex;
- HardEndpoint = &(Controller->Endpoints[HardIndex]);
- //
- // If the hardware endpoint is already set up from last time, then there's
- // no need to reprogram it.
- //
- if (HardEndpoint->CurrentEndpoint == SoftEndpoint) {
- //
- // Just write the control register.
- //
- if (SoftEndpoint->Direction == UsbTransferDirectionOut) {
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus, HardIndex);
- } else {
- Register = MUSB_ENDPOINT_CONTROL(MusbRxControlStatus, HardIndex);
- }
- MUSB_WRITE16(Controller, Register, SoftEndpoint->Control);
- return;
- }
- if (SoftEndpoint->Direction == UsbTransferDirectionOut) {
- Controller->TxInterruptEnable &= ~(1 << HardIndex);
- MUSB_WRITE16(Controller,
- MusbInterruptEnableTx,
- Controller->TxInterruptEnable);
- //
- // Write the control registers.
- //
- Register = MUSB_ENDPOINT_CONTROL(MusbTxMaxPacketSize, HardIndex);
- MUSB_WRITE16(Controller, Register, SoftEndpoint->MaxPayload);
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus, HardIndex);
- if (SoftEndpoint->HardwareIndex == 0) {
- Control = SoftEndpoint->Control |
- MUSB_EP0_CONTROL_DATA_TOGGLE_WRITE;
- } else {
- Control = SoftEndpoint->Control | MUSB_TX_CONTROL_DATA_TOGGLE_WRITE;
- }
- MUSB_WRITE16(Controller, Register, Control);
- Register = MUSB_ENDPOINT_CONTROL(MusbTxType, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->Type);
- Register = MUSB_ENDPOINT_CONTROL(MusbTxInterval, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->Interval);
- //
- // Write the setup registers.
- //
- Register = MUSB_ENDPOINT_SETUP(MusbTxFunctionAddress, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->Device);
- Register = MUSB_ENDPOINT_SETUP(MusbTxHubAddress, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->HubAddress);
- Register = MUSB_ENDPOINT_SETUP(MusbTxHubPort, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->HubPort);
- //
- // For the control endpoint, initialize both TX and RX setup registers.
- //
- if (SoftEndpoint->HardwareIndex == 0) {
- Register = MUSB_ENDPOINT_SETUP(MusbRxFunctionAddress, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->Device);
- Register = MUSB_ENDPOINT_SETUP(MusbRxHubAddress, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->HubAddress);
- Register = MUSB_ENDPOINT_SETUP(MusbRxHubPort, HardIndex);
- }
- } else {
- ASSERT(SoftEndpoint->Direction == UsbTransferDirectionIn);
- Controller->RxInterruptEnable &= ~(1 << HardIndex);
- MUSB_WRITE16(Controller,
- MusbInterruptEnableRx,
- Controller->RxInterruptEnable);
- //
- // Write the control registers.
- //
- Register = MUSB_ENDPOINT_CONTROL(MusbRxMaxPacketSize, HardIndex);
- MUSB_WRITE16(Controller, Register, SoftEndpoint->MaxPayload);
- Register = MUSB_ENDPOINT_CONTROL(MusbRxControlStatus, HardIndex);
- Control = SoftEndpoint->Control | MUSB_RX_CONTROL_DATA_TOGGLE_WRITE;
- MUSB_WRITE16(Controller, Register, Control);
- Register = MUSB_ENDPOINT_CONTROL(MusbRxType, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->Type);
- Register = MUSB_ENDPOINT_CONTROL(MusbRxInterval, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->Interval);
- //
- // Write the setup registers.
- //
- Register = MUSB_ENDPOINT_SETUP(MusbRxFunctionAddress, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->Device);
- Register = MUSB_ENDPOINT_SETUP(MusbRxHubAddress, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->HubAddress);
- Register = MUSB_ENDPOINT_SETUP(MusbRxHubPort, HardIndex);
- MUSB_WRITE8(Controller, Register, SoftEndpoint->HubPort);
- }
- HardEndpoint->CurrentEndpoint = SoftEndpoint;
- return;
- }
- VOID
- MusbpUpdateDataToggle (
- PMUSB_CONTROLLER Controller,
- PMUSB_TRANSFER_SET TransferSet
- )
- /*++
- Routine Description:
- This routine updates the data toggle bit in the control member of the soft
- endpoint corresponding to the given transfer set.
- Arguments:
- Controller - Supplies a pointer to the controller.
- TransferSet - Supplies a pointer to the transfer set. The current index
- transfer will be used to determine whether the transfer is IN or OUT.
- Return Value:
- None.
- --*/
- {
- USHORT Control;
- UCHAR HardwareIndex;
- ULONG Register;
- PMUSB_SOFT_ENDPOINT SoftEndpoint;
- PMUSB_TRANSFER Transfer;
- SoftEndpoint = TransferSet->SoftEndpoint;
- HardwareIndex = SoftEndpoint->HardwareIndex;
- Transfer = &(TransferSet->Transfers[TransferSet->CurrentIndex]);
- //
- // Update the data toggle.
- //
- if ((Transfer->Flags & MUSB_TRANSFER_OUT) != 0) {
- if (HardwareIndex != 0) {
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus,
- HardwareIndex);
- Control = MUSB_READ16(Controller, Register);
- SoftEndpoint->Control = (SoftEndpoint->Control &
- ~MUSB_TX_CONTROL_DATA_TOGGLE) |
- (Control & MUSB_TX_CONTROL_DATA_TOGGLE);
- }
- } else {
- Register = MUSB_ENDPOINT_CONTROL(MusbRxControlStatus,
- HardwareIndex);
- Control = MUSB_READ16(Controller, Register);
- SoftEndpoint->Control = (SoftEndpoint->Control &
- ~MUSB_RX_CONTROL_DATA_TOGGLE) |
- (Control & MUSB_RX_CONTROL_DATA_TOGGLE);
- }
- return;
- }
- VOID
- MusbpWriteFifo (
- PMUSB_CONTROLLER Controller,
- UCHAR EndpointIndex,
- PVOID Buffer,
- ULONG Size
- )
- /*++
- Routine Description:
- This routine writes the given buffer contents to the FIFO.
- Arguments:
- Controller - Supplies a pointer to the controller.
- EndpointIndex - Supplies the hardware endpoint number to write to.
- Buffer - Supplies a pointer to the data to write.
- Size - Supplies the number of bytes to write.
- Return Value:
- None.
- --*/
- {
- PUCHAR Bytes;
- ULONG Index;
- ULONG Register;
- Bytes = Buffer;
- Register = MUSB_FIFO_REGISTER(EndpointIndex);
- for (Index = 0; Index < Size; Index += 1) {
- MUSB_WRITE8(Controller, Register, Bytes[Index]);
- }
- return;
- }
- VOID
- MusbpReadFifo (
- PMUSB_CONTROLLER Controller,
- UCHAR EndpointIndex,
- PVOID Buffer,
- ULONG BufferSize
- )
- /*++
- Routine Description:
- This routine reads from the FIFO into the given buffer.
- Arguments:
- Controller - Supplies a pointer to the controller.
- EndpointIndex - Supplies the hardware endpoint number to read from.
- Buffer - Supplies a pointer where the read data will be returned..
- BufferSize - Supplies the number of bytes to read into the buffer.
- Return Value:
- None.
- --*/
- {
- PUCHAR Bytes;
- ULONG Index;
- ULONG Register;
- Bytes = Buffer;
- Register = MUSB_FIFO_REGISTER(EndpointIndex);
- for (Index = 0; Index < BufferSize; Index += 1) {
- Bytes[Index] = MUSB_READ8(Controller, Register);
- }
- MmSyncCacheRegion(Buffer, BufferSize);
- return;
- }
- VOID
- MusbpFlushFifo (
- PMUSB_CONTROLLER Controller,
- UCHAR HardwareIndex,
- BOOL HostOut
- )
- /*++
- Routine Description:
- This routine forcefully flushes the FIFO.
- Arguments:
- Controller - Supplies a pointer to the controller.
- HardwareIndex - Supplies the hardware endpoint number to write to.
- HostOut - Supplies a boolean indicating whether to flush the transmit FIFO
- (TRUE) or the receive FIFO (FALSE).
- Return Value:
- None.
- --*/
- {
- UCHAR Control;
- ULONG Register;
- if (HardwareIndex == 0) {
- //
- // If there's something in the FIFO, hit the red button.
- //
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus, 0);
- Control = MUSB_READ8(Controller, Register);
- if ((Control &
- (MUSB_EP0_CONTROL_TX_PACKET_READY |
- MUSB_EP0_CONTROL_RX_PACKET_READY)) != 0) {
- //
- // Just write the high byte of the control word.
- //
- Control = MUSB_EP0_CONTROL_FLUSH_FIFO >> 8;
- MUSB_WRITE8(Controller, Register + 1, Control);
- }
- } else if (HostOut != FALSE) {
- //
- // If the FIFO is not empty, flush it.
- //
- Register = MUSB_ENDPOINT_CONTROL(MusbTxControlStatus, HardwareIndex);
- Control = MUSB_READ8(Controller, Register);
- if ((Control & MUSB_TX_CONTROL_PACKET_READY) != 0) {
- Control |= MUSB_TX_CONTROL_FLUSH_FIFO | MUSB_TX_CONTROL_ERROR_MASK;
- MUSB_WRITE8(Controller, Register, Control);
- }
- } else {
- Register = MUSB_ENDPOINT_CONTROL(MusbRxControlStatus, HardwareIndex);
- Control = MUSB_READ8(Controller, Register);
- if ((Control & MUSB_RX_CONTROL_PACKET_READY) != 0) {
- Control |= MUSB_RX_CONTROL_FLUSH_FIFO | MUSB_RX_CONTROL_ERROR_MASK;
- MUSB_WRITE8(Controller, Register, Control);
- }
- }
- Controller->Endpoints[HardwareIndex].CurrentEndpoint = NULL;
- return;
- }
- VOID
- MusbpAssignEndpoint (
- PMUSB_CONTROLLER Controller,
- PMUSB_SOFT_ENDPOINT SoftEndpoint
- )
- /*++
- Routine Description:
- This routine assigns a software endpoint to a hardware endpoint. Ideally it
- tries to find one with no transfers on it already, and will try not to
- move endpoints if possible. This routine assumes the controller lock is
- already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- SoftEndpoint - Supplies a pointer to the endpoint to assign. On output, the
- hardware index of this endpoint will be set.
- Return Value:
- None.
- --*/
- {
- UCHAR Alternate;
- USHORT FifoSize;
- PMUSB_HARD_ENDPOINT HardEndpoint;
- ULONG Index;
- UCHAR SearchIndex;
- //
- // Control endpoints always go to hardware endpoint 0, by hardware mandate.
- //
- if ((SoftEndpoint->Type & MUSB_TXTYPE_PROTOCOL_MASK) ==
- MUSB_TXTYPE_PROTOCOL_CONTROL) {
- SoftEndpoint->HardwareIndex = 0;
- return;
- }
- //
- // If there are already transfers in flight on this endpoint, then it
- // cannot move as that would mess up the ordering of transfers on the bus.
- //
- if (SoftEndpoint->InFlight != 0) {
- ASSERT(SoftEndpoint->HardwareIndex != 0);
- return;
- }
- //
- // This endpoint is not a control endpoint. If its hardware index is not
- // yet assigned, pick a round-robin new one. Otherwise, start from the
- // previous one.
- //
- Alternate = 0;
- SearchIndex = SoftEndpoint->HardwareIndex;
- if (SearchIndex == 0) {
- SearchIndex = Controller->NextEndpointAssignment;
- Controller->NextEndpointAssignment += 1;
- if (Controller->NextEndpointAssignment == Controller->EndpointCount) {
- Controller->NextEndpointAssignment = 1;
- }
- }
- for (Index = 1; Index < Controller->EndpointCount; Index += 1) {
- ASSERT(SearchIndex != 0);
- HardEndpoint = &(Controller->Endpoints[SearchIndex]);
- if (SoftEndpoint->Direction == UsbTransferDirectionOut) {
- FifoSize = HardEndpoint->TxFifoSize;
- } else {
- FifoSize = HardEndpoint->RxFifoSize;
- }
- //
- // If the endpoint has the FIFO space, then this endpoint may work.
- //
- if (SoftEndpoint->MaxPayload <= FifoSize) {
- //
- // If this endpoint has no transfers on it, then definitely use it.
- //
- if (LIST_EMPTY(&(HardEndpoint->TransferList))) {
- SoftEndpoint->HardwareIndex = SearchIndex;
- return;
- }
- //
- // Otherwise, save the endpoint as a backup.
- //
- if (Alternate == 0) {
- Alternate = SearchIndex;
- //
- // This endpoint is moving off what it was before, so clear out
- // the saved configuration, since when the endpoint is
- // destroyed it may never know to clear this old pointer.
- //
- if (HardEndpoint->CurrentEndpoint == SoftEndpoint) {
- HardEndpoint->CurrentEndpoint = NULL;
- }
- }
- }
- SearchIndex += 1;
- if (SearchIndex == Controller->EndpointCount) {
- SearchIndex = 1;
- }
- }
- //
- // Use the alternate, even though there are transfers queued on it.
- //
- ASSERT(Alternate != 0);
- SoftEndpoint->HardwareIndex = Alternate;
- return;
- }
- UCHAR
- MusbpReadIndexed8 (
- PMUSB_CONTROLLER Controller,
- UCHAR Index,
- MUSB_INDEXED_REGISTER Register
- )
- /*++
- Routine Description:
- This routine performs an indexed register read. It is assumed the
- controller lock is already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Index - Supplies the hardware endpoint index to read from.
- Register - Supplies the register to read.
- Return Value:
- Returns the register value.
- --*/
- {
- if (Controller->CurrentIndex != Index) {
- MUSB_WRITE8(Controller, MusbIndex, Index);
- Controller->CurrentIndex = Index;
- }
- return MUSB_READ8(Controller, Register);
- }
- UCHAR
- MusbpReadIndexed16 (
- PMUSB_CONTROLLER Controller,
- UCHAR Index,
- MUSB_INDEXED_REGISTER Register
- )
- /*++
- Routine Description:
- This routine performs an indexed register read. It is assumed the
- controller lock is already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Index - Supplies the hardware endpoint index to read from.
- Register - Supplies the register to read.
- Return Value:
- Returns the register value.
- --*/
- {
- if (Controller->CurrentIndex != Index) {
- MUSB_WRITE8(Controller, MusbIndex, Index);
- Controller->CurrentIndex = Index;
- }
- return MUSB_READ16(Controller, Register);
- }
- VOID
- MusbpWriteIndexed8 (
- PMUSB_CONTROLLER Controller,
- UCHAR Index,
- MUSB_INDEXED_REGISTER Register,
- UCHAR Value
- )
- /*++
- Routine Description:
- This routine performs an indexed register write. It is assumed the
- controller lock is already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Index - Supplies the hardware endpoint index to write to.
- Register - Supplies the register to write.
- Value - Supplies the value to write.
- Return Value:
- None.
- --*/
- {
- if (Controller->CurrentIndex != Index) {
- MUSB_WRITE8(Controller, MusbIndex, Index);
- Controller->CurrentIndex = Index;
- }
- MUSB_WRITE8(Controller, Register, Value);
- return;
- }
- VOID
- MusbpWriteIndexed16 (
- PMUSB_CONTROLLER Controller,
- UCHAR Index,
- MUSB_INDEXED_REGISTER Register,
- USHORT Value
- )
- /*++
- Routine Description:
- This routine performs an indexed register write. It is assumed the
- controller lock is already held.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Index - Supplies the hardware endpoint index to write to.
- Register - Supplies the register to write.
- Value - Supplies the value to write.
- Return Value:
- None.
- --*/
- {
- if (Controller->CurrentIndex != Index) {
- MUSB_WRITE8(Controller, MusbIndex, Index);
- Controller->CurrentIndex = Index;
- }
- MUSB_WRITE16(Controller, Register, Value);
- return;
- }
- VOID
- MusbpAcquireLock (
- PMUSB_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine acquires the controller lock.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Return Value:
- None.
- --*/
- {
- RUNLEVEL OldRunLevel;
- OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
- KeAcquireSpinLock(&(Controller->Lock));
- Controller->OldRunLevel = OldRunLevel;
- return;
- }
- VOID
- MusbpReleaseLock (
- PMUSB_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine releases the controller lock.
- Arguments:
- Controller - Supplies a pointer to the controller.
- OldRunLevel - Stores the original runlevel to return to.
- Return Value:
- None.
- --*/
- {
- RUNLEVEL OldRunLevel;
- OldRunLevel = Controller->OldRunLevel;
- KeReleaseSpinLock(&(Controller->Lock));
- KeLowerRunLevel(OldRunLevel);
- return;
- }
|