VirtualBox

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

Last change on this file since 53402 was 42154, checked in by vboxsync, 12 years ago

VS2010 preps.

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