From: Jean Guyader Date: Wed, 3 Dec 2008 17:05:13 +0000 (+0000) Subject: Add keyboard pass through ioemu frontend. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=8670ca7a744fccda611f93df18e18965d20f9de1;p=xenclient%2Fioemu.git Add keyboard pass through ioemu frontend. --- diff --git a/hw/pc.c b/hw/pc.c index 3c4f8985..49a83364 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -54,6 +54,7 @@ static IOAPICState *ioapic; static PCIDevice *i440fx_state; extern int vga_passthrough; +extern int kbd_passthrough; static void xen_relocator_hook(target_phys_addr_t *prot_addr_upd, uint16_t protocol, @@ -1063,7 +1064,10 @@ vga_bios_error: tpm_tis_init(&i8259[11]); #endif - i8042_init(i8259[1], i8259[12], 0x60); + if (kbd_passthrough) + pt_i8042_init(i8259[1], i8259[12], 0x60); + else + i8042_init(i8259[1], i8259[12], 0x60); DMA_init(0); #ifdef HAS_AUDIO audio_init(pci_enabled ? pci_bus : NULL, i8259); diff --git a/hw/pc.h b/hw/pc.h index 7628422e..55cf3199 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -75,6 +75,8 @@ void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_phys_addr_t base, int it_shift); +void pt_i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); + /* mc146818rtc.c */ typedef struct RTCState RTCState; diff --git a/hw/pt_pckbd.c b/hw/pt_pckbd.c new file mode 100644 index 00000000..2b3be315 --- /dev/null +++ b/hw/pt_pckbd.c @@ -0,0 +1,314 @@ +/* + * QEMU PC keyboard emulation + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw.h" +#include "isa.h" +#include "pc.h" +#include "ps2.h" +#include "sysemu.h" + +#include "qemu-common.h" +#include "console.h" +#include "qemu-timer.h" +#include "qemu-xen.h" + +#include +#include +#include + +/* debug PC keyboard */ +//#define DEBUG_KBD + +#ifdef DEBUG_KBD +# define DPRINTF(_f, _a...) fprintf(stderr, __FILE__ ":%d: " _f, __LINE__, ##_a) +#else +# define DPRINTF(_f, _a...) (void(0)) +#endif + +/* Keyboard Controller Commands */ +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ +#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ +#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ +#define KBD_CCMD_WRITE_OBUF 0xD2 +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ +#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ +#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ +#define KBD_CCMD_RESET 0xFE + +/* Keyboard Commands */ +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_ECHO 0xEE +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* Keyboard Replies */ +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* Status Register Bits */ +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +/* Controller Mode Register Bits */ +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* Mouse Commands */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_POLL 0xEB /* Poll */ +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ +#define AUX_GET_TYPE 0xF2 /* Get type */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_SET_DEFAULT 0xF6 +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define MOUSE_STATUS_REMOTE 0x40 +#define MOUSE_STATUS_ENABLED 0x20 +#define MOUSE_STATUS_SCALE21 0x10 + +#define KBD_QUEUE_SIZE 256 + +#define KBD_PENDING_KBD 1 +#define KBD_PENDING_AUX 2 + +#define PS2BACK_FILE "/proc/xen/ps2back_" + +#define KBD_BUFF_SIZE 128 + +typedef struct KBDState { + /* Bitmask of devices with data available. */ + uint8_t pending_irq; + uint8_t current_irq; + int aux_fd, kbd_fd; + qemu_irq irq_kbd; + qemu_irq irq_mouse; + +} KBDState; + +KBDState kbd_state; + +static void kbd_host_kbd_read_data(void *opaque); +static void kbd_host_aux_read_data(void *opaque); + +static void kbd_update_irq(void *opaque) +{ + KBDState *s = (KBDState *)opaque; + + if (s->current_irq == 0) + { + if (s->pending_irq & KBD_PENDING_KBD) + { + s->current_irq = KBD_PENDING_KBD; + qemu_set_fd_handler(s->kbd_fd, NULL, NULL, s); + qemu_set_irq(s->irq_kbd, 1); + } + else if (s->pending_irq & KBD_PENDING_AUX) + { + s->current_irq = KBD_PENDING_AUX; + qemu_set_fd_handler(s->aux_fd, NULL, NULL, s); + qemu_set_irq(s->irq_mouse, 1); + } + } + else + { + if (s->current_irq == KBD_PENDING_KBD) + { + qemu_set_irq(s->irq_kbd, 0); + qemu_set_fd_handler(s->kbd_fd, kbd_host_kbd_read_data, NULL, s); + } + else if (s->current_irq == KBD_PENDING_AUX) + { + qemu_set_irq(s->irq_mouse, 0); + qemu_set_fd_handler(s->aux_fd, kbd_host_aux_read_data, NULL, s); + } + s->current_irq = 0; + s->pending_irq = 0; + } +} + +static void kbd_update_aux_irq(void *opaque, int level) +{ + KBDState *s = (KBDState *)opaque; + + qemu_set_irq(s->irq_mouse, level); +} + +static uint32_t kbd_read_status(void *opaque, uint32_t addr) +{ + KBDState *s = opaque; + uint32_t val; + int fd; + + if (s->current_irq & KBD_PENDING_AUX) + fd = s->aux_fd; + else + fd = s->kbd_fd; + + ioctl(fd, IOCTL_PS2BACK_READ_CMD, &val); + + DPRINTF("kbd: read cmd=0x%02x, current_irq=0x%x\n", val, s->current_irq); + return val; +} + +static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) +{ + KBDState *s = opaque; + int fd; + + DPRINTF("kbd: write cmd=0x%02x\n", val); + if (val == KBD_CCMD_WRITE_AUX_OBUF || val == KBD_CCMD_WRITE_MOUSE) + fd = s->aux_fd; + else + fd = s->kbd_fd; + + if (ioctl(fd, IOCTL_PS2BACK_WRITE_CMD, &val)) + DPRINTF("kbd: ps2back_ioctl_write_command failed\n"); +} + +static uint32_t kbd_read_data(void *opaque, uint32_t addr) +{ + KBDState *s = opaque; + int fd; + uint8_t val = 0; + + if (s->current_irq == 0 || s->current_irq == KBD_PENDING_KBD) + fd = s->kbd_fd; + else + fd = s->aux_fd; + + read(fd, &val, 1); + DPRINTF("kbd: read data=0x%02x, current_irq=0x%x\n", val, s->current_irq); + + kbd_update_irq(s); + return val; +} + +static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) +{ + KBDState *s = opaque; + + DPRINTF("kbd: write data=0x%02x\n", val); + + if (ioctl(s->kbd_fd, IOCTL_PS2BACK_WRITE_DATA, &val)) + DPRINTF("kbd: ps2back_ioctl_write_data failed\n"); +} + +static void kbd_host_kbd_read_data(void *opaque) +{ + KBDState *s = opaque; + + DPRINTF("Some data to read from the kbd ...\n"); + + s->pending_irq |= KBD_PENDING_KBD; + kbd_update_irq(s); +} + +static void kbd_host_aux_read_data(void *opaque) +{ + KBDState *s = opaque; + + DPRINTF("Some data to read from the aux ...\n"); + + s->pending_irq |= KBD_PENDING_AUX; + kbd_update_irq(s); +} + +void pt_i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base) +{ + KBDState *s = &kbd_state; + int rc; + + memset(s, 0, sizeof (*s)); + + s->irq_kbd = kbd_irq; + s->irq_mouse = mouse_irq; + + register_ioport_read(io_base, 1, 1, kbd_read_data, s); + register_ioport_write(io_base, 1, 1, kbd_write_data, s); + register_ioport_read(io_base + 4, 1, 1, kbd_read_status, s); + register_ioport_write(io_base + 4, 1, 1, kbd_write_command, s); + + s->kbd_fd = open(PS2BACK_FILE "kbd", O_RDONLY); + if (s->kbd_fd < 0) + { + DPRINTF("kbd: failed to open the proc file\n"); + exit(2); + } + if ((rc = ioctl(s->kbd_fd, IOCTL_PS2BACK_GRAB, 1))) + { + DPRINTF("kbd: failed to grab %d\n", rc); + exit(2); + } + s->aux_fd = open(PS2BACK_FILE "aux", O_RDONLY); + if (s->aux_fd < 0) + { + DPRINTF("kbd: failed to open the proc file\n"); + exit(2); + } + if ((rc = ioctl(s->aux_fd, IOCTL_PS2BACK_GRAB, 1))) + { + DPRINTF("kbd: failed to grab %d\n", rc); + exit(2); + } + + qemu_set_fd_handler(s->kbd_fd, kbd_host_kbd_read_data, NULL, s); + qemu_set_fd_handler(s->aux_fd, kbd_host_aux_read_data, NULL, s); +} diff --git a/vl.c b/vl.c index 9491b070..1b98273a 100644 --- a/vl.c +++ b/vl.c @@ -211,6 +211,7 @@ int opengl_enabled = 0; #endif const char *dom0_input = NULL; int vga_passthrough = 0; +int kbd_passthrough = 0; char *intel_output = NULL; static const char *direct_pci; static int nb_pci_emulation = 0; @@ -7554,6 +7555,7 @@ enum { QEMU_OPTION_disable_opengl, QEMU_OPTION_dom0_input, QEMU_OPTION_vga_passthrough, + QEMU_OPTION_kbd_passthrough, QEMU_OPTION_direct_pci, QEMU_OPTION_pci_emulation, QEMU_OPTION_vcpus, @@ -7669,6 +7671,7 @@ const QEMUOption qemu_options[] = { #endif { "dom0-input", 1, QEMU_OPTION_dom0_input }, { "vga-passthrough", 0, QEMU_OPTION_vga_passthrough }, + { "kbd-passthrough", 0, QEMU_OPTION_kbd_passthrough }, { "vcpus", 1, QEMU_OPTION_vcpus }, { "acpi", 0, QEMU_OPTION_acpi }, /* deprecated, for xend compatibility */ { "direct_pci", HAS_ARG, QEMU_OPTION_direct_pci }, @@ -8458,6 +8461,9 @@ int main(int argc, char **argv) case QEMU_OPTION_vga_passthrough: vga_passthrough = 1; break; + case QEMU_OPTION_kbd_passthrough: + kbd_passthrough = 1; + break; case QEMU_OPTION_direct_pci: direct_pci = optarg; break; diff --git a/xen-hooks.mak b/xen-hooks.mak index e8745528..ac3c925c 100644 --- a/xen-hooks.mak +++ b/xen-hooks.mak @@ -33,6 +33,7 @@ OBJS += xen_machine_fv.o OBJS += exec-dm.o OBJS += pci_emulation.o OBJS += battery_mgmt.o +OBJS += pt_pckbd.o ifdef CONFIG_STUBDOM CPPFLAGS += $(TARGET_CPPFLAGS)