vmstate: Add pre/post_save() hooks
[qemu] / hw / smc91c111.c
index d90ab32..a08bdb0 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * SMSC 91C111 Ethernet interface emulation
  *
  * Copyright (c) 2005 CodeSourcery, LLC.
@@ -7,7 +7,9 @@
  * This code is licenced under the GPL
  */
 
-#include "vl.h"
+#include "sysbus.h"
+#include "net.h"
+#include "devices.h"
 /* For crc32 */
 #include <zlib.h>
 
@@ -15,7 +17,7 @@
 #define NUM_PACKETS 4
 
 typedef struct {
-    uint32_t base;
+    SysBusDevice busdev;
     VLANClientState *vc;
     uint16_t tcr;
     uint16_t rcr;
@@ -41,6 +43,7 @@ typedef struct {
     uint8_t int_level;
     uint8_t int_mask;
     uint8_t macaddr[6];
+    int mmio_index;
 } smc91c111_state;
 
 #define RCR_SOFT_RST  0x8000
@@ -247,7 +250,6 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
 {
     smc91c111_state *s = (smc91c111_state *)opaque;
 
-    offset -= s->base;
     if (offset == 14) {
         s->bank = value;
         return;
@@ -412,15 +414,13 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
         }
         break;
     }
-    cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n",
-               s->bank, offset);
+    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
 }
 
 static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
 {
     smc91c111_state *s = (smc91c111_state *)opaque;
 
-    offset -= s->base;
     if (offset == 14) {
         return s->bank;
     }
@@ -554,8 +554,7 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
         }
         break;
     }
-    cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n",
-               s->bank, offset);
+    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
     return 0;
 }
 
@@ -569,10 +568,9 @@ static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
 static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
                              uint32_t value)
 {
-    smc91c111_state *s = (smc91c111_state *)opaque;
     /* 32-bit writes to offset 0xc only actually write to the bank select
        register (offset 0xe)  */
-    if (offset != s->base + 0xc)
+    if (offset != 0xc)
         smc91c111_writew(opaque, offset, value & 0xffff);
     smc91c111_writew(opaque, offset + 2, value >> 16);
 }
@@ -593,9 +591,9 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
     return val;
 }
 
-static int smc91c111_can_receive(void *opaque)
+static int smc91c111_can_receive(VLANClientState *vc)
 {
-    smc91c111_state *s = (smc91c111_state *)opaque;
+    smc91c111_state *s = vc->opaque;
 
     if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
         return 1;
@@ -604,9 +602,9 @@ static int smc91c111_can_receive(void *opaque)
     return 1;
 }
 
-static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
+static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
 {
-    smc91c111_state *s = (smc91c111_state *)opaque;
+    smc91c111_state *s = vc->opaque;
     int status;
     int packetsize;
     uint32_t crc;
@@ -614,7 +612,7 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
     uint8_t *p;
 
     if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
-        return;
+        return -1;
     /* Short packets are padded with zeros.  Receiving a packet
        < 64 bytes long is considered an error condition.  */
     if (size < 64)
@@ -627,10 +625,10 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
         packetsize += 4;
     /* TODO: Flag overrun and receive errors.  */
     if (packetsize > 2048)
-        return;
+        return -1;
     packetnum = smc91c111_allocate_packet(s);
     if (packetnum == 0x80)
-        return;
+        return -1;
     s->rx_fifo[s->rx_fifo_len++] = packetnum;
 
     p = &s->data[packetnum][0];
@@ -649,7 +647,7 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
     /* Pad short packets.  */
     if (size < 64) {
         int pad;
-        
+
         if (size & 1)
             *(p++) = buf[size - 1];
         pad = 64 - size;
@@ -678,36 +676,69 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
     /* TODO: Raise early RX interrupt?  */
     s->int_level |= INT_RCV;
     smc91c111_update(s);
+
+    return size;
 }
 
-static CPUReadMemoryFunc *smc91c111_readfn[] = {
+static CPUReadMemoryFunc * const smc91c111_readfn[] = {
     smc91c111_readb,
     smc91c111_readw,
     smc91c111_readl
 };
 
-static CPUWriteMemoryFunc *smc91c111_writefn[] = {
+static CPUWriteMemoryFunc * const smc91c111_writefn[] = {
     smc91c111_writeb,
     smc91c111_writew,
     smc91c111_writel
 };
 
-void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+static void smc91c111_cleanup(VLANClientState *vc)
+{
+    smc91c111_state *s = vc->opaque;
+
+    cpu_unregister_io_memory(s->mmio_index);
+    qemu_free(s);
+}
+
+static int smc91c111_init1(SysBusDevice *dev)
 {
-    smc91c111_state *s;
-    int iomemtype;
+    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
 
-    s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
-    iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
-                                       smc91c111_writefn, s);
-    cpu_register_physical_memory(base, 16, iomemtype);
-    s->base = base;
-    s->irq = irq;
-    memcpy(s->macaddr, nd->macaddr, 6);
+    s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
+                                           smc91c111_writefn, s);
+    sysbus_init_mmio(dev, 16, s->mmio_index);
+    sysbus_init_irq(dev, &s->irq);
+    qdev_get_macaddr(&dev->qdev, s->macaddr);
 
     smc91c111_reset(s);
 
-    s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive,
-                                 smc91c111_can_receive, s);
+    s->vc = qdev_get_vlan_client(&dev->qdev,
+                                 smc91c111_can_receive, smc91c111_receive, NULL,
+                                 smc91c111_cleanup, s);
+    qemu_format_nic_info_str(s->vc, s->macaddr);
     /* ??? Save/restore.  */
+    return 0;
+}
+
+static void smc91c111_register_devices(void)
+{
+    sysbus_register_dev("smc91c111", sizeof(smc91c111_state), smc91c111_init1);
 }
+
+/* Legacy helper function.  Should go away when machine config files are
+   implemented.  */
+void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    qemu_check_nic_model(nd, "smc91c111");
+    dev = qdev_create(NULL, "smc91c111");
+    dev->nd = nd;
+    qdev_init(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+device_init(smc91c111_register_devices)