qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [patch] Split PS2 emulation from PC keyboard controller


From: Paul Brook
Subject: [Qemu-devel] [patch] Split PS2 emulation from PC keyboard controller
Date: Sun, 6 Nov 2005 16:15:56 +0000
User-agent: KMail/1.8.2

The attached patch splits the PS/2 device emulation from the PC keyboard 
controller emulation.  The Arm board I'm working on uses PS/2 keyboard+mouse 
with a custom host controller.

Paul
Index: vl.h
===================================================================
RCS file: /cvsroot/qemu/qemu/vl.h,v
retrieving revision 1.83
diff -u -p -r1.83 vl.h
--- vl.h        30 Oct 2005 18:58:21 -0000      1.83
+++ vl.h        6 Nov 2005 15:53:43 -0000
@@ -859,6 +859,14 @@ void adb_mouse_init(ADBBusState *bus);
 extern ADBBusState adb_bus;
 int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq);
 
+/* ps2.c */
+typedef struct PS2State PS2State;
+PS2State *ps2_init(void (*update_irq)(void *, int, int), void *update_arg);
+void ps2_write_mouse(PS2State *s, int val);
+void ps2_write_keyboard(PS2State *s, int val);
+uint32_t ps2_read_data(PS2State *s);
+void ps2_queue(PS2State *s, int b, int aux);
+
 #endif /* defined(QEMU_TOOL) */
 
 /* monitor.c */
Index: hw/pckbd.c
===================================================================
RCS file: /cvsroot/qemu/qemu/hw/pckbd.c,v
retrieving revision 1.11
diff -u -p -r1.11 pckbd.c
--- hw/pckbd.c  27 Jan 2005 22:32:51 -0000      1.11
+++ hw/pckbd.c  6 Nov 2005 15:53:43 -0000
@@ -110,32 +110,13 @@
 
 #define KBD_QUEUE_SIZE 256
 
-typedef struct {
-    uint8_t aux[KBD_QUEUE_SIZE];
-    uint8_t data[KBD_QUEUE_SIZE];
-    int rptr, wptr, count;
-} KBDQueue;
-
 typedef struct KBDState {
-    KBDQueue queue;
     uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
     uint8_t status;
     uint8_t mode;
-    /* keyboard state */
-    int kbd_write_cmd;
-    int scan_enabled;
-    /* mouse state */
-    int mouse_write_cmd;
-    uint8_t mouse_status;
-    uint8_t mouse_resolution;
-    uint8_t mouse_sample_rate;
-    uint8_t mouse_wrap;
-    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
-    uint8_t mouse_detect_state;
-    int mouse_dx; /* current values, needed for 'poll' mode */
-    int mouse_dy;
-    int mouse_dz;
-    uint8_t mouse_buttons;
+    int pending;
+    int pending_aux;
+    PS2State *ps2;
 } KBDState;
 
 KBDState kbd_state;
@@ -143,17 +124,17 @@ KBDState kbd_state;
 /* update irq and KBD_STAT_[MOUSE_]OBF */
 /* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
    incorrect, but it avoids having to simulate exact delays */
-static void kbd_update_irq(KBDState *s)
+static void kbd_update_irq(void *opaque, int aux, int level)
 {
-    KBDQueue *q = &s->queue;
+    KBDState *s = (KBDState *)opaque;
     int irq12_level, irq1_level;
 
     irq1_level = 0;    
     irq12_level = 0;    
     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
-    if (q->count != 0) {
+    if (level) {
         s->status |= KBD_STAT_OBF;
-        if (q->aux[q->rptr]) {
+        if (aux) {
             s->status |= KBD_STAT_MOUSE_OBF;
             if (s->mode & KBD_MODE_MOUSE_INT)
                 irq12_level = 1;
@@ -163,38 +144,12 @@ static void kbd_update_irq(KBDState *s)
                 irq1_level = 1;
         }
     }
+    s->pending = level;
+    s->pending_aux = aux;
     pic_set_irq(1, irq1_level);
     pic_set_irq(12, irq12_level);
 }
 
-static void kbd_queue(KBDState *s, int b, int aux)
-{
-    KBDQueue *q = &s->queue;
-
-#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
-    if (aux)
-        printf("mouse event: 0x%02x\n", b);
-#ifdef DEBUG_KBD
-    else
-        printf("kbd event: 0x%02x\n", b);
-#endif
-#endif
-    if (q->count >= KBD_QUEUE_SIZE)
-        return;
-    q->aux[q->wptr] = aux;
-    q->data[q->wptr] = b;
-    if (++q->wptr == KBD_QUEUE_SIZE)
-        q->wptr = 0;
-    q->count++;
-    kbd_update_irq(s);
-}
-
-static void pc_kbd_put_keycode(void *opaque, int keycode)
-{
-    KBDState *s = opaque;
-    kbd_queue(s, keycode, 0);
-}
-
 static uint32_t kbd_read_status(void *opaque, uint32_t addr)
 {
     KBDState *s = opaque;
@@ -206,6 +161,11 @@ static uint32_t kbd_read_status(void *op
     return val;
 }
 
+static void kbd_queue(KBDState *s, int b, int aux)
+{
+    ps2_queue(s->ps2, b, aux);
+}
+
 static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
 {
     KBDState *s = opaque;
@@ -242,11 +202,11 @@ static void kbd_write_command(void *opaq
         break;
     case KBD_CCMD_KBD_DISABLE:
         s->mode |= KBD_MODE_DISABLE_KBD;
-        kbd_update_irq(s);
+        kbd_update_irq(s, s->pending_aux, s->pending);
         break;
     case KBD_CCMD_KBD_ENABLE:
         s->mode &= ~KBD_MODE_DISABLE_KBD;
-        kbd_update_irq(s);
+        kbd_update_irq(s, s->pending_aux, s->pending);
         break;
     case KBD_CCMD_READ_INPORT:
         kbd_queue(s, 0x00, 0);
@@ -287,304 +247,8 @@ static void kbd_write_command(void *opaq
 static uint32_t kbd_read_data(void *opaque, uint32_t addr)
 {
     KBDState *s = opaque;
-    KBDQueue *q;
-    int val, index, aux;
-    
-    q = &s->queue;
-    if (q->count == 0) {
-        /* NOTE: if no data left, we return the last keyboard one
-           (needed for EMM386) */
-        /* XXX: need a timer to do things correctly */
-        index = q->rptr - 1;
-        if (index < 0)
-            index = KBD_QUEUE_SIZE - 1;
-        val = q->data[index];
-    } else {
-        aux = q->aux[q->rptr];
-        val = q->data[q->rptr];
-        if (++q->rptr == KBD_QUEUE_SIZE)
-            q->rptr = 0;
-        q->count--;
-        /* reading deasserts IRQ */
-        if (aux)
-            pic_set_irq(12, 0);
-        else
-            pic_set_irq(1, 0);
-    }
-    /* reassert IRQs if data left */
-    kbd_update_irq(s);
-#ifdef DEBUG_KBD
-    printf("kbd: read data=0x%02x\n", val);
-#endif
-    return val;
-}
 
-static void kbd_reset_keyboard(KBDState *s)
-{
-    s->scan_enabled = 1;
-}
-
-static void kbd_write_keyboard(KBDState *s, int val)
-{
-    switch(s->kbd_write_cmd) {
-    default:
-    case -1:
-        switch(val) {
-        case 0x00:
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case 0x05:
-            kbd_queue(s, KBD_REPLY_RESEND, 0);
-            break;
-        case KBD_CMD_GET_ID:
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            kbd_queue(s, 0xab, 0);
-            kbd_queue(s, 0x83, 0);
-            break;
-        case KBD_CMD_ECHO:
-            kbd_queue(s, KBD_CMD_ECHO, 0);
-            break;
-        case KBD_CMD_ENABLE:
-            s->scan_enabled = 1;
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case KBD_CMD_SET_LEDS:
-        case KBD_CMD_SET_RATE:
-            s->kbd_write_cmd = val;
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case KBD_CMD_RESET_DISABLE:
-            kbd_reset_keyboard(s);
-            s->scan_enabled = 0;
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case KBD_CMD_RESET_ENABLE:
-            kbd_reset_keyboard(s);
-            s->scan_enabled = 1;
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case KBD_CMD_RESET:
-            kbd_reset_keyboard(s);
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            kbd_queue(s, KBD_REPLY_POR, 0);
-            break;
-        default:
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        }
-        break;
-    case KBD_CMD_SET_LEDS:
-        kbd_queue(s, KBD_REPLY_ACK, 0);
-        s->kbd_write_cmd = -1;
-        break;
-    case KBD_CMD_SET_RATE:
-        kbd_queue(s, KBD_REPLY_ACK, 0);
-        s->kbd_write_cmd = -1;
-        break;
-    }
-}
-
-static void kbd_mouse_send_packet(KBDState *s)
-{
-    unsigned int b;
-    int dx1, dy1, dz1;
-
-    dx1 = s->mouse_dx;
-    dy1 = s->mouse_dy;
-    dz1 = s->mouse_dz;
-    /* XXX: increase range to 8 bits ? */
-    if (dx1 > 127)
-        dx1 = 127;
-    else if (dx1 < -127)
-        dx1 = -127;
-    if (dy1 > 127)
-        dy1 = 127;
-    else if (dy1 < -127)
-        dy1 = -127;
-    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
-    kbd_queue(s, b, 1);
-    kbd_queue(s, dx1 & 0xff, 1);
-    kbd_queue(s, dy1 & 0xff, 1);
-    /* extra byte for IMPS/2 or IMEX */
-    switch(s->mouse_type) {
-    default:
-        break;
-    case 3:
-        if (dz1 > 127)
-            dz1 = 127;
-        else if (dz1 < -127)
-                dz1 = -127;
-        kbd_queue(s, dz1 & 0xff, 1);
-        break;
-    case 4:
-        if (dz1 > 7)
-            dz1 = 7;
-        else if (dz1 < -7)
-            dz1 = -7;
-        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
-        kbd_queue(s, b, 1);
-        break;
-    }
-
-    /* update deltas */
-    s->mouse_dx -= dx1;
-    s->mouse_dy -= dy1;
-    s->mouse_dz -= dz1;
-}
-
-static void pc_kbd_mouse_event(void *opaque, 
-                               int dx, int dy, int dz, int buttons_state)
-{
-    KBDState *s = opaque;
-
-    /* check if deltas are recorded when disabled */
-    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
-        return;
-
-    s->mouse_dx += dx;
-    s->mouse_dy -= dy;
-    s->mouse_dz += dz;
-    /* XXX: SDL sometimes generates nul events: we delete them */
-    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
-        s->mouse_buttons == buttons_state)
-       return;
-    s->mouse_buttons = buttons_state;
-    
-    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
-        (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
-        for(;;) {
-            /* if not remote, send event. Multiple events are sent if
-               too big deltas */
-            kbd_mouse_send_packet(s);
-            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
-                break;
-        }
-    }
-}
-
-static void kbd_write_mouse(KBDState *s, int val)
-{
-#ifdef DEBUG_MOUSE
-    printf("kbd: write mouse 0x%02x\n", val);
-#endif
-    switch(s->mouse_write_cmd) {
-    default:
-    case -1:
-        /* mouse command */
-        if (s->mouse_wrap) {
-            if (val == AUX_RESET_WRAP) {
-                s->mouse_wrap = 0;
-                kbd_queue(s, AUX_ACK, 1);
-                return;
-            } else if (val != AUX_RESET) {
-                kbd_queue(s, val, 1);
-                return;
-            }
-        }
-        switch(val) {
-        case AUX_SET_SCALE11:
-            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_SCALE21:
-            s->mouse_status |= MOUSE_STATUS_SCALE21;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_STREAM:
-            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_WRAP:
-            s->mouse_wrap = 1;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_REMOTE:
-            s->mouse_status |= MOUSE_STATUS_REMOTE;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_GET_TYPE:
-            kbd_queue(s, AUX_ACK, 1);
-            kbd_queue(s, s->mouse_type, 1);
-            break;
-        case AUX_SET_RES:
-        case AUX_SET_SAMPLE:
-            s->mouse_write_cmd = val;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_GET_SCALE:
-            kbd_queue(s, AUX_ACK, 1);
-            kbd_queue(s, s->mouse_status, 1);
-            kbd_queue(s, s->mouse_resolution, 1);
-            kbd_queue(s, s->mouse_sample_rate, 1);
-            break;
-        case AUX_POLL:
-            kbd_queue(s, AUX_ACK, 1);
-            kbd_mouse_send_packet(s);
-            break;
-        case AUX_ENABLE_DEV:
-            s->mouse_status |= MOUSE_STATUS_ENABLED;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_DISABLE_DEV:
-            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_DEFAULT:
-            s->mouse_sample_rate = 100;
-            s->mouse_resolution = 2;
-            s->mouse_status = 0;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_RESET:
-            s->mouse_sample_rate = 100;
-            s->mouse_resolution = 2;
-            s->mouse_status = 0;
-            s->mouse_type = 0;
-            kbd_queue(s, AUX_ACK, 1);
-            kbd_queue(s, 0xaa, 1);
-            kbd_queue(s, s->mouse_type, 1);
-            break;
-        default:
-            break;
-        }
-        break;
-    case AUX_SET_SAMPLE:
-        s->mouse_sample_rate = val;
-        /* detect IMPS/2 or IMEX */
-        switch(s->mouse_detect_state) {
-        default:
-        case 0:
-            if (val == 200)
-                s->mouse_detect_state = 1;
-            break;
-        case 1:
-            if (val == 100)
-                s->mouse_detect_state = 2;
-            else if (val == 200)
-                s->mouse_detect_state = 3;
-            else
-                s->mouse_detect_state = 0;
-            break;
-        case 2:
-            if (val == 80) 
-                s->mouse_type = 3; /* IMPS/2 */
-            s->mouse_detect_state = 0;
-            break;
-        case 3:
-            if (val == 80) 
-                s->mouse_type = 4; /* IMEX */
-            s->mouse_detect_state = 0;
-            break;
-        }
-        kbd_queue(s, AUX_ACK, 1);
-        s->mouse_write_cmd = -1;
-        break;
-    case AUX_SET_RES:
-        s->mouse_resolution = val;
-        kbd_queue(s, AUX_ACK, 1);
-        s->mouse_write_cmd = -1;
-        break;
-    }
+    return ps2_read_data(s->ps2);
 }
 
 void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
@@ -597,11 +261,12 @@ void kbd_write_data(void *opaque, uint32
 
     switch(s->write_cmd) {
     case 0:
-        kbd_write_keyboard(s, val);
+        ps2_write_keyboard(s->ps2, val);
         break;
     case KBD_CCMD_WRITE_MODE:
         s->mode = val;
-        kbd_update_irq(s);
+        /* ??? */
+        kbd_update_irq(s, s->pending_aux, s->pending);
         break;
     case KBD_CCMD_WRITE_OBUF:
         kbd_queue(s, val, 0);
@@ -618,7 +283,7 @@ void kbd_write_data(void *opaque, uint32
         }
         break;
     case KBD_CCMD_WRITE_MOUSE:
-        kbd_write_mouse(s, val);
+        ps2_write_mouse(s->ps2, val);
         break;
     default:
         break;
@@ -629,16 +294,9 @@ void kbd_write_data(void *opaque, uint32
 static void kbd_reset(void *opaque)
 {
     KBDState *s = opaque;
-    KBDQueue *q;
 
-    s->kbd_write_cmd = -1;
-    s->mouse_write_cmd = -1;
     s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
     s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
-    q = &s->queue;
-    q->rptr = 0;
-    q->wptr = 0;
-    q->count = 0;
 }
 
 static void kbd_save(QEMUFile* f, void* opaque)
@@ -648,6 +306,7 @@ static void kbd_save(QEMUFile* f, void* 
     qemu_put_8s(f, &s->write_cmd);
     qemu_put_8s(f, &s->status);
     qemu_put_8s(f, &s->mode);
+    /*
     qemu_put_be32s(f, &s->kbd_write_cmd);
     qemu_put_be32s(f, &s->scan_enabled);
     qemu_put_be32s(f, &s->mouse_write_cmd);
@@ -661,17 +320,19 @@ static void kbd_save(QEMUFile* f, void* 
     qemu_put_be32s(f, &s->mouse_dy);
     qemu_put_be32s(f, &s->mouse_dz);
     qemu_put_8s(f, &s->mouse_buttons);
+    */
 }
 
 static int kbd_load(QEMUFile* f, void* opaque, int version_id)
 {
     KBDState *s = (KBDState*)opaque;
     
-    if (version_id != 1)
+    if (version_id != 2)
         return -EINVAL;
     qemu_get_8s(f, &s->write_cmd);
     qemu_get_8s(f, &s->status);
     qemu_get_8s(f, &s->mode);
+    /*
     qemu_get_be32s(f, &s->kbd_write_cmd);
     qemu_get_be32s(f, &s->scan_enabled);
     qemu_get_be32s(f, &s->mouse_write_cmd);
@@ -685,6 +346,7 @@ static int kbd_load(QEMUFile* f, void* o
     qemu_get_be32s(f, &s->mouse_dy);
     qemu_get_be32s(f, &s->mouse_dz);
     qemu_get_8s(f, &s->mouse_buttons);
+    */
     return 0;
 }
 
@@ -693,13 +355,12 @@ void kbd_init(void)
     KBDState *s = &kbd_state;
     
     kbd_reset(s);
-    register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);
+    register_savevm("pckbd", 0, 2, kbd_save, kbd_load, s);
     register_ioport_read(0x60, 1, 1, kbd_read_data, s);
     register_ioport_write(0x60, 1, 1, kbd_write_data, s);
     register_ioport_read(0x64, 1, 1, kbd_read_status, s);
     register_ioport_write(0x64, 1, 1, kbd_write_command, s);
 
-    qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
-    qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
+    s->ps2 = ps2_init(kbd_update_irq, s);
     qemu_register_reset(kbd_reset, s);
 }
Index: hw/ps2.c
===================================================================
RCS file: hw/ps2.c
diff -N hw/ps2.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ hw/ps2.c    6 Nov 2005 15:53:43 -0000
@@ -0,0 +1,493 @@
+/*
+ * QEMU PS/2 keyboard/mouse 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 "vl.h"
+
+/* debug PC keyboard */
+//#define DEBUG_KBD
+
+/* debug PC keyboard : only mouse */
+//#define DEBUG_MOUSE
+
+/* 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 */
+
+/* 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
+
+typedef struct {
+    uint8_t aux[KBD_QUEUE_SIZE];
+    uint8_t data[KBD_QUEUE_SIZE];
+    int rptr, wptr, count;
+} PS2Queue;
+
+struct PS2State {
+    PS2Queue queue;
+    /* keyboard state */
+    int kbd_write_cmd;
+    int scan_enabled;
+    /* mouse state */
+    int mouse_write_cmd;
+    uint8_t mouse_status;
+    uint8_t mouse_resolution;
+    uint8_t mouse_sample_rate;
+    uint8_t mouse_wrap;
+    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
+    uint8_t mouse_detect_state;
+    int mouse_dx; /* current values, needed for 'poll' mode */
+    int mouse_dy;
+    int mouse_dz;
+    uint8_t mouse_buttons;
+    void (*update_irq)(void *, int, int);
+    void *update_arg;
+};
+
+void ps2_queue(PS2State *s, int b, int aux)
+{
+    PS2Queue *q = &s->queue;
+
+#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
+    if (aux)
+        printf("mouse event: 0x%02x\n", b);
+#ifdef DEBUG_KBD
+    else
+        printf("kbd event: 0x%02x\n", b);
+#endif
+#endif
+    if (q->count >= KBD_QUEUE_SIZE)
+        return;
+    q->aux[q->wptr] = aux;
+    q->data[q->wptr] = b;
+    if (++q->wptr == KBD_QUEUE_SIZE)
+        q->wptr = 0;
+    q->count++;
+    s->update_irq(s->update_arg, q->aux[q->rptr], 1);
+}
+
+static void ps2_put_keycode(void *opaque, int keycode)
+{
+    PS2State *s = opaque;
+    ps2_queue(s, keycode, 0);
+}
+
+uint32_t ps2_read_data(PS2State *s)
+{
+    PS2Queue *q;
+    int val, index, aux;
+    
+    q = &s->queue;
+    if (q->count == 0) {
+        /* NOTE: if no data left, we return the last keyboard one
+           (needed for EMM386) */
+        /* XXX: need a timer to do things correctly */
+        index = q->rptr - 1;
+        if (index < 0)
+            index = KBD_QUEUE_SIZE - 1;
+        val = q->data[index];
+    } else {
+        aux = q->aux[q->rptr];
+        val = q->data[q->rptr];
+        if (++q->rptr == KBD_QUEUE_SIZE)
+            q->rptr = 0;
+        q->count--;
+        /* reading deasserts IRQ */
+        s->update_irq(s->update_arg, aux, 0);
+        if (aux)
+            pic_set_irq(12, 0);
+        else
+            pic_set_irq(1, 0);
+    }
+    /* reassert IRQs if data left */
+    s->update_irq(s->update_arg, q->aux[q->rptr], q->count != 0);
+#ifdef DEBUG_KBD
+    printf("kbd: read data=0x%02x\n", val);
+#endif
+    return val;
+}
+
+static void ps2_reset_keyboard(PS2State *s)
+{
+    s->scan_enabled = 1;
+}
+
+void ps2_write_keyboard(PS2State *s, int val)
+{
+    switch(s->kbd_write_cmd) {
+    default:
+    case -1:
+        switch(val) {
+        case 0x00:
+            ps2_queue(s, KBD_REPLY_ACK, 0);
+            break;
+        case 0x05:
+            ps2_queue(s, KBD_REPLY_RESEND, 0);
+            break;
+        case KBD_CMD_GET_ID:
+            ps2_queue(s, KBD_REPLY_ACK, 0);
+            ps2_queue(s, 0xab, 0);
+            ps2_queue(s, 0x83, 0);
+            break;
+        case KBD_CMD_ECHO:
+            ps2_queue(s, KBD_CMD_ECHO, 0);
+            break;
+        case KBD_CMD_ENABLE:
+            s->scan_enabled = 1;
+            ps2_queue(s, KBD_REPLY_ACK, 0);
+            break;
+        case KBD_CMD_SET_LEDS:
+        case KBD_CMD_SET_RATE:
+            s->kbd_write_cmd = val;
+            ps2_queue(s, KBD_REPLY_ACK, 0);
+            break;
+        case KBD_CMD_RESET_DISABLE:
+            ps2_reset_keyboard(s);
+            s->scan_enabled = 0;
+            ps2_queue(s, KBD_REPLY_ACK, 0);
+            break;
+        case KBD_CMD_RESET_ENABLE:
+            ps2_reset_keyboard(s);
+            s->scan_enabled = 1;
+            ps2_queue(s, KBD_REPLY_ACK, 0);
+            break;
+        case KBD_CMD_RESET:
+            ps2_reset_keyboard(s);
+            ps2_queue(s, KBD_REPLY_ACK, 0);
+            ps2_queue(s, KBD_REPLY_POR, 0);
+            break;
+        default:
+            ps2_queue(s, KBD_REPLY_ACK, 0);
+            break;
+        }
+        break;
+    case KBD_CMD_SET_LEDS:
+        ps2_queue(s, KBD_REPLY_ACK, 0);
+        s->kbd_write_cmd = -1;
+        break;
+    case KBD_CMD_SET_RATE:
+        ps2_queue(s, KBD_REPLY_ACK, 0);
+        s->kbd_write_cmd = -1;
+        break;
+    }
+}
+
+static void ps2_mouse_send_packet(PS2State *s)
+{
+    unsigned int b;
+    int dx1, dy1, dz1;
+
+    dx1 = s->mouse_dx;
+    dy1 = s->mouse_dy;
+    dz1 = s->mouse_dz;
+    /* XXX: increase range to 8 bits ? */
+    if (dx1 > 127)
+        dx1 = 127;
+    else if (dx1 < -127)
+        dx1 = -127;
+    if (dy1 > 127)
+        dy1 = 127;
+    else if (dy1 < -127)
+        dy1 = -127;
+    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
+    ps2_queue(s, b, 1);
+    ps2_queue(s, dx1 & 0xff, 1);
+    ps2_queue(s, dy1 & 0xff, 1);
+    /* extra byte for IMPS/2 or IMEX */
+    switch(s->mouse_type) {
+    default:
+        break;
+    case 3:
+        if (dz1 > 127)
+            dz1 = 127;
+        else if (dz1 < -127)
+                dz1 = -127;
+        ps2_queue(s, dz1 & 0xff, 1);
+        break;
+    case 4:
+        if (dz1 > 7)
+            dz1 = 7;
+        else if (dz1 < -7)
+            dz1 = -7;
+        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
+        ps2_queue(s, b, 1);
+        break;
+    }
+
+    /* update deltas */
+    s->mouse_dx -= dx1;
+    s->mouse_dy -= dy1;
+    s->mouse_dz -= dz1;
+}
+
+static void ps2_mouse_event(void *opaque, 
+                            int dx, int dy, int dz, int buttons_state)
+{
+    PS2State *s = opaque;
+
+    /* check if deltas are recorded when disabled */
+    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
+        return;
+
+    s->mouse_dx += dx;
+    s->mouse_dy -= dy;
+    s->mouse_dz += dz;
+    /* XXX: SDL sometimes generates nul events: we delete them */
+    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
+        s->mouse_buttons == buttons_state)
+       return;
+    s->mouse_buttons = buttons_state;
+    
+    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
+        (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
+        for(;;) {
+            /* if not remote, send event. Multiple events are sent if
+               too big deltas */
+            ps2_mouse_send_packet(s);
+            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
+                break;
+        }
+    }
+}
+
+void ps2_write_mouse(PS2State *s, int val)
+{
+#ifdef DEBUG_MOUSE
+    printf("kbd: write mouse 0x%02x\n", val);
+#endif
+    switch(s->mouse_write_cmd) {
+    default:
+    case -1:
+        /* mouse command */
+        if (s->mouse_wrap) {
+            if (val == AUX_RESET_WRAP) {
+                s->mouse_wrap = 0;
+                ps2_queue(s, AUX_ACK, 1);
+                return;
+            } else if (val != AUX_RESET) {
+                ps2_queue(s, val, 1);
+                return;
+            }
+        }
+        switch(val) {
+        case AUX_SET_SCALE11:
+            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_SET_SCALE21:
+            s->mouse_status |= MOUSE_STATUS_SCALE21;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_SET_STREAM:
+            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_SET_WRAP:
+            s->mouse_wrap = 1;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_SET_REMOTE:
+            s->mouse_status |= MOUSE_STATUS_REMOTE;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_GET_TYPE:
+            ps2_queue(s, AUX_ACK, 1);
+            ps2_queue(s, s->mouse_type, 1);
+            break;
+        case AUX_SET_RES:
+        case AUX_SET_SAMPLE:
+            s->mouse_write_cmd = val;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_GET_SCALE:
+            ps2_queue(s, AUX_ACK, 1);
+            ps2_queue(s, s->mouse_status, 1);
+            ps2_queue(s, s->mouse_resolution, 1);
+            ps2_queue(s, s->mouse_sample_rate, 1);
+            break;
+        case AUX_POLL:
+            ps2_queue(s, AUX_ACK, 1);
+            ps2_mouse_send_packet(s);
+            break;
+        case AUX_ENABLE_DEV:
+            s->mouse_status |= MOUSE_STATUS_ENABLED;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_DISABLE_DEV:
+            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_SET_DEFAULT:
+            s->mouse_sample_rate = 100;
+            s->mouse_resolution = 2;
+            s->mouse_status = 0;
+            ps2_queue(s, AUX_ACK, 1);
+            break;
+        case AUX_RESET:
+            s->mouse_sample_rate = 100;
+            s->mouse_resolution = 2;
+            s->mouse_status = 0;
+            s->mouse_type = 0;
+            ps2_queue(s, AUX_ACK, 1);
+            ps2_queue(s, 0xaa, 1);
+            ps2_queue(s, s->mouse_type, 1);
+            break;
+        default:
+            break;
+        }
+        break;
+    case AUX_SET_SAMPLE:
+        s->mouse_sample_rate = val;
+        /* detect IMPS/2 or IMEX */
+        switch(s->mouse_detect_state) {
+        default:
+        case 0:
+            if (val == 200)
+                s->mouse_detect_state = 1;
+            break;
+        case 1:
+            if (val == 100)
+                s->mouse_detect_state = 2;
+            else if (val == 200)
+                s->mouse_detect_state = 3;
+            else
+                s->mouse_detect_state = 0;
+            break;
+        case 2:
+            if (val == 80) 
+                s->mouse_type = 3; /* IMPS/2 */
+            s->mouse_detect_state = 0;
+            break;
+        case 3:
+            if (val == 80) 
+                s->mouse_type = 4; /* IMEX */
+            s->mouse_detect_state = 0;
+            break;
+        }
+        ps2_queue(s, AUX_ACK, 1);
+        s->mouse_write_cmd = -1;
+        break;
+    case AUX_SET_RES:
+        s->mouse_resolution = val;
+        ps2_queue(s, AUX_ACK, 1);
+        s->mouse_write_cmd = -1;
+        break;
+    }
+}
+
+static void ps2_reset(void *opaque)
+{
+    PS2State *s = (PS2State *)opaque;
+    PS2Queue *q;
+    s->kbd_write_cmd = -1;
+    s->mouse_write_cmd = -1;
+    q = &s->queue;
+    q->rptr = 0;
+    q->wptr = 0;
+    q->count = 0;
+}
+
+static void ps2_save(QEMUFile* f, void* opaque)
+{
+    PS2State *s = (PS2State*)opaque;
+    
+    qemu_put_be32s(f, &s->kbd_write_cmd);
+    qemu_put_be32s(f, &s->scan_enabled);
+    qemu_put_be32s(f, &s->mouse_write_cmd);
+    qemu_put_8s(f, &s->mouse_status);
+    qemu_put_8s(f, &s->mouse_resolution);
+    qemu_put_8s(f, &s->mouse_sample_rate);
+    qemu_put_8s(f, &s->mouse_wrap);
+    qemu_put_8s(f, &s->mouse_type);
+    qemu_put_8s(f, &s->mouse_detect_state);
+    qemu_put_be32s(f, &s->mouse_dx);
+    qemu_put_be32s(f, &s->mouse_dy);
+    qemu_put_be32s(f, &s->mouse_dz);
+    qemu_put_8s(f, &s->mouse_buttons);
+}
+
+static int ps2_load(QEMUFile* f, void* opaque, int version_id)
+{
+    PS2State *s = (PS2State*)opaque;
+    
+    if (version_id != 1)
+        return -EINVAL;
+    qemu_get_be32s(f, &s->kbd_write_cmd);
+    qemu_get_be32s(f, &s->scan_enabled);
+    qemu_get_be32s(f, &s->mouse_write_cmd);
+    qemu_get_8s(f, &s->mouse_status);
+    qemu_get_8s(f, &s->mouse_resolution);
+    qemu_get_8s(f, &s->mouse_sample_rate);
+    qemu_get_8s(f, &s->mouse_wrap);
+    qemu_get_8s(f, &s->mouse_type);
+    qemu_get_8s(f, &s->mouse_detect_state);
+    qemu_get_be32s(f, &s->mouse_dx);
+    qemu_get_be32s(f, &s->mouse_dy);
+    qemu_get_be32s(f, &s->mouse_dz);
+    qemu_get_8s(f, &s->mouse_buttons);
+    return 0;
+}
+PS2State *ps2_init(void (*update_irq)(void *, int, int), void *update_arg)
+{
+    PS2State *s = (PS2State *)qemu_mallocz(sizeof(PS2State));
+
+    s->update_irq = update_irq;
+    s->update_arg = update_arg;
+    ps2_reset(s);
+    register_savevm("ps2", 0, 1, ps2_save, ps2_load, s);
+    qemu_add_kbd_event_handler(ps2_put_keycode, s);
+    qemu_add_mouse_event_handler(ps2_mouse_event, s);
+    qemu_register_reset(ps2_reset, s);
+    return s;
+}
Index: hw/pckbd.c
===================================================================
--- Makefile.target     (revision 1795)
+++ Makefile.target     (local)
@@ -240,6 +240,9 @@
 ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
 LIBOBJS+=arm-dis.o
 endif
+ifeq ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k)
+LIBOBJS+=m68k-dis.o
+endif
 
 ifeq ($(ARCH),ia64)
 OBJS += ia64-syscall.o
@@ -292,25 +295,25 @@
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
-VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
 VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
 VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
 VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o
 DEFINES += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), ppc)
-VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o 
$(AUDIODRV)
 VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
 VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
 DEFINES += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_ARCH), mips)
 VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.o
-#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
+#VL_OBJS+= #ide.o pckbd.o ps2.o fdc.o m48t59.o
 endif
 ifeq ($(TARGET_BASE_ARCH), sparc)
 ifeq ($(TARGET_ARCH), sparc64)
-VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o
+VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o ps2.o vga.o
 VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
 VL_OBJS+= cirrus_vga.o parallel.o
 VL_OBJS+= magic-load.o

reply via email to

[Prev in Thread] Current Thread [Next in Thread]