Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1850 lines
53 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. isorwr.c
  5. Abstract:
  6. This file has dispatch routines for read and write.
  7. Environment:
  8. Kernel mode
  9. Notes:
  10. Copyright (c) 2000 Microsoft Corporation.
  11. All Rights Reserved.
  12. --*/
  13. #include "isousb.h"
  14. #include "isopnp.h"
  15. #include "isopwr.h"
  16. #include "isodev.h"
  17. #include "isowmi.h"
  18. #include "isousr.h"
  19. #include "isorwr.h"
  20. #include "isostrm.h"
  21. NTSTATUS
  22. IsoUsb_DispatchReadWrite(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PIRP Irp
  25. )
  26. /*++
  27. Routine Description:
  28. This routine does some validation and
  29. invokes appropriate function to perform
  30. Isoch transfer
  31. Arguments:
  32. DeviceObject - pointer to device object
  33. Irp - I/O request packet
  34. Return Value:
  35. NT status value
  36. --*/
  37. {
  38. ULONG totalLength;
  39. ULONG packetSize;
  40. NTSTATUS ntStatus;
  41. PFILE_OBJECT fileObject;
  42. PDEVICE_EXTENSION deviceExtension;
  43. PIO_STACK_LOCATION irpStack;
  44. PFILE_OBJECT_CONTENT fileObjectContent;
  45. PUSBD_PIPE_INFORMATION pipeInformation;
  46. //
  47. // initialize vars
  48. //
  49. irpStack = IoGetCurrentIrpStackLocation(Irp);
  50. fileObject = irpStack->FileObject;
  51. totalLength = 0;
  52. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  53. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite - begins\n"));
  54. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
  55. IsoUsb_IoIncrement(deviceExtension);
  56. if(deviceExtension->DeviceState != Working) {
  57. IsoUsb_DbgPrint(1, ("Invalid device state\n"));
  58. ntStatus = STATUS_INVALID_DEVICE_STATE;
  59. goto IsoUsb_DispatchReadWrite_Exit;
  60. }
  61. //
  62. // make sure that the selective suspend request has been completed.
  63. //
  64. if(deviceExtension->SSEnable) {
  65. //
  66. // It is true that the client driver cancelled the selective suspend
  67. // request in the dispatch routine for create Irps.
  68. // But there is no guarantee that it has indeed completed.
  69. // so wait on the NoIdleReqPendEvent and proceed only if this event
  70. // is signalled.
  71. //
  72. IsoUsb_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n"));
  73. KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
  74. Executive,
  75. KernelMode,
  76. FALSE,
  77. NULL);
  78. }
  79. //
  80. // obtain the pipe information for read
  81. // and write from the fileobject.
  82. //
  83. if(fileObject && fileObject->FsContext) {
  84. fileObjectContent = (PFILE_OBJECT_CONTENT) fileObject->FsContext;
  85. pipeInformation = (PUSBD_PIPE_INFORMATION)
  86. fileObjectContent->PipeInformation;
  87. }
  88. else {
  89. IsoUsb_DbgPrint(1, ("Invalid device state\n"));
  90. ntStatus = STATUS_INVALID_DEVICE_STATE;
  91. goto IsoUsb_DispatchReadWrite_Exit;
  92. }
  93. if((pipeInformation == NULL) ||
  94. (UsbdPipeTypeIsochronous != pipeInformation->PipeType)) {
  95. IsoUsb_DbgPrint(1, ("Incorrect pipe\n"));
  96. ntStatus = STATUS_INVALID_DEVICE_STATE;
  97. goto IsoUsb_DispatchReadWrite_Exit;
  98. }
  99. if(Irp->MdlAddress) {
  100. totalLength = MmGetMdlByteCount(Irp->MdlAddress);
  101. }
  102. if(totalLength == 0) {
  103. IsoUsb_DbgPrint(1, ("Transfer data length = 0\n"));
  104. ntStatus = STATUS_SUCCESS;
  105. goto IsoUsb_DispatchReadWrite_Exit;
  106. }
  107. //
  108. // each packet can hold this much info
  109. //
  110. packetSize = pipeInformation->MaximumPacketSize;
  111. if(packetSize == 0) {
  112. IsoUsb_DbgPrint(1, ("Invalid parameter\n"));
  113. ntStatus = STATUS_INVALID_PARAMETER;
  114. goto IsoUsb_DispatchReadWrite_Exit;
  115. }
  116. //
  117. // atleast packet worth of data to be transferred.
  118. //
  119. if(totalLength < packetSize) {
  120. IsoUsb_DbgPrint(1, ("Atleast packet worth of data..\n"));
  121. ntStatus = STATUS_INVALID_PARAMETER;
  122. goto IsoUsb_DispatchReadWrite_Exit;
  123. }
  124. // perform reset. if there are some active transfers queued up
  125. // for this endpoint then the reset pipe will fail.
  126. //
  127. IsoUsb_ResetPipe(DeviceObject, pipeInformation);
  128. if(deviceExtension->IsDeviceHighSpeed) {
  129. ntStatus = PerformHighSpeedIsochTransfer(DeviceObject,
  130. pipeInformation,
  131. Irp,
  132. totalLength);
  133. }
  134. else {
  135. ntStatus = PerformFullSpeedIsochTransfer(DeviceObject,
  136. pipeInformation,
  137. Irp,
  138. totalLength);
  139. }
  140. return ntStatus;
  141. IsoUsb_DispatchReadWrite_Exit:
  142. Irp->IoStatus.Status = ntStatus;
  143. Irp->IoStatus.Information = 0;
  144. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  145. IsoUsb_DbgPrint(3, ("IsoUsb_DispatchReadWrite::"));
  146. IsoUsb_IoDecrement(deviceExtension);
  147. IsoUsb_DbgPrint(3, ("-------------------------------\n"));
  148. return ntStatus;
  149. }
  150. NTSTATUS
  151. PerformHighSpeedIsochTransfer(
  152. IN PDEVICE_OBJECT DeviceObject,
  153. IN PUSBD_PIPE_INFORMATION PipeInformation,
  154. IN PIRP Irp,
  155. IN ULONG TotalLength
  156. )
  157. /*++
  158. Routine Description:
  159. High Speed Isoch Transfer requires packets in multiples of 8.
  160. (Argument: 8 micro-frames per ms frame)
  161. Another restriction is that each Irp/Urb pair can be associated
  162. with a max of 1024 packets.
  163. Here is one of the ways of creating Irp/Urb pairs.
  164. Depending on the characteristics of real-world device,
  165. the algorithm may be different
  166. This algorithm will distribute data evenly among all the packets.
  167. Input:
  168. TotalLength - no. of bytes to be transferred.
  169. Other parameters:
  170. packetSize - max size of each packet for this pipe.
  171. Implementation Details:
  172. Step 1:
  173. ASSERT(TotalLength >= 8)
  174. Step 2:
  175. Find the exact number of packets required to transfer all of this data
  176. numberOfPackets = (TotalLength + packetSize - 1) / packetSize
  177. Step 3:
  178. Number of packets in multiples of 8.
  179. if(0 == (numberOfPackets % 8)) {
  180. actualPackets = numberOfPackets;
  181. }
  182. else {
  183. actualPackets = numberOfPackets +
  184. (8 - (numberOfPackets % 8));
  185. }
  186. Step 4:
  187. Determine the min. data in each packet.
  188. minDataInEachPacket = TotalLength / actualPackets;
  189. Step 5:
  190. After placing min data in each packet,
  191. determine how much data is left to be distributed.
  192. dataLeftToBeDistributed = TotalLength -
  193. (minDataInEachPacket * actualPackets);
  194. Step 6:
  195. Start placing the left over data in the packets
  196. (above the min data already placed)
  197. numberOfPacketsFilledToBrim = dataLeftToBeDistributed /
  198. (packetSize - minDataInEachPacket);
  199. Step 7:
  200. determine if there is any more data left.
  201. dataLeftToBeDistributed -= (numberOfPacketsFilledToBrim *
  202. (packetSize - minDataInEachPacket));
  203. Step 8:
  204. The "dataLeftToBeDistributed" is placed in the packet at index
  205. "numberOfPacketsFilledToBrim"
  206. Algorithm at play:
  207. TotalLength = 8193
  208. packetSize = 8
  209. Step 1
  210. Step 2
  211. numberOfPackets = (8193 + 8 - 1) / 8 = 1025
  212. Step 3
  213. actualPackets = 1025 + 7 = 1032
  214. Step 4
  215. minDataInEachPacket = 8193 / 1032 = 7 bytes
  216. Step 5
  217. dataLeftToBeDistributed = 8193 - (7 * 1032) = 969.
  218. Step 6
  219. numberOfPacketsFilledToBrim = 969 / (8 - 7) = 969.
  220. Step 7
  221. dataLeftToBeDistributed = 969 - (969 * 1) = 0.
  222. Step 8
  223. Done :)
  224. Another algorithm
  225. Completely fill up (as far as possible) the early packets.
  226. Place 1 byte each in the rest of them.
  227. Ensure that the total number of packets is multiple of 8.
  228. This routine then
  229. 1. creates a ISOUSB_RW_CONTEXT for each
  230. read/write to be performed.
  231. 2. creates SUB_CONTEXT for each irp/urb pair.
  232. (Each irp/urb pair can transfer a max of 1024 packets.)
  233. 3. All the irp/urb pairs are initialized
  234. 4. The subsidiary irps (of the irp/urb pair) are passed
  235. down the stack at once.
  236. 5. The main Read/Write irp is pending
  237. Arguments:
  238. DeviceObject - pointer to device object
  239. Irp - I/O request packet
  240. Return Value:
  241. NT status value
  242. --*/
  243. {
  244. ULONG i;
  245. ULONG j;
  246. ULONG numIrps;
  247. ULONG stageSize;
  248. ULONG contextSize;
  249. ULONG packetSize;
  250. ULONG numberOfPackets;
  251. ULONG actualPackets;
  252. ULONG minDataInEachPacket;
  253. ULONG dataLeftToBeDistributed;
  254. ULONG numberOfPacketsFilledToBrim;
  255. CCHAR stackSize;
  256. KIRQL oldIrql;
  257. PUCHAR virtualAddress;
  258. BOOLEAN read;
  259. NTSTATUS ntStatus;
  260. PDEVICE_EXTENSION deviceExtension;
  261. PIO_STACK_LOCATION irpStack;
  262. PIO_STACK_LOCATION nextStack;
  263. PISOUSB_RW_CONTEXT rwContext;
  264. //
  265. // initialize vars
  266. //
  267. irpStack = IoGetCurrentIrpStackLocation(Irp);
  268. read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
  269. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  270. if(TotalLength < 8) {
  271. ntStatus = STATUS_INVALID_PARAMETER;
  272. goto PerformHighSpeedIsochTransfer_Exit;
  273. }
  274. //
  275. // each packet can hold this much info
  276. //
  277. packetSize = PipeInformation->MaximumPacketSize;
  278. numberOfPackets = (TotalLength + packetSize - 1) / packetSize;
  279. if(0 == (numberOfPackets % 8)) {
  280. actualPackets = numberOfPackets;
  281. }
  282. else {
  283. //
  284. // we need multiple of 8 packets only.
  285. //
  286. actualPackets = numberOfPackets +
  287. (8 - (numberOfPackets % 8));
  288. }
  289. minDataInEachPacket = TotalLength / actualPackets;
  290. if(minDataInEachPacket == packetSize) {
  291. numberOfPacketsFilledToBrim = actualPackets;
  292. dataLeftToBeDistributed = 0;
  293. IsoUsb_DbgPrint(1, ("TotalLength = %d\n", TotalLength));
  294. IsoUsb_DbgPrint(1, ("PacketSize = %d\n", packetSize));
  295. IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytes\n",
  296. numberOfPacketsFilledToBrim,
  297. packetSize));
  298. }
  299. else {
  300. dataLeftToBeDistributed = TotalLength -
  301. (minDataInEachPacket * actualPackets);
  302. numberOfPacketsFilledToBrim = dataLeftToBeDistributed /
  303. (packetSize - minDataInEachPacket);
  304. dataLeftToBeDistributed -= (numberOfPacketsFilledToBrim *
  305. (packetSize - minDataInEachPacket));
  306. IsoUsb_DbgPrint(1, ("TotalLength = %d\n", TotalLength));
  307. IsoUsb_DbgPrint(1, ("PacketSize = %d\n", packetSize));
  308. IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytes\n",
  309. numberOfPacketsFilledToBrim,
  310. packetSize));
  311. if(dataLeftToBeDistributed) {
  312. IsoUsb_DbgPrint(1, ("One packet has %d bytes\n",
  313. minDataInEachPacket + dataLeftToBeDistributed));
  314. IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytes\n",
  315. actualPackets - (numberOfPacketsFilledToBrim + 1),
  316. minDataInEachPacket));
  317. }
  318. else {
  319. IsoUsb_DbgPrint(1, ("Each of %d packets has %d bytes\n",
  320. actualPackets - numberOfPacketsFilledToBrim,
  321. minDataInEachPacket));
  322. }
  323. }
  324. //
  325. // determine how many stages of transfer needs to be done.
  326. // in other words, how many irp/urb pairs required.
  327. // this irp/urb pair is also called the subsidiary irp/urb pair
  328. //
  329. numIrps = (actualPackets + 1023) / 1024;
  330. IsoUsb_DbgPrint(1, ("PeformHighSpeedIsochTransfer::numIrps = %d\n", numIrps));
  331. //
  332. // for every read/write transfer
  333. // we create an ISOUSB_RW_CONTEXT
  334. //
  335. // initialize the read/write context
  336. //
  337. contextSize = sizeof(ISOUSB_RW_CONTEXT);
  338. rwContext = (PISOUSB_RW_CONTEXT) ExAllocatePool(NonPagedPool,
  339. contextSize);
  340. if(rwContext == NULL) {
  341. IsoUsb_DbgPrint(1, ("Failed to alloc mem for rwContext\n"));
  342. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  343. goto PerformHighSpeedIsochTransfer_Exit;
  344. }
  345. RtlZeroMemory(rwContext, contextSize);
  346. //
  347. // allocate memory for every stage context -
  348. // subcontext has state information for every irp/urb pair.
  349. //
  350. rwContext->SubContext = (PSUB_CONTEXT)
  351. ExAllocatePool(NonPagedPool,
  352. numIrps * sizeof(SUB_CONTEXT));
  353. if(rwContext->SubContext == NULL) {
  354. IsoUsb_DbgPrint(1, ("Failed to alloc mem for SubContext\n"));
  355. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  356. ExFreePool(rwContext);
  357. goto PerformHighSpeedIsochTransfer_Exit;
  358. }
  359. RtlZeroMemory(rwContext->SubContext, numIrps * sizeof(SUB_CONTEXT));
  360. rwContext->RWIrp = Irp;
  361. rwContext->Lock = 2;
  362. rwContext->NumIrps = numIrps;
  363. rwContext->IrpsPending = numIrps;
  364. rwContext->DeviceExtension = deviceExtension;
  365. KeInitializeSpinLock(&rwContext->SpinLock);
  366. //
  367. // save the rwContext pointer in the tail union.
  368. //
  369. Irp->Tail.Overlay.DriverContext[0] = (PVOID) rwContext;
  370. stackSize = deviceExtension->TopOfStackDeviceObject->StackSize + 1;
  371. virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
  372. for(i = 0; i < numIrps; i++) {
  373. PIRP subIrp;
  374. PURB subUrb;
  375. PMDL subMdl;
  376. ULONG nPackets;
  377. ULONG siz;
  378. ULONG offset;
  379. //
  380. // for every stage of transfer we need to do the following
  381. // tasks
  382. // 1. allocate an irp
  383. // 2. allocate an urb
  384. // 3. allocate a mdl.
  385. //
  386. // create a subsidiary irp
  387. //
  388. subIrp = IoAllocateIrp(stackSize, FALSE);
  389. if(subIrp == NULL) {
  390. IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context irp\n"));
  391. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  392. goto PerformHighSpeedIsochTransfer_Free;
  393. }
  394. rwContext->SubContext[i].SubIrp = subIrp;
  395. if(actualPackets <= 1024) {
  396. nPackets = actualPackets;
  397. actualPackets = 0;
  398. }
  399. else {
  400. nPackets = 1024;
  401. actualPackets -= 1024;
  402. }
  403. IsoUsb_DbgPrint(1, ("nPackets = %d for Irp/URB pair %d\n", nPackets, i));
  404. ASSERT(nPackets <= 1024);
  405. siz = GET_ISO_URB_SIZE(nPackets);
  406. //
  407. // create a subsidiary urb.
  408. //
  409. subUrb = (PURB) ExAllocatePool(NonPagedPool, siz);
  410. if(subUrb == NULL) {
  411. IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context urb\n"));
  412. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  413. goto PerformHighSpeedIsochTransfer_Free;
  414. }
  415. rwContext->SubContext[i].SubUrb = subUrb;
  416. if(nPackets > numberOfPacketsFilledToBrim) {
  417. stageSize = packetSize * numberOfPacketsFilledToBrim;
  418. stageSize += (minDataInEachPacket *
  419. (nPackets - numberOfPacketsFilledToBrim));
  420. stageSize += dataLeftToBeDistributed;
  421. }
  422. else {
  423. stageSize = packetSize * nPackets;
  424. }
  425. //
  426. // allocate a mdl.
  427. //
  428. subMdl = IoAllocateMdl((PVOID) virtualAddress,
  429. stageSize,
  430. FALSE,
  431. FALSE,
  432. NULL);
  433. if(subMdl == NULL) {
  434. IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context mdl\n"));
  435. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  436. goto PerformHighSpeedIsochTransfer_Free;
  437. }
  438. IoBuildPartialMdl(Irp->MdlAddress,
  439. subMdl,
  440. (PVOID) virtualAddress,
  441. stageSize);
  442. rwContext->SubContext[i].SubMdl = subMdl;
  443. virtualAddress += stageSize;
  444. TotalLength -= stageSize;
  445. //
  446. // Initialize the subsidiary urb
  447. //
  448. RtlZeroMemory(subUrb, siz);
  449. subUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
  450. subUrb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
  451. subUrb->UrbIsochronousTransfer.PipeHandle = PipeInformation->PipeHandle;
  452. if(read) {
  453. IsoUsb_DbgPrint(1, ("read\n"));
  454. subUrb->UrbIsochronousTransfer.TransferFlags =
  455. USBD_TRANSFER_DIRECTION_IN;
  456. }
  457. else {
  458. IsoUsb_DbgPrint(1, ("write\n"));
  459. subUrb->UrbIsochronousTransfer.TransferFlags =
  460. USBD_TRANSFER_DIRECTION_OUT;
  461. }
  462. subUrb->UrbIsochronousTransfer.TransferBufferLength = stageSize;
  463. subUrb->UrbIsochronousTransfer.TransferBufferMDL = subMdl;
  464. /*
  465. This is a way to set the start frame and NOT specify ASAP flag.
  466. subUrb->UrbIsochronousTransfer.StartFrame =
  467. IsoUsb_GetCurrentFrame(DeviceObject, Irp) +
  468. SOME_LATENCY;
  469. */
  470. subUrb->UrbIsochronousTransfer.TransferFlags |=
  471. USBD_START_ISO_TRANSFER_ASAP;
  472. subUrb->UrbIsochronousTransfer.NumberOfPackets = nPackets;
  473. subUrb->UrbIsochronousTransfer.UrbLink = NULL;
  474. //
  475. // set the offsets for every packet for reads/writes
  476. //
  477. if(read) {
  478. offset = 0;
  479. for(j = 0; j < nPackets; j++) {
  480. subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
  481. subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
  482. if(numberOfPacketsFilledToBrim) {
  483. offset += packetSize;
  484. numberOfPacketsFilledToBrim--;
  485. stageSize -= packetSize;
  486. }
  487. else if(dataLeftToBeDistributed) {
  488. offset += (minDataInEachPacket + dataLeftToBeDistributed);
  489. stageSize -= (minDataInEachPacket + dataLeftToBeDistributed);
  490. dataLeftToBeDistributed = 0;
  491. }
  492. else {
  493. offset += minDataInEachPacket;
  494. stageSize -= minDataInEachPacket;
  495. }
  496. }
  497. ASSERT(stageSize == 0);
  498. }
  499. else {
  500. offset = 0;
  501. for(j = 0; j < nPackets; j++) {
  502. subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
  503. if(numberOfPacketsFilledToBrim) {
  504. subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = packetSize;
  505. offset += packetSize;
  506. numberOfPacketsFilledToBrim--;
  507. stageSize -= packetSize;
  508. }
  509. else if(dataLeftToBeDistributed) {
  510. subUrb->UrbIsochronousTransfer.IsoPacket[j].Length =
  511. minDataInEachPacket + dataLeftToBeDistributed;
  512. offset += (minDataInEachPacket + dataLeftToBeDistributed);
  513. stageSize -= (minDataInEachPacket + dataLeftToBeDistributed);
  514. dataLeftToBeDistributed = 0;
  515. }
  516. else {
  517. subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = minDataInEachPacket;
  518. offset += minDataInEachPacket;
  519. stageSize -= minDataInEachPacket;
  520. }
  521. }
  522. ASSERT(stageSize == 0);
  523. }
  524. IoSetNextIrpStackLocation(subIrp);
  525. nextStack = IoGetCurrentIrpStackLocation(subIrp);
  526. nextStack->DeviceObject = DeviceObject;
  527. nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
  528. nextStack->Parameters.Others.Argument2 = (PVOID) subMdl;
  529. nextStack = IoGetNextIrpStackLocation(subIrp);
  530. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  531. nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
  532. nextStack->Parameters.DeviceIoControl.IoControlCode =
  533. IOCTL_INTERNAL_USB_SUBMIT_URB;
  534. IoSetCompletionRoutine(subIrp,
  535. (PIO_COMPLETION_ROUTINE) IsoUsb_SinglePairComplete,
  536. (PVOID) rwContext,
  537. TRUE,
  538. TRUE,
  539. TRUE);
  540. }
  541. //
  542. // while we were busy create subsidiary irp/urb pairs..
  543. // the main read/write irp may have been cancelled !!
  544. //
  545. KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
  546. IoSetCancelRoutine(Irp, IsoUsb_CancelReadWrite);
  547. if(Irp->Cancel) {
  548. //
  549. // The Cancel flag for the Irp has been set.
  550. //
  551. IsoUsb_DbgPrint(3, ("Cancel flag set\n"));
  552. ntStatus = STATUS_CANCELLED;
  553. if(IoSetCancelRoutine(Irp, NULL)) {
  554. //
  555. // But the I/O manager did not call our cancel routine.
  556. // we need to free the 1) irp, 2) urb and 3) mdl for every
  557. // stage and complete the main Irp after releasing the lock
  558. //
  559. IsoUsb_DbgPrint(3, ("cancellation routine NOT run\n"));
  560. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  561. goto PerformHighSpeedIsochTransfer_Free;
  562. }
  563. else {
  564. //
  565. // The cancel routine will resume the moment we release the lock.
  566. //
  567. for(j = 0; j < numIrps; j++) {
  568. if(rwContext->SubContext[j].SubUrb) {
  569. ExFreePool(rwContext->SubContext[j].SubUrb);
  570. rwContext->SubContext[j].SubUrb = NULL;
  571. }
  572. if(rwContext->SubContext[j].SubMdl) {
  573. IoFreeMdl(rwContext->SubContext[j].SubMdl);
  574. rwContext->SubContext[j].SubMdl = NULL;
  575. }
  576. }
  577. IoMarkIrpPending(Irp);
  578. //
  579. // it is the job of the cancellation routine to free
  580. // sub-context irps, release rwContext and complete
  581. // the main readwrite irp
  582. //
  583. InterlockedDecrement(&rwContext->Lock);
  584. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  585. return STATUS_PENDING;
  586. }
  587. }
  588. else {
  589. //
  590. // normal processing
  591. //
  592. IsoUsb_DbgPrint(3, ("normal processing\n"));
  593. IoMarkIrpPending(Irp);
  594. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  595. for(j = 0; j < numIrps; j++) {
  596. IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
  597. IsoUsb_IoIncrement(deviceExtension);
  598. IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  599. rwContext->SubContext[j].SubIrp);
  600. }
  601. return STATUS_PENDING;
  602. }
  603. PerformHighSpeedIsochTransfer_Free:
  604. for(j = 0; j < numIrps; j++) {
  605. if(rwContext->SubContext[j].SubIrp) {
  606. IoFreeIrp(rwContext->SubContext[j].SubIrp);
  607. rwContext->SubContext[j].SubIrp = NULL;
  608. }
  609. if(rwContext->SubContext[j].SubUrb) {
  610. ExFreePool(rwContext->SubContext[j].SubUrb);
  611. rwContext->SubContext[j].SubUrb = NULL;
  612. }
  613. if(rwContext->SubContext[j].SubMdl) {
  614. IoFreeMdl(rwContext->SubContext[j].SubMdl);
  615. rwContext->SubContext[j].SubMdl = NULL;
  616. }
  617. }
  618. ExFreePool(rwContext->SubContext);
  619. ExFreePool(rwContext);
  620. PerformHighSpeedIsochTransfer_Exit:
  621. Irp->IoStatus.Status = ntStatus;
  622. Irp->IoStatus.Information = 0;
  623. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  624. IsoUsb_DbgPrint(3, ("PerformHighSpeedIsochTransfer::"));
  625. IsoUsb_IoDecrement(deviceExtension);
  626. IsoUsb_DbgPrint(3, ("-------------------------------\n"));
  627. return ntStatus;
  628. }
  629. NTSTATUS
  630. PerformFullSpeedIsochTransfer(
  631. IN PDEVICE_OBJECT DeviceObject,
  632. IN PUSBD_PIPE_INFORMATION PipeInformation,
  633. IN PIRP Irp,
  634. IN ULONG TotalLength
  635. )
  636. /*++
  637. Routine Description:
  638. This routine
  639. 1. creates a ISOUSB_RW_CONTEXT for every
  640. read/write to be performed.
  641. 2. creates SUB_CONTEXT for each irp/urb pair.
  642. (Each irp/urb pair can transfer only 255 packets.)
  643. 3. All the irp/urb pairs are initialized
  644. 4. The subsidiary irps (of the irp/urb pair) are passed
  645. down the stack at once.
  646. 5. The main Read/Write irp is pending
  647. Arguments:
  648. DeviceObject - pointer to device object
  649. PipeInformation - USBD_PIPE_INFORMATION
  650. Irp - I/O request packet
  651. TotalLength - no. of bytes to be transferred
  652. Return Value:
  653. NT status value
  654. --*/
  655. {
  656. ULONG i;
  657. ULONG j;
  658. ULONG packetSize;
  659. ULONG numIrps;
  660. ULONG stageSize;
  661. ULONG contextSize;
  662. CCHAR stackSize;
  663. KIRQL oldIrql;
  664. PUCHAR virtualAddress;
  665. BOOLEAN read;
  666. NTSTATUS ntStatus;
  667. PDEVICE_EXTENSION deviceExtension;
  668. PIO_STACK_LOCATION irpStack;
  669. PIO_STACK_LOCATION nextStack;
  670. PISOUSB_RW_CONTEXT rwContext;
  671. //
  672. // initialize vars
  673. //
  674. irpStack = IoGetCurrentIrpStackLocation(Irp);
  675. read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
  676. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  677. IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer - begins\n"));
  678. /*
  679. if(read) {
  680. pipeInformation = &deviceExtension->UsbInterface->Pipes[ISOCH_IN_PIPE_INDEX];
  681. }
  682. else {
  683. pipeInformation = &deviceExtension->UsbInterface->Pipes[ISOCH_OUT_PIPE_INDEX];
  684. }
  685. */
  686. //
  687. // each packet can hold this much info
  688. //
  689. packetSize = PipeInformation->MaximumPacketSize;
  690. IsoUsb_DbgPrint(3, ("totalLength = %d\n", TotalLength));
  691. IsoUsb_DbgPrint(3, ("packetSize = %d\n", packetSize));
  692. //
  693. // there is an inherent limit on the number of packets
  694. // that can be passed down the stack with each
  695. // irp/urb pair (255)
  696. // if the number of required packets is > 255,
  697. // we shall create "required-packets / 255 + 1" number
  698. // of irp/urb pairs.
  699. // Each irp/urb pair transfer is also called a stage transfer.
  700. //
  701. if(TotalLength > (packetSize * 255)) {
  702. stageSize = packetSize * 255;
  703. }
  704. else {
  705. stageSize = TotalLength;
  706. }
  707. IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::stageSize = %d\n", stageSize));
  708. //
  709. // determine how many stages of transfer needs to be done.
  710. // in other words, how many irp/urb pairs required.
  711. // this irp/urb pair is also called the subsidiary irp/urb pair
  712. //
  713. numIrps = (TotalLength + stageSize - 1) / stageSize;
  714. IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::numIrps = %d\n", numIrps));
  715. //
  716. // for every read/write transfer
  717. // we create an ISOUSB_RW_CONTEXT
  718. //
  719. // initialize the read/write context
  720. //
  721. contextSize = sizeof(ISOUSB_RW_CONTEXT);
  722. rwContext = (PISOUSB_RW_CONTEXT) ExAllocatePool(NonPagedPool,
  723. contextSize);
  724. if(rwContext == NULL) {
  725. IsoUsb_DbgPrint(1, ("Failed to alloc mem for rwContext\n"));
  726. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  727. goto PerformFullSpeedIsochTransfer_Exit;
  728. }
  729. RtlZeroMemory(rwContext, contextSize);
  730. //
  731. // allocate memory for every stage context -
  732. // subcontext has state information for every irp/urb pair.
  733. //
  734. rwContext->SubContext = (PSUB_CONTEXT)
  735. ExAllocatePool(NonPagedPool,
  736. numIrps * sizeof(SUB_CONTEXT));
  737. if(rwContext->SubContext == NULL) {
  738. IsoUsb_DbgPrint(1, ("Failed to alloc mem for SubContext\n"));
  739. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  740. ExFreePool(rwContext);
  741. goto PerformFullSpeedIsochTransfer_Exit;
  742. }
  743. RtlZeroMemory(rwContext->SubContext, numIrps * sizeof(SUB_CONTEXT));
  744. rwContext->RWIrp = Irp;
  745. rwContext->Lock = 2;
  746. rwContext->NumIrps = numIrps;
  747. rwContext->IrpsPending = numIrps;
  748. rwContext->DeviceExtension = deviceExtension;
  749. KeInitializeSpinLock(&rwContext->SpinLock);
  750. //
  751. // save the rwContext pointer in the tail union.
  752. //
  753. Irp->Tail.Overlay.DriverContext[0] = (PVOID) rwContext;
  754. stackSize = deviceExtension->TopOfStackDeviceObject->StackSize + 1;
  755. virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
  756. for(i = 0; i < numIrps; i++) {
  757. PIRP subIrp;
  758. PURB subUrb;
  759. PMDL subMdl;
  760. ULONG nPackets;
  761. ULONG siz;
  762. ULONG offset;
  763. //
  764. // for every stage of transfer we need to do the following
  765. // tasks
  766. // 1. allocate an irp
  767. // 2. allocate an urb
  768. // 3. allocate a mdl.
  769. //
  770. // create a subsidiary irp
  771. //
  772. subIrp = IoAllocateIrp(stackSize, FALSE);
  773. if(subIrp == NULL) {
  774. IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context irp\n"));
  775. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  776. goto PerformFullSpeedIsochTransfer_Free;
  777. }
  778. rwContext->SubContext[i].SubIrp = subIrp;
  779. nPackets = (stageSize + packetSize - 1) / packetSize;
  780. IsoUsb_DbgPrint(3, ("nPackets = %d for Irp/URB pair %d\n", nPackets, i));
  781. ASSERT(nPackets <= 255);
  782. siz = GET_ISO_URB_SIZE(nPackets);
  783. //
  784. // create a subsidiary urb.
  785. //
  786. subUrb = (PURB) ExAllocatePool(NonPagedPool, siz);
  787. if(subUrb == NULL) {
  788. IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context urb\n"));
  789. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  790. goto PerformFullSpeedIsochTransfer_Free;
  791. }
  792. rwContext->SubContext[i].SubUrb = subUrb;
  793. //
  794. // allocate a mdl.
  795. //
  796. subMdl = IoAllocateMdl((PVOID) virtualAddress,
  797. stageSize,
  798. FALSE,
  799. FALSE,
  800. NULL);
  801. if(subMdl == NULL) {
  802. IsoUsb_DbgPrint(1, ("failed to alloc mem for sub context mdl\n"));
  803. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  804. goto PerformFullSpeedIsochTransfer_Free;
  805. }
  806. IoBuildPartialMdl(Irp->MdlAddress,
  807. subMdl,
  808. (PVOID) virtualAddress,
  809. stageSize);
  810. rwContext->SubContext[i].SubMdl = subMdl;
  811. virtualAddress += stageSize;
  812. TotalLength -= stageSize;
  813. //
  814. // Initialize the subsidiary urb
  815. //
  816. RtlZeroMemory(subUrb, siz);
  817. subUrb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
  818. subUrb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
  819. subUrb->UrbIsochronousTransfer.PipeHandle = PipeInformation->PipeHandle;
  820. if(read) {
  821. IsoUsb_DbgPrint(3, ("read\n"));
  822. subUrb->UrbIsochronousTransfer.TransferFlags =
  823. USBD_TRANSFER_DIRECTION_IN;
  824. }
  825. else {
  826. IsoUsb_DbgPrint(3, ("write\n"));
  827. subUrb->UrbIsochronousTransfer.TransferFlags =
  828. USBD_TRANSFER_DIRECTION_OUT;
  829. }
  830. subUrb->UrbIsochronousTransfer.TransferBufferLength = stageSize;
  831. subUrb->UrbIsochronousTransfer.TransferBufferMDL = subMdl;
  832. /*
  833. This is a way to set the start frame and NOT specify ASAP flag.
  834. subUrb->UrbIsochronousTransfer.StartFrame =
  835. IsoUsb_GetCurrentFrame(DeviceObject, Irp) +
  836. SOME_LATENCY;
  837. */
  838. //
  839. // when the client driver sets the ASAP flag, it basically
  840. // guarantees that it will make data available to the HC
  841. // and that the HC should transfer it in the next transfer frame
  842. // for the endpoint.(The HC maintains a next transfer frame
  843. // state variable for each endpoint). By resetting the pipe,
  844. // we make the pipe as virgin. If the data does not get to the HC
  845. // fast enough, the USBD_ISO_PACKET_DESCRIPTOR - Status is
  846. // USBD_STATUS_BAD_START_FRAME on uhci. On ohci it is 0xC000000E.
  847. //
  848. subUrb->UrbIsochronousTransfer.TransferFlags |=
  849. USBD_START_ISO_TRANSFER_ASAP;
  850. subUrb->UrbIsochronousTransfer.NumberOfPackets = nPackets;
  851. subUrb->UrbIsochronousTransfer.UrbLink = NULL;
  852. //
  853. // set the offsets for every packet for reads/writes
  854. //
  855. if(read) {
  856. offset = 0;
  857. for(j = 0; j < nPackets; j++) {
  858. subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
  859. subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
  860. if(stageSize > packetSize) {
  861. offset += packetSize;
  862. stageSize -= packetSize;
  863. }
  864. else {
  865. offset += stageSize;
  866. stageSize = 0;
  867. }
  868. }
  869. }
  870. else {
  871. offset = 0;
  872. for(j = 0; j < nPackets; j++) {
  873. subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
  874. if(stageSize > packetSize) {
  875. subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = packetSize;
  876. offset += packetSize;
  877. stageSize -= packetSize;
  878. }
  879. else {
  880. subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = stageSize;
  881. offset += stageSize;
  882. stageSize = 0;
  883. ASSERT(offset == (subUrb->UrbIsochronousTransfer.IsoPacket[j].Length +
  884. subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset));
  885. }
  886. }
  887. }
  888. IoSetNextIrpStackLocation(subIrp);
  889. nextStack = IoGetCurrentIrpStackLocation(subIrp);
  890. nextStack->DeviceObject = DeviceObject;
  891. nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
  892. nextStack->Parameters.Others.Argument2 = (PVOID) subMdl;
  893. nextStack = IoGetNextIrpStackLocation(subIrp);
  894. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  895. nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
  896. nextStack->Parameters.DeviceIoControl.IoControlCode =
  897. IOCTL_INTERNAL_USB_SUBMIT_URB;
  898. IoSetCompletionRoutine(subIrp,
  899. (PIO_COMPLETION_ROUTINE) IsoUsb_SinglePairComplete,
  900. (PVOID) rwContext,
  901. TRUE,
  902. TRUE,
  903. TRUE);
  904. if(TotalLength > (packetSize * 255)) {
  905. stageSize = packetSize * 255;
  906. }
  907. else {
  908. stageSize = TotalLength;
  909. }
  910. }
  911. //
  912. // while we were busy create subsidiary irp/urb pairs..
  913. // the main read/write irp may have been cancelled !!
  914. //
  915. KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
  916. IoSetCancelRoutine(Irp, IsoUsb_CancelReadWrite);
  917. if(Irp->Cancel) {
  918. //
  919. // The Cancel flag for the Irp has been set.
  920. //
  921. IsoUsb_DbgPrint(3, ("Cancel flag set\n"));
  922. ntStatus = STATUS_CANCELLED;
  923. if(IoSetCancelRoutine(Irp, NULL)) {
  924. //
  925. // But the I/O manager did not call our cancel routine.
  926. // we need to free the 1) irp, 2) urb and 3) mdl for every
  927. // stage and complete the main Irp after releasing the lock
  928. //
  929. IsoUsb_DbgPrint(3, ("cancellation routine NOT run\n"));
  930. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  931. goto PerformFullSpeedIsochTransfer_Free;
  932. }
  933. else {
  934. //
  935. // The cancel routine will resume the moment we release the lock.
  936. //
  937. for(j = 0; j < numIrps; j++) {
  938. if(rwContext->SubContext[j].SubUrb) {
  939. ExFreePool(rwContext->SubContext[j].SubUrb);
  940. rwContext->SubContext[j].SubUrb = NULL;
  941. }
  942. if(rwContext->SubContext[j].SubMdl) {
  943. IoFreeMdl(rwContext->SubContext[j].SubMdl);
  944. rwContext->SubContext[j].SubMdl = NULL;
  945. }
  946. }
  947. IoMarkIrpPending(Irp);
  948. //
  949. // it is the job of the cancellation routine to free
  950. // sub-context irps, release rwContext and complete
  951. // the main readwrite irp
  952. //
  953. InterlockedDecrement(&rwContext->Lock);
  954. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  955. return STATUS_PENDING;
  956. }
  957. }
  958. else {
  959. //
  960. // normal processing
  961. //
  962. IsoUsb_DbgPrint(3, ("normal processing\n"));
  963. IoMarkIrpPending(Irp);
  964. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  965. for(j = 0; j < numIrps; j++) {
  966. IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::"));
  967. IsoUsb_IoIncrement(deviceExtension);
  968. IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  969. rwContext->SubContext[j].SubIrp);
  970. }
  971. return STATUS_PENDING;
  972. }
  973. PerformFullSpeedIsochTransfer_Free:
  974. for(j = 0; j < numIrps; j++) {
  975. if(rwContext->SubContext[j].SubIrp) {
  976. IoFreeIrp(rwContext->SubContext[j].SubIrp);
  977. rwContext->SubContext[j].SubIrp = NULL;
  978. }
  979. if(rwContext->SubContext[j].SubUrb) {
  980. ExFreePool(rwContext->SubContext[j].SubUrb);
  981. rwContext->SubContext[j].SubUrb = NULL;
  982. }
  983. if(rwContext->SubContext[j].SubMdl) {
  984. IoFreeMdl(rwContext->SubContext[j].SubMdl);
  985. rwContext->SubContext[j].SubMdl = NULL;
  986. }
  987. }
  988. ExFreePool(rwContext->SubContext);
  989. ExFreePool(rwContext);
  990. PerformFullSpeedIsochTransfer_Exit:
  991. Irp->IoStatus.Status = ntStatus;
  992. Irp->IoStatus.Information = 0;
  993. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  994. IsoUsb_DbgPrint(3, ("PerformFullSpeedIsochTransfer::"));
  995. IsoUsb_IoDecrement(deviceExtension);
  996. IsoUsb_DbgPrint(3, ("-------------------------------\n"));
  997. return ntStatus;
  998. }
  999. NTSTATUS
  1000. IsoUsb_SinglePairComplete(
  1001. IN PDEVICE_OBJECT DeviceObject,
  1002. IN PIRP Irp,
  1003. IN PVOID Context
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This is the completion routine for the subsidiary irp.
  1008. For every irp/urb pair, we have allocated
  1009. 1. an irp
  1010. 2. an urb
  1011. 3. a mdl.
  1012. Case 1:
  1013. we do NOT free the irp on its completion
  1014. we do free the urb and the mdl.
  1015. Case 1 is executed in Block 3.
  1016. Case 2:
  1017. when we complete the last of the subsidiary irp,
  1018. we check if the cancel routine for the main Irp
  1019. has run. If not, we free all the irps, release
  1020. the subcontext and the context and complete the
  1021. main Irp.we also free the urb and mdl for this
  1022. stage.
  1023. Case 2 is executed in Block 2.
  1024. Case 3:
  1025. when we complete the last of the subsidiary irp,
  1026. we check if the cancel routine for the main Irp
  1027. has run. If yes, we atomically decrement the
  1028. rwContext->Lock field. (the completion routine
  1029. is in race with Cancel routine). If the count is 1,
  1030. the cancel routine will free all the resources.
  1031. we do free the urb and mdl.
  1032. it is expected of the cancellation routine to free
  1033. all the irps, free the subcontext and the context
  1034. and complete the main irp
  1035. Case 3 is executed in Block 1b.
  1036. Case 4:
  1037. when we complete the last of the subsidiary irp,
  1038. we check if the cancel routine for the main Irp
  1039. has run. If yes, we atomically decrement the
  1040. rwContext->Lock field. (the completion routine
  1041. is in race with Cancel routine). If the count is 0,
  1042. we free the irp, subcontext and the context and
  1043. complete the main irp. we also free the urb and
  1044. the mdl for this particular stage.
  1045. the reason we do not free the subsidiary irp at its
  1046. completion is because the cancellation routine can
  1047. run any time.
  1048. Case 4 is executed in Block 1a.
  1049. Arguments:
  1050. DeviceObject - pointer to device object
  1051. Irp - I/O request packet
  1052. Context - context for the completion routine
  1053. Return Value:
  1054. NT status value
  1055. --*/
  1056. {
  1057. PURB urb;
  1058. PMDL mdl;
  1059. PIRP mainIrp;
  1060. KIRQL oldIrql;
  1061. ULONG i;
  1062. ULONG info;
  1063. NTSTATUS ntStatus;
  1064. PDEVICE_EXTENSION deviceExtension;
  1065. PISOUSB_RW_CONTEXT rwContext;
  1066. PIO_STACK_LOCATION irpStack;
  1067. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1068. urb = (PURB) irpStack->Parameters.Others.Argument1;
  1069. mdl = (PMDL) irpStack->Parameters.Others.Argument2;
  1070. info = 0;
  1071. ntStatus = Irp->IoStatus.Status;
  1072. rwContext = (PISOUSB_RW_CONTEXT) Context;
  1073. deviceExtension = rwContext->DeviceExtension;
  1074. IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - begins\n"));
  1075. ASSERT(rwContext);
  1076. KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
  1077. if(NT_SUCCESS(ntStatus) &&
  1078. USBD_SUCCESS(urb->UrbHeader.Status)) {
  1079. rwContext->NumXfer +=
  1080. urb->UrbIsochronousTransfer.TransferBufferLength;
  1081. IsoUsb_DbgPrint(1, ("rwContext->NumXfer = %d\n", rwContext->NumXfer));
  1082. }
  1083. else {
  1084. IsoUsb_DbgPrint(1, ("read-write irp failed with status %X\n", ntStatus));
  1085. IsoUsb_DbgPrint(1, ("urb header status %X\n", urb->UrbHeader.Status));
  1086. }
  1087. for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  1088. IsoUsb_DbgPrint(3, ("IsoPacket[%d].Length = %X IsoPacket[%d].Status = %X\n",
  1089. i,
  1090. urb->UrbIsochronousTransfer.IsoPacket[i].Length,
  1091. i,
  1092. urb->UrbIsochronousTransfer.IsoPacket[i].Status));
  1093. }
  1094. if(InterlockedDecrement(&rwContext->IrpsPending) == 0) {
  1095. IsoUsb_DbgPrint(3, ("no more irps pending\n"));
  1096. if(NT_SUCCESS(ntStatus)) {
  1097. IsoUsb_DbgPrint(1, ("urb start frame %X\n",
  1098. urb->UrbIsochronousTransfer.StartFrame));
  1099. }
  1100. mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);
  1101. ASSERT(mainIrp);
  1102. if(IoSetCancelRoutine(mainIrp, NULL) == NULL) {
  1103. //
  1104. // cancel routine has begun the race
  1105. //
  1106. // Block 1a.
  1107. //
  1108. IsoUsb_DbgPrint(3, ("cancel routine has begun the race\n"));
  1109. if(InterlockedDecrement(&rwContext->Lock) == 0) {
  1110. //
  1111. // do the cleanup job ourselves
  1112. //
  1113. IsoUsb_DbgPrint(3, ("losers do the cleanup\n"));
  1114. for(i = 0; i < rwContext->NumIrps; i++) {
  1115. IoFreeIrp(rwContext->SubContext[i].SubIrp);
  1116. rwContext->SubContext[i].SubIrp = NULL;
  1117. }
  1118. info = rwContext->NumXfer;
  1119. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1120. ExFreePool(rwContext->SubContext);
  1121. ExFreePool(rwContext);
  1122. //
  1123. // if we transferred some data, main Irp completes with success
  1124. //
  1125. IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));
  1126. IsoUsb_DbgPrint(1, ("***\n"));
  1127. mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
  1128. mainIrp->IoStatus.Information = info;
  1129. IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
  1130. IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
  1131. IsoUsb_IoDecrement(deviceExtension);
  1132. IsoUsb_DbgPrint(3, ("-------------------------------\n"));
  1133. goto IsoUsb_SinglePairComplete_Exit;
  1134. }
  1135. else {
  1136. //
  1137. // Block 1b.
  1138. //
  1139. IsoUsb_DbgPrint(3, ("cancel routine performs the cleanup\n"));
  1140. }
  1141. }
  1142. else {
  1143. //
  1144. // Block 2.
  1145. //
  1146. IsoUsb_DbgPrint(3, ("cancel routine has NOT run\n"));
  1147. for(i = 0; i < rwContext->NumIrps; i++) {
  1148. IoFreeIrp(rwContext->SubContext[i].SubIrp);
  1149. rwContext->SubContext[i].SubIrp = NULL;
  1150. }
  1151. info = rwContext->NumXfer;
  1152. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1153. ExFreePool(rwContext->SubContext);
  1154. ExFreePool(rwContext);
  1155. //
  1156. // if we transferred some data, main Irp completes with success
  1157. //
  1158. IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));
  1159. IsoUsb_DbgPrint(1, ("***\n"));
  1160. mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
  1161. mainIrp->IoStatus.Information = info;
  1162. IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
  1163. IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
  1164. IsoUsb_IoDecrement(deviceExtension);
  1165. IsoUsb_DbgPrint(3, ("-------------------------------\n"));
  1166. goto IsoUsb_SinglePairComplete_Exit;
  1167. }
  1168. }
  1169. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1170. IsoUsb_SinglePairComplete_Exit:
  1171. //
  1172. // Block 3.
  1173. //
  1174. ExFreePool(urb);
  1175. IoFreeMdl(mdl);
  1176. IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
  1177. IsoUsb_IoDecrement(deviceExtension);
  1178. IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - ends\n"));
  1179. return STATUS_MORE_PROCESSING_REQUIRED;
  1180. }
  1181. VOID
  1182. IsoUsb_CancelReadWrite(
  1183. IN PDEVICE_OBJECT DeviceObject,
  1184. IN PIRP Irp
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. This is the cancellation routine for the main read/write Irp.
  1189. The policy is as follows:
  1190. If the cancellation routine is the last to decrement
  1191. rwContext->Lock, then free the irps, subcontext and
  1192. the context. Complete the main irp
  1193. Otherwise, call IoCancelIrp on each of the subsidiary irp.
  1194. It is valid to call IoCancelIrp on irps for which the
  1195. completion routine has executed, because, we do not free the
  1196. irps in the completion routine.
  1197. Arguments:
  1198. DeviceObject - pointer to device object
  1199. Irp - I/O request packet
  1200. Return Value:
  1201. None
  1202. --*/
  1203. {
  1204. PIRP mainIrp;
  1205. KIRQL oldIrql;
  1206. ULONG i;
  1207. ULONG info;
  1208. PDEVICE_EXTENSION deviceExtension;
  1209. PISOUSB_RW_CONTEXT rwContext;
  1210. //
  1211. // initialize vars
  1212. //
  1213. info = 0;
  1214. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1215. IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - begins\n"));
  1216. rwContext = (PISOUSB_RW_CONTEXT) Irp->Tail.Overlay.DriverContext[0];
  1217. ASSERT(rwContext);
  1218. deviceExtension = rwContext->DeviceExtension;
  1219. KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);
  1220. if(InterlockedDecrement(&rwContext->Lock)) {
  1221. IsoUsb_DbgPrint(3, ("about to cancel sub context irps..\n"));
  1222. for(i = 0; i < rwContext->NumIrps; i++) {
  1223. if(rwContext->SubContext[i].SubIrp) {
  1224. IoCancelIrp(rwContext->SubContext[i].SubIrp);
  1225. }
  1226. }
  1227. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1228. IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - ends\n"));
  1229. return;
  1230. }
  1231. else {
  1232. for(i = 0; i < rwContext->NumIrps; i++) {
  1233. IoFreeIrp(rwContext->SubContext[i].SubIrp);
  1234. rwContext->SubContext[i].SubIrp = NULL;
  1235. }
  1236. mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);
  1237. info = rwContext->NumXfer;
  1238. KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);
  1239. ExFreePool(rwContext->SubContext);
  1240. ExFreePool(rwContext);
  1241. //
  1242. // if we transferred some data, main Irp completes with success
  1243. //
  1244. IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));
  1245. IsoUsb_DbgPrint(1, ("***\n"));
  1246. Irp->IoStatus.Status = STATUS_SUCCESS;
  1247. Irp->IoStatus.Status = info;
  1248. /*
  1249. Irp->IoStatus.Status = STATUS_CANCELLED;
  1250. Irp->IoStatus.Information = 0;
  1251. */
  1252. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1253. IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite::"));
  1254. IsoUsb_IoDecrement(deviceExtension);
  1255. IsoUsb_DbgPrint(3, ("-------------------------------\n"));
  1256. return;
  1257. }
  1258. }
  1259. ULONG
  1260. IsoUsb_GetCurrentFrame(
  1261. IN PDEVICE_OBJECT DeviceObject,
  1262. IN PIRP Irp
  1263. )
  1264. /*++
  1265. Routine Description:
  1266. This routine send an irp/urb pair with
  1267. function code URB_FUNCTION_GET_CURRENT_FRAME_NUMBER
  1268. to fetch the current frame
  1269. Arguments:
  1270. DeviceObject - pointer to device object
  1271. PIRP - I/O request packet
  1272. Return Value:
  1273. Current frame
  1274. --*/
  1275. {
  1276. KEVENT event;
  1277. PDEVICE_EXTENSION deviceExtension;
  1278. PIO_STACK_LOCATION nextStack;
  1279. struct _URB_GET_CURRENT_FRAME_NUMBER urb;
  1280. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1281. //
  1282. // initialize the urb
  1283. //
  1284. IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - begins\n"));
  1285. urb.Hdr.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
  1286. urb.Hdr.Length = sizeof(urb);
  1287. urb.FrameNumber = (ULONG) -1;
  1288. nextStack = IoGetNextIrpStackLocation(Irp);
  1289. nextStack->Parameters.Others.Argument1 = (PVOID) &urb;
  1290. nextStack->Parameters.DeviceIoControl.IoControlCode =
  1291. IOCTL_INTERNAL_USB_SUBMIT_URB;
  1292. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1293. KeInitializeEvent(&event,
  1294. NotificationEvent,
  1295. FALSE);
  1296. IoSetCompletionRoutine(Irp,
  1297. IsoUsb_StopCompletion,
  1298. &event,
  1299. TRUE,
  1300. TRUE,
  1301. TRUE);
  1302. IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
  1303. IsoUsb_IoIncrement(deviceExtension);
  1304. IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  1305. Irp);
  1306. KeWaitForSingleObject((PVOID) &event,
  1307. Executive,
  1308. KernelMode,
  1309. FALSE,
  1310. NULL);
  1311. IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
  1312. IsoUsb_IoDecrement(deviceExtension);
  1313. IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - ends\n"));
  1314. return urb.FrameNumber;
  1315. }
  1316. NTSTATUS
  1317. IsoUsb_StopCompletion(
  1318. IN PDEVICE_OBJECT DeviceObject,
  1319. IN PIRP Irp,
  1320. IN PVOID Context
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. This is the completion routine for request to retrieve the frame number
  1325. Arguments:
  1326. DeviceObject - pointer to device object
  1327. Irp - I/O request packet
  1328. Context - context passed to the completion routine
  1329. Return Value:
  1330. NT status value
  1331. --*/
  1332. {
  1333. PKEVENT event;
  1334. IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - begins\n"));
  1335. event = (PKEVENT) Context;
  1336. KeSetEvent(event, IO_NO_INCREMENT, FALSE);
  1337. IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - ends\n"));
  1338. return STATUS_MORE_PROCESSING_REQUIRED;
  1339. }