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

2477 lines
69 KiB

  1. /*++
  2. Copyright (c) 1995,1996 Microsoft Corporation
  3. :ts=4
  4. Module Name:
  5. urb.c
  6. Abstract:
  7. The module manages transactions on the USB.
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. 11-01-95 : created
  13. 04-28-96 : linked urb support & cancel support
  14. --*/
  15. #include "wdm.h"
  16. #include "stdarg.h"
  17. #include "stdio.h"
  18. #include "usbdi.h"
  19. #include "hcdi.h"
  20. #include "uhcd.h"
  21. #define COMPUTE_HCD_EXTENSION_SIZE(urb) (sizeof(HCD_EXTENSION) + \
  22. (urb->HcdUrbCommonTransfer.TransferBufferLength / PAGE_SIZE + 1) \
  23. * sizeof(UHCD_LOGICAL_ADDRESS))
  24. #define UHCD_IS_TRANSFER(urb) (((urb)->UrbHeader.Function == URB_FUNCTION_CONTROL_TRANSFER || \
  25. (urb)->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER ||\
  26. (urb)->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER) \
  27. ? TRUE : FALSE)
  28. // calc the maxrequests based on endpoint type nad
  29. // flag options
  30. UCHAR
  31. MAX_REQUESTS(
  32. IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
  33. IN ULONG EpFlags
  34. )
  35. {
  36. if (EpFlags & EPFLAG_DBL_BUFFER) {
  37. return 1;
  38. }
  39. switch (USB_ENDPOINT_TYPE_MASK &
  40. EndpointDescriptor->bmAttributes) {
  41. case USB_ENDPOINT_TYPE_BULK:
  42. return 2;
  43. //return 1;
  44. case USB_ENDPOINT_TYPE_ISOCHRONOUS:
  45. return 3;
  46. default:
  47. return 1;
  48. }
  49. }
  50. #if 0
  51. ULONG
  52. UHCD_CountPageCrossings(
  53. IN ULONG MaxRequests,
  54. IN ULONG MaxTransferSize
  55. )
  56. /*++
  57. Routine Description:
  58. Completes an I/O Request
  59. Arguments:
  60. Return Value:
  61. maximum number of possible page crossings
  62. --*/
  63. {
  64. ULONG pageCrossings;
  65. pageCrossings = (MaxTransferSize + PAGE_SIZE) / PAGE_SIZE;
  66. if (MaxRequests>1) {
  67. pageCrossings *= 2;
  68. }
  69. // now allocate space for packet buffers
  70. UHCD_KdPrint((2, "'UHCD_CountPageCrossings, max transfer size 0x%x -- page crossings = 0x%x\n",
  71. MaxTransferSize, pageCrossings));
  72. UHCD_ASSERT(pageCrossings > 0);
  73. return pageCrossings;
  74. }
  75. #endif
  76. VOID
  77. UHCD_CompleteIrp(
  78. IN PDEVICE_OBJECT DeviceObject,
  79. IN PIRP Irp,
  80. IN NTSTATUS ntStatus,
  81. IN ULONG Information,
  82. IN PHCD_URB Urb
  83. )
  84. /*++
  85. Routine Description:
  86. Completes an I/O Request
  87. Arguments:
  88. DeviceObject - pointer to a device object
  89. Irp - pointer to an I/O Request Packet to complete
  90. ntStatus - status code to set int the IRP when completed
  91. Information -
  92. Urb - root transfer urb if this Irp is associated with
  93. a transfer.
  94. Return Value:
  95. --*/
  96. {
  97. KIRQL irql;
  98. UCHAR flags = 0;
  99. STARTPROC("cIrp");
  100. UHCD_KdPrint((2, "'UHCD_CompleteIrp status = %x\n", ntStatus));
  101. LOGENTRY(LOG_MISC, 'ICan', Urb, 0, Irp);
  102. if (Urb) {
  103. //
  104. // if we have any working space free it now
  105. //
  106. if (UHCD_IS_TRANSFER(Urb) && HCD_AREA(Urb).HcdExtension) {
  107. PHCD_EXTENSION urbWork;
  108. urbWork = HCD_AREA(Urb).HcdExtension;
  109. // remember the flags
  110. flags = urbWork->Flags;
  111. RETHEAP(HCD_AREA(Urb).HcdExtension);
  112. HCD_AREA(Urb).HcdExtension = NULL;
  113. }
  114. //
  115. // Decrement the urb counter that we keep in our stack location for
  116. // the irp, when it goes to zero -- complete it
  117. //
  118. //
  119. // one Urb completed
  120. //
  121. DECREMENT_PENDING_URB_COUNT(Irp);
  122. if (PENDING_URB_COUNT(Irp)) {
  123. //
  124. // stall completion until all Urbs are done.
  125. //
  126. TEST_TRAP();
  127. return;
  128. } else {
  129. IoAcquireCancelSpinLock(&irql);
  130. if (Irp->Cancel) {
  131. LOGENTRY(LOG_MISC, 'irpX', flags, 0, Irp);
  132. // note that the cancel routine will only mess
  133. // with the urbs on the active list -- any active
  134. // urbs should have been removed from the active
  135. // list before calling this routine
  136. //
  137. // Irp associated with this transfer has
  138. // been canceled.
  139. //
  140. // The cancel routine will complete the Irp
  141. // unless there are active transfers.
  142. //
  143. if (flags & UHCD_TRANSFER_ACTIVE) {
  144. IoSetCancelRoutine(Irp, NULL);
  145. IoReleaseCancelSpinLock(irql);
  146. //
  147. // if the io has already started the we must
  148. // complete the Irp with STATUS_CANCELLED here.
  149. //
  150. ntStatus = STATUS_CANCELLED;
  151. Information = 0;
  152. goto UHCD_CompleteIrp_CompleteRequest;
  153. }
  154. IoReleaseCancelSpinLock(irql);
  155. return;
  156. } else {
  157. //
  158. // Irp is no longer cancelable
  159. //
  160. LOGENTRY(LOG_MISC, 'NCan', flags, 0, Irp);
  161. IoSetCancelRoutine(Irp, NULL);
  162. IoReleaseCancelSpinLock(irql);
  163. //
  164. // Pending bit should be cleared
  165. //
  166. UHCD_ASSERT(!USBD_PENDING(Urb->HcdUrbCommonTransfer.Status));
  167. }
  168. }
  169. }
  170. UHCD_CompleteIrp_CompleteRequest:
  171. Irp->IoStatus.Status = ntStatus;
  172. Irp->IoStatus.Information = Information;
  173. LOGENTRY(LOG_MISC, 'irpC', Irp, DeviceObject, Urb);
  174. USBD_CompleteRequest(Irp,
  175. IO_NO_INCREMENT);
  176. ENDPROC("cIrp");
  177. }
  178. NTSTATUS
  179. UHCD_URB_Dispatch(
  180. IN PDEVICE_OBJECT DeviceObject,
  181. IN PIRP Irp
  182. )
  183. /*++
  184. Routine Description:
  185. Process URBs from the dispatch routine.
  186. Arguments:
  187. DeviceObject - pointer to a device object
  188. Irp - pointer to an I/O Request Packet
  189. Return Value:
  190. --*/
  191. {
  192. PHCD_URB urb;
  193. NTSTATUS ntStatus = STATUS_SUCCESS;
  194. PDEVICE_EXTENSION deviceExtension;
  195. PUHCD_ENDPOINT endpoint = NULL;
  196. ULONG siz, cnt;
  197. ULONG numTDs;
  198. UHCD_KdPrint((2, "'enter UHCD_URB_Dispatch \n"));
  199. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  200. urb = (PHCD_URB) URB_FROM_IRP(Irp);
  201. if (deviceExtension->CurrentDevicePowerState != PowerDeviceD0 ||
  202. deviceExtension->HcFlags & HCFLAG_HCD_SHUTDOWN) {
  203. //
  204. // someone is submitting requests while the
  205. // HC is suspended or OFF, we will just fail them
  206. //
  207. UHCD_KdPrint
  208. ((0, "'Warning: UHCD got a request while not in D0 in shutdown\n"));
  209. ntStatus = STATUS_DEVICE_NOT_READY;
  210. URB_HEADER(urb).Status = USBD_STATUS_REQUEST_FAILED;
  211. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  212. return ntStatus;
  213. }
  214. switch(URB_HEADER(urb).Function) {
  215. //
  216. // These commands get queued to the startio routine
  217. // for processing.
  218. //
  219. case URB_FUNCTION_HCD_OPEN_ENDPOINT:
  220. #ifdef ROOT_HUB
  221. if (urb->HcdUrbOpenEndpoint.DeviceAddress ==
  222. deviceExtension->RootHubDeviceAddress) {
  223. // This routine will either complete
  224. // the irp or mark it pending.
  225. ntStatus = UHCD_RootHub_OpenEndpoint(DeviceObject,
  226. Irp,
  227. urb);
  228. break;
  229. }
  230. #endif
  231. //
  232. // Grow the common buffer pool based on how much
  233. // memory we'll need for transfers
  234. //
  235. // Well need enough for one set of TDs plus
  236. // a common buffer for each possible page crossing
  237. // within a trasnsfer.
  238. // first allocate space for the TDs
  239. // for now use a global value
  240. //
  241. // allocate the endpoint structures here while we are
  242. // at passive level
  243. //
  244. endpoint = (PUHCD_ENDPOINT) GETHEAP(NonPagedPool,
  245. sizeof(UHCD_ENDPOINT));
  246. if (endpoint) {
  247. // start endpoint initialization
  248. RtlZeroMemory(endpoint, sizeof(*endpoint));
  249. endpoint->Sig = SIG_EP;
  250. // check for bulk and iso special options
  251. // we only support double buffering for bulk-IN
  252. // we only support fast iso for iso-OUT
  253. if (urb->HcdUrbOpenEndpoint.HcdEndpointFlags &
  254. USBD_EP_FLAG_DOUBLE_BUFFER) {
  255. if (USB_ENDPOINT_DIRECTION_IN(
  256. urb->HcdUrbOpenEndpoint.EndpointDescriptor->bEndpointAddress)
  257. &&
  258. (USB_ENDPOINT_TYPE_MASK &
  259. urb->HcdUrbOpenEndpoint.EndpointDescriptor->bmAttributes)
  260. ==
  261. USB_ENDPOINT_TYPE_BULK) {
  262. SET_EPFLAG(endpoint, EPFLAG_DBL_BUFFER);
  263. } else { // bugbug error here?
  264. UHCD_KdPrint((1, "'WARNING: Cannot double buffer this endpoint\n"));
  265. }
  266. }
  267. #ifdef FAST_ISO
  268. if (urb->HcdUrbOpenEndpoint.HcdEndpointFlags &
  269. USBD_EP_FLAG_FAST_ISO) {
  270. if (USB_ENDPOINT_DIRECTION_OUT(
  271. urb->HcdUrbOpenEndpoint.EndpointDescriptor->bEndpointAddress)
  272. &&
  273. (USB_ENDPOINT_TYPE_MASK &
  274. urb->HcdUrbOpenEndpoint.EndpointDescriptor->bmAttributes)
  275. ==
  276. USB_ENDPOINT_TYPE_ISOCHRONOUS) {
  277. SET_EPFLAG(endpoint, EPFLAG_FAST_ISO);
  278. } else { // bugbug error here?
  279. UHCD_KdPrint((1, "'WARNING: Cannot fast-iso this endpoint\n"));
  280. }
  281. }
  282. #endif
  283. urb->HcdUrbOpenEndpoint.HcdEndpoint = endpoint;
  284. urb->HcdUrbOpenEndpoint.ScheduleOffset = 0;
  285. numTDs =
  286. endpoint->TDCount = UHCD_GetNumTDsPerEndoint((UCHAR) (USB_ENDPOINT_TYPE_MASK &
  287. urb->HcdUrbOpenEndpoint.EndpointDescriptor->bmAttributes));
  288. UHCD_ASSERT(TD_LIST_SIZE(numTDs) <= UHCD_LARGE_COMMON_BUFFER_SIZE);
  289. if (endpoint->EndpointFlags & EPFLAG_DBL_BUFFER) {
  290. // do the double buffer init
  291. ntStatus = UHCD_InitializeNoDMAEndpoint(DeviceObject,
  292. endpoint);
  293. }
  294. if (NT_SUCCESS(ntStatus)) {
  295. endpoint->MaxRequests =
  296. MAX_REQUESTS(urb->HcdUrbOpenEndpoint.EndpointDescriptor,
  297. endpoint->EndpointFlags);
  298. UHCD_KdPrint((2, "'MaxRequests = %d\n", endpoint->MaxRequests));
  299. // init transfer sequence numbers
  300. endpoint->NextXferId = 0;
  301. endpoint->CurrentXferId = 0;
  302. if (endpoint->EndpointFlags & EPFLAG_FAST_ISO) {
  303. // do the double buffer init
  304. UHCD_KdPrint((1, "'Using Fast ISO for Endpoint\n"));
  305. ntStatus = UHCD_FinishInitializeEndpoint(DeviceObject,
  306. endpoint,
  307. urb->HcdUrbOpenEndpoint.EndpointDescriptor,
  308. urb);
  309. if (NT_SUCCESS(ntStatus)) {
  310. ntStatus = UHCD_InitializeFastIsoEndpoint(DeviceObject,
  311. endpoint);
  312. }
  313. } else {
  314. for (cnt=0; cnt< endpoint->MaxRequests; cnt++) {
  315. if ((UHCD_AllocateHardwareDescriptors(DeviceObject,
  316. &endpoint->HardwareDescriptorList[cnt],
  317. endpoint->TDCount))) {
  318. PUCHAR descriptors;
  319. ULONG i;
  320. descriptors = endpoint->HardwareDescriptorList[cnt]->MemoryDescriptor->VirtualAddress;
  321. // Initialize the queue head for this endpoint
  322. // use the TD on the first list
  323. if (cnt == 0) {
  324. endpoint->QueueHead = (PHW_QUEUE_HEAD) descriptors;
  325. // save our endpoint in the QueueHead
  326. endpoint->QueueHead->Endpoint = endpoint;
  327. }
  328. //
  329. // the TDs we'll need to service this endpoint
  330. //
  331. endpoint->SlotTDList[cnt] = (PUHCD_TD_LIST) (descriptors + sizeof(HW_QUEUE_HEAD));
  332. // BUGBUG possibly move this to allocate TD code
  333. for (i=0; i<= endpoint->TDCount; i++) {
  334. // one time init stuff
  335. // for isoch TDs.
  336. endpoint->SlotTDList[cnt]->TDs[i].Frame = 0;
  337. endpoint->SlotTDList[cnt]->TDs[i].Urb = NULL;
  338. }
  339. } else {
  340. RETHEAP(endpoint);
  341. endpoint = NULL;
  342. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  343. break;
  344. }
  345. } // for
  346. // point to first list
  347. if (endpoint) {
  348. endpoint->TDList = endpoint->SlotTDList[0];
  349. }
  350. }
  351. }
  352. } else {
  353. // failed to alloc endpoint structure
  354. UHCD_KdTrap(("UHCD failed to alloc endpoint structure\n"));
  355. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  356. }
  357. #if DBG
  358. UHCD_KdPrint((2, "'Open Endpoint, max transfer size 0x%x \n",
  359. urb->HcdUrbOpenEndpoint.MaxTransferSize));
  360. // transfers >64k are valid
  361. // if (urb->HcdUrbOpenEndpoint.MaxTransferSize >
  362. // 1024*64) {
  363. // // bigger than 64k, probably a bug.
  364. // UHCD_KdPrint((2, "'Open Endpoint, max transfer size 0x%x \n",
  365. // urb->HcdUrbOpenEndpoint.MaxTransferSize));
  366. // TEST_TRAP();
  367. // }
  368. #endif
  369. if (NT_SUCCESS(ntStatus)) {
  370. //
  371. // take the opportunity to grow our pool
  372. // in necessary
  373. //
  374. // BUGBUG possibly use max_packet size as a hint
  375. UHCD_MoreCommonBuffers(DeviceObject);
  376. URB_HEADER(urb).Status = UHCD_STATUS_PENDING_STARTIO;
  377. ntStatus = STATUS_PENDING;
  378. UHCD_KdPrint((2, "'Queue Irp To StartIo\n"));
  379. Irp->IoStatus.Status = ntStatus;
  380. Irp->IoStatus.Information = 0;
  381. IoMarkIrpPending(Irp);
  382. IoStartPacket(DeviceObject,
  383. Irp,
  384. 0,
  385. UHCD_StartIoCancel);
  386. } else {
  387. URB_HEADER(urb).Status = USBD_STATUS_NO_MEMORY;
  388. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  389. }
  390. break;
  391. case URB_FUNCTION_CONTROL_TRANSFER:
  392. case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
  393. // this will activate the rolover interrupts
  394. deviceExtension->XferIdleTime = 0;
  395. case URB_FUNCTION_HCD_CLOSE_ENDPOINT:
  396. if (URB_HEADER(urb).Function == URB_FUNCTION_HCD_CLOSE_ENDPOINT) {
  397. endpoint = urb->HcdUrbCloseEndpoint.HcdEndpoint;
  398. ASSERT_ENDPOINT(endpoint);
  399. } else {
  400. //#if DBG
  401. // UHCD_KdPrint((2, "'originalTransfer Buffer = 0x%x \n",
  402. // urb->HcdUrbCommonTransfer.TransferBuffer));
  403. // // Trash the TransferBuffer field - we only use MDLs
  404. // urb->HcdUrbCommonTransfer.TransferBuffer = (PVOID)-1;
  405. //#endif
  406. // allocate some working space and attach it to
  407. // this urb
  408. endpoint = HCD_AREA(urb).HcdEndpoint;
  409. ASSERT_ENDPOINT(endpoint);
  410. if (urb->HcdUrbCommonTransfer.TransferBufferLength >
  411. endpoint->MaxTransferSize) {
  412. ntStatus = STATUS_INVALID_PARAMETER;
  413. URB_HEADER(urb).Status = USBD_STATUS_INVALID_PARAMETER;
  414. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  415. break;
  416. }
  417. siz = COMPUTE_HCD_EXTENSION_SIZE(urb);
  418. HCD_AREA(urb).HcdExtension =
  419. GETHEAP(NonPagedPool, siz);
  420. if (HCD_AREA(urb).HcdExtension == NULL) {
  421. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  422. URB_HEADER(urb).Status = USBD_STATUS_NO_MEMORY;
  423. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  424. break;
  425. }
  426. RtlZeroMemory(HCD_AREA(urb).HcdExtension, siz);
  427. }
  428. #ifdef ROOT_HUB
  429. if (endpoint->EndpointFlags & EPFLAG_ROOT_HUB) {
  430. // These routines will either complete
  431. // the irp or mark it pending.
  432. switch (URB_HEADER(urb).Function) {
  433. case URB_FUNCTION_CONTROL_TRANSFER:
  434. ntStatus = UHCD_RootHub_ControlTransfer(DeviceObject,
  435. Irp,
  436. urb);
  437. // note: URB and IRP may be gone
  438. break;
  439. case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
  440. ntStatus = UHCD_RootHub_InterruptTransfer(DeviceObject,
  441. Irp,
  442. urb);
  443. // note: URB and IRP may be gone
  444. break;
  445. case URB_FUNCTION_HCD_CLOSE_ENDPOINT:
  446. ntStatus = UHCD_RootHub_CloseEndpoint(DeviceObject,
  447. Irp,
  448. urb);
  449. break;
  450. default:
  451. //BUGBUG could just complete it with an error
  452. //here
  453. // this is probably a bug in the hub driver
  454. UHCD_KdTrap(("Bogus transfer request to root hub\n"));
  455. }
  456. break;
  457. }
  458. #endif
  459. URB_HEADER(urb).Status = UHCD_STATUS_PENDING_STARTIO;
  460. ntStatus = STATUS_PENDING;
  461. UHCD_KdPrint((2, "'Queue Irp To StartIo\n"));
  462. Irp->IoStatus.Status = ntStatus;
  463. Irp->IoStatus.Information = 0;
  464. IoMarkIrpPending(Irp);
  465. IoStartPacket(DeviceObject,
  466. Irp,
  467. 0,
  468. UHCD_StartIoCancel);
  469. break;
  470. case URB_FUNCTION_ISOCH_TRANSFER:
  471. //
  472. // validate max transfer size
  473. // this will activate the rollover interrupts
  474. UHCD_WakeIdle(DeviceObject);
  475. endpoint = HCD_AREA(urb).HcdEndpoint;
  476. ASSERT_ENDPOINT(endpoint);
  477. // don't ref TDList
  478. endpoint->TDList = (PVOID) -1;
  479. if (urb->HcdUrbCommonTransfer.TransferBufferLength >
  480. endpoint->MaxTransferSize) {
  481. ntStatus = STATUS_INVALID_PARAMETER;
  482. URB_HEADER(urb).Status = USBD_STATUS_INVALID_PARAMETER;
  483. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  484. break;
  485. }
  486. // allocate some working space and attach it to
  487. // this urb
  488. siz = COMPUTE_HCD_EXTENSION_SIZE(urb);
  489. HCD_AREA(urb).HcdExtension =
  490. GETHEAP(NonPagedPool, siz);
  491. if (HCD_AREA(urb).HcdExtension == NULL) {
  492. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  493. URB_HEADER(urb).Status = USBD_STATUS_NO_MEMORY;
  494. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  495. break;
  496. }
  497. RtlZeroMemory(HCD_AREA(urb).HcdExtension, siz);
  498. if (HCD_AREA(urb).HcdExtension == NULL) {
  499. UHCD_KdBreak((2, "'Unable to allocate working space for isoch transfer\n"));
  500. URB_HEADER(urb).Status = USBD_STATUS_NO_MEMORY;
  501. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  502. break;
  503. }
  504. URB_HEADER(urb).Status = UHCD_STATUS_PENDING_STARTIO;
  505. ntStatus = STATUS_PENDING;
  506. UHCD_KdPrint((2, "'Queue Irp To StartIo\n"));
  507. Irp->IoStatus.Status = ntStatus;
  508. Irp->IoStatus.Information = 0;
  509. IoMarkIrpPending(Irp);
  510. #if DBG
  511. {
  512. UHCD_KdPrint((2, "'cf = %x",
  513. UHCD_GetCurrentFrame(DeviceObject)));
  514. }
  515. #endif
  516. if (endpoint->EndpointFlags & EPFLAG_FAST_ISO) {
  517. KIRQL irql;
  518. KeRaiseIrql(DISPATCH_LEVEL, &irql);
  519. UHCD_Transfer_StartIo(DeviceObject, Irp);
  520. KeLowerIrql(irql);
  521. } else {
  522. IoStartPacket(DeviceObject,
  523. Irp,
  524. 0,
  525. UHCD_StartIoCancel);
  526. }
  527. break;
  528. case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER:
  529. // this will activate the rollover interrupts
  530. UHCD_WakeIdle(DeviceObject);
  531. urb->UrbGetCurrentFrameNumber.FrameNumber =
  532. UHCD_GetCurrentFrame(DeviceObject);
  533. LOGENTRY(LOG_MISC, 'gcfR',
  534. Irp, urb, urb->UrbGetCurrentFrameNumber.FrameNumber);
  535. URB_HEADER(urb).Status = USBD_STATUS_SUCCESS;
  536. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  537. break;
  538. case URB_FUNCTION_HCD_GET_ENDPOINT_STATE:
  539. case URB_FUNCTION_HCD_SET_ENDPOINT_STATE:
  540. URB_HEADER(urb).Status = UHCD_STATUS_PENDING_STARTIO;
  541. ntStatus = STATUS_PENDING;
  542. UHCD_KdPrint((2, "'Queue Irp To StartIo\n"));
  543. Irp->IoStatus.Status = ntStatus;
  544. Irp->IoStatus.Information = 0;
  545. IoMarkIrpPending(Irp);
  546. IoStartPacket(DeviceObject,
  547. Irp,
  548. 0,
  549. UHCD_StartIoCancel);
  550. break;
  551. case URB_FUNCTION_HCD_ABORT_ENDPOINT:
  552. endpoint = urb->HcdUrbAbortEndpoint.HcdEndpoint;
  553. ASSERT_ENDPOINT(endpoint);
  554. //
  555. // Mark the endpoint so that we abort all the transfers the
  556. // next time we process it.
  557. //
  558. SET_EPFLAG(endpoint,
  559. EPFLAG_ABORT_PENDING_TRANSFERS | EPFLAG_ABORT_ACTIVE_TRANSFERS);
  560. URB_HEADER(urb).Status = UHCD_STATUS_PENDING_STARTIO;
  561. ntStatus = STATUS_PENDING;
  562. UHCD_KdPrint((2, "'Queue Irp To StartIo\n"));
  563. Irp->IoStatus.Status = ntStatus;
  564. Irp->IoStatus.Information = 0;
  565. IoMarkIrpPending(Irp);
  566. IoStartPacket(DeviceObject,
  567. Irp,
  568. 0,
  569. UHCD_StartIoCancel);
  570. break;
  571. case URB_FUNCTION_SET_FRAME_LENGTH:
  572. {
  573. CHAR sofModify;
  574. //get the current value
  575. sofModify = (CHAR) (READ_PORT_UCHAR(SOF_MODIFY_REG(deviceExtension)));
  576. sofModify += (CHAR) urb->UrbSetFrameLength.FrameLengthDelta;
  577. WRITE_PORT_UCHAR(SOF_MODIFY_REG(deviceExtension), (UCHAR) sofModify);
  578. URB_HEADER(urb).Status = USBD_STATUS_SUCCESS;
  579. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  580. UHCD_KdPrint((2, "'Irp Completed in dispatch\n"));
  581. }
  582. break;
  583. case URB_FUNCTION_GET_FRAME_LENGTH:
  584. {
  585. CHAR sofModify;
  586. //get the current value
  587. sofModify = (CHAR) (READ_PORT_UCHAR(SOF_MODIFY_REG(deviceExtension)));
  588. urb->UrbGetFrameLength.FrameNumber = UHCD_GetCurrentFrame(DeviceObject);
  589. urb->UrbGetFrameLength.FrameLength = UHCD_12MHZ_SOF + sofModify;
  590. URB_HEADER(urb).Status = USBD_STATUS_SUCCESS;
  591. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  592. UHCD_KdPrint((2, "'Irp Completed in dispatch\n"));
  593. }
  594. break;
  595. default:
  596. UHCD_KdPrint((2, "'UHCD_URB_Dispatch -- invalid URB function (%x)\n",
  597. URB_HEADER(urb).Function));
  598. URB_HEADER(urb).Status = USBD_STATUS_INVALID_URB_FUNCTION;
  599. ntStatus = STATUS_INVALID_PARAMETER;
  600. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  601. }
  602. UHCD_KdPrint((2, "'exit UHCD_URB_Dispatch (%x)\n", ntStatus));
  603. return ntStatus;
  604. }
  605. VOID
  606. UHCD_StartIo(
  607. IN PDEVICE_OBJECT DeviceObject,
  608. IN PIRP Irp
  609. )
  610. /*++
  611. Routine Description:
  612. Process URBs from the startIo routine.
  613. Arguments:
  614. DeviceObject - pointer to a device object
  615. Irp - pointer to an I/O Request Packet
  616. Return Value:
  617. --*/
  618. {
  619. PHCD_URB urb;
  620. KIRQL irql;
  621. UHCD_KdPrint((2, "'enter UHCD_StartIo\n"));
  622. //
  623. // see if the Irp was canceled
  624. //
  625. urb = URB_FROM_IRP(Irp);
  626. IoAcquireCancelSpinLock(&irql);
  627. IoSetCancelRoutine(Irp, NULL);
  628. if (Irp->Cancel) {
  629. TEST_TRAP();
  630. Irp->IoStatus.Status = STATUS_CANCELLED;
  631. IoReleaseCancelSpinLock(irql);
  632. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  633. IoStartNextPacket(DeviceObject, FALSE);
  634. } else {
  635. if (UHCD_IS_TRANSFER(urb)) {
  636. IoSetCancelRoutine(Irp, UHCD_TransferCancel);
  637. } else {
  638. IoSetCancelRoutine(Irp, NULL);
  639. }
  640. IoReleaseCancelSpinLock(irql);
  641. switch(URB_HEADER(urb).Function) {
  642. case URB_FUNCTION_HCD_OPEN_ENDPOINT:
  643. UHCD_OpenEndpoint_StartIo(DeviceObject, Irp);
  644. break;
  645. case URB_FUNCTION_HCD_CLOSE_ENDPOINT:
  646. LOGENTRY(LOG_MISC, 'CLEP',
  647. (PUHCD_ENDPOINT)urb->HcdUrbAbortEndpoint.HcdEndpoint, 0,
  648. 0);
  649. UHCD_CloseEndpoint_StartIo(DeviceObject, Irp);
  650. break;
  651. case URB_FUNCTION_ISOCH_TRANSFER:
  652. case URB_FUNCTION_CONTROL_TRANSFER:
  653. case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
  654. UHCD_Transfer_StartIo(DeviceObject, Irp);
  655. break;
  656. case URB_FUNCTION_HCD_ABORT_ENDPOINT:
  657. // walk the pending transfer list, since the
  658. // enpoint is halted no new transfers will
  659. // be dequeued by EndpointWorker and the only
  660. // way to clear the HALT is thru
  661. // GetSetEndpointState_StartIo so it is safe to
  662. // mess with the list.
  663. {
  664. PIRP irp;
  665. PHCD_URB urbtmp;
  666. PUHCD_ENDPOINT endpoint;
  667. PLIST_ENTRY listEntry;
  668. KIRQL irql;
  669. endpoint = (PUHCD_ENDPOINT) urb->HcdUrbAbortEndpoint.HcdEndpoint;
  670. ASSERT_ENDPOINT(endpoint);
  671. UHCD_KdPrint((2, "'Aborting endpoint %x flags = %x\n",
  672. endpoint, endpoint->EndpointFlags));
  673. LOGENTRY(LOG_MISC, 'ABRP', endpoint, 0, 0);
  674. LOCK_ENDPOINT_PENDING_LIST(endpoint, irql, 'lck4');
  675. while (!IsListEmpty(&endpoint->PendingTransferList)) {
  676. listEntry = RemoveHeadList(&endpoint->PendingTransferList);
  677. urbtmp = (PHCD_URB) CONTAINING_RECORD(listEntry,
  678. struct _URB_HCD_COMMON_TRANSFER,
  679. hca.HcdListEntry);
  680. UNLOCK_ENDPOINT_PENDING_LIST(endpoint, irql, 'ulk4');
  681. UHCD_KdPrint((2, "'Aborting urb = %x\n", urbtmp));
  682. URB_HEADER(urbtmp).Status = USBD_STATUS_CANCELED;
  683. //
  684. // complete the request
  685. //
  686. irp = HCD_AREA(urbtmp).HcdIrp;
  687. LOGENTRY(LOG_MISC, 'ABRc', endpoint, irp, 0);
  688. UHCD_CompleteIrp(DeviceObject,
  689. irp,
  690. STATUS_CANCELLED,
  691. 0,
  692. urbtmp);
  693. LOCK_ENDPOINT_PENDING_LIST(endpoint, irql, 'lck5');
  694. }
  695. UNLOCK_ENDPOINT_PENDING_LIST(endpoint, irql, 'ulk5');
  696. // do cleanup for fast iso
  697. if (endpoint->EndpointFlags & EPFLAG_FAST_ISO) {
  698. ULONG f;
  699. for (f=0; f < FRAME_LIST_SIZE; f++) {
  700. UHCD_CleanupFastIsoTD(DeviceObject,
  701. endpoint,
  702. f,
  703. FALSE);
  704. }
  705. }
  706. }
  707. //
  708. // we have already set the abortPendingTransfers and
  709. // abortActiveTransfers flags in the dispatch
  710. // routine. Now we need to request an interrupt
  711. // so that any active transfers will be cleaned
  712. // up.
  713. //
  714. UHCD_RequestInterrupt(DeviceObject, -2);
  715. IoStartNextPacket(DeviceObject, FALSE);
  716. URB_HEADER(urb).Status = USBD_STATUS_SUCCESS;
  717. UHCD_CompleteIrp(DeviceObject, Irp, STATUS_SUCCESS, 0, NULL);
  718. UHCD_KdPrint((2, "'UHCD Abort Endpoint Request Complete\n"));
  719. break;
  720. case URB_FUNCTION_HCD_GET_ENDPOINT_STATE:
  721. case URB_FUNCTION_HCD_SET_ENDPOINT_STATE:
  722. UHCD_GetSetEndpointState_StartIo(DeviceObject, Irp);
  723. break;
  724. default:
  725. UHCD_KdPrint((2, "'UHCD_URB_StartIo -- invalid URB function (%x)\n", URB_HEADER(urb).Function));
  726. URB_HEADER(urb).Status = USBD_STATUS_INVALID_URB_FUNCTION;
  727. UHCD_CompleteIrp(DeviceObject, Irp, STATUS_SUCCESS, 0, NULL);
  728. }
  729. }
  730. UHCD_KdPrint((2, "'exit UHCD_StartIo\n"));
  731. }
  732. VOID
  733. UHCD_OpenEndpoint_StartIo(
  734. IN PDEVICE_OBJECT DeviceObject,
  735. IN PIRP Irp
  736. )
  737. /*++
  738. Routine Description:
  739. Create a UHCD endpoint, this function is called from UHCD_StartIo to
  740. create a new endpoint structure.
  741. Arguments:
  742. DeviceObject - pointer to a device object
  743. Irp - pointer to an I/O Request Packet
  744. Return Value:
  745. --*/
  746. {
  747. PHCD_URB urb;
  748. PDEVICE_EXTENSION deviceExtension;
  749. PUHCD_ENDPOINT endpoint;
  750. PUSB_ENDPOINT_DESCRIPTOR endpointDescriptor;
  751. KIRQL irql;
  752. NTSTATUS ntStatus;
  753. BOOLEAN haveBW;
  754. ULONG offset;
  755. UHCD_KdPrint((2, "'enter UHCD_OpenEndpoint_StartIo\n"));
  756. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  757. //
  758. // extract a pointer to the URB
  759. //
  760. urb = URB_FROM_IRP(Irp);
  761. //
  762. // make sure the length of the urb is what we expect
  763. //
  764. if (urb->HcdUrbOpenEndpoint.Length != sizeof(struct _URB_HCD_OPEN_ENDPOINT)) {
  765. URB_HEADER(urb).Status = USBD_STATUS_INVALID_PARAMETER;
  766. ntStatus = STATUS_INVALID_PARAMETER;
  767. goto UHCD_OpenEndpoint_StartIo_Done;
  768. }
  769. //
  770. // information about the endpoint comes from the USB endpoint
  771. // descriptor passed in the URB.
  772. //
  773. endpointDescriptor = urb->HcdUrbOpenEndpoint.EndpointDescriptor;
  774. URB_HEADER(urb).Status = USBD_STATUS_SUCCESS;
  775. //
  776. // Allocate resources for the endpoint, this includes an endpoint
  777. // handle that will be passed to us in subsequent transfer requests
  778. //
  779. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  780. endpoint = urb->HcdUrbOpenEndpoint.HcdEndpoint;
  781. UHCD_ASSERT(endpoint != NULL);
  782. ASSERT_ENDPOINT(endpoint);
  783. if (endpoint) {
  784. //
  785. // initialize endpoint structures, state variables, queue head, ...
  786. //
  787. // bugbug -- may not need to call this for fastIiso
  788. ntStatus = UHCD_FinishInitializeEndpoint(DeviceObject,
  789. endpoint,
  790. endpointDescriptor,
  791. urb);
  792. if (!NT_SUCCESS(ntStatus)) {
  793. RETHEAP(endpoint);
  794. goto UHCD_OpenEndpoint_StartIo_Done;
  795. }
  796. UHCD_KdPrint((2, "'Open Endpoint:\n"));
  797. UHCD_KdPrint((2, "'Type = (%d) \n", endpoint->Type));
  798. #if DBG
  799. switch (endpoint->Type) {
  800. case USB_ENDPOINT_TYPE_CONTROL:
  801. UHCD_KdPrint((2, "'-control\n"));
  802. break;
  803. case USB_ENDPOINT_TYPE_ISOCHRONOUS:
  804. UHCD_KdPrint((2, "'-iso\n"));
  805. break;
  806. case USB_ENDPOINT_TYPE_BULK:
  807. UHCD_KdPrint((2, "'-bulk\n"));
  808. break;
  809. case USB_ENDPOINT_TYPE_INTERRUPT:
  810. UHCD_KdPrint((2, "'-interrupt\n"));
  811. }
  812. if (USB_ENDPOINT_DIRECTION_IN(endpointDescriptor->bEndpointAddress)) {
  813. UHCD_KdPrint((2, "'IN\n"));
  814. } else {
  815. UHCD_KdPrint((2, "'OUT\n"));
  816. }
  817. #endif
  818. UHCD_KdPrint((2, "'EP Address = %d\n", endpoint->EndpointAddress));
  819. UHCD_KdPrint((2, "'DEV Address = %d\n", endpoint->DeviceAddress));
  820. UHCD_KdPrint((2, "'MaxPacket = %d\n", endpoint->MaxPacketSize));
  821. UHCD_KdPrint((2, "'Interval: Requested = %d, Selected = %d\n", endpointDescriptor->bInterval,
  822. endpoint->Interval));
  823. //
  824. // Now attempt to allocate the bandwidth we'll need to
  825. // open this endpoint
  826. //
  827. if (endpoint->Type == USB_ENDPOINT_TYPE_INTERRUPT) {
  828. ULONG i;
  829. // check bw available in all locations and
  830. // pick the least loaded frame
  831. offset = 0;
  832. for (i=0; i< endpoint->Interval; i++) {
  833. if (deviceExtension->BwTable[i] > deviceExtension->BwTable[offset]) {
  834. offset = i;
  835. }
  836. }
  837. haveBW = UHCD_AllocateBandwidth(DeviceObject,
  838. endpoint,
  839. offset);
  840. if (!haveBW) {
  841. //
  842. // could not use the least loaded frame, just grab the
  843. // first frame we can fit in.
  844. //
  845. for (offset=0; offset<endpoint->Interval; offset++) {
  846. haveBW = UHCD_AllocateBandwidth(DeviceObject,
  847. endpoint,
  848. offset);
  849. if (haveBW) {
  850. UHCD_KdPrint((2, "'using offset %d\n", offset));
  851. break;
  852. }
  853. }
  854. }
  855. urb->HcdUrbOpenEndpoint.ScheduleOffset = offset;
  856. } else {
  857. offset = 0;
  858. haveBW = UHCD_AllocateBandwidth(DeviceObject,
  859. endpoint,
  860. offset);
  861. }
  862. if (!haveBW) { // no offset
  863. ULONG cnt;
  864. //
  865. // insufficient bandwidth to open this
  866. // endpoint.
  867. //
  868. URB_HEADER(urb).Status = USBD_STATUS_NO_BANDWIDTH;
  869. UHCD_KdPrint((0, "'warning: no bandwidth for endpoint\n"));
  870. for (cnt=0; cnt< endpoint->MaxRequests; cnt++) {
  871. UHCD_FreeHardwareDescriptors(DeviceObject,
  872. endpoint->HardwareDescriptorList[cnt]);
  873. }
  874. RETHEAP(endpoint);
  875. goto UHCD_OpenEndpoint_StartIo_Done;
  876. }
  877. if (endpoint->EndpointFlags & EPFLAG_FAST_ISO) {
  878. goto UHCD_OpenEndpoint_StartIo_Done;
  879. }
  880. //
  881. // put the endpoint in to our list of active endpoints
  882. //
  883. // BUGBUG may want to wait for the first transfer to
  884. // do this.
  885. //
  886. LOCK_ENDPOINT_LIST(deviceExtension, irql);
  887. if (deviceExtension->EndpointListBusy) {
  888. // if the endpoint list is busy we have to put the endpoint
  889. // on a lookaside list so that the ISRDPC can add it later
  890. InsertHeadList(&deviceExtension->EndpointLookAsideList, &endpoint->ListEntry);
  891. } else {
  892. InsertHeadList(&deviceExtension->EndpointList, &endpoint->ListEntry);
  893. }
  894. UNLOCK_ENDPOINT_LIST(deviceExtension, irql);
  895. //
  896. // Put this Queue Head in the Schedule.
  897. //
  898. //
  899. // This routine will insert the queue head in the proper place
  900. // in the schedule and add the endpoint to the endpoint list
  901. // so that completed transfers will be detected.
  902. //
  903. KeAcquireSpinLock(&deviceExtension->HcScheduleSpin, &irql);
  904. UHCD_InsertQueueHeadInSchedule(DeviceObject,
  905. endpoint,
  906. endpoint->QueueHead,
  907. offset); // no offset
  908. // clear the idle flag just in case it got set
  909. CLR_EPFLAG(endpoint, EPFLAG_IDLE);
  910. KeReleaseSpinLock(&deviceExtension->HcScheduleSpin, irql);
  911. //
  912. // return the endpoint handle
  913. //
  914. urb->HcdUrbOpenEndpoint.HcdEndpoint = endpoint;
  915. ntStatus = STATUS_SUCCESS;
  916. } /* if endpoint */
  917. //
  918. // Complete the IRP, status is in the status field of the URB
  919. //
  920. UHCD_KdPrint((2, "'exit UHCD_OpenEndpoint_StartIo (URB STATUS = %x)\n", URB_HEADER(urb).Status ));
  921. UHCD_OpenEndpoint_StartIo_Done:
  922. #if DBG
  923. //
  924. // sanity check our buffer pools
  925. //
  926. // UHCD_BufferPoolCheck(DeviceObject);
  927. #endif
  928. IoStartNextPacket(DeviceObject, FALSE);
  929. UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
  930. return;
  931. }
  932. VOID
  933. UHCD_CloseEndpoint_StartIo(
  934. IN PDEVICE_OBJECT DeviceObject,
  935. IN PIRP Irp
  936. )
  937. /*++
  938. Routine Description:
  939. Free a UHCD endpoint, if there are any pending transfers for this
  940. endpoint this routine should fail.
  941. Arguments:
  942. DeviceObject - pointer to a device object
  943. Irp - pointer to an I/O Request Packet
  944. Return Value:
  945. --*/
  946. {
  947. PHCD_URB urb;
  948. PUHCD_ENDPOINT endpoint;
  949. BOOLEAN outstandingTransfers = FALSE;
  950. PDEVICE_EXTENSION deviceExtension;
  951. ULONG i;
  952. KIRQL irql;
  953. BOOLEAN removed;
  954. UHCD_KdPrint((2, "'enter UHCD_CloseEndpoint_StartIo\n"));
  955. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  956. urb = URB_FROM_IRP(Irp);
  957. endpoint = urb->HcdUrbCloseEndpoint.HcdEndpoint;
  958. ASSERT_ENDPOINT(endpoint);
  959. if (endpoint->EndpointFlags & EPFLAG_FAST_ISO) {
  960. UHCD_UnInitializeFastIsoEndpoint(DeviceObject,
  961. endpoint);
  962. UHCD_FreeBandwidth(DeviceObject, endpoint, endpoint->Offset);
  963. }
  964. //
  965. // if there are any pending transfers fail this request
  966. //
  967. LOCK_ENDPOINT_PENDING_LIST(endpoint, irql, 'lck4');
  968. //
  969. // Do we have any transfers pending?
  970. //
  971. outstandingTransfers = !IsListEmpty(&endpoint->PendingTransferList);
  972. for (i=0; !outstandingTransfers && i < endpoint->MaxRequests; i++) {
  973. //
  974. // no outstanding transfers in the queue, check the active list
  975. // -- if some transfers get retired while we walk the list that
  976. // is OK.
  977. //
  978. if (endpoint->ActiveTransfers[i] != NULL) {
  979. outstandingTransfers = TRUE;
  980. }
  981. }
  982. UNLOCK_ENDPOINT_PENDING_LIST(endpoint, irql, 'ulk4');
  983. if (outstandingTransfers) {
  984. //
  985. // If we have outstanding transfers then we fail the
  986. // request
  987. //
  988. URB_HEADER(urb).Status = USBD_STATUS_ERROR_BUSY;
  989. } else {
  990. //
  991. // Remove the endpoint Queue from the schedule
  992. //
  993. KeAcquireSpinLock(&deviceExtension->HcScheduleSpin, &irql);
  994. removed = UHCD_RemoveQueueHeadFromSchedule(DeviceObject,
  995. endpoint,
  996. endpoint->QueueHead,
  997. TRUE);
  998. KeReleaseSpinLock(&deviceExtension->HcScheduleSpin, irql);
  999. // stop 'NoDMA' transfers
  1000. if (endpoint->EndpointFlags & EPFLAG_DBL_BUFFER) {
  1001. UHCD_StopNoDMATransfer(DeviceObject,
  1002. endpoint);
  1003. }
  1004. //
  1005. // Put the endpoint on a queue to be freed at after
  1006. // the next frame has executed
  1007. //
  1008. // At this point the hardware links have been updated to remove this
  1009. // endpoint.
  1010. //
  1011. // we note the frame when it is safe to retire the endpoint so that
  1012. // the queue head may be freed safely by the ISR DPC routine next time
  1013. // we take an interrupt.
  1014. endpoint->FrameToClose = UHCD_GetCurrentFrame(DeviceObject)+2;
  1015. // BUGBUG this needs to be protected from the ISR DPC
  1016. // routine where these things are actually freed.
  1017. // queue it to be released
  1018. if (removed) {
  1019. InsertTailList(&deviceExtension->ClosedEndpointList, &endpoint->ListEntry);
  1020. }
  1021. URB_HEADER(urb).Status = USBD_STATUS_SUCCESS;
  1022. }
  1023. IoStartNextPacket(DeviceObject, FALSE);
  1024. UHCD_CompleteIrp(DeviceObject, Irp, STATUS_SUCCESS, 0, NULL);
  1025. UHCD_KdPrint((2, "'exit UHCD_CloseEndpoint_StartIo\n"));
  1026. }
  1027. VOID
  1028. UHCD_InsertQueueHeadInSchedule(
  1029. IN PDEVICE_OBJECT DeviceObject,
  1030. IN PUHCD_ENDPOINT Endpoint,
  1031. IN PHW_QUEUE_HEAD QueueHead,
  1032. IN ULONG Offset
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. Inserts an initialized queue head into the schedule
  1037. Queue head schedule looks like this:
  1038. PQH = persistant queue head
  1039. CQH = control Queue Head
  1040. IQH = Interrupt Queue Head
  1041. BQH = Bulk Queue Head
  1042. The persistant queue head software links
  1043. look like this:
  1044. |>---->---->-|
  1045. | <- <- | prev
  1046. BQH PQH CQH
  1047. | -> -> | next
  1048. |<----<----<-|
  1049. IQH->IQH->PQH
  1050. Hardware links look like this:
  1051. PQH->CQH->BQH->| (reclimaton on)
  1052. |-<-|
  1053. or
  1054. PQH->CQH->BQH->| (reclimation off)
  1055. |<-T-| (T BIT SET)
  1056. Iso/Interrupt hardware links:
  1057. ISO->IQH->PQH
  1058. Arguments:
  1059. DeviceObject - device object for this controller.
  1060. Endpoint - endpoint this Queue Head belongs to.
  1061. QueueHead - queue head to insert in schedule.
  1062. Return Value:
  1063. --*/
  1064. {
  1065. PDEVICE_EXTENSION deviceExtension;
  1066. PHW_QUEUE_HEAD persistantQueueHead, queueHeadForFrame,
  1067. nextQueueHead, prevQueueHead;
  1068. #ifdef RECLAIM_BW
  1069. PHW_QUEUE_HEAD firstBulkQueueHead;
  1070. #endif
  1071. ULONG i, interval;
  1072. BOOLEAN fixFrameList = FALSE;
  1073. UHCD_ASSERT(!(Endpoint->EndpointFlags & EPFLAG_ED_IN_SCHEDULE));
  1074. UHCD_KdPrint((2, "'enter InsertQueueHeadInSchedule\n"));
  1075. ASSERT_ENDPOINT(Endpoint);
  1076. ASSERT_QUEUE_HEAD(QueueHead);
  1077. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1078. persistantQueueHead = deviceExtension->PersistantQueueHead;
  1079. switch(Endpoint->Type) {
  1080. case USB_ENDPOINT_TYPE_CONTROL:
  1081. LOGENTRY(LOG_MISC, 'Cep+', Endpoint, 0, DeviceObject);
  1082. //
  1083. // before
  1084. //
  1085. // a b
  1086. // -PQH<->CQH-
  1087. // |---<->---|
  1088. //
  1089. // after
  1090. //
  1091. // a b
  1092. // -PQH<->CQH(new)<->CQH-
  1093. // |-------<->----------|
  1094. //
  1095. // insert in list
  1096. QueueHead->Next = persistantQueueHead->Next; //point to b
  1097. QueueHead->Prev = persistantQueueHead; //point to a
  1098. QueueHead->Next->Prev = QueueHead; // item b points back to new
  1099. // PQH points to the new element
  1100. QueueHead->Prev->Next = QueueHead; // item a points to new
  1101. // Fix up hardware links
  1102. QueueHead->HW_HLink = persistantQueueHead->HW_HLink;
  1103. // we are in the chain just after the Persistant Queue Head
  1104. // this line activates the QH
  1105. persistantQueueHead->HW_HLink =
  1106. QueueHead->PhysicalAddress;
  1107. break;
  1108. case USB_ENDPOINT_TYPE_INTERRUPT:
  1109. LOGENTRY(LOG_MISC, 'Iep+', Endpoint, QueueHead, DeviceObject);
  1110. QueueHead->Next = 0;
  1111. QueueHead->Prev = 0;
  1112. interval = Endpoint->Interval;
  1113. UHCD_ASSERT(Offset < interval);
  1114. UHCD_ASSERT(interval != 0);
  1115. LOGENTRY(LOG_MISC, 'Iep+',
  1116. Endpoint,
  1117. interval,
  1118. &deviceExtension->InterruptSchedule[0]);
  1119. // MAX_INTERVAL is the maximum polling interval we support in UHCD (power of 2).
  1120. // the requested polling intervals is always rounded to the next lowest power of 2.
  1121. // We keep an array (InterruptSchedule) of MAX_INTERVAL with the virtual addresses
  1122. // of the queue heads in the schedule. The size of InterruptSchedule is always a
  1123. // multiple of MAX_FRAME. i.e. InterruptSchedule contains the virtual addresses of
  1124. // queue heads for the first MAX_INTERVAL frames in the schedule.
  1125. UHCD_ASSERT(interval<=MAX_INTERVAL);
  1126. UHCD_ASSERT(Offset<interval);
  1127. UHCD_ASSERT(MAX_INTERVAL % interval == 0);
  1128. for (i=Offset; i<MAX_INTERVAL; i+=interval) {
  1129. // select the queue head
  1130. queueHeadForFrame = deviceExtension->InterruptSchedule[i];
  1131. LOGENTRY(LOG_MISC, 'Iqhf',
  1132. 0, //queueHeadForFrame->Endpoint->Interval,
  1133. queueHeadForFrame,
  1134. i);
  1135. // find the appropriate place to add ourselves
  1136. if (queueHeadForFrame == persistantQueueHead ||
  1137. interval >= queueHeadForFrame->Endpoint->Interval) {
  1138. // if the first entry is the persistant queue head or our polling
  1139. // interval is greater or equal than this queue head then we just
  1140. // add in front of this one, we become the root node for this
  1141. // frame.
  1142. LOGENTRY(LOG_MISC, 'I>SC', 0, QueueHead, i);
  1143. deviceExtension->InterruptSchedule[i] = QueueHead;
  1144. fixFrameList = TRUE;
  1145. if (QueueHead->Next == 0) {
  1146. QueueHead->Next = queueHeadForFrame;
  1147. // update hardware link here
  1148. QueueHead->HW_HLink = queueHeadForFrame->PhysicalAddress;
  1149. } else {
  1150. // ounce the next pointer is updated
  1151. // it should never change
  1152. UHCD_ASSERT(QueueHead->Next == queueHeadForFrame);
  1153. }
  1154. } else {
  1155. // if our polling interval is less than the current queue
  1156. // head we need to insert in the proper position
  1157. LOGENTRY(LOG_MISC, 'I<SC', queueHeadForFrame, QueueHead, i);
  1158. nextQueueHead = queueHeadForFrame;
  1159. do {
  1160. prevQueueHead = nextQueueHead;
  1161. nextQueueHead = nextQueueHead->Next;
  1162. } while (nextQueueHead != persistantQueueHead &&
  1163. nextQueueHead->Endpoint->Interval > interval);
  1164. LOGENTRY(LOG_MISC, 'I<SQ', nextQueueHead,
  1165. QueueHead, prevQueueHead);
  1166. UHCD_ASSERT(nextQueueHead != 0);
  1167. // link in to the chain
  1168. if (QueueHead->Next == 0) {
  1169. QueueHead->Next = nextQueueHead;
  1170. // update hardware link here
  1171. QueueHead->HW_HLink = nextQueueHead->PhysicalAddress;
  1172. } else {
  1173. UHCD_ASSERT(QueueHead->Next == nextQueueHead ||
  1174. nextQueueHead == QueueHead);
  1175. }
  1176. prevQueueHead->Next = QueueHead;
  1177. // update hardware link here
  1178. prevQueueHead->HW_HLink = QueueHead->PhysicalAddress;
  1179. }
  1180. //
  1181. // repeat the process until we
  1182. // have visited all possible nodes for this queue head
  1183. //
  1184. }
  1185. // now update the physical frame list based on the virtual list
  1186. // if we have modified it.
  1187. if (fixFrameList) {
  1188. UHCD_CopyInterruptScheduleToFrameList(DeviceObject);
  1189. }
  1190. break;
  1191. case USB_ENDPOINT_TYPE_BULK:
  1192. //
  1193. // before
  1194. //
  1195. // b a
  1196. // -BQH<->PQH-
  1197. // |---<->---|
  1198. //
  1199. // after
  1200. //
  1201. // b a
  1202. // -BQH<->BQH(new)<->PQH-
  1203. // |-------<->----------|
  1204. //
  1205. // We need to add this endpoint to the tail of the
  1206. // persistant queue
  1207. //
  1208. LOGENTRY(LOG_MISC, 'Bep+', Endpoint, 0, DeviceObject);
  1209. // set up queue head fields
  1210. UHCD_KdPrint((2, "'bulk QH = %x, %x\n", QueueHead, Endpoint));
  1211. // insert in list
  1212. QueueHead->Next = persistantQueueHead; // point to a
  1213. QueueHead->Prev = persistantQueueHead->Prev; // point to b
  1214. // first item points back to us
  1215. QueueHead->Prev->Next = QueueHead; // item b points to new
  1216. // head points to the element
  1217. // select the old tail element
  1218. prevQueueHead = persistantQueueHead->Prev; // remember b
  1219. persistantQueueHead->Prev = QueueHead; // item a points to new
  1220. #ifdef RECLAIM_BW
  1221. //
  1222. // Fix up hardware links
  1223. //
  1224. // BUGBUG
  1225. // NOTE: we are only reclaiming bandwidth for bulk right
  1226. // now.
  1227. //
  1228. if (deviceExtension->SteppingVersion == UHCD_B0_STEP) {
  1229. //TEST_TRAP();
  1230. //
  1231. // BW reclimation, point back to the first bulk queue head
  1232. // with no T bit set
  1233. //
  1234. // walk the list and find the first bulk
  1235. // queue head
  1236. firstBulkQueueHead = persistantQueueHead;
  1237. do {
  1238. PUHCD_ENDPOINT endpoint;
  1239. endpoint = firstBulkQueueHead->Endpoint;
  1240. if (endpoint &&
  1241. endpoint->Type == USB_ENDPOINT_TYPE_BULK) {
  1242. break;
  1243. }
  1244. firstBulkQueueHead = firstBulkQueueHead->Next;
  1245. } while (firstBulkQueueHead != persistantQueueHead);
  1246. UHCD_ASSERT(firstBulkQueueHead != persistantQueueHead);
  1247. QueueHead->HW_HLink = firstBulkQueueHead->PhysicalAddress;
  1248. deviceExtension->HcFlags |= HCFLAG_BWRECLIMATION_ENABLED;
  1249. } else {
  1250. // Fix up hardware links
  1251. // points to the control queue head with T bit set
  1252. QueueHead->HW_HLink = prevQueueHead->HW_HLink;
  1253. UHCD_ASSERT(QueueHead->HW_HLink & UHCD_CF_TERMINATE);
  1254. }
  1255. #else
  1256. // Fix up hardware links
  1257. // points to the control queue head with T bit set
  1258. QueueHead->HW_HLink = prevQueueHead->HW_HLink;
  1259. UHCD_ASSERT(QueueHead->HW_HLink & UHCD_CF_TERMINATE);
  1260. #endif
  1261. // we are in the chain just before the PersistantQueueHead
  1262. // this line activates the QH
  1263. prevQueueHead->HW_HLink =
  1264. QueueHead->PhysicalAddress;
  1265. break;
  1266. case USB_ENDPOINT_TYPE_ISOCHRONOUS:
  1267. LOGENTRY(LOG_MISC, 'Sep+', Endpoint, 0, DeviceObject);
  1268. break;
  1269. default:
  1270. // invalid endpoint type, probably a bug
  1271. UHCD_KdTrap(
  1272. ("UHCD_InsertQueueHeadInSchedule inavlid endpoint type\n"));
  1273. }
  1274. SET_EPFLAG(Endpoint, EPFLAG_ED_IN_SCHEDULE);
  1275. UHCD_KdPrint((2, "'exit InsertQueueHeadInSchedule\n"));
  1276. return;
  1277. }
  1278. BOOLEAN
  1279. UHCD_RemoveQueueHeadFromSchedule(
  1280. IN PDEVICE_OBJECT DeviceObject,
  1281. IN PUHCD_ENDPOINT Endpoint,
  1282. IN PHW_QUEUE_HEAD QueueHead,
  1283. IN BOOLEAN RemoveFromEPList
  1284. )
  1285. /*++
  1286. Routine Description:
  1287. Removes a queue head from the schedule
  1288. Arguments:
  1289. DeviceObject - device object for this controller.
  1290. Endpoint - endpoint this Queue Head belongs to.
  1291. QueueHead - queue head to remove.
  1292. Return Value:
  1293. returns TRUE if EP was removed from ep list
  1294. --*/
  1295. {
  1296. PDEVICE_EXTENSION deviceExtension;
  1297. PHW_QUEUE_HEAD persistantQueueHead, queueHeadForFrame,
  1298. nextQueueHead, prevQueueHead;
  1299. BOOLEAN fixFrameList = FALSE;
  1300. ULONG i;
  1301. HW_DESCRIPTOR_PHYSICAL_ADDRESS physicalAddress;
  1302. KIRQL irql;
  1303. BOOLEAN removed = FALSE;
  1304. UHCD_KdPrint((2, "'enter RemoveQueueHeadFromSchedule\n"));
  1305. ASSERT_ENDPOINT(Endpoint);
  1306. if (Endpoint->EndpointFlags & EPFLAG_FAST_ISO) {
  1307. // nothing to remove
  1308. return FALSE;
  1309. }
  1310. ASSERT_QUEUE_HEAD(QueueHead);
  1311. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1312. persistantQueueHead = deviceExtension->PersistantQueueHead;
  1313. //
  1314. // Remove the Queue Head from the endpoint list
  1315. //
  1316. if (RemoveFromEPList) {
  1317. LOCK_ENDPOINT_LIST(deviceExtension, irql);
  1318. if (deviceExtension->EndpointListBusy) {
  1319. // mark the entry so we can remove it later
  1320. SET_EPFLAG(Endpoint, EPFLAG_EP_CLOSED);
  1321. } else {
  1322. RemoveEntryList(&Endpoint->ListEntry);
  1323. removed = TRUE;
  1324. }
  1325. UNLOCK_ENDPOINT_LIST(deviceExtension, irql);
  1326. }
  1327. if (!(Endpoint->EndpointFlags & EPFLAG_ED_IN_SCHEDULE)) {
  1328. LOGENTRY(LOG_MISC, 'NISc', Endpoint, 0, DeviceObject);
  1329. return removed;
  1330. }
  1331. switch(Endpoint->Type) {
  1332. case USB_ENDPOINT_TYPE_CONTROL:
  1333. case USB_ENDPOINT_TYPE_BULK:
  1334. // set up queue head fields
  1335. prevQueueHead = QueueHead->Prev;
  1336. nextQueueHead = QueueHead->Next;
  1337. // unlink software links
  1338. prevQueueHead->Next = QueueHead->Next;
  1339. nextQueueHead->Prev = QueueHead->Prev;
  1340. if ((QueueHead->HW_HLink & UHCD_DESCRIPTOR_PTR_MASK)
  1341. ==
  1342. (QueueHead->PhysicalAddress & UHCD_DESCRIPTOR_PTR_MASK)) {
  1343. //
  1344. // Queue head points to itself, this means it is
  1345. // the only bulk queue in the list.
  1346. //
  1347. // This will only happen if we have BW reclaimation
  1348. // is enabled.
  1349. //
  1350. physicalAddress =
  1351. deviceExtension->PersistantQueueHead->PhysicalAddress;
  1352. SET_T_BIT(physicalAddress);
  1353. UHCD_ASSERT(physicalAddress & UHCD_CF_QUEUE);
  1354. prevQueueHead->HW_HLink = physicalAddress;
  1355. } else {
  1356. // Fix up hardware link
  1357. prevQueueHead->HW_HLink = QueueHead->HW_HLink;
  1358. }
  1359. break;
  1360. case USB_ENDPOINT_TYPE_INTERRUPT:
  1361. //
  1362. // Brute force method:
  1363. // Walk every frame in the InterruptSchedule and update
  1364. // any node that references this queue head.
  1365. //
  1366. for (i=0; i<MAX_INTERVAL; i++) {
  1367. queueHeadForFrame = deviceExtension->InterruptSchedule[i];
  1368. if (queueHeadForFrame == QueueHead) {
  1369. // Queue Head was root node for this frame
  1370. deviceExtension->InterruptSchedule[i] = QueueHead->Next;
  1371. fixFrameList = TRUE;
  1372. } else {
  1373. while (queueHeadForFrame != persistantQueueHead &&
  1374. queueHeadForFrame->Endpoint->Interval >=
  1375. QueueHead->Endpoint->Interval) {
  1376. if (queueHeadForFrame->Next == QueueHead) {
  1377. // found a link to our queue head,
  1378. // remove it
  1379. queueHeadForFrame->Next = QueueHead->Next;
  1380. // unlink from Hardware Queue
  1381. queueHeadForFrame->HW_HLink = QueueHead->HW_HLink;
  1382. }
  1383. queueHeadForFrame = queueHeadForFrame->Next;
  1384. }
  1385. }
  1386. if (fixFrameList) {
  1387. UHCD_CopyInterruptScheduleToFrameList(DeviceObject);
  1388. }
  1389. }
  1390. break;
  1391. case USB_ENDPOINT_TYPE_ISOCHRONOUS:
  1392. LOGENTRY(LOG_MISC, 'Sep-', Endpoint, 0, DeviceObject);
  1393. break;
  1394. default:
  1395. // Invalid endpoint type, probably a bug
  1396. UHCD_KdTrap(
  1397. ("UHCD_RemoveQueueHeadFromSchedule inavlid endpoint type\n"));
  1398. }
  1399. CLR_EPFLAG(Endpoint,
  1400. EPFLAG_ED_IN_SCHEDULE);
  1401. UHCD_KdPrint((2, "'exit RemoveQueueHeadFromSchedule\n"));
  1402. return removed;
  1403. }
  1404. VOID
  1405. UHCD_CopyInterruptScheduleToFrameList(
  1406. IN PDEVICE_OBJECT DeviceObject
  1407. )
  1408. /*++
  1409. Routine Description:
  1410. Transfers the virtual interrupt schedule to the frame list
  1411. Arguments:
  1412. DeviceObject - device object for this controller.
  1413. Return Value:
  1414. None.
  1415. --*/
  1416. {
  1417. PDEVICE_EXTENSION deviceExtension;
  1418. ULONG i;
  1419. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1420. for (i=0; i < FRAME_LIST_SIZE; i++) {
  1421. if (i == 0 || i == FRAME_LIST_SIZE-1)
  1422. deviceExtension->TriggerTDList->TDs[i == 0 ? 0 : 1].HW_Link =
  1423. deviceExtension->InterruptSchedule[i % MAX_INTERVAL]->PhysicalAddress;
  1424. else {
  1425. ULONG currentTdCopy, currentTd;
  1426. PUHCD_ENDPOINT endpoint;
  1427. currentTd =
  1428. *( ((PULONG) (deviceExtension->FrameListVirtualAddress)+i));
  1429. currentTdCopy =
  1430. *( ((PULONG) (deviceExtension->FrameListCopyVirtualAddress)+i));
  1431. endpoint = UHCD_GetLastFastIsoEndpoint(DeviceObject);
  1432. // have fast iso?
  1433. if (endpoint) {
  1434. PFAST_ISO_DATA fastIsoData;
  1435. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  1436. // fast iso TDs are present, we will need to insert
  1437. // the interrupt schedule after these TDs.
  1438. fastIsoData = &endpoint->FastIsoData;
  1439. transferDescriptor = (PHW_TRANSFER_DESCRIPTOR)
  1440. (fastIsoData->IsoTDListVa + (i*32));
  1441. transferDescriptor->HW_Link =
  1442. deviceExtension->InterruptSchedule[i % MAX_INTERVAL]->PhysicalAddress;
  1443. } else {
  1444. // no fast iso -- just update the schedule
  1445. *( ((PULONG) (deviceExtension->FrameListCopyVirtualAddress)+i) ) =
  1446. deviceExtension->InterruptSchedule[i % MAX_INTERVAL]->PhysicalAddress;
  1447. // if the currentTd == the copy then we don't have any iso
  1448. // tds in the schedule so it is safe to update the schedule directly
  1449. if (currentTd == currentTdCopy) {
  1450. *( ((PULONG) (deviceExtension->FrameListVirtualAddress)+i) ) =
  1451. deviceExtension->InterruptSchedule[i % MAX_INTERVAL]->PhysicalAddress;
  1452. }
  1453. }
  1454. }
  1455. }
  1456. }
  1457. VOID
  1458. UHCD_StartIoCancel(
  1459. IN PDEVICE_OBJECT DeviceObject,
  1460. IN PIRP Irp
  1461. )
  1462. /*++
  1463. Routine Description:
  1464. Arguments:
  1465. Return Value:
  1466. --*/
  1467. {
  1468. PHCD_URB urb;
  1469. //
  1470. // Irp has not been processed by StartIo yet
  1471. //
  1472. LOGENTRY(LOG_MISC, 'sioC', Irp, 0, DeviceObject);
  1473. if (DeviceObject->CurrentIrp == Irp) {
  1474. LOGENTRY(LOG_MISC, 'curI', Irp, 0, DeviceObject);
  1475. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1476. } else {
  1477. LOGENTRY(LOG_MISC, 'Ncur', Irp, 0, DeviceObject);
  1478. if (KeRemoveEntryDeviceQueue(&DeviceObject->DeviceQueue,
  1479. &Irp->Tail.Overlay.DeviceQueueEntry)) {
  1480. LOGENTRY(LOG_MISC, 'YDVQ', Irp, 0, DeviceObject);
  1481. TEST_TRAP();
  1482. urb = (PHCD_URB) URB_FROM_IRP(Irp);
  1483. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1484. while (urb) {
  1485. URB_HEADER(urb).Status = USBD_STATUS_CANCELED;
  1486. if (UHCD_IS_TRANSFER(urb)) {
  1487. urb = urb->HcdUrbCommonTransfer.UrbLink;
  1488. } else {
  1489. break;
  1490. }
  1491. }
  1492. Irp->IoStatus.Status = STATUS_CANCELLED;
  1493. Irp->IoStatus.Information = 0;
  1494. USBD_CompleteRequest(Irp,
  1495. IO_NO_INCREMENT);
  1496. } else {
  1497. LOGENTRY(LOG_MISC, 'NDVQ', Irp, 0, DeviceObject);
  1498. TEST_TRAP();
  1499. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1500. }
  1501. }
  1502. }
  1503. VOID
  1504. UHCD_GetSetEndpointState_StartIo(
  1505. IN PDEVICE_OBJECT DeviceObject,
  1506. IN PIRP Irp
  1507. )
  1508. /*++
  1509. Routine Description:
  1510. Change or report state of an endpoint
  1511. Arguments:
  1512. DeviceObject - pointer to a device object
  1513. Irp - pointer to an I/O Request Packet
  1514. Return Value:
  1515. --*/
  1516. {
  1517. PUHCD_ENDPOINT endpoint;
  1518. PHCD_URB urb;
  1519. BOOLEAN outstandingTransfers;
  1520. ULONG i;
  1521. KIRQL irql;
  1522. urb = (PHCD_URB) URB_FROM_IRP(Irp);
  1523. endpoint = (PUHCD_ENDPOINT) urb->HcdUrbEndpointState.HcdEndpoint;
  1524. ASSERT_ENDPOINT(endpoint);
  1525. //
  1526. // Do we have any transfers pending?
  1527. //
  1528. irql = KeGetCurrentIrql();
  1529. LOCK_ENDPOINT_PENDING_LIST(endpoint, irql, 'lck5');
  1530. outstandingTransfers = !IsListEmpty(&endpoint->PendingTransferList);
  1531. #if DBG
  1532. if (outstandingTransfers) {
  1533. UHCD_KdPrint((2, "'GET_ENDPOINT_STATE ep has pending transfers\n"));
  1534. }
  1535. #endif
  1536. for (i=0; !outstandingTransfers && i < endpoint->MaxRequests; i++) {
  1537. //
  1538. // no outstanding transfers in the queue, check the active list
  1539. // -- if some transfers get retired while we walk the list that
  1540. // is OK.
  1541. //
  1542. if (endpoint->ActiveTransfers[i] != NULL) {
  1543. UHCD_KdPrint((2, "'GETSET_ENDPOINT_STATE ep has active transfers\n"));
  1544. outstandingTransfers = TRUE;
  1545. }
  1546. }
  1547. UNLOCK_ENDPOINT_PENDING_LIST(endpoint, irql, 'ulk5');
  1548. switch (urb->HcdUrbEndpointState.Function) {
  1549. case URB_FUNCTION_HCD_GET_ENDPOINT_STATE:
  1550. urb->HcdUrbEndpointState.HcdEndpointState = 0;
  1551. if (endpoint->EndpointFlags & EPFLAG_HOST_HALTED) {
  1552. UHCD_KdPrint((2, "'GET_ENDPOINT_STATE host halted\n"));
  1553. urb->HcdUrbEndpointState.HcdEndpointState |=
  1554. HCD_ENDPOINT_HALTED;
  1555. }
  1556. if (outstandingTransfers) {
  1557. urb->HcdUrbEndpointState.HcdEndpointState |=
  1558. HCD_ENDPOINT_TRANSFERS_QUEUED;
  1559. }
  1560. URB_HEADER(urb).Status = USBD_STATUS_SUCCESS;
  1561. UHCD_KdPrint((2, "'GET_ENDPOINT_STATE state = %x\n",
  1562. urb->HcdUrbEndpointState.HcdEndpointState));
  1563. break;
  1564. case URB_FUNCTION_HCD_SET_ENDPOINT_STATE:
  1565. if (!outstandingTransfers) {
  1566. LOGENTRY(LOG_MISC, 'cla2', endpoint, 0, 0);
  1567. CLR_EPFLAG(endpoint,
  1568. EPFLAG_ABORT_PENDING_TRANSFERS |
  1569. EPFLAG_ABORT_ACTIVE_TRANSFERS);
  1570. }
  1571. UHCD_KdPrint((2, "'Set Enpoint State flags = %x\n", endpoint->EndpointFlags));
  1572. if (endpoint->EndpointFlags & (EPFLAG_ABORT_ACTIVE_TRANSFERS |
  1573. EPFLAG_ABORT_PENDING_TRANSFERS)) {
  1574. //fail the request
  1575. IoStartNextPacket(DeviceObject, FALSE);
  1576. // let USBD map the error for us
  1577. URB_HEADER(urb).Status = USBD_STATUS_ERROR_BUSY;
  1578. UHCD_CompleteIrp(DeviceObject, Irp, STATUS_SUCCESS, 0, NULL);
  1579. return;
  1580. }
  1581. if (endpoint->EndpointFlags & EPFLAG_DBL_BUFFER) {
  1582. // stop streaming data
  1583. UHCD_StopNoDMATransfer(DeviceObject,
  1584. endpoint);
  1585. }
  1586. //
  1587. // restore virgin status to the pipe
  1588. //
  1589. SET_EPFLAG(endpoint, EPFLAG_VIRGIN);
  1590. //
  1591. // set the data toggle back to 0
  1592. //
  1593. if (urb->HcdUrbEndpointState.HcdEndpointState &
  1594. HCD_ENDPOINT_RESET_DATA_TOGGLE) {
  1595. endpoint->DataToggle = 0;
  1596. }
  1597. if (!(urb->HcdUrbEndpointState.HcdEndpointState & HCD_ENDPOINT_HALTED)) {
  1598. //
  1599. // halt bit cleared, reset the endpoint.
  1600. //
  1601. LOGENTRY(LOG_MISC, 'cla3', endpoint, 0, 0);
  1602. CLR_EPFLAG(endpoint,
  1603. EPFLAG_ABORT_PENDING_TRANSFERS |
  1604. EPFLAG_ABORT_ACTIVE_TRANSFERS |
  1605. EPFLAG_HOST_HALTED);
  1606. //
  1607. // Start any transfers in the pending queue
  1608. //
  1609. if (endpoint->EndpointFlags & EPFLAG_DBL_BUFFER) {
  1610. // transfers will re-start on the next interrupt
  1611. UHCD_RequestInterrupt(DeviceObject, -2);
  1612. } else {
  1613. UHCD_EndpointWorker(DeviceObject, endpoint);
  1614. }
  1615. }
  1616. URB_HEADER(urb).Status = USBD_STATUS_SUCCESS;
  1617. break;
  1618. default:
  1619. // unknown command, probably a bug
  1620. UHCD_KdTrap(("Bogus Endpoint state command\n"));
  1621. }
  1622. IoStartNextPacket(DeviceObject, FALSE);
  1623. UHCD_CompleteIrp(DeviceObject, Irp, STATUS_SUCCESS, 0, NULL);
  1624. }
  1625. NTSTATUS
  1626. UHCD_FinishInitializeEndpoint(
  1627. IN PDEVICE_OBJECT DeviceObject,
  1628. IN PUHCD_ENDPOINT Endpoint,
  1629. IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
  1630. IN PHCD_URB Urb
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. Change or report state of an endpoint
  1635. Arguments:
  1636. Endpoint - endpoint structure to initilaize
  1637. EndpointDescriptor - pointer to the USB endpoint descriptor
  1638. for this endpoint.
  1639. Urb - urb associated with the open request
  1640. Return Value:
  1641. --*/
  1642. {
  1643. UCHAR tmp;
  1644. ULONG i;
  1645. NTSTATUS ntStatus = STATUS_SUCCESS;
  1646. // note that some fields are already initilaized
  1647. ASSERT_ENDPOINT(Endpoint);
  1648. Endpoint->Type = USB_ENDPOINT_TYPE_MASK & EndpointDescriptor->bmAttributes;
  1649. Endpoint->EndpointAddress = EndpointDescriptor->bEndpointAddress;
  1650. Endpoint->MaxPacketSize = EndpointDescriptor->wMaxPacketSize;
  1651. Endpoint->DeviceAddress = (UCHAR) Urb->HcdUrbOpenEndpoint.DeviceAddress;
  1652. Endpoint->LastPacketDataToggle =
  1653. Endpoint->DataToggle = 0;
  1654. Endpoint->Interval = 0;
  1655. Endpoint->IdleTime = 0;
  1656. SET_EPFLAG(Endpoint, EPFLAG_VIRGIN);
  1657. SET_EPFLAG(Endpoint, EPFLAG_INIT);
  1658. Endpoint->MaxTransferSize = Urb->HcdUrbOpenEndpoint.MaxTransferSize;
  1659. // No DMA endpoint ?
  1660. #if DBG
  1661. if (Endpoint->EndpointFlags & EPFLAG_DBL_BUFFER) {
  1662. // client idicates that transfers will be mostly short
  1663. // in this case we will turn off short packet detect
  1664. // and double buffer all transfers to reduce the overhead of
  1665. // having to program each transfer to the hardware separately
  1666. UHCD_KdPrint((1, "'Client requesting double buffering EP = %x\n", Endpoint));
  1667. }
  1668. #endif
  1669. #if DBG
  1670. if (!(Endpoint->EndpointFlags & EPFLAG_ROOT_HUB)) {
  1671. UHCD_ASSERT(Endpoint->TDCount == UHCD_GetNumTDsPerEndoint(Endpoint->Type));
  1672. }
  1673. #endif
  1674. if (Urb->HcdUrbOpenEndpoint.HcdEndpointFlags & USBD_EP_FLAG_LOWSPEED) {
  1675. SET_EPFLAG(Endpoint, EPFLAG_LOWSPEED);
  1676. }
  1677. if (Urb->HcdUrbOpenEndpoint.HcdEndpointFlags & USBD_EP_FLAG_NEVERHALT) {
  1678. SET_EPFLAG(Endpoint, EPFLAG_NO_HALT);
  1679. }
  1680. KeInitializeSpinLock(&Endpoint->ActiveListSpin);
  1681. KeInitializeSpinLock(&Endpoint->PendingListSpin);
  1682. #if DBG
  1683. Endpoint->AccessPendingList = 0;
  1684. Endpoint->AccessActiveList = 0;
  1685. #endif
  1686. UHCD_KdPrint((2, "'MaxRequests = %d\n", Endpoint->MaxRequests));
  1687. UHCD_ASSERT(Endpoint->MaxRequests == MAX_REQUESTS(EndpointDescriptor,
  1688. Endpoint->EndpointFlags));
  1689. // Select the highest interval we support <= the requested interval.
  1690. // note: an interval of zero gets a oeriod of MAX_INTERVAL
  1691. tmp = EndpointDescriptor->bInterval;
  1692. Endpoint->Interval = MAX_INTERVAL;
  1693. if (EndpointDescriptor->bInterval > MAX_INTERVAL ||
  1694. EndpointDescriptor->bInterval == 0) {
  1695. tmp |= MAX_INTERVAL;
  1696. }
  1697. while ((Endpoint->Interval & tmp) == 0) {
  1698. Endpoint->Interval >>= 1;
  1699. }
  1700. //
  1701. // make sure that iso endpoints have an
  1702. // interval of 1
  1703. //
  1704. if (Endpoint->Type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
  1705. Endpoint->Interval = 1; //iso endpoints have a period of 1
  1706. }
  1707. InitializeListHead(&Endpoint->PendingTransferList);
  1708. for (i=0; i<UHCD_MAX_ACTIVE_TRANSFERS; i++) {
  1709. Endpoint->ActiveTransfers[i] = NULL;
  1710. }
  1711. return ntStatus;
  1712. }
  1713. USHORT
  1714. UHCD_GetNumTDsPerEndoint(
  1715. IN UCHAR EndpointType
  1716. )
  1717. /*++
  1718. Routine Description:
  1719. Return the number of TDs to use for this endpoint based on type
  1720. Arguments:
  1721. Return Value:
  1722. --*/
  1723. {
  1724. // use max TDs always for bulk to get max thru-put regardless
  1725. // of packet size.
  1726. // Historical Note:
  1727. // this is a change from Win98gold and Win98se,
  1728. // originally we only enabled this if MAX_PACKET was 64 to save
  1729. // memory for slower devices -- but vendors bitched about it so
  1730. // now we enable it regardless of packet size.
  1731. if (EndpointType == USB_ENDPOINT_TYPE_ISOCHRONOUS ||
  1732. EndpointType == USB_ENDPOINT_TYPE_BULK) {
  1733. return MAX_TDS_PER_ENDPOINT;
  1734. } else {
  1735. return MIN_TDS_PER_ENDPOINT;
  1736. }
  1737. }
  1738. VOID
  1739. UHCD_BW_Reclimation(
  1740. IN PDEVICE_OBJECT DeviceObject,
  1741. IN BOOLEAN Enable
  1742. )
  1743. /*++
  1744. Routine Description:
  1745. Turn on/off BW reclimation for the Bulk Queues
  1746. Arguments:
  1747. Return Value:
  1748. None.
  1749. --*/
  1750. {
  1751. PDEVICE_EXTENSION deviceExtension;
  1752. PHW_QUEUE_HEAD persistantQueueHead, firstBulkQueueHead,
  1753. lastBulkQueueHead;
  1754. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1755. persistantQueueHead = deviceExtension->PersistantQueueHead;
  1756. if ((deviceExtension->HcFlags & HCFLAG_BWRECLIMATION_ENABLED)
  1757. == Enable) {
  1758. // no state change just return;
  1759. return;
  1760. }
  1761. LOGENTRY(LOG_MISC, 'BRCL', deviceExtension, Enable, DeviceObject);
  1762. //
  1763. // BW reclimation, point back to the first bulk queue head
  1764. // with no T bit set
  1765. //
  1766. // walk the list and find the first bulk
  1767. // queue head
  1768. firstBulkQueueHead = persistantQueueHead;
  1769. do {
  1770. PUHCD_ENDPOINT endpoint;
  1771. endpoint = firstBulkQueueHead->Endpoint;
  1772. if (endpoint &&
  1773. endpoint->Type == USB_ENDPOINT_TYPE_BULK) {
  1774. break;
  1775. }
  1776. firstBulkQueueHead = firstBulkQueueHead->Next;
  1777. } while (firstBulkQueueHead != persistantQueueHead);
  1778. if (firstBulkQueueHead != persistantQueueHead) {
  1779. // no bulk endpoints
  1780. PHW_QUEUE_HEAD next;
  1781. PUHCD_ENDPOINT endpoint;
  1782. lastBulkQueueHead = firstBulkQueueHead;
  1783. do {
  1784. next = lastBulkQueueHead->Next;
  1785. endpoint = next->Endpoint;
  1786. if (endpoint == NULL ||
  1787. endpoint->Type != USB_ENDPOINT_TYPE_BULK) {
  1788. break;
  1789. }
  1790. lastBulkQueueHead = next;
  1791. } while (1);
  1792. if (Enable) {
  1793. //clear the T-bit to enable reclimation
  1794. LOGENTRY(LOG_MISC, 'BRC+', lastBulkQueueHead, 0, DeviceObject);
  1795. CLEAR_T_BIT(lastBulkQueueHead->HW_HLink);
  1796. deviceExtension->HcFlags |= HCFLAG_BWRECLIMATION_ENABLED;
  1797. } else {
  1798. //set the T-bit to disable reclimation
  1799. LOGENTRY(LOG_MISC, 'BRC-', lastBulkQueueHead, 0, DeviceObject);
  1800. SET_T_BIT(lastBulkQueueHead->HW_HLink);
  1801. deviceExtension->HcFlags &= ~HCFLAG_BWRECLIMATION_ENABLED;
  1802. }
  1803. }
  1804. }