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.

318 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. feature.c
  5. Abstract
  6. Feature handling routines
  7. Author:
  8. Ervin P.
  9. Environment:
  10. Kernel mode only
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #if 0
  15. /*
  16. ********************************************************************************
  17. * HidpGetSetFeatureComplete
  18. ********************************************************************************
  19. *
  20. *
  21. */
  22. NTSTATUS HidpGetSetFeatureComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  23. {
  24. PHIDCLASS_DEVICE_EXTENSION hidDeviceExtension = (PHIDCLASS_DEVICE_EXTENSION)Context;
  25. PHID_XFER_PACKET featurePacket = Irp->UserBuffer;
  26. NTSTATUS status = Irp->IoStatus.Status;
  27. DBG_COMMON_ENTRY()
  28. ASSERT(hidDeviceExtension->isClientPdo);
  29. if (featurePacket){
  30. DBG_RECORD_FEATURE(featurePacket->reportId, IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode, TRUE)
  31. /*
  32. * Free the feature packet.
  33. */
  34. ExFreePool(featurePacket);
  35. Irp->UserBuffer = NULL;
  36. }
  37. if (NT_SUCCESS(status)){
  38. FDO_EXTENSION *fdoExt = &hidDeviceExtension->pdoExt.deviceFdoExt->fdoExt;
  39. if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0){
  40. /*
  41. * Since this collection only has one report,
  42. * we deleted the report id (which is known implicitly)
  43. * on the way down. We now have to bump the return
  44. * value to indicate that one more byte was sent or received.
  45. */
  46. (ULONG)Irp->IoStatus.Information++;
  47. }
  48. }
  49. /*
  50. * If the lower driver returned PENDING, mark our stack location as pending also.
  51. */
  52. if (Irp->PendingReturned){
  53. IoMarkIrpPending(Irp);
  54. }
  55. DBG_COMMON_EXIT()
  56. return status;
  57. }
  58. /*
  59. ********************************************************************************
  60. * HidpGetSetFeature
  61. ********************************************************************************
  62. *
  63. * There are not many differences between reading and writing a feature at this level,
  64. * so we have one function do both.
  65. *
  66. * controlCode is either IOCTL_HID_GET_FEATURE or IOCTL_HID_SET_FEATURE.
  67. *
  68. * Note: This function cannot be pageable because it is called
  69. * from the IOCTL dispatch routine, which can get called
  70. * at DISPATCH_LEVEL.
  71. *
  72. */
  73. NTSTATUS HidpGetSetFeature( IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension,
  74. IN OUT PIRP Irp,
  75. IN ULONG controlCode,
  76. OUT BOOLEAN *sentIrp)
  77. {
  78. FDO_EXTENSION *fdoExt;
  79. NTSTATUS status = STATUS_SUCCESS;
  80. PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
  81. PFILE_OBJECT fileObject;
  82. PHIDCLASS_FILE_EXTENSION fileExtension;
  83. DBG_COMMON_ENTRY()
  84. ASSERT(HidDeviceExtension->isClientPdo);
  85. fdoExt = &HidDeviceExtension->pdoExt.deviceFdoExt->fdoExt;
  86. currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
  87. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  88. *sentIrp = FALSE;
  89. /*
  90. * Get the file extension.
  91. */
  92. ASSERT(currentIrpSp->FileObject);
  93. fileObject = currentIrpSp->FileObject;
  94. if(!fileObject->FsContext) {
  95. DBGWARN(("Attempted to get/set feature with no file extension"))
  96. return STATUS_PRIVILEGE_NOT_HELD;
  97. }
  98. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  99. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  100. /*
  101. * Check security.
  102. */
  103. if (fileExtension->SecurityCheck){
  104. PHIDP_COLLECTION_DESC collectionDesc;
  105. /*
  106. * Get our collection description.
  107. */
  108. collectionDesc = GetCollectionDesc(fdoExt, fileExtension->CollectionNumber);
  109. if (collectionDesc){
  110. /*
  111. * Make sure that there is a feature report on this collection
  112. * (or that we allow feature reads on a non-feature ctn for this device).
  113. */
  114. if ((collectionDesc->FeatureLength > 0) ||
  115. (fdoExt->deviceSpecificFlags & DEVICE_FLAG_ALLOW_FEATURE_ON_NON_FEATURE_COLLECTION)){
  116. PUCHAR featureBuf;
  117. ULONG featureBufLen;
  118. switch (controlCode){
  119. case IOCTL_HID_GET_FEATURE:
  120. featureBufLen = currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  121. featureBuf = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
  122. break;
  123. case IOCTL_HID_SET_FEATURE:
  124. featureBuf = Irp->AssociatedIrp.SystemBuffer;
  125. featureBufLen = currentIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  126. break;
  127. default:
  128. TRAP;
  129. status = STATUS_INVALID_PARAMETER;
  130. featureBuf = NULL;
  131. featureBufLen = 0;
  132. }
  133. if (featureBuf && featureBufLen){
  134. PHIDP_REPORT_IDS reportIdent;
  135. UCHAR reportId;
  136. /*
  137. * The client includes the report id as the first byte of the report.
  138. * We send down the report byte only if the device has multiple
  139. * report IDs (i.e. the report id is not implicit).
  140. */
  141. reportId = featureBuf[0];
  142. if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0){
  143. DBGASSERT((reportId == 0),
  144. ("Report Id should be zero, acutal id = %d", reportId),
  145. FALSE)
  146. featureBuf++;
  147. featureBufLen--;
  148. }
  149. /*
  150. * Try to find a matching feature report for this device.
  151. */
  152. reportIdent = GetReportIdentifier(fdoExt, reportId);
  153. /*
  154. * Check the buffer length against the
  155. * feature length in the report identifier.
  156. */
  157. if (reportIdent){
  158. if (reportIdent->FeatureLength){
  159. switch (controlCode){
  160. case IOCTL_HID_GET_FEATURE:
  161. /*
  162. * The buffer must be big enough for the report.
  163. */
  164. if (featureBufLen < reportIdent->FeatureLength){
  165. ASSERT(!(PVOID)"feature buf must be at least feature size for get-feature.");
  166. reportIdent = NULL;
  167. }
  168. break;
  169. case IOCTL_HID_SET_FEATURE:
  170. /*
  171. * The buffer must be big enough for the report.
  172. * It CAN be larger, and it is up to us to use
  173. * the correct report size from the report identifier.
  174. */
  175. if (featureBufLen < reportIdent->FeatureLength){
  176. ASSERT(!(PVOID)"feature buf must be exact size for set-feature.");
  177. reportIdent = NULL;
  178. }
  179. else {
  180. featureBufLen = reportIdent->FeatureLength;
  181. }
  182. break;
  183. }
  184. }
  185. else {
  186. /*
  187. * This report id is not for a feature report.
  188. */
  189. reportIdent = NULL;
  190. }
  191. }
  192. if (reportIdent ||
  193. (fdoExt->deviceSpecificFlags & DEVICE_FLAG_ALLOW_FEATURE_ON_NON_FEATURE_COLLECTION)){
  194. PHID_XFER_PACKET featurePacket = ALLOCATEPOOL(NonPagedPool, sizeof(HID_XFER_PACKET));
  195. if (featurePacket){
  196. featurePacket->reportBuffer = featureBuf;
  197. featurePacket->reportBufferLen = featureBufLen;
  198. featurePacket->reportId = reportId;
  199. Irp->UserBuffer = featurePacket;
  200. /*
  201. * Prepare the next (lower) IRP stack location.
  202. * This will be HIDUSB's "current" stack location.
  203. */
  204. nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  205. nextIrpSp->Parameters.DeviceIoControl.IoControlCode = controlCode;
  206. /*
  207. * Note - input/output is relative to IOCTL servicer
  208. */
  209. switch (controlCode){
  210. case IOCTL_HID_GET_FEATURE:
  211. nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_XFER_PACKET);
  212. break;
  213. case IOCTL_HID_SET_FEATURE:
  214. nextIrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(HID_XFER_PACKET);
  215. break;
  216. default:
  217. TRAP;
  218. }
  219. DBG_RECORD_FEATURE(reportId, controlCode, FALSE)
  220. status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
  221. if (!NT_SUCCESS(status)){
  222. DBGWARN(("HidpGetSetFeature: usb returned status %xh.", status))
  223. }
  224. DBG_RECORD_FEATURE(reportId, controlCode, TRUE)
  225. ExFreePool(featurePacket);
  226. *sentIrp = FALSE; // needs to be completed again
  227. }
  228. else {
  229. ASSERT(featurePacket);
  230. status = STATUS_INSUFFICIENT_RESOURCES;
  231. }
  232. }
  233. else {
  234. DBGASSERT(reportIdent, ("Some yahoo sent invalid data in ioctl %x", controlCode), FALSE)
  235. status = STATUS_DATA_ERROR;
  236. }
  237. }
  238. else if (NT_SUCCESS(status)) {
  239. DBGASSERT(featureBuf, ("Feature buffer is invalid"), FALSE)
  240. DBGASSERT(featureBufLen, ("Feature buffer length is invalid"), FALSE)
  241. status = STATUS_INVALID_BUFFER_SIZE;
  242. }
  243. }
  244. else {
  245. ASSERT(collectionDesc->FeatureLength);
  246. status = STATUS_INVALID_DEVICE_REQUEST;
  247. }
  248. }
  249. else {
  250. ASSERT(collectionDesc);
  251. status = STATUS_DEVICE_NOT_CONNECTED;
  252. }
  253. }
  254. else {
  255. ASSERT(fileExtension->SecurityCheck);
  256. status = STATUS_PRIVILEGE_NOT_HELD;
  257. }
  258. DBGSUCCESS(status, FALSE)
  259. DBG_COMMON_EXIT()
  260. return status;
  261. }
  262. #endif