ehcihc.c 131 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. ehcihc.c
  5. Abstract:
  6. This module implements support for the EHCI USB 2.0 Host Controller.
  7. Author:
  8. Evan Green 18-Mar-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/driver.h>
  16. #include <minoca/fw/acpitabs.h>
  17. #include <minoca/usb/usbhost.h>
  18. #include "ehci.h"
  19. //
  20. // --------------------------------------------------------------------- Macros
  21. //
  22. //
  23. // These macros read from and write to a EHCI host controller register.
  24. //
  25. #define EHCI_READ_REGISTER(_Controller, _Register) \
  26. HlReadRegister32((_Controller)->RegisterBase + _Register)
  27. #define EHCI_WRITE_REGISTER(_Controller, _Register, _Value) \
  28. HlWriteRegister32((_Controller)->RegisterBase + _Register, _Value);
  29. #define EHCI_READ_PORT_REGISTER(_Controller, _PortIndex) \
  30. EHCI_READ_REGISTER( \
  31. _Controller, \
  32. EhciRegisterPortStatusBase + ((_PortIndex) * sizeof(ULONG)))
  33. #define EHCI_WRITE_PORT_REGISTER(_Controller, _PortIndex, _Value) \
  34. EHCI_WRITE_REGISTER( \
  35. _Controller, \
  36. EhciRegisterPortStatusBase + ((_PortIndex) * sizeof(ULONG)), \
  37. _Value)
  38. //
  39. // ---------------------------------------------------------------- Definitions
  40. //
  41. //
  42. // Define values to convert between frames and microframes.
  43. //
  44. #define EHCI_MICROFRAMES_PER_FRAME 8
  45. #define EHCI_MICROFRAMES_PER_FRAME_SHIFT 3
  46. //
  47. // Define EHCI debug flags.
  48. //
  49. #define EHCI_DEBUG_PORTS 0x00000001
  50. #define EHCI_DEBUG_TRANSFERS 0x00000002
  51. #define EHCI_DEBUG_ERRORS 0x00000004
  52. //
  53. // Define the timeout value for the endpoint flush operation.
  54. //
  55. #define EHCI_ENDPOINT_FLUSH_TIMEOUT 10
  56. //
  57. // Define the timeout value for the polled I/O operations.
  58. //
  59. #define EHCI_POLLED_TRANSFER_TIMEOUT 10
  60. //
  61. // ------------------------------------------------------ Data Type Definitions
  62. //
  63. //
  64. // ----------------------------------------------- Internal Function Prototypes
  65. //
  66. KSTATUS
  67. EhcipCreateEndpoint (
  68. PVOID HostControllerContext,
  69. PUSB_HOST_ENDPOINT_CREATION_REQUEST Endpoint,
  70. PVOID *EndpointContext
  71. );
  72. VOID
  73. EhcipResetEndpoint (
  74. PVOID HostControllerContext,
  75. PVOID EndpointContext,
  76. ULONG MaxPacketSize
  77. );
  78. KSTATUS
  79. EhcipFlushEndpoint (
  80. PVOID HostControllerContext,
  81. PVOID EndpointContext,
  82. PULONG TransferCount
  83. );
  84. VOID
  85. EhcipDestroyEndpoint (
  86. PVOID HostControllerContext,
  87. PVOID EndpointContext
  88. );
  89. KSTATUS
  90. EhcipCreateTransfer (
  91. PVOID HostControllerContext,
  92. PVOID EndpointContext,
  93. ULONG MaxBufferSize,
  94. ULONG Flags,
  95. PVOID *TransferContext
  96. );
  97. VOID
  98. EhcipDestroyTransfer (
  99. PVOID HostControllerContext,
  100. PVOID EndpointContext,
  101. PVOID TransferContext
  102. );
  103. KSTATUS
  104. EhcipSubmitTransfer (
  105. PVOID HostControllerContext,
  106. PVOID EndpointContext,
  107. PUSB_TRANSFER_INTERNAL Transfer,
  108. PVOID TransferContext
  109. );
  110. KSTATUS
  111. EhcipSubmitPolledTransfer (
  112. PVOID HostControllerContext,
  113. PVOID EndpointContext,
  114. PUSB_TRANSFER_INTERNAL Transfer,
  115. PVOID TransferContext
  116. );
  117. KSTATUS
  118. EhcipSubmitTransferSet (
  119. PEHCI_CONTROLLER Controller,
  120. PEHCI_ENDPOINT Endpoint,
  121. PEHCI_TRANSFER_SET TransferSet,
  122. PULONG SubmittedTransferCount,
  123. BOOL LockRequired
  124. );
  125. KSTATUS
  126. EhcipCancelTransfer (
  127. PVOID HostControllerContext,
  128. PVOID EndpointContext,
  129. PUSB_TRANSFER_INTERNAL Transfer,
  130. PVOID TransferContext
  131. );
  132. KSTATUS
  133. EhcipGetRootHubStatus (
  134. PVOID HostControllerContext,
  135. PUSB_HUB_STATUS HubStatus
  136. );
  137. KSTATUS
  138. EhcipSetRootHubStatus (
  139. PVOID HostControllerContext,
  140. PUSB_HUB_STATUS NewStatus
  141. );
  142. RUNLEVEL
  143. EhcipAcquireControllerLock (
  144. PEHCI_CONTROLLER Controller
  145. );
  146. VOID
  147. EhcipReleaseControllerLock (
  148. PEHCI_CONTROLLER Controller,
  149. RUNLEVEL OldRunLevel
  150. );
  151. VOID
  152. EhcipProcessInterrupt (
  153. PEHCI_CONTROLLER Controller,
  154. ULONG PendingStatusBits
  155. );
  156. VOID
  157. EhcipFillOutTransferDescriptor (
  158. PEHCI_CONTROLLER Controller,
  159. PEHCI_TRANSFER EhciTransfer,
  160. ULONG Offset,
  161. ULONG Length,
  162. BOOL LastTransfer,
  163. PBOOL DataToggle,
  164. PEHCI_TRANSFER AlternateNextTransfer
  165. );
  166. VOID
  167. EhcipLinkTransferSetInHardware (
  168. PEHCI_TRANSFER_SET TransferSet
  169. );
  170. BOOL
  171. EhcipProcessPotentiallyCompletedTransfer (
  172. PEHCI_TRANSFER Transfer
  173. );
  174. VOID
  175. EhcipRemoveCompletedTransferSet (
  176. PEHCI_CONTROLLER Controller,
  177. PEHCI_TRANSFER_SET TransferSet
  178. );
  179. VOID
  180. EhcipProcessAsyncOnAdvanceInterrupt (
  181. PEHCI_CONTROLLER Controller
  182. );
  183. VOID
  184. EhcipRemoveCancelledTransferSet (
  185. PEHCI_CONTROLLER Controller,
  186. PEHCI_TRANSFER_SET TransferSet
  187. );
  188. VOID
  189. EhcipDestroyQueuesWorkRoutine (
  190. PVOID Parameter
  191. );
  192. //
  193. // -------------------------------------------------------------------- Globals
  194. //
  195. //
  196. // Define a bitfield of debug flags that enable various print messages for
  197. // EHCI. See EHCI_DEBUG_* definitions.
  198. //
  199. ULONG EhciDebugFlags = 0x0;
  200. //
  201. // ------------------------------------------------------------------ Functions
  202. //
  203. PEHCI_CONTROLLER
  204. EhcipInitializeControllerState (
  205. PVOID OperationalRegisterBase,
  206. PHYSICAL_ADDRESS RegisterBasePhysical,
  207. ULONG PortCount,
  208. PDEBUG_USB_HANDOFF_DATA HandoffData
  209. )
  210. /*++
  211. Routine Description:
  212. This routine initializes the state and variables needed to start up an EHCI
  213. host controller.
  214. Arguments:
  215. OperationalRegisterBase - Supplies the virtual address of the base of the
  216. operational registers.
  217. RegisterBasePhysical - Supplies the physical address of the base of the
  218. EHCI registers (not the operational registers).
  219. PortCount - Supplies the number of ports on the EHCI controller.
  220. HandoffData - Supplies an optional pointer to the debug handoff data if the
  221. kernel debugger is using this controller.
  222. Return Value:
  223. Returns a pointer to the EHCI controller state object on success.
  224. NULL on failure.
  225. --*/
  226. {
  227. ULONG BlockSize;
  228. PEHCI_CONTROLLER Controller;
  229. PEHCI_DEBUG_HANDOFF_DATA EhciHandoff;
  230. ULONG Flags;
  231. ULONG Frame;
  232. ULONG FrameBits;
  233. ULONG IoBufferFlags;
  234. PEHCI_TRANSFER_QUEUE PreviousTransferQueue;
  235. PEHCI_QUEUE_HEAD QueueHead;
  236. PHYSICAL_ADDRESS QueueHeadPhysicalAddress;
  237. ULONG RemainingSize;
  238. KSTATUS Status;
  239. PEHCI_TRANSFER_QUEUE TransferQueue;
  240. ULONG TreeLevel;
  241. ASSERT(PortCount != 0);
  242. EhciHandoff = NULL;
  243. if (HandoffData != NULL) {
  244. ASSERT(HandoffData->HostDataSize == sizeof(EHCI_DEBUG_HANDOFF_DATA));
  245. EhciHandoff = HandoffData->HostData;
  246. }
  247. //
  248. // Allocate the controller structure itself.
  249. //
  250. Controller = MmAllocateNonPagedPool(sizeof(EHCI_CONTROLLER),
  251. EHCI_ALLOCATION_TAG);
  252. if (Controller == NULL) {
  253. Status = STATUS_INSUFFICIENT_RESOURCES;
  254. goto InitializeControllerStateEnd;
  255. }
  256. RtlZeroMemory(Controller, sizeof(EHCI_CONTROLLER));
  257. INITIALIZE_LIST_HEAD(&(Controller->IsochronousTransferListHead));
  258. INITIALIZE_LIST_HEAD(&(Controller->TransferListHead));
  259. INITIALIZE_LIST_HEAD(&(Controller->AsyncOnAdvanceReadyListHead));
  260. INITIALIZE_LIST_HEAD(&(Controller->AsyncOnAdvancePendingListHead));
  261. INITIALIZE_LIST_HEAD(&(Controller->QueuesToDestroyListHead));
  262. INITIALIZE_LIST_HEAD(&(Controller->EndpointListHead));
  263. Controller->RegisterBase = OperationalRegisterBase;
  264. Controller->PhysicalBase = RegisterBasePhysical;
  265. Controller->UsbCoreHandle = INVALID_HANDLE;
  266. Controller->InterruptHandle = INVALID_HANDLE;
  267. Controller->PortCount = PortCount;
  268. Controller->HandoffData = EhciHandoff;
  269. KeInitializeSpinLock(&(Controller->Lock));
  270. Controller->DestroyQueuesWorkItem = KeCreateWorkItem(
  271. NULL,
  272. WorkPriorityNormal,
  273. EhcipDestroyQueuesWorkRoutine,
  274. Controller,
  275. EHCI_ALLOCATION_TAG);
  276. if (Controller->DestroyQueuesWorkItem == NULL) {
  277. Status = STATUS_INSUFFICIENT_RESOURCES;
  278. goto InitializeControllerStateEnd;
  279. }
  280. //
  281. // Allocate and initialize the buffer used to hold the EHCI schedule. Since
  282. // the controller never writes to the periodic schedule memory, just map
  283. // it cached and manage it carefully (rather than mapping the whole schedule
  284. // uncached).
  285. //
  286. IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
  287. Controller->PeriodicScheduleIoBuffer = MmAllocateNonPagedIoBuffer(
  288. 0,
  289. MAX_ULONG,
  290. EHCI_FRAME_LIST_ALIGNMENT,
  291. sizeof(EHCI_PERIODIC_SCHEDULE),
  292. IoBufferFlags);
  293. if (Controller->PeriodicScheduleIoBuffer == NULL) {
  294. Status = STATUS_INSUFFICIENT_RESOURCES;
  295. goto InitializeControllerStateEnd;
  296. }
  297. ASSERT(Controller->PeriodicScheduleIoBuffer->FragmentCount == 1);
  298. ASSERT(Controller->PeriodicScheduleIoBuffer->Fragment[0].Size >=
  299. sizeof(EHCI_PERIODIC_SCHEDULE));
  300. Controller->PeriodicSchedule =
  301. Controller->PeriodicScheduleIoBuffer->Fragment[0].VirtualAddress;
  302. //
  303. // Create the block allocator used to allocate transfers and queues. The
  304. // block size is that of the larger structure.
  305. //
  306. ASSERT((EHCI_BLOCK_ALLOCATOR_ALIGNMENT & (~EHCI_LINK_ADDRESS_MASK)) == 0);
  307. if (sizeof(EHCI_TRANSFER_DESCRIPTOR) >= sizeof(EHCI_QUEUE_HEAD)) {
  308. BlockSize = sizeof(EHCI_TRANSFER_DESCRIPTOR);
  309. } else {
  310. BlockSize = sizeof(EHCI_QUEUE_HEAD);
  311. }
  312. Flags = BLOCK_ALLOCATOR_FLAG_NON_CACHED |
  313. BLOCK_ALLOCATOR_FLAG_PHYSICALLY_CONTIGUOUS;
  314. Controller->BlockAllocator = MmCreateBlockAllocator(
  315. BlockSize,
  316. EHCI_BLOCK_ALLOCATOR_ALIGNMENT,
  317. EHCI_BLOCK_ALLOCATOR_EXPANSION_COUNT,
  318. Flags,
  319. EHCI_BLOCK_ALLOCATION_TAG);
  320. if (Controller->BlockAllocator == NULL) {
  321. Status = STATUS_INSUFFICIENT_RESOURCES;
  322. goto InitializeControllerStateEnd;
  323. }
  324. //
  325. // Create the periodic schedule, which is a tree of empty queues. Interrupt
  326. // transfers can get different polling rates by inserting themselves at
  327. // different levels of the tree.
  328. //
  329. for (TreeLevel = 0;
  330. TreeLevel < EHCI_PERIODIC_SCHEDULE_TREE_DEPTH;
  331. TreeLevel += 1) {
  332. QueueHead = MmAllocateBlock(Controller->BlockAllocator,
  333. &QueueHeadPhysicalAddress);
  334. if (QueueHead == NULL) {
  335. Status = STATUS_INSUFFICIENT_RESOURCES;
  336. goto InitializeControllerStateEnd;
  337. }
  338. //
  339. // Initialize the transfer queue.
  340. //
  341. TransferQueue = &(Controller->InterruptTree[TreeLevel]);
  342. INITIALIZE_LIST_HEAD(&(TransferQueue->ListEntry));
  343. TransferQueue->HardwareQueueHead = QueueHead;
  344. TransferQueue->PhysicalAddress = QueueHeadPhysicalAddress;
  345. //
  346. // Initialize the queue head. This is non-cached memory, so don't
  347. // needlessly zero the structure. Be smart about it.
  348. //
  349. QueueHead->HorizontalLink = EHCI_LINK_TERMINATE;
  350. QueueHead->Destination = 0;
  351. QueueHead->SplitInformation = EHCI_QUEUE_1_TRANSACTION_PER_MICRO_FRAME;
  352. QueueHead->CurrentTransferDescriptorLink = 0;
  353. QueueHead->TransferOverlay.NextTransfer = EHCI_LINK_TERMINATE;
  354. QueueHead->TransferOverlay.AlternateNextTransfer = EHCI_LINK_TERMINATE;
  355. QueueHead->TransferOverlay.Token = EHCI_TRANSFER_STATUS_HALTED;
  356. RemainingSize = sizeof(EHCI_TRANSFER_DESCRIPTOR) -
  357. FIELD_OFFSET(EHCI_TRANSFER_DESCRIPTOR, BufferPointer);
  358. RtlZeroMemory(&(QueueHead->TransferOverlay.BufferPointer),
  359. RemainingSize);
  360. //
  361. // Unless this is the first (least often polled) queue, set the
  362. // previous queue to point at this more often polled queue.
  363. //
  364. if (TreeLevel != 0) {
  365. PreviousTransferQueue = &(Controller->InterruptTree[TreeLevel - 1]);
  366. ASSERT(((ULONG)QueueHeadPhysicalAddress &
  367. (~EHCI_LINK_ADDRESS_MASK)) == 0);
  368. PreviousTransferQueue->HardwareQueueHead->HorizontalLink =
  369. ((ULONG)QueueHeadPhysicalAddress &
  370. EHCI_LINK_ADDRESS_MASK) | EHCI_LINK_TYPE_QUEUE_HEAD;
  371. INSERT_AFTER(&(TransferQueue->ListEntry),
  372. &(PreviousTransferQueue->ListEntry));
  373. }
  374. }
  375. //
  376. // Initialize the array of frame list pointers for the periodic schedule
  377. // to point to the various levels of the tree with their respective
  378. // frequencies.
  379. //
  380. for (Frame = 0; Frame < EHCI_DEFAULT_FRAME_LIST_ENTRY_COUNT; Frame += 1) {
  381. FrameBits = Frame;
  382. TreeLevel = 0;
  383. //
  384. // Figure out how many zero bits are clear. For example, one in 8 times,
  385. // the first three bits are 0. Use that to determine which frequency
  386. // level to put for this frame.
  387. //
  388. while (((FrameBits & 0x1) == 0) &&
  389. (TreeLevel < EHCI_PERIODIC_SCHEDULE_TREE_DEPTH - 1)) {
  390. TreeLevel += 1;
  391. FrameBits = FrameBits >> 1;
  392. }
  393. //
  394. // The most common one is at the end, remember.
  395. //
  396. TreeLevel = EHCI_PERIODIC_SCHEDULE_TREE_DEPTH - 1 - TreeLevel;
  397. ASSERT(TreeLevel < EHCI_PERIODIC_SCHEDULE_TREE_DEPTH);
  398. TransferQueue = &(Controller->InterruptTree[TreeLevel]);
  399. Controller->PeriodicSchedule->FrameLink[Frame] =
  400. ((ULONG)TransferQueue->PhysicalAddress &
  401. EHCI_LINK_ADDRESS_MASK) |
  402. EHCI_LINK_TYPE_QUEUE_HEAD;
  403. }
  404. //
  405. // Clean the cache of the periodic schedule.
  406. //
  407. MmFlushBufferForDataOut(Controller->PeriodicSchedule,
  408. sizeof(EHCI_PERIODIC_SCHEDULE));
  409. //
  410. // Create an empty queue head for the asynchronous list.
  411. //
  412. QueueHead = MmAllocateBlock(Controller->BlockAllocator,
  413. &QueueHeadPhysicalAddress);
  414. if (QueueHead == NULL) {
  415. Status = STATUS_INSUFFICIENT_RESOURCES;
  416. goto InitializeControllerStateEnd;
  417. }
  418. //
  419. // Link the asynchronous schedule with this new queue head.
  420. //
  421. TransferQueue = &(Controller->AsynchronousSchedule);
  422. INITIALIZE_LIST_HEAD(&(TransferQueue->ListEntry));
  423. TransferQueue->HardwareQueueHead = QueueHead;
  424. TransferQueue->PhysicalAddress = QueueHeadPhysicalAddress;
  425. //
  426. // Initialize the queue head. Do not zero the whole thing, as every field
  427. // will be filled in below.
  428. //
  429. QueueHead->SplitInformation = EHCI_QUEUE_1_TRANSACTION_PER_MICRO_FRAME;
  430. QueueHead->CurrentTransferDescriptorLink = 0;
  431. QueueHead->TransferOverlay.NextTransfer = EHCI_LINK_TERMINATE;
  432. QueueHead->TransferOverlay.AlternateNextTransfer = EHCI_LINK_TERMINATE;
  433. QueueHead->TransferOverlay.Token = EHCI_TRANSFER_STATUS_HALTED;
  434. RemainingSize = sizeof(EHCI_TRANSFER_DESCRIPTOR) -
  435. FIELD_OFFSET(EHCI_TRANSFER_DESCRIPTOR, BufferPointer);
  436. RtlZeroMemory(&(QueueHead->TransferOverlay.BufferPointer),
  437. RemainingSize);
  438. //
  439. // Here's where things get interesting. If there's handoff data, then the
  440. // kernel debugger has set up two queue heads already, one is an empty
  441. // reclamation queue, and the other is an empty queue that's never used.
  442. // It inserts its own queue heads in between these two queues. The
  443. // handoff data contains the actual pointers to the queue heads the kernel
  444. // debugger uses, so they can be moved.
  445. //
  446. if (EhciHandoff != NULL) {
  447. //
  448. // Take down the kernel debug connection, as the controller's going to
  449. // be reset. The USB core driver will reconnect when it re-discovers
  450. // the debug device.
  451. //
  452. RtlDebugPrint("EHCI: Temporarily disconnecting kernel debugger "
  453. "while the controller is reinitialized.\n");
  454. KdDisconnect();
  455. //
  456. // Use the newly allocated queue to replace the end queue. This EHCI
  457. // driver will insert all its queue heads after this new end queue head,
  458. // as it appears to be the start of the asynchronous schedule. The
  459. // actual start of the schedule is the reclamation queue head in the
  460. // kernel debugger.
  461. //
  462. QueueHead->HorizontalLink = EhciHandoff->EndQueue->HorizontalLink;
  463. QueueHead->Destination = EhciHandoff->EndQueue->Destination;
  464. EhciHandoff->ReclamationQueue->HorizontalLink =
  465. QueueHeadPhysicalAddress | EHCI_LINK_TYPE_QUEUE_HEAD;
  466. //
  467. // Replace the end queue for the kernel debugger.
  468. //
  469. EhciHandoff->EndQueue = QueueHead;
  470. EhciHandoff->EndQueuePhysical = QueueHeadPhysicalAddress;
  471. //
  472. // There is no handoff data, so initialize the queue head to be the
  473. // reclamation queue head and the beginning of the asynchronous schedule.
  474. // Loop that queue to point back to itself.
  475. //
  476. } else {
  477. QueueHead->Destination = EHCI_QUEUE_RECLAMATION_HEAD;
  478. QueueHead->HorizontalLink = ((ULONG)QueueHeadPhysicalAddress &
  479. EHCI_LINK_ADDRESS_MASK) |
  480. EHCI_LINK_TYPE_QUEUE_HEAD;
  481. }
  482. Status = STATUS_SUCCESS;
  483. InitializeControllerStateEnd:
  484. if (!KSUCCESS(Status)) {
  485. if (Controller != NULL) {
  486. EhcipDestroyControllerState(Controller);
  487. Controller = NULL;
  488. }
  489. }
  490. return Controller;
  491. }
  492. VOID
  493. EhcipDestroyControllerState (
  494. PEHCI_CONTROLLER Controller
  495. )
  496. /*++
  497. Routine Description:
  498. This routine destroys the memory associated with an EHCI controller.
  499. Arguments:
  500. Controller - Supplies a pointer to the EHCI controller state to release.
  501. Return Value:
  502. None.
  503. --*/
  504. {
  505. ULONG TreeLevel;
  506. ASSERT(LIST_EMPTY(&(Controller->EndpointListHead)) != FALSE);
  507. if (Controller->DestroyQueuesWorkItem != NULL) {
  508. KeDestroyWorkItem(Controller->DestroyQueuesWorkItem);
  509. }
  510. if (Controller->PeriodicScheduleIoBuffer != NULL) {
  511. MmFreeIoBuffer(Controller->PeriodicScheduleIoBuffer);
  512. }
  513. for (TreeLevel = 0;
  514. TreeLevel < EHCI_PERIODIC_SCHEDULE_TREE_DEPTH;
  515. TreeLevel += 1) {
  516. if (Controller->InterruptTree[TreeLevel].HardwareQueueHead == NULL) {
  517. continue;
  518. }
  519. MmFreeBlock(Controller->BlockAllocator,
  520. Controller->InterruptTree[TreeLevel].HardwareQueueHead);
  521. Controller->InterruptTree[TreeLevel].HardwareQueueHead = NULL;
  522. }
  523. //
  524. // If there's handoff data, it's not great that the controller is going
  525. // down. Disconnect the debugger for safety.
  526. //
  527. if (Controller->HandoffData != NULL) {
  528. RtlDebugPrint("EHCI: Disconnecting kernel debugger as EHCI "
  529. "controller is being removed.\n");
  530. KdDisconnect();
  531. }
  532. if (Controller->AsynchronousSchedule.HardwareQueueHead != NULL) {
  533. MmFreeBlock(Controller->BlockAllocator,
  534. Controller->AsynchronousSchedule.HardwareQueueHead);
  535. Controller->AsynchronousSchedule.HardwareQueueHead = NULL;
  536. }
  537. if (Controller->BlockAllocator != NULL) {
  538. MmDestroyBlockAllocator(Controller->BlockAllocator);
  539. Controller->BlockAllocator = NULL;
  540. }
  541. ASSERT(LIST_EMPTY(&(Controller->IsochronousTransferListHead)) != FALSE);
  542. if (Controller->UsbCoreHandle != INVALID_HANDLE) {
  543. UsbHostDestroyControllerState(Controller->UsbCoreHandle);
  544. }
  545. MmFreeNonPagedPool(Controller);
  546. return;
  547. }
  548. KSTATUS
  549. EhcipRegisterController (
  550. PEHCI_CONTROLLER Controller,
  551. PDEVICE Device
  552. )
  553. /*++
  554. Routine Description:
  555. This routine registers the started EHCI controller with the core USB
  556. library.
  557. Arguments:
  558. Controller - Supplies a pointer to the EHCI controller state of the
  559. controller to register.
  560. Device - Supplies a pointer to the device object.
  561. Return Value:
  562. Status code.
  563. --*/
  564. {
  565. USB_HOST_CONTROLLER_INTERFACE Interface;
  566. KSTATUS Status;
  567. //
  568. // Fill out the functions that the USB core library will use to control
  569. // the EHCI controller.
  570. //
  571. RtlZeroMemory(&Interface, sizeof(USB_HOST_CONTROLLER_INTERFACE));
  572. Interface.Version = USB_HOST_CONTROLLER_INTERFACE_VERSION;
  573. Interface.DriverObject = EhciDriver;
  574. Interface.DeviceObject = Device;
  575. Interface.HostControllerContext = Controller;
  576. Interface.Speed = UsbDeviceSpeedHigh;
  577. Interface.Identifier = Controller->PhysicalBase;
  578. Interface.DebugPortSubType = DEBUG_PORT_USB_EHCI;
  579. Interface.RootHubPortCount = Controller->PortCount;
  580. Interface.CreateEndpoint = EhcipCreateEndpoint;
  581. Interface.ResetEndpoint = EhcipResetEndpoint;
  582. Interface.FlushEndpoint = EhcipFlushEndpoint;
  583. Interface.DestroyEndpoint = EhcipDestroyEndpoint;
  584. Interface.CreateTransfer = EhcipCreateTransfer;
  585. Interface.DestroyTransfer = EhcipDestroyTransfer;
  586. Interface.SubmitTransfer = EhcipSubmitTransfer;
  587. Interface.SubmitPolledTransfer = EhcipSubmitPolledTransfer;
  588. Interface.CancelTransfer = EhcipCancelTransfer;
  589. Interface.GetRootHubStatus = EhcipGetRootHubStatus;
  590. Interface.SetRootHubStatus = EhcipSetRootHubStatus;
  591. Status = UsbHostRegisterController(&Interface,
  592. &(Controller->UsbCoreHandle));
  593. if (!KSUCCESS(Status)) {
  594. goto RegisterControllerEnd;
  595. }
  596. RegisterControllerEnd:
  597. return Status;
  598. }
  599. VOID
  600. EhcipSetInterruptHandle (
  601. PEHCI_CONTROLLER Controller,
  602. HANDLE InterruptHandle
  603. )
  604. /*++
  605. Routine Description:
  606. This routine saves the handle of the connected interrupt in the EHCI
  607. controller.
  608. Arguments:
  609. Controller - Supplies a pointer to the EHCI controller state.
  610. InterruptHandle - Supplies the connected interrupt handle.
  611. Return Value:
  612. None.
  613. --*/
  614. {
  615. Controller->InterruptHandle = InterruptHandle;
  616. return;
  617. }
  618. KSTATUS
  619. EhcipResetController (
  620. PEHCI_CONTROLLER Controller
  621. )
  622. /*++
  623. Routine Description:
  624. This routine resets and starts the EHCI controller.
  625. Arguments:
  626. Controller - Supplies a pointer to the EHCI controller state of the
  627. controller to reset.
  628. Return Value:
  629. Status code.
  630. --*/
  631. {
  632. ULONG CommandRegister;
  633. ULONG InterruptRegister;
  634. PIO_BUFFER PeriodicIoBuffer;
  635. ULONG PhysicalAddress;
  636. ULONG PortIndex;
  637. ULONG PortStatusRegister;
  638. //
  639. // Reset the host controller and wait for the hardware to clear the bit,
  640. // which indicates that the reset is complete.
  641. //
  642. CommandRegister = EHCI_COMMAND_CONTROLLER_RESET;
  643. EHCI_WRITE_REGISTER(Controller, EhciRegisterUsbCommand, CommandRegister);
  644. do {
  645. //
  646. // AND in the hardware register to see if the bit has cleared.
  647. //
  648. CommandRegister &= EHCI_READ_REGISTER(Controller,
  649. EhciRegisterUsbCommand);
  650. } while (CommandRegister != 0);
  651. //
  652. // Clear the status register.
  653. //
  654. EHCI_WRITE_REGISTER(Controller, EhciRegisterUsbStatus, 0);
  655. //
  656. // Write the the segment selector to use the first 4GB of physical memory.
  657. //
  658. EHCI_WRITE_REGISTER(Controller, EhciRegisterSegmentSelector, 0);
  659. //
  660. // Enable all interrupts except the frame list rollover.
  661. //
  662. InterruptRegister = EHCI_INTERRUPT_ASYNC_ADVANCE |
  663. EHCI_INTERRUPT_HOST_SYSTEM_ERROR |
  664. EHCI_INTERRUPT_PORT_CHANGE |
  665. EHCI_INTERRUPT_USB_ERROR |
  666. EHCI_INTERRUPT_ENABLE;
  667. EHCI_WRITE_REGISTER(Controller,
  668. EhciRegisterUsbInterruptEnable,
  669. InterruptRegister);
  670. //
  671. // Set the periodic list base register to the physical address of the EHCI
  672. // periodic schedule.
  673. //
  674. PeriodicIoBuffer = Controller->PeriodicScheduleIoBuffer;
  675. PhysicalAddress = (ULONG)PeriodicIoBuffer->Fragment[0].PhysicalAddress;
  676. ASSERT(PhysicalAddress == PeriodicIoBuffer->Fragment[0].PhysicalAddress);
  677. EHCI_WRITE_REGISTER(Controller,
  678. EhciRegisterPeriodicListBase,
  679. PhysicalAddress);
  680. //
  681. // Write the asynchronous list base to the reclamation list head.
  682. //
  683. PhysicalAddress = (ULONG)Controller->AsynchronousSchedule.PhysicalAddress;
  684. ASSERT(PhysicalAddress == Controller->AsynchronousSchedule.PhysicalAddress);
  685. EHCI_WRITE_REGISTER(Controller,
  686. EhciRegisterAsynchronousListAddress,
  687. PhysicalAddress);
  688. //
  689. // Write to the command register to start the controller.
  690. //
  691. CommandRegister = EHCI_COMMAND_INTERRUPT_EVERY_8_UFRAMES |
  692. ECHI_COMMAND_ASYNC_PARK_ENABLE |
  693. (3 << EHCI_COMMAND_PARK_COUNT_SHIFT) |
  694. EHCI_COMMAND_ENABLE_ASYNC_SCHEDULE |
  695. EHCI_COMMAND_ENABLE_PERIODIC_SCHEDULE |
  696. EHCI_COMMAND_1024_FRAME_LIST_ENTRIES |
  697. EHCI_COMMAND_RUN;
  698. EHCI_WRITE_REGISTER(Controller, EhciRegisterUsbCommand, CommandRegister);
  699. Controller->CommandRegister = CommandRegister;
  700. //
  701. // Set the config flag, which switches all the ports to EHCI away from the
  702. // companion controllers.
  703. //
  704. EHCI_WRITE_REGISTER(Controller, EhciRegisterConfigured, 1);
  705. //
  706. // Fire up the ports.
  707. //
  708. for (PortIndex = 0; PortIndex < Controller->PortCount; PortIndex += 1) {
  709. PortStatusRegister = EHCI_READ_PORT_REGISTER(Controller, PortIndex);
  710. if ((PortStatusRegister & EHCI_PORT_POWER) == 0) {
  711. PortStatusRegister |= EHCI_PORT_POWER;
  712. EHCI_WRITE_PORT_REGISTER(Controller, PortIndex, PortStatusRegister);
  713. }
  714. }
  715. return STATUS_SUCCESS;
  716. }
  717. INTERRUPT_STATUS
  718. EhcipInterruptService (
  719. PVOID Context
  720. )
  721. /*++
  722. Routine Description:
  723. This routine implements the EHCI interrupt service routine.
  724. Arguments:
  725. Context - Supplies the context pointer given to the system when the
  726. interrupt was connected. In this case, this points to the EHCI
  727. controller.
  728. Return Value:
  729. Interrupt status.
  730. --*/
  731. {
  732. PEHCI_CONTROLLER Controller;
  733. INTERRUPT_STATUS InterruptStatus;
  734. USHORT UsbStatus;
  735. Controller = (PEHCI_CONTROLLER)Context;
  736. InterruptStatus = InterruptStatusNotClaimed;
  737. //
  738. // Read the status register. If it's non-zero, this is USB's interrupt.
  739. //
  740. UsbStatus = EHCI_READ_REGISTER(Controller, EhciRegisterUsbStatus) &
  741. EHCI_STATUS_INTERRUPT_MASK;
  742. if (UsbStatus != 0) {
  743. InterruptStatus = InterruptStatusClaimed;
  744. RtlAtomicOr32(&(Controller->PendingStatusBits), UsbStatus);
  745. //
  746. // Clear the bits in the status register to acknowledge the interrupt.
  747. //
  748. EHCI_WRITE_REGISTER(Controller, EhciRegisterUsbStatus, UsbStatus);
  749. }
  750. return InterruptStatus;
  751. }
  752. INTERRUPT_STATUS
  753. EhcipInterruptServiceDpc (
  754. PVOID Parameter
  755. )
  756. /*++
  757. Routine Description:
  758. This routine implements the EHCI dispatch level interrupt service.
  759. Arguments:
  760. Parameter - Supplies the context, in this case the EHCI controller
  761. structure.
  762. Return Value:
  763. None.
  764. --*/
  765. {
  766. PEHCI_CONTROLLER Controller;
  767. ULONG StatusBits;
  768. Controller = Parameter;
  769. StatusBits = RtlAtomicExchange32(&(Controller->PendingStatusBits), 0);
  770. if (StatusBits == 0) {
  771. return InterruptStatusNotClaimed;
  772. }
  773. EhcipProcessInterrupt(Controller, StatusBits);
  774. return InterruptStatusClaimed;
  775. }
  776. //
  777. // --------------------------------------------------------- Internal Functions
  778. //
  779. KSTATUS
  780. EhcipCreateEndpoint (
  781. PVOID HostControllerContext,
  782. PUSB_HOST_ENDPOINT_CREATION_REQUEST Endpoint,
  783. PVOID *EndpointContext
  784. )
  785. /*++
  786. Routine Description:
  787. This routine is called by the USB core when a new endpoint is being opened.
  788. It allows the host controller to create and store any context needed to
  789. support a new endpoint (such as a queue head).
  790. Arguments:
  791. HostControllerContext - Supplies the context pointer passed to the USB core
  792. when the controller was created. This is used to identify the USB host
  793. controller to the host controller driver.
  794. Endpoint - Supplies a pointer containing information about the endpoint
  795. being created. The host controller cannot count on this buffer sticking
  796. around after the function returns. If it needs this information it
  797. should make a copy of it.
  798. EndpointContext - Supplies a pointer where the host controller can store a
  799. context pointer identifying the endpoint created.
  800. Return Value:
  801. STATUS_SUCCESS if the endpoint can be successfully accommodated.
  802. Failing status code if the endpoint cannot be opened.
  803. --*/
  804. {
  805. ULONG ClosestRate;
  806. PEHCI_CONTROLLER Controller;
  807. ULONG Destination;
  808. PEHCI_TRANSFER DummyTransfer;
  809. ULONG EndMask;
  810. PEHCI_TRANSFER_DESCRIPTOR HardwareTransfer;
  811. PHYSICAL_ADDRESS HardwareTransferPhysicalAddress;
  812. ULONG InterruptTreeLevel;
  813. ULONG NakReloadCount;
  814. PEHCI_ENDPOINT NewEndpoint;
  815. PEHCI_TRANSFER_QUEUE NewQueue;
  816. RUNLEVEL OldRunLevel;
  817. PHYSICAL_ADDRESS PhysicalAddress;
  818. ULONG PollRate;
  819. PEHCI_TRANSFER_QUEUE QueueBefore;
  820. PEHCI_QUEUE_HEAD QueueHead;
  821. PHYSICAL_ADDRESS QueueHeadPhysicalAddress;
  822. ULONG RemainingSize;
  823. ULONG SplitInformation;
  824. ULONG StartMicroFrame;
  825. KSTATUS Status;
  826. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  827. NewEndpoint = MmAllocateNonPagedPool(sizeof(EHCI_ENDPOINT),
  828. EHCI_ALLOCATION_TAG);
  829. if (NewEndpoint == NULL) {
  830. Status = STATUS_INSUFFICIENT_RESOURCES;
  831. goto CreateEndpointEnd;
  832. }
  833. RtlZeroMemory(NewEndpoint, sizeof(EHCI_ENDPOINT));
  834. INITIALIZE_LIST_HEAD(&(NewEndpoint->TransferListHead));
  835. NewEndpoint->TransferType = Endpoint->Type;
  836. ASSERT((Endpoint->Speed == UsbDeviceSpeedLow) ||
  837. (Endpoint->Speed == UsbDeviceSpeedFull) ||
  838. (Endpoint->Speed == UsbDeviceSpeedHigh));
  839. NewEndpoint->Speed = Endpoint->Speed;
  840. ASSERT(Endpoint->MaxPacketSize != 0);
  841. NewEndpoint->MaxPacketSize = Endpoint->MaxPacketSize;
  842. NewEndpoint->EndpointNumber = Endpoint->EndpointNumber;
  843. NewEndpoint->PollRate = Endpoint->PollRate;
  844. //
  845. // If the endpoint is high speed, the units are in microframes. But EHCI
  846. // periodic schedules run in frames, so convert down (rounding up).
  847. //
  848. if (NewEndpoint->Speed == UsbDeviceSpeedHigh) {
  849. NewEndpoint->PollRate =
  850. ALIGN_RANGE_UP(NewEndpoint->PollRate, EHCI_MICROFRAMES_PER_FRAME) >>
  851. EHCI_MICROFRAMES_PER_FRAME_SHIFT;
  852. }
  853. //
  854. // For isochronous endpoints, that's all that is needed.
  855. //
  856. if (NewEndpoint->TransferType == UsbTransferTypeIsochronous) {
  857. Status = STATUS_SUCCESS;
  858. goto CreateEndpointEnd;
  859. }
  860. //
  861. // Create the hardware queue head.
  862. //
  863. QueueHead = MmAllocateBlock(Controller->BlockAllocator,
  864. &QueueHeadPhysicalAddress);
  865. if (QueueHead == NULL) {
  866. Status = STATUS_INSUFFICIENT_RESOURCES;
  867. goto CreateEndpointEnd;
  868. }
  869. RtlZeroMemory(QueueHead, sizeof(EHCI_QUEUE_HEAD));
  870. NewQueue = &(NewEndpoint->Queue);
  871. NewQueue->HardwareQueueHead = QueueHead;
  872. NewQueue->PhysicalAddress = QueueHeadPhysicalAddress;
  873. //
  874. // Set the NAK reload count to the maximum for control and bulk transfers.
  875. // Interrupt and isochronous transfers must have the NAK reload count set
  876. // to zero.
  877. //
  878. if ((NewEndpoint->TransferType == UsbTransferTypeControl) ||
  879. (NewEndpoint->TransferType == UsbTransferTypeBulk)) {
  880. NakReloadCount = EHCI_QUEUE_DEFAULT_NAK_RELOAD_COUNT;
  881. } else {
  882. NakReloadCount = 0;
  883. }
  884. //
  885. // Initialize the hardware queue entry. Notice one thing conspicuously
  886. // missing is the device address. This gets initialized to zero, and fixed
  887. // up during transfer submissions (when the device is potentially moved off
  888. // address zero).
  889. //
  890. Destination =
  891. (NakReloadCount << EHCI_QUEUE_NAK_RELOAD_COUNT_SHIFT) |
  892. ((NewEndpoint->MaxPacketSize << EHCI_QUEUE_MAX_PACKET_LENGTH_SHIFT) &
  893. EHCI_QUEUE_MAX_PACKET_LENGTH_MASK) |
  894. ((NewEndpoint->EndpointNumber & USB_ENDPOINT_ADDRESS_MASK) <<
  895. EHCI_QUEUE_ENDPOINT_SHIFT);
  896. switch (NewEndpoint->Speed) {
  897. case UsbDeviceSpeedLow:
  898. Destination |= EHCI_QUEUE_LOW_SPEED;
  899. break;
  900. case UsbDeviceSpeedFull:
  901. Destination |= EHCI_QUEUE_FULL_SPEED;
  902. break;
  903. case UsbDeviceSpeedHigh:
  904. Destination |= EHCI_QUEUE_HIGH_SPEED;
  905. break;
  906. default:
  907. ASSERT(FALSE);
  908. Status = STATUS_INVALID_PARAMETER;
  909. goto CreateEndpointEnd;
  910. }
  911. //
  912. // All control transfers handle the data toggle without hardware
  913. // assistance. Non-high speed control transfers must have the control
  914. // endpoint flag set. High speed control transfers should not have said
  915. // flag set.
  916. //
  917. if (NewEndpoint->TransferType == UsbTransferTypeControl) {
  918. Destination |= EHCI_QUEUE_USE_TRANSFER_DESCRIPTOR_DATA_TOGGLE;
  919. if (NewEndpoint->Speed != UsbDeviceSpeedHigh) {
  920. Destination |= EHCI_QUEUE_CONTROL_ENDPOINT;
  921. }
  922. }
  923. QueueHead->Destination = Destination;
  924. //
  925. // Set the split information in the hardware queue entry.
  926. //
  927. if (NewEndpoint->Speed == UsbDeviceSpeedHigh) {
  928. SplitInformation = EHCI_QUEUE_1_TRANSACTION_PER_MICRO_FRAME;
  929. } else {
  930. SplitInformation = EHCI_QUEUE_1_TRANSACTION_PER_MICRO_FRAME;
  931. }
  932. if ((NewEndpoint->Speed == UsbDeviceSpeedLow) ||
  933. (NewEndpoint->Speed == UsbDeviceSpeedFull)) {
  934. ASSERT(Endpoint->HubAddress != 0);
  935. ASSERT(Endpoint->HubPortNumber != 0);
  936. SplitInformation |=
  937. ((Endpoint->HubPortNumber << EHCI_QUEUE_PORT_NUMBER_SHIFT) &
  938. EHCI_QUEUE_PORT_NUMBER_MASK) |
  939. ((Endpoint->HubAddress << EHCI_QUEUE_HUB_ADDRESS_SHIFT) &
  940. EHCI_QUEUE_HUB_ADDRESS_MASK);
  941. if (NewEndpoint->TransferType == UsbTransferTypeInterrupt) {
  942. //
  943. // Make a weak attempt at spreading out these transfers throughout
  944. // micro frames. Only start in 0-3, inclusive, to avoid dealing
  945. // with Frame Split Transaction Nodes.
  946. //
  947. // N.B. Interrupt transfer cancellation will need to change if the
  948. // above behavior is changed.
  949. //
  950. StartMicroFrame = Controller->EndpointCount & 0x3;
  951. //
  952. // Isochronous OUT endpoints don't use complete splits, but
  953. // interrupt and other endpoints usually skip a microframe and then
  954. // issue complete splits for the next three.
  955. //
  956. if ((Endpoint->Type == UsbTransferTypeIsochronous) &&
  957. (Endpoint->Direction == UsbTransferDirectionOut)) {
  958. EndMask = 0;
  959. } else {
  960. EndMask = (1 << (StartMicroFrame + 2)) |
  961. (1 << (StartMicroFrame + 3)) |
  962. (1 << (StartMicroFrame + 4));
  963. }
  964. SplitInformation |=
  965. ((EndMask << EHCI_QUEUE_SPLIT_COMPLETION_SHIFT) &
  966. EHCI_QUEUE_SPLIT_COMPLETION_MASK) |
  967. ((1 << StartMicroFrame) &
  968. EHCI_QUEUE_SPLIT_START_MASK);
  969. }
  970. } else {
  971. //
  972. // Make a weak attempt at spreading the transfers throughout micro-
  973. // frames.
  974. //
  975. if (NewEndpoint->TransferType == UsbTransferTypeInterrupt) {
  976. SplitInformation |= ((1 << (Controller->EndpointCount & 0x7)) &
  977. EHCI_QUEUE_SPLIT_START_MASK);
  978. }
  979. }
  980. QueueHead->SplitInformation = SplitInformation;
  981. //
  982. // Allocate an initial dummy transfer to point this queue at.
  983. //
  984. DummyTransfer = MmAllocateNonPagedPool(sizeof(EHCI_TRANSFER),
  985. EHCI_ALLOCATION_TAG);
  986. if (DummyTransfer == NULL) {
  987. Status = STATUS_INSUFFICIENT_RESOURCES;
  988. goto CreateEndpointEnd;
  989. }
  990. HardwareTransfer = MmAllocateBlock(Controller->BlockAllocator,
  991. &HardwareTransferPhysicalAddress);
  992. if (HardwareTransfer == NULL) {
  993. Status = STATUS_INSUFFICIENT_RESOURCES;
  994. goto CreateEndpointEnd;
  995. }
  996. RtlZeroMemory(DummyTransfer, sizeof(EHCI_TRANSFER));
  997. NewQueue->DummyTransfer = DummyTransfer;
  998. DummyTransfer->HardwareTransfer = HardwareTransfer;
  999. DummyTransfer->PhysicalAddress = HardwareTransferPhysicalAddress;
  1000. HardwareTransfer->NextTransfer = EHCI_LINK_TERMINATE;
  1001. HardwareTransfer->AlternateNextTransfer = EHCI_LINK_TERMINATE;
  1002. HardwareTransfer->Token = EHCI_TRANSFER_STATUS_HALTED;
  1003. RemainingSize = sizeof(EHCI_TRANSFER_DESCRIPTOR) -
  1004. FIELD_OFFSET(EHCI_TRANSFER_DESCRIPTOR, BufferPointer);
  1005. RtlZeroMemory(&(HardwareTransfer->BufferPointer),
  1006. RemainingSize);
  1007. //
  1008. // Point the queue at the dummy transfer.
  1009. //
  1010. QueueHead->TransferOverlay.NextTransfer =
  1011. (ULONG)HardwareTransferPhysicalAddress;
  1012. QueueHead->TransferOverlay.AlternateNextTransfer =
  1013. (ULONG)HardwareTransferPhysicalAddress;
  1014. //
  1015. // Figure out where to insert this queue. If it's an interrupt transfer,
  1016. // determine what level of the tree it belongs in based on the polling rate.
  1017. //
  1018. if (NewEndpoint->TransferType == UsbTransferTypeInterrupt) {
  1019. PollRate = NewEndpoint->PollRate;
  1020. if (PollRate > MAX_USHORT / 2) {
  1021. PollRate = MAX_USHORT / 2;
  1022. }
  1023. ClosestRate = 1;
  1024. while (ClosestRate < PollRate) {
  1025. ClosestRate <<= 1;
  1026. }
  1027. if (ClosestRate != PollRate) {
  1028. ClosestRate >>= 1;
  1029. }
  1030. ASSERT(ClosestRate != 0);
  1031. InterruptTreeLevel = EHCI_PERIODIC_SCHEDULE_TREE_DEPTH - 1;
  1032. while (((ClosestRate & 0x1) == 0) && (InterruptTreeLevel != 0)) {
  1033. ClosestRate >>= 1;
  1034. InterruptTreeLevel -= 1;
  1035. }
  1036. ASSERT(InterruptTreeLevel < EHCI_PERIODIC_SCHEDULE_TREE_DEPTH);
  1037. QueueBefore = &(Controller->InterruptTree[InterruptTreeLevel]);
  1038. NewEndpoint->PollRate = ClosestRate;
  1039. } else {
  1040. QueueBefore = &(Controller->AsynchronousSchedule);
  1041. }
  1042. //
  1043. // Insert the endpoint onto the global queue, both the software list and
  1044. // the hardware's singly linked list. Use register writes for memory that
  1045. // is potentially being actively observed by hardware.
  1046. //
  1047. OldRunLevel = EhcipAcquireControllerLock(Controller);
  1048. Controller->EndpointCount += 1;
  1049. INSERT_BEFORE(&(NewEndpoint->ListEntry), &(Controller->EndpointListHead));
  1050. INSERT_AFTER(&(NewQueue->ListEntry), &(QueueBefore->ListEntry));
  1051. QueueHead->HorizontalLink = QueueBefore->HardwareQueueHead->HorizontalLink;
  1052. ASSERT(((ULONG)NewQueue->PhysicalAddress & (~EHCI_LINK_ADDRESS_MASK)) == 0);
  1053. PhysicalAddress = NewQueue->PhysicalAddress | EHCI_LINK_TYPE_QUEUE_HEAD;
  1054. HlWriteRegister32(&(QueueBefore->HardwareQueueHead->HorizontalLink),
  1055. (ULONG)PhysicalAddress);
  1056. EhcipReleaseControllerLock(Controller, OldRunLevel);
  1057. Status = STATUS_SUCCESS;
  1058. CreateEndpointEnd:
  1059. if (!KSUCCESS(Status)) {
  1060. if (NewEndpoint != NULL) {
  1061. DummyTransfer = NewEndpoint->Queue.DummyTransfer;
  1062. if (DummyTransfer != NULL) {
  1063. if (DummyTransfer->HardwareTransfer != NULL) {
  1064. MmFreeBlock(Controller->BlockAllocator,
  1065. DummyTransfer->HardwareTransfer);
  1066. }
  1067. MmFreeNonPagedPool(DummyTransfer);
  1068. }
  1069. MmFreeNonPagedPool(NewEndpoint);
  1070. NewEndpoint = NULL;
  1071. }
  1072. }
  1073. *EndpointContext = NewEndpoint;
  1074. return Status;
  1075. }
  1076. VOID
  1077. EhcipResetEndpoint (
  1078. PVOID HostControllerContext,
  1079. PVOID EndpointContext,
  1080. ULONG MaxPacketSize
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. This routine is called by the USB core when an endpoint needs to be reset.
  1085. Arguments:
  1086. HostControllerContext - Supplies the context pointer passed to the USB core
  1087. when the controller was created. This is used to identify the USB host
  1088. controller to the host controller driver.
  1089. EndpointContext - Supplies a pointer to the context returned by the host
  1090. controller when the endpoint was created.
  1091. MaxPacketSize - Supplies the maximum transfer size of the endpoint.
  1092. Return Value:
  1093. None.
  1094. --*/
  1095. {
  1096. PEHCI_ENDPOINT Endpoint;
  1097. PEHCI_QUEUE_HEAD HardwareQueueHead;
  1098. ULONG Token;
  1099. Endpoint = (PEHCI_ENDPOINT)EndpointContext;
  1100. //
  1101. // There better not be any active transfers running around during an
  1102. // endpoint reset.
  1103. //
  1104. ASSERT(LIST_EMPTY(&(Endpoint->TransferListHead)) != FALSE);
  1105. //
  1106. // If the max packet size changed, update the queue head.
  1107. //
  1108. HardwareQueueHead = Endpoint->Queue.HardwareQueueHead;
  1109. if (MaxPacketSize != Endpoint->MaxPacketSize) {
  1110. Endpoint->MaxPacketSize = MaxPacketSize;
  1111. HardwareQueueHead->Destination =
  1112. (HardwareQueueHead->Destination &
  1113. (~EHCI_QUEUE_MAX_PACKET_LENGTH_MASK)) |
  1114. ((MaxPacketSize << EHCI_QUEUE_MAX_PACKET_LENGTH_SHIFT) &
  1115. EHCI_QUEUE_MAX_PACKET_LENGTH_MASK);
  1116. }
  1117. //
  1118. // Reset the data toggle in the transfer overlay.
  1119. //
  1120. Token = HlReadRegister32(&(HardwareQueueHead->TransferOverlay.Token));
  1121. Token &= ~EHCI_TRANSFER_DATA_TOGGLE;
  1122. HlWriteRegister32(&(HardwareQueueHead->TransferOverlay.Token), Token);
  1123. return;
  1124. }
  1125. KSTATUS
  1126. EhcipFlushEndpoint (
  1127. PVOID HostControllerContext,
  1128. PVOID EndpointContext,
  1129. PULONG TransferCount
  1130. )
  1131. /*++
  1132. Routine Description:
  1133. This routine flushes all the active transfers from an endpoint. It does so
  1134. by polling for completion status and does not return until all transfers
  1135. are completed. This must be called at high run level.
  1136. Arguments:
  1137. HostControllerContext - Supplies the context pointer passed to the USB core
  1138. when the controller was created. This is used to identify the USB host
  1139. controller to the host controller driver.
  1140. EndpointContext - Supplies a pointer to the context returned by the host
  1141. controller when the endpoint was created.
  1142. TransferCount - Supplies a pointer to a boolean that receives the number
  1143. of transfers that were flushed.
  1144. Return Value:
  1145. Status code.
  1146. --*/
  1147. {
  1148. PEHCI_CONTROLLER Controller;
  1149. ULONG Count;
  1150. PLIST_ENTRY CurrentEntry;
  1151. PEHCI_ENDPOINT Endpoint;
  1152. PEHCI_TRANSFER NextTransfer;
  1153. BOOL RemoveSet;
  1154. KSTATUS Status;
  1155. ULONGLONG Timeout;
  1156. PEHCI_TRANSFER Transfer;
  1157. PEHCI_TRANSFER_SET TransferSet;
  1158. //
  1159. // This routine removes transfers without acquiring the controller lock. It
  1160. // is expected that the caller is using under special circumstances at high
  1161. // run level (e.g. to prepare for crash dump writes during system failure).
  1162. //
  1163. ASSERT(KeGetRunLevel() == RunLevelHigh);
  1164. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  1165. Endpoint = (PEHCI_ENDPOINT)EndpointContext;
  1166. if (Endpoint->TransferType == UsbTransferTypeIsochronous) {
  1167. //
  1168. // TODO: Implement support for isochronous transfers.
  1169. //
  1170. ASSERT(FALSE);
  1171. return STATUS_NOT_SUPPORTED;
  1172. }
  1173. //
  1174. // Let every transfer set in the endpoint complete. If the caller is about
  1175. // to use this endpoint for an operation during a system failure, then the
  1176. // endpoint better be alive enough to finish the rest of its current
  1177. // transfers.
  1178. //
  1179. Timeout = HlQueryTimeCounter() +
  1180. (HlQueryTimeCounterFrequency() * EHCI_ENDPOINT_FLUSH_TIMEOUT);
  1181. Count = 0;
  1182. while (LIST_EMPTY(&(Endpoint->TransferListHead)) == FALSE) {
  1183. if (HlQueryTimeCounter() > Timeout) {
  1184. Status = STATUS_TIMEOUT;
  1185. goto FlushEndpointEnd;
  1186. }
  1187. CurrentEntry = Endpoint->TransferListHead.Next;
  1188. while (CurrentEntry != &(Endpoint->TransferListHead)) {
  1189. ASSERT((CurrentEntry != NULL) && (CurrentEntry->Next != NULL));
  1190. Transfer = LIST_VALUE(CurrentEntry,
  1191. EHCI_TRANSFER,
  1192. EndpointListEntry);
  1193. CurrentEntry = CurrentEntry->Next;
  1194. RemoveSet = EhcipProcessPotentiallyCompletedTransfer(Transfer);
  1195. if (RemoveSet != FALSE) {
  1196. //
  1197. // Get the current entry off of this set, as several transfers
  1198. // may be removed here.
  1199. //
  1200. TransferSet = Transfer->Set;
  1201. if (CurrentEntry != &(Endpoint->TransferListHead)) {
  1202. NextTransfer = LIST_VALUE(CurrentEntry,
  1203. EHCI_TRANSFER,
  1204. EndpointListEntry);
  1205. while (NextTransfer->Set == TransferSet) {
  1206. CurrentEntry = CurrentEntry->Next;
  1207. if (CurrentEntry == &(Endpoint->TransferListHead)) {
  1208. break;
  1209. }
  1210. NextTransfer = LIST_VALUE(CurrentEntry,
  1211. EHCI_TRANSFER,
  1212. EndpointListEntry);
  1213. }
  1214. }
  1215. //
  1216. // Remove the transfer set from the owning endpoint's queue,
  1217. // but don't bother to call the completion routine. It's really
  1218. // just lights out for this transfer.
  1219. //
  1220. EhcipRemoveCompletedTransferSet(Controller, TransferSet);
  1221. Count += 1;
  1222. }
  1223. }
  1224. }
  1225. Status = STATUS_SUCCESS;
  1226. FlushEndpointEnd:
  1227. *TransferCount = Count;
  1228. return Status;
  1229. }
  1230. VOID
  1231. EhcipDestroyEndpoint (
  1232. PVOID HostControllerContext,
  1233. PVOID EndpointContext
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. This routine tears down and destroys an endpoint created with the endpoint
  1238. creation routine.
  1239. Arguments:
  1240. HostControllerContext - Supplies the context pointer passed to the USB core
  1241. when the controller was created. This is used to identify the USB host
  1242. controller to the host controller driver.
  1243. EndpointContext - Supplies a pointer to the context returned by the host
  1244. controller when the endpoint was created.
  1245. Return Value:
  1246. None.
  1247. --*/
  1248. {
  1249. ULONG CommandRegister;
  1250. PEHCI_CONTROLLER Controller;
  1251. PEHCI_ENDPOINT Endpoint;
  1252. BOOL LockHeld;
  1253. RUNLEVEL OldRunLevel;
  1254. PEHCI_TRANSFER_QUEUE Queue;
  1255. PEHCI_TRANSFER_QUEUE QueueBefore;
  1256. BOOL ReleaseEndpoint;
  1257. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  1258. Endpoint = (PEHCI_ENDPOINT)EndpointContext;
  1259. LockHeld = FALSE;
  1260. ReleaseEndpoint = TRUE;
  1261. ASSERT(LIST_EMPTY(&(Endpoint->TransferListHead)) != FALSE);
  1262. //
  1263. // Remove the endpoint's queue from the hardware schedule.
  1264. //
  1265. if (Endpoint->Queue.HardwareQueueHead != NULL) {
  1266. OldRunLevel = EhcipAcquireControllerLock(Controller);
  1267. LockHeld = TRUE;
  1268. if (Endpoint->Queue.HardwareQueueHead == NULL) {
  1269. goto DestroyEndpointEnd;
  1270. }
  1271. Queue = &(Endpoint->Queue);
  1272. Controller->EndpointCount -= 1;
  1273. LIST_REMOVE(&(Endpoint->ListEntry));
  1274. //
  1275. // Isochronous transfers are handled differently.
  1276. //
  1277. if (Endpoint->TransferType == UsbTransferTypeIsochronous) {
  1278. ASSERT(FALSE);
  1279. goto DestroyEndpointEnd;
  1280. //
  1281. // Remove the interrupt endpoint's queue from the synchronous schedule.
  1282. //
  1283. } else if (Endpoint->TransferType == UsbTransferTypeInterrupt) {
  1284. ASSERT(Queue->ListEntry.Next != NULL);
  1285. QueueBefore = LIST_VALUE(Queue->ListEntry.Previous,
  1286. EHCI_TRANSFER_QUEUE,
  1287. ListEntry);
  1288. HlWriteRegister32(&(QueueBefore->HardwareQueueHead->HorizontalLink),
  1289. Queue->HardwareQueueHead->HorizontalLink);
  1290. LIST_REMOVE(&(Queue->ListEntry));
  1291. Queue->ListEntry.Next = NULL;
  1292. //
  1293. // Now release the lock and wait a full frame to make sure that the
  1294. // periodic schedule has moved beyond this queue head. This simple
  1295. // wait accounts for split transactions, but will need to be
  1296. // updated if Frame Split Transaction Nodes are supported.
  1297. //
  1298. EhcipReleaseControllerLock(Controller, OldRunLevel);
  1299. LockHeld = FALSE;
  1300. KeDelayExecution(FALSE, FALSE, 1 * MICROSECONDS_PER_MILLISECOND);
  1301. //
  1302. // The queue can be safely destroyed.
  1303. //
  1304. if (Queue->DummyTransfer != NULL) {
  1305. if (Queue->DummyTransfer->HardwareTransfer != NULL) {
  1306. MmFreeBlock(Controller->BlockAllocator,
  1307. Queue->DummyTransfer->HardwareTransfer);
  1308. }
  1309. MmFreeNonPagedPool(Queue->DummyTransfer);
  1310. }
  1311. MmFreeBlock(Controller->BlockAllocator, Queue->HardwareQueueHead);
  1312. Queue->HardwareQueueHead = NULL;
  1313. //
  1314. // Remove bulk and control endpoint's queue head from the asynchronous
  1315. // schedule. The transfer set will be fully removed from the queue head
  1316. // once the interrupt for async-on-advance has fired.
  1317. //
  1318. } else {
  1319. ASSERT(Queue->AsyncOnAdvanceCancel == FALSE);
  1320. ASSERT((Endpoint->TransferType == UsbTransferTypeControl) ||
  1321. (Endpoint->TransferType == UsbTransferTypeBulk));
  1322. QueueBefore = LIST_VALUE(Queue->ListEntry.Previous,
  1323. EHCI_TRANSFER_QUEUE,
  1324. ListEntry);
  1325. HlWriteRegister32(&(QueueBefore->HardwareQueueHead->HorizontalLink),
  1326. Queue->HardwareQueueHead->HorizontalLink);
  1327. LIST_REMOVE(&(Queue->ListEntry));
  1328. //
  1329. // If the asynchronous on advance ready list is empty, then add
  1330. // this queue head to the ready list and ring the doorbell.
  1331. //
  1332. if (LIST_EMPTY(&(Controller->AsyncOnAdvanceReadyListHead))) {
  1333. INSERT_BEFORE(&(Queue->ListEntry),
  1334. &(Controller->AsyncOnAdvanceReadyListHead));
  1335. CommandRegister = Controller->CommandRegister;
  1336. CommandRegister |= EHCI_COMMAND_INTERRUPT_ON_ASYNC_ADVANCE;
  1337. EHCI_WRITE_REGISTER(Controller,
  1338. EhciRegisterUsbCommand,
  1339. CommandRegister);
  1340. //
  1341. // Otherwise the doorbell has already been rung. This queue head
  1342. // will have to wait for the next chance to ring it. Put it on the
  1343. // pending list.
  1344. //
  1345. } else {
  1346. INSERT_BEFORE(&(Queue->ListEntry),
  1347. &(Controller->AsyncOnAdvancePendingListHead));
  1348. }
  1349. //
  1350. // Do not release the endpoint. It will get released along with the
  1351. // queue when the async-on-advance interrupt is handled.
  1352. //
  1353. ReleaseEndpoint = FALSE;
  1354. }
  1355. }
  1356. DestroyEndpointEnd:
  1357. if (LockHeld != FALSE) {
  1358. EhcipReleaseControllerLock(Controller, OldRunLevel);
  1359. }
  1360. if (ReleaseEndpoint != FALSE) {
  1361. MmFreeNonPagedPool(Endpoint);
  1362. }
  1363. return;
  1364. }
  1365. KSTATUS
  1366. EhcipCreateTransfer (
  1367. PVOID HostControllerContext,
  1368. PVOID EndpointContext,
  1369. ULONG MaxBufferSize,
  1370. ULONG Flags,
  1371. PVOID *TransferContext
  1372. )
  1373. /*++
  1374. Routine Description:
  1375. This routine allocates structures needed for the USB host controller to
  1376. support a transfer.
  1377. Arguments:
  1378. HostControllerContext - Supplies the context pointer passed to the USB core
  1379. when the controller was created. This is used to identify the USB host
  1380. controller to the host controller driver.
  1381. EndpointContext - Supplies a pointer to the host controller's context of
  1382. the endpoint that this transfer will eventually be submitted to.
  1383. MaxBufferSize - Supplies the maximum buffer length, in bytes, of the
  1384. transfer when it is submitted. It is assumed that the host controller
  1385. will set up as many transfer descriptors as are needed to support a
  1386. transfer of this size.
  1387. Flags - Supplies a bitfield of flags regarding the transaction. See
  1388. USB_TRANSFER_FLAG_* definitions.
  1389. TransferContext - Supplies a pointer where the host controller can store a
  1390. context pointer containing any needed structures for the transfer.
  1391. Return Value:
  1392. None.
  1393. --*/
  1394. {
  1395. ULONG AllocationSize;
  1396. PEHCI_CONTROLLER Controller;
  1397. PEHCI_ENDPOINT Endpoint;
  1398. BOOL ForceShortTransfer;
  1399. PEHCI_TRANSFER_DESCRIPTOR HardwareTransfer;
  1400. PHYSICAL_ADDRESS HardwareTransferPhysicalAddress;
  1401. KSTATUS Status;
  1402. PEHCI_TRANSFER Transfer;
  1403. PEHCI_TRANSFER *TransferArray;
  1404. ULONG TransferCount;
  1405. ULONG TransferIndex;
  1406. PEHCI_TRANSFER_SET TransferSet;
  1407. ASSERT(TransferContext != NULL);
  1408. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  1409. Endpoint = (PEHCI_ENDPOINT)EndpointContext;
  1410. ForceShortTransfer = FALSE;
  1411. if ((Flags & USB_TRANSFER_FLAG_FORCE_SHORT_TRANSFER) != 0) {
  1412. ForceShortTransfer = TRUE;
  1413. }
  1414. //
  1415. // Figure out the number of transfers needed. The first 8 bytes of a
  1416. // control transfer (the setup packet) are always on their own. Control
  1417. // transfers also have a status stage at the end.
  1418. //
  1419. TransferCount = 0;
  1420. if (Endpoint->TransferType == UsbTransferTypeControl) {
  1421. ASSERT(MaxBufferSize >= sizeof(USB_SETUP_PACKET));
  1422. MaxBufferSize -= sizeof(USB_SETUP_PACKET);
  1423. //
  1424. // Account for both the setup and status stage here.
  1425. //
  1426. TransferCount += 2;
  1427. }
  1428. //
  1429. // Create enough data transfers knowing that all submitted transfers will
  1430. // have virtually contiguous data. An extra page must be added to the max
  1431. // transfer size for the transfer calculation because a non page-aligned
  1432. // buffer could cause an EHCI max packet size aligned buffer to be split
  1433. // across two hardware transfers.
  1434. //
  1435. if (MaxBufferSize != 0) {
  1436. MaxBufferSize += (EHCI_PAGE_SIZE - 1);
  1437. TransferCount += MaxBufferSize / EHCI_TRANSFER_MAX_PACKET_SIZE;
  1438. if ((MaxBufferSize % EHCI_TRANSFER_MAX_PACKET_SIZE) != 0) {
  1439. TransferCount += 1;
  1440. }
  1441. //
  1442. // If a short transfer needs to be forced and the last packet might not
  1443. // be a short packet, then add another transfer to account for the
  1444. // forced zero length packet.
  1445. //
  1446. if ((ForceShortTransfer != FALSE) &&
  1447. (MaxBufferSize >= Endpoint->MaxPacketSize)) {
  1448. TransferCount += 1;
  1449. }
  1450. //
  1451. // Account for a USB transfer that will only send zero length packets and
  1452. // for control transfers that need to force a zero length packet in the
  1453. // data phase.
  1454. //
  1455. } else if ((ForceShortTransfer != FALSE) ||
  1456. (Endpoint->TransferType != UsbTransferTypeControl)) {
  1457. TransferCount += 1;
  1458. }
  1459. //
  1460. // Allocate the transfer set structure. Include space for all but the first
  1461. // EHCI_TRANSFER. The first transfer is swapped with the queue's dummy
  1462. // transfer and must be done with its own allocation.
  1463. //
  1464. AllocationSize = sizeof(EHCI_TRANSFER_SET);
  1465. if (TransferCount > 1) {
  1466. AllocationSize += sizeof(PEHCI_TRANSFER) * (TransferCount - 1);
  1467. AllocationSize += sizeof(EHCI_TRANSFER) * (TransferCount - 1);
  1468. }
  1469. TransferSet = MmAllocateNonPagedPool(AllocationSize, EHCI_ALLOCATION_TAG);
  1470. if (TransferSet == NULL) {
  1471. Status = STATUS_INSUFFICIENT_RESOURCES;
  1472. goto CreateTransferEnd;
  1473. }
  1474. RtlZeroMemory(TransferSet, AllocationSize);
  1475. TransferSet->TransferCount = TransferCount;
  1476. TransferSet->Endpoint = Endpoint;
  1477. TransferArray = (PEHCI_TRANSFER *)&(TransferSet->Transfer);
  1478. //
  1479. // Allocate the first transfer.
  1480. //
  1481. ASSERT(TransferCount >= 1);
  1482. Transfer = MmAllocateNonPagedPool(sizeof(EHCI_TRANSFER),
  1483. EHCI_ALLOCATION_TAG);
  1484. if (Transfer == NULL) {
  1485. Status = STATUS_INSUFFICIENT_RESOURCES;
  1486. goto CreateTransferEnd;
  1487. }
  1488. RtlZeroMemory(Transfer, sizeof(EHCI_TRANSFER));
  1489. Transfer->Set = TransferSet;
  1490. TransferArray[0] = Transfer;
  1491. //
  1492. // Create the new transfer's hardware descriptors while initializing the
  1493. // transfers that are included within the transfer set allocation.
  1494. //
  1495. Transfer = (PEHCI_TRANSFER)((PVOID)(TransferSet + 1) +
  1496. (sizeof(PEHCI_TRANSFER) * (TransferCount - 1)));
  1497. for (TransferIndex = 0; TransferIndex < TransferCount; TransferIndex += 1) {
  1498. HardwareTransfer = MmAllocateBlock(Controller->BlockAllocator,
  1499. &HardwareTransferPhysicalAddress);
  1500. if (HardwareTransfer == NULL) {
  1501. Status = STATUS_INSUFFICIENT_RESOURCES;
  1502. goto CreateTransferEnd;
  1503. }
  1504. if (TransferIndex != 0) {
  1505. TransferArray[TransferIndex] = Transfer;
  1506. Transfer->Set = TransferSet;
  1507. Transfer += 1;
  1508. }
  1509. TransferArray[TransferIndex]->HardwareTransfer = HardwareTransfer;
  1510. TransferArray[TransferIndex]->PhysicalAddress =
  1511. HardwareTransferPhysicalAddress;
  1512. ASSERT((HardwareTransferPhysicalAddress & EHCI_LINK_ADDRESS_MASK) ==
  1513. HardwareTransferPhysicalAddress);
  1514. }
  1515. Status = STATUS_SUCCESS;
  1516. CreateTransferEnd:
  1517. if (!KSUCCESS(Status)) {
  1518. if (TransferSet != NULL) {
  1519. TransferArray = (PEHCI_TRANSFER *)&(TransferSet->Transfer);
  1520. for (TransferIndex = 0;
  1521. TransferIndex < TransferSet->TransferCount;
  1522. TransferIndex += 1) {
  1523. Transfer = TransferArray[TransferIndex];
  1524. if (Transfer != NULL) {
  1525. if (Transfer->HardwareTransfer != NULL) {
  1526. MmFreeBlock(Controller->BlockAllocator,
  1527. Transfer->HardwareTransfer);
  1528. }
  1529. if (TransferIndex == 0) {
  1530. MmFreeNonPagedPool(Transfer);
  1531. }
  1532. }
  1533. }
  1534. MmFreeNonPagedPool(TransferSet);
  1535. TransferSet = NULL;
  1536. }
  1537. }
  1538. *TransferContext = TransferSet;
  1539. return Status;
  1540. }
  1541. VOID
  1542. EhcipDestroyTransfer (
  1543. PVOID HostControllerContext,
  1544. PVOID EndpointContext,
  1545. PVOID TransferContext
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. This routine destroys host controller structures associated with a USB
  1550. transfer.
  1551. Arguments:
  1552. HostControllerContext - Supplies the context pointer passed to the USB core
  1553. when the controller was created. This is used to identify the USB host
  1554. controller to the host controller driver.
  1555. EndpointContext - Supplies a pointer to the host controller context for the
  1556. endpoint this transfer belonged to.
  1557. TransferContext - Supplies the pointer provided to the USB core by the host
  1558. controller when the transfer was created.
  1559. Return Value:
  1560. None.
  1561. --*/
  1562. {
  1563. PEHCI_CONTROLLER Controller;
  1564. PEHCI_TRANSFER Transfer;
  1565. PEHCI_TRANSFER *TransferArray;
  1566. ULONG TransferIndex;
  1567. PEHCI_TRANSFER_SET TransferSet;
  1568. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  1569. TransferSet = (PEHCI_TRANSFER_SET)TransferContext;
  1570. //
  1571. // Free all transfers that were allocated.
  1572. //
  1573. TransferArray = (PEHCI_TRANSFER *)&(TransferSet->Transfer);
  1574. for (TransferIndex = 0;
  1575. TransferIndex < TransferSet->TransferCount;
  1576. TransferIndex += 1) {
  1577. Transfer = TransferArray[TransferIndex];
  1578. ASSERT(Transfer != NULL);
  1579. ASSERT(Transfer->HardwareTransfer != NULL);
  1580. ASSERT(Transfer->EndpointListEntry.Next == NULL);
  1581. MmFreeBlock(Controller->BlockAllocator, Transfer->HardwareTransfer);
  1582. if (TransferIndex == 0) {
  1583. MmFreeNonPagedPool(Transfer);
  1584. }
  1585. TransferArray[TransferIndex] = NULL;
  1586. }
  1587. MmFreeNonPagedPool(TransferSet);
  1588. return;
  1589. }
  1590. KSTATUS
  1591. EhcipSubmitTransfer (
  1592. PVOID HostControllerContext,
  1593. PVOID EndpointContext,
  1594. PUSB_TRANSFER_INTERNAL Transfer,
  1595. PVOID TransferContext
  1596. )
  1597. /*++
  1598. Routine Description:
  1599. This routine submits a transfer to the USB host controller for execution.
  1600. Arguments:
  1601. HostControllerContext - Supplies the context pointer passed to the USB core
  1602. when the controller was created. This is used to identify the USB host
  1603. controller to the host controller driver.
  1604. EndpointContext - Supplies the context pointer provided to the USB core by
  1605. the host controller when the endpoint was created.
  1606. Transfer - Supplies a pointer to the USB transfer to execute.
  1607. TransferContext - Supplies the pointer provided to the USB core by the host
  1608. controller when the transfer was created.
  1609. Return Value:
  1610. STATUS_SUCCESS if the transfer was successfully added to the hardware queue.
  1611. Failure codes if the transfer could not be added.
  1612. --*/
  1613. {
  1614. PEHCI_CONTROLLER Controller;
  1615. PEHCI_ENDPOINT Endpoint;
  1616. UCHAR QueueDeviceAddress;
  1617. KSTATUS Status;
  1618. PEHCI_TRANSFER_SET TransferSet;
  1619. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  1620. Endpoint = (PEHCI_ENDPOINT)EndpointContext;
  1621. TransferSet = (PEHCI_TRANSFER_SET)TransferContext;
  1622. TransferSet->UsbTransfer = Transfer;
  1623. //
  1624. // Before filling out and inserting transfers, take a look to see if the
  1625. // device address has changed. If it has, then it should still be in the
  1626. // enumeration phase, meaning there are no pending transfers floating
  1627. // around.
  1628. //
  1629. QueueDeviceAddress = Endpoint->Queue.HardwareQueueHead->Destination &
  1630. EHCI_QUEUE_DEVICE_ADDRESS_MASK;
  1631. if (Transfer->DeviceAddress != QueueDeviceAddress) {
  1632. ASSERT((QueueDeviceAddress == 0) && (Transfer->DeviceAddress != 0));
  1633. ASSERT(LIST_EMPTY(&(Endpoint->TransferListHead)) != FALSE);
  1634. Endpoint->Queue.HardwareQueueHead->Destination |=
  1635. Transfer->DeviceAddress & EHCI_QUEUE_DEVICE_ADDRESS_MASK;
  1636. }
  1637. //
  1638. // Initialize and submit the EHCI transfer set.
  1639. //
  1640. Status = EhcipSubmitTransferSet(Controller,
  1641. Endpoint,
  1642. TransferSet,
  1643. NULL,
  1644. FALSE);
  1645. return Status;
  1646. }
  1647. KSTATUS
  1648. EhcipSubmitPolledTransfer (
  1649. PVOID HostControllerContext,
  1650. PVOID EndpointContext,
  1651. PUSB_TRANSFER_INTERNAL Transfer,
  1652. PVOID TransferContext
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. This routine submits a transfer to the USB host controller for execution
  1657. and busy waits for it to complete. This routine is meant for crash dump
  1658. support to allow USB transfers when the system is fragile. As a result, it
  1659. forgoes acquiring the normal sequence of locks.
  1660. Arguments:
  1661. HostControllerContext - Supplies the context pointer passed to the USB core
  1662. when the controller was created. This is used to identify the USB host
  1663. controller to the host controller driver.
  1664. EndpointContext - Supplies the context pointer provided to the USB core by
  1665. the host controller when the endpoint was created.
  1666. Transfer - Supplies a pointer to the USB transfer to execute.
  1667. TransferContext - Supplies the pointer provided to the USB core by the host
  1668. controller when the transfer was created.
  1669. Return Value:
  1670. STATUS_SUCCESS if the transfer was successfully added to the hardware queue.
  1671. Failure codes if the transfer could not be added.
  1672. --*/
  1673. {
  1674. PEHCI_CONTROLLER Controller;
  1675. PEHCI_TRANSFER EhciTransfer;
  1676. PEHCI_ENDPOINT Endpoint;
  1677. volatile PULONG HardwareStatus;
  1678. PEHCI_TRANSFER_QUEUE Queue;
  1679. UCHAR QueueDeviceAddress;
  1680. BOOL RemoveSet;
  1681. KSTATUS Status;
  1682. ULONGLONG Timeout;
  1683. PEHCI_TRANSFER *TransferArray;
  1684. ULONG TransferCount;
  1685. ULONG TransferIndex;
  1686. PEHCI_TRANSFER_SET TransferSet;
  1687. ASSERT(KeGetRunLevel() == RunLevelHigh);
  1688. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  1689. Endpoint = (PEHCI_ENDPOINT)EndpointContext;
  1690. TransferSet = (PEHCI_TRANSFER_SET)TransferContext;
  1691. TransferSet->UsbTransfer = Transfer;
  1692. TransferArray = (PEHCI_TRANSFER *)&(TransferSet->Transfer);
  1693. //
  1694. // Then endpoint better not be in the middle of a transfer.
  1695. //
  1696. ASSERT(LIST_EMPTY(&(Endpoint->TransferListHead)) != FALSE);
  1697. //
  1698. // The queue head should be pointing at the dummy transfer and that dummy
  1699. // transfer should be the end of the line.
  1700. //
  1701. Queue = &(Endpoint->Queue);
  1702. ASSERT(Queue->HardwareQueueHead->TransferOverlay.NextTransfer ==
  1703. Queue->DummyTransfer->PhysicalAddress);
  1704. ASSERT(Queue->DummyTransfer->HardwareTransfer->NextTransfer ==
  1705. EHCI_LINK_TERMINATE);
  1706. ASSERT(Queue->DummyTransfer->HardwareTransfer->AlternateNextTransfer ==
  1707. EHCI_LINK_TERMINATE);
  1708. ASSERT(Queue->DummyTransfer->HardwareTransfer->Token ==
  1709. EHCI_TRANSFER_STATUS_HALTED);
  1710. //
  1711. // Before filling out and inserting transfers, assert that the device's
  1712. // address has not changed. Polled I/O should not be used during a device's
  1713. // enumeration phase.
  1714. //
  1715. QueueDeviceAddress = Queue->HardwareQueueHead->Destination &
  1716. EHCI_QUEUE_DEVICE_ADDRESS_MASK;
  1717. ASSERT(Transfer->DeviceAddress == QueueDeviceAddress);
  1718. //
  1719. // Initialize and submit the EHCI transfer set.
  1720. //
  1721. Status = EhcipSubmitTransferSet(Controller,
  1722. Endpoint,
  1723. TransferSet,
  1724. &TransferCount,
  1725. TRUE);
  1726. if (!KSUCCESS(Status)) {
  1727. return Status;
  1728. }
  1729. //
  1730. // The transfer is under way. Time to wait for it to complete. This
  1731. // requires a busy spin as threads cannot yield in the limited environment
  1732. // this routine is meant for.
  1733. //
  1734. Timeout = HlQueryTimeCounter() +
  1735. (HlQueryTimeCounterFrequency() * EHCI_POLLED_TRANSFER_TIMEOUT);
  1736. for (TransferIndex = 0; TransferIndex < TransferCount; TransferIndex += 1) {
  1737. EhciTransfer = TransferArray[TransferIndex];
  1738. HardwareStatus = &(EhciTransfer->HardwareTransfer->Token);
  1739. while ((*HardwareStatus & EHCI_TRANSFER_STATUS_ACTIVE) != 0) {
  1740. if (HlQueryTimeCounter() > Timeout) {
  1741. Transfer->Public.Status = STATUS_TIMEOUT;
  1742. goto SubmitPolledTransferEnd;
  1743. }
  1744. }
  1745. RemoveSet = EhcipProcessPotentiallyCompletedTransfer(EhciTransfer);
  1746. if (RemoveSet != FALSE) {
  1747. break;
  1748. }
  1749. }
  1750. EhcipRemoveCompletedTransferSet(Controller, TransferSet);
  1751. SubmitPolledTransferEnd:
  1752. return Transfer->Public.Status;
  1753. }
  1754. KSTATUS
  1755. EhcipSubmitTransferSet (
  1756. PEHCI_CONTROLLER Controller,
  1757. PEHCI_ENDPOINT Endpoint,
  1758. PEHCI_TRANSFER_SET TransferSet,
  1759. PULONG SubmittedTransferCount,
  1760. BOOL LockNotRequired
  1761. )
  1762. /*++
  1763. Routine Description:
  1764. This routine submits the given transfer set on the provided endpoint.
  1765. Arguments:
  1766. Controller - Supplies a pointer to the EHCI controller context.
  1767. Endpoint - Supplies a pointer to the endpoint that owns the transfer set.
  1768. TransferSet - Supplies a pointer to the transfer set to submit.
  1769. SubmittedTransferCount - Supplies an optional pointer to a boolean that
  1770. receives the total number of transfers submitted for the set.
  1771. LockNotRequired - Supplies a pointer indicating whether or not the
  1772. controllers lock is required when submitting. The default is FALSE.
  1773. Return Value:
  1774. Status code.
  1775. --*/
  1776. {
  1777. LIST_ENTRY ControllerList;
  1778. BOOL ControlTransfer;
  1779. BOOL DataToggle;
  1780. PEHCI_TRANSFER EhciTransfer;
  1781. LIST_ENTRY EndpointList;
  1782. PEHCI_TRANSFER FinalTransfer;
  1783. BOOL ForceShortTransfer;
  1784. BOOL LastTransfer;
  1785. ULONG Length;
  1786. ULONG Offset;
  1787. RUNLEVEL OldRunLevel;
  1788. ULONG PageOffset;
  1789. PEHCI_TRANSFER PreviousTransfer;
  1790. ULONG TotalLength;
  1791. PUSB_TRANSFER_INTERNAL Transfer;
  1792. PEHCI_TRANSFER *TransferArray;
  1793. ULONG TransferCount;
  1794. ULONG TransferIndex;
  1795. ControlTransfer = FALSE;
  1796. EhciTransfer = NULL;
  1797. FinalTransfer = NULL;
  1798. Transfer = TransferSet->UsbTransfer;
  1799. TransferArray = (PEHCI_TRANSFER *)&(TransferSet->Transfer);
  1800. //
  1801. // This queue had better be inserted.
  1802. //
  1803. ASSERT(Endpoint->Queue.ListEntry.Next != NULL);
  1804. //
  1805. // The transfer set had better not already be queued.
  1806. //
  1807. ASSERT((TransferSet->Flags & EHCI_TRANSFER_SET_FLAG_QUEUED) == 0);
  1808. //
  1809. // Initialize the state to queued. Old state from the last go-around should
  1810. // be wiped.
  1811. //
  1812. TransferSet->Flags = EHCI_TRANSFER_SET_FLAG_QUEUED;
  1813. //
  1814. // Assume that this is going to be a rousing success.
  1815. //
  1816. Transfer->Public.Status = STATUS_SUCCESS;
  1817. Transfer->Public.Error = UsbErrorNone;
  1818. //
  1819. // Determine the number of EHCI transfers needed for this USB transfer,
  1820. // and loop filling them out. This is necessary because the number of
  1821. // EHCI transfers per USB transfer is not constant; the system may re-use a
  1822. // transfer and change the length.
  1823. //
  1824. PageOffset = REMAINDER(Transfer->Public.BufferPhysicalAddress,
  1825. EHCI_PAGE_SIZE);
  1826. TransferCount = 0;
  1827. TotalLength = Transfer->Public.Length;
  1828. if (Endpoint->TransferType == UsbTransferTypeControl) {
  1829. ControlTransfer = TRUE;
  1830. ASSERT(TotalLength >= sizeof(USB_SETUP_PACKET));
  1831. TotalLength -= sizeof(USB_SETUP_PACKET);
  1832. //
  1833. // Account for both the setup and status transfers.
  1834. //
  1835. TransferCount += 2;
  1836. PageOffset += sizeof(USB_SETUP_PACKET);
  1837. PageOffset = REMAINDER(PageOffset, EHCI_PAGE_SIZE);
  1838. }
  1839. ForceShortTransfer = FALSE;
  1840. if ((Transfer->Public.Flags &
  1841. USB_TRANSFER_FLAG_FORCE_SHORT_TRANSFER) != 0) {
  1842. ForceShortTransfer = TRUE;
  1843. }
  1844. //
  1845. // If the USB transfer has data, the number of data transfers depends on
  1846. // the length of the data and the page offset for the start of the data.
  1847. //
  1848. if (TotalLength != 0) {
  1849. TotalLength += PageOffset;
  1850. TransferCount += TotalLength / EHCI_TRANSFER_MAX_PACKET_SIZE;
  1851. if ((TotalLength % EHCI_TRANSFER_MAX_PACKET_SIZE) != 0) {
  1852. TransferCount += 1;
  1853. }
  1854. //
  1855. // If a short transfer must be sent and the total length is a multiple,
  1856. // of the max packet size, then add an extra transfer to make sure a
  1857. // short transfer is sent.
  1858. //
  1859. if ((ForceShortTransfer != FALSE) &&
  1860. ((TotalLength % Endpoint->MaxPacketSize) == 0)) {
  1861. TransferCount += 1;
  1862. }
  1863. //
  1864. // Make sure at least one packet is set for zero-length packets. Unless a
  1865. // short transfer is being forced, exclude control transfers as there is
  1866. // just no data phase if this is the case.
  1867. //
  1868. } else if ((ForceShortTransfer != FALSE) ||
  1869. (Endpoint->TransferType != UsbTransferTypeControl)) {
  1870. TransferCount = 1;
  1871. }
  1872. ASSERT(TransferSet->TransferCount >= TransferCount);
  1873. //
  1874. // Now that the transfer count has been computed, save the ultimate
  1875. // transfer if it's a control request.
  1876. //
  1877. if (ControlTransfer != FALSE) {
  1878. FinalTransfer = TransferArray[TransferCount - 1];
  1879. }
  1880. PageOffset = REMAINDER(Transfer->Public.BufferPhysicalAddress,
  1881. EHCI_PAGE_SIZE);
  1882. DataToggle = FALSE;
  1883. Offset = 0;
  1884. LastTransfer = FALSE;
  1885. INITIALIZE_LIST_HEAD(&ControllerList);
  1886. INITIALIZE_LIST_HEAD(&EndpointList);
  1887. for (TransferIndex = 0; TransferIndex < TransferCount; TransferIndex += 1) {
  1888. //
  1889. // Calculate the length for this transfer descriptor.
  1890. //
  1891. Length = EHCI_TRANSFER_MAX_PACKET_SIZE - PageOffset;
  1892. if ((Offset + Length) > Transfer->Public.Length) {
  1893. Length = Transfer->Public.Length - Offset;
  1894. }
  1895. if (TransferIndex == (TransferCount - 1)) {
  1896. LastTransfer = TRUE;
  1897. }
  1898. if (ControlTransfer != FALSE) {
  1899. //
  1900. // The first part of a control transfer is the setup packet, which
  1901. // is always 8 bytes long.
  1902. //
  1903. if (Offset == 0) {
  1904. Length = sizeof(USB_SETUP_PACKET);
  1905. }
  1906. //
  1907. // The last part of a control transfer is the status phase and the
  1908. // length better be zero.
  1909. //
  1910. ASSERT((LastTransfer == FALSE) || (Length == 0));
  1911. }
  1912. ASSERT((Length != 0) ||
  1913. (LastTransfer != FALSE) ||
  1914. ((ForceShortTransfer != FALSE) && (ControlTransfer != FALSE)));
  1915. //
  1916. // Fill out this transfer descriptor.
  1917. //
  1918. EhciTransfer = TransferArray[TransferIndex];
  1919. EhcipFillOutTransferDescriptor(Controller,
  1920. EhciTransfer,
  1921. Offset,
  1922. Length,
  1923. LastTransfer,
  1924. &DataToggle,
  1925. FinalTransfer);
  1926. //
  1927. // Point the previous transfer to this transfer.
  1928. //
  1929. if (TransferIndex != 0) {
  1930. PreviousTransfer = TransferArray[TransferIndex - 1];
  1931. PreviousTransfer->HardwareTransfer->NextTransfer =
  1932. (ULONG)EhciTransfer->PhysicalAddress;
  1933. }
  1934. ASSERT(EhciTransfer->GlobalListEntry.Next == NULL);
  1935. INSERT_BEFORE(&(EhciTransfer->EndpointListEntry), &EndpointList);
  1936. INSERT_BEFORE(&(EhciTransfer->GlobalListEntry), &ControllerList);
  1937. //
  1938. // Advance the buffer position.
  1939. //
  1940. Offset += Length;
  1941. PageOffset += Length;
  1942. PageOffset = REMAINDER(PageOffset, EHCI_PAGE_SIZE);
  1943. }
  1944. //
  1945. // Acquire the lock, if requested. It did not need to be acquired for
  1946. // filling out the descriptors because no modifiable global or endpoint
  1947. // state was read or modified.
  1948. //
  1949. if (LockNotRequired == FALSE) {
  1950. OldRunLevel = EhcipAcquireControllerLock(Controller);
  1951. }
  1952. //
  1953. // Add the transfer to the endpoint and controller global lists by
  1954. // appending the locally created lists.
  1955. //
  1956. APPEND_LIST(&EndpointList, &(Endpoint->TransferListHead));
  1957. APPEND_LIST(&ControllerList, &(Controller->TransferListHead));
  1958. //
  1959. // The transfer is ready to go. Do the actual insertion.
  1960. //
  1961. if (Transfer->Type == UsbTransferTypeIsochronous) {
  1962. //
  1963. // TODO: Implement isochronous support.
  1964. //
  1965. ASSERT(FALSE);
  1966. return STATUS_NOT_IMPLEMENTED;
  1967. } else {
  1968. //
  1969. // Mark the last transfer, then submit the transfer array to the
  1970. // hardware.
  1971. //
  1972. ASSERT(TransferCount != 0);
  1973. TransferArray[TransferCount - 1]->LastTransfer = TRUE;
  1974. EhcipLinkTransferSetInHardware(TransferSet);
  1975. }
  1976. //
  1977. // All done. Release the lock, if necessary, and return.
  1978. //
  1979. if (LockNotRequired == FALSE) {
  1980. EhcipReleaseControllerLock(Controller, OldRunLevel);
  1981. }
  1982. if (SubmittedTransferCount != NULL) {
  1983. *SubmittedTransferCount = TransferCount;
  1984. }
  1985. return STATUS_SUCCESS;
  1986. }
  1987. KSTATUS
  1988. EhcipCancelTransfer (
  1989. PVOID HostControllerContext,
  1990. PVOID EndpointContext,
  1991. PUSB_TRANSFER_INTERNAL Transfer,
  1992. PVOID TransferContext
  1993. )
  1994. /*++
  1995. Routine Description:
  1996. This routine submits attempts to cancel a transfer that was previously
  1997. submitted for execution.
  1998. Arguments:
  1999. HostControllerContext - Supplies the context pointer passed to the USB core
  2000. when the controller was created. This is used to identify the USB host
  2001. controller to the host controller driver.
  2002. EndpointContext - Supplies the context pointer provided to the USB core by
  2003. the host controller when the endpoint was created.
  2004. Transfer - Supplies a pointer to the USB transfer to execute.
  2005. TransferContext - Supplies the pointer provided to the USB core by the host
  2006. controller when the transfer was created.
  2007. Return Value:
  2008. STATUS_SUCCESS if the transfer was successfully removed from the hardware
  2009. queue.
  2010. STATUS_TOO_LATE if the transfer had already completed.
  2011. Other failure codes if the transfer could not be cancelled but has not yet
  2012. completed.
  2013. --*/
  2014. {
  2015. ULONG CommandRegister;
  2016. PEHCI_CONTROLLER Controller;
  2017. ULONG HorizontalLink;
  2018. ULONG InterruptTreeLevel;
  2019. RUNLEVEL OldRunLevel;
  2020. ULONG PollRate;
  2021. PEHCI_TRANSFER_QUEUE Queue;
  2022. PEHCI_TRANSFER_QUEUE QueueBefore;
  2023. KSTATUS Status;
  2024. PEHCI_TRANSFER_SET TransferSet;
  2025. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  2026. Status = STATUS_SUCCESS;
  2027. TransferSet = (PEHCI_TRANSFER_SET)TransferContext;
  2028. ASSERT(TransferSet->UsbTransfer == Transfer);
  2029. //
  2030. // Lock the controller to manipulate lists.
  2031. //
  2032. OldRunLevel = EhcipAcquireControllerLock(Controller);
  2033. //
  2034. // If the transfer set is not currently queued, then there is nothing to be
  2035. // done.
  2036. //
  2037. if ((TransferSet->Flags & EHCI_TRANSFER_SET_FLAG_QUEUED) == 0) {
  2038. Status = STATUS_TOO_LATE;
  2039. goto CancelTransferEnd;
  2040. }
  2041. //
  2042. // Isochronous transfers are handled differently.
  2043. //
  2044. if (Transfer->Type == UsbTransferTypeIsochronous) {
  2045. ASSERT(FALSE);
  2046. Status = STATUS_NOT_IMPLEMENTED;
  2047. goto CancelTransferEnd;
  2048. //
  2049. // Remove the interrupt endpoint's queue head from the synchronous schedule.
  2050. //
  2051. } else if (Transfer->Type == UsbTransferTypeInterrupt) {
  2052. Queue = &(TransferSet->Endpoint->Queue);
  2053. //
  2054. // This code assumes that there is only one transfer on an interrupt
  2055. // endpoint.
  2056. //
  2057. ASSERT(Queue->ListEntry.Next != NULL);
  2058. QueueBefore = LIST_VALUE(Queue->ListEntry.Previous,
  2059. EHCI_TRANSFER_QUEUE,
  2060. ListEntry);
  2061. HlWriteRegister32(&(QueueBefore->HardwareQueueHead->HorizontalLink),
  2062. Queue->HardwareQueueHead->HorizontalLink);
  2063. LIST_REMOVE(&(Queue->ListEntry));
  2064. Queue->ListEntry.Next = NULL;
  2065. //
  2066. // Now release the lock and wait a full frame to make sure that the
  2067. // periodic schedule has moved beyond this queue head. This simple wait
  2068. // accounts for split transactions, but will need to be updated if
  2069. // Frame Split Transaction Nodes are supported.
  2070. //
  2071. EhcipReleaseControllerLock(Controller, OldRunLevel);
  2072. KeDelayExecution(FALSE, FALSE, 1 * MICROSECONDS_PER_MILLISECOND);
  2073. //
  2074. // Reacquire the lock to complete the cancellation.
  2075. //
  2076. OldRunLevel = EhcipAcquireControllerLock(Controller);
  2077. ASSERT(Queue->ListEntry.Next == NULL);
  2078. //
  2079. // If the interrupt was completed while the lock was released, then
  2080. // return that it was too late to cancel.
  2081. //
  2082. if ((TransferSet->Flags & EHCI_TRANSFER_SET_FLAG_QUEUED) == 0) {
  2083. Status = STATUS_TOO_LATE;
  2084. //
  2085. // Otherwise mark the transfer as cancelled, remove the transfer set
  2086. // and complete the callback.
  2087. //
  2088. } else {
  2089. Transfer->Public.Status = STATUS_OPERATION_CANCELLED;
  2090. Transfer->Public.Error = UsbErrorTransferCancelled;
  2091. EhcipRemoveCancelledTransferSet(Controller, TransferSet);
  2092. UsbHostProcessCompletedTransfer(TransferSet->UsbTransfer);
  2093. }
  2094. //
  2095. // Add the queue back into the periodic schedule.
  2096. //
  2097. PollRate = TransferSet->Endpoint->PollRate;
  2098. ASSERT(PollRate != 0);
  2099. InterruptTreeLevel = EHCI_PERIODIC_SCHEDULE_TREE_DEPTH - 1;
  2100. while (((PollRate & 0x1) == 0) && (InterruptTreeLevel != 0)) {
  2101. PollRate = PollRate >> 1;
  2102. InterruptTreeLevel -= 1;
  2103. }
  2104. ASSERT(InterruptTreeLevel < EHCI_PERIODIC_SCHEDULE_TREE_DEPTH);
  2105. QueueBefore = &(Controller->InterruptTree[InterruptTreeLevel]);
  2106. INSERT_AFTER(&(Queue->ListEntry), &(QueueBefore->ListEntry));
  2107. Queue->HardwareQueueHead->HorizontalLink =
  2108. QueueBefore->HardwareQueueHead->HorizontalLink;
  2109. HorizontalLink = (ULONG)Queue->PhysicalAddress;
  2110. ASSERT((HorizontalLink & (~EHCI_LINK_ADDRESS_MASK)) == 0);
  2111. HorizontalLink |= EHCI_LINK_TYPE_QUEUE_HEAD;
  2112. HlWriteRegister32(&(QueueBefore->HardwareQueueHead->HorizontalLink),
  2113. HorizontalLink);
  2114. //
  2115. // Remove bulk and control endpoint's queue head from the asynchronous
  2116. // schedule. The transfer set will be fully removed from the queue head
  2117. // once the interrupt for async-on-advance has fired.
  2118. //
  2119. } else {
  2120. ASSERT((Transfer->Type == UsbTransferTypeControl) ||
  2121. (Transfer->Type == UsbTransferTypeBulk));
  2122. //
  2123. // Mark that the transfer set is in the process of being cancelled.
  2124. //
  2125. TransferSet->Flags |= EHCI_TRANSFER_SET_FLAG_CANCELLING;
  2126. //
  2127. // If the queue's async on advance state is already set, that means it
  2128. // is already out of the hardware's queue head and on a list. This
  2129. // transfer will be handled by interrupt processing.
  2130. //
  2131. Queue = &(TransferSet->Endpoint->Queue);
  2132. if (Queue->AsyncOnAdvanceCancel != FALSE) {
  2133. goto CancelTransferEnd;
  2134. }
  2135. Queue->AsyncOnAdvanceCancel = TRUE;
  2136. //
  2137. // Otherwise the queue must be removed from the hardware list.
  2138. //
  2139. QueueBefore = LIST_VALUE(Queue->ListEntry.Previous,
  2140. EHCI_TRANSFER_QUEUE,
  2141. ListEntry);
  2142. HlWriteRegister32(&(QueueBefore->HardwareQueueHead->HorizontalLink),
  2143. Queue->HardwareQueueHead->HorizontalLink);
  2144. LIST_REMOVE(&(Queue->ListEntry));
  2145. //
  2146. // If the asynchronous on advance ready list is empty, then add this
  2147. // queue head to the ready list and ring the doorbell.
  2148. //
  2149. if (LIST_EMPTY(&(Controller->AsyncOnAdvanceReadyListHead)) != FALSE) {
  2150. INSERT_BEFORE(&(Queue->ListEntry),
  2151. &(Controller->AsyncOnAdvanceReadyListHead));
  2152. CommandRegister = Controller->CommandRegister;
  2153. CommandRegister |= EHCI_COMMAND_INTERRUPT_ON_ASYNC_ADVANCE;
  2154. EHCI_WRITE_REGISTER(Controller,
  2155. EhciRegisterUsbCommand,
  2156. CommandRegister);
  2157. //
  2158. // Otherwise the doorbell has already been rung. This queue head will
  2159. // have to wait for the next chance to ring it. Put it on the pending
  2160. // list.
  2161. //
  2162. } else {
  2163. INSERT_BEFORE(&(Queue->ListEntry),
  2164. &(Controller->AsyncOnAdvancePendingListHead));
  2165. }
  2166. }
  2167. CancelTransferEnd:
  2168. //
  2169. // Release the lock and return.
  2170. //
  2171. EhcipReleaseControllerLock(Controller, OldRunLevel);
  2172. return Status;
  2173. }
  2174. KSTATUS
  2175. EhcipGetRootHubStatus (
  2176. PVOID HostControllerContext,
  2177. PUSB_HUB_STATUS HubStatus
  2178. )
  2179. /*++
  2180. Routine Description:
  2181. This routine queries the host controller for the status of the root hub.
  2182. Arguments:
  2183. HostControllerContext - Supplies the context pointer passed to the USB core
  2184. when the controller was created. This is used to identify the USB host
  2185. controller to the host controller driver.
  2186. HubStatus - Supplies a pointer where the host controller should fill out
  2187. the root hub status.
  2188. Return Value:
  2189. STATUS_SUCCESS if the hub status was successfully queried.
  2190. Failure codes if the status could not be queried.
  2191. --*/
  2192. {
  2193. USHORT ChangeBits;
  2194. PEHCI_CONTROLLER Controller;
  2195. USHORT HardwareStatus;
  2196. ULONG PortIndex;
  2197. PUSB_PORT_STATUS PortStatus;
  2198. USHORT SoftwareStatus;
  2199. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  2200. ASSERT(Controller->PortCount != 0);
  2201. ASSERT(HubStatus->PortStatus != NULL);
  2202. for (PortIndex = 0; PortIndex < Controller->PortCount; PortIndex += 1) {
  2203. HardwareStatus = EHCI_READ_PORT_REGISTER(Controller, PortIndex);
  2204. //
  2205. // Set the corresponding software bits. If the owner bit is set,
  2206. // pretend like there's nothing here.
  2207. //
  2208. SoftwareStatus = 0;
  2209. if (((HardwareStatus & EHCI_PORT_CONNECT_STATUS) != 0) &&
  2210. ((HardwareStatus & EHCI_PORT_OWNER) == 0)) {
  2211. SoftwareStatus |= USB_PORT_STATUS_CONNECTED;
  2212. //
  2213. // If the port is presenting a K state, then it's a low speed.
  2214. // Otherwise, assume that if it hasn't yet been passed off to the
  2215. // companion controller that it's a high speed device. If it turns
  2216. // out to be a full speed device, it will eventually get
  2217. // disconnected from here and passed on to the companion controller.
  2218. //
  2219. if ((HardwareStatus & EHCI_PORT_LINE_STATE_MASK) ==
  2220. EHCI_PORT_LINE_STATE_K) {
  2221. HubStatus->PortDeviceSpeed[PortIndex] = UsbDeviceSpeedLow;
  2222. //
  2223. // Release ownership of this device.
  2224. //
  2225. HardwareStatus |= EHCI_PORT_OWNER;
  2226. EHCI_WRITE_PORT_REGISTER(Controller, PortIndex, HardwareStatus);
  2227. HardwareStatus = 0;
  2228. SoftwareStatus = 0;
  2229. } else {
  2230. HubStatus->PortDeviceSpeed[PortIndex] = UsbDeviceSpeedHigh;
  2231. }
  2232. }
  2233. if ((HardwareStatus & EHCI_PORT_ENABLE) != 0) {
  2234. SoftwareStatus |= USB_PORT_STATUS_ENABLED;
  2235. }
  2236. if ((HardwareStatus & EHCI_PORT_RESET) != 0) {
  2237. SoftwareStatus |= USB_PORT_STATUS_RESET;
  2238. }
  2239. if ((HardwareStatus & EHCI_PORT_OVER_CURRENT_ACTIVE) != 0) {
  2240. SoftwareStatus |= USB_PORT_STATUS_OVER_CURRENT;
  2241. }
  2242. //
  2243. // If the new software status is different from the current software
  2244. // status, record the change bits and set the new software status.
  2245. //
  2246. PortStatus = &(HubStatus->PortStatus[PortIndex]);
  2247. if (SoftwareStatus != PortStatus->Status) {
  2248. ChangeBits = SoftwareStatus ^ PortStatus->Status;
  2249. //
  2250. // Because the change bits correspond with the status bits 1-to-1,
  2251. // just OR in the change bits.
  2252. //
  2253. PortStatus->Change |= ChangeBits;
  2254. PortStatus->Status = SoftwareStatus;
  2255. }
  2256. //
  2257. // Acknowledge the over current change bit if it is set.
  2258. //
  2259. if ((HardwareStatus & EHCI_PORT_OVER_CURRENT_CHANGE) != 0) {
  2260. PortStatus->Change |= USB_PORT_STATUS_CHANGE_OVER_CURRENT;
  2261. EHCI_WRITE_PORT_REGISTER(Controller, PortIndex, HardwareStatus);
  2262. }
  2263. //
  2264. // Acknowledge the port connection status change in the hardware and
  2265. // set the bit in the software's port status change bits. It may be
  2266. // that the port transitioned from connected to connected and the above
  2267. // checks did not pick up the change.
  2268. //
  2269. if ((HardwareStatus & EHCI_PORT_CONNECT_STATUS_CHANGE) != 0) {
  2270. PortStatus->Change |= USB_PORT_STATUS_CHANGE_CONNECTED;
  2271. //
  2272. // If the port is not in the middle of a reset, clear the connect
  2273. // status change bit in the hardware by setting it to 1. Resets
  2274. // clear the connect status changed bit.
  2275. //
  2276. if ((HardwareStatus & EHCI_PORT_RESET) == 0) {
  2277. EHCI_WRITE_PORT_REGISTER(Controller, PortIndex, HardwareStatus);
  2278. }
  2279. }
  2280. if ((EhciDebugFlags & EHCI_DEBUG_PORTS) != 0) {
  2281. RtlDebugPrint(
  2282. "EHCI: Controller 0x%x Port %d Status 0x%x. "
  2283. "Connected %d, Owner %d, Enabled %d, Reset %d, "
  2284. "Changed %d.\n",
  2285. Controller,
  2286. PortIndex,
  2287. HardwareStatus,
  2288. (HardwareStatus & EHCI_PORT_CONNECT_STATUS) != 0,
  2289. (HardwareStatus & EHCI_PORT_OWNER) != 0,
  2290. (HardwareStatus & EHCI_PORT_ENABLE) != 0,
  2291. (HardwareStatus & EHCI_PORT_RESET) != 0,
  2292. (HardwareStatus & EHCI_PORT_CONNECT_STATUS_CHANGE) != 0);
  2293. }
  2294. }
  2295. return STATUS_SUCCESS;
  2296. }
  2297. KSTATUS
  2298. EhcipSetRootHubStatus (
  2299. PVOID HostControllerContext,
  2300. PUSB_HUB_STATUS HubStatus
  2301. )
  2302. /*++
  2303. Routine Description:
  2304. This routine sets the state of the root hub in the USB host controller. It
  2305. looks at the status change bits for each port in order to determine what
  2306. needs to be set.
  2307. Arguments:
  2308. HostControllerContext - Supplies the context pointer passed to the USB core
  2309. when the controller was created. This is used to identify the USB host
  2310. controller to the host controller driver.
  2311. HubStatus - Supplies a pointer to the status that should be set in the root
  2312. hub.
  2313. Return Value:
  2314. STATUS_SUCCESS if the hub state was successfully programmed into the device.
  2315. Failure codes if the status could not be set.
  2316. --*/
  2317. {
  2318. PEHCI_CONTROLLER Controller;
  2319. USHORT HardwareStatus;
  2320. USHORT OriginalHardwareStatus;
  2321. ULONG PortIndex;
  2322. PUSB_PORT_STATUS PortStatus;
  2323. Controller = (PEHCI_CONTROLLER)HostControllerContext;
  2324. ASSERT(Controller->PortCount != 0);
  2325. //
  2326. // The supplied hub status has change bits indicate what is to be newly set
  2327. // in each port's software status. This routine will clear any change bits
  2328. // it handles.
  2329. //
  2330. for (PortIndex = 0; PortIndex < Controller->PortCount; PortIndex += 1) {
  2331. //
  2332. // The caller is required to notify the routine about what needs to be
  2333. // set by updating the change bits. If there are not changed bits, then
  2334. // skip the port.
  2335. //
  2336. PortStatus = &(HubStatus->PortStatus[PortIndex]);
  2337. if (PortStatus->Change == 0) {
  2338. continue;
  2339. }
  2340. OriginalHardwareStatus = EHCI_READ_PORT_REGISTER(Controller, PortIndex);
  2341. HardwareStatus = OriginalHardwareStatus;
  2342. //
  2343. // Leave the port alone if it's not owned by EHCI and there isn't an
  2344. // active reset.
  2345. //
  2346. if (((HardwareStatus & EHCI_PORT_OWNER) != 0) &&
  2347. ((PortStatus->Status & USB_PORT_STATUS_RESET) == 0)) {
  2348. //
  2349. // Clear any change bits that this routine would otherwise handle.
  2350. // This acknowledges that they were dealt with (i.e. this port is
  2351. // dead and there is nothing anyone else should do with the change
  2352. // bits later).
  2353. //
  2354. PortStatus->Change &= ~(USB_PORT_STATUS_CHANGE_RESET |
  2355. USB_PORT_STATUS_CHANGE_ENABLED |
  2356. USB_PORT_STATUS_CHANGE_SUSPENDED);
  2357. continue;
  2358. }
  2359. //
  2360. // Clear out the bits that may potentially be adjusted.
  2361. //
  2362. HardwareStatus &= ~(EHCI_PORT_ENABLE | EHCI_PORT_RESET |
  2363. EHCI_PORT_SUSPEND | EHCI_PORT_INDICATOR_MASK |
  2364. EHCI_PORT_OWNER);
  2365. //
  2366. // Set the hardware bits according to what's passed in.
  2367. //
  2368. if ((PortStatus->Change & USB_PORT_STATUS_CHANGE_ENABLED) != 0) {
  2369. //
  2370. // If the port is being enabled, then set the enabled bits, power
  2371. // it on and turn on the green indicator.
  2372. //
  2373. if ((PortStatus->Status & USB_PORT_STATUS_ENABLED) != 0) {
  2374. HardwareStatus |= EHCI_PORT_ENABLE |
  2375. EHCI_PORT_INDICATOR_GREEN |
  2376. EHCI_PORT_POWER;
  2377. }
  2378. //
  2379. // Acknowledge that the enable bit was handled.
  2380. //
  2381. PortStatus->Change &= ~USB_PORT_STATUS_CHANGE_ENABLED;
  2382. }
  2383. //
  2384. // The EHCI spec says that whenever the reset bit is set, the enable
  2385. // bit must be cleared. If the port is high speed, the enable bit will
  2386. // be set automatically once the reset completes.
  2387. //
  2388. if ((PortStatus->Change & USB_PORT_STATUS_CHANGE_RESET) != 0) {
  2389. if ((PortStatus->Status & USB_PORT_STATUS_RESET) != 0) {
  2390. HardwareStatus |= EHCI_PORT_RESET;
  2391. HardwareStatus &= ~EHCI_PORT_ENABLE;
  2392. }
  2393. //
  2394. // Acknowledge that the reset bit was handled.
  2395. //
  2396. PortStatus->Change &= ~USB_PORT_STATUS_CHANGE_RESET;
  2397. }
  2398. //
  2399. // Suspend the port if requested.
  2400. //
  2401. if ((PortStatus->Change & USB_PORT_STATUS_CHANGE_SUSPENDED) != 0) {
  2402. if ((PortStatus->Status & USB_PORT_STATUS_SUSPENDED) != 0) {
  2403. HardwareStatus |= EHCI_PORT_SUSPEND;
  2404. }
  2405. PortStatus->Change &= ~USB_PORT_STATUS_CHANGE_SUSPENDED;
  2406. }
  2407. //
  2408. // Write out the new value if it is different than the old one.
  2409. //
  2410. if (HardwareStatus != OriginalHardwareStatus) {
  2411. EHCI_WRITE_PORT_REGISTER(Controller, PortIndex, HardwareStatus);
  2412. }
  2413. //
  2414. // If reset was set, wait the required amount of time and then clear
  2415. // the reset bit, as if this were a hub and it was cleared
  2416. // automatically.
  2417. //
  2418. if ((HardwareStatus & EHCI_PORT_RESET) != 0) {
  2419. HlBusySpin(20 * 1000);
  2420. HardwareStatus = EHCI_READ_PORT_REGISTER(Controller, PortIndex);
  2421. HardwareStatus &= ~EHCI_PORT_RESET;
  2422. EHCI_WRITE_PORT_REGISTER(Controller, PortIndex, HardwareStatus);
  2423. //
  2424. // Wait a further 5ms (the EHCI spec says the host controller has
  2425. // to have it done in 2ms), and if the port is not enabled, then
  2426. // it's a full speed device, and should be handed off to the
  2427. // companion controller.
  2428. //
  2429. HlBusySpin(5 * 1000);
  2430. HardwareStatus = EHCI_READ_PORT_REGISTER(Controller, PortIndex);
  2431. if ((HardwareStatus & EHCI_PORT_ENABLE) == 0) {
  2432. HardwareStatus |= EHCI_PORT_OWNER;
  2433. EHCI_WRITE_PORT_REGISTER(Controller, PortIndex, HardwareStatus);
  2434. }
  2435. }
  2436. }
  2437. return STATUS_SUCCESS;
  2438. }
  2439. RUNLEVEL
  2440. EhcipAcquireControllerLock (
  2441. PEHCI_CONTROLLER Controller
  2442. )
  2443. /*++
  2444. Routine Description:
  2445. This routine acquires the given EHCI controller's lock at dispatch level.
  2446. Arguments:
  2447. Controller - Supplies a pointer to the controller to lock.
  2448. Return Value:
  2449. Returns the previous run-level, which must be passed in when the controller
  2450. is unlocked.
  2451. --*/
  2452. {
  2453. RUNLEVEL OldRunLevel;
  2454. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  2455. KeAcquireSpinLock(&(Controller->Lock));
  2456. return OldRunLevel;
  2457. }
  2458. VOID
  2459. EhcipReleaseControllerLock (
  2460. PEHCI_CONTROLLER Controller,
  2461. RUNLEVEL OldRunLevel
  2462. )
  2463. /*++
  2464. Routine Description:
  2465. This routine releases the given EHCI controller's lock, and returns the
  2466. run-level to its previous value.
  2467. Arguments:
  2468. Controller - Supplies a pointer to the controller to unlock.
  2469. OldRunLevel - Supplies the original run level returned when the lock was
  2470. acquired.
  2471. Return Value:
  2472. None.
  2473. --*/
  2474. {
  2475. KeReleaseSpinLock(&(Controller->Lock));
  2476. KeLowerRunLevel(OldRunLevel);
  2477. return;
  2478. }
  2479. VOID
  2480. EhcipProcessInterrupt (
  2481. PEHCI_CONTROLLER Controller,
  2482. ULONG PendingStatusBits
  2483. )
  2484. /*++
  2485. Routine Description:
  2486. This routine performs the work associated with receiving an EHCI interrupt.
  2487. This routine runs at dispatch level.
  2488. Arguments:
  2489. Controller - Supplies a pointer to the controller.
  2490. PendingStatusBits - Supplies the pending status bits to service.
  2491. Return Value:
  2492. None.
  2493. --*/
  2494. {
  2495. PLIST_ENTRY CurrentEntry;
  2496. PEHCI_TRANSFER NextTransfer;
  2497. RUNLEVEL OldRunLevel;
  2498. BOOL RemoveSet;
  2499. PEHCI_TRANSFER Transfer;
  2500. PEHCI_TRANSFER_SET TransferSet;
  2501. //
  2502. // Lock the controller and loop until this routine has caught up with the
  2503. // interrupts.
  2504. //
  2505. OldRunLevel = EhcipAcquireControllerLock(Controller);
  2506. //
  2507. // If the interrupt was a device change interrupt, then notify the USB core
  2508. // that the root hub noticed a device change.
  2509. //
  2510. if ((PendingStatusBits & EHCI_STATUS_PORT_CHANGE_DETECT) != 0) {
  2511. UsbHostNotifyPortChange(Controller->UsbCoreHandle);
  2512. }
  2513. //
  2514. // TODO: Go through the isochronous transfers.
  2515. //
  2516. ASSERT(LIST_EMPTY(&(Controller->IsochronousTransferListHead)) != FALSE);
  2517. //
  2518. // Loop through every transfer in the schedule.
  2519. //
  2520. CurrentEntry = Controller->TransferListHead.Next;
  2521. while (CurrentEntry != &(Controller->TransferListHead)) {
  2522. ASSERT((CurrentEntry != NULL) && (CurrentEntry->Next != NULL));
  2523. Transfer = LIST_VALUE(CurrentEntry, EHCI_TRANSFER, GlobalListEntry);
  2524. CurrentEntry = CurrentEntry->Next;
  2525. RemoveSet = EhcipProcessPotentiallyCompletedTransfer(Transfer);
  2526. if (RemoveSet != FALSE) {
  2527. //
  2528. // Get the current entry off of this set, as several transfers
  2529. // may be removed here.
  2530. //
  2531. TransferSet = Transfer->Set;
  2532. if (CurrentEntry != &(Controller->TransferListHead)) {
  2533. NextTransfer = LIST_VALUE(CurrentEntry,
  2534. EHCI_TRANSFER,
  2535. GlobalListEntry);
  2536. while (NextTransfer->Set == TransferSet) {
  2537. CurrentEntry = CurrentEntry->Next;
  2538. if (CurrentEntry == &(Controller->TransferListHead)) {
  2539. break;
  2540. }
  2541. NextTransfer = LIST_VALUE(CurrentEntry,
  2542. EHCI_TRANSFER,
  2543. GlobalListEntry);
  2544. }
  2545. }
  2546. //
  2547. // Remove the transfer set from the owning endpoint's queue and
  2548. // call the completion routine.
  2549. //
  2550. EhcipRemoveCompletedTransferSet(Controller, TransferSet);
  2551. UsbHostProcessCompletedTransfer(TransferSet->UsbTransfer);
  2552. }
  2553. }
  2554. //
  2555. // If the interrupt was the "interrupt on asynchronous schedule advance"
  2556. // doorbell, then process the ready list, knowing that hardware is no
  2557. // longer using it. Run this after processing all the transfers in case a
  2558. // transfer finished before any of the queues were removed.
  2559. //
  2560. if ((PendingStatusBits & EHCI_STATUS_INTERRUPT_ON_ASYNC_ADVANCE) != 0) {
  2561. EhcipProcessAsyncOnAdvanceInterrupt(Controller);
  2562. }
  2563. //
  2564. // Release the lock.
  2565. //
  2566. EhcipReleaseControllerLock(Controller, OldRunLevel);
  2567. return;
  2568. }
  2569. VOID
  2570. EhcipFillOutTransferDescriptor (
  2571. PEHCI_CONTROLLER Controller,
  2572. PEHCI_TRANSFER EhciTransfer,
  2573. ULONG Offset,
  2574. ULONG Length,
  2575. BOOL LastTransfer,
  2576. PBOOL DataToggle,
  2577. PEHCI_TRANSFER AlternateNextTransfer
  2578. )
  2579. /*++
  2580. Routine Description:
  2581. This routine fills out an EHCI transfer descriptor.
  2582. Arguments:
  2583. Controller - Supplies a pointer to the EHCI controller.
  2584. EhciTransfer - Supplies a pointer to EHCI's transfer descriptor information.
  2585. Offset - Supplies the offset from the public transfer physical address that
  2586. this transfer descriptor should be initialize to.
  2587. Length - Supplies the length of the transfer, in bytes.
  2588. LastTransfer - Supplies a boolean indicating if this transfer descriptor
  2589. represents the last transfer in a set. For control transfers, this is
  2590. the status phase where the in/out is reversed and the length had better
  2591. be zero.
  2592. DataToggle - Supplies a pointer to a boolean that indicates the current
  2593. data toggle status for the overall transfer. This routine will update
  2594. the data toggle upon return to indicate what the data toggle should be
  2595. for the next transfer to be initialized.
  2596. AlternateNextTransfer - Supplies an optional pointer to a transfer to move
  2597. to if this transfer is an IN and comes up short of its max transfer
  2598. length.
  2599. Return Value:
  2600. None.
  2601. --*/
  2602. {
  2603. ULONG BufferIndex;
  2604. ULONG BufferPhysical;
  2605. ULONG EndAddress;
  2606. PEHCI_ENDPOINT Endpoint;
  2607. PEHCI_TRANSFER_DESCRIPTOR HardwareTransfer;
  2608. ULONG Token;
  2609. PUSB_TRANSFER_INTERNAL Transfer;
  2610. PEHCI_TRANSFER_SET TransferSet;
  2611. TransferSet = EhciTransfer->Set;
  2612. Endpoint = TransferSet->Endpoint;
  2613. Transfer = TransferSet->UsbTransfer;
  2614. EhciTransfer->LastTransfer = FALSE;
  2615. HardwareTransfer = EhciTransfer->HardwareTransfer;
  2616. //
  2617. // Set up the buffer pointers.
  2618. //
  2619. BufferPhysical = Transfer->Public.BufferPhysicalAddress + Offset;
  2620. EndAddress = BufferPhysical + Length;
  2621. ASSERT((REMAINDER(BufferPhysical, EHCI_PAGE_SIZE) + Length) <=
  2622. EHCI_TRANSFER_MAX_PACKET_SIZE);
  2623. for (BufferIndex = 0;
  2624. BufferIndex < EHCI_TRANSFER_POINTER_COUNT;
  2625. BufferIndex += 1) {
  2626. if (BufferPhysical < EndAddress) {
  2627. HardwareTransfer->BufferPointer[BufferIndex] = BufferPhysical;
  2628. BufferPhysical += EHCI_PAGE_SIZE;
  2629. BufferPhysical = ALIGN_RANGE_DOWN(BufferPhysical, EHCI_PAGE_SIZE);
  2630. } else {
  2631. HardwareTransfer->BufferPointer[BufferIndex] = 0;
  2632. }
  2633. HardwareTransfer->BufferAddressHigh[BufferIndex] = 0;
  2634. }
  2635. //
  2636. // Figure out the token value for this transfer descriptor.
  2637. //
  2638. EhciTransfer->TransferLength = Length;
  2639. Token = (Length << EHCI_TRANSFER_TOTAL_BYTES_SHIFT);
  2640. Token |= EHCI_TRANSFER_3_ERRORS_ALLOWED;
  2641. Token |= EHCI_TRANSFER_STATUS_ACTIVE;
  2642. //
  2643. // The first packet in a control transfer is always a setup packet. It does
  2644. // not have the data toggle set, but prepares for the next transfer to have
  2645. // the bit set by setting the data toggle to true.
  2646. //
  2647. if ((Endpoint->TransferType == UsbTransferTypeControl) && (Offset == 0)) {
  2648. Token |= EHCI_TRANSFER_PID_CODE_SETUP;
  2649. *DataToggle = TRUE;
  2650. //
  2651. // Do it backwards if this is the status phase. Status phases always have
  2652. // a data toggle of 1. The data toggle boolean does not need to be updated
  2653. // as this is always the last transfer.
  2654. //
  2655. } else if ((Endpoint->TransferType == UsbTransferTypeControl) &&
  2656. (LastTransfer != FALSE)) {
  2657. Token |= EHCI_TRANSFER_DATA_TOGGLE;
  2658. ASSERT((Length == 0) &&
  2659. (Endpoint->TransferType == UsbTransferTypeControl));
  2660. if (Transfer->Public.Direction == UsbTransferDirectionIn) {
  2661. Token |= EHCI_TRANSFER_PID_CODE_OUT;
  2662. } else {
  2663. ASSERT(Transfer->Public.Direction == UsbTransferDirectionOut);
  2664. Token |= EHCI_TRANSFER_PID_CODE_IN;
  2665. }
  2666. //
  2667. // Not setup and not status, fill this out like a normal descriptor.
  2668. //
  2669. } else {
  2670. if (Transfer->Public.Direction == UsbTransferDirectionIn) {
  2671. Token |= EHCI_TRANSFER_PID_CODE_IN;
  2672. } else {
  2673. ASSERT(Transfer->Public.Direction == UsbTransferDirectionOut);
  2674. Token |= EHCI_TRANSFER_PID_CODE_OUT;
  2675. }
  2676. //
  2677. // The host controller keeps track of the data toggle bits for control
  2678. // transfers (rather than the hardware), so set the data toggle bit
  2679. // accordingly and update the data toggle boolean for the next
  2680. // transfer.
  2681. //
  2682. if (Endpoint->TransferType == UsbTransferTypeControl) {
  2683. if (*DataToggle != FALSE) {
  2684. Token |= EHCI_TRANSFER_DATA_TOGGLE;
  2685. *DataToggle = FALSE;
  2686. } else {
  2687. *DataToggle = TRUE;
  2688. }
  2689. }
  2690. }
  2691. ASSERT((Endpoint->Speed == UsbDeviceSpeedLow) ||
  2692. (Endpoint->Speed == UsbDeviceSpeedFull) ||
  2693. (Endpoint->Speed == UsbDeviceSpeedHigh));
  2694. //
  2695. // Don't set the interrupt flag if 1) This is not the last descriptor or
  2696. // 2) The caller requested not to.
  2697. //
  2698. if ((LastTransfer != FALSE) &&
  2699. ((Transfer->Public.Flags &
  2700. USB_TRANSFER_FLAG_NO_INTERRUPT_ON_COMPLETION) == 0)) {
  2701. Token |= EHCI_TRANSFER_INTERRUPT_ON_COMPLETE;
  2702. }
  2703. HardwareTransfer->Token = Token;
  2704. if ((EhciDebugFlags & EHCI_DEBUG_TRANSFERS) != 0) {
  2705. RtlDebugPrint("EHCI: Adding transfer (0x%08x) PA 0x%I64x to endpoint "
  2706. "(0x%08x): Token 0x%08x.\n",
  2707. EhciTransfer,
  2708. EhciTransfer->PhysicalAddress,
  2709. Endpoint,
  2710. EhciTransfer->HardwareTransfer->Token);
  2711. }
  2712. //
  2713. // Set up the link pointers of the transfer descriptor. With the exception
  2714. // of isochronous transfers (which will get patched up later) transfer
  2715. // descriptors are always put at the end of the queue. They confusingly
  2716. // point back to the first transfer because the first transfer will
  2717. // eventually get swapped out to be a dummy last transfer. That fact is
  2718. // anticipated here so that now all transfers lead to the dummy at the end.
  2719. //
  2720. HardwareTransfer->NextTransfer =
  2721. (ULONG)(TransferSet->Transfer[0]->PhysicalAddress);
  2722. if ((AlternateNextTransfer != NULL) &&
  2723. (AlternateNextTransfer != EhciTransfer)) {
  2724. ASSERT((ULONG)AlternateNextTransfer->PhysicalAddress ==
  2725. AlternateNextTransfer->PhysicalAddress);
  2726. HardwareTransfer->AlternateNextTransfer =
  2727. (ULONG)AlternateNextTransfer->PhysicalAddress;
  2728. } else {
  2729. //
  2730. // Point the next transfer to what will become the end of this set, so
  2731. // that if a short packet comes in this transfer set will be done and
  2732. // the queue moves to the next set of transfers.
  2733. //
  2734. HardwareTransfer->AlternateNextTransfer =
  2735. (ULONG)(TransferSet->Transfer[0]->PhysicalAddress);
  2736. }
  2737. if (Transfer->Type == UsbTransferTypeIsochronous) {
  2738. //
  2739. // TODO: Implement isochronous transfers.
  2740. //
  2741. ASSERT(FALSE);
  2742. }
  2743. return;
  2744. }
  2745. VOID
  2746. EhcipLinkTransferSetInHardware (
  2747. PEHCI_TRANSFER_SET TransferSet
  2748. )
  2749. /*++
  2750. Routine Description:
  2751. This routine links a set of transfer descriptors up to their proper queue
  2752. head, making them visible to the hardware. This routine assumes the
  2753. controller lock is already held.
  2754. Arguments:
  2755. TransferSet - Supplies a pointer to the transfer set.
  2756. Return Value:
  2757. None.
  2758. --*/
  2759. {
  2760. PEHCI_ENDPOINT Endpoint;
  2761. PEHCI_TRANSFER OriginalDummyTransfer;
  2762. PEHCI_TRANSFER OriginalFirstTransfer;
  2763. PEHCI_QUEUE_HEAD QueueHead;
  2764. ULONG RemainingSize;
  2765. ULONG Token;
  2766. Endpoint = TransferSet->Endpoint;
  2767. //
  2768. // TODO: Implement support for isochronous.
  2769. //
  2770. ASSERT(Endpoint->TransferType != UsbTransferTypeIsochronous);
  2771. OriginalDummyTransfer = Endpoint->Queue.DummyTransfer;
  2772. OriginalFirstTransfer = TransferSet->Transfer[0];
  2773. ASSERT((OriginalDummyTransfer->HardwareTransfer->Token &
  2774. EHCI_TRANSFER_STATUS_HALTED) != 0);
  2775. //
  2776. // The way this is going to work is to not actually use the first transfer
  2777. // of the set, but to copy it into the dummy transfer that's already on the
  2778. // hardware list. That dummy transfer becomes the first transfer of the set,
  2779. // and the original first transfer becomes the new dummy. Begin by saving
  2780. // the original first transfer's token.
  2781. //
  2782. Token = OriginalFirstTransfer->HardwareTransfer->Token;
  2783. OriginalFirstTransfer->HardwareTransfer->Token =
  2784. OriginalDummyTransfer->HardwareTransfer->Token;
  2785. //
  2786. // Copy the remainder of the original first transfer over the dummy, but
  2787. // make sure it stays inactive so the hardware doesn't look at it.
  2788. //
  2789. OriginalDummyTransfer->HardwareTransfer->NextTransfer =
  2790. OriginalFirstTransfer->HardwareTransfer->NextTransfer;
  2791. OriginalDummyTransfer->HardwareTransfer->AlternateNextTransfer =
  2792. OriginalFirstTransfer->HardwareTransfer->AlternateNextTransfer;
  2793. RemainingSize = sizeof(EHCI_TRANSFER_DESCRIPTOR) -
  2794. FIELD_OFFSET(EHCI_TRANSFER_DESCRIPTOR, BufferPointer);
  2795. RtlCopyMemory(&(OriginalDummyTransfer->HardwareTransfer->BufferPointer),
  2796. &(OriginalFirstTransfer->HardwareTransfer->BufferPointer),
  2797. RemainingSize);
  2798. ASSERT((OriginalDummyTransfer->EndpointListEntry.Next == NULL) &&
  2799. (OriginalDummyTransfer->GlobalListEntry.Next == NULL) &&
  2800. (OriginalFirstTransfer->EndpointListEntry.Next != NULL) &&
  2801. (OriginalFirstTransfer->GlobalListEntry.Next != NULL));
  2802. //
  2803. // Add the dummy transfer to the software lists, and remove the original
  2804. // first transfer.
  2805. //
  2806. INSERT_BEFORE(&(OriginalDummyTransfer->EndpointListEntry),
  2807. &(OriginalFirstTransfer->EndpointListEntry));
  2808. INSERT_BEFORE(&(OriginalDummyTransfer->GlobalListEntry),
  2809. &(OriginalFirstTransfer->GlobalListEntry));
  2810. LIST_REMOVE(&(OriginalFirstTransfer->GlobalListEntry));
  2811. LIST_REMOVE(&(OriginalFirstTransfer->EndpointListEntry));
  2812. OriginalFirstTransfer->EndpointListEntry.Next = NULL;
  2813. OriginalFirstTransfer->GlobalListEntry.Next = NULL;
  2814. //
  2815. // Copy over any other aspects.
  2816. //
  2817. OriginalFirstTransfer->HardwareTransfer->NextTransfer = EHCI_LINK_TERMINATE;
  2818. OriginalFirstTransfer->HardwareTransfer->AlternateNextTransfer =
  2819. EHCI_LINK_TERMINATE;
  2820. OriginalDummyTransfer->TransferLength =
  2821. OriginalFirstTransfer->TransferLength;
  2822. OriginalFirstTransfer->TransferLength = 0;
  2823. OriginalDummyTransfer->LastTransfer = OriginalFirstTransfer->LastTransfer;
  2824. OriginalFirstTransfer->LastTransfer = FALSE;
  2825. //
  2826. // Switch their roles.
  2827. //
  2828. TransferSet->Transfer[0] = OriginalDummyTransfer;
  2829. OriginalFirstTransfer->Set = NULL;
  2830. OriginalDummyTransfer->Set = TransferSet;
  2831. Endpoint->Queue.DummyTransfer = OriginalFirstTransfer;
  2832. //
  2833. // Make everything live by setting the token in the new first transfer.
  2834. // Use the register write function to ensure the compiler does this in a
  2835. // single write (and not something goofy like byte by byte). This routine
  2836. // also serves as a full memory barrier.
  2837. //
  2838. QueueHead = Endpoint->Queue.HardwareQueueHead;
  2839. HlWriteRegister32(&(OriginalDummyTransfer->HardwareTransfer->Token), Token);
  2840. //
  2841. // If the queue head was halted, it needs to be restarted. Zero out the
  2842. // current descriptor so nothing gets written back, set the next link to
  2843. // the start of the list, and zero out the token. Avoid the very rare
  2844. // situation where the hardware got all the way through the transfers
  2845. // linked in the previous line (and has an errata where the halted
  2846. // descriptor is copied into the overlay).
  2847. //
  2848. if (((QueueHead->TransferOverlay.Token &
  2849. EHCI_TRANSFER_STATUS_HALTED) != 0) &&
  2850. (QueueHead->CurrentTransferDescriptorLink !=
  2851. (ULONG)(OriginalFirstTransfer->PhysicalAddress))) {
  2852. QueueHead->CurrentTransferDescriptorLink = 0;
  2853. QueueHead->TransferOverlay.NextTransfer =
  2854. OriginalDummyTransfer->PhysicalAddress;
  2855. HlWriteRegister32(
  2856. &(QueueHead->TransferOverlay.Token),
  2857. QueueHead->TransferOverlay.Token & EHCI_TRANSFER_DATA_TOGGLE);
  2858. }
  2859. return;
  2860. }
  2861. BOOL
  2862. EhcipProcessPotentiallyCompletedTransfer (
  2863. PEHCI_TRANSFER Transfer
  2864. )
  2865. /*++
  2866. Routine Description:
  2867. This routine processes a transfer descriptor, adjusting the USB transfer if
  2868. the transfer descriptor errored out.
  2869. Arguments:
  2870. Transfer - Supplies a pointer to the transfer to evaluate.
  2871. Return Value:
  2872. TRUE if the transfer set should be removed from the list because the
  2873. transfer has failed.
  2874. FALSE if the transfer set should not be removed from the list.
  2875. --*/
  2876. {
  2877. ULONG HardwareStatus;
  2878. ULONG LengthTransferred;
  2879. PEHCI_QUEUE_HEAD QueueHead;
  2880. BOOL RemoveSet;
  2881. PUSB_TRANSFER UsbTransfer;
  2882. RemoveSet = FALSE;
  2883. //
  2884. // Skip the transfer if it's already been dealt with.
  2885. //
  2886. if (Transfer->GlobalListEntry.Next == NULL) {
  2887. goto ProcessPotentiallyCompletedTransferEnd;
  2888. }
  2889. HardwareStatus = Transfer->HardwareTransfer->Token;
  2890. if ((HardwareStatus & EHCI_TRANSFER_STATUS_ACTIVE) == 0) {
  2891. if ((EhciDebugFlags & EHCI_DEBUG_TRANSFERS) != 0) {
  2892. RtlDebugPrint("EHCI: Transfer (0x%08x) PA 0x%I64x completed with "
  2893. "token 0x%08x\n",
  2894. Transfer,
  2895. Transfer->PhysicalAddress,
  2896. HardwareStatus);
  2897. }
  2898. LIST_REMOVE(&(Transfer->EndpointListEntry));
  2899. Transfer->EndpointListEntry.Next = NULL;
  2900. LIST_REMOVE(&(Transfer->GlobalListEntry));
  2901. Transfer->GlobalListEntry.Next = NULL;
  2902. LengthTransferred = Transfer->TransferLength -
  2903. ((HardwareStatus &
  2904. EHCI_TRANSFER_TOTAL_BYTES_MASK) >>
  2905. EHCI_TRANSFER_TOTAL_BYTES_SHIFT);
  2906. UsbTransfer = &(Transfer->Set->UsbTransfer->Public);
  2907. UsbTransfer->LengthTransferred += LengthTransferred;
  2908. //
  2909. // If error bits were set, it's curtains for this transfer. Figure out
  2910. // exactly what went wrong. A halted error is first in line even if
  2911. // another bit (e.g. Babble) is set, because the driver may want to
  2912. // clear the halted state.
  2913. //
  2914. if ((HardwareStatus & EHCI_TRANSFER_ERROR_MASK) != 0) {
  2915. if (((EhciDebugFlags & EHCI_DEBUG_ERRORS) != 0) &&
  2916. ((EhciDebugFlags & EHCI_DEBUG_TRANSFERS) == 0)) {
  2917. RtlDebugPrint("EHCI: Transfer (0x%08x) PA 0x%I64x completed "
  2918. "with token 0x%08x\n",
  2919. Transfer,
  2920. Transfer->PhysicalAddress,
  2921. HardwareStatus);
  2922. }
  2923. RemoveSet = TRUE;
  2924. UsbTransfer->Status = STATUS_DEVICE_IO_ERROR;
  2925. if ((HardwareStatus & EHCI_TRANSFER_STATUS_HALTED) != 0) {
  2926. UsbTransfer->Error = UsbErrorTransferStalled;
  2927. //
  2928. // Clear out the current link so that when the next transfer
  2929. // set is linked in it won't get confused if this transfer
  2930. // is reused.
  2931. //
  2932. QueueHead = Transfer->Set->Endpoint->Queue.HardwareQueueHead;
  2933. QueueHead->CurrentTransferDescriptorLink = 0;
  2934. } else if ((HardwareStatus &
  2935. EHCI_TRANSFER_MISSED_MICRO_FRAME_ERROR) != 0) {
  2936. UsbTransfer->Error = UsbErrorTransferMissedMicroFrame;
  2937. } else if ((HardwareStatus &
  2938. EHCI_TRANSFER_TRANSACTION_ERROR) != 0) {
  2939. UsbTransfer->Error = UsbErrorTransferCrcOrTimeoutError;
  2940. } else if ((HardwareStatus & EHCI_TRANSFER_BABBLE_ERROR) != 0) {
  2941. UsbTransfer->Error = UsbErrorTransferBabbleDetected;
  2942. } else if ((HardwareStatus &
  2943. EHCI_TRANSFER_STATUS_DATA_BUFFER_ERROR) != 0) {
  2944. UsbTransfer->Error = UsbErrorTransferDataBuffer;
  2945. }
  2946. //
  2947. // Also check for short packets.
  2948. //
  2949. } else if ((LengthTransferred != Transfer->TransferLength) &&
  2950. ((UsbTransfer->Flags &
  2951. USB_TRANSFER_FLAG_NO_SHORT_TRANSFERS) != 0)) {
  2952. UsbTransfer->Status = STATUS_DATA_LENGTH_MISMATCH;
  2953. UsbTransfer->Error = UsbErrorShortPacket;
  2954. }
  2955. //
  2956. // If this is the last transfer, then signal that processing on this
  2957. // set is complete.
  2958. //
  2959. if ((Transfer->LastTransfer != FALSE) ||
  2960. (LengthTransferred != Transfer->TransferLength)) {
  2961. RemoveSet = TRUE;
  2962. }
  2963. }
  2964. ProcessPotentiallyCompletedTransferEnd:
  2965. return RemoveSet;
  2966. }
  2967. VOID
  2968. EhcipRemoveCompletedTransferSet (
  2969. PEHCI_CONTROLLER Controller,
  2970. PEHCI_TRANSFER_SET TransferSet
  2971. )
  2972. /*++
  2973. Routine Description:
  2974. This routine removes a completed transfer set from the schedule. This
  2975. routine assumes that the controller lock is already held.
  2976. Arguments:
  2977. Controller - Supplies a pointer to the controller being operated on.
  2978. TransferSet - Supplies a pointer to the set of transfers to remove.
  2979. Return Value:
  2980. None.
  2981. --*/
  2982. {
  2983. ULONG BackwardsTransferIndex;
  2984. PEHCI_TRANSFER EhciTransfer;
  2985. PEHCI_ENDPOINT Endpoint;
  2986. PEHCI_TRANSFER *TransferArray;
  2987. ULONG TransferIndex;
  2988. Endpoint = TransferSet->Endpoint;
  2989. //
  2990. // Isochronous transfers are handled differently.
  2991. //
  2992. if (Endpoint->TransferType == UsbTransferTypeIsochronous) {
  2993. ASSERT(FALSE);
  2994. goto RemoveCompletedTransferSetEnd;
  2995. }
  2996. TransferArray = (PEHCI_TRANSFER *)&(TransferSet->Transfer);
  2997. for (TransferIndex = 0;
  2998. TransferIndex < TransferSet->TransferCount;
  2999. TransferIndex += 1) {
  3000. BackwardsTransferIndex = TransferSet->TransferCount - 1 - TransferIndex;
  3001. EhciTransfer = TransferArray[BackwardsTransferIndex];
  3002. //
  3003. // Skip this transfer if it's done or otherwise not currently queued.
  3004. //
  3005. if (EhciTransfer->EndpointListEntry.Next == NULL) {
  3006. continue;
  3007. }
  3008. //
  3009. // Since the transfer set completed, all of the transfers are already
  3010. // out of the hardware's queue. Just remove them from the software
  3011. // list.
  3012. //
  3013. LIST_REMOVE(&(EhciTransfer->EndpointListEntry));
  3014. EhciTransfer->EndpointListEntry.Next = NULL;
  3015. ASSERT(EhciTransfer->GlobalListEntry.Next != NULL);
  3016. LIST_REMOVE(&(EhciTransfer->GlobalListEntry));
  3017. EhciTransfer->GlobalListEntry.Next = NULL;
  3018. }
  3019. RemoveCompletedTransferSetEnd:
  3020. //
  3021. // Transfer set has been removed. Mark that it is no longer queued.
  3022. //
  3023. TransferSet->Flags &= ~EHCI_TRANSFER_SET_FLAG_QUEUED;
  3024. return;
  3025. }
  3026. VOID
  3027. EhcipProcessAsyncOnAdvanceInterrupt (
  3028. PEHCI_CONTROLLER Controller
  3029. )
  3030. /*++
  3031. Routine Description:
  3032. This routine processes the queue heads that were waiting for an advance of
  3033. the asynchronous schedule. This routine assumes that the controller lock is
  3034. held.
  3035. Arguments:
  3036. Controller - Supplies a pointer to the controller being operated on.
  3037. Return Value:
  3038. None.
  3039. --*/
  3040. {
  3041. ULONG CommandRegister;
  3042. PLIST_ENTRY CurrentEntry;
  3043. PEHCI_TRANSFER EhciTransfer;
  3044. PEHCI_ENDPOINT Endpoint;
  3045. ULONG Flags;
  3046. ULONG HorizontalLink;
  3047. PEHCI_TRANSFER LastTransfer;
  3048. PEHCI_TRANSFER_QUEUE Queue;
  3049. PEHCI_TRANSFER_QUEUE QueueBefore;
  3050. LIST_ENTRY QueueListHead;
  3051. BOOL QueueWorkItem;
  3052. PEHCI_TRANSFER *TransferArray;
  3053. ULONG TransferIndex;
  3054. PEHCI_TRANSFER_SET TransferSet;
  3055. PUSB_TRANSFER UsbTransfer;
  3056. ASSERT(KeIsSpinLockHeld(&(Controller->Lock)) != FALSE);
  3057. //
  3058. // First transfer the list of queue heads that are ready to be processed to
  3059. // a local list. Be a bit defensive against spurious async advance
  3060. // interrupts (potentially caused by KD USB).
  3061. //
  3062. if (LIST_EMPTY(&(Controller->AsyncOnAdvanceReadyListHead)) != FALSE) {
  3063. INITIALIZE_LIST_HEAD(&QueueListHead);
  3064. } else {
  3065. MOVE_LIST(&(Controller->AsyncOnAdvanceReadyListHead), &QueueListHead);
  3066. }
  3067. INITIALIZE_LIST_HEAD(&(Controller->AsyncOnAdvanceReadyListHead));
  3068. //
  3069. // If the pending list is not empty, transfer it to the ready list and ring
  3070. // the doorbell.
  3071. //
  3072. if (LIST_EMPTY(&(Controller->AsyncOnAdvancePendingListHead)) == FALSE) {
  3073. MOVE_LIST(&(Controller->AsyncOnAdvancePendingListHead),
  3074. &(Controller->AsyncOnAdvanceReadyListHead));
  3075. INITIALIZE_LIST_HEAD(&(Controller->AsyncOnAdvancePendingListHead));
  3076. CommandRegister = Controller->CommandRegister;
  3077. CommandRegister |= EHCI_COMMAND_INTERRUPT_ON_ASYNC_ADVANCE;
  3078. EHCI_WRITE_REGISTER(Controller,
  3079. EhciRegisterUsbCommand,
  3080. CommandRegister);
  3081. }
  3082. //
  3083. // Now that the next doorbell is all set up, process the list of queue
  3084. // heads that have been fully removed from the hardware's grasp. There are
  3085. // two reasons for which a queue head can be removed. The first is if the
  3086. // endpoint is being removed. The second is if a transfer set in the queue
  3087. // was cancelled.
  3088. //
  3089. QueueWorkItem = FALSE;
  3090. while (LIST_EMPTY(&QueueListHead) == FALSE) {
  3091. Queue = LIST_VALUE(QueueListHead.Next, EHCI_TRANSFER_QUEUE, ListEntry);
  3092. LIST_REMOVE(&(Queue->ListEntry));
  3093. //
  3094. // If the queue has no async on advance context, then it's on the list
  3095. // in order to be destroyed. Add it to the list of queue heads to
  3096. // destroy. Note that a work item needs to be scheduled if this is the
  3097. // first entry on the list.
  3098. //
  3099. if (Queue->AsyncOnAdvanceCancel == FALSE) {
  3100. if (LIST_EMPTY(&(Controller->QueuesToDestroyListHead)) != FALSE) {
  3101. QueueWorkItem = TRUE;
  3102. }
  3103. INSERT_BEFORE(&(Queue->ListEntry),
  3104. &(Controller->QueuesToDestroyListHead));
  3105. //
  3106. // Otherwise the queue is here to remove one or more transfer sets that
  3107. // were cancelled.
  3108. //
  3109. } else {
  3110. Endpoint = PARENT_STRUCTURE(Queue, EHCI_ENDPOINT, Queue);
  3111. Queue->AsyncOnAdvanceCancel = FALSE;
  3112. ASSERT((Endpoint->TransferType == UsbTransferTypeControl) ||
  3113. (Endpoint->TransferType == UsbTransferTypeBulk));
  3114. CurrentEntry = Endpoint->TransferListHead.Next;
  3115. while (CurrentEntry != &(Endpoint->TransferListHead)) {
  3116. EhciTransfer = LIST_VALUE(CurrentEntry,
  3117. EHCI_TRANSFER,
  3118. EndpointListEntry);
  3119. //
  3120. // If the transfer set was not marked for cancelling, skip it.
  3121. //
  3122. TransferSet = EhciTransfer->Set;
  3123. Flags = TransferSet->Flags;
  3124. ASSERT((Flags & EHCI_TRANSFER_SET_FLAG_QUEUED) != 0);
  3125. if ((Flags & EHCI_TRANSFER_SET_FLAG_CANCELLING) == 0) {
  3126. CurrentEntry = CurrentEntry->Next;
  3127. continue;
  3128. }
  3129. //
  3130. // The next transfer to process is the next transfer after this
  3131. // set.
  3132. //
  3133. CurrentEntry = NULL;
  3134. TransferArray = (PEHCI_TRANSFER *)&(TransferSet->Transfer);
  3135. for (TransferIndex = 0;
  3136. TransferIndex < TransferSet->TransferCount;
  3137. TransferIndex += 1) {
  3138. if (TransferArray[TransferIndex]->LastTransfer != FALSE) {
  3139. LastTransfer = TransferArray[TransferIndex];
  3140. CurrentEntry = LastTransfer->EndpointListEntry.Next;
  3141. break;
  3142. }
  3143. }
  3144. ASSERT(CurrentEntry != NULL);
  3145. //
  3146. // Officially mark the transfer as cancelled, remove the
  3147. // transfer set and call the completion routine.
  3148. //
  3149. UsbTransfer = &(TransferSet->UsbTransfer->Public);
  3150. UsbTransfer->Status = STATUS_OPERATION_CANCELLED;
  3151. UsbTransfer->Error = UsbErrorTransferCancelled;
  3152. EhcipRemoveCancelledTransferSet(Controller, TransferSet);
  3153. UsbHostProcessCompletedTransfer(TransferSet->UsbTransfer);
  3154. }
  3155. //
  3156. // Now that all of the queue's cancelled transfer sets have been
  3157. // processed add it back to the asynchronous schedule.
  3158. //
  3159. QueueBefore = &(Controller->AsynchronousSchedule);
  3160. INSERT_AFTER(&(Queue->ListEntry), &(QueueBefore->ListEntry));
  3161. Queue->HardwareQueueHead->HorizontalLink =
  3162. QueueBefore->HardwareQueueHead->HorizontalLink;
  3163. HorizontalLink = (ULONG)Queue->PhysicalAddress;
  3164. ASSERT((HorizontalLink & (~EHCI_LINK_ADDRESS_MASK)) == 0);
  3165. HorizontalLink |= EHCI_LINK_TYPE_QUEUE_HEAD;
  3166. HlWriteRegister32(&(QueueBefore->HardwareQueueHead->HorizontalLink),
  3167. HorizontalLink);
  3168. }
  3169. }
  3170. //
  3171. // Queue the work item now if there is work to do.
  3172. //
  3173. if (QueueWorkItem != FALSE) {
  3174. KeQueueWorkItem(Controller->DestroyQueuesWorkItem);
  3175. }
  3176. return;
  3177. }
  3178. VOID
  3179. EhcipRemoveCancelledTransferSet (
  3180. PEHCI_CONTROLLER Controller,
  3181. PEHCI_TRANSFER_SET TransferSet
  3182. )
  3183. /*++
  3184. Routine Description:
  3185. This routine removes a cancelled transfer set from the schedule. This
  3186. routine assumes that the controller lock is already held.
  3187. Arguments:
  3188. Controller - Supplies a pointer to the controller being operated on.
  3189. TransferSet - Supplies a pointer to the set of transfers to remove.
  3190. Return Value:
  3191. None.
  3192. --*/
  3193. {
  3194. ULONG BackwardsTransferIndex;
  3195. PEHCI_TRANSFER EhciTransfer;
  3196. PEHCI_ENDPOINT Endpoint;
  3197. PEHCI_QUEUE_HEAD HardwareQueueHead;
  3198. PEHCI_TRANSFER_DESCRIPTOR HardwareTransfer;
  3199. PLIST_ENTRY NextEntry;
  3200. PEHCI_TRANSFER NextTransfer;
  3201. PLIST_ENTRY PreviousEntry;
  3202. PEHCI_TRANSFER PreviousTransfer;
  3203. PEHCI_TRANSFER_QUEUE Queue;
  3204. PEHCI_TRANSFER *TransferArray;
  3205. ULONG TransferIndex;
  3206. ASSERT(KeIsSpinLockHeld(&(Controller->Lock)) != FALSE);
  3207. Endpoint = TransferSet->Endpoint;
  3208. Queue = &(Endpoint->Queue);
  3209. TransferArray = (PEHCI_TRANSFER *)&(TransferSet->Transfer);
  3210. //
  3211. // Isochronous transfers are handled differently.
  3212. //
  3213. if (Endpoint->TransferType == UsbTransferTypeIsochronous) {
  3214. ASSERT(FALSE);
  3215. goto RemoveCancelledTransferSetEnd;
  3216. }
  3217. //
  3218. // Loop over all transfers in the set, removing any incomplete transfers.
  3219. //
  3220. NextEntry = NULL;
  3221. PreviousEntry = NULL;
  3222. for (TransferIndex = 0;
  3223. TransferIndex < TransferSet->TransferCount;
  3224. TransferIndex += 1) {
  3225. BackwardsTransferIndex = TransferSet->TransferCount - 1 - TransferIndex;
  3226. EhciTransfer = TransferArray[BackwardsTransferIndex];
  3227. //
  3228. // Skip this transfer if it's done or otherwise not currently queued.
  3229. //
  3230. if (EhciTransfer->EndpointListEntry.Next == NULL) {
  3231. continue;
  3232. }
  3233. //
  3234. // Record the transfer directly following the set. This is the next
  3235. // entry of the last transfer in the set.
  3236. //
  3237. if (EhciTransfer->LastTransfer != FALSE) {
  3238. NextEntry = EhciTransfer->EndpointListEntry.Next;
  3239. }
  3240. //
  3241. // Record the previous entry of the first transfer in the set that is
  3242. // still queued. This loop iterates backwards, so just record it every
  3243. // time.
  3244. //
  3245. PreviousEntry = EhciTransfer->EndpointListEntry.Previous;
  3246. //
  3247. // Either the previous entry is valid or this transfer was previously
  3248. // the first transfer in the queue.
  3249. //
  3250. ASSERT((PreviousEntry != &(Endpoint->TransferListHead)) ||
  3251. (Queue->HardwareQueueHead->CurrentTransferDescriptorLink == 0) ||
  3252. (Queue->HardwareQueueHead->CurrentTransferDescriptorLink ==
  3253. EhciTransfer->PhysicalAddress));
  3254. //
  3255. // Remove the transfer from the software lists. The endpoint's queue
  3256. // head is not in the schedule so the hardware transfer does not need
  3257. // to be modified - that is handled below.
  3258. //
  3259. LIST_REMOVE(&(EhciTransfer->EndpointListEntry));
  3260. EhciTransfer->EndpointListEntry.Next = NULL;
  3261. ASSERT(EhciTransfer->GlobalListEntry.Next != NULL);
  3262. LIST_REMOVE(&(EhciTransfer->GlobalListEntry));
  3263. EhciTransfer->GlobalListEntry.Next = NULL;
  3264. }
  3265. //
  3266. // Determine the next transfer in the queue after the set being removed.
  3267. // It could be the dummy transfer.
  3268. //
  3269. if ((NextEntry == NULL) || (NextEntry == &(Endpoint->TransferListHead))) {
  3270. NextTransfer = Queue->DummyTransfer;
  3271. } else {
  3272. NextTransfer = LIST_VALUE(NextEntry, EHCI_TRANSFER, EndpointListEntry);
  3273. }
  3274. //
  3275. // If there was a previous transfer in the queue, then point that at the
  3276. // next transfer.
  3277. //
  3278. if ((PreviousEntry != NULL) &&
  3279. (PreviousEntry != &(Endpoint->TransferListHead))) {
  3280. PreviousTransfer = LIST_VALUE(PreviousEntry,
  3281. EHCI_TRANSFER,
  3282. EndpointListEntry);
  3283. HardwareTransfer = PreviousTransfer->HardwareTransfer;
  3284. HlWriteRegister32(&(HardwareTransfer->NextTransfer),
  3285. (ULONG)(NextTransfer->PhysicalAddress));
  3286. HlWriteRegister32(&(HardwareTransfer->AlternateNextTransfer),
  3287. (ULONG)(NextTransfer->PhysicalAddress));
  3288. //
  3289. // Otherwise the queue head needs to be updated to grab the next transfer
  3290. // the next time is runs in the schedule.
  3291. //
  3292. } else {
  3293. HardwareQueueHead = Queue->HardwareQueueHead;
  3294. HardwareQueueHead->CurrentTransferDescriptorLink = 0;
  3295. HardwareQueueHead->TransferOverlay.NextTransfer =
  3296. (ULONG)(NextTransfer->PhysicalAddress);
  3297. HardwareQueueHead->TransferOverlay.AlternateNextTransfer =
  3298. (ULONG)(NextTransfer->PhysicalAddress);
  3299. }
  3300. RemoveCancelledTransferSetEnd:
  3301. //
  3302. // Transfer set has been removed. Mark that it is no longer queued.
  3303. //
  3304. TransferSet->Flags &= ~EHCI_TRANSFER_SET_FLAG_QUEUED;
  3305. return;
  3306. }
  3307. VOID
  3308. EhcipDestroyQueuesWorkRoutine (
  3309. PVOID Parameter
  3310. )
  3311. /*++
  3312. Routine Description:
  3313. This routine implements the queue head destruction work routine.
  3314. Arguments:
  3315. Parameter - Supplies an optional parameter passed in by the creator of the
  3316. work item. The EHCI controller context is supplied in this case.
  3317. Return Value:
  3318. None.
  3319. --*/
  3320. {
  3321. PEHCI_CONTROLLER Controller;
  3322. PEHCI_ENDPOINT Endpoint;
  3323. RUNLEVEL OldRunLevel;
  3324. PEHCI_TRANSFER_QUEUE Queue;
  3325. LIST_ENTRY QueueListHead;
  3326. Controller = (PEHCI_CONTROLLER)Parameter;
  3327. ASSERT(LIST_EMPTY(&(Controller->QueuesToDestroyListHead)) == FALSE);
  3328. //
  3329. // Acquire the controller lock and move all the queue heads that are
  3330. // awaiting removal to a local list.
  3331. //
  3332. OldRunLevel = EhcipAcquireControllerLock(Controller);
  3333. MOVE_LIST(&(Controller->QueuesToDestroyListHead), &QueueListHead);
  3334. INITIALIZE_LIST_HEAD(&(Controller->QueuesToDestroyListHead));
  3335. EhcipReleaseControllerLock(Controller, OldRunLevel);
  3336. //
  3337. // Iterate over the local list, destroying each queue head.
  3338. //
  3339. while (LIST_EMPTY(&QueueListHead) == FALSE) {
  3340. Queue = LIST_VALUE(QueueListHead.Next, EHCI_TRANSFER_QUEUE, ListEntry);
  3341. Endpoint = PARENT_STRUCTURE(Queue, EHCI_ENDPOINT, Queue);
  3342. LIST_REMOVE(&(Queue->ListEntry));
  3343. if (Queue->DummyTransfer != NULL) {
  3344. if (Queue->DummyTransfer->HardwareTransfer != NULL) {
  3345. MmFreeBlock(Controller->BlockAllocator,
  3346. Queue->DummyTransfer->HardwareTransfer);
  3347. }
  3348. MmFreeNonPagedPool(Queue->DummyTransfer);
  3349. }
  3350. if (Queue->HardwareQueueHead != NULL) {
  3351. MmFreeBlock(Controller->BlockAllocator, Queue->HardwareQueueHead);
  3352. }
  3353. MmFreeNonPagedPool(Endpoint);
  3354. }
  3355. return;
  3356. }