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.

530 lines
16 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. hid.c
  5. Abstract: Human Input Device (HID) minidriver for Infrared (IR) devices
  6. The HID IR Minidriver (HidIr) provides an abstraction layer for the
  7. HID Class to talk to HID IR devices.
  8. Author:
  9. jsenior
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "pch.h"
  15. PVOID
  16. HidIrGetSystemAddressForMdlSafe(PMDL MdlAddress)
  17. {
  18. PVOID buf = NULL;
  19. /*
  20. * Can't call MmGetSystemAddressForMdlSafe in a WDM driver,
  21. * so set the MDL_MAPPING_CAN_FAIL bit and check the result
  22. * of the mapping.
  23. */
  24. if (MdlAddress) {
  25. MdlAddress->MdlFlags |= MDL_MAPPING_CAN_FAIL;
  26. buf = MmGetSystemAddressForMdl(MdlAddress);
  27. MdlAddress->MdlFlags &= ~(MDL_MAPPING_CAN_FAIL);
  28. }
  29. return buf;
  30. }
  31. /*
  32. ********************************************************************************
  33. * HidIrGetHidDescriptor
  34. ********************************************************************************
  35. *
  36. * Routine Description:
  37. *
  38. * Return the hid descriptor of the requested type. This ioctl can only
  39. * be sent from the HidClass driver. The hidclass driver always sends the
  40. * irp with a userbuffer, so there is no need to check for its existence.
  41. * But better safe then sorry...
  42. *
  43. * Arguments:
  44. *
  45. * DeviceObject - pointer to a device object.
  46. *
  47. * Return Value:
  48. *
  49. * NT status code.
  50. *
  51. */
  52. NTSTATUS HidIrGetHidDescriptor(
  53. IN PDEVICE_OBJECT DeviceObject,
  54. IN PIRP Irp,
  55. USHORT DescriptorType
  56. )
  57. {
  58. PHIDIR_EXTENSION devExt;
  59. PIO_STACK_LOCATION irpStack;
  60. ULONG descLength = 0, bytesToCopy;
  61. PUCHAR descriptor = NULL;
  62. PAGED_CODE();
  63. HidIrKdPrint((3, "HidIrGetHidDescriptor type %x", DescriptorType));
  64. devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
  65. irpStack = IoGetCurrentIrpStackLocation(Irp);
  66. bytesToCopy = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  67. switch (DescriptorType) {
  68. case HID_HID_DESCRIPTOR_TYPE:
  69. descLength = devExt->HidDescriptor.bLength;
  70. descriptor = (PUCHAR)&devExt->HidDescriptor;
  71. break;
  72. case HID_REPORT_DESCRIPTOR_TYPE:
  73. descLength = devExt->HidDescriptor.DescriptorList[0].wDescriptorLength;
  74. descriptor = devExt->ReportDescriptor;
  75. break;
  76. case HID_PHYSICAL_DESCRIPTOR_TYPE:
  77. // Not handled
  78. break;
  79. default:
  80. HIR_TRAP();
  81. }
  82. if (descLength == 0 ||
  83. descriptor == NULL) {
  84. return STATUS_UNSUCCESSFUL;
  85. }
  86. if (bytesToCopy > descLength) {
  87. bytesToCopy = descLength;
  88. }
  89. if (Irp->UserBuffer) {
  90. RtlCopyMemory((PUCHAR)Irp->UserBuffer, descriptor, bytesToCopy);
  91. Irp->IoStatus.Information = bytesToCopy;
  92. } else {
  93. HIR_TRAP();
  94. return STATUS_INVALID_USER_BUFFER;
  95. }
  96. return STATUS_SUCCESS;
  97. }
  98. /*
  99. ********************************************************************************
  100. * HidIrGetDeviceAttributes
  101. ********************************************************************************
  102. *
  103. * Routine Description:
  104. *
  105. * Fill in the given struct _HID_DEVICE_ATTRIBUTES. This ioctl can only
  106. * be sent from the HidClass driver. The hidclass driver always sends the
  107. * irp with a userbuffer, so there is no need to check for its existence.
  108. * But better safe then sorry...
  109. *
  110. * Arguments:
  111. *
  112. * DeviceObject - pointer to a device object.
  113. *
  114. * Return Value:
  115. *
  116. * NT status code.
  117. *
  118. */
  119. NTSTATUS HidIrGetDeviceAttributes(
  120. IN PDEVICE_OBJECT DeviceObject,
  121. IN PIRP Irp
  122. )
  123. {
  124. NTSTATUS ntStatus;
  125. PAGED_CODE();
  126. HidIrKdPrint((3, "HidIrGetDeviceAttributes Enter"));
  127. if (Irp->UserBuffer) {
  128. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  129. PHID_DEVICE_ATTRIBUTES deviceAttributes =
  130. (PHID_DEVICE_ATTRIBUTES) Irp->UserBuffer;
  131. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
  132. sizeof (HID_DEVICE_ATTRIBUTES)){
  133. PHIDIR_EXTENSION devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
  134. //
  135. // Report how many bytes were copied
  136. //
  137. Irp->IoStatus.Information = sizeof (HID_DEVICE_ATTRIBUTES);
  138. deviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES);
  139. // TODO: Get these values from the bth stack.
  140. deviceAttributes->VendorID = devExt->VendorID;
  141. deviceAttributes->ProductID = devExt->ProductID;
  142. deviceAttributes->VersionNumber = devExt->VersionNumber;
  143. ntStatus = STATUS_SUCCESS;
  144. } else {
  145. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  146. }
  147. } else {
  148. HIR_TRAP();
  149. ntStatus = STATUS_INVALID_USER_BUFFER;
  150. }
  151. ASSERT(NT_SUCCESS(ntStatus));
  152. return ntStatus;
  153. }
  154. /*
  155. ********************************************************************************
  156. * HidIrIncrementPendingRequestCount
  157. ********************************************************************************
  158. *
  159. *
  160. */
  161. NTSTATUS HidIrIncrementPendingRequestCount(IN PHIDIR_EXTENSION DevExt)
  162. {
  163. LONG newRequestCount;
  164. NTSTATUS ntStatus = STATUS_SUCCESS;
  165. newRequestCount = InterlockedIncrement(&DevExt->NumPendingRequests);
  166. HidIrKdPrint((3, "Increment Pending Request Count to %x", newRequestCount));
  167. // Make sure that the device is capable of receiving new requests.
  168. if ((DevExt->DeviceState != DEVICE_STATE_RUNNING) &&
  169. (DevExt->DeviceState != DEVICE_STATE_STARTING)){
  170. HIR_TRAP();
  171. // Device cannot receive any more IOs, decrement back, fail the increment
  172. HidIrDecrementPendingRequestCount(DevExt);
  173. ntStatus = STATUS_NO_SUCH_DEVICE;
  174. }
  175. return ntStatus;
  176. }
  177. /*
  178. ********************************************************************************
  179. * HidIrDecrementPendingRequestCount
  180. ********************************************************************************
  181. *
  182. *
  183. */
  184. VOID HidIrDecrementPendingRequestCount(IN PHIDIR_EXTENSION DevExt)
  185. {
  186. LONG PendingCount;
  187. ASSERT(DevExt->NumPendingRequests >= 0);
  188. PendingCount = InterlockedDecrement(&DevExt->NumPendingRequests);
  189. HidIrKdPrint((3, "Decrement Pending Request Count to %x", PendingCount));
  190. if (PendingCount < 0){
  191. ASSERT(DevExt->DeviceState != DEVICE_STATE_RUNNING);
  192. /*
  193. * The device state is stopping, and the last outstanding request
  194. * has just completed.
  195. *
  196. * Note: RemoveDevice does an extra decrement, so we complete
  197. * the REMOVE IRP on the transition to -1, whether this
  198. * happens in RemoveDevice itself or subsequently while
  199. * RemoveDevice is waiting for this event to fire.
  200. */
  201. KeSetEvent(&DevExt->AllRequestsCompleteEvent, 0, FALSE);
  202. }
  203. }
  204. /*
  205. ********************************************************************************
  206. * HidIrReadCompletion
  207. ********************************************************************************
  208. *
  209. *
  210. */
  211. NTSTATUS HidIrReadCompletion(
  212. IN PDEVICE_OBJECT DeviceObject,
  213. IN PIRP Irp,
  214. IN PHIDIR_EXTENSION DevExt
  215. )
  216. {
  217. NTSTATUS ntStatus = Irp->IoStatus.Status;
  218. ULONG bytesRead;
  219. PUCHAR buffer;
  220. BOOLEAN resend = FALSE;
  221. PHIDIR_EXTENSION devExt;
  222. devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
  223. HidIrKdPrint((3, "HidIrReadCompletion status %x", ntStatus));
  224. ASSERT(Irp->MdlAddress);
  225. buffer = HidIrGetSystemAddressForMdlSafe(Irp->MdlAddress);
  226. if(!buffer) {
  227. // If this fails, we really should bugcheck, since someone
  228. // in the kernel screwed up our MDL on us. I'll fail safely, but
  229. // definitely trap on debug builds.
  230. HIR_TRAP();
  231. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  232. } else if (NT_SUCCESS(ntStatus)){
  233. // Get the bytes read from the status block
  234. bytesRead = (ULONG)Irp->IoStatus.Information;
  235. // Predispose to zero
  236. Irp->IoStatus.Information = 0;
  237. if (bytesRead == sizeof(ULONG)) {
  238. ULONG value, i;
  239. RtlCopyMemory(&value, buffer, sizeof(ULONG));
  240. if (value == 0) {
  241. // Key up. Do we have a pending key down?
  242. if (devExt->PreviousButton.UsageString[0]) {
  243. // We have a pending key down. Send key up.
  244. PUCHAR destination;
  245. // Send the ~usage.
  246. HidIrKdPrint((2,"Sending ~usage"));
  247. Irp->IoStatus.Information = devExt->ReportLength;
  248. destination = (PUCHAR) Irp->UserBuffer;
  249. RtlZeroMemory(Irp->UserBuffer, Irp->IoStatus.Information); // already checked that buffer is big enuf.
  250. destination[0] = devExt->PreviousButton.UsageString[0]; // report ID
  251. RtlZeroMemory(&devExt->PreviousButton, sizeof(devExt->PreviousButton));
  252. } else {
  253. // No pending key down message for this key up. Fire it back.
  254. resend = TRUE;
  255. }
  256. } else if (value == devExt->PreviousButton.IRString) {
  257. // Same thing as last time. Fire it back down.
  258. resend = TRUE;
  259. } else {
  260. // Something new. Hmmm...
  261. ULONG entrySize = HIDIR_TABLE_ENTRY_SIZE(devExt->ReportLength);
  262. PUSAGE_TABLE_ENTRY entry;
  263. // Predispose to bounce the irp back down if we don't find a match.
  264. resend = TRUE;
  265. for (i = 0; i < devExt->NumUsages; i++) {
  266. entry = (PUSAGE_TABLE_ENTRY) (devExt->MappingTable+(entrySize*i));
  267. if (entry->IRString == value) {
  268. HidIrKdPrint((2,"Found usage %x!", value));
  269. // New usage. Copy it and complete the irp.
  270. Irp->IoStatus.Information = devExt->ReportLength;
  271. RtlCopyMemory(Irp->UserBuffer,
  272. entry->UsageString,
  273. devExt->ReportLength);
  274. RtlCopyMemory(&devExt->PreviousButton,
  275. entry,
  276. sizeof(devExt->PreviousButton));
  277. // Check if we are allowed to send up standby button presses yet.
  278. if (KeReadStateTimer(&devExt->IgnoreStandbyTimer) ||
  279. !devExt->StandbyReportIdValid ||
  280. devExt->StandbyReportId != entry->UsageString[0]) {
  281. resend = FALSE;
  282. }
  283. break;
  284. }
  285. }
  286. if (resend) {
  287. // This might be an OEM button. Check if it's within the approved range.
  288. if (value >= 0x800F0400 && value <= 0x800F04FF) {
  289. PUCHAR usageString = Irp->UserBuffer;
  290. UCHAR oemValue = (UCHAR) (value & 0xFF);
  291. // It's in the range!
  292. HidIrKdPrint((2,"OEM button %x", value));
  293. RtlZeroMemory(usageString, devExt->ReportLength);
  294. // Check if this is the "flag" button. If so, and we are not running
  295. // media center, we want to eject the windows key instead.
  296. if (oemValue == 0x0D && !RunningMediaCenter && devExt->KeyboardReportIdValid) {
  297. HidIrKdPrint((2,"Change flag button to Windows key"));
  298. usageString[0] = devExt->KeyboardReportId;
  299. usageString[1] = 0x8;
  300. Irp->IoStatus.Information = devExt->ReportLength;
  301. } else {
  302. usageString[0] = 0x1;
  303. usageString[1] = oemValue;
  304. Irp->IoStatus.Information = 2;
  305. }
  306. devExt->PreviousButton.IRString = value;
  307. devExt->PreviousButton.UsageString[0] = usageString[0];
  308. resend = FALSE;
  309. }
  310. }
  311. }
  312. HidIrKdPrint((3, "HidIrReadCompletion buffer value 0x%x", value));
  313. } else {
  314. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  315. }
  316. } else if (ntStatus == STATUS_CANCELLED){
  317. /*
  318. * The IRP was cancelled, which means that the device is probably getting removed.
  319. */
  320. HidIrKdPrint((1, "Read irp %p cancelled ...", Irp));
  321. ASSERT(!Irp->CancelRoutine);
  322. }
  323. // Balance the increment we did when we issued the read.
  324. HidIrDecrementPendingRequestCount(DevExt);
  325. //
  326. // Don't need the MDL and buffer anymore.
  327. //
  328. if (Irp->MdlAddress) {
  329. IoFreeMdl(Irp->MdlAddress);
  330. Irp->MdlAddress = NULL;
  331. if (buffer) {
  332. ExFreePool(buffer);
  333. }
  334. }
  335. // If we didn't get anything useful back, just poke it back down
  336. // to the hardware.
  337. if (resend) {
  338. BOOLEAN needsCompletion = TRUE;
  339. ntStatus = HidIrReadReport(DeviceObject, Irp, &needsCompletion);
  340. if (!needsCompletion) {
  341. return STATUS_MORE_PROCESSING_REQUIRED;
  342. }
  343. Irp->IoStatus.Status = ntStatus; // fall thru and irp will complete.
  344. }
  345. /*
  346. * If the lower driver returned PENDING, mark our stack location as
  347. * pending also. This prevents the IRP's thread from being freed if
  348. * the client's call returns pending.
  349. */
  350. if (Irp->PendingReturned){
  351. IoMarkIrpPending(Irp);
  352. }
  353. return STATUS_SUCCESS; // something other than SMPR
  354. }
  355. /*
  356. ********************************************************************************
  357. * HidIrReadReport
  358. ********************************************************************************
  359. *
  360. * Routine Description:
  361. *
  362. *
  363. * Arguments:
  364. *
  365. * DeviceObject - Pointer to class device object.
  366. *
  367. * IrpStack - Pointer to Interrupt Request Packet.
  368. *
  369. *
  370. * Return Value:
  371. *
  372. * STATUS_SUCCESS, STATUS_UNSUCCESSFUL.
  373. *
  374. *
  375. * Note: this function cannot be pageable because reads/writes
  376. * can be made at dispatch-level.
  377. */
  378. NTSTATUS HidIrReadReport(
  379. IN PDEVICE_OBJECT DeviceObject,
  380. IN PIRP Irp,
  381. IN OUT BOOLEAN *NeedsCompletion)
  382. {
  383. NTSTATUS status = STATUS_UNSUCCESSFUL;
  384. PHIDIR_EXTENSION devExt;
  385. PUCHAR buffer;
  386. ULONG bufferLen;
  387. PIO_STACK_LOCATION irpStack;
  388. HidIrKdPrint((3, "HidIrReadReport Enter"));
  389. devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
  390. ASSERT(Irp->UserBuffer);
  391. irpStack = IoGetCurrentIrpStackLocation(Irp);
  392. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < devExt->ReportLength) {
  393. return STATUS_INVALID_BUFFER_SIZE;
  394. }
  395. bufferLen = HIDIR_REPORT_SIZE;
  396. buffer = ALLOCATEPOOL(NonPagedPool, bufferLen);
  397. if (buffer) {
  398. ASSERT(!Irp->MdlAddress);
  399. if (IoAllocateMdl(buffer,
  400. bufferLen,
  401. FALSE,
  402. FALSE,
  403. Irp)) {
  404. MmBuildMdlForNonPagedPool(Irp->MdlAddress);
  405. irpStack = IoGetNextIrpStackLocation(Irp);
  406. irpStack->MajorFunction = IRP_MJ_READ;
  407. irpStack->DeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);
  408. irpStack->Parameters.Read.Length = bufferLen;
  409. IoSetCompletionRoutine(
  410. Irp,
  411. HidIrReadCompletion,
  412. devExt,
  413. TRUE,
  414. TRUE,
  415. TRUE );
  416. //
  417. // We need to keep track of the number of pending requests
  418. // so that we can make sure they're all cancelled properly during
  419. // processing of a stop device request.
  420. //
  421. if (NT_SUCCESS(HidIrIncrementPendingRequestCount(devExt))){
  422. status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  423. *NeedsCompletion = FALSE;
  424. } else {
  425. IoFreeMdl(Irp->MdlAddress);
  426. Irp->MdlAddress = NULL;
  427. ExFreePool(buffer);
  428. status = STATUS_NO_SUCH_DEVICE;
  429. }
  430. } else {
  431. ExFreePool(buffer);
  432. status = STATUS_INSUFFICIENT_RESOURCES;
  433. }
  434. } else {
  435. status = STATUS_INSUFFICIENT_RESOURCES;
  436. }
  437. return status;
  438. }