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.

940 lines
30 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. GENUSB.C
  5. Abstract:
  6. This source file contains the DriverEntry() and AddDevice() entry points
  7. for the GENUSB driver and the dispatch routines which handle:
  8. IRP_MJ_POWER
  9. IRP_MJ_SYSTEM_CONTROL
  10. IRP_MJ_PNP
  11. Environment:
  12. kernel mode
  13. Revision History:
  14. Sep 2001 : Copied from USBMASS
  15. --*/
  16. //*****************************************************************************
  17. // I N C L U D E S
  18. //*****************************************************************************
  19. #include "genusb.h"
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE, GenUSB_DeviceControl)
  22. #endif
  23. //******************************************************************************
  24. //
  25. // GenUSB_DeviceControl()
  26. //
  27. //******************************************************************************
  28. NTSTATUS
  29. GenUSB_DeviceControl (
  30. IN PDEVICE_OBJECT DeviceObject,
  31. IN PIRP Irp
  32. )
  33. {
  34. NTSTATUS status;
  35. PDEVICE_EXTENSION deviceExtension;
  36. ULONG ioControlCode;
  37. ULONG buffLen;
  38. ULONG requiredLen;
  39. ULONG numberInterfaces;
  40. ULONG i;
  41. PVOID source;
  42. PIO_STACK_LOCATION irpSp;
  43. PCHAR buffer;
  44. ULONG urbStatus;
  45. USHORT resultLength;
  46. BOOLEAN complete;
  47. USBD_PIPE_HANDLE usbdPipeHandle;
  48. PGENUSB_GET_STRING_DESCRIPTOR stringDescriptor;
  49. PGENUSB_GET_REQUEST request;
  50. PGENUSB_REQUEST_RESULTS requestResult;
  51. PGENUSB_SELECT_CONFIGURATION selectConfig;
  52. PGENUSB_SET_READ_WRITE_PIPES readWritePipes;
  53. GENUSB_READ_WRITE_PIPE transfer;
  54. PAGED_CODE ();
  55. complete = TRUE;
  56. deviceExtension = DeviceObject->DeviceExtension;
  57. status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
  58. if (!NT_SUCCESS(status)) {
  59. Irp->IoStatus.Status = status;
  60. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  61. return status;
  62. }
  63. // While there are several readers of the IsStarted state, it is only
  64. // set at the end of GenUSB_StartDevice.
  65. if (!deviceExtension->IsStarted) {
  66. LOGENTRY(deviceExtension,'IOns', DeviceObject, Irp, 0);
  67. status = STATUS_DEVICE_NOT_CONNECTED;
  68. goto GenUSB_DeviceControlDone;
  69. }
  70. //
  71. // After talking extensively with JD, he tells me that I do not need
  72. // to queue requests for power downs or query stop. If that is the
  73. // case then even if the device power state isn't PowerDeviceD0 we
  74. // can still allow trasfers. This, of course, is a property of the
  75. // brand new port driver that went into XP.
  76. //
  77. // if (DeviceExtension->DevicePowerState != PowerDeviceD0)
  78. // {
  79. // }
  80. //
  81. //
  82. // BUGBUG if we ever implement IDLE, we need to turn the device
  83. // back on here.
  84. //
  85. irpSp = IoGetCurrentIrpStackLocation (Irp);
  86. // Get the Ioctl code
  87. ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
  88. // We need to clear the information field in all cases.
  89. Irp->IoStatus.Information = 0;
  90. switch (ioControlCode) {
  91. case IOCTL_GENUSB_GET_DEVICE_DESCRIPTOR:
  92. case IOCTL_GENUSB_GET_CONFIGURATION_DESCRIPTOR:
  93. LOGENTRY(deviceExtension, 'IO_1', ioControlCode, DeviceObject, Irp);
  94. //
  95. // All of these ioctls copy data from the device extension
  96. // to the caller's buffer
  97. //
  98. switch (ioControlCode) {
  99. case IOCTL_GENUSB_GET_DEVICE_DESCRIPTOR:
  100. source = deviceExtension->DeviceDescriptor;
  101. requiredLen = deviceExtension->DeviceDescriptor->bLength;
  102. break;
  103. case IOCTL_GENUSB_GET_CONFIGURATION_DESCRIPTOR:
  104. source = deviceExtension->ConfigurationDescriptor;
  105. requiredLen = deviceExtension->ConfigurationDescriptor->wTotalLength;
  106. break;
  107. default:
  108. // Panic
  109. ASSERT (ioControlCode);
  110. status = STATUS_INVALID_PARAMETER;
  111. goto GenUSB_DeviceControlDone;
  112. }
  113. // Verify that there is a system buffer
  114. if (NULL == Irp->AssociatedIrp.SystemBuffer) {
  115. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  116. status = STATUS_INVALID_PARAMETER;
  117. break;
  118. }
  119. buffer = Irp->AssociatedIrp.SystemBuffer;
  120. // Verify that this buffer is of sufficient length
  121. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  122. if (buffLen < requiredLen) {
  123. status = STATUS_BUFFER_TOO_SMALL;
  124. break;
  125. }
  126. // Copy in the data and return the length in the information field.
  127. RtlCopyMemory (buffer, source, requiredLen);
  128. Irp->IoStatus.Information = requiredLen;
  129. break;
  130. case IOCTL_GENUSB_GET_STRING_DESCRIPTOR:
  131. LOGENTRY(deviceExtension, 'IO_2', ioControlCode, DeviceObject, Irp);
  132. if (NULL == Irp->AssociatedIrp.SystemBuffer)
  133. {
  134. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  135. status = STATUS_INVALID_PARAMETER;
  136. break;
  137. }
  138. stringDescriptor = Irp->AssociatedIrp.SystemBuffer;
  139. buffer = Irp->AssociatedIrp.SystemBuffer;
  140. //
  141. // verify input length
  142. //
  143. buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  144. if (buffLen != sizeof (GENUSB_GET_STRING_DESCRIPTOR))
  145. {
  146. status = STATUS_INVALID_PARAMETER;
  147. break;
  148. }
  149. //
  150. // verify output length
  151. //
  152. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  153. if (buffLen < sizeof (USB_STRING_DESCRIPTOR)) {
  154. status = STATUS_BUFFER_TOO_SMALL;
  155. break;
  156. }
  157. //
  158. // if the caller didn't specify a language ID, then insert the default
  159. // language ID. (but only if the caller is not trying to retrive
  160. // the array of language IDs.
  161. //
  162. if ((0 == stringDescriptor->LanguageId) &&
  163. (0 != stringDescriptor->Index)) {
  164. stringDescriptor->LanguageId = deviceExtension->LanguageId;
  165. }
  166. switch (stringDescriptor->Recipient)
  167. {
  168. case GENUSB_RECIPIENT_DEVICE:
  169. stringDescriptor->Recipient = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
  170. break;
  171. case GENUSB_RECIPIENT_INTERFACE:
  172. stringDescriptor->Recipient = URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE;
  173. break;
  174. case GENUSB_RECIPIENT_ENDPOINT:
  175. stringDescriptor->Recipient = URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT;
  176. break;
  177. default:
  178. status = STATUS_INVALID_PARAMETER;
  179. goto GenUSB_DeviceControlDone;
  180. }
  181. status = GenUSB_GetDescriptor (DeviceObject,
  182. stringDescriptor->Recipient,
  183. USB_STRING_DESCRIPTOR_TYPE,
  184. stringDescriptor->Index,
  185. stringDescriptor->LanguageId,
  186. 0, // retry count
  187. buffLen,
  188. &buffer);
  189. if (!NT_SUCCESS (status)) {
  190. DBGPRINT(1, ("Get String Descriptor failed (%x) %08X\n",
  191. stringDescriptor->Index,
  192. status));
  193. break;
  194. }
  195. Irp->IoStatus.Information = buffLen;
  196. break;
  197. case IOCTL_GENUSB_GET_REQUEST:
  198. LOGENTRY(deviceExtension, 'IO_3', ioControlCode, DeviceObject, Irp);
  199. if (NULL == Irp->AssociatedIrp.SystemBuffer) {
  200. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  201. status = STATUS_INVALID_PARAMETER;
  202. break;
  203. }
  204. request = Irp->AssociatedIrp.SystemBuffer;
  205. requestResult = Irp->AssociatedIrp.SystemBuffer;
  206. //
  207. // verify input length
  208. //
  209. buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  210. if (buffLen != sizeof (GENUSB_GET_REQUEST)) {
  211. status = STATUS_INVALID_PARAMETER;
  212. break;
  213. }
  214. //
  215. // verify output length
  216. //
  217. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  218. if (buffLen < sizeof (GENUSB_REQUEST_RESULTS)) {
  219. status = STATUS_BUFFER_TOO_SMALL;
  220. break;
  221. }
  222. //
  223. // adjust the buffer
  224. //
  225. buffer = requestResult->Buffer;
  226. buffLen -= FIELD_OFFSET (GENUSB_REQUEST_RESULTS, Buffer);
  227. LOGENTRY(deviceExtension,
  228. 'IoGR',
  229. (request->RequestType << 8) & request->Request,
  230. request->Value,
  231. request->Index);
  232. DBGPRINT(2, ("Get Request: Type %x Request %x Value %x Index %x\n",
  233. request->RequestType,
  234. request->Request,
  235. request->Value,
  236. request->Index));
  237. status = GenUSB_VendorControlRequest (DeviceObject,
  238. request->RequestType,
  239. request->Request,
  240. request->Value,
  241. request->Index,
  242. (USHORT) buffLen, // disallow longer descriptors
  243. 0, // retry count
  244. &urbStatus,
  245. &resultLength,
  246. &buffer);
  247. requestResult->Status = urbStatus;
  248. requestResult->Length = resultLength;
  249. if (!NT_SUCCESS (status))
  250. {
  251. DBGPRINT(1, ("Get Descriptor failed (%x) %08X\n", urbStatus));
  252. Irp->IoStatus.Information = sizeof (GENUSB_REQUEST_RESULTS);
  253. status = STATUS_SUCCESS;
  254. } else {
  255. Irp->IoStatus.Information = resultLength
  256. + FIELD_OFFSET (GENUSB_REQUEST_RESULTS, Buffer);
  257. }
  258. break;
  259. case IOCTL_GENUSB_GET_CAPS:
  260. LOGENTRY(deviceExtension, 'IO_4', ioControlCode, DeviceObject, Irp);
  261. //
  262. // METHOD_BUFFERED irp. the buffer is in the AssociatedIrp.
  263. //
  264. if (NULL == Irp->AssociatedIrp.SystemBuffer) {
  265. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  266. status = STATUS_INVALID_PARAMETER;
  267. break;
  268. }
  269. buffer = Irp->AssociatedIrp.SystemBuffer;
  270. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  271. if (buffLen < sizeof (GENUSB_CAPABILITIES)) {
  272. status = STATUS_BUFFER_TOO_SMALL;
  273. break;
  274. }
  275. ((PGENUSB_CAPABILITIES) buffer) ->DeviceDescriptorLength =
  276. deviceExtension->DeviceDescriptor->bLength;
  277. ((PGENUSB_CAPABILITIES) buffer) ->ConfigurationInformationLength =
  278. deviceExtension->ConfigurationDescriptor->wTotalLength;
  279. Irp->IoStatus.Information = sizeof (GENUSB_CAPABILITIES);
  280. status = STATUS_SUCCESS;
  281. break;
  282. case IOCTL_GENUSB_SELECT_CONFIGURATION:
  283. LOGENTRY(deviceExtension, 'IO_5', ioControlCode, DeviceObject, Irp);
  284. //
  285. // GenUSB_SelectInterface checks to see if the configuration handle
  286. // is already set and fails if it is.
  287. //
  288. // if (NULL != deviceExtension->ConfigurationHandle)
  289. // {
  290. // status = STATUS_UNSUCCESSFUL;
  291. // }
  292. //
  293. if (NULL == Irp->AssociatedIrp.SystemBuffer)
  294. {
  295. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  296. status = STATUS_INVALID_PARAMETER;
  297. break;
  298. }
  299. selectConfig = Irp->AssociatedIrp.SystemBuffer;
  300. //
  301. // The input buffer must be long enough to contain at least the
  302. // header information
  303. //
  304. buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  305. if (buffLen < sizeof (GENUSB_SELECT_CONFIGURATION))
  306. {
  307. status = STATUS_BUFFER_TOO_SMALL;
  308. break;
  309. }
  310. //
  311. // The input buffer must be exactly the length as specfied by the
  312. // header information.
  313. //
  314. numberInterfaces = selectConfig->NumberInterfaces;
  315. if (buffLen != sizeof (GENUSB_SELECT_CONFIGURATION)
  316. + (sizeof (USB_INTERFACE_DESCRIPTOR) * numberInterfaces))
  317. {
  318. status = STATUS_BUFFER_TOO_SMALL;
  319. break;
  320. }
  321. //
  322. // The output buffer must be same length
  323. //
  324. if (buffLen != irpSp->Parameters.DeviceIoControl.OutputBufferLength)
  325. {
  326. status = STATUS_BUFFER_TOO_SMALL;
  327. break;
  328. }
  329. status = GenUSB_SelectConfiguration (deviceExtension,
  330. numberInterfaces,
  331. selectConfig->Interfaces,
  332. selectConfig->Interfaces);
  333. if (!NT_SUCCESS (status))
  334. {
  335. break;
  336. }
  337. //
  338. // rebase the interface numbers
  339. //
  340. for (i = 0; i < selectConfig->NumberInterfaces; i++)
  341. {
  342. selectConfig->Interfaces[i].bInterfaceNumber = (UCHAR) i;
  343. }
  344. selectConfig->NumberInterfaces = deviceExtension->InterfacesFound;
  345. Irp->IoStatus.Information = buffLen;
  346. break;
  347. case IOCTL_GENUSB_DESELECT_CONFIGURATION:
  348. LOGENTRY(deviceExtension, 'IO_6', ioControlCode, DeviceObject, Irp);
  349. status = GenUSB_DeselectConfiguration (deviceExtension, TRUE);
  350. Irp->IoStatus.Information = 0;
  351. break;
  352. case IOCTL_GENUSB_GET_PIPE_INFO:
  353. LOGENTRY(deviceExtension, 'IO_7', ioControlCode, DeviceObject, Irp);
  354. if (NULL == Irp->AssociatedIrp.SystemBuffer)
  355. {
  356. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  357. status = STATUS_INVALID_PARAMETER;
  358. break;
  359. }
  360. //
  361. // verify input length
  362. //
  363. buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  364. if (buffLen != sizeof (GENUSB_PIPE_INFO_REQUEST))
  365. {
  366. status = STATUS_INVALID_PARAMETER;
  367. break;
  368. }
  369. //
  370. // verify output length
  371. //
  372. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  373. if (buffLen != sizeof (GENUSB_PIPE_INFORMATION))
  374. {
  375. status = STATUS_INVALID_PARAMETER;
  376. break;
  377. }
  378. status =
  379. GenUSB_GetSetPipe (
  380. deviceExtension,
  381. NULL, // no interface index
  382. &((PGENUSB_PIPE_INFO_REQUEST) Irp->AssociatedIrp.SystemBuffer)->InterfaceNumber,
  383. NULL, // no pipe index
  384. &((PGENUSB_PIPE_INFO_REQUEST) Irp->AssociatedIrp.SystemBuffer)->EndpointAddress,
  385. NULL, // No set Properties
  386. (PGENUSB_PIPE_INFORMATION) Irp->AssociatedIrp.SystemBuffer,
  387. NULL, // No set Properties
  388. NULL); // No UsbdPipeHandles needed
  389. if (NT_SUCCESS (status))
  390. {
  391. Irp->IoStatus.Information = sizeof (GENUSB_PIPE_INFORMATION);
  392. }
  393. break;
  394. case IOCTL_GENUSB_SET_READ_WRITE_PIPES:
  395. LOGENTRY(deviceExtension, 'IO_8', ioControlCode, DeviceObject, Irp);
  396. if (NULL == Irp->AssociatedIrp.SystemBuffer)
  397. {
  398. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  399. status = STATUS_INVALID_PARAMETER;
  400. break;
  401. }
  402. readWritePipes =
  403. (PGENUSB_SET_READ_WRITE_PIPES) Irp->AssociatedIrp.SystemBuffer;
  404. //
  405. // verify input length
  406. //
  407. buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  408. if (buffLen != sizeof (GENUSB_SET_READ_WRITE_PIPES))
  409. {
  410. status = STATUS_INVALID_PARAMETER;
  411. break;
  412. }
  413. //
  414. // verify output length
  415. //
  416. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  417. if (buffLen != 0)
  418. {
  419. status = STATUS_INVALID_PARAMETER;
  420. break;
  421. }
  422. status = GenUSB_SetReadWritePipes (
  423. deviceExtension,
  424. (PGENUSB_PIPE_HANDLE) &readWritePipes->ReadPipe,
  425. (PGENUSB_PIPE_HANDLE) &readWritePipes->WritePipe);
  426. // on success the information field stays at zero.
  427. //
  428. // if (NT_SUCCESS (status))
  429. // {
  430. // Irp->IoStatus.Information = 0;
  431. // }
  432. break;
  433. case IOCTL_GENUSB_GET_PIPE_PROPERTIES:
  434. LOGENTRY(deviceExtension, 'IO_9', ioControlCode, DeviceObject, Irp);
  435. //
  436. // METHOD_BUFFERED irp. the buffer is in the AssociatedIrp.
  437. //
  438. if (NULL == Irp->AssociatedIrp.SystemBuffer)
  439. {
  440. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  441. status = STATUS_INVALID_PARAMETER;
  442. break;
  443. }
  444. buffer = Irp->AssociatedIrp.SystemBuffer;
  445. buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  446. if (buffLen != sizeof (GENUSB_PIPE_HANDLE))
  447. {
  448. status = STATUS_BUFFER_TOO_SMALL;
  449. break;
  450. }
  451. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  452. if (buffLen != sizeof (GENUSB_PIPE_PROPERTIES))
  453. {
  454. status = STATUS_BUFFER_TOO_SMALL;
  455. break;
  456. }
  457. if (! VERIFY_PIPE_HANDLE_SIG (buffer, deviceExtension))
  458. {
  459. status = STATUS_INVALID_PARAMETER;
  460. break;
  461. }
  462. status =
  463. GenUSB_GetSetPipe (
  464. deviceExtension,
  465. &((PGENUSB_PIPE_HANDLE) buffer)->InterfaceIndex,
  466. NULL, // no interface number
  467. &((PGENUSB_PIPE_HANDLE) buffer)->PipeIndex,
  468. NULL, // no endpoint address
  469. NULL, // no set
  470. NULL, // no Pipe Info
  471. ((PGENUSB_PIPE_PROPERTIES) buffer),
  472. NULL); // usbd PipeHandle not needed
  473. Irp->IoStatus.Information = sizeof (GENUSB_PIPE_PROPERTIES);
  474. status = STATUS_SUCCESS;
  475. break;
  476. case IOCTL_GENUSB_SET_PIPE_PROPERTIES:
  477. LOGENTRY(deviceExtension, 'IO_A', ioControlCode, DeviceObject, Irp);
  478. //
  479. // METHOD_BUFFERED irp. the buffer is in the AssociatedIrp.
  480. //
  481. if (NULL == Irp->AssociatedIrp.SystemBuffer)
  482. {
  483. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  484. status = STATUS_INVALID_PARAMETER;
  485. break;
  486. }
  487. buffer = Irp->AssociatedIrp.SystemBuffer;
  488. // Verify Input Length
  489. buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  490. if (buffLen != sizeof (GENUSB_PIPE_HANDLE) + sizeof (GENUSB_PIPE_PROPERTIES))
  491. {
  492. status = STATUS_BUFFER_TOO_SMALL;
  493. break;
  494. }
  495. // Verify Output Length
  496. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  497. if (buffLen != 0)
  498. {
  499. status = STATUS_INVALID_PARAMETER;
  500. break;
  501. }
  502. if (! VERIFY_PIPE_HANDLE_SIG (buffer, deviceExtension))
  503. {
  504. status = STATUS_INVALID_PARAMETER;
  505. break;
  506. }
  507. status =
  508. GenUSB_GetSetPipe (
  509. deviceExtension,
  510. &((PGENUSB_PIPE_HANDLE) buffer)->InterfaceIndex,
  511. NULL, // no interface number
  512. &((PGENUSB_PIPE_HANDLE) buffer)->PipeIndex,
  513. NULL, // no endpoint address
  514. (PGENUSB_PIPE_PROPERTIES) (buffer + sizeof (GENUSB_PIPE_HANDLE)),
  515. NULL, // no Pipe Info
  516. NULL, // no Get
  517. NULL); // no UsbdPipeHandle needed
  518. Irp->IoStatus.Information = 0;
  519. status = STATUS_SUCCESS;
  520. break;
  521. case IOCTL_GENUSB_RESET_PIPE:
  522. LOGENTRY(deviceExtension, 'IO_B', ioControlCode, DeviceObject, Irp);
  523. //
  524. // METHOD_BUFFERED irp. the buffer is in the AssociatedIrp.
  525. //
  526. if (NULL == Irp->AssociatedIrp.SystemBuffer)
  527. {
  528. ASSERT (Irp->AssociatedIrp.SystemBuffer);
  529. status = STATUS_INVALID_PARAMETER;
  530. break;
  531. }
  532. buffer = Irp->AssociatedIrp.SystemBuffer;
  533. buffLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  534. if (buffLen != sizeof (GENUSB_RESET_PIPE))
  535. {
  536. status = STATUS_BUFFER_TOO_SMALL;
  537. break;
  538. }
  539. buffLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  540. if (buffLen != 0)
  541. {
  542. status = STATUS_INVALID_PARAMETER;
  543. break;
  544. }
  545. if (! VERIFY_PIPE_HANDLE_SIG (buffer, deviceExtension))
  546. {
  547. status = STATUS_INVALID_PARAMETER;
  548. break;
  549. }
  550. status =
  551. GenUSB_GetSetPipe (
  552. deviceExtension,
  553. &((PGENUSB_PIPE_HANDLE) buffer)->InterfaceIndex,
  554. NULL, // no interface number
  555. &((PGENUSB_PIPE_HANDLE) buffer)->PipeIndex,
  556. NULL, // no endpoint address
  557. NULL, // no set
  558. NULL, // no Pipe Info
  559. NULL, // no PipeProperties
  560. &usbdPipeHandle);
  561. if (!NT_SUCCESS (status))
  562. {
  563. break;
  564. }
  565. status = GenUSB_ResetPipe (deviceExtension,
  566. usbdPipeHandle,
  567. ((PGENUSB_RESET_PIPE)buffer)->ResetPipe,
  568. ((PGENUSB_RESET_PIPE)buffer)->ClearStall,
  569. ((PGENUSB_RESET_PIPE)buffer)->FlushData);
  570. Irp->IoStatus.Information = 0;
  571. break;
  572. case IOCTL_GENUSB_READ_WRITE_PIPE:
  573. LOGENTRY(deviceExtension, 'IO_C', ioControlCode, DeviceObject, Irp);
  574. status = GenUSB_ProbeAndSubmitTransfer (Irp, irpSp, deviceExtension);
  575. complete = FALSE;
  576. break;
  577. default:
  578. //
  579. // 'Fail' the Irp by returning the default status.
  580. //
  581. status = STATUS_NOT_IMPLEMENTED;
  582. break;
  583. }
  584. GenUSB_DeviceControlDone:
  585. IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
  586. if (complete)
  587. {
  588. Irp->IoStatus.Status = status;
  589. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  590. }
  591. return status;
  592. }
  593. NTSTATUS
  594. GenUSB_ProbeAndSubmitTransferComplete (
  595. IN PDEVICE_OBJECT DeviceObject,
  596. IN PIRP Irp,
  597. IN PGENUSB_TRANSFER LocalTrans,
  598. IN USBD_STATUS Status,
  599. IN ULONG Length
  600. );
  601. NTSTATUS
  602. GenUSB_ProbeAndSubmitTransfer (
  603. IN PIRP Irp,
  604. IN PIO_STACK_LOCATION IrpSp,
  605. IN PDEVICE_EXTENSION DeviceExtension
  606. )
  607. {
  608. NTSTATUS status;
  609. PMDL mdl;
  610. BOOLEAN userLocked;
  611. BOOLEAN transferLocked;
  612. PGENUSB_READ_WRITE_PIPE userTrans; // a pointer to the user's buffer
  613. PGENUSB_TRANSFER localTrans; // a local copy of the user data.
  614. LOGENTRY(DeviceExtension, 'PROB', DeviceExtension->Self, Irp, 0);
  615. status = STATUS_SUCCESS;
  616. userTrans = NULL;
  617. localTrans = NULL;
  618. userLocked = FALSE;
  619. transferLocked = FALSE;
  620. //
  621. // Validate the user's buffer.
  622. //
  623. try {
  624. if (sizeof (GENUSB_READ_WRITE_PIPE) !=
  625. IrpSp->Parameters.DeviceIoControl.InputBufferLength)
  626. {
  627. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  628. }
  629. userTrans = (PGENUSB_READ_WRITE_PIPE)
  630. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  631. if (NULL == userTrans)
  632. {
  633. ExRaiseStatus (STATUS_INVALID_PARAMETER);
  634. }
  635. localTrans = (PGENUSB_TRANSFER)
  636. ExAllocatePool (NonPagedPool, sizeof (GENUSB_TRANSFER));
  637. if (NULL == localTrans)
  638. {
  639. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  640. }
  641. RtlZeroMemory (localTrans, sizeof (GENUSB_TRANSFER));
  642. //
  643. // The input comes in User Buffer, and should be a
  644. // PGENUSB_READ_WRITE_PIPE structure.
  645. //
  646. localTrans->UserMdl = IoAllocateMdl (userTrans,
  647. sizeof(PGENUSB_READ_WRITE_PIPE),
  648. FALSE, // no 2nd buffer
  649. TRUE, // charge quota
  650. NULL); // no associated irp
  651. if (NULL == localTrans->UserMdl)
  652. {
  653. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  654. }
  655. MmProbeAndLockPages (localTrans->UserMdl,
  656. KernelMode,
  657. ((localTrans->UserCopy.UsbdTransferFlags
  658. & USBD_TRANSFER_DIRECTION_IN)
  659. ? IoReadAccess
  660. : IoWriteAccess));
  661. userLocked = TRUE;
  662. // make a local copy of the user data so that it doesn't move.
  663. localTrans->UserCopy = *userTrans;
  664. // mask off the invalid flags.
  665. localTrans->UserCopy.UsbdTransferFlags &=
  666. USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION;
  667. // Now probe the transfer location
  668. localTrans->TransferMdl = IoAllocateMdl (
  669. localTrans->UserCopy.UserBuffer,
  670. localTrans->UserCopy.BufferLength,
  671. FALSE, // no 2nd buffer
  672. TRUE, // do charge the quota
  673. NULL); // no associated irp
  674. if (NULL == localTrans->TransferMdl)
  675. {
  676. ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES);
  677. }
  678. MmProbeAndLockPages (localTrans->TransferMdl,
  679. KernelMode,
  680. ((localTrans->UserCopy.UsbdTransferFlags
  681. & USBD_TRANSFER_DIRECTION_IN)
  682. ? IoReadAccess
  683. : IoWriteAccess));
  684. transferLocked = TRUE;
  685. } except (EXCEPTION_EXECUTE_HANDLER) {
  686. status = GetExceptionCode();
  687. goto GenUSBProbSubmitTransferReject;
  688. }
  689. if (! VERIFY_PIPE_HANDLE_SIG (&localTrans->UserCopy.Pipe, DeviceExtension))
  690. {
  691. status = STATUS_INVALID_PARAMETER;
  692. goto GenUSBProbSubmitTransferReject;
  693. }
  694. // Unfortunately we complete, we will no longer running in the contect
  695. // of the caller.
  696. // Therefore we we cannot use LocalTrans->UserCopy.UserBuffer to just
  697. // dump the return data. We instead need a system address for it.
  698. localTrans->SystemAddress =
  699. MmGetSystemAddressForMdlSafe (localTrans->UserMdl, NormalPagePriority);
  700. if (NULL == localTrans->SystemAddress)
  701. {
  702. status = STATUS_INSUFFICIENT_RESOURCES;
  703. goto GenUSBProbSubmitTransferReject;
  704. }
  705. //
  706. // now perform the transfer.
  707. //
  708. LOGENTRY(DeviceExtension, 'prob', DeviceExtension->Self, Irp, status);
  709. status = GenUSB_TransmitReceive (
  710. DeviceExtension,
  711. Irp,
  712. ((PGENUSB_PIPE_HANDLE)&localTrans->UserCopy.Pipe)->InterfaceIndex,
  713. ((PGENUSB_PIPE_HANDLE)&localTrans->UserCopy.Pipe)->PipeIndex,
  714. localTrans->UserCopy.UsbdTransferFlags,
  715. NULL, // no buffer pointer
  716. localTrans->TransferMdl,
  717. localTrans->UserCopy.BufferLength,
  718. localTrans,
  719. GenUSB_ProbeAndSubmitTransferComplete);
  720. return status;
  721. GenUSBProbSubmitTransferReject:
  722. LOGENTRY (DeviceExtension, 'prob', DeviceExtension->Self, Irp, status);
  723. if (NULL != localTrans)
  724. {
  725. if (localTrans->UserMdl)
  726. {
  727. if (userLocked)
  728. {
  729. MmUnlockPages (localTrans->UserMdl);
  730. }
  731. IoFreeMdl (localTrans->UserMdl);
  732. }
  733. if (localTrans->TransferMdl)
  734. {
  735. if (transferLocked)
  736. {
  737. MmUnlockPages (localTrans->TransferMdl);
  738. }
  739. IoFreeMdl (localTrans->TransferMdl);
  740. }
  741. ExFreePool (localTrans);
  742. }
  743. Irp->IoStatus.Status = status;
  744. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  745. return status;
  746. }
  747. NTSTATUS
  748. GenUSB_ProbeAndSubmitTransferComplete (
  749. IN PDEVICE_OBJECT DeviceObject,
  750. IN PIRP Irp,
  751. IN PGENUSB_TRANSFER LocalTrans,
  752. IN USBD_STATUS UrbStatus,
  753. IN ULONG Length
  754. )
  755. {
  756. PDEVICE_EXTENSION deviceExtension;
  757. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  758. LOGENTRY(deviceExtension, 'PrbC', Irp, Length, UrbStatus);
  759. // Regardless of whether or not the transaction was successful,
  760. // we need to free the MDL that points to the users transfer buffer.
  761. MmUnlockPages (LocalTrans->TransferMdl);
  762. IoFreeMdl (LocalTrans->TransferMdl);
  763. LocalTrans->UserCopy.UrbStatus = UrbStatus;
  764. LocalTrans->UserCopy.BufferLength = Length;
  765. //
  766. // since we are not in the caller's context any more
  767. // we cannot just use LocalTrans->UserCopy.UserBuffer to copy the data
  768. // back. We must instead use the system address, which should already
  769. // be all set up.
  770. //
  771. ASSERT (NULL != LocalTrans->SystemAddress);
  772. *LocalTrans->SystemAddress = LocalTrans->UserCopy;
  773. // Now free the user buffer containing the arguments.
  774. MmUnlockPages (LocalTrans->UserMdl);
  775. IoFreeMdl (LocalTrans->UserMdl);
  776. ExFreePool (LocalTrans);
  777. return Irp->IoStatus.Status;
  778. }