dwhci.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. dwhci.c
  5. Abstract:
  6. This module implements support for the DesignWare High-Speed USB 2.0
  7. On-The-Go (HS OTG) host controller.
  8. Author:
  9. Chris Stevens 28-Mar-2014
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include <minoca/usb/usbhost.h>
  18. #include "dwhci.h"
  19. //
  20. // --------------------------------------------------------------------- Macros
  21. //
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. /*++
  29. Structure Description:
  30. This structure stores context about a DWHCI Host Controller.
  31. Members:
  32. InterruptLine - Stores the interrupt line that this controller's interrupt
  33. comes in on.
  34. InterruptVector - Stores the interrupt vector that this controller's
  35. interrupt comes in on.
  36. InterruptResourcesFound - Stores a boolean indicating whether or not the
  37. interrupt line and interrupt vector fields are valid.
  38. InterruptHandle - Stores a pointer to the handle received when the
  39. interrupt was connected.
  40. Controller - Stores a pointer to the OTG controller.
  41. RegisterBasePhysical - Stores the physical memory address where the DWHCI
  42. registers are located.
  43. RegisterBase - Stores a pointer to the virtual address where the DWHCI
  44. registers are located.
  45. ChannelCount - Stores the number of channels for this host controller.
  46. Speed - Stores the speed of the DWHCI host controller.
  47. MaxTransferSize - Stores the maximum tranfer size for the DWHCI host
  48. controller.
  49. MaxPacketCount - Store the maximum packet count for the DWHCI host
  50. controller.
  51. Revision - Stores the revision of the DWHCI host controller.
  52. --*/
  53. typedef struct _DWHCI_CONTROLLER_CONTEXT {
  54. ULONGLONG InterruptLine;
  55. ULONGLONG InterruptVector;
  56. BOOL InterruptResourcesFound;
  57. HANDLE InterruptHandle;
  58. PDWHCI_CONTROLLER Controller;
  59. PHYSICAL_ADDRESS RegisterBasePhysical;
  60. PVOID RegisterBase;
  61. ULONG ChannelCount;
  62. USB_DEVICE_SPEED Speed;
  63. ULONG MaxTransferSize;
  64. ULONG MaxPacketCount;
  65. ULONG Revision;
  66. } DWHCI_CONTROLLER_CONTEXT, *PDWHCI_CONTROLLER_CONTEXT;
  67. //
  68. // ----------------------------------------------- Internal Function Prototypes
  69. //
  70. KSTATUS
  71. DwhciAddDevice (
  72. PVOID Driver,
  73. PSTR DeviceId,
  74. PSTR ClassId,
  75. PSTR CompatibleIds,
  76. PVOID DeviceToken
  77. );
  78. VOID
  79. DwhciDispatchStateChange (
  80. PIRP Irp,
  81. PVOID DeviceContext,
  82. PVOID IrpContext
  83. );
  84. VOID
  85. DwhciDispatchOpen (
  86. PIRP Irp,
  87. PVOID DeviceContext,
  88. PVOID IrpContext
  89. );
  90. VOID
  91. DwhciDispatchClose (
  92. PIRP Irp,
  93. PVOID DeviceContext,
  94. PVOID IrpContext
  95. );
  96. VOID
  97. DwhciDispatchIo (
  98. PIRP Irp,
  99. PVOID DeviceContext,
  100. PVOID IrpContext
  101. );
  102. VOID
  103. DwhciDispatchSystemControl (
  104. PIRP Irp,
  105. PVOID DeviceContext,
  106. PVOID IrpContext
  107. );
  108. KSTATUS
  109. DwhcipProcessResourceRequirements (
  110. PIRP Irp,
  111. PDWHCI_CONTROLLER_CONTEXT Device
  112. );
  113. KSTATUS
  114. DwhcipStartDevice (
  115. PIRP Irp,
  116. PDWHCI_CONTROLLER_CONTEXT Device
  117. );
  118. VOID
  119. DwhcipEnumerateChildren (
  120. PIRP Irp,
  121. PDWHCI_CONTROLLER_CONTEXT Device
  122. );
  123. KSTATUS
  124. DwhcipGatherControllerParameters (
  125. PDWHCI_CONTROLLER_CONTEXT ControllerContext,
  126. PRESOURCE_ALLOCATION ControllerBase
  127. );
  128. //
  129. // -------------------------------------------------------------------- Globals
  130. //
  131. PDRIVER DwhciDriver = NULL;
  132. //
  133. // ------------------------------------------------------------------ Functions
  134. //
  135. KSTATUS
  136. DriverEntry (
  137. PDRIVER Driver
  138. )
  139. /*++
  140. Routine Description:
  141. This routine is the entry point for the DWHCI driver. It registers its
  142. other dispatch functions, and performs driver-wide initialization.
  143. Arguments:
  144. Driver - Supplies a pointer to the driver object.
  145. Return Value:
  146. STATUS_SUCCESS on success.
  147. Failure code on error.
  148. --*/
  149. {
  150. DRIVER_FUNCTION_TABLE FunctionTable;
  151. KSTATUS Status;
  152. DwhciDriver = Driver;
  153. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  154. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  155. FunctionTable.AddDevice = DwhciAddDevice;
  156. FunctionTable.DispatchStateChange = DwhciDispatchStateChange;
  157. FunctionTable.DispatchOpen = DwhciDispatchOpen;
  158. FunctionTable.DispatchClose = DwhciDispatchClose;
  159. FunctionTable.DispatchIo = DwhciDispatchIo;
  160. FunctionTable.DispatchSystemControl = DwhciDispatchSystemControl;
  161. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  162. return Status;
  163. }
  164. //
  165. // --------------------------------------------------------- Internal Functions
  166. //
  167. KSTATUS
  168. DwhciAddDevice (
  169. PVOID Driver,
  170. PSTR DeviceId,
  171. PSTR ClassId,
  172. PSTR CompatibleIds,
  173. PVOID DeviceToken
  174. )
  175. /*++
  176. Routine Description:
  177. This routine is called when a device is detected for which the DWHCI driver
  178. acts as the function driver. The driver will attach itself to the stack.
  179. Arguments:
  180. Driver - Supplies a pointer to the driver being called.
  181. DeviceId - Supplies a pointer to a string with the device ID.
  182. ClassId - Supplies a pointer to a string containing the device's class ID.
  183. CompatibleIds - Supplies a pointer to a string containing device IDs
  184. that would be compatible with this device.
  185. DeviceToken - Supplies an opaque token that the driver can use to identify
  186. the device in the system. This token should be used when attaching to
  187. the stack.
  188. Return Value:
  189. STATUS_SUCCESS on success.
  190. Failure code if the driver was unsuccessful in attaching itself.
  191. --*/
  192. {
  193. PDWHCI_CONTROLLER_CONTEXT NewDevice;
  194. KSTATUS Status;
  195. //
  196. // Create the device context and attach to the device.
  197. //
  198. NewDevice = MmAllocateNonPagedPool(sizeof(DWHCI_CONTROLLER_CONTEXT),
  199. DWHCI_ALLOCATION_TAG);
  200. if (NewDevice == NULL) {
  201. return STATUS_INSUFFICIENT_RESOURCES;
  202. }
  203. RtlZeroMemory(NewDevice, sizeof(DWHCI_CONTROLLER_CONTEXT));
  204. NewDevice->InterruptHandle = INVALID_HANDLE;
  205. Status = IoAttachDriverToDevice(Driver, DeviceToken, NewDevice);
  206. return Status;
  207. }
  208. VOID
  209. DwhciDispatchStateChange (
  210. PIRP Irp,
  211. PVOID DeviceContext,
  212. PVOID IrpContext
  213. )
  214. /*++
  215. Routine Description:
  216. This routine handles State Change IRPs.
  217. Arguments:
  218. Irp - Supplies a pointer to the I/O request packet.
  219. DeviceContext - Supplies the context pointer supplied by the driver when it
  220. attached itself to the driver stack. Presumably this pointer contains
  221. driver-specific device context.
  222. IrpContext - Supplies the context pointer supplied by the driver when
  223. the IRP was created.
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. PDWHCI_CONTROLLER_CONTEXT Device;
  229. KSTATUS Status;
  230. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  231. Device = (PDWHCI_CONTROLLER_CONTEXT)DeviceContext;
  232. //
  233. // If there is no controller context, then DWHCI is acting as the bus
  234. // driver for the root hub. Simply complete standard IRPs.
  235. //
  236. if (Device == NULL) {
  237. switch (Irp->MinorCode) {
  238. case IrpMinorQueryResources:
  239. case IrpMinorStartDevice:
  240. case IrpMinorQueryChildren:
  241. IoCompleteIrp(DwhciDriver, Irp, STATUS_SUCCESS);
  242. break;
  243. default:
  244. break;
  245. }
  246. return;
  247. }
  248. switch (Irp->MinorCode) {
  249. case IrpMinorQueryResources:
  250. //
  251. // On the way up, filter the resource requirements to add interrupt
  252. // vectors to any lines.
  253. //
  254. if (Irp->Direction == IrpUp) {
  255. Status = DwhcipProcessResourceRequirements(Irp, Device);
  256. if (!KSUCCESS(Status)) {
  257. IoCompleteIrp(DwhciDriver, Irp, Status);
  258. }
  259. }
  260. break;
  261. case IrpMinorStartDevice:
  262. //
  263. // Attempt to fire the thing up if the bus has already started it.
  264. //
  265. if (Irp->Direction == IrpUp) {
  266. Status = DwhcipStartDevice(Irp, Device);
  267. if (!KSUCCESS(Status)) {
  268. IoCompleteIrp(DwhciDriver, Irp, Status);
  269. }
  270. }
  271. break;
  272. case IrpMinorQueryChildren:
  273. if (Irp->Direction == IrpUp) {
  274. DwhcipEnumerateChildren(Irp, Device);
  275. }
  276. break;
  277. case IrpMinorRemoveDevice:
  278. ASSERT(FALSE);
  279. break;
  280. //
  281. // For all other IRPs, do nothing.
  282. //
  283. default:
  284. break;
  285. }
  286. return;
  287. }
  288. VOID
  289. DwhciDispatchOpen (
  290. PIRP Irp,
  291. PVOID DeviceContext,
  292. PVOID IrpContext
  293. )
  294. /*++
  295. Routine Description:
  296. This routine handles Open IRPs.
  297. Arguments:
  298. Irp - Supplies a pointer to the I/O request packet.
  299. DeviceContext - Supplies the context pointer supplied by the driver when it
  300. attached itself to the driver stack. Presumably this pointer contains
  301. driver-specific device context.
  302. IrpContext - Supplies the context pointer supplied by the driver when
  303. the IRP was created.
  304. Return Value:
  305. None.
  306. --*/
  307. {
  308. return;
  309. }
  310. VOID
  311. DwhciDispatchClose (
  312. PIRP Irp,
  313. PVOID DeviceContext,
  314. PVOID IrpContext
  315. )
  316. /*++
  317. Routine Description:
  318. This routine handles Close IRPs.
  319. Arguments:
  320. Irp - Supplies a pointer to the I/O request packet.
  321. DeviceContext - Supplies the context pointer supplied by the driver when it
  322. attached itself to the driver stack. Presumably this pointer contains
  323. driver-specific device context.
  324. IrpContext - Supplies the context pointer supplied by the driver when
  325. the IRP was created.
  326. Return Value:
  327. None.
  328. --*/
  329. {
  330. return;
  331. }
  332. VOID
  333. DwhciDispatchIo (
  334. PIRP Irp,
  335. PVOID DeviceContext,
  336. PVOID IrpContext
  337. )
  338. /*++
  339. Routine Description:
  340. This routine handles I/O IRPs.
  341. Arguments:
  342. Irp - Supplies a pointer to the I/O request packet.
  343. DeviceContext - Supplies the context pointer supplied by the driver when it
  344. attached itself to the driver stack. Presumably this pointer contains
  345. driver-specific device context.
  346. IrpContext - Supplies the context pointer supplied by the driver when
  347. the IRP was created.
  348. Return Value:
  349. None.
  350. --*/
  351. {
  352. return;
  353. }
  354. VOID
  355. DwhciDispatchSystemControl (
  356. PIRP Irp,
  357. PVOID DeviceContext,
  358. PVOID IrpContext
  359. )
  360. /*++
  361. Routine Description:
  362. This routine handles System Control IRPs.
  363. Arguments:
  364. Irp - Supplies a pointer to the I/O request packet.
  365. DeviceContext - Supplies the context pointer supplied by the driver when it
  366. attached itself to the driver stack. Presumably this pointer contains
  367. driver-specific device context.
  368. IrpContext - Supplies the context pointer supplied by the driver when
  369. the IRP was created.
  370. Return Value:
  371. None.
  372. --*/
  373. {
  374. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  375. //
  376. // Do no processing on any IRPs. Let them flow.
  377. //
  378. return;
  379. }
  380. KSTATUS
  381. DwhcipProcessResourceRequirements (
  382. PIRP Irp,
  383. PDWHCI_CONTROLLER_CONTEXT Device
  384. )
  385. /*++
  386. Routine Description:
  387. This routine filters through the resource requirements presented by the
  388. bus for a DWHCI Host controller. It adds an interrupt vector requirement
  389. for any interrupt line requested.
  390. Arguments:
  391. Irp - Supplies a pointer to the I/O request packet.
  392. Device - Supplies a pointer to this DWHCI device.
  393. Return Value:
  394. Status code.
  395. --*/
  396. {
  397. PRESOURCE_CONFIGURATION_LIST Requirements;
  398. KSTATUS Status;
  399. RESOURCE_REQUIREMENT VectorRequirement;
  400. ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
  401. (Irp->MinorCode == IrpMinorQueryResources));
  402. //
  403. // Initialize a nice interrupt vector requirement in preparation.
  404. //
  405. RtlZeroMemory(&VectorRequirement, sizeof(RESOURCE_REQUIREMENT));
  406. VectorRequirement.Type = ResourceTypeInterruptVector;
  407. VectorRequirement.Minimum = 0;
  408. VectorRequirement.Maximum = -1;
  409. VectorRequirement.Length = 1;
  410. //
  411. // Loop through all configuration lists, creating a vector for each line.
  412. //
  413. Requirements = Irp->U.QueryResources.ResourceRequirements;
  414. Status = IoCreateAndAddInterruptVectorsForLines(Requirements,
  415. &VectorRequirement);
  416. if (!KSUCCESS(Status)) {
  417. goto ProcessResourceRequirementsEnd;
  418. }
  419. ProcessResourceRequirementsEnd:
  420. return Status;
  421. }
  422. KSTATUS
  423. DwhcipStartDevice (
  424. PIRP Irp,
  425. PDWHCI_CONTROLLER_CONTEXT Device
  426. )
  427. /*++
  428. Routine Description:
  429. This routine starts up the DWHCI controller.
  430. Arguments:
  431. Irp - Supplies a pointer to the I/O request packet.
  432. Device - Supplies a pointer to this DWHCI device.
  433. Return Value:
  434. Status code.
  435. --*/
  436. {
  437. PRESOURCE_ALLOCATION Allocation;
  438. PRESOURCE_ALLOCATION_LIST AllocationList;
  439. IO_CONNECT_INTERRUPT_PARAMETERS Connect;
  440. PDWHCI_CONTROLLER Controller;
  441. PRESOURCE_ALLOCATION ControllerBase;
  442. PRESOURCE_ALLOCATION LineAllocation;
  443. KSTATUS Status;
  444. Controller = NULL;
  445. ControllerBase = NULL;
  446. //
  447. // Loop through the allocated resources to get the controller base and the
  448. // interrupt.
  449. //
  450. AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
  451. Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
  452. while (Allocation != NULL) {
  453. //
  454. // If the resource is an interrupt vector, then it should have an
  455. // owning interrupt line allocation.
  456. //
  457. if (Allocation->Type == ResourceTypeInterruptVector) {
  458. //
  459. // Currently only one interrupt resource is expected.
  460. //
  461. ASSERT(Device->InterruptResourcesFound == FALSE);
  462. ASSERT(Allocation->OwningAllocation != NULL);
  463. //
  464. // Save the line and vector number.
  465. //
  466. LineAllocation = Allocation->OwningAllocation;
  467. Device->InterruptLine = LineAllocation->Allocation;
  468. Device->InterruptVector = Allocation->Allocation;
  469. Device->InterruptResourcesFound = TRUE;
  470. } else if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
  471. ASSERT(ControllerBase == NULL);
  472. ControllerBase = Allocation;
  473. }
  474. //
  475. // Get the next allocation in the list.
  476. //
  477. Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
  478. }
  479. //
  480. // Fail to start if the controller base was not found.
  481. //
  482. if (ControllerBase == NULL) {
  483. Status = STATUS_INVALID_CONFIGURATION;
  484. goto StartDeviceEnd;
  485. }
  486. //
  487. // Get DWHCI register parameters, including the register base and port
  488. // count.
  489. //
  490. Status = DwhcipGatherControllerParameters(Device, ControllerBase);
  491. if (!KSUCCESS(Status)) {
  492. goto StartDeviceEnd;
  493. }
  494. ASSERT(ControllerBase->Allocation == Device->RegisterBasePhysical);
  495. //
  496. // Allocate the controller structures.
  497. //
  498. Controller = DwhcipInitializeControllerState(Device->RegisterBase,
  499. Device->ChannelCount,
  500. Device->Speed,
  501. Device->MaxTransferSize,
  502. Device->MaxPacketCount,
  503. Device->Revision);
  504. if (Controller == NULL) {
  505. Status = STATUS_INSUFFICIENT_RESOURCES;
  506. goto StartDeviceEnd;
  507. }
  508. Device->Controller = Controller;
  509. //
  510. // Start up the controller.
  511. //
  512. Status = DwhcipInitializeController(Controller);
  513. if (!KSUCCESS(Status)) {
  514. goto StartDeviceEnd;
  515. }
  516. //
  517. // Register the device with the USB core. This is required before enabling
  518. // the interrupt.
  519. //
  520. Status = DwhcipRegisterController(Controller, Irp->Device);
  521. if (!KSUCCESS(Status)) {
  522. goto StartDeviceEnd;
  523. }
  524. //
  525. // Attempt to connect the interrupt.
  526. //
  527. ASSERT(Device->InterruptHandle == INVALID_HANDLE);
  528. RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
  529. Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
  530. Connect.Device = Irp->Device;
  531. Connect.LineNumber = Device->InterruptLine;
  532. Connect.Vector = Device->InterruptVector;
  533. Connect.InterruptServiceRoutine = DwhcipInterruptService;
  534. Connect.Context = Device->Controller;
  535. Connect.Interrupt = &(Device->InterruptHandle);
  536. Status = IoConnectInterrupt(&Connect);
  537. if (!KSUCCESS(Status)) {
  538. goto StartDeviceEnd;
  539. }
  540. DwhcipSetInterruptHandle(Controller, Device->InterruptHandle);
  541. StartDeviceEnd:
  542. if (!KSUCCESS(Status)) {
  543. if (Device->InterruptHandle != INVALID_HANDLE) {
  544. IoDisconnectInterrupt(Device->InterruptHandle);
  545. Device->InterruptHandle = INVALID_HANDLE;
  546. }
  547. if (Controller != NULL) {
  548. DwhcipDestroyControllerState(Controller);
  549. }
  550. }
  551. return Status;
  552. }
  553. VOID
  554. DwhcipEnumerateChildren (
  555. PIRP Irp,
  556. PDWHCI_CONTROLLER_CONTEXT Device
  557. )
  558. /*++
  559. Routine Description:
  560. This routine enumerates the root hub of a DWHCI controller.
  561. Arguments:
  562. Irp - Supplies a pointer to the I/O request packet.
  563. Device - Supplies a pointer to this DWHCI device.
  564. Return Value:
  565. None.
  566. --*/
  567. {
  568. KSTATUS Status;
  569. //
  570. // Forward this on to the USB core to figure out.
  571. //
  572. Status = UsbHostQueryChildren(Irp, Device->Controller->UsbCoreHandle);
  573. IoCompleteIrp(DwhciDriver, Irp, Status);
  574. return;
  575. }
  576. KSTATUS
  577. DwhcipGatherControllerParameters (
  578. PDWHCI_CONTROLLER_CONTEXT ControllerContext,
  579. PRESOURCE_ALLOCATION ControllerBase
  580. )
  581. /*++
  582. Routine Description:
  583. This routine pokes around and collects various pieces of needed information
  584. for the controller, such as the register base and port count.
  585. Arguments:
  586. ControllerContext - Supplies a pointer to the DWHCI controller context.
  587. ControllerBase - Supplies a pointer to the resource allocation defining the
  588. location of the controller's registers.
  589. Return Value:
  590. Status code.
  591. --*/
  592. {
  593. ULONG AlignmentOffset;
  594. ULONG ChannelCount;
  595. PHYSICAL_ADDRESS EndAddress;
  596. ULONG PageSize;
  597. PHYSICAL_ADDRESS PhysicalAddress;
  598. PVOID RegisterAddress;
  599. ULONG RegisterValue;
  600. ULONG Size;
  601. KSTATUS Status;
  602. PVOID VirtualAddress;
  603. ULONG Width;
  604. PageSize = MmPageSize();
  605. ControllerContext->RegisterBasePhysical = ControllerBase->Allocation;
  606. //
  607. // Initialize and map the DWHCI registers.
  608. //
  609. if (ControllerContext->RegisterBase == NULL) {
  610. PhysicalAddress = ControllerContext->RegisterBasePhysical;
  611. EndAddress = PhysicalAddress + ControllerBase->Length;
  612. PhysicalAddress = ALIGN_RANGE_DOWN(PhysicalAddress, PageSize);
  613. AlignmentOffset = ControllerContext->RegisterBasePhysical -
  614. PhysicalAddress;
  615. EndAddress = ALIGN_RANGE_UP(EndAddress, PageSize);
  616. Size = (ULONG)(EndAddress - PhysicalAddress);
  617. VirtualAddress = MmMapPhysicalAddress(PhysicalAddress,
  618. Size,
  619. TRUE,
  620. FALSE,
  621. TRUE);
  622. if (VirtualAddress == NULL) {
  623. Status = STATUS_NO_MEMORY;
  624. goto GatherControllerParametersEnd;
  625. }
  626. ControllerContext->RegisterBase = VirtualAddress + AlignmentOffset;
  627. }
  628. //
  629. // Read the host channel count. The stored value is one less than the
  630. // actual number of channels.
  631. //
  632. if (ControllerContext->ChannelCount == 0) {
  633. RegisterAddress = ControllerContext->RegisterBase +
  634. DwhciRegisterHardware2;
  635. RegisterValue = HlReadRegister32(RegisterAddress);
  636. ChannelCount = 1 + ((RegisterValue &
  637. DWHCI_HARDWARE2_HOST_CHANNEL_COUNT_MASK) >>
  638. DWHCI_HARDWARE2_HOST_CHANNEL_COUNT_SHIFT);
  639. ControllerContext->ChannelCount = ChannelCount;
  640. }
  641. if (ControllerContext->ChannelCount == 0) {
  642. ASSERT(FALSE);
  643. Status = STATUS_NO_SUCH_DEVICE;
  644. goto GatherControllerParametersEnd;
  645. }
  646. //
  647. // Determine the speed of the DWHCI host controller.
  648. //
  649. if (ControllerContext->Speed == UsbDeviceSpeedInvalid) {
  650. RegisterAddress = ControllerContext->RegisterBase +
  651. DwhciRegisterHardware2;
  652. RegisterValue = HlReadRegister32(RegisterAddress);
  653. if ((RegisterValue & DWHCI_HARDWARE2_HIGH_SPEED_MASK) ==
  654. DWHCI_HARDWARE2_HIGH_SPEED_NOT_SUPPORTED) {
  655. ControllerContext->Speed = UsbDeviceSpeedFull;
  656. } else {
  657. ControllerContext->Speed = UsbDeviceSpeedHigh;
  658. }
  659. }
  660. //
  661. // Determine the maximum transfer size and the maximum packet count for the
  662. // DWHCI host controller.
  663. //
  664. if ((ControllerContext->MaxTransferSize == 0) ||
  665. (ControllerContext->MaxPacketCount == 0)) {
  666. RegisterAddress = ControllerContext->RegisterBase +
  667. DwhciRegisterHardware3;
  668. RegisterValue = HlReadRegister32(RegisterAddress);
  669. Width = (RegisterValue & DWHCI_HARDWARE3_TRANSFER_SIZE_WIDTH_MASK) >>
  670. DWHCI_HARDWARE3_TRANSFER_SIZE_WIDTH_SHIFT;
  671. Width += DWHCI_HARDWARE3_TRANSFER_SIZE_WIDTH_OFFSET;
  672. ControllerContext->MaxTransferSize = (1 << Width) - 1;
  673. Width = (RegisterValue & DWHCI_HARDWARE3_PACKET_COUNT_WIDTH_MASK) >>
  674. DWHCI_HARDWARE3_PACKET_COUNT_WIDTH_SHIFT;
  675. Width += DWHCI_HARDWARE3_PACKET_COUNT_WIDTH_OFFSET;
  676. ControllerContext->MaxPacketCount = (1 << Width) - 1;
  677. }
  678. if ((ControllerContext->MaxTransferSize == 0) ||
  679. (ControllerContext->MaxPacketCount == 0)) {
  680. ASSERT(FALSE);
  681. Status = STATUS_NO_SUCH_DEVICE;
  682. goto GatherControllerParametersEnd;
  683. }
  684. //
  685. // Query the revision.
  686. //
  687. RegisterAddress = ControllerContext->RegisterBase +
  688. DwhciRegisterCoreId;
  689. ControllerContext->Revision = HlReadRegister32(RegisterAddress);
  690. Status = STATUS_SUCCESS;
  691. GatherControllerParametersEnd:
  692. return Status;
  693. }