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.

2750 lines
80 KiB

  1. /*++
  2. Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. i8042cmn.c
  5. Abstract:
  6. The common portions of the Intel i8042 port driver which
  7. apply to both the keyboard and the auxiliary (PS/2 mouse) device.
  8. Environment:
  9. Kernel mode only.
  10. Notes:
  11. NOTES: (Future/outstanding issues)
  12. - Powerfail not implemented.
  13. - IOCTL_INTERNAL_KEYBOARD_DISCONNECT and IOCTL_INTERNAL_MOUSE_DISCONNECT
  14. have not been implemented. They're not needed until the class
  15. unload routine is implemented. Right now, we don't want to allow
  16. either the keyboard or the mouse class driver to unload.
  17. - Consolidate duplicate code, where possible and appropriate.
  18. Revision History:
  19. --*/
  20. #include "stdarg.h"
  21. #include "stdio.h"
  22. #include "string.h"
  23. #include "i8042prt.h"
  24. #include "i8042log.h"
  25. // sys button IOCTL definitions
  26. #include "poclass.h"
  27. #ifdef ALLOC_PRAGMA
  28. #pragma alloc_text(PAGE, I8xClose)
  29. #pragma alloc_text(PAGE, I8xCreate)
  30. #pragma alloc_text(PAGE, I8xDeviceControl)
  31. #pragma alloc_text(PAGE, I8xSanityCheckResources)
  32. #endif // ALLOC_PRAGMA
  33. NTSTATUS
  34. I8xCreate (
  35. IN PDEVICE_OBJECT DeviceObject,
  36. IN PIRP Irp
  37. )
  38. /*++
  39. Routine Description:
  40. This is the dispatch routine for create/open requests.
  41. Arguments:
  42. DeviceObject - Pointer to the device object.
  43. Irp - Pointer to the request packet.
  44. Return Value:
  45. NT status code.
  46. --*/
  47. {
  48. NTSTATUS status = STATUS_SUCCESS;
  49. PCOMMON_DATA commonData = NULL;
  50. Print(DBG_CC_TRACE, ("Create enter\n"));
  51. PAGED_CODE();
  52. commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  53. if (NULL == commonData->ConnectData.ClassService) {
  54. //
  55. // No Connection yet. How can we be enabled?
  56. //
  57. Print(DBG_IOCTL_ERROR | DBG_CC_ERROR,
  58. ("ERROR: enable before connect!\n"));
  59. status = STATUS_INVALID_DEVICE_STATE;
  60. }
  61. else if (MANUALLY_REMOVED(commonData)) {
  62. status = STATUS_NO_SUCH_DEVICE;
  63. }
  64. else
  65. #if defined(_M_IX86) && (_MSC_FULL_VER < 13009175) // workaround for 13.00.9111 compiler (fixed in 9175 or better)
  66. {
  67. ULONG i = InterlockedIncrement(&commonData->EnableCount);
  68. if (1 >= i) {
  69. Print(DBG_CC_INFO,
  70. ("Enabling %s (%d)\n",
  71. commonData->IsKeyboard ? "Keyboard" : "Mouse",
  72. commonData->EnableCount
  73. ));
  74. }
  75. }
  76. #else
  77. if (1 >= InterlockedIncrement(&commonData->EnableCount)) {
  78. Print(DBG_CC_INFO,
  79. ("Enabling %s (%d)\n",
  80. commonData->IsKeyboard ? "Keyboard" : "Mouse",
  81. commonData->EnableCount
  82. ));
  83. }
  84. #endif
  85. //
  86. // No need to call the lower driver (the root bus) because it only handles
  87. // Power and PnP Irps
  88. //
  89. Irp->IoStatus.Status = status;
  90. Irp->IoStatus.Information = 0;
  91. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  92. Print(DBG_CC_TRACE, ("Create (%x)\n", status));
  93. return status;
  94. }
  95. NTSTATUS
  96. I8xClose (
  97. IN PDEVICE_OBJECT DeviceObject,
  98. IN PIRP Irp
  99. )
  100. /*++
  101. Routine Description:
  102. This is the dispatch routine for close requests. This request
  103. completes successfully.
  104. Arguments:
  105. DeviceObject - Pointer to the device object.
  106. Irp - Pointer to the request packet.
  107. Return Value:
  108. NT status code.
  109. --*/
  110. {
  111. PCOMMON_DATA commonData;
  112. ULONG count;
  113. PAGED_CODE();
  114. Print(DBG_CC_TRACE, ("Close\n"));
  115. commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  116. ASSERT(0 < commonData->EnableCount);
  117. count = InterlockedDecrement(&commonData->EnableCount);
  118. if (0 >= count) {
  119. Print(DBG_IOCTL_INFO,
  120. ("Disabling %s (%d)\n",
  121. commonData->IsKeyboard ? "Keyboard" : "Mouse",
  122. commonData->EnableCount
  123. ));
  124. }
  125. Irp->IoStatus.Status = STATUS_SUCCESS;
  126. Irp->IoStatus.Information = 0;
  127. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  128. return STATUS_SUCCESS;
  129. }
  130. VOID
  131. I8042CompletionDpc(
  132. IN PKDPC Dpc,
  133. IN PDEVICE_OBJECT DeviceObject,
  134. IN PIRP Irp,
  135. IN ISR_DPC_CAUSE IsrDpcCause
  136. )
  137. /*++
  138. Routine Description:
  139. This routine runs at DISPATCH_LEVEL IRQL to complete requests.
  140. It is queued by the ISR routine.
  141. Arguments:
  142. Dpc - Pointer to the DPC object.
  143. DeviceObject - Pointer to the device object.
  144. Irp - Irp about to be completed
  145. Context - Indicates type of error to log.
  146. Return Value:
  147. None.
  148. --*/
  149. {
  150. PIO_STACK_LOCATION irpSp;
  151. PPORT_KEYBOARD_EXTENSION kbExtension = DeviceObject->DeviceExtension;
  152. PPORT_MOUSE_EXTENSION mouseExtension = DeviceObject->DeviceExtension;
  153. PCOMMON_DATA commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  154. UNREFERENCED_PARAMETER(Dpc);
  155. UNREFERENCED_PARAMETER(IsrDpcCause);
  156. Print(DBG_DPC_TRACE, ("I8042CompletionDpc: enter\n"));
  157. // Stop the command timer.
  158. KeCancelTimer(&Globals.ControllerData->CommandTimer);
  159. ASSERT(Irp == DeviceObject->CurrentIrp);
  160. ASSERT(Irp != NULL);
  161. if (Irp == NULL) {
  162. #if DBG
  163. if (Globals.ControllerData->CurrentIoControlCode != 0x0) {
  164. Print(DBG_DPC_ERROR,
  165. ("Current IOCTL code is 0x%x\n",
  166. Globals.ControllerData->CurrentIoControlCode
  167. ));
  168. }
  169. #endif
  170. goto CompletionDpcFinished;
  171. }
  172. irpSp = IoGetCurrentIrpStackLocation(Irp);
  173. #if DBG
  174. ASSERT(irpSp->Parameters.DeviceIoControl.IoControlCode ==
  175. Globals.ControllerData->CurrentIoControlCode);
  176. Globals.ControllerData->CurrentIoControlCode = 0x0;
  177. #endif
  178. //
  179. // We know we're completing an internal device control request. Switch
  180. // on IoControlCode.
  181. //
  182. switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
  183. //
  184. // Complete the keyboard set indicators request.
  185. //
  186. case IOCTL_KEYBOARD_SET_INDICATORS:
  187. Print(DBG_IOCTL_NOISE | DBG_DPC_NOISE,
  188. ("I8042CompletionDpc: keyboard set indicators updated\n"
  189. ));
  190. //
  191. // Update the current indicators flag in the device extension.
  192. //
  193. kbExtension->KeyboardIndicators =
  194. *(PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
  195. Print(DBG_IOCTL_INFO | DBG_DPC_INFO,
  196. ("I8042CompletionDpc: new LED flags 0x%x\n",
  197. kbExtension->KeyboardIndicators.LedFlags
  198. ));
  199. break;
  200. //
  201. // Complete the keyboard set typematic request.
  202. //
  203. case IOCTL_KEYBOARD_SET_TYPEMATIC:
  204. Print(DBG_IOCTL_NOISE | DBG_DPC_NOISE,
  205. ("I8042CompletionDpc: keyboard set typematic updated\n"
  206. ));
  207. //
  208. // Update the current typematic rate/delay in the device extension.
  209. //
  210. kbExtension->KeyRepeatCurrent =
  211. *(PKEYBOARD_TYPEMATIC_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
  212. Print(DBG_IOCTL_INFO | DBG_DPC_INFO,
  213. ("I8042CompletionDpc: new rate/delay 0x%x/%x\n",
  214. kbExtension->KeyRepeatCurrent.Rate,
  215. kbExtension->KeyRepeatCurrent.Delay
  216. ));
  217. break;
  218. case IOCTL_INTERNAL_MOUSE_RESET:
  219. Print(DBG_IOCTL_NOISE | DBG_DPC_NOISE,
  220. ("I8042CompletionDpc: mouse reset complete\n"
  221. ));
  222. I8xFinishResetRequest(mouseExtension,
  223. FALSE, // success
  224. FALSE, // at DISPATCH already
  225. TRUE); // cancel the timer
  226. return;
  227. default:
  228. Print(DBG_DPC_INFO, ("I8042CompletionDpc: miscellaneous\n"));
  229. break;
  230. }
  231. //
  232. // Set the completion status, start the next packet, and complete the
  233. // request.
  234. //
  235. Irp->IoStatus.Status = STATUS_SUCCESS;
  236. IoCompleteRequest (Irp, IO_KEYBOARD_INCREMENT);
  237. KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
  238. if (commonData->CurrentOutput.Bytes &&
  239. commonData->CurrentOutput.Bytes != Globals.ControllerData->DefaultBuffer) {
  240. ExFreePool(commonData->CurrentOutput.Bytes);
  241. }
  242. #if DBG
  243. else {
  244. RtlZeroMemory(Globals.ControllerData->DefaultBuffer,
  245. sizeof(Globals.ControllerData->DefaultBuffer));
  246. }
  247. #endif
  248. commonData->CurrentOutput.Bytes = NULL;
  249. KeReleaseSpinLockFromDpcLevel(&Globals.ControllerData->BytesSpinLock);
  250. CompletionDpcFinished:
  251. IoFreeController(Globals.ControllerData->ControllerObject);
  252. IoStartNextPacket(DeviceObject, FALSE);
  253. if (Irp != NULL) {
  254. IoReleaseRemoveLock(&commonData->RemoveLock, Irp);
  255. }
  256. Print(DBG_DPC_TRACE, ("I8042CompletionDpc: exit\n"));
  257. }
  258. VOID
  259. I8042ErrorLogDpc(
  260. IN PKDPC Dpc,
  261. IN PDEVICE_OBJECT DeviceObject,
  262. IN PIRP Irp,
  263. IN PVOID Context
  264. )
  265. /*++
  266. Routine Description:
  267. This routine runs at DISPATCH_LEVEL IRQL to log errors that are
  268. discovered at IRQL > DISPATCH_LEVEL (e.g., in the ISR routine or
  269. in a routine that is executed via KeSynchronizeExecution). There
  270. is not necessarily a current request associated with this condition.
  271. Arguments:
  272. Dpc - Pointer to the DPC object.
  273. DeviceObject - Pointer to the device object.
  274. Irp - Not used.
  275. Context - Indicates type of error to log.
  276. Return Value:
  277. None.
  278. --*/
  279. {
  280. PIO_ERROR_LOG_PACKET errorLogEntry;
  281. UNREFERENCED_PARAMETER(Dpc);
  282. UNREFERENCED_PARAMETER(Irp);
  283. Print(DBG_DPC_TRACE, ("I8042ErrorLogDpc: enter\n"));
  284. //
  285. // Log an error packet.
  286. //
  287. errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
  288. DeviceObject,
  289. sizeof(IO_ERROR_LOG_PACKET)
  290. + (2 * sizeof(ULONG))
  291. );
  292. if (errorLogEntry != NULL) {
  293. errorLogEntry->DumpDataSize = 2 * sizeof(ULONG);
  294. if ((ULONG_PTR) Context == I8042_KBD_BUFFER_OVERFLOW) {
  295. errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 310;
  296. errorLogEntry->DumpData[0] = sizeof(KEYBOARD_INPUT_DATA);
  297. errorLogEntry->DumpData[1] = ((PPORT_KEYBOARD_EXTENSION)
  298. DeviceObject->DeviceExtension)->KeyboardAttributes.InputDataQueueLength;
  299. }
  300. else if ((ULONG_PTR) Context == I8042_MOU_BUFFER_OVERFLOW) {
  301. errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 320;
  302. errorLogEntry->DumpData[0] = sizeof(MOUSE_INPUT_DATA);
  303. errorLogEntry->DumpData[1] = ((PPORT_MOUSE_EXTENSION)
  304. DeviceObject->DeviceExtension)->MouseAttributes.InputDataQueueLength;
  305. }
  306. else {
  307. errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 330;
  308. errorLogEntry->DumpData[0] = 0;
  309. errorLogEntry->DumpData[1] = 0;
  310. }
  311. errorLogEntry->ErrorCode = (NTSTATUS)((ULONG_PTR)Context);
  312. errorLogEntry->SequenceNumber = 0;
  313. errorLogEntry->MajorFunctionCode = 0;
  314. errorLogEntry->IoControlCode = 0;
  315. errorLogEntry->RetryCount = 0;
  316. errorLogEntry->FinalStatus = 0;
  317. IoWriteErrorLogEntry(errorLogEntry);
  318. }
  319. Print(DBG_DPC_TRACE, ("I8042ErrorLogDpc: exit\n"));
  320. }
  321. NTSTATUS
  322. I8xFlush(
  323. IN PDEVICE_OBJECT DeviceObject,
  324. IN PIRP Irp
  325. )
  326. /*++
  327. Routine Description:
  328. Unimplemented flush routine
  329. Arguments:
  330. DeviceObject - An FDO
  331. Irp - The flush request
  332. Return Value:
  333. STATUS_NOT_IMPLEMENTED;
  334. --*/
  335. {
  336. UNREFERENCED_PARAMETER(DeviceObject);
  337. UNREFERENCED_PARAMETER(Irp);
  338. Print(DBG_CALL_TRACE, ("I8042Flush: enter\n"));
  339. Print(DBG_CALL_TRACE, ("I8042Flush: exit\n"));
  340. return(STATUS_NOT_IMPLEMENTED);
  341. }
  342. NTSTATUS
  343. I8xDeviceControl(
  344. IN PDEVICE_OBJECT DeviceObject,
  345. IN PIRP Irp
  346. )
  347. {
  348. PPORT_KEYBOARD_EXTENSION kbExtension;
  349. PIO_STACK_LOCATION stack;
  350. NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  351. PAGED_CODE();
  352. //
  353. // Get a pointer to the device extension.
  354. //
  355. kbExtension = (PPORT_KEYBOARD_EXTENSION) DeviceObject->DeviceExtension;
  356. if (!kbExtension->IsKeyboard || !kbExtension->Started ||
  357. MANUALLY_REMOVED(kbExtension)) {
  358. status = STATUS_INVALID_DEVICE_REQUEST;
  359. }
  360. else {
  361. stack = IoGetCurrentIrpStackLocation(Irp);
  362. switch (stack->Parameters.DeviceIoControl.IoControlCode) {
  363. case IOCTL_GET_SYS_BUTTON_CAPS:
  364. return I8xKeyboardGetSysButtonCaps(kbExtension, Irp);
  365. case IOCTL_GET_SYS_BUTTON_EVENT:
  366. return I8xKeyboardGetSysButtonEvent(kbExtension, Irp);
  367. default:
  368. status = STATUS_INVALID_DEVICE_REQUEST;
  369. break;
  370. }
  371. }
  372. Irp->IoStatus.Status = status;
  373. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  374. return status;
  375. }
  376. NTSTATUS
  377. I8xSendIoctl(
  378. PDEVICE_OBJECT Target,
  379. ULONG Ioctl,
  380. PVOID InputBuffer,
  381. ULONG InputBufferLength
  382. )
  383. /*++
  384. Routine Description:
  385. Sends an internal IOCTL to the top of the stack.
  386. Arguments:
  387. Target - The top of the stack
  388. Ioctl - The IOCTL to send
  389. InputBuffer - The buffer to be filled if the IOCTL is handled on the way down
  390. InputBufferLength - size, in bytes, of InputBuffer
  391. Return Value:
  392. STATUS_NOT_IMPLEMENTED;
  393. --*/
  394. {
  395. KEVENT event;
  396. NTSTATUS status = STATUS_SUCCESS;
  397. IO_STATUS_BLOCK iosb;
  398. PIRP irp;
  399. KeInitializeEvent(&event,
  400. NotificationEvent,
  401. FALSE
  402. );
  403. //
  404. // Allocate an IRP - No need to release
  405. // When the next-lower driver completes this IRP, the I/O Manager releases it.
  406. //
  407. if (NULL == (irp = IoBuildDeviceIoControlRequest(Ioctl,
  408. Target,
  409. InputBuffer,
  410. InputBufferLength,
  411. 0,
  412. 0,
  413. TRUE,
  414. &event,
  415. &iosb))) {
  416. return STATUS_INSUFFICIENT_RESOURCES;
  417. }
  418. status = IoCallDriver(Target, irp);
  419. Print(DBG_IOCTL_INFO,
  420. ("result of sending 0x%x was 0x%x\n",
  421. Ioctl,
  422. status
  423. ));
  424. if (STATUS_PENDING == status) {
  425. //
  426. // wait for it...
  427. //
  428. status = KeWaitForSingleObject(&event,
  429. Executive,
  430. KernelMode,
  431. FALSE, // Not alertable
  432. NULL); // No timeout structure
  433. ASSERT(STATUS_SUCCESS == status);
  434. status = iosb.Status;
  435. }
  436. return status;
  437. }
  438. NTSTATUS
  439. I8xInternalDeviceControl(
  440. IN PDEVICE_OBJECT DeviceObject,
  441. IN PIRP Irp
  442. )
  443. /*++
  444. Routine Description:
  445. This routine is the dispatch routine for internal device control requests.
  446. This routine cannot be paged because the class drivers send down internal
  447. IOCTLs at DISPATCH_LEVEL.
  448. Arguments:
  449. DeviceObject - Pointer to the device object.
  450. Irp - Pointer to the request packet.
  451. Return Value:
  452. Status is returned.
  453. --*/
  454. {
  455. PIO_STACK_LOCATION irpSp;
  456. PPORT_MOUSE_EXTENSION mouseExtension = DeviceObject->DeviceExtension;
  457. PPORT_KEYBOARD_EXTENSION kbExtension = DeviceObject->DeviceExtension;
  458. NTSTATUS status;
  459. PVOID parameters;
  460. PKEYBOARD_ATTRIBUTES keyboardAttributes;
  461. ULONG sizeOfTranslation;
  462. PDEVICE_OBJECT topOfStack;
  463. PINTERNAL_I8042_HOOK_KEYBOARD hookKeyboard;
  464. PINTERNAL_I8042_HOOK_MOUSE hookMouse;
  465. KEYBOARD_ID keyboardId;
  466. Print(DBG_IOCTL_TRACE, ("IOCTL: enter\n"));
  467. Irp->IoStatus.Information = 0;
  468. irpSp = IoGetCurrentIrpStackLocation(Irp);
  469. //
  470. // Case on the device control subfunction that is being performed by the
  471. // requestor.
  472. //
  473. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  474. //
  475. // Connect a keyboard class device driver to the port driver.
  476. //
  477. case IOCTL_INTERNAL_KEYBOARD_CONNECT:
  478. //
  479. // This really isn't something to worry about overall, but it is worthy
  480. // enough to be noted and recorded. The multiple starts will be handled in
  481. // I8xPnp and I8xKeyboardStartDevice routines
  482. //
  483. if (KEYBOARD_PRESENT()) {
  484. Print(DBG_ALWAYS, ("Received 1+ kb connects!\n"));
  485. SET_HW_FLAGS(DUP_KEYBOARD_HARDWARE_PRESENT);
  486. }
  487. InterlockedIncrement(&Globals.AddedKeyboards);
  488. kbExtension->IsKeyboard = TRUE;
  489. SET_HW_FLAGS(KEYBOARD_HARDWARE_PRESENT);
  490. Print(DBG_IOCTL_INFO, ("IOCTL: keyboard connect\n"));
  491. //
  492. // Only allow a connection if the keyboard hardware is present.
  493. // Also, only allow one connection.
  494. //
  495. if (kbExtension->ConnectData.ClassService != NULL) {
  496. Print(DBG_IOCTL_ERROR, ("IOCTL: error - already connected\n"));
  497. status = STATUS_SHARING_VIOLATION;
  498. break;
  499. }
  500. else if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  501. sizeof(CONNECT_DATA)) {
  502. Print(DBG_IOCTL_ERROR, ("IOCTL: error - invalid buffer length\n"));
  503. status = STATUS_INVALID_PARAMETER;
  504. break;
  505. }
  506. //
  507. // Copy the connection parameters to the device extension.
  508. //
  509. kbExtension->ConnectData =
  510. *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
  511. hookKeyboard = ExAllocatePool(PagedPool,
  512. sizeof(INTERNAL_I8042_HOOK_KEYBOARD)
  513. );
  514. if (hookKeyboard) {
  515. topOfStack = IoGetAttachedDeviceReference(kbExtension->Self);
  516. RtlZeroMemory(hookKeyboard,
  517. sizeof(INTERNAL_I8042_HOOK_KEYBOARD)
  518. );
  519. hookKeyboard->CallContext = (PVOID) DeviceObject;
  520. hookKeyboard->QueueKeyboardPacket = (PI8042_QUEUE_PACKET)
  521. I8xQueueCurrentKeyboardInput;
  522. hookKeyboard->IsrWritePort = (PI8042_ISR_WRITE_PORT)
  523. I8xKeyboardIsrWritePort;
  524. I8xSendIoctl(topOfStack,
  525. IOCTL_INTERNAL_I8042_HOOK_KEYBOARD,
  526. (PVOID) hookKeyboard,
  527. sizeof(INTERNAL_I8042_HOOK_KEYBOARD)
  528. );
  529. ObDereferenceObject(topOfStack);
  530. ExFreePool(hookKeyboard);
  531. }
  532. status = STATUS_SUCCESS;
  533. break;
  534. //
  535. // Disconnect a keyboard class device driver from the port driver.
  536. //
  537. // NOTE: Not implemented.
  538. //
  539. case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
  540. Print(DBG_IOCTL_INFO, ("IOCTL: keyboard disconnect\n"));
  541. //
  542. // Perform a keyboard interrupt disable call.
  543. //
  544. //
  545. // Clear the connection parameters in the device extension.
  546. // NOTE: Must synchronize this with the keyboard ISR.
  547. //
  548. //
  549. //deviceExtension->KeyboardExtension.ConnectData.ClassDeviceObject =
  550. // Null;
  551. //deviceExtension->KeyboardExtension.ConnectData.ClassService =
  552. // Null;
  553. status = STATUS_NOT_IMPLEMENTED;
  554. break;
  555. case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
  556. Print(DBG_IOCTL_INFO, ("hook keyboard received!\n"));
  557. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  558. sizeof(INTERNAL_I8042_HOOK_KEYBOARD)) {
  559. Print(DBG_IOCTL_ERROR,
  560. ("InternalIoctl error - invalid buffer length\n"
  561. ));
  562. status = STATUS_INVALID_PARAMETER;
  563. }
  564. else {
  565. //
  566. // Copy the values if they are filled in
  567. //
  568. hookKeyboard = (PINTERNAL_I8042_HOOK_KEYBOARD)
  569. irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  570. kbExtension->HookContext = hookKeyboard->Context;
  571. if (hookKeyboard->InitializationRoutine) {
  572. Print(DBG_IOCTL_NOISE,
  573. ("KB Init Routine 0x%x\n",
  574. hookKeyboard->IsrRoutine
  575. ));
  576. kbExtension->InitializationHookCallback =
  577. hookKeyboard->InitializationRoutine;
  578. }
  579. if (hookKeyboard->IsrRoutine) {
  580. Print(DBG_IOCTL_NOISE,
  581. ("KB Hook Routine 0x%x\n",
  582. hookKeyboard->IsrRoutine
  583. ));
  584. kbExtension->IsrHookCallback = hookKeyboard->IsrRoutine;
  585. }
  586. status = STATUS_SUCCESS;
  587. }
  588. break;
  589. //
  590. // Connect a mouse class device driver to the port driver.
  591. //
  592. case IOCTL_INTERNAL_MOUSE_CONNECT:
  593. //
  594. // This really isn't something to worry about overall, but it is worthy
  595. // enough to be noted and recorded. The multiple starts will be handled in
  596. // I8xPnp and I8xMouseStartDevice routines
  597. //
  598. if (MOUSE_PRESENT()) {
  599. Print(DBG_ALWAYS, ("Received 1+ mouse connects!\n"));
  600. SET_HW_FLAGS(DUP_MOUSE_HARDWARE_PRESENT);
  601. }
  602. InterlockedIncrement(&Globals.AddedMice);
  603. mouseExtension->IsKeyboard = FALSE;
  604. SET_HW_FLAGS(MOUSE_HARDWARE_PRESENT);
  605. Print(DBG_IOCTL_INFO, ("IOCTL: mouse connect\n"));
  606. //
  607. // Only allow a connection if the mouse hardware is present.
  608. // Also, only allow one connection.
  609. //
  610. if (mouseExtension->ConnectData.ClassService != NULL) {
  611. Print(DBG_IOCTL_ERROR, ("IOCTL: error - already connected\n"));
  612. status = STATUS_SHARING_VIOLATION;
  613. break;
  614. }
  615. else if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  616. sizeof(CONNECT_DATA)) {
  617. Print(DBG_IOCTL_ERROR, ("IOCTL: error - invalid buffer length\n"));
  618. status = STATUS_INVALID_PARAMETER;
  619. break;
  620. }
  621. //
  622. // Copy the connection parameters to the device extension.
  623. //
  624. mouseExtension->ConnectData =
  625. *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
  626. hookMouse = ExAllocatePool(PagedPool,
  627. sizeof(INTERNAL_I8042_HOOK_MOUSE)
  628. );
  629. if (hookMouse) {
  630. topOfStack = IoGetAttachedDeviceReference(mouseExtension->Self);
  631. RtlZeroMemory(hookMouse,
  632. sizeof(INTERNAL_I8042_HOOK_MOUSE)
  633. );
  634. hookMouse->CallContext = (PVOID) DeviceObject;
  635. hookMouse->QueueMousePacket = (PI8042_QUEUE_PACKET)
  636. I8xQueueCurrentMouseInput;
  637. hookMouse->IsrWritePort = (PI8042_ISR_WRITE_PORT)
  638. I8xMouseIsrWritePort;
  639. I8xSendIoctl(topOfStack,
  640. IOCTL_INTERNAL_I8042_HOOK_MOUSE,
  641. (PVOID) hookMouse,
  642. sizeof(INTERNAL_I8042_HOOK_MOUSE)
  643. );
  644. ObDereferenceObject(topOfStack);
  645. ExFreePool(hookMouse);
  646. }
  647. status = STATUS_SUCCESS;
  648. break;
  649. //
  650. // Disconnect a mouse class device driver from the port driver.
  651. //
  652. // NOTE: Not implemented.
  653. //
  654. case IOCTL_INTERNAL_MOUSE_DISCONNECT:
  655. Print(DBG_IOCTL_INFO, ("IOCTL: mouse disconnect\n"));
  656. //
  657. // Perform a mouse interrupt disable call.
  658. //
  659. //
  660. // Clear the connection parameters in the device extension.
  661. // NOTE: Must synchronize this with the mouse ISR.
  662. //
  663. //
  664. //deviceExtension->MouseExtension.ConnectData.ClassDeviceObject =
  665. // Null;
  666. //deviceExtension->MouseExtension.ConnectData.ClassService =
  667. // Null;
  668. status = STATUS_NOT_IMPLEMENTED;
  669. break;
  670. case IOCTL_INTERNAL_I8042_HOOK_MOUSE:
  671. Print(DBG_IOCTL_INFO, ("hook mouse received!\n"));
  672. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  673. sizeof(INTERNAL_I8042_HOOK_MOUSE)) {
  674. Print(DBG_IOCTL_ERROR,
  675. ("InternalIoctl error - invalid buffer length\n"
  676. ));
  677. status = STATUS_INVALID_PARAMETER;
  678. }
  679. else {
  680. //
  681. // Copy the values if they are filled in
  682. //
  683. hookMouse = (PINTERNAL_I8042_HOOK_MOUSE)
  684. irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  685. mouseExtension->HookContext = hookMouse->Context;
  686. if (hookMouse->IsrRoutine) {
  687. Print(DBG_IOCTL_NOISE,
  688. ("Mou Hook Routine 0x%x\n",
  689. hookMouse->IsrRoutine
  690. ));
  691. mouseExtension->IsrHookCallback = hookMouse->IsrRoutine;
  692. }
  693. status = STATUS_SUCCESS;
  694. }
  695. break;
  696. //
  697. // Query the keyboard attributes. First check for adequate buffer
  698. // length. Then, copy the keyboard attributes from the device
  699. // extension to the output buffer.
  700. //
  701. case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
  702. Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard query attributes\n"));
  703. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  704. sizeof(KEYBOARD_ATTRIBUTES)) {
  705. status = STATUS_BUFFER_TOO_SMALL;
  706. }
  707. else {
  708. //
  709. // Copy the attributes from the DeviceExtension to the
  710. // buffer.
  711. //
  712. *(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
  713. kbExtension->KeyboardAttributes;
  714. Irp->IoStatus.Information = sizeof(KEYBOARD_ATTRIBUTES);
  715. status = STATUS_SUCCESS;
  716. }
  717. break;
  718. //
  719. // Query the scan code to indicator-light mapping. Validate the
  720. // parameters, and copy the indicator mapping information from
  721. // the port device extension to the SystemBuffer.
  722. //
  723. case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: {
  724. PKEYBOARD_INDICATOR_TRANSLATION translation;
  725. ASSERT(kbExtension->IsKeyboard);
  726. Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard query indicator translation\n"));
  727. sizeOfTranslation = sizeof(KEYBOARD_INDICATOR_TRANSLATION)
  728. + (sizeof(INDICATOR_LIST)
  729. * (kbExtension->KeyboardAttributes.NumberOfIndicators - 1));
  730. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  731. sizeOfTranslation) {
  732. status = STATUS_BUFFER_TOO_SMALL;
  733. }
  734. else {
  735. //
  736. // Copy the indicator mapping information to the system
  737. // buffer.
  738. //
  739. translation = (PKEYBOARD_INDICATOR_TRANSLATION)
  740. Irp->AssociatedIrp.SystemBuffer;
  741. translation->NumberOfIndicatorKeys =
  742. kbExtension->KeyboardAttributes.NumberOfIndicators;
  743. RtlMoveMemory(
  744. translation->IndicatorList,
  745. (PCHAR) IndicatorList,
  746. sizeof(INDICATOR_LIST) * translation->NumberOfIndicatorKeys
  747. );
  748. Irp->IoStatus.Information = sizeOfTranslation;
  749. status = STATUS_SUCCESS;
  750. }
  751. break;
  752. }
  753. //
  754. // Query the keyboard indicators. Validate the parameters, and
  755. // copy the indicator information from the port device extension to
  756. // the SystemBuffer.
  757. //
  758. case IOCTL_KEYBOARD_QUERY_INDICATORS:
  759. ASSERT(kbExtension->IsKeyboard);
  760. Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard query indicators\n"));
  761. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  762. sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
  763. status = STATUS_BUFFER_TOO_SMALL;
  764. }
  765. else {
  766. //
  767. // Don't bother to synchronize access to the DeviceExtension
  768. // KeyboardIndicators field while copying it. We don't
  769. // really care if another process is setting the LEDs via
  770. // StartIo running on another processor.
  771. //
  772. *(PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
  773. kbExtension->KeyboardIndicators;
  774. #if defined(FE_SB)
  775. keyboardId = kbExtension->KeyboardAttributes.KeyboardIdentifier;
  776. if (DEC_KANJI_KEYBOARD(keyboardId)) {
  777. //
  778. // DEC LK411 keyboard does not have LED for NumLock,
  779. // but the bit is used for KanaLock.
  780. //
  781. if (((PKEYBOARD_INDICATOR_PARAMETERS)
  782. Irp->AssociatedIrp.SystemBuffer)->LedFlags & KEYBOARD_NUM_LOCK_ON) {
  783. //
  784. // KEYBOARD_KANA_LOCK_ON is mapped to KEYBOARD_NUM_LOCK_ON
  785. //
  786. ((PKEYBOARD_INDICATOR_PARAMETERS)
  787. Irp->AssociatedIrp.SystemBuffer)->LedFlags |= KEYBOARD_KANA_LOCK_ON;
  788. ((PKEYBOARD_INDICATOR_PARAMETERS)
  789. Irp->AssociatedIrp.SystemBuffer)->LedFlags &= ~(KEYBOARD_NUM_LOCK_ON);
  790. }
  791. }
  792. #endif
  793. Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
  794. status = STATUS_SUCCESS;
  795. }
  796. break;
  797. //
  798. // Set the keyboard indicators (validate the parameters, mark the
  799. // request pending, and handle it in StartIo).
  800. //
  801. case IOCTL_KEYBOARD_SET_INDICATORS:
  802. if (!kbExtension->InterruptObject) {
  803. status = STATUS_DEVICE_NOT_READY;
  804. break;
  805. }
  806. if (kbExtension->PowerState != PowerDeviceD0) {
  807. status = STATUS_POWER_STATE_INVALID;
  808. break;
  809. }
  810. Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard set indicators\n"));
  811. #ifdef FE_SB // I8042InternalDeviceControl()
  812. //
  813. // Katakana keyboard indicator support on AX Japanese keyboard
  814. //
  815. if ((irpSp->Parameters.DeviceIoControl.InputBufferLength <
  816. sizeof(KEYBOARD_INDICATOR_PARAMETERS)) ||
  817. ((((PKEYBOARD_INDICATOR_PARAMETERS)
  818. Irp->AssociatedIrp.SystemBuffer)->LedFlags
  819. & ~(KEYBOARD_SCROLL_LOCK_ON
  820. | KEYBOARD_NUM_LOCK_ON | KEYBOARD_CAPS_LOCK_ON
  821. | KEYBOARD_KANA_LOCK_ON)) != 0)) {
  822. status = STATUS_INVALID_PARAMETER;
  823. }
  824. else {
  825. keyboardId = kbExtension->KeyboardAttributes.KeyboardIdentifier;
  826. if (DEC_KANJI_KEYBOARD(keyboardId)) {
  827. //
  828. // DEC LK411 keyboard does not have LED for NumLock,
  829. // but the bit is used for KanaLock.
  830. //
  831. if (((PKEYBOARD_INDICATOR_PARAMETERS)
  832. Irp->AssociatedIrp.SystemBuffer)->LedFlags & KEYBOARD_KANA_LOCK_ON) {
  833. //
  834. // KEYBOARD_KANA_LOCK_ON is mapped to KEYBOARD_NUM_LOCK_ON
  835. //
  836. ((PKEYBOARD_INDICATOR_PARAMETERS)
  837. Irp->AssociatedIrp.SystemBuffer)->LedFlags |= KEYBOARD_NUM_LOCK_ON;
  838. ((PKEYBOARD_INDICATOR_PARAMETERS)
  839. Irp->AssociatedIrp.SystemBuffer)->LedFlags &= ~(KEYBOARD_KANA_LOCK_ON);
  840. }
  841. else {
  842. //
  843. // Ignore NumLock. (There is no LED for NumLock)
  844. //
  845. ((PKEYBOARD_INDICATOR_PARAMETERS)
  846. Irp->AssociatedIrp.SystemBuffer)->LedFlags &= ~(KEYBOARD_NUM_LOCK_ON);
  847. }
  848. }
  849. else if (! AX_KEYBOARD(keyboardId) &&
  850. (((PKEYBOARD_INDICATOR_PARAMETERS)
  851. Irp->AssociatedIrp.SystemBuffer)->LedFlags
  852. & KEYBOARD_KANA_LOCK_ON)) {
  853. //
  854. // If this is not AX keyboard, the keyboard dose
  855. // have 'kana' LED, then just turn off the bit.
  856. //
  857. ((PKEYBOARD_INDICATOR_PARAMETERS)
  858. Irp->AssociatedIrp.SystemBuffer)->LedFlags &=
  859. ~(KEYBOARD_KANA_LOCK_ON);
  860. }
  861. status = STATUS_PENDING;
  862. }
  863. #else
  864. if ((irpSp->Parameters.DeviceIoControl.InputBufferLength <
  865. sizeof(KEYBOARD_INDICATOR_PARAMETERS)) ||
  866. ((((PKEYBOARD_INDICATOR_PARAMETERS)
  867. Irp->AssociatedIrp.SystemBuffer)->LedFlags
  868. & ~(KEYBOARD_SCROLL_LOCK_ON
  869. | KEYBOARD_NUM_LOCK_ON | KEYBOARD_CAPS_LOCK_ON)) != 0)) {
  870. status = STATUS_INVALID_PARAMETER;
  871. }
  872. else {
  873. status = STATUS_PENDING;
  874. }
  875. #endif // FE_SB
  876. break;
  877. //
  878. // Query the current keyboard typematic rate and delay. Validate
  879. // the parameters, and copy the typematic information from the port
  880. // device extension to the SystemBuffer.
  881. //
  882. case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
  883. Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard query typematic\n"));
  884. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  885. sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
  886. status = STATUS_BUFFER_TOO_SMALL;
  887. }
  888. else {
  889. //
  890. // Don't bother to synchronize access to the DeviceExtension
  891. // KeyRepeatCurrent field while copying it. We don't
  892. // really care if another process is setting the typematic
  893. // rate/delay via StartIo running on another processor.
  894. //
  895. *(PKEYBOARD_TYPEMATIC_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
  896. kbExtension->KeyRepeatCurrent;
  897. Irp->IoStatus.Information = sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
  898. status = STATUS_SUCCESS;
  899. }
  900. break;
  901. //
  902. // Set the keyboard typematic rate and delay (validate the parameters,
  903. // mark the request pending, and handle it in StartIo).
  904. //
  905. case IOCTL_KEYBOARD_SET_TYPEMATIC:
  906. if (!kbExtension->InterruptObject) {
  907. status = STATUS_DEVICE_NOT_READY;
  908. break;
  909. }
  910. if (kbExtension->PowerState != PowerDeviceD0) {
  911. status = STATUS_POWER_STATE_INVALID;
  912. break;
  913. }
  914. Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard set typematic\n"));
  915. parameters = Irp->AssociatedIrp.SystemBuffer;
  916. keyboardAttributes = &kbExtension->KeyboardAttributes;
  917. if ((irpSp->Parameters.DeviceIoControl.InputBufferLength <
  918. sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) ||
  919. (((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Rate <
  920. keyboardAttributes->KeyRepeatMinimum.Rate) ||
  921. (((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Rate >
  922. keyboardAttributes->KeyRepeatMaximum.Rate) ||
  923. (((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Delay <
  924. keyboardAttributes->KeyRepeatMinimum.Delay) ||
  925. (((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Delay >
  926. keyboardAttributes->KeyRepeatMaximum.Delay)) {
  927. status = STATUS_INVALID_PARAMETER;
  928. }
  929. else {
  930. status = STATUS_PENDING;
  931. }
  932. break;
  933. #if defined(_X86_)
  934. case IOCTL_KEYBOARD_SET_IME_STATUS:
  935. Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard set ime status\n"));
  936. if (!kbExtension->InterruptObject) {
  937. status = STATUS_DEVICE_NOT_READY;
  938. break;
  939. }
  940. if (kbExtension->PowerState != PowerDeviceD0) {
  941. status = STATUS_POWER_STATE_INVALID;
  942. break;
  943. }
  944. keyboardId = kbExtension->KeyboardAttributes.KeyboardIdentifier;
  945. if (!OYAYUBI_KEYBOARD(keyboardId)) {
  946. //
  947. // This ioctl supported on 'Fujitsu oyayubi' keyboard only...
  948. //
  949. status = STATUS_INVALID_DEVICE_REQUEST;
  950. }
  951. else {
  952. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  953. sizeof(KEYBOARD_IME_STATUS)) {
  954. status = STATUS_INVALID_PARAMETER;
  955. }
  956. else {
  957. ULONG InternalMode;
  958. parameters = Irp->AssociatedIrp.SystemBuffer;
  959. InternalMode = I8042QueryIMEStatusForOasys(
  960. (PKEYBOARD_IME_STATUS)parameters
  961. );
  962. if ((InternalMode <= 0) || (InternalMode > 8)) {
  963. //
  964. // IME mode could not translate to hardware mode.
  965. //
  966. status = STATUS_INVALID_PARAMETER;
  967. }
  968. else {
  969. status = STATUS_PENDING;
  970. }
  971. }
  972. }
  973. break;
  974. #endif
  975. //
  976. // Query the mouse attributes. First check for adequate buffer
  977. // length. Then, copy the mouse attributes from the device
  978. // extension to the output buffer.
  979. //
  980. case IOCTL_MOUSE_QUERY_ATTRIBUTES:
  981. Print(DBG_IOCTL_NOISE, ("IOCTL: mouse query attributes\n"));
  982. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  983. sizeof(MOUSE_ATTRIBUTES)) {
  984. status = STATUS_BUFFER_TOO_SMALL;
  985. }
  986. else {
  987. //
  988. // Copy the attributes from the DeviceExtension to the
  989. // buffer.
  990. //
  991. *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
  992. mouseExtension->MouseAttributes;
  993. Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
  994. status = STATUS_SUCCESS;
  995. }
  996. break;
  997. case IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION:
  998. case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION:
  999. status = STATUS_SUCCESS;
  1000. break;
  1001. case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
  1002. case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
  1003. if (!mouseExtension->InterruptObject) {
  1004. status = STATUS_DEVICE_NOT_READY;
  1005. break;
  1006. }
  1007. if (mouseExtension->PowerState != PowerDeviceD0) {
  1008. status = STATUS_POWER_STATE_INVALID;
  1009. break;
  1010. }
  1011. Print(DBG_IOCTL_NOISE, ("IOCTL: mouse send buffer\n"));
  1012. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < 1 ||
  1013. !irpSp->Parameters.DeviceIoControl.Type3InputBuffer) {
  1014. status = STATUS_INVALID_PARAMETER;
  1015. }
  1016. else {
  1017. status = STATUS_PENDING;
  1018. }
  1019. break;
  1020. case IOCTL_INTERNAL_I8042_CONTROLLER_WRITE_BUFFER:
  1021. if (!kbExtension->IsKeyboard) {
  1022. //
  1023. // This should only be sent down the kb stack
  1024. //
  1025. Print(DBG_ALWAYS, ("Send this request down the kb stack!!!\n"));
  1026. ASSERT(FALSE);
  1027. status = STATUS_INVALID_DEVICE_REQUEST;
  1028. }
  1029. else {
  1030. //
  1031. // We currently do not support this IOCTL
  1032. //
  1033. status = STATUS_NOT_SUPPORTED;
  1034. }
  1035. break;
  1036. default:
  1037. Print(DBG_IOCTL_ERROR, ("IOCTL: INVALID REQUEST\n"));
  1038. status = STATUS_INVALID_DEVICE_REQUEST;
  1039. break;
  1040. }
  1041. Irp->IoStatus.Status = status;
  1042. if (status == STATUS_PENDING) {
  1043. Print(DBG_IOCTL_NOISE, ("Acquiring tag %p on remlock %p\n",
  1044. Irp,
  1045. &GET_COMMON_DATA(DeviceObject->DeviceExtension)->RemoveLock));
  1046. status = IoAcquireRemoveLock(
  1047. &GET_COMMON_DATA(DeviceObject->DeviceExtension)->RemoveLock,
  1048. Irp
  1049. );
  1050. if (!NT_SUCCESS(status)) {
  1051. Irp->IoStatus.Status = status;
  1052. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1053. }
  1054. else {
  1055. status = STATUS_PENDING;
  1056. IoMarkIrpPending(Irp);
  1057. IoStartPacket(DeviceObject,
  1058. Irp,
  1059. (PULONG) NULL,
  1060. NULL
  1061. );
  1062. }
  1063. }
  1064. else {
  1065. IoCompleteRequest(Irp,
  1066. IO_NO_INCREMENT
  1067. );
  1068. }
  1069. Print(DBG_IOCTL_TRACE, ("IOCTL: exit (0x%x)\n", status));
  1070. return status;
  1071. }
  1072. VOID
  1073. I8042RetriesExceededDpc(
  1074. IN PKDPC Dpc,
  1075. IN PDEVICE_OBJECT DeviceObject,
  1076. IN PIRP Irp,
  1077. IN PVOID Context
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. This routine runs at DISPATCH_LEVEL IRQL to complete requests that
  1082. have exceeded the maximum number of retries. It is queued in the
  1083. keyboard ISR.
  1084. Arguments:
  1085. Dpc - Pointer to the DPC object.
  1086. DeviceObject - Pointer to the device object.
  1087. Irp - Pointer to the Irp.
  1088. Context - Not used.
  1089. Return Value:
  1090. None.
  1091. --*/
  1092. {
  1093. PCOMMON_DATA commonData;
  1094. PIO_ERROR_LOG_PACKET errorLogEntry;
  1095. PIO_STACK_LOCATION irpSp;
  1096. ULONG i;
  1097. UNREFERENCED_PARAMETER(Dpc);
  1098. UNREFERENCED_PARAMETER(Context);
  1099. Print(DBG_DPC_TRACE, ("I8042RetriesExceededDpc: enter\n"));
  1100. commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  1101. //
  1102. // Set the completion status.
  1103. //
  1104. Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
  1105. if(Globals.ReportResetErrors == TRUE)
  1106. {
  1107. //
  1108. // Log an error.
  1109. //
  1110. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  1111. IoAllocateErrorLogEntry(DeviceObject,
  1112. (UCHAR) (sizeof(IO_ERROR_LOG_PACKET) +
  1113. commonData->CurrentOutput.ByteCount *
  1114. sizeof(ULONG))
  1115. );
  1116. KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
  1117. if (errorLogEntry != NULL) {
  1118. errorLogEntry->ErrorCode = commonData->IsKeyboard ?
  1119. I8042_RETRIES_EXCEEDED_KBD :
  1120. I8042_RETRIES_EXCEEDED_MOU;
  1121. errorLogEntry->DumpDataSize = (USHORT)
  1122. commonData->CurrentOutput.ByteCount * sizeof(ULONG);
  1123. errorLogEntry->SequenceNumber = commonData->SequenceNumber;
  1124. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1125. errorLogEntry->MajorFunctionCode = irpSp->MajorFunction;
  1126. errorLogEntry->IoControlCode =
  1127. irpSp->Parameters.DeviceIoControl.IoControlCode;
  1128. errorLogEntry->RetryCount = (UCHAR) commonData->ResendCount;
  1129. errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 210;
  1130. errorLogEntry->FinalStatus = Irp->IoStatus.Status;
  1131. if (commonData->CurrentOutput.Bytes) {
  1132. for (i = 0; i < commonData->CurrentOutput.ByteCount; i++) {
  1133. errorLogEntry->DumpData[i] = commonData->CurrentOutput.Bytes[i];
  1134. }
  1135. }
  1136. IoWriteErrorLogEntry(errorLogEntry);
  1137. }
  1138. }
  1139. else{
  1140. KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
  1141. }
  1142. if (commonData->CurrentOutput.Bytes &&
  1143. commonData->CurrentOutput.Bytes != Globals.ControllerData->DefaultBuffer) {
  1144. ExFreePool(commonData->CurrentOutput.Bytes);
  1145. }
  1146. commonData->CurrentOutput.Bytes = NULL;
  1147. KeReleaseSpinLockFromDpcLevel(&Globals.ControllerData->BytesSpinLock);
  1148. I8xCompletePendedRequest(DeviceObject, Irp, 0, STATUS_IO_TIMEOUT);
  1149. Print(DBG_DPC_TRACE, ("I8042RetriesExceededDpc: exit\n"));
  1150. }
  1151. VOID
  1152. I8xStartIo(
  1153. IN PDEVICE_OBJECT DeviceObject,
  1154. IN PIRP Irp
  1155. )
  1156. /*++
  1157. Routine Description:
  1158. This routine starts an I/O operation for the device which is further
  1159. controlled by the controller object
  1160. Arguments:
  1161. DeviceObject - Pointer to the device object.
  1162. Irp - Pointer to the request packet.
  1163. Return Value:
  1164. None.
  1165. --*/
  1166. {
  1167. KIRQL cancelIrql;
  1168. PIO_STACK_LOCATION irpSp;
  1169. PCOMMON_DATA common;
  1170. Print(DBG_IOCTL_TRACE, ("I8042StartIo: enter\n"));
  1171. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1172. switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
  1173. case IOCTL_KEYBOARD_SET_INDICATORS:
  1174. case IOCTL_KEYBOARD_SET_TYPEMATIC:
  1175. #if defined(_X86_)
  1176. case IOCTL_KEYBOARD_SET_IME_STATUS:
  1177. #endif
  1178. case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
  1179. case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
  1180. case IOCTL_INTERNAL_MOUSE_RESET:
  1181. IoAllocateController(Globals.ControllerData->ControllerObject,
  1182. DeviceObject,
  1183. I8xControllerRoutine,
  1184. NULL
  1185. );
  1186. break;
  1187. default:
  1188. Print(DBG_IOCTL_ERROR, ("I8042StartIo: INVALID REQUEST\n"));
  1189. //
  1190. // Log an internal error. Note that we're calling the
  1191. // error log DPC routine directly, rather than duplicating
  1192. // code.
  1193. //
  1194. common = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  1195. I8042ErrorLogDpc((PKDPC) NULL,
  1196. DeviceObject,
  1197. Irp,
  1198. LongToPtr(common->IsKeyboard ?
  1199. I8042_INVALID_STARTIO_REQUEST_KBD :
  1200. I8042_INVALID_STARTIO_REQUEST_MOU)
  1201. );
  1202. IoAcquireCancelSpinLock(&cancelIrql);
  1203. IoSetCancelRoutine(Irp, NULL);
  1204. IoReleaseCancelSpinLock(cancelIrql);
  1205. Irp->IoStatus.Information = 0;
  1206. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  1207. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1208. IoStartNextPacket(DeviceObject, FALSE);
  1209. //
  1210. // Release the lock we acquired when we started the packet
  1211. //
  1212. IoReleaseRemoveLock(&common->RemoveLock, Irp);
  1213. }
  1214. Print(DBG_IOCTL_TRACE, ("I8042StartIo: exit\n"));
  1215. }
  1216. IO_ALLOCATION_ACTION
  1217. I8xControllerRoutine (
  1218. IN PDEVICE_OBJECT DeviceObject,
  1219. IN PIRP Irp,
  1220. IN PVOID MapRegisterBase,
  1221. IN PVOID Context
  1222. )
  1223. /*++
  1224. Routine Description:
  1225. This routine synchronously writes the first byte to the intended device and
  1226. fires off a timer to assure the write took place.
  1227. Arguments:
  1228. DeviceObject - The device object for which the write is meant for
  1229. Irp - Pointer to the request packet.
  1230. MapRegisterBase - Unused
  1231. Context - Unused
  1232. Return Value:
  1233. None.
  1234. --*/
  1235. {
  1236. PCOMMON_DATA commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  1237. PPORT_KEYBOARD_EXTENSION kbExtension = DeviceObject->DeviceExtension;
  1238. PPORT_MOUSE_EXTENSION mouseExtension = DeviceObject->DeviceExtension;
  1239. KIRQL cancelIrql;
  1240. PIO_STACK_LOCATION irpSp;
  1241. INITIATE_OUTPUT_CONTEXT ic;
  1242. LARGE_INTEGER deltaTime;
  1243. LONG interlockedResult;
  1244. ULONG bufferLen;
  1245. NTSTATUS status = STATUS_SUCCESS;
  1246. KEYBOARD_ID keyboardId;
  1247. commonData->SequenceNumber += 1;
  1248. UNREFERENCED_PARAMETER(MapRegisterBase);
  1249. UNREFERENCED_PARAMETER(Context);
  1250. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1251. #if DBG
  1252. Globals.ControllerData->CurrentIoControlCode =
  1253. irpSp->Parameters.DeviceIoControl.IoControlCode;
  1254. #endif
  1255. switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
  1256. //
  1257. // Set the keyboard indicators to the desired state.
  1258. //
  1259. case IOCTL_KEYBOARD_SET_INDICATORS:
  1260. Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: keyboard set indicators\n"));
  1261. if (kbExtension->KeyboardIndicators.LedFlags ==
  1262. ((PKEYBOARD_INDICATOR_PARAMETERS)
  1263. Irp->AssociatedIrp.SystemBuffer)->LedFlags) {
  1264. ASSERT(Irp->CancelRoutine == NULL);
  1265. I8xCompletePendedRequest(DeviceObject,
  1266. Irp,
  1267. 0,
  1268. STATUS_SUCCESS
  1269. );
  1270. //
  1271. // Tell the controller processing routine to stop processing packets
  1272. // because we called IoFreeController ourselves.
  1273. //
  1274. return KeepObject;
  1275. }
  1276. ic.Bytes = Globals.ControllerData->DefaultBuffer;
  1277. //
  1278. // Set up the context structure for the InitiateIo wrapper.
  1279. //
  1280. ic.DeviceObject = DeviceObject;
  1281. ic.ByteCount = 2;
  1282. ic.Bytes[0] = SET_KEYBOARD_INDICATORS;
  1283. ic.Bytes[1] = (UCHAR) ((PKEYBOARD_INDICATOR_PARAMETERS)
  1284. Irp->AssociatedIrp.SystemBuffer)->LedFlags;
  1285. break;
  1286. //
  1287. // Set the keyboard typematic rate and delay.
  1288. //
  1289. case IOCTL_KEYBOARD_SET_TYPEMATIC:
  1290. Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: keyboard set typematic\n"));
  1291. ic.Bytes = Globals.ControllerData->DefaultBuffer;
  1292. //
  1293. // Set up the context structure for the InitiateIo wrapper.
  1294. //
  1295. ic.DeviceObject = DeviceObject;
  1296. ic.ByteCount = 2;
  1297. ic.Bytes[0] = SET_KEYBOARD_TYPEMATIC;
  1298. ic.Bytes[1] =
  1299. I8xConvertTypematicParameters(
  1300. ((PKEYBOARD_TYPEMATIC_PARAMETERS)
  1301. Irp->AssociatedIrp.SystemBuffer)->Rate,
  1302. ((PKEYBOARD_TYPEMATIC_PARAMETERS)
  1303. Irp->AssociatedIrp.SystemBuffer)->Delay
  1304. );
  1305. break;
  1306. case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER: // Write data to the mouse
  1307. case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER: // Write data to the kb
  1308. #if DBG
  1309. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  1310. IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER) {
  1311. Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: mou write buffer\n"));
  1312. }
  1313. else {
  1314. Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: kb write buffer\n"));
  1315. }
  1316. #endif
  1317. bufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  1318. if (bufferLen <= 4) {
  1319. ic.Bytes = Globals.ControllerData->DefaultBuffer;
  1320. }
  1321. else {
  1322. ic.Bytes = ExAllocatePool(NonPagedPool, bufferLen);
  1323. if (!ic.Bytes) {
  1324. status = STATUS_INSUFFICIENT_RESOURCES;
  1325. goto ControllerRequestError;
  1326. }
  1327. }
  1328. ic.DeviceObject = DeviceObject;
  1329. RtlCopyMemory(ic.Bytes,
  1330. irpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  1331. bufferLen);
  1332. ic.ByteCount = bufferLen;
  1333. break;
  1334. #if defined(_X86_)
  1335. case IOCTL_KEYBOARD_SET_IME_STATUS:
  1336. Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: keyboard set ime status\n"));
  1337. keyboardId = kbExtension->KeyboardAttributes.KeyboardIdentifier;
  1338. if (OYAYUBI_KEYBOARD(keyboardId)) {
  1339. status = I8042SetIMEStatusForOasys(DeviceObject,
  1340. Irp,
  1341. &ic);
  1342. if (!NT_SUCCESS(status)) {
  1343. goto ControllerRequestError;
  1344. }
  1345. }
  1346. else {
  1347. status = STATUS_INVALID_DEVICE_REQUEST;
  1348. goto ControllerRequestError;
  1349. }
  1350. break;
  1351. #endif
  1352. case IOCTL_INTERNAL_MOUSE_RESET:
  1353. Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: internal reset mouse\n"));
  1354. I8xSendResetCommand(mouseExtension);
  1355. return KeepObject;
  1356. default:
  1357. Print(DBG_IOCTL_ERROR, ("I8xContollerRoutine: INVALID REQUEST\n"));
  1358. ASSERT(FALSE);
  1359. ControllerRequestError:
  1360. IoAcquireCancelSpinLock(&cancelIrql);
  1361. IoSetCancelRoutine(Irp, NULL);
  1362. IoReleaseCancelSpinLock(cancelIrql);
  1363. I8xCompletePendedRequest(DeviceObject, Irp, 0, status);
  1364. //
  1365. // Since we called IoFreeController already, tell the controller object
  1366. // routine to stop processing packets
  1367. //
  1368. return KeepObject;
  1369. }
  1370. KeSynchronizeExecution(
  1371. commonData->InterruptObject,
  1372. (PKSYNCHRONIZE_ROUTINE) I8xInitiateOutputWrapper,
  1373. (PVOID) &ic
  1374. );
  1375. deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
  1376. deltaTime.HighPart = -1;
  1377. KeSetTimer(&Globals.ControllerData->CommandTimer,
  1378. deltaTime,
  1379. &commonData->TimeOutDpc
  1380. );
  1381. return KeepObject;
  1382. }
  1383. VOID
  1384. I8xCompletePendedRequest(
  1385. PDEVICE_OBJECT DeviceObject,
  1386. PIRP Irp,
  1387. ULONG_PTR Information,
  1388. NTSTATUS Status
  1389. )
  1390. {
  1391. PIO_STACK_LOCATION stack;
  1392. PCOMMON_DATA common;
  1393. stack = IoGetCurrentIrpStackLocation(Irp);
  1394. common = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  1395. Irp->IoStatus.Information = Information;
  1396. Irp->IoStatus.Status = Status;
  1397. ASSERT(IOCTL_INTERNAL_MOUSE_RESET !=
  1398. IoGetCurrentIrpStackLocation(Irp)->
  1399. Parameters.DeviceIoControl.IoControlCode);
  1400. Print(DBG_IOCTL_INFO,
  1401. ("Completing IOCTL irp %p, code 0x%x, status 0x%x\n",
  1402. Irp, stack->Parameters.DeviceIoControl.IoControlCode, Status));
  1403. ASSERT(stack->Control & SL_PENDING_RETURNED);
  1404. IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
  1405. //
  1406. // Start the next packet and complete the request.
  1407. //
  1408. // Order is important! If IoStartNextPacket is called first, then
  1409. // (potentially) the same device object will be enqueued twice on
  1410. // the controller object which will cause corruption in the
  1411. // controller object's list of allocated routines
  1412. //
  1413. IoFreeController(Globals.ControllerData->ControllerObject);
  1414. IoStartNextPacket(DeviceObject, FALSE);
  1415. //
  1416. // Release the lock we acquired in start io. Release this last so
  1417. // that lifetime is guaranteed for IoFreeController and IoStart
  1418. //
  1419. IoReleaseRemoveLock(&common->RemoveLock, Irp);
  1420. }
  1421. VOID
  1422. I8042TimeOutDpc(
  1423. IN PKDPC Dpc,
  1424. IN PDEVICE_OBJECT DeviceObject,
  1425. IN PVOID SystemContext1,
  1426. IN PVOID SystemContext2
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. This is the driver's command timeout routine. It is called when the
  1431. command timer fires.
  1432. Arguments:
  1433. Dpc - Not Used.
  1434. DeviceObject - Pointer to the device object.
  1435. SystemContext1 - Not Used.
  1436. SystemContext2 - Not Used.
  1437. Return Value:
  1438. None. As a side-effect, the timeout counter is updated and an error
  1439. is logged.
  1440. --*/
  1441. {
  1442. PCOMMON_DATA commonData;
  1443. KIRQL cancelIrql;
  1444. TIMER_CONTEXT timerContext;
  1445. PIRP irp;
  1446. PIO_ERROR_LOG_PACKET errorLogEntry;
  1447. PIO_STACK_LOCATION irpSp;
  1448. LARGE_INTEGER deltaTime;
  1449. ULONG i;
  1450. Print(DBG_DPC_TRACE, ("I8042TimeOutDpc: enter\n"));
  1451. //
  1452. // Get the device extension.
  1453. //
  1454. commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  1455. //
  1456. // Acquire the cancel spinlock, verify that the CurrentIrp has not been
  1457. // cancelled (i.e., CurrentIrp != NULL), set the cancel routine to NULL,
  1458. // and release the cancel spinlock.
  1459. //
  1460. IoAcquireCancelSpinLock(&cancelIrql);
  1461. irp = DeviceObject->CurrentIrp;
  1462. if (irp == NULL) {
  1463. IoReleaseCancelSpinLock(cancelIrql);
  1464. Print(DBG_DPC_TRACE, ("I8042RetriesExceededDpc: exit (NULL irp)\n"));
  1465. return;
  1466. }
  1467. IoSetCancelRoutine(irp, NULL);
  1468. IoReleaseCancelSpinLock(cancelIrql);
  1469. //
  1470. // If the TimerCounter == 0 on entry to this routine, the last packet
  1471. // timed out and was completed. We just decrement TimerCounter
  1472. // (synchronously) to indicate that we're no longer timing.
  1473. //
  1474. // If the TimerCounter indicates no timeout (I8042_ASYNC_NO_TIMEOUT)
  1475. // on entry to this routine, there is no command being timed.
  1476. //
  1477. timerContext.DeviceObject = DeviceObject;
  1478. timerContext.TimerCounter = &Globals.ControllerData->TimerCount;
  1479. KeSynchronizeExecution(
  1480. commonData->InterruptObject,
  1481. (PKSYNCHRONIZE_ROUTINE) I8xDecrementTimer,
  1482. &timerContext
  1483. );
  1484. if (timerContext.NewTimerCount == 0) {
  1485. //
  1486. // Set up the IO Status Block prior to completing the request.
  1487. //
  1488. irp->IoStatus.Information = 0;
  1489. irp->IoStatus.Status = STATUS_IO_TIMEOUT;
  1490. if(Globals.ReportResetErrors == TRUE)
  1491. {
  1492. //
  1493. // Log a timeout error.
  1494. //
  1495. errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
  1496. DeviceObject,
  1497. (UCHAR) (sizeof(IO_ERROR_LOG_PACKET) +
  1498. commonData->CurrentOutput.ByteCount * sizeof(ULONG))
  1499. );
  1500. KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
  1501. if (errorLogEntry != NULL) {
  1502. errorLogEntry->ErrorCode = commonData->IsKeyboard ?
  1503. I8042_TIMEOUT_KBD :
  1504. I8042_TIMEOUT_MOU;
  1505. errorLogEntry->DumpDataSize = (USHORT)
  1506. commonData->CurrentOutput.ByteCount * sizeof(ULONG);
  1507. errorLogEntry->SequenceNumber = commonData->SequenceNumber;
  1508. irpSp = IoGetCurrentIrpStackLocation(irp);
  1509. errorLogEntry->MajorFunctionCode = irpSp->MajorFunction;
  1510. errorLogEntry->IoControlCode =
  1511. irpSp->Parameters.DeviceIoControl.IoControlCode;
  1512. errorLogEntry->RetryCount = (UCHAR) commonData->ResendCount;
  1513. errorLogEntry->UniqueErrorValue = 90;
  1514. errorLogEntry->FinalStatus = STATUS_IO_TIMEOUT;
  1515. if (commonData->CurrentOutput.Bytes) {
  1516. for (i = 0; i < commonData->CurrentOutput.ByteCount; i++) {
  1517. errorLogEntry->DumpData[i] = commonData->CurrentOutput.Bytes[i];
  1518. }
  1519. }
  1520. IoWriteErrorLogEntry(errorLogEntry);
  1521. }
  1522. }
  1523. else{
  1524. KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
  1525. }
  1526. if (commonData->CurrentOutput.Bytes &&
  1527. commonData->CurrentOutput.Bytes != Globals.ControllerData->DefaultBuffer) {
  1528. ExFreePool(commonData->CurrentOutput.Bytes);
  1529. }
  1530. commonData->CurrentOutput.Bytes = NULL;
  1531. KeReleaseSpinLockFromDpcLevel(&Globals.ControllerData->BytesSpinLock);
  1532. I8xCompletePendedRequest(DeviceObject, irp, 0, irp->IoStatus.Status);
  1533. }
  1534. else {
  1535. //
  1536. // Restart the command timer. Once started, the timer stops only
  1537. // when the TimerCount goes to zero (indicating that the command
  1538. // has timed out) or when explicitly cancelled in the completion
  1539. // DPC (indicating that the command has successfully completed).
  1540. //
  1541. deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
  1542. deltaTime.HighPart = -1;
  1543. (VOID) KeSetTimer(
  1544. &Globals.ControllerData->CommandTimer,
  1545. deltaTime,
  1546. &commonData->TimeOutDpc
  1547. );
  1548. }
  1549. Print(DBG_DPC_TRACE, ("I8042TimeOutDpc: exit\n" ));
  1550. }
  1551. VOID
  1552. I8xDecrementTimer(
  1553. IN PTIMER_CONTEXT Context
  1554. )
  1555. /*++
  1556. Routine Description:
  1557. This routine decrements the timeout counter. It is called from
  1558. I8042TimeOutDpc.
  1559. Arguments:
  1560. Context - Points to the context structure containing a pointer
  1561. to the device object and a pointer to the timeout counter.
  1562. Return Value:
  1563. None. As a side-effect, the timeout counter is updated.
  1564. --*/
  1565. {
  1566. PDEVICE_OBJECT deviceObject;
  1567. PCOMMON_DATA commonData;
  1568. deviceObject = Context->DeviceObject;
  1569. commonData = GET_COMMON_DATA(deviceObject->DeviceExtension);
  1570. //
  1571. // Decrement the timeout counter.
  1572. //
  1573. if (*(Context->TimerCounter) != I8042_ASYNC_NO_TIMEOUT)
  1574. (*(Context->TimerCounter))--;
  1575. //
  1576. // Return the decremented timer count in NewTimerCount. The
  1577. // TimerCounter itself could change between the time this KeSynch'ed
  1578. // routine returns to the TimeOutDpc, and the time the TimeOutDpc
  1579. // looks at the value. The TimeOutDpc will use NewTimerCount.
  1580. //
  1581. Context->NewTimerCount = *(Context->TimerCounter);
  1582. //
  1583. // Reset the state and the resend count, if the timeout counter goes to 0.
  1584. //
  1585. if (*(Context->TimerCounter) == 0) {
  1586. commonData->CurrentOutput.State = Idle;
  1587. commonData->ResendCount = 0;
  1588. }
  1589. }
  1590. VOID
  1591. I8xDpcVariableOperation(
  1592. IN PVOID Context
  1593. )
  1594. /*++
  1595. Routine Description:
  1596. This routine is called synchronously by the ISR DPC to perform an
  1597. operation on the InterlockedDpcVariable. The operations that can be
  1598. performed include increment, decrement, write, and read. The ISR
  1599. itself reads and writes the InterlockedDpcVariable without calling this
  1600. routine.
  1601. Arguments:
  1602. Context - Pointer to a structure containing the address of the variable
  1603. to be operated on, the operation to perform, and the address at
  1604. which to copy the resulting value of the variable (the latter is also
  1605. used to pass in the value to write to the variable, on a write
  1606. operation).
  1607. Return Value:
  1608. None.
  1609. --*/
  1610. {
  1611. PVARIABLE_OPERATION_CONTEXT operationContext = Context;
  1612. Print(DBG_DPC_TRACE, ("I8xDpcVariableOperation: enter\n"));
  1613. Print(DBG_DPC_INFO,
  1614. ("\tPerforming %s at 0x%x (current value 0x%x)\n",
  1615. (operationContext->Operation == IncrementOperation)? "increment":
  1616. (operationContext->Operation == DecrementOperation)? "decrement":
  1617. (operationContext->Operation == WriteOperation)? "write":
  1618. (operationContext->Operation == ReadOperation)? "read":"",
  1619. operationContext->VariableAddress,
  1620. *(operationContext->VariableAddress)
  1621. ));
  1622. //
  1623. // Perform the specified operation at the specified address.
  1624. //
  1625. switch(operationContext->Operation) {
  1626. case IncrementOperation:
  1627. *(operationContext->VariableAddress) += 1;
  1628. break;
  1629. case DecrementOperation:
  1630. *(operationContext->VariableAddress) -= 1;
  1631. break;
  1632. case ReadOperation:
  1633. break;
  1634. case WriteOperation:
  1635. Print(DBG_DPC_INFO,
  1636. ("\tWriting 0x%x\n",
  1637. *(operationContext->NewValue)
  1638. ));
  1639. *(operationContext->VariableAddress) =
  1640. *(operationContext->NewValue);
  1641. break;
  1642. default:
  1643. ASSERT(FALSE);
  1644. break;
  1645. }
  1646. *(operationContext->NewValue) = *(operationContext->VariableAddress);
  1647. Print(DBG_DPC_TRACE,
  1648. ("I8xDpcVariableOperation: exit with value 0x%x\n",
  1649. *(operationContext->NewValue)
  1650. ));
  1651. }
  1652. VOID
  1653. I8xGetDataQueuePointer(
  1654. IN PGET_DATA_POINTER_CONTEXT Context
  1655. )
  1656. /*++
  1657. Routine Description:
  1658. This routine is called synchronously to get the current DataIn and DataOut
  1659. pointers for the port InputData queue.
  1660. Arguments:
  1661. Context - Pointer to a structure containing the device extension,
  1662. device type, address at which to store the current DataIn pointer,
  1663. and the address at which to store the current DataOut pointer.
  1664. Return Value:
  1665. None.
  1666. --*/
  1667. {
  1668. PPORT_MOUSE_EXTENSION mouseExtension;
  1669. PPORT_KEYBOARD_EXTENSION kbExtension;
  1670. CCHAR deviceType;
  1671. Print(DBG_CALL_TRACE, ("I8xGetDataQueuePointer: enter\n"));
  1672. //
  1673. // Get address of device extension.
  1674. //
  1675. deviceType = (CCHAR) ((PGET_DATA_POINTER_CONTEXT) Context)->DeviceType;
  1676. //
  1677. // Get the DataIn and DataOut pointers for the indicated device.
  1678. //
  1679. if (deviceType == KeyboardDeviceType) {
  1680. kbExtension = (PPORT_KEYBOARD_EXTENSION) Context->DeviceExtension;
  1681. Print(DBG_CALL_INFO,
  1682. ("I8xGetDataQueuePointer: keyboard\n"
  1683. ));
  1684. Print(DBG_CALL_INFO,
  1685. ("I8xGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
  1686. kbExtension->DataIn,
  1687. kbExtension->DataOut
  1688. ));
  1689. Context->DataIn = kbExtension->DataIn;
  1690. Context->DataOut = kbExtension->DataOut;
  1691. Context->InputCount = kbExtension->InputCount;
  1692. } else if (deviceType == MouseDeviceType) {
  1693. mouseExtension = (PPORT_MOUSE_EXTENSION) Context->DeviceExtension;
  1694. Print(DBG_CALL_INFO,
  1695. ("I8xGetDataQueuePointer: mouse\n"
  1696. ));
  1697. Print(DBG_CALL_INFO,
  1698. ("I8xGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
  1699. mouseExtension->DataIn,
  1700. mouseExtension->DataOut
  1701. ));
  1702. Context->DataIn = mouseExtension->DataIn;
  1703. Context->DataOut = mouseExtension->DataOut;
  1704. Context->InputCount = mouseExtension->InputCount;
  1705. }
  1706. else {
  1707. ASSERT(FALSE);
  1708. }
  1709. Print(DBG_CALL_TRACE, ("I8xGetDataQueuePointer: exit\n"));
  1710. }
  1711. VOID
  1712. I8xInitializeDataQueue (
  1713. IN PI8042_INITIALIZE_DATA_CONTEXT InitializeDataContext
  1714. )
  1715. /*++
  1716. Routine Description:
  1717. This routine initializes the input data queue for the indicated device.
  1718. This routine is called via KeSynchronization, except when called from
  1719. the initialization routine.
  1720. Arguments:
  1721. Context - Pointer to a structure containing the device extension and
  1722. the device type.
  1723. Return Value:
  1724. None.
  1725. --*/
  1726. {
  1727. PPORT_KEYBOARD_EXTENSION kbExtension;
  1728. PPORT_MOUSE_EXTENSION mouseExtension;
  1729. CCHAR deviceType;
  1730. Print(DBG_CALL_TRACE, ("I8xInitializeDataQueue: enter\n"));
  1731. //
  1732. // Get address of device extension.
  1733. //
  1734. deviceType = InitializeDataContext->DeviceType;
  1735. //
  1736. // Initialize the input data queue for the indicated device.
  1737. //
  1738. if (deviceType == KeyboardDeviceType) {
  1739. kbExtension = (PPORT_KEYBOARD_EXTENSION)
  1740. InitializeDataContext->DeviceExtension;
  1741. kbExtension->InputCount = 0;
  1742. kbExtension->DataIn = kbExtension->InputData;
  1743. kbExtension->DataOut = kbExtension->InputData;
  1744. kbExtension->OkayToLogOverflow = TRUE;
  1745. Print(DBG_CALL_INFO, ("I8xInitializeDataQueue: keyboard\n"));
  1746. }
  1747. else if (deviceType == MouseDeviceType) {
  1748. mouseExtension = (PPORT_MOUSE_EXTENSION)
  1749. InitializeDataContext->DeviceExtension;
  1750. mouseExtension->InputCount = 0;
  1751. mouseExtension->DataIn = mouseExtension->InputData;
  1752. mouseExtension->DataOut = mouseExtension->InputData;
  1753. mouseExtension->OkayToLogOverflow = TRUE;
  1754. Print(DBG_CALL_INFO, ("I8xInitializeDataQueue: mouse\n"));
  1755. }
  1756. else {
  1757. ASSERT(FALSE);
  1758. }
  1759. Print(DBG_CALL_TRACE, ("I8xInitializeDataQueue: exit\n"));
  1760. }
  1761. VOID
  1762. I8xLogError(
  1763. IN PDEVICE_OBJECT DeviceObject,
  1764. IN NTSTATUS ErrorCode,
  1765. IN ULONG UniqueErrorValue,
  1766. IN NTSTATUS FinalStatus,
  1767. IN PULONG DumpData,
  1768. IN ULONG DumpCount
  1769. )
  1770. /*++
  1771. Routine Description:
  1772. This routine contains common code to write an error log entry. It is
  1773. called from other routines, especially I8xInitializeKeyboard, to avoid
  1774. duplication of code. Note that some routines continue to have their
  1775. own error logging code (especially in the case where the error logging
  1776. can be localized and/or the routine has more data because there is
  1777. and IRP).
  1778. Arguments:
  1779. DeviceObject - Pointer to the device object.
  1780. ErrorCode - The error code for the error log packet.
  1781. UniqueErrorValue - The unique error value for the error log packet.
  1782. FinalStatus - The final status of the operation for the error log packet.
  1783. DumpData - Pointer to an array of dump data for the error log packet.
  1784. DumpCount - The number of entries in the dump data array.
  1785. Return Value:
  1786. None.
  1787. --*/
  1788. {
  1789. PIO_ERROR_LOG_PACKET errorLogEntry;
  1790. ULONG i;
  1791. errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
  1792. DeviceObject,
  1793. (UCHAR)
  1794. (sizeof(IO_ERROR_LOG_PACKET)
  1795. + (DumpCount * sizeof(ULONG)))
  1796. );
  1797. if (errorLogEntry != NULL) {
  1798. errorLogEntry->ErrorCode = ErrorCode;
  1799. errorLogEntry->DumpDataSize = (USHORT) (DumpCount * sizeof(ULONG));
  1800. errorLogEntry->SequenceNumber = 0;
  1801. errorLogEntry->MajorFunctionCode = 0;
  1802. errorLogEntry->IoControlCode = 0;
  1803. errorLogEntry->RetryCount = 0;
  1804. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  1805. errorLogEntry->FinalStatus = FinalStatus;
  1806. for (i = 0; i < DumpCount; i++)
  1807. errorLogEntry->DumpData[i] = DumpData[i];
  1808. IoWriteErrorLogEntry(errorLogEntry);
  1809. }
  1810. }
  1811. VOID
  1812. I8xSetDataQueuePointer(
  1813. IN PSET_DATA_POINTER_CONTEXT SetDataPointerContext
  1814. )
  1815. /*++
  1816. Routine Description:
  1817. This routine is called synchronously to set the DataOut pointer
  1818. and InputCount for the port InputData queue.
  1819. Arguments:
  1820. Context - Pointer to a structure containing the device extension,
  1821. device type, and the new DataOut value for the port InputData queue.
  1822. Return Value:
  1823. None.
  1824. --*/
  1825. {
  1826. PPORT_MOUSE_EXTENSION mouseExtension;
  1827. PPORT_KEYBOARD_EXTENSION kbExtension;
  1828. CCHAR deviceType;
  1829. Print(DBG_CALL_TRACE, ("I8xSetDataQueuePointer: enter\n"));
  1830. //
  1831. // Get address of device extension.
  1832. //
  1833. deviceType = (CCHAR) SetDataPointerContext->DeviceType;
  1834. //
  1835. // Set the DataOut pointer for the indicated device.
  1836. //
  1837. if (deviceType == KeyboardDeviceType) {
  1838. kbExtension = (PPORT_KEYBOARD_EXTENSION)
  1839. SetDataPointerContext->DeviceExtension;
  1840. Print(DBG_CALL_INFO,
  1841. ("I8xSetDataQueuePointer: old keyboard DataOut 0x%x, InputCount %d\n",
  1842. kbExtension->DataOut,
  1843. kbExtension->InputCount
  1844. ));
  1845. kbExtension->DataOut = SetDataPointerContext->DataOut;
  1846. kbExtension->InputCount -= SetDataPointerContext->InputCount;
  1847. if (kbExtension->InputCount == 0) {
  1848. //
  1849. // Reset the flag that determines whether it is time to log
  1850. // queue overflow errors. We don't want to log errors too often.
  1851. // Instead, log an error on the first overflow that occurs after
  1852. // the ring buffer has been emptied, and then stop logging errors
  1853. // until it gets cleared out and overflows again.
  1854. //
  1855. Print(DBG_CALL_INFO,
  1856. ("I8xSetDataQueuePointer: Okay to log keyboard overflow\n"
  1857. ));
  1858. kbExtension->OkayToLogOverflow = TRUE;
  1859. }
  1860. Print(DBG_CALL_INFO,
  1861. ("I8xSetDataQueuePointer: new keyboard DataOut 0x%x, InputCount %d\n",
  1862. kbExtension->DataOut,
  1863. kbExtension->InputCount
  1864. ));
  1865. } else if (deviceType == MouseDeviceType) {
  1866. mouseExtension = (PPORT_MOUSE_EXTENSION)
  1867. SetDataPointerContext->DeviceExtension;
  1868. Print(DBG_CALL_INFO,
  1869. ("I8xSetDataQueuePointer: old mouse DataOut 0x%x, InputCount %d\n",
  1870. mouseExtension->DataOut,
  1871. mouseExtension->InputCount
  1872. ));
  1873. mouseExtension->DataOut = SetDataPointerContext->DataOut;
  1874. mouseExtension->InputCount -= SetDataPointerContext->InputCount;
  1875. if (mouseExtension->InputCount == 0) {
  1876. //
  1877. // Reset the flag that determines whether it is time to log
  1878. // queue overflow errors. We don't want to log errors too often.
  1879. // Instead, log an error on the first overflow that occurs after
  1880. // the ring buffer has been emptied, and then stop logging errors
  1881. // until it gets cleared out and overflows again.
  1882. //
  1883. Print(DBG_CALL_INFO,
  1884. ("I8xSetDataQueuePointer: Okay to log mouse overflow\n"
  1885. ));
  1886. mouseExtension->OkayToLogOverflow = TRUE;
  1887. }
  1888. Print(DBG_CALL_INFO,
  1889. ("I8xSetDataQueuePointer: new mouse DataOut 0x%x, InputCount %d\n",
  1890. mouseExtension->DataOut,
  1891. mouseExtension->InputCount
  1892. ));
  1893. } else {
  1894. ASSERT(FALSE);
  1895. }
  1896. Print(DBG_CALL_TRACE, ("I8xSetDataQueuePointer: exit\n"));
  1897. }
  1898. #if WRAP_IO_FUNCTIONS
  1899. UCHAR
  1900. NTAPI
  1901. I8xReadRegisterUchar(
  1902. PUCHAR Register
  1903. )
  1904. {
  1905. return READ_REGISTER_UCHAR(Register);
  1906. }
  1907. void
  1908. NTAPI
  1909. I8xWriteRegisterUchar(
  1910. PUCHAR Register,
  1911. UCHAR Value
  1912. )
  1913. {
  1914. WRITE_REGISTER_UCHAR(Register, Value);
  1915. }
  1916. UCHAR
  1917. NTAPI
  1918. I8xReadPortUchar(
  1919. PUCHAR Port
  1920. )
  1921. {
  1922. return READ_PORT_UCHAR(Port);
  1923. }
  1924. void
  1925. NTAPI
  1926. I8xWritePortUchar(
  1927. PUCHAR Port,
  1928. UCHAR Value
  1929. )
  1930. {
  1931. WRITE_PORT_UCHAR(Port, Value);
  1932. }
  1933. #endif // WRAP_IO_FUNCTIONS
  1934. BOOLEAN
  1935. I8xSanityCheckResources(
  1936. VOID
  1937. )
  1938. /*++
  1939. Routine Description:
  1940. Upon receiving the last Start Device IRP, all of the necessary i/o ports are checked
  1941. to see if they exist. If not, try to acquire them the old (non PnP) way.
  1942. Arguments:
  1943. None.
  1944. Return Value:
  1945. None.
  1946. --*/
  1947. {
  1948. ULONG i;
  1949. ULONG interruptVector;
  1950. KIRQL interruptLevel;
  1951. PI8042_CONFIGURATION_INFORMATION configuration;
  1952. CM_PARTIAL_RESOURCE_DESCRIPTOR tmpResourceDescriptor;
  1953. PCM_RESOURCE_LIST resources = NULL;
  1954. ULONG resourceListSize = 0;
  1955. UNICODE_STRING resourceDeviceClass;
  1956. PDEVICE_OBJECT deviceObject = NULL;
  1957. ULONG dumpData[4];
  1958. BOOLEAN conflictDetected;
  1959. BOOLEAN resourcesOK = TRUE;
  1960. PAGED_CODE();
  1961. //
  1962. // If no port configuration information was found and we are at the last
  1963. // added device (in the PnP view of things), use the i8042 defaults.
  1964. //
  1965. configuration = &Globals.ControllerData->Configuration;
  1966. if (configuration->PortListCount == 0) {
  1967. //
  1968. // This state is now taken care of in IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
  1969. // it should never happen!
  1970. //
  1971. return FALSE;
  1972. }
  1973. else if (configuration->PortListCount == 1) {
  1974. //
  1975. // Kludge for Jazz machines. Their ARC firmware neglects to
  1976. // separate out the port addresses, so fix that up here.
  1977. //
  1978. configuration->PortList[DataPort].u.Port.Length = I8042_REGISTER_LENGTH;
  1979. configuration->PortList[CommandPort] = configuration->PortList[DataPort];
  1980. configuration->PortList[CommandPort].u.Port.Start.LowPart +=
  1981. I8042_COMMAND_REGISTER_OFFSET;
  1982. configuration->PortListCount += 1;
  1983. }
  1984. //
  1985. // Put the lowest port address range in the DataPort element of
  1986. // the port list.
  1987. //
  1988. if (configuration->PortList[CommandPort].u.Port.Start.LowPart
  1989. < configuration->PortList[DataPort].u.Port.Start.LowPart) {
  1990. tmpResourceDescriptor = configuration->PortList[DataPort];
  1991. configuration->PortList[DataPort] =
  1992. configuration->PortList[CommandPort];
  1993. configuration->PortList[CommandPort] = tmpResourceDescriptor;
  1994. }
  1995. //
  1996. // Set the DeviceRegister, mapping them if necessary
  1997. //
  1998. if (Globals.ControllerData->DeviceRegisters[0] == NULL) {
  1999. if (Globals.RegistersMapped) {
  2000. Print(DBG_SS_INFO, ("\tMapping registers !!!\n\n"));
  2001. for (i=0; i < Globals.ControllerData->Configuration.PortListCount; i++) {
  2002. Globals.ControllerData->DeviceRegisters[i] = (PUCHAR)
  2003. MmMapIoSpace(
  2004. Globals.ControllerData->Configuration.PortList[i].u.Memory.Start,
  2005. Globals.ControllerData->Configuration.PortList[i].u.Memory.Length,
  2006. MmNonCached
  2007. );
  2008. }
  2009. #if WRAP_IO_FUNCTIONS
  2010. Globals.I8xReadXxxUchar = I8xReadRegisterUchar;
  2011. Globals.I8xWriteXxxUchar = I8xWriteRegisterUchar;
  2012. #else
  2013. Globals.I8xReadXxxUchar = READ_REGISTER_UCHAR;
  2014. Globals.I8xWriteXxxUchar = WRITE_REGISTER_UCHAR;
  2015. #endif
  2016. }
  2017. else {
  2018. for (i=0; i < Globals.ControllerData->Configuration.PortListCount; i++) {
  2019. Globals.ControllerData->DeviceRegisters[i] = (PUCHAR)
  2020. ULongToPtr(Globals.ControllerData->Configuration.PortList[i].u.Port.Start.LowPart);
  2021. }
  2022. #if WRAP_IO_FUNCTIONS
  2023. Globals.I8xReadXxxUchar = I8xReadPortUchar;
  2024. Globals.I8xWriteXxxUchar = I8xWritePortUchar;
  2025. #else
  2026. Globals.I8xReadXxxUchar = READ_PORT_UCHAR;
  2027. Globals.I8xWriteXxxUchar = WRITE_PORT_UCHAR;
  2028. #endif
  2029. }
  2030. }
  2031. for (i = 0; i < configuration->PortListCount; i++) {
  2032. Print(DBG_SS_INFO,
  2033. (" %s, Ports (#%d) 0x%x - 0x%x\n",
  2034. configuration->PortList[i].ShareDisposition
  2035. == CmResourceShareShared ? "Sharable" : "NonSharable",
  2036. i,
  2037. configuration->PortList[i].u.Port.Start.LowPart,
  2038. configuration->PortList[i].u.Port.Start.LowPart +
  2039. configuration->PortList[i].u.Port.Length - 1
  2040. ));
  2041. }
  2042. return TRUE;
  2043. }
  2044. VOID
  2045. I8xInitiateIo(
  2046. IN PDEVICE_OBJECT DeviceObject
  2047. )
  2048. /*++
  2049. Routine Description:
  2050. This routine is called synchronously from I8xKeyboardInitiateWrapper and
  2051. the ISR to initiate an I/O operation for the keyboard device.
  2052. Arguments:
  2053. Context - Pointer to the device object.
  2054. Return Value:
  2055. None.
  2056. --*/
  2057. {
  2058. PCOMMON_DATA commonData;
  2059. PUCHAR bytes;
  2060. Print(DBG_CALL_TRACE, ("I8xInitiateIo: enter\n"));
  2061. //
  2062. // Get the device extension.
  2063. //
  2064. commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
  2065. //
  2066. // Set the timeout value.
  2067. //
  2068. Globals.ControllerData->TimerCount = I8042_ASYNC_TIMEOUT;
  2069. bytes = commonData->CurrentOutput.Bytes;
  2070. //
  2071. // Check to see if we have a valid buffer and we are actually transmitting.
  2072. // We can get a bytes == 0 and State != SendingBytes by timing out a request
  2073. // (a set lights for example) and then receiving the ACK for the request
  2074. // after the cancellation.
  2075. //
  2076. // I don't think we should log an error here because the timeout will have
  2077. // already done so and the relevant errror msg for this is too cryptic
  2078. // for the user to understand.
  2079. //
  2080. if (!bytes || commonData->CurrentOutput.State != SendingBytes) {
  2081. return;
  2082. }
  2083. if (commonData->CurrentOutput.CurrentByte <
  2084. commonData->CurrentOutput.ByteCount) {
  2085. Print(DBG_CALL_INFO,
  2086. ("I8xInitiateIo: sending byte #%d (0x%x)\n",
  2087. commonData->CurrentOutput.CurrentByte,
  2088. bytes[commonData->CurrentOutput.CurrentByte]
  2089. ));
  2090. //
  2091. // Send a byte of a command sequence to the keyboard/mouse
  2092. // asynchronously.
  2093. //
  2094. if (!commonData->IsKeyboard) {
  2095. I8X_WRITE_CMD_TO_MOUSE();
  2096. }
  2097. I8xPutByteAsynchronous(
  2098. (CCHAR) DataPort,
  2099. bytes[commonData->CurrentOutput.CurrentByte++]
  2100. );
  2101. }
  2102. else {
  2103. Print(DBG_CALL_ERROR | DBG_CALL_INFO,
  2104. ("I8xInitiateIo: INVALID REQUEST\n"
  2105. ));
  2106. //
  2107. // Queue a DPC to log an internal driver error.
  2108. //
  2109. KeInsertQueueDpc(
  2110. &commonData->ErrorLogDpc,
  2111. (PIRP) NULL,
  2112. LongToPtr(commonData->IsKeyboard ?
  2113. I8042_INVALID_INITIATE_STATE_KBD :
  2114. I8042_INVALID_INITIATE_STATE_MOU)
  2115. );
  2116. ASSERT(FALSE);
  2117. }
  2118. Print(DBG_CALL_TRACE, ("I8xInitiateIo: exit\n"));
  2119. return;
  2120. }
  2121. VOID
  2122. I8xInitiateOutputWrapper(
  2123. IN PINITIATE_OUTPUT_CONTEXT InitiateContext
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. This routine is called from StartIo synchronously. It sets up the
  2128. CurrentOutput and ResendCount fields in the device extension, and
  2129. then calls I8xKeyboardInitiateIo to do the real work.
  2130. Arguments:
  2131. Context - Pointer to the context structure containing the first and
  2132. last bytes of the send sequence.
  2133. Return Value:
  2134. None.
  2135. --*/
  2136. {
  2137. PDEVICE_OBJECT deviceObject;
  2138. PCOMMON_DATA commonData;
  2139. LARGE_INTEGER li;
  2140. //
  2141. // Get a pointer to the device object from the context argument.
  2142. //
  2143. deviceObject = InitiateContext->DeviceObject;
  2144. //
  2145. // Set up CurrentOutput state for this operation.
  2146. //
  2147. commonData = GET_COMMON_DATA(deviceObject->DeviceExtension);
  2148. commonData->CurrentOutput.Bytes = InitiateContext->Bytes;
  2149. commonData->CurrentOutput.ByteCount = InitiateContext->ByteCount;
  2150. commonData->CurrentOutput.CurrentByte = 0;
  2151. commonData->CurrentOutput.State = SendingBytes;
  2152. //
  2153. // We're starting a new operation, so reset the resend count.
  2154. //
  2155. commonData->ResendCount = 0;
  2156. //
  2157. // Initiate the keyboard I/O operation. Note that we were called
  2158. // using KeSynchronizeExecution, so I8xKeyboardInitiateIo is also
  2159. // synchronized with the keyboard ISR.
  2160. //
  2161. I8xInitiateIo(deviceObject);
  2162. }