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.

1161 lines
32 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(INIT,KbdHid_GetRegistryParameters)
  26. #pragma alloc_text(PAGE,KbdHid_UpdateRegistryProblemFlagsCallback)
  27. #pragma alloc_text(PAGE,KbdHid_Unload)
  28. #endif
  29. GLOBALS Globals;
  30. NTSTATUS
  31. DriverEntry(
  32. IN PDRIVER_OBJECT DriverObject,
  33. IN PUNICODE_STRING RegistryPath
  34. )
  35. /*++
  36. Routine Description:
  37. Installable driver initialization entry point.
  38. Arguments:
  39. DriverObject - pointer to the driver object
  40. RegistryPath - pointer to a unicode string representing the path
  41. to driver-specific key in the registry
  42. Return Value:
  43. NT status code
  44. --*/
  45. {
  46. NTSTATUS status = STATUS_SUCCESS;
  47. PUNICODE_STRING registryPath = &Globals.RegistryPath;
  48. Print (DBG_SS_TRACE, ("entering DriverEntry\n"));
  49. Print (DBG_SS_INFO, ("Keyboard to hid mapper\n"));
  50. RtlZeroMemory (&Globals, sizeof (GLOBALS));
  51. //
  52. // Need to ensure that the registry path is null-terminated.
  53. // Allocate pool to hold a null-terminated copy of the path.
  54. // Safe in paged pool since all registry routines execute at
  55. // PASSIVE_LEVEL.
  56. //
  57. registryPath->MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
  58. registryPath->Length = RegistryPath->Length;
  59. registryPath->Buffer = ExAllocatePool(
  60. PagedPool,
  61. registryPath->MaximumLength
  62. );
  63. if (!registryPath->Buffer) {
  64. Print (DBG_SS_ERROR,
  65. ("Initialize: Couldn't allocate pool for registry path."));
  66. status = STATUS_INSUFFICIENT_RESOURCES;
  67. goto DriverEntryReject;
  68. }
  69. RtlZeroMemory (registryPath->Buffer, registryPath->MaximumLength);
  70. RtlMoveMemory (registryPath->Buffer,
  71. RegistryPath->Buffer,
  72. RegistryPath->Length);
  73. //
  74. // Obtain configuration information for this driver.
  75. //
  76. status = KbdHid_GetRegistryParameters();
  77. if (!NT_SUCCESS (status)) {
  78. goto DriverEntryReject;
  79. }
  80. //
  81. // Set up the device driver entry points.
  82. //
  83. DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdHid_Create;
  84. DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdHid_Close;
  85. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]=KbdHid_IOCTL;
  86. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdHid_PassThrough;
  87. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = KbdHid_Flush;
  88. DriverObject->MajorFunction[IRP_MJ_PNP] = KbdHid_PnP;
  89. DriverObject->MajorFunction[IRP_MJ_POWER] = KbdHid_Power;
  90. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KbdHid_SystemControl;
  91. DriverObject->DriverUnload = KbdHid_Unload;
  92. DriverObject->DriverExtension->AddDevice = KbdHid_AddDevice;
  93. Print (DBG_SS_TRACE, ("exit DriverEntry (0x%x) \n", status));
  94. return status;
  95. DriverEntryReject:
  96. if (registryPath->Buffer) {
  97. ExFreePool (registryPath->Buffer);
  98. }
  99. return status;
  100. }
  101. NTSTATUS
  102. KbdHid_PassThrough (
  103. IN PDEVICE_OBJECT DeviceObject,
  104. IN PIRP Irp
  105. )
  106. /*++
  107. Routine Description:
  108. Pass the irp on through
  109. --*/
  110. {
  111. NTSTATUS status;
  112. PDEVICE_EXTENSION data;
  113. data = DeviceObject->DeviceExtension;
  114. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  115. if (!NT_SUCCESS (status)) {
  116. Irp->IoStatus.Status = status;
  117. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  118. return status;
  119. }
  120. IoSkipCurrentIrpStackLocation (Irp);
  121. status = IoCallDriver (data->TopOfStack, Irp);
  122. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  123. return status;
  124. }
  125. VOID
  126. KbdHid_Unload(
  127. IN PDRIVER_OBJECT Driver
  128. )
  129. /*++
  130. Routine Description:
  131. Free all the allocated resources, etc.
  132. Arguments:
  133. DriverObject - pointer to a driver object
  134. Return Value:
  135. None
  136. --*/
  137. {
  138. PAGED_CODE ();
  139. ASSERT (NULL == Driver->DeviceObject);
  140. Print (DBG_SS_INFO, ("Unload \n"));
  141. //
  142. // Free resources in device extension.
  143. //
  144. ExFreePool (Globals.RegistryPath.Buffer);
  145. return;
  146. }
  147. NTSTATUS
  148. KbdHid_Flush(
  149. IN PDEVICE_OBJECT DeviceObject,
  150. IN PIRP Irp
  151. )
  152. /*++
  153. Routine Description:
  154. Respond to flush requests from the mouse class driver. Currently does
  155. nothing but pass IRP down to next lower driver. This routine expects
  156. the current IRQL to be < DISPATCH_LEVEL.
  157. Arguments:
  158. DeviceObject - Pointer to the device object.
  159. Irp - Pointer to the request packet.
  160. Return Value:
  161. NT status code.
  162. --*/
  163. {
  164. PDEVICE_EXTENSION data;
  165. NTSTATUS status;
  166. PIO_STACK_LOCATION stack;
  167. Print (DBG_CALL_INFO, ("Flush \n"));
  168. TRAP();
  169. //
  170. // Get a pointer to the device extension.
  171. //
  172. data = DeviceObject->DeviceExtension;
  173. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  174. if (!NT_SUCCESS (status)) {
  175. Irp->IoStatus.Status = status;
  176. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  177. return status;
  178. }
  179. //
  180. // Send the flush request down to the HID class driver, one for each
  181. // of our mouse device context structures.
  182. //
  183. IoCopyCurrentIrpStackLocationToNext (Irp);
  184. stack = IoGetNextIrpStackLocation (Irp);
  185. stack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  186. stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE;
  187. //
  188. // Fire and forget
  189. //
  190. status = IoCallDriver (data->TopOfStack, Irp);
  191. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  192. return status;
  193. }
  194. NTSTATUS
  195. KbdHid_IOCTL (
  196. IN PDEVICE_OBJECT DeviceObject,
  197. IN PIRP Irp
  198. )
  199. /*++
  200. Routine Description:
  201. Respond to queries from the mouse class driver.
  202. The IOCTLs for DISABLE, ENABLE, and QUERY_ATTRIBUTES, expect the current
  203. IRQL to be < DISPATCH_LEVEL.
  204. Arguments:
  205. DeviceObject - Pointer to the device object.
  206. Irp - Pointer to the request packet.
  207. Return Value:
  208. NT status code.
  209. --*/
  210. {
  211. PIO_STACK_LOCATION stack;
  212. NTSTATUS status = STATUS_SUCCESS;
  213. PDEVICE_EXTENSION data;
  214. ULONG length;
  215. PKEYBOARD_INDICATOR_TRANSLATION translation;
  216. BOOLEAN completeIt = TRUE;
  217. data = DeviceObject->DeviceExtension;
  218. Irp->IoStatus.Information = 0;
  219. stack = IoGetCurrentIrpStackLocation (Irp);
  220. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  221. if (!NT_SUCCESS (status)) {
  222. Irp->IoStatus.Status = status;
  223. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  224. return status;
  225. }
  226. ASSERT (data->Started ||
  227. (IOCTL_INTERNAL_KEYBOARD_CONNECT ==
  228. stack->Parameters.DeviceIoControl.IoControlCode));
  229. switch (stack->Parameters.DeviceIoControl.IoControlCode) {
  230. case IOCTL_INTERNAL_KEYBOARD_CONNECT:
  231. //
  232. // Connect a keyboard class device driver to the port driver.
  233. //
  234. Print (DBG_IOCTL_TRACE, ("enter Connect \n"));
  235. //
  236. // Connect a mouse class device driver to the filter driver.
  237. // Only allow one connection.
  238. //
  239. if (NULL != data->ConnectData.ClassService) {
  240. Print (DBG_IOCTL_ERROR, ("ERROR: Multiple connects \n"));
  241. TRAP ();
  242. status = STATUS_SHARING_VIOLATION;
  243. break;
  244. } else if (stack->Parameters.DeviceIoControl.InputBufferLength <
  245. sizeof(CONNECT_DATA)) {
  246. Print (DBG_IOCTL_ERROR, ("ERROR: Invalid connect parameter size. \n"));
  247. TRAP ();
  248. status = STATUS_INVALID_PARAMETER;
  249. break;
  250. }
  251. //
  252. // Copy the connection parameters to the device extension.
  253. //
  254. data->ConnectData = *(PCONNECT_DATA)
  255. stack->Parameters.DeviceIoControl.Type3InputBuffer;
  256. status = STATUS_SUCCESS;
  257. break;
  258. case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
  259. //
  260. // Disconnect a keyboard class device driver from the port driver.
  261. //
  262. Print (DBG_IOCTL_TRACE, ("Disconnect \n"));
  263. TRAP ();
  264. //
  265. // Not implemented.
  266. //
  267. // To implement, code the following:
  268. // ---------------------------------
  269. // o ENSURE that we are NOT enabled (mouHidDeviceExt->EnableCount);
  270. // o If we are, then (a) return STATUS_UNSUCCESSFUL, or
  271. // (b) disable all devices immediately; see
  272. // DISABLE IOCTL call for necessary code.
  273. // o SYNCHRONIZE with the mouse read completion routine (must
  274. // protect the callback pointer from being dereferenced when
  275. // it becomes null). Note that no mechanism currently exists
  276. // for this.
  277. // o CLEAR the connection parameters in the device extension;
  278. // ie. mouHidDeviceExt->MouClassObject = NULL;
  279. // mouHidDeviceExt->MouClassCallback = NULL;
  280. // o RELEASE the synchronizing lock.
  281. // o RETURN STATUS_SUCCESS.
  282. //
  283. status = STATUS_NOT_IMPLEMENTED;
  284. break;
  285. case IOCTL_INTERNAL_KEYBOARD_ENABLE:
  286. //
  287. // Enable keyboard interrupts which really means start the ping pong
  288. // down to hid class.
  289. //
  290. Print (DBG_IOCTL_ERROR, ("ERROR: PnP => use create not enable! \n"));
  291. status = STATUS_NOT_SUPPORTED;
  292. break;
  293. case IOCTL_INTERNAL_KEYBOARD_DISABLE:
  294. //
  295. // Disable keyboard interrupts which really means stop the ping pongs
  296. // down to hid class.
  297. //
  298. Print (DBG_IOCTL_ERROR, ("ERROR: PnP => use close not Disable! \n"));
  299. status = STATUS_NOT_SUPPORTED;
  300. break;
  301. case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
  302. //
  303. // Query the keyboard attributes. First check for adequate buffer
  304. // length. Then, copy the keyboard attributes from the first device
  305. // context to the output buffer. [DAN]
  306. //
  307. Print (DBG_IOCTL_TRACE, ("Query Attributes \n"));
  308. if (stack->Parameters.DeviceIoControl.OutputBufferLength <
  309. sizeof(KEYBOARD_ATTRIBUTES)) {
  310. Print (DBG_IOCTL_ERROR,
  311. ("ERROR: Query Attributes buffer too small \n"));
  312. TRAP();
  313. status = STATUS_BUFFER_TOO_SMALL;
  314. } else {
  315. //
  316. // Copy the keyboard attributes to the buffer.
  317. //
  318. *(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
  319. data->Attributes;
  320. Irp->IoStatus.Information = sizeof (KEYBOARD_ATTRIBUTES);
  321. status = STATUS_SUCCESS;
  322. }
  323. break;
  324. case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
  325. //
  326. // Query the scan code to indicator-light mapping. Validate the
  327. // parameters, and copy the indicator mapping information from
  328. // the static translation list to the SystemBuffer.
  329. //
  330. Print (DBG_IOCTL_TRACE, ("Query Indicator Translation \n"));
  331. TRAP ();
  332. length = sizeof(KEYBOARD_INDICATOR_TRANSLATION)
  333. + (sizeof(INDICATOR_LIST)
  334. * (HID_KEYBOARD_NUMBER_OF_INDICATORS - 1));
  335. if (stack->Parameters.DeviceIoControl.OutputBufferLength < length) {
  336. status = STATUS_BUFFER_TOO_SMALL;
  337. break;
  338. }
  339. //
  340. // Copy the indicator mapping information to the system
  341. // buffer.
  342. //
  343. translation = ((PKEYBOARD_INDICATOR_TRANSLATION)
  344. Irp->AssociatedIrp.SystemBuffer);
  345. translation->NumberOfIndicatorKeys = HID_KEYBOARD_NUMBER_OF_INDICATORS;
  346. RtlMoveMemory(translation->IndicatorList,
  347. (PCHAR) IndicatorList,
  348. length - FIELD_OFFSET (KEYBOARD_INDICATOR_TRANSLATION,
  349. IndicatorList));
  350. Irp->IoStatus.Information = length;
  351. status = STATUS_SUCCESS;
  352. break;
  353. case IOCTL_KEYBOARD_QUERY_INDICATORS:
  354. //
  355. // Query the keyboard indicators. Validate the parameters, and
  356. // copy the indicator information from the device context to
  357. // the SystemBuffer. [DAN]
  358. //
  359. Print (DBG_IOCTL_TRACE, ("Query Indicators \n"));
  360. if (stack->Parameters.DeviceIoControl.OutputBufferLength <
  361. sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
  362. TRAP ();
  363. status = STATUS_BUFFER_TOO_SMALL;
  364. break;
  365. }
  366. //
  367. // Copy the keyboard indicators to the buffer.
  368. //
  369. //
  370. // Don't bother to synchronize access to the device context
  371. // KeyboardIndicators field while copying it. We don't care
  372. // if another process is setting the LEDs.
  373. //
  374. // Copy the keyboard indicators to the buffer.
  375. *(PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
  376. data->Indicators;
  377. Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
  378. status = STATUS_SUCCESS;
  379. break;
  380. case IOCTL_KEYBOARD_SET_INDICATORS:
  381. //
  382. // Set the keyboard indicators for all known device contexts. [DAN]
  383. //
  384. Print (DBG_IOCTL_TRACE, ("Set Indicators \n"));
  385. if (stack->Parameters.DeviceIoControl.InputBufferLength <
  386. sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
  387. Print (DBG_IOCTL_ERROR, ("ERROR: Set Indicators size!\n"));
  388. TRAP ();
  389. status = STATUS_INVALID_PARAMETER;
  390. break;
  391. }
  392. status = KbdHid_SetLedIndicators (
  393. data,
  394. (PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer,
  395. Irp);
  396. completeIt = FALSE;
  397. break;
  398. case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
  399. //
  400. // Query the current keyboard typematic rate and delay. Validate
  401. // the parameters, and copy the typematic information from the port
  402. // device extension to the SystemBuffer. [DAN]
  403. //
  404. Print (DBG_IOCTL_TRACE, ("Query Typematic \n"));
  405. if (stack->Parameters.DeviceIoControl.OutputBufferLength <
  406. sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
  407. Print (DBG_IOCTL_ERROR, ("ERROR: query typematic size!\n"));
  408. TRAP ();
  409. status = STATUS_BUFFER_TOO_SMALL;
  410. break;
  411. }
  412. //
  413. // Copy the keyboard typematic info to the buffer.
  414. //
  415. //
  416. // Don't bother to synchronize access to the device context
  417. // KeyboardTypematic field while copying it. We don't care
  418. // if another process is setting the typematic info.
  419. //
  420. *(PKEYBOARD_TYPEMATIC_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
  421. data->Typematic;
  422. Irp->IoStatus.Information = sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
  423. status = STATUS_SUCCESS;
  424. break;
  425. case IOCTL_KEYBOARD_SET_TYPEMATIC:
  426. //
  427. // Set the keyboard typematic rate and delay for all known device
  428. // contexts. [DAN]
  429. //
  430. Print (DBG_IOCTL_TRACE, ("Set Typematic \n"));
  431. if (stack->Parameters.DeviceIoControl.InputBufferLength <
  432. sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
  433. Print (DBG_IOCTL_ERROR, ("ERROR: Set Typematic size\n"));
  434. TRAP ();
  435. status = STATUS_INVALID_PARAMETER;
  436. break;
  437. }
  438. #define NewTypematic ((PKEYBOARD_TYPEMATIC_PARAMETERS) \
  439. Irp->AssociatedIrp.SystemBuffer)
  440. if ((NewTypematic->Rate == 0) && (NewTypematic->Delay == 0)) {
  441. break;
  442. }
  443. if ((NewTypematic->Rate < data->Attributes.KeyRepeatMinimum.Rate) ||
  444. (NewTypematic->Rate > data->Attributes.KeyRepeatMaximum.Rate) ||
  445. (NewTypematic->Delay < data->Attributes.KeyRepeatMinimum.Delay) ||
  446. (NewTypematic->Delay > data->Attributes.KeyRepeatMaximum.Delay)) {
  447. Print (DBG_IOCTL_ERROR, ("ERROR: Set Typematic range\n"));
  448. TRAP ();
  449. status = STATUS_INVALID_PARAMETER;
  450. break;
  451. }
  452. Print (DBG_IOCTL_INFO,
  453. ("Set Typematic Rate: %d Delay: %d\n",
  454. NewTypematic->Rate,
  455. NewTypematic->Delay));
  456. //
  457. // Don't bother to synchronize access to the device context
  458. // KeyboardTypematic field while copying it. We don't care
  459. // if another thread is reading the typematic info.
  460. //
  461. // Note the only danger here is in setting the 64-bit integer
  462. // "AutoRepeatDelay" in two non-atomic statements. However,
  463. // we are safe since we never set "HighPart" to anything but
  464. // -1.
  465. //
  466. data->Typematic = *NewTypematic;
  467. data->AutoRepeatRate = 1000 / NewTypematic->Rate; // ms
  468. data->AutoRepeatDelay.LowPart = -NewTypematic->Delay*10000; // 100ns
  469. data->AutoRepeatDelay.HighPart = -1;
  470. break;
  471. #undef NewTypematic
  472. default:
  473. Print (DBG_IOCTL_ERROR,
  474. ("ERROR: unknown IOCTL: 0x%x \n",
  475. stack->Parameters.DeviceIoControl.IoControlCode));
  476. TRAP ();
  477. status = STATUS_INVALID_DEVICE_REQUEST;
  478. break;
  479. }
  480. if (completeIt) {
  481. Irp->IoStatus.Status = status;
  482. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  483. }
  484. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  485. Print (DBG_IOCTL_TRACE, ("IOCTL exit (%x)\n", status));
  486. return status;
  487. }
  488. NTSTATUS
  489. KbdHid_GetRegistryParameters()
  490. /*++
  491. Routine Description:
  492. This routine retrieves this driver's parameters from the registry,
  493. including it's base device name.
  494. Return Value:
  495. --*/
  496. {
  497. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  498. UNICODE_STRING parametersPath = {0,0,0};
  499. PWSTR path = NULL;
  500. USHORT queriesPlus1 = 2;
  501. NTSTATUS status = STATUS_SUCCESS;
  502. PAGED_CODE ();
  503. parametersPath.Buffer = NULL;
  504. //
  505. // Registry path is already null-terminated, so just use it as a string.
  506. //
  507. path = Globals.RegistryPath.Buffer;
  508. //
  509. // Allocate the Rtl query table.
  510. //
  511. parameters = ExAllocatePool(
  512. PagedPool,
  513. sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlus1);
  514. if (!parameters) {
  515. Print (DBG_SS_ERROR,
  516. ("Initialize: Couldn't allocate table for Rtl query to parameters for %ws.",
  517. path));
  518. status = STATUS_UNSUCCESSFUL;
  519. goto KbdHid_GetRegistryParametersExit;
  520. }
  521. RtlZeroMemory(parameters, sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlus1);
  522. //
  523. // Form a path to this driver's Parameters subkey.
  524. //
  525. parametersPath.MaximumLength = Globals.RegistryPath.Length
  526. + sizeof(L"\\Parameters");
  527. parametersPath.Buffer = ExAllocatePool(PagedPool,
  528. parametersPath.MaximumLength);
  529. if (!parametersPath.Buffer) {
  530. Print (DBG_SS_ERROR,
  531. ("Initialize: Couldn't allocate string for path to parameters for %ws.",
  532. path));
  533. status = STATUS_INSUFFICIENT_RESOURCES;
  534. goto KbdHid_GetRegistryParametersExit;
  535. }
  536. //
  537. // Form the parameters path.
  538. //
  539. RtlZeroMemory(parametersPath.Buffer, parametersPath.MaximumLength);
  540. RtlAppendUnicodeToString(&parametersPath, path);
  541. RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
  542. #if 0 // We ignore the device name since this is now plug and play
  543. //
  544. // Gather all of the "user specified" information from
  545. // the registry.
  546. //
  547. parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  548. parameters[0].Name = L"KeyboardDeviceBaseName";
  549. parameters[0].EntryContext = DeviceName;
  550. parameters[0].DefaultType = REG_SZ;
  551. parameters[0].DefaultData = defaultUnicodeName.Buffer;
  552. parameters[0].DefaultLength = 0;
  553. status = RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE,
  554. parametersPath.Buffer,
  555. parameters,
  556. NULL,
  557. NULL);
  558. #endif
  559. if (!NT_SUCCESS(status)) {
  560. Print (DBG_SS_ERROR,
  561. ("ERROR: Initialize: RtlQueryRegistryValues (0x%x).",
  562. status));
  563. }
  564. KbdHid_GetRegistryParametersExit:
  565. //
  566. // Free the allocated memory before returning.
  567. //
  568. if (parametersPath.Buffer)
  569. ExFreePool(parametersPath.Buffer);
  570. if (parameters)
  571. ExFreePool(parameters);
  572. return status;
  573. }
  574. NTSTATUS
  575. KbdHid_SetLedIndicatorsComplete (
  576. IN PDEVICE_OBJECT DeviceObject,
  577. IN PIRP Irp,
  578. IN PVOID Context
  579. )
  580. {
  581. PIO_STACK_LOCATION stack;
  582. PDEVICE_EXTENSION data;
  583. stack = IoGetCurrentIrpStackLocation (Irp);
  584. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  585. if (Irp->PendingReturned) {
  586. IoMarkIrpPending (Irp);
  587. }
  588. IoFreeMdl (Irp->MdlAddress);
  589. Irp->MdlAddress = (PMDL) stack->Parameters.Others.Argument4;
  590. ExFreePool (Context);
  591. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  592. return STATUS_SUCCESS;
  593. }
  594. NTSTATUS
  595. KbdHid_SetLedIndicators (
  596. PDEVICE_EXTENSION Data,
  597. PKEYBOARD_INDICATOR_PARAMETERS NewIndicators,
  598. PIRP Irp
  599. )
  600. /*++
  601. Routine Description:
  602. Set the LED indicators of the supplied keyboard device context.
  603. Arguments:
  604. Data - Pointer to the driver device extension.
  605. Parameters - Pointer to the keyboard indicators to set/unset.
  606. Irp - An Irp to use for setting these parameters
  607. Return Value:
  608. STATUS_SUCCESS on success, STATUS_PENDING if operation is still pending,
  609. or otherwise an NTSTATUS error code on an error.
  610. --*/
  611. {
  612. PIO_STACK_LOCATION nextStack;
  613. PIO_STACK_LOCATION curStack;
  614. NTSTATUS status = STATUS_SUCCESS;
  615. USAGE usageBuffer [4]; // only 4 known usages hardcoded below
  616. ULONG usageBufferLen = 0;
  617. PCHAR outputBuffer = 0;
  618. PMDL outputMdl = 0;
  619. PHID_EXTENSION hid = Data->HidExtension;
  620. status = IoAcquireRemoveLock (&Data->RemoveLock, Irp);
  621. if (!NT_SUCCESS (status)) {
  622. Irp->IoStatus.Status = status;
  623. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  624. return status;
  625. }
  626. if (0 == hid->Caps.OutputReportByteLength) {
  627. //
  628. // This device has no LEDs, now while that is strange it is not really
  629. // an error. HID keyboards can have any LEDs that they want, including
  630. // none.
  631. //
  632. status = STATUS_SUCCESS;
  633. goto KbdHid_SetIndicatorsReject;
  634. }
  635. outputBuffer = ExAllocatePool (NonPagedPool,
  636. hid->Caps.OutputReportByteLength);
  637. if (NULL == outputBuffer) {
  638. status = STATUS_INSUFFICIENT_RESOURCES;
  639. goto KbdHid_SetIndicatorsReject;
  640. }
  641. outputMdl = IoAllocateMdl (outputBuffer, // The virtual address
  642. hid->Caps.OutputReportByteLength, // length of the MDL
  643. FALSE, // No associated IRP -> not secondary
  644. FALSE, // No quota charge
  645. 0); // No associated IRP
  646. if (NULL == outputMdl) {
  647. status = STATUS_INSUFFICIENT_RESOURCES;
  648. goto KbdHid_SetIndicatorsReject;
  649. }
  650. MmBuildMdlForNonPagedPool (outputMdl); // Build this MDL.
  651. //
  652. // Zero the output report packet.
  653. //
  654. RtlZeroMemory(outputBuffer, hid->Caps.OutputReportByteLength);
  655. //
  656. // Setup the usage list of LEDs.
  657. //
  658. if (NewIndicators->LedFlags & KEYBOARD_KANA_LOCK_ON) {
  659. usageBuffer[usageBufferLen++] = HID_USAGE_LED_KANA;
  660. }
  661. if (NewIndicators->LedFlags & KEYBOARD_CAPS_LOCK_ON) {
  662. usageBuffer[usageBufferLen++] = HID_USAGE_LED_CAPS_LOCK;
  663. }
  664. if (NewIndicators->LedFlags & KEYBOARD_NUM_LOCK_ON) {
  665. usageBuffer[usageBufferLen++] = HID_USAGE_LED_NUM_LOCK;
  666. }
  667. if (NewIndicators->LedFlags & KEYBOARD_SCROLL_LOCK_ON) {
  668. usageBuffer[usageBufferLen++] = HID_USAGE_LED_SCROLL_LOCK;
  669. }
  670. if (usageBufferLen == 0) {
  671. ASSERT((NewIndicators->LedFlags & (KEYBOARD_KANA_LOCK_ON |
  672. KEYBOARD_CAPS_LOCK_ON |
  673. KEYBOARD_NUM_LOCK_ON |
  674. KEYBOARD_SCROLL_LOCK_ON)) == 0);
  675. //
  676. // In order to fix led setting on a multiple collection keyboard, we
  677. // have to initialize the output report to make sure we get the correct
  678. // collection id. This is for the case where we are going from one
  679. // led on to all leds off. If not initialized, we'll get a report with no
  680. // collection id at the beginning.
  681. //
  682. usageBuffer[0] = HID_USAGE_LED_SCROLL_LOCK; // arbitirary led
  683. usageBufferLen = 1;
  684. HidP_UnsetUsages(HidP_Output,
  685. HID_USAGE_PAGE_LED,
  686. 0,
  687. usageBuffer,
  688. &usageBufferLen,
  689. hid->Ppd,
  690. outputBuffer,
  691. hid->Caps.OutputReportByteLength);
  692. }
  693. else {
  694. //
  695. // Set the usages in the output report.
  696. //
  697. HidP_SetUsages(HidP_Output,
  698. HID_USAGE_PAGE_LED,
  699. 0,
  700. usageBuffer,
  701. &usageBufferLen,
  702. hid->Ppd,
  703. outputBuffer,
  704. hid->Caps.OutputReportByteLength);
  705. }
  706. //
  707. // Obtain a pointer to the next IRP stack location.
  708. //
  709. nextStack = IoGetNextIrpStackLocation (Irp);
  710. curStack = IoGetCurrentIrpStackLocation (Irp);
  711. ASSERT(nextStack != NULL);
  712. //
  713. // Set up our write to HIDCLASS.
  714. //
  715. curStack->Parameters.Others.Argument4 = (PVOID) Irp->MdlAddress;
  716. Irp->MdlAddress = outputMdl;
  717. IoCopyCurrentIrpStackLocationToNext (Irp);
  718. nextStack->MajorFunction = IRP_MJ_WRITE;
  719. nextStack->Parameters.Write.Length = hid->Caps.OutputReportByteLength;
  720. nextStack->Parameters.Write.Key = 0;
  721. nextStack->Parameters.Write.ByteOffset.QuadPart = 0;
  722. //
  723. // Hook a completion routine to be called when the request completes.
  724. //
  725. IoSetCompletionRoutine (Irp,
  726. KbdHid_SetLedIndicatorsComplete,
  727. outputBuffer,
  728. TRUE,
  729. TRUE,
  730. TRUE);
  731. //
  732. // Call the next driver.
  733. //
  734. status = IoCallDriver(Data->TopOfStack, Irp);
  735. //
  736. // Return status.
  737. //
  738. return status;
  739. KbdHid_SetIndicatorsReject:
  740. Irp->IoStatus.Status = status;
  741. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  742. if (NULL != outputBuffer) {
  743. ExFreePool (outputBuffer);
  744. }
  745. if (NULL != outputMdl) {
  746. IoFreeMdl (outputMdl);
  747. }
  748. IoReleaseRemoveLock (&Data->RemoveLock, Irp);
  749. return status;
  750. }
  751. VOID
  752. KbdHid_UpdateRegistryProblemFlags(
  753. IN PDEVICE_EXTENSION Data
  754. )
  755. /*++
  756. [DAN]
  757. Routine Description:
  758. This routine stores the OR'd ProblemFlags value into the registry.
  759. It will queue the write to the registry if this routine is not run
  760. at PASSIVE_LEVEL.
  761. Arguments:
  762. KbdHidDeviceExt - HID Keyboard Filter Driver device extension.
  763. Return Value:
  764. None.
  765. --*/
  766. {
  767. PIO_WORKITEM item;
  768. NTSTATUS status;
  769. status = IoAcquireRemoveLock (&Data->RemoveLock, KbdHid_UpdateRegistryProblemFlags);
  770. if (!NT_SUCCESS (status)) {
  771. //
  772. // Device has gone away, just silently exit
  773. //
  774. return;
  775. }
  776. item = IoAllocateWorkItem (Data->Self);
  777. if (item) {
  778. if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
  779. //
  780. // We are safely at PASSIVE_LEVEL, call callback directly to perform
  781. // this operation immediately.
  782. //
  783. KbdHid_UpdateRegistryProblemFlagsCallback (Data->Self, item);
  784. } else {
  785. //
  786. // We are not at PASSIVE_LEVEL, so queue a workitem to handle this
  787. // at a later time.
  788. //
  789. IoQueueWorkItem (item,
  790. KbdHid_UpdateRegistryProblemFlagsCallback,
  791. DelayedWorkQueue,
  792. item);
  793. }
  794. }
  795. else {
  796. //
  797. // Match the Acquire at the top of the function
  798. //
  799. IoReleaseRemoveLock (&Data->RemoveLock, KbdHid_UpdateRegistryProblemFlags);
  800. }
  801. }
  802. VOID
  803. KbdHid_UpdateRegistryProblemFlagsCallback (
  804. IN PDEVICE_OBJECT DeviceObject,
  805. IN PIO_WORKITEM Item
  806. )
  807. /*++
  808. [DAN]
  809. Routine Description:
  810. This routine stores the OR'd ProblemFlags value into the registry. This
  811. routine must execute at PASSIVE_LEVEL.
  812. --*/
  813. {
  814. NTSTATUS status;
  815. PDEVICE_EXTENSION data;
  816. HANDLE hDevNode;
  817. UNICODE_STRING strProblemFlags;
  818. PAGED_CODE ();
  819. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  820. status = IoOpenDeviceRegistryKey (data->PDO,
  821. PLUGPLAY_REGKEY_DEVICE,
  822. STANDARD_RIGHTS_ALL,
  823. &hDevNode);
  824. if (NT_SUCCESS(status)) {
  825. RtlInitUnicodeString (&strProblemFlags, L"ProblemFlags");
  826. ZwSetValueKey (hDevNode,
  827. &strProblemFlags,
  828. 0,
  829. REG_DWORD,
  830. &data->ProblemFlags,
  831. sizeof(data->ProblemFlags));
  832. ZwClose(hDevNode);
  833. }
  834. else {
  835. Print(DBG_SS_ERROR,
  836. ("UpdateRegistryProblemFlags: failed (%x).\n", status));
  837. }
  838. IoReleaseRemoveLock(&data->RemoveLock, KbdHid_UpdateRegistryProblemFlags);
  839. IoFreeWorkItem(Item);
  840. }
  841. VOID
  842. KbdHid_LogError(
  843. IN PDRIVER_OBJECT DriverObject,
  844. IN NTSTATUS ErrorCode,
  845. IN PWSTR ErrorInsertionString OPTIONAL)
  846. /*++
  847. [DAN]
  848. Routine Description:
  849. Logs an error to the system.
  850. Arguments:
  851. DriverObject - Pointer to driver object reporting the error.
  852. ErrorCode - Indicates the type of error, system or driver-defined.
  853. ErrorInsertionString - Null-terminated Unicode string inserted into error
  854. description, as defined by error code. Must be no
  855. no longer than 50 characters.
  856. Return Value:
  857. None.
  858. --*/
  859. {
  860. ULONG errorInsertionStringSize = 0;
  861. PIO_ERROR_LOG_PACKET errorLogEntry;
  862. ULONG errorLogEntrySize; // [including null]
  863. PWCHAR pWChar;
  864. if (ErrorInsertionString) {
  865. for (pWChar = ErrorInsertionString; *pWChar; pWChar++) {
  866. errorInsertionStringSize += sizeof(WCHAR);
  867. }
  868. errorInsertionStringSize += sizeof(UNICODE_NULL);
  869. }
  870. errorLogEntrySize = sizeof(IO_ERROR_LOG_PACKET) + errorInsertionStringSize;
  871. //
  872. // Log an error.
  873. //
  874. if (errorLogEntrySize <= ERROR_LOG_MAXIMUM_SIZE) {
  875. errorLogEntry = IoAllocateErrorLogEntry(DriverObject,
  876. (UCHAR)errorLogEntrySize);
  877. if (errorLogEntry != NULL) {
  878. RtlZeroMemory(errorLogEntry, errorLogEntrySize);
  879. errorLogEntry->ErrorCode = ErrorCode;
  880. errorLogEntry->FinalStatus = ErrorCode;
  881. errorLogEntry->NumberOfStrings = (ErrorInsertionString) ? 1 : 0;
  882. if (ErrorInsertionString) {
  883. RtlCopyMemory(errorLogEntry->DumpData,
  884. ErrorInsertionString,
  885. errorInsertionStringSize);
  886. }
  887. IoWriteErrorLogEntry(errorLogEntry);
  888. }
  889. }
  890. return;
  891. }