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.

730 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. isostrm.c
  5. Abstract:
  6. This file has routines for stream transfers.
  7. Stream transfers are initiated and stopped using
  8. the IOCTLs exposed by this driver.
  9. The stream transfer information is contained in
  10. ISOUSB_STREAM_OBJECT structure which is securely
  11. placed in the FileObject. The ISOUSB_STREAM_OBJECT
  12. structure has links to ISOUSB_TRANSFER_OBJECT
  13. (each TRANSFER_OBJECT corresponds to the number of
  14. irp/urb pair circulating).
  15. So if the user-mode app simply crashes or aborts or
  16. does not terminate, we can cleanly abort the stream
  17. transfers.
  18. Environment:
  19. Kernel mode
  20. Notes:
  21. Copyright (c) 2000 Microsoft Corporation.
  22. All Rights Reserved.
  23. --*/
  24. #include "isousb.h"
  25. #include "isopnp.h"
  26. #include "isopwr.h"
  27. #include "isodev.h"
  28. #include "isousr.h"
  29. #include "isowmi.h"
  30. #include "isorwr.h"
  31. #include "isostrm.h"
  32. NTSTATUS
  33. IsoUsb_StartIsoStream(
  34. IN PDEVICE_OBJECT DeviceObject,
  35. IN PIRP Irp
  36. )
  37. /*++
  38. Routine Description:
  39. This routine create a single stream object and
  40. invokes StartTransfer for ISOUSB_MAX_IRP number of
  41. times.
  42. Arguments:
  43. DeviceObject - pointer to device object
  44. Irp - I/O request packet
  45. Return Value:
  46. NT status value
  47. --*/
  48. {
  49. ULONG i;
  50. ULONG info;
  51. ULONG inputBufferLength;
  52. ULONG outputBufferLength;
  53. NTSTATUS ntStatus;
  54. PFILE_OBJECT fileObject;
  55. PDEVICE_EXTENSION deviceExtension;
  56. PIO_STACK_LOCATION irpStack;
  57. PISOUSB_STREAM_OBJECT streamObject;
  58. PUSBD_PIPE_INFORMATION pipeInformation;
  59. info = 0;
  60. irpStack = IoGetCurrentIrpStackLocation(Irp);
  61. fileObject = irpStack->FileObject;
  62. streamObject = NULL;
  63. pipeInformation = NULL;
  64. deviceExtension = DeviceObject->DeviceExtension;
  65. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  66. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  67. IsoUsb_DbgPrint(3, ("IsoUsb_StartIsoStream - begins\n"));
  68. streamObject = ExAllocatePool(NonPagedPool,
  69. sizeof(struct _ISOUSB_STREAM_OBJECT));
  70. if(streamObject == NULL) {
  71. IsoUsb_DbgPrint(1, ("failed to alloc mem for streamObject\n"));
  72. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  73. goto IsoUsb_StartIsoStream_Exit;
  74. }
  75. RtlZeroMemory(streamObject, sizeof(ISOUSB_STREAM_OBJECT));
  76. //
  77. // The Isoch IN pipe for the board is the 5th pipe
  78. //
  79. pipeInformation = &(deviceExtension->UsbInterface->Pipes[ISOCH_IN_PIPE_INDEX]);
  80. // reset the pipe
  81. //
  82. IsoUsb_ResetPipe(DeviceObject, pipeInformation);
  83. streamObject->DeviceObject = DeviceObject;
  84. streamObject->PipeInformation = pipeInformation;
  85. KeInitializeEvent(&streamObject->NoPendingIrpEvent,
  86. NotificationEvent,
  87. FALSE);
  88. for(i = 0; i < ISOUSB_MAX_IRP; i++) {
  89. ntStatus = IsoUsb_StartTransfer(DeviceObject,
  90. streamObject,
  91. i);
  92. if(!NT_SUCCESS(ntStatus)) {
  93. //
  94. // we continue sending transfer object irps..
  95. //
  96. IsoUsb_DbgPrint(1, ("IsoUsb_StartTransfer [%d] - failed\n", i));
  97. if(ntStatus == STATUS_INSUFFICIENT_RESOURCES) {
  98. ASSERT(streamObject->TransferObjectList[i] == NULL);
  99. }
  100. }
  101. }
  102. if(fileObject && fileObject->FsContext) {
  103. if(streamObject->PendingIrps) {
  104. ((PFILE_OBJECT_CONTENT)fileObject->FsContext)->StreamInformation
  105. = streamObject;
  106. }
  107. else {
  108. IsoUsb_DbgPrint(1, ("no transfer object irp sent..abort..\n"));
  109. ExFreePool(streamObject);
  110. ((PFILE_OBJECT_CONTENT)fileObject->FsContext)->StreamInformation = NULL;
  111. }
  112. }
  113. IsoUsb_StartIsoStream_Exit:
  114. Irp->IoStatus.Information = info;
  115. Irp->IoStatus.Status = ntStatus;
  116. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  117. IsoUsb_DbgPrint(3, ("IsoUsb_StartIsoStream::"));
  118. IsoUsb_IoDecrement(deviceExtension);
  119. IsoUsb_DbgPrint(3, ("IsoUsb_StartIsoStream - ends\n"));
  120. return ntStatus;
  121. }
  122. NTSTATUS
  123. IsoUsb_StartTransfer(
  124. IN PDEVICE_OBJECT DeviceObject,
  125. IN PISOUSB_STREAM_OBJECT StreamObject,
  126. IN ULONG Index
  127. )
  128. /*++
  129. Routine Description:
  130. This routine creates a transfer object for each irp/urb pair.
  131. After initializing the pair, it sends the irp down the stack.
  132. Arguments:
  133. DeviceObject - pointer to device object.
  134. StreamObject - pointer to stream object
  135. Index - index into the transfer object table in stream object
  136. Return Value:
  137. NT status value
  138. --*/
  139. {
  140. PIRP irp;
  141. CCHAR stackSize;
  142. ULONG packetSize;
  143. ULONG maxXferSize;
  144. ULONG numPackets;
  145. NTSTATUS ntStatus;
  146. PDEVICE_EXTENSION deviceExtension;
  147. PIO_STACK_LOCATION nextStack;
  148. PISOUSB_TRANSFER_OBJECT transferObject;
  149. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  150. maxXferSize = StreamObject->PipeInformation->MaximumTransferSize;
  151. packetSize = StreamObject->PipeInformation->MaximumPacketSize;
  152. numPackets = maxXferSize / packetSize;
  153. IsoUsb_DbgPrint(3, ("IsoUsb_StartTransfer - begins\n"));
  154. transferObject = ExAllocatePool(NonPagedPool,
  155. sizeof(struct _ISOUSB_TRANSFER_OBJECT));
  156. if(transferObject == NULL) {
  157. IsoUsb_DbgPrint(1, ("failed to alloc mem for transferObject\n"));
  158. return STATUS_INSUFFICIENT_RESOURCES;
  159. }
  160. RtlZeroMemory(transferObject,
  161. sizeof(struct _ISOUSB_TRANSFER_OBJECT));
  162. transferObject->StreamObject = StreamObject;
  163. stackSize = (CCHAR) (deviceExtension->TopOfStackDeviceObject->StackSize + 1);
  164. irp = IoAllocateIrp(stackSize, FALSE);
  165. if(irp == NULL) {
  166. IsoUsb_DbgPrint(1, ("failed to alloc mem for irp\n"));
  167. ExFreePool(transferObject);
  168. return STATUS_INSUFFICIENT_RESOURCES;
  169. }
  170. transferObject->Irp = irp;
  171. transferObject->DataBuffer = ExAllocatePool(NonPagedPool,
  172. maxXferSize);
  173. if(transferObject->DataBuffer == NULL) {
  174. IsoUsb_DbgPrint(1, ("failed to alloc mem for DataBuffer\n"));
  175. ExFreePool(transferObject);
  176. IoFreeIrp(irp);
  177. return STATUS_INSUFFICIENT_RESOURCES;
  178. }
  179. transferObject->Urb = ExAllocatePool(NonPagedPool,
  180. GET_ISO_URB_SIZE(numPackets));
  181. if(transferObject->Urb == NULL) {
  182. IsoUsb_DbgPrint(1, ("failed to alloc mem for Urb\n"));
  183. ExFreePool(transferObject->DataBuffer);
  184. IoFreeIrp(irp);
  185. ExFreePool(transferObject);
  186. return STATUS_INSUFFICIENT_RESOURCES;
  187. }
  188. IsoUsb_InitializeStreamUrb(DeviceObject, transferObject);
  189. StreamObject->TransferObjectList[Index] = transferObject;
  190. InterlockedIncrement(&StreamObject->PendingIrps);
  191. nextStack = IoGetNextIrpStackLocation(irp);
  192. nextStack->Parameters.Others.Argument1 = transferObject->Urb;
  193. nextStack->Parameters.DeviceIoControl.IoControlCode =
  194. IOCTL_INTERNAL_USB_SUBMIT_URB;
  195. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  196. IoSetCompletionRoutine(irp,
  197. IsoUsb_IsoIrp_Complete,
  198. transferObject,
  199. TRUE,
  200. TRUE,
  201. TRUE);
  202. IsoUsb_DbgPrint(3, ("IsoUsb_StartTransfer::"));
  203. IsoUsb_IoIncrement(deviceExtension);
  204. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  205. irp);
  206. if(NT_SUCCESS(ntStatus)) {
  207. ntStatus = STATUS_SUCCESS;
  208. }
  209. IsoUsb_DbgPrint(3, ("IsoUsb_StartTransfer - ends\n"));
  210. return ntStatus;
  211. }
  212. NTSTATUS
  213. IsoUsb_InitializeStreamUrb(
  214. IN PDEVICE_OBJECT DeviceObject,
  215. IN PISOUSB_TRANSFER_OBJECT TransferObject
  216. )
  217. /*++
  218. Routine Description:
  219. This routine initializes the irp/urb pair in the transfer object.
  220. Arguments:
  221. DeviceObject - pointer to device object
  222. TransferObject - pointer to transfer object
  223. Return Value:
  224. NT status value
  225. --*/
  226. {
  227. PURB urb;
  228. ULONG i;
  229. ULONG siz;
  230. ULONG packetSize;
  231. ULONG numPackets;
  232. ULONG maxXferSize;
  233. PISOUSB_STREAM_OBJECT streamObject;
  234. urb = TransferObject->Urb;
  235. streamObject = TransferObject->StreamObject;
  236. maxXferSize = streamObject->PipeInformation->MaximumTransferSize;
  237. packetSize = streamObject->PipeInformation->MaximumPacketSize;
  238. numPackets = maxXferSize / packetSize;
  239. IsoUsb_DbgPrint(3, ("IsoUsb_InitializeStreamUrb - begins\n"));
  240. if(numPackets > 255) {
  241. numPackets = 255;
  242. maxXferSize = packetSize * numPackets;
  243. }
  244. siz = GET_ISO_URB_SIZE(numPackets);
  245. RtlZeroMemory(urb, siz);
  246. urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) siz;
  247. urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
  248. urb->UrbIsochronousTransfer.PipeHandle =
  249. streamObject->PipeInformation->PipeHandle;
  250. urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
  251. urb->UrbIsochronousTransfer.TransferBufferMDL = NULL;
  252. urb->UrbIsochronousTransfer.TransferBuffer = TransferObject->DataBuffer;
  253. urb->UrbIsochronousTransfer.TransferBufferLength = numPackets * packetSize;
  254. urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
  255. urb->UrbIsochronousTransfer.NumberOfPackets = numPackets;
  256. urb->UrbIsochronousTransfer.UrbLink = NULL;
  257. for(i=0; i<urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  258. urb->UrbIsochronousTransfer.IsoPacket[i].Offset = i * packetSize;
  259. //
  260. // For input operation, length is set to whatever the device supplies.
  261. //
  262. urb->UrbIsochronousTransfer.IsoPacket[i].Length = 0;
  263. }
  264. IsoUsb_DbgPrint(3, ("IsoUsb_InitializeStreamUrb - ends\n"));
  265. return STATUS_SUCCESS;
  266. }
  267. NTSTATUS
  268. IsoUsb_IsoIrp_Complete(
  269. IN PDEVICE_OBJECT DeviceObject,
  270. IN PIRP Irp,
  271. IN PVOID Context
  272. )
  273. /*++
  274. Routine Description:
  275. This is the completion routine of the irp in the irp/urb pair
  276. passed down the stack for stream transfers.
  277. If the transfer was cancelled or the device yanked out, then we
  278. release resources, dump the statistics and return
  279. STATUS_MORE_PROCESSING_REQUIRED, so that the cleanup module can
  280. free the irp.
  281. otherwise, we reinitialize the transfers and continue recirculaiton
  282. of the irps.
  283. Arguments:
  284. DeviceObject - pointer to device object below us.
  285. Irp - I/O completion routine.
  286. Context - context passed to the completion routine
  287. Return Value:
  288. --*/
  289. {
  290. NTSTATUS ntStatus;
  291. PDEVICE_OBJECT deviceObject;
  292. PDEVICE_EXTENSION deviceExtension;
  293. PIO_STACK_LOCATION nextStack;
  294. PISOUSB_STREAM_OBJECT streamObject;
  295. PISOUSB_TRANSFER_OBJECT transferObject;
  296. transferObject = (PISOUSB_TRANSFER_OBJECT) Context;
  297. streamObject = transferObject->StreamObject;
  298. deviceObject = streamObject->DeviceObject;
  299. deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  300. IsoUsb_DbgPrint(3, ("IsoUsb_IsoIrp_Complete - begins\n"));
  301. ntStatus = IsoUsb_ProcessTransfer(transferObject);
  302. if((ntStatus == STATUS_CANCELLED) ||
  303. (ntStatus == STATUS_DEVICE_NOT_CONNECTED)) {
  304. IsoUsb_DbgPrint(3, ("Isoch irp cancelled/device removed\n"));
  305. //
  306. // this is the last irp to complete with this erroneous value
  307. // signal an event and return STATUS_MORE_PROCESSING_REQUIRED
  308. //
  309. if(InterlockedDecrement(&streamObject->PendingIrps) == 0) {
  310. KeSetEvent(&streamObject->NoPendingIrpEvent,
  311. 1,
  312. FALSE);
  313. IsoUsb_DbgPrint(3, ("-----------------------------\n"));
  314. }
  315. IsoUsb_DbgPrint(3, ("IsoUsb_IsoIrp_Complete::"));
  316. IsoUsb_IoDecrement(deviceExtension);
  317. transferObject->Irp = NULL;
  318. IoFreeIrp(Irp);
  319. return STATUS_MORE_PROCESSING_REQUIRED;
  320. }
  321. //
  322. // otherwise circulate the irps.
  323. //
  324. IsoUsb_InitializeStreamUrb(deviceObject, transferObject);
  325. nextStack = IoGetNextIrpStackLocation(Irp);
  326. nextStack->Parameters.Others.Argument1 = transferObject->Urb;
  327. nextStack->Parameters.DeviceIoControl.IoControlCode =
  328. IOCTL_INTERNAL_USB_SUBMIT_URB;
  329. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  330. IoSetCompletionRoutine(Irp,
  331. IsoUsb_IsoIrp_Complete,
  332. transferObject,
  333. TRUE,
  334. TRUE,
  335. TRUE);
  336. transferObject->TimesRecycled++;
  337. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  338. Irp);
  339. IsoUsb_DbgPrint(3, ("IsoUsb_IsoIrp_Complete - ends\n"));
  340. IsoUsb_DbgPrint(3, ("-----------------------------\n"));
  341. return STATUS_MORE_PROCESSING_REQUIRED;
  342. }
  343. NTSTATUS
  344. IsoUsb_ProcessTransfer(
  345. IN PISOUSB_TRANSFER_OBJECT TransferObject
  346. )
  347. /*++
  348. Routine Description:
  349. This routine is invoked from the completion routine to check the status
  350. of the irp, urb and the isochronous packets.
  351. updates statistics
  352. Arguments:
  353. TranferObject - pointer to transfer object for the irp/urb pair which completed.
  354. Return Value:
  355. NT status value
  356. --*/
  357. {
  358. PIRP irp;
  359. PURB urb;
  360. ULONG i;
  361. NTSTATUS ntStatus;
  362. USBD_STATUS usbdStatus;
  363. irp = TransferObject->Irp;
  364. urb = TransferObject->Urb;
  365. ntStatus = irp->IoStatus.Status;
  366. IsoUsb_DbgPrint(3, ("IsoUsb_ProcessTransfer - begins\n"));
  367. if(!NT_SUCCESS(ntStatus)) {
  368. IsoUsb_DbgPrint(3, ("Isoch irp failed with status = %X\n", ntStatus));
  369. }
  370. usbdStatus = urb->UrbHeader.Status;
  371. if(!USBD_SUCCESS(usbdStatus)) {
  372. IsoUsb_DbgPrint(3, ("urb failed with status = %X\n", usbdStatus));
  373. }
  374. //
  375. // check each of the urb packets
  376. //
  377. for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  378. TransferObject->TotalPacketsProcessed++;
  379. usbdStatus = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
  380. if(!USBD_SUCCESS(usbdStatus)) {
  381. // IsoUsb_DbgPrint(3, ("Iso packet %d failed with status = %X\n", i, usbdStatus));
  382. TransferObject->ErrorPacketCount++;
  383. }
  384. else {
  385. TransferObject->TotalBytesProcessed += urb->UrbIsochronousTransfer.IsoPacket[i].Length;
  386. }
  387. }
  388. IsoUsb_DbgPrint(3, ("IsoUsb_ProcessTransfer - ends\n"));
  389. return ntStatus;
  390. }
  391. NTSTATUS
  392. IsoUsb_StopIsoStream(
  393. IN PDEVICE_OBJECT DeviceObject,
  394. IN PISOUSB_STREAM_OBJECT StreamObject,
  395. IN PIRP Irp
  396. )
  397. /*++
  398. Routine Description:
  399. This routine is invoked from the IOCTL to stop the stream transfers.
  400. Arguments:
  401. DeviceObject - pointer to device object
  402. StreamObject - pointer to stream object
  403. Irp - pointer to Irp
  404. Return Value:
  405. NT status value
  406. --*/
  407. {
  408. ULONG i;
  409. KIRQL oldIrql;
  410. PDEVICE_EXTENSION deviceExtension;
  411. PIO_STACK_LOCATION irpStack;
  412. //
  413. // initialize vars
  414. //
  415. irpStack = IoGetCurrentIrpStackLocation(Irp);
  416. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  417. IsoUsb_DbgPrint(3, ("IsoUsb_StopIsoStream - begins\n"));
  418. if((StreamObject == NULL) ||
  419. (StreamObject->DeviceObject != DeviceObject)) {
  420. IsoUsb_DbgPrint(1, ("invalid streamObject\n"));
  421. return STATUS_INVALID_PARAMETER;
  422. }
  423. IsoUsb_StreamObjectCleanup(StreamObject, deviceExtension);
  424. IsoUsb_DbgPrint(3, ("IsoUsb_StopIsoStream - ends\n"));
  425. return STATUS_SUCCESS;
  426. }
  427. NTSTATUS
  428. IsoUsb_StreamObjectCleanup(
  429. IN PISOUSB_STREAM_OBJECT StreamObject,
  430. IN PDEVICE_EXTENSION DeviceExtension
  431. )
  432. /*++
  433. Routine Description:
  434. This routine is invoked either when the user-mode app passes an IOCTL to
  435. abort stream transfers or when the the cleanup dispatch routine is run.
  436. It is guaranteed to run only once for every stream transfer.
  437. Arguments:
  438. StreamObject - StreamObject corresponding to stream transfer which
  439. needs to be aborted.
  440. DeviceExtension - pointer to device extension
  441. Return Value:
  442. NT status value
  443. --*/
  444. {
  445. ULONG i;
  446. ULONG timesRecycled;
  447. ULONG totalPacketsProcessed;
  448. ULONG totalBytesProcessed;
  449. ULONG errorPacketCount;
  450. PISOUSB_TRANSFER_OBJECT xferObject;
  451. //
  452. // initialize the variables
  453. //
  454. timesRecycled = 0;
  455. totalPacketsProcessed = 0;
  456. totalBytesProcessed = 0;
  457. errorPacketCount = 0;
  458. //
  459. // cancel transferobject irps/urb pair
  460. // safe to touch these irps because the
  461. // completion routine always returns
  462. // STATUS_MORE_PRCESSING_REQUIRED
  463. //
  464. //
  465. for(i = 0; i < ISOUSB_MAX_IRP; i++) {
  466. if(StreamObject->TransferObjectList[i] &&
  467. StreamObject->TransferObjectList[i]->Irp) {
  468. IoCancelIrp(StreamObject->TransferObjectList[i]->Irp);
  469. }
  470. }
  471. //
  472. // wait for the transfer objects irps to complete.
  473. //
  474. KeWaitForSingleObject(&StreamObject->NoPendingIrpEvent,
  475. Executive,
  476. KernelMode,
  477. FALSE,
  478. NULL);
  479. //
  480. // dump the statistics
  481. //
  482. for(i = 0; i < ISOUSB_MAX_IRP; i++) {
  483. xferObject = StreamObject->TransferObjectList[i];
  484. if(xferObject) {
  485. timesRecycled += xferObject->TimesRecycled;
  486. totalPacketsProcessed += xferObject->TotalPacketsProcessed;
  487. totalBytesProcessed += xferObject->TotalBytesProcessed;
  488. errorPacketCount += xferObject->ErrorPacketCount;
  489. }
  490. }
  491. IsoUsb_DbgPrint(3, ("TimesRecycled = %d\n", timesRecycled));
  492. IsoUsb_DbgPrint(3, ("TotalPacketsProcessed = %d\n", totalPacketsProcessed));
  493. IsoUsb_DbgPrint(3, ("TotalBytesProcessed = %d\n", totalBytesProcessed));
  494. IsoUsb_DbgPrint(3, ("ErrorPacketCount = %d\n", errorPacketCount));
  495. //
  496. // free all the buffers, urbs and transfer objects
  497. // associated with stream object
  498. //
  499. for(i = 0; i < ISOUSB_MAX_IRP; i++) {
  500. xferObject = StreamObject->TransferObjectList[i];
  501. if(xferObject) {
  502. if(xferObject->Urb) {
  503. ExFreePool(xferObject->Urb);
  504. xferObject->Urb = NULL;
  505. }
  506. if(xferObject->DataBuffer) {
  507. ExFreePool(xferObject->DataBuffer);
  508. xferObject->DataBuffer = NULL;
  509. }
  510. ExFreePool(xferObject);
  511. StreamObject->TransferObjectList[i] = NULL;
  512. }
  513. }
  514. ExFreePool(StreamObject);
  515. // IsoUsb_ResetParentPort(DeviceObject);
  516. return STATUS_SUCCESS;
  517. }