VirtualBox

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

Last change on this file since 56284 was 56284, checked in by vboxsync, 9 years ago

s/VMMGC.gc/VMMRC.rc/g s/VBoxDDGC.gc/VBoxDDRC.rc/g s/VBoxDD2GC.gc/VBoxDD2RC.rc/g

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.9 KB
Line 
1/* $Id: DevPS2.cpp 56284 2015-06-09 10:46:34Z 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
219 uint32_t Alignment0;
220#endif
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, 0xBF);
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 uint8_t u8State;
1191 uint8_t u8Rate;
1192 uint8_t u8Proto;
1193
1194 SSMR3GetU32(pSSM, &u32Dummy);
1195 SSMR3GetU8(pSSM, &u8State);
1196 SSMR3GetU8(pSSM, &u8Dummy);
1197 SSMR3GetU8(pSSM, &u8Rate);
1198 SSMR3GetU8(pSSM, &u8Dummy);
1199 SSMR3GetU8(pSSM, &u8Proto);
1200 SSMR3GetU8(pSSM, &u8Dummy);
1201 SSMR3GetS32(pSSM, &i32Dummy);
1202 SSMR3GetS32(pSSM, &i32Dummy);
1203 SSMR3GetS32(pSSM, &i32Dummy);
1204 if (version_id > 2)
1205 {
1206 SSMR3GetS32(pSSM, &i32Dummy);
1207 SSMR3GetS32(pSSM, &i32Dummy);
1208 }
1209 rc = SSMR3GetU8(pSSM, &u8Dummy);
1210 if (version_id == 4)
1211 {
1212 SSMR3GetU32(pSSM, &u32Dummy);
1213 rc = SSMR3GetU32(pSSM, &u32Dummy);
1214 }
1215 if (version_id > 3)
1216 rc = SSMR3GetU8(pSSM, &u8Dummy);
1217 if (version_id == 4)
1218 rc = SSMR3GetU8(pSSM, &u8Dummy);
1219 AssertLogRelRCReturn(rc, rc);
1220
1221 PS2MFixupState(&s->Aux, u8State, u8Rate, u8Proto);
1222 }
1223#endif
1224
1225 /* Determine the translation state. */
1226 s->translate = (s->mode & KBD_MODE_KCC) == KBD_MODE_KCC;
1227
1228 /*
1229 * Load the queues
1230 */
1231 if (version_id <= 5)
1232 {
1233 rc = SSMR3GetU32(pSSM, &u32);
1234 if (RT_FAILURE(rc))
1235 return rc;
1236 for (i = 0; i < u32; i++)
1237 {
1238 rc = SSMR3GetU8(pSSM, &u8Dummy);
1239 if (RT_FAILURE(rc))
1240 return rc;
1241 }
1242 Log(("kbd_load: %d keyboard queue items discarded from old saved state\n", u32));
1243 }
1244
1245#ifndef VBOX_WITH_NEW_PS2M
1246 rc = SSMR3GetU32(pSSM, &u32);
1247 if (RT_FAILURE(rc))
1248 return rc;
1249 if (u32 > RT_ELEMENTS(s->mouse_command_queue.data))
1250 {
1251 AssertMsgFailed(("u32=%#x\n", u32));
1252 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1253 }
1254 for (i = 0; i < u32; i++)
1255 {
1256 rc = SSMR3GetU8(pSSM, &s->mouse_command_queue.data[i]);
1257 if (RT_FAILURE(rc))
1258 return rc;
1259 }
1260 s->mouse_command_queue.wptr = u32 % RT_ELEMENTS(s->mouse_command_queue.data);
1261 s->mouse_command_queue.count = u32;
1262 Log(("kbd_load: %d mouse command queue items loaded\n", u32));
1263
1264 rc = SSMR3GetU32(pSSM, &u32);
1265 if (RT_FAILURE(rc))
1266 return rc;
1267 if (u32 > RT_ELEMENTS(s->mouse_event_queue.data))
1268 {
1269 AssertMsgFailed(("u32=%#x\n", u32));
1270 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1271 }
1272 for (i = 0; i < u32; i++)
1273 {
1274 rc = SSMR3GetU8(pSSM, &s->mouse_event_queue.data[i]);
1275 if (RT_FAILURE(rc))
1276 return rc;
1277 }
1278 s->mouse_event_queue.wptr = u32 % RT_ELEMENTS(s->mouse_event_queue.data);
1279 s->mouse_event_queue.count = u32;
1280 Log(("kbd_load: %d mouse event queue items loaded\n", u32));
1281#else
1282 if (version_id <= 7)
1283 {
1284 rc = SSMR3GetU32(pSSM, &u32);
1285 if (RT_FAILURE(rc))
1286 return rc;
1287 for (i = 0; i < u32; i++)
1288 {
1289 rc = SSMR3GetU8(pSSM, &u8Dummy);
1290 if (RT_FAILURE(rc))
1291 return rc;
1292 }
1293 Log(("kbd_load: %d mouse event queue items discarded from old saved state\n", u32));
1294
1295 rc = SSMR3GetU32(pSSM, &u32);
1296 if (RT_FAILURE(rc))
1297 return rc;
1298 for (i = 0; i < u32; i++)
1299 {
1300 rc = SSMR3GetU8(pSSM, &u8Dummy);
1301 if (RT_FAILURE(rc))
1302 return rc;
1303 }
1304 Log(("kbd_load: %d mouse command queue items discarded from old saved state\n", u32));
1305 }
1306#endif
1307
1308 /* terminator */
1309 rc = SSMR3GetU32(pSSM, &u32);
1310 if (RT_FAILURE(rc))
1311 return rc;
1312 if (u32 != ~0U)
1313 {
1314 AssertMsgFailed(("u32=%#x\n", u32));
1315 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1316 }
1317#ifndef VBOX_WITH_NEW_PS2M
1318 /* Resend a notification to Main if the device is active */
1319 kbd_mouse_update_downstream_status(s);
1320#endif
1321 return 0;
1322}
1323#endif /* IN_RING3 */
1324
1325
1326/* VirtualBox code start */
1327
1328/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
1329
1330/**
1331 * Port I/O Handler for keyboard data IN operations.
1332 *
1333 * @returns VBox status code.
1334 *
1335 * @param pDevIns The device instance.
1336 * @param pvUser User argument - ignored.
1337 * @param Port Port number used for the IN operation.
1338 * @param pu32 Where to store the result.
1339 * @param cb Number of bytes read.
1340 */
1341PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1342{
1343 NOREF(pvUser);
1344 if (cb == 1)
1345 {
1346 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1347 *pu32 = kbd_read_data(pThis, Port);
1348 Log2(("kbdIOPortDataRead: Port=%#x cb=%d *pu32=%#x\n", Port, cb, *pu32));
1349 return VINF_SUCCESS;
1350 }
1351 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1352 return VERR_IOM_IOPORT_UNUSED;
1353}
1354
1355/**
1356 * Port I/O Handler for keyboard data OUT operations.
1357 *
1358 * @returns VBox status code.
1359 *
1360 * @param pDevIns The device instance.
1361 * @param pvUser User argument - ignored.
1362 * @param Port Port number used for the IN operation.
1363 * @param u32 The value to output.
1364 * @param cb The value size in bytes.
1365 */
1366PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1367{
1368 int rc = VINF_SUCCESS;
1369 NOREF(pvUser);
1370 if (cb == 1 || cb == 2)
1371 {
1372 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1373 rc = kbd_write_data(pThis, Port, (uint8_t)u32);
1374 Log2(("kbdIOPortDataWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1375 }
1376 else
1377 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1378 return rc;
1379}
1380
1381/**
1382 * Port I/O Handler for keyboard status IN operations.
1383 *
1384 * @returns VBox status code.
1385 *
1386 * @param pDevIns The device instance.
1387 * @param pvUser User argument - ignored.
1388 * @param Port Port number used for the IN operation.
1389 * @param pu32 Where to store the result.
1390 * @param cb Number of bytes read.
1391 */
1392PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1393{
1394 uint16_t fluff = 0;
1395 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1396
1397 NOREF(pvUser);
1398 switch (cb) {
1399 case 2:
1400 fluff = 0xff00;
1401 case 1:
1402 *pu32 = fluff | kbd_read_status(pThis, Port);
1403 Log2(("kbdIOPortStatusRead: Port=%#x cb=%d -> *pu32=%#x\n", Port, cb, *pu32));
1404 return VINF_SUCCESS;
1405 default:
1406 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1407 return VERR_IOM_IOPORT_UNUSED;
1408 }
1409}
1410
1411/**
1412 * Port I/O Handler for keyboard command OUT operations.
1413 *
1414 * @returns VBox status code.
1415 *
1416 * @param pDevIns The device instance.
1417 * @param pvUser User argument - ignored.
1418 * @param Port Port number used for the IN operation.
1419 * @param u32 The value to output.
1420 * @param cb The value size in bytes.
1421 */
1422PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1423{
1424 int rc = VINF_SUCCESS;
1425 NOREF(pvUser);
1426 if (cb == 1 || cb == 2)
1427 {
1428 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1429 rc = kbd_write_command(pThis, Port, (uint8_t)u32);
1430 Log2(("kbdIOPortCommandWrite: Port=%#x cb=%d u32=%#x rc=%Rrc\n", Port, cb, u32, rc));
1431 }
1432 else
1433 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1434 return rc;
1435}
1436
1437#ifdef IN_RING3
1438
1439/**
1440 * Saves a state of the keyboard device.
1441 *
1442 * @returns VBox status code.
1443 * @param pDevIns The device instance.
1444 * @param pSSM The handle to save the state to.
1445 */
1446static DECLCALLBACK(int) kbdSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1447{
1448 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1449 kbd_save(pSSM, pThis);
1450 PS2KSaveState(&pThis->Kbd, pSSM);
1451#ifdef VBOX_WITH_NEW_PS2M
1452 PS2MSaveState(&pThis->Aux, pSSM);
1453#endif
1454 return VINF_SUCCESS;
1455}
1456
1457
1458/**
1459 * Loads a saved keyboard device state.
1460 *
1461 * @returns VBox status code.
1462 * @param pDevIns The device instance.
1463 * @param pSSM The handle to the saved state.
1464 * @param uVersion The data unit version number.
1465 * @param uPass The data pass.
1466 */
1467static DECLCALLBACK(int) kbdLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1468{
1469 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1470 int rc;
1471
1472 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1473 rc = kbd_load(pSSM, pThis, uVersion);
1474 if (uVersion >= 6)
1475 rc = PS2KLoadState(&pThis->Kbd, pSSM, uVersion);
1476#ifdef VBOX_WITH_NEW_PS2M
1477 if (uVersion >= 8)
1478 rc = PS2MLoadState(&pThis->Aux, pSSM, uVersion);
1479#endif
1480 return rc;
1481}
1482
1483/**
1484 * @callback_method_impl{FNSSMDEVLOADDONE, Key state fix-up after loading
1485 */
1486static DECLCALLBACK(int) kbdLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1487{
1488 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1489 int rc;
1490
1491 rc = PS2KLoadDone(&pThis->Kbd, pSSM);
1492 return rc;
1493}
1494
1495/**
1496 * Reset notification.
1497 *
1498 * @returns VBox status.
1499 * @param pDevIns The device instance data.
1500 */
1501static DECLCALLBACK(void) kbdReset(PPDMDEVINS pDevIns)
1502{
1503 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1504
1505 kbd_reset(pThis);
1506 PS2KReset(&pThis->Kbd);
1507#ifdef VBOX_WITH_NEW_PS2M
1508 PS2MReset(&pThis->Aux);
1509#endif
1510}
1511
1512
1513#ifndef VBOX_WITH_NEW_PS2M
1514/* -=-=-=-=-=- Mouse: IBase -=-=-=-=-=- */
1515
1516/**
1517 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1518 */
1519static DECLCALLBACK(void *) kbdMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1520{
1521 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Mouse.IBase);
1522 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Mouse.IBase);
1523 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Mouse.IPort);
1524 return NULL;
1525}
1526
1527
1528/* -=-=-=-=-=- Mouse: IMousePort -=-=-=-=-=- */
1529
1530/**
1531 * @interface_method_impl{PDMIMOUSEPORT, pfnPutEvent}
1532 */
1533static DECLCALLBACK(int) kbdMousePutEvent(PPDMIMOUSEPORT pInterface, int32_t dx,
1534 int32_t dy, int32_t dz, int32_t dw,
1535 uint32_t fButtons)
1536{
1537 KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Mouse.IPort);
1538 int rc = PDMCritSectEnter(pThis->pDevInsR3->pCritSectRoR3, VERR_SEM_BUSY);
1539 AssertReleaseRC(rc);
1540
1541 pc_kbd_mouse_event(pThis, dx, dy, dz, dw, fButtons);
1542
1543 PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3);
1544 return VINF_SUCCESS;
1545}
1546
1547/**
1548 * @interface_method_impl{PDMIMOUSEPORT, pfnPutEventAbs}
1549 */
1550static DECLCALLBACK(int) kbdMousePutEventAbs(PPDMIMOUSEPORT pInterface,
1551 uint32_t x, uint32_t y, int32_t dz,
1552 int32_t dw, uint32_t fButtons)
1553{
1554 AssertFailedReturn(VERR_NOT_SUPPORTED);
1555 NOREF(pInterface); NOREF(x); NOREF(y); NOREF(dz); NOREF(dw); NOREF(fButtons);
1556}
1557
1558/**
1559 * @interface_method_impl{PDMIMOUSEPORT, pfnPutEventMultiTouch}
1560 */
1561static DECLCALLBACK(int) kbdMousePutEventMultiTouch(PPDMIMOUSEPORT pInterface,
1562 uint8_t cContacts,
1563 const uint64_t *pau64Contacts,
1564 uint32_t u32ScanTime)
1565{
1566 AssertFailedReturn(VERR_NOT_SUPPORTED);
1567 NOREF(pInterface); NOREF(cContacts); NOREF(pau64Contacts); NOREF(u32ScanTime);
1568}
1569#endif
1570
1571/* -=-=-=-=-=- real code -=-=-=-=-=- */
1572
1573
1574/**
1575 * Attach command.
1576 *
1577 * This is called to let the device attach to a driver for a specified LUN
1578 * during runtime. This is not called during VM construction, the device
1579 * constructor have to attach to all the available drivers.
1580 *
1581 * This is like plugging in the keyboard or mouse after turning on the PC.
1582 *
1583 * @returns VBox status code.
1584 * @param pDevIns The device instance.
1585 * @param iLUN The logical unit which is being detached.
1586 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1587 * @remark The keyboard controller doesn't support this action, this is just
1588 * implemented to try out the driver<->device structure.
1589 */
1590static DECLCALLBACK(int) kbdAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1591{
1592 int rc;
1593 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1594
1595 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
1596 ("PS/2 device does not support hotplugging\n"),
1597 VERR_INVALID_PARAMETER);
1598
1599 switch (iLUN)
1600 {
1601 /* LUN #0: keyboard */
1602 case 0:
1603 rc = PS2KAttach(&pThis->Kbd, pDevIns, iLUN, fFlags);
1604 if (RT_FAILURE(rc))
1605 return rc;
1606 break;
1607
1608 /* LUN #1: aux/mouse */
1609 case 1:
1610#ifdef VBOX_WITH_NEW_PS2M
1611 rc = PS2MAttach(&pThis->Aux, pDevIns, iLUN, fFlags);
1612#else
1613 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Mouse.IBase, &pThis->Mouse.pDrvBase, "Aux (Mouse) Port");
1614 if (RT_SUCCESS(rc))
1615 {
1616 pThis->Mouse.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Mouse.pDrvBase, PDMIMOUSECONNECTOR);
1617 if (!pThis->Mouse.pDrv)
1618 {
1619 AssertLogRelMsgFailed(("LUN #1 doesn't have a mouse interface! rc=%Rrc\n", rc));
1620 rc = VERR_PDM_MISSING_INTERFACE;
1621 }
1622 }
1623 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1624 {
1625 Log(("%s/%d: warning: no driver attached to LUN #1!\n", pDevIns->pReg->szName, pDevIns->iInstance));
1626 rc = VINF_SUCCESS;
1627 }
1628 else
1629 AssertLogRelMsgFailed(("Failed to attach LUN #1! rc=%Rrc\n", rc));
1630#endif
1631 break;
1632
1633 default:
1634 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1635 return VERR_PDM_NO_SUCH_LUN;
1636 }
1637
1638 return rc;
1639}
1640
1641
1642/**
1643 * Detach notification.
1644 *
1645 * This is called when a driver is detaching itself from a LUN of the device.
1646 * The device should adjust it's state to reflect this.
1647 *
1648 * This is like unplugging the network cable to use it for the laptop or
1649 * something while the PC is still running.
1650 *
1651 * @param pDevIns The device instance.
1652 * @param iLUN The logical unit which is being detached.
1653 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1654 * @remark The keyboard controller doesn't support this action, this is just
1655 * implemented to try out the driver<->device structure.
1656 */
1657static DECLCALLBACK(void) kbdDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1658{
1659#if 0
1660 /*
1661 * Reset the interfaces and update the controller state.
1662 */
1663 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1664 switch (iLUN)
1665 {
1666 /* LUN #0: keyboard */
1667 case 0:
1668 pThis->Keyboard.pDrv = NULL;
1669 pThis->Keyboard.pDrvBase = NULL;
1670 break;
1671
1672 /* LUN #1: aux/mouse */
1673 case 1:
1674 pThis->Mouse.pDrv = NULL;
1675 pThis->Mouse.pDrvBase = NULL;
1676 break;
1677
1678 default:
1679 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1680 break;
1681 }
1682#else
1683 NOREF(pDevIns); NOREF(iLUN); NOREF(fFlags);
1684#endif
1685}
1686
1687
1688/**
1689 * @copydoc FNPDMDEVRELOCATE
1690 */
1691static DECLCALLBACK(void) kbdRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1692{
1693 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1694 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1695 PS2KRelocate(&pThis->Kbd, offDelta, pDevIns);
1696#ifdef VBOX_WITH_NEW_PS2M
1697 PS2MRelocate(&pThis->Aux, offDelta, pDevIns);
1698#endif
1699}
1700
1701
1702/**
1703 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1704 */
1705static DECLCALLBACK(int) kbdConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1706{
1707 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1708 int rc;
1709 bool fGCEnabled;
1710 bool fR0Enabled;
1711 Assert(iInstance == 0);
1712
1713 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1714
1715 /*
1716 * Validate and read the configuration.
1717 */
1718 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0R0Enabled\0"))
1719 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1720 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
1721 if (RT_FAILURE(rc))
1722 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"GCEnabled\" from the config"));
1723 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1724 if (RT_FAILURE(rc))
1725 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"R0Enabled\" from the config"));
1726 Log(("pckbd: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
1727
1728
1729 /*
1730 * Initialize the interfaces.
1731 */
1732 pThis->pDevInsR3 = pDevIns;
1733 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1734 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1735
1736 rc = PS2KConstruct(&pThis->Kbd, pDevIns, pThis, iInstance);
1737 if (RT_FAILURE(rc))
1738 return rc;
1739
1740#ifdef VBOX_WITH_NEW_PS2M
1741 rc = PS2MConstruct(&pThis->Aux, pDevIns, pThis, iInstance);
1742 if (RT_FAILURE(rc))
1743 return rc;
1744#else
1745 pThis->Mouse.IBase.pfnQueryInterface = kbdMouseQueryInterface;
1746 pThis->Mouse.IPort.pfnPutEvent = kbdMousePutEvent;
1747 pThis->Mouse.IPort.pfnPutEventAbs = kbdMousePutEventAbs;
1748 pThis->Mouse.IPort.pfnPutEventMultiTouch = kbdMousePutEventMultiTouch;
1749#endif
1750
1751 /*
1752 * Register I/O ports, save state, keyboard event handler and mouse event handlers.
1753 */
1754 rc = PDMDevHlpIOPortRegister(pDevIns, 0x60, 1, NULL, kbdIOPortDataWrite, kbdIOPortDataRead, NULL, NULL, "PC Keyboard - Data");
1755 if (RT_FAILURE(rc))
1756 return rc;
1757 rc = PDMDevHlpIOPortRegister(pDevIns, 0x64, 1, NULL, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL, NULL, "PC Keyboard - Command / Status");
1758 if (RT_FAILURE(rc))
1759 return rc;
1760 if (fGCEnabled)
1761 {
1762 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1763 if (RT_FAILURE(rc))
1764 return rc;
1765 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1766 if (RT_FAILURE(rc))
1767 return rc;
1768 }
1769 if (fR0Enabled)
1770 {
1771 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1772 if (RT_FAILURE(rc))
1773 return rc;
1774 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1775 if (RT_FAILURE(rc))
1776 return rc;
1777 }
1778 rc = PDMDevHlpSSMRegisterEx(pDevIns, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
1779 NULL, NULL, NULL,
1780 NULL, kbdSaveExec, NULL,
1781 NULL, kbdLoadExec, kbdLoadDone);
1782 if (RT_FAILURE(rc))
1783 return rc;
1784
1785 /*
1786 * Attach to the keyboard and mouse drivers.
1787 */
1788 rc = kbdAttach(pDevIns, 0 /* keyboard LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1789 if (RT_FAILURE(rc))
1790 return rc;
1791 rc = kbdAttach(pDevIns, 1 /* aux/mouse LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1792 if (RT_FAILURE(rc))
1793 return rc;
1794
1795 /*
1796 * Initialize the device state.
1797 */
1798 kbdReset(pDevIns);
1799
1800 return VINF_SUCCESS;
1801}
1802
1803
1804/**
1805 * The device registration structure.
1806 */
1807const PDMDEVREG g_DevicePS2KeyboardMouse =
1808{
1809 /* u32Version */
1810 PDM_DEVREG_VERSION,
1811 /* szName */
1812 "pckbd",
1813 /* szRCMod */
1814 "VBoxDDRC.rc",
1815 /* szR0Mod */
1816 "VBoxDDR0.r0",
1817 /* pszDescription */
1818 "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller. "
1819 "LUN #0 is the keyboard connector. "
1820 "LUN #1 is the aux/mouse connector.",
1821 /* fFlags */
1822 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,
1823 /* fClass */
1824 PDM_DEVREG_CLASS_INPUT,
1825 /* cMaxInstances */
1826 1,
1827 /* cbInstance */
1828 sizeof(KBDState),
1829 /* pfnConstruct */
1830 kbdConstruct,
1831 /* pfnDestruct */
1832 NULL,
1833 /* pfnRelocate */
1834 kbdRelocate,
1835 /* pfnMemSetup */
1836 NULL,
1837 /* pfnPowerOn */
1838 NULL,
1839 /* pfnReset */
1840 kbdReset,
1841 /* pfnSuspend */
1842 NULL,
1843 /* pfnResume */
1844 NULL,
1845 /* pfnAttach */
1846 kbdAttach,
1847 /* pfnDetach */
1848 kbdDetach,
1849 /* pfnQueryInterface. */
1850 NULL,
1851 /* pfnInitComplete */
1852 NULL,
1853 /* pfnPowerOff */
1854 NULL,
1855 /* pfnSoftReset */
1856 NULL,
1857 /* u32VersionEnd */
1858 PDM_DEVREG_VERSION
1859};
1860
1861#endif /* IN_RING3 */
1862#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1863
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