uhcihc.c 94 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. uhcihc.c
  5. Abstract:
  6. This module implements the meaty support for the UHCI Host Controller.
  7. Author:
  8. Evan Green 14-Jan-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/driver.h>
  16. #include <minoca/usb/usbhost.h>
  17. #include "uhci.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. //
  22. // These macros read from and write to a UHCI host controller register.
  23. //
  24. #define UHCI_READ_REGISTER(_Controller, _Register) \
  25. HlIoPortInShort((_Controller)->IoPortBase + _Register)
  26. #define UHCI_WRITE_REGISTER(_Controller, _Register, _Value) \
  27. HlIoPortOutShort((_Controller)->IoPortBase + _Register, _Value);
  28. #define UHCI_READ_REGISTER_LONG(_Controller, _Register) \
  29. HlIoPortInLong((_Controller)->IoPortBase + _Register)
  30. #define UHCI_WRITE_REGISTER_LONG(_Controller, _Register, _Value) \
  31. HlIoPortOutLong((_Controller)->IoPortBase + _Register, _Value);
  32. //
  33. // Define the polling period for the UHCI port status.
  34. //
  35. #define UHCI_PORT_STATUS_CHANGE_PERIOD (3000 * MICROSECONDS_PER_MILLISECOND)
  36. //
  37. // Define UHCI debug flags.
  38. //
  39. #define UHCI_DEBUG_PORTS 0x00000001
  40. #define UHCI_DEBUG_TRANSFERS 0x00000002
  41. //
  42. // Define the timeout value for the endpoint flush operation.
  43. //
  44. #define UHCI_ENDPOINT_FLUSH_TIMEOUT 10
  45. //
  46. // Define the timeout value for the polled I/O operations.
  47. //
  48. #define UHCI_POLLED_TRANSFER_TIMEOUT 10
  49. //
  50. // ------------------------------------------------------ Data Type Definitions
  51. //
  52. //
  53. // ----------------------------------------------- Internal Function Prototypes
  54. //
  55. KSTATUS
  56. UhcipCreateEndpoint (
  57. PVOID HostControllerContext,
  58. PUSB_HOST_ENDPOINT_CREATION_REQUEST Endpoint,
  59. PVOID *EndpointContext
  60. );
  61. VOID
  62. UhcipResetEndpoint (
  63. PVOID HostControllerContext,
  64. PVOID EndpointContext,
  65. ULONG MaxPacketSize
  66. );
  67. KSTATUS
  68. UhcipFlushEndpoint (
  69. PVOID HostControllerContext,
  70. PVOID EndpointContext,
  71. PULONG TransferCount
  72. );
  73. VOID
  74. UhcipDestroyEndpoint (
  75. PVOID HostControllerContext,
  76. PVOID EndpointContext
  77. );
  78. KSTATUS
  79. UhcipCreateTransfer (
  80. PVOID HostControllerContext,
  81. PVOID EndpointContext,
  82. ULONG MaxBufferSize,
  83. ULONG Flags,
  84. PVOID *TransferContext
  85. );
  86. VOID
  87. UhcipDestroyTransfer (
  88. PVOID HostControllerContext,
  89. PVOID EndpointContext,
  90. PVOID TransferContext
  91. );
  92. KSTATUS
  93. UhcipSubmitTransfer (
  94. PVOID HostControllerContext,
  95. PVOID EndpointContext,
  96. PUSB_TRANSFER_INTERNAL Transfer,
  97. PVOID TransferContext
  98. );
  99. KSTATUS
  100. UhcipSubmitPolledTransfer (
  101. PVOID HostControllerContext,
  102. PVOID EndpointContext,
  103. PUSB_TRANSFER_INTERNAL Transfer,
  104. PVOID TransferContext
  105. );
  106. KSTATUS
  107. UhcipSubmitTransferQueue (
  108. PUHCI_CONTROLLER Controller,
  109. PUHCI_ENDPOINT Endpoint,
  110. PUHCI_TRANSFER_QUEUE Queue,
  111. PULONG SubmittedTransferCount,
  112. BOOL LockNotRequired
  113. );
  114. KSTATUS
  115. UhcipCancelTransfer (
  116. PVOID HostControllerContext,
  117. PVOID EndpointContext,
  118. PUSB_TRANSFER_INTERNAL Transfer,
  119. PVOID TransferContext
  120. );
  121. KSTATUS
  122. UhcipGetRootHubStatus (
  123. PVOID HostControllerContext,
  124. PUSB_HUB_STATUS HubStatus
  125. );
  126. KSTATUS
  127. UhcipSetRootHubStatus (
  128. PVOID HostControllerContext,
  129. PUSB_HUB_STATUS NewStatus
  130. );
  131. RUNLEVEL
  132. UhcipAcquireControllerLock (
  133. PUHCI_CONTROLLER Controller
  134. );
  135. VOID
  136. UhcipReleaseControllerLock (
  137. PUHCI_CONTROLLER Controller,
  138. RUNLEVEL OldRunLevel
  139. );
  140. VOID
  141. UhcipWaitForNextFrame (
  142. PUHCI_CONTROLLER Controller
  143. );
  144. VOID
  145. UhcipProcessInterrupt (
  146. PUHCI_CONTROLLER Controller,
  147. ULONG PendingStatus
  148. );
  149. VOID
  150. UhcipFillOutTransferDescriptor (
  151. PUHCI_CONTROLLER Controller,
  152. PUHCI_ENDPOINT Endpoint,
  153. PUHCI_TRANSFER_QUEUE Queue,
  154. PUHCI_TRANSFER UhciTransfer,
  155. PUSB_TRANSFER_INTERNAL Transfer,
  156. ULONG Offset,
  157. ULONG Length,
  158. BOOL LastTransfer
  159. );
  160. BOOL
  161. UhcipProcessPotentiallyCompletedTransfer (
  162. PUHCI_TRANSFER_QUEUE Queue,
  163. PUHCI_TRANSFER Transfer
  164. );
  165. VOID
  166. UhcipRemoveTransferQueue (
  167. PUHCI_CONTROLLER Controller,
  168. PUHCI_TRANSFER_QUEUE Queue,
  169. BOOL Cancel
  170. );
  171. VOID
  172. UhcipPortStatusDpc (
  173. PDPC Dpc
  174. );
  175. BOOL
  176. UhcipHasPortStatusChanged (
  177. PUHCI_CONTROLLER Controller
  178. );
  179. VOID
  180. UhcipFlushCacheRegion (
  181. PVOID VirtualAddress,
  182. ULONG Size
  183. );
  184. VOID
  185. UhcipFixDataToggles (
  186. PUHCI_TRANSFER_QUEUE RemovingQueue,
  187. BOOL Toggle
  188. );
  189. //
  190. // -------------------------------------------------------------------- Globals
  191. //
  192. //
  193. // Define a bitfield of debug flags that enable various print messages for
  194. // UHCI. See UHCI_DEBUG_* definitions.
  195. //
  196. ULONG UhciDebugFlags = 0x0;
  197. //
  198. // ------------------------------------------------------------------ Functions
  199. //
  200. PUHCI_CONTROLLER
  201. UhcipInitializeControllerState (
  202. ULONG IoPortBase
  203. )
  204. /*++
  205. Routine Description:
  206. This routine initializes the state and variables needed to start up a UHCI
  207. host controller.
  208. Arguments:
  209. IoPortBase - Supplies the base I/O port of the UHCI registers.
  210. Return Value:
  211. Returns a pointer to the UHCI controller state object on success.
  212. NULL on failure.
  213. --*/
  214. {
  215. ULONG BlockSize;
  216. PUHCI_CONTROLLER Controller;
  217. PHYSICAL_ADDRESS ControlQueuePhysicalAddress;
  218. ULONG Flags;
  219. ULONG Frame;
  220. PHYSICAL_ADDRESS InterruptQueuePhysicalAddress;
  221. ULONG IoBufferFlags;
  222. KSTATUS Status;
  223. //
  224. // Allocate the controller structure itself.
  225. //
  226. Controller = MmAllocateNonPagedPool(sizeof(UHCI_CONTROLLER),
  227. UHCI_ALLOCATION_TAG);
  228. if (Controller == NULL) {
  229. Status = STATUS_INSUFFICIENT_RESOURCES;
  230. goto InitializeControllerStateEnd;
  231. }
  232. RtlZeroMemory(Controller, sizeof(UHCI_CONTROLLER));
  233. INITIALIZE_LIST_HEAD(&(Controller->QueueListHead));
  234. INITIALIZE_LIST_HEAD(&(Controller->IsochronousTransferListHead));
  235. Controller->IoPortBase = (USHORT)IoPortBase;
  236. Controller->UsbCoreHandle = INVALID_HANDLE;
  237. Controller->InterruptHandle = INVALID_HANDLE;
  238. KeInitializeSpinLock(&(Controller->Lock));
  239. //
  240. // Allocate and initialize the buffer used to hold the UHCI schedule.
  241. //
  242. IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
  243. Controller->ScheduleIoBuffer = MmAllocateNonPagedIoBuffer(
  244. 0,
  245. MAX_ULONG,
  246. UHCI_FRAME_LIST_ALIGNMENT,
  247. sizeof(UHCI_SCHEDULE),
  248. IoBufferFlags);
  249. if (Controller->ScheduleIoBuffer == NULL) {
  250. Status = STATUS_INSUFFICIENT_RESOURCES;
  251. goto InitializeControllerStateEnd;
  252. }
  253. ASSERT(Controller->ScheduleIoBuffer->FragmentCount == 1);
  254. ASSERT(Controller->ScheduleIoBuffer->Fragment[0].Size >=
  255. sizeof(UHCI_SCHEDULE));
  256. Controller->Schedule =
  257. Controller->ScheduleIoBuffer->Fragment[0].VirtualAddress;
  258. //
  259. // Create the block allocator used to allocate transfers and queues. The
  260. // block size is that of the larger structure.
  261. //
  262. if (sizeof(UHCI_TRANSFER) >= sizeof(UHCI_TRANSFER_QUEUE)) {
  263. BlockSize = sizeof(UHCI_TRANSFER);
  264. } else {
  265. BlockSize = sizeof(UHCI_TRANSFER_QUEUE);
  266. }
  267. Flags = BLOCK_ALLOCATOR_FLAG_NON_PAGED |
  268. BLOCK_ALLOCATOR_FLAG_PHYSICALLY_CONTIGUOUS;
  269. Controller->BlockAllocator = MmCreateBlockAllocator(
  270. BlockSize,
  271. UHCI_BLOCK_ALLOCATOR_ALIGNMENT,
  272. UHCI_BLOCK_ALLOCATOR_EXPANSION_COUNT,
  273. Flags,
  274. UHCI_BLOCK_ALLOCATION_TAG);
  275. if (Controller->BlockAllocator == NULL) {
  276. Status = STATUS_INSUFFICIENT_RESOURCES;
  277. goto InitializeControllerStateEnd;
  278. }
  279. //
  280. // Allocate and initialize the head of the interrupt queue.
  281. //
  282. Controller->InterruptQueue = MmAllocateBlock(
  283. Controller->BlockAllocator,
  284. &InterruptQueuePhysicalAddress);
  285. if (Controller->InterruptQueue == NULL) {
  286. Status = STATUS_INSUFFICIENT_RESOURCES;
  287. goto InitializeControllerStateEnd;
  288. }
  289. RtlZeroMemory(Controller->InterruptQueue, sizeof(UHCI_TRANSFER_QUEUE));
  290. Controller->InterruptQueue->PhysicalAddress = InterruptQueuePhysicalAddress;
  291. INITIALIZE_LIST_HEAD(&(Controller->InterruptQueue->TransferListHead));
  292. Controller->InterruptQueue->HardwareQueueHead.ElementLink =
  293. UHCI_QUEUE_HEAD_LINK_TERMINATE;
  294. //
  295. // Allocate and initialize the control queue.
  296. //
  297. Controller->ControlQueue = MmAllocateBlock(Controller->BlockAllocator,
  298. &ControlQueuePhysicalAddress);
  299. if (Controller->ControlQueue == NULL) {
  300. Status = STATUS_INSUFFICIENT_RESOURCES;
  301. goto InitializeControllerStateEnd;
  302. }
  303. RtlZeroMemory(Controller->ControlQueue, sizeof(UHCI_TRANSFER_QUEUE));
  304. Controller->ControlQueue->PhysicalAddress = ControlQueuePhysicalAddress;
  305. INITIALIZE_LIST_HEAD(&(Controller->ControlQueue->TransferListHead));
  306. Controller->ControlQueue->HardwareQueueHead.ElementLink =
  307. UHCI_QUEUE_HEAD_LINK_TERMINATE;
  308. //
  309. // Point the interrupt queue at the control queue, and the control queue
  310. // back at the control queue. Bulk transfers will insert themselves
  311. // after the control queue and Isochronous transfers will insert thesmelves
  312. // at specific frames before the interrupt queue. So the total order will
  313. // go Isochronous, Interrupt, Control, Bulk, and then loop back to
  314. // Control and Bulk if there is time remaining.
  315. //
  316. ASSERT((ControlQueuePhysicalAddress &
  317. (~UHCI_QUEUE_HEAD_LINK_ADDRESS_MASK)) == 0);
  318. ASSERT((InterruptQueuePhysicalAddress &
  319. (~UHCI_QUEUE_HEAD_LINK_ADDRESS_MASK)) == 0);
  320. Controller->InterruptQueue->HardwareQueueHead.LinkPointer =
  321. (ULONG)ControlQueuePhysicalAddress | UHCI_QUEUE_HEAD_LINK_QUEUE_HEAD;
  322. Controller->ControlQueue->HardwareQueueHead.LinkPointer =
  323. (ULONG)ControlQueuePhysicalAddress | UHCI_QUEUE_HEAD_LINK_QUEUE_HEAD;
  324. //
  325. // Wire up the software list as well.
  326. //
  327. INSERT_AFTER(&(Controller->InterruptQueue->GlobalListEntry),
  328. &(Controller->QueueListHead));
  329. INSERT_AFTER(&(Controller->ControlQueue->GlobalListEntry),
  330. &(Controller->InterruptQueue->GlobalListEntry));
  331. //
  332. // Initialize all frames to point at the interrupt queue.
  333. //
  334. for (Frame = 0; Frame < UHCI_FRAME_LIST_ENTRY_COUNT; Frame += 1) {
  335. Controller->Schedule->Frame[Frame] =
  336. (ULONG)InterruptQueuePhysicalAddress |
  337. UHCI_QUEUE_HEAD_LINK_QUEUE_HEAD;
  338. }
  339. UhcipFlushCacheRegion(Controller->Schedule, sizeof(UHCI_SCHEDULE));
  340. UhcipFlushCacheRegion(&(Controller->ControlQueue->HardwareQueueHead),
  341. sizeof(UHCI_QUEUE_HEAD));
  342. UhcipFlushCacheRegion(&(Controller->InterruptQueue->HardwareQueueHead),
  343. sizeof(UHCI_QUEUE_HEAD));
  344. //
  345. // Create the port status timer and DPC.
  346. //
  347. Controller->PortStatusTimer = KeCreateTimer(UHCI_ALLOCATION_TAG);
  348. if (Controller->PortStatusTimer == NULL) {
  349. Status = STATUS_INSUFFICIENT_RESOURCES;
  350. goto InitializeControllerStateEnd;
  351. }
  352. Controller->PortStatusDpc = KeCreateDpc(UhcipPortStatusDpc, Controller);
  353. if (Controller->PortStatusDpc == NULL) {
  354. Status = STATUS_INSUFFICIENT_RESOURCES;
  355. goto InitializeControllerStateEnd;
  356. }
  357. Status = STATUS_SUCCESS;
  358. InitializeControllerStateEnd:
  359. if (!KSUCCESS(Status)) {
  360. if (Controller != NULL) {
  361. UhcipDestroyControllerState(Controller);
  362. Controller = NULL;
  363. }
  364. }
  365. return Controller;
  366. }
  367. VOID
  368. UhcipDestroyControllerState (
  369. PUHCI_CONTROLLER Controller
  370. )
  371. /*++
  372. Routine Description:
  373. This routine destroys the memory associated with a UHCI controller.
  374. Arguments:
  375. Controller - Supplies a pointer to the UHCI controller state to release.
  376. Return Value:
  377. None.
  378. --*/
  379. {
  380. if (Controller->ScheduleIoBuffer != NULL) {
  381. MmFreeIoBuffer(Controller->ScheduleIoBuffer);
  382. }
  383. if (Controller->InterruptQueue != NULL) {
  384. MmFreeBlock(Controller->BlockAllocator,
  385. Controller->InterruptQueue);
  386. }
  387. if (Controller->ControlQueue != NULL) {
  388. MmFreeBlock(Controller->BlockAllocator,
  389. Controller->ControlQueue);
  390. }
  391. if (Controller->BlockAllocator != NULL) {
  392. MmDestroyBlockAllocator(Controller->BlockAllocator);
  393. }
  394. ASSERT(LIST_EMPTY(&(Controller->QueueListHead)) != FALSE);
  395. ASSERT(LIST_EMPTY(&(Controller->IsochronousTransferListHead)) != FALSE);
  396. if (Controller->PortStatusTimer != NULL) {
  397. KeDestroyTimer(Controller->PortStatusTimer);
  398. }
  399. if (Controller->PortStatusDpc != NULL) {
  400. KeDestroyDpc(Controller->PortStatusDpc);
  401. }
  402. if (Controller->UsbCoreHandle != INVALID_HANDLE) {
  403. UsbHostDestroyControllerState(Controller->UsbCoreHandle);
  404. }
  405. MmFreeNonPagedPool(Controller);
  406. return;
  407. }
  408. KSTATUS
  409. UhcipRegisterController (
  410. PUHCI_CONTROLLER Controller,
  411. PDEVICE Device
  412. )
  413. /*++
  414. Routine Description:
  415. This routine registers the started UHCI controller with the core USB
  416. library.
  417. Arguments:
  418. Controller - Supplies a pointer to the UHCI controller state of the
  419. controller to register.
  420. Device - Supplies a pointer to the device object.
  421. Return Value:
  422. Status code.
  423. --*/
  424. {
  425. USB_HOST_CONTROLLER_INTERFACE Interface;
  426. KSTATUS Status;
  427. //
  428. // Fill out the functions that the USB core library will use to control
  429. // the UHCI controller.
  430. //
  431. RtlZeroMemory(&Interface, sizeof(USB_HOST_CONTROLLER_INTERFACE));
  432. Interface.Version = USB_HOST_CONTROLLER_INTERFACE_VERSION;
  433. Interface.DriverObject = UhciDriver;
  434. Interface.DeviceObject = Device;
  435. Interface.HostControllerContext = Controller;
  436. Interface.Speed = UsbDeviceSpeedFull;
  437. Interface.DebugPortSubType = -1;
  438. Interface.RootHubPortCount = 2;
  439. Interface.CreateEndpoint = UhcipCreateEndpoint;
  440. Interface.ResetEndpoint = UhcipResetEndpoint;
  441. Interface.FlushEndpoint = UhcipFlushEndpoint;
  442. Interface.DestroyEndpoint = UhcipDestroyEndpoint;
  443. Interface.CreateTransfer = UhcipCreateTransfer;
  444. Interface.DestroyTransfer = UhcipDestroyTransfer;
  445. Interface.SubmitTransfer = UhcipSubmitTransfer;
  446. Interface.SubmitPolledTransfer = UhcipSubmitPolledTransfer;
  447. Interface.CancelTransfer = UhcipCancelTransfer;
  448. Interface.GetRootHubStatus = UhcipGetRootHubStatus;
  449. Interface.SetRootHubStatus = UhcipSetRootHubStatus;
  450. Status = UsbHostRegisterController(&Interface,
  451. &(Controller->UsbCoreHandle));
  452. if (!KSUCCESS(Status)) {
  453. goto RegisterControllerEnd;
  454. }
  455. RegisterControllerEnd:
  456. return Status;
  457. }
  458. VOID
  459. UhcipSetInterruptHandle (
  460. PUHCI_CONTROLLER Controller,
  461. HANDLE InterruptHandle
  462. )
  463. /*++
  464. Routine Description:
  465. This routine saves the handle of the connected interrupt in the UHCI
  466. controller.
  467. Arguments:
  468. Controller - Supplies a pointer to the UHCI controller state.
  469. InterruptHandle - Supplies the connected interrupt handle.
  470. Return Value:
  471. None.
  472. --*/
  473. {
  474. Controller->InterruptHandle = InterruptHandle;
  475. return;
  476. }
  477. KSTATUS
  478. UhcipResetController (
  479. PUHCI_CONTROLLER Controller
  480. )
  481. /*++
  482. Routine Description:
  483. This routine resets and starts the UHCI controller.
  484. Arguments:
  485. Controller - Supplies a pointer to the UHCI controller state of the
  486. controller to reset.
  487. Return Value:
  488. Status code.
  489. --*/
  490. {
  491. ULONG CommandRegister;
  492. ULONG FrameBaseRegister;
  493. ULONG InterruptRegister;
  494. ULONG PortStatusRegister;
  495. //
  496. // Reset the host controller and wait for the hardware to clear the bit,
  497. // which indicates that the reset is complete.
  498. //
  499. CommandRegister = UHCI_COMMAND_HOST_CONTROLLER_RESET;
  500. UHCI_WRITE_REGISTER(Controller, UhciRegisterUsbCommand, CommandRegister);
  501. do {
  502. //
  503. // AND in the hardware register to see if the bit has cleared.
  504. //
  505. CommandRegister &= UHCI_READ_REGISTER(Controller,
  506. UhciRegisterUsbCommand);
  507. } while (CommandRegister != 0);
  508. //
  509. // Disable the ports.
  510. //
  511. UHCI_WRITE_REGISTER(Controller, UhciRegisterPort1StatusControl, 0);
  512. UHCI_WRITE_REGISTER(Controller, UhciRegisterPort2StatusControl, 0);
  513. //
  514. // Clear the status register.
  515. //
  516. UHCI_WRITE_REGISTER(Controller, UhciRegisterUsbStatus, 0);
  517. //
  518. // Enable all interrupts.
  519. //
  520. InterruptRegister = UHCI_INTERRUPT_SHORT_PACKET |
  521. UHCI_INTERRUPT_COMPLETION |
  522. UHCI_INTERRUPT_RESUME |
  523. UHCI_INTERRUPT_TIMEOUT_CRC_ERROR;
  524. UHCI_WRITE_REGISTER(Controller,
  525. UhciRegisterUsbInterruptEnable,
  526. InterruptRegister);
  527. //
  528. // Set the frame list base register to the physical address of the UHCI
  529. // schedule.
  530. //
  531. FrameBaseRegister =
  532. (ULONG)Controller->ScheduleIoBuffer->Fragment[0].PhysicalAddress;
  533. UHCI_WRITE_REGISTER_LONG(Controller,
  534. UhciRegisterFrameBaseAddress,
  535. FrameBaseRegister);
  536. //
  537. // Write to the command register to start the controller.
  538. //
  539. CommandRegister = UHCI_COMMAND_MAX_RECLAMATION_PACKET_64 |
  540. UHCI_COMMAND_CONFIGURED |
  541. UHCI_COMMAND_RUN;
  542. UHCI_WRITE_REGISTER(Controller, UhciRegisterUsbCommand, CommandRegister);
  543. //
  544. // Fire up both ports.
  545. //
  546. PortStatusRegister = UHCI_PORT_ENABLED;
  547. UHCI_WRITE_REGISTER(Controller,
  548. UhciRegisterPort1StatusControl,
  549. PortStatusRegister);
  550. UHCI_WRITE_REGISTER(Controller,
  551. UhciRegisterPort2StatusControl,
  552. PortStatusRegister);
  553. return STATUS_SUCCESS;
  554. }
  555. INTERRUPT_STATUS
  556. UhcipInterruptService (
  557. PVOID Context
  558. )
  559. /*++
  560. Routine Description:
  561. This routine implements the UHCI interrupt service routine.
  562. Arguments:
  563. Context - Supplies the context pointer given to the system when the
  564. interrupt was connected. In this case, this points to the UHCI
  565. controller.
  566. Return Value:
  567. Interrupt status.
  568. --*/
  569. {
  570. PUHCI_CONTROLLER Controller;
  571. INTERRUPT_STATUS InterruptStatus;
  572. USHORT UsbStatus;
  573. Controller = (PUHCI_CONTROLLER)Context;
  574. InterruptStatus = InterruptStatusNotClaimed;
  575. //
  576. // Read the status register. If it's non-zero, this is USB's interrupt.
  577. //
  578. UsbStatus = UHCI_READ_REGISTER(Controller, UhciRegisterUsbStatus);
  579. if (UsbStatus != 0) {
  580. InterruptStatus = InterruptStatusClaimed;
  581. UHCI_WRITE_REGISTER(Controller, UhciRegisterUsbStatus, UsbStatus);
  582. RtlAtomicOr32(&(Controller->PendingStatusBits), UsbStatus);
  583. }
  584. return InterruptStatus;
  585. }
  586. INTERRUPT_STATUS
  587. UhcipInterruptServiceDpc (
  588. PVOID Context
  589. )
  590. /*++
  591. Routine Description:
  592. This routine implements the dispatch level UHCI interrupt service routine.
  593. Arguments:
  594. Context - Supplies the context pointer given to the system when the
  595. interrupt was connected. In this case, this points to the UHCI
  596. controller.
  597. Return Value:
  598. Interrupt status.
  599. --*/
  600. {
  601. PUHCI_CONTROLLER Controller;
  602. ULONG PendingStatus;
  603. Controller = Context;
  604. PendingStatus = RtlAtomicExchange32(&(Controller->PendingStatusBits), 0);
  605. if (PendingStatus == 0) {
  606. return InterruptStatusNotClaimed;
  607. }
  608. UhcipProcessInterrupt(Controller, PendingStatus);
  609. return InterruptStatusClaimed;
  610. }
  611. KSTATUS
  612. UhcipInitializePortChangeDetection (
  613. PUHCI_CONTROLLER Controller
  614. )
  615. /*++
  616. Routine Description:
  617. This routine initializes the UHCI port status change timer in order to
  618. periodically check to see if devices have been added or removed from
  619. the USB root hub.
  620. Arguments:
  621. Controller - Supplies a pointer to the UHCI controller state of the
  622. controller whose ports need status change detection.
  623. Return Value:
  624. Status code.
  625. --*/
  626. {
  627. ULONGLONG Period;
  628. KSTATUS Status;
  629. Period = KeConvertMicrosecondsToTimeTicks(UHCI_PORT_STATUS_CHANGE_PERIOD);
  630. Status = KeQueueTimer(Controller->PortStatusTimer,
  631. TimerQueueSoft,
  632. 0,
  633. Period,
  634. 0,
  635. Controller->PortStatusDpc);
  636. ASSERT(KSUCCESS(Status));
  637. return Status;
  638. }
  639. //
  640. // --------------------------------------------------------- Internal Functions
  641. //
  642. KSTATUS
  643. UhcipCreateEndpoint (
  644. PVOID HostControllerContext,
  645. PUSB_HOST_ENDPOINT_CREATION_REQUEST Endpoint,
  646. PVOID *EndpointContext
  647. )
  648. /*++
  649. Routine Description:
  650. This routine is called by the USB core when a new endpoint is being opened.
  651. It allows the host controller to create and store any context needed to
  652. support a new endpoint (such as a queue head).
  653. Arguments:
  654. HostControllerContext - Supplies the context pointer passed to the USB core
  655. when the controller was created. This is used to identify the USB host
  656. controller to the host controller driver.
  657. Endpoint - Supplies a pointer containing information about the endpoint
  658. being created. The host controller cannot count on this buffer sticking
  659. around after the function returns. If it needs this information it
  660. should make a copy of it.
  661. EndpointContext - Supplies a pointer where the host controller can store a
  662. context pointer identifying the endpoint created.
  663. Return Value:
  664. STATUS_SUCCESS if the endpoint can be successfully accommodated.
  665. Failing status code if the endpoint cannot be opened.
  666. --*/
  667. {
  668. PUHCI_ENDPOINT NewEndpoint;
  669. KSTATUS Status;
  670. NewEndpoint = MmAllocateNonPagedPool(sizeof(UHCI_ENDPOINT),
  671. UHCI_ALLOCATION_TAG);
  672. if (NewEndpoint == NULL) {
  673. Status = STATUS_INSUFFICIENT_RESOURCES;
  674. goto CreateEndpointEnd;
  675. }
  676. RtlZeroMemory(NewEndpoint, sizeof(UHCI_ENDPOINT));
  677. INITIALIZE_LIST_HEAD(&(NewEndpoint->QueueListHead));
  678. NewEndpoint->TransferType = Endpoint->Type;
  679. ASSERT((Endpoint->Speed == UsbDeviceSpeedLow) ||
  680. (Endpoint->Speed == UsbDeviceSpeedFull));
  681. NewEndpoint->Speed = Endpoint->Speed;
  682. ASSERT(Endpoint->MaxPacketSize != 0);
  683. NewEndpoint->MaxPacketSize = Endpoint->MaxPacketSize;
  684. NewEndpoint->EndpointNumber = Endpoint->EndpointNumber;
  685. Status = STATUS_SUCCESS;
  686. CreateEndpointEnd:
  687. if (!KSUCCESS(Status)) {
  688. if (NewEndpoint != NULL) {
  689. MmFreeNonPagedPool(NewEndpoint);
  690. NewEndpoint = NULL;
  691. }
  692. }
  693. *EndpointContext = NewEndpoint;
  694. return Status;
  695. }
  696. VOID
  697. UhcipResetEndpoint (
  698. PVOID HostControllerContext,
  699. PVOID EndpointContext,
  700. ULONG MaxPacketSize
  701. )
  702. /*++
  703. Routine Description:
  704. This routine is called by the USB core when an endpoint needs to be reset.
  705. Arguments:
  706. HostControllerContext - Supplies the context pointer passed to the USB core
  707. when the controller was created. This is used to identify the USB host
  708. controller to the host controller driver.
  709. EndpointContext - Supplies a pointer to the context returned by the host
  710. controller when the endpoint was created.
  711. MaxPacketSize - Supplies the maximum transfer size of the endpoint.
  712. Return Value:
  713. None.
  714. --*/
  715. {
  716. PUHCI_ENDPOINT Endpoint;
  717. Endpoint = (PUHCI_ENDPOINT)EndpointContext;
  718. //
  719. // There better not be any active queues running around during an endpoint
  720. // reset.
  721. //
  722. ASSERT(LIST_EMPTY(&(Endpoint->QueueListHead)) != FALSE);
  723. Endpoint->DataToggle = FALSE;
  724. Endpoint->MaxPacketSize = MaxPacketSize;
  725. return;
  726. }
  727. KSTATUS
  728. UhcipFlushEndpoint (
  729. PVOID HostControllerContext,
  730. PVOID EndpointContext,
  731. PULONG TransferCount
  732. )
  733. /*++
  734. Routine Description:
  735. This routine flushes all the active transfers from an endpoint. It does so
  736. by polling for completion status and does not return until all transfers
  737. are completed. This must be called at high run level.
  738. Arguments:
  739. HostControllerContext - Supplies the context pointer passed to the USB core
  740. when the controller was created. This is used to identify the USB host
  741. controller to the host controller driver.
  742. EndpointContext - Supplies a pointer to the context returned by the host
  743. controller when the endpoint was created.
  744. TransferCount - Supplies a pointer to a boolean that receives the number
  745. of transfers that were flushed.
  746. Return Value:
  747. Status code.
  748. --*/
  749. {
  750. PUHCI_CONTROLLER Controller;
  751. ULONG Count;
  752. PLIST_ENTRY CurrentQueueEntry;
  753. PLIST_ENTRY CurrentTransferEntry;
  754. PUHCI_ENDPOINT Endpoint;
  755. PUHCI_TRANSFER_QUEUE Queue;
  756. BOOL RemoveQueue;
  757. KSTATUS Status;
  758. ULONGLONG Timeout;
  759. PUHCI_TRANSFER Transfer;
  760. //
  761. // This routine removes transfers without acquiring the controller lock. It
  762. // is expected that the caller is using under special circumstances at high
  763. // run level (e.g. to prepare for crash dump writes during system failure).
  764. //
  765. ASSERT(KeGetRunLevel() == RunLevelHigh);
  766. Controller = (PUHCI_CONTROLLER)HostControllerContext;
  767. Endpoint = (PUHCI_ENDPOINT)EndpointContext;
  768. if (Endpoint->TransferType == UsbTransferTypeIsochronous) {
  769. //
  770. // TODO: Implement support for isochronous transfers.
  771. //
  772. ASSERT(FALSE);
  773. return STATUS_NOT_SUPPORTED;
  774. }
  775. //
  776. // Let every transfer queue in the endpoint complete. If the caller is
  777. // about to use this endpoint for an operation during a system failure,
  778. // then the endpoint better be alive enough to finish the rest of its
  779. // current transfers.
  780. //
  781. Timeout = HlQueryTimeCounter() +
  782. (HlQueryTimeCounterFrequency() * UHCI_ENDPOINT_FLUSH_TIMEOUT);
  783. Count = 0;
  784. while (LIST_EMPTY(&(Endpoint->QueueListHead)) == FALSE) {
  785. if (HlQueryTimeCounter() > Timeout) {
  786. Status = STATUS_TIMEOUT;
  787. goto FlushEndpointEnd;
  788. }
  789. CurrentQueueEntry = Endpoint->QueueListHead.Next;
  790. while (CurrentQueueEntry != &(Endpoint->QueueListHead)) {
  791. Queue = LIST_VALUE(CurrentQueueEntry,
  792. UHCI_TRANSFER_QUEUE,
  793. EndpointListEntry);
  794. CurrentQueueEntry = CurrentQueueEntry->Next;
  795. ASSERT(Queue != Controller->ControlQueue);
  796. ASSERT(Queue != Controller->InterruptQueue);
  797. //
  798. // Loop through every transfer in the queue.
  799. //
  800. RemoveQueue = FALSE;
  801. CurrentTransferEntry = Queue->TransferListHead.Next;
  802. while (CurrentTransferEntry != &(Queue->TransferListHead)) {
  803. Transfer = LIST_VALUE(CurrentTransferEntry,
  804. UHCI_TRANSFER,
  805. QueueListEntry);
  806. CurrentTransferEntry = CurrentTransferEntry->Next;
  807. //
  808. // Examine the tranfser, and determine whether or not it's
  809. // complete.
  810. //
  811. RemoveQueue = UhcipProcessPotentiallyCompletedTransfer(
  812. Queue,
  813. Transfer);
  814. if ((RemoveQueue != FALSE) ||
  815. (Transfer == Queue->LastTransfer)) {
  816. break;
  817. }
  818. }
  819. //
  820. // If the queue isn't already slated to be removed, look to see
  821. // if it is empty.
  822. //
  823. if ((RemoveQueue == FALSE) &&
  824. ((Queue->HardwareQueueHead.ElementLink &
  825. UHCI_QUEUE_HEAD_LINK_TERMINATE) != 0)) {
  826. RemoveQueue = TRUE;
  827. }
  828. //
  829. // If necessary, remove the queue from the schedule. Do not notify
  830. // the USB core that the transfer is done. This routine is meant
  831. // to be used at high run level during system failure. There isn't
  832. // anyone listening for the transfer completion.
  833. //
  834. if (RemoveQueue != FALSE) {
  835. UhcipRemoveTransferQueue(Controller, Queue, FALSE);
  836. Count += 1;
  837. }
  838. }
  839. }
  840. Status = STATUS_SUCCESS;
  841. FlushEndpointEnd:
  842. *TransferCount = Count;
  843. return Status;
  844. }
  845. VOID
  846. UhcipDestroyEndpoint (
  847. PVOID HostControllerContext,
  848. PVOID EndpointContext
  849. )
  850. /*++
  851. Routine Description:
  852. This routine tears down and destroys an endpoint created with the endpoint
  853. creation routine.
  854. Arguments:
  855. HostControllerContext - Supplies the context pointer passed to the USB core
  856. when the controller was created. This is used to identify the USB host
  857. controller to the host controller driver.
  858. EndpointContext - Supplies a pointer to the context returned by the host
  859. controller when the endpoint was created.
  860. Return Value:
  861. None.
  862. --*/
  863. {
  864. PUHCI_ENDPOINT Endpoint;
  865. Endpoint = (PUHCI_ENDPOINT)EndpointContext;
  866. ASSERT(LIST_EMPTY(&(Endpoint->QueueListHead)) != FALSE);
  867. MmFreeNonPagedPool(Endpoint);
  868. return;
  869. }
  870. KSTATUS
  871. UhcipCreateTransfer (
  872. PVOID HostControllerContext,
  873. PVOID EndpointContext,
  874. ULONG MaxBufferSize,
  875. ULONG Flags,
  876. PVOID *TransferContext
  877. )
  878. /*++
  879. Routine Description:
  880. This routine allocates structures needed for the USB host controller to
  881. support a transfer.
  882. Arguments:
  883. HostControllerContext - Supplies the context pointer passed to the USB core
  884. when the controller was created. This is used to identify the USB host
  885. controller to the host controller driver.
  886. EndpointContext - Supplies a pointer to the host controller's context of
  887. the endpoint that this transfer will eventually be submitted to.
  888. MaxBufferSize - Supplies the maximum buffer length, in bytes, of the
  889. transfer when it is submitted. It is assumed that the host controller
  890. will set up as many transfer descriptors as are needed to support a
  891. transfer of this size.
  892. Flags - Supplies a bitfield of flags regarding the transaction. See
  893. USB_TRANSFER_FLAG_* definitions.
  894. TransferContext - Supplies a pointer where the host controller can store a
  895. context pointer containing any needed structures for the transfer.
  896. Return Value:
  897. None.
  898. --*/
  899. {
  900. PUHCI_CONTROLLER Controller;
  901. PUHCI_ENDPOINT Endpoint;
  902. BOOL ForceShortTransfer;
  903. PUHCI_TRANSFER_QUEUE Queue;
  904. PHYSICAL_ADDRESS QueuePhysicalAddress;
  905. KSTATUS Status;
  906. PUHCI_TRANSFER Transfer;
  907. ULONG TransferCount;
  908. ULONG TransferIndex;
  909. PHYSICAL_ADDRESS TransferPhysicalAddress;
  910. ASSERT(TransferContext != NULL);
  911. Controller = (PUHCI_CONTROLLER)HostControllerContext;
  912. Endpoint = (PUHCI_ENDPOINT)EndpointContext;
  913. ForceShortTransfer = FALSE;
  914. if ((Flags & USB_TRANSFER_FLAG_FORCE_SHORT_TRANSFER) != 0) {
  915. ForceShortTransfer = TRUE;
  916. }
  917. //
  918. // Create a new transfer queue.
  919. //
  920. Queue = MmAllocateBlock(Controller->BlockAllocator, &QueuePhysicalAddress);
  921. if (Queue == NULL) {
  922. Status = STATUS_INSUFFICIENT_RESOURCES;
  923. goto CreateTransferEnd;
  924. }
  925. RtlZeroMemory(Queue, sizeof(UHCI_TRANSFER_QUEUE));
  926. Queue->PhysicalAddress = QueuePhysicalAddress;
  927. INITIALIZE_LIST_HEAD(&(Queue->TransferListHead));
  928. Queue->HardwareQueueHead.ElementLink = UHCI_QUEUE_HEAD_LINK_TERMINATE;
  929. Queue->HardwareQueueHead.LinkPointer = UHCI_QUEUE_HEAD_LINK_TERMINATE;
  930. Queue->Endpoint = Endpoint;
  931. //
  932. // Figure out the number of transfers needed. The first 8 bytes of a
  933. // control transfer (the setup packet) are always on their own. Control
  934. // transfers also have a status stage at the end.
  935. //
  936. TransferCount = 0;
  937. if (Endpoint->TransferType == UsbTransferTypeControl) {
  938. ASSERT(MaxBufferSize >= sizeof(USB_SETUP_PACKET));
  939. MaxBufferSize -= sizeof(USB_SETUP_PACKET);
  940. //
  941. // Account for both the setup and status stage here.
  942. //
  943. TransferCount += 2;
  944. }
  945. //
  946. // Create enough data transfers, where one transfer can hold up to the max
  947. // packet size.
  948. //
  949. if (MaxBufferSize != 0) {
  950. TransferCount += MaxBufferSize / Endpoint->MaxPacketSize;
  951. if ((MaxBufferSize % Endpoint->MaxPacketSize) != 0) {
  952. TransferCount += 1;
  953. }
  954. //
  955. // If this transfer needs to indicate completion with a short packet,
  956. // make sure another transfer is available. This is only necessary if
  957. // the max size for this transfer won't guarantee a short transfer.
  958. //
  959. if (((Flags & USB_TRANSFER_FLAG_FORCE_SHORT_TRANSFER) != 0) &&
  960. (MaxBufferSize >= Endpoint->MaxPacketSize)) {
  961. TransferCount += 1;
  962. }
  963. //
  964. // Account for a USB transfer that will only send zero length packets and
  965. // for control transfers what need to force a zero length packet in the
  966. // data phase.
  967. //
  968. } else if ((ForceShortTransfer != FALSE) ||
  969. (Endpoint->TransferType != UsbTransferTypeControl)) {
  970. TransferCount += 1;
  971. }
  972. //
  973. // Create the new transfers.
  974. //
  975. for (TransferIndex = 0; TransferIndex < TransferCount; TransferIndex += 1) {
  976. //
  977. // Allocate a new transfer.
  978. //
  979. Transfer = MmAllocateBlock(Controller->BlockAllocator,
  980. &TransferPhysicalAddress);
  981. if (Transfer == NULL) {
  982. Status = STATUS_INSUFFICIENT_RESOURCES;
  983. goto CreateTransferEnd;
  984. }
  985. RtlZeroMemory(Transfer, sizeof(UHCI_TRANSFER));
  986. Transfer->PhysicalAddress = TransferPhysicalAddress;
  987. ASSERT((TransferPhysicalAddress &
  988. UHCI_TRANSFER_DESCRIPTOR_LINK_ADDRESS_MASK) ==
  989. TransferPhysicalAddress);
  990. //
  991. // Add the transfer to the end of the queue.
  992. //
  993. INSERT_BEFORE(&(Transfer->QueueListEntry), &(Queue->TransferListHead));
  994. }
  995. Status = STATUS_SUCCESS;
  996. CreateTransferEnd:
  997. if (!KSUCCESS(Status)) {
  998. if (Queue != NULL) {
  999. //
  1000. // Free all transfers that were allocated.
  1001. //
  1002. while (LIST_EMPTY(&(Queue->TransferListHead)) == FALSE) {
  1003. Transfer = LIST_VALUE(Queue->TransferListHead.Next,
  1004. UHCI_TRANSFER,
  1005. QueueListEntry);
  1006. LIST_REMOVE(&(Transfer->QueueListEntry));
  1007. MmFreeBlock(Controller->BlockAllocator, Transfer);
  1008. }
  1009. MmFreeBlock(Controller->BlockAllocator, Queue);
  1010. Queue = NULL;
  1011. }
  1012. }
  1013. *TransferContext = Queue;
  1014. return Status;
  1015. }
  1016. VOID
  1017. UhcipDestroyTransfer (
  1018. PVOID HostControllerContext,
  1019. PVOID EndpointContext,
  1020. PVOID TransferContext
  1021. )
  1022. /*++
  1023. Routine Description:
  1024. This routine destroys host controller structures associated with a USB
  1025. transfer.
  1026. Arguments:
  1027. HostControllerContext - Supplies the context pointer passed to the USB core
  1028. when the controller was created. This is used to identify the USB host
  1029. controller to the host controller driver.
  1030. EndpointContext - Supplies a pointer to the host controller context for the
  1031. endpoint this transfer belonged to.
  1032. TransferContext - Supplies the pointer provided to the USB core by the host
  1033. controller when the transfer was created.
  1034. Return Value:
  1035. None.
  1036. --*/
  1037. {
  1038. PUHCI_CONTROLLER Controller;
  1039. PUHCI_TRANSFER_QUEUE Queue;
  1040. PUHCI_TRANSFER Transfer;
  1041. Controller = (PUHCI_CONTROLLER)HostControllerContext;
  1042. Queue = (PUHCI_TRANSFER_QUEUE)TransferContext;
  1043. //
  1044. // Free all transfers that were allocated.
  1045. //
  1046. while (LIST_EMPTY(&(Queue->TransferListHead)) == FALSE) {
  1047. Transfer = LIST_VALUE(Queue->TransferListHead.Next,
  1048. UHCI_TRANSFER,
  1049. QueueListEntry);
  1050. LIST_REMOVE(&(Transfer->QueueListEntry));
  1051. MmFreeBlock(Controller->BlockAllocator, Transfer);
  1052. }
  1053. MmFreeBlock(Controller->BlockAllocator, Queue);
  1054. return;
  1055. }
  1056. KSTATUS
  1057. UhcipSubmitTransfer (
  1058. PVOID HostControllerContext,
  1059. PVOID EndpointContext,
  1060. PUSB_TRANSFER_INTERNAL Transfer,
  1061. PVOID TransferContext
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine submits a transfer to the USB host controller for execution.
  1066. Arguments:
  1067. HostControllerContext - Supplies the context pointer passed to the USB core
  1068. when the controller was created. This is used to identify the USB host
  1069. controller to the host controller driver.
  1070. EndpointContext - Supplies the context pointer provided to the USB core by
  1071. the host controller when the endpoint was created.
  1072. Transfer - Supplies a pointer to the USB transfer to execute.
  1073. TransferContext - Supplies the pointer provided to the USB core by the host
  1074. controller when the transfer was created.
  1075. Return Value:
  1076. STATUS_SUCCESS if the transfer was successfully added to the hardware queue.
  1077. Failure codes if the transfer could not be added.
  1078. --*/
  1079. {
  1080. PUHCI_CONTROLLER Controller;
  1081. PUHCI_ENDPOINT Endpoint;
  1082. PUHCI_TRANSFER_QUEUE Queue;
  1083. KSTATUS Status;
  1084. Controller = (PUHCI_CONTROLLER)HostControllerContext;
  1085. Endpoint = (PUHCI_ENDPOINT)EndpointContext;
  1086. Queue = (PUHCI_TRANSFER_QUEUE)TransferContext;
  1087. //
  1088. // Prepare and submit the transfer queue.
  1089. //
  1090. Queue->UsbTransfer = Transfer;
  1091. Status = UhcipSubmitTransferQueue(Controller, Endpoint, Queue, NULL, FALSE);
  1092. return Status;
  1093. }
  1094. KSTATUS
  1095. UhcipSubmitPolledTransfer (
  1096. PVOID HostControllerContext,
  1097. PVOID EndpointContext,
  1098. PUSB_TRANSFER_INTERNAL Transfer,
  1099. PVOID TransferContext
  1100. )
  1101. /*++
  1102. Routine Description:
  1103. This routine submits a transfer to the USB host controller for execution
  1104. and busily waits until the transfer has completed.
  1105. Arguments:
  1106. HostControllerContext - Supplies the context pointer passed to the USB core
  1107. when the controller was created. This is used to identify the USB host
  1108. controller to the host controller driver.
  1109. EndpointContext - Supplies the context pointer provided to the USB core by
  1110. the host controller when the endpoint was created.
  1111. Transfer - Supplies a pointer to the USB transfer to execute.
  1112. TransferContext - Supplies the pointer provided to the USB core by the host
  1113. controller when the transfer was created.
  1114. Return Value:
  1115. STATUS_SUCCESS if the transfer was successfully added to the hardware queue.
  1116. Failure codes if the transfer could not be added.
  1117. --*/
  1118. {
  1119. PUHCI_CONTROLLER Controller;
  1120. PLIST_ENTRY CurrentEntry;
  1121. PUHCI_ENDPOINT Endpoint;
  1122. volatile PULONG HardwareStatus;
  1123. PUHCI_TRANSFER_QUEUE Queue;
  1124. BOOL RemoveQueue;
  1125. KSTATUS Status;
  1126. ULONGLONG Timeout;
  1127. ULONG TransferCount;
  1128. ULONG TransferIndex;
  1129. PUHCI_TRANSFER UhciTransfer;
  1130. Controller = (PUHCI_CONTROLLER)HostControllerContext;
  1131. Endpoint = (PUHCI_ENDPOINT)EndpointContext;
  1132. Queue = (PUHCI_TRANSFER_QUEUE)TransferContext;
  1133. //
  1134. // Polled I/O should only be requested at high run level.
  1135. //
  1136. ASSERT(KeGetRunLevel() == RunLevelHigh);
  1137. //
  1138. // There should be no other active queues on the endpoint.
  1139. //
  1140. ASSERT(LIST_EMPTY(&(Endpoint->QueueListHead)) != FALSE);
  1141. //
  1142. // Prepare and submit the transfer queue.
  1143. //
  1144. Queue->UsbTransfer = Transfer;
  1145. Status = UhcipSubmitTransferQueue(Controller,
  1146. Endpoint,
  1147. Queue,
  1148. &TransferCount,
  1149. TRUE);
  1150. if (!KSUCCESS(Status)) {
  1151. return Status;
  1152. }
  1153. //
  1154. // Now poll the transfers in the queue in until they are complete.
  1155. //
  1156. Timeout = HlQueryTimeCounter() +
  1157. (HlQueryTimeCounterFrequency() * UHCI_POLLED_TRANSFER_TIMEOUT);
  1158. CurrentEntry = Queue->TransferListHead.Next;
  1159. for (TransferIndex = 0; TransferIndex < TransferCount; TransferIndex += 1) {
  1160. UhciTransfer = LIST_VALUE(CurrentEntry, UHCI_TRANSFER, QueueListEntry);
  1161. CurrentEntry = CurrentEntry->Next;
  1162. HardwareStatus = &(UhciTransfer->HardwareTransfer.Status);
  1163. while ((*HardwareStatus &
  1164. UHCI_TRANSFER_DESCRIPTOR_STATUS_ACTIVE) != 0) {
  1165. if (HlQueryTimeCounter() > Timeout) {
  1166. Transfer->Public.Status = STATUS_TIMEOUT;
  1167. goto SubmitPolledTransferEnd;
  1168. }
  1169. }
  1170. RemoveQueue = UhcipProcessPotentiallyCompletedTransfer(Queue,
  1171. UhciTransfer);
  1172. if (RemoveQueue != FALSE) {
  1173. break;
  1174. }
  1175. }
  1176. UhcipRemoveTransferQueue(Controller, Queue, FALSE);
  1177. SubmitPolledTransferEnd:
  1178. return Transfer->Public.Status;
  1179. }
  1180. KSTATUS
  1181. UhcipSubmitTransferQueue (
  1182. PUHCI_CONTROLLER Controller,
  1183. PUHCI_ENDPOINT Endpoint,
  1184. PUHCI_TRANSFER_QUEUE Queue,
  1185. PULONG SubmittedTransferCount,
  1186. BOOL LockNotRequired
  1187. )
  1188. /*++
  1189. Routine Description:
  1190. This routine submits a UHCI transfer queue, initializing the transfers and
  1191. placing them in the schedule.
  1192. Arguments:
  1193. Controller - Supplies a pointer to the UHCI controller context.
  1194. Endpoint - Supplies a pointer to the context for the UHCI endpoint on which
  1195. the queue will be submitted.
  1196. Queue - Supplies a pointer to the UHCI transfer queue to submit.
  1197. SubmittedTransferCount - Supplies an optional pointer that receives the
  1198. number of individual transfers submitted for the queue.
  1199. LockNotRequired - Supplies a boolean indicating if the global controller
  1200. lock does not need to be acquired when making the queue submission. The
  1201. default value is FALSE. The lock is only not required in certain
  1202. critical code paths.
  1203. Return Value:
  1204. Status code.
  1205. --*/
  1206. {
  1207. BOOL ControlTransfer;
  1208. PLIST_ENTRY CurrentEntry;
  1209. BOOL ForceShortTransfer;
  1210. BOOL InGlobalList;
  1211. BOOL LastTransfer;
  1212. ULONG Length;
  1213. ULONG Offset;
  1214. RUNLEVEL OldRunLevel;
  1215. PUHCI_TRANSFER PreviousLastTransfer;
  1216. PUHCI_TRANSFER_QUEUE QueueBefore;
  1217. ULONG TotalLength;
  1218. PUSB_TRANSFER_INTERNAL Transfer;
  1219. ULONG TransferCount;
  1220. ULONG TransferIndex;
  1221. PUHCI_TRANSFER UhciTransfer;
  1222. ControlTransfer = FALSE;
  1223. Queue->LinkToLastTransfer = 0;
  1224. Transfer = Queue->UsbTransfer;
  1225. UhciTransfer = NULL;
  1226. //
  1227. // This queue had better not be on a list already.
  1228. //
  1229. ASSERT((Queue->GlobalListEntry.Next == NULL) &&
  1230. (Queue->EndpointListEntry.Next == NULL));
  1231. //
  1232. // Assume that this is going to be a rousing success.
  1233. //
  1234. Transfer->Public.Status = STATUS_SUCCESS;
  1235. Transfer->Public.Error = UsbErrorNone;
  1236. //
  1237. // Determine the number of transfers needed for this transfer, and loop
  1238. // filling them out. This is necessary because the number of transfers
  1239. // per transfer is not constant; the system may re-use a transfer and
  1240. // and change the length.
  1241. //
  1242. TransferCount = 0;
  1243. TotalLength = Transfer->Public.Length;
  1244. if (Endpoint->TransferType == UsbTransferTypeControl) {
  1245. ControlTransfer = TRUE;
  1246. ASSERT(TotalLength >= sizeof(USB_SETUP_PACKET));
  1247. TotalLength -= sizeof(USB_SETUP_PACKET);
  1248. //
  1249. // Account for both the setup and status transfers.
  1250. //
  1251. TransferCount += 2;
  1252. }
  1253. ForceShortTransfer = FALSE;
  1254. if ((Transfer->Public.Flags &
  1255. USB_TRANSFER_FLAG_FORCE_SHORT_TRANSFER) != 0) {
  1256. ForceShortTransfer = TRUE;
  1257. }
  1258. //
  1259. // The required number of transfers for the data can be obtained by
  1260. // dividing the total length by the maximum packet size. An additional
  1261. // transfer is necessary for a remaining short transfer or if a short
  1262. // transfer must be forced in order to complete the whole transaction.
  1263. // Non-control zero length transfers also need to have at least one
  1264. // transfer.
  1265. //
  1266. TransferCount += TotalLength / Endpoint->MaxPacketSize;
  1267. if (((TotalLength % Endpoint->MaxPacketSize) != 0) ||
  1268. ((TotalLength == 0) &&
  1269. (Endpoint->TransferType != UsbTransferTypeControl)) ||
  1270. (ForceShortTransfer != FALSE)) {
  1271. TransferCount += 1;
  1272. }
  1273. Offset = 0;
  1274. CurrentEntry = Queue->TransferListHead.Next;
  1275. //
  1276. // Acquire the lock, if required. It is acquired here as opposed to after
  1277. // the transfer descriptors are filled out to protect the endpoint's data
  1278. // toggle bit, which needs to be sequential even if multiple transfers are
  1279. // being submitted simultaneously.
  1280. //
  1281. if (LockNotRequired == FALSE) {
  1282. OldRunLevel = UhcipAcquireControllerLock(Controller);
  1283. }
  1284. LastTransfer = FALSE;
  1285. for (TransferIndex = 0; TransferIndex < TransferCount; TransferIndex += 1) {
  1286. //
  1287. // Calculate the length for this transfer descriptor.
  1288. //
  1289. Length = Endpoint->MaxPacketSize;
  1290. if (Offset + Length > Transfer->Public.Length) {
  1291. Length = Transfer->Public.Length - Offset;
  1292. }
  1293. if (TransferIndex == (TransferCount - 1)) {
  1294. LastTransfer = TRUE;
  1295. }
  1296. if (ControlTransfer != FALSE) {
  1297. //
  1298. // The first part of a control transfer is the setup packet, which
  1299. // is always 8 bytes long.
  1300. //
  1301. if (Offset == 0) {
  1302. Length = sizeof(USB_SETUP_PACKET);
  1303. }
  1304. //
  1305. // The last part of a control transfer is the status phase and it
  1306. // must be zero in length.
  1307. //
  1308. ASSERT((LastTransfer == FALSE) || (Length == 0));
  1309. }
  1310. ASSERT((Length != 0) ||
  1311. (LastTransfer != FALSE) ||
  1312. ((ForceShortTransfer != FALSE) && (ControlTransfer != FALSE)));
  1313. //
  1314. // Fill out this transfer descriptor.
  1315. //
  1316. ASSERT(CurrentEntry != &(Queue->TransferListHead));
  1317. UhciTransfer = LIST_VALUE(CurrentEntry, UHCI_TRANSFER, QueueListEntry);
  1318. UhcipFillOutTransferDescriptor(Controller,
  1319. Endpoint,
  1320. Queue,
  1321. UhciTransfer,
  1322. Transfer,
  1323. Offset,
  1324. Length,
  1325. LastTransfer);
  1326. //
  1327. // Move on to the next descriptor.
  1328. //
  1329. CurrentEntry = CurrentEntry->Next;
  1330. Offset += Length;
  1331. }
  1332. //
  1333. // Terminate the last transaction filled out.
  1334. //
  1335. UhciTransfer->HardwareTransfer.LinkPointer =
  1336. UHCI_TRANSFER_DESCRIPTOR_LINK_TERMINATE;
  1337. Queue->LastTransfer = UhciTransfer;
  1338. //
  1339. // For control transfers, remember the link value that points to the last
  1340. // transfer.
  1341. //
  1342. if (Transfer->Type == UsbTransferTypeControl) {
  1343. UhciTransfer = LIST_VALUE(UhciTransfer->QueueListEntry.Previous,
  1344. UHCI_TRANSFER,
  1345. QueueListEntry);
  1346. Queue->LinkToLastTransfer = UhciTransfer->HardwareTransfer.LinkPointer;
  1347. }
  1348. //
  1349. // The transfer is ready to go. Do the actual insertion.
  1350. //
  1351. if (Transfer->Type == UsbTransferTypeIsochronous) {
  1352. //
  1353. // TODO: Implement support for isochronous transfers.
  1354. //
  1355. ASSERT(FALSE);
  1356. //
  1357. // If this is not an isochronous transfer, put the transfer in the hardware
  1358. // queue head corresponding to its endpoint.
  1359. //
  1360. } else {
  1361. INSERT_BEFORE(&(Queue->EndpointListEntry), &(Endpoint->QueueListHead));
  1362. //
  1363. // The async schedule looks something like this. Forgive the ASCII art.
  1364. // ControlQueue -> EP0,Q0 -> EPX,Q0 -> Interrupt Queue -> ...
  1365. // | // | /
  1366. // EP0,Q1_// EPX, Q1_/
  1367. // TD | TD
  1368. // TD |
  1369. // ... |
  1370. // EP0,Q2/
  1371. // TD
  1372. // ...
  1373. //
  1374. // Queues encaspulate the many transfer descriptors that make up a
  1375. // single USB Transfer. All the transfers for an single endpoint run
  1376. // vertically, and all link pointers for that endpoint point at the
  1377. // next endpoint's column of stuff (so that if something stalls in an
  1378. // endpoint, the controller moves on to other work).
  1379. //
  1380. // If this is the only queue/transfer in the endpoint, then link onto
  1381. // the global queues.
  1382. //
  1383. if (Queue->EndpointListEntry.Previous == &(Endpoint->QueueListHead)) {
  1384. InGlobalList = TRUE;
  1385. if (Transfer->Type == UsbTransferTypeControl) {
  1386. QueueBefore = Controller->ControlQueue;
  1387. } else if (Transfer->Type == UsbTransferTypeInterrupt) {
  1388. QueueBefore = Controller->InterruptQueue;
  1389. } else {
  1390. ASSERT(Transfer->Type == UsbTransferTypeBulk);
  1391. ASSERT(LIST_EMPTY(&(Controller->QueueListHead)) == FALSE);
  1392. QueueBefore = LIST_VALUE(Controller->QueueListHead.Previous,
  1393. UHCI_TRANSFER_QUEUE,
  1394. GlobalListEntry);
  1395. }
  1396. //
  1397. // There are other transfer queues in for this endpoint, so link onto
  1398. // the last transfer descriptor of the last queue.
  1399. //
  1400. } else {
  1401. InGlobalList = FALSE;
  1402. QueueBefore = LIST_VALUE(Queue->EndpointListEntry.Previous,
  1403. UHCI_TRANSFER_QUEUE,
  1404. EndpointListEntry);
  1405. }
  1406. INSERT_AFTER(&(Queue->GlobalListEntry),
  1407. &(QueueBefore->GlobalListEntry));
  1408. //
  1409. // Set the link of this queue to point wherever the previous queue
  1410. // pointed.
  1411. //
  1412. Queue->HardwareQueueHead.LinkPointer =
  1413. QueueBefore->HardwareQueueHead.LinkPointer;
  1414. UhcipFlushCacheRegion(&(Queue->HardwareQueueHead),
  1415. sizeof(UHCI_QUEUE_HEAD));
  1416. //
  1417. // If being inserted into the global list, then insert this queue into
  1418. // the chain.
  1419. //
  1420. if (InGlobalList != FALSE) {
  1421. QueueBefore->HardwareQueueHead.LinkPointer =
  1422. (ULONG)Queue->PhysicalAddress | UHCI_QUEUE_HEAD_LINK_QUEUE_HEAD;
  1423. UhcipFlushCacheRegion(&(QueueBefore->HardwareQueueHead),
  1424. sizeof(UHCI_QUEUE_HEAD));
  1425. //
  1426. // If this queue goes on the tail of another queue, find the last
  1427. // transfer descriptor of the previous queue and stick it there.
  1428. //
  1429. } else {
  1430. ASSERT(LIST_EMPTY(&(QueueBefore->TransferListHead)) == FALSE);
  1431. PreviousLastTransfer = QueueBefore->LastTransfer;
  1432. ASSERT(PreviousLastTransfer->HardwareTransfer.LinkPointer ==
  1433. UHCI_TRANSFER_DESCRIPTOR_LINK_TERMINATE);
  1434. PreviousLastTransfer->HardwareTransfer.LinkPointer =
  1435. (ULONG)Queue->PhysicalAddress |
  1436. UHCI_TRANSFER_DESCRIPTOR_LINK_QUEUE_HEAD;
  1437. UhcipFlushCacheRegion(&(QueueBefore->HardwareQueueHead),
  1438. sizeof(UHCI_TRANSFER_DESCRIPTOR));
  1439. //
  1440. // There was just a race between this routine setting the new link
  1441. // and the controller reading and recording the old terminate. If
  1442. // the queue before has already got a terminate in it, then set
  1443. // the next element to this queue head so the controller finds this
  1444. // queue.
  1445. //
  1446. if (QueueBefore->HardwareQueueHead.ElementLink ==
  1447. UHCI_QUEUE_HEAD_LINK_TERMINATE) {
  1448. QueueBefore->HardwareQueueHead.ElementLink =
  1449. (ULONG)Queue->PhysicalAddress |
  1450. UHCI_QUEUE_HEAD_LINK_QUEUE_HEAD;
  1451. UhcipFlushCacheRegion(&(QueueBefore->HardwareQueueHead),
  1452. sizeof(UHCI_QUEUE_HEAD));
  1453. }
  1454. }
  1455. }
  1456. //
  1457. // All done. Release the lock, if required, and return.
  1458. //
  1459. if (LockNotRequired == FALSE) {
  1460. UhcipReleaseControllerLock(Controller, OldRunLevel);
  1461. }
  1462. if (SubmittedTransferCount != NULL) {
  1463. *SubmittedTransferCount = TransferCount;
  1464. }
  1465. return STATUS_SUCCESS;
  1466. }
  1467. KSTATUS
  1468. UhcipCancelTransfer (
  1469. PVOID HostControllerContext,
  1470. PVOID EndpointContext,
  1471. PUSB_TRANSFER_INTERNAL Transfer,
  1472. PVOID TransferContext
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. This routine submits attempts to cancel a transfer that was previously
  1477. submitted for execution.
  1478. Arguments:
  1479. HostControllerContext - Supplies the context pointer passed to the USB core
  1480. when the controller was created. This is used to identify the USB host
  1481. controller to the host controller driver.
  1482. EndpointContext - Supplies the context pointer provided to the USB core by
  1483. the host controller when the endpoint was created.
  1484. Transfer - Supplies a pointer to the USB transfer to execute.
  1485. TransferContext - Supplies the pointer provided to the USB core by the host
  1486. controller when the transfer was created.
  1487. Return Value:
  1488. STATUS_SUCCESS if the transfer was successfully removed from the hardware
  1489. queue.
  1490. STATUS_TOO_LATE if the transfer had already completed.
  1491. Other failure codes if the transfer could not be cancelled but has not yet
  1492. completed.
  1493. --*/
  1494. {
  1495. PUHCI_CONTROLLER Controller;
  1496. RUNLEVEL OldRunLevel;
  1497. PUHCI_TRANSFER_QUEUE Queue;
  1498. KSTATUS Status;
  1499. Controller = (PUHCI_CONTROLLER)HostControllerContext;
  1500. Queue = (PUHCI_TRANSFER_QUEUE)TransferContext;
  1501. ASSERT(Queue->UsbTransfer == Transfer);
  1502. //
  1503. // Lock the controller to manipulate lists.
  1504. //
  1505. OldRunLevel = UhcipAcquireControllerLock(Controller);
  1506. //
  1507. // If the queue was already taken off the global list, then the
  1508. // transfer has already completed.
  1509. //
  1510. if (Queue->GlobalListEntry.Next == NULL) {
  1511. ASSERT(Queue->EndpointListEntry.Next == NULL);
  1512. Status = STATUS_TOO_LATE;
  1513. goto CancelTransferEnd;
  1514. }
  1515. //
  1516. // For successfully cancelled, non-isochronous transfers, send the transfer
  1517. // back to USB core. It will be queued there for full completion, so this
  1518. // call is safe while holding the lock.
  1519. //
  1520. if (Transfer->Type != UsbTransferTypeIsochronous) {
  1521. UhcipRemoveTransferQueue(Controller, Queue, TRUE);
  1522. Transfer->Public.Status = STATUS_OPERATION_CANCELLED;
  1523. Transfer->Public.Error = UsbErrorTransferCancelled;
  1524. UsbHostProcessCompletedTransfer(Transfer);
  1525. } else {
  1526. //
  1527. // TODO: Implement support for isochronous transfers.
  1528. //
  1529. ASSERT(FALSE);
  1530. }
  1531. Status = STATUS_SUCCESS;
  1532. CancelTransferEnd:
  1533. //
  1534. // Release the lock and return.
  1535. //
  1536. UhcipReleaseControllerLock(Controller, OldRunLevel);
  1537. return Status;
  1538. }
  1539. KSTATUS
  1540. UhcipGetRootHubStatus (
  1541. PVOID HostControllerContext,
  1542. PUSB_HUB_STATUS HubStatus
  1543. )
  1544. /*++
  1545. Routine Description:
  1546. This routine queries the host controller for the status of the root hub.
  1547. Arguments:
  1548. HostControllerContext - Supplies the context pointer passed to the USB core
  1549. when the controller was created. This is used to identify the USB host
  1550. controller to the host controller driver.
  1551. HubStatus - Supplies a pointer where the host controller should fill out
  1552. the root hub status.
  1553. Return Value:
  1554. STATUS_SUCCESS if the hub status was successfully queried.
  1555. Failure codes if the status could not be queried.
  1556. --*/
  1557. {
  1558. USHORT ChangeBits;
  1559. PUHCI_CONTROLLER Controller;
  1560. USHORT HardwareStatus;
  1561. ULONG PortIndex;
  1562. PUSB_PORT_STATUS PortStatus;
  1563. UHCI_REGISTER Register;
  1564. USHORT SoftwareStatus;
  1565. ASSERT(HubStatus->PortStatus != NULL);
  1566. Controller = (PUHCI_CONTROLLER)HostControllerContext;
  1567. for (PortIndex = 0; PortIndex < UHCI_PORT_COUNT; PortIndex += 1) {
  1568. //
  1569. // Read the hardware register.
  1570. //
  1571. if (PortIndex == 0) {
  1572. Register = UhciRegisterPort1StatusControl;
  1573. } else {
  1574. ASSERT(PortIndex == 1);
  1575. Register = UhciRegisterPort2StatusControl;
  1576. }
  1577. HardwareStatus = UHCI_READ_REGISTER(Controller, Register);
  1578. //
  1579. // Set the corresponding software bits.
  1580. //
  1581. SoftwareStatus = 0;
  1582. if ((HardwareStatus & UHCI_PORT_DEVICE_CONNECTED) != 0) {
  1583. SoftwareStatus |= USB_PORT_STATUS_CONNECTED;
  1584. if ((HardwareStatus & UHCI_PORT_LOW_SPEED) != 0) {
  1585. HubStatus->PortDeviceSpeed[PortIndex] = UsbDeviceSpeedLow;
  1586. } else {
  1587. HubStatus->PortDeviceSpeed[PortIndex] = UsbDeviceSpeedFull;
  1588. }
  1589. }
  1590. if ((HardwareStatus & UHCI_PORT_ENABLED) != 0) {
  1591. SoftwareStatus |= USB_PORT_STATUS_ENABLED;
  1592. }
  1593. if ((HardwareStatus & UHCI_PORT_RESET) != 0) {
  1594. SoftwareStatus |= USB_PORT_STATUS_RESET;
  1595. }
  1596. //
  1597. // If the new software status is different from the current status,
  1598. // then set the appropriate change bits and update the status.
  1599. //
  1600. PortStatus = &(HubStatus->PortStatus[PortIndex]);
  1601. if (SoftwareStatus != PortStatus->Status) {
  1602. ChangeBits = SoftwareStatus ^ PortStatus->Status;
  1603. //
  1604. // Since the status bits are 1-to-1 with the change bits, just OR
  1605. // in the new bits.
  1606. //
  1607. PortStatus->Change |= ChangeBits;
  1608. PortStatus->Status = SoftwareStatus;
  1609. }
  1610. //
  1611. // Acknowledge port connection changes in the hardware and set the
  1612. // change bit in the software. This may have been missed above if the
  1613. // port transitions from connected to connected.
  1614. //
  1615. if ((HardwareStatus & UHCI_PORT_CONNECT_STATUS_CHANGED) != 0) {
  1616. PortStatus->Change |= USB_PORT_STATUS_CHANGE_CONNECTED;
  1617. UHCI_WRITE_REGISTER(Controller, Register, HardwareStatus);
  1618. }
  1619. if ((UhciDebugFlags & UHCI_DEBUG_PORTS) != 0) {
  1620. RtlDebugPrint(
  1621. "UHCI: Controller 0x%x Port %d Status 0x%x. "
  1622. "Connected %d, LowSpeed %d, Enabled %d, Reset %d, "
  1623. "Changed %d.\n",
  1624. Controller,
  1625. PortIndex,
  1626. HardwareStatus,
  1627. (HardwareStatus & UHCI_PORT_DEVICE_CONNECTED) != 0,
  1628. (HardwareStatus & UHCI_PORT_LOW_SPEED) != 0,
  1629. (HardwareStatus & UHCI_PORT_ENABLED) != 0,
  1630. (HardwareStatus & UHCI_PORT_RESET) != 0,
  1631. (HardwareStatus & UHCI_PORT_CONNECT_STATUS_CHANGED) != 0);
  1632. }
  1633. }
  1634. return STATUS_SUCCESS;
  1635. }
  1636. KSTATUS
  1637. UhcipSetRootHubStatus (
  1638. PVOID HostControllerContext,
  1639. PUSB_HUB_STATUS HubStatus
  1640. )
  1641. /*++
  1642. Routine Description:
  1643. This routine sets the state of the root hub in the USB host controller. It
  1644. looks at the status change bits for each port in order to determine what
  1645. needs to be set.
  1646. Arguments:
  1647. HostControllerContext - Supplies the context pointer passed to the USB core
  1648. when the controller was created. This is used to identify the USB host
  1649. controller to the host controller driver.
  1650. HubStatus - Supplies a pointer to the status that should be set in the root
  1651. hub.
  1652. Return Value:
  1653. STATUS_SUCCESS if the hub state was successfully programmed into the device.
  1654. Failure codes if the status could not be set.
  1655. --*/
  1656. {
  1657. PUHCI_CONTROLLER Controller;
  1658. USHORT HardwareStatus;
  1659. USHORT OriginalHardwareStatus;
  1660. ULONG PortIndex;
  1661. PUSB_PORT_STATUS PortStatus;
  1662. UHCI_REGISTER Register;
  1663. USHORT RegisterValue;
  1664. Controller = (PUHCI_CONTROLLER)HostControllerContext;
  1665. for (PortIndex = 0; PortIndex < UHCI_PORT_COUNT; PortIndex += 1) {
  1666. //
  1667. // The caller is required to notify the routine about what needs to be
  1668. // set by updating the change bits. If there are not changed bits, then
  1669. // skip the port.
  1670. //
  1671. PortStatus = &(HubStatus->PortStatus[PortIndex]);
  1672. if (PortStatus->Change == 0) {
  1673. continue;
  1674. }
  1675. //
  1676. // Read the hardware register.
  1677. //
  1678. if (PortIndex == 0) {
  1679. Register = UhciRegisterPort1StatusControl;
  1680. } else {
  1681. ASSERT(PortIndex == 1);
  1682. Register = UhciRegisterPort2StatusControl;
  1683. }
  1684. OriginalHardwareStatus = UHCI_READ_REGISTER(Controller, Register);
  1685. HardwareStatus = OriginalHardwareStatus;
  1686. //
  1687. // Clear out the bits that may potentially be adjusted.
  1688. //
  1689. HardwareStatus &= ~(UHCI_PORT_RESET |
  1690. UHCI_PORT_ENABLED |
  1691. UHCI_PORT_SUSPEND);
  1692. //
  1693. // Set the hardware bits according to what's changed.
  1694. //
  1695. if ((PortStatus->Change & USB_PORT_STATUS_CHANGE_ENABLED) != 0) {
  1696. if ((PortStatus->Status & USB_PORT_STATUS_ENABLED) != 0) {
  1697. HardwareStatus |= UHCI_PORT_ENABLED;
  1698. }
  1699. PortStatus->Change &= ~USB_PORT_STATUS_CHANGE_ENABLED;
  1700. }
  1701. if ((PortStatus->Change & USB_PORT_STATUS_CHANGE_RESET) != 0) {
  1702. if ((PortStatus->Status & USB_PORT_STATUS_RESET) != 0) {
  1703. HardwareStatus |= UHCI_PORT_RESET;
  1704. }
  1705. PortStatus->Change &= ~USB_PORT_STATUS_CHANGE_RESET;
  1706. }
  1707. //
  1708. // Section 2.1.7 of the UHCI Specification says that the PORTSC suspend
  1709. // bit should not be written to 1 if EGSM is set in USBCMD.
  1710. //
  1711. if ((PortStatus->Change & USB_PORT_STATUS_CHANGE_SUSPENDED) != 0) {
  1712. if ((PortStatus->Status & USB_PORT_STATUS_SUSPENDED) != 0) {
  1713. RegisterValue = UHCI_READ_REGISTER(Controller,
  1714. UhciRegisterUsbCommand);
  1715. if ((RegisterValue & UHCI_COMMAND_ENTER_GLOBAL_SUSPEND) == 0) {
  1716. HardwareStatus |= UHCI_PORT_SUSPEND;
  1717. }
  1718. }
  1719. PortStatus->Change &= ~USB_PORT_STATUS_CHANGE_SUSPENDED;
  1720. }
  1721. //
  1722. // Write out the new value if it is different than the old one.
  1723. //
  1724. if (HardwareStatus != OriginalHardwareStatus) {
  1725. UHCI_WRITE_REGISTER(Controller, Register, HardwareStatus);
  1726. }
  1727. //
  1728. // If reset was set, wait the required amount of time and then clear
  1729. // the reset bit, as if this were a hub and it was cleared
  1730. // automatically.
  1731. //
  1732. if ((HardwareStatus & UHCI_PORT_RESET) != 0) {
  1733. HlBusySpin(20 * 1000);
  1734. HardwareStatus &= ~UHCI_PORT_RESET;
  1735. UHCI_WRITE_REGISTER(Controller, Register, HardwareStatus);
  1736. }
  1737. }
  1738. return STATUS_SUCCESS;
  1739. }
  1740. RUNLEVEL
  1741. UhcipAcquireControllerLock (
  1742. PUHCI_CONTROLLER Controller
  1743. )
  1744. /*++
  1745. Routine Description:
  1746. This routine acquires the given UHCI controller's lock at dispatch level.
  1747. Arguments:
  1748. Controller - Supplies a pointer to the controller to lock.
  1749. Return Value:
  1750. Returns the previous run-level, which must be passed in when the controller
  1751. is unlocked.
  1752. --*/
  1753. {
  1754. RUNLEVEL OldRunLevel;
  1755. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  1756. KeAcquireSpinLock(&(Controller->Lock));
  1757. return OldRunLevel;
  1758. }
  1759. VOID
  1760. UhcipReleaseControllerLock (
  1761. PUHCI_CONTROLLER Controller,
  1762. RUNLEVEL OldRunLevel
  1763. )
  1764. /*++
  1765. Routine Description:
  1766. This routine releases the given UHCI controller's lock, and returns the
  1767. run-level to its previous value.
  1768. Arguments:
  1769. Controller - Supplies a pointer to the controller to unlock.
  1770. OldRunLevel - Supplies the original run level returned when the lock was
  1771. acquired.
  1772. Return Value:
  1773. None.
  1774. --*/
  1775. {
  1776. KeReleaseSpinLock(&(Controller->Lock));
  1777. KeLowerRunLevel(OldRunLevel);
  1778. return;
  1779. }
  1780. VOID
  1781. UhcipWaitForNextFrame (
  1782. PUHCI_CONTROLLER Controller
  1783. )
  1784. /*++
  1785. Routine Description:
  1786. This routine does not return until the UHCI hardware controller has
  1787. advanced at least one frame.
  1788. Arguments:
  1789. Controller - Supplies a pointer to the controller to wait for.
  1790. Return Value:
  1791. None.
  1792. --*/
  1793. {
  1794. ULONG CurrentFrame;
  1795. RUNLEVEL RunLevel;
  1796. RunLevel = KeGetRunLevel();
  1797. CurrentFrame = UHCI_READ_REGISTER(Controller, UhciRegisterFrameNumber);
  1798. while (UHCI_READ_REGISTER(Controller, UhciRegisterFrameNumber) ==
  1799. CurrentFrame) {
  1800. if (RunLevel < RunLevelDispatch) {
  1801. KeYield();
  1802. }
  1803. }
  1804. return;
  1805. }
  1806. VOID
  1807. UhcipProcessInterrupt (
  1808. PUHCI_CONTROLLER Controller,
  1809. ULONG PendingStatus
  1810. )
  1811. /*++
  1812. Routine Description:
  1813. This routine performs the work associated with receiving a UHCI interrupt.
  1814. This routine runs at dispatch level.
  1815. Arguments:
  1816. Controller - Supplies a pointer to the UHCI controller.
  1817. PendingStatus - Supplies the pending status bits to deal with.
  1818. Return Value:
  1819. None.
  1820. --*/
  1821. {
  1822. PLIST_ENTRY CurrentQueueEntry;
  1823. PLIST_ENTRY CurrentTransferEntry;
  1824. RUNLEVEL OldRunLevel;
  1825. PUHCI_TRANSFER_QUEUE Queue;
  1826. BOOL RemoveQueue;
  1827. PUHCI_TRANSFER Transfer;
  1828. //
  1829. // Lock the controller and loop until this routine has caught up with the
  1830. // interrupts.
  1831. //
  1832. OldRunLevel = UhcipAcquireControllerLock(Controller);
  1833. //
  1834. // TODO: Go through the isochronous transfers.
  1835. //
  1836. //
  1837. // Loop through every queue in the schedule.
  1838. //
  1839. CurrentQueueEntry = Controller->QueueListHead.Next;
  1840. while (CurrentQueueEntry != &(Controller->QueueListHead)) {
  1841. Queue = LIST_VALUE(CurrentQueueEntry,
  1842. UHCI_TRANSFER_QUEUE,
  1843. GlobalListEntry);
  1844. CurrentQueueEntry = CurrentQueueEntry->Next;
  1845. //
  1846. // Loop through every transfer in the queue.
  1847. //
  1848. RemoveQueue = FALSE;
  1849. CurrentTransferEntry = Queue->TransferListHead.Next;
  1850. while (CurrentTransferEntry != &(Queue->TransferListHead)) {
  1851. Transfer = LIST_VALUE(CurrentTransferEntry,
  1852. UHCI_TRANSFER,
  1853. QueueListEntry);
  1854. CurrentTransferEntry = CurrentTransferEntry->Next;
  1855. //
  1856. // Examine the tranfser, and determine whether or not it's
  1857. // failed.
  1858. //
  1859. RemoveQueue = UhcipProcessPotentiallyCompletedTransfer(Queue,
  1860. Transfer);
  1861. if ((RemoveQueue != FALSE) || (Transfer == Queue->LastTransfer)) {
  1862. break;
  1863. }
  1864. }
  1865. //
  1866. // If the queue isn't already slated to be removed, look to see
  1867. // if it is empty. Unless it is one of the sentinal queues, empty
  1868. // queues should be removed.
  1869. //
  1870. if ((RemoveQueue == FALSE) &&
  1871. ((Queue->HardwareQueueHead.ElementLink &
  1872. UHCI_QUEUE_HEAD_LINK_TERMINATE) != 0) &&
  1873. (Queue != Controller->ControlQueue) &&
  1874. (Queue != Controller->InterruptQueue)) {
  1875. RemoveQueue = TRUE;
  1876. }
  1877. //
  1878. // If necessary, remove the queue from the schedule and call the USB
  1879. // host to notify USB core that the transfer is done. This is safe to
  1880. // do at dispatch level because the USB core queues any real work.
  1881. //
  1882. if (RemoveQueue != FALSE) {
  1883. UhcipRemoveTransferQueue(Controller, Queue, FALSE);
  1884. UsbHostProcessCompletedTransfer(Queue->UsbTransfer);
  1885. }
  1886. }
  1887. //
  1888. // Release the controller lock.
  1889. //
  1890. UhcipReleaseControllerLock(Controller, OldRunLevel);
  1891. return;
  1892. }
  1893. VOID
  1894. UhcipFillOutTransferDescriptor (
  1895. PUHCI_CONTROLLER Controller,
  1896. PUHCI_ENDPOINT Endpoint,
  1897. PUHCI_TRANSFER_QUEUE Queue,
  1898. PUHCI_TRANSFER UhciTransfer,
  1899. PUSB_TRANSFER_INTERNAL Transfer,
  1900. ULONG Offset,
  1901. ULONG Length,
  1902. BOOL LastTransfer
  1903. )
  1904. /*++
  1905. Routine Description:
  1906. This routine fills out a UHCI transfer descriptor.
  1907. Arguments:
  1908. Controller - Supplies a pointer to the UHCI controller.
  1909. Endpoint - Supplies a pointer to the endpoint the transfer will go on.
  1910. Queue - Supplies an optional pointer to the transfer queue the transfer
  1911. is going on.
  1912. UhciTransfer - Supplies a pointer to UHCI's transfer descriptor information.
  1913. Transfer - Supplies a pointer to the core USB library transfer.
  1914. Offset - Supplies the offset from the public transfer physical address that
  1915. this transfer descriptor should be initialize to.
  1916. Length - Supplies the length of the transfer, in bytes.
  1917. LastTransfer - Supplies a boolean indicating if this transfer descriptor
  1918. represents the last transfer in a set. For control transfers, this is
  1919. the status phase where the in/out is reversed and the length had better
  1920. be zero.
  1921. Return Value:
  1922. None.
  1923. --*/
  1924. {
  1925. ULONG Control;
  1926. PUHCI_TRANSFER PreviousTransfer;
  1927. BOOL Setup;
  1928. ULONG Token;
  1929. Setup = FALSE;
  1930. //
  1931. // Set up the token field of the hardware transfer descriptor.
  1932. //
  1933. UhciTransfer->HardwareTransfer.BufferPointer =
  1934. Transfer->Public.BufferPhysicalAddress + Offset;
  1935. Token = (Length - 1) <<
  1936. UHCI_TRANSFER_DESCRIPTOR_TOKEN_MAX_LENGTH_SHIFT;
  1937. Token |= (Endpoint->EndpointNumber & USB_ENDPOINT_ADDRESS_MASK) <<
  1938. UHCI_TRANSFER_DESCRIPTOR_TOKEN_ENDPOINT_SHIFT;
  1939. Token |= Transfer->DeviceAddress <<
  1940. UHCI_TRANSFER_DESCRIPTOR_TOKEN_ADDRESS_SHIFT;
  1941. //
  1942. // The first packet in a control transfer is always a setup packet.
  1943. //
  1944. if ((Endpoint->TransferType == UsbTransferTypeControl) && (Offset == 0)) {
  1945. Token |= USB_PID_SETUP;
  1946. Endpoint->DataToggle = FALSE;
  1947. Setup = TRUE;
  1948. //
  1949. // Do it backwards if this is the status phase. Status phases always have
  1950. // a data toggle of 1.
  1951. //
  1952. } else if ((Endpoint->TransferType == UsbTransferTypeControl) &&
  1953. (LastTransfer != FALSE)) {
  1954. Endpoint->DataToggle = TRUE;
  1955. ASSERT((Length == 0) &&
  1956. (Endpoint->TransferType == UsbTransferTypeControl));
  1957. if (Transfer->Public.Direction == UsbTransferDirectionIn) {
  1958. Token |= USB_PID_OUT;
  1959. } else {
  1960. ASSERT(Transfer->Public.Direction == UsbTransferDirectionOut);
  1961. Token |= USB_PID_IN;
  1962. }
  1963. //
  1964. // Not setup and not status, fill this out like a normal descriptor.
  1965. //
  1966. } else {
  1967. if (Transfer->Public.Direction == UsbTransferDirectionIn) {
  1968. Token |= USB_PID_IN;
  1969. } else {
  1970. ASSERT(Transfer->Public.Direction == UsbTransferDirectionOut);
  1971. Token |= USB_PID_OUT;
  1972. }
  1973. }
  1974. ASSERT(UhciTransfer->HardwareTransfer.Token == 0);
  1975. UhciTransfer->HardwareTransfer.Token = Token;
  1976. //
  1977. // Set up the control/status field of the hardware transfer descriptor.
  1978. // Avoid setting the short packet detect bit if the caller specified not
  1979. // to allow short transfers.
  1980. //
  1981. Control = UHCI_TRANSFER_DESCRIPTOR_STATUS_ACTIVE;
  1982. if ((Setup == FALSE) &&
  1983. ((Transfer->Public.Flags &
  1984. USB_TRANSFER_FLAG_NO_SHORT_TRANSFERS) == 0)) {
  1985. Control |= UHCI_TRANSFER_DESCRIPTOR_STATUS_SHORT_PACKET;
  1986. }
  1987. ASSERT((Endpoint->Speed == UsbDeviceSpeedLow) ||
  1988. (Endpoint->Speed == UsbDeviceSpeedFull));
  1989. if ((Queue != NULL) && (Endpoint->Speed == UsbDeviceSpeedLow)) {
  1990. Control |= UHCI_TRANSFER_DESCRIPTOR_STATUS_LOW_SPEED;
  1991. }
  1992. //
  1993. // Mark isochronous transfers. For all other transfer types, set the error
  1994. // count to 3. Isochronous transfers do not get an error count because the
  1995. // active bit is always set to 0 by the hardware after execution,
  1996. // regardless of the result.
  1997. //
  1998. if (Transfer->Type == UsbTransferTypeIsochronous) {
  1999. Control |= UHCI_TRANSFER_DESCRIPTOR_STATUS_ISOCHRONOUS;
  2000. } else {
  2001. Control |= UHCI_TRANSFER_DESCRIPTOR_STATUS_3_ERRORS;
  2002. }
  2003. //
  2004. // Don't set the interrupt flag if 1) This is not the last descriptor or
  2005. // 2) The caller requested not to.
  2006. //
  2007. if ((LastTransfer != FALSE) &&
  2008. ((Transfer->Public.Flags &
  2009. USB_TRANSFER_FLAG_NO_INTERRUPT_ON_COMPLETION) == 0)) {
  2010. Control |= UHCI_TRANSFER_DESCRIPTOR_STATUS_INTERRUPT;
  2011. }
  2012. UhciTransfer->HardwareTransfer.Status = Control;
  2013. //
  2014. // Set up the link pointer of the transfer descriptor. With the exception
  2015. // of isochronous transfers (which will get patched up later) transfer
  2016. // descriptors are always put at the end of the queue.
  2017. //
  2018. UhciTransfer->HardwareTransfer.LinkPointer =
  2019. UHCI_TRANSFER_DESCRIPTOR_LINK_TERMINATE;
  2020. if (Transfer->Type == UsbTransferTypeIsochronous) {
  2021. //
  2022. // TODO: Implement support for isochronous transfers.
  2023. //
  2024. ASSERT(FALSE);
  2025. //
  2026. // If the transfer is not isochronous, set the data toggle bit.
  2027. //
  2028. } else {
  2029. if (Endpoint->DataToggle != FALSE) {
  2030. UhciTransfer->HardwareTransfer.Token |=
  2031. UHCI_TRANSFER_DESCRIPTOR_TOKEN_DATA_TOGGLE;
  2032. Endpoint->DataToggle = FALSE;
  2033. } else {
  2034. Endpoint->DataToggle = TRUE;
  2035. }
  2036. }
  2037. if ((UhciDebugFlags & UHCI_DEBUG_TRANSFERS) != 0) {
  2038. RtlDebugPrint("UHCI: Adding transfer (0x%08x) to endpoint (0x%08x): "
  2039. "Status: 0x%08x, Token 0x%08x.\n",
  2040. UhciTransfer,
  2041. Endpoint,
  2042. UhciTransfer->HardwareTransfer.Status,
  2043. UhciTransfer->HardwareTransfer.Token);
  2044. }
  2045. //
  2046. // If this is not an isochronous transfer, fix up the hardware links so that
  2047. // this transfer goes at the back of the list.
  2048. //
  2049. if (Transfer->Type != UsbTransferTypeIsochronous) {
  2050. //
  2051. // If this is the first element in the list, set the queue's vertical
  2052. // link pointer directly.
  2053. //
  2054. if (UhciTransfer->QueueListEntry.Previous ==
  2055. &(Queue->TransferListHead)) {
  2056. Queue->HardwareQueueHead.ElementLink =
  2057. (ULONG)UhciTransfer->PhysicalAddress;
  2058. //
  2059. // If the queue is not empty, use the previous transfer descriptor in
  2060. // the software list to insert it into the hardware list.
  2061. //
  2062. } else {
  2063. PreviousTransfer = LIST_VALUE(UhciTransfer->QueueListEntry.Previous,
  2064. UHCI_TRANSFER,
  2065. QueueListEntry);
  2066. ASSERT((PreviousTransfer->HardwareTransfer.LinkPointer &
  2067. UHCI_QUEUE_HEAD_LINK_TERMINATE) != 0);
  2068. PreviousTransfer->HardwareTransfer.LinkPointer =
  2069. (ULONG)UhciTransfer->PhysicalAddress;
  2070. }
  2071. }
  2072. UhcipFlushCacheRegion(&(UhciTransfer->HardwareTransfer),
  2073. sizeof(UHCI_TRANSFER_DESCRIPTOR));
  2074. UhcipFlushCacheRegion(&(Queue->HardwareQueueHead), sizeof(UHCI_QUEUE_HEAD));
  2075. return;
  2076. }
  2077. BOOL
  2078. UhcipProcessPotentiallyCompletedTransfer (
  2079. PUHCI_TRANSFER_QUEUE Queue,
  2080. PUHCI_TRANSFER Transfer
  2081. )
  2082. /*++
  2083. Routine Description:
  2084. This routine processes a transfer descriptor, adjusting the USB transfer if
  2085. the transfer descriptor errored out.
  2086. Arguments:
  2087. Queue - Supplies a pointer to the transfer queue this transfer is operating
  2088. under.
  2089. Transfer - Supplies a pointer to the transfer to evaluate.
  2090. Return Value:
  2091. TRUE if the queue should be removed from the list because the transfer has
  2092. failed.
  2093. FALSE if the queue should not be removed from the list.
  2094. --*/
  2095. {
  2096. ULONG CrcOrTimeoutError;
  2097. ULONG DataBufferError;
  2098. ULONG ElementLinkPhysicalAddress;
  2099. ULONG HardwareStatus;
  2100. ULONG LengthTransferred;
  2101. ULONG MaxLength;
  2102. BOOL NewToggle;
  2103. PUHCI_TRANSFER NextTransfer;
  2104. BOOL RemoveQueue;
  2105. PUSB_TRANSFER UsbTransfer;
  2106. RemoveQueue = FALSE;
  2107. //
  2108. // If the transfer has a zero token, then it's already been dealt with, so
  2109. // stop looking.
  2110. //
  2111. if (Transfer->HardwareTransfer.Token == 0) {
  2112. goto ProcessPotentiallyCompletedTransferEnd;
  2113. }
  2114. HardwareStatus = Transfer->HardwareTransfer.Status;
  2115. if ((HardwareStatus &
  2116. UHCI_TRANSFER_DESCRIPTOR_STATUS_ACTIVE) == 0) {
  2117. if ((UhciDebugFlags & UHCI_DEBUG_TRANSFERS) != 0) {
  2118. RtlDebugPrint("UHCI: Transfer (0x%08x) completed with status "
  2119. "0x%08x, token 0x%08x\n",
  2120. Transfer,
  2121. HardwareStatus,
  2122. Transfer->HardwareTransfer.Token);
  2123. }
  2124. UsbTransfer = &(Queue->UsbTransfer->Public);
  2125. LengthTransferred =
  2126. ((HardwareStatus + 1) &
  2127. UHCI_TRANSFER_DESCRIPTOR_STATUS_ACTUAL_LENGTH_MASK);
  2128. UsbTransfer->LengthTransferred += LengthTransferred;
  2129. //
  2130. // If error bits were set, it's curtains for this transfer. Figure out
  2131. // exactly what went wrong. A halted error is first in line even if
  2132. // another bit (e.g. Babble) is set, because the driver may want to
  2133. // clear the halted state.
  2134. //
  2135. if ((HardwareStatus &
  2136. UHCI_TRANSFER_DESCRIPTOR_STATUS_ERROR_MASK) != 0) {
  2137. RemoveQueue = TRUE;
  2138. UsbTransfer->Status = STATUS_DEVICE_IO_ERROR;
  2139. DataBufferError = UHCI_TRANSFER_DESCRIPTOR_STATUS_DATA_BUFFER_ERROR;
  2140. CrcOrTimeoutError = UHCI_TRANSFER_DESCRIPTOR_STATUS_CRC_OR_TIMEOUT;
  2141. if ((HardwareStatus & DataBufferError) != 0) {
  2142. UsbTransfer->Error = UsbErrorTransferDataBuffer;
  2143. } else if ((HardwareStatus &
  2144. UHCI_TRANSFER_DESCRIPTOR_STATUS_BABBLE) != 0) {
  2145. UsbTransfer->Error = UsbErrorTransferBabbleDetected;
  2146. } else if ((HardwareStatus &
  2147. UHCI_TRANSFER_DESCRIPTOR_STATUS_NAK) != 0) {
  2148. UsbTransfer->Error = UsbErrorTransferNakReceived;
  2149. } else if ((HardwareStatus & CrcOrTimeoutError) != 0) {
  2150. UsbTransfer->Error = UsbErrorTransferCrcOrTimeoutError;
  2151. } else if ((HardwareStatus &
  2152. UHCI_TRANSFER_DESCRIPTOR_STATUS_STALLED) != 0) {
  2153. UsbTransfer->Error = UsbErrorTransferStalled;
  2154. }
  2155. //
  2156. // If the transfer was not the last one, fix up the data toggles.
  2157. // A failed transfer does not cause a toggle, so the next queue
  2158. // should have the same toggle as this failed one.
  2159. //
  2160. if (Transfer->QueueListEntry.Next != &(Queue->TransferListHead)) {
  2161. NewToggle = FALSE;
  2162. if ((Transfer->HardwareTransfer.Token &
  2163. UHCI_TRANSFER_DESCRIPTOR_TOKEN_DATA_TOGGLE) != 0) {
  2164. NewToggle = TRUE;
  2165. }
  2166. UhcipFixDataToggles(Queue, NewToggle);
  2167. }
  2168. } else {
  2169. //
  2170. // Check to see if it was a short IN transfer.
  2171. //
  2172. MaxLength = (Transfer->HardwareTransfer.Token >>
  2173. UHCI_TRANSFER_DESCRIPTOR_TOKEN_MAX_LENGTH_SHIFT) + 1;
  2174. if ((LengthTransferred != MaxLength) &&
  2175. (UsbTransfer->Direction == UsbTransferDirectionIn) &&
  2176. (Transfer->QueueListEntry.Next !=
  2177. &(Queue->TransferListHead))) {
  2178. //
  2179. // For a control transfer, move the queue pointer to the last
  2180. // transfer. Then the queue will complete normally.
  2181. //
  2182. ElementLinkPhysicalAddress =
  2183. Queue->HardwareQueueHead.ElementLink &
  2184. UHCI_QUEUE_HEAD_LINK_ADDRESS_MASK;
  2185. if ((Queue->UsbTransfer->Type == UsbTransferTypeControl) &&
  2186. (ElementLinkPhysicalAddress == Transfer->PhysicalAddress)) {
  2187. ASSERT(Queue->LinkToLastTransfer != 0);
  2188. Queue->HardwareQueueHead.ElementLink =
  2189. Queue->LinkToLastTransfer;
  2190. UhcipFlushCacheRegion(&(Queue->HardwareQueueHead),
  2191. sizeof(UHCI_QUEUE_HEAD));
  2192. } else {
  2193. RemoveQueue = TRUE;
  2194. if ((UsbTransfer->Flags &
  2195. USB_TRANSFER_FLAG_NO_SHORT_TRANSFERS) != 0) {
  2196. UsbTransfer->Status = STATUS_DATA_LENGTH_MISMATCH;
  2197. UsbTransfer->Error = UsbErrorShortPacket;
  2198. }
  2199. //
  2200. // If the short packet was not the last transfer descriptor
  2201. // then the upcoming data toggles need to be fixed up. The
  2202. // packet was short but successful, so the next queue
  2203. // should have the opposite toggle of this one.
  2204. //
  2205. if (Transfer->QueueListEntry.Next !=
  2206. &(Queue->TransferListHead)) {
  2207. NewToggle = FALSE;
  2208. if ((Transfer->HardwareTransfer.Token &
  2209. UHCI_TRANSFER_DESCRIPTOR_TOKEN_DATA_TOGGLE) == 0) {
  2210. NewToggle = TRUE;
  2211. }
  2212. UhcipFixDataToggles(Queue, NewToggle);
  2213. }
  2214. }
  2215. }
  2216. }
  2217. //
  2218. // Clear out the token to indicate this packet has been dealt with.
  2219. //
  2220. Transfer->HardwareTransfer.Token = 0;
  2221. //
  2222. // If this is the last transfer, then signal that processing on this
  2223. // queue is complete.
  2224. //
  2225. if (Transfer->QueueListEntry.Next == &(Queue->TransferListHead)) {
  2226. RemoveQueue = TRUE;
  2227. } else {
  2228. NextTransfer = LIST_VALUE(Transfer->QueueListEntry.Next,
  2229. UHCI_TRANSFER,
  2230. QueueListEntry);
  2231. if (NextTransfer->HardwareTransfer.Token == 0) {
  2232. RemoveQueue = TRUE;
  2233. }
  2234. }
  2235. }
  2236. ProcessPotentiallyCompletedTransferEnd:
  2237. return RemoveQueue;
  2238. }
  2239. VOID
  2240. UhcipRemoveTransferQueue (
  2241. PUHCI_CONTROLLER Controller,
  2242. PUHCI_TRANSFER_QUEUE Queue,
  2243. BOOL Cancel
  2244. )
  2245. /*++
  2246. Routine Description:
  2247. This routine removes a transfer queue from the schedule. This routine
  2248. assumes that the controller lock is already held.
  2249. Arguments:
  2250. Controller - Supplies a pointer to the controller being operated on.
  2251. Queue - Supplies a pointer to the inserted queue to remove from the
  2252. schedule.
  2253. Cancel - Supplies a boolean indicating if this transfer is being canceled.
  2254. If it is, data toggles for subsequent queues may need to be fixed up.
  2255. Return Value:
  2256. None.
  2257. --*/
  2258. {
  2259. PLIST_ENTRY CurrentEntry;
  2260. PUHCI_ENDPOINT Endpoint;
  2261. BOOL NewToggle;
  2262. ULONG NextLink;
  2263. PUHCI_TRANSFER_QUEUE NextQueue;
  2264. PUHCI_ENDPOINT PreviousEndpoint;
  2265. PUHCI_TRANSFER_QUEUE PreviousQueue;
  2266. PUHCI_TRANSFER_QUEUE QueueToFix;
  2267. PUHCI_TRANSFER Transfer;
  2268. Endpoint = Queue->Endpoint;
  2269. ASSERT(Endpoint != NULL);
  2270. PreviousQueue = LIST_VALUE(Queue->GlobalListEntry.Previous,
  2271. UHCI_TRANSFER_QUEUE,
  2272. GlobalListEntry);
  2273. PreviousEndpoint = PreviousQueue->Endpoint;
  2274. //
  2275. // Figure out what previous queues pointing at this one should point at
  2276. // instead. They should point at the next queue in this endpoint if there
  2277. // is one, or whatever this queue's link pointer is pointing at if not.
  2278. //
  2279. if (Queue->EndpointListEntry.Next != &(Endpoint->QueueListHead)) {
  2280. NextQueue = LIST_VALUE(Queue->EndpointListEntry.Next,
  2281. UHCI_TRANSFER_QUEUE,
  2282. EndpointListEntry);
  2283. NextLink = (ULONG)(NextQueue->PhysicalAddress) |
  2284. UHCI_QUEUE_HEAD_LINK_QUEUE_HEAD;
  2285. } else {
  2286. NextLink = Queue->HardwareQueueHead.LinkPointer;
  2287. }
  2288. //
  2289. // If this is the first entry in the endpoint, then potentially many queue
  2290. // heads point at it and need to be fixed up.
  2291. //
  2292. if (Endpoint->QueueListHead.Next == &(Queue->EndpointListEntry)) {
  2293. //
  2294. // If there's a previous endpoint, then for each queue in that endpoint
  2295. // point to the next queue in this endpoint.
  2296. //
  2297. if (PreviousEndpoint != NULL) {
  2298. CurrentEntry = PreviousEndpoint->QueueListHead.Next;
  2299. while (CurrentEntry != &(PreviousEndpoint->QueueListHead)) {
  2300. QueueToFix = LIST_VALUE(CurrentEntry,
  2301. UHCI_TRANSFER_QUEUE,
  2302. EndpointListEntry);
  2303. //
  2304. // The queue should already point at this queue. Fix it up to
  2305. // point beyond.
  2306. //
  2307. ASSERT(QueueToFix->HardwareQueueHead.LinkPointer ==
  2308. ((ULONG)(Queue->PhysicalAddress) |
  2309. UHCI_QUEUE_HEAD_LINK_QUEUE_HEAD));
  2310. QueueToFix->HardwareQueueHead.LinkPointer = NextLink;
  2311. UhcipFlushCacheRegion(&(QueueToFix->HardwareQueueHead),
  2312. sizeof(UHCI_QUEUE_HEAD));
  2313. CurrentEntry = CurrentEntry->Next;
  2314. }
  2315. //
  2316. // There is no previous endpoint, so the previous queue is a sentinal
  2317. // queue. Just move its link.
  2318. //
  2319. } else {
  2320. ASSERT(LIST_EMPTY(&(PreviousQueue->TransferListHead)) != FALSE);
  2321. ASSERT(PreviousQueue->HardwareQueueHead.LinkPointer ==
  2322. ((ULONG)(Queue->PhysicalAddress) |
  2323. UHCI_QUEUE_HEAD_LINK_QUEUE_HEAD));
  2324. PreviousQueue->HardwareQueueHead.LinkPointer = NextLink;
  2325. }
  2326. //
  2327. // This is not the first queue in the endpoint, so only the previous queue
  2328. // points to it.
  2329. //
  2330. } else {
  2331. QueueToFix = LIST_VALUE(Queue->EndpointListEntry.Previous,
  2332. UHCI_TRANSFER_QUEUE,
  2333. EndpointListEntry);
  2334. ASSERT(QueueToFix->LastTransfer->HardwareTransfer.LinkPointer ==
  2335. ((ULONG)(Queue->PhysicalAddress) |
  2336. UHCI_TRANSFER_DESCRIPTOR_LINK_QUEUE_HEAD));
  2337. QueueToFix->LastTransfer->HardwareTransfer.LinkPointer = NextLink;
  2338. }
  2339. //
  2340. // Wait for the next frame to ensure that the controller isn't sitting on
  2341. // this just-removed queue head.
  2342. //
  2343. UhcipWaitForNextFrame(Controller);
  2344. //
  2345. // The queue and all transfers are now no longer visible to the hardware.
  2346. // Clear the token fields of all transfers.
  2347. //
  2348. CurrentEntry = Queue->TransferListHead.Next;
  2349. while (CurrentEntry != &(Queue->TransferListHead)) {
  2350. Transfer = LIST_VALUE(CurrentEntry, UHCI_TRANSFER, QueueListEntry);
  2351. CurrentEntry = CurrentEntry->Next;
  2352. //
  2353. // If the queue was cancelled (meaning it was ripped out from under the
  2354. // controller) and this transfer is still active, then fix up the
  2355. // data toggles for subsequent queues. Because the transfer was never
  2356. // completed, the next queue should have the same toggle bit as this
  2357. // one.
  2358. //
  2359. if ((Cancel != FALSE) &&
  2360. ((Transfer->HardwareTransfer.Status &
  2361. UHCI_TRANSFER_DESCRIPTOR_STATUS_ACTIVE) != 0)) {
  2362. NewToggle = FALSE;
  2363. if ((Transfer->HardwareTransfer.Token &
  2364. UHCI_TRANSFER_DESCRIPTOR_TOKEN_DATA_TOGGLE) != 0) {
  2365. NewToggle = TRUE;
  2366. }
  2367. UhcipFixDataToggles(Queue, NewToggle);
  2368. //
  2369. // Prevent this fixup from happening multiple times.
  2370. //
  2371. Cancel = FALSE;
  2372. }
  2373. Transfer->HardwareTransfer.Token = 0;
  2374. }
  2375. //
  2376. // Finally, pull the queue out of the software lists.
  2377. //
  2378. LIST_REMOVE(&(Queue->GlobalListEntry));
  2379. Queue->GlobalListEntry.Next = NULL;
  2380. LIST_REMOVE(&(Queue->EndpointListEntry));
  2381. Queue->EndpointListEntry.Next = NULL;
  2382. return;
  2383. }
  2384. VOID
  2385. UhcipPortStatusDpc (
  2386. PDPC Dpc
  2387. )
  2388. /*++
  2389. Routine Description:
  2390. This routine implements the UHCI DPC that is fired when the port status
  2391. timer expires.
  2392. Arguments:
  2393. Dpc - Supplies a pointer to the DPC that is running.
  2394. Return Value:
  2395. None.
  2396. --*/
  2397. {
  2398. BOOL Changed;
  2399. PUHCI_CONTROLLER Controller;
  2400. ASSERT(KeGetRunLevel() == RunLevelDispatch);
  2401. //
  2402. // Test to see if the UHCI ports have changed. If they have, then call USB
  2403. // core to notify it of the change.
  2404. //
  2405. Controller = (PUHCI_CONTROLLER)Dpc->UserData;
  2406. Changed = UhcipHasPortStatusChanged(Controller);
  2407. if (Changed != FALSE) {
  2408. UsbHostNotifyPortChange(Controller->UsbCoreHandle);
  2409. }
  2410. return;
  2411. }
  2412. BOOL
  2413. UhcipHasPortStatusChanged (
  2414. PUHCI_CONTROLLER Controller
  2415. )
  2416. /*++
  2417. Routine Description:
  2418. This routine determines if the port status and control registers have
  2419. changed for the root hub of the USB host controller.
  2420. Arguments:
  2421. Controller - Supplies a pointer to the UHCI host controller whose port
  2422. status needs to be queried for changes.
  2423. Return Value:
  2424. Returns TRUE if the port status and control registers have changed, or
  2425. FALSE otherwise.
  2426. --*/
  2427. {
  2428. BOOL Changed;
  2429. USHORT HardwareStatus;
  2430. ULONG PortIndex;
  2431. UHCI_REGISTER Register;
  2432. ASSERT(Controller != NULL);
  2433. //
  2434. // Loop through each UHCI host controller port to see if it's connection
  2435. // status has changed.
  2436. //
  2437. Changed = FALSE;
  2438. for (PortIndex = 0; PortIndex < UHCI_PORT_COUNT; PortIndex += 1) {
  2439. //
  2440. // Read the hardware register.
  2441. //
  2442. if (PortIndex == 0) {
  2443. Register = UhciRegisterPort1StatusControl;
  2444. } else {
  2445. ASSERT(PortIndex == 1);
  2446. Register = UhciRegisterPort2StatusControl;
  2447. }
  2448. //
  2449. // If any port's connection status has changed, exit reporting a
  2450. // change.
  2451. //
  2452. HardwareStatus = UHCI_READ_REGISTER(Controller, Register);
  2453. if ((HardwareStatus & UHCI_PORT_CONNECT_STATUS_CHANGED) != 0) {
  2454. Changed = TRUE;
  2455. if ((UhciDebugFlags & UHCI_DEBUG_PORTS) != 0) {
  2456. RtlDebugPrint("UHCI: Controller 0x%x, Port %d changed. "
  2457. "Status 0x%x\n.",
  2458. Controller,
  2459. PortIndex,
  2460. HardwareStatus);
  2461. }
  2462. break;
  2463. }
  2464. }
  2465. return Changed;
  2466. }
  2467. VOID
  2468. UhcipFlushCacheRegion (
  2469. PVOID VirtualAddress,
  2470. ULONG Size
  2471. )
  2472. /*++
  2473. Routine Description:
  2474. This routine flushes the given region of memory for visibility to the
  2475. hardware.
  2476. Arguments:
  2477. VirtualAddress - Supplies the virtual address of the region to flush.
  2478. Size - Supplies the number of bytes to flush.
  2479. Return Value:
  2480. None.
  2481. --*/
  2482. {
  2483. //
  2484. // UHCI currently only runs on x86 architectures, and x86 architectures
  2485. // are cache coherent, so no action is needed here. Fill this in if UHCI
  2486. // is ever implemented on an architecture with a weaker memory model.
  2487. //
  2488. return;
  2489. }
  2490. VOID
  2491. UhcipFixDataToggles (
  2492. PUHCI_TRANSFER_QUEUE RemovingQueue,
  2493. BOOL Toggle
  2494. )
  2495. /*++
  2496. Routine Description:
  2497. This routine fixes up the data toggle bits for every queue after the given
  2498. one. It is called when a packet comes in short, errors out, or is cancelled.
  2499. Arguments:
  2500. RemovingQueue - Supplies a pointer to the queue that is disappearing.
  2501. Every queue after this one in the endpoint will be fixed up.
  2502. Toggle - Supplies the toggle value that the first transfer in the next
  2503. queue should have.
  2504. Return Value:
  2505. None.
  2506. --*/
  2507. {
  2508. PLIST_ENTRY CurrentEntry;
  2509. PUHCI_ENDPOINT Endpoint;
  2510. ULONG NewToken;
  2511. PUHCI_TRANSFER_QUEUE Queue;
  2512. PUHCI_TRANSFER Transfer;
  2513. PLIST_ENTRY TransferEntry;
  2514. Endpoint = RemovingQueue->Endpoint;
  2515. if ((Endpoint->TransferType == UsbTransferTypeControl) ||
  2516. (Endpoint->TransferType == UsbTransferTypeIsochronous)) {
  2517. return;
  2518. }
  2519. if ((UhciDebugFlags & UHCI_DEBUG_TRANSFERS) != 0) {
  2520. RtlDebugPrint("UHCI: Fixing data toggles for Endpoint 0x%x 0x%x, "
  2521. "RemovingQueue 0x%x, Toggle 0x%x\n",
  2522. Endpoint->EndpointNumber,
  2523. Endpoint,
  2524. RemovingQueue,
  2525. Toggle);
  2526. }
  2527. //
  2528. // Loop through every remaining queue in the endpoint. The USB spec says
  2529. // devices should simply ignore packets that come in with the wrong data
  2530. // toggle, so it's okay to fix these up live as long as they're fixed up
  2531. // in order.
  2532. //
  2533. CurrentEntry = RemovingQueue->EndpointListEntry.Next;
  2534. while (CurrentEntry != &(Endpoint->QueueListHead)) {
  2535. Queue = LIST_VALUE(CurrentEntry,
  2536. UHCI_TRANSFER_QUEUE,
  2537. EndpointListEntry);
  2538. CurrentEntry = CurrentEntry->Next;
  2539. //
  2540. // Loop through every transfer in the queue.
  2541. //
  2542. TransferEntry = Queue->TransferListHead.Next;
  2543. while (TransferEntry != &(Queue->TransferListHead)) {
  2544. Transfer = LIST_VALUE(TransferEntry, UHCI_TRANSFER, QueueListEntry);
  2545. TransferEntry = TransferEntry->Next;
  2546. NewToken = Transfer->HardwareTransfer.Token &
  2547. (~UHCI_TRANSFER_DESCRIPTOR_TOKEN_DATA_TOGGLE);
  2548. ASSERT(NewToken != 0);
  2549. if (Toggle != FALSE) {
  2550. NewToken |= UHCI_TRANSFER_DESCRIPTOR_TOKEN_DATA_TOGGLE;
  2551. Toggle = FALSE;
  2552. } else {
  2553. Toggle = TRUE;
  2554. }
  2555. if (NewToken != Transfer->HardwareTransfer.Token) {
  2556. Transfer->HardwareTransfer.Token = NewToken;
  2557. RtlMemoryBarrier();
  2558. UhcipFlushCacheRegion(&(Transfer->HardwareTransfer),
  2559. sizeof(UHCI_TRANSFER));
  2560. }
  2561. }
  2562. }
  2563. Endpoint->DataToggle = Toggle;
  2564. return;
  2565. }