VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Mouse/NT4/VBoxPS2NT.cpp@ 71872

Last change on this file since 71872 was 70337, checked in by vboxsync, 7 years ago

VBoxMouseNT: NT 3.1 tweaks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 114.1 KB
Line 
1/* $Id: VBoxPS2NT.cpp 70337 2017-12-24 14:38:58Z vboxsync $ */
2/** @file
3 * VBox NT4 Mouse Driver
4 */
5
6/*
7 * Copyright (C) 2011-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_DRV_MOUSE
19#include <iprt/asm.h>
20#include <VBox/err.h>
21#include <VBox/log.h>
22
23#include <stdarg.h>
24#include <string.h>
25#undef PAGE_SIZE
26#undef PAGE_SHIFT
27#include <iprt/nt/ntddk.h>
28RT_C_DECLS_BEGIN
29#include <ntddkbd.h>
30#include <ntddmou.h>
31RT_C_DECLS_END
32
33#include <VBox/VMMDev.h>
34#include <VBox/VBoxGuestLib.h>
35
36/* not available on NT4 */
37#undef ExFreePool
38#undef ExAllocatePool
39
40/* KeQueryTickCount is a macro accessing KeTickCount data export from NT 3.50+. */
41#if 0 //def TARGET_NT3
42# undef KeQueryTickCount
43extern "C" NTKERNELAPI VOID NTAPI KeQueryTickCount(PLARGE_INTEGER);
44#endif
45
46/* i8042 mouse status bits */
47#define LEFT_BUTTON_DOWN 0x01
48#define RIGHT_BUTTON_DOWN 0x02
49#define MIDDLE_BUTTON_DOWN 0x04
50#define X_DATA_SIGN 0x10
51#define Y_DATA_SIGN 0x20
52#define X_OVERFLOW 0x40
53#define Y_OVERFLOW 0x80
54
55#define MOUSE_SIGN_OVERFLOW_MASK (X_DATA_SIGN | Y_DATA_SIGN | X_OVERFLOW | Y_OVERFLOW)
56
57#define MOUSE_MAXIMUM_POSITIVE_DELTA 0x000000FF
58#define MOUSE_MAXIMUM_NEGATIVE_DELTA 0xFFFFFF00
59
60#define KEYBOARD_HARDWARE_PRESENT 0x01
61#define MOUSE_HARDWARE_PRESENT 0x02
62#define BALLPOINT_HARDWARE_PRESENT 0x04
63#define WHEELMOUSE_HARDWARE_PRESENT 0x08
64
65#define I8X_PUT_COMMAND_BYTE(Address, Byte) WRITE_PORT_UCHAR(Address, (UCHAR) Byte)
66#define I8X_PUT_DATA_BYTE(Address, Byte) WRITE_PORT_UCHAR(Address, (UCHAR) Byte)
67#define I8X_GET_STATUS_BYTE(Address) READ_PORT_UCHAR(Address)
68#define I8X_GET_DATA_BYTE(Address) READ_PORT_UCHAR(Address)
69
70/* commands to the i8042 controller */
71#define I8042_READ_CONTROLLER_COMMAND_BYTE 0x20
72#define I8042_WRITE_CONTROLLER_COMMAND_BYTE 0x60
73#define I8042_DISABLE_MOUSE_DEVICE 0xA7
74#define I8042_ENABLE_MOUSE_DEVICE 0xA8
75#define I8042_AUXILIARY_DEVICE_TEST 0xA9
76#define I8042_KEYBOARD_DEVICE_TEST 0xAB
77#define I8042_DISABLE_KEYBOARD_DEVICE 0xAD
78#define I8042_ENABLE_KEYBOARD_DEVICE 0xAE
79#define I8042_WRITE_TO_AUXILIARY_DEVICE 0xD4
80
81/* i8042 Controller Command Byte */
82#define CCB_ENABLE_KEYBOARD_INTERRUPT 0x01
83#define CCB_ENABLE_MOUSE_INTERRUPT 0x02
84#define CCB_DISABLE_KEYBOARD_DEVICE 0x10
85#define CCB_DISABLE_MOUSE_DEVICE 0x20
86#define CCB_KEYBOARD_TRANSLATE_MODE 0x40
87
88/* i8042 Controller Status Register bits */
89#define OUTPUT_BUFFER_FULL 0x01
90#define INPUT_BUFFER_FULL 0x02
91#define MOUSE_OUTPUT_BUFFER_FULL 0x20
92
93/* i8042 responses */
94#define ACKNOWLEDGE 0xFA
95#define RESEND 0xFE
96
97/* commands to the keyboard (through the 8042 data port) */
98#define SET_KEYBOARD_INDICATORS 0xED
99#define SELECT_SCAN_CODE_SET 0xF0
100#define READ_KEYBOARD_ID 0xF2
101#define SET_KEYBOARD_TYPEMATIC 0xF3
102#define SET_ALL_TYPEMATIC_MAKE_BREAK 0xFA
103#define KEYBOARD_RESET 0xFF
104
105/* commands to the mouse (through the 8042 data port) */
106#define SET_MOUSE_SCALING_1TO1 0xE6
107#define SET_MOUSE_RESOLUTION 0xE8
108#define READ_MOUSE_STATUS 0xE9
109#define GET_DEVICE_ID 0xF2
110#define SET_MOUSE_SAMPLING_RATE 0xF3
111#define ENABLE_MOUSE_TRANSMISSION 0xF4
112#define MOUSE_RESET 0xFF
113
114/* mouse responses */
115#define MOUSE_COMPLETE 0xAA
116#define MOUSE_ID_BYTE 0x00
117#define WHEELMOUSE_ID_BYTE 0x03
118
119/* maximum number of pointer/keyboard port names the port driver */
120#define POINTER_PORTS_MAXIMUM 8
121#define KEYBOARD_PORTS_MAXIMUM 8
122
123/* NtDeviceIoControlFile internal IoControlCode values for keyboard device */
124#define IOCTL_INTERNAL_KEYBOARD_CONNECT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
125#define IOCTL_INTERNAL_KEYBOARD_DISCONNECT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS)
126#define IOCTL_INTERNAL_KEYBOARD_ENABLE CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS)
127#define IOCTL_INTERNAL_KEYBOARD_DISABLE CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS)
128
129/* NtDeviceIoControlFile internal IoControlCode values for mouse device */
130#define IOCTL_INTERNAL_MOUSE_CONNECT CTL_CODE(FILE_DEVICE_MOUSE, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
131#define IOCTL_INTERNAL_MOUSE_DISCONNECT CTL_CODE(FILE_DEVICE_MOUSE, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS)
132#define IOCTL_INTERNAL_MOUSE_ENABLE CTL_CODE(FILE_DEVICE_MOUSE, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS)
133#define IOCTL_INTERNAL_MOUSE_DISABLE CTL_CODE(FILE_DEVICE_MOUSE, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS)
134
135/* i8042 controller input/output ports */
136typedef enum _I8042IOPORTTYPE
137{
138 i8042Dat = 0,
139 i8042Cmd,
140 i8042MaxPorts
141} I8042IOPORTTYPE;
142
143/* device types attached to the i8042 controller */
144typedef enum _I8042DEVTYPE
145{
146 CtrlDevType,
147 KbdDevType,
148 MouDevType,
149 NoDevice
150} I8042DEVTYPE;
151
152/* keyboard output states */
153typedef enum _KBDSTATE
154{
155 Idle,
156 SendFirstByte,
157 SendLastByte
158} KBDSTATE;
159
160/* keyboard scan code input states */
161typedef enum _KBDSCANSTATE
162{
163 Normal,
164 GotE0,
165 GotE1
166} KBDSCANSTATE;
167
168/* mouse states */
169typedef enum _MOUSTATE
170{
171 MouseIdle,
172 XMovement,
173 YMovement,
174 ZMovement,
175 MouseExpectingACK
176} MOUSTATE;
177
178typedef VOID (*PSERVICECALLBACK)(PVOID Ctx, PVOID pArg1, PVOID pArg2, PVOID pArg3);
179
180typedef struct _CONNECT_DATA
181{
182 PDEVICE_OBJECT ClassDeviceObject;
183 PSERVICECALLBACK ClassService;
184} CONNECT_DATA, *PCONNECT_DATA;
185
186typedef struct _KBDSETPACKET
187{
188 USHORT State;
189 UCHAR FirstByte;
190 UCHAR LastByte;
191} KBDSETPACKET, *PKBDSETPACKET;
192
193typedef struct _I8042CFGINF
194{
195 INTERFACE_TYPE InterfaceType; /**< bus interface type */
196 ULONG uBusNr; /**< bus number */
197 ULONG cPorts;
198 CM_PARTIAL_RESOURCE_DESCRIPTOR aPorts[i8042MaxPorts];
199 CM_PARTIAL_RESOURCE_DESCRIPTOR KbdInt;
200 CM_PARTIAL_RESOURCE_DESCRIPTOR MouInt;
201 BOOLEAN fFloatSave; /**< whether to save floating point context */
202 USHORT iResend; /**< number of retries allowed */
203 USHORT PollingIterations; /**< number of polling iterations */
204 USHORT PollingIterationsMaximum;
205 USHORT PollStatusIterations;
206 USHORT StallMicroseconds;
207 KEYBOARD_ATTRIBUTES KbdAttr;
208 KEYBOARD_TYPEMATIC_PARAMETERS KeyRepeatCurrent;
209 KEYBOARD_INDICATOR_PARAMETERS KbdInd;
210 MOUSE_ATTRIBUTES MouAttr;
211 USHORT MouseResolution;
212 ULONG EnableWheelDetection;
213} I8042CFGINF, *PI8042CFGINF;
214
215typedef struct _PORTKBDEXT
216{
217 CONNECT_DATA ConnectData;
218 ULONG cInput;
219 PKEYBOARD_INPUT_DATA InputData;
220 PKEYBOARD_INPUT_DATA DataIn;
221 PKEYBOARD_INPUT_DATA DataOut;
222 PKEYBOARD_INPUT_DATA DataEnd;
223 KEYBOARD_INPUT_DATA CurrentInput;
224 KBDSCANSTATE CurrentScanState;
225 KBDSETPACKET CurrentOutput;
226 USHORT ResendCount;
227 KTIMER DataConsumptionTimer;
228 USHORT UnitId;
229} PORTKBDEXT, *PPORTKBDEXT;
230
231typedef struct _PORTMOUEXT
232{
233 CONNECT_DATA ConnectData;
234 ULONG cInput;
235 PMOUSE_INPUT_DATA InputData;
236 PMOUSE_INPUT_DATA DataIn;
237 PMOUSE_INPUT_DATA DataOut;
238 PMOUSE_INPUT_DATA DataEnd;
239 MOUSE_INPUT_DATA CurrentInput;
240 USHORT InputState;
241 UCHAR uCurrSignAndOverflow;
242 UCHAR uPrevSignAndOverflow;
243 UCHAR PreviousButtons;
244 KTIMER DataConsumptionTimer;
245 LARGE_INTEGER PreviousTick;
246 USHORT UnitId;
247 ULONG SynchTickCount;
248 UCHAR LastByteReceived;
249} PORTMOUEXT, *PPORTMOUEXT;
250
251typedef struct _DEVEXT
252{
253 ULONG HardwarePresent;
254 volatile uint32_t KeyboardEnableCount;
255 volatile uint32_t MouseEnableCount;
256 PDEVICE_OBJECT pDevObj;
257 PUCHAR DevRegs[i8042MaxPorts];
258 PORTKBDEXT KbdExt;
259 PORTMOUEXT MouExt;
260 I8042CFGINF Cfg;
261 PKINTERRUPT KbdIntObj;
262 PKINTERRUPT MouIntObj;
263 KSPIN_LOCK ShIntObj;
264 KDPC RetriesExceededDpc;
265 KDPC KeyboardIsrDpc;
266 KDPC KeyboardIsrDpcRetry;
267 LONG DpcInterlockKeyboard;
268 KDPC MouseIsrDpc;
269 KDPC MouseIsrDpcRetry;
270 LONG DpcInterlockMouse;
271 KDPC TimeOutDpc;
272 KTIMER CommandTimer;
273 LONG TimerCount;
274 BOOLEAN fUnmapRegs;
275 VMMDevReqMouseStatus *pReq;
276} DEVEXT, *PDEVEXT;
277
278typedef struct _INITEXT
279{
280 DEVEXT DevExt;
281} INITEXT, *PINITEXT;
282
283typedef struct _I8042INITDATACTX
284{
285 PDEVEXT pDevExt;
286 int DevType;
287} I8042INITDATACTX, *PI8042INITDATACTX;
288
289typedef struct _I8042TRANSMITCCBCTX
290{
291 ULONG HwDisEnMask;
292 BOOLEAN fAndOp;
293 UCHAR ByteMask;
294 NTSTATUS Status;
295} I8042TRANSMITCCBCTX, *PI8042TRANSMITCCBCTX;
296
297typedef struct _GETDATAPTRCTX
298{
299 PDEVEXT pDevExt;
300 int DevType;
301 PVOID DataIn;
302 PVOID DataOut;
303 ULONG cInput;
304} GETDATAPTRCTX, *PGETDATAPTRCTX;
305
306typedef struct _SETDATAPTRCTX
307{
308 PDEVEXT pDevExt;
309 int DevType;
310 ULONG cInput;
311 PVOID DataOut;
312} SETDATAPTRCTX, *PSETDATAPTRCTX;
313
314typedef struct _TIMERCTX
315{
316 PDEVICE_OBJECT pDevObj;
317 PLONG TimerCounter;
318 LONG NewTimerCount;
319} TIMERCTX, *PTIMERCTX;
320
321typedef struct _KBDINITIATECTX
322{
323 PDEVICE_OBJECT pDevObj;
324 UCHAR FirstByte;
325 UCHAR LastByte;
326} KBDINITIATECTX, *PKBDINITIATECTX;
327
328typedef enum _OPTYPE
329{
330 IncrementOperation,
331 DecrementOperation,
332 WriteOperation,
333} OPTYPE;
334
335typedef struct _VAROPCTX
336{
337 PLONG VariableAddress;
338 OPTYPE Operation;
339 PLONG NewValue;
340} VAROPCTX, *PVAROPCTX;
341
342typedef struct _KBDTYPEINFO
343{
344 USHORT cFunctionKeys;
345 USHORT cIndicators;
346 USHORT cKeysTotal;
347} KBDTYPEINFO;
348
349static const INDICATOR_LIST s_aIndicators[3] =
350{
351 {0x3A, KEYBOARD_CAPS_LOCK_ON},
352 {0x45, KEYBOARD_NUM_LOCK_ON},
353 {0x46, KEYBOARD_SCROLL_LOCK_ON}
354};
355
356static const KBDTYPEINFO s_aKeybType[4] =
357{
358 {10, 3, 84}, /* PC/XT 83- 84-key keyboard (and compatibles) */
359 {12, 3, 102}, /* Olivetti M24 102-key keyboard (and compatibles) */
360 {10, 3, 84}, /* All AT type keyboards (84-86 keys) */
361 {12, 3, 101} /* Enhanced 101- or 102-key keyboards (and compatibles) */
362};
363
364RT_C_DECLS_BEGIN
365static NTSTATUS MouFindWheel(PDEVICE_OBJECT pDevObj);
366static VOID MouGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
367 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName);
368static NTSTATUS MouInitHw(PDEVICE_OBJECT pDevObj);
369static VOID KbdGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
370 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName);
371static NTSTATUS KbdInitHw(PDEVICE_OBJECT pDevObj);
372static VOID HwGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
373 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName);
374static VOID CreateResList(PDEVEXT pDevExt, PCM_RESOURCE_LIST *pResList, PULONG pResListSize);
375static VOID InitHw(PDEVICE_OBJECT pDevObj);
376static NTSTATUS MouCallOut(PVOID pCtx, PUNICODE_STRING PathName,
377 INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
378 CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
379 CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf);
380static NTSTATUS KbdCallOut(PVOID pCtx, PUNICODE_STRING PathName,
381 INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
382 CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
383 CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf);
384/* */ NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING RegistryPath);
385RT_C_DECLS_END
386
387#ifdef ALLOC_PRAGMA
388#pragma alloc_text(INIT,CreateResList)
389#pragma alloc_text(INIT,MouFindWheel)
390#pragma alloc_text(INIT,KbdInitHw)
391#pragma alloc_text(INIT,KbdGetRegstry)
392#pragma alloc_text(INIT,KbdCallOut)
393#pragma alloc_text(INIT,MouInitHw)
394#pragma alloc_text(INIT,MouGetRegstry)
395#pragma alloc_text(INIT,MouCallOut)
396#pragma alloc_text(INIT,InitHw)
397#pragma alloc_text(INIT,HwGetRegstry)
398#pragma alloc_text(INIT,DriverEntry)
399#endif
400
401static BOOLEAN MouDataToQueue(PPORTMOUEXT MouExt, PMOUSE_INPUT_DATA InputData)
402{
403 if ( MouExt->DataIn == MouExt->DataOut
404 && MouExt->cInput)
405 return FALSE;
406
407 *(MouExt->DataIn) = *InputData;
408 MouExt->cInput++;
409 MouExt->DataIn++;
410 if (MouExt->DataIn == MouExt->DataEnd)
411 MouExt->DataIn = MouExt->InputData;
412 return TRUE;
413}
414
415static BOOLEAN KbdDataToQueue(PPORTKBDEXT KbdExt, PKEYBOARD_INPUT_DATA InputData)
416{
417 PKEYBOARD_INPUT_DATA previousDataIn;
418
419 if ( KbdExt->DataIn == KbdExt->DataOut
420 && KbdExt->cInput)
421 {
422 if (KbdExt->DataIn == KbdExt->InputData)
423 previousDataIn = KbdExt->DataEnd;
424 else
425 previousDataIn = KbdExt->DataIn - 1;
426 previousDataIn->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
427 previousDataIn->Flags = 0;
428 return FALSE;
429 }
430
431 *(KbdExt->DataIn) = *InputData;
432 KbdExt->cInput++;
433 KbdExt->DataIn++;
434 if (KbdExt->DataIn == KbdExt->DataEnd)
435 KbdExt->DataIn = KbdExt->InputData;
436 return TRUE;
437}
438
439/**
440 * Queues the current input data to be processed by a DPC outside the ISR
441 */
442static VOID QueueInput(PDEVICE_OBJECT pDevObj)
443{
444 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
445 if (pDevExt->MouseEnableCount)
446 {
447 pDevExt->MouExt.CurrentInput.UnitId = pDevExt->MouExt.UnitId;
448 if (!MouDataToQueue(&pDevExt->MouExt, &pDevExt->MouExt.CurrentInput))
449 {
450 }
451 else if (pDevExt->DpcInterlockMouse >= 0)
452 pDevExt->DpcInterlockMouse++;
453 else
454 KeInsertQueueDpc(&pDevExt->MouseIsrDpc, pDevObj->CurrentIrp, NULL);
455 }
456}
457
458/**
459 * Drain the i8042 controller buffer.
460 */
461static VOID DrainOutBuf(PUCHAR DataAddress, PUCHAR CommandAddress)
462{
463 UCHAR byte;
464 for (unsigned i = 0; i < 2000; i++)
465 {
466 if (!(I8X_GET_STATUS_BYTE(CommandAddress) & INPUT_BUFFER_FULL))
467 break;
468 KeStallExecutionProcessor(500);
469 }
470 while (I8X_GET_STATUS_BYTE(CommandAddress) & OUTPUT_BUFFER_FULL)
471 byte = I8X_GET_DATA_BYTE(DataAddress);
472}
473
474/**
475 * Read a data byte from the controller, keyboard or mouse in polling mode.
476 */
477static NTSTATUS GetBytePoll(int DevType, PDEVEXT pDevExt, PUCHAR Byte)
478{
479 UCHAR byte;
480
481 ULONG i = 0;
482 UCHAR fMask = (DevType == MouDevType) ? (UCHAR)(OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL)
483 : (UCHAR) OUTPUT_BUFFER_FULL;
484 while ( (i < (ULONG)pDevExt->Cfg.PollingIterations)
485 && ((UCHAR)((byte = I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd])) & fMask) != fMask))
486 {
487 if (byte & OUTPUT_BUFFER_FULL)
488 *Byte = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
489 else
490 {
491 KeStallExecutionProcessor(pDevExt->Cfg.StallMicroseconds);
492 i++;
493 }
494 }
495 if (i >= (ULONG)pDevExt->Cfg.PollingIterations)
496 return STATUS_IO_TIMEOUT;
497
498 *Byte = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
499 return STATUS_SUCCESS;
500}
501
502/**
503 * Send a command or data byte to the controller, keyboard or mouse.
504 */
505static NTSTATUS PutBytePoll(CCHAR PortType, BOOLEAN fWaitForAck, int AckDevType, PDEVEXT pDevExt, UCHAR Byte)
506{
507 NTSTATUS status;
508
509 if (AckDevType == MouDevType)
510 {
511 /* switch to AUX device */
512 PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
513 }
514
515 PUCHAR dataAddress = pDevExt->DevRegs[i8042Dat];
516 PUCHAR commandAddress = pDevExt->DevRegs[i8042Cmd];
517 for (unsigned j = 0; j < (unsigned)pDevExt->Cfg.iResend; j++)
518 {
519 unsigned i = 0;
520 while ( i++ < (ULONG)pDevExt->Cfg.PollingIterations
521 && (I8X_GET_STATUS_BYTE(commandAddress) & INPUT_BUFFER_FULL))
522 KeStallExecutionProcessor(pDevExt->Cfg.StallMicroseconds);
523 if (i >= (ULONG)pDevExt->Cfg.PollingIterations)
524 return STATUS_IO_TIMEOUT;
525
526 DrainOutBuf(dataAddress, commandAddress);
527
528 if (PortType == i8042Cmd)
529 I8X_PUT_COMMAND_BYTE(commandAddress, Byte);
530 else
531 I8X_PUT_DATA_BYTE(dataAddress, Byte);
532
533 if (!fWaitForAck)
534 return STATUS_SUCCESS;
535
536 BOOLEAN fKeepTrying = FALSE;
537 UCHAR byte;
538 while ((status = GetBytePoll(AckDevType, pDevExt, &byte)) == STATUS_SUCCESS)
539 {
540 if (byte == ACKNOWLEDGE)
541 break;
542 else if (byte == RESEND)
543 {
544 if (AckDevType == MouDevType)
545 PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
546 fKeepTrying = TRUE;
547 break;
548 }
549 }
550
551 if (!fKeepTrying)
552 return status;
553 }
554
555 return STATUS_IO_TIMEOUT;
556}
557
558/**
559 * Read a byte from controller, keyboard or mouse
560 */
561static VOID GetByteAsync(int DevType, PDEVEXT pDevExt, PUCHAR pByte)
562{
563 UCHAR byte;
564 UCHAR fMask;
565
566 ULONG i = 0;
567 fMask = (DevType == MouDevType)
568 ? (UCHAR) (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL)
569 : (UCHAR) OUTPUT_BUFFER_FULL;
570
571 while ( i < (ULONG)pDevExt->Cfg.PollingIterations
572 && ((UCHAR)((byte = I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd])) & fMask) != fMask))
573 {
574 if (byte & OUTPUT_BUFFER_FULL)
575 *pByte = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
576 else
577 i++;
578 }
579 if (i >= (ULONG)pDevExt->Cfg.PollingIterations)
580 return;
581
582 *pByte = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
583}
584
585/**
586 * Send a command or data byte to the controller, keyboard or mouse
587 * asynchronously.
588 */
589static VOID PutByteAsync(CCHAR PortType, PDEVEXT pDevExt, UCHAR Byte)
590{
591 unsigned i = 0;
592 while (I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & INPUT_BUFFER_FULL)
593 if (i++ >= (ULONG)pDevExt->Cfg.PollingIterations)
594 return;
595
596 if (PortType == i8042Cmd)
597 I8X_PUT_COMMAND_BYTE(pDevExt->DevRegs[i8042Cmd], Byte);
598 else
599 I8X_PUT_DATA_BYTE(pDevExt->DevRegs[i8042Dat], Byte);
600}
601
602/**
603 * Initiaze an I/O operation for the keyboard device.
604 */
605static VOID KbdStartIO(PVOID pCtx)
606{
607 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCtx;
608 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
609
610 pDevExt->TimerCount = 3;
611
612 KBDSETPACKET keyboardPacket = pDevExt->KbdExt.CurrentOutput;
613
614 if (pDevExt->KbdExt.CurrentOutput.State == SendFirstByte)
615 PutByteAsync(i8042Dat, pDevExt, keyboardPacket.FirstByte);
616 else if (pDevExt->KbdExt.CurrentOutput.State == SendLastByte)
617 PutByteAsync(i8042Dat, pDevExt, keyboardPacket.LastByte);
618 else
619 ASSERT(FALSE);
620}
621
622static BOOLEAN KbdStartWrapper(PVOID pCtx)
623{
624 PDEVICE_OBJECT pDevObj = ((PKBDINITIATECTX)pCtx)->pDevObj;
625 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
626 pDevExt->KbdExt.CurrentOutput.State = SendFirstByte;
627 pDevExt->KbdExt.CurrentOutput.FirstByte = ((PKBDINITIATECTX)pCtx)->FirstByte;
628 pDevExt->KbdExt.CurrentOutput.LastByte = ((PKBDINITIATECTX)pCtx)->LastByte;
629 pDevExt->KbdExt.ResendCount = 0;
630 KbdStartIO(pDevObj);
631 return TRUE;
632}
633
634static BOOLEAN DecTimer(PVOID pCtx)
635{
636 PTIMERCTX pTmCtx = (PTIMERCTX)pCtx;
637 PDEVICE_OBJECT pDevObj = pTmCtx->pDevObj;
638 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
639
640 if (*(pTmCtx->TimerCounter) != -1)
641 (*(pTmCtx->TimerCounter))--;
642
643 pTmCtx->NewTimerCount = *(pTmCtx->TimerCounter);
644
645 if (*(pTmCtx->TimerCounter) == 0)
646 {
647 pDevExt->KbdExt.CurrentOutput.State = Idle;
648 pDevExt->KbdExt.ResendCount = 0;
649 }
650 return TRUE;
651}
652
653/**
654 * Perform an operation on the InterlockedDpcVariable.
655 */
656static BOOLEAN DpcVarOp(PVOID pCtx)
657{
658 PVAROPCTX pOpCtx = (PVAROPCTX)pCtx;
659 switch (pOpCtx->Operation)
660 {
661 case IncrementOperation:
662 (*pOpCtx->VariableAddress)++;
663 break;
664 case DecrementOperation:
665 (*pOpCtx->VariableAddress)--;
666 break;
667 case WriteOperation:
668 *pOpCtx->VariableAddress = *pOpCtx->NewValue;
669 break;
670 default:
671 ASSERT(FALSE);
672 break;
673 }
674
675 *(pOpCtx->NewValue) = *(pOpCtx->VariableAddress);
676 return TRUE;
677}
678
679static BOOLEAN GetDataQueuePtr(PVOID pCtx)
680{
681 PDEVEXT pDevExt = (PDEVEXT)((PGETDATAPTRCTX)pCtx)->pDevExt;
682 CCHAR DevType = (CCHAR)((PGETDATAPTRCTX)pCtx)->DevType;
683
684 if (DevType == KbdDevType)
685 {
686 ((PGETDATAPTRCTX)pCtx)->DataIn = pDevExt->KbdExt.DataIn;
687 ((PGETDATAPTRCTX)pCtx)->DataOut = pDevExt->KbdExt.DataOut;
688 ((PGETDATAPTRCTX)pCtx)->cInput = pDevExt->KbdExt.cInput;
689 }
690 else if (DevType == MouDevType)
691 {
692 ((PGETDATAPTRCTX)pCtx)->DataIn = pDevExt->MouExt.DataIn;
693 ((PGETDATAPTRCTX)pCtx)->DataOut = pDevExt->MouExt.DataOut;
694 ((PGETDATAPTRCTX)pCtx)->cInput = pDevExt->MouExt.cInput;
695 }
696 else
697 ASSERT(FALSE);
698 return TRUE;
699}
700
701static BOOLEAN InitDataQueue(PVOID pCtx)
702{
703 PDEVEXT pDevExt = (PDEVEXT)((PI8042INITDATACTX)pCtx)->pDevExt;
704 CCHAR DevType = (CCHAR) ((PI8042INITDATACTX)pCtx)->DevType;
705
706 if (DevType == KbdDevType)
707 {
708 pDevExt->KbdExt.cInput = 0;
709 pDevExt->KbdExt.DataIn = pDevExt->KbdExt.InputData;
710 pDevExt->KbdExt.DataOut = pDevExt->KbdExt.InputData;
711 }
712 else if (DevType == MouDevType)
713 {
714 pDevExt->MouExt.cInput = 0;
715 pDevExt->MouExt.DataIn = pDevExt->MouExt.InputData;
716 pDevExt->MouExt.DataOut = pDevExt->MouExt.InputData;
717 }
718 else
719 ASSERT(FALSE);
720 return TRUE;
721}
722
723static BOOLEAN SetDataQueuePtr(PVOID pCtx)
724{
725 PDEVEXT pDevExt = (PDEVEXT)((PSETDATAPTRCTX)pCtx)->pDevExt;
726 CCHAR DevType = (CCHAR) ((PSETDATAPTRCTX)pCtx)->DevType;
727
728 if (DevType == KbdDevType)
729 {
730 pDevExt->KbdExt.DataOut = (PKEYBOARD_INPUT_DATA)((PSETDATAPTRCTX)pCtx)->DataOut;
731 pDevExt->KbdExt.cInput -= ((PSETDATAPTRCTX)pCtx)->cInput;
732 }
733 else if (DevType == MouDevType)
734 {
735 pDevExt->MouExt.DataOut = (PMOUSE_INPUT_DATA)((PSETDATAPTRCTX)pCtx)->DataOut;
736 pDevExt->MouExt.cInput -= ((PSETDATAPTRCTX)pCtx)->cInput;
737 }
738 else
739 ASSERT(FALSE);
740 return TRUE;
741}
742
743/**
744 * DISPATCH_LEVEL IRQL: Complete requests.
745 */
746static VOID CompleteDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
747{
748 NOREF(Dpc);
749 NOREF(pCtx);
750
751 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
752
753 KeCancelTimer(&pDevExt->CommandTimer);
754
755 Irp = pDevObj->CurrentIrp;
756 ASSERT(Irp);
757
758 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
759 switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
760 {
761 case IOCTL_KEYBOARD_SET_INDICATORS:
762 pDevExt->Cfg.KbdInd = *(PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
763 break;
764
765 case IOCTL_KEYBOARD_SET_TYPEMATIC:
766 pDevExt->Cfg.KeyRepeatCurrent = *(PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
767 break;
768
769 default:
770 break;
771 }
772
773 Irp->IoStatus.Status = STATUS_SUCCESS;
774 IoStartNextPacket(pDevObj, FALSE);
775 IoCompleteRequest (Irp, IO_KEYBOARD_INCREMENT);
776}
777
778static NTSTATUS I8042Flush(PDEVICE_OBJECT pDevObj, PIRP Irp)
779{
780 NOREF(pDevObj);
781 NOREF(Irp);
782
783 return STATUS_NOT_IMPLEMENTED;
784}
785
786/**
787 * Dispatch internal device control requests.
788 */
789static NTSTATUS I8042DevCtrl(PDEVICE_OBJECT pDevObj, PIRP Irp)
790{
791 NTSTATUS status;
792 I8042INITDATACTX initDataCtx;
793 PVOID pParams;
794 PKEYBOARD_ATTRIBUTES KbdAttr;
795 ULONG cbTrans;
796
797 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
798
799 Irp->IoStatus.Information = 0;
800 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
801
802 switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
803 {
804 case IOCTL_INTERNAL_KEYBOARD_CONNECT:
805 if ((pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) != KEYBOARD_HARDWARE_PRESENT)
806 {
807 status = STATUS_NO_SUCH_DEVICE;
808 break;
809 }
810 else if (pDevExt->KbdExt.ConnectData.ClassService)
811 {
812 status = STATUS_SHARING_VIOLATION;
813 break;
814 }
815 else if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
816 {
817 status = STATUS_INVALID_PARAMETER;
818 break;
819 }
820 pDevExt->KbdExt.ConnectData = *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
821 initDataCtx.pDevExt = pDevExt;
822 initDataCtx.DevType = KbdDevType;
823 KeSynchronizeExecution(pDevExt->KbdIntObj, InitDataQueue, &initDataCtx);
824 status = STATUS_SUCCESS;
825 break;
826
827 case IOCTL_INTERNAL_MOUSE_CONNECT:
828 if ((pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT) != MOUSE_HARDWARE_PRESENT)
829 {
830 status = STATUS_NO_SUCH_DEVICE;
831 break;
832 }
833 else if (pDevExt->MouExt.ConnectData.ClassService)
834 {
835 status = STATUS_SHARING_VIOLATION;
836 break;
837 }
838 else if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
839 {
840 status = STATUS_INVALID_PARAMETER;
841 break;
842 }
843 pDevExt->MouExt.ConnectData = *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
844 initDataCtx.pDevExt = pDevExt;
845 initDataCtx.DevType = MouDevType;
846 KeSynchronizeExecution(pDevExt->MouIntObj, InitDataQueue, &initDataCtx);
847 status = STATUS_SUCCESS;
848 break;
849
850 case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
851 case IOCTL_INTERNAL_MOUSE_DISCONNECT:
852 status = STATUS_NOT_IMPLEMENTED;
853 break;
854
855 case IOCTL_INTERNAL_KEYBOARD_ENABLE:
856 case IOCTL_INTERNAL_KEYBOARD_DISABLE:
857 case IOCTL_INTERNAL_MOUSE_ENABLE:
858 case IOCTL_INTERNAL_MOUSE_DISABLE:
859 status = STATUS_PENDING;
860 break;
861
862 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
863 if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_ATTRIBUTES))
864 status = STATUS_BUFFER_TOO_SMALL;
865 else
866 {
867 *(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = pDevExt->Cfg.KbdAttr;
868 Irp->IoStatus.Information = sizeof(KEYBOARD_ATTRIBUTES);
869 status = STATUS_SUCCESS;
870 }
871 break;
872
873 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
874 cbTrans = sizeof(KEYBOARD_INDICATOR_TRANSLATION)
875 + (sizeof(INDICATOR_LIST) * (pDevExt->Cfg.KbdAttr.NumberOfIndicators - 1));
876
877 if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < cbTrans)
878 status = STATUS_BUFFER_TOO_SMALL;
879 else
880 {
881 ((PKEYBOARD_INDICATOR_TRANSLATION)
882 Irp->AssociatedIrp.SystemBuffer)->NumberOfIndicatorKeys = pDevExt->Cfg.KbdAttr.NumberOfIndicators;
883 RtlMoveMemory(((PKEYBOARD_INDICATOR_TRANSLATION)
884 Irp->AssociatedIrp.SystemBuffer)->IndicatorList, (PCHAR)s_aIndicators, cbTrans);
885
886 Irp->IoStatus.Information = cbTrans;
887 status = STATUS_SUCCESS;
888 }
889 break;
890
891 case IOCTL_KEYBOARD_QUERY_INDICATORS:
892 if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
893 status = STATUS_BUFFER_TOO_SMALL;
894 else
895 {
896 *(PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer = pDevExt->Cfg.KbdInd;
897 Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
898 status = STATUS_SUCCESS;
899 }
900 break;
901
902 case IOCTL_KEYBOARD_SET_INDICATORS:
903 if ( (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
904 || ( (((PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->LedFlags
905 & ~(KEYBOARD_SCROLL_LOCK_ON | KEYBOARD_NUM_LOCK_ON | KEYBOARD_CAPS_LOCK_ON)) != 0))
906 status = STATUS_INVALID_PARAMETER;
907 else
908 status = STATUS_PENDING;
909 break;
910
911 case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
912 if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_TYPEMATIC_PARAMETERS))
913 status = STATUS_BUFFER_TOO_SMALL;
914 else
915 {
916 *(PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer = pDevExt->Cfg.KeyRepeatCurrent;
917 Irp->IoStatus.Information = sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
918 status = STATUS_SUCCESS;
919 }
920 break;
921
922 case IOCTL_KEYBOARD_SET_TYPEMATIC:
923 pParams = Irp->AssociatedIrp.SystemBuffer;
924 KbdAttr = &pDevExt->Cfg.KbdAttr;
925 if ( irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)
926 || ((PKEYBOARD_TYPEMATIC_PARAMETERS)pParams)->Rate < KbdAttr->KeyRepeatMinimum.Rate
927 || ((PKEYBOARD_TYPEMATIC_PARAMETERS)pParams)->Rate > KbdAttr->KeyRepeatMaximum.Rate
928 || ((PKEYBOARD_TYPEMATIC_PARAMETERS)pParams)->Delay < KbdAttr->KeyRepeatMinimum.Delay
929 || ((PKEYBOARD_TYPEMATIC_PARAMETERS)pParams)->Delay > KbdAttr->KeyRepeatMaximum.Delay)
930 status = STATUS_INVALID_PARAMETER;
931 else
932 status = STATUS_PENDING;
933 break;
934
935 case IOCTL_MOUSE_QUERY_ATTRIBUTES:
936 if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
937 status = STATUS_BUFFER_TOO_SMALL;
938 else
939 {
940 *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = pDevExt->Cfg.MouAttr;
941
942 Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
943 status = STATUS_SUCCESS;
944 }
945 break;
946
947 default:
948 status = STATUS_INVALID_DEVICE_REQUEST;
949 break;
950 }
951
952 Irp->IoStatus.Status = status;
953 if (status == STATUS_PENDING)
954 {
955 IoMarkIrpPending(Irp);
956 IoStartPacket(pDevObj, Irp, (PULONG)NULL, NULL);
957 }
958 else
959 IoCompleteRequest(Irp, IO_NO_INCREMENT);
960 return status;
961}
962
963/**
964 * Dispatch routine for create/open and close requests.
965 */
966static NTSTATUS I8042OpenClose(PDEVICE_OBJECT pDevObj, PIRP Irp)
967{
968 NOREF(pDevObj);
969
970 Irp->IoStatus.Status = STATUS_SUCCESS;
971 Irp->IoStatus.Information = 0;
972 IoCompleteRequest(Irp, IO_NO_INCREMENT);
973 return STATUS_SUCCESS;
974}
975
976/**
977 * DISPATCH_LEVEL IRQL: Complete requests that have exceeded the maximum
978 * number of retries.
979 */
980static VOID CtrlRetriesExceededDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
981{
982 RT_NOREF(Dpc, pCtx);
983
984 Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
985
986 IoStartNextPacket(pDevObj, FALSE);
987 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
988}
989
990static UCHAR TypematicPeriod[] =
991{
992 31, 31, 28, 26, 23, 20, 18, 17, 15, 13, 12, 11, 10, 9,
993 9, 8, 7, 6, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1
994};
995
996/**
997 * Convert typematic rate/delay to a value expected by the keyboard:
998 * - bit 7 is zero
999 * - bits 5...6 indicate the delay
1000 * - bits 0...4 indicate the rate
1001 */
1002static UCHAR ConvertTypematic(USHORT Rate, USHORT Delay)
1003{
1004 UCHAR value = (UCHAR) ((Delay / 250) - 1);
1005 value <<= 5;
1006 if (Rate <= 27)
1007 value |= TypematicPeriod[Rate];
1008
1009 return value;
1010}
1011
1012/**
1013 * Start an I/O operation for the device.
1014 */
1015static VOID I8042StartIo(PDEVICE_OBJECT pDevObj, PIRP Irp)
1016{
1017 KBDINITIATECTX keyboardInitiateContext;
1018 LARGE_INTEGER deltaTime;
1019 LONG interlockedResult;
1020
1021 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
1022
1023 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
1024 switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
1025 {
1026 case IOCTL_INTERNAL_KEYBOARD_ENABLE:
1027 interlockedResult = ASMAtomicIncU32(&pDevExt->KeyboardEnableCount);
1028 Irp->IoStatus.Status = STATUS_SUCCESS;
1029 IoStartNextPacket(pDevObj, FALSE);
1030 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
1031 break;
1032
1033 case IOCTL_INTERNAL_KEYBOARD_DISABLE:
1034 if (pDevExt->KeyboardEnableCount == 0)
1035 Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
1036 else
1037 {
1038 ASMAtomicDecU32(&pDevExt->KeyboardEnableCount);
1039 Irp->IoStatus.Status = STATUS_SUCCESS;
1040 }
1041 IoStartNextPacket(pDevObj, FALSE);
1042 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
1043 break;
1044
1045 case IOCTL_INTERNAL_MOUSE_ENABLE:
1046 ASMAtomicIncU32(&pDevExt->MouseEnableCount);
1047 Irp->IoStatus.Status = STATUS_SUCCESS;
1048 IoStartNextPacket(pDevObj, FALSE);
1049 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
1050 break;
1051
1052 case IOCTL_INTERNAL_MOUSE_DISABLE:
1053 if (pDevExt->MouseEnableCount == 0)
1054 Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
1055 else
1056 {
1057 ASMAtomicDecU32(&pDevExt->MouseEnableCount);
1058 Irp->IoStatus.Status = STATUS_SUCCESS;
1059 }
1060 IoStartNextPacket(pDevObj, FALSE);
1061 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
1062 break;
1063
1064 case IOCTL_KEYBOARD_SET_INDICATORS:
1065 keyboardInitiateContext.pDevObj = pDevObj;
1066 keyboardInitiateContext.FirstByte = SET_KEYBOARD_INDICATORS;
1067 keyboardInitiateContext.LastByte =
1068 (UCHAR) ((PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->LedFlags;
1069 KeSynchronizeExecution(pDevExt->KbdIntObj, KbdStartWrapper, &keyboardInitiateContext);
1070 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1071 deltaTime.HighPart = -1;
1072 KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
1073 break;
1074
1075 case IOCTL_KEYBOARD_SET_TYPEMATIC:
1076 keyboardInitiateContext.pDevObj = pDevObj;
1077 keyboardInitiateContext.FirstByte = SET_KEYBOARD_TYPEMATIC;
1078 keyboardInitiateContext.LastByte =
1079 ConvertTypematic(((PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->Rate,
1080 ((PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->Delay);
1081
1082 KeSynchronizeExecution(pDevExt->KbdIntObj, KbdStartWrapper, &keyboardInitiateContext);
1083 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1084 deltaTime.HighPart = -1;
1085 KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
1086 break;
1087
1088 default:
1089 ASSERT(FALSE);
1090 break;
1091 }
1092}
1093
1094/**
1095 * Driver's command timeout routine.
1096 */
1097static VOID CtrlTimeoutDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PVOID SystemContext1, PVOID SystemContext2)
1098{
1099 RT_NOREF(Dpc, SystemContext1, SystemContext2);
1100 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
1101
1102 KIRQL cancelIrql;
1103 IoAcquireCancelSpinLock(&cancelIrql);
1104 PIRP irp = pDevObj->CurrentIrp;
1105 if (!irp)
1106 {
1107 IoReleaseCancelSpinLock(cancelIrql);
1108 return;
1109 }
1110 IoSetCancelRoutine(irp, NULL);
1111 IoReleaseCancelSpinLock(cancelIrql);
1112
1113 TIMERCTX timerContext;
1114 timerContext.pDevObj = pDevObj;
1115 timerContext.TimerCounter = &pDevExt->TimerCount;
1116 KeSynchronizeExecution(pDevExt->KbdIntObj, DecTimer, &timerContext);
1117
1118 if (timerContext.NewTimerCount == 0)
1119 {
1120 pDevObj->CurrentIrp->IoStatus.Information = 0;
1121 pDevObj->CurrentIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
1122
1123 IoStartNextPacket(pDevObj, FALSE);
1124 IoCompleteRequest(irp, IO_KEYBOARD_INCREMENT);
1125 }
1126 else
1127 {
1128 LARGE_INTEGER deltaTime;
1129 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1130 deltaTime.HighPart = -1;
1131 KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
1132 }
1133}
1134
1135/**
1136 * DISPATCH_LEVEL IRQL: Finish processing for keyboard interrupts.
1137 */
1138static VOID CtrlKbdIsrDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
1139{
1140 NOREF(Dpc);
1141 NOREF(Irp);
1142 NOREF(pCtx);
1143
1144 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
1145
1146 VAROPCTX opCtx;
1147 LONG interlockedResult;
1148 opCtx.VariableAddress = &pDevExt->DpcInterlockKeyboard;
1149 opCtx.Operation = IncrementOperation;
1150 opCtx.NewValue = &interlockedResult;
1151 KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, (PVOID)&opCtx);
1152 BOOLEAN fContinue = (interlockedResult == 0) ? TRUE : FALSE;
1153
1154 while (fContinue)
1155 {
1156 ULONG cbNotConsumed = 0;
1157 ULONG inputDataConsumed = 0;
1158
1159 GETDATAPTRCTX getPtrCtx;
1160 getPtrCtx.pDevExt = pDevExt;
1161 getPtrCtx.DevType = KbdDevType;
1162 SETDATAPTRCTX setPtrCtx;
1163 setPtrCtx.pDevExt = pDevExt;
1164 setPtrCtx.DevType = KbdDevType;
1165 setPtrCtx.cInput = 0;
1166 KeSynchronizeExecution(pDevExt->KbdIntObj, GetDataQueuePtr, &getPtrCtx);
1167
1168 if (getPtrCtx.cInput)
1169 {
1170 PVOID classDeviceObject = pDevExt->KbdExt.ConnectData.ClassDeviceObject;
1171 PSERVICECALLBACK classService = pDevExt->KbdExt.ConnectData.ClassService;
1172 ASSERT(classService);
1173
1174 if (getPtrCtx.DataOut >= getPtrCtx.DataIn)
1175 {
1176 classService(classDeviceObject, getPtrCtx.DataOut, pDevExt->KbdExt.DataEnd, &inputDataConsumed);
1177 cbNotConsumed = (((PUCHAR) pDevExt->KbdExt.DataEnd - (PUCHAR) getPtrCtx.DataOut)
1178 / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
1179
1180 setPtrCtx.cInput += inputDataConsumed;
1181
1182 if (cbNotConsumed)
1183 {
1184 setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut)
1185 + (inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
1186 }
1187 else
1188 {
1189 setPtrCtx.DataOut = pDevExt->KbdExt.InputData;
1190 getPtrCtx.DataOut = setPtrCtx.DataOut;
1191 }
1192 }
1193
1194 if ( cbNotConsumed == 0
1195 && inputDataConsumed < getPtrCtx.cInput)
1196 {
1197 classService(classDeviceObject, getPtrCtx.DataOut, getPtrCtx.DataIn, &inputDataConsumed);
1198 cbNotConsumed = (((PUCHAR) getPtrCtx.DataIn - (PUCHAR) getPtrCtx.DataOut)
1199 / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
1200
1201 setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) +
1202 (inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
1203 setPtrCtx.cInput += inputDataConsumed;
1204 }
1205
1206 KeSynchronizeExecution(pDevExt->KbdIntObj, SetDataQueuePtr, &setPtrCtx);
1207 }
1208
1209 if (cbNotConsumed)
1210 {
1211 opCtx.Operation = WriteOperation;
1212 interlockedResult = -1;
1213 opCtx.NewValue = &interlockedResult;
1214 KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
1215
1216 LARGE_INTEGER deltaTime;
1217 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1218 deltaTime.HighPart = -1;
1219 KeSetTimer(&pDevExt->KbdExt.DataConsumptionTimer, deltaTime, &pDevExt->KeyboardIsrDpcRetry);
1220 fContinue = FALSE;
1221 }
1222 else
1223 {
1224 opCtx.Operation = DecrementOperation;
1225 opCtx.NewValue = &interlockedResult;
1226 KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
1227 if (interlockedResult != -1)
1228 {
1229 opCtx.Operation = WriteOperation;
1230 interlockedResult = 0;
1231 opCtx.NewValue = &interlockedResult;
1232 KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
1233 }
1234 else
1235 fContinue = FALSE;
1236 }
1237 }
1238}
1239
1240/**
1241 * DISPATCH_LEVEL IRQL: Finish processing of mouse interrupts
1242 */
1243static VOID CtrlMouIsrDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
1244{
1245 NOREF(Dpc);
1246 NOREF(Irp);
1247 NOREF(pCtx);
1248
1249 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
1250
1251 VAROPCTX opCtx;
1252 LONG interlockedResult;
1253 opCtx.VariableAddress = &pDevExt->DpcInterlockMouse;
1254 opCtx.Operation = IncrementOperation;
1255 opCtx.NewValue = &interlockedResult;
1256 KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
1257 BOOLEAN fContinue = (interlockedResult == 0) ? TRUE : FALSE;
1258 while (fContinue)
1259 {
1260 ULONG cbNotConsumed = 0;
1261 ULONG inputDataConsumed = 0;
1262
1263 GETDATAPTRCTX getPtrCtx;
1264 getPtrCtx.pDevExt = pDevExt;
1265 getPtrCtx.DevType = MouDevType;
1266 SETDATAPTRCTX setPtrCtx;
1267 setPtrCtx.pDevExt = pDevExt;
1268 setPtrCtx.DevType = MouDevType;
1269 setPtrCtx.cInput = 0;
1270 KeSynchronizeExecution(pDevExt->MouIntObj, GetDataQueuePtr, &getPtrCtx);
1271 if (getPtrCtx.cInput)
1272 {
1273 PVOID classDeviceObject = pDevExt->MouExt.ConnectData.ClassDeviceObject;
1274 PSERVICECALLBACK classService = pDevExt->MouExt.ConnectData.ClassService;
1275 ASSERT(classService);
1276
1277 if (getPtrCtx.DataOut >= getPtrCtx.DataIn)
1278 {
1279 classService(classDeviceObject, getPtrCtx.DataOut, pDevExt->MouExt.DataEnd, &inputDataConsumed);
1280 cbNotConsumed = (((PUCHAR)pDevExt->MouExt.DataEnd - (PUCHAR) getPtrCtx.DataOut)
1281 / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
1282
1283 setPtrCtx.cInput += inputDataConsumed;
1284 if (cbNotConsumed)
1285 {
1286 setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) + (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
1287 }
1288 else
1289 {
1290 setPtrCtx.DataOut = pDevExt->MouExt.InputData;
1291 getPtrCtx.DataOut = setPtrCtx.DataOut;
1292 }
1293 }
1294
1295 if ( cbNotConsumed == 0
1296 && inputDataConsumed < getPtrCtx.cInput)
1297 {
1298 classService(classDeviceObject, getPtrCtx.DataOut, getPtrCtx.DataIn, &inputDataConsumed);
1299 cbNotConsumed = (((PUCHAR) getPtrCtx.DataIn - (PUCHAR) getPtrCtx.DataOut)
1300 / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
1301
1302 setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) + (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
1303 setPtrCtx.cInput += inputDataConsumed;
1304 }
1305 KeSynchronizeExecution(pDevExt->MouIntObj, SetDataQueuePtr, &setPtrCtx);
1306 }
1307
1308 if (cbNotConsumed)
1309 {
1310 opCtx.Operation = WriteOperation;
1311 interlockedResult = -1;
1312 opCtx.NewValue = &interlockedResult;
1313 KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
1314
1315 LARGE_INTEGER deltaTime;
1316 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1317 deltaTime.HighPart = -1;
1318 KeSetTimer(&pDevExt->MouExt.DataConsumptionTimer, deltaTime, &pDevExt->MouseIsrDpcRetry);
1319 fContinue = FALSE;
1320 }
1321 else
1322 {
1323 opCtx.Operation = DecrementOperation;
1324 opCtx.NewValue = &interlockedResult;
1325 KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
1326
1327 if (interlockedResult != -1)
1328 {
1329 opCtx.Operation = WriteOperation;
1330 interlockedResult = 0;
1331 opCtx.NewValue = &interlockedResult;
1332 KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
1333 }
1334 else
1335 fContinue = FALSE;
1336 }
1337 }
1338}
1339
1340/**
1341 * Interrupt service routine for the mouse device.
1342 */
1343static BOOLEAN MouIntHandler(PKINTERRUPT Interrupt, PVOID pCtx)
1344{
1345 UCHAR uPrevSignAndOverflow;
1346
1347 NOREF(Interrupt);
1348
1349 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCtx;
1350 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
1351
1352 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1353 != (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1354 {
1355 KeStallExecutionProcessor(10);
1356 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1357 != (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1358 return FALSE;
1359 }
1360
1361 UCHAR byte;
1362 GetByteAsync(MouDevType, pDevExt, &byte);
1363
1364 if ( pDevExt->MouExt.LastByteReceived == 0xaa
1365 && byte == 0x00)
1366 {
1367 pDevExt->HardwarePresent &= ~WHEELMOUSE_HARDWARE_PRESENT;
1368 pDevExt->Cfg.MouAttr.NumberOfButtons = 2;
1369
1370 PutByteAsync(i8042Cmd, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
1371 PutByteAsync(i8042Dat, pDevExt, ENABLE_MOUSE_TRANSMISSION);
1372
1373 pDevExt->MouExt.InputState = MouseExpectingACK;
1374 }
1375
1376 pDevExt->MouExt.LastByteReceived = byte;
1377
1378 LARGE_INTEGER tickDelta, newTick;
1379 KeQueryTickCount(&newTick);
1380 tickDelta.QuadPart = newTick.QuadPart - pDevExt->MouExt.PreviousTick.QuadPart;
1381 if ( pDevExt->MouExt.InputState != MouseIdle
1382 && pDevExt->MouExt.InputState != MouseExpectingACK
1383 && (tickDelta.LowPart >= pDevExt->MouExt.SynchTickCount || tickDelta.HighPart != 0))
1384 pDevExt->MouExt.InputState = MouseIdle;
1385 pDevExt->MouExt.PreviousTick = newTick;
1386
1387 switch (pDevExt->MouExt.InputState)
1388 {
1389 case MouseIdle:
1390 {
1391 UCHAR fPrevBtns = pDevExt->MouExt.PreviousButtons;
1392 pDevExt->MouExt.CurrentInput.ButtonFlags = 0;
1393 pDevExt->MouExt.CurrentInput.ButtonData = 0;
1394
1395 if ((!(fPrevBtns & LEFT_BUTTON_DOWN)) && (byte & LEFT_BUTTON_DOWN))
1396 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
1397 else if ((fPrevBtns & LEFT_BUTTON_DOWN) && !(byte & LEFT_BUTTON_DOWN))
1398 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
1399 if ((!(fPrevBtns & RIGHT_BUTTON_DOWN)) && (byte & RIGHT_BUTTON_DOWN))
1400 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
1401 else if ((fPrevBtns & RIGHT_BUTTON_DOWN) && !(byte & RIGHT_BUTTON_DOWN))
1402 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
1403 if ((!(fPrevBtns & MIDDLE_BUTTON_DOWN)) && (byte & MIDDLE_BUTTON_DOWN))
1404 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
1405 else if ((fPrevBtns & MIDDLE_BUTTON_DOWN) && !(byte & MIDDLE_BUTTON_DOWN))
1406 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
1407
1408 pDevExt->MouExt.PreviousButtons = byte & (RIGHT_BUTTON_DOWN|MIDDLE_BUTTON_DOWN|LEFT_BUTTON_DOWN);
1409 pDevExt->MouExt.uCurrSignAndOverflow = (UCHAR) (byte & MOUSE_SIGN_OVERFLOW_MASK);
1410 pDevExt->MouExt.InputState = XMovement;
1411 break;
1412 }
1413
1414 case XMovement:
1415 {
1416 if (pDevExt->MouExt.uCurrSignAndOverflow & X_OVERFLOW)
1417 {
1418 uPrevSignAndOverflow = pDevExt->MouExt.uPrevSignAndOverflow;
1419 if (uPrevSignAndOverflow & X_OVERFLOW)
1420 {
1421 if ((uPrevSignAndOverflow & X_DATA_SIGN) != (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN))
1422 pDevExt->MouExt.uCurrSignAndOverflow ^= X_DATA_SIGN;
1423 }
1424 if (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN)
1425 pDevExt->MouExt.CurrentInput.LastX = MOUSE_MAXIMUM_NEGATIVE_DELTA;
1426 else
1427 pDevExt->MouExt.CurrentInput.LastX = MOUSE_MAXIMUM_POSITIVE_DELTA;
1428 }
1429 else
1430 {
1431 pDevExt->MouExt.CurrentInput.LastX = (ULONG) byte;
1432 if (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN)
1433 pDevExt->MouExt.CurrentInput.LastX |= MOUSE_MAXIMUM_NEGATIVE_DELTA;
1434 }
1435 pDevExt->MouExt.InputState = YMovement;
1436 break;
1437 }
1438
1439 case YMovement:
1440 {
1441 if (pDevExt->MouExt.uCurrSignAndOverflow & Y_OVERFLOW)
1442 {
1443 uPrevSignAndOverflow = pDevExt->MouExt.uPrevSignAndOverflow;
1444 if (uPrevSignAndOverflow & Y_OVERFLOW)
1445 {
1446 if ((uPrevSignAndOverflow & Y_DATA_SIGN) != (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN))
1447 pDevExt->MouExt.uCurrSignAndOverflow ^= Y_DATA_SIGN;
1448 }
1449 if (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN)
1450 pDevExt->MouExt.CurrentInput.LastY = MOUSE_MAXIMUM_POSITIVE_DELTA;
1451 else
1452 pDevExt->MouExt.CurrentInput.LastY = MOUSE_MAXIMUM_NEGATIVE_DELTA;
1453 }
1454 else
1455 {
1456 pDevExt->MouExt.CurrentInput.LastY = (ULONG) byte;
1457 if (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN)
1458 pDevExt->MouExt.CurrentInput.LastY |= MOUSE_MAXIMUM_NEGATIVE_DELTA;
1459 pDevExt->MouExt.CurrentInput.LastY = -pDevExt->MouExt.CurrentInput.LastY;
1460 }
1461 pDevExt->MouExt.uPrevSignAndOverflow = pDevExt->MouExt.uCurrSignAndOverflow;
1462
1463 if (pDevExt->HardwarePresent & WHEELMOUSE_HARDWARE_PRESENT)
1464 pDevExt->MouExt.InputState = ZMovement;
1465 else
1466 {
1467 pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_RELATIVE;
1468
1469 {
1470 VMMDevReqMouseStatus *pReq = pDevExt->pReq;
1471 if (pReq)
1472 {
1473 int rc = VbglR0GRPerform (&pReq->header);
1474 if (RT_SUCCESS(rc))
1475 {
1476 if (pReq->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
1477 {
1478 /* make it an absolute move */
1479 pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_ABSOLUTE;
1480 pDevExt->MouExt.CurrentInput.LastX = pReq->pointerXPos;
1481 pDevExt->MouExt.CurrentInput.LastY = pReq->pointerYPos;
1482 }
1483 }
1484 else
1485 Log(("VBoxMouseNT: ERROR querying mouse capabilities from VMMDev. rc = %Rrc\n", rc));
1486 }
1487 }
1488 QueueInput(pDevObj);
1489 pDevExt->MouExt.InputState = MouseIdle;
1490 }
1491 break;
1492 }
1493
1494 case ZMovement:
1495 {
1496#if 0
1497 if (byte && pDevExt->MouExt.CurrentInput.Buttons == 0)
1498#else
1499 if (byte)
1500#endif
1501 {
1502 if (byte & 0x80)
1503 pDevExt->MouExt.CurrentInput.ButtonData = 0x0078;
1504 else
1505 pDevExt->MouExt.CurrentInput.ButtonData = 0xFF88;
1506 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_WHEEL;
1507 }
1508
1509 pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_RELATIVE;
1510
1511 {
1512 VMMDevReqMouseStatus *pReq = pDevExt->pReq;
1513 if (pReq)
1514 {
1515 int rc = VbglR0GRPerform(&pReq->header);
1516 if (RT_SUCCESS(rc))
1517 {
1518 if (pReq->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
1519 {
1520 /* make it an absolute move */
1521 pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_ABSOLUTE;
1522 pDevExt->MouExt.CurrentInput.LastX = pReq->pointerXPos;
1523 pDevExt->MouExt.CurrentInput.LastY = pReq->pointerYPos;
1524 }
1525 }
1526 else
1527 Log(("VBoxMouseNT: ERROR querying mouse capabilities from VMMDev. rc = %Rrc\n", rc));
1528 }
1529 }
1530
1531 QueueInput(pDevObj);
1532 pDevExt->MouExt.InputState = MouseIdle;
1533 break;
1534 }
1535
1536 case MouseExpectingACK:
1537 {
1538 if (byte == ACKNOWLEDGE)
1539 pDevExt->MouExt.InputState = MouseIdle;
1540 else if (byte == RESEND)
1541 {
1542 PutByteAsync(i8042Cmd, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
1543 PutByteAsync(i8042Dat, pDevExt, ENABLE_MOUSE_TRANSMISSION);
1544 }
1545 break;
1546 }
1547
1548 default:
1549 {
1550 ASSERT(FALSE);
1551 break;
1552 }
1553 }
1554
1555 return TRUE;
1556}
1557
1558/**
1559 * Interrupt service routine.
1560 */
1561static BOOLEAN KbdIntHandler(PKINTERRUPT Interrupt, PVOID pCtx)
1562{
1563 NOREF(Interrupt);
1564
1565 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCtx;
1566 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
1567
1568 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1569 != OUTPUT_BUFFER_FULL)
1570 {
1571 for (unsigned i = 0; i < (ULONG)pDevExt->Cfg.PollStatusIterations; i++)
1572 {
1573 KeStallExecutionProcessor(1);
1574 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1575 == (OUTPUT_BUFFER_FULL))
1576 break;
1577 }
1578
1579 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1580 != (OUTPUT_BUFFER_FULL))
1581 {
1582 if (pDevExt->KeyboardEnableCount == 0)
1583 {
1584 UCHAR scanCode = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
1585 NOREF(scanCode);
1586 }
1587 return FALSE;
1588 }
1589 }
1590
1591 UCHAR scanCode;
1592 GetByteAsync(KbdDevType, pDevExt, &scanCode);
1593 switch (scanCode)
1594 {
1595 case RESEND:
1596 if (pDevExt->TimerCount == 0)
1597 break;
1598 pDevExt->TimerCount = -1;
1599
1600 if ( pDevExt->KbdExt.CurrentOutput.State==Idle
1601 || !pDevObj->CurrentIrp)
1602 goto ScanCodeCase;
1603 else if (pDevExt->KbdExt.ResendCount < pDevExt->Cfg.iResend)
1604 {
1605 pDevExt->KbdExt.ResendCount++;
1606 KbdStartIO(pDevObj);
1607 }
1608 else
1609 {
1610 pDevExt->KbdExt.CurrentOutput.State = Idle;
1611 KeInsertQueueDpc(&pDevExt->RetriesExceededDpc, pDevObj->CurrentIrp, NULL);
1612 }
1613 break;
1614
1615 case ACKNOWLEDGE:
1616 if (pDevExt->TimerCount == 0)
1617 break;
1618
1619 pDevExt->TimerCount = -1;
1620
1621 pDevExt->KbdExt.ResendCount = 0;
1622 if (pDevExt->KbdExt.CurrentOutput.State == SendFirstByte)
1623 {
1624 pDevExt->KbdExt.CurrentOutput.State = SendLastByte;
1625 KbdStartIO(pDevObj);
1626 }
1627 else if (pDevExt->KbdExt.CurrentOutput.State == SendLastByte)
1628 {
1629 pDevExt->KbdExt.CurrentOutput.State = Idle;
1630 IoRequestDpc(pDevObj, pDevObj->CurrentIrp, NULL);
1631 }
1632 break;
1633
1634 ScanCodeCase:
1635 default:
1636 {
1637 PKEYBOARD_INPUT_DATA input = &pDevExt->KbdExt.CurrentInput;
1638 KBDSCANSTATE *pScanState = &pDevExt->KbdExt.CurrentScanState;
1639
1640 if (scanCode == (UCHAR) 0xFF)
1641 {
1642 input->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
1643 input->Flags = 0;
1644 *pScanState = Normal;
1645 }
1646 else
1647 {
1648 switch (*pScanState)
1649 {
1650 case Normal:
1651 if (scanCode == (UCHAR) 0xE0)
1652 {
1653 input->Flags |= KEY_E0;
1654 *pScanState = GotE0;
1655 break;
1656 }
1657 else if (scanCode == (UCHAR) 0xE1)
1658 {
1659 input->Flags |= KEY_E1;
1660 *pScanState = GotE1;
1661 break;
1662 }
1663 /* fall through */
1664 case GotE0:
1665 case GotE1:
1666 if (scanCode > 0x7F)
1667 {
1668 input->MakeCode = scanCode & 0x7F;
1669 input->Flags |= KEY_BREAK;
1670 }
1671 else
1672 input->MakeCode = scanCode;
1673 *pScanState = Normal;
1674 break;
1675
1676 default:
1677 ASSERT(FALSE);
1678 break;
1679 }
1680 }
1681
1682 if (*pScanState == Normal)
1683 {
1684 if (pDevExt->KeyboardEnableCount)
1685 {
1686 pDevExt->KbdExt.CurrentInput.UnitId = pDevExt->KbdExt.UnitId;
1687 if (!KbdDataToQueue(&pDevExt->KbdExt, input))
1688 {
1689 }
1690 else if (pDevExt->DpcInterlockKeyboard >= 0)
1691 pDevExt->DpcInterlockKeyboard++;
1692 else
1693 KeInsertQueueDpc(&pDevExt->KeyboardIsrDpc, pDevObj->CurrentIrp, NULL);
1694 }
1695 input->Flags = 0;
1696 }
1697 break;
1698 }
1699 }
1700 return TRUE;
1701}
1702
1703static NTSTATUS MouEnableTrans(PDEVICE_OBJECT pDevObj)
1704{
1705 NTSTATUS status;
1706
1707 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
1708 status = PutBytePoll(i8042Dat, FALSE /*=wait*/, MouDevType, pDevExt, ENABLE_MOUSE_TRANSMISSION);
1709 return status;
1710}
1711
1712/**
1713 * Configuration information for the keyboard.
1714 */
1715static VOID KbdGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
1716 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
1717{
1718 PDEVEXT pDevExt = &pInit->DevExt;
1719 for (unsigned i = 0; i < MaximumInterfaceType; i++)
1720 {
1721 INTERFACE_TYPE interfaceType = (INTERFACE_TYPE)i;
1722 CONFIGURATION_TYPE controllerType = KeyboardController;
1723 CONFIGURATION_TYPE peripheralType = KeyboardPeripheral;
1724 NTSTATUS status = IoQueryDeviceDescription(&interfaceType, NULL,
1725 &controllerType, NULL,
1726 &peripheralType, NULL,
1727 KbdCallOut, pInit);
1728 NOREF(status); /* how diligent of us */
1729
1730 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
1731 {
1732 HwGetRegstry(pInit, RegistryPath, KeyboardDeviceName, PointerDeviceName);
1733
1734 PI8042CFGINF pCfg = &pInit->DevExt.Cfg;
1735 PKEYBOARD_ID keyboardId = &pCfg->KbdAttr.KeyboardIdentifier;
1736 if (!ENHANCED_KEYBOARD(*keyboardId))
1737 pCfg->PollingIterations = pCfg->PollingIterationsMaximum;
1738
1739 pCfg->KbdAttr.NumberOfFunctionKeys = s_aKeybType[keyboardId->Type-1].cFunctionKeys;
1740 pCfg->KbdAttr.NumberOfIndicators = s_aKeybType[keyboardId->Type-1].cIndicators;
1741 pCfg->KbdAttr.NumberOfKeysTotal = s_aKeybType[keyboardId->Type-1].cKeysTotal;
1742 pCfg->KbdAttr.KeyboardMode = 1;
1743 pCfg->KbdAttr.KeyRepeatMinimum.Rate = 2;
1744 pCfg->KbdAttr.KeyRepeatMinimum.Delay = 250;
1745 pCfg->KbdAttr.KeyRepeatMaximum.Rate = 30;
1746 pCfg->KbdAttr.KeyRepeatMaximum.Delay = 1000;
1747 pCfg->KeyRepeatCurrent.Rate = 30;
1748 pCfg->KeyRepeatCurrent.Delay = 250;
1749 break;
1750 }
1751 }
1752}
1753
1754/**
1755 * Retrieve the configuration information for the mouse.
1756 */
1757static VOID MouGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
1758 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
1759{
1760 NTSTATUS status = STATUS_SUCCESS;
1761 INTERFACE_TYPE interfaceType;
1762 CONFIGURATION_TYPE controllerType = PointerController;
1763 CONFIGURATION_TYPE peripheralType = PointerPeripheral;
1764
1765 for (unsigned i = 0; i < MaximumInterfaceType; i++)
1766 {
1767 interfaceType = (INTERFACE_TYPE)i;
1768 status = IoQueryDeviceDescription(&interfaceType, NULL,
1769 &controllerType, NULL,
1770 &peripheralType, NULL,
1771 MouCallOut, pInit);
1772
1773 if (pInit->DevExt.HardwarePresent & MOUSE_HARDWARE_PRESENT)
1774 {
1775 if (!(pInit->DevExt.HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
1776 HwGetRegstry(pInit, RegistryPath, KeyboardDeviceName, PointerDeviceName);
1777 pInit->DevExt.Cfg.MouAttr.MouseIdentifier = MOUSE_I8042_HARDWARE;
1778 break;
1779 }
1780 }
1781}
1782
1783/**
1784 * Initialize the driver.
1785 */
1786NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING RegistryPath)
1787{
1788 PDEVICE_OBJECT pPortDevObj = NULL;
1789 PDEVEXT pDevExt = NULL;
1790 NTSTATUS status = STATUS_SUCCESS;
1791 KIRQL IrqlCoord = 0;
1792 ULONG IntVecKbd;
1793 ULONG IntVecMou;
1794 KIRQL IrqlKbd;
1795 KIRQL IrqlMou;
1796 KAFFINITY AffKbd;
1797 KAFFINITY AffMou;
1798 ULONG addressSpace;
1799 PHYSICAL_ADDRESS Phys;
1800 BOOLEAN fConflict;
1801
1802 ULONG resourceListSize = 0;
1803 PCM_RESOURCE_LIST resources = NULL;
1804
1805 UNICODE_STRING KbdNameFull = { 0, 0, NULL };
1806 UNICODE_STRING MouNameFull = { 0, 0, NULL };
1807 UNICODE_STRING KbdNameBase = { 0, 0, NULL };
1808 UNICODE_STRING MouNameBase = { 0, 0, NULL };
1809 UNICODE_STRING DevNameSuff = { 0, 0, NULL };
1810 UNICODE_STRING resourceDeviceClass = { 0, 0, NULL };
1811 UNICODE_STRING registryPath = { 0, 0, NULL };
1812
1813#define NAME_MAX 256
1814 WCHAR keyboardBuffer[NAME_MAX];
1815 WCHAR pointerBuffer[NAME_MAX];
1816
1817 LogFlow(("VBoxMouseNT::DriverEntry: enter\n"));
1818
1819 PINITEXT pInit = (PINITEXT)ExAllocatePool(NonPagedPool, sizeof(INITEXT));
1820 if (!pInit)
1821 {
1822 status = STATUS_UNSUCCESSFUL;
1823 goto fail;
1824 }
1825
1826 RtlZeroMemory(pInit, sizeof(INITEXT));
1827 RtlZeroMemory(keyboardBuffer, NAME_MAX * sizeof(WCHAR));
1828 KbdNameBase.Buffer = keyboardBuffer;
1829 KbdNameBase.Length = 0;
1830 KbdNameBase.MaximumLength = NAME_MAX * sizeof(WCHAR);
1831 RtlZeroMemory(pointerBuffer, NAME_MAX * sizeof(WCHAR));
1832 MouNameBase.Buffer = pointerBuffer;
1833 MouNameBase.Length = 0;
1834 MouNameBase.MaximumLength = NAME_MAX * sizeof(WCHAR);
1835
1836 registryPath.Buffer = (PWSTR)ExAllocatePool(PagedPool, RegistryPath->Length + sizeof(UNICODE_NULL));
1837 if (!registryPath.Buffer)
1838 {
1839 status = STATUS_UNSUCCESSFUL;
1840 goto fail;
1841 }
1842 else
1843 {
1844 registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
1845 registryPath.MaximumLength = registryPath.Length;
1846
1847 RtlZeroMemory(registryPath.Buffer, registryPath.Length);
1848 RtlMoveMemory(registryPath.Buffer, RegistryPath->Buffer, RegistryPath->Length);
1849 }
1850
1851 KbdGetRegstry(pInit, &registryPath, &KbdNameBase, &MouNameBase);
1852 MouGetRegstry(pInit, &registryPath, &KbdNameBase, &MouNameBase);
1853 if (pInit->DevExt.HardwarePresent == 0)
1854 {
1855 status = STATUS_NO_SUCH_DEVICE;
1856 goto fail;
1857 }
1858 else if (!(pInit->DevExt.HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
1859 status = STATUS_NO_SUCH_DEVICE;
1860
1861 RtlInitUnicodeString(&DevNameSuff, NULL);
1862
1863 DevNameSuff.MaximumLength = (KEYBOARD_PORTS_MAXIMUM > POINTER_PORTS_MAXIMUM)
1864 ? KEYBOARD_PORTS_MAXIMUM * sizeof(WCHAR)
1865 : POINTER_PORTS_MAXIMUM * sizeof(WCHAR);
1866 DevNameSuff.MaximumLength += sizeof(UNICODE_NULL);
1867 DevNameSuff.Buffer = (PWSTR)ExAllocatePool(PagedPool, DevNameSuff.MaximumLength);
1868 if (!DevNameSuff.Buffer)
1869 {
1870 status = STATUS_UNSUCCESSFUL;
1871 goto fail;
1872 }
1873
1874 RtlZeroMemory(DevNameSuff.Buffer, DevNameSuff.MaximumLength);
1875
1876 RtlInitUnicodeString(&KbdNameFull, NULL);
1877 KbdNameFull.MaximumLength = sizeof(L"\\Device\\") + KbdNameBase.Length + DevNameSuff.MaximumLength;
1878 KbdNameFull.Buffer = (PWSTR)ExAllocatePool(PagedPool, KbdNameFull.MaximumLength);
1879 if (!KbdNameFull.Buffer)
1880 {
1881 status = STATUS_UNSUCCESSFUL;
1882 goto fail;
1883 }
1884
1885 RtlZeroMemory(KbdNameFull.Buffer, KbdNameFull.MaximumLength);
1886 RtlAppendUnicodeToString(&KbdNameFull, L"\\Device\\");
1887 RtlAppendUnicodeToString(&KbdNameFull, KbdNameBase.Buffer);
1888
1889 for (unsigned i = 0; i < KEYBOARD_PORTS_MAXIMUM; i++)
1890 {
1891 status = RtlIntegerToUnicodeString(i, 10, &DevNameSuff);
1892 if (!NT_SUCCESS(status))
1893 break;
1894 RtlAppendUnicodeStringToString(&KbdNameFull, &DevNameSuff);
1895
1896 LogFlow(("VBoxMouseNT::DriverEntry: Creating device object named %S\n", KbdNameFull.Buffer));
1897
1898 status = IoCreateDevice(pDrvObj, sizeof(DEVEXT), &KbdNameFull,
1899 FILE_DEVICE_8042_PORT, 0, FALSE, &pPortDevObj);
1900 if (NT_SUCCESS(status))
1901 break;
1902 else
1903 KbdNameFull.Length -= DevNameSuff.Length;
1904 }
1905
1906 if (!NT_SUCCESS(status))
1907 goto fail;
1908
1909 pDevExt = (PDEVEXT)pPortDevObj->DeviceExtension;
1910 *pDevExt = pInit->DevExt;
1911 pDevExt->pDevObj = pPortDevObj;
1912
1913 CreateResList(pDevExt, &resources, &resourceListSize);
1914
1915 RtlInitUnicodeString(&resourceDeviceClass, NULL);
1916
1917 resourceDeviceClass.MaximumLength = KbdNameBase.Length + sizeof(L"/") + MouNameBase.Length;
1918 resourceDeviceClass.Buffer = (PWSTR)ExAllocatePool(PagedPool, resourceDeviceClass.MaximumLength);
1919 if (!resourceDeviceClass.Buffer)
1920 {
1921 status = STATUS_UNSUCCESSFUL;
1922 goto fail;
1923 }
1924
1925 RtlZeroMemory(resourceDeviceClass.Buffer, resourceDeviceClass.MaximumLength);
1926 RtlAppendUnicodeStringToString(&resourceDeviceClass, &KbdNameBase);
1927 RtlAppendUnicodeToString(&resourceDeviceClass, L"/");
1928 RtlAppendUnicodeStringToString(&resourceDeviceClass, &MouNameBase);
1929
1930 IoReportResourceUsage(&resourceDeviceClass, pDrvObj, NULL, 0, pPortDevObj,
1931 resources, resourceListSize, FALSE, &fConflict);
1932 if (fConflict)
1933 {
1934 status = STATUS_INSUFFICIENT_RESOURCES;
1935 goto fail;
1936 }
1937
1938 for (unsigned i = 0; i < pDevExt->Cfg.cPorts; i++)
1939 {
1940 addressSpace = (pDevExt->Cfg.aPorts[i].Flags & CM_RESOURCE_PORT_IO) == CM_RESOURCE_PORT_IO ? 1 : 0;
1941 if (!HalTranslateBusAddress(pDevExt->Cfg.InterfaceType,
1942 pDevExt->Cfg.uBusNr,
1943 pDevExt->Cfg.aPorts[i].u.Port.Start,
1944 &addressSpace, &Phys))
1945 {
1946 addressSpace = 1;
1947 Phys.QuadPart = 0;
1948 }
1949
1950 if (!addressSpace)
1951 {
1952 pDevExt->fUnmapRegs = TRUE;
1953 pDevExt->DevRegs[i] = (PUCHAR)MmMapIoSpace(Phys, pDevExt->Cfg.aPorts[i].u.Port.Length,
1954 (MEMORY_CACHING_TYPE)FALSE);
1955 }
1956 else
1957 {
1958 pDevExt->fUnmapRegs = FALSE;
1959 pDevExt->DevRegs[i] = (PUCHAR)Phys.LowPart;
1960 }
1961
1962 if (!pDevExt->DevRegs[i])
1963 {
1964 status = STATUS_NONE_MAPPED;
1965 goto fail;
1966 }
1967 }
1968
1969 pPortDevObj->Flags |= DO_BUFFERED_IO;
1970
1971 InitHw(pPortDevObj);
1972
1973 KeInitializeSpinLock(&pDevExt->ShIntObj);
1974
1975 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
1976 {
1977 pDevExt->KbdExt.InputData = (PKEYBOARD_INPUT_DATA)ExAllocatePool(NonPagedPool, pDevExt->Cfg.KbdAttr.InputDataQueueLength);
1978 if (!pDevExt->KbdExt.InputData)
1979 {
1980 status = STATUS_INSUFFICIENT_RESOURCES;
1981 goto fail;
1982 }
1983
1984 pDevExt->KbdExt.DataEnd =
1985 (PKEYBOARD_INPUT_DATA)((PCHAR) (pDevExt->KbdExt.InputData) + pDevExt->Cfg.KbdAttr.InputDataQueueLength);
1986
1987 RtlZeroMemory(pDevExt->KbdExt.InputData, pDevExt->Cfg.KbdAttr.InputDataQueueLength);
1988 }
1989
1990 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
1991 {
1992 RtlInitUnicodeString(&MouNameFull, NULL);
1993
1994 MouNameFull.MaximumLength = sizeof(L"\\Device\\") + MouNameBase.Length + DevNameSuff.MaximumLength;
1995 MouNameFull.Buffer = (PWSTR)ExAllocatePool(PagedPool, MouNameFull.MaximumLength);
1996 if (!MouNameFull.Buffer)
1997 {
1998 status = STATUS_UNSUCCESSFUL;
1999 goto fail;
2000 }
2001
2002 RtlZeroMemory(MouNameFull.Buffer, MouNameFull.MaximumLength);
2003 RtlAppendUnicodeToString(&MouNameFull, L"\\Device\\");
2004 RtlAppendUnicodeToString(&MouNameFull, MouNameBase.Buffer);
2005
2006 RtlZeroMemory(DevNameSuff.Buffer, DevNameSuff.MaximumLength);
2007 DevNameSuff.Length = 0;
2008
2009 for (unsigned i = 0; i < POINTER_PORTS_MAXIMUM; i++)
2010 {
2011 status = RtlIntegerToUnicodeString(i, 10, &DevNameSuff);
2012 if (!NT_SUCCESS(status))
2013 break;
2014
2015 RtlAppendUnicodeStringToString(&MouNameFull, &DevNameSuff);
2016 LogFlow(("VBoxMouseNT::DriverEntry: pointer port name (symbolic link) = %S\n", MouNameFull.Buffer));
2017
2018 status = IoCreateSymbolicLink(&MouNameFull, &KbdNameFull);
2019 if (NT_SUCCESS(status))
2020 break;
2021 else
2022 MouNameFull.Length -= DevNameSuff.Length;
2023 }
2024 if (!NT_SUCCESS(status))
2025 goto fail;
2026
2027 pDevExt->MouExt.InputData = (PMOUSE_INPUT_DATA)ExAllocatePool(NonPagedPool, pDevExt->Cfg.MouAttr.InputDataQueueLength);
2028 if (!pDevExt->MouExt.InputData)
2029 {
2030 status = STATUS_INSUFFICIENT_RESOURCES;
2031 goto fail;
2032 }
2033
2034 pDevExt->MouExt.DataEnd = (PMOUSE_INPUT_DATA)((PCHAR) (pDevExt->MouExt.InputData) + pDevExt->Cfg.MouAttr.InputDataQueueLength);
2035
2036 RtlZeroMemory(pDevExt->MouExt.InputData, pDevExt->Cfg.MouAttr.InputDataQueueLength);
2037 }
2038
2039 pDevExt->KbdExt.ConnectData.ClassDeviceObject = NULL;
2040 pDevExt->KbdExt.ConnectData.ClassService = NULL;
2041 pDevExt->MouExt.ConnectData.ClassDeviceObject = NULL;
2042 pDevExt->MouExt.ConnectData.ClassService = NULL;
2043
2044 I8042INITDATACTX initDataCtx;
2045 initDataCtx.pDevExt = pDevExt;
2046 initDataCtx.DevType = KbdDevType;
2047 InitDataQueue(&initDataCtx);
2048 initDataCtx.DevType = MouDevType;
2049 InitDataQueue(&initDataCtx);
2050
2051 pDevExt->DpcInterlockKeyboard = -1;
2052 pDevExt->DpcInterlockMouse = -1;
2053
2054 IoInitializeDpcRequest(pPortDevObj, CompleteDpc);
2055 KeInitializeDpc(&pDevExt->RetriesExceededDpc, (PKDEFERRED_ROUTINE)CtrlRetriesExceededDpc, pPortDevObj);
2056 KeInitializeDpc(&pDevExt->KeyboardIsrDpc, (PKDEFERRED_ROUTINE)CtrlKbdIsrDpc, pPortDevObj);
2057 KeInitializeDpc(&pDevExt->KeyboardIsrDpcRetry, (PKDEFERRED_ROUTINE)CtrlKbdIsrDpc, pPortDevObj);
2058 KeInitializeDpc(&pDevExt->MouseIsrDpc, (PKDEFERRED_ROUTINE)CtrlMouIsrDpc, pPortDevObj);
2059 KeInitializeDpc(&pDevExt->MouseIsrDpcRetry, (PKDEFERRED_ROUTINE)CtrlMouIsrDpc, pPortDevObj);
2060 KeInitializeDpc(&pDevExt->TimeOutDpc, (PKDEFERRED_ROUTINE)CtrlTimeoutDpc, pPortDevObj);
2061
2062 KeInitializeTimer(&pDevExt->CommandTimer);
2063 pDevExt->TimerCount = -1;
2064
2065 KeInitializeTimer(&pDevExt->KbdExt.DataConsumptionTimer);
2066 KeInitializeTimer(&pDevExt->MouExt.DataConsumptionTimer);
2067
2068 IntVecKbd = HalGetInterruptVector(pDevExt->Cfg.InterfaceType,
2069 pDevExt->Cfg.uBusNr,
2070 pDevExt->Cfg.KbdInt.u.Interrupt.Level,
2071 pDevExt->Cfg.KbdInt.u.Interrupt.Vector,
2072 &IrqlKbd, &AffKbd);
2073
2074 IntVecMou = HalGetInterruptVector(pDevExt->Cfg.InterfaceType,
2075 pDevExt->Cfg.uBusNr,
2076 pDevExt->Cfg.MouInt.u.Interrupt.Level,
2077 pDevExt->Cfg.MouInt.u.Interrupt.Vector,
2078 &IrqlMou, &AffMou);
2079
2080 if ( (pDevExt->HardwarePresent & (KEYBOARD_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT))
2081 == (KEYBOARD_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT))
2082 IrqlCoord = IrqlKbd > IrqlMou ? IrqlKbd : IrqlMou;
2083
2084 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
2085 {
2086 status = IoConnectInterrupt(&pDevExt->MouIntObj, MouIntHandler, pPortDevObj,
2087 &pDevExt->ShIntObj, IntVecMou, IrqlMou,
2088 (KIRQL) ((IrqlCoord == (KIRQL)0) ? IrqlMou : IrqlCoord),
2089 pDevExt->Cfg.MouInt.Flags == CM_RESOURCE_INTERRUPT_LATCHED
2090 ? Latched : LevelSensitive,
2091 pDevExt->Cfg.MouInt.ShareDisposition,
2092 AffMou, pDevExt->Cfg.fFloatSave);
2093 if (!NT_SUCCESS(status))
2094 goto fail;
2095
2096 status = MouEnableTrans(pPortDevObj);
2097 if (!NT_SUCCESS(status))
2098 status = STATUS_SUCCESS;
2099 }
2100
2101 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2102 {
2103 status = IoConnectInterrupt(&pDevExt->KbdIntObj, KbdIntHandler, pPortDevObj,
2104 &pDevExt->ShIntObj, IntVecKbd, IrqlKbd,
2105 (KIRQL) ((IrqlCoord == (KIRQL)0) ? IrqlKbd : IrqlCoord),
2106 pDevExt->Cfg.KbdInt.Flags == CM_RESOURCE_INTERRUPT_LATCHED
2107 ? Latched : LevelSensitive,
2108 pDevExt->Cfg.KbdInt.ShareDisposition,
2109 AffKbd, pDevExt->Cfg.fFloatSave);
2110 if (!NT_SUCCESS(status))
2111 goto fail;
2112 }
2113
2114 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2115 {
2116 status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
2117 KbdNameBase.Buffer, KbdNameFull.Buffer,
2118 REG_SZ,
2119 registryPath.Buffer, registryPath.Length);
2120 if (!NT_SUCCESS(status))
2121 goto fail;
2122 }
2123
2124 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
2125 {
2126 status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
2127 MouNameBase.Buffer, MouNameFull.Buffer,
2128 REG_SZ,
2129 registryPath.Buffer, registryPath.Length);
2130 if (!NT_SUCCESS(status))
2131 goto fail;
2132 }
2133
2134 ASSERT(status == STATUS_SUCCESS);
2135
2136 int rcVBox = VbglR0InitClient();
2137 if (RT_FAILURE(rcVBox))
2138 {
2139 Log(("VBoxMouseNT::DriverEntry: could not initialize guest library, rc = %Rrc\n", rcVBox));
2140 /* Continue working in non-VBox mode. */
2141 }
2142 else
2143 {
2144 VMMDevReqMouseStatus *pReq = NULL;
2145
2146 rcVBox = VbglR0GRAlloc((VMMDevRequestHeader**)&pReq, sizeof(VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
2147 if (RT_SUCCESS(rcVBox))
2148 {
2149 /* Inform host that we support absolute */
2150 pReq->mouseFeatures = VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE;
2151 pReq->pointerXPos = 0;
2152 pReq->pointerYPos = 0;
2153 rcVBox = VbglR0GRPerform(&pReq->header);
2154 if (RT_FAILURE(rcVBox))
2155 Log(("VBoxMouseNT::DriverEntry: ERROR communicating new mouse capabilities to VMMDev. rc = %Rrc\n", rcVBox));
2156 else
2157 {
2158 /* We will use the allocated request buffer in the ServiceCallback to GET mouse status. */
2159 pReq->header.requestType = VMMDevReq_GetMouseStatus;
2160 pDevExt->pReq = pReq;
2161 }
2162 }
2163 else
2164 {
2165 VbglR0TerminateClient();
2166 Log(("VBoxMouseNT::DriverEntry: could not allocate request buffer, rc = %Rrc\n", rcVBox));
2167 /* Continue working in non-VBox mode. */
2168 }
2169 }
2170
2171 pDrvObj->DriverStartIo = I8042StartIo;
2172 pDrvObj->MajorFunction[IRP_MJ_CREATE] = I8042OpenClose;
2173 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = I8042OpenClose;
2174 pDrvObj->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = I8042Flush;
2175 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = I8042DevCtrl;
2176
2177fail:
2178 if (!NT_SUCCESS(status))
2179 {
2180 if (resources)
2181 {
2182 resources->Count = 0;
2183 IoReportResourceUsage(&resourceDeviceClass, pDrvObj, NULL,
2184 0, pPortDevObj, resources, resourceListSize, FALSE, &fConflict);
2185 }
2186
2187 if (pDevExt)
2188 {
2189 if (pDevExt->KbdIntObj)
2190 IoDisconnectInterrupt(pDevExt->KbdIntObj);
2191 if (pDevExt->MouIntObj)
2192 IoDisconnectInterrupt(pDevExt->MouIntObj);
2193 if (pDevExt->KbdExt.InputData)
2194 ExFreePool(pDevExt->KbdExt.InputData);
2195 if (pDevExt->MouExt.InputData)
2196 ExFreePool(pDevExt->MouExt.InputData);
2197 if (pDevExt->fUnmapRegs)
2198 {
2199 for (unsigned i = 0; i < pDevExt->Cfg.cPorts; i++)
2200 if (pDevExt->DevRegs[i])
2201 MmUnmapIoSpace(pDevExt->DevRegs[i], pDevExt->Cfg.aPorts[i].u.Port.Length);
2202 }
2203 }
2204 if (pPortDevObj)
2205 {
2206 if (MouNameFull.Length > 0)
2207 IoDeleteSymbolicLink(&MouNameFull);
2208 IoDeleteDevice(pPortDevObj);
2209 }
2210 }
2211
2212 if (resources)
2213 ExFreePool(resources);
2214 if (pInit)
2215 ExFreePool(pInit);
2216 if (DevNameSuff.MaximumLength)
2217 ExFreePool(DevNameSuff.Buffer);
2218 if (KbdNameFull.MaximumLength)
2219 ExFreePool(KbdNameFull.Buffer);
2220 if (MouNameFull.MaximumLength)
2221 ExFreePool(MouNameFull.Buffer);
2222 if (resourceDeviceClass.MaximumLength)
2223 ExFreePool(resourceDeviceClass.Buffer);
2224 if (registryPath.MaximumLength)
2225 ExFreePool(registryPath.Buffer);
2226
2227 LogFlow(("VBoxMouseNT::DriverEntry: leave, status = %d\n", status));
2228
2229 return status;
2230}
2231
2232static VOID I8042Unload(PDRIVER_OBJECT pDrvObj)
2233{
2234 NOREF(pDrvObj);
2235}
2236
2237/**
2238 * Build a resource list.
2239 */
2240static VOID CreateResList(PDEVEXT pDevExt, PCM_RESOURCE_LIST *pResList, PULONG pResListSize)
2241{
2242 ULONG cPorts = pDevExt->Cfg.cPorts;
2243 if (pDevExt->Cfg.KbdInt.Type == CmResourceTypeInterrupt)
2244 cPorts++;
2245 if (pDevExt->Cfg.MouInt.Type == CmResourceTypeInterrupt)
2246 cPorts++;
2247
2248 *pResListSize = sizeof(CM_RESOURCE_LIST) + ((cPorts - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
2249 *pResList = (PCM_RESOURCE_LIST)ExAllocatePool(PagedPool, *pResListSize);
2250 if (!*pResList)
2251 {
2252 *pResListSize = 0;
2253 return;
2254 }
2255
2256 RtlZeroMemory(*pResList, *pResListSize);
2257
2258 (*pResList)->Count = 1;
2259 (*pResList)->List[0].InterfaceType = pDevExt->Cfg.InterfaceType;
2260 (*pResList)->List[0].BusNumber = pDevExt->Cfg.uBusNr;
2261
2262 (*pResList)->List[0].PartialResourceList.Count = cPorts;
2263 ULONG i = 0;
2264 if (pDevExt->Cfg.KbdInt.Type == CmResourceTypeInterrupt)
2265 (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.KbdInt;
2266 if (pDevExt->Cfg.MouInt.Type == CmResourceTypeInterrupt)
2267 (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.MouInt;
2268 for (unsigned j = 0; j < pDevExt->Cfg.cPorts; j++)
2269 (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.aPorts[j];
2270}
2271
2272/**
2273 * Read the i8042 controller command byte
2274 */
2275static NTSTATUS GetCtrlCmd(ULONG HwDisEnMask, PDEVEXT pDevExt, PUCHAR pByte)
2276{
2277 NTSTATUS status;
2278 if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
2279 {
2280 status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_DISABLE_KEYBOARD_DEVICE);
2281 if (!NT_SUCCESS(status))
2282 return status;
2283 }
2284
2285 if (HwDisEnMask & MOUSE_HARDWARE_PRESENT)
2286 {
2287 status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_DISABLE_MOUSE_DEVICE);
2288 if (!NT_SUCCESS(status))
2289 {
2290 if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
2291 PutBytePoll(i8042Cmd, FALSE/*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
2292 return status;
2293 }
2294 }
2295
2296 status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_READ_CONTROLLER_COMMAND_BYTE);
2297 if (NT_SUCCESS(status))
2298 {
2299 for (unsigned iRetry = 0; iRetry < 5; iRetry++)
2300 {
2301 status = GetBytePoll(CtrlDevType, pDevExt, pByte);
2302 if (NT_SUCCESS(status))
2303 break;
2304 if (status == STATUS_IO_TIMEOUT)
2305 KeStallExecutionProcessor(50);
2306 else
2307 break;
2308 }
2309 }
2310
2311 NTSTATUS status2;
2312 if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
2313 {
2314 status2 = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
2315 if (!NT_SUCCESS(status2))
2316 {
2317 if (NT_SUCCESS(status))
2318 status = status2;
2319 }
2320 else if (status == STATUS_SUCCESS)
2321 *pByte &= (UCHAR)~CCB_DISABLE_KEYBOARD_DEVICE;
2322 }
2323
2324 if (HwDisEnMask & MOUSE_HARDWARE_PRESENT)
2325 {
2326 status2 = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_MOUSE_DEVICE);
2327 if (!NT_SUCCESS(status2))
2328 {
2329 if (NT_SUCCESS(status))
2330 status = status2;
2331 }
2332 else if (NT_SUCCESS(status))
2333 *pByte &= (UCHAR)~CCB_DISABLE_MOUSE_DEVICE;
2334 }
2335 return status;
2336}
2337
2338/**
2339 * Write the i8042 controller command byte.
2340 */
2341static NTSTATUS PutCtrlCmd(PDEVEXT pDevExt, UCHAR Byte)
2342{
2343 NTSTATUS status;
2344 status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_WRITE_CONTROLLER_COMMAND_BYTE);
2345 if (!NT_SUCCESS(status))
2346 return status;
2347
2348 return (PutBytePoll(i8042Dat, FALSE /*=wait*/, NoDevice, pDevExt, Byte));
2349}
2350
2351/**
2352 * Read the i8042 controller command byte.
2353 */
2354static VOID TransCtrlCmd(PDEVEXT pDevExt, PI8042TRANSMITCCBCTX pCtx)
2355{
2356 UCHAR bCtrlCmd;
2357 pCtx->Status = GetCtrlCmd(pCtx->HwDisEnMask, pDevExt, &bCtrlCmd);
2358 if (!NT_SUCCESS(pCtx->Status))
2359 return;
2360
2361 if (pCtx->fAndOp)
2362 bCtrlCmd &= pCtx->ByteMask;
2363 else
2364 bCtrlCmd |= pCtx->ByteMask;
2365
2366 pCtx->Status = PutCtrlCmd(pDevExt, bCtrlCmd);
2367
2368 UCHAR bVrfyCmd;
2369 pCtx->Status = GetCtrlCmd(pCtx->HwDisEnMask, pDevExt, &bVrfyCmd);
2370
2371 if ( NT_SUCCESS(pCtx->Status)
2372 && bVrfyCmd != bCtrlCmd)
2373 pCtx->Status = STATUS_DEVICE_DATA_ERROR;
2374}
2375
2376/**
2377 * Detect the number of mouse buttons.
2378 */
2379static NTSTATUS MouQueryButtons(PDEVICE_OBJECT pDevObj, PUCHAR pNumButtons)
2380{
2381 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
2382
2383 NTSTATUS status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_RESOLUTION);
2384 if (!NT_SUCCESS(status))
2385 return status;
2386
2387 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, 0x00);
2388 if (!NT_SUCCESS(status))
2389 return status;
2390
2391 for (unsigned i = 0; i < 3; i++)
2392 {
2393 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_SCALING_1TO1);
2394 if (!NT_SUCCESS(status))
2395 return status;
2396 }
2397
2398 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, READ_MOUSE_STATUS);
2399 if (!NT_SUCCESS(status))
2400 return status;
2401 UCHAR byte;
2402 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
2403 if (!NT_SUCCESS(status))
2404 return status;
2405 UCHAR buttons;
2406 status = GetBytePoll(CtrlDevType, pDevExt, &buttons);
2407 if (!NT_SUCCESS(status))
2408 return status;
2409 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
2410 if (!NT_SUCCESS(status))
2411 return status;
2412
2413 if (buttons == 2 || buttons == 3)
2414 *pNumButtons = buttons;
2415 else
2416 *pNumButtons = 0;
2417
2418 return status;
2419}
2420
2421/**
2422 * Initialize the i8042 mouse hardware.
2423 */
2424static NTSTATUS MouInitHw(PDEVICE_OBJECT pDevObj)
2425{
2426 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
2427
2428 NTSTATUS status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, MOUSE_RESET);
2429 if (!NT_SUCCESS(status))
2430 goto fail;
2431
2432 UCHAR byte;
2433 for (unsigned i = 0; i < 11200; i++)
2434 {
2435 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
2436 if (NT_SUCCESS(status) && byte == (UCHAR) MOUSE_COMPLETE)
2437 break;
2438 if (status != STATUS_IO_TIMEOUT)
2439 break;
2440 KeStallExecutionProcessor(50);
2441 }
2442
2443 if (!NT_SUCCESS(status))
2444 goto fail;
2445
2446 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
2447 if ((!NT_SUCCESS(status)) || (byte != MOUSE_ID_BYTE))
2448 goto fail;
2449
2450 MouFindWheel(pDevObj);
2451
2452 UCHAR numButtons;
2453 status = MouQueryButtons(pDevObj, &numButtons);
2454 if (!NT_SUCCESS(status))
2455 goto fail;
2456 else if (numButtons)
2457 pDevExt->Cfg.MouAttr.NumberOfButtons = numButtons;
2458
2459 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_SAMPLING_RATE);
2460 if (!NT_SUCCESS(status))
2461 goto fail;
2462
2463 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, 60);
2464 if (!NT_SUCCESS(status))
2465 goto fail;
2466
2467 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_RESOLUTION);
2468 if (!NT_SUCCESS(status))
2469 goto fail;
2470
2471 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, (UCHAR)pDevExt->Cfg.MouseResolution);
2472
2473fail:
2474 pDevExt->MouExt.uPrevSignAndOverflow = 0;
2475 pDevExt->MouExt.InputState = MouseExpectingACK;
2476 pDevExt->MouExt.LastByteReceived = 0;
2477
2478 return status;
2479}
2480
2481/**
2482 * Initialize the i8042 keyboard hardware.
2483 */
2484static NTSTATUS KbdInitHw(PDEVICE_OBJECT pDevObj)
2485{
2486 NTSTATUS status = STATUS_SUCCESS; /* Shut up MSC. */
2487 BOOLEAN fWaitForAck = TRUE;
2488 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
2489
2490retry:
2491 PutBytePoll(i8042Dat, fWaitForAck, KbdDevType, pDevExt, KEYBOARD_RESET);
2492
2493 LARGE_INTEGER startOfSpin;
2494 KeQueryTickCount(&startOfSpin);
2495 for (unsigned i = 0; i < 11200; i++)
2496 {
2497 UCHAR byte;
2498 status = GetBytePoll(KbdDevType, pDevExt, &byte);
2499 if (NT_SUCCESS(status))
2500 break;
2501 if (status == STATUS_IO_TIMEOUT)
2502 {
2503 LARGE_INTEGER nextQuery, difference, tenSeconds;
2504 KeStallExecutionProcessor(50);
2505 KeQueryTickCount(&nextQuery);
2506 difference.QuadPart = nextQuery.QuadPart - startOfSpin.QuadPart;
2507 tenSeconds.QuadPart = 10*10*1000*1000;
2508 ASSERT(KeQueryTimeIncrement() <= MAXLONG);
2509 if (difference.QuadPart*KeQueryTimeIncrement() >= tenSeconds.QuadPart)
2510 break;
2511 }
2512 else
2513 break;
2514 }
2515
2516 if (!NT_SUCCESS(status))
2517 {
2518 if (fWaitForAck)
2519 {
2520 fWaitForAck = FALSE;
2521 goto retry;
2522 }
2523 goto fail;
2524 }
2525
2526 I8042TRANSMITCCBCTX Ctx;
2527 Ctx.HwDisEnMask = 0;
2528 Ctx.fAndOp = TRUE;
2529 Ctx.ByteMask = (UCHAR) ~((UCHAR)CCB_KEYBOARD_TRANSLATE_MODE);
2530
2531 TransCtrlCmd(pDevExt, &Ctx);
2532 if (!NT_SUCCESS(Ctx.Status))
2533 TransCtrlCmd(pDevExt, &Ctx);
2534 if (!NT_SUCCESS(Ctx.Status))
2535 {
2536 status = Ctx.Status;
2537 goto fail;
2538 }
2539
2540 PKEYBOARD_ID pId = &pDevExt->Cfg.KbdAttr.KeyboardIdentifier;
2541 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SET_KEYBOARD_TYPEMATIC);
2542 if (status == STATUS_SUCCESS)
2543 {
2544 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt,
2545 ConvertTypematic(pDevExt->Cfg.KeyRepeatCurrent.Rate,
2546 pDevExt->Cfg.KeyRepeatCurrent.Delay));
2547 /* ignore errors */
2548 }
2549
2550 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SET_KEYBOARD_INDICATORS);
2551 if (status == STATUS_SUCCESS)
2552 {
2553 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt,
2554 (UCHAR)pDevExt->Cfg.KbdInd.LedFlags);
2555 /* ignore errors */
2556 }
2557 status = STATUS_SUCCESS;
2558
2559 if (pDevExt->Cfg.KbdAttr.KeyboardMode == 1)
2560 {
2561 Ctx.HwDisEnMask = 0;
2562 Ctx.fAndOp = FALSE;
2563 Ctx.ByteMask = CCB_KEYBOARD_TRANSLATE_MODE;
2564 TransCtrlCmd(pDevExt, &Ctx);
2565 if (!NT_SUCCESS(Ctx.Status))
2566 {
2567 if (Ctx.Status == STATUS_DEVICE_DATA_ERROR)
2568 {
2569 if (ENHANCED_KEYBOARD(*pId))
2570 {
2571 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SELECT_SCAN_CODE_SET);
2572 if (!NT_SUCCESS(status))
2573 pDevExt->Cfg.KbdAttr.KeyboardMode = 2;
2574 else
2575 {
2576 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, 1);
2577 if (!NT_SUCCESS(status))
2578 pDevExt->Cfg.KbdAttr.KeyboardMode = 2;
2579 }
2580 }
2581 }
2582 else
2583 {
2584 status = Ctx.Status;
2585 goto fail;
2586 }
2587 }
2588 }
2589
2590fail:
2591 pDevExt->KbdExt.CurrentOutput.State = Idle;
2592 pDevExt->KbdExt.CurrentOutput.FirstByte = 0;
2593 pDevExt->KbdExt.CurrentOutput.LastByte = 0;
2594
2595 return status;
2596}
2597
2598/**
2599 * Initialize the i8042 controller, keyboard and mouse.
2600 */
2601static VOID InitHw(PDEVICE_OBJECT pDevObj)
2602{
2603 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
2604 PUCHAR dataAddress = pDevExt->DevRegs[i8042Dat];
2605 PUCHAR commandAddress = pDevExt->DevRegs[i8042Cmd];
2606
2607 DrainOutBuf(dataAddress, commandAddress);
2608
2609 I8042TRANSMITCCBCTX Ctx;
2610 Ctx.HwDisEnMask = 0;
2611 Ctx.fAndOp = TRUE;
2612 Ctx.ByteMask = (UCHAR) ~((UCHAR)CCB_ENABLE_KEYBOARD_INTERRUPT | (UCHAR)CCB_ENABLE_MOUSE_INTERRUPT);
2613 TransCtrlCmd(pDevExt, &Ctx);
2614 if (!NT_SUCCESS(Ctx.Status))
2615 return;
2616
2617 DrainOutBuf(dataAddress, commandAddress);
2618
2619 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
2620 {
2621 NTSTATUS status = MouInitHw(pDevObj);
2622 if (!NT_SUCCESS(status))
2623 pDevExt->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2624 }
2625
2626 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2627 {
2628 NTSTATUS status = KbdInitHw(pDevObj);
2629 if (!NT_SUCCESS(status))
2630 pDevExt->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2631 }
2632
2633 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2634 {
2635 NTSTATUS status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
2636 if (!NT_SUCCESS(status))
2637 pDevExt->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2638
2639 DrainOutBuf(dataAddress, commandAddress);
2640 }
2641
2642 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
2643 {
2644 NTSTATUS status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_MOUSE_DEVICE);
2645 if (!NT_SUCCESS(status))
2646 pDevExt->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2647 DrainOutBuf(dataAddress, commandAddress);
2648 }
2649
2650 if (pDevExt->HardwarePresent)
2651 {
2652 Ctx.HwDisEnMask = pDevExt->HardwarePresent;
2653 Ctx.fAndOp = FALSE;
2654 Ctx.ByteMask = (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2655 ? CCB_ENABLE_KEYBOARD_INTERRUPT : 0;
2656 Ctx.ByteMask |= (UCHAR)
2657 (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT) ? CCB_ENABLE_MOUSE_INTERRUPT : 0;
2658 TransCtrlCmd(pDevExt, &Ctx);
2659 if (!NT_SUCCESS(Ctx.Status))
2660 {
2661 /* ignore */
2662 }
2663 }
2664}
2665
2666/**
2667 * retrieve the drivers service parameters from the registry
2668 */
2669static VOID HwGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
2670 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
2671
2672{
2673 PRTL_QUERY_REGISTRY_TABLE aQuery = NULL;
2674 UNICODE_STRING parametersPath = { 0, 0, NULL }; /* Shut up MSC (actually badly structured code is a fault, but whatever). */
2675 UNICODE_STRING defaultPointerName;
2676 UNICODE_STRING defaultKeyboardName;
2677 USHORT defaultResendIterations = 3;
2678 ULONG iResend = 0;
2679 USHORT defaultPollingIterations = 12000;
2680 ULONG pollingIterations = 0;
2681 USHORT defaultPollingIterationsMaximum = 12000;
2682 ULONG pollingIterationsMaximum = 0;
2683 USHORT defaultPollStatusIterations = 12000;
2684 ULONG pollStatusIterations = 0;
2685 ULONG defaultDataQueueSize = 100;
2686 ULONG cButtons = 2;
2687 USHORT cButtonsDef = 2;
2688 ULONG sampleRate = 60;
2689 USHORT defaultSampleRate = 60;
2690 ULONG mouseResolution = 3;
2691 USHORT defaultMouseResolution = 3;
2692 ULONG overrideKeyboardType = 0;
2693 ULONG invalidKeyboardType = 0;
2694 ULONG overrideKeyboardSubtype = (ULONG)-1;
2695 ULONG invalidKeyboardSubtype = (ULONG)-1;
2696 ULONG defaultSynchPacket100ns = 10000000UL;
2697 ULONG enableWheelDetection = 0;
2698 ULONG defaultEnableWheelDetection = 1;
2699 PWSTR path = NULL;
2700 USHORT queries = 15;
2701 PI8042CFGINF pCfg = &pInit->DevExt.Cfg;
2702 NTSTATUS status = STATUS_SUCCESS;
2703
2704 pCfg->StallMicroseconds = 50;
2705 parametersPath.Buffer = NULL;
2706
2707 path = RegistryPath->Buffer;
2708 if (NT_SUCCESS(status))
2709 {
2710 aQuery = (PRTL_QUERY_REGISTRY_TABLE)ExAllocatePool(PagedPool, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1));
2711 if (!aQuery)
2712 status = STATUS_UNSUCCESSFUL;
2713 else
2714 {
2715 RtlZeroMemory(aQuery, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1));
2716 RtlInitUnicodeString(&parametersPath, NULL);
2717 parametersPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
2718 parametersPath.Buffer = (PWSTR)ExAllocatePool(PagedPool, parametersPath.MaximumLength);
2719 if (!parametersPath.Buffer)
2720 status = STATUS_UNSUCCESSFUL;
2721 }
2722 }
2723
2724 if (NT_SUCCESS(status))
2725 {
2726 RtlZeroMemory(parametersPath.Buffer, parametersPath.MaximumLength);
2727 RtlAppendUnicodeToString(&parametersPath, path);
2728 RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
2729
2730 RtlInitUnicodeString(&defaultKeyboardName, L"KeyboardPort");
2731 RtlInitUnicodeString(&defaultPointerName, L"PointerPort");
2732
2733 aQuery[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2734 aQuery[0].Name = L"iResend";
2735 aQuery[0].EntryContext = &iResend;
2736 aQuery[0].DefaultType = REG_DWORD;
2737 aQuery[0].DefaultData = &defaultResendIterations;
2738 aQuery[0].DefaultLength = sizeof(USHORT);
2739
2740 aQuery[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2741 aQuery[1].Name = L"PollingIterations";
2742 aQuery[1].EntryContext = &pollingIterations;
2743 aQuery[1].DefaultType = REG_DWORD;
2744 aQuery[1].DefaultData = &defaultPollingIterations;
2745 aQuery[1].DefaultLength = sizeof(USHORT);
2746
2747 aQuery[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
2748 aQuery[2].Name = L"PollingIterationsMaximum";
2749 aQuery[2].EntryContext = &pollingIterationsMaximum;
2750 aQuery[2].DefaultType = REG_DWORD;
2751 aQuery[2].DefaultData = &defaultPollingIterationsMaximum;
2752 aQuery[2].DefaultLength = sizeof(USHORT);
2753
2754 aQuery[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
2755 aQuery[3].Name = L"KeyboardDataQueueSize";
2756 aQuery[3].EntryContext = &pCfg->KbdAttr.InputDataQueueLength;
2757 aQuery[3].DefaultType = REG_DWORD;
2758 aQuery[3].DefaultData = &defaultDataQueueSize;
2759 aQuery[3].DefaultLength = sizeof(ULONG);
2760
2761 aQuery[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
2762 aQuery[4].Name = L"MouseDataQueueSize";
2763 aQuery[4].EntryContext = &pCfg->MouAttr.InputDataQueueLength;
2764 aQuery[4].DefaultType = REG_DWORD;
2765 aQuery[4].DefaultData = &defaultDataQueueSize;
2766 aQuery[4].DefaultLength = sizeof(ULONG);
2767
2768 aQuery[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
2769 aQuery[5].Name = L"NumberOfButtons";
2770 aQuery[5].EntryContext = &cButtons;
2771 aQuery[5].DefaultType = REG_DWORD;
2772 aQuery[5].DefaultData = &cButtonsDef;
2773 aQuery[5].DefaultLength = sizeof(USHORT);
2774
2775 aQuery[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
2776 aQuery[6].Name = L"SampleRate";
2777 aQuery[6].EntryContext = &sampleRate;
2778 aQuery[6].DefaultType = REG_DWORD;
2779 aQuery[6].DefaultData = &defaultSampleRate;
2780 aQuery[6].DefaultLength = sizeof(USHORT);
2781
2782 aQuery[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
2783 aQuery[7].Name = L"MouseResolution";
2784 aQuery[7].EntryContext = &mouseResolution;
2785 aQuery[7].DefaultType = REG_DWORD;
2786 aQuery[7].DefaultData = &defaultMouseResolution;
2787 aQuery[7].DefaultLength = sizeof(USHORT);
2788
2789 aQuery[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
2790 aQuery[8].Name = L"OverrideKeyboardType";
2791 aQuery[8].EntryContext = &overrideKeyboardType;
2792 aQuery[8].DefaultType = REG_DWORD;
2793 aQuery[8].DefaultData = &invalidKeyboardType;
2794 aQuery[8].DefaultLength = sizeof(ULONG);
2795
2796 aQuery[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
2797 aQuery[9].Name = L"OverrideKeyboardSubtype";
2798 aQuery[9].EntryContext = &overrideKeyboardSubtype;
2799 aQuery[9].DefaultType = REG_DWORD;
2800 aQuery[9].DefaultData = &invalidKeyboardSubtype;
2801 aQuery[9].DefaultLength = sizeof(ULONG);
2802
2803 aQuery[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
2804 aQuery[10].Name = L"KeyboardDeviceBaseName";
2805 aQuery[10].EntryContext = KeyboardDeviceName;
2806 aQuery[10].DefaultType = REG_SZ;
2807 aQuery[10].DefaultData = defaultKeyboardName.Buffer;
2808 aQuery[10].DefaultLength = 0;
2809
2810 aQuery[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
2811 aQuery[11].Name = L"PointerDeviceBaseName";
2812 aQuery[11].EntryContext = PointerDeviceName;
2813 aQuery[11].DefaultType = REG_SZ;
2814 aQuery[11].DefaultData = defaultPointerName.Buffer;
2815 aQuery[11].DefaultLength = 0;
2816
2817 aQuery[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
2818 aQuery[12].Name = L"MouseSynchIn100ns";
2819 aQuery[12].EntryContext = &pInit->DevExt.MouExt.SynchTickCount;
2820 aQuery[12].DefaultType = REG_DWORD;
2821 aQuery[12].DefaultData = &defaultSynchPacket100ns;
2822 aQuery[12].DefaultLength = sizeof(ULONG);
2823
2824 aQuery[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
2825 aQuery[13].Name = L"PollStatusIterations";
2826 aQuery[13].EntryContext = &pollStatusIterations;
2827 aQuery[13].DefaultType = REG_DWORD;
2828 aQuery[13].DefaultData = &defaultPollStatusIterations;
2829 aQuery[13].DefaultLength = sizeof(USHORT);
2830
2831 aQuery[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
2832 aQuery[14].Name = L"EnableWheelDetection";
2833 aQuery[14].EntryContext = &enableWheelDetection;
2834 aQuery[14].DefaultType = REG_DWORD;
2835 aQuery[14].DefaultData = &defaultEnableWheelDetection;
2836 aQuery[14].DefaultLength = sizeof(ULONG);
2837
2838 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
2839 parametersPath.Buffer, aQuery, NULL, NULL);
2840 }
2841
2842 if (!NT_SUCCESS(status))
2843 {
2844 /* driver defaults */
2845 pCfg->iResend = defaultResendIterations;
2846 pCfg->PollingIterations = defaultPollingIterations;
2847 pCfg->PollingIterationsMaximum = defaultPollingIterationsMaximum;
2848 pCfg->PollStatusIterations = defaultPollStatusIterations;
2849 pCfg->KbdAttr.InputDataQueueLength = defaultDataQueueSize;
2850 pCfg->MouAttr.InputDataQueueLength = defaultDataQueueSize;
2851 pCfg->EnableWheelDetection = defaultEnableWheelDetection;
2852 pInit->DevExt.MouExt.SynchTickCount = defaultSynchPacket100ns;
2853 RtlCopyUnicodeString(KeyboardDeviceName, &defaultKeyboardName);
2854 RtlCopyUnicodeString(PointerDeviceName, &defaultPointerName);
2855 }
2856 else
2857 {
2858 pCfg->iResend = (USHORT)iResend;
2859 pCfg->PollingIterations = (USHORT) pollingIterations;
2860 pCfg->PollingIterationsMaximum = (USHORT) pollingIterationsMaximum;
2861 pCfg->PollStatusIterations = (USHORT) pollStatusIterations;
2862 pCfg->EnableWheelDetection = (ULONG) ((enableWheelDetection) ? 1 : 0);
2863 }
2864
2865 if (pCfg->KbdAttr.InputDataQueueLength == 0)
2866 pCfg->KbdAttr.InputDataQueueLength = defaultDataQueueSize;
2867 pCfg->KbdAttr.InputDataQueueLength *= sizeof(KEYBOARD_INPUT_DATA);
2868
2869 if (pCfg->MouAttr.InputDataQueueLength == 0)
2870 pCfg->MouAttr.InputDataQueueLength = defaultDataQueueSize;
2871 pCfg->MouAttr.InputDataQueueLength *= sizeof(MOUSE_INPUT_DATA);
2872
2873 pCfg->MouAttr.NumberOfButtons = (USHORT)cButtons;
2874 pCfg->MouAttr.SampleRate = (USHORT)sampleRate;
2875 pCfg->MouseResolution = (USHORT)mouseResolution;
2876
2877 if (overrideKeyboardType != invalidKeyboardType)
2878 {
2879 if (overrideKeyboardType <= RT_ELEMENTS(s_aKeybType))
2880 pCfg->KbdAttr.KeyboardIdentifier.Type = (UCHAR) overrideKeyboardType;
2881 }
2882
2883 if (overrideKeyboardSubtype != invalidKeyboardSubtype)
2884 pCfg->KbdAttr.KeyboardIdentifier.Subtype = (UCHAR) overrideKeyboardSubtype;
2885
2886 if (pInit->DevExt.MouExt.SynchTickCount == 0)
2887 pInit->DevExt.MouExt.SynchTickCount = defaultSynchPacket100ns;
2888
2889 pInit->DevExt.MouExt.SynchTickCount /= KeQueryTimeIncrement();
2890
2891 if (parametersPath.Buffer)
2892 ExFreePool(parametersPath.Buffer);
2893 if (aQuery)
2894 ExFreePool(aQuery);
2895}
2896
2897static void GetDevIdentifier(PKEY_VALUE_FULL_INFORMATION *ppInf, PUNICODE_STRING pStr)
2898{
2899 pStr->Length = (USHORT)(*(ppInf + IoQueryDeviceIdentifier))->DataLength;
2900 if (!pStr->Length)
2901 return;
2902 pStr->MaximumLength = pStr->Length;
2903 pStr->Buffer = (PWSTR) (((PUCHAR)(*(ppInf + IoQueryDeviceIdentifier)))
2904 + (*(ppInf + IoQueryDeviceIdentifier))->DataOffset);
2905}
2906
2907static ULONG GetDevCfgData(PKEY_VALUE_FULL_INFORMATION *ppInf, PCM_PARTIAL_RESOURCE_LIST *ppData)
2908{
2909 ULONG DataLength = (*(ppInf + IoQueryDeviceConfigurationData))->DataLength;
2910 if (DataLength)
2911 *ppData = (PCM_PARTIAL_RESOURCE_LIST)( ((PUCHAR) (*(ppInf + IoQueryDeviceConfigurationData)))
2912 + (*(ppInf + IoQueryDeviceConfigurationData))->DataOffset
2913 + FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList));
2914 return DataLength;
2915}
2916
2917/**
2918 * Callout routine. Grab keyboard controller and peripheral configuration
2919 * information.
2920 */
2921static NTSTATUS KbdCallOut(PVOID pCtx, PUNICODE_STRING PathName,
2922 INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
2923 CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
2924 CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf)
2925{
2926 RT_NOREF(PathName, pBusInf, uCtrlType, uCtrlNr, uPrfType, uPrfNr);
2927 UNICODE_STRING unicodeIdentifier;
2928 GetDevIdentifier(pPrfInf, &unicodeIdentifier);
2929
2930 PINITEXT pInit = (PINITEXT)pCtx;
2931 PDEVEXT pDevExt = &pInit->DevExt;
2932 if ( (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2933 || !unicodeIdentifier.Length)
2934 return STATUS_SUCCESS;
2935
2936 pDevExt->HardwarePresent |= KEYBOARD_HARDWARE_PRESENT;
2937
2938 PI8042CFGINF pCfg = &pDevExt->Cfg;
2939 pCfg->KbdAttr.KeyboardIdentifier.Type = 0;
2940 pCfg->KbdAttr.KeyboardIdentifier.Subtype = 0;
2941
2942 PCM_PARTIAL_RESOURCE_LIST pPrfData;
2943 if (GetDevCfgData(pPrfInf, &pPrfData))
2944 {
2945 unsigned cList = pPrfData->Count;
2946 PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pPrfData->PartialDescriptors;
2947 for (unsigned i = 0; i < cList; i++, pResDesc++)
2948 {
2949 switch (pResDesc->Type)
2950 {
2951 case CmResourceTypeDeviceSpecific:
2952 {
2953 PCM_KEYBOARD_DEVICE_DATA KbdData = (PCM_KEYBOARD_DEVICE_DATA)(((PUCHAR)pResDesc)
2954 + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
2955 if (KbdData->Type <= RT_ELEMENTS(s_aKeybType))
2956 pCfg->KbdAttr.KeyboardIdentifier.Type = KbdData->Type;
2957 pCfg->KbdAttr.KeyboardIdentifier.Subtype = KbdData->Subtype;
2958 pCfg->KbdInd.LedFlags = (KbdData->KeyboardFlags >> 4) & 7;
2959 break;
2960 }
2961 default:
2962 break;
2963 }
2964 }
2965 }
2966
2967 if (pCfg->KbdAttr.KeyboardIdentifier.Type == 0)
2968 {
2969 pCfg->KbdAttr.KeyboardIdentifier.Type = 4;
2970 pCfg->KbdInd.LedFlags = 0;
2971 }
2972
2973 pCfg->InterfaceType = BusType;
2974 pCfg->uBusNr = uBusNr;
2975 pCfg->fFloatSave = FALSE;
2976
2977 BOOLEAN fDefIntShare;
2978 KINTERRUPT_MODE DefIntMode;
2979 if (BusType == MicroChannel)
2980 {
2981 fDefIntShare = TRUE;
2982 DefIntMode = LevelSensitive;
2983 }
2984 else
2985 {
2986 fDefIntShare = FALSE;
2987 DefIntMode = Latched;
2988 }
2989
2990 PCM_PARTIAL_RESOURCE_LIST pCtrlData;
2991 if (GetDevCfgData(pCtrlInf, &pCtrlData))
2992 {
2993 unsigned cList = pCtrlData->Count;
2994 PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pCtrlData->PartialDescriptors;
2995 for (unsigned i = 0; i < cList; i++, pResDesc++)
2996 {
2997 switch (pResDesc->Type)
2998 {
2999 case CmResourceTypePort:
3000 ASSERT(pCfg->cPorts < i8042MaxPorts);
3001 pCfg->aPorts[pCfg->cPorts] = *pResDesc;
3002 pCfg->aPorts[pCfg->cPorts].ShareDisposition = CmResourceShareDriverExclusive;
3003 pCfg->cPorts++;
3004 break;
3005
3006 case CmResourceTypeInterrupt:
3007 pCfg->KbdInt = *pResDesc;
3008 pCfg->KbdInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
3009 : CmResourceShareDeviceExclusive;
3010 break;
3011
3012 case CmResourceTypeDeviceSpecific:
3013 break;
3014
3015 default:
3016 break;
3017 }
3018 }
3019 }
3020
3021 if (!(pCfg->KbdInt.Type & CmResourceTypeInterrupt))
3022 {
3023 pCfg->KbdInt.Type = CmResourceTypeInterrupt;
3024 pCfg->KbdInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
3025 : CmResourceShareDeviceExclusive;
3026 pCfg->KbdInt.Flags = (DefIntMode == Latched) ? CM_RESOURCE_INTERRUPT_LATCHED
3027 : CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
3028 pCfg->KbdInt.u.Interrupt.Level = 1;
3029 pCfg->KbdInt.u.Interrupt.Vector = 1;
3030 }
3031
3032 if (pCfg->cPorts == 0)
3033 {
3034 pCfg->aPorts[i8042Dat].Type = CmResourceTypePort;
3035 pCfg->aPorts[i8042Dat].Flags = CM_RESOURCE_PORT_IO;
3036 pCfg->aPorts[i8042Dat].ShareDisposition = CmResourceShareDriverExclusive;
3037 pCfg->aPorts[i8042Dat].u.Port.Start.LowPart = 0x60;
3038 pCfg->aPorts[i8042Dat].u.Port.Start.HighPart = 0;
3039 pCfg->aPorts[i8042Dat].u.Port.Length = 1;
3040
3041 pCfg->aPorts[i8042Cmd].Type = CmResourceTypePort;
3042 pCfg->aPorts[i8042Cmd].Flags = CM_RESOURCE_PORT_IO;
3043 pCfg->aPorts[i8042Cmd].ShareDisposition = CmResourceShareDriverExclusive;
3044 pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart = 0x64;
3045 pCfg->aPorts[i8042Cmd].u.Port.Start.HighPart = 0;
3046 pCfg->aPorts[i8042Cmd].u.Port.Length = 1;
3047
3048 pCfg->cPorts = 2;
3049 }
3050 else if (pCfg->cPorts == 1)
3051 {
3052 pCfg->aPorts[i8042Dat].u.Port.Length = 1;
3053 pCfg->aPorts[i8042Cmd] = pCfg->aPorts[i8042Dat];
3054 pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart += 4;
3055 pCfg->cPorts++;
3056 }
3057 else
3058 {
3059 if (pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart < pCfg->aPorts[i8042Dat].u.Port.Start.LowPart)
3060 {
3061 CM_PARTIAL_RESOURCE_DESCRIPTOR Desc = pCfg->aPorts[i8042Dat];
3062 pCfg->aPorts[i8042Dat] = pCfg->aPorts[i8042Cmd];
3063 pCfg->aPorts[i8042Cmd] = Desc;
3064 }
3065 }
3066
3067 return STATUS_SUCCESS;
3068}
3069
3070/**
3071 * Callout routine. Grab the pointer controller and the peripheral
3072 * configuration information.
3073 */
3074static NTSTATUS MouCallOut(PVOID pCtx, PUNICODE_STRING PathName,
3075 INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
3076 CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
3077 CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf)
3078{
3079 RT_NOREF(PathName, pBusInf, uCtrlType, uCtrlNr, uPrfType, uPrfNr);
3080 NTSTATUS status = STATUS_SUCCESS;
3081
3082 UNICODE_STRING unicodeIdentifier;
3083 GetDevIdentifier(pPrfInf, &unicodeIdentifier);
3084
3085 PINITEXT pInit = (PINITEXT)pCtx;
3086 PDEVEXT pDevExt = &pInit->DevExt;
3087
3088 if ( (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
3089 || unicodeIdentifier.Length == 0)
3090 return status;
3091
3092 ANSI_STRING ansiString;
3093 status = RtlUnicodeStringToAnsiString(&ansiString, &unicodeIdentifier, TRUE);
3094 if (!NT_SUCCESS(status))
3095 return status;
3096
3097 if (strstr(ansiString.Buffer, "PS2"))
3098 pDevExt->HardwarePresent |= MOUSE_HARDWARE_PRESENT;
3099
3100 RtlFreeAnsiString(&ansiString);
3101
3102 if (!(pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT))
3103 return status;
3104
3105 PI8042CFGINF pCfg = &pDevExt->Cfg;
3106 if (!(pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
3107 {
3108 pCfg->InterfaceType = BusType;
3109 pCfg->uBusNr = uBusNr;
3110 pCfg->fFloatSave = FALSE;
3111 }
3112
3113 BOOLEAN fDefIntShare;
3114 KINTERRUPT_MODE DefIntMode;
3115 if (pCfg->InterfaceType == MicroChannel)
3116 {
3117 fDefIntShare = TRUE;
3118 DefIntMode = LevelSensitive;
3119 }
3120 else
3121 {
3122 fDefIntShare = FALSE;
3123 DefIntMode = Latched;
3124 }
3125
3126 PCM_PARTIAL_RESOURCE_LIST pCtrlData;
3127 if (GetDevCfgData(pCtrlInf, &pCtrlData))
3128 {
3129 unsigned cList = pCtrlData->Count;
3130 PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pCtrlData->PartialDescriptors;
3131 BOOLEAN fPortInfoNeeded = pCfg->cPorts ? FALSE : TRUE;
3132
3133 for (unsigned i = 0; i < cList; i++, pResDesc++)
3134 {
3135 switch (pResDesc->Type)
3136 {
3137 case CmResourceTypePort:
3138 if (fPortInfoNeeded)
3139 {
3140 pCfg->aPorts[pCfg->cPorts] = *pResDesc;
3141 pCfg->aPorts[pCfg->cPorts].ShareDisposition = CmResourceShareDriverExclusive;
3142 pCfg->cPorts++;
3143 }
3144 break;
3145
3146 case CmResourceTypeInterrupt:
3147 pCfg->MouInt = *pResDesc;
3148 pCfg->MouInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
3149 : CmResourceShareDeviceExclusive;
3150 break;
3151
3152 default:
3153 break;
3154 }
3155 }
3156 }
3157
3158 if (!(pCfg->MouInt.Type & CmResourceTypeInterrupt))
3159 {
3160 pCfg->MouInt.Type = CmResourceTypeInterrupt;
3161 pCfg->MouInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
3162 : CmResourceShareDeviceExclusive;
3163 pCfg->MouInt.Flags = (DefIntMode == Latched) ? CM_RESOURCE_INTERRUPT_LATCHED
3164 : CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
3165 pCfg->MouInt.u.Interrupt.Level = 12;
3166 pCfg->MouInt.u.Interrupt.Vector = 12;
3167 }
3168
3169 if (pCfg->cPorts == 0)
3170 {
3171 pCfg->aPorts[i8042Dat].Type = CmResourceTypePort;
3172 pCfg->aPorts[i8042Dat].Flags = CM_RESOURCE_PORT_IO;
3173 pCfg->aPorts[i8042Dat].ShareDisposition = CmResourceShareDriverExclusive;
3174 pCfg->aPorts[i8042Dat].u.Port.Start.LowPart = 0x60;
3175 pCfg->aPorts[i8042Dat].u.Port.Start.HighPart = 0;
3176 pCfg->aPorts[i8042Dat].u.Port.Length = 1;
3177
3178 pCfg->aPorts[i8042Cmd].Type = CmResourceTypePort;
3179 pCfg->aPorts[i8042Cmd].Flags = CM_RESOURCE_PORT_IO;
3180 pCfg->aPorts[i8042Cmd].ShareDisposition = CmResourceShareDriverExclusive;
3181 pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart = 0x64;
3182 pCfg->aPorts[i8042Cmd].u.Port.Start.HighPart = 0;
3183 pCfg->aPorts[i8042Cmd].u.Port.Length = 1;
3184
3185 pCfg->cPorts = 2;
3186 }
3187 else if (pCfg->cPorts == 1)
3188 {
3189 pCfg->aPorts[i8042Cmd] = pCfg->aPorts[i8042Dat];
3190 pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart += 4;
3191 pCfg->cPorts++;
3192 }
3193 else
3194 {
3195 if (pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart < pCfg->aPorts[i8042Dat].u.Port.Start.LowPart)
3196 {
3197 CM_PARTIAL_RESOURCE_DESCRIPTOR Desc = pCfg->aPorts[i8042Dat];
3198 pCfg->aPorts[i8042Dat] = pCfg->aPorts[i8042Cmd];
3199 pCfg->aPorts[i8042Cmd] = Desc;
3200 }
3201 }
3202
3203 return status;
3204}
3205
3206static const UCHAR s_ucCommands[] =
3207{
3208 SET_MOUSE_SAMPLING_RATE, 200,
3209 SET_MOUSE_SAMPLING_RATE, 100,
3210 SET_MOUSE_SAMPLING_RATE, 80,
3211 GET_DEVICE_ID, 0
3212};
3213
3214static NTSTATUS MouFindWheel(PDEVICE_OBJECT pDevObj)
3215{
3216 NTSTATUS status = STATUS_SUCCESS; /* Shut up MSC. */
3217 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
3218
3219 if (!pDevExt->Cfg.EnableWheelDetection)
3220 return STATUS_NO_SUCH_DEVICE;
3221
3222 KeStallExecutionProcessor(50);
3223
3224 for (unsigned iCmd = 0; s_ucCommands[iCmd];)
3225 {
3226 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, s_ucCommands[iCmd]);
3227 if (!NT_SUCCESS(status))
3228 goto fail;
3229
3230 iCmd++;
3231 KeStallExecutionProcessor(50);
3232 }
3233
3234 UCHAR byte = UINT8_MAX;
3235 for (unsigned i = 0; i < 5; i++)
3236 {
3237 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
3238 if (status != STATUS_IO_TIMEOUT)
3239 break;
3240 KeStallExecutionProcessor(50);
3241 }
3242
3243 if ( NT_SUCCESS(status)
3244 && (byte == MOUSE_ID_BYTE || byte == WHEELMOUSE_ID_BYTE))
3245 {
3246 if (byte == WHEELMOUSE_ID_BYTE)
3247 {
3248 pDevExt->HardwarePresent |= (WHEELMOUSE_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT);
3249 pDevExt->Cfg.MouAttr.MouseIdentifier = WHEELMOUSE_I8042_HARDWARE;
3250 }
3251 else
3252 pDevExt->HardwarePresent |= MOUSE_HARDWARE_PRESENT;
3253 }
3254
3255fail:
3256 pDevExt->MouExt.uPrevSignAndOverflow = 0;
3257 pDevExt->MouExt.InputState = MouseExpectingACK;
3258 return status;
3259}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette