Merge remote-tracking branch 'stefanha/trivial-patches' into staging

* stefanha/trivial-patches:
  linux-user: brk() debugging
  virtio: Remove unneeded g_free() check in virtio_cleanup()
  net: remove extra spaces in help messages
  fmopl: Fix typo in function name
  vl.c: Fix typo in variable name
  ide: fix compilation errors when DEBUG_IDE is set
  cpu-exec.c: Correct comment about this file and indentation cleanup
  CODING_STYLE: Clarify style for enum and function type names
  linux-user: fail execve() if env/args too big
diff --git a/block.c b/block.c
index 3621d11..ae297bb 100644
--- a/block.c
+++ b/block.c
@@ -50,6 +50,7 @@
 
 typedef enum {
     BDRV_REQ_COPY_ON_READ = 0x1,
+    BDRV_REQ_ZERO_WRITE   = 0x2,
 } BdrvRequestFlags;
 
 static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
@@ -69,7 +70,8 @@
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
     BdrvRequestFlags flags);
 static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
-    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+    BdrvRequestFlags flags);
 static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
                                                int64_t sector_num,
                                                QEMUIOVector *qiov,
@@ -1300,7 +1302,7 @@
                                      rwco->nb_sectors, rwco->qiov, 0);
     } else {
         rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
-                                      rwco->nb_sectors, rwco->qiov);
+                                      rwco->nb_sectors, rwco->qiov, 0);
     }
 }
 
@@ -1515,6 +1517,7 @@
      */
     void *bounce_buffer;
 
+    BlockDriver *drv = bs->drv;
     struct iovec iov;
     QEMUIOVector bounce_qiov;
     int64_t cluster_sector_num;
@@ -1535,14 +1538,21 @@
     iov.iov_base = bounce_buffer = qemu_blockalign(bs, iov.iov_len);
     qemu_iovec_init_external(&bounce_qiov, &iov, 1);
 
-    ret = bs->drv->bdrv_co_readv(bs, cluster_sector_num, cluster_nb_sectors,
-                                 &bounce_qiov);
+    ret = drv->bdrv_co_readv(bs, cluster_sector_num, cluster_nb_sectors,
+                             &bounce_qiov);
     if (ret < 0) {
         goto err;
     }
 
-    ret = bs->drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
+    if (drv->bdrv_co_write_zeroes &&
+        buffer_is_zero(bounce_buffer, iov.iov_len)) {
+        ret = drv->bdrv_co_write_zeroes(bs, cluster_sector_num,
+                                        cluster_nb_sectors);
+    } else {
+        ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
                                   &bounce_qiov);
+    }
+
     if (ret < 0) {
         /* It might be okay to ignore write errors for guest requests.  If this
          * is a deliberate copy-on-read then we don't want to ignore the error.
@@ -1639,11 +1649,37 @@
                             BDRV_REQ_COPY_ON_READ);
 }
 
+static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
+    int64_t sector_num, int nb_sectors)
+{
+    BlockDriver *drv = bs->drv;
+    QEMUIOVector qiov;
+    struct iovec iov;
+    int ret;
+
+    /* First try the efficient write zeroes operation */
+    if (drv->bdrv_co_write_zeroes) {
+        return drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+    }
+
+    /* Fall back to bounce buffer if write zeroes is unsupported */
+    iov.iov_len  = nb_sectors * BDRV_SECTOR_SIZE;
+    iov.iov_base = qemu_blockalign(bs, iov.iov_len);
+    memset(iov.iov_base, 0, iov.iov_len);
+    qemu_iovec_init_external(&qiov, &iov, 1);
+
+    ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, &qiov);
+
+    qemu_vfree(iov.iov_base);
+    return ret;
+}
+
 /*
  * Handle a write request in coroutine context
  */
 static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
-    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+    int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+    BdrvRequestFlags flags)
 {
     BlockDriver *drv = bs->drv;
     BdrvTrackedRequest req;
@@ -1670,7 +1706,11 @@
 
     tracked_request_begin(&req, bs, sector_num, nb_sectors, true);
 
-    ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
+    if (flags & BDRV_REQ_ZERO_WRITE) {
+        ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors);
+    } else {
+        ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
+    }
 
     if (bs->dirty_bitmap) {
         set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
@@ -1690,7 +1730,16 @@
 {
     trace_bdrv_co_writev(bs, sector_num, nb_sectors);
 
-    return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov);
+    return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov, 0);
+}
+
+int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs,
+                                      int64_t sector_num, int nb_sectors)
+{
+    trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+
+    return bdrv_co_do_writev(bs, sector_num, nb_sectors, NULL,
+                             BDRV_REQ_ZERO_WRITE);
 }
 
 /**
@@ -3192,7 +3241,7 @@
             acb->req.nb_sectors, acb->req.qiov, 0);
     } else {
         acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
-            acb->req.nb_sectors, acb->req.qiov);
+            acb->req.nb_sectors, acb->req.qiov, 0);
     }
 
     acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
diff --git a/block.h b/block.h
index cae289b..60ea730 100644
--- a/block.h
+++ b/block.h
@@ -146,6 +146,14 @@
     int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
 int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
     int nb_sectors, QEMUIOVector *qiov);
+/*
+ * Efficiently zero a region of the disk image.  Note that this is a regular
+ * I/O request like read or write and should have a reasonable size.  This
+ * function is not suitable for zeroing the entire image in a single request
+ * because it may allocate memory for the entire region.
+ */
+int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors);
 int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num,
     int nb_sectors, int *pnum);
 BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
diff --git a/block/iscsi.c b/block/iscsi.c
index 938c568..bd3ca11 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -455,6 +455,109 @@
     }
 }
 
+static int parse_chap(struct iscsi_context *iscsi, const char *target)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    const char *user = NULL;
+    const char *password = NULL;
+
+    list = qemu_find_opts("iscsi");
+    if (!list) {
+        return 0;
+    }
+
+    opts = qemu_opts_find(list, target);
+    if (opts == NULL) {
+        opts = QTAILQ_FIRST(&list->head);
+        if (!opts) {
+            return 0;
+        }
+    }
+
+    user = qemu_opt_get(opts, "user");
+    if (!user) {
+        return 0;
+    }
+
+    password = qemu_opt_get(opts, "password");
+    if (!password) {
+        error_report("CHAP username specified but no password was given");
+        return -1;
+    }
+
+    if (iscsi_set_initiator_username_pwd(iscsi, user, password)) {
+        error_report("Failed to set initiator username and password");
+        return -1;
+    }
+
+    return 0;
+}
+
+static void parse_header_digest(struct iscsi_context *iscsi, const char *target)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    const char *digest = NULL;
+
+    list = qemu_find_opts("iscsi");
+    if (!list) {
+        return;
+    }
+
+    opts = qemu_opts_find(list, target);
+    if (opts == NULL) {
+        opts = QTAILQ_FIRST(&list->head);
+        if (!opts) {
+            return;
+        }
+    }
+
+    digest = qemu_opt_get(opts, "header-digest");
+    if (!digest) {
+        return;
+    }
+
+    if (!strcmp(digest, "CRC32C")) {
+        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C);
+    } else if (!strcmp(digest, "NONE")) {
+        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE);
+    } else if (!strcmp(digest, "CRC32C-NONE")) {
+        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE);
+    } else if (!strcmp(digest, "NONE-CRC32C")) {
+        iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
+    } else {
+        error_report("Invalid header-digest setting : %s", digest);
+    }
+}
+
+static char *parse_initiator_name(const char *target)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    const char *name = NULL;
+
+    list = qemu_find_opts("iscsi");
+    if (!list) {
+        return g_strdup("iqn.2008-11.org.linux-kvm");
+    }
+
+    opts = qemu_opts_find(list, target);
+    if (opts == NULL) {
+        opts = QTAILQ_FIRST(&list->head);
+        if (!opts) {
+            return g_strdup("iqn.2008-11.org.linux-kvm");
+        }
+    }
+
+    name = qemu_opt_get(opts, "initiator-name");
+    if (!name) {
+        return g_strdup("iqn.2008-11.org.linux-kvm");
+    }
+
+    return g_strdup(name);
+}
+
 /*
  * We support iscsi url's on the form
  * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
@@ -465,6 +568,7 @@
     struct iscsi_context *iscsi = NULL;
     struct iscsi_url *iscsi_url = NULL;
     struct IscsiTask task;
+    char *initiator_name = NULL;
     int ret;
 
     if ((BDRV_SECTOR_SIZE % 512) != 0) {
@@ -474,16 +578,6 @@
         return -EINVAL;
     }
 
-    memset(iscsilun, 0, sizeof(IscsiLun));
-
-    /* Should really append the KVM name after the ':' here */
-    iscsi = iscsi_create_context("iqn.2008-11.org.linux-kvm:");
-    if (iscsi == NULL) {
-        error_report("iSCSI: Failed to create iSCSI context.");
-        ret = -ENOMEM;
-        goto failed;
-    }
-
     iscsi_url = iscsi_parse_full_url(iscsi, filename);
     if (iscsi_url == NULL) {
         error_report("Failed to parse URL : %s %s", filename,
@@ -492,6 +586,17 @@
         goto failed;
     }
 
+    memset(iscsilun, 0, sizeof(IscsiLun));
+
+    initiator_name = parse_initiator_name(iscsi_url->target);
+
+    iscsi = iscsi_create_context(initiator_name);
+    if (iscsi == NULL) {
+        error_report("iSCSI: Failed to create iSCSI context.");
+        ret = -ENOMEM;
+        goto failed;
+    }
+
     if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
         error_report("iSCSI: Failed to set target name.");
         ret = -EINVAL;
@@ -507,6 +612,14 @@
             goto failed;
         }
     }
+
+    /* check if we got CHAP username/password via the options */
+    if (parse_chap(iscsi, iscsi_url->target) != 0) {
+        error_report("iSCSI: Failed to set CHAP user/password");
+        ret = -EINVAL;
+        goto failed;
+    }
+
     if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
         error_report("iSCSI: Failed to set session type to normal.");
         ret = -EINVAL;
@@ -515,6 +628,9 @@
 
     iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
 
+    /* check if we got HEADER_DIGEST via the options */
+    parse_header_digest(iscsi, iscsi_url->target);
+
     task.iscsilun = iscsilun;
     task.status = 0;
     task.complete = 0;
@@ -548,6 +664,9 @@
     return 0;
 
 failed:
+    if (initiator_name != NULL) {
+        g_free(initiator_name);
+    }
     if (iscsi_url != NULL) {
         iscsi_destroy_url(iscsi_url);
     }
diff --git a/block/qcow2.c b/block/qcow2.c
index aa32e8d..3692b45 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -77,8 +77,10 @@
 static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
                                  uint64_t end_offset)
 {
+    BDRVQcowState *s = bs->opaque;
     QCowExtension ext;
     uint64_t offset;
+    int ret;
 
 #ifdef DEBUG_EXT
     printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
@@ -129,8 +131,22 @@
             break;
 
         default:
-            /* unknown magic -- just skip it */
-            offset = ((offset + ext.len + 7) & ~7);
+            /* unknown magic - save it in case we need to rewrite the header */
+            {
+                Qcow2UnknownHeaderExtension *uext;
+
+                uext = g_malloc0(sizeof(*uext)  + ext.len);
+                uext->magic = ext.magic;
+                uext->len = ext.len;
+                QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
+
+                ret = bdrv_pread(bs->file, offset , uext->data, uext->len);
+                if (ret < 0) {
+                    return ret;
+                }
+
+                offset = ((offset + ext.len + 7) & ~7);
+            }
             break;
         }
     }
@@ -138,6 +154,16 @@
     return 0;
 }
 
+static void cleanup_unknown_header_ext(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    Qcow2UnknownHeaderExtension *uext, *next;
+
+    QLIST_FOREACH_SAFE(uext, &s->unknown_header_ext, next, next) {
+        QLIST_REMOVE(uext, next);
+        g_free(uext);
+    }
+}
 
 static int qcow2_open(BlockDriverState *bs, int flags)
 {
@@ -291,6 +317,7 @@
     return ret;
 
  fail:
+    cleanup_unknown_header_ext(bs);
     qcow2_free_snapshots(bs);
     qcow2_refcount_close(bs);
     g_free(s->l1_table);
@@ -632,6 +659,7 @@
     qcow2_cache_destroy(bs, s->l2_table_cache);
     qcow2_cache_destroy(bs, s->refcount_block_cache);
 
+    cleanup_unknown_header_ext(bs);
     g_free(s->cluster_cache);
     qemu_vfree(s->cluster_data);
     qcow2_refcount_close(bs);
@@ -669,103 +697,149 @@
     }
 }
 
-/*
- * Updates the variable length parts of the qcow2 header, i.e. the backing file
- * name and all extensions. qcow2 was not designed to allow such changes, so if
- * we run out of space (we can only use the first cluster) this function may
- * fail.
- *
- * Returns 0 on success, -errno in error cases.
- */
-static int qcow2_update_ext_header(BlockDriverState *bs,
-    const char *backing_file, const char *backing_fmt)
+static size_t header_ext_add(char *buf, uint32_t magic, const void *s,
+    size_t len, size_t buflen)
 {
-    size_t backing_file_len = 0;
-    size_t backing_fmt_len = 0;
-    BDRVQcowState *s = bs->opaque;
-    QCowExtension ext_backing_fmt = {0, 0};
-    int ret;
+    QCowExtension *ext_backing_fmt = (QCowExtension*) buf;
+    size_t ext_len = sizeof(QCowExtension) + ((len + 7) & ~7);
 
-    /* Backing file format doesn't make sense without a backing file */
-    if (backing_fmt && !backing_file) {
-        return -EINVAL;
-    }
-
-    /* Prepare the backing file format extension if needed */
-    if (backing_fmt) {
-        ext_backing_fmt.len = cpu_to_be32(strlen(backing_fmt));
-        ext_backing_fmt.magic = cpu_to_be32(QCOW2_EXT_MAGIC_BACKING_FORMAT);
-        backing_fmt_len = ((sizeof(ext_backing_fmt)
-            + strlen(backing_fmt) + 7) & ~7);
-    }
-
-    /* Check if we can fit the new header into the first cluster */
-    if (backing_file) {
-        backing_file_len = strlen(backing_file);
-    }
-
-    size_t header_size = sizeof(QCowHeader) + backing_file_len
-        + backing_fmt_len;
-
-    if (header_size > s->cluster_size) {
+    if (buflen < ext_len) {
         return -ENOSPC;
     }
 
-    /* Rewrite backing file name and qcow2 extensions */
-    size_t ext_size = header_size - sizeof(QCowHeader);
-    uint8_t buf[ext_size];
-    size_t offset = 0;
-    size_t backing_file_offset = 0;
+    *ext_backing_fmt = (QCowExtension) {
+        .magic  = cpu_to_be32(magic),
+        .len    = cpu_to_be32(len),
+    };
+    memcpy(buf + sizeof(QCowExtension), s, len);
 
-    if (backing_file) {
-        if (backing_fmt) {
-            int padding = backing_fmt_len -
-                (sizeof(ext_backing_fmt) + strlen(backing_fmt));
+    return ext_len;
+}
 
-            memcpy(buf + offset, &ext_backing_fmt, sizeof(ext_backing_fmt));
-            offset += sizeof(ext_backing_fmt);
+/*
+ * Updates the qcow2 header, including the variable length parts of it, i.e.
+ * the backing file name and all extensions. qcow2 was not designed to allow
+ * such changes, so if we run out of space (we can only use the first cluster)
+ * this function may fail.
+ *
+ * Returns 0 on success, -errno in error cases.
+ */
+int qcow2_update_header(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowHeader *header;
+    char *buf;
+    size_t buflen = s->cluster_size;
+    int ret;
+    uint64_t total_size;
+    uint32_t refcount_table_clusters;
+    Qcow2UnknownHeaderExtension *uext;
 
-            memcpy(buf + offset, backing_fmt, strlen(backing_fmt));
-            offset += strlen(backing_fmt);
+    buf = qemu_blockalign(bs, buflen);
+    memset(buf, 0, s->cluster_size);
 
-            memset(buf + offset, 0, padding);
-            offset += padding;
+    /* Header structure */
+    header = (QCowHeader*) buf;
+
+    if (buflen < sizeof(*header)) {
+        ret = -ENOSPC;
+        goto fail;
+    }
+
+    total_size = bs->total_sectors * BDRV_SECTOR_SIZE;
+    refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
+
+    *header = (QCowHeader) {
+        .magic                  = cpu_to_be32(QCOW_MAGIC),
+        .version                = cpu_to_be32(QCOW_VERSION),
+        .backing_file_offset    = 0,
+        .backing_file_size      = 0,
+        .cluster_bits           = cpu_to_be32(s->cluster_bits),
+        .size                   = cpu_to_be64(total_size),
+        .crypt_method           = cpu_to_be32(s->crypt_method_header),
+        .l1_size                = cpu_to_be32(s->l1_size),
+        .l1_table_offset        = cpu_to_be64(s->l1_table_offset),
+        .refcount_table_offset  = cpu_to_be64(s->refcount_table_offset),
+        .refcount_table_clusters = cpu_to_be32(refcount_table_clusters),
+        .nb_snapshots           = cpu_to_be32(s->nb_snapshots),
+        .snapshots_offset       = cpu_to_be64(s->snapshots_offset),
+    };
+
+    buf += sizeof(*header);
+    buflen -= sizeof(*header);
+
+    /* Backing file format header extension */
+    if (*bs->backing_format) {
+        ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BACKING_FORMAT,
+                             bs->backing_format, strlen(bs->backing_format),
+                             buflen);
+        if (ret < 0) {
+            goto fail;
         }
 
-        memcpy(buf + offset, backing_file, backing_file_len);
-        backing_file_offset = sizeof(QCowHeader) + offset;
+        buf += ret;
+        buflen -= ret;
     }
 
-    ret = bdrv_pwrite_sync(bs->file, sizeof(QCowHeader), buf, ext_size);
+    /* Keep unknown header extensions */
+    QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
+        ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
+        if (ret < 0) {
+            goto fail;
+        }
+
+        buf += ret;
+        buflen -= ret;
+    }
+
+    /* End of header extensions */
+    ret = header_ext_add(buf, QCOW2_EXT_MAGIC_END, NULL, 0, buflen);
     if (ret < 0) {
         goto fail;
     }
 
-    /* Update header fields */
-    uint64_t be_backing_file_offset = cpu_to_be64(backing_file_offset);
-    uint32_t be_backing_file_size = cpu_to_be32(backing_file_len);
+    buf += ret;
+    buflen -= ret;
 
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_offset),
-        &be_backing_file_offset, sizeof(uint64_t));
-    if (ret < 0) {
-        goto fail;
+    /* Backing file name */
+    if (*bs->backing_file) {
+        size_t backing_file_len = strlen(bs->backing_file);
+
+        if (buflen < backing_file_len) {
+            ret = -ENOSPC;
+            goto fail;
+        }
+
+        strncpy(buf, bs->backing_file, buflen);
+
+        header->backing_file_offset = cpu_to_be64(buf - ((char*) header));
+        header->backing_file_size   = cpu_to_be32(backing_file_len);
     }
 
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, backing_file_size),
-        &be_backing_file_size, sizeof(uint32_t));
+    /* Write the new header */
+    ret = bdrv_pwrite(bs->file, 0, header, s->cluster_size);
     if (ret < 0) {
         goto fail;
     }
 
     ret = 0;
 fail:
+    qemu_vfree(header);
     return ret;
 }
 
 static int qcow2_change_backing_file(BlockDriverState *bs,
     const char *backing_file, const char *backing_fmt)
 {
-    return qcow2_update_ext_header(bs, backing_file, backing_fmt);
+    /* Backing file format doesn't make sense without a backing file */
+    if (backing_fmt && !backing_file) {
+        return -EINVAL;
+    }
+
+    pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
+    pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
+
+    return qcow2_update_header(bs);
 }
 
 static int preallocate(BlockDriverState *bs)
diff --git a/block/qcow2.h b/block/qcow2.h
index 99e4536..fc35838 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -87,6 +87,13 @@
 struct Qcow2Cache;
 typedef struct Qcow2Cache Qcow2Cache;
 
+typedef struct Qcow2UnknownHeaderExtension {
+    uint32_t magic;
+    uint32_t len;
+    QLIST_ENTRY(Qcow2UnknownHeaderExtension) next;
+    uint8_t data[];
+} Qcow2UnknownHeaderExtension;
+
 typedef struct BDRVQcowState {
     int cluster_bits;
     int cluster_size;
@@ -127,6 +134,7 @@
     QCowSnapshot *snapshots;
 
     int flags;
+    QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
 } BDRVQcowState;
 
 /* XXX: use std qcow open function ? */
@@ -178,6 +186,7 @@
 /* qcow2.c functions */
 int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
                   int64_t sector_num, int nb_sectors);
+int qcow2_update_header(BlockDriverState *bs);
 
 /* qcow2-refcount.c functions */
 int qcow2_refcount_init(BlockDriverState *bs);
diff --git a/block/qed.c b/block/qed.c
index 8da3ebe..a041d31 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -875,6 +875,12 @@
     qemu_iovec_destroy(&acb->cur_qiov);
     qed_unref_l2_cache_entry(acb->request.l2_table);
 
+    /* Free the buffer we may have allocated for zero writes */
+    if (acb->flags & QED_AIOCB_ZERO) {
+        qemu_vfree(acb->qiov->iov[0].iov_base);
+        acb->qiov->iov[0].iov_base = NULL;
+    }
+
     /* Arrange for a bh to invoke the completion function */
     acb->bh_ret = ret;
     acb->bh = qemu_bh_new(qed_aio_complete_bh, acb);
@@ -941,9 +947,8 @@
 /**
  * Update L2 table with new cluster offsets and write them out
  */
-static void qed_aio_write_l2_update(void *opaque, int ret)
+static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
 {
-    QEDAIOCB *acb = opaque;
     BDRVQEDState *s = acb_to_s(acb);
     bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
     int index;
@@ -959,7 +964,7 @@
 
     index = qed_l2_index(s, acb->cur_pos);
     qed_update_l2_table(s, acb->request.l2_table->table, index, acb->cur_nclusters,
-                         acb->cur_cluster);
+                         offset);
 
     if (need_alloc) {
         /* Write out the whole new L2 table */
@@ -976,6 +981,12 @@
     qed_aio_complete(acb, ret);
 }
 
+static void qed_aio_write_l2_update_cb(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    qed_aio_write_l2_update(acb, ret, acb->cur_cluster);
+}
+
 /**
  * Flush new data clusters before updating the L2 table
  *
@@ -990,7 +1001,7 @@
     QEDAIOCB *acb = opaque;
     BDRVQEDState *s = acb_to_s(acb);
 
-    if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update, opaque)) {
+    if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update_cb, opaque)) {
         qed_aio_complete(acb, -EIO);
     }
 }
@@ -1019,7 +1030,7 @@
         if (s->bs->backing_hd) {
             next_fn = qed_aio_write_flush_before_l2_update;
         } else {
-            next_fn = qed_aio_write_l2_update;
+            next_fn = qed_aio_write_l2_update_cb;
         }
     }
 
@@ -1081,6 +1092,18 @@
     return !(s->header.features & QED_F_NEED_CHECK);
 }
 
+static void qed_aio_write_zero_cluster(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    qed_aio_write_l2_update(acb, 0, 1);
+}
+
 /**
  * Write new data cluster
  *
@@ -1092,6 +1115,7 @@
 static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
 {
     BDRVQEDState *s = acb_to_s(acb);
+    BlockDriverCompletionFunc *cb;
 
     /* Cancel timer when the first allocating request comes in */
     if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
@@ -1109,14 +1133,26 @@
 
     acb->cur_nclusters = qed_bytes_to_clusters(s,
             qed_offset_into_cluster(s, acb->cur_pos) + len);
-    acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
     qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
 
+    if (acb->flags & QED_AIOCB_ZERO) {
+        /* Skip ahead if the clusters are already zero */
+        if (acb->find_cluster_ret == QED_CLUSTER_ZERO) {
+            qed_aio_next_io(acb, 0);
+            return;
+        }
+
+        cb = qed_aio_write_zero_cluster;
+    } else {
+        cb = qed_aio_write_prefill;
+        acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
+    }
+
     if (qed_should_set_need_check(s)) {
         s->header.features |= QED_F_NEED_CHECK;
-        qed_write_header(s, qed_aio_write_prefill, acb);
+        qed_write_header(s, cb, acb);
     } else {
-        qed_aio_write_prefill(acb, 0);
+        cb(acb, 0);
     }
 }
 
@@ -1131,6 +1167,16 @@
  */
 static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
 {
+    /* Allocate buffer for zero writes */
+    if (acb->flags & QED_AIOCB_ZERO) {
+        struct iovec *iov = acb->qiov->iov;
+
+        if (!iov->iov_base) {
+            iov->iov_base = qemu_blockalign(acb->common.bs, iov->iov_len);
+            memset(iov->iov_base, 0, iov->iov_len);
+        }
+    }
+
     /* Calculate the I/O vector */
     acb->cur_cluster = offset;
     qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
@@ -1233,8 +1279,8 @@
 {
     QEDAIOCB *acb = opaque;
     BDRVQEDState *s = acb_to_s(acb);
-    QEDFindClusterFunc *io_fn =
-        acb->is_write ? qed_aio_write_data : qed_aio_read_data;
+    QEDFindClusterFunc *io_fn = (acb->flags & QED_AIOCB_WRITE) ?
+                                qed_aio_write_data : qed_aio_read_data;
 
     trace_qed_aio_next_io(s, acb, ret, acb->cur_pos + acb->cur_qiov.size);
 
@@ -1264,14 +1310,14 @@
                                        int64_t sector_num,
                                        QEMUIOVector *qiov, int nb_sectors,
                                        BlockDriverCompletionFunc *cb,
-                                       void *opaque, bool is_write)
+                                       void *opaque, int flags)
 {
     QEDAIOCB *acb = qemu_aio_get(&qed_aio_pool, bs, cb, opaque);
 
     trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
-                         opaque, is_write);
+                        opaque, flags);
 
-    acb->is_write = is_write;
+    acb->flags = flags;
     acb->finished = NULL;
     acb->qiov = qiov;
     acb->qiov_offset = 0;
@@ -1291,7 +1337,7 @@
                                             BlockDriverCompletionFunc *cb,
                                             void *opaque)
 {
-    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, false);
+    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
 }
 
 static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
@@ -1300,7 +1346,8 @@
                                              BlockDriverCompletionFunc *cb,
                                              void *opaque)
 {
-    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, true);
+    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb,
+                         opaque, QED_AIOCB_WRITE);
 }
 
 static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
@@ -1310,6 +1357,53 @@
     return bdrv_aio_flush(bs->file, cb, opaque);
 }
 
+typedef struct {
+    Coroutine *co;
+    int ret;
+    bool done;
+} QEDWriteZeroesCB;
+
+static void coroutine_fn qed_co_write_zeroes_cb(void *opaque, int ret)
+{
+    QEDWriteZeroesCB *cb = opaque;
+
+    cb->done = true;
+    cb->ret = ret;
+    if (cb->co) {
+        qemu_coroutine_enter(cb->co, NULL);
+    }
+}
+
+static int coroutine_fn bdrv_qed_co_write_zeroes(BlockDriverState *bs,
+                                                 int64_t sector_num,
+                                                 int nb_sectors)
+{
+    BlockDriverAIOCB *blockacb;
+    QEDWriteZeroesCB cb = { .done = false };
+    QEMUIOVector qiov;
+    struct iovec iov;
+
+    /* Zero writes start without an I/O buffer.  If a buffer becomes necessary
+     * then it will be allocated during request processing.
+     */
+    iov.iov_base = NULL,
+    iov.iov_len  = nb_sectors * BDRV_SECTOR_SIZE,
+
+    qemu_iovec_init_external(&qiov, &iov, 1);
+    blockacb = qed_aio_setup(bs, sector_num, &qiov, nb_sectors,
+                             qed_co_write_zeroes_cb, &cb,
+                             QED_AIOCB_WRITE | QED_AIOCB_ZERO);
+    if (!blockacb) {
+        return -EIO;
+    }
+    if (!cb.done) {
+        cb.co = qemu_coroutine_self();
+        qemu_coroutine_yield();
+    }
+    assert(cb.done);
+    return cb.ret;
+}
+
 static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
 {
     BDRVQEDState *s = bs->opaque;
@@ -1469,6 +1563,7 @@
     .bdrv_aio_readv           = bdrv_qed_aio_readv,
     .bdrv_aio_writev          = bdrv_qed_aio_writev,
     .bdrv_aio_flush           = bdrv_qed_aio_flush,
+    .bdrv_co_write_zeroes     = bdrv_qed_co_write_zeroes,
     .bdrv_truncate            = bdrv_qed_truncate,
     .bdrv_getlength           = bdrv_qed_getlength,
     .bdrv_get_info            = bdrv_qed_get_info,
diff --git a/block/qed.h b/block/qed.h
index 62cbd3b..62624a1 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -123,12 +123,17 @@
     CachedL2Table *l2_table;
 } QEDRequest;
 
+enum {
+    QED_AIOCB_WRITE = 0x0001,       /* read or write? */
+    QED_AIOCB_ZERO  = 0x0002,       /* zero write, used with QED_AIOCB_WRITE */
+};
+
 typedef struct QEDAIOCB {
     BlockDriverAIOCB common;
     QEMUBH *bh;
     int bh_ret;                     /* final return status for completion bh */
     QSIMPLEQ_ENTRY(QEDAIOCB) next;  /* next request */
-    bool is_write;                  /* false - read, true - write */
+    int flags;                      /* QED_AIOCB_* bits ORed together */
     bool *finished;                 /* signal for cancel completion */
     uint64_t end_pos;               /* request end on block device, in bytes */
 
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 9416400..00276f6f 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -629,6 +629,9 @@
 
     switch (acb->aiocb_type) {
     case AIOCB_WRITE_UDATA:
+        /* this coroutine context is no longer suitable for co_recv
+         * because we may send data to update vdi objects */
+        s->co_recv = NULL;
         if (!is_data_obj(aio_req->oid)) {
             break;
         }
diff --git a/block/vpc.c b/block/vpc.c
index 89a5ee2..6b4816f 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -161,13 +161,27 @@
     uint8_t buf[HEADER_SIZE];
     uint32_t checksum;
     int err = -1;
+    int disk_type = VHD_DYNAMIC;
 
     if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
         goto fail;
 
     footer = (struct vhd_footer*) s->footer_buf;
-    if (strncmp(footer->creator, "conectix", 8))
-        goto fail;
+    if (strncmp(footer->creator, "conectix", 8)) {
+        int64_t offset = bdrv_getlength(bs->file);
+        if (offset < HEADER_SIZE) {
+            goto fail;
+        }
+        /* If a fixed disk, the footer is found only at the end of the file */
+        if (bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE)
+                != HEADER_SIZE) {
+            goto fail;
+        }
+        if (strncmp(footer->creator, "conectix", 8)) {
+            goto fail;
+        }
+        disk_type = VHD_FIXED;
+    }
 
     checksum = be32_to_cpu(footer->checksum);
     footer->checksum = 0;
@@ -186,49 +200,54 @@
         goto fail;
     }
 
-    if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
-            != HEADER_SIZE)
-        goto fail;
-
-    dyndisk_header = (struct vhd_dyndisk_header*) buf;
-
-    if (strncmp(dyndisk_header->magic, "cxsparse", 8))
-        goto fail;
-
-
-    s->block_size = be32_to_cpu(dyndisk_header->block_size);
-    s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
-
-    s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
-    s->pagetable = g_malloc(s->max_table_entries * 4);
-
-    s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
-    if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
-            s->max_table_entries * 4) != s->max_table_entries * 4)
-	    goto fail;
-
-    s->free_data_block_offset =
-        (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
-
-    for (i = 0; i < s->max_table_entries; i++) {
-        be32_to_cpus(&s->pagetable[i]);
-        if (s->pagetable[i] != 0xFFFFFFFF) {
-            int64_t next = (512 * (int64_t) s->pagetable[i]) +
-                s->bitmap_size + s->block_size;
-
-            if (next> s->free_data_block_offset)
-                s->free_data_block_offset = next;
+    if (disk_type == VHD_DYNAMIC) {
+        if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
+                HEADER_SIZE) != HEADER_SIZE) {
+            goto fail;
         }
-    }
 
-    s->last_bitmap_offset = (int64_t) -1;
+        dyndisk_header = (struct vhd_dyndisk_header *) buf;
+
+        if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
+            goto fail;
+        }
+
+        s->block_size = be32_to_cpu(dyndisk_header->block_size);
+        s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
+
+        s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
+        s->pagetable = g_malloc(s->max_table_entries * 4);
+
+        s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
+        if (bdrv_pread(bs->file, s->bat_offset, s->pagetable,
+                s->max_table_entries * 4) != s->max_table_entries * 4) {
+            goto fail;
+        }
+
+        s->free_data_block_offset =
+            (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
+
+        for (i = 0; i < s->max_table_entries; i++) {
+            be32_to_cpus(&s->pagetable[i]);
+            if (s->pagetable[i] != 0xFFFFFFFF) {
+                int64_t next = (512 * (int64_t) s->pagetable[i]) +
+                    s->bitmap_size + s->block_size;
+
+                if (next > s->free_data_block_offset) {
+                    s->free_data_block_offset = next;
+                }
+            }
+        }
+
+        s->last_bitmap_offset = (int64_t) -1;
 
 #ifdef CACHE
-    s->pageentry_u8 = g_malloc(512);
-    s->pageentry_u32 = s->pageentry_u8;
-    s->pageentry_u16 = s->pageentry_u8;
-    s->last_pagetable = -1;
+        s->pageentry_u8 = g_malloc(512);
+        s->pageentry_u32 = s->pageentry_u8;
+        s->pageentry_u16 = s->pageentry_u8;
+        s->last_pagetable = -1;
 #endif
+    }
 
     qemu_co_mutex_init(&s->lock);
 
@@ -395,7 +414,11 @@
     int ret;
     int64_t offset;
     int64_t sectors, sectors_per_block;
+    struct vhd_footer *footer = (struct vhd_footer *) s->footer_buf;
 
+    if (cpu_to_be32(footer->type) == VHD_FIXED) {
+        return bdrv_read(bs->file, sector_num, buf, nb_sectors);
+    }
     while (nb_sectors > 0) {
         offset = get_sector_offset(bs, sector_num, 0);
 
@@ -440,7 +463,11 @@
     int64_t offset;
     int64_t sectors, sectors_per_block;
     int ret;
+    struct vhd_footer *footer =  (struct vhd_footer *) s->footer_buf;
 
+    if (cpu_to_be32(footer->type) == VHD_FIXED) {
+        return bdrv_write(bs->file, sector_num, buf, nb_sectors);
+    }
     while (nb_sectors > 0) {
         offset = get_sector_offset(bs, sector_num, 1);
 
@@ -533,70 +560,14 @@
     return 0;
 }
 
-static int vpc_create(const char *filename, QEMUOptionParameter *options)
+static int create_dynamic_disk(int fd, uint8_t *buf, int64_t total_sectors)
 {
-    uint8_t buf[1024];
-    struct vhd_footer* footer = (struct vhd_footer*) buf;
     struct vhd_dyndisk_header* dyndisk_header =
         (struct vhd_dyndisk_header*) buf;
-    int fd, i;
-    uint16_t cyls = 0;
-    uint8_t heads = 0;
-    uint8_t secs_per_cyl = 0;
     size_t block_size, num_bat_entries;
-    int64_t total_sectors = 0;
+    int i;
     int ret = -EIO;
 
-    // Read out options
-    total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n /
-                    BDRV_SECTOR_SIZE;
-
-    // Create the file
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-    if (fd < 0)
-        return -EIO;
-
-    /* Calculate matching total_size and geometry. Increase the number of
-       sectors requested until we get enough (or fail). */
-    for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
-        if (calculate_geometry(total_sectors + i,
-                               &cyls, &heads, &secs_per_cyl)) {
-            ret = -EFBIG;
-            goto fail;
-        }
-    }
-    total_sectors = (int64_t) cyls * heads * secs_per_cyl;
-
-    // Prepare the Hard Disk Footer
-    memset(buf, 0, 1024);
-
-    memcpy(footer->creator, "conectix", 8);
-    // TODO Check if "qemu" creator_app is ok for VPC
-    memcpy(footer->creator_app, "qemu", 4);
-    memcpy(footer->creator_os, "Wi2k", 4);
-
-    footer->features = be32_to_cpu(0x02);
-    footer->version = be32_to_cpu(0x00010000);
-    footer->data_offset = be64_to_cpu(HEADER_SIZE);
-    footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
-
-    // Version of Virtual PC 2007
-    footer->major = be16_to_cpu(0x0005);
-    footer->minor =be16_to_cpu(0x0003);
-
-    footer->orig_size = be64_to_cpu(total_sectors * 512);
-    footer->size = be64_to_cpu(total_sectors * 512);
-
-    footer->cyls = be16_to_cpu(cyls);
-    footer->heads = heads;
-    footer->secs_per_cyl = secs_per_cyl;
-
-    footer->type = be32_to_cpu(VHD_DYNAMIC);
-
-    // TODO uuid is missing
-
-    footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
-
     // Write the footer (twice: at the beginning and at the end)
     block_size = 0x200000;
     num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
@@ -624,7 +595,6 @@
         }
     }
 
-
     // Prepare the Dynamic Disk Header
     memset(buf, 0, 1024);
 
@@ -653,6 +623,129 @@
     ret = 0;
 
  fail:
+    return ret;
+}
+
+static int create_fixed_disk(int fd, uint8_t *buf, int64_t total_size)
+{
+    int ret = -EIO;
+
+    /* Add footer to total size */
+    total_size += 512;
+    if (ftruncate(fd, total_size) != 0) {
+        ret = -errno;
+        goto fail;
+    }
+    if (lseek(fd, -512, SEEK_END) < 0) {
+        goto fail;
+    }
+    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+        goto fail;
+    }
+
+    ret = 0;
+
+ fail:
+    return ret;
+}
+
+static int vpc_create(const char *filename, QEMUOptionParameter *options)
+{
+    uint8_t buf[1024];
+    struct vhd_footer *footer = (struct vhd_footer *) buf;
+    QEMUOptionParameter *disk_type_param;
+    int fd, i;
+    uint16_t cyls = 0;
+    uint8_t heads = 0;
+    uint8_t secs_per_cyl = 0;
+    int64_t total_sectors;
+    int64_t total_size;
+    int disk_type;
+    int ret = -EIO;
+
+    /* Read out options */
+    total_size = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n;
+
+    disk_type_param = get_option_parameter(options, BLOCK_OPT_SUBFMT);
+    if (disk_type_param && disk_type_param->value.s) {
+        if (!strcmp(disk_type_param->value.s, "dynamic")) {
+            disk_type = VHD_DYNAMIC;
+        } else if (!strcmp(disk_type_param->value.s, "fixed")) {
+            disk_type = VHD_FIXED;
+        } else {
+            return -EINVAL;
+        }
+    } else {
+        disk_type = VHD_DYNAMIC;
+    }
+
+    /* Create the file */
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0) {
+        return -EIO;
+    }
+
+    /*
+     * Calculate matching total_size and geometry. Increase the number of
+     * sectors requested until we get enough (or fail). This ensures that
+     * qemu-img convert doesn't truncate images, but rather rounds up.
+     */
+    total_sectors = total_size / BDRV_SECTOR_SIZE;
+    for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
+        if (calculate_geometry(total_sectors + i, &cyls, &heads,
+                               &secs_per_cyl))
+        {
+            ret = -EFBIG;
+            goto fail;
+        }
+    }
+
+    total_sectors = (int64_t) cyls * heads * secs_per_cyl;
+
+    /* Prepare the Hard Disk Footer */
+    memset(buf, 0, 1024);
+
+    memcpy(footer->creator, "conectix", 8);
+    /* TODO Check if "qemu" creator_app is ok for VPC */
+    memcpy(footer->creator_app, "qemu", 4);
+    memcpy(footer->creator_os, "Wi2k", 4);
+
+    footer->features = be32_to_cpu(0x02);
+    footer->version = be32_to_cpu(0x00010000);
+    if (disk_type == VHD_DYNAMIC) {
+        footer->data_offset = be64_to_cpu(HEADER_SIZE);
+    } else {
+        footer->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
+    }
+    footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
+
+    /* Version of Virtual PC 2007 */
+    footer->major = be16_to_cpu(0x0005);
+    footer->minor = be16_to_cpu(0x0003);
+    if (disk_type == VHD_DYNAMIC) {
+        footer->orig_size = be64_to_cpu(total_sectors * 512);
+        footer->size = be64_to_cpu(total_sectors * 512);
+    } else {
+        footer->orig_size = be64_to_cpu(total_size);
+        footer->size = be64_to_cpu(total_size);
+    }
+    footer->cyls = be16_to_cpu(cyls);
+    footer->heads = heads;
+    footer->secs_per_cyl = secs_per_cyl;
+
+    footer->type = be32_to_cpu(disk_type);
+
+    /* TODO uuid is missing */
+
+    footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
+
+    if (disk_type == VHD_DYNAMIC) {
+        ret = create_dynamic_disk(fd, buf, total_sectors);
+    } else {
+        ret = create_fixed_disk(fd, buf, total_size);
+    }
+
+ fail:
     close(fd);
     return ret;
 }
@@ -675,6 +768,13 @@
         .type = OPT_SIZE,
         .help = "Virtual disk size"
     },
+    {
+        .name = BLOCK_OPT_SUBFMT,
+        .type = OPT_STRING,
+        .help =
+            "Type of virtual hard disk format. Supported formats are "
+            "{dynamic (default) | fixed} "
+    },
     { NULL }
 };
 
diff --git a/block_int.h b/block_int.h
index 7be2988..7946cf6 100644
--- a/block_int.h
+++ b/block_int.h
@@ -131,6 +131,14 @@
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
     int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    /*
+     * Efficiently zero a region of the disk image.  Typically an image format
+     * would use a compact metadata representation to implement this.  This
+     * function pointer may be NULL and .bdrv_co_writev() will be called
+     * instead.
+     */
+    int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors);
     int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors);
     int coroutine_fn (*bdrv_co_is_allocated)(BlockDriverState *bs,
diff --git a/compiler.h b/compiler.h
index a1c0794..736e770 100644
--- a/compiler.h
+++ b/compiler.h
@@ -30,8 +30,10 @@
 # define QEMU_PACKED __attribute__((packed))
 #endif
 
+#define cat(x,y) x ## y
+#define cat2(x,y) cat(x,y)
 #define QEMU_BUILD_BUG_ON(x) \
-    typedef char qemu_build_bug_on__##__LINE__[(x)?-1:1];
+    typedef char cat2(qemu_build_bug_on__,__LINE__)[(x)?-1:1];
 
 #if defined __GNUC__
 # if !QEMU_GNUC_PREREQ(4, 4)
diff --git a/configure b/configure
index 763db24..68f9ee6 100755
--- a/configure
+++ b/configure
@@ -2584,7 +2584,7 @@
 
 # check for usbredirparser for usb network redirection support
 if test "$usb_redir" != "no" ; then
-    if $pkg_config libusbredirparser >/dev/null 2>&1 ; then
+    if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then
         usb_redir="yes"
         usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
         usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
diff --git a/cutils.c b/cutils.c
index a6ffd46..af308cd 100644
--- a/cutils.c
+++ b/cutils.c
@@ -303,6 +303,41 @@
     }
 }
 
+/*
+ * Checks if a buffer is all zeroes
+ *
+ * Attention! The len must be a multiple of 4 * sizeof(long) due to
+ * restriction of optimizations in this function.
+ */
+bool buffer_is_zero(const void *buf, size_t len)
+{
+    /*
+     * Use long as the biggest available internal data type that fits into the
+     * CPU register and unroll the loop to smooth out the effect of memory
+     * latency.
+     */
+
+    size_t i;
+    long d0, d1, d2, d3;
+    const long * const data = buf;
+
+    assert(len % (4 * sizeof(long)) == 0);
+    len /= sizeof(long);
+
+    for (i = 0; i < len; i += 4) {
+        d0 = data[i + 0];
+        d1 = data[i + 1];
+        d2 = data[i + 2];
+        d3 = data[i + 3];
+
+        if (d0 || d1 || d2 || d3) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 #ifndef _WIN32
 /* Sets a specific flag */
 int fcntl_setfl(int fd, int flag)
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 791a557..b8220ab 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -184,10 +184,10 @@
     .class_init    = virtio_9p_class_init,
 };
 
-static void virtio_9p_register_devices(void)
+static void virtio_9p_register_types(void)
 {
     type_register_static(&virtio_9p_info);
     virtio_9p_set_fd_limit();
 }
 
-device_init(virtio_9p_register_devices)
+type_init(virtio_9p_register_types)
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 19de12b..03b128c 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -238,9 +238,9 @@
     .class_init    = a9mp_priv_class_init,
 };
 
-static void a9mp_register_devices(void)
+static void a9mp_register_types(void)
 {
     type_register_static(&a9mp_priv_info);
 }
 
-device_init(a9mp_register_devices)
+type_init(a9mp_register_types)
diff --git a/hw/ac97.c b/hw/ac97.c
index 7bf9171..c0fd019 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1372,9 +1372,9 @@
     .class_init    = ac97_class_init,
 };
 
-static void ac97_register (void)
+static void ac97_register_types (void)
 {
     type_register_static (&ac97_info);
 }
-device_init (ac97_register);
 
+type_init (ac97_register_types)
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 21484ae..d959f49 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -426,12 +426,12 @@
     .class_init    = piix4_pm_class_init,
 };
 
-static void piix4_pm_register(void)
+static void piix4_pm_register_types(void)
 {
     type_register_static(&piix4_pm_info);
 }
 
-device_init(piix4_pm_register);
+type_init(piix4_pm_register_types)
 
 static uint32_t gpe_readb(void *opaque, uint32_t addr)
 {
diff --git a/hw/ads7846.c b/hw/ads7846.c
index 3cfdecb..41c7f10 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -168,9 +168,9 @@
     .class_init    = ads7846_class_init,
 };
 
-static void ads7846_register_devices(void)
+static void ads7846_register_types(void)
 {
     type_register_static(&ads7846_info);
 }
 
-device_init(ads7846_register_devices)
+type_init(ads7846_register_types)
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 736c28a..b539416 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -824,8 +824,9 @@
     .class_init    = typhoon_pcihost_class_init,
 };
 
-static void typhoon_register(void)
+static void typhoon_register_types(void)
 {
     type_register_static(&typhoon_pcihost_info);
 }
-device_init(typhoon_register);
+
+type_init(typhoon_register_types)
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index c7aaa72..1d25da8 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -493,11 +493,11 @@
     .class_init    = pbm_pci_bridge_class_init,
 };
 
-static void pbm_register_devices(void)
+static void pbm_register_types(void)
 {
     type_register_static(&pbm_host_info);
     type_register_static(&pbm_pci_host_info);
     type_register_static(&pbm_pci_bridge_info);
 }
 
-device_init(pbm_register_devices)
+type_init(pbm_register_types)
diff --git a/hw/apic.c b/hw/apic.c
index 086c544..ff9d24e 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -781,9 +781,9 @@
     .class_init    = apic_class_init,
 };
 
-static void apic_register_devices(void)
+static void apic_register_types(void)
 {
     type_register_static(&apic_info);
 }
 
-device_init(apic_register_devices)
+type_init(apic_register_types)
diff --git a/hw/apic_common.c b/hw/apic_common.c
index 26991b4..c91f7d5 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -188,6 +188,7 @@
 static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
 {
     APICCommonState *s = opaque;
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
     int i;
 
     if (version_id > 2) {
@@ -220,7 +221,11 @@
     s->next_time = qemu_get_be64(f);
 
     if (version_id >= 2) {
-        qemu_get_timer(f, s->timer);
+        s->timer_expiry = qemu_get_be64(f);
+    }
+
+    if (info->post_load) {
+        info->post_load(s);
     }
     return 0;
 }
@@ -313,9 +318,9 @@
     .abstract = true,
 };
 
-static void register_devices(void)
+static void register_types(void)
 {
     type_register_static(&apic_common_type);
 }
 
-device_init(register_devices);
+type_init(register_types)
diff --git a/hw/applesmc.c b/hw/applesmc.c
index b06487f..8bedaad 100644
--- a/hw/applesmc.c
+++ b/hw/applesmc.c
@@ -243,9 +243,9 @@
     .class_init    = qdev_applesmc_class_init,
 };
 
-static void applesmc_register_devices(void)
+static void applesmc_register_types(void)
 {
     type_register_static(&applesmc_isa_info);
 }
 
-device_init(applesmc_register_devices)
+type_init(applesmc_register_types)
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index 3c0839c..102348b 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -252,10 +252,10 @@
     .class_init    = mpcore_priv_class_init,
 };
 
-static void arm11mpcore_register_devices(void)
+static void arm11mpcore_register_types(void)
 {
     type_register_static(&mpcore_rirq_info);
     type_register_static(&mpcore_priv_info);
 }
 
-device_init(arm11mpcore_register_devices)
+type_init(arm11mpcore_register_types)
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 5f163fd..34a8739 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -81,9 +81,10 @@
     p += 4;                       \
 } while (0)
 
-static void set_kernel_args(const struct arm_boot_info *info,
-                int initrd_size, target_phys_addr_t base)
+static void set_kernel_args(const struct arm_boot_info *info)
 {
+    int initrd_size = info->initrd_size;
+    target_phys_addr_t base = info->loader_start;
     target_phys_addr_t p;
 
     p = base + KERNEL_ARGS_ADDR;
@@ -134,12 +135,12 @@
     WRITE_WORD(p, 0);
 }
 
-static void set_kernel_args_old(const struct arm_boot_info *info,
-                int initrd_size, target_phys_addr_t base)
+static void set_kernel_args_old(const struct arm_boot_info *info)
 {
     target_phys_addr_t p;
     const char *s;
-
+    int initrd_size = info->initrd_size;
+    target_phys_addr_t base = info->loader_start;
 
     /* see linux/include/asm-arm/setup.h */
     p = base + KERNEL_ARGS_ADDR;
@@ -222,11 +223,9 @@
             if (env == first_cpu) {
                 env->regs[15] = info->loader_start;
                 if (old_param) {
-                    set_kernel_args_old(info, info->initrd_size,
-                                        info->loader_start);
+                    set_kernel_args_old(info);
                 } else {
-                    set_kernel_args(info, info->initrd_size,
-                                    info->loader_start);
+                    set_kernel_args(info);
                 }
             } else {
                 info->secondary_cpu_reset_hook(env, info);
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
index ba26abc..09f290c 100644
--- a/hw/arm_l2x0.c
+++ b/hw/arm_l2x0.c
@@ -184,9 +184,9 @@
     .class_init = l2x0_class_init,
 };
 
-static void l2x0_register_device(void)
+static void l2x0_register_types(void)
 {
     type_register_static(&l2x0_info);
 }
 
-device_init(l2x0_register_device)
+type_init(l2x0_register_types)
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index 5a02365..361e887 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -335,9 +335,9 @@
     .class_init    = arm_mptimer_class_init,
 };
 
-static void arm_mptimer_register_devices(void)
+static void arm_mptimer_register_types(void)
 {
     type_register_static(&arm_mptimer_info);
 }
 
-device_init(arm_mptimer_register_devices)
+type_init(arm_mptimer_register_types)
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 9d25799..149c639 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -425,9 +425,9 @@
     .class_init    = arm_sysctl_class_init,
 };
 
-static void arm_sysctl_register_devices(void)
+static void arm_sysctl_register_types(void)
 {
     type_register_static(&arm_sysctl_info);
 }
 
-device_init(arm_sysctl_register_devices)
+type_init(arm_sysctl_register_types)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 1019d41..e3ecce2 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -383,10 +383,10 @@
     .class_init    = sp804_class_init,
 };
 
-static void arm_timer_register_devices(void)
+static void arm_timer_register_types(void)
 {
     type_register_static(&icp_pit_info);
     type_register_static(&sp804_info);
 }
 
-device_init(arm_timer_register_devices)
+type_init(arm_timer_register_types)
diff --git a/hw/armv7m.c b/hw/armv7m.c
index de3d7e0..6b80579 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -266,9 +266,9 @@
     .class_init    = bitband_class_init,
 };
 
-static void armv7m_register_devices(void)
+static void armv7m_register_types(void)
 {
     type_register_static(&bitband_info);
 }
 
-device_init(armv7m_register_devices)
+type_init(armv7m_register_types)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 1ed0abc..3210129 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -417,9 +417,9 @@
     .class_init    = armv7m_nvic_class_init,
 };
 
-static void armv7m_nvic_register_devices(void)
+static void armv7m_nvic_register_types(void)
 {
     type_register_static(&armv7m_nvic_info);
 }
 
-device_init(armv7m_nvic_register_devices)
+type_init(armv7m_nvic_register_types)
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
index c9c1182..44ed7f4 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -237,9 +237,9 @@
     .class_init    = gpio_i2c_class_init,
 };
 
-static void bitbang_i2c_register(void)
+static void bitbang_i2c_register_types(void)
 {
     type_register_static(&gpio_i2c_info);
 }
 
-device_init(bitbang_i2c_register)
+type_init(bitbang_i2c_register_types)
diff --git a/hw/bonito.c b/hw/bonito.c
index 7350a4f..77786f8 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -804,9 +804,10 @@
     .class_init    = bonito_pcihost_class_init,
 };
 
-static void bonito_register(void)
+static void bonito_register_types(void)
 {
     type_register_static(&bonito_pcihost_info);
     type_register_static(&bonito_info);
 }
-device_init(bonito_register);
+
+type_init(bonito_register_types)
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 9510ed4..f4a6da4 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -594,9 +594,9 @@
     .class_init    = emulated_class_initfn,
 };
 
-static void ccid_card_emulated_register_devices(void)
+static void ccid_card_emulated_register_types(void)
 {
     type_register_static(&emulated_card_info);
 }
 
-device_init(ccid_card_emulated_register_devices)
+type_init(ccid_card_emulated_register_types)
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
index a7006ca..bd6c777 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -343,9 +343,9 @@
     .class_init    = passthru_class_initfn,
 };
 
-static void ccid_card_passthru_register_devices(void)
+static void ccid_card_passthru_register_types(void)
 {
     type_register_static(&passthru_card_info);
 }
 
-device_init(ccid_card_passthru_register_devices)
+type_init(ccid_card_passthru_register_types)
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index a8e8ab7..4edcb94 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2923,12 +2923,6 @@
     .class_init = isa_cirrus_vga_class_init,
 };
 
-static void isa_cirrus_vga_register(void)
-{
-    type_register_static(&isa_cirrus_vga_info);
-}
-device_init(isa_cirrus_vga_register)
-
 /***************************************
  *
  *  PCI bus support
@@ -2996,8 +2990,10 @@
     .class_init    = cirrus_vga_class_init,
 };
 
-static void cirrus_vga_register(void)
+static void cirrus_vga_register_types(void)
 {
+    type_register_static(&isa_cirrus_vga_info);
     type_register_static(&cirrus_vga_info);
 }
-device_init(cirrus_vga_register);
+
+type_init(cirrus_vga_register_types)
diff --git a/hw/cs4231.c b/hw/cs4231.c
index c0badbf..cfec1d9 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -173,9 +173,9 @@
     .class_init    = cs4231_class_init,
 };
 
-static void cs4231_register_devices(void)
+static void cs4231_register_types(void)
 {
     type_register_static(&cs4231_info);
 }
 
-device_init(cs4231_register_devices)
+type_init(cs4231_register_types)
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index ad04ad6..e07b9d6 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -689,8 +689,9 @@
     .class_init    = cs4231a_class_initfn,
 };
 
-static void cs4231a_register (void)
+static void cs4231a_register_types (void)
 {
     type_register_static (&cs4231a_info);
 }
-device_init (cs4231a_register)
+
+type_init (cs4231a_register_types)
diff --git a/hw/debugcon.c b/hw/debugcon.c
index 3903b26..14ab326 100644
--- a/hw/debugcon.c
+++ b/hw/debugcon.c
@@ -109,9 +109,9 @@
     .class_init    = debugcon_isa_class_initfn,
 };
 
-static void debugcon_register_devices(void)
+static void debugcon_register_types(void)
 {
     type_register_static(&debugcon_isa_info);
 }
 
-device_init(debugcon_register_devices)
+type_init(debugcon_register_types)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index a40fbcf..37337bf 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -140,11 +140,11 @@
     .class_init    = pci_dec_21154_device_class_init,
 };
 
-static void dec_register_devices(void)
+static void dec_register_types(void)
 {
     type_register_static(&pci_dec_21154_device_info);
     type_register_static(&dec_21154_pci_host_info);
     type_register_static(&dec_21154_pci_bridge_info);
 }
 
-device_init(dec_register_devices)
+type_init(dec_register_types)
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 539bceb..2cd355b 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -157,9 +157,9 @@
     .class_init    = nvram_sysbus_class_init,
 };
 
-static void nvram_register(void)
+static void nvram_register_types(void)
 {
     type_register_static(&nvram_sysbus_info);
 }
 
-device_init(nvram_register)
+type_init(nvram_register_types)
diff --git a/hw/ds1338.c b/hw/ds1338.c
index b137e13..6397f0a 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -135,9 +135,9 @@
     .class_init    = ds1338_class_init,
 };
 
-static void ds1338_register_devices(void)
+static void ds1338_register_types(void)
 {
     type_register_static(&ds1338_info);
 }
 
-device_init(ds1338_register_devices)
+type_init(ds1338_register_types)
diff --git a/hw/e1000.c b/hw/e1000.c
index 751f79d5..7babc0b 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1227,9 +1227,9 @@
     .class_init    = e1000_class_init,
 };
 
-static void e1000_register_devices(void)
+static void e1000_register_types(void)
 {
     type_register_static(&e1000_info);
 }
 
-device_init(e1000_register_devices)
+type_init(e1000_register_types)
diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c
index 1cf2090..fe1cd90 100644
--- a/hw/eccmemctl.c
+++ b/hw/eccmemctl.c
@@ -332,9 +332,9 @@
 };
 
 
-static void ecc_register_devices(void)
+static void ecc_register_types(void)
 {
     type_register_static(&ecc_info);
 }
 
-device_init(ecc_register_devices)
+type_init(ecc_register_types)
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 843610c..e3ba719 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -2089,7 +2089,7 @@
     k->subsystem_id = info->subsystem_id;
 }
 
-static void eepro100_register_devices(void)
+static void eepro100_register_types(void)
 {
     size_t i;
     for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
@@ -2105,4 +2105,4 @@
     }
 }
 
-device_init(eepro100_register_devices)
+type_init(eepro100_register_types)
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
index 1bc1815..099c85e 100644
--- a/hw/empty_slot.c
+++ b/hw/empty_slot.c
@@ -90,9 +90,9 @@
     .class_init    = empty_slot_class_init,
 };
 
-static void empty_slot_register_devices(void)
+static void empty_slot_register_types(void)
 {
     type_register_static(&empty_slot_info);
 }
 
-device_init(empty_slot_register_devices);
+type_init(empty_slot_register_types)
diff --git a/hw/es1370.c b/hw/es1370.c
index e377c48..f19cef3 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -1054,9 +1054,10 @@
     .class_init    = es1370_class_init,
 };
 
-static void es1370_register (void)
+static void es1370_register_types (void)
 {
     type_register_static (&es1370_info);
 }
-device_init (es1370_register);
+
+type_init (es1370_register_types)
 
diff --git a/hw/escc.c b/hw/escc.c
index 9fe282f..4d8a8e8 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -931,9 +931,9 @@
     .class_init    = escc_class_init,
 };
 
-static void escc_register_devices(void)
+static void escc_register_types(void)
 {
     type_register_static(&escc_info);
 }
 
-device_init(escc_register_devices)
+type_init(escc_register_types)
diff --git a/hw/esp.c b/hw/esp.c
index 2f44386..2dda8e3 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -775,9 +775,9 @@
     .class_init    = esp_class_init,
 };
 
-static void esp_register_devices(void)
+static void esp_register_types(void)
 {
     type_register_static(&esp_info);
 }
 
-device_init(esp_register_devices)
+type_init(esp_register_types)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index aefd577..16a0637 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -637,9 +637,9 @@
     .class_init    = etraxfs_eth_class_init,
 };
 
-static void etraxfs_eth_register(void)
+static void etraxfs_eth_register_types(void)
 {
     type_register_static(&etraxfs_eth_info);
 }
 
-device_init(etraxfs_eth_register)
+type_init(etraxfs_eth_register_types)
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index 33541fc..dc27f88 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -172,9 +172,9 @@
     .class_init    = etraxfs_pic_class_init,
 };
 
-static void etraxfs_pic_register(void)
+static void etraxfs_pic_register_types(void)
 {
     type_register_static(&etraxfs_pic_info);
 }
 
-device_init(etraxfs_pic_register)
+type_init(etraxfs_pic_register_types)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 567cb8c..cecd819 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -240,9 +240,9 @@
     .class_init    = etraxfs_ser_class_init,
 };
 
-static void etraxfs_serial_register(void)
+static void etraxfs_serial_register_types(void)
 {
     type_register_static(&etraxfs_ser_info);
 }
 
-device_init(etraxfs_serial_register)
+type_init(etraxfs_serial_register_types)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index b71c5ee..9076a49 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -343,9 +343,9 @@
     .class_init    = etraxfs_timer_class_init,
 };
 
-static void etraxfs_timer_register(void)
+static void etraxfs_timer_register_types(void)
 {
     type_register_static(&etraxfs_timer_info);
 }
 
-device_init(etraxfs_timer_register)
+type_init(etraxfs_timer_register_types)
diff --git a/hw/fdc.c b/hw/fdc.c
index f575a2c..38fad58 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -2043,11 +2043,11 @@
     .class_init    = sun4m_fdc_class_init,
 };
 
-static void fdc_register_devices(void)
+static void fdc_register_types(void)
 {
     type_register_static(&isa_fdc_info);
     type_register_static(&sysbus_fdc_info);
     type_register_static(&sun4m_fdc_info);
 }
 
-device_init(fdc_register_devices)
+type_init(fdc_register_types)
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index ea122fb..f4747cd 100644
--- a/hw/framebuffer.c
+++ b/hw/framebuffer.c
@@ -87,7 +87,7 @@
     dest += i * dest_row_pitch;
 
     for (; i < rows; i++) {
-        dirty = memory_region_get_dirty(mem, addr, addr + src_width,
+        dirty = memory_region_get_dirty(mem, addr, src_width,
                                              DIRTY_MEMORY_VGA);
         if (dirty || invalidate) {
             fn(opaque, dest, src, cols, dest_col_pitch);
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index 6b2f7d1..7b3b576 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -556,9 +556,9 @@
     .class_init    = fw_cfg_class_init,
 };
 
-static void fw_cfg_register_devices(void)
+static void fw_cfg_register_types(void)
 {
     type_register_static(&fw_cfg_info);
 }
 
-device_init(fw_cfg_register_devices)
+type_init(fw_cfg_register_types)
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 66d0044..9c63bdd 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -574,9 +574,9 @@
     .class_init    = g364fb_sysbus_class_init,
 };
 
-static void g364fb_register(void)
+static void g364fb_register_types(void)
 {
     type_register_static(&g364fb_sysbus_info);
 }
 
-device_init(g364fb_register);
+type_init(g364fb_register_types)
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 8122baf..81ff3a3 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -157,10 +157,10 @@
     .class_init    = pci_grackle_class_init,
 };
 
-static void grackle_register_devices(void)
+static void grackle_register_types(void)
 {
     type_register_static(&grackle_pci_info);
     type_register_static(&grackle_pci_host_info);
 }
 
-device_init(grackle_register_devices)
+type_init(grackle_register_types)
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index 89de2d8..73fc989 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -263,9 +263,9 @@
     .class_init    = grlib_gptimer_class_init,
 };
 
-static void grlib_gptimer_register(void)
+static void grlib_gptimer_register_types(void)
 {
     type_register_static(&grlib_gptimer_info);
 }
 
-device_init(grlib_gptimer_register)
+type_init(grlib_gptimer_register_types)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
index fb0b236..41770a9 100644
--- a/hw/grlib_gptimer.c
+++ b/hw/grlib_gptimer.c
@@ -396,9 +396,9 @@
     .class_init    = grlib_gptimer_class_init,
 };
 
-static void grlib_gptimer_register(void)
+static void grlib_gptimer_register_types(void)
 {
     type_register_static(&grlib_gptimer_info);
 }
 
-device_init(grlib_gptimer_register)
+type_init(grlib_gptimer_register_types)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
index 1e5ad82..0f6e65c 100644
--- a/hw/grlib_irqmp.c
+++ b/hw/grlib_irqmp.c
@@ -377,9 +377,9 @@
     .class_init    = grlib_irqmp_class_init,
 };
 
-static void grlib_irqmp_register(void)
+static void grlib_irqmp_register_types(void)
 {
     type_register_static(&grlib_irqmp_info);
 }
 
-device_init(grlib_irqmp_register)
+type_init(grlib_irqmp_register_types)
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index e8cd59c..a2d0e5a 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1168,10 +1168,10 @@
     .class_init    = gt64120_class_init,
 };
 
-static void gt64120_pci_register_devices(void)
+static void gt64120_pci_register_types(void)
 {
     type_register_static(&gt64120_info);
     type_register_static(&gt64120_pci_info);
 }
 
-device_init(gt64120_pci_register_devices)
+type_init(gt64120_pci_register_types)
diff --git a/hw/gus.c b/hw/gus.c
index 2054707..840d098 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -324,8 +324,9 @@
     .class_init    = gus_class_initfn,
 };
 
-static void gus_register (void)
+static void gus_register_types (void)
 {
     type_register_static (&gus_info);
 }
-device_init (gus_register)
+
+type_init (gus_register_types)
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 152f8e6..8995519 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -948,9 +948,10 @@
     .class_init    = hda_audio_duplex_class_init,
 };
 
-static void hda_audio_register(void)
+static void hda_audio_register_types(void)
 {
     type_register_static(&hda_audio_output_info);
     type_register_static(&hda_audio_duplex_info);
 }
-device_init(hda_audio_register);
+
+type_init(hda_audio_register_types)
diff --git a/hw/highbank.c b/hw/highbank.c
index 684178e..b28b464 100644
--- a/hw/highbank.c
+++ b/hw/highbank.c
@@ -177,12 +177,12 @@
     .class_init    = highbank_regs_class_init,
 };
 
-static void highbank_regs_register_device(void)
+static void highbank_regs_register_types(void)
 {
     type_register_static(&highbank_regs_info);
 }
 
-device_init(highbank_regs_register_device)
+type_init(highbank_regs_register_types)
 
 static struct arm_boot_info highbank_binfo;
 
diff --git a/hw/hpet.c b/hw/hpet.c
index b6ace4e..ba36e10 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -720,9 +720,9 @@
     .class_init    = hpet_device_class_init,
 };
 
-static void hpet_register_device(void)
+static void hpet_register_types(void)
 {
     type_register_static(&hpet_device_info);
 }
 
-device_init(hpet_register_device)
+type_init(hpet_register_types)
diff --git a/hw/i2c.c b/hw/i2c.c
index 8ae4aaa..23dfccb 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -230,9 +230,9 @@
     .class_init = i2c_slave_class_init,
 };
 
-static void i2c_slave_register_devices(void)
+static void i2c_slave_register_types(void)
 {
     type_register_static(&i2c_slave_type_info);
 }
 
-device_init(i2c_slave_register_devices);
+type_init(i2c_slave_register_types)
diff --git a/hw/i82374.c b/hw/i82374.c
index 220e8cc..67298a3 100644
--- a/hw/i82374.c
+++ b/hw/i82374.c
@@ -157,9 +157,9 @@
     .class_init = i82374_class_init,
 };
 
-static void i82374_register_devices(void)
+static void i82374_register_types(void)
 {
     type_register_static(&i82374_isa_info);
 }
 
-device_init(i82374_register_devices)
+type_init(i82374_register_types)
diff --git a/hw/i82378.c b/hw/i82378.c
index 9c3efe8..3929c04 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -267,9 +267,9 @@
     .class_init = pci_i82378_class_init,
 };
 
-static void i82378_register_devices(void)
+static void i82378_register_types(void)
 {
     type_register_static(&pci_i82378_info);
 }
 
-device_init(i82378_register_devices)
+type_init(i82378_register_types)
diff --git a/hw/i8254.c b/hw/i8254.c
index 522fed8..481fc7b 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -559,8 +559,9 @@
     .class_init    = pit_class_initfn,
 };
 
-static void pit_register(void)
+static void pit_register_types(void)
 {
     type_register_static(&pit_info);
 }
-device_init(pit_register)
+
+type_init(pit_register_types)
diff --git a/hw/i8259.c b/hw/i8259.c
index 7ae5380..1a4b1ab 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -488,9 +488,9 @@
     .class_init = i8259_class_init,
 };
 
-static void pic_register(void)
+static void pic_register_types(void)
 {
     type_register_static(&i8259_info);
 }
 
-device_init(pic_register)
+type_init(pic_register_types)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
index 9f150bc..775fda4 100644
--- a/hw/i8259_common.c
+++ b/hw/i8259_common.c
@@ -153,9 +153,9 @@
     .abstract = true,
 };
 
-static void register_devices(void)
+static void register_types(void)
 {
     type_register_static(&pic_common_type);
 }
 
-device_init(register_devices);
+type_init(register_types);
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index c87a6ca..b515f41 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -146,6 +146,7 @@
 
     DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
 
+    s->control_regs.irqstatus = 0;
     for (i = 0; i < s->ports; i++) {
         AHCIPortRegs *pr = &s->dev[i].port_regs;
         if (pr->irq_stat & pr->irq_mask) {
@@ -216,6 +217,7 @@
             break;
         case PORT_IRQ_STAT:
             pr->irq_stat &= ~val;
+            ahci_check_irq(s);
             break;
         case PORT_IRQ_MASK:
             pr->irq_mask = val & 0xfdc000ff;
@@ -560,6 +562,11 @@
             ncq_tfs->aiocb = NULL;
         }
 
+        /* Maybe we just finished the request thanks to bdrv_aio_cancel() */
+        if (!ncq_tfs->used) {
+            continue;
+        }
+
         qemu_sglist_destroy(&ncq_tfs->sglist);
         ncq_tfs->used = 0;
     }
@@ -1261,9 +1268,9 @@
     .class_init    = sysbus_ahci_class_init,
 };
 
-static void sysbus_ahci_register(void)
+static void sysbus_ahci_register_types(void)
 {
     type_register_static(&sysbus_ahci_info);
 }
 
-device_init(sysbus_ahci_register);
+type_init(sysbus_ahci_register_types)
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index a119500..743ec02 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -351,8 +351,9 @@
     .class_init    = cmd646_ide_class_init,
 };
 
-static void cmd646_ide_register(void)
+static void cmd646_ide_register_types(void)
 {
     type_register_static(&cmd646_ide_info);
 }
-device_init(cmd646_ide_register);
+
+type_init(cmd646_ide_register_types)
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 5cdaa99..560ae37 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -168,8 +168,9 @@
     .class_init    = ich_ahci_class_init,
 };
 
-static void ich_ahci_register(void)
+static void ich_ahci_register_types(void)
 {
     type_register_static(&ich_ahci_info);
 }
-device_init(ich_ahci_register);
+
+type_init(ich_ahci_register_types)
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index a0bcb43..8ab2718 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -118,9 +118,9 @@
     .class_init    = isa_ide_class_initfn,
 };
 
-static void isa_ide_register_devices(void)
+static void isa_ide_register_types(void)
 {
     type_register_static(&isa_ide_info);
 }
 
-device_init(isa_ide_register_devices)
+type_init(isa_ide_register_types)
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 76cf209..1030fcc 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -299,10 +299,11 @@
     .class_init    = piix4_ide_class_init,
 };
 
-static void piix_ide_register(void)
+static void piix_ide_register_types(void)
 {
     type_register_static(&piix3_ide_info);
     type_register_static(&piix3_ide_xen_info);
     type_register_static(&piix4_ide_info);
 }
-device_init(piix_ide_register);
+
+type_init(piix_ide_register_types)
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 1640616..f6a4896 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -257,11 +257,12 @@
     .class_init = ide_device_class_init,
 };
 
-static void ide_dev_register(void)
+static void ide_register_types(void)
 {
     type_register_static(&ide_hd_info);
     type_register_static(&ide_cd_info);
     type_register_static(&ide_drive_info);
     type_register_static(&ide_device_type_info);
 }
-device_init(ide_dev_register);
+
+type_init(ide_register_types)
diff --git a/hw/ide/via.c b/hw/ide/via.c
index b4ca6f2..2886bc6 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -234,8 +234,9 @@
     .class_init    = via_ide_class_init,
 };
 
-static void via_ide_register(void)
+static void via_ide_register_types(void)
 {
     type_register_static(&via_ide_info);
 }
-device_init(via_ide_register);
+
+type_init(via_ide_register_types)
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 6dbd649..294d7da 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -553,10 +553,10 @@
     .class_init    = icp_pic_class_init,
 };
 
-static void integratorcp_register_devices(void)
+static void integratorcp_register_types(void)
 {
     type_register_static(&icp_pic_info);
     type_register_static(&core_info);
 }
 
-device_init(integratorcp_register_devices)
+type_init(integratorcp_register_types)
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 83c42d5..bb11af2 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1287,12 +1287,13 @@
     .class_init = hda_codec_device_class_init,
 };
 
-static void intel_hda_register(void)
+static void intel_hda_register_types(void)
 {
     type_register_static(&intel_hda_info);
     type_register_static(&hda_codec_device_type_info);
 }
-device_init(intel_hda_register);
+
+type_init(intel_hda_register_types)
 
 /*
  * create intel hda controller with codec attached to it,
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 79549f8..3fee011 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -251,9 +251,9 @@
     .class_init    = ioapic_class_init,
 };
 
-static void ioapic_register_devices(void)
+static void ioapic_register_types(void)
 {
     type_register_static(&ioapic_info);
 }
 
-device_init(ioapic_register_devices)
+type_init(ioapic_register_types)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
index f932700..653eef2 100644
--- a/hw/ioapic_common.c
+++ b/hw/ioapic_common.c
@@ -112,10 +112,9 @@
     .abstract = true,
 };
 
-static void register_devices(void)
+static void register_types(void)
 {
     type_register_static(&ioapic_common_type);
 }
 
-device_init(register_devices);
-
+type_init(register_types)
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index 1c60123..1632d31 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -237,12 +237,12 @@
     .class_init    = ioh3420_class_init,
 };
 
-static void ioh3420_register(void)
+static void ioh3420_register_types(void)
 {
     type_register_static(&ioh3420_info);
 }
 
-device_init(ioh3420_register);
+type_init(ioh3420_register_types)
 
 /*
  * Local variables:
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index d03f828..5a43f03 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -210,7 +210,7 @@
     .class_init = isa_device_class_init,
 };
 
-static void isabus_register_devices(void)
+static void isabus_register_types(void)
 {
     type_register_static(&isabus_bridge_info);
     type_register_static(&isa_device_type_info);
@@ -235,4 +235,4 @@
     return get_system_memory();
 }
 
-device_init(isabus_register_devices)
+type_init(isabus_register_types)
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 6f017d4..64e1cd9 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -798,9 +798,9 @@
     .class_init    = ivshmem_class_init,
 };
 
-static void ivshmem_register_devices(void)
+static void ivshmem_register_types(void)
 {
     type_register_static(&ivshmem_info);
 }
 
-device_init(ivshmem_register_devices)
+type_init(ivshmem_register_types)
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
index dfc2ab3..5bb0a4b 100644
--- a/hw/kvm/apic.c
+++ b/hw/kvm/apic.c
@@ -139,9 +139,9 @@
     .class_init = kvm_apic_class_init,
 };
 
-static void kvm_apic_register_device(void)
+static void kvm_apic_register_types(void)
 {
     type_register_static(&kvm_apic_info);
 }
 
-device_init(kvm_apic_register_device)
+type_init(kvm_apic_register_types)
diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c
index d5a5386..2157340 100644
--- a/hw/kvm/clock.c
+++ b/hw/kvm/clock.c
@@ -119,11 +119,11 @@
     }
 }
 
-static void kvmclock_register_device(void)
+static void kvmclock_register_types(void)
 {
     if (kvm_enabled()) {
     type_register_static(&kvmclock_info);
     }
 }
 
-device_init(kvmclock_register_device);
+type_init(kvmclock_register_types)
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
index 14bd427..eb98889 100644
--- a/hw/kvm/i8259.c
+++ b/hw/kvm/i8259.c
@@ -130,9 +130,9 @@
     .class_init = kvm_i8259_class_init,
 };
 
-static void kvm_pic_register(void)
+static void kvm_pic_register_types(void)
 {
     type_register_static(&kvm_i8259_info);
 }
 
-device_init(kvm_pic_register)
+type_init(kvm_pic_register_types)
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
index b316933..3ae3175 100644
--- a/hw/kvm/ioapic.c
+++ b/hw/kvm/ioapic.c
@@ -117,9 +117,9 @@
     .class_init = kvm_ioapic_class_init,
 };
 
-static void kvm_ioapic_register_device(void)
+static void kvm_ioapic_register_types(void)
 {
     type_register_static(&kvm_ioapic_info);
 }
 
-device_init(kvm_ioapic_register_device)
+type_init(kvm_ioapic_register_types)
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 78777c7..aeb0c39 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -1261,7 +1261,7 @@
     .class_init    = lan9118_class_init,
 };
 
-static void lan9118_register_devices(void)
+static void lan9118_register_types(void)
 {
     type_register_static(&lan9118_info);
 }
@@ -1282,4 +1282,4 @@
     sysbus_connect_irq(s, 0, irq);
 }
 
-device_init(lan9118_register_devices)
+type_init(lan9118_register_types)
diff --git a/hw/lance.c b/hw/lance.c
index 519720b..ce3d46c 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -162,8 +162,9 @@
     .class_init    = lance_class_init,
 };
 
-static void lance_register_devices(void)
+static void lance_register_types(void)
 {
     type_register_static(&lance_info);
 }
-device_init(lance_register_devices)
+
+type_init(lance_register_types)
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
index 38dd282..f07ed39 100644
--- a/hw/lm32_juart.c
+++ b/hw/lm32_juart.c
@@ -151,9 +151,9 @@
     .class_init    = lm32_juart_class_init,
 };
 
-static void lm32_juart_register(void)
+static void lm32_juart_register_types(void)
 {
     type_register_static(&lm32_juart_info);
 }
 
-device_init(lm32_juart_register)
+type_init(lm32_juart_register_types)
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
index 7be6d0d..32f65db 100644
--- a/hw/lm32_pic.c
+++ b/hw/lm32_pic.c
@@ -191,9 +191,9 @@
     .class_init    = lm32_pic_class_init,
 };
 
-static void lm32_pic_register(void)
+static void lm32_pic_register_types(void)
 {
     type_register_static(&lm32_pic_info);
 }
 
-device_init(lm32_pic_register)
+type_init(lm32_pic_register_types)
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
index ba6f4ac..bbe03c4 100644
--- a/hw/lm32_sys.c
+++ b/hw/lm32_sys.c
@@ -164,9 +164,9 @@
     .class_init    = lm32_sys_class_init,
 };
 
-static void lm32_sys_register(void)
+static void lm32_sys_register_types(void)
 {
     type_register_static(&lm32_sys_info);
 }
 
-device_init(lm32_sys_register)
+type_init(lm32_sys_register_types)
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
index 3cb4e0a..e9450a0 100644
--- a/hw/lm32_timer.c
+++ b/hw/lm32_timer.c
@@ -222,9 +222,9 @@
     .class_init    = lm32_timer_class_init,
 };
 
-static void lm32_timer_register(void)
+static void lm32_timer_register_types(void)
 {
     type_register_static(&lm32_timer_info);
 }
 
-device_init(lm32_timer_register)
+type_init(lm32_timer_register_types)
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
index 630ccb7..57066e2 100644
--- a/hw/lm32_uart.c
+++ b/hw/lm32_uart.c
@@ -288,9 +288,9 @@
     .class_init    = lm32_uart_class_init,
 };
 
-static void lm32_uart_register(void)
+static void lm32_uart_register_types(void)
 {
     type_register_static(&lm32_uart_info);
 }
 
-device_init(lm32_uart_register)
+type_init(lm32_uart_register_types)
diff --git a/hw/lm832x.c b/hw/lm832x.c
index 895d306..8e09f9b 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -513,9 +513,9 @@
     .class_init    = lm8323_class_init,
 };
 
-static void lm832x_register_devices(void)
+static void lm832x_register_types(void)
 {
     type_register_static(&lm8323_info);
 }
 
-device_init(lm832x_register_devices)
+type_init(lm832x_register_types)
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 9a7ffe3..0acd1d0 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2142,9 +2142,9 @@
     .class_init    = lsi_class_init,
 };
 
-static void lsi53c895a_register_devices(void)
+static void lsi53c895a_register_types(void)
 {
     type_register_static(&lsi_info);
 }
 
-device_init(lsi53c895a_register_devices);
+type_init(lsi53c895a_register_types)
diff --git a/hw/m48t59.c b/hw/m48t59.c
index c35867d..60bbb00 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -768,10 +768,10 @@
     .class_init    = m48t59_class_init,
 };
 
-static void m48t59_register_devices(void)
+static void m48t59_register_types(void)
 {
     type_register_static(&m48t59_info);
     type_register_static(&m48t59_isa_info);
 }
 
-device_init(m48t59_register_devices)
+type_init(m48t59_register_types)
diff --git a/hw/macio.c b/hw/macio.c
index 3d648e9..eb15b89 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -97,12 +97,12 @@
     .class_init    = macio_class_init,
 };
 
-static void macio_register(void)
+static void macio_register_types(void)
 {
     type_register_static(&macio_info);
 }
 
-device_init(macio_register);
+type_init(macio_register_types)
 
 void macio_init (PCIBus *bus, int device_id, int is_oldworld,
                  MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index b628f17..f6f1937 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -295,9 +295,9 @@
     .class_init    = mv88w8618_audio_class_init,
 };
 
-static void mv88w8618_register_devices(void)
+static void mv88w8618_register_types(void)
 {
     type_register_static(&mv88w8618_audio_info);
 }
 
-device_init(mv88w8618_register_devices)
+type_init(mv88w8618_register_types)
diff --git a/hw/max111x.c b/hw/max111x.c
index 9d61aa9..706d89f 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -183,10 +183,10 @@
     .class_init    = max1111_class_init,
 };
 
-static void max111x_register_devices(void)
+static void max111x_register_types(void)
 {
     type_register_static(&max1110_info);
     type_register_static(&max1111_info);
 }
 
-device_init(max111x_register_devices)
+type_init(max111x_register_types)
diff --git a/hw/max7310.c b/hw/max7310.c
index 3a6bb96..1ed18ba 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -205,9 +205,9 @@
     .class_init    = max7310_class_init,
 };
 
-static void max7310_register_devices(void)
+static void max7310_register_types(void)
 {
     type_register_static(&max7310_info);
 }
 
-device_init(max7310_register_devices)
+type_init(max7310_register_types)
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 4a43225..6c1ad38 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -733,8 +733,9 @@
     .class_init    = rtc_class_initfn,
 };
 
-static void mc146818rtc_register(void)
+static void mc146818rtc_register_types(void)
 {
     type_register_static(&mc146818rtc_info);
 }
-device_init(mc146818rtc_register)
+
+type_init(mc146818rtc_register_types)
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
index 0881643..4414f39 100644
--- a/hw/milkymist-ac97.c
+++ b/hw/milkymist-ac97.c
@@ -336,9 +336,9 @@
     .class_init    = milkymist_ac97_class_init,
 };
 
-static void milkymist_ac97_register(void)
+static void milkymist_ac97_register_types(void)
 {
     type_register_static(&milkymist_ac97_info);
 }
 
-device_init(milkymist_ac97_register)
+type_init(milkymist_ac97_register_types)
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
index b5122af..2da0293 100644
--- a/hw/milkymist-hpdmc.c
+++ b/hw/milkymist-hpdmc.c
@@ -162,9 +162,9 @@
     .class_init    = milkymist_hpdmc_class_init,
 };
 
-static void milkymist_hpdmc_register(void)
+static void milkymist_hpdmc_register_types(void)
 {
     type_register_static(&milkymist_hpdmc_info);
 }
 
-device_init(milkymist_hpdmc_register)
+type_init(milkymist_hpdmc_register_types)
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
index 3c1c68a..3515c3c 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -295,9 +295,9 @@
     .class_init    = milkymist_memcard_class_init,
 };
 
-static void milkymist_memcard_register(void)
+static void milkymist_memcard_register_types(void)
 {
     type_register_static(&milkymist_memcard_info);
 }
 
-device_init(milkymist_memcard_register)
+type_init(milkymist_memcard_register_types)
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index b9b553f..70bf336 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -542,9 +542,9 @@
     .class_init    = milkymist_minimac2_class_init,
 };
 
-static void milkymist_minimac2_register(void)
+static void milkymist_minimac2_register_types(void)
 {
     type_register_static(&milkymist_minimac2_info);
 }
 
-device_init(milkymist_minimac2_register)
+type_init(milkymist_minimac2_register_types)
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
index 1b73a46..0f9ff4a 100644
--- a/hw/milkymist-pfpu.c
+++ b/hw/milkymist-pfpu.c
@@ -536,9 +536,9 @@
     .class_init    = milkymist_pfpu_class_init,
 };
 
-static void milkymist_pfpu_register(void)
+static void milkymist_pfpu_register_types(void)
 {
     type_register_static(&milkymist_pfpu_info);
 }
 
-device_init(milkymist_pfpu_register)
+type_init(milkymist_pfpu_register_types)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 5d496cb..ecc2be9 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -323,9 +323,9 @@
     .class_init    = milkymist_softusb_class_init,
 };
 
-static void milkymist_softusb_register(void)
+static void milkymist_softusb_register_types(void)
 {
     type_register_static(&milkymist_softusb_info);
 }
 
-device_init(milkymist_softusb_register)
+type_init(milkymist_softusb_register_types)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index 18171f6..a88548e 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -322,9 +322,9 @@
     .class_init    = milkymist_sysctl_class_init,
 };
 
-static void milkymist_sysctl_register(void)
+static void milkymist_sysctl_register_types(void)
 {
     type_register_static(&milkymist_sysctl_info);
 }
 
-device_init(milkymist_sysctl_register)
+type_init(milkymist_sysctl_register_types)
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
index 474eae0..210ceed 100644
--- a/hw/milkymist-tmu2.c
+++ b/hw/milkymist-tmu2.c
@@ -482,9 +482,9 @@
     .class_init    = milkymist_tmu2_class_init,
 };
 
-static void milkymist_tmu2_register(void)
+static void milkymist_tmu2_register_types(void)
 {
     type_register_static(&milkymist_tmu2_info);
 }
 
-device_init(milkymist_tmu2_register)
+type_init(milkymist_tmu2_register_types)
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index f9a229c..291fe3c 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -235,9 +235,9 @@
     .class_init    = milkymist_uart_class_init,
 };
 
-static void milkymist_uart_register(void)
+static void milkymist_uart_register_types(void)
 {
     type_register_static(&milkymist_uart_info);
 }
 
-device_init(milkymist_uart_register)
+type_init(milkymist_uart_register_types)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
index 92ad02f..69afd72 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -323,9 +323,9 @@
     .class_init    = milkymist_vgafb_class_init,
 };
 
-static void milkymist_vgafb_register(void)
+static void milkymist_vgafb_register_types(void)
 {
     type_register_static(&milkymist_vgafb_info);
 }
 
-device_init(milkymist_vgafb_register)
+type_init(milkymist_vgafb_register_types)
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index d232630..ffecefd 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -1029,7 +1029,7 @@
     .is_default = 1,
 };
 
-static void mips_malta_device_init(void)
+static void mips_malta_register_types(void)
 {
     type_register_static(&mips_malta_device);
 }
@@ -1039,5 +1039,5 @@
     qemu_register_machine(&mips_malta_machine);
 }
 
-device_init(mips_malta_device_init);
+type_init(mips_malta_register_types)
 machine_init(mips_malta_machine_init);
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index a0e6c9f..50d92f8 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -276,9 +276,9 @@
     .class_init    = mipsnet_class_init,
 };
 
-static void mipsnet_register_devices(void)
+static void mipsnet_register_types(void)
 {
     type_register_static(&mipsnet_info);
 }
 
-device_init(mipsnet_register_devices)
+type_init(mipsnet_register_types)
diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
index 28cd60d..aeb2de7 100644
--- a/hw/mpc8544_guts.c
+++ b/hw/mpc8544_guts.c
@@ -135,8 +135,9 @@
     .class_init    = mpc8544_guts_class_init,
 };
 
-static void mpc8544_guts_register(void)
+static void mpc8544_guts_register_types(void)
 {
     type_register_static(&mpc8544_guts_info);
 }
-device_init(mpc8544_guts_register);
+
+type_init(mpc8544_guts_register_types)
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 1729db0..024192d 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -255,8 +255,9 @@
     .class_init    = mst_fpga_class_init,
 };
 
-static void mst_fpga_register(void)
+static void mst_fpga_register_types(void)
 {
     type_register_static(&mst_fpga_info);
 }
-device_init(mst_fpga_register);
+
+type_init(mst_fpga_register_types)
diff --git a/hw/musicpal.c b/hw/musicpal.c
index ac90924..187a1ae 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -1681,7 +1681,7 @@
     .class_init    = mv88w8618_wlan_class_init,
 };
 
-static void musicpal_register_devices(void)
+static void musicpal_register_types(void)
 {
     type_register_static(&mv88w8618_pic_info);
     type_register_static(&mv88w8618_pit_info);
@@ -1693,4 +1693,4 @@
     type_register_static(&musicpal_key_info);
 }
 
-device_init(musicpal_register_devices)
+type_init(musicpal_register_types)
diff --git a/hw/nand.c b/hw/nand.c
index 5d947b1..e9501ae 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -442,7 +442,7 @@
     .class_init    = nand_class_init,
 };
 
-static void nand_create_device(void)
+static void nand_register_types(void)
 {
     type_register_static(&nand_info);
 }
@@ -635,7 +635,7 @@
     return dev;
 }
 
-device_init(nand_create_device)
+type_init(nand_register_types)
 
 #else
 
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 1352282..a4a783a 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -104,9 +104,9 @@
     .class_init    = isa_ne2000_class_initfn,
 };
 
-static void ne2000_isa_register_devices(void)
+static void ne2000_isa_register_types(void)
 {
     type_register_static(&ne2000_isa_info);
 }
 
-device_init(ne2000_isa_register_devices)
+type_init(ne2000_isa_register_types)
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 080811e..bb84fd1 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -812,9 +812,9 @@
     .class_init    = ne2000_class_init,
 };
 
-static void ne2000_register_devices(void)
+static void ne2000_register_types(void)
 {
     type_register_static(&ne2000_info);
 }
 
-device_init(ne2000_register_devices)
+type_init(ne2000_register_types)
diff --git a/hw/nseries.c b/hw/nseries.c
index d429dbd..c5b3184 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -204,6 +204,8 @@
                           qdev_get_gpio_in(s->cpu->ih[0],
                                            OMAP_INT_24XX_SYS_NIRQ));
 
+    qemu_system_powerdown = qdev_get_gpio_in(dev, 3);
+
     /* Attach a TMP105 PM chip (A0 wired to ground) */
     dev = i2c_create_slave(s->i2c, "tmp105", N8X0_TMP105_ADDR);
     qdev_connect_gpio_out(dev, 0, tmp_irq);
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 9a9a8e1..201ff77 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -783,10 +783,10 @@
     .class_init    = omap2_gpio_class_init,
 };
 
-static void omap_gpio_register_device(void)
+static void omap_gpio_register_types(void)
 {
     type_register_static(&omap_gpio_info);
     type_register_static(&omap2_gpio_info);
 }
 
-device_init(omap_gpio_register_device)
+type_init(omap_gpio_register_types)
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index 5aa98a8..5076e07 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -640,10 +640,10 @@
     .class_init    = omap2_intc_class_init,
 };
 
-static void omap_intc_register_device(void)
+static void omap_intc_register_types(void)
 {
     type_register_static(&omap_intc_info);
     type_register_static(&omap2_intc_info);
 }
 
-device_init(omap_intc_register_device)
+type_init(omap_intc_register_types)
diff --git a/hw/onenand.c b/hw/onenand.c
index 8744b04..db6af68 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -828,7 +828,7 @@
     .class_init    = onenand_class_init,
 };
 
-static void onenand_register_device(void)
+static void onenand_register_types(void)
 {
     type_register_static(&onenand_info);
 }
@@ -838,4 +838,4 @@
     return FROM_SYSBUS(OneNANDState, sysbus_from_qdev(onenand_device))->otp;
 }
 
-device_init(onenand_register_device)
+type_init(onenand_register_types)
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index 09f2757..9b036cb 100644
--- a/hw/opencores_eth.c
+++ b/hw/opencores_eth.c
@@ -750,9 +750,9 @@
     .class_init    = open_eth_class_init,
 };
 
-static void open_eth_register_devices(void)
+static void open_eth_register_types(void)
 {
     type_register_static(&open_eth_info);
 }
 
-device_init(open_eth_register_devices)
+type_init(open_eth_register_types)
diff --git a/hw/parallel.c b/hw/parallel.c
index 484d727..219f384 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -606,9 +606,9 @@
     .class_init    = parallel_isa_class_initfn,
 };
 
-static void parallel_register_devices(void)
+static void parallel_register_types(void)
 {
     type_register_static(&parallel_isa_info);
 }
 
-device_init(parallel_register_devices)
+type_init(parallel_register_types)
diff --git a/hw/pc.c b/hw/pc.c
index 7f3aa65..ab94d72 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -514,11 +514,12 @@
     .class_init    = port92_class_initfn,
 };
 
-static void port92_register(void)
+static void port92_register_types(void)
 {
     type_register_static(&port92_info);
 }
-device_init(port92_register)
+
+type_init(port92_register_types)
 
 static void handle_a20_line_change(void *opaque, int irq, int level)
 {
@@ -889,7 +890,7 @@
     DeviceState *dev;
     static int apic_mapped;
 
-    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (kvm_irqchip_in_kernel()) {
         dev = qdev_create(NULL, "kvm-apic");
     } else {
         dev = qdev_create(NULL, "apic");
@@ -908,7 +909,7 @@
     }
 
     /* KVM does not support MSI yet. */
-    if (!kvm_enabled() || !kvm_irqchip_in_kernel()) {
+    if (!kvm_irqchip_in_kernel()) {
         msi_supported = true;
     }
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index c06f1b5..17f8d5d 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -104,7 +104,7 @@
     SysBusDevice *d;
     unsigned int i;
 
-    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (kvm_irqchip_in_kernel()) {
         dev = qdev_create(NULL, "kvm-ioapic");
     } else {
         dev = qdev_create(NULL, "ioapic");
@@ -183,7 +183,7 @@
     }
 
     gsi_state = g_malloc0(sizeof(*gsi_state));
-    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (kvm_irqchip_in_kernel()) {
         kvm_piix3_setup_irq_routing(pci_enabled);
         gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
                                  GSI_NUM_PINS);
@@ -209,7 +209,7 @@
     }
     isa_bus_irqs(isa_bus, gsi);
 
-    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (kvm_irqchip_in_kernel()) {
         i8259 = kvm_i8259_init(isa_bus);
     } else if (xen_enabled()) {
         i8259 = xen_interrupt_controller_init();
diff --git a/hw/pci.c b/hw/pci.c
index 5f4f80e..678a8c1 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -2003,9 +2003,9 @@
     .class_init = pci_device_class_init,
 };
 
-static void pci_register_devices(void)
+static void pci_register_types(void)
 {
     type_register_static(&pci_device_type_info);
 }
 
-device_init(pci_register_devices);
+type_init(pci_register_types)
diff --git a/hw/pckbd.c b/hw/pckbd.c
index b4c53be..69857ba 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -513,8 +513,9 @@
     .class_init    = i8042_class_initfn,
 };
 
-static void i8042_register(void)
+static void i8042_register_types(void)
 {
     type_register_static(&i8042_info);
 }
-device_init(i8042_register)
+
+type_init(i8042_register_types)
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 439f32c..3682609 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -376,9 +376,9 @@
     .class_init    = pcnet_class_init,
 };
 
-static void pci_pcnet_register_devices(void)
+static void pci_pcnet_register_types(void)
 {
     type_register_static(&pcnet_info);
 }
 
-device_init(pci_pcnet_register_devices)
+type_init(pci_pcnet_register_types)
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index a9e88b9..2ca0fd4 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -102,6 +102,7 @@
 static void pflash_register_memory(pflash_t *pfl, int rom_mode)
 {
     memory_region_rom_device_set_readable(&pfl->orig_mem, rom_mode);
+    pfl->rom_mode = rom_mode;
 }
 
 static void pflash_timer (void *opaque)
diff --git a/hw/piix4.c b/hw/piix4.c
index 4e7a237..ce4eb0d 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -124,8 +124,9 @@
     .class_init    = piix4_class_init,
 };
 
-static void piix4_register(void)
+static void piix4_register_types(void)
 {
     type_register_static(&piix4_info);
 }
-device_init(piix4_register);
+
+type_init(piix4_register_types)
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 1906427..e0268fe 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -589,11 +589,12 @@
     .class_init    = i440fx_pcihost_class_init,
 };
 
-static void i440fx_register(void)
+static void i440fx_register_types(void)
 {
     type_register_static(&i440fx_info);
     type_register_static(&piix3_info);
     type_register_static(&piix3_xen_info);
     type_register_static(&i440fx_pcihost_info);
 }
-device_init(i440fx_register);
+
+type_init(i440fx_register_types)
diff --git a/hw/pl011.c b/hw/pl011.c
index 752cbf9..8a5a8f5 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -316,10 +316,10 @@
     .class_init    = pl011_luminary_class_init,
 };
 
-static void pl011_register_devices(void)
+static void pl011_register_types(void)
 {
     type_register_static(&pl011_arm_info);
     type_register_static(&pl011_luminary_info);
 }
 
-device_init(pl011_register_devices)
+type_init(pl011_register_types)
diff --git a/hw/pl022.c b/hw/pl022.c
index 30bd344..03bf63c 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -299,9 +299,9 @@
     .class_init    = pl022_class_init,
 };
 
-static void pl022_register_devices(void)
+static void pl022_register_types(void)
 {
     type_register_static(&pl022_info);
 }
 
-device_init(pl022_register_devices)
+type_init(pl022_register_types)
diff --git a/hw/pl031.c b/hw/pl031.c
index 8416a60..05b5b11 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -230,9 +230,9 @@
     .class_init    = pl031_class_init,
 };
 
-static void pl031_register_devices(void)
+static void pl031_register_types(void)
 {
     type_register_static(&pl031_info);
 }
 
-device_init(pl031_register_devices)
+type_init(pl031_register_types)
diff --git a/hw/pl041.c b/hw/pl041.c
index 6d99c9c..b6723be 100644
--- a/hw/pl041.c
+++ b/hw/pl041.c
@@ -638,9 +638,9 @@
     .class_init    = pl041_device_class_init,
 };
 
-static void pl041_register_device(void)
+static void pl041_register_types(void)
 {
     type_register_static(&pl041_device_info);
 }
 
-device_init(pl041_register_device)
+type_init(pl041_register_types)
diff --git a/hw/pl050.c b/hw/pl050.c
index b0094ac..b13924a 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -189,10 +189,10 @@
     .class_init    = pl050_mouse_class_init,
 };
 
-static void pl050_register_devices(void)
+static void pl050_register_types(void)
 {
     type_register_static(&pl050_kbd_info);
     type_register_static(&pl050_mouse_info);
 }
 
-device_init(pl050_register_devices)
+type_init(pl050_register_types)
diff --git a/hw/pl061.c b/hw/pl061.c
index 3136c99..2aac7e8 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -325,10 +325,10 @@
     .class_init    = pl061_luminary_class_init,
 };
 
-static void pl061_register_devices(void)
+static void pl061_register_types(void)
 {
     type_register_static(&pl061_info);
     type_register_static(&pl061_luminary_info);
 }
 
-device_init(pl061_register_devices)
+type_init(pl061_register_types)
diff --git a/hw/pl080.c b/hw/pl080.c
index 4405d18..b3cf651 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -409,10 +409,10 @@
 
 /* The PL080 and PL081 are the same except for the number of channels
    they implement (8 and 2 respectively).  */
-static void pl080_register_devices(void)
+static void pl080_register_types(void)
 {
     type_register_static(&pl080_info);
     type_register_static(&pl081_info);
 }
 
-device_init(pl080_register_devices)
+type_init(pl080_register_types)
diff --git a/hw/pl110.c b/hw/pl110.c
index 86e95a3..f94608c 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -520,11 +520,11 @@
     .class_init    = pl111_class_init,
 };
 
-static void pl110_register_devices(void)
+static void pl110_register_types(void)
 {
     type_register_static(&pl110_info);
     type_register_static(&pl110_versatile_info);
     type_register_static(&pl111_info);
 }
 
-device_init(pl110_register_devices)
+type_init(pl110_register_types)
diff --git a/hw/pl181.c b/hw/pl181.c
index ae636e2..7d91fbb 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -505,9 +505,9 @@
     .class_init    = pl181_class_init,
 };
 
-static void pl181_register_devices(void)
+static void pl181_register_types(void)
 {
     type_register_static(&pl181_info);
 }
 
-device_init(pl181_register_devices)
+type_init(pl181_register_types)
diff --git a/hw/pl190.c b/hw/pl190.c
index 956ab21..cb50afb 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -273,9 +273,9 @@
     .class_init    = pl190_class_init,
 };
 
-static void pl190_register_devices(void)
+static void pl190_register_types(void)
 {
     type_register_static(&pl190_info);
 }
 
-device_init(pl190_register_devices)
+type_init(pl190_register_types)
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index d11f120..203c3cd 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -400,9 +400,10 @@
     .class_init    = ppc4xx_pcihost_class_init,
 };
 
-static void ppc4xx_pci_register(void)
+static void ppc4xx_pci_register_types(void)
 {
     type_register_static(&ppc4xx_pcihost_info);
     type_register_static(&ppc4xx_host_bridge_info);
 }
-device_init(ppc4xx_pci_register);
+
+type_init(ppc4xx_pci_register_types)
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index d5bce71..0f60b24 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -373,9 +373,10 @@
     .class_init    = e500_pcihost_class_init,
 };
 
-static void e500_pci_register(void)
+static void e500_pci_register_types(void)
 {
     type_register_static(&e500_pcihost_info);
     type_register_static(&e500_host_bridge_info);
 }
-device_init(e500_pci_register);
+
+type_init(e500_pci_register_types)
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
index 9d648ec..6b8a189 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -217,8 +217,9 @@
     .class_init    = ppce500_spin_class_init,
 };
 
-static void ppce500_spin_register(void)
+static void ppce500_spin_register_types(void)
 {
     type_register_static(&ppce500_spin_info);
 }
-device_init(ppce500_spin_register);
+
+type_init(ppce500_spin_register_types)
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 40b8bb0..8b29da9 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -173,10 +173,10 @@
     .class_init = raven_pcihost_class_init,
 };
 
-static void raven_register_devices(void)
+static void raven_register_types(void)
 {
     type_register_static(&raven_pcihost_info);
     type_register_static(&raven_info);
 }
 
-device_init(raven_register_devices)
+type_init(raven_register_types)
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 244c614..1ab2701 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -2330,7 +2330,7 @@
     .class_init    = pxa2xx_ssp_class_init,
 };
 
-static void pxa2xx_register_devices(void)
+static void pxa2xx_register_types(void)
 {
     type_register_static(&pxa2xx_i2c_slave_info);
     type_register_static(&pxa2xx_ssp_info);
@@ -2338,4 +2338,4 @@
     type_register_static(&pxa2xx_rtc_sysbus_info);
 }
 
-device_init(pxa2xx_register_devices)
+type_init(pxa2xx_register_types)
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index 2d61565..8ced0dd 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -566,8 +566,9 @@
     .class_init    = pxa2xx_dma_class_init,
 };
 
-static void pxa2xx_dma_register(void)
+static void pxa2xx_dma_register_types(void)
 {
     type_register_static(&pxa2xx_dma_info);
 }
-device_init(pxa2xx_dma_register);
+
+type_init(pxa2xx_dma_register_types)
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index 67fd17c..d5f5716 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -340,8 +340,9 @@
     .class_init    = pxa2xx_gpio_class_init,
 };
 
-static void pxa2xx_gpio_register(void)
+static void pxa2xx_gpio_register_types(void)
 {
     type_register_static(&pxa2xx_gpio_info);
 }
-device_init(pxa2xx_gpio_register);
+
+type_init(pxa2xx_gpio_register_types)
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 4e9f7b4..9495226 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -308,9 +308,12 @@
         } else
             descptr = s->dma_ch[i].descriptor;
 
-        if (!(descptr >= PXA2XX_SDRAM_BASE && descptr +
-                    sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size))
+        if (!((descptr >= PXA2XX_SDRAM_BASE && descptr +
+                 sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size) ||
+                (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <=
+                 PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
             continue;
+        }
 
         cpu_physical_memory_read(descptr, (void *)&desc, sizeof(desc));
         s->dma_ch[i].descriptor = tswap32(desc.fdaddr);
@@ -830,8 +833,10 @@
                 continue;
             }
             fbptr = s->dma_ch[ch].source;
-            if (!(fbptr >= PXA2XX_SDRAM_BASE &&
-                    fbptr <= PXA2XX_SDRAM_BASE + ram_size)) {
+            if (!((fbptr >= PXA2XX_SDRAM_BASE &&
+                     fbptr <= PXA2XX_SDRAM_BASE + ram_size) ||
+                    (fbptr >= PXA2XX_INTERNAL_BASE &&
+                     fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
                 pxa2xx_dma_ber_set(s, ch);
                 continue;
             }
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
index ca85743..6b2bdb0 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -313,8 +313,9 @@
     .class_init    = pxa2xx_pic_class_init,
 };
 
-static void pxa2xx_pic_register(void)
+static void pxa2xx_pic_register_types(void)
 {
     type_register_static(&pxa2xx_pic_info);
 }
-device_init(pxa2xx_pic_register);
+
+type_init(pxa2xx_pic_register_types)
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
index 9080075..77b033b 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -527,9 +527,10 @@
     .class_init    = pxa27x_timer_dev_class_init,
 };
 
-static void pxa2xx_timer_register(void)
+static void pxa2xx_timer_register_types(void)
 {
     type_register_static(&pxa25x_timer_dev_info);
     type_register_static(&pxa27x_timer_dev_info);
-};
-device_init(pxa2xx_timer_register);
+}
+
+type_init(pxa2xx_timer_register_types)
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 49f13ca..a310cc7 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -457,6 +457,16 @@
     id = qemu_opts_id(opts);
     if (id) {
         qdev->id = id;
+    }
+    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
+        qdev_free(qdev);
+        return NULL;
+    }
+    if (qdev_init(qdev) < 0) {
+        qerror_report(QERR_DEVICE_INIT_FAILED, driver);
+        return NULL;
+    }
+    if (qdev->id) {
         object_property_add_child(qdev_get_peripheral(), qdev->id,
                                   OBJECT(qdev), NULL);
     } else {
@@ -466,14 +476,6 @@
                                   OBJECT(qdev), NULL);
         g_free(name);
     }        
-    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
-        qdev_free(qdev);
-        return NULL;
-    }
-    if (qdev_init(qdev) < 0) {
-        qerror_report(QERR_DEVICE_INIT_FAILED, driver);
-        return NULL;
-    }
     qdev->opts = opts;
     return qdev;
 }
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index b6d6fcf..7b74dd5 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -613,7 +613,7 @@
     }
     if (!*str) {
         g_free(str);
-        error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+        *ptr = NULL;
         return;
     }
     ret = parse(dev, str, ptr);
@@ -1072,55 +1072,56 @@
 {
     Error *errp = NULL;
     object_property_set_bool(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
 {
     Error *errp = NULL;
     object_property_set_str(OBJECT(dev), value, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
 {
     Error *errp = NULL;
-    object_property_set_str(OBJECT(dev), bdrv_get_device_name(value),
+    const char *bdrv_name = value ? bdrv_get_device_name(value) : "";
+    object_property_set_str(OBJECT(dev), bdrv_name,
                             name, &errp);
     if (errp) {
         qerror_report_err(errp);
@@ -1139,24 +1140,26 @@
 void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value)
 {
     Error *errp = NULL;
-    assert(value->label);
-    object_property_set_str(OBJECT(dev), value->label, name, &errp);
-    assert(!errp);
+    assert(!value || value->label);
+    object_property_set_str(OBJECT(dev),
+                            value ? value->label : "", name, &errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value)
 {
     Error *errp = NULL;
-    assert(value->name);
-    object_property_set_str(OBJECT(dev), value->name, name, &errp);
-    assert(!errp);
+    assert(!value || value->name);
+    object_property_set_str(OBJECT(dev),
+                            value ? value->name : "", name, &errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value)
 {
     Error *errp = NULL;
     object_property_set_int(OBJECT(dev), value ? value->id : -1, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
@@ -1167,7 +1170,7 @@
              value[0], value[1], value[2], value[3], value[4], value[5]);
 
     object_property_set_str(OBJECT(dev), str, name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
@@ -1178,7 +1181,7 @@
     prop = qdev_prop_find(dev, name);
     object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
                             name, &errp);
-    assert(!errp);
+    assert_no_error(errp);
 }
 
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
@@ -1210,7 +1213,7 @@
         } else if (props->qtype == QTYPE_QINT) {
             object_property_set_int(obj, props->defval, props->name, &errp);
         }
-        assert(!errp);
+        assert_no_error(errp);
     }
 }
 
diff --git a/hw/qdev.c b/hw/qdev.c
index 8a413ef..f0eb3a7 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -665,9 +665,9 @@
     .class_size = sizeof(DeviceClass),
 };
 
-static void init_qdev(void)
+static void qdev_register_types(void)
 {
     type_register_static(&device_type_info);
 }
 
-device_init(init_qdev);
+type_init(qdev_register_types)
diff --git a/hw/qxl.c b/hw/qxl.c
index bc03c1d..ac69125 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1870,10 +1870,10 @@
     .class_init    = qxl_secondary_class_init,
 };
 
-static void qxl_register(void)
+static void qxl_register_types(void)
 {
     type_register_static(&qxl_primary_info);
     type_register_static(&qxl_secondary_info);
 }
 
-device_init(qxl_register);
+type_init(qxl_register_types)
diff --git a/hw/realview.c b/hw/realview.c
index 8b0b03d..bcf982f 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -96,7 +96,7 @@
     .class_init    = realview_i2c_class_init,
 };
 
-static void realview_register_devices(void)
+static void realview_register_types(void)
 {
     type_register_static(&realview_i2c_info);
 }
@@ -491,4 +491,4 @@
 }
 
 machine_init(realview_machine_init);
-device_init(realview_register_devices)
+type_init(realview_register_types)
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 4121502..071ef13 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -60,9 +60,9 @@
     .class_init    = realview_gic_class_init,
 };
 
-static void realview_gic_register_devices(void)
+static void realview_gic_register_types(void)
 {
     type_register_static(&realview_gic_info);
 }
 
-device_init(realview_gic_register_devices)
+type_init(realview_gic_register_types)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 1668390..05b8e1e 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3523,9 +3523,9 @@
     .class_init    = rtl8139_class_init,
 };
 
-static void rtl8139_register_devices(void)
+static void rtl8139_register_types(void)
 {
     type_register_static(&rtl8139_info);
 }
 
-device_init(rtl8139_register_devices)
+type_init(rtl8139_register_types)
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 49140f8..9d48056 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -433,15 +433,6 @@
     .abstract = true,
 };
 
-static void s390_virtio_register(void)
-{
-    type_register_static(&virtio_s390_device_info);
-    type_register_static(&s390_virtio_serial);
-    type_register_static(&s390_virtio_blk);
-    type_register_static(&s390_virtio_net);
-}
-device_init(s390_virtio_register);
-
 
 /***************** S390 Virtio Bus Bridge Device *******************/
 /* Only required to have the virtio bus as child in the system bus */
@@ -468,9 +459,13 @@
     .class_init    = s390_virtio_bridge_class_init,
 };
 
-static void s390_virtio_register_devices(void)
+static void s390_virtio_register_types(void)
 {
+    type_register_static(&virtio_s390_device_info);
+    type_register_static(&s390_virtio_serial);
+    type_register_static(&s390_virtio_blk);
+    type_register_static(&s390_virtio_net);
     type_register_static(&s390_virtio_bridge_info);
 }
 
-device_init(s390_virtio_register_devices)
+type_init(s390_virtio_register_types)
diff --git a/hw/sb16.c b/hw/sb16.c
index db8929b..c81455d 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1417,8 +1417,9 @@
     .class_init    = sb16_class_initfn,
 };
 
-static void sb16_register (void)
+static void sb16_register_types (void)
 {
     type_register_static (&sb16_info);
 }
-device_init (sb16_register)
+
+type_init (sb16_register_types)
diff --git a/hw/sbi.c b/hw/sbi.c
index 847a4dd..52982a9 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -148,9 +148,9 @@
     .class_init    = sbi_class_init,
 };
 
-static void sbi_register_devices(void)
+static void sbi_register_types(void)
 {
     type_register_static(&sbi_info);
 }
 
-device_init(sbi_register_devices)
+type_init(sbi_register_types)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 0ee50a8..b3e97ce 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1431,9 +1431,9 @@
     .class_init = scsi_device_class_init,
 };
 
-static void scsi_register_devices(void)
+static void scsi_register_types(void)
 {
     type_register_static(&scsi_device_type_info);
 }
 
-device_init(scsi_register_devices);
+type_init(scsi_register_types)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 399e51e..c12e3a6 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1823,7 +1823,7 @@
     .class_init    = scsi_disk_class_initfn,
 };
 
-static void scsi_disk_register_devices(void)
+static void scsi_disk_register_types(void)
 {
     type_register_static(&scsi_hd_info);
     type_register_static(&scsi_cd_info);
@@ -1832,4 +1832,5 @@
 #endif
     type_register_static(&scsi_disk_info);
 }
-device_init(scsi_disk_register_devices)
+
+type_init(scsi_disk_register_types)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 4859212..86014aa 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -483,10 +483,11 @@
     .class_init    = scsi_generic_class_initfn,
 };
 
-static void scsi_generic_register_devices(void)
+static void scsi_generic_register_types(void)
 {
     type_register_static(&scsi_generic_info);
 }
-device_init(scsi_generic_register_devices)
+
+type_init(scsi_generic_register_types)
 
 #endif /* __linux__ */
diff --git a/hw/serial.c b/hw/serial.c
index 82917e2..144d1b3 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -903,9 +903,9 @@
     .class_init    = serial_isa_class_initfn,
 };
 
-static void serial_register_devices(void)
+static void serial_register_types(void)
 {
     type_register_static(&serial_isa_info);
 }
 
-device_init(serial_register_devices)
+type_init(serial_register_types)
diff --git a/hw/sga.c b/hw/sga.c
index b08e3c5..a666349 100644
--- a/hw/sga.c
+++ b/hw/sga.c
@@ -55,9 +55,9 @@
     .class_init    = sga_class_initfn,
 };
 
-static void sga_register(void)
+static void sga_register_types(void)
 {
     type_register_static(&sga_info);
 }
 
-device_init(sga_register);
+type_init(sga_register_types)
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 4234d93..0cfac46 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -177,10 +177,10 @@
     .class_init    = sh_pci_device_class_init,
 };
 
-static void sh_pci_register_devices(void)
+static void sh_pci_register_types(void)
 {
     type_register_static(&sh_pci_device_info);
     type_register_static(&sh_pci_host_info);
 }
 
-device_init(sh_pci_register_devices)
+type_init(sh_pci_register_types)
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index e3701c7..7fdc3be 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -463,9 +463,9 @@
     .class_init    = slavio_intctl_class_init,
 };
 
-static void slavio_intctl_register_devices(void)
+static void slavio_intctl_register_types(void)
 {
     type_register_static(&slavio_intctl_info);
 }
 
-device_init(slavio_intctl_register_devices)
+type_init(slavio_intctl_register_types)
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 5a02518..944835e 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -499,10 +499,10 @@
     .class_init    = apc_class_init,
 };
 
-static void slavio_misc_register_devices(void)
+static void slavio_misc_register_types(void)
 {
     type_register_static(&slavio_misc_info);
     type_register_static(&apc_info);
 }
 
-device_init(slavio_misc_register_devices)
+type_init(slavio_misc_register_types)
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 3878f6f..97edebb 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -427,9 +427,9 @@
     .class_init    = slavio_timer_class_init,
 };
 
-static void slavio_timer_register_devices(void)
+static void slavio_timer_register_types(void)
 {
     type_register_static(&slavio_timer_info);
 }
 
-device_init(slavio_timer_register_devices)
+type_init(slavio_timer_register_types)
diff --git a/hw/sm501.c b/hw/sm501.c
index 94c0abf..786e076 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -1327,8 +1327,8 @@
         ram_addr_t page1 = offset + width * src_bpp - 1;
 
 	/* check dirty flags for each line */
-        update = memory_region_get_dirty(&s->local_mem_region, page0, page1,
-                                         DIRTY_MEMORY_VGA);
+        update = memory_region_get_dirty(&s->local_mem_region, page0,
+                                         page1 - page0, DIRTY_MEMORY_VGA);
 
 	/* draw line and change status */
 	if (update) {
diff --git a/hw/smbus.c b/hw/smbus.c
index 77626f3..e3cf6a2 100644
--- a/hw/smbus.c
+++ b/hw/smbus.c
@@ -327,9 +327,9 @@
     .class_init = smbus_device_class_init,
 };
 
-static void smbus_device_register_devices(void)
+static void smbus_device_register_types(void)
 {
     type_register_static(&smbus_device_type_info);
 }
 
-device_init(smbus_device_register_devices);
+type_init(smbus_device_register_types)
diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c
index 9d96cbe..11adab0 100644
--- a/hw/smbus_eeprom.c
+++ b/hw/smbus_eeprom.c
@@ -130,12 +130,12 @@
     .class_init    = smbus_eeprom_class_initfn,
 };
 
-static void smbus_eeprom_register_devices(void)
+static void smbus_eeprom_register_types(void)
 {
     type_register_static(&smbus_eeprom_info);
 }
 
-device_init(smbus_eeprom_register_devices)
+type_init(smbus_eeprom_register_types)
 
 void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
                        const uint8_t *eeprom_spd, int eeprom_spd_size)
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 1bf2901..1a5213f 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -781,7 +781,7 @@
     .class_init    = smc91c111_class_init,
 };
 
-static void smc91c111_register_devices(void)
+static void smc91c111_register_types(void)
 {
     type_register_static(&smc91c111_info);
 }
@@ -802,4 +802,4 @@
     sysbus_connect_irq(s, 0, irq);
 }
 
-device_init(smc91c111_register_devices)
+type_init(smc91c111_register_types)
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 84281be..6ac7384 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -672,7 +672,7 @@
     return H_FUNCTION;
 }
 
-static void hypercall_init(void)
+static void hypercall_register_types(void)
 {
     /* hcall-pft */
     spapr_register_hypercall(H_ENTER, h_enter);
@@ -704,4 +704,5 @@
     /* qemu/KVM-PPC specific hcalls */
     spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
 }
-device_init(hypercall_init);
+
+type_init(hypercall_register_types)
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 79b3941..77d4047 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -501,7 +501,7 @@
     .class_init    = spapr_vlan_class_init,
 };
 
-static void spapr_vlan_register(void)
+static void spapr_vlan_register_types(void)
 {
     spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
     spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
@@ -511,4 +511,5 @@
     spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
     type_register_static(&spapr_vlan_info);
 }
-device_init(spapr_vlan_register);
+
+type_init(spapr_vlan_register_types)
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index ed2e4b3..cfdd9dd 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -242,13 +242,13 @@
     .class_init    = spapr_phb_class_init,
 };
 
-static void spapr_register_devices(void)
+static void spapr_register_types(void)
 {
     type_register_static(&spapr_phb_info);
     type_register_static(&spapr_main_pci_host_info);
 }
 
-device_init(spapr_register_devices)
+type_init(spapr_register_types)
 
 static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
                               unsigned size)
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
index d1ac74c..c0723b3 100644
--- a/hw/spapr_rtas.c
+++ b/hw/spapr_rtas.c
@@ -288,7 +288,7 @@
     return 0;
 }
 
-static void register_core_rtas(void)
+static void core_rtas_register_types(void)
 {
     spapr_rtas_register("display-character", rtas_display_character);
     spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
@@ -298,4 +298,5 @@
                         rtas_query_cpu_stopped_state);
     spapr_rtas_register("start-cpu", rtas_start_cpu);
 }
-device_init(register_core_rtas);
+
+type_init(core_rtas_register_types)
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 64f0009..ea317ef 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -778,13 +778,13 @@
     .class_init = vio_spapr_device_class_init,
 };
 
-static void spapr_vio_register_devices(void)
+static void spapr_vio_register_types(void)
 {
     type_register_static(&spapr_vio_bridge_info);
     type_register_static(&spapr_vio_type_info);
 }
 
-device_init(spapr_vio_register_devices)
+type_init(spapr_vio_register_types)
 
 #ifdef CONFIG_FDT
 static int compare_reg(const void *p1, const void *p2)
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 9cfce19..ffce261 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -973,8 +973,9 @@
     .class_init    = spapr_vscsi_class_init,
 };
 
-static void spapr_vscsi_register(void)
+static void spapr_vscsi_register_types(void)
 {
     type_register_static(&spapr_vscsi_info);
 }
-device_init(spapr_vscsi_register);
+
+type_init(spapr_vscsi_register_types)
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index a954e7d..3efe242 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -212,10 +212,11 @@
     return sdev;
 }
 
-static void spapr_vty_register(void)
+static void spapr_vty_register_types(void)
 {
     spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
     spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
     type_register_static(&spapr_vty_info);
 }
-device_init(spapr_vty_register);
+
+type_init(spapr_vty_register_types)
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index f07cc6f..1dbf69e 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -307,9 +307,9 @@
     .class_init    = sparc32_dma_class_init,
 };
 
-static void sparc32_dma_register_devices(void)
+static void sparc32_dma_register_types(void)
 {
     type_register_static(&sparc32_dma_info);
 }
 
-device_init(sparc32_dma_register_devices)
+type_init(sparc32_dma_register_types)
diff --git a/hw/spitz.c b/hw/spitz.c
index 4e6540d..1d6d2b0 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -1138,7 +1138,7 @@
     .class_init    = spitz_lcdtg_class_init,
 };
 
-static void spitz_register_devices(void)
+static void spitz_register_types(void)
 {
     type_register_static(&corgi_ssp_info);
     type_register_static(&spitz_lcdtg_info);
@@ -1146,4 +1146,4 @@
     type_register_static(&sl_nand_info);
 }
 
-device_init(spitz_register_devices)
+type_init(spitz_register_types)
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index 685602a..4e1ee6e 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -313,9 +313,9 @@
     .class_init    = ssd0303_class_init,
 };
 
-static void ssd0303_register_devices(void)
+static void ssd0303_register_types(void)
 {
     type_register_static(&ssd0303_info);
 }
 
-device_init(ssd0303_register_devices)
+type_init(ssd0303_register_types)
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index 3c43738..b0b2e94 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -355,9 +355,9 @@
     .class_init    = ssd0323_class_init,
 };
 
-static void ssd03232_register_devices(void)
+static void ssd03232_register_types(void)
 {
     type_register_static(&ssd0323_info);
 }
 
-device_init(ssd03232_register_devices)
+type_init(ssd03232_register_types)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index f2e6cec..b519bdb 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -259,9 +259,9 @@
     .class_init    = ssi_sd_class_init,
 };
 
-static void ssi_sd_register_devices(void)
+static void ssi_sd_register_types(void)
 {
     type_register_static(&ssi_sd_info);
 }
 
-device_init(ssi_sd_register_devices)
+type_init(ssi_sd_register_types)
diff --git a/hw/ssi.c b/hw/ssi.c
index ead446c..8f2d9bc 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -80,9 +80,9 @@
     return ssc->transfer(slave, val);
 }
 
-static void register_ssi_slave(void)
+static void ssi_slave_register_types(void)
 {
     type_register_static(&ssi_slave_info);
 }
 
-device_init(register_ssi_slave);
+type_init(ssi_slave_register_types)
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 31a65cf..562fbbf 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1451,7 +1451,7 @@
     .class_init    = stellaris_adc_class_init,
 };
 
-static void stellaris_register_devices(void)
+static void stellaris_register_types(void)
 {
     type_register_static(&stellaris_i2c_info);
     type_register_static(&stellaris_gptm_info);
@@ -1459,4 +1459,4 @@
     type_register_static(&stellaris_ssi_bus_info);
 }
 
-device_init(stellaris_register_devices)
+type_init(stellaris_register_types)
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 9b1be8d..fbe99cb 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -441,9 +441,9 @@
     .class_init    = stellaris_enet_class_init,
 };
 
-static void stellaris_enet_register_devices(void)
+static void stellaris_enet_register_types(void)
 {
     type_register_static(&stellaris_enet_info);
 }
 
-device_init(stellaris_enet_register_devices)
+type_init(stellaris_enet_register_types)
diff --git a/hw/strongarm.c b/hw/strongarm.c
index 8d2e7eb..4d5b60f 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -1609,7 +1609,7 @@
     return s;
 }
 
-static void strongarm_register_devices(void)
+static void strongarm_register_types(void)
 {
     type_register_static(&strongarm_pic_info);
     type_register_static(&strongarm_rtc_sysbus_info);
@@ -1618,4 +1618,5 @@
     type_register_static(&strongarm_uart_info);
     type_register_static(&strongarm_ssp_info);
 }
-device_init(strongarm_register_devices)
+
+type_init(strongarm_register_types)
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
index 081d6cc..8dfa5ec 100644
--- a/hw/sun4c_intctl.c
+++ b/hw/sun4c_intctl.c
@@ -223,9 +223,9 @@
     .class_init    = sun4c_intctl_class_init,
 };
 
-static void sun4c_intctl_register_devices(void)
+static void sun4c_intctl_register_types(void)
 {
     type_register_static(&sun4c_intctl_info);
 }
 
-device_init(sun4c_intctl_register_devices)
+type_init(sun4c_intctl_register_types)
diff --git a/hw/sun4m.c b/hw/sun4m.c
index b79d14c..99fb219 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -623,13 +623,6 @@
     .class_init    = idreg_class_init,
 };
 
-static void idreg_register_devices(void)
-{
-    type_register_static(&idreg_info);
-}
-
-device_init(idreg_register_devices);
-
 typedef struct AFXState {
     SysBusDevice busdev;
     MemoryRegion mem;
@@ -672,13 +665,6 @@
     .class_init    = afx_class_init,
 };
 
-static void afx_register_devices(void)
-{
-    type_register_static(&afx_info);
-}
-
-device_init(afx_register_devices);
-
 typedef struct PROMState {
     SysBusDevice busdev;
     MemoryRegion prom;
@@ -756,13 +742,6 @@
     .class_init    = prom_class_init,
 };
 
-static void prom_register_devices(void)
-{
-    type_register_static(&prom_info);
-}
-
-device_init(prom_register_devices);
-
 typedef struct RamDevice
 {
     SysBusDevice busdev;
@@ -827,13 +806,6 @@
     .class_init    = ram_class_init,
 };
 
-static void ram_register_devices(void)
-{
-    type_register_static(&ram_info);
-}
-
-device_init(ram_register_devices);
-
 static void cpu_devinit(const char *cpu_model, unsigned int id,
                         uint64_t prom_addr, qemu_irq **cpu_irqs)
 {
@@ -1865,6 +1837,14 @@
     .use_scsi = 1,
 };
 
+static void sun4m_register_types(void)
+{
+    type_register_static(&idreg_info);
+    type_register_static(&afx_info);
+    type_register_static(&prom_info);
+    type_register_static(&ram_info);
+}
+
 static void ss2_machine_init(void)
 {
     qemu_register_machine(&ss5_machine);
@@ -1881,4 +1861,5 @@
     qemu_register_machine(&ss2_machine);
 }
 
+type_init(sun4m_register_types)
 machine_init(ss2_machine_init);
diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c
index 727532c..ebefa91 100644
--- a/hw/sun4m_iommu.c
+++ b/hw/sun4m_iommu.c
@@ -380,9 +380,9 @@
     .class_init    = iommu_class_init,
 };
 
-static void iommu_register_devices(void)
+static void iommu_register_types(void)
 {
     type_register_static(&iommu_info);
 }
 
-device_init(iommu_register_devices)
+type_init(iommu_register_types)
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 79bbd49..423108f 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -580,13 +580,6 @@
     .class_init    = ebus_class_init,
 };
 
-static void pci_ebus_register(void)
-{
-    type_register_static(&ebus_info);
-}
-
-device_init(pci_ebus_register);
-
 typedef struct PROMState {
     SysBusDevice busdev;
     MemoryRegion prom;
@@ -664,13 +657,6 @@
     .class_init    = prom_class_init,
 };
 
-static void prom_register_devices(void)
-{
-    type_register_static(&prom_info);
-}
-
-device_init(prom_register_devices);
-
 
 typedef struct RamDevice
 {
@@ -728,13 +714,6 @@
     .class_init    = ram_class_init,
 };
 
-static void ram_register_devices(void)
-{
-    type_register_static(&ram_info);
-}
-
-device_init(ram_register_devices);
-
 static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
 {
     CPUState *env;
@@ -957,6 +936,13 @@
     .max_cpus = 1, // XXX for now
 };
 
+static void sun4u_register_types(void)
+{
+    type_register_static(&ebus_info);
+    type_register_static(&prom_info);
+    type_register_static(&ram_info);
+}
+
 static void sun4u_machine_init(void)
 {
     qemu_register_machine(&sun4u_machine);
@@ -964,4 +950,5 @@
     qemu_register_machine(&niagara_machine);
 }
 
+type_init(sun4u_register_types)
 machine_init(sun4u_machine_init);
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 282060a..db4efcc 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -256,9 +256,9 @@
     .class_init = sysbus_device_class_init,
 };
 
-static void sysbus_register(void)
+static void sysbus_register_types(void)
 {
     type_register_static(&sysbus_device_type_info);
 }
 
-device_init(sysbus_register);
+type_init(sysbus_register_types)
diff --git a/hw/tcx.c b/hw/tcx.c
index ceb94c7..2b66d86 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -664,9 +664,9 @@
     .class_init    = tcx_class_init,
 };
 
-static void tcx_register_devices(void)
+static void tcx_register_types(void)
 {
     type_register_static(&tcx_info);
 }
 
-device_init(tcx_register_devices)
+type_init(tcx_register_types)
diff --git a/hw/tmp105.c b/hw/tmp105.c
index a3bdd91..8e8dbd9 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -245,9 +245,9 @@
     .class_init    = tmp105_class_init,
 };
 
-static void tmp105_register_devices(void)
+static void tmp105_register_types(void)
 {
     type_register_static(&tmp105_info);
 }
 
-device_init(tmp105_register_devices)
+type_init(tmp105_register_types)
diff --git a/hw/tosa.c b/hw/tosa.c
index c0d4017..6baa17d 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -291,10 +291,10 @@
     .class_init    = tosa_ssp_class_init,
 };
 
-static void tosa_register_devices(void)
+static void tosa_register_types(void)
 {
     type_register_static(&tosa_dac_info);
     type_register_static(&tosa_ssp_info);
 }
 
-device_init(tosa_register_devices)
+type_init(tosa_register_types)
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 0ade670..5ba8da6 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -805,9 +805,9 @@
     .class_init    = tusb6010_class_init,
 };
 
-static void tusb6010_register_device(void)
+static void tusb6010_register_types(void)
 {
     type_register_static(&tusb6010_info);
 }
 
-device_init(tusb6010_register_device)
+type_init(tusb6010_register_types)
diff --git a/hw/twl92230.c b/hw/twl92230.c
index 03fdccc..22da6f8 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -61,9 +61,7 @@
     } rtc;
     uint16_t rtc_next_vmstate;
     qemu_irq out[4];
-    qemu_irq *in;
     uint8_t pwrbtn_state;
-    qemu_irq pwrbtn;
 } MenelausState;
 
 static inline void menelaus_update(MenelausState *s)
@@ -186,14 +184,12 @@
 {
     MenelausState *s = (MenelausState *) opaque;
 
-    /* No interrupt generated */
-    s->inputs &= ~(1 << line);
-    s->inputs |= level << line;
-}
-
-static void menelaus_pwrbtn_set(void *opaque, int line, int level)
-{
-    MenelausState *s = (MenelausState *) opaque;
+    if (line < 3) {
+        /* No interrupt generated */
+        s->inputs &= ~(1 << line);
+        s->inputs |= level << line;
+        return;
+    }
 
     if (!s->pwrbtn_state && level) {
         s->status |= 1 << 11;					/* PSHBTN */
@@ -849,8 +845,9 @@
     s->rtc.hz_tm = qemu_new_timer_ms(rt_clock, menelaus_rtc_hz, s);
     /* Three output pins plus one interrupt pin.  */
     qdev_init_gpio_out(&i2c->qdev, s->out, 4);
-    qdev_init_gpio_in(&i2c->qdev, menelaus_gpio_set, 3);
-    s->pwrbtn = qemu_allocate_irqs(menelaus_pwrbtn_set, s, 1)[0];
+
+    /* Three input pins plus one power-button pin.  */
+    qdev_init_gpio_in(&i2c->qdev, menelaus_gpio_set, 4);
 
     menelaus_reset(&s->i2c);
 
@@ -876,9 +873,9 @@
     .class_init    = twl92230_class_init,
 };
 
-static void twl92230_register_devices(void)
+static void twl92230_register_types(void)
 {
     type_register_static(&twl92230_info);
 }
 
-device_init(twl92230_register_devices)
+type_init(twl92230_register_types)
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 17d86aa..409bcd4 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -467,7 +467,7 @@
     .class_init    = pci_unin_internal_class_init,
 };
 
-static void unin_register_devices(void)
+static void unin_register_types(void)
 {
     type_register_static(&unin_main_pci_host_info);
     type_register_static(&u3_agp_pci_host_info);
@@ -480,4 +480,4 @@
     type_register_static(&pci_unin_internal_info);
 }
 
-device_init(unin_register_devices)
+type_init(unin_register_types)
diff --git a/hw/usb-audio.c b/hw/usb-audio.c
index cd589b7..fed1361 100644
--- a/hw/usb-audio.c
+++ b/hw/usb-audio.c
@@ -607,7 +607,7 @@
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
-        switch (p->devep) {
+        switch (p->ep->nr) {
         case 1:
             ret = usb_audio_handle_dataout(s, p);
             break;
@@ -624,7 +624,7 @@
     if (ret == USB_RET_STALL && s->debug) {
         fprintf(stderr, "usb-audio: failed data transaction: "
                         "pid 0x%x ep 0x%x len 0x%zx\n",
-                        p->pid, p->devep, p->iov.size);
+                        p->pid, p->ep->nr, p->iov.size);
     }
     return ret;
 }
@@ -691,7 +691,6 @@
     k->product_desc   = "QEMU USB Audio Interface";
     k->usb_desc       = &desc_audio;
     k->init           = usb_audio_initfn;
-    k->handle_packet  = usb_generic_handle_packet;
     k->handle_reset   = usb_audio_handle_reset;
     k->handle_control = usb_audio_handle_control;
     k->handle_data    = usb_audio_handle_data;
@@ -706,10 +705,10 @@
     .class_init    = usb_audio_class_init,
 };
 
-static void usb_audio_register_devices(void)
+static void usb_audio_register_types(void)
 {
     type_register_static(&usb_audio_info);
     usb_legacy_register("usb-audio", "audio", NULL);
 }
 
-device_init(usb_audio_register_devices)
+type_init(usb_audio_register_types)
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 90c3b0e..649bdcf 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -423,7 +423,7 @@
 
     switch (p->pid) {
     case USB_TOKEN_IN:
-        switch (p->devep & 0xf) {
+        switch (p->ep->nr) {
         case USB_EVT_EP:
             ret = usb_bt_fifo_dequeue(&s->evt, p);
             break;
@@ -442,7 +442,7 @@
         break;
 
     case USB_TOKEN_OUT:
-        switch (p->devep & 0xf) {
+        switch (p->ep->nr) {
         case USB_ACL_EP:
             usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
                             usb_bt_hci_acl_complete, p);
@@ -535,7 +535,6 @@
     uc->init           = usb_bt_initfn;
     uc->product_desc   = "QEMU BT dongle";
     uc->usb_desc       = &desc_bluetooth;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_bt_handle_reset;
     uc->handle_control = usb_bt_handle_control;
     uc->handle_data    = usb_bt_handle_data;
@@ -550,8 +549,9 @@
     .class_init    = usb_bt_class_initfn,
 };
 
-static void usb_bt_register_devices(void)
+static void usb_bt_register_types(void)
 {
     type_register_static(&bt_info);
 }
-device_init(usb_bt_register_devices)
+
+type_init(usb_bt_register_types)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index b753834..ae79a45 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -74,6 +74,15 @@
     return 0;
 }
 
+USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
+{
+    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+    if (klass->find_device) {
+        return klass->find_device(dev, addr);
+    }
+    return NULL;
+}
+
 static void usb_device_handle_destroy(USBDevice *dev)
 {
     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
@@ -82,15 +91,6 @@
     }
 }
 
-int usb_device_handle_packet(USBDevice *dev, USBPacket *p)
-{
-    USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
-    if (klass->handle_packet) {
-        return klass->handle_packet(dev, p);
-    }
-    return -ENOSYS;
-}
-
 void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
 {
     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
@@ -586,9 +586,9 @@
     .class_init = usb_device_class_init,
 };
 
-static void usb_register_devices(void)
+static void usb_register_types(void)
 {
     type_register_static(&usb_device_type_info);
 }
 
-device_init(usb_register_devices);
+type_init(usb_register_types)
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 881da30..0b2ac80 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -267,6 +267,7 @@
  */
 typedef struct USBCCIDState {
     USBDevice dev;
+    USBEndpoint *intr;
     CCIDBus bus;
     CCIDCardState *card;
     BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
@@ -839,7 +840,7 @@
         s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
     }
     s->notify_slot_change = true;
-    usb_wakeup(&s->dev);
+    usb_wakeup(s->intr);
 }
 
 static void ccid_write_data_block_error(
@@ -995,7 +996,7 @@
         break;
 
     case USB_TOKEN_IN:
-        switch (p->devep & 0xf) {
+        switch (p->ep->nr) {
         case CCID_BULK_IN_EP:
             if (!p->iov.size) {
                 ret = USB_RET_NAK;
@@ -1190,6 +1191,7 @@
 
     usb_desc_init(dev);
     qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
+    s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
     s->bus.qbus.allow_hotplug = 1;
     s->card = NULL;
     s->migration_state = MIGRATION_NONE;
@@ -1320,7 +1322,6 @@
     uc->init           = ccid_initfn;
     uc->product_desc   = "QEMU USB CCID";
     uc->usb_desc       = &desc_ccid;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = ccid_handle_reset;
     uc->handle_control = ccid_handle_control;
     uc->handle_data    = ccid_handle_data;
@@ -1354,10 +1355,11 @@
     .class_init = ccid_card_class_init,
 };
 
-static void ccid_register_devices(void)
+static void ccid_register_types(void)
 {
     type_register_static(&ccid_card_type_info);
     type_register_static(&ccid_info);
     usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
 }
-device_init(ccid_register_devices)
+
+type_init(ccid_register_types)
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 75ef71e..e699814 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -715,8 +715,8 @@
     EHCIQueue *q, *tmp;
 
     QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
-        if (q->packet.owner == NULL ||
-            q->packet.owner->dev != dev) {
+        if (!usb_packet_is_inflight(&q->packet) ||
+            q->packet.ep->dev != dev) {
             continue;
         }
         ehci_free_queue(q);
@@ -765,6 +765,11 @@
         USBPort *companion = s->companion_ports[port->index];
         companion->ops->detach(companion);
         companion->dev = NULL;
+        /*
+         * EHCI spec 4.2.2: "When a disconnect occurs... On the event,
+         * the port ownership is returned immediately to the EHCI controller."
+         */
+        *portsc &= ~PORTSC_POWNER;
         return;
     }
 
@@ -845,6 +850,26 @@
     return 0;
 }
 
+static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
+{
+    USBDevice *dev;
+    USBPort *port;
+    int i;
+
+    for (i = 0; i < NB_PORTS; i++) {
+        port = &ehci->ports[i];
+        if (!(ehci->portsc[i] & PORTSC_PED)) {
+            DPRINTF("Port %d not enabled\n", i);
+            continue;
+        }
+        dev = usb_find_device(port, addr);
+        if (dev != NULL) {
+            return dev;
+        }
+    }
+    return NULL;
+}
+
 /* 4.1 host controller initialization */
 static void ehci_reset(void *opaque)
 {
@@ -883,7 +908,7 @@
         }
         if (devs[i] && devs[i]->attached) {
             usb_attach(&s->ports[i]);
-            usb_send_msg(devs[i], USB_MSG_RESET);
+            usb_device_reset(devs[i]);
         }
     }
     ehci_queues_rip_all(s);
@@ -982,7 +1007,7 @@
     if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
         trace_usb_ehci_port_reset(port, 0);
         if (dev && dev->attached) {
-            usb_reset(&s->ports[port]);
+            usb_port_reset(&s->ports[port]);
             *portsc &= ~PORTSC_CSC;
         }
 
@@ -1331,10 +1356,9 @@
 
 static int ehci_execute(EHCIQueue *q)
 {
-    USBPort *port;
     USBDevice *dev;
+    USBEndpoint *ep;
     int ret;
-    int i;
     int endp;
     int devadr;
 
@@ -1364,33 +1388,18 @@
     endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
     devadr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
 
-    ret = USB_RET_NODEV;
+    /* TODO: associating device with ehci port */
+    dev = ehci_find_device(q->ehci, devadr);
+    ep = usb_ep_get(dev, q->pid, endp);
 
-    usb_packet_setup(&q->packet, q->pid, devadr, endp);
+    usb_packet_setup(&q->packet, q->pid, ep);
     usb_packet_map(&q->packet, &q->sgl);
 
-    // TO-DO: associating device with ehci port
-    for(i = 0; i < NB_PORTS; i++) {
-        port = &q->ehci->ports[i];
-        dev = port->dev;
-
-        if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
-            DPRINTF("Port %d, no exec, not connected(%08X)\n",
-                    i, q->ehci->portsc[i]);
-            continue;
-        }
-
-        ret = usb_handle_packet(dev, &q->packet);
-
-        DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
-                "(total %d) endp %x ret %d\n",
-                q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
-                q->packet.iov.size, q->tbytes, endp, ret);
-
-        if (ret != USB_RET_NODEV) {
-            break;
-        }
-    }
+    ret = usb_handle_packet(dev, &q->packet);
+    DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
+            "(total %d) endp %x ret %d\n",
+            q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
+            q->packet.iov.size, q->tbytes, endp, ret);
 
     if (ret > BUFF_SIZE) {
         fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
@@ -1406,10 +1415,10 @@
 static int ehci_process_itd(EHCIState *ehci,
                             EHCIitd *itd)
 {
-    USBPort *port;
     USBDevice *dev;
+    USBEndpoint *ep;
     int ret;
-    uint32_t i, j, len, pid, dir, devaddr, endp;
+    uint32_t i, len, pid, dir, devaddr, endp;
     uint32_t pg, off, ptr1, ptr2, max, mult;
 
     dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
@@ -1447,24 +1456,12 @@
 
             pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
 
-            usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
+            dev = ehci_find_device(ehci, devaddr);
+            ep = usb_ep_get(dev, pid, endp);
+            usb_packet_setup(&ehci->ipacket, pid, ep);
             usb_packet_map(&ehci->ipacket, &ehci->isgl);
 
-            ret = USB_RET_NODEV;
-            for (j = 0; j < NB_PORTS; j++) {
-                port = &ehci->ports[j];
-                dev = port->dev;
-
-                if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
-                    continue;
-                }
-
-                ret = usb_handle_packet(dev, &ehci->ipacket);
-
-                if (ret != USB_RET_NODEV) {
-                    break;
-                }
-            }
+            ret = usb_handle_packet(dev, &ehci->ipacket);
 
             usb_packet_unmap(&ehci->ipacket);
             qemu_sglist_destroy(&ehci->isgl);
@@ -2376,12 +2373,13 @@
     return 0;
 }
 
-static void ehci_register(void)
+static void ehci_register_types(void)
 {
     type_register_static(&ehci_info);
     type_register_static(&ich9_ehci_info);
 }
-device_init(ehci_register);
+
+type_init(ehci_register_types)
 
 /*
  * vim: expandtab ts=4
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 3c4e45d..7fc0bd8 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -44,6 +44,7 @@
 
 typedef struct USBHIDState {
     USBDevice dev;
+    USBEndpoint *intr;
     HIDState hid;
 } USBHIDState;
 
@@ -360,7 +361,7 @@
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    usb_wakeup(&us->dev);
+    usb_wakeup(us->intr);
 }
 
 static void usb_hid_handle_reset(USBDevice *dev)
@@ -463,7 +464,7 @@
 
     switch (p->pid) {
     case USB_TOKEN_IN:
-        if (p->devep == 1) {
+        if (p->ep->nr == 1) {
             int64_t curtime = qemu_get_clock_ns(vm_clock);
             if (!hid_has_events(hs) &&
                 (!hs->idle || hs->next_idle_clock - curtime > 0)) {
@@ -501,6 +502,7 @@
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
     usb_desc_init(dev);
+    us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
     hid_init(&us->hid, kind, usb_hid_changed);
     return 0;
 }
@@ -557,7 +559,6 @@
 {
     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_hid_handle_reset;
     uc->handle_control = usb_hid_handle_control;
     uc->handle_data    = usb_hid_handle_data;
@@ -621,7 +622,7 @@
     .class_init    = usb_keyboard_class_initfn,
 };
 
-static void usb_hid_register_devices(void)
+static void usb_hid_register_types(void)
 {
     type_register_static(&usb_tablet_info);
     usb_legacy_register("usb-tablet", "tablet", NULL);
@@ -630,4 +631,5 @@
     type_register_static(&usb_keyboard_info);
     usb_legacy_register("usb-kbd", "keyboard", NULL);
 }
-device_init(usb_hid_register_devices)
+
+type_init(usb_hid_register_types)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 956b020..a12856e 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -37,6 +37,7 @@
 
 typedef struct USBHubState {
     USBDevice dev;
+    USBEndpoint *intr;
     USBHubPort ports[NUM_PORTS];
 } USBHubState;
 
@@ -163,7 +164,7 @@
     } else {
         port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
     }
-    usb_wakeup(&s->dev);
+    usb_wakeup(s->intr);
 }
 
 static void usb_hub_detach(USBPort *port1)
@@ -171,7 +172,7 @@
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
 
-    usb_wakeup(&s->dev);
+    usb_wakeup(s->intr);
 
     /* Let upstream know the device on this port is gone */
     s->dev.port->ops->child_detach(s->dev.port, port1->dev);
@@ -199,7 +200,7 @@
 
     if (port->wPortStatus & PORT_STAT_SUSPEND) {
         port->wPortChange |= PORT_STAT_C_SUSPEND;
-        usb_wakeup(&s->dev);
+        usb_wakeup(s->intr);
     }
 }
 
@@ -220,6 +221,26 @@
     s->dev.port->ops->complete(s->dev.port, packet);
 }
 
+static USBDevice *usb_hub_find_device(USBDevice *dev, uint8_t addr)
+{
+    USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+    USBHubPort *port;
+    USBDevice *downstream;
+    int i;
+
+    for (i = 0; i < NUM_PORTS; i++) {
+        port = &s->ports[i];
+        if (!(port->wPortStatus & PORT_STAT_ENABLE)) {
+            continue;
+        }
+        downstream = usb_find_device(&port->port, addr);
+        if (downstream != NULL) {
+            return downstream;
+        }
+    }
+    return NULL;
+}
+
 static void usb_hub_handle_reset(USBDevice *dev)
 {
     USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
@@ -305,7 +326,7 @@
                 break;
             case PORT_RESET:
                 if (dev && dev->attached) {
-                    usb_send_msg(dev, USB_MSG_RESET);
+                    usb_device_reset(dev);
                     port->wPortChange |= PORT_STAT_C_RESET;
                     /* set enable bit */
                     port->wPortStatus |= PORT_STAT_ENABLE;
@@ -396,7 +417,7 @@
 
     switch(p->pid) {
     case USB_TOKEN_IN:
-        if (p->devep == 1) {
+        if (p->ep->nr == 1) {
             USBHubPort *port;
             unsigned int status;
             uint8_t buf[4];
@@ -435,44 +456,6 @@
     return ret;
 }
 
-static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
-{
-    USBHubPort *port;
-    USBDevice *dev;
-    int i, ret;
-
-    for(i = 0; i < NUM_PORTS; i++) {
-        port = &s->ports[i];
-        dev = port->port.dev;
-        if (dev && dev->attached && (port->wPortStatus & PORT_STAT_ENABLE)) {
-            ret = usb_handle_packet(dev, p);
-            if (ret != USB_RET_NODEV) {
-                return ret;
-            }
-        }
-    }
-    return USB_RET_NODEV;
-}
-
-static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p)
-{
-    USBHubState *s = (USBHubState *)dev;
-
-#if defined(DEBUG) && 0
-    printf("usb_hub: pid=0x%x\n", pid);
-#endif
-    if (dev->state == USB_STATE_DEFAULT &&
-        dev->addr != 0 &&
-        p->devaddr != dev->addr &&
-        (p->pid == USB_TOKEN_SETUP ||
-         p->pid == USB_TOKEN_OUT ||
-         p->pid == USB_TOKEN_IN)) {
-        /* broadcast the packet to the devices */
-        return usb_hub_broadcast_packet(s, p);
-    }
-    return usb_generic_handle_packet(dev, p);
-}
-
 static void usb_hub_handle_destroy(USBDevice *dev)
 {
     USBHubState *s = (USBHubState *)dev;
@@ -499,6 +482,7 @@
     int i;
 
     usb_desc_init(dev);
+    s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
     for (i = 0; i < NUM_PORTS; i++) {
         port = &s->ports[i];
         usb_register_port(usb_bus_from_device(dev),
@@ -541,7 +525,7 @@
     uc->init           = usb_hub_initfn;
     uc->product_desc   = "QEMU USB Hub";
     uc->usb_desc       = &desc_hub;
-    uc->handle_packet  = usb_hub_handle_packet;
+    uc->find_device    = usb_hub_find_device;
     uc->handle_reset   = usb_hub_handle_reset;
     uc->handle_control = usb_hub_handle_control;
     uc->handle_data    = usb_hub_handle_data;
@@ -557,8 +541,9 @@
     .class_init    = usb_hub_class_initfn,
 };
 
-static void usb_hub_register_devices(void)
+static void usb_hub_register_types(void)
 {
     type_register_static(&hub_info);
 }
-device_init(usb_hub_register_devices)
+
+type_init(usb_hub_register_types)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 6153376..c933efe 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -341,7 +341,7 @@
     uint32_t tag;
     int ret = 0;
     struct usb_msd_cbw cbw;
-    uint8_t devep = p->devep;
+    uint8_t devep = p->ep->nr;
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
@@ -651,7 +651,6 @@
     uc->init           = usb_msd_initfn;
     uc->product_desc   = "QEMU USB MSD";
     uc->usb_desc       = &desc;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->cancel_packet  = usb_msd_cancel_io;
     uc->handle_attach  = usb_desc_attach;
     uc->handle_reset   = usb_msd_handle_reset;
@@ -669,9 +668,10 @@
     .class_init    = usb_msd_class_initfn,
 };
 
-static void usb_msd_register_devices(void)
+static void usb_msd_register_types(void)
 {
     type_register_static(&msd_info);
     usb_legacy_register("usb-storage", "disk", usb_msd_init);
 }
-device_init(usb_msd_register_devices)
+
+type_init(usb_msd_register_types)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 4f528d2..820907a 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -605,6 +605,8 @@
 static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
                 int epnum, int pid, int len, USBCallback cb, int dir)
 {
+    USBDevice *dev;
+    USBEndpoint *uep;
     int ret;
     int idx = epnum && dir;
     int ttype;
@@ -622,16 +624,14 @@
     ep->delayed_cb[dir] = cb;
 
     /* A wild guess on the FADDR semantics... */
-    usb_packet_setup(&ep->packey[dir].p, pid, ep->faddr[idx],
-                     ep->type[idx] & 0xf);
+    dev = usb_find_device(&s->port, ep->faddr[idx]);
+    uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
+    usb_packet_setup(&ep->packey[dir].p, pid, uep);
     usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
     ep->packey[dir].ep = ep;
     ep->packey[dir].dir = dir;
 
-    if (s->port.dev)
-        ret = usb_handle_packet(s->port.dev, &ep->packey[dir].p);
-    else
-        ret = USB_RET_NODEV;
+    ret = usb_handle_packet(dev, &ep->packey[dir].p);
 
     if (ret == USB_RET_ASYNC) {
         ep->status[dir] = len;
@@ -812,8 +812,8 @@
 
     for (ep = 0; ep < 16; ep++) {
         for (dir = 0; dir < 2; dir++) {
-            if (s->ep[ep].packey[dir].p.owner == NULL ||
-                s->ep[ep].packey[dir].p.owner->dev != dev) {
+            if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) ||
+                s->ep[ep].packey[dir].p.ep->dev != dev) {
                 continue;
             }
             usb_cancel_packet(&s->ep[ep].packey[dir].p);
@@ -1310,7 +1310,7 @@
         s->power = (value & 0xef) | (s->power & 0x10);
         /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
         if ((value & MGC_M_POWER_RESET) && s->port.dev) {
-            usb_send_msg(s->port.dev, USB_MSG_RESET);
+            usb_device_reset(s->port.dev);
             /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set.  */
             if ((value & MGC_M_POWER_HSENAB) &&
                             s->port.dev->speed == USB_SPEED_HIGH)
diff --git a/hw/usb-net.c b/hw/usb-net.c
index e211141..49d5d4d 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1210,7 +1210,7 @@
 
     switch(p->pid) {
     case USB_TOKEN_IN:
-        switch (p->devep) {
+        switch (p->ep->nr) {
         case 1:
             ret = usb_net_handle_statusin(s, p);
             break;
@@ -1225,7 +1225,7 @@
         break;
 
     case USB_TOKEN_OUT:
-        switch (p->devep) {
+        switch (p->ep->nr) {
         case 2:
             ret = usb_net_handle_dataout(s, p);
             break;
@@ -1243,7 +1243,7 @@
     if (ret == USB_RET_STALL)
         fprintf(stderr, "usbnet: failed data transaction: "
                         "pid 0x%x ep 0x%x len 0x%zx\n",
-                        p->pid, p->devep, p->iov.size);
+                        p->pid, p->ep->nr, p->iov.size);
     return ret;
 }
 
@@ -1398,7 +1398,6 @@
     uc->init           = usb_net_initfn;
     uc->product_desc   = "QEMU USB Network Interface";
     uc->usb_desc       = &desc_net;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_net_handle_reset;
     uc->handle_control = usb_net_handle_control;
     uc->handle_data    = usb_net_handle_data;
@@ -1415,9 +1414,10 @@
     .class_init    = usb_net_class_initfn,
 };
 
-static void usb_net_register_devices(void)
+static void usb_net_register_types(void)
 {
     type_register_static(&net_info);
     usb_legacy_register("usb-net", "net", usb_net_init);
 }
-device_init(usb_net_register_devices)
+
+type_init(usb_net_register_types)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 425030f..7aa19fe 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -408,6 +408,23 @@
     ohci_async_cancel_device(s, child);
 }
 
+static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
+{
+    USBDevice *dev;
+    int i;
+
+    for (i = 0; i < ohci->num_ports; i++) {
+        if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) {
+            continue;
+        }
+        dev = usb_find_device(&ohci->rhport[i].port, addr);
+        if (dev != NULL) {
+            return dev;
+        }
+    }
+    return NULL;
+}
+
 /* Reset the controller */
 static void ohci_reset(void *opaque)
 {
@@ -449,7 +466,7 @@
         port = &ohci->rhport[i];
         port->ctrl = 0;
         if (port->port.dev && port->port.dev->attached) {
-            usb_reset(&port->port);
+            usb_port_reset(&port->port);
         }
       }
     if (ohci->async_td) {
@@ -640,6 +657,7 @@
     int ret;
     int i;
     USBDevice *dev;
+    USBEndpoint *ep;
     struct ohci_iso_td iso_td;
     uint32_t addr;
     uint16_t starting_frame;
@@ -779,20 +797,11 @@
     if (completion) {
         ret = ohci->usb_packet.result;
     } else {
-        ret = USB_RET_NODEV;
-        for (i = 0; i < ohci->num_ports; i++) {
-            dev = ohci->rhport[i].port.dev;
-            if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
-                continue;
-            usb_packet_setup(&ohci->usb_packet, pid,
-                             OHCI_BM(ed->flags, ED_FA),
-                             OHCI_BM(ed->flags, ED_EN));
-            usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
-            ret = usb_handle_packet(dev, &ohci->usb_packet);
-            if (ret != USB_RET_NODEV)
-                break;
-        }
-    
+        dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
+        ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
+        usb_packet_setup(&ohci->usb_packet, pid, ep);
+        usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
+        ret = usb_handle_packet(dev, &ohci->usb_packet);
         if (ret == USB_RET_ASYNC) {
             return 1;
         }
@@ -880,6 +889,7 @@
     int ret;
     int i;
     USBDevice *dev;
+    USBEndpoint *ep;
     struct ohci_td td;
     uint32_t addr;
     int flag_r;
@@ -972,31 +982,22 @@
         ohci->async_td = 0;
         ohci->async_complete = 0;
     } else {
-        ret = USB_RET_NODEV;
-        for (i = 0; i < ohci->num_ports; i++) {
-            dev = ohci->rhport[i].port.dev;
-            if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
-                continue;
-
-            if (ohci->async_td) {
-                /* ??? The hardware should allow one active packet per
-                   endpoint.  We only allow one active packet per controller.
-                   This should be sufficient as long as devices respond in a
-                   timely manner.
-                 */
+        if (ohci->async_td) {
+            /* ??? The hardware should allow one active packet per
+               endpoint.  We only allow one active packet per controller.
+               This should be sufficient as long as devices respond in a
+               timely manner.
+            */
 #ifdef DEBUG_PACKET
-                DPRINTF("Too many pending packets\n");
+            DPRINTF("Too many pending packets\n");
 #endif
-                return 1;
-            }
-            usb_packet_setup(&ohci->usb_packet, pid,
-                             OHCI_BM(ed->flags, ED_FA),
-                             OHCI_BM(ed->flags, ED_EN));
-            usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
-            ret = usb_handle_packet(dev, &ohci->usb_packet);
-            if (ret != USB_RET_NODEV)
-                break;
+            return 1;
         }
+        dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
+        ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
+        usb_packet_setup(&ohci->usb_packet, pid, ep);
+        usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
+        ret = usb_handle_packet(dev, &ohci->usb_packet);
 #ifdef DEBUG_PACKET
         DPRINTF("ret=%d\n", ret);
 #endif
@@ -1435,7 +1436,7 @@
 
     if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
         DPRINTF("usb-ohci: port %d: RESET\n", portnum);
-        usb_send_msg(port->port.dev, USB_MSG_RESET);
+        usb_device_reset(port->port.dev);
         port->ctrl &= ~OHCI_PORT_PRS;
         /* ??? Should this also set OHCI_PORT_PESC.  */
         port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC;
@@ -1708,8 +1709,8 @@
 static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
 {
     if (ohci->async_td &&
-        ohci->usb_packet.owner != NULL &&
-        ohci->usb_packet.owner->dev == dev) {
+        usb_packet_is_inflight(&ohci->usb_packet) &&
+        ohci->usb_packet.ep->dev == dev) {
         usb_cancel_packet(&ohci->usb_packet);
         ohci->async_td = 0;
     }
@@ -1886,9 +1887,10 @@
     .class_init    = ohci_sysbus_class_init,
 };
 
-static void ohci_register(void)
+static void ohci_register_types(void)
 {
     type_register_static(&ohci_pci_info);
     type_register_static(&ohci_sysbus_info);
 }
-device_init(ohci_register);
+
+type_init(ohci_register_types)
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index c2cb6d2..52676e8 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -353,7 +353,7 @@
 {
     USBSerialState *s = (USBSerialState *)dev;
     int i, ret = 0;
-    uint8_t devep = p->devep;
+    uint8_t devep = p->ep->nr;
     struct iovec *iov;
     uint8_t header[2];
     int first_len, len;
@@ -583,7 +583,6 @@
     uc->init = usb_serial_initfn;
     uc->product_desc   = "QEMU USB Serial";
     uc->usb_desc       = &desc_serial;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_serial_handle_reset;
     uc->handle_control = usb_serial_handle_control;
     uc->handle_data    = usb_serial_handle_data;
@@ -612,7 +611,6 @@
     uc->init           = usb_serial_initfn;
     uc->product_desc   = "QEMU USB Braille";
     uc->usb_desc       = &desc_braille;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_serial_handle_reset;
     uc->handle_control = usb_serial_handle_control;
     uc->handle_data    = usb_serial_handle_data;
@@ -628,11 +626,12 @@
     .class_init    = usb_braille_class_initfn,
 };
 
-static void usb_serial_register_devices(void)
+static void usb_serial_register_types(void)
 {
     type_register_static(&serial_info);
     usb_legacy_register("usb-serial", "serial", usb_serial_init);
     type_register_static(&braille_info);
     usb_legacy_register("usb-braille", "braille", usb_braille_init);
 }
-device_init(usb_serial_register_devices)
+
+type_init(usb_serial_register_types)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index cddcc89..2280dc7 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -73,7 +73,7 @@
 
 #define FRAME_TIMER_FREQ 1000
 
-#define FRAME_MAX_LOOPS  100
+#define FRAME_MAX_LOOPS  256
 
 #define NB_PORTS 2
 
@@ -94,15 +94,6 @@
 #define DPRINTF(...)
 #endif
 
-#ifdef DEBUG_DUMP_DATA
-static void dump_data(USBPacket *p, int ret)
-{
-    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "uhci", ret);
-}
-#else
-static void dump_data(USBPacket *p, int ret) {}
-#endif
-
 typedef struct UHCIState UHCIState;
 
 /* 
@@ -245,8 +236,8 @@
     UHCIAsync *curr, *n;
 
     QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
-        if (curr->packet.owner == NULL ||
-            curr->packet.owner->dev != dev) {
+        if (!usb_packet_is_inflight(&curr->packet) ||
+            curr->packet.ep->dev != dev) {
             continue;
         }
         uhci_async_unlink(s, curr);
@@ -342,7 +333,7 @@
         port = &s->ports[i];
         port->ctrl = 0x0080;
         if (port->port.dev && port->port.dev->attached) {
-            usb_reset(&port->port);
+            usb_port_reset(&port->port);
         }
     }
 
@@ -440,16 +431,12 @@
         }
         if (val & UHCI_CMD_GRESET) {
             UHCIPort *port;
-            USBDevice *dev;
             int i;
 
             /* send reset on the USB bus */
             for(i = 0; i < NB_PORTS; i++) {
                 port = &s->ports[i];
-                dev = port->port.dev;
-                if (dev && dev->attached) {
-                    usb_send_msg(dev, USB_MSG_RESET);
-                }
+                usb_device_reset(port->port.dev);
             }
             uhci_reset(s);
             return;
@@ -491,7 +478,7 @@
                 /* port reset */
                 if ( (val & UHCI_PORT_RESET) &&
                      !(port->ctrl & UHCI_PORT_RESET) ) {
-                    usb_send_msg(dev, USB_MSG_RESET);
+                    usb_device_reset(dev);
                 }
             }
             port->ctrl &= UHCI_PORT_READ_ONLY;
@@ -647,30 +634,22 @@
     }
 }
 
-static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
+static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr)
 {
-    int i, ret;
+    USBDevice *dev;
+    int i;
 
-    DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %zd\n",
-           pid2str(p->pid), p->devaddr, p->devep, p->iov.size);
-    if (p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_SETUP)
-        dump_data(p, 0);
-
-    ret = USB_RET_NODEV;
-    for (i = 0; i < NB_PORTS && ret == USB_RET_NODEV; i++) {
+    for (i = 0; i < NB_PORTS; i++) {
         UHCIPort *port = &s->ports[i];
-        USBDevice *dev = port->port.dev;
-
-        if (dev && dev->attached && (port->ctrl & UHCI_PORT_EN)) {
-            ret = usb_handle_packet(dev, p);
+        if (!(port->ctrl & UHCI_PORT_EN)) {
+            continue;
+        }
+        dev = usb_find_device(&port->port, addr);
+        if (dev != NULL) {
+            return dev;
         }
     }
-
-    DPRINTF("uhci: packet exit. ret %d len %zd\n", ret, p->iov.size);
-    if (p->pid == USB_TOKEN_IN && ret > 0)
-        dump_data(p, ret);
-
-    return ret;
+    return NULL;
 }
 
 static void uhci_async_complete(USBPort *port, USBPacket *packet);
@@ -782,6 +761,8 @@
     int len = 0, max_len;
     uint8_t pid, isoc;
     uint32_t token;
+    USBDevice *dev;
+    USBEndpoint *ep;
 
     /* Is active ? */
     if (!(td->ctrl & TD_CTRL_ACTIVE))
@@ -826,21 +807,22 @@
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     pid = td->token & 0xff;
 
-    usb_packet_setup(&async->packet, pid, (td->token >> 8) & 0x7f,
-                     (td->token >> 15) & 0xf);
+    dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
+    ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
+    usb_packet_setup(&async->packet, pid, ep);
     qemu_sglist_add(&async->sgl, td->buffer, max_len);
     usb_packet_map(&async->packet, &async->sgl);
 
     switch(pid) {
     case USB_TOKEN_OUT:
     case USB_TOKEN_SETUP:
-        len = uhci_broadcast_packet(s, &async->packet);
+        len = usb_handle_packet(dev, &async->packet);
         if (len >= 0)
             len = max_len;
         break;
 
     case USB_TOKEN_IN:
-        len = uhci_broadcast_packet(s, &async->packet);
+        len = usb_handle_packet(dev, &async->packet);
         break;
 
     default:
@@ -942,7 +924,7 @@
 static void uhci_process_frame(UHCIState *s)
 {
     uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
-    uint32_t curr_qh;
+    uint32_t curr_qh, td_count = 0, bytes_count = 0;
     int cnt, ret;
     UHCI_TD td;
     UHCI_QH qh;
@@ -967,13 +949,26 @@
             if (qhdb_insert(&qhdb, link)) {
                 /*
                  * We're going in circles. Which is not a bug because
-                 * HCD is allowed to do that as part of the BW management. 
-                 * In our case though it makes no sense to spin here. Sync transations 
-                 * are already done, and async completion handler will re-process 
-                 * the frame when something is ready.
+                 * HCD is allowed to do that as part of the BW management.
+                 *
+                 * Stop processing here if
+                 *  (a) no transaction has been done since we've been
+                 *      here last time, or
+                 *  (b) we've reached the usb 1.1 bandwidth, which is
+                 *      1280 bytes/frame.
                  */
                 DPRINTF("uhci: detected loop. qh 0x%x\n", link);
-                break;
+                if (td_count == 0) {
+                    DPRINTF("uhci: no transaction last round, stop\n");
+                    break;
+                } else if (bytes_count >= 1280) {
+                    DPRINTF("uhci: bandwidth limit reached, stop\n");
+                    break;
+                } else {
+                    td_count = 0;
+                    qhdb_reset(&qhdb);
+                    qhdb_insert(&qhdb, link);
+                }
             }
 
             pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh));
@@ -1033,6 +1028,8 @@
                 link, td.link, td.ctrl, td.token, curr_qh);
 
         link = td.link;
+        td_count++;
+        bytes_count += (td.ctrl & 0x7ff) + 1;
 
         if (curr_qh) {
 	    /* update QH element link */
@@ -1321,7 +1318,7 @@
     .class_init    = ich9_uhci3_class_init,
 };
 
-static void uhci_register(void)
+static void uhci_register_types(void)
 {
     type_register_static(&piix3_uhci_info);
     type_register_static(&piix4_uhci_info);
@@ -1330,7 +1327,8 @@
     type_register_static(&ich9_uhci2_info);
     type_register_static(&ich9_uhci3_info);
 }
-device_init(uhci_register);
+
+type_init(uhci_register_types)
 
 void usb_uhci_piix3_init(PCIBus *bus, int devfn)
 {
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 14de14d..197e2dc 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -306,7 +306,7 @@
 
     switch (p->pid) {
     case USB_TOKEN_IN:
-        if (p->devep == 1) {
+        if (p->ep->nr == 1) {
             if (!(s->changed || s->idle))
                 return USB_RET_NAK;
             s->changed = 0;
@@ -357,7 +357,6 @@
     uc->product_desc   = "QEMU PenPartner Tablet";
     uc->usb_desc       = &desc_wacom;
     uc->init           = usb_wacom_initfn;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_wacom_handle_reset;
     uc->handle_control = usb_wacom_handle_control;
     uc->handle_data    = usb_wacom_handle_data;
@@ -373,9 +372,10 @@
     .class_init    = usb_wacom_class_init,
 };
 
-static void usb_wacom_register_devices(void)
+static void usb_wacom_register_types(void)
 {
     type_register_static(&wacom_info);
     usb_legacy_register("usb-wacom-tablet", "wacom-tablet", NULL);
 }
-device_init(usb_wacom_register_devices)
+
+type_init(usb_wacom_register_types)
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
index 37e887c..008b0b5 100644
--- a/hw/usb-xhci.c
+++ b/hw/usb-xhci.c
@@ -307,7 +307,8 @@
 typedef struct XHCITransfer {
     XHCIState *xhci;
     USBPacket packet;
-    bool running;
+    bool running_async;
+    bool running_retry;
     bool cancelled;
     bool complete;
     bool backgrounded;
@@ -338,6 +339,7 @@
     unsigned int next_xfer;
     unsigned int comp_xfer;
     XHCITransfer transfers[TD_QUEUE];
+    XHCITransfer *retry;
     bool bg_running;
     bool bg_updating;
     unsigned int next_bg;
@@ -420,6 +422,60 @@
     uint32_t rsvd;
 } XHCIEvRingSeg;
 
+#ifdef DEBUG_XHCI
+static const char *TRBType_names[] = {
+    [TRB_RESERVED]                     = "TRB_RESERVED",
+    [TR_NORMAL]                        = "TR_NORMAL",
+    [TR_SETUP]                         = "TR_SETUP",
+    [TR_DATA]                          = "TR_DATA",
+    [TR_STATUS]                        = "TR_STATUS",
+    [TR_ISOCH]                         = "TR_ISOCH",
+    [TR_LINK]                          = "TR_LINK",
+    [TR_EVDATA]                        = "TR_EVDATA",
+    [TR_NOOP]                          = "TR_NOOP",
+    [CR_ENABLE_SLOT]                   = "CR_ENABLE_SLOT",
+    [CR_DISABLE_SLOT]                  = "CR_DISABLE_SLOT",
+    [CR_ADDRESS_DEVICE]                = "CR_ADDRESS_DEVICE",
+    [CR_CONFIGURE_ENDPOINT]            = "CR_CONFIGURE_ENDPOINT",
+    [CR_EVALUATE_CONTEXT]              = "CR_EVALUATE_CONTEXT",
+    [CR_RESET_ENDPOINT]                = "CR_RESET_ENDPOINT",
+    [CR_STOP_ENDPOINT]                 = "CR_STOP_ENDPOINT",
+    [CR_SET_TR_DEQUEUE]                = "CR_SET_TR_DEQUEUE",
+    [CR_RESET_DEVICE]                  = "CR_RESET_DEVICE",
+    [CR_FORCE_EVENT]                   = "CR_FORCE_EVENT",
+    [CR_NEGOTIATE_BW]                  = "CR_NEGOTIATE_BW",
+    [CR_SET_LATENCY_TOLERANCE]         = "CR_SET_LATENCY_TOLERANCE",
+    [CR_GET_PORT_BANDWIDTH]            = "CR_GET_PORT_BANDWIDTH",
+    [CR_FORCE_HEADER]                  = "CR_FORCE_HEADER",
+    [CR_NOOP]                          = "CR_NOOP",
+    [ER_TRANSFER]                      = "ER_TRANSFER",
+    [ER_COMMAND_COMPLETE]              = "ER_COMMAND_COMPLETE",
+    [ER_PORT_STATUS_CHANGE]            = "ER_PORT_STATUS_CHANGE",
+    [ER_BANDWIDTH_REQUEST]             = "ER_BANDWIDTH_REQUEST",
+    [ER_DOORBELL]                      = "ER_DOORBELL",
+    [ER_HOST_CONTROLLER]               = "ER_HOST_CONTROLLER",
+    [ER_DEVICE_NOTIFICATION]           = "ER_DEVICE_NOTIFICATION",
+    [ER_MFINDEX_WRAP]                  = "ER_MFINDEX_WRAP",
+    [CR_VENDOR_VIA_CHALLENGE_RESPONSE] = "CR_VENDOR_VIA_CHALLENGE_RESPONSE",
+    [CR_VENDOR_NEC_FIRMWARE_REVISION]  = "CR_VENDOR_NEC_FIRMWARE_REVISION",
+    [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE",
+};
+
+static const char *lookup_name(uint32_t index, const char **list, uint32_t llen)
+{
+    if (index >= llen || list[index] == NULL) {
+        return "???";
+    }
+    return list[index];
+}
+
+static const char *trb_name(XHCITRB *trb)
+{
+    return lookup_name(TRB_TYPE(*trb), TRBType_names,
+                       ARRAY_SIZE(TRBType_names));
+}
+#endif
+
 static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
                          unsigned int epid);
 
@@ -487,8 +543,9 @@
     }
     ev_trb.control = cpu_to_le32(ev_trb.control);
 
-    DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x\n",
-            xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control);
+    DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x %s\n",
+            xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control,
+            trb_name(&ev_trb));
 
     addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
     cpu_physical_memory_write(addr, (uint8_t *) &ev_trb, TRB_SIZE);
@@ -649,8 +706,9 @@
         le32_to_cpus(&trb->control);
 
         DPRINTF("xhci: TRB fetched [" TARGET_FMT_plx "]: "
-                "%016" PRIx64 " %08x %08x\n",
-                ring->dequeue, trb->parameter, trb->status, trb->control);
+                "%016" PRIx64 " %08x %08x %s\n",
+                ring->dequeue, trb->parameter, trb->status, trb->control,
+                trb_name(trb));
 
         if ((trb->control & TRB_C) != ring->ccs) {
             return 0;
@@ -859,12 +917,17 @@
     xferi = epctx->next_xfer;
     for (i = 0; i < TD_QUEUE; i++) {
         XHCITransfer *t = &epctx->transfers[xferi];
-        if (t->running) {
+        if (t->running_async) {
+            usb_cancel_packet(&t->packet);
+            t->running_async = 0;
             t->cancelled = 1;
-            /* libusb_cancel_transfer(t->usbxfer) */
             DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i);
             killed++;
         }
+        if (t->running_retry) {
+            t->running_retry = 0;
+            epctx->retry = NULL;
+        }
         if (t->backgrounded) {
             t->backgrounded = 0;
         }
@@ -885,9 +948,10 @@
         xferi = epctx->next_bg;
         for (i = 0; i < BG_XFERS; i++) {
             XHCITransfer *t = &epctx->bg_transfers[xferi];
-            if (t->running) {
+            if (t->running_async) {
+                usb_cancel_packet(&t->packet);
+                t->running_async = 0;
                 t->cancelled = 1;
-                /* libusb_cancel_transfer(t->usbxfer); */
                 DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i);
                 killed++;
             }
@@ -1336,27 +1400,37 @@
 }
 #endif
 
-static int xhci_setup_packet(XHCITransfer *xfer, XHCIPort *port, int ep)
+static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
 {
-    usb_packet_setup(&xfer->packet,
-                     xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT,
-                     xfer->xhci->slots[xfer->slotid-1].devaddr,
-                     ep & 0x7f);
+    USBEndpoint *ep;
+    int dir;
+
+    dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
+    ep = usb_ep_get(dev, dir, xfer->epid >> 1);
+    usb_packet_setup(&xfer->packet, dir, ep);
     usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
     DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
-            xfer->packet.pid, xfer->packet.devaddr, xfer->packet.devep);
+            xfer->packet.pid, dev->addr, ep->nr);
     return 0;
 }
 
 static int xhci_complete_packet(XHCITransfer *xfer, int ret)
 {
     if (ret == USB_RET_ASYNC) {
-        xfer->running = 1;
+        xfer->running_async = 1;
+        xfer->running_retry = 0;
+        xfer->complete = 0;
+        xfer->cancelled = 0;
+        return 0;
+    } else if (ret == USB_RET_NAK) {
+        xfer->running_async = 0;
+        xfer->running_retry = 1;
         xfer->complete = 0;
         xfer->cancelled = 0;
         return 0;
     } else {
-        xfer->running = 0;
+        xfer->running_async = 0;
+        xfer->running_retry = 0;
         xfer->complete = 1;
     }
 
@@ -1385,6 +1459,14 @@
     return 0;
 }
 
+static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr)
+{
+    if (!(port->portsc & PORTSC_PED)) {
+        return NULL;
+    }
+    return usb_find_device(&port->port, addr);
+}
+
 static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
 {
     XHCITRB *trb_setup, *trb_status;
@@ -1444,7 +1526,7 @@
     xfer->data_length = wLength;
 
     port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
-    dev = port->port.dev;
+    dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
     if (!dev) {
         fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
                 xhci->slots[xfer->slotid-1].port);
@@ -1454,7 +1536,7 @@
     xfer->in_xfer = bmRequestType & USB_DIR_IN;
     xfer->iso_xfer = false;
 
-    xhci_setup_packet(xfer, port, 0);
+    xhci_setup_packet(xfer, dev);
     if (!xfer->in_xfer) {
         xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
     }
@@ -1463,7 +1545,7 @@
                                     wValue, wIndex, wLength, xfer->data);
 
     xhci_complete_packet(xfer, ret);
-    if (!xfer->running) {
+    if (!xfer->running_async && !xfer->running_retry) {
         xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
     }
     return 0;
@@ -1476,12 +1558,8 @@
     int ret;
 
     DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
-    uint8_t ep = xfer->epid>>1;
 
     xfer->in_xfer = epctx->type>>2;
-    if (xfer->in_xfer) {
-        ep |= 0x80;
-    }
 
     if (xfer->data && xfer->data_alloced < xfer->data_length) {
         xfer->data_alloced = 0;
@@ -1502,14 +1580,14 @@
     }
 
     port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
-    dev = port->port.dev;
+    dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr);
     if (!dev) {
         fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
                 xhci->slots[xfer->slotid-1].port);
         return -1;
     }
 
-    xhci_setup_packet(xfer, port, ep);
+    xhci_setup_packet(xfer, dev);
 
     switch(epctx->type) {
     case ET_INTR_OUT:
@@ -1522,8 +1600,9 @@
         FIXME();
         break;
     default:
-        fprintf(stderr, "xhci: unknown or unhandled EP type %d (ep %02x)\n",
-                epctx->type, ep);
+        fprintf(stderr, "xhci: unknown or unhandled EP "
+                "(type %d, in %d, ep %02x)\n",
+                epctx->type, xfer->in_xfer, xfer->epid);
         return -1;
     }
 
@@ -1533,7 +1612,7 @@
     ret = usb_handle_packet(dev, &xfer->packet);
 
     xhci_complete_packet(xfer, ret);
-    if (!xfer->running) {
+    if (!xfer->running_async && !xfer->running_retry) {
         xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
     }
     return 0;
@@ -1604,6 +1683,25 @@
         return;
     }
 
+    if (epctx->retry) {
+        /* retry nak'ed transfer */
+        XHCITransfer *xfer = epctx->retry;
+        int result;
+
+        DPRINTF("xhci: retry nack'ed transfer ...\n");
+        assert(xfer->running_retry);
+        xhci_setup_packet(xfer, xfer->packet.ep->dev);
+        result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
+        if (result == USB_RET_NAK) {
+            DPRINTF("xhci: ... xfer still nacked\n");
+            return;
+        }
+        DPRINTF("xhci: ... result %d\n", result);
+        xhci_complete_packet(xfer, result);
+        assert(!xfer->running_retry);
+        epctx->retry = NULL;
+    }
+
     if (epctx->state == EP_HALTED) {
         DPRINTF("xhci: ep halted, not running schedule\n");
         return;
@@ -1613,9 +1711,13 @@
 
     while (1) {
         XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
-        if (xfer->running || xfer->backgrounded) {
-            DPRINTF("xhci: ep is busy\n");
+        if (xfer->running_async || xfer->running_retry || xfer->backgrounded) {
+            DPRINTF("xhci: ep is busy (#%d,%d,%d,%d)\n",
+                    epctx->next_xfer, xfer->running_async,
+                    xfer->running_retry, xfer->backgrounded);
             break;
+        } else {
+            DPRINTF("xhci: ep: using #%d\n", epctx->next_xfer);
         }
         length = xhci_ring_chain_length(xhci, &epctx->ring);
         if (length < 0) {
@@ -1658,10 +1760,19 @@
             }
         }
 
+        if (epctx->state == EP_HALTED) {
+            DPRINTF("xhci: ep halted, stopping schedule\n");
+            break;
+        }
+        if (xfer->running_retry) {
+            DPRINTF("xhci: xfer nacked, stopping schedule\n");
+            epctx->retry = xfer;
+            break;
+        }
+
         /*
          * Qemu usb can't handle multiple in-flight xfers.
-         * Also xfers might be finished here already,
-         * possibly with an error.  Stop here for now.
+         * Stop here for now.
          */
         break;
     }
@@ -2346,9 +2457,7 @@
         /* write-1-to-start bits */
         if (val & PORTSC_PR) {
             DPRINTF("xhci: port %d reset\n", port);
-            if (xhci->ports[port].port.dev) {
-                usb_send_msg(xhci->ports[port].port.dev, USB_MSG_RESET);
-            }
+            usb_device_reset(xhci->ports[port].port.dev);
             portsc |= PORTSC_PRC | PORTSC_PED;
         }
         xhci->ports[port].portsc = portsc;
@@ -2633,6 +2742,26 @@
     xhci_update_port(xhci, port, 1);
 }
 
+static void xhci_wakeup(USBPort *usbport)
+{
+    XHCIState *xhci = usbport->opaque;
+    XHCIPort *port = &xhci->ports[usbport->index];
+    int nr = port->port.index + 1;
+    XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
+    uint32_t pls;
+
+    pls = (port->portsc >> PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK;
+    if (pls != 3) {
+        return;
+    }
+    port->portsc |= 0xf << PORTSC_PLS_SHIFT;
+    if (port->portsc & PORTSC_PLC) {
+        return;
+    }
+    port->portsc |= PORTSC_PLC;
+    xhci_event(xhci, &ev);
+}
+
 static void xhci_complete(USBPort *port, USBPacket *packet)
 {
     XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
@@ -2649,11 +2778,53 @@
 static USBPortOps xhci_port_ops = {
     .attach   = xhci_attach,
     .detach   = xhci_detach,
+    .wakeup   = xhci_wakeup,
     .complete = xhci_complete,
     .child_detach = xhci_child_detach,
 };
 
+static int xhci_find_slotid(XHCIState *xhci, USBDevice *dev)
+{
+    XHCISlot *slot;
+    int slotid;
+
+    for (slotid = 1; slotid <= MAXSLOTS; slotid++) {
+        slot = &xhci->slots[slotid-1];
+        if (slot->devaddr == dev->addr) {
+            return slotid;
+        }
+    }
+    return 0;
+}
+
+static int xhci_find_epid(USBEndpoint *ep)
+{
+    if (ep->nr == 0) {
+        return 1;
+    }
+    if (ep->pid == USB_TOKEN_IN) {
+        return ep->nr * 2 + 1;
+    } else {
+        return ep->nr * 2;
+    }
+}
+
+static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
+{
+    XHCIState *xhci = container_of(bus, XHCIState, bus);
+    int slotid;
+
+    DPRINTF("%s\n", __func__);
+    slotid = xhci_find_slotid(xhci, ep->dev);
+    if (slotid == 0 || !xhci->slots[slotid-1].enabled) {
+        DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
+        return;
+    }
+    xhci_kick_ep(xhci, slotid, xhci_find_epid(ep));
+}
+
 static USBBusOps xhci_bus_ops = {
+    .wakeup_endpoint = xhci_wakeup_endpoint,
 };
 
 static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
@@ -2667,7 +2838,10 @@
     for (i = 0; i < MAXPORTS; i++) {
         memset(&xhci->ports[i], 0, sizeof(xhci->ports[i]));
         usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i,
-                          &xhci_port_ops, USB_SPEED_MASK_HIGH);
+                          &xhci_port_ops,
+                          USB_SPEED_MASK_LOW  |
+                          USB_SPEED_MASK_FULL |
+                          USB_SPEED_MASK_HIGH);
     }
     for (i = 0; i < MAXSLOTS; i++) {
         xhci->slots[i].enabled = 0;
@@ -2752,8 +2926,9 @@
     .class_init    = xhci_class_init,
 };
 
-static void xhci_register(void)
+static void xhci_register_types(void)
 {
     type_register_static(&xhci_info);
 }
-device_init(xhci_register);
+
+type_init(xhci_register_types)
diff --git a/hw/usb.c b/hw/usb.c
index c3ff5b7..e5b8f33 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -35,7 +35,8 @@
     assert(dev->attached);
     assert(dev->state == USB_STATE_NOTATTACHED);
     port->ops->attach(port);
-    usb_send_msg(dev, USB_MSG_ATTACH);
+    dev->state = USB_STATE_ATTACHED;
+    usb_device_handle_attach(dev);
 }
 
 void usb_detach(USBPort *port)
@@ -45,24 +46,41 @@
     assert(dev != NULL);
     assert(dev->state != USB_STATE_NOTATTACHED);
     port->ops->detach(port);
-    usb_send_msg(dev, USB_MSG_DETACH);
+    dev->state = USB_STATE_NOTATTACHED;
 }
 
-void usb_reset(USBPort *port)
+void usb_port_reset(USBPort *port)
 {
     USBDevice *dev = port->dev;
 
     assert(dev != NULL);
     usb_detach(port);
     usb_attach(port);
-    usb_send_msg(dev, USB_MSG_RESET);
+    usb_device_reset(dev);
 }
 
-void usb_wakeup(USBDevice *dev)
+void usb_device_reset(USBDevice *dev)
 {
+    if (dev == NULL || !dev->attached) {
+        return;
+    }
+    dev->remote_wakeup = 0;
+    dev->addr = 0;
+    dev->state = USB_STATE_DEFAULT;
+    usb_device_handle_reset(dev);
+}
+
+void usb_wakeup(USBEndpoint *ep)
+{
+    USBDevice *dev = ep->dev;
+    USBBus *bus = usb_bus_from_device(dev);
+
     if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
         dev->port->ops->wakeup(dev->port);
     }
+    if (bus->ops->wakeup_endpoint) {
+        bus->ops->wakeup_endpoint(bus, ep);
+    }
 }
 
 /**********************/
@@ -128,8 +146,7 @@
     int request, value, index;
     int ret = 0;
 
-    if (p->devep != 0)
-        return usb_device_handle_data(s, p);
+    assert(p->ep->nr == 0);
 
     request = (s->setup_buf[0] << 8) | s->setup_buf[1];
     value   = (s->setup_buf[3] << 8) | s->setup_buf[2];
@@ -175,8 +192,7 @@
 
 static int do_token_out(USBDevice *s, USBPacket *p)
 {
-    if (p->devep != 0)
-        return usb_device_handle_data(s, p);
+    assert(p->ep->nr == 0);
 
     switch(s->setup_state) {
     case SETUP_STATE_ACK:
@@ -209,51 +225,6 @@
     }
 }
 
-/*
- * Generic packet handler.
- * Called by the HC (host controller).
- *
- * Returns length of the transaction or one of the USB_RET_XXX codes.
- */
-int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
-{
-    switch(p->pid) {
-    case USB_MSG_ATTACH:
-        s->state = USB_STATE_ATTACHED;
-        usb_device_handle_attach(s);
-        return 0;
-
-    case USB_MSG_DETACH:
-        s->state = USB_STATE_NOTATTACHED;
-        return 0;
-
-    case USB_MSG_RESET:
-        s->remote_wakeup = 0;
-        s->addr = 0;
-        s->state = USB_STATE_DEFAULT;
-        usb_device_handle_reset(s);
-        return 0;
-    }
-
-    /* Rest of the PIDs must match our address */
-    if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr)
-        return USB_RET_NODEV;
-
-    switch (p->pid) {
-    case USB_TOKEN_SETUP:
-        return do_token_setup(s, p);
-
-    case USB_TOKEN_IN:
-        return do_token_in(s, p);
-
-    case USB_TOKEN_OUT:
-        return do_token_out(s, p);
- 
-    default:
-        return USB_RET_STALL;
-    }
-}
-
 /* ctrl complete function for devices which use usb_generic_handle_packet and
    may return USB_RET_ASYNC from their handle_control callback. Device code
    which does this *must* call this function instead of the normal
@@ -301,17 +272,39 @@
     return q - buf;
 }
 
-/* Send an internal message to a USB device.  */
-void usb_send_msg(USBDevice *dev, int msg)
+USBDevice *usb_find_device(USBPort *port, uint8_t addr)
 {
-    USBPacket p;
-    int ret;
+    USBDevice *dev = port->dev;
 
-    memset(&p, 0, sizeof(p));
-    p.pid = msg;
-    ret = usb_handle_packet(dev, &p);
-    /* This _must_ be synchronous */
-    assert(ret != USB_RET_ASYNC);
+    if (dev == NULL || !dev->attached || dev->state != USB_STATE_DEFAULT) {
+        return NULL;
+    }
+    if (dev->addr == addr) {
+        return dev;
+    }
+    return usb_device_find_device(dev, addr);
+}
+
+static int usb_process_one(USBPacket *p)
+{
+    USBDevice *dev = p->ep->dev;
+
+    if (p->ep->nr == 0) {
+        /* control pipe */
+        switch (p->pid) {
+        case USB_TOKEN_SETUP:
+            return do_token_setup(dev, p);
+        case USB_TOKEN_IN:
+            return do_token_in(dev, p);
+        case USB_TOKEN_OUT:
+            return do_token_out(dev, p);
+        default:
+            return USB_RET_STALL;
+        }
+    } else {
+        /* data pipe */
+        return usb_device_handle_data(dev, p);
+    }
 }
 
 /* Hand over a packet to a device for processing.  Return value
@@ -321,17 +314,27 @@
 {
     int ret;
 
-    assert(p->owner == NULL);
-    ret = usb_device_handle_packet(dev, p);
-    if (ret == USB_RET_ASYNC) {
-        if (p->owner == NULL) {
-            p->owner = usb_ep_get(dev, p->pid, p->devep);
+    if (dev == NULL) {
+        return USB_RET_NODEV;
+    }
+    assert(dev == p->ep->dev);
+    assert(dev->state == USB_STATE_DEFAULT);
+    assert(p->state == USB_PACKET_SETUP);
+    assert(p->ep != NULL);
+
+    if (QTAILQ_EMPTY(&p->ep->queue)) {
+        ret = usb_process_one(p);
+        if (ret == USB_RET_ASYNC) {
+            usb_packet_set_state(p, USB_PACKET_ASYNC);
+            QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
         } else {
-            /* We'll end up here when usb_handle_packet is called
-             * recursively due to a hub being in the chain.  Nothing
-             * to do.  Leave p->owner pointing to the device, not the
-             * hub. */;
+            p->result = ret;
+            usb_packet_set_state(p, USB_PACKET_COMPLETE);
         }
+    } else {
+        ret = USB_RET_ASYNC;
+        usb_packet_set_state(p, USB_PACKET_QUEUED);
+        QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
     }
     return ret;
 }
@@ -341,10 +344,28 @@
    handle_packet. */
 void usb_packet_complete(USBDevice *dev, USBPacket *p)
 {
-    /* Note: p->owner != dev is possible in case dev is a hub */
-    assert(p->owner != NULL);
-    p->owner = NULL;
+    USBEndpoint *ep = p->ep;
+    int ret;
+
+    assert(p->state == USB_PACKET_ASYNC);
+    assert(QTAILQ_FIRST(&ep->queue) == p);
+    usb_packet_set_state(p, USB_PACKET_COMPLETE);
+    QTAILQ_REMOVE(&ep->queue, p, queue);
     dev->port->ops->complete(dev->port, p);
+
+    while (!QTAILQ_EMPTY(&ep->queue)) {
+        p = QTAILQ_FIRST(&ep->queue);
+        assert(p->state == USB_PACKET_QUEUED);
+        ret = usb_process_one(p);
+        if (ret == USB_RET_ASYNC) {
+            usb_packet_set_state(p, USB_PACKET_ASYNC);
+            break;
+        }
+        p->result = ret;
+        usb_packet_set_state(p, USB_PACKET_COMPLETE);
+        QTAILQ_REMOVE(&ep->queue, p, queue);
+        dev->port->ops->complete(dev->port, p);
+    }
 }
 
 /* Cancel an active packet.  The packed must have been deferred by
@@ -352,9 +373,13 @@
    completed.  */
 void usb_cancel_packet(USBPacket * p)
 {
-    assert(p->owner != NULL);
-    usb_device_cancel_packet(p->owner->dev, p);
-    p->owner = NULL;
+    bool callback = (p->state == USB_PACKET_ASYNC);
+    assert(usb_packet_is_inflight(p));
+    usb_packet_set_state(p, USB_PACKET_CANCELED);
+    QTAILQ_REMOVE(&p->ep->queue, p, queue);
+    if (callback) {
+        usb_device_cancel_packet(p->ep->dev, p);
+    }
 }
 
 
@@ -363,13 +388,50 @@
     qemu_iovec_init(&p->iov, 1);
 }
 
-void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep)
+void usb_packet_set_state(USBPacket *p, USBPacketState state)
 {
+#ifdef DEBUG
+    static const char *name[] = {
+        [USB_PACKET_UNDEFINED] = "undef",
+        [USB_PACKET_SETUP]     = "setup",
+        [USB_PACKET_QUEUED]    = "queued",
+        [USB_PACKET_ASYNC]     = "async",
+        [USB_PACKET_COMPLETE]  = "complete",
+        [USB_PACKET_CANCELED]  = "canceled",
+    };
+    static const char *rets[] = {
+        [-USB_RET_NODEV]  = "NODEV",
+        [-USB_RET_NAK]    = "NAK",
+        [-USB_RET_STALL]  = "STALL",
+        [-USB_RET_BABBLE] = "BABBLE",
+        [-USB_RET_ASYNC]  = "ASYNC",
+    };
+    char add[16] = "";
+
+    if (state == USB_PACKET_COMPLETE) {
+        if (p->result < 0) {
+            snprintf(add, sizeof(add), " - %s", rets[-p->result]);
+        } else {
+            snprintf(add, sizeof(add), " - %d", p->result);
+        }
+    }
+    fprintf(stderr, "bus %s, port %s, dev %d, ep %d: packet %p: %s -> %s%s\n",
+            p->ep->dev->qdev.parent_bus->name,
+            p->ep->dev->port->path,
+            p->ep->dev->addr, p->ep->nr,
+            p, name[p->state], name[state], add);
+#endif
+    p->state = state;
+}
+
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep)
+{
+    assert(!usb_packet_is_inflight(p));
     p->pid = pid;
-    p->devaddr = addr;
-    p->devep = ep;
+    p->ep = ep;
     p->result = 0;
     qemu_iovec_reset(&p->iov);
+    usb_packet_set_state(p, USB_PACKET_SETUP);
 }
 
 void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
@@ -408,6 +470,7 @@
 
 void usb_packet_cleanup(USBPacket *p)
 {
+    assert(!usb_packet_is_inflight(p));
     qemu_iovec_destroy(&p->iov);
 }
 
@@ -415,16 +478,24 @@
 {
     int ep;
 
+    dev->ep_ctl.nr = 0;
     dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
     dev->ep_ctl.ifnum = 0;
     dev->ep_ctl.dev = dev;
+    QTAILQ_INIT(&dev->ep_ctl.queue);
     for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
+        dev->ep_in[ep].nr = ep + 1;
+        dev->ep_out[ep].nr = ep + 1;
+        dev->ep_in[ep].pid = USB_TOKEN_IN;
+        dev->ep_out[ep].pid = USB_TOKEN_OUT;
         dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
         dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
         dev->ep_in[ep].ifnum = 0;
         dev->ep_out[ep].ifnum = 0;
         dev->ep_in[ep].dev = dev;
         dev->ep_out[ep].dev = dev;
+        QTAILQ_INIT(&dev->ep_in[ep].queue);
+        QTAILQ_INIT(&dev->ep_out[ep].queue);
     }
 }
 
@@ -472,7 +543,12 @@
 
 struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
 {
-    struct USBEndpoint *eps = pid == USB_TOKEN_IN ? dev->ep_in : dev->ep_out;
+    struct USBEndpoint *eps;
+
+    if (dev == NULL) {
+        return NULL;
+    }
+    eps = (pid == USB_TOKEN_IN) ? dev->ep_in : dev->ep_out;
     if (ep == 0) {
         return &dev->ep_ctl;
     }
diff --git a/hw/usb.h b/hw/usb.h
index 13e7c8e..4470ea8 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -39,11 +39,6 @@
 #define USB_TOKEN_IN    0x69 /* device -> host */
 #define USB_TOKEN_OUT   0xe1 /* host -> device */
 
-/* specific usb messages, also sent in the 'pid' parameter */
-#define USB_MSG_ATTACH   0x100
-#define USB_MSG_DETACH   0x101
-#define USB_MSG_RESET    0x102
-
 #define USB_RET_NODEV  (-1)
 #define USB_RET_NAK    (-2)
 #define USB_RET_STALL  (-3)
@@ -176,10 +171,13 @@
 #define USB_MAX_INTERFACES 16
 
 struct USBEndpoint {
+    uint8_t nr;
+    uint8_t pid;
     uint8_t type;
     uint8_t ifnum;
     int max_packet_size;
     USBDevice *dev;
+    QTAILQ_HEAD(, USBPacket) queue;
 };
 
 /* definition of a USB device */
@@ -234,13 +232,10 @@
     int (*init)(USBDevice *dev);
 
     /*
-     * Process USB packet.
-     * Called by the HC (Host Controller).
-     *
-     * Returns length of the transaction
-     * or one of the USB_RET_XXX codes.
+     * Walk (enabled) downstream ports, check for a matching device.
+     * Only hubs implement this.
      */
-    int (*handle_packet)(USBDevice *dev, USBPacket *p);
+    USBDevice *(*find_device)(USBDevice *dev, uint8_t addr);
 
     /*
      * Called when a packet is canceled.
@@ -297,8 +292,7 @@
     void (*wakeup)(USBPort *port);
     /*
      * Note that port->dev will be different then the device from which
-     * the packet originated when a hub is involved, if you want the orginating
-     * device use p->owner
+     * the packet originated when a hub is involved.
      */
     void (*complete)(USBPort *port, USBPacket *p);
 } USBPortOps;
@@ -316,20 +310,30 @@
 
 typedef void USBCallback(USBPacket * packet, void *opaque);
 
+typedef enum USBPacketState {
+    USB_PACKET_UNDEFINED = 0,
+    USB_PACKET_SETUP,
+    USB_PACKET_QUEUED,
+    USB_PACKET_ASYNC,
+    USB_PACKET_COMPLETE,
+    USB_PACKET_CANCELED,
+} USBPacketState;
+
 /* Structure used to hold information about an active USB packet.  */
 struct USBPacket {
     /* Data fields for use by the driver.  */
     int pid;
-    uint8_t devaddr;
-    uint8_t devep;
+    USBEndpoint *ep;
     QEMUIOVector iov;
     int result; /* transfer length or USB_RET_* status code */
     /* Internal use by the USB layer.  */
-    USBEndpoint *owner;
+    USBPacketState state;
+    QTAILQ_ENTRY(USBPacket) queue;
 };
 
 void usb_packet_init(USBPacket *p);
-void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep);
+void usb_packet_set_state(USBPacket *p, USBPacketState state);
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep);
 void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
 int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
 void usb_packet_unmap(USBPacket *p);
@@ -337,6 +341,14 @@
 void usb_packet_skip(USBPacket *p, size_t bytes);
 void usb_packet_cleanup(USBPacket *p);
 
+static inline bool usb_packet_is_inflight(USBPacket *p)
+{
+    return (p->state == USB_PACKET_QUEUED ||
+            p->state == USB_PACKET_ASYNC);
+}
+
+USBDevice *usb_find_device(USBPort *port, uint8_t addr);
+
 int usb_handle_packet(USBDevice *dev, USBPacket *p);
 void usb_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_cancel_packet(USBPacket * p);
@@ -354,12 +366,11 @@
 
 void usb_attach(USBPort *port);
 void usb_detach(USBPort *port);
-void usb_reset(USBPort *port);
-void usb_wakeup(USBDevice *dev);
-int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
+void usb_port_reset(USBPort *port);
+void usb_device_reset(USBDevice *dev);
+void usb_wakeup(USBEndpoint *ep);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
-void usb_send_msg(USBDevice *dev, int msg);
 
 /* usb-linux.c */
 USBDevice *usb_host_device_open(const char *devname);
@@ -414,6 +425,7 @@
 struct USBBusOps {
     int (*register_companion)(USBBus *bus, USBPort *ports[],
                               uint32_t portcount, uint32_t firstport);
+    void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep);
 };
 
 void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
@@ -451,7 +463,7 @@
     .offset     = vmstate_offset_value(_state, _field, USBDevice),   \
 }
 
-int usb_device_handle_packet(USBDevice *dev, USBPacket *p);
+USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr);
 
 void usb_device_cancel_packet(USBDevice *dev, USBPacket *p);
 
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index c4105e9..ae53a8b 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -154,11 +154,11 @@
     .class_init    = pci_realview_class_init,
 };
 
-static void versatile_pci_register_devices(void)
+static void versatile_pci_register_types(void)
 {
     type_register_static(&pci_vpb_info);
     type_register_static(&pci_realview_info);
     type_register_static(&versatile_pci_host_info);
 }
 
-device_init(versatile_pci_register_devices)
+type_init(versatile_pci_register_types)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 6ea0ce5..1903db6 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -382,9 +382,9 @@
     .class_init    = vpb_sic_class_init,
 };
 
-static void versatilepb_register_devices(void)
+static void versatilepb_register_types(void)
 {
     type_register_static(&vpb_sic_info);
 }
 
-device_init(versatilepb_register_devices)
+type_init(versatilepb_register_types)
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 8d3ff0d..4bcc4db 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -85,8 +85,9 @@
     .class_init    = vga_class_initfn,
 };
 
-static void vga_register(void)
+static void vga_register_types(void)
 {
     type_register_static(&vga_info);
 }
-device_init(vga_register)
+
+type_init(vga_register_types)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 974a7a9..465b643 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -96,8 +96,9 @@
     .class_init    = vga_class_init,
 };
 
-static void vga_register(void)
+static void vga_register_types(void)
 {
     type_register_static(&vga_info);
 }
-device_init(vga_register);
+
+type_init(vga_register_types)
diff --git a/hw/vga.c b/hw/vga.c
index d87c4f9..c1029db 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1777,10 +1777,11 @@
         if (!(s->cr[VGA_CRTC_MODE] & 2)) {
             addr = (addr & ~0x8000) | ((y1 & 2) << 14);
         }
+        update = full_update;
         page0 = addr;
         page1 = addr + bwidth - 1;
-        update = memory_region_get_dirty(&s->vram, page0, page1,
-                                         DIRTY_MEMORY_VGA);
+        update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
+                                          DIRTY_MEMORY_VGA);
         /* explicit invalidation for the hardware cursor */
         update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
         if (update) {
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 4f2c3e4..cffee3d 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -149,12 +149,6 @@
     .class_init    = virtconsole_class_init,
 };
 
-static void virtconsole_register(void)
-{
-    type_register_static(&virtconsole_info);
-}
-device_init(virtconsole_register)
-
 static Property virtserialport_properties[] = {
     DEFINE_PROP_CHR("chardev", VirtConsole, chr),
     DEFINE_PROP_END_OF_LIST(),
@@ -179,8 +173,10 @@
     .class_init    = virtserialport_class_init,
 };
 
-static void virtserialport_register(void)
+static void virtconsole_register_types(void)
 {
+    type_register_static(&virtconsole_info);
     type_register_static(&virtserialport_info);
 }
-device_init(virtserialport_register)
+
+type_init(virtconsole_register_types)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 93fff54..907b52a 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -930,7 +930,7 @@
     .class_init    = virtio_balloon_class_init,
 };
 
-static void virtio_pci_register_devices(void)
+static void virtio_pci_register_types(void)
 {
     type_register_static(&virtio_blk_info);
     type_register_static(&virtio_net_info);
@@ -938,4 +938,4 @@
     type_register_static(&virtio_balloon_info);
 }
 
-device_init(virtio_pci_register_devices)
+type_init(virtio_pci_register_types)
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 6117629..e22940e 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -949,9 +949,9 @@
     .class_init = virtio_serial_port_class_init,
 };
 
-static void virtio_serial_register_devices(void)
+static void virtio_serial_register_types(void)
 {
     type_register_static(&virtio_serial_port_type_info);
 }
 
-device_init(virtio_serial_register_devices);
+type_init(virtio_serial_register_types)
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index fda4f89..6338efa 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -294,8 +294,9 @@
     .class_init    = vmmouse_class_initfn,
 };
 
-static void vmmouse_dev_register(void)
+static void vmmouse_register_types(void)
 {
     type_register_static(&vmmouse_info);
 }
-device_init(vmmouse_dev_register)
+
+type_init(vmmouse_register_types)
diff --git a/hw/vmport.c b/hw/vmport.c
index a2c45e1..9373be9 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -159,8 +159,9 @@
     .class_init    = vmport_class_initfn,
 };
 
-static void vmport_dev_register(void)
+static void vmport_register_types(void)
 {
     type_register_static(&vmport_info);
 }
-device_init(vmport_dev_register)
+
+type_init(vmport_register_types)
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 3f3eb21..f8afa3c 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1223,8 +1223,9 @@
     .class_init    = vmsvga_class_init,
 };
 
-static void vmsvga_register(void)
+static void vmsvga_register_types(void)
 {
     type_register_static(&vmsvga_info);
 }
-device_init(vmsvga_register);
+
+type_init(vmsvga_register_types)
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index aa0954f..fbab0bb 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -366,13 +366,6 @@
     .class_init    = via_ac97_class_init,
 };
 
-static void vt82c686b_ac97_register(void)
-{
-    type_register_static(&via_ac97_info);
-}
-
-device_init(vt82c686b_ac97_register);
-
 static int vt82c686b_mc97_initfn(PCIDevice *dev)
 {
     VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev);
@@ -414,13 +407,6 @@
     .class_init    = via_mc97_class_init,
 };
 
-static void vt82c686b_mc97_register(void)
-{
-    type_register_static(&via_mc97_info);
-}
-
-device_init(vt82c686b_mc97_register);
-
 /* vt82c686 pm init */
 static int vt82c686b_pm_initfn(PCIDevice *dev)
 {
@@ -497,13 +483,6 @@
     .class_init    = via_pm_class_init,
 };
 
-static void vt82c686b_pm_register(void)
-{
-    type_register_static(&via_pm_info);
-}
-
-device_init(vt82c686b_pm_register);
-
 static const VMStateDescription vmstate_via = {
     .name = "vt82c686b",
     .version_id = 1,
@@ -571,8 +550,12 @@
     .class_init    = via_class_init,
 };
 
-static void vt82c686b_register(void)
+static void vt82c686b_register_types(void)
 {
+    type_register_static(&via_ac97_info);
+    type_register_static(&via_mc97_info);
+    type_register_static(&via_pm_info);
     type_register_static(&via_info);
 }
-device_init(vt82c686b_register);
+
+type_init(vt82c686b_register_types)
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 41325f0..15c69db 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -448,10 +448,10 @@
     .class_init    = i6300esb_class_init,
 };
 
-static void i6300esb_register_devices(void)
+static void i6300esb_register_types(void)
 {
     watchdog_add_model(&model);
     type_register_static(&i6300esb_info);
 }
 
-device_init(i6300esb_register_devices);
+type_init(i6300esb_register_types)
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
index 8faa231..7f6c21d 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -136,10 +136,10 @@
     .class_init    = wdt_ib700_class_init,
 };
 
-static void wdt_ib700_register_devices(void)
+static void wdt_ib700_register_types(void)
 {
     watchdog_add_model(&model);
     type_register_static(&wdt_ib700_info);
 }
 
-device_init(wdt_ib700_register_devices);
+type_init(wdt_ib700_register_types)
diff --git a/hw/wm8750.c b/hw/wm8750.c
index 18afa4c..11bcec3 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -708,9 +708,9 @@
     .class_init    = wm8750_class_init,
 };
 
-static void wm8750_register_devices(void)
+static void wm8750_register_types(void)
 {
     type_register_static(&wm8750_info);
 }
 
-device_init(wm8750_register_devices)
+type_init(wm8750_register_types)
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index e757102..5a7c4cc 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -396,9 +396,9 @@
     .class_init    = xen_platform_class_init,
 };
 
-static void xen_platform_register(void)
+static void xen_platform_register_types(void)
 {
     type_register_static(&xen_platform_info);
 }
 
-device_init(xen_platform_register);
+type_init(xen_platform_register_types)
diff --git a/hw/xgmac.c b/hw/xgmac.c
index d395b1c..dd4bdc4 100644
--- a/hw/xgmac.c
+++ b/hw/xgmac.c
@@ -425,9 +425,9 @@
     .class_init    = xgmac_enet_class_init,
 };
 
-static void xgmac_enet_register(void)
+static void xgmac_enet_register_types(void)
 {
     type_register_static(&xgmac_enet_info);
 }
 
-device_init(xgmac_enet_register)
+type_init(xgmac_enet_register_types)
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index e8a5312..85dfcbf 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -508,9 +508,9 @@
     .class_init    = axidma_class_init,
 };
 
-static void xilinx_axidma_register(void)
+static void xilinx_axidma_register_types(void)
 {
     type_register_static(&axidma_info);
 }
 
-device_init(xilinx_axidma_register)
+type_init(xilinx_axidma_register_types)
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index 1ce2db4..7526273 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -894,9 +894,10 @@
     .instance_size = sizeof(struct XilinxAXIEnet),
     .class_init    = xilinx_enet_class_init,
 };
-static void xilinx_enet_register(void)
+
+static void xilinx_enet_register_types(void)
 {
     type_register_static(&xilinx_enet_info);
 }
 
-device_init(xilinx_enet_register)
+type_init(xilinx_enet_register_types)
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index 499feef..857b33d 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -249,9 +249,9 @@
     .class_init    = xilinx_ethlite_class_init,
 };
 
-static void xilinx_ethlite_register(void)
+static void xilinx_ethlite_register_types(void)
 {
     type_register_static(&xilinx_ethlite_info);
 }
 
-device_init(xilinx_ethlite_register)
+type_init(xilinx_ethlite_register_types)
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
index 73eed6d..553f848 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -182,9 +182,9 @@
     .class_init    = xilinx_intc_class_init,
 };
 
-static void xilinx_intc_register(void)
+static void xilinx_intc_register_types(void)
 {
     type_register_static(&xilinx_intc_info);
 }
 
-device_init(xilinx_intc_register)
+type_init(xilinx_intc_register_types)
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index c8236d2..3ab2f2b 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -241,9 +241,9 @@
     .class_init    = xilinx_timer_class_init,
 };
 
-static void xilinx_timer_register(void)
+static void xilinx_timer_register_types(void)
 {
     type_register_static(&xilinx_timer_info);
 }
 
-device_init(xilinx_timer_register)
+type_init(xilinx_timer_register_types)
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 1c2b908..aa0170d 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -225,9 +225,9 @@
     .class_init    = xilinx_uartlite_class_init,
 };
 
-static void xilinx_uart_register(void)
+static void xilinx_uart_register_types(void)
 {
     type_register_static(&xilinx_uartlite_info);
 }
 
-device_init(xilinx_uart_register)
+type_init(xilinx_uart_register_types)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index 07e4fc1..319624f 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -203,12 +203,12 @@
     .class_init    = xio3130_downstream_class_init,
 };
 
-static void xio3130_downstream_register(void)
+static void xio3130_downstream_register_types(void)
 {
     type_register_static(&xio3130_downstream_info);
 }
 
-device_init(xio3130_downstream_register);
+type_init(xio3130_downstream_register_types)
 
 /*
  * Local variables:
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 7887c92..34a99bb 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -177,12 +177,12 @@
     .class_init    = xio3130_upstream_class_init,
 };
 
-static void xio3130_upstream_register(void)
+static void xio3130_upstream_register_types(void)
 {
     type_register_static(&xio3130_upstream_info);
 }
 
-device_init(xio3130_upstream_register);
+type_init(xio3130_upstream_register_types)
 
 
 /*
diff --git a/hw/zaurus.c b/hw/zaurus.c
index 055df9b..72838ec 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -243,11 +243,12 @@
     .class_init    = scoop_sysbus_class_init,
 };
 
-static void scoop_register(void)
+static void scoop_register_types(void)
 {
     type_register_static(&scoop_sysbus_info);
 }
-device_init(scoop_register);
+
+type_init(scoop_register_types)
 
 /* Write the bootloader parameters memory area.  */
 
diff --git a/include/qemu/object.h b/include/qemu/object.h
index 7d50da9..69cc2ab 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -71,12 +71,12 @@
  *     .instance_size = sizeof(MyDevice),
  * };
  *
- * static void my_device_module_init(void)
+ * static void my_device_register_types(void)
  * {
  *     type_register_static(&my_device_info);
  * }
  *
- * device_init(my_device_module_init);
+ * type_init(my_device_register_types)
  *   </programlisting>
  * </example>
  *
diff --git a/kvm-all.c b/kvm-all.c
index 0b87658..c4babda 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -74,7 +74,6 @@
 #ifdef KVM_CAP_SET_GUEST_DEBUG
     struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
 #endif
-    int irqchip_in_kernel;
     int pit_in_kernel;
     int xsave, xcrs;
     int many_ioeventfds;
@@ -88,6 +87,7 @@
 };
 
 KVMState *kvm_state;
+bool kvm_kernel_irqchip;
 
 static const KVMCapabilityInfo kvm_required_capabilites[] = {
     KVM_CAP_INFO(USER_MEMORY),
@@ -193,11 +193,6 @@
     kvm_arch_reset_vcpu(env);
 }
 
-int kvm_irqchip_in_kernel(void)
-{
-    return kvm_state->irqchip_in_kernel;
-}
-
 int kvm_pit_in_kernel(void)
 {
     return kvm_state->pit_in_kernel;
@@ -742,7 +737,7 @@
     struct kvm_irq_level event;
     int ret;
 
-    assert(s->irqchip_in_kernel);
+    assert(kvm_irqchip_in_kernel());
 
     event.level = level;
     event.irq = irq;
@@ -862,7 +857,7 @@
     if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) {
         s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
     }
-    s->irqchip_in_kernel = 1;
+    kvm_kernel_irqchip = true;
 
     kvm_init_irq_routing(s);
 
@@ -1315,7 +1310,7 @@
 
 int kvm_allows_irq0_override(void)
 {
-    return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+    return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
 }
 
 void kvm_setup_guest_memory(void *start, size_t size)
diff --git a/kvm-stub.c b/kvm-stub.c
index 6c2b06b..f63a0d2 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -16,11 +16,6 @@
 #include "gdbstub.h"
 #include "kvm.h"
 
-int kvm_irqchip_in_kernel(void)
-{
-    return 0;
-}
-
 int kvm_pit_in_kernel(void)
 {
     return 0;
diff --git a/kvm.h b/kvm.h
index 40b5ffc..f9f1dc8 100644
--- a/kvm.h
+++ b/kvm.h
@@ -23,11 +23,14 @@
 #endif
 
 extern int kvm_allowed;
+extern bool kvm_kernel_irqchip;
 
 #if defined CONFIG_KVM || !defined NEED_CPU_H
-#define kvm_enabled() (kvm_allowed)
+#define kvm_enabled()           (kvm_allowed)
+#define kvm_irqchip_in_kernel() (kvm_kernel_irqchip)
 #else
-#define kvm_enabled() (0)
+#define kvm_enabled()           (0)
+#define kvm_irqchip_in_kernel() (false)
 #endif
 
 struct kvm_run;
@@ -80,7 +83,6 @@
 #endif
 
 int kvm_pit_in_kernel(void);
-int kvm_irqchip_in_kernel(void);
 
 int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
 int kvm_on_sigbus(int code, void *addr);
diff --git a/memory.c b/memory.c
index 5e77d8a..22816e2 100644
--- a/memory.c
+++ b/memory.c
@@ -1609,23 +1609,31 @@
             ml->printed = false;
             QTAILQ_INSERT_TAIL(alias_print_queue, ml, queue);
         }
-        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): alias %s @%s "
-                   TARGET_FMT_plx "-" TARGET_FMT_plx "\n",
+        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx
+                   " (prio %d, %c%c): alias %s @%s " TARGET_FMT_plx
+                   "-" TARGET_FMT_plx "\n",
                    base + mr->addr,
                    base + mr->addr
                    + (target_phys_addr_t)int128_get64(mr->size) - 1,
                    mr->priority,
+                   mr->readable ? 'R' : '-',
+                   !mr->readonly && !(mr->rom_device && mr->readable) ? 'W'
+                                                                      : '-',
                    mr->name,
                    mr->alias->name,
                    mr->alias_offset,
                    mr->alias_offset
                    + (target_phys_addr_t)int128_get64(mr->size) - 1);
     } else {
-        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): %s\n",
+        mon_printf(f,
+                   TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %c%c): %s\n",
                    base + mr->addr,
                    base + mr->addr
                    + (target_phys_addr_t)int128_get64(mr->size) - 1,
                    mr->priority,
+                   mr->readable ? 'R' : '-',
+                   !mr->readonly && !(mr->rom_device && mr->readable) ? 'W'
+                                                                      : '-',
                    mr->name);
     }
 
diff --git a/module.h b/module.h
index ef66730..c4ccd57 100644
--- a/module.h
+++ b/module.h
@@ -22,16 +22,16 @@
 
 typedef enum {
     MODULE_INIT_BLOCK,
-    MODULE_INIT_DEVICE,
     MODULE_INIT_MACHINE,
     MODULE_INIT_QAPI,
+    MODULE_INIT_QOM,
     MODULE_INIT_MAX
 } module_init_type;
 
 #define block_init(function) module_init(function, MODULE_INIT_BLOCK)
-#define device_init(function) module_init(function, MODULE_INIT_DEVICE)
 #define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
 #define qapi_init(function) module_init(function, MODULE_INIT_QAPI)
+#define type_init(function) module_init(function, MODULE_INIT_QOM)
 
 void register_module_init(void (*fn)(void), module_init_type type);
 
diff --git a/qemu-common.h b/qemu-common.h
index 9b997f8..c5e9cad 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -335,6 +335,8 @@
 void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
                             size_t skip);
 
+bool buffer_is_zero(const void *buf, size_t len);
+
 void qemu_progress_init(int enabled, float min_skip);
 void qemu_progress_end(void);
 void qemu_progress_print(float delta, int max);
diff --git a/qemu-config.c b/qemu-config.c
index b030205..c9763e0 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -118,6 +118,32 @@
     },
 };
 
+static QemuOptsList qemu_iscsi_opts = {
+    .name = "iscsi",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head),
+    .desc = {
+        {
+            .name = "user",
+            .type = QEMU_OPT_STRING,
+            .help = "username for CHAP authentication to target",
+        },{
+            .name = "password",
+            .type = QEMU_OPT_STRING,
+            .help = "password for CHAP authentication to target",
+        },{
+            .name = "header-digest",
+            .type = QEMU_OPT_STRING,
+            .help = "HeaderDigest setting. "
+                    "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}",
+        },{
+            .name = "initiator-name",
+            .type = QEMU_OPT_STRING,
+            .help = "Initiator iqn name to use when connecting",
+        },
+        { /* end of list */ }
+    },
+};
+
 static QemuOptsList qemu_chardev_opts = {
     .name = "chardev",
     .implied_opt_name = "backend",
@@ -521,6 +547,7 @@
 static QemuOptsList qemu_machine_opts = {
     .name = "machine",
     .implied_opt_name = "type",
+    .merge_lists = true,
     .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
     .desc = {
         {
@@ -535,6 +562,10 @@
             .name = "kernel_irqchip",
             .type = QEMU_OPT_BOOL,
             .help = "use KVM in-kernel irqchip",
+        }, {
+            .name = "kvm_shadow_mem",
+            .type = QEMU_OPT_SIZE,
+            .help = "KVM shadow MMU size",
         },
         { /* End of list */ }
     },
@@ -580,6 +611,7 @@
     &qemu_option_rom_opts,
     &qemu_machine_opts,
     &qemu_boot_opts,
+    &qemu_iscsi_opts,
     NULL,
 };
 
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 11f4166..83b2ad5 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -730,6 +730,57 @@
 iscsi://<host>/<target-iqn-name>/<lun>
 @end example
 
+Various session related parameters can be set via special options, either
+in a configuration file provided via '-readconfig' or directly on the
+command line.
+
+@example
+Setting a specific initiator name to use when logging in to the target
+-iscsi initiator-name=iqn.qemu.test:my-initiator
+@end example
+
+@example
+Controlling which type of header digest to negotiate with the target
+-iscsi header-digest=CRC32C|CRC32C-NONE|NONE-CRC32C|NONE
+@end example
+
+These can also be set via a configuration file
+@example
+[iscsi]
+  user = "CHAP username"
+  password = "CHAP password"
+  initiator-name = "iqn.qemu.test:my-initiator"
+  # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE
+  header-digest = "CRC32C"
+@end example
+
+
+Setting the target name allows different options for different targets
+@example
+[iscsi "iqn.target.name"]
+  user = "CHAP username"
+  password = "CHAP password"
+  initiator-name = "iqn.qemu.test:my-initiator"
+  # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE
+  header-digest = "CRC32C"
+@end example
+
+
+Howto use a configuration file to set iSCSI configuration options:
+@example
+cat >iscsi.conf <<EOF
+[iscsi]
+  user = "me"
+  password = "my password"
+  initiator-name = "iqn.qemu.test:my-initiator"
+  header-digest = "CRC32C"
+EOF
+
+qemu-system-i386 -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
+    -readconfig iscsi.conf
+@end example
+
+
 Howto set up a simple iSCSI target on loopback and accessing it via QEMU:
 @example
 This example shows how to set up an iSCSI target with one CDROM and one DISK
@@ -744,7 +795,8 @@
     -b /IMAGES/cd.iso --device-type=cd
 tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
 
-qemu-system-i386 -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
+qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \
+    -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \
     -cdrom iscsi://127.0.0.1/iqn.qemu.test/2
 @end example
 
diff --git a/qemu-img.c b/qemu-img.c
index 01cc0d3..c4bcf41 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -515,40 +515,6 @@
 }
 
 /*
- * Checks whether the sector is not a zero sector.
- *
- * Attention! The len must be a multiple of 4 * sizeof(long) due to
- * restriction of optimizations in this function.
- */
-static int is_not_zero(const uint8_t *sector, int len)
-{
-    /*
-     * Use long as the biggest available internal data type that fits into the
-     * CPU register and unroll the loop to smooth out the effect of memory
-     * latency.
-     */
-
-    int i;
-    long d0, d1, d2, d3;
-    const long * const data = (const long *) sector;
-
-    len /= sizeof(long);
-
-    for(i = 0; i < len; i += 4) {
-        d0 = data[i + 0];
-        d1 = data[i + 1];
-        d2 = data[i + 2];
-        d3 = data[i + 3];
-
-        if (d0 || d1 || d2 || d3) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-/*
  * Returns true iff the first sector pointed to by 'buf' contains at least
  * a non-NUL byte.
  *
@@ -557,20 +523,22 @@
  */
 static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
 {
-    int v, i;
+    bool is_zero;
+    int i;
 
     if (n <= 0) {
         *pnum = 0;
         return 0;
     }
-    v = is_not_zero(buf, 512);
+    is_zero = buffer_is_zero(buf, 512);
     for(i = 1; i < n; i++) {
         buf += 512;
-        if (v != is_not_zero(buf, 512))
+        if (is_zero != buffer_is_zero(buf, 512)) {
             break;
+        }
     }
     *pnum = i;
-    return v;
+    return !is_zero;
 }
 
 /*
@@ -955,7 +923,7 @@
             if (n < cluster_sectors) {
                 memset(buf + n * 512, 0, cluster_size - n * 512);
             }
-            if (is_not_zero(buf, cluster_size)) {
+            if (!buffer_is_zero(buf, cluster_size)) {
                 ret = bdrv_write_compressed(out_bs, sector_num, buf,
                                             cluster_sectors);
                 if (ret != 0) {
diff --git a/qemu-io.c b/qemu-io.c
index d4a5fcb..0249be4 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -218,6 +218,51 @@
     return 1;
 }
 
+typedef struct {
+    int64_t offset;
+    int count;
+    int *total;
+    int ret;
+    bool done;
+} CoWriteZeroes;
+
+static void coroutine_fn co_write_zeroes_entry(void *opaque)
+{
+    CoWriteZeroes *data = opaque;
+
+    data->ret = bdrv_co_write_zeroes(bs, data->offset / BDRV_SECTOR_SIZE,
+                                     data->count / BDRV_SECTOR_SIZE);
+    data->done = true;
+    if (data->ret < 0) {
+        *data->total = data->ret;
+        return;
+    }
+
+    *data->total = data->count;
+}
+
+static int do_co_write_zeroes(int64_t offset, int count, int *total)
+{
+    Coroutine *co;
+    CoWriteZeroes data = {
+        .offset = offset,
+        .count  = count,
+        .total  = total,
+        .done   = false,
+    };
+
+    co = qemu_coroutine_create(co_write_zeroes_entry);
+    qemu_coroutine_enter(co, &data);
+    while (!data.done) {
+        qemu_aio_wait();
+    }
+    if (data.ret < 0) {
+        return data.ret;
+    } else {
+        return 1;
+    }
+}
+
 static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
 {
     *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
@@ -643,6 +688,7 @@
 " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"
 " -q, -- quiet mode, do not show I/O statistics\n"
+" -z, -- write zeroes using bdrv_co_write_zeroes\n"
 "\n");
 }
 
@@ -654,7 +700,7 @@
     .cfunc      = write_f,
     .argmin     = 2,
     .argmax     = -1,
-    .args       = "[-abCpq] [-P pattern ] off len",
+    .args       = "[-bCpqz] [-P pattern ] off len",
     .oneline    = "writes a number of bytes at a specified offset",
     .help       = write_help,
 };
@@ -662,16 +708,16 @@
 static int write_f(int argc, char **argv)
 {
     struct timeval t1, t2;
-    int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
+    int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
     int c, cnt;
-    char *buf;
+    char *buf = NULL;
     int64_t offset;
     int count;
     /* Some compilers get confused and warn if this is not initialized.  */
     int total = 0;
     int pattern = 0xcd;
 
-    while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
+    while ((c = getopt(argc, argv, "bCpP:qz")) != EOF) {
         switch (c) {
         case 'b':
             bflag = 1;
@@ -683,6 +729,7 @@
             pflag = 1;
             break;
         case 'P':
+            Pflag = 1;
             pattern = parse_pattern(optarg);
             if (pattern < 0) {
                 return 0;
@@ -691,6 +738,9 @@
         case 'q':
             qflag = 1;
             break;
+        case 'z':
+            zflag = 1;
+            break;
         default:
             return command_usage(&write_cmd);
         }
@@ -700,8 +750,13 @@
         return command_usage(&write_cmd);
     }
 
-    if (bflag && pflag) {
-        printf("-b and -p cannot be specified at the same time\n");
+    if (bflag + pflag + zflag > 1) {
+        printf("-b, -p, or -z cannot be specified at the same time\n");
+        return 0;
+    }
+
+    if (zflag && Pflag) {
+        printf("-z and -P cannot be specified at the same time\n");
         return 0;
     }
 
@@ -732,13 +787,17 @@
         }
     }
 
-    buf = qemu_io_alloc(count, pattern);
+    if (!zflag) {
+        buf = qemu_io_alloc(count, pattern);
+    }
 
     gettimeofday(&t1, NULL);
     if (pflag) {
         cnt = do_pwrite(buf, offset, count, &total);
     } else if (bflag) {
         cnt = do_save_vmstate(buf, offset, count, &total);
+    } else if (zflag) {
+        cnt = do_co_write_zeroes(offset, count, &total);
     } else {
         cnt = do_write(buf, offset, count, &total);
     }
@@ -758,7 +817,9 @@
     print_report("wrote", &t2, offset, count, total, cnt, Cflag);
 
 out:
-    qemu_io_free(buf);
+    if (!zflag) {
+        qemu_io_free(buf);
+    }
 
     return 0;
 }
diff --git a/qemu-option.c b/qemu-option.c
index 4626ccf..35cd609 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -741,13 +741,18 @@
         }
         opts = qemu_opts_find(list, id);
         if (opts != NULL) {
-            if (fail_if_exists) {
+            if (fail_if_exists && !list->merge_lists) {
                 qerror_report(QERR_DUPLICATE_ID, id, list->name);
                 return NULL;
             } else {
                 return opts;
             }
         }
+    } else if (list->merge_lists) {
+        opts = qemu_opts_find(list, NULL);
+        if (opts) {
+            return opts;
+        }
     }
     opts = g_malloc0(sizeof(*opts));
     if (id) {
diff --git a/qemu-option.h b/qemu-option.h
index e6f61e6..3ca00c3 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -100,6 +100,7 @@
 struct QemuOptsList {
     const char *name;
     const char *implied_opt_name;
+    bool merge_lists;  /* Merge multiple uses of option into a single list? */
     QTAILQ_HEAD(, QemuOpts) head;
     QemuOptDesc desc[];
 };
diff --git a/qemu-options.hx b/qemu-options.hx
index f577cc8..b129996 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -32,7 +32,8 @@
     "                selects emulated machine (-machine ? for list)\n"
     "                property accel=accel1[:accel2[:...]] selects accelerator\n"
     "                supported accelerators are kvm, xen, tcg (default: tcg)\n"
-    "                kernel_irqchip=on|off controls accelerated irqchip support\n",
+    "                kernel_irqchip=on|off controls accelerated irqchip support\n"
+    "                kvm_shadow_mem=size of KVM shadow MMU\n",
     QEMU_ARCH_ALL)
 STEXI
 @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -47,6 +48,8 @@
 to initialize.
 @item kernel_irqchip=on|off
 Enables in-kernel irqchip support for the chosen accelerator when available.
+@item kvm_shadow_mem=size
+Defines the size of the KVM shadow MMU.
 @end table
 ETEXI
 
@@ -1095,6 +1098,19 @@
 adaptive encodings allows to restore the original static behavior of encodings
 like Tight.
 
+@item share=[allow-exclusive|force-shared|ignore]
+
+Set display sharing policy.  'allow-exclusive' allows clients to ask
+for exclusive access.  As suggested by the rfb spec this is
+implemented by dropping other connections.  Connecting multiple
+clients in parallel requires all clients asking for a shared session
+(vncviewer: -shared switch).  This is the default.  'force-shared'
+disables exclusive client access.  Useful for shared desktop sessions,
+where you don't want someone forgetting specify -shared disconnect
+everybody else.  'ignore' completely ignores the shared flag and
+allows everybody connect unconditionally.  Doesn't conform to the rfb
+spec but is traditional qemu behavior.
+
 @end table
 ETEXI
 
@@ -1829,24 +1845,32 @@
 
 Example (without authentication):
 @example
-qemu -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
---drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+qemu -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
+-cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
+-drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
 @end example
 
 Example (CHAP username/password via URL):
 @example
-qemu --drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
+qemu -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
 @end example
 
 Example (CHAP username/password via environment variables):
 @example
 LIBISCSI_CHAP_USERNAME="user" \
 LIBISCSI_CHAP_PASSWORD="password" \
-qemu --drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
+qemu -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
 @end example
 
 iSCSI support is an optional feature of QEMU and only available when
 compiled and linked against libiscsi.
+ETEXI
+DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi,
+    "-iscsi [user=user][,password=password]\n"
+    "       [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE\n"
+    "       [,initiator-name=iqn]\n"
+    "                iSCSI session parameters\n", QEMU_ARCH_ALL)
+STEXI
 
 @item NBD
 QEMU supports NBD (Network Block Devices) both using TCP protocol as well
diff --git a/qerror.c b/qerror.c
index 8e6efaf..f55d435 100644
--- a/qerror.c
+++ b/qerror.c
@@ -572,6 +572,14 @@
     }
 }
 
+void assert_no_error(Error *err)
+{
+    if (err) {
+        qerror_report_err(err);
+        abort();
+    }
+}
+
 /**
  * qobject_to_qerror(): Convert a QObject into a QError
  */
diff --git a/qerror.h b/qerror.h
index e8718bf..e26c635 100644
--- a/qerror.h
+++ b/qerror.h
@@ -41,6 +41,7 @@
 void qerror_report_internal(const char *file, int linenr, const char *func,
                             const char *fmt, ...) GCC_FMT_ATTR(4, 5);
 void qerror_report_err(Error *err);
+void assert_no_error(Error *err);
 QString *qerror_format(const char *fmt, QDict *error);
 #define qerror_report(fmt, ...) \
     qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
diff --git a/qom/container.c b/qom/container.c
index 946cbff..f107208 100644
--- a/qom/container.c
+++ b/qom/container.c
@@ -19,9 +19,9 @@
     .parent        = TYPE_OBJECT,
 };
 
-static void container_init(void)
+static void container_register_types(void)
 {
     type_register_static(&container_info);
 }
 
-device_init(container_init);
+type_init(container_register_types)
diff --git a/qom/object.c b/qom/object.c
index 5e5b261..0cbd9bb 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -444,7 +444,7 @@
 }
 
 
-static void register_interface(void)
+static void register_types(void)
 {
     static TypeInfo interface_info = {
         .name = TYPE_INTERFACE,
@@ -455,7 +455,7 @@
     type_interface = type_register_static(&interface_info);
 }
 
-device_init(register_interface);
+type_init(register_types)
 
 Object *object_dynamic_cast_assert(Object *obj, const char *typename)
 {
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index 4b43994..5dbf21d 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -262,6 +262,11 @@
 #endif
   if(ip->ip_off & IP_OFFMASK) goto end_error;    /* Only reply to fragment 0 */
 
+  /* Do not reply to source-only IPs */
+  if ((ip->ip_src.s_addr & htonl(~(0xf << 28))) == 0) {
+      goto end_error;
+  }
+
   shlen=ip->ip_hl << 2;
   s_ip_len=ip->ip_len;
   if(ip->ip_p == IPPROTO_ICMP) {
diff --git a/slirp/misc.c b/slirp/misc.c
index 6c80e69..3432fbf 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -113,7 +113,6 @@
 	struct sockaddr_in addr;
 	socklen_t addrlen = sizeof(addr);
 	int opt;
-        int master = -1;
 	const char *argv[256];
 	/* don't want to clobber the original */
 	char *bptr;
@@ -148,32 +147,23 @@
 	 case -1:
 		lprint("Error: fork failed: %s\n", strerror(errno));
 		close(s);
-		if (do_pty == 2)
-		   close(master);
 		return 0;
 
 	 case 0:
                 setsid();
 
 		/* Set the DISPLAY */
-		if (do_pty == 2) {
-			(void) close(master);
-#ifdef TIOCSCTTY /* XXXXX */
-			ioctl(s, TIOCSCTTY, (char *)NULL);
-#endif
-		} else {
-			getsockname(s, (struct sockaddr *)&addr, &addrlen);
-			close(s);
-			/*
-			 * Connect to the socket
-			 * XXX If any of these fail, we're in trouble!
-	 		 */
-			s = qemu_socket(AF_INET, SOCK_STREAM, 0);
-			addr.sin_addr = loopback_addr;
-                        do {
-                            ret = connect(s, (struct sockaddr *)&addr, addrlen);
-                        } while (ret < 0 && errno == EINTR);
-		}
+                getsockname(s, (struct sockaddr *)&addr, &addrlen);
+                close(s);
+                /*
+                 * Connect to the socket
+                 * XXX If any of these fail, we're in trouble!
+                 */
+                s = qemu_socket(AF_INET, SOCK_STREAM, 0);
+                addr.sin_addr = loopback_addr;
+                do {
+                    ret = connect(s, (struct sockaddr *)&addr, addrlen);
+                } while (ret < 0 && errno == EINTR);
 
 		dup2(s, 0);
 		dup2(s, 1);
@@ -210,26 +200,21 @@
 
 	 default:
 		qemu_add_child_watch(pid);
-		if (do_pty == 2) {
-			close(s);
-			so->s = master;
-		} else {
-			/*
-			 * XXX this could block us...
-			 * XXX Should set a timer here, and if accept() doesn't
-		 	 * return after X seconds, declare it a failure
-		 	 * The only reason this will block forever is if socket()
-		 	 * of connect() fail in the child process
-		 	 */
-                        do {
-                            so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
-                        } while (so->s < 0 && errno == EINTR);
-                        closesocket(s);
-			opt = 1;
-			setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
-			opt = 1;
-			setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
-		}
+                /*
+                 * XXX this could block us...
+                 * XXX Should set a timer here, and if accept() doesn't
+                 * return after X seconds, declare it a failure
+                 * The only reason this will block forever is if socket()
+                 * of connect() fail in the child process
+                 */
+                do {
+                    so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
+                } while (so->s < 0 && errno == EINTR);
+                closesocket(s);
+                opt = 1;
+                setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
+                opt = 1;
+                setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
 		fd_nonblock(so->s);
 
 		/* Append the telnet options now */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index ea4f35f..4929372 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -157,7 +157,7 @@
          * and valid configurations; we don't model A9UP).
          */
         set_feature(env, ARM_FEATURE_V7MP);
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x41033090;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
         memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -344,6 +344,11 @@
     set_float_detect_tininess(float_tininess_before_rounding,
                               &env->vfp.standard_fp_status);
     tlb_flush(env, 1);
+    /* Reset is a state change for some CPUState fields which we
+     * bake assumptions about into translated code, so we need to
+     * tb_flush().
+     */
+    tb_flush(env);
 }
 
 static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg)
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index e41de39..981192d 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -646,7 +646,9 @@
 
 int kvm_arch_init(KVMState *s)
 {
+    QemuOptsList *list = qemu_find_opts("machine");
     uint64_t identity_base = 0xfffbc000;
+    uint64_t shadow_mem;
     int ret;
     struct utsname utsname;
 
@@ -693,6 +695,17 @@
     }
     qemu_register_reset(kvm_unpoison_all, NULL);
 
+    if (!QTAILQ_EMPTY(&list->head)) {
+        shadow_mem = qemu_opt_get_size(QTAILQ_FIRST(&list->head),
+                                       "kvm_shadow_mem", -1);
+        if (shadow_mem != -1) {
+            shadow_mem /= 4096;
+            ret = kvm_vm_ioctl(s, KVM_SET_NR_MMU_PAGES, shadow_mem);
+            if (ret < 0) {
+                return ret;
+            }
+        }
+    }
     return 0;
 }
 
@@ -1343,7 +1356,7 @@
     struct kvm_lapic_state kapic;
     int ret;
 
-    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (apic && kvm_irqchip_in_kernel()) {
         ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic);
         if (ret < 0) {
             return ret;
@@ -1359,7 +1372,7 @@
     DeviceState *apic = env->apic_state;
     struct kvm_lapic_state kapic;
 
-    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+    if (apic && kvm_irqchip_in_kernel()) {
         kvm_put_apic_state(apic, &kapic);
 
         return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic);
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index e56fac8..928fbcf 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1293,11 +1293,8 @@
 
 target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
 {
-    uint32_t tlbncfg;
-    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
     int tlbm_size;
 
-    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
     tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
 
     return 1024ULL << tlbm_size;
diff --git a/trace-events b/trace-events
index 5d05749..9b26ce2 100644
--- a/trace-events
+++ b/trace-events
@@ -67,6 +67,7 @@
 bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+bdrv_co_write_zeroes(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
 bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
 
@@ -320,7 +321,7 @@
 qed_start_need_check_timer(void *s) "s %p"
 qed_cancel_need_check_timer(void *s) "s %p"
 qed_aio_complete(void *s, void *acb, int ret) "s %p acb %p ret %d"
-qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int is_write) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p is_write %d"
+qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int flags) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p flags %#x"
 qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64
 qed_aio_read_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
 qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 5639c6f..b4629f8 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -753,8 +753,9 @@
 }
 machine_init(spice_register_config);
 
-static void spice_initialize(void)
+static void spice_register_types(void)
 {
     qemu_spice_init();
 }
-device_init(spice_initialize);
+
+type_init(spice_register_types)
diff --git a/ui/vnc.c b/ui/vnc.c
index 16b79ec..02b71bc 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -46,6 +46,30 @@
 static DisplayChangeListener *dcl;
 
 static int vnc_cursor_define(VncState *vs);
+static void vnc_release_modifiers(VncState *vs);
+
+static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
+{
+#ifdef _VNC_DEBUG
+    static const char *mn[] = {
+        [0]                           = "undefined",
+        [VNC_SHARE_MODE_CONNECTING]   = "connecting",
+        [VNC_SHARE_MODE_SHARED]       = "shared",
+        [VNC_SHARE_MODE_EXCLUSIVE]    = "exclusive",
+        [VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
+    };
+    fprintf(stderr, "%s/%d: %s -> %s\n", __func__,
+            vs->csock, mn[vs->share_mode], mn[mode]);
+#endif
+
+    if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
+        vs->vd->num_exclusive--;
+    }
+    vs->share_mode = mode;
+    if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
+        vs->vd->num_exclusive++;
+    }
+}
 
 static char *addr_to_string(const char *format,
                             struct sockaddr_storage *sa,
@@ -997,6 +1021,7 @@
 {
     if (vs->csock == -1)
         return;
+    vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
     qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
     closesocket(vs->csock);
     vs->csock = -1;
@@ -1027,6 +1052,7 @@
     vnc_sasl_client_cleanup(vs);
 #endif /* CONFIG_VNC_SASL */
     audio_del(vs);
+    vnc_release_modifiers(vs);
 
     QTAILQ_REMOVE(&vs->vd->clients, vs, next);
 
@@ -1552,9 +1578,11 @@
         else
             kbd_put_keycode(keycode | SCANCODE_UP);
     } else {
+        bool numlock = vs->modifiers_state[0x45];
+        bool control = (vs->modifiers_state[0x1d] ||
+                        vs->modifiers_state[0x9d]);
         /* QEMU console emulation */
         if (down) {
-            int numlock = vs->modifiers_state[0x45];
             switch (keycode) {
             case 0x2a:                          /* Left Shift */
             case 0x36:                          /* Right Shift */
@@ -1642,13 +1670,40 @@
                 break;
 
             default:
-                kbd_put_keysym(sym);
+                if (control) {
+                    kbd_put_keysym(sym & 0x1f);
+                } else {
+                    kbd_put_keysym(sym);
+                }
                 break;
             }
         }
     }
 }
 
+static void vnc_release_modifiers(VncState *vs)
+{
+    static const int keycodes[] = {
+        /* shift, control, alt keys, both left & right */
+        0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
+    };
+    int i, keycode;
+
+    if (!is_graphic_console()) {
+        return;
+    }
+    for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
+        keycode = keycodes[i];
+        if (!vs->modifiers_state[keycode]) {
+            continue;
+        }
+        if (keycode & SCANCODE_GREY) {
+            kbd_put_keycode(SCANCODE_EMUL0);
+        }
+        kbd_put_keycode(keycode | SCANCODE_UP);
+    }
+}
+
 static void key_event(VncState *vs, int down, uint32_t sym)
 {
     int keycode;
@@ -2048,8 +2103,67 @@
 static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
 {
     char buf[1024];
+    VncShareMode mode;
     int size;
 
+    mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
+    switch (vs->vd->share_policy) {
+    case VNC_SHARE_POLICY_IGNORE:
+        /*
+         * Ignore the shared flag.  Nothing to do here.
+         *
+         * Doesn't conform to the rfb spec but is traditional qemu
+         * behavior, thus left here as option for compatibility
+         * reasons.
+         */
+        break;
+    case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
+        /*
+         * Policy: Allow clients ask for exclusive access.
+         *
+         * Implementation: When a client asks for exclusive access,
+         * disconnect all others. Shared connects are allowed as long
+         * as no exclusive connection exists.
+         *
+         * This is how the rfb spec suggests to handle the shared flag.
+         */
+        if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
+            VncState *client;
+            QTAILQ_FOREACH(client, &vs->vd->clients, next) {
+                if (vs == client) {
+                    continue;
+                }
+                if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
+                    client->share_mode != VNC_SHARE_MODE_SHARED) {
+                    continue;
+                }
+                vnc_disconnect_start(client);
+            }
+        }
+        if (mode == VNC_SHARE_MODE_SHARED) {
+            if (vs->vd->num_exclusive > 0) {
+                vnc_disconnect_start(vs);
+                return 0;
+            }
+        }
+        break;
+    case VNC_SHARE_POLICY_FORCE_SHARED:
+        /*
+         * Policy: Shared connects only.
+         * Implementation: Disallow clients asking for exclusive access.
+         *
+         * Useful for shared desktop sessions where you don't want
+         * someone forgetting to say -shared when running the vnc
+         * client disconnect everybody else.
+         */
+        if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
+            vnc_disconnect_start(vs);
+            return 0;
+        }
+        break;
+    }
+    vnc_set_share_mode(vs, mode);
+
     vs->client_width = ds_get_width(vs->ds);
     vs->client_height = ds_get_height(vs->ds);
     vnc_write_u16(vs, vs->client_width);
@@ -2445,7 +2559,7 @@
             guest_ptr  = guest_row;
             server_ptr = server_row;
 
-            for (x = 0; x < vd->guest.ds->width;
+            for (x = 0; x + 15 < vd->guest.ds->width;
                     x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
                 if (!test_and_clear_bit((x / 16), vd->guest.dirty[y]))
                     continue;
@@ -2556,6 +2670,7 @@
 
     vnc_client_cache_addr(vs);
     vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
+    vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
 
     vs->vd = vd;
     vs->ds = vd->ds;
@@ -2749,6 +2864,7 @@
 
     if (!(vs->display = strdup(display)))
         return -1;
+    vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
 
     options = display;
     while ((options = strchr(options, ','))) {
@@ -2804,6 +2920,19 @@
             vs->lossy = true;
         } else if (strncmp(options, "non-adapative", 13) == 0) {
             vs->non_adaptive = true;
+        } else if (strncmp(options, "share=", 6) == 0) {
+            if (strncmp(options+6, "ignore", 6) == 0) {
+                vs->share_policy = VNC_SHARE_POLICY_IGNORE;
+            } else if (strncmp(options+6, "allow-exclusive", 15) == 0) {
+                vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+            } else if (strncmp(options+6, "force-shared", 12) == 0) {
+                vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
+            } else {
+                fprintf(stderr, "unknown vnc share= option\n");
+                g_free(vs->display);
+                vs->display = NULL;
+                return -1;
+            }
         }
     }
 
diff --git a/ui/vnc.h b/ui/vnc.h
index 66689f1..0bd1fc6 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -122,9 +122,24 @@
     DisplaySurface *ds;
 };
 
+typedef enum VncShareMode {
+    VNC_SHARE_MODE_CONNECTING = 1,
+    VNC_SHARE_MODE_SHARED,
+    VNC_SHARE_MODE_EXCLUSIVE,
+    VNC_SHARE_MODE_DISCONNECTED,
+} VncShareMode;
+
+typedef enum VncSharePolicy {
+    VNC_SHARE_POLICY_IGNORE = 1,
+    VNC_SHARE_POLICY_ALLOW_EXCLUSIVE,
+    VNC_SHARE_POLICY_FORCE_SHARED,
+} VncSharePolicy;
+
 struct VncDisplay
 {
     QTAILQ_HEAD(, VncState) clients;
+    int num_exclusive;
+    VncSharePolicy share_policy;
     QEMUTimer *timer;
     int timer_interval;
     int lsock;
@@ -250,6 +265,7 @@
     int last_y;
     int client_width;
     int client_height;
+    VncShareMode share_mode;
 
     uint32_t vnc_encoding;
 
diff --git a/usb-bsd.c b/usb-bsd.c
index fc722b3..4fa4b42 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -214,7 +214,7 @@
     int ret, fd, mode;
     int one = 1, shortpacket = 0, timeout = 50;
     sigset_t new_mask, old_mask;
-    uint8_t devep = p->devep;
+    uint8_t devep = p->ep->nr;
 
     /* protect data transfers from SIGALRM signal */
     sigemptyset(&new_mask);
@@ -403,7 +403,6 @@
 
     uc->product_desc   = "USB Host Device";
     uc->init           = usb_host_initfn;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->handle_reset   = usb_host_handle_reset;
     uc->handle_control = usb_host_handle_control;
     uc->handle_data    = usb_host_handle_data;
@@ -417,11 +416,12 @@
     .class_init    = usb_host_class_initfn,
 };
 
-static void usb_host_register_devices(void)
+static void usb_host_register_types(void)
 {
     type_register_static(&usb_host_dev_info);
 }
-device_init(usb_host_register_devices)
+
+type_init(usb_host_register_types)
 
 static int usb_host_scan(void *opaque, USBScanFunc *func)
 {
diff --git a/usb-linux.c b/usb-linux.c
index e7fc9ec..24700fc 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -137,7 +137,7 @@
         [USB_ENDPOINT_XFER_BULK]    = USBDEVFS_URB_TYPE_BULK,
         [USB_ENDPOINT_XFER_INT]     = USBDEVFS_URB_TYPE_INTERRUPT,
     };
-    uint8_t type = usb_ep_get_type(&s->dev, p->pid, p->devep);
+    uint8_t type = p->ep->type;
     assert(type < ARRAY_SIZE(usbfs));
     return usbfs[type];
 }
@@ -360,7 +360,7 @@
                 break;
 
             case -EPIPE:
-                set_halt(s, p->pid, p->devep);
+                set_halt(s, p->pid, p->ep->nr);
                 p->result = USB_RET_STALL;
                 break;
 
@@ -733,16 +733,16 @@
     int i, j, ret, max_packet_size, offset, len = 0;
     uint8_t *buf;
 
-    max_packet_size = usb_ep_get_max_packet_size(&s->dev, p->pid, p->devep);
+    max_packet_size = p->ep->max_packet_size;
     if (max_packet_size == 0)
         return USB_RET_NAK;
 
-    aurb = get_iso_urb(s, p->pid, p->devep);
+    aurb = get_iso_urb(s, p->pid, p->ep->nr);
     if (!aurb) {
-        aurb = usb_host_alloc_iso(s, p->pid, p->devep);
+        aurb = usb_host_alloc_iso(s, p->pid, p->ep->nr);
     }
 
-    i = get_iso_urb_idx(s, p->pid, p->devep);
+    i = get_iso_urb_idx(s, p->pid, p->ep->nr);
     j = aurb[i].iso_frame_idx;
     if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
         if (in) {
@@ -769,7 +769,7 @@
             }
         } else {
             len = p->iov.size;
-            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
+            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->ep->nr);
 
             /* Check the frame fits */
             if (len > max_packet_size) {
@@ -781,27 +781,27 @@
             usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
             aurb[i].urb.iso_frame_desc[j].length = len;
             offset += len;
-            set_iso_buffer_used(s, p->pid, p->devep, offset);
+            set_iso_buffer_used(s, p->pid, p->ep->nr, offset);
 
             /* Start the stream once we have buffered enough data */
-            if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
-                set_iso_started(s, p->pid, p->devep);
+            if (!is_iso_started(s, p->pid, p->ep->nr) && i == 1 && j == 8) {
+                set_iso_started(s, p->pid, p->ep->nr);
             }
         }
         aurb[i].iso_frame_idx++;
         if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
             i = (i + 1) % s->iso_urb_count;
-            set_iso_urb_idx(s, p->pid, p->devep, i);
+            set_iso_urb_idx(s, p->pid, p->ep->nr, i);
         }
     } else {
         if (in) {
-            set_iso_started(s, p->pid, p->devep);
+            set_iso_started(s, p->pid, p->ep->nr);
         } else {
             DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
         }
     }
 
-    if (is_iso_started(s, p->pid, p->devep)) {
+    if (is_iso_started(s, p->pid, p->ep->nr)) {
         /* (Re)-submit all fully consumed / filled urbs */
         for (i = 0; i < s->iso_urb_count; i++) {
             if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
@@ -821,7 +821,7 @@
                     break;
                 }
                 aurb[i].iso_frame_idx = -1;
-                change_iso_inflight(s, p->pid, p->devep, 1);
+                change_iso_inflight(s, p->pid, p->ep->nr, 1);
             }
         }
     }
@@ -840,20 +840,20 @@
 
     trace_usb_host_req_data(s->bus_num, s->addr,
                             p->pid == USB_TOKEN_IN,
-                            p->devep, p->iov.size);
+                            p->ep->nr, p->iov.size);
 
-    if (!is_valid(s, p->pid, p->devep)) {
+    if (!is_valid(s, p->pid, p->ep->nr)) {
         trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
         return USB_RET_NAK;
     }
 
     if (p->pid == USB_TOKEN_IN) {
-        ep = p->devep | 0x80;
+        ep = p->ep->nr | 0x80;
     } else {
-        ep = p->devep;
+        ep = p->ep->nr;
     }
 
-    if (is_halted(s, p->pid, p->devep)) {
+    if (is_halted(s, p->pid, p->ep->nr)) {
         unsigned int arg = ep;
         ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
         if (ret < 0) {
@@ -861,10 +861,10 @@
             trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
             return USB_RET_NAK;
         }
-        clear_halt(s, p->pid, p->devep);
+        clear_halt(s, p->pid, p->ep->nr);
     }
 
-    if (is_isoc(s, p->pid, p->devep)) {
+    if (is_isoc(s, p->pid, p->ep->nr)) {
         return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
     }
 
@@ -1057,7 +1057,7 @@
     urb = &aurb->urb;
 
     urb->type     = USBDEVFS_URB_TYPE_CONTROL;
-    urb->endpoint = p->devep;
+    urb->endpoint = p->ep->nr;
 
     urb->buffer        = &dev->setup_buf;
     urb->buffer_length = length + 8;
@@ -1419,7 +1419,6 @@
 
     uc->init           = usb_host_initfn;
     uc->product_desc   = "USB Host Device";
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->cancel_packet  = usb_host_async_cancel;
     uc->handle_data    = usb_host_handle_data;
     uc->handle_control = usb_host_handle_control;
@@ -1436,12 +1435,13 @@
     .class_init    = usb_host_class_initfn,
 };
 
-static void usb_host_register_devices(void)
+static void usb_host_register_types(void)
 {
     type_register_static(&usb_host_dev_info);
     usb_legacy_register("usb-host", "host", usb_host_device_open);
 }
-device_init(usb_host_register_devices)
+
+type_init(usb_host_register_types)
 
 USBDevice *usb_host_device_open(const char *devname)
 {
diff --git a/usb-redir.c b/usb-redir.c
index 303292a..a59b347 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -34,6 +34,7 @@
 #include <sys/ioctl.h>
 #include <signal.h>
 #include <usbredirparser.h>
+#include <usbredirfilter.h>
 
 #include "hw/usb.h"
 
@@ -72,6 +73,7 @@
     /* Properties */
     CharDriverState *cs;
     uint8_t debug;
+    char *filter_str;
     /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
     const uint8_t *read_buf;
     int read_buf_size;
@@ -84,6 +86,11 @@
     struct endp_data endpoint[MAX_ENDPOINTS];
     uint32_t packet_id;
     QTAILQ_HEAD(, AsyncURB) asyncq;
+    /* Data for device filtering */
+    struct usb_redir_device_connect_header device_info;
+    struct usb_redir_interface_info_header interface_info;
+    struct usbredirfilter_rule *filter_rules;
+    int filter_rules_count;
 };
 
 struct AsyncURB {
@@ -603,7 +610,7 @@
     USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
     uint8_t ep;
 
-    ep = p->devep;
+    ep = p->ep->nr;
     if (p->pid == USB_TOKEN_IN) {
         ep |= USB_DIR_IN;
     }
@@ -780,6 +787,7 @@
 static void usbredir_open_close_bh(void *opaque)
 {
     USBRedirDevice *dev = opaque;
+    uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
 
     usbredir_device_disconnect(dev);
 
@@ -810,7 +818,9 @@
         dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
         dev->read_buf = NULL;
         dev->read_buf_size = 0;
-        usbredirparser_init(dev->parser, VERSION, NULL, 0, 0);
+
+        usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
+        usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0);
         usbredirparser_do_write(dev->parser);
     }
 }
@@ -880,6 +890,17 @@
         return -1;
     }
 
+    if (dev->filter_str) {
+        i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|",
+                                           &dev->filter_rules,
+                                           &dev->filter_rules_count);
+        if (i) {
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "filter",
+                          "a usb device filter string");
+            return -1;
+        }
+    }
+
     dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev);
     dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
 
@@ -929,6 +950,44 @@
     if (dev->parser) {
         usbredirparser_destroy(dev->parser);
     }
+
+    free(dev->filter_rules);
+}
+
+static int usbredir_check_filter(USBRedirDevice *dev)
+{
+    if (dev->interface_info.interface_count == 0) {
+        ERROR("No interface info for device\n");
+        return -1;
+    }
+
+    if (dev->filter_rules) {
+        if (!usbredirparser_peer_has_cap(dev->parser,
+                                    usb_redir_cap_connect_device_version)) {
+            ERROR("Device filter specified and peer does not have the "
+                  "connect_device_version capability\n");
+            return -1;
+        }
+
+        if (usbredirfilter_check(
+                dev->filter_rules,
+                dev->filter_rules_count,
+                dev->device_info.device_class,
+                dev->device_info.device_subclass,
+                dev->device_info.device_protocol,
+                dev->interface_info.interface_class,
+                dev->interface_info.interface_subclass,
+                dev->interface_info.interface_protocol,
+                dev->interface_info.interface_count,
+                dev->device_info.vendor_id,
+                dev->device_info.product_id,
+                dev->device_info.device_version_bcd,
+                0) != 0) {
+            return -1;
+        }
+    }
+
+    return 0;
 }
 
 /*
@@ -957,6 +1016,7 @@
     struct usb_redir_device_connect_header *device_connect)
 {
     USBRedirDevice *dev = priv;
+    const char *speed;
 
     if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
         ERROR("Received device connect while already connected\n");
@@ -965,26 +1025,48 @@
 
     switch (device_connect->speed) {
     case usb_redir_speed_low:
-        DPRINTF("attaching low speed device\n");
+        speed = "low speed";
         dev->dev.speed = USB_SPEED_LOW;
         break;
     case usb_redir_speed_full:
-        DPRINTF("attaching full speed device\n");
+        speed = "full speed";
         dev->dev.speed = USB_SPEED_FULL;
         break;
     case usb_redir_speed_high:
-        DPRINTF("attaching high speed device\n");
+        speed = "high speed";
         dev->dev.speed = USB_SPEED_HIGH;
         break;
     case usb_redir_speed_super:
-        DPRINTF("attaching super speed device\n");
+        speed = "super speed";
         dev->dev.speed = USB_SPEED_SUPER;
         break;
     default:
-        DPRINTF("attaching unknown speed device, assuming full speed\n");
+        speed = "unknown speed";
         dev->dev.speed = USB_SPEED_FULL;
     }
+
+    if (usbredirparser_peer_has_cap(dev->parser,
+                                    usb_redir_cap_connect_device_version)) {
+        INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
+             speed, device_connect->vendor_id, device_connect->product_id,
+             device_connect->device_version_bcd >> 8,
+             device_connect->device_version_bcd & 0xff,
+             device_connect->device_class);
+    } else {
+        INFO("attaching %s device %04x:%04x class %02x\n", speed,
+             device_connect->vendor_id, device_connect->product_id,
+             device_connect->device_class);
+    }
+
     dev->dev.speedmask = (1 << dev->dev.speed);
+    dev->device_info = *device_connect;
+
+    if (usbredir_check_filter(dev)) {
+        WARNING("Device %04x:%04x rejected by device filter, not attaching\n",
+                device_connect->vendor_id, device_connect->product_id);
+        return;
+    }
+
     qemu_mod_timer(dev->attach_timer, dev->next_attach_time);
 }
 
@@ -1011,15 +1093,27 @@
     for (i = 0; i < MAX_ENDPOINTS; i++) {
         QTAILQ_INIT(&dev->endpoint[i].bufpq);
     }
+    dev->interface_info.interface_count = 0;
 }
 
 static void usbredir_interface_info(void *priv,
     struct usb_redir_interface_info_header *interface_info)
 {
-    /* The intention is to allow specifying acceptable interface classes
-       for redirection on the cmdline and in the future verify this here,
-       and disconnect (or never connect) the device if a not accepted
-       interface class is detected */
+    USBRedirDevice *dev = priv;
+
+    dev->interface_info = *interface_info;
+
+    /*
+     * If we receive interface info after the device has already been
+     * connected (ie on a set_config), re-check the filter.
+     */
+    if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
+        if (usbredir_check_filter(dev)) {
+            ERROR("Device no longer matches filter after interface info "
+                  "change, disconnecting!\n");
+            usbredir_device_disconnect(dev);
+        }
+    }
 }
 
 static void usbredir_ep_info(void *priv,
@@ -1318,6 +1412,7 @@
 static Property usbredir_properties[] = {
     DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
     DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
+    DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -1329,7 +1424,6 @@
     uc->init           = usbredir_initfn;
     uc->product_desc   = "USB Redirection Device";
     uc->handle_destroy = usbredir_handle_destroy;
-    uc->handle_packet  = usb_generic_handle_packet;
     uc->cancel_packet  = usbredir_cancel_packet;
     uc->handle_reset   = usbredir_handle_reset;
     uc->handle_data    = usbredir_handle_data;
@@ -1344,8 +1438,9 @@
     .class_init    = usbredir_class_initfn,
 };
 
-static void usbredir_register_devices(void)
+static void usbredir_register_types(void)
 {
     type_register_static(&usbredir_dev_info);
 }
-device_init(usbredir_register_devices);
+
+type_init(usbredir_register_types)
diff --git a/vl.c b/vl.c
index c4b3aab..9609d2b 100644
--- a/vl.c
+++ b/vl.c
@@ -2529,6 +2529,14 @@
                     exit(1);
                 }
                 break;
+#ifdef CONFIG_LIBISCSI
+            case QEMU_OPTION_iscsi:
+                opts = qemu_opts_parse(qemu_find_opts("iscsi"), optarg, 0);
+                if (!opts) {
+                    exit(1);
+                }
+                break;
+#endif
 #ifdef CONFIG_SLIRP
             case QEMU_OPTION_tftp:
                 legacy_tftp_prefix = optarg;
@@ -2874,12 +2882,10 @@
                 break;
             case QEMU_OPTION_enable_kvm:
                 olist = qemu_find_opts("machine");
-                qemu_opts_reset(olist);
                 qemu_opts_parse(olist, "accel=kvm", 0);
                 break;
             case QEMU_OPTION_machine:
                 olist = qemu_find_opts("machine");
-                qemu_opts_reset(olist);
                 opts = qemu_opts_parse(olist, optarg, 1);
                 if (!opts) {
                     fprintf(stderr, "parse error: %s\n", optarg);
@@ -3361,7 +3367,7 @@
     if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0)
         exit(1);
 
-    module_call_init(MODULE_INIT_DEVICE);
+    module_call_init(MODULE_INIT_QOM);
 
     /* must be after qdev registration but before machine init */
     if (vga_model) {