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.

233 lines
7.5 KiB

  1. /*
  2. ********************************************************************************
  3. *
  4. * READ.C
  5. *
  6. *
  7. * VXDCLNT - Sample Ring-0 HID device mapper for Memphis
  8. *
  9. * Copyright 1997 Microsoft Corp.
  10. *
  11. * (ep)
  12. *
  13. ********************************************************************************
  14. */
  15. #include "vxdclnt.h"
  16. /*
  17. * WorkItemCallback_Read
  18. *
  19. */
  20. VOID WorkItemCallback_Read(PVOID context)
  21. {
  22. deviceContext *device = (deviceContext *)context;
  23. NTSTATUS Status;
  24. DBGOUT(("==> WorkItemCallback_Read()"));
  25. device->dataLength.LowPart = device->dataLength.HighPart = 0;
  26. device->readPending = TRUE;
  27. /*
  28. * Do an asynchronous read on the device device.
  29. * When the device has a delta value to report, we will be called back
  30. * via ReadCompletion().
  31. */
  32. Status = _NtKernReadFile(
  33. device->devHandle,
  34. NULL,
  35. ReadCompletion,
  36. (PVOID)device, // context for callback
  37. (PIO_STATUS_BLOCK)&device->ioStatusBlock,
  38. (PVOID)device->report,
  39. device->hidCapabilities.InputReportByteLength,
  40. &device->dataLength,
  41. NULL
  42. );
  43. if (!NT_SUCCESS(Status) && (Status != STATUS_PENDING)) {
  44. /*
  45. * Read failed. Since device is no longer usable, shut it down.
  46. */
  47. DBGERR(("_NtKernReadFile error (Status=%xh) - SHUTTING DOWN THIS DEVICE", (UINT)Status));
  48. device->readPending = FALSE;
  49. DequeueDevice(device);
  50. DestroyDevice(device);
  51. }
  52. DBGOUT(("<== WorkItemCallback_Read()"));
  53. }
  54. /*
  55. * DispatchNtReadFile
  56. *
  57. *
  58. */
  59. VOID _cdecl DispatchNtReadFile(deviceContext *device)
  60. {
  61. DBGOUT(("==> DispatchNtReadFile()"));
  62. /*
  63. * Queue a work item to do the read; this way we'll be on a worker thread
  64. * instead of (possibly) the NTKERN thread when we call NtReadFile().
  65. * This prevents a contention bug.
  66. */
  67. _NtKernQueueWorkItem(&device->workItemRead, DelayedWorkQueue);
  68. DBGOUT(("<== DispatchNtReadFile()"));
  69. }
  70. /*
  71. * ReadCompletion
  72. *
  73. *
  74. */
  75. VOID ReadCompletion(IN PVOID Context, IN PIO_STATUS_BLOCK IoStatusBlock, IN ULONG Reserved)
  76. {
  77. ULONG dX = 0, dY = 0, Buttons = 0, scrollWheel=0;
  78. NTSTATUS ntStatus;
  79. deviceContext *device = (deviceContext *)Context;
  80. UINT numActualButtons;
  81. DBGOUT(("==> ReadCompletion()"));
  82. device->readPending = FALSE;
  83. /*
  84. * If this callback got to us after we've shut down, just delete this device context.
  85. */
  86. if (ShutDown){
  87. TryDestroyAll();
  88. return;
  89. }
  90. /*
  91. * If the read succeeded, parse out the report information.
  92. */
  93. if (NT_SUCCESS(IoStatusBlock->Status)){
  94. /*
  95. * <<COMPLETE>>
  96. *
  97. * What types of usage-values will you parse out of the device report?
  98. * This is device specific.
  99. * The code below would be appropriate for a 2-dimensional pointing
  100. * device with buttons (e.g. a mouse or touch screen).
  101. *
  102. */
  103. /*
  104. * Parse the device "report" for the values we want.
  105. *
  106. * For each value, try HIDPARSE's scaled function first;
  107. * failing that, try the non-scaled function.
  108. * (the scaled functions can fail for some devices that don't
  109. * report their min and max values correctly).
  110. */
  111. ntStatus = pHidP_GetScaledUsageValue(HidP_Input,
  112. HID_USAGE_PAGE_GENERIC,
  113. 0,
  114. HID_USAGE_GENERIC_X,
  115. (PLONG)&dX,
  116. device->hidDescriptor,
  117. (PUCHAR)device->report,
  118. device->hidCapabilities.InputReportByteLength);
  119. if (NT_ERROR(ntStatus)){
  120. DBGERR(("pHidP_GetScaledUsageValue failed"));
  121. ntStatus = pHidP_GetUsageValue(HidP_Input,
  122. HID_USAGE_PAGE_GENERIC,
  123. 0,
  124. HID_USAGE_GENERIC_X,
  125. &dX,
  126. device->hidDescriptor,
  127. (PUCHAR)device->report,
  128. device->hidCapabilities.InputReportByteLength);
  129. if (NT_ERROR(ntStatus)){
  130. DBGERR(("pHidP_GetUsageValue failed"));
  131. }
  132. }
  133. ntStatus = pHidP_GetScaledUsageValue(HidP_Input,
  134. HID_USAGE_PAGE_GENERIC,
  135. 0,
  136. HID_USAGE_GENERIC_Y,
  137. (PLONG)&dY,
  138. device->hidDescriptor,
  139. (PUCHAR)device->report,
  140. device->hidCapabilities.InputReportByteLength);
  141. if (NT_ERROR(ntStatus)){
  142. DBGERR(("pHidP_GetScaledUsageValue failed"));
  143. ntStatus = pHidP_GetUsageValue(HidP_Input,
  144. HID_USAGE_PAGE_GENERIC,
  145. 0,
  146. HID_USAGE_GENERIC_Y,
  147. &dY,
  148. device->hidDescriptor,
  149. (PUCHAR)device->report,
  150. device->hidCapabilities.InputReportByteLength);
  151. if (NT_ERROR(ntStatus)){
  152. DBGERR(("pHidP_GetUsageValue failed"));
  153. }
  154. }
  155. /*
  156. * Parse the button values
  157. */
  158. numActualButtons = device->buttonListLength;
  159. pHidP_GetUsages(HidP_Input,
  160. HID_USAGE_PAGE_BUTTON,
  161. 0,
  162. device->buttonValues,
  163. &numActualButtons,
  164. device->hidDescriptor,
  165. (PUCHAR)device->report,
  166. device->hidCapabilities.InputReportByteLength);
  167. /*
  168. * <<COMPLETE>>
  169. *
  170. * What are you going to do with the parsed data from the device?
  171. * This is device specific.
  172. *
  173. */
  174. }
  175. else {
  176. DBGERR(("ReadCompletion returned ERROR %xh.", (UINT)IoStatusBlock->Status));
  177. /*
  178. * Remove this device and then try to re-open it.
  179. */
  180. DequeueDevice(device);
  181. DestroyDevice(device);
  182. ConnectNTDeviceDrivers();
  183. }
  184. /*
  185. * Set up the next read of the device device.
  186. */
  187. DispatchNtReadFile(device);
  188. DBGOUT(("<== ReadCompletion()"));
  189. }