added virtual USB mouse support
[qemu] / hw / pckbd.c
index 8c0d3a7..be559eb 100644 (file)
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/time.h>
-#include <malloc.h>
-#include <termios.h>
-#include <sys/poll.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-
-#include "cpu.h"
 #include "vl.h"
 
 /* debug PC keyboard */
 #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 queues[2];
+    KBDQueue queue;
     uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
     uint8_t status;
     uint8_t mode;
@@ -158,22 +139,21 @@ typedef struct KBDState {
 } KBDState;
 
 KBDState kbd_state;
-int reset_requested;
 
 /* 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)
 {
+    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 (s->queues[0].count != 0 ||
-        s->queues[1].count != 0) {
+    if (q->count != 0) {
         s->status |= KBD_STAT_OBF;
-        if (s->queues[1].count != 0) {
+        if (q->aux[q->rptr]) {
             s->status |= KBD_STAT_MOUSE_OBF;
             if (s->mode & KBD_MODE_MOUSE_INT)
                 irq12_level = 1;
@@ -189,7 +169,7 @@ static void kbd_update_irq(KBDState *s)
 
 static void kbd_queue(KBDState *s, int b, int aux)
 {
-    KBDQueue *q = &kbd_state.queues[aux];
+    KBDQueue *q = &s->queue;
 
 #if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
     if (aux)
@@ -201,6 +181,7 @@ static void kbd_queue(KBDState *s, int b, int aux)
 #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;
@@ -208,15 +189,15 @@ static void kbd_queue(KBDState *s, int b, int aux)
     kbd_update_irq(s);
 }
 
-void kbd_put_keycode(int keycode)
+static void pc_kbd_put_keycode(void *opaque, int keycode)
 {
-    KBDState *s = &kbd_state;
+    KBDState *s = opaque;
     kbd_queue(s, keycode, 0);
 }
 
-static uint32_t kbd_read_status(CPUState *env, uint32_t addr)
+static uint32_t kbd_read_status(void *opaque, uint32_t addr)
 {
-    KBDState *s = &kbd_state;
+    KBDState *s = opaque;
     int val;
     val = s->status;
 #if defined(DEBUG_KBD)
@@ -225,9 +206,9 @@ static uint32_t kbd_read_status(CPUState *env, uint32_t addr)
     return val;
 }
 
-static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val)
+static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
 {
-    KBDState *s = &kbd_state;
+    KBDState *s = opaque;
 
 #ifdef DEBUG_KBD
     printf("kbd: write cmd=0x%02x\n", val);
@@ -285,15 +266,14 @@ static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val)
         break;
 #ifdef TARGET_I386
     case KBD_CCMD_ENABLE_A20:
-        cpu_x86_set_a20(env, 1);
+        cpu_x86_set_a20(cpu_single_env, 1);
         break;
     case KBD_CCMD_DISABLE_A20:
-        cpu_x86_set_a20(env, 0);
+        cpu_x86_set_a20(cpu_single_env, 0);
         break;
 #endif
     case KBD_CCMD_RESET:
-        reset_requested = 1;
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+        qemu_system_reset_request();
         break;
     case 0xff:
         /* ignore that - I don't know what is its use */
@@ -304,34 +284,32 @@ static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val)
     }
 }
 
-static uint32_t kbd_read_data(CPUState *env, uint32_t addr)
+static uint32_t kbd_read_data(void *opaque, uint32_t addr)
 {
-    KBDState *s = &kbd_state;
+    KBDState *s = opaque;
     KBDQueue *q;
-    int val, index;
+    int val, index, aux;
     
-    q = &s->queues[0]; /* first check KBD data */
-    if (q->count == 0)
-        q = &s->queues[1]; /* then check AUX data */
+    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 */
-        q = &s->queues[0];
         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 (q == &s->queues[0])
-            pic_set_irq(1, 0);
-        else
+        if (aux)
             pic_set_irq(12, 0);
+        else
+            pic_set_irq(1, 0);
     }
     /* reassert IRQs if data left */
     kbd_update_irq(s);
@@ -454,9 +432,10 @@ static void kbd_mouse_send_packet(KBDState *s)
     s->mouse_dz -= dz1;
 }
 
-void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
+static void pc_kbd_mouse_event(void *opaque, 
+                               int dx, int dy, int dz, int buttons_state)
 {
-    KBDState *s = &kbd_state;
+    KBDState *s = opaque;
 
     /* check if deltas are recorded when disabled */
     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
@@ -465,10 +444,14 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
     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->queues[1].count < (KBD_QUEUE_SIZE - 16))) {
+        (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
         for(;;) {
             /* if not remote, send event. Multiple events are sent if
                too big deltas */
@@ -556,6 +539,7 @@ static void kbd_write_mouse(KBDState *s, int val)
             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);
@@ -566,7 +550,6 @@ static void kbd_write_mouse(KBDState *s, int val)
         break;
     case AUX_SET_SAMPLE:
         s->mouse_sample_rate = val;
-#if 0
         /* detect IMPS/2 or IMEX */
         switch(s->mouse_detect_state) {
         default:
@@ -593,7 +576,6 @@ static void kbd_write_mouse(KBDState *s, int val)
             s->mouse_detect_state = 0;
             break;
         }
-#endif
         kbd_queue(s, AUX_ACK, 1);
         s->mouse_write_cmd = -1;
         break;
@@ -605,9 +587,9 @@ static void kbd_write_mouse(KBDState *s, int val)
     }
 }
 
-void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val)
+void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
 {
-    KBDState *s = &kbd_state;
+    KBDState *s = opaque;
 
 #ifdef DEBUG_KBD
     printf("kbd: write data=0x%02x\n", val);
@@ -629,11 +611,10 @@ void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val)
         break;
     case KBD_CCMD_WRITE_OUTPORT:
 #ifdef TARGET_I386
-        cpu_x86_set_a20(env, (val >> 1) & 1);
+        cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
 #endif
         if (!(val & 1)) {
-            reset_requested = 1;
-            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+            qemu_system_reset_request();
         }
         break;
     case KBD_CCMD_WRITE_MOUSE:
@@ -645,28 +626,80 @@ void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val)
     s->write_cmd = 0;
 }
 
-void kbd_reset(KBDState *s)
+static void kbd_reset(void *opaque)
 {
+    KBDState *s = opaque;
     KBDQueue *q;
-    int i;
 
     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;
-    for(i = 0; i < 2; i++) {
-        q = &s->queues[i];
-        q->rptr = 0;
-        q->wptr = 0;
-        q->count = 0;
-    }
+    q = &s->queue;
+    q->rptr = 0;
+    q->wptr = 0;
+    q->count = 0;
+}
+
+static void kbd_save(QEMUFile* f, void* opaque)
+{
+    KBDState *s = (KBDState*)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)
+        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;
 }
 
 void kbd_init(void)
 {
-    kbd_reset(&kbd_state);
-    register_ioport_read(0x60, 1, kbd_read_data, 1);
-    register_ioport_write(0x60, 1, kbd_write_data, 1);
-    register_ioport_read(0x64, 1, kbd_read_status, 1);
-    register_ioport_write(0x64, 1, kbd_write_command, 1);
+    KBDState *s = &kbd_state;
+    
+    kbd_reset(s);
+    register_savevm("pckbd", 0, 1, 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);
+    qemu_register_reset(kbd_reset, s);
 }