]> git.proxmox.com Git - qemu.git/blobdiff - hw/escc.c
Merge remote-tracking branch 'luiz/queue/qmp' into staging
[qemu.git] / hw / escc.c
index 491c4cfcd962e45a9fefe044616fd611934caf84..baf02193043bb6e923ec8f960ca753ac91fb61a3 100644 (file)
--- a/hw/escc.c
+++ b/hw/escc.c
  * THE SOFTWARE.
  */
 
-#include "hw.h"
-#include "sysbus.h"
-#include "escc.h"
-#include "qemu-char.h"
-#include "console.h"
-
-/* debug serial */
-//#define DEBUG_SERIAL
-
-/* debug keyboard */
-//#define DEBUG_KBD
-
-/* debug mouse */
-//#define DEBUG_MOUSE
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/escc.h"
+#include "char/char.h"
+#include "ui/console.h"
+#include "trace.h"
 
 /*
+ * Chipset docs:
+ * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
+ * http://www.zilog.com/docs/serial/scc_escc_um.pdf
+ *
  * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
  * (Slave I/O), also produced as NCR89C105. See
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
  *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
  *                                  serial mouse queue.
  *                                  Implemented serial mouse protocol.
+ *
+ *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
  */
 
-#ifdef DEBUG_SERIAL
-#define SER_DPRINTF(fmt, ...)                                   \
-    do { printf("SER: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define SER_DPRINTF(fmt, ...)
-#endif
-#ifdef DEBUG_KBD
-#define KBD_DPRINTF(fmt, ...)                                   \
-    do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define KBD_DPRINTF(fmt, ...)
-#endif
-#ifdef DEBUG_MOUSE
-#define MS_DPRINTF(fmt, ...)                                    \
-    do { printf("MSC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define MS_DPRINTF(fmt, ...)
-#endif
-
 typedef enum {
     chn_a, chn_b,
-} chn_id_t;
+} ChnID;
 
 #define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
 
 typedef enum {
     ser, kbd, mouse,
-} chn_type_t;
+} ChnType;
 
 #define SERIO_QUEUE_SIZE 256
 
@@ -102,24 +81,26 @@ typedef struct {
 #define SERIAL_REGS 16
 typedef struct ChannelState {
     qemu_irq irq;
-    uint32_t reg;
     uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
-    chn_id_t chn; // this channel, A (base+4) or B (base+0)
-    chn_type_t type;
     struct ChannelState *otherchn;
-    uint8_t rx, tx, wregs[SERIAL_REGS], rregs[SERIAL_REGS];
+    uint32_t reg;
+    uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
     SERIOQueue queue;
     CharDriverState *chr;
     int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
     int disabled;
     int clock;
+    uint32_t vmstate_dummy;
+    ChnID chn; // this channel, A (base+4) or B (base+0)
+    ChnType type;
+    uint8_t rx, tx;
 } ChannelState;
 
 struct SerialState {
     SysBusDevice busdev;
     struct ChannelState chn[2];
     uint32_t it_shift;
-    int mmio_index;
+    MemoryRegion mmio;
     uint32_t disabled;
     uint32_t frequency;
 };
@@ -242,7 +223,7 @@ static void put_queue(void *opaque, int b)
     ChannelState *s = opaque;
     SERIOQueue *q = &s->queue;
 
-    SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
+    trace_escc_put_queue(CHN_C(s), b);
     if (q->count >= SERIO_QUEUE_SIZE)
         return;
     q->data[q->wptr] = b;
@@ -266,7 +247,7 @@ static uint32_t get_queue(void *opaque)
             q->rptr = 0;
         q->count--;
     }
-    SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
+    trace_escc_get_queue(CHN_C(s), val);
     if (q->count > 0)
         serial_receive_byte(s, 0);
     return val;
@@ -274,7 +255,7 @@ static uint32_t get_queue(void *opaque)
 
 static int escc_update_irq_chn(ChannelState *s)
 {
-    if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
+    if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
          // tx ints enabled, pending
          ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
            ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
@@ -293,7 +274,7 @@ static void escc_update_irq(ChannelState *s)
     irq = escc_update_irq_chn(s);
     irq |= escc_update_irq_chn(s->otherchn);
 
-    SER_DPRINTF("IRQ = %d\n", irq);
+    trace_escc_update_irq(irq);
     qemu_set_irq(s->irq, irq);
 }
 
@@ -326,9 +307,10 @@ static void escc_reset_chn(ChannelState *s)
     clear_queue(s);
 }
 
-static void escc_reset(void *opaque)
+static void escc_reset(DeviceState *d)
 {
-    SerialState *s = opaque;
+    SerialState *s = container_of(d, SerialState, busdev.qdev);
+
     escc_reset_chn(&s->chn[0]);
     escc_reset_chn(&s->chn[1]);
 }
@@ -336,24 +318,22 @@ static void escc_reset(void *opaque)
 static inline void set_rxint(ChannelState *s)
 {
     s->rxint = 1;
-    if (!s->txint_under_svc) {
-        s->rxint_under_svc = 1;
-        if (s->chn == chn_a) {
-            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-                s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
-            else
-                s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
-        } else {
-            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-                s->rregs[R_IVEC] = IVEC_HIRXINTB;
-            else
-                s->rregs[R_IVEC] = IVEC_LORXINTB;
-        }
-    }
-    if (s->chn == chn_a)
+    /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
+       than chn_a rx/tx/special_condition service*/
+    s->rxint_under_svc = 1;
+    if (s->chn == chn_a) {
         s->rregs[R_INTR] |= INTR_RXINTA;
-    else
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
+    } else {
         s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HIRXINTB;
+        else
+            s->rregs[R_IVEC] = IVEC_LORXINTB;
+    }
     escc_update_irq(s);
 }
 
@@ -363,19 +343,21 @@ static inline void set_txint(ChannelState *s)
     if (!s->rxint_under_svc) {
         s->txint_under_svc = 1;
         if (s->chn == chn_a) {
+            if (s->wregs[W_INTR] & INTR_TXINT) {
+                s->rregs[R_INTR] |= INTR_TXINTA;
+            }
             if (s->wregs[W_MINTR] & MINTR_STATUSHI)
                 s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
             else
                 s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
         } else {
             s->rregs[R_IVEC] = IVEC_TXINTB;
+            if (s->wregs[W_INTR] & INTR_TXINT) {
+                s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
+            }
         }
-    }
-    if (s->chn == chn_a)
-        s->rregs[R_INTR] |= INTR_TXINTA;
-    else
-        s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
     escc_update_irq(s);
+    }
 }
 
 static inline void clr_rxint(ChannelState *s)
@@ -411,6 +393,7 @@ static inline void clr_txint(ChannelState *s)
             s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
         s->rregs[R_INTR] &= ~INTR_TXINTA;
     } else {
+        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
             s->rregs[R_IVEC] = IVEC_HINOINT;
         else
@@ -476,12 +459,12 @@ static void escc_update_parameters(ChannelState *s)
     ssp.parity = parity;
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
-    SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
-                speed, parity, data_bits, stop_bits);
-    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
+    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
 
-static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void escc_mem_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
 {
     SerialState *serial = opaque;
     ChannelState *s;
@@ -494,8 +477,7 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     s = &serial->chn[channel];
     switch (saddr) {
     case SERIAL_CTRL:
-        SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
-                    val & 0xff);
+        trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
         newreg = 0;
         switch (s->reg) {
         case W_CMD:
@@ -509,10 +491,15 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
                 clr_txint(s);
                 break;
             case CMD_CLR_IUS:
-                if (s->rxint_under_svc)
-                    clr_rxint(s);
-                else if (s->txint_under_svc)
-                    clr_txint(s);
+                if (s->rxint_under_svc) {
+                    s->rxint_under_svc = 0;
+                    if (s->txint) {
+                        set_txint(s);
+                    }
+                } else if (s->txint_under_svc) {
+                    s->txint_under_svc = 0;
+                }
+                escc_update_irq(s);
                 break;
             default:
                 break;
@@ -547,7 +534,7 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
                 escc_reset_chn(&serial->chn[1]);
                 return;
             case MINTR_RST_ALL:
-                escc_reset(serial);
+                escc_reset(&serial->busdev.qdev);
                 return;
             }
             break;
@@ -560,11 +547,11 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
             s->reg = 0;
         break;
     case SERIAL_DATA:
-        SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
+        trace_escc_mem_writeb_data(CHN_C(s), val);
         s->tx = val;
         if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
             if (s->chr)
-                qemu_chr_write(s->chr, &s->tx, 1);
+                qemu_chr_fe_write(s->chr, &s->tx, 1);
             else if (s->type == kbd && !s->disabled) {
                 handle_kbd_command(s, val);
             }
@@ -578,7 +565,8 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t escc_mem_read(void *opaque, hwaddr addr,
+                              unsigned size)
 {
     SerialState *serial = opaque;
     ChannelState *s;
@@ -591,8 +579,7 @@ static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
     s = &serial->chn[channel];
     switch (saddr) {
     case SERIAL_CTRL:
-        SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
-                    s->rregs[s->reg]);
+        trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
         ret = s->rregs[s->reg];
         s->reg = 0;
         return ret;
@@ -603,7 +590,7 @@ static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
             ret = get_queue(s);
         else
             ret = s->rx;
-        SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
+        trace_escc_mem_readb_data(CHN_C(s), ret);
         if (s->chr)
             qemu_chr_accept_input(s->chr);
         return ret;
@@ -613,6 +600,16 @@ static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
+static const MemoryRegionOps escc_mem_ops = {
+    .read = escc_mem_read,
+    .write = escc_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
 static int serial_can_receive(void *opaque)
 {
     ChannelState *s = opaque;
@@ -629,7 +626,7 @@ static int serial_can_receive(void *opaque)
 
 static void serial_receive_byte(ChannelState *s, int ch)
 {
-    SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
+    trace_escc_serial_receive_byte(CHN_C(s), ch);
     s->rregs[R_STATUS] |= STATUS_RXAV;
     s->rx = ch;
     set_rxint(s);
@@ -654,78 +651,39 @@ static void serial_event(void *opaque, int event)
         serial_receive_break(s);
 }
 
-static CPUReadMemoryFunc * const escc_mem_read[3] = {
-    escc_mem_readb,
-    NULL,
-    NULL,
-};
-
-static CPUWriteMemoryFunc * const escc_mem_write[3] = {
-    escc_mem_writeb,
-    NULL,
-    NULL,
+static const VMStateDescription vmstate_escc_chn = {
+    .name ="escc_chn",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(vmstate_dummy, ChannelState),
+        VMSTATE_UINT32(reg, ChannelState),
+        VMSTATE_UINT32(rxint, ChannelState),
+        VMSTATE_UINT32(txint, ChannelState),
+        VMSTATE_UINT32(rxint_under_svc, ChannelState),
+        VMSTATE_UINT32(txint_under_svc, ChannelState),
+        VMSTATE_UINT8(rx, ChannelState),
+        VMSTATE_UINT8(tx, ChannelState),
+        VMSTATE_BUFFER(wregs, ChannelState),
+        VMSTATE_BUFFER(rregs, ChannelState),
+        VMSTATE_END_OF_LIST()
+    }
 };
 
-static void escc_save_chn(QEMUFile *f, ChannelState *s)
-{
-    uint32_t tmp = 0;
-
-    qemu_put_be32s(f, &tmp); /* unused, was IRQ.  */
-    qemu_put_be32s(f, &s->reg);
-    qemu_put_be32s(f, &s->rxint);
-    qemu_put_be32s(f, &s->txint);
-    qemu_put_be32s(f, &s->rxint_under_svc);
-    qemu_put_be32s(f, &s->txint_under_svc);
-    qemu_put_8s(f, &s->rx);
-    qemu_put_8s(f, &s->tx);
-    qemu_put_buffer(f, s->wregs, SERIAL_REGS);
-    qemu_put_buffer(f, s->rregs, SERIAL_REGS);
-}
-
-static void escc_save(QEMUFile *f, void *opaque)
-{
-    SerialState *s = opaque;
-
-    escc_save_chn(f, &s->chn[0]);
-    escc_save_chn(f, &s->chn[1]);
-}
-
-static int escc_load_chn(QEMUFile *f, ChannelState *s, int version_id)
-{
-    uint32_t tmp;
-
-    if (version_id > 2)
-        return -EINVAL;
-
-    qemu_get_be32s(f, &tmp); /* unused */
-    qemu_get_be32s(f, &s->reg);
-    qemu_get_be32s(f, &s->rxint);
-    qemu_get_be32s(f, &s->txint);
-    if (version_id >= 2) {
-        qemu_get_be32s(f, &s->rxint_under_svc);
-        qemu_get_be32s(f, &s->txint_under_svc);
+static const VMStateDescription vmstate_escc = {
+    .name ="escc",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(chn, SerialState, 2, 2, vmstate_escc_chn,
+                             ChannelState),
+        VMSTATE_END_OF_LIST()
     }
-    qemu_get_8s(f, &s->rx);
-    qemu_get_8s(f, &s->tx);
-    qemu_get_buffer(f, s->wregs, SERIAL_REGS);
-    qemu_get_buffer(f, s->rregs, SERIAL_REGS);
-    return 0;
-}
-
-static int escc_load(QEMUFile *f, void *opaque, int version_id)
-{
-    SerialState *s = opaque;
-    int ret;
-
-    ret = escc_load_chn(f, &s->chn[0], version_id);
-    if (ret != 0)
-        return ret;
-    ret = escc_load_chn(f, &s->chn[1], version_id);
-    return ret;
-
-}
+};
 
-int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
+MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
               CharDriverState *chrA, CharDriverState *chrB,
               int clock, int it_shift)
 {
@@ -741,16 +699,16 @@ int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
     qdev_prop_set_chr(dev, "chrA", chrA);
     qdev_prop_set_uint32(dev, "chnBtype", ser);
     qdev_prop_set_uint32(dev, "chnAtype", ser);
-    qdev_init(dev);
-    s = sysbus_from_qdev(dev);
-    sysbus_connect_irq(s, 0, irqA);
-    sysbus_connect_irq(s, 1, irqB);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irqB);
+    sysbus_connect_irq(s, 1, irqA);
     if (base) {
         sysbus_mmio_map(s, 0, base);
     }
 
     d = FROM_SYSBUS(SerialState, s);
-    return d->mmio_index;
+    return &d->mmio;
 }
 
 static const uint8_t keycodes[128] = {
@@ -780,8 +738,7 @@ static void sunkbd_event(void *opaque, int ch)
     ChannelState *s = opaque;
     int release = ch & 0x80;
 
-    KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" :
-                "press");
+    trace_escc_sunkbd_event_in(ch);
     switch (ch) {
     case 58: // Caps lock press
         s->caps_lock_mode ^= 1;
@@ -815,13 +772,13 @@ static void sunkbd_event(void *opaque, int ch)
     } else {
         ch = keycodes[ch & 0x7f];
     }
-    KBD_DPRINTF("Translated keycode %2.2x\n", ch);
+    trace_escc_sunkbd_event_out(ch);
     put_queue(s, ch | release);
 }
 
 static void handle_kbd_command(ChannelState *s, int val)
 {
-    KBD_DPRINTF("Command %d\n", val);
+    trace_escc_kbd_command(val);
     if (s->led_mode) { // Ignore led byte
         s->led_mode = 0;
         return;
@@ -853,8 +810,7 @@ static void sunmouse_event(void *opaque,
     ChannelState *s = opaque;
     int ch;
 
-    MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
-
+    trace_escc_sunmouse_event(dx, dy, buttons_state);
     ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
 
     if (buttons_state & MOUSE_EVENT_LBUTTON)
@@ -869,18 +825,18 @@ static void sunmouse_event(void *opaque,
     ch = dx;
 
     if (ch > 127)
-        ch=127;
+        ch = 127;
     else if (ch < -127)
-        ch=-127;
+        ch = -127;
 
     put_queue(s, ch & 0xff);
 
     ch = -dy;
 
     if (ch > 127)
-        ch=127;
+        ch = 127;
     else if (ch < -127)
-        ch=-127;
+        ch = -127;
 
     put_queue(s, ch & 0xff);
 
@@ -890,7 +846,7 @@ static void sunmouse_event(void *opaque,
     put_queue(s, 0);
 }
 
-void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
+void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
                                int disabled, int clock, int it_shift)
 {
     DeviceState *dev;
@@ -904,8 +860,8 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
     qdev_prop_set_chr(dev, "chrA", NULL);
     qdev_prop_set_uint32(dev, "chnBtype", mouse);
     qdev_prop_set_uint32(dev, "chnAtype", kbd);
-    qdev_init(dev);
-    s = sysbus_from_qdev(dev);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
     sysbus_connect_irq(s, 0, irq);
     sysbus_connect_irq(s, 1, irq);
     sysbus_mmio_map(s, 0, base);
@@ -914,7 +870,6 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
 static int escc_init1(SysBusDevice *dev)
 {
     SerialState *s = FROM_SYSBUS(SerialState, dev);
-    int io;
     unsigned int i;
 
     s->chn[0].disabled = s->disabled;
@@ -931,9 +886,9 @@ static int escc_init1(SysBusDevice *dev)
     s->chn[0].otherchn = &s->chn[1];
     s->chn[1].otherchn = &s->chn[0];
 
-    io = cpu_register_io_memory(escc_mem_read, escc_mem_write, s);
-    sysbus_init_mmio(dev, ESCC_SIZE << s->it_shift, io);
-    s->mmio_index = io;
+    memory_region_init_io(&s->mmio, &escc_mem_ops, s, "escc",
+                          ESCC_SIZE << s->it_shift);
+    sysbus_init_mmio(dev, &s->mmio);
 
     if (s->chn[0].type == mouse) {
         qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
@@ -942,32 +897,42 @@ static int escc_init1(SysBusDevice *dev)
     if (s->chn[1].type == kbd) {
         qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
     }
-    register_savevm("escc", -1, 2, escc_save, escc_load, s);
-    qemu_register_reset(escc_reset, s);
-    escc_reset(s);
+
     return 0;
 }
 
-static SysBusDeviceInfo escc_info = {
-    .init = escc_init1,
-    .qdev.name  = "escc",
-    .qdev.size  = sizeof(SerialState),
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("frequency", SerialState, frequency,   0),
-        DEFINE_PROP_UINT32("it_shift",  SerialState, it_shift,    0),
-        DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
-        DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
-        DEFINE_PROP_UINT32("chnBtype",  SerialState, chn[0].type, 0),
-        DEFINE_PROP_UINT32("chnAtype",  SerialState, chn[1].type, 0),
-        DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
-        DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property escc_properties[] = {
+    DEFINE_PROP_UINT32("frequency", SerialState, frequency,   0),
+    DEFINE_PROP_UINT32("it_shift",  SerialState, it_shift,    0),
+    DEFINE_PROP_UINT32("disabled",  SerialState, disabled,    0),
+    DEFINE_PROP_UINT32("chnBtype",  SerialState, chn[0].type, 0),
+    DEFINE_PROP_UINT32("chnAtype",  SerialState, chn[1].type, 0),
+    DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
+    DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void escc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = escc_init1;
+    dc->reset = escc_reset;
+    dc->vmsd = &vmstate_escc;
+    dc->props = escc_properties;
+}
+
+static const TypeInfo escc_info = {
+    .name          = "escc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SerialState),
+    .class_init    = escc_class_init,
 };
 
-static void escc_register_devices(void)
+static void escc_register_types(void)
 {
-    sysbus_register_withprop(&escc_info);
+    type_register_static(&escc_info);
 }
 
-device_init(escc_register_devices)
+type_init(escc_register_types)