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.

892 lines
25 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. :ts=4
  4. Module Name:
  5. dblbuff.c
  6. Abstract:
  7. The module manages double buffered bulk transactions on USB.
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. 2-1-99 : created
  13. --*/
  14. #include "wdm.h"
  15. #include "stdarg.h"
  16. #include "stdio.h"
  17. #include "usbdi.h"
  18. #include "hcdi.h"
  19. #include "uhcd.h"
  20. #if DBG
  21. extern ULONG UHCD_XferNoise;
  22. #endif
  23. VOID
  24. UHCD_StartNoDMATransfer(
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN PUHCD_ENDPOINT Endpoint
  27. )
  28. /*++
  29. Routine Description:
  30. starts receiving data for the endpoint
  31. Arguments:
  32. Return Value:
  33. None.
  34. --*/
  35. {
  36. PUHCD_TD_LIST tDList;
  37. ULONG i;
  38. HW_DESCRIPTOR_PHYSICAL_ADDRESS physicalAddress;
  39. if (Endpoint->EndpointFlags & EPFLAG_NODMA_ON) {
  40. // already on, bail
  41. LOGENTRY(LOG_MISC, 'dmaO', Endpoint, 0, 0);
  42. return;
  43. }
  44. // current TD is the first TD
  45. tDList = Endpoint->SlotTDList[0];
  46. Endpoint->CurrentTDIdx[0] = 0;
  47. physicalAddress = Endpoint->NoDMAPhysicalAddress;
  48. LOGENTRY(LOG_MISC, 'dmG1', Endpoint, physicalAddress, tDList);
  49. for (i=0; i < Endpoint->TDCount; i++) {
  50. tDList->TDs[i].Endpoint = Endpoint->EndpointAddress;
  51. tDList->TDs[i].Address = Endpoint->DeviceAddress;
  52. tDList->TDs[i].HW_Link =
  53. tDList->TDs[(i+1) % Endpoint->TDCount].PhysicalAddress;
  54. UHCD_InitializeAsyncTD(Endpoint, &tDList->TDs[i]);
  55. // for now take an interrupt every TD so we can keep up
  56. tDList->TDs[i].InterruptOnComplete = 1;
  57. tDList->TDs[i].PID = USB_IN_PID;
  58. // set data toggle;
  59. tDList->TDs[i].RetryToggle = Endpoint->DataToggle;
  60. Endpoint->DataToggle ^=1;
  61. // buffer length is packet size
  62. tDList->TDs[i].MaxLength =
  63. UHCD_SYSTEM_TO_USB_BUFFER_LENGTH(Endpoint->MaxPacketSize);
  64. // point TDs at our NoDMA buffer;
  65. tDList->TDs[i].PacketBuffer =
  66. physicalAddress + 64*i;
  67. tDList->TDs[i].ShortPacketDetect = 0;
  68. UHCD_KdPrint((2, "'**TD for BULK DBLBUFF packet (%d)\n", i));
  69. UHCD_Debug_DumpTD(&tDList->TDs[i]);
  70. }
  71. // no T bit the controller will stop at the first in-active TD
  72. // mark the endpoint as started
  73. SET_EPFLAG(Endpoint, EPFLAG_NODMA_ON);
  74. LOGENTRY(LOG_MISC, 'dmG2', Endpoint, Endpoint->QueueHead, 0);
  75. // fire up the transfer loop
  76. // point QH at the first TD
  77. Endpoint->QueueHead->HW_VLink =
  78. Endpoint->TDList->TDs[0].PhysicalAddress;
  79. }
  80. VOID
  81. UHCD_StopNoDMATransfer(
  82. IN PDEVICE_OBJECT DeviceObject,
  83. IN PUHCD_ENDPOINT Endpoint
  84. )
  85. /*++
  86. Routine Description:
  87. stops receiving data for the endpoint
  88. Arguments:
  89. Return Value:
  90. None.
  91. --*/
  92. {
  93. CLR_EPFLAG(Endpoint, EPFLAG_NODMA_ON);
  94. LOGENTRY(LOG_MISC, 'dmaX', Endpoint, Endpoint->QueueHead, 0);
  95. UHCD_KdPrint((0, "'** stopping noDMA transfer\n"));
  96. #if DBG
  97. if (!IsListEmpty(&Endpoint->PendingTransferList)) {
  98. UHCD_KdPrint((0, "'** stopping noDMA w/ pending transfers\n"));
  99. }
  100. if(Endpoint->ActiveTransfers[0] != NULL) {
  101. UHCD_KdPrint((0, "'** stopping noDMA w/ active transfers\n"));
  102. }
  103. #endif
  104. // fixup the TDs point the QH at the first TD
  105. // and mark it inactive
  106. // note that by the time the ep is actually closed more
  107. // than one frame will have elapsed so it will be safe to
  108. // remove the QH
  109. // preserve the data toglge in case the ep gets another
  110. // transfer that starts it again
  111. Endpoint->DataToggle =
  112. Endpoint->LastPacketDataToggle;
  113. Endpoint->TDList->TDs[0].Active = 0;
  114. Endpoint->QueueHead->HW_VLink =
  115. Endpoint->TDList->TDs[0].PhysicalAddress;
  116. // so that only startdmatransfer can activate it
  117. SET_T_BIT(Endpoint->QueueHead->HW_VLink);
  118. #if 0
  119. // DEBUG ONLY
  120. // see if we have any unclaimed data in the buffer
  121. {
  122. LONG i, cnt = 0;
  123. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  124. i = Endpoint->CurrentTDIdx[0];
  125. for (;;) {
  126. transferDescriptor = &Endpoint->TDList->TDs[i];
  127. LOGENTRY(LOG_MISC, 'CKtd', i, transferDescriptor,
  128. Endpoint->CurrentTDIdx[0]);
  129. //
  130. // Did this TD complete?
  131. //
  132. if (transferDescriptor->Active == 0) {
  133. cnt++;
  134. i = NEXT_TD(i, Endpoint);
  135. } else {
  136. break;
  137. }
  138. // see if all TDs were processed
  139. if (i == Endpoint->CurrentTDIdx[0]) {
  140. break;
  141. }
  142. }
  143. if (cnt) {
  144. UHCD_KdPrint((0, "'** abort with %d unprocessed TDs\n", cnt));
  145. TEST_TRAP();
  146. }
  147. }
  148. #endif
  149. }
  150. #define RECYCLE_TD(t) \
  151. (t)->ActualLength = 0;\
  152. (t)->Active = 1;\
  153. (t)->StatusField = 0; \
  154. (t)->ErrorCounter = 3;
  155. BOOLEAN
  156. UHCD_ProcessNoDMATransfer(
  157. IN PDEVICE_OBJECT DeviceObject,
  158. IN PUHCD_ENDPOINT Endpoint,
  159. IN PHCD_URB Urb
  160. )
  161. /*++
  162. Routine Description:
  163. Arguments:
  164. Return Value:
  165. True if current active transfer is complete
  166. --*/
  167. {
  168. BOOLEAN complete = FALSE;
  169. USHORT i, thisTD;
  170. USBD_STATUS usbdStatus = USBD_STATUS_SUCCESS;
  171. PUCHAR tdBuffer;
  172. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  173. PDEVICE_EXTENSION deviceExtension;
  174. ULONG remain, length;
  175. PHCD_EXTENSION urbWork = HCD_AREA(Urb).HcdExtension;
  176. BOOLEAN processed = FALSE;
  177. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  178. // see if this transfer has been canceled
  179. if (Urb->HcdUrbCommonTransfer.Status == UHCD_STATUS_PENDING_XXX) {
  180. usbdStatus = USBD_STATUS_CANCELED;
  181. LOGENTRY(LOG_MISC, 'TCAN', Endpoint, Urb, usbdStatus);
  182. complete = TRUE;
  183. goto UHCD_ProcessNoDMATransfer_Done;
  184. }
  185. // walk through the TD list starting from currentTDIdx
  186. // stop as soon as:
  187. // we fill the active client buffer OR
  188. // we find a short packet OR
  189. // we find an unprocessed TD
  190. // Start at the last TD that had not completed
  191. i = Endpoint->CurrentTDIdx[0];
  192. for (;;) {
  193. transferDescriptor = &Endpoint->TDList->TDs[i];
  194. LOGENTRY(LOG_MISC, 'CKtd', i, transferDescriptor,
  195. Endpoint->CurrentTDIdx[0]);
  196. //
  197. // Did this TD complete?
  198. //
  199. UHCD_KdPrint((2, "'checking DB TD %x\n", transferDescriptor));
  200. UHCD_Debug_DumpTD(transferDescriptor);
  201. if (transferDescriptor->Active == 0) {
  202. LOG_TD('nACT', (PULONG) transferDescriptor);
  203. processed = TRUE;
  204. UHCD_KdPrint((2, "'TD %x completed\n", transferDescriptor));
  205. UHCD_Debug_DumpTD(transferDescriptor);
  206. Endpoint->LastPacketDataToggle = (UCHAR) transferDescriptor->RetryToggle;
  207. //
  208. // Yes, TD completed figure out what to do
  209. //
  210. if (transferDescriptor->StatusField != 0) {
  211. // we got an error, map the status code and retire
  212. // this transfer
  213. // if appropriate the caller will halt transfers
  214. // on the endpoint
  215. complete = TRUE;
  216. usbdStatus = UHCD_MapTDError(deviceExtension, transferDescriptor->StatusField,
  217. UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->ActualLength));
  218. LOGENTRY(LOG_MISC, 'Stal', Endpoint,
  219. transferDescriptor->StatusField, usbdStatus);
  220. i = NEXT_TD(i, Endpoint);
  221. break;
  222. }
  223. //
  224. // No Error, process the TDs data
  225. //
  226. // should be an IN
  227. UHCD_ASSERT(transferDescriptor->PID == USB_IN_PID);
  228. // see how much room is left
  229. remain = Urb->HcdUrbCommonTransfer.TransferBufferLength -
  230. urbWork->BytesTransferred;
  231. length =
  232. UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->ActualLength);
  233. tdBuffer = Endpoint->NoDMABuffer + 64*i;
  234. if (length < remain) {
  235. LOGENTRY(LOG_MISC, 'lsTD', 0, transferDescriptor, 0);
  236. // copy the data to the client buffer
  237. RtlCopyMemory((PUCHAR) urbWork->SystemAddressForMdl +
  238. urbWork->BytesTransferred,
  239. tdBuffer,
  240. length);
  241. urbWork->BytesTransferred += length;
  242. i = NEXT_TD(i, Endpoint);
  243. // check for short packet
  244. // short packets cause the transfer to complete.
  245. if (length <
  246. Endpoint->MaxPacketSize) {
  247. LOGENTRY(LOG_MISC, 'sHRT',
  248. transferDescriptor,
  249. transferDescriptor->ActualLength,
  250. transferDescriptor->MaxLength);
  251. complete = TRUE;
  252. break;
  253. }
  254. } else if (length == remain) {
  255. LOGENTRY(LOG_MISC, 'eqTD', 0, transferDescriptor, 0);
  256. // this td just fills the client buffer
  257. RtlCopyMemory((PUCHAR)urbWork->SystemAddressForMdl +
  258. urbWork->BytesTransferred,
  259. tdBuffer,
  260. length);
  261. urbWork->BytesTransferred += length;
  262. complete = TRUE;
  263. i = NEXT_TD(i, Endpoint);
  264. break;
  265. } else {
  266. TEST_TRAP();
  267. // bugbug this is an odd case, not sure how to handle
  268. // it yet.
  269. // normally two transfers cannot span a single packet
  270. // TD data is bigger than space left in client buffer
  271. // copy what we can
  272. RtlCopyMemory(urbWork->SystemAddressForMdl,
  273. tdBuffer,
  274. remain);
  275. complete = TRUE;
  276. // save the rest of the data for the next pass
  277. break;
  278. }
  279. /* active == 0 */
  280. } else {
  281. // this TD still active, all done
  282. LOGENTRY(LOG_MISC, 'acBK', Endpoint, transferDescriptor, 0);
  283. break;
  284. }
  285. // see if all TDs were processed
  286. if (i == Endpoint->CurrentTDIdx[0]) {
  287. UHCD_ASSERT(processed == TRUE);
  288. break;
  289. }
  290. } /* for ;; */
  291. if (processed) {
  292. // at least one TD completed
  293. thisTD = Endpoint->CurrentTDIdx[0];
  294. UHCD_ASSERT(Endpoint->TDList->TDs[thisTD].Active == 0);
  295. RECYCLE_TD(&Endpoint->TDList->TDs[thisTD]);
  296. thisTD = NEXT_TD(thisTD, Endpoint);
  297. // set currentTDidx to where we left off
  298. Endpoint->CurrentTDIdx[0] = i;
  299. // recycle the TDs we processed
  300. for(;;) {
  301. if (thisTD == Endpoint->CurrentTDIdx[0]) {
  302. break;
  303. }
  304. UHCD_ASSERT(Endpoint->TDList->TDs[thisTD].Active == 0);
  305. RECYCLE_TD(&Endpoint->TDList->TDs[thisTD]);
  306. thisTD = NEXT_TD(thisTD, Endpoint);
  307. }
  308. }
  309. UHCD_KdPrint((2, "'check DB TD done\n"));
  310. UHCD_ProcessNoDMATransfer_Done:
  311. if (complete) {
  312. Urb->HcdUrbCommonTransfer.Status = usbdStatus;
  313. }
  314. return complete;
  315. }
  316. NTSTATUS
  317. UHCD_InitializeNoDMAEndpoint(
  318. IN PDEVICE_OBJECT DeviceObject,
  319. IN PUHCD_ENDPOINT Endpoint
  320. )
  321. /*++
  322. Routine Description:
  323. Set up a No-DMA style (double buffered endpoint)
  324. Arguments:
  325. Return Value:
  326. None.
  327. --*/
  328. {
  329. NTSTATUS ntStatus = STATUS_SUCCESS;
  330. PDEVICE_EXTENSION deviceExtension;
  331. ULONG length;
  332. UHCD_KdPrint((2, "'Init No DMA Endpoint\n"));
  333. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  334. // we always have work
  335. SET_EPFLAG(Endpoint, EPFLAG_HAVE_WORK);
  336. //
  337. // first we need a buffer to receive Data, and TDs to
  338. // point in to it
  339. //
  340. // we should have the max TDs reserved for this endpoint
  341. UHCD_ASSERT(Endpoint->TDCount == MAX_TDS_PER_ENDPOINT);
  342. // length will be largest USB packet (64) * the MAX tds per
  343. // endpoint (ends up being one page on x86)
  344. length = 64 * MAX_TDS_PER_ENDPOINT;
  345. Endpoint->NoDMABuffer =
  346. UHCD_Alloc_NoDMA_Buffer(DeviceObject, Endpoint, length);
  347. if (Endpoint->NoDMABuffer == NULL) {
  348. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  349. }
  350. return ntStatus;
  351. }
  352. NTSTATUS
  353. UHCD_UnInitializeNoDMAEndpoint(
  354. IN PDEVICE_OBJECT DeviceObject,
  355. IN PUHCD_ENDPOINT Endpoint
  356. )
  357. /*++
  358. Routine Description:
  359. Set up a No-DMA style (Dbl buffered endpoint)
  360. Arguments:
  361. Return Value:
  362. None.
  363. --*/
  364. {
  365. NTSTATUS ntStatus = STATUS_SUCCESS;
  366. PDEVICE_EXTENSION deviceExtension;
  367. LOGENTRY(LOG_MISC, 'unIN', Endpoint, 0, 0);
  368. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  369. UHCD_ASSERT(!(Endpoint->EndpointFlags & EPFLAG_NODMA_ON));
  370. if (Endpoint->NoDMABuffer) {
  371. UHCD_Free_NoDMA_Buffer(DeviceObject, Endpoint->NoDMABuffer);
  372. Endpoint->NoDMABuffer = NULL;
  373. }
  374. return STATUS_SUCCESS;
  375. }
  376. VOID
  377. UHCD_EndpointNoDMA_Abort(
  378. IN PDEVICE_OBJECT DeviceObject,
  379. IN PUHCD_ENDPOINT Endpoint
  380. )
  381. /*++
  382. Routine Description:
  383. Aborts all active and/or pending transfers for a NoDMA endpoint
  384. Called at DPC level
  385. Arguments:
  386. Return Value:
  387. None.
  388. --*/
  389. {
  390. KIRQL irql;
  391. //BOOLEAN done = FALSE;
  392. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  393. UHCD_ASSERT(Endpoint->EndpointFlags &
  394. (EPFLAG_ABORT_PENDING_TRANSFERS | EPFLAG_ABORT_ACTIVE_TRANSFERS));
  395. if (Endpoint->EndpointFlags & EPFLAG_ABORT_ACTIVE_TRANSFERS) {
  396. PHCD_URB urb;
  397. urb = Endpoint->ActiveTransfers[0];
  398. LOGENTRY(LOG_MISC, 'ABac', urb, 0, Endpoint);
  399. if (urb) {
  400. Endpoint->ActiveTransfers[0] = NULL;
  401. URB_HEADER(urb).Status = USBD_STATUS_CANCELED;
  402. UHCD_CompleteIrp(DeviceObject,
  403. HCD_AREA(urb).HcdIrp,
  404. STATUS_CANCELLED,
  405. 0,
  406. urb);
  407. CLR_EPFLAG(Endpoint,
  408. EPFLAG_ABORT_ACTIVE_TRANSFERS);
  409. }
  410. }
  411. if (Endpoint->EndpointFlags & EPFLAG_ABORT_PENDING_TRANSFERS) {
  412. BOOLEAN pendingTransfers = TRUE;
  413. LOGENTRY(LOG_MISC, 'ABpd', Endpoint, 0, 0);
  414. // dequeue all of our pending requests an complete them with status
  415. // canceled
  416. while (pendingTransfers) {
  417. PHCD_URB urb;
  418. PLIST_ENTRY listEntry;
  419. LOCK_ENDPOINT_PENDING_LIST(Endpoint, irql, 'lck3');
  420. if (IsListEmpty(&Endpoint->PendingTransferList)) {
  421. pendingTransfers = FALSE;
  422. // clear the abort flag
  423. CLR_EPFLAG(Endpoint,
  424. EPFLAG_ABORT_PENDING_TRANSFERS);
  425. UNLOCK_ENDPOINT_PENDING_LIST(Endpoint, irql, 'ulk3');
  426. } else {
  427. listEntry = RemoveHeadList(&Endpoint->PendingTransferList);
  428. urb = (PHCD_URB) CONTAINING_RECORD(
  429. listEntry,
  430. struct _URB_HCD_COMMON_TRANSFER,
  431. hca.HcdListEntry);
  432. LOGENTRY(LOG_MISC, 'DQXF', urb, 0, 0);
  433. UNLOCK_ENDPOINT_PENDING_LIST(Endpoint, irql, 'ulk3');
  434. URB_HEADER(urb).Status = USBD_STATUS_CANCELED;
  435. UHCD_CompleteIrp(DeviceObject,
  436. HCD_AREA(urb).HcdIrp,
  437. STATUS_CANCELLED,
  438. 0,
  439. urb);
  440. // complete this transfer
  441. }
  442. } /* while */
  443. }
  444. }
  445. VOID
  446. UHCD_EndpointNoDMAWorker(
  447. IN PDEVICE_OBJECT DeviceObject,
  448. IN PUHCD_ENDPOINT Endpoint
  449. )
  450. /*++
  451. Routine Description:
  452. Main worker function for an endpoint that does not require DMA.
  453. Note: We should never have transfers in the active list for one
  454. of these endooints.
  455. Called at DPC level
  456. Arguments:
  457. Return Value:
  458. None.
  459. --*/
  460. {
  461. ULONG slot;
  462. BOOLEAN complete;
  463. KIRQL irql;
  464. //BOOLEAN done = FALSE;
  465. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  466. //UHCD_KdPrint((2, "'enter UHCD_EndpointNoDMAWorker\n"));
  467. //
  468. // some asserts
  469. //
  470. // max request should always be one -- we will manage with just one
  471. // set of TDs
  472. UHCD_ASSERT(Endpoint->MaxRequests == 1);
  473. slot = 0;
  474. if (Endpoint->EndpointFlags &
  475. (EPFLAG_ABORT_PENDING_TRANSFERS | EPFLAG_ABORT_ACTIVE_TRANSFERS)) {
  476. // client has requested abort
  477. UHCD_KdPrint((0, "'abort no DMA ep\n"));
  478. UHCD_EndpointNoDMA_Abort(DeviceObject,
  479. Endpoint);
  480. goto UHCD_EndpointNoDMAWorker_Done;
  481. }
  482. do {
  483. // check our pending request list
  484. if (IsListEmpty(&Endpoint->PendingTransferList) &&
  485. Endpoint->ActiveTransfers[slot] == NULL) {
  486. // client list is empty,
  487. // no more to do for now
  488. LOGENTRY(LOG_MISC, 'ndMT', Endpoint, 0, 0);
  489. break;
  490. } else {
  491. USBD_STATUS usbdStatus;
  492. PIRP irp;
  493. PHCD_URB urb;
  494. PHCD_EXTENSION urbWork;
  495. // no active transfer
  496. // dequeue the next pending one for processing
  497. // if the endpoint is not stalled, start up the DMA
  498. // loop if not running on the first transfer
  499. if (!(Endpoint->EndpointFlags & EPFLAG_HOST_HALTED)) {
  500. LOGENTRY(LOG_MISC, 'ndST', Endpoint, 0, 0);
  501. UHCD_StartNoDMATransfer(DeviceObject,
  502. Endpoint);
  503. }
  504. if (Endpoint->ActiveTransfers[slot] == NULL) {
  505. PLIST_ENTRY listEntry;
  506. // dequeue the next transfer
  507. LOCK_ENDPOINT_PENDING_LIST(Endpoint, irql, 'lck6');
  508. UHCD_ASSERT(!IsListEmpty(&Endpoint->PendingTransferList));
  509. listEntry = RemoveHeadList(&Endpoint->PendingTransferList);
  510. urb = (PHCD_URB) CONTAINING_RECORD(
  511. listEntry,
  512. struct _URB_HCD_COMMON_TRANSFER,
  513. hca.HcdListEntry);
  514. LOGENTRY(LOG_MISC, 'ndDQ', Endpoint, urb, 0);
  515. UHCD_ASSERT(urb);
  516. UNLOCK_ENDPOINT_PENDING_LIST(Endpoint, irql, 'ulk6');
  517. urbWork = HCD_AREA(urb).HcdExtension;
  518. UHCD_ASSERT(urbWork);
  519. //#if DBG
  520. // if (UHCD_XferNoise) {
  521. // UHCD_KdPrint((0, "'db xfer len req =%d\n", urb->HcdUrbCommonTransfer.TransferBufferLength));
  522. // }
  523. //#endif
  524. // init the work area
  525. // note: this area is zeroed
  526. if (urb->HcdUrbCommonTransfer.TransferBufferLength) {
  527. PMDL mdl;
  528. mdl = urb->HcdUrbCommonTransfer.TransferBufferMDL;
  529. if (!(mdl->MdlFlags &
  530. (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))) {
  531. urbWork->Flags |= UHCD_MAPPED_LOCKED_PAGES;
  532. }
  533. urbWork->SystemAddressForMdl =
  534. MmGetSystemAddressForMdl(mdl);
  535. LOGENTRY(LOG_MISC, 'sMDL',
  536. Endpoint, urb, urbWork->SystemAddressForMdl);
  537. } else {
  538. urbWork->SystemAddressForMdl = NULL;
  539. TEST_TRAP();
  540. }
  541. urbWork->Flags |= UHCD_TRANSFER_ACTIVE;
  542. Endpoint->ActiveTransfers[slot] = urb;
  543. }
  544. //
  545. // so now we have a client transfer in the active slot
  546. //
  547. UHCD_ASSERT(Endpoint->ActiveTransfers[slot] != NULL);
  548. urb = Endpoint->ActiveTransfers[slot];
  549. irp = HCD_AREA(urb).HcdIrp;
  550. UHCD_ASSERT(irp);
  551. urbWork = HCD_AREA(urb).HcdExtension;
  552. LOGENTRY(LOG_MISC, 'ndPR', Endpoint, urb, 0);
  553. complete = UHCD_ProcessNoDMATransfer(DeviceObject,
  554. Endpoint,
  555. urb);
  556. if (complete) {
  557. usbdStatus = urb->HcdUrbCommonTransfer.Status;
  558. // active transfer is complete
  559. Endpoint->ActiveTransfers[slot] = NULL;
  560. if (USBD_ERROR(usbdStatus)) {
  561. if (USBD_HALTED(usbdStatus)) {
  562. //
  563. // error code indicates a condition that should halt
  564. // the endpoint.
  565. //
  566. // check the endpoint state bit, if the endpoint
  567. // is marked for NO_HALT then clear the halt bit
  568. // and proceed to cancel this transfer.
  569. if (Endpoint->EndpointFlags & EPFLAG_NO_HALT) {
  570. //
  571. // clear the halt bit on the usbdStatus code
  572. //
  573. usbdStatus = USBD_STATUS(usbdStatus) | USBD_STATUS_ERROR;
  574. } else {
  575. //
  576. // mark the endpoint as halted, when the client
  577. // sends a reset we'll start processing with the
  578. // next queued transfer.
  579. //
  580. SET_EPFLAG(Endpoint, EPFLAG_HOST_HALTED);
  581. LOGENTRY(LOG_MISC, 'Hhlt', Endpoint, 0, 0);
  582. // stop streaming from the endpoint,
  583. // it should be NAKing anyway
  584. UHCD_StopNoDMATransfer(DeviceObject,
  585. Endpoint);
  586. }
  587. }
  588. //
  589. // complete the original request
  590. //
  591. UHCD_ASSERT(irp != NULL);
  592. UHCD_CompleteIrp(DeviceObject,
  593. irp,
  594. STATUS_SUCCESS,
  595. 0,
  596. urb);
  597. if (Endpoint->EndpointFlags & EPFLAG_HOST_HALTED) {
  598. //
  599. // if the endpoint is halted then stop the stream now
  600. //
  601. UHCD_StopNoDMATransfer(DeviceObject,
  602. Endpoint);
  603. break;
  604. }
  605. } else {
  606. // xfer completed with success
  607. urb->HcdUrbCommonTransfer.Status = usbdStatus;
  608. urb->HcdUrbCommonTransfer.TransferBufferLength =
  609. urbWork->BytesTransferred;
  610. //#if DBG
  611. // if (UHCD_XferNoise) {
  612. // UHCD_KdPrint((0, "'xfer len cpt =%d\n",
  613. // urb->HcdUrbCommonTransfer.TransferBufferLength));
  614. // }
  615. //#endif
  616. UHCD_ASSERT(irp != NULL);
  617. UHCD_CompleteIrp(DeviceObject,
  618. irp,
  619. STATUS_SUCCESS,
  620. 0,
  621. urb);
  622. }
  623. } /* xfer complete */
  624. }
  625. // cuurent transfer completed, grab the next one and process it
  626. } while (complete);
  627. UHCD_EndpointNoDMAWorker_Done:
  628. return;
  629. }