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.

767 lines
19 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. :ts=4
  4. Module Name:
  5. fastiso.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. BOOLEAN
  21. UHCD_InitFastIsoTDs(
  22. IN PVOID Context
  23. )
  24. /*++
  25. Routine Description:
  26. Intialize our frame list, ie put our TDs phys addresses in the list,
  27. link our TDs to the current phys entry in the virtual list copy.
  28. Make a copy of the virtual frame list and copy our list
  29. to the virtual list copy.
  30. this will cause the ISR to update the schedule with our iso TDs
  31. when it removes other iso TDs.
  32. Arguments:
  33. Context - DeviceData for this USB controller.
  34. Return Value:
  35. TRUE
  36. --*/
  37. {
  38. PUHCD_ENDPOINT endpoint;
  39. PFAST_ISO_DATA fastIsoData;
  40. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  41. ULONG i;
  42. PDEVICE_EXTENSION deviceExtension;
  43. PDEVICE_OBJECT deviceObject;
  44. endpoint = Context;
  45. ASSERT_ENDPOINT(endpoint);
  46. fastIsoData = &endpoint->FastIsoData;
  47. deviceObject = fastIsoData->DeviceObject;
  48. deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  49. UHCD_KdPrint((2, "'Init Fast ISO - FrameListCopyVirtualAddress %x\n",
  50. deviceExtension->FrameListCopyVirtualAddress));
  51. // intialize our iso TDs, mark them not active
  52. transferDescriptor =
  53. (PHW_TRANSFER_DESCRIPTOR) fastIsoData->IsoTDListVa;
  54. for (i=0; i < FRAME_LIST_SIZE ;i++) {
  55. // link out TD to what is in the copy
  56. transferDescriptor->HW_Link =
  57. *( ((PULONG) (deviceExtension->FrameListCopyVirtualAddress) + i));
  58. // update copy to point to our TD
  59. *( ((PULONG) (deviceExtension->FrameListCopyVirtualAddress) + i)) =
  60. transferDescriptor->PhysicalAddress;
  61. transferDescriptor++;
  62. }
  63. return TRUE;
  64. }
  65. BOOLEAN
  66. UHCD_UnInitFastIso(
  67. IN PVOID Context
  68. )
  69. /*++
  70. Routine Description:
  71. Arguments:
  72. Context - DeviceData for this USB controller.
  73. Return Value:
  74. TRUE
  75. --*/
  76. {
  77. PUHCD_ENDPOINT endpoint;
  78. PFAST_ISO_DATA fastIsoData;
  79. ULONG i;
  80. PDEVICE_EXTENSION deviceExtension;
  81. PDEVICE_OBJECT deviceObject;
  82. endpoint = Context;
  83. ASSERT_ENDPOINT(endpoint);
  84. fastIsoData = &endpoint->FastIsoData;
  85. deviceObject = fastIsoData->DeviceObject;
  86. deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  87. for (i=0; i < FRAME_LIST_SIZE ;i++) {
  88. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  89. transferDescriptor = (PHW_TRANSFER_DESCRIPTOR)
  90. (fastIsoData->IsoTDListVa + (i*32));
  91. // remove our TD from the Virtual Frame list copy
  92. // if we are the first td in the copy then we just need to
  93. // update the copy to point to the next link
  94. if (*( ((PULONG) (deviceExtension->FrameListCopyVirtualAddress) + i) )
  95. == transferDescriptor->PhysicalAddress) {
  96. *( ((PULONG) (deviceExtension->FrameListCopyVirtualAddress) + i) ) =
  97. transferDescriptor->HW_Link;
  98. } else {
  99. // not the first TD ie we have >one fast iso endpoint
  100. TEST_TRAP();
  101. // we need to find the precious TD and link it to the next
  102. }
  103. }
  104. return TRUE;
  105. }
  106. NTSTATUS
  107. UHCD_InitializeFastIsoEndpoint(
  108. IN PDEVICE_OBJECT DeviceObject,
  109. IN PUHCD_ENDPOINT Endpoint
  110. )
  111. /*++
  112. Routine Description:
  113. Set up a No-DMA style (double buffered endpoint) for ISO
  114. This is the init code for the endpoint called at PASSIVE_LEVEL
  115. Arguments:
  116. Return Value:
  117. None.
  118. --*/
  119. {
  120. NTSTATUS ntStatus = STATUS_SUCCESS;
  121. PDEVICE_EXTENSION deviceExtension;
  122. PFAST_ISO_DATA fastIsoData;
  123. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  124. ULONG phys, i, length;
  125. UHCD_KdPrint((1, "'Initializing Fast ISO endpoint\n"));
  126. UHCD_KdPrint((2, "'Init Fast ISO Endpoint\n"));
  127. UHCD_KdPrint((2, "'Max Packet = %d\n", Endpoint->MaxPacketSize));
  128. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  129. fastIsoData = &Endpoint->FastIsoData;
  130. fastIsoData->FastIsoFrameList = NULL;
  131. fastIsoData->DeviceObject = DeviceObject;
  132. Endpoint->NoDMABuffer = NULL;
  133. if ( Endpoint->MaxPacketSize == 0) {
  134. UHCD_KdPrint((2, "'Init Fast ISO Endpoint - zero MP\n"));
  135. TEST_TRAP();
  136. return STATUS_SUCCESS;
  137. }
  138. // allocate our Iso FrameList
  139. // this is a list that contains the phys addresses of
  140. // our persistent ISO TDs
  141. fastIsoData->FastIsoFrameList =
  142. GETHEAP(NonPagedPool, sizeof(ULONG)*FRAME_LIST_SIZE);
  143. if (fastIsoData->FastIsoFrameList == NULL) {
  144. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  145. }
  146. // allocate our common buffers
  147. if (NT_SUCCESS(ntStatus)) {
  148. // allocate 1024 persistent ISO TDs
  149. // plus space for buffers
  150. length = FRAME_LIST_SIZE * 32;
  151. length += (Endpoint->MaxPacketSize * FRAME_LIST_SIZE);
  152. UHCD_KdPrint((2, "'Init Fast ISO Endpoint - need %d\n", length));
  153. Endpoint->NoDMABuffer =
  154. UHCD_Alloc_NoDMA_Buffer(DeviceObject, Endpoint, length);
  155. UHCD_KdPrint((2, "'NoDMA buffer = %x\n", Endpoint->NoDMABuffer));
  156. if (Endpoint->NoDMABuffer == NULL) {
  157. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  158. } else {
  159. fastIsoData->IsoTDListVa = Endpoint->NoDMABuffer;
  160. // physical address of first iso TD
  161. fastIsoData->IsoTDListPhys = Endpoint->NoDMAPhysicalAddress;
  162. fastIsoData->DataBufferStartVa =
  163. fastIsoData->IsoTDListVa + (FRAME_LIST_SIZE*32);
  164. fastIsoData->DataBufferStartPhys =
  165. fastIsoData->IsoTDListPhys + (FRAME_LIST_SIZE*32);
  166. }
  167. }
  168. if (NT_SUCCESS(ntStatus)) {
  169. // intialize our iso TDs, mark them not active
  170. transferDescriptor =
  171. (PHW_TRANSFER_DESCRIPTOR) fastIsoData->IsoTDListVa;
  172. phys = fastIsoData->DataBufferStartPhys;
  173. for (i=0; i<1024 ;i++) {
  174. // prepare the TD
  175. RtlZeroMemory(transferDescriptor,
  176. sizeof(*transferDescriptor));
  177. // td in initially not active
  178. transferDescriptor->Active = 0;
  179. // we will use the Frame entry to track lost
  180. // iso TDs
  181. // initially this is set to zero -- when we mark
  182. // the TD active we set it to 0xabadbabe
  183. // when we recycle it we set it to 0xffffffff
  184. transferDescriptor->Frame = 0;
  185. transferDescriptor->Endpoint = Endpoint->EndpointAddress;
  186. transferDescriptor->Address = Endpoint->DeviceAddress;
  187. //
  188. // Set Pid, only support out
  189. //
  190. transferDescriptor->PID = USB_OUT_PID;
  191. transferDescriptor->Sig = SIG_TD;
  192. transferDescriptor->Isochronous = 1;
  193. transferDescriptor->ActualLength =
  194. UHCD_SYSTEM_TO_USB_BUFFER_LENGTH(0);
  195. transferDescriptor->StatusField = 0;
  196. transferDescriptor->LowSpeedControl = 0;
  197. transferDescriptor->ReservedMBZ = 0;
  198. transferDescriptor->ErrorCounter = 0;
  199. transferDescriptor->RetryToggle = 0;
  200. transferDescriptor->InterruptOnComplete = 1;
  201. transferDescriptor->PhysicalAddress =
  202. fastIsoData->IsoTDListPhys + i*sizeof(*transferDescriptor);
  203. transferDescriptor->PacketBuffer = phys;
  204. UHCD_Debug_DumpTD(transferDescriptor);
  205. transferDescriptor++;
  206. phys += Endpoint->MaxPacketSize;
  207. }
  208. }
  209. if (NT_SUCCESS(ntStatus)) {
  210. InsertHeadList(&deviceExtension->FastIsoEndpointList,
  211. &Endpoint->ListEntry);
  212. // now put the TDs in the schedule
  213. // this must be synchronized with the ISR
  214. UHCD_ASSERT(deviceExtension->InterruptObject);
  215. if (!KeSynchronizeExecution(deviceExtension->InterruptObject,
  216. UHCD_InitFastIsoTDs,
  217. Endpoint)) {
  218. TRAP(); //something has gone terribly wrong
  219. }
  220. // Our TDs are now in permenently in the schedule!
  221. } else {
  222. if (fastIsoData->FastIsoFrameList) {
  223. RETHEAP(fastIsoData->FastIsoFrameList);
  224. }
  225. if (Endpoint->NoDMABuffer) {
  226. UHCD_Free_NoDMA_Buffer(DeviceObject,
  227. Endpoint->NoDMABuffer);
  228. }
  229. }
  230. UHCD_RequestInterrupt(DeviceObject, -2);
  231. UHCD_KdPrint((2, "'Init Fast ISO - FrameListCopyVirtualAddress %x\n",
  232. deviceExtension->FrameListCopyVirtualAddress));
  233. return ntStatus;
  234. }
  235. NTSTATUS
  236. UHCD_UnInitializeFastIsoEndpoint(
  237. IN PDEVICE_OBJECT DeviceObject,
  238. IN PUHCD_ENDPOINT Endpoint
  239. )
  240. /*++
  241. Routine Description:
  242. Set up a No-DMA style (iso dbl buffered endpoint)
  243. Arguments:
  244. Return Value:
  245. None.
  246. --*/
  247. {
  248. NTSTATUS ntStatus = STATUS_SUCCESS;
  249. PDEVICE_EXTENSION deviceExtension;
  250. PFAST_ISO_DATA fastIsoData;
  251. UHCD_KdPrint((1, "'Free Fast ISO Endpoint\n"));
  252. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  253. fastIsoData = &Endpoint->FastIsoData;
  254. // remove from the fast iso list
  255. RemoveEntryList(&Endpoint->ListEntry);
  256. // put the original frame list copy back
  257. UHCD_ASSERT(deviceExtension->InterruptObject);
  258. if (!KeSynchronizeExecution(deviceExtension->InterruptObject,
  259. UHCD_UnInitFastIso,
  260. Endpoint)) {
  261. TRAP(); //something has gone terribly wrong
  262. }
  263. if (fastIsoData->FastIsoFrameList) {
  264. RETHEAP(fastIsoData->FastIsoFrameList);
  265. }
  266. if (Endpoint->NoDMABuffer) {
  267. UHCD_Free_NoDMA_Buffer(DeviceObject,
  268. Endpoint->NoDMABuffer);
  269. }
  270. return STATUS_SUCCESS;
  271. }
  272. PUHCD_ENDPOINT
  273. UHCD_GetLastFastIsoEndpoint(
  274. IN PDEVICE_OBJECT DeviceObject
  275. )
  276. /*++
  277. Routine Description:
  278. Arguments:
  279. Return Value:
  280. --*/
  281. {
  282. PUHCD_ENDPOINT endpoint;
  283. PLIST_ENTRY listEntry;
  284. PDEVICE_EXTENSION deviceExtension;
  285. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  286. // walk the list and return the last endpoint
  287. listEntry = &deviceExtension->FastIsoEndpointList;
  288. if (IsListEmpty(listEntry)) {
  289. endpoint = NULL;
  290. } else {
  291. listEntry = deviceExtension->FastIsoEndpointList.Flink;
  292. }
  293. while (listEntry != &deviceExtension->FastIsoEndpointList) {
  294. endpoint = (PUHCD_ENDPOINT) CONTAINING_RECORD(
  295. listEntry,
  296. struct _UHCD_ENDPOINT,
  297. ListEntry);
  298. ASSERT_ENDPOINT(endpoint);
  299. listEntry = endpoint->ListEntry.Flink;
  300. }
  301. return endpoint;
  302. }
  303. PHW_TRANSFER_DESCRIPTOR
  304. UHCD_GetRelativeTD(
  305. IN PDEVICE_OBJECT DeviceObject,
  306. IN PUHCD_ENDPOINT Endpoint,
  307. IN ULONG FrameNumber,
  308. IN OUT PUCHAR *DataBuffer
  309. )
  310. /*++
  311. Routine Description:
  312. Arguments:
  313. Return Value:
  314. fastIsoData = &Endpoint->FastIsoData;
  315. --*/
  316. {
  317. ULONG i;
  318. PDEVICE_EXTENSION deviceExtension =
  319. DeviceObject->DeviceExtension;
  320. PHW_TRANSFER_DESCRIPTOR transferDescriptor = NULL;
  321. PUCHAR isoData;
  322. PFAST_ISO_DATA fastIsoData;
  323. fastIsoData = &Endpoint->FastIsoData;
  324. i = FrameNumber % FRAME_LIST_SIZE;
  325. if (FrameNumber <= deviceExtension->LastFrameProcessed) {
  326. //
  327. // we missed it
  328. //
  329. deviceExtension->IsoStats.IsoPacketNotAccesed++;
  330. deviceExtension->Stats.IsoMissedCount++;
  331. // TEST_TRAP();
  332. return NULL;
  333. }
  334. UHCD_KdPrint((2, "'frm = %x relfrm %x \n", FrameNumber, i));
  335. UHCD_KdPrint((2, "'base = %x \n", fastIsoData->DataBufferStartVa));
  336. transferDescriptor = (PHW_TRANSFER_DESCRIPTOR)
  337. (fastIsoData->IsoTDListVa + (i*32));
  338. isoData =
  339. (fastIsoData->DataBufferStartVa + (i*Endpoint->MaxPacketSize));
  340. *DataBuffer = isoData;
  341. return transferDescriptor;
  342. }
  343. PHW_TRANSFER_DESCRIPTOR
  344. UHCD_CleanupFastIsoTD(
  345. IN PDEVICE_OBJECT DeviceObject,
  346. IN PUHCD_ENDPOINT Endpoint,
  347. IN ULONG RelativeFrame,
  348. IN BOOLEAN Count
  349. )
  350. /*++
  351. Routine Description:
  352. Arguments:
  353. Count - count the TD as missed if not accessd
  354. Return Value:
  355. fastIsoData = &Endpoint->FastIsoData;
  356. --*/
  357. {
  358. ULONG i;
  359. PDEVICE_EXTENSION deviceExtension =
  360. DeviceObject->DeviceExtension;
  361. PHW_TRANSFER_DESCRIPTOR transferDescriptor = NULL;
  362. PUCHAR isoData;
  363. PFAST_ISO_DATA fastIsoData;
  364. // ULONG cf;
  365. fastIsoData = &Endpoint->FastIsoData;
  366. i = RelativeFrame;
  367. transferDescriptor = (PHW_TRANSFER_DESCRIPTOR)
  368. (fastIsoData->IsoTDListVa + (i*32));
  369. if (transferDescriptor->Active &&
  370. Count) {
  371. // TD was initialized but and set active
  372. // but never accessed.
  373. // count as a HW miss
  374. deviceExtension->IsoStats.HWIsoMissedCount++;
  375. deviceExtension->IsoStats.IsoPacketNotAccesed++;
  376. UHCD_KdPrint((3, "'Fast ISO HWMiss = %d\n",
  377. deviceExtension->IsoStats.HWIsoMissedCount));
  378. }
  379. // mark inactive and set the id to
  380. // 'recycled'
  381. transferDescriptor->Frame = 0xffffffff;
  382. transferDescriptor->Active = 0;
  383. return transferDescriptor;
  384. }
  385. NTSTATUS
  386. UHCD_ProcessFastIsoTransfer(
  387. IN PDEVICE_OBJECT DeviceObject,
  388. IN PUHCD_ENDPOINT Endpoint,
  389. IN PIRP Irp,
  390. IN PHCD_URB Urb
  391. )
  392. /*++
  393. Routine Description:
  394. process a fast ios transfer
  395. Arguments:
  396. Return Value:
  397. --*/
  398. {
  399. PHW_TRANSFER_DESCRIPTOR transferDescriptor;
  400. PDEVICE_EXTENSION deviceExtension;
  401. ULONG i, nextPacket, offset, length;
  402. ULONG bytesTransferred = 0;
  403. PUCHAR isoData, currentVa;
  404. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  405. // loop thru the packets in the URB
  406. // all we have to do is compute the relative TD and copy the client
  407. // data to it
  408. currentVa =
  409. MmGetMdlVirtualAddress(Urb->HcdUrbCommonTransfer.TransferBufferMDL);
  410. for (i=0; i < Urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  411. transferDescriptor =
  412. UHCD_GetRelativeTD(DeviceObject,
  413. Endpoint,
  414. Urb->UrbIsochronousTransfer.StartFrame+i,
  415. &isoData);
  416. if (transferDescriptor != NULL) {
  417. //
  418. // Prepare the buffer part of the TD.
  419. //
  420. offset =
  421. Urb->UrbIsochronousTransfer.IsoPacket[i].Offset;
  422. nextPacket = i+1;
  423. if (nextPacket >=
  424. Urb->UrbIsochronousTransfer.NumberOfPackets) {
  425. // this is the last packet
  426. length = Urb->UrbIsochronousTransfer.TransferBufferLength -
  427. offset;
  428. } else {
  429. // compute length based on offset of next packet
  430. UHCD_ASSERT(Urb->UrbIsochronousTransfer.IsoPacket[nextPacket].Offset >
  431. offset);
  432. length = Urb->UrbIsochronousTransfer.IsoPacket[nextPacket].Offset -
  433. offset;
  434. }
  435. UHCD_ASSERT(length <= Endpoint->MaxPacketSize);
  436. Urb->UrbIsochronousTransfer.IsoPacket[i].Length = 0;
  437. Urb->UrbIsochronousTransfer.IsoPacket[i].Status =
  438. USBD_STATUS_SUCCESS;
  439. UHCD_KdPrint((2, "'Fast ISO xfer TD = %x\n", transferDescriptor));
  440. UHCD_KdPrint((2, "'offset 0x%x len 0x%x\n", offset, length));
  441. UHCD_KdPrint((2, "'transfer buffer %x iso data %x\n",
  442. currentVa, isoData));
  443. // copy the client data to our DMA buffer
  444. RtlCopyMemory(isoData,
  445. currentVa+offset,
  446. length);
  447. bytesTransferred += length;
  448. transferDescriptor->MaxLength =
  449. UHCD_SYSTEM_TO_USB_BUFFER_LENGTH(length);
  450. // if the active bit is still set then this TD has
  451. // not been processed by HW
  452. if (transferDescriptor->Active &&
  453. transferDescriptor->Frame == 0xabadbabe) {
  454. // we have an overrun
  455. TEST_TRAP();
  456. } else if (transferDescriptor->Active) {
  457. // for some reason HW did not access this TD
  458. deviceExtension->IsoStats.HWIsoMissedCount++;
  459. deviceExtension->IsoStats.IsoPacketNotAccesed++;
  460. UHCD_KdPrint((3, "'Fast ISO HWMiss = %d\n",
  461. deviceExtension->IsoStats.HWIsoMissedCount));
  462. }
  463. transferDescriptor->Active = 1;
  464. transferDescriptor->Frame = 0xabadbabe;
  465. transferDescriptor->InterruptOnComplete = 1;
  466. UHCD_Debug_DumpTD(transferDescriptor);
  467. }
  468. }
  469. // now complete the transfer
  470. // since we double buffer the client data we can actually
  471. // complete the transfer before the data is actually transmitted
  472. // on the bus.
  473. Urb->UrbIsochronousTransfer.ErrorCount = 0;
  474. Urb->HcdUrbCommonTransfer.Status =
  475. USBD_STATUS_SUCCESS;
  476. Urb->HcdUrbCommonTransfer.TransferBufferLength =
  477. bytesTransferred;
  478. deviceExtension->Stats.BytesTransferred +=
  479. Urb->HcdUrbCommonTransfer.TransferBufferLength;
  480. deviceExtension->IsoStats.IsoBytesTransferred +=
  481. Urb->HcdUrbCommonTransfer.TransferBufferLength;
  482. if (Irp != NULL) {
  483. InsertTailList(&deviceExtension->FastIsoTransferList,
  484. &HCD_AREA(Urb).HcdListEntry);
  485. }
  486. //TEST_TRAP();
  487. return STATUS_PENDING;
  488. }
  489. NTSTATUS
  490. UHCD_SubmitFastIsoUrb(
  491. IN PDEVICE_OBJECT DeviceObject,
  492. IN PURB Urb
  493. )
  494. /*++
  495. Routine Description:
  496. Arguments:
  497. Context - DeviceData for this USB controller.
  498. Return Value:
  499. nt status code for operation
  500. --*/
  501. {
  502. NTSTATUS ntStatus = STATUS_NOT_SUPPORTED;
  503. PHCD_URB hcdUrb;
  504. PDEVICE_EXTENSION deviceExtension;
  505. PUHCD_ENDPOINT endpoint;
  506. hcdUrb = (PHCD_URB) Urb;
  507. endpoint = HCD_AREA(hcdUrb).HcdEndpoint;
  508. ASSERT_ENDPOINT(endpoint);
  509. LOGENTRY(LOG_ISO,'subI', endpoint, hcdUrb, 0);
  510. UHCD_WakeIdle(DeviceObject);
  511. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  512. if (endpoint->EndpointFlags & EPFLAG_FAST_ISO) {
  513. UHCD_ValidateIsoUrb(DeviceObject,
  514. endpoint,
  515. hcdUrb);
  516. if (URB_HEADER(Urb).Status == USBD_STATUS_BAD_START_FRAME) {
  517. LOGENTRY(LOG_ISO,'Badf', 0, hcdUrb, 0);
  518. deviceExtension->IsoStats.BadStartFrame++;
  519. // NOTE: we only allow one urb per iso request
  520. // since we pended the original request bump
  521. // the pending count so we'll complete this request
  522. ntStatus = STATUS_INVALID_PARAMETER;
  523. } else {
  524. LOGENTRY(LOG_ISO,'rtmI', endpoint,
  525. hcdUrb->UrbIsochronousTransfer.StartFrame, 0);
  526. // Advance the next free StartFrame for this endpoint to be the
  527. // frame immediately following the last frame of this transfer.
  528. //
  529. endpoint->CurrentFrame = hcdUrb->UrbIsochronousTransfer.StartFrame +
  530. hcdUrb->UrbIsochronousTransfer.NumberOfPackets;
  531. //
  532. // we lose our virginity when the first transfer starts
  533. //
  534. CLR_EPFLAG(endpoint, EPFLAG_VIRGIN);
  535. UHCD_ProcessFastIsoTransfer(
  536. DeviceObject,
  537. endpoint,
  538. NULL,
  539. hcdUrb);
  540. // we always succeed a fast_iso request
  541. ntStatus = STATUS_SUCCESS;
  542. }
  543. }
  544. return ntStatus;
  545. }