VirtualBox

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

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

DevPS2: Release keys after restoring saved state, not while loading it.

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