microblaze: linux-user support.
[qemu] / hw / pl050.c
index a71ccf6..1f8878c 100644 (file)
@@ -1,26 +1,34 @@
-/* 
- * Arm PrimeCell PL050 Kyeboard / Mouse Interface
+/*
+ * Arm PrimeCell PL050 Keyboard / Mouse Interface
  *
- * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
  * This code is licenced under the GPL.
  */
 
-#include "vl.h"
+#include "sysbus.h"
+#include "ps2.h"
 
 typedef struct {
+    SysBusDevice busdev;
     void *dev;
-    uint32_t base;
     uint32_t cr;
     uint32_t clk;
     uint32_t last;
-    void *pic;
     int pending;
-    int irq;
+    qemu_irq irq;
     int is_mouse;
 } pl050_state;
 
+#define PL050_TXEMPTY         (1 << 6)
+#define PL050_TXBUSY          (1 << 5)
+#define PL050_RXFULL          (1 << 4)
+#define PL050_RXBUSY          (1 << 3)
+#define PL050_RXPARITY        (1 << 2)
+#define PL050_KMIC            (1 << 1)
+#define PL050_KMID            (1 << 0)
+
 static const unsigned char pl050_id[] =
 { 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
 
@@ -32,13 +40,12 @@ static void pl050_update(void *opaque, int level)
     s->pending = level;
     raise = (s->pending && (s->cr & 0x10) != 0)
             || (s->cr & 0x08) != 0;
-    pic_set_irq_new(s->pic, s->irq, raise);
+    qemu_set_irq(s->irq, raise);
 }
 
 static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
 {
     pl050_state *s = (pl050_state *)opaque;
-    offset -= s->base;
     if (offset >= 0xfe0 && offset < 0x1000)
         return pl050_id[(offset - 0xfe0) >> 2];
 
@@ -46,11 +53,22 @@ static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
     case 0: /* KMICR */
         return s->cr;
     case 1: /* KMISTAT */
-        /* KMIC and KMID bits not implemented.  */
-        if (s->pending) {
-            return 0x10;
-        } else {
-            return 0;
+        {
+            uint8_t val;
+            uint32_t stat;
+
+            val = s->last;
+            val = val ^ (val >> 4);
+            val = val ^ (val >> 2);
+            val = (val ^ (val >> 1)) & 1;
+
+            stat = PL050_TXEMPTY;
+            if (val)
+                stat |= PL050_RXPARITY;
+            if (s->pending)
+                stat |= PL050_RXFULL;
+
+            return stat;
         }
     case 2: /* KMIDATA */
         if (s->pending)
@@ -61,7 +79,7 @@ static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
     case 4: /* KMIIR */
         return s->pending | 2;
     default:
-        cpu_abort (cpu_single_env, "pl050_read: Bad offset %x\n", offset);
+        hw_error("pl050_read: Bad offset %x\n", (int)offset);
         return 0;
     }
 }
@@ -70,7 +88,6 @@ static void pl050_write(void *opaque, target_phys_addr_t offset,
                           uint32_t value)
 {
     pl050_state *s = (pl050_state *)opaque;
-    offset -= s->base;
     switch (offset >> 2) {
     case 0: /* KMICR */
         s->cr = value;
@@ -90,7 +107,7 @@ static void pl050_write(void *opaque, target_phys_addr_t offset,
         s->clk = value;
         return;
     default:
-        cpu_abort (cpu_single_env, "pl050_write: Bad offset %x\n", offset);
+        hw_error("pl050_write: Bad offset %x\n", (int)offset);
     }
 }
 static CPUReadMemoryFunc *pl050_readfn[] = {
@@ -105,23 +122,39 @@ static CPUWriteMemoryFunc *pl050_writefn[] = {
    pl050_write
 };
 
-void pl050_init(uint32_t base, void *pic, int irq, int is_mouse)
+static void pl050_init(SysBusDevice *dev, int is_mouse)
 {
+    pl050_state *s = FROM_SYSBUS(pl050_state, dev);
     int iomemtype;
-    pl050_state *s;
 
-    s = (pl050_state *)qemu_mallocz(sizeof(pl050_state));
     iomemtype = cpu_register_io_memory(0, pl050_readfn,
                                        pl050_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
-    s->base = base;
-    s->pic = pic;
-    s->irq = irq;
+    sysbus_init_mmio(dev, 0x1000, iomemtype);
+    sysbus_init_irq(dev, &s->irq);
     s->is_mouse = is_mouse;
-    if (is_mouse)
+    if (s->is_mouse)
         s->dev = ps2_mouse_init(pl050_update, s);
     else
         s->dev = ps2_kbd_init(pl050_update, s);
     /* ??? Save/restore.  */
 }
 
+static void pl050_init_keyboard(SysBusDevice *dev)
+{
+    pl050_init(dev, 0);
+}
+
+static void pl050_init_mouse(SysBusDevice *dev)
+{
+    pl050_init(dev, 1);
+}
+
+static void pl050_register_devices(void)
+{
+    sysbus_register_dev("pl050_keyboard", sizeof(pl050_state),
+                        pl050_init_keyboard);
+    sysbus_register_dev("pl050_mouse", sizeof(pl050_state),
+                        pl050_init_mouse);
+}
+
+device_init(pl050_register_devices)