sparc merge (Blue Swirl)
[qemu] / hw / pckbd.c
index 2328d20..730b573 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;
 
 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;
@@ -138,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;
@@ -169,7 +169,7 @@ static void kbd_update_irq(KBDState *s)
 
 static void kbd_queue(KBDState *s, int b, int aux)
 {
-    KBDQueue *q = &s->queues[aux];
+    KBDQueue *q = &s->queue;
 
 #if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
     if (aux)
@@ -181,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;
@@ -188,9 +189,9 @@ 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);
 }
 
@@ -272,8 +273,7 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
         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 */
@@ -288,30 +288,28 @@ static uint32_t kbd_read_data(void *opaque, uint32_t addr)
 {
     KBDState *s = opaque;
     KBDQueue *q;
-    int val, index;
+    int val, index, aux;
     
-    q = &s->queues[1]; /* first check AUX data */
-    if (q->count == 0)
-        q = &s->queues[0]; /* then check KBD 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);
@@ -434,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))
@@ -452,7 +451,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
     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 */
@@ -616,8 +615,7 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
         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:
@@ -629,21 +627,66 @@ void kbd_write_data(void *opaque, 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)
@@ -651,8 +694,13 @@ void kbd_init(void)
     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);
 }