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.

764 lines
21 KiB

  1. /*++
  2. Copyright (c) 1995,1996 Microsoft Corporation
  3. :ts=4
  4. Module Name:
  5. isoch.c
  6. Abstract:
  7. This module manages bulk, interrupt & control type
  8. transactions on the USB.
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. 2-15-95 : created
  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. typedef struct _UHCD_INSERTION_CONTEXT {
  22. PDEVICE_EXTENSION DeviceExtension;
  23. ULONG FrameNumber;
  24. PHW_TRANSFER_DESCRIPTOR TransferDescriptor;
  25. } UHCD_INSERTION_CONTEXT, *PUHCD_INSERTION_CONTEXT;
  26. BOOLEAN
  27. UHCD_SyncInsertIsochDescriptor(
  28. IN PUHCD_INSERTION_CONTEXT InsertionContext
  29. )
  30. /*++
  31. Routine Description:
  32. Arguments:
  33. Return Value:
  34. --*/
  35. {
  36. ULONG i;
  37. PDEVICE_EXTENSION deviceExtension =
  38. InsertionContext->DeviceExtension;
  39. ULONG frameNumber = InsertionContext->FrameNumber;
  40. PHW_TRANSFER_DESCRIPTOR transferDescriptor =
  41. InsertionContext->TransferDescriptor;
  42. i = frameNumber % FRAME_LIST_SIZE;
  43. if (frameNumber <= deviceExtension->LastFrameProcessed) {
  44. //
  45. // we missed it just don't insert
  46. //
  47. goto UHCD_SyncInsertIsochDescriptor_Done;
  48. }
  49. // link to what is currently in the
  50. // frame
  51. transferDescriptor->HW_Link =
  52. *( ((PULONG) (deviceExtension->FrameListVirtualAddress) + i) );
  53. // now we are in the frame
  54. *( ((PULONG) (deviceExtension->FrameListVirtualAddress) + i) ) =
  55. transferDescriptor->PhysicalAddress;
  56. #if DBG
  57. {
  58. ULONG length;
  59. length = *( deviceExtension->IsoList + i);
  60. length +=
  61. UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->MaxLength);
  62. *( deviceExtension->IsoList + i ) = length;
  63. // BUGBUG for iso debugging with camera only!!
  64. //#ifdef MAX_DEBUG
  65. // UHCD_ASSERT(length <= 385);
  66. //#endif
  67. }
  68. #endif
  69. //
  70. // free our context info
  71. //
  72. UHCD_SyncInsertIsochDescriptor_Done:
  73. return TRUE;
  74. }
  75. VOID
  76. UHCD_InsertIsochDescriptor(
  77. IN PDEVICE_OBJECT DeviceObject,
  78. IN PHW_TRANSFER_DESCRIPTOR TransferDescriptor,
  79. IN ULONG FrameNumber
  80. )
  81. /*++
  82. Routine Description:
  83. Arguments:
  84. Return Value:
  85. --*/
  86. {
  87. UHCD_INSERTION_CONTEXT insertionContext;
  88. PDEVICE_EXTENSION deviceExtension =
  89. DeviceObject->DeviceExtension;
  90. LOGENTRY(LOG_ISO,'iFrm', FrameNumber, &insertionContext,
  91. deviceExtension->LastFrameProcessed);
  92. insertionContext.DeviceExtension = DeviceObject->DeviceExtension;
  93. insertionContext.FrameNumber = FrameNumber;
  94. insertionContext.TransferDescriptor = TransferDescriptor;
  95. // we had better have an interrupt object
  96. UHCD_ASSERT(deviceExtension->InterruptObject != NULL);
  97. KeSynchronizeExecution(deviceExtension->InterruptObject,
  98. UHCD_SyncInsertIsochDescriptor,
  99. &insertionContext);
  100. }
  101. USBD_STATUS
  102. UHCD_InitializeIsochTransfer(
  103. IN PDEVICE_OBJECT DeviceObject,
  104. IN PUHCD_ENDPOINT Endpoint,
  105. IN PHCD_URB Urb
  106. )
  107. /*++
  108. Routine Description:
  109. This routine initializes the TDs needed by the hardware
  110. to process this request, called from the AdapterControl
  111. function of from within TranferCompleteDPC.
  112. The transfer list for this URB should be ready for
  113. processing before returning from this routine.
  114. Arguments:
  115. DeviceObject - pointer to a device object.
  116. Endpoint - Endpoint associated with this Urb.
  117. Urb - pointer to URB Request Packet for this transfer.
  118. Return Value:
  119. --*/
  120. {
  121. PDEVICE_EXTENSION deviceExtension;
  122. PHCD_EXTENSION urbWork;
  123. #if DBG
  124. ULONG i;
  125. #endif
  126. // UHCD_KdPrint((2, "'enter UHCD_InitializeIsochTransfer\n"));
  127. ASSERT_ENDPOINT(Endpoint);
  128. LOGENTRY(LOG_ISO,'tISO', Endpoint, Urb, Urb->UrbIsochronousTransfer.StartFrame);
  129. deviceExtension = DeviceObject->DeviceExtension;
  130. urbWork = HCD_AREA(Urb).HcdExtension;
  131. LOGENTRY(LOG_ISO,'tISw', urbWork->Flags, Urb, urbWork->Slot);
  132. //
  133. // See if we have already initialized this urb
  134. //
  135. if (urbWork->Flags & UHCD_TRANSFER_INITIALIZED) {
  136. goto UHCD_InitializeIsochTransfer_Done;
  137. }
  138. //
  139. // make sure the transfer is mapped
  140. //
  141. if (!(urbWork->Flags & UHCD_TRANSFER_MAPPED)) {
  142. LOGENTRY(LOG_ISO,'nMpd', urbWork->Flags, Urb, 0);
  143. goto UHCD_InitializeIsochTransfer_Done;
  144. }
  145. if (Urb->UrbIsochronousTransfer.StartFrame >
  146. deviceExtension->LastFrameProcessed+1+FRAME_LIST_SIZE-1) {
  147. //
  148. // if the request is too far in the future to schedule
  149. // TDs then delay initialization, request an interrupt.
  150. // near a time when we can schedule this transfer.
  151. //
  152. UHCD_RequestInterrupt(DeviceObject, Urb->UrbIsochronousTransfer.StartFrame - 32);
  153. LOGENTRY(LOG_ISO,'erly', Urb->UrbIsochronousTransfer.StartFrame,
  154. deviceExtension->LastFrameProcessed, 0);
  155. goto UHCD_InitializeIsochTransfer_Done;
  156. }
  157. urbWork->Flags |= UHCD_TRANSFER_INITIALIZED;
  158. Endpoint->TdsScheduled[urbWork->Slot] = 0;
  159. //
  160. // initialize working space variables for this
  161. // transfer.
  162. //
  163. urbWork->CurrentPacketIdx =
  164. urbWork->BytesTransferred = 0;
  165. urbWork->PacketsProcessed = 0;
  166. Urb->UrbIsochronousTransfer.ErrorCount = 0;
  167. #if DBG
  168. i = UHCD_GetCurrentFrame(DeviceObject);
  169. LOGENTRY(LOG_ISO,'bISO', i, Urb->UrbIsochronousTransfer.StartFrame, DeviceObject);
  170. UHCD_KdPrint((2, "'IsochTransfer: start frame = 0x%x current frame = 0x%x\n",
  171. Urb->UrbIsochronousTransfer.StartFrame, i));
  172. #endif
  173. UHCD_ScheduleIsochTransfer(DeviceObject,
  174. Endpoint,
  175. Urb);
  176. UHCD_InitializeIsochTransfer_Done:
  177. // UHCD_KdPrint((2, "'exit UHCD_InitializeIsochTransfer\n"));
  178. return USBD_STATUS_SUCCESS;
  179. }
  180. VOID
  181. UHCD_ScheduleIsochTransfer(
  182. IN PDEVICE_OBJECT DeviceObject,
  183. IN PUHCD_ENDPOINT Endpoint,
  184. IN PHCD_URB Urb
  185. )
  186. /*++
  187. Routine Description:
  188. Arguments:
  189. DeviceObject - pointer to a device object.
  190. Endpoint - Endpoint associated with this Urb.
  191. Urb - pointer to URB Request Packet for this transfer.
  192. Return Value:
  193. --*/
  194. {
  195. PDEVICE_EXTENSION deviceExtension;
  196. PHCD_EXTENSION urbWork;
  197. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  198. ULONG i, offset, length;
  199. ULONG nextPacket;
  200. PUHCD_TD_LIST urbTDList;
  201. //UHCD_KdPrint((2, "'enter UHCD_ScheduleIsochTransfer\n"));
  202. ASSERT_ENDPOINT(Endpoint);
  203. UHCD_ASSERT(Endpoint->Type == USB_ENDPOINT_TYPE_ISOCHRONOUS);
  204. UHCD_ASSERT(Endpoint->EndpointFlags & EPFLAG_NO_HALT);
  205. LOGENTRY(LOG_ISO,'sISO', Endpoint, Urb, DeviceObject);
  206. deviceExtension = DeviceObject->DeviceExtension;
  207. urbWork = HCD_AREA(Urb).HcdExtension;
  208. urbTDList = Endpoint->SlotTDList[urbWork->Slot];
  209. UHCD_ASSERT(urbWork->Flags & UHCD_TRANSFER_MAPPED);
  210. LOGENTRY(LOG_ISO,'sIS2', Endpoint, urbTDList, urbWork->Slot);
  211. //
  212. // If we are done with this transfer just exit
  213. //
  214. if (urbWork->CurrentPacketIdx ==
  215. Urb->UrbIsochronousTransfer.NumberOfPackets) {
  216. goto UHCD_ScheduleIsochTransfer_Done;
  217. }
  218. //
  219. // See if we can put any TDs into the schedule
  220. //
  221. for (i=0; i< Endpoint->TDCount; i++) {
  222. //
  223. // BUGBUG possibly attach TD list to URB
  224. // for now we share the TDs among mutiple active
  225. // requests.
  226. //
  227. transferDescriptor = &urbTDList->TDs[i];
  228. if (transferDescriptor->Frame == 0) {
  229. //
  230. // TD is not in use, go ahead and schedule it
  231. //
  232. LOGENTRY(LOG_ISO,'ISOc', Urb->UrbIsochronousTransfer.StartFrame,
  233. urbWork->CurrentPacketIdx, deviceExtension->LastFrameProcessed);
  234. // See if it is too early to set up this TD
  235. if (Urb->UrbIsochronousTransfer.StartFrame + urbWork->CurrentPacketIdx >
  236. deviceExtension->LastFrameProcessed+1+FRAME_LIST_SIZE-1) {
  237. LOGENTRY(LOG_ISO,'ISOd', 0, 0, 0);
  238. break; // No, stop setting up TDs
  239. }
  240. // prepare the TD for this packet
  241. transferDescriptor->Active = 1;
  242. transferDescriptor->Endpoint = Endpoint->EndpointAddress;
  243. transferDescriptor->Address = Endpoint->DeviceAddress;
  244. //
  245. // Set Pid based on direction
  246. //
  247. transferDescriptor->PID = DATA_DIRECTION_IN(Urb) ? USB_IN_PID : USB_OUT_PID;
  248. transferDescriptor->Isochronous = 1;
  249. transferDescriptor->ActualLength =
  250. UHCD_SYSTEM_TO_USB_BUFFER_LENGTH(0);
  251. transferDescriptor->StatusField = 0;
  252. transferDescriptor->LowSpeedControl = 0;
  253. transferDescriptor->ReservedMBZ = 0;
  254. transferDescriptor->ErrorCounter = 0;
  255. transferDescriptor->RetryToggle = 0;
  256. //
  257. // BUGBUG for now, one every frame
  258. //
  259. Endpoint->TdsScheduled[urbWork->Slot]++;
  260. transferDescriptor->InterruptOnComplete = 0;
  261. if (Endpoint->TdsScheduled[urbWork->Slot] >
  262. (Endpoint->TDCount/2)) {
  263. transferDescriptor->InterruptOnComplete = 1;
  264. Endpoint->TdsScheduled[urbWork->Slot] = 0;
  265. }
  266. // request some interrupts near the end
  267. if (Urb->UrbIsochronousTransfer.NumberOfPackets -
  268. urbWork->CurrentPacketIdx < 5) {
  269. transferDescriptor->InterruptOnComplete = 1;
  270. }
  271. transferDescriptor->Frame = Urb->UrbIsochronousTransfer.StartFrame +
  272. urbWork->CurrentPacketIdx;
  273. transferDescriptor->Urb = Urb;
  274. //
  275. // Prepare the buffer part of the TD.
  276. //
  277. offset =
  278. Urb->UrbIsochronousTransfer.IsoPacket[urbWork->CurrentPacketIdx].Offset;
  279. UHCD_ASSERT(urbWork->CurrentPacketIdx <
  280. Urb->UrbIsochronousTransfer.NumberOfPackets);
  281. nextPacket = urbWork->CurrentPacketIdx+1;
  282. if (nextPacket >=
  283. Urb->UrbIsochronousTransfer.NumberOfPackets) {
  284. // this is the last packet
  285. length = Urb->UrbIsochronousTransfer.TransferBufferLength -
  286. offset;
  287. } else {
  288. // compute length based on offset of next packet
  289. UHCD_ASSERT(Urb->UrbIsochronousTransfer.IsoPacket[nextPacket].Offset >
  290. offset);
  291. length = Urb->UrbIsochronousTransfer.IsoPacket[nextPacket].Offset -
  292. offset;
  293. }
  294. transferDescriptor->PacketBuffer =
  295. UHCD_GetPacketBuffer(DeviceObject,
  296. Endpoint,
  297. Urb,
  298. urbWork,
  299. offset,
  300. length);
  301. transferDescriptor->MaxLength =
  302. UHCD_SYSTEM_TO_USB_BUFFER_LENGTH(length);
  303. //
  304. // Put the TD in to the schedule at the requested frame.
  305. //
  306. LOG_TD('isTD', transferDescriptor);
  307. //UHCD_Debug_DumpTD(transferDescriptor);
  308. if (transferDescriptor->PacketBuffer) {
  309. UHCD_ASSERT(urbWork->CurrentPacketIdx <=
  310. Urb->UrbIsochronousTransfer.NumberOfPackets);
  311. UHCD_InsertIsochDescriptor(DeviceObject,
  312. transferDescriptor,
  313. Urb->UrbIsochronousTransfer.StartFrame +
  314. urbWork->CurrentPacketIdx);
  315. } else {
  316. TEST_TRAP();
  317. // failed to get the packet buffer,
  318. // we set the fields in the TD as
  319. // if the HC got it, the urb will
  320. // get updated when the rest of the TDs
  321. // are processed.
  322. // make inactive
  323. transferDescriptor->Active = 0;
  324. // mark TD so we know we have a software
  325. // error
  326. transferDescriptor->StatusField = 0x3f;
  327. }
  328. urbWork->CurrentPacketIdx++;
  329. if (urbWork->CurrentPacketIdx ==
  330. Urb->UrbIsochronousTransfer.NumberOfPackets) {
  331. break;
  332. }
  333. } /* end td->FRame == 0*/
  334. } /* end for */
  335. UHCD_ScheduleIsochTransfer_Done:
  336. //UHCD_KdPrint((2, "'exit UHCD_ScheduleIsochTransfer\n"));
  337. return;
  338. }
  339. USBD_STATUS
  340. UHCD_ProcessIsochTransfer(
  341. IN PDEVICE_OBJECT DeviceObject,
  342. IN PUHCD_ENDPOINT Endpoint,
  343. IN PHCD_URB Urb,
  344. IN OUT PBOOLEAN Completed
  345. )
  346. /*++
  347. Routine Description:
  348. Checks to see if an isoch transfer is complete.
  349. Arguments:
  350. DeviceObject - pointer to a device object.
  351. Endpoint - endpoint to check for completed transfers.
  352. Urb - ptr to URB to process.
  353. Completed - TRUE if this transfer is complete.
  354. Return Value:
  355. TRUE if this transfer is complete, Status set to proper
  356. error code.
  357. --*/
  358. {
  359. PHCD_EXTENSION urbWork;
  360. PDEVICE_EXTENSION deviceExtension;
  361. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  362. ULONG i, packetIdx;
  363. USBD_STATUS err;
  364. // PHCD_URB urb;
  365. USBD_STATUS usbStatus = USBD_STATUS_SUCCESS;
  366. PUHCD_TD_LIST urbTDList;
  367. STARTPROC("Piso");
  368. *Completed = FALSE;
  369. deviceExtension = DeviceObject->DeviceExtension;
  370. urbWork = HCD_AREA(Urb).HcdExtension;
  371. urbTDList = Endpoint->SlotTDList[urbWork->Slot];
  372. ASSERT_ENDPOINT(Endpoint);
  373. // make sure the urb has been properly initialized
  374. UHCD_InitializeIsochTransfer(DeviceObject,
  375. Endpoint,
  376. Urb);
  377. if ((urbWork->Flags & UHCD_TRANSFER_INITIALIZED) == 0) {
  378. //
  379. // urb has not been initialized yet, probably too early
  380. // attempt to initialize now.
  381. //
  382. LOGENTRY(LOG_ISO,'npIS', Endpoint, Urb, urbTDList);
  383. goto UHCD_ProcessIsochTransfer_Done;
  384. }
  385. //
  386. // walk thru our TD list for this URB retire any TDs
  387. // that are done.
  388. //
  389. LOGENTRY(LOG_ISO,'doIS', Endpoint, urbWork->Slot, urbTDList);
  390. for (i=0; i< Endpoint->TDCount; i++) {
  391. UHCD_ASSERT(urbTDList->TDs[i].Urb == Urb ||
  392. urbTDList->TDs[i].Urb == NULL);
  393. if (urbTDList->TDs[i].Frame <= deviceExtension->LastFrameProcessed &&
  394. // only deal with TDs that have been removed
  395. // from the schedule.
  396. urbTDList->TDs[i].Frame != 0 &&
  397. // don't check retired TDs
  398. urbTDList->TDs[i].Urb == Urb) {
  399. // only look at TDs for this urb
  400. transferDescriptor = &urbTDList->TDs[i];
  401. LOGENTRY(LOG_ISO,'piTD', transferDescriptor, transferDescriptor->Frame,
  402. urbWork->PacketsProcessed);
  403. //
  404. // index for this packet
  405. //
  406. packetIdx = transferDescriptor->Frame -
  407. Urb->UrbIsochronousTransfer.StartFrame;
  408. //
  409. // Update transfer buffer based on data received for
  410. // this frame.
  411. //
  412. // assume we got no error
  413. err = Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Status =
  414. USBD_STATUS_SUCCESS;
  415. //
  416. // see if we got an error.
  417. //
  418. if (transferDescriptor->Active) {
  419. //
  420. // if the active bit is still set then we put this transfer
  421. // in the schedule too late.
  422. //
  423. err = USBD_STATUS_NOT_ACCESSED;
  424. deviceExtension->IsoStats.IsoPacketNotAccesed++;
  425. LOGENTRY(LOG_MISC, 'nPRO', transferDescriptor, transferDescriptor->Frame,
  426. err);
  427. // TEST_TRAP();
  428. } else if (transferDescriptor->StatusField) {
  429. // BUGBUG map the hardware error
  430. err = UHCD_MapTDError(deviceExtension, transferDescriptor->StatusField,
  431. UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->ActualLength));
  432. LOGENTRY(LOG_MISC, 'hERR', transferDescriptor, transferDescriptor->Frame,
  433. err);
  434. deviceExtension->IsoStats.IsoPacketHWError++;
  435. // TEST_TRAP();
  436. }
  437. if (USBD_ERROR(err)) {
  438. //
  439. // Note this error in the error list
  440. //
  441. // ErrorList is a list of packet indexes which have an error
  442. UHCD_ASSERT(packetIdx <= 255);
  443. Urb->UrbIsochronousTransfer.ErrorCount++;
  444. Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Status = err;
  445. }
  446. // BUGBUG
  447. // note, we report length even for
  448. // errors.
  449. //
  450. // keep count the number of bytes succesfully transferred.
  451. //
  452. urbWork->BytesTransferred +=
  453. UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->ActualLength);
  454. //
  455. // return the length of the packet
  456. //
  457. if (USBD_TRANSFER_DIRECTION(
  458. Urb->UrbIsochronousTransfer.TransferFlags) ==
  459. USBD_TRANSFER_DIRECTION_IN) {
  460. //
  461. // return the length of the packet
  462. //
  463. Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Length =
  464. UHCD_USB_TO_SYSTEM_BUFFER_LENGTH(transferDescriptor->ActualLength);
  465. // if the device transmitted < max packet size
  466. // set the buffer underrun status.
  467. if (Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Length <
  468. Endpoint->MaxPacketSize) {
  469. Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Status =
  470. USBD_STATUS_DATA_UNDERRUN & ~USBD_STATUS_HALTED;
  471. }
  472. } else {
  473. Urb->UrbIsochronousTransfer.IsoPacket[packetIdx].Length = 0;
  474. }
  475. //
  476. // retire this isoch TD
  477. //
  478. transferDescriptor->Frame = 0;
  479. urbWork->PacketsProcessed++;
  480. UHCD_ASSERT(urbWork->PacketsProcessed <=
  481. Urb->UrbIsochronousTransfer.NumberOfPackets);
  482. }
  483. } /* for */
  484. //
  485. // see if we are done with this transfer
  486. //
  487. if (urbWork->PacketsProcessed ==
  488. Urb->UrbIsochronousTransfer.NumberOfPackets) {
  489. //
  490. // All TDs for this transfer have been processed.
  491. LOGENTRY(LOG_MISC, 'iCmp', Urb, 0,
  492. urbWork->PacketsProcessed);
  493. *Completed = TRUE;
  494. //
  495. // Clear the Urb field for all TDs associated with
  496. // the completing urb
  497. //
  498. for (i=0; i< Endpoint->TDCount; i++) {
  499. urbTDList->TDs[i].Urb = NULL;
  500. }
  501. //
  502. // we should return an error if all packets completed with an error.
  503. //
  504. if (Urb->UrbIsochronousTransfer.ErrorCount ==
  505. Urb->UrbIsochronousTransfer.NumberOfPackets) {
  506. //
  507. // Isoch transfer will be failed but isoch
  508. // errors never stall the endpoint on the host so
  509. // clear the stall bit now.
  510. //
  511. usbStatus = USBD_STATUS_ISOCH_REQUEST_FAILED;
  512. // clear stall bit
  513. usbStatus &= ~USBD_STATUS_HALTED;
  514. } else {
  515. usbStatus = USBD_STATUS_SUCCESS;
  516. }
  517. } else {
  518. //
  519. // not complete yet, put some more TDs in the schedule.
  520. //
  521. //
  522. // Set up any TDs we still need to complete the
  523. // current URB
  524. //
  525. UHCD_ScheduleIsochTransfer(DeviceObject,
  526. Endpoint,
  527. Urb);
  528. #if 0
  529. //
  530. // some preprocessing code, try to start up the next transfer here
  531. //
  532. // NOTE: this will kick in close to the end of the current transfer
  533. //
  534. UHCD_ASSERT(Endpoint->MaxRequests == 2);
  535. // this trick only works if maxrequests is 2
  536. i = !urbWork->Slot;
  537. urb = Endpoint->ActiveTransfers[i];
  538. //
  539. // When we near the end of this transfer we want to start the next one
  540. //
  541. //BUGBUG
  542. // should be when numpackets - packetsprocessed < numTds
  543. // ie there are some extra
  544. // Urb->UrbIsochronousTransfer.NumberOfPackets -
  545. // urbWork->PacketsProcessed < NUM_TDS_PER_ENDPOINT
  546. if (urbWork->PacketsProcessed > Urb->UrbIsochronousTransfer.NumberOfPackets-
  547. 8
  548. && urb != NULL) {
  549. UHCD_KdPrint((2, "'process next iso urb from ProcessIsochTransfer\n"));
  550. LOGENTRY(LOG_ISO,'iPRE', urb, &Endpoint->PendingTransferList, Endpoint);
  551. UHCD_InitializeIsochTransfer(DeviceObject,
  552. Endpoint,
  553. urb);
  554. }
  555. #endif
  556. }
  557. UHCD_ProcessIsochTransfer_Done:
  558. ENDPROC("pIso");
  559. return usbStatus;
  560. }