microblaze: linux-user support.
[qemu] / hw / smc91c111.c
index 375debd..38cbd01 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;
@@ -24,8 +26,7 @@ typedef struct {
     uint16_t gpr;
     uint16_t ptr;
     uint16_t ercv;
-    void *pic;
-    int irq;
+    qemu_irq irq;
     int bank;
     int packet_num;
     int tx_alloc;
@@ -42,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
@@ -86,7 +88,7 @@ static void smc91c111_update(smc91c111_state *s)
     if (s->tx_fifo_done_len != 0)
         s->int_level |= INT_TX;
     level = (s->int_level & s->int_mask) != 0;
-    pic_set_irq_new(s->pic, s->irq, level);
+    qemu_set_irq(s->irq, level);
 }
 
 /* Try to allocate a packet.  Returns 0x80 on failure.  */
@@ -159,7 +161,6 @@ static void smc91c111_do_tx(smc91c111_state *s)
     int len;
     int control;
     int add_crc;
-    uint32_t crc;
     int packetnum;
     uint8_t *p;
 
@@ -192,6 +193,8 @@ static void smc91c111_do_tx(smc91c111_state *s)
            about.  */
         add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
         if (add_crc) {
+            uint32_t crc;
+
             crc = crc32(~0, p, len);
             memcpy(p + len, &crc, 4);
             len += 4;
@@ -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;
     }
@@ -445,7 +445,9 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
         case 7:
             /* Not implemented.  */
             return 0;
-        case 8: /* Free memory available.  */
+        case 8: /* Memory size.  */
+            return NUM_PACKETS;
+        case 9: /* Free memory available.  */
             {
                 int i;
                 int n;
@@ -456,8 +458,6 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
                 }
                 return n;
             }
-        case 9: /* Memory size.  */
-            return NUM_PACKETS;
         case 10: case 11: /* RPCR */
             /* Not implemented.  */
             return 0;
@@ -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,6 +591,17 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
     return val;
 }
 
+static int smc91c111_can_receive(void *opaque)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+
+    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
+        return 1;
+    if (s->allocated == (1 << NUM_PACKETS) - 1)
+        return 0;
+    return 1;
+}
+
 static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
 {
     smc91c111_state *s = (smc91c111_state *)opaque;
@@ -604,7 +613,7 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
 
     if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
         return;
-    /* Short packets are padded with zeros.  Recieveing a packet
+    /* Short packets are padded with zeros.  Receiving a packet
        < 64 bytes long is considered an error condition.  */
     if (size < 64)
         packetsize = 64;
@@ -638,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;
@@ -681,22 +690,52 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = {
     smc91c111_writel
 };
 
-void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq)
+static void smc91c111_cleanup(VLANClientState *vc)
 {
-    smc91c111_state *s;
-    int iomemtype;
-
-    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->pic = pic;
-    s->irq = irq;
-    memcpy(s->macaddr, nd->macaddr, 6);
+    smc91c111_state *s = vc->opaque;
+
+    cpu_unregister_io_memory(s->mmio_index);
+    qemu_free(s);
+}
+
+static void smc91c111_init1(SysBusDevice *dev)
+{
+    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
+
+    s->mmio_index = cpu_register_io_memory(0, 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, s);
+    s->vc = qdev_get_vlan_client(&dev->qdev,
+                                 smc91c111_receive, smc91c111_can_receive,
+                                 smc91c111_cleanup, s);
+    qemu_format_nic_info_str(s->vc, s->macaddr);
     /* ??? Save/restore.  */
 }
+
+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");
+    qdev_set_netdev(dev, 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)