]> git.proxmox.com Git - qemu.git/blobdiff - hw/pckbd.c
sun4c: remove unused functions
[qemu.git] / hw / pckbd.c
index de508b309083722eb0392f90c8fa07ad40c5b1a8..5bb3e0abf3fd167f85f817d0cbcc85fd6228b4fd 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * 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
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "vl.h"
+#include "hw.h"
+#include "isa.h"
+#include "pc.h"
+#include "ps2.h"
+#include "sysemu.h"
 
 /* debug PC keyboard */
 //#define DEBUG_KBD
-
-/* debug PC keyboard : only mouse */
-//#define DEBUG_MOUSE
+#ifdef DEBUG_KBD
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
 
 /*     Keyboard Controller Commands */
 #define KBD_CCMD_READ_MODE     0x20    /* Read mode bits */
@@ -49,7 +56,9 @@
 #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
+#define KBD_CCMD_PULSE_BITS_3_0 0xF0    /* Pulse bits 3-0 of the output port P2. */
+#define KBD_CCMD_RESET          0xFE    /* Pulse bit 0 of the output port P2 = CPU reset. */
+#define KBD_CCMD_NO_OP          0xFF    /* Pulse no bits of the output port P2. */
 
 /* Keyboard Commands */
 #define KBD_CMD_SET_LEDS       0xED    /* Set keyboard leds */
 #define KBD_MODE_KCC           0x40    /* Scan code conversion to PC format */
 #define KBD_MODE_RFU           0x80
 
+/* Output Port Bits */
+#define KBD_OUT_RESET           0x01    /* 1=normal mode, 0=reset */
+#define KBD_OUT_A20             0x02    /* x86 only */
+#define KBD_OUT_OBF             0x10    /* Keyboard output buffer full */
+#define KBD_OUT_MOUSE_OBF       0x20    /* Mouse output buffer full */
+
 /* Mouse Commands */
 #define AUX_SET_SCALE11                0xE6    /* Set 1:1 scaling */
 #define AUX_SET_SCALE21                0xE7    /* Set 2:1 scaling */
 #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
 
@@ -117,6 +130,7 @@ typedef struct KBDState {
     uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
     uint8_t status;
     uint8_t mode;
+    uint8_t outport;
     /* Bitmask of devices with data available.  */
     uint8_t pending;
     void *kbd;
@@ -124,12 +138,10 @@ typedef struct KBDState {
 
     qemu_irq irq_kbd;
     qemu_irq irq_mouse;
-    target_phys_addr_t base;
-    int it_shift;
+    qemu_irq *a20_out;
+    hwaddr mask;
 } KBDState;
 
-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 */
@@ -140,15 +152,18 @@ static void kbd_update_irq(KBDState *s)
     irq_kbd_level = 0;
     irq_mouse_level = 0;
     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
+    s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
     if (s->pending) {
         s->status |= KBD_STAT_OBF;
+        s->outport |= KBD_OUT_OBF;
         /* kbd data takes priority over aux data.  */
         if (s->pending == KBD_PENDING_AUX) {
             s->status |= KBD_STAT_MOUSE_OBF;
+            s->outport |= KBD_OUT_MOUSE_OBF;
             if (s->mode & KBD_MODE_MOUSE_INT)
                 irq_mouse_level = 1;
         } else {
-            if ((s->mode & KBD_MODE_KBD_INT) && 
+            if ((s->mode & KBD_MODE_KBD_INT) &&
                 !(s->mode & KBD_MODE_DISABLE_KBD))
                 irq_kbd_level = 1;
         }
@@ -179,14 +194,13 @@ static void kbd_update_aux_irq(void *opaque, int level)
     kbd_update_irq(s);
 }
 
-static uint32_t kbd_read_status(void *opaque, uint32_t addr)
+static uint64_t kbd_read_status(void *opaque, hwaddr addr,
+                                unsigned size)
 {
     KBDState *s = opaque;
     int val;
     val = s->status;
-#if defined(DEBUG_KBD)
-    printf("kbd: read status=0x%02x\n", val);
-#endif
+    DPRINTF("kbd: read status=0x%02x\n", val);
     return val;
 }
 
@@ -198,13 +212,39 @@ static void kbd_queue(KBDState *s, int b, int aux)
         ps2_queue(s->kbd, b);
 }
 
-static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
+static void outport_write(KBDState *s, uint32_t val)
+{
+    DPRINTF("kbd: write outport=0x%02x\n", val);
+    s->outport = val;
+    if (s->a20_out) {
+        qemu_set_irq(*s->a20_out, (val >> 1) & 1);
+    }
+    if (!(val & 1)) {
+        qemu_system_reset_request();
+    }
+}
+
+static void kbd_write_command(void *opaque, hwaddr addr,
+                              uint64_t val, unsigned size)
 {
     KBDState *s = opaque;
 
-#ifdef DEBUG_KBD
-    printf("kbd: write cmd=0x%02x\n", val);
-#endif
+    DPRINTF("kbd: write cmd=0x%02x\n", val);
+
+    /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
+     * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
+     * command specify the output port bits to be pulsed.
+     * 0: Bit should be pulsed. 1: Bit should not be modified.
+     * The only useful version of this command is pulsing bit 0,
+     * which does a CPU reset.
+     */
+    if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
+        if(!(val & 1))
+            val = KBD_CCMD_RESET;
+        else
+            val = KBD_CCMD_NO_OP;
+    }
+
     switch(val) {
     case KBD_CCMD_READ_MODE:
         kbd_queue(s, s->mode, 0);
@@ -244,55 +284,53 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
         kbd_queue(s, 0x00, 0);
         break;
     case KBD_CCMD_READ_OUTPORT:
-        /* XXX: check that */
-#ifdef TARGET_I386
-        val = 0x01 | (ioport_get_a20() << 1);
-#else
-        val = 0x01;
-#endif
-        if (s->status & KBD_STAT_OBF)
-            val |= 0x10;
-        if (s->status & KBD_STAT_MOUSE_OBF)
-            val |= 0x20;
-        kbd_queue(s, val, 0);
+        kbd_queue(s, s->outport, 0);
         break;
-#ifdef TARGET_I386
     case KBD_CCMD_ENABLE_A20:
-        ioport_set_a20(1);
+        if (s->a20_out) {
+            qemu_irq_raise(*s->a20_out);
+        }
+        s->outport |= KBD_OUT_A20;
         break;
     case KBD_CCMD_DISABLE_A20:
-        ioport_set_a20(0);
+        if (s->a20_out) {
+            qemu_irq_lower(*s->a20_out);
+        }
+        s->outport &= ~KBD_OUT_A20;
         break;
-#endif
     case KBD_CCMD_RESET:
         qemu_system_reset_request();
         break;
-    case 0xff:
-        /* ignore that - I don't know what is its use */
+    case KBD_CCMD_NO_OP:
+        /* ignore that */
         break;
     default:
-        fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
+        fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", (int)val);
         break;
     }
 }
 
-static uint32_t kbd_read_data(void *opaque, uint32_t addr)
+static uint64_t kbd_read_data(void *opaque, hwaddr addr,
+                              unsigned size)
 {
     KBDState *s = opaque;
+    uint32_t val;
 
     if (s->pending == KBD_PENDING_AUX)
-        return ps2_read_data(s->mouse);
+        val = ps2_read_data(s->mouse);
+    else
+        val = ps2_read_data(s->kbd);
 
-    return ps2_read_data(s->kbd);
+    DPRINTF("kbd: read data=0x%02x\n", val);
+    return val;
 }
 
-void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
+static void kbd_write_data(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
 {
     KBDState *s = opaque;
 
-#ifdef DEBUG_KBD
-    printf("kbd: write data=0x%02x\n", val);
-#endif
+    DPRINTF("kbd: write data=0x%02x\n", val);
 
     switch(s->write_cmd) {
     case 0:
@@ -311,12 +349,7 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
         kbd_queue(s, val, 1);
         break;
     case KBD_CCMD_WRITE_OUTPORT:
-#ifdef TARGET_I386
-        ioport_set_a20((val >> 1) & 1);
-#endif
-        if (!(val & 1)) {
-            qemu_system_reset_request();
-        }
+        outport_write(s, val);
         break;
     case KBD_CCMD_WRITE_MOUSE:
         ps2_write_mouse(s->mouse, val);
@@ -333,114 +366,162 @@ static void kbd_reset(void *opaque)
 
     s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
     s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
+    s->outport = KBD_OUT_RESET | KBD_OUT_A20;
 }
 
-static void kbd_save(QEMUFile* f, void* opaque)
+static const VMStateDescription vmstate_kbd = {
+    .name = "pckbd",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(write_cmd, KBDState),
+        VMSTATE_UINT8(status, KBDState),
+        VMSTATE_UINT8(mode, KBDState),
+        VMSTATE_UINT8(pending, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Memory mapped interface */
+static uint32_t kbd_mm_readb (void *opaque, hwaddr addr)
 {
-    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_8s(f, &s->pending);
+    KBDState *s = opaque;
+
+    if (addr & s->mask)
+        return kbd_read_status(s, 0, 1) & 0xff;
+    else
+        return kbd_read_data(s, 0, 1) & 0xff;
 }
 
-static int kbd_load(QEMUFile* f, void* opaque, int version_id)
+static void kbd_mm_writeb (void *opaque, hwaddr addr, uint32_t value)
 {
-    KBDState *s = (KBDState*)opaque;
-    
-    if (version_id != 3)
-        return -EINVAL;
-    qemu_get_8s(f, &s->write_cmd);
-    qemu_get_8s(f, &s->status);
-    qemu_get_8s(f, &s->mode);
-    qemu_get_8s(f, &s->pending);
-    return 0;
+    KBDState *s = opaque;
+
+    if (addr & s->mask)
+        kbd_write_command(s, 0, value & 0xff, 1);
+    else
+        kbd_write_data(s, 0, value & 0xff, 1);
 }
 
-void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base)
+static const MemoryRegionOps i8042_mmio_ops = {
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .old_mmio = {
+        .read = { kbd_mm_readb, kbd_mm_readb, kbd_mm_readb },
+        .write = { kbd_mm_writeb, kbd_mm_writeb, kbd_mm_writeb },
+    },
+};
+
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
+                   MemoryRegion *region, ram_addr_t size,
+                   hwaddr mask)
 {
-    KBDState *s = &kbd_state;
+    KBDState *s = g_malloc0(sizeof(KBDState));
 
     s->irq_kbd = kbd_irq;
     s->irq_mouse = mouse_irq;
+    s->mask = mask;
+
+    vmstate_register(NULL, 0, &vmstate_kbd, s);
 
-    kbd_reset(s);
-    register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
-    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);
+    memory_region_init_io(region, &i8042_mmio_ops, s, "i8042", size);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
-#ifdef TARGET_I386
-    vmmouse_init(s->mouse);
-#endif
     qemu_register_reset(kbd_reset, s);
 }
 
-/* Memory mapped interface */
-uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr)
+typedef struct ISAKBDState {
+    ISADevice dev;
+    KBDState kbd;
+    MemoryRegion io[2];
+} ISAKBDState;
+
+void i8042_isa_mouse_fake_event(void *opaque)
 {
-    KBDState *s = opaque;
+    ISADevice *dev = opaque;
+    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
 
-    switch ((addr - s->base) >> s->it_shift) {
-    case 0:
-        return kbd_read_data(s, 0) & 0xff;
-    case 1:
-        return kbd_read_status(s, 0) & 0xff;
-    default:
-        return 0xff;
-    }
+    ps2_mouse_fake_event(s->mouse);
 }
 
-void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out)
 {
-    KBDState *s = opaque;
+    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
 
-    switch ((addr - s->base) >> s->it_shift) {
-    case 0:
-        kbd_write_data(s, 0, value & 0xff);
-        break;
-    case 1:
-        kbd_write_command(s, 0, value & 0xff);
-        break;
-    }
+    s->a20_out = a20_out;
 }
 
-static CPUReadMemoryFunc *kbd_mm_read[] = {
-    &kbd_mm_readb,
-    &kbd_mm_readb,
-    &kbd_mm_readb,
+static const VMStateDescription vmstate_kbd_isa = {
+    .name = "pckbd",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
 };
 
-static CPUWriteMemoryFunc *kbd_mm_write[] = {
-    &kbd_mm_writeb,
-    &kbd_mm_writeb,
-    &kbd_mm_writeb,
+static const MemoryRegionOps i8042_data_ops = {
+    .read = kbd_read_data,
+    .write = kbd_write_data,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base,
-                   int it_shift)
+static const MemoryRegionOps i8042_cmd_ops = {
+    .read = kbd_read_status,
+    .write = kbd_write_command,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int i8042_initfn(ISADevice *dev)
 {
-    KBDState *s = &kbd_state;
-    int s_io_memory;
+    ISAKBDState *isa_s = DO_UPCAST(ISAKBDState, dev, dev);
+    KBDState *s = &isa_s->kbd;
 
-    s->irq_kbd = kbd_irq;
-    s->irq_mouse = mouse_irq;
-    s->base = base;
-    s->it_shift = it_shift;
+    isa_init_irq(dev, &s->irq_kbd, 1);
+    isa_init_irq(dev, &s->irq_mouse, 12);
+
+    memory_region_init_io(isa_s->io + 0, &i8042_data_ops, s, "i8042-data", 1);
+    isa_register_ioport(dev, isa_s->io + 0, 0x60);
 
-    kbd_reset(s);
-    register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
-    s_io_memory = cpu_register_io_memory(0, kbd_mm_read, kbd_mm_write, s);
-    cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+    memory_region_init_io(isa_s->io + 1, &i8042_cmd_ops, s, "i8042-cmd", 1);
+    isa_register_ioport(dev, isa_s->io + 1, 0x64);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
-#ifdef TARGET_I386
-    vmmouse_init(s->mouse);
-#endif
     qemu_register_reset(kbd_reset, s);
+    return 0;
 }
+
+static void i8042_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = i8042_initfn;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_kbd_isa;
+}
+
+static TypeInfo i8042_info = {
+    .name          = "i8042",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAKBDState),
+    .class_init    = i8042_class_initfn,
+};
+
+static void i8042_register_types(void)
+{
+    type_register_static(&i8042_info);
+}
+
+type_init(i8042_register_types)