Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
7.2 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. write.c
  5. Abstract
  6. Write handling routines
  7. Author:
  8. Forrest Foltz
  9. Ervin P.
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "pch.h"
  15. /*
  16. ********************************************************************************
  17. * HidpInterruptWriteComplete
  18. ********************************************************************************
  19. *
  20. *
  21. */
  22. NTSTATUS HidpInterruptWriteComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  23. {
  24. PHIDCLASS_DEVICE_EXTENSION hidDeviceExtension = (PHIDCLASS_DEVICE_EXTENSION)Context;
  25. NTSTATUS status = Irp->IoStatus.Status;
  26. PHID_XFER_PACKET hidWritePacket;
  27. DBG_COMMON_ENTRY()
  28. ASSERT(hidDeviceExtension->isClientPdo);
  29. ASSERT(Irp->UserBuffer);
  30. hidWritePacket = Irp->UserBuffer;
  31. ExFreePool(hidWritePacket);
  32. Irp->UserBuffer = NULL;
  33. if (NT_SUCCESS(status)){
  34. FDO_EXTENSION *fdoExt = &hidDeviceExtension->pdoExt.deviceFdoExt->fdoExt;
  35. PHIDP_COLLECTION_DESC collectionDesc = GetCollectionDesc(fdoExt, hidDeviceExtension->pdoExt.collectionNum);
  36. if (collectionDesc){
  37. HidpSetDeviceBusy(fdoExt);
  38. Irp->IoStatus.Information = collectionDesc->OutputLength;
  39. } else {
  40. //
  41. // How could we get here? Had to get the collectionDesc in order
  42. // to start the write!
  43. //
  44. TRAP;
  45. }
  46. DBGVERBOSE(("HidpInterruptWriteComplete: write irp %ph succeeded, wrote %xh bytes.", Irp, Irp->IoStatus.Information))
  47. }
  48. else {
  49. DBGWARN(("HidpInterruptWriteComplete: write irp %ph failed w/ status %xh.", Irp, status))
  50. }
  51. /*
  52. * If the lower driver returned PENDING, mark our stack location as pending also.
  53. */
  54. if (Irp->PendingReturned){
  55. IoMarkIrpPending(Irp);
  56. }
  57. DBGSUCCESS(status, FALSE)
  58. DBG_COMMON_EXIT()
  59. return status;
  60. }
  61. /*
  62. ********************************************************************************
  63. * HidpIrpMajorWrite
  64. ********************************************************************************
  65. *
  66. * Note: This function cannot be pageable code because
  67. * writes can happen at dispatch level.
  68. *
  69. */
  70. NTSTATUS HidpIrpMajorWrite(IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension, IN OUT PIRP Irp)
  71. {
  72. NTSTATUS status;
  73. PDO_EXTENSION *pdoExt;
  74. FDO_EXTENSION *fdoExt;
  75. PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
  76. BOOLEAN securityCheckOk = FALSE;
  77. PUCHAR buffer;
  78. PHIDP_REPORT_IDS reportIdentifier;
  79. PHIDP_COLLECTION_DESC collectionDesc;
  80. PHID_XFER_PACKET hidWritePacket;
  81. DBG_COMMON_ENTRY()
  82. ASSERT(HidDeviceExtension->isClientPdo);
  83. pdoExt = &HidDeviceExtension->pdoExt;
  84. fdoExt = &HidDeviceExtension->pdoExt.deviceFdoExt->fdoExt;
  85. currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
  86. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  87. if (pdoExt->state != COLLECTION_STATE_RUNNING ||
  88. fdoExt->state != DEVICE_STATE_START_SUCCESS){
  89. status = STATUS_DEVICE_NOT_CONNECTED;
  90. goto HidpIrpMajorWriteDone;
  91. }
  92. /*
  93. * Get the file extension.
  94. */
  95. if (currentIrpSp->FileObject){
  96. PHIDCLASS_FILE_EXTENSION fileExtension = (PHIDCLASS_FILE_EXTENSION)currentIrpSp->FileObject->FsContext;
  97. if (fileExtension) {
  98. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  99. securityCheckOk = fileExtension->SecurityCheck;
  100. }
  101. DBGASSERT(fileExtension, ("Attempted write with no file extension"), FALSE)
  102. }
  103. else {
  104. /*
  105. * KBDCLASS can send a NULL FileObject to set LEDs on a keyboard
  106. * (it may need to do this for a keyboard which was opened by
  107. * the raw user input thread, for which kbdclass has no fileObj).
  108. * A write with FileObject==NULL can only come from kernel space,
  109. * so we treat this as a secure write.
  110. */
  111. securityCheckOk = TRUE;
  112. }
  113. /*
  114. * Check security.
  115. */
  116. if (!securityCheckOk){
  117. status = STATUS_PRIVILEGE_NOT_HELD;
  118. goto HidpIrpMajorWriteDone;
  119. }
  120. status = HidpCheckIdleState(HidDeviceExtension, Irp);
  121. if (status != STATUS_SUCCESS) {
  122. Irp = (status != STATUS_PENDING) ? Irp : (PIRP) BAD_POINTER;
  123. goto HidpIrpMajorWriteDone;
  124. }
  125. buffer = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
  126. if (!buffer) {
  127. status = STATUS_INVALID_USER_BUFFER;
  128. goto HidpIrpMajorWriteDone;
  129. }
  130. /*
  131. * Extract the report identifier with the given id from
  132. * the HID device extension. The report id is the first
  133. * byte of the buffer.
  134. */
  135. reportIdentifier = GetReportIdentifier(fdoExt, buffer[0]);
  136. collectionDesc = GetCollectionDesc(fdoExt, HidDeviceExtension->pdoExt.collectionNum);
  137. if (!collectionDesc ||
  138. !reportIdentifier) {
  139. status = STATUS_INVALID_PARAMETER;
  140. goto HidpIrpMajorWriteDone;
  141. }
  142. if (!reportIdentifier->OutputLength){
  143. status = STATUS_INVALID_PARAMETER;
  144. goto HidpIrpMajorWriteDone;
  145. }
  146. /*
  147. * Make sure the caller's buffer is the right size.
  148. */
  149. if (currentIrpSp->Parameters.Write.Length != collectionDesc->OutputLength){
  150. status = STATUS_INVALID_BUFFER_SIZE;
  151. goto HidpIrpMajorWriteDone;
  152. }
  153. /*
  154. * All parameters are correct. Allocate the write packet and
  155. * send this puppy down.
  156. */
  157. hidWritePacket = ALLOCATEPOOL(NonPagedPool, sizeof(HID_XFER_PACKET));
  158. if (!hidWritePacket){
  159. status = STATUS_INSUFFICIENT_RESOURCES;
  160. goto HidpIrpMajorWriteDone;
  161. }
  162. /*
  163. * Prepare write packet for minidriver.
  164. */
  165. hidWritePacket->reportBuffer = buffer;
  166. hidWritePacket->reportBufferLen = reportIdentifier->OutputLength;
  167. /*
  168. * The client includes the report id as the first byte of the report.
  169. * We send down the report byte only if the device has multiple
  170. * report IDs (i.e. the report id is not implicit).
  171. */
  172. hidWritePacket->reportId = hidWritePacket->reportBuffer[0];
  173. if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0){
  174. ASSERT(hidWritePacket->reportId == 0);
  175. hidWritePacket->reportBuffer++;
  176. }
  177. Irp->UserBuffer = (PVOID)hidWritePacket;
  178. /*
  179. * Prepare the next (lower) IRP stack location.
  180. * This will be HIDUSB's "current" stack location.
  181. */
  182. nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  183. nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_WRITE_REPORT;
  184. nextIrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(HID_XFER_PACKET);
  185. IoSetCompletionRoutine( Irp,
  186. HidpInterruptWriteComplete,
  187. (PVOID)HidDeviceExtension,
  188. TRUE,
  189. TRUE,
  190. TRUE );
  191. status = HidpCallDriver(fdoExt->fdo, Irp);
  192. /*
  193. * The Irp no longer belongs to us, and it can be
  194. * completed at any time; so don't touch it.
  195. */
  196. Irp = (PIRP)BAD_POINTER;
  197. HidpIrpMajorWriteDone:
  198. if (ISPTR(Irp)){
  199. Irp->IoStatus.Status = status;
  200. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  201. }
  202. DBGSUCCESS(status, FALSE)
  203. DBG_COMMON_EXIT();
  204. return status;
  205. }