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.

467 lines
16 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. name.c
  5. Abstract
  6. Get-friendly-name handling routines
  7. Author:
  8. Ervin P.
  9. Environment:
  10. Kernel mode only
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. /*
  15. ********************************************************************************
  16. * HidpGetDeviceString
  17. ********************************************************************************
  18. *
  19. * Note: This function cannot be pageable because it is called
  20. * from the IOCTL dispatch routine, which can get called
  21. * at DISPATCH_LEVEL.
  22. *
  23. */
  24. NTSTATUS HidpGetDeviceString(IN FDO_EXTENSION *fdoExt,
  25. IN OUT PIRP Irp,
  26. IN ULONG stringId,
  27. IN ULONG languageId)
  28. {
  29. BOOLEAN completeIrpHere = TRUE;
  30. NTSTATUS status;
  31. PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
  32. currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
  33. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  34. /*
  35. * The Irp we got uses buffering type METHOD_OUT_DIRECT,
  36. * which passes the buffer in the MDL.
  37. * IOCTL_HID_GET_STRING uses buffering type METHOD_NEITHER,
  38. * which passes the buffer in Irp->UserBuffer.
  39. * So we have to copy the pointer.
  40. */
  41. Irp->UserBuffer = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
  42. if (Irp->UserBuffer){
  43. /*
  44. * Prepare the next (lower) IRP stack location.
  45. * This will be the minidriver's (e.g. HIDUSB's) "current" stack location.
  46. */
  47. nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  48. nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_STRING;
  49. nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength =
  50. currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  51. // Type3InputBuffer has string/lang IDs
  52. nextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  53. ULongToPtr((ULONG)(stringId + (languageId << 16)));
  54. status = HidpCallDriver(fdoExt->fdo, Irp);
  55. /*
  56. * Irp will be completed by lower driver
  57. */
  58. completeIrpHere = FALSE;
  59. }
  60. else {
  61. status = STATUS_INVALID_USER_BUFFER;
  62. }
  63. if (completeIrpHere){
  64. Irp->IoStatus.Status = status;
  65. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  66. }
  67. DBGSUCCESS(status, FALSE)
  68. return status;
  69. }
  70. /*
  71. ********************************************************************************
  72. * HidpGetIndexedString
  73. ********************************************************************************
  74. *
  75. *
  76. *
  77. */
  78. NTSTATUS HidpGetIndexedString( IN FDO_EXTENSION *fdoExt,
  79. IN OUT PIRP Irp,
  80. IN ULONG stringIndex,
  81. IN ULONG languageId)
  82. {
  83. NTSTATUS status;
  84. PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
  85. currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
  86. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  87. /*
  88. * The Irp we got uses buffering type METHOD_OUT_DIRECT,
  89. * which passes the buffer in the MDL.
  90. * The Irp we're sending down uses the same buffering method,
  91. * so just let the lower driver derive the system address
  92. * from the MDL.
  93. */
  94. /*
  95. * Prepare the next (lower) IRP stack location.
  96. * This will be the minidriver's (e.g. HIDUSB's) "current" stack location.
  97. */
  98. nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  99. nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_INDEXED_STRING;
  100. nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  101. // Type3InputBuffer has string index/lang IDs
  102. nextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  103. ULongToPtr((ULONG)(stringIndex + (languageId << 16)));
  104. status = HidpCallDriver(fdoExt->fdo, Irp);
  105. DBGSUCCESS(status, FALSE)
  106. return status;
  107. }
  108. /*
  109. ********************************************************************************
  110. * HidpGetMsGenreDescriptor
  111. ********************************************************************************
  112. *
  113. *
  114. *
  115. */
  116. NTSTATUS HidpGetMsGenreDescriptor(
  117. IN FDO_EXTENSION *fdoExt,
  118. IN OUT PIRP Irp)
  119. {
  120. NTSTATUS status;
  121. PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
  122. DBGOUT(("Received request for genre descriptor in hidclass"))
  123. currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
  124. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  125. /*
  126. * The Irp we got uses buffering type METHOD_OUT_DIRECT,
  127. * which passes the buffer in the MDL.
  128. * The Irp we're sending down uses the same buffering method,
  129. * so just let the lower driver derive the system address
  130. * from the MDL.
  131. */
  132. /*
  133. * Prepare the next (lower) IRP stack location.
  134. * This will be the minidriver's (e.g. HIDUSB's) "current" stack location.
  135. */
  136. nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  137. nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_MS_GENRE_DESCRIPTOR;
  138. nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  139. status = HidpCallDriver(fdoExt->fdo, Irp);
  140. DBGSUCCESS(status, FALSE)
  141. return status;
  142. }
  143. /*
  144. ********************************************************************************
  145. * HidpGetSetReport
  146. ********************************************************************************
  147. *
  148. * There are not many differences between reading and writing a
  149. * report at this level, whether it be an input, output or feature
  150. * report, so we have one function do all six.
  151. *
  152. * controlCode is one of:
  153. * IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_INPUT_REPORT
  154. * IOCTL_HID_GET_OUTPUT_REPORT, IOCTL_HID_SET_OUTPUT_REPORT
  155. * IOCTL_HID_GET_FEATURE, IOCTL_HID_SET_FEATURE
  156. *
  157. * Note: This function cannot be pageable because it is called
  158. * from the IOCTL dispatch routine, which can get called
  159. * at DISPATCH_LEVEL.
  160. *
  161. */
  162. NTSTATUS HidpGetSetReport ( IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension,
  163. IN OUT PIRP Irp,
  164. IN ULONG controlCode,
  165. OUT BOOLEAN *sentIrp)
  166. {
  167. FDO_EXTENSION *fdoExt;
  168. NTSTATUS status = STATUS_SUCCESS;
  169. PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
  170. PFILE_OBJECT fileObject;
  171. PHIDCLASS_FILE_EXTENSION fileExtension;
  172. DBG_COMMON_ENTRY()
  173. ASSERT(HidDeviceExtension->isClientPdo);
  174. fdoExt = &HidDeviceExtension->pdoExt.deviceFdoExt->fdoExt;
  175. currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
  176. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  177. *sentIrp = FALSE;
  178. /*
  179. * Get the file extension.
  180. */
  181. ASSERT(currentIrpSp->FileObject);
  182. fileObject = currentIrpSp->FileObject;
  183. if(!fileObject->FsContext) {
  184. DBGWARN(("Attempted to get/set report with no file extension"))
  185. return STATUS_PRIVILEGE_NOT_HELD;
  186. }
  187. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  188. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  189. /*
  190. * Check security.
  191. */
  192. if (fileExtension->SecurityCheck){
  193. PHIDP_COLLECTION_DESC collectionDesc;
  194. /*
  195. * Get our collection description.
  196. */
  197. collectionDesc = GetCollectionDesc(fdoExt, fileExtension->CollectionNumber);
  198. if (collectionDesc){
  199. PUCHAR reportBuf;
  200. ULONG reportBufLen;
  201. BOOLEAN featureRequest = FALSE;
  202. switch (controlCode){
  203. case IOCTL_HID_GET_INPUT_REPORT:
  204. // Make sure that there is an input report on this collection.
  205. if (collectionDesc->InputLength == 0) {
  206. DBGWARN(("No input report on collection %x",
  207. fileExtension->CollectionNumber))
  208. status = STATUS_INVALID_DEVICE_REQUEST;
  209. }
  210. break;
  211. case IOCTL_HID_SET_OUTPUT_REPORT:
  212. // Make sure that there is an output report on this collection.
  213. if (collectionDesc->OutputLength == 0){
  214. DBGWARN(("No output report on collection %x",
  215. fileExtension->CollectionNumber))
  216. status = STATUS_INVALID_DEVICE_REQUEST;
  217. }
  218. break;
  219. case IOCTL_HID_GET_FEATURE:
  220. case IOCTL_HID_SET_FEATURE:
  221. featureRequest = TRUE;
  222. // Make sure that there is a feature report on this collection.
  223. if ((collectionDesc->FeatureLength == 0) &&
  224. !(fdoExt->deviceSpecificFlags & DEVICE_FLAG_ALLOW_FEATURE_ON_NON_FEATURE_COLLECTION)){
  225. DBGWARN(("No feature report on collection %x",
  226. fileExtension->CollectionNumber))
  227. status = STATUS_INVALID_DEVICE_REQUEST;
  228. }
  229. break;
  230. default:
  231. TRAP;
  232. status = STATUS_INVALID_DEVICE_REQUEST;
  233. }
  234. switch (controlCode){
  235. case IOCTL_HID_GET_INPUT_REPORT:
  236. case IOCTL_HID_GET_FEATURE:
  237. reportBufLen = currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  238. reportBuf = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
  239. break;
  240. case IOCTL_HID_SET_OUTPUT_REPORT:
  241. case IOCTL_HID_SET_FEATURE:
  242. reportBuf = Irp->AssociatedIrp.SystemBuffer;
  243. reportBufLen = currentIrpSp->Parameters.DeviceIoControl.InputBufferLength;
  244. break;
  245. default:
  246. TRAP;
  247. status = STATUS_INVALID_PARAMETER;
  248. reportBuf = NULL;
  249. reportBufLen = 0;
  250. }
  251. if (reportBuf && reportBufLen && NT_SUCCESS(status)){
  252. PHIDP_REPORT_IDS reportIdent;
  253. UCHAR reportId;
  254. /*
  255. * The client includes the report id as the first byte of the report.
  256. * We send down the report byte only if the device has multiple
  257. * report IDs (i.e. the report id is not implicit).
  258. */
  259. reportId = reportBuf[0];
  260. if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0){
  261. DBGASSERT((reportId == 0),
  262. ("Report Id should be zero, acutal id = %d", reportId),
  263. FALSE)
  264. reportBuf++;
  265. reportBufLen--;
  266. }
  267. /*
  268. * Find a matching report identifier.
  269. */
  270. reportIdent = GetReportIdentifier(fdoExt, reportId);
  271. /*
  272. * Check the buffer length against the
  273. * report length in the report identifier.
  274. */
  275. if (reportIdent){
  276. switch (controlCode){
  277. case IOCTL_HID_GET_INPUT_REPORT:
  278. /*
  279. * The buffer must be big enough for the report.
  280. */
  281. if (!reportIdent->InputLength ||
  282. reportBufLen < reportIdent->InputLength){
  283. ASSERT(!(PVOID)"report buf must be at least report size for get-report.");
  284. reportIdent = NULL;
  285. }
  286. break;
  287. case IOCTL_HID_GET_FEATURE:
  288. /*
  289. * The buffer must be big enough for the report.
  290. */
  291. if (!reportIdent->FeatureLength ||
  292. reportBufLen < reportIdent->FeatureLength){
  293. ASSERT(!(PVOID)"report buf must be at least report size for get-report.");
  294. reportIdent = NULL;
  295. }
  296. break;
  297. case IOCTL_HID_SET_OUTPUT_REPORT:
  298. /*
  299. * The buffer must be big enough for the report.
  300. * It CAN be larger, and it is up to us to use
  301. * the correct report size from the report identifier.
  302. */
  303. if (!reportIdent->OutputLength ||
  304. reportBufLen < reportIdent->OutputLength){
  305. ASSERT(!(PVOID)"report buf must be exact size for set-report.");
  306. reportIdent = NULL;
  307. } else {
  308. reportBufLen = reportIdent->OutputLength;
  309. }
  310. break;
  311. case IOCTL_HID_SET_FEATURE:
  312. if (!reportIdent->FeatureLength ||
  313. reportBufLen < reportIdent->FeatureLength){
  314. ASSERT(!(PVOID)"report buf must be exact size for set-report.");
  315. reportIdent = NULL;
  316. } else {
  317. reportBufLen = reportIdent->FeatureLength;
  318. }
  319. break;
  320. default:
  321. TRAP;
  322. }
  323. }
  324. if (reportIdent ||
  325. (featureRequest &&
  326. (fdoExt->deviceSpecificFlags &
  327. DEVICE_FLAG_ALLOW_FEATURE_ON_NON_FEATURE_COLLECTION))){
  328. PHID_XFER_PACKET reportPacket = ALLOCATEPOOL(NonPagedPool, sizeof(HID_XFER_PACKET));
  329. if (reportPacket){
  330. reportPacket->reportBuffer = reportBuf;
  331. reportPacket->reportBufferLen = reportBufLen;
  332. reportPacket->reportId = reportId;
  333. Irp->UserBuffer = reportPacket;
  334. /*
  335. * Prepare the next (lower) IRP stack location.
  336. * This will be HIDUSB's "current" stack location.
  337. */
  338. nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  339. nextIrpSp->Parameters.DeviceIoControl.IoControlCode = controlCode;
  340. /*
  341. * Note - input/output is relative to IOCTL servicer
  342. */
  343. switch (controlCode){
  344. case IOCTL_HID_GET_INPUT_REPORT:
  345. case IOCTL_HID_GET_FEATURE:
  346. nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_XFER_PACKET);
  347. break;
  348. case IOCTL_HID_SET_OUTPUT_REPORT:
  349. case IOCTL_HID_SET_FEATURE:
  350. nextIrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(HID_XFER_PACKET);
  351. break;
  352. default:
  353. TRAP;
  354. }
  355. DBG_RECORD_REPORT(reportId, controlCode, FALSE)
  356. status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
  357. if (!NT_SUCCESS(status)){
  358. DBGWARN(("HidpGetSetFeature: usb returned status %xh.", status))
  359. }
  360. DBG_RECORD_REPORT(reportId, controlCode, TRUE)
  361. ExFreePool(reportPacket);
  362. *sentIrp = FALSE; // needs to be completed again
  363. }
  364. else {
  365. ASSERT(reportPacket);
  366. status = STATUS_INSUFFICIENT_RESOURCES;
  367. }
  368. }
  369. else {
  370. DBGASSERT(reportIdent, ("Some yahoo sent invalid data in ioctl %x", controlCode), FALSE)
  371. status = STATUS_DATA_ERROR;
  372. }
  373. }
  374. else if (NT_SUCCESS(status)) {
  375. DBGASSERT(reportBuf, ("Feature buffer is invalid"), FALSE)
  376. DBGASSERT(reportBufLen, ("Feature buffer length is invalid"), FALSE)
  377. status = STATUS_INVALID_BUFFER_SIZE;
  378. }
  379. }
  380. else {
  381. ASSERT(collectionDesc);
  382. status = STATUS_DEVICE_NOT_CONNECTED;
  383. }
  384. }
  385. else {
  386. ASSERT(fileExtension->SecurityCheck);
  387. status = STATUS_PRIVILEGE_NOT_HELD;
  388. }
  389. DBGSUCCESS(status, FALSE)
  390. DBG_COMMON_EXIT()
  391. return status;
  392. }