DevPS2.cpp revision 15f3cc0e31052bd293b0c9092d2dcd76a0aaae8f
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* $Id: $ */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * DevPS2 - PS/2 keyboard & mouse controller device.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * available from http://www.virtualbox.org. This file is free software;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * General Public License (GPL) as published by the Free Software
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * additional information or have any questions.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * --------------------------------------------------------------------
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * This code is based on:
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * QEMU PC keyboard emulation (revision 1.12)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Copyright (c) 2003 Fabrice Bellard
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Permission is hereby granted, free of charge, to any person obtaining a copy
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * of this software and associated documentation files (the "Software"), to deal
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * in the Software without restriction, including without limitation the rights
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * copies of the Software, and to permit persons to whom the Software is
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * furnished to do so, subject to the following conditions:
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * The above copyright notice and this permission notice shall be included in
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * all copies or substantial portions of the Software.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * THE SOFTWARE.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/*******************************************************************************
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync* Header Files *
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync*******************************************************************************/
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/*******************************************************************************
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync* Internal Functions *
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync*******************************************************************************/
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncPDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncPDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncPDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncPDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* debug PC keyboard */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* debug PC keyboard : only mouse */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* Keyboard Controller Commands */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync initiated by the auxiliary device */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CCMD_READ_TSTINP 0xE0 /* Read test inputs T0, T1 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* Keyboard Commands */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* Keyboard Replies */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* Status Register Bits */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* Controller Mode Register Bits */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* Mouse Commands */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsynctypedef struct {
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsynctypedef struct {
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsynctypedef struct {
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsynctypedef struct KBDState {
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* keyboard state */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* mouse state */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync int32_t mouse_dx; /* current values, needed for 'poll' mode */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** Pointer to the device instance - RC. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** Pointer to the device instance - R3 . */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** Pointer to the device instance. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** Critical section protecting the state. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Keyboard port - LUN#0.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** The base interface for the keyboard port. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** The keyboard port base interface. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** The base interface of the attached keyboard driver. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** The keyboard interface of the attached keyboard driver. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Mouse port - LUN#1.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** The base interface for the mouse port. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** The mouse port base interface. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** The base interface of the attached mouse driver. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** The mouse interface of the attached mouse driver. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* update irq and KBD_STAT_[MOUSE_]OBF */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync incorrect, but it avoids having to simulate exact delays */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if (q->count != 0)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if ((s->mode & KBD_MODE_KBD_INT) && !(s->mode & KBD_MODE_DISABLE_KBD))
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if (q->count != 0) {
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 1, irq1_level);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 12, irq12_level);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync case 0: /* keyboard */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic void pc_kbd_put_keycode(void *opaque, int keycode)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic uint32_t kbd_read_status(void *opaque, uint32_t addr)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* VBOX (we need VMReset return code passed back) */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic int kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* XXX: check that */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync val = 0x01 | (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) << 1);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# else /* IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# endif /* IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# else /* IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# endif /* !IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* Keyboard clock line is zero IFF keyboard is disabled */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# else /* IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# endif /* !IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* ignore that - I don't know what is its use */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* The 8042 RAM is readble using commands 0x20 thru 0x3f, and writable
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync by 0x60 thru 0x7f. Now days only the firs byte, the mode, is used.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync We'll ignore the writes (0x61..7f) and return 0 for all the reads
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync just to make some OS/2 debug stuff a bit happier. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync Log(("kbd: reading non-standard RAM addr %#x\n", val & 0x1f));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync Log(("kbd: unsupported keyboard cmd=0x%02x\n", val));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic uint32_t kbd_read_data(void *opaque, uint32_t addr)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if (q->count == 0 && mcq->count == 0 && meq->count == 0) {
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if (q->count == 0) {
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* NOTE: if no data left, we return the last keyboard one
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync (needed for EMM386) */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* XXX: need a timer to do things correctly */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* reading deasserts IRQ */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* reassert IRQs if data left */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic void kbd_write_keyboard(KBDState *s, int val)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync s->Keyboard.pDrv->pfnLedStatusChange(s->Keyboard.pDrv, enmLeds);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic void kbd_mouse_send_packet(KBDState *s, bool fToCmdQueue)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync unsigned int b;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* XXX: increase range to 8 bits ? */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* extra byte for IMPS/2 or IMEX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* update deltas */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* check if deltas are recorded when disabled */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* XXX: SDL sometimes generates nul events: we delete them */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* This issue does not affect VBox, and under some circumstances (which?)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * we may wish to send null events to make mouse integration work. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync (s->mouse_event_queue.count < (MOUSE_EVENT_QUEUE_SIZE - 4))) {
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* if not remote, send event. Multiple events are sent if
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync too big deltas */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* if not remote, send event. Multiple events are sent if
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync too big deltas */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* Flush the mouse command response queue. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* mouse command */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* !VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* Flush the mouse events queue. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* Flush the mouse events queue. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* NACK all commands we don't know.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync The usecase for this is the OS/2 mouse driver which will try
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync read 0xE2 in order to figure out if it's a trackpoint device
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync or not. If it doesn't get a NACK (or ACK) on the command it'll
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync do several hundred thousand status reads before giving up. This
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync is slows down the OS/2 boot up considerably. (It also seems that
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync the code is somehow vulnerable while polling like this and that
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync mouse or keyboard input at this point might screw things up badly.)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync From http://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html:
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync Every command or data byte sent to the mouse (except for the
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync resend command fe) is ACKed with fa. If the command or data
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync is invalid, it is NACKed with fe. If the next byte is again
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync invalid, the reply is ERROR: fc. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /** @todo send error if we NACKed the previous command? */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* detect IMPS/2 or IMEX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsyncstatic int kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) != !!(val & 2))
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# else /* IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), !!(val & 2));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# endif /* !IN_RING3 */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync# endif /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#else /* VBOX */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#endif /* VBOX */
s->write_cmd = 0;
s->scan_enabled = 0;
s->mouse_status = 0;
s->mouse_resolution = 0;
s->mouse_sample_rate = 0;
s->mouse_wrap = 0;
s->mouse_type = 0;
s->mouse_detect_state = 0;
s->mouse_dx = 0;
s->mouse_dy = 0;
s->mouse_dz = 0;
s->mouse_buttons = 0;
q = &s->queue;
q->rptr = 0;
q->wptr = 0;
q->count = 0;
#ifdef VBOX
#ifdef VBOX
#ifdef VBOX
for (i = s->mouse_command_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_command_queue.data))
for (i = s->mouse_event_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_event_queue.data))
SSMR3PutU32(f, ~0);
#ifdef VBOX
int rc;
#ifndef VBOX
return -EINVAL;
#ifdef VBOX
return rc;
for (i = 0; i < u32; i++)
return rc;
return rc;
for (i = 0; i < u32; i++)
return rc;
return rc;
for (i = 0; i < u32; i++)
return rc;
return rc;
if (u32 != ~0U)
#ifndef VBOX
void kbd_init(void)
kbd_reset(s);
PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
return rc;
return VERR_IOM_IOPORT_UNUSED;
PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
return rc;
PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
return rc;
return VERR_IOM_IOPORT_UNUSED;
PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
return rc;
#ifdef IN_RING3
return VINF_SUCCESS;
static DECLCALLBACK(int) kbdLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
static DECLCALLBACK(void *) kbdKeyboardQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
switch (enmInterface)
case PDMINTERFACE_BASE:
return NULL;
#define IKEYBOARDPORT_2_KBDSTATE(pInterface) ( (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Keyboard.Port)) )
return VINF_SUCCESS;
switch (enmInterface)
case PDMINTERFACE_BASE:
case PDMINTERFACE_MOUSE_PORT:
return NULL;
#define IMOUSEPORT_2_KBDSTATE(pInterface) ( (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Mouse.Port)) )
static DECLCALLBACK(int) kbdMousePutEvent(PPDMIMOUSEPORT pInterface, int32_t i32DeltaX, int32_t i32DeltaY, int32_t i32DeltaZ, uint32_t fButtonStates)
return VINF_SUCCESS;
int rc;
switch (iLUN)
rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Keyboard.Base, &pThis->Keyboard.pDrvBase, "Keyboard Port");
pThis->Keyboard.pDrv = (PDMIKEYBOARDCONNECTOR*)(pThis->Keyboard.pDrvBase->pfnQueryInterface(pThis->Keyboard.pDrvBase, PDMINTERFACE_KEYBOARD_CONNECTOR));
Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Mouse.Base, &pThis->Mouse.pDrvBase, "Aux (Mouse) Port");
pThis->Mouse.pDrv = (PDMIMOUSECONNECTOR*)(pThis->Mouse.pDrvBase->pfnQueryInterface(pThis->Mouse.pDrvBase, PDMINTERFACE_MOUSE_CONNECTOR));
Log(("%s/%d: warning: no driver attached to LUN #1!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
return VERR_PDM_NO_SUCH_LUN;
return rc;
switch (iLUN)
return VINF_SUCCESS;
int rc;
bool fGCEnabled;
bool fR0Enabled;
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x60, 1, NULL, kbdIOPortDataWrite, kbdIOPortDataRead, NULL, NULL, "PC Keyboard - Data");
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x64, 1, NULL, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL, NULL, "PC Keyboard - Command / Status");
return rc;
if (fGCEnabled)
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
return rc;
rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
return rc;
if (fR0Enabled)
rc = pDevIns->pDevHlpR3->pfnIOPortRegisterR0(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
return rc;
rc = pDevIns->pDevHlpR3->pfnIOPortRegisterR0(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
return rc;
rc = PDMDevHlpSSMRegister(pDevIns, g_DevicePS2KeyboardMouse.szDeviceName, iInstance, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis),
return rc;
return rc;
return rc;
return VINF_SUCCESS;
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,
sizeof(KBDState),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,