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.

594 lines
17 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. bulkrwr.c
  5. Abstract:
  6. This file has routines to perform reads and writes.
  7. The read and writes are for bulk transfers.
  8. Environment:
  9. Kernel mode
  10. Notes:
  11. Copyright (c) 2000 Microsoft Corporation.
  12. All Rights Reserved.
  13. --*/
  14. #include "bulkusb.h"
  15. #include "bulkpnp.h"
  16. #include "bulkpwr.h"
  17. #include "bulkdev.h"
  18. #include "bulkrwr.h"
  19. #include "bulkwmi.h"
  20. #include "bulkusr.h"
  21. PBULKUSB_PIPE_CONTEXT
  22. BulkUsb_PipeWithName(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PUNICODE_STRING FileName
  25. )
  26. /*++
  27. Routine Description:
  28. This routine will pass the string pipe name and
  29. fetch the pipe number.
  30. Arguments:
  31. DeviceObject - pointer to DeviceObject
  32. FileName - string pipe name
  33. Return Value:
  34. The device extension maintains a pipe context for
  35. the pipes on 82930 board.
  36. This routine returns the pointer to this context in
  37. the device extension for the "FileName" pipe.
  38. --*/
  39. {
  40. LONG ix;
  41. ULONG uval;
  42. ULONG nameLength;
  43. ULONG umultiplier;
  44. PDEVICE_EXTENSION deviceExtension;
  45. PBULKUSB_PIPE_CONTEXT pipeContext;
  46. //
  47. // initialize variables
  48. //
  49. pipeContext = NULL;
  50. //
  51. // typedef WCHAR *PWSTR;
  52. //
  53. nameLength = (FileName->Length / sizeof(WCHAR));
  54. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  55. BulkUsb_DbgPrint(3, ("BulkUsb_PipeWithName - begins\n"));
  56. if(nameLength != 0) {
  57. BulkUsb_DbgPrint(3, ("Filename = %ws nameLength = %d\n", FileName->Buffer, nameLength));
  58. //
  59. // Parse the pipe#
  60. //
  61. ix = nameLength - 1;
  62. // if last char isn't digit, decrement it.
  63. while((ix > -1) &&
  64. ((FileName->Buffer[ix] < (WCHAR) '0') ||
  65. (FileName->Buffer[ix] > (WCHAR) '9'))) {
  66. ix--;
  67. }
  68. if(ix > -1) {
  69. uval = 0;
  70. umultiplier = 1;
  71. // traversing least to most significant digits.
  72. while((ix > -1) &&
  73. (FileName->Buffer[ix] >= (WCHAR) '0') &&
  74. (FileName->Buffer[ix] <= (WCHAR) '9')) {
  75. uval += (umultiplier *
  76. (ULONG) (FileName->Buffer[ix] - (WCHAR) '0'));
  77. ix--;
  78. umultiplier *= 10;
  79. }
  80. if(uval < 6 && deviceExtension->PipeContext) {
  81. pipeContext = &deviceExtension->PipeContext[uval];
  82. }
  83. }
  84. }
  85. BulkUsb_DbgPrint(3, ("BulkUsb_PipeWithName - ends\n"));
  86. return pipeContext;
  87. }
  88. NTSTATUS
  89. BulkUsb_DispatchReadWrite(
  90. IN PDEVICE_OBJECT DeviceObject,
  91. IN PIRP Irp
  92. )
  93. /*++
  94. Routine Description:
  95. Dispatch routine for read and write.
  96. This routine creates a BULKUSB_RW_CONTEXT for a read/write.
  97. This read/write is performed in stages of BULKUSB_MAX_TRANSFER_SIZE.
  98. once a stage of transfer is complete, then the irp is circulated again,
  99. until the requested length of tranfer is performed.
  100. Arguments:
  101. DeviceObject - pointer to device object
  102. Irp - I/O request packet
  103. Return Value:
  104. NT status value
  105. --*/
  106. {
  107. PMDL mdl;
  108. PURB urb;
  109. ULONG totalLength;
  110. ULONG stageLength;
  111. ULONG urbFlags;
  112. BOOLEAN read;
  113. NTSTATUS ntStatus;
  114. ULONG_PTR virtualAddress;
  115. PFILE_OBJECT fileObject;
  116. PDEVICE_EXTENSION deviceExtension;
  117. PIO_STACK_LOCATION irpStack;
  118. PIO_STACK_LOCATION nextStack;
  119. PBULKUSB_RW_CONTEXT rwContext;
  120. PUSBD_PIPE_INFORMATION pipeInformation;
  121. //
  122. // initialize variables
  123. //
  124. urb = NULL;
  125. mdl = NULL;
  126. rwContext = NULL;
  127. totalLength = 0;
  128. irpStack = IoGetCurrentIrpStackLocation(Irp);
  129. fileObject = irpStack->FileObject;
  130. read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
  131. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  132. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite - begins\n"));
  133. if(deviceExtension->DeviceState != Working) {
  134. BulkUsb_DbgPrint(1, ("Invalid device state\n"));
  135. ntStatus = STATUS_INVALID_DEVICE_STATE;
  136. goto BulkUsb_DispatchReadWrite_Exit;
  137. }
  138. //
  139. // It is true that the client driver cancelled the selective suspend
  140. // request in the dispatch routine for create Irps.
  141. // But there is no guarantee that it has indeed completed.
  142. // so wait on the NoIdleReqPendEvent and proceed only if this event
  143. // is signalled.
  144. //
  145. BulkUsb_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n"));
  146. //
  147. // make sure that the selective suspend request has been completed.
  148. //
  149. if(deviceExtension->SSEnable) {
  150. KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
  151. Executive,
  152. KernelMode,
  153. FALSE,
  154. NULL);
  155. }
  156. if(fileObject && fileObject->FsContext) {
  157. pipeInformation = fileObject->FsContext;
  158. if((UsbdPipeTypeBulk != pipeInformation->PipeType) &&
  159. (UsbdPipeTypeInterrupt != pipeInformation->PipeType)) {
  160. BulkUsb_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt\n"));
  161. ntStatus = STATUS_INVALID_HANDLE;
  162. goto BulkUsb_DispatchReadWrite_Exit;
  163. }
  164. }
  165. else {
  166. BulkUsb_DbgPrint(1, ("Invalid handle\n"));
  167. ntStatus = STATUS_INVALID_HANDLE;
  168. goto BulkUsb_DispatchReadWrite_Exit;
  169. }
  170. rwContext = (PBULKUSB_RW_CONTEXT)
  171. ExAllocatePool(NonPagedPool,
  172. sizeof(BULKUSB_RW_CONTEXT));
  173. if(rwContext == NULL) {
  174. BulkUsb_DbgPrint(1, ("Failed to alloc mem for rwContext\n"));
  175. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  176. goto BulkUsb_DispatchReadWrite_Exit;
  177. }
  178. if(Irp->MdlAddress) {
  179. totalLength = MmGetMdlByteCount(Irp->MdlAddress);
  180. }
  181. if(totalLength > BULKUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE) {
  182. BulkUsb_DbgPrint(1, ("Transfer length > circular buffer\n"));
  183. ntStatus = STATUS_INVALID_PARAMETER;
  184. ExFreePool(rwContext);
  185. goto BulkUsb_DispatchReadWrite_Exit;
  186. }
  187. if(totalLength == 0) {
  188. BulkUsb_DbgPrint(1, ("Transfer data length = 0\n"));
  189. ntStatus = STATUS_SUCCESS;
  190. ExFreePool(rwContext);
  191. goto BulkUsb_DispatchReadWrite_Exit;
  192. }
  193. urbFlags = USBD_SHORT_TRANSFER_OK;
  194. virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
  195. if(read) {
  196. urbFlags |= USBD_TRANSFER_DIRECTION_IN;
  197. BulkUsb_DbgPrint(3, ("Read operation\n"));
  198. }
  199. else {
  200. urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
  201. BulkUsb_DbgPrint(3, ("Write operation\n"));
  202. }
  203. //
  204. // the transfer request is for totalLength.
  205. // we can perform a max of BULKUSB_MAX_TRANSFER_SIZE
  206. // in each stage.
  207. //
  208. if(totalLength > BULKUSB_MAX_TRANSFER_SIZE) {
  209. stageLength = BULKUSB_MAX_TRANSFER_SIZE;
  210. }
  211. else {
  212. stageLength = totalLength;
  213. }
  214. mdl = IoAllocateMdl((PVOID) virtualAddress,
  215. totalLength,
  216. FALSE,
  217. FALSE,
  218. NULL);
  219. if(mdl == NULL) {
  220. BulkUsb_DbgPrint(1, ("Failed to alloc mem for mdl\n"));
  221. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  222. ExFreePool(rwContext);
  223. goto BulkUsb_DispatchReadWrite_Exit;
  224. }
  225. //
  226. // map the portion of user-buffer described by an mdl to another mdl
  227. //
  228. IoBuildPartialMdl(Irp->MdlAddress,
  229. mdl,
  230. (PVOID) virtualAddress,
  231. stageLength);
  232. urb = ExAllocatePool(NonPagedPool,
  233. sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
  234. if(urb == NULL) {
  235. BulkUsb_DbgPrint(1, ("Failed to alloc mem for urb\n"));
  236. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  237. ExFreePool(rwContext);
  238. IoFreeMdl(mdl);
  239. goto BulkUsb_DispatchReadWrite_Exit;
  240. }
  241. UsbBuildInterruptOrBulkTransferRequest(
  242. urb,
  243. sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
  244. pipeInformation->PipeHandle,
  245. NULL,
  246. mdl,
  247. stageLength,
  248. urbFlags,
  249. NULL);
  250. //
  251. // set BULKUSB_RW_CONTEXT parameters.
  252. //
  253. rwContext->Urb = urb;
  254. rwContext->Mdl = mdl;
  255. rwContext->Length = totalLength - stageLength;
  256. rwContext->Numxfer = 0;
  257. rwContext->VirtualAddress = virtualAddress + stageLength;
  258. rwContext->DeviceExtension = deviceExtension;
  259. //
  260. // use the original read/write irp as an internal device control irp
  261. //
  262. nextStack = IoGetNextIrpStackLocation(Irp);
  263. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  264. nextStack->Parameters.Others.Argument1 = (PVOID) urb;
  265. nextStack->Parameters.DeviceIoControl.IoControlCode =
  266. IOCTL_INTERNAL_USB_SUBMIT_URB;
  267. IoSetCompletionRoutine(Irp,
  268. (PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
  269. rwContext,
  270. TRUE,
  271. TRUE,
  272. TRUE);
  273. //
  274. // since we return STATUS_PENDING call IoMarkIrpPending.
  275. // This is the boiler plate code.
  276. // This may cause extra overhead of an APC for the Irp completion
  277. // but this is the correct thing to do.
  278. //
  279. IoMarkIrpPending(Irp);
  280. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite::"));
  281. BulkUsb_IoIncrement(deviceExtension);
  282. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
  283. Irp);
  284. if(!NT_SUCCESS(ntStatus)) {
  285. BulkUsb_DbgPrint(1, ("IoCallDriver fails with status %X\n", ntStatus));
  286. //
  287. // if the device was yanked out, then the pipeInformation
  288. // field is invalid.
  289. // similarly if the request was cancelled, then we need not
  290. // invoked reset pipe/device.
  291. //
  292. if((ntStatus != STATUS_CANCELLED) &&
  293. (ntStatus != STATUS_DEVICE_NOT_CONNECTED)) {
  294. ntStatus = BulkUsb_ResetPipe(DeviceObject,
  295. pipeInformation);
  296. if(!NT_SUCCESS(ntStatus)) {
  297. BulkUsb_DbgPrint(1, ("BulkUsb_ResetPipe failed\n"));
  298. ntStatus = BulkUsb_ResetDevice(DeviceObject);
  299. }
  300. }
  301. else {
  302. BulkUsb_DbgPrint(3, ("ntStatus is STATUS_CANCELLED or "
  303. "STATUS_DEVICE_NOT_CONNECTED\n"));
  304. }
  305. }
  306. //
  307. // we return STATUS_PENDING and not the status returned by the lower layer.
  308. //
  309. return STATUS_PENDING;
  310. BulkUsb_DispatchReadWrite_Exit:
  311. Irp->IoStatus.Status = ntStatus;
  312. Irp->IoStatus.Information = 0;
  313. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  314. BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite - ends\n"));
  315. return ntStatus;
  316. }
  317. NTSTATUS
  318. BulkUsb_ReadWriteCompletion(
  319. IN PDEVICE_OBJECT DeviceObject,
  320. IN PIRP Irp,
  321. IN PVOID Context
  322. )
  323. /*++
  324. Routine Description:
  325. This is the completion routine for reads/writes
  326. If the irp completes with success, we check if we
  327. need to recirculate this irp for another stage of
  328. transfer. In this case return STATUS_MORE_PROCESSING_REQUIRED.
  329. if the irp completes in error, free all memory allocs and
  330. return the status.
  331. Arguments:
  332. DeviceObject - pointer to device object
  333. Irp - I/O request packet
  334. Context - context passed to the completion routine.
  335. Return Value:
  336. NT status value
  337. --*/
  338. {
  339. ULONG stageLength;
  340. NTSTATUS ntStatus;
  341. PIO_STACK_LOCATION nextStack;
  342. PBULKUSB_RW_CONTEXT rwContext;
  343. //
  344. // initialize variables
  345. //
  346. rwContext = (PBULKUSB_RW_CONTEXT) Context;
  347. ntStatus = Irp->IoStatus.Status;
  348. UNREFERENCED_PARAMETER(DeviceObject);
  349. BulkUsb_DbgPrint(3, ("BulkUsb_ReadWriteCompletion - begins\n"));
  350. //
  351. // successfully performed a stageLength of transfer.
  352. // check if we need to recirculate the irp.
  353. //
  354. if(NT_SUCCESS(ntStatus)) {
  355. if(rwContext) {
  356. rwContext->Numxfer +=
  357. rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  358. if(rwContext->Length) {
  359. //
  360. // another stage transfer
  361. //
  362. BulkUsb_DbgPrint(3, ("Another stage transfer...\n"));
  363. if(rwContext->Length > BULKUSB_MAX_TRANSFER_SIZE) {
  364. stageLength = BULKUSB_MAX_TRANSFER_SIZE;
  365. }
  366. else {
  367. stageLength = rwContext->Length;
  368. }
  369. // the source MDL is not mapped and so when the lower driver
  370. // calls MmGetSystemAddressForMdl(Safe) on Urb->Mdl (target Mdl),
  371. // system PTEs are used.
  372. // IoFreeMdl calls MmPrepareMdlForReuse to release PTEs (unlock
  373. // VA address before freeing any Mdl
  374. // Rather than calling IoFreeMdl and IoAllocateMdl each time,
  375. // just call MmPrepareMdlForReuse
  376. // Not calling MmPrepareMdlForReuse will leak system PTEs
  377. //
  378. MmPrepareMdlForReuse(rwContext->Mdl);
  379. IoBuildPartialMdl(Irp->MdlAddress,
  380. rwContext->Mdl,
  381. (PVOID) rwContext->VirtualAddress,
  382. stageLength);
  383. //
  384. // reinitialize the urb
  385. //
  386. rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength
  387. = stageLength;
  388. rwContext->VirtualAddress += stageLength;
  389. rwContext->Length -= stageLength;
  390. nextStack = IoGetNextIrpStackLocation(Irp);
  391. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  392. nextStack->Parameters.Others.Argument1 = rwContext->Urb;
  393. nextStack->Parameters.DeviceIoControl.IoControlCode =
  394. IOCTL_INTERNAL_USB_SUBMIT_URB;
  395. IoSetCompletionRoutine(Irp,
  396. BulkUsb_ReadWriteCompletion,
  397. rwContext,
  398. TRUE,
  399. TRUE,
  400. TRUE);
  401. IoCallDriver(rwContext->DeviceExtension->TopOfStackDeviceObject,
  402. Irp);
  403. return STATUS_MORE_PROCESSING_REQUIRED;
  404. }
  405. else {
  406. //
  407. // this is the last transfer
  408. //
  409. Irp->IoStatus.Information = rwContext->Numxfer;
  410. }
  411. }
  412. }
  413. else {
  414. BulkUsb_DbgPrint(1, ("ReadWriteCompletion - failed with status = %X\n", ntStatus));
  415. }
  416. if(rwContext) {
  417. //
  418. // dump rwContext
  419. //
  420. BulkUsb_DbgPrint(3, ("rwContext->Urb = %X\n",
  421. rwContext->Urb));
  422. BulkUsb_DbgPrint(3, ("rwContext->Mdl = %X\n",
  423. rwContext->Mdl));
  424. BulkUsb_DbgPrint(3, ("rwContext->Length = %d\n",
  425. rwContext->Length));
  426. BulkUsb_DbgPrint(3, ("rwContext->Numxfer = %d\n",
  427. rwContext->Numxfer));
  428. BulkUsb_DbgPrint(3, ("rwContext->VirtualAddress = %X\n",
  429. rwContext->VirtualAddress));
  430. BulkUsb_DbgPrint(3, ("rwContext->DeviceExtension = %X\n",
  431. rwContext->DeviceExtension));
  432. BulkUsb_DbgPrint(3, ("BulkUsb_ReadWriteCompletion::"));
  433. BulkUsb_IoDecrement(rwContext->DeviceExtension);
  434. ExFreePool(rwContext->Urb);
  435. IoFreeMdl(rwContext->Mdl);
  436. ExFreePool(rwContext);
  437. }
  438. BulkUsb_DbgPrint(3, ("BulkUsb_ReadWriteCompletion - ends\n"));
  439. return ntStatus;
  440. }