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.

2850 lines
75 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. SYNC.C
  5. Abstract:
  6. This module contains Synchronous calls for USB Hub driver
  7. Author:
  8. John Lee
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. 04-01-96 : created
  14. 10-27-96 : jd modified to use a single transact function for calls to usb stack
  15. --*/
  16. #include <wdm.h>
  17. #ifdef WMI_SUPPORT
  18. #include <wmilib.h>
  19. #endif /* WMI_SUPPORT */
  20. #include "usbhub.h"
  21. #include <stdio.h>
  22. // delay after usb reset (in milliseconds), spec calls for 10ms
  23. ULONG USBH_PostResetDelay = 10;
  24. //
  25. // expect string descriptor header on list of supported languages
  26. //
  27. #define HEADER
  28. #define DEADMAN_TIMER
  29. #define DEADMAN_TIMEOUT 5000 //timeout in ms
  30. //use a 5 second timeout
  31. #ifdef PAGE_CODE
  32. #ifdef ALLOC_PRAGMA
  33. #pragma alloc_text(PAGE, USBH_SyncSubmitUrb)
  34. #pragma alloc_text(PAGE, UsbhWait)
  35. #pragma alloc_text(PAGE, USBH_SyncGetRootHubPdo)
  36. #pragma alloc_text(PAGE, USBH_FdoSyncSubmitUrb)
  37. #pragma alloc_text(PAGE, USBH_Transact)
  38. #pragma alloc_text(PAGE, USBH_SyncGetPortStatus)
  39. #pragma alloc_text(PAGE, USBH_SyncGetHubStatus)
  40. #pragma alloc_text(PAGE, USBH_SyncClearHubStatus)
  41. #pragma alloc_text(PAGE, USBH_SyncClearPortStatus)
  42. #pragma alloc_text(PAGE, USBH_SyncPowerOnPort)
  43. #pragma alloc_text(PAGE, USBH_SyncPowerOnPorts)
  44. #pragma alloc_text(PAGE, USBH_SyncSuspendPort)
  45. #pragma alloc_text(PAGE, USBH_SyncDisablePort)
  46. #pragma alloc_text(PAGE, USBH_SyncEnablePort)
  47. #pragma alloc_text(PAGE, USBH_SyncPowerOffPort)
  48. #pragma alloc_text(PAGE, USBH_SyncResumePort)
  49. #pragma alloc_text(PAGE, USBH_SyncResetPort)
  50. #pragma alloc_text(PAGE, USBH_SyncResetDevice)
  51. #pragma alloc_text(PAGE, USBH_SyncGetDeviceConfigurationDescriptor)
  52. #pragma alloc_text(PAGE, USBH_GetConfigurationDescriptor)
  53. #pragma alloc_text(PAGE, USBH_GetDeviceDescriptor)
  54. #pragma alloc_text(PAGE, USBH_GetDeviceQualifierDescriptor)
  55. #pragma alloc_text(PAGE, USBH_SyncGetHubDescriptor)
  56. #pragma alloc_text(PAGE, USBH_GetSerialNumberString)
  57. #pragma alloc_text(PAGE, USBH_SyncGetStatus)
  58. #pragma alloc_text(PAGE, USBH_SyncGetStringDescriptor)
  59. #pragma alloc_text(PAGE, USBH_SyncFeatureRequest)
  60. #pragma alloc_text(PAGE, USBH_CheckDeviceLanguage)
  61. #endif
  62. #endif
  63. VOID
  64. UsbhWait(
  65. IN ULONG MiliSeconds)
  66. /* ++
  67. *
  68. * Descriptor:
  69. *
  70. * This causes the thread execution delayed for ulMiliSeconds.
  71. *
  72. * Argument:
  73. *
  74. * Mili-seconds to delay.
  75. *
  76. * Return:
  77. *
  78. * VOID
  79. *
  80. * -- */
  81. {
  82. LARGE_INTEGER time;
  83. ULONG timerIncerent;
  84. USBH_KdPrint((2,"'Wait for %d ms\n", MiliSeconds));
  85. //
  86. // work only when LowPart is not overflown.
  87. //
  88. USBH_ASSERT(21474 > MiliSeconds);
  89. //
  90. // wait ulMiliSeconds( 10000 100ns unit)
  91. //
  92. timerIncerent = KeQueryTimeIncrement() - 1;
  93. time.HighPart = -1;
  94. // round up to the next highest timer increment
  95. time.LowPart = -1 * (10000 * MiliSeconds + timerIncerent);
  96. KeDelayExecutionThread(KernelMode, FALSE, &time);
  97. USBH_KdPrint((2,"'Wait done\n"));
  98. return;
  99. }
  100. #ifdef DEADMAN_TIMER
  101. VOID
  102. UsbhTimeoutDPC(
  103. IN PKDPC Dpc,
  104. IN PVOID DeferredContext,
  105. IN PVOID SystemArgument1,
  106. IN PVOID SystemArgument2
  107. )
  108. /*++
  109. Routine Description:
  110. This routine runs at DISPATCH_LEVEL IRQL.
  111. Arguments:
  112. Dpc - Pointer to the DPC object.
  113. DeferredContext -
  114. SystemArgument1 - not used.
  115. SystemArgument2 - not used.
  116. Return Value:
  117. None.
  118. --*/
  119. {
  120. PHUB_TIMEOUT_CONTEXT hubTimeoutContext = DeferredContext;
  121. BOOLEAN complete, status;
  122. KIRQL irql;
  123. KeAcquireSpinLock(&hubTimeoutContext->TimeoutSpin, &irql);
  124. complete = hubTimeoutContext->Complete;
  125. LOGENTRY(LOG_PNP, "dpTO", hubTimeoutContext->Irp, 0, complete);
  126. KeReleaseSpinLock(&hubTimeoutContext->TimeoutSpin, irql);
  127. if (!complete) {
  128. LOGENTRY(LOG_PNP, "TOca", hubTimeoutContext->Irp, 0, complete);
  129. IoCancelIrp(hubTimeoutContext->Irp);
  130. }
  131. //OK to free it
  132. KeSetEvent(&hubTimeoutContext->Event, 1, FALSE);
  133. }
  134. NTSTATUS
  135. USBH_SyncIrp_Complete(
  136. IN PDEVICE_OBJECT DeviceObject,
  137. IN PIRP Irp,
  138. IN PVOID Context
  139. )
  140. /*++
  141. Routine Description:
  142. This routine is called when the port driver completes an IRP.
  143. Arguments:
  144. DeviceObject - Pointer to the device object for the class device.
  145. Irp - Irp completed.
  146. Context - Driver defined context.
  147. Return Value:
  148. The function value is the final status from the operation.
  149. --*/
  150. {
  151. PHUB_TIMEOUT_CONTEXT hubTimeoutContext = Context;
  152. KIRQL irql;
  153. BOOLEAN cancelled;
  154. KeAcquireSpinLock(&hubTimeoutContext->TimeoutSpin, &irql);
  155. LOGENTRY(LOG_PNP, "klTO", hubTimeoutContext->Irp, 0, Context);
  156. hubTimeoutContext->Complete = TRUE;
  157. cancelled = KeCancelTimer(&hubTimeoutContext->TimeoutTimer);
  158. KeReleaseSpinLock(&hubTimeoutContext->TimeoutSpin, irql);
  159. // see if the timer was in the queue, if it was then it is safe to free
  160. // it
  161. if (cancelled) {
  162. // safe to free it
  163. KeSetEvent(&hubTimeoutContext->Event, 1, FALSE);
  164. }
  165. return STATUS_SUCCESS;
  166. }
  167. #endif /* DEADMAN_TIMER */
  168. NTSTATUS
  169. USBH_SyncSubmitUrb(
  170. IN PDEVICE_OBJECT DeviceObject,
  171. IN PURB Urb)
  172. /* ++
  173. *
  174. * Routine Description:
  175. *
  176. * Passes a URB to the USBD class driver, and wait for return.
  177. *
  178. * Arguments:
  179. *
  180. * pDeviceObject - the hub device pUrb - pointer to the URB to send to USBD
  181. *
  182. * Return Value:
  183. *
  184. * STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise
  185. *
  186. * -- */
  187. {
  188. NTSTATUS ntStatus, status;
  189. PIRP irp;
  190. KEVENT event;
  191. IO_STATUS_BLOCK ioStatus;
  192. PIO_STACK_LOCATION nextStack;
  193. BOOLEAN haveTimer = FALSE;
  194. PHUB_TIMEOUT_CONTEXT hubTimeoutContext = NULL;
  195. USBH_KdPrint((2,"'enter USBH_SyncSubmitUrb\n"));
  196. PAGED_CODE();
  197. //
  198. // null out device handle in case we are the root hub
  199. Urb->UrbHeader.UsbdDeviceHandle = NULL;
  200. //
  201. // issue a synchronous request to the RootHubBdo
  202. //
  203. KeInitializeEvent(&event, NotificationEvent, FALSE);
  204. irp = IoBuildDeviceIoControlRequest(
  205. IOCTL_INTERNAL_USB_SUBMIT_URB,
  206. DeviceObject,
  207. NULL,
  208. 0,
  209. NULL,
  210. 0,
  211. TRUE, // INTERNAL
  212. &event,
  213. &ioStatus);
  214. if (NULL == irp) {
  215. USBH_KdBreak(("CallUsbd build Irp failed\n"));
  216. return STATUS_INSUFFICIENT_RESOURCES;
  217. }
  218. //
  219. // Call the class driver to perform the operation. If the returned
  220. // status
  221. // is PENDING, wait for the request to complete.
  222. //
  223. nextStack = IoGetNextIrpStackLocation(irp);
  224. //
  225. // pass the URB to the USBD 'class driver'
  226. //
  227. nextStack->Parameters.Others.Argument1 = Urb;
  228. #ifdef DEADMAN_TIMER
  229. hubTimeoutContext = UsbhExAllocatePool(NonPagedPool,
  230. sizeof(*hubTimeoutContext));
  231. if (hubTimeoutContext) {
  232. LARGE_INTEGER dueTime;
  233. hubTimeoutContext->Irp = irp;
  234. hubTimeoutContext->Complete = FALSE;
  235. KeInitializeEvent(&hubTimeoutContext->Event, NotificationEvent, FALSE);
  236. KeInitializeSpinLock(&hubTimeoutContext->TimeoutSpin);
  237. KeInitializeTimer(&hubTimeoutContext->TimeoutTimer);
  238. KeInitializeDpc(&hubTimeoutContext->TimeoutDpc,
  239. UsbhTimeoutDPC,
  240. hubTimeoutContext);
  241. dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
  242. KeSetTimer(&hubTimeoutContext->TimeoutTimer,
  243. dueTime,
  244. &hubTimeoutContext->TimeoutDpc);
  245. haveTimer = TRUE;
  246. IoSetCompletionRoutine(irp,
  247. USBH_SyncIrp_Complete,
  248. // always pass FDO to completion routine
  249. hubTimeoutContext,
  250. TRUE,
  251. TRUE,
  252. TRUE);
  253. }
  254. #endif
  255. USBH_KdPrint((2,"'calling USBD\n"));
  256. LOGENTRY(LOG_PNP, "ssUR", irp, 0, Urb);
  257. ntStatus = IoCallDriver(DeviceObject, irp);
  258. USBH_KdPrint((2,"'return from IoCallDriver USBD %x\n", ntStatus));
  259. if (ntStatus == STATUS_PENDING) {
  260. USBH_KdPrint((2,"'Wait for single object\n"));
  261. status = KeWaitForSingleObject(&event,
  262. Suspended,
  263. KernelMode,
  264. FALSE,
  265. NULL);
  266. USBH_KdPrint((2,"'Wait for single object, returned %x\n", status));
  267. } else {
  268. ioStatus.Status = ntStatus;
  269. }
  270. #ifdef DEADMAN_TIMER
  271. // the completion routine should have canceled the timer
  272. // so we should never find it in the queue
  273. //
  274. // remove our timeoutDPC from the queue
  275. //
  276. if (haveTimer) {
  277. USBH_ASSERT(KeCancelTimer(&hubTimeoutContext->TimeoutTimer) == FALSE);
  278. KeWaitForSingleObject(&hubTimeoutContext->Event,
  279. Suspended,
  280. KernelMode,
  281. FALSE,
  282. NULL);
  283. LOGENTRY(LOG_PNP, "frTO", irp, 0, Urb);
  284. UsbhExFreePool(hubTimeoutContext);
  285. }
  286. #endif /* DEADMAN_TIMER */
  287. USBH_KdPrint((2,"'URB status = %x status = %x irp status %x\n",
  288. Urb->UrbHeader.Status, status, ioStatus.Status));
  289. //
  290. // USBD maps the error code for us
  291. //
  292. ntStatus = ioStatus.Status;
  293. USBH_KdPrint((2,"'exit USBH_SyncSubmitUrb (%x)\n", ntStatus));
  294. return ntStatus;
  295. }
  296. NTSTATUS
  297. USBH_SyncGetRootHubPdo(
  298. IN PDEVICE_OBJECT DeviceObject,
  299. IN OUT PDEVICE_OBJECT *RootHubPdo,
  300. IN OUT PDEVICE_OBJECT *TopOfHcdStackDeviceObject,
  301. IN OUT PULONG Count
  302. )
  303. /* ++
  304. *
  305. * Routine Description:
  306. *
  307. * call pdo to get the root hub PDO for our fastpath to the
  308. * usb stack.
  309. * if Count is non-null then return th ehub count, otherwise return
  310. * the root hub PDO
  311. * Arguments:
  312. *
  313. * Return Value:
  314. *
  315. * NTSTATUS
  316. *
  317. * -- */
  318. {
  319. NTSTATUS ntStatus, status;
  320. PIRP irp;
  321. KEVENT event;
  322. IO_STATUS_BLOCK ioStatus;
  323. PIO_STACK_LOCATION nextStack;
  324. PAGED_CODE();
  325. USBH_KdPrint((2,"'enter USBH_SyncSubmitUrb\n"));
  326. //
  327. // issue a synchronous request to the RootHubBdo
  328. //
  329. KeInitializeEvent(&event, NotificationEvent, FALSE);
  330. irp = IoBuildDeviceIoControlRequest( Count == NULL ?
  331. IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO :
  332. IOCTL_INTERNAL_USB_GET_HUB_COUNT,
  333. DeviceObject,
  334. NULL,
  335. 0,
  336. NULL,
  337. 0,
  338. TRUE, // INTERNAL
  339. &event,
  340. &ioStatus);
  341. if (NULL == irp) {
  342. USBH_KdBreak(("USBH_SyncGetRootHubPdo build Irp failed\n"));
  343. return STATUS_INSUFFICIENT_RESOURCES;
  344. }
  345. //
  346. // Call the class driver to perform the operation. If the returned
  347. // status
  348. // is PENDING, wait for the request to complete.
  349. //
  350. nextStack = IoGetNextIrpStackLocation(irp);
  351. //
  352. // pass the URB to the USBD 'class driver'
  353. //
  354. if (Count == NULL) {
  355. nextStack->Parameters.Others.Argument1 = RootHubPdo;
  356. nextStack->Parameters.Others.Argument2 = TopOfHcdStackDeviceObject;
  357. } else {
  358. nextStack->Parameters.Others.Argument1 = Count;
  359. }
  360. ntStatus = IoCallDriver(DeviceObject, irp);
  361. USBH_KdPrint((2,"'return from IoCallDriver USBD %x\n", ntStatus));
  362. if (ntStatus == STATUS_PENDING) {
  363. USBH_KdPrint((2,"'Wait for single object\n"));
  364. status = KeWaitForSingleObject(&event,
  365. Suspended,
  366. KernelMode,
  367. FALSE,
  368. NULL);
  369. USBH_KdPrint((2,"'Wait for single object, returned %x\n", status));
  370. } else {
  371. ioStatus.Status = ntStatus;
  372. }
  373. ntStatus = ioStatus.Status;
  374. USBH_KdPrint((2,"'exit USBH_SyncGetRootHubPdo (%x)\n", ntStatus));
  375. return ntStatus;
  376. }
  377. NTSTATUS
  378. USBH_SyncGetControllerInfo(
  379. IN PDEVICE_OBJECT DeviceObject,
  380. IN PVOID Buffer,
  381. IN ULONG BufferLength,
  382. IN ULONG Ioctl
  383. )
  384. /* ++
  385. *
  386. * Routine Description:
  387. *
  388. * call pdo to get the root hub PDO for our fastpath to the
  389. * usb stack.
  390. * if Count is non-null then return th ehub count, otherwise return
  391. * the root hub PDO
  392. * Arguments:
  393. *
  394. * Return Value:
  395. *
  396. * NTSTATUS
  397. *
  398. * -- */
  399. {
  400. NTSTATUS ntStatus, status;
  401. PIRP irp;
  402. KEVENT event;
  403. IO_STATUS_BLOCK ioStatus;
  404. PIO_STACK_LOCATION nextStack;
  405. PAGED_CODE();
  406. USBH_KdPrint((2,"'enter USBH_SyncGetControllerName\n"));
  407. //
  408. // issue a synchronous request to the RootHubBdo
  409. //
  410. KeInitializeEvent(&event, NotificationEvent, FALSE);
  411. irp = IoBuildDeviceIoControlRequest( Ioctl,
  412. DeviceObject,
  413. NULL,
  414. 0,
  415. NULL,
  416. 0,
  417. TRUE, // INTERNAL
  418. &event,
  419. &ioStatus);
  420. if (NULL == irp) {
  421. USBH_KdBreak(("USBH_SyncGetControllerName build Irp failed\n"));
  422. return STATUS_INSUFFICIENT_RESOURCES;
  423. }
  424. //
  425. // Call the class driver to perform the operation. If the returned
  426. // status
  427. // is PENDING, wait for the request to complete.
  428. //
  429. nextStack = IoGetNextIrpStackLocation(irp);
  430. nextStack->Parameters.Others.Argument1 = Buffer;
  431. nextStack->Parameters.Others.Argument2 = ULongToPtr(BufferLength);
  432. ntStatus = IoCallDriver(DeviceObject, irp);
  433. USBH_KdPrint((2,"'return from IoCallDriver USBD %x\n", ntStatus));
  434. if (ntStatus == STATUS_PENDING) {
  435. USBH_KdPrint((2,"'Wait for single object\n"));
  436. status = KeWaitForSingleObject(&event,
  437. Suspended,
  438. KernelMode,
  439. FALSE,
  440. NULL);
  441. USBH_KdPrint((2,"'Wait for single object, returned %x\n", status));
  442. } else {
  443. ioStatus.Status = ntStatus;
  444. }
  445. ntStatus = ioStatus.Status;
  446. USBH_KdPrint((2,"'exit USBH_SyncGetHubName (%x)\n", ntStatus));
  447. return ntStatus;
  448. }
  449. NTSTATUS
  450. USBH_SyncGetHubName(
  451. IN PDEVICE_OBJECT DeviceObject,
  452. IN PVOID Buffer,
  453. IN ULONG BufferLength
  454. )
  455. /* ++
  456. *
  457. * Routine Description:
  458. *
  459. * call pdo to get the root hub PDO for our fastpath to the
  460. * usb stack.
  461. * if Count is non-null then return th ehub count, otherwise return
  462. * the root hub PDO
  463. * Arguments:
  464. *
  465. * Return Value:
  466. *
  467. * NTSTATUS
  468. *
  469. * -- */
  470. {
  471. NTSTATUS ntStatus, status;
  472. PIRP irp;
  473. KEVENT event;
  474. IO_STATUS_BLOCK ioStatus;
  475. PIO_STACK_LOCATION nextStack;
  476. PAGED_CODE();
  477. USBH_KdPrint((2,"'enter USBH_SyncGetHubName\n"));
  478. //
  479. // issue a synchronous request to the RootHubBdo
  480. //
  481. KeInitializeEvent(&event, NotificationEvent, FALSE);
  482. irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_GET_HUB_NAME,
  483. DeviceObject,
  484. Buffer,
  485. BufferLength,
  486. Buffer,
  487. BufferLength,
  488. TRUE, // INTERNAL
  489. &event,
  490. &ioStatus);
  491. if (NULL == irp) {
  492. USBH_KdBreak(("USBH_SyncGetHubName build Irp failed\n"));
  493. return STATUS_INSUFFICIENT_RESOURCES;
  494. }
  495. //
  496. // Call the class driver to perform the operation. If the returned
  497. // status
  498. // is PENDING, wait for the request to complete.
  499. //
  500. nextStack = IoGetNextIrpStackLocation(irp);
  501. ntStatus = IoCallDriver(DeviceObject, irp);
  502. USBH_KdPrint((2,"'return from IoCallDriver USBD %x\n", ntStatus));
  503. if (ntStatus == STATUS_PENDING) {
  504. USBH_KdPrint((2,"'Wait for single object\n"));
  505. status = KeWaitForSingleObject(&event,
  506. Suspended,
  507. KernelMode,
  508. FALSE,
  509. NULL);
  510. USBH_KdPrint((2,"'Wait for single object, returned %x\n", status));
  511. } else {
  512. ioStatus.Status = ntStatus;
  513. }
  514. ntStatus = ioStatus.Status;
  515. USBH_KdPrint((2,"'exit USBH_SyncGetHubName (%x)\n", ntStatus));
  516. return ntStatus;
  517. }
  518. NTSTATUS
  519. USBH_FdoSyncSubmitUrb(
  520. IN PDEVICE_OBJECT HubDeviceObject,
  521. IN PURB Urb)
  522. /* ++
  523. *
  524. * Routine Description:
  525. *
  526. * Arguments:
  527. *
  528. * Return Value:
  529. *
  530. * NTSTATUS
  531. *
  532. * -- */
  533. {
  534. NTSTATUS ntStatus;
  535. PDEVICE_EXTENSION_HEADER deviceExtensionHeader;
  536. PDEVICE_EXTENSION_FDO deviceExtensionFdo;
  537. PAGED_CODE();
  538. USBH_KdPrint((2,"'enter USBH_FdoSyncSubmitUrb\n"));
  539. deviceExtensionHeader = (PDEVICE_EXTENSION_HEADER) HubDeviceObject->DeviceExtension;
  540. deviceExtensionFdo = (PDEVICE_EXTENSION_FDO) HubDeviceObject->DeviceExtension;
  541. USBH_ASSERT(EXTENSION_TYPE_HUB == deviceExtensionHeader->ExtensionType ||
  542. EXTENSION_TYPE_PARENT == deviceExtensionHeader->ExtensionType );
  543. ntStatus = USBH_SyncSubmitUrb(deviceExtensionFdo->TopOfStackDeviceObject, Urb);
  544. USBH_KdPrint((2,"'return from USBH_FdoSyncSubmitUrb %x\n", ntStatus));
  545. return ntStatus;
  546. }
  547. NTSTATUS
  548. USBH_Transact(
  549. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  550. IN PUCHAR DataBuffer,
  551. IN ULONG DataBufferLength,
  552. IN BOOLEAN DataOutput,
  553. IN USHORT Function,
  554. IN UCHAR RequestType,
  555. IN UCHAR Request,
  556. IN USHORT Feature,
  557. IN USHORT Port,
  558. OUT PULONG BytesTransferred)
  559. /* ++
  560. *
  561. * Description:
  562. *
  563. * Arguments:
  564. *
  565. * Return:
  566. *
  567. * NTSTATUS
  568. *
  569. * -- */
  570. {
  571. NTSTATUS ntStatus;
  572. PURB urb = NULL;
  573. PUCHAR transferBuffer = NULL;
  574. ULONG transferFlags;
  575. ULONG localDataBuferLength;
  576. #if DBG || defined(DEBUG_LOG)
  577. USBD_STATUS usbdStatus = USBD_STATUS_SUCCESS;
  578. #endif
  579. PAGED_CODE();
  580. USBH_KdPrint((2,"'Enter USBH_Transact\n"));
  581. USBH_ASSERT(DeviceExtensionHub);
  582. // round DataTransferLength
  583. localDataBuferLength = DataBufferLength+sizeof(ULONG);
  584. // make sure we are dword aligned
  585. localDataBuferLength &= 0xFFFFFFFC;
  586. USBH_ASSERT(localDataBuferLength >= DataBufferLength);
  587. //
  588. // Allocate a transaction buffer and Urb from the non-paged pool
  589. //
  590. transferBuffer = UsbhExAllocatePool(NonPagedPool, localDataBuferLength );
  591. urb = UsbhExAllocatePool(NonPagedPool,
  592. sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
  593. if (transferBuffer && urb) {
  594. USBH_KdPrint((2,"'Transact transfer buffer = %x urb = %x\n",
  595. transferBuffer, urb));
  596. transferFlags = 0;
  597. if (DataOutput) {
  598. // copy output data to transfer buffer
  599. if (DataBufferLength) {
  600. RtlCopyMemory(transferBuffer,
  601. DataBuffer,
  602. DataBufferLength);
  603. }
  604. transferFlags = USBD_TRANSFER_DIRECTION_OUT;
  605. } else {
  606. // zero the input buffer
  607. if (DataBufferLength) {
  608. RtlZeroMemory(DataBuffer,
  609. DataBufferLength);
  610. }
  611. transferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
  612. }
  613. UsbhBuildVendorClassUrb(urb,
  614. NULL,
  615. Function,
  616. transferFlags,
  617. RequestType,
  618. Request,
  619. Feature,
  620. Port,
  621. DataBufferLength,
  622. DataBufferLength ? transferBuffer : NULL);
  623. //
  624. // pass the URB to the USBD 'class driver'
  625. //
  626. ntStatus = USBH_FdoSyncSubmitUrb(DeviceExtensionHub->FunctionalDeviceObject,
  627. urb);
  628. if (!DataOutput && DataBufferLength) {
  629. RtlCopyMemory(DataBuffer,
  630. transferBuffer,
  631. DataBufferLength);
  632. }
  633. #if DBG || defined(DEBUG_LOG)
  634. usbdStatus = urb->UrbHeader.Status;
  635. #endif
  636. UsbhExFreePool(transferBuffer);
  637. UsbhExFreePool(urb);
  638. } else {
  639. if (transferBuffer) {
  640. UsbhExFreePool(transferBuffer);
  641. }
  642. if (urb) {
  643. UsbhExFreePool(urb);
  644. }
  645. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  646. }
  647. LOGENTRY(LOG_PNP, "Xact", DeviceExtensionHub, usbdStatus, ntStatus);
  648. USBH_KdPrint((2,"'Exit USBH_Transact %x\n", ntStatus));
  649. return ntStatus;
  650. }
  651. NTSTATUS
  652. USBH_SyncGetPortStatus(
  653. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  654. IN USHORT PortNumber,
  655. OUT PUCHAR DataBuffer,
  656. IN ULONG DataBufferLength)
  657. /* ++
  658. *
  659. * Description:
  660. *
  661. * Arguments:
  662. * PortNumber
  663. *
  664. * Return:
  665. *
  666. * NTSTATUS
  667. *
  668. * -- */
  669. {
  670. NTSTATUS ntStatus;
  671. PAGED_CODE();
  672. USBH_ASSERT(DeviceExtensionHub);
  673. ntStatus = USBH_Transact(DeviceExtensionHub,
  674. DataBuffer,
  675. DataBufferLength,
  676. FALSE,
  677. URB_FUNCTION_CLASS_OTHER,
  678. REQUEST_TYPE_GET_PORT_STATUS,
  679. REQUEST_GET_STATUS,
  680. 0,
  681. PortNumber,
  682. NULL);
  683. #if DBG
  684. {
  685. PPORT_STATE portState;
  686. portState = (PPORT_STATE) DataBuffer;
  687. LOGENTRY(LOG_PNP, "pSTS", PortNumber, portState->PortChange, portState->PortStatus);
  688. }
  689. #endif
  690. USBH_KdPrint((2,"'GetPortStatus ntStatus %x port %x state %x\n", ntStatus,
  691. PortNumber, *DataBuffer));
  692. LOGENTRY(LOG_PNP, "pSTA", DeviceExtensionHub, PortNumber, ntStatus);
  693. return ntStatus;
  694. }
  695. NTSTATUS
  696. USBH_SyncGetHubStatus(
  697. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  698. OUT PUCHAR DataBuffer,
  699. IN ULONG DataBufferLength)
  700. /* ++
  701. *
  702. * Description:
  703. *
  704. * Arguments:
  705. * PortNumber
  706. *
  707. * Return:
  708. *
  709. * NTSTATUS
  710. *
  711. * -- */
  712. {
  713. PAGED_CODE();
  714. return USBH_Transact(DeviceExtensionHub,
  715. DataBuffer,
  716. DataBufferLength,
  717. FALSE,
  718. URB_FUNCTION_CLASS_DEVICE,
  719. REQUEST_TYPE_GET_HUB_STATUS,
  720. REQUEST_GET_STATUS,
  721. 0,
  722. 0,
  723. NULL);
  724. }
  725. NTSTATUS
  726. USBH_SyncClearHubStatus(
  727. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  728. IN USHORT Feature)
  729. /* ++
  730. *
  731. * Description:
  732. *
  733. * Arguments:
  734. * PortNumber
  735. *
  736. * Return:
  737. *
  738. * NTSTATUS
  739. *
  740. * -- */
  741. {
  742. PAGED_CODE();
  743. return USBH_Transact(DeviceExtensionHub,
  744. NULL,
  745. 0,
  746. TRUE, // Host to Device
  747. URB_FUNCTION_CLASS_DEVICE,
  748. REQUEST_TYPE_SET_HUB_FEATURE,
  749. REQUEST_CLEAR_FEATURE,
  750. Feature,
  751. 0,
  752. NULL);
  753. }
  754. NTSTATUS
  755. USBH_SyncClearPortStatus(
  756. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  757. IN USHORT PortNumber,
  758. IN USHORT Feature)
  759. /* ++
  760. *
  761. * Description:
  762. *
  763. * Arguments:
  764. * PortNumber
  765. *
  766. * Return:
  767. *
  768. * NTSTATUS
  769. *
  770. * -- */
  771. {
  772. PAGED_CODE();
  773. return USBH_Transact(DeviceExtensionHub,
  774. NULL,
  775. 0,
  776. TRUE,
  777. URB_FUNCTION_CLASS_OTHER,
  778. REQUEST_TYPE_SET_PORT_FEATURE,
  779. REQUEST_CLEAR_FEATURE,
  780. Feature,
  781. PortNumber,
  782. NULL);
  783. }
  784. NTSTATUS
  785. USBH_SyncPowerOnPort(
  786. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  787. IN USHORT PortNumber,
  788. IN BOOLEAN WaitForPowerGood)
  789. /* ++
  790. *
  791. * Description:
  792. *
  793. * Argument:
  794. *
  795. * Return:
  796. *
  797. * NTSTATUS
  798. *
  799. * -- */
  800. {
  801. NTSTATUS ntStatus;
  802. PUSB_HUB_DESCRIPTOR hubDescriptor;
  803. PPORT_DATA portData;
  804. ULONG numberOfPorts;
  805. // ULONG i;
  806. PAGED_CODE();
  807. USBH_KdPrint((2,"'Enter SyncPowerOnPort pDE %x Port %x\n", DeviceExtensionHub, PortNumber));
  808. hubDescriptor = DeviceExtensionHub->HubDescriptor;
  809. USBH_ASSERT(NULL != hubDescriptor);
  810. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  811. numberOfPorts = hubDescriptor->bNumberOfPorts;
  812. USBH_ASSERT(PortNumber <= hubDescriptor->bNumberOfPorts);
  813. if (portData->PortState.PortStatus & PORT_STATUS_POWER) {
  814. //
  815. // our state flags indicate the port is already powered
  816. // just exit with success
  817. USBH_KdPrint((2,"'Exit SyncPowerOnPort port is on\n"));
  818. return STATUS_SUCCESS;
  819. }
  820. // USB 1.1 spec change requires all ports to be powered on
  821. // regardless of hub characteristics
  822. #if 0
  823. if (HUB_IS_NOT_POWER_SWITCHED(hubDescriptor->wHubCharacteristics) &&
  824. !PORT_DEVICE_NOT_REMOVABLE(hubDescriptor, PortNumber)) {
  825. //
  826. // Ports always on when hub is on.
  827. // As soon as we power the first non-removable port mark all ports
  828. // as powered
  829. //
  830. //
  831. // mark all ports as powered
  832. //
  833. for (i=0; i<numberOfPorts; i++) {
  834. DeviceExtensionHub->PortData[i].PortState.PortStatus |= PORT_STATUS_POWER;
  835. USBH_KdPrint((1,"'POWER ON PORT --> marking port(%d) powered\n", i));
  836. }
  837. USBH_KdPrint((1,"'POWER ON PORT --> hub is not power switched\n"));
  838. return STATUS_SUCCESS;
  839. }
  840. #endif
  841. //
  842. // Turn the power on
  843. //
  844. USBH_KdPrint((1,"'POWER ON PORT --> port(%d)\n", PortNumber));
  845. ntStatus = USBH_Transact(DeviceExtensionHub,
  846. NULL,
  847. 0,
  848. TRUE,
  849. URB_FUNCTION_CLASS_OTHER,
  850. REQUEST_TYPE_SET_PORT_FEATURE,
  851. REQUEST_SET_FEATURE,
  852. FEATURE_PORT_POWER,
  853. PortNumber,
  854. NULL);
  855. if (NT_SUCCESS(ntStatus)) {
  856. // wait powerOnToPowerGood good for this hub to come up
  857. if (WaitForPowerGood) {
  858. UsbhWait(2*hubDescriptor->bPowerOnToPowerGood);
  859. }
  860. #ifdef DEBUG
  861. USBH_KdPrint((1,"'Power On -> Power Good delay is: %d ms\n",
  862. 2*hubDescriptor->bPowerOnToPowerGood));
  863. #endif
  864. LOGENTRY(LOG_PNP, "PO2G", DeviceExtensionHub, PortNumber ,
  865. 2*hubDescriptor->bPowerOnToPowerGood);
  866. //
  867. // mark this port as powered
  868. //
  869. portData->PortState.PortStatus |= PORT_STATUS_POWER;
  870. // USB 1.1 spec change requires all ports to be powered on
  871. // regardless of hub characteristics
  872. #if 0
  873. if (HUB_IS_GANG_POWER_SWITCHED(hubDescriptor->wHubCharacteristics)) {
  874. // since the hub is gang switched we need to loop thru
  875. // all the ports and mark them as powered
  876. USBH_KdPrint((1,"'POWER ON PORT --> gang switched hub\n"));
  877. for (i=0; i<numberOfPorts; i++) {
  878. PPORT_STATE portState;
  879. portState = &DeviceExtensionHub->PortData[i].PortState;
  880. // if the port is not marked powered and the power mask
  881. // is not set for this port (ie it is affected by gang
  882. // mode power switching) then mark it as powered
  883. if (!(portState->PortStatus & PORT_STATUS_POWER) &&
  884. !(PORT_ALWAYS_POWER_SWITCHED(hubDescriptor, i+1))) {
  885. USBH_KdPrint((1,"'POWER ON PORT --> marking port(%d) powered\n", i));
  886. DeviceExtensionHub->PortData[i].PortState.PortStatus |= PORT_STATUS_POWER;
  887. }
  888. }
  889. }
  890. #endif
  891. //
  892. // port power is on
  893. //
  894. }
  895. #if DBG
  896. else {
  897. UsbhWarning(NULL,
  898. "SyncPowerOnPort unsuccessful\n",
  899. FALSE);
  900. }
  901. #endif
  902. return ntStatus;
  903. }
  904. NTSTATUS
  905. USBH_SyncPowerOnPorts(
  906. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub)
  907. /* ++
  908. *
  909. * Description:
  910. *
  911. * We will turn on the power of all ports unless this hub is not switched.
  912. *
  913. * Argument:
  914. *
  915. * Return:
  916. *
  917. * NTSTATUS
  918. *
  919. * -- */
  920. {
  921. NTSTATUS ntStatus;
  922. PUSB_HUB_DESCRIPTOR hubDescriptor;
  923. ULONG numberOfPorts, i;
  924. PAGED_CODE();
  925. USBH_KdPrint((2,"'Enter SyncPowerOnPorts pDE %x\n", DeviceExtensionHub));
  926. hubDescriptor = DeviceExtensionHub->HubDescriptor;
  927. USBH_ASSERT(NULL != hubDescriptor);
  928. numberOfPorts = hubDescriptor->bNumberOfPorts;
  929. for (i=0; i<numberOfPorts; i++) {
  930. #ifdef RESUME_PERF
  931. ntStatus = USBH_SyncPowerOnPort(DeviceExtensionHub,
  932. (USHORT) (i+1),
  933. FALSE);
  934. #else
  935. ntStatus = USBH_SyncPowerOnPort(DeviceExtensionHub,
  936. (USHORT) (i+1),
  937. TRUE);
  938. #endif
  939. if (!NT_SUCCESS(ntStatus)) {
  940. break;
  941. }
  942. }
  943. #ifdef RESUME_PERF
  944. // if you want to fix bug 516250 the uncomment this line and
  945. // pass FALSE to USBH_SyncPowerOnPort
  946. // do the power-on to power good wait here
  947. UsbhWait(2*hubDescriptor->bPowerOnToPowerGood);
  948. #endif
  949. USBH_KdPrint((2,"'Exit SyncPowerOnPorts status %x\n", ntStatus));
  950. return ntStatus;
  951. }
  952. #if 0
  953. NTSTATUS
  954. USBH_SyncPowerOffPorts(
  955. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub
  956. )
  957. /* ++
  958. *
  959. * Description:
  960. *
  961. * We will turn off the power of all ports.
  962. *
  963. * Argument:
  964. *
  965. * Return:
  966. *
  967. * NTSTATUS
  968. *
  969. * -- */
  970. {
  971. NTSTATUS ntStatus;
  972. PUSB_HUB_DESCRIPTOR hubDescriptor;
  973. ULONG numberOfPorts, i;
  974. USBH_KdPrint((2,"'Enter SyncPowerOffPorts pDE %x\n", DeviceExtensionHub));
  975. TEST_TRAP();
  976. hubDescriptor = DeviceExtensionHub->HubDescriptor;
  977. USBH_ASSERT(NULL != hubDescriptor);
  978. numberOfPorts = hubDescriptor->bNumberOfPorts;
  979. for (i=0; i<numberOfPorts; i++) {
  980. ntStatus = USBH_SyncPowerOffPort(DeviceExtensionHub,
  981. (USHORT) (i+1));
  982. if (!NT_SUCCESS(ntStatus)) {
  983. break;
  984. }
  985. }
  986. USBH_KdPrint((2,"'Exit SyncPowerOffPorts status %x\n", ntStatus));
  987. return ntStatus;
  988. }
  989. #endif
  990. NTSTATUS
  991. USBH_SyncSuspendPort(
  992. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  993. IN USHORT PortNumber)
  994. /* ++
  995. *
  996. * Description:
  997. *
  998. * We will suspend the port specified on this hub
  999. *
  1000. * Argument:
  1001. *
  1002. * Return:
  1003. *
  1004. * NTSTATUS
  1005. *
  1006. * -- */
  1007. {
  1008. NTSTATUS ntStatus;
  1009. PPORT_DATA portData;
  1010. PAGED_CODE();
  1011. USBH_KdPrint((2,"'Enter SyncSuspendPort pDE %x\n", DeviceExtensionHub));
  1012. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  1013. ntStatus = USBH_Transact(DeviceExtensionHub,
  1014. NULL,
  1015. 0,
  1016. TRUE,
  1017. URB_FUNCTION_CLASS_OTHER,
  1018. REQUEST_TYPE_SET_PORT_FEATURE,
  1019. REQUEST_SET_FEATURE,
  1020. FEATURE_PORT_SUSPEND,
  1021. PortNumber,
  1022. NULL);
  1023. if (NT_SUCCESS(ntStatus)) {
  1024. portData->PortState.PortStatus |= PORT_STATUS_SUSPEND;
  1025. }
  1026. USBH_KdPrint((2,"'Exit SyncSuspendPort %x\n", ntStatus));
  1027. return ntStatus;
  1028. }
  1029. NTSTATUS
  1030. USBH_SyncDisablePort(
  1031. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1032. IN USHORT PortNumber)
  1033. /* ++
  1034. *
  1035. * Description:
  1036. *
  1037. * Argument:
  1038. *
  1039. * Return:
  1040. *
  1041. * NTSTATUS
  1042. *
  1043. * -- */
  1044. {
  1045. NTSTATUS ntStatus;
  1046. PPORT_DATA portData;
  1047. PAGED_CODE();
  1048. USBH_KdPrint((2,"'Enter SyncDisablePort pDE %x\n", DeviceExtensionHub));
  1049. LOGENTRY(LOG_PNP, "DISp", DeviceExtensionHub, PortNumber , 0);
  1050. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  1051. ntStatus = USBH_Transact(DeviceExtensionHub,
  1052. NULL,
  1053. 0,
  1054. TRUE,
  1055. URB_FUNCTION_CLASS_OTHER,
  1056. REQUEST_TYPE_CLEAR_PORT_FEATURE,
  1057. REQUEST_CLEAR_FEATURE,
  1058. FEATURE_PORT_ENABLE,
  1059. PortNumber,
  1060. NULL);
  1061. if (NT_SUCCESS(ntStatus)) {
  1062. portData->PortState.PortStatus &= ~PORT_STATUS_ENABLE;
  1063. }
  1064. return ntStatus;
  1065. }
  1066. NTSTATUS
  1067. USBH_SyncEnablePort(
  1068. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1069. IN USHORT PortNumber)
  1070. /* ++
  1071. *
  1072. * Description:
  1073. *
  1074. * Argument:
  1075. *
  1076. * Return:
  1077. *
  1078. * NTSTATUS
  1079. *
  1080. * -- */
  1081. {
  1082. NTSTATUS ntStatus;
  1083. PPORT_DATA portData;
  1084. PAGED_CODE();
  1085. USBH_KdPrint((2,"'Enter SyncEnablePort pDE %x port %d\n", DeviceExtensionHub,
  1086. PortNumber));
  1087. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  1088. ntStatus = USBH_Transact(DeviceExtensionHub,
  1089. NULL,
  1090. 0,
  1091. TRUE,
  1092. URB_FUNCTION_CLASS_OTHER,
  1093. REQUEST_TYPE_SET_PORT_FEATURE,
  1094. REQUEST_SET_FEATURE,
  1095. FEATURE_PORT_ENABLE,
  1096. PortNumber,
  1097. NULL);
  1098. if (NT_SUCCESS(ntStatus)) {
  1099. portData->PortState.PortStatus |= PORT_STATUS_ENABLE;
  1100. }
  1101. return ntStatus;
  1102. }
  1103. NTSTATUS
  1104. USBH_SyncPowerOffPort(
  1105. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1106. IN USHORT PortNumber)
  1107. /* ++
  1108. *
  1109. * Description:
  1110. *
  1111. * We will suspend the port specified on this hub
  1112. *
  1113. * Argument:
  1114. *
  1115. * Return:
  1116. *
  1117. * NTSTATUS
  1118. *
  1119. * -- */
  1120. {
  1121. NTSTATUS ntStatus;
  1122. PUSB_HUB_DESCRIPTOR hubDescriptor;
  1123. PPORT_DATA portData;
  1124. ULONG numberOfPorts;
  1125. USBH_KdPrint((2,"'Enter SyncPowerOffPort pDE %x Port %x\n", DeviceExtensionHub, PortNumber));
  1126. hubDescriptor = DeviceExtensionHub->HubDescriptor;
  1127. USBH_ASSERT(NULL != hubDescriptor);
  1128. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  1129. numberOfPorts = hubDescriptor->bNumberOfPorts;
  1130. USBH_ASSERT(PortNumber <= hubDescriptor->bNumberOfPorts);
  1131. //
  1132. // Turn the power off
  1133. //
  1134. ntStatus = USBH_Transact(DeviceExtensionHub,
  1135. NULL,
  1136. 0,
  1137. TRUE,
  1138. URB_FUNCTION_CLASS_OTHER,
  1139. REQUEST_TYPE_CLEAR_PORT_FEATURE,
  1140. REQUEST_CLEAR_FEATURE,
  1141. FEATURE_PORT_POWER,
  1142. PortNumber,
  1143. NULL);
  1144. if (NT_SUCCESS(ntStatus)) {
  1145. //
  1146. // mark this port as not powered
  1147. //
  1148. portData->PortState.PortStatus &= ~PORT_STATUS_POWER;
  1149. }
  1150. #if DBG
  1151. else {
  1152. // hub failed the power off request
  1153. TEST_TRAP();
  1154. }
  1155. #endif
  1156. return ntStatus;
  1157. }
  1158. NTSTATUS
  1159. USBH_SyncResumePort(
  1160. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1161. IN USHORT PortNumber)
  1162. /* ++
  1163. *
  1164. * Description:
  1165. *
  1166. * We will resume the port by clearing Port_Feature_Suspend which transits the
  1167. * state to Enable according to the spec.
  1168. *
  1169. * Argument:
  1170. *
  1171. * Return:
  1172. *
  1173. * NTSTATUS
  1174. *
  1175. * -- */
  1176. {
  1177. NTSTATUS ntStatus, status;
  1178. KEVENT suspendEvent;
  1179. LARGE_INTEGER dueTime;
  1180. PAGED_CODE();
  1181. USBH_KdPrint((2,"'Enter SyncResumePort pDE %x\n", DeviceExtensionHub));
  1182. LOGENTRY(LOG_PNP, "rspE", DeviceExtensionHub, PortNumber, 0);
  1183. USBH_KdPrint((2,"'***WAIT hub port resume mutex %x\n", DeviceExtensionHub));
  1184. USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub);
  1185. KeWaitForSingleObject(&DeviceExtensionHub->HubPortResetMutex,
  1186. Executive,
  1187. KernelMode,
  1188. FALSE,
  1189. NULL);
  1190. USBH_KdPrint((2,"'***WAIT hub port resume mutex done %x\n", DeviceExtensionHub));
  1191. USBH_ASSERT(DeviceExtensionHub->Event == NULL);
  1192. KeInitializeEvent(&suspendEvent, NotificationEvent, FALSE);
  1193. InterlockedExchangePointer(&DeviceExtensionHub->Event, &suspendEvent);
  1194. //
  1195. // first clear the suspend for this port
  1196. //
  1197. ntStatus = USBH_Transact(DeviceExtensionHub,
  1198. NULL,
  1199. 0,
  1200. TRUE,
  1201. URB_FUNCTION_CLASS_OTHER,
  1202. REQUEST_TYPE_CLEAR_PORT_FEATURE,
  1203. REQUEST_CLEAR_FEATURE,
  1204. FEATURE_PORT_SUSPEND,
  1205. PortNumber,
  1206. NULL);
  1207. //
  1208. // now wait for the hub to signal us
  1209. // that the port has resumed
  1210. //
  1211. dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
  1212. LOGENTRY(LOG_PNP, "rspW", DeviceExtensionHub,
  1213. PortNumber, ntStatus);
  1214. if (NT_SUCCESS(ntStatus)) {
  1215. status = KeWaitForSingleObject(
  1216. &suspendEvent,
  1217. Suspended,
  1218. KernelMode,
  1219. FALSE,
  1220. &dueTime);
  1221. if (status == STATUS_TIMEOUT) {
  1222. // the resume timed out
  1223. LOGENTRY(LOG_PNP, "rsTO", DeviceExtensionHub, PortNumber, 0);
  1224. //
  1225. // resume timed out return an error
  1226. //
  1227. InterlockedExchangePointer(&DeviceExtensionHub->Event, NULL);
  1228. LOGENTRY(LOG_PNP, "rspO", DeviceExtensionHub,
  1229. PortNumber, ntStatus);
  1230. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1231. }
  1232. } else {
  1233. // Clear the hub's event pointer for the next time if the call to
  1234. // USBH_Transact was unsuccessful.
  1235. InterlockedExchangePointer(&DeviceExtensionHub->Event, NULL);
  1236. }
  1237. //
  1238. // resume has completed
  1239. //
  1240. //
  1241. // chap 11 USB 1.1 change wait 10 ms after resume is complete
  1242. //
  1243. UsbhWait(10);
  1244. LOGENTRY(LOG_PNP, "rspX", DeviceExtensionHub,
  1245. PortNumber, ntStatus);
  1246. USBH_KdPrint((2,"'***RELEASE hub port resume mutex %x\n", DeviceExtensionHub));
  1247. KeReleaseSemaphore(&DeviceExtensionHub->HubPortResetMutex,
  1248. LOW_REALTIME_PRIORITY,
  1249. 1,
  1250. FALSE);
  1251. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub);
  1252. return ntStatus;
  1253. }
  1254. NTSTATUS
  1255. USBH_SyncResetPort(
  1256. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1257. IN USHORT PortNumber)
  1258. /* ++
  1259. *
  1260. * Description:
  1261. *
  1262. * We will resume the port by clearing Port_Feature_Suspend which transits the
  1263. * state to Enable according to the spec.
  1264. *
  1265. This is a synchronous function that resets the port on a usb hub. This
  1266. function assumes exclusive access to the hub, it sends the request and
  1267. waits for the hub to indicate the request is complete via a change on the
  1268. interrupt pipe.
  1269. There is one problem -- the hub may report a connect or other status
  1270. change and if it does it is possible that another interrupt transfer
  1271. (listen) will not be posted to here the reset completeion. The result
  1272. is the infamous port reset timeout. We handle this case by completing
  1273. reset with an error so that it can be retried later.
  1274. * Argument:
  1275. *
  1276. * Return:
  1277. *
  1278. * NTSTATUS
  1279. *
  1280. * -- */
  1281. {
  1282. NTSTATUS ntStatus, status;
  1283. KEVENT resetEvent;
  1284. LARGE_INTEGER dueTime;
  1285. ULONG retry = 0;
  1286. PORT_STATE portState;
  1287. //
  1288. PAGED_CODE();
  1289. USBH_KdPrint((2,"'Enter SyncResetPort pDE %x\n", DeviceExtensionHub));
  1290. LOGENTRY(LOG_PNP, "srpE", DeviceExtensionHub, PortNumber, 0);
  1291. USBH_KdPrint((2,"'***WAIT hub port reset mutex %x\n", DeviceExtensionHub));
  1292. USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub);
  1293. KeWaitForSingleObject(&DeviceExtensionHub->HubPortResetMutex,
  1294. Executive,
  1295. KernelMode,
  1296. FALSE,
  1297. NULL);
  1298. USBH_KdPrint((2,"'***WAIT hub port reset mutex done %x\n", DeviceExtensionHub));
  1299. USBH_ASSERT(DeviceExtensionHub->Event == NULL);
  1300. // first verify that we have something to reset
  1301. ntStatus = USBH_SyncGetPortStatus(DeviceExtensionHub,
  1302. PortNumber,
  1303. (PUCHAR) &portState,
  1304. sizeof(portState));
  1305. if (NT_SUCCESS(ntStatus)) {
  1306. DBG_ONLY(USBH_ShowPortState(PortNumber,
  1307. &portState));
  1308. if (!(portState.PortStatus & PORT_STATUS_CONNECT)) {
  1309. USBH_KdPrint((0,"'port %d has no device --> fail\n", PortNumber));
  1310. LOGENTRY(LOG_PNP, "srpF", DeviceExtensionHub,
  1311. PortNumber, 0);
  1312. ntStatus = STATUS_UNSUCCESSFUL;
  1313. goto USBH_SyncResetPortDone;
  1314. }
  1315. }
  1316. DeviceExtensionHub->HubFlags |= HUBFLAG_PENDING_PORT_RESET;
  1317. USBH_SyncResetPort_Retry:
  1318. KeInitializeEvent(&resetEvent, NotificationEvent, FALSE);
  1319. InterlockedExchangePointer(&DeviceExtensionHub->Event, &resetEvent);
  1320. ntStatus = USBH_Transact(DeviceExtensionHub,
  1321. NULL,
  1322. 0,
  1323. TRUE,
  1324. URB_FUNCTION_CLASS_OTHER,
  1325. REQUEST_TYPE_SET_PORT_FEATURE,
  1326. REQUEST_SET_FEATURE,
  1327. FEATURE_PORT_RESET,
  1328. PortNumber,
  1329. NULL);
  1330. //
  1331. // now wait for the hub to signal us
  1332. // that the port has resumed
  1333. //
  1334. dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
  1335. LOGENTRY(LOG_PNP, "srpW", DeviceExtensionHub,
  1336. PortNumber, ntStatus);
  1337. if (NT_SUCCESS(ntStatus)) {
  1338. status = KeWaitForSingleObject(
  1339. &resetEvent,
  1340. Suspended,
  1341. KernelMode,
  1342. FALSE,
  1343. &dueTime);
  1344. if (status == STATUS_TIMEOUT) {
  1345. // the reset timed out, get the current state of the hub port
  1346. LOGENTRY(LOG_PNP, "srTO", DeviceExtensionHub, PortNumber, retry);
  1347. status = USBH_SyncGetPortStatus(DeviceExtensionHub,
  1348. PortNumber,
  1349. (PUCHAR) &portState,
  1350. sizeof(portState));
  1351. LOGENTRY(LOG_PNP, "srT1", PortNumber,
  1352. portState.PortStatus, portState.PortChange);
  1353. if (NT_SUCCESS(status) &&
  1354. portState.PortStatus & PORT_STATUS_CONNECT) {
  1355. // device is still connected, we may have a flaky connection
  1356. // attempt a retry
  1357. USBH_KdPrint((0,"'port %d failed to reset --> retry\n", PortNumber));
  1358. if (retry < 3) {
  1359. retry++;
  1360. LOGENTRY(LOG_PNP, "rtry", DeviceExtensionHub, PortNumber, retry);
  1361. // we may have a weak connection -- we will retry in case
  1362. // it has stabilized
  1363. USBH_KdPrint((0,"'device still present -- retry reset\n"));
  1364. goto USBH_SyncResetPort_Retry;
  1365. }
  1366. #if DBG
  1367. else {
  1368. UsbhWarning(NULL,
  1369. "Port RESET timed out --> this is bad\n",
  1370. FALSE);
  1371. }
  1372. #endif
  1373. }
  1374. // nothing connected, device must have been removed
  1375. #if DBG
  1376. else {
  1377. USBH_KdPrint((0,"'-->device removed during reset\n"));
  1378. }
  1379. #endif
  1380. //
  1381. // reset timed out return an error
  1382. //
  1383. InterlockedExchangePointer(&DeviceExtensionHub->Event, NULL);
  1384. LOGENTRY(LOG_PNP, "srpO", DeviceExtensionHub,
  1385. PortNumber, ntStatus);
  1386. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1387. } else {
  1388. // check the port status, if this is a high speed reset then we
  1389. // need to return an error if the connection dropped so that
  1390. // the hub stops enumeration
  1391. if (DeviceExtensionHub->HubFlags & HUBFLAG_USB20_HUB) {
  1392. status = USBH_SyncGetPortStatus(DeviceExtensionHub,
  1393. PortNumber,
  1394. (PUCHAR) &portState,
  1395. sizeof(portState));
  1396. if (NT_SUCCESS(status) &&
  1397. !(portState.PortStatus & PORT_STATUS_CONNECT)) {
  1398. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1399. }
  1400. }
  1401. }
  1402. } else {
  1403. // Clear the hub's event pointer for the next time if the call to
  1404. // USBH_Transact was unsuccessful.
  1405. InterlockedExchangePointer(&DeviceExtensionHub->Event, NULL);
  1406. }
  1407. //
  1408. // Reset has completed.
  1409. //
  1410. //
  1411. // Wait 10 ms after reset according to section 7.1.4.3
  1412. // of the USB specification.
  1413. //
  1414. UsbhWait(USBH_PostResetDelay);
  1415. #if DBG
  1416. if (UsbhPnpTest & PNP_TEST_FAIL_PORT_RESET) {
  1417. ntStatus = STATUS_UNSUCCESSFUL;
  1418. }
  1419. #endif
  1420. DeviceExtensionHub->HubFlags &= ~HUBFLAG_PENDING_PORT_RESET;
  1421. USBH_SyncResetPortDone:
  1422. LOGENTRY(LOG_PNP, "srpX", DeviceExtensionHub,
  1423. PortNumber, ntStatus);
  1424. USBH_KdPrint((2,"'***RELEASE hub port reset mutex %x\n", DeviceExtensionHub));
  1425. KeReleaseSemaphore(&DeviceExtensionHub->HubPortResetMutex,
  1426. LOW_REALTIME_PRIORITY,
  1427. 1,
  1428. FALSE);
  1429. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub);
  1430. return ntStatus;
  1431. }
  1432. //******************************************************************************
  1433. //
  1434. // USBH_SyncCompletionRoutine()
  1435. //
  1436. // If the Irp is one we allocated ourself, DeviceObject is NULL.
  1437. //
  1438. //******************************************************************************
  1439. NTSTATUS
  1440. USBH_SyncCompletionRoutine (
  1441. IN PDEVICE_OBJECT DeviceObject,
  1442. IN PIRP Irp,
  1443. IN PVOID Context
  1444. )
  1445. {
  1446. PKEVENT kevent;
  1447. kevent = (PKEVENT)Context;
  1448. KeSetEvent(kevent,
  1449. IO_NO_INCREMENT,
  1450. FALSE);
  1451. return STATUS_MORE_PROCESSING_REQUIRED;
  1452. }
  1453. #ifndef USBHUB20
  1454. //******************************************************************************
  1455. //
  1456. // USBH_SyncResetDevice()
  1457. //
  1458. // This routine resets the device (actually it resets the port to which the
  1459. // device is attached).
  1460. //
  1461. // This routine runs at PASSIVE level.
  1462. //
  1463. //******************************************************************************
  1464. NTSTATUS
  1465. USBH_SyncResetDevice (
  1466. IN PDEVICE_OBJECT DeviceObject
  1467. )
  1468. {
  1469. PIRP irp;
  1470. KEVENT localevent;
  1471. PIO_STACK_LOCATION nextStack;
  1472. ULONG portStatus;
  1473. NTSTATUS ntStatus;
  1474. PAGED_CODE();
  1475. // Allocate the Irp
  1476. //
  1477. irp = IoAllocateIrp((CCHAR)(DeviceObject->StackSize),
  1478. FALSE);
  1479. if (irp == NULL)
  1480. {
  1481. return STATUS_INSUFFICIENT_RESOURCES;
  1482. }
  1483. // Initialize the event we'll wait on.
  1484. //
  1485. KeInitializeEvent(&localevent,
  1486. SynchronizationEvent,
  1487. FALSE);
  1488. // Set the Irp parameters
  1489. //
  1490. nextStack = IoGetNextIrpStackLocation(irp);
  1491. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1492. nextStack->Parameters.DeviceIoControl.IoControlCode =
  1493. IOCTL_INTERNAL_USB_RESET_PORT;
  1494. // Set the completion routine, which will signal the event
  1495. //
  1496. IoSetCompletionRoutineEx(DeviceObject,
  1497. irp,
  1498. USBH_SyncCompletionRoutine,
  1499. &localevent,
  1500. TRUE, // InvokeOnSuccess
  1501. TRUE, // InvokeOnError
  1502. TRUE); // InvokeOnCancel
  1503. // Pass the Irp & Urb down the stack
  1504. //
  1505. ntStatus = IoCallDriver(DeviceObject,
  1506. irp);
  1507. // If the request is pending, block until it completes
  1508. //
  1509. if (ntStatus == STATUS_PENDING)
  1510. {
  1511. KeWaitForSingleObject(&localevent,
  1512. Executive,
  1513. KernelMode,
  1514. FALSE,
  1515. NULL);
  1516. ntStatus = irp->IoStatus.Status;
  1517. }
  1518. IoFreeIrp(irp);
  1519. return ntStatus;
  1520. }
  1521. #endif
  1522. NTSTATUS
  1523. USBH_SyncGetDeviceConfigurationDescriptor(
  1524. IN PDEVICE_OBJECT DeviceObject,
  1525. IN OUT PUCHAR DataBuffer,
  1526. IN ULONG DataBufferLength,
  1527. OUT PULONG BytesReturned)
  1528. /* ++
  1529. *
  1530. * Description:
  1531. *
  1532. * DeviceObject hub/parent FDO or device/function PDO
  1533. *
  1534. * Return:
  1535. *
  1536. * NTSTATUS
  1537. *
  1538. * -- */
  1539. {
  1540. NTSTATUS ntStatus = STATUS_SUCCESS;
  1541. PURB urb;
  1542. PDEVICE_EXTENSION_HEADER deviceExtensionHeader;
  1543. PAGED_CODE();
  1544. USBH_KdPrint((2,"'enter SyncGetDeviceConfigurationDescriptor\n"));
  1545. deviceExtensionHeader = DeviceObject->DeviceExtension;
  1546. if (BytesReturned) {
  1547. *BytesReturned = 0;
  1548. }
  1549. //
  1550. // Allocate an Urb and descriptor buffer.
  1551. //
  1552. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1553. if (NULL == urb) {
  1554. USBH_KdBreak(("SyncGetDeviceConfigurationDescriptor fail alloc Urb\n"));
  1555. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1556. }
  1557. if (NT_SUCCESS(ntStatus)) {
  1558. UsbBuildGetDescriptorRequest(urb,
  1559. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1560. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  1561. 0,
  1562. 0,
  1563. DataBuffer,
  1564. NULL,
  1565. DataBufferLength,
  1566. NULL);
  1567. switch (deviceExtensionHeader->ExtensionType) {
  1568. case EXTENSION_TYPE_HUB:
  1569. case EXTENSION_TYPE_PARENT:
  1570. ntStatus = USBH_FdoSyncSubmitUrb(DeviceObject, urb);
  1571. break;
  1572. default:
  1573. ntStatus = USBH_SyncSubmitUrb(DeviceObject, urb);
  1574. }
  1575. if (BytesReturned) {
  1576. *BytesReturned =
  1577. urb->UrbControlDescriptorRequest.TransferBufferLength;
  1578. }
  1579. } else {
  1580. USBH_KdBreak(("SyncGetDeviceConfigurationDescriptor fail alloc memory\n"));
  1581. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1582. }
  1583. if (urb != NULL) {
  1584. UsbhExFreePool(urb);
  1585. }
  1586. return ntStatus;
  1587. }
  1588. NTSTATUS
  1589. USBH_GetConfigurationDescriptor(
  1590. IN PDEVICE_OBJECT DeviceObject,
  1591. IN OUT PUSB_CONFIGURATION_DESCRIPTOR *ConfigurationDescriptor
  1592. )
  1593. /* ++
  1594. *
  1595. * Description:
  1596. *
  1597. * ConfigurationDescriptor - filled in with a pointer to the config
  1598. * descriptor or NULL if an error.
  1599. *
  1600. * DeviceObject hub/parent FDO or device/function PDO
  1601. *
  1602. * Return:
  1603. *
  1604. * NTSTATUS
  1605. *
  1606. * -- */
  1607. {
  1608. ULONG bufferLength, bytesReturned;
  1609. PUCHAR buffer = NULL;
  1610. NTSTATUS ntStatus;
  1611. PAGED_CODE();
  1612. // some versions of the philips hub ignore
  1613. // the low byte of the requested data length
  1614. bufferLength = 255;
  1615. USBH_GetConfigurationDescriptor_Retry:
  1616. buffer = UsbhExAllocatePool(NonPagedPool, bufferLength);
  1617. if (buffer) {
  1618. ntStatus =
  1619. USBH_SyncGetDeviceConfigurationDescriptor(
  1620. DeviceObject,
  1621. buffer,
  1622. bufferLength,
  1623. &bytesReturned);
  1624. //
  1625. // if the device returns no data report an error
  1626. //
  1627. if (bytesReturned < sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
  1628. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1629. }
  1630. if (NT_SUCCESS(ntStatus)) {
  1631. *ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) buffer;
  1632. if ((*ConfigurationDescriptor)->wTotalLength > bufferLength) {
  1633. bufferLength = (*ConfigurationDescriptor)->wTotalLength;
  1634. UsbhExFreePool(buffer);
  1635. buffer = NULL;
  1636. *ConfigurationDescriptor = NULL;
  1637. goto USBH_GetConfigurationDescriptor_Retry;
  1638. }
  1639. }
  1640. } else {
  1641. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1642. }
  1643. if (NT_SUCCESS(ntStatus)) {
  1644. if (bytesReturned < (*ConfigurationDescriptor)->wTotalLength) {
  1645. USBH_KdBreak(("device returned truncated config descriptor!!!\n"))
  1646. // device returned trucated config descriptor
  1647. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1648. }
  1649. }
  1650. if (!NT_SUCCESS(ntStatus)) {
  1651. //
  1652. // something went wrong return no descriptor data
  1653. //
  1654. if (buffer) {
  1655. UsbhExFreePool(buffer);
  1656. buffer = NULL;
  1657. }
  1658. *ConfigurationDescriptor = NULL;
  1659. }
  1660. USBH_ASSERT((PUCHAR) (*ConfigurationDescriptor) == buffer);
  1661. return ntStatus;
  1662. }
  1663. NTSTATUS
  1664. USBH_SyncGetStringDescriptor(
  1665. IN PDEVICE_OBJECT DevicePDO,
  1666. IN UCHAR Index,
  1667. IN USHORT LangId,
  1668. IN OUT PUSB_STRING_DESCRIPTOR Buffer,
  1669. IN ULONG BufferLength,
  1670. IN PULONG BytesReturned,
  1671. IN BOOLEAN ExpectHeader
  1672. )
  1673. /* ++
  1674. *
  1675. * Description:
  1676. *
  1677. * Return:
  1678. *
  1679. * NTSTATUS
  1680. *
  1681. * -- */
  1682. {
  1683. NTSTATUS ntStatus = STATUS_SUCCESS;
  1684. PURB urb;
  1685. PAGED_CODE();
  1686. USBH_KdPrint((2,"'enter USBH_SyncGetStringDescriptor\n"));
  1687. //
  1688. // Allocate an Urb .
  1689. //
  1690. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1691. if (NULL == urb) {
  1692. USBH_KdBreak(("USBH_SyncGetStringDescriptor fail alloc Urb\n"));
  1693. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1694. }
  1695. if (urb) {
  1696. //
  1697. // got the urb no try to get descriptor data
  1698. //
  1699. UsbBuildGetDescriptorRequest(urb,
  1700. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1701. USB_STRING_DESCRIPTOR_TYPE,
  1702. Index,
  1703. LangId,
  1704. Buffer,
  1705. NULL,
  1706. BufferLength,
  1707. NULL);
  1708. ntStatus = USBH_SyncSubmitUrb(DevicePDO, urb);
  1709. if (NT_SUCCESS(ntStatus) &&
  1710. urb->UrbControlDescriptorRequest.TransferBufferLength > BufferLength) {
  1711. USBH_KdBreak(("Invalid length returned in USBH_SyncGetStringDescriptor, possible buffer overrun\n"));
  1712. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1713. }
  1714. if (NT_SUCCESS(ntStatus) && BytesReturned) {
  1715. *BytesReturned =
  1716. urb->UrbControlDescriptorRequest.TransferBufferLength;
  1717. }
  1718. if (NT_SUCCESS(ntStatus) &&
  1719. urb->UrbControlDescriptorRequest.TransferBufferLength != Buffer->bLength &&
  1720. ExpectHeader) {
  1721. USBH_KdBreak(("Bogus Descriptor from devce xfer buf %d descriptor %d\n",
  1722. urb->UrbControlDescriptorRequest.TransferBufferLength,
  1723. Buffer->bLength));
  1724. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1725. }
  1726. USBH_KdPrint((2,"'GetDeviceDescriptor, string descriptor = %x\n",
  1727. Buffer));
  1728. UsbhExFreePool(urb);
  1729. } else {
  1730. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1731. }
  1732. return ntStatus;
  1733. }
  1734. NTSTATUS
  1735. USBH_CheckDeviceLanguage(
  1736. IN PDEVICE_OBJECT DevicePDO,
  1737. IN LANGID LanguageId
  1738. )
  1739. /* ++
  1740. *
  1741. * Description:
  1742. *
  1743. * queries the device for a supported language id -- if the device supports
  1744. * the language then the index for this language is returned .
  1745. *
  1746. * DevicePDO - device object to call with urb request
  1747. *
  1748. * LanguageId -
  1749. *
  1750. * Return:
  1751. *
  1752. * success if a particular language is is supported by a device
  1753. *
  1754. * -- */
  1755. {
  1756. NTSTATUS ntStatus = STATUS_SUCCESS;
  1757. PUSB_STRING_DESCRIPTOR usbString;
  1758. PUSHORT supportedLangId;
  1759. ULONG numLangIds, i;
  1760. ULONG length;
  1761. PAGED_CODE();
  1762. USBH_KdPrint((2,"'enter USBH_CheckDeviceLanguage\n"));
  1763. usbString = UsbhExAllocatePool(NonPagedPool, MAXIMUM_USB_STRING_LENGTH);
  1764. if (usbString) {
  1765. //
  1766. // first get the array of supported languages
  1767. //
  1768. ntStatus = USBH_SyncGetStringDescriptor(DevicePDO,
  1769. 0, //index 0
  1770. 0, //langid 0
  1771. usbString,
  1772. MAXIMUM_USB_STRING_LENGTH,
  1773. &length,
  1774. #ifdef HEADER
  1775. TRUE);
  1776. #else
  1777. FALSE);
  1778. #endif /* HEADER */
  1779. //
  1780. // now check for the requested language in the array of supported
  1781. // languages
  1782. //
  1783. //
  1784. // NOTE: this seems a bit much -- we should be able to just ask for
  1785. // the string with a given language id and expect it to fail but since
  1786. // the array of supported languages is part of the USB spec we may as
  1787. // well check it.
  1788. //
  1789. if (NT_SUCCESS(ntStatus)) {
  1790. #ifdef HEADER
  1791. if (length < 2) {
  1792. numLangIds = 0;
  1793. } else {
  1794. // subtract size of header
  1795. numLangIds = (length - 2)/2;
  1796. }
  1797. supportedLangId = (PUSHORT) &usbString->bString;
  1798. #else
  1799. numLangIds = length/2;
  1800. supportedLangId = (PUSHORT) usbString;
  1801. #endif /* HEADER */
  1802. USBH_KdPrint((2,"'NumLangIds = %d\n", numLangIds));
  1803. #if DBG
  1804. for (i=0; i<numLangIds; i++) {
  1805. USBH_KdPrint((2,"'LangId = %x\n", *supportedLangId));
  1806. supportedLangId++;
  1807. }
  1808. #ifdef HEADER
  1809. supportedLangId = (PUSHORT) &usbString->bString;
  1810. #else
  1811. supportedLangId = (PUSHORT) usbString;
  1812. #endif /* HEADER */
  1813. #endif /* DBG */
  1814. ntStatus = STATUS_NOT_SUPPORTED;
  1815. for (i=0; i<numLangIds; i++) {
  1816. if (*supportedLangId == LanguageId) {
  1817. ntStatus = STATUS_SUCCESS;
  1818. break;
  1819. }
  1820. supportedLangId++;
  1821. }
  1822. }
  1823. UsbhExFreePool(usbString);
  1824. } else {
  1825. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1826. }
  1827. #if DBG
  1828. if (!NT_SUCCESS(ntStatus)) {
  1829. USBH_KdBreak(("'Language %x -- not supported by this device = %x\n",
  1830. LanguageId));
  1831. }
  1832. #endif
  1833. return ntStatus;
  1834. }
  1835. NTSTATUS
  1836. USBH_GetSerialNumberString(
  1837. IN PDEVICE_OBJECT DevicePDO,
  1838. IN OUT PWCHAR *SerialNumberBuffer,
  1839. IN OUT PUSHORT SerialNumberBufferLength,
  1840. IN LANGID LanguageId,
  1841. IN UCHAR StringIndex
  1842. )
  1843. /* ++
  1844. *
  1845. * Description:
  1846. *
  1847. * queries the device for the serial number string then allocates a buffer
  1848. * just big enough to hold it.
  1849. *
  1850. * *SerialNumberBuffer is null if an error occurs, otherwise it is filled in
  1851. * with a pointer to the NULL terminated UNICODE serial number for the device
  1852. *
  1853. * DeviceObject - deviceobject to call with urb request
  1854. *
  1855. * LanguageId - 16 bit language id
  1856. *
  1857. * StringIndex - USB string Index to fetch
  1858. *
  1859. * Return:
  1860. *
  1861. * NTSTATUS code
  1862. *
  1863. * -- */
  1864. {
  1865. NTSTATUS ntStatus = STATUS_SUCCESS;
  1866. PUSB_STRING_DESCRIPTOR usbString;
  1867. PVOID tmp;
  1868. PAGED_CODE();
  1869. USBH_KdPrint((2,"'enter GetSerialNumberString\n"));
  1870. *SerialNumberBuffer = NULL;
  1871. *SerialNumberBufferLength = 0;
  1872. usbString = UsbhExAllocatePool(NonPagedPool, MAXIMUM_USB_STRING_LENGTH);
  1873. if (usbString) {
  1874. ntStatus = USBH_CheckDeviceLanguage(DevicePDO,
  1875. LanguageId);
  1876. if (NT_SUCCESS(ntStatus)) {
  1877. //
  1878. // this device supports our language,
  1879. // go ahead and try to get the serial number
  1880. //
  1881. ntStatus = USBH_SyncGetStringDescriptor(DevicePDO,
  1882. StringIndex, //index
  1883. LanguageId, //langid
  1884. usbString,
  1885. MAXIMUM_USB_STRING_LENGTH,
  1886. NULL,
  1887. TRUE);
  1888. if (NT_SUCCESS(ntStatus)) {
  1889. //
  1890. // device returned a string!!!
  1891. //
  1892. USBH_KdPrint((2,"'device returned serial number string = %x\n",
  1893. usbString));
  1894. //
  1895. // allocate a buffer and copy the string to it
  1896. //
  1897. // NOTE: must use stock alloc function because
  1898. // PnP frees this string.
  1899. tmp = UsbhExAllocatePool(PagedPool, usbString->bLength);
  1900. if (tmp) {
  1901. USBH_KdPrint((2,"'SN = %x \n", tmp));
  1902. RtlZeroMemory(tmp, usbString->bLength);
  1903. RtlCopyMemory(tmp,
  1904. &usbString->bString,
  1905. usbString->bLength-2);
  1906. *SerialNumberBuffer = tmp;
  1907. *SerialNumberBufferLength = usbString->bLength;
  1908. } else {
  1909. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1910. }
  1911. }
  1912. }
  1913. UsbhExFreePool(usbString);
  1914. } else {
  1915. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1916. }
  1917. return ntStatus;
  1918. }
  1919. NTSTATUS
  1920. USBH_SyncGetStatus(
  1921. IN PDEVICE_OBJECT HubFDO,
  1922. IN OUT PUSHORT StatusBits,
  1923. IN USHORT function,
  1924. IN USHORT Index
  1925. )
  1926. /* ++
  1927. *
  1928. * Description:
  1929. *
  1930. * HubFDO - device object for hub (FDO)
  1931. * function - (targets a device, interface or endpoint)
  1932. * Index - wIndex value
  1933. *
  1934. *
  1935. * Return:
  1936. *
  1937. * ntStatus
  1938. *
  1939. * -- */
  1940. {
  1941. NTSTATUS ntStatus = STATUS_SUCCESS;
  1942. PURB urb;
  1943. USHORT tmpStatusBits;
  1944. PAGED_CODE();
  1945. USBH_KdPrint((2,"'enter USBH_SyncGetStatus\n"));
  1946. //
  1947. // Allocate an Urb and descriptor buffer.
  1948. //
  1949. urb = UsbhExAllocatePool(NonPagedPool,
  1950. sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST));
  1951. if (NULL == urb) {
  1952. USBH_KdBreak(("GetStatus fail alloc Urb\n"));
  1953. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1954. }
  1955. if (urb) {
  1956. UsbBuildGetStatusRequest(urb,
  1957. function,
  1958. Index,
  1959. &tmpStatusBits,
  1960. NULL,
  1961. NULL);
  1962. ntStatus = USBH_FdoSyncSubmitUrb(HubFDO, urb);
  1963. *StatusBits = tmpStatusBits;
  1964. UsbhExFreePool(urb);
  1965. }
  1966. return ntStatus;
  1967. }
  1968. NTSTATUS
  1969. USBH_GetDeviceDescriptor(
  1970. IN PDEVICE_OBJECT HubFDO,
  1971. OUT PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
  1972. )
  1973. /* ++
  1974. *
  1975. * Description:
  1976. *
  1977. * Get our configuration info.
  1978. *
  1979. * Return:
  1980. *
  1981. * NTSTATUS
  1982. *
  1983. * -- */
  1984. {
  1985. NTSTATUS ntStatus = STATUS_SUCCESS;
  1986. PURB urb;
  1987. PAGED_CODE();
  1988. USBH_KdPrint((2,"'enter GetDeviceDescriptor\n"));
  1989. //
  1990. // Allocate an Urb and descriptor buffer.
  1991. //
  1992. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1993. if (NULL == urb) {
  1994. USBH_KdBreak(("GetDeviceDescriptor fail alloc Urb\n"));
  1995. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1996. }
  1997. if (urb) {
  1998. //
  1999. // got the urb no try to get descriptor data
  2000. //
  2001. UsbBuildGetDescriptorRequest(urb,
  2002. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  2003. USB_DEVICE_DESCRIPTOR_TYPE,
  2004. 0,
  2005. 0,
  2006. DeviceDescriptor,
  2007. NULL,
  2008. sizeof(USB_DEVICE_DESCRIPTOR),
  2009. NULL);
  2010. ntStatus = USBH_FdoSyncSubmitUrb(HubFDO, urb);
  2011. UsbhExFreePool(urb);
  2012. }
  2013. return ntStatus;
  2014. }
  2015. NTSTATUS
  2016. USBH_GetDeviceQualifierDescriptor(
  2017. IN PDEVICE_OBJECT DevicePDO,
  2018. OUT PUSB_DEVICE_QUALIFIER_DESCRIPTOR DeviceQualifierDescriptor
  2019. )
  2020. /* ++
  2021. *
  2022. * Description:
  2023. *
  2024. * Get the USB_DEVICE_QUALIFIER_DESCRIPTOR for the device.
  2025. *
  2026. * Return:
  2027. *
  2028. * NTSTATUS
  2029. *
  2030. * -- */
  2031. {
  2032. NTSTATUS ntStatus = STATUS_SUCCESS;
  2033. PURB urb;
  2034. PAGED_CODE();
  2035. USBH_KdPrint((2,"'enter GetDeviceQualifierDescriptor\n"));
  2036. //
  2037. // Allocate an Urb and descriptor buffer.
  2038. //
  2039. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  2040. if (NULL == urb) {
  2041. USBH_KdBreak(("GetDeviceQualifierDescriptor fail alloc Urb\n"));
  2042. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2043. }
  2044. if (urb) {
  2045. //
  2046. // got the urb no try to get descriptor data
  2047. //
  2048. UsbBuildGetDescriptorRequest(urb,
  2049. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  2050. USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE,
  2051. 0,
  2052. 0,
  2053. DeviceQualifierDescriptor,
  2054. NULL,
  2055. sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR),
  2056. NULL);
  2057. ntStatus = USBH_SyncSubmitUrb(DevicePDO, urb);
  2058. UsbhExFreePool(urb);
  2059. }
  2060. return ntStatus;
  2061. }
  2062. VOID
  2063. USBH_SyncRefreshPortAttributes(
  2064. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub
  2065. )
  2066. /* ++
  2067. * -- */
  2068. {
  2069. PUSB_EXTHUB_INFORMATION_0 extHubInfo;
  2070. PPORT_DATA p;
  2071. ULONG numberOfPorts, i;
  2072. NTSTATUS localStatus;
  2073. numberOfPorts = DeviceExtensionHub->HubDescriptor->bNumberOfPorts;
  2074. // get extended hub info if any
  2075. extHubInfo = UsbhExAllocatePool(NonPagedPool, sizeof(*extHubInfo));
  2076. if (extHubInfo != NULL) {
  2077. NTSTATUS localStatus;
  2078. // get extended hub info
  2079. localStatus = USBHUB_GetExtendedHubInfo(DeviceExtensionHub, extHubInfo);
  2080. if (!NT_SUCCESS(localStatus)) {
  2081. UsbhExFreePool(extHubInfo);
  2082. extHubInfo = NULL;
  2083. }
  2084. }
  2085. p = DeviceExtensionHub->PortData;
  2086. for (i=0; extHubInfo && i<numberOfPorts; i++, p++) {
  2087. p->PortAttributes = extHubInfo->Port[i].PortAttributes;
  2088. }
  2089. if (extHubInfo) {
  2090. UsbhExFreePool(extHubInfo);
  2091. }
  2092. }
  2093. NTSTATUS
  2094. USBH_SyncGetHubDescriptor(
  2095. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub)
  2096. /* ++
  2097. *
  2098. * Description:
  2099. *
  2100. * Get hub descriptor. If successful, we have allocated memory for the hub
  2101. * descriptor and have a the pointer to the memory recorded in the device
  2102. * extension. The memory also has the info filled. An array of port_data is
  2103. * also allocated and a pointer to the array recorded in the device
  2104. * extension.
  2105. *
  2106. * Arguments:
  2107. *
  2108. * pDeviceObject - the hub device
  2109. *
  2110. * Return:
  2111. *
  2112. * STATUS_SUCCESS - if successful STATUS_UNSUCCESSFUL - otherwise
  2113. *
  2114. * -- */
  2115. {
  2116. NTSTATUS ntStatus;
  2117. ULONG numBytes;
  2118. PUSB_HUB_DESCRIPTOR hubDescriptor = NULL;
  2119. PPORT_DATA portData;
  2120. ULONG numberOfPorts;
  2121. PDEVICE_OBJECT deviceObject;
  2122. USHORT descriptorTypeAndIndex = 0x0000;
  2123. PUSB_EXTHUB_INFORMATION_0 extHubInfo;
  2124. PAGED_CODE();
  2125. USBH_KdPrint((2,"'enter GetHubDescriptor\n"));
  2126. USBH_ASSERT(EXTENSION_TYPE_HUB == DeviceExtensionHub->ExtensionType);
  2127. // get extended hub info if any
  2128. extHubInfo = UsbhExAllocatePool(NonPagedPool, sizeof(*extHubInfo));
  2129. if (extHubInfo != NULL) {
  2130. NTSTATUS localStatus;
  2131. // get extended hub info
  2132. localStatus = USBHUB_GetExtendedHubInfo(DeviceExtensionHub, extHubInfo);
  2133. if (!NT_SUCCESS(localStatus)) {
  2134. UsbhExFreePool(extHubInfo);
  2135. extHubInfo = NULL;
  2136. }
  2137. }
  2138. deviceObject = DeviceExtensionHub->FunctionalDeviceObject;
  2139. numBytes = sizeof(USB_HUB_DESCRIPTOR);
  2140. USBH_SyncGetHubDescriptor_Retry2:
  2141. hubDescriptor = UsbhExAllocatePool(NonPagedPool, numBytes);
  2142. if (hubDescriptor) {
  2143. USBH_SyncGetHubDescriptor_Retry:
  2144. ntStatus = USBH_Transact(DeviceExtensionHub,
  2145. (PUCHAR) hubDescriptor,
  2146. numBytes,
  2147. FALSE, // input
  2148. URB_FUNCTION_CLASS_DEVICE,
  2149. REQUEST_TYPE_GET_HUB_DESCRIPTOR,
  2150. REQUEST_GET_DESCRIPTOR,
  2151. descriptorTypeAndIndex,
  2152. 0,
  2153. NULL);
  2154. if (!NT_SUCCESS(ntStatus) && descriptorTypeAndIndex == 0) {
  2155. descriptorTypeAndIndex = 0x2900;
  2156. goto USBH_SyncGetHubDescriptor_Retry;
  2157. } else {
  2158. if (hubDescriptor->bDescriptorLength > numBytes) {
  2159. numBytes = hubDescriptor->bDescriptorLength;
  2160. UsbhExFreePool(hubDescriptor);
  2161. goto USBH_SyncGetHubDescriptor_Retry2;
  2162. }
  2163. }
  2164. } else {
  2165. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2166. }
  2167. if (NT_SUCCESS(ntStatus)) {
  2168. PPORT_DATA p;
  2169. ULONG i;
  2170. //
  2171. // So, we have obtained hub descriptor. Now prepare port data
  2172. //
  2173. numberOfPorts = (ULONG) hubDescriptor->bNumberOfPorts;
  2174. USBH_KdPrint((2,"'GetHubDescriptor %x Hub has %d ports\n", hubDescriptor, numberOfPorts));
  2175. if (DeviceExtensionHub->PortData) {
  2176. // we already have port data, re-init the flags
  2177. p = portData = DeviceExtensionHub->PortData;
  2178. for (i=0; i<numberOfPorts; i++, p++) {
  2179. p->PortState.PortStatus = 0;
  2180. p->PortState.PortChange = 0;
  2181. if (extHubInfo != NULL) {
  2182. p->PortAttributes = extHubInfo->Port[i].PortAttributes;
  2183. } else {
  2184. p->PortAttributes = 0;
  2185. }
  2186. // In the case of hub start after stop, we want ConnectionStatus
  2187. // to accurately reflect the status of the port, depending on
  2188. // if there is a device connected or not. Note that QBR
  2189. // used to do this but this broke the UI in the case of
  2190. // overcurrent, bandwidth error, etc., so now we do this here.
  2191. if (p->DeviceObject) {
  2192. p->ConnectionStatus = DeviceConnected;
  2193. } else {
  2194. p->ConnectionStatus = NoDeviceConnected;
  2195. }
  2196. }
  2197. } else {
  2198. // Weird. Test found a case where if they had DriverVerifier
  2199. // fault injection turned on we bugcheck in the following call.
  2200. // We bugchecked because we were asking for zero bytes, so it
  2201. // is somehow possible to end up here with ntStatus == STATUS_SUCCESS
  2202. // and numberOfPorts == 0. So, we have to guard for that here.
  2203. if (numberOfPorts) {
  2204. portData = UsbhExAllocatePool(NonPagedPool,
  2205. sizeof(PORT_DATA) * numberOfPorts);
  2206. } else {
  2207. portData = NULL;
  2208. }
  2209. if (portData) {
  2210. RtlZeroMemory(portData, sizeof(PORT_DATA) * numberOfPorts);
  2211. p = portData;
  2212. for (i=0; i<numberOfPorts; i++, p++) {
  2213. p->ConnectionStatus = NoDeviceConnected;
  2214. if (extHubInfo != NULL) {
  2215. p->PortAttributes = extHubInfo->Port[i].PortAttributes;
  2216. }
  2217. }
  2218. }
  2219. }
  2220. if (NULL == portData) {
  2221. USBH_KdBreak(("GetHubDescriptor alloc port_data failed\n"));
  2222. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2223. }
  2224. }
  2225. if (NT_SUCCESS(ntStatus)) {
  2226. //
  2227. // Remember our HubDescriptor and PortData
  2228. //
  2229. DeviceExtensionHub->HubDescriptor = hubDescriptor;
  2230. DeviceExtensionHub->PortData = portData;
  2231. } else {
  2232. if (hubDescriptor) {
  2233. UsbhExFreePool(hubDescriptor);
  2234. }
  2235. }
  2236. if (extHubInfo != NULL) {
  2237. UsbhExFreePool(extHubInfo);
  2238. }
  2239. USBH_KdPrint((2,"'Exit GetHubDescriptor %x\n", ntStatus));
  2240. return ntStatus;
  2241. }
  2242. NTSTATUS
  2243. USBH_SyncFeatureRequest(
  2244. IN PDEVICE_OBJECT DeviceObject,
  2245. IN USHORT FeatureSelector,
  2246. IN USHORT Index,
  2247. IN USHORT Target,
  2248. IN BOOLEAN ClearFeature
  2249. )
  2250. /* ++
  2251. *
  2252. * Description:
  2253. *
  2254. * DeviceObject - may be either a device PDO or the TopOfDeviceStack for the
  2255. * hub
  2256. *
  2257. * Return:
  2258. *
  2259. * NTSTATUS
  2260. *
  2261. * -- */
  2262. {
  2263. NTSTATUS ntStatus = STATUS_SUCCESS;
  2264. PURB urb;
  2265. PAGED_CODE();
  2266. USBH_KdPrint((2,"'USBH_SyncFeatureRequest\n"));
  2267. //
  2268. // Allocate an Urb .
  2269. //
  2270. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
  2271. if (NULL == urb) {
  2272. USBH_KdBreak(("USBH_SyncFeatureRequest fail alloc Urb\n"));
  2273. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2274. }
  2275. if (urb) {
  2276. USHORT op;
  2277. //
  2278. // got the urb no try to get descriptor data
  2279. //
  2280. if (ClearFeature) {
  2281. switch(Target) {
  2282. case TO_USB_DEVICE:
  2283. op = URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE;
  2284. break;
  2285. case TO_USB_INTERFACE:
  2286. op = URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE;
  2287. break;
  2288. case TO_USB_ENDPOINT:
  2289. op = URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT;
  2290. break;
  2291. }
  2292. } else {
  2293. switch(Target) {
  2294. case TO_USB_DEVICE:
  2295. op = URB_FUNCTION_SET_FEATURE_TO_DEVICE;
  2296. break;
  2297. case TO_USB_INTERFACE:
  2298. op = URB_FUNCTION_SET_FEATURE_TO_INTERFACE;
  2299. break;
  2300. case TO_USB_ENDPOINT:
  2301. op = URB_FUNCTION_SET_FEATURE_TO_ENDPOINT;
  2302. break;
  2303. }
  2304. }
  2305. UsbBuildFeatureRequest(urb,
  2306. op,
  2307. FeatureSelector,
  2308. Index,
  2309. NULL);
  2310. ntStatus = USBH_SyncSubmitUrb(DeviceObject, urb);
  2311. UsbhExFreePool(urb);
  2312. } else {
  2313. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2314. }
  2315. return ntStatus;
  2316. }