VirtualBox

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

Last change on this file since 27040 was 26925, checked in by vboxsync, 15 years ago

Devices/Input/DevPS2: backed out the absolute reporting code, minus cleanup done to the device code

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