VirtualBox

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

Last change on this file since 51856 was 50965, checked in by vboxsync, 11 years ago

DevPS2: Saved state update for new PS/2 mouse emulation. Curretly disabled.

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