OSDN Git Service

PS2 mouse and keyboard separation (Paul Brook)
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 26 Nov 2005 10:14:03 +0000 (10:14 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 26 Nov 2005 10:14:03 +0000 (10:14 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1658 c046a42c-6fe2-441c-8c8c-71466251a162

Makefile.target
hw/pckbd.c
vl.h

index 9e06fb6..9280c59 100644 (file)
@@ -298,13 +298,13 @@ VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o
 
 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
 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
@@ -315,7 +315,7 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.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
index 1be1560..61f8a63 100644 (file)
 
 #define KBD_QUEUE_SIZE 256
 
-typedef struct {
-    uint8_t aux[KBD_QUEUE_SIZE];
-    uint8_t data[KBD_QUEUE_SIZE];
-    int rptr, wptr, count;
-} KBDQueue;
+#define KBD_PENDING_KBD         1
+#define KBD_PENDING_AUX         2
 
 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;
+    /* Bitmask of devices with data available.  */
+    int pending;
+    void *kbd;
+    void *mouse;
 } KBDState;
 
 KBDState kbd_state;
@@ -145,15 +130,15 @@ KBDState kbd_state;
    incorrect, but it avoids having to simulate exact delays */
 static void kbd_update_irq(KBDState *s)
 {
-    KBDQueue *q = &s->queue;
     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 (s->pending) {
         s->status |= KBD_STAT_OBF;
-        if (q->aux[q->rptr]) {
+        /* kdb data takes priority over aux data.  */
+        if (s->pending == KBD_PENDING_AUX) {
             s->status |= KBD_STAT_MOUSE_OBF;
             if (s->mode & KBD_MODE_MOUSE_INT)
                 irq12_level = 1;
@@ -167,32 +152,26 @@ static void kbd_update_irq(KBDState *s)
     pic_set_irq(12, irq12_level);
 }
 
-static void kbd_queue(KBDState *s, int b, int aux)
+static void kbd_update_kbd_irq(void *opaque, int level)
 {
-    KBDQueue *q = &s->queue;
+    KBDState *s = (KBDState *)opaque;
 
-#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
-    if (aux)
-        printf("mouse event: 0x%02x\n", b);
-#ifdef DEBUG_KBD
+    if (level)
+        s->pending |= KBD_PENDING_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->pending &= ~KBD_PENDING_KBD;
     kbd_update_irq(s);
 }
 
-static void pc_kbd_put_keycode(void *opaque, int keycode)
+static void kbd_update_aux_irq(void *opaque, int level)
 {
-    KBDState *s = opaque;
-    kbd_queue(s, keycode, 0);
+    KBDState *s = (KBDState *)opaque;
+
+    if (level)
+        s->pending |= KBD_PENDING_AUX;
+    else
+        s->pending &= ~KBD_PENDING_AUX;
+    kbd_update_irq(s);
 }
 
 static uint32_t kbd_read_status(void *opaque, uint32_t addr)
@@ -206,6 +185,14 @@ static uint32_t kbd_read_status(void *opaque, uint32_t addr)
     return val;
 }
 
+static void kbd_queue(KBDState *s, int b, int aux)
+{
+    if (aux)
+        ps2_queue(s->mouse, b);
+    else
+        ps2_queue(s->kbd, b);
+}
+
 static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
 {
     KBDState *s = opaque;
@@ -287,304 +274,11 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
 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;
-        }
-    }
-}
+    if (s->pending == KBD_PENDING_AUX)
+        return ps2_read_data(s->mouse);
 
-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->kbd);
 }
 
 void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
@@ -597,10 +291,11 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
 
     switch(s->write_cmd) {
     case 0:
-        kbd_write_keyboard(s, val);
+        ps2_write_keyboard(s->kbd, val);
         break;
     case KBD_CCMD_WRITE_MODE:
         s->mode = val;
+        /* ??? */
         kbd_update_irq(s);
         break;
     case KBD_CCMD_WRITE_OBUF:
@@ -618,7 +313,7 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
         }
         break;
     case KBD_CCMD_WRITE_MOUSE:
-        kbd_write_mouse(s, val);
+        ps2_write_mouse(s->mouse, val);
         break;
     default:
         break;
@@ -629,16 +324,9 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
 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,43 +336,17 @@ static void kbd_save(QEMUFile* f, void* opaque)
     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);
-    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 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);
-    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;
 }
 
@@ -693,13 +355,13 @@ 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->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
     qemu_register_reset(kbd_reset, s);
 }
diff --git a/vl.h b/vl.h
index 2326c4c..6f4ac7f 100644 (file)
--- a/vl.h
+++ b/vl.h
@@ -928,6 +928,14 @@ void do_usb_add(const char *devname);
 void do_usb_del(const char *devname);
 void usb_info(void);
 
+/* ps2.c */
+void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
+void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
+void ps2_write_mouse(void *, int val);
+void ps2_write_keyboard(void *, int val);
+uint32_t ps2_read_data(void *);
+void ps2_queue(void *, int b);
+
 #endif /* defined(QEMU_TOOL) */
 
 /* monitor.c */