Leaked source code of windows server 2003
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.

2844 lines
76 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. // resume time perf change
  931. ntStatus = USBH_SyncPowerOnPort(DeviceExtensionHub,
  932. (USHORT) (i+1),
  933. FALSE);
  934. if (!NT_SUCCESS(ntStatus)) {
  935. break;
  936. }
  937. }
  938. // bug 516250
  939. // pass FALSE to USBH_SyncPowerOnPort
  940. // do the power-on to power good wait here
  941. UsbhWait(2*hubDescriptor->bPowerOnToPowerGood);
  942. USBH_KdPrint((2,"'Exit SyncPowerOnPorts status %x\n", ntStatus));
  943. return ntStatus;
  944. }
  945. #if 0
  946. NTSTATUS
  947. USBH_SyncPowerOffPorts(
  948. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub
  949. )
  950. /* ++
  951. *
  952. * Description:
  953. *
  954. * We will turn off the power of all ports.
  955. *
  956. * Argument:
  957. *
  958. * Return:
  959. *
  960. * NTSTATUS
  961. *
  962. * -- */
  963. {
  964. NTSTATUS ntStatus;
  965. PUSB_HUB_DESCRIPTOR hubDescriptor;
  966. ULONG numberOfPorts, i;
  967. USBH_KdPrint((2,"'Enter SyncPowerOffPorts pDE %x\n", DeviceExtensionHub));
  968. TEST_TRAP();
  969. hubDescriptor = DeviceExtensionHub->HubDescriptor;
  970. USBH_ASSERT(NULL != hubDescriptor);
  971. numberOfPorts = hubDescriptor->bNumberOfPorts;
  972. for (i=0; i<numberOfPorts; i++) {
  973. ntStatus = USBH_SyncPowerOffPort(DeviceExtensionHub,
  974. (USHORT) (i+1));
  975. if (!NT_SUCCESS(ntStatus)) {
  976. break;
  977. }
  978. }
  979. USBH_KdPrint((2,"'Exit SyncPowerOffPorts status %x\n", ntStatus));
  980. return ntStatus;
  981. }
  982. #endif
  983. NTSTATUS
  984. USBH_SyncSuspendPort(
  985. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  986. IN USHORT PortNumber)
  987. /* ++
  988. *
  989. * Description:
  990. *
  991. * We will suspend the port specified on this hub
  992. *
  993. * Argument:
  994. *
  995. * Return:
  996. *
  997. * NTSTATUS
  998. *
  999. * -- */
  1000. {
  1001. NTSTATUS ntStatus;
  1002. PPORT_DATA portData;
  1003. PAGED_CODE();
  1004. USBH_KdPrint((2,"'Enter SyncSuspendPort pDE %x\n", DeviceExtensionHub));
  1005. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  1006. ntStatus = USBH_Transact(DeviceExtensionHub,
  1007. NULL,
  1008. 0,
  1009. TRUE,
  1010. URB_FUNCTION_CLASS_OTHER,
  1011. REQUEST_TYPE_SET_PORT_FEATURE,
  1012. REQUEST_SET_FEATURE,
  1013. FEATURE_PORT_SUSPEND,
  1014. PortNumber,
  1015. NULL);
  1016. if (NT_SUCCESS(ntStatus)) {
  1017. portData->PortState.PortStatus |= PORT_STATUS_SUSPEND;
  1018. }
  1019. USBH_KdPrint((2,"'Exit SyncSuspendPort %x\n", ntStatus));
  1020. return ntStatus;
  1021. }
  1022. NTSTATUS
  1023. USBH_SyncDisablePort(
  1024. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1025. IN USHORT PortNumber)
  1026. /* ++
  1027. *
  1028. * Description:
  1029. *
  1030. * Argument:
  1031. *
  1032. * Return:
  1033. *
  1034. * NTSTATUS
  1035. *
  1036. * -- */
  1037. {
  1038. NTSTATUS ntStatus;
  1039. PPORT_DATA portData;
  1040. PAGED_CODE();
  1041. USBH_KdPrint((2,"'Enter SyncDisablePort pDE %x\n", DeviceExtensionHub));
  1042. LOGENTRY(LOG_PNP, "DISp", DeviceExtensionHub, PortNumber , 0);
  1043. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  1044. ntStatus = USBH_Transact(DeviceExtensionHub,
  1045. NULL,
  1046. 0,
  1047. TRUE,
  1048. URB_FUNCTION_CLASS_OTHER,
  1049. REQUEST_TYPE_CLEAR_PORT_FEATURE,
  1050. REQUEST_CLEAR_FEATURE,
  1051. FEATURE_PORT_ENABLE,
  1052. PortNumber,
  1053. NULL);
  1054. if (NT_SUCCESS(ntStatus)) {
  1055. portData->PortState.PortStatus &= ~PORT_STATUS_ENABLE;
  1056. }
  1057. return ntStatus;
  1058. }
  1059. NTSTATUS
  1060. USBH_SyncEnablePort(
  1061. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1062. IN USHORT PortNumber)
  1063. /* ++
  1064. *
  1065. * Description:
  1066. *
  1067. * Argument:
  1068. *
  1069. * Return:
  1070. *
  1071. * NTSTATUS
  1072. *
  1073. * -- */
  1074. {
  1075. NTSTATUS ntStatus;
  1076. PPORT_DATA portData;
  1077. PAGED_CODE();
  1078. USBH_KdPrint((2,"'Enter SyncEnablePort pDE %x port %d\n", DeviceExtensionHub,
  1079. PortNumber));
  1080. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  1081. ntStatus = USBH_Transact(DeviceExtensionHub,
  1082. NULL,
  1083. 0,
  1084. TRUE,
  1085. URB_FUNCTION_CLASS_OTHER,
  1086. REQUEST_TYPE_SET_PORT_FEATURE,
  1087. REQUEST_SET_FEATURE,
  1088. FEATURE_PORT_ENABLE,
  1089. PortNumber,
  1090. NULL);
  1091. if (NT_SUCCESS(ntStatus)) {
  1092. portData->PortState.PortStatus |= PORT_STATUS_ENABLE;
  1093. }
  1094. return ntStatus;
  1095. }
  1096. NTSTATUS
  1097. USBH_SyncPowerOffPort(
  1098. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1099. IN USHORT PortNumber)
  1100. /* ++
  1101. *
  1102. * Description:
  1103. *
  1104. * We will suspend the port specified on this hub
  1105. *
  1106. * Argument:
  1107. *
  1108. * Return:
  1109. *
  1110. * NTSTATUS
  1111. *
  1112. * -- */
  1113. {
  1114. NTSTATUS ntStatus;
  1115. PUSB_HUB_DESCRIPTOR hubDescriptor;
  1116. PPORT_DATA portData;
  1117. ULONG numberOfPorts;
  1118. USBH_KdPrint((2,"'Enter SyncPowerOffPort pDE %x Port %x\n", DeviceExtensionHub, PortNumber));
  1119. hubDescriptor = DeviceExtensionHub->HubDescriptor;
  1120. USBH_ASSERT(NULL != hubDescriptor);
  1121. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  1122. numberOfPorts = hubDescriptor->bNumberOfPorts;
  1123. USBH_ASSERT(PortNumber <= hubDescriptor->bNumberOfPorts);
  1124. //
  1125. // Turn the power off
  1126. //
  1127. ntStatus = USBH_Transact(DeviceExtensionHub,
  1128. NULL,
  1129. 0,
  1130. TRUE,
  1131. URB_FUNCTION_CLASS_OTHER,
  1132. REQUEST_TYPE_CLEAR_PORT_FEATURE,
  1133. REQUEST_CLEAR_FEATURE,
  1134. FEATURE_PORT_POWER,
  1135. PortNumber,
  1136. NULL);
  1137. if (NT_SUCCESS(ntStatus)) {
  1138. //
  1139. // mark this port as not powered
  1140. //
  1141. portData->PortState.PortStatus &= ~PORT_STATUS_POWER;
  1142. }
  1143. #if DBG
  1144. else {
  1145. // hub failed the power off request
  1146. TEST_TRAP();
  1147. }
  1148. #endif
  1149. return ntStatus;
  1150. }
  1151. NTSTATUS
  1152. USBH_SyncResumePort(
  1153. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1154. IN USHORT PortNumber)
  1155. /* ++
  1156. *
  1157. * Description:
  1158. *
  1159. * We will resume the port by clearing Port_Feature_Suspend which transits the
  1160. * state to Enable according to the spec.
  1161. *
  1162. * Argument:
  1163. *
  1164. * Return:
  1165. *
  1166. * NTSTATUS
  1167. *
  1168. * -- */
  1169. {
  1170. NTSTATUS ntStatus, status;
  1171. KEVENT suspendEvent;
  1172. LARGE_INTEGER dueTime;
  1173. PAGED_CODE();
  1174. USBH_KdPrint((2,"'Enter SyncResumePort pDE %x\n", DeviceExtensionHub));
  1175. LOGENTRY(LOG_PNP, "rspE", DeviceExtensionHub, PortNumber, 0);
  1176. USBH_KdPrint((2,"'***WAIT hub port resume mutex %x\n", DeviceExtensionHub));
  1177. USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub);
  1178. KeWaitForSingleObject(&DeviceExtensionHub->HubPortResetMutex,
  1179. Executive,
  1180. KernelMode,
  1181. FALSE,
  1182. NULL);
  1183. USBH_KdPrint((2,"'***WAIT hub port resume mutex done %x\n", DeviceExtensionHub));
  1184. USBH_ASSERT(DeviceExtensionHub->Event == NULL);
  1185. KeInitializeEvent(&suspendEvent, NotificationEvent, FALSE);
  1186. InterlockedExchangePointer(&DeviceExtensionHub->Event, &suspendEvent);
  1187. //
  1188. // first clear the suspend for this port
  1189. //
  1190. ntStatus = USBH_Transact(DeviceExtensionHub,
  1191. NULL,
  1192. 0,
  1193. TRUE,
  1194. URB_FUNCTION_CLASS_OTHER,
  1195. REQUEST_TYPE_CLEAR_PORT_FEATURE,
  1196. REQUEST_CLEAR_FEATURE,
  1197. FEATURE_PORT_SUSPEND,
  1198. PortNumber,
  1199. NULL);
  1200. //
  1201. // now wait for the hub to signal us
  1202. // that the port has resumed
  1203. //
  1204. dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
  1205. LOGENTRY(LOG_PNP, "rspW", DeviceExtensionHub,
  1206. PortNumber, ntStatus);
  1207. if (NT_SUCCESS(ntStatus)) {
  1208. status = KeWaitForSingleObject(
  1209. &suspendEvent,
  1210. Suspended,
  1211. KernelMode,
  1212. FALSE,
  1213. &dueTime);
  1214. if (status == STATUS_TIMEOUT) {
  1215. // the resume timed out
  1216. LOGENTRY(LOG_PNP, "rsTO", DeviceExtensionHub, PortNumber, 0);
  1217. //
  1218. // resume timed out return an error
  1219. //
  1220. InterlockedExchangePointer(&DeviceExtensionHub->Event, NULL);
  1221. LOGENTRY(LOG_PNP, "rspO", DeviceExtensionHub,
  1222. PortNumber, ntStatus);
  1223. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1224. }
  1225. } else {
  1226. // Clear the hub's event pointer for the next time if the call to
  1227. // USBH_Transact was unsuccessful.
  1228. InterlockedExchangePointer(&DeviceExtensionHub->Event, NULL);
  1229. }
  1230. //
  1231. // resume has completed
  1232. //
  1233. //
  1234. // chap 11 USB 1.1 change wait 10 ms after resume is complete
  1235. //
  1236. UsbhWait(10);
  1237. LOGENTRY(LOG_PNP, "rspX", DeviceExtensionHub,
  1238. PortNumber, ntStatus);
  1239. USBH_KdPrint((2,"'***RELEASE hub port resume mutex %x\n", DeviceExtensionHub));
  1240. KeReleaseSemaphore(&DeviceExtensionHub->HubPortResetMutex,
  1241. LOW_REALTIME_PRIORITY,
  1242. 1,
  1243. FALSE);
  1244. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub);
  1245. return ntStatus;
  1246. }
  1247. NTSTATUS
  1248. USBH_SyncResetPort(
  1249. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1250. IN USHORT PortNumber)
  1251. /* ++
  1252. *
  1253. * Description:
  1254. *
  1255. * We will resume the port by clearing Port_Feature_Suspend which transits the
  1256. * state to Enable according to the spec.
  1257. *
  1258. This is a synchronous function that resets the port on a usb hub. This
  1259. function assumes exclusive access to the hub, it sends the request and
  1260. waits for the hub to indicate the request is complete via a change on the
  1261. interrupt pipe.
  1262. There is one problem -- the hub may report a connect or other status
  1263. change and if it does it is possible that another interrupt transfer
  1264. (listen) will not be posted to here the reset completeion. The result
  1265. is the infamous port reset timeout. We handle this case by completing
  1266. reset with an error so that it can be retried later.
  1267. * Argument:
  1268. *
  1269. * Return:
  1270. *
  1271. * NTSTATUS
  1272. *
  1273. * -- */
  1274. {
  1275. NTSTATUS ntStatus, status;
  1276. KEVENT resetEvent;
  1277. LARGE_INTEGER dueTime;
  1278. ULONG retry = 0;
  1279. PORT_STATE portState;
  1280. //
  1281. PAGED_CODE();
  1282. USBH_KdPrint((2,"'Enter SyncResetPort pDE %x\n", DeviceExtensionHub));
  1283. LOGENTRY(LOG_PNP, "srpE", DeviceExtensionHub, PortNumber, 0);
  1284. USBH_KdPrint((2,"'***WAIT hub port reset mutex %x\n", DeviceExtensionHub));
  1285. USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub);
  1286. KeWaitForSingleObject(&DeviceExtensionHub->HubPortResetMutex,
  1287. Executive,
  1288. KernelMode,
  1289. FALSE,
  1290. NULL);
  1291. USBH_KdPrint((2,"'***WAIT hub port reset mutex done %x\n", DeviceExtensionHub));
  1292. USBH_ASSERT(DeviceExtensionHub->Event == NULL);
  1293. // first verify that we have something to reset
  1294. ntStatus = USBH_SyncGetPortStatus(DeviceExtensionHub,
  1295. PortNumber,
  1296. (PUCHAR) &portState,
  1297. sizeof(portState));
  1298. if (NT_SUCCESS(ntStatus)) {
  1299. DBG_ONLY(USBH_ShowPortState(PortNumber,
  1300. &portState));
  1301. if (!(portState.PortStatus & PORT_STATUS_CONNECT)) {
  1302. USBH_KdPrint((0,"'port %d has no device --> fail\n", PortNumber));
  1303. LOGENTRY(LOG_PNP, "srpF", DeviceExtensionHub,
  1304. PortNumber, 0);
  1305. ntStatus = STATUS_UNSUCCESSFUL;
  1306. goto USBH_SyncResetPortDone;
  1307. }
  1308. }
  1309. DeviceExtensionHub->HubFlags |= HUBFLAG_PENDING_PORT_RESET;
  1310. USBH_SyncResetPort_Retry:
  1311. KeInitializeEvent(&resetEvent, NotificationEvent, FALSE);
  1312. InterlockedExchangePointer(&DeviceExtensionHub->Event, &resetEvent);
  1313. ntStatus = USBH_Transact(DeviceExtensionHub,
  1314. NULL,
  1315. 0,
  1316. TRUE,
  1317. URB_FUNCTION_CLASS_OTHER,
  1318. REQUEST_TYPE_SET_PORT_FEATURE,
  1319. REQUEST_SET_FEATURE,
  1320. FEATURE_PORT_RESET,
  1321. PortNumber,
  1322. NULL);
  1323. //
  1324. // now wait for the hub to signal us
  1325. // that the port has resumed
  1326. //
  1327. dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
  1328. LOGENTRY(LOG_PNP, "srpW", DeviceExtensionHub,
  1329. PortNumber, ntStatus);
  1330. if (NT_SUCCESS(ntStatus)) {
  1331. status = KeWaitForSingleObject(
  1332. &resetEvent,
  1333. Suspended,
  1334. KernelMode,
  1335. FALSE,
  1336. &dueTime);
  1337. if (status == STATUS_TIMEOUT) {
  1338. // the reset timed out, get the current state of the hub port
  1339. LOGENTRY(LOG_PNP, "srTO", DeviceExtensionHub, PortNumber, retry);
  1340. status = USBH_SyncGetPortStatus(DeviceExtensionHub,
  1341. PortNumber,
  1342. (PUCHAR) &portState,
  1343. sizeof(portState));
  1344. LOGENTRY(LOG_PNP, "srT1", PortNumber,
  1345. portState.PortStatus, portState.PortChange);
  1346. if (NT_SUCCESS(status) &&
  1347. portState.PortStatus & PORT_STATUS_CONNECT) {
  1348. // device is still connected, we may have a flaky connection
  1349. // attempt a retry
  1350. USBH_KdPrint((0,"'port %d failed to reset --> retry\n", PortNumber));
  1351. if (retry < 3) {
  1352. retry++;
  1353. LOGENTRY(LOG_PNP, "rtry", DeviceExtensionHub, PortNumber, retry);
  1354. // we may have a weak connection -- we will retry in case
  1355. // it has stabilized
  1356. USBH_KdPrint((0,"'device still present -- retry reset\n"));
  1357. goto USBH_SyncResetPort_Retry;
  1358. }
  1359. #if DBG
  1360. else {
  1361. UsbhWarning(NULL,
  1362. "Port RESET timed out --> this is bad\n",
  1363. FALSE);
  1364. }
  1365. #endif
  1366. }
  1367. // nothing connected, device must have been removed
  1368. #if DBG
  1369. else {
  1370. USBH_KdPrint((0,"'-->device removed during reset\n"));
  1371. }
  1372. #endif
  1373. //
  1374. // reset timed out return an error
  1375. //
  1376. InterlockedExchangePointer(&DeviceExtensionHub->Event, NULL);
  1377. LOGENTRY(LOG_PNP, "srpO", DeviceExtensionHub,
  1378. PortNumber, ntStatus);
  1379. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1380. } else {
  1381. // check the port status, if this is a high speed reset then we
  1382. // need to return an error if the connection dropped so that
  1383. // the hub stops enumeration
  1384. if (DeviceExtensionHub->HubFlags & HUBFLAG_USB20_HUB) {
  1385. status = USBH_SyncGetPortStatus(DeviceExtensionHub,
  1386. PortNumber,
  1387. (PUCHAR) &portState,
  1388. sizeof(portState));
  1389. if (NT_SUCCESS(status) &&
  1390. !(portState.PortStatus & PORT_STATUS_CONNECT)) {
  1391. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1392. }
  1393. }
  1394. }
  1395. } else {
  1396. // Clear the hub's event pointer for the next time if the call to
  1397. // USBH_Transact was unsuccessful.
  1398. InterlockedExchangePointer(&DeviceExtensionHub->Event, NULL);
  1399. }
  1400. //
  1401. // Reset has completed.
  1402. //
  1403. //
  1404. // Wait 10 ms after reset according to section 7.1.4.3
  1405. // of the USB specification.
  1406. //
  1407. UsbhWait(USBH_PostResetDelay);
  1408. #if DBG
  1409. if (UsbhPnpTest & PNP_TEST_FAIL_PORT_RESET) {
  1410. ntStatus = STATUS_UNSUCCESSFUL;
  1411. }
  1412. #endif
  1413. DeviceExtensionHub->HubFlags &= ~HUBFLAG_PENDING_PORT_RESET;
  1414. USBH_SyncResetPortDone:
  1415. LOGENTRY(LOG_PNP, "srpX", DeviceExtensionHub,
  1416. PortNumber, ntStatus);
  1417. USBH_KdPrint((2,"'***RELEASE hub port reset mutex %x\n", DeviceExtensionHub));
  1418. KeReleaseSemaphore(&DeviceExtensionHub->HubPortResetMutex,
  1419. LOW_REALTIME_PRIORITY,
  1420. 1,
  1421. FALSE);
  1422. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub);
  1423. return ntStatus;
  1424. }
  1425. //******************************************************************************
  1426. //
  1427. // USBH_SyncCompletionRoutine()
  1428. //
  1429. // If the Irp is one we allocated ourself, DeviceObject is NULL.
  1430. //
  1431. //******************************************************************************
  1432. NTSTATUS
  1433. USBH_SyncCompletionRoutine (
  1434. IN PDEVICE_OBJECT DeviceObject,
  1435. IN PIRP Irp,
  1436. IN PVOID Context
  1437. )
  1438. {
  1439. PKEVENT kevent;
  1440. kevent = (PKEVENT)Context;
  1441. KeSetEvent(kevent,
  1442. IO_NO_INCREMENT,
  1443. FALSE);
  1444. return STATUS_MORE_PROCESSING_REQUIRED;
  1445. }
  1446. #ifndef USBHUB20
  1447. //******************************************************************************
  1448. //
  1449. // USBH_SyncResetDevice()
  1450. //
  1451. // This routine resets the device (actually it resets the port to which the
  1452. // device is attached).
  1453. //
  1454. // This routine runs at PASSIVE level.
  1455. //
  1456. //******************************************************************************
  1457. NTSTATUS
  1458. USBH_SyncResetDevice (
  1459. IN PDEVICE_OBJECT DeviceObject
  1460. )
  1461. {
  1462. PIRP irp;
  1463. KEVENT localevent;
  1464. PIO_STACK_LOCATION nextStack;
  1465. ULONG portStatus;
  1466. NTSTATUS ntStatus;
  1467. PAGED_CODE();
  1468. // Allocate the Irp
  1469. //
  1470. irp = IoAllocateIrp((CCHAR)(DeviceObject->StackSize),
  1471. FALSE);
  1472. if (irp == NULL)
  1473. {
  1474. return STATUS_INSUFFICIENT_RESOURCES;
  1475. }
  1476. // Initialize the event we'll wait on.
  1477. //
  1478. KeInitializeEvent(&localevent,
  1479. SynchronizationEvent,
  1480. FALSE);
  1481. // Set the Irp parameters
  1482. //
  1483. nextStack = IoGetNextIrpStackLocation(irp);
  1484. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1485. nextStack->Parameters.DeviceIoControl.IoControlCode =
  1486. IOCTL_INTERNAL_USB_RESET_PORT;
  1487. // Set the completion routine, which will signal the event
  1488. //
  1489. IoSetCompletionRoutineEx(DeviceObject,
  1490. irp,
  1491. USBH_SyncCompletionRoutine,
  1492. &localevent,
  1493. TRUE, // InvokeOnSuccess
  1494. TRUE, // InvokeOnError
  1495. TRUE); // InvokeOnCancel
  1496. // Pass the Irp & Urb down the stack
  1497. //
  1498. ntStatus = IoCallDriver(DeviceObject,
  1499. irp);
  1500. // If the request is pending, block until it completes
  1501. //
  1502. if (ntStatus == STATUS_PENDING)
  1503. {
  1504. KeWaitForSingleObject(&localevent,
  1505. Executive,
  1506. KernelMode,
  1507. FALSE,
  1508. NULL);
  1509. ntStatus = irp->IoStatus.Status;
  1510. }
  1511. IoFreeIrp(irp);
  1512. return ntStatus;
  1513. }
  1514. #endif
  1515. NTSTATUS
  1516. USBH_SyncGetDeviceConfigurationDescriptor(
  1517. IN PDEVICE_OBJECT DeviceObject,
  1518. IN OUT PUCHAR DataBuffer,
  1519. IN ULONG DataBufferLength,
  1520. OUT PULONG BytesReturned)
  1521. /* ++
  1522. *
  1523. * Description:
  1524. *
  1525. * DeviceObject hub/parent FDO or device/function PDO
  1526. *
  1527. * Return:
  1528. *
  1529. * NTSTATUS
  1530. *
  1531. * -- */
  1532. {
  1533. NTSTATUS ntStatus = STATUS_SUCCESS;
  1534. PURB urb;
  1535. PDEVICE_EXTENSION_HEADER deviceExtensionHeader;
  1536. PAGED_CODE();
  1537. USBH_KdPrint((2,"'enter SyncGetDeviceConfigurationDescriptor\n"));
  1538. deviceExtensionHeader = DeviceObject->DeviceExtension;
  1539. if (BytesReturned) {
  1540. *BytesReturned = 0;
  1541. }
  1542. //
  1543. // Allocate an Urb and descriptor buffer.
  1544. //
  1545. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1546. if (NULL == urb) {
  1547. USBH_KdBreak(("SyncGetDeviceConfigurationDescriptor fail alloc Urb\n"));
  1548. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1549. }
  1550. if (NT_SUCCESS(ntStatus)) {
  1551. UsbBuildGetDescriptorRequest(urb,
  1552. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1553. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  1554. 0,
  1555. 0,
  1556. DataBuffer,
  1557. NULL,
  1558. DataBufferLength,
  1559. NULL);
  1560. switch (deviceExtensionHeader->ExtensionType) {
  1561. case EXTENSION_TYPE_HUB:
  1562. case EXTENSION_TYPE_PARENT:
  1563. ntStatus = USBH_FdoSyncSubmitUrb(DeviceObject, urb);
  1564. break;
  1565. default:
  1566. ntStatus = USBH_SyncSubmitUrb(DeviceObject, urb);
  1567. }
  1568. if (BytesReturned) {
  1569. *BytesReturned =
  1570. urb->UrbControlDescriptorRequest.TransferBufferLength;
  1571. }
  1572. } else {
  1573. USBH_KdBreak(("SyncGetDeviceConfigurationDescriptor fail alloc memory\n"));
  1574. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1575. }
  1576. if (urb != NULL) {
  1577. UsbhExFreePool(urb);
  1578. }
  1579. return ntStatus;
  1580. }
  1581. NTSTATUS
  1582. USBH_GetConfigurationDescriptor(
  1583. IN PDEVICE_OBJECT DeviceObject,
  1584. IN OUT PUSB_CONFIGURATION_DESCRIPTOR *ConfigurationDescriptor
  1585. )
  1586. /* ++
  1587. *
  1588. * Description:
  1589. *
  1590. * ConfigurationDescriptor - filled in with a pointer to the config
  1591. * descriptor or NULL if an error.
  1592. *
  1593. * DeviceObject hub/parent FDO or device/function PDO
  1594. *
  1595. * Return:
  1596. *
  1597. * NTSTATUS
  1598. *
  1599. * -- */
  1600. {
  1601. ULONG bufferLength, bytesReturned;
  1602. PUCHAR buffer = NULL;
  1603. NTSTATUS ntStatus;
  1604. PAGED_CODE();
  1605. // some versions of the philips hub ignore
  1606. // the low byte of the requested data length
  1607. bufferLength = 255;
  1608. USBH_GetConfigurationDescriptor_Retry:
  1609. buffer = UsbhExAllocatePool(NonPagedPool, bufferLength);
  1610. if (buffer) {
  1611. ntStatus =
  1612. USBH_SyncGetDeviceConfigurationDescriptor(
  1613. DeviceObject,
  1614. buffer,
  1615. bufferLength,
  1616. &bytesReturned);
  1617. //
  1618. // if the device returns no data report an error
  1619. //
  1620. if (bytesReturned < sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
  1621. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1622. }
  1623. if (NT_SUCCESS(ntStatus)) {
  1624. *ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) buffer;
  1625. if ((*ConfigurationDescriptor)->wTotalLength > bufferLength) {
  1626. bufferLength = (*ConfigurationDescriptor)->wTotalLength;
  1627. UsbhExFreePool(buffer);
  1628. buffer = NULL;
  1629. *ConfigurationDescriptor = NULL;
  1630. goto USBH_GetConfigurationDescriptor_Retry;
  1631. }
  1632. }
  1633. } else {
  1634. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1635. }
  1636. if (NT_SUCCESS(ntStatus)) {
  1637. if (bytesReturned < (*ConfigurationDescriptor)->wTotalLength) {
  1638. USBH_KdBreak(("device returned truncated config descriptor!!!\n"))
  1639. // device returned trucated config descriptor
  1640. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1641. }
  1642. }
  1643. if (!NT_SUCCESS(ntStatus)) {
  1644. //
  1645. // something went wrong return no descriptor data
  1646. //
  1647. if (buffer) {
  1648. UsbhExFreePool(buffer);
  1649. buffer = NULL;
  1650. }
  1651. *ConfigurationDescriptor = NULL;
  1652. }
  1653. USBH_ASSERT((PUCHAR) (*ConfigurationDescriptor) == buffer);
  1654. return ntStatus;
  1655. }
  1656. NTSTATUS
  1657. USBH_SyncGetStringDescriptor(
  1658. IN PDEVICE_OBJECT DevicePDO,
  1659. IN UCHAR Index,
  1660. IN USHORT LangId,
  1661. IN OUT PUSB_STRING_DESCRIPTOR Buffer,
  1662. IN ULONG BufferLength,
  1663. IN PULONG BytesReturned,
  1664. IN BOOLEAN ExpectHeader
  1665. )
  1666. /* ++
  1667. *
  1668. * Description:
  1669. *
  1670. * Return:
  1671. *
  1672. * NTSTATUS
  1673. *
  1674. * -- */
  1675. {
  1676. NTSTATUS ntStatus = STATUS_SUCCESS;
  1677. PURB urb;
  1678. PAGED_CODE();
  1679. USBH_KdPrint((2,"'enter USBH_SyncGetStringDescriptor\n"));
  1680. //
  1681. // Allocate an Urb .
  1682. //
  1683. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1684. if (NULL == urb) {
  1685. USBH_KdBreak(("USBH_SyncGetStringDescriptor fail alloc Urb\n"));
  1686. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1687. }
  1688. if (urb) {
  1689. //
  1690. // got the urb no try to get descriptor data
  1691. //
  1692. UsbBuildGetDescriptorRequest(urb,
  1693. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1694. USB_STRING_DESCRIPTOR_TYPE,
  1695. Index,
  1696. LangId,
  1697. Buffer,
  1698. NULL,
  1699. BufferLength,
  1700. NULL);
  1701. ntStatus = USBH_SyncSubmitUrb(DevicePDO, urb);
  1702. if (NT_SUCCESS(ntStatus) &&
  1703. urb->UrbControlDescriptorRequest.TransferBufferLength > BufferLength) {
  1704. USBH_KdBreak(("Invalid length returned in USBH_SyncGetStringDescriptor, possible buffer overrun\n"));
  1705. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1706. }
  1707. if (NT_SUCCESS(ntStatus) && BytesReturned) {
  1708. *BytesReturned =
  1709. urb->UrbControlDescriptorRequest.TransferBufferLength;
  1710. }
  1711. if (NT_SUCCESS(ntStatus) &&
  1712. urb->UrbControlDescriptorRequest.TransferBufferLength != Buffer->bLength &&
  1713. ExpectHeader) {
  1714. USBH_KdBreak(("Bogus Descriptor from devce xfer buf %d descriptor %d\n",
  1715. urb->UrbControlDescriptorRequest.TransferBufferLength,
  1716. Buffer->bLength));
  1717. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1718. }
  1719. USBH_KdPrint((2,"'GetDeviceDescriptor, string descriptor = %x\n",
  1720. Buffer));
  1721. UsbhExFreePool(urb);
  1722. } else {
  1723. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1724. }
  1725. return ntStatus;
  1726. }
  1727. NTSTATUS
  1728. USBH_CheckDeviceLanguage(
  1729. IN PDEVICE_OBJECT DevicePDO,
  1730. IN LANGID LanguageId
  1731. )
  1732. /* ++
  1733. *
  1734. * Description:
  1735. *
  1736. * queries the device for a supported language id -- if the device supports
  1737. * the language then the index for this language is returned .
  1738. *
  1739. * DevicePDO - device object to call with urb request
  1740. *
  1741. * LanguageId -
  1742. *
  1743. * Return:
  1744. *
  1745. * success if a particular language is is supported by a device
  1746. *
  1747. * -- */
  1748. {
  1749. NTSTATUS ntStatus = STATUS_SUCCESS;
  1750. PUSB_STRING_DESCRIPTOR usbString;
  1751. PUSHORT supportedLangId;
  1752. ULONG numLangIds, i;
  1753. ULONG length;
  1754. PAGED_CODE();
  1755. USBH_KdPrint((2,"'enter USBH_CheckDeviceLanguage\n"));
  1756. usbString = UsbhExAllocatePool(NonPagedPool, MAXIMUM_USB_STRING_LENGTH);
  1757. if (usbString) {
  1758. //
  1759. // first get the array of supported languages
  1760. //
  1761. ntStatus = USBH_SyncGetStringDescriptor(DevicePDO,
  1762. 0, //index 0
  1763. 0, //langid 0
  1764. usbString,
  1765. MAXIMUM_USB_STRING_LENGTH,
  1766. &length,
  1767. #ifdef HEADER
  1768. TRUE);
  1769. #else
  1770. FALSE);
  1771. #endif /* HEADER */
  1772. //
  1773. // now check for the requested language in the array of supported
  1774. // languages
  1775. //
  1776. //
  1777. // NOTE: this seems a bit much -- we should be able to just ask for
  1778. // the string with a given language id and expect it to fail but since
  1779. // the array of supported languages is part of the USB spec we may as
  1780. // well check it.
  1781. //
  1782. if (NT_SUCCESS(ntStatus)) {
  1783. #ifdef HEADER
  1784. if (length < 2) {
  1785. numLangIds = 0;
  1786. } else {
  1787. // subtract size of header
  1788. numLangIds = (length - 2)/2;
  1789. }
  1790. supportedLangId = (PUSHORT) &usbString->bString;
  1791. #else
  1792. numLangIds = length/2;
  1793. supportedLangId = (PUSHORT) usbString;
  1794. #endif /* HEADER */
  1795. USBH_KdPrint((2,"'NumLangIds = %d\n", numLangIds));
  1796. #if DBG
  1797. for (i=0; i<numLangIds; i++) {
  1798. USBH_KdPrint((2,"'LangId = %x\n", *supportedLangId));
  1799. supportedLangId++;
  1800. }
  1801. #ifdef HEADER
  1802. supportedLangId = (PUSHORT) &usbString->bString;
  1803. #else
  1804. supportedLangId = (PUSHORT) usbString;
  1805. #endif /* HEADER */
  1806. #endif /* DBG */
  1807. ntStatus = STATUS_NOT_SUPPORTED;
  1808. for (i=0; i<numLangIds; i++) {
  1809. if (*supportedLangId == LanguageId) {
  1810. ntStatus = STATUS_SUCCESS;
  1811. break;
  1812. }
  1813. supportedLangId++;
  1814. }
  1815. }
  1816. UsbhExFreePool(usbString);
  1817. } else {
  1818. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1819. }
  1820. #if DBG
  1821. if (!NT_SUCCESS(ntStatus)) {
  1822. USBH_KdBreak(("'Language %x -- not supported by this device = %x\n",
  1823. LanguageId));
  1824. }
  1825. #endif
  1826. return ntStatus;
  1827. }
  1828. NTSTATUS
  1829. USBH_GetSerialNumberString(
  1830. IN PDEVICE_OBJECT DevicePDO,
  1831. IN OUT PWCHAR *SerialNumberBuffer,
  1832. IN OUT PUSHORT SerialNumberBufferLength,
  1833. IN LANGID LanguageId,
  1834. IN UCHAR StringIndex
  1835. )
  1836. /* ++
  1837. *
  1838. * Description:
  1839. *
  1840. * queries the device for the serial number string then allocates a buffer
  1841. * just big enough to hold it.
  1842. *
  1843. * *SerialNumberBuffer is null if an error occurs, otherwise it is filled in
  1844. * with a pointer to the NULL terminated UNICODE serial number for the device
  1845. *
  1846. * DeviceObject - deviceobject to call with urb request
  1847. *
  1848. * LanguageId - 16 bit language id
  1849. *
  1850. * StringIndex - USB string Index to fetch
  1851. *
  1852. * Return:
  1853. *
  1854. * NTSTATUS code
  1855. *
  1856. * -- */
  1857. {
  1858. NTSTATUS ntStatus = STATUS_SUCCESS;
  1859. PUSB_STRING_DESCRIPTOR usbString;
  1860. PVOID tmp;
  1861. PAGED_CODE();
  1862. USBH_KdPrint((2,"'enter GetSerialNumberString\n"));
  1863. *SerialNumberBuffer = NULL;
  1864. *SerialNumberBufferLength = 0;
  1865. usbString = UsbhExAllocatePool(NonPagedPool, MAXIMUM_USB_STRING_LENGTH);
  1866. if (usbString) {
  1867. ntStatus = USBH_CheckDeviceLanguage(DevicePDO,
  1868. LanguageId);
  1869. if (NT_SUCCESS(ntStatus)) {
  1870. //
  1871. // this device supports our language,
  1872. // go ahead and try to get the serial number
  1873. //
  1874. ntStatus = USBH_SyncGetStringDescriptor(DevicePDO,
  1875. StringIndex, //index
  1876. LanguageId, //langid
  1877. usbString,
  1878. MAXIMUM_USB_STRING_LENGTH,
  1879. NULL,
  1880. TRUE);
  1881. if (NT_SUCCESS(ntStatus)) {
  1882. //
  1883. // device returned a string!!!
  1884. //
  1885. USBH_KdPrint((2,"'device returned serial number string = %x\n",
  1886. usbString));
  1887. //
  1888. // allocate a buffer and copy the string to it
  1889. //
  1890. // NOTE: must use stock alloc function because
  1891. // PnP frees this string.
  1892. tmp = UsbhExAllocatePool(PagedPool, usbString->bLength);
  1893. if (tmp) {
  1894. USBH_KdPrint((2,"'SN = %x \n", tmp));
  1895. RtlZeroMemory(tmp, usbString->bLength);
  1896. RtlCopyMemory(tmp,
  1897. &usbString->bString,
  1898. usbString->bLength-2);
  1899. *SerialNumberBuffer = tmp;
  1900. *SerialNumberBufferLength = usbString->bLength;
  1901. } else {
  1902. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1903. }
  1904. }
  1905. }
  1906. UsbhExFreePool(usbString);
  1907. } else {
  1908. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1909. }
  1910. return ntStatus;
  1911. }
  1912. NTSTATUS
  1913. USBH_SyncGetStatus(
  1914. IN PDEVICE_OBJECT HubFDO,
  1915. IN OUT PUSHORT StatusBits,
  1916. IN USHORT function,
  1917. IN USHORT Index
  1918. )
  1919. /* ++
  1920. *
  1921. * Description:
  1922. *
  1923. * HubFDO - device object for hub (FDO)
  1924. * function - (targets a device, interface or endpoint)
  1925. * Index - wIndex value
  1926. *
  1927. *
  1928. * Return:
  1929. *
  1930. * ntStatus
  1931. *
  1932. * -- */
  1933. {
  1934. NTSTATUS ntStatus = STATUS_SUCCESS;
  1935. PURB urb;
  1936. USHORT tmpStatusBits;
  1937. PAGED_CODE();
  1938. USBH_KdPrint((2,"'enter USBH_SyncGetStatus\n"));
  1939. //
  1940. // Allocate an Urb and descriptor buffer.
  1941. //
  1942. urb = UsbhExAllocatePool(NonPagedPool,
  1943. sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST));
  1944. if (NULL == urb) {
  1945. USBH_KdBreak(("GetStatus fail alloc Urb\n"));
  1946. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1947. }
  1948. if (urb) {
  1949. UsbBuildGetStatusRequest(urb,
  1950. function,
  1951. Index,
  1952. &tmpStatusBits,
  1953. NULL,
  1954. NULL);
  1955. ntStatus = USBH_FdoSyncSubmitUrb(HubFDO, urb);
  1956. *StatusBits = tmpStatusBits;
  1957. UsbhExFreePool(urb);
  1958. }
  1959. return ntStatus;
  1960. }
  1961. NTSTATUS
  1962. USBH_GetDeviceDescriptor(
  1963. IN PDEVICE_OBJECT HubFDO,
  1964. OUT PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
  1965. )
  1966. /* ++
  1967. *
  1968. * Description:
  1969. *
  1970. * Get our configuration info.
  1971. *
  1972. * Return:
  1973. *
  1974. * NTSTATUS
  1975. *
  1976. * -- */
  1977. {
  1978. NTSTATUS ntStatus = STATUS_SUCCESS;
  1979. PURB urb;
  1980. PAGED_CODE();
  1981. USBH_KdPrint((2,"'enter GetDeviceDescriptor\n"));
  1982. //
  1983. // Allocate an Urb and descriptor buffer.
  1984. //
  1985. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1986. if (NULL == urb) {
  1987. USBH_KdBreak(("GetDeviceDescriptor fail alloc Urb\n"));
  1988. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1989. }
  1990. if (urb) {
  1991. //
  1992. // got the urb no try to get descriptor data
  1993. //
  1994. UsbBuildGetDescriptorRequest(urb,
  1995. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1996. USB_DEVICE_DESCRIPTOR_TYPE,
  1997. 0,
  1998. 0,
  1999. DeviceDescriptor,
  2000. NULL,
  2001. sizeof(USB_DEVICE_DESCRIPTOR),
  2002. NULL);
  2003. ntStatus = USBH_FdoSyncSubmitUrb(HubFDO, urb);
  2004. UsbhExFreePool(urb);
  2005. }
  2006. return ntStatus;
  2007. }
  2008. NTSTATUS
  2009. USBH_GetDeviceQualifierDescriptor(
  2010. IN PDEVICE_OBJECT DevicePDO,
  2011. OUT PUSB_DEVICE_QUALIFIER_DESCRIPTOR DeviceQualifierDescriptor
  2012. )
  2013. /* ++
  2014. *
  2015. * Description:
  2016. *
  2017. * Get the USB_DEVICE_QUALIFIER_DESCRIPTOR for the device.
  2018. *
  2019. * Return:
  2020. *
  2021. * NTSTATUS
  2022. *
  2023. * -- */
  2024. {
  2025. NTSTATUS ntStatus = STATUS_SUCCESS;
  2026. PURB urb;
  2027. PAGED_CODE();
  2028. USBH_KdPrint((2,"'enter GetDeviceQualifierDescriptor\n"));
  2029. //
  2030. // Allocate an Urb and descriptor buffer.
  2031. //
  2032. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  2033. if (NULL == urb) {
  2034. USBH_KdBreak(("GetDeviceQualifierDescriptor fail alloc Urb\n"));
  2035. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2036. }
  2037. if (urb) {
  2038. //
  2039. // got the urb no try to get descriptor data
  2040. //
  2041. UsbBuildGetDescriptorRequest(urb,
  2042. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  2043. USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE,
  2044. 0,
  2045. 0,
  2046. DeviceQualifierDescriptor,
  2047. NULL,
  2048. sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR),
  2049. NULL);
  2050. ntStatus = USBH_SyncSubmitUrb(DevicePDO, urb);
  2051. UsbhExFreePool(urb);
  2052. }
  2053. return ntStatus;
  2054. }
  2055. VOID
  2056. USBH_SyncRefreshPortAttributes(
  2057. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub
  2058. )
  2059. /* ++
  2060. * -- */
  2061. {
  2062. PUSB_EXTHUB_INFORMATION_0 extHubInfo;
  2063. PPORT_DATA p;
  2064. ULONG numberOfPorts, i;
  2065. NTSTATUS localStatus;
  2066. numberOfPorts = DeviceExtensionHub->HubDescriptor->bNumberOfPorts;
  2067. // get extended hub info if any
  2068. extHubInfo = UsbhExAllocatePool(NonPagedPool, sizeof(*extHubInfo));
  2069. if (extHubInfo != NULL) {
  2070. NTSTATUS localStatus;
  2071. // get extended hub info
  2072. localStatus = USBHUB_GetExtendedHubInfo(DeviceExtensionHub, extHubInfo);
  2073. if (!NT_SUCCESS(localStatus)) {
  2074. UsbhExFreePool(extHubInfo);
  2075. extHubInfo = NULL;
  2076. }
  2077. }
  2078. p = DeviceExtensionHub->PortData;
  2079. for (i=0; extHubInfo && i<numberOfPorts; i++, p++) {
  2080. p->PortAttributes = extHubInfo->Port[i].PortAttributes;
  2081. }
  2082. if (extHubInfo) {
  2083. UsbhExFreePool(extHubInfo);
  2084. }
  2085. }
  2086. NTSTATUS
  2087. USBH_SyncGetHubDescriptor(
  2088. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub)
  2089. /* ++
  2090. *
  2091. * Description:
  2092. *
  2093. * Get hub descriptor. If successful, we have allocated memory for the hub
  2094. * descriptor and have a the pointer to the memory recorded in the device
  2095. * extension. The memory also has the info filled. An array of port_data is
  2096. * also allocated and a pointer to the array recorded in the device
  2097. * extension.
  2098. *
  2099. * Arguments:
  2100. *
  2101. * pDeviceObject - the hub device
  2102. *
  2103. * Return:
  2104. *
  2105. * STATUS_SUCCESS - if successful STATUS_UNSUCCESSFUL - otherwise
  2106. *
  2107. * -- */
  2108. {
  2109. NTSTATUS ntStatus;
  2110. ULONG numBytes;
  2111. PUSB_HUB_DESCRIPTOR hubDescriptor = NULL;
  2112. PPORT_DATA portData;
  2113. ULONG numberOfPorts;
  2114. PDEVICE_OBJECT deviceObject;
  2115. USHORT descriptorTypeAndIndex = 0x0000;
  2116. PUSB_EXTHUB_INFORMATION_0 extHubInfo;
  2117. PAGED_CODE();
  2118. USBH_KdPrint((2,"'enter GetHubDescriptor\n"));
  2119. USBH_ASSERT(EXTENSION_TYPE_HUB == DeviceExtensionHub->ExtensionType);
  2120. // get extended hub info if any
  2121. extHubInfo = UsbhExAllocatePool(NonPagedPool, sizeof(*extHubInfo));
  2122. if (extHubInfo != NULL) {
  2123. NTSTATUS localStatus;
  2124. // get extended hub info
  2125. localStatus = USBHUB_GetExtendedHubInfo(DeviceExtensionHub, extHubInfo);
  2126. if (!NT_SUCCESS(localStatus)) {
  2127. UsbhExFreePool(extHubInfo);
  2128. extHubInfo = NULL;
  2129. }
  2130. }
  2131. deviceObject = DeviceExtensionHub->FunctionalDeviceObject;
  2132. numBytes = sizeof(USB_HUB_DESCRIPTOR);
  2133. USBH_SyncGetHubDescriptor_Retry2:
  2134. hubDescriptor = UsbhExAllocatePool(NonPagedPool, numBytes);
  2135. if (hubDescriptor) {
  2136. USBH_SyncGetHubDescriptor_Retry:
  2137. ntStatus = USBH_Transact(DeviceExtensionHub,
  2138. (PUCHAR) hubDescriptor,
  2139. numBytes,
  2140. FALSE, // input
  2141. URB_FUNCTION_CLASS_DEVICE,
  2142. REQUEST_TYPE_GET_HUB_DESCRIPTOR,
  2143. REQUEST_GET_DESCRIPTOR,
  2144. descriptorTypeAndIndex,
  2145. 0,
  2146. NULL);
  2147. if (!NT_SUCCESS(ntStatus) && descriptorTypeAndIndex == 0) {
  2148. descriptorTypeAndIndex = 0x2900;
  2149. goto USBH_SyncGetHubDescriptor_Retry;
  2150. } else {
  2151. if (hubDescriptor->bDescriptorLength > numBytes) {
  2152. numBytes = hubDescriptor->bDescriptorLength;
  2153. UsbhExFreePool(hubDescriptor);
  2154. goto USBH_SyncGetHubDescriptor_Retry2;
  2155. }
  2156. }
  2157. } else {
  2158. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2159. }
  2160. if (NT_SUCCESS(ntStatus)) {
  2161. PPORT_DATA p;
  2162. ULONG i;
  2163. //
  2164. // So, we have obtained hub descriptor. Now prepare port data
  2165. //
  2166. numberOfPorts = (ULONG) hubDescriptor->bNumberOfPorts;
  2167. USBH_KdPrint((2,"'GetHubDescriptor %x Hub has %d ports\n", hubDescriptor, numberOfPorts));
  2168. if (DeviceExtensionHub->PortData) {
  2169. // we already have port data, re-init the flags
  2170. p = portData = DeviceExtensionHub->PortData;
  2171. for (i=0; i<numberOfPorts; i++, p++) {
  2172. p->PortState.PortStatus = 0;
  2173. p->PortState.PortChange = 0;
  2174. if (extHubInfo != NULL) {
  2175. p->PortAttributes = extHubInfo->Port[i].PortAttributes;
  2176. } else {
  2177. p->PortAttributes = 0;
  2178. }
  2179. // In the case of hub start after stop, we want ConnectionStatus
  2180. // to accurately reflect the status of the port, depending on
  2181. // if there is a device connected or not. Note that QBR
  2182. // used to do this but this broke the UI in the case of
  2183. // overcurrent, bandwidth error, etc., so now we do this here.
  2184. if (p->DeviceObject) {
  2185. p->ConnectionStatus = DeviceConnected;
  2186. } else {
  2187. p->ConnectionStatus = NoDeviceConnected;
  2188. }
  2189. }
  2190. } else {
  2191. // Weird. Test found a case where if they had DriverVerifier
  2192. // fault injection turned on we bugcheck in the following call.
  2193. // We bugchecked because we were asking for zero bytes, so it
  2194. // is somehow possible to end up here with ntStatus == STATUS_SUCCESS
  2195. // and numberOfPorts == 0. So, we have to guard for that here.
  2196. if (numberOfPorts) {
  2197. portData = UsbhExAllocatePool(NonPagedPool,
  2198. sizeof(PORT_DATA) * numberOfPorts);
  2199. } else {
  2200. portData = NULL;
  2201. }
  2202. if (portData) {
  2203. RtlZeroMemory(portData, sizeof(PORT_DATA) * numberOfPorts);
  2204. p = portData;
  2205. for (i=0; i<numberOfPorts; i++, p++) {
  2206. p->ConnectionStatus = NoDeviceConnected;
  2207. if (extHubInfo != NULL) {
  2208. p->PortAttributes = extHubInfo->Port[i].PortAttributes;
  2209. }
  2210. }
  2211. }
  2212. }
  2213. if (NULL == portData) {
  2214. USBH_KdBreak(("GetHubDescriptor alloc port_data failed\n"));
  2215. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2216. }
  2217. }
  2218. if (NT_SUCCESS(ntStatus)) {
  2219. //
  2220. // Remember our HubDescriptor and PortData
  2221. //
  2222. DeviceExtensionHub->HubDescriptor = hubDescriptor;
  2223. DeviceExtensionHub->PortData = portData;
  2224. } else {
  2225. if (hubDescriptor) {
  2226. UsbhExFreePool(hubDescriptor);
  2227. }
  2228. }
  2229. if (extHubInfo != NULL) {
  2230. UsbhExFreePool(extHubInfo);
  2231. }
  2232. USBH_KdPrint((2,"'Exit GetHubDescriptor %x\n", ntStatus));
  2233. return ntStatus;
  2234. }
  2235. NTSTATUS
  2236. USBH_SyncFeatureRequest(
  2237. IN PDEVICE_OBJECT DeviceObject,
  2238. IN USHORT FeatureSelector,
  2239. IN USHORT Index,
  2240. IN USHORT Target,
  2241. IN BOOLEAN ClearFeature
  2242. )
  2243. /* ++
  2244. *
  2245. * Description:
  2246. *
  2247. * DeviceObject - may be either a device PDO or the TopOfDeviceStack for the
  2248. * hub
  2249. *
  2250. * Return:
  2251. *
  2252. * NTSTATUS
  2253. *
  2254. * -- */
  2255. {
  2256. NTSTATUS ntStatus = STATUS_SUCCESS;
  2257. PURB urb;
  2258. PAGED_CODE();
  2259. USBH_KdPrint((2,"'USBH_SyncFeatureRequest\n"));
  2260. //
  2261. // Allocate an Urb .
  2262. //
  2263. urb = UsbhExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
  2264. if (NULL == urb) {
  2265. USBH_KdBreak(("USBH_SyncFeatureRequest fail alloc Urb\n"));
  2266. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2267. }
  2268. if (urb) {
  2269. USHORT op;
  2270. //
  2271. // got the urb no try to get descriptor data
  2272. //
  2273. if (ClearFeature) {
  2274. switch(Target) {
  2275. case TO_USB_DEVICE:
  2276. op = URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE;
  2277. break;
  2278. case TO_USB_INTERFACE:
  2279. op = URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE;
  2280. break;
  2281. case TO_USB_ENDPOINT:
  2282. op = URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT;
  2283. break;
  2284. }
  2285. } else {
  2286. switch(Target) {
  2287. case TO_USB_DEVICE:
  2288. op = URB_FUNCTION_SET_FEATURE_TO_DEVICE;
  2289. break;
  2290. case TO_USB_INTERFACE:
  2291. op = URB_FUNCTION_SET_FEATURE_TO_INTERFACE;
  2292. break;
  2293. case TO_USB_ENDPOINT:
  2294. op = URB_FUNCTION_SET_FEATURE_TO_ENDPOINT;
  2295. break;
  2296. }
  2297. }
  2298. UsbBuildFeatureRequest(urb,
  2299. op,
  2300. FeatureSelector,
  2301. Index,
  2302. NULL);
  2303. ntStatus = USBH_SyncSubmitUrb(DeviceObject, urb);
  2304. UsbhExFreePool(urb);
  2305. } else {
  2306. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2307. }
  2308. return ntStatus;
  2309. }