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.

512 lines
14 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-Apr-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 | HbutInternalIoctl |
  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. HbutInternalIoctl(
  38. IN PDEVICE_OBJECT DevObj,
  39. IN PIRP Irp
  40. )
  41. {
  42. PROCNAME("HbutInternalIoctl")
  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. ASSERT(devext->dwfHBut & HBUTF_DEVICE_STARTED);
  63. switch(irpsp->Parameters.DeviceIoControl.IoControlCode)
  64. {
  65. case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
  66. status = GetDeviceDescriptor(DevObj, Irp);
  67. break;
  68. case IOCTL_HID_GET_REPORT_DESCRIPTOR:
  69. status = GetReportDescriptor(DevObj, Irp);
  70. break;
  71. case IOCTL_HID_READ_REPORT:
  72. status = ReadReport(DevObj, Irp);
  73. break;
  74. case IOCTL_HID_GET_STRING:
  75. status = GetString(DevObj, Irp);
  76. break;
  77. case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
  78. status = GetAttributes(DevObj, Irp);
  79. break;
  80. case IOCTL_HID_ACTIVATE_DEVICE:
  81. case IOCTL_HID_DEACTIVATE_DEVICE:
  82. status = STATUS_SUCCESS;
  83. break;
  84. default:
  85. WARNPRINT(("unsupported ioctl code (ioctl=%s)\n",
  86. LookupName(irpsp->Parameters.DeviceIoControl.IoControlCode,
  87. HidIoctlNames)));
  88. status = Irp->IoStatus.Status;
  89. break;
  90. }
  91. if (status != STATUS_PENDING)
  92. {
  93. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  94. Irp->IoStatus.Status = status;
  95. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  96. }
  97. else
  98. {
  99. IoMarkIrpPending(Irp);
  100. }
  101. }
  102. EXIT(1, ("=%x\n", status));
  103. return status;
  104. } //HbutInternalIoctl
  105. /*****************************************************************************
  106. *
  107. * @doc INTERNAL
  108. *
  109. * @func NTSTATUS | GetDeviceDescriptor |
  110. * Respond to HIDCLASS IOCTL_HID_GET_DEVICE_DESCRIPTOR
  111. * by returning a device descriptor.
  112. *
  113. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  114. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  115. *
  116. * @rvalue SUCCESS | returns STATUS_SUCCESS
  117. * @rvalue FAILURE | returns STATUS_BUFFER_TOO_SMALL - need more memory
  118. *
  119. *****************************************************************************/
  120. NTSTATUS INTERNAL
  121. GetDeviceDescriptor(
  122. IN PDEVICE_OBJECT DevObj,
  123. IN PIRP Irp
  124. )
  125. {
  126. PROCNAME("GetDeviceDescriptor")
  127. NTSTATUS status;
  128. PIO_STACK_LOCATION irpsp;
  129. PAGED_CODE ();
  130. irpsp = IoGetCurrentIrpStackLocation(Irp);
  131. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
  132. if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
  133. sizeof(gHidDescriptor))
  134. {
  135. ERRPRINT(("output buffer too small (bufflen=%d)\n",
  136. irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  137. status = STATUS_BUFFER_TOO_SMALL;
  138. }
  139. else
  140. {
  141. RtlCopyMemory(Irp->UserBuffer,
  142. &gHidDescriptor,
  143. sizeof(gHidDescriptor));
  144. Irp->IoStatus.Information = sizeof(gHidDescriptor);
  145. status = STATUS_SUCCESS;
  146. }
  147. EXIT(2, ("=%x\n", status));
  148. return status;
  149. } //GetDeviceDescriptor
  150. /*****************************************************************************
  151. *
  152. * @doc INTERNAL
  153. *
  154. * @func NTSTATUS | GetReportDescriptor |
  155. * Respond to HIDCLASS IOCTL_HID_GET_REPORT_DESCRIPTOR
  156. * by returning appropriate the report descriptor.
  157. *
  158. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  159. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  160. *
  161. * @rvalue SUCCESS | returns STATUS_SUCCESS
  162. * @rvalue FAILURE | returns NT status code
  163. *
  164. *****************************************************************************/
  165. NTSTATUS INTERNAL
  166. GetReportDescriptor(
  167. IN PDEVICE_OBJECT DevObj,
  168. IN PIRP Irp
  169. )
  170. {
  171. PROCNAME("GetReportDescriptor")
  172. NTSTATUS status;
  173. PIO_STACK_LOCATION irpsp;
  174. PAGED_CODE ();
  175. irpsp = IoGetCurrentIrpStackLocation(Irp);
  176. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p\n", DevObj, Irp, irpsp));
  177. if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
  178. sizeof(gReportDescriptor))
  179. {
  180. ERRPRINT(("output buffer too small (bufflen=%d)\n",
  181. irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  182. status = STATUS_BUFFER_TOO_SMALL;
  183. }
  184. else
  185. {
  186. RtlCopyMemory(Irp->UserBuffer,
  187. gReportDescriptor,
  188. sizeof(gReportDescriptor));
  189. Irp->IoStatus.Information = sizeof(gReportDescriptor);
  190. status = STATUS_SUCCESS;
  191. }
  192. EXIT(2, ("=%x\n", status));
  193. return status;
  194. } //GetReportDescriptor
  195. /*****************************************************************************
  196. *
  197. * @doc INTERNAL
  198. *
  199. * @func NTSTATUS | ReadReport |
  200. * Read input report.
  201. *
  202. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  203. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  204. *
  205. * @rvalue SUCCESS | returns STATUS_SUCCESS
  206. * @rvalue FAILURE | returns NT status code
  207. *
  208. *****************************************************************************/
  209. NTSTATUS INTERNAL
  210. ReadReport(
  211. IN PDEVICE_OBJECT DevObj,
  212. IN PIRP Irp
  213. )
  214. {
  215. PROCNAME("ReadReport")
  216. NTSTATUS status;
  217. PIO_STACK_LOCATION irpsp;
  218. PDEVICE_EXTENSION devext;
  219. irpsp = IoGetCurrentIrpStackLocation(Irp);
  220. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
  221. ASSERT(Irp->UserBuffer != NULL);
  222. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  223. if (irpsp->Parameters.DeviceIoControl.OutputBufferLength !=
  224. sizeof(OEM_INPUT_REPORT))
  225. {
  226. ERRPRINT(("invalid input report size (bufflen=%d)\n",
  227. irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  228. status = STATUS_INVALID_BUFFER_SIZE;
  229. }
  230. else if (!(devext->dwfHBut & HBUTF_DEVICE_STARTED))
  231. {
  232. ERRPRINT(("device not started yet\n"));
  233. status = STATUS_DEVICE_NOT_READY ;
  234. }
  235. else
  236. {
  237. KIRQL OldIrql;
  238. PDRIVER_CANCEL OldCancelRoutine;
  239. KeAcquireSpinLock(&devext->SpinLock, &OldIrql);
  240. OldCancelRoutine = IoSetCancelRoutine(Irp, ReadReportCanceled);
  241. ASSERT(OldCancelRoutine == NULL);
  242. if (Irp->Cancel)
  243. {
  244. //
  245. // This IRP was canceled. Do not queue it.
  246. //
  247. OldCancelRoutine = IoSetCancelRoutine(Irp, NULL);
  248. if (OldCancelRoutine != NULL)
  249. {
  250. //
  251. // Cancel routine was not called.
  252. //
  253. ASSERT(OldCancelRoutine == ReadReportCanceled);
  254. status = STATUS_CANCELLED;
  255. }
  256. else
  257. {
  258. //
  259. // Cancel routine was called and it will complete this IRP
  260. // as soon as we drop the spinlock. Return PENDING so the
  261. // caller doesn't touch this IRP.
  262. //
  263. InitializeListHead(&Irp->Tail.Overlay.ListEntry);
  264. IoMarkIrpPending(Irp);
  265. status = STATUS_PENDING;
  266. }
  267. }
  268. else
  269. {
  270. InsertTailList(&devext->PendingIrpList,
  271. &Irp->Tail.Overlay.ListEntry);
  272. IoMarkIrpPending(Irp);
  273. status = STATUS_PENDING;
  274. }
  275. KeReleaseSpinLock(&devext->SpinLock, OldIrql);
  276. }
  277. EXIT(2, ("=%x\n", status));
  278. return status;
  279. } //ReadReport
  280. /*****************************************************************************
  281. *
  282. * @doc EXTERNAL
  283. *
  284. * @func VOID | ReadReportCanceled |
  285. * ReadReport IRP has been canceled, so do the clean up.
  286. *
  287. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  288. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  289. *
  290. * @rvalue None.
  291. *
  292. *****************************************************************************/
  293. VOID EXTERNAL
  294. ReadReportCanceled(
  295. IN PDEVICE_OBJECT DevObj,
  296. IN PIRP Irp
  297. )
  298. {
  299. PROCNAME("ReadReportCanceled")
  300. PDEVICE_EXTENSION devext;
  301. KIRQL OldIrql;
  302. ENTER(2, ("(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  303. ASSERT(Irp->Cancel);
  304. ASSERT(Irp->CancelRoutine == NULL);
  305. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  306. KeAcquireSpinLock(&devext->SpinLock, &OldIrql);
  307. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  308. KeReleaseSpinLock(&devext->SpinLock, OldIrql);
  309. IoReleaseCancelSpinLock(Irp->CancelIrql);
  310. Irp->IoStatus.Status = STATUS_CANCELLED;
  311. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  312. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  313. WARNPRINT(("ReadReport IRP was canceled\n"));
  314. EXIT(2, ("!\n"));
  315. return;
  316. } //ReadReportCanceled
  317. /*****************************************************************************
  318. *
  319. * @doc INTERNAL
  320. *
  321. * @func NTSTATUS | GetString |
  322. * Respond to IOCTL_HID_GET_STRING.
  323. *
  324. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  325. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  326. *
  327. * @rvalue SUCCESS | returns STATUS_SUCCESS
  328. * @rvalue FAILURE | returns NT status code
  329. *
  330. *****************************************************************************/
  331. NTSTATUS INTERNAL
  332. GetString(
  333. PDEVICE_OBJECT DevObj,
  334. PIRP Irp
  335. )
  336. {
  337. PROCNAME("GetString")
  338. NTSTATUS status;
  339. PIO_STACK_LOCATION irpsp;
  340. PWSTR pwstrID;
  341. ULONG lenID;
  342. PAGED_CODE();
  343. irpsp = IoGetCurrentIrpStackLocation(Irp);
  344. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p,StringID=%x)\n",
  345. DevObj, Irp, irpsp,
  346. (ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer));
  347. switch ((ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer &
  348. 0xffff)
  349. {
  350. case HID_STRING_ID_IMANUFACTURER:
  351. pwstrID = gpwstrManufacturerID;
  352. break;
  353. case HID_STRING_ID_IPRODUCT:
  354. pwstrID = gpwstrProductID;
  355. break;
  356. case HID_STRING_ID_ISERIALNUMBER:
  357. pwstrID = gpwstrSerialNumber;
  358. break;
  359. default:
  360. pwstrID = NULL;
  361. break;
  362. }
  363. lenID = pwstrID? wcslen(pwstrID)*sizeof(WCHAR) + sizeof(UNICODE_NULL): 0;
  364. if (pwstrID == NULL)
  365. {
  366. ERRPRINT(("invalid string ID (ID=%x)\n",
  367. (ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer));
  368. status = STATUS_INVALID_PARAMETER;
  369. }
  370. else if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < lenID)
  371. {
  372. ERRPRINT(("output buffer too small (bufflen=%d,need=%d)\n",
  373. irpsp->Parameters.DeviceIoControl.OutputBufferLength, lenID));
  374. status = STATUS_BUFFER_TOO_SMALL;
  375. }
  376. else
  377. {
  378. RtlCopyMemory(Irp->UserBuffer, pwstrID, lenID);
  379. Irp->IoStatus.Information = lenID;
  380. status = STATUS_SUCCESS;
  381. }
  382. EXIT(2, ("=%x (string=%S)\n", status, pwstrID? pwstrID: L"Null"));
  383. return status;
  384. } //GetString
  385. /*****************************************************************************
  386. *
  387. * @doc INTERNAL
  388. *
  389. * @func NTSTATUS | GetAttributes |
  390. * Respond to IOCTL_HID_GET_ATTRIBUTES, by filling
  391. * the HID_DEVICE_ATTRIBUTES struct.
  392. *
  393. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  394. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  395. *
  396. * @rvalue SUCCESS | returns STATUS_SUCCESS
  397. * @rvalue FAILURE | returns NT status code
  398. *
  399. *****************************************************************************/
  400. NTSTATUS INTERNAL
  401. GetAttributes(
  402. PDEVICE_OBJECT DevObj,
  403. PIRP Irp
  404. )
  405. {
  406. PROCNAME("GetAttributes")
  407. NTSTATUS status;
  408. PIO_STACK_LOCATION irpsp;
  409. PAGED_CODE();
  410. irpsp = IoGetCurrentIrpStackLocation(Irp);
  411. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
  412. if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
  413. sizeof(HID_DEVICE_ATTRIBUTES))
  414. {
  415. ERRPRINT(("output buffer too small (bufflen=%d)\n",
  416. irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  417. status = STATUS_BUFFER_TOO_SMALL;
  418. }
  419. else
  420. {
  421. PDEVICE_EXTENSION devext;
  422. PHID_DEVICE_ATTRIBUTES DevAttrib;
  423. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  424. DevAttrib = (PHID_DEVICE_ATTRIBUTES)Irp->UserBuffer;
  425. DevAttrib->Size = sizeof(HID_DEVICE_ATTRIBUTES);
  426. DevAttrib->VendorID = OEM_VENDOR_ID;
  427. DevAttrib->ProductID = OEM_PRODUCT_ID;
  428. DevAttrib->VersionNumber = OEM_VERSION_NUM;
  429. Irp->IoStatus.Information = sizeof(HID_DEVICE_ATTRIBUTES);
  430. status = STATUS_SUCCESS;
  431. }
  432. EXIT(2, ("=%x\n", status));
  433. return status;
  434. } //GetAttributes