Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4213 lines
114 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. OpenHCI.c
  5. Abstract:
  6. The OpenHCI driver for USB, this module contains the initialization code.
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. 12-28-95 : created jfuller
  12. 3-1-96 : modified kenray
  13. --*/
  14. #include "openhci.h"
  15. #include <windef.h>
  16. #include <unknown.h>
  17. #ifdef DRM_SUPPORT
  18. #include <ks.h>
  19. #include <ksmedia.h>
  20. #include <drmk.h>
  21. #include <ksdrmhlp.h>
  22. #endif
  23. #ifdef MAX_DEBUG
  24. ULONG OHCI_Debug_Trace_Level = 2;
  25. #else
  26. #ifdef NTKERN
  27. ULONG OHCI_Debug_Trace_Level = 1;
  28. #else
  29. ULONG OHCI_Debug_Trace_Level
  30. #ifdef JD
  31. = 1;
  32. #else
  33. = 0;
  34. #endif /* JD */
  35. #endif /* NTKERN */
  36. #endif /* MAX_DEBUG */
  37. #define OHCI_WAIT(ms) {\
  38. LARGE_INTEGER t;\
  39. t.QuadPart = (((LONG)KeQueryTimeIncrement()-1) + (ms) * 10000) * -1;\
  40. KeDelayExecutionThread(KernelMode, FALSE, &t);\
  41. }
  42. NTSTATUS
  43. DriverEntry(
  44. IN PDRIVER_OBJECT DriverObject,
  45. IN PUNICODE_STRING RegistryPath
  46. )
  47. /*++
  48. Routine Description:
  49. Installable driver initialization entry point.
  50. This entry point is called directly by the I/O system.
  51. Arguments:
  52. DriverObject - pointer to the driver object
  53. RegistryPath - pointer to a unicode string representing the path
  54. to driver-specific key in the registry
  55. Return Value:
  56. NT status code
  57. --*/
  58. {
  59. PDEVICE_OBJECT deviceObject = NULL;
  60. NTSTATUS ntStatus = STATUS_SUCCESS;
  61. OpenHCI_KdPrint((2, "'entering DriverEntry\n"));
  62. OpenHCI_KdPrint ((1, "'HCD using USBDI version %x\n", USBDI_VERSION));
  63. if (NT_SUCCESS(ntStatus)) {
  64. //
  65. // Create dispatch points for device control, create, close.
  66. //
  67. DriverObject->MajorFunction[IRP_MJ_CREATE] =
  68. DriverObject->MajorFunction[IRP_MJ_CLOSE] =
  69. DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] =
  70. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  71. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] =
  72. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
  73. = OpenHCI_Dispatch;
  74. DriverObject->MajorFunction[IRP_MJ_PNP] = OpenHCI_Dispatch;
  75. DriverObject->MajorFunction[IRP_MJ_POWER] = OpenHCI_Dispatch;
  76. DriverObject->DriverExtension->AddDevice = OpenHCI_PnPAddDevice;
  77. DriverObject->DriverUnload = OpenHCI_Unload;
  78. }
  79. OpenHCI_KdPrint((2, "'exit DriverEntry %x\n", ntStatus));
  80. return ntStatus;
  81. }
  82. #ifdef DRM_SUPPORT
  83. NTSTATUS
  84. OpenHCI_PreUSBD_SetContentId
  85. (
  86. IN PIRP irp,
  87. IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
  88. IN PKSDRMAUDIOSTREAM_CONTENTID pvData
  89. )
  90. /* ++
  91. *
  92. * Description:
  93. *
  94. *
  95. * Arguments:
  96. *
  97. * Return:
  98. *
  99. * -- */
  100. {
  101. PVOID Handlers[1];
  102. ULONG ContentId;
  103. PAGED_CODE();
  104. ASSERT(irp);
  105. ASSERT(pKsProperty);
  106. ASSERT(pvData);
  107. ContentId = pvData->ContentId;
  108. Handlers[0] = USBD_Dispatch;
  109. return pKsProperty->DrmAddContentHandlers(ContentId, Handlers, SIZEOF_ARRAY(Handlers));
  110. }
  111. NTSTATUS
  112. OpenHCI_PostUSBD_SetContentId
  113. (
  114. IN PIRP irp,
  115. IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
  116. IN PKSDRMAUDIOSTREAM_CONTENTID pvData
  117. )
  118. /* ++
  119. *
  120. * Description:
  121. *
  122. *
  123. * Arguments:
  124. *
  125. * Return:
  126. *
  127. * -- */
  128. {
  129. NTSTATUS ntStatus;
  130. PAGED_CODE();
  131. ASSERT(irp);
  132. ASSERT(pKsProperty);
  133. ASSERT(pvData);
  134. // ioStackLocation = IoGetCurrentIrpStackLocation(irp);
  135. // deviceExtension = ioStackLocation->DeviceObject->DeviceExtension;
  136. // Context = pKsProperty->Context;
  137. // ContentId = pvData->ContentId;;
  138. return STATUS_SUCCESS;
  139. }
  140. #endif
  141. NTSTATUS
  142. OpenHCI_Dispatch(
  143. IN PDEVICE_OBJECT DeviceObject,
  144. IN PIRP Irp
  145. )
  146. /*++
  147. Routine Description:
  148. Process the IRPs sent to this device.
  149. Arguments:
  150. DeviceObject - pointer to a device object
  151. Irp - pointer to an I/O Request Packet
  152. Return Value:
  153. NT status code
  154. --*/
  155. {
  156. PIO_STACK_LOCATION irpStack;
  157. NTSTATUS ntStatus = STATUS_SUCCESS;
  158. PHCD_DEVICE_DATA DeviceData;
  159. PDEVICE_OBJECT hcdDeviceObject, topOfStackPhysicalDeviceObject;
  160. BOOLEAN touchHardware = TRUE;
  161. #ifdef DRM_SUPPORT
  162. //
  163. // Need to check DRM request before passing to USBD and advise DRM of
  164. // the USBD entry point. Otherwise, a rogue USBD could circumvent DRM.
  165. //
  166. irpStack = IoGetCurrentIrpStackLocation (Irp);
  167. if (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction && IOCTL_KS_PROPERTY == irpStack->Parameters.DeviceIoControl.IoControlCode) {
  168. NTSTATUS ntStatus;
  169. ntStatus = KsPropertyHandleDrmSetContentId(Irp, OpenHCI_PreUSBD_SetContentId);
  170. if (!NT_SUCCESS(ntStatus) && ntStatus != STATUS_PROPSET_NOT_FOUND) {
  171. Irp->IoStatus.Status = ntStatus;
  172. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  173. return ntStatus;
  174. }
  175. }
  176. #endif
  177. //
  178. // see if USBD will handle this request
  179. //
  180. //
  181. // First we pass the irp to USBD
  182. //
  183. if (!USBD_Dispatch(DeviceObject,
  184. Irp,
  185. &hcdDeviceObject,
  186. &ntStatus)) {
  187. //
  188. // Irp was completed by USBD just exit our dispatch
  189. // routine.
  190. //
  191. DeviceData = (PHCD_DEVICE_DATA) hcdDeviceObject->DeviceExtension;
  192. goto OpenHCI_Dispatch_Done;
  193. }
  194. IRP_IN(Irp);
  195. DeviceData = (PHCD_DEVICE_DATA) hcdDeviceObject->DeviceExtension;
  196. OpenHCI_KdPrintDD(DeviceData,
  197. OHCI_DBG_CALL_TRACE, ("'enter OHCI_Dispatch\n"));
  198. //
  199. // use the extension from our FDO, note the USBD function returns us
  200. // our FDO.
  201. //
  202. irpStack = IoGetCurrentIrpStackLocation(Irp);
  203. switch (irpStack->MajorFunction) {
  204. case IRP_MJ_CREATE:
  205. OpenHCI_KdPrintDD(DeviceData,
  206. OHCI_DBG_CALL_TRACE, ("'IRP_MJ_CREATE\n"));
  207. OpenHCI_CompleteIrp(hcdDeviceObject, Irp, ntStatus);
  208. break;
  209. case IRP_MJ_CLOSE:
  210. OpenHCI_KdPrintDD(DeviceData,
  211. OHCI_DBG_CALL_TRACE, ("'IRP_MJ_CLOSE\n"));
  212. OpenHCI_CompleteIrp(hcdDeviceObject, Irp, ntStatus);
  213. break;
  214. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  215. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  216. case IOCTL_INTERNAL_USB_SUBMIT_URB:
  217. OpenHCI_KdPrintDD(DeviceData,
  218. OHCI_DBG_CALL_TRACE, ("'Process URB\n"));
  219. ntStatus = OpenHCI_URB_Dispatch(hcdDeviceObject, Irp);
  220. break;
  221. default:
  222. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_ERROR,
  223. ("'Unhandled Internal IOCTL IoCtl: %x, min: %x\n",
  224. irpStack->Parameters.DeviceIoControl.IoControlCode,
  225. irpStack->MinorFunction));
  226. TEST_TRAP();
  227. ntStatus = STATUS_NOT_IMPLEMENTED;
  228. OpenHCI_CompleteIrp(hcdDeviceObject, Irp, ntStatus);
  229. }
  230. break;
  231. case IRP_MJ_DEVICE_CONTROL:
  232. OpenHCI_KdPrintDD(DeviceData,
  233. OHCI_DBG_CALL_TRACE, ("'IRP_MJ_DEVICE_CONTROL\n"));
  234. switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
  235. {
  236. #ifdef DRM_SUPPORT
  237. case IOCTL_KS_PROPERTY:
  238. {
  239. ntStatus = KsPropertyHandleDrmSetContentId(Irp, OpenHCI_PostUSBD_SetContentId);
  240. OpenHCI_CompleteIrp(hcdDeviceObject, Irp, ntStatus);
  241. break;
  242. }
  243. #endif
  244. #if FAKEPORTCHANGE
  245. case IOCTL_USB_HCD_DISABLE_PORT:
  246. case IOCTL_USB_HCD_ENABLE_PORT:
  247. {
  248. ULONG portIndex;
  249. PHC_OPERATIONAL_REGISTER HC;
  250. HC = DeviceData->HC;
  251. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  252. sizeof(ULONG))
  253. {
  254. ntStatus = STATUS_BUFFER_TOO_SMALL;
  255. }
  256. else
  257. {
  258. // Get the zero-based port number.
  259. //
  260. portIndex = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
  261. if (portIndex >= DeviceData->NumberOfPorts)
  262. {
  263. ntStatus = STATUS_INVALID_PARAMETER;
  264. }
  265. else
  266. {
  267. LOGENTRY(G, 'FAKE', DeviceData->FakePortChange,
  268. DeviceData->FakePortDisconnect, portIndex);
  269. DeviceData->FakePortChange |= (1 << portIndex);
  270. if (irpStack->Parameters.DeviceIoControl.IoControlCode ==
  271. IOCTL_USB_HCD_DISABLE_PORT)
  272. {
  273. DeviceData->FakePortDisconnect |= (1 << portIndex);
  274. }
  275. else
  276. {
  277. DeviceData->FakePortDisconnect &= ~(1 << portIndex);
  278. }
  279. LOGENTRY(G, 'fake', DeviceData->FakePortChange,
  280. DeviceData->FakePortDisconnect, portIndex);
  281. // Can't trigger an HcInt_RootHubStatusChange interrupt
  282. // so just trigger an SOF interrupt and OpenHCI_IsrDPC()
  283. // will call EmulateRootHubInterruptXfer() since we just
  284. // set a bit in DeviceData->FakePortChange.
  285. //
  286. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable,
  287. HcInt_StartOfFrame);
  288. ntStatus = STATUS_SUCCESS;
  289. }
  290. }
  291. OpenHCI_CompleteIrp(hcdDeviceObject, Irp, ntStatus);
  292. break;
  293. }
  294. #endif // FAKEPORTCHANGE
  295. default:
  296. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  297. OpenHCI_CompleteIrp(hcdDeviceObject, Irp, ntStatus);
  298. break;
  299. }
  300. break;
  301. //
  302. // Process PnP messages
  303. //
  304. case IRP_MJ_PNP:
  305. OpenHCI_KdPrintDD(DeviceData,
  306. OHCI_DBG_CALL_TRACE, ("'IRP_MJ_PNP\n"));
  307. topOfStackPhysicalDeviceObject =
  308. DeviceData->TopOfStackPhysicalDeviceObject;
  309. switch (irpStack->MinorFunction) {
  310. case IRP_MN_START_DEVICE:
  311. OpenHCI_KdPrintDD(DeviceData,
  312. OHCI_DBG_PNP_TRACE, ("'IRP_MN_START_DEVICE\n"));
  313. OpenHCI_KdTrap(("'should not see start\n"));
  314. break;
  315. //
  316. // STOP & REMOVE messages unload the driver.
  317. // When we get a STOP message it is still possible touch the
  318. // hardware,
  319. // When we get a REMOVE message we assume that the hardware is
  320. // gone.
  321. //
  322. case IRP_MN_STOP_DEVICE:
  323. OpenHCI_KdPrintDD(DeviceData,
  324. OHCI_DBG_PNP_TRACE, ("'IRP_MN_STOP_DEVICE\n"));
  325. ntStatus = OpenHCI_StopDevice(hcdDeviceObject, TRUE);
  326. // The documentation says to set the status before passing the
  327. // Irp down the stack
  328. //
  329. Irp->IoStatus.Status = STATUS_SUCCESS;
  330. break;
  331. case IRP_MN_SURPRISE_REMOVAL:
  332. touchHardware = FALSE;
  333. // Stop assert failure in OpenHCI_StopDevice() by clearing these
  334. //
  335. DeviceData->RootHubAddress = 0;
  336. DeviceData->RootHubConfig = 0;
  337. // Fall Through!
  338. case IRP_MN_REMOVE_DEVICE:
  339. OpenHCI_KdPrintDD(DeviceData,
  340. OHCI_DBG_PNP_TRACE, ("'IRP_MN_REMOVE_DEVICE\n"));
  341. // Currently we touch the hardware registers suring a remove
  342. // the reason is that during shutdown to DOS mode in Win95
  343. // we only get a remove messages.
  344. //
  345. // this code may need some modifiaction in the event we see
  346. // a PC-CARD version of the OHCI host controller
  347. ntStatus = OpenHCI_StopDevice(hcdDeviceObject, touchHardware);
  348. USBD_FreeDeviceName(DeviceData->DeviceNameHandle);
  349. IoDetachDevice(DeviceData->TopOfStackPhysicalDeviceObject);
  350. IoDeleteDevice(hcdDeviceObject);
  351. break;
  352. default:
  353. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_PNP_ERROR,
  354. ("'PNP MESSAGE NOT HANDLED 0x%x\n",
  355. irpStack->MinorFunction));
  356. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_CALL_TRACE,
  357. ("'exit OpenHCI_Dispatch\n"));
  358. //
  359. // PnP messages not handled are passed on to the PDO
  360. //
  361. } // switch (irpStack->MinorFunction), PNP
  362. //
  363. // All PNP messages are passed on to the lower levels.
  364. // aka the PhysicalDeviceObject
  365. //
  366. IRP_OUT(Irp);
  367. IoDecrementStackLocation(Irp);
  368. ntStatus = IoCallDriver(topOfStackPhysicalDeviceObject,
  369. Irp);
  370. break; // IRP_MJ_PNP
  371. //
  372. // Process Power messages
  373. //
  374. case IRP_MJ_POWER:
  375. OpenHCI_KdPrintDD(DeviceData,
  376. OHCI_DBG_CALL_TRACE, ("'IRP_MJ_POWER\n"));
  377. // should not get here, USBD should handle all power irps
  378. OpenHCI_KdTrap(("'power message to HCD?\n"));
  379. TRAP();
  380. break; // IRP_MJ_POWER
  381. default:
  382. OpenHCI_KdBreak(("'unrecognized IRP_MJ_ function (%x)\n",
  383. irpStack->MajorFunction));
  384. ntStatus = STATUS_INVALID_PARAMETER;
  385. OpenHCI_CompleteIrp(hcdDeviceObject, Irp, ntStatus);
  386. } /* case */
  387. OpenHCI_Dispatch_Done:
  388. OpenHCI_KdPrint((2, "'exit OpenHCI_Dispatch\n", ntStatus));
  389. return ntStatus;
  390. }
  391. NTSTATUS
  392. OpenHCI_PowerIrpComplete(
  393. IN PDEVICE_OBJECT PhysicalDeviceObject,
  394. IN PIRP Irp,
  395. IN PVOID Context
  396. )
  397. /*++
  398. Routine Description:
  399. This routine is called when the BUS a completes IRP_MJ_POWER
  400. Irp.
  401. Arguments:
  402. DeviceObject - Pointer to the OpenHCI device object
  403. Irp - The IPR_MJ_POWER Irp, which was just sent down to the PDO.
  404. Context - The OpenHCI DeviceObject (FDO).
  405. --*/
  406. {
  407. NTSTATUS ntStatus = STATUS_SUCCESS;
  408. PIO_STACK_LOCATION irpStack = NULL;
  409. PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
  410. PHCD_DEVICE_DATA DeviceData = deviceObject->DeviceExtension;
  411. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_PNP_TRACE, ("'PowerIrpComplete"));
  412. irpStack = IoGetCurrentIrpStackLocation(Irp);
  413. if (TRUE == Irp->PendingReturned) {
  414. IoMarkIrpPending(Irp);
  415. }
  416. OHCI_ASSERT(IRP_MJ_POWER == irpStack->MajorFunction);
  417. OHCI_ASSERT(IRP_MN_SET_POWER == irpStack->MinorFunction);
  418. OHCI_ASSERT(irpStack->Parameters.Power.Type == DevicePowerState);
  419. OHCI_ASSERT(irpStack->Parameters.Power.State.DeviceState ==
  420. PowerDeviceD0);
  421. DeviceData->CurrentDevicePowerState = PowerDeviceD0;
  422. OpenHCI_KdPrint((1, "'Host Controller entered (D0)\n"));
  423. Irp->IoStatus.Status = ntStatus;
  424. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_PNP_TRACE,
  425. ("'exit PowerIrpComplete 0x%x\n", ntStatus));
  426. return ntStatus;
  427. }
  428. VOID
  429. OpenHCI_Unload(
  430. IN PDRIVER_OBJECT Driver
  431. )
  432. /*++
  433. Routine Description:
  434. Free all the global allocated resources, etc.
  435. Arguments:
  436. DriverObject - pointer to a driver object
  437. Return Value:
  438. None
  439. --*/
  440. {
  441. OpenHCI_KdPrint((2, "'unloading\n"));
  442. OHCI_LogFree();
  443. }
  444. NTSTATUS
  445. OpenHCI_CreateDeviceObject(
  446. IN PDRIVER_OBJECT DriverObject,
  447. IN OUT PDEVICE_OBJECT * DeviceObject,
  448. IN PUNICODE_STRING DeviceNameUnicodeString
  449. )
  450. /*++
  451. Routine Description:
  452. This routine is called to create a new instance of a USB host
  453. controller.
  454. Arguments:
  455. DriverObject - pointer to the driver object for USBD.
  456. *DeviceObject - ptr to DeviceObject ptr to be filled
  457. in with the device object we create.
  458. Configuration - ptr to configuration data to be stored
  459. in the device extension.
  460. AdpatersFound - zero based index for this adapter, used to
  461. create a unique device name.
  462. Return Value:
  463. NT status code
  464. --*/
  465. {
  466. NTSTATUS ntStatus;
  467. PHCD_DEVICE_DATA DeviceData;
  468. OpenHCI_KdPrint((2,
  469. "'enter OpenHCI_CreateDeviceObject\n"));
  470. ASSERT((PDEVICE_OBJECT *) NULL != DeviceObject);
  471. if (DeviceNameUnicodeString) {
  472. OpenHCI_KdPrint((2, "'CreateDeviceObject: device object named %ws\n",
  473. DeviceNameUnicodeString->Buffer));
  474. } else {
  475. OpenHCI_KdPrint((2, "'CreateDeviceObject w/ no name\n"));
  476. }
  477. ntStatus = IoCreateDevice(DriverObject,
  478. sizeof(HCD_DEVICE_DATA),
  479. DeviceNameUnicodeString,
  480. FILE_DEVICE_CONTROLLER,
  481. 0,
  482. FALSE,
  483. DeviceObject);
  484. if (NT_SUCCESS(ntStatus)) {
  485. DeviceData = (PHCD_DEVICE_DATA) ((*DeviceObject)->DeviceExtension);
  486. //
  487. // Zero / NULL initialize all fields of the DeviceData structure.
  488. //
  489. RtlZeroMemory(DeviceData, sizeof(HCD_DEVICE_DATA));
  490. //
  491. // link configuration info to the DeviceData
  492. //
  493. DeviceData->DeviceObject = *DeviceObject;
  494. //
  495. // Initialize various objects in DeviceData
  496. //
  497. KeInitializeSpinLock(&DeviceData->InterruptSpin);
  498. KeInitializeSpinLock(&DeviceData->EDListSpin);
  499. InitializeListHead(&DeviceData->StalledEDReclamation);
  500. InitializeListHead(&DeviceData->RunningEDReclamation);
  501. InitializeListHead(&DeviceData->PausedEDRestart);
  502. DeviceData->DebugLevel = OHCI_DEFAULT_DEBUG_OUTPUT_LEVEL;
  503. DeviceData->AvailableBandwidth = 10280;
  504. DeviceData->HcDma = -1;
  505. KeInitializeSpinLock(&DeviceData->HcDmaSpin);
  506. KeInitializeSpinLock(&DeviceData->DescriptorsSpin);
  507. KeInitializeSpinLock(&DeviceData->ReclamationSpin);
  508. KeInitializeSpinLock(&DeviceData->PausedSpin);
  509. KeInitializeSpinLock(&DeviceData->HcFlagSpin);
  510. KeInitializeSpinLock(&DeviceData->PageListSpin);
  511. // Initialize our deadman timer
  512. //
  513. KeInitializeDpc(&DeviceData->DeadmanTimerDPC,
  514. OpenHCI_DeadmanDPC,
  515. *DeviceObject);
  516. KeInitializeTimer(&DeviceData->DeadmanTimer);
  517. #if DBG
  518. // will roll over in < 6 minutes
  519. DeviceData->FrameHighPart = 0xFFFB0000;
  520. // noone is in open or close Endpoint.
  521. DeviceData->OpenCloseSync = -1;
  522. #endif
  523. }
  524. OpenHCI_KdPrint((2, "'exit CreateDevObject %x\n", ntStatus));
  525. return ntStatus;
  526. }
  527. NTSTATUS
  528. OpenHCI_PnPAddDevice(
  529. IN PDRIVER_OBJECT DriverObject,
  530. IN PDEVICE_OBJECT PhysicalDeviceObject
  531. )
  532. /*++
  533. jd
  534. Routine Description:
  535. This routine creates a new instance of a USB host controller
  536. Arguments:
  537. DriverObject - pointer to the driver object for this instance of ohcd
  538. PhysicalDeviceObject - pointer to a device object created by the bus
  539. Return Value:
  540. STATUS_SUCCESS if successful,
  541. STATUS_UNSUCCESSFUL otherwise
  542. --*/
  543. {
  544. NTSTATUS ntStatus;
  545. PDEVICE_OBJECT deviceObject = NULL;
  546. PHCD_DEVICE_DATA DeviceData;
  547. UNICODE_STRING deviceNameUnicodeString;
  548. ULONG deviceNameHandle;
  549. OpenHCI_KdPrint((2, "'enter OpenHCI_PnPAddDevice\n"));
  550. deviceNameHandle = USBD_AllocateDeviceName(&deviceNameUnicodeString);
  551. ntStatus = OpenHCI_CreateDeviceObject(DriverObject,
  552. &deviceObject,
  553. &deviceNameUnicodeString);
  554. if (NT_SUCCESS(ntStatus)) {
  555. DeviceData = deviceObject->DeviceExtension;
  556. DeviceData->DeviceNameHandle = deviceNameHandle;
  557. DeviceData->RealPhysicalDeviceObject = PhysicalDeviceObject;
  558. DeviceData->TopOfStackPhysicalDeviceObject =
  559. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  560. //
  561. // We need to keep track of BOTH the pdo and any filter drivers
  562. // that might have attaced to the top of the pdo. We cannot use
  563. // IoAttachDevice, and we must have another variable.
  564. //
  565. if (NT_SUCCESS(ntStatus)) {
  566. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  567. deviceObject->Flags |= DO_POWER_PAGABLE;
  568. //
  569. // The device is ready for requests.
  570. //
  571. USBD_RegisterHostController(PhysicalDeviceObject,
  572. deviceObject,
  573. DeviceData->
  574. TopOfStackPhysicalDeviceObject,
  575. DriverObject,
  576. OpenHCI_DeferredStartDevice,
  577. OpenHCI_SetDevicePowerState,
  578. OpenHCI_ExternalGetCurrentFrame,
  579. #ifndef WIN98
  580. OpenHCI_ExternalGetConsumedBW,
  581. #endif
  582. NULL, // fast iso entry point
  583. deviceNameHandle);
  584. // A great little function that JD put together to do the PnP
  585. // magic.
  586. RtlFreeUnicodeString(&deviceNameUnicodeString);
  587. #ifdef DEBUG_LOG
  588. OHCI_LogInit();
  589. #endif
  590. }
  591. }
  592. OpenHCI_KdPrint((2, "'exit OpenHCI_PnPAddDevice (%x)\n", ntStatus));
  593. return ntStatus;
  594. }
  595. NTSTATUS
  596. OpenHCI_ExternalGetCurrentFrame(
  597. IN PDEVICE_OBJECT DeviceObject,
  598. IN PULONG CurrentFrame
  599. )
  600. /*++
  601. Routine Description:
  602. Arguments:
  603. DeviceObject - DeviceObject for this USB controller.
  604. Return Value:
  605. NT status code.
  606. --*/
  607. {
  608. *CurrentFrame = Get32BitFrameNumber(DeviceObject->DeviceExtension);
  609. return STATUS_SUCCESS;
  610. }
  611. ULONG
  612. OpenHCI_ExternalGetConsumedBW(
  613. IN PDEVICE_OBJECT DeviceObject
  614. )
  615. /*++
  616. Routine Description:
  617. Arguments:
  618. DeviceObject - DeviceObject for this USB controller.
  619. Return Value:
  620. NT status code.
  621. --*/
  622. {
  623. PHCD_DEVICE_DATA deviceData;
  624. deviceData = DeviceObject->DeviceExtension;
  625. // bits/ms
  626. return deviceData->MaxBandwidthInUse;
  627. }
  628. NTSTATUS
  629. OpenHCI_Shutdown(
  630. IN PDEVICE_OBJECT DeviceObject
  631. )
  632. /*++
  633. Routine Description:
  634. Stops an instance of a USB controller, by shutting down the
  635. controller and removing the resources.
  636. Arguments:
  637. DeviceObject - DeviceObject of the controller to stop
  638. TouchTheHardware - should we access the device.
  639. Return Value:
  640. NT status code.
  641. --*/
  642. {
  643. PHCD_DEVICE_DATA DeviceData =
  644. (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  645. PHC_OPERATIONAL_REGISTER hC;
  646. LOGENTRY(G, 'SHTd', DeviceData, 0, 0);
  647. OpenHCI_KdPrintDD(DeviceData,
  648. OHCI_DBG_SS_TRACE, ("'enter OpenHCI_ShutDown \n"));
  649. DeviceData->HcFlags |= HC_FLAG_SHUTDOWN;
  650. if (DeviceData->InterruptObject) {
  651. hC = DeviceData->HC;
  652. WRITE_REGISTER_ULONG(&hC->HcInterruptDisable, 0xFFFFFFFF);
  653. if (!KeSynchronizeExecution(DeviceData->InterruptObject,
  654. OpenHCI_StopController,
  655. DeviceData)) {
  656. return STATUS_UNSUCCESSFUL;
  657. }
  658. IoDisconnectInterrupt(DeviceData->InterruptObject);
  659. DeviceData->InterruptObject = NULL;
  660. #ifdef NTKERN
  661. // now we do any BIOS handback that is necessary
  662. OpenHCI_StartBIOS(DeviceObject);
  663. #endif
  664. }
  665. return STATUS_SUCCESS;
  666. }
  667. NTSTATUS
  668. OpenHCI_StopDevice(
  669. IN PDEVICE_OBJECT DeviceObject,
  670. IN BOOLEAN TouchTheHardware
  671. )
  672. /*++
  673. Routine Description:
  674. Stops an instance of a USB controller, by shutting down the
  675. controller and removing the resources.
  676. Arguments:
  677. DeviceObject - DeviceObject of the controller to stop
  678. TouchTheHardware - should we access the device.
  679. Return Value:
  680. NT status code.
  681. --*/
  682. {
  683. PHCD_DEVICE_DATA DeviceData =
  684. (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  685. PPAGE_LIST_ENTRY pageList;
  686. LOGENTRY(G, 'STPc', DeviceData, 0, 0);
  687. OpenHCI_KdPrintDD(DeviceData,
  688. OHCI_DBG_SS_TRACE, ("'enter OHCI_StopDevice \n"));
  689. if (!(DeviceData->HcFlags & HC_FLAG_DEVICE_STARTED)) {
  690. OpenHCI_KdPrintDD(DeviceData,
  691. OHCI_DBG_SS_INFO, ("'Already Stopped !!!\n"));
  692. return STATUS_SUCCESS;
  693. }
  694. // stop idle checking
  695. DeviceData->HcFlags |= HC_FLAG_DISABLE_IDLE_CHECK;
  696. // Stop our deadman timer
  697. //
  698. KeCancelTimer(&DeviceData->DeadmanTimer);
  699. if (TouchTheHardware && DeviceData->InterruptObject) {
  700. if (!KeSynchronizeExecution(DeviceData->InterruptObject,
  701. OpenHCI_StopController,
  702. DeviceData)) {
  703. return STATUS_UNSUCCESSFUL;
  704. }
  705. }
  706. if (DeviceData->InterruptObject) {
  707. IoDisconnectInterrupt(DeviceData->InterruptObject);
  708. DeviceData->InterruptObject = NULL;
  709. }
  710. OHCI_ASSERT(DeviceData->FrozenHcDoneHead == 0);
  711. //
  712. // free our common buffer pool
  713. //
  714. while (pageList = (PPAGE_LIST_ENTRY)ExInterlockedPopEntryList(
  715. (PSINGLE_LIST_ENTRY) &DeviceData->PageList,
  716. &DeviceData->DescriptorsSpin))
  717. {
  718. HalFreeCommonBuffer(DeviceData->AdapterObject,
  719. pageList->BufferSize,
  720. pageList->PhysAddr,
  721. pageList->VirtAddr,
  722. CacheCommon);
  723. ExFreePool(pageList);
  724. }
  725. OHCI_ASSERT(DeviceData->PageList == NULL);
  726. DeviceData->FreeDescriptorCount = 0;
  727. // no root hub address should be assigned
  728. OHCI_ASSERT(DeviceData->RootHubAddress == 0);
  729. // root hub should no longer be configured
  730. OHCI_ASSERT(DeviceData->RootHubConfig == 0);
  731. // Free the (HalGetAdapter call)
  732. (DeviceData->AdapterObject->DmaOperations->PutDmaAdapter)
  733. (DeviceData->AdapterObject);
  734. DeviceData->AdapterObject = NULL;
  735. // unmap device registers here
  736. OpenHCI_KdPrintDD(DeviceData,
  737. OHCI_DBG_SS_TRACE, ("'exit OHCI_StopDevice \n"));
  738. DeviceData->HcFlags &= ~HC_FLAG_DEVICE_STARTED;
  739. return STATUS_SUCCESS;
  740. }
  741. BOOLEAN
  742. OpenHCI_StopController(
  743. IN PVOID Context
  744. )
  745. /*++
  746. Routine Description:
  747. Stops an OpenHCI host controller by putting it into USBReset
  748. StopController is run from KeSynchronizeExecution
  749. Arguments:
  750. Context - DeviceData of the controller to stop
  751. Return Value:
  752. TRUE.
  753. --*/
  754. {
  755. #define DeviceData ((PHCD_DEVICE_DATA) Context)
  756. PHC_OPERATIONAL_REGISTER HC = DeviceData->HC;
  757. OpenHCI_KdPrintDD(DeviceData,
  758. OHCI_DBG_SS_TRACE, ("'enter OHCI_StopContr \n"));
  759. //
  760. // There is no need to call OpenHCI_HcControl_AND as we are
  761. // already in a KeSynch situation.
  762. //
  763. DeviceData->CurrentHcControl.ul &= ~(HcCtrl_PeriodicListEnable |
  764. HcCtrl_IsochronousEnable |
  765. HcCtrl_ControlListEnable |
  766. HcCtrl_BulkListEnable |
  767. HcCtrl_RemoteWakeupEnable);
  768. DeviceData->CurrentHcControl.HostControllerFunctionalState =
  769. HcHCFS_USBSuspend;
  770. WRITE_REGISTER_ULONG(&HC->HcControl.ul, DeviceData->CurrentHcControl.ul);
  771. WRITE_REGISTER_ULONG(&HC->HcInterruptDisable, 0xFFFFffff);
  772. WRITE_REGISTER_ULONG(&HC->HcInterruptStatus, 0xFFFFffff);
  773. OpenHCI_KdPrintDD(DeviceData,
  774. OHCI_DBG_SS_TRACE, ("'exit OHCI_StopContr \n"));
  775. return TRUE;
  776. #undef DeviceData
  777. }
  778. NTSTATUS
  779. OpenHCI_InitializeSchedule(
  780. IN PDEVICE_OBJECT DeviceObject
  781. )
  782. /*++
  783. Routine Description:
  784. Initializes the schedule structures for the HCD
  785. Arguments:
  786. DeviceObject - DeviceObject for this USB controller.
  787. Return Value:
  788. NT Status code.
  789. --*/
  790. {
  791. PHCD_DEVICE_DATA DeviceData;
  792. PHC_OPERATIONAL_REGISTER HC;
  793. PCHAR PageVirt;
  794. PHYSICAL_ADDRESS PagePhys;
  795. PHCCA_BLOCK HCCA;
  796. PHC_ENDPOINT_DESCRIPTOR HcED;
  797. PHC_ENDPOINT_DESCRIPTOR StaticED[ED_INTERRUPT_32ms];
  798. ULONG reserveLength;
  799. ULONG i, j, k;
  800. NTSTATUS ntStatus;
  801. // See section 5.2.7.2 of the OpenHCI spec
  802. //
  803. static UCHAR Balance[16] = {
  804. 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
  805. 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF
  806. };
  807. DeviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  808. HC = DeviceData->HC;
  809. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  810. ("'enter OpenHCI_InitializeSchedule\n"));
  811. #ifdef MAX_DEBUG
  812. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE, ("'HC = %x\n", HC));
  813. TRAP();
  814. #endif
  815. if (DeviceData->AdapterObject == NULL) {
  816. //
  817. // We need to get the AdapterObject for the host adapter
  818. //
  819. DEVICE_DESCRIPTION DeviceDescription;
  820. RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
  821. DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  822. DeviceDescription.Master = TRUE;
  823. DeviceDescription.ScatterGather = TRUE;
  824. DeviceDescription.Dma32BitAddresses = TRUE;
  825. DeviceDescription.InterfaceType = PCIBus;
  826. DeviceDescription.MaximumLength = (ULONG) -1;
  827. DeviceData->AdapterObject =
  828. IoGetDmaAdapter(DeviceData->RealPhysicalDeviceObject,
  829. &DeviceDescription,
  830. &DeviceData->NumberOfMapRegisters);
  831. if (DeviceData->AdapterObject == NULL) {
  832. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_ERROR,
  833. ("'exit OpenHCI_InitializeSchedule: Insufficient Resources\n"));
  834. return STATUS_INSUFFICIENT_RESOURCES;
  835. }
  836. }
  837. //
  838. // Allocate the first page of common buffer for TDs and EDs, reserving
  839. // space at the beginning of the page for the HCCA plus the statically
  840. // disabled ED for the interrupt polling tree
  841. //
  842. reserveLength = sizeof(HCCA_BLOCK) +
  843. sizeof(HC_ENDPOINT_DESCRIPTOR) * ED_INTERRUPT_32ms;
  844. ntStatus = OpenHCI_GrowDescriptorPool(DeviceData,
  845. reserveLength,
  846. &PageVirt,
  847. &PagePhys);
  848. if (!NT_SUCCESS(ntStatus))
  849. {
  850. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_ERROR,
  851. ("'exit OpenHCI_InitializeSchedule: No Memory\n"));
  852. return ntStatus;
  853. }
  854. //
  855. // In theory the Host Controller Communications Area (HCCA) has alignment
  856. // requirements that must be determined by examining the HcHCCA register;
  857. // but the best alignment we can provide is page alignment, so that is what
  858. // we do. Right now, we just set our virtual pointer, we'll get the
  859. // hardware's physical pointer set later.
  860. //
  861. DeviceData->HCCA = HCCA = (PHCCA_BLOCK) PageVirt;
  862. // Advance past the HCCA to the space reserved for the statically
  863. // disabled EDs for the interrupt polling tree.
  864. //
  865. PageVirt += sizeof(HCCA_BLOCK);
  866. PagePhys.LowPart += sizeof(HCCA_BLOCK);
  867. //
  868. // Allocate sataticly disabled EDs, and set head pointers for scheduling
  869. // lists
  870. //
  871. for (i = 0; i < ED_INTERRUPT_32ms; i++)
  872. {
  873. //
  874. // Carve next ED from our common memory (assume appropriate boundries)
  875. //
  876. HcED = (PHC_ENDPOINT_DESCRIPTOR) PageVirt;
  877. HcED->TailP = PagePhys.LowPart; // store self physical address in TailP
  878. HcED->HeadP = 0xDEADBEAF;
  879. DeviceData->EDList[i].PhysicalHead = &HcED->NextED;
  880. HcED->Control = HcEDControl_SKIP; // mark ED as disabled
  881. InitializeListHead(&DeviceData->EDList[i].Head);
  882. StaticED[i] = HcED;
  883. if (i > 0) {
  884. DeviceData->EDList[i].Next = (char) (i - 1) / 2;
  885. HcED->NextED = StaticED[(i - 1) / 2]->TailP;
  886. } else {
  887. DeviceData->EDList[i].Next = ED_EOF;
  888. HcED->NextED = 0;
  889. }
  890. // Advance pointers to next ED
  891. //
  892. PageVirt += sizeof(HC_ENDPOINT_DESCRIPTOR);
  893. PagePhys.LowPart += sizeof(HC_ENDPOINT_DESCRIPTOR);
  894. }
  895. //
  896. // Set head pointers for 32ms scheduling lists which start from HCCA
  897. //
  898. for (i = 0, j = ED_INTERRUPT_32ms;
  899. i < 32;
  900. i++, j++)
  901. {
  902. DeviceData->EDList[j].PhysicalHead = &HCCA->HccaInterruptTable[i];
  903. InitializeListHead(&DeviceData->EDList[j].Head);
  904. k = Balance[i & 0xF] + ED_INTERRUPT_16ms;
  905. DeviceData->EDList[j].Next = (char) k;
  906. HCCA->HccaInterruptTable[i] = StaticED[k]->TailP;
  907. }
  908. //
  909. // Setup EDList entries for Control & Bulk
  910. //
  911. InitializeListHead(&DeviceData->EDList[ED_CONTROL].Head);
  912. DeviceData->EDList[ED_CONTROL].PhysicalHead = &HC->HcControlHeadED;
  913. DeviceData->EDList[ED_CONTROL].Next = ED_EOF;
  914. DeviceData->EDList[ED_CONTROL].HcRegister = TRUE;
  915. InitializeListHead(&DeviceData->EDList[ED_BULK].Head);
  916. DeviceData->EDList[ED_BULK].PhysicalHead = &HC->HcBulkHeadED;
  917. DeviceData->EDList[ED_BULK].Next = ED_EOF;
  918. DeviceData->EDList[ED_BULK].HcRegister = TRUE;
  919. // our list of active endpoints
  920. InitializeListHead(&DeviceData->ActiveEndpointList);
  921. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  922. ("'exit OpenHCI_InitializeSchedule: Success\n"));
  923. return STATUS_SUCCESS;
  924. }
  925. NTSTATUS
  926. OpenHCI_StopBIOS(
  927. IN PDEVICE_OBJECT DeviceObject
  928. )
  929. /*++
  930. Routine Description:
  931. Takes control from legacy BIOS.
  932. Arguments:
  933. DeviceObject - DeviceObject for this USB controller.
  934. Return Value:
  935. --*/
  936. {
  937. PHCD_DEVICE_DATA DeviceData;
  938. PHC_OPERATIONAL_REGISTER HC;
  939. LARGE_INTEGER finishTime;
  940. LARGE_INTEGER currentTime;
  941. ULONG HcControl;
  942. DeviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  943. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  944. ("'OpenHCI_StopBIOS\n"));
  945. HC = DeviceData->HC;
  946. //
  947. // Check to see if a System Management Mode driver owns the HC
  948. //
  949. HcControl = READ_REGISTER_ULONG(&HC->HcControl.ul);
  950. if (HcControl & HcCtrl_InterruptRouting)
  951. {
  952. OpenHCI_KdPrint((1, "'OpenHCI detected Legacy BIOS\n"));
  953. if ((HcControl == HcCtrl_InterruptRouting) &&
  954. (READ_REGISTER_ULONG(&HC->HcInterruptEnable) == 0))
  955. {
  956. // Major assumption: If HcCtrl_InterruptRouting is set but
  957. // no other bits in HcControl are set, i.e. HCFS==UsbReset,
  958. // and no interrupts are enabled, then assume that the BIOS
  959. // is not actually using the host controller. In this case
  960. // just clear the erroneously set HcCtrl_InterruptRouting.
  961. //
  962. // This assumption appears to be correct on a Portege 3010CT,
  963. // where HcCtrl_InterruptRouting is set during a Resume from
  964. // Standby, but the BIOS doesn't actually appear to be using
  965. // the host controller. If we were to continue on and set
  966. // HcCmd_OwnershipChangeRequest, the BIOS appears to wake up
  967. // and try to take ownership of the host controller instead of
  968. // giving it up.
  969. //
  970. OpenHCI_KdPrint((0, "'OpenHCI_StopBIOS: HcCtrl_InterruptRouting erroneously set\n"));
  971. WRITE_REGISTER_ULONG(&HC->HcControl.ul, 0);
  972. }
  973. else
  974. {
  975. //
  976. // A SMM driver does own the HC, it will take some time to
  977. // get the SMM driver to relinquish control of the HC. We
  978. // will ping the SMM driver, and then wait repeatedly until
  979. // the SMM driver has relinquished control of the HC.
  980. //
  981. // THIS CODE ONLY WORKS IF WE ARE EXECUTING IN THE CONTEXT
  982. // OF A SYSTEM THREAD.
  983. //
  984. WRITE_REGISTER_ULONG(&HC->HcCommandStatus.ul,
  985. HcCmd_OwnershipChangeRequest);
  986. KeQuerySystemTime(&finishTime); // get current time
  987. finishTime.QuadPart += 5000000; // figure when we quit (.5 seconds
  988. // later)
  989. //
  990. // We told the SMM driver we want the HC, now all we can do is wait
  991. // for the SMM driver to be done with the HC.
  992. //
  993. while (READ_REGISTER_ULONG(&HC->HcControl.ul) &
  994. HcCtrl_InterruptRouting)
  995. {
  996. KeQuerySystemTime(&currentTime);
  997. if (currentTime.QuadPart >= finishTime.QuadPart)
  998. {
  999. OpenHCI_KdPrint((0, "'OpenHCI_StopBIOS: SMM has not relinquised HC -- this is a bug\n"));
  1000. return STATUS_UNSUCCESSFUL;
  1001. }
  1002. OHCI_WAIT(1); // wait 1 ms
  1003. }
  1004. }
  1005. DeviceData->HcFlags |= HC_FLAG_LEGACY_BIOS_DETECTED;
  1006. }
  1007. return STATUS_SUCCESS;
  1008. }
  1009. NTSTATUS
  1010. OpenHCI_StartBIOS(
  1011. IN PDEVICE_OBJECT DeviceObject
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Returns control to legacy BIOS.
  1016. Arguments:
  1017. DeviceObject - DeviceObject for this USB controller.
  1018. Return Value:
  1019. --*/
  1020. {
  1021. PHCD_DEVICE_DATA DeviceData;
  1022. PHC_OPERATIONAL_REGISTER HC;
  1023. LARGE_INTEGER finishTime, currentTime;
  1024. DeviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  1025. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  1026. ("'enter OpenHCI_StartBIOS\n"));
  1027. HC = DeviceData->HC;
  1028. if (DeviceData->HcFlags & HC_FLAG_LEGACY_BIOS_DETECTED) {
  1029. // hand back control
  1030. WRITE_REGISTER_ULONG(&HC->HcCommandStatus.ul, HcCmd_OwnershipChangeRequest);
  1031. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable,
  1032. HcInt_OwnershipChange);
  1033. // enable interrupts
  1034. WRITE_REGISTER_ULONG(&DeviceData->HC->HcInterruptEnable,
  1035. HcInt_MasterInterruptEnable);
  1036. KeQuerySystemTime(&finishTime); // get current time
  1037. finishTime.QuadPart += 5000000; // figure when we quit (.5 seconds
  1038. // later)
  1039. //
  1040. // Wait for SMM driver to take control back
  1041. //
  1042. while (READ_REGISTER_ULONG(&HC->HcControl.ul) & HcCtrl_InterruptRouting) {
  1043. KeQuerySystemTime(&currentTime);
  1044. if (currentTime.QuadPart >= finishTime.QuadPart) {
  1045. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_ERROR,
  1046. ("'OpenHCI_InitializeHardware: SMM has not relinquised HC.\n"));
  1047. return STATUS_UNSUCCESSFUL;
  1048. }
  1049. OHCI_WAIT(1); // wait 1 ms
  1050. }
  1051. }
  1052. return STATUS_SUCCESS;
  1053. }
  1054. NTSTATUS
  1055. OpenHCI_InitializeHardware(
  1056. IN PDEVICE_OBJECT DeviceObject
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. Initializes the hardware registers in the host controller.
  1061. Arguments:
  1062. DeviceObject - DeviceObject for this USB controller.
  1063. Return Value:
  1064. NT Status code.
  1065. Note: This routine is written assuming that it is called in the
  1066. context of a system thread.
  1067. --*/
  1068. {
  1069. PHCD_DEVICE_DATA DeviceData;
  1070. PHC_OPERATIONAL_REGISTER HC;
  1071. HC_RH_DESCRIPTOR_A descA;
  1072. ULONG reg;
  1073. NTSTATUS ntStatus;
  1074. ULONG sofModifyValue;
  1075. DeviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  1076. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  1077. ("'enter OpenHCI_InitializeHardware\n"));
  1078. HC = DeviceData->HC;
  1079. ntStatus = OpenHCI_StopBIOS(DeviceObject);
  1080. if (!NT_SUCCESS(ntStatus)) {
  1081. return ntStatus;
  1082. }
  1083. //
  1084. // If we made it here then we now own the HC and can initialize it.
  1085. //
  1086. //
  1087. // Get current frame interval (could account for a known clock error)
  1088. //
  1089. DeviceData->OriginalInterval.ul = READ_REGISTER_ULONG(&HC->HcFmInterval.ul);
  1090. // If FrameInterval is outside the range of the nominal value of 11999
  1091. // +/- 1% then assume the value is bogus and set it to the nomial value.
  1092. //
  1093. if ((DeviceData->OriginalInterval.FrameInterval < 11879) ||
  1094. (DeviceData->OriginalInterval.FrameInterval > 12119))
  1095. {
  1096. DeviceData->OriginalInterval.FrameInterval = 11999; // 0x2EDF
  1097. }
  1098. reg = READ_REGISTER_ULONG(&HC->HcControl.ul);
  1099. // Always enable for now
  1100. //
  1101. DeviceData->HcFlags |= HC_FLAG_REMOTE_WAKEUP_CONNECTED;
  1102. if (reg & HcCtrl_RemoteWakeupConnected) {
  1103. DeviceData->HcFlags |= HC_FLAG_REMOTE_WAKEUP_CONNECTED;
  1104. OpenHCI_KdPrint((1, "'controller is wakeup enabled.\n"));
  1105. }
  1106. //
  1107. // Set largest data packet (in case BIOS did not set)
  1108. //
  1109. DeviceData->OriginalInterval.FSLargestDataPacket =
  1110. ((DeviceData->OriginalInterval.FrameInterval - MAXIMUM_OVERHEAD) * 6) / 7;
  1111. DeviceData->OriginalInterval.FrameIntervalToggle ^= 1;
  1112. //
  1113. // Reset the controller
  1114. //
  1115. WRITE_REGISTER_ULONG(&HC->HcCommandStatus.ul, HcCmd_HostControllerReset);
  1116. //
  1117. // Wait at least 10 microseconds for the reset to complete
  1118. //
  1119. KeStallExecutionProcessor(20);
  1120. //
  1121. // Setup our copy of HcControl, and take HC to USBReset state
  1122. //
  1123. DeviceData->CurrentHcControl.ul
  1124. = (READ_REGISTER_ULONG(&HC->HcControl.ul) & ~HcCtrl_HCFS_MASK)
  1125. | HcCtrl_HCFS_USBReset;
  1126. WRITE_REGISTER_ULONG(&HC->HcControl.ul, DeviceData->CurrentHcControl.ul);
  1127. //
  1128. // Restore original frame interval
  1129. //
  1130. // check for a registry based SOF modify Value
  1131. sofModifyValue = DeviceData->OriginalInterval.FrameInterval;
  1132. OpenHCI_GetSOFRegModifyValue(DeviceObject,
  1133. &sofModifyValue);
  1134. DeviceData->OriginalInterval.FrameInterval =
  1135. sofModifyValue;
  1136. do {
  1137. WRITE_REGISTER_ULONG(&HC->HcFmInterval.ul, DeviceData->OriginalInterval.ul);
  1138. reg = READ_REGISTER_ULONG(&HC->HcFmInterval.ul);
  1139. OpenHCI_KdPrint((2, "'fi reg = %x\n", reg));
  1140. } while (reg != DeviceData->OriginalInterval.ul);
  1141. OpenHCI_KdPrint((2, "'fi = %x\n", DeviceData->OriginalInterval.ul));
  1142. OpenHCI_GetRegFlags(DeviceObject,
  1143. &sofModifyValue);
  1144. //
  1145. // Set the HcPeriodicStart register to 90% of the FrameInterval
  1146. //
  1147. WRITE_REGISTER_ULONG(&HC->HcPeriodicStart,
  1148. (DeviceData->OriginalInterval.FrameInterval * 9 + 5)
  1149. / 10);
  1150. descA.ul = READ_REGISTER_ULONG(&HC->HcRhDescriptorA.ul);
  1151. DeviceData->NumberOfPorts = (UCHAR) descA.NumberDownstreamPorts;
  1152. // Maximum number of ports supported by the OpenHCI specification is 15
  1153. //
  1154. ASSERT(DeviceData->NumberOfPorts);
  1155. ASSERT(DeviceData->NumberOfPorts <= 15);
  1156. //
  1157. // Enable some interrupts, but don't hit the master enable yet, wait
  1158. // until the interrupt is connected.
  1159. //
  1160. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable,
  1161. HcInt_OwnershipChange |
  1162. HcInt_SchedulingOverrun |
  1163. HcInt_WritebackDoneHead |
  1164. HcInt_FrameNumberOverflow |
  1165. HcInt_ResumeDetected |
  1166. HcInt_UnrecoverableError);
  1167. //
  1168. // Tell the HC where the HCCA is, we know that OpenHCI_InitializeSchedule
  1169. // has
  1170. // just run and that the only entry in the PageList begins with the HCCA
  1171. // so we just pick it up and use it without any checks.
  1172. //
  1173. WRITE_REGISTER_ULONG(&HC->HcHCCA, DeviceData->PageList->PhysAddr.LowPart);
  1174. // **
  1175. //
  1176. // Due to a problem with the CMD controller we need to ensure that an ED
  1177. // list always points to a valid ED so we will insert a dummy ED on each
  1178. // list here.
  1179. //
  1180. //
  1181. // Reserve the two dummy EDs+TDs
  1182. //
  1183. OpenHCI_ReserveDescriptors(DeviceData, 4);
  1184. //
  1185. // Insert the two dummy EDs+TDs
  1186. //
  1187. InsertEDForEndpoint(DeviceData, NULL, ED_CONTROL, NULL);
  1188. InsertEDForEndpoint(DeviceData, NULL, ED_BULK, NULL);
  1189. // Bulk and control Lists initialized with DUMMY ED
  1190. {
  1191. // WRITE_REGISTER_ULONG(&HC->HcControlHeadED, 0);
  1192. WRITE_REGISTER_ULONG(&HC->HcControlCurrentED, 0);
  1193. // WRITE_REGISTER_ULONG(&HC->HcBulkHeadED, 0);
  1194. WRITE_REGISTER_ULONG(&HC->HcBulkCurrentED, 0);
  1195. }
  1196. /**/
  1197. if (DeviceData->HcFlags & HC_FLAG_USE_HYDRA_HACK) {
  1198. ULONG len;
  1199. OpenHCI_KdPrint((1, "'Initialize Hs/Ls fix\n"));
  1200. OpenHCI_InsertMagicEDs(DeviceObject);
  1201. len = PENDING_TD_LIST_SIZE * sizeof(PVOID);
  1202. DeviceData->LastHccaDoneHead = 0;
  1203. }
  1204. /**/
  1205. //
  1206. // Wait USB specified time for reset signaling.
  1207. //
  1208. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  1209. ("'exit OpenHCI_InitializeHardware -- (STATUS_SUCCESS)\n"));
  1210. return STATUS_SUCCESS;
  1211. }
  1212. BOOLEAN
  1213. OpenHCI_IdleController(
  1214. IN PVOID Context
  1215. )
  1216. /*++
  1217. Routine Description:
  1218. Starts the USB host controller executing the schedule.
  1219. Start Controller is called in by KeSynchronizeExecution.
  1220. Arguments:
  1221. Context - DeviceData for this USB controller.
  1222. Return Value:
  1223. TRUE
  1224. --*/
  1225. {
  1226. #define DeviceData ((PHCD_DEVICE_DATA) Context)
  1227. PHC_OPERATIONAL_REGISTER HC;
  1228. OpenHCI_KdPrint((1, "'HC-->suspend state\n"));
  1229. HC = DeviceData->HC;
  1230. //
  1231. // put the controller in 'suspend'
  1232. //
  1233. #if DBG
  1234. // double check that the ports are idle
  1235. OHCI_ASSERT(OpenHCI_RhPortsIdle(DeviceData));
  1236. #endif
  1237. // disable some interrupts while idle
  1238. // WRITE_REGISTER_ULONG(&HC->HcInterruptDisable,
  1239. // HcInt_StartOfFrame |
  1240. // HcInt_OwnershipChange |
  1241. // HcInt_SchedulingOverrun |
  1242. // HcInt_WritebackDoneHead |
  1243. // HcInt_FrameNumberOverflow |
  1244. // HcInt_UnrecoverableError);
  1245. DeviceData->CurrentHcControl.ul &= ~(HcCtrl_HCFS_MASK);
  1246. DeviceData->CurrentHcControl.ul |= HcCtrl_HCFS_USBSuspend;
  1247. if (DeviceData->HcFlags & HC_FLAG_REMOTE_WAKEUP_CONNECTED) {
  1248. DeviceData->CurrentHcControl.ul |=
  1249. (HcCtrl_RemoteWakeupConnected | HcCtrl_RemoteWakeupEnable);
  1250. OpenHCI_KdPrint((1, "'enable control reg for wakeup\n"));
  1251. }
  1252. WRITE_REGISTER_ULONG(&HC->HcControl.ul, DeviceData->CurrentHcControl.ul);
  1253. //
  1254. // we are already in a KeSynch routine, so these last two accesses to
  1255. // CurrentHcControl need no additional deadlocks (I mean protection).
  1256. //
  1257. // do a global power on for all ports, if the root hub is switched
  1258. // this command should have no effect
  1259. return TRUE;
  1260. }
  1261. BOOLEAN
  1262. OpenHCI_StartController(
  1263. IN PVOID Context
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. Starts the USB host controller executing the schedule.
  1268. Start Controller is called in by KeSynchronizeExecution.
  1269. Arguments:
  1270. Context - DeviceData for this USB controller.
  1271. Return Value:
  1272. TRUE
  1273. --*/
  1274. {
  1275. #define DeviceData ((PHCD_DEVICE_DATA) Context)
  1276. PHC_OPERATIONAL_REGISTER HC;
  1277. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE, ("'enter OHCI_StartContr \n"));
  1278. HC = DeviceData->HC;
  1279. //
  1280. // Start the controller schedule
  1281. //
  1282. // When the HC is in the operational state, HccaPad1 should be set to
  1283. // zero every time the HC updates HccaFrameNumer. Preset HccaPad1 to zero
  1284. // before entering the operational state. OpenHCI_DeadmanDPC() should
  1285. // always find a zero value in HccaPad1 when the HC is in the operational
  1286. // state.
  1287. //
  1288. DeviceData->HCCA->HccaPad1 = 0;
  1289. DeviceData->CurrentHcControl.ul &= ~(HcCtrl_HCFS_MASK);
  1290. DeviceData->CurrentHcControl.ul |= HcCtrl_HCFS_USBOperational;
  1291. if (DeviceData->HcFlags & HC_FLAG_REMOTE_WAKEUP_CONNECTED) {
  1292. DeviceData->CurrentHcControl.ul |=
  1293. (HcCtrl_RemoteWakeupConnected | HcCtrl_RemoteWakeupEnable);
  1294. OpenHCI_KdPrint((1, "'enable control reg for wakeup\n"));
  1295. }
  1296. DeviceData->ListEnablesAtNextSOF.ul =
  1297. HcCtrl_PeriodicListEnable
  1298. | HcCtrl_ControlListEnable
  1299. | HcCtrl_BulkListEnable
  1300. | HcCtrl_IsochronousEnable;
  1301. WRITE_REGISTER_ULONG(&HC->HcControl.ul, DeviceData->CurrentHcControl.ul);
  1302. //
  1303. // we are already in a KeSynch routine, so these last two accesses to
  1304. // CurrentHcControl need no additional deadlocks (I mean protection).
  1305. //
  1306. // do a global power on for all ports, if the root hub is switched
  1307. // this command should have no effect
  1308. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable,
  1309. HcInt_StartOfFrame |
  1310. HcInt_OwnershipChange |
  1311. HcInt_SchedulingOverrun |
  1312. HcInt_WritebackDoneHead |
  1313. HcInt_FrameNumberOverflow |
  1314. HcInt_ResumeDetected |
  1315. HcInt_UnrecoverableError);
  1316. #if DBG
  1317. {
  1318. ULONG reg;
  1319. reg = READ_REGISTER_ULONG(&HC->HcRhStatus);
  1320. OpenHCI_KdPrint((1, "rhStatus reg = %x\n", reg));
  1321. if (reg & HcRhS_DeviceRemoteWakeupEnable) {
  1322. OpenHCI_KdPrint((1, "Connect changes are wakeup events\n"));
  1323. }
  1324. }
  1325. #endif
  1326. WRITE_REGISTER_ULONG(&HC->HcRhStatus, HcRhS_SetGlobalPower |
  1327. HcRhS_SetRemoteWakeupEnable);
  1328. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE, ("'exit OHCI_StartContr \n"));
  1329. return TRUE;
  1330. #undef DeviceData
  1331. }
  1332. NTSTATUS
  1333. OpenHCI_Suspend(
  1334. PDEVICE_OBJECT Device
  1335. )
  1336. /*++
  1337. jd
  1338. Routine Description:
  1339. Put the HC in the global suspeneded state as a result of a
  1340. D1 message to the root hub PDO, the hub driver has already
  1341. suspended or powered off the ports if necessary.
  1342. This function saves whatever state is necessary to recover
  1343. from the off state as well
  1344. --*/
  1345. {
  1346. NTSTATUS ntStatus = STATUS_SUCCESS;
  1347. KeSynch_HcControl context;
  1348. PHCD_DEVICE_DATA deviceData;
  1349. PHC_OPERATIONAL_REGISTER HC;
  1350. KIRQL oldIrql;
  1351. deviceData = (PHCD_DEVICE_DATA) ((PDEVICE_OBJECT) Device)->DeviceExtension;
  1352. OpenHCI_KdPrint((1, "'suspending host controller (Root Hub)\n"));
  1353. LOGENTRY(G, 'HsuI', deviceData, 0, 0);
  1354. KeAcquireSpinLock(&deviceData->HcFlagSpin, &oldIrql);
  1355. deviceData->HcFlags |= HC_FLAG_DISABLE_IDLE_CHECK;
  1356. // ounce we resume we will have to re-enter idle mode
  1357. deviceData->HcFlags &= ~HC_FLAG_IDLE;
  1358. KeReleaseSpinLock(&deviceData->HcFlagSpin, oldIrql);
  1359. HC = deviceData->HC;
  1360. OpenHCI_KdPrint((2, "'Enter Suspend HC:%x\n", HC));
  1361. //
  1362. // Disable the enpoint lists.
  1363. //
  1364. context.NewHcControl.ul = (ULONG) ~ (HcCtrl_PeriodicListEnable |
  1365. HcCtrl_IsochronousEnable |
  1366. HcCtrl_ControlListEnable |
  1367. HcCtrl_BulkListEnable);
  1368. context.DeviceData = deviceData;
  1369. KeSynchronizeExecution(deviceData->InterruptObject,
  1370. OpenHCI_HcControl_AND,
  1371. &context);
  1372. OHCI_WAIT(5);
  1373. // is it only necessary to enter the suspend state to detect remote
  1374. // wakeup requests?
  1375. context.NewHcControl.ul = HcCtrl_HCFS_USBSuspend;
  1376. context.DeviceData = deviceData;
  1377. KeSynchronizeExecution(deviceData->InterruptObject,
  1378. OpenHCI_HcControl_SetHCFS,
  1379. &context);
  1380. OpenHCI_KdPrint((2, "'Exit and Suspended\n"));
  1381. return ntStatus;
  1382. }
  1383. NTSTATUS
  1384. OpenHCI_Resume(
  1385. PDEVICE_OBJECT DeviceObject,
  1386. BOOLEAN LostPower
  1387. )
  1388. /*++
  1389. Put the device in the working state.
  1390. This function is called when the root hub is transitioned
  1391. to the working state
  1392. NOTE:
  1393. We must stay in suspend for at least 5 miliseconds.
  1394. We must stay in resume (once we go to resume) for at least 20 ms.
  1395. --*/
  1396. {
  1397. NTSTATUS ntStatus = STATUS_SUCCESS;
  1398. PHCD_DEVICE_DATA DeviceData;
  1399. PHC_OPERATIONAL_REGISTER HC;
  1400. ULONG i;
  1401. KIRQL oldIrql;
  1402. DeviceData = (PHCD_DEVICE_DATA) ((PDEVICE_OBJECT) DeviceObject)->DeviceExtension;
  1403. HC = DeviceData->HC;
  1404. OpenHCI_KdPrint((2, "'Enter Resume HC:%x\n", HC));
  1405. // be sure th controller stays in suspend for at leaset 5 ms
  1406. // time is in units of 100-nanoseconds. Neg vals are relative time.
  1407. OHCI_WAIT(5);
  1408. // resume signalling is driven by the hub driver
  1409. // so we will just reset here
  1410. //
  1411. // Start the resume signalling to all down stream ports;
  1412. //
  1413. // context.NewHcControl.ul = HcCtrl_HCFS_USBResume;
  1414. // context.DeviceData = DeviceData;
  1415. // KeSynchronizeExecution(DeviceData->InterruptObject,
  1416. // OpenHCI_HcControl_SetHCFS,
  1417. // &context);
  1418. if (READ_REGISTER_ULONG(&HC->HcRevision.ul) == 0xFFFFFFFF)
  1419. {
  1420. OpenHCI_KdPrint((0, "'Resume HC, controller not there!\n"));
  1421. // The return value of OpenHCI_Resume() is propagated back
  1422. // up to USBHUB, but if we we don't return success here,
  1423. // USBH_PowerIrpCompletion() won't handle it correctly,
  1424. // causing a hang.
  1425. //
  1426. // Just return success for now until USBHUB can handle an error
  1427. // being propagate back up.
  1428. //
  1429. return STATUS_SUCCESS;
  1430. }
  1431. //
  1432. // start the controller
  1433. //
  1434. if (!KeSynchronizeExecution(DeviceData->InterruptObject,
  1435. OpenHCI_StartController,
  1436. DeviceData)) {
  1437. TRAP(); //something has gone terribly wrong
  1438. }
  1439. //
  1440. // Fire up the HC
  1441. //
  1442. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_NOISE, ("'Set Master Int Enable.\n"));
  1443. WRITE_REGISTER_ULONG(&DeviceData->HC->HcInterruptEnable, HcInt_MasterInterruptEnable);
  1444. WRITE_REGISTER_ULONG(&DeviceData->HC->HcInterruptStatus, HcInt_StartOfFrame);
  1445. WRITE_REGISTER_ULONG(&DeviceData->HC->HcInterruptEnable, HcInt_StartOfFrame);
  1446. if (LostPower) {
  1447. // if power was lost we need to turn the ports back on
  1448. for (i = 0; i < DeviceData->NumberOfPorts; i++) {
  1449. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[i], HcRhPS_SetPortPower);
  1450. }
  1451. }
  1452. // enable idle checking
  1453. KeAcquireSpinLock(&DeviceData->HcFlagSpin, &oldIrql);
  1454. DeviceData->HcFlags &= ~HC_FLAG_DISABLE_IDLE_CHECK;
  1455. KeReleaseSpinLock(&DeviceData->HcFlagSpin, oldIrql);
  1456. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_PNP_TRACE, ("'Exit Resume\n"));
  1457. return ntStatus;
  1458. }
  1459. NTSTATUS
  1460. OpenHCI_SaveHCstate(
  1461. PHCD_DEVICE_DATA DeviceData
  1462. )
  1463. /*++
  1464. Save the the HC state in case we lose power
  1465. --*/
  1466. {
  1467. NTSTATUS ntStatus = STATUS_SUCCESS;
  1468. PHC_OPERATIONAL_REGISTER HC;
  1469. OpenHCI_KdPrint((1, "'Save HC state\n"));
  1470. LOGENTRY(G, 'SAVs', 0, 0, 0);
  1471. HC = DeviceData->HC;
  1472. DeviceData->BulkSav = READ_REGISTER_ULONG(&HC->HcBulkHeadED);
  1473. DeviceData->ControlSav = READ_REGISTER_ULONG(&HC->HcControlHeadED);
  1474. DeviceData->HcHCCASav = READ_REGISTER_ULONG(&HC->HcHCCA);
  1475. return ntStatus;
  1476. }
  1477. NTSTATUS
  1478. OpenHCI_RestoreHCstate(
  1479. PHCD_DEVICE_DATA DeviceData,
  1480. PBOOLEAN LostPower
  1481. )
  1482. /*++
  1483. Restore the HC state in case we lost power
  1484. --*/
  1485. {
  1486. PHC_OPERATIONAL_REGISTER HC;
  1487. ULONG hcca;
  1488. NTSTATUS ntStatus = STATUS_SUCCESS;
  1489. ULONG i;
  1490. ULONG ulRegVal;
  1491. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  1492. ("'enter OpenHCI_RestoreHardware\n"));
  1493. *LostPower = FALSE;
  1494. HC = DeviceData->HC;
  1495. DeviceData->FrameHighPart = 0;
  1496. LOGENTRY(G, 'RESs', 0, 0, 0);
  1497. if (READ_REGISTER_ULONG(&HC->HcRevision.ul) == 0xFFFFFFFF)
  1498. {
  1499. OpenHCI_KdPrint((0, "'Restore HC state, controller not there!\n"));
  1500. // Nothing currently checks the return value of OpenHCI_RestoreHCstate()
  1501. // Just return success for now.
  1502. //
  1503. return STATUS_SUCCESS;
  1504. }
  1505. hcca = READ_REGISTER_ULONG(&HC->HcHCCA);
  1506. if (hcca == DeviceData->HcHCCASav &&
  1507. !(DeviceData->HcFlags & HC_FLAG_LOST_POWER)) {
  1508. return STATUS_SUCCESS;
  1509. }
  1510. DeviceData->HcFlags &= ~HC_FLAG_LOST_POWER;
  1511. *LostPower = TRUE;
  1512. OpenHCI_KdPrint((1, "'Restore HC state\n"));
  1513. //
  1514. // Stop the legacy BIOS if it is active
  1515. //
  1516. ntStatus = OpenHCI_StopBIOS(DeviceData->DeviceObject);
  1517. if (!NT_SUCCESS(ntStatus)) {
  1518. return ntStatus;
  1519. }
  1520. //
  1521. // Disable/clear all interrupts in case a legacy BIOS left some enabled.
  1522. //
  1523. WRITE_REGISTER_ULONG(&HC->HcInterruptDisable, 0xFFFFFFFF);
  1524. //
  1525. // Take the host controller to the UsbSuspend state
  1526. //
  1527. WRITE_REGISTER_ULONG(&HC->HcCommandStatus.ul, HcCmd_HostControllerReset);
  1528. KeStallExecutionProcessor(10);
  1529. //
  1530. // Take the host controller to the UsbReset state
  1531. //
  1532. WRITE_REGISTER_ULONG(&HC->HcControl.ul, 0);
  1533. //
  1534. // Restore original frame interval. There is something funky about
  1535. // this register. Sometimes writing a value to it does not always
  1536. // take. If it doesn't take and FSLargestDataPacket ends up being
  1537. // zero, no transfers will work and SchedulingOverrun will occur.
  1538. //
  1539. for (i = 0; i < 10; i++)
  1540. {
  1541. WRITE_REGISTER_ULONG(&HC->HcFmInterval.ul,
  1542. DeviceData->OriginalInterval.ul);
  1543. ulRegVal = READ_REGISTER_ULONG(&HC->HcFmInterval.ul);
  1544. if (ulRegVal == DeviceData->OriginalInterval.ul)
  1545. {
  1546. break;
  1547. }
  1548. KeStallExecutionProcessor(5);
  1549. }
  1550. LOGENTRY(G, 'HcFm', ulRegVal, DeviceData->OriginalInterval.ul, i);
  1551. //
  1552. // Set the HcPeriodicStart register to 90% of the FrameInterval
  1553. //
  1554. WRITE_REGISTER_ULONG(&HC->HcPeriodicStart,
  1555. (DeviceData->OriginalInterval.FrameInterval * 9 + 5)
  1556. / 10);
  1557. //
  1558. // Enable some interrupts, but don't hit the master enable yet, wait
  1559. // until the interrupt is connected.
  1560. //
  1561. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable,
  1562. HcInt_OwnershipChange |
  1563. HcInt_SchedulingOverrun |
  1564. HcInt_WritebackDoneHead |
  1565. HcInt_FrameNumberOverflow |
  1566. HcInt_ResumeDetected |
  1567. HcInt_UnrecoverableError);
  1568. //
  1569. // Tell the HC where the HCCA is, we know that OpenHCI_InitializeSchedule
  1570. // has
  1571. // just run and that the only entry in the PageList begins with the HCCA
  1572. // so we just pick it up and use it without any checks.
  1573. //
  1574. //WRITE_REGISTER_ULONG(&HC->HcHCCA, DeviceData->PageList->PhysAddr.LowPart);
  1575. WRITE_REGISTER_ULONG(&HC->HcHCCA, DeviceData->HcHCCASav);
  1576. // **
  1577. //
  1578. // Due to a problem with the CMD controller we need to ensure that an ED
  1579. // list always points to a valid ED so we will insert a dummy ED on each
  1580. // list here.
  1581. //
  1582. //InsertEDForEndpoint(DeviceData, NULL, ED_CONTROL);
  1583. //InsertEDForEndpoint(DeviceData, NULL, ED_BULK);
  1584. WRITE_REGISTER_ULONG(&HC->HcControlHeadED, DeviceData->ControlSav);
  1585. WRITE_REGISTER_ULONG(&HC->HcBulkHeadED, DeviceData->BulkSav);
  1586. // Bulk and control Lists initialized with DUMMY ED
  1587. {
  1588. // WRITE_REGISTER_ULONG(&HC->HcControlHeadED, 0);
  1589. WRITE_REGISTER_ULONG(&HC->HcControlCurrentED, 0);
  1590. // WRITE_REGISTER_ULONG(&HC->HcBulkHeadED, 0);
  1591. WRITE_REGISTER_ULONG(&HC->HcBulkCurrentED, 0);
  1592. }
  1593. //
  1594. // Wait USB specified time for reset signaling.
  1595. //
  1596. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  1597. ("'exit OpenHCI_RestoreHardware -- (STATUS_SUCCESS)\n"));
  1598. return STATUS_SUCCESS;
  1599. }
  1600. NTSTATUS
  1601. OpenHCI_SetDevicePowerState(
  1602. IN PDEVICE_OBJECT DeviceObject,
  1603. IN PIRP Irp,
  1604. IN DEVICE_POWER_STATE DeviceState
  1605. )
  1606. /*++
  1607. Routine Description:
  1608. Arguments:
  1609. DeviceObject - Pointer to the device object for the class device.
  1610. Irp - Irp completed.
  1611. DeviceState - Device specific power state to set the device in to.
  1612. Return Value:
  1613. --*/
  1614. {
  1615. NTSTATUS ntStatus = STATUS_SUCCESS;
  1616. PHCD_DEVICE_DATA deviceData;
  1617. BOOLEAN hookIt = FALSE;
  1618. PIO_STACK_LOCATION irpStack;
  1619. PHC_OPERATIONAL_REGISTER HC;
  1620. PUSBD_EXTENSION usbdExtension;
  1621. PDEVICE_CAPABILITIES hcDeviceCapabilities;
  1622. BOOLEAN bIsSuspend;
  1623. deviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  1624. HC = deviceData->HC;
  1625. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1626. if (irpStack->Parameters.Power.Type ==
  1627. SystemPowerState) {
  1628. switch (irpStack->Parameters.Power.State.SystemState) {
  1629. case PowerSystemSleeping1:
  1630. case PowerSystemSleeping2:
  1631. case PowerSystemSleeping3:
  1632. // suspend coming thru
  1633. OpenHCI_KdPrint((1, "'Shutdown (Suspend) Host Controller\n"));
  1634. deviceData->HcFlags |= HC_FLAG_SUSPEND_NEXT_D3;
  1635. ntStatus = STATUS_SUCCESS;
  1636. break;
  1637. case PowerSystemShutdown:
  1638. //
  1639. // this is a shutdown request
  1640. //
  1641. OpenHCI_KdPrint((1, "'Shutdown Host Controller\n"));
  1642. ntStatus = OpenHCI_Shutdown(DeviceObject);
  1643. break;
  1644. default:
  1645. // should not get here
  1646. TRAP();
  1647. break;
  1648. }
  1649. } else {
  1650. bIsSuspend = (deviceData->HcFlags & HC_FLAG_SUSPEND_NEXT_D3) ? 1:0;
  1651. deviceData->HcFlags &= ~HC_FLAG_SUSPEND_NEXT_D3;
  1652. switch (DeviceState) {
  1653. case PowerDeviceD3:
  1654. //
  1655. // Request for HC to power off
  1656. //
  1657. // save HC state if the Root hub is disabled
  1658. if (deviceData->RootHubControl == NULL)
  1659. {
  1660. KeCancelTimer(&deviceData->DeadmanTimer);
  1661. OpenHCI_SaveHCstate(deviceData);
  1662. }
  1663. LOGENTRY(G, 'Coff', deviceData, 0, 0);
  1664. // In the NT power management model, D3 is not necessarily "OFF".
  1665. // What governs this is the DeviceWake setting in the DeviceCaps
  1666. // structure. If DeviceWake for our controller device is D3, then
  1667. // we know that it is possible for the controller to wake the
  1668. // machine from this power level. The controller must have power
  1669. // to be able to do so, therefore, we suppress setting the
  1670. // HCFLAG_LOST_POWER flag in this case. Setting it actually has
  1671. // the undesired effect of causing us to reset the controller on
  1672. // resume, which in turn causes the hub to fail and the devices to
  1673. // be surprise removed/reenumerated unnecessarily when the hub is
  1674. // reinitialized. This normally isn't more than a minor annoyance
  1675. // (e.g. slow resume time), except in the case where one of these
  1676. // devices is a USB mass storage device. Surprise removal is
  1677. // dangerous for mass storage devices, and the user is presented
  1678. // with the annoying "don't surprise remove this device" dialog
  1679. // when the system is resumed, even though the user himself did not
  1680. // directly cause the device removal.
  1681. //
  1682. // Note that the case where the host controller really does lose
  1683. // power could result in the same problem, but that will have to
  1684. // be addressed in the hub driver.
  1685. usbdExtension = DeviceObject->DeviceExtension;
  1686. hcDeviceCapabilities = &usbdExtension->HcDeviceCapabilities;
  1687. if (!bIsSuspend ||
  1688. DeviceState > hcDeviceCapabilities->DeviceWake) {
  1689. deviceData->HcFlags |= HC_FLAG_LOST_POWER;
  1690. }
  1691. // disable interrupts
  1692. WRITE_REGISTER_ULONG(&HC->HcInterruptDisable, 0xFFFFFFFF);
  1693. deviceData->CurrentDevicePowerState = DeviceState;
  1694. OpenHCI_KdPrint((1, "'Host Controller entered (D3)\n"));
  1695. // pass on to PDO
  1696. break;
  1697. case PowerDeviceD1:
  1698. case PowerDeviceD2:
  1699. //
  1700. // power states D1,D2 translate to USB suspend
  1701. //
  1702. // Note, we should not get here unless all the children of the HC
  1703. // have been suspended.
  1704. //
  1705. LOGENTRY(G, 'CD12', deviceData, 0, 0);
  1706. // disable interrupts
  1707. WRITE_REGISTER_ULONG(&HC->HcInterruptDisable, 0xFFFFFFFF);
  1708. deviceData->CurrentDevicePowerState = DeviceState;
  1709. #ifdef WIN98
  1710. // this is necessary to make remote wakeup work
  1711. // on the TECRA 750
  1712. // having interrupts enabled in D1/D2 is not
  1713. // valid (to my knowlege) on Win2k
  1714. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable,
  1715. HcInt_MasterInterruptEnable |
  1716. HcInt_ResumeDetected);
  1717. #endif
  1718. OpenHCI_KdPrint((1, "'Host Controller entered (D%d)\n", DeviceState-1));
  1719. // pass on to PDO
  1720. break;
  1721. case PowerDeviceD0:
  1722. //
  1723. // Request for HC to go to resume
  1724. //
  1725. OpenHCI_KdPrint((2, "'PowerDeviceD0 (ON)\n"));
  1726. LOGENTRY(G, 'CgD0', deviceData, 0, 0);
  1727. //
  1728. // finish the rest in the completion routine
  1729. //
  1730. hookIt = TRUE;
  1731. // pass on to PDO
  1732. break;
  1733. default:
  1734. TRAP(); //Bogus DeviceState;
  1735. }
  1736. if (hookIt) {
  1737. OpenHCI_KdPrintDD(deviceData, OHCI_DBG_CALL_TRACE, ("'Set PowerIrp Completion Routine\n"));
  1738. IoSetCompletionRoutine(Irp,
  1739. OpenHCI_PowerIrpComplete,
  1740. // always pass FDO to completion routine
  1741. DeviceObject,
  1742. hookIt,
  1743. hookIt,
  1744. hookIt);
  1745. }
  1746. }
  1747. return ntStatus;
  1748. }
  1749. NTSTATUS
  1750. OpenHCI_GetRegistryKeyValue(
  1751. IN PHCD_DEVICE_DATA DeviceData,
  1752. IN HANDLE Handle,
  1753. IN PWCHAR KeyNameString,
  1754. IN ULONG KeyNameStringLength,
  1755. IN PVOID Data,
  1756. IN ULONG DataLength
  1757. )
  1758. /*++
  1759. Routine Description:
  1760. Arguments:
  1761. Return Value:
  1762. --*/
  1763. {
  1764. NTSTATUS ntStatus = STATUS_NO_MEMORY;
  1765. UNICODE_STRING keyName;
  1766. ULONG length;
  1767. PKEY_VALUE_FULL_INFORMATION fullInfo;
  1768. RtlInitUnicodeString(&keyName, KeyNameString);
  1769. length = sizeof(KEY_VALUE_FULL_INFORMATION) +
  1770. KeyNameStringLength + DataLength;
  1771. fullInfo = ExAllocatePoolWithTag(PagedPool, length, OpenHCI_TAG);
  1772. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  1773. (" GetRegistryKeyValue buffer = 0x%x\n", fullInfo));
  1774. if (fullInfo) {
  1775. ntStatus = ZwQueryValueKey(Handle,
  1776. &keyName,
  1777. KeyValueFullInformation,
  1778. fullInfo,
  1779. length,
  1780. &length);
  1781. if (NT_SUCCESS(ntStatus)) {
  1782. ASSERT(DataLength == fullInfo->DataLength);
  1783. RtlCopyMemory(Data, ((PUCHAR) fullInfo) + fullInfo->DataOffset, DataLength);
  1784. }
  1785. ExFreePool(fullInfo);
  1786. }
  1787. return ntStatus;
  1788. }
  1789. NTSTATUS
  1790. OpenHCI_DeferIrpCompletion(
  1791. IN PDEVICE_OBJECT DeviceObject,
  1792. IN PIRP Irp,
  1793. IN PVOID Context
  1794. )
  1795. /*++
  1796. jd
  1797. Routine Description:
  1798. This routine is called when the port driver completes an IRP.
  1799. Arguments:
  1800. DeviceObject - Pointer to the device object for the class device.
  1801. Irp - Irp completed.
  1802. Context - Driver defined context.
  1803. Return Value:
  1804. The function value is the final status from the operation.
  1805. --*/
  1806. {
  1807. PKEVENT event = Context;
  1808. KeSetEvent(event,
  1809. 1,
  1810. FALSE);
  1811. return STATUS_MORE_PROCESSING_REQUIRED;
  1812. }
  1813. NTSTATUS
  1814. OpenHCI_DeferPoRequestCompletion(
  1815. IN PDEVICE_OBJECT DeviceObject,
  1816. IN UCHAR MinorFunction,
  1817. IN POWER_STATE DeviceState,
  1818. IN PVOID Context,
  1819. IN PIO_STATUS_BLOCK IoStatus
  1820. )
  1821. /*++
  1822. Routine Description:
  1823. This routine is called when the port driver completes an IRP.
  1824. Arguments:
  1825. DeviceObject - Pointer to the device object for the class device.
  1826. SetState - TRUE for set, FALSE for query.
  1827. DevicePowerState - The Dx that we are in/tagetted.
  1828. Context - Driver defined context.
  1829. IoStatus - The status of the IRP.
  1830. Return Value:
  1831. The function value is the final status from the operation.
  1832. --*/
  1833. {
  1834. PKEVENT event = Context;
  1835. KeSetEvent(event,
  1836. 1,
  1837. FALSE);
  1838. return STATUS_MORE_PROCESSING_REQUIRED;
  1839. }
  1840. NTSTATUS
  1841. OpenHCI_QueryCapabilities(
  1842. IN PDEVICE_OBJECT PdoDeviceObject,
  1843. IN PDEVICE_CAPABILITIES DeviceCapabilities
  1844. )
  1845. /*++
  1846. jd
  1847. Routine Description:
  1848. This routine reads or write config space.
  1849. Arguments:
  1850. DeviceObject - Physical DeviceObject for this USB controller.
  1851. Return Value:
  1852. None.
  1853. --*/
  1854. {
  1855. PIO_STACK_LOCATION nextStack;
  1856. PIRP irp;
  1857. NTSTATUS ntStatus;
  1858. KEVENT event;
  1859. PAGED_CODE();
  1860. RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  1861. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  1862. DeviceCapabilities->Version = 1;
  1863. DeviceCapabilities->Address = -1;
  1864. DeviceCapabilities->UINumber = -1;
  1865. irp = IoAllocateIrp(PdoDeviceObject->StackSize, FALSE);
  1866. if (!irp) {
  1867. TRAP(); //"failed to allocate Irp
  1868. return STATUS_INSUFFICIENT_RESOURCES;
  1869. }
  1870. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1871. nextStack = IoGetNextIrpStackLocation(irp);
  1872. ASSERT(nextStack != NULL);
  1873. nextStack->MajorFunction= IRP_MJ_PNP;
  1874. nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES;
  1875. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1876. IoSetCompletionRoutine(irp,
  1877. OpenHCI_DeferIrpCompletion,
  1878. &event,
  1879. TRUE,
  1880. TRUE,
  1881. TRUE);
  1882. nextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
  1883. ntStatus = IoCallDriver(PdoDeviceObject,
  1884. irp);
  1885. // OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_PNP_TRACE, ("'ntStatus from IoCallDriver to PCI = 0x%x\n", ntStatus));
  1886. if (ntStatus == STATUS_PENDING) {
  1887. // wait for irp to complete
  1888. KeWaitForSingleObject(
  1889. &event,
  1890. Suspended,
  1891. KernelMode,
  1892. FALSE,
  1893. NULL);
  1894. ntStatus = irp->IoStatus.Status;
  1895. }
  1896. IoFreeIrp(irp);
  1897. return ntStatus;
  1898. }
  1899. NTSTATUS
  1900. OpenHCI_RootHubPower(
  1901. IN PDEVICE_OBJECT DeviceObject,
  1902. IN PIRP Irp
  1903. )
  1904. /*++
  1905. Routine Description:
  1906. This function handles power messages to the root hub, note that
  1907. we save the stae of the HC here instead of when the HC itself is
  1908. powered down. The reason for this is for compatibility with APM
  1909. systems that cut power to the HC during a suspend. On these
  1910. systems WDM never sends a power state change mesage to the HC ie
  1911. the HC is assumed to always stay on.
  1912. Arguments:
  1913. DeviceObject - DeviceObject for this USB controller.
  1914. Return Value:
  1915. NT status code.
  1916. --*/
  1917. {
  1918. PIO_STACK_LOCATION irpStack;
  1919. NTSTATUS ntStatus = STATUS_SUCCESS;
  1920. PHCD_DEVICE_DATA deviceData;
  1921. BOOLEAN lostPower;
  1922. OpenHCI_KdPrint((2, "'OpenHCI_RootHubPower\n"));
  1923. deviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  1924. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1925. switch (irpStack->MinorFunction) {
  1926. case IRP_MN_WAIT_WAKE:
  1927. OpenHCI_KdPrintDD(deviceData, OHCI_DBG_SS_TRACE, ("'IRP_MN_WAIT_WAKE\n"));
  1928. //
  1929. // someone is enabling us for wakeup
  1930. //
  1931. TEST_TRAP(); // never seen this before?
  1932. break;
  1933. case IRP_MN_SET_POWER:
  1934. switch (irpStack->Parameters.Power.Type) {
  1935. case SystemPowerState:
  1936. // should not get here
  1937. TRAP(); //(("RootHubPower -- SystemState\n"));
  1938. break;
  1939. case DevicePowerState:
  1940. switch(irpStack->Parameters.Power.State.DeviceState) {
  1941. case PowerDeviceD0:
  1942. #ifdef JD
  1943. TEST_TRAP();
  1944. #endif
  1945. OpenHCI_RestoreHCstate(deviceData, &lostPower);
  1946. ntStatus = OpenHCI_Resume(DeviceObject, lostPower);
  1947. KeSetTimerEx(&deviceData->DeadmanTimer,
  1948. RtlConvertLongToLargeInteger(-10000),
  1949. 10,
  1950. &deviceData->DeadmanTimerDPC);
  1951. break;
  1952. case PowerDeviceD1:
  1953. case PowerDeviceD3:
  1954. case PowerDeviceD2:
  1955. KeCancelTimer(&deviceData->DeadmanTimer);
  1956. OpenHCI_SaveHCstate(deviceData);
  1957. ntStatus = OpenHCI_Suspend(DeviceObject);
  1958. break;
  1959. }
  1960. break;
  1961. }
  1962. }
  1963. return ntStatus;
  1964. }
  1965. NTSTATUS
  1966. OpenHCI_StartDevice(
  1967. IN PDEVICE_OBJECT DeviceObject,
  1968. IN POHCI_RESOURCES Resources
  1969. )
  1970. /*++
  1971. Routine Description:
  1972. This routine initializes the DeviceObject for a given instance
  1973. of a USB host controller.
  1974. Arguments:
  1975. DeviceObject - DeviceObject for this USB controller.
  1976. PartialResourceList - Resources for this controller.
  1977. Return Value:
  1978. NT status code.
  1979. --*/
  1980. {
  1981. NTSTATUS ntStatus = STATUS_SUCCESS;
  1982. PHCD_DEVICE_DATA DeviceData;
  1983. DEVICE_CAPABILITIES deviceCapabilities;
  1984. DeviceData = DeviceObject->DeviceExtension;
  1985. LOGENTRY(G, 'STRc', DeviceData, Resources, 0);
  1986. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  1987. ("'e: OpenHCI_StartDevice\n"));
  1988. if (DeviceData->HcFlags & HC_FLAG_DEVICE_STARTED) {
  1989. OpenHCI_KdPrintDD(DeviceData,
  1990. OHCI_DBG_SS_INFO, ("'already started !!\n"));
  1991. return STATUS_SUCCESS;
  1992. }
  1993. #if 0
  1994. // get the device & vendor id
  1995. {
  1996. UCHAR revisionId;
  1997. USHORT vendorId, deviceId;
  1998. OpenHCI_KdPrint((2, "'Get the version\n"));
  1999. OpenHCI_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2000. TRUE,
  2001. &vendorId,
  2002. 0,
  2003. sizeof(vendorId));
  2004. OpenHCI_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2005. TRUE,
  2006. &deviceId,
  2007. 2,
  2008. sizeof(deviceId));
  2009. OpenHCI_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2010. TRUE,
  2011. &revisionId,
  2012. 8,
  2013. sizeof(revisionId));
  2014. OpenHCI_KdPrint((1, "'vendor = (%x) device = (%x) rev = (%x)\n",
  2015. vendorId, deviceId, revisionId));
  2016. }
  2017. #endif
  2018. //
  2019. // We found a host controller or a host controller found us, do the final
  2020. // stages of initilalization.
  2021. // Setup state variables for the host controller
  2022. //
  2023. ntStatus = OpenHCI_InitializeSchedule(DeviceObject);
  2024. if (!NT_SUCCESS(ntStatus)) {
  2025. goto OpenHCI_InitializeDeviceExit;
  2026. }
  2027. //
  2028. // Initialize the controller registers
  2029. //
  2030. ntStatus = OpenHCI_InitializeHardware(DeviceObject);
  2031. if (!NT_SUCCESS(ntStatus)) {
  2032. goto OpenHCI_InitializeDeviceExit;
  2033. }
  2034. // During a STOP_DEVICE / START_DEVICE rebalance cycle, it is possible
  2035. // for an endpoint to be left on the StalledEDReclamation list and not
  2036. // be removed by OpenHCI_IsrDPC() before the STOP_DEVICE completes. Make
  2037. // sure START_DEVICE restarts with an empty StalledEDReclamation list.
  2038. // Note that no resources are leaked if we just throw away anything
  2039. // that might be left on the StalledEDReclamation list since all of the
  2040. // common buffer pages containing EDs are freed during STOP_DEVICE
  2041. // regardless of whether or not OpenHCI_Free_HcdED() is called for
  2042. // all EDs.
  2043. //
  2044. InitializeListHead(&DeviceData->StalledEDReclamation);
  2045. //
  2046. // initialization all done, last step is to connect the interrupt & DPCs.
  2047. //
  2048. KeInitializeDpc(&DeviceData->IsrDPC,
  2049. OpenHCI_IsrDPC,
  2050. DeviceObject);
  2051. //
  2052. // our initial state is 'ON'
  2053. //
  2054. DeviceData->CurrentDevicePowerState = PowerDeviceD0;
  2055. //
  2056. // Initialize and connect the interrupt object for the controller.
  2057. //
  2058. ntStatus = IoConnectInterrupt(&(DeviceData->InterruptObject),
  2059. (PKSERVICE_ROUTINE) OpenHCI_InterruptService,
  2060. (PVOID) DeviceObject,
  2061. &DeviceData->InterruptSpin,
  2062. Resources->InterruptVector,
  2063. Resources->InterruptLevel,
  2064. Resources->InterruptLevel,
  2065. Resources->InterruptMode,
  2066. Resources->ShareIRQ,
  2067. Resources->Affinity,
  2068. FALSE);
  2069. if (!NT_SUCCESS(ntStatus)) {
  2070. goto OpenHCI_InitializeDeviceExit;
  2071. }
  2072. //
  2073. // get our capabilities
  2074. //
  2075. ntStatus = OpenHCI_QueryCapabilities(DeviceData->TopOfStackPhysicalDeviceObject,
  2076. &deviceCapabilities);
  2077. if (!NT_SUCCESS(ntStatus)) {
  2078. goto OpenHCI_InitializeDeviceExit;
  2079. }
  2080. #if DBG
  2081. {
  2082. ULONG i;
  2083. OpenHCI_KdPrint((1, "'HCD Device Caps returned from PCI:\n"));
  2084. OpenHCI_KdPrint((1, "'\tSystemWake = S%d\n", deviceCapabilities.SystemWake-1));
  2085. OpenHCI_KdPrint((1, "'\tDeviceWake = D%d\n", deviceCapabilities.DeviceWake-1));
  2086. OpenHCI_KdPrint((1, "'\tDevice State Map:\n"));
  2087. for (i=0; i< PowerSystemHibernate; i++) {
  2088. OpenHCI_KdPrint((1, "'\t-->S%d = D%d\n", i-1,
  2089. deviceCapabilities.DeviceState[i]-1));
  2090. }
  2091. }
  2092. #endif
  2093. USBD_RegisterHcDeviceCapabilities(DeviceObject,
  2094. &deviceCapabilities,
  2095. OpenHCI_RootHubPower);
  2096. if (!NT_SUCCESS(ntStatus)) {
  2097. goto OpenHCI_InitializeDeviceExit;
  2098. }
  2099. //
  2100. // **
  2101. // SUCCESS!!
  2102. // **
  2103. //
  2104. // init the idle counter
  2105. KeQuerySystemTime(&DeviceData->LastIdleTime);
  2106. DeviceData->IdleTime = 100000000;
  2107. OHCI_WAIT(10);
  2108. if (!KeSynchronizeExecution(DeviceData->InterruptObject,
  2109. OpenHCI_StartController,
  2110. DeviceData)) {
  2111. ntStatus = STATUS_UNSUCCESSFUL;
  2112. }
  2113. OHCI_WAIT(10);
  2114. WRITE_REGISTER_ULONG(&DeviceData->HC->HcInterruptStatus, HcInt_StartOfFrame);
  2115. WRITE_REGISTER_ULONG(&DeviceData->HC->HcInterruptEnable, HcInt_StartOfFrame);
  2116. WRITE_REGISTER_ULONG(&DeviceData->HC->HcInterruptEnable, HcInt_ResumeDetected);
  2117. WRITE_REGISTER_ULONG(&DeviceData->HC->HcInterruptEnable, HcInt_MasterInterruptEnable);
  2118. // For debugging only.
  2119. // WRITE_REGISTER_ULONG(&DeviceData->HC->HcRhPortStatus[0],
  2120. // HcRhPS_SetPortEnable);
  2121. // WRITE_REGISTER_ULONG(&DeviceData->HC->HcRhPortStatus[1],
  2122. // HcRhPS_SetPortEnable);
  2123. if (NT_SUCCESS(ntStatus)) {
  2124. // enable idle checking
  2125. DeviceData->HcFlags &= ~HC_FLAG_DISABLE_IDLE_CHECK;
  2126. }
  2127. #if DBG
  2128. if (!(DeviceData->HcFlags & HC_FLAG_REMOTE_WAKEUP_CONNECTED)) {
  2129. // this controller probably won't do idle properly
  2130. OpenHCI_KdPrint((1, "'This Controller won't support idle\n"));
  2131. }
  2132. #endif
  2133. OpenHCI_InitializeDeviceExit:
  2134. DeviceData->HcFlags |= HC_FLAG_DEVICE_STARTED;
  2135. if (!NT_SUCCESS(ntStatus))
  2136. {
  2137. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE, ("'Init Failed \n"));
  2138. //
  2139. // The initialization failed. Cleanup resources before exiting.
  2140. //
  2141. // Note: No need/way to undo the KeInitializeDpc or
  2142. // KeInitializeTimer calls.
  2143. //
  2144. OpenHCI_StopDevice(DeviceObject, TRUE);
  2145. }
  2146. else
  2147. {
  2148. // Start our deadman timer
  2149. //
  2150. KeSetTimerEx(&DeviceData->DeadmanTimer,
  2151. RtlConvertLongToLargeInteger(-10000),
  2152. 10,
  2153. &DeviceData->DeadmanTimerDPC);
  2154. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  2155. ("'Init Passed extension 0x%x\n",
  2156. sizeof(USBD_EXTENSION)));
  2157. }
  2158. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_TRACE,
  2159. ("'exit StartDevice (%x)\n", ntStatus));
  2160. LOGENTRY(G, 'STRd', DeviceData, 0, ntStatus);
  2161. return ntStatus;
  2162. }
  2163. NTSTATUS
  2164. OpenHCI_GetResources(
  2165. IN PDEVICE_OBJECT DeviceObject,
  2166. IN PCM_RESOURCE_LIST ResourceList,
  2167. IN OUT POHCI_RESOURCES Resources
  2168. )
  2169. /*++
  2170. Routine Description:
  2171. This routines parses the resources for the controller
  2172. Arguments:
  2173. DeviceObject - DeviceObject for this USB controller.
  2174. PartialResourceList - Resources for this controller.
  2175. Return Value:
  2176. NT status code.
  2177. --*/
  2178. {
  2179. PHCD_DEVICE_DATA DeviceData;
  2180. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDescriptor;
  2181. PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
  2182. PCM_PARTIAL_RESOURCE_DESCRIPTOR interrupt;
  2183. PCM_PARTIAL_RESOURCE_DESCRIPTOR memory;
  2184. PCM_PARTIAL_RESOURCE_DESCRIPTOR port;
  2185. ULONG i;
  2186. NTSTATUS ntStatus = STATUS_SUCCESS;
  2187. DeviceData = DeviceObject->DeviceExtension;
  2188. if (ResourceList == NULL) {
  2189. return STATUS_NONE_MAPPED;
  2190. }
  2191. fullResourceDescriptor = &ResourceList->List[0];
  2192. PartialResourceList = &fullResourceDescriptor->PartialResourceList;
  2193. OpenHCI_KdPrintDD(DeviceData,
  2194. OHCI_DBG_SS_TRACE, ("'e: OpenHCI_GetResources\n"));
  2195. interrupt = NULL;
  2196. memory = NULL;
  2197. port = NULL;
  2198. for (i = 0; i < PartialResourceList->Count; i++)
  2199. {
  2200. switch (PartialResourceList->PartialDescriptors[i].Type) {
  2201. case CmResourceTypeInterrupt:
  2202. if (interrupt == NULL)
  2203. {
  2204. interrupt = &PartialResourceList->PartialDescriptors[i];
  2205. }
  2206. break;
  2207. case CmResourceTypeMemory:
  2208. if (memory == NULL)
  2209. {
  2210. memory = &PartialResourceList->PartialDescriptors[i];
  2211. }
  2212. break;
  2213. case CmResourceTypePort:
  2214. if (port == NULL)
  2215. {
  2216. port = &PartialResourceList->PartialDescriptors[i];
  2217. }
  2218. break;
  2219. }
  2220. }
  2221. if (interrupt == NULL)
  2222. {
  2223. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_ERROR,
  2224. ("'Host Controller interrupt resource not found.\n"));
  2225. ntStatus = STATUS_NONE_MAPPED;
  2226. goto OpenHCI_GetResourcesExit;
  2227. }
  2228. if (memory == NULL && port == NULL)
  2229. {
  2230. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_ERROR,
  2231. ("'Host Controller memory/port resource not found.\n"));
  2232. ntStatus = STATUS_NONE_MAPPED;
  2233. goto OpenHCI_GetResourcesExit;
  2234. }
  2235. //
  2236. // Get Vector, level, and affinity information for the interrupt
  2237. //
  2238. OpenHCI_KdPrint((1,
  2239. "'Interrupt Resources Found! Level = %x Vector = %x\n",
  2240. interrupt->u.Interrupt.Level,
  2241. interrupt->u.Interrupt.Vector
  2242. ));
  2243. Resources->InterruptVector = interrupt->u.Interrupt.Vector;
  2244. Resources->InterruptLevel = (KIRQL)interrupt->u.Interrupt.Level;
  2245. Resources->Affinity = interrupt->u.Interrupt.Affinity,
  2246. Resources->InterruptMode = interrupt->Flags == CM_RESOURCE_INTERRUPT_LATCHED
  2247. ? Latched
  2248. : LevelSensitive;
  2249. Resources->ShareIRQ = interrupt->ShareDisposition == CmResourceShareShared
  2250. ? TRUE
  2251. : FALSE;
  2252. if (memory != NULL)
  2253. {
  2254. //
  2255. // Set up AddressSpace to be of type Memory mapped I/O
  2256. //
  2257. OpenHCI_KdPrint((1,
  2258. "'Memory Resources Found @ %x, Length = %x\n",
  2259. memory->u.Memory.Start.LowPart,
  2260. memory->u.Memory.Length
  2261. ));
  2262. DeviceData->HClength = memory->u.Memory.Length;
  2263. DeviceData->cardAddress = memory->u.Memory.Start;
  2264. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_INFO,
  2265. ("'Card address 0x%x\n", DeviceData->cardAddress.LowPart));
  2266. DeviceData->HC = MmMapIoSpace(DeviceData->cardAddress,
  2267. DeviceData->HClength,
  2268. FALSE);
  2269. if (DeviceData->HC == NULL)
  2270. {
  2271. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_ERROR,
  2272. ("'Host Controller memory window not mapped.\n"));
  2273. ntStatus = STATUS_NONE_MAPPED;
  2274. }
  2275. }
  2276. else
  2277. {
  2278. //
  2279. // Set up AddressSpace to be of type Port I/O
  2280. //
  2281. // port resources are equiv to adressSpace 1
  2282. // ie don't call mmMapIoSpace
  2283. OpenHCI_KdPrint((0,
  2284. "'Port Resources Found @ %x, %d Ports Available\n",
  2285. port->u.Port.Start.LowPart,
  2286. port->u.Port.Length
  2287. ));
  2288. DeviceData->HC = (PVOID)(ULONG_PTR)port->u.Port.Start.QuadPart;
  2289. DeviceData->HClength = port->u.Port.Length;
  2290. }
  2291. //
  2292. // Check host controller register window length and
  2293. // host controller revision register value.
  2294. //
  2295. if (NT_SUCCESS(ntStatus)) {
  2296. HC_REVISION revision;
  2297. OHCI_ASSERT(DeviceData->HC);
  2298. LOGENTRY(G, 'HCrr', DeviceData, DeviceData->HC, 0);
  2299. if (DeviceData->HClength < sizeof(HC_OPERATIONAL_REGISTER)) {
  2300. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_ERROR,
  2301. ("'Controller memory len short.\n"));
  2302. ntStatus = STATUS_NONE_MAPPED;
  2303. goto OpenHCI_GetResourcesExit;
  2304. }
  2305. revision.ul = READ_REGISTER_ULONG(&DeviceData->HC->HcRevision.ul);
  2306. if (revision.Rev != 0x10) {
  2307. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_ERROR,
  2308. ("'Unknown Rev of OHCI Controller: 0x%02x.\n",
  2309. revision.Rev));
  2310. ntStatus = STATUS_UNKNOWN_REVISION;
  2311. goto OpenHCI_GetResourcesExit;
  2312. }
  2313. OpenHCI_KdPrintDD(DeviceData, OHCI_DBG_SS_INFO,
  2314. ("'Mapped device memory registers to 0x%x.\n",
  2315. DeviceData->HC));
  2316. }
  2317. OpenHCI_GetResourcesExit:
  2318. OpenHCI_KdPrintDD(DeviceData,
  2319. OHCI_DBG_SS_INFO,
  2320. ("'OpenHCI_GetResources %x.\n", ntStatus));
  2321. return ntStatus;
  2322. }
  2323. NTSTATUS
  2324. OpenHCI_DeferredStartDevice(
  2325. IN PDEVICE_OBJECT DeviceObject,
  2326. IN PIRP Irp
  2327. )
  2328. /*++
  2329. Routine Description:
  2330. Arguments:
  2331. DeviceObject - DeviceObject for this USB controller.
  2332. Return Value:
  2333. NT Status code.
  2334. --*/
  2335. {
  2336. NTSTATUS ntStatus;
  2337. OHCI_RESOURCES resources;
  2338. PIO_STACK_LOCATION irpStack;
  2339. PHCD_DEVICE_DATA deviceData;
  2340. PAGED_CODE();
  2341. deviceData = DeviceObject->DeviceExtension;
  2342. irpStack = IoGetCurrentIrpStackLocation (Irp);
  2343. ntStatus = OpenHCI_GetResources(DeviceObject,
  2344. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated,
  2345. &resources);
  2346. if (NT_SUCCESS(ntStatus)) {
  2347. ntStatus = OpenHCI_StartDevice(DeviceObject,
  2348. &resources);
  2349. }
  2350. //#if PREALLOCATE_DESCRIPTOR_MEMORY
  2351. // if (NT_SUCCESS(ntStatus)) {
  2352. // ULONG k;
  2353. // for (k = 0; k < PREALLOCATE_DESCRIPTOR_MEMORY_NUM_PAGES; k++) {
  2354. // OpenHCI_ReserveDescriptors(deviceData);
  2355. // }
  2356. // }
  2357. //#endif
  2358. Irp->IoStatus.Status = ntStatus;
  2359. return ntStatus;
  2360. }
  2361. NTSTATUS
  2362. OpenHCI_GetRegFlags(
  2363. IN PDEVICE_OBJECT DeviceObject,
  2364. IN OUT PULONG SofModifyValue
  2365. )
  2366. /*++
  2367. Routine Description:
  2368. Arguments:
  2369. DeviceObject - DeviceObject for this USB controller.
  2370. Return Value:
  2371. NT Status code.
  2372. --*/
  2373. {
  2374. NTSTATUS ntStatus = STATUS_SUCCESS;
  2375. static WCHAR slowBulkEnableKey[] = L"SlowBulkEnable";
  2376. static WCHAR hydraHackEnableKey[] = L"HydraFixEnable";
  2377. static WCHAR idleEnableKey[] = L"IdleEnable";
  2378. static WCHAR listFixEnableKey[] = L"ListFixEnable";
  2379. static WCHAR hungCheckEnableKey[] = L"HungCheckEnable";
  2380. PHCD_DEVICE_DATA deviceData;
  2381. ULONG enable;
  2382. PAGED_CODE();
  2383. deviceData = DeviceObject->DeviceExtension;
  2384. enable = 0;
  2385. ntStatus = USBD_GetPdoRegistryParameter(deviceData->RealPhysicalDeviceObject,
  2386. &enable,
  2387. sizeof(enable),
  2388. slowBulkEnableKey,
  2389. sizeof(slowBulkEnableKey));
  2390. if (NT_SUCCESS(ntStatus) && enable) {
  2391. deviceData->HcFlags |= HC_FLAG_SLOW_BULK_ENABLE;
  2392. OpenHCI_KdPrint((1, "'Slow bulk enabled for HC\n"));
  2393. }
  2394. //
  2395. // check for HYDRA
  2396. //
  2397. enable = 0;
  2398. ntStatus = USBD_GetPdoRegistryParameter(deviceData->RealPhysicalDeviceObject,
  2399. &enable,
  2400. sizeof(enable),
  2401. hydraHackEnableKey,
  2402. sizeof(hydraHackEnableKey));
  2403. if (NT_SUCCESS(ntStatus) && enable) {
  2404. deviceData->HcFlags |= HC_FLAG_USE_HYDRA_HACK;
  2405. OpenHCI_KdPrint((1, "'Hydra fixes enabled for HC\n"));
  2406. }
  2407. //
  2408. // check for Idle support
  2409. //
  2410. enable = 0;
  2411. ntStatus = USBD_GetPdoRegistryParameter(deviceData->RealPhysicalDeviceObject,
  2412. &enable,
  2413. sizeof(enable),
  2414. idleEnableKey,
  2415. sizeof(idleEnableKey));
  2416. // default is no idle mode
  2417. deviceData->HcFlags |= HC_FLAG_DISABLE_IDLE_MODE;
  2418. if (NT_SUCCESS(ntStatus) && enable) {
  2419. deviceData->HcFlags &= ~HC_FLAG_DISABLE_IDLE_MODE;
  2420. OpenHCI_KdPrint((1, "'Enable idle mode for HC\n"));
  2421. }
  2422. //
  2423. // check for BulkListFilled / ControllListFilled hack
  2424. //
  2425. enable = 0;
  2426. ntStatus = USBD_GetPdoRegistryParameter(deviceData->RealPhysicalDeviceObject,
  2427. &enable,
  2428. sizeof(enable),
  2429. listFixEnableKey,
  2430. sizeof(listFixEnableKey));
  2431. if (NT_SUCCESS(ntStatus) && enable) {
  2432. deviceData->HcFlags |= HC_FLAG_LIST_FIX_ENABLE;
  2433. OpenHCI_KdPrint((1, "'BLF/CLF fixes enabled for HC\n"));
  2434. }
  2435. //
  2436. // check for Hung Host Controller Check enable
  2437. //
  2438. enable = 0;
  2439. ntStatus = USBD_GetPdoRegistryParameter(deviceData->RealPhysicalDeviceObject,
  2440. &enable,
  2441. sizeof(enable),
  2442. hungCheckEnableKey,
  2443. sizeof(hungCheckEnableKey));
  2444. if (NT_SUCCESS(ntStatus) && enable) {
  2445. deviceData->HcFlags |= HC_FLAG_HUNG_CHECK_ENABLE;
  2446. OpenHCI_KdPrint((1, "'Hung check enabled for HC\n"));
  2447. }
  2448. return ntStatus;
  2449. }
  2450. NTSTATUS
  2451. OpenHCI_GetSOFRegModifyValue(
  2452. IN PDEVICE_OBJECT DeviceObject,
  2453. IN OUT PULONG SofModifyValue
  2454. )
  2455. /*++
  2456. Routine Description:
  2457. Arguments:
  2458. DeviceObject - DeviceObject for this USB controller.
  2459. Return Value:
  2460. NT Status code.
  2461. --*/
  2462. {
  2463. NTSTATUS ntStatus = STATUS_SUCCESS;
  2464. WCHAR clocksPerFrameKey[] = L"timingClocksPerFrame";
  2465. WCHAR recClocksPerFrameKey[] = L"recommendedClocksPerFrame";
  2466. LONG recClocksPerFrame = 0;
  2467. PHCD_DEVICE_DATA deviceData;
  2468. PAGED_CODE();
  2469. deviceData = DeviceObject->DeviceExtension;
  2470. //ntStatus = USBD_GetPdoRegistryParameter(deviceExtension->PhysicalDeviceObject,
  2471. // &clocksPerFrame,
  2472. // sizeof(clocksPerFrame),
  2473. // clocksPerFrameKey,
  2474. // sizeof(clocksPerFrameKey));
  2475. if (NT_SUCCESS(ntStatus)) {
  2476. ntStatus = USBD_GetPdoRegistryParameter(deviceData->RealPhysicalDeviceObject,
  2477. &recClocksPerFrame,
  2478. sizeof(recClocksPerFrame),
  2479. recClocksPerFrameKey,
  2480. sizeof(recClocksPerFrameKey));
  2481. }
  2482. if (NT_SUCCESS(ntStatus) && recClocksPerFrame) {
  2483. *SofModifyValue = recClocksPerFrame;
  2484. }
  2485. OpenHCI_KdPrint((1,
  2486. "'Recommended Clocks/Frame %d sofModify = %d\n", recClocksPerFrame,
  2487. *SofModifyValue));
  2488. return ntStatus;
  2489. }
  2490. VOID
  2491. OpenHCI_ReadWriteConfig(
  2492. IN PDEVICE_OBJECT DeviceObject,
  2493. IN BOOLEAN Read,
  2494. IN PVOID Buffer,
  2495. IN ULONG Offset,
  2496. IN ULONG Length
  2497. )
  2498. /*++
  2499. Routine Description:
  2500. This routine reads or write config space.
  2501. Arguments:
  2502. DeviceObject - Physical DeviceObject for this USB controller.
  2503. Read - TRUE if read, FALSE if write.
  2504. Buffer - The info to read or write.
  2505. Offset - The offset in config space to read or write.
  2506. Length - The length to transfer.
  2507. Return Value:
  2508. None.
  2509. --*/
  2510. {
  2511. PIO_STACK_LOCATION nextStack;
  2512. PIRP irp;
  2513. NTSTATUS ntStatus;
  2514. KEVENT event;
  2515. PHCD_DEVICE_DATA deviceData;
  2516. PAGED_CODE();
  2517. deviceData = DeviceObject->DeviceExtension;
  2518. if (Read) {
  2519. memset(Buffer, '\0', Length);
  2520. }
  2521. irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  2522. if (!irp) {
  2523. OpenHCI_KdTrap(("'failed to allocate Irp\n"));
  2524. return;
  2525. }
  2526. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2527. IoSetCompletionRoutine(irp,
  2528. OpenHCI_DeferIrpCompletion,
  2529. &event,
  2530. TRUE,
  2531. TRUE,
  2532. TRUE);
  2533. nextStack = IoGetNextIrpStackLocation(irp);
  2534. ASSERT(nextStack != NULL);
  2535. nextStack->MajorFunction= IRP_MJ_PNP;
  2536. nextStack->MinorFunction= Read ? IRP_MN_READ_CONFIG : IRP_MN_WRITE_CONFIG;
  2537. nextStack->Parameters.ReadWriteConfig.Buffer = Buffer;
  2538. nextStack->Parameters.ReadWriteConfig.Buffer = Buffer;
  2539. nextStack->Parameters.ReadWriteConfig.Offset = Offset;
  2540. nextStack->Parameters.ReadWriteConfig.Length = Length;
  2541. ntStatus = IoCallDriver(DeviceObject,
  2542. irp);
  2543. OpenHCI_KdPrint((2, "'ntStatus from IoCallDriver to PCI = 0x%x\n", ntStatus));
  2544. if (ntStatus == STATUS_PENDING) {
  2545. // wait for irp to complete
  2546. TEST_TRAP(); // first time we hit this
  2547. KeWaitForSingleObject(
  2548. &event,
  2549. Suspended,
  2550. KernelMode,
  2551. FALSE,
  2552. NULL);
  2553. }
  2554. if (!NT_SUCCESS(ntStatus)) {
  2555. // failed? this is probably a bug
  2556. OpenHCI_KdTrap(("ReadWriteConfig failed, why?\n"));
  2557. }
  2558. IoFreeIrp(irp);
  2559. }
  2560. VOID
  2561. OpenHCI_FixLists(
  2562. PHCD_DEVICE_DATA DeviceData
  2563. )
  2564. {
  2565. PHC_OPERATIONAL_REGISTER HC;
  2566. ULONG Temp, Temp0, Temp1;
  2567. // this hack is required to work around problems with certain
  2568. // revs of the NEC controller
  2569. OpenHCI_KdPrint((2, "'Fix Bulk/Control Lists\n"));
  2570. HC = DeviceData->HC;
  2571. Temp = READ_REGISTER_ULONG(&HC->HcCommandStatus.ul);
  2572. Temp0 = Temp & ~(HcCmd_ControlListFilled | HcCmd_BulkListFilled);
  2573. Temp1 = Temp | (HcCmd_ControlListFilled | HcCmd_BulkListFilled);
  2574. WRITE_REGISTER_ULONG(&HC->HcCommandStatus.ul, Temp0);
  2575. WRITE_REGISTER_ULONG(&HC->HcCommandStatus.ul, Temp1);
  2576. }
  2577. BOOLEAN
  2578. OpenHCI_RhPortsIdle(
  2579. PHCD_DEVICE_DATA DeviceData
  2580. )
  2581. /*++
  2582. Routine Description:
  2583. Arguments:
  2584. DeviceObject - DeviceObject of the controller to stop
  2585. Return Value:
  2586. NT status code.
  2587. --*/
  2588. {
  2589. ULONG i;
  2590. BOOLEAN idle = TRUE;
  2591. // don't log in here, this function can be called
  2592. // in a kesync situation
  2593. // Note always return false if the root hub is disabled --
  2594. // we don't want to go idle with no root hub to control the
  2595. // ports.
  2596. if (DeviceData->RootHubControl == NULL) {
  2597. idle = FALSE;
  2598. }
  2599. for (i = 0; idle && i < DeviceData->NumberOfPorts; i++)
  2600. {
  2601. ULONG currentStatus;
  2602. currentStatus = ReadPortStatusFix(DeviceData, i);
  2603. //LOGENTRY(G, 'idPS', currentStatus, i, 0);
  2604. if (currentStatus & (HcRhPS_ConnectStatusChange |
  2605. HcRhPS_CurrentConnectStatus)) {
  2606. idle = FALSE;
  2607. }
  2608. }
  2609. return idle;
  2610. }
  2611. VOID
  2612. OpenHCI_CheckIdle(
  2613. PHCD_DEVICE_DATA DeviceData
  2614. )
  2615. /*++
  2616. Routine Description:
  2617. If the controllers hub ports are not connected this function
  2618. stops the host controller
  2619. If there are no iso enpoints open then this function
  2620. disables the rollover interrupt
  2621. Arguments:
  2622. DeviceObject - DeviceObject of the controller to stop
  2623. Return Value:
  2624. NT status code.
  2625. --*/
  2626. {
  2627. NTSTATUS ntStatus = STATUS_SUCCESS;
  2628. BOOLEAN portsIdle = TRUE;
  2629. LARGE_INTEGER timeNow;
  2630. PHC_OPERATIONAL_REGISTER HC;
  2631. OpenHCI_KdPrint((3, "'Check Idle\n"));
  2632. HC = DeviceData->HC;
  2633. if (DeviceData->HcFlags &
  2634. (HC_FLAG_DISABLE_IDLE_CHECK | HC_FLAG_IDLE | HC_FLAG_DISABLE_IDLE_MODE)) {
  2635. // no idle checking until we are started and the root hub
  2636. // is operational
  2637. return;
  2638. }
  2639. KeAcquireSpinLockAtDpcLevel(&DeviceData->HcFlagSpin);
  2640. portsIdle = OpenHCI_RhPortsIdle(DeviceData);
  2641. if (portsIdle) {
  2642. // if ports are idle turn off sof int
  2643. WRITE_REGISTER_ULONG(&HC->HcInterruptDisable,
  2644. HcInt_StartOfFrame);
  2645. KeQuerySystemTime(&timeNow);
  2646. // we are not idle,
  2647. // see how long ports have been idle if it
  2648. // is longer then 10 seconds stop the
  2649. // controller
  2650. if (DeviceData->IdleTime == 0) {
  2651. KeQuerySystemTime(&DeviceData->LastIdleTime);
  2652. DeviceData->IdleTime = 1;
  2653. }
  2654. DeviceData->IdleTime +=
  2655. (LONG) (timeNow.QuadPart -
  2656. DeviceData->LastIdleTime.QuadPart);
  2657. LOGENTRY(G, 'idlT', DeviceData->IdleTime, 0, 0);
  2658. // ports are idle stop the controller
  2659. if (// 10 seconds in 100ns units
  2660. DeviceData->IdleTime > 100000000) {
  2661. LOGENTRY(G, 'sOFF', DeviceData, 0, 0);
  2662. OpenHCI_KdPrint((2, "'HC stopped\n"));
  2663. // attempt to move the controller to the suspend state
  2664. OpenHCI_KdPrint((1, "'controller going idle\n"));
  2665. if (!KeSynchronizeExecution(DeviceData->InterruptObject,
  2666. OpenHCI_IdleController,
  2667. DeviceData)) {
  2668. TRAP(); //something has gone terribly wrong
  2669. }
  2670. DeviceData->HcFlags |= HC_FLAG_IDLE;
  2671. OpenHCI_KdPrint((1, "'controller idle\n"));
  2672. }
  2673. DeviceData->LastIdleTime = timeNow;
  2674. } else {
  2675. DeviceData->IdleTime = 0;
  2676. }
  2677. KeReleaseSpinLockFromDpcLevel(&DeviceData->HcFlagSpin);
  2678. }
  2679. VOID
  2680. OpenHCI_DeadmanDPC(
  2681. PKDPC Dpc,
  2682. PVOID DeviceObject,
  2683. PVOID Context1,
  2684. PVOID Context2
  2685. )
  2686. /*++
  2687. Routine Description:
  2688. Arguments:
  2689. Return Value:
  2690. --*/
  2691. {
  2692. PHCD_DEVICE_DATA deviceData;
  2693. PHC_OPERATIONAL_REGISTER HC;
  2694. ULONGLONG lastDeadmanTime;
  2695. deviceData =
  2696. (PHCD_DEVICE_DATA) ((PDEVICE_OBJECT) DeviceObject)->DeviceExtension;
  2697. HC = deviceData->HC;
  2698. lastDeadmanTime = deviceData->LastDeadmanTime;
  2699. deviceData->LastDeadmanTime = KeQueryInterruptTime();
  2700. ASSERT(deviceData->CurrentDevicePowerState == PowerDeviceD0);
  2701. ASSERT(deviceData->HcFlags & HC_FLAG_DEVICE_STARTED);
  2702. {
  2703. // If the HC is in the operational state, try to determine if it
  2704. // is still alive and updating the HCCA.
  2705. //
  2706. if ((deviceData->HcFlags & HC_FLAG_HUNG_CHECK_ENABLE) &&
  2707. ((READ_REGISTER_ULONG(&HC->HcControl.ul) & HcCtrl_HCFS_MASK) ==
  2708. HcCtrl_HCFS_USBOperational) &&
  2709. (lastDeadmanTime != deviceData->LastDeadmanTime))
  2710. {
  2711. #if DBG
  2712. ULONG HcFmNumber;
  2713. HcFmNumber = READ_REGISTER_ULONG(&HC->HcFmNumber);
  2714. #endif
  2715. switch (deviceData->HCCA->HccaPad1)
  2716. {
  2717. case 0:
  2718. //
  2719. // When the HC updates HccaFrameNumber, it is supposed
  2720. // to set HccaPad1 to zero, so this is the expected case.
  2721. // Here we set HccaPad1 to a non-zero value to try to
  2722. // detect situations when the HC is no longer functioning
  2723. // correctly and accessing and updating host memory.
  2724. //
  2725. deviceData->HCCA->HccaPad1 = 0xBAD1;
  2726. break;
  2727. case 0xBAD1:
  2728. //
  2729. // Apparently the HC has not updated the HCCA since the
  2730. // last time the DPC ran. This is probably not good.
  2731. //
  2732. deviceData->HCCA->HccaPad1 = 0xBAD2;
  2733. LOGENTRY(G, 'BAD2', deviceData, HcFmNumber,
  2734. deviceData->LastDeadmanTime);
  2735. LOGENTRY(G, 'bad2', deviceData,
  2736. deviceData->HCCA->HccaFrameNumber, 0);
  2737. break;
  2738. case 0xBAD2:
  2739. //
  2740. // Apparently the HC has not updated the HCCA since the
  2741. // last two times the DPC ran. This looks even worse.
  2742. // Assume the HC has become wedged.
  2743. //
  2744. deviceData->HCCA->HccaPad1 = 0xBAD3;
  2745. LOGENTRY(G, 'BAD3', deviceData, HcFmNumber,
  2746. deviceData->LastDeadmanTime);
  2747. LOGENTRY(G, 'bad3', deviceData,
  2748. deviceData->HCCA->HccaFrameNumber, 0);
  2749. OpenHCI_KdPrint((0,
  2750. "*** Warning: HC %08X appears to be wedged!\n",
  2751. DeviceObject));
  2752. OpenHCI_ResurrectHC(deviceData);
  2753. return;
  2754. case 0xBAD3:
  2755. break;
  2756. default:
  2757. TEST_TRAP();
  2758. break;
  2759. }
  2760. }
  2761. if (deviceData->HcFlags & HC_FLAG_LIST_FIX_ENABLE)
  2762. {
  2763. // fix NEC bulk and control lists
  2764. OpenHCI_FixLists(deviceData);
  2765. }
  2766. // see if we can go idle
  2767. OpenHCI_CheckIdle(deviceData);
  2768. }
  2769. }
  2770. NTSTATUS
  2771. OpenHCI_InsertMagicEDs(
  2772. IN PDEVICE_OBJECT DeviceObject
  2773. )
  2774. /*++
  2775. Routine Description:
  2776. Arguments:
  2777. DeviceObject - DeviceObject for this USB controller.
  2778. Return Value:
  2779. NT Status code.
  2780. --*/
  2781. {
  2782. PHCD_ENDPOINT_DESCRIPTOR ed;
  2783. PHCD_DEVICE_DATA deviceData;
  2784. PHCD_TRANSFER_DESCRIPTOR td;
  2785. ULONG i;
  2786. OpenHCI_KdPrint((1, "'*** WARNING: Turning on HS/LS Fix ***\n"));
  2787. //
  2788. // **
  2789. // WARNING:
  2790. /*
  2791. The folllowing code is specific for the COMPAQ OHCI hardware
  2792. design -- it should not be executed on other controllers
  2793. */
  2794. /* Dummy ED must look like this:
  2795. ED->TD->XXX
  2796. XXX is bogus address 0xABADBABE
  2797. (HeadP points to TD)
  2798. (TailP points to XXX)
  2799. TD has CBP=0 and BE=0
  2800. NextTD points to XXX
  2801. TD will never be retired by the hardware
  2802. */
  2803. //
  2804. // create a dummy interrupt ED with period 1
  2805. //
  2806. deviceData = (PHCD_DEVICE_DATA) DeviceObject->DeviceExtension;
  2807. // Reserve the 17 dummy EDs+TDs
  2808. //
  2809. OpenHCI_ReserveDescriptors(deviceData, 34);
  2810. // add 17 dummy EDs+TDs
  2811. //
  2812. for (i=0; i< 17; i++) {
  2813. ed = InsertEDForEndpoint(deviceData, NULL, ED_INTERRUPT_1ms,
  2814. &td);
  2815. OHCI_ASSERT(td);
  2816. ed->Endpoint = NULL;
  2817. ed->HcED.FunctionAddress = 0;
  2818. ed->HcED.EndpointNumber = 0;
  2819. ed->HcED.Direction = 0;
  2820. ed->HcED.LowSpeed = 0;
  2821. ed->HcED.sKip = 1;
  2822. ed->HcED.Isochronous = 0;
  2823. ed->HcED.MaxPacket = 0;
  2824. //fixup the TD
  2825. td->Canceled = FALSE;
  2826. td->NextHcdTD = (PVOID)-1;
  2827. td->UsbdRequest = MAGIC_SIG;
  2828. td->HcTD.CBP = 0;
  2829. td->HcTD.BE = 0;
  2830. td->HcTD.Control = 0;
  2831. td->HcTD.NextTD = 0xABADBABE;
  2832. // set head/Tail pointers
  2833. // ed->HcED.HeadP = td->PhysicalAddress;
  2834. // ed->HcED.TailP = 0xABADBABE;
  2835. // turn it on
  2836. LOGENTRY(G, 'MagI', 0, ed, td);
  2837. //TEST_TRAP();
  2838. //ed->HcED.sKip = 0;
  2839. }
  2840. return STATUS_SUCCESS;
  2841. }
  2842. NTSTATUS
  2843. OpenHCI_ResurrectHC(
  2844. PHCD_DEVICE_DATA DeviceData
  2845. )
  2846. /*++
  2847. Attempt to resurrect the HC after we have determined that it is dead.
  2848. --*/
  2849. {
  2850. PHC_OPERATIONAL_REGISTER HC;
  2851. ULONG HccaFrameNumber;
  2852. ULONG HcControl;
  2853. ULONG HcHCCA;
  2854. ULONG HcControlHeadED;
  2855. ULONG HcBulkHeadED;
  2856. ULONG HcDoneHead;
  2857. ULONG HcFmInterval;
  2858. ULONG HcPeriodicStart;
  2859. ULONG HcLSThreshold;
  2860. ULONG port;
  2861. OpenHCI_KdPrint((1, "Resurrecting HC\n"));
  2862. // For diagnostic purposes, keep track of how many times the
  2863. // HC appears to have hung;
  2864. //
  2865. DeviceData->ResurrectHCCount++;
  2866. LOGENTRY(G, 'RHC!', DeviceData, DeviceData->ResurrectHCCount, 0);
  2867. //
  2868. // Get the pointer to the HC Operational Registers
  2869. //
  2870. HC = DeviceData->HC;
  2871. //
  2872. // Save the last FrameNumber from the HCCA from when the HC froze
  2873. //
  2874. HccaFrameNumber = DeviceData->HCCA->HccaFrameNumber;
  2875. //
  2876. // Read the HcDoneHead in case some TDs completed during the frame
  2877. // in which the HC froze.
  2878. //
  2879. HcDoneHead = READ_REGISTER_ULONG(&HC->HcDoneHead);
  2880. #if DBG
  2881. {
  2882. PPAGE_LIST_ENTRY pageList;
  2883. PHCD_TRANSFER_DESCRIPTOR td;
  2884. ULONG nullcount;
  2885. // Some TDs might have completed during the frame in which the
  2886. // HC froze. If that happened, one and only one TD should have
  2887. // a NULL NextTD pointer, and the HC->HcDoneHead register should
  2888. // still be pointing to the head of done queue.
  2889. //
  2890. // Assert that the current hardware state matches our assumptions.
  2891. //
  2892. nullcount = 0;
  2893. pageList = DeviceData->PageList;
  2894. while (pageList)
  2895. {
  2896. for (td = pageList->FirstTDVirt; td <= pageList->LastTDVirt; td++)
  2897. {
  2898. if (td->Flags == TD_FLAG_INUSE)
  2899. {
  2900. if (td->HcTD.NextTD == 0)
  2901. {
  2902. nullcount++;
  2903. }
  2904. }
  2905. }
  2906. pageList = pageList->NextPage;
  2907. }
  2908. OpenHCI_KdPrint((0, "Resurrecting HC, nullcount %d, HcDoneHead %08X\n",
  2909. nullcount, HcDoneHead));
  2910. OHCI_ASSERT(nullcount <= 1);
  2911. OHCI_ASSERT((nullcount != 0) == (HcDoneHead != 0));
  2912. }
  2913. #endif
  2914. //
  2915. // If the HcDoneHead is non-zero, the TDs which completed during the
  2916. // frame in which the HC froze will be processed the next time the
  2917. // ISR DPC runs.
  2918. //
  2919. HcDoneHead = InterlockedExchange(&DeviceData->FrozenHcDoneHead, HcDoneHead);
  2920. OHCI_ASSERT(HcDoneHead == 0);
  2921. //
  2922. // Save current HC operational register values
  2923. //
  2924. // offset 0x04, save HcControl
  2925. //
  2926. HcControl = READ_REGISTER_ULONG(&HC->HcControl.ul);
  2927. // offset 0x18, save HcHCCA
  2928. //
  2929. HcHCCA = READ_REGISTER_ULONG(&HC->HcHCCA);
  2930. // offset 0x20, save HcControlHeadED
  2931. //
  2932. HcControlHeadED = READ_REGISTER_ULONG(&HC->HcControlHeadED);
  2933. // offset 0x28, save HcBulkHeadED
  2934. //
  2935. HcBulkHeadED = READ_REGISTER_ULONG(&HC->HcBulkHeadED);
  2936. // offset 0x34, save HcFmInterval
  2937. //
  2938. HcFmInterval = READ_REGISTER_ULONG(&HC->HcFmInterval.ul);
  2939. // offset 0x40, save HcPeriodicStart
  2940. //
  2941. HcPeriodicStart = READ_REGISTER_ULONG(&HC->HcPeriodicStart);
  2942. // offset 0x44, save HcLSThreshold
  2943. //
  2944. HcLSThreshold = READ_REGISTER_ULONG(&HC->HcLSThreshold);
  2945. //
  2946. // Reset the host controller
  2947. //
  2948. WRITE_REGISTER_ULONG(&HC->HcCommandStatus.ul, HcCmd_HostControllerReset);
  2949. KeStallExecutionProcessor(10);
  2950. //
  2951. // Restore / reinitialize HC operational register values
  2952. //
  2953. // offset 0x08, HcCommandStatus is set to zero on reset
  2954. // offset 0x0C, HcInterruptStatus is set to zero on reset
  2955. // offset 0x10, HcInterruptEnable is set to zero on reset
  2956. // offset 0x14, HcInterruptDisable is set to zero on reset
  2957. // offset 0x18, restore HcHCCA
  2958. //
  2959. WRITE_REGISTER_ULONG(&HC->HcHCCA, HcHCCA);
  2960. // offset 0x1C, HcPeriodCurrentED is set to zero on reset
  2961. // offset 0x20, restore HcControlHeadED
  2962. //
  2963. WRITE_REGISTER_ULONG(&HC->HcControlHeadED, HcControlHeadED);
  2964. // offset 0x24, HcControlCurrentED is set to zero on reset
  2965. // offset 0x28, restore HcBulkHeadED
  2966. //
  2967. WRITE_REGISTER_ULONG(&HC->HcBulkHeadED, HcBulkHeadED);
  2968. // offset 0x2C, HcBulkCurrentED is set to zero on reset
  2969. // offset 0x30, HcDoneHead is set to zero on reset
  2970. // It appears that writes to HcFmInterval don't stick unless the HC
  2971. // is in the operational state. Set the HC into the operational
  2972. // state at this point, but don't enable any list processing yet
  2973. // by setting any of the BLE, CLE, IE, or PLE bits.
  2974. //
  2975. WRITE_REGISTER_ULONG(&HC->HcControl.ul, HcCtrl_HCFS_USBOperational);
  2976. // offset 0x34, restore HcFmInterval
  2977. //
  2978. WRITE_REGISTER_ULONG(&HC->HcFmInterval.ul,
  2979. HcFmInterval | HcFmI_FRAME_INTERVAL_TOGGLE);
  2980. // offset 0x38, HcFmRemaining is set to zero on reset
  2981. // offset 0x3C, restore HcFmNumber
  2982. //
  2983. WRITE_REGISTER_ULONG(&HC->HcFmNumber, HccaFrameNumber);
  2984. // offset 0x40, restore HcPeriodicStart
  2985. //
  2986. WRITE_REGISTER_ULONG(&HC->HcPeriodicStart, HcPeriodicStart);
  2987. // offset 0x44, restore HcLSThreshold
  2988. //
  2989. WRITE_REGISTER_ULONG(&HC->HcLSThreshold, HcLSThreshold);
  2990. // Power on downstream ports
  2991. //
  2992. WRITE_REGISTER_ULONG(&HC->HcRhStatus,
  2993. HcRhS_SetGlobalPower | HcRhS_SetRemoteWakeupEnable);
  2994. for (port = 0; port < DeviceData->NumberOfPorts; port++)
  2995. {
  2996. WRITE_REGISTER_ULONG(&HC->HcRhPortStatus[port], HcRhPS_SetPortPower);
  2997. }
  2998. // offset 0x04, restore HcControl
  2999. //
  3000. HcControl &= ~(HcCtrl_HCFS_MASK);
  3001. HcControl |= HcCtrl_HCFS_USBOperational;
  3002. WRITE_REGISTER_ULONG(&HC->HcControl.ul, HcControl);
  3003. // offset 0x10, restore HcInterruptEnable (just turn everything on!)
  3004. //
  3005. WRITE_REGISTER_ULONG(&HC->HcInterruptEnable,
  3006. HcInt_MasterInterruptEnable | // 0x80000000
  3007. HcInt_OwnershipChange | // 0x40000000
  3008. HcInt_RootHubStatusChange | // 0x00000040
  3009. HcInt_FrameNumberOverflow | // 0x00000020
  3010. HcInt_UnrecoverableError | // 0x00000010
  3011. HcInt_ResumeDetected | // 0x00000008
  3012. HcInt_StartOfFrame | // 0x00000004
  3013. HcInt_WritebackDoneHead | // 0x00000002
  3014. HcInt_SchedulingOverrun // 0x00000001
  3015. );
  3016. return STATUS_SUCCESS;
  3017. }
  3018. ULONG
  3019. FindLostDoneHead (
  3020. IN PHCD_DEVICE_DATA DeviceData
  3021. )
  3022. /*++
  3023. Attempt to find the lost head of the done TD queue.
  3024. --*/
  3025. {
  3026. PHC_OPERATIONAL_REGISTER HC;
  3027. PPAGE_LIST_ENTRY PageList;
  3028. PHCD_TRANSFER_DESCRIPTOR Td;
  3029. ULONG TdList1;
  3030. ULONG TdList2;
  3031. ULONG HcDoneHead;
  3032. BOOLEAN updated;
  3033. // For diagnostic purposes, keep track of how many times the
  3034. // HCCA->HccaDoneHead update appears to have been lost.
  3035. //
  3036. DeviceData->LostDoneHeadCount++;
  3037. LOGENTRY(G, 'FLst', DeviceData, DeviceData->LostDoneHeadCount, 0);
  3038. HC = DeviceData->HC;
  3039. TdList1 = 0;
  3040. TdList2 = 0;
  3041. HcDoneHead = 0;
  3042. //
  3043. // Scan the TD pool looking for TDs with a NULL NextTD pointer.
  3044. // A TD should only have NULL NextTD pointer if it is the tail of
  3045. // a done TD list. There might be two such lists: the list of TDs
  3046. // that were completed the last time the HC should have updated the
  3047. // HCCA->HccaDoneHead, and the list of TDs that have completed since
  3048. // then.
  3049. //
  3050. PageList = DeviceData->PageList;
  3051. while (PageList)
  3052. {
  3053. for (Td = PageList->FirstTDVirt; Td <= PageList->LastTDVirt; Td++)
  3054. {
  3055. if (Td->Flags == TD_FLAG_INUSE)
  3056. {
  3057. if (Td->HcTD.NextTD == 0)
  3058. {
  3059. // This TD has a NULL NextTD pointer. Save it as the
  3060. // tail of either TdList1 or TdList2.
  3061. //
  3062. if (TdList1 == 0)
  3063. {
  3064. TdList1 = Td->PhysicalAddress;
  3065. }
  3066. else
  3067. {
  3068. // We expect to find at most two TDs with NULL
  3069. // NextTD pointers.
  3070. //
  3071. OHCI_ASSERT(TdList2 == 0);
  3072. TdList2 = Td->PhysicalAddress;
  3073. }
  3074. }
  3075. }
  3076. }
  3077. PageList = PageList->NextPage;
  3078. }
  3079. if (TdList1 == 0)
  3080. {
  3081. // We found no TDs with NULL NextTD pointers.
  3082. //
  3083. return 0;
  3084. }
  3085. if (TdList2 != 0)
  3086. {
  3087. // There are two lists of completed TDs. One list should be
  3088. // pointed to by HCCA->HccaDoneHead, and the other list should be
  3089. // pointed to by HC->HcDoneHead. Read HC->HcDoneHead so we can
  3090. // determine which list is pointed to (or should have been pointed
  3091. // to) by HCCA->HccaDoneHead and which list is pointed to by
  3092. // HC->HcDoneHead.
  3093. //
  3094. HcDoneHead = READ_REGISTER_ULONG(&HC->HcDoneHead);
  3095. // If HC->HcDoneHead is NULL, then something is does not match our
  3096. // expectations.
  3097. //
  3098. OHCI_ASSERT(HcDoneHead != 0);
  3099. }
  3100. do
  3101. {
  3102. updated = FALSE;
  3103. if (HcDoneHead)
  3104. {
  3105. if (HcDoneHead == TdList1)
  3106. {
  3107. // TdList1 is pointed to by HC->HcDoneHead. Toss TdList1
  3108. // and keep TdList2
  3109. //
  3110. TdList1 = TdList2;
  3111. TdList2 = 0;
  3112. }
  3113. else if (HcDoneHead == TdList2)
  3114. {
  3115. // TdList2 is pointed to by HC->HcDoneHead. Toss TdList2
  3116. // and keep TdList1
  3117. //
  3118. TdList2 = 0;
  3119. }
  3120. }
  3121. //
  3122. // Scan the TD pool looking for TDs with NextTD pointers that
  3123. // point to the head of either TdList1 or TdList2. If such a TD
  3124. // is found, it becomes the new head of the appropriate list, and
  3125. // loop around at least one more time. If no such TD is found, then
  3126. // the current heads of the lists must be the true heads and we can
  3127. // quit looping.
  3128. //
  3129. PageList = DeviceData->PageList;
  3130. while (PageList)
  3131. {
  3132. for (Td = PageList->FirstTDVirt; Td <= PageList->LastTDVirt; Td++)
  3133. {
  3134. if ((Td->Flags == TD_FLAG_INUSE) && (Td->HcTD.NextTD != 0))
  3135. {
  3136. if (Td->HcTD.NextTD == TdList1)
  3137. {
  3138. TdList1 = Td->PhysicalAddress;
  3139. updated = TRUE;
  3140. }
  3141. else if (Td->HcTD.NextTD == TdList2)
  3142. {
  3143. TdList2 = Td->PhysicalAddress;
  3144. updated = TRUE;
  3145. }
  3146. }
  3147. }
  3148. PageList = PageList->NextPage;
  3149. }
  3150. } while (updated);
  3151. OHCI_ASSERT(TdList1 != 0);
  3152. OHCI_ASSERT(TdList2 == 0);
  3153. return TdList1;
  3154. }