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.

1511 lines
50 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. oempen.c
  5. Abstract: Contains OEM specific functions.
  6. Environment:
  7. Kernel mode
  8. Author:
  9. Michael Tsang (MikeTs) 13-Mar-2000
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, OemAddDevice)
  15. #pragma alloc_text(PAGE, OemInitSerialPort)
  16. #pragma alloc_text(PAGE, OemInitDevice)
  17. #pragma alloc_text(PAGE, OemQueryDeviceInfo)
  18. #pragma alloc_text(PAGE, OemRemoveDevice)
  19. #pragma alloc_text(PAGE, OemWakeupDevice)
  20. #pragma alloc_text(PAGE, OemStandbyDevice)
  21. #pragma alloc_text(PAGE, OemReadMoreBytes)
  22. #pragma alloc_text(PAGE, OemGetFeatures)
  23. #pragma alloc_text(PAGE, OemSetFeatures)
  24. #pragma alloc_text(PAGE, OemSetTabletFeatures)
  25. #pragma alloc_text(PAGE, RegQueryDeviceParam)
  26. #pragma alloc_text(PAGE, RegSetDeviceParam)
  27. #endif //ifdef ALLOC_PRAGMA
  28. UCHAR gReportDescriptor[130] = {
  29. 0x05, 0x0d, // USAGE_PAGE (Digitizers)
  30. 0x09, 0x02, // USAGE (Pen)
  31. 0xa1, 0x01, // COLLECTION (Application)
  32. 0x85, 0x01, // REPORT_ID (1)
  33. 0x09, 0x20, // USAGE (Stylus)
  34. 0xa1, 0x00, // COLLECTION (Physical)
  35. 0x09, 0x42, // USAGE (Tip Switch)
  36. 0x09, 0x44, // USAGE (Barrel Switch)
  37. 0x15, 0x00, // LOGICAL_MINIMUM (0)
  38. 0x25, 0x01, // LOGICAL_MAXIMUM (1)
  39. 0x75, 0x01, // REPORT_SIZE (1)
  40. 0x95, 0x02, // REPORT_COUNT (2)
  41. 0x81, 0x02, // INPUT (Data,Var,Abs)
  42. 0x95, 0x03, // REPORT_COUNT (3)
  43. 0x81, 0x03, // INPUT (Cnst,Var,Abs)
  44. 0x09, 0x32, // USAGE (In Range)
  45. 0x95, 0x01, // REPORT_COUNT (1)
  46. 0x81, 0x02, // INPUT (Data,Var,Abs)
  47. 0x95, 0x02, // REPORT_COUNT (2)
  48. 0x81, 0x03, // INPUT (Cnst,Var,Abs)
  49. 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
  50. 0x09, 0x30, // USAGE (X)
  51. 0x26, 0x98, 0x21, // LOGICAL_MAXIMUM (8600)
  52. 0x75, 0x10, // REPORT_SIZE (16)
  53. 0x95, 0x01, // REPORT_COUNT (1)
  54. 0x81, 0x02, // INPUT (Data,Var,Abs)
  55. 0x09, 0x31, // USAGE (Y)
  56. 0x26, 0x50, 0x19, // LOGICAL_MAXIMUM (6480)
  57. 0x81, 0x02, // INPUT (Data,Var,Abs)
  58. 0xc0, // END_COLLECTION
  59. //
  60. // Feature report
  61. //
  62. 0x85, 0x02, // REPORT_ID (2)
  63. 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined)
  64. 0x09, 0x01, // USAGE (Vendor Usage 1)
  65. 0x27, 0xff, 0xff, 0xff, 0xff, // LOGICAL_MAXIMUM (0xffffffff)
  66. 0x75, 0x20, // REPORT_SIZE (32)
  67. 0x95, 0x01, // REPORT_COUNT (1)
  68. 0xb1, 0x02, // FEATURE (Data,Var,Abs)
  69. 0xc0, // END_COLLECTION
  70. //
  71. // Dummy mouse collection starts here
  72. //
  73. 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
  74. 0x09, 0x02, // USAGE (Mouse)
  75. 0xa1, 0x01, // COLLECTION (Application)
  76. 0x85, 0x03, // REPORT_ID (3)
  77. 0x09, 0x01, // USAGE (Pointer)
  78. 0xa1, 0x00, // COLLECTION (Physical)
  79. 0x05, 0x09, // USAGE_PAGE (Button)
  80. 0x19, 0x01, // USAGE_MINIMUM (Button 1)
  81. 0x29, 0x02, // USAGE_MAXIMUM (Button 2)
  82. 0x15, 0x00, // LOGICAL_MINIMUM (0)
  83. 0x25, 0x01, // LOGICAL_MAXIMUM (1)
  84. 0x75, 0x01, // REPORT_SIZE (1)
  85. 0x95, 0x02, // REPORT_COUNT (2)
  86. 0x81, 0x02, // INPUT (Data,Var,Abs)
  87. 0x95, 0x06, // REPORT_COUNT (6)
  88. 0x81, 0x03, // INPUT (Cnst,Var,Abs)
  89. 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
  90. 0x09, 0x30, // USAGE (X)
  91. 0x09, 0x31, // USAGE (Y)
  92. 0x15, 0x81, // LOGICAL_MINIMUM (-127)
  93. 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
  94. 0x75, 0x08, // REPORT_SIZE (8)
  95. 0x95, 0x02, // REPORT_COUNT (2)
  96. 0x81, 0x06, // INPUT (Data,Var,Rel)
  97. 0xc0, // END_COLLECTION
  98. 0xc0 // END_COLLECTION
  99. };
  100. HID_DESCRIPTOR gHidDescriptor =
  101. {
  102. sizeof(HID_DESCRIPTOR), //bLength
  103. HID_HID_DESCRIPTOR_TYPE, //bDescriptorType
  104. HID_REVISION, //bcdHID
  105. 0, //bCountry - not localized
  106. 1, //bNumDescriptors
  107. { //DescriptorList[0]
  108. HID_REPORT_DESCRIPTOR_TYPE, //bReportType
  109. sizeof(gReportDescriptor) //wReportLength
  110. }
  111. };
  112. PWSTR gpwstrManufacturerID = L"Mutoh";
  113. PWSTR gpwstrProductID = L"Serial Pen Tablet (3310)";
  114. PWSTR gpwstrSerialNumber = L"0";
  115. OEM_INPUT_REPORT gLastReport = {0};
  116. LARGE_INTEGER gLastReportTime = {0};
  117. USHORT gwDXThreshold = OEM_THRESHOLD_DX;
  118. USHORT gwDYThreshold = OEM_THRESHOLD_DY;
  119. /*****************************************************************************
  120. *
  121. * @doc INTERNAL
  122. *
  123. * @func NTSTATUS | OemAddDevice |
  124. * OEM specific AddDevice code.
  125. *
  126. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  127. *
  128. * @rvalue STATUS_SUCCESS | success
  129. *
  130. *****************************************************************************/
  131. NTSTATUS INTERNAL
  132. OemAddDevice(
  133. IN PDEVICE_EXTENSION DevExt
  134. )
  135. {
  136. PROCNAME("OemAddDevice")
  137. NTSTATUS status;
  138. UCHAR bConversionRate;
  139. PAGED_CODE ();
  140. ENTER(2, ("(DevExt=%p)\n", DevExt));
  141. status = RegQueryDeviceParam(DevExt->pdo,
  142. STR_TABLET_FEATURES,
  143. &DevExt->OemData.dwTabletFeatures,
  144. sizeof(DevExt->OemData.dwTabletFeatures));
  145. if (!NT_SUCCESS(status))
  146. {
  147. //
  148. // Registry doesn't have this parameter, default to maximum conversion
  149. // rate, digital filter on.
  150. //
  151. DevExt->OemData.dwTabletFeatures = 1 |
  152. OEM_FEATURE_DIGITAL_FILTER_ON;
  153. status = STATUS_SUCCESS;
  154. }
  155. bConversionRate = (UCHAR)(DevExt->OemData.dwTabletFeatures &
  156. OEM_FEATURE_RATE_MASK);
  157. if (bConversionRate != 0)
  158. {
  159. //
  160. // At sampling rate of 133.3, the sampling period is 7.5msec.
  161. // We set the threshold period 10 times of the sampling period.
  162. // ThresholdPeriod = 75000*10*ConversionRate (in units of 100nsec)
  163. //
  164. DevExt->OemData.dwThresholdPeriod = 75000*10*bConversionRate;
  165. }
  166. else
  167. {
  168. //
  169. // Conversion rate of 0 means 100 samples per second which
  170. // means sampling interval is 10msec.
  171. // ThresholdPeriod = 100000*10 (in units of 100nsec)
  172. //
  173. DevExt->OemData.dwThresholdPeriod = 1000000;
  174. }
  175. EXIT(2, ("=%x\n", status));
  176. return status;
  177. } //OemAddDevice
  178. /*****************************************************************************
  179. *
  180. * @doc INTERNAL
  181. *
  182. * @func NTSTATUS | OemInitSerialPort |
  183. * Initialize com port for communication.
  184. *
  185. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  186. *
  187. * @rvalue SUCCESS | returns STATUS_SUCCESS
  188. * @rvalue FAILURE | returns NT status code
  189. *
  190. *****************************************************************************/
  191. NTSTATUS INTERNAL
  192. OemInitSerialPort(
  193. IN PDEVICE_EXTENSION DevExt
  194. )
  195. {
  196. PROCNAME("OemInitSerialPort")
  197. NTSTATUS status;
  198. IO_STATUS_BLOCK iosb;
  199. PAGED_CODE();
  200. ENTER(2, ("(DevExt=%p)\n", DevExt));
  201. //
  202. // Set the com port to basic operating mode: reads/writes one byte at
  203. // time, no handshake flow control or timeouts.
  204. //
  205. status = SerialSyncSendIoctl(IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS,
  206. DevExt->SerialDevObj,
  207. NULL,
  208. 0,
  209. &DevExt->PrevSerialSettings,
  210. sizeof(DevExt->PrevSerialSettings),
  211. TRUE,
  212. &iosb);
  213. if (!NT_SUCCESS(status))
  214. {
  215. ERRPRINT(("failed to set com to basic settings (status=%x)\n", status));
  216. }
  217. else
  218. {
  219. SERIAL_BAUD_RATE sbr;
  220. sbr.BaudRate = OEM_SERIAL_BAUDRATE;
  221. status = SerialSyncSendIoctl(IOCTL_SERIAL_SET_BAUD_RATE,
  222. DevExt->SerialDevObj,
  223. &sbr,
  224. sizeof(sbr),
  225. NULL,
  226. 0,
  227. FALSE,
  228. &iosb);
  229. if (!NT_SUCCESS(status))
  230. {
  231. ERRPRINT(("failed to set com port to 19200 baud (status=%x)\n",
  232. status));
  233. }
  234. else
  235. {
  236. SERIAL_LINE_CONTROL slc;
  237. slc.WordLength = OEM_SERIAL_WORDLEN;
  238. slc.Parity = OEM_SERIAL_PARITY;
  239. slc.StopBits = OEM_SERIAL_STOPBITS;
  240. status = SerialSyncSendIoctl(IOCTL_SERIAL_SET_LINE_CONTROL,
  241. DevExt->SerialDevObj,
  242. &slc,
  243. sizeof(slc),
  244. NULL,
  245. 0,
  246. FALSE,
  247. &iosb);
  248. if (!NT_SUCCESS(status))
  249. {
  250. ERRPRINT(("failed to set com line control (status=%x)\n",
  251. status));
  252. }
  253. else
  254. {
  255. //
  256. // Enable FIFO receive trigger at 4 bytes
  257. //
  258. ULONG Data = SERIAL_IOC_FCR_FIFO_ENABLE |
  259. SERIAL_IOC_FCR_RCVR_RESET |
  260. SERIAL_IOC_FCR_XMIT_RESET |
  261. SERIAL_IOC_FCR_RCVR_TRIGGER_04_BYTES;
  262. status = SerialSyncSendIoctl(IOCTL_SERIAL_SET_FIFO_CONTROL,
  263. DevExt->SerialDevObj,
  264. &Data,
  265. sizeof(Data),
  266. NULL,
  267. 0,
  268. FALSE,
  269. &iosb);
  270. if (!NT_SUCCESS(status))
  271. {
  272. ERRPRINT(("failed to set FIFO control (status=%x)\n",
  273. status));
  274. }
  275. else
  276. {
  277. Data = SERIAL_PURGE_RXCLEAR;
  278. status = SerialSyncSendIoctl(IOCTL_SERIAL_PURGE,
  279. DevExt->SerialDevObj,
  280. &Data,
  281. sizeof(Data),
  282. NULL,
  283. 0,
  284. FALSE,
  285. &iosb);
  286. if (!NT_SUCCESS(status))
  287. {
  288. ERRPRINT(("failed to flush receive buffer (status=%x)\n",
  289. status));
  290. }
  291. }
  292. }
  293. }
  294. }
  295. EXIT(2, ("=%x\n", status));
  296. return status;
  297. } //OemInitSerialPort
  298. /*****************************************************************************
  299. *
  300. * @doc INTERNAL
  301. *
  302. * @func NTSTATUS | OemInitDevice |
  303. * Initialize pen tablet device.
  304. *
  305. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  306. *
  307. * @rvalue SUCCESS | returns STATUS_SUCCESS
  308. * @rvalue FAILURE | returns NT status code
  309. *
  310. *****************************************************************************/
  311. NTSTATUS INTERNAL
  312. OemInitDevice(
  313. IN PDEVICE_EXTENSION DevExt
  314. )
  315. {
  316. PROCNAME("OemInitDevice")
  317. NTSTATUS status;
  318. PAGED_CODE();
  319. ENTER(2, ("(DevExt=%p)\n", DevExt));
  320. status = SerialSyncReadWritePort(FALSE, DevExt, "@", 1, NULL, NULL);
  321. if (!NT_SUCCESS(status))
  322. {
  323. ERRPRINT(("failed to send reset command to tablet (status=%x)\n",
  324. status));
  325. }
  326. else
  327. {
  328. LONGLONG WaitTime = Int32x32To64(100, -10000);
  329. //
  330. // We need to delay 20msec after a software reset is sent.
  331. //
  332. KeDelayExecutionThread(KernelMode,
  333. FALSE,
  334. (LARGE_INTEGER *)&WaitTime);
  335. status = OemSetTabletFeatures(DevExt, DevExt->OemData.dwTabletFeatures);
  336. if (!NT_SUCCESS(status))
  337. {
  338. ERRPRINT(("failed to set default tablet features (status=%x,features=%x)\n",
  339. status, DevExt->OemData.dwTabletFeatures));
  340. }
  341. else if (!NT_SUCCESS(status = SerialSyncReadWritePort(
  342. FALSE, DevExt, "LO", 2, NULL, NULL)))
  343. {
  344. ERRPRINT(("failed to set default tablet configuration (status=%x)\n",
  345. status));
  346. }
  347. else
  348. {
  349. status = OemQueryDeviceInfo(DevExt);
  350. if (!NT_SUCCESS(status))
  351. {
  352. //
  353. // It's not a big deal if we don't get the device info.
  354. // It's more important to keep the driver running.
  355. //
  356. status = STATUS_SUCCESS;
  357. }
  358. }
  359. }
  360. EXIT(2, ("=%x\n", status));
  361. return status;
  362. } //OemInitDevice
  363. /*****************************************************************************
  364. *
  365. * @doc INTERNAL
  366. *
  367. * @func NTSTATUS | OemQueryDeviceInfo |
  368. * Query pen tablet device information.
  369. *
  370. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  371. *
  372. * @rvalue SUCCESS | returns STATUS_SUCCESS
  373. * @rvalue FAILURE | returns NT status code
  374. *
  375. *****************************************************************************/
  376. NTSTATUS INTERNAL
  377. OemQueryDeviceInfo(
  378. IN PDEVICE_EXTENSION DevExt
  379. )
  380. {
  381. PROCNAME("OemQueryDeviceInfo")
  382. NTSTATUS status, status2;
  383. PAGED_CODE();
  384. ENTER(2, ("(DevExt=%p)\n", DevExt));
  385. status = SerialSyncReadWritePort(FALSE, DevExt, "K", 1, NULL, NULL);
  386. if (NT_SUCCESS(status))
  387. {
  388. LARGE_INTEGER Timeout;
  389. OEM_INPUT_REPORT InData[3];
  390. ULONG BytesRead;
  391. // Set timeout to 100 msec.
  392. Timeout.QuadPart = Int32x32To64(100, -10000);
  393. while ((status = SerialSyncReadWritePort(TRUE,
  394. DevExt,
  395. (PUCHAR)InData,
  396. 1,
  397. &Timeout,
  398. &BytesRead)) ==
  399. STATUS_SUCCESS)
  400. {
  401. if (InData[0].InputReport.bStatus == 0x88)
  402. {
  403. break;
  404. }
  405. }
  406. if (NT_SUCCESS(status))
  407. {
  408. status = SerialSyncReadWritePort(TRUE,
  409. DevExt,
  410. ((PUCHAR)InData) + 1,
  411. sizeof(InData) - 1,
  412. &Timeout,
  413. &BytesRead);
  414. if (NT_SUCCESS(status))
  415. {
  416. if ((BytesRead == sizeof(InData) - 1) &&
  417. (InData[0].InputReport.bStatus == 0x88) &&
  418. (InData[1].InputReport.bStatus == 0x88) &&
  419. (InData[2].InputReport.bStatus == 0x8f))
  420. {
  421. DevExt->OemData.wFirmwareDate =
  422. NORMALIZE_DATA(InData[0].InputReport.wXData);
  423. DevExt->OemData.wFirmwareYear =
  424. NORMALIZE_DATA(InData[0].InputReport.wYData);
  425. DevExt->OemData.wProductID =
  426. NORMALIZE_DATA(InData[1].InputReport.wXData);
  427. DevExt->OemData.wFirmwareRev =
  428. NORMALIZE_DATA(InData[1].InputReport.wYData);
  429. DevExt->OemData.wCorrectionRev =
  430. NORMALIZE_DATA(InData[2].InputReport.wXData);
  431. DBGPRINT(1, ("FirmwareDate=%d,FirmwareYear=%d,ProductID=%d,FirmwareRev=%d,CorrectionRev=%d\n",
  432. DevExt->OemData.wFirmwareDate,
  433. DevExt->OemData.wFirmwareYear,
  434. DevExt->OemData.wProductID,
  435. DevExt->OemData.wFirmwareRev,
  436. DevExt->OemData.wCorrectionRev));
  437. }
  438. else
  439. {
  440. ERRPRINT(("invalid response of status command (size=%d,InData=%p)\n",
  441. BytesRead, InData));
  442. status = STATUS_DEVICE_DATA_ERROR;
  443. }
  444. }
  445. else
  446. {
  447. ERRPRINT(("failed to read response packet (status=%x)\n",
  448. status));
  449. }
  450. }
  451. else
  452. {
  453. ERRPRINT(("failed to read first byte of the response (status=%x)\n",
  454. status));
  455. }
  456. }
  457. else
  458. {
  459. ERRPRINT(("failed to send status command (status=%x)\n", status));
  460. }
  461. status2 = SerialSyncReadWritePort(FALSE,
  462. DevExt,
  463. "A",
  464. 1,
  465. NULL,
  466. NULL);
  467. if (!NT_SUCCESS(status2))
  468. {
  469. ERRPRINT(("failed to send acknowledge command to tablet (status=%x)\n",
  470. status2));
  471. }
  472. EXIT(2, ("=%x\n", status));
  473. return status;
  474. } //OemQueryDeviceInfo
  475. /*****************************************************************************
  476. *
  477. * @doc INTERNAL
  478. *
  479. * @func NTSTATUS | OemRemoveDevice |
  480. * OEM specific cleanups.
  481. *
  482. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  483. *
  484. * @rvalue SUCCESS | returns STATUS_SUCCESS
  485. * @rvalue FAILURE | returns NT status code
  486. *
  487. *****************************************************************************/
  488. NTSTATUS INTERNAL
  489. OemRemoveDevice(
  490. IN PDEVICE_EXTENSION DevExt
  491. )
  492. {
  493. PROCNAME("OemRemoveDevice")
  494. NTSTATUS status;
  495. IO_STATUS_BLOCK iosb;
  496. PAGED_CODE();
  497. ENTER(2, ("(DevExt=%p)\n", DevExt));
  498. status = SerialSyncSendIoctl(IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS,
  499. DevExt->SerialDevObj,
  500. &DevExt->PrevSerialSettings,
  501. sizeof(DevExt->PrevSerialSettings),
  502. NULL,
  503. 0,
  504. TRUE,
  505. &iosb);
  506. if (!NT_SUCCESS(status))
  507. {
  508. ERRPRINT(("failed to restore serial port settings (status=%x)\n",
  509. status));
  510. }
  511. EXIT(2, ("=%x\n", status));
  512. return status;
  513. } //OemRemoveDevice
  514. /*****************************************************************************
  515. *
  516. * @doc INTERNAL
  517. *
  518. * @func NTSTATUS | OemWakeupDevice |
  519. * OEM specific wake up code.
  520. *
  521. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  522. *
  523. * @rvalue SUCCESS | returns STATUS_SUCCESS
  524. * @rvalue FAILURE | returns NT status code
  525. *
  526. *****************************************************************************/
  527. NTSTATUS INTERNAL
  528. OemWakeupDevice(
  529. IN PDEVICE_EXTENSION DevExt
  530. )
  531. {
  532. PROCNAME("OemWakeupDevice")
  533. NTSTATUS status = STATUS_SUCCESS;
  534. PAGED_CODE();
  535. ENTER(2, ("(DevExt=%p)\n", DevExt));
  536. if (DevExt->dwfHPen & HPENF_DEVICE_STARTED)
  537. {
  538. status = SerialSyncReadWritePort(FALSE, DevExt, "A", 1, NULL, NULL);
  539. if (!NT_SUCCESS(status))
  540. {
  541. ERRPRINT(("failed to send acknowledge command to the tablet (status=%x)\n",
  542. status));
  543. }
  544. }
  545. EXIT(2, ("=%x\n", status));
  546. return status;
  547. } //OemWakeupDevice
  548. /*****************************************************************************
  549. *
  550. * @doc INTERNAL
  551. *
  552. * @func NTSTATUS | OemStandbyDevice |
  553. * OEM specific wake up code.
  554. *
  555. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  556. *
  557. * @rvalue SUCCESS | returns STATUS_SUCCESS
  558. * @rvalue FAILURE | returns NT status code
  559. *
  560. *****************************************************************************/
  561. NTSTATUS INTERNAL
  562. OemStandbyDevice(
  563. IN PDEVICE_EXTENSION DevExt
  564. )
  565. {
  566. PROCNAME("OemStandbyDevice")
  567. NTSTATUS status = STATUS_SUCCESS;
  568. PAGED_CODE();
  569. ENTER(2, ("(DevExt=%p)\n", DevExt));
  570. if (DevExt->dwfHPen & HPENF_DEVICE_STARTED)
  571. {
  572. status = SerialSyncReadWritePort(FALSE, DevExt, "W", 1, NULL, NULL);
  573. if (!NT_SUCCESS(status))
  574. {
  575. ERRPRINT(("failed to send standby command to the tablet (status=%x)\n",
  576. status));
  577. }
  578. }
  579. EXIT(2, ("=%x\n", status));
  580. return status;
  581. } //OemStandbyDevice
  582. /*****************************************************************************
  583. *
  584. * @doc INTERNAL
  585. *
  586. * @func NTSTATUS | OemProcessResyncBuffer |
  587. * Process input data from the resync buffer.
  588. * Note that this function must be called at IRQL==DISPATCH_LEVEL
  589. *
  590. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  591. * @parm IN PIRP | Irp | Points to an I/O request packet.
  592. *
  593. * @rvalue SUCCESS | Returns STATUS_SUCCESS.
  594. * @rvalue FAILURE | Returns STATUS_MORE_PROCESSING_REQUIRED
  595. * (We want the IRP back).
  596. *
  597. *****************************************************************************/
  598. NTSTATUS INTERNAL
  599. OemProcessResyncBuffer(
  600. IN PDEVICE_EXTENSION DevExt,
  601. IN PIRP Irp
  602. )
  603. {
  604. PROCNAME("OemProcessResyncBuffer")
  605. NTSTATUS status = STATUS_DATA_ERROR;
  606. PHID_INPUT_REPORT HidReport = (PHID_INPUT_REPORT)Irp->UserBuffer;
  607. ENTER(2, ("(DevExt=%p,Irp=%p,Len=%d,status=%x,xData=%x,yData=%x)\n",
  608. DevExt, Irp, DevExt->BytesInBuff,
  609. DevExt->ResyncData[0].InputReport.bStatus,
  610. DevExt->ResyncData[0].InputReport.wXData,
  611. DevExt->ResyncData[0].InputReport.wYData));
  612. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  613. while (DevExt->BytesInBuff >= sizeof(OEM_INPUT_REPORT))
  614. {
  615. if (OemIsResyncDataValid(DevExt))
  616. {
  617. status = OemNormalizeInputData(DevExt, &DevExt->ResyncData[0]);
  618. if (NT_SUCCESS(status))
  619. {
  620. HidReport->ReportID = OEM_PEN_REPORT_ID;
  621. RtlCopyMemory(HidReport->Report.RawInput,
  622. &DevExt->ResyncData[0],
  623. sizeof(OEM_INPUT_REPORT));
  624. Irp->IoStatus.Information = sizeof(HID_INPUT_REPORT);
  625. }
  626. DevExt->BytesInBuff -= sizeof(OEM_INPUT_REPORT);
  627. if (DevExt->BytesInBuff > 0)
  628. {
  629. RtlMoveMemory(&DevExt->ResyncData[0],
  630. &DevExt->ResyncData[1],
  631. DevExt->BytesInBuff);
  632. }
  633. if (NT_SUCCESS(status))
  634. {
  635. break;
  636. }
  637. }
  638. }
  639. EXIT(2, ("=%x (status=%x,xData=%x,yData=%x)\n",
  640. status,
  641. HidReport->Report.InputReport.bStatus,
  642. HidReport->Report.InputReport.wXData,
  643. HidReport->Report.InputReport.wYData));
  644. return status;
  645. } //OemProcessResyncBuffer
  646. /*****************************************************************************
  647. *
  648. * @doc INTERNAL
  649. *
  650. * @func NTSTATUS | OemProcessInputData |
  651. * OEM specific code to process input data.
  652. *
  653. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  654. * @parm IN PIRP | Irp | Points to an I/O request packet.
  655. * @parm IN PHID_INPUT_REPORT | HidReport | Points to hid report packet.
  656. *
  657. * @rvalue SUCCESS | Returns STATUS_SUCCESS.
  658. * @rvalue FAILURE | Returns STATUS_MORE_PROCESSING_REQUIRED
  659. * (We want the IRP back).
  660. *
  661. *****************************************************************************/
  662. NTSTATUS INTERNAL
  663. OemProcessInputData(
  664. IN PDEVICE_EXTENSION DevExt,
  665. IN PIRP Irp,
  666. IN PHID_INPUT_REPORT HidReport
  667. )
  668. {
  669. PROCNAME("OemProcessInputData")
  670. NTSTATUS status;
  671. KIRQL OldIrql;
  672. ENTER(2, ("(DevExt=%p,Irp=%p,HidReport=%p,Len=%d,status=%x,xData=%x,yData=%x)\n",
  673. DevExt, Irp, HidReport, Irp->IoStatus.Information,
  674. HidReport->Report.InputReport.bStatus,
  675. HidReport->Report.InputReport.wXData,
  676. HidReport->Report.InputReport.wYData));
  677. KeAcquireSpinLock(&DevExt->SpinLock, &OldIrql);
  678. if ((DevExt->BytesInBuff == 0) &&
  679. (Irp->IoStatus.Information == sizeof(OEM_INPUT_REPORT)) &&
  680. OemIsValidPacket(&HidReport->Report))
  681. {
  682. status = OemNormalizeInputData(DevExt, &HidReport->Report);
  683. if (NT_SUCCESS(status))
  684. {
  685. HidReport->ReportID = OEM_PEN_REPORT_ID;
  686. Irp->IoStatus.Information = sizeof(HID_INPUT_REPORT);
  687. }
  688. }
  689. else
  690. {
  691. //
  692. // Either resync buffer already has something in it or packet is
  693. // partial or invalid, so append data to resync buffer and process
  694. // it again.
  695. //
  696. RtlMoveMemory((PUCHAR)&DevExt->ResyncData[0] + DevExt->BytesInBuff,
  697. &HidReport->Report,
  698. Irp->IoStatus.Information);
  699. DevExt->BytesInBuff += (ULONG)Irp->IoStatus.Information;
  700. ASSERT(DevExt->BytesInBuff <= sizeof(DevExt->ResyncData));
  701. status = OemProcessResyncBuffer(DevExt, Irp);
  702. }
  703. if (!NT_SUCCESS(status))
  704. {
  705. PREAD_WORKITEM ReadWorkItem;
  706. //
  707. // No valid data packet, send another IRP down to read more.
  708. //
  709. if (!(DevExt->QueuedWorkItems & QUEUED_WORKITEM_0))
  710. {
  711. ReadWorkItem = &DevExt->ReadWorkItem[0];
  712. ReadWorkItem->WorkItemBit = QUEUED_WORKITEM_0;
  713. }
  714. else
  715. {
  716. ASSERT(!(DevExt->QueuedWorkItems & QUEUED_WORKITEM_1));
  717. DBGPRINT(3, ("Queue second work item!\n"));
  718. ReadWorkItem = &DevExt->ReadWorkItem[1];
  719. ReadWorkItem->WorkItemBit = QUEUED_WORKITEM_1;
  720. }
  721. status = IoAcquireRemoveLock(&DevExt->RemoveLock, Irp);
  722. if (!NT_SUCCESS(status))
  723. {
  724. ERRPRINT(("trying to queue a work item after device was removed\n"));
  725. }
  726. else
  727. {
  728. DevExt->QueuedWorkItems |= ReadWorkItem->WorkItemBit;
  729. ReadWorkItem->Irp = Irp;
  730. ReadWorkItem->HidReport = HidReport;
  731. IoQueueWorkItem(ReadWorkItem->WorkItem,
  732. OemReadMoreBytes,
  733. DelayedWorkQueue,
  734. ReadWorkItem);
  735. status = STATUS_MORE_PROCESSING_REQUIRED;
  736. }
  737. }
  738. KeReleaseSpinLock(&DevExt->SpinLock, OldIrql);
  739. EXIT(2, ("=%x (status=%x,xData=%x,yData=%x)\n",
  740. status,
  741. HidReport->Report.InputReport.bStatus,
  742. HidReport->Report.InputReport.wXData,
  743. HidReport->Report.InputReport.wYData));
  744. return status;
  745. } //OemProcessInputData
  746. /*****************************************************************************
  747. *
  748. * @doc INTERNAL
  749. *
  750. * @func NTSTATUS | OemReadMoreBytes |
  751. * Read more bytes to resync packet.
  752. *
  753. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  754. * @parm IN PREAD_WORKITEM | ReadWorkItem | Points to the read work item.
  755. * @parm IN PIRP | Irp | Points to an I/O request packet.
  756. *
  757. * @rvalue None.
  758. *
  759. *****************************************************************************/
  760. VOID INTERNAL
  761. OemReadMoreBytes(
  762. IN PDEVICE_OBJECT DevObj,
  763. IN PREAD_WORKITEM ReadWorkItem
  764. )
  765. {
  766. PROCNAME("OemReadMoreBytes")
  767. PDEVICE_EXTENSION devext;
  768. ULONG BytesToRead;
  769. KIRQL OldIrql;
  770. PAGED_CODE();
  771. ENTER(2, ("(DevObj=%p,ReadWorkItem=%p)\n", DevObj, ReadWorkItem));
  772. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  773. KeAcquireSpinLock(&devext->SpinLock, &OldIrql);
  774. ASSERT(devext->QueuedWorkItems & ReadWorkItem->WorkItemBit);
  775. devext->QueuedWorkItems &= ~ReadWorkItem->WorkItemBit;
  776. IoReleaseRemoveLock(&devext->RemoveLock, ReadWorkItem->Irp);
  777. BytesToRead = sizeof(OEM_INPUT_REPORT) -
  778. devext->BytesInBuff%sizeof(OEM_INPUT_REPORT);
  779. KeReleaseSpinLock(&devext->SpinLock, OldIrql);
  780. DBGPRINT(3, ("Read %d more bytes (WorkItemBit=%x)\n",
  781. BytesToRead, ReadWorkItem->WorkItemBit));
  782. SerialAsyncReadWritePort(TRUE,
  783. devext,
  784. ReadWorkItem->Irp,
  785. ReadWorkItem->HidReport->Report.RawInput,
  786. BytesToRead,
  787. ReadReportCompletion,
  788. ReadWorkItem->HidReport);
  789. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  790. EXIT(2, ("!\n"));
  791. return;
  792. } //OemReadMoreBytes
  793. /*****************************************************************************
  794. *
  795. * @doc INTERNAL
  796. *
  797. * @func BOOLEAN | OemIsResyncDataValid |
  798. * Check if the data in the resync buffer is valid.
  799. *
  800. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  801. *
  802. * @rvalue SUCCESS | Returns TRUE.
  803. * @rvalue FAILURE | Returns FALSE.
  804. *
  805. *****************************************************************************/
  806. BOOLEAN INTERNAL
  807. OemIsResyncDataValid(
  808. IN PDEVICE_EXTENSION DevExt
  809. )
  810. {
  811. PROCNAME("OemIsResyncDataValid")
  812. BOOLEAN rc;
  813. ENTER(2, ("(DevExt=%p)\n", DevExt));
  814. rc = OemIsValidPacket(&DevExt->ResyncData[0]);
  815. if ((rc == FALSE) || (DevExt->BytesInBuff > sizeof(OEM_INPUT_REPORT)))
  816. {
  817. PUCHAR pb = (PUCHAR)&DevExt->ResyncData[0] + DevExt->BytesInBuff - 1;
  818. PUCHAR pbEnd = rc? (PUCHAR)&DevExt->ResyncData[1]:
  819. (PUCHAR)&DevExt->ResyncData[0];
  820. //
  821. // Even if we seem to have a valid packet in the resync buffer, we
  822. // still need to scan the next packet if any. If the next packet
  823. // has a sync bit out of place, the first packet could still be
  824. // invalid and we better throw it away.
  825. //
  826. while (pb > pbEnd)
  827. {
  828. if (*pb & INSTATUS_SYNC)
  829. {
  830. DBGPRINT(3,
  831. ("invalid buffer (len=%d,status0=%x,xData0=%x,yData0=%x,status1=%x,xData1=%x,yData1=%x)\n",
  832. DevExt->BytesInBuff,
  833. DevExt->ResyncData[0].InputReport.bStatus,
  834. DevExt->ResyncData[0].InputReport.wXData,
  835. DevExt->ResyncData[0].InputReport.wYData,
  836. DevExt->ResyncData[1].InputReport.bStatus,
  837. DevExt->ResyncData[1].InputReport.wXData,
  838. DevExt->ResyncData[1].InputReport.wYData));
  839. DevExt->BytesInBuff = (ULONG)((PUCHAR)&DevExt->ResyncData[0] +
  840. DevExt->BytesInBuff - pb);
  841. RtlMoveMemory(&DevExt->ResyncData[0], pb, DevExt->BytesInBuff);
  842. DBGPRINT(3,
  843. ("Resync'd buffer (len=%d,status=%x,xData=%x,yData=%x)\n",
  844. DevExt->BytesInBuff,
  845. DevExt->ResyncData[0].InputReport.bStatus,
  846. DevExt->ResyncData[0].InputReport.wXData,
  847. DevExt->ResyncData[0].InputReport.wYData));
  848. #ifdef DEBUG
  849. {
  850. ULONG dwcDeletedBytes = (ULONG)(pb -
  851. (PUCHAR)&DevExt->ResyncData[0]);
  852. gdwcLostBytes +=
  853. (dwcDeletedBytes > sizeof(OEM_INPUT_REPORT))?
  854. sizeof(OEM_INPUT_REPORT)*2 - dwcDeletedBytes:
  855. sizeof(OEM_INPUT_REPORT) - dwcDeletedBytes;
  856. }
  857. #endif
  858. rc = FALSE;
  859. break;
  860. }
  861. --pb;
  862. }
  863. if ((rc == FALSE) && (pb <= pbEnd))
  864. {
  865. //
  866. // We didn't have a valid packet and we couldn't find the sync
  867. // bit of the next packet, so the whole resync buffer is invalid.
  868. //
  869. DevExt->BytesInBuff = 0;
  870. }
  871. }
  872. EXIT(2, ("=%x\n", rc));
  873. return rc;
  874. } //OemIsResyncDataValid
  875. /*****************************************************************************
  876. *
  877. * @doc INTERNAL
  878. *
  879. * @func NTSTATUS | OemNormalizeInputData |
  880. * Normalize the input data.
  881. *
  882. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  883. * @parm IN OUT POEM_INPUT_REPORT | InData | Points to the input data packet.
  884. *
  885. * @rvalue SUCCESS | Returns STATUS_SUCCESS.
  886. * @rvalue FAILURE | Returns STATUS_DATA_ERROR.
  887. *
  888. *****************************************************************************/
  889. NTSTATUS INTERNAL
  890. OemNormalizeInputData(
  891. IN PDEVICE_EXTENSION DevExt,
  892. IN OUT POEM_INPUT_REPORT InData
  893. )
  894. {
  895. PROCNAME("OemNormalizeInputData")
  896. NTSTATUS status = STATUS_SUCCESS;
  897. LARGE_INTEGER CurrentTime;
  898. ENTER(2, ("(DevExt=%p,InData=%p,Status=%x,XData=%x,YData=%x)\n",
  899. DevExt, InData, InData->InputReport.bStatus,
  900. InData->InputReport.wXData, InData->InputReport.wYData));
  901. InData->InputReport.wXData = NORMALIZE_DATA(InData->InputReport.wXData);
  902. InData->InputReport.wYData = NORMALIZE_DATA(InData->InputReport.wYData);
  903. if (InData->InputReport.wXData >= OEM_PEN_MAX_X)
  904. {
  905. #ifdef DEBUG
  906. if (InData->InputReport.wXData > gwMaxX)
  907. {
  908. gwMaxX = InData->InputReport.wXData;
  909. }
  910. #endif
  911. InData->InputReport.wXData = OEM_PEN_MAX_X - 1;
  912. }
  913. if (InData->InputReport.wYData >= OEM_PEN_MAX_Y)
  914. {
  915. #ifdef DEBUG
  916. if (InData->InputReport.wYData > gwMaxY)
  917. {
  918. gwMaxY = InData->InputReport.wYData;
  919. }
  920. #endif
  921. InData->InputReport.wYData = 0;
  922. }
  923. else
  924. {
  925. InData->InputReport.wYData = OEM_PEN_MAX_Y - 1 -
  926. InData->InputReport.wYData;
  927. }
  928. KeQuerySystemTime(&CurrentTime);
  929. #ifdef DEBUG
  930. if ((gLastReport.InputReport.bStatus ^ InData->InputReport.bStatus) &
  931. INSTATUS_PEN_TIP_DOWN)
  932. {
  933. //
  934. // The tip switch changes state
  935. //
  936. if (InData->InputReport.bStatus & INSTATUS_PEN_TIP_DOWN)
  937. {
  938. gdwcSamples = 0;
  939. gdwcLostBytes = 0;
  940. gStartTime = CurrentTime;
  941. }
  942. else
  943. {
  944. CurrentTime.QuadPart -= gStartTime.QuadPart;
  945. CurrentTime.QuadPart /= (LONGLONG)10000;
  946. DBGPRINT(1, ("Samples=%d,Elapsed=%d,Rate=%d,BytesLost=%d\n",
  947. gdwcSamples,
  948. CurrentTime.LowPart,
  949. CurrentTime.LowPart?
  950. gdwcSamples*1000/CurrentTime.LowPart: 0,
  951. gdwcLostBytes));
  952. }
  953. }
  954. gdwcSamples++;
  955. #endif
  956. if (DevExt->OemData.dwTabletFeatures & OEM_FEATURE_GLITCH_FILTER_ON)
  957. {
  958. LARGE_INTEGER ElapsedTime;
  959. ElapsedTime.QuadPart = CurrentTime.QuadPart - gLastReportTime.QuadPart;
  960. if (ElapsedTime.QuadPart < (LONGLONG)DevExt->OemData.dwThresholdPeriod)
  961. {
  962. USHORT wDX, wDY;
  963. wDX = (USHORT)(abs(InData->InputReport.wXData -
  964. gLastReport.InputReport.wXData));
  965. wDY = (USHORT)(abs(InData->InputReport.wYData -
  966. gLastReport.InputReport.wYData));
  967. if ((wDX > gwDXThreshold) || (wDY > gwDYThreshold))
  968. {
  969. //
  970. // Spike detected, drop this packet.
  971. //
  972. WARNPRINT(("dX or dY exceeding threshold (dX=%d,dY=%d)\n",
  973. wDX, wDY));
  974. status = STATUS_DATA_ERROR;
  975. }
  976. #ifdef DEBUG
  977. else
  978. {
  979. if (wDX > gwMaxDX)
  980. {
  981. gwMaxDX = wDX;
  982. }
  983. if (wDY > gwMaxDY)
  984. {
  985. gwMaxDY = wDY;
  986. }
  987. }
  988. #endif
  989. }
  990. }
  991. gLastReportTime = CurrentTime;
  992. RtlCopyMemory(&gLastReport, InData, sizeof(gLastReport));
  993. if (NT_SUCCESS(status))
  994. {
  995. //
  996. // We have a valid report, tell the system that we are not idling.
  997. //
  998. PoSetSystemState(ES_USER_PRESENT);
  999. }
  1000. DBGPRINT(3, ("status=%x,xData=%x(%d),yData=%x(%d)\n",
  1001. InData->InputReport.bStatus,
  1002. InData->InputReport.wXData,
  1003. InData->InputReport.wXData,
  1004. InData->InputReport.wYData,
  1005. InData->InputReport.wYData));
  1006. EXIT(2, ("=%x (Status=%x,XData=%x(%d),YData=%x(%d)\n",
  1007. status,
  1008. InData->InputReport.bStatus,
  1009. InData->InputReport.wXData,
  1010. InData->InputReport.wXData,
  1011. InData->InputReport.wYData,
  1012. InData->InputReport.wYData));
  1013. return status;
  1014. } //OemNormalizeInputData
  1015. /*****************************************************************************
  1016. *
  1017. * @doc INTERNAL
  1018. *
  1019. * @func NTSTATUS | OemGetFeatures |
  1020. * Get feature report.
  1021. *
  1022. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  1023. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  1024. *
  1025. * @rvalue SUCCESS | returns STATUS_SUCCESS
  1026. * @rvalue FAILURE | returns NT status code
  1027. *
  1028. *****************************************************************************/
  1029. NTSTATUS INTERNAL
  1030. OemGetFeatures(
  1031. IN PDEVICE_OBJECT DevObj,
  1032. IN PIRP Irp
  1033. )
  1034. {
  1035. PROCNAME("OemGetFeatures")
  1036. NTSTATUS status;
  1037. PIO_STACK_LOCATION irpsp;
  1038. PDEVICE_EXTENSION devext;
  1039. PHID_XFER_PACKET FeaturePacket = (PHID_XFER_PACKET)Irp->UserBuffer;
  1040. PAGED_CODE();
  1041. irpsp = IoGetCurrentIrpStackLocation(Irp);
  1042. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
  1043. ASSERT(FeaturePacket != NULL);
  1044. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  1045. if (irpsp->Parameters.DeviceIoControl.OutputBufferLength !=
  1046. sizeof(HID_XFER_PACKET))
  1047. {
  1048. ERRPRINT(("invalid xfer packet size (bufflen=%d)\n",
  1049. irpsp->Parameters.DeviceIoControl.OutputBufferLength));
  1050. status = STATUS_INVALID_BUFFER_SIZE;
  1051. }
  1052. else if (FeaturePacket->reportBufferLen != sizeof(HID_FEATURE_REPORT))
  1053. {
  1054. ERRPRINT(("invalid feature report size (bufflen=%d)\n",
  1055. FeaturePacket->reportBufferLen));
  1056. status = STATUS_INVALID_BUFFER_SIZE;
  1057. }
  1058. else if (!(devext->dwfHPen & HPENF_DEVICE_STARTED))
  1059. {
  1060. ERRPRINT(("device not started yet\n"));
  1061. status = STATUS_DEVICE_NOT_READY ;
  1062. }
  1063. else
  1064. {
  1065. PHID_FEATURE_REPORT Feature =
  1066. (PHID_FEATURE_REPORT)FeaturePacket->reportBuffer;
  1067. ASSERT(FeaturePacket->reportId == OEM_FEATURE_REPORT_ID);
  1068. Feature->ReportID = OEM_FEATURE_REPORT_ID;
  1069. Feature->Report.dwTabletFeatures = devext->OemData.dwTabletFeatures;
  1070. Irp->IoStatus.Information = sizeof(HID_FEATURE_REPORT);
  1071. status = STATUS_SUCCESS;
  1072. }
  1073. EXIT(2, ("=%x\n", status));
  1074. return status;
  1075. } //OemGetFeatures
  1076. /*****************************************************************************
  1077. *
  1078. * @doc INTERNAL
  1079. *
  1080. * @func NTSTATUS | OemSetFeatures |
  1081. * Set feature report.
  1082. *
  1083. * @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
  1084. * @parm IN PIRP | Irp | Points to an I/O Request Packet.
  1085. *
  1086. * @rvalue SUCCESS | returns STATUS_SUCCESS
  1087. * @rvalue FAILURE | returns NT status code
  1088. *
  1089. *****************************************************************************/
  1090. NTSTATUS INTERNAL
  1091. OemSetFeatures(
  1092. IN PDEVICE_OBJECT DevObj,
  1093. IN PIRP Irp
  1094. )
  1095. {
  1096. PROCNAME("OemSetFeatures")
  1097. NTSTATUS status;
  1098. PIO_STACK_LOCATION irpsp;
  1099. PDEVICE_EXTENSION devext;
  1100. PHID_XFER_PACKET FeaturePacket = (PHID_XFER_PACKET)Irp->UserBuffer;
  1101. PHID_FEATURE_REPORT Feature;
  1102. PAGED_CODE();
  1103. irpsp = IoGetCurrentIrpStackLocation(Irp);
  1104. ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
  1105. ASSERT(FeaturePacket != NULL);
  1106. Feature = (PHID_FEATURE_REPORT)FeaturePacket->reportBuffer;
  1107. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  1108. if (irpsp->Parameters.DeviceIoControl.InputBufferLength !=
  1109. sizeof(HID_XFER_PACKET))
  1110. {
  1111. ERRPRINT(("invalid xfer packet size (bufflen=%d)\n",
  1112. irpsp->Parameters.DeviceIoControl.InputBufferLength));
  1113. status = STATUS_INVALID_BUFFER_SIZE;
  1114. }
  1115. else if (FeaturePacket->reportBufferLen != sizeof(HID_FEATURE_REPORT))
  1116. {
  1117. ERRPRINT(("invalid feature report size (bufflen=%d)\n",
  1118. FeaturePacket->reportBufferLen));
  1119. status = STATUS_INVALID_BUFFER_SIZE;
  1120. }
  1121. else if (!(devext->dwfHPen & HPENF_DEVICE_STARTED))
  1122. {
  1123. ERRPRINT(("device not started yet\n"));
  1124. status = STATUS_DEVICE_NOT_READY ;
  1125. }
  1126. else if ((Feature->Report.dwTabletFeatures & OEM_FEATURE_UNUSED_BITS) ||
  1127. ((Feature->Report.dwTabletFeatures & OEM_FEATURE_RATE_MASK) >
  1128. OEM_MAX_RATE_DIVISOR))
  1129. {
  1130. ERRPRINT(("invalid tablet features (features=%x)\n",
  1131. Feature->Report.dwTabletFeatures));
  1132. status = STATUS_INVALID_DEVICE_REQUEST;
  1133. }
  1134. else
  1135. {
  1136. ASSERT(FeaturePacket->reportId == OEM_FEATURE_REPORT_ID);
  1137. devext->OemData.dwTabletFeatures = Feature->Report.dwTabletFeatures;
  1138. status = OemSetTabletFeatures(devext, Feature->Report.dwTabletFeatures);
  1139. }
  1140. EXIT(2, ("=%x\n", status));
  1141. return status;
  1142. } //OemSetFeatures
  1143. /*****************************************************************************
  1144. *
  1145. * @doc INTERNAL
  1146. *
  1147. * @func NTSTATUS | OemSetTabletFeatures |
  1148. * Set tablet feature.
  1149. *
  1150. * @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
  1151. * @parm IN ULONG | dwTabletFeatures | Specifies the tablet features.
  1152. *
  1153. * @rvalue SUCCESS | returns STATUS_SUCCESS
  1154. * @rvalue FAILURE | returns NT status code
  1155. *
  1156. *****************************************************************************/
  1157. NTSTATUS INTERNAL
  1158. OemSetTabletFeatures(
  1159. IN PDEVICE_EXTENSION DevExt,
  1160. IN ULONG dwTabletFeatures
  1161. )
  1162. {
  1163. PROCNAME("OemSetTabletFeatures")
  1164. NTSTATUS status;
  1165. char szTabletCmd[3] = "??";
  1166. UCHAR bConversionRate = (UCHAR)(dwTabletFeatures & OEM_FEATURE_RATE_MASK);
  1167. PAGED_CODE();
  1168. ENTER(2, ("(DevExt=%p,Features=%x)\n", DevExt, dwTabletFeatures));
  1169. status = RegSetDeviceParam(DevExt->pdo,
  1170. STR_TABLET_FEATURES,
  1171. REG_DWORD,
  1172. &dwTabletFeatures,
  1173. sizeof(dwTabletFeatures));
  1174. if (NT_SUCCESS(status))
  1175. {
  1176. szTabletCmd[0] = (dwTabletFeatures & OEM_FEATURE_DIGITAL_FILTER_ON)?
  1177. 'V': 'N';
  1178. szTabletCmd[1] = (char)('0' + bConversionRate);
  1179. if (bConversionRate != 0)
  1180. {
  1181. //
  1182. // At sampling rate of 133.3, the sampling period is 7.5msec.
  1183. // We set the threshold period 10 times of the sampling period.
  1184. // ThresholdPeriod = 75000*ConversionRate*10 (in units of 100nsec)
  1185. //
  1186. DevExt->OemData.dwThresholdPeriod = bConversionRate*750000;
  1187. }
  1188. else
  1189. {
  1190. //
  1191. // Conversion rate of 0 means 100 samples per second which
  1192. // means sampling interval is 10msec.
  1193. // ThresholdPeriod = 100000*10 (in units of 100nsec)
  1194. //
  1195. DevExt->OemData.dwThresholdPeriod = 1000000;
  1196. }
  1197. status = SerialSyncReadWritePort(FALSE,
  1198. DevExt,
  1199. szTabletCmd,
  1200. sizeof(szTabletCmd) - 1,
  1201. NULL,
  1202. NULL);
  1203. }
  1204. else
  1205. {
  1206. ERRPRINT(("failed to set tablet features in the registry (status=%x)\n",
  1207. status));
  1208. }
  1209. EXIT(2, ("=%x\n", status));
  1210. return status;
  1211. } //OemSetTabletFeatures
  1212. /*****************************************************************************
  1213. *
  1214. * @doc INTERNAL
  1215. *
  1216. * @func NTSTATUS | RegQueryDeviceParam | Query the registry for a device
  1217. * parameter.
  1218. *
  1219. * @parm IN PDEVICE_OBJECT | pdo | Points to the pdo of the device.
  1220. * @parm IN PWSTR | pwstrParamName | Points to the param name string.
  1221. * @parm OUT PVOID | pbBuff | Points to the buffer to hold the result.
  1222. * @parm IN ULONG | dwcbLen | Specifies the length of the buffer.
  1223. *
  1224. * @rvalue SUCCESS | returns STATUS_SUCCESS
  1225. * @rvalue FAILURE | returns NT status code
  1226. *
  1227. *****************************************************************************/
  1228. NTSTATUS INTERNAL
  1229. RegQueryDeviceParam(
  1230. IN PDEVICE_OBJECT pdo,
  1231. IN PWSTR pwstrParamName,
  1232. OUT PVOID pbBuff,
  1233. IN ULONG dwcbLen
  1234. )
  1235. {
  1236. PROCNAME("RegQueryDeviceParam")
  1237. NTSTATUS status;
  1238. ULONG dwSize;
  1239. PKEY_VALUE_PARTIAL_INFORMATION pValueInfo;
  1240. PAGED_CODE();
  1241. ENTER(2, ("(pdo=%p,ParamName=%S,pbBuff=%p,Len=%d)\n",
  1242. pdo, pwstrParamName, pbBuff, dwcbLen));
  1243. dwSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + dwcbLen;
  1244. pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool,
  1245. dwSize);
  1246. if (pValueInfo != NULL)
  1247. {
  1248. HANDLE hkey;
  1249. status = IoOpenDeviceRegistryKey(pdo,
  1250. PLUGPLAY_REGKEY_DEVICE,
  1251. STANDARD_RIGHTS_READ,
  1252. &hkey);
  1253. if (NT_SUCCESS(status))
  1254. {
  1255. UNICODE_STRING ucKeyName;
  1256. RtlInitUnicodeString(&ucKeyName, pwstrParamName);
  1257. status = ZwQueryValueKey(hkey,
  1258. &ucKeyName,
  1259. KeyValuePartialInformation,
  1260. pValueInfo,
  1261. dwSize,
  1262. &dwSize);
  1263. if (NT_SUCCESS(status))
  1264. {
  1265. ASSERT(pValueInfo->DataLength == dwcbLen);
  1266. RtlCopyMemory(pbBuff, pValueInfo->Data, dwcbLen);
  1267. }
  1268. else
  1269. {
  1270. WARNPRINT(("failed to read parameter %S (status=%x)\n",
  1271. pwstrParamName, status));
  1272. }
  1273. ZwClose(hkey);
  1274. }
  1275. else
  1276. {
  1277. ERRPRINT(("failed to open device registry key (status=%x)\n",
  1278. status));
  1279. }
  1280. ExFreePool(pValueInfo);
  1281. }
  1282. else
  1283. {
  1284. status = STATUS_INSUFFICIENT_RESOURCES;
  1285. ERRPRINT(("failed to allocate registry value buffer (size=%d)\n",
  1286. dwSize));
  1287. }
  1288. EXIT(2, ("=%x\n", status));
  1289. return status;
  1290. } //RegQueryDeviceParam
  1291. /*****************************************************************************
  1292. *
  1293. * @doc INTERNAL
  1294. *
  1295. * @func NTSTATUS | RegSetDeviceParam | Set the device parameter in the
  1296. * registry.
  1297. *
  1298. * @parm IN PDEVICE_OBJECT | pdo | Points to the pdo of the device.
  1299. * @parm IN PWSTR | pwstrParamName | Points to the param name string.
  1300. * @parm IN ULONG | dwType | Value type.
  1301. * @parm IN PVOID | pbBuff | Points to the buffer to hold the result.
  1302. * @parm IN ULONG | dwcbLen | Specifies the length of the buffer.
  1303. *
  1304. * @rvalue SUCCESS | returns STATUS_SUCCESS
  1305. * @rvalue FAILURE | returns NT status code
  1306. *
  1307. *****************************************************************************/
  1308. NTSTATUS INTERNAL
  1309. RegSetDeviceParam(
  1310. IN PDEVICE_OBJECT pdo,
  1311. IN PWSTR pwstrParamName,
  1312. IN ULONG dwType,
  1313. IN PVOID pbBuff,
  1314. IN ULONG dwcbLen
  1315. )
  1316. {
  1317. PROCNAME("RegSetDeviceParam")
  1318. NTSTATUS status;
  1319. HANDLE hkey;
  1320. PAGED_CODE();
  1321. ENTER(2, ("(pdo=%p,ParamName=%S,Type=%x,pbBuff=%p,Len=%d)\n",
  1322. pdo, pwstrParamName, dwType, pbBuff, dwcbLen));
  1323. status = IoOpenDeviceRegistryKey(pdo,
  1324. PLUGPLAY_REGKEY_DEVICE,
  1325. STANDARD_RIGHTS_ALL,
  1326. &hkey);
  1327. if (NT_SUCCESS(status))
  1328. {
  1329. UNICODE_STRING ucKeyName;
  1330. RtlInitUnicodeString(&ucKeyName, pwstrParamName);
  1331. status = ZwSetValueKey(hkey,
  1332. &ucKeyName,
  1333. 0,
  1334. dwType,
  1335. pbBuff,
  1336. dwcbLen);
  1337. if (!NT_SUCCESS(status))
  1338. {
  1339. ERRPRINT(("failed to set parameter %S (status=%x)\n",
  1340. pwstrParamName, status));
  1341. }
  1342. ZwClose(hkey);
  1343. }
  1344. else
  1345. {
  1346. ERRPRINT(("failed to open device registry key (status=%x)\n",
  1347. status));
  1348. }
  1349. EXIT(2, ("=%x\n", status));
  1350. return status;
  1351. } //RegSetDeviceParam