VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/DevPS2.cpp@ 26831

Last change on this file since 26831 was 26690, checked in by vboxsync, 15 years ago

Devices/PS/2: do not report that the touchscreen is being touched, as that may be treated as button 1 being held down

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.1 KB
Line 
1/* $Id: DevPS2.cpp 26690 2010-02-22 22:25:22Z vboxsync $ */
2/** @file
3 * DevPS2 - PS/2 keyboard & mouse controller device.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 * --------------------------------------------------------------------
21 *
22 * This code is based on:
23 *
24 * QEMU PC keyboard emulation (revision 1.12)
25 *
26 * Copyright (c) 2003 Fabrice Bellard
27 *
28 * Permission is hereby granted, free of charge, to any person obtaining a copy
29 * of this software and associated documentation files (the "Software"), to deal
30 * in the Software without restriction, including without limitation the rights
31 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32 * copies of the Software, and to permit persons to whom the Software is
33 * furnished to do so, subject to the following conditions:
34 *
35 * The above copyright notice and this permission notice shall be included in
36 * all copies or substantial portions of the Software.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 * THE SOFTWARE.
45 *
46 */
47
48/*******************************************************************************
49* Header Files *
50*******************************************************************************/
51#define LOG_GROUP LOG_GROUP_DEV_KBD
52#include "vl_vbox.h"
53#include <VBox/pdmdev.h>
54#include <iprt/assert.h>
55#include <iprt/uuid.h>
56
57#include "../Builtins.h"
58
59#define PCKBD_SAVED_STATE_VERSION 4
60
61
62#ifndef VBOX_DEVICE_STRUCT_TESTCASE
63/*******************************************************************************
64* Internal Functions *
65*******************************************************************************/
66RT_C_DECLS_BEGIN
67PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
68PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
69PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
70PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
71RT_C_DECLS_END
72#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
73
74/* debug PC keyboard */
75#define DEBUG_KBD
76
77/* debug PC keyboard : only mouse */
78#define DEBUG_MOUSE
79
80/* Keyboard Controller Commands */
81#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
82#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
83#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
84#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
85#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
86#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
87#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
88#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
89#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
90#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
91#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
92#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
93#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
94#define KBD_CCMD_WRITE_OBUF 0xD2
95#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
96 initiated by the auxiliary device */
97#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
98#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
99#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
100#define KBD_CCMD_READ_TSTINP 0xE0 /* Read test inputs T0, T1 */
101#define KBD_CCMD_RESET 0xFE
102
103/* Keyboard Commands */
104#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
105#define KBD_CMD_ECHO 0xEE
106#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
107#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
108#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
109#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
110#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
111#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
112#define KBD_CMD_RESET 0xFF /* Reset */
113
114/* Keyboard Replies */
115#define KBD_REPLY_POR 0xAA /* Power on reset */
116#define KBD_REPLY_ACK 0xFA /* Command ACK */
117#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
118
119/* Status Register Bits */
120#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
121#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
122#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
123#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
124#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
125#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
126#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
127#define KBD_STAT_PERR 0x80 /* Parity error */
128
129/* Controller Mode Register Bits */
130#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
131#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
132#define KBD_MODE_SYS 0x04 /* The system flag (?) */
133#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
134#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
135#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
136#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
137#define KBD_MODE_RFU 0x80
138
139/* Mouse Commands */
140#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
141#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
142#define AUX_SET_RES 0xE8 /* Set resolution */
143#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
144#define AUX_SET_STREAM 0xEA /* Set stream mode */
145#define AUX_POLL 0xEB /* Poll */
146#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
147#define AUX_SET_WRAP 0xEE /* Set wrap mode */
148#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
149#define AUX_GET_TYPE 0xF2 /* Get type */
150#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
151#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
152#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
153#define AUX_SET_DEFAULT 0xF6
154#define AUX_RESET 0xFF /* Reset aux device */
155#define AUX_ACK 0xFA /* Command byte ACK. */
156#define AUX_NACK 0xFE /* Command byte NACK. */
157
158#define MOUSE_STATUS_REMOTE 0x40
159#define MOUSE_STATUS_ENABLED 0x20
160#define MOUSE_STATUS_SCALE21 0x10
161
162#define KBD_QUEUE_SIZE 256
163
164/** Supported mouse protocols */
165enum
166{
167 MOUSE_PROT_PS2 = 0,
168 MOUSE_PROT_IMPS2 = 3,
169 MOUSE_PROT_IMEX = 4,
170 MOUSE_PROT_LIFEBOOK = 5
171};
172
173/** Mouse flags */
174# define MOUSE_REPORT_HORIZONTAL 0x01
175
176/** @name Extended mouse button values for Lifebook mode
177 * @{ */
178/** Downwards scrollwheel movement of one step. Doesn't affect the mouse
179 * buttons */
180# define MOUSE_EXT_VSCROLL_DN 4
181/** Upwards scrollwheel movement of one step. */
182# define MOUSE_EXT_VSCROLL_UP 5
183/** Leftwards scrollwheel movement of one step. */
184# define MOUSE_EXT_HSCROLL_BW 6
185/** Rightwards scrollwheel movement of one step. */
186# define MOUSE_EXT_HSCROLL_FW 7
187/** @} */
188
189typedef struct {
190 uint8_t data[KBD_QUEUE_SIZE];
191 int rptr, wptr, count;
192} KBDQueue;
193
194#define MOUSE_CMD_QUEUE_SIZE 8
195
196typedef struct {
197 uint8_t data[MOUSE_CMD_QUEUE_SIZE];
198 int rptr, wptr, count;
199} MouseCmdQueue;
200
201
202#define MOUSE_EVENT_QUEUE_SIZE 256
203
204typedef struct {
205 uint8_t data[MOUSE_EVENT_QUEUE_SIZE];
206 int rptr, wptr, count;
207} MouseEventQueue;
208
209typedef struct KBDState {
210 KBDQueue queue;
211 MouseCmdQueue mouse_command_queue;
212 MouseEventQueue mouse_event_queue;
213 uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
214 uint8_t status;
215 uint8_t mode;
216 /* keyboard state */
217 int32_t kbd_write_cmd;
218 int32_t scan_enabled;
219 int32_t translate;
220 int32_t scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
221 /* mouse state */
222 int32_t mouse_write_cmd;
223 uint8_t mouse_status;
224 uint8_t mouse_resolution;
225 uint8_t mouse_sample_rate;
226 uint8_t mouse_wrap;
227 uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
228 uint8_t mouse_detect_state;
229 int32_t mouse_dx; /* current values, needed for 'poll' mode */
230 int32_t mouse_dy;
231 int32_t mouse_dz;
232 int32_t mouse_dw;
233 int32_t mouse_flags;
234 uint32_t mouse_cx; /** @todo r=bird: cx/cy? aren't these absolute coordinates? 'c' usually means 'count of'. mouse_abs_x or just mouse_x would probably be clearer. */
235 uint32_t mouse_cy;
236 uint8_t mouse_buttons;
237 uint8_t mouse_buttons_reported;
238 uint8_t mouse_last_button;
239
240 /** Pointer to the device instance - RC. */
241 PPDMDEVINSRC pDevInsRC;
242 /** Pointer to the device instance - R3 . */
243 PPDMDEVINSR3 pDevInsR3;
244 /** Pointer to the device instance. */
245 PPDMDEVINSR0 pDevInsR0;
246 /** Critical section protecting the state. */
247 PDMCRITSECT CritSect;
248 /**
249 * Keyboard port - LUN#0.
250 *
251 * @implements PDMIBASE
252 * @implements PDMIKEYBOARDPORT
253 */
254 struct
255 {
256 /** The base interface for the keyboard port. */
257 PDMIBASE IBase;
258 /** The keyboard port base interface. */
259 PDMIKEYBOARDPORT IPort;
260
261 /** The base interface of the attached keyboard driver. */
262 R3PTRTYPE(PPDMIBASE) pDrvBase;
263 /** The keyboard interface of the attached keyboard driver. */
264 R3PTRTYPE(PPDMIKEYBOARDCONNECTOR) pDrv;
265 } Keyboard;
266
267 /**
268 * Mouse port - LUN#1.
269 *
270 * @implements PDMIBASE
271 * @implements PDMIMOUSEPORT
272 */
273 struct
274 {
275 /** The base interface for the mouse port. */
276 PDMIBASE IBase;
277 /** The mouse port base interface. */
278 PDMIMOUSEPORT IPort;
279
280 /** The base interface of the attached mouse driver. */
281 R3PTRTYPE(PPDMIBASE) pDrvBase;
282 /** The mouse interface of the attached mouse driver. */
283 R3PTRTYPE(PPDMIMOUSECONNECTOR) pDrv;
284 } Mouse;
285} KBDState;
286
287/* Table to convert from PC scancodes to raw scancodes. */
288static const unsigned char ps2_raw_keycode[128] = {
289 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
290 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
291 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
292 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
293 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
294 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
295 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
296 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
297};
298
299#ifndef VBOX_DEVICE_STRUCT_TESTCASE
300
301/* update irq and KBD_STAT_[MOUSE_]OBF */
302/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
303 incorrect, but it avoids having to simulate exact delays */
304static void kbd_update_irq(KBDState *s)
305{
306 KBDQueue *q = &s->queue;
307 MouseCmdQueue *mcq = &s->mouse_command_queue;
308 MouseEventQueue *meq = &s->mouse_event_queue;
309 int irq12_level, irq1_level;
310
311 irq1_level = 0;
312 irq12_level = 0;
313 s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
314 if (q->count != 0)
315 {
316 s->status |= KBD_STAT_OBF;
317 if ((s->mode & KBD_MODE_KBD_INT) && !(s->mode & KBD_MODE_DISABLE_KBD))
318 irq1_level = 1;
319 }
320 else if (mcq->count != 0 || meq->count != 0)
321 {
322 s->status |= KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
323 if (s->mode & KBD_MODE_MOUSE_INT)
324 irq12_level = 1;
325 }
326 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 1, irq1_level);
327 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 12, irq12_level);
328}
329
330static void kbd_queue(KBDState *s, int b, int aux)
331{
332 KBDQueue *q = &s->queue;
333 MouseCmdQueue *mcq = &s->mouse_command_queue;
334 MouseEventQueue *meq = &s->mouse_event_queue;
335
336#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
337 if (aux == 1)
338 LogRel3(("%s: mouse command response: 0x%02x\n", __PRETTY_FUNCTION__, b));
339 else if (aux == 2)
340 LogRel3(("%s: mouse event data: 0x%02x\n", __PRETTY_FUNCTION__, b));
341#ifdef DEBUG_KBD
342 else
343 LogRel3(("%s: kbd event: 0x%02x\n", __PRETTY_FUNCTION__, b));
344#endif
345#endif
346 switch (aux)
347 {
348 case 0: /* keyboard */
349 if (q->count >= KBD_QUEUE_SIZE)
350 return;
351 q->data[q->wptr] = b;
352 if (++q->wptr == KBD_QUEUE_SIZE)
353 q->wptr = 0;
354 q->count++;
355 break;
356 case 1: /* mouse command response */
357 if (mcq->count >= MOUSE_CMD_QUEUE_SIZE)
358 return;
359 mcq->data[mcq->wptr] = b;
360 if (++mcq->wptr == MOUSE_CMD_QUEUE_SIZE)
361 mcq->wptr = 0;
362 mcq->count++;
363 break;
364 case 2: /* mouse event data */
365 if (meq->count >= MOUSE_EVENT_QUEUE_SIZE)
366 return;
367 meq->data[meq->wptr] = b;
368 if (++meq->wptr == MOUSE_EVENT_QUEUE_SIZE)
369 meq->wptr = 0;
370 meq->count++;
371 break;
372 default:
373 AssertMsgFailed(("aux=%d\n", aux));
374 }
375 kbd_update_irq(s);
376}
377
378#ifdef IN_RING3
379static void pc_kbd_put_keycode(void *opaque, int keycode)
380{
381 KBDState *s = (KBDState*)opaque;
382
383 /* XXX: add support for scancode sets 1 and 3 */
384 if (!s->translate && keycode < 0xe0 && s->scancode_set == 2)
385 {
386 if (keycode & 0x80)
387 kbd_queue(s, 0xf0, 0);
388 keycode = ps2_raw_keycode[keycode & 0x7f];
389 }
390 kbd_queue(s, keycode, 0);
391}
392#endif /* IN_RING3 */
393
394static uint32_t kbd_read_status(void *opaque, uint32_t addr)
395{
396 KBDState *s = (KBDState*)opaque;
397 int val;
398 val = s->status;
399#if defined(DEBUG_KBD)
400 Log(("kbd: read status=0x%02x\n", val));
401#endif
402 return val;
403}
404
405static int kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
406{
407 int rc = VINF_SUCCESS;
408 KBDState *s = (KBDState*)opaque;
409
410#ifdef DEBUG_KBD
411 Log(("kbd: write cmd=0x%02x\n", val));
412#endif
413 switch(val) {
414 case KBD_CCMD_READ_MODE:
415 kbd_queue(s, s->mode, 0);
416 break;
417 case KBD_CCMD_WRITE_MODE:
418 case KBD_CCMD_WRITE_OBUF:
419 case KBD_CCMD_WRITE_AUX_OBUF:
420 case KBD_CCMD_WRITE_MOUSE:
421 case KBD_CCMD_WRITE_OUTPORT:
422 s->write_cmd = val;
423 break;
424 case KBD_CCMD_MOUSE_DISABLE:
425 s->mode |= KBD_MODE_DISABLE_MOUSE;
426 break;
427 case KBD_CCMD_MOUSE_ENABLE:
428 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
429 break;
430 case KBD_CCMD_TEST_MOUSE:
431 kbd_queue(s, 0x00, 0);
432 break;
433 case KBD_CCMD_SELF_TEST:
434 s->status |= KBD_STAT_SELFTEST;
435 kbd_queue(s, 0x55, 0);
436 break;
437 case KBD_CCMD_KBD_TEST:
438 kbd_queue(s, 0x00, 0);
439 break;
440 case KBD_CCMD_KBD_DISABLE:
441 s->mode |= KBD_MODE_DISABLE_KBD;
442 kbd_update_irq(s);
443 break;
444 case KBD_CCMD_KBD_ENABLE:
445 s->mode &= ~KBD_MODE_DISABLE_KBD;
446 kbd_update_irq(s);
447 break;
448 case KBD_CCMD_READ_INPORT:
449 kbd_queue(s, 0x00, 0);
450 break;
451 case KBD_CCMD_READ_OUTPORT:
452 /* XXX: check that */
453#ifdef TARGET_I386
454 val = 0x01 | (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) << 1);
455#else
456 val = 0x01;
457#endif
458 if (s->status & KBD_STAT_OBF)
459 val |= 0x10;
460 if (s->status & KBD_STAT_MOUSE_OBF)
461 val |= 0x20;
462 kbd_queue(s, val, 0);
463 break;
464#ifdef TARGET_I386
465 case KBD_CCMD_ENABLE_A20:
466# ifndef IN_RING3
467 if (!PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
468 rc = VINF_IOM_HC_IOPORT_WRITE;
469# else /* IN_RING3 */
470 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), true);
471# endif /* IN_RING3 */
472 break;
473 case KBD_CCMD_DISABLE_A20:
474# ifndef IN_RING3
475 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
476 rc = VINF_IOM_HC_IOPORT_WRITE;
477# else /* IN_RING3 */
478 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), false);
479# endif /* !IN_RING3 */
480 break;
481#endif
482 case KBD_CCMD_READ_TSTINP:
483 /* Keyboard clock line is zero IFF keyboard is disabled */
484 val = (s->mode & KBD_MODE_DISABLE_KBD) ? 0 : 1;
485 kbd_queue(s, val, 0);
486 break;
487 case KBD_CCMD_RESET:
488#ifndef IN_RING3
489 rc = VINF_IOM_HC_IOPORT_WRITE;
490#else /* IN_RING3 */
491 rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns));
492#endif /* !IN_RING3 */
493 break;
494 case 0xff:
495 /* ignore that - I don't know what is its use */
496 break;
497 /* Make OS/2 happy. */
498 /* The 8042 RAM is readble using commands 0x20 thru 0x3f, and writable
499 by 0x60 thru 0x7f. Now days only the firs byte, the mode, is used.
500 We'll ignore the writes (0x61..7f) and return 0 for all the reads
501 just to make some OS/2 debug stuff a bit happier. */
502 case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
503 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
504 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
505 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
506 kbd_queue(s, 0, 0);
507 Log(("kbd: reading non-standard RAM addr %#x\n", val & 0x1f));
508 break;
509 default:
510 Log(("kbd: unsupported keyboard cmd=0x%02x\n", val));
511 break;
512 }
513 return rc;
514}
515
516static uint32_t kbd_read_data(void *opaque, uint32_t addr)
517{
518 KBDState *s = (KBDState*)opaque;
519 KBDQueue *q;
520 MouseCmdQueue *mcq;
521 MouseEventQueue *meq;
522 int val, index, aux;
523
524 q = &s->queue;
525 mcq = &s->mouse_command_queue;
526 meq = &s->mouse_event_queue;
527 if (q->count == 0 && mcq->count == 0 && meq->count == 0) {
528 /* NOTE: if no data left, we return the last keyboard one
529 (needed for EMM386) */
530 /* XXX: need a timer to do things correctly */
531 index = q->rptr - 1;
532 if (index < 0)
533 index = KBD_QUEUE_SIZE - 1;
534 val = q->data[index];
535 } else {
536 aux = (s->status & KBD_STAT_MOUSE_OBF);
537 if (!aux)
538 {
539 val = q->data[q->rptr];
540 if (++q->rptr == KBD_QUEUE_SIZE)
541 q->rptr = 0;
542 q->count--;
543 }
544 else
545 {
546 if (mcq->count)
547 {
548 val = mcq->data[mcq->rptr];
549 if (++mcq->rptr == MOUSE_CMD_QUEUE_SIZE)
550 mcq->rptr = 0;
551 mcq->count--;
552 }
553 else
554 {
555 val = meq->data[meq->rptr];
556 if (++meq->rptr == MOUSE_EVENT_QUEUE_SIZE)
557 meq->rptr = 0;
558 meq->count--;
559 }
560 }
561 /* reading deasserts IRQ */
562 if (aux)
563 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 12, 0);
564 else
565 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 1, 0);
566 }
567 /* reassert IRQs if data left */
568 kbd_update_irq(s);
569#ifdef DEBUG_KBD
570 Log(("kbd: read data=0x%02x\n", val));
571#endif
572 return val;
573}
574
575static void kbd_reset_keyboard(KBDState *s)
576{
577 s->scan_enabled = 1;
578 s->scancode_set = 2;
579}
580
581static int kbd_write_keyboard(KBDState *s, int val)
582{
583 switch(s->kbd_write_cmd) {
584 default:
585 case -1:
586 switch(val) {
587 case 0x00:
588 kbd_queue(s, KBD_REPLY_ACK, 0);
589 break;
590 case 0x05:
591 kbd_queue(s, KBD_REPLY_RESEND, 0);
592 break;
593 case KBD_CMD_GET_ID:
594 kbd_queue(s, KBD_REPLY_ACK, 0);
595 kbd_queue(s, 0xab, 0);
596 kbd_queue(s, 0x83, 0);
597 break;
598 case KBD_CMD_ECHO:
599 kbd_queue(s, KBD_CMD_ECHO, 0);
600 break;
601 case KBD_CMD_ENABLE:
602 s->scan_enabled = 1;
603 kbd_queue(s, KBD_REPLY_ACK, 0);
604 break;
605 case KBD_CMD_SCANCODE:
606 case KBD_CMD_SET_LEDS:
607 case KBD_CMD_SET_RATE:
608 s->kbd_write_cmd = val;
609 kbd_queue(s, KBD_REPLY_ACK, 0);
610 break;
611 case KBD_CMD_RESET_DISABLE:
612 kbd_reset_keyboard(s);
613 s->scan_enabled = 0;
614 kbd_queue(s, KBD_REPLY_ACK, 0);
615 break;
616 case KBD_CMD_RESET_ENABLE:
617 kbd_reset_keyboard(s);
618 s->scan_enabled = 1;
619 kbd_queue(s, KBD_REPLY_ACK, 0);
620 break;
621 case KBD_CMD_RESET:
622 kbd_reset_keyboard(s);
623 kbd_queue(s, KBD_REPLY_ACK, 0);
624 kbd_queue(s, KBD_REPLY_POR, 0);
625 break;
626 default:
627 kbd_queue(s, KBD_REPLY_ACK, 0);
628 break;
629 }
630 break;
631 case KBD_CMD_SCANCODE:
632#ifdef IN_RING3
633 if (val == 0) {
634 if (s->scancode_set == 1)
635 pc_kbd_put_keycode(s, 0x43);
636 else if (s->scancode_set == 2)
637 pc_kbd_put_keycode(s, 0x41);
638 else if (s->scancode_set == 3)
639 pc_kbd_put_keycode(s, 0x3f);
640 } else {
641 if (val >= 1 && val <= 3)
642 s->scancode_set = val;
643 kbd_queue(s, KBD_REPLY_ACK, 0);
644 }
645#else
646 return VINF_IOM_HC_IOPORT_WRITE;
647#endif
648 case KBD_CMD_SET_LEDS:
649 {
650#ifdef IN_RING3
651 PDMKEYBLEDS enmLeds = PDMKEYBLEDS_NONE;
652 if (val & 0x01)
653 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK);
654 if (val & 0x02)
655 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK);
656 if (val & 0x04)
657 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK);
658 s->Keyboard.pDrv->pfnLedStatusChange(s->Keyboard.pDrv, enmLeds);
659#else
660 return VINF_IOM_HC_IOPORT_WRITE;
661#endif
662 kbd_queue(s, KBD_REPLY_ACK, 0);
663 s->kbd_write_cmd = -1;
664 }
665 break;
666 case KBD_CMD_SET_RATE:
667 kbd_queue(s, KBD_REPLY_ACK, 0);
668 s->kbd_write_cmd = -1;
669 break;
670 }
671
672 return VINF_SUCCESS;
673}
674
675static void kbd_mouse_set_reported_buttons(KBDState *s, unsigned fButtons, unsigned fButtonMask)
676{
677 s->mouse_buttons_reported |= (fButtons & fButtonMask);
678 s->mouse_buttons_reported &= (fButtons | ~fButtonMask);
679}
680
681static bool kbd_mouse_test_set_button(KBDState *s, unsigned cIndex)
682{
683 unsigned fButtonMask = 1 << (cIndex - 1);
684
685 AssertReturn(3 <= cIndex && cIndex <= 5, false);
686 if ( (s->mouse_buttons & fButtonMask)
687 && !(s->mouse_buttons_reported & fButtonMask))
688 {
689 s->mouse_last_button = cIndex;
690 kbd_mouse_set_reported_buttons(s, fButtonMask, 0x1c);
691 return true;
692 }
693 return false;
694}
695
696static bool kbd_mouse_test_clear_last_button(KBDState *s)
697{
698 unsigned fButtonMask = 1 << (s->mouse_last_button - 1);
699
700 if ( s->mouse_last_button != 0
701 && !(s->mouse_buttons & fButtonMask))
702 {
703 s->mouse_last_button = 0;
704 kbd_mouse_set_reported_buttons(s, 0, fButtonMask);
705 return true;
706 }
707 return false;
708}
709
710/**
711 * Send a single relative packet in 3-byte PS/2 format, optionally with our
712 * packed button protocol extension, to the PS/2 controller.
713 * @param s keyboard state object
714 * @param dx relative X value, must be between -256 and +255
715 * @param dy relative y value, must be between -256 and +255
716 * @param fButtonsLow the state of the two first mouse buttons
717 * @param fButtonsPacked the state of the upper three mouse buttons and
718 * scroll wheel movement, packed as per the
719 * MOUSE_EXT_* defines. For standard PS/2 packets
720 * only pass the value of button 3 here.
721 */
722static void kbd_mouse_send_rel3_packet(KBDState *s, bool fToCmdQueue)
723{
724 int aux = fToCmdQueue ? 1 : 2;
725 int dx1 = s->mouse_dx < 0 ? RT_MAX(s->mouse_dx, -256)
726 : s->mouse_dx > 0 ? RT_MIN(s->mouse_dx, 255) : 0;
727 int dy1 = s->mouse_dy < 0 ? RT_MAX(s->mouse_dy, -256)
728 : s->mouse_dy > 0 ? RT_MIN(s->mouse_dy, 255) : 0;
729 unsigned int b;
730 unsigned fButtonsPacked;
731 unsigned fButtonsLow = s->mouse_buttons & 0x03;
732 s->mouse_dx -= dx1;
733 s->mouse_dy -= dy1;
734 kbd_mouse_set_reported_buttons(s, fButtonsLow, 0x03);
735 /* When we are not in lifebook mode, we just set the third bit
736 * in the first packet byte if the middle button is pressed,
737 * as per the PS/2 protocol. */
738 if (s->mouse_type != MOUSE_PROT_LIFEBOOK)
739 {
740 fButtonsPacked = (s->mouse_buttons & 0x04 ? 0x04 : 0);
741 kbd_mouse_set_reported_buttons(s, s->mouse_buttons, 0x04);
742 }
743 else
744 {
745 if (kbd_mouse_test_set_button(s, 3))
746 fButtonsPacked = 1;
747 else if (kbd_mouse_test_set_button(s, 4))
748 fButtonsPacked = 2;
749 else if (kbd_mouse_test_set_button(s, 5))
750 fButtonsPacked = 3;
751 /* Release event for buttons in the range 3-5. */
752 else if (kbd_mouse_test_clear_last_button(s))
753 fButtonsPacked = 0;
754 else if (s->mouse_dz < 0)
755 {
756 ++s->mouse_dz;
757 fButtonsPacked = MOUSE_EXT_VSCROLL_DN;
758 }
759 else if (s->mouse_dz > 0)
760 {
761 --s->mouse_dz;
762 fButtonsPacked = MOUSE_EXT_VSCROLL_UP;
763 }
764 else if (s->mouse_dw < 0)
765 {
766 ++s->mouse_dw;
767 fButtonsPacked = MOUSE_EXT_HSCROLL_BW;
768 }
769 else if (s->mouse_dw > 0)
770 {
771 --s->mouse_dw;
772 fButtonsPacked = MOUSE_EXT_HSCROLL_FW;
773 }
774 else
775 fButtonsPacked = s->mouse_last_button;
776 }
777 LogRel3(("%s: dx1=%d, dy1=%d, fButtonsLow=0x%x, fButtonsPacked=0x%x\n",
778 __PRETTY_FUNCTION__, dx1, dy1, fButtonsLow, fButtonsPacked));
779 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | fButtonsLow
780 | (fButtonsPacked & 4) | ((fButtonsPacked & 3) << 6);
781 kbd_queue(s, b, aux);
782 kbd_queue(s, dx1 & 0xff, aux);
783 kbd_queue(s, dy1 & 0xff, aux);
784}
785
786static void kbd_mouse_send_imps2_byte4(KBDState *s, bool fToCmdQueue)
787{
788 int aux = fToCmdQueue ? 1 : 2;
789
790 int dz1 = s->mouse_dz < 0 ? RT_MAX(s->mouse_dz, -127)
791 : s->mouse_dz > 0 ? RT_MIN(s->mouse_dz, 127) : 0;
792 s->mouse_dz -= dz1;
793 kbd_queue(s, dz1 & 0xff, aux);
794}
795
796static void kbd_mouse_send_imex_byte4(KBDState *s, bool fToCmdQueue)
797{
798 int aux = fToCmdQueue ? 1 : 2;
799
800 if (s->mouse_dw)
801 {
802 int dw1 = s->mouse_dw < 0 ? RT_MAX(s->mouse_dw, -32)
803 : s->mouse_dw > 0 ? RT_MIN(s->mouse_dw, 32) : 0;
804 s->mouse_dw -= dw1;
805 kbd_queue(s, 0x40 | (dw1 & 0x3f), aux);
806 }
807 else if (s->mouse_flags & MOUSE_REPORT_HORIZONTAL && s->mouse_dz)
808 {
809 int dz1 = s->mouse_dz < 0 ? RT_MAX(s->mouse_dz, -32)
810 : s->mouse_dz > 0 ? RT_MIN(s->mouse_dz, 32) : 0;
811 s->mouse_dz -= dz1;
812 kbd_queue(s, 0x80 | (dz1 & 0x3f), aux);
813 }
814 else
815 {
816 int dz1 = s->mouse_dz < 0 ? RT_MAX(s->mouse_dz, -8)
817 : s->mouse_dz > 0 ? RT_MIN(s->mouse_dz, 8) : 0;
818 s->mouse_dz -= dz1;
819 kbd_mouse_set_reported_buttons(s, s->mouse_buttons, 0x18);
820 kbd_queue(s, (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1), aux);
821 }
822}
823
824/**
825 * Send a single relative packet in (IM)PS/2 or IMEX format to the PS/2
826 * controller.
827 * @param s keyboard state object
828 * @param fToCmdQueue should this packet go to the command queue (or the
829 * event queue)?
830 */
831static void kbd_mouse_send_rel_packet(KBDState *s, bool fToCmdQueue)
832{
833 kbd_mouse_send_rel3_packet(s, fToCmdQueue);
834 if (s->mouse_type == MOUSE_PROT_IMPS2)
835 kbd_mouse_send_imps2_byte4(s, fToCmdQueue);
836 if (s->mouse_type == MOUSE_PROT_IMEX)
837 kbd_mouse_send_imex_byte4(s, fToCmdQueue);
838}
839
840/**
841 * Send a single absolute packet in 6-byte lifebook format to the PS/2
842 * controller.
843 * @param s keyboard state object
844 * @param fToCmdQueue Which queue.
845 */
846static void kbd_mouse_send_abs_packet(KBDState *s, bool fToCmdQueue)
847{
848 int aux = fToCmdQueue ? 1 : 2;
849 unsigned cx1 = s->mouse_cx * 4095 / 0xffff;
850 unsigned cy1 = 4095 - (s->mouse_cy * 4095 / 0xffff);
851 unsigned fButtons = s->mouse_buttons & 0x03;
852 unsigned int b[6];
853
854 LogRel3(("%s: cx1=%d, cy1=%d, fButtons=0x%x\n", __PRETTY_FUNCTION__,
855 cx1, cy1, fButtons));
856 b[0] = fButtons;
857 Assert((b[0] & 0xf8) == 0);
858 kbd_queue(s, b[0], aux);
859 b[1] = ((cy1 << 2) & 0xc0) | (cx1 >> 6);
860 kbd_queue(s, b[1], aux);
861 b[2] = ((cx1 << 2) & 0xc0) | (cx1 & 0x3f);
862 Assert(((b[2] & 0x30) << 2) == (b[2] & 0xc0));
863 kbd_queue(s, b[2], aux);
864 b[3] = 0xc0;
865 kbd_queue(s, b[3], aux); /* This byte is really wasted in the protocol */
866 b[4] = ((cx1 << 2) & 0xc0) | (cy1 >> 6);
867 Assert((b[4] & 0xc0) == (b[2] & 0xc0));
868 kbd_queue(s, b[4], aux);
869 b[5] = ((cy1 << 2) & 0xc0) | (cy1 & 0x3f);
870 Assert( (((b[5] & 0x30) << 2) == (b[1] & 0xc0))
871 && ((b[5] & 0xc0) == (b[1] & 0xc0)));
872 kbd_queue(s, b[5], aux);
873}
874
875static bool kbd_mouse_rel_unreported(KBDState *s)
876{
877 return s->mouse_dx
878 || s->mouse_dy
879 || s->mouse_dz
880 || s->mouse_dw
881 || s->mouse_buttons != s->mouse_buttons_reported;
882}
883
884/**
885 * Send a single packet in (IM)PS/2, IMEX or Lifebook format to the PS/2
886 * controller.
887 * @param s keyboard state object
888 * @param fToCmdQueue is this the result of a poll on the mouse controller?
889 */
890static void kbd_mouse_send_packet(KBDState *s, bool fToCmdQueue)
891{
892 if ( kbd_mouse_rel_unreported(s)
893 || (s->mouse_type != MOUSE_PROT_LIFEBOOK))
894 kbd_mouse_send_rel_packet(s, fToCmdQueue);
895 else
896 kbd_mouse_send_abs_packet(s, fToCmdQueue);
897}
898
899#ifdef IN_RING3
900static size_t kbd_mouse_event_queue_free(KBDState *s)
901{
902 AssertReturn(s->mouse_event_queue.count <= MOUSE_EVENT_QUEUE_SIZE, 0);
903 return MOUSE_EVENT_QUEUE_SIZE - s->mouse_event_queue.count;
904}
905
906static void pc_kbd_mouse_event(void *opaque, int dx, int dy, int dz, int dw,
907 int buttons_state)
908{
909 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d, buttons_state=0x%x\n",
910 __PRETTY_FUNCTION__, dx, dy, dz, dw, buttons_state));
911 KBDState *s = (KBDState*)opaque;
912
913 /* check if deltas are recorded when disabled */
914 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
915 return;
916 AssertReturnVoid((buttons_state & ~0x1f) == 0);
917
918 s->mouse_dx += dx;
919 s->mouse_dy -= dy;
920 s->mouse_dz += dz;
921 if ( ( (s->mouse_type == MOUSE_PROT_IMEX)
922 && s->mouse_flags & MOUSE_REPORT_HORIZONTAL)
923 || (s->mouse_type == MOUSE_PROT_LIFEBOOK))
924 s->mouse_dw += dw;
925 s->mouse_buttons = buttons_state;
926 if (!(s->mouse_status & MOUSE_STATUS_REMOTE))
927 /* if not remote, send event. Multiple events are sent if
928 too big deltas */
929 while ( kbd_mouse_rel_unreported(s)
930 && kbd_mouse_event_queue_free(s) > 4)
931 kbd_mouse_send_rel_packet(s, false);
932}
933
934static void pc_kbd_mouse_event_abs(void *opaque, unsigned cx, unsigned cy)
935{
936 LogRel3(("%s: cx=%d, cy=%d\n", __PRETTY_FUNCTION__, cx, cy));
937 KBDState *s = (KBDState*)opaque;
938
939 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
940 return;
941
942 if (s->mouse_type != MOUSE_PROT_LIFEBOOK)
943 return;
944
945 s->mouse_cx = cx;
946 s->mouse_cy = cy;
947
948 if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
949 (s->mouse_event_queue.count < (MOUSE_EVENT_QUEUE_SIZE - 4)))
950 /* if not remote, send event */
951 kbd_mouse_send_abs_packet(s, false);
952}
953#endif /* IN_RING3 */
954
955static int kbd_write_mouse(KBDState *s, int val)
956{
957#ifdef DEBUG_MOUSE
958 LogRelFlowFunc(("kbd: write mouse 0x%02x\n", val));
959#endif
960 /* Flush the mouse command response queue. */
961 s->mouse_command_queue.count = 0;
962 s->mouse_command_queue.rptr = 0;
963 s->mouse_command_queue.wptr = 0;
964 switch(s->mouse_write_cmd) {
965 default:
966 case -1:
967 /* mouse command */
968 if (s->mouse_wrap) {
969 if (val == AUX_RESET_WRAP) {
970 s->mouse_wrap = 0;
971 kbd_queue(s, AUX_ACK, 1);
972 return VINF_SUCCESS;
973 } else if (val != AUX_RESET) {
974 kbd_queue(s, val, 1);
975 return VINF_SUCCESS;
976 }
977 }
978 switch(val) {
979 case AUX_SET_SCALE11:
980 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
981 kbd_queue(s, AUX_ACK, 1);
982 break;
983 case AUX_SET_SCALE21:
984 s->mouse_status |= MOUSE_STATUS_SCALE21;
985 kbd_queue(s, AUX_ACK, 1);
986 break;
987 case AUX_SET_STREAM:
988 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
989 kbd_queue(s, AUX_ACK, 1);
990 break;
991 case AUX_SET_WRAP:
992 s->mouse_wrap = 1;
993 kbd_queue(s, AUX_ACK, 1);
994 break;
995 case AUX_SET_REMOTE:
996 s->mouse_status |= MOUSE_STATUS_REMOTE;
997 kbd_queue(s, AUX_ACK, 1);
998 break;
999 case AUX_GET_TYPE:
1000 kbd_queue(s, AUX_ACK, 1);
1001 kbd_queue(s, s->mouse_type, 1);
1002 break;
1003 case AUX_SET_RES:
1004 case AUX_SET_SAMPLE:
1005 s->mouse_write_cmd = val;
1006 kbd_queue(s, AUX_ACK, 1);
1007 break;
1008 case AUX_GET_SCALE:
1009 kbd_queue(s, AUX_ACK, 1);
1010 kbd_queue(s, s->mouse_status, 1);
1011 kbd_queue(s, s->mouse_resolution, 1);
1012 kbd_queue(s, s->mouse_sample_rate, 1);
1013 break;
1014 case AUX_POLL:
1015 kbd_queue(s, AUX_ACK, 1);
1016 kbd_mouse_send_packet(s, true);
1017 break;
1018 case AUX_ENABLE_DEV:
1019 s->mouse_status |= MOUSE_STATUS_ENABLED;
1020 kbd_queue(s, AUX_ACK, 1);
1021 break;
1022 case AUX_DISABLE_DEV:
1023 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
1024 kbd_queue(s, AUX_ACK, 1);
1025 /* Flush the mouse events queue. */
1026 s->mouse_event_queue.count = 0;
1027 s->mouse_event_queue.rptr = 0;
1028 s->mouse_event_queue.wptr = 0;
1029 break;
1030 case AUX_SET_DEFAULT:
1031 s->mouse_sample_rate = 100;
1032 s->mouse_resolution = 2;
1033 s->mouse_status = 0;
1034 kbd_queue(s, AUX_ACK, 1);
1035 break;
1036 case AUX_RESET:
1037 s->mouse_sample_rate = 100;
1038 s->mouse_resolution = 2;
1039 s->mouse_status = 0;
1040 s->mouse_type = MOUSE_PROT_PS2;
1041 kbd_queue(s, AUX_ACK, 1);
1042 kbd_queue(s, 0xaa, 1);
1043 kbd_queue(s, s->mouse_type, 1);
1044 /* Flush the mouse events queue. */
1045 s->mouse_event_queue.count = 0;
1046 s->mouse_event_queue.rptr = 0;
1047 s->mouse_event_queue.wptr = 0;
1048 break;
1049 default:
1050 /* NACK all commands we don't know.
1051
1052 The usecase for this is the OS/2 mouse driver which will try
1053 read 0xE2 in order to figure out if it's a trackpoint device
1054 or not. If it doesn't get a NACK (or ACK) on the command it'll
1055 do several hundred thousand status reads before giving up. This
1056 is slows down the OS/2 boot up considerably. (It also seems that
1057 the code is somehow vulnerable while polling like this and that
1058 mouse or keyboard input at this point might screw things up badly.)
1059
1060 From http://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html:
1061
1062 Every command or data byte sent to the mouse (except for the
1063 resend command fe) is ACKed with fa. If the command or data
1064 is invalid, it is NACKed with fe. If the next byte is again
1065 invalid, the reply is ERROR: fc. */
1066 /** @todo send error if we NACKed the previous command? */
1067 kbd_queue(s, AUX_NACK, 1);
1068 break;
1069 }
1070 break;
1071 case AUX_SET_SAMPLE:
1072 s->mouse_sample_rate = val;
1073 /* detect IMPS/2 or IMEX */
1074 /* And enable horizontal scrolling reporting when requested */
1075 switch(s->mouse_detect_state) {
1076 default:
1077 case 0:
1078 if (val == 200)
1079 s->mouse_detect_state = 1;
1080 break;
1081 case 1:
1082 if (val == 100)
1083 s->mouse_detect_state = 2;
1084 else if (val == 200)
1085 s->mouse_detect_state = 3;
1086 else if ((val == 80) && s->mouse_type == MOUSE_PROT_IMEX)
1087 /* enable horizontal scrolling, byte two */
1088 s->mouse_detect_state = 4;
1089 else
1090 s->mouse_detect_state = 0;
1091 break;
1092 case 2:
1093 if (val == 80)
1094 {
1095 LogRelFlowFunc(("switching mouse device to IMPS/2 mode\n"));
1096 s->mouse_type = MOUSE_PROT_IMPS2;
1097 }
1098 s->mouse_detect_state = 0;
1099 break;
1100 case 3:
1101 if (val == 80)
1102 {
1103 LogRelFlowFunc(("switching mouse device to IMEX mode\n"));
1104 s->mouse_type = MOUSE_PROT_IMEX;
1105 }
1106 s->mouse_detect_state = 0;
1107 break;
1108 case 4:
1109 if (val == 40)
1110 {
1111 LogFlowFunc(("enabling IMEX horizontal scrolling reporting\n"));
1112 s->mouse_flags |= MOUSE_REPORT_HORIZONTAL;
1113 }
1114 s->mouse_detect_state = 0;
1115 break;
1116 }
1117 kbd_queue(s, AUX_ACK, 1);
1118 s->mouse_write_cmd = -1;
1119 break;
1120 case AUX_SET_RES:
1121 if (0 <= val && val < 4)
1122 {
1123 s->mouse_resolution = val;
1124 kbd_queue(s, AUX_ACK, 1);
1125 }
1126 else if (val == 6) /* Lifebook off magic knock */
1127 {
1128#ifdef IN_RING3
1129 LogRelFlowFunc(("switching mouse device to basic PS/2 mode\n"));
1130 s->mouse_type = MOUSE_PROT_PS2;
1131 s->Mouse.pDrv->pfnAbsModeChange(s->Mouse.pDrv, false);
1132#else
1133 return VINF_IOM_HC_IOPORT_WRITE;
1134#endif
1135 kbd_queue(s, AUX_NACK, 1);
1136 }
1137 else if (val == 8) /* Lifebook on magic knock */
1138 {
1139#ifdef IN_RING3
1140 LogRelFlowFunc(("switching mouse device to touch screen mode\n"));
1141 s->mouse_type = MOUSE_PROT_LIFEBOOK;
1142 s->Mouse.pDrv->pfnAbsModeChange(s->Mouse.pDrv, true);
1143#else
1144 return VINF_IOM_HC_IOPORT_WRITE;
1145#endif
1146 kbd_queue(s, AUX_NACK, 1);
1147 }
1148 else
1149 kbd_queue(s, AUX_NACK, 1);
1150 s->mouse_write_cmd = -1;
1151 break;
1152 }
1153 return VINF_SUCCESS;
1154}
1155
1156static int kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
1157{
1158 int rc = VINF_SUCCESS;
1159 KBDState *s = (KBDState*)opaque;
1160
1161#ifdef DEBUG_KBD
1162 Log(("kbd: write data=0x%02x\n", val));
1163#endif
1164
1165 switch(s->write_cmd) {
1166 case 0:
1167 rc = kbd_write_keyboard(s, val);
1168 break;
1169 case KBD_CCMD_WRITE_MODE:
1170 s->mode = val;
1171 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
1172 kbd_update_irq(s);
1173 break;
1174 case KBD_CCMD_WRITE_OBUF:
1175 kbd_queue(s, val, 0);
1176 break;
1177 case KBD_CCMD_WRITE_AUX_OBUF:
1178 kbd_queue(s, val, 1);
1179 break;
1180 case KBD_CCMD_WRITE_OUTPORT:
1181#ifdef TARGET_I386
1182# ifndef IN_RING3
1183 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) != !!(val & 2))
1184 rc = VINF_IOM_HC_IOPORT_WRITE;
1185# else /* IN_RING3 */
1186 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), !!(val & 2));
1187# endif /* !IN_RING3 */
1188#endif
1189 if (!(val & 1)) {
1190# ifndef IN_RING3
1191 rc = VINF_IOM_HC_IOPORT_WRITE;
1192# else
1193 rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns));
1194# endif
1195 }
1196 break;
1197 case KBD_CCMD_WRITE_MOUSE:
1198 rc = kbd_write_mouse(s, val);
1199 break;
1200 default:
1201 break;
1202 }
1203 s->write_cmd = 0;
1204 return rc;
1205}
1206
1207#ifdef IN_RING3
1208
1209static void kbd_reset(void *opaque)
1210{
1211 KBDState *s = (KBDState*)opaque;
1212 KBDQueue *q;
1213 MouseCmdQueue *mcq;
1214 MouseEventQueue *meq;
1215
1216 s->kbd_write_cmd = -1;
1217 s->mouse_write_cmd = -1;
1218 s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
1219 s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
1220 /* Resetting everything, keyword was not working right on NT4 reboot. */
1221 s->write_cmd = 0;
1222 s->scan_enabled = 0;
1223 s->translate = 0;
1224 s->scancode_set = 2;
1225 s->mouse_status = 0;
1226 s->mouse_resolution = 0;
1227 s->mouse_sample_rate = 0;
1228 s->mouse_wrap = 0;
1229 s->mouse_type = MOUSE_PROT_PS2;
1230 if (s->Mouse.pDrv)
1231 s->Mouse.pDrv->pfnAbsModeChange(s->Mouse.pDrv, false);
1232 s->mouse_detect_state = 0;
1233 s->mouse_dx = 0;
1234 s->mouse_dy = 0;
1235 s->mouse_dz = 0;
1236 s->mouse_dw = 0;
1237 s->mouse_flags = 0;
1238 s->mouse_cx = 0x8000;
1239 s->mouse_cy = 0x8000;
1240 s->mouse_buttons = 0;
1241 s->mouse_buttons_reported = 0;
1242 s->mouse_last_button = 0;
1243 q = &s->queue;
1244 q->rptr = 0;
1245 q->wptr = 0;
1246 q->count = 0;
1247 mcq = &s->mouse_command_queue;
1248 mcq->rptr = 0;
1249 mcq->wptr = 0;
1250 mcq->count = 0;
1251 meq = &s->mouse_event_queue;
1252 meq->rptr = 0;
1253 meq->wptr = 0;
1254 meq->count = 0;
1255}
1256
1257static void kbd_save(QEMUFile* f, void* opaque)
1258{
1259 uint32_t cItems;
1260 int i;
1261 KBDState *s = (KBDState*)opaque;
1262
1263 qemu_put_8s(f, &s->write_cmd);
1264 qemu_put_8s(f, &s->status);
1265 qemu_put_8s(f, &s->mode);
1266 qemu_put_be32s(f, &s->kbd_write_cmd);
1267 qemu_put_be32s(f, &s->scan_enabled);
1268 qemu_put_be32s(f, &s->mouse_write_cmd);
1269 qemu_put_8s(f, &s->mouse_status);
1270 qemu_put_8s(f, &s->mouse_resolution);
1271 qemu_put_8s(f, &s->mouse_sample_rate);
1272 qemu_put_8s(f, &s->mouse_wrap);
1273 qemu_put_8s(f, &s->mouse_type);
1274 qemu_put_8s(f, &s->mouse_detect_state);
1275 qemu_put_be32s(f, &s->mouse_dx);
1276 qemu_put_be32s(f, &s->mouse_dy);
1277 qemu_put_be32s(f, &s->mouse_dz);
1278 qemu_put_be32s(f, &s->mouse_dw);
1279 qemu_put_be32s(f, &s->mouse_flags);
1280 qemu_put_be32s(f, &s->mouse_cx);
1281 qemu_put_be32s(f, &s->mouse_cy);
1282 qemu_put_8s(f, &s->mouse_buttons);
1283 qemu_put_8s(f, &s->mouse_buttons_reported);
1284 qemu_put_8s(f, &s->mouse_last_button);
1285
1286 /* XXX: s->scancode_set isn't being saved, but we only really support set 2,
1287 * so no real harm done.
1288 */
1289
1290 /*
1291 * We have to save the queues too.
1292 */
1293 cItems = s->queue.count;
1294 SSMR3PutU32(f, cItems);
1295 for (i = s->queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->queue.data))
1296 SSMR3PutU8(f, s->queue.data[i]);
1297 Log(("kbd_save: %d keyboard queue items stored\n", s->queue.count));
1298
1299 cItems = s->mouse_command_queue.count;
1300 SSMR3PutU32(f, cItems);
1301 for (i = s->mouse_command_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_command_queue.data))
1302 SSMR3PutU8(f, s->mouse_command_queue.data[i]);
1303 Log(("kbd_save: %d mouse command queue items stored\n", s->mouse_command_queue.count));
1304
1305 cItems = s->mouse_event_queue.count;
1306 SSMR3PutU32(f, cItems);
1307 for (i = s->mouse_event_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_event_queue.data))
1308 SSMR3PutU8(f, s->mouse_event_queue.data[i]);
1309 Log(("kbd_save: %d mouse event queue items stored\n", s->mouse_event_queue.count));
1310
1311 /* terminator */
1312 SSMR3PutU32(f, ~0);
1313}
1314
1315static int kbd_load(QEMUFile* f, void* opaque, int version_id)
1316{
1317 uint32_t u32, i;
1318 int rc;
1319 KBDState *s = (KBDState*)opaque;
1320
1321 if (version_id < 2 || version_id > PCKBD_SAVED_STATE_VERSION)
1322 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1323 qemu_get_8s(f, &s->write_cmd);
1324 qemu_get_8s(f, &s->status);
1325 qemu_get_8s(f, &s->mode);
1326 qemu_get_be32s(f, (uint32_t *)&s->kbd_write_cmd);
1327 qemu_get_be32s(f, (uint32_t *)&s->scan_enabled);
1328 qemu_get_be32s(f, (uint32_t *)&s->mouse_write_cmd);
1329 qemu_get_8s(f, &s->mouse_status);
1330 qemu_get_8s(f, &s->mouse_resolution);
1331 qemu_get_8s(f, &s->mouse_sample_rate);
1332 qemu_get_8s(f, &s->mouse_wrap);
1333 qemu_get_8s(f, &s->mouse_type);
1334 if (s->mouse_type == MOUSE_PROT_LIFEBOOK && s->Mouse.pDrv)
1335 s->Mouse.pDrv->pfnAbsModeChange(s->Mouse.pDrv, true);
1336 qemu_get_8s(f, &s->mouse_detect_state);
1337 qemu_get_be32s(f, (uint32_t *)&s->mouse_dx);
1338 qemu_get_be32s(f, (uint32_t *)&s->mouse_dy);
1339 qemu_get_be32s(f, (uint32_t *)&s->mouse_dz);
1340 if (version_id > 2)
1341 {
1342 SSMR3GetS32(f, &s->mouse_dw);
1343 SSMR3GetS32(f, &s->mouse_flags);
1344 }
1345 qemu_get_8s(f, &s->mouse_buttons);
1346 if (version_id > 3)
1347 {
1348 SSMR3GetU32(f, &s->mouse_cx);
1349 SSMR3GetU32(f, &s->mouse_cy);
1350 SSMR3GetU8(f, &s->mouse_buttons_reported);
1351 SSMR3GetU8(f, &s->mouse_last_button);
1352 }
1353 s->queue.count = 0;
1354 s->queue.rptr = 0;
1355 s->queue.wptr = 0;
1356 s->mouse_command_queue.count = 0;
1357 s->mouse_command_queue.rptr = 0;
1358 s->mouse_command_queue.wptr = 0;
1359 s->mouse_event_queue.count = 0;
1360 s->mouse_event_queue.rptr = 0;
1361 s->mouse_event_queue.wptr = 0;
1362
1363 /* Determine the translation state. */
1364 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
1365 s->scancode_set = 2; /* XXX: See comment in kbd_save(). */
1366
1367 /*
1368 * Load the queues
1369 */
1370 rc = SSMR3GetU32(f, &u32);
1371 if (RT_FAILURE(rc))
1372 return rc;
1373 if (u32 > RT_ELEMENTS(s->queue.data))
1374 {
1375 AssertMsgFailed(("u32=%#x\n", u32));
1376 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1377 }
1378 for (i = 0; i < u32; i++)
1379 {
1380 rc = SSMR3GetU8(f, &s->queue.data[i]);
1381 if (RT_FAILURE(rc))
1382 return rc;
1383 }
1384 s->queue.wptr = u32 % RT_ELEMENTS(s->queue.data);
1385 s->queue.count = u32;
1386 Log(("kbd_load: %d keyboard queue items loaded\n", u32));
1387
1388 rc = SSMR3GetU32(f, &u32);
1389 if (RT_FAILURE(rc))
1390 return rc;
1391 if (u32 > RT_ELEMENTS(s->mouse_command_queue.data))
1392 {
1393 AssertMsgFailed(("u32=%#x\n", u32));
1394 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1395 }
1396 for (i = 0; i < u32; i++)
1397 {
1398 rc = SSMR3GetU8(f, &s->mouse_command_queue.data[i]);
1399 if (RT_FAILURE(rc))
1400 return rc;
1401 }
1402 s->mouse_command_queue.wptr = u32 % RT_ELEMENTS(s->mouse_command_queue.data);
1403 s->mouse_command_queue.count = u32;
1404 Log(("kbd_load: %d mouse command queue items loaded\n", u32));
1405
1406 rc = SSMR3GetU32(f, &u32);
1407 if (RT_FAILURE(rc))
1408 return rc;
1409 if (u32 > RT_ELEMENTS(s->mouse_event_queue.data))
1410 {
1411 AssertMsgFailed(("u32=%#x\n", u32));
1412 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1413 }
1414 for (i = 0; i < u32; i++)
1415 {
1416 rc = SSMR3GetU8(f, &s->mouse_event_queue.data[i]);
1417 if (RT_FAILURE(rc))
1418 return rc;
1419 }
1420 s->mouse_event_queue.wptr = u32 % RT_ELEMENTS(s->mouse_event_queue.data);
1421 s->mouse_event_queue.count = u32;
1422 Log(("kbd_load: %d mouse event queue items loaded\n", u32));
1423
1424 /* terminator */
1425 rc = SSMR3GetU32(f, &u32);
1426 if (RT_FAILURE(rc))
1427 return rc;
1428 if (u32 != ~0U)
1429 {
1430 AssertMsgFailed(("u32=%#x\n", u32));
1431 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1432 }
1433 return 0;
1434}
1435#endif /* IN_RING3 */
1436
1437
1438/* VirtualBox code start */
1439
1440/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
1441
1442/**
1443 * Port I/O Handler for keyboard data IN operations.
1444 *
1445 * @returns VBox status code.
1446 *
1447 * @param pDevIns The device instance.
1448 * @param pvUser User argument - ignored.
1449 * @param Port Port number used for the IN operation.
1450 * @param pu32 Where to store the result.
1451 * @param cb Number of bytes read.
1452 */
1453PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1454{
1455 NOREF(pvUser);
1456 if (cb == 1)
1457 {
1458 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1459 int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
1460 if (RT_LIKELY(rc == VINF_SUCCESS))
1461 {
1462 *pu32 = kbd_read_data(pThis, Port);
1463 PDMCritSectLeave(&pThis->CritSect);
1464 Log2(("kbdIOPortDataRead: Port=%#x cb=%d *pu32=%#x\n", Port, cb, *pu32));
1465 }
1466 return rc;
1467 }
1468 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1469 return VERR_IOM_IOPORT_UNUSED;
1470}
1471
1472/**
1473 * Port I/O Handler for keyboard data OUT operations.
1474 *
1475 * @returns VBox status code.
1476 *
1477 * @param pDevIns The device instance.
1478 * @param pvUser User argument - ignored.
1479 * @param Port Port number used for the IN operation.
1480 * @param u32 The value to output.
1481 * @param cb The value size in bytes.
1482 */
1483PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1484{
1485 int rc = VINF_SUCCESS;
1486 NOREF(pvUser);
1487 if (cb == 1)
1488 {
1489 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1490 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
1491 if (RT_LIKELY(rc == VINF_SUCCESS))
1492 {
1493 rc = kbd_write_data(pThis, Port, u32);
1494 PDMCritSectLeave(&pThis->CritSect);
1495 Log2(("kbdIOPortDataWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1496 }
1497 }
1498 else
1499 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1500 return rc;
1501}
1502
1503/**
1504 * Port I/O Handler for keyboard status IN operations.
1505 *
1506 * @returns VBox status code.
1507 *
1508 * @param pDevIns The device instance.
1509 * @param pvUser User argument - ignored.
1510 * @param Port Port number used for the IN operation.
1511 * @param pu32 Where to store the result.
1512 * @param cb Number of bytes read.
1513 */
1514PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1515{
1516 NOREF(pvUser);
1517 if (cb == 1)
1518 {
1519 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1520 int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
1521 if (RT_LIKELY(rc == VINF_SUCCESS))
1522 {
1523 *pu32 = kbd_read_status(pThis, Port);
1524 PDMCritSectLeave(&pThis->CritSect);
1525 Log2(("kbdIOPortStatusRead: Port=%#x cb=%d -> *pu32=%#x\n", Port, cb, *pu32));
1526 }
1527 return rc;
1528 }
1529 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1530 return VERR_IOM_IOPORT_UNUSED;
1531}
1532
1533/**
1534 * Port I/O Handler for keyboard command OUT operations.
1535 *
1536 * @returns VBox status code.
1537 *
1538 * @param pDevIns The device instance.
1539 * @param pvUser User argument - ignored.
1540 * @param Port Port number used for the IN operation.
1541 * @param u32 The value to output.
1542 * @param cb The value size in bytes.
1543 */
1544PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1545{
1546 int rc = VINF_SUCCESS;
1547 NOREF(pvUser);
1548 if (cb == 1)
1549 {
1550 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1551 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
1552 if (RT_LIKELY(rc == VINF_SUCCESS))
1553 {
1554 rc = kbd_write_command(pThis, Port, u32);
1555 PDMCritSectLeave(&pThis->CritSect);
1556 Log2(("kbdIOPortCommandWrite: Port=%#x cb=%d u32=%#x rc=%Rrc\n", Port, cb, u32, rc));
1557 }
1558 }
1559 else
1560 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1561 return rc;
1562}
1563
1564#ifdef IN_RING3
1565
1566/**
1567 * Saves a state of the keyboard device.
1568 *
1569 * @returns VBox status code.
1570 * @param pDevIns The device instance.
1571 * @param pSSMHandle The handle to save the state to.
1572 */
1573static DECLCALLBACK(int) kbdSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1574{
1575 kbd_save(pSSMHandle, PDMINS_2_DATA(pDevIns, KBDState *));
1576 return VINF_SUCCESS;
1577}
1578
1579
1580/**
1581 * Loads a saved keyboard device state.
1582 *
1583 * @returns VBox status code.
1584 * @param pDevIns The device instance.
1585 * @param pSSMHandle The handle to the saved state.
1586 * @param uVersion The data unit version number.
1587 * @param uPass The data pass.
1588 */
1589static DECLCALLBACK(int) kbdLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass)
1590{
1591 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1592 return kbd_load(pSSMHandle, PDMINS_2_DATA(pDevIns, KBDState *), uVersion);
1593}
1594
1595/**
1596 * Reset notification.
1597 *
1598 * @returns VBox status.
1599 * @param pDevIns The device instance data.
1600 */
1601static DECLCALLBACK(void) kbdReset(PPDMDEVINS pDevIns)
1602{
1603 kbd_reset(PDMINS_2_DATA(pDevIns, KBDState *));
1604}
1605
1606
1607/* -=-=-=-=-=- Keyboard: IBase -=-=-=-=-=- */
1608
1609/**
1610 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1611 */
1612static DECLCALLBACK(void *) kbdKeyboardQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1613{
1614 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Keyboard.IBase);
1615 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Keyboard.IBase);
1616 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDPORT, &pThis->Keyboard.IPort);
1617 return NULL;
1618}
1619
1620
1621/* -=-=-=-=-=- Keyboard: IKeyboardPort -=-=-=-=-=- */
1622
1623/**
1624 * Keyboard event handler.
1625 *
1626 * @returns VBox status code.
1627 * @param pInterface Pointer to the keyboard port interface (KBDState::Keyboard.IPort).
1628 * @param u8KeyCode The keycode.
1629 */
1630static DECLCALLBACK(int) kbdKeyboardPutEvent(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)
1631{
1632 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Keyboard.IPort);
1633 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1634 AssertReleaseRC(rc);
1635
1636 pc_kbd_put_keycode(pThis, u8KeyCode);
1637
1638 PDMCritSectLeave(&pThis->CritSect);
1639 return VINF_SUCCESS;
1640}
1641
1642
1643/* -=-=-=-=-=- Mouse: IBase -=-=-=-=-=- */
1644
1645/**
1646 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1647 */
1648static DECLCALLBACK(void *) kbdMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1649{
1650 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Mouse.IBase);
1651 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Mouse.IBase);
1652 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Mouse.IPort);
1653 return NULL;
1654}
1655
1656
1657/* -=-=-=-=-=- Mouse: IMousePort -=-=-=-=-=- */
1658
1659/**
1660 * @interface_method_impl{PDMIMOUSEPORT, pfnPutEvent}
1661 */
1662static DECLCALLBACK(int) kbdMousePutEvent(PPDMIMOUSEPORT pInterface, int32_t iDeltaX, int32_t iDeltaY,
1663 int32_t iDeltaZ, int32_t iDeltaW, uint32_t fButtonStates)
1664{
1665 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Mouse.IPort);
1666 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1667 AssertReleaseRC(rc);
1668
1669 pc_kbd_mouse_event(pThis, iDeltaX, iDeltaY, iDeltaZ, iDeltaW, fButtonStates);
1670
1671 PDMCritSectLeave(&pThis->CritSect);
1672 return VINF_SUCCESS;
1673}
1674
1675/**
1676 * @interface_method_impl{PDMIMOUSEPORT, pfnPutEventAbs}
1677 */
1678static DECLCALLBACK(int) kbdMousePutEventAbs(PPDMIMOUSEPORT pInterface, uint32_t uX, uint32_t uY, int32_t iDeltaZ, int32_t iDeltaW, uint32_t fButtons)
1679{
1680 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Mouse.IPort);
1681 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1682 AssertReleaseRC(rc);
1683
1684 if (uX != pThis->mouse_cx || uY != pThis->mouse_cy)
1685 pc_kbd_mouse_event_abs(pThis, uX, uY);
1686 if (iDeltaZ || iDeltaW || fButtons != pThis->mouse_buttons)
1687 pc_kbd_mouse_event(pThis, 0, 0, iDeltaZ, iDeltaW, fButtons);
1688
1689 PDMCritSectLeave(&pThis->CritSect);
1690 return VINF_SUCCESS;
1691}
1692
1693
1694/* -=-=-=-=-=- real code -=-=-=-=-=- */
1695
1696
1697/**
1698 * Attach command.
1699 *
1700 * This is called to let the device attach to a driver for a specified LUN
1701 * during runtime. This is not called during VM construction, the device
1702 * constructor have to attach to all the available drivers.
1703 *
1704 * This is like plugging in the keyboard or mouse after turning on the PC.
1705 *
1706 * @returns VBox status code.
1707 * @param pDevIns The device instance.
1708 * @param iLUN The logical unit which is being detached.
1709 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1710 * @remark The keyboard controller doesn't support this action, this is just
1711 * implemented to try out the driver<->device structure.
1712 */
1713static DECLCALLBACK(int) kbdAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1714{
1715 int rc;
1716 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1717
1718 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
1719 ("PS/2 device does not support hotplugging\n"),
1720 VERR_INVALID_PARAMETER);
1721
1722 switch (iLUN)
1723 {
1724 /* LUN #0: keyboard */
1725 case 0:
1726 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Keyboard.IBase, &pThis->Keyboard.pDrvBase, "Keyboard Port");
1727 if (RT_SUCCESS(rc))
1728 {
1729 pThis->Keyboard.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Keyboard.pDrvBase, PDMIKEYBOARDCONNECTOR);
1730 if (!pThis->Keyboard.pDrv)
1731 {
1732 AssertLogRelMsgFailed(("LUN #0 doesn't have a keyboard interface! rc=%Rrc\n", rc));
1733 rc = VERR_PDM_MISSING_INTERFACE;
1734 }
1735 }
1736 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1737 {
1738 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
1739 rc = VINF_SUCCESS;
1740 }
1741 else
1742 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
1743 break;
1744
1745 /* LUN #1: aux/mouse */
1746 case 1:
1747 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Mouse.IBase, &pThis->Mouse.pDrvBase, "Aux (Mouse) Port");
1748 if (RT_SUCCESS(rc))
1749 {
1750 pThis->Mouse.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Mouse.pDrvBase, PDMIMOUSECONNECTOR);
1751 if (!pThis->Mouse.pDrv)
1752 {
1753 AssertLogRelMsgFailed(("LUN #1 doesn't have a mouse interface! rc=%Rrc\n", rc));
1754 rc = VERR_PDM_MISSING_INTERFACE;
1755 }
1756 }
1757 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1758 {
1759 Log(("%s/%d: warning: no driver attached to LUN #1!\n", pDevIns->pReg->szName, pDevIns->iInstance));
1760 rc = VINF_SUCCESS;
1761 }
1762 else
1763 AssertLogRelMsgFailed(("Failed to attach LUN #1! rc=%Rrc\n", rc));
1764 break;
1765
1766 default:
1767 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1768 return VERR_PDM_NO_SUCH_LUN;
1769 }
1770
1771 return rc;
1772}
1773
1774
1775/**
1776 * Detach notification.
1777 *
1778 * This is called when a driver is detaching itself from a LUN of the device.
1779 * The device should adjust it's state to reflect this.
1780 *
1781 * This is like unplugging the network cable to use it for the laptop or
1782 * something while the PC is still running.
1783 *
1784 * @param pDevIns The device instance.
1785 * @param iLUN The logical unit which is being detached.
1786 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1787 * @remark The keyboard controller doesn't support this action, this is just
1788 * implemented to try out the driver<->device structure.
1789 */
1790static DECLCALLBACK(void) kbdDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1791{
1792#if 0
1793 /*
1794 * Reset the interfaces and update the controller state.
1795 */
1796 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1797 switch (iLUN)
1798 {
1799 /* LUN #0: keyboard */
1800 case 0:
1801 pThis->Keyboard.pDrv = NULL;
1802 pThis->Keyboard.pDrvBase = NULL;
1803 break;
1804
1805 /* LUN #1: aux/mouse */
1806 case 1:
1807 pThis->Mouse.pDrv = NULL;
1808 pThis->Mouse.pDrvBase = NULL;
1809 break;
1810
1811 default:
1812 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1813 break;
1814 }
1815#endif
1816}
1817
1818
1819/**
1820 * @copydoc FNPDMDEVRELOCATE
1821 */
1822static DECLCALLBACK(void) kdbRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1823{
1824 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1825 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1826}
1827
1828
1829/**
1830 * Destruct a device instance for a VM.
1831 *
1832 * @returns VBox status.
1833 * @param pDevIns The device instance data.
1834 */
1835static DECLCALLBACK(int) kbdDestruct(PPDMDEVINS pDevIns)
1836{
1837 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1838 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1839
1840 PDMR3CritSectDelete(&pThis->CritSect);
1841
1842 return VINF_SUCCESS;
1843}
1844
1845
1846/**
1847 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1848 */
1849static DECLCALLBACK(int) kbdConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1850{
1851 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1852 int rc;
1853 bool fGCEnabled;
1854 bool fR0Enabled;
1855 Assert(iInstance == 0);
1856
1857 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1858
1859 /*
1860 * Validate and read the configuration.
1861 */
1862 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0R0Enabled\0"))
1863 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1864 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
1865 if (RT_FAILURE(rc))
1866 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"GCEnabled\" from the config"));
1867 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1868 if (RT_FAILURE(rc))
1869 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"R0Enabled\" from the config"));
1870 Log(("pckbd: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
1871
1872
1873 /*
1874 * Initialize the interfaces.
1875 */
1876 pThis->pDevInsR3 = pDevIns;
1877 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1878 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1879 pThis->Keyboard.IBase.pfnQueryInterface = kbdKeyboardQueryInterface;
1880 pThis->Keyboard.IPort.pfnPutEvent = kbdKeyboardPutEvent;
1881
1882 pThis->Mouse.IBase.pfnQueryInterface = kbdMouseQueryInterface;
1883 pThis->Mouse.IPort.pfnPutEvent = kbdMousePutEvent;
1884 pThis->Mouse.IPort.pfnPutEventAbs = kbdMousePutEventAbs;
1885
1886 /*
1887 * Initialize the critical section.
1888 */
1889 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "PS2KM#%d", iInstance);
1890 if (RT_FAILURE(rc))
1891 return rc;
1892
1893 /*
1894 * Register I/O ports, save state, keyboard event handler and mouse event handlers.
1895 */
1896 rc = PDMDevHlpIOPortRegister(pDevIns, 0x60, 1, NULL, kbdIOPortDataWrite, kbdIOPortDataRead, NULL, NULL, "PC Keyboard - Data");
1897 if (RT_FAILURE(rc))
1898 return rc;
1899 rc = PDMDevHlpIOPortRegister(pDevIns, 0x64, 1, NULL, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL, NULL, "PC Keyboard - Command / Status");
1900 if (RT_FAILURE(rc))
1901 return rc;
1902 if (fGCEnabled)
1903 {
1904 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1905 if (RT_FAILURE(rc))
1906 return rc;
1907 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1908 if (RT_FAILURE(rc))
1909 return rc;
1910 }
1911 if (fR0Enabled)
1912 {
1913 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1914 if (RT_FAILURE(rc))
1915 return rc;
1916 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1917 if (RT_FAILURE(rc))
1918 return rc;
1919 }
1920 rc = PDMDevHlpSSMRegister(pDevIns, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis), kbdSaveExec, kbdLoadExec);
1921 if (RT_FAILURE(rc))
1922 return rc;
1923
1924 /*
1925 * Attach to the keyboard and mouse drivers.
1926 */
1927 rc = kbdAttach(pDevIns, 0 /* keyboard LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1928 if (RT_FAILURE(rc))
1929 return rc;
1930 rc = kbdAttach(pDevIns, 1 /* aux/mouse LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1931 if (RT_FAILURE(rc))
1932 return rc;
1933
1934 /*
1935 * Initialize the device state.
1936 */
1937 kbdReset(pDevIns);
1938
1939 return VINF_SUCCESS;
1940}
1941
1942
1943/**
1944 * The device registration structure.
1945 */
1946const PDMDEVREG g_DevicePS2KeyboardMouse =
1947{
1948 /* u32Version */
1949 PDM_DEVREG_VERSION,
1950 /* szName */
1951 "pckbd",
1952 /* szRCMod */
1953 "VBoxDDGC.gc",
1954 /* szR0Mod */
1955 "VBoxDDR0.r0",
1956 /* pszDescription */
1957 "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller. "
1958 "LUN #0 is the keyboard connector. "
1959 "LUN #1 is the aux/mouse connector.",
1960 /* fFlags */
1961 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1962 /* fClass */
1963 PDM_DEVREG_CLASS_INPUT,
1964 /* cMaxInstances */
1965 1,
1966 /* cbInstance */
1967 sizeof(KBDState),
1968 /* pfnConstruct */
1969 kbdConstruct,
1970 /* pfnDestruct */
1971 kbdDestruct,
1972 /* pfnRelocate */
1973 kdbRelocate,
1974 /* pfnIOCtl */
1975 NULL,
1976 /* pfnPowerOn */
1977 NULL,
1978 /* pfnReset */
1979 kbdReset,
1980 /* pfnSuspend */
1981 NULL,
1982 /* pfnResume */
1983 NULL,
1984 /* pfnAttach */
1985 kbdAttach,
1986 /* pfnDetach */
1987 kbdDetach,
1988 /* pfnQueryInterface. */
1989 NULL,
1990 /* pfnInitComplete */
1991 NULL,
1992 /* pfnPowerOff */
1993 NULL,
1994 /* pfnSoftReset */
1995 NULL,
1996 /* u32VersionEnd */
1997 PDM_DEVREG_VERSION
1998};
1999
2000#endif /* IN_RING3 */
2001#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2002
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