Leaked source code of windows server 2003
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.

911 lines
27 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. KBDHID.C
  5. Abstract:
  6. This module contains the init code for the i8042 to hid converter.
  7. Note: This is NOT a WDM driver, since it cannot run as a HID mapper on
  8. Memphis (Memphis requires that the keyboard to HID mapper be a VXD) and
  9. since it uses Event logs, which are not part of WDM 1.0
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. Nov-96 : created by Kenneth D. Ray
  14. Jan-97 : Dan Markarian : Made work
  15. May-97 : Kenneth D. Ray : reconstructed as PnP filter for Keyboard class
  16. --*/
  17. #include "kbdhid.h"
  18. #include "hidclass.h"
  19. //
  20. // Use the alloc_text pragma to specify the driver initialization routines
  21. // (they can be paged out). [DAN]
  22. //
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(INIT,DriverEntry)
  25. #pragma alloc_text(PAGE,KbdHid_Unload)
  26. #endif
  27. GLOBALS Globals;
  28. NTSTATUS
  29. DriverEntry(
  30. IN PDRIVER_OBJECT DriverObject,
  31. IN PUNICODE_STRING RegistryPath
  32. )
  33. /*++
  34. Routine Description:
  35. Installable driver initialization entry point.
  36. Arguments:
  37. DriverObject - pointer to the driver object
  38. RegistryPath - pointer to a unicode string representing the path
  39. to driver-specific key in the registry
  40. Return Value:
  41. NT status code
  42. --*/
  43. {
  44. NTSTATUS status = STATUS_SUCCESS;
  45. PUNICODE_STRING registryPath = &Globals.RegistryPath;
  46. Print (DBG_SS_TRACE, ("entering DriverEntry\n"));
  47. Print (DBG_SS_INFO, ("Keyboard to hid mapper\n"));
  48. RtlZeroMemory (&Globals, sizeof (GLOBALS));
  49. //
  50. // Need to ensure that the registry path is null-terminated.
  51. // Allocate pool to hold a null-terminated copy of the path.
  52. // Safe in paged pool since all registry routines execute at
  53. // PASSIVE_LEVEL.
  54. //
  55. registryPath->MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
  56. registryPath->Length = RegistryPath->Length;
  57. registryPath->Buffer = ExAllocatePool(
  58. PagedPool,
  59. registryPath->MaximumLength
  60. );
  61. if (!registryPath->Buffer) {
  62. Print (DBG_SS_ERROR,
  63. ("Initialize: Couldn't allocate pool for registry path."));
  64. status = STATUS_INSUFFICIENT_RESOURCES;
  65. goto DriverEntryReject;
  66. }
  67. RtlZeroMemory (registryPath->Buffer, registryPath->MaximumLength);
  68. RtlMoveMemory (registryPath->Buffer,
  69. RegistryPath->Buffer,
  70. RegistryPath->Length);
  71. //
  72. // Set up the device driver entry points.
  73. //
  74. DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdHid_Create;
  75. DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdHid_Close;
  76. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]=KbdHid_IOCTL;
  77. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdHid_PassThrough;
  78. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = KbdHid_Flush;
  79. DriverObject->MajorFunction[IRP_MJ_PNP] = KbdHid_PnP;
  80. DriverObject->MajorFunction[IRP_MJ_POWER] = KbdHid_Power;
  81. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KbdHid_SystemControl;
  82. DriverObject->DriverUnload = KbdHid_Unload;
  83. DriverObject->DriverExtension->AddDevice = KbdHid_AddDevice;
  84. Print (DBG_SS_TRACE, ("exit DriverEntry (0x%x) \n", status));
  85. return status;
  86. DriverEntryReject:
  87. if (registryPath->Buffer) {
  88. ExFreePool (registryPath->Buffer);
  89. }
  90. return status;
  91. }
  92. NTSTATUS
  93. KbdHid_PassThrough (
  94. IN PDEVICE_OBJECT DeviceObject,
  95. IN PIRP Irp
  96. )
  97. /*++
  98. Routine Description:
  99. Pass the irp on through
  100. --*/
  101. {
  102. NTSTATUS status;
  103. PDEVICE_EXTENSION data;
  104. data = DeviceObject->DeviceExtension;
  105. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  106. if (!NT_SUCCESS (status)) {
  107. Irp->IoStatus.Status = status;
  108. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  109. return status;
  110. }
  111. IoSkipCurrentIrpStackLocation (Irp);
  112. status = IoCallDriver (data->TopOfStack, Irp);
  113. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  114. return status;
  115. }
  116. VOID
  117. KbdHid_Unload(
  118. IN PDRIVER_OBJECT Driver
  119. )
  120. /*++
  121. Routine Description:
  122. Free all the allocated resources, etc.
  123. Arguments:
  124. DriverObject - pointer to a driver object
  125. Return Value:
  126. None
  127. --*/
  128. {
  129. PAGED_CODE ();
  130. ASSERT (NULL == Driver->DeviceObject);
  131. Print (DBG_SS_INFO, ("Unload \n"));
  132. //
  133. // Free resources in device extension.
  134. //
  135. ExFreePool (Globals.RegistryPath.Buffer);
  136. return;
  137. }
  138. NTSTATUS
  139. KbdHid_Flush(
  140. IN PDEVICE_OBJECT DeviceObject,
  141. IN PIRP Irp
  142. )
  143. /*++
  144. Routine Description:
  145. Respond to flush requests from the mouse class driver. Currently does
  146. nothing but pass IRP down to next lower driver. This routine expects
  147. the current IRQL to be < DISPATCH_LEVEL.
  148. Arguments:
  149. DeviceObject - Pointer to the device object.
  150. Irp - Pointer to the request packet.
  151. Return Value:
  152. NT status code.
  153. --*/
  154. {
  155. PDEVICE_EXTENSION data;
  156. NTSTATUS status;
  157. PIO_STACK_LOCATION stack;
  158. Print (DBG_CALL_INFO, ("Flush \n"));
  159. TRAP();
  160. //
  161. // Get a pointer to the device extension.
  162. //
  163. data = DeviceObject->DeviceExtension;
  164. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  165. if (!NT_SUCCESS (status)) {
  166. Irp->IoStatus.Status = status;
  167. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  168. return status;
  169. }
  170. //
  171. // Send the flush request down to the HID class driver, one for each
  172. // of our mouse device context structures.
  173. //
  174. IoCopyCurrentIrpStackLocationToNext (Irp);
  175. stack = IoGetNextIrpStackLocation (Irp);
  176. stack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  177. stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE;
  178. //
  179. // Fire and forget
  180. //
  181. status = IoCallDriver (data->TopOfStack, Irp);
  182. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  183. return status;
  184. }
  185. NTSTATUS
  186. KbdHid_IOCTL (
  187. IN PDEVICE_OBJECT DeviceObject,
  188. IN PIRP Irp
  189. )
  190. /*++
  191. Routine Description:
  192. Respond to queries from the mouse class driver.
  193. The IOCTLs for DISABLE, ENABLE, and QUERY_ATTRIBUTES, expect the current
  194. IRQL to be < DISPATCH_LEVEL.
  195. Arguments:
  196. DeviceObject - Pointer to the device object.
  197. Irp - Pointer to the request packet.
  198. Return Value:
  199. NT status code.
  200. --*/
  201. {
  202. PIO_STACK_LOCATION stack;
  203. NTSTATUS status = STATUS_SUCCESS;
  204. PDEVICE_EXTENSION data;
  205. ULONG length;
  206. PKEYBOARD_INDICATOR_TRANSLATION translation;
  207. BOOLEAN completeIt = TRUE;
  208. data = DeviceObject->DeviceExtension;
  209. Irp->IoStatus.Information = 0;
  210. stack = IoGetCurrentIrpStackLocation (Irp);
  211. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  212. if (!NT_SUCCESS (status)) {
  213. Irp->IoStatus.Status = status;
  214. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  215. return status;
  216. }
  217. ASSERT (data->Started ||
  218. (IOCTL_INTERNAL_KEYBOARD_CONNECT ==
  219. stack->Parameters.DeviceIoControl.IoControlCode));
  220. switch (stack->Parameters.DeviceIoControl.IoControlCode) {
  221. case IOCTL_INTERNAL_KEYBOARD_CONNECT:
  222. //
  223. // Connect a keyboard class device driver to the port driver.
  224. //
  225. Print (DBG_IOCTL_TRACE, ("enter Connect \n"));
  226. //
  227. // Connect a mouse class device driver to the filter driver.
  228. // Only allow one connection.
  229. //
  230. if (NULL != data->ConnectData.ClassService) {
  231. Print (DBG_IOCTL_ERROR, ("ERROR: Multiple connects \n"));
  232. TRAP ();
  233. status = STATUS_SHARING_VIOLATION;
  234. break;
  235. } else if (stack->Parameters.DeviceIoControl.InputBufferLength <
  236. sizeof(CONNECT_DATA)) {
  237. Print (DBG_IOCTL_ERROR, ("ERROR: Invalid connect parameter size. \n"));
  238. TRAP ();
  239. status = STATUS_INVALID_PARAMETER;
  240. break;
  241. }
  242. //
  243. // Copy the connection parameters to the device extension.
  244. //
  245. data->ConnectData = *(PCONNECT_DATA)
  246. stack->Parameters.DeviceIoControl.Type3InputBuffer;
  247. status = STATUS_SUCCESS;
  248. break;
  249. case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
  250. //
  251. // Disconnect a keyboard class device driver from the port driver.
  252. //
  253. Print (DBG_IOCTL_TRACE, ("Disconnect \n"));
  254. //
  255. // Not implemented.
  256. //
  257. // To implement, code the following:
  258. // ---------------------------------
  259. // o ENSURE that we are NOT enabled (mouHidDeviceExt->EnableCount);
  260. // o If we are, then (a) return STATUS_UNSUCCESSFUL, or
  261. // (b) disable all devices immediately; see
  262. // DISABLE IOCTL call for necessary code.
  263. // o SYNCHRONIZE with the mouse read completion routine (must
  264. // protect the callback pointer from being dereferenced when
  265. // it becomes null). Note that no mechanism currently exists
  266. // for this.
  267. // o CLEAR the connection parameters in the device extension;
  268. // ie. mouHidDeviceExt->MouClassObject = NULL;
  269. // mouHidDeviceExt->MouClassCallback = NULL;
  270. // o RELEASE the synchronizing lock.
  271. // o RETURN STATUS_SUCCESS.
  272. //
  273. status = STATUS_NOT_IMPLEMENTED;
  274. break;
  275. case IOCTL_INTERNAL_KEYBOARD_ENABLE:
  276. //
  277. // Enable keyboard interrupts which really means start the ping pong
  278. // down to hid class.
  279. //
  280. Print (DBG_IOCTL_ERROR, ("ERROR: PnP => use create not enable! \n"));
  281. status = STATUS_NOT_SUPPORTED;
  282. break;
  283. case IOCTL_INTERNAL_KEYBOARD_DISABLE:
  284. //
  285. // Disable keyboard interrupts which really means stop the ping pongs
  286. // down to hid class.
  287. //
  288. Print (DBG_IOCTL_ERROR, ("ERROR: PnP => use close not Disable! \n"));
  289. status = STATUS_NOT_SUPPORTED;
  290. break;
  291. case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
  292. //
  293. // Query the keyboard attributes. First check for adequate buffer
  294. // length. Then, copy the keyboard attributes from the first device
  295. // context to the output buffer. [DAN]
  296. //
  297. Print (DBG_IOCTL_TRACE, ("Query Attributes \n"));
  298. if (stack->Parameters.DeviceIoControl.OutputBufferLength <
  299. sizeof(KEYBOARD_ATTRIBUTES)) {
  300. Print (DBG_IOCTL_ERROR,
  301. ("ERROR: Query Attributes buffer too small \n"));
  302. status = STATUS_BUFFER_TOO_SMALL;
  303. } else {
  304. //
  305. // Copy the keyboard attributes to the buffer.
  306. //
  307. *(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
  308. data->Attributes;
  309. Irp->IoStatus.Information = sizeof (KEYBOARD_ATTRIBUTES);
  310. status = STATUS_SUCCESS;
  311. }
  312. break;
  313. case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
  314. //
  315. // Query the scan code to indicator-light mapping. Validate the
  316. // parameters, and copy the indicator mapping information from
  317. // the static translation list to the SystemBuffer.
  318. //
  319. Print (DBG_IOCTL_TRACE, ("Query Indicator Translation \n"));
  320. length = sizeof(KEYBOARD_INDICATOR_TRANSLATION)
  321. + (sizeof(INDICATOR_LIST)
  322. * (HID_KEYBOARD_NUMBER_OF_INDICATORS - 1));
  323. if (stack->Parameters.DeviceIoControl.OutputBufferLength < length) {
  324. status = STATUS_BUFFER_TOO_SMALL;
  325. break;
  326. }
  327. //
  328. // Copy the indicator mapping information to the system
  329. // buffer.
  330. //
  331. translation = ((PKEYBOARD_INDICATOR_TRANSLATION)
  332. Irp->AssociatedIrp.SystemBuffer);
  333. translation->NumberOfIndicatorKeys = HID_KEYBOARD_NUMBER_OF_INDICATORS;
  334. RtlMoveMemory(translation->IndicatorList,
  335. (PCHAR) IndicatorList,
  336. length - FIELD_OFFSET (KEYBOARD_INDICATOR_TRANSLATION,
  337. IndicatorList));
  338. Irp->IoStatus.Information = length;
  339. status = STATUS_SUCCESS;
  340. break;
  341. case IOCTL_KEYBOARD_QUERY_INDICATORS:
  342. //
  343. // Query the keyboard indicators. Validate the parameters, and
  344. // copy the indicator information from the device context to
  345. // the SystemBuffer. [DAN]
  346. //
  347. Print (DBG_IOCTL_TRACE, ("Query Indicators \n"));
  348. if (stack->Parameters.DeviceIoControl.OutputBufferLength <
  349. sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
  350. status = STATUS_BUFFER_TOO_SMALL;
  351. break;
  352. }
  353. //
  354. // Copy the keyboard indicators to the buffer.
  355. //
  356. //
  357. // Don't bother to synchronize access to the device context
  358. // KeyboardIndicators field while copying it. We don't care
  359. // if another process is setting the LEDs.
  360. //
  361. // Copy the keyboard indicators to the buffer.
  362. *(PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
  363. data->Indicators;
  364. Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
  365. status = STATUS_SUCCESS;
  366. break;
  367. case IOCTL_KEYBOARD_SET_INDICATORS:
  368. //
  369. // Set the keyboard indicators for all known device contexts. [DAN]
  370. //
  371. Print (DBG_IOCTL_TRACE, ("Set Indicators \n"));
  372. if (stack->Parameters.DeviceIoControl.InputBufferLength <
  373. sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
  374. Print (DBG_IOCTL_ERROR, ("ERROR: Set Indicators size!\n"));
  375. status = STATUS_INVALID_PARAMETER;
  376. break;
  377. }
  378. status = KbdHid_SetLedIndicators (
  379. data,
  380. (PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer,
  381. Irp);
  382. completeIt = FALSE;
  383. break;
  384. case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
  385. //
  386. // Query the current keyboard typematic rate and delay. Validate
  387. // the parameters, and copy the typematic information from the port
  388. // device extension to the SystemBuffer. [DAN]
  389. //
  390. Print (DBG_IOCTL_TRACE, ("Query Typematic \n"));
  391. if (stack->Parameters.DeviceIoControl.OutputBufferLength <
  392. sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
  393. Print (DBG_IOCTL_ERROR, ("ERROR: query typematic size!\n"));
  394. status = STATUS_BUFFER_TOO_SMALL;
  395. break;
  396. }
  397. //
  398. // Copy the keyboard typematic info to the buffer.
  399. //
  400. //
  401. // Don't bother to synchronize access to the device context
  402. // KeyboardTypematic field while copying it. We don't care
  403. // if another process is setting the typematic info.
  404. //
  405. *(PKEYBOARD_TYPEMATIC_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
  406. data->Typematic;
  407. Irp->IoStatus.Information = sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
  408. status = STATUS_SUCCESS;
  409. break;
  410. case IOCTL_KEYBOARD_SET_TYPEMATIC:
  411. //
  412. // Set the keyboard typematic rate and delay for all known device
  413. // contexts. [DAN]
  414. //
  415. Print (DBG_IOCTL_TRACE, ("Set Typematic \n"));
  416. if (stack->Parameters.DeviceIoControl.InputBufferLength <
  417. sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
  418. Print (DBG_IOCTL_ERROR, ("ERROR: Set Typematic size\n"));
  419. status = STATUS_INVALID_PARAMETER;
  420. break;
  421. }
  422. #define NewTypematic ((PKEYBOARD_TYPEMATIC_PARAMETERS) \
  423. Irp->AssociatedIrp.SystemBuffer)
  424. if ((NewTypematic->Rate == 0) && (NewTypematic->Delay == 0)) {
  425. break;
  426. }
  427. if ((NewTypematic->Rate < data->Attributes.KeyRepeatMinimum.Rate) ||
  428. (NewTypematic->Rate > data->Attributes.KeyRepeatMaximum.Rate) ||
  429. (NewTypematic->Delay < data->Attributes.KeyRepeatMinimum.Delay) ||
  430. (NewTypematic->Delay > data->Attributes.KeyRepeatMaximum.Delay)) {
  431. Print (DBG_IOCTL_ERROR, ("ERROR: Set Typematic range\n"));
  432. status = STATUS_INVALID_PARAMETER;
  433. break;
  434. }
  435. Print (DBG_IOCTL_INFO,
  436. ("Set Typematic Rate: %d Delay: %d\n",
  437. NewTypematic->Rate,
  438. NewTypematic->Delay));
  439. //
  440. // Don't bother to synchronize access to the device context
  441. // KeyboardTypematic field while copying it. We don't care
  442. // if another thread is reading the typematic info.
  443. //
  444. // Note the only danger here is in setting the 64-bit integer
  445. // "AutoRepeatDelay" in two non-atomic statements. However,
  446. // we are safe since we never set "HighPart" to anything but
  447. // -1.
  448. //
  449. data->Typematic = *NewTypematic;
  450. data->AutoRepeatRate = 1000 / NewTypematic->Rate; // ms
  451. data->AutoRepeatDelay.LowPart = -NewTypematic->Delay*10000; // 100ns
  452. data->AutoRepeatDelay.HighPart = -1;
  453. break;
  454. #undef NewTypematic
  455. default:
  456. Print (DBG_IOCTL_ERROR,
  457. ("ERROR: unknown IOCTL: 0x%x \n",
  458. stack->Parameters.DeviceIoControl.IoControlCode));
  459. status = STATUS_INVALID_DEVICE_REQUEST;
  460. break;
  461. }
  462. if (completeIt) {
  463. Irp->IoStatus.Status = status;
  464. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  465. }
  466. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  467. Print (DBG_IOCTL_TRACE, ("IOCTL exit (%x)\n", status));
  468. return status;
  469. }
  470. NTSTATUS
  471. KbdHid_SetLedIndicatorsComplete (
  472. IN PDEVICE_OBJECT DeviceObject,
  473. IN PIRP Irp,
  474. IN PVOID Context
  475. )
  476. {
  477. PIO_STACK_LOCATION stack;
  478. PDEVICE_EXTENSION data;
  479. stack = IoGetCurrentIrpStackLocation (Irp);
  480. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  481. if (Irp->PendingReturned) {
  482. IoMarkIrpPending (Irp);
  483. }
  484. IoFreeMdl (Irp->MdlAddress);
  485. Irp->MdlAddress = (PMDL) stack->Parameters.Others.Argument4;
  486. ExFreePool (Context);
  487. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  488. return STATUS_SUCCESS;
  489. }
  490. NTSTATUS
  491. KbdHid_SetLedIndicators (
  492. PDEVICE_EXTENSION Data,
  493. PKEYBOARD_INDICATOR_PARAMETERS NewIndicators,
  494. PIRP Irp
  495. )
  496. /*++
  497. Routine Description:
  498. Set the LED indicators of the supplied keyboard device context.
  499. Arguments:
  500. Data - Pointer to the driver device extension.
  501. Parameters - Pointer to the keyboard indicators to set/unset.
  502. Irp - An Irp to use for setting these parameters
  503. Return Value:
  504. STATUS_SUCCESS on success, STATUS_PENDING if operation is still pending,
  505. or otherwise an NTSTATUS error code on an error.
  506. --*/
  507. {
  508. PIO_STACK_LOCATION nextStack;
  509. PIO_STACK_LOCATION curStack;
  510. NTSTATUS status = STATUS_SUCCESS;
  511. USAGE usageBuffer [4]; // only 4 known usages hardcoded below
  512. ULONG usageBufferLen = 0;
  513. PCHAR outputBuffer = 0;
  514. PMDL outputMdl = 0;
  515. PHID_EXTENSION hid = Data->HidExtension;
  516. status = IoAcquireRemoveLock (&Data->RemoveLock, Irp);
  517. if (!NT_SUCCESS (status)) {
  518. Irp->IoStatus.Status = status;
  519. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  520. return status;
  521. }
  522. if (0 == hid->Caps.OutputReportByteLength) {
  523. //
  524. // This device has no LEDs, now while that is strange it is not really
  525. // an error. HID keyboards can have any LEDs that they want, including
  526. // none.
  527. //
  528. status = STATUS_SUCCESS;
  529. goto KbdHid_SetIndicatorsReject;
  530. }
  531. outputBuffer = ExAllocatePool (NonPagedPool,
  532. hid->Caps.OutputReportByteLength);
  533. if (NULL == outputBuffer) {
  534. status = STATUS_INSUFFICIENT_RESOURCES;
  535. goto KbdHid_SetIndicatorsReject;
  536. }
  537. outputMdl = IoAllocateMdl (outputBuffer, // The virtual address
  538. hid->Caps.OutputReportByteLength, // length of the MDL
  539. FALSE, // No associated IRP -> not secondary
  540. FALSE, // No quota charge
  541. 0); // No associated IRP
  542. if (NULL == outputMdl) {
  543. status = STATUS_INSUFFICIENT_RESOURCES;
  544. goto KbdHid_SetIndicatorsReject;
  545. }
  546. MmBuildMdlForNonPagedPool (outputMdl); // Build this MDL.
  547. //
  548. // Zero the output report packet.
  549. //
  550. RtlZeroMemory(outputBuffer, hid->Caps.OutputReportByteLength);
  551. //
  552. // Setup the usage list of LEDs.
  553. //
  554. if (NewIndicators->LedFlags & KEYBOARD_KANA_LOCK_ON) {
  555. usageBuffer[usageBufferLen++] = HID_USAGE_LED_KANA;
  556. }
  557. if (NewIndicators->LedFlags & KEYBOARD_CAPS_LOCK_ON) {
  558. usageBuffer[usageBufferLen++] = HID_USAGE_LED_CAPS_LOCK;
  559. }
  560. if (NewIndicators->LedFlags & KEYBOARD_NUM_LOCK_ON) {
  561. usageBuffer[usageBufferLen++] = HID_USAGE_LED_NUM_LOCK;
  562. }
  563. if (NewIndicators->LedFlags & KEYBOARD_SCROLL_LOCK_ON) {
  564. usageBuffer[usageBufferLen++] = HID_USAGE_LED_SCROLL_LOCK;
  565. }
  566. if (usageBufferLen == 0) {
  567. ASSERT((NewIndicators->LedFlags & (KEYBOARD_KANA_LOCK_ON |
  568. KEYBOARD_CAPS_LOCK_ON |
  569. KEYBOARD_NUM_LOCK_ON |
  570. KEYBOARD_SCROLL_LOCK_ON)) == 0);
  571. //
  572. // In order to fix led setting on a multiple collection keyboard, we
  573. // have to initialize the output report to make sure we get the correct
  574. // collection id. This is for the case where we are going from one
  575. // led on to all leds off. If not initialized, we'll get a report with no
  576. // collection id at the beginning.
  577. //
  578. usageBuffer[0] = HID_USAGE_LED_SCROLL_LOCK; // arbitirary led
  579. usageBufferLen = 1;
  580. HidP_UnsetUsages(HidP_Output,
  581. HID_USAGE_PAGE_LED,
  582. 0,
  583. usageBuffer,
  584. &usageBufferLen,
  585. hid->Ppd,
  586. outputBuffer,
  587. hid->Caps.OutputReportByteLength);
  588. }
  589. else {
  590. //
  591. // Set the usages in the output report.
  592. //
  593. HidP_SetUsages(HidP_Output,
  594. HID_USAGE_PAGE_LED,
  595. 0,
  596. usageBuffer,
  597. &usageBufferLen,
  598. hid->Ppd,
  599. outputBuffer,
  600. hid->Caps.OutputReportByteLength);
  601. }
  602. //
  603. // Obtain a pointer to the next IRP stack location.
  604. //
  605. nextStack = IoGetNextIrpStackLocation (Irp);
  606. curStack = IoGetCurrentIrpStackLocation (Irp);
  607. ASSERT(nextStack != NULL);
  608. //
  609. // Set up our write to HIDCLASS.
  610. //
  611. curStack->Parameters.Others.Argument4 = (PVOID) Irp->MdlAddress;
  612. Irp->MdlAddress = outputMdl;
  613. IoCopyCurrentIrpStackLocationToNext (Irp);
  614. nextStack->MajorFunction = IRP_MJ_WRITE;
  615. nextStack->Parameters.Write.Length = hid->Caps.OutputReportByteLength;
  616. nextStack->Parameters.Write.Key = 0;
  617. nextStack->Parameters.Write.ByteOffset.QuadPart = 0;
  618. //
  619. // Hook a completion routine to be called when the request completes.
  620. //
  621. IoSetCompletionRoutine (Irp,
  622. KbdHid_SetLedIndicatorsComplete,
  623. outputBuffer,
  624. TRUE,
  625. TRUE,
  626. TRUE);
  627. //
  628. // Call the next driver.
  629. //
  630. status = IoCallDriver(Data->TopOfStack, Irp);
  631. //
  632. // Return status.
  633. //
  634. return status;
  635. KbdHid_SetIndicatorsReject:
  636. Irp->IoStatus.Status = status;
  637. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  638. if (NULL != outputBuffer) {
  639. ExFreePool (outputBuffer);
  640. }
  641. if (NULL != outputMdl) {
  642. IoFreeMdl (outputMdl);
  643. }
  644. IoReleaseRemoveLock (&Data->RemoveLock, Irp);
  645. return status;
  646. }
  647. VOID
  648. KbdHid_LogError(
  649. IN PDRIVER_OBJECT DriverObject,
  650. IN NTSTATUS ErrorCode,
  651. IN PWSTR ErrorInsertionString OPTIONAL)
  652. /*++
  653. [DAN]
  654. Routine Description:
  655. Logs an error to the system.
  656. Arguments:
  657. DriverObject - Pointer to driver object reporting the error.
  658. ErrorCode - Indicates the type of error, system or driver-defined.
  659. ErrorInsertionString - Null-terminated Unicode string inserted into error
  660. description, as defined by error code. Must be no
  661. no longer than 50 characters.
  662. Return Value:
  663. None.
  664. --*/
  665. {
  666. ULONG errorInsertionStringSize = 0;
  667. PIO_ERROR_LOG_PACKET errorLogEntry;
  668. ULONG errorLogEntrySize; // [including null]
  669. PWCHAR pWChar;
  670. if (ErrorInsertionString) {
  671. for (pWChar = ErrorInsertionString; *pWChar; pWChar++) {
  672. errorInsertionStringSize += sizeof(WCHAR);
  673. }
  674. errorInsertionStringSize += sizeof(UNICODE_NULL);
  675. }
  676. errorLogEntrySize = sizeof(IO_ERROR_LOG_PACKET) + errorInsertionStringSize;
  677. //
  678. // Log an error.
  679. //
  680. if (errorLogEntrySize <= ERROR_LOG_MAXIMUM_SIZE) {
  681. errorLogEntry = IoAllocateErrorLogEntry(DriverObject,
  682. (UCHAR)errorLogEntrySize);
  683. if (errorLogEntry != NULL) {
  684. RtlZeroMemory(errorLogEntry, errorLogEntrySize);
  685. errorLogEntry->ErrorCode = ErrorCode;
  686. errorLogEntry->FinalStatus = ErrorCode;
  687. errorLogEntry->NumberOfStrings = (ErrorInsertionString) ? 1 : 0;
  688. if (ErrorInsertionString) {
  689. RtlCopyMemory(errorLogEntry->DumpData,
  690. ErrorInsertionString,
  691. errorInsertionStringSize);
  692. }
  693. IoWriteErrorLogEntry(errorLogEntry);
  694. }
  695. }
  696. return;
  697. }