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.

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