VirtualBox

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

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

Devices/Input/DevPS2.cpp: eliminate use of vl_vbox.h

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