]> xenbits.xensource.com Git - xenclient/ioemu.git/commitdiff
Add keyboard pass through ioemu frontend.
authorJean Guyader <jean.guyader@eu.citrix.com>
Wed, 3 Dec 2008 17:05:13 +0000 (17:05 +0000)
committerJean Guyader <jean.guyader@eu.citrix.com>
Wed, 3 Dec 2008 17:08:51 +0000 (17:08 +0000)
hw/pc.c
hw/pc.h
hw/pt_pckbd.c [new file with mode: 0644]
vl.c
xen-hooks.mak

diff --git a/hw/pc.c b/hw/pc.c
index 3c4f8985726feb6d09267c91ed7ec32078239066..49a833640333e83b94c7513a7ee1ce10a95b5cfa 100644 (file)
--- 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 7628422e8084844285a2a84f55e1f3002eeeaa12..55cf3199b66eb118cf4441b0e3b9b324c7bf351b 100644 (file)
--- 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 (file)
index 0000000..2b3be31
--- /dev/null
@@ -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 <xen/sys/ps2back.h>
+#include <sys/ioctl.h>
+#include <assert.h>
+
+/* 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 9491b070f68c3b6ac10f53dce5962beb15700774..1b98273a29bf77a1e8a25db24a063bd012385d1a 100644 (file)
--- 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;
index e87455285d64133f1b9e0a86dc1cafa0c8d4a4aa..ac3c925c5b3f23481512b67e8ac18d78ccb62332 100644 (file)
@@ -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)