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.

3432 lines
102 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. device.c
  5. Abstract:
  6. This module creates "Devices" on the bus for
  7. bus emuerators like the hub driver
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. 6-20-99 : created
  13. --*/
  14. #include "common.h"
  15. // paged functions
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, USBPORT_FreeUsbAddress)
  18. #pragma alloc_text(PAGE, USBPORT_AllocateUsbAddress)
  19. #pragma alloc_text(PAGE, USBPORT_SendCommand)
  20. #endif
  21. // non paged functions
  22. //USBPORT_ValidateDeviceHandle
  23. //USBPORT_RemoveDeviceHandle
  24. //USBPORT_AddDeviceHandle
  25. //USBPORT_ValidatePipeHandle
  26. //USBPORT_OpenEndpoint
  27. //USBPORT_CloseEndpoint
  28. //USBPORT_CreateDevice
  29. //USBPORT_RemoveDevice
  30. //USBPORT_InitializeDevice
  31. //USBPORT_RemovePipeHandle
  32. //USBPORT_AddPipeHandle
  33. //USBPORT_LazyCloseEndpoint
  34. //USBPORT_FlushClosedEndpointList
  35. /*
  36. Handle validation routines, we keep a list
  37. of valid handles and match the ones passed
  38. in with our list.
  39. Access to the device handle list for
  40. //USBPORT_CreateDevice
  41. //USBPORT_RemoveDevice
  42. //USBPORT_InitializeDevice
  43. is serialized with a global semaphore so we don't
  44. need a spinlock.
  45. BUGBUG
  46. We may be able to use try/except block
  47. here but I'm not sure it works at all IRQL
  48. and on all platforms
  49. */
  50. BOOLEAN
  51. USBPORT_ValidateDeviceHandle(
  52. PDEVICE_OBJECT FdoDeviceObject,
  53. PUSBD_DEVICE_HANDLE DeviceHandle,
  54. BOOLEAN ReferenceUrb
  55. )
  56. /*++
  57. Routine Description:
  58. returns true if a device handle is valid
  59. Arguments:
  60. Return Value:
  61. TRUE is handle is valid
  62. --*/
  63. {
  64. BOOLEAN found = FALSE;
  65. PLIST_ENTRY listEntry;
  66. PDEVICE_EXTENSION devExt;
  67. KIRQL irql;
  68. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  69. ASSERT_FDOEXT(devExt);
  70. KeAcquireSpinLock(&devExt->Fdo.DevHandleListSpin.sl, &irql);
  71. if (DeviceHandle == NULL) {
  72. // NULL is obviously not valid
  73. goto USBPORT_ValidateDeviceHandle_Done;
  74. }
  75. listEntry = &devExt->Fdo.DeviceHandleList;
  76. if (!IsListEmpty(listEntry)) {
  77. listEntry = devExt->Fdo.DeviceHandleList.Flink;
  78. }
  79. while (listEntry != &devExt->Fdo.DeviceHandleList) {
  80. PUSBD_DEVICE_HANDLE nextHandle;
  81. nextHandle = (PUSBD_DEVICE_HANDLE) CONTAINING_RECORD(
  82. listEntry,
  83. struct _USBD_DEVICE_HANDLE,
  84. ListEntry);
  85. listEntry = nextHandle->ListEntry.Flink;
  86. if (nextHandle == DeviceHandle) {
  87. found = TRUE;
  88. if (ReferenceUrb) {
  89. InterlockedIncrement(&DeviceHandle->PendingUrbs);
  90. }
  91. break;
  92. }
  93. }
  94. USBPORT_ValidateDeviceHandle_Done:
  95. #if DBG
  96. if (!found) {
  97. // USBPORT_KdPrint((1, "'bad device handle %x\n", DeviceHandle));
  98. DEBUG_BREAK();
  99. }
  100. #endif
  101. KeReleaseSpinLock(&devExt->Fdo.DevHandleListSpin.sl, irql);
  102. return found;
  103. }
  104. VOID
  105. USBPORT_RemoveDeviceHandle(
  106. PDEVICE_OBJECT FdoDeviceObject,
  107. PUSBD_DEVICE_HANDLE DeviceHandle
  108. )
  109. /*++
  110. Routine Description:
  111. Arguments:
  112. Return Value:
  113. TRUE is handle is valid
  114. --*/
  115. {
  116. PDEVICE_EXTENSION devExt;
  117. KIRQL irql;
  118. ASSERT_DEVICE_HANDLE(DeviceHandle);
  119. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  120. ASSERT_FDOEXT(devExt);
  121. LOGENTRY(NULL,
  122. FdoDeviceObject, LOG_MISC, 'remD', DeviceHandle, 0, 0);
  123. // synchronize with the validation function,
  124. // NOTE: we don't synchornize with the ADD function becuause it
  125. // is already serialized
  126. USBPORT_InterlockedRemoveEntryList(&DeviceHandle->ListEntry,
  127. &devExt->Fdo.DevHandleListSpin.sl);
  128. }
  129. ULONG
  130. USBPORT_GetDeviceCount(
  131. PDEVICE_OBJECT FdoDeviceObject
  132. )
  133. /*++
  134. Routine Description:
  135. counts devices on the BUS
  136. Arguments:
  137. Return Value:
  138. number of devices (including the root hub)
  139. --*/
  140. {
  141. PLIST_ENTRY listEntry;
  142. PDEVICE_EXTENSION devExt;
  143. KIRQL irql;
  144. ULONG deviceCount = 0;
  145. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  146. ASSERT_FDOEXT(devExt);
  147. KeAcquireSpinLock(&devExt->Fdo.DevHandleListSpin.sl, &irql);
  148. listEntry = &devExt->Fdo.DeviceHandleList;
  149. if (!IsListEmpty(listEntry)) {
  150. listEntry = devExt->Fdo.DeviceHandleList.Flink;
  151. }
  152. while (listEntry != &devExt->Fdo.DeviceHandleList) {
  153. PUSBD_DEVICE_HANDLE nextHandle;
  154. nextHandle = (PUSBD_DEVICE_HANDLE) CONTAINING_RECORD(
  155. listEntry,
  156. struct _USBD_DEVICE_HANDLE,
  157. ListEntry);
  158. deviceCount++;
  159. listEntry = nextHandle->ListEntry.Flink;
  160. }
  161. KeReleaseSpinLock(&devExt->Fdo.DevHandleListSpin.sl, irql);
  162. return deviceCount;
  163. }
  164. VOID
  165. USBPORT_AddDeviceHandle(
  166. PDEVICE_OBJECT FdoDeviceObject,
  167. PUSBD_DEVICE_HANDLE DeviceHandle
  168. )
  169. /*++
  170. Routine Description:
  171. adds a device handle to our internal list
  172. Arguments:
  173. Return Value:
  174. TRUE is handle is valid
  175. --*/
  176. {
  177. PDEVICE_EXTENSION devExt;
  178. ASSERT_DEVICE_HANDLE(DeviceHandle);
  179. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  180. ASSERT_FDOEXT(devExt);
  181. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'addD', DeviceHandle, 0, 0);
  182. InsertTailList(&devExt->Fdo.DeviceHandleList,
  183. &DeviceHandle->ListEntry);
  184. }
  185. VOID
  186. USBPORT_RemovePipeHandle(
  187. PUSBD_DEVICE_HANDLE DeviceHandle,
  188. PUSBD_PIPE_HANDLE_I PipeHandle
  189. )
  190. /*++
  191. Routine Description:
  192. Removes a pipe handle from our list of 'valid handles'
  193. Arguments:
  194. Return Value:
  195. none
  196. --*/
  197. {
  198. USBPORT_ASSERT(PipeHandle->ListEntry.Flink != NULL &&
  199. PipeHandle->ListEntry.Blink != NULL);
  200. RemoveEntryList(&PipeHandle->ListEntry);
  201. PipeHandle->ListEntry.Flink = NULL;
  202. PipeHandle->ListEntry.Blink = NULL;
  203. }
  204. VOID
  205. USBPORT_AddPipeHandle(
  206. PUSBD_DEVICE_HANDLE DeviceHandle,
  207. PUSBD_PIPE_HANDLE_I PipeHandle
  208. )
  209. /*++
  210. Routine Description:
  211. adds a pipe handle to our internal list
  212. Arguments:
  213. Return Value:
  214. TRUE is handle is valid
  215. --*/
  216. {
  217. ASSERT_DEVICE_HANDLE(DeviceHandle);
  218. USBPORT_ASSERT(PipeHandle->ListEntry.Flink == NULL &&
  219. PipeHandle->ListEntry.Blink == NULL);
  220. InsertTailList(&DeviceHandle->PipeHandleList,
  221. &PipeHandle->ListEntry);
  222. }
  223. BOOLEAN
  224. USBPORT_ValidatePipeHandle(
  225. PUSBD_DEVICE_HANDLE DeviceHandle,
  226. PUSBD_PIPE_HANDLE_I PipeHandle
  227. )
  228. /*++
  229. Routine Description:
  230. returns true if a device handle is valid
  231. Arguments:
  232. Return Value:
  233. TRUE is handle is valid
  234. --*/
  235. {
  236. BOOLEAN found = FALSE;
  237. PLIST_ENTRY listEntry;
  238. ASSERT_DEVICE_HANDLE(DeviceHandle);
  239. listEntry = &DeviceHandle->PipeHandleList;
  240. if (!IsListEmpty(listEntry)) {
  241. listEntry = DeviceHandle->PipeHandleList.Flink;
  242. }
  243. while (listEntry != &DeviceHandle->PipeHandleList) {
  244. PUSBD_PIPE_HANDLE_I nextHandle;
  245. nextHandle = (PUSBD_PIPE_HANDLE_I) CONTAINING_RECORD(
  246. listEntry,
  247. struct _USBD_PIPE_HANDLE_I,
  248. ListEntry);
  249. listEntry = nextHandle->ListEntry.Flink;
  250. if (nextHandle == PipeHandle) {
  251. found = TRUE;
  252. break;
  253. }
  254. }
  255. #if DBG
  256. if (!found) {
  257. USBPORT_KdPrint((1, "'bad pipe handle %x\n", PipeHandle));
  258. DEBUG_BREAK();
  259. }
  260. #endif
  261. return found;
  262. }
  263. NTSTATUS
  264. USBPORT_SendCommand(
  265. PUSBD_DEVICE_HANDLE DeviceHandle,
  266. PDEVICE_OBJECT FdoDeviceObject,
  267. PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
  268. PVOID Buffer,
  269. ULONG BufferLength,
  270. PULONG BytesReturned,
  271. USBD_STATUS *UsbdStatus
  272. )
  273. /*++
  274. Routine Description:
  275. Send a standard USB command on the default pipe.
  276. essentially what we do here is build a control
  277. transfer and queue it directly
  278. Arguments:
  279. DeviceHandle - ptr to USBPORT device structure the command will be sent to
  280. DeviceObject -
  281. RequestCode -
  282. WValue - wValue for setup packet
  283. WIndex - wIndex for setup packet
  284. WLength - wLength for setup packet
  285. Buffer - Input/Output Buffer for command
  286. BufferLength - Length of Input/Output buffer.
  287. BytesReturned - pointer to ulong to copy number of bytes
  288. returned (optional)
  289. UsbStatus - USBPORT status code returned in the URB.
  290. Return Value:
  291. STATUS_SUCCESS if successful,
  292. STATUS_UNSUCCESSFUL otherwise
  293. --*/
  294. {
  295. NTSTATUS ntStatus;
  296. PTRANSFER_URB urb = NULL;
  297. PUSBD_PIPE_HANDLE_I defaultPipe = &(DeviceHandle->DefaultPipe);
  298. PDEVICE_EXTENSION devExt;
  299. USBD_STATUS usbdStatus = USBD_STATUS_SUCCESS;
  300. KEVENT event;
  301. PAGED_CODE();
  302. USBPORT_KdPrint((2, "'enter USBPORT_SendCommand\n"));
  303. ASSERT_DEVICE_HANDLE(DeviceHandle);
  304. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  305. ASSERT_FDOEXT(devExt);
  306. USBPORT_ASSERT((USHORT)BufferLength == SetupPacket->wLength);
  307. LOGENTRY(defaultPipe->Endpoint,
  308. FdoDeviceObject, LOG_MISC, 'SENc', 0, 0, 0);
  309. KeInitializeEvent(&event,
  310. NotificationEvent,
  311. FALSE);
  312. ALLOC_POOL_Z(urb, NonPagedPool,
  313. sizeof(struct _TRANSFER_URB));
  314. if (urb) {
  315. InterlockedIncrement(&DeviceHandle->PendingUrbs);
  316. ntStatus = STATUS_SUCCESS;
  317. usbdStatus = USBD_STATUS_SUCCESS;
  318. urb->Hdr.Length = sizeof(struct _TRANSFER_URB);
  319. urb->Hdr.Function = URB_FUNCTION_CONTROL_TRANSFER;
  320. RtlCopyMemory(urb->u.SetupPacket,
  321. SetupPacket,
  322. 8);
  323. urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
  324. urb->UsbdPipeHandle = defaultPipe;
  325. urb->Hdr.UsbdDeviceHandle = DeviceHandle;
  326. urb->Hdr.UsbdFlags = 0;
  327. // USBPORT is responsible for setting the transfer direction
  328. //
  329. // TRANSFER direction is implied in the command
  330. if (SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST) {
  331. USBPORT_SET_TRANSFER_DIRECTION_IN(urb->TransferFlags);
  332. } else {
  333. USBPORT_SET_TRANSFER_DIRECTION_OUT(urb->TransferFlags);
  334. }
  335. urb->TransferBufferLength = BufferLength;
  336. urb->TransferBuffer = Buffer;
  337. urb->TransferBufferMDL = NULL;
  338. if (urb->TransferBufferLength != 0) {
  339. if ((urb->TransferBufferMDL =
  340. IoAllocateMdl(urb->TransferBuffer,
  341. urb->TransferBufferLength,
  342. FALSE,
  343. FALSE,
  344. NULL)) == NULL) {
  345. usbdStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
  346. // map the error
  347. ntStatus = USBPORT_SetUSBDError(NULL, usbdStatus);
  348. } else {
  349. SET_FLAG(urb->Hdr.UsbdFlags, USBPORT_REQUEST_MDL_ALLOCATED);
  350. MmBuildMdlForNonPagedPool(
  351. urb->TransferBufferMDL);
  352. }
  353. }
  354. LOGENTRY(defaultPipe->Endpoint, FdoDeviceObject,
  355. LOG_MISC, 'sndC',
  356. urb->TransferBufferLength,
  357. SetupPacket->bmRequestType.B,
  358. SetupPacket->bRequest);
  359. USBPORT_KdPrint((2,
  360. "'SendCommand cmd = 0x%x 0x%x buffer = 0x%x length = 0x%x direction = 0x%x\n",
  361. SetupPacket->bmRequestType.B,
  362. SetupPacket->bRequest,
  363. urb->TransferBuffer,
  364. urb->TransferBufferLength,
  365. urb->TransferFlags));
  366. // queue the transfer
  367. if (NT_SUCCESS(ntStatus)) {
  368. usbdStatus = USBPORT_AllocTransfer(FdoDeviceObject,
  369. urb,
  370. NULL,
  371. NULL,
  372. &event,
  373. 5000);
  374. if (USBD_SUCCESS(usbdStatus)) {
  375. // do the transfer, 5 second timeout
  376. // match the decrement in queue transferurb
  377. InterlockedIncrement(&DeviceHandle->PendingUrbs);
  378. USBPORT_QueueTransferUrb(urb);
  379. LOGENTRY(NULL, FdoDeviceObject,
  380. LOG_MISC, 'sWTt', 0, 0, 0);
  381. // wait for completion
  382. KeWaitForSingleObject(&event,
  383. Suspended,
  384. KernelMode,
  385. FALSE,
  386. NULL);
  387. LOGENTRY(NULL, FdoDeviceObject,
  388. LOG_MISC, 'sWTd', 0, 0, 0);
  389. // map the error
  390. usbdStatus = urb->Hdr.Status;
  391. }
  392. ntStatus =
  393. SET_USBD_ERROR(urb, usbdStatus);
  394. if (BytesReturned) {
  395. *BytesReturned = urb->TransferBufferLength;
  396. }
  397. if (UsbdStatus) {
  398. *UsbdStatus = usbdStatus;
  399. }
  400. }
  401. // free the transfer URB
  402. InterlockedDecrement(&DeviceHandle->PendingUrbs);
  403. FREE_POOL(FdoDeviceObject, urb);
  404. } else {
  405. if (UsbdStatus) {
  406. *UsbdStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
  407. ntStatus = USBPORT_SetUSBDError(NULL, *UsbdStatus);
  408. } else {
  409. ntStatus = USBPORT_SetUSBDError(NULL, USBD_STATUS_INSUFFICIENT_RESOURCES);
  410. }
  411. }
  412. //LOGENTRY(defaultPipe->Endpoint,
  413. // FdoDeviceObject, LOG_MISC, 'SENd', 0, ntStatus, usbdStatus);
  414. USBPORT_KdPrint((2, "'exit USBPORT_SendCommand 0x%x\n", ntStatus));
  415. return ntStatus;
  416. }
  417. NTSTATUS
  418. USBPORT_PokeEndpoint(
  419. PDEVICE_OBJECT FdoDeviceObject,
  420. PHCD_ENDPOINT Endpoint
  421. )
  422. /*++
  423. Routine Description:
  424. This function closes an existing endpoint in the miniport,
  425. frees the common buffer the reopens it with new requirements
  426. and parameters.
  427. This function is synchronous and assumes no active transfers
  428. are pending for the endpoint.
  429. This function is currently used to grow the transfer parameters
  430. on interrupt and control endpoints and to change the address of
  431. the default control endpoint
  432. NOTES:
  433. 1. for now we assume no changes to bw allocation
  434. 2. new parameters are set before the call in the endpoint
  435. structure
  436. Arguments:
  437. Return Value:
  438. NT status code.
  439. --*/
  440. {
  441. NTSTATUS ntStatus;
  442. ENDPOINT_REQUIREMENTS requirements;
  443. USB_MINIPORT_STATUS mpStatus;
  444. PDEVICE_EXTENSION devExt;
  445. PUSBPORT_COMMON_BUFFER commonBuffer;
  446. LONG busy;
  447. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  448. ASSERT_FDOEXT(devExt);
  449. // close the endpoint in the miniport
  450. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'poke', Endpoint, 0, 0);
  451. // mark the endpoint busy so that we don't poll it until
  452. // we open it again
  453. do {
  454. busy = InterlockedIncrement(&Endpoint->Busy);
  455. if (!busy) {
  456. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'pNby', 0, Endpoint, busy);
  457. break;
  458. }
  459. // defer processing
  460. InterlockedDecrement(&Endpoint->Busy);
  461. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'pbsy', 0, Endpoint, busy);
  462. USBPORT_Wait(FdoDeviceObject, 1);
  463. } while (busy != 0);
  464. ACQUIRE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'Ley0');
  465. MP_SetEndpointState(devExt, Endpoint, ENDPOINT_REMOVE);
  466. RELEASE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'Uey0');
  467. USBPORT_Wait(FdoDeviceObject, 2);
  468. // enpoint should now be out of the schedule
  469. // zero miniport data
  470. RtlZeroMemory(&Endpoint->MiniportEndpointData[0],
  471. REGISTRATION_PACKET(devExt).EndpointDataSize);
  472. // free the old miniport common buffer
  473. if (Endpoint->CommonBuffer) {
  474. USBPORT_HalFreeCommonBuffer(FdoDeviceObject,
  475. Endpoint->CommonBuffer);
  476. Endpoint->CommonBuffer = NULL;
  477. }
  478. MP_QueryEndpointRequirements(devExt,
  479. Endpoint,
  480. &requirements);
  481. // alloc new common buffer
  482. // save the requirements
  483. USBPORT_ASSERT(Endpoint->Parameters.TransferType != Bulk);
  484. USBPORT_ASSERT(Endpoint->Parameters.TransferType != Isochronous);
  485. USBPORT_KdPrint((1, "'(POKE) miniport requesting %d bytes\n",
  486. requirements.MinCommonBufferBytes));
  487. // allocate common buffer for this endpoint
  488. if (requirements.MinCommonBufferBytes) {
  489. commonBuffer =
  490. USBPORT_HalAllocateCommonBuffer(FdoDeviceObject,
  491. requirements.MinCommonBufferBytes);
  492. } else {
  493. commonBuffer = NULL;
  494. }
  495. if (commonBuffer == NULL &&
  496. requirements.MinCommonBufferBytes) {
  497. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  498. Endpoint->CommonBuffer = NULL;
  499. } else {
  500. Endpoint->CommonBuffer = commonBuffer;
  501. ntStatus = STATUS_SUCCESS;
  502. }
  503. // this check is redundant but it keeps
  504. // prefast happy
  505. if (Endpoint->CommonBuffer &&
  506. commonBuffer) {
  507. Endpoint->Parameters.CommonBufferVa =
  508. commonBuffer->MiniportVa;
  509. Endpoint->Parameters.CommonBufferPhys =
  510. commonBuffer->MiniportPhys;
  511. Endpoint->Parameters.CommonBufferBytes =
  512. commonBuffer->MiniportLength;
  513. }
  514. if (NT_SUCCESS(ntStatus)) {
  515. MP_OpenEndpoint(devExt, Endpoint, mpStatus);
  516. // in this UNIQUE situation this API is not allowed
  517. // (and should not) fail
  518. USBPORT_ASSERT(mpStatus == USBMP_STATUS_SUCCESS);
  519. // we need to sync the endpoint state with
  520. // the miniport, when first opened the miniport
  521. // puts the endpoint in status HALT.
  522. ACQUIRE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'LeK0');
  523. ACQUIRE_STATECHG_LOCK(FdoDeviceObject, Endpoint);
  524. if (Endpoint->CurrentState == ENDPOINT_ACTIVE) {
  525. RELEASE_STATECHG_LOCK(FdoDeviceObject, Endpoint);
  526. MP_SetEndpointState(devExt, Endpoint, ENDPOINT_ACTIVE);
  527. } else {
  528. RELEASE_STATECHG_LOCK(FdoDeviceObject, Endpoint);
  529. }
  530. RELEASE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'LeK0');
  531. }
  532. InterlockedDecrement(&Endpoint->Busy);
  533. return ntStatus;
  534. }
  535. VOID
  536. USBPORT_WaitActive(
  537. PDEVICE_OBJECT FdoDeviceObject,
  538. PHCD_ENDPOINT Endpoint
  539. )
  540. {
  541. MP_ENDPOINT_STATE currentState;
  542. ASSERT_ENDPOINT(Endpoint);
  543. do {
  544. ACQUIRE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'LeH0');
  545. currentState = USBPORT_GetEndpointState(Endpoint);
  546. RELEASE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'UeH0');
  547. LOGENTRY(Endpoint,
  548. FdoDeviceObject, LOG_XFERS, 'watA', Endpoint,
  549. currentState, 0);
  550. if (currentState == ENDPOINT_ACTIVE) {
  551. // quick release
  552. break;
  553. }
  554. ASSERT_PASSIVE();
  555. USBPORT_Wait(FdoDeviceObject, 1);
  556. } while (currentState != ENDPOINT_ACTIVE);
  557. }
  558. NTSTATUS
  559. USBPORT_OpenEndpoint(
  560. PUSBD_DEVICE_HANDLE DeviceHandle,
  561. PDEVICE_OBJECT FdoDeviceObject,
  562. PUSBD_PIPE_HANDLE_I PipeHandle,
  563. OUT USBD_STATUS *ReturnUsbdStatus,
  564. BOOLEAN IsDefaultPipe
  565. )
  566. /*++
  567. Routine Description:
  568. open an endpoint on a USB device.
  569. This function creates (initializes) endpoints and
  570. hooks it to a pipehandle
  571. Arguments:
  572. DeviceHandle - data describes the device this endpoint is on.
  573. DeviceObject - USBPORT device object.
  574. ReturnUsbdStatus - OPTIONAL
  575. Return Value:
  576. NT status code.
  577. --*/
  578. {
  579. NTSTATUS ntStatus;
  580. PDEVICE_EXTENSION devExt;
  581. PHCD_ENDPOINT endpoint;
  582. USBD_STATUS usbdStatus;
  583. ULONG siz;
  584. BOOLEAN gotBw;
  585. USB_HIGH_SPEED_MAXPACKET muxPacket;
  586. extern ULONG USB2LIB_EndpointContextSize;
  587. // this function is not pagable because we raise irql
  588. // we should be at passive level
  589. ASSERT_PASSIVE();
  590. // devhandle should have been validated
  591. // before we get here
  592. ASSERT_DEVICE_HANDLE(DeviceHandle);
  593. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  594. ASSERT_FDOEXT(devExt);
  595. siz = sizeof(*endpoint) + REGISTRATION_PACKET(devExt).EndpointDataSize;
  596. if (USBPORT_IS_USB20(devExt)) {
  597. siz += USB2LIB_EndpointContextSize;
  598. }
  599. LOGENTRY(NULL, FdoDeviceObject,
  600. LOG_PNP, 'opE+', PipeHandle, siz,
  601. REGISTRATION_PACKET(devExt).EndpointDataSize);
  602. // allocate the endoint
  603. // * begin special case
  604. // check for a no bandwidth endpoint ie max_oacket = 0
  605. // if so return success and set the endpoint pointer
  606. // in the pipe handle to a dummy value
  607. if (PipeHandle->EndpointDescriptor.wMaxPacketSize == 0) {
  608. USBPORT_AddPipeHandle(DeviceHandle,
  609. PipeHandle);
  610. PipeHandle->Endpoint = USB_BAD_PTR;
  611. ntStatus = STATUS_SUCCESS;
  612. SET_FLAG(PipeHandle->PipeStateFlags, USBPORT_PIPE_ZERO_BW);
  613. CLEAR_FLAG(PipeHandle->PipeStateFlags, USBPORT_PIPE_STATE_CLOSED);
  614. goto USBPORT_OpenEndpoint_Done;
  615. }
  616. // * end special case
  617. ALLOC_POOL_Z(endpoint, NonPagedPool, siz);
  618. if (endpoint) {
  619. endpoint->Sig = SIG_ENDPOINT;
  620. endpoint->Flags = 0;
  621. endpoint->EndpointRef = 0;
  622. endpoint->Busy = -1;
  623. endpoint->FdoDeviceObject = FdoDeviceObject;
  624. endpoint->DeviceHandle = DeviceHandle;
  625. // USBPORT_ResetEndpointIdle(endpoint);
  626. endpoint->Tt = DeviceHandle->Tt;
  627. if (endpoint->Tt != NULL) {
  628. ASSERT_TT(endpoint->Tt);
  629. ExInterlockedInsertTailList(&DeviceHandle->Tt->EndpointList,
  630. &endpoint->TtLink,
  631. &devExt->Fdo.TtEndpointListSpin.sl);
  632. }
  633. if (USBPORT_IS_USB20(devExt)) {
  634. PUCHAR pch;
  635. pch = (PUCHAR) &endpoint->MiniportEndpointData[0];
  636. pch += REGISTRATION_PACKET(devExt).EndpointDataSize;
  637. endpoint->Usb2LibEpContext = pch;
  638. } else {
  639. endpoint->Usb2LibEpContext = USB_BAD_PTR;
  640. }
  641. #if DBG
  642. USBPORT_LogAlloc(&endpoint->Log, 1);
  643. #endif
  644. LOGENTRY(endpoint, FdoDeviceObject,
  645. LOG_PNP, 'ope+', PipeHandle, siz,
  646. REGISTRATION_PACKET(devExt).EndpointDataSize);
  647. // initialize the endpoint
  648. InitializeListHead(&endpoint->ActiveList);
  649. InitializeListHead(&endpoint->CancelList);
  650. InitializeListHead(&endpoint->PendingList);
  651. InitializeListHead(&endpoint->AbortIrpList);
  652. USBPORT_InitializeSpinLock(&endpoint->ListSpin, 'EPL+', 'EPL-');
  653. USBPORT_InitializeSpinLock(&endpoint->StateChangeSpin, 'SCL+', 'SCL-');
  654. // extract some information from the
  655. // descriptor
  656. endpoint->Parameters.DeviceAddress =
  657. DeviceHandle->DeviceAddress;
  658. if (endpoint->Tt != NULL) {
  659. ASSERT_TT(endpoint->Tt);
  660. endpoint->Parameters.TtDeviceAddress =
  661. endpoint->Tt->DeviceAddress;
  662. } else {
  663. endpoint->Parameters.TtDeviceAddress = 0xFFFF;
  664. }
  665. endpoint->Parameters.TtPortNumber =
  666. DeviceHandle->TtPortNumber;
  667. muxPacket.us = PipeHandle->EndpointDescriptor.wMaxPacketSize;
  668. endpoint->Parameters.MuxPacketSize =
  669. muxPacket.MaxPacket;
  670. endpoint->Parameters.TransactionsPerMicroframe =
  671. muxPacket.HSmux+1;
  672. endpoint->Parameters.MaxPacketSize =
  673. muxPacket.MaxPacket * (muxPacket.HSmux+1);
  674. endpoint->Parameters.EndpointAddress =
  675. PipeHandle->EndpointDescriptor.bEndpointAddress;
  676. if ((PipeHandle->EndpointDescriptor.bmAttributes &
  677. USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
  678. #ifdef ISO_LOG
  679. USBPORT_LogAlloc(&endpoint->IsoLog, 4);
  680. #endif
  681. endpoint->Parameters.TransferType = Isochronous;
  682. } else if ((PipeHandle->EndpointDescriptor.bmAttributes &
  683. USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) {
  684. endpoint->Parameters.TransferType = Bulk;
  685. } else if ((PipeHandle->EndpointDescriptor.bmAttributes &
  686. USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT) {
  687. endpoint->Parameters.TransferType = Interrupt;
  688. } else {
  689. USBPORT_ASSERT((PipeHandle->EndpointDescriptor.bmAttributes &
  690. USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_CONTROL);
  691. endpoint->Parameters.TransferType = Control;
  692. }
  693. // check for low speed
  694. endpoint->Parameters.DeviceSpeed = DeviceHandle->DeviceSpeed;
  695. // Set max transfer size based on transfer type
  696. //
  697. // Note: that the MaximumTransferSize set by the
  698. // client driver in the pipe information structure
  699. // is no longer used.
  700. switch(endpoint->Parameters.TransferType) {
  701. case Interrupt:
  702. // this allows clients to put down larger
  703. // interrupt buffers if they want without
  704. // taking a perf hit. For some reason
  705. // printers do this.
  706. // bugbug research the praticality of splitting
  707. // interrupt transfers for the miniports this may
  708. // significantly reduce the memory allocated by
  709. // he uhci miniport
  710. endpoint->Parameters.MaxTransferSize = 1024;
  711. //endpoint->Parameters.MaxPacketSize;
  712. break;
  713. case Control:
  714. // 4k
  715. // node that the old win2k 4k usb stack does not actually
  716. // handle transfers larger than this correctly.
  717. endpoint->Parameters.MaxTransferSize = 1024*4;
  718. // set the default to 64k if this is not the control endpoint
  719. if (endpoint->Parameters.EndpointAddress != 0) {
  720. // the COMPAQ guys test this
  721. endpoint->Parameters.MaxTransferSize = 1024*64;
  722. }
  723. break;
  724. case Bulk:
  725. // 64k default
  726. endpoint->Parameters.MaxTransferSize = 1024*64;
  727. break;
  728. case Isochronous:
  729. // there is no reason to have a limit here
  730. // choose a really large default
  731. endpoint->Parameters.MaxTransferSize = 0x01000000;
  732. break;
  733. }
  734. endpoint->Parameters.Period = 0;
  735. // compute period required
  736. if (endpoint->Parameters.TransferType == Interrupt) {
  737. UCHAR tmp;
  738. UCHAR hsInterval;
  739. if (endpoint->Parameters.DeviceSpeed == HighSpeed) {
  740. // normalize the high speed period to microframes
  741. // for USB 20 the period specifies a power of 2
  742. // ie period = 2^(hsInterval-1)
  743. hsInterval = PipeHandle->EndpointDescriptor.bInterval;
  744. if (hsInterval) {
  745. hsInterval--;
  746. }
  747. // hsInterval must be 0..5
  748. if (hsInterval > 5) {
  749. hsInterval = 5;
  750. }
  751. tmp = 1<<hsInterval;
  752. } else {
  753. tmp = PipeHandle->EndpointDescriptor.bInterval;
  754. }
  755. // this code finds the first interval
  756. // <= USBPORT_MAX_INTEP_POLLING_INTERVAL
  757. // valid intervals are:
  758. // 1, 2, 4, 8, 16, 32(USBPORT_MAX_INTEP_POLLING_INTERVAL)
  759. // Initialize Period, may be adjusted down
  760. endpoint->Parameters.Period = USBPORT_MAX_INTEP_POLLING_INTERVAL;
  761. if ((tmp != 0) && (tmp < USBPORT_MAX_INTEP_POLLING_INTERVAL)) {
  762. // bInterval is in range. Adjust Period down if necessary.
  763. if ((endpoint->Parameters.DeviceSpeed == LowSpeed) &&
  764. (tmp < 8)) {
  765. // bInterval is not valid for LowSpeed, cap Period at 8
  766. endpoint->Parameters.Period = 8;
  767. } else {
  768. // Adjust Period down to greatest power of 2 less than or
  769. // equal to bInterval.
  770. while ((endpoint->Parameters.Period & tmp) == 0) {
  771. endpoint->Parameters.Period >>= 1;
  772. }
  773. }
  774. }
  775. //!!!
  776. //if (endpoint->Parameters.DeviceSpeed == LowSpeed) {
  777. // TEST_TRAP();
  778. // endpoint->Parameters.Period = 1;
  779. //}
  780. //!!!
  781. endpoint->Parameters.MaxPeriod =
  782. endpoint->Parameters.Period;
  783. }
  784. if (endpoint->Parameters.TransferType == Isochronous) {
  785. endpoint->Parameters.Period = 1;
  786. }
  787. if (IS_ROOT_HUB(DeviceHandle)) {
  788. SET_FLAG(endpoint->Flags, EPFLAG_ROOTHUB);
  789. }
  790. if (USB_ENDPOINT_DIRECTION_IN(
  791. PipeHandle->EndpointDescriptor.bEndpointAddress)) {
  792. endpoint->Parameters.TransferDirection = In;
  793. } else {
  794. endpoint->Parameters.TransferDirection = Out;
  795. }
  796. if (USBPORT_IS_USB20(devExt)) {
  797. // call the engine and attempt to allocate the necessary
  798. // bus time for this endoint
  799. gotBw = USBPORT_AllocateBandwidthUSB20(FdoDeviceObject, endpoint);
  800. //!!!
  801. //if (endpoint->Parameters.DeviceSpeed == LowSpeed) {
  802. // TEST_TRAP();
  803. // endpoint->Parameters.InterruptScheduleMask = 0x10; //sMask;
  804. // endpoint->Parameters.SplitCompletionMask = 0xc1; //cMask;
  805. //}
  806. //!!!
  807. } else {
  808. // * USB 1.1
  809. endpoint->Parameters.Bandwidth =
  810. USBPORT_CalculateUsbBandwidth(FdoDeviceObject, endpoint);
  811. // caclualte the best schedule position
  812. gotBw = USBPORT_AllocateBandwidthUSB11(FdoDeviceObject, endpoint);
  813. }
  814. if (gotBw) {
  815. if (IsDefaultPipe ||
  816. endpoint->Parameters.TransferType == Isochronous) {
  817. // iso and default pipes do not halt on errors
  818. // ie they do not require a resetpipe
  819. endpoint->Parameters.EndpointFlags |= EP_PARM_FLAG_NOHALT;
  820. }
  821. ntStatus = STATUS_SUCCESS;
  822. } else {
  823. LOGENTRY(endpoint,
  824. FdoDeviceObject, LOG_PNP, 'noBW', endpoint, 0, 0);
  825. // no bandwidth error
  826. ntStatus = USBPORT_SetUSBDError(NULL, USBD_STATUS_NO_BANDWIDTH);
  827. if (ReturnUsbdStatus != NULL) {
  828. *ReturnUsbdStatus = USBD_STATUS_NO_BANDWIDTH;
  829. }
  830. }
  831. } else {
  832. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  833. }
  834. if (NT_SUCCESS(ntStatus)) {
  835. // now do the open
  836. if (TEST_FLAG(endpoint->Flags, EPFLAG_ROOTHUB)) {
  837. PDEVICE_EXTENSION rhDevExt;
  838. GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
  839. ASSERT_PDOEXT(rhDevExt);
  840. // opens for the root hub device
  841. // are not passed to the miniport
  842. usbdStatus = USBD_STATUS_SUCCESS;
  843. endpoint->EpWorkerFunction =
  844. USBPORT_RootHub_EndpointWorker;
  845. // successful open the enpoint defaults
  846. // to active
  847. endpoint->NewState =
  848. endpoint->CurrentState = ENDPOINT_ACTIVE;
  849. // track the hub interrupt endpoint
  850. if (endpoint->Parameters.TransferType == Interrupt) {
  851. rhDevExt->Pdo.RootHubInterruptEndpoint =
  852. endpoint;
  853. }
  854. } else {
  855. USB_MINIPORT_STATUS mpStatus;
  856. PUSBPORT_COMMON_BUFFER commonBuffer;
  857. ENDPOINT_REQUIREMENTS requirements;
  858. ULONG ordinal;
  859. // find out what we will need from the
  860. // miniport for this endpoint
  861. MP_QueryEndpointRequirements(devExt,
  862. endpoint, &requirements);
  863. // adjust maxtransfer based on miniport
  864. // feedback.
  865. switch (endpoint->Parameters.TransferType) {
  866. case Bulk:
  867. case Interrupt:
  868. LOGENTRY(endpoint,
  869. FdoDeviceObject, LOG_MISC, 'MaxT', endpoint,
  870. requirements.MaximumTransferSize, 0);
  871. EP_MAX_TRANSFER(endpoint) =
  872. requirements.MaximumTransferSize;
  873. break;
  874. }
  875. ordinal = USBPORT_SelectOrdinal(FdoDeviceObject,
  876. endpoint);
  877. USBPORT_KdPrint((1, "'miniport requesting %d bytes\n",
  878. requirements.MinCommonBufferBytes));
  879. // allocate common buffer for this endpoint
  880. if (requirements.MinCommonBufferBytes) {
  881. commonBuffer =
  882. USBPORT_HalAllocateCommonBuffer(FdoDeviceObject,
  883. requirements.MinCommonBufferBytes);
  884. } else {
  885. commonBuffer = NULL;
  886. }
  887. if (commonBuffer == NULL &&
  888. requirements.MinCommonBufferBytes) {
  889. mpStatus = USBMP_STATUS_NO_RESOURCES;
  890. endpoint->CommonBuffer = NULL;
  891. } else {
  892. ULONG mpOptionFlags;
  893. mpOptionFlags = REGISTRATION_PACKET(devExt).OptionFlags;
  894. endpoint->CommonBuffer = commonBuffer;
  895. if (commonBuffer != NULL) {
  896. endpoint->Parameters.CommonBufferVa =
  897. commonBuffer->MiniportVa;
  898. endpoint->Parameters.CommonBufferPhys =
  899. commonBuffer->MiniportPhys;
  900. endpoint->Parameters.CommonBufferBytes =
  901. commonBuffer->MiniportLength;
  902. }
  903. endpoint->Parameters.Ordinal = ordinal;
  904. // call open request to minport
  905. MP_OpenEndpoint(devExt, endpoint, mpStatus);
  906. // note that once we call open this enpoint
  907. // may show up on the Attention list
  908. // set our internal flags based on what the
  909. // miniport passed back
  910. // if (endpoint->Parameters.EndpointFlags & EP_PARM_FLAG_DMA) {
  911. SET_FLAG(endpoint->Flags, EPFLAG_MAP_XFERS);
  912. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NO_PNP_RESOURCES)) {
  913. // no mapping for the virtual bus
  914. CLEAR_FLAG(endpoint->Flags, EPFLAG_MAP_XFERS);
  915. SET_FLAG(endpoint->Flags, EPFLAG_VBUS);
  916. }
  917. SET_FLAG(endpoint->Flags, EPFLAG_VIRGIN);
  918. endpoint->EpWorkerFunction =
  919. USBPORT_DmaEndpointWorker;
  920. // } else {
  921. // non-dma endpoint
  922. // TEST_TRAP();
  923. // }
  924. }
  925. // successful open the enpoint defaults
  926. // to pause, we need to move it to active
  927. if (mpStatus == USBMP_STATUS_SUCCESS) {
  928. ACQUIRE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'LeF0');
  929. // initialize endpoint state machine
  930. endpoint->CurrentState = ENDPOINT_PAUSE;
  931. endpoint->NewState = ENDPOINT_PAUSE;
  932. endpoint->CurrentStatus = ENDPOINT_STATUS_RUN;
  933. USBPORT_SetEndpointState(endpoint, ENDPOINT_ACTIVE);
  934. RELEASE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'UeF0');
  935. // Wait for endpoint to go active. The reason here
  936. // is that an iso driver (usbaudio) will immediatly
  937. // send transfers to the endpoint, these tranfers are
  938. // marked with a transmission frame on submission but
  939. // will have to wait until the endpoint is active to
  940. // be programmed, hence they arrive in the miniport
  941. // too late on slower systems.
  942. USBPORT_WaitActive(FdoDeviceObject,
  943. endpoint);
  944. }
  945. usbdStatus = MPSTATUS_TO_USBSTATUS(mpStatus);
  946. }
  947. // convert usb status to nt status
  948. ntStatus = USBPORT_SetUSBDError(NULL, usbdStatus);
  949. if (ReturnUsbdStatus != NULL) {
  950. *ReturnUsbdStatus = usbdStatus;
  951. }
  952. }
  953. if (NT_SUCCESS(ntStatus)) {
  954. USBPORT_AddPipeHandle(DeviceHandle,
  955. PipeHandle);
  956. // track the endpoint
  957. ExInterlockedInsertTailList(&devExt->Fdo.GlobalEndpointList,
  958. &endpoint->GlobalLink,
  959. &devExt->Fdo.EndpointListSpin.sl);
  960. PipeHandle->Endpoint = endpoint;
  961. CLEAR_FLAG(PipeHandle->PipeStateFlags, USBPORT_PIPE_STATE_CLOSED);
  962. } else {
  963. if (endpoint) {
  964. if (endpoint->Tt != NULL) {
  965. ASSERT_TT(endpoint->Tt);
  966. USBPORT_InterlockedRemoveEntryList(&endpoint->TtLink,
  967. &devExt->Fdo.TtEndpointListSpin.sl);
  968. }
  969. USBPORT_LogFree(FdoDeviceObject, &endpoint->Log);
  970. UNSIG(endpoint);
  971. FREE_POOL(FdoDeviceObject, endpoint);
  972. }
  973. }
  974. USBPORT_OpenEndpoint_Done:
  975. return ntStatus;
  976. }
  977. VOID
  978. USBPORT_CloseEndpoint(
  979. PUSBD_DEVICE_HANDLE DeviceHandle,
  980. PDEVICE_OBJECT FdoDeviceObject,
  981. PHCD_ENDPOINT Endpoint
  982. )
  983. /*++
  984. Routine Description:
  985. Close an Endpoint
  986. Arguments:
  987. DeviceHandle - ptr to USBPORT device data structure.
  988. DeviceObject - USBPORT device object.
  989. Return Value:
  990. STATUS_SUCCESS if successful,
  991. STATUS_UNSUCCESSFUL otherwise
  992. --*/
  993. {
  994. NTSTATUS ntStatus = 0;
  995. PURB urb;
  996. PDEVICE_EXTENSION devExt;
  997. USB_MINIPORT_STATUS mpStatus;
  998. KIRQL irql;
  999. BOOLEAN stallClose;
  1000. LONG busy;
  1001. // should have been validated before we
  1002. // get here
  1003. ASSERT_DEVICE_HANDLE(DeviceHandle);
  1004. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1005. ASSERT_FDOEXT(devExt);
  1006. // we should have no requests queued to the
  1007. // endpoint
  1008. LOGENTRY(Endpoint, FdoDeviceObject,
  1009. LOG_MISC, 'clEP', Endpoint, 0, 0);
  1010. // USBPORT_ResetEndpointIdle(Endpoint);
  1011. // remove from our 'Active' lists
  1012. KeAcquireSpinLock(&devExt->Fdo.EndpointListSpin.sl, &irql);
  1013. if (TEST_FLAG(Endpoint->Flags, EPFLAG_ROOTHUB) &&
  1014. Endpoint->Parameters.TransferType == Interrupt) {
  1015. KIRQL rhIrql;
  1016. PDEVICE_EXTENSION rhDevExt;
  1017. // remove references to th eroot hub
  1018. ACQUIRE_ROOTHUB_LOCK(FdoDeviceObject, rhIrql);
  1019. // we should have a root hub pdo since we are closing
  1020. // an endpoint associated with it.
  1021. USBPORT_ASSERT(devExt->Fdo.RootHubPdo != NULL);
  1022. GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
  1023. ASSERT_PDOEXT(rhDevExt);
  1024. rhDevExt->Pdo.RootHubInterruptEndpoint = NULL;
  1025. RELEASE_ROOTHUB_LOCK(FdoDeviceObject, rhIrql);
  1026. }
  1027. KeReleaseSpinLock(&devExt->Fdo.EndpointListSpin.sl, irql);
  1028. // The client is locked out at this point ie he can't access the
  1029. // pipe tied to the endpoint. We need to wait for any outstanding
  1030. // stuff to complete -- including any state changes, after which
  1031. // we can ask the coreworker to remove the endpoint.
  1032. // the endpoint lock protects the lists -- which need to be
  1033. // empty
  1034. do {
  1035. stallClose = FALSE;
  1036. ACQUIRE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'LeD1');
  1037. if (!IsListEmpty(&Endpoint->PendingList)) {
  1038. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'stc1', Endpoint, 0, 0);
  1039. stallClose = TRUE;
  1040. }
  1041. if (!IsListEmpty(&Endpoint->ActiveList)) {
  1042. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'stc2', Endpoint, 0, 0);
  1043. stallClose = TRUE;
  1044. }
  1045. if (!IsListEmpty(&Endpoint->CancelList)) {
  1046. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'stc3', Endpoint, 0, 0);
  1047. stallClose = TRUE;
  1048. }
  1049. if (!IsListEmpty(&Endpoint->AbortIrpList)) {
  1050. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'stc4', Endpoint, 0, 0);
  1051. stallClose = TRUE;
  1052. }
  1053. if (Endpoint->EndpointRef) {
  1054. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'stc6', Endpoint, 0, 0);
  1055. stallClose = TRUE;
  1056. }
  1057. ACQUIRE_STATECHG_LOCK(FdoDeviceObject, Endpoint);
  1058. if (Endpoint->CurrentState !=
  1059. Endpoint->NewState) {
  1060. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'stc5', Endpoint, 0, 0);
  1061. stallClose = TRUE;
  1062. }
  1063. RELEASE_STATECHG_LOCK(FdoDeviceObject, Endpoint);
  1064. RELEASE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'UeD1');
  1065. // last check...
  1066. // synchronize with worker
  1067. // we just need to wait for worker to finish if it is running
  1068. // it should not pick up and run again unless it has stuff to
  1069. // do -- in which case stallClose will already be set.
  1070. busy = InterlockedIncrement(&Endpoint->Busy);
  1071. if (busy) {
  1072. // defer processing
  1073. LOGENTRY(Endpoint,
  1074. FdoDeviceObject, LOG_XFERS, 'clby', 0, Endpoint, 0);
  1075. stallClose = TRUE;
  1076. }
  1077. InterlockedDecrement(&Endpoint->Busy);
  1078. if (stallClose) {
  1079. LOGENTRY(Endpoint,
  1080. FdoDeviceObject, LOG_XFERS, 'stlC', 0, Endpoint, 0);
  1081. USBPORT_Wait(FdoDeviceObject, 1);
  1082. }
  1083. } while (stallClose);
  1084. LOGENTRY(Endpoint,
  1085. FdoDeviceObject, LOG_XFERS, 'CLdn', 0, Endpoint, 0);
  1086. // unlink ref to device handle since it will be removed when
  1087. // all endpoints are closed
  1088. Endpoint->DeviceHandle = NULL;
  1089. // lock the endpoint & set the state to remove and
  1090. // free the bw
  1091. if (USBPORT_IS_USB20(devExt)) {
  1092. PTRANSACTION_TRANSLATOR tt;
  1093. USBPORT_FreeBandwidthUSB20(FdoDeviceObject, Endpoint);
  1094. KeAcquireSpinLock(&devExt->Fdo.TtEndpointListSpin.sl, &irql);
  1095. tt = Endpoint->Tt;
  1096. if (tt != NULL) {
  1097. ASSERT_TT(tt);
  1098. USBPORT_ASSERT(Endpoint->TtLink.Flink != NULL);
  1099. USBPORT_ASSERT(Endpoint->TtLink.Blink != NULL);
  1100. RemoveEntryList(&Endpoint->TtLink);
  1101. Endpoint->TtLink.Flink = NULL;
  1102. Endpoint->TtLink.Blink = NULL;
  1103. if (TEST_FLAG(tt->TtFlags, USBPORT_TTFLAG_REMOVED) &&
  1104. IsListEmpty(&tt->EndpointList)) {
  1105. ULONG i, bandwidth;
  1106. USBPORT_UpdateAllocatedBwTt(tt);
  1107. // alloc new
  1108. bandwidth = tt->MaxAllocedBw;
  1109. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  1110. devExt->Fdo.BandwidthTable[i] += bandwidth;
  1111. }
  1112. // last endpoint free the TT if it is marked gone
  1113. FREE_POOL(FdoDeviceObject, tt);
  1114. }
  1115. }
  1116. KeReleaseSpinLock(&devExt->Fdo.TtEndpointListSpin.sl, irql);
  1117. } else {
  1118. USBPORT_FreeBandwidthUSB11(FdoDeviceObject, Endpoint);
  1119. }
  1120. ACQUIRE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'LeD0');
  1121. USBPORT_SetEndpointState(Endpoint, ENDPOINT_REMOVE);
  1122. RELEASE_ENDPOINT_LOCK(Endpoint, FdoDeviceObject, 'UeD0');
  1123. // the endpoint will be freed when it reaches the 'REMOVE'
  1124. // state
  1125. // endpointWorker will be signalled when a frame has passed
  1126. // at that time the endpoint will be moved to the closed list
  1127. // and the worker thread will be signalled to flush the closed
  1128. // endpoints ie free the common buffer.
  1129. USBPORT_SignalWorker(FdoDeviceObject);
  1130. return;
  1131. }
  1132. VOID
  1133. USBPORT_ClosePipe(
  1134. PUSBD_DEVICE_HANDLE DeviceHandle,
  1135. PDEVICE_OBJECT FdoDeviceObject,
  1136. PUSBD_PIPE_HANDLE_I PipeHandle
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. Close a USB pipe and the endpoint associated with it
  1141. This is a synchronous operation that waits for all
  1142. transfers associated with the pipe to be completed.
  1143. Arguments:
  1144. DeviceHandle - ptr to USBPORT device data structure.
  1145. DeviceObject - USBPORT device object.
  1146. PipeHandle - USBPORT pipe handle associated with the endpoint.
  1147. Return Value:
  1148. STATUS_SUCCESS if successful,
  1149. STATUS_UNSUCCESSFUL otherwise
  1150. --*/
  1151. {
  1152. NTSTATUS ntStatus = 0;
  1153. PDEVICE_EXTENSION devExt;
  1154. // should have beed validated before we
  1155. // get here
  1156. ASSERT_DEVICE_HANDLE(DeviceHandle);
  1157. ASSERT_PIPE_HANDLE(PipeHandle);
  1158. LOGENTRY(NULL, FdoDeviceObject,
  1159. LOG_MISC, 'clPI', PipeHandle, 0, 0);
  1160. if (PipeHandle->PipeStateFlags & USBPORT_PIPE_STATE_CLOSED) {
  1161. // already closed
  1162. // generally when a pertially open interface needs to
  1163. // be closed due to an error
  1164. USBPORT_ASSERT(PipeHandle->ListEntry.Flink == NULL &&
  1165. PipeHandle->ListEntry.Blink == NULL);
  1166. return;
  1167. }
  1168. // invalidate the pipe
  1169. USBPORT_RemovePipeHandle(DeviceHandle,
  1170. PipeHandle);
  1171. SET_FLAG(PipeHandle->PipeStateFlags, USBPORT_PIPE_STATE_CLOSED);
  1172. // at this point the client will be unable to queue
  1173. // any transfers to this pipe or endpoint
  1174. // BUGBUG flush tranfers and wait, this also includes waiting
  1175. // for any state changes to complete
  1176. LOGENTRY(NULL, FdoDeviceObject,
  1177. LOG_MISC, 'pipW', PipeHandle, 0, 0);
  1178. // KeWait(PipeEvent) {
  1179. // }
  1180. // now 'close' the endpoint
  1181. if (TEST_FLAG(PipeHandle->PipeStateFlags, USBPORT_PIPE_ZERO_BW)) {
  1182. CLEAR_FLAG(PipeHandle->PipeStateFlags, USBPORT_PIPE_ZERO_BW);
  1183. } else {
  1184. USBPORT_CloseEndpoint(DeviceHandle,
  1185. FdoDeviceObject,
  1186. PipeHandle->Endpoint);
  1187. }
  1188. }
  1189. VOID
  1190. USBPORT_FlushClosedEndpointList(
  1191. PDEVICE_OBJECT FdoDeviceObject
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. walk the "closed" endpoint list and close any endpoints
  1196. that are ready.
  1197. endpoints are placed on the 'closed' list when they reach the
  1198. removed state.
  1199. Arguments:
  1200. Return Value:
  1201. --*/
  1202. {
  1203. PDEVICE_EXTENSION devExt;
  1204. PLIST_ENTRY listEntry;
  1205. PHCD_ENDPOINT endpoint;
  1206. KIRQL irql;
  1207. BOOLEAN closed = TRUE;
  1208. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1209. ASSERT_FDOEXT(devExt);
  1210. LOGENTRY(NULL, FdoDeviceObject,
  1211. LOG_NOISY, 'fCLO', FdoDeviceObject, 0, 0);
  1212. // stall any closes
  1213. KeAcquireSpinLock(&devExt->Fdo.EpClosedListSpin.sl, &irql);
  1214. while (!IsListEmpty(&devExt->Fdo.EpClosedList) &&
  1215. closed) {
  1216. listEntry = RemoveHeadList(&devExt->Fdo.EpClosedList);
  1217. endpoint = (PHCD_ENDPOINT) CONTAINING_RECORD(
  1218. listEntry,
  1219. struct _HCD_ENDPOINT,
  1220. ClosedLink);
  1221. LOGENTRY(NULL, FdoDeviceObject,
  1222. LOG_PNP, 'fclo', endpoint, 0, 0);
  1223. ASSERT_ENDPOINT(endpoint);
  1224. USBPORT_ASSERT(endpoint->CurrentState == ENDPOINT_CLOSED);
  1225. endpoint->ClosedLink.Flink = NULL;
  1226. endpoint->ClosedLink.Blink = NULL;
  1227. KeReleaseSpinLock(&devExt->Fdo.EpClosedListSpin.sl, irql);
  1228. // if we are unable to close now we must bail so the
  1229. // worker function can run
  1230. closed = USBPORT_LazyCloseEndpoint(FdoDeviceObject, endpoint);
  1231. KeAcquireSpinLock(&devExt->Fdo.EpClosedListSpin.sl, &irql);
  1232. }
  1233. KeReleaseSpinLock(&devExt->Fdo.EpClosedListSpin.sl, irql);
  1234. }
  1235. BOOLEAN
  1236. USBPORT_LazyCloseEndpoint(
  1237. PDEVICE_OBJECT FdoDeviceObject,
  1238. PHCD_ENDPOINT Endpoint
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. Close an Endpoint. Put the endpoint on our list
  1243. of endpoints-to-close and wakeup the worker thread.
  1244. Arguments:
  1245. Return Value:
  1246. returns true if closed
  1247. --*/
  1248. {
  1249. PDEVICE_EXTENSION devExt;
  1250. KIRQL irql;
  1251. BOOLEAN closed;
  1252. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1253. ASSERT_FDOEXT(devExt);
  1254. LOGENTRY(NULL, FdoDeviceObject,
  1255. LOG_XFERS, 'frEP', Endpoint, 0, 0);
  1256. // endpoint is no longer on the global list, now we just need
  1257. // to make sure no one has a reference to it before we delete
  1258. // it.
  1259. // The endpoint may have been invalidated ie on the Attention
  1260. // List before being removed from the global list to avoid this
  1261. // potential conlict we check here until both the busy flag is
  1262. // -1 (meaning coreworker is thru) AND AttendLink is NULL
  1263. // if it is busy we put it back on the closed list
  1264. if (IS_ON_ATTEND_LIST(Endpoint) ||
  1265. Endpoint->Busy != -1) {
  1266. // still have work to do, put the endpoint back on
  1267. // the close list
  1268. KeAcquireSpinLock(&devExt->Fdo.EndpointListSpin.sl, &irql);
  1269. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'CLOr', 0, Endpoint, 0);
  1270. // it is OK to be on the attention list and the closed
  1271. // list
  1272. USBPORT_ASSERT(Endpoint->ClosedLink.Flink == NULL);
  1273. USBPORT_ASSERT(Endpoint->ClosedLink.Blink == NULL);
  1274. ExInterlockedInsertTailList(&devExt->Fdo.EpClosedList,
  1275. &Endpoint->ClosedLink,
  1276. &devExt->Fdo.EpClosedListSpin.sl);
  1277. KeReleaseSpinLock(&devExt->Fdo.EndpointListSpin.sl, irql);
  1278. closed = FALSE;
  1279. } else {
  1280. // remove from global list
  1281. KeAcquireSpinLock(&devExt->Fdo.EndpointListSpin.sl, &irql);
  1282. RemoveEntryList(&Endpoint->GlobalLink);
  1283. Endpoint->GlobalLink.Flink = NULL;
  1284. Endpoint->GlobalLink.Blink = NULL;
  1285. KeReleaseSpinLock(&devExt->Fdo.EndpointListSpin.sl, irql);
  1286. // free endpoint memory
  1287. if (Endpoint->CommonBuffer) {
  1288. USBPORT_HalFreeCommonBuffer(FdoDeviceObject,
  1289. Endpoint->CommonBuffer);
  1290. }
  1291. USBPORT_LogFree(FdoDeviceObject, &Endpoint->Log);
  1292. #ifdef ISO_LOG
  1293. USBPORT_LogFree(FdoDeviceObject, &Endpoint->IsoLog);
  1294. #endif
  1295. UNSIG(Endpoint);
  1296. FREE_POOL(FdoDeviceObject, Endpoint);
  1297. closed = TRUE;
  1298. }
  1299. return closed;
  1300. }
  1301. VOID
  1302. USBPORT_FreeUsbAddress(
  1303. PDEVICE_OBJECT FdoDeviceObject,
  1304. USHORT DeviceAddress
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. Arguments:
  1309. Return Value:
  1310. Valid USB address (1..127) to use for this device,
  1311. returns 0 if no device address available.
  1312. --*/
  1313. {
  1314. PDEVICE_EXTENSION devExt;
  1315. USHORT address = 0, i, j;
  1316. ULONG bit;
  1317. PAGED_CODE();
  1318. // we should never see a free to device address 0
  1319. USBPORT_ASSERT(DeviceAddress != 0);
  1320. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1321. ASSERT_FDOEXT(devExt);
  1322. for (j=0; j<4; j++) {
  1323. bit = 1;
  1324. for (i=0; i<32; i++) {
  1325. address = (USHORT)(j*32+i);
  1326. if (address == DeviceAddress) {
  1327. devExt->Fdo.AddressList[j] &= ~bit;
  1328. goto USBPORT_FreeUsbAddress_Done;
  1329. }
  1330. bit = bit<<1;
  1331. }
  1332. }
  1333. USBPORT_FreeUsbAddress_Done:
  1334. USBPORT_KdPrint((3, "'USBPORT free Address %d\n", address));
  1335. }
  1336. USHORT
  1337. USBPORT_AllocateUsbAddress(
  1338. PDEVICE_OBJECT FdoDeviceObject
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. Arguments:
  1343. Return Value:
  1344. Valid USB address (1..127) to use for this device,
  1345. returns 0 if no device address available.
  1346. --*/
  1347. {
  1348. PDEVICE_EXTENSION devExt;
  1349. USHORT address, i, j;
  1350. ULONG bit;
  1351. PAGED_CODE();
  1352. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1353. ASSERT_FDOEXT(devExt);
  1354. address = 0;
  1355. for (j=0; j<4; j++) {
  1356. bit = 1;
  1357. for (i=0; i<32; i++) {
  1358. if (!(devExt->Fdo.AddressList[j] & bit)) {
  1359. devExt->Fdo.AddressList[j] |= bit;
  1360. address = (USHORT)(j*32+i);
  1361. goto USBPORT_AllocateUsbAddress_Done;
  1362. }
  1363. bit = bit<<1;
  1364. }
  1365. }
  1366. // no free addresses?
  1367. USBPORT_ASSERT(0);
  1368. USBPORT_AllocateUsbAddress_Done:
  1369. USBPORT_KdPrint((3, "'USBPORT assigning Address %d\n", address));
  1370. return address;
  1371. }
  1372. NTSTATUS
  1373. USBPORT_InitializeHsHub(
  1374. PDEVICE_OBJECT FdoDeviceObject,
  1375. PUSBD_DEVICE_HANDLE HubDeviceHandle,
  1376. ULONG TtCount
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. Service exported for use by the hub driver
  1381. This service initializes a high speed hub
  1382. Arguments:
  1383. HubDeviceHandle - DeviceHandle for the creating USB Hub
  1384. Return Value:
  1385. NT status code.
  1386. --*/
  1387. {
  1388. NTSTATUS ntStatus;
  1389. ULONG i;
  1390. LOGENTRY(NULL, FdoDeviceObject,
  1391. LOG_MISC, 'ihsb', 0, HubDeviceHandle, TtCount);
  1392. // hub driver might pass us NULL if it could not
  1393. // retrieve a device handle
  1394. if (HubDeviceHandle == NULL) {
  1395. return STATUS_INVALID_PARAMETER;
  1396. }
  1397. ASSERT_DEVICE_HANDLE(HubDeviceHandle)
  1398. USBPORT_ASSERT(HubDeviceHandle->DeviceSpeed == HighSpeed);
  1399. if (IS_ROOT_HUB(HubDeviceHandle)) {
  1400. // no TTs for the root hub yet
  1401. return STATUS_SUCCESS;
  1402. }
  1403. USBPORT_ASSERT(HubDeviceHandle->DeviceDescriptor.bDeviceClass ==
  1404. USB_DEVICE_CLASS_HUB);
  1405. USBPORT_ASSERT(TEST_FLAG(HubDeviceHandle->DeviceFlags,
  1406. USBPORT_DEVICEFLAG_HSHUB));
  1407. for (i=0; i< TtCount; i++) {
  1408. ntStatus = USBPORT_InitializeTT(FdoDeviceObject,
  1409. HubDeviceHandle,
  1410. (USHORT)i+1);
  1411. if(!NT_SUCCESS(ntStatus)) {
  1412. break;
  1413. }
  1414. }
  1415. HubDeviceHandle->TtCount = TtCount;
  1416. return ntStatus;
  1417. }
  1418. NTSTATUS
  1419. USBPORT_CreateDevice(
  1420. PUSBD_DEVICE_HANDLE *DeviceHandle,
  1421. PDEVICE_OBJECT FdoDeviceObject,
  1422. PUSBD_DEVICE_HANDLE HubDeviceHandle,
  1423. USHORT PortStatus,
  1424. USHORT PortNumber
  1425. )
  1426. /*++
  1427. Routine Description:
  1428. Service exported for use by the hub driver
  1429. Called for each new device on the USB bus, this function sets
  1430. up the internal data structures we need to keep track of the
  1431. device and assigns it an address.
  1432. Arguments:
  1433. DeviceHandle - ptr to return the ptr to the new device structure
  1434. created by this routine
  1435. DeviceObject - USBPORT device object for the USB bus this device is on.
  1436. HubDeviceHandle - DeviceHandle for the creating USB Hub
  1437. Return Value:
  1438. NT status code.
  1439. --*/
  1440. {
  1441. NTSTATUS ntStatus;
  1442. PUSBD_DEVICE_HANDLE deviceHandle;
  1443. PUSBD_PIPE_HANDLE_I defaultPipe;
  1444. PDEVICE_EXTENSION devExt;
  1445. ULONG bytesReturned = 0;
  1446. PUCHAR data = NULL;
  1447. BOOLEAN open = FALSE;
  1448. ULONG dataSize;
  1449. PTRANSACTION_TRANSLATOR tt = NULL;
  1450. USHORT ttPort;
  1451. PAGED_CODE();
  1452. USBPORT_KdPrint((2, "'CreateDevice\n"));
  1453. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1454. ASSERT_FDOEXT(devExt);
  1455. //
  1456. // first validate the deviceHandle for the creating hub, we need
  1457. // this information for USB 1.1 devices behind a USB 2.0 hub.
  1458. //
  1459. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'crD>', HubDeviceHandle,
  1460. PortNumber, PortStatus);
  1461. // NOTE: this actually locks all device handles
  1462. LOCK_DEVICE(HubDeviceHandle, FdoDeviceObject);
  1463. if (!USBPORT_ValidateDeviceHandle(FdoDeviceObject,
  1464. HubDeviceHandle,
  1465. FALSE)) {
  1466. // this is most likely a bug in the hub driver
  1467. DEBUG_BREAK();
  1468. UNLOCK_DEVICE(DeviceHandle, FdoDeviceObject);
  1469. // fail the create if the hubs device handle is bugus
  1470. // chances are that the device handle is bad becuse the
  1471. // device is gone.
  1472. return STATUS_DEVICE_NOT_CONNECTED;
  1473. }
  1474. // start at the port for this device,
  1475. // if this is a 1.1 device in a 1.1 hub
  1476. // downstream of a 2.0 hub then we need
  1477. // the port number from the 1.1 hub
  1478. ttPort = PortNumber;
  1479. // port status tells us the type of device we are dealing with
  1480. if (USBPORT_IS_USB20(devExt) &&
  1481. !TEST_FLAG(PortStatus, PORT_STATUS_HIGH_SPEED)) {
  1482. // walk upstream until we reach a USB 2.0 hub
  1483. // this hub will conatin the appropriate TT
  1484. tt = USBPORT_GetTt(FdoDeviceObject,
  1485. HubDeviceHandle,
  1486. &ttPort);
  1487. }
  1488. UNLOCK_DEVICE(DeviceHandle, FdoDeviceObject);
  1489. ALLOC_POOL_Z(deviceHandle, NonPagedPool,
  1490. sizeof(USBD_DEVICE_HANDLE));
  1491. *DeviceHandle = NULL;
  1492. if (deviceHandle == NULL) {
  1493. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1494. } else {
  1495. LOGENTRY(NULL,
  1496. FdoDeviceObject, LOG_MISC, 'CRED', 0, 0, deviceHandle);
  1497. deviceHandle->PendingUrbs = 0;
  1498. deviceHandle->HubDeviceHandle = HubDeviceHandle;
  1499. deviceHandle->ConfigurationHandle = NULL;
  1500. deviceHandle->DeviceAddress = USB_DEFAULT_DEVICE_ADDRESS;
  1501. //deviceHandle->DeviceBandwidth = 0;
  1502. if (PortStatus & PORT_STATUS_LOW_SPEED) {
  1503. deviceHandle->DeviceSpeed = LowSpeed;
  1504. } else if (PortStatus & PORT_STATUS_HIGH_SPEED) {
  1505. deviceHandle->DeviceSpeed = HighSpeed;
  1506. } else {
  1507. deviceHandle->DeviceSpeed = FullSpeed;
  1508. }
  1509. deviceHandle->Sig = SIG_DEVICE_HANDLE;
  1510. // port number is maps to a specific tt but hub fw
  1511. // has to make sense of this.
  1512. deviceHandle->TtPortNumber = ttPort;
  1513. deviceHandle->Tt = tt;
  1514. LOCK_DEVICE(deviceHandle, FdoDeviceObject);
  1515. // buffer for our descriptor, one packet
  1516. data = (PUCHAR) &deviceHandle->DeviceDescriptor;
  1517. dataSize = sizeof(deviceHandle->DeviceDescriptor);
  1518. // **
  1519. // We need to talk to the device, first we open the default pipe
  1520. // using the defined max packet size (defined by USB spec as 8
  1521. // bytes until device receives the GET_DESCRIPTOR (device) command).
  1522. // We set the address get the device descriptor then close the pipe
  1523. // and re-open it with the correct max packet size.
  1524. // **
  1525. #define USB_DEFAULT_LS_MAX_PACKET 8
  1526. //
  1527. // open the default pipe for the device
  1528. //
  1529. defaultPipe = &deviceHandle->DefaultPipe;
  1530. if (deviceHandle->DeviceSpeed == LowSpeed) {
  1531. INITIALIZE_DEFAULT_PIPE(*defaultPipe, USB_DEFAULT_LS_MAX_PACKET);
  1532. } else {
  1533. INITIALIZE_DEFAULT_PIPE(*defaultPipe, USB_DEFAULT_MAX_PACKET);
  1534. }
  1535. InitializeListHead(&deviceHandle->PipeHandleList);
  1536. InitializeListHead(&deviceHandle->TtList);
  1537. ntStatus = USBPORT_OpenEndpoint(deviceHandle,
  1538. FdoDeviceObject,
  1539. defaultPipe,
  1540. NULL,
  1541. TRUE);
  1542. open = NT_SUCCESS(ntStatus);
  1543. bytesReturned = 0;
  1544. if (NT_SUCCESS(ntStatus)) {
  1545. //
  1546. // Configure the default pipe for this device and assign the
  1547. // device an address
  1548. //
  1549. // NOTE: if this operation fails it means that we have a device
  1550. // that will respond to the default endpoint and we can't change
  1551. // it.
  1552. // we have no choice but to disable the port on the hub this
  1553. // device is attached to.
  1554. //
  1555. //
  1556. // Get information about the device
  1557. //
  1558. USB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
  1559. PUCHAR tmpDevDescBuf;
  1560. // Would you believe that there exist some devices that get confused
  1561. // if the very first Get Device Descriptor request does not have a
  1562. // wLength value of 0x40 even though the device only has a 0x12 byte
  1563. // Device Descriptor to return? Any change to the way devices have
  1564. // always been enumerated since the being of USB 1.0 time can cause
  1565. // bizarre consequences. Use a wLength value of 0x40 for the very
  1566. // first Get Device Descriptor request.
  1567. ALLOC_POOL_Z(tmpDevDescBuf, NonPagedPool,
  1568. USB_DEFAULT_MAX_PACKET);
  1569. if (tmpDevDescBuf == NULL) {
  1570. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1571. } else {
  1572. // setup packet for get device descriptor
  1573. USBPORT_INIT_SETUP_PACKET(setupPacket,
  1574. USB_REQUEST_GET_DESCRIPTOR, // bRequest
  1575. BMREQUEST_DEVICE_TO_HOST, // Dir
  1576. BMREQUEST_TO_DEVICE, // Recipient
  1577. BMREQUEST_STANDARD, // Type
  1578. USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(USB_DEVICE_DESCRIPTOR_TYPE, 0), // wValue
  1579. 0, // wIndex
  1580. USB_DEFAULT_MAX_PACKET); // wLength
  1581. ntStatus = USBPORT_SendCommand(deviceHandle,
  1582. FdoDeviceObject,
  1583. &setupPacket,
  1584. tmpDevDescBuf,
  1585. USB_DEFAULT_MAX_PACKET,
  1586. &bytesReturned,
  1587. NULL);
  1588. // NOTE:
  1589. // at this point we only have the first 8 bytes of the
  1590. // device descriptor.
  1591. RtlCopyMemory(data, tmpDevDescBuf, dataSize);
  1592. FREE_POOL(FdoDeviceObject, tmpDevDescBuf);
  1593. }
  1594. }
  1595. // some devices babble so we ignore the error
  1596. // on this transaction if we got enough data
  1597. if (bytesReturned == 8 && !NT_SUCCESS(ntStatus)) {
  1598. USBPORT_KdPrint((1,
  1599. "'Error returned from get device descriptor -- ignored\n"));
  1600. ntStatus = STATUS_SUCCESS;
  1601. }
  1602. // validate the max packet value and descriptor
  1603. // we need at least eight bytes a value of zero
  1604. // in max packet is bogus
  1605. if (NT_SUCCESS(ntStatus) &&
  1606. (bytesReturned >= 8) &&
  1607. (deviceHandle->DeviceDescriptor.bLength >= sizeof(USB_DEVICE_DESCRIPTOR)) &&
  1608. (deviceHandle->DeviceDescriptor.bDescriptorType == USB_DEVICE_DESCRIPTOR_TYPE) &&
  1609. ((deviceHandle->DeviceDescriptor.bMaxPacketSize0 == 0x08) ||
  1610. (deviceHandle->DeviceDescriptor.bMaxPacketSize0 == 0x10) ||
  1611. (deviceHandle->DeviceDescriptor.bMaxPacketSize0 == 0x20) ||
  1612. (deviceHandle->DeviceDescriptor.bMaxPacketSize0 == 0x40))) {
  1613. USBPORT_AddDeviceHandle(FdoDeviceObject, deviceHandle);
  1614. *DeviceHandle = deviceHandle;
  1615. } else {
  1616. PUCHAR p = (PUCHAR)&deviceHandle->DeviceDescriptor;
  1617. // print a big debug message
  1618. USBPORT_KdPrint((0, "'CREATEDEVICE failed enumeration %08X %02X\n",
  1619. ntStatus, bytesReturned));
  1620. USBPORT_KdPrint((0, "'%02X %02X %02X %02X %02X %02X %02X %02X"
  1621. " %02X %02X %02X %02X %02X %02X %02X %02X"
  1622. " %02X %02X\n",
  1623. p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],
  1624. p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15],
  1625. p[16],p[17]));
  1626. USBPORT_DebugClient((
  1627. "Bad Device Detected\n"));
  1628. DEBUG_BREAK();
  1629. //
  1630. // something went wrong, if we assigned any resources to
  1631. // the default pipe then we free them before we get out.
  1632. //
  1633. // we need to signal to the parent hub that this
  1634. // port is to be be disabled we will do this by
  1635. // returning an error.
  1636. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1637. // if we opened a pipe close it
  1638. if (open) {
  1639. USBPORT_ClosePipe(deviceHandle,
  1640. FdoDeviceObject,
  1641. defaultPipe);
  1642. }
  1643. }
  1644. UNLOCK_DEVICE(deviceHandle, FdoDeviceObject);
  1645. if (!NT_SUCCESS(ntStatus)) {
  1646. UNSIG(deviceHandle);
  1647. FREE_POOL(FdoDeviceObject, deviceHandle);
  1648. }
  1649. }
  1650. USBPORT_CreateDevice_Done:
  1651. CATC_TRAP_ERROR(FdoDeviceObject, ntStatus);
  1652. LOGENTRY(NULL,
  1653. FdoDeviceObject, LOG_MISC, 'creD', 0, 0, ntStatus);
  1654. USBPORT_ENUMLOG(FdoDeviceObject, 'cdev', ntStatus, 0);
  1655. return ntStatus;
  1656. }
  1657. NTSTATUS
  1658. USBPORT_RemoveDevice(
  1659. PUSBD_DEVICE_HANDLE DeviceHandle,
  1660. PDEVICE_OBJECT FdoDeviceObject,
  1661. ULONG Flags
  1662. )
  1663. /*++
  1664. Routine Description:
  1665. Service exported for use by the hub driver
  1666. Called for each device on the USB bus that needs to be removed.
  1667. This routine frees the device handle and the address assigned
  1668. to the device.
  1669. Some new tricks here:
  1670. When this function is called it is asumed the client driver has
  1671. received the REMOVE irp and passed it on to the bus driver. We
  1672. remove the device handle from our list, this will cause any new
  1673. transfers submitted by the driver to be failed. Any current
  1674. transfers the driver has will be completed with error.
  1675. Once all transfer are flushed for all the endpoints we will close
  1676. the endpoints and free the device handle (ie) noone has any references
  1677. to it anymore.
  1678. This should -- in theory -- prevent bad drivers from crashing in usbport
  1679. or the miniport if they send requests after a remove.
  1680. Arguments:
  1681. DeviceHandle - ptr to device data structure created by class driver
  1682. in USBPORT_CreateDevice.
  1683. FdoDeviceObject - USBPORT device object for the USB bus this device is on.
  1684. Flags -
  1685. USBD_KEEP_DEVICE_DATA
  1686. USBD_MARK_DEVICE_BUSY - we don't use this one
  1687. Return Value:
  1688. NT status code.
  1689. --*/
  1690. {
  1691. NTSTATUS ntStatus;
  1692. PDEVICE_EXTENSION devExt;
  1693. PUSBD_PIPE_HANDLE_I defaultPipe;
  1694. USBD_STATUS usbdStatus;
  1695. if (Flags & USBD_KEEP_DEVICE_DATA) {
  1696. // keep data means keep the handle valid
  1697. return STATUS_SUCCESS;
  1698. }
  1699. if (Flags & USBD_MARK_DEVICE_BUSY) {
  1700. // This means stop accepting requests. Only used by USBHUB when
  1701. // handling a IOCTL_INTERNAL_USB_RESET_PORT request?? Need to do
  1702. // anything special here?? Need to keep the handle valid since it
  1703. // will be used to restore the device after the reset.
  1704. //
  1705. // GlenS note to JD: review this.
  1706. //
  1707. return STATUS_SUCCESS;
  1708. }
  1709. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1710. // assume success
  1711. ntStatus = STATUS_SUCCESS;
  1712. LOCK_DEVICE(DeviceHandle, FdoDeviceObject);
  1713. if (!USBPORT_ValidateDeviceHandle(FdoDeviceObject,
  1714. DeviceHandle,
  1715. FALSE)) {
  1716. // this is most likely a bug in the hub
  1717. // driver
  1718. DEBUG_BREAK();
  1719. UNLOCK_DEVICE(DeviceHandle, FdoDeviceObject);
  1720. // chances are that the device handle is bad becuse the
  1721. // device is gone.
  1722. return STATUS_DEVICE_NOT_CONNECTED;
  1723. }
  1724. LOGENTRY(NULL,
  1725. FdoDeviceObject, LOG_PNP, 'REMV', DeviceHandle, 0, 0);
  1726. // handle is no longer on our lists so all attempts
  1727. // to submit urbs by the client driver will now fail
  1728. USBPORT_RemoveDeviceHandle(FdoDeviceObject,
  1729. DeviceHandle);
  1730. SET_FLAG(DeviceHandle->DeviceFlags,
  1731. USBPORT_DEVICEFLAG_REMOVED);
  1732. USBPORT_AbortAllTransfers(FdoDeviceObject,
  1733. DeviceHandle);
  1734. // wait for any refs from non-transfer URBs to drain
  1735. while (InterlockedDecrement(&DeviceHandle->PendingUrbs) >= 0) {
  1736. LOGENTRY(NULL,
  1737. FdoDeviceObject, LOG_PNP, 'dPUR', DeviceHandle, 0,
  1738. DeviceHandle->PendingUrbs);
  1739. InterlockedIncrement(&DeviceHandle->PendingUrbs);
  1740. USBPORT_Wait(FdoDeviceObject, 100);
  1741. }
  1742. //
  1743. // make sure and clean up any open pipe handles
  1744. // the device may have
  1745. //
  1746. if (DeviceHandle->ConfigurationHandle) {
  1747. USBPORT_InternalCloseConfiguration(DeviceHandle,
  1748. FdoDeviceObject,
  1749. 0);
  1750. }
  1751. defaultPipe = &DeviceHandle->DefaultPipe;
  1752. // we should aways have a default pipe, this will free
  1753. // the endpoint
  1754. USBPORT_ClosePipe(DeviceHandle,
  1755. FdoDeviceObject,
  1756. defaultPipe);
  1757. if (DeviceHandle->DeviceAddress != USB_DEFAULT_DEVICE_ADDRESS) {
  1758. USBPORT_FreeUsbAddress(FdoDeviceObject, DeviceHandle->DeviceAddress);
  1759. }
  1760. //
  1761. // free any Tt handles associated with this device handle
  1762. //
  1763. while (!IsListEmpty(&DeviceHandle->TtList)) {
  1764. PTRANSACTION_TRANSLATOR tt;
  1765. PLIST_ENTRY listEntry;
  1766. KIRQL irql;
  1767. listEntry = RemoveHeadList(&DeviceHandle->TtList);
  1768. tt = (PTRANSACTION_TRANSLATOR) CONTAINING_RECORD(
  1769. listEntry,
  1770. struct _TRANSACTION_TRANSLATOR,
  1771. TtLink);
  1772. ASSERT_TT(tt);
  1773. KeAcquireSpinLock(&devExt->Fdo.TtEndpointListSpin.sl, &irql);
  1774. SET_FLAG(tt->TtFlags, USBPORT_TTFLAG_REMOVED);
  1775. if (IsListEmpty(&tt->EndpointList)) {
  1776. ULONG i, bandwidth;
  1777. USBPORT_UpdateAllocatedBwTt(tt);
  1778. // alloc new
  1779. bandwidth = tt->MaxAllocedBw;
  1780. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  1781. devExt->Fdo.BandwidthTable[i] += bandwidth;
  1782. }
  1783. FREE_POOL(FdoDeviceObject, tt);
  1784. }
  1785. KeReleaseSpinLock(&devExt->Fdo.TtEndpointListSpin.sl, irql);
  1786. }
  1787. UNLOCK_DEVICE(DeviceHandle, FdoDeviceObject);
  1788. if (!IS_ROOT_HUB(DeviceHandle)) {
  1789. ASSERT_DEVICE_HANDLE(DeviceHandle);
  1790. FREE_POOL(FdoDeviceObject, DeviceHandle);
  1791. }
  1792. return ntStatus;
  1793. }
  1794. NTSTATUS
  1795. USBPORT_InitializeDevice(
  1796. PUSBD_DEVICE_HANDLE DeviceHandle,
  1797. PDEVICE_OBJECT FdoDeviceObject
  1798. )
  1799. /*++
  1800. Routine Description:
  1801. Service exported for use by the hub driver
  1802. Called for each device on the USB bus that needs to be initialized.
  1803. This routine allocates an address and assigns it to the device.
  1804. NOTE: on entry the the device descriptor in DeviceHandle is expected to
  1805. contain at least the first 8 bytes of the device descriptor, this
  1806. information is used to open the default pipe.
  1807. On Error the DeviceHandle structure is freed.
  1808. Arguments:
  1809. DeviceHandle - ptr to device data structure created by class driver
  1810. from a call to USBPORT_CreateDevice.
  1811. DeviceObject - USBPORT device object for the USB bus this device is on.
  1812. Return Value:
  1813. NT status code.
  1814. --*/
  1815. {
  1816. NTSTATUS ntStatus;
  1817. PUSBD_PIPE_HANDLE_I defaultPipe;
  1818. USHORT address;
  1819. PDEVICE_EXTENSION devExt;
  1820. USB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
  1821. PAGED_CODE();
  1822. USBPORT_KdPrint((2, "'InitializeDevice\n"));
  1823. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1824. ASSERT_FDOEXT(devExt);
  1825. USBPORT_ASSERT(DeviceHandle != NULL);
  1826. LOCK_DEVICE(DeviceHandle, FdoDeviceObject);
  1827. defaultPipe = &DeviceHandle->DefaultPipe;
  1828. // assume success
  1829. ntStatus = STATUS_SUCCESS;
  1830. //
  1831. // Assign Address to the device
  1832. //
  1833. address = USBPORT_AllocateUsbAddress(FdoDeviceObject);
  1834. USBPORT_KdPrint((2, "'SetAddress, assigning 0x%x address\n", address));
  1835. LOGENTRY(NULL,
  1836. FdoDeviceObject, LOG_MISC, 'ADRa', DeviceHandle, 0, address);
  1837. USBPORT_ASSERT(DeviceHandle->DeviceAddress == USB_DEFAULT_DEVICE_ADDRESS);
  1838. // setup packet for set_address
  1839. USBPORT_INIT_SETUP_PACKET(setupPacket,
  1840. USB_REQUEST_SET_ADDRESS, // bRequest
  1841. BMREQUEST_HOST_TO_DEVICE, // Dir
  1842. BMREQUEST_TO_DEVICE, // Recipient
  1843. BMREQUEST_STANDARD, // Type
  1844. address, // wValue
  1845. 0, // wIndex
  1846. 0); // wLength
  1847. ntStatus = USBPORT_SendCommand(DeviceHandle,
  1848. FdoDeviceObject,
  1849. &setupPacket,
  1850. NULL,
  1851. 0,
  1852. NULL,
  1853. NULL);
  1854. DeviceHandle->DeviceAddress = address;
  1855. if (NT_SUCCESS(ntStatus)) {
  1856. USB_MINIPORT_STATUS mpStatus;
  1857. //
  1858. // done with addressing process...
  1859. //
  1860. // poke the endpoint zero to the new address and
  1861. // the true max packet size for the default control.
  1862. // endpoint.
  1863. //
  1864. defaultPipe->Endpoint->Parameters.MaxPacketSize =
  1865. DeviceHandle->DeviceDescriptor.bMaxPacketSize0;
  1866. defaultPipe->Endpoint->Parameters.DeviceAddress = address;
  1867. //MP_PokeEndpoint(devExt, defaultPipe->Endpoint, mpStatus);
  1868. //ntStatus = MPSTATUS_TO_NTSTATUS(mpStatus);
  1869. ntStatus = USBPORT_PokeEndpoint(FdoDeviceObject, defaultPipe->Endpoint);
  1870. }
  1871. if (NT_SUCCESS(ntStatus)) {
  1872. ULONG bytesReturned;
  1873. USB_DEFAULT_PIPE_SETUP_PACKET setupPacket2;
  1874. // 10ms delay to allow devices to respond after
  1875. // the setaddress command
  1876. USBPORT_Wait(FdoDeviceObject, 10);
  1877. //
  1878. // Fetch the device descriptor again, this time
  1879. // get the whole thing.
  1880. //
  1881. // setup packet for get device descriptor
  1882. USBPORT_INIT_SETUP_PACKET(setupPacket2,
  1883. USB_REQUEST_GET_DESCRIPTOR, // bRequest
  1884. BMREQUEST_DEVICE_TO_HOST, // Dir
  1885. BMREQUEST_TO_DEVICE, // Recipient
  1886. BMREQUEST_STANDARD, // Type
  1887. USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(USB_DEVICE_DESCRIPTOR_TYPE, 0), // wValue
  1888. 0, // wIndex
  1889. sizeof(DeviceHandle->DeviceDescriptor)); // wLength
  1890. ntStatus =
  1891. USBPORT_SendCommand(DeviceHandle,
  1892. FdoDeviceObject,
  1893. &setupPacket2,
  1894. (PUCHAR) &DeviceHandle->DeviceDescriptor,
  1895. sizeof(DeviceHandle->DeviceDescriptor),
  1896. &bytesReturned,
  1897. NULL);
  1898. if (NT_SUCCESS(ntStatus) &&
  1899. (bytesReturned != sizeof(USB_DEVICE_DESCRIPTOR)) ||
  1900. (DeviceHandle->DeviceDescriptor.bLength < sizeof(USB_DEVICE_DESCRIPTOR)) ||
  1901. (DeviceHandle->DeviceDescriptor.bDescriptorType != USB_DEVICE_DESCRIPTOR_TYPE) ||
  1902. ((DeviceHandle->DeviceDescriptor.bMaxPacketSize0 != 0x08) &&
  1903. (DeviceHandle->DeviceDescriptor.bMaxPacketSize0 != 0x10) &&
  1904. (DeviceHandle->DeviceDescriptor.bMaxPacketSize0 != 0x20) &&
  1905. (DeviceHandle->DeviceDescriptor.bMaxPacketSize0 != 0x40))) {
  1906. // print a big debug message
  1907. USBPORT_KdPrint((0, "'InitializeDevice failed enumeration\n"));
  1908. ntStatus = STATUS_DEVICE_DATA_ERROR;
  1909. }
  1910. }
  1911. if (NT_SUCCESS(ntStatus)) {
  1912. if (DeviceHandle->DeviceSpeed == HighSpeed &&
  1913. DeviceHandle->DeviceDescriptor.bDeviceClass ==
  1914. USB_DEVICE_CLASS_HUB) {
  1915. // note that this is a hs hub, these require special
  1916. // handling because of the TTs
  1917. SET_FLAG(DeviceHandle->DeviceFlags, USBPORT_DEVICEFLAG_HSHUB);
  1918. }
  1919. UNLOCK_DEVICE(DeviceHandle, FdoDeviceObject);
  1920. } else {
  1921. //
  1922. // something went wrong, if we assigned any resources to
  1923. // the default pipe then we free them before we get out.
  1924. //
  1925. // we need to signal to the parent hub that this
  1926. // port is to be be disabled we will do this by
  1927. // returning an error.
  1928. // if we got here then we know the default
  1929. // endpoint is open
  1930. DEBUG_BREAK();
  1931. USBPORT_ClosePipe(DeviceHandle,
  1932. FdoDeviceObject,
  1933. defaultPipe);
  1934. if (DeviceHandle->DeviceAddress != USB_DEFAULT_DEVICE_ADDRESS) {
  1935. USBPORT_FreeUsbAddress(FdoDeviceObject, DeviceHandle->DeviceAddress);
  1936. }
  1937. UNLOCK_DEVICE(DeviceHandle, FdoDeviceObject);
  1938. // this device handle is no longer valid
  1939. USBPORT_RemoveDeviceHandle(FdoDeviceObject, DeviceHandle);
  1940. FREE_POOL(FdoDeviceObject, DeviceHandle);
  1941. }
  1942. LOGENTRY(NULL,
  1943. FdoDeviceObject, LOG_MISC, 'iniD', DeviceHandle, 0, ntStatus);
  1944. CATC_TRAP_ERROR(FdoDeviceObject, ntStatus);
  1945. USBPORT_ENUMLOG(FdoDeviceObject, 'idev', ntStatus, 0);
  1946. return ntStatus;
  1947. }
  1948. NTSTATUS
  1949. USBPORT_GetUsbDescriptor(
  1950. PUSBD_DEVICE_HANDLE DeviceHandle,
  1951. PDEVICE_OBJECT FdoDeviceObject,
  1952. UCHAR DescriptorType,
  1953. PUCHAR DescriptorBuffer,
  1954. PULONG DescriptorBufferLength
  1955. )
  1956. /*++
  1957. Routine Description:
  1958. Arguments:
  1959. DeviceHandle - ptr to device data structure created by class driver
  1960. from a call to USBPORT_CreateDevice.
  1961. Return Value:
  1962. NT status code.
  1963. --*/
  1964. {
  1965. NTSTATUS ntStatus;
  1966. PUSBD_PIPE_HANDLE_I defaultPipe;
  1967. PDEVICE_EXTENSION devExt;
  1968. USB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
  1969. USBPORT_INIT_SETUP_PACKET(setupPacket,
  1970. USB_REQUEST_GET_DESCRIPTOR, // bRequest
  1971. BMREQUEST_DEVICE_TO_HOST, // Dir
  1972. BMREQUEST_TO_DEVICE, // Recipient
  1973. BMREQUEST_STANDARD, // Type
  1974. USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(DescriptorType, 0), // wValue
  1975. 0, // wIndex
  1976. *DescriptorBufferLength); // wLength
  1977. ntStatus =
  1978. USBPORT_SendCommand(DeviceHandle,
  1979. FdoDeviceObject,
  1980. &setupPacket,
  1981. DescriptorBuffer,
  1982. *DescriptorBufferLength,
  1983. DescriptorBufferLength,
  1984. NULL);
  1985. return ntStatus;
  1986. }
  1987. BOOLEAN
  1988. USBPORT_DeviceHasQueuedTransfers(
  1989. PDEVICE_OBJECT FdoDeviceObject,
  1990. PUSBD_DEVICE_HANDLE DeviceHandle
  1991. )
  1992. /*++
  1993. Routine Description:
  1994. Returns TRUE device has queued transfers
  1995. Arguments:
  1996. Return Value:
  1997. True if device has transfers queued transfers
  1998. --*/
  1999. {
  2000. PDEVICE_EXTENSION devExt;
  2001. BOOLEAN hasTransfers = FALSE;
  2002. PLIST_ENTRY listEntry;
  2003. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2004. ASSERT_FDOEXT(devExt);
  2005. ASSERT_DEVICE_HANDLE(DeviceHandle);
  2006. listEntry = &DeviceHandle->PipeHandleList;
  2007. if (!IsListEmpty(listEntry)) {
  2008. listEntry = DeviceHandle->PipeHandleList.Flink;
  2009. }
  2010. while (listEntry != &DeviceHandle->PipeHandleList) {
  2011. PUSBD_PIPE_HANDLE_I nextHandle;
  2012. nextHandle = (PUSBD_PIPE_HANDLE_I) CONTAINING_RECORD(
  2013. listEntry,
  2014. struct _USBD_PIPE_HANDLE_I,
  2015. ListEntry);
  2016. ASSERT_PIPE_HANDLE(nextHandle);
  2017. listEntry = nextHandle->ListEntry.Flink;
  2018. if (!TEST_FLAG(nextHandle->PipeStateFlags, USBPORT_PIPE_ZERO_BW) &&
  2019. USBPORT_EndpointHasQueuedTransfers(FdoDeviceObject,
  2020. nextHandle->Endpoint)) {
  2021. hasTransfers = TRUE;
  2022. break;
  2023. }
  2024. }
  2025. return hasTransfers;
  2026. }
  2027. VOID
  2028. USBPORT_AbortAllTransfers(
  2029. PDEVICE_OBJECT FdoDeviceObject,
  2030. PUSBD_DEVICE_HANDLE DeviceHandle
  2031. )
  2032. /*++
  2033. Routine Description:
  2034. abort all pending transfers associated with a device handle.
  2035. This function is synchronous -- it is called after the device
  2036. handle is removed from our tables so no new transfers can be
  2037. posted.
  2038. The idea here is to complete any transfers that may still be
  2039. pending when the device is removed in case the client driver
  2040. neglected to.
  2041. On entry to this function the device is locked.
  2042. Arguments:
  2043. DeviceHandle - ptr to device data structure created by class driver
  2044. in USBPORT_CreateDevice.
  2045. FdoDeviceObject - USBPORT device object for the USB bus this device is on.
  2046. Return Value:
  2047. NT status code.
  2048. --*/
  2049. {
  2050. PLIST_ENTRY listEntry;
  2051. ASSERT_DEVICE_HANDLE(DeviceHandle);
  2052. listEntry = &DeviceHandle->PipeHandleList;
  2053. if (!IsListEmpty(listEntry)) {
  2054. listEntry = DeviceHandle->PipeHandleList.Flink;
  2055. }
  2056. while (listEntry != &DeviceHandle->PipeHandleList) {
  2057. PUSBD_PIPE_HANDLE_I nextHandle;
  2058. nextHandle = (PUSBD_PIPE_HANDLE_I) CONTAINING_RECORD(
  2059. listEntry,
  2060. struct _USBD_PIPE_HANDLE_I,
  2061. ListEntry);
  2062. ASSERT_PIPE_HANDLE(nextHandle);
  2063. listEntry = nextHandle->ListEntry.Flink;
  2064. if (!TEST_FLAG(nextHandle->PipeStateFlags, USBPORT_PIPE_ZERO_BW)) {
  2065. SET_FLAG(nextHandle->Endpoint->Flags, EPFLAG_DEVICE_GONE);
  2066. USBPORT_AbortEndpoint(FdoDeviceObject,
  2067. nextHandle->Endpoint,
  2068. NULL);
  2069. USBPORT_FlushMapTransferList(FdoDeviceObject);
  2070. }
  2071. }
  2072. // This gaurantees that no transfers are in our lists or
  2073. // in the miniport when we remove the device.
  2074. // NOTE: If a driver passed a remove with transfers still pending
  2075. // we still may crash but this should happen in the offending
  2076. // driver.
  2077. // NOTE 2: The whistler hub driver will remove the device early
  2078. // (on connect change) so this code will be hit legit-ly in
  2079. // this case.
  2080. // now wait for queues to empty
  2081. while (USBPORT_DeviceHasQueuedTransfers(FdoDeviceObject, DeviceHandle)) {
  2082. // wait, then check again
  2083. USBPORT_Wait(FdoDeviceObject, 100);
  2084. }
  2085. }
  2086. NTSTATUS
  2087. USBPORT_CloneDevice(
  2088. PDEVICE_OBJECT FdoDeviceObject,
  2089. PUSBD_DEVICE_HANDLE OldDeviceHandle,
  2090. PUSBD_DEVICE_HANDLE NewDeviceHandle
  2091. )
  2092. /*++
  2093. Routine Description:
  2094. Service exported for use by the hub driver
  2095. Arguments:
  2096. NewDeviceHandle - ptr to device data structure created by class driver
  2097. in USBPORT_CreateDevice.
  2098. OldDeviceHandle - ptr to device data structure created by class driver
  2099. in USBPORT_CreateDevice.
  2100. FdoDeviceObject - USBPORT device object for the USB bus this device is on.
  2101. Return Value:
  2102. NT status code.
  2103. --*/
  2104. {
  2105. NTSTATUS ntStatus;
  2106. PDEVICE_EXTENSION devExt;
  2107. USBD_STATUS usbdStatus;
  2108. USB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
  2109. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2110. // assume success
  2111. ntStatus = STATUS_SUCCESS;
  2112. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'Cln>',
  2113. OldDeviceHandle, NewDeviceHandle, 0);
  2114. USBPORT_KdPrint((1,"'Cloning Device\n"));
  2115. DEBUG_BREAK();
  2116. LOCK_DEVICE(NewDeviceHandle, FdoDeviceObject);
  2117. // make sure we have two valid device handles
  2118. if (!USBPORT_ValidateDeviceHandle(FdoDeviceObject,
  2119. OldDeviceHandle,
  2120. FALSE)) {
  2121. // this is most likely a bug in the hub
  2122. // driver
  2123. DEBUG_BREAK();
  2124. UNLOCK_DEVICE(NewDeviceHandle, FdoDeviceObject);
  2125. // chances are that the device handle is bad becuse the
  2126. // device is gone.
  2127. return STATUS_DEVICE_NOT_CONNECTED;
  2128. }
  2129. if (!USBPORT_ValidateDeviceHandle(FdoDeviceObject,
  2130. NewDeviceHandle,
  2131. FALSE)) {
  2132. // this is most likely a bug in the hub
  2133. // driver
  2134. DEBUG_BREAK();
  2135. UNLOCK_DEVICE(NewDeviceHandle, FdoDeviceObject);
  2136. // chances are that the device handle is bad becuse the
  2137. // device is gone.
  2138. return STATUS_DEVICE_NOT_CONNECTED;
  2139. }
  2140. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'Cln+',
  2141. OldDeviceHandle, NewDeviceHandle, 0);
  2142. // There are two cases where this API is called:
  2143. // case 1 - the device driver has requested a reset of the device.
  2144. // In this event the device has returned to the unconfigured state
  2145. // and has been re-addressed with the 'NewDeviceHandle'
  2146. //
  2147. // case 2 - the controller has been shut off -- thanks to power
  2148. // management. In this case the device is also in the unconfigured
  2149. // state and associated with the 'NewDeviceHandle' device handle
  2150. // make sure the 'new device' is unconfigured
  2151. USBPORT_ASSERT(NewDeviceHandle->ConfigurationHandle == NULL);
  2152. #ifdef XPSE
  2153. // before performing the clone operation remove the device handle
  2154. // and wait for any pending URBs to drain
  2155. USBPORT_RemoveDeviceHandle(FdoDeviceObject,
  2156. OldDeviceHandle);
  2157. USBPORT_AbortAllTransfers(FdoDeviceObject,
  2158. OldDeviceHandle);
  2159. // wait for any refs from non-transfer URBs to drain
  2160. while (InterlockedDecrement(&OldDeviceHandle->PendingUrbs) >= 0) {
  2161. LOGENTRY(NULL,
  2162. FdoDeviceObject, LOG_PNP, 'dPR2', OldDeviceHandle, 0,
  2163. OldDeviceHandle->PendingUrbs);
  2164. InterlockedIncrement(&OldDeviceHandle->PendingUrbs);
  2165. USBPORT_Wait(FdoDeviceObject, 100);
  2166. }
  2167. #endif
  2168. // make sure we are dealing with the same device
  2169. if (RtlCompareMemory(&NewDeviceHandle->DeviceDescriptor,
  2170. &OldDeviceHandle->DeviceDescriptor,
  2171. sizeof(OldDeviceHandle->DeviceDescriptor)) !=
  2172. sizeof(OldDeviceHandle->DeviceDescriptor)) {
  2173. ntStatus = STATUS_UNSUCCESSFUL;
  2174. goto USBPORT_CloneDevice_FreeOldDevice;
  2175. }
  2176. // clone the config
  2177. NewDeviceHandle->ConfigurationHandle =
  2178. OldDeviceHandle->ConfigurationHandle;
  2179. if (OldDeviceHandle->ConfigurationHandle != NULL) {
  2180. // set the device to the previous configuration,
  2181. // Send the 'set configuration' command.
  2182. USBPORT_INIT_SETUP_PACKET(setupPacket,
  2183. USB_REQUEST_SET_CONFIGURATION, // bRequest
  2184. BMREQUEST_HOST_TO_DEVICE, // Dir
  2185. BMREQUEST_TO_DEVICE, // Recipient
  2186. BMREQUEST_STANDARD, // Type
  2187. NewDeviceHandle->ConfigurationHandle->\
  2188. ConfigurationDescriptor->bConfigurationValue, // wValue
  2189. 0, // wIndex
  2190. 0); // wLength
  2191. USBPORT_SendCommand(NewDeviceHandle,
  2192. FdoDeviceObject,
  2193. &setupPacket,
  2194. NULL,
  2195. 0,
  2196. NULL,
  2197. &usbdStatus);
  2198. USBPORT_KdPrint((2,"' SendCommand, SetConfiguration returned 0x%x\n", usbdStatus));
  2199. if (USBD_ERROR(usbdStatus)) {
  2200. USBPORT_KdPrint((1, "failed to 'set' the configuration on a clone\n"));
  2201. //
  2202. // the set_config failed, this can happen if the device has been
  2203. // removed or if the device has lost its brains.
  2204. // We continue with the cloning process for the endpoints so they
  2205. // will be properly freed when the 'new' device handle is
  2206. // eventually removed.
  2207. //
  2208. ntStatus = SET_USBD_ERROR(NULL, usbdStatus);
  2209. }
  2210. }
  2211. // clone any alternate interface settings, since we restore the pipes to
  2212. // the state at the time of hibernate they may be associated with
  2213. // particular alternate interfaces
  2214. // walk the interface chain
  2215. if (OldDeviceHandle->ConfigurationHandle != NULL &&
  2216. NT_SUCCESS(ntStatus)) {
  2217. PUSBD_CONFIG_HANDLE cfgHandle;
  2218. PLIST_ENTRY listEntry;
  2219. PUSBD_INTERFACE_HANDLE_I iHandle;
  2220. cfgHandle = NewDeviceHandle->ConfigurationHandle;
  2221. GET_HEAD_LIST(cfgHandle->InterfaceHandleList, listEntry);
  2222. while (listEntry &&
  2223. listEntry != &cfgHandle->InterfaceHandleList) {
  2224. // extract the handle from this entry
  2225. iHandle = (PUSBD_INTERFACE_HANDLE_I) CONTAINING_RECORD(
  2226. listEntry,
  2227. struct _USBD_INTERFACE_HANDLE_I,
  2228. InterfaceLink);
  2229. ASSERT_INTERFACE(iHandle);
  2230. // see if we currently have an alt setting selected
  2231. if (iHandle->HasAlternateSettings) {
  2232. NTSTATUS status;
  2233. //
  2234. // If we have alternate settings we need
  2235. // to send the set interface command.
  2236. //
  2237. USBPORT_INIT_SETUP_PACKET(setupPacket,
  2238. USB_REQUEST_SET_INTERFACE, // bRequest
  2239. BMREQUEST_HOST_TO_DEVICE, // Dir
  2240. BMREQUEST_TO_INTERFACE, // Recipient
  2241. BMREQUEST_STANDARD, // Type
  2242. iHandle->InterfaceDescriptor.bAlternateSetting, // wValue
  2243. iHandle->InterfaceDescriptor.bInterfaceNumber, // wIndex
  2244. 0); // wLength
  2245. status = USBPORT_SendCommand(NewDeviceHandle,
  2246. FdoDeviceObject,
  2247. &setupPacket,
  2248. NULL,
  2249. 0,
  2250. NULL,
  2251. &usbdStatus);
  2252. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'sIF2',
  2253. 0,
  2254. iHandle->InterfaceDescriptor.bAlternateSetting,
  2255. iHandle->InterfaceDescriptor.bInterfaceNumber);
  2256. }
  2257. listEntry = iHandle->InterfaceLink.Flink;
  2258. }
  2259. }
  2260. // clone the TT and TT related data
  2261. if (TEST_FLAG(NewDeviceHandle->DeviceFlags, USBPORT_DEVICEFLAG_HSHUB)) {
  2262. // remove the TT entries from the old handle and add them
  2263. // to the new handle
  2264. while (!IsListEmpty(&OldDeviceHandle->TtList)) {
  2265. PTRANSACTION_TRANSLATOR tt;
  2266. PLIST_ENTRY listEntry;
  2267. listEntry = RemoveTailList(&OldDeviceHandle->TtList);
  2268. USBPORT_ASSERT(listEntry != NULL);
  2269. tt = (PTRANSACTION_TRANSLATOR) CONTAINING_RECORD(
  2270. listEntry,
  2271. struct _TRANSACTION_TRANSLATOR,
  2272. TtLink);
  2273. ASSERT_TT(tt);
  2274. tt->DeviceAddress = NewDeviceHandle->DeviceAddress;
  2275. InsertHeadList(&NewDeviceHandle->TtList, &tt->TtLink);
  2276. }
  2277. NewDeviceHandle->TtCount = OldDeviceHandle->TtCount;
  2278. }
  2279. // copy the pipe handle list, for each pipe we will need to re-open
  2280. // the endpoint or re-init the endpoint.
  2281. //
  2282. // if the device did not loose its brains then all we need to do
  2283. // is update the host controllers idea of what the endpoint address is.
  2284. // this has the added advantage of allowing a reset even when transfers
  2285. // are queued to the HW although we don't allow that.
  2286. while (!IsListEmpty(&OldDeviceHandle->PipeHandleList)) {
  2287. PHCD_ENDPOINT endpoint;
  2288. PLIST_ENTRY listEntry = OldDeviceHandle->PipeHandleList.Flink;
  2289. PUSBD_PIPE_HANDLE_I pipeHandle;
  2290. PTRANSACTION_TRANSLATOR transactionTranslator = NULL;
  2291. // see if we are dealing with a TT
  2292. if (NewDeviceHandle->Tt != NULL) {
  2293. transactionTranslator = NewDeviceHandle->Tt;
  2294. ASSERT_TT(transactionTranslator);
  2295. }
  2296. pipeHandle = (PUSBD_PIPE_HANDLE_I) CONTAINING_RECORD(
  2297. listEntry,
  2298. struct _USBD_PIPE_HANDLE_I,
  2299. ListEntry);
  2300. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'CLNE', pipeHandle, 0, 0);
  2301. ASSERT_PIPE_HANDLE(pipeHandle);
  2302. USBPORT_RemovePipeHandle(OldDeviceHandle,
  2303. pipeHandle);
  2304. // we need to special case the default pipe because it
  2305. // is embedded in the DeviceHandle.
  2306. //
  2307. // Since NewDeviceHandle is a newly created device
  2308. // the endpoint associated with it is valid, so is
  2309. // the one for the 'OldDeviceHandle'
  2310. if (pipeHandle != &OldDeviceHandle->DefaultPipe) {
  2311. USB_MINIPORT_STATUS mpStatus;
  2312. USBPORT_AddPipeHandle(NewDeviceHandle, pipeHandle);
  2313. // skip re-init for sero bw endpoints becuase we have
  2314. // no endpoint structure -- these are ghost endpoints
  2315. if (!TEST_FLAG(pipeHandle->PipeStateFlags, USBPORT_PIPE_ZERO_BW)) {
  2316. endpoint = pipeHandle->Endpoint;
  2317. ASSERT_ENDPOINT(endpoint);
  2318. endpoint->DeviceHandle = NewDeviceHandle;
  2319. endpoint->Parameters.DeviceAddress =
  2320. NewDeviceHandle->DeviceAddress;
  2321. if (TEST_FLAG(endpoint->Flags, EPFLAG_NUKED)) {
  2322. // re-open
  2323. ENDPOINT_REQUIREMENTS requirements;
  2324. if (transactionTranslator != NULL) {
  2325. endpoint->Parameters.TtDeviceAddress =
  2326. transactionTranslator->DeviceAddress;
  2327. }
  2328. // call open request to minport, all the endpoint
  2329. // structures are still valid we just need to re-add
  2330. // it to the schedule.
  2331. RtlZeroMemory(&endpoint->MiniportEndpointData[0],
  2332. REGISTRATION_PACKET(devExt).EndpointDataSize);
  2333. RtlZeroMemory(endpoint->Parameters.CommonBufferVa,
  2334. endpoint->Parameters.CommonBufferBytes);
  2335. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'clRO', pipeHandle,
  2336. endpoint, 0);
  2337. // query requirements (although they should not change)
  2338. // just in case the miniport does some initialization here
  2339. MP_QueryEndpointRequirements(devExt,
  2340. endpoint, &requirements);
  2341. MP_OpenEndpoint(devExt, endpoint, mpStatus);
  2342. // in this UNIQUE situation this API is not allowed
  2343. // (and should not) fail
  2344. USBPORT_ASSERT(mpStatus == USBMP_STATUS_SUCCESS);
  2345. CLEAR_FLAG(endpoint->Flags, EPFLAG_NUKED);
  2346. // gone flag is set when we abort transfers
  2347. CLEAR_FLAG(endpoint->Flags, EPFLAG_DEVICE_GONE);
  2348. // we need to sync the endpoint state with
  2349. // the miniport, when first opened the miniport
  2350. // puts the endpoint in status HALT.
  2351. ACQUIRE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'LeK0');
  2352. // initialize endpoint state machine
  2353. //if (endpoint->CurrentStatus == ENDPOINT_STATUS_RUN) {
  2354. // MP_SetEndpointStatus(devExt, endpoint, ENDPOINT_STATUS_RUN);
  2355. //}
  2356. if (endpoint->CurrentState == ENDPOINT_ACTIVE) {
  2357. MP_SetEndpointState(devExt, endpoint, ENDPOINT_ACTIVE);
  2358. }
  2359. RELEASE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'UeK0');
  2360. } else {
  2361. // if this device has an associated TT then
  2362. // we will need to do a little more here
  2363. if (transactionTranslator != NULL) {
  2364. endpoint->Parameters.TtDeviceAddress =
  2365. transactionTranslator->DeviceAddress;
  2366. }
  2367. // this endpoint is already in the schedule,
  2368. // poke-it with the new address.
  2369. MP_PokeEndpoint(devExt, endpoint, mpStatus);
  2370. // in this UNIQUE situation this API is not allowed
  2371. // (and should not) fail
  2372. USBPORT_ASSERT(mpStatus == USBMP_STATUS_SUCCESS);
  2373. // The endpoint on the device should have had its data
  2374. // toggle reset back to Data0 so reset the data toggle
  2375. // on the host endpoint to match.
  2376. //
  2377. MP_SetEndpointDataToggle(devExt, endpoint, 0);
  2378. // clear halt status
  2379. MP_SetEndpointStatus(devExt, endpoint, ENDPOINT_STATUS_RUN);
  2380. }
  2381. }
  2382. }
  2383. }
  2384. // the pipes and config have been cloned, the final step is to free the
  2385. // 'OldDeviceData' ie the old handle.
  2386. // put the old 'default' pipe back on the list before
  2387. // we close it
  2388. USBPORT_AddPipeHandle(OldDeviceHandle,
  2389. &OldDeviceHandle->DefaultPipe);
  2390. USBPORT_CloneDevice_FreeOldDevice:
  2391. #ifndef XPSE
  2392. USBPORT_RemoveDeviceHandle(FdoDeviceObject,
  2393. OldDeviceHandle);
  2394. USBPORT_AbortAllTransfers(FdoDeviceObject,
  2395. OldDeviceHandle);
  2396. #endif
  2397. // we should aways have a default pipe, this will free
  2398. // the endpoint
  2399. USBPORT_ClosePipe(OldDeviceHandle,
  2400. FdoDeviceObject,
  2401. &OldDeviceHandle->DefaultPipe);
  2402. if (OldDeviceHandle->DeviceAddress != USB_DEFAULT_DEVICE_ADDRESS) {
  2403. USBPORT_FreeUsbAddress(FdoDeviceObject, OldDeviceHandle->DeviceAddress);
  2404. }
  2405. UNLOCK_DEVICE(NewDeviceHandle, FdoDeviceObject);
  2406. FREE_POOL(FdoDeviceObject, OldDeviceHandle);
  2407. return ntStatus;
  2408. }
  2409. PTRANSACTION_TRANSLATOR
  2410. USBPORT_GetTt(
  2411. PDEVICE_OBJECT FdoDeviceObject,
  2412. PUSBD_DEVICE_HANDLE HubDeviceHandle,
  2413. PUSHORT PortNumber
  2414. )
  2415. /*++
  2416. Routine Description:
  2417. Walk upstream until we find the first high speed device
  2418. Arguments:
  2419. Return Value:
  2420. ttDeviceAddress
  2421. --*/
  2422. {
  2423. PDEVICE_EXTENSION devExt;
  2424. PTRANSACTION_TRANSLATOR tt = NULL;
  2425. PLIST_ENTRY listEntry;
  2426. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2427. ASSERT_FDOEXT(devExt);
  2428. do {
  2429. if (HubDeviceHandle->DeviceSpeed == UsbHighSpeed) {
  2430. if (HubDeviceHandle->TtCount > 1) {
  2431. GET_HEAD_LIST(HubDeviceHandle->TtList, listEntry);
  2432. while (listEntry != NULL &&
  2433. listEntry != &HubDeviceHandle->TtList) {
  2434. tt = (PTRANSACTION_TRANSLATOR) CONTAINING_RECORD(
  2435. listEntry,
  2436. struct _TRANSACTION_TRANSLATOR,
  2437. TtLink);
  2438. ASSERT_TT(tt);
  2439. if (tt->Port == *PortNumber) {
  2440. break;
  2441. }
  2442. listEntry = tt->TtLink.Flink;
  2443. tt = NULL;
  2444. }
  2445. } else {
  2446. // single TT, use the one tt structure regardless of port
  2447. GET_HEAD_LIST(HubDeviceHandle->TtList, listEntry);
  2448. tt = (PTRANSACTION_TRANSLATOR) CONTAINING_RECORD(
  2449. listEntry,
  2450. struct _TRANSACTION_TRANSLATOR,
  2451. TtLink);
  2452. ASSERT_TT(tt);
  2453. }
  2454. // we should have selected a tt
  2455. USBPORT_ASSERT(tt != NULL);
  2456. break;
  2457. } else {
  2458. *PortNumber = HubDeviceHandle->TtPortNumber;
  2459. }
  2460. HubDeviceHandle = HubDeviceHandle->HubDeviceHandle;
  2461. ASSERT_DEVICE_HANDLE(HubDeviceHandle);
  2462. } while (HubDeviceHandle != NULL);
  2463. USBPORT_KdPrint((1, "TtPortNumber %d\n",
  2464. *PortNumber));
  2465. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'gTTa', HubDeviceHandle,
  2466. *PortNumber, tt);
  2467. return tt;
  2468. }
  2469. NTSTATUS
  2470. USBPORT_InitializeTT(
  2471. PDEVICE_OBJECT FdoDeviceObject,
  2472. PUSBD_DEVICE_HANDLE HubDeviceHandle,
  2473. USHORT Port
  2474. )
  2475. /*++
  2476. Routine Description:
  2477. Initialze the TT table used to track this hub
  2478. Arguments:
  2479. Return Value:
  2480. nt status code
  2481. --*/
  2482. {
  2483. PDEVICE_EXTENSION devExt;
  2484. PTRANSACTION_TRANSLATOR transactionTranslator;
  2485. USHORT siz;
  2486. extern ULONG USB2LIB_TtContextSize;
  2487. NTSTATUS ntStatus;
  2488. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2489. ASSERT_FDOEXT(devExt);
  2490. USBPORT_ASSERT(USBPORT_IS_USB20(devExt));
  2491. siz = sizeof(TRANSACTION_TRANSLATOR) +
  2492. USB2LIB_TtContextSize;
  2493. ALLOC_POOL_Z(transactionTranslator, NonPagedPool, siz);
  2494. if (transactionTranslator != NULL) {
  2495. ULONG i;
  2496. ULONG bandwidth;
  2497. transactionTranslator->Sig = SIG_TT;
  2498. transactionTranslator->DeviceAddress =
  2499. HubDeviceHandle->DeviceAddress;
  2500. transactionTranslator->Port = Port;
  2501. transactionTranslator->PdoDeviceObject =
  2502. devExt->Fdo.RootHubPdo;
  2503. // each translator is a virtual 1.1 bus
  2504. transactionTranslator->TotalBusBandwidth =
  2505. USB_11_BUS_BANDWIDTH;
  2506. InitializeListHead(&transactionTranslator->EndpointList);
  2507. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  2508. transactionTranslator->BandwidthTable[i] =
  2509. transactionTranslator->TotalBusBandwidth -
  2510. transactionTranslator->TotalBusBandwidth/10;
  2511. }
  2512. // reserve the basic 10% from the parent bus
  2513. USBPORT_UpdateAllocatedBwTt(transactionTranslator);
  2514. // alloc new
  2515. bandwidth = transactionTranslator->MaxAllocedBw;
  2516. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  2517. devExt->Fdo.BandwidthTable[i] -= bandwidth;
  2518. }
  2519. USB2LIB_InitTt(devExt->Fdo.Usb2LibHcContext,
  2520. &transactionTranslator->Usb2LibTtContext);
  2521. InsertTailList(&HubDeviceHandle->TtList,
  2522. &transactionTranslator->TtLink);
  2523. ntStatus = STATUS_SUCCESS;
  2524. } else {
  2525. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2526. }
  2527. return ntStatus;
  2528. }