ehci.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. ehci.c
  9. Abstract:
  10. This module implements support for the EHCI USB 2.0 Host controller.
  11. Author:
  12. Evan Green 18-Mar-2013
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/driver.h>
  20. #include <minoca/fw/acpitabs.h>
  21. #include <minoca/intrface/pci.h>
  22. #include <minoca/usb/usbhost.h>
  23. #include "ehci.h"
  24. //
  25. // --------------------------------------------------------------------- Macros
  26. //
  27. //
  28. // ---------------------------------------------------------------- Definitions
  29. //
  30. //
  31. // Define the wait time in seconds for the legacy bit to flip.
  32. //
  33. #define EHCI_LEGACY_SWITCH_TIMEOUT 5
  34. //
  35. // ------------------------------------------------------ Data Type Definitions
  36. //
  37. /*++
  38. Structure Description:
  39. This structure stores context about a EHCI Host Controller.
  40. Members:
  41. InterruptLine - Stores the interrupt line that this controller's interrupt
  42. comes in on.
  43. InterruptVector - Stores the interrupt vector that this controller's
  44. interrupt comes in on.
  45. InterruptResourcesFound - Stores a boolean indicating whether or not the
  46. interrupt line and interrupt vector fields are valid.
  47. InterruptHandle - Stores a pointer to the handle received when the
  48. interrupt was connected.
  49. Controller - Stores a pointer to the EHCI controller.
  50. PciConfigInterface - Stores the interface to access PCI configuration space.
  51. PciConfigInterfaceAvailable - Stores a boolean indicating if the PCI
  52. config interface is actively available.
  53. RegisteredForPciConfigInterfaces - Stores a boolean indicating whether or
  54. not the driver has regsistered for PCI Configuration Space interface
  55. access.
  56. RegisterBasePhysical - Stores the physical memory address where the EHCI
  57. registers are located.
  58. RegisterBase - Stores a pointer to the virtual address where the EHCI
  59. registers are located.
  60. OperationalOffset - Stores the offset from the register base where the
  61. operational registers begin.
  62. PortCount - Stores the number of ports in this controller.
  63. ExtendedCapabilitiesOffset - Stores the offset in PCI configuration space
  64. where the extended capabilities begin. This value must be greater than
  65. 0x40 to be valid (or else it would clash with the PCI spec).
  66. --*/
  67. typedef struct _EHCI_CONTROLLER_CONTEXT {
  68. ULONGLONG InterruptLine;
  69. ULONGLONG InterruptVector;
  70. BOOL InterruptResourcesFound;
  71. HANDLE InterruptHandle;
  72. PEHCI_CONTROLLER Controller;
  73. INTERFACE_PCI_CONFIG_ACCESS PciConfigInterface;
  74. BOOL PciConfigInterfaceAvailable;
  75. BOOL RegisteredForPciConfigInterfaces;
  76. PHYSICAL_ADDRESS RegisterBasePhysical;
  77. PVOID RegisterBase;
  78. ULONG OperationalOffset;
  79. ULONG PortCount;
  80. UCHAR ExtendedCapabilitiesOffset;
  81. } EHCI_CONTROLLER_CONTEXT, *PEHCI_CONTROLLER_CONTEXT;
  82. //
  83. // ----------------------------------------------- Internal Function Prototypes
  84. //
  85. KSTATUS
  86. EhciAddDevice (
  87. PVOID Driver,
  88. PCSTR DeviceId,
  89. PCSTR ClassId,
  90. PCSTR CompatibleIds,
  91. PVOID DeviceToken
  92. );
  93. VOID
  94. EhciDispatchStateChange (
  95. PIRP Irp,
  96. PVOID DeviceContext,
  97. PVOID IrpContext
  98. );
  99. VOID
  100. EhciDispatchOpen (
  101. PIRP Irp,
  102. PVOID DeviceContext,
  103. PVOID IrpContext
  104. );
  105. VOID
  106. EhciDispatchClose (
  107. PIRP Irp,
  108. PVOID DeviceContext,
  109. PVOID IrpContext
  110. );
  111. VOID
  112. EhciDispatchIo (
  113. PIRP Irp,
  114. PVOID DeviceContext,
  115. PVOID IrpContext
  116. );
  117. VOID
  118. EhciDispatchSystemControl (
  119. PIRP Irp,
  120. PVOID DeviceContext,
  121. PVOID IrpContext
  122. );
  123. KSTATUS
  124. EhcipProcessResourceRequirements (
  125. PIRP Irp,
  126. PEHCI_CONTROLLER_CONTEXT Device
  127. );
  128. KSTATUS
  129. EhcipStartDevice (
  130. PIRP Irp,
  131. PEHCI_CONTROLLER_CONTEXT Device
  132. );
  133. VOID
  134. EhcipEnumerateChildren (
  135. PIRP Irp,
  136. PEHCI_CONTROLLER_CONTEXT Device
  137. );
  138. VOID
  139. EhcipProcessPciConfigInterfaceChangeNotification (
  140. PVOID Context,
  141. PDEVICE Device,
  142. PVOID InterfaceBuffer,
  143. ULONG InterfaceBufferSize,
  144. BOOL Arrival
  145. );
  146. KSTATUS
  147. EhcipDisableLegacyInterrupts (
  148. PEHCI_CONTROLLER_CONTEXT ControllerContext
  149. );
  150. KSTATUS
  151. EhcipGatherControllerParameters (
  152. PEHCI_CONTROLLER_CONTEXT ControllerContext,
  153. PRESOURCE_ALLOCATION ControllerBase
  154. );
  155. //
  156. // -------------------------------------------------------------------- Globals
  157. //
  158. //
  159. // Set this flag to avoid bringing up the EHCI driver if there's debug data.
  160. // This is helpful when debugging other drivers that come up at the same time
  161. // as EHCI.
  162. //
  163. BOOL EhciLeaveDebuggerAlone = FALSE;
  164. PDRIVER EhciDriver = NULL;
  165. UUID EhciPciConfigurationInterfaceUuid = UUID_PCI_CONFIG_ACCESS;
  166. //
  167. // ------------------------------------------------------------------ Functions
  168. //
  169. __USED
  170. KSTATUS
  171. DriverEntry (
  172. PDRIVER Driver
  173. )
  174. /*++
  175. Routine Description:
  176. This routine is the entry point for the EHCI driver. It registers its other
  177. dispatch functions, and performs driver-wide initialization.
  178. Arguments:
  179. Driver - Supplies a pointer to the driver object.
  180. Return Value:
  181. STATUS_SUCCESS on success.
  182. Failure code on error.
  183. --*/
  184. {
  185. DRIVER_FUNCTION_TABLE FunctionTable;
  186. KSTATUS Status;
  187. EhciDriver = Driver;
  188. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  189. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  190. FunctionTable.AddDevice = EhciAddDevice;
  191. FunctionTable.DispatchStateChange = EhciDispatchStateChange;
  192. FunctionTable.DispatchOpen = EhciDispatchOpen;
  193. FunctionTable.DispatchClose = EhciDispatchClose;
  194. FunctionTable.DispatchIo = EhciDispatchIo;
  195. FunctionTable.DispatchSystemControl = EhciDispatchSystemControl;
  196. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  197. return Status;
  198. }
  199. //
  200. // --------------------------------------------------------- Internal Functions
  201. //
  202. KSTATUS
  203. EhciAddDevice (
  204. PVOID Driver,
  205. PCSTR DeviceId,
  206. PCSTR ClassId,
  207. PCSTR CompatibleIds,
  208. PVOID DeviceToken
  209. )
  210. /*++
  211. Routine Description:
  212. This routine is called when a device is detected for which the EHCI driver
  213. acts as the function driver. The driver will attach itself to the stack.
  214. Arguments:
  215. Driver - Supplies a pointer to the driver being called.
  216. DeviceId - Supplies a pointer to a string with the device ID.
  217. ClassId - Supplies a pointer to a string containing the device's class ID.
  218. CompatibleIds - Supplies a pointer to a string containing device IDs
  219. that would be compatible with this device.
  220. DeviceToken - Supplies an opaque token that the driver can use to identify
  221. the device in the system. This token should be used when attaching to
  222. the stack.
  223. Return Value:
  224. STATUS_SUCCESS on success.
  225. Failure code if the driver was unsuccessful in attaching itself.
  226. --*/
  227. {
  228. PEHCI_CONTROLLER_CONTEXT NewDevice;
  229. KSTATUS Status;
  230. //
  231. // Create the device context and attach to the device.
  232. //
  233. NewDevice = MmAllocateNonPagedPool(sizeof(EHCI_CONTROLLER_CONTEXT),
  234. EHCI_ALLOCATION_TAG);
  235. if (NewDevice == NULL) {
  236. return STATUS_INSUFFICIENT_RESOURCES;
  237. }
  238. RtlZeroMemory(NewDevice, sizeof(EHCI_CONTROLLER_CONTEXT));
  239. NewDevice->InterruptHandle = INVALID_HANDLE;
  240. Status = IoAttachDriverToDevice(Driver, DeviceToken, NewDevice);
  241. return Status;
  242. }
  243. VOID
  244. EhciDispatchStateChange (
  245. PIRP Irp,
  246. PVOID DeviceContext,
  247. PVOID IrpContext
  248. )
  249. /*++
  250. Routine Description:
  251. This routine handles State Change IRPs.
  252. Arguments:
  253. Irp - Supplies a pointer to the I/O request packet.
  254. DeviceContext - Supplies the context pointer supplied by the driver when it
  255. attached itself to the driver stack. Presumably this pointer contains
  256. driver-specific device context.
  257. IrpContext - Supplies the context pointer supplied by the driver when
  258. the IRP was created.
  259. Return Value:
  260. None.
  261. --*/
  262. {
  263. PEHCI_CONTROLLER_CONTEXT Device;
  264. KSTATUS Status;
  265. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  266. Device = (PEHCI_CONTROLLER_CONTEXT)DeviceContext;
  267. //
  268. // If there is no controller context, then EHCI is acting as the bus driver
  269. // for the root hub. Simply complete standard IRPs.
  270. //
  271. if (Device == NULL) {
  272. switch (Irp->MinorCode) {
  273. case IrpMinorQueryResources:
  274. case IrpMinorStartDevice:
  275. case IrpMinorQueryChildren:
  276. IoCompleteIrp(EhciDriver, Irp, STATUS_SUCCESS);
  277. break;
  278. default:
  279. break;
  280. }
  281. return;
  282. }
  283. if ((Irp->Direction == IrpUp) && (!KSUCCESS(IoGetIrpStatus(Irp)))) {
  284. return;
  285. }
  286. switch (Irp->MinorCode) {
  287. case IrpMinorQueryResources:
  288. //
  289. // On the way up, filter the resource requirements to add interrupt
  290. // vectors to any lines.
  291. //
  292. if (Irp->Direction == IrpUp) {
  293. Status = EhcipProcessResourceRequirements(Irp, Device);
  294. if (!KSUCCESS(Status)) {
  295. IoCompleteIrp(EhciDriver, Irp, Status);
  296. }
  297. }
  298. break;
  299. case IrpMinorStartDevice:
  300. //
  301. // Attempt to fire the thing up if the bus has already started it.
  302. //
  303. if (Irp->Direction == IrpUp) {
  304. Status = EhcipStartDevice(Irp, Device);
  305. if (!KSUCCESS(Status)) {
  306. IoCompleteIrp(EhciDriver, Irp, Status);
  307. }
  308. }
  309. break;
  310. case IrpMinorQueryChildren:
  311. if (Irp->Direction == IrpUp) {
  312. EhcipEnumerateChildren(Irp, Device);
  313. }
  314. break;
  315. case IrpMinorRemoveDevice:
  316. ASSERT(FALSE);
  317. break;
  318. //
  319. // For all other IRPs, do nothing.
  320. //
  321. default:
  322. break;
  323. }
  324. return;
  325. }
  326. VOID
  327. EhciDispatchOpen (
  328. PIRP Irp,
  329. PVOID DeviceContext,
  330. PVOID IrpContext
  331. )
  332. /*++
  333. Routine Description:
  334. This routine handles Open IRPs.
  335. Arguments:
  336. Irp - Supplies a pointer to the I/O request packet.
  337. DeviceContext - Supplies the context pointer supplied by the driver when it
  338. attached itself to the driver stack. Presumably this pointer contains
  339. driver-specific device context.
  340. IrpContext - Supplies the context pointer supplied by the driver when
  341. the IRP was created.
  342. Return Value:
  343. None.
  344. --*/
  345. {
  346. return;
  347. }
  348. VOID
  349. EhciDispatchClose (
  350. PIRP Irp,
  351. PVOID DeviceContext,
  352. PVOID IrpContext
  353. )
  354. /*++
  355. Routine Description:
  356. This routine handles Close IRPs.
  357. Arguments:
  358. Irp - Supplies a pointer to the I/O request packet.
  359. DeviceContext - Supplies the context pointer supplied by the driver when it
  360. attached itself to the driver stack. Presumably this pointer contains
  361. driver-specific device context.
  362. IrpContext - Supplies the context pointer supplied by the driver when
  363. the IRP was created.
  364. Return Value:
  365. None.
  366. --*/
  367. {
  368. return;
  369. }
  370. VOID
  371. EhciDispatchIo (
  372. PIRP Irp,
  373. PVOID DeviceContext,
  374. PVOID IrpContext
  375. )
  376. /*++
  377. Routine Description:
  378. This routine handles I/O IRPs.
  379. Arguments:
  380. Irp - Supplies a pointer to the I/O request packet.
  381. DeviceContext - Supplies the context pointer supplied by the driver when it
  382. attached itself to the driver stack. Presumably this pointer contains
  383. driver-specific device context.
  384. IrpContext - Supplies the context pointer supplied by the driver when
  385. the IRP was created.
  386. Return Value:
  387. None.
  388. --*/
  389. {
  390. return;
  391. }
  392. VOID
  393. EhciDispatchSystemControl (
  394. PIRP Irp,
  395. PVOID DeviceContext,
  396. PVOID IrpContext
  397. )
  398. /*++
  399. Routine Description:
  400. This routine handles System Control IRPs.
  401. Arguments:
  402. Irp - Supplies a pointer to the I/O request packet.
  403. DeviceContext - Supplies the context pointer supplied by the driver when it
  404. attached itself to the driver stack. Presumably this pointer contains
  405. driver-specific device context.
  406. IrpContext - Supplies the context pointer supplied by the driver when
  407. the IRP was created.
  408. Return Value:
  409. None.
  410. --*/
  411. {
  412. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  413. //
  414. // Do no processing on any IRPs. Let them flow.
  415. //
  416. return;
  417. }
  418. KSTATUS
  419. EhcipProcessResourceRequirements (
  420. PIRP Irp,
  421. PEHCI_CONTROLLER_CONTEXT Device
  422. )
  423. /*++
  424. Routine Description:
  425. This routine filters through the resource requirements presented by the
  426. bus for a EHCI Host controller. It adds an interrupt vector requirement for
  427. any interrupt line requested.
  428. Arguments:
  429. Irp - Supplies a pointer to the I/O request packet.
  430. Device - Supplies a pointer to this EHCI device.
  431. Return Value:
  432. Status code.
  433. --*/
  434. {
  435. PRESOURCE_CONFIGURATION_LIST Requirements;
  436. KSTATUS Status;
  437. RESOURCE_REQUIREMENT VectorRequirement;
  438. ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
  439. (Irp->MinorCode == IrpMinorQueryResources));
  440. //
  441. // Initialize a nice interrupt vector requirement in preparation.
  442. //
  443. RtlZeroMemory(&VectorRequirement, sizeof(RESOURCE_REQUIREMENT));
  444. VectorRequirement.Type = ResourceTypeInterruptVector;
  445. VectorRequirement.Minimum = 0;
  446. VectorRequirement.Maximum = -1;
  447. VectorRequirement.Length = 1;
  448. //
  449. // Loop through all configuration lists, creating a vector for each line.
  450. //
  451. Requirements = Irp->U.QueryResources.ResourceRequirements;
  452. Status = IoCreateAndAddInterruptVectorsForLines(Requirements,
  453. &VectorRequirement);
  454. if (!KSUCCESS(Status)) {
  455. goto ProcessResourceRequirementsEnd;
  456. }
  457. ProcessResourceRequirementsEnd:
  458. return Status;
  459. }
  460. KSTATUS
  461. EhcipStartDevice (
  462. PIRP Irp,
  463. PEHCI_CONTROLLER_CONTEXT Device
  464. )
  465. /*++
  466. Routine Description:
  467. This routine starts up the EHCI controller.
  468. Arguments:
  469. Irp - Supplies a pointer to the I/O request packet.
  470. Device - Supplies a pointer to this EHCI device.
  471. Return Value:
  472. Status code.
  473. --*/
  474. {
  475. PRESOURCE_ALLOCATION Allocation;
  476. PRESOURCE_ALLOCATION_LIST AllocationList;
  477. IO_CONNECT_INTERRUPT_PARAMETERS Connect;
  478. PEHCI_CONTROLLER Controller;
  479. PRESOURCE_ALLOCATION ControllerBase;
  480. PDEBUG_HANDOFF_DATA HandoffData;
  481. PRESOURCE_ALLOCATION LineAllocation;
  482. KSTATUS Status;
  483. PDEBUG_USB_HANDOFF_DATA UsbHandoffData;
  484. Controller = NULL;
  485. ControllerBase = NULL;
  486. //
  487. // Start listening for a PCI config interface.
  488. //
  489. if (Device->RegisteredForPciConfigInterfaces == FALSE) {
  490. Status = IoRegisterForInterfaceNotifications(
  491. &EhciPciConfigurationInterfaceUuid,
  492. EhcipProcessPciConfigInterfaceChangeNotification,
  493. Irp->Device,
  494. Device,
  495. TRUE);
  496. if (!KSUCCESS(Status)) {
  497. goto StartDeviceEnd;
  498. }
  499. Device->RegisteredForPciConfigInterfaces = TRUE;
  500. }
  501. //
  502. // Loop through the allocated resources to get the controller base and the
  503. // interrupt.
  504. //
  505. AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
  506. Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
  507. while (Allocation != NULL) {
  508. //
  509. // If the resource is an interrupt vector, then it should have an
  510. // owning interrupt line allocation.
  511. //
  512. if (Allocation->Type == ResourceTypeInterruptVector) {
  513. //
  514. // Currently only one interrupt resource is expected.
  515. //
  516. ASSERT(Device->InterruptResourcesFound == FALSE);
  517. ASSERT(Allocation->OwningAllocation != NULL);
  518. //
  519. // Save the line and vector number.
  520. //
  521. LineAllocation = Allocation->OwningAllocation;
  522. Device->InterruptLine = LineAllocation->Allocation;
  523. Device->InterruptVector = Allocation->Allocation;
  524. Device->InterruptResourcesFound = TRUE;
  525. } else if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
  526. ASSERT(ControllerBase == NULL);
  527. ControllerBase = Allocation;
  528. }
  529. //
  530. // Get the next allocation in the list.
  531. //
  532. Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
  533. }
  534. //
  535. // Fail to start if the controller base was not found.
  536. //
  537. if (ControllerBase == NULL) {
  538. Status = STATUS_INVALID_CONFIGURATION;
  539. goto StartDeviceEnd;
  540. }
  541. //
  542. // Get EHCI register parameters, including the register base and port count.
  543. //
  544. Status = EhcipGatherControllerParameters(Device, ControllerBase);
  545. if (!KSUCCESS(Status)) {
  546. goto StartDeviceEnd;
  547. }
  548. //
  549. // If there is a PCI configuation interface, shut off the legacy interrupt
  550. // redirection to SMI land.
  551. //
  552. Status = EhcipDisableLegacyInterrupts(Device);
  553. if (!KSUCCESS(Status)) {
  554. goto StartDeviceEnd;
  555. }
  556. //
  557. // Also fail if the allocation provided by the OS doesn't line up with
  558. // what's in the registers.
  559. //
  560. if (ControllerBase->Allocation != Device->RegisterBasePhysical) {
  561. ASSERT(FALSE);
  562. Status = STATUS_INVALID_CONFIGURATION;
  563. goto StartDeviceEnd;
  564. }
  565. //
  566. // Look for handoff data to see if the debugger is using this controller.
  567. //
  568. HandoffData = NULL;
  569. Status = KdGetDeviceInformation(&HandoffData);
  570. if (KSUCCESS(Status)) {
  571. if ((HandoffData == NULL) ||
  572. (HandoffData->PortType != DEBUG_PORT_TYPE_USB) ||
  573. (HandoffData->PortSubType != DEBUG_PORT_USB_EHCI) ||
  574. (HandoffData->Identifier != Device->RegisterBasePhysical)) {
  575. HandoffData = NULL;
  576. }
  577. } else {
  578. HandoffData = NULL;
  579. }
  580. if ((HandoffData != NULL) && (EhciLeaveDebuggerAlone != FALSE)) {
  581. RtlDebugPrint("EHCI: Not starting due to debug device.\n");
  582. Status = STATUS_RESOURCE_IN_USE;
  583. goto StartDeviceEnd;
  584. }
  585. //
  586. // Allocate the controller structures.
  587. //
  588. UsbHandoffData = NULL;
  589. if (HandoffData != NULL) {
  590. UsbHandoffData = &(HandoffData->U.Usb);
  591. }
  592. Controller = EhcipInitializeControllerState(
  593. Device->RegisterBase + Device->OperationalOffset,
  594. Device->RegisterBasePhysical,
  595. Device->PortCount,
  596. UsbHandoffData);
  597. if (Controller == NULL) {
  598. Status = STATUS_INSUFFICIENT_RESOURCES;
  599. goto StartDeviceEnd;
  600. }
  601. Device->Controller = Controller;
  602. //
  603. // Start up the controller.
  604. //
  605. Status = EhcipResetController(Controller);
  606. if (!KSUCCESS(Status)) {
  607. goto StartDeviceEnd;
  608. }
  609. //
  610. // Register the device with the USB core. This is required before enabling
  611. // the interrupt.
  612. //
  613. Status = EhcipRegisterController(Controller, Irp->Device);
  614. if (!KSUCCESS(Status)) {
  615. goto StartDeviceEnd;
  616. }
  617. //
  618. // Attempt to connect the interrupt.
  619. //
  620. ASSERT(Device->InterruptHandle == INVALID_HANDLE);
  621. RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
  622. Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
  623. Connect.Device = Irp->Device;
  624. Connect.LineNumber = Device->InterruptLine;
  625. Connect.Vector = Device->InterruptVector;
  626. Connect.InterruptServiceRoutine = EhcipInterruptService;
  627. Connect.DispatchServiceRoutine = EhcipInterruptServiceDpc;
  628. Connect.Context = Device->Controller;
  629. Connect.Interrupt = &(Device->InterruptHandle);
  630. Status = IoConnectInterrupt(&Connect);
  631. if (!KSUCCESS(Status)) {
  632. goto StartDeviceEnd;
  633. }
  634. EhcipSetInterruptHandle(Controller, Device->InterruptHandle);
  635. StartDeviceEnd:
  636. if (!KSUCCESS(Status)) {
  637. if (Device->InterruptHandle != INVALID_HANDLE) {
  638. IoDisconnectInterrupt(Device->InterruptHandle);
  639. Device->InterruptHandle = INVALID_HANDLE;
  640. }
  641. if (Controller != NULL) {
  642. EhcipDestroyControllerState(Controller);
  643. }
  644. }
  645. return Status;
  646. }
  647. VOID
  648. EhcipEnumerateChildren (
  649. PIRP Irp,
  650. PEHCI_CONTROLLER_CONTEXT Device
  651. )
  652. /*++
  653. Routine Description:
  654. This routine enumerates the root hub of a EHCI controller.
  655. Arguments:
  656. Irp - Supplies a pointer to the I/O request packet.
  657. Device - Supplies a pointer to this EHCI device.
  658. Return Value:
  659. None.
  660. --*/
  661. {
  662. KSTATUS Status;
  663. //
  664. // Forward this on to the USB core to figure out.
  665. //
  666. Status = UsbHostQueryChildren(Irp, Device->Controller->UsbCoreHandle);
  667. IoCompleteIrp(EhciDriver, Irp, Status);
  668. return;
  669. }
  670. VOID
  671. EhcipProcessPciConfigInterfaceChangeNotification (
  672. PVOID Context,
  673. PDEVICE Device,
  674. PVOID InterfaceBuffer,
  675. ULONG InterfaceBufferSize,
  676. BOOL Arrival
  677. )
  678. /*++
  679. Routine Description:
  680. This routine is called when a PCI configuration space access interface
  681. changes in availability.
  682. Arguments:
  683. Context - Supplies the caller's context pointer, supplied when the caller
  684. requested interface notifications.
  685. Device - Supplies a pointer to the device exposing or deleting the
  686. interface.
  687. InterfaceBuffer - Supplies a pointer to the interface buffer of the
  688. interface.
  689. InterfaceBufferSize - Supplies the buffer size.
  690. Arrival - Supplies TRUE if a new interface is arriving, or FALSE if an
  691. interface is departing.
  692. Return Value:
  693. None.
  694. --*/
  695. {
  696. PEHCI_CONTROLLER_CONTEXT ControllerContext;
  697. ControllerContext = (PEHCI_CONTROLLER_CONTEXT)Context;
  698. if (Arrival != FALSE) {
  699. if (InterfaceBufferSize >= sizeof(INTERFACE_PCI_CONFIG_ACCESS)) {
  700. ASSERT(ControllerContext->PciConfigInterfaceAvailable == FALSE);
  701. RtlCopyMemory(&(ControllerContext->PciConfigInterface),
  702. InterfaceBuffer,
  703. sizeof(INTERFACE_PCI_CONFIG_ACCESS));
  704. ControllerContext->PciConfigInterfaceAvailable = TRUE;
  705. }
  706. } else {
  707. ControllerContext->PciConfigInterfaceAvailable = FALSE;
  708. }
  709. return;
  710. }
  711. KSTATUS
  712. EhcipDisableLegacyInterrupts (
  713. PEHCI_CONTROLLER_CONTEXT ControllerContext
  714. )
  715. /*++
  716. Routine Description:
  717. This routine disables routing of EHCI interrupts to SMI land (which is used
  718. to emulate a PS/2 keyboard when a USB keyboard is connected).
  719. Without running this, the BIOS would continue to think it owned the EHCI
  720. controller, causing both register clashes and the OS not to get interrupts.
  721. Arguments:
  722. ControllerContext - Supplies a pointer to the EHCI controller context.
  723. Return Value:
  724. Status code.
  725. --*/
  726. {
  727. ULONGLONG LegacyControl;
  728. ULONG LegacyControlRegister;
  729. PVOID PciDeviceToken;
  730. PREAD_PCI_CONFIG ReadPciConfig;
  731. KSTATUS Status;
  732. BOOL TimedOut;
  733. ULONGLONG Timeout;
  734. PWRITE_PCI_CONFIG WritePciConfig;
  735. //
  736. // If no PCI config interface is available, then this must not be a legacy
  737. // platform.
  738. //
  739. if ((ControllerContext->PciConfigInterfaceAvailable == FALSE) ||
  740. (ControllerContext->ExtendedCapabilitiesOffset == 0)) {
  741. Status = STATUS_SUCCESS;
  742. goto DisableLegacyInterruptsEnd;
  743. }
  744. ReadPciConfig = ControllerContext->PciConfigInterface.ReadPciConfig;
  745. WritePciConfig = ControllerContext->PciConfigInterface.WritePciConfig;
  746. PciDeviceToken = ControllerContext->PciConfigInterface.DeviceToken;
  747. //
  748. // Check to see if the EHCI controller is owned by the OS. If it is still
  749. // owned by the BIOS, claim ownership, and wait for the BIOS to agree.
  750. //
  751. LegacyControlRegister = ControllerContext->ExtendedCapabilitiesOffset +
  752. EHCI_EECP_LEGACY_SUPPORT_REGISTER;
  753. Status = ReadPciConfig(PciDeviceToken,
  754. LegacyControlRegister,
  755. sizeof(ULONG),
  756. &LegacyControl);
  757. if (!KSUCCESS(Status)) {
  758. goto DisableLegacyInterruptsEnd;
  759. }
  760. if ((LegacyControl & EHCI_LEGACY_SUPPORT_BIOS_OWNED) != 0) {
  761. //
  762. // If both the OS and BIOS owned bits are set, this is an indication
  763. // something more serious is wrong, or these are not really EHCI
  764. // registers.
  765. //
  766. ASSERT((LegacyControl & EHCI_LEGACY_SUPPORT_OS_OWNED) == 0);
  767. //
  768. // Write the "OS owned" bit to request that the BIOS stop trying to be
  769. // helpful and get out of the way.
  770. //
  771. LegacyControl |= EHCI_LEGACY_SUPPORT_OS_OWNED;
  772. Status = WritePciConfig(PciDeviceToken,
  773. LegacyControlRegister,
  774. sizeof(ULONG),
  775. LegacyControl);
  776. //
  777. // Now loop waiting for the BIOS to give it up.
  778. //
  779. Timeout = KeGetRecentTimeCounter() +
  780. (HlQueryTimeCounterFrequency() * EHCI_LEGACY_SWITCH_TIMEOUT);
  781. TimedOut = TRUE;
  782. do {
  783. Status = ReadPciConfig(PciDeviceToken,
  784. LegacyControlRegister,
  785. sizeof(ULONG),
  786. &LegacyControl);
  787. if (!KSUCCESS(Status)) {
  788. goto DisableLegacyInterruptsEnd;
  789. }
  790. if ((LegacyControl & EHCI_LEGACY_SUPPORT_BIOS_OWNED) == 0) {
  791. Status = STATUS_SUCCESS;
  792. TimedOut = FALSE;
  793. break;
  794. }
  795. } while (KeGetRecentTimeCounter() <= Timeout);
  796. if (TimedOut != FALSE) {
  797. RtlDebugPrint("EHCI: BIOS failed to relinquish control: 0x%I64x\n",
  798. LegacyControl);
  799. Status = STATUS_TIMEOUT;
  800. }
  801. if (!KSUCCESS(Status)) {
  802. goto DisableLegacyInterruptsEnd;
  803. }
  804. }
  805. Status = STATUS_SUCCESS;
  806. DisableLegacyInterruptsEnd:
  807. return Status;
  808. }
  809. KSTATUS
  810. EhcipGatherControllerParameters (
  811. PEHCI_CONTROLLER_CONTEXT ControllerContext,
  812. PRESOURCE_ALLOCATION ControllerBase
  813. )
  814. /*++
  815. Routine Description:
  816. This routine pokes around and collects various pieces of needed information
  817. for the controller, such as the register base, operational offset, and
  818. port count.
  819. Arguments:
  820. ControllerContext - Supplies a pointer to the EHCI controller context.
  821. ControllerBase - Supplies a pointer to the resource allocation defining the
  822. location of the controller's registers.
  823. Return Value:
  824. Status code.
  825. --*/
  826. {
  827. ULONG AlignmentOffset;
  828. ULONG Capabilities;
  829. PVOID CapabilitiesRegister;
  830. PHYSICAL_ADDRESS EndAddress;
  831. PVOID LengthRegister;
  832. ULONG PageSize;
  833. ULONG Parameters;
  834. PVOID ParametersRegister;
  835. PVOID PciDeviceToken;
  836. PHYSICAL_ADDRESS PhysicalAddress;
  837. PREAD_PCI_CONFIG ReadPciConfig;
  838. ULONG Size;
  839. KSTATUS Status;
  840. ULONGLONG Value;
  841. PVOID VirtualAddress;
  842. //
  843. // If a PCI config interface is available, verify the base address.
  844. //
  845. if (ControllerContext->PciConfigInterfaceAvailable != FALSE) {
  846. //
  847. // Read the register base register to find out where all the other
  848. // registers begin in memory.
  849. //
  850. ReadPciConfig = ControllerContext->PciConfigInterface.ReadPciConfig;
  851. PciDeviceToken = ControllerContext->PciConfigInterface.DeviceToken;
  852. if (ControllerContext->RegisterBasePhysical == 0) {
  853. Status = ReadPciConfig(PciDeviceToken,
  854. EHCI_USB_REGISTER_BASE_REGISTER,
  855. sizeof(ULONG),
  856. &Value);
  857. if (!KSUCCESS(Status)) {
  858. goto GatherControllerParametersEnd;
  859. }
  860. PhysicalAddress = (ULONG)Value &
  861. EHCI_USB_REGISTER_BASE_ADDRESS_MASK;
  862. ASSERT(PhysicalAddress == ControllerBase->Allocation);
  863. ControllerContext->RegisterBasePhysical = PhysicalAddress;
  864. }
  865. } else {
  866. ControllerContext->RegisterBasePhysical = ControllerBase->Allocation;
  867. }
  868. //
  869. // Map those registers if needed.
  870. //
  871. ASSERT(ControllerContext->RegisterBasePhysical != 0);
  872. if (ControllerContext->RegisterBase == NULL) {
  873. //
  874. // Page align the mapping request.
  875. //
  876. PageSize = MmPageSize();
  877. ASSERT(ControllerContext->RegisterBasePhysical ==
  878. ControllerBase->Allocation);
  879. PhysicalAddress = ControllerContext->RegisterBasePhysical;
  880. EndAddress = PhysicalAddress + ControllerBase->Length;
  881. PhysicalAddress = ALIGN_RANGE_DOWN(PhysicalAddress, PageSize);
  882. AlignmentOffset = ControllerContext->RegisterBasePhysical -
  883. PhysicalAddress;
  884. EndAddress = ALIGN_RANGE_UP(EndAddress, PageSize);
  885. Size = (ULONG)(EndAddress - PhysicalAddress);
  886. VirtualAddress = MmMapPhysicalAddress(PhysicalAddress,
  887. Size,
  888. TRUE,
  889. FALSE,
  890. TRUE);
  891. if (VirtualAddress == NULL) {
  892. Status = STATUS_NO_MEMORY;
  893. goto GatherControllerParametersEnd;
  894. }
  895. ControllerContext->RegisterBase = VirtualAddress + AlignmentOffset;
  896. }
  897. ASSERT(ControllerContext->RegisterBase != NULL);
  898. //
  899. // Read the operational offset if needed.
  900. //
  901. if (ControllerContext->OperationalOffset == 0) {
  902. LengthRegister = ControllerContext->RegisterBase +
  903. EHCI_CAPABILITY_LENGTH_REGISTER;
  904. ControllerContext->OperationalOffset = HlReadRegister8(LengthRegister);
  905. }
  906. //
  907. // Read the port count and other structural parameters if needed.
  908. //
  909. if (ControllerContext->PortCount == 0) {
  910. ParametersRegister = ControllerContext->RegisterBase +
  911. EHCI_CAPABILITY_PARAMETERS_REGISTER;
  912. Parameters = HlReadRegister32(ParametersRegister);
  913. ControllerContext->PortCount =
  914. Parameters & EHCI_CAPABILITY_PARAMETERS_PORT_COUNT_MASK;
  915. }
  916. if (ControllerContext->PortCount == 0) {
  917. ASSERT(FALSE);
  918. Status = STATUS_NO_SUCH_DEVICE;
  919. goto GatherControllerParametersEnd;
  920. }
  921. //
  922. // Grab the extended capabilities offset.
  923. //
  924. if (ControllerContext->ExtendedCapabilitiesOffset == 0) {
  925. CapabilitiesRegister = ControllerContext->RegisterBase +
  926. EHCI_CAPABILITY_CAPABILITIES_REGISTER;
  927. Capabilities = HlReadRegister32(CapabilitiesRegister);
  928. ControllerContext->ExtendedCapabilitiesOffset =
  929. (Capabilities &
  930. EHCI_CAPABILITY_CAPABILITIES_EXTENDED_CAPABILITIES_MASK) >>
  931. EHCI_CAPABILITY_CAPABILITIES_EXTENDED_CAPABILITIES_SHIFT;
  932. }
  933. Status = STATUS_SUCCESS;
  934. GatherControllerParametersEnd:
  935. return Status;
  936. }