VirtualBox

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

Last change on this file since 79781 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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

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