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.

4993 lines
131 KiB

  1. /*++
  2. Copyright (c) 1995,1996 Microsoft Corporation
  3. :ts=4
  4. Module Name:
  5. uhcd.c
  6. Abstract:
  7. The UHC driver for USB, this module contains the initialization code.
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. 10-08-95 : created
  13. --*/
  14. #include "wdm.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. #include "stdarg.h"
  24. #include "stdio.h"
  25. #include "usbdi.h"
  26. #include "hcdi.h"
  27. #include "uhcd.h"
  28. #ifdef DRM_SUPPORT
  29. NTSTATUS
  30. UHCD_PreUSBD_SetContentId
  31. (
  32. IN PIRP irp,
  33. IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
  34. IN PKSDRMAUDIOSTREAM_CONTENTID pvData
  35. );
  36. NTSTATUS
  37. UHCD_PostUSBD_SetContentId
  38. (
  39. IN PIRP irp,
  40. IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
  41. IN PKSDRMAUDIOSTREAM_CONTENTID pvData
  42. );
  43. #endif
  44. #ifdef PAGE_CODE
  45. #ifdef ALLOC_PRAGMA
  46. // WIN98 breaks if we have an INIT segment
  47. //#pragma alloc_text(INIT, DriverEntry)
  48. #pragma alloc_text(PAGE, UHCD_CreateDeviceObject)
  49. #pragma alloc_text(PAGE, UHCD_ReadWriteConfig)
  50. #pragma alloc_text(PAGE, UHCD_QueryCapabilities)
  51. #pragma alloc_text(PAGE, UHCD_StartDevice)
  52. #pragma alloc_text(PAGE, UHCD_InitializeSchedule)
  53. #pragma alloc_text(PAGE, UHCD_StartGlobalReset)
  54. #pragma alloc_text(PAGE, UHCD_Suspend)
  55. #pragma alloc_text(PAGE, UHCD_StopBIOS)
  56. #ifdef DRM_SUPPORT
  57. #pragma alloc_text(PAGE, UHCD_PreUSBD_SetContentId)
  58. #pragma alloc_text(PAGE, UHCD_PostUSBD_SetContentId)
  59. #endif
  60. #endif
  61. #endif
  62. NTSTATUS
  63. DriverEntry(
  64. IN PDRIVER_OBJECT DriverObject,
  65. IN PUNICODE_STRING RegistryPath
  66. )
  67. /*++
  68. Routine Description:
  69. Installable driver initialization entry point.
  70. This entry point is called directly by the I/O system.
  71. Arguments:
  72. DriverObject - pointer to the driver object
  73. RegistryPath - pointer to a unicode string representing the path
  74. to driver-specific key in the registry
  75. Return Value:
  76. NT status code
  77. --*/
  78. {
  79. PDEVICE_OBJECT deviceObject = NULL;
  80. NTSTATUS ntStatus = STATUS_SUCCESS;
  81. UHCD_KdPrint((2, "'entering DriverEntry\n"));
  82. UHCD_KdPrint ((1, "'UHCI Universal Serial Bus Host Controller Driver.\n"));
  83. UHCD_KdPrint ((1, "'HCD using USBDI version %x\n", USBDI_VERSION));
  84. #ifdef DEBUG_LOG
  85. //
  86. // Initialize our debug trace log
  87. //
  88. UHCD_LogInit();
  89. #endif
  90. //
  91. // Create dispatch points for device control, create, close.
  92. //
  93. DriverObject->MajorFunction[IRP_MJ_CREATE]=
  94. DriverObject->MajorFunction[IRP_MJ_CLOSE] =
  95. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
  96. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] =
  97. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = UHCD_Dispatch;
  98. DriverObject->MajorFunction[IRP_MJ_PNP] = UHCD_Dispatch;
  99. DriverObject->MajorFunction[IRP_MJ_POWER] = UHCD_Dispatch;
  100. DriverObject->DriverExtension->AddDevice = UHCD_PnPAddDevice;
  101. DriverObject->DriverUnload = UHCD_Unload;
  102. DriverObject->DriverStartIo = UHCD_StartIo;
  103. return ntStatus;
  104. }
  105. NTSTATUS
  106. UHCD_ProcessPnPIrp(
  107. IN PDEVICE_OBJECT DeviceObject,
  108. IN PIRP Irp
  109. )
  110. /*++
  111. Routine Description:
  112. Process the Power IRPs sent to the PDO for this device.
  113. Arguments:
  114. DeviceObject - pointer to a hcd device object (FDO)
  115. Irp - pointer to an I/O Request Packet
  116. Return Value:
  117. NT status code
  118. --*/
  119. {
  120. PIO_STACK_LOCATION irpStack;
  121. NTSTATUS ntStatus = STATUS_SUCCESS;
  122. PDEVICE_EXTENSION deviceExtension;
  123. PDEVICE_OBJECT stackDeviceObject;
  124. BOOLEAN touchTheHardware = TRUE;
  125. UHCD_KdPrint((2, "'IRP_MJ_PNP\n"));
  126. // we should only process PnP messages sent to our
  127. // FDO for the HCD, USBD will handle any others.
  128. // UHCD_ASSERT(DeviceObject == hcdDeviceObject);
  129. irpStack = IoGetCurrentIrpStackLocation(Irp);
  130. deviceExtension = DeviceObject->DeviceExtension;
  131. UHCD_PrintPnPMessage("PNP DISPATCH:", irpStack->MinorFunction);
  132. UHCD_ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
  133. switch (irpStack->MinorFunction) {
  134. case IRP_MN_START_DEVICE:
  135. //
  136. // USB handles start for us so we
  137. // should not get here.
  138. //
  139. LOGENTRY(LOG_MISC, 'STR!', deviceExtension->TopOfStackDeviceObject, 0, 0);
  140. UHCD_KdTrap(("HCD START_DEVICE Irp\n"));
  141. break;
  142. //
  143. // STOP & REMOVE messages unload the driver
  144. // when we get a STOP message it is still possible
  145. // touch the hardware, when we get a REMOVE message
  146. // we have to assume that the hardware is gone.
  147. //
  148. case IRP_MN_STOP_DEVICE:
  149. stackDeviceObject = deviceExtension->TopOfStackDeviceObject;
  150. ntStatus = UHCD_StopDevice(DeviceObject);
  151. UHCD_CleanupDevice(DeviceObject);
  152. LOGENTRY(LOG_MISC, 'STOP', deviceExtension->TopOfStackDeviceObject, 0, 0);
  153. // Pass on to PDO
  154. break;
  155. case IRP_MN_SURPRISE_REMOVAL:
  156. touchTheHardware = FALSE;
  157. LOGENTRY(LOG_MISC, 'SRMV', deviceExtension->TopOfStackDeviceObject,
  158. ntStatus, 0);
  159. case IRP_MN_REMOVE_DEVICE:
  160. stackDeviceObject = deviceExtension->TopOfStackDeviceObject;
  161. //
  162. // BUGBUG
  163. // we really only want stop processing if we are
  164. // sure the device is present.
  165. //
  166. ntStatus = UHCD_StopDevice(DeviceObject);
  167. UHCD_CleanupDevice(DeviceObject);
  168. LOGENTRY(LOG_MISC, 'REMV', deviceExtension->TopOfStackDeviceObject,
  169. ntStatus, 0);
  170. //
  171. // Undo anything we did in the PnPAddDevice function
  172. //
  173. UHCD_KdPrint((2, "'UHCD -- removing device object\n"));
  174. //
  175. // Detach FDO from PDO
  176. //
  177. IoCopyCurrentIrpStackLocationToNext(Irp);
  178. //
  179. // pass on to our PDO
  180. //
  181. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  182. Irp);
  183. //
  184. // important to detach after we pass the irp on
  185. //
  186. IoDetachDevice( deviceExtension->TopOfStackDeviceObject );
  187. USBD_FreeDeviceName(deviceExtension->DeviceNameHandle);
  188. //
  189. // Delete the device object we created for this controller
  190. //
  191. IoDeleteDevice (DeviceObject);
  192. goto UHCD_ProcessPnPIrp_Done;
  193. break;
  194. //
  195. // All other PnP messages passed on to our PDO
  196. //
  197. default:
  198. stackDeviceObject = deviceExtension->TopOfStackDeviceObject;
  199. UHCD_ASSERT(stackDeviceObject != NULL);
  200. UHCD_KdPrint((2, "'UNKNOWN PNP MESSAGE (%x)\n", irpStack->MinorFunction));
  201. //
  202. // All unahndled PnP messages are passed on to the PDO
  203. //
  204. } /* case PNP minor function */
  205. IoCopyCurrentIrpStackLocationToNext(Irp);
  206. //
  207. // pass on to our PDO
  208. //
  209. ntStatus = IoCallDriver(stackDeviceObject,
  210. Irp);
  211. UHCD_ProcessPnPIrp_Done:
  212. return ntStatus;
  213. }
  214. #ifdef DRM_SUPPORT
  215. NTSTATUS
  216. UHCD_PreUSBD_SetContentId
  217. (
  218. IN PIRP irp,
  219. IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
  220. IN PKSDRMAUDIOSTREAM_CONTENTID pvData
  221. )
  222. /* ++
  223. *
  224. * Description:
  225. *
  226. *
  227. * Arguments:
  228. *
  229. * Return:
  230. *
  231. * -- */
  232. {
  233. PVOID Handlers[1];
  234. ULONG ContentId;
  235. PAGED_CODE();
  236. ASSERT(irp);
  237. ASSERT(pKsProperty);
  238. ASSERT(pvData);
  239. ContentId = pvData->ContentId;
  240. Handlers[0] = USBD_Dispatch;
  241. return pKsProperty->DrmAddContentHandlers(ContentId, Handlers, SIZEOF_ARRAY(Handlers));
  242. }
  243. NTSTATUS
  244. UHCD_PostUSBD_SetContentId
  245. (
  246. IN PIRP irp,
  247. IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
  248. IN PKSDRMAUDIOSTREAM_CONTENTID pvData
  249. )
  250. /* ++
  251. *
  252. * Description:
  253. *
  254. *
  255. * Arguments:
  256. *
  257. * Return:
  258. *
  259. * -- */
  260. {
  261. NTSTATUS ntStatus;
  262. PAGED_CODE();
  263. ASSERT(irp);
  264. ASSERT(pKsProperty);
  265. ASSERT(pvData);
  266. // ioStackLocation = IoGetCurrentIrpStackLocation(irp);
  267. // deviceExtension = ioStackLocation->DeviceObject->DeviceExtension;
  268. // Context = pKsProperty->Context;
  269. // ContentId = pvData->ContentId;;
  270. return STATUS_SUCCESS;
  271. }
  272. #endif
  273. NTSTATUS
  274. UHCD_Dispatch(
  275. IN PDEVICE_OBJECT DeviceObject,
  276. IN PIRP Irp
  277. )
  278. /*++
  279. Routine Description:
  280. Process the IRPs sent to this device.
  281. Power States for the USB host controller
  282. D0 - On.
  283. D1 - USB defined Suspend per 1.00 specification.
  284. D2 - undefined, reserved for future use.
  285. D3 - Off
  286. Arguments:
  287. DeviceObject - pointer to a device object
  288. Irp - pointer to an I/O Request Packet
  289. Return Value:
  290. NT status code
  291. --*/
  292. {
  293. PIO_STACK_LOCATION irpStack;
  294. NTSTATUS ntStatus = STATUS_SUCCESS;
  295. PDEVICE_EXTENSION deviceExtension;
  296. PDEVICE_OBJECT hcdDeviceObject;
  297. UHCD_KdPrint((2, "'enter UHCD_Dispatch\n"));
  298. #ifdef DRM_SUPPORT
  299. //
  300. // Need to check DRM request before passing to USBD and advise DRM of
  301. // the USBD entry point. Otherwise, a rogue USBD could circumvent DRM.
  302. //
  303. irpStack = IoGetCurrentIrpStackLocation (Irp);
  304. if (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction && IOCTL_KS_PROPERTY == irpStack->Parameters.DeviceIoControl.IoControlCode) {
  305. NTSTATUS ntStatus;
  306. ntStatus = KsPropertyHandleDrmSetContentId(Irp, UHCD_PreUSBD_SetContentId);
  307. if (!NT_SUCCESS(ntStatus) && ntStatus != STATUS_PROPSET_NOT_FOUND) {
  308. Irp->IoStatus.Status = ntStatus;
  309. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  310. return ntStatus;
  311. }
  312. }
  313. #endif
  314. //
  315. // pass the irp to USBD
  316. //
  317. if (!USBD_Dispatch(DeviceObject,
  318. Irp,
  319. &hcdDeviceObject,
  320. &ntStatus)) {
  321. //
  322. // Irp was completed by USBD just exit our dispatch
  323. // routine.
  324. //
  325. goto UHCD_Dispatch_Done;
  326. }
  327. deviceExtension = (PDEVICE_EXTENSION) hcdDeviceObject->DeviceExtension;
  328. irpStack = IoGetCurrentIrpStackLocation (Irp);
  329. UHCD_KdPrint((2, "'UHCD_Dispatch IRP = %x, stack = %x\n", Irp, irpStack));
  330. switch (irpStack->MajorFunction) {
  331. case IRP_MJ_CREATE:
  332. UHCD_KdPrint((2, "'IRP_MJ_CREATE\n"));
  333. UHCD_CompleteIrp(hcdDeviceObject, Irp, ntStatus, 0, NULL);
  334. break;
  335. case IRP_MJ_CLOSE:
  336. UHCD_KdPrint((2, "'IRP_MJ_CLOSE\n"));
  337. UHCD_CompleteIrp(hcdDeviceObject, Irp, ntStatus, 0, NULL);
  338. break;
  339. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  340. UHCD_KdPrint((2, "'IRP_MJ_INTERNAL_DEVICE_CONTROL\n"));
  341. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  342. case IOCTL_INTERNAL_USB_SUBMIT_URB:
  343. UHCD_KdPrint((2, "'IOCTL_USB_SUBMIT_URB\n"));
  344. ntStatus = UHCD_URB_Dispatch(hcdDeviceObject, Irp);
  345. break;
  346. default:
  347. // this IOCTL not handled by the HCD, we need
  348. // to invetigate why
  349. UHCD_KdTrap(("why is this IOCTL NOT HANDLED by HCD?\n"));
  350. // BUGBUG
  351. UHCD_CompleteIrp(hcdDeviceObject, Irp, STATUS_SUCCESS, 0, NULL);
  352. break;
  353. } /* case */
  354. break;
  355. case IRP_MJ_DEVICE_CONTROL:
  356. UHCD_KdPrint((2, "'IRP_MJ_DEVICE_CONTROL\n"));
  357. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  358. #ifdef DRM_SUPPORT
  359. case IOCTL_KS_PROPERTY:
  360. {
  361. ntStatus = KsPropertyHandleDrmSetContentId(Irp, UHCD_PostUSBD_SetContentId);
  362. UHCD_CompleteIrp(hcdDeviceObject, Irp, ntStatus, 0, NULL);
  363. break;
  364. }
  365. #endif
  366. case IOCTL_USB_HCD_GET_STATS_1:
  367. {
  368. PVOID ioBuffer;
  369. ULONG inputBufferLength;
  370. ULONG outputBufferLength;
  371. PHCD_STAT_INFORMATION_1 uhcdStatInfo;
  372. UHCD_KdPrint((1, "'IOCTL_USB_HCD_GET_STATS 1\n"));
  373. //
  374. // Get a pointer to the current location in the Irp. This is where
  375. // the function codes and parameters are located.
  376. //
  377. irpStack = IoGetCurrentIrpStackLocation (Irp);
  378. //
  379. // Get the pointer to the input/output buffer and it's length
  380. //
  381. uhcdStatInfo = (PHCD_STAT_INFORMATION_1) ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  382. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  383. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  384. if (outputBufferLength >= sizeof(HCD_STAT_INFORMATION_1)) {
  385. //
  386. // return the IOBASE address of the controller
  387. // followed by the Phys address of the persistent queue head
  388. //
  389. // This is for Intels TD-Poker app on Memphis
  390. #ifdef NTKERN
  391. uhcdStatInfo->Reserved1 =
  392. *((PULONG) &deviceExtension->DeviceRegisters[0]);
  393. uhcdStatInfo->Reserved2 =
  394. (ULONG) deviceExtension->PersistantQueueHead->PhysicalAddress;
  395. #endif
  396. // reg counters
  397. RtlCopyMemory(&uhcdStatInfo->Counters,
  398. &deviceExtension->Stats,
  399. sizeof(uhcdStatInfo->Counters));
  400. KeQuerySystemTime(&uhcdStatInfo->TimeRead);
  401. if (uhcdStatInfo->ResetCounters) {
  402. UHCD_KdPrint((1, "'<Reset Stats>\n"));
  403. RtlZeroMemory(&deviceExtension->Stats,
  404. sizeof(deviceExtension->Stats));
  405. }
  406. ntStatus = STATUS_SUCCESS;
  407. } else {
  408. ntStatus = STATUS_BUFFER_TOO_SMALL;
  409. }
  410. UHCD_KdPrint((2, "'inputBufferLength = %d outputBufferLength = %d\n",
  411. inputBufferLength, outputBufferLength));
  412. UHCD_CompleteIrp(hcdDeviceObject, Irp, ntStatus,
  413. sizeof(HCD_STAT_INFORMATION_1), NULL);
  414. }
  415. break;
  416. case IOCTL_USB_HCD_GET_STATS_2:
  417. {
  418. PVOID ioBuffer;
  419. ULONG inputBufferLength;
  420. ULONG outputBufferLength;
  421. PHCD_STAT_INFORMATION_2 uhcdStatInfo;
  422. UHCD_KdPrint((1, "'IOCTL_USB_HCD_GET_STATS 2\n"));
  423. //
  424. // Get a pointer to the current location in the Irp. This is where
  425. // the function codes and parameters are located.
  426. //
  427. irpStack = IoGetCurrentIrpStackLocation (Irp);
  428. //
  429. // Get the pointer to the input/output buffer and it's length
  430. //
  431. uhcdStatInfo = (PHCD_STAT_INFORMATION_2) ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  432. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  433. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  434. if (outputBufferLength >= sizeof(HCD_STAT_INFORMATION_2)) {
  435. extern LONG UHCD_CommonBufferBytes;
  436. //
  437. // return the IOBASE address of the controller
  438. // followed by the Phys address of the persistent queue head
  439. //
  440. // This is for Intels TD-Poker app on Memphis
  441. #ifdef NTKERN
  442. uhcdStatInfo->Reserved1 =
  443. *((PULONG) &deviceExtension->DeviceRegisters[0]);
  444. uhcdStatInfo->Reserved2 =
  445. (ULONG) deviceExtension->PersistantQueueHead->PhysicalAddress;
  446. #endif
  447. // reg counters
  448. RtlCopyMemory(&uhcdStatInfo->Counters,
  449. &deviceExtension->Stats,
  450. sizeof(uhcdStatInfo->Counters));
  451. // iso counters
  452. RtlCopyMemory(&uhcdStatInfo->IsoCounters,
  453. &deviceExtension->IsoStats,
  454. sizeof(uhcdStatInfo->IsoCounters));
  455. KeQuerySystemTime(&uhcdStatInfo->TimeRead);
  456. uhcdStatInfo->LockedMemoryUsed = UHCD_CommonBufferBytes;
  457. if (uhcdStatInfo->ResetCounters) {
  458. UHCD_KdPrint((1, "'<Reset Stats>\n"));
  459. RtlZeroMemory(&deviceExtension->Stats,
  460. sizeof(deviceExtension->Stats));
  461. RtlZeroMemory(&deviceExtension->IsoStats,
  462. sizeof(deviceExtension->IsoStats));
  463. deviceExtension->LastFrameInterrupt = 0;
  464. }
  465. ntStatus = STATUS_SUCCESS;
  466. } else {
  467. ntStatus = STATUS_BUFFER_TOO_SMALL;
  468. }
  469. UHCD_KdPrint((2, "'inputBufferLength = %d outputBufferLength = %d\n",
  470. inputBufferLength, outputBufferLength));
  471. UHCD_CompleteIrp(hcdDeviceObject, Irp, ntStatus,
  472. sizeof(HCD_STAT_INFORMATION_2), NULL);
  473. }
  474. break;
  475. #if DBG
  476. //
  477. // This is a test IOCTL only in debug versions
  478. //
  479. case IOCTL_USB_HCD_DISABLE_PORT:
  480. {
  481. PVOID ioBuffer;
  482. ULONG inputBufferLength;
  483. ULONG outputBufferLength;
  484. PIO_STACK_LOCATION pIrpSp;
  485. ULONG portIndex;
  486. PROOTHUB pRootHub;
  487. pIrpSp = IoGetCurrentIrpStackLocation(Irp);
  488. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  489. pRootHub = deviceExtension->RootHub;
  490. inputBufferLength
  491. = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  492. if (inputBufferLength < sizeof(ULONG)) {
  493. ntStatus = STATUS_BUFFER_TOO_SMALL;
  494. goto IoctlDisablePortError;
  495. }
  496. portIndex = *(ULONG *)ioBuffer;
  497. if (portIndex >= pRootHub->NumberOfPorts) {
  498. ntStatus = STATUS_INVALID_PARAMETER;
  499. goto IoctlDisablePortError;
  500. }
  501. //
  502. // Flag the port as having no devices in there and
  503. // status changed.
  504. //
  505. pRootHub->DisabledPort[portIndex]
  506. |= UHCD_FAKE_CONNECT_CHANGE | UHCD_FAKE_DISCONNECT;
  507. IoctlDisablePortError:;
  508. //
  509. // Complete the IRP
  510. //
  511. UHCD_CompleteIrp(hcdDeviceObject, Irp, ntStatus, 0, NULL);
  512. }
  513. break;
  514. case IOCTL_USB_HCD_ENABLE_PORT:
  515. {
  516. PVOID ioBuffer;
  517. ULONG inputBufferLength;
  518. ULONG outputBufferLength;
  519. PIO_STACK_LOCATION pIrpSp;
  520. ULONG portIndex;
  521. PROOTHUB pRootHub;
  522. pIrpSp = IoGetCurrentIrpStackLocation(Irp);
  523. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  524. pRootHub = deviceExtension->RootHub;
  525. inputBufferLength
  526. = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  527. if (inputBufferLength < sizeof(ULONG)) {
  528. ntStatus = STATUS_BUFFER_TOO_SMALL;
  529. goto IoctlEnablePortError;
  530. }
  531. portIndex = *(ULONG *)ioBuffer;
  532. if (portIndex >= pRootHub->NumberOfPorts) {
  533. ntStatus = STATUS_INVALID_PARAMETER;
  534. goto IoctlEnablePortError;
  535. }
  536. //
  537. // Flag the port as having no devices in there and
  538. // status changed.
  539. //
  540. pRootHub->DisabledPort[portIndex] = UHCD_FAKE_CONNECT_CHANGE;
  541. IoctlEnablePortError:;
  542. //
  543. // Complete the IRP
  544. //
  545. UHCD_CompleteIrp(hcdDeviceObject, Irp, ntStatus, 0, NULL);
  546. }
  547. break;
  548. #endif
  549. default:
  550. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  551. UHCD_CompleteIrp(hcdDeviceObject, Irp,
  552. STATUS_INVALID_DEVICE_REQUEST, 0, NULL);
  553. } /* case */
  554. break;
  555. //
  556. // Process PnP and Power messages
  557. //
  558. case IRP_MJ_POWER:
  559. // should not get here
  560. UHCD_KdTrap(("Power Message to HCD\n"));
  561. break;
  562. case IRP_MJ_PNP:
  563. ntStatus = UHCD_ProcessPnPIrp(hcdDeviceObject, Irp);
  564. break;
  565. default:
  566. UHCD_KdPrint((2, "'unrecognized IRP_MJ_ function (%x)\n", irpStack->MajorFunction));
  567. ntStatus = STATUS_INVALID_PARAMETER;
  568. UHCD_CompleteIrp(hcdDeviceObject, Irp, ntStatus, 0, NULL);
  569. } /* case MJ_FUNCTION */
  570. UHCD_Dispatch_Done:
  571. UHCD_KdPrint((2, "'exit UHCD_Dispatch 0x%x\n", ntStatus));
  572. return ntStatus;
  573. }
  574. NTSTATUS
  575. UHCD_SetDevicePowerState(
  576. IN PDEVICE_OBJECT DeviceObject,
  577. IN PIRP Irp,
  578. IN DEVICE_POWER_STATE DeviceState
  579. )
  580. /*++
  581. Routine Description:
  582. Arguments:
  583. DeviceObject - Pointer to the device object for the class device.
  584. Irp - Irp completed.
  585. DeviceState - Device specific power state to set the device in to.
  586. Return Value:
  587. --*/
  588. {
  589. NTSTATUS ntStatus = STATUS_SUCCESS;
  590. PDEVICE_EXTENSION deviceExtension;
  591. BOOLEAN hookIt = FALSE;
  592. PIO_STACK_LOCATION irpStack;
  593. PUSBD_EXTENSION usbdExtension;
  594. PDEVICE_CAPABILITIES hcDeviceCapabilities;
  595. BOOLEAN bIsSuspend;
  596. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  597. irpStack = IoGetCurrentIrpStackLocation (Irp);
  598. if (irpStack->Parameters.Power.Type ==
  599. SystemPowerState) {
  600. switch (irpStack->Parameters.Power.State.SystemState) {
  601. case PowerSystemSleeping1:
  602. case PowerSystemSleeping2:
  603. case PowerSystemSleeping3:
  604. // suspend coming thru
  605. UHCD_KdPrint((1, "'Shutdown (Suspend) Host Controller\n"));
  606. deviceExtension->HcFlags |= HCFLAG_SUSPEND_NEXT_D3;
  607. ntStatus = STATUS_SUCCESS;
  608. break;
  609. case PowerSystemShutdown:
  610. //
  611. // this is a shutdown request
  612. //
  613. UHCD_KdPrint((1, "'Shutdown Host Controller\n"));
  614. //
  615. // do a stop to unhook the interrupt
  616. //
  617. UHCD_StopDevice(DeviceObject);
  618. #ifdef NTKERN
  619. //
  620. // now give control back to the BIOS if we have one
  621. //
  622. if (deviceExtension->HcFlags & HCFLAG_USBBIOS) {
  623. UHCD_StartBIOS(DeviceObject);
  624. }
  625. #endif
  626. ntStatus = STATUS_SUCCESS;
  627. break;
  628. default:
  629. // should not get here
  630. TRAP();
  631. break;
  632. }
  633. } else {
  634. bIsSuspend = (deviceExtension->HcFlags & HCFLAG_SUSPEND_NEXT_D3) ? 1:0;
  635. deviceExtension->HcFlags &= ~HCFLAG_SUSPEND_NEXT_D3;
  636. switch (DeviceState) {
  637. case PowerDeviceD3:
  638. //
  639. // Request for HC to power off
  640. // we will:
  641. //
  642. // 1. stop the controller schedule
  643. // 2. clean up the schedule
  644. // 3. reset the frame counter
  645. //
  646. LOGENTRY(LOG_MISC, 'D3go', deviceExtension, 0, 0);
  647. // it is possible (although remote) to are get a D3 with no
  648. // root hub attached if so we will turn off the hardware here
  649. if (!(deviceExtension->HcFlags & HCFLAG_RH_OFF)) {
  650. UHCD_SaveHCstate(DeviceObject);
  651. UHCD_Suspend(DeviceObject, FALSE);
  652. }
  653. UHCD_KdPrint((2, "'PowerDeviceD3 (OFF)\n"));
  654. // In the NT power management model, D3 is not necessarily "OFF".
  655. // What governs this is the DeviceWake setting in the DeviceCaps
  656. // structure. If DeviceWake for our controller device is D3, then
  657. // we know that it is possible for the controller to wake the
  658. // machine from this power level. The controller must have power
  659. // to be able to do so, therefore, we suppress setting the
  660. // HCFLAG_LOST_POWER flag in this case. Setting it actually has
  661. // the undesired effect of causing us to reset the controller on
  662. // resume, which in turn causes the hub to fail and the devices to
  663. // be surprise removed/reenumerated unnecessarily when the hub is
  664. // reinitialized. This normally isn't more than a minor annoyance
  665. // (e.g. slow resume time), except in the case where one of these
  666. // devices is a USB mass storage device. Surprise removal is
  667. // dangerous for mass storage devices, and the user is presented
  668. // with the annoying "don't surprise remove this device" dialog
  669. // when the system is resumed, even though the user himself did not
  670. // directly cause the device removal.
  671. //
  672. // Note that the case where the host controller really does lose
  673. // power could result in the same problem, but that will have to
  674. // be addressed in the hub driver.
  675. usbdExtension = (PUSBD_EXTENSION)deviceExtension;
  676. hcDeviceCapabilities = &usbdExtension->HcDeviceCapabilities;
  677. if (!bIsSuspend ||
  678. DeviceState > hcDeviceCapabilities->DeviceWake) {
  679. deviceExtension->HcFlags |= HCFLAG_LOST_POWER;
  680. UHCD_KdPrint((1, "'HC will lose power in D3\n"));
  681. }
  682. #if DBG
  683. else {
  684. UHCD_KdPrint((1, "'HC will NOT lose power in D3\n"));
  685. }
  686. #endif
  687. // ensure no interrupts are generated by the controller
  688. {
  689. USHORT legsup;
  690. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  691. TRUE,
  692. &legsup,
  693. 0xc0, // offset of legacy bios reg
  694. sizeof(legsup));
  695. LOGENTRY(LOG_MISC, 'PIRd', deviceExtension, legsup, 0);
  696. // clear the PIRQD routing bit
  697. legsup &= ~LEGSUP_USBPIRQD_EN;
  698. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  699. FALSE,
  700. &legsup,
  701. 0xc0, // offset of legacy bios reg
  702. sizeof(legsup));
  703. }
  704. deviceExtension->CurrentDevicePowerState = DeviceState;
  705. UHCD_KdPrint((1, "'Host Controller entered (D%d)\n", DeviceState-1));
  706. // pass on to PDO
  707. break;
  708. case PowerDeviceD1:
  709. case PowerDeviceD2:
  710. //
  711. // power states D1,D2 translate to USB suspend
  712. UHCD_KdPrint((2, "'PowerDeviceD1/D2 (SUSPEND) HC\n"));
  713. #ifdef DEBUG_LOG
  714. if (DeviceState == PowerDeviceD1) {
  715. LOGENTRY(LOG_MISC, 'D1go', deviceExtension, 0, 0);
  716. } else {
  717. LOGENTRY(LOG_MISC, 'D2go', deviceExtension, 0, 0);
  718. }
  719. #endif
  720. // change the state of the PRIQD routing bit
  721. {
  722. USHORT legsup;
  723. UHCD_ReadWriteConfig( deviceExtension->PhysicalDeviceObject,
  724. TRUE,
  725. &legsup,
  726. 0xc0, // offset of legacy bios reg
  727. sizeof(legsup));
  728. LOGENTRY(LOG_MISC, 'PIRd', deviceExtension, legsup, 0);
  729. // clear the PIRQD routing bit
  730. legsup &= ~LEGSUP_USBPIRQD_EN;
  731. UHCD_ReadWriteConfig( deviceExtension->PhysicalDeviceObject,
  732. FALSE,
  733. &legsup,
  734. 0xc0, // offset of legacy bios reg
  735. sizeof(legsup));
  736. }
  737. //
  738. // Note, we should not get here unless all the children of the HC
  739. // have been suspended.
  740. //
  741. deviceExtension->CurrentDevicePowerState = DeviceState;
  742. UHCD_KdPrint((1, "'Host Controller entered (D%d)\n", DeviceState-1));
  743. // pass on to PDO
  744. break;
  745. case PowerDeviceD0:
  746. //
  747. // Request for HC to go to resume
  748. // we will:
  749. //
  750. // 1. start the controller in the completetion routine
  751. //
  752. UHCD_KdPrint((2, "'PowerDeviceD0 (ON), defer\n"));
  753. LOGENTRY(LOG_MISC, 'D0go', deviceExtension, 0, 0);
  754. //
  755. // finish the rest in the completion routine
  756. //
  757. hookIt = TRUE;
  758. // pass on to PDO
  759. break;
  760. default:
  761. UHCD_KdTrap(("Bogus DeviceState = %x\n", DeviceState));
  762. }
  763. if (hookIt) {
  764. UHCD_KdPrint((2, "'Set PowerIrp Completion Routine\n"));
  765. IoSetCompletionRoutine(Irp,
  766. UHCD_PowerIrp_Complete,
  767. // always pass FDO to completion routine
  768. DeviceObject,
  769. hookIt,
  770. hookIt,
  771. hookIt);
  772. }
  773. }
  774. return ntStatus;
  775. }
  776. NTSTATUS
  777. UHCD_PowerIrp_Complete(
  778. IN PDEVICE_OBJECT DeviceObject,
  779. IN PIRP Irp,
  780. IN PVOID Context
  781. )
  782. /*++
  783. Routine Description:
  784. This routine is called when the port driver completes an IRP.
  785. Arguments:
  786. DeviceObject - Pointer to the device object for the class device.
  787. Irp - Irp completed.
  788. Context - Driver defined context.
  789. Return Value:
  790. The function value is the final status from the operation.
  791. --*/
  792. {
  793. PDEVICE_OBJECT deviceObject;
  794. PIO_STACK_LOCATION irpStack;
  795. PDEVICE_EXTENSION deviceExtension;
  796. NTSTATUS ntStatus;
  797. UHCD_KdPrint((2, "' enter UHCD_PowerIrp_Complete\n"));
  798. deviceObject = (PDEVICE_OBJECT) Context;
  799. deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  800. irpStack = IoGetCurrentIrpStackLocation (Irp);
  801. UHCD_KdPrint((1, "'Controller is in D0\n"));
  802. LOGENTRY(LOG_MISC, 'POWc', deviceExtension->CurrentDevicePowerState,
  803. 0, Irp);
  804. // This function should only be called whe the controller
  805. // is put in D0
  806. UHCD_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
  807. UHCD_ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
  808. UHCD_ASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
  809. UHCD_ASSERT(irpStack->Parameters.Power.State.DeviceState==PowerDeviceD0);
  810. #ifdef JD
  811. //TEST_TRAP();
  812. #endif
  813. ntStatus = deviceExtension->LastPowerUpStatus = Irp->IoStatus.Status;
  814. if (NT_SUCCESS(ntStatus)) {
  815. deviceExtension->CurrentDevicePowerState = PowerDeviceD0;
  816. }
  817. UHCD_KdPrint((2, "' exit UHCD_PowerIrp_Complete\n"));
  818. return ntStatus;
  819. }
  820. VOID
  821. UHCD_Unload(
  822. IN PDRIVER_OBJECT DriverObject
  823. )
  824. /*++
  825. Routine Description:
  826. Free all the allocated resources, etc.
  827. Arguments:
  828. DriverObject - pointer to a driver object
  829. Return Value:
  830. None
  831. --*/
  832. {
  833. //
  834. // Free any global resources
  835. //
  836. UHCD_KdPrint((2, "'unloading\n"));
  837. #ifdef DEBUG_LOG
  838. //
  839. // free our debug trace log
  840. //
  841. UHCD_LogFree();
  842. #endif
  843. }
  844. NTSTATUS
  845. UHCD_CreateDeviceObject(
  846. IN PDRIVER_OBJECT DriverObject,
  847. IN OUT PDEVICE_OBJECT *DeviceObject,
  848. IN PUNICODE_STRING DeviceNameUnicodeString
  849. )
  850. /*++
  851. Routine Description:
  852. This routine is called to create a new instance of a USB host
  853. controller.
  854. Arguments:
  855. DriverObject - pointer to the driver object for USBD.
  856. *DeviceObject - ptr to DeviceObject ptr to be filled
  857. in with the device object we create.
  858. Configuration - ptr to configuration data to be stored
  859. in the device extension.
  860. DeviceNameUnicodeString - optional pointer to a device
  861. name for this FDO, can be NULL
  862. Return Value:
  863. NT status code
  864. --*/
  865. {
  866. NTSTATUS ntStatus;
  867. PDEVICE_EXTENSION deviceExtension;
  868. PAGED_CODE();
  869. UHCD_KdPrint((2, "'enter UHCD_CreateDeviceObject\n"));
  870. ntStatus = IoCreateDevice(DriverObject,
  871. sizeof (DEVICE_EXTENSION),
  872. DeviceNameUnicodeString, // Name
  873. FILE_DEVICE_CONTROLLER,
  874. 0,
  875. FALSE, //NOT Exclusive
  876. DeviceObject);
  877. if (NT_SUCCESS(ntStatus)) {
  878. deviceExtension = (PDEVICE_EXTENSION) ((*DeviceObject)->DeviceExtension);
  879. UHCD_KdPrint((2, "'UHCD_CreateDeviceObject: device object %x device extension = %x\n",
  880. *DeviceObject, deviceExtension));
  881. } else if (*DeviceObject) {
  882. IoDeleteDevice(*DeviceObject);
  883. }
  884. UHCD_KdPrint((2, "'exit UHCD_CreateDeviceObject (%x)\n", ntStatus));
  885. return ntStatus;
  886. }
  887. NTSTATUS
  888. UHCD_PnPAddDevice(
  889. IN PDRIVER_OBJECT DriverObject,
  890. IN PDEVICE_OBJECT PhysicalDeviceObject
  891. )
  892. /*++
  893. Routine Description:
  894. This routine is called to create a new instance of a USB host controller
  895. Arguments:
  896. DriverObject - pointer to the driver object for this instance of UHCD
  897. PhysicalDeviceObject - pointer to a device object created by the bus
  898. Return Value:
  899. STATUS_SUCCESS if successful,
  900. STATUS_UNSUCCESSFUL otherwise
  901. --*/
  902. {
  903. NTSTATUS ntStatus;
  904. PDEVICE_OBJECT deviceObject = NULL;
  905. PDEVICE_EXTENSION deviceExtension;
  906. UNICODE_STRING deviceNameUnicodeString;
  907. ULONG deviceNameHandle;
  908. ULONG disableController = 0;
  909. UHCD_KdBreak((2, "'UHCD_PnPAddDevice\n"));
  910. LOGENTRY(LOG_MISC, 'ADDd', 0, 0, PhysicalDeviceObject);
  911. //#ifdef JD
  912. // TEST_TRAP();
  913. //#endif
  914. //UHCD_GetGlobalRegistryParameters(&disableController);
  915. if (disableController) {
  916. ntStatus = STATUS_UNSUCCESSFUL;
  917. goto UHCD_PnPAddDevice_Done;
  918. }
  919. //
  920. // Let USBD generate a device name
  921. //
  922. deviceNameHandle = USBD_AllocateDeviceName(&deviceNameUnicodeString);
  923. ntStatus = UHCD_CreateDeviceObject( DriverObject,
  924. &deviceObject,
  925. &deviceNameUnicodeString);
  926. LOGENTRY(LOG_MISC, 'cdnS', 0, 0, ntStatus);
  927. if (NT_SUCCESS(ntStatus)) {
  928. deviceExtension = deviceObject->DeviceExtension;
  929. RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
  930. deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
  931. deviceExtension->DeviceNameHandle = deviceNameHandle;
  932. //
  933. // until we get a start we will comsider ourselves OFF
  934. //
  935. deviceExtension->CurrentDevicePowerState = PowerDeviceD3;
  936. //deviceExtension->NeedCleanup = FALSE;
  937. //deviceExtension->BWReclimationEnabled = FALSE;
  938. //deviceExtension->Stopped = FALSE;
  939. deviceExtension->TopOfStackDeviceObject =
  940. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  941. //
  942. // Indicate that the device object is ready for requests.
  943. //
  944. if (deviceExtension->TopOfStackDeviceObject) {
  945. //
  946. // a device object has been created, register with the bus driver now
  947. //
  948. USBD_RegisterHostController(PhysicalDeviceObject,
  949. deviceObject,
  950. deviceExtension->TopOfStackDeviceObject,
  951. DriverObject,
  952. UHCD_DeferredStartDevice,
  953. UHCD_SetDevicePowerState,
  954. UHCD_ExternalGetCurrentFrame,
  955. #ifndef WIN98
  956. UHCD_ExternalGetConsumedBW,
  957. #endif
  958. UHCD_SubmitFastIsoUrb,
  959. deviceNameHandle);
  960. {
  961. // make sure our USBD and HCD used matching hcdi header files
  962. PUSBD_EXTENSION usbdExtension;
  963. usbdExtension = deviceObject->DeviceExtension;
  964. if (usbdExtension->Length != sizeof(USBD_EXTENSION)) {
  965. UHCD_KdTrap(("UHCD/USBD version mismatch\n"));
  966. ntStatus = STATUS_UNSUCCESSFUL;
  967. }
  968. }
  969. }
  970. deviceObject->Flags |= DO_POWER_PAGABLE;
  971. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  972. }
  973. RtlFreeUnicodeString(&deviceNameUnicodeString);
  974. UHCD_PnPAddDevice_Done:
  975. LOGENTRY(LOG_MISC, 'addD', 0, 0, ntStatus);
  976. UHCD_KdPrint((2, "'exit UHCD_PnPAddDevice (%x)\n", ntStatus));
  977. return ntStatus;
  978. }
  979. NTSTATUS
  980. UHCD_DeferIrpCompletion(
  981. IN PDEVICE_OBJECT DeviceObject,
  982. IN PIRP Irp,
  983. IN PVOID Context
  984. )
  985. /*++
  986. Routine Description:
  987. This routine is called when the port driver completes an IRP.
  988. Arguments:
  989. DeviceObject - Pointer to the device object for the class device.
  990. Irp - Irp completed.
  991. Context - Driver defined context.
  992. Return Value:
  993. The function value is the final status from the operation.
  994. --*/
  995. {
  996. PKEVENT event = Context;
  997. KeSetEvent(event,
  998. 1,
  999. FALSE);
  1000. return STATUS_MORE_PROCESSING_REQUIRED;
  1001. }
  1002. VOID
  1003. UHCD_ReadWriteConfig(
  1004. IN PDEVICE_OBJECT DeviceObject,
  1005. IN BOOLEAN Read,
  1006. IN PVOID Buffer,
  1007. IN ULONG Offset,
  1008. IN ULONG Length
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This routine reads or write config space.
  1013. Arguments:
  1014. DeviceObject - Physical DeviceObject for this USB controller.
  1015. Read - TRUE if read, FALSE if write.
  1016. Buffer - The info to read or write.
  1017. Offset - The offset in config space to read or write.
  1018. Length - The length to transfer.
  1019. Return Value:
  1020. None.
  1021. --*/
  1022. {
  1023. PIO_STACK_LOCATION nextStack;
  1024. PIRP irp;
  1025. NTSTATUS ntStatus;
  1026. KEVENT event;
  1027. PAGED_CODE();
  1028. if (Read) {
  1029. memset(Buffer, '\0', Length);
  1030. }
  1031. irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  1032. if (!irp) {
  1033. UHCD_KdTrap(("failed to allocate Irp\n"));
  1034. return;
  1035. }
  1036. // All PnP IRP's need the Status field initialized to STATUS_NOT_SUPPORTED.
  1037. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1038. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1039. IoSetCompletionRoutine(irp,
  1040. UHCD_DeferIrpCompletion,
  1041. &event,
  1042. TRUE,
  1043. TRUE,
  1044. TRUE);
  1045. nextStack = IoGetNextIrpStackLocation(irp);
  1046. UHCD_ASSERT(nextStack != NULL);
  1047. nextStack->MajorFunction= IRP_MJ_PNP;
  1048. nextStack->MinorFunction= Read ? IRP_MN_READ_CONFIG : IRP_MN_WRITE_CONFIG;
  1049. nextStack->Parameters.ReadWriteConfig.WhichSpace = 0; /*PCI_WHICHSPACE_CONFIG */
  1050. nextStack->Parameters.ReadWriteConfig.Buffer = Buffer;
  1051. nextStack->Parameters.ReadWriteConfig.Offset = Offset;
  1052. nextStack->Parameters.ReadWriteConfig.Length = Length;
  1053. ntStatus = IoCallDriver(DeviceObject,
  1054. irp);
  1055. UHCD_KdPrint((2, "'ntStatus from IoCallDriver to PCI = 0x%x\n", ntStatus));
  1056. if (ntStatus == STATUS_PENDING) {
  1057. // wait for irp to complete
  1058. TEST_TRAP(); // first time we hit this
  1059. KeWaitForSingleObject(
  1060. &event,
  1061. Suspended,
  1062. KernelMode,
  1063. FALSE,
  1064. NULL);
  1065. }
  1066. if (!NT_SUCCESS(ntStatus)) {
  1067. // failed? this is probably a bug
  1068. UHCD_KdTrap(("ReadWriteConfig failed, why?\n"));
  1069. }
  1070. IoFreeIrp(irp);
  1071. }
  1072. NTSTATUS
  1073. UHCD_QueryCapabilities(
  1074. IN PDEVICE_OBJECT PdoDeviceObject,
  1075. IN PDEVICE_CAPABILITIES DeviceCapabilities
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. This routine reads or write config space.
  1080. Arguments:
  1081. DeviceObject - Physical DeviceObject for this USB controller.
  1082. Return Value:
  1083. None.
  1084. --*/
  1085. {
  1086. PIO_STACK_LOCATION nextStack;
  1087. PIRP irp;
  1088. NTSTATUS ntStatus;
  1089. KEVENT event;
  1090. PAGED_CODE();
  1091. // init the caps structure before calldown
  1092. RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  1093. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  1094. DeviceCapabilities->Version = 1;
  1095. DeviceCapabilities->Address = -1;
  1096. DeviceCapabilities->UINumber = -1;
  1097. irp = IoAllocateIrp(PdoDeviceObject->StackSize, FALSE);
  1098. if (!irp) {
  1099. UHCD_KdTrap(("failed to allocate Irp\n"));
  1100. return STATUS_INSUFFICIENT_RESOURCES;
  1101. }
  1102. // All PnP IRP's need the Status field initialized to STATUS_NOT_SUPPORTED.
  1103. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1104. nextStack = IoGetNextIrpStackLocation(irp);
  1105. UHCD_ASSERT(nextStack != NULL);
  1106. nextStack->MajorFunction= IRP_MJ_PNP;
  1107. nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES;
  1108. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1109. IoSetCompletionRoutine(irp,
  1110. UHCD_DeferIrpCompletion,
  1111. &event,
  1112. TRUE,
  1113. TRUE,
  1114. TRUE);
  1115. nextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
  1116. ntStatus = IoCallDriver(PdoDeviceObject,
  1117. irp);
  1118. UHCD_KdPrint((2, "'ntStatus from IoCallDriver to PCI = 0x%x\n", ntStatus));
  1119. if (ntStatus == STATUS_PENDING) {
  1120. // wait for irp to complete
  1121. KeWaitForSingleObject(
  1122. &event,
  1123. Suspended,
  1124. KernelMode,
  1125. FALSE,
  1126. NULL);
  1127. ntStatus = irp->IoStatus.Status;
  1128. }
  1129. #if DBG
  1130. if (!NT_SUCCESS(ntStatus)) {
  1131. // failed? this is probably a bug
  1132. UHCD_KdTrap(("QueryCapabilities failed, why?\n"));
  1133. }
  1134. #endif
  1135. IoFreeIrp(irp);
  1136. return ntStatus;
  1137. }
  1138. #if 0
  1139. BOOLEAN
  1140. UHCD_StopController(
  1141. IN PVOID Context
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. Starts the USB host controller executing the schedule.
  1146. Start Controller is called in by KeSynchronizeExecution.
  1147. Arguments:
  1148. Context - DeviceData for this USB controller.
  1149. Return Value:
  1150. TRUE
  1151. --*/
  1152. {
  1153. PDEVICE_EXTENSION deviceExtension;
  1154. USHORT cmd;
  1155. deviceExtension = Context;
  1156. // no more interrupts
  1157. cmd = 0;
  1158. WRITE_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension), cmd);
  1159. return TRUE;
  1160. }
  1161. #endif
  1162. NTSTATUS
  1163. UHCD_StopDevice(
  1164. IN PDEVICE_OBJECT DeviceObject
  1165. )
  1166. /*++
  1167. Routine Description:
  1168. Resets the USB host controller and disconnects the interrupt.
  1169. if a USB bios is present it is re-started.
  1170. Arguments:
  1171. DeviceObject - DeviceObject of the controller to stop
  1172. Return Value:
  1173. NT status code.
  1174. --*/
  1175. {
  1176. NTSTATUS ntStatus = STATUS_SUCCESS;
  1177. PDEVICE_EXTENSION deviceExtension;
  1178. LARGE_INTEGER startTime;
  1179. USHORT cmd;
  1180. USHORT status;
  1181. KIRQL irql;
  1182. UHCD_KdPrint((2, "'enter UHCD_StopDevice \n"));
  1183. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1184. if (deviceExtension->HcFlags & HCFLAG_HCD_STOPPED) {
  1185. // already stopped, bail
  1186. goto UHCD_StopDevice_Done;
  1187. }
  1188. UHCD_DisableIdleCheck(deviceExtension);
  1189. if (!(deviceExtension->HcFlags & HCFLAG_GOT_IO)) {
  1190. // if we don't have io ports we can't stop
  1191. // the controller
  1192. //
  1193. // This check is here because Win98 will send a stop
  1194. // if we fail the start and we mail fail to start because
  1195. // we did not get io ports
  1196. goto UHCD_StopDevice_Done;
  1197. }
  1198. //
  1199. // disable all interrupts
  1200. //
  1201. // KeSynchronizeExecution(deviceExtension->InterruptObject,
  1202. // UHCD_StopController,
  1203. // deviceExtension);
  1204. cmd = 0;
  1205. WRITE_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension), cmd);
  1206. //
  1207. // reset the controller
  1208. //
  1209. cmd = UHCD_CMD_RESET;
  1210. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  1211. // now wait for HC to reset
  1212. KeQuerySystemTime(&startTime);
  1213. for (;;) {
  1214. LARGE_INTEGER sysTime;
  1215. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  1216. UHCD_KdPrint((2, "'COMMAND = %x\n", cmd));
  1217. if ((cmd & UHCD_CMD_RESET) == 0) {
  1218. break;
  1219. }
  1220. KeQuerySystemTime(&sysTime);
  1221. if (sysTime.QuadPart - startTime.QuadPart > 10000) {
  1222. // timeout trying to rest
  1223. #if DBG
  1224. UHCD_KdPrint((1, "TIMEOUT RESETTING CONTROLLER! \n"));
  1225. UHCD_KdPrint((1, "'Port Resources @ %x Ports Available \n",
  1226. deviceExtension->Port));
  1227. TRAP();
  1228. #endif
  1229. break;
  1230. }
  1231. }
  1232. //
  1233. // after reset the halt bit is set, clear status register just
  1234. // in case.
  1235. //
  1236. status = 0xff;
  1237. WRITE_PORT_USHORT(STATUS_REG(deviceExtension), status);
  1238. #if DBG
  1239. {
  1240. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  1241. status = READ_PORT_USHORT(STATUS_REG(deviceExtension));
  1242. UHCD_KdBreak((2, "'after reset cmd = %x stat = %x\n", cmd, status));
  1243. }
  1244. #endif
  1245. UHCD_StopDevice_Done:
  1246. //
  1247. // handle no more interrupts for the HC
  1248. //
  1249. KeAcquireSpinLock(&deviceExtension->HcFlagSpin, &irql);
  1250. deviceExtension->HcFlags |= HCFLAG_HCD_STOPPED;
  1251. if (deviceExtension->InterruptObject) {
  1252. PKINTERRUPT interruptObject;
  1253. interruptObject = deviceExtension->InterruptObject;
  1254. deviceExtension->InterruptObject = NULL;
  1255. KeReleaseSpinLock(&deviceExtension->HcFlagSpin, irql);
  1256. IoDisconnectInterrupt(interruptObject);
  1257. } else {
  1258. KeReleaseSpinLock(&deviceExtension->HcFlagSpin, irql);
  1259. }
  1260. UHCD_KdPrint((2, "'exit UHCD_StopDevice (%x)\n", ntStatus));
  1261. return ntStatus;
  1262. }
  1263. VOID
  1264. UHCD_CleanupDevice(
  1265. IN PDEVICE_OBJECT DeviceObject
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. Cleans up resources allocated for the host controller,
  1270. this routine should undo anything done in START_DEVICE
  1271. that does not require access to the HC hardware.
  1272. Arguments:
  1273. DeviceObject - DeviceObject of the controller to stop
  1274. Return Value:
  1275. NT status code.
  1276. --*/
  1277. {
  1278. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1279. PUHCD_PAGE_LIST_ENTRY pageListEntry;
  1280. BOOLEAN waitMore = TRUE;
  1281. LARGE_INTEGER deltaTime;
  1282. #ifdef MAX_DEBUG
  1283. extern LONG UHCD_CommonBufferBytes;
  1284. extern LONG UHCD_TotalAllocatedHeapSpace;
  1285. #endif
  1286. PAGED_CODE();
  1287. UHCD_KdPrint((2, "'enter UHCD_CleanupDevice \n"));
  1288. if (deviceExtension->HcFlags & HCFLAG_NEED_CLEANUP) {
  1289. deviceExtension->HcFlags &= ~HCFLAG_NEED_CLEANUP;
  1290. if (deviceExtension->RootHubPollTimerInitialized) {
  1291. KeCancelTimer(&deviceExtension->RootHubPollTimer);
  1292. }
  1293. //
  1294. // If someone issued a reset to one of the root
  1295. // hub ports before the stop there may be timers
  1296. // still outstanding, we wait here fo them to
  1297. // expire.
  1298. //
  1299. while (deviceExtension->RootHubTimersActive) {
  1300. //
  1301. // wait 20 ms for our timers to expire
  1302. //
  1303. deltaTime.QuadPart = -10000 * 20;
  1304. (VOID) KeDelayExecutionThread(KernelMode,
  1305. FALSE,
  1306. &deltaTime);
  1307. waitMore = FALSE;
  1308. }
  1309. //
  1310. // Wait for the polling timer to expire if we didn't wait
  1311. // for the the root hub timers
  1312. //
  1313. if (waitMore && deviceExtension->RootHubPollTimerInitialized) {
  1314. deltaTime.QuadPart = -10000 * 10;
  1315. (VOID)KeDelayExecutionThread(KernelMode, FALSE,
  1316. &deltaTime);
  1317. }
  1318. //
  1319. // free memory allocated for frame list
  1320. //
  1321. if (deviceExtension->FrameListVirtualAddress != NULL) {
  1322. UHCD_ASSERT(deviceExtension->AdapterObject != NULL);
  1323. HalFreeCommonBuffer(deviceExtension->AdapterObject,
  1324. #if DBG
  1325. FRAME_LIST_LENGTH *3,
  1326. #else
  1327. FRAME_LIST_LENGTH *2,
  1328. #endif
  1329. deviceExtension->FrameListLogicalAddress,
  1330. deviceExtension->FrameListVirtualAddress,
  1331. FALSE);
  1332. deviceExtension->FrameListVirtualAddress = NULL;
  1333. #if DBG
  1334. {
  1335. extern LONG UHCD_CommonBufferBytes;
  1336. UHCD_ASSERT(UHCD_CommonBufferBytes > FRAME_LIST_LENGTH*3);
  1337. UHCD_CommonBufferBytes -= (FRAME_LIST_LENGTH*3);
  1338. }
  1339. #endif
  1340. }
  1341. // free HW descriptors used as interrupt triggers
  1342. if (deviceExtension->PersistantQueueHead) {
  1343. UHCD_FreeHardwareDescriptors(DeviceObject, deviceExtension->PQH_DescriptorList);
  1344. deviceExtension->PersistantQueueHead = NULL;
  1345. }
  1346. //
  1347. // unmap device registers here
  1348. //
  1349. if (deviceExtension->HcFlags & HCFLAG_UNMAP_REGISTERS) {
  1350. TEST_TRAP();
  1351. }
  1352. if (deviceExtension->Piix4EP) {
  1353. RETHEAP(deviceExtension->Piix4EP);
  1354. deviceExtension->Piix4EP = NULL;
  1355. }
  1356. //BUGBUG
  1357. //ASSERT that we have no active endpoints
  1358. //and that no endpoints are on the close list
  1359. //
  1360. // free root hub memory
  1361. //
  1362. if (deviceExtension->RootHub) {
  1363. #if DBG
  1364. if (deviceExtension->RootHub->DisabledPort) {
  1365. RETHEAP (deviceExtension->RootHub->DisabledPort);
  1366. }
  1367. #endif
  1368. RETHEAP(deviceExtension->RootHub);
  1369. deviceExtension->RootHub = NULL;
  1370. }
  1371. //
  1372. // free all pages allocated with HalAllocateCommonBuffer
  1373. //
  1374. while (!IsListEmpty(&deviceExtension->PageList)) {
  1375. pageListEntry = (PUHCD_PAGE_LIST_ENTRY)
  1376. RemoveHeadList(&deviceExtension->PageList);
  1377. #ifdef MAX_DEBUG
  1378. UHCD_CommonBufferBytes -= pageListEntry->Length;
  1379. #endif
  1380. HalFreeCommonBuffer(deviceExtension->AdapterObject,
  1381. pageListEntry->Length,
  1382. pageListEntry->LogicalAddress,
  1383. pageListEntry,
  1384. FALSE);
  1385. }
  1386. //
  1387. // NOTE: may not have an adapter object if getresources fails
  1388. //
  1389. if (deviceExtension->AdapterObject) {
  1390. KIRQL oldIrql;
  1391. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  1392. (deviceExtension->AdapterObject->DmaOperations->PutDmaAdapter)
  1393. (deviceExtension->AdapterObject);
  1394. KeLowerIrql (oldIrql);
  1395. }
  1396. deviceExtension->AdapterObject = NULL;
  1397. #ifdef MAX_DEBUG
  1398. {
  1399. extern LONG UHCD_CommonBufferBytes;
  1400. extern LONG UHCD_TotalAllocatedHeapSpace;
  1401. //
  1402. // Check totalmemory allocated count
  1403. //
  1404. if (UHCD_TotalAllocatedHeapSpace != 0) {
  1405. //
  1406. // memory leak!!
  1407. //
  1408. TRAP();
  1409. }
  1410. if (UHCD_CommonBufferBytes != 0) {
  1411. //
  1412. // memory leak!!
  1413. //
  1414. TRAP();
  1415. }
  1416. TEST_TRAP();
  1417. }
  1418. #endif
  1419. }
  1420. UHCD_KdPrint((2, "'exit UHCD_CleanupDevice (%x)\n", STATUS_SUCCESS));
  1421. return;
  1422. }
  1423. NTSTATUS
  1424. UHCD_InitializeSchedule(
  1425. IN PDEVICE_OBJECT DeviceObject
  1426. )
  1427. /*++
  1428. Routine Description:
  1429. Initializes the schedule structures for the HCD
  1430. Arguments:
  1431. DeviceObject - DeviceObject for this USB controller.
  1432. Return Value:
  1433. NT Status code.
  1434. --*/
  1435. {
  1436. NTSTATUS ntStatus = STATUS_SUCCESS;
  1437. PDEVICE_EXTENSION deviceExtension;
  1438. ULONG i, length;
  1439. PHW_QUEUE_HEAD persistantQueueHead;
  1440. PUHCD_HARDWARE_DESCRIPTOR_LIST pqh_DescriptorList;
  1441. PAGED_CODE();
  1442. UHCD_KdPrint((2, "'enter UHCD_InitializeSchedule\n"));
  1443. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1444. //
  1445. // allocate a contiguous range of physical memory for the frame list --
  1446. // we will need enough for 1024 physical addresses
  1447. //
  1448. length = FRAME_LIST_LENGTH;
  1449. //
  1450. // Allocate a common buffer for the frame list (that is programmed into
  1451. // the hardware later) as well as a copy of the active frame list.
  1452. //
  1453. deviceExtension->FrameListVirtualAddress =
  1454. HalAllocateCommonBuffer(deviceExtension->AdapterObject,
  1455. #if DBG
  1456. length*3,
  1457. #else
  1458. length*2,
  1459. #endif
  1460. &deviceExtension->FrameListLogicalAddress,
  1461. FALSE);
  1462. #if DBG
  1463. {
  1464. extern LONG UHCD_CommonBufferBytes;
  1465. UHCD_CommonBufferBytes += length*3;
  1466. }
  1467. #endif
  1468. //
  1469. // Set the copy pointer into the common buffer at the end of the
  1470. // master frame list.
  1471. //
  1472. deviceExtension->FrameListCopyVirtualAddress =
  1473. ((PUCHAR) deviceExtension->FrameListVirtualAddress) + length;
  1474. if (deviceExtension->FrameListVirtualAddress == NULL ||
  1475. deviceExtension->FrameListCopyVirtualAddress == NULL) {
  1476. if (deviceExtension->FrameListVirtualAddress != NULL) {
  1477. HalFreeCommonBuffer(deviceExtension->AdapterObject,
  1478. #if DBG
  1479. length*3,
  1480. #else
  1481. length*2,
  1482. #endif
  1483. deviceExtension->FrameListLogicalAddress,
  1484. deviceExtension->FrameListVirtualAddress,
  1485. FALSE);
  1486. deviceExtension->FrameListVirtualAddress = NULL;
  1487. #if DBG
  1488. {
  1489. extern LONG UHCD_CommonBufferBytes;
  1490. UHCD_CommonBufferBytes -= length*3;
  1491. }
  1492. #endif
  1493. }
  1494. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1495. goto UHCD_InitializeScheduleExit;
  1496. } else {
  1497. RtlZeroMemory(deviceExtension->FrameListVirtualAddress, length);
  1498. RtlZeroMemory(deviceExtension->FrameListCopyVirtualAddress, length);
  1499. #if DBG
  1500. deviceExtension->IsoList =
  1501. (PULONG)(((PUCHAR) deviceExtension->FrameListCopyVirtualAddress) + length);
  1502. RtlZeroMemory(deviceExtension->IsoList, length);
  1503. UHCD_KdPrint((2, "'(%d) bytes allocated for usb iso list va = %x\n", length,
  1504. deviceExtension->IsoList));
  1505. #endif
  1506. //
  1507. // this should be 1 page
  1508. //
  1509. UHCD_KdPrint((2, "'(%d) bytes allocated for usb frame list va = %x\n", length,
  1510. deviceExtension->FrameListVirtualAddress));
  1511. UHCD_KdPrint((2, "'(%d) bytes allocated for usb frame list copy va = %x\n", length,
  1512. deviceExtension->FrameListCopyVirtualAddress));
  1513. }
  1514. //
  1515. // Initialize the lists of Memory Descriptors
  1516. // used to allocate TDs and packet buffers
  1517. //
  1518. UHCD_InitializeCommonBufferPool(DeviceObject,
  1519. &deviceExtension->LargeBufferPool,
  1520. UHCD_LARGE_COMMON_BUFFER_SIZE,
  1521. UHCD_RESERVE_LARGE_BUFFERS);
  1522. UHCD_InitializeCommonBufferPool(DeviceObject,
  1523. &deviceExtension->MediumBufferPool,
  1524. UHCD_MEDIUM_COMMON_BUFFER_SIZE,
  1525. UHCD_RESERVE_MEDIUM_BUFFERS);
  1526. UHCD_InitializeCommonBufferPool(DeviceObject,
  1527. &deviceExtension->SmallBufferPool,
  1528. UHCD_SMALL_COMMON_BUFFER_SIZE,
  1529. UHCD_RESERVE_SMALL_BUFFERS);
  1530. //
  1531. // Now set up our base queues for active endpoints
  1532. //
  1533. InitializeListHead(&deviceExtension->EndpointList);
  1534. InitializeListHead(&deviceExtension->EndpointLookAsideList);
  1535. InitializeListHead(&deviceExtension->FastIsoEndpointList);
  1536. InitializeListHead(&deviceExtension->FastIsoTransferList);
  1537. //
  1538. // Queue for released endpoints
  1539. //
  1540. InitializeListHead(&deviceExtension->ClosedEndpointList);
  1541. //BUGBUG check for error
  1542. //
  1543. // TDs are allocated for use as interrupt triggers.
  1544. // the first two are used to detect when the sign bit for
  1545. // the frame counter changes.
  1546. //
  1547. // The rest are used to generate interrupts for cleanup and cancel
  1548. //
  1549. if (!UHCD_AllocateHardwareDescriptors(DeviceObject,
  1550. &deviceExtension->PQH_DescriptorList,
  1551. MAX_TDS_PER_ENDPOINT)) {
  1552. HalFreeCommonBuffer(deviceExtension->AdapterObject,
  1553. #if DBG
  1554. length*3,
  1555. #else
  1556. length*2,
  1557. #endif
  1558. deviceExtension->FrameListLogicalAddress,
  1559. deviceExtension->FrameListVirtualAddress,
  1560. FALSE);
  1561. deviceExtension->FrameListVirtualAddress = NULL;
  1562. #if DBG
  1563. {
  1564. extern LONG UHCD_CommonBufferBytes;
  1565. UHCD_CommonBufferBytes -= length*3;
  1566. }
  1567. #endif
  1568. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1569. goto UHCD_InitializeScheduleExit;
  1570. }
  1571. pqh_DescriptorList = deviceExtension->PQH_DescriptorList;
  1572. persistantQueueHead =
  1573. deviceExtension->PersistantQueueHead = (PHW_QUEUE_HEAD) pqh_DescriptorList->MemoryDescriptor->VirtualAddress;
  1574. UHCD_KdPrint((2, "'Control Queue Head va = (%x)\n", deviceExtension->PersistantQueueHead));
  1575. //
  1576. // This is our base queue head, it goes in every frame
  1577. // but never has transfers associated with it.
  1578. // Control Q heads are always added after this guy,
  1579. // Bulk Q heads are always added in front of this guy (end of queue).
  1580. //
  1581. // initialize Horiz ptr to point to himself with the T-Bit set
  1582. //
  1583. persistantQueueHead->HW_HLink = persistantQueueHead->PhysicalAddress;
  1584. SET_T_BIT(persistantQueueHead->HW_HLink);
  1585. persistantQueueHead->HW_VLink = LIST_END;
  1586. persistantQueueHead->Next =
  1587. persistantQueueHead->Prev = persistantQueueHead;
  1588. // Put the control 'base' queue in every frame
  1589. for (i=0; i < FRAME_LIST_SIZE; i++)
  1590. *( ((PULONG) (deviceExtension->FrameListVirtualAddress)+i) ) =
  1591. persistantQueueHead->PhysicalAddress;
  1592. //
  1593. // Initialize an empty interrupt schedule.
  1594. //
  1595. for (i=0; i < MAX_INTERVAL; i++)
  1596. deviceExtension-> InterruptSchedule[i] =
  1597. persistantQueueHead;
  1598. // this is a dummy TD we use to generate an interrupt
  1599. // when the sign bit changes on the frame counter
  1600. deviceExtension->TriggerTDList = (PUHCD_TD_LIST) (pqh_DescriptorList->MemoryDescriptor->VirtualAddress +
  1601. UHCD_HW_DESCRIPTOR_SIZE);
  1602. deviceExtension->TriggerTDList->TDs[0].Active = 0;
  1603. deviceExtension->TriggerTDList->TDs[0].InterruptOnComplete = 1;
  1604. #ifdef VIA_HC
  1605. // VIA Host Controller requires a valid PID even if the TD is inactive
  1606. deviceExtension->TriggerTDList->TDs[0].PID = USB_IN_PID;
  1607. #endif /* VIA_HC */
  1608. deviceExtension->TriggerTDList->TDs[1].Active = 0;
  1609. deviceExtension->TriggerTDList->TDs[1].InterruptOnComplete = 1;
  1610. #ifdef VIA_HC
  1611. deviceExtension->TriggerTDList->TDs[1].PID = USB_IN_PID;
  1612. #endif /* VIA_HC */
  1613. deviceExtension->TriggerTDList->TDs[0].HW_Link =
  1614. deviceExtension->TriggerTDList->TDs[1].HW_Link = persistantQueueHead->PhysicalAddress;
  1615. //
  1616. // The PIIX3 has the following bug:
  1617. //
  1618. // If a frame babble occurrs an interrupt in generated with no way to
  1619. // clear it -- the host controller will continue to generate interrupts
  1620. // until an active TD is encountered.
  1621. //
  1622. // The workaround for this is to put an active TD in the schedule
  1623. // (on the persistent queue head). We activate this TD whenever a TD
  1624. // completes with the babble bit set.
  1625. //
  1626. //
  1627. // set up a TD for frame babble recovery
  1628. //
  1629. {
  1630. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  1631. transferDescriptor =
  1632. &deviceExtension->TriggerTDList->TDs[2];
  1633. transferDescriptor->Active = 1;
  1634. transferDescriptor->Isochronous = 1;
  1635. transferDescriptor->InterruptOnComplete = 0;
  1636. transferDescriptor->PID = USB_OUT_PID;
  1637. transferDescriptor->Address = 0;
  1638. transferDescriptor->Endpoint = 1;
  1639. transferDescriptor->ErrorCounter = 0;
  1640. transferDescriptor->PacketBuffer = 0;
  1641. transferDescriptor->MaxLength =
  1642. NULL_PACKET_LENGTH;
  1643. // point to ourself
  1644. transferDescriptor->HW_Link =
  1645. transferDescriptor->PhysicalAddress;
  1646. //SET_T_BIT(transferDescriptor->HW_Link);
  1647. // point the persistent queue head at this TD
  1648. persistantQueueHead->HW_VLink =
  1649. transferDescriptor->PhysicalAddress;
  1650. deviceExtension->FrameBabbleRecoverTD =
  1651. transferDescriptor;
  1652. }
  1653. // Initilaize the remainder of the trigger TDs for use by the
  1654. // transfer code -- used to generate interrupts.
  1655. for (i=UHCD_FIRST_TRIGGER_TD; i<MAX_TDS_PER_ENDPOINT; i++) {
  1656. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  1657. transferDescriptor =
  1658. &deviceExtension->TriggerTDList->TDs[i];
  1659. transferDescriptor->PID = USB_IN_PID;
  1660. transferDescriptor->Frame = 0;
  1661. }
  1662. // Initialize internal frame counters.
  1663. deviceExtension->FrameHighPart =
  1664. deviceExtension->LastFrame = 0;
  1665. // BUGBUG for now just insert trigger TDs
  1666. *( ((PULONG) (deviceExtension->FrameListVirtualAddress)) ) =
  1667. deviceExtension->TriggerTDList->TDs[0].PhysicalAddress;
  1668. *( ((PULONG) (deviceExtension->FrameListVirtualAddress) + FRAME_LIST_SIZE-1) ) =
  1669. deviceExtension->TriggerTDList->TDs[1].PhysicalAddress;
  1670. // schedule has been set up, make copy here
  1671. RtlCopyMemory(deviceExtension->FrameListCopyVirtualAddress,
  1672. deviceExtension->FrameListVirtualAddress,
  1673. FRAME_LIST_SIZE * sizeof(HW_DESCRIPTOR_PHYSICAL_ADDRESS));
  1674. UHCD_KdPrint((2, "'FrameListCopy = %x FrameList= %x\n",
  1675. deviceExtension->FrameListCopyVirtualAddress,
  1676. deviceExtension->FrameListVirtualAddress));
  1677. //
  1678. // Initilaize Root hub variables
  1679. //
  1680. deviceExtension->RootHubDeviceAddress = USB_DEFAULT_DEVICE_ADDRESS;
  1681. deviceExtension->RootHubInterruptEndpoint = NULL;
  1682. //
  1683. // Initialize Isoch variables
  1684. //
  1685. deviceExtension->LastFrameProcessed = 0;
  1686. //
  1687. // Initialize Misc variables
  1688. //
  1689. deviceExtension->EndpointListBusy = FALSE;
  1690. deviceExtension->LastPowerUpStatus = STATUS_SUCCESS;
  1691. UHCD_InitBandwidthTable(DeviceObject);
  1692. KeInitializeSpinLock(&deviceExtension->EndpointListSpin);
  1693. KeInitializeSpinLock(&deviceExtension->HcFlagSpin);
  1694. KeInitializeSpinLock(&deviceExtension->HcDmaSpin);
  1695. KeInitializeSpinLock(&deviceExtension->HcScheduleSpin);
  1696. deviceExtension->HcDma = -1;
  1697. //
  1698. // fix PIIX4 issues.
  1699. //
  1700. UHCD_FixPIIX4(DeviceObject);
  1701. UHCD_InitializeScheduleExit:
  1702. LOGENTRY(LOG_MISC, 'BASE', deviceExtension->FrameListVirtualAddress, 0, DeviceObject);
  1703. UHCD_KdPrint((2, "'exit UHCD_InitializeSchedule (%x)\n", ntStatus));
  1704. return ntStatus;
  1705. }
  1706. NTSTATUS
  1707. UHCD_StartGlobalReset(
  1708. IN PDEVICE_OBJECT DeviceObject
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. Initializes the hardware registers in the host controller.
  1713. Arguments:
  1714. DeviceObject - DeviceObject for this USB controller.
  1715. Return Value:
  1716. NT Status code.
  1717. --*/
  1718. {
  1719. PDEVICE_EXTENSION deviceExtension;
  1720. PAGED_CODE();
  1721. UHCD_KdPrint((2, "'enter UHCD_StartGlobalReset\n"));
  1722. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1723. LOGENTRY(LOG_MISC, 'InHW', DeviceObject, deviceExtension, 0);
  1724. UHCD_KdPrint((2, "'before init -- hardware state: Command = %x Status = %x interrupt mask %x\nFrame Base = %x\n",
  1725. READ_PORT_USHORT(COMMAND_REG(deviceExtension)),
  1726. READ_PORT_USHORT(STATUS_REG(deviceExtension)),
  1727. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension)),
  1728. READ_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension))));
  1729. //
  1730. // Perform global reset on the controller
  1731. //
  1732. // A global reset of the USB requires 20ms, we
  1733. // begin the process here and finish later (in the
  1734. // hub emulation code)
  1735. UHCD_KdPrint((2, "'Begin Global Reset of Host Controller \n"));
  1736. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), UHCD_CMD_GLOBAL_RESET);
  1737. UHCD_KdPrint((2, "'exit UHCD_StartGlobalReset -- (STATUS_SUCCESS)\n"));
  1738. return STATUS_SUCCESS;
  1739. }
  1740. NTSTATUS
  1741. UHCD_CompleteGlobalReset(
  1742. IN PDEVICE_OBJECT DeviceObject
  1743. )
  1744. /*++
  1745. Routine Description:
  1746. Starts the USB host controller executing the schedule,
  1747. his routine is called when the global reset for the
  1748. controller has completed.
  1749. Arguments:
  1750. DeviceObject - DeviceObject for this USB controller.
  1751. Return Value:
  1752. NT Status code.
  1753. --*/
  1754. {
  1755. PHYSICAL_ADDRESS frameListBaseAddress;
  1756. PDEVICE_EXTENSION deviceExtension;
  1757. USHORT cmd;
  1758. UHCD_KdPrint((2, "'enter CompleteGlobalReset\n"));
  1759. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1760. //
  1761. // Initialization has completed
  1762. //
  1763. UHCD_KdPrint((2, "'Initialization Completed, starting controller\n"));
  1764. // clear the global reset bit
  1765. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  1766. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd &= ~UHCD_CMD_GLOBAL_RESET);
  1767. UHCD_KdPrint((2, "'after global reset -- hardware state: Command = %x Status = %x interrupt mask %x\nFrame Base = %x\n",
  1768. READ_PORT_USHORT(COMMAND_REG(deviceExtension)),
  1769. READ_PORT_USHORT(STATUS_REG(deviceExtension)),
  1770. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension)),
  1771. READ_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension))));
  1772. //
  1773. // do a HC reset
  1774. //
  1775. // cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension)) | UHCD_CMD_RESET;
  1776. // WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  1777. // stall for 10 microseconds
  1778. // KeStallExecutionProcessor(10); //stall for 10 microseconds
  1779. // cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  1780. //
  1781. // HCReset bit should be cleared when HC completes the reset
  1782. //
  1783. // if (cmd & UHCD_CMD_RESET) {
  1784. // UHCD_KdPrint((2, "'Host Controller unable to reset!!!\n"));
  1785. // TRAP();
  1786. // }
  1787. //
  1788. // program the frame list base address
  1789. //
  1790. frameListBaseAddress = deviceExtension->FrameListLogicalAddress;
  1791. WRITE_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension), frameListBaseAddress.LowPart);
  1792. UHCD_KdPrint((2, "'Frame list base address programmed to (physical) %x.\n", frameListBaseAddress));
  1793. UHCD_KdPrint((2, "'after init -- hardware state: Command = %x Status = %x interrupt mask %x\nFrame Base = %x\n",
  1794. READ_PORT_USHORT(COMMAND_REG(deviceExtension)),
  1795. READ_PORT_USHORT(STATUS_REG(deviceExtension)),
  1796. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension)),
  1797. READ_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension))));
  1798. if (deviceExtension->SteppingVersion >= UHCD_B0_STEP) {
  1799. #ifdef ENABLE_B0_FEATURES
  1800. //
  1801. // set maxpacket for bandwidth reclimation
  1802. //
  1803. // TEST_TRAP();
  1804. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), UHCD_CMD_MAXPKT_64);
  1805. UHCD_KdPrint((2, "'Set MaxPacket to 64\n"));
  1806. #endif
  1807. }
  1808. //
  1809. // Enable Interrupts on the controller
  1810. //
  1811. UHCD_KdPrint((2, "'Enable Interrupts \n"));
  1812. cmd = UHCD_INT_MASK_IOC | UHCD_INT_MASK_TIMEOUT | UHCD_INT_MASK_RESUME;
  1813. if (deviceExtension->SteppingVersion >= UHCD_B0_STEP) {
  1814. // enable short packet detect
  1815. cmd |= UHCD_INT_MASK_SHORT;
  1816. }
  1817. WRITE_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension), cmd);
  1818. // set the SOF modify to whatever we found before
  1819. // the reset
  1820. UHCD_KdPrint((1, "'Setting SOF Modify to %d\n",
  1821. deviceExtension->SavedSofModify));
  1822. WRITE_PORT_UCHAR(SOF_MODIFY_REG(deviceExtension),
  1823. deviceExtension->SavedSofModify);
  1824. //
  1825. // Start the controller schedule
  1826. //
  1827. UHCD_KdPrint((2, "'Set Run/Stop bit \n"));
  1828. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension)) | UHCD_CMD_RUN;
  1829. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  1830. //
  1831. // Make sure that the controller is really running and if not, kick it
  1832. //
  1833. UhcdKickStartController(DeviceObject);
  1834. UHCD_KdPrint((2, "'after start -- hardware state: Command = %x Status = %x interrupt mask %x\nFrame Base = %x\n",
  1835. READ_PORT_USHORT(COMMAND_REG(deviceExtension)),
  1836. READ_PORT_USHORT(STATUS_REG(deviceExtension)),
  1837. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension)),
  1838. READ_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension))));
  1839. UHCD_KdPrint((2, "'exit CompleteGlobalReset\n"));
  1840. return STATUS_SUCCESS;
  1841. }
  1842. ULONG
  1843. UHCD_GetCurrentFrame(
  1844. IN PDEVICE_OBJECT DeviceObject
  1845. )
  1846. /*++
  1847. Routine Description:
  1848. returns the current frame number as an unsigned 32-bit value.
  1849. Arguments:
  1850. DeviceObject - pointer to a device object
  1851. Return Value:
  1852. Current Frame Number.
  1853. --*/
  1854. {
  1855. PDEVICE_EXTENSION deviceExtension;
  1856. ULONG currentFrame, highPart, frameNumber;
  1857. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1858. //
  1859. // The following algorithm compliments
  1860. // of jfuller and kenr
  1861. //
  1862. // get Hcd's high part of frame number
  1863. highPart = deviceExtension->FrameHighPart;
  1864. // get 11-bit frame number, high 17-bits are 0
  1865. frameNumber = (ULONG) READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension));
  1866. currentFrame = ((frameNumber & 0x0bff) | highPart) +
  1867. ((frameNumber ^ highPart) & 0x0400);
  1868. //UHCD_KdPrint((2, "'exit UHCD_GetCurrentFrame = %d\n", currentFrame));
  1869. return currentFrame;
  1870. }
  1871. NTSTATUS
  1872. UHCD_SaveHCstate(
  1873. IN PDEVICE_OBJECT DeviceObject
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. Arguments:
  1878. DeviceObject - DeviceObject for this USB controller.
  1879. Return Value:
  1880. NT status code.
  1881. --*/
  1882. {
  1883. NTSTATUS ntStatus = STATUS_SUCCESS;
  1884. USHORT cmd;
  1885. PDEVICE_EXTENSION deviceExtension;
  1886. UHCD_KdPrint((1, "'saving host controller state\n"));
  1887. LOGENTRY(LOG_MISC, 'HCsv', 0, 0, 0);
  1888. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1889. //
  1890. // save some state info
  1891. //
  1892. deviceExtension->SavedInterruptEnable =
  1893. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension));
  1894. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  1895. // save the cmd regs in the "stopped" state
  1896. cmd &= ~UHCD_CMD_RUN;
  1897. deviceExtension->SavedCommandReg = cmd;
  1898. // additonal saved info needed to restore from hibernate
  1899. deviceExtension->SavedFRNUM =
  1900. READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension));
  1901. deviceExtension->SavedFRBASEADD =
  1902. READ_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension));
  1903. return ntStatus;
  1904. }
  1905. NTSTATUS
  1906. UHCD_RestoreHCstate(
  1907. IN PDEVICE_OBJECT DeviceObject
  1908. )
  1909. /*++
  1910. Routine Description:
  1911. Arguments:
  1912. DeviceObject - DeviceObject for this USB controller.
  1913. Return Value:
  1914. NT status code.
  1915. --*/
  1916. {
  1917. NTSTATUS ntStatus = STATUS_SUCCESS;
  1918. PDEVICE_EXTENSION deviceExtension;
  1919. BOOLEAN lostPower = FALSE;
  1920. LARGE_INTEGER deltaTime;
  1921. BOOLEAN apm = FALSE;
  1922. UHCD_KdPrint((1, "'restoring host controller state\n"));
  1923. LOGENTRY(LOG_MISC, 'HCrs', 0, 0, 0);
  1924. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1925. //
  1926. // this check tells us that power was turned off
  1927. // to the controller.
  1928. //
  1929. // IBM Aptiva rapid resume will turn off power to
  1930. // the controller without going thru the OS
  1931. // may APM BIOSes do this too
  1932. //
  1933. // see if we were in D3, if so restore additional info
  1934. // necessary to recover from hibernate
  1935. if (deviceExtension->HcFlags & HCFLAG_LOST_POWER) {
  1936. UHCD_KdPrint((0, "'restoring HC from hibernate\n"));
  1937. deviceExtension->HcFlags &= ~HCFLAG_LOST_POWER;
  1938. // we will need to do much the same thing we do
  1939. // in START_DEVICE
  1940. // first restore the HC regs for the schedule
  1941. WRITE_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension),
  1942. deviceExtension->SavedFRNUM);
  1943. WRITE_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension),
  1944. deviceExtension->SavedFRBASEADD);
  1945. // now do a global reset
  1946. ntStatus = UHCD_StartGlobalReset(DeviceObject);
  1947. if (!NT_SUCCESS(ntStatus)) {
  1948. goto UHCD_RestoreHCstate_Done;
  1949. }
  1950. //
  1951. // Everything is set, we need to wait for the
  1952. // global reset of the Host controller to complete.
  1953. //
  1954. // 20 ms to reset...
  1955. deltaTime.QuadPart = -10000 * 20;
  1956. //
  1957. // block here until reset is complete
  1958. //
  1959. (VOID) KeDelayExecutionThread(KernelMode,
  1960. FALSE,
  1961. &deltaTime);
  1962. ntStatus = UHCD_CompleteGlobalReset(DeviceObject);
  1963. lostPower = TRUE;
  1964. } else {
  1965. //
  1966. // interrupt masks disabled indicates power was turned
  1967. // off to the piix3/piix4.
  1968. //
  1969. lostPower =
  1970. (BOOLEAN) (READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension)) == 0);
  1971. // we get here on APM/ACPI systems
  1972. // note that lostPower should be false on an ACPI system
  1973. apm = TRUE;
  1974. }
  1975. if (lostPower) {
  1976. // we get here for hibernate, APM suspend or ACPI D2/D3
  1977. // on hibernate we need to re-init the controller
  1978. // on APM we let the BIOS do it.
  1979. //for APM:
  1980. // lostPower = TRUE if APM BIOS turned off hc
  1981. // apm = TRUE
  1982. //for ACPI D3/Hibernate
  1983. // HCFLAG_LOST_POWER flag is set
  1984. // lostPower TRUE
  1985. //for ACPI D2 & APM supprted USB suspend
  1986. // lostPower = FALSE
  1987. // HCFLAG_LOST_POWER is clear
  1988. // apm = FALSE;
  1989. UHCD_KdPrint((0, "'detected (APM/HIBERNATE) loss of power during suspend\n"));
  1990. if (apm) {
  1991. //
  1992. // some APM BIOSes trash these registers so we'll have to put
  1993. // them back
  1994. //
  1995. WRITE_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension),
  1996. deviceExtension->SavedFRNUM);
  1997. WRITE_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension),
  1998. deviceExtension->SavedFRBASEADD);
  1999. }
  2000. WRITE_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension),
  2001. deviceExtension->SavedInterruptEnable);
  2002. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension),
  2003. deviceExtension->SavedCommandReg);
  2004. }
  2005. UHCD_RestoreHCstate_Done:
  2006. return ntStatus;
  2007. }
  2008. NTSTATUS
  2009. UHCD_Suspend(
  2010. IN PDEVICE_OBJECT DeviceObject,
  2011. IN BOOLEAN SuspendBus
  2012. )
  2013. /*++
  2014. Routine Description:
  2015. This routine suspends the host controller.
  2016. Arguments:
  2017. DeviceObject - DeviceObject for this USB controller.
  2018. Return Value:
  2019. NT status code.
  2020. --*/
  2021. {
  2022. NTSTATUS ntStatus = STATUS_SUCCESS;
  2023. PDEVICE_EXTENSION deviceExtension;
  2024. USHORT cmd, status;
  2025. LARGE_INTEGER finishTime, currentTime;
  2026. PAGED_CODE();
  2027. UHCD_KdPrint((1, "'suspending Host Controller (Root Hub)\n"));
  2028. LOGENTRY(LOG_MISC, 'RHsu', 0, 0, 0);
  2029. #ifdef JD
  2030. //TEST_TRAP();
  2031. #endif
  2032. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2033. //may not be in D0 if we haven't started yet.
  2034. //UHCD_ASSERT(deviceExtension->CurrentDevicePowerState == PowerDeviceD0);
  2035. UHCD_DisableIdleCheck(deviceExtension);
  2036. #if DBG
  2037. UHCD_KdPrint((2, "'HC regs before suspend\n"));
  2038. UHCD_KdPrint((2, "'cmd register = %x\n",
  2039. READ_PORT_USHORT(COMMAND_REG(deviceExtension)) ));
  2040. UHCD_KdPrint((2, "'status register = %x\n",
  2041. READ_PORT_USHORT(STATUS_REG(deviceExtension)) ));
  2042. UHCD_KdPrint((2, "'interrupt enable register = %x\n",
  2043. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension)) ));
  2044. UHCD_KdPrint((2, "'frame list base = %x\n",
  2045. READ_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension)) ));
  2046. #endif
  2047. //
  2048. // save some state info
  2049. //
  2050. deviceExtension->SavedInterruptEnable =
  2051. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension));
  2052. // set the run/stop bit
  2053. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2054. cmd &= ~UHCD_CMD_RUN;
  2055. deviceExtension->SavedCommandReg = cmd;
  2056. UHCD_KdPrint((2, "'run/stop = %x\n", cmd));
  2057. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  2058. KeQuerySystemTime(&finishTime); // get current time
  2059. finishTime.QuadPart += 5000000; // figure when we quit (.5 seconds
  2060. // later)
  2061. // poll the status reg for the halt bit
  2062. for (;;) {
  2063. status = READ_PORT_USHORT(STATUS_REG(deviceExtension));
  2064. UHCD_KdPrint((2, "'STATUS = %x\n", status));
  2065. if (status & UHCD_STATUS_HCHALT) {
  2066. break;
  2067. }
  2068. KeQuerySystemTime(&currentTime);
  2069. if (currentTime.QuadPart >= finishTime.QuadPart) {
  2070. UHCD_KdPrint((0, "'Warning: Host contoller did not respond to halt req\n"));
  2071. #if DBG
  2072. if (SuspendBus) {
  2073. // this is very bad if we are suspending
  2074. TRAP();
  2075. }
  2076. #endif
  2077. break;
  2078. }
  2079. }
  2080. UHCD_KdPrint((2, "'UHCD Suspend RH, schedule stopped\n"));
  2081. // reset the frame list current index
  2082. WRITE_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension), 0);
  2083. // re-initialize internal frame counters.
  2084. deviceExtension->FrameHighPart =
  2085. deviceExtension->LastFrame = 0;
  2086. deviceExtension->XferIdleTime =
  2087. deviceExtension->IdleTime = 0;
  2088. // clear idle flag sinec we will be running on resume
  2089. // note we leave the state of the rollover ints since
  2090. // it reflects the status of the TDs not the HC schecdule
  2091. deviceExtension->HcFlags &= ~HCFLAG_IDLE;
  2092. //
  2093. // we let the hub driver handle suspending the ports
  2094. //
  2095. // BUGBUG
  2096. // not sure if we need to force resume
  2097. if (SuspendBus) {
  2098. LOGENTRY(LOG_MISC, 'RHew', 0, 0, 0);
  2099. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2100. // FGR=0
  2101. cmd &= ~UHCD_CMD_FORCE_RESUME;
  2102. // EGSM=1
  2103. cmd |= UHCD_CMD_SUSPEND;
  2104. UHCD_KdPrint((2, "'enter suspend = %x\n", cmd));
  2105. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  2106. }
  2107. UHCD_KdPrint((2, "'exit UHCD_SuspendHC 0x%x\n", ntStatus));
  2108. #ifdef MAX_DEBUG
  2109. TEST_TRAP();
  2110. #endif
  2111. return ntStatus;
  2112. }
  2113. NTSTATUS
  2114. UHCD_Resume(
  2115. IN PDEVICE_OBJECT DeviceObject,
  2116. IN BOOLEAN DoResumeSignaling
  2117. )
  2118. /*++
  2119. Routine Description:
  2120. This routine resumes the host controller from either the
  2121. OFF or suspended state.
  2122. Arguments:
  2123. DeviceObject - DeviceObject for this USB controller.
  2124. Return Value:
  2125. NT status code.
  2126. --*/
  2127. {
  2128. NTSTATUS ntStatus = STATUS_SUCCESS;
  2129. USHORT cmd;
  2130. PDEVICE_EXTENSION deviceExtension;
  2131. LARGE_INTEGER deltaTime;
  2132. UHCD_KdPrint((1, "'resuming Host Controller (Root Hub)\n"));
  2133. LOGENTRY(LOG_MISC, 'RHre', 0, 0, 0);
  2134. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2135. #if DBG
  2136. UHCD_KdPrint((2, "'HC regs after suspend\n"));
  2137. UHCD_KdPrint((2, "'cmd register = %x\n",
  2138. READ_PORT_USHORT(COMMAND_REG(deviceExtension)) ));
  2139. UHCD_KdPrint((2, "'status register = %x\n",
  2140. READ_PORT_USHORT(STATUS_REG(deviceExtension)) ));
  2141. UHCD_KdPrint((2, "'interrupt enable register = %x\n",
  2142. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension)) ));
  2143. UHCD_KdPrint((2, "'frame list base = %x\n",
  2144. READ_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension)) ));
  2145. #endif
  2146. // if we are resuming the controller should be in D0
  2147. UHCD_ASSERT(deviceExtension->CurrentDevicePowerState == PowerDeviceD0);
  2148. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2149. if (DoResumeSignaling) {
  2150. // force a global resume
  2151. UHCD_KdPrint((2, "'forcing resume = %x\n", cmd));
  2152. cmd |= UHCD_CMD_FORCE_RESUME;
  2153. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  2154. //
  2155. // wait 20 ms for our timers to expire
  2156. //
  2157. deltaTime.QuadPart = -10000 * 20;
  2158. (VOID) KeDelayExecutionThread(KernelMode,
  2159. FALSE,
  2160. &deltaTime);
  2161. //done with resume
  2162. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2163. cmd &= ~(UHCD_CMD_SUSPEND | UHCD_CMD_FORCE_RESUME);
  2164. UHCD_KdPrint((2, "'clear suspend = %x\n", cmd));
  2165. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  2166. //
  2167. // start schedule
  2168. //
  2169. // wait for FGR bit to go low
  2170. do {
  2171. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2172. } while (cmd & UHCD_CMD_FORCE_RESUME);
  2173. }
  2174. // start controller
  2175. cmd |= UHCD_CMD_RUN;
  2176. UHCD_KdPrint((2, "'exit resume = %x\n", cmd));
  2177. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  2178. //
  2179. // Note: we let the hub driver handle resume
  2180. // signaling
  2181. //
  2182. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2183. //
  2184. // Make sure that the controller is really running and if not, kick it
  2185. //
  2186. UhcdKickStartController(DeviceObject);
  2187. UHCD_KdPrint((2, "'exit UHCD_Resume 0x%x\n", ntStatus));
  2188. #ifdef MAX_DEBUG
  2189. TEST_TRAP();
  2190. #endif
  2191. // enable the idle check routine
  2192. deviceExtension->HcFlags &= ~HCFLAG_DISABLE_IDLE;
  2193. UHCD_KdPrint((1, "'Host controller root hub entered D0\n"));
  2194. return ntStatus;
  2195. }
  2196. NTSTATUS
  2197. UHCD_ExternalGetCurrentFrame(
  2198. IN PDEVICE_OBJECT DeviceObject,
  2199. IN PULONG CurrentFrame
  2200. )
  2201. /*++
  2202. Routine Description:
  2203. Arguments:
  2204. DeviceObject - DeviceObject for this USB controller.
  2205. Return Value:
  2206. NT status code.
  2207. --*/
  2208. {
  2209. *CurrentFrame = UHCD_GetCurrentFrame(DeviceObject);
  2210. return STATUS_SUCCESS;
  2211. }
  2212. ULONG
  2213. UHCD_ExternalGetConsumedBW(
  2214. IN PDEVICE_OBJECT DeviceObject
  2215. )
  2216. /*++
  2217. Routine Description:
  2218. Arguments:
  2219. DeviceObject - DeviceObject for this USB controller.
  2220. Return Value:
  2221. NT status code.
  2222. --*/
  2223. {
  2224. PDEVICE_EXTENSION deviceExtension;
  2225. ULONG low, i;
  2226. LOGENTRY(LOG_MISC, 'AVbw', 0, 0, 0);
  2227. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2228. low = UHCD_TOTAL_USB_BW;
  2229. // find the lowest value in our available bandwidth table
  2230. for (i=0; i<MAX_INTERVAL; i++) {
  2231. //
  2232. // max bytes per frame - bw reaerved for bulk and control
  2233. //
  2234. if (deviceExtension->BwTable[i] < low) {
  2235. low = deviceExtension->BwTable[i];
  2236. }
  2237. }
  2238. // lowest available - total = consumed bw
  2239. return UHCD_TOTAL_USB_BW-low;
  2240. }
  2241. NTSTATUS
  2242. UHCD_RootHubPower(
  2243. IN PDEVICE_OBJECT DeviceObject,
  2244. IN PIRP Irp
  2245. )
  2246. /*++
  2247. Routine Description:
  2248. This function handles power messages to the root hub, note that
  2249. we save the state of the HC here instead of when the HC itself is
  2250. powered down. The reason for this is for compatibility with APM
  2251. systems that cut power to the HC during a suspend. On these
  2252. systems WDM never sends a power state change mesage to the HC ie
  2253. the HC is assumed to always stay on.
  2254. Arguments:
  2255. DeviceObject - DeviceObject for this USB controller.
  2256. Return Value:
  2257. NT status code.
  2258. --*/
  2259. {
  2260. PIO_STACK_LOCATION irpStack;
  2261. NTSTATUS ntStatus = STATUS_SUCCESS;
  2262. PDEVICE_EXTENSION deviceExtension;
  2263. UHCD_KdPrint((2, "'UHCD_RootHubPower\n"));
  2264. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2265. irpStack = IoGetCurrentIrpStackLocation (Irp);
  2266. LOGENTRY(LOG_MISC, 'HCrp', irpStack->MinorFunction, 0, 0);
  2267. switch (irpStack->MinorFunction) {
  2268. case IRP_MN_WAIT_WAKE:
  2269. UHCD_KdPrint((2, "'IRP_MN_WAIT_WAKE\n"));
  2270. //
  2271. // someone is enabling us for wakeup
  2272. //
  2273. LOGENTRY(LOG_MISC, 'rpWW', 0, 0, 0);
  2274. TEST_TRAP(); // never seen this before?
  2275. break;
  2276. case IRP_MN_SET_POWER:
  2277. switch (irpStack->Parameters.Power.Type) {
  2278. case SystemPowerState:
  2279. LOGENTRY(LOG_MISC, 'SPsp', 0, 0, 0);
  2280. // should not get here
  2281. UHCD_KdTrap(("RootHubPower -- SystemState\n"));
  2282. break;
  2283. case DevicePowerState:
  2284. LOGENTRY(LOG_MISC, 'SPdp', 0, 0, 0);
  2285. switch(irpStack->Parameters.Power.State.DeviceState) {
  2286. case PowerDeviceD0:
  2287. {
  2288. BOOLEAN doResumeSignaling;
  2289. if (!NT_SUCCESS(deviceExtension->LastPowerUpStatus)) {
  2290. ntStatus = deviceExtension->LastPowerUpStatus;
  2291. } else {
  2292. doResumeSignaling = !(deviceExtension->HcFlags
  2293. & HCFLAG_RH_OFF);
  2294. deviceExtension->HcFlags &= ~HCFLAG_RH_OFF;
  2295. UHCD_SetControllerD0(DeviceObject);
  2296. UHCD_RestoreHCstate(DeviceObject);
  2297. ntStatus = UHCD_Resume(DeviceObject, doResumeSignaling);
  2298. }
  2299. }
  2300. break;
  2301. case PowerDeviceD1:
  2302. case PowerDeviceD2:
  2303. UHCD_SaveHCstate(DeviceObject);
  2304. ntStatus = UHCD_Suspend(DeviceObject, TRUE);
  2305. break;
  2306. case PowerDeviceD3:
  2307. deviceExtension->HcFlags |= HCFLAG_RH_OFF;
  2308. UHCD_SaveHCstate(DeviceObject);
  2309. ntStatus = UHCD_Suspend(DeviceObject, FALSE);
  2310. break;
  2311. }
  2312. break;
  2313. }
  2314. }
  2315. return ntStatus;
  2316. }
  2317. VOID
  2318. UhcdKickStartController(IN PDEVICE_OBJECT PDevObj)
  2319. /*++
  2320. Routine Description:
  2321. Best effort at fixing a hung UHCI device on power up.
  2322. Symptom is that everything is fine and chip in run state,
  2323. but frame counter never increments. It was found that if
  2324. we strobe the run/stop (RS) bit, the frame counter starts incrementing
  2325. and the device starts working.
  2326. We don't know the exact cause or why the fix appears to work, but the
  2327. addition of this code was requested by MS management to help alleviate the
  2328. problem.
  2329. Arguments:
  2330. PDevObj - DeviceObject for this USB controller.
  2331. Return Value:
  2332. VOID
  2333. --*/
  2334. {
  2335. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)PDevObj->DeviceExtension;
  2336. USHORT cmd;
  2337. USHORT counter;
  2338. ULONG i;
  2339. LARGE_INTEGER deltaTime;
  2340. for (i = 0; i < UHCD_MAX_KICK_STARTS; i++) {
  2341. //
  2342. // Wait at least two frames (2 ms)
  2343. //
  2344. deltaTime.QuadPart = -10000 * 2;
  2345. KeDelayExecutionThread(KernelMode, FALSE, &deltaTime);
  2346. counter = READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(pDevExt));
  2347. if (counter != 0x0000) {
  2348. //
  2349. // It is working splendidly
  2350. //
  2351. break;
  2352. }
  2353. //
  2354. // The frame counter is jammed. Kick the chip.
  2355. //
  2356. cmd = READ_PORT_USHORT(COMMAND_REG(pDevExt)) & ~UHCD_CMD_RUN;
  2357. WRITE_PORT_USHORT(COMMAND_REG(pDevExt), cmd);
  2358. //
  2359. // Delay two frames (2ms)
  2360. //
  2361. deltaTime.QuadPart = -10000 * 2;
  2362. KeDelayExecutionThread(KernelMode, FALSE, &deltaTime);
  2363. cmd |= UHCD_CMD_RUN;
  2364. WRITE_PORT_USHORT(COMMAND_REG(pDevExt), cmd);
  2365. }
  2366. LOGENTRY(LOG_MISC | LOG_IO, 'HCks', i, UHCD_MAX_KICK_STARTS, 0);
  2367. }
  2368. NTSTATUS
  2369. UHCD_FixPIIX4(
  2370. IN PDEVICE_OBJECT DeviceObject
  2371. )
  2372. /*++
  2373. Routine Description:
  2374. PIIX4 hack
  2375. we will need a dummy bulk queue head inserted in the schedule
  2376. This routine resumes the host controller.
  2377. Arguments:
  2378. DeviceObject - DeviceObject for this USB controller.
  2379. Return Value:
  2380. NT status code.
  2381. --*/
  2382. {
  2383. PUHCD_ENDPOINT endpoint;
  2384. PHW_TRANSFER_DESCRIPTOR transferDescriptor,
  2385. qhtransferDescriptor;
  2386. PHW_QUEUE_HEAD queueHead;
  2387. PDEVICE_EXTENSION deviceExtension;
  2388. NTSTATUS ntStatus = STATUS_SUCCESS;
  2389. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2390. //
  2391. // create the endpoint
  2392. //
  2393. endpoint = GETHEAP(NonPagedPool, sizeof(UHCD_ENDPOINT));
  2394. if (endpoint) {
  2395. deviceExtension->Piix4EP = endpoint;
  2396. endpoint->Type = USB_ENDPOINT_TYPE_BULK;
  2397. endpoint->Sig = SIG_EP;
  2398. endpoint->EndpointFlags = 0;
  2399. // we will use two of the trigger TDs
  2400. //
  2401. // to set up the dummy qh with TD attached.
  2402. //
  2403. transferDescriptor =
  2404. &deviceExtension->TriggerTDList->TDs[3];
  2405. transferDescriptor->Active = 0;
  2406. transferDescriptor->Isochronous = 1;
  2407. transferDescriptor->InterruptOnComplete = 0;
  2408. transferDescriptor->PID = USB_OUT_PID;
  2409. transferDescriptor->Address = 0;
  2410. transferDescriptor->Endpoint = 1;
  2411. transferDescriptor->ErrorCounter = 0;
  2412. transferDescriptor->PacketBuffer = 0;
  2413. transferDescriptor->MaxLength =
  2414. NULL_PACKET_LENGTH;
  2415. // point to ourself
  2416. transferDescriptor->HW_Link =
  2417. transferDescriptor->PhysicalAddress;
  2418. queueHead = (PHW_QUEUE_HEAD)
  2419. &deviceExtension->TriggerTDList->TDs[4];
  2420. qhtransferDescriptor =
  2421. &deviceExtension->TriggerTDList->TDs[4];
  2422. UHCD_InitializeHardwareQueueHeadDescriptor(
  2423. DeviceObject,
  2424. queueHead,
  2425. qhtransferDescriptor->PhysicalAddress);
  2426. UHCD_KdPrint((2, "'PIIX4 dummy endpoint, qh 0x%x\n", endpoint, queueHead));
  2427. //link the td to the QH
  2428. queueHead->HW_VLink = transferDescriptor->PhysicalAddress;
  2429. queueHead->Endpoint = endpoint;
  2430. UHCD_InsertQueueHeadInSchedule(DeviceObject,
  2431. endpoint,
  2432. queueHead,
  2433. 0);
  2434. UHCD_BW_Reclimation(DeviceObject, FALSE);
  2435. } else {
  2436. // could not get memory for dummy queue head,
  2437. // something is really broken.
  2438. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2439. UHCD_KdTrap(("failed to get memory for dummy qh\n"));
  2440. }
  2441. return ntStatus;
  2442. }
  2443. #ifdef USB_BIOS
  2444. // this is the Phoenix revised version
  2445. NTSTATUS
  2446. UHCD_StopBIOS(
  2447. IN PDEVICE_OBJECT DeviceObject
  2448. )
  2449. /*++
  2450. Routine Description:
  2451. This routine stops a UHCI USB BIOS if present.
  2452. Arguments:
  2453. DeviceObject - DeviceObject for this USB controller.
  2454. Return Value:
  2455. NT status code.
  2456. --*/
  2457. {
  2458. USHORT cmd;
  2459. USHORT legsup, status;
  2460. PDEVICE_EXTENSION deviceExtension;
  2461. NTSTATUS ntStatus = STATUS_SUCCESS;
  2462. LARGE_INTEGER startTime;
  2463. ULONG sofModifyValue = 0;
  2464. WCHAR UHCD_SofModifyKey[] = L"SofModify";
  2465. PAGED_CODE();
  2466. UHCD_KdPrint((2, "'UHCD_Stopping BIOS\n"));
  2467. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2468. // initilialize to whatever the BIOS set it to.
  2469. sofModifyValue =
  2470. (ULONG) (READ_PORT_UCHAR(SOF_MODIFY_REG(deviceExtension)));
  2471. //
  2472. // save current values for BIOS hand-back
  2473. //
  2474. deviceExtension->BiosCmd =
  2475. READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2476. deviceExtension->BiosIntMask =
  2477. READ_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension));
  2478. deviceExtension->BiosFrameListBase =
  2479. READ_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension));
  2480. deviceExtension->BiosFrameListBase &= 0xfffff000;
  2481. // Grab any SOF ModifyValue indicated in the registry
  2482. //USBD_GetPdoRegistryParameter(deviceExtension->PhysicalDeviceObject,
  2483. // &sofModifyValue,
  2484. // sizeof(sofModifyValue),
  2485. // UHCD_SofModifyKey,
  2486. // sizeof(UHCD_SofModifyKey));
  2487. UHCD_GetSOFRegModifyValue(DeviceObject,
  2488. &sofModifyValue);
  2489. // save the SOF modify for posterity
  2490. deviceExtension->SavedSofModify = (CHAR) sofModifyValue;
  2491. UHCD_ASSERT(sofModifyValue <= 255);
  2492. // stop the controller,
  2493. // clear RUN bit but keep config flag set so BIOS won't reinit
  2494. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2495. LOGENTRY(LOG_MISC, 'spBI', cmd, 0, 0);
  2496. // BUGBUG
  2497. // save cmd bits to set when we hand back
  2498. cmd &= ~(UHCD_CMD_RUN | UHCD_CMD_SW_CONFIGURED);
  2499. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  2500. // NOTE: if no BIOS is present
  2501. // halt bit is initially set with PIIX3
  2502. // halt bit is initially clear with VIA
  2503. // now wait for HC to halt
  2504. KeQuerySystemTime(&startTime);
  2505. for (;;) {
  2506. LARGE_INTEGER sysTime;
  2507. status = READ_PORT_USHORT(STATUS_REG(deviceExtension));
  2508. UHCD_KdPrint((2, "'STATUS = %x\n", status));
  2509. if (status & UHCD_STATUS_HCHALT) {
  2510. WRITE_PORT_USHORT(STATUS_REG(deviceExtension), 0xff);
  2511. LOGENTRY(LOG_MISC, 'spBH', cmd, 0, 0);
  2512. break;
  2513. }
  2514. KeQuerySystemTime(&sysTime);
  2515. if (sysTime.QuadPart - startTime.QuadPart > 10000) {
  2516. // time out
  2517. #if DBG
  2518. UHCD_KdPrint((1,
  2519. "'TIMEOUT HALTING CONTROLLER! (I hope you don't have USB L-BIOS)\n"));
  2520. UHCD_KdPrint((1, "'THIS IS A BIOS BUG, Port Resources @ %x Ports Available \n",
  2521. deviceExtension->Port));
  2522. //TRAP();
  2523. #endif
  2524. break;
  2525. }
  2526. }
  2527. UHCD_ReadWriteConfig( deviceExtension->PhysicalDeviceObject,
  2528. TRUE,
  2529. &legsup,
  2530. 0xc0, // offset of legacy bios reg
  2531. sizeof(legsup));
  2532. LOGENTRY(LOG_MISC, 'legs', legsup, 0, 0);
  2533. UHCD_KdPrint((2, "'legs = %x\n", legsup));
  2534. #ifdef JD
  2535. // TEST_TRAP();
  2536. #endif
  2537. // save it
  2538. deviceExtension->LegacySupportRegister = legsup;
  2539. if ((legsup & LEGSUP_BIOS_MODE) != 0) {
  2540. // BUGBUG save old state
  2541. deviceExtension->HcFlags |= HCFLAG_USBBIOS;
  2542. UHCD_KdPrint((1, "'*** uhcd detected a USB legacy BIOS ***\n"));
  2543. //
  2544. // if BIOS mode bits set we have to take over
  2545. //
  2546. // shut off host controller SMI enable
  2547. legsup &= ~0x10;
  2548. UHCD_ReadWriteConfig( deviceExtension->PhysicalDeviceObject,
  2549. FALSE,
  2550. &legsup,
  2551. 0xc0, // offset of legacy bios reg
  2552. sizeof(legsup));
  2553. //
  2554. // BUGBUG
  2555. // out 0xff to 64h if possible
  2556. //
  2557. //
  2558. // take control
  2559. //
  2560. // read
  2561. UHCD_ReadWriteConfig( deviceExtension->PhysicalDeviceObject,
  2562. TRUE,
  2563. &legsup,
  2564. 0xc0, // offset of legacy bios reg
  2565. sizeof(legsup));
  2566. legsup = LEGSUP_HCD_MODE;
  2567. //write
  2568. UHCD_ReadWriteConfig( deviceExtension->PhysicalDeviceObject,
  2569. FALSE,
  2570. &legsup,
  2571. 0xc0, // offset of legacy bios reg
  2572. sizeof(legsup));
  2573. }
  2574. UHCD_KdPrint((2, "'exit UHCD_StopBIOS 0x%x\n", ntStatus));
  2575. return ntStatus;
  2576. }
  2577. NTSTATUS
  2578. UHCD_StartBIOS(
  2579. IN PDEVICE_OBJECT DeviceObject
  2580. )
  2581. /*++
  2582. Routine Description:
  2583. This routine start a USB bios.
  2584. Arguments:
  2585. DeviceObject - DeviceObject for this USB controller.
  2586. Return Value:
  2587. NT status code.
  2588. --*/
  2589. {
  2590. NTSTATUS ntStatus = STATUS_SUCCESS;
  2591. PDEVICE_EXTENSION deviceExtension;
  2592. USHORT cmd, legsup;
  2593. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2594. UHCD_KdPrint((1, "'Returning Control to USB BIOS, base port = %x\n",
  2595. deviceExtension->DeviceRegisters[0]));
  2596. // restore saved reg values
  2597. WRITE_PORT_USHORT(STATUS_REG(deviceExtension), 0xff);
  2598. WRITE_PORT_USHORT(INTERRUPT_MASK_REG(deviceExtension),
  2599. deviceExtension->BiosIntMask);
  2600. WRITE_PORT_ULONG(FRAME_LIST_BASE_REG(deviceExtension),
  2601. deviceExtension->BiosFrameListBase);
  2602. legsup = deviceExtension->LegacySupportRegister;
  2603. //write
  2604. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2605. FALSE,
  2606. &legsup,
  2607. 0xc0, // offset of legacy bios reg
  2608. sizeof(legsup));
  2609. // read
  2610. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2611. TRUE,
  2612. &legsup,
  2613. 0xc0, // offset of legacy bios reg
  2614. sizeof(legsup));
  2615. // enable SMI
  2616. legsup |= 0x10;
  2617. //write
  2618. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2619. FALSE,
  2620. &legsup,
  2621. 0xc0, // offset of legacy bios reg
  2622. sizeof(legsup));
  2623. cmd = deviceExtension->BiosCmd | UHCD_CMD_RUN;
  2624. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension),
  2625. cmd);
  2626. return ntStatus;
  2627. }
  2628. #endif //USB_BIOS
  2629. NTSTATUS
  2630. UHCD_GetResources(
  2631. IN PDEVICE_OBJECT DeviceObject,
  2632. IN PCM_RESOURCE_LIST ResourceList,
  2633. IN OUT PUHCD_RESOURCES Resources
  2634. )
  2635. /*++
  2636. Routine Description:
  2637. Arguments:
  2638. DeviceObject - DeviceObject for this USB controller.
  2639. ResourceList - Resources for this controller.
  2640. Return Value:
  2641. NT status code.
  2642. --*/
  2643. {
  2644. ULONG i;
  2645. NTSTATUS ntStatus = STATUS_SUCCESS;
  2646. PCM_PARTIAL_RESOURCE_DESCRIPTOR interrupt;
  2647. PHYSICAL_ADDRESS cardAddress;
  2648. ULONG addressSpace;
  2649. PDEVICE_EXTENSION deviceExtension;
  2650. PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
  2651. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDescriptor;
  2652. BOOLEAN gotIO=FALSE, gotIRQ=FALSE;
  2653. UHCD_KdPrint((2, "'enter UHCD_GetResources\n"));
  2654. LOGENTRY(LOG_MISC, 'GRES', 0, 0, 0);
  2655. if (ResourceList == NULL) {
  2656. UHCD_KdPrint((1, "'got no resources, failing start.\n"));
  2657. return STATUS_NONE_MAPPED;
  2658. }
  2659. fullResourceDescriptor = &ResourceList->List[0];
  2660. PartialResourceList = &fullResourceDescriptor->PartialResourceList;
  2661. deviceExtension = DeviceObject->DeviceExtension;
  2662. //
  2663. // Initailize our page list, do this here so that UHCD_CleanupDevice can
  2664. // clean up if necessary.
  2665. //
  2666. InitializeListHead(&deviceExtension->PageList);
  2667. deviceExtension->HcFlags |= HCFLAG_NEED_CLEANUP;
  2668. for (i = 0; i < PartialResourceList->Count && NT_SUCCESS(ntStatus); i++) {
  2669. switch (PartialResourceList->PartialDescriptors[i].Type) {
  2670. case CmResourceTypePort:
  2671. //
  2672. // Set up AddressSpace to be of type Port I/O
  2673. //
  2674. UHCD_KdPrint((1, "'Port Resources Found @ %x, %d Ports Available \n",
  2675. PartialResourceList->PartialDescriptors[i].u.Port.Start.LowPart,
  2676. PartialResourceList->PartialDescriptors[i].u.Port.Length));
  2677. #if DBG
  2678. deviceExtension->Port =
  2679. PartialResourceList->PartialDescriptors[i].u.Port.Start.LowPart;
  2680. #endif
  2681. addressSpace =
  2682. (PartialResourceList->PartialDescriptors[i].Flags & CM_RESOURCE_PORT_IO) ==
  2683. CM_RESOURCE_PORT_IO? 1:0;
  2684. cardAddress=PartialResourceList->PartialDescriptors[i].u.Port.Start;
  2685. if (!addressSpace) {
  2686. deviceExtension->HcFlags |= HCFLAG_UNMAP_REGISTERS;
  2687. deviceExtension->DeviceRegisters[0] =
  2688. MmMapIoSpace(
  2689. cardAddress,
  2690. PartialResourceList->PartialDescriptors[i].u.Port.Length,
  2691. FALSE);
  2692. } else {
  2693. deviceExtension->HcFlags &= ~HCFLAG_UNMAP_REGISTERS;
  2694. deviceExtension->DeviceRegisters[0] =
  2695. (PVOID)(ULONG_PTR)cardAddress.QuadPart;
  2696. }
  2697. //
  2698. // see if we successfully mapped the IO regs
  2699. //
  2700. if (!deviceExtension->DeviceRegisters[0]) {
  2701. UHCD_KdPrint((2, "'Couldn't map the device registers. \n"));
  2702. ntStatus = STATUS_NONE_MAPPED;
  2703. } else {
  2704. UHCD_KdPrint((2, "'Mapped device registers to 0x%x.\n",
  2705. deviceExtension->DeviceRegisters[0]));
  2706. gotIO=TRUE;
  2707. deviceExtension->HcFlags |= HCFLAG_GOT_IO;
  2708. }
  2709. break;
  2710. case CmResourceTypeInterrupt:
  2711. //
  2712. // Get Vector, level, and affinity information for this interrupt.
  2713. //
  2714. UHCD_KdPrint((1, "'Interrupt Resources Found! Level = %x Vector = %x\n",
  2715. PartialResourceList->PartialDescriptors[i].u.Interrupt.Level,
  2716. PartialResourceList->PartialDescriptors[i].u.Interrupt.Vector
  2717. ));
  2718. interrupt = &PartialResourceList->PartialDescriptors[i];
  2719. gotIRQ=TRUE;
  2720. //BUGBUG ??
  2721. //KeInitializeSpinLock(&DeviceExtension->InterruptSpinLock);
  2722. //DeviceExtension->InterruptMode = PartialResourceList->PartialDescriptors[i].Flags;
  2723. break;
  2724. case CmResourceTypeMemory:
  2725. //
  2726. // Set up AddressSpace to be of type Memory mapped I/O
  2727. //
  2728. UHCD_KdPrint((1, "'Memory Resources Found @ %x, Length = %x\n",
  2729. PartialResourceList->PartialDescriptors[i].u.Memory.Start.LowPart,
  2730. PartialResourceList->PartialDescriptors[i].u.Memory.Length
  2731. ));
  2732. // we should never get memory resources
  2733. UHCD_KdTrap(("PnP gave us memory resources!!\n"));
  2734. break;
  2735. } /* switch */
  2736. } /* for */
  2737. //
  2738. // Sanity check that we got enough resources.
  2739. //
  2740. if (!gotIO || !gotIRQ) {
  2741. UHCD_KdPrint((1, "'Missing IO or IRQ: failing to start\n"));
  2742. ntStatus = STATUS_NONE_MAPPED;
  2743. }
  2744. if (NT_SUCCESS(ntStatus)) {
  2745. //
  2746. // Note that we have all the resources we need
  2747. // to start
  2748. //
  2749. //
  2750. // Set up our interrupt.
  2751. //
  2752. UHCD_KdPrint((2, "'requesting interrupt vector %x level %x\n",
  2753. interrupt->u.Interrupt.Level,
  2754. interrupt->u.Interrupt.Vector));
  2755. Resources->InterruptLevel=(KIRQL)interrupt->u.Interrupt.Level;
  2756. Resources->InterruptVector=interrupt->u.Interrupt.Vector;
  2757. Resources->Affinity=interrupt->u.Interrupt.Affinity;
  2758. //
  2759. // Initialize the interrupt object for the controller.
  2760. //
  2761. deviceExtension->InterruptObject = NULL;
  2762. Resources->ShareIRQ =
  2763. interrupt->ShareDisposition == CmResourceShareShared ? TRUE : FALSE;
  2764. Resources->InterruptMode =
  2765. interrupt->Flags == CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive;
  2766. #ifdef MAX_DEBUG
  2767. UHCD_KdPrint((2, "'interrupt->ShareDisposition %x\n", interrupt->ShareDisposition));
  2768. if (!Resources->ShareIRQ) {
  2769. TEST_TRAP();
  2770. }
  2771. #endif
  2772. }
  2773. UHCD_KdPrint((2, "'exit UHCD_GetResources (%x)\n", ntStatus));
  2774. LOGENTRY(LOG_MISC, 'GRS1', 0, 0, ntStatus);
  2775. return ntStatus;
  2776. }
  2777. NTSTATUS
  2778. UHCD_StartDevice(
  2779. IN PDEVICE_OBJECT DeviceObject,
  2780. IN PUHCD_RESOURCES Resources
  2781. )
  2782. /*++
  2783. Routine Description:
  2784. This routine initializes the DeviceObject for a given instance
  2785. of a USB host controller.
  2786. Arguments:
  2787. DeviceObject - DeviceObject for this USB controller.
  2788. Resources - our assigned resources
  2789. Return Value:
  2790. NT status code.
  2791. --*/
  2792. {
  2793. NTSTATUS ntStatus = STATUS_SUCCESS;
  2794. PDEVICE_EXTENSION deviceExtension;
  2795. LARGE_INTEGER deltaTime;
  2796. DEVICE_CAPABILITIES deviceCapabilities;
  2797. ULONG numberOfMapRegisters = (ULONG)-1;
  2798. DEVICE_DESCRIPTION deviceDescription;
  2799. BOOLEAN isPIIX3or4;
  2800. ULONG disableSelectiveSuspendValue = 0;
  2801. WCHAR disableSelectiveSuspendKey[] = DISABLE_SELECTIVE_SUSPEND;
  2802. WCHAR clocksPerFrameKey[] = CLOCKS_PER_FRAME;
  2803. WCHAR recClocksPerFrameKey[] = REC_CLOCKS_PER_FRAME;
  2804. LONG clocksPerFrame = 0;
  2805. LONG recClocksPerFrame = 0;
  2806. PUSBD_EXTENSION usbdExtension;
  2807. PAGED_CODE();
  2808. deviceExtension = DeviceObject->DeviceExtension;
  2809. // get the debug options from the registry
  2810. #if DBG
  2811. UHCD_GetClassGlobalDebugRegistryParameters();
  2812. #endif
  2813. UHCD_KdPrint((2, "'enter UHCD_StartDevice\n"));
  2814. deviceExtension->HcFlags &= ~HCFLAG_HCD_STOPPED;
  2815. // enable the idle check routine
  2816. deviceExtension->HcFlags &= ~HCFLAG_DISABLE_IDLE;
  2817. LOGENTRY(LOG_MISC, 'STRT', deviceExtension->TopOfStackDeviceObject, 0, 0);
  2818. //
  2819. // sanity check our registers
  2820. //
  2821. {
  2822. USHORT cmd;
  2823. cmd = READ_PORT_USHORT(COMMAND_REG(deviceExtension));
  2824. if (cmd == 0xffff) {
  2825. UHCD_KdPrint((0, "'Controller Registers are bogus -- this is a bug\n"));
  2826. UHCD_KdPrint((0, "'Controller will FAIL to start\n"));
  2827. TRAP();
  2828. // regs are bogus -- clear the gotio flag so we don't
  2829. // try to access the registers any more
  2830. deviceExtension->HcFlags &= ~HCFLAG_GOT_IO;
  2831. ntStatus = STATUS_UNSUCCESSFUL;
  2832. }
  2833. }
  2834. if (!NT_SUCCESS(ntStatus)) {
  2835. goto UHCD_InitializeDeviceExit;
  2836. }
  2837. //
  2838. // Create our adapter object
  2839. //
  2840. RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
  2841. //BUGBUG check these
  2842. deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  2843. deviceDescription.Master = TRUE;
  2844. deviceDescription.ScatterGather = TRUE;
  2845. deviceDescription.Dma32BitAddresses = TRUE;
  2846. deviceDescription.InterfaceType = PCIBus;
  2847. deviceDescription.DmaWidth = Width32Bits;
  2848. deviceDescription.DmaSpeed = Compatible;
  2849. deviceDescription.MaximumLength = (ULONG)-1;
  2850. deviceExtension->NumberOfMapRegisters = (ULONG)-1;
  2851. deviceExtension->AdapterObject =
  2852. IoGetDmaAdapter(deviceExtension->PhysicalDeviceObject,
  2853. &deviceDescription,
  2854. &deviceExtension->NumberOfMapRegisters);
  2855. if (deviceExtension->AdapterObject == NULL) {
  2856. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2857. goto UHCD_InitializeDeviceExit;
  2858. }
  2859. //
  2860. // We found a host controller or a host controller found us, do the final
  2861. // stages of initialization.
  2862. // Setup state variables for the host controller
  2863. //
  2864. ntStatus = UHCD_QueryCapabilities(deviceExtension->TopOfStackDeviceObject,
  2865. &deviceCapabilities);
  2866. if (!NT_SUCCESS(ntStatus)) {
  2867. goto UHCD_InitializeDeviceExit;
  2868. }
  2869. if (deviceExtension->HcFlags & HCFLAG_MAP_SX_TO_D3) {
  2870. ULONG i;
  2871. for (i=PowerSystemSleeping1; i< PowerSystemMaximum; i++) {
  2872. deviceCapabilities.DeviceState[i] = PowerDeviceD3;
  2873. UHCD_KdPrint((1, "'changing -->S%d = D%d\n", i-1,
  2874. deviceCapabilities.DeviceState[i]-1));
  2875. }
  2876. }
  2877. #if DBG
  2878. {
  2879. ULONG i;
  2880. UHCD_KdPrint((1, "'HCD Device Caps returned from PCI:\n"));
  2881. UHCD_KdPrint((1, "'\tSystemWake = S%d\n", deviceCapabilities.SystemWake-1));
  2882. UHCD_KdPrint((1, "'\tDeviceWake = D%d\n", deviceCapabilities.DeviceWake-1));
  2883. UHCD_KdPrint((1, "'\tDevice State Map:\n"));
  2884. for (i=0; i< PowerSystemHibernate; i++) {
  2885. UHCD_KdPrint((1, "'\t-->S%d = D%d\n", i-1,
  2886. deviceCapabilities.DeviceState[i]-1));
  2887. }
  2888. }
  2889. #endif
  2890. USBD_RegisterHcDeviceCapabilities(DeviceObject,
  2891. &deviceCapabilities,
  2892. UHCD_RootHubPower);
  2893. //
  2894. // Detect the Host Controller stepping version.
  2895. //
  2896. {
  2897. UCHAR revisionId;
  2898. USHORT vendorId, deviceId;
  2899. UHCD_KdPrint((2, "'Get the stepping version\n"));
  2900. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2901. TRUE,
  2902. &vendorId,
  2903. 0,
  2904. sizeof(vendorId));
  2905. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2906. TRUE,
  2907. &deviceId,
  2908. 2,
  2909. sizeof(deviceId));
  2910. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2911. TRUE,
  2912. &revisionId,
  2913. 8,
  2914. sizeof(revisionId));
  2915. UHCD_KdPrint((1, "'HC vendor = %x device = %x rev = %x\n",
  2916. vendorId, deviceId, revisionId));
  2917. if (vendorId == UHCD_INTEL_VENDOR_ID &&
  2918. deviceId == UHCD_PIIX3_DEVICE_ID) {
  2919. UHCD_KdPrint((1, "'detected PIIX3\n"));
  2920. deviceExtension->ControllerType = UHCI_HW_VERSION_PIIX3;
  2921. } else if (vendorId == UHCD_INTEL_VENDOR_ID &&
  2922. deviceId == UHCD_PIIX4_DEVICE_ID) {
  2923. UHCD_KdPrint((1, "'detected PIIX4\n"));
  2924. deviceExtension->ControllerType = UHCI_HW_VERSION_PIIX4;
  2925. } else {
  2926. UHCD_KdPrint((1, "'detected unknown host controller type\n"));
  2927. deviceExtension->ControllerType = UHCI_HW_VERSION_UNKNOWN;
  2928. }
  2929. //
  2930. // is this an A1 stepping version of the piix3?
  2931. //
  2932. if (revisionId == 0 &&
  2933. vendorId == UHCD_INTEL_VENDOR_ID &&
  2934. deviceId == UHCD_PIIX3_DEVICE_ID) {
  2935. //yes, we will fail to load on the A1 systems
  2936. UHCD_KdPrint((0, "'Intel USB HC stepping version A1 is not supported\n"));
  2937. deviceExtension->SteppingVersion = UHCD_A1_STEP;
  2938. ntStatus = STATUS_UNSUCCESSFUL;
  2939. } else {
  2940. #ifdef ENABLE_B0_FEATURES
  2941. deviceExtension->SteppingVersion = UHCD_B0_STEP;
  2942. #else
  2943. deviceExtension->SteppingVersion = UHCD_A1_STEP;
  2944. #endif //ENABLE_B0_FEATURES
  2945. }
  2946. #ifdef USB_BIOS
  2947. if (NT_SUCCESS(ntStatus)) {
  2948. ntStatus = UHCD_StopBIOS(DeviceObject);
  2949. }
  2950. #endif //USB_BIOS
  2951. }
  2952. {
  2953. USHORT legsup;
  2954. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  2955. TRUE,
  2956. &legsup,
  2957. 0xc0, // offset of legacy bios reg
  2958. sizeof(legsup));
  2959. LOGENTRY(LOG_MISC, 'PIRd', deviceExtension, legsup, 0);
  2960. // set the PIRQD routing bit
  2961. legsup |= LEGSUP_USBPIRQD_EN;
  2962. UHCD_ReadWriteConfig( deviceExtension->PhysicalDeviceObject,
  2963. FALSE,
  2964. &legsup,
  2965. 0xc0, // offset of legacy bios reg
  2966. sizeof(legsup));
  2967. }
  2968. if (!NT_SUCCESS(ntStatus)) {
  2969. goto UHCD_InitializeDeviceExit;
  2970. }
  2971. ntStatus = UHCD_InitializeSchedule(DeviceObject);
  2972. LOGENTRY(LOG_MISC, 'INIs', 0, 0, ntStatus);
  2973. if (!NT_SUCCESS(ntStatus)) {
  2974. UHCD_KdPrint((0, "'InitializeSchedule Failed! %x\n", ntStatus));
  2975. goto UHCD_InitializeDeviceExit;
  2976. }
  2977. //
  2978. // initialization all done, last step is to connect the interrupt & DPCs.
  2979. //
  2980. KeInitializeDpc(&deviceExtension->IsrDpc,
  2981. UHCD_IsrDpc,
  2982. DeviceObject);
  2983. UHCD_KdPrint((2, "'requesting interrupt vector %x level %x\n",
  2984. Resources->InterruptLevel,
  2985. Resources->InterruptVector));
  2986. ntStatus = IoConnectInterrupt(
  2987. &(deviceExtension->InterruptObject),
  2988. (PKSERVICE_ROUTINE) UHCD_InterruptService,
  2989. (PVOID) DeviceObject,
  2990. (PKSPIN_LOCK)NULL,
  2991. Resources->InterruptVector,
  2992. Resources->InterruptLevel,
  2993. Resources->InterruptLevel,
  2994. Resources->InterruptMode,
  2995. Resources->ShareIRQ,
  2996. Resources->Affinity,
  2997. FALSE); // BUGBUG FloatingSave, this is configurable
  2998. LOGENTRY(LOG_MISC, 'IOCi', 0, 0, ntStatus);
  2999. if (!NT_SUCCESS(ntStatus)) {
  3000. UHCD_KdPrint((0, "'IoConnectInterrupt Failed! %x\n", ntStatus));
  3001. goto UHCD_InitializeDeviceExit;
  3002. }
  3003. // consider ourselves 'ON'
  3004. deviceExtension->CurrentDevicePowerState = PowerDeviceD0;
  3005. //
  3006. // Initialize the controller registers.
  3007. // NOTE:
  3008. // We don't do reset until the interrrupt is hooked because
  3009. // the HC for some reason likes to generate an interrupt
  3010. // (USBINT) when it is reset.
  3011. //
  3012. ntStatus = UHCD_StartGlobalReset(DeviceObject);
  3013. LOGENTRY(LOG_MISC, 'GLBr', 0, 0, ntStatus);
  3014. if (!NT_SUCCESS(ntStatus)) {
  3015. UHCD_KdPrint((0, "'GlobalReset Failed! %x\n", ntStatus));
  3016. goto UHCD_InitializeDeviceExit;
  3017. }
  3018. //
  3019. // Everything is set, we need to wait for the
  3020. // global reset of the Host controller to complete.
  3021. //
  3022. // 20 ms to reset...
  3023. deltaTime.QuadPart = -10000 * 20;
  3024. //
  3025. // block here until reset is complete
  3026. //
  3027. (VOID) KeDelayExecutionThread(KernelMode,
  3028. FALSE,
  3029. &deltaTime);
  3030. ntStatus = UHCD_CompleteGlobalReset(DeviceObject);
  3031. // 10 ms for devices to recover
  3032. // BUGBUG seems the Philips speakers need this
  3033. // deltaTime.QuadPart = -10000 * 1000;
  3034. //
  3035. // (VOID) KeDelayExecutionThread(KernelMode,
  3036. // FALSE,
  3037. // &deltaTime);
  3038. if (!NT_SUCCESS(ntStatus)) {
  3039. goto UHCD_InitializeDeviceExit;
  3040. }
  3041. //
  3042. // bus reset complete, now activate the root hub emulation
  3043. //
  3044. #ifdef ROOT_HUB
  3045. UHCD_KdPrint((2, "'Initialize Root Hub\n"));
  3046. //
  3047. // BUGBUG hard coded to two ports
  3048. //
  3049. isPIIX3or4 = (deviceExtension->ControllerType == UHCI_HW_VERSION_PIIX3) ||
  3050. (deviceExtension->ControllerType == UHCI_HW_VERSION_PIIX4);
  3051. USBD_GetPdoRegistryParameter(deviceExtension->PhysicalDeviceObject,
  3052. &disableSelectiveSuspendValue,
  3053. sizeof(disableSelectiveSuspendValue),
  3054. disableSelectiveSuspendKey,
  3055. sizeof(disableSelectiveSuspendKey));
  3056. USBD_GetPdoRegistryParameter(deviceExtension->PhysicalDeviceObject,
  3057. &recClocksPerFrame,
  3058. sizeof(recClocksPerFrame),
  3059. recClocksPerFrameKey,
  3060. sizeof(recClocksPerFrameKey));
  3061. deviceExtension->RegRecClocksPerFrame =
  3062. recClocksPerFrame;
  3063. if ((deviceExtension->RootHub =
  3064. RootHub_Initialize(DeviceObject,
  3065. 2,
  3066. (BOOLEAN)(!isPIIX3or4 &&
  3067. !disableSelectiveSuspendValue))) == NULL) {
  3068. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  3069. }
  3070. #if DBG
  3071. if (!isPIIX3or4 && !disableSelectiveSuspendValue) {
  3072. UHCD_KdPrint ((1, "'selective suspend enabled\n"));
  3073. } else {
  3074. UHCD_KdPrint ((1, "'selective suspend disabled\n"));
  3075. }
  3076. #endif
  3077. // HACK - Tell USBD if this HC is PIIX3 or PIIX4.
  3078. if (isPIIX3or4) {
  3079. usbdExtension = (PUSBD_EXTENSION)deviceExtension;
  3080. usbdExtension->IsPIIX3or4 = TRUE;
  3081. }
  3082. // END HACK
  3083. deviceExtension->RootHubTimersActive = 0;
  3084. #endif //ROOT_HUB
  3085. //
  3086. // our current power state is 'ON'
  3087. //
  3088. deviceExtension->CurrentDevicePowerState = PowerDeviceD0;
  3089. // this will disable the controller if nothing
  3090. // is initailly connected to the ports
  3091. KeQuerySystemTime(&deviceExtension->LastIdleTime);
  3092. deviceExtension->IdleTime = 100000000;
  3093. deviceExtension->XferIdleTime = 0;
  3094. UHCD_InitializeDeviceExit:
  3095. if (!NT_SUCCESS(ntStatus)) {
  3096. #ifdef MAX_DEBUG
  3097. TEST_TRAP();
  3098. #endif
  3099. UHCD_KdPrint((2, "'Initialization Failed, cleaning up \n"));
  3100. //
  3101. // The initialization failed. Cleanup resources before exiting.
  3102. //
  3103. //
  3104. // Note: No need/way to undo the KeInitializeDpc or
  3105. // KeInitializeTimer calls.
  3106. //
  3107. UHCD_CleanupDevice(DeviceObject);
  3108. }
  3109. UHCD_KdPrint((2, "'exit UHCD_StartDevice (%x)\n", ntStatus));
  3110. return ntStatus;
  3111. }
  3112. NTSTATUS
  3113. UHCD_DeferredStartDevice(
  3114. IN PDEVICE_OBJECT DeviceObject,
  3115. IN PIRP Irp
  3116. )
  3117. /*++
  3118. Routine Description:
  3119. Arguments:
  3120. DeviceObject - DeviceObject for this USB controller.
  3121. Return Value:
  3122. NT Status code.
  3123. --*/
  3124. {
  3125. NTSTATUS ntStatus;
  3126. UHCD_RESOURCES resources;
  3127. PIO_STACK_LOCATION irpStack;
  3128. PDEVICE_EXTENSION deviceExtension;
  3129. ULONG forceLowPowerState = 0;
  3130. PAGED_CODE();
  3131. deviceExtension = DeviceObject->DeviceExtension;
  3132. // initailize extension here
  3133. deviceExtension->HcFlags = 0;
  3134. UHCD_GetClassGlobalRegistryParameters(&forceLowPowerState);
  3135. if (forceLowPowerState) {
  3136. deviceExtension->HcFlags |= HCFLAG_MAP_SX_TO_D3;
  3137. }
  3138. irpStack = IoGetCurrentIrpStackLocation (Irp);
  3139. ntStatus = UHCD_GetResources(DeviceObject,
  3140. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated,
  3141. &resources);
  3142. if (NT_SUCCESS(ntStatus)) {
  3143. ntStatus = UHCD_StartDevice(DeviceObject,
  3144. &resources);
  3145. }
  3146. //
  3147. // Set the IRP status because USBD doesn't
  3148. //
  3149. Irp->IoStatus.Status = ntStatus;
  3150. LOGENTRY(LOG_MISC, 'dfST', 0, 0, ntStatus);
  3151. return ntStatus;
  3152. }
  3153. BOOLEAN
  3154. UHCD_UpdateFrameCounter(
  3155. IN PVOID Context
  3156. )
  3157. /*++
  3158. Routine Description:
  3159. Starts the USB host controller executing the schedule.
  3160. Start Controller is called in by KeSynchronizeExecution.
  3161. Arguments:
  3162. Context - DeviceData for this USB controller.
  3163. Return Value:
  3164. TRUE
  3165. --*/
  3166. {
  3167. PDEVICE_EXTENSION deviceExtension;
  3168. ULONG frameNumber;
  3169. ULONG currentFrame, highPart;
  3170. deviceExtension = Context;
  3171. // This code maintains the 32-bit frame counter
  3172. frameNumber = (ULONG) READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension));
  3173. // did the sign bit change ?
  3174. if ((deviceExtension->LastFrame ^ frameNumber) & 0x0400) {
  3175. // Yes
  3176. deviceExtension->FrameHighPart += 0x0800 -
  3177. ((frameNumber ^ deviceExtension->FrameHighPart) & 0x0400);
  3178. }
  3179. // remember the last frame number
  3180. deviceExtension->LastFrame = frameNumber;
  3181. // calc frame number and update las frame processed
  3182. // if necseesary
  3183. highPart = deviceExtension->FrameHighPart;
  3184. // get 11-bit frame number, high 17-bits are 0
  3185. //frameNumber = (ULONG) READ_PORT_USHORT(FRAME_LIST_CURRENT_INDEX_REG(deviceExtension));
  3186. currentFrame = ((frameNumber & 0x0bff) | highPart) +
  3187. ((frameNumber ^ highPart) & 0x0400);
  3188. //UHCD_KdPrint((2, "'currentFrame2 = %x\n", currentFrame));
  3189. if (deviceExtension->HcFlags & HCFLAG_ROLLOVER_IDLE) {
  3190. deviceExtension->LastFrameProcessed = currentFrame - 1;
  3191. }
  3192. return TRUE;
  3193. }
  3194. VOID
  3195. UHCD_DisableIdleCheck(
  3196. IN PDEVICE_EXTENSION DeviceExtension
  3197. )
  3198. {
  3199. KIRQL irql;
  3200. KeAcquireSpinLock(&DeviceExtension->HcFlagSpin, &irql);
  3201. DeviceExtension->HcFlags |= HCFLAG_DISABLE_IDLE;
  3202. KeReleaseSpinLock(&DeviceExtension->HcFlagSpin, irql);
  3203. }
  3204. VOID
  3205. UHCD_WakeIdle(
  3206. IN PDEVICE_OBJECT DeviceObject
  3207. )
  3208. /*++
  3209. Routine Description:
  3210. takes the controller out of the idle state
  3211. Arguments:
  3212. Return Value:
  3213. None
  3214. --*/
  3215. {
  3216. KIRQL irql;
  3217. PDEVICE_EXTENSION deviceExtension;
  3218. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  3219. LOGENTRY(LOG_MISC, 'wIDL', DeviceObject, 0, 0);
  3220. KeRaiseIrql(DISPATCH_LEVEL, &irql);
  3221. deviceExtension->XferIdleTime = 0;
  3222. UHCD_CheckIdle(DeviceObject);
  3223. KeLowerIrql(irql);
  3224. }
  3225. VOID
  3226. UHCD_CheckIdle(
  3227. IN PDEVICE_OBJECT DeviceObject
  3228. )
  3229. /*++
  3230. Routine Description:
  3231. If the controllers hub ports are not connected this function
  3232. stops the host controller
  3233. If there are no iso enpoints open then this function
  3234. disables the rollover interrupt
  3235. Arguments:
  3236. DeviceObject - DeviceObject of the controller to stop
  3237. Return Value:
  3238. NT status code.
  3239. --*/
  3240. {
  3241. NTSTATUS ntStatus = STATUS_SUCCESS;
  3242. PDEVICE_EXTENSION deviceExtension;
  3243. BOOLEAN portsIdle = TRUE;
  3244. USHORT cmd;
  3245. LARGE_INTEGER timeNow;
  3246. BOOLEAN fastIsoEndpointListEmpty;
  3247. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  3248. fastIsoEndpointListEmpty = IsListEmpty(&deviceExtension->FastIsoEndpointList);
  3249. KeAcquireSpinLockAtDpcLevel(&deviceExtension->HcFlagSpin);
  3250. if (deviceExtension->HcFlags & HCFLAG_DISABLE_IDLE) {
  3251. goto UHCD_CheckIdle_Done;
  3252. }
  3253. UHCD_ASSERT(deviceExtension->InterruptObject);
  3254. if (!KeSynchronizeExecution(deviceExtension->InterruptObject,
  3255. UHCD_UpdateFrameCounter,
  3256. deviceExtension)) {
  3257. TRAP(); //something has gone terribly wrong
  3258. }
  3259. portsIdle = RootHub_PortsIdle(deviceExtension->RootHub) &&
  3260. IsListEmpty(&deviceExtension->EndpointList);
  3261. if (portsIdle) {
  3262. if (!(deviceExtension->HcFlags & HCFLAG_IDLE)) {
  3263. // we are not idle,
  3264. // see how long ports have been idle if it
  3265. // is longer then 10 seconds stop the
  3266. // controller
  3267. KeQuerySystemTime(&timeNow);
  3268. if (deviceExtension->IdleTime == 0) {
  3269. KeQuerySystemTime(&deviceExtension->LastIdleTime);
  3270. deviceExtension->IdleTime = 1;
  3271. }
  3272. deviceExtension->IdleTime +=
  3273. (LONG) (timeNow.QuadPart -
  3274. deviceExtension->LastIdleTime.QuadPart);
  3275. deviceExtension->LastIdleTime = timeNow;
  3276. // ports are idle stop the controller
  3277. if (// 10 seconds in 100ns units
  3278. deviceExtension->IdleTime > 100000000) {
  3279. cmd = READ_PORT_USHORT(
  3280. COMMAND_REG(deviceExtension)) & ~UHCD_CMD_RUN;
  3281. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  3282. deviceExtension->HcFlags |= HCFLAG_IDLE;
  3283. deviceExtension->IdleTime = 0;
  3284. LOGENTRY(LOG_MISC, 'sOFF', DeviceObject, 0, 0);
  3285. UHCD_KdPrint((2, "'HC stopped\n"));
  3286. }
  3287. }
  3288. } else {
  3289. // ports are active start the controller
  3290. deviceExtension->IdleTime = 0;
  3291. if (deviceExtension->HcFlags & HCFLAG_IDLE) {
  3292. UHCD_KdPrint((2, "'ports active, break idle\n"));
  3293. // reset the frame list current index
  3294. WRITE_PORT_USHORT(
  3295. FRAME_LIST_CURRENT_INDEX_REG(deviceExtension), 0);
  3296. // re-initialize internal frame counters.
  3297. deviceExtension->FrameHighPart =
  3298. deviceExtension->LastFrame = 0;
  3299. cmd = READ_PORT_USHORT(
  3300. COMMAND_REG(deviceExtension)) | UHCD_CMD_RUN;
  3301. WRITE_PORT_USHORT(COMMAND_REG(deviceExtension), cmd);
  3302. LOGENTRY(LOG_MISC, 's-ON', DeviceObject, 0, 0);
  3303. deviceExtension->HcFlags &= ~HCFLAG_IDLE;
  3304. UHCD_KdPrint((2, "'HC restart\n"));
  3305. }
  3306. }
  3307. //
  3308. // now deal with the HC rollover interrupt
  3309. //
  3310. if (!(deviceExtension->HcFlags & HCFLAG_ROLLOVER_IDLE)) {
  3311. //
  3312. // rollover ints are on,
  3313. // see how long it has been since the last data transfer
  3314. //
  3315. KeQuerySystemTime(&timeNow);
  3316. if (deviceExtension->XferIdleTime == 0) {
  3317. KeQuerySystemTime(&deviceExtension->LastXferIdleTime);
  3318. deviceExtension->XferIdleTime = 1;
  3319. }
  3320. deviceExtension->XferIdleTime +=
  3321. (LONG) (timeNow.QuadPart -
  3322. deviceExtension->LastXferIdleTime.QuadPart);
  3323. deviceExtension->LastXferIdleTime = timeNow;
  3324. }
  3325. if (deviceExtension->XferIdleTime > 100000000 &&
  3326. !fastIsoEndpointListEmpty) {
  3327. // are we currently idle
  3328. if (!(deviceExtension->HcFlags & HCFLAG_ROLLOVER_IDLE)) {
  3329. //
  3330. // No
  3331. //
  3332. // if we have seen no data transfers submitted
  3333. // for 10 seconds disable the rollover interrupt
  3334. //
  3335. // turn off the interrupts for rollover
  3336. deviceExtension->HcFlags |= HCFLAG_ROLLOVER_IDLE;
  3337. deviceExtension->TriggerTDList->TDs[0].InterruptOnComplete =
  3338. deviceExtension->TriggerTDList->TDs[1].InterruptOnComplete = 0;
  3339. //UHCD_KdPrint((2, "UHCD: HC idle ints stopped\n"));
  3340. }
  3341. } else {
  3342. //
  3343. // this will turn on the rollover interrupts
  3344. // when we see transfers
  3345. //
  3346. // are we currently idle
  3347. if (deviceExtension->HcFlags & HCFLAG_ROLLOVER_IDLE) {
  3348. //
  3349. // Yes
  3350. //
  3351. UHCD_KdPrint((2, "'activate rollover ints\n"));
  3352. deviceExtension->TriggerTDList->TDs[0].InterruptOnComplete =
  3353. deviceExtension->TriggerTDList->TDs[1].InterruptOnComplete = 1;
  3354. deviceExtension->HcFlags &= ~HCFLAG_ROLLOVER_IDLE;
  3355. //UHCD_KdPrint((2, "UHCD: HC idle ints started\n"));
  3356. }
  3357. }
  3358. UHCD_CheckIdle_Done:
  3359. KeReleaseSpinLockFromDpcLevel(&deviceExtension->HcFlagSpin);
  3360. }
  3361. NTSTATUS
  3362. UHCD_GetSOFRegModifyValue(
  3363. IN PDEVICE_OBJECT DeviceObject,
  3364. IN OUT PULONG SofModifyValue
  3365. )
  3366. /*++
  3367. Routine Description:
  3368. Arguments:
  3369. DeviceObject - DeviceObject for this USB controller.
  3370. Return Value:
  3371. NT Status code.
  3372. --*/
  3373. {
  3374. NTSTATUS ntStatus = STATUS_SUCCESS;
  3375. LONG clocksPerFrame = 12000;
  3376. LONG recClocksPerFrame;
  3377. LONG sofModify;
  3378. PDEVICE_EXTENSION deviceExtension;
  3379. PAGED_CODE();
  3380. // the default
  3381. *SofModifyValue = 64;
  3382. deviceExtension = DeviceObject->DeviceExtension;
  3383. recClocksPerFrame =
  3384. deviceExtension->RegRecClocksPerFrame;
  3385. if (recClocksPerFrame && clocksPerFrame) {
  3386. sofModify = recClocksPerFrame - clocksPerFrame + 64;
  3387. *SofModifyValue = sofModify;
  3388. }
  3389. UHCD_KdPrint((1, "'Clocks/Frame %d Recommended Clocks/Frame %d SofModify %d\n",
  3390. clocksPerFrame, recClocksPerFrame, *SofModifyValue));
  3391. return ntStatus;
  3392. }
  3393. NTSTATUS
  3394. UHCD_GetConfigValue(
  3395. IN PWSTR ValueName,
  3396. IN ULONG ValueType,
  3397. IN PVOID ValueData,
  3398. IN ULONG ValueLength,
  3399. IN PVOID Context,
  3400. IN PVOID EntryContext
  3401. )
  3402. /*++
  3403. Routine Description:
  3404. This routine is a callback routine for RtlQueryRegistryValues
  3405. It is called for each entry in the Parameters
  3406. node to set the config values. The table is set up
  3407. so that this function will be called with correct default
  3408. values for keys that are not present.
  3409. Arguments:
  3410. ValueName - The name of the value (ignored).
  3411. ValueType - The type of the value
  3412. ValueData - The data for the value.
  3413. ValueLength - The length of ValueData.
  3414. Context - A pointer to the CONFIG structure.
  3415. EntryContext - The index in Config->Parameters to save the value.
  3416. Return Value:
  3417. --*/
  3418. {
  3419. NTSTATUS ntStatus = STATUS_SUCCESS;
  3420. UHCD_KdPrint((2, "'Type 0x%x, Length 0x%x\n", ValueType, ValueLength));
  3421. switch (ValueType) {
  3422. case REG_DWORD:
  3423. RtlCopyMemory(EntryContext, ValueData, sizeof(ULONG));
  3424. break;
  3425. case REG_BINARY:
  3426. // BUGBUG we are only set up to read a byte
  3427. RtlCopyMemory(EntryContext, ValueData, 1);
  3428. break;
  3429. default:
  3430. ntStatus = STATUS_INVALID_PARAMETER;
  3431. }
  3432. return ntStatus;
  3433. }
  3434. VOID
  3435. UHCD_SetControllerD0(
  3436. IN PDEVICE_OBJECT DeviceObject
  3437. )
  3438. /* ++
  3439. *
  3440. * Description:
  3441. *
  3442. * Work item scheduled to do processing at passive
  3443. * level when the controller is put in D0 by PNP/POWER.
  3444. *
  3445. *
  3446. * Arguments:
  3447. *
  3448. * Return:
  3449. *
  3450. * -- */
  3451. {
  3452. PDEVICE_EXTENSION deviceExtension;
  3453. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  3454. //if (deviceExtension->CurrentDevicePowerState == PowerDeviceD0) {
  3455. // TEST_TRAP();
  3456. // return;
  3457. //}
  3458. LOGENTRY(LOG_MISC, 'POWC', deviceExtension->CurrentDevicePowerState,
  3459. DeviceObject, 0);
  3460. switch (deviceExtension->CurrentDevicePowerState) {
  3461. case PowerDeviceD3:
  3462. UHCD_KdPrint((2, "'PowerDeviceD0 (ON) from (OFF)\n"));
  3463. deviceExtension->CurrentDevicePowerState = PowerDeviceD0;
  3464. break;
  3465. case PowerDeviceD1:
  3466. case PowerDeviceD2:
  3467. UHCD_KdPrint((2, "'PowerDeviceD0 (ON) from (SUSPEND)\n"));
  3468. break;
  3469. case PowerDeviceD0:
  3470. // probably a bug in the kernel/configmg or usbd
  3471. UHCD_KdPrint((2, "'PowerDeviceD0 (ON) from (ON)\n"));
  3472. break;
  3473. } /* case */
  3474. #ifdef USB_BIOS
  3475. //if (deviceExtension->HcFlags & HCFLAG_USBBIOS) {
  3476. UHCD_StopBIOS(DeviceObject);
  3477. //}
  3478. #endif //USB_BIOS
  3479. {
  3480. USHORT legsup;
  3481. UHCD_ReadWriteConfig(deviceExtension->PhysicalDeviceObject,
  3482. TRUE,
  3483. &legsup,
  3484. 0xc0, // offset of legacy bios reg
  3485. sizeof(legsup));
  3486. LOGENTRY(LOG_MISC, 'PIRd', deviceExtension, legsup, 0);
  3487. // set the PIRQD routing bit
  3488. legsup |= LEGSUP_USBPIRQD_EN;
  3489. UHCD_ReadWriteConfig( deviceExtension->PhysicalDeviceObject,
  3490. FALSE,
  3491. &legsup,
  3492. 0xc0, // offset of legacy bios reg
  3493. sizeof(legsup));
  3494. }
  3495. deviceExtension->CurrentDevicePowerState = PowerDeviceD0;
  3496. UHCD_KdPrint((1, " Host Controller entered (D0)\n"));
  3497. }
  3498. #if DBG
  3499. NTSTATUS
  3500. UHCD_GetClassGlobalDebugRegistryParameters(
  3501. )
  3502. /*++
  3503. Routine Description:
  3504. Arguments:
  3505. Return Value:
  3506. --*/
  3507. {
  3508. NTSTATUS ntStatus;
  3509. RTL_QUERY_REGISTRY_TABLE QueryTable[3];
  3510. PWCHAR usb = L"usb";
  3511. extern ULONG UHCD_Debug_Trace_Level;
  3512. extern ULONG UHCD_W98_Debug_Trace;
  3513. extern ULONG UHCD_Debug_Asserts;
  3514. PAGED_CODE();
  3515. //
  3516. // Set up QueryTable to do the following:
  3517. //
  3518. // spew level
  3519. QueryTable[0].QueryRoutine = UHCD_GetConfigValue;
  3520. QueryTable[0].Flags = 0;
  3521. QueryTable[0].Name = DEBUG_LEVEL;
  3522. QueryTable[0].EntryContext = &UHCD_Debug_Trace_Level;
  3523. QueryTable[0].DefaultType = REG_DWORD;
  3524. QueryTable[0].DefaultData = &UHCD_Debug_Trace_Level;
  3525. QueryTable[0].DefaultLength = sizeof(UHCD_Debug_Trace_Level);
  3526. // ntkern trace buffer
  3527. QueryTable[1].QueryRoutine = UHCD_GetConfigValue;
  3528. QueryTable[1].Flags = 0;
  3529. QueryTable[1].Name = DEBUG_WIN9X;
  3530. QueryTable[1].EntryContext = &UHCD_W98_Debug_Trace;
  3531. QueryTable[1].DefaultType = REG_DWORD;
  3532. QueryTable[1].DefaultData = &UHCD_W98_Debug_Trace;
  3533. QueryTable[1].DefaultLength = sizeof(UHCD_W98_Debug_Trace);
  3534. //
  3535. // Stop
  3536. //
  3537. QueryTable[2].QueryRoutine = NULL;
  3538. QueryTable[2].Flags = 0;
  3539. QueryTable[2].Name = NULL;
  3540. ntStatus = RtlQueryRegistryValues(
  3541. RTL_REGISTRY_SERVICES,
  3542. usb,
  3543. QueryTable, // QueryTable
  3544. NULL, // Context
  3545. NULL); // Environment
  3546. if (NT_SUCCESS(ntStatus)) {
  3547. UHCD_KdPrint((1, "'Debug Trace Level Set: (%d)\n", UHCD_Debug_Trace_Level));
  3548. if (UHCD_W98_Debug_Trace) {
  3549. UHCD_KdPrint((1, "'NTKERN Trace is ON\n"));
  3550. } else {
  3551. UHCD_KdPrint((1, "'NTKERN Trace is OFF\n"));
  3552. }
  3553. if (UHCD_Debug_Trace_Level > 0) {
  3554. ULONG UHCD_Debug_Asserts = 1;
  3555. }
  3556. }
  3557. if ( STATUS_OBJECT_NAME_NOT_FOUND == ntStatus ) {
  3558. ntStatus = STATUS_SUCCESS;
  3559. }
  3560. return ntStatus;
  3561. }
  3562. #endif
  3563. NTSTATUS
  3564. UHCD_GetClassGlobalRegistryParameters(
  3565. IN OUT PULONG ForceLowPowerState
  3566. )
  3567. /*++
  3568. Routine Description:
  3569. Arguments:
  3570. Return Value:
  3571. --*/
  3572. {
  3573. NTSTATUS ntStatus;
  3574. UCHAR toshibaLegacyFlags = 0;
  3575. RTL_QUERY_REGISTRY_TABLE QueryTable[2];
  3576. PWCHAR usb = L"class\\usb";
  3577. PAGED_CODE();
  3578. //
  3579. // Set up QueryTable to do the following:
  3580. //
  3581. // force power mapping
  3582. QueryTable[0].QueryRoutine = UHCD_GetConfigValue;
  3583. QueryTable[0].Flags = 0;
  3584. QueryTable[0].Name = L"ForceLowPowerState";
  3585. QueryTable[0].EntryContext = ForceLowPowerState;
  3586. QueryTable[0].DefaultType = REG_DWORD;
  3587. QueryTable[0].DefaultData = ForceLowPowerState;
  3588. QueryTable[0].DefaultLength = sizeof(*ForceLowPowerState);
  3589. //
  3590. // Stop
  3591. //
  3592. QueryTable[1].QueryRoutine = NULL;
  3593. QueryTable[1].Flags = 0;
  3594. QueryTable[1].Name = NULL;
  3595. ntStatus = RtlQueryRegistryValues(
  3596. // RTL_REGISTRY_ABSOLUTE, // RelativeTo
  3597. RTL_REGISTRY_SERVICES,
  3598. // UnicodeRegistryPath->Buffer, // Path
  3599. usb,
  3600. QueryTable, // QueryTable
  3601. NULL, // Context
  3602. NULL); // Environment
  3603. if (NT_SUCCESS(ntStatus)) {
  3604. UHCD_KdPrint(( 0, "'HC ForceLowPower = 0x%x\n",
  3605. *ForceLowPowerState));
  3606. }
  3607. if ( STATUS_OBJECT_NAME_NOT_FOUND == ntStatus ) {
  3608. ntStatus = STATUS_SUCCESS;
  3609. }
  3610. return ntStatus;
  3611. }
  3612. #if 0
  3613. // not used
  3614. NTSTATUS
  3615. UHCD_GetGlobalRegistryParameters(
  3616. IN OUT PULONG DisableController
  3617. )
  3618. /*++
  3619. Routine Description:
  3620. Arguments:
  3621. Return Value:
  3622. --*/
  3623. {
  3624. NTSTATUS ntStatus;
  3625. UCHAR toshibaLegacyFlags = 0;
  3626. RTL_QUERY_REGISTRY_TABLE QueryTable[2];
  3627. PWCHAR usb = L"usb";
  3628. PAGED_CODE();
  3629. //
  3630. // Set up QueryTable to do the following:
  3631. //
  3632. // legacy flag
  3633. QueryTable[0].QueryRoutine = UHCD_GetConfigValue;
  3634. QueryTable[0].Flags = 0;
  3635. QueryTable[0].Name = L"DisablePIIXUsb";
  3636. QueryTable[0].EntryContext = DisableController;
  3637. QueryTable[0].DefaultType = REG_BINARY;
  3638. QueryTable[0].DefaultData = DisableController;
  3639. QueryTable[0].DefaultLength = sizeof(*DisableController);
  3640. //
  3641. // Stop
  3642. //
  3643. QueryTable[1].QueryRoutine = NULL;
  3644. QueryTable[1].Flags = 0;
  3645. QueryTable[1].Name = NULL;
  3646. ntStatus = RtlQueryRegistryValues(
  3647. // RTL_REGISTRY_ABSOLUTE, // RelativeTo
  3648. RTL_REGISTRY_SERVICES,
  3649. // UnicodeRegistryPath->Buffer,// Path
  3650. usb,
  3651. QueryTable, // QurryTable
  3652. NULL, // Context
  3653. NULL); // Environment
  3654. if (NT_SUCCESS(ntStatus)) {
  3655. UHCD_KdPrint(( 0, "'HC Disable flag = 0x%x\n",
  3656. *DisableController));
  3657. }
  3658. if ( STATUS_OBJECT_NAME_NOT_FOUND == ntStatus ) {
  3659. ntStatus = STATUS_SUCCESS;
  3660. }
  3661. return ntStatus;
  3662. }
  3663. #endif