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.

522 lines
15 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract: Contains routines to support HIDCLASS internal
  6. ioctl queries for the pen tablet devices.
  7. Environment:
  8. Kernel mode
  9. Author:
  10. Michael Tsang (MikeTs) 13-Mar-2000
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, GetDeviceDescriptor)
  16. #pragma alloc_text(PAGE, GetReportDescriptor)
  17. #pragma alloc_text(PAGE, GetString)
  18. #pragma alloc_text(PAGE, GetAttributes)
  19. #endif
  20. /*****************************************************************************
  21. *
  22. * @doc EXTERNAL
  23. *
  24. * @func NTSTATUS | HpenInternalIoctl |
  25. * Process the Control IRPs sent to this device.
  26. * <nl>This function cannot be pageable because reads/writes
  27. * can be made at dispatch-level
  28. *
  29. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  30. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  31. *
  32. * @rvalue SUCCESS | returns STATUS_SUCCESS
  33. * @rvalue FAILURE | returns NT status code
  34. *
  35. *****************************************************************************/
  36. NTSTATUS EXTERNAL
  37. HpenInternalIoctl(
  38. IN PDEVICE_OBJECT DevObj,
  39. IN PIRP Irp
  40. )
  41. {
  42. PROCNAME("HpenInternalIoctl")
  43. NTSTATUS status;
  44. PIO_STACK_LOCATION irpsp;
  45. PDEVICE_EXTENSION devext;
  46. irpsp = IoGetCurrentIrpStackLocation(Irp);
  47. ENTER(1, ("(DevObj=%p,Irp=%p,IrpSp=%p,Ioctl=%s)\n",
  48. DevObj, Irp, irpsp,
  49. LookupName(irpsp->Parameters.DeviceIoControl.IoControlCode,
  50. HidIoctlNames)));
  51. Irp->IoStatus.Information = 0;
  52. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  53. status = IoAcquireRemoveLock(&devext->RemoveLock, Irp);
  54. if (!NT_SUCCESS(status))
  55. {
  56. ERRPRINT(("received PnP IRP after device was removed\n"));
  57. Irp->IoStatus.Status = status;
  58. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  59. }
  60. else
  61. {
  62. BOOLEAN fNeedCompletion = TRUE;
  63. ASSERT(devext->dwfHPen & HPENF_DEVICE_STARTED);
  64. switch(irpsp->Parameters.DeviceIoControl.IoControlCode)
  65. {
  66. case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
  67. status = GetDeviceDescriptor(DevObj, Irp);
  68. break;
  69. case IOCTL_HID_GET_REPORT_DESCRIPTOR:
  70. status = GetReportDescriptor(DevObj, Irp);
  71. break;
  72. case IOCTL_HID_READ_REPORT:
  73. status = ReadReport(DevObj, Irp);
  74. fNeedCompletion = FALSE;
  75. break;
  76. case IOCTL_HID_GET_FEATURE:
  77. status = OemGetFeatures(DevObj, Irp);
  78. break;
  79. case IOCTL_HID_SET_FEATURE:
  80. status = OemSetFeatures(DevObj, Irp);
  81. break;
  82. case IOCTL_HID_GET_STRING:
  83. status = GetString(DevObj, Irp);
  84. break;
  85. case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
  86. status = GetAttributes(DevObj, Irp);
  87. break;
  88. case IOCTL_HID_ACTIVATE_DEVICE:
  89. case IOCTL_HID_DEACTIVATE_DEVICE:
  90. status = STATUS_SUCCESS;
  91. break;
  92. default:
  93. WARNPRINT(("unsupported ioctl code (ioctl=%s)\n",
  94. LookupName(irpsp->Parameters.DeviceIoControl.IoControlCode,
  95. HidIoctlNames)));
  96. status = Irp->IoStatus.Status;
  97. break;
  98. }
  99. if (status != STATUS_PENDING)
  100. {
  101. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  102. if (fNeedCompletion)
  103. {
  104. Irp->IoStatus.Status = status;
  105. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  106. }
  107. }
  108. else
  109. {
  110. IoMarkIrpPending(Irp);
  111. }
  112. }
  113. EXIT(1, ("=%x\n", status));
  114. return status;
  115. } //HpenInternalIoctl
  116. /*****************************************************************************
  117. *
  118. * @doc INTERNAL
  119. *
  120. * @func NTSTATUS | GetDeviceDescriptor |
  121. * Respond to HIDCLASS IOCTL_HID_GET_DEVICE_DESCRIPTOR
  122. * by returning a device descriptor.
  123. *
  124. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  125. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  126. *
  127. * @rvalue SUCCESS | returns STATUS_SUCCESS
  128. * @rvalue FAILURE | returns STATUS_BUFFER_TOO_SMALL - need more memory
  129. *
  130. *****************************************************************************/
  131. NTSTATUS INTERNAL
  132. GetDeviceDescriptor(
  133. IN PDEVICE_OBJECT DevObj,
  134. IN PIRP Irp
  135. )
  136. {
  137. PROCNAME("GetDeviceDescriptor")
  138. NTSTATUS status;
  139. PIO_STACK_LOCATION irpsp;
  140. PAGED_CODE ();
  141. irpsp = IoGetCurrentIrpStackLocation(Irp);
  142. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
  143. if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
  144. sizeof(gHidDescriptor))
  145. {
  146. ERRPRINT(("output buffer too small (bufflen=%d)\n",
  147. irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  148. status = STATUS_BUFFER_TOO_SMALL;
  149. }
  150. else
  151. {
  152. RtlCopyMemory(Irp->UserBuffer,
  153. &gHidDescriptor,
  154. sizeof(gHidDescriptor));
  155. Irp->IoStatus.Information = sizeof(gHidDescriptor);
  156. status = STATUS_SUCCESS;
  157. }
  158. EXIT(2, ("=%x\n", status));
  159. return status;
  160. } //GetDeviceDescriptor
  161. /*****************************************************************************
  162. *
  163. * @doc INTERNAL
  164. *
  165. * @func NTSTATUS | GetReportDescriptor |
  166. * Respond to HIDCLASS IOCTL_HID_GET_REPORT_DESCRIPTOR
  167. * by returning appropriate the report descriptor.
  168. *
  169. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  170. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  171. *
  172. * @rvalue SUCCESS | returns STATUS_SUCCESS
  173. * @rvalue FAILURE | returns NT status code
  174. *
  175. *****************************************************************************/
  176. NTSTATUS INTERNAL
  177. GetReportDescriptor(
  178. IN PDEVICE_OBJECT DevObj,
  179. IN PIRP Irp
  180. )
  181. {
  182. PROCNAME("GetReportDescriptor")
  183. NTSTATUS status;
  184. PIO_STACK_LOCATION irpsp;
  185. PAGED_CODE ();
  186. irpsp = IoGetCurrentIrpStackLocation(Irp);
  187. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p\n", DevObj, Irp, irpsp));
  188. if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
  189. sizeof(gReportDescriptor))
  190. {
  191. ERRPRINT(("output buffer too small (bufflen=%d)\n",
  192. irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  193. status = STATUS_BUFFER_TOO_SMALL;
  194. }
  195. else
  196. {
  197. RtlCopyMemory(Irp->UserBuffer,
  198. gReportDescriptor,
  199. sizeof(gReportDescriptor));
  200. Irp->IoStatus.Information = sizeof(gReportDescriptor);
  201. status = STATUS_SUCCESS;
  202. }
  203. EXIT(2, ("=%x\n", status));
  204. return status;
  205. } //GetReportDescriptor
  206. /*****************************************************************************
  207. *
  208. * @doc INTERNAL
  209. *
  210. * @func NTSTATUS | ReadReport |
  211. * Read input report.
  212. *
  213. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  214. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  215. *
  216. * @rvalue SUCCESS | returns STATUS_SUCCESS
  217. * @rvalue FAILURE | returns NT status code
  218. *
  219. *****************************************************************************/
  220. NTSTATUS INTERNAL
  221. ReadReport(
  222. IN PDEVICE_OBJECT DevObj,
  223. IN PIRP Irp
  224. )
  225. {
  226. PROCNAME("ReadReport")
  227. NTSTATUS status;
  228. PIO_STACK_LOCATION irpsp;
  229. PDEVICE_EXTENSION devext;
  230. ULONG DataLen;
  231. irpsp = IoGetCurrentIrpStackLocation(Irp);
  232. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
  233. ASSERT(Irp->UserBuffer != NULL);
  234. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  235. DataLen = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
  236. if (DataLen != sizeof(HID_INPUT_REPORT))
  237. {
  238. ERRPRINT(("invalid input report size (bufflen=%d)\n", DataLen));
  239. status = STATUS_INVALID_BUFFER_SIZE;
  240. }
  241. else if (!(devext->dwfHPen & HPENF_DEVICE_STARTED))
  242. {
  243. ERRPRINT(("device not started yet\n"));
  244. status = STATUS_DEVICE_NOT_READY ;
  245. }
  246. else
  247. {
  248. PHID_INPUT_REPORT HidReport = (PHID_INPUT_REPORT)Irp->UserBuffer;
  249. KIRQL OldIrql;
  250. KeAcquireSpinLock(&devext->SpinLock, &OldIrql);
  251. status = OemProcessResyncBuffer(devext, Irp);
  252. KeReleaseSpinLock(&devext->SpinLock, OldIrql);
  253. if (!NT_SUCCESS(status))
  254. {
  255. //
  256. // If we don't have enough bytes in the resync buffer or the packet
  257. // in the resync buffer is invalid, send an IRP down to read some
  258. // more.
  259. //
  260. status = SerialAsyncReadWritePort(TRUE,
  261. devext,
  262. Irp,
  263. HidReport->Report.RawInput,
  264. sizeof(OEM_INPUT_REPORT),
  265. ReadReportCompletion,
  266. HidReport);
  267. }
  268. }
  269. EXIT(2, ("=%x\n", status));
  270. return status;
  271. } //ReadReport
  272. /*****************************************************************************
  273. *
  274. * @doc INTERNAL
  275. *
  276. * @func NTSTATUS | GetString |
  277. * Respond to IOCTL_HID_GET_STRING.
  278. *
  279. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  280. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  281. *
  282. * @rvalue SUCCESS | returns STATUS_SUCCESS
  283. * @rvalue FAILURE | returns NT status code
  284. *
  285. *****************************************************************************/
  286. NTSTATUS INTERNAL
  287. GetString(
  288. PDEVICE_OBJECT DevObj,
  289. PIRP Irp
  290. )
  291. {
  292. PROCNAME("GetString")
  293. NTSTATUS status;
  294. PIO_STACK_LOCATION irpsp;
  295. PWSTR pwstrID;
  296. ULONG lenID;
  297. PAGED_CODE();
  298. irpsp = IoGetCurrentIrpStackLocation(Irp);
  299. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p,StringID=%x)\n",
  300. DevObj, Irp, irpsp,
  301. (ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer));
  302. switch ((ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer &
  303. 0xffff)
  304. {
  305. case HID_STRING_ID_IMANUFACTURER:
  306. pwstrID = gpwstrManufacturerID;
  307. break;
  308. case HID_STRING_ID_IPRODUCT:
  309. pwstrID = gpwstrProductID;
  310. break;
  311. case HID_STRING_ID_ISERIALNUMBER:
  312. pwstrID = gpwstrSerialNumber;
  313. break;
  314. default:
  315. pwstrID = NULL;
  316. break;
  317. }
  318. lenID = pwstrID? wcslen(pwstrID)*sizeof(WCHAR) + sizeof(UNICODE_NULL): 0;
  319. if (pwstrID == NULL)
  320. {
  321. ERRPRINT(("invalid string ID (ID=%x)\n",
  322. (ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer));
  323. status = STATUS_INVALID_PARAMETER;
  324. }
  325. else if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < lenID)
  326. {
  327. ERRPRINT(("output buffer too small (bufflen=%d,need=%d)\n",
  328. irpsp->Parameters.DeviceIoControl.OutputBufferLength, lenID));
  329. status = STATUS_BUFFER_TOO_SMALL;
  330. }
  331. else
  332. {
  333. RtlCopyMemory(Irp->UserBuffer, pwstrID, lenID);
  334. Irp->IoStatus.Information = lenID;
  335. status = STATUS_SUCCESS;
  336. }
  337. EXIT(2, ("=%x (string=%S)\n", status, pwstrID? pwstrID: L"Null"));
  338. return status;
  339. } //GetString
  340. /*****************************************************************************
  341. *
  342. * @doc INTERNAL
  343. *
  344. * @func NTSTATUS | GetAttributes |
  345. * Respond to IOCTL_HID_GET_ATTRIBUTES, by filling
  346. * the HID_DEVICE_ATTRIBUTES struct.
  347. *
  348. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  349. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  350. *
  351. * @rvalue SUCCESS | returns STATUS_SUCCESS
  352. * @rvalue FAILURE | returns NT status code
  353. *
  354. *****************************************************************************/
  355. NTSTATUS INTERNAL
  356. GetAttributes(
  357. PDEVICE_OBJECT DevObj,
  358. PIRP Irp
  359. )
  360. {
  361. PROCNAME("GetAttributes")
  362. NTSTATUS status;
  363. PIO_STACK_LOCATION irpsp;
  364. PAGED_CODE();
  365. irpsp = IoGetCurrentIrpStackLocation(Irp);
  366. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
  367. if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
  368. sizeof(HID_DEVICE_ATTRIBUTES))
  369. {
  370. ERRPRINT(("output buffer too small (bufflen=%d)\n",
  371. irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  372. status = STATUS_BUFFER_TOO_SMALL;
  373. }
  374. else
  375. {
  376. PDEVICE_EXTENSION devext;
  377. PHID_DEVICE_ATTRIBUTES DevAttrib;
  378. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  379. DevAttrib = (PHID_DEVICE_ATTRIBUTES)Irp->UserBuffer;
  380. DevAttrib->Size = sizeof(HID_DEVICE_ATTRIBUTES);
  381. DevAttrib->VendorID = OEM_VENDOR_ID;
  382. DevAttrib->ProductID = devext->OemData.wProductID;
  383. DevAttrib->VersionNumber = devext->OemData.wFirmwareRev;
  384. Irp->IoStatus.Information = sizeof(HID_DEVICE_ATTRIBUTES);
  385. status = STATUS_SUCCESS;
  386. }
  387. EXIT(2, ("=%x\n", status));
  388. return status;
  389. } //GetAttributes
  390. /*****************************************************************************
  391. *
  392. * @doc INTERNAL
  393. *
  394. * @func NTSTATUS | ReadReportCompletion | Completion routine for ReadReport.
  395. *
  396. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  397. * @parm IN PIRP | Irp | Points to an I/O request packet.
  398. * @parm IN PHID_INPUT_REPORT | HidReport | Points to input data packet.
  399. *
  400. * @rvalue SUCCESS | Returns STATUS_SUCCESS
  401. * @rvalue FAILURE | Returns STATUS_MORE_PROCESSING_REQUIRED
  402. *
  403. *****************************************************************************/
  404. NTSTATUS INTERNAL
  405. ReadReportCompletion(
  406. IN PDEVICE_OBJECT DevObj,
  407. IN PIRP Irp,
  408. IN PHID_INPUT_REPORT HidReport
  409. )
  410. {
  411. PROCNAME("ReadReportCompletion")
  412. NTSTATUS status = Irp->IoStatus.Status;
  413. PDEVICE_EXTENSION devext;
  414. ENTER(2, ("(DevObj=%p,Irp=%p,HidReport=%p,Status=%x)\n",
  415. DevObj, Irp, HidReport, status));
  416. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  417. if (status == STATUS_CANCELLED)
  418. {
  419. WARNPRINT(("ReadReport IRP was cancelled\n"));
  420. status = STATUS_SUCCESS;
  421. }
  422. else if (!NT_SUCCESS(status))
  423. {
  424. ERRPRINT(("failed to read input data packet (status=%x)\n", status));
  425. status = STATUS_SUCCESS;
  426. }
  427. else
  428. {
  429. status = OemProcessInputData(devext, Irp, HidReport);
  430. }
  431. if (Irp->PendingReturned)
  432. {
  433. IoMarkIrpPending(Irp);
  434. }
  435. if (status != STATUS_MORE_PROCESSING_REQUIRED)
  436. {
  437. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  438. }
  439. EXIT(2, ("=%x\n", status));
  440. return status;
  441. } //ReadReportCompletion