Index: Makefile.target
===================================================================
--- Makefile.target	(revision 4734)
+++ Makefile.target	(working copy)
@@ -466,7 +466,7 @@
 # System emulator target
 ifndef CONFIG_USER_ONLY
 
-OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o
+OBJS=vl.o osdep.o device.o monitor.o pci.o loader.o isa_mmio.o machine.o
 ifdef CONFIG_WIN32
 OBJS+=block-raw-win32.o
 else
Index: vl.c
===================================================================
--- vl.c	(revision 4734)
+++ vl.c	(working copy)
@@ -29,6 +29,11 @@
 #include "hw/audiodev.h"
 #include "hw/isa.h"
 #include "hw/baum.h"
+#include "hw/pci.h"
+#include "hw/mcf.h"
+#include "hw/devices.h"
+#include "hw/arm-misc.h"
+#include "hw/mips.h"
 #include "net.h"
 #include "console.h"
 #include "sysemu.h"
@@ -170,27 +175,18 @@
 int vga_ram_size;
 static DisplayState display_state;
 int nographic;
-int curses;
 const char* keyboard_layout = NULL;
 int64_t ticks_per_sec;
 ram_addr_t ram_size;
 int pit_min_timer_count = 0;
-int nb_nics;
-NICInfo nd_table[MAX_NICS];
 int vm_running;
 static int rtc_utc = 1;
 static int rtc_date_offset = -1; /* -1 means no change */
 int cirrus_vga_enabled = 1;
 int vmsvga_enabled = 0;
-#ifdef TARGET_SPARC
-int graphic_width = 1024;
-int graphic_height = 768;
-int graphic_depth = 8;
-#else
-int graphic_width = 800;
-int graphic_height = 600;
-int graphic_depth = 15;
-#endif
+int graphic_width;
+int graphic_height;
+int graphic_depth;
 int full_screen = 0;
 int no_frame = 0;
 int no_quit = 0;
@@ -239,6 +235,8 @@
 static CPUState *cur_cpu;
 static CPUState *next_cpu;
 static int event_pending = 1;
+QEMUDevice *qemu_prefs;
+QEMUDevice *machine_dev;
 
 #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
 
@@ -3816,18 +3814,6 @@
     slirp_input(buf, size);
 }
 
-static int net_slirp_init(VLANState *vlan)
-{
-    if (!slirp_inited) {
-        slirp_inited = 1;
-        slirp_init();
-    }
-    slirp_vc = qemu_new_vlan_client(vlan,
-                                    slirp_receive, NULL, NULL);
-    snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector");
-    return 0;
-}
-
 static void net_slirp_redir(const char *redir_str)
 {
     int is_udp;
@@ -3971,6 +3957,58 @@
 }
 
 #endif /* !defined(_WIN32) */
+
+#define SLIRP_MAX_REDIRS 8
+
+static int net_slirp_init(QEMUDevice *dev)
+{
+    VLANState *vlan;
+    int vlan_id, i;
+    const char *str;
+    char buf[128];
+
+    vlan_id = qemu_device_get_int(dev, "vlan");
+    vlan = qemu_find_vlan(vlan_id);
+    if (!vlan) {
+        fprintf(stderr, "Could not create vlan %d\n", vlan_id);
+        return -1;
+    }
+    if (!slirp_inited) {
+        slirp_inited = 1;
+        slirp_init();
+    }
+    str = qemu_device_get_str(dev, "hostname");
+    if (str[0] != '\0') {
+        pstrcpy(slirp_hostname, sizeof(slirp_hostname), str);
+    }
+    str = qemu_device_get_str(dev, "tftp");
+    if (str[0] != '\0')
+        tftp_prefix = str;
+    str = qemu_device_get_str(dev, "bootp");
+    if (str[0] != '\0')
+        bootp_filename = str;
+#if !defined(_WIN32)
+    str = qemu_device_get_str(dev, "smb");
+    if (str[0] != '\0') {
+        net_slirp_smb(str);
+    }
+#endif
+    
+    for(i = 0; i < SLIRP_MAX_REDIRS; i++) {
+        snprintf(buf, sizeof(buf), "redir%d", i);
+        str = qemu_device_get_str(dev, buf);
+        if (str[0] == '\0') 
+            break;
+        net_slirp_redir(str);
+    }
+    
+    slirp_vc = qemu_new_vlan_client(vlan,
+                                    slirp_receive, NULL, NULL);
+    snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector");
+    vlan->nb_host_devs++;
+    return 0;
+}
+
 void do_info_slirp(void)
 {
     slirp_stats();
@@ -4286,8 +4324,61 @@
     return 0;
 }
 
+static int net_tap_init2(QEMUDevice *dev)
+{
+    VLANState *vlan;
+    int vlan_id;
+    const char *ifname, *setup_script, *down_script;
+    int fd;
+
+    vlan_id = qemu_device_get_int(dev, "vlan");
+    vlan = qemu_find_vlan(vlan_id);
+    if (!vlan) {
+        fprintf(stderr, "Could not create vlan %d\n", vlan_id);
+        return -1;
+    }
+    vlan->nb_host_devs++;
+
+    fd = qemu_device_get_int(dev, "fd");
+    if (fd >= 0) {
+        fcntl(fd, F_SETFL, O_NONBLOCK);
+        if (net_tap_fd_init(vlan, fd))
+            return 0;
+        else
+            return -1;
+    } else {
+        ifname = qemu_device_get_str(dev, "ifname");
+        setup_script = qemu_device_get_str(dev, "script");
+        if (setup_script[0] == '\0')
+            setup_script = DEFAULT_NETWORK_SCRIPT;
+        down_script = qemu_device_get_str(dev, "downscript");
+        if (down_script[0] == '\0')
+            down_script = DEFAULT_NETWORK_DOWN_SCRIPT;
+        return net_tap_init(vlan, ifname, setup_script, down_script);
+    }
+}
+
 #endif /* !_WIN32 */
 
+#ifdef _WIN32
+static int net_tap_init2(QEMUDevice *dev)
+{
+    VLANState *vlan;
+    int vlan_id;
+    const char *ifname;
+
+    vlan_id = qemu_device_get_int(dev, "vlan");
+    vlan = qemu_find_vlan(vlan_id);
+    if (!vlan) {
+        fprintf(stderr, "Could not create vlan %d\n", vlan_id);
+        return -1;
+    }
+    vlan->nb_host_devs++;
+    ifname = qemu_device_get_str(dev, "ifname");
+    return tap_win32_init(vlan, ifname);
+}
+#endif
+
 /* network connection */
 typedef struct NetSocketState {
     VLANClientState *vc;
@@ -4701,8 +4792,43 @@
 
 }
 
-static const char *get_opt_name(char *buf, int buf_size, const char *p)
+int net_socket_init(QEMUDevice *dev)
 {
+    VLANState *vlan;
+    int vlan_id, fd, ret;
+    const char *listen_str, *connect_str, *mcast_str;
+    vlan_id = qemu_device_get_int(dev, "vlan");
+    vlan = qemu_find_vlan(vlan_id);
+    if (!vlan) {
+        fprintf(stderr, "Could not create vlan %d\n", vlan_id);
+        return -1;
+    }
+    fd = qemu_device_get_int(dev, "fd");
+    listen_str = qemu_device_get_str(dev, "listen");
+    connect_str = qemu_device_get_str(dev, "connect");
+    mcast_str = qemu_device_get_str(dev, "mcast");
+    ret = -1;
+
+    if (fd >= 0) {
+        if (net_socket_fd_init(vlan, fd, 1))
+            ret = 0;
+    } else if (listen_str[0] != '\0') {
+        ret = net_socket_listen_init(vlan, listen_str);
+    } else if (connect_str[0] != '\0') {
+        ret = net_socket_connect_init(vlan, connect_str);
+    } else if (mcast_str[0] != '\0') {
+        ret = net_socket_mcast_init(vlan, mcast_str);
+    } else {
+        fprintf(stderr, "%s: no socket connection specified\n", dev->name);
+        return -1;
+    }
+    if (ret == 0)
+        vlan->nb_host_devs++;
+    return ret;
+}
+
+const char *get_opt_name(char *buf, int buf_size, const char *p)
+{
     char *q;
 
     q = buf;
@@ -4717,7 +4843,7 @@
     return p;
 }
 
-static const char *get_opt_value(char *buf, int buf_size, const char *p)
+const char *get_opt_value(char *buf, int buf_size, const char *p)
 {
     char *q;
 
@@ -4738,8 +4864,8 @@
     return p;
 }
 
-static int get_param_value(char *buf, int buf_size,
-                           const char *tag, const char *str)
+int get_param_value(char *buf, int buf_size,
+                    const char *tag, const char *str)
 {
     const char *p;
     char option[128];
@@ -4763,40 +4889,16 @@
     return 0;
 }
 
-static int check_params(char *buf, int buf_size,
-                        char **params, const char *str)
-{
-    const char *p;
-    int i;
+static QEMUMachine *find_machine(const char *name);
 
-    p = str;
-    for(;;) {
-        p = get_opt_name(buf, buf_size, p);
-        if (*p != '=')
-            return -1;
-        p++;
-        for(i = 0; params[i] != NULL; i++)
-            if (!strcmp(params[i], buf))
-                break;
-        if (params[i] == NULL)
-            return -1;
-        p = get_opt_value(NULL, 0, p);
-        if (*p != ',')
-            break;
-        p++;
-    }
-    return 0;
-}
-
-
-static int net_client_init(const char *str)
+static int net_add(const char *str)
 {
     const char *p;
     char *q;
     char device[64];
     char buf[1024];
-    int vlan_id, ret;
-    VLANState *vlan;
+    QEMUDevice *dev;
+    QEMUDeviceClass *dc;
 
     p = str;
     q = device;
@@ -4808,124 +4910,50 @@
     *q = '\0';
     if (*p == ',')
         p++;
-    vlan_id = 0;
-    if (get_param_value(buf, sizeof(buf), "vlan", p)) {
-        vlan_id = strtol(buf, NULL, 0);
-    }
-    vlan = qemu_find_vlan(vlan_id);
-    if (!vlan) {
-        fprintf(stderr, "Could not create vlan %d\n", vlan_id);
-        return -1;
-    }
     if (!strcmp(device, "nic")) {
-        NICInfo *nd;
-        uint8_t *macaddr;
-
-        if (nb_nics >= MAX_NICS) {
-            fprintf(stderr, "Too Many NICs\n");
-            return -1;
-        }
-        nd = &nd_table[nb_nics];
-        macaddr = nd->macaddr;
-        macaddr[0] = 0x52;
-        macaddr[1] = 0x54;
-        macaddr[2] = 0x00;
-        macaddr[3] = 0x12;
-        macaddr[4] = 0x34;
-        macaddr[5] = 0x56 + nb_nics;
-
-        if (get_param_value(buf, sizeof(buf), "macaddr", p)) {
-            if (parse_macaddr(macaddr, buf) < 0) {
-                fprintf(stderr, "invalid syntax for ethernet address\n");
+        if (get_param_value(buf, sizeof(buf), "model", p) <= 0) {
+            /* no network card, get a default */
+            QEMUMachine *machine;
+            machine = find_machine(machine_dev->dev_class->name);
+            if (machine->default_nic_model) {
+                pstrcpy(buf, sizeof(buf), machine->default_nic_model);
+            } else {
+                fprintf(stderr, "You must specify the NIC model\n");
                 return -1;
             }
         }
-        if (get_param_value(buf, sizeof(buf), "model", p)) {
-            nd->model = strdup(buf);
+        dc = qemu_class_find(buf);
+        if (!dc) {
+            fprintf(stderr, "unknown network device '%s'\n", buf);
+            return -1;
         }
-        nd->vlan = vlan;
-        nb_nics++;
-        vlan->nb_guest_devs++;
-        ret = 0;
+        dev = qemu_device_new_nodup(dc, "nic");
+        if (qemu_device_set_params(dev, p, "model=!") < 0) {
+            fprintf(stderr, "Invalid network device options '%s'\n", p);
+            return -1;
+        }
     } else
     if (!strcmp(device, "none")) {
         /* does nothing. It is needed to signal that no network cards
            are wanted */
-        ret = 0;
-    } else
-#ifdef CONFIG_SLIRP
-    if (!strcmp(device, "user")) {
-        if (get_param_value(buf, sizeof(buf), "hostname", p)) {
-            pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf);
-        }
-        vlan->nb_host_devs++;
-        ret = net_slirp_init(vlan);
-    } else
-#endif
-#ifdef _WIN32
-    if (!strcmp(device, "tap")) {
-        char ifname[64];
-        if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
-            fprintf(stderr, "tap: no interface name\n");
+    } else {
+        if (!strcmp(device, "user")) {
+            dc = qemu_class_find("net-user");
+        } else if (!strcmp(device, "tap")) {
+            dc = qemu_class_find("net-tap");
+        } else if (!strcmp(device, "socket")) {
+            dc = qemu_class_find("net-socket");
+        } else {
+            fprintf(stderr, "Unknown network device: %s\n", device);
             return -1;
         }
-        vlan->nb_host_devs++;
-        ret = tap_win32_init(vlan, ifname);
-    } else
-#else
-    if (!strcmp(device, "tap")) {
-        char ifname[64];
-        char setup_script[1024], down_script[1024];
-        int fd;
-        vlan->nb_host_devs++;
-        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
-            fd = strtol(buf, NULL, 0);
-            fcntl(fd, F_SETFL, O_NONBLOCK);
-            ret = -1;
-            if (net_tap_fd_init(vlan, fd))
-                ret = 0;
-        } else {
-            if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
-                ifname[0] = '\0';
-            }
-            if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
-                pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
-            }
-            if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) {
-                pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT);
-            }
-            ret = net_tap_init(vlan, ifname, setup_script, down_script);
-        }
-    } else
-#endif
-    if (!strcmp(device, "socket")) {
-        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
-            int fd;
-            fd = strtol(buf, NULL, 0);
-            ret = -1;
-            if (net_socket_fd_init(vlan, fd, 1))
-                ret = 0;
-        } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) {
-            ret = net_socket_listen_init(vlan, buf);
-        } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
-            ret = net_socket_connect_init(vlan, buf);
-        } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
-            ret = net_socket_mcast_init(vlan, buf);
-        } else {
-            fprintf(stderr, "Unknown socket options: %s\n", p);
+        dev = qemu_device_new_nodup(dc, "net");
+        if (qemu_device_set_params(dev, p, "") < 0) {
+            fprintf(stderr, "Invalid network device options\n");
             return -1;
         }
-        vlan->nb_host_devs++;
-    } else
-    {
-        fprintf(stderr, "Unknown network device: %s\n", device);
-        return -1;
     }
-    if (ret < 0) {
-        fprintf(stderr, "Could not initialize device '%s'\n", device);
-    }
-
-    return ret;
+    return 0;
 }
 
 void do_info_network(void)
@@ -4951,21 +4979,112 @@
 #define MTD_ALIAS "if=mtd"
 #define SD_ALIAS "index=0,if=sd"
 
+
+static int drive_get_type(BlockInterfaceType *ptype,
+                          int *pmax_devs, 
+                          const char *str)
+{
+    BlockInterfaceType type;
+    int max_devs;
+
+    if (!strcmp(str, "ide")) {
+        type = IF_IDE;
+        max_devs = MAX_IDE_DEVS;
+    } else if (!strcmp(str, "scsi")) {
+        type = IF_SCSI;
+        max_devs = MAX_SCSI_DEVS;
+    } else if (!strcmp(str, "floppy")) {
+        type = IF_FLOPPY;
+        max_devs = 0;
+    } else if (!strcmp(str, "pflash")) {
+        type = IF_PFLASH;
+        max_devs = 0;
+    } else if (!strcmp(str, "mtd")) {
+        type = IF_MTD;
+        max_devs = 0;
+    } else if (!strcmp(str, "sd")) {
+        type = IF_SD;
+        max_devs = 0;
+    } else {
+        return -1;
+    }
+    if (ptype)
+        *ptype = type;
+    if (pmax_devs)
+        *pmax_devs = max_devs;
+    return 0;
+}
+
 static int drive_add(const char *file, const char *fmt, ...)
 {
     va_list ap;
+    BlockInterfaceType type;
+    int max_devs;
+    char buf[1024], opt_value[1024];
+    QEMUDeviceClass *dc;
+    QEMUDevice *dev;
 
-    if (nb_drives_opt >= MAX_DRIVES) {
-        fprintf(stderr, "qemu: too many drives\n");
-        exit(1);
-    }
-
-    drives_opt[nb_drives_opt].file = file;
     va_start(ap, fmt);
-    vsnprintf(drives_opt[nb_drives_opt].opt,
-              sizeof(drives_opt[0].opt), fmt, ap);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
     va_end(ap);
+    
+    /* find type */
+    if (get_param_value(opt_value, sizeof(opt_value), "if", buf) <= 0) {
+        const char *name;
+        name = machine_dev->dev_class->name;
+        if (!strcmp(name, "realview") ||
+            !strcmp(name, "SS-5") ||
+            !strcmp(name, "SS-10") ||
+            !strcmp(name, "SS-600MP") ||
+            !strcmp(name, "versatilepb") ||
+            !strcmp(name, "versatileab")) {
+            pstrcpy(opt_value, sizeof(opt_value), "scsi");
+        } else {
+            pstrcpy(opt_value, sizeof(opt_value), "ide");
+        }
+    }
+    
+    if (drive_get_type(&type, &max_devs, opt_value) < 0) {
+        fprintf(stderr, "Invalid drive type '%s'\n", opt_value);
+        return -1;
+    }
 
+    dc = qemu_class_find(opt_value);
+    if (!dc) 
+        return -1;
+
+#if 0
+    {
+        const char *mediastr;
+        /* XXX: could compute a better default device name */
+        if (type == IF_IDE || type == IF_SCSI) {
+            mediastr = qemu_device_get_str(dev, "media");
+            if (!strcmp("cdrom"))
+                mediastr = "_cd";
+            else
+                mediastr = "_hd";
+        } else {
+            mediastr = "";
+        }
+        if (max_devs)
+            snprintf(dev_name, sizeof(dev_name), "%s%i%s%i",
+                     dc->name, bus_id, mediastr, unit_id);
+        else
+            snprintf(dev_name, sizeof(dev_name), "%s%s%i",
+                     dc->name, mediastr, unit_id);
+    }
+#endif
+    dev = qemu_device_new_nodup(dc, "drive");
+
+    if (qemu_device_set_params(dev, buf, "if=!") < 0) {
+        fprintf(stderr, "Invalid drive options\n");
+        return -1;
+    }
+
+    if (file) {
+        qemu_device_set_str(dev, "file", file);
+    }
+
     return nb_drives_opt++;
 }
 
@@ -5003,13 +5122,8 @@
     fprintf(stderr, " %s", name);
 }
 
-static int drive_init(struct drive_opt *arg, int snapshot,
-                      QEMUMachine *machine)
+static int drive_init(QEMUDevice *dev)
 {
-    char buf[128];
-    char file[1024];
-    char devname[128];
-    const char *mediastr = "";
     BlockInterfaceType type;
     enum { MEDIA_DISK, MEDIA_CDROM } media;
     int bus_id, unit_id;
@@ -5020,202 +5134,118 @@
     int index;
     int cache;
     int bdrv_flags;
-    char *str = arg->opt;
-    char *params[] = { "bus", "unit", "if", "index", "cyls", "heads",
-                       "secs", "trans", "media", "snapshot", "file",
-                       "cache", "format", NULL };
+    const char *str, *file;
+    int snapshot;
 
-    if (check_params(buf, sizeof(buf), params, str) < 0) {
-         fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
-                         buf, str);
-         return -1;
-    }
-
-    file[0] = 0;
-    cyls = heads = secs = 0;
-    bus_id = 0;
-    unit_id = -1;
-    translation = BIOS_ATA_TRANSLATION_AUTO;
-    index = -1;
-    cache = 1;
-
-    if (!strcmp(machine->name, "realview") ||
-        !strcmp(machine->name, "SS-5") ||
-        !strcmp(machine->name, "SS-10") ||
-        !strcmp(machine->name, "SS-600MP") ||
-        !strcmp(machine->name, "versatilepb") ||
-        !strcmp(machine->name, "versatileab")) {
-        type = IF_SCSI;
-        max_devs = MAX_SCSI_DEVS;
-        strcpy(devname, "scsi");
-    } else {
-        type = IF_IDE;
-        max_devs = MAX_IDE_DEVS;
-        strcpy(devname, "ide");
-    }
-    media = MEDIA_DISK;
-
     /* extract parameters */
 
-    if (get_param_value(buf, sizeof(buf), "bus", str)) {
-        bus_id = strtol(buf, NULL, 0);
-	if (bus_id < 0) {
-	    fprintf(stderr, "qemu: '%s' invalid bus id\n", str);
-	    return -1;
-	}
-    }
+    if (drive_get_type(&type, &max_devs, dev->dev_class->name) < 0)
+        return -1;
 
-    if (get_param_value(buf, sizeof(buf), "unit", str)) {
-        unit_id = strtol(buf, NULL, 0);
-	if (unit_id < 0) {
-	    fprintf(stderr, "qemu: '%s' invalid unit id\n", str);
-	    return -1;
-	}
-    }
+    bus_id = qemu_device_get_int(dev, "bus");
+    if (bus_id < 0)
+        return -1;
 
-    if (get_param_value(buf, sizeof(buf), "if", str)) {
-        pstrcpy(devname, sizeof(devname), buf);
-        if (!strcmp(buf, "ide")) {
-	    type = IF_IDE;
-            max_devs = MAX_IDE_DEVS;
-        } else if (!strcmp(buf, "scsi")) {
-	    type = IF_SCSI;
-            max_devs = MAX_SCSI_DEVS;
-        } else if (!strcmp(buf, "floppy")) {
-	    type = IF_FLOPPY;
-            max_devs = 0;
-        } else if (!strcmp(buf, "pflash")) {
-	    type = IF_PFLASH;
-            max_devs = 0;
-	} else if (!strcmp(buf, "mtd")) {
-	    type = IF_MTD;
-            max_devs = 0;
-	} else if (!strcmp(buf, "sd")) {
-	    type = IF_SD;
-            max_devs = 0;
-	} else {
-            fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
-            return -1;
-	}
-    }
+    unit_id = qemu_device_get_int(dev, "unit");
+    if (unit_id < 0 && unit_id != -1)
+        return -1;
 
-    if (get_param_value(buf, sizeof(buf), "index", str)) {
-        index = strtol(buf, NULL, 0);
-	if (index < 0) {
-	    fprintf(stderr, "qemu: '%s' invalid index\n", str);
-	    return -1;
-	}
+    index = qemu_device_get_int(dev, "index");
+    if (index < 0 && index != -1)
+        return -1;
+    
+    cyls = heads = secs = 0;
+    translation = BIOS_ATA_TRANSLATION_AUTO;
+    if (type == IF_IDE || type == IF_SCSI) {
+        cyls = qemu_device_get_int(dev, "cyls");
+        heads = qemu_device_get_int(dev, "heads");
+        secs = qemu_device_get_int(dev, "secs");
+        
+        if (cyls || heads || secs) {
+            if (cyls < 1 || cyls > 16383) {
+                fprintf(stderr, "qemu: '%d' invalid physical cyls number\n", cyls);
+                return -1;
+            }
+            if (heads < 1 || heads > 16) {
+                fprintf(stderr, "qemu: '%d' invalid physical heads number\n", heads);
+                return -1;
+            }
+            if (secs < 1 || secs > 63) {
+                fprintf(stderr, "qemu: '%d' invalid physical secs number\n", secs);
+                return -1;
+            }
+        }
+        
+        str = qemu_device_get_str(dev, "trans");
+        if (str[0] != '\0') {
+            if (!cyls) {
+                fprintf(stderr,
+                        "qemu: '%s' trans must be used with cyls,heads and secs\n",
+                        str);
+                return -1;
+            }
+            if (!strcmp(str, "none"))
+                translation = BIOS_ATA_TRANSLATION_NONE;
+            else if (!strcmp(str, "lba"))
+                translation = BIOS_ATA_TRANSLATION_LBA;
+            else if (!strcmp(str, "auto"))
+                translation = BIOS_ATA_TRANSLATION_AUTO;
+            else {
+                fprintf(stderr, "qemu: '%s' invalid translation type\n", str);
+                return -1;
+            }
+        }
     }
 
-    if (get_param_value(buf, sizeof(buf), "cyls", str)) {
-        cyls = strtol(buf, NULL, 0);
-    }
 
-    if (get_param_value(buf, sizeof(buf), "heads", str)) {
-        heads = strtol(buf, NULL, 0);
-    }
-
-    if (get_param_value(buf, sizeof(buf), "secs", str)) {
-        secs = strtol(buf, NULL, 0);
-    }
-
-    if (cyls || heads || secs) {
-        if (cyls < 1 || cyls > 16383) {
-            fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str);
-	    return -1;
-	}
-        if (heads < 1 || heads > 16) {
-            fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str);
-	    return -1;
-	}
-        if (secs < 1 || secs > 63) {
-            fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str);
-	    return -1;
-	}
-    }
-
-    if (get_param_value(buf, sizeof(buf), "trans", str)) {
-        if (!cyls) {
-            fprintf(stderr,
-                    "qemu: '%s' trans must be used with cyls,heads and secs\n",
-                    str);
-            return -1;
-        }
-        if (!strcmp(buf, "none"))
-            translation = BIOS_ATA_TRANSLATION_NONE;
-        else if (!strcmp(buf, "lba"))
-            translation = BIOS_ATA_TRANSLATION_LBA;
-        else if (!strcmp(buf, "auto"))
-            translation = BIOS_ATA_TRANSLATION_AUTO;
-	else {
-            fprintf(stderr, "qemu: '%s' invalid translation type\n", str);
-	    return -1;
-	}
-    }
-
-    if (get_param_value(buf, sizeof(buf), "media", str)) {
-        if (!strcmp(buf, "disk")) {
-	    media = MEDIA_DISK;
-	} else if (!strcmp(buf, "cdrom")) {
+    str = qemu_device_get_str(dev, "media");
+    if (str[0] != '\0') {
+        if (!strcmp(str, "disk")) {
+            media = MEDIA_DISK;
+        } else if (!strcmp(str, "cdrom")) {
             if (cyls || secs || heads) {
                 fprintf(stderr,
                         "qemu: '%s' invalid physical CHS format\n", str);
-	        return -1;
+                return -1;
             }
-	    media = MEDIA_CDROM;
-	} else {
-	    fprintf(stderr, "qemu: '%s' invalid media\n", str);
-	    return -1;
-	}
+            media = MEDIA_CDROM;
+        } else {
+            fprintf(stderr, "qemu: '%s' invalid media\n", str);
+            return -1;
+        }
+    } else {
+        media = MEDIA_DISK;
     }
 
-    if (get_param_value(buf, sizeof(buf), "snapshot", str)) {
-        if (!strcmp(buf, "on"))
-	    snapshot = 1;
-        else if (!strcmp(buf, "off"))
-	    snapshot = 0;
-	else {
-	    fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str);
-	    return -1;
-	}
-    }
+    snapshot = qemu_device_get_bool(dev, "snapshot") ||
+        qemu_device_get_bool(machine_dev, "snapshot");
 
-    if (get_param_value(buf, sizeof(buf), "cache", str)) {
-        if (!strcmp(buf, "off"))
-            cache = 0;
-        else if (!strcmp(buf, "on"))
-            cache = 1;
-        else {
-           fprintf(stderr, "qemu: invalid cache option\n");
-           return -1;
-        }
-    }
+    cache = qemu_device_get_bool(dev, "cache");
 
-    if (get_param_value(buf, sizeof(buf), "format", str)) {
-       if (strcmp(buf, "?") == 0) {
+    str = qemu_device_get_str(dev, "format");
+    if (str[0] != '\0') {
+        if (strcmp(str, "?") == 0) {
             fprintf(stderr, "qemu: Supported formats:");
             bdrv_iterate_format(bdrv_format_print, NULL);
             fprintf(stderr, "\n");
 	    return -1;
         }
-        drv = bdrv_find_format(buf);
+        drv = bdrv_find_format(str);
         if (!drv) {
-            fprintf(stderr, "qemu: '%s' invalid format\n", buf);
+            fprintf(stderr, "qemu: '%s' invalid format\n", str);
             return -1;
         }
     }
 
-    if (arg->file == NULL)
-        get_param_value(file, sizeof(file), "file", str);
-    else
-        pstrcpy(file, sizeof(file), arg->file);
+    file = qemu_device_get_str(dev, "file");
 
     /* compute bus and unit according index */
 
     if (index != -1) {
         if (bus_id != 0 || unit_id != -1) {
             fprintf(stderr,
-                    "qemu: '%s' index cannot be used with bus and unit\n", str);
+                    "qemu: '%d' index cannot be used with bus and unit\n", 
+                    index);
             return -1;
         }
         if (max_devs == 0)
@@ -5259,16 +5289,7 @@
         return 0;
 
     /* init */
-
-    if (type == IF_IDE || type == IF_SCSI)
-        mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
-    if (max_devs)
-        snprintf(buf, sizeof(buf), "%s%i%s%i",
-                 devname, bus_id, mediastr, unit_id);
-    else
-        snprintf(buf, sizeof(buf), "%s%s%i",
-                 devname, mediastr, unit_id);
-    bdrv = bdrv_new(buf);
+    bdrv = bdrv_new(dev->name);
     drives_table[nb_drives].bdrv = bdrv;
     drives_table[nb_drives].type = type;
     drives_table[nb_drives].bus = bus_id;
@@ -5332,11 +5353,38 @@
     free_usb_ports = port;
 }
 
+static int usb_device_add_dev(USBDevice *dev)
+{
+    USBPort *port;
+
+    /* Find a USB port to add the device to.  */
+    port = free_usb_ports;
+    if (!port)
+        return -1;
+    if (!port->next) {
+        USBDevice *hub;
+
+        /* Create a new hub and chain it on.  */
+        free_usb_ports = NULL;
+        port->next = used_usb_ports;
+        used_usb_ports = port;
+
+        hub = usb_hub_init(VM_USB_HUB_SIZE);
+        usb_attach(port, hub);
+        port = free_usb_ports;
+    }
+
+    free_usb_ports = port->next;
+    port->next = used_usb_ports;
+    used_usb_ports = port;
+    usb_attach(port, dev);
+    return 0;
+}
+
 static int usb_device_add(const char *devname)
 {
     const char *p;
     USBDevice *dev;
-    USBPort *port;
 
     if (!free_usb_ports)
         return -1;
@@ -5364,29 +5412,70 @@
     }
     if (!dev)
         return -1;
+    return usb_device_add_dev(dev);
+}
 
-    /* Find a USB port to add the device to.  */
-    port = free_usb_ports;
-    if (!port->next) {
-        USBDevice *hub;
+static void usb_device_add_cmdline(const char *devname)
+{
+    QEMUDevice *dev;
+    const char *p;
 
-        /* Create a new hub and chain it on.  */
-        free_usb_ports = NULL;
-        port->next = used_usb_ports;
-        used_usb_ports = port;
+    if (strstart(devname, "host:", &p)) {
+        dev = qemu_device_new_nodup(qemu_class_find("usb-host"), "usb");
+        qemu_device_set_str(dev, "host_device", p);
+    } else if (!strcmp(devname, "mouse")) {
+        dev = qemu_device_new_nodup(qemu_class_find("usb-mouse"), "usb");
+    } else if (!strcmp(devname, "tablet")) {
+        dev = qemu_device_new_nodup(qemu_class_find("usb-tablet"), "usb");
+    } else if (!strcmp(devname, "keyboard")) {
+        dev = qemu_device_new_nodup(qemu_class_find("usb-keyboard"), "usb");
+    } else if (strstart(devname, "disk:", &p)) {
+        dev = qemu_device_new_nodup(qemu_class_find("usb-msd"), "usb");
+        qemu_device_set_str(dev, "file", p);
+    } else if (!strcmp(devname, "wacom-tablet")) {
+        dev = qemu_device_new_nodup(qemu_class_find("usb-wacom-tablet"), "usb");
+    } else if (strstart(devname, "serial:", &p)) {
+        dev = qemu_device_new_nodup(qemu_class_find("usb-serial"), "usb");
+        qemu_device_set_str(dev, "device", p);
+#ifdef CONFIG_BRLAPI
+    } else if (!strcmp(devname, "braille")) {
+        dev = qemu_device_new_nodup(qemu_class_find("usb-braille"), "usb");
+#endif
+    } else {
+        fprintf(stderr, "Warning: could not add USB device %s\n",
+                devname);
+    }
+}
 
-        hub = usb_hub_init(VM_USB_HUB_SIZE);
-        usb_attach(port, hub);
-        port = free_usb_ports;
+/* XXX: should be handled in each device */
+static int usb_device_init(QEMUDevice *dev)
+{
+    USBDevice *(*usb_dev_init)(void);
+    const char *str;
+    USBDevice *usb_dev;
+
+    if (!free_usb_ports)
+        return -1;
+
+    if (!strcmp(dev->dev_class->name, "usb-host")) {
+        str = qemu_device_get_str(dev, "host_device");
+        usb_dev = usb_host_device_open(str);
+    } else if (!strcmp(dev->dev_class->name, "usb-msd")) {
+        str = qemu_device_get_str(dev, "file");
+        usb_dev = usb_msd_init(str);
+    } else if (!strcmp(dev->dev_class->name, "usb-serial")) {
+        str = qemu_device_get_str(dev, "device");
+        usb_dev = usb_serial_init(str);
+    } else {
+        usb_dev_init = dev->dev_class->opaque;
+        usb_dev = usb_dev_init();
     }
-
-    free_usb_ports = port->next;
-    port->next = used_usb_ports;
-    used_usb_ports = port;
-    usb_attach(port, dev);
-    return 0;
+    if (!usb_dev)
+        return -1;
+    return usb_device_add_dev(usb_dev);
 }
 
+
 static int usb_device_del(const char *devname)
 {
     USBPort *port;
@@ -5850,6 +5939,41 @@
     return size1 - size;
 }
 
+/* Same as qemu_get_byte but return EOF (-1) at end of file */
+int qemu_getc(QEMUFile *f)
+{
+    if (f->buf_index >= f->buf_size) {
+        qemu_fill_buffer(f);
+        if (f->buf_index >= f->buf_size)
+            return -1;
+    }
+    return f->buf[f->buf_index++];
+}
+
+/* Return EOF (-1) if end of file reached */
+int qemu_get_line(QEMUFile *f, char *buf, int buf_size)
+{
+    char *q;
+    int c;
+    q = buf;
+    for(;;) {
+        c = qemu_getc(f);
+        if (c == '\n') {
+            break;
+        } else if (c == EOF) {
+            if (q == buf)
+                return EOF;
+            else
+                break;
+        } else {
+            if ((q - buf) < (buf_size - 1))
+                *q++ = c;
+        }
+    }
+    *q = '\0';
+    return 0;
+}
+
 int qemu_get_byte(QEMUFile *f)
 {
     if (f->buf_index >= f->buf_size) {
@@ -7378,6 +7502,9 @@
     QEMU_OPTION_clock,
     QEMU_OPTION_startdate,
     QEMU_OPTION_tb_size,
+    QEMU_OPTION_f,
+    QEMU_OPTION_md,
+    QEMU_OPTION_dump_devices,
 };
 
 typedef struct QEMUOption {
@@ -7490,6 +7617,9 @@
     { "clock", HAS_ARG, QEMU_OPTION_clock },
     { "startdate", HAS_ARG, QEMU_OPTION_startdate },
     { "tb-size", HAS_ARG, QEMU_OPTION_tb_size },
+    { "f", HAS_ARG, QEMU_OPTION_f },
+    { "md", HAS_ARG, QEMU_OPTION_md },
+    { "dump-devices", 0, QEMU_OPTION_dump_devices },
     { NULL },
 };
 
@@ -7533,7 +7663,7 @@
 }
 
 #ifdef HAS_AUDIO
-struct soundhw soundhw[] = {
+static struct soundhw soundhw[] = {
 #ifdef HAS_AUDIO_CHOICE
 #if defined(TARGET_I386) || defined(TARGET_MIPS)
     {
@@ -7601,58 +7731,43 @@
 static void select_soundhw (const char *optarg)
 {
     struct soundhw *c;
-
+    QEMUDeviceClass *dc, *audio_class;
+    QEMUDevice *dev;
+    
     if (*optarg == '?') {
     show_valid_cards:
-
         printf ("Valid sound card names (comma separated):\n");
         for (c = soundhw; c->name; ++c) {
             printf ("%-11s %s\n", c->name, c->descr);
         }
-        printf ("\n-soundhw all will enable all of the above\n");
         exit (*optarg != '?');
-    }
-    else {
-        size_t l;
+    } else {
         const char *p;
-        char *e;
-        int bad_card = 0;
-
-        if (!strcmp (optarg, "all")) {
-            for (c = soundhw; c->name; ++c) {
-                c->enabled = 1;
-            }
-            return;
-        }
-
+        const char *e;
+        char class_name[64];
+        int l;
+        audio_class = qemu_class_find("audio-device");
+        
         p = optarg;
         while (*p) {
             e = strchr (p, ',');
             l = !e ? strlen (p) : (size_t) (e - p);
-
-            for (c = soundhw; c->name; ++c) {
-                if (!strncmp (c->name, p, l)) {
-                    c->enabled = 1;
-                    break;
-                }
+            if (l > sizeof(class_name) - 1)
+                l = sizeof(class_name) - 1;
+            memcpy(class_name, p, l);
+            class_name[l] = '\0';
+            
+            dc = qemu_class_find(class_name);
+            if (!dc || !qemu_class_instanceof(dc, audio_class)) {
+                fprintf(stderr, "Unknown audio device: '%s'\n", class_name);
+                goto show_valid_cards;
             }
-
-            if (!c->name) {
-                if (l > 80) {
-                    fprintf (stderr,
-                             "Unknown sound card name (too big to show)\n");
-                }
-                else {
-                    fprintf (stderr, "Unknown sound card name `%.*s'\n",
-                             (int) l, p);
-                }
-                bad_card = 1;
-            }
-            p += l + (e != NULL);
+            dev = qemu_device_new_nodup(dc, "audio");
+            if (!e)
+                break;
+            else 
+                p = e + 1;
         }
-
-        if (bad_card)
-            goto show_valid_cards;
     }
 }
 #endif
@@ -7665,8 +7780,951 @@
 }
 #endif
 
-#define MAX_NET_CLIENTS 32
+/***************************************************/
 
+typedef struct QEMUIRQVector {
+    const char *name;
+    qemu_irq *irqs;
+    int nb_irqs;
+    struct QEMUIRQVector *next;
+} QEMUIRQVector;
+
+static QEMUIRQVector *first_irq_vec;
+QEMUDeviceClass *qemu_eth_class;
+QEMUDeviceClass *qemu_isa_class;
+QEMUDeviceClass *qemu_default_pic_class;
+
+/* primitive IRQ naming, waiting until PICs are registered as
+   objects. */
+void qemu_register_irqs(const char *name, qemu_irq *irqs, int nb_irqs)
+{
+    QEMUIRQVector *irq_vec;
+    QEMUDevice *dev;
+
+    dev = qemu_device_new_after(qemu_default_pic_class, name, machine_dev);
+    if (!dev)
+        return;
+    dev->instantiated = 1;
+    irq_vec = qemu_mallocz(sizeof(QEMUIRQVector));
+    irq_vec->name = qemu_strdup(name);
+    irq_vec->irqs = irqs;
+    irq_vec->nb_irqs = nb_irqs;
+    irq_vec->next = first_irq_vec;
+    first_irq_vec = irq_vec;
+}
+
+/* XXX: must be suppressed asap */
+qemu_irq *qemu_get_default_pic(void)
+{
+    if (!first_irq_vec)
+        return NULL;
+    return first_irq_vec->irqs;
+}
+
+/* return NULL if not found */
+qemu_irq *qemu_irq_vec_from_name(const char *name, int nb_irqs)
+{
+    const char *p;
+    char dev_name[256], *q;
+    int irq_index;
+    QEMUIRQVector *irq_vec;
+
+    p = name;
+    q = dev_name;
+    while (*p != '.' && *p != '\0') {
+        if ((q - dev_name) >= sizeof(dev_name) - 1)
+            return NULL;
+        *q++ = *p++;
+    }
+    *q = '\0';
+    if (!strstart(p, ".irq", &p))
+        return NULL;
+    irq_index = strtoul(p, (char **)&p, 10);
+    if (*p != '\0')
+        return NULL;
+    for(irq_vec = first_irq_vec; irq_vec != NULL; irq_vec = irq_vec->next) {
+        if (!strcmp(irq_vec->name, dev_name))
+            break;
+    }
+    if (!irq_vec)
+        return NULL;
+    if (irq_index < 0 || (irq_index + nb_irqs - 1) >= irq_vec->nb_irqs)
+        return NULL;
+    return irq_vec->irqs + irq_index;
+}
+
+/* return NULL if not found */
+qemu_irq qemu_irq_from_name(const char *name)
+{
+    qemu_irq *irq_vec;
+    irq_vec = qemu_irq_vec_from_name(name, 1);
+    if (!irq_vec)
+        return NULL;
+    return irq_vec[0];
+}
+
+char *qemu_irq_name(char *buf, int buf_size, qemu_irq *pic, int irq_num)
+{
+    QEMUIRQVector *irq_vec;
+    for(irq_vec = first_irq_vec; irq_vec != NULL; irq_vec = irq_vec->next) {
+        if (irq_vec->irqs == pic)
+            break;
+    }
+    if (!irq_vec)
+        goto fail;
+    if (irq_num < 0 || irq_num >= irq_vec->nb_irqs)
+        goto fail;
+    snprintf(buf, buf_size, "%s.irq%d", irq_vec->name, irq_num);
+    return buf;
+ fail:
+    buf[0] = '\0';
+    return buf;
+}
+
+/* return NULL if error */
+PCIBus *pci_get_bus_devfn(QEMUDevice *dev, int *pdevfn)
+{
+    PCIBus *pci_bus;
+    const char *str;
+    str = qemu_device_get_str(dev, "pci_bus");
+    pci_bus = pci_bus_from_name(str);
+    if (!pci_bus) {
+        fprintf(stderr, "%s: unknown PCI bus: '%s'\n", dev->name, str);
+        return NULL;
+    }
+    *pdevfn = qemu_device_get_int(dev, "devfn");
+    return pci_bus;
+}
+                                 
+
+#ifdef HAS_AUDIO
+static AudioState *audio_state;
+
+/* XXX: all the following will be moved to device or machine C definitions */
+static int pci_audio_init(QEMUDevice *dev)
+{
+    int (*init_pci) (PCIBus *bus, AudioState *s);
+    PCIBus *pci_bus;
+    int devfn;
+
+    pci_bus = pci_get_bus_devfn(dev, &devfn);
+    if (!pci_bus)
+        return -1;
+    if (!audio_state) {
+        audio_state = AUD_init();
+    }
+    init_pci = dev->dev_class->opaque;
+    init_pci(pci_bus, audio_state);
+    return 0;
+}
+
+static int isa_audio_init(QEMUDevice *dev)
+{
+    int (*init_isa) (AudioState *s, qemu_irq *pic);
+    qemu_irq *pic;
+    pic = qemu_get_default_pic();
+    if (!pic)
+        return -1;
+    if (!audio_state) {
+        audio_state = AUD_init();
+    }
+    init_isa = dev->dev_class->opaque;
+    init_isa(audio_state, pic);
+    return 0;
+}
+#endif
+
+static const uint8_t default_macaddr[6] = {
+    0x52, 0x54, 0x00, 0x12, 0x34, 0x56,
+};
+    
+int nd_init(QEMUDevice *dev, NICInfo *nd)
+{
+    static int nic_count = 0;
+    int vlan_id;
+    const char *str;
+    uint8_t *macaddr;
+
+    vlan_id = qemu_device_get_int(dev, "vlan");
+    nd->vlan = qemu_find_vlan(vlan_id);
+    if (!nd->vlan) {
+        fprintf(stderr, "%s: could not create vlan %d\n", dev->name, vlan_id);
+        return -1;
+    }
+    nd->vlan->nb_guest_devs++;
+
+    str = qemu_device_get_str(dev, "macaddr");
+    if (str[0] == '\0') {
+        macaddr = nd->macaddr;
+        memcpy(macaddr, default_macaddr, 6);
+        macaddr[5] = 0x56 + nic_count;
+    } else {
+        if (parse_macaddr(nd->macaddr, str) < 0) {
+            fprintf(stderr, "%s: invalid syntax for ethernet address\n",
+                    dev->name);
+            return -1;
+        }
+    }
+    nic_count++;
+    return 0;
+}
+
+/* return a "global" macaddr by taking the one of the first defined
+   ethernet device */
+void qemu_get_machine_macaddr(uint8_t *macaddr)
+{
+    QEMUDevice *dev;
+    const char *str;
+
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (qemu_class_instanceof(dev->dev_class, qemu_eth_class)) {
+            str = qemu_device_get_str(dev, "macaddr");
+            if (str[0] == '\0' ||
+                parse_macaddr(macaddr, str) < 0)
+                goto default_mac;
+            return;
+        }
+    }
+ default_mac:
+    macaddr[0] = 0x52;
+    macaddr[1] = 0x54;
+    macaddr[2] = 0x00;
+    macaddr[3] = 0x12;
+    macaddr[4] = 0x34;
+    macaddr[5] = 0x56;
+}
+
+static int pci_eth_init(QEMUDevice *dev)
+{
+    void (*init_pci)(PCIBus *bus, NICInfo *nd, int devfn);
+    NICInfo nd;
+    PCIBus *pci_bus;
+    int devfn;
+    
+    pci_bus = pci_get_bus_devfn(dev, &devfn);
+    if (!pci_bus)
+        return -1;
+    if (nd_init(dev, &nd) < 0)
+        return -1;
+    init_pci = dev->dev_class->opaque;
+    init_pci(pci_bus, &nd, devfn);
+    return 0;
+}
+
+#define NE2000_NB_MAX 6
+
+static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
+static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
+
+static int isa_ne2000_dev_init(QEMUDevice *dev)
+{
+    static int ne2000_count = 0;
+    uint32_t iobase;
+    NICInfo nd;
+    qemu_irq irq;
+    const char *irq_str;
+    char buf[128];
+
+    iobase = qemu_device_get_int(dev, "iobase");
+    irq_str = qemu_device_get_str(dev, "irq");
+    if (iobase == -1 && irq_str[0] == '\0') {
+        if (ne2000_count >= NE2000_NB_MAX)
+            return -1;
+        iobase = ne2000_io[ne2000_count];
+        snprintf(buf, sizeof(buf), "isapic0.irq%d", 
+                 ne2000_irq[ne2000_count]);
+        irq_str = buf;
+        ne2000_count++;
+    }
+    irq = qemu_irq_from_name(irq_str);
+    if (!irq)
+        return -1;
+    if (nd_init(dev, &nd) < 0)
+        return -1;
+    isa_ne2000_init(iobase, irq, &nd);
+    return 0;
+}
+
+void isa_ne2000_class_init(void)
+{
+    QEMUDeviceClass *dc;
+
+    dc = qemu_class_new("ne2k_isa", 0, "NE2000 ISA");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_add_parent(dc, qemu_isa_class);
+    qemu_class_field_new(dc, "iobase", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "iobase", -1);
+    qemu_class_field_new(dc, "irq", QEMU_CTYPE_STR);
+    dc->dev_init = isa_ne2000_dev_init;
+}
+
+#ifdef TARGET_ARM
+static int smc91c111_dev_init(QEMUDevice *dev)
+{
+    int64_t membase;
+    qemu_irq irq;
+    NICInfo nd;
+
+    membase = qemu_device_get_int(dev, "membase");
+    irq = qemu_irq_from_name(qemu_device_get_str(dev, "irq"));
+    if (!irq)
+        return -1;
+    if (nd_init(dev, &nd) < 0)
+        return -1;
+    smc91c111_init(&nd, membase, irq);
+    return 0;
+}
+
+void smc91c111_set_defaults(uint32_t membase, qemu_irq *pic, int irq_num)
+{
+    QEMUDevice *dev;
+    QEMUDeviceClass *dc;
+    char buf[128];
+
+    dc = qemu_class_find("smc91c111");
+    if (!dc)
+        return;
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (dev->dev_class == dc) {
+            if (qemu_device_get_int(dev, "membase") == -1) {
+                qemu_device_set_int(dev, "membase", membase);
+            }
+            if (qemu_device_get_str(dev, "irq")[0] == '\0') {
+                qemu_device_set_str(dev, "irq", 
+                                    qemu_irq_name(buf, sizeof(buf), pic, irq_num));
+            }
+            break;
+        }
+    }
+}
+
+void smc91c111_class_init(void)
+{
+    QEMUDeviceClass *dc;
+
+    dc = qemu_class_new("smc91c111", 0, "smc91c111");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_field_new(dc, "membase", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "membase", -1);
+    qemu_class_field_new(dc, "irq", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "irq", -1);
+    dc->dev_init = smc91c111_dev_init;
+}
+
+static int mv88w8618_eth_dev_init(QEMUDevice *dev)
+{
+    int64_t membase;
+    NICInfo nd;
+    qemu_irq irq;
+
+    membase = qemu_device_get_int(dev, "membase");
+    irq = qemu_irq_from_name(qemu_device_get_str(dev, "irq"));
+    if (!irq)
+        return -1;
+    if (nd_init(dev, &nd) < 0)
+        return -1;
+    mv88w8618_eth_init(&nd, membase, irq);
+    return 0;
+}
+
+void mv88w8618_eth_set_defaults(uint32_t membase, qemu_irq *pic, int irq_num)
+{
+    QEMUDevice *dev;
+    QEMUDeviceClass *dc;
+    char buf[128];
+
+    dc = qemu_class_find("mv88w8618_eth");
+    if (!dc)
+        return;
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (dev->dev_class == dc) {
+            if (qemu_device_get_int(dev, "membase") == -1) {
+                qemu_device_set_int(dev, "membase", membase);
+            }
+            if (qemu_device_get_str(dev, "irq")[0] == '\0') {
+                qemu_device_set_str(dev, "irq", 
+                                    qemu_irq_name(buf, sizeof(buf), pic, irq_num));
+            }
+            break;
+        }
+    }
+}
+
+void mv88w8618_eth_class_init(void)
+{
+    QEMUDeviceClass *dc;
+
+    dc = qemu_class_new("mv88w8618_eth", 0, "mv88w8618_eth");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_field_new(dc, "membase", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "membase", -1);
+    qemu_class_field_new(dc, "irq", QEMU_CTYPE_STR);
+    dc->dev_init = mv88w8618_eth_dev_init;
+}
+
+static int stellaris_enet_dev_init(QEMUDevice *dev)
+{
+    int64_t membase;
+    qemu_irq irq;
+    NICInfo nd;
+
+    membase = qemu_device_get_int(dev, "membase");
+    irq = qemu_irq_from_name(qemu_device_get_str(dev, "irq"));
+    if (!irq)
+        return -1;
+    if (nd_init(dev, &nd) < 0)
+        return -1;
+    stellaris_enet_init(&nd, membase, irq);
+    return 0;
+}
+
+void stellaris_enet_set_defaults(uint32_t membase, qemu_irq *pic, int irq_num)
+{
+    QEMUDevice *dev;
+    QEMUDeviceClass *dc;
+    char buf[128];
+
+    dc = qemu_class_find("stellaris_enet");
+    if (!dc)
+        return;
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (dev->dev_class == dc) {
+            if (qemu_device_get_int(dev, "membase") == -1) {
+                qemu_device_set_int(dev, "membase", membase);
+            }
+            if (qemu_device_get_str(dev, "irq")[0] == '\0') {
+                qemu_device_set_str(dev, "irq", 
+                                    qemu_irq_name(buf, sizeof(buf), pic, irq_num));
+            }
+            break;
+        }
+    }
+}
+
+void stellaris_enet_class_init(void)
+{
+    QEMUDeviceClass *dc;
+
+    dc = qemu_class_new("stellaris_enet", 0, "stellaris_enet");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_field_new(dc, "membase", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "membase", -1);
+    qemu_class_field_new(dc, "irq", QEMU_CTYPE_STR);
+    dc->dev_init = stellaris_enet_dev_init;
+}
+#endif
+
+#ifdef TARGET_MIPS
+static int mipsnet_dev_init(QEMUDevice *dev)
+{
+    int iobase;
+    NICInfo nd;
+    qemu_irq irq;
+
+    iobase = qemu_device_get_int(dev, "iobase");
+    irq = qemu_irq_from_name(qemu_device_get_str(dev, "irq"));
+    if (!irq)
+        return -1;
+    if (nd_init(dev, &nd) < 0)
+        return -1;
+    mipsnet_init(iobase, irq, &nd);
+    return 0;
+}
+
+void mipsnet_set_defaults(uint32_t iobase, qemu_irq *pic, int irq_num)
+{
+    QEMUDevice *dev;
+    QEMUDeviceClass *dc;
+    char buf[128];
+
+    dc = qemu_class_find("mipsnet");
+    if (!dc)
+        return;
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (dev->dev_class == dc) {
+            if (qemu_device_get_int(dev, "iobase") == -1) {
+                qemu_device_set_int(dev, "iobase", iobase);
+            }
+            if (qemu_device_get_str(dev, "irq")[0] == '\0') {
+                qemu_device_set_str(dev, "irq", 
+                                    qemu_irq_name(buf, sizeof(buf), pic, irq_num));
+            }
+            break;
+        }
+    }
+}
+
+void mipsnet_class_init(void)
+{
+    QEMUDeviceClass *dc;
+
+    dc = qemu_class_new("mipsnet", 0, "mipsnet");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_field_new(dc, "iobase", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "iobase", -1);
+    qemu_class_field_new(dc, "irq", QEMU_CTYPE_STR);
+    dc->dev_init = mipsnet_dev_init;
+}
+#endif
+
+#ifdef TARGET_M68K
+static int mcf_fec_dev_init(QEMUDevice *dev)
+{
+    int64_t membase;
+    NICInfo nd;
+    qemu_irq *irq;
+
+    membase = qemu_device_get_int(dev, "membase");
+    irq = qemu_irq_vec_from_name(qemu_device_get_str(dev, "irq"), 12);
+    if (!irq)
+        return -1;
+    if (nd_init(dev, &nd) < 0)
+        return -1;
+    mcf_fec_init(&nd, membase, irq);
+    return 0;
+}
+
+void mcf_fec_set_defaults(uint32_t membase, qemu_irq *pic, int irq_num)
+{
+    QEMUDevice *dev;
+    QEMUDeviceClass *dc;
+    char buf[128];
+
+    dc = qemu_class_find("mcf_fec");
+    if (!dc)
+        return;
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (dev->dev_class == dc) {
+            if (qemu_device_get_int(dev, "membase") == -1) {
+                qemu_device_set_int(dev, "membase", membase);
+            }
+            if (qemu_device_get_str(dev, "irq")[0] == '\0') {
+                qemu_device_set_str(dev, "irq", 
+                                    qemu_irq_name(buf, sizeof(buf), pic, irq_num));
+            }
+            break;
+        }
+    }
+}
+
+void mcf_fec_class_init(void)
+{
+    QEMUDeviceClass *dc;
+
+    dc = qemu_class_new("mcf_fec", 0, "mcf_fec");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_field_new(dc, "membase", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "membase", -1);
+    qemu_class_field_new(dc, "irq", QEMU_CTYPE_STR);
+    dc->dev_init = mcf_fec_dev_init;
+}
+#endif
+
+#ifdef TARGET_CRIS
+void etraxfs_eth_class_init(void)
+{
+    QEMUDeviceClass *dc;
+
+    dc = qemu_class_new("etraxfs_eth", 0, "etraxfs_eth");
+    qemu_class_add_parent(dc, qemu_eth_class);
+}
+#endif
+
+#ifdef TARGET_SPARC
+void lance_class_init(void)
+{
+    QEMUDeviceClass *dc;
+
+    dc = qemu_class_new("lance", 0, "lance");
+    qemu_class_add_parent(dc, qemu_eth_class);
+}
+#endif
+
+void init_classes(void)
+{
+    QEMUDeviceClass *dc, *dc1, *drive_class;
+    QEMUDeviceClass *usb_class, *pci_class;
+    QEMUMachine *m;
+    int i;
+    char buf[128];
+
+    /* preferences */
+    dc = qemu_class_new("preferences", 0, "User preferences");
+    qemu_class_field_new(dc, "ui", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc, "full_screen", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc, "keyboard_layout", QEMU_CTYPE_STR);
+
+    qemu_class_field_new(dc, "sdl_no_frame", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc, "sdl_alt_grab", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc, "sdl_no_quit", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc, "sdl_show_cursor", QEMU_CTYPE_BOOL);
+
+    qemu_class_field_new(dc, "vnc_params", QEMU_CTYPE_STR);
+
+    qemu_class_field_new(dc, "daemonize", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc, "pidfile", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc, "clock", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc, "tb_size", QEMU_CTYPE_INT);
+
+    /* XXX: add all sound config options and suppress corresponding
+       environment variables */
+
+    /* machines */
+    dc1 = qemu_class_new("generic-machine", QEMU_CLASS_ABSTRACT, NULL);
+    qemu_class_field_new(dc1, "name", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "ramsize", QEMU_CTYPE_INT);
+    qemu_class_field_new(dc1, "cpu", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "kernel", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "append", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "initrd", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "snapshot", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc1, "portrait", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc1, "boot", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "localtime", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc1, "reboot", QEMU_CTYPE_BOOL);
+    qemu_class_set_bool(dc1, "reboot", 1);
+    qemu_class_field_new(dc1, "shutdown", QEMU_CTYPE_BOOL);
+    qemu_class_set_bool(dc1, "shutdown", 1);
+    qemu_class_field_new(dc1, "startdate", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "autostart", QEMU_CTYPE_BOOL);
+    qemu_class_set_bool(dc1, "autostart", 1);
+    qemu_class_field_new(dc1, "smp", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc1, "smp", 1);
+    qemu_class_field_new(dc1, "debug", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "bios_dir", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "bios", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "term_escape_char", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc1, "term_escape_char", 1);
+
+    qemu_class_field_new(dc1, "monitor", QEMU_CTYPE_STR);
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        snprintf(buf, sizeof(buf), "serial%d", i);
+        qemu_class_field_new(dc1, buf, QEMU_CTYPE_STR);
+    }
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        snprintf(buf, sizeof(buf), "parallel%d", i);
+        qemu_class_field_new(dc1, buf, QEMU_CTYPE_STR);
+    }
+    qemu_class_field_new(dc1, "gdb_server", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc1, "usb", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(dc1, "loadvm", QEMU_CTYPE_STR);
+
+    /* register machine classes */
+    for(m = first_machine; m != NULL; m = m->next) {
+        dc = qemu_class_new(m->name, 0, m->desc);
+        qemu_class_add_parent(dc, dc1);
+        /* XXX: move it to machine defs */
+#if defined(TARGET_ARM)
+        qemu_class_field_new(dc, "old_param", QEMU_CTYPE_BOOL);
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
+        qemu_class_field_new(dc, "semihosting", QEMU_CTYPE_BOOL);
+#endif
+#ifdef TARGET_I386
+        qemu_class_field_new(dc, "fd_bootchk", QEMU_CTYPE_BOOL);
+        qemu_class_set_bool(dc, "fd_bootchk", 1);
+        qemu_class_field_new(dc, "acpi", QEMU_CTYPE_BOOL);
+        qemu_class_set_bool(dc, "acpi", 1);
+        qemu_class_field_new(dc, "win2k_hack", QEMU_CTYPE_BOOL);
+        /* XXX: add an array type ? */
+        for(i=0;i<MAX_OPTION_ROMS;i++) {
+            snprintf(buf, sizeof(buf), "option_rom%d", i);
+            qemu_class_field_new(dc, buf, QEMU_CTYPE_STR);
+        }
+        qemu_class_field_new(dc, "display", QEMU_CTYPE_STR);
+#ifdef USE_KQEMU
+        qemu_class_field_new(dc, "kqemu", QEMU_CTYPE_STR);
+#endif
+#endif
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
+        qemu_class_field_new(dc, "display_params", QEMU_CTYPE_STR);
+#ifdef TARGET_SPARC
+        qemu_class_set_str(dc, "display_params", "1024x768x8");
+#else
+        qemu_class_set_str(dc, "display_params", "800x600x15");
+#endif
+#endif
+    }
+
+    /* register drive classes */
+    drive_class = qemu_class_new("generic-drive", QEMU_CLASS_ABSTRACT, NULL);
+    qemu_class_field_new(drive_class, "file", QEMU_CTYPE_STR);
+    qemu_class_field_new(drive_class, "format", QEMU_CTYPE_STR);
+    qemu_class_field_new(drive_class, "media", QEMU_CTYPE_STR);
+    qemu_class_field_new(drive_class, "snapshot", QEMU_CTYPE_BOOL);
+    qemu_class_field_new(drive_class, "cache", QEMU_CTYPE_BOOL);
+    qemu_class_set_bool(drive_class, "cache", 1);
+    qemu_class_field_new(drive_class, "bus", QEMU_CTYPE_INT);
+    qemu_class_field_new(drive_class, "unit", QEMU_CTYPE_INT);
+    qemu_class_set_int(drive_class, "unit", -1);
+    qemu_class_field_new(drive_class, "index", QEMU_CTYPE_INT);
+    qemu_class_set_int(drive_class, "index", -1);
+    qemu_class_field_new(drive_class, "cyls", QEMU_CTYPE_INT);
+    qemu_class_field_new(drive_class, "heads", QEMU_CTYPE_INT);
+    qemu_class_field_new(drive_class, "secs", QEMU_CTYPE_INT);
+    qemu_class_field_new(drive_class, "trans", QEMU_CTYPE_STR);
+    
+    dc = qemu_class_new("ide", 0, "IDE drive");
+    qemu_class_add_parent(dc, drive_class);
+    dc->dev_init = drive_init;
+    
+    dc = qemu_class_new("scsi", 0, "SCSI drive");
+    qemu_class_add_parent(dc, drive_class);
+    dc->dev_init = drive_init;
+
+    dc = qemu_class_new("floppy", 0, "Floppy drive");
+    qemu_class_add_parent(dc, drive_class);
+    dc->dev_init = drive_init;
+
+    dc = qemu_class_new("pflash", 0, "Flash memory");
+    qemu_class_add_parent(dc, drive_class);
+    dc->dev_init = drive_init;
+
+    dc = qemu_class_new("mtd", 0, "MTD drive");
+    qemu_class_add_parent(dc, drive_class);
+    dc->dev_init = drive_init;
+
+    dc = qemu_class_new("sd", 0, "SD drive");
+    qemu_class_add_parent(dc, drive_class);
+    dc->dev_init = drive_init;
+
+    pci_class = qemu_class_new("pci-device", QEMU_CLASS_ABSTRACT, NULL);
+    qemu_class_field_new(pci_class, "pci_bus", QEMU_CTYPE_STR);
+    qemu_class_field_new(pci_class, "devfn", QEMU_CTYPE_INT);
+    qemu_class_set_int(pci_class, "devfn", -1);
+    
+    qemu_isa_class = qemu_class_new("isa-device", QEMU_CLASS_ABSTRACT, NULL);
+
+#ifdef HAS_AUDIO
+    {
+        QEMUDeviceClass *qemu_audio_class;
+        struct soundhw *c;
+        
+        /* register audio devices */
+        qemu_audio_class = qemu_class_new("audio-device", 
+                                          QEMU_CLASS_ABSTRACT, NULL);
+    
+        for (c = soundhw; c->name; ++c) {
+            dc = qemu_class_new(c->name, 0, c->descr);
+            qemu_class_add_parent(dc, qemu_audio_class);
+            if (c->isa) {
+                qemu_class_add_parent(dc, qemu_isa_class);
+                dc->dev_init = isa_audio_init;
+                dc->opaque = c->init.init_isa;
+            } else {
+                qemu_class_add_parent(dc, pci_class);
+                dc->dev_init = pci_audio_init;
+                dc->opaque = c->init.init_pci;
+            }
+        }
+    }
+#endif
+
+    /* network clients except nics */
+    dc = qemu_class_new("net-user", 0, "User mode network router");
+    qemu_class_field_new(dc, "vlan", QEMU_CTYPE_INT);
+    qemu_class_field_new(dc, "hostname", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc, "tftp", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc, "bootp", QEMU_CTYPE_STR);
+#if !defined(_WIN32)
+    qemu_class_field_new(dc, "smb", QEMU_CTYPE_STR);
+#endif
+    for(i = 0; i < SLIRP_MAX_REDIRS; i++) {
+        snprintf(buf, sizeof(buf), "redir%d", i);
+        qemu_class_field_new(dc, buf, QEMU_CTYPE_STR);
+    }
+    dc->dev_init = net_slirp_init;
+
+    dc = qemu_class_new("net-tap", 0, "TAP network interface");
+    qemu_class_field_new(dc, "vlan", QEMU_CTYPE_INT);
+    qemu_class_field_new(dc, "ifname", QEMU_CTYPE_STR);
+#ifndef _WIN32
+    qemu_class_field_new(dc, "fd", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "fd", -1);
+    qemu_class_field_new(dc, "script", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc, "downscript", QEMU_CTYPE_STR);
+#endif
+    dc->dev_init = net_tap_init2;
+
+    dc = qemu_class_new("net-socket", 0, "Socket network interface");
+    qemu_class_field_new(dc, "vlan", QEMU_CTYPE_INT);
+    qemu_class_field_new(dc, "fd", QEMU_CTYPE_INT);
+    qemu_class_set_int(dc, "fd", -1);
+    qemu_class_field_new(dc, "listen", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc, "connect", QEMU_CTYPE_STR);
+    qemu_class_field_new(dc, "mcast", QEMU_CTYPE_STR);
+    dc->dev_init = net_socket_init;
+
+    /* network devices */
+    qemu_eth_class = qemu_class_new("ethernet-device", QEMU_CLASS_ABSTRACT, NULL);
+    qemu_class_field_new(qemu_eth_class, "macaddr", QEMU_CTYPE_STR);
+    qemu_class_field_new(qemu_eth_class, "vlan", QEMU_CTYPE_INT);
+    
+    dc = qemu_class_new("ne2k_pci", 0, "NE2000 PCI");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_add_parent(dc, pci_class);
+    dc->dev_init = pci_eth_init;
+    dc->opaque = pci_ne2000_init;
+
+    dc = qemu_class_new("i82551", 0, "i82551");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_add_parent(dc, pci_class);
+    dc->dev_init = pci_eth_init;
+    dc->opaque = pci_i82551_init;
+
+    dc = qemu_class_new("i82557b", 0, "i82557b");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_add_parent(dc, pci_class);
+    dc->dev_init = pci_eth_init;
+    dc->opaque = pci_i82557b_init;
+
+    dc = qemu_class_new("i82559er", 0, "i82559er");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_add_parent(dc, pci_class);
+    dc->dev_init = pci_eth_init;
+    dc->opaque = pci_i82559er_init;
+
+    dc = qemu_class_new("e1000", 0, "e1000");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_add_parent(dc, pci_class);
+    dc->dev_init = pci_eth_init;
+    dc->opaque = pci_e1000_init;
+
+    dc = qemu_class_new("pcnet", 0, "pcnet");
+    qemu_class_add_parent(dc, qemu_eth_class);
+    qemu_class_add_parent(dc, pci_class);
+    dc->dev_init = pci_eth_init;
+    dc->opaque = pci_pcnet_init;
+
+    isa_ne2000_class_init();
+
+#ifdef TARGET_ARM
+    smc91c111_class_init();
+    mv88w8618_eth_class_init();
+    stellaris_enet_class_init();
+#endif
+
+#ifdef TARGET_MIPS
+    mipsnet_class_init();
+#endif
+
+#ifdef TARGET_M68K
+    mcf_fec_class_init();
+#endif
+
+#ifdef TARGET_SPARC
+    lance_class_init();
+#endif
+
+    /* usb devices */
+    usb_class = qemu_class_new("usb-device", QEMU_CLASS_ABSTRACT, NULL);
+
+    dc = qemu_class_new("usb-host", 0, "USB Host Device Redirector");
+    qemu_class_add_parent(dc, usb_class);
+    dc->dev_init = usb_device_init; 
+    qemu_class_field_new(dc, "host_device", QEMU_CTYPE_STR);
+    
+    dc = qemu_class_new("usb-mouse", 0, "USB Mouse");
+    qemu_class_add_parent(dc, usb_class);
+    dc->dev_init = usb_device_init; 
+    dc->opaque = usb_mouse_init;
+
+    dc = qemu_class_new("usb-tablet", 0, "USB Tablet");
+    qemu_class_add_parent(dc, usb_class);
+    dc->dev_init = usb_device_init; 
+    dc->opaque = usb_tablet_init;
+    
+    dc = qemu_class_new("usb-keyboard", 0, "USB Keyboard");
+    qemu_class_add_parent(dc, usb_class);
+    dc->dev_init = usb_device_init; 
+    dc->opaque = usb_keyboard_init;
+
+    dc = qemu_class_new("usb-msd", 0, "USB Mass Storage Device");
+    qemu_class_add_parent(dc, usb_class);
+    dc->dev_init = usb_device_init; 
+    qemu_class_field_new(dc, "file", QEMU_CTYPE_STR);
+
+    dc = qemu_class_new("usb-wacom-tablet", 0, "USB Wacom Tablet");
+    qemu_class_add_parent(dc, usb_class);
+    dc->dev_init = usb_device_init; 
+    dc->opaque = usb_wacom_init;
+    
+    dc = qemu_class_new("usb-serial", 0, "USB Serial Port");
+    qemu_class_add_parent(dc, usb_class);
+    dc->dev_init = usb_device_init; 
+    qemu_class_field_new(dc, "device", QEMU_CTYPE_STR);
+
+#ifdef CONFIG_BRLAPI
+    dc = qemu_class_new("usb-braille", 0, "USB Braille");
+    qemu_class_add_parent(dc, usb_class);
+    dc->dev_init = usb_device_init; 
+    dc->opaque = usb_baum_init;
+#endif
+
+    /* generic PIC */
+    qemu_default_pic_class = qemu_class_new("default-pic", 0,
+                                            "Default Interrupt Controller");
+}
+
+void dev_init(QEMUDevice *dev)
+{
+    int ret;
+    QEMUDeviceClass *dev_class;
+
+    if (dev->instantiated)
+        return;
+    dev->instantiated = 1;
+    dev_class = dev->dev_class;
+    if (!dev_class->dev_init) {
+        ret = -ENOENT;
+    } else {
+        ret = dev_class->dev_init(dev);
+    }
+    if (ret < 0) {
+        fprintf(stderr, "Could not initialize device '%s' (type='%s')\n", 
+                dev->name, dev_class->name);
+    }
+}
+
+void drives_init(void)
+{
+    QEMUDeviceClass *drive_class;
+    QEMUDevice *dev;
+
+    drive_class = qemu_class_find("generic-drive");
+    if (!drive_class)
+        return;
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (!dev->instantiated) {
+            if (qemu_class_instanceof(dev->dev_class, drive_class)) {
+                dev_init(dev);
+            }
+        }
+    }
+}
+
+/* initialize additional devices */
+void generic_device_init(void)
+{
+    QEMUDevice *dev;
+
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (!dev->instantiated) {
+            dev_init(dev);
+        }
+    }
+}
+
+/****************************************************/
+
+static const char *str_zton(const char *str)
+{
+    if (str[0] == '\0')
+        return NULL;
+    else
+        return str;
+}
+
 int main(int argc, char **argv)
 {
 #ifdef CONFIG_GDBSTUB
@@ -7681,7 +8739,6 @@
     const char *boot_devices = "";
     DisplayState *ds = &display_state;
     int cyls, heads, secs, translation;
-    const char *net_clients[MAX_NET_CLIENTS];
     int nb_net_clients;
     int hda_index;
     int optind;
@@ -7695,13 +8752,21 @@
     const char *loadvm = NULL;
     QEMUMachine *machine;
     const char *cpu_model;
-    const char *usb_devices[MAX_USB_CMDLINE];
-    int usb_devices_index;
     int fds[2];
     int tb_size;
-    const char *pid_file = NULL;
+    const char *pid_file;
     VLANState *vlan;
-
+    int has_config;
+    const char *slirp_tftp_prefix = NULL;
+    const char *slirp_bootp_filename = NULL;
+    const char *slirp_smb_path = NULL;
+    const char *slirp_redirs[SLIRP_MAX_REDIRS];
+    int nb_slirp_redirs = 0;
+    const char *ui_str;
+    const char *str;
+    const char *prefs_filename;
+    int do_dump_devices;
+    
     LIST_INIT (&vm_change_state_head);
 #ifndef _WIN32
     {
@@ -7732,47 +8797,83 @@
         }
     }
 #endif
+#ifdef _WIN32
+    /* compute the bios directory by using the executable dir */
+    {
+        static char exe_path[1024];
+        char *p;
 
+        GetModuleFileNameA(NULL, exe_path, sizeof(exe_path));
+        p = strrchr(exe_path, '\\');
+        if (p)
+            *p = '\0';
+        bios_dir = exe_path;
+    }
+#endif
+    
     register_machines();
-    machine = first_machine;
-    cpu_model = NULL;
-    initrd_filename = NULL;
-    ram_size = 0;
+    init_classes();
+    qemu_prefs = qemu_device_new(qemu_class_find("preferences"), "prefs");
+    qemu_prefs->instantiated = 1;
+
+    /* XXX: reuse generic option parser, this parser is buggy */
+    prefs_filename = NULL;
+    for(optind = 1; optind < (argc - 1); optind++) {
+        if (!strcmp(argv[optind], "-f") || !strcmp(argv[optind], "--f")) {
+            optind++;
+            prefs_filename = argv[optind];
+        }
+    }
+    /* read user preference file */
+    if (prefs_filename) {
+        if (qemu_parse_config(&qemu_prefs, prefs_filename, 
+                              QEMU_CONF_NO_OBJ | QEMU_CONF_ERR_FILE) < 0)
+            exit(1);
+    } else {
+#ifdef _WIN32
+        {
+            char buf[1024];
+            snprintf(buf, sizeof(buf), "%s/config", bios_dir);
+            if (qemu_parse_config(&qemu_prefs, buf, QEMU_CONF_NO_OBJ) == -1)
+                exit(1);
+        }
+#else
+        {   
+            char buf[1024];
+            const char *home_path;
+            home_path = getenv("HOME");
+            if (!home_path)
+                home_path = "";
+            snprintf(buf, sizeof(buf), "%s/.qemu/config", home_path);
+            if (qemu_parse_config(&qemu_prefs, buf, QEMU_CONF_NO_OBJ) == -1)
+                exit(1);
+        }
+#endif
+    }
+    
+    /* Note: unlike other devices, we may change the type of this
+       device later */
+    machine_dev = qemu_device_new(qemu_class_find(first_machine->name), "hw0");
     vga_ram_size = VGA_RAM_SIZE;
 #ifdef CONFIG_GDBSTUB
     use_gdbstub = 0;
     gdbstub_port = DEFAULT_GDBSTUB_PORT;
 #endif
-    snapshot = 0;
     nographic = 0;
-    curses = 0;
-    kernel_filename = NULL;
-    kernel_cmdline = "";
     cyls = heads = secs = 0;
     translation = BIOS_ATA_TRANSLATION_AUTO;
-    monitor_device = "vc:800x600";
 
-    serial_devices[0] = "vc:80Cx24C";
-    for(i = 1; i < MAX_SERIAL_PORTS; i++)
-        serial_devices[i] = NULL;
     serial_device_index = 0;
-
-    parallel_devices[0] = "vc:640x480";
-    for(i = 1; i < MAX_PARALLEL_PORTS; i++)
-        parallel_devices[i] = NULL;
     parallel_device_index = 0;
 
-    usb_devices_index = 0;
-
     nb_net_clients = 0;
     nb_drives = 0;
     nb_drives_opt = 0;
     hda_index = -1;
 
-    nb_nics = 0;
+    has_config = 0;
+    do_dump_devices = 0;
 
-    tb_size = 0;
-    
     optind = 1;
     for(;;) {
         if (optind >= argc)
@@ -7811,16 +8912,21 @@
 
             switch(popt->index) {
             case QEMU_OPTION_M:
-                machine = find_machine(optarg);
-                if (!machine) {
-                    QEMUMachine *m;
-                    printf("Supported machines are:\n");
-                    for(m = first_machine; m != NULL; m = m->next) {
-                        printf("%-10s %s%s\n",
-                               m->name, m->desc,
-                               m == first_machine ? " (default)" : "");
+                {
+                    QEMUMachine *m, *machine;
+                    machine = find_machine(optarg);
+                    if (!machine) {
+                        printf("Supported machines are:\n");
+                        for(m = first_machine; m != NULL; m = m->next) {
+                            printf("%-10s %s%s\n",
+                                   m->name, m->desc,
+                                   m == first_machine ? " (default)" : "");
+                        }
+                        exit(*optarg != '?');
                     }
-                    exit(*optarg != '?');
+                    qemu_device_delete(machine_dev);
+                    machine_dev = qemu_device_new(qemu_class_find(machine->name), 
+                                                  "hw0");
                 }
                 break;
             case QEMU_OPTION_cpu:
@@ -7832,11 +8938,11 @@
 #endif
                     exit(0);
                 } else {
-                    cpu_model = optarg;
+                    qemu_device_set_str(machine_dev, "cpu", optarg);
                 }
                 break;
             case QEMU_OPTION_initrd:
-                initrd_filename = optarg;
+                qemu_device_set_str(machine_dev, "initrd", optarg);
                 break;
             case QEMU_OPTION_hda:
                 if (cyls == 0)
@@ -7868,7 +8974,7 @@
                 drive_add(optarg, PFLASH_ALIAS);
                 break;
             case QEMU_OPTION_snapshot:
-                snapshot = 1;
+                qemu_device_set_bool(machine_dev, "snapshot", 1);
                 break;
             case QEMU_OPTION_hdachs:
                 {
@@ -7916,58 +9022,27 @@
                 }
                 break;
             case QEMU_OPTION_nographic:
-                serial_devices[0] = "stdio";
-                parallel_devices[0] = "null";
-                monitor_device = "stdio";
-                nographic = 1;
+                qemu_device_set_str(qemu_prefs, "ui", "cmdline");
                 break;
 #ifdef CONFIG_CURSES
             case QEMU_OPTION_curses:
-                curses = 1;
+                qemu_device_set_str(qemu_prefs, "ui", "curses");
                 break;
 #endif
             case QEMU_OPTION_portrait:
-                graphic_rotate = 1;
+                qemu_device_set_bool(machine_dev, "portrait", 1);
                 break;
             case QEMU_OPTION_kernel:
-                kernel_filename = optarg;
+                qemu_device_set_str(machine_dev, "kernel", optarg);
                 break;
             case QEMU_OPTION_append:
-                kernel_cmdline = optarg;
+                qemu_device_set_str(machine_dev, "append", optarg);
                 break;
             case QEMU_OPTION_cdrom:
                 drive_add(optarg, CDROM_ALIAS);
                 break;
             case QEMU_OPTION_boot:
-                boot_devices = optarg;
-                /* We just do some generic consistency checks */
-                {
-                    /* Could easily be extended to 64 devices if needed */
-                    const char *p;
-                    
-                    boot_devices_bitmap = 0;
-                    for (p = boot_devices; *p != '\0'; p++) {
-                        /* Allowed boot devices are:
-                         * a b     : floppy disk drives
-                         * c ... f : IDE disk drives
-                         * g ... m : machine implementation dependant drives
-                         * n ... p : network devices
-                         * It's up to each machine implementation to check
-                         * if the given boot devices match the actual hardware
-                         * implementation and firmware features.
-                         */
-                        if (*p < 'a' || *p > 'q') {
-                            fprintf(stderr, "Invalid boot device '%c'\n", *p);
-                            exit(1);
-                        }
-                        if (boot_devices_bitmap & (1 << (*p - 'a'))) {
-                            fprintf(stderr,
-                                    "Boot device '%c' was given twice\n",*p);
-                            exit(1);
-                        }
-                        boot_devices_bitmap |= 1 << (*p - 'a');
-                    }
-                }
+                qemu_device_set_str(machine_dev, "boot", optarg);
                 break;
             case QEMU_OPTION_fda:
             case QEMU_OPTION_fdb:
@@ -7975,31 +9050,31 @@
                 break;
 #ifdef TARGET_I386
             case QEMU_OPTION_no_fd_bootchk:
-                fd_bootchk = 0;
+                qemu_device_set_bool(machine_dev, "fd_bootchk", 0);
                 break;
 #endif
             case QEMU_OPTION_net:
-                if (nb_net_clients >= MAX_NET_CLIENTS) {
-                    fprintf(stderr, "qemu: too many network clients\n");
-                    exit(1);
-                }
-                net_clients[nb_net_clients] = optarg;
+                net_add(optarg);
                 nb_net_clients++;
                 break;
 #ifdef CONFIG_SLIRP
             case QEMU_OPTION_tftp:
-		tftp_prefix = optarg;
+		slirp_tftp_prefix = optarg;
                 break;
             case QEMU_OPTION_bootp:
-                bootp_filename = optarg;
+                slirp_bootp_filename = optarg;
                 break;
 #ifndef _WIN32
             case QEMU_OPTION_smb:
-		net_slirp_smb(optarg);
+		slirp_smb_path = optarg;
                 break;
 #endif
             case QEMU_OPTION_redir:
-                net_slirp_redir(optarg);
+                if (nb_slirp_redirs >= SLIRP_MAX_REDIRS) {
+                    fprintf(stderr, "Too many slirp redirections\n");
+                    exit(1);
+                }
+                slirp_redirs[nb_slirp_redirs++] = optarg;
                 break;
 #endif
 #ifdef HAS_AUDIO
@@ -8014,55 +9089,28 @@
             case QEMU_OPTION_h:
                 help(0);
                 break;
-            case QEMU_OPTION_m: {
-                uint64_t value;
-                char *ptr;
-
-                value = strtoul(optarg, &ptr, 10);
-                switch (*ptr) {
-                case 0: case 'M': case 'm':
-                    value <<= 20;
-                    break;
-                case 'G': case 'g':
-                    value <<= 30;
-                    break;
-                default:
-                    fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
-                    exit(1);
-                }
-
-                /* On 32-bit hosts, QEMU is limited by virtual address space */
-                if (value > (2047 << 20)
-#ifndef USE_KQEMU
-                    && HOST_LONG_BITS == 32
-#endif
-                    ) {
-                    fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n");
-                    exit(1);
-                }
-                if (value != (uint64_t)(ram_addr_t)value) {
-                    fprintf(stderr, "qemu: ram size too large\n");
-                    exit(1);
-                }
-                ram_size = value;
-                break;
-            }
-            case QEMU_OPTION_d:
+            case QEMU_OPTION_m: 
                 {
-                    int mask;
-                    CPULogItem *item;
-
-                    mask = cpu_str_to_log_mask(optarg);
-                    if (!mask) {
-                        printf("Log items (comma separated):\n");
-                    for(item = cpu_log_items; item->mask != 0; item++) {
-                        printf("%-10s %s\n", item->name, item->help);
+                    uint64_t value;
+                    char *ptr;
+                    
+                    value = strtoul(optarg, &ptr, 0);
+                    switch (*ptr) {
+                    case 0: case 'M': case 'm':
+                        break;
+                    case 'G': case 'g':
+                        value <<= 10;
+                        break;
+                    default:
+                        fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
+                        exit(1);
                     }
-                    exit(1);
-                    }
-                    cpu_set_log(mask);
+                    qemu_device_set_int(machine_dev, "ramsize", value);
                 }
                 break;
+            case QEMU_OPTION_d:
+                qemu_device_set_str(machine_dev, "debug", optarg);
+                break;
 #ifdef CONFIG_GDBSTUB
             case QEMU_OPTION_s:
                 use_gdbstub = 1;
@@ -8072,176 +9120,149 @@
                 break;
 #endif
             case QEMU_OPTION_L:
-                bios_dir = optarg;
+                qemu_device_set_str(machine_dev, "bios_dir", optarg);
                 break;
             case QEMU_OPTION_bios:
-                bios_name = optarg;
+                qemu_device_set_str(machine_dev, "bios", optarg);
                 break;
             case QEMU_OPTION_S:
-                autostart = 0;
+                qemu_device_set_bool(machine_dev, "autostart", 0);
                 break;
 	    case QEMU_OPTION_k:
-		keyboard_layout = optarg;
+                qemu_device_set_str(qemu_prefs, "keyboard_layout", optarg);
 		break;
             case QEMU_OPTION_localtime:
-                rtc_utc = 0;
+                qemu_device_set_bool(machine_dev, "localtime", 1);
                 break;
             case QEMU_OPTION_cirrusvga:
-                cirrus_vga_enabled = 1;
-                vmsvga_enabled = 0;
+                qemu_device_set_str(machine_dev, "display", "cirrus");
                 break;
             case QEMU_OPTION_vmsvga:
-                cirrus_vga_enabled = 0;
-                vmsvga_enabled = 1;
+                qemu_device_set_str(machine_dev, "display", "vmsvga");
                 break;
             case QEMU_OPTION_std_vga:
-                cirrus_vga_enabled = 0;
-                vmsvga_enabled = 0;
+                qemu_device_set_str(machine_dev, "display", "vga");
                 break;
             case QEMU_OPTION_g:
+                qemu_device_set_str(machine_dev, "display_params", optarg);
+                break;
+            case QEMU_OPTION_echr:
                 {
-                    const char *p;
-                    int w, h, depth;
-                    p = optarg;
-                    w = strtol(p, (char **)&p, 10);
-                    if (w <= 0) {
-                    graphic_error:
-                        fprintf(stderr, "qemu: invalid resolution or depth\n");
+                    int val;
+                    char *r;
+                    val = strtol(optarg, &r, 0);
+                    if (*r != '\0') {
+                        fprintf(stderr, "Bad argument to echr\n");
                         exit(1);
                     }
-                    if (*p != 'x')
-                        goto graphic_error;
-                    p++;
-                    h = strtol(p, (char **)&p, 10);
-                    if (h <= 0)
-                        goto graphic_error;
-                    if (*p == 'x') {
-                        p++;
-                        depth = strtol(p, (char **)&p, 10);
-                        if (depth != 8 && depth != 15 && depth != 16 &&
-                            depth != 24 && depth != 32)
-                            goto graphic_error;
-                    } else if (*p == '\0') {
-                        depth = graphic_depth;
-                    } else {
-                        goto graphic_error;
-                    }
-
-                    graphic_width = w;
-                    graphic_height = h;
-                    graphic_depth = depth;
+                    qemu_device_set_int(machine_dev, "term_escape_char", val);
                 }
                 break;
-            case QEMU_OPTION_echr:
-                {
-                    char *r;
-                    term_escape_char = strtol(optarg, &r, 0);
-                    if (r == optarg)
-                        printf("Bad argument to echr\n");
-                    break;
-                }
             case QEMU_OPTION_monitor:
-                monitor_device = optarg;
+                qemu_device_set_str(machine_dev, "monitor", optarg);
                 break;
             case QEMU_OPTION_serial:
-                if (serial_device_index >= MAX_SERIAL_PORTS) {
-                    fprintf(stderr, "qemu: too many serial ports\n");
-                    exit(1);
+                {
+                    char buf[128];
+                    if (serial_device_index >= MAX_SERIAL_PORTS) {
+                        fprintf(stderr, "qemu: too many serial ports\n");
+                        exit(1);
+                    }
+                    snprintf(buf, sizeof(buf), "serial%d", 
+                             serial_device_index);
+                    qemu_device_set_str(machine_dev, buf, optarg);
+                    serial_device_index++;
                 }
-                serial_devices[serial_device_index] = optarg;
-                serial_device_index++;
                 break;
             case QEMU_OPTION_parallel:
-                if (parallel_device_index >= MAX_PARALLEL_PORTS) {
-                    fprintf(stderr, "qemu: too many parallel ports\n");
-                    exit(1);
+                {
+                    char buf[128];
+                    if (parallel_device_index >= MAX_PARALLEL_PORTS) {
+                        fprintf(stderr, "qemu: too many parallel ports\n");
+                        exit(1);
+                    }
+                    snprintf(buf, sizeof(buf), "parallel%d", 
+                             parallel_device_index);
+                    qemu_device_set_str(machine_dev, buf, optarg);
+                    parallel_device_index++;
                 }
-                parallel_devices[parallel_device_index] = optarg;
-                parallel_device_index++;
                 break;
 	    case QEMU_OPTION_loadvm:
-		loadvm = optarg;
+                qemu_device_set_str(machine_dev, "loadvm", optarg);
 		break;
             case QEMU_OPTION_full_screen:
-                full_screen = 1;
+                qemu_device_set_bool(qemu_prefs, "full_screen", 1);
                 break;
 #ifdef CONFIG_SDL
             case QEMU_OPTION_no_frame:
-                no_frame = 1;
+                qemu_device_set_bool(qemu_prefs, "sdl_no_frame", 1);
                 break;
             case QEMU_OPTION_alt_grab:
-                alt_grab = 1;
+                qemu_device_set_bool(qemu_prefs, "sdl_alt_grab", 1);
                 break;
             case QEMU_OPTION_no_quit:
-                no_quit = 1;
+                qemu_device_set_bool(qemu_prefs, "sdl_no_quit", 1);
                 break;
 #endif
             case QEMU_OPTION_pidfile:
-                pid_file = optarg;
+                qemu_device_set_str(qemu_prefs, "pidfile", optarg);
                 break;
 #ifdef TARGET_I386
             case QEMU_OPTION_win2k_hack:
-                win2k_install_hack = 1;
+                qemu_device_set_bool(machine_dev, "win2k_hack", 1);
                 break;
 #endif
 #ifdef USE_KQEMU
             case QEMU_OPTION_no_kqemu:
-                kqemu_allowed = 0;
+                qemu_device_set_str(machine_dev, "kqemu", "no");
                 break;
             case QEMU_OPTION_kernel_kqemu:
-                kqemu_allowed = 2;
+                qemu_device_set_str(machine_dev, "kqemu", "kernel");
                 break;
 #endif
             case QEMU_OPTION_usb:
-                usb_enabled = 1;
+                qemu_device_set_bool(machine_dev, "usb", 1);
                 break;
             case QEMU_OPTION_usbdevice:
-                usb_enabled = 1;
-                if (usb_devices_index >= MAX_USB_CMDLINE) {
-                    fprintf(stderr, "Too many USB devices\n");
-                    exit(1);
-                }
-                usb_devices[usb_devices_index] = optarg;
-                usb_devices_index++;
+                qemu_device_set_bool(machine_dev, "usb", 1);
+                usb_device_add_cmdline(optarg);
                 break;
             case QEMU_OPTION_smp:
-                smp_cpus = atoi(optarg);
-                if (smp_cpus < 1 || smp_cpus > MAX_CPUS) {
-                    fprintf(stderr, "Invalid number of CPUs\n");
-                    exit(1);
-                }
+                qemu_device_set_int(machine_dev, "smp", atoi(optarg));
                 break;
 	    case QEMU_OPTION_vnc:
-		vnc_display = optarg;
+                qemu_device_set_str(qemu_prefs, "ui", "vnc");
+                qemu_device_set_str(qemu_prefs, "vnc_params", optarg);
 		break;
             case QEMU_OPTION_no_acpi:
-                acpi_enabled = 0;
+                qemu_device_set_bool(machine_dev, "acpi", 0);
                 break;
             case QEMU_OPTION_no_reboot:
-                no_reboot = 1;
+                qemu_device_set_bool(machine_dev, "reboot", 0);
                 break;
             case QEMU_OPTION_no_shutdown:
-                no_shutdown = 1;
+                qemu_device_set_bool(machine_dev, "shutdown", 0);
                 break;
             case QEMU_OPTION_show_cursor:
-                cursor_hide = 0;
+                qemu_device_set_bool(qemu_prefs, "sdl_show_cursor", 1);
                 break;
 	    case QEMU_OPTION_daemonize:
-		daemonize = 1;
+                qemu_device_set_bool(qemu_prefs, "daemonize", 1);
 		break;
 	    case QEMU_OPTION_option_rom:
-		if (nb_option_roms >= MAX_OPTION_ROMS) {
-		    fprintf(stderr, "Too many option ROMs\n");
-		    exit(1);
-		}
-		option_rom[nb_option_roms] = optarg;
-		nb_option_roms++;
+                {
+                    char buf[128];
+                    snprintf(buf, sizeof(buf), "option_rom%d", 
+                             nb_option_roms);
+                    qemu_device_set_str(machine_dev, buf, optarg);
+                    nb_option_roms++;
+                }
 		break;
             case QEMU_OPTION_semihosting:
-                semihosting_enabled = 1;
+                qemu_device_set_bool(machine_dev, "semihosting", 1);
                 break;
             case QEMU_OPTION_name:
-                qemu_name = optarg;
+                qemu_device_set_str(machine_dev, "name", optarg);
                 break;
 #ifdef TARGET_SPARC
             case QEMU_OPTION_prom_env:
@@ -8255,59 +9276,385 @@
 #endif
 #ifdef TARGET_ARM
             case QEMU_OPTION_old_param:
-                old_param = 1;
+                qemu_device_set_bool(machine_dev, "old_param", 1);
                 break;
 #endif
             case QEMU_OPTION_clock:
-                configure_alarms(optarg);
+                qemu_device_set_str(qemu_prefs, "clock", optarg);
                 break;
             case QEMU_OPTION_startdate:
-                {
-                    struct tm tm;
-                    time_t rtc_start_date;
-                    if (!strcmp(optarg, "now")) {
-                        rtc_date_offset = -1;
-                    } else {
-                        if (sscanf(optarg, "%d-%d-%dT%d:%d:%d",
-                               &tm.tm_year,
-                               &tm.tm_mon,
-                               &tm.tm_mday,
-                               &tm.tm_hour,
-                               &tm.tm_min,
-                               &tm.tm_sec) == 6) {
-                            /* OK */
-                        } else if (sscanf(optarg, "%d-%d-%d",
-                                          &tm.tm_year,
-                                          &tm.tm_mon,
-                                          &tm.tm_mday) == 3) {
-                            tm.tm_hour = 0;
-                            tm.tm_min = 0;
-                            tm.tm_sec = 0;
-                        } else {
-                            goto date_fail;
-                        }
-                        tm.tm_year -= 1900;
-                        tm.tm_mon--;
-                        rtc_start_date = mktimegm(&tm);
-                        if (rtc_start_date == -1) {
-                        date_fail:
-                            fprintf(stderr, "Invalid date format. Valid format are:\n"
-                                    "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n");
-                            exit(1);
-                        }
-                        rtc_date_offset = time(NULL) - rtc_start_date;
-                    }
-                }
+                qemu_device_set_str(machine_dev, "startdate", optarg);
                 break;
             case QEMU_OPTION_tb_size:
-                tb_size = strtol(optarg, NULL, 0);
-                if (tb_size < 0)
-                    tb_size = 0;
+                qemu_device_set_int(qemu_prefs, "tb_size", 
+                                    strtol(optarg, NULL, 0));
                 break;
+            case QEMU_OPTION_md:
+                if (qemu_parse_config(&machine_dev, optarg, 
+                                      QEMU_CONF_ERR_FILE) < 0)
+                    exit(1);
+                has_config = 1;
+                break;
+            case QEMU_OPTION_f:
+                /* already handled */
+                break;
+            case QEMU_OPTION_dump_devices:
+                do_dump_devices = 1;
+                break;
             }
         }
     }
 
+    if (!has_config) {
+        /* if no network clients, we use a default config */
+        machine = find_machine(machine_dev->dev_class->name);
+        if (nb_net_clients == 0 && machine && machine->default_nic_model) {
+            net_add("nic");
+            net_add("user");
+        }
+
+        /* if no config file, we always create the cdrom drive, even
+           if no disk is there */
+
+        if (nb_drives_opt < MAX_DRIVES)
+            drive_add(NULL, CDROM_ALIAS);
+        
+        /* we always create at least one floppy */
+        
+        if (nb_drives_opt < MAX_DRIVES)
+            drive_add(NULL, FD_ALIAS, 0);
+        
+        /* we always create one sd slot, even if no card is in it */
+        
+        if (nb_drives_opt < MAX_DRIVES)
+            drive_add(NULL, SD_ALIAS);
+    }
+
+    /* set net-user options */
+    {
+        QEMUDevice *dev;
+        int i;
+        char buf[64];
+
+        for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+            if (!strcmp(dev->dev_class->name, "net-user"))
+                break;
+        }
+        if (dev) {
+            if (slirp_tftp_prefix) 
+                qemu_device_set_str(dev, "tftp", slirp_tftp_prefix);
+            if (slirp_bootp_filename) 
+                qemu_device_set_str(dev, "bootp", slirp_bootp_filename);
+            if (slirp_smb_path) 
+                qemu_device_set_str(dev, "smb", slirp_smb_path);
+            for(i = 0; i < nb_slirp_redirs; i++) {
+                snprintf(buf, sizeof(buf), "redir%d", i);
+                qemu_device_set_str(dev, buf, slirp_redirs[i]);
+            }
+        }
+    }
+
+    if (use_gdbstub) {
+        qemu_device_set_str(machine_dev, "gdb_server", gdbstub_port);
+    }
+
+    if (do_dump_devices) {
+        dump_devices();
+    }
+
+    /* read back user preferences */
+    ui_str = qemu_device_get_str(qemu_prefs, "ui");
+    if (ui_str[0] == '\0') {
+        /* default ui */
+#if defined(CONFIG_SDL)
+        ui_str = "sdl";
+#elif defined(CONFIG_COCOA)
+        ui_str = "cocoa";
+#else
+        ui_str = "cmdline";
+#endif
+    }
+    if (!strcmp(ui_str, "cmdline")) {
+        nographic = 1;
+    } else 
+    if (!strcmp(ui_str, "vnc")) {
+        vnc_display = qemu_device_get_str(qemu_prefs, "vnc_params");
+    } else 
+#if defined(CONFIG_SDL)
+    if (!strcmp(ui_str, "sdl")) {
+    } else 
+#endif
+#if defined(CONFIG_CURSES)
+    if (!strcmp(ui_str, "curses")) {
+    } else
+#endif
+#if defined(CONFIG_COCOA)
+    if (!strcmp(ui_str, "cocoa")) {
+    } else
+#endif
+    {
+        fprintf(stderr, "qemu: invalid user interface: '%s'\n", ui_str);
+        exit(1);
+    }
+    full_screen = qemu_device_get_bool(qemu_prefs, "full_screen");
+#ifdef CONFIG_SDL
+    no_frame = qemu_device_get_bool(qemu_prefs, "sdl_no_frame");
+    alt_grab = qemu_device_get_bool(qemu_prefs, "sdl_alt_grab");
+    no_quit = qemu_device_get_bool(qemu_prefs, "sdl_no_quit");
+    cursor_hide = !qemu_device_get_bool(qemu_prefs, "sdl_show_cursor");
+#endif
+    keyboard_layout = str_zton(qemu_device_get_str(qemu_prefs, "keyboard_layout"));
+    daemonize = qemu_device_get_bool(qemu_prefs, "daemonize");
+    pid_file = str_zton(qemu_device_get_str(qemu_prefs, "pidfile"));
+    str = qemu_device_get_str(qemu_prefs, "clock");
+    if (str[0] != '\0')
+        configure_alarms(str);
+    tb_size = qemu_device_get_int(qemu_prefs, "tb_size");
+    if (tb_size < 0)
+        tb_size = 0;
+
+    /* read back machine config */
+    machine = find_machine(machine_dev->dev_class->name);
+    snapshot = qemu_device_get_bool(machine_dev, "snapshot");
+    cpu_model = str_zton(qemu_device_get_str(machine_dev, "cpu"));
+    initrd_filename = str_zton(qemu_device_get_str(machine_dev, "initrd"));
+    kernel_filename = str_zton(qemu_device_get_str(machine_dev, "kernel"));
+    kernel_cmdline = qemu_device_get_str(machine_dev, "append");
+    graphic_rotate = qemu_device_get_bool(machine_dev, "portrait");
+    rtc_utc = !qemu_device_get_bool(machine_dev, "localtime");
+    no_reboot = !qemu_device_get_bool(machine_dev, "reboot");
+    no_shutdown = !qemu_device_get_bool(machine_dev, "shutdown");
+#ifdef TARGET_ARM
+    old_param = qemu_device_get_bool(machine_dev, "old_param");
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
+    semihosting_enabled = qemu_device_get_bool(machine_dev, "semihosting");
+#endif
+#ifdef TARGET_I386
+    /* XXX: move that to hw/pc.c */
+    acpi_enabled = qemu_device_get_bool(machine_dev, "acpi");
+    win2k_install_hack = qemu_device_get_bool(machine_dev, "win2k_hack");
+    fd_bootchk = qemu_device_get_bool(machine_dev, "fd_bootchk");
+    {
+        str = qemu_device_get_str(machine_dev, "display");
+        if (str[0] == '\0')
+            str = "cirrus";
+        if (!strcmp(str, "vga")) {
+            cirrus_vga_enabled = 0;
+            vmsvga_enabled = 0;
+        } else if (!strcmp(str, "cirrus")) {
+            cirrus_vga_enabled = 1;
+            vmsvga_enabled = 0;
+        } else if (!strcmp(str, "vmsvga")) {
+            cirrus_vga_enabled = 0;
+            vmsvga_enabled = 1;
+        } else {
+            fprintf(stderr, "qemu: unsupported display: '%s'\n", str);
+            exit(1);
+        }
+    }
+#ifdef USE_KQEMU
+    str = qemu_device_get_str(machine_dev, "kqemu");
+    if (str[0] != '\0') {
+        if (!strcmp(str, "no")) {
+            kqemu_allowed = 0;
+        } else if (!strcmp(str, "user")) {
+            kqemu_allowed = 1;
+        } else if (!strcmp(str, "kernel")) {
+            kqemu_allowed = 2;
+        } else {
+            fprintf(stderr, "qemu: invalid kqemu value: '%s'\n", str);
+            exit(1);
+        }
+    }
+#endif
+#endif
+#if defined(TARGET_PPC) || defined(TARGET_SPARC)
+    {
+        const char *p;
+        int w, h, depth;
+        p = qemu_device_get_str(machine_dev, "display_params");
+        w = strtol(p, (char **)&p, 10);
+        if (w <= 0) {
+        graphic_error:
+            fprintf(stderr, "qemu: invalid resolution or depth\n");
+            exit(1);
+        }
+        if (*p != 'x')
+            goto graphic_error;
+        p++;
+        h = strtol(p, (char **)&p, 10);
+        if (h <= 0)
+            goto graphic_error;
+        if (*p != 'x') 
+            goto graphic_error;
+        p++;
+        depth = strtol(p, (char **)&p, 10);
+        if (depth != 8 && depth != 15 && depth != 16 &&
+            depth != 24 && depth != 32)
+            goto graphic_error;
+        
+        graphic_width = w;
+        graphic_height = h;
+        graphic_depth = depth;
+    }
+#endif
+    qemu_name = str_zton(qemu_device_get_str(machine_dev, "name"));
+    autostart = qemu_device_get_bool(machine_dev, "autostart");
+    term_escape_char = qemu_device_get_int(machine_dev, "term_escape_char");
+    {
+        int i;
+        char buf[128];
+        monitor_device = str_zton(qemu_device_get_str(machine_dev, "monitor"));
+        for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+            snprintf(buf, sizeof(buf), "serial%d", i);
+            serial_devices[i] = str_zton(qemu_device_get_str(machine_dev, buf));
+        }
+        for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+            snprintf(buf, sizeof(buf), "parallel%d", i);
+            parallel_devices[i] = str_zton(qemu_device_get_str(machine_dev, buf));
+        }
+    }
+
+    /* set default devices */
+    if (nographic) {
+        if (!monitor_device)
+            monitor_device = "stdio";
+        if (!serial_devices[0])
+            serial_devices[0] = "stdio";
+        if (!parallel_devices[0])
+            parallel_devices[0] = "null";
+    } else {
+        if (!monitor_device)
+            monitor_device = "vc:800x600";
+        if (!serial_devices[0])
+            serial_devices[0] = "vc:80Cx24C";
+        if (!parallel_devices[0])
+            parallel_devices[0] = "vc:80Cx24C";
+    }
+    
+    str = qemu_device_get_str(machine_dev, "bios_dir");
+    if (str[0] != '\0')
+        bios_dir = str;
+    bios_name = str_zton(qemu_device_get_str(machine_dev, "bios"));
+
+    {
+        int mask;
+        CPULogItem *item;
+        const char *str;
+        str = qemu_device_get_str(machine_dev, "debug");
+        if (str[0] != '\0') {
+            mask = cpu_str_to_log_mask(str);
+            if (!mask) {
+                printf("Log items (comma separated):\n");
+                for(item = cpu_log_items; item->mask != 0; item++) {
+                    printf("%-10s %s\n", item->name, item->help);
+                }
+                exit(1);
+            }
+            cpu_set_log(mask);
+        }
+    }
+    {
+        smp_cpus = qemu_device_get_int(machine_dev, "smp");
+        if (smp_cpus < 1 || smp_cpus > MAX_CPUS) {
+            fprintf(stderr, "Invalid number of CPUs\n");
+            exit(1);
+        }
+    }
+
+    {
+        uint64_t value;
+        value = qemu_device_get_int(machine_dev, "ramsize");
+        value <<= 20;
+
+        /* On 32-bit hosts, QEMU is limited by virtual address space */
+        if (value > (2047 << 20)
+#ifndef USE_KQEMU
+            && HOST_LONG_BITS == 32
+#endif
+            ) {
+            fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n");
+            exit(1);
+        }
+        if (value != (uint64_t)(ram_addr_t)value) {
+            fprintf(stderr, "qemu: ram size too large\n");
+            exit(1);
+        }
+        ram_size = value;
+    }
+    
+    {
+        /* Could easily be extended to 64 devices if needed */
+        const char *p;
+        
+        boot_devices = qemu_device_get_str(machine_dev, "boot");
+        boot_devices_bitmap = 0;
+        for (p = boot_devices; *p != '\0'; p++) {
+            /* Allowed boot devices are:
+             * a b     : floppy disk drives
+             * c ... f : IDE disk drives
+             * g ... m : machine implementation dependant drives
+             * n ... p : network devices
+             * It's up to each machine implementation to check
+             * if the given boot devices match the actual hardware
+             * implementation and firmware features.
+             */
+            if (*p < 'a' || *p > 'q') {
+                fprintf(stderr, "Invalid boot device '%c'\n", *p);
+                exit(1);
+            }
+            if (boot_devices_bitmap & (1 << (*p - 'a'))) {
+                fprintf(stderr,
+                        "Boot device '%c' was given twice\n",*p);
+                            exit(1);
+            }
+            boot_devices_bitmap |= 1 << (*p - 'a');
+        }
+    }
+
+    {
+        struct tm tm;
+        time_t rtc_start_date;
+        const char *start_date;
+        start_date = qemu_device_get_str(machine_dev, "startdate");
+        if (start_date[0] == '\0' || !strcmp(start_date, "now")) {
+            rtc_date_offset = -1;
+        } else {
+            if (sscanf(start_date, "%d-%d-%dT%d:%d:%d",
+                       &tm.tm_year,
+                       &tm.tm_mon,
+                       &tm.tm_mday,
+                       &tm.tm_hour,
+                       &tm.tm_min,
+                       &tm.tm_sec) == 6) {
+                /* OK */
+            } else if (sscanf(start_date, "%d-%d-%d",
+                              &tm.tm_year,
+                              &tm.tm_mon,
+                              &tm.tm_mday) == 3) {
+                tm.tm_hour = 0;
+                tm.tm_min = 0;
+                tm.tm_sec = 0;
+            } else {
+                goto date_fail;
+            }
+            tm.tm_year -= 1900;
+            tm.tm_mon--;
+            rtc_start_date = mktimegm(&tm);
+            if (rtc_start_date == -1) {
+            date_fail:
+                fprintf(stderr, "Invalid date format. Valid format are:\n"
+                        "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n");
+                exit(1);
+            }
+            rtc_date_offset = time(NULL) - rtc_start_date;
+        }
+    }
+    gdbstub_port = str_zton(qemu_device_get_str(machine_dev, "gdb_server"));
+    usb_enabled = qemu_device_get_bool(machine_dev, "usb");
+    loadvm = str_zton(qemu_device_get_str(machine_dev, "loadvm"));
+
 #ifndef _WIN32
     if (daemonize && !nographic && vnc_display == NULL) {
 	fprintf(stderr, "Can only daemonize if using -nographic or -vnc\n");
@@ -8377,7 +9724,7 @@
 
     /* XXX: this should not be: some embedded targets just have flash */
     if (!linux_boot && net_boot == 0 &&
-        nb_drives_opt == 0)
+        nb_drives_opt == 0 && !has_config)
         help(1);
 
     /* boot to floppy or the default cd if no hard disk defined yet */
@@ -8394,53 +9741,52 @@
     socket_init();
 #endif
 
-    /* init network clients */
-    if (nb_net_clients == 0) {
-        /* if no clients, we use a default config */
-        net_clients[0] = "nic";
-        net_clients[1] = "user";
-        nb_net_clients = 2;
-    }
 
-    for(i = 0;i < nb_net_clients; i++) {
-        if (net_client_init(net_clients[i]) < 0)
-            exit(1);
-    }
-    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
-        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
-            continue;
-        if (vlan->nb_guest_devs == 0) {
-            fprintf(stderr, "Invalid vlan (%d) with no nics\n", vlan->id);
-            exit(1);
+#ifdef TARGET_I386
+    {
+        char buf[128];
+        const char *str;
+
+        nb_option_roms = 0;
+        while (nb_option_roms < MAX_OPTION_ROMS) {
+            snprintf(buf, sizeof(buf), "option_rom%d", nb_option_roms);
+            str = qemu_device_get_str(machine_dev, buf);
+            if (str[0] == '\0')
+                break;
+            option_rom[nb_option_roms++] = str;
         }
-        if (vlan->nb_host_devs == 0)
-            fprintf(stderr,
-                    "Warning: vlan %d is not connected to host network\n",
-                    vlan->id);
     }
 
-#ifdef TARGET_I386
     /* XXX: this should be moved in the PC machine instantiation code */
+    /* XXX: it would have been better to add a ROM option to the
+       network adapter */
     if (net_boot != 0) {
         int netroms = 0;
-	for (i = 0; i < nb_nics && i < 4; i++) {
-	    const char *model = nd_table[i].model;
-	    char buf[1024];
-            if (net_boot & (1 << i)) {
-                if (model == NULL)
-                    model = "ne2k_pci";
-                snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model);
-                if (get_image_size(buf) > 0) {
-                    if (nb_option_roms >= MAX_OPTION_ROMS) {
-                        fprintf(stderr, "Too many option ROMs\n");
-                        exit(1);
+        QEMUDevice *dev;
+        QEMUDeviceClass *dc;
+        i = 0;
+        for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+            dc = dev->dev_class;
+            if (qemu_class_instanceof(dc, qemu_eth_class)) {
+                const char *model = dc->name;
+                char buf[1024];
+                if (net_boot & (1 << i)) {
+                    snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model);
+                    if (get_image_size(buf) > 0) {
+                        if (nb_option_roms >= MAX_OPTION_ROMS) {
+                            fprintf(stderr, "Too many option ROMs\n");
+                            exit(1);
+                        }
+                        option_rom[nb_option_roms] = strdup(buf);
+                        nb_option_roms++;
+                        netroms++;
                     }
-                    option_rom[nb_option_roms] = strdup(buf);
-                    nb_option_roms++;
-                    netroms++;
                 }
+                i++;
+                if (i >= 4)
+                    break;
             }
-	}
+        }
 	if (netroms == 0) {
 	    fprintf(stderr, "No valid PXE rom found for network device\n");
 	    exit(1);
@@ -8480,27 +9826,9 @@
 
     bdrv_init();
 
-    /* we always create the cdrom drive, even if no disk is there */
-
-    if (nb_drives_opt < MAX_DRIVES)
-        drive_add(NULL, CDROM_ALIAS);
-
-    /* we always create at least one floppy */
-
-    if (nb_drives_opt < MAX_DRIVES)
-        drive_add(NULL, FD_ALIAS, 0);
-
-    /* we always create one sd slot, even if no card is in it */
-
-    if (nb_drives_opt < MAX_DRIVES)
-        drive_add(NULL, SD_ALIAS);
-
     /* open the virtual block devices */
+    drives_init();
 
-    for(i = 0; i < nb_drives_opt; i++)
-        if (drive_init(&drives_opt[i], snapshot, machine) == -1)
-	    exit(1);
-
     register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
     register_savevm("ram", 0, 2, ram_save, ram_load, NULL);
 
@@ -8508,35 +9836,36 @@
 
     /* terminal init */
     memset(&display_state, 0, sizeof(display_state));
-    if (nographic) {
-        if (curses) {
-            fprintf(stderr, "fatal: -nographic can't be used with -curses\n");
-            exit(1);
-        }
-        /* nearly nothing to do */
+    if (!strcmp(ui_str, "cmdline")) {
         dumb_display_init(ds);
-    } else if (vnc_display != NULL) {
+    } else 
+    if (!strcmp(ui_str, "vnc")) {
         vnc_display_init(ds);
         if (vnc_display_open(ds, vnc_display) < 0)
             exit(1);
     } else
 #if defined(CONFIG_CURSES)
-    if (curses) {
+    if (!strcmp(ui_str, "curses")) {
         curses_display_init(ds, full_screen);
     } else
 #endif
-    {
 #if defined(CONFIG_SDL)
+    if (!strcmp(ui_str, "sdl")) {
         sdl_display_init(ds, full_screen, no_frame);
-#elif defined(CONFIG_COCOA)
+    } else
+#endif
+#if defined(CONFIG_COCOA)
+    if (!strcmp(ui_str, "cocoa")) {
         cocoa_display_init(ds, full_screen);
-#else
-        dumb_display_init(ds);
+    } else
 #endif
+    {
+        fprintf(stderr, "qemu: invalid user interface: '%s'\n", ui_str);
+        exit(1);
     }
 
     /* Maintain compatibility with multiple stdio monitors */
-    if (!strcmp(monitor_device,"stdio")) {
+    if (monitor_device && !strcmp(monitor_device,"stdio")) {
         for (i = 0; i < MAX_SERIAL_PORTS; i++) {
             const char *devname = serial_devices[i];
             if (devname && !strcmp(devname,"mon:stdio")) {
@@ -8586,17 +9915,23 @@
         }
     }
 
+    machine_dev->instantiated = 1;
     machine->init(ram_size, vga_ram_size, boot_devices, ds,
                   kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
 
-    /* init USB devices */
-    if (usb_enabled) {
-        for(i = 0; i < usb_devices_index; i++) {
-            if (usb_device_add(usb_devices[i]) < 0) {
-                fprintf(stderr, "Warning: could not add USB device %s\n",
-                        usb_devices[i]);
-            }
+    generic_device_init();
+
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
+            continue;
+        if (vlan->nb_guest_devs == 0) {
+            fprintf(stderr, "Invalid vlan (%d) with no nics\n", vlan->id);
+            exit(1);
         }
+        if (vlan->nb_host_devs == 0)
+            fprintf(stderr,
+                    "Warning: vlan %d is not connected to host network\n",
+                    vlan->id);
     }
 
     if (display_state.dpy_refresh) {
@@ -8605,7 +9940,7 @@
     }
 
 #ifdef CONFIG_GDBSTUB
-    if (use_gdbstub) {
+    if (gdbstub_port) {
         /* XXX: use standard host:port notation and modify options
            accordingly. */
         if (gdbserver_start(gdbstub_port) < 0) {
Index: net.h
===================================================================
--- net.h	(revision 4734)
+++ net.h	(working copy)
@@ -40,11 +40,7 @@
 
 struct NICInfo {
     uint8_t macaddr[6];
-    const char *model;
     VLANState *vlan;
 };
 
-extern int nb_nics;
-extern NICInfo nd_table[MAX_NICS];
-
 #endif
Index: device.c
===================================================================
--- device.c	(revision 0)
+++ device.c	(revision 0)
@@ -0,0 +1,984 @@
+/*
+ * QEMU Device and configuration managament
+ *
+ * Copyright (c) 2008 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
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "console.h"
+
+typedef union {
+    int64_t i;
+    char *str;
+} QEMUFieldValue;
+
+struct QEMUDeviceClassField {
+    QEMUTypeEnum type;
+    char *name;
+    struct QEMUDeviceClassField *next_field;
+};
+
+typedef struct QEMUDeviceClassInitField {
+    QEMUDeviceClassField *field;
+    struct QEMUDeviceClassInitField *next_init_field;
+    QEMUFieldValue u;
+} QEMUDeviceClassInitField;
+
+typedef struct QEMUDeviceField {
+    struct QEMUDeviceField *next_field;
+    QEMUDeviceClassField *field;
+    QEMUFieldValue u;
+} QEMUDeviceField;
+
+static QEMUDeviceClassField *qemu_class_find_field(QEMUDeviceClass *dc,
+                                                   const char *name);
+
+static QEMUDeviceClass *qemu_first_class;
+QEMUDevice *qemu_first_device;
+
+QEMUDeviceClass *qemu_class_new(const char *name, int flags,
+                                const char *descr)
+{
+    QEMUDeviceClass *dc, **pdc;
+    dc = qemu_mallocz(sizeof(QEMUDeviceClass));
+    if (!dc)
+        return NULL;
+    dc->name = qemu_strdup(name);
+    if (descr)
+        dc->descr = qemu_strdup(descr);
+    dc->flags = flags;
+    pdc = &qemu_first_class;
+    while (*pdc != NULL)
+        pdc = &(*pdc)->next_class;
+    *pdc = dc;
+    return dc;
+}
+
+int qemu_class_add_parent(QEMUDeviceClass *dc, 
+                          QEMUDeviceClass *parent)
+{
+    if (dc->nb_parents >= QEMU_CLASS_MAX_PARENTS)
+        return -1;
+    dc->parents[dc->nb_parents++] = parent;
+    return 0;
+}
+
+QEMUDeviceClassField *qemu_class_field_new(QEMUDeviceClass *dc, 
+                                           const char *name,
+                                           QEMUTypeEnum type)
+{
+    QEMUDeviceClassField *dcf, **pdcf;
+    int i;
+
+    /* No duplicate field overriding */
+    for(i = 0; i < dc->nb_parents; i++) {
+        dcf = qemu_class_find_field(dc->parents[i], name);
+        if (dcf)
+            return NULL;
+    }
+
+    dcf = qemu_mallocz(sizeof(QEMUDeviceClassField));
+    if (!dcf)
+        return NULL;
+    dcf->name = qemu_strdup(name);
+    dcf->type = type;
+    pdcf = &dc->first_field;
+    while (*pdcf != NULL)
+        pdcf = &(*pdcf)->next_field;
+    *pdcf = dcf;
+    return dcf;
+}
+
+QEMUDeviceClass *qemu_class_find(const char *name)
+{
+    QEMUDeviceClass *dc;
+    for(dc = qemu_first_class; dc != NULL; dc = dc->next_class) {
+        if (!strcmp(dc->name, name))
+            return dc;
+    }
+    return NULL;
+}
+
+/* return true if dc1 = dc2 or if dc2 is a parent of dc1 */
+int qemu_class_instanceof(QEMUDeviceClass *dc1, QEMUDeviceClass *dc2)
+{
+    int i, ret;
+
+    if (dc1 == dc2)
+        return 1;
+    for(i = 0; i < dc1->nb_parents; i++) {
+        ret = qemu_class_instanceof(dc1->parents[i], dc2);
+        if (ret)
+            return ret;
+    }
+    return 0;
+}
+
+static QEMUDeviceClassField *qemu_class_find_field(QEMUDeviceClass *dc,
+                                                   const char *name)
+{
+    QEMUDeviceClassField *dcf;
+    int i;
+
+    /* look first in class fields */
+    for(dcf = dc->first_field; dcf != NULL; dcf = dcf->next_field) {
+        if (!strcmp(dcf->name, name))
+            return dcf;
+    }
+    
+    /* then in parents */
+    for(i = 0; i < dc->nb_parents; i++) {
+        dcf = qemu_class_find_field(dc->parents[i], name);
+        if (dcf)
+            return dcf;
+    }
+    return NULL;
+}
+
+static QEMUDeviceClassInitField *qemu_class_find_default(QEMUDeviceClass *dc,
+                                                         QEMUDeviceClassField *dcf)
+{
+    QEMUDeviceClassInitField *dci;
+    int i;
+
+    for(dci = dc->first_init_field; dci != NULL; dci = dci->next_init_field) {
+        if (dci->field == dcf)
+            return dci;
+    }
+    /* find in parents */
+    for(i = 0; i < dc->nb_parents; i++) {
+        dci = qemu_class_find_default(dc->parents[i], dcf);
+        if (dci)
+            return dci;
+    }
+    return NULL;
+}
+
+/* set default value for a class field */
+static int qemu_class_set_default(QEMUDeviceClass *dc, const char *name,
+                                  QEMUTypeEnum type, QEMUFieldValue val)
+{
+    QEMUDeviceClassField *dcf;
+    QEMUDeviceClassInitField *dci;
+    dcf = qemu_class_find_field(dc, name);
+    if (dcf->type != type)
+        return -EINVAL;
+    for(dci = dc->first_init_field; dci != NULL; dci = dci->next_init_field) {
+        if (dci->field == dcf)
+            break;
+    }
+    if (!dci) {
+        dci = qemu_mallocz(sizeof(QEMUDeviceClassInitField));
+        dci->field = dcf;
+        dci->next_init_field = dc->first_init_field;
+        dc->first_init_field = dci;
+    }
+    if (type == QEMU_CTYPE_STR) {
+        qemu_free(dci->u.str);
+        dci->u.str = qemu_strdup(val.str);
+    } else {
+        dci->u = val;
+    }
+    return 0;
+}
+
+int qemu_class_set_int(QEMUDeviceClass *dc, const char *name,
+                       int64_t val)
+{
+    QEMUFieldValue u;
+    u.i = val;
+    return qemu_class_set_default(dc, name, QEMU_CTYPE_INT, u);
+}
+
+int qemu_class_set_bool(QEMUDeviceClass *dc, const char *name,
+                        int val)
+{
+    QEMUFieldValue u;
+    u.i = val;
+    return qemu_class_set_default(dc, name, QEMU_CTYPE_BOOL, u);
+}
+
+int qemu_class_set_str(QEMUDeviceClass *dc, const char *name,
+                       const char *str)
+{
+    QEMUFieldValue u;
+    u.str = (char *)str;
+    return qemu_class_set_default(dc, name, QEMU_CTYPE_STR, u);
+}
+
+QEMUDevice *qemu_device_find(const char *name)
+{
+    QEMUDevice *dev;
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (!strcmp(name, dev->name))
+            return dev;
+    }
+    return NULL;
+}
+
+static QEMUDevice *qemu_device_new1(QEMUDeviceClass *dc, const char *name)
+{
+    QEMUDevice *dev;
+
+    dev = qemu_device_find(name);
+    if (dev)
+        return NULL;
+    dev = qemu_mallocz(sizeof(QEMUDevice));
+    if (!dev)
+        return NULL;
+    dev->name = strdup(name);
+    dev->dev_class = dc;
+    return dev;
+}
+
+QEMUDevice *qemu_device_new(QEMUDeviceClass *dc, const char *name)
+{
+    QEMUDevice *dev, **pdev;
+    dev = qemu_device_new1(dc, name);
+    if (!dev)
+        return NULL;
+    pdev = &qemu_first_device;
+    while (*pdev != NULL)
+        pdev = &(*pdev)->dev_next;
+    *pdev = dev;
+    return dev;
+}
+
+/* insert the device after dev1 */
+QEMUDevice *qemu_device_new_after(QEMUDeviceClass *dc, const char *name,
+                                  QEMUDevice *dev1)
+{
+    QEMUDevice *dev;
+    dev = qemu_device_new1(dc, name);
+    if (!dev)
+        return NULL;
+    dev->dev_next = dev1->dev_next;
+    dev1->dev_next = dev;
+    return dev;
+}
+
+/* same as qemu_device_new, but add a number to ensure the device name
+   is new */
+QEMUDevice *qemu_device_new_nodup(QEMUDeviceClass *dc, const char *base_name)
+{
+    char buf[1024];
+    int i;
+
+    i = 0;
+    for(;;) {
+        snprintf(buf, sizeof(buf), "%s%d", base_name, i);
+        if (!qemu_device_find(buf))
+            break;
+        i++;
+    }
+    return qemu_device_new(dc, buf);
+}
+
+void qemu_device_delete(QEMUDevice *dev)
+{
+    QEMUDevice **pdev;
+    QEMUDeviceField *df, *df_next;
+
+    pdev = &qemu_first_device;
+    while (*pdev != NULL && *pdev != dev) {
+        pdev = &(*pdev)->dev_next;
+    }
+    if (*pdev == NULL)
+        return;
+    *pdev = dev->dev_next;
+
+    for(df = dev->first_field; df != NULL; df = df_next) {
+        df_next = df->next_field;
+        if (df->field->type == QEMU_CTYPE_STR)
+            qemu_free(df->u.str);
+        qemu_free(df);
+    }
+
+    qemu_free(dev->name);
+    qemu_free(dev);
+}
+
+static int qemu_device_set_field(QEMUDevice *dev, const char *name,
+                                 QEMUTypeEnum type, QEMUFieldValue val)
+{
+    QEMUDeviceField *df, **pdf;
+    QEMUDeviceClassField *dcf;
+
+    dcf = qemu_class_find_field(dev->dev_class, name);
+    if (!dcf)
+        return -ENOENT;
+    if (dcf->type != type)
+        return -EINVAL;
+    
+    for(df = dev->first_field; df != NULL; df = df->next_field) {
+        if (df->field == dcf)
+            break;
+    }
+    if (!df) {
+        df = qemu_mallocz(sizeof(QEMUDeviceField));
+        if (!df)
+            return -ENOMEM;
+        df->field = dcf;
+        pdf = &dev->first_field;
+        while (*pdf != NULL)
+            pdf = &(*pdf)->next_field;
+        *pdf = df;
+    }
+    if (type == QEMU_CTYPE_STR) {
+        qemu_free(df->u.str);
+        df->u.str = qemu_strdup(val.str);
+    } else {
+        df->u = val;
+    }
+    return 0;
+}
+
+int qemu_device_set_int(QEMUDevice *dev, const char *name, int64_t val)
+{
+    QEMUFieldValue u;
+    u.i = val;
+    return qemu_device_set_field(dev, name, QEMU_CTYPE_INT, u);
+}
+                        
+int qemu_device_set_bool(QEMUDevice *dev, const char *name, int val)
+{
+    QEMUFieldValue u;
+    u.i = (val != 0);
+    return qemu_device_set_field(dev, name, QEMU_CTYPE_BOOL, u);
+}
+
+int qemu_device_set_str(QEMUDevice *dev, const char *name, const char *str)
+{
+    QEMUFieldValue u;
+    u.str = (char *)str;
+    return qemu_device_set_field(dev, name, QEMU_CTYPE_STR, u);
+}
+
+/* Note: if there is an error, a zero (or empty string) is returned */
+static int qemu_device_get_field(QEMUDevice *dev, 
+                                 const char *name,
+                                 QEMUTypeEnum type,
+                                 QEMUFieldValue *pu)
+{
+    QEMUDeviceField *df;
+    QEMUDeviceClassField *dcf;
+    QEMUDeviceClassInitField *dci;
+    int ret;
+
+    dcf = qemu_class_find_field(dev->dev_class, name);
+    if (!dcf) {
+        ret = -ENOENT;
+        /* for debug */
+        fprintf(stderr, "%s: unknown field '%s'\n", dev->name, name);
+        goto fail;
+    }
+    if (dcf->type != type) {
+        fprintf(stderr, "%s: bad type for field '%s'\n", dev->name, name);
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    /* is there a field ? */
+    for(df = dev->first_field; df != NULL; df = df->next_field) {
+        if (df->field == dcf) {
+            *pu = df->u;
+            return 0;
+        }
+    }
+    
+    dci = qemu_class_find_default(dev->dev_class, dcf);
+    if (dci) {
+        *pu = dci->u;
+        return 0;
+    }
+    ret = 0;
+ fail:
+    switch(type) {
+    case QEMU_CTYPE_INT:
+    case QEMU_CTYPE_BOOL:
+        pu->i = 0;
+        break;
+    case QEMU_CTYPE_STR:
+        pu->str = (char *)"";
+        break;
+    }
+    return ret;
+}
+
+int64_t qemu_device_get_int(QEMUDevice *dev, const char *name)
+{
+    QEMUFieldValue u;
+    qemu_device_get_field(dev, name, QEMU_CTYPE_INT, &u);
+    return u.i;
+}
+
+int qemu_device_get_bool(QEMUDevice *dev, const char *name)
+{
+    QEMUFieldValue u;
+    qemu_device_get_field(dev, name, QEMU_CTYPE_BOOL, &u);
+    return u.i;
+}
+
+/* Note: NULL is never returned */
+const char *qemu_device_get_str(QEMUDevice *dev, const char *name)
+{
+    QEMUFieldValue u;
+    qemu_device_get_field(dev, name, QEMU_CTYPE_STR, &u);
+    return u.str;
+}
+
+static void __attribute__((format(printf, 3, 4))) parse_error(const char *filename, int line_num,
+                        const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "%s:%d: ", filename, line_num);
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+}
+
+static inline int is_first_ident(int c)
+{
+    return (c >= 'a' && c <= 'z') ||
+        (c >= 'A' && c <= 'Z') ||
+        (c == '_');
+}
+
+static inline int is_next_ident(int c)
+{
+    return (c >= 'a' && c <= 'z') ||
+        (c >= 'A' && c <= 'Z') ||
+        (c >= '0' && c <= '9') ||
+        (c == '_');
+}
+
+const char *ctype_str[3] = {
+    "string",
+    "bool",
+    "int",
+};
+
+void dump_value(QEMUTypeEnum type, QEMUFieldValue u)
+{
+    switch(type) {
+    case QEMU_CTYPE_STR:
+        printf("\"%s\"", u.str);
+        break;
+    case QEMU_CTYPE_INT:
+        printf("%" PRId64, u.i);
+        break;
+    case QEMU_CTYPE_BOOL:
+        if (u.i)
+            printf("true");
+        else
+            printf("false");
+        break;
+    default:
+        break;
+    }
+}
+
+void dump_classes(void)
+{
+    QEMUDeviceClass *dc;
+    QEMUDeviceClassField *dcf;
+    QEMUDeviceClassInitField *dci;
+    int i;
+
+    for(dc = qemu_first_class; dc != NULL; dc = dc->next_class) {
+        printf("Class %s", dc->name);
+        if (dc->nb_parents > 0) {
+            printf(": ");
+            for(i = 0; i < dc->nb_parents; i++) {
+                if (i != 0)
+                    printf(", ");
+                printf("%s", dc->parents[i]->name);
+            }
+        }
+        if (dc->flags & QEMU_CLASS_ABSTRACT)
+            printf(" [abstract]");
+        if (dc->descr) {
+            printf(" {%s}", dc->descr);
+        }
+        printf("\n");
+        for(dcf = dc->first_field; dcf != NULL; dcf = dcf->next_field) {
+            printf("  %s: %s\n", dcf->name, ctype_str[dcf->type]);
+        }
+        
+        if (dc->first_init_field) {
+            printf("\n  Defaults:\n");
+            for(dci = dc->first_init_field; dci != NULL; dci = dci->next_init_field) {
+                printf("    %s = ", dci->field->name);
+                dump_value(dci->field->type, dci->u);
+                printf("\n");
+            }
+        }
+
+        printf("\n");
+    }
+}
+
+void dump_devices(void)
+{
+    QEMUDevice *dev;
+    QEMUDeviceField *df;
+
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        printf("%s.type = \"%s\"\n", dev->name, dev->dev_class->name);
+        for(df = dev->first_field; df != NULL; df = df->next_field) {
+            printf("%s.%s = ", dev->name, df->field->name);
+            dump_value(df->field->type, df->u);
+            printf("\n");
+        }
+        printf("\n");
+    }
+}
+
+int qemu_parse_config(QEMUDevice **pmain_dev, const char *filename, int flags)
+{
+    QEMUFile *f;
+    char line[1024];
+    const char *p;
+    char obj_name[128], *q, field_name[128], buf[1024];
+    int line_num;
+    QEMUTypeEnum type;
+    QEMUFieldValue u;
+
+    f = qemu_fopen(filename, "rb");
+    if (!f) {
+        if (flags & QEMU_CONF_ERR_FILE)
+            perror(filename);
+        return -2;
+    }
+    line_num = 0;
+    for(;;) {
+        line_num++;
+        if (qemu_get_line(f, line, sizeof(line)) < 0)
+            break;
+        p = line;
+        while (isspace(*(uint8_t *)p))
+            p++;
+        if (*p == '#')
+            continue;
+        if (*p == '\0')
+            continue;
+
+        if (!is_first_ident(*(uint8_t *)p)) {
+            parse_error(filename, line_num, "object or field name expected");
+            goto fail;
+        }
+        q = obj_name;
+        while (is_next_ident(*(uint8_t *)p)) {
+            if ((q - obj_name) < sizeof(obj_name) - 1)
+                *q++ = *p;
+            p++;
+        }
+        *q = '\0';
+
+        while (isspace(*(uint8_t *)p))
+            p++;
+
+        if (*p == '.') {
+            p++;
+            while (isspace(*(uint8_t *)p))
+                p++;
+            if (!is_first_ident(*(uint8_t *)p)) {
+                parse_error(filename, line_num, "field name expected");
+                goto fail;
+            }
+            q = field_name;
+            while (is_next_ident(*(uint8_t *)p)) {
+                if ((q - field_name) < sizeof(field_name) - 1)
+                    *q++ = *p;
+                p++;
+            }
+            *q = '\0';
+        } else {
+            pstrcpy(field_name, sizeof(field_name), obj_name);
+            obj_name[0] = '\0';
+        }
+        
+        while (isspace(*(uint8_t *)p))
+            p++;
+        if (*p != '=') {
+            parse_error(filename, line_num, "'=' expected");
+            goto fail;
+        }
+        p++;
+        while (isspace(*(uint8_t *)p))
+            p++;
+        
+        if (*p == '"') {
+            p++;
+            q = buf;
+            for(;;) {
+                if (*p == '\0') {
+                    parse_error(filename, line_num, "'\"' expected");
+                    goto fail;
+                } else if (*p == '"') {
+                    p++;
+                    break;
+                } else if (*p == '\\') {
+                    p++;
+                    switch(*(uint8_t *)p) {
+                    case '\"':
+                    case '\'':
+                    case '\\':
+                        *q++ = *p++;
+                        break;
+                    case 'r':
+                        *q++ = '\r';
+                        p++;
+                        break;
+                    case 'n':
+                        *q++ = '\n';
+                        p++;
+                        break;
+                    case 't':
+                        *q++ = '\t';
+                        p++;
+                        break;
+                    case '0' ... '7':
+                        {
+                            int v, i, c;
+                            v = 0;
+                            for(i=0;i<3;i++) {
+                                c = *(uint8_t *)p;
+                                if (c >= '0' && c <= '7')
+                                    v = v * 8 + c - '0';
+                                else
+                                    break;
+                                p++;
+                            }
+                            *q++ = v;
+                        }
+                        break;
+                        /* XXX: add 'x' quoted with UTF8 encoding */
+                    default:
+                        parse_error(filename, line_num, "invalid backquoted character");
+                        goto fail;
+                    }
+                } else {
+                    *q++ = *p++;
+                }
+            }
+            *q = '\0';
+            type = QEMU_CTYPE_STR;
+            u.str = buf;
+        } else if (isdigit(*(uint8_t *)p)) {
+            u.i = strtoll(p, (char **)&p, 0);
+            type = QEMU_CTYPE_INT;
+        } else {
+            q = buf;
+            while (*p != '\0' && !isspace(*(uint8_t *)p)) {
+                *q++ = *p++;
+            }
+            *q = '\0';
+            if (!strcmp(buf, "true")) {
+                u.i = 1;
+                type = QEMU_CTYPE_BOOL;
+            } else if (!strcmp(buf, "false")) {
+                u.i = 0;
+                type = QEMU_CTYPE_BOOL;
+            } else {
+                parse_error(filename, line_num, "invalid value");
+                goto fail;
+            }
+        }
+        while (isspace(*(uint8_t *)p))
+            p++;
+        if (*p != '\0' && *p != '#') {
+            parse_error(filename, line_num, "unexpected chars at end of line");
+            goto fail;
+        }
+#if 0
+        {
+            printf("obj=%s field=%s val=", obj_name, field_name);
+            dump_value(type, u);
+            printf("\n");
+        }
+#endif
+        if (!strcmp(field_name, "type")) {
+            QEMUDeviceClass *dc;
+            QEMUDevice *dev;
+
+            if (flags & QEMU_CONF_NO_OBJ) {
+                parse_error(filename, line_num, "new object instantiation not allowed here");
+                goto fail;
+            }
+            /* type field means instance creation */
+            if (type != QEMU_CTYPE_STR) {
+                parse_error(filename, line_num, "string value expected");
+                goto fail;
+            }
+            dc = qemu_class_find(u.str);
+            if (!dc) {
+                parse_error(filename, line_num, "type '%s' does not exist",
+                            u.str);
+                goto fail;
+            }
+            if (dc->flags & QEMU_CLASS_ABSTRACT) {
+                parse_error(filename, line_num, "abstract classes cannot be instantiated");
+                goto fail;
+            }
+
+            if (obj_name[0] == '\0') {
+                /* In order to allow a machine type change from the
+                   command line, we allow a type change for the main
+                   object. The previous object is destroyed. */
+                if (dc != (*pmain_dev)->dev_class) {
+                    char name[128];
+                    pstrcpy(name, sizeof(name), (*pmain_dev)->name);
+                    qemu_device_delete(*pmain_dev);
+                    *pmain_dev = qemu_device_new(dc, name);
+                }
+            } else {
+                dev = qemu_device_new(dc, obj_name);
+                if (!dev) {
+                    parse_error(filename, line_num, "object '%s' already exists",
+                                obj_name);
+                    goto fail;
+                }
+            }
+        } else {
+            QEMUDevice *dev;
+            QEMUDeviceClassField *dcf;
+            int ret;
+
+            if (obj_name[0] == '\0') {
+                dev = *pmain_dev;
+            } else {
+                dev = qemu_device_find(obj_name);
+            }
+            if (!dev) {
+                parse_error(filename, line_num, "object '%s' is not defined",
+                            obj_name);
+                goto fail;
+            }
+            dcf = qemu_class_find_field(dev->dev_class, field_name);
+            if (dcf && 
+                dcf->type == QEMU_CTYPE_BOOL && 
+                type == QEMU_CTYPE_INT) {
+                /* convert int to bool */
+                if (u.i != 0 && u.i != 1) {
+                    parse_error(filename, line_num, "boolean value expected");
+                    goto fail;
+                }
+                type = QEMU_CTYPE_BOOL;
+            }
+            switch(type) {
+            case QEMU_CTYPE_INT:
+                ret = qemu_device_set_int(dev, field_name, u.i);
+                break;
+            case QEMU_CTYPE_BOOL:
+                ret = qemu_device_set_bool(dev, field_name, u.i);
+                break;
+            case QEMU_CTYPE_STR:
+                ret = qemu_device_set_str(dev, field_name, u.str);
+                break;
+            default:
+                abort();
+            }
+            if (ret < 0) {
+                if (ret == -ENOENT) {
+                    parse_error(filename, line_num, "field '%s' does not exist",
+                                field_name);
+                    goto fail;
+                } else {
+                    parse_error(filename, line_num, "invalid type for field '%s'",
+                                field_name);
+                    goto fail;
+                }
+            }
+        }
+    }
+
+    qemu_fclose(f);
+    return 0;
+ fail:
+    qemu_fclose(f);
+    return -1;
+}
+
+/* compatibility: add device fields from param list. trans_list allows
+   to change the name of a field or to ignore it. */
+int qemu_device_set_params(QEMUDevice *dev, const char *opts,
+                           const char *trans_list)
+{
+    char opt_name[128], alt_opt_name[128], opt_value[1024];
+    QEMUFieldValue u;
+    const char *p;
+    QEMUDeviceClassField *dcf;
+
+    p = opts;
+    if (*p == '\0')
+        return 0;
+    for(;;) {
+        p = get_opt_name(opt_name, sizeof(opt_name), p);
+        if (*p != '=')
+            return -1;
+        p++;
+        p = get_opt_value(opt_value, sizeof(opt_value), p);
+        
+        if (get_param_value(alt_opt_name, sizeof(alt_opt_name), opt_name, 
+                            trans_list) > 0) {
+            pstrcpy(opt_name, sizeof(opt_name), alt_opt_name);
+        }
+        if (strcmp(opt_name, "!") != 0) {
+            dcf = qemu_class_find_field(dev->dev_class, opt_name);
+            if (!dcf) {
+                fprintf(stderr, "Unknown field: '%s'\n", opt_name);
+                return -1;
+            }
+            switch(dcf->type) {
+            case QEMU_CTYPE_INT:
+                u.i = strtoll(opt_value, NULL, 0);
+                break;
+            case QEMU_CTYPE_BOOL:
+                if (!strcmp(opt_value, "1") ||
+                    !strcmp(opt_value, "on") ||
+                    !strcmp(opt_value, "true")) {
+                    u.i = 1;
+                } else if (!strcmp(opt_value, "0") ||
+                    !strcmp(opt_value, "off") ||
+                    !strcmp(opt_value, "false")) {
+                    u.i = 0;
+                } else {
+                    fprintf(stderr, "invalid boolean value for field '%s'\n",
+                            opt_name);
+                    return -1;
+                }
+                break;
+            case QEMU_CTYPE_STR:
+                u.str = opt_value;
+                break;
+            default:
+                return -1;
+            }
+            if (qemu_device_set_field(dev, opt_name, dcf->type, u) != 0)
+                return -1;
+        }
+        if (*p != ',')
+            break;
+        p++;
+    }
+    return 0;
+}
+
+
+void do_info_devices(void)
+{
+    QEMUDevice *dev;
+
+    term_printf("%-12s %-12s %s\n", "DEVICE", "TYPE", "DESCRIPTION");
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (dev == qemu_prefs)
+            continue;
+        term_printf("%-12s %-12s %s\n", 
+               dev->name, 
+               dev->dev_class->name, 
+               dev->dev_class->descr);
+    }
+}
+
+static void term_dump_value(QEMUTypeEnum type, QEMUFieldValue u)
+{
+    switch(type) {
+    case QEMU_CTYPE_STR:
+        term_printf("\"%s\"", u.str);
+        break;
+    case QEMU_CTYPE_INT:
+        term_printf("%" PRId64, u.i);
+        break;
+    case QEMU_CTYPE_BOOL:
+        if (u.i)
+            term_printf("true");
+        else
+            term_printf("false");
+        break;
+    default:
+        break;
+    }
+}
+
+void do_info_classes(const char *class_name)
+{
+    QEMUDeviceClass *dc, *dc1;
+
+    if (class_name) {
+        QEMUDeviceClassField *dcf;
+        QEMUDeviceClassInitField *dci;
+        int i;
+
+        dc = qemu_class_find(class_name);
+        if (!dc) {
+            term_printf("unknown device class: '%s'\n", class_name);
+            return;
+        }
+        term_printf("Parents: ");
+        for(i=0;i<dc->nb_parents;i++) {
+            if (i != 0)
+                term_printf(", ");
+            term_printf("%s", dc->parents[i]->name);
+        }
+        term_printf("\n");
+
+        term_printf("Fields:\n");
+        for(dcf = dc->first_field; dcf != NULL; dcf = dcf->next_field) {
+            term_printf("  %s: %s\n", dcf->name, ctype_str[dcf->type]);
+        }
+        
+        if (dc->first_init_field) {
+            term_printf("Defaults:\n");
+            for(dci = dc->first_init_field; dci != NULL; dci = dci->next_init_field) {
+                term_printf("  %s = ", dci->field->name);
+                term_dump_value(dci->field->type, dci->u);
+                term_printf("\n");
+            }
+        }
+    } else {
+        QEMUDeviceClass *dc1;
+        int i;
+
+        dc1 = qemu_class_find("preferences");
+        term_printf("%-20s %s\n", "CLASS", "DESCRIPTION {PARENTS}");
+        for(dc = qemu_first_class; dc != NULL; dc = dc->next_class) {
+            if (dc->flags & QEMU_CLASS_ABSTRACT)
+                continue;
+            if (dc == dc1)
+                continue;
+            term_printf("%-20s", dc->name);
+            if (dc->descr)
+                term_printf(" %s", dc->descr);
+            if (dc->nb_parents) {
+                term_printf(" {");
+                for(i=0;i<dc->nb_parents;i++) {
+                    if (i != 0)
+                        term_printf(", ");
+                    term_printf("%s", dc->parents[i]->name);
+                }
+                term_printf("}");
+            }
+            term_printf("\n");
+        }
+    }
+}
+
Index: device.h
===================================================================
--- device.h	(revision 0)
+++ device.h	(revision 0)
@@ -0,0 +1,108 @@
+typedef enum {
+    QEMU_CTYPE_STR,
+    QEMU_CTYPE_BOOL,
+    QEMU_CTYPE_INT,
+    /* XXX: add array type ? */
+    /* XXX: add struct type ? */
+} QEMUTypeEnum;
+
+#define QEMU_CLASS_MAX_PARENTS 8
+
+#define QEMU_CLASS_ABSTRACT 0x0001 /* object of this class cannot be
+                                      instantiated */
+
+typedef struct QEMUDevice QEMUDevice;
+
+/* entry type definition */
+typedef struct QEMUDeviceClass {
+    char *name;
+    char *descr;
+    int flags;
+    int nb_parents;
+    struct QEMUDeviceClass *parents[QEMU_CLASS_MAX_PARENTS];
+    struct QEMUDeviceClass *next_class;
+    struct QEMUDeviceClassField *first_field;
+    /* default value for fields. Can initialize fields of parents too */
+    struct QEMUDeviceClassInitField *first_init_field;
+    
+    /* constructor */
+    int (*dev_init)(QEMUDevice *dev);
+    void (*dev_release)(QEMUDevice *dev);
+    void *opaque;
+} QEMUDeviceClass;
+
+typedef struct QEMUDeviceClassField QEMUDeviceClassField;
+
+struct QEMUDevice {
+    char *name;
+    QEMUDeviceClass *dev_class;
+    struct QEMUDevice *dev_next;
+    struct QEMUDeviceField *first_field;
+
+    void *opaque; /* opaque usable by the device model */
+    int instantiated;
+};
+
+/* class handling */
+QEMUDeviceClass *qemu_class_new(const char *name, int flags,
+                                const char *descr);
+QEMUDeviceClass *qemu_class_find(const char *name);
+int qemu_class_add_parent(QEMUDeviceClass *dc, 
+                          QEMUDeviceClass *parent);
+int qemu_class_instanceof(QEMUDeviceClass *dc1, QEMUDeviceClass *dc2);
+QEMUDeviceClassField *qemu_class_field_new(QEMUDeviceClass *dc, 
+                                           const char *name,
+                                           QEMUTypeEnum type);
+int qemu_class_set_int(QEMUDeviceClass *dc, const char *name,
+                       int64_t val);
+int qemu_class_set_bool(QEMUDeviceClass *dc, const char *name,
+                        int val);
+int qemu_class_set_str(QEMUDeviceClass *dc, const char *name,
+                       const char *str);
+
+/* device handling */
+extern QEMUDevice *qemu_first_device;
+
+QEMUDevice *qemu_device_find(const char *name);
+QEMUDevice *qemu_device_new(QEMUDeviceClass *dc, const char *name);
+QEMUDevice *qemu_device_new_after(QEMUDeviceClass *dc, const char *name,
+                                  QEMUDevice *dev1);
+QEMUDevice *qemu_device_new_nodup(QEMUDeviceClass *dc, const char *base_name);
+void qemu_device_delete(QEMUDevice *dev);
+int qemu_device_set_int(QEMUDevice *dev, const char *name, int64_t val);
+int qemu_device_set_bool(QEMUDevice *dev, const char *name, int val);
+int qemu_device_set_str(QEMUDevice *dev, const char *name, const char *str);
+int64_t qemu_device_get_int(QEMUDevice *dev, const char *name);
+int qemu_device_get_bool(QEMUDevice *dev, const char *name);
+const char *qemu_device_get_str(QEMUDevice *dev, const char *name);
+
+/* config file */
+#define QEMU_CONF_NO_OBJ   (1 << 0)
+#define QEMU_CONF_ERR_FILE (1 << 1)
+
+int qemu_parse_config(QEMUDevice **pmain_dev, const char *filename, int flags);
+
+/* params */
+const char *get_opt_name(char *buf, int buf_size, const char *p);
+const char *get_opt_value(char *buf, int buf_size, const char *p);
+int get_param_value(char *buf, int buf_size,
+                    const char *tag, const char *str);
+int qemu_device_set_params(QEMUDevice *dev, const char *opts,
+                           const char *trans_list);
+
+/* global devices / types */
+extern QEMUDevice *machine_dev;
+extern QEMUDevice *qemu_prefs;
+
+int nd_init(QEMUDevice *dev, NICInfo *nd);
+void qemu_get_machine_macaddr(uint8_t *macaddr);
+qemu_irq qemu_irq_from_name(const char *name);
+PCIBus *pci_get_bus_devfn(QEMUDevice *dev, int *pdevfn);
+void qemu_register_irqs(const char *name, qemu_irq *irqs, int nb_irqs);
+
+void do_info_devices(void);
+void do_info_classes(const char *class_name);
+
+/* debug */
+void dump_classes(void);
+void dump_devices(void);
Index: monitor.c
===================================================================
--- monitor.c	(revision 4734)
+++ monitor.c	(working copy)
@@ -223,23 +223,6 @@
     }
 }
 
-static void do_info(const char *item)
-{
-    term_cmd_t *cmd;
-
-    if (!item)
-        goto help;
-    for(cmd = info_cmds; cmd->name != NULL; cmd++) {
-        if (compare_cmd(item, cmd->name))
-            goto found;
-    }
- help:
-    help_cmd("info");
-    return;
- found:
-    cmd->handler();
-}
-
 static void do_info_version(void)
 {
   term_printf("%s\n", QEMU_VERSION);
@@ -1333,8 +1316,8 @@
       "[cmd]", "show the help" },
     { "commit", "s", do_commit,
       "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" },
-    { "info", "s?", do_info,
-      "subcommand", "show various information about the system state" },
+    { "info", "s?", NULL,
+      "subcommand...", "show various information about the system state" },
     { "q|quit", "", do_quit,
       "", "quit the emulator" },
     { "eject", "-fB", do_eject,
@@ -1467,6 +1450,10 @@
     { "slirp", "", do_info_slirp,
       "", "show SLIRP statistics", },
 #endif
+    { "devices", "", do_info_devices,
+      "", "show the instantiated devices" },
+    { "classes", "s?", do_info_classes,
+      "", "show the available device types" },
     { NULL, NULL, },
 };
 
@@ -2144,15 +2131,34 @@
     memcpy(cmdname, pstart, len);
     cmdname[len] = '\0';
 
-    /* find the command */
-    for(cmd = term_cmds; cmd->name != NULL; cmd++) {
-        if (compare_cmd(cmdname, cmd->name))
-            goto found;
+    if (!strcmp(cmdname, "info")) {
+        /* info subcommands */
+        q = cmdname;
+        while (isspace(*p))
+            p++;
+        pstart = p;
+        while (*p != '\0' && !isspace(*p))
+            p++;
+        len = p - pstart;
+        if (len > sizeof(cmdname) - 1)
+            len = sizeof(cmdname) - 1;
+        memcpy(cmdname, pstart, len);
+        cmdname[len] = '\0';
+        for(cmd = info_cmds; cmd->name != NULL; cmd++) {
+            if (compare_cmd(cmdname, cmd->name))
+                goto found;
+        }
+        help_cmd("info");
+    } else {
+        /* find the command */
+        for(cmd = term_cmds; cmd->name != NULL; cmd++) {
+            if (compare_cmd(cmdname, cmd->name))
+                goto found;
+        }
+        term_printf("unknown command: '%s'\n", cmdname);
     }
-    term_printf("unknown command: '%s'\n", cmdname);
     return;
  found:
-
     for(i = 0; i < MAX_ARGS; i++)
         str_allocated[i] = NULL;
 
Index: hw/integratorcp.c
===================================================================
--- hw/integratorcp.c	(revision 4734)
+++ hw/integratorcp.c	(working copy)
@@ -518,18 +518,9 @@
         exit(1);
     }
     pl181_init(0x1c000000, drives_table[sd].bdrv, pic[23], pic[24]);
-    if (nd_table[0].vlan) {
-        if (nd_table[0].model == NULL
-            || strcmp(nd_table[0].model, "smc91c111") == 0) {
-            smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
-        } else if (strcmp(nd_table[0].model, "?") == 0) {
-            fprintf(stderr, "qemu: Supported NICs: smc91c111\n");
-            exit (1);
-        } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-            exit (1);
-        }
-    }
+
+    qemu_register_irqs("pic0", pic, 32);
+    smc91c111_set_defaults(0xc8000000, pic, 27);
     pl110_init(ds, 0xc0000000, pic[22], 0);
 
     integrator_binfo.ram_size = ram_size;
@@ -544,4 +535,5 @@
     "ARM Integrator/CP (ARM926EJ-S)",
     integratorcp_init,
     0x100000,
+    "smc91c111",
 };
Index: hw/ppc_chrp.c
===================================================================
--- hw/ppc_chrp.c	(revision 4734)
+++ hw/ppc_chrp.c	(working copy)
@@ -265,11 +265,7 @@
 
     /* XXX: use Mac Serial port */
     serial_init(0x3f8, dummy_irq[4], 115200, serial_hds[0]);
-    for(i = 0; i < nb_nics; i++) {
-        if (!nd_table[i].model)
-            nd_table[i].model = "ne2k_pci";
-        pci_nic_init(pci_bus, &nd_table[i], -1);
-    }
+
     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
         fprintf(stderr, "qemu: too many IDE bus\n");
         exit(1);
@@ -329,6 +325,8 @@
 
     /* Special port to get debug messages from Open-Firmware */
     register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
+
+    qemu_register_irqs("isapic0", dummy_irq, 16);
 }
 
 QEMUMachine core99_machine = {
@@ -336,4 +334,5 @@
     "Mac99 based PowerMAC",
     ppc_core99_init,
     BIOS_SIZE + VGA_RAM_SIZE,
+    "ne2k_pci",
 };
Index: hw/arm-misc.h
===================================================================
--- hw/arm-misc.h	(revision 4734)
+++ hw/arm-misc.h	(working copy)
@@ -39,6 +39,11 @@
 
 /* stellaris_enent.c */
 void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq);
+void stellaris_enet_set_defaults(uint32_t membase, qemu_irq *pic, int irq);
 
+/* musicpal.c */
+void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq);
+void mv88w8618_eth_set_defaults(uint32_t membase, qemu_irq *pic, int irq);
+
 #endif /* !ARM_MISC_H */
 
Index: hw/mips_jazz.c
===================================================================
--- hw/mips_jazz.c	(revision 4734)
+++ hw/mips_jazz.c	(working copy)
@@ -75,33 +75,6 @@
     rtc_writeb,
 };
 
-#ifdef HAS_AUDIO
-static void audio_init(qemu_irq *pic)
-{
-    struct soundhw *c;
-    int audio_enabled = 0;
-
-    for (c = soundhw; !audio_enabled && c->name; ++c) {
-        audio_enabled = c->enabled;
-    }
-
-    if (audio_enabled) {
-        AudioState *s;
-
-        s = AUD_init();
-        if (s) {
-            for (c = soundhw; c->name; ++c) {
-                if (c->enabled) {
-                    if (c->isa) {
-                        c->init.init_isa(s, pic);
-                    }
-                }
-            }
-        }
-    }
-}
-#endif
-
 void espdma_memory_read(void *opaque, uint8_t *buf, int len)
 {
     printf("espdma_memory_read(buf %p, len %d) not implemented\n", buf, len);
@@ -244,9 +217,6 @@
 
     /* Sound card */
     /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
-#ifdef HAS_AUDIO
-    audio_init(i8259);
-#endif
 
     /* NVRAM: Unprotected at 0x9000, Protected at 0xa000, Read only at 0xb000 */
     ds1225y_init(0x80009000, "nvram");
Index: hw/sun4m.c
===================================================================
--- hw/sun4m.c	(revision 4734)
+++ hw/sun4m.c	(working copy)
@@ -366,6 +366,27 @@
     return kernel_size;
 }
 
+static void lance_dev_init(target_phys_addr_t leaddr, void *dma_opaque,
+                           qemu_irq irq, qemu_irq *reset)
+{
+    QEMUDevice *dev;
+    QEMUDeviceClass *dc;
+    NICInfo nd;
+
+    dc = qemu_class_find("lance");
+    for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+        if (dev->dev_class == dc) {
+            break;
+        }
+    }
+    if (!dev)
+        return;
+    dev->instantiated = 1;
+    if (nd_init(dev, &nd) < 0)
+        return;
+    lance_init(&nd, leaddr, dma_opaque, irq, reset);
+}
+
 static void sun4m_hw_init(const struct hwdef *hwdef, ram_addr_t RAM_size,
                           const char *boot_device,
                           DisplayState *ds, const char *kernel_filename,
@@ -385,6 +406,7 @@
     char buf[1024];
     BlockDriverState *fd[MAX_FD];
     int drive_index;
+    uint8_t macaddr[6];
 
     /* init CPUs */
     if (!cpu_model)
@@ -477,16 +499,7 @@
     tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size,
              hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
 
-    if (nd_table[0].model == NULL
-        || strcmp(nd_table[0].model, "lance") == 0) {
-        lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
-    } else if (strcmp(nd_table[0].model, "?") == 0) {
-        fprintf(stderr, "qemu: Supported NICs: lance\n");
-        exit (1);
-    } else {
-        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-        exit (1);
-    }
+    lance_dev_init(hwdef->le_base, ledma, *ledma_irq, le_reset);
 
     nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
                         hwdef->nvram_size, 8);
@@ -539,7 +552,8 @@
     kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
                                     RAM_size);
 
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+    qemu_get_machine_macaddr(macaddr);
+    nvram_init(nvram, macaddr, kernel_cmdline,
                boot_device, RAM_size, kernel_size, graphic_width,
                graphic_height, graphic_depth, hwdef->machine_id, "Sun4m");
 
@@ -565,6 +579,7 @@
     char buf[1024];
     BlockDriverState *fd[MAX_FD];
     int drive_index;
+    uint8_t macaddr[6];
 
     /* init CPU */
     if (!cpu_model)
@@ -634,16 +649,7 @@
     tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size,
              hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
 
-    if (nd_table[0].model == NULL
-        || strcmp(nd_table[0].model, "lance") == 0) {
-        lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
-    } else if (strcmp(nd_table[0].model, "?") == 0) {
-        fprintf(stderr, "qemu: Supported NICs: lance\n");
-        exit (1);
-    } else {
-        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-        exit (1);
-    }
+    lance_dev_init(hwdef->le_base, ledma, *ledma_irq, le_reset);
 
     nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
                         hwdef->nvram_size, 2);
@@ -689,7 +695,8 @@
     kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
                                     RAM_size);
 
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+    qemu_get_machine_macaddr(macaddr);
+    nvram_init(nvram, macaddr, kernel_cmdline,
                boot_device, RAM_size, kernel_size, graphic_width,
                graphic_height, graphic_depth, hwdef->machine_id, "Sun4c");
 }
@@ -1222,6 +1229,7 @@
     "Sun4m platform, SPARCstation 5",
     ss5_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine ss10_machine = {
@@ -1229,6 +1237,7 @@
     "Sun4m platform, SPARCstation 10",
     ss10_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine ss600mp_machine = {
@@ -1236,6 +1245,7 @@
     "Sun4m platform, SPARCserver 600MP",
     ss600mp_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine ss20_machine = {
@@ -1243,6 +1253,7 @@
     "Sun4m platform, SPARCstation 20",
     ss20_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine ss2_machine = {
@@ -1250,6 +1261,7 @@
     "Sun4c platform, SPARCstation 2",
     ss2_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine voyager_machine = {
@@ -1257,6 +1269,7 @@
     "Sun4m platform, SPARCstation Voyager",
     vger_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine ss_lx_machine = {
@@ -1264,6 +1277,7 @@
     "Sun4m platform, SPARCstation LX",
     ss_lx_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine ss4_machine = {
@@ -1271,6 +1285,7 @@
     "Sun4m platform, SPARCstation 4",
     ss4_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine scls_machine = {
@@ -1278,6 +1293,7 @@
     "Sun4m platform, SPARCClassic",
     scls_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine sbook_machine = {
@@ -1285,6 +1301,7 @@
     "Sun4m platform, SPARCbook",
     sbook_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 static const struct sun4d_hwdef sun4d_hwdefs[] = {
@@ -1372,6 +1389,7 @@
     int ret;
     char buf[1024];
     int drive_index;
+    uint8_t macaddr[6];
 
     /* init CPUs */
     if (!cpu_model)
@@ -1450,16 +1468,7 @@
     tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size,
              hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
 
-    if (nd_table[0].model == NULL
-        || strcmp(nd_table[0].model, "lance") == 0) {
-        lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
-    } else if (strcmp(nd_table[0].model, "?") == 0) {
-        fprintf(stderr, "qemu: Supported NICs: lance\n");
-        exit (1);
-    } else {
-        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-        exit (1);
-    }
+    lance_dev_init(hwdef->le_base, ledma, *ledma_irq, le_reset);
 
     nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0,
                         hwdef->nvram_size, 8);
@@ -1493,7 +1502,8 @@
     kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
                                     RAM_size);
 
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+    qemu_get_machine_macaddr(macaddr);
+    nvram_init(nvram, macaddr, kernel_cmdline,
                boot_device, RAM_size, kernel_size, graphic_width,
                graphic_height, graphic_depth, hwdef->machine_id, "Sun4d");
 }
@@ -1523,6 +1533,7 @@
     "Sun4d platform, SPARCserver 1000",
     ss1000_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
 
 QEMUMachine ss2000_machine = {
@@ -1530,4 +1541,5 @@
     "Sun4d platform, SPARCcenter 2000",
     ss2000_init,
     PROM_SIZE_MAX + TCX_SIZE,
+    "lance",
 };
Index: hw/ppc_prep.c
===================================================================
--- hw/ppc_prep.c	(revision 4734)
+++ hw/ppc_prep.c	(working copy)
@@ -76,11 +76,6 @@
 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
 static const int ide_irq[2] = { 13, 13 };
 
-#define NE2000_NB_MAX 6
-
-static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
-static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-
 //static PITState *pit;
 
 /* ISA IO ports bridge */
@@ -547,7 +542,7 @@
     nvram_t nvram;
     m48t59_t *m48t59;
     int PPC_io_memory;
-    int linux_boot, i, nb_nics1, bios_size;
+    int linux_boot, i, bios_size;
     unsigned long bios_offset;
     uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
     PCIBus *pci_bus;
@@ -668,17 +663,6 @@
     rtc_init(0x70, i8259[8]);
 
     serial_init(0x3f8, i8259[4], 115200, serial_hds[0]);
-    nb_nics1 = nb_nics;
-    if (nb_nics1 > NE2000_NB_MAX)
-        nb_nics1 = NE2000_NB_MAX;
-    for(i = 0; i < nb_nics1; i++) {
-        if (nd_table[i].model == NULL
-            || strcmp(nd_table[i].model, "ne2k_isa") == 0) {
-            isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]);
-        } else {
-            pci_nic_init(pci_bus, &nd_table[i], -1);
-        }
-    }
 
     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
         fprintf(stderr, "qemu: too many IDE bus\n");
@@ -740,24 +724,26 @@
     }
 
     m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
-    if (m48t59 == NULL)
-        return;
-    sysctrl->nvram = m48t59;
+    if (m48t59) {
+        sysctrl->nvram = m48t59;
+        
+        /* Initialise NVRAM */
+        nvram.opaque = m48t59;
+        nvram.read_fn = &m48t59_read;
+        nvram.write_fn = &m48t59_write;
+        PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "PREP", ram_size, ppc_boot_device,
+                             kernel_base, kernel_size,
+                             kernel_cmdline,
+                             initrd_base, initrd_size,
+                             /* XXX: need an option to load a NVRAM image */
+                             0,
+                             graphic_width, graphic_height, graphic_depth);
+        
+        /* Special port to get debug messages from Open-Firmware */
+        register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
+    }
 
-    /* Initialise NVRAM */
-    nvram.opaque = m48t59;
-    nvram.read_fn = &m48t59_read;
-    nvram.write_fn = &m48t59_write;
-    PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "PREP", ram_size, ppc_boot_device,
-                         kernel_base, kernel_size,
-                         kernel_cmdline,
-                         initrd_base, initrd_size,
-                         /* XXX: need an option to load a NVRAM image */
-                         0,
-                         graphic_width, graphic_height, graphic_depth);
-
-    /* Special port to get debug messages from Open-Firmware */
-    register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
+    qemu_register_irqs("isapic0", i8259, 16);
 }
 
 QEMUMachine prep_machine = {
@@ -765,4 +751,5 @@
     "PowerPC PREP platform",
     ppc_prep_init,
     BIOS_SIZE + VGA_RAM_SIZE,
+    "ne2k_pci",
 };
Index: hw/mips.h
===================================================================
--- hw/mips.h	(revision 4734)
+++ hw/mips.h	(working copy)
@@ -16,6 +16,7 @@
 
 /* mipsnet.c */
 void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
+void mipsnet_set_defaults(uint32_t iobase, qemu_irq *pic, int irq_num);
 
 /* jazz_led.c */
 extern void jazz_led_init(DisplayState *ds, target_phys_addr_t base);
Index: hw/sun4u.c
===================================================================
--- hw/sun4u.c	(revision 4734)
+++ hw/sun4u.c	(working copy)
@@ -341,12 +341,6 @@
         }
     }
 
-    for(i = 0; i < nb_nics; i++) {
-        if (!nd_table[i].model)
-            nd_table[i].model = "ne2k_pci";
-        pci_nic_init(pci_bus, &nd_table[i], -1);
-    }
-
     irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32);
     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
         fprintf(stderr, "qemu: too many IDE bus\n");
@@ -381,7 +375,6 @@
                          /* XXX: need an option to load a NVRAM image */
                          0,
                          graphic_width, graphic_height, graphic_depth);
-
 }
 
 QEMUMachine sun4u_machine = {
@@ -389,4 +382,5 @@
     "Sun4u platform",
     sun4u_init,
     PROM_SIZE_MAX + VGA_RAM_SIZE,
+    "ne2k_pci",
 };
Index: hw/versatilepb.c
===================================================================
--- hw/versatilepb.c	(revision 4734)
+++ hw/versatilepb.c	(working copy)
@@ -172,7 +172,6 @@
     PCIBus *pci_bus;
     NICInfo *nd;
     int n;
-    int done_smc = 0;
     int index;
 
     if (!cpu_model)
@@ -194,18 +193,10 @@
     pl050_init(0x10007000, sic[4], 1);
 
     pci_bus = pci_vpb_init(sic, 27, 0);
-    /* The Versatile PCI bridge does not provide access to PCI IO space,
-       so many of the qemu PCI devices are not useable.  */
-    for(n = 0; n < nb_nics; n++) {
-        nd = &nd_table[n];
-        if (!nd->model)
-            nd->model = done_smc ? "rtl8139" : "smc91c111";
-        if (strcmp(nd->model, "smc91c111") == 0) {
-            smc91c111_init(nd, 0x10010000, sic[25]);
-        } else {
-            pci_nic_init(pci_bus, nd, -1);
-        }
-    }
+
+    qemu_register_irqs("pic0", sic, 32);
+    smc91c111_set_defaults(0x10010000, sic, 25);
+
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, 3, -1);
     }
@@ -291,6 +282,9 @@
     versatile_binfo.initrd_filename = initrd_filename;
     versatile_binfo.board_id = board_id;
     arm_load_kernel(env, &versatile_binfo);
+
+    /* The Versatile PCI bridge does not provide access to PCI IO space,
+       so many of the qemu PCI devices are not useable.  */
 }
 
 static void vpb_init(ram_addr_t ram_size, int vga_ram_size,
@@ -319,10 +313,12 @@
     "versatilepb",
     "ARM Versatile/PB (ARM926EJ-S)",
     vpb_init,
+    "smc91c111",
 };
 
 QEMUMachine versatileab_machine = {
     "versatileab",
     "ARM Versatile/AB (ARM926EJ-S)",
     vab_init,
+    "smc91c111",
 };
Index: hw/mainstone.c
===================================================================
--- hw/mainstone.c	(revision 4734)
+++ hw/mainstone.c	(working copy)
@@ -125,7 +125,8 @@
     /* MMC/SD host */
     pxa2xx_mmci_handlers(cpu->mmc, NULL, mst_irq[MMC_IRQ]);
 
-    smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]);
+    qemu_register_irqs("pic0", mst_irq, 16);
+    smc91c111_set_defaults(MST_ETH_PHYS, mst_irq, ETHERNET_IRQ);
 
     mainstone_binfo.kernel_filename = kernel_filename;
     mainstone_binfo.kernel_cmdline = kernel_cmdline;
@@ -149,4 +150,5 @@
     mainstone_init,
     (MAINSTONE_RAM + MAINSTONE_ROM + 2 * MAINSTONE_FLASH +
      PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED,
+    "smc91c111",
 };
Index: hw/mips_mipssim.c
===================================================================
--- hw/mips_mipssim.c	(revision 4734)
+++ hw/mips_mipssim.c	(working copy)
@@ -176,19 +176,9 @@
     if (serial_hds[0])
         serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]);
 
-    if (nd_table[0].vlan) {
-        if (nd_table[0].model == NULL
-            || strcmp(nd_table[0].model, "mipsnet") == 0) {
-            /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
-            mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
-        } else if (strcmp(nd_table[0].model, "?") == 0) {
-            fprintf(stderr, "qemu: Supported NICs: mipsnet\n");
-            exit (1);
-        } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-            exit (1);
-        }
-    }
+    /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
+    qemu_register_irqs("isapic0", (qemu_irq *)env->irq, 8);
+    mipsnet_set_defaults(0x4200, (qemu_irq *)env->irq, 2);
 }
 
 QEMUMachine mips_mipssim_machine = {
@@ -196,4 +186,5 @@
     "MIPS MIPSsim platform",
     mips_mipssim_init,
     BIOS_SIZE + VGA_RAM_SIZE /* unused */,
+    "mipsnet",
 };
Index: hw/mcf5208.c
===================================================================
--- hw/mcf5208.c	(revision 4734)
+++ hw/mcf5208.c	(working copy)
@@ -242,22 +242,8 @@
 
     mcf5208_sys_init(pic);
 
-    if (nb_nics > 1) {
-        fprintf(stderr, "Too many NICs\n");
-        exit(1);
-    }
-    if (nd_table[0].vlan) {
-        if (nd_table[0].model == NULL
-            || strcmp(nd_table[0].model, "mcf_fec") == 0) {
-            mcf_fec_init(&nd_table[0], 0xfc030000, pic + 36);
-        } else if (strcmp(nd_table[0].model, "?") == 0) {
-            fprintf(stderr, "qemu: Supported NICs: mcf_fec\n");
-            exit (1);
-        } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-            exit (1);
-        }
-    }
+    qemu_register_irqs("pic0", pic, 64);
+    mcf_fec_set_defaults(0xfc030000, pic, 36);
 
     /*  0xfc000000 SCM.  */
     /*  0xfc004000 XBS.  */
Index: hw/stellaris.c
===================================================================
--- hw/stellaris.c	(revision 4734)
+++ hw/stellaris.c	(working copy)
@@ -1088,7 +1088,8 @@
     int flash_size;
     i2c_bus *i2c;
     int i;
-
+    uint8_t macaddr[6];
+    
     flash_size = ((board->dc0 & 0xffff) + 1) << 1;
     sram_size = (board->dc0 >> 18) + 1;
     pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
@@ -1105,7 +1106,8 @@
         }
     }
 
-    stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
+    qemu_get_machine_macaddr(macaddr);
+    stellaris_sys_init(0x400fe000, pic[28], board, macaddr);
 
     for (i = 0; i < 7; i++) {
         if (board->dc4 & (1 << i)) {
@@ -1150,9 +1152,10 @@
             pl022_init(0x40008000, pic[7], NULL, NULL);
         }
     }
+    qemu_register_irqs("pic0", pic, 64);
     if (board->dc4 & (1 << 28)) {
         /* FIXME: Obey network model.  */
-        stellaris_enet_init(&nd_table[0], 0x40048000, pic[42]);
+        stellaris_enet_set_defaults(0x40048000, pic, 42);
     }
     if (board->peripherals & BP_GAMEPAD) {
         qemu_irq gpad_irq[5];
@@ -1190,6 +1193,7 @@
     "Stellaris LM3S811EVB",
     lm3s811evb_init,
     (64 * 1024 + 8 * 1024) | RAMSIZE_FIXED,
+    "stellaris_enet",
 };
 
 QEMUMachine lm3s6965evb_machine = {
@@ -1197,4 +1201,5 @@
     "Stellaris LM3S6965EVB",
     lm3s6965evb_init,
     (256 * 1024 + 64 * 1024) | RAMSIZE_FIXED,
+    "stellaris_enet",
 };
Index: hw/mcf.h
===================================================================
--- hw/mcf.h	(revision 4734)
+++ hw/mcf.h	(working copy)
@@ -14,6 +14,7 @@
 
 /* mcf_fec.c */
 void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq);
+void mcf_fec_set_defaults(uint32_t membase, qemu_irq *pic, int irq);
 
 /* mcf5206.c */
 qemu_irq *mcf5206_init(uint32_t base, CPUState *env);
Index: hw/realview.c
===================================================================
--- hw/realview.c	(revision 4734)
+++ hw/realview.c	(working copy)
@@ -119,17 +119,10 @@
             continue;
         lsi_scsi_attach(scsi_hba, drives_table[index].bdrv, n);
     }
-    for(n = 0; n < nb_nics; n++) {
-        nd = &nd_table[n];
-        if (!nd->model)
-            nd->model = done_smc ? "rtl8139" : "smc91c111";
-        if (strcmp(nd->model, "smc91c111") == 0) {
-            smc91c111_init(nd, 0x4e000000, pic[28]);
-        } else {
-            pci_nic_init(pci_bus, nd, -1);
-        }
-    }
 
+    qemu_register_irqs("pic0", pic, 32);
+    smc91c111_set_defaults(0x4e000000, pic, 28);
+
     /* Memory map for RealView Emulation Baseboard:  */
     /* 0x10000000 System registers.  */
     /*  0x10001000 System controller.  */
@@ -200,5 +193,6 @@
     "realview",
     "ARM RealView Emulation Baseboard (ARM926EJ-S)",
     realview_init,
-    0x1000
+    0x1000,
+    "smc91c111",
 };
Index: hw/boards.h
===================================================================
--- hw/boards.h	(revision 4734)
+++ hw/boards.h	(working copy)
@@ -16,6 +16,7 @@
     QEMUMachineInitFunc *init;
 #define RAMSIZE_FIXED	(1 << 0)
     ram_addr_t ram_require;
+    const char *default_nic_model;
     struct QEMUMachine *next;
 } QEMUMachine;
 
Index: hw/ppc_oldworld.c
===================================================================
--- hw/ppc_oldworld.c	(revision 4734)
+++ hw/ppc_oldworld.c	(working copy)
@@ -289,12 +289,6 @@
     /* XXX: use Mac Serial port */
     serial_init(0x3f8, dummy_irq[4], 115200, serial_hds[0]);
 
-    for(i = 0; i < nb_nics; i++) {
-        if (!nd_table[i].model)
-            nd_table[i].model = "ne2k_pci";
-        pci_nic_init(pci_bus, &nd_table[i], -1);
-    }
-
     /* First IDE channel is a CMD646 on the PCI bus */
 
     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
@@ -364,6 +358,8 @@
 
     /* Special port to get debug messages from Open-Firmware */
     register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
+    
+    qemu_register_irqs("isapic0", dummy_irq, 16);
 }
 
 QEMUMachine heathrow_machine = {
@@ -371,4 +367,5 @@
     "Heathrow based PowerMAC",
     ppc_heathrow_init,
     BIOS_SIZE + VGA_RAM_SIZE,
+    "ne2k_pci",
 };
Index: hw/gumstix.c
===================================================================
--- hw/gumstix.c	(revision 4734)
+++ hw/gumstix.c	(working copy)
@@ -77,8 +77,8 @@
     cpu->env->regs[15] = 0x00000000;
 
     /* Interrupt line of NIC is connected to GPIO line 36 */
-    smc91c111_init(&nd_table[0], 0x04000300,
-                    pxa2xx_gpio_in_get(cpu->gpio)[36]);
+    qemu_register_irqs("pic0", pxa2xx_gpio_in_get(cpu->gpio) + 36, 1);
+    smc91c111_set_defaults(0x04000300, pxa2xx_gpio_in_get(cpu->gpio) + 36, 0);
 }
 
 static void verdex_init(ram_addr_t ram_size, int vga_ram_size,
@@ -117,8 +117,8 @@
     cpu->env->regs[15] = 0x00000000;
 
     /* Interrupt line of NIC is connected to GPIO line 99 */
-    smc91c111_init(&nd_table[0], 0x04000300,
-                    pxa2xx_gpio_in_get(cpu->gpio)[99]);
+    qemu_register_irqs("pic0", pxa2xx_gpio_in_get(cpu->gpio) + 99, 1);
+    smc91c111_set_defaults(0x04000300, pxa2xx_gpio_in_get(cpu->gpio) + 99, 0);
 }
 
 QEMUMachine connex_machine = {
@@ -126,6 +126,7 @@
     "Gumstix Connex (PXA255)",
     connex_init,
     (0x05000000 + PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED,
+    "smc91c111",
 };
 
 QEMUMachine verdex_machine = {
@@ -133,4 +134,5 @@
     "Gumstix Verdex (PXA270)",
     verdex_init,
     (0x12000000 + PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED,
+    "smc91c111",
 };
Index: hw/mips_malta.c
===================================================================
--- hw/mips_malta.c	(revision 4734)
+++ hw/mips_malta.c	(working copy)
@@ -458,51 +458,6 @@
     return s;
 }
 
-/* Audio support */
-#ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus)
-{
-    struct soundhw *c;
-    int audio_enabled = 0;
-
-    for (c = soundhw; !audio_enabled && c->name; ++c) {
-        audio_enabled = c->enabled;
-    }
-
-    if (audio_enabled) {
-        AudioState *s;
-
-        s = AUD_init ();
-        if (s) {
-            for (c = soundhw; c->name; ++c) {
-                if (c->enabled)
-                    c->init.init_pci (pci_bus, s);
-            }
-        }
-    }
-}
-#endif
-
-/* Network support */
-static void network_init (PCIBus *pci_bus)
-{
-    int i;
-    NICInfo *nd;
-
-    for(i = 0; i < nb_nics; i++) {
-        nd = &nd_table[i];
-        if (!nd->model) {
-            nd->model = "pcnet";
-        }
-        if (i == 0  && strcmp(nd->model, "pcnet") == 0) {
-            /* The malta board has a PCNet card using PCI SLOT 11 */
-            pci_nic_init(pci_bus, nd, 88);
-        } else {
-            pci_nic_init(pci_bus, nd, -1);
-        }
-    }
-}
-
 /* ROM and pseudo bootloader
 
    The following code implements a very very simple bootloader. It first
@@ -933,17 +888,26 @@
     }
     floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
 
-    /* Sound card */
-#ifdef HAS_AUDIO
-    audio_init(pci_bus);
-#endif
-
-    /* Network card */
-    network_init(pci_bus);
-
     /* Optional PCI video card */
     pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size,
                         ram_size, vga_ram_size);
+
+    /* set default pcnet devfn number */
+    {
+        QEMUDevice *dev;
+        QEMUDeviceClass *dc;
+        
+        dc = qemu_class_find("pcnet");
+        for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+            if (dev->dev_class == dc) {
+                if (qemu_device_get_int(dev, "devfn") == -1) {
+                    qemu_device_set_int(dev, "devfn", 88);
+                }
+                break;
+            }
+        }
+    }
+    qemu_register_irqs("isapic0", i8259, 16);
 }
 
 QEMUMachine mips_malta_machine = {
@@ -951,4 +915,5 @@
     "MIPS Malta Core LV",
     mips_malta_init,
     VGA_RAM_SIZE + BIOS_SIZE,
+    "pcnet",
 };
Index: hw/devices.h
===================================================================
--- hw/devices.h	(revision 4734)
+++ hw/devices.h	(working copy)
@@ -5,6 +5,7 @@
 
 /* smc91c111.c */
 void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
+void smc91c111_set_defaults(uint32_t membase, qemu_irq *pic, int irq_num);
 
 /* ssd0323.c */
 int ssd0323_xfer_ssi(void *opaque, int data);
Index: hw/pc.c
===================================================================
--- hw/pc.c	(revision 4734)
+++ hw/pc.c	(working copy)
@@ -659,59 +659,12 @@
 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
 static const int ide_irq[2] = { 14, 15 };
 
-#define NE2000_NB_MAX 6
-
-static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
-static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-
 static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
 static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
 
 static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
 static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
 
-#ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
-{
-    struct soundhw *c;
-    int audio_enabled = 0;
-
-    for (c = soundhw; !audio_enabled && c->name; ++c) {
-        audio_enabled = c->enabled;
-    }
-
-    if (audio_enabled) {
-        AudioState *s;
-
-        s = AUD_init ();
-        if (s) {
-            for (c = soundhw; c->name; ++c) {
-                if (c->enabled) {
-                    if (c->isa) {
-                        c->init.init_isa (s, pic);
-                    }
-                    else {
-                        if (pci_bus) {
-                            c->init.init_pci (pci_bus, s);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-#endif
-
-static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
-{
-    static int nb_ne2k = 0;
-
-    if (nb_ne2k == NE2000_NB_MAX)
-        return;
-    isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
-    nb_ne2k++;
-}
-
 /* PC hardware initialisation */
 static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
                      const char *boot_device, DisplayState *ds,
@@ -727,7 +680,6 @@
     PCIBus *pci_bus;
     int piix3_devfn = -1;
     CPUState *env;
-    NICInfo *nd;
     qemu_irq *cpu_irq;
     qemu_irq *i8259;
     int index;
@@ -943,30 +895,6 @@
         }
     }
 
-    for(i = 0; i < nb_nics; i++) {
-        nd = &nd_table[i];
-        if (!nd->model) {
-            if (pci_enabled) {
-                nd->model = "ne2k_pci";
-            } else {
-                nd->model = "ne2k_isa";
-            }
-        }
-        if (strcmp(nd->model, "ne2k_isa") == 0) {
-            pc_init_ne2k_isa(nd, i8259);
-        } else if (pci_enabled) {
-            if (strcmp(nd->model, "?") == 0)
-                fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n");
-            pci_nic_init(pci_bus, nd, -1);
-        } else if (strcmp(nd->model, "?") == 0) {
-            fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n");
-            exit(1);
-        } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
-            exit(1);
-        }
-    }
-
     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
         fprintf(stderr, "qemu: too many IDE bus\n");
         exit(1);
@@ -991,9 +919,6 @@
 
     i8042_init(i8259[1], i8259[12], 0x60);
     DMA_init(0);
-#ifdef HAS_AUDIO
-    audio_init(pci_enabled ? pci_bus : NULL, i8259);
-#endif
 
     for(i = 0; i < MAX_FD; i++) {
         index = drive_get_index(IF_FLOPPY, 0, i);
@@ -1042,6 +967,7 @@
 	    }
         }
     }
+    qemu_register_irqs("isapic0", i8259, 16);
 }
 
 static void pc_init_pci(ram_addr_t ram_size, int vga_ram_size,
@@ -1073,6 +999,7 @@
     "Standard PC",
     pc_init_pci,
     VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,
+    "ne2k_pci",
 };
 
 QEMUMachine isapc_machine = {
@@ -1080,4 +1007,5 @@
     "ISA-only PC",
     pc_init_isa,
     VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,
+    "ne2k_isa",
 };
Index: hw/pci.c
===================================================================
--- hw/pci.c	(revision 4734)
+++ hw/pci.c	(working copy)
@@ -112,6 +112,15 @@
     return bus;
 }
 
+/* XXX: add naming info. The empty string is the "default" PCI bus. */
+PCIBus *pci_bus_from_name(const char *bus_name)
+{
+    if (bus_name[0] == '\0')
+        return first_bus;
+    else
+        return NULL;
+}
+
 int pci_bus_num(PCIBus *s)
 {
     return s->bus_num;
@@ -623,33 +632,6 @@
     pci_for_each_device(0, pci_info_device);
 }
 
-/* Initialize a PCI NIC.  */
-void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn)
-{
-    if (strcmp(nd->model, "ne2k_pci") == 0) {
-        pci_ne2000_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82551") == 0) {
-        pci_i82551_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82557b") == 0) {
-        pci_i82557b_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82559er") == 0) {
-        pci_i82559er_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "rtl8139") == 0) {
-        pci_rtl8139_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "e1000") == 0) {
-        pci_e1000_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "pcnet") == 0) {
-        pci_pcnet_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "?") == 0) {
-        fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
-                        " ne2k_pci pcnet rtl8139 e1000\n");
-        exit (1);
-    } else {
-        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
-        exit (1);
-    }
-}
-
 typedef struct {
     PCIDevice dev;
     PCIBus *bus;
@@ -697,3 +679,4 @@
     s->bus = pci_register_secondary_bus(&s->dev, map_irq);
     return s->bus;
 }
+
Index: hw/etraxfs.c
===================================================================
--- hw/etraxfs.c	(revision 4734)
+++ hw/etraxfs.c	(working copy)
@@ -105,18 +105,42 @@
     }
 
     /* Add the two ethernet blocks.  */
-    eth[0] = etraxfs_eth_init(&nd_table[0], env, pic->irq + 25, 0xb0034000);
-    if (nb_nics > 1)
-        eth[1] = etraxfs_eth_init(&nd_table[1], env, pic->irq + 26, 0xb0036000);
+    {
+        QEMUDevice *dev;
+        QEMUDeviceClass *dc;
+        int eth_index;
+        NICInfo nd;
 
-    /* The DMA Connector block is missing, hardwire things for now.  */
-    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
-    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
-    if (eth[1]) {
-        etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
-        etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
+        dc = qemu_class_find("etraxfs_eth");
+        eth_index = 0;
+        for(dev = qemu_first_device; dev != NULL; dev = dev->dev_next) {
+            if (dev->dev_class == dc) {
+                dev->instantiated = 1;
+                if (nd_init(dev, &nd) < 0)
+                    continue;
+                if (eth_index == 0) {
+                    eth[0] = etraxfs_eth_init(&nd, env, 
+                                              pic->irq + 25, 0xb0034000);
+                    /* The DMA Connector block is missing, hardwire
+                       things for now.  */
+                    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
+                    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
+                } else {
+                    eth[1] = etraxfs_eth_init(&nd, 
+                                              env, pic->irq + 26, 0xb0036000);
+                    /* The DMA Connector block is missing, hardwire
+                       things for now.  */
+                    etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
+                    etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
+                }
+
+                if (++eth_index >= 2)
+                    break;
+            }
+        }
     }
 
+
     /* 2 timers.  */
     etraxfs_timer_init(env, pic->irq + 0x1b, pic->nmi + 1, 0xb001e000);
     etraxfs_timer_init(env, pic->irq + 0x1b, pic->nmi + 1, 0xb005e000);
@@ -155,4 +179,5 @@
     "Bare ETRAX FS board",
     bareetraxfs_init,
     0x8000000,
+    "etraxfs_eth",
 };
Index: hw/musicpal.c
===================================================================
--- hw/musicpal.c	(revision 4734)
+++ hw/musicpal.c	(working copy)
@@ -716,7 +716,7 @@
     mv88w8618_eth_write
 };
 
-static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq)
 {
     mv88w8618_eth_state *s;
     int iomemtype;
@@ -1504,7 +1504,8 @@
 
     qemu_add_kbd_event_handler(musicpal_key_event, pic[MP_GPIO_IRQ]);
 
-    mv88w8618_eth_init(&nd_table[0], MP_ETH_BASE, pic[MP_ETH_IRQ]);
+    qemu_register_irqs("pic0", pic, 32);
+    mv88w8618_eth_set_defaults(MP_ETH_BASE, pic, MP_ETH_IRQ);
 
     mixer_i2c = musicpal_audio_init(MP_AUDIO_BASE, pic[MP_AUDIO_IRQ]);
 
@@ -1519,5 +1520,6 @@
     "musicpal",
     "Marvell 88w8618 / MusicPal (ARM926EJ-S)",
     musicpal_init,
-    MP_RAM_DEFAULT_SIZE + MP_SRAM_SIZE + MP_FLASH_SIZE_MAX + RAMSIZE_FIXED
+    MP_RAM_DEFAULT_SIZE + MP_SRAM_SIZE + MP_FLASH_SIZE_MAX + RAMSIZE_FIXED,
+    "mv88w8618_eth",
 };
Index: hw/pci.h
===================================================================
--- hw/pci.h	(revision 4734)
+++ hw/pci.h	(working copy)
@@ -85,8 +85,8 @@
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
 PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          qemu_irq *pic, int devfn_min, int nirq);
+PCIBus *pci_bus_from_name(const char *bus_name);
 
-void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn);
 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
 uint32_t pci_data_read(void *opaque, uint32_t addr, int len);
 int pci_bus_num(PCIBus *s);
Index: hw/hw.h
===================================================================
--- hw/hw.h	(revision 4734)
+++ hw/hw.h	(working copy)
@@ -4,6 +4,7 @@
 
 #include "qemu-common.h"
 #include "irq.h"
+#include "device.h"
 
 /* VM Load/Save */
 
@@ -16,6 +17,8 @@
 void qemu_put_be32(QEMUFile *f, unsigned int v);
 void qemu_put_be64(QEMUFile *f, uint64_t v);
 int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
+int qemu_getc(QEMUFile *f);
+int qemu_get_line(QEMUFile *f, char *buf, int buf_size);
 int qemu_get_byte(QEMUFile *f);
 unsigned int qemu_get_be16(QEMUFile *f);
 unsigned int qemu_get_be32(QEMUFile *f);
Index: hw/mips_r4k.c
===================================================================
--- hw/mips_r4k.c	(revision 4734)
+++ hw/mips_r4k.c	(working copy)
@@ -249,19 +249,6 @@
     isa_vga_init(ds, phys_ram_base + ram_size, ram_size,
                  vga_ram_size);
 
-    if (nd_table[0].vlan) {
-        if (nd_table[0].model == NULL
-            || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
-            isa_ne2000_init(0x300, i8259[9], &nd_table[0]);
-        } else if (strcmp(nd_table[0].model, "?") == 0) {
-            fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n");
-            exit (1);
-        } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-            exit (1);
-        }
-    }
-
     if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
         fprintf(stderr, "qemu: too many IDE bus\n");
         exit(1);
@@ -281,6 +268,7 @@
 		     hd[MAX_IDE_DEVS * i + 1]);
 
     i8042_init(i8259[1], i8259[12], 0x60);
+    qemu_register_irqs("isapic0", i8259, 16);
 }
 
 QEMUMachine mips_machine = {
@@ -288,4 +276,5 @@
     "mips r4k platform",
     mips_r4k_init,
     VGA_RAM_SIZE + BIOS_SIZE,
+    "ne2k_isa",
 };
