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.

804 lines
26 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. read.c
  5. Abstract:
  6. This module contains the code for translating HID reports to keyboard
  7. reports.
  8. Environment:
  9. Kernel & user mode
  10. Revision History:
  11. Nov-96 : Created by Kenneth D. Ray
  12. --*/
  13. #include <stdio.h>
  14. #include "kbdhid.h"
  15. NTSYSAPI
  16. VOID
  17. NTAPI
  18. DbgBreakPointWithStatus(
  19. IN ULONG Status
  20. );
  21. #define KbdHid_RestartTimer(HidDevice) \
  22. KeSetTimerEx (&(HidDevice)->AutoRepeatTimer, \
  23. (HidDevice)->AutoRepeatDelay, \
  24. (HidDevice)->AutoRepeatRate, \
  25. &(HidDevice)->AutoRepeatDPC);
  26. #define KbdHid_CancelTimer(HidDevice) \
  27. KeCancelTimer (&(HidDevice)->AutoRepeatTimer);
  28. #define KEYBOARD_INITIATED_KERNEL_EVENT FALSE
  29. #if KEYBOARD_INITIATED_KERNEL_EVENT
  30. typedef enum _HARDWARE_PROFILE_BUS_TYPE {
  31. HardwareProfileBusTypeACPI
  32. } HARDWARE_PROFILE_BUS_TYPE, * PHARDWARE_PROFILE_BUS_TYPE;
  33. // typedef struct _KBDHID_KERNEL_EVENT_WORK_ITEM {
  34. // PVOID Data;
  35. // WORK_QUEUE_ITEM Item;
  36. // } KBDHID_KERNEL_EVENT_WORK_ITEM, * PKBDHID_KERNEL_EVENT_WORK_ITEM;
  37. NTSTATUS
  38. IopExecuteHardwareProfileChange(
  39. IN HARDWARE_PROFILE_BUS_TYPE Bus,
  40. IN PWCHAR * ProfileSerialNumbers,
  41. IN ULONG SerialNumbersCount,
  42. OUT PHANDLE NewProfile,
  43. OUT PBOOLEAN ProfileChanged
  44. );
  45. KSPIN_LOCK KbdHid_KernelEventSpin;
  46. ULONG KbdHid_KernelEventState = -1;
  47. VOID
  48. KbdHid_KernelEvent (
  49. IN PDEVICE_OBJECT DeviceObject,
  50. IN PIO_WORKITEM Item
  51. )
  52. {
  53. KIRQL oldIrql;
  54. WCHAR docked[] = L"1234\0";
  55. WCHAR undocked[] = L"\0";
  56. PWCHAR strings [2] = {docked, undocked};
  57. HANDLE handle;
  58. BOOLEAN changed;
  59. UNREFERENCED_PARAMETER (DeviceObject);
  60. if (-1 == KbdHid_KernelEventState) {
  61. KeInitializeSpinLock (&KbdHid_KernelEventSpin);
  62. KbdHid_KernelEventState = 0;
  63. }
  64. Beginning:
  65. switch (KbdHid_KernelEventState++) {
  66. case 0:
  67. IopExecuteHardwareProfileChange (HardwareProfileBusTypeACPI,
  68. strings,
  69. 1,
  70. &handle,
  71. &changed);
  72. break;
  73. case 1:
  74. IopExecuteHardwareProfileChange (HardwareProfileBusTypeACPI,
  75. strings + 1,
  76. 1,
  77. &handle,
  78. &changed);
  79. break;
  80. default:
  81. KbdHid_KernelEventState = 0;
  82. goto Beginning;
  83. }
  84. IoFreeWorkItem (Item);
  85. }
  86. #endif
  87. NTSTATUS
  88. KbdHid_ReadComplete (
  89. PDEVICE_OBJECT DeviceObject,
  90. PIRP Irp,
  91. IN PDEVICE_EXTENSION Data // (PVOID Context)
  92. )
  93. /*++
  94. Routine Description:
  95. The read Completetion routine.
  96. The read came in.
  97. (a) Find the Buttons (usages) that are currently down
  98. (b) Diff to find the buttons that went up, and those that went down.
  99. (c) Convert the ups and downs to i8042 scan codes.
  100. (d) Swap the Previous Usage List and the Current Usage List.
  101. (d) If there are keys still down then we need to:
  102. (1) send another read to HidClass to wait for those keys to come back up
  103. (2) reset the autotimer.
  104. --*/
  105. {
  106. ULONG newUsages;
  107. NTSTATUS status;
  108. PUSAGE_AND_PAGE usageList;
  109. PHID_EXTENSION hid;
  110. KIRQL oldirq;
  111. ULONG i;
  112. PUSAGE_AND_PAGE usage;
  113. BOOLEAN rollover;
  114. BOOLEAN startRead;
  115. rollover = FALSE;
  116. status = Irp->IoStatus.Status;
  117. hid = Data->HidExtension;
  118. //
  119. // If ReadInterlock is == START_READ, this func has been completed
  120. // synchronously. Place IMMEDIATE_READ into the interlock to signify this
  121. // situation; this will notify StartRead to loop when IoCallDriver returns.
  122. // Otherwise, we have been completed async and it is safe to call StartRead()
  123. //
  124. startRead =
  125. (KBDHID_START_READ !=
  126. InterlockedCompareExchange(&Data->ReadInterlock,
  127. KBDHID_IMMEDIATE_READ,
  128. KBDHID_START_READ));
  129. if (Data->EnableCount == 0) {
  130. goto SetEventAndBreak;
  131. }
  132. switch (status) {
  133. case STATUS_SUCCESS:
  134. //
  135. // Hopefully this means that the data found in the buffer of the
  136. // context contains a single hid packet read from the device.
  137. //
  138. ASSERT (Irp->IoStatus.Information == hid->Caps.InputReportByteLength);
  139. //
  140. // Find the current usages
  141. //
  142. newUsages = hid->MaxUsages;
  143. status = HidP_GetUsagesEx (
  144. HidP_Input,
  145. 0, // Not interested in link collections
  146. hid->CurrentUsageList,
  147. &newUsages,
  148. hid->Ppd,
  149. hid->InputBuffer,
  150. hid->Caps.InputReportByteLength);
  151. //
  152. // If the SysRq button is the only button down then
  153. // break. This is to behave like the i8042prt driver, we clearly
  154. // have far less of an advantage since we have gone through MANY
  155. // drivers before we received the data, but let's check it anyway.
  156. //
  157. if ((1 == newUsages) &&
  158. (HID_USAGE_PAGE_KEYBOARD == hid->CurrentUsageList->UsagePage) &&
  159. (HID_USAGE_KEYBOARD_PRINT_SCREEN == hid->CurrentUsageList->Usage) &&
  160. (**((PUCHAR *)&KdDebuggerEnabled))) {
  161. DbgBreakPointWithStatus(DBG_STATUS_SYSRQ);
  162. }
  163. #if KEYBOARD_INITIATED_KERNEL_EVENT
  164. if ((1 == newUsages) &&
  165. hid->ModifierState.ScollLock &
  166. (HID_USAGE_PAGE_KEYBOARD == hid->CurrentUsageList->UsagePage) &&
  167. (HID_USAGE_KEYBOARD_F12 == hid->CurrentUsageList->Usage)) {
  168. PIO_WORKITEM item;
  169. item = IoAllocateWorkItem (Data->Self);
  170. if (NULL != item) {
  171. // item->Data = NULL;
  172. // ExInitializeWorkItem (&item->Item, KbdHid_KernelEvent, item);
  173. // ExQueueWorkItem (&item->Item, DelayedWorkQueue);
  174. IoQueueWorkItem (item,
  175. KbdHid_KernelEvent,
  176. DelayedWorkQueue,
  177. item);
  178. }
  179. }
  180. #endif
  181. for (i = 0, usage = hid->CurrentUsageList;
  182. i < hid->MaxUsages;
  183. i++, usage++) {
  184. if (HID_USAGE_PAGE_KEYBOARD != hid->CurrentUsageList->UsagePage) {
  185. continue;
  186. }
  187. //
  188. // If this is a broken keyboard, map the usage
  189. // to the correct value.
  190. //
  191. usage->Usage = MapUsage(Data, usage->Usage);
  192. //
  193. // If this packet contains the Rollover key then the packet should be
  194. // ignored.
  195. //
  196. if (HID_USAGE_KEYBOARD_ROLLOVER == usage->Usage) {
  197. rollover = TRUE;
  198. break;
  199. }
  200. if (0 == usage->Usage) {
  201. break;
  202. }
  203. }
  204. if (!rollover) {
  205. USAGE_AND_PAGE zero = {0,0};
  206. //
  207. // First, check whether the keyboard is repeating keys in hardware.
  208. // If it is, then we'll ignore this package. To do this, diff the
  209. // current and the previous usages. If the resulting make and break
  210. // usage lists have nothing in them, then ignore this package.
  211. //
  212. HidP_UsageAndPageListDifference (hid->PreviousUsageList,
  213. hid->CurrentUsageList,
  214. hid->ScrapBreakUsageList,
  215. hid->OldMakeUsageList,
  216. hid->MaxUsages);
  217. if (HidP_IsSameUsageAndPage(hid->OldMakeUsageList[0], zero) &&
  218. HidP_IsSameUsageAndPage(hid->ScrapBreakUsageList[0], zero)) {
  219. //
  220. // No new keys. The keyboard is trying
  221. // to perform repeating in hardware.
  222. //
  223. goto Kbdhid_ReadComplete_Done;
  224. }
  225. //
  226. // Save the make usages temporarily
  227. //
  228. RtlCopyMemory(hid->OldMakeUsageList,
  229. hid->MakeUsageList,
  230. hid->MaxUsages * sizeof(USAGE_AND_PAGE));
  231. //
  232. // Diff the current and the previous usages
  233. //
  234. status = HidP_UsageAndPageListDifference (hid->PreviousUsageList,
  235. hid->CurrentUsageList,
  236. hid->BreakUsageList,
  237. hid->MakeUsageList,
  238. hid->MaxUsages);
  239. //
  240. // Convert the ups into scan codes and add to the ring buffer.
  241. // Convert the downs.
  242. //
  243. HidP_TranslateUsageAndPagesToI8042ScanCodes (hid->BreakUsageList,
  244. hid->MaxUsages,
  245. HidP_Keyboard_Break,
  246. &hid->ModifierState,
  247. KbdHid_InsertCodesIntoQueue,
  248. Data);
  249. if (!HidP_IsSameUsageAndPage(hid->CurrentUsageList[0], zero) &&
  250. HidP_IsSameUsageAndPage(hid->MakeUsageList[0], zero)) {
  251. //
  252. // There are no new downs, but there may be some old ones
  253. // kicking around. We don't want to get rid of keys that are
  254. // still repeating.
  255. //
  256. HidP_UsageAndPageListDifference (hid->BreakUsageList,
  257. hid->OldMakeUsageList,
  258. hid->ScrapBreakUsageList,
  259. hid->MakeUsageList,
  260. hid->MaxUsages);
  261. } else {
  262. //
  263. // Only refresh the downs when there are new ones to add
  264. //
  265. HidP_TranslateUsageAndPagesToI8042ScanCodes (hid->MakeUsageList,
  266. hid->MaxUsages,
  267. HidP_Keyboard_Make,
  268. &hid->ModifierState,
  269. KbdHid_InsertCodesIntoQueue,
  270. Data);
  271. }
  272. //
  273. // Swap previous with next.
  274. //
  275. usageList = hid->PreviousUsageList;
  276. hid->PreviousUsageList = hid->CurrentUsageList;
  277. hid->CurrentUsageList = usageList;
  278. #if KEYBOARD_HW_CHATTERY_FIX
  279. //
  280. // [DAN]
  281. // Chattery Keyboard H/W Workaround -
  282. // Only call StartRead() if this was a meaningful packet (ie. it
  283. // had a make or a break), otherwise "schedule" the StartRead for
  284. // a later time. Notify tester that this is a chattery keyboard.
  285. //
  286. if ((0 < newUsages) &&
  287. (0 == hid->BreakUsageList->Usage) &&
  288. (0 == hid->MakeUsageList->Usage)) {
  289. if (FALSE == Data->InitiateStartReadUserNotified) {
  290. Data->InitiateStartReadUserNotified = TRUE;
  291. DbgPrint("*****\n***** "
  292. "CHATTERY KEYBOARD : "
  293. "Keyboard is sending useless reports. "
  294. "Tell 'em to fix it.\n*****\n"
  295. );
  296. Data->ProblemFlags |= PROBLEM_CHATTERY_KEYBOARD;
  297. //
  298. // Update ProblemFlags value in registry and log the problem.
  299. //
  300. KbdHid_UpdateRegistryProblemFlags (Data);
  301. KbdHid_LogError(Data->Self->DriverObject,
  302. KBDHID_CHATTERY_KEYBOARD,
  303. NULL);
  304. }
  305. if (!Data->ShuttingDown &&
  306. startRead) {
  307. KeSetTimerEx(&Data->InitiateStartReadTimer,
  308. Data->InitiateStartReadDelay,
  309. 0,
  310. &Data->InitiateStartReadDPC);
  311. }
  312. startRead = FALSE;
  313. IoReleaseRemoveLock (&Data->RemoveLock, Data->ReadIrp);
  314. KbdHid_CancelTimer (Data);
  315. break;
  316. } else
  317. #endif
  318. if (0 < newUsages) {
  319. //
  320. // Reset the auto repeat timer.
  321. //
  322. KbdHid_RestartTimer (Data);
  323. } else {
  324. KbdHid_CancelTimer (Data);
  325. }
  326. }
  327. //
  328. // Get the next packet from Hid Class.
  329. // Hid class has its own buffer so we do not need ping pong irps.
  330. //
  331. break;
  332. case STATUS_PRIVILEGE_NOT_HELD:
  333. //
  334. // The create didn't succeed
  335. //
  336. case STATUS_CANCELLED:
  337. //
  338. // The read IRP was cancelled. Do not send any more read IRPs.
  339. //
  340. case STATUS_DELETE_PENDING:
  341. case STATUS_DEVICE_NOT_CONNECTED:
  342. //
  343. // The HID class device object is being deleted. We will soon
  344. // receive Plug 'n Play notification of this device's removal,
  345. // if we have not received it already.
  346. //
  347. SetEventAndBreak:
  348. if (startRead) {
  349. KeSetEvent (&Data->ReadCompleteEvent, 0, FALSE);
  350. IoReleaseRemoveLock (&Data->RemoveLock, Data->ReadIrp);
  351. startRead = FALSE;
  352. }
  353. break;
  354. default:
  355. //
  356. // We don't expect any other error codes.
  357. //
  358. TRAP();
  359. }
  360. Kbdhid_ReadComplete_Done:
  361. //
  362. // Initiate the next read request to the HID class driver.
  363. //
  364. if (startRead) {
  365. Print(DBG_READ_TRACE, ("calling StartRead directly\n"));
  366. KbdHid_StartRead (Data);
  367. } else {
  368. Print(DBG_READ_TRACE, ("StartRead will loop\n"));
  369. }
  370. return STATUS_MORE_PROCESSING_REQUIRED;
  371. #undef hidDevice
  372. }
  373. BOOLEAN
  374. KbdHid_InsertCodesIntoQueue (
  375. PDEVICE_EXTENSION Data,
  376. PCHAR NewCodes,
  377. ULONG Length
  378. )
  379. /*++
  380. [DAN]
  381. RoutineDescription:
  382. Given a pointer to some i8042 Codes and the length of those codes.
  383. send those codes to KbdClass via KbdClassCallback.
  384. This routine is transmits the supplied I8042 scancodes to the keyboard
  385. class driver via a callback routine. This function was supplied in our
  386. call to HidP_TranslateUsagesToI8042ScanCodes.
  387. Arguments:
  388. HidDevice - Pointer to the device context.
  389. NewCodes - Pointer to the I8042 scancodes.
  390. Length - Number of I8042 scancodes.
  391. Return Value:
  392. Always returns TRUE.
  393. --*/
  394. {
  395. KIRQL oldIrql;
  396. ULONG index;
  397. PKEYBOARD_INPUT_DATA input;
  398. PHID_EXTENSION hid;
  399. ULONG inputDataConsumed;
  400. UCHAR scanCode;
  401. KEYBOARD_SCAN_STATE * scanState;
  402. hid = Data->HidExtension;
  403. input = &Data->InputData;
  404. scanState = &Data->ScanState;
  405. for (index = 0; index < Length; index++, NewCodes++) {
  406. scanCode = *NewCodes;
  407. if (scanCode == (UCHAR) 0xFF) {
  408. Print (DBG_READ_TRACE, ("OVERRUN\n"));
  409. input->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
  410. input->Flags = 0;
  411. *scanState = Normal;
  412. } else {
  413. switch (*scanState) {
  414. case Normal:
  415. if (scanCode == (UCHAR) 0xE0) {
  416. input->Flags |= KEY_E0;
  417. *scanState = GotE0;
  418. break;
  419. } else if (scanCode == (UCHAR) 0xE1) {
  420. input->Flags |= KEY_E1;
  421. *scanState = GotE1;
  422. break;
  423. }
  424. //
  425. // Fall through to the GotE0/GotE1 case for the rest of the
  426. // Normal case.
  427. //
  428. case GotE0:
  429. case GotE1:
  430. if (scanCode > 0x7F) {
  431. //
  432. // Got a break code. Strip the high bit off
  433. // to get the associated make code and set flags
  434. // to indicate a break code.
  435. //
  436. input->MakeCode = scanCode & 0x7F;
  437. input->Flags |= KEY_BREAK;
  438. } else {
  439. //
  440. // Got a make code.
  441. //
  442. input->MakeCode = scanCode;
  443. }
  444. //
  445. // Reset the state to Normal.
  446. //
  447. *scanState = Normal;
  448. break;
  449. default:
  450. ASSERT(FALSE);
  451. break;
  452. }
  453. //
  454. // In the Normal state, if the keyboard device is enabled,
  455. // add the data to the InputData queue and queue the ISR DPC.
  456. //
  457. if (*scanState == Normal) {
  458. if (Data->EnableCount) {
  459. //
  460. // Leave the remaining mouse input data fields as they were
  461. // initialized (on the device's creation). This includes:
  462. // o UnitID
  463. // o ExtraInformation
  464. //
  465. // Now send the data up to the keyboard class driver via
  466. // our callback.
  467. //
  468. //
  469. // Synchronization issue: it's not a big deal if .Enabled
  470. // is set FALSE after the condition above, but before the
  471. // callback below, so long as the .KbdClassCallback field
  472. // is not nulled. This is guaranteed since the disconnect
  473. // IOCTL is not implemented yet.
  474. //
  475. // Keyboard class callback assumes we are running at
  476. // DISPATCH level, however this IoCompletion routine
  477. // can be running <= DISPATCH. Raise the IRQL before
  478. // calling the callback. [13.1]
  479. //
  480. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  481. //
  482. // Call the callback.
  483. //
  484. (*(PSERVICE_CALLBACK_ROUTINE)
  485. Data->ConnectData.ClassService) (
  486. Data->ConnectData.ClassDeviceObject,
  487. input,
  488. input + 1, // (one data element)
  489. &inputDataConsumed);
  490. //
  491. // Restore the previous IRQL right away.
  492. //
  493. KeLowerIrql(oldIrql);
  494. ASSERT (1 == inputDataConsumed);
  495. }
  496. //
  497. // Reset the input state.
  498. //
  499. input->Flags = 0;
  500. }
  501. }
  502. }
  503. return TRUE;
  504. }
  505. NTSTATUS
  506. KbdHid_StartRead (
  507. PDEVICE_EXTENSION Data
  508. )
  509. /*++
  510. Routine Description:
  511. Initiates a read to the HID class driver.
  512. Note that the routine does not verify that the device context is in the
  513. OperationPending state, but simply assumes it.
  514. Note the IoCount must be incremented before entering into this read loop.
  515. Arguments:
  516. HidDeviceContext - Device context structure describing the HID device.
  517. Return Value:
  518. NTSTATUS result code from IoCallDriver().
  519. --*/
  520. {
  521. PIRP irp = Data->ReadIrp;
  522. NTSTATUS status = irp->IoStatus.Status;
  523. PIO_STACK_LOCATION stack;
  524. PHID_EXTENSION hid;
  525. LONG oldInterlock;
  526. Print (DBG_READ_TRACE, ("Start Read: Ente\n"));
  527. hid = Data->HidExtension;
  528. //
  529. // start this read.
  530. //
  531. while (1) {
  532. oldInterlock = InterlockedExchange(&Data->ReadInterlock,
  533. KBDHID_START_READ);
  534. //
  535. // END_READ should be the only value here!!! If not, the state machine
  536. // of the interlock has been broken
  537. //
  538. ASSERT(oldInterlock == KBDHID_END_READ);
  539. if (NT_SUCCESS(status)) {
  540. //
  541. // Set the stack location for the Hid stack.
  542. // Remember to get the file pointer correct.
  543. // NOTE: we do not have any of the cool thread stuff set.
  544. // therefore we need to make sure that we cut this IRP off
  545. // at the knees when it returns. (STATUS_MORE_PROCESSING_REQUIRED)
  546. //
  547. // Note also that Hid class does direct IO.
  548. //
  549. IoReuseIrp (irp, STATUS_SUCCESS);
  550. irp->MdlAddress = hid->InputMdl;
  551. ASSERT (NULL != Data->ReadFile);
  552. stack = IoGetNextIrpStackLocation (irp);
  553. stack->Parameters.Read.Length = hid->Caps.InputReportByteLength;
  554. stack->Parameters.Read.Key = 0;
  555. stack->Parameters.Read.ByteOffset.QuadPart = 0;
  556. stack->MajorFunction = IRP_MJ_READ;
  557. stack->FileObject = Data->ReadFile;
  558. //
  559. // Hook a completion routine for when the device completes.
  560. //
  561. IoSetCompletionRoutine (irp,
  562. KbdHid_ReadComplete,
  563. Data,
  564. TRUE,
  565. TRUE,
  566. TRUE);
  567. //
  568. // Unset the fact that the read has been sent. Synchoronizing
  569. // with remove and close code. Remove portion (data->Shuttingdown)
  570. // only really relevant on 9X.
  571. //
  572. KeResetEvent(&Data->ReadSentEvent);
  573. if (!Data->EnableCount || Data->ShuttingDown) {
  574. IoReleaseRemoveLock (&Data->RemoveLock, Data->ReadIrp);
  575. status = Data->ShuttingDown ? STATUS_DELETE_PENDING : STATUS_UNSUCCESSFUL;
  576. KeSetEvent (&Data->ReadSentEvent, 0, FALSE);
  577. break;
  578. } else {
  579. status = IoCallDriver (Data->TopOfStack, irp);
  580. }
  581. KeSetEvent (&Data->ReadSentEvent, 0, FALSE);
  582. if (KBDHID_IMMEDIATE_READ != InterlockedExchange(&Data->ReadInterlock,
  583. KBDHID_END_READ)) {
  584. //
  585. // The read is asynch, will call SerialMouseStartRead from the
  586. // completion routine
  587. //
  588. Print(DBG_READ_TRACE, ("read is pending\n"));
  589. break;
  590. } else {
  591. //
  592. // The read was synchronous (probably bytes in the buffer). The
  593. // completion routine will not call SerialMouseStartRead, so we
  594. // just loop here. This is to prevent us from running out of stack
  595. // space if always call StartRead from the completion routine
  596. //
  597. Print(DBG_READ_TRACE, ("read is looping\n"));
  598. }
  599. } else if (status == STATUS_PRIVILEGE_NOT_HELD ||
  600. status == STATUS_CANCELLED ||
  601. status == STATUS_DELETE_PENDING ||
  602. status == STATUS_DEVICE_NOT_CONNECTED) {
  603. //
  604. // The HID class device object is being deleted. We will soon
  605. // receive Plug 'n Play notification of this device's removal,
  606. // if we have not received it already.
  607. //
  608. KeSetEvent (&Data->ReadCompleteEvent, 0, FALSE);
  609. IoReleaseRemoveLock (&Data->RemoveLock, Data->ReadIrp);
  610. break;
  611. } else {
  612. //
  613. // BUGBUG what shall we do with errors?
  614. //
  615. //
  616. // Panic
  617. //
  618. TRAP();
  619. }
  620. }
  621. return status;
  622. }
  623. VOID
  624. KbdHid_AutoRepeat (
  625. IN PKDPC DPC,
  626. IN PDEVICE_EXTENSION Data,
  627. IN PVOID SystemArgument1,
  628. IN PVOID SystemArgument2
  629. )
  630. /*++
  631. Routine Description:
  632. The auto repeat time has gone off. We should therefore duplicate the
  633. keystrokes that are currently down, by signalling them all going up,
  634. and then signaling them all going down.
  635. Afterwards we need to reset the timer to the repeat rate.
  636. Arguments:
  637. DeferredContext is set to the HID_DEVICE structure.
  638. --*/
  639. {
  640. PUSAGE_AND_PAGE previous;
  641. previous = Data->HidExtension->MakeUsageList; // PreviousUsageList;
  642. //
  643. // We really do not protect the previous list
  644. // But in order for the Previous list to be touched (written to),
  645. // the completion routine must fire, swap current with previous,
  646. // and the HIDCLASS must start writing on the list.
  647. // So we don't worry about this for now.
  648. //
  649. //
  650. // simulate a repeated key-down
  651. //
  652. HidP_TranslateUsageAndPagesToI8042ScanCodes (
  653. previous,
  654. Data->HidExtension->MaxUsages,
  655. HidP_Keyboard_Make,
  656. &Data->HidExtension->ModifierState,
  657. KbdHid_InsertCodesIntoQueue,
  658. Data);
  659. }
  660. #if KEYBOARD_HW_CHATTERY_FIX // [DAN]
  661. VOID
  662. KbdHid_InitiateStartRead (
  663. IN PKDPC DPC,
  664. IN PDEVICE_EXTENSION Data,
  665. IN PVOID SystemArgument1,
  666. IN PVOID SystemArgument2
  667. )
  668. {
  669. IoAcquireRemoveLock (&Data->RemoveLock, Data->ReadIrp);
  670. KbdHid_StartRead(Data);
  671. }
  672. #endif