VirtualBox

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

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

*: scm --update-copyright-year

  • 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 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 * VBox NT4 Mouse Driver
4 */
5
6/*
7 * Copyright (C) 2011-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_DRV_MOUSE
19#include <iprt/asm.h>
20#include <VBox/err.h>
21#include <VBox/log.h>
22
23#include <stdarg.h>
24#include <string.h>
25#undef PAGE_SIZE
26#undef PAGE_SHIFT
27#include <iprt/nt/ntddk.h>
28RT_C_DECLS_BEGIN
29#include <ntddkbd.h>
30#include <ntddmou.h>
31RT_C_DECLS_END
32
33#include <VBox/VMMDev.h>
34#include <VBox/VBoxGuestLib.h>
35
36/* not available on NT4 */
37#undef ExFreePool
38#undef ExAllocatePool
39
40/* 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; /**< whether 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 RT_NOREF(Dpc, pCtx);
977
978 Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
979
980 IoStartNextPacket(pDevObj, FALSE);
981 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
982}
983
984static UCHAR TypematicPeriod[] =
985{
986 31, 31, 28, 26, 23, 20, 18, 17, 15, 13, 12, 11, 10, 9,
987 9, 8, 7, 6, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1
988};
989
990/**
991 * Convert typematic rate/delay to a value expected by the keyboard:
992 * - bit 7 is zero
993 * - bits 5...6 indicate the delay
994 * - bits 0...4 indicate the rate
995 */
996static UCHAR ConvertTypematic(USHORT Rate, USHORT Delay)
997{
998 UCHAR value = (UCHAR) ((Delay / 250) - 1);
999 value <<= 5;
1000 if (Rate <= 27)
1001 value |= TypematicPeriod[Rate];
1002
1003 return value;
1004}
1005
1006/**
1007 * Start an I/O operation for the device.
1008 */
1009static VOID I8042StartIo(PDEVICE_OBJECT pDevObj, PIRP Irp)
1010{
1011 KBDINITIATECTX keyboardInitiateContext;
1012 LARGE_INTEGER deltaTime;
1013 LONG interlockedResult;
1014
1015 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
1016
1017 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
1018 switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
1019 {
1020 case IOCTL_INTERNAL_KEYBOARD_ENABLE:
1021 interlockedResult = ASMAtomicIncU32(&pDevExt->KeyboardEnableCount);
1022 Irp->IoStatus.Status = STATUS_SUCCESS;
1023 IoStartNextPacket(pDevObj, FALSE);
1024 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
1025 break;
1026
1027 case IOCTL_INTERNAL_KEYBOARD_DISABLE:
1028 if (pDevExt->KeyboardEnableCount == 0)
1029 Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
1030 else
1031 {
1032 ASMAtomicDecU32(&pDevExt->KeyboardEnableCount);
1033 Irp->IoStatus.Status = STATUS_SUCCESS;
1034 }
1035 IoStartNextPacket(pDevObj, FALSE);
1036 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
1037 break;
1038
1039 case IOCTL_INTERNAL_MOUSE_ENABLE:
1040 ASMAtomicIncU32(&pDevExt->MouseEnableCount);
1041 Irp->IoStatus.Status = STATUS_SUCCESS;
1042 IoStartNextPacket(pDevObj, FALSE);
1043 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
1044 break;
1045
1046 case IOCTL_INTERNAL_MOUSE_DISABLE:
1047 if (pDevExt->MouseEnableCount == 0)
1048 Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
1049 else
1050 {
1051 ASMAtomicDecU32(&pDevExt->MouseEnableCount);
1052 Irp->IoStatus.Status = STATUS_SUCCESS;
1053 }
1054 IoStartNextPacket(pDevObj, FALSE);
1055 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
1056 break;
1057
1058 case IOCTL_KEYBOARD_SET_INDICATORS:
1059 keyboardInitiateContext.pDevObj = pDevObj;
1060 keyboardInitiateContext.FirstByte = SET_KEYBOARD_INDICATORS;
1061 keyboardInitiateContext.LastByte =
1062 (UCHAR) ((PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->LedFlags;
1063 KeSynchronizeExecution(pDevExt->KbdIntObj, KbdStartWrapper, &keyboardInitiateContext);
1064 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1065 deltaTime.HighPart = -1;
1066 KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
1067 break;
1068
1069 case IOCTL_KEYBOARD_SET_TYPEMATIC:
1070 keyboardInitiateContext.pDevObj = pDevObj;
1071 keyboardInitiateContext.FirstByte = SET_KEYBOARD_TYPEMATIC;
1072 keyboardInitiateContext.LastByte =
1073 ConvertTypematic(((PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->Rate,
1074 ((PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->Delay);
1075
1076 KeSynchronizeExecution(pDevExt->KbdIntObj, KbdStartWrapper, &keyboardInitiateContext);
1077 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1078 deltaTime.HighPart = -1;
1079 KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
1080 break;
1081
1082 default:
1083 ASSERT(FALSE);
1084 break;
1085 }
1086}
1087
1088/**
1089 * Driver's command timeout routine.
1090 */
1091static VOID CtrlTimeoutDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PVOID SystemContext1, PVOID SystemContext2)
1092{
1093 RT_NOREF(Dpc, SystemContext1, SystemContext2);
1094 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
1095
1096 KIRQL cancelIrql;
1097 IoAcquireCancelSpinLock(&cancelIrql);
1098 PIRP irp = pDevObj->CurrentIrp;
1099 if (!irp)
1100 {
1101 IoReleaseCancelSpinLock(cancelIrql);
1102 return;
1103 }
1104 IoSetCancelRoutine(irp, NULL);
1105 IoReleaseCancelSpinLock(cancelIrql);
1106
1107 TIMERCTX timerContext;
1108 timerContext.pDevObj = pDevObj;
1109 timerContext.TimerCounter = &pDevExt->TimerCount;
1110 KeSynchronizeExecution(pDevExt->KbdIntObj, DecTimer, &timerContext);
1111
1112 if (timerContext.NewTimerCount == 0)
1113 {
1114 pDevObj->CurrentIrp->IoStatus.Information = 0;
1115 pDevObj->CurrentIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
1116
1117 IoStartNextPacket(pDevObj, FALSE);
1118 IoCompleteRequest(irp, IO_KEYBOARD_INCREMENT);
1119 }
1120 else
1121 {
1122 LARGE_INTEGER deltaTime;
1123 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1124 deltaTime.HighPart = -1;
1125 KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
1126 }
1127}
1128
1129/**
1130 * DISPATCH_LEVEL IRQL: Finish processing for keyboard interrupts.
1131 */
1132static VOID CtrlKbdIsrDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
1133{
1134 NOREF(Dpc);
1135 NOREF(Irp);
1136 NOREF(pCtx);
1137
1138 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
1139
1140 VAROPCTX opCtx;
1141 LONG interlockedResult;
1142 opCtx.VariableAddress = &pDevExt->DpcInterlockKeyboard;
1143 opCtx.Operation = IncrementOperation;
1144 opCtx.NewValue = &interlockedResult;
1145 KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, (PVOID)&opCtx);
1146 BOOLEAN fContinue = (interlockedResult == 0) ? TRUE : FALSE;
1147
1148 while (fContinue)
1149 {
1150 ULONG cbNotConsumed = 0;
1151 ULONG inputDataConsumed = 0;
1152
1153 GETDATAPTRCTX getPtrCtx;
1154 getPtrCtx.pDevExt = pDevExt;
1155 getPtrCtx.DevType = KbdDevType;
1156 SETDATAPTRCTX setPtrCtx;
1157 setPtrCtx.pDevExt = pDevExt;
1158 setPtrCtx.DevType = KbdDevType;
1159 setPtrCtx.cInput = 0;
1160 KeSynchronizeExecution(pDevExt->KbdIntObj, GetDataQueuePtr, &getPtrCtx);
1161
1162 if (getPtrCtx.cInput)
1163 {
1164 PVOID classDeviceObject = pDevExt->KbdExt.ConnectData.ClassDeviceObject;
1165 PSERVICECALLBACK classService = pDevExt->KbdExt.ConnectData.ClassService;
1166 ASSERT(classService);
1167
1168 if (getPtrCtx.DataOut >= getPtrCtx.DataIn)
1169 {
1170 classService(classDeviceObject, getPtrCtx.DataOut, pDevExt->KbdExt.DataEnd, &inputDataConsumed);
1171 cbNotConsumed = (((PUCHAR) pDevExt->KbdExt.DataEnd - (PUCHAR) getPtrCtx.DataOut)
1172 / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
1173
1174 setPtrCtx.cInput += inputDataConsumed;
1175
1176 if (cbNotConsumed)
1177 {
1178 setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut)
1179 + (inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
1180 }
1181 else
1182 {
1183 setPtrCtx.DataOut = pDevExt->KbdExt.InputData;
1184 getPtrCtx.DataOut = setPtrCtx.DataOut;
1185 }
1186 }
1187
1188 if ( cbNotConsumed == 0
1189 && inputDataConsumed < getPtrCtx.cInput)
1190 {
1191 classService(classDeviceObject, getPtrCtx.DataOut, getPtrCtx.DataIn, &inputDataConsumed);
1192 cbNotConsumed = (((PUCHAR) getPtrCtx.DataIn - (PUCHAR) getPtrCtx.DataOut)
1193 / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
1194
1195 setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) +
1196 (inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
1197 setPtrCtx.cInput += inputDataConsumed;
1198 }
1199
1200 KeSynchronizeExecution(pDevExt->KbdIntObj, SetDataQueuePtr, &setPtrCtx);
1201 }
1202
1203 if (cbNotConsumed)
1204 {
1205 opCtx.Operation = WriteOperation;
1206 interlockedResult = -1;
1207 opCtx.NewValue = &interlockedResult;
1208 KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
1209
1210 LARGE_INTEGER deltaTime;
1211 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1212 deltaTime.HighPart = -1;
1213 KeSetTimer(&pDevExt->KbdExt.DataConsumptionTimer, deltaTime, &pDevExt->KeyboardIsrDpcRetry);
1214 fContinue = FALSE;
1215 }
1216 else
1217 {
1218 opCtx.Operation = DecrementOperation;
1219 opCtx.NewValue = &interlockedResult;
1220 KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
1221 if (interlockedResult != -1)
1222 {
1223 opCtx.Operation = WriteOperation;
1224 interlockedResult = 0;
1225 opCtx.NewValue = &interlockedResult;
1226 KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
1227 }
1228 else
1229 fContinue = FALSE;
1230 }
1231 }
1232}
1233
1234/**
1235 * DISPATCH_LEVEL IRQL: Finish processing of mouse interrupts
1236 */
1237static VOID CtrlMouIsrDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
1238{
1239 NOREF(Dpc);
1240 NOREF(Irp);
1241 NOREF(pCtx);
1242
1243 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
1244
1245 VAROPCTX opCtx;
1246 LONG interlockedResult;
1247 opCtx.VariableAddress = &pDevExt->DpcInterlockMouse;
1248 opCtx.Operation = IncrementOperation;
1249 opCtx.NewValue = &interlockedResult;
1250 KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
1251 BOOLEAN fContinue = (interlockedResult == 0) ? TRUE : FALSE;
1252 while (fContinue)
1253 {
1254 ULONG cbNotConsumed = 0;
1255 ULONG inputDataConsumed = 0;
1256
1257 GETDATAPTRCTX getPtrCtx;
1258 getPtrCtx.pDevExt = pDevExt;
1259 getPtrCtx.DevType = MouDevType;
1260 SETDATAPTRCTX setPtrCtx;
1261 setPtrCtx.pDevExt = pDevExt;
1262 setPtrCtx.DevType = MouDevType;
1263 setPtrCtx.cInput = 0;
1264 KeSynchronizeExecution(pDevExt->MouIntObj, GetDataQueuePtr, &getPtrCtx);
1265 if (getPtrCtx.cInput)
1266 {
1267 PVOID classDeviceObject = pDevExt->MouExt.ConnectData.ClassDeviceObject;
1268 PSERVICECALLBACK classService = pDevExt->MouExt.ConnectData.ClassService;
1269 ASSERT(classService);
1270
1271 if (getPtrCtx.DataOut >= getPtrCtx.DataIn)
1272 {
1273 classService(classDeviceObject, getPtrCtx.DataOut, pDevExt->MouExt.DataEnd, &inputDataConsumed);
1274 cbNotConsumed = (((PUCHAR)pDevExt->MouExt.DataEnd - (PUCHAR) getPtrCtx.DataOut)
1275 / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
1276
1277 setPtrCtx.cInput += inputDataConsumed;
1278 if (cbNotConsumed)
1279 {
1280 setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) + (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
1281 }
1282 else
1283 {
1284 setPtrCtx.DataOut = pDevExt->MouExt.InputData;
1285 getPtrCtx.DataOut = setPtrCtx.DataOut;
1286 }
1287 }
1288
1289 if ( cbNotConsumed == 0
1290 && inputDataConsumed < getPtrCtx.cInput)
1291 {
1292 classService(classDeviceObject, getPtrCtx.DataOut, getPtrCtx.DataIn, &inputDataConsumed);
1293 cbNotConsumed = (((PUCHAR) getPtrCtx.DataIn - (PUCHAR) getPtrCtx.DataOut)
1294 / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
1295
1296 setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) + (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
1297 setPtrCtx.cInput += inputDataConsumed;
1298 }
1299 KeSynchronizeExecution(pDevExt->MouIntObj, SetDataQueuePtr, &setPtrCtx);
1300 }
1301
1302 if (cbNotConsumed)
1303 {
1304 opCtx.Operation = WriteOperation;
1305 interlockedResult = -1;
1306 opCtx.NewValue = &interlockedResult;
1307 KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
1308
1309 LARGE_INTEGER deltaTime;
1310 deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1311 deltaTime.HighPart = -1;
1312 KeSetTimer(&pDevExt->MouExt.DataConsumptionTimer, deltaTime, &pDevExt->MouseIsrDpcRetry);
1313 fContinue = FALSE;
1314 }
1315 else
1316 {
1317 opCtx.Operation = DecrementOperation;
1318 opCtx.NewValue = &interlockedResult;
1319 KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
1320
1321 if (interlockedResult != -1)
1322 {
1323 opCtx.Operation = WriteOperation;
1324 interlockedResult = 0;
1325 opCtx.NewValue = &interlockedResult;
1326 KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
1327 }
1328 else
1329 fContinue = FALSE;
1330 }
1331 }
1332}
1333
1334/**
1335 * Interrupt service routine for the mouse device.
1336 */
1337static BOOLEAN MouIntHandler(PKINTERRUPT Interrupt, PVOID pCtx)
1338{
1339 UCHAR uPrevSignAndOverflow;
1340
1341 NOREF(Interrupt);
1342
1343 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCtx;
1344 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
1345
1346 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1347 != (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1348 {
1349 KeStallExecutionProcessor(10);
1350 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1351 != (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1352 return FALSE;
1353 }
1354
1355 UCHAR byte;
1356 GetByteAsync(MouDevType, pDevExt, &byte);
1357
1358 if ( pDevExt->MouExt.LastByteReceived == 0xaa
1359 && byte == 0x00)
1360 {
1361 pDevExt->HardwarePresent &= ~WHEELMOUSE_HARDWARE_PRESENT;
1362 pDevExt->Cfg.MouAttr.NumberOfButtons = 2;
1363
1364 PutByteAsync(i8042Cmd, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
1365 PutByteAsync(i8042Dat, pDevExt, ENABLE_MOUSE_TRANSMISSION);
1366
1367 pDevExt->MouExt.InputState = MouseExpectingACK;
1368 }
1369
1370 pDevExt->MouExt.LastByteReceived = byte;
1371
1372 LARGE_INTEGER tickDelta, newTick;
1373 KeQueryTickCount(&newTick);
1374 tickDelta.QuadPart = newTick.QuadPart - pDevExt->MouExt.PreviousTick.QuadPart;
1375 if ( pDevExt->MouExt.InputState != MouseIdle
1376 && pDevExt->MouExt.InputState != MouseExpectingACK
1377 && (tickDelta.LowPart >= pDevExt->MouExt.SynchTickCount || tickDelta.HighPart != 0))
1378 pDevExt->MouExt.InputState = MouseIdle;
1379 pDevExt->MouExt.PreviousTick = newTick;
1380
1381 switch (pDevExt->MouExt.InputState)
1382 {
1383 case MouseIdle:
1384 {
1385 UCHAR fPrevBtns = pDevExt->MouExt.PreviousButtons;
1386 pDevExt->MouExt.CurrentInput.ButtonFlags = 0;
1387 pDevExt->MouExt.CurrentInput.ButtonData = 0;
1388
1389 if ((!(fPrevBtns & LEFT_BUTTON_DOWN)) && (byte & LEFT_BUTTON_DOWN))
1390 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
1391 else if ((fPrevBtns & LEFT_BUTTON_DOWN) && !(byte & LEFT_BUTTON_DOWN))
1392 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
1393 if ((!(fPrevBtns & RIGHT_BUTTON_DOWN)) && (byte & RIGHT_BUTTON_DOWN))
1394 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
1395 else if ((fPrevBtns & RIGHT_BUTTON_DOWN) && !(byte & RIGHT_BUTTON_DOWN))
1396 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
1397 if ((!(fPrevBtns & MIDDLE_BUTTON_DOWN)) && (byte & MIDDLE_BUTTON_DOWN))
1398 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
1399 else if ((fPrevBtns & MIDDLE_BUTTON_DOWN) && !(byte & MIDDLE_BUTTON_DOWN))
1400 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
1401
1402 pDevExt->MouExt.PreviousButtons = byte & (RIGHT_BUTTON_DOWN|MIDDLE_BUTTON_DOWN|LEFT_BUTTON_DOWN);
1403 pDevExt->MouExt.uCurrSignAndOverflow = (UCHAR) (byte & MOUSE_SIGN_OVERFLOW_MASK);
1404 pDevExt->MouExt.InputState = XMovement;
1405 break;
1406 }
1407
1408 case XMovement:
1409 {
1410 if (pDevExt->MouExt.uCurrSignAndOverflow & X_OVERFLOW)
1411 {
1412 uPrevSignAndOverflow = pDevExt->MouExt.uPrevSignAndOverflow;
1413 if (uPrevSignAndOverflow & X_OVERFLOW)
1414 {
1415 if ((uPrevSignAndOverflow & X_DATA_SIGN) != (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN))
1416 pDevExt->MouExt.uCurrSignAndOverflow ^= X_DATA_SIGN;
1417 }
1418 if (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN)
1419 pDevExt->MouExt.CurrentInput.LastX = MOUSE_MAXIMUM_NEGATIVE_DELTA;
1420 else
1421 pDevExt->MouExt.CurrentInput.LastX = MOUSE_MAXIMUM_POSITIVE_DELTA;
1422 }
1423 else
1424 {
1425 pDevExt->MouExt.CurrentInput.LastX = (ULONG) byte;
1426 if (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN)
1427 pDevExt->MouExt.CurrentInput.LastX |= MOUSE_MAXIMUM_NEGATIVE_DELTA;
1428 }
1429 pDevExt->MouExt.InputState = YMovement;
1430 break;
1431 }
1432
1433 case YMovement:
1434 {
1435 if (pDevExt->MouExt.uCurrSignAndOverflow & Y_OVERFLOW)
1436 {
1437 uPrevSignAndOverflow = pDevExt->MouExt.uPrevSignAndOverflow;
1438 if (uPrevSignAndOverflow & Y_OVERFLOW)
1439 {
1440 if ((uPrevSignAndOverflow & Y_DATA_SIGN) != (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN))
1441 pDevExt->MouExt.uCurrSignAndOverflow ^= Y_DATA_SIGN;
1442 }
1443 if (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN)
1444 pDevExt->MouExt.CurrentInput.LastY = MOUSE_MAXIMUM_POSITIVE_DELTA;
1445 else
1446 pDevExt->MouExt.CurrentInput.LastY = MOUSE_MAXIMUM_NEGATIVE_DELTA;
1447 }
1448 else
1449 {
1450 pDevExt->MouExt.CurrentInput.LastY = (ULONG) byte;
1451 if (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN)
1452 pDevExt->MouExt.CurrentInput.LastY |= MOUSE_MAXIMUM_NEGATIVE_DELTA;
1453 pDevExt->MouExt.CurrentInput.LastY = -pDevExt->MouExt.CurrentInput.LastY;
1454 }
1455 pDevExt->MouExt.uPrevSignAndOverflow = pDevExt->MouExt.uCurrSignAndOverflow;
1456
1457 if (pDevExt->HardwarePresent & WHEELMOUSE_HARDWARE_PRESENT)
1458 pDevExt->MouExt.InputState = ZMovement;
1459 else
1460 {
1461 pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_RELATIVE;
1462
1463 {
1464 VMMDevReqMouseStatus *pReq = pDevExt->pReq;
1465 if (pReq)
1466 {
1467 int rc = VbglR0GRPerform (&pReq->header);
1468 if (RT_SUCCESS(rc))
1469 {
1470 if (pReq->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
1471 {
1472 /* make it an absolute move */
1473 pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_ABSOLUTE;
1474 pDevExt->MouExt.CurrentInput.LastX = pReq->pointerXPos;
1475 pDevExt->MouExt.CurrentInput.LastY = pReq->pointerYPos;
1476 }
1477 }
1478 else
1479 Log(("VBoxMouseNT: ERROR querying mouse capabilities from VMMDev. rc = %Rrc\n", rc));
1480 }
1481 }
1482 QueueInput(pDevObj);
1483 pDevExt->MouExt.InputState = MouseIdle;
1484 }
1485 break;
1486 }
1487
1488 case ZMovement:
1489 {
1490#if 0
1491 if (byte && pDevExt->MouExt.CurrentInput.Buttons == 0)
1492#else
1493 if (byte)
1494#endif
1495 {
1496 if (byte & 0x80)
1497 pDevExt->MouExt.CurrentInput.ButtonData = 0x0078;
1498 else
1499 pDevExt->MouExt.CurrentInput.ButtonData = 0xFF88;
1500 pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_WHEEL;
1501 }
1502
1503 pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_RELATIVE;
1504
1505 {
1506 VMMDevReqMouseStatus *pReq = pDevExt->pReq;
1507 if (pReq)
1508 {
1509 int rc = VbglR0GRPerform(&pReq->header);
1510 if (RT_SUCCESS(rc))
1511 {
1512 if (pReq->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
1513 {
1514 /* make it an absolute move */
1515 pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_ABSOLUTE;
1516 pDevExt->MouExt.CurrentInput.LastX = pReq->pointerXPos;
1517 pDevExt->MouExt.CurrentInput.LastY = pReq->pointerYPos;
1518 }
1519 }
1520 else
1521 Log(("VBoxMouseNT: ERROR querying mouse capabilities from VMMDev. rc = %Rrc\n", rc));
1522 }
1523 }
1524
1525 QueueInput(pDevObj);
1526 pDevExt->MouExt.InputState = MouseIdle;
1527 break;
1528 }
1529
1530 case MouseExpectingACK:
1531 {
1532 if (byte == ACKNOWLEDGE)
1533 pDevExt->MouExt.InputState = MouseIdle;
1534 else if (byte == RESEND)
1535 {
1536 PutByteAsync(i8042Cmd, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
1537 PutByteAsync(i8042Dat, pDevExt, ENABLE_MOUSE_TRANSMISSION);
1538 }
1539 break;
1540 }
1541
1542 default:
1543 {
1544 ASSERT(FALSE);
1545 break;
1546 }
1547 }
1548
1549 return TRUE;
1550}
1551
1552/**
1553 * Interrupt service routine.
1554 */
1555static BOOLEAN KbdIntHandler(PKINTERRUPT Interrupt, PVOID pCtx)
1556{
1557 NOREF(Interrupt);
1558
1559 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCtx;
1560 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
1561
1562 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1563 != OUTPUT_BUFFER_FULL)
1564 {
1565 for (unsigned i = 0; i < (ULONG)pDevExt->Cfg.PollStatusIterations; i++)
1566 {
1567 KeStallExecutionProcessor(1);
1568 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1569 == (OUTPUT_BUFFER_FULL))
1570 break;
1571 }
1572
1573 if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
1574 != (OUTPUT_BUFFER_FULL))
1575 {
1576 if (pDevExt->KeyboardEnableCount == 0)
1577 {
1578 UCHAR scanCode = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
1579 NOREF(scanCode);
1580 }
1581 return FALSE;
1582 }
1583 }
1584
1585 UCHAR scanCode;
1586 GetByteAsync(KbdDevType, pDevExt, &scanCode);
1587 switch (scanCode)
1588 {
1589 case RESEND:
1590 if (pDevExt->TimerCount == 0)
1591 break;
1592 pDevExt->TimerCount = -1;
1593
1594 if ( pDevExt->KbdExt.CurrentOutput.State==Idle
1595 || !pDevObj->CurrentIrp)
1596 goto ScanCodeCase;
1597 else if (pDevExt->KbdExt.ResendCount < pDevExt->Cfg.iResend)
1598 {
1599 pDevExt->KbdExt.ResendCount++;
1600 KbdStartIO(pDevObj);
1601 }
1602 else
1603 {
1604 pDevExt->KbdExt.CurrentOutput.State = Idle;
1605 KeInsertQueueDpc(&pDevExt->RetriesExceededDpc, pDevObj->CurrentIrp, NULL);
1606 }
1607 break;
1608
1609 case ACKNOWLEDGE:
1610 if (pDevExt->TimerCount == 0)
1611 break;
1612
1613 pDevExt->TimerCount = -1;
1614
1615 pDevExt->KbdExt.ResendCount = 0;
1616 if (pDevExt->KbdExt.CurrentOutput.State == SendFirstByte)
1617 {
1618 pDevExt->KbdExt.CurrentOutput.State = SendLastByte;
1619 KbdStartIO(pDevObj);
1620 }
1621 else if (pDevExt->KbdExt.CurrentOutput.State == SendLastByte)
1622 {
1623 pDevExt->KbdExt.CurrentOutput.State = Idle;
1624 IoRequestDpc(pDevObj, pDevObj->CurrentIrp, NULL);
1625 }
1626 break;
1627
1628 ScanCodeCase:
1629 default:
1630 {
1631 PKEYBOARD_INPUT_DATA input = &pDevExt->KbdExt.CurrentInput;
1632 KBDSCANSTATE *pScanState = &pDevExt->KbdExt.CurrentScanState;
1633
1634 if (scanCode == (UCHAR) 0xFF)
1635 {
1636 input->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
1637 input->Flags = 0;
1638 *pScanState = Normal;
1639 }
1640 else
1641 {
1642 switch (*pScanState)
1643 {
1644 case Normal:
1645 if (scanCode == (UCHAR) 0xE0)
1646 {
1647 input->Flags |= KEY_E0;
1648 *pScanState = GotE0;
1649 break;
1650 }
1651 else if (scanCode == (UCHAR) 0xE1)
1652 {
1653 input->Flags |= KEY_E1;
1654 *pScanState = GotE1;
1655 break;
1656 }
1657 /* fall through */
1658 case GotE0:
1659 case GotE1:
1660 if (scanCode > 0x7F)
1661 {
1662 input->MakeCode = scanCode & 0x7F;
1663 input->Flags |= KEY_BREAK;
1664 }
1665 else
1666 input->MakeCode = scanCode;
1667 *pScanState = Normal;
1668 break;
1669
1670 default:
1671 ASSERT(FALSE);
1672 break;
1673 }
1674 }
1675
1676 if (*pScanState == Normal)
1677 {
1678 if (pDevExt->KeyboardEnableCount)
1679 {
1680 pDevExt->KbdExt.CurrentInput.UnitId = pDevExt->KbdExt.UnitId;
1681 if (!KbdDataToQueue(&pDevExt->KbdExt, input))
1682 {
1683 }
1684 else if (pDevExt->DpcInterlockKeyboard >= 0)
1685 pDevExt->DpcInterlockKeyboard++;
1686 else
1687 KeInsertQueueDpc(&pDevExt->KeyboardIsrDpc, pDevObj->CurrentIrp, NULL);
1688 }
1689 input->Flags = 0;
1690 }
1691 break;
1692 }
1693 }
1694 return TRUE;
1695}
1696
1697static NTSTATUS MouEnableTrans(PDEVICE_OBJECT pDevObj)
1698{
1699 NTSTATUS status;
1700
1701 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
1702 status = PutBytePoll(i8042Dat, FALSE /*=wait*/, MouDevType, pDevExt, ENABLE_MOUSE_TRANSMISSION);
1703 return status;
1704}
1705
1706/**
1707 * Configuration information for the keyboard.
1708 */
1709static VOID KbdGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
1710 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
1711{
1712 PDEVEXT pDevExt = &pInit->DevExt;
1713 for (unsigned i = 0; i < MaximumInterfaceType; i++)
1714 {
1715 INTERFACE_TYPE interfaceType = (INTERFACE_TYPE)i;
1716 CONFIGURATION_TYPE controllerType = KeyboardController;
1717 CONFIGURATION_TYPE peripheralType = KeyboardPeripheral;
1718 NTSTATUS status = IoQueryDeviceDescription(&interfaceType, NULL,
1719 &controllerType, NULL,
1720 &peripheralType, NULL,
1721 KbdCallOut, pInit);
1722 NOREF(status); /* how diligent of us */
1723
1724 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
1725 {
1726 HwGetRegstry(pInit, RegistryPath, KeyboardDeviceName, PointerDeviceName);
1727
1728 PI8042CFGINF pCfg = &pInit->DevExt.Cfg;
1729 PKEYBOARD_ID keyboardId = &pCfg->KbdAttr.KeyboardIdentifier;
1730 if (!ENHANCED_KEYBOARD(*keyboardId))
1731 pCfg->PollingIterations = pCfg->PollingIterationsMaximum;
1732
1733 pCfg->KbdAttr.NumberOfFunctionKeys = s_aKeybType[keyboardId->Type-1].cFunctionKeys;
1734 pCfg->KbdAttr.NumberOfIndicators = s_aKeybType[keyboardId->Type-1].cIndicators;
1735 pCfg->KbdAttr.NumberOfKeysTotal = s_aKeybType[keyboardId->Type-1].cKeysTotal;
1736 pCfg->KbdAttr.KeyboardMode = 1;
1737 pCfg->KbdAttr.KeyRepeatMinimum.Rate = 2;
1738 pCfg->KbdAttr.KeyRepeatMinimum.Delay = 250;
1739 pCfg->KbdAttr.KeyRepeatMaximum.Rate = 30;
1740 pCfg->KbdAttr.KeyRepeatMaximum.Delay = 1000;
1741 pCfg->KeyRepeatCurrent.Rate = 30;
1742 pCfg->KeyRepeatCurrent.Delay = 250;
1743 break;
1744 }
1745 }
1746}
1747
1748/**
1749 * Retrieve the configuration information for the mouse.
1750 */
1751static VOID MouGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
1752 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
1753{
1754 NTSTATUS status = STATUS_SUCCESS;
1755 INTERFACE_TYPE interfaceType;
1756 CONFIGURATION_TYPE controllerType = PointerController;
1757 CONFIGURATION_TYPE peripheralType = PointerPeripheral;
1758
1759 for (unsigned i = 0; i < MaximumInterfaceType; i++)
1760 {
1761 interfaceType = (INTERFACE_TYPE)i;
1762 status = IoQueryDeviceDescription(&interfaceType, NULL,
1763 &controllerType, NULL,
1764 &peripheralType, NULL,
1765 MouCallOut, pInit);
1766
1767 if (pInit->DevExt.HardwarePresent & MOUSE_HARDWARE_PRESENT)
1768 {
1769 if (!(pInit->DevExt.HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
1770 HwGetRegstry(pInit, RegistryPath, KeyboardDeviceName, PointerDeviceName);
1771 pInit->DevExt.Cfg.MouAttr.MouseIdentifier = MOUSE_I8042_HARDWARE;
1772 break;
1773 }
1774 }
1775}
1776
1777/**
1778 * Initialize the driver.
1779 */
1780NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING RegistryPath)
1781{
1782 PDEVICE_OBJECT pPortDevObj = NULL;
1783 PDEVEXT pDevExt = NULL;
1784 NTSTATUS status = STATUS_SUCCESS;
1785 KIRQL IrqlCoord = 0;
1786 ULONG IntVecKbd;
1787 ULONG IntVecMou;
1788 KIRQL IrqlKbd;
1789 KIRQL IrqlMou;
1790 KAFFINITY AffKbd;
1791 KAFFINITY AffMou;
1792 ULONG addressSpace;
1793 PHYSICAL_ADDRESS Phys;
1794 BOOLEAN fConflict;
1795
1796 ULONG resourceListSize = 0;
1797 PCM_RESOURCE_LIST resources = NULL;
1798
1799 UNICODE_STRING KbdNameFull = { 0, 0, NULL };
1800 UNICODE_STRING MouNameFull = { 0, 0, NULL };
1801 UNICODE_STRING KbdNameBase = { 0, 0, NULL };
1802 UNICODE_STRING MouNameBase = { 0, 0, NULL };
1803 UNICODE_STRING DevNameSuff = { 0, 0, NULL };
1804 UNICODE_STRING resourceDeviceClass = { 0, 0, NULL };
1805 UNICODE_STRING registryPath = { 0, 0, NULL };
1806
1807#define NAME_MAX 256
1808 WCHAR keyboardBuffer[NAME_MAX];
1809 WCHAR pointerBuffer[NAME_MAX];
1810
1811 LogFlow(("VBoxMouseNT::DriverEntry: enter\n"));
1812
1813 PINITEXT pInit = (PINITEXT)ExAllocatePool(NonPagedPool, sizeof(INITEXT));
1814 if (!pInit)
1815 {
1816 status = STATUS_UNSUCCESSFUL;
1817 goto fail;
1818 }
1819
1820 RtlZeroMemory(pInit, sizeof(INITEXT));
1821 RtlZeroMemory(keyboardBuffer, NAME_MAX * sizeof(WCHAR));
1822 KbdNameBase.Buffer = keyboardBuffer;
1823 KbdNameBase.Length = 0;
1824 KbdNameBase.MaximumLength = NAME_MAX * sizeof(WCHAR);
1825 RtlZeroMemory(pointerBuffer, NAME_MAX * sizeof(WCHAR));
1826 MouNameBase.Buffer = pointerBuffer;
1827 MouNameBase.Length = 0;
1828 MouNameBase.MaximumLength = NAME_MAX * sizeof(WCHAR);
1829
1830 registryPath.Buffer = (PWSTR)ExAllocatePool(PagedPool, RegistryPath->Length + sizeof(UNICODE_NULL));
1831 if (!registryPath.Buffer)
1832 {
1833 status = STATUS_UNSUCCESSFUL;
1834 goto fail;
1835 }
1836 else
1837 {
1838 registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
1839 registryPath.MaximumLength = registryPath.Length;
1840
1841 RtlZeroMemory(registryPath.Buffer, registryPath.Length);
1842 RtlMoveMemory(registryPath.Buffer, RegistryPath->Buffer, RegistryPath->Length);
1843 }
1844
1845 KbdGetRegstry(pInit, &registryPath, &KbdNameBase, &MouNameBase);
1846 MouGetRegstry(pInit, &registryPath, &KbdNameBase, &MouNameBase);
1847 if (pInit->DevExt.HardwarePresent == 0)
1848 {
1849 status = STATUS_NO_SUCH_DEVICE;
1850 goto fail;
1851 }
1852 else if (!(pInit->DevExt.HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
1853 status = STATUS_NO_SUCH_DEVICE;
1854
1855 RtlInitUnicodeString(&DevNameSuff, NULL);
1856
1857 DevNameSuff.MaximumLength = (KEYBOARD_PORTS_MAXIMUM > POINTER_PORTS_MAXIMUM)
1858 ? KEYBOARD_PORTS_MAXIMUM * sizeof(WCHAR)
1859 : POINTER_PORTS_MAXIMUM * sizeof(WCHAR);
1860 DevNameSuff.MaximumLength += sizeof(UNICODE_NULL);
1861 DevNameSuff.Buffer = (PWSTR)ExAllocatePool(PagedPool, DevNameSuff.MaximumLength);
1862 if (!DevNameSuff.Buffer)
1863 {
1864 status = STATUS_UNSUCCESSFUL;
1865 goto fail;
1866 }
1867
1868 RtlZeroMemory(DevNameSuff.Buffer, DevNameSuff.MaximumLength);
1869
1870 RtlInitUnicodeString(&KbdNameFull, NULL);
1871 KbdNameFull.MaximumLength = sizeof(L"\\Device\\") + KbdNameBase.Length + DevNameSuff.MaximumLength;
1872 KbdNameFull.Buffer = (PWSTR)ExAllocatePool(PagedPool, KbdNameFull.MaximumLength);
1873 if (!KbdNameFull.Buffer)
1874 {
1875 status = STATUS_UNSUCCESSFUL;
1876 goto fail;
1877 }
1878
1879 RtlZeroMemory(KbdNameFull.Buffer, KbdNameFull.MaximumLength);
1880 RtlAppendUnicodeToString(&KbdNameFull, L"\\Device\\");
1881 RtlAppendUnicodeToString(&KbdNameFull, KbdNameBase.Buffer);
1882
1883 for (unsigned i = 0; i < KEYBOARD_PORTS_MAXIMUM; i++)
1884 {
1885 status = RtlIntegerToUnicodeString(i, 10, &DevNameSuff);
1886 if (!NT_SUCCESS(status))
1887 break;
1888 RtlAppendUnicodeStringToString(&KbdNameFull, &DevNameSuff);
1889
1890 LogFlow(("VBoxMouseNT::DriverEntry: Creating device object named %S\n", KbdNameFull.Buffer));
1891
1892 status = IoCreateDevice(pDrvObj, sizeof(DEVEXT), &KbdNameFull,
1893 FILE_DEVICE_8042_PORT, 0, FALSE, &pPortDevObj);
1894 if (NT_SUCCESS(status))
1895 break;
1896 else
1897 KbdNameFull.Length -= DevNameSuff.Length;
1898 }
1899
1900 if (!NT_SUCCESS(status))
1901 goto fail;
1902
1903 pDevExt = (PDEVEXT)pPortDevObj->DeviceExtension;
1904 *pDevExt = pInit->DevExt;
1905 pDevExt->pDevObj = pPortDevObj;
1906
1907 CreateResList(pDevExt, &resources, &resourceListSize);
1908
1909 RtlInitUnicodeString(&resourceDeviceClass, NULL);
1910
1911 resourceDeviceClass.MaximumLength = KbdNameBase.Length + sizeof(L"/") + MouNameBase.Length;
1912 resourceDeviceClass.Buffer = (PWSTR)ExAllocatePool(PagedPool, resourceDeviceClass.MaximumLength);
1913 if (!resourceDeviceClass.Buffer)
1914 {
1915 status = STATUS_UNSUCCESSFUL;
1916 goto fail;
1917 }
1918
1919 RtlZeroMemory(resourceDeviceClass.Buffer, resourceDeviceClass.MaximumLength);
1920 RtlAppendUnicodeStringToString(&resourceDeviceClass, &KbdNameBase);
1921 RtlAppendUnicodeToString(&resourceDeviceClass, L"/");
1922 RtlAppendUnicodeStringToString(&resourceDeviceClass, &MouNameBase);
1923
1924 IoReportResourceUsage(&resourceDeviceClass, pDrvObj, NULL, 0, pPortDevObj,
1925 resources, resourceListSize, FALSE, &fConflict);
1926 if (fConflict)
1927 {
1928 status = STATUS_INSUFFICIENT_RESOURCES;
1929 goto fail;
1930 }
1931
1932 for (unsigned i = 0; i < pDevExt->Cfg.cPorts; i++)
1933 {
1934 addressSpace = (pDevExt->Cfg.aPorts[i].Flags & CM_RESOURCE_PORT_IO) == CM_RESOURCE_PORT_IO ? 1 : 0;
1935 if (!HalTranslateBusAddress(pDevExt->Cfg.InterfaceType,
1936 pDevExt->Cfg.uBusNr,
1937 pDevExt->Cfg.aPorts[i].u.Port.Start,
1938 &addressSpace, &Phys))
1939 {
1940 addressSpace = 1;
1941 Phys.QuadPart = 0;
1942 }
1943
1944 if (!addressSpace)
1945 {
1946 pDevExt->fUnmapRegs = TRUE;
1947 pDevExt->DevRegs[i] = (PUCHAR)MmMapIoSpace(Phys, pDevExt->Cfg.aPorts[i].u.Port.Length,
1948 (MEMORY_CACHING_TYPE)FALSE);
1949 }
1950 else
1951 {
1952 pDevExt->fUnmapRegs = FALSE;
1953 pDevExt->DevRegs[i] = (PUCHAR)Phys.LowPart;
1954 }
1955
1956 if (!pDevExt->DevRegs[i])
1957 {
1958 status = STATUS_NONE_MAPPED;
1959 goto fail;
1960 }
1961 }
1962
1963 pPortDevObj->Flags |= DO_BUFFERED_IO;
1964
1965 InitHw(pPortDevObj);
1966
1967 KeInitializeSpinLock(&pDevExt->ShIntObj);
1968
1969 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
1970 {
1971 pDevExt->KbdExt.InputData = (PKEYBOARD_INPUT_DATA)
1972 ExAllocatePool(NonPagedPool, pDevExt->Cfg.KbdAttr.InputDataQueueLength);
1973
1974 if (!pDevExt->KbdExt.InputData)
1975 {
1976 status = STATUS_INSUFFICIENT_RESOURCES;
1977 goto fail;
1978 }
1979
1980 pDevExt->KbdExt.DataEnd =
1981 (PKEYBOARD_INPUT_DATA)((PCHAR) (pDevExt->KbdExt.InputData) + pDevExt->Cfg.KbdAttr.InputDataQueueLength);
1982
1983 RtlZeroMemory(pDevExt->KbdExt.InputData, pDevExt->Cfg.KbdAttr.InputDataQueueLength);
1984 }
1985
1986 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
1987 {
1988 RtlInitUnicodeString(&MouNameFull, NULL);
1989
1990 MouNameFull.MaximumLength = sizeof(L"\\Device\\") + MouNameBase.Length + DevNameSuff.MaximumLength;
1991 MouNameFull.Buffer = (PWSTR)ExAllocatePool(PagedPool, MouNameFull.MaximumLength);
1992
1993 if (!MouNameFull.Buffer)
1994 {
1995 status = STATUS_UNSUCCESSFUL;
1996 goto fail;
1997 }
1998
1999 RtlZeroMemory(MouNameFull.Buffer, MouNameFull.MaximumLength);
2000 RtlAppendUnicodeToString(&MouNameFull, L"\\Device\\");
2001 RtlAppendUnicodeToString(&MouNameFull, MouNameBase.Buffer);
2002
2003 RtlZeroMemory(DevNameSuff.Buffer, DevNameSuff.MaximumLength);
2004 DevNameSuff.Length = 0;
2005
2006 for (unsigned i = 0; i < POINTER_PORTS_MAXIMUM; i++)
2007 {
2008 status = RtlIntegerToUnicodeString(i, 10, &DevNameSuff);
2009 if (!NT_SUCCESS(status))
2010 break;
2011
2012 RtlAppendUnicodeStringToString(&MouNameFull, &DevNameSuff);
2013 LogFlow(("VBoxMouseNT::DriverEntry: pointer port name (symbolic link) = %S\n", MouNameFull.Buffer));
2014
2015 status = IoCreateSymbolicLink(&MouNameFull, &KbdNameFull);
2016 if (NT_SUCCESS(status))
2017 break;
2018 else
2019 MouNameFull.Length -= DevNameSuff.Length;
2020 }
2021 if (!NT_SUCCESS(status))
2022 goto fail;
2023
2024 pDevExt->MouExt.InputData =
2025 (PMOUSE_INPUT_DATA)ExAllocatePool(NonPagedPool, pDevExt->Cfg.MouAttr.InputDataQueueLength);
2026 if (!pDevExt->MouExt.InputData)
2027 {
2028 status = STATUS_INSUFFICIENT_RESOURCES;
2029 goto fail;
2030 }
2031
2032 pDevExt->MouExt.DataEnd = (PMOUSE_INPUT_DATA)((PCHAR) (pDevExt->MouExt.InputData) + pDevExt->Cfg.MouAttr.InputDataQueueLength);
2033
2034 RtlZeroMemory(pDevExt->MouExt.InputData, pDevExt->Cfg.MouAttr.InputDataQueueLength);
2035 }
2036
2037 pDevExt->KbdExt.ConnectData.ClassDeviceObject = NULL;
2038 pDevExt->KbdExt.ConnectData.ClassService = NULL;
2039 pDevExt->MouExt.ConnectData.ClassDeviceObject = NULL;
2040 pDevExt->MouExt.ConnectData.ClassService = NULL;
2041
2042 I8042INITDATACTX initDataCtx;
2043 initDataCtx.pDevExt = pDevExt;
2044 initDataCtx.DevType = KbdDevType;
2045 InitDataQueue(&initDataCtx);
2046 initDataCtx.DevType = MouDevType;
2047 InitDataQueue(&initDataCtx);
2048
2049 pDevExt->DpcInterlockKeyboard = -1;
2050 pDevExt->DpcInterlockMouse = -1;
2051
2052 IoInitializeDpcRequest(pPortDevObj, CompleteDpc);
2053 KeInitializeDpc(&pDevExt->RetriesExceededDpc, (PKDEFERRED_ROUTINE)CtrlRetriesExceededDpc, pPortDevObj);
2054 KeInitializeDpc(&pDevExt->KeyboardIsrDpc, (PKDEFERRED_ROUTINE)CtrlKbdIsrDpc, pPortDevObj);
2055 KeInitializeDpc(&pDevExt->KeyboardIsrDpcRetry, (PKDEFERRED_ROUTINE)CtrlKbdIsrDpc, pPortDevObj);
2056 KeInitializeDpc(&pDevExt->MouseIsrDpc, (PKDEFERRED_ROUTINE)CtrlMouIsrDpc, pPortDevObj);
2057 KeInitializeDpc(&pDevExt->MouseIsrDpcRetry, (PKDEFERRED_ROUTINE)CtrlMouIsrDpc, pPortDevObj);
2058 KeInitializeDpc(&pDevExt->TimeOutDpc, (PKDEFERRED_ROUTINE)CtrlTimeoutDpc, pPortDevObj);
2059
2060 KeInitializeTimer(&pDevExt->CommandTimer);
2061 pDevExt->TimerCount = -1;
2062
2063 KeInitializeTimer(&pDevExt->KbdExt.DataConsumptionTimer);
2064 KeInitializeTimer(&pDevExt->MouExt.DataConsumptionTimer);
2065
2066 IntVecKbd = HalGetInterruptVector(pDevExt->Cfg.InterfaceType,
2067 pDevExt->Cfg.uBusNr,
2068 pDevExt->Cfg.KbdInt.u.Interrupt.Level,
2069 pDevExt->Cfg.KbdInt.u.Interrupt.Vector,
2070 &IrqlKbd, &AffKbd);
2071
2072 IntVecMou = HalGetInterruptVector(pDevExt->Cfg.InterfaceType,
2073 pDevExt->Cfg.uBusNr,
2074 pDevExt->Cfg.MouInt.u.Interrupt.Level,
2075 pDevExt->Cfg.MouInt.u.Interrupt.Vector,
2076 &IrqlMou, &AffMou);
2077
2078 if ( (pDevExt->HardwarePresent & (KEYBOARD_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT))
2079 == (KEYBOARD_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT))
2080 IrqlCoord = IrqlKbd > IrqlMou ? IrqlKbd : IrqlMou;
2081
2082 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
2083 {
2084 status = IoConnectInterrupt(&pDevExt->MouIntObj, MouIntHandler, pPortDevObj,
2085 &pDevExt->ShIntObj, IntVecMou, IrqlMou,
2086 (KIRQL) ((IrqlCoord == (KIRQL)0) ? IrqlMou : IrqlCoord),
2087 pDevExt->Cfg.MouInt.Flags == CM_RESOURCE_INTERRUPT_LATCHED
2088 ? Latched : LevelSensitive,
2089 pDevExt->Cfg.MouInt.ShareDisposition,
2090 AffMou, pDevExt->Cfg.fFloatSave);
2091 if (!NT_SUCCESS(status))
2092 goto fail;
2093
2094 status = MouEnableTrans(pPortDevObj);
2095 if (!NT_SUCCESS(status))
2096 status = STATUS_SUCCESS;
2097 }
2098
2099 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2100 {
2101 status = IoConnectInterrupt(&pDevExt->KbdIntObj, KbdIntHandler, pPortDevObj,
2102 &pDevExt->ShIntObj, IntVecKbd, IrqlKbd,
2103 (KIRQL) ((IrqlCoord == (KIRQL)0) ? IrqlKbd : IrqlCoord),
2104 pDevExt->Cfg.KbdInt.Flags == CM_RESOURCE_INTERRUPT_LATCHED
2105 ? Latched : LevelSensitive,
2106 pDevExt->Cfg.KbdInt.ShareDisposition,
2107 AffKbd, pDevExt->Cfg.fFloatSave);
2108 if (!NT_SUCCESS(status))
2109 goto fail;
2110 }
2111
2112 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2113 {
2114 status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
2115 KbdNameBase.Buffer, KbdNameFull.Buffer,
2116 REG_SZ,
2117 registryPath.Buffer, registryPath.Length);
2118 if (!NT_SUCCESS(status))
2119 goto fail;
2120 }
2121
2122 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
2123 {
2124 status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
2125 MouNameBase.Buffer, MouNameFull.Buffer,
2126 REG_SZ,
2127 registryPath.Buffer, registryPath.Length);
2128 if (!NT_SUCCESS(status))
2129 goto fail;
2130 }
2131
2132 ASSERT(status == STATUS_SUCCESS);
2133
2134 int rcVBox = VbglR0InitClient();
2135 if (RT_FAILURE(rcVBox))
2136 {
2137 Log(("VBoxMouseNT::DriverEntry: could not initialize guest library, rc = %Rrc\n", rcVBox));
2138 /* Continue working in non-VBox mode. */
2139 }
2140 else
2141 {
2142 VMMDevReqMouseStatus *pReq = NULL;
2143
2144 rcVBox = VbglR0GRAlloc((VMMDevRequestHeader**)&pReq, sizeof(VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
2145 if (RT_SUCCESS(rcVBox))
2146 {
2147 /* Inform host that we support absolute */
2148 pReq->mouseFeatures = VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE;
2149 pReq->pointerXPos = 0;
2150 pReq->pointerYPos = 0;
2151 rcVBox = VbglR0GRPerform(&pReq->header);
2152 if (RT_FAILURE(rcVBox))
2153 Log(("VBoxMouseNT::DriverEntry: ERROR communicating new mouse capabilities to VMMDev. rc = %Rrc\n", rcVBox));
2154 else
2155 {
2156 /* We will use the allocated request buffer in the ServiceCallback to GET mouse status. */
2157 pReq->header.requestType = VMMDevReq_GetMouseStatus;
2158 pDevExt->pReq = pReq;
2159 }
2160 }
2161 else
2162 {
2163 VbglR0TerminateClient();
2164 Log(("VBoxMouseNT::DriverEntry: could not allocate request buffer, rc = %Rrc\n", rcVBox));
2165 /* Continue working in non-VBox mode. */
2166 }
2167 }
2168
2169 pDrvObj->DriverStartIo = I8042StartIo;
2170 pDrvObj->MajorFunction[IRP_MJ_CREATE] = I8042OpenClose;
2171 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = I8042OpenClose;
2172 pDrvObj->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = I8042Flush;
2173 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = I8042DevCtrl;
2174
2175fail:
2176 if (!NT_SUCCESS(status))
2177 {
2178 if (resources)
2179 {
2180 resources->Count = 0;
2181 IoReportResourceUsage(&resourceDeviceClass, pDrvObj, NULL,
2182 0, pPortDevObj, resources, resourceListSize, FALSE, &fConflict);
2183 }
2184
2185 if (pDevExt)
2186 {
2187 if (pDevExt->KbdIntObj)
2188 IoDisconnectInterrupt(pDevExt->KbdIntObj);
2189 if (pDevExt->MouIntObj)
2190 IoDisconnectInterrupt(pDevExt->MouIntObj);
2191 if (pDevExt->KbdExt.InputData)
2192 ExFreePool(pDevExt->KbdExt.InputData);
2193 if (pDevExt->MouExt.InputData)
2194 ExFreePool(pDevExt->MouExt.InputData);
2195 if (pDevExt->fUnmapRegs)
2196 {
2197 for (unsigned i = 0; i < pDevExt->Cfg.cPorts; i++)
2198 if (pDevExt->DevRegs[i])
2199 MmUnmapIoSpace(pDevExt->DevRegs[i], pDevExt->Cfg.aPorts[i].u.Port.Length);
2200 }
2201 }
2202 if (pPortDevObj)
2203 {
2204 if (MouNameFull.Length > 0)
2205 IoDeleteSymbolicLink(&MouNameFull);
2206 IoDeleteDevice(pPortDevObj);
2207 }
2208 }
2209
2210 if (resources)
2211 ExFreePool(resources);
2212 if (pInit)
2213 ExFreePool(pInit);
2214 if (DevNameSuff.MaximumLength)
2215 ExFreePool(DevNameSuff.Buffer);
2216 if (KbdNameFull.MaximumLength)
2217 ExFreePool(KbdNameFull.Buffer);
2218 if (MouNameFull.MaximumLength)
2219 ExFreePool(MouNameFull.Buffer);
2220 if (resourceDeviceClass.MaximumLength)
2221 ExFreePool(resourceDeviceClass.Buffer);
2222 if (registryPath.MaximumLength)
2223 ExFreePool(registryPath.Buffer);
2224
2225 LogFlow(("VBoxMouseNT::DriverEntry: leave, status = %d\n", status));
2226
2227 return status;
2228}
2229
2230static VOID I8042Unload(PDRIVER_OBJECT pDrvObj)
2231{
2232 NOREF(pDrvObj);
2233}
2234
2235/**
2236 * Build a resource list.
2237 */
2238static VOID CreateResList(PDEVEXT pDevExt, PCM_RESOURCE_LIST *pResList, PULONG pResListSize)
2239{
2240 ULONG cPorts = pDevExt->Cfg.cPorts;
2241 if (pDevExt->Cfg.KbdInt.Type == CmResourceTypeInterrupt)
2242 cPorts++;
2243 if (pDevExt->Cfg.MouInt.Type == CmResourceTypeInterrupt)
2244 cPorts++;
2245
2246 *pResListSize = sizeof(CM_RESOURCE_LIST) + ((cPorts - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
2247 *pResList = (PCM_RESOURCE_LIST)ExAllocatePool(PagedPool, *pResListSize);
2248 if (!*pResList)
2249 {
2250 *pResListSize = 0;
2251 return;
2252 }
2253
2254 RtlZeroMemory(*pResList, *pResListSize);
2255
2256 (*pResList)->Count = 1;
2257 (*pResList)->List[0].InterfaceType = pDevExt->Cfg.InterfaceType;
2258 (*pResList)->List[0].BusNumber = pDevExt->Cfg.uBusNr;
2259
2260 (*pResList)->List[0].PartialResourceList.Count = cPorts;
2261 ULONG i = 0;
2262 if (pDevExt->Cfg.KbdInt.Type == CmResourceTypeInterrupt)
2263 (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.KbdInt;
2264 if (pDevExt->Cfg.MouInt.Type == CmResourceTypeInterrupt)
2265 (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.MouInt;
2266 for (unsigned j = 0; j < pDevExt->Cfg.cPorts; j++)
2267 (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.aPorts[j];
2268}
2269
2270/**
2271 * Read the i8042 controller command byte
2272 */
2273static NTSTATUS GetCtrlCmd(ULONG HwDisEnMask, PDEVEXT pDevExt, PUCHAR pByte)
2274{
2275 NTSTATUS status;
2276 if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
2277 {
2278 status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_DISABLE_KEYBOARD_DEVICE);
2279 if (!NT_SUCCESS(status))
2280 return status;
2281 }
2282
2283 if (HwDisEnMask & MOUSE_HARDWARE_PRESENT)
2284 {
2285 status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_DISABLE_MOUSE_DEVICE);
2286 if (!NT_SUCCESS(status))
2287 {
2288 if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
2289 PutBytePoll(i8042Cmd, FALSE/*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
2290 return status;
2291 }
2292 }
2293
2294 status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_READ_CONTROLLER_COMMAND_BYTE);
2295 if (NT_SUCCESS(status))
2296 {
2297 for (unsigned iRetry = 0; iRetry < 5; iRetry++)
2298 {
2299 status = GetBytePoll(CtrlDevType, pDevExt, pByte);
2300 if (NT_SUCCESS(status))
2301 break;
2302 if (status == STATUS_IO_TIMEOUT)
2303 KeStallExecutionProcessor(50);
2304 else
2305 break;
2306 }
2307 }
2308
2309 NTSTATUS status2;
2310 if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
2311 {
2312 status2 = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
2313 if (!NT_SUCCESS(status2))
2314 {
2315 if (NT_SUCCESS(status))
2316 status = status2;
2317 }
2318 else if (status == STATUS_SUCCESS)
2319 *pByte &= (UCHAR)~CCB_DISABLE_KEYBOARD_DEVICE;
2320 }
2321
2322 if (HwDisEnMask & MOUSE_HARDWARE_PRESENT)
2323 {
2324 status2 = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_MOUSE_DEVICE);
2325 if (!NT_SUCCESS(status2))
2326 {
2327 if (NT_SUCCESS(status))
2328 status = status2;
2329 }
2330 else if (NT_SUCCESS(status))
2331 *pByte &= (UCHAR)~CCB_DISABLE_MOUSE_DEVICE;
2332 }
2333 return status;
2334}
2335
2336/**
2337 * Write the i8042 controller command byte.
2338 */
2339static NTSTATUS PutCtrlCmd(PDEVEXT pDevExt, UCHAR Byte)
2340{
2341 NTSTATUS status;
2342 status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_WRITE_CONTROLLER_COMMAND_BYTE);
2343 if (!NT_SUCCESS(status))
2344 return status;
2345
2346 return (PutBytePoll(i8042Dat, FALSE /*=wait*/, NoDevice, pDevExt, Byte));
2347}
2348
2349/**
2350 * Read the i8042 controller command byte.
2351 */
2352static VOID TransCtrlCmd(PDEVEXT pDevExt, PI8042TRANSMITCCBCTX pCtx)
2353{
2354 UCHAR bCtrlCmd;
2355 pCtx->Status = GetCtrlCmd(pCtx->HwDisEnMask, pDevExt, &bCtrlCmd);
2356 if (!NT_SUCCESS(pCtx->Status))
2357 return;
2358
2359 if (pCtx->fAndOp)
2360 bCtrlCmd &= pCtx->ByteMask;
2361 else
2362 bCtrlCmd |= pCtx->ByteMask;
2363
2364 pCtx->Status = PutCtrlCmd(pDevExt, bCtrlCmd);
2365
2366 UCHAR bVrfyCmd;
2367 pCtx->Status = GetCtrlCmd(pCtx->HwDisEnMask, pDevExt, &bVrfyCmd);
2368
2369 if ( NT_SUCCESS(pCtx->Status)
2370 && bVrfyCmd != bCtrlCmd)
2371 pCtx->Status = STATUS_DEVICE_DATA_ERROR;
2372}
2373
2374/**
2375 * Detect the number of mouse buttons.
2376 */
2377static NTSTATUS MouQueryButtons(PDEVICE_OBJECT pDevObj, PUCHAR pNumButtons)
2378{
2379 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
2380
2381 NTSTATUS status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_RESOLUTION);
2382 if (!NT_SUCCESS(status))
2383 return status;
2384
2385 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, 0x00);
2386 if (!NT_SUCCESS(status))
2387 return status;
2388
2389 for (unsigned i = 0; i < 3; i++)
2390 {
2391 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_SCALING_1TO1);
2392 if (!NT_SUCCESS(status))
2393 return status;
2394 }
2395
2396 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, READ_MOUSE_STATUS);
2397 if (!NT_SUCCESS(status))
2398 return status;
2399 UCHAR byte;
2400 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
2401 if (!NT_SUCCESS(status))
2402 return status;
2403 UCHAR buttons;
2404 status = GetBytePoll(CtrlDevType, pDevExt, &buttons);
2405 if (!NT_SUCCESS(status))
2406 return status;
2407 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
2408 if (!NT_SUCCESS(status))
2409 return status;
2410
2411 if (buttons == 2 || buttons == 3)
2412 *pNumButtons = buttons;
2413 else
2414 *pNumButtons = 0;
2415
2416 return status;
2417}
2418
2419/**
2420 * Initialize the i8042 mouse hardware.
2421 */
2422static NTSTATUS MouInitHw(PDEVICE_OBJECT pDevObj)
2423{
2424 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
2425
2426 NTSTATUS status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, MOUSE_RESET);
2427 if (!NT_SUCCESS(status))
2428 goto fail;
2429
2430 UCHAR byte;
2431 for (unsigned i = 0; i < 11200; i++)
2432 {
2433 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
2434 if (NT_SUCCESS(status) && byte == (UCHAR) MOUSE_COMPLETE)
2435 break;
2436 if (status != STATUS_IO_TIMEOUT)
2437 break;
2438 KeStallExecutionProcessor(50);
2439 }
2440
2441 if (!NT_SUCCESS(status))
2442 goto fail;
2443
2444 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
2445 if ((!NT_SUCCESS(status)) || (byte != MOUSE_ID_BYTE))
2446 goto fail;
2447
2448 MouFindWheel(pDevObj);
2449
2450 UCHAR numButtons;
2451 status = MouQueryButtons(pDevObj, &numButtons);
2452 if (!NT_SUCCESS(status))
2453 goto fail;
2454 else if (numButtons)
2455 pDevExt->Cfg.MouAttr.NumberOfButtons = numButtons;
2456
2457 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_SAMPLING_RATE);
2458 if (!NT_SUCCESS(status))
2459 goto fail;
2460
2461 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, 60);
2462 if (!NT_SUCCESS(status))
2463 goto fail;
2464
2465 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_RESOLUTION);
2466 if (!NT_SUCCESS(status))
2467 goto fail;
2468
2469 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, (UCHAR)pDevExt->Cfg.MouseResolution);
2470
2471fail:
2472 pDevExt->MouExt.uPrevSignAndOverflow = 0;
2473 pDevExt->MouExt.InputState = MouseExpectingACK;
2474 pDevExt->MouExt.LastByteReceived = 0;
2475
2476 return status;
2477}
2478
2479/**
2480 * Initialize the i8042 keyboard hardware.
2481 */
2482static NTSTATUS KbdInitHw(PDEVICE_OBJECT pDevObj)
2483{
2484 NTSTATUS status = STATUS_SUCCESS; /* Shut up MSC. */
2485 BOOLEAN fWaitForAck = TRUE;
2486 PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
2487
2488retry:
2489 PutBytePoll(i8042Dat, fWaitForAck, KbdDevType, pDevExt, KEYBOARD_RESET);
2490
2491 LARGE_INTEGER startOfSpin;
2492 KeQueryTickCount(&startOfSpin);
2493 for (unsigned i = 0; i < 11200; i++)
2494 {
2495 UCHAR byte;
2496 status = GetBytePoll(KbdDevType, pDevExt, &byte);
2497 if (NT_SUCCESS(status))
2498 break;
2499 if (status == STATUS_IO_TIMEOUT)
2500 {
2501 LARGE_INTEGER nextQuery, difference, tenSeconds;
2502 KeStallExecutionProcessor(50);
2503 KeQueryTickCount(&nextQuery);
2504 difference.QuadPart = nextQuery.QuadPart - startOfSpin.QuadPart;
2505 tenSeconds.QuadPart = 10*10*1000*1000;
2506 ASSERT(KeQueryTimeIncrement() <= MAXLONG);
2507 if (difference.QuadPart*KeQueryTimeIncrement() >= tenSeconds.QuadPart)
2508 break;
2509 }
2510 else
2511 break;
2512 }
2513
2514 if (!NT_SUCCESS(status))
2515 {
2516 if (fWaitForAck)
2517 {
2518 fWaitForAck = FALSE;
2519 goto retry;
2520 }
2521 goto fail;
2522 }
2523
2524 I8042TRANSMITCCBCTX Ctx;
2525 Ctx.HwDisEnMask = 0;
2526 Ctx.fAndOp = TRUE;
2527 Ctx.ByteMask = (UCHAR) ~((UCHAR)CCB_KEYBOARD_TRANSLATE_MODE);
2528
2529 TransCtrlCmd(pDevExt, &Ctx);
2530 if (!NT_SUCCESS(Ctx.Status))
2531 TransCtrlCmd(pDevExt, &Ctx);
2532 if (!NT_SUCCESS(Ctx.Status))
2533 {
2534 status = Ctx.Status;
2535 goto fail;
2536 }
2537
2538 PKEYBOARD_ID pId = &pDevExt->Cfg.KbdAttr.KeyboardIdentifier;
2539 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SET_KEYBOARD_TYPEMATIC);
2540 if (status == STATUS_SUCCESS)
2541 {
2542 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt,
2543 ConvertTypematic(pDevExt->Cfg.KeyRepeatCurrent.Rate,
2544 pDevExt->Cfg.KeyRepeatCurrent.Delay));
2545 /* ignore errors */
2546 }
2547
2548 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SET_KEYBOARD_INDICATORS);
2549 if (status == STATUS_SUCCESS)
2550 {
2551 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt,
2552 (UCHAR)pDevExt->Cfg.KbdInd.LedFlags);
2553 /* ignore errors */
2554 }
2555 status = STATUS_SUCCESS;
2556
2557 if (pDevExt->Cfg.KbdAttr.KeyboardMode == 1)
2558 {
2559 Ctx.HwDisEnMask = 0;
2560 Ctx.fAndOp = FALSE;
2561 Ctx.ByteMask = CCB_KEYBOARD_TRANSLATE_MODE;
2562 TransCtrlCmd(pDevExt, &Ctx);
2563 if (!NT_SUCCESS(Ctx.Status))
2564 {
2565 if (Ctx.Status == STATUS_DEVICE_DATA_ERROR)
2566 {
2567 if (ENHANCED_KEYBOARD(*pId))
2568 {
2569 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SELECT_SCAN_CODE_SET);
2570 if (!NT_SUCCESS(status))
2571 pDevExt->Cfg.KbdAttr.KeyboardMode = 2;
2572 else
2573 {
2574 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, 1);
2575 if (!NT_SUCCESS(status))
2576 pDevExt->Cfg.KbdAttr.KeyboardMode = 2;
2577 }
2578 }
2579 }
2580 else
2581 {
2582 status = Ctx.Status;
2583 goto fail;
2584 }
2585 }
2586 }
2587
2588fail:
2589 pDevExt->KbdExt.CurrentOutput.State = Idle;
2590 pDevExt->KbdExt.CurrentOutput.FirstByte = 0;
2591 pDevExt->KbdExt.CurrentOutput.LastByte = 0;
2592
2593 return status;
2594}
2595
2596/**
2597 * Initialize the i8042 controller, keyboard and mouse.
2598 */
2599static VOID InitHw(PDEVICE_OBJECT pDevObj)
2600{
2601 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
2602 PUCHAR dataAddress = pDevExt->DevRegs[i8042Dat];
2603 PUCHAR commandAddress = pDevExt->DevRegs[i8042Cmd];
2604
2605 DrainOutBuf(dataAddress, commandAddress);
2606
2607 I8042TRANSMITCCBCTX Ctx;
2608 Ctx.HwDisEnMask = 0;
2609 Ctx.fAndOp = TRUE;
2610 Ctx.ByteMask = (UCHAR) ~((UCHAR)CCB_ENABLE_KEYBOARD_INTERRUPT | (UCHAR)CCB_ENABLE_MOUSE_INTERRUPT);
2611 TransCtrlCmd(pDevExt, &Ctx);
2612 if (!NT_SUCCESS(Ctx.Status))
2613 return;
2614
2615 DrainOutBuf(dataAddress, commandAddress);
2616
2617 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
2618 {
2619 NTSTATUS status = MouInitHw(pDevObj);
2620 if (!NT_SUCCESS(status))
2621 pDevExt->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2622 }
2623
2624 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2625 {
2626 NTSTATUS status = KbdInitHw(pDevObj);
2627 if (!NT_SUCCESS(status))
2628 pDevExt->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2629 }
2630
2631 if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2632 {
2633 NTSTATUS status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
2634 if (!NT_SUCCESS(status))
2635 pDevExt->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
2636
2637 DrainOutBuf(dataAddress, commandAddress);
2638 }
2639
2640 if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
2641 {
2642 NTSTATUS status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_MOUSE_DEVICE);
2643 if (!NT_SUCCESS(status))
2644 pDevExt->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
2645 DrainOutBuf(dataAddress, commandAddress);
2646 }
2647
2648 if (pDevExt->HardwarePresent)
2649 {
2650 Ctx.HwDisEnMask = pDevExt->HardwarePresent;
2651 Ctx.fAndOp = FALSE;
2652 Ctx.ByteMask = (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2653 ? CCB_ENABLE_KEYBOARD_INTERRUPT : 0;
2654 Ctx.ByteMask |= (UCHAR)
2655 (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT) ? CCB_ENABLE_MOUSE_INTERRUPT : 0;
2656 TransCtrlCmd(pDevExt, &Ctx);
2657 if (!NT_SUCCESS(Ctx.Status))
2658 {
2659 /* ignore */
2660 }
2661 }
2662}
2663
2664/**
2665 * retrieve the drivers service parameters from the registry
2666 */
2667static VOID HwGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
2668 PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
2669
2670{
2671 PRTL_QUERY_REGISTRY_TABLE aQuery = NULL;
2672 UNICODE_STRING parametersPath = { 0, 0, NULL }; /* Shut up MSC (actually badly structured code is a fault, but whatever). */
2673 UNICODE_STRING defaultPointerName;
2674 UNICODE_STRING defaultKeyboardName;
2675 USHORT defaultResendIterations = 3;
2676 ULONG iResend = 0;
2677 USHORT defaultPollingIterations = 12000;
2678 ULONG pollingIterations = 0;
2679 USHORT defaultPollingIterationsMaximum = 12000;
2680 ULONG pollingIterationsMaximum = 0;
2681 USHORT defaultPollStatusIterations = 12000;
2682 ULONG pollStatusIterations = 0;
2683 ULONG defaultDataQueueSize = 100;
2684 ULONG cButtons = 2;
2685 USHORT cButtonsDef = 2;
2686 ULONG sampleRate = 60;
2687 USHORT defaultSampleRate = 60;
2688 ULONG mouseResolution = 3;
2689 USHORT defaultMouseResolution = 3;
2690 ULONG overrideKeyboardType = 0;
2691 ULONG invalidKeyboardType = 0;
2692 ULONG overrideKeyboardSubtype = (ULONG)-1;
2693 ULONG invalidKeyboardSubtype = (ULONG)-1;
2694 ULONG defaultSynchPacket100ns = 10000000UL;
2695 ULONG enableWheelDetection = 0;
2696 ULONG defaultEnableWheelDetection = 1;
2697 PWSTR path = NULL;
2698 USHORT queries = 15;
2699 PI8042CFGINF pCfg = &pInit->DevExt.Cfg;
2700 NTSTATUS status = STATUS_SUCCESS;
2701
2702 pCfg->StallMicroseconds = 50;
2703 parametersPath.Buffer = NULL;
2704
2705 path = RegistryPath->Buffer;
2706 if (NT_SUCCESS(status))
2707 {
2708 aQuery = (PRTL_QUERY_REGISTRY_TABLE)
2709 ExAllocatePool(PagedPool, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1));
2710 if (!aQuery)
2711 status = STATUS_UNSUCCESSFUL;
2712 else
2713 {
2714 RtlZeroMemory(aQuery, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1));
2715 RtlInitUnicodeString(&parametersPath, NULL);
2716 parametersPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
2717 parametersPath.Buffer = (PWSTR)ExAllocatePool(PagedPool, parametersPath.MaximumLength);
2718 if (!parametersPath.Buffer)
2719 status = STATUS_UNSUCCESSFUL;
2720 }
2721 }
2722
2723 if (NT_SUCCESS(status))
2724 {
2725 RtlZeroMemory(parametersPath.Buffer, parametersPath.MaximumLength);
2726 RtlAppendUnicodeToString(&parametersPath, path);
2727 RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
2728
2729 RtlInitUnicodeString(&defaultKeyboardName, L"KeyboardPort");
2730 RtlInitUnicodeString(&defaultPointerName, L"PointerPort");
2731
2732 aQuery[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2733 aQuery[0].Name = L"iResend";
2734 aQuery[0].EntryContext = &iResend;
2735 aQuery[0].DefaultType = REG_DWORD;
2736 aQuery[0].DefaultData = &defaultResendIterations;
2737 aQuery[0].DefaultLength = sizeof(USHORT);
2738
2739 aQuery[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2740 aQuery[1].Name = L"PollingIterations";
2741 aQuery[1].EntryContext = &pollingIterations;
2742 aQuery[1].DefaultType = REG_DWORD;
2743 aQuery[1].DefaultData = &defaultPollingIterations;
2744 aQuery[1].DefaultLength = sizeof(USHORT);
2745
2746 aQuery[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
2747 aQuery[2].Name = L"PollingIterationsMaximum";
2748 aQuery[2].EntryContext = &pollingIterationsMaximum;
2749 aQuery[2].DefaultType = REG_DWORD;
2750 aQuery[2].DefaultData = &defaultPollingIterationsMaximum;
2751 aQuery[2].DefaultLength = sizeof(USHORT);
2752
2753 aQuery[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
2754 aQuery[3].Name = L"KeyboardDataQueueSize";
2755 aQuery[3].EntryContext = &pCfg->KbdAttr.InputDataQueueLength;
2756 aQuery[3].DefaultType = REG_DWORD;
2757 aQuery[3].DefaultData = &defaultDataQueueSize;
2758 aQuery[3].DefaultLength = sizeof(ULONG);
2759
2760 aQuery[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
2761 aQuery[4].Name = L"MouseDataQueueSize";
2762 aQuery[4].EntryContext = &pCfg->MouAttr.InputDataQueueLength;
2763 aQuery[4].DefaultType = REG_DWORD;
2764 aQuery[4].DefaultData = &defaultDataQueueSize;
2765 aQuery[4].DefaultLength = sizeof(ULONG);
2766
2767 aQuery[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
2768 aQuery[5].Name = L"NumberOfButtons";
2769 aQuery[5].EntryContext = &cButtons;
2770 aQuery[5].DefaultType = REG_DWORD;
2771 aQuery[5].DefaultData = &cButtonsDef;
2772 aQuery[5].DefaultLength = sizeof(USHORT);
2773
2774 aQuery[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
2775 aQuery[6].Name = L"SampleRate";
2776 aQuery[6].EntryContext = &sampleRate;
2777 aQuery[6].DefaultType = REG_DWORD;
2778 aQuery[6].DefaultData = &defaultSampleRate;
2779 aQuery[6].DefaultLength = sizeof(USHORT);
2780
2781 aQuery[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
2782 aQuery[7].Name = L"MouseResolution";
2783 aQuery[7].EntryContext = &mouseResolution;
2784 aQuery[7].DefaultType = REG_DWORD;
2785 aQuery[7].DefaultData = &defaultMouseResolution;
2786 aQuery[7].DefaultLength = sizeof(USHORT);
2787
2788 aQuery[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
2789 aQuery[8].Name = L"OverrideKeyboardType";
2790 aQuery[8].EntryContext = &overrideKeyboardType;
2791 aQuery[8].DefaultType = REG_DWORD;
2792 aQuery[8].DefaultData = &invalidKeyboardType;
2793 aQuery[8].DefaultLength = sizeof(ULONG);
2794
2795 aQuery[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
2796 aQuery[9].Name = L"OverrideKeyboardSubtype";
2797 aQuery[9].EntryContext = &overrideKeyboardSubtype;
2798 aQuery[9].DefaultType = REG_DWORD;
2799 aQuery[9].DefaultData = &invalidKeyboardSubtype;
2800 aQuery[9].DefaultLength = sizeof(ULONG);
2801
2802 aQuery[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
2803 aQuery[10].Name = L"KeyboardDeviceBaseName";
2804 aQuery[10].EntryContext = KeyboardDeviceName;
2805 aQuery[10].DefaultType = REG_SZ;
2806 aQuery[10].DefaultData = defaultKeyboardName.Buffer;
2807 aQuery[10].DefaultLength = 0;
2808
2809 aQuery[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
2810 aQuery[11].Name = L"PointerDeviceBaseName";
2811 aQuery[11].EntryContext = PointerDeviceName;
2812 aQuery[11].DefaultType = REG_SZ;
2813 aQuery[11].DefaultData = defaultPointerName.Buffer;
2814 aQuery[11].DefaultLength = 0;
2815
2816 aQuery[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
2817 aQuery[12].Name = L"MouseSynchIn100ns";
2818 aQuery[12].EntryContext = &pInit->DevExt.MouExt.SynchTickCount;
2819 aQuery[12].DefaultType = REG_DWORD;
2820 aQuery[12].DefaultData = &defaultSynchPacket100ns;
2821 aQuery[12].DefaultLength = sizeof(ULONG);
2822
2823 aQuery[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
2824 aQuery[13].Name = L"PollStatusIterations";
2825 aQuery[13].EntryContext = &pollStatusIterations;
2826 aQuery[13].DefaultType = REG_DWORD;
2827 aQuery[13].DefaultData = &defaultPollStatusIterations;
2828 aQuery[13].DefaultLength = sizeof(USHORT);
2829
2830 aQuery[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
2831 aQuery[14].Name = L"EnableWheelDetection";
2832 aQuery[14].EntryContext = &enableWheelDetection;
2833 aQuery[14].DefaultType = REG_DWORD;
2834 aQuery[14].DefaultData = &defaultEnableWheelDetection;
2835 aQuery[14].DefaultLength = sizeof(ULONG);
2836
2837 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
2838 parametersPath.Buffer, aQuery, NULL, NULL);
2839 }
2840
2841 if (!NT_SUCCESS(status))
2842 {
2843 /* driver defaults */
2844 pCfg->iResend = defaultResendIterations;
2845 pCfg->PollingIterations = defaultPollingIterations;
2846 pCfg->PollingIterationsMaximum = defaultPollingIterationsMaximum;
2847 pCfg->PollStatusIterations = defaultPollStatusIterations;
2848 pCfg->KbdAttr.InputDataQueueLength = defaultDataQueueSize;
2849 pCfg->MouAttr.InputDataQueueLength = defaultDataQueueSize;
2850 pCfg->EnableWheelDetection = defaultEnableWheelDetection;
2851 pInit->DevExt.MouExt.SynchTickCount = defaultSynchPacket100ns;
2852 RtlCopyUnicodeString(KeyboardDeviceName, &defaultKeyboardName);
2853 RtlCopyUnicodeString(PointerDeviceName, &defaultPointerName);
2854 }
2855 else
2856 {
2857 pCfg->iResend = (USHORT)iResend;
2858 pCfg->PollingIterations = (USHORT) pollingIterations;
2859 pCfg->PollingIterationsMaximum = (USHORT) pollingIterationsMaximum;
2860 pCfg->PollStatusIterations = (USHORT) pollStatusIterations;
2861 pCfg->EnableWheelDetection = (ULONG) ((enableWheelDetection) ? 1 : 0);
2862 }
2863
2864 if (pCfg->KbdAttr.InputDataQueueLength == 0)
2865 pCfg->KbdAttr.InputDataQueueLength = defaultDataQueueSize;
2866 pCfg->KbdAttr.InputDataQueueLength *= sizeof(KEYBOARD_INPUT_DATA);
2867
2868 if (pCfg->MouAttr.InputDataQueueLength == 0)
2869 pCfg->MouAttr.InputDataQueueLength = defaultDataQueueSize;
2870 pCfg->MouAttr.InputDataQueueLength *= sizeof(MOUSE_INPUT_DATA);
2871
2872 pCfg->MouAttr.NumberOfButtons = (USHORT)cButtons;
2873 pCfg->MouAttr.SampleRate = (USHORT)sampleRate;
2874 pCfg->MouseResolution = (USHORT)mouseResolution;
2875
2876 if (overrideKeyboardType != invalidKeyboardType)
2877 {
2878 if (overrideKeyboardType <= RT_ELEMENTS(s_aKeybType))
2879 pCfg->KbdAttr.KeyboardIdentifier.Type = (UCHAR) overrideKeyboardType;
2880 }
2881
2882 if (overrideKeyboardSubtype != invalidKeyboardSubtype)
2883 pCfg->KbdAttr.KeyboardIdentifier.Subtype = (UCHAR) overrideKeyboardSubtype;
2884
2885 if (pInit->DevExt.MouExt.SynchTickCount == 0)
2886 pInit->DevExt.MouExt.SynchTickCount = defaultSynchPacket100ns;
2887
2888 pInit->DevExt.MouExt.SynchTickCount /= KeQueryTimeIncrement();
2889
2890 if (parametersPath.Buffer)
2891 ExFreePool(parametersPath.Buffer);
2892 if (aQuery)
2893 ExFreePool(aQuery);
2894}
2895
2896static void GetDevIdentifier(PKEY_VALUE_FULL_INFORMATION *ppInf, PUNICODE_STRING pStr)
2897{
2898 pStr->Length = (USHORT)(*(ppInf + IoQueryDeviceIdentifier))->DataLength;
2899 if (!pStr->Length)
2900 return;
2901 pStr->MaximumLength = pStr->Length;
2902 pStr->Buffer = (PWSTR) (((PUCHAR)(*(ppInf + IoQueryDeviceIdentifier)))
2903 + (*(ppInf + IoQueryDeviceIdentifier))->DataOffset);
2904}
2905
2906static ULONG GetDevCfgData(PKEY_VALUE_FULL_INFORMATION *ppInf, PCM_PARTIAL_RESOURCE_LIST *ppData)
2907{
2908 ULONG DataLength = (*(ppInf + IoQueryDeviceConfigurationData))->DataLength;
2909 if (DataLength)
2910 *ppData = (PCM_PARTIAL_RESOURCE_LIST)( ((PUCHAR) (*(ppInf + IoQueryDeviceConfigurationData)))
2911 + (*(ppInf + IoQueryDeviceConfigurationData))->DataOffset
2912 + FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList));
2913 return DataLength;
2914}
2915
2916/**
2917 * Callout routine. Grab keyboard controller and peripheral configuration
2918 * information.
2919 */
2920static NTSTATUS KbdCallOut(PVOID pCtx, PUNICODE_STRING PathName,
2921 INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
2922 CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
2923 CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf)
2924{
2925 RT_NOREF(PathName, pBusInf, uCtrlType, uCtrlNr, uPrfType, uPrfNr);
2926 UNICODE_STRING unicodeIdentifier;
2927 GetDevIdentifier(pPrfInf, &unicodeIdentifier);
2928
2929 PINITEXT pInit = (PINITEXT)pCtx;
2930 PDEVEXT pDevExt = &pInit->DevExt;
2931 if ( (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
2932 || !unicodeIdentifier.Length)
2933 return STATUS_SUCCESS;
2934
2935 pDevExt->HardwarePresent |= KEYBOARD_HARDWARE_PRESENT;
2936
2937 PI8042CFGINF pCfg = &pDevExt->Cfg;
2938 pCfg->KbdAttr.KeyboardIdentifier.Type = 0;
2939 pCfg->KbdAttr.KeyboardIdentifier.Subtype = 0;
2940
2941 PCM_PARTIAL_RESOURCE_LIST pPrfData;
2942 if (GetDevCfgData(pPrfInf, &pPrfData))
2943 {
2944 unsigned cList = pPrfData->Count;
2945 PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pPrfData->PartialDescriptors;
2946 for (unsigned i = 0; i < cList; i++, pResDesc++)
2947 {
2948 switch (pResDesc->Type)
2949 {
2950 case CmResourceTypeDeviceSpecific:
2951 {
2952 PCM_KEYBOARD_DEVICE_DATA KbdData = (PCM_KEYBOARD_DEVICE_DATA)(((PUCHAR)pResDesc)
2953 + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
2954 if (KbdData->Type <= RT_ELEMENTS(s_aKeybType))
2955 pCfg->KbdAttr.KeyboardIdentifier.Type = KbdData->Type;
2956 pCfg->KbdAttr.KeyboardIdentifier.Subtype = KbdData->Subtype;
2957 pCfg->KbdInd.LedFlags = (KbdData->KeyboardFlags >> 4) & 7;
2958 break;
2959 }
2960 default:
2961 break;
2962 }
2963 }
2964 }
2965
2966 if (pCfg->KbdAttr.KeyboardIdentifier.Type == 0)
2967 {
2968 pCfg->KbdAttr.KeyboardIdentifier.Type = 4;
2969 pCfg->KbdInd.LedFlags = 0;
2970 }
2971
2972 pCfg->InterfaceType = BusType;
2973 pCfg->uBusNr = uBusNr;
2974 pCfg->fFloatSave = FALSE;
2975
2976 BOOLEAN fDefIntShare;
2977 KINTERRUPT_MODE DefIntMode;
2978 if (BusType == MicroChannel)
2979 {
2980 fDefIntShare = TRUE;
2981 DefIntMode = LevelSensitive;
2982 }
2983 else
2984 {
2985 fDefIntShare = FALSE;
2986 DefIntMode = Latched;
2987 }
2988
2989 PCM_PARTIAL_RESOURCE_LIST pCtrlData;
2990 if (GetDevCfgData(pCtrlInf, &pCtrlData))
2991 {
2992 unsigned cList = pCtrlData->Count;
2993 PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pCtrlData->PartialDescriptors;
2994 for (unsigned i = 0; i < cList; i++, pResDesc++)
2995 {
2996 switch (pResDesc->Type)
2997 {
2998 case CmResourceTypePort:
2999 ASSERT(pCfg->cPorts < i8042MaxPorts);
3000 pCfg->aPorts[pCfg->cPorts] = *pResDesc;
3001 pCfg->aPorts[pCfg->cPorts].ShareDisposition = CmResourceShareDriverExclusive;
3002 pCfg->cPorts++;
3003 break;
3004
3005 case CmResourceTypeInterrupt:
3006 pCfg->KbdInt = *pResDesc;
3007 pCfg->KbdInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
3008 : CmResourceShareDeviceExclusive;
3009 break;
3010
3011 case CmResourceTypeDeviceSpecific:
3012 break;
3013
3014 default:
3015 break;
3016 }
3017 }
3018 }
3019
3020 if (!(pCfg->KbdInt.Type & CmResourceTypeInterrupt))
3021 {
3022 pCfg->KbdInt.Type = CmResourceTypeInterrupt;
3023 pCfg->KbdInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
3024 : CmResourceShareDeviceExclusive;
3025 pCfg->KbdInt.Flags = (DefIntMode == Latched) ? CM_RESOURCE_INTERRUPT_LATCHED
3026 : CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
3027 pCfg->KbdInt.u.Interrupt.Level = 1;
3028 pCfg->KbdInt.u.Interrupt.Vector = 1;
3029 }
3030
3031 if (pCfg->cPorts == 0)
3032 {
3033 pCfg->aPorts[i8042Dat].Type = CmResourceTypePort;
3034 pCfg->aPorts[i8042Dat].Flags = CM_RESOURCE_PORT_IO;
3035 pCfg->aPorts[i8042Dat].ShareDisposition = CmResourceShareDriverExclusive;
3036 pCfg->aPorts[i8042Dat].u.Port.Start.LowPart = 0x60;
3037 pCfg->aPorts[i8042Dat].u.Port.Start.HighPart = 0;
3038 pCfg->aPorts[i8042Dat].u.Port.Length = 1;
3039
3040 pCfg->aPorts[i8042Cmd].Type = CmResourceTypePort;
3041 pCfg->aPorts[i8042Cmd].Flags = CM_RESOURCE_PORT_IO;
3042 pCfg->aPorts[i8042Cmd].ShareDisposition = CmResourceShareDriverExclusive;
3043 pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart = 0x64;
3044 pCfg->aPorts[i8042Cmd].u.Port.Start.HighPart = 0;
3045 pCfg->aPorts[i8042Cmd].u.Port.Length = 1;
3046
3047 pCfg->cPorts = 2;
3048 }
3049 else if (pCfg->cPorts == 1)
3050 {
3051 pCfg->aPorts[i8042Dat].u.Port.Length = 1;
3052 pCfg->aPorts[i8042Cmd] = pCfg->aPorts[i8042Dat];
3053 pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart += 4;
3054 pCfg->cPorts++;
3055 }
3056 else
3057 {
3058 if (pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart < pCfg->aPorts[i8042Dat].u.Port.Start.LowPart)
3059 {
3060 CM_PARTIAL_RESOURCE_DESCRIPTOR Desc = pCfg->aPorts[i8042Dat];
3061 pCfg->aPorts[i8042Dat] = pCfg->aPorts[i8042Cmd];
3062 pCfg->aPorts[i8042Cmd] = Desc;
3063 }
3064 }
3065
3066 return STATUS_SUCCESS;
3067}
3068
3069/**
3070 * Callout routine. Grab the pointer controller and the peripheral
3071 * configuration information.
3072 */
3073static NTSTATUS MouCallOut(PVOID pCtx, PUNICODE_STRING PathName,
3074 INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
3075 CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
3076 CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf)
3077{
3078 RT_NOREF(PathName, pBusInf, uCtrlType, uCtrlNr, uPrfType, uPrfNr);
3079 NTSTATUS status = STATUS_SUCCESS;
3080
3081 UNICODE_STRING unicodeIdentifier;
3082 GetDevIdentifier(pPrfInf, &unicodeIdentifier);
3083
3084 PINITEXT pInit = (PINITEXT)pCtx;
3085 PDEVEXT pDevExt = &pInit->DevExt;
3086
3087 if ( (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
3088 || unicodeIdentifier.Length == 0)
3089 return status;
3090
3091 ANSI_STRING ansiString;
3092 status = RtlUnicodeStringToAnsiString(&ansiString, &unicodeIdentifier, TRUE);
3093 if (!NT_SUCCESS(status))
3094 return status;
3095
3096 if (strstr(ansiString.Buffer, "PS2"))
3097 pDevExt->HardwarePresent |= MOUSE_HARDWARE_PRESENT;
3098
3099 RtlFreeAnsiString(&ansiString);
3100
3101 if (!(pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT))
3102 return status;
3103
3104 PI8042CFGINF pCfg = &pDevExt->Cfg;
3105 if (!(pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
3106 {
3107 pCfg->InterfaceType = BusType;
3108 pCfg->uBusNr = uBusNr;
3109 pCfg->fFloatSave = FALSE;
3110 }
3111
3112 BOOLEAN fDefIntShare;
3113 KINTERRUPT_MODE DefIntMode;
3114 if (pCfg->InterfaceType == MicroChannel)
3115 {
3116 fDefIntShare = TRUE;
3117 DefIntMode = LevelSensitive;
3118 }
3119 else
3120 {
3121 fDefIntShare = FALSE;
3122 DefIntMode = Latched;
3123 }
3124
3125 PCM_PARTIAL_RESOURCE_LIST pCtrlData;
3126 if (GetDevCfgData(pCtrlInf, &pCtrlData))
3127 {
3128 unsigned cList = pCtrlData->Count;
3129 PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pCtrlData->PartialDescriptors;
3130 BOOLEAN fPortInfoNeeded = pCfg->cPorts ? FALSE : TRUE;
3131
3132 for (unsigned i = 0; i < cList; i++, pResDesc++)
3133 {
3134 switch (pResDesc->Type)
3135 {
3136 case CmResourceTypePort:
3137 if (fPortInfoNeeded)
3138 {
3139 pCfg->aPorts[pCfg->cPorts] = *pResDesc;
3140 pCfg->aPorts[pCfg->cPorts].ShareDisposition = CmResourceShareDriverExclusive;
3141 pCfg->cPorts++;
3142 }
3143 break;
3144
3145 case CmResourceTypeInterrupt:
3146 pCfg->MouInt = *pResDesc;
3147 pCfg->MouInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
3148 : CmResourceShareDeviceExclusive;
3149 break;
3150
3151 default:
3152 break;
3153 }
3154 }
3155 }
3156
3157 if (!(pCfg->MouInt.Type & CmResourceTypeInterrupt))
3158 {
3159 pCfg->MouInt.Type = CmResourceTypeInterrupt;
3160 pCfg->MouInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
3161 : CmResourceShareDeviceExclusive;
3162 pCfg->MouInt.Flags = (DefIntMode == Latched) ? CM_RESOURCE_INTERRUPT_LATCHED
3163 : CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
3164 pCfg->MouInt.u.Interrupt.Level = 12;
3165 pCfg->MouInt.u.Interrupt.Vector = 12;
3166 }
3167
3168 if (pCfg->cPorts == 0)
3169 {
3170 pCfg->aPorts[i8042Dat].Type = CmResourceTypePort;
3171 pCfg->aPorts[i8042Dat].Flags = CM_RESOURCE_PORT_IO;
3172 pCfg->aPorts[i8042Dat].ShareDisposition = CmResourceShareDriverExclusive;
3173 pCfg->aPorts[i8042Dat].u.Port.Start.LowPart = 0x60;
3174 pCfg->aPorts[i8042Dat].u.Port.Start.HighPart = 0;
3175 pCfg->aPorts[i8042Dat].u.Port.Length = 1;
3176
3177 pCfg->aPorts[i8042Cmd].Type = CmResourceTypePort;
3178 pCfg->aPorts[i8042Cmd].Flags = CM_RESOURCE_PORT_IO;
3179 pCfg->aPorts[i8042Cmd].ShareDisposition = CmResourceShareDriverExclusive;
3180 pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart = 0x64;
3181 pCfg->aPorts[i8042Cmd].u.Port.Start.HighPart = 0;
3182 pCfg->aPorts[i8042Cmd].u.Port.Length = 1;
3183
3184 pCfg->cPorts = 2;
3185 }
3186 else if (pCfg->cPorts == 1)
3187 {
3188 pCfg->aPorts[i8042Cmd] = pCfg->aPorts[i8042Dat];
3189 pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart += 4;
3190 pCfg->cPorts++;
3191 }
3192 else
3193 {
3194 if (pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart < pCfg->aPorts[i8042Dat].u.Port.Start.LowPart)
3195 {
3196 CM_PARTIAL_RESOURCE_DESCRIPTOR Desc = pCfg->aPorts[i8042Dat];
3197 pCfg->aPorts[i8042Dat] = pCfg->aPorts[i8042Cmd];
3198 pCfg->aPorts[i8042Cmd] = Desc;
3199 }
3200 }
3201
3202 return status;
3203}
3204
3205static const UCHAR s_ucCommands[] =
3206{
3207 SET_MOUSE_SAMPLING_RATE, 200,
3208 SET_MOUSE_SAMPLING_RATE, 100,
3209 SET_MOUSE_SAMPLING_RATE, 80,
3210 GET_DEVICE_ID, 0
3211};
3212
3213static NTSTATUS MouFindWheel(PDEVICE_OBJECT pDevObj)
3214{
3215 NTSTATUS status = STATUS_SUCCESS; /* Shut up MSC. */
3216 PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
3217
3218 if (!pDevExt->Cfg.EnableWheelDetection)
3219 return STATUS_NO_SUCH_DEVICE;
3220
3221 KeStallExecutionProcessor(50);
3222
3223 for (unsigned iCmd = 0; s_ucCommands[iCmd];)
3224 {
3225 status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, s_ucCommands[iCmd]);
3226 if (!NT_SUCCESS(status))
3227 goto fail;
3228
3229 iCmd++;
3230 KeStallExecutionProcessor(50);
3231 }
3232
3233 UCHAR byte = UINT8_MAX;
3234 for (unsigned i = 0; i < 5; i++)
3235 {
3236 status = GetBytePoll(CtrlDevType, pDevExt, &byte);
3237 if (status != STATUS_IO_TIMEOUT)
3238 break;
3239 KeStallExecutionProcessor(50);
3240 }
3241
3242 if ( NT_SUCCESS(status)
3243 && (byte == MOUSE_ID_BYTE || byte == WHEELMOUSE_ID_BYTE))
3244 {
3245 if (byte == WHEELMOUSE_ID_BYTE)
3246 {
3247 pDevExt->HardwarePresent |= (WHEELMOUSE_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT);
3248 pDevExt->Cfg.MouAttr.MouseIdentifier = WHEELMOUSE_I8042_HARDWARE;
3249 }
3250 else
3251 pDevExt->HardwarePresent |= MOUSE_HARDWARE_PRESENT;
3252 }
3253
3254fail:
3255 pDevExt->MouExt.uPrevSignAndOverflow = 0;
3256 pDevExt->MouExt.InputState = MouseExpectingACK;
3257 return status;
3258}
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