diff options
289 files changed, 3632 insertions, 1708 deletions
@@ -114,8 +114,6 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS) QEMU_CFLAGS+=$(CURL_CFLAGS) -QEMU_CFLAGS+=$(GLIB_CFLAGS) - QEMU_CFLAGS += -I$(SRC_PATH)/include ui/cocoa.o: ui/cocoa.m diff --git a/Makefile.hw b/Makefile.hw index 7b8d068c94..33f1ab0183 100644 --- a/Makefile.hw +++ b/Makefile.hw @@ -10,7 +10,6 @@ include $(SRC_PATH)/rules.mak $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) QEMU_CFLAGS+=-I.. -QEMU_CFLAGS += $(GLIB_CFLAGS) QEMU_CFLAGS += -I$(SRC_PATH)/include include $(SRC_PATH)/Makefile.objs diff --git a/Makefile.objs b/Makefile.objs index ec35320ff5..391e524525 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -323,8 +323,6 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-proxy.o hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y)) -$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS) - ###################################################################### # libdis diff --git a/Makefile.target b/Makefile.target index 68481a3a6c..29fde6e982 100644 --- a/Makefile.target +++ b/Makefile.target @@ -29,10 +29,17 @@ ifdef CONFIG_USER_ONLY QEMU_PROG=qemu-$(TARGET_ARCH2) else # system emulator name +ifneq (,$(findstring -mwindows,$(LIBS))) +# Terminate program name with a 'w' because the linker builds a windows executable. +QEMU_PROGW=qemu-system-$(TARGET_ARCH2)w$(EXESUF) +endif # windows executable QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF) endif PROGS=$(QEMU_PROG) +ifdef QEMU_PROGW +PROGS+=$(QEMU_PROGW) +endif STPFILES= ifndef CONFIG_HAIKU @@ -208,7 +215,6 @@ QEMU_CFLAGS += $(VNC_TLS_CFLAGS) QEMU_CFLAGS += $(VNC_SASL_CFLAGS) QEMU_CFLAGS += $(VNC_JPEG_CFLAGS) QEMU_CFLAGS += $(VNC_PNG_CFLAGS) -QEMU_CFLAGS += $(GLIB_CFLAGS) # xen support obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o @@ -407,9 +413,16 @@ endif # CONFIG_LINUX_USER obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o +ifdef QEMU_PROGW +# The linker builds a windows executable. Make also a console executable. +$(QEMU_PROGW): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) + $(call LINK,$^) +$(QEMU_PROG): $(QEMU_PROGW) + $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)") +else $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) $(call LINK,$^) - +endif gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") @@ -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 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, 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 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque) 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 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs, */ void *bounce_buffer; + BlockDriver *drv = bs->drv; struct iovec iov; QEMUIOVector bounce_qiov; int64_t cluster_sector_num; @@ -1535,14 +1538,21 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs, 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 @@ int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, 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 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs, 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 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num, { 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 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque) 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); @@ -146,6 +146,14 @@ int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, 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 938c568071..bd3ca11b2e 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -455,6 +455,109 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data, } } +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 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) 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 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) 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 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) 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 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) 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 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) 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 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) 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 aa32e8d01a..3692b4523b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -77,8 +77,10 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) 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 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, 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 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, 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 @@ static int qcow2_open(BlockDriverState *bs, int flags) 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 @@ static void qcow2_close(BlockDriverState *bs) 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 @@ static void qcow2_invalidate_cache(BlockDriverState *bs) } } +static size_t header_ext_add(char *buf, uint32_t magic, const void *s, + size_t len, size_t buflen) +{ + QCowExtension *ext_backing_fmt = (QCowExtension*) buf; + size_t ext_len = sizeof(QCowExtension) + ((len + 7) & ~7); + + if (buflen < ext_len) { + return -ENOSPC; + } + + *ext_backing_fmt = (QCowExtension) { + .magic = cpu_to_be32(magic), + .len = cpu_to_be32(len), + }; + memcpy(buf + sizeof(QCowExtension), s, len); + + return ext_len; +} + /* - * 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. + * 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. */ -static int qcow2_update_ext_header(BlockDriverState *bs, - const char *backing_file, const char *backing_fmt) +int qcow2_update_header(BlockDriverState *bs) { - size_t backing_file_len = 0; - size_t backing_fmt_len = 0; BDRVQcowState *s = bs->opaque; - QCowExtension ext_backing_fmt = {0, 0}; + QCowHeader *header; + char *buf; + size_t buflen = s->cluster_size; int ret; + uint64_t total_size; + uint32_t refcount_table_clusters; + Qcow2UnknownHeaderExtension *uext; - /* Backing file format doesn't make sense without a backing file */ - if (backing_fmt && !backing_file) { - return -EINVAL; - } + buf = qemu_blockalign(bs, buflen); + memset(buf, 0, s->cluster_size); - /* 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); - } + /* Header structure */ + header = (QCowHeader*) buf; - /* 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) { - return -ENOSPC; + if (buflen < sizeof(*header)) { + ret = -ENOSPC; + goto fail; } - /* 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; + 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), + }; - if (backing_file) { - if (backing_fmt) { - int padding = backing_fmt_len - - (sizeof(ext_backing_fmt) + strlen(backing_fmt)); + buf += sizeof(*header); + buflen -= sizeof(*header); - memcpy(buf + offset, &ext_backing_fmt, sizeof(ext_backing_fmt)); - offset += sizeof(ext_backing_fmt); + /* 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_fmt, strlen(backing_fmt)); - offset += strlen(backing_fmt); + buf += ret; + buflen -= ret; + } - memset(buf + offset, 0, padding); - offset += padding; + /* 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; } - 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); + /* 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 99e45361f5..fc35838175 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -87,6 +87,13 @@ typedef struct QCowSnapshot { 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 @@ typedef struct BDRVQcowState { QCowSnapshot *snapshots; int flags; + QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext; } BDRVQcowState; /* XXX: use std qcow open function ? */ @@ -178,6 +186,7 @@ static inline int64_t align_offset(int64_t offset, int n) /* 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 8da3ebe9d4..a041d31e66 100644 --- a/block/qed.c +++ b/block/qed.c @@ -875,6 +875,12 @@ static void qed_aio_complete(QEDAIOCB *acb, int ret) 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 @@ static void qed_aio_write_l1_update(void *opaque, int ret) /** * 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 @@ static void qed_aio_write_l2_update(void *opaque, int ret) 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 @@ err: 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 @@ static void qed_aio_write_flush_before_l2_update(void *opaque, int ret) 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 @@ static void qed_aio_write_main(void *opaque, int ret) 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 @@ static bool qed_should_set_need_check(BDRVQEDState *s) 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 bool qed_should_set_need_check(BDRVQEDState *s) 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 @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len) 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_alloc(QEDAIOCB *acb, size_t len) */ 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 @@ static void qed_aio_next_io(void *opaque, int ret) { 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 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs, 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 @@ static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs, 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 @@ static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs, 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 @@ static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs, 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 @@ static BlockDriver bdrv_qed = { .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 62cbd3b899..62624a1f34 100644 --- a/block/qed.h +++ b/block/qed.h @@ -123,12 +123,17 @@ typedef struct QEDRequest { 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 9416400165..00276f6f46 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -629,6 +629,9 @@ static void coroutine_fn aio_read_response(void *opaque) 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 89a5ee2668..6b4816f563 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -161,13 +161,27 @@ static int vpc_open(BlockDriverState *bs, int flags) 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 @@ static int vpc_open(BlockDriverState *bs, int flags) 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 (disk_type == VHD_DYNAMIC) { + if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, + HEADER_SIZE) != HEADER_SIZE) { + goto fail; + } - if (strncmp(dyndisk_header->magic, "cxsparse", 8)) - 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->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->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->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; + 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; + 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 (next > s->free_data_block_offset) { + s->free_data_block_offset = next; + } + } } - } - s->last_bitmap_offset = (int64_t) -1; + 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 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num, 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 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num, 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 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls, 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 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options) } } - // Prepare the Dynamic Disk Header memset(buf, 0, 1024); @@ -653,6 +623,129 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options) 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 @@ static QEMUOptionParameter vpc_create_options[] = { .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 7be2988ca7..7946cf66a1 100644 --- a/block_int.h +++ b/block_int.h @@ -131,6 +131,14 @@ struct BlockDriver { 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 a1c0794947..736e77075a 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) @@ -2584,7 +2584,7 @@ fi # 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) @@ -303,6 +303,41 @@ void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count, } } +/* + * 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/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 1e96c8bed9..956fda0919 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -56,11 +56,15 @@ typedef struct extended_ops { * On failure ignore the error. */ #define V9FS_SM_NONE 0x00000010 -#define V9FS_RDONLY 0x00000020 -#define V9FS_PROXY_SOCK_FD 0x00000040 -#define V9FS_PROXY_SOCK_NAME 0x00000080 +/* + * uid/gid part of .virtfs_meatadata namespace + */ +#define V9FS_SM_MAPPED_FILE 0x00000020 +#define V9FS_RDONLY 0x00000040 +#define V9FS_PROXY_SOCK_FD 0x00000080 +#define V9FS_PROXY_SOCK_NAME 0x00000100 -#define V9FS_SEC_MASK 0x0000001C +#define V9FS_SEC_MASK 0x0000003C typedef struct FileOperations FileOperations; diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index 4a507d860e..f9a8270ee9 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -1036,7 +1036,13 @@ int main(int argc, char **argv) return -1; } - if (*sock_name && (own_u == -1 || own_g == -1)) { + if (sock_name && sock != -1) { + fprintf(stderr, "both named socket and socket descriptor specified\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + if (sock_name && (own_u == -1 || own_g == -1)) { fprintf(stderr, "owner uid:gid not specified, "); fprintf(stderr, "owner uid:gid specifies who can access the socket file\n"); @@ -1064,7 +1070,7 @@ int main(int argc, char **argv) } do_log(LOG_INFO, "Started\n"); - if (*sock_name) { + if (sock_name) { sock = proxy_socket(sock_name, own_u, own_g); if (sock < 0) { goto error; diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index b15838c1e6..9345aaeb2e 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -76,6 +76,20 @@ int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf) err = -errno; } }); + /* + * Some FS driver (local:mapped-file) can't support fetching attributes + * using file descriptor. Use Path name in that case. + */ + if (err == -EOPNOTSUPP) { + err = v9fs_co_lstat(pdu, &fidp->path, stbuf); + if (err == -ENOENT) { + /* + * fstat on an unlinked file. Work with partial results + * returned from s->ops->fstat + */ + err = 0; + } + } return err; } diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 3f15540c5f..b8220abae7 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -91,15 +91,6 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) s->ctx.fs_root = NULL; } s->ctx.exops.get_st_gen = NULL; - - if (fse->export_flags & V9FS_SM_PASSTHROUGH) { - s->ctx.xops = passthrough_xattr_ops; - } else if (fse->export_flags & V9FS_SM_MAPPED) { - s->ctx.xops = mapped_xattr_ops; - } else if (fse->export_flags & V9FS_SM_NONE) { - s->ctx.xops = none_xattr_ops; - } - len = strlen(conf->tag); if (len > MAX_TAG_LEN - 1) { fprintf(stderr, "mount tag '%s' (%d bytes) is longer than " @@ -193,10 +184,10 @@ static TypeInfo virtio_9p_info = { .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/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c index cb012c0510..f96d17a974 100644 --- a/hw/9pfs/virtio-9p-handle.c +++ b/hw/9pfs/virtio-9p-handle.c @@ -63,11 +63,11 @@ static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp) if (fd < 0) { return fd; } - ret = fchmod(fd, credp->fc_mode & 07777); + ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH); if (ret < 0) { goto err_out; } - ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH); + ret = fchmod(fd, credp->fc_mode & 07777); err_out: close(fd); return ret; diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 3ae6ef2e39..33a41d2e18 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -20,6 +20,7 @@ #include <sys/socket.h> #include <sys/un.h> #include "qemu-xattr.h" +#include <libgen.h> #include <linux/fs.h> #ifdef CONFIG_LINUX_MAGIC_H #include <linux/magic.h> @@ -39,6 +40,54 @@ #define BTRFS_SUPER_MAGIC 0x9123683E #endif +#define VIRTFS_META_DIR ".virtfs_metadata" + +static const char *local_mapped_attr_path(FsContext *ctx, + const char *path, char *buffer) +{ + char *dir_name; + char *tmp_path = strdup(path); + char *base_name = basename(tmp_path); + + /* NULL terminate the directory */ + dir_name = tmp_path; + *(base_name - 1) = '\0'; + + snprintf(buffer, PATH_MAX, "%s/%s/%s/%s", + ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name); + free(tmp_path); + return buffer; +} + +#define ATTR_MAX 100 +static void local_mapped_file_attr(FsContext *ctx, const char *path, + struct stat *stbuf) +{ + FILE *fp; + char buf[ATTR_MAX]; + char attr_path[PATH_MAX]; + + local_mapped_attr_path(ctx, path, attr_path); + fp = fopen(attr_path, "r"); + if (!fp) { + return; + } + memset(buf, 0, ATTR_MAX); + while (fgets(buf, ATTR_MAX, fp)) { + if (!strncmp(buf, "virtfs.uid", 10)) { + stbuf->st_uid = atoi(buf+11); + } else if (!strncmp(buf, "virtfs.gid", 10)) { + stbuf->st_gid = atoi(buf+11); + } else if (!strncmp(buf, "virtfs.mode", 11)) { + stbuf->st_mode = atoi(buf+12); + } else if (!strncmp(buf, "virtfs.rdev", 11)) { + stbuf->st_rdev = atoi(buf+12); + } + memset(buf, 0, ATTR_MAX); + } + fclose(fp); +} + static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { int err; @@ -71,10 +120,103 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) sizeof(dev_t)) > 0) { stbuf->st_rdev = tmp_dev; } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + local_mapped_file_attr(fs_ctx, path, stbuf); } return err; } +static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) +{ + int err; + char attr_dir[PATH_MAX]; + char *tmp_path = strdup(path); + + snprintf(attr_dir, PATH_MAX, "%s/%s/%s", + ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR); + + err = mkdir(attr_dir, 0700); + if (err < 0 && errno == EEXIST) { + err = 0; + } + free(tmp_path); + return err; +} + +static int local_set_mapped_file_attr(FsContext *ctx, + const char *path, FsCred *credp) +{ + FILE *fp; + int ret = 0; + char buf[ATTR_MAX]; + char attr_path[PATH_MAX]; + int uid = -1, gid = -1, mode = -1, rdev = -1; + + fp = fopen(local_mapped_attr_path(ctx, path, attr_path), "r"); + if (!fp) { + goto create_map_file; + } + memset(buf, 0, ATTR_MAX); + while (fgets(buf, ATTR_MAX, fp)) { + if (!strncmp(buf, "virtfs.uid", 10)) { + uid = atoi(buf+11); + } else if (!strncmp(buf, "virtfs.gid", 10)) { + gid = atoi(buf+11); + } else if (!strncmp(buf, "virtfs.mode", 11)) { + mode = atoi(buf+12); + } else if (!strncmp(buf, "virtfs.rdev", 11)) { + rdev = atoi(buf+12); + } + memset(buf, 0, ATTR_MAX); + } + fclose(fp); + goto update_map_file; + +create_map_file: + ret = local_create_mapped_attr_dir(ctx, path); + if (ret < 0) { + goto err_out; + } + +update_map_file: + fp = fopen(attr_path, "w"); + if (!fp) { + ret = -1; + goto err_out; + } + + if (credp->fc_uid != -1) { + uid = credp->fc_uid; + } + if (credp->fc_gid != -1) { + gid = credp->fc_gid; + } + if (credp->fc_mode != -1) { + mode = credp->fc_mode; + } + if (credp->fc_rdev != -1) { + rdev = credp->fc_rdev; + } + + + if (uid != -1) { + fprintf(fp, "virtfs.uid=%d\n", uid); + } + if (gid != -1) { + fprintf(fp, "virtfs.gid=%d\n", gid); + } + if (mode != -1) { + fprintf(fp, "virtfs.mode=%d\n", mode); + } + if (rdev != -1) { + fprintf(fp, "virtfs.rdev=%d\n", rdev); + } + fclose(fp); + +err_out: + return ret; +} + static int local_set_xattr(const char *path, FsCred *credp) { int err; @@ -115,9 +257,6 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, { char buffer[PATH_MAX]; - if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) { - return -1; - } if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, credp->fc_gid) < 0) { /* @@ -128,6 +267,10 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, return -1; } } + + if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) { + return -1; + } return 0; } @@ -138,7 +281,8 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, char buffer[PATH_MAX]; char *path = fs_path->data; - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + if ((fs_ctx->export_flags & V9FS_SM_MAPPED) || + (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) { int fd; fd = open(rpath(fs_ctx, path, buffer), O_RDONLY); if (fd == -1) { @@ -203,7 +347,18 @@ static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, struct dirent *entry, struct dirent **result) { - return readdir_r(fs->dir, entry, result); + int ret; + +again: + ret = readdir_r(fs->dir, entry, result); + if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + if (!ret && *result != NULL && + !strcmp(entry->d_name, VIRTFS_META_DIR)) { + /* skp the meta data directory */ + goto again; + } + } + return ret; } static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) @@ -264,6 +419,8 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) if (fs_ctx->export_flags & V9FS_SM_MAPPED) { return local_set_xattr(rpath(fs_ctx, path, buffer), credp); + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + return local_set_mapped_file_attr(fs_ctx, path, credp); } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || (fs_ctx->export_flags & V9FS_SM_NONE)) { return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode); @@ -296,6 +453,18 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, serrno = errno; goto err_end; } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + + err = mknod(rpath(fs_ctx, path, buffer), + SM_LOCAL_MODE_BITS|S_IFREG, 0); + if (err == -1) { + goto out; + } + err = local_set_mapped_file_attr(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || (fs_ctx->export_flags & V9FS_SM_NONE)) { err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode, @@ -344,6 +513,17 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, serrno = errno; goto err_end; } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); + if (err == -1) { + goto out; + } + credp->fc_mode = credp->fc_mode|S_IFDIR; + err = local_set_mapped_file_attr(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || (fs_ctx->export_flags & V9FS_SM_NONE)) { err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode); @@ -404,6 +584,9 @@ static int local_fstat(FsContext *fs_ctx, int fid_type, &tmp_dev, sizeof(dev_t)) > 0) { stbuf->st_rdev = tmp_dev; } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + errno = EOPNOTSUPP; + return -1; } return err; } @@ -436,6 +619,19 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, serrno = errno; goto err_end; } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); + if (fd == -1) { + err = fd; + goto out; + } + credp->fc_mode = credp->fc_mode|S_IFREG; + /* Set client credentials in .virtfs_metadata directory files */ + err = local_set_mapped_file_attr(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || (fs_ctx->export_flags & V9FS_SM_NONE)) { fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode); @@ -506,6 +702,35 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, serrno = errno; goto err_end; } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + int fd; + ssize_t oldpath_size, write_size; + fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, + SM_LOCAL_MODE_BITS); + if (fd == -1) { + err = fd; + goto out; + } + /* Write the oldpath (target) to the file. */ + oldpath_size = strlen(oldpath); + do { + write_size = write(fd, (void *)oldpath, oldpath_size); + } while (write_size == -1 && errno == EINTR); + + if (write_size != oldpath_size) { + serrno = errno; + close(fd); + err = -1; + goto err_end; + } + close(fd); + /* Set cleint credentials in symlink's xattr */ + credp->fc_mode = credp->fc_mode|S_IFLNK; + err = local_set_mapped_file_attr(fs_ctx, newpath, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || (fs_ctx->export_flags & V9FS_SM_NONE)) { err = symlink(oldpath, rpath(fs_ctx, newpath, buffer)); @@ -548,6 +773,21 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath, ret = link(rpath(ctx, oldpath->data, buffer), rpath(ctx, newpath.data, buffer1)); + + /* now link the virtfs_metadata files */ + if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) { + /* Link the .virtfs_metadata files. Create the metada directory */ + ret = local_create_mapped_attr_dir(ctx, newpath.data); + if (ret < 0) { + goto err_out; + } + ret = link(local_mapped_attr_path(ctx, oldpath->data, buffer), + local_mapped_attr_path(ctx, newpath.data, buffer1)); + if (ret < 0 && errno != ENOENT) { + goto err_out; + } + } +err_out: v9fs_string_free(&newpath); return ret; } @@ -563,8 +803,21 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) static int local_rename(FsContext *ctx, const char *oldpath, const char *newpath) { + int err; char buffer[PATH_MAX], buffer1[PATH_MAX]; + if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + err = local_create_mapped_attr_dir(ctx, newpath); + if (err < 0) { + return err; + } + /* rename the .virtfs_metadata files */ + err = rename(local_mapped_attr_path(ctx, oldpath, buffer), + local_mapped_attr_path(ctx, newpath, buffer1)); + if (err < 0 && errno != ENOENT) { + return err; + } + } return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); } @@ -580,6 +833,8 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) credp->fc_uid, credp->fc_gid); } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { return local_set_xattr(rpath(fs_ctx, path, buffer), credp); + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + return local_set_mapped_file_attr(fs_ctx, path, credp); } return -1; } @@ -595,8 +850,46 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path, static int local_remove(FsContext *ctx, const char *path) { + int err; + struct stat stbuf; char buffer[PATH_MAX]; + + if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + err = lstat(rpath(ctx, path, buffer), &stbuf); + if (err) { + goto err_out; + } + /* + * If directory remove .virtfs_metadata contained in the + * directory + */ + if (S_ISDIR(stbuf.st_mode)) { + sprintf(buffer, "%s/%s/%s", ctx->fs_root, path, VIRTFS_META_DIR); + err = remove(buffer); + if (err < 0 && errno != ENOENT) { + /* + * We didn't had the .virtfs_metadata file. May be file created + * in non-mapped mode ?. Ignore ENOENT. + */ + goto err_out; + } + } + /* + * Now remove the name from parent directory + * .virtfs_metadata directory + */ + err = remove(local_mapped_attr_path(ctx, path, buffer));; + if (err < 0 && errno != ENOENT) { + /* + * We didn't had the .virtfs_metadata file. May be file created + * in non-mapped mode ?. Ignore ENOENT. + */ + goto err_out; + } + } return remove(rpath(ctx, path, buffer)); +err_out: + return err; } static int local_fsync(FsContext *ctx, int fid_type, @@ -696,12 +989,45 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, int ret; V9fsString fullname; char buffer[PATH_MAX]; + v9fs_string_init(&fullname); v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); + if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + if (flags == AT_REMOVEDIR) { + /* + * If directory remove .virtfs_metadata contained in the + * directory + */ + sprintf(buffer, "%s/%s/%s", ctx->fs_root, + fullname.data, VIRTFS_META_DIR); + ret = remove(buffer); + if (ret < 0 && errno != ENOENT) { + /* + * We didn't had the .virtfs_metadata file. May be file created + * in non-mapped mode ?. Ignore ENOENT. + */ + goto err_out; + } + } + /* + * Now remove the name from parent directory + * .virtfs_metadata directory. + */ + ret = remove(local_mapped_attr_path(ctx, fullname.data, buffer)); + if (ret < 0 && errno != ENOENT) { + /* + * We didn't had the .virtfs_metadata file. May be file created + * in non-mapped mode ?. Ignore ENOENT. + */ + goto err_out; + } + } + /* Remove the name finally */ ret = remove(rpath(ctx, fullname.data, buffer)); v9fs_string_free(&fullname); +err_out: return ret; } @@ -736,6 +1062,19 @@ static int local_init(FsContext *ctx) int err = 0; struct statfs stbuf; + if (ctx->export_flags & V9FS_SM_PASSTHROUGH) { + ctx->xops = passthrough_xattr_ops; + } else if (ctx->export_flags & V9FS_SM_MAPPED) { + ctx->xops = mapped_xattr_ops; + } else if (ctx->export_flags & V9FS_SM_NONE) { + ctx->xops = none_xattr_ops; + } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + /* + * xattr operation for mapped-file and passthrough + * remain same. + */ + ctx->xops = passthrough_xattr_ops; + } ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; #ifdef FS_IOC_GETVERSION /* @@ -770,13 +1109,17 @@ static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse) if (!strcmp(sec_model, "passthrough")) { fse->export_flags |= V9FS_SM_PASSTHROUGH; - } else if (!strcmp(sec_model, "mapped")) { + } else if (!strcmp(sec_model, "mapped") || + !strcmp(sec_model, "mapped-xattr")) { fse->export_flags |= V9FS_SM_MAPPED; } else if (!strcmp(sec_model, "none")) { fse->export_flags |= V9FS_SM_NONE; + } else if (!strcmp(sec_model, "mapped-file")) { + fse->export_flags |= V9FS_SM_MAPPED_FILE; } else { fprintf(stderr, "Invalid security model %s specified, valid options are" - "\n\t [passthrough|mapped|none]\n", sec_model); + "\n\t [passthrough|mapped-xattr|mapped-file|none]\n", + sec_model); return -1; } diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index e6ba6ba30b..a72ffc3390 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -986,7 +986,7 @@ static void v9fs_attach(void *opaque) s->root_fid = fid; /* disable migration */ error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION, - s->ctx.fs_root, s->tag); + s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag); migrate_add_blocker(s->migration_blocker); out: put_fid(pdu, fidp); @@ -1391,7 +1391,6 @@ static void v9fs_open(void *opaque) err = -EROFS; goto out; } - flags |= O_NOATIME; } err = v9fs_co_open(pdu, fidp, flags); if (err < 0) { diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 19de12b4b4..03b128ce5b 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -238,9 +238,9 @@ static TypeInfo a9mp_priv_info = { .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) @@ -1372,9 +1372,9 @@ static TypeInfo ac97_info = { .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 21484aec42..d959f4907b 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -426,12 +426,12 @@ static TypeInfo piix4_pm_info = { .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 3cfdecbe5c..41c7f101c4 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -168,9 +168,9 @@ static TypeInfo ads7846_info = { .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 736c28a3a9..b539416589 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -824,8 +824,9 @@ static TypeInfo typhoon_pcihost_info = { .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 c7aaa72d07..1d25da8da9 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -493,11 +493,11 @@ static TypeInfo pbm_pci_bridge_info = { .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) @@ -781,9 +781,9 @@ static TypeInfo apic_info = { .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 8373d79c41..c91f7d5391 100644 --- a/hw/apic_common.c +++ b/hw/apic_common.c @@ -318,9 +318,9 @@ static TypeInfo apic_common_type = { .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 b06487f70d..8bedaad310 100644 --- a/hw/applesmc.c +++ b/hw/applesmc.c @@ -243,9 +243,9 @@ static TypeInfo applesmc_isa_info = { .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 3c0839c4b4..102348bb70 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -252,10 +252,10 @@ static TypeInfo mpcore_priv_info = { .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_l2x0.c b/hw/arm_l2x0.c index ba26abc6f4..09f290c85f 100644 --- a/hw/arm_l2x0.c +++ b/hw/arm_l2x0.c @@ -184,9 +184,9 @@ static TypeInfo l2x0_info = { .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 5a02365b6f..361e887dec 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -335,9 +335,9 @@ static TypeInfo arm_mptimer_info = { .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 9d257994c0..149c6394e6 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -425,9 +425,9 @@ static TypeInfo arm_sysctl_info = { .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 1019d41b3e..e3ecce29f0 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -383,10 +383,10 @@ static TypeInfo sp804_info = { .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 de3d7e0828..6b805798e6 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -266,9 +266,9 @@ static TypeInfo bitband_info = { .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 1ed0abc3e7..3210129c3f 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -417,9 +417,9 @@ static TypeInfo armv7m_nvic_info = { .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 c9c11823af..44ed7f4d61 100644 --- a/hw/bitbang_i2c.c +++ b/hw/bitbang_i2c.c @@ -237,9 +237,9 @@ static TypeInfo gpio_i2c_info = { .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 7350a4f9ec..77786f8883 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -804,9 +804,10 @@ static TypeInfo bonito_pcihost_info = { .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 9510ed4d94..f4a6da4283 100644 --- a/hw/ccid-card-emulated.c +++ b/hw/ccid-card-emulated.c @@ -594,9 +594,9 @@ static TypeInfo emulated_card_info = { .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 a7006ca035..bd6c77777d 100644 --- a/hw/ccid-card-passthru.c +++ b/hw/ccid-card-passthru.c @@ -343,9 +343,9 @@ static TypeInfo passthru_card_info = { .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 a8e8ab7660..4edcb94774 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2923,12 +2923,6 @@ static TypeInfo isa_cirrus_vga_info = { .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 @@ static TypeInfo cirrus_vga_info = { .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 c0badbff5c..cfec1d9cd1 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -173,9 +173,9 @@ static TypeInfo cs4231_info = { .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 ad04ad667c..e07b9d6237 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -689,8 +689,9 @@ static TypeInfo cs4231a_info = { .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 3903b2605d..14ab326be3 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -109,9 +109,9 @@ static TypeInfo debugcon_isa_info = { .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 a40fbcf3e5..37337bf4b6 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -140,11 +140,11 @@ static TypeInfo pci_dec_21154_device_info = { .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 539bcebae0..2cd355bd0a 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -157,9 +157,9 @@ static TypeInfo nvram_sysbus_info = { .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 b137e13379..6397f0aa6f 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -135,9 +135,9 @@ static TypeInfo ds1338_info = { .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 751f79d5ff..7babc0b06e 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1227,9 +1227,9 @@ static TypeInfo e1000_info = { .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 1cf2090c1f..fe1cd90007 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -332,9 +332,9 @@ static TypeInfo ecc_info = { }; -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 843610c933..e3ba71974e 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -2089,7 +2089,7 @@ static void eepro100_class_init(ObjectClass *klass, void *data) 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 @@ static void eepro100_register_devices(void) } } -device_init(eepro100_register_devices) +type_init(eepro100_register_types) diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 1bc181555f..099c85e583 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -90,9 +90,9 @@ static TypeInfo empty_slot_info = { .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 e377c48e49..f19cef31a6 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -1054,9 +1054,10 @@ static TypeInfo es1370_info = { .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) @@ -931,9 +931,9 @@ static TypeInfo escc_info = { .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) @@ -775,9 +775,9 @@ static TypeInfo esp_info = { .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 aefd5778ab..16a0637a4a 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -637,9 +637,9 @@ static TypeInfo etraxfs_eth_info = { .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 33541fcc61..dc27f88ac9 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -172,9 +172,9 @@ static TypeInfo etraxfs_pic_info = { .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 567cb8cc2d..cecd819584 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -240,9 +240,9 @@ static TypeInfo etraxfs_ser_info = { .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 b71c5ee9d5..9076a49884 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -343,9 +343,9 @@ static TypeInfo etraxfs_timer_info = { .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) @@ -2043,11 +2043,11 @@ static TypeInfo sun4m_fdc_info = { .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 ea122fb266..f4747cd646 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -87,7 +87,7 @@ void framebuffer_update_display( 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 6b2f7d1986..7b3b5769a2 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -556,9 +556,9 @@ static TypeInfo fw_cfg_info = { .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 66d0044c06..9c63bddc59 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -574,9 +574,9 @@ static TypeInfo g364fb_sysbus_info = { .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 8122baf482..81ff3a339a 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -157,10 +157,10 @@ static TypeInfo grackle_pci_host_info = { .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 89de2d85ae..73fc9894db 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -263,9 +263,9 @@ static TypeInfo grlib_gptimer_info = { .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 fb0b236746..41770a9e6c 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -396,9 +396,9 @@ static TypeInfo grlib_gptimer_info = { .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 1e5ad826f5..0f6e65cf20 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -377,9 +377,9 @@ static TypeInfo grlib_irqmp_info = { .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 e8cd59c3a4..a2d0e5a2c3 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -1168,10 +1168,10 @@ static TypeInfo gt64120_info = { .class_init = gt64120_class_init, }; -static void gt64120_pci_register_devices(void) +static void gt64120_pci_register_types(void) { type_register_static(>64120_info); type_register_static(>64120_pci_info); } -device_init(gt64120_pci_register_devices) +type_init(gt64120_pci_register_types) @@ -324,8 +324,9 @@ static TypeInfo gus_info = { .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 152f8e6f13..8995519573 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -948,9 +948,10 @@ static TypeInfo hda_audio_duplex_info = { .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 684178ee3e..b28b4640aa 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -177,12 +177,12 @@ static TypeInfo highbank_regs_info = { .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; @@ -720,9 +720,9 @@ static TypeInfo hpet_device_info = { .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) @@ -230,9 +230,9 @@ static TypeInfo i2c_slave_type_info = { .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 220e8cccb6..67298a39f5 100644 --- a/hw/i82374.c +++ b/hw/i82374.c @@ -157,9 +157,9 @@ static TypeInfo i82374_isa_info = { .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 9c3efe8b95..3929c041b7 100644 --- a/hw/i82378.c +++ b/hw/i82378.c @@ -267,9 +267,9 @@ static TypeInfo pci_i82378_info = { .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 522fed8809..481fc7b252 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -559,8 +559,9 @@ static TypeInfo pit_info = { .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 7ae53805d7..1a4b1ab0dd 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -488,9 +488,9 @@ static TypeInfo i8259_info = { .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 9f150bc6d0..775fda453c 100644 --- a/hw/i8259_common.c +++ b/hw/i8259_common.c @@ -153,9 +153,9 @@ static TypeInfo pic_common_type = { .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 c87a6ca515..b515f417b1 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -146,6 +146,7 @@ static void ahci_check_irq(AHCIState *s) 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 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) 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 @@ static void ahci_reset_port(AHCIState *s, int port) 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 @@ static TypeInfo sysbus_ahci_info = { .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 a119500f40..743ec02406 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -351,8 +351,9 @@ static TypeInfo cmd646_ide_info = { .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 5cdaa990ea..560ae37618 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -168,8 +168,9 @@ static TypeInfo ich_ahci_info = { .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 a0bcb43eba..8ab2718eea 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -118,9 +118,9 @@ static TypeInfo isa_ide_info = { .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 bf4465bb49..aee60aa390 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -299,10 +299,11 @@ static TypeInfo piix4_ide_info = { .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 1640616906..f6a48961c5 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -257,11 +257,12 @@ static TypeInfo ide_device_type_info = { .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 b4ca6f27b3..2886bc6dfb 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -234,8 +234,9 @@ static TypeInfo via_ide_info = { .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 6dbd649908..294d7da7fc 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -553,10 +553,10 @@ static TypeInfo icp_pic_info = { .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 83c42d58b6..bb11af286a 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -1287,12 +1287,13 @@ static TypeInfo hda_codec_device_type_info = { .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 79549f8ed1..3fee0114d9 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -251,9 +251,9 @@ static TypeInfo ioapic_info = { .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 f932700d12..653eef2ce1 100644 --- a/hw/ioapic_common.c +++ b/hw/ioapic_common.c @@ -112,10 +112,9 @@ static TypeInfo ioapic_common_type = { .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 1c60123d43..1632d31c19 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -237,12 +237,12 @@ static TypeInfo ioh3420_info = { .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 d03f82824c..5a43f03a7c 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -210,7 +210,7 @@ static TypeInfo isa_device_type_info = { .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 @@ MemoryRegion *isa_address_space(ISADevice *dev) 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 6f017d474c..64e1cd968e 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -798,9 +798,9 @@ static TypeInfo ivshmem_info = { .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 dfc2ab3b03..5bb0a4b9fd 100644 --- a/hw/kvm/apic.c +++ b/hw/kvm/apic.c @@ -139,9 +139,9 @@ static TypeInfo kvm_apic_info = { .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 d5a53869b3..2157340326 100644 --- a/hw/kvm/clock.c +++ b/hw/kvm/clock.c @@ -119,11 +119,11 @@ void kvmclock_create(void) } } -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 14bd427518..eb98889329 100644 --- a/hw/kvm/i8259.c +++ b/hw/kvm/i8259.c @@ -130,9 +130,9 @@ static TypeInfo kvm_i8259_info = { .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 b316933a96..3ae3175403 100644 --- a/hw/kvm/ioapic.c +++ b/hw/kvm/ioapic.c @@ -117,9 +117,9 @@ static TypeInfo kvm_ioapic_info = { .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 78777c7336..aeb0c39529 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -1261,7 +1261,7 @@ static TypeInfo lan9118_info = { .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 @@ void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq) 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 519720bd9c..ce3d46c17b 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -162,8 +162,9 @@ static TypeInfo lance_info = { .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 38dd28230d..f07ed3977f 100644 --- a/hw/lm32_juart.c +++ b/hw/lm32_juart.c @@ -151,9 +151,9 @@ static TypeInfo lm32_juart_info = { .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 7be6d0d68e..32f65db7f1 100644 --- a/hw/lm32_pic.c +++ b/hw/lm32_pic.c @@ -191,9 +191,9 @@ static TypeInfo lm32_pic_info = { .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 ba6f4acbaa..bbe03c41d5 100644 --- a/hw/lm32_sys.c +++ b/hw/lm32_sys.c @@ -164,9 +164,9 @@ static TypeInfo lm32_sys_info = { .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 3cb4e0a4f3..e9450a0ce1 100644 --- a/hw/lm32_timer.c +++ b/hw/lm32_timer.c @@ -222,9 +222,9 @@ static TypeInfo lm32_timer_info = { .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 630ccb7131..57066e28c6 100644 --- a/hw/lm32_uart.c +++ b/hw/lm32_uart.c @@ -288,9 +288,9 @@ static TypeInfo lm32_uart_info = { .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 895d306635..8e09f9bcc9 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -513,9 +513,9 @@ static TypeInfo lm8323_info = { .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 9a7ffe3f42..0acd1d06df 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -2142,9 +2142,9 @@ static TypeInfo lsi_info = { .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 c35867d0a1..60bbb00946 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -768,10 +768,10 @@ static TypeInfo m48t59_info = { .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 3d648e934b..eb15b890b1 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -97,12 +97,12 @@ static TypeInfo macio_info = { .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 b628f1718d..f6f1937442 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -295,9 +295,9 @@ static TypeInfo mv88w8618_audio_info = { .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 9d61aa98db..706d89f4fd 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -183,10 +183,10 @@ static TypeInfo max1111_info = { .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 3a6bb961ef..1ed18ba876 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -205,9 +205,9 @@ static TypeInfo max7310_info = { .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 4a43225707..6c1ad38f72 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -733,8 +733,9 @@ static TypeInfo mc146818rtc_info = { .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 0881643a4c..4414f39734 100644 --- a/hw/milkymist-ac97.c +++ b/hw/milkymist-ac97.c @@ -336,9 +336,9 @@ static TypeInfo milkymist_ac97_info = { .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 b5122afd57..2da0293683 100644 --- a/hw/milkymist-hpdmc.c +++ b/hw/milkymist-hpdmc.c @@ -162,9 +162,9 @@ static TypeInfo milkymist_hpdmc_info = { .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 3c1c68a2e7..3515c3cd9a 100644 --- a/hw/milkymist-memcard.c +++ b/hw/milkymist-memcard.c @@ -295,9 +295,9 @@ static TypeInfo milkymist_memcard_info = { .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 b9b553fc95..70bf336add 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -542,9 +542,9 @@ static TypeInfo milkymist_minimac2_info = { .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 1b73a4686b..0f9ff4a13d 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -536,9 +536,9 @@ static TypeInfo milkymist_pfpu_info = { .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 5d496cbdb0..ecc2be9225 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -323,9 +323,9 @@ static TypeInfo milkymist_softusb_info = { .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 18171f6165..a88548e0aa 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -322,9 +322,9 @@ static TypeInfo milkymist_sysctl_info = { .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 474eae0a4a..210ceede2a 100644 --- a/hw/milkymist-tmu2.c +++ b/hw/milkymist-tmu2.c @@ -482,9 +482,9 @@ static TypeInfo milkymist_tmu2_info = { .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 f9a229cf68..291fe3c57b 100644 --- a/hw/milkymist-uart.c +++ b/hw/milkymist-uart.c @@ -235,9 +235,9 @@ static TypeInfo milkymist_uart_info = { .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 92ad02f9e2..69afd72d8a 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -323,9 +323,9 @@ static TypeInfo milkymist_vgafb_info = { .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 d232630e66..ffecefdede 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -1029,7 +1029,7 @@ static QEMUMachine mips_malta_machine = { .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 @@ static void mips_malta_machine_init(void) 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 a0e6c9fa1e..50d92f8f54 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -276,9 +276,9 @@ static TypeInfo mipsnet_info = { .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 28cd60d89c..aeb2de7ccc 100644 --- a/hw/mpc8544_guts.c +++ b/hw/mpc8544_guts.c @@ -135,8 +135,9 @@ static TypeInfo mpc8544_guts_info = { .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 1729db01a4..024192d135 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -255,8 +255,9 @@ static TypeInfo mst_fpga_info = { .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 ac909248d4..187a1aef5e 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1681,7 +1681,7 @@ static TypeInfo mv88w8618_wlan_info = { .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 @@ static void musicpal_register_devices(void) type_register_static(&musicpal_key_info); } -device_init(musicpal_register_devices) +type_init(musicpal_register_types) @@ -442,7 +442,7 @@ static TypeInfo nand_info = { .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 @@ DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id) 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 1352282152..a4a783ab89 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -104,9 +104,9 @@ static TypeInfo ne2000_isa_info = { .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 080811ec4d..bb84fd1f93 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -812,9 +812,9 @@ static TypeInfo ne2000_info = { .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/omap_gpio.c b/hw/omap_gpio.c index 9a9a8e183f..201ff77c36 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -783,10 +783,10 @@ static TypeInfo omap2_gpio_info = { .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 5aa98a8fdb..5076e07ed5 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -640,10 +640,10 @@ static TypeInfo omap2_intc_info = { .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 8744b04db3..db6af682c4 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -828,7 +828,7 @@ static TypeInfo onenand_info = { .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 @@ void *onenand_raw_otp(DeviceState *onenand_device) 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 09f2757df3..9b036cb103 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -750,9 +750,9 @@ static TypeInfo open_eth_info = { .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 484d727927..219f38436f 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -606,9 +606,9 @@ static TypeInfo parallel_isa_info = { .class_init = parallel_isa_class_initfn, }; -static void parallel_register_devices(void) +static void parallel_register_types(void) { type_register_static(¶llel_isa_info); } -device_init(parallel_register_devices) +type_init(parallel_register_types) @@ -514,11 +514,12 @@ static TypeInfo port92_info = { .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) { @@ -2003,9 +2003,9 @@ static TypeInfo pci_device_type_info = { .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 b4c53bed6c..69857bade9 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -513,8 +513,9 @@ static TypeInfo i8042_info = { .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 439f32caae..368260959f 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -376,9 +376,9 @@ static TypeInfo pcnet_info = { .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 a9e88b9b3c..2ca0fd4560 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -102,6 +102,7 @@ static void pflash_setup_mappings(pflash_t *pfl) 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 4e7a2370cd..ce4eb0d1ae 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -124,8 +124,9 @@ static TypeInfo piix4_info = { .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 190642733f..e0268fe053 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -589,11 +589,12 @@ static TypeInfo i440fx_pcihost_info = { .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 752cbf9725..8a5a8f554a 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -316,10 +316,10 @@ static TypeInfo pl011_luminary_info = { .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 30bd3442bb..03bf63c4d2 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -299,9 +299,9 @@ static TypeInfo pl022_info = { .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 8416a609ef..05b5b11e1a 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -230,9 +230,9 @@ static TypeInfo pl031_info = { .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 6d99c9cbbc..b6723be0a9 100644 --- a/hw/pl041.c +++ b/hw/pl041.c @@ -638,9 +638,9 @@ static TypeInfo pl041_device_info = { .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 b0094ac9b3..b13924a160 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -189,10 +189,10 @@ static TypeInfo pl050_mouse_info = { .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 3136c99423..2aac7e8e9e 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -325,10 +325,10 @@ static TypeInfo pl061_luminary_info = { .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 4405d1823b..b3cf651ab7 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -409,10 +409,10 @@ static TypeInfo pl081_info = { /* 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 86e95a3ffd..f94608cb62 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -520,11 +520,11 @@ static TypeInfo pl111_info = { .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 ae636e220e..7d91fbba1d 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -505,9 +505,9 @@ static TypeInfo pl181_info = { .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 956ab21c6a..cb50afb9f4 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -273,9 +273,9 @@ static TypeInfo pl190_info = { .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 d11f120d32..203c3cdc47 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -400,9 +400,10 @@ static TypeInfo ppc4xx_pcihost_info = { .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 d5bce71429..0f60b24134 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -373,9 +373,10 @@ static TypeInfo e500_pcihost_info = { .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 9d648ec90a..6b8a189c0e 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -217,8 +217,9 @@ static TypeInfo ppce500_spin_info = { .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 40b8bb0edd..8b29da9948 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -173,10 +173,10 @@ static TypeInfo raven_pcihost_info = { .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 244c614510..1ab27012c1 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2330,7 +2330,7 @@ static TypeInfo pxa2xx_ssp_info = { .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 @@ static void pxa2xx_register_devices(void) 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 2d61565f1d..8ced0dd8ec 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -566,8 +566,9 @@ static TypeInfo pxa2xx_dma_info = { .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 67fd17c4ca..d5f57162ed 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -340,8 +340,9 @@ static TypeInfo pxa2xx_gpio_info = { .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_pic.c b/hw/pxa2xx_pic.c index ca85743aea..6b2bdb0df1 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -313,8 +313,9 @@ static TypeInfo pxa2xx_pic_info = { .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 90800751b1..77b033b541 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -527,9 +527,10 @@ static TypeInfo pxa27x_timer_dev_info = { .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-addr.c b/hw/qdev-addr.c index 5976dcdf47..0bb16c7eb3 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -61,8 +61,6 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_taddr = { .name = "taddr", - .type = PROP_TYPE_TADDR, - .size = sizeof(target_phys_addr_t), .parse = parse_taddr, .print = print_taddr, .get = get_taddr, @@ -71,5 +69,8 @@ PropertyInfo qdev_prop_taddr = { void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_TADDR); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert(!errp); + } diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index 135c2bf237..a310cc7b16 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -457,6 +457,16 @@ DeviceState *qdev_device_add(QemuOpts *opts) 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 @@ DeviceState *qdev_device_add(QemuOpts *opts) 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; } @@ -485,22 +487,26 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent); static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, const char *prefix, int indent) { - char buf[64]; - if (!props) return; - while (props->name) { - /* - * TODO Properties without a print method are just for dirty - * hacks. qdev_prop_ptr is the only such PropertyInfo. It's - * marked for removal. The test props->info->print should be - * removed along with it. - */ - if (props->info->print) { - props->info->print(dev, props, buf, sizeof(buf)); - qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf); + for (; props->name; props++) { + Error *err = NULL; + char *value; + char *legacy_name = g_strdup_printf("legacy-%s", props->name); + if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { + value = object_property_get_str(OBJECT(dev), legacy_name, &err); + } else { + value = object_property_get_str(OBJECT(dev), props->name, &err); + } + g_free(legacy_name); + + if (err) { + error_free(err); + continue; } - props++; + qdev_printf("%s-prop: %s = %s\n", prefix, props->name, + value && *value ? value : "<null>"); + g_free(value); } } diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index c4583a14d7..7b74dd5beb 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -12,7 +12,7 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) static uint32_t qdev_get_prop_mask(Property *prop) { - assert(prop->info->type == PROP_TYPE_BIT); + assert(prop->info == &qdev_prop_bit); return 0x1 << prop->bitnr; } @@ -26,17 +26,6 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) *p &= ~mask; } -static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src) -{ - if (props->info->type == PROP_TYPE_BIT) { - bool *defval = src; - bit_prop_set(dev, props, *defval); - } else { - char *dst = qdev_get_prop_ptr(dev, props); - memcpy(dst, src, props->info->size); - } -} - /* Bit */ static int parse_bit(DeviceState *dev, Property *prop, const char *str) { @@ -90,8 +79,6 @@ static void set_bit(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_bit = { .name = "boolean", .legacy_name = "on/off", - .type = PROP_TYPE_BIT, - .size = sizeof(uint32_t), .parse = parse_bit, .print = print_bit, .get = get_bit, @@ -151,7 +138,7 @@ static void set_int8(Object *obj, Visitor *v, void *opaque, error_propagate(errp, local_err); return; } - if (value > prop->info->min && value <= prop->info->max) { + if (value >= prop->info->min && value <= prop->info->max) { *ptr = value; } else { error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, @@ -162,8 +149,6 @@ static void set_int8(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint8 = { .name = "uint8", - .type = PROP_TYPE_UINT8, - .size = sizeof(uint8_t), .parse = parse_uint8, .print = print_uint8, .get = get_int8, @@ -196,8 +181,6 @@ static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) PropertyInfo qdev_prop_hex8 = { .name = "uint8", .legacy_name = "hex8", - .type = PROP_TYPE_UINT8, - .size = sizeof(uint8_t), .parse = parse_hex8, .print = print_hex8, .get = get_int8, @@ -259,7 +242,7 @@ static void set_int16(Object *obj, Visitor *v, void *opaque, error_propagate(errp, local_err); return; } - if (value > prop->info->min && value <= prop->info->max) { + if (value >= prop->info->min && value <= prop->info->max) { *ptr = value; } else { error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, @@ -270,8 +253,6 @@ static void set_int16(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint16 = { .name = "uint16", - .type = PROP_TYPE_UINT16, - .size = sizeof(uint16_t), .parse = parse_uint16, .print = print_uint16, .get = get_int16, @@ -333,7 +314,7 @@ static void set_int32(Object *obj, Visitor *v, void *opaque, error_propagate(errp, local_err); return; } - if (value > prop->info->min && value <= prop->info->max) { + if (value >= prop->info->min && value <= prop->info->max) { *ptr = value; } else { error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, @@ -344,8 +325,6 @@ static void set_int32(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint32 = { .name = "uint32", - .type = PROP_TYPE_UINT32, - .size = sizeof(uint32_t), .parse = parse_uint32, .print = print_uint32, .get = get_int32, @@ -375,8 +354,6 @@ static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len) PropertyInfo qdev_prop_int32 = { .name = "int32", - .type = PROP_TYPE_INT32, - .size = sizeof(int32_t), .parse = parse_int32, .print = print_int32, .get = get_int32, @@ -409,8 +386,6 @@ static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) PropertyInfo qdev_prop_hex32 = { .name = "uint32", .legacy_name = "hex32", - .type = PROP_TYPE_UINT32, - .size = sizeof(uint32_t), .parse = parse_hex32, .print = print_hex32, .get = get_int32, @@ -468,8 +443,6 @@ static void set_int64(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_uint64 = { .name = "uint64", - .type = PROP_TYPE_UINT64, - .size = sizeof(uint64_t), .parse = parse_uint64, .print = print_uint64, .get = get_int64, @@ -500,8 +473,6 @@ static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) PropertyInfo qdev_prop_hex64 = { .name = "uint64", .legacy_name = "hex64", - .type = PROP_TYPE_UINT64, - .size = sizeof(uint64_t), .parse = parse_hex64, .print = print_hex64, .get = get_int64, @@ -510,19 +481,10 @@ PropertyInfo qdev_prop_hex64 = { /* --- string --- */ -static int parse_string(DeviceState *dev, Property *prop, const char *str) -{ - char **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) - g_free(*ptr); - *ptr = g_strdup(str); - return 0; -} - -static void free_string(DeviceState *dev, Property *prop) +static void release_string(Object *obj, const char *name, void *opaque) { - g_free(*(char **)qdev_get_prop_ptr(dev, prop)); + Property *prop = opaque; + g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); } static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) @@ -579,20 +541,16 @@ static void set_string(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_string = { .name = "string", - .type = PROP_TYPE_STRING, - .size = sizeof(char*), - .parse = parse_string, .print = print_string, - .free = free_string, + .release = release_string, .get = get_string, .set = set_string, }; /* --- drive --- */ -static int parse_drive(DeviceState *dev, Property *prop, const char *str) +static int parse_drive(DeviceState *dev, const char *str, void **ptr) { - BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); BlockDriverState *bs; bs = bdrv_find(str); @@ -604,8 +562,10 @@ static int parse_drive(DeviceState *dev, Property *prop, const char *str) return 0; } -static void free_drive(DeviceState *dev, Property *prop) +static void release_drive(Object *obj, const char *name, void *opaque) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); if (*ptr) { @@ -614,35 +574,30 @@ static void free_drive(DeviceState *dev, Property *prop) } } -static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len) +static const char *print_drive(void *ptr) { - BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%s", - *ptr ? bdrv_get_device_name(*ptr) : "<null>"); + return bdrv_get_device_name(ptr); } -static void get_generic(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void get_pointer(Object *obj, Visitor *v, Property *prop, + const char *(*print)(void *ptr), + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); - Property *prop = opaque; void **ptr = qdev_get_prop_ptr(dev, prop); - char buffer[1024]; - char *p = buffer; + char *p; - buffer[0] = 0; - if (*ptr) { - prop->info->print(dev, prop, buffer, sizeof(buffer)); - } + p = (char *) (*ptr ? print(*ptr) : ""); visit_type_str(v, &p, name, errp); } -static void set_generic(Object *obj, Visitor *v, void *opaque, +static void set_pointer(Object *obj, Visitor *v, Property *prop, + int (*parse)(DeviceState *dev, const char *str, void **ptr), const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); - Property *prop = opaque; Error *local_err = NULL; + void **ptr = qdev_get_prop_ptr(dev, prop); char *str; int ret; @@ -658,44 +613,53 @@ static void set_generic(Object *obj, Visitor *v, void *opaque, } if (!*str) { g_free(str); - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + *ptr = NULL; return; } - ret = prop->info->parse(dev, prop, str); + ret = parse(dev, str, ptr); error_set_from_qdev_prop_error(errp, ret, dev, prop, str); g_free(str); } +static void get_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_drive, name, errp); +} + +static void set_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_drive, name, errp); +} + PropertyInfo qdev_prop_drive = { .name = "drive", - .type = PROP_TYPE_DRIVE, - .size = sizeof(BlockDriverState *), - .parse = parse_drive, - .print = print_drive, - .get = get_generic, - .set = set_generic, - .free = free_drive, + .get = get_drive, + .set = set_drive, + .release = release_drive, }; /* --- character device --- */ -static int parse_chr(DeviceState *dev, Property *prop, const char *str) +static int parse_chr(DeviceState *dev, const char *str, void **ptr) { - CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - *ptr = qemu_chr_find(str); - if (*ptr == NULL) { + CharDriverState *chr = qemu_chr_find(str); + if (chr == NULL) { return -ENOENT; } - if ((*ptr)->avail_connections < 1) { + if (chr->avail_connections < 1) { return -EEXIST; } - --(*ptr)->avail_connections; + *ptr = chr; + --chr->avail_connections; return 0; } -static void free_chr(DeviceState *dev, Property *prop) +static void release_chr(Object *obj, const char *name, void *opaque) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); if (*ptr) { @@ -704,62 +668,71 @@ static void free_chr(DeviceState *dev, Property *prop) } -static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len) +static const char *print_chr(void *ptr) { - CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); + CharDriverState *chr = ptr; - if (*ptr && (*ptr)->label) { - return snprintf(dest, len, "%s", (*ptr)->label); - } else { - return snprintf(dest, len, "<null>"); - } + return chr->label ? chr->label : ""; +} + +static void get_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_chr, name, errp); +} + +static void set_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_chr, name, errp); } PropertyInfo qdev_prop_chr = { .name = "chr", - .type = PROP_TYPE_CHR, - .size = sizeof(CharDriverState*), - .parse = parse_chr, - .print = print_chr, - .get = get_generic, - .set = set_generic, - .free = free_chr, + .get = get_chr, + .set = set_chr, + .release = release_chr, }; /* --- netdev device --- */ -static int parse_netdev(DeviceState *dev, Property *prop, const char *str) +static int parse_netdev(DeviceState *dev, const char *str, void **ptr) { - VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); + VLANClientState *netdev = qemu_find_netdev(str); - *ptr = qemu_find_netdev(str); - if (*ptr == NULL) + if (netdev == NULL) { return -ENOENT; - if ((*ptr)->peer) { + } + if (netdev->peer) { return -EEXIST; } + *ptr = netdev; return 0; } -static int print_netdev(DeviceState *dev, Property *prop, char *dest, size_t len) +static const char *print_netdev(void *ptr) { - VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); + VLANClientState *netdev = ptr; - if (*ptr && (*ptr)->name) { - return snprintf(dest, len, "%s", (*ptr)->name); - } else { - return snprintf(dest, len, "<null>"); - } + return netdev->name ? netdev->name : ""; +} + +static void get_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_netdev, name, errp); +} + +static void set_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_netdev, name, errp); } PropertyInfo qdev_prop_netdev = { .name = "netdev", - .type = PROP_TYPE_NETDEV, - .size = sizeof(VLANClientState*), - .parse = parse_netdev, - .print = print_netdev, - .get = get_generic, - .set = set_generic, + .get = get_netdev, + .set = set_netdev, }; /* --- vlan --- */ @@ -835,8 +808,6 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_vlan = { .name = "vlan", - .type = PROP_TYPE_VLAN, - .size = sizeof(VLANClientState*), .parse = parse_vlan, .print = print_vlan, .get = get_vlan, @@ -848,8 +819,6 @@ PropertyInfo qdev_prop_vlan = { /* Not a proper property, just for dirty hacks. TODO Remove it! */ PropertyInfo qdev_prop_ptr = { .name = "ptr", - .type = PROP_TYPE_PTR, - .size = sizeof(void*), }; /* --- mac address --- */ @@ -859,95 +828,114 @@ PropertyInfo qdev_prop_ptr = { * 01:02:03:04:05:06 * 01-02-03-04-05-06 */ -static int parse_mac(DeviceState *dev, Property *prop, const char *str) +static void get_mac(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + MACAddr *mac = qdev_get_prop_ptr(dev, prop); + char buffer[2 * 6 + 5 + 1]; + char *p = buffer; + + snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", + mac->a[0], mac->a[1], mac->a[2], + mac->a[3], mac->a[4], mac->a[5]); + + visit_type_str(v, &p, name, errp); +} + +static void set_mac(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; MACAddr *mac = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; int i, pos; - char *p; + char *str, *p; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } for (i = 0, pos = 0; i < 6; i++, pos += 3) { if (!qemu_isxdigit(str[pos])) - return -EINVAL; + goto inval; if (!qemu_isxdigit(str[pos+1])) - return -EINVAL; + goto inval; if (i == 5) { if (str[pos+2] != '\0') - return -EINVAL; + goto inval; } else { if (str[pos+2] != ':' && str[pos+2] != '-') - return -EINVAL; + goto inval; } mac->a[i] = strtol(str+pos, &p, 16); } - return 0; -} + return; -static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - MACAddr *mac = qdev_get_prop_ptr(dev, prop); - - return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x", - mac->a[0], mac->a[1], mac->a[2], - mac->a[3], mac->a[4], mac->a[5]); +inval: + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); } PropertyInfo qdev_prop_macaddr = { .name = "macaddr", - .type = PROP_TYPE_MACADDR, - .size = sizeof(MACAddr), - .parse = parse_mac, - .print = print_mac, - .get = get_generic, - .set = set_generic, + .get = get_mac, + .set = set_mac, }; /* --- lost tick policy --- */ -static const struct { - const char *name; - LostTickPolicy code; -} lost_tick_policy_table[] = { - { .name = "discard", .code = LOST_TICK_DISCARD }, - { .name = "delay", .code = LOST_TICK_DELAY }, - { .name = "merge", .code = LOST_TICK_MERGE }, - { .name = "slew", .code = LOST_TICK_SLEW }, +static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = { + [LOST_TICK_DISCARD] = "discard", + [LOST_TICK_DELAY] = "delay", + [LOST_TICK_MERGE] = "merge", + [LOST_TICK_SLEW] = "slew", + [LOST_TICK_MAX] = NULL, }; -static int parse_lost_tick_policy(DeviceState *dev, Property *prop, - const char *str) +QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); + +static void get_enum(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { - LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop); - int i; + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + int *ptr = qdev_get_prop_ptr(dev, prop); - for (i = 0; i < ARRAY_SIZE(lost_tick_policy_table); i++) { - if (!strcasecmp(str, lost_tick_policy_table[i].name)) { - *ptr = lost_tick_policy_table[i].code; - break; - } - } - if (i == ARRAY_SIZE(lost_tick_policy_table)) { - return -EINVAL; - } - return 0; + visit_type_enum(v, ptr, prop->info->enum_table, + prop->info->name, prop->name, errp); } -static int print_lost_tick_policy(DeviceState *dev, Property *prop, char *dest, - size_t len) +static void set_enum(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { - LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop); + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + int *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } - return snprintf(dest, len, "%s", lost_tick_policy_table[*ptr].name); + visit_type_enum(v, ptr, prop->info->enum_table, + prop->info->name, prop->name, errp); } PropertyInfo qdev_prop_losttickpolicy = { - .name = "lost_tick_policy", - .type = PROP_TYPE_LOSTTICKPOLICY, - .size = sizeof(LostTickPolicy), - .parse = parse_lost_tick_policy, - .print = print_lost_tick_policy, - .get = get_generic, - .set = set_generic, + .name = "LostTickPolicy", + .enum_table = lost_tick_policy_table, + .get = get_enum, + .set = set_enum, }; /* --- pci address --- */ @@ -987,30 +975,18 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t } } -static void get_pci_devfn(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - char buffer[32]; - char *p = buffer; - - buffer[0] = 0; - if (*ptr != -1) { - snprintf(buffer, sizeof(buffer), "%02x.%x", *ptr >> 3, *ptr & 7); - } - visit_type_str(v, &p, name, errp); -} - PropertyInfo qdev_prop_pci_devfn = { - .name = "pci-devfn", - .type = PROP_TYPE_UINT32, - .size = sizeof(uint32_t), + .name = "int32", + .legacy_name = "pci-devfn", .parse = parse_pci_devfn, .print = print_pci_devfn, - .get = get_pci_devfn, - .set = set_generic, + .get = get_int32, + .set = set_int32, + /* FIXME: this should be -1...255, but the address is stored + * into an uint32_t rather than int32_t. + */ + .min = 0, + .max = 0xFFFFFFFFULL, }; /* --- public helpers --- */ @@ -1073,24 +1049,18 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) { - Property *prop; - int ret; + char *legacy_name; + Error *err = NULL; - prop = qdev_prop_find(dev, name); - /* - * TODO Properties without a parse method are just for dirty - * hacks. qdev_prop_ptr is the only such PropertyInfo. It's - * marked for removal. The test !prop->info->parse should be - * removed along with it. - */ - if (!prop || !prop->info->parse) { - qerror_report(QERR_PROPERTY_NOT_FOUND, object_get_typename(OBJECT(dev)), name); - return -1; + legacy_name = g_strdup_printf("legacy-%s", name); + if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { + object_property_set_str(OBJECT(dev), value, legacy_name, &err); + } else { + object_property_set_str(OBJECT(dev), value, name, &err); } - ret = prop->info->parse(dev, prop, value); - if (ret < 0) { - Error *err; - error_set_from_qdev_prop_error(&err, ret, dev, prop, value); + g_free(legacy_name); + + if (err) { qerror_report_err(err); error_free(err); return -1; @@ -1098,72 +1068,66 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) return 0; } -void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type) -{ - Property *prop; - - prop = qdev_prop_find(dev, name); - if (!prop) { - fprintf(stderr, "%s: property \"%s.%s\" not found\n", - __FUNCTION__, object_get_typename(OBJECT(dev)), name); - abort(); - } - if (prop->info->type != type) { - fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n", - __FUNCTION__, object_get_typename(OBJECT(dev)), name); - abort(); - } - qdev_prop_cpy(dev, prop, src); -} - void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_BIT); + Error *errp = NULL; + object_property_set_bool(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_INT32); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_string(DeviceState *dev, const char *name, char *value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_STRING); + Error *errp = NULL; + object_property_set_str(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) { - int res; - - res = bdrv_attach_dev(value, dev); - if (res < 0) { - error_report("Can't attach drive %s to %s.%s: %s", - bdrv_get_device_name(value), - dev->id ? dev->id : object_get_typename(OBJECT(dev)), - name, strerror(-res)); + Error *errp = NULL; + 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); + error_free(errp); return -1; } - qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE); return 0; } @@ -1175,44 +1139,81 @@ void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverS } void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_CHR); + Error *errp = NULL; + 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) { - qdev_prop_set(dev, name, &value, PROP_TYPE_NETDEV); + Error *errp = NULL; + 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) { - qdev_prop_set(dev, name, &value, PROP_TYPE_VLAN); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value ? value->id : -1, name, &errp); + assert_no_error(errp); } void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) { - qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR); + Error *errp = NULL; + char str[2 * 6 + 5 + 1]; + snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", + value[0], value[1], value[2], value[3], value[4], value[5]); + + object_property_set_str(OBJECT(dev), str, name, &errp); + assert_no_error(errp); } -void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name, - LostTickPolicy *value) +void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) { - qdev_prop_set(dev, name, value, PROP_TYPE_LOSTTICKPOLICY); + Property *prop; + Error *errp = NULL; + + prop = qdev_prop_find(dev, name); + object_property_set_str(OBJECT(dev), prop->info->enum_table[value], + name, &errp); + assert_no_error(errp); } void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_PTR); + Property *prop; + void **ptr; + + prop = qdev_prop_find(dev, name); + assert(prop && prop->info == &qdev_prop_ptr); + ptr = qdev_get_prop_ptr(dev, prop); + *ptr = value; } void qdev_prop_set_defaults(DeviceState *dev, Property *props) { + Object *obj = OBJECT(dev); if (!props) return; - while (props->name) { - if (props->defval) { - qdev_prop_cpy(dev, props, props->defval); + for (; props->name; props++) { + Error *errp = NULL; + if (props->qtype == QTYPE_NONE) { + continue; } - props++; + if (props->qtype == QTYPE_QBOOL) { + object_property_set_bool(obj, props->defval, props->name, &errp); + } else if (props->info->enum_table) { + object_property_set_str(obj, props->info->enum_table[props->defval], + props->name, &errp); + } else if (props->qtype == QTYPE_QINT) { + object_property_set_int(obj, props->defval, props->name, &errp); + } + assert_no_error(errp); } } @@ -86,11 +86,11 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus) dev->parent_bus = bus; QTAILQ_INSERT_HEAD(&bus->children, dev, sibling); - qdev_prop_set_defaults(dev, dev->parent_bus->info->props); for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) { qdev_property_add_legacy(dev, prop, NULL); qdev_property_add_static(dev, prop, NULL); } + qdev_prop_set_defaults(dev, dev->parent_bus->info->props); } /* Create a new device. This only initializes the device state structure @@ -550,21 +550,24 @@ static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque, * Do not use this is new code! Properties added through this interface will * be given names and types in the "legacy" namespace. * - * Legacy properties are always processed as strings. The format of the string - * depends on the property type. + * Legacy properties are string versions of other OOM properties. The format + * of the string depends on the property type. */ void qdev_property_add_legacy(DeviceState *dev, Property *prop, Error **errp) { gchar *name, *type; + if (!prop->info->print && !prop->info->parse) { + return; + } name = g_strdup_printf("legacy-%s", prop->name); type = g_strdup_printf("legacy<%s>", prop->info->legacy_name ?: prop->info->name); object_property_add(OBJECT(dev), name, type, - prop->info->print ? qdev_get_legacy_property : NULL, - prop->info->parse ? qdev_set_legacy_property : NULL, + prop->info->print ? qdev_get_legacy_property : prop->info->get, + prop->info->parse ? qdev_set_legacy_property : prop->info->set, NULL, prop, errp); @@ -581,9 +584,18 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop, void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp) { + /* + * TODO qdev_prop_ptr does not have getters or setters. It must + * go now that it can be replaced with links. The test should be + * removed along with it: all static properties are read/write. + */ + if (!prop->info->get && !prop->info->set) { + return; + } + object_property_add(OBJECT(dev), prop->name, prop->info->name, prop->info->get, prop->info->set, - NULL, + prop->info->release, prop, errp); } @@ -600,13 +612,13 @@ static void device_initfn(Object *obj) dev->instance_id_alias = -1; dev->state = DEV_STATE_CREATED; - qdev_prop_set_defaults(dev, qdev_get_props(dev)); for (prop = qdev_get_props(dev); prop && prop->name; prop++) { qdev_property_add_legacy(dev, prop, NULL); qdev_property_add_static(dev, prop, NULL); } object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL); + qdev_prop_set_defaults(dev, qdev_get_props(dev)); } /* Unlink device from bus and free the structure. */ @@ -614,7 +626,6 @@ static void device_finalize(Object *obj) { DeviceState *dev = DEVICE(obj); BusState *bus; - Property *prop; DeviceClass *dc = DEVICE_GET_CLASS(dev); if (dev->state == DEV_STATE_INITIALIZED) { @@ -633,11 +644,6 @@ static void device_finalize(Object *obj) } } QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling); - for (prop = qdev_get_props(dev); prop && prop->name; prop++) { - if (prop->info->free) { - prop->info->free(dev, prop); - } - } } void device_reset(DeviceState *dev) @@ -659,9 +665,9 @@ static TypeInfo device_type_info = { .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) @@ -112,41 +112,22 @@ struct Property { const char *name; PropertyInfo *info; int offset; - int bitnr; - void *defval; -}; - -enum PropertyType { - PROP_TYPE_UNSPEC = 0, - PROP_TYPE_UINT8, - PROP_TYPE_UINT16, - PROP_TYPE_UINT32, - PROP_TYPE_INT32, - PROP_TYPE_UINT64, - PROP_TYPE_TADDR, - PROP_TYPE_MACADDR, - PROP_TYPE_LOSTTICKPOLICY, - PROP_TYPE_DRIVE, - PROP_TYPE_CHR, - PROP_TYPE_STRING, - PROP_TYPE_NETDEV, - PROP_TYPE_VLAN, - PROP_TYPE_PTR, - PROP_TYPE_BIT, + uint8_t bitnr; + uint8_t qtype; + int64_t defval; }; struct PropertyInfo { const char *name; const char *legacy_name; - size_t size; - enum PropertyType type; + const char **enum_table; int64_t min; int64_t max; int (*parse)(DeviceState *dev, Property *prop, const char *str); int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); - void (*free)(DeviceState *dev, Property *prop); ObjectPropertyAccessor *get; ObjectPropertyAccessor *set; + ObjectPropertyRelease *release; }; typedef struct GlobalProperty { @@ -254,7 +235,8 @@ extern PropertyInfo qdev_prop_pci_devfn; .info = &(_prop), \ .offset = offsetof(_state, _field) \ + type_check(_type,typeof_field(_state, _field)), \ - .defval = (_type[]) { _defval }, \ + .qtype = QTYPE_QINT, \ + .defval = (_type)_defval, \ } #define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \ .name = (_name), \ @@ -262,7 +244,8 @@ extern PropertyInfo qdev_prop_pci_devfn; .bitnr = (_bit), \ .offset = offsetof(_state, _field) \ + type_check(uint32_t,typeof_field(_state, _field)), \ - .defval = (bool[]) { (_defval) }, \ + .qtype = QTYPE_QBOOL, \ + .defval = (bool)_defval, \ } #define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ @@ -309,7 +292,6 @@ extern PropertyInfo qdev_prop_pci_devfn; void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); int qdev_prop_exists(DeviceState *dev, const char *name); int qdev_prop_parse(DeviceState *dev, const char *name, const char *value); -void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type); void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value); void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value); void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value); @@ -323,8 +305,7 @@ void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value); int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT; void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value); void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); -void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name, - LostTickPolicy *value); +void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); /* FIXME: Remove opaque pointer properties. */ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); void qdev_prop_set_defaults(DeviceState *dev, Property *props); @@ -1870,10 +1870,10 @@ static TypeInfo qxl_secondary_info = { .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 821e627560..bcf982fac5 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -96,7 +96,7 @@ static TypeInfo realview_i2c_info = { .class_init = realview_i2c_class_init, }; -static void realview_register_devices(void) +static void realview_register_types(void) { type_register_static(&realview_i2c_info); } @@ -217,8 +217,8 @@ static void realview_init(ram_addr_t ram_size, sys_id = is_pb ? 0x01780500 : 0xc1400400; sysctl = qdev_create(NULL, "realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", sys_id); - qdev_init_nofail(sysctl); qdev_prop_set_uint32(sysctl, "proc_id", proc_id); + qdev_init_nofail(sysctl); sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); if (is_mpcore) { @@ -491,4 +491,4 @@ static void realview_machine_init(void) } 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 4121502c7b..071ef13c9e 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -60,9 +60,9 @@ static TypeInfo realview_gic_info = { .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 1668390e1f..05b8e1e3d7 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3523,9 +3523,9 @@ static TypeInfo rtl8139_info = { .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 49140f8a9e..9d480564d7 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -433,15 +433,6 @@ static TypeInfo virtio_s390_device_info = { .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 @@ static TypeInfo s390_virtio_bridge_info = { .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) @@ -1417,8 +1417,9 @@ static TypeInfo sb16_info = { .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) @@ -148,9 +148,9 @@ static TypeInfo sbi_info = { .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 0ee50a8360..b3e97ceeec 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1431,9 +1431,9 @@ static TypeInfo scsi_device_type_info = { .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 399e51e494..c12e3a6cb3 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1823,7 +1823,7 @@ static TypeInfo scsi_disk_info = { .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 @@ static void scsi_disk_register_devices(void) #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 4859212734..86014aa893 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -483,10 +483,11 @@ static TypeInfo scsi_generic_info = { .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 82917e24d7..144d1b3526 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -903,9 +903,9 @@ static TypeInfo serial_isa_info = { .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) @@ -55,9 +55,9 @@ static TypeInfo sga_info = { .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 4234d935e7..0cfac46f7f 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -177,10 +177,10 @@ static TypeInfo sh_pci_device_info = { .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 e3701c75d2..7fdc3be086 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -463,9 +463,9 @@ static TypeInfo slavio_intctl_info = { .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 5a025186af..944835e880 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -499,10 +499,10 @@ static TypeInfo apc_info = { .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 3878f6fa5e..97edebb3ba 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -427,9 +427,9 @@ static TypeInfo slavio_timer_info = { .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 94c0abf4cb..786e07629c 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -1327,8 +1327,8 @@ static void sm501_draw_crt(SM501State * s) 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 77626f3645..e3cf6a2cc8 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -327,9 +327,9 @@ static TypeInfo smbus_device_type_info = { .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 9d96cbe41a..11adab01b8 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -130,12 +130,12 @@ static TypeInfo smbus_eeprom_info = { .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 1bf2901d1a..1a5213fa56 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -781,7 +781,7 @@ static TypeInfo smc91c111_info = { .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 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) 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 84281be9e2..6ac7384013 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -672,7 +672,7 @@ target_ulong spapr_hypercall(CPUState *env, target_ulong opcode, 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 @@ static void hypercall_init(void) /* 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 79b394132b..77d40479c8 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -501,7 +501,7 @@ static TypeInfo spapr_vlan_info = { .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 @@ static void spapr_vlan_register(void) 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 ed2e4b33e7..cfdd9ddd41 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -242,13 +242,13 @@ static TypeInfo spapr_phb_info = { .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 d1ac74cfbd..c0723b3039 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -288,7 +288,7 @@ int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr, 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 @@ static void register_core_rtas(void) 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 64f0009814..ea317efbe4 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -778,13 +778,13 @@ static TypeInfo spapr_vio_type_info = { .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 9cfce19a73..ffce261f98 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -973,8 +973,9 @@ static TypeInfo spapr_vscsi_info = { .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 a954e7d29b..3efe24211e 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -212,10 +212,11 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) 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 f07cc6fdf0..1dbf69e808 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -307,9 +307,9 @@ static TypeInfo sparc32_dma_info = { .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 4e6540d976..1d6d2b0e1b 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1138,7 +1138,7 @@ static TypeInfo spitz_lcdtg_info = { .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 @@ static void spitz_register_devices(void) 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 685602a584..4e1ee6e12b 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -313,9 +313,9 @@ static TypeInfo ssd0303_info = { .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 3c43738ae1..b0b2e94a81 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -355,9 +355,9 @@ static TypeInfo ssd0323_info = { .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 f2e6cecb71..b519bdb29a 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -259,9 +259,9 @@ static TypeInfo ssi_sd_info = { .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) @@ -80,9 +80,9 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val) 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 31a65cfb77..562fbbf494 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1451,7 +1451,7 @@ static TypeInfo stellaris_adc_info = { .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 @@ static void stellaris_register_devices(void) 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 9b1be8dadc..fbe99cb4a9 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -441,9 +441,9 @@ static TypeInfo stellaris_enet_info = { .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 8d2e7eb6fe..4d5b60fd1f 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -1609,7 +1609,7 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, 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 @@ static void strongarm_register_devices(void) 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 081d6cc8bd..8dfa5ecab6 100644 --- a/hw/sun4c_intctl.c +++ b/hw/sun4c_intctl.c @@ -223,9 +223,9 @@ static TypeInfo sun4c_intctl_info = { .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 b79d14c35a..99fb219b3a 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -623,13 +623,6 @@ static TypeInfo idreg_info = { .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 @@ static TypeInfo afx_info = { .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 @@ static TypeInfo prom_info = { .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 @@ static TypeInfo ram_info = { .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 @@ static QEMUMachine ss2_machine = { .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 @@ static void ss2_machine_init(void) 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 727532cb09..ebefa91b7a 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -380,9 +380,9 @@ static TypeInfo iommu_info = { .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 79bbd495eb..423108f236 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -580,13 +580,6 @@ static TypeInfo ebus_info = { .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 @@ static TypeInfo prom_info = { .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 @@ static TypeInfo ram_info = { .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 @@ static QEMUMachine niagara_machine = { .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 @@ static void sun4u_machine_init(void) 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 282060abb6..db4efccef4 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -256,9 +256,9 @@ static TypeInfo sysbus_device_type_info = { .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) @@ -664,9 +664,9 @@ static TypeInfo tcx_info = { .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 a3bdd91d40..8e8dbd94eb 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -245,9 +245,9 @@ static TypeInfo tmp105_info = { .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) @@ -291,10 +291,10 @@ static TypeInfo tosa_ssp_info = { .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 0ade670906..5ba8da6d6a 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -805,9 +805,9 @@ static TypeInfo tusb6010_info = { .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 03fdccc8ce..873dc8f068 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -876,9 +876,9 @@ static TypeInfo twl92230_info = { .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 17d86aac68..409bcd4cc6 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -467,7 +467,7 @@ static TypeInfo pci_unin_internal_info = { .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 @@ static void unin_register_devices(void) 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 cd589b718a..fed136117b 100644 --- a/hw/usb-audio.c +++ b/hw/usb-audio.c @@ -607,7 +607,7 @@ static int usb_audio_handle_data(USBDevice *dev, USBPacket *p) 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 @@ fail: 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 @@ static void usb_audio_class_init(ObjectClass *klass, void *data) 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 @@ static TypeInfo usb_audio_info = { .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 90c3b0e0eb..649bdcf2d7 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -423,7 +423,7 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo bt_info = { .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 b753834584..ae79a4527b 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -74,21 +74,21 @@ static int usb_device_init(USBDevice *dev) return 0; } -static void usb_device_handle_destroy(USBDevice *dev) +USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); - if (klass->handle_destroy) { - klass->handle_destroy(dev); + if (klass->find_device) { + return klass->find_device(dev, addr); } + return NULL; } -int usb_device_handle_packet(USBDevice *dev, USBPacket *p) +static void usb_device_handle_destroy(USBDevice *dev) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); - if (klass->handle_packet) { - return klass->handle_packet(dev, p); + if (klass->handle_destroy) { + klass->handle_destroy(dev); } - return -ENOSYS; } void usb_device_cancel_packet(USBDevice *dev, USBPacket *p) @@ -586,9 +586,9 @@ static TypeInfo usb_device_type_info = { .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 881da3002e..0b2ac8037a 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -267,6 +267,7 @@ typedef struct CCIDBus { */ typedef struct USBCCIDState { USBDevice dev; + USBEndpoint *intr; CCIDBus bus; CCIDCardState *card; BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */ @@ -839,7 +840,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full) 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 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int ccid_initfn(USBDevice *dev) 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 @@ static void ccid_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo ccid_card_type_info = { .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 75ef71e69e..e699814305 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -715,8 +715,8 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev) 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 @@ static void ehci_detach(USBPort *port) 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 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], 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 @@ static void ehci_reset(void *opaque) } 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 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) 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 @@ err: static int ehci_execute(EHCIQueue *q) { - USBPort *port; USBDevice *dev; + USBEndpoint *ep; int ret; - int i; int endp; int devadr; @@ -1364,33 +1388,18 @@ static int ehci_execute(EHCIQueue *q) 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_execute(EHCIQueue *q) 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 @@ static int ehci_process_itd(EHCIState *ehci, 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 @@ static int usb_ehci_initfn(PCIDevice *dev) 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 3c4e45da70..7fc0bd81aa 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 @@ static void usb_hid_changed(HIDState *hs) { 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 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int usb_hid_initfn(USBDevice *dev, int kind) 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 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data) { 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 @@ static TypeInfo usb_keyboard_info = { .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 @@ static void usb_hid_register_devices(void) 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 956b020eed..a12856e2e9 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -37,6 +37,7 @@ typedef struct USBHubPort { typedef struct USBHubState { USBDevice dev; + USBEndpoint *intr; USBHubPort ports[NUM_PORTS]; } USBHubState; @@ -163,7 +164,7 @@ static void usb_hub_attach(USBPort *port1) } 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 @@ static void usb_hub_detach(USBPort *port1) 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 @@ static void usb_hub_wakeup(USBPort *port1) if (port->wPortStatus & PORT_STAT_SUSPEND) { port->wPortChange |= PORT_STAT_C_SUSPEND; - usb_wakeup(&s->dev); + usb_wakeup(s->intr); } } @@ -220,6 +221,26 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet) 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 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, 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 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int usb_hub_initfn(USBDevice *dev) 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 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo hub_info = { .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 6153376f3f..c933efe19a 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -341,7 +341,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo msd_info = { .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 4f528d25e5..820907a9a9 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -605,6 +605,8 @@ static int musb_timeout(int ttype, int speed, int val) 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 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, 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 @@ static void musb_async_cancel_device(MUSBState *s, USBDevice *dev) 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 @@ static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) 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 e2111413b4..49d5d4db65 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1210,7 +1210,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo net_info = { .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 425030f141..7aa19fe781 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -408,6 +408,23 @@ static void ohci_child_detach(USBPort *port1, USBDevice *child) 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 @@ static void ohci_reset(void *opaque) 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 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, 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 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, 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 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) int ret; int i; USBDevice *dev; + USBEndpoint *ep; struct ohci_td td; uint32_t addr; int flag_r; @@ -972,31 +982,22 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) 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 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) 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_mem_write(void *opaque, 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 @@ static TypeInfo ohci_sysbus_info = { .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 c2cb6d24e8..52676e8f7b 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -353,7 +353,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) { 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 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data) 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 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo braille_info = { .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 cddcc8927a..2280dc792d 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 @@ static const char *pid2str(int pid) #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 @@ static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev) 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 @@ static void uhci_reset(void *opaque) 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 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) } 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 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) /* 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 void uhci_wakeup(USBPort *port1) } } -static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) +static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr) { - int i, ret; - - 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); + USBDevice *dev; + int i; - 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 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in 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 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in 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 int qhdb_insert(QhDb *db, uint32_t addr) 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 @@ static void uhci_process_frame(UHCIState *s) 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 @@ static void uhci_process_frame(UHCIState *s) 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 @@ static TypeInfo ich9_uhci3_info = { .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 @@ static void uhci_register(void) 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 14de14d5f7..197e2dced5 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -306,7 +306,7 @@ static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data) 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 @@ static TypeInfo wacom_info = { .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 37e887c431..008b0b5718 100644 --- a/hw/usb-xhci.c +++ b/hw/usb-xhci.c @@ -307,7 +307,8 @@ typedef struct XHCIState XHCIState; 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 @@ typedef struct XHCIEPContext { 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 @@ typedef struct XHCIEvRingSeg { 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 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) } 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 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, 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 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, 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 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, 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 @@ static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer, } #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 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) 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 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) 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 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) 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 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) 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 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx 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 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx } 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 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx 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 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx 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 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid 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 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid 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 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid } } + 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 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) /* 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 @@ static void xhci_detach(USBPort *usbport) 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 void xhci_child_detach(USBPort *port, USBDevice *child) 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 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) 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 @@ static TypeInfo xhci_info = { .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) @@ -35,7 +35,8 @@ void usb_attach(USBPort *port) 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 @@ void usb_detach(USBPort *port) 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 @@ static int do_token_in(USBDevice *s, USBPacket *p) 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_in(USBDevice *s, USBPacket *p) 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 @@ static int do_token_out(USBDevice *s, USBPacket *p) } } -/* - * 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 @@ int set_usb_string(uint8_t *buf, const char *str) 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 usb_handle_packet(USBDevice *dev, USBPacket *p) { 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 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) 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 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p) 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 @@ void usb_packet_init(USBPacket *p) 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_skip(USBPacket *p, size_t bytes) void usb_packet_cleanup(USBPacket *p) { + assert(!usb_packet_is_inflight(p)); qemu_iovec_destroy(&p->iov); } @@ -415,16 +478,24 @@ void usb_ep_init(USBDevice *dev) { 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 @@ void usb_ep_dump(USBDevice *dev) 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; } @@ -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 @@ struct USBDescString { #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 @@ typedef struct USBDeviceClass { 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 @@ typedef struct USBPortOps { 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 @@ struct USBPort { 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_copy(USBPacket *p, void *ptr, size_t bytes); 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 @@ int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep); 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 USBBus { 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 @@ extern const VMStateDescription vmstate_usb_device; .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 c4105e977b..ae53a8b37b 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -154,11 +154,11 @@ static TypeInfo pci_realview_info = { .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 6e28e78f44..1903db6435 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -198,8 +198,8 @@ static void versatile_init(ram_addr_t ram_size, sysctl = qdev_create(NULL, "realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004); - qdev_init_nofail(sysctl); qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000); + qdev_init_nofail(sysctl); sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); cpu_pic = arm_pic_init_cpu(env); @@ -382,9 +382,9 @@ static TypeInfo vpb_sic_info = { .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/vexpress.c b/hw/vexpress.c index 64fab4574c..43f47a65ce 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -123,8 +123,8 @@ static void vexpress_a9_init(ram_addr_t ram_size, /* 0x10000000 System registers */ sysctl = qdev_create(NULL, "realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", sys_id); - qdev_init_nofail(sysctl); qdev_prop_set_uint32(sysctl, "proc_id", proc_id); + qdev_init_nofail(sysctl); sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); /* 0x10001000 SP810 system control */ diff --git a/hw/vga-isa.c b/hw/vga-isa.c index 8d3ff0d47b..4bcc4db62f 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -85,8 +85,9 @@ static TypeInfo vga_info = { .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 974a7a9d6f..465b643d21 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -96,8 +96,9 @@ static TypeInfo vga_info = { .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) @@ -1777,10 +1777,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) 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 4f2c3e4379..cffee3d470 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -149,12 +149,6 @@ static TypeInfo virtconsole_info = { .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 @@ static TypeInfo virtserialport_info = { .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 93fff54782..907b52a25d 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -930,7 +930,7 @@ static TypeInfo virtio_balloon_info = { .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 @@ static void virtio_pci_register_devices(void) 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 61176299a3..e22940ecb2 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -949,9 +949,9 @@ static TypeInfo virtio_serial_port_type_info = { .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 fda4f89a76..6338efa1c3 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -294,8 +294,9 @@ static TypeInfo vmmouse_info = { .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 a2c45e1950..9373be9775 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -159,8 +159,9 @@ static TypeInfo vmport_info = { .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 3f3eb21d02..f8afa3c367 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1223,8 +1223,9 @@ static TypeInfo vmsvga_info = { .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 aa0954f487..fbab0bbc07 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -366,13 +366,6 @@ static TypeInfo via_ac97_info = { .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 @@ static TypeInfo via_mc97_info = { .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 @@ static TypeInfo via_pm_info = { .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 @@ static TypeInfo via_info = { .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 41325f0955..15c69db932 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -448,10 +448,10 @@ static TypeInfo i6300esb_info = { .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 8faa2316c9..7f6c21d809 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -136,10 +136,10 @@ static TypeInfo wdt_ib700_info = { .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 18afa4c1ac..11bcec3410 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -708,9 +708,9 @@ static TypeInfo wm8750_info = { .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 e7571022e4..5a7c4cc97b 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -396,9 +396,9 @@ static TypeInfo xen_platform_info = { .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 d395b1cc2d..dd4bdc46f5 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -425,9 +425,9 @@ static TypeInfo xgmac_enet_info = { .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 e8a53123f9..85dfcbf2b9 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -508,9 +508,9 @@ static TypeInfo axidma_info = { .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 1ce2db4510..7526273b4d 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -894,9 +894,10 @@ static TypeInfo xilinx_enet_info = { .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 499feef488..857b33d172 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -249,9 +249,9 @@ static TypeInfo xilinx_ethlite_info = { .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 73eed6dc5f..553f8488f6 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -182,9 +182,9 @@ static TypeInfo xilinx_intc_info = { .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 c8236d2e2a..3ab2f2bb03 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -241,9 +241,9 @@ static TypeInfo xilinx_timer_info = { .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 1c2b9087b4..aa0170db49 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -225,9 +225,9 @@ static TypeInfo xilinx_uartlite_info = { .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 07e4fc1018..319624f212 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -203,12 +203,12 @@ static TypeInfo xio3130_downstream_info = { .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 7887c92fcc..34a99bba08 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -177,12 +177,12 @@ static TypeInfo xio3130_upstream_info = { .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 055df9b4e2..72838ec440 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -243,11 +243,12 @@ static TypeInfo scoop_sysbus_info = { .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 9d0251d56a..69cc2abc66 100644 --- a/include/qemu/object.h +++ b/include/qemu/object.h @@ -55,6 +55,9 @@ typedef struct InterfaceInfo InterfaceInfo; * * #define TYPE_MY_DEVICE "my-device" * + * // No new virtual functions: we can reuse the typedef for the + * // superclass. + * typedef DeviceClass MyDeviceClass; * typedef struct MyDevice * { * DeviceState parent; @@ -68,12 +71,12 @@ typedef struct InterfaceInfo InterfaceInfo; * .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> * @@ -88,8 +91,21 @@ typedef struct InterfaceInfo InterfaceInfo; * * Using object_new(), a new #Object derivative will be instantiated. You can * cast an #Object to a subclass (or base-class) type using - * object_dynamic_cast(). You typically want to define a macro wrapper around - * object_dynamic_cast_assert() to make it easier to convert to a specific type. + * object_dynamic_cast(). You typically want to define macro wrappers around + * OBJECT_CHECK() and OBJECT_CLASS_CHECK() to make it easier to convert to a + * specific type: + * + * <example> + * <title>Typecasting macros</title> + * <programlisting> + * #define MY_DEVICE_GET_CLASS(obj) \ + * OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE) + * #define MY_DEVICE_CLASS(klass) \ + * OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE) + * #define MY_DEVICE(obj) \ + * OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE) + * </programlisting> + * </example> * * # Class Initialization # * @@ -108,7 +124,61 @@ typedef struct InterfaceInfo InterfaceInfo; * * Once all of the parent classes have been initialized, #TypeInfo::class_init * is called to let the class being instantiated provide default initialize for - * it's virtual functions. + * it's virtual functions. Here is how the above example might be modified + * to introduce an overridden virtual function: + * + * <example> + * <title>Overriding a virtual function</title> + * <programlisting> + * #include "qdev.h" + * + * void my_device_class_init(ObjectClass *klass, void *class_data) + * { + * DeviceClass *dc = DEVICE_CLASS(klass); + * dc->reset = my_device_reset; + * } + * + * static TypeInfo my_device_info = { + * .name = TYPE_MY_DEVICE, + * .parent = TYPE_DEVICE, + * .instance_size = sizeof(MyDevice), + * .class_init = my_device_class_init, + * }; + * </programlisting> + * </example> + * + * Introducing new virtual functions requires a class to define its own + * struct and to add a .class_size member to the TypeInfo. Each function + * will also have a wrapper to call it easily: + * + * <example> + * <title>Defining an abstract class</title> + * <programlisting> + * #include "qdev.h" + * + * typedef struct MyDeviceClass + * { + * DeviceClass parent; + * + * void (*frobnicate) (MyDevice *obj); + * } MyDeviceClass; + * + * static TypeInfo my_device_info = { + * .name = TYPE_MY_DEVICE, + * .parent = TYPE_DEVICE, + * .instance_size = sizeof(MyDevice), + * .abstract = true, // or set a default in my_device_class_init + * .class_size = sizeof(MyDeviceClass), + * }; + * + * void my_device_frobnicate(MyDevice *obj) + * { + * MyDeviceClass *klass = MY_DEVICE_GET_CLASS(obj); + * + * klass->frobnicate(obj); + * } + * </programlisting> + * </example> * * # Interfaces # * @@ -259,6 +329,16 @@ struct TypeInfo ((Object *)(obj)) /** + * OBJECT_CLASS: + * @class: A derivative of #ObjectClas. + * + * Converts a class to an #ObjectClass. Since all objects are #Objects, + * this function will always succeed. + */ +#define OBJECT_CLASS(class) \ + ((ObjectClass *)(class)) + +/** * OBJECT_CHECK: * @type: The C type to use for the return value. * @obj: A derivative of @type to cast. @@ -272,7 +352,7 @@ struct TypeInfo * generated. */ #define OBJECT_CHECK(type, obj, name) \ - ((type *)object_dynamic_cast_assert((Object *)(obj), (name))) + ((type *)object_dynamic_cast_assert(OBJECT(obj), (name))) /** * OBJECT_CLASS_CHECK: @@ -280,11 +360,12 @@ struct TypeInfo * @obj: A derivative of @type to cast. * @name: the QOM typename of @class. * - * A type safe version of @object_check_class. This macro is typically wrapped - * by each type to perform type safe casts of a class to a specific class type. + * A type safe version of @object_class_dynamic_cast_assert. This macro is + * typically wrapped by each type to perform type safe casts of a class to a + * specific class type. */ #define OBJECT_CLASS_CHECK(class, obj, name) \ - ((class *)object_class_dynamic_cast_assert((ObjectClass *)(obj), (name))) + ((class *)object_class_dynamic_cast_assert(OBJECT_CLASS(obj), (name))) /** * OBJECT_GET_CLASS: @@ -299,9 +380,6 @@ struct TypeInfo #define OBJECT_GET_CLASS(class, obj, name) \ OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name) -#define OBJECT_CLASS(class) \ - ((ObjectClass *)(class)) - /** * InterfaceClass: * @parent_class: the base class @@ -544,6 +622,100 @@ void object_property_get(Object *obj, struct Visitor *v, const char *name, struct Error **errp); /** + * object_property_set_str: + * @value: the value to be written to the property + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Writes a string value to a property. + */ +void object_property_set_str(Object *obj, const char *value, + const char *name, struct Error **errp); + +/** + * object_property_get_str: + * @obj: the object + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Returns: the value of the property, converted to a C string, or NULL if + * an error occurs (including when the property value is not a string). + * The caller should free the string. + */ +char *object_property_get_str(Object *obj, const char *name, + struct Error **errp); + +/** + * object_property_set_link: + * @value: the value to be written to the property + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Writes an object's canonical path to a property. + */ +void object_property_set_link(Object *obj, Object *value, + const char *name, struct Error **errp); + +/** + * object_property_get_link: + * @obj: the object + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Returns: the value of the property, resolved from a path to an Object, + * or NULL if an error occurs (including when the property value is not a + * string or not a valid object path). + */ +Object *object_property_get_link(Object *obj, const char *name, + struct Error **errp); + +/** + * object_property_set_bool: + * @value: the value to be written to the property + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Writes a bool value to a property. + */ +void object_property_set_bool(Object *obj, bool value, + const char *name, struct Error **errp); + +/** + * object_property_get_bool: + * @obj: the object + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Returns: the value of the property, converted to a boolean, or NULL if + * an error occurs (including when the property value is not a bool). + */ +bool object_property_get_bool(Object *obj, const char *name, + struct Error **errp); + +/** + * object_property_set_int: + * @value: the value to be written to the property + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Writes an integer value to a property. + */ +void object_property_set_int(Object *obj, int64_t value, + const char *name, struct Error **errp); + +/** + * object_property_get_int: + * @obj: the object + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Returns: the value of the property, converted to an integer, or NULL if + * an error occurs (including when the property value is not an integer). + */ +int64_t object_property_get_int(Object *obj, const char *name, + struct Error **errp); + +/** * object_property_set: * @obj: the object * @v: the visitor that will be used to write the property value. This should @@ -601,14 +773,35 @@ gchar *object_get_canonical_path(Object *obj); * specifying objects easy. At each level of the composition tree, the partial * path is matched as an absolute path. The first match is not returned. At * least two matches are searched for. A successful result is only returned if - * only one match is founded. If more than one match is found, a flag is - * return to indicate that the match was ambiguous. + * only one match is found. If more than one match is found, a flag is + * returned to indicate that the match was ambiguous. * * Returns: The matched object or NULL on path lookup failure. */ Object *object_resolve_path(const char *path, bool *ambiguous); /** + * object_resolve_path_type: + * @path: the path to resolve + * @typename: the type to look for. + * @ambiguous: returns true if the path resolution failed because of an + * ambiguous match + * + * This is similar to object_resolve_path. However, when looking for a + * partial path only matches that implement the given type are considered. + * This restricts the search and avoids spuriously flagging matches as + * ambiguous. + * + * For both partial and absolute paths, the return value goes through + * a dynamic cast to @typename. This is important if either the link, + * or the typename itself are of interface types. + * + * Returns: The matched object or NULL on path lookup failure. + */ +Object *object_resolve_path_type(const char *path, const char *typename, + bool *ambiguous); + +/** * object_property_add_child: * @obj: the object to add a property to * @name: the name of the property diff --git a/include/qemu/qom-qobject.h b/include/qemu/qom-qobject.h new file mode 100644 index 0000000000..f9dff12f11 --- /dev/null +++ b/include/qemu/qom-qobject.h @@ -0,0 +1,42 @@ +/* + * QEMU Object Model - QObject wrappers + * + * Copyright (C) 2012 Red Hat, Inc. + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_QOM_QOBJECT_H +#define QEMU_QOM_QOBJECT_H + +#include "qemu/object.h" + +/* + * object_property_get_qobject: + * @obj: the object + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Returns: the value of the property, converted to QObject, or NULL if + * an error occurs. + */ +struct QObject *object_property_get_qobject(Object *obj, const char *name, + struct Error **errp); + +/** + * object_property_set_qobject: + * @obj: the object + * @ret: The value that will be written to the property. + * @name: the name of the property + * @errp: returns an error if this function fails + * + * Writes a property to a object. + */ +void object_property_set_qobject(Object *obj, struct QObject *qobj, + const char *name, struct Error **errp); + +#endif diff --git a/libcacard/Makefile b/libcacard/Makefile index a145569044..c6a896a739 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -15,8 +15,6 @@ QEMU_OBJS_LIB=$(addsuffix .lo,$(basename $(QEMU_OBJS))) QEMU_CFLAGS+=-I../ -QEMU_CFLAGS+=$(GLIB_CFLAGS) - libcacard.lib-y=$(addsuffix .lo,$(basename $(libcacard-y))) vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o @@ -1609,23 +1609,31 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, 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); } @@ -22,16 +22,16 @@ static void __attribute__((constructor)) do_qemu_init_ ## function(void) { \ 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 8b69a9eea5..c5e9cad35e 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -255,6 +255,7 @@ typedef enum LostTickPolicy { LOST_TICK_DELAY, LOST_TICK_MERGE, LOST_TICK_SLEW, + LOST_TICK_MAX } LostTickPolicy; void tcg_exec_init(unsigned long tb_size); @@ -334,6 +335,8 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count); 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 95bf5e5202..12f5c27535 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -118,6 +118,32 @@ static QemuOptsList qemu_drive_opts = { }, }; +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", @@ -584,6 +610,7 @@ static QemuOptsList *vm_config_groups[32] = { &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 11f4166995..83b2ad5237 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -730,6 +730,57 @@ export LIBISCSI_CHAP_PASSWORD=<password> 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 @@ tgtadm --lld iscsi --mode logicalunit --op new --tid 1 --lun 2 \ -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 01cc0d35ad..c4bcf41e15 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -515,40 +515,6 @@ static int img_commit(int argc, char **argv) } /* - * 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_not_zero(const uint8_t *sector, int len) */ 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 @@ static int img_convert(int argc, char **argv) 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) { @@ -218,6 +218,51 @@ static int do_pwrite(char *buf, int64_t offset, int count, int *total) 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 @@ static void write_help(void) " -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 @@ static const cmdinfo_t write_cmd = { .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 const cmdinfo_t write_cmd = { 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 @@ static int write_f(int argc, char **argv) pflag = 1; break; case 'P': + Pflag = 1; pattern = parse_pattern(optarg); if (pattern < 0) { return 0; @@ -691,6 +738,9 @@ static int write_f(int argc, char **argv) case 'q': qflag = 1; break; + case 'z': + zflag = 1; + break; default: return command_usage(&write_cmd); } @@ -700,8 +750,13 @@ static int write_f(int argc, char **argv) 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 @@ static int write_f(int argc, char **argv) } } - 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 @@ static int write_f(int argc, char **argv) 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-options.hx b/qemu-options.hx index 4ad1fc72fd..b12999649f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -557,7 +557,7 @@ DEFHEADING() DEFHEADING(File system options:) DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev, - "-fsdev fsdriver,id=id[,path=path,][security_model={mapped|passthrough|none}]\n" + "-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n" " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n", QEMU_ARCH_ALL) @@ -577,12 +577,13 @@ Specifies the export path for the file system device. Files under this path will be available to the 9p client on the guest. @item security_model=@var{security_model} Specifies the security model to be used for this export path. -Supported security models are "passthrough", "mapped" and "none". +Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none". In "passthrough" security model, files are stored using the same credentials as they are created on the guest. This requires qemu -to run as root. In "mapped" security model, some of the file +to run as root. In "mapped-xattr" security model, some of the file attributes like uid, gid, mode bits and link target are stored as -file attributes. Directories exported by this security model cannot +file attributes. For "mapped-file" these attributes are stored in the +hidden .virtfs_metadata directory. Directories exported by this security model cannot interact with other unix tools. "none" security model is same as passthrough except the sever won't report failures if it fails to set file attributes like ownership. Security model is mandatory @@ -622,7 +623,7 @@ DEFHEADING() DEFHEADING(Virtual File system pass-through options:) DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs, - "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n" + "-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n" " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n", QEMU_ARCH_ALL) @@ -643,12 +644,13 @@ Specifies the export path for the file system device. Files under this path will be available to the 9p client on the guest. @item security_model=@var{security_model} Specifies the security model to be used for this export path. -Supported security models are "passthrough", "mapped" and "none". +Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none". In "passthrough" security model, files are stored using the same credentials as they are created on the guest. This requires qemu -to run as root. In "mapped" security model, some of the file +to run as root. In "mapped-xattr" security model, some of the file attributes like uid, gid, mode bits and link target are stored as -file attributes. Directories exported by this security model cannot +file attributes. For "mapped-file" these attributes are stored in the +hidden .virtfs_metadata directory. Directories exported by this security model cannot interact with other unix tools. "none" security model is same as passthrough except the sever won't report failures if it fails to set file attributes like ownership. Security model is mandatory only @@ -1096,6 +1098,19 @@ This can be really helpful to save bandwidth when playing videos. Disabling 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 @@ -1830,24 +1845,32 @@ Syntax for specifying iSCSI LUNs is 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/qemu-thread-win32.c b/qemu-thread-win32.c index fe9b931863..3524c8b785 100644 --- a/qemu-thread-win32.c +++ b/qemu-thread-win32.c @@ -215,8 +215,6 @@ static unsigned __stdcall win32_start_routine(void *arg) if (data->mode == QEMU_THREAD_DETACHED) { g_free(data); data = NULL; - } else { - InitializeCriticalSection(&data->cs); } TlsSetValue(qemu_thread_tls_index, data); qemu_thread_exit(start_routine(thread_arg)); @@ -227,6 +225,7 @@ void qemu_thread_exit(void *arg) { QemuThreadData *data = TlsGetValue(qemu_thread_tls_index); if (data) { + assert(data->mode != QEMU_THREAD_DETACHED); data->ret = arg; EnterCriticalSection(&data->cs); data->exited = true; @@ -258,6 +257,7 @@ void *qemu_thread_join(QemuThread *thread) CloseHandle(handle); } ret = data->ret; + assert(data->mode != QEMU_THREAD_DETACHED); DeleteCriticalSection(&data->cs); g_free(data); return ret; @@ -288,6 +288,10 @@ void qemu_thread_create(QemuThread *thread, data->mode = mode; data->exited = false; + if (data->mode != QEMU_THREAD_DETACHED) { + InitializeCriticalSection(&data->cs); + } + hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine, data, 0, &thread->tid); if (!hThread) { @@ -314,6 +318,7 @@ HANDLE qemu_thread_get_handle(QemuThread *thread) return NULL; } + assert(data->mode != QEMU_THREAD_DETACHED); EnterCriticalSection(&data->cs); if (!data->exited) { handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE, @@ -48,6 +48,10 @@ static const QErrorStringTable qerror_table[] = { .desc = "Could not add client", }, { + .error_fmt = QERR_AMBIGUOUS_PATH, + .desc = "Path '%(path)' does not uniquely identify a %(object)" + }, + { .error_fmt = QERR_BAD_BUS_FOR_DEVICE, .desc = "Device '%(device)' can't go on a %(bad_bus_type) bus", }, @@ -568,6 +572,14 @@ void qerror_report_err(Error *err) } } +void assert_no_error(Error *err) +{ + if (err) { + qerror_report_err(err); + abort(); + } +} + /** * qobject_to_qerror(): Convert a QObject into a QError */ @@ -41,6 +41,7 @@ void qerror_print(QError *qerror); 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__) @@ -54,6 +55,9 @@ QError *qobject_to_qerror(const QObject *obj); #define QERR_ADD_CLIENT_FAILED \ "{ 'class': 'AddClientFailed', 'data': {} }" +#define QERR_AMBIGUOUS_PATH \ + "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }" + #define QERR_BAD_BUS_FOR_DEVICE \ "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" @@ -21,9 +21,8 @@ #include "kvm.h" #include "arch_init.h" #include "hw/qdev.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi/qmp-output-visitor.h" #include "blockdev.h" +#include "qemu/qom-qobject.h" NameInfo *qmp_query_name(Error **errp) { @@ -198,7 +197,6 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret) const char *property = qdict_get_str(qdict, "property"); QObject *value = qdict_get(qdict, "value"); Error *local_err = NULL; - QmpInputVisitor *mi; Object *obj; obj = object_resolve_path(path, NULL); @@ -207,10 +205,7 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret) goto out; } - mi = qmp_input_visitor_new(value); - object_property_set(obj, qmp_input_get_visitor(mi), property, &local_err); - - qmp_input_visitor_cleanup(mi); + object_property_set_qobject(obj, value, property, &local_err); out: if (local_err) { @@ -227,7 +222,6 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret) const char *path = qdict_get_str(qdict, "path"); const char *property = qdict_get_str(qdict, "property"); Error *local_err = NULL; - QmpOutputVisitor *mo; Object *obj; obj = object_resolve_path(path, NULL); @@ -236,13 +230,7 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret) goto out; } - mo = qmp_output_visitor_new(); - object_property_get(obj, qmp_output_get_visitor(mo), property, &local_err); - if (!local_err) { - *ret = qmp_output_get_qobject(mo); - } - - qmp_output_visitor_cleanup(mo); + *ret = object_property_get_qobject(obj, property, &local_err); out: if (local_err) { diff --git a/qom/Makefile b/qom/Makefile index f33f0be8c9..885a2631bb 100644 --- a/qom/Makefile +++ b/qom/Makefile @@ -1 +1 @@ -qom-y = object.o container.o +qom-y = object.o container.o qom-qobject.o diff --git a/qom/container.c b/qom/container.c index 946cbff90f..f107208867 100644 --- a/qom/container.c +++ b/qom/container.c @@ -19,9 +19,9 @@ static TypeInfo container_info = { .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 4261944849..0cbd9bb004 100644 --- a/qom/object.c +++ b/qom/object.c @@ -13,8 +13,14 @@ #include "qemu/object.h" #include "qemu-common.h" #include "qapi/qapi-visit-core.h" -#include "hw/qdev.h" -// FIXME remove above + +/* TODO: replace QObject with a simpler visitor to avoid a dependency + * of the QOM core on QObject? */ +#include "qemu/qom-qobject.h" +#include "qobject.h" +#include "qbool.h" +#include "qint.h" +#include "qstring.h" #define MAX_INTERFACES 32 @@ -63,6 +69,8 @@ typedef struct Interface #define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE) +static Type type_interface; + static GHashTable *type_table_get(void) { static GHashTable *type_table; @@ -368,11 +376,9 @@ void object_delete(Object *obj) g_free(obj); } -static bool object_is_type(Object *obj, const char *typename) +static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type) { - TypeImpl *target_type = type_get_by_name(typename); - TypeImpl *type = obj->class->type; - GSList *i; + assert(target_type); /* Check if typename is a direct ancestor of type */ while (type) { @@ -383,24 +389,45 @@ static bool object_is_type(Object *obj, const char *typename) type = type_get_parent(type); } - /* Check if obj has an interface of typename */ - for (i = obj->interfaces; i; i = i->next) { - Interface *iface = i->data; - - if (object_is_type(OBJECT(iface), typename)) { - return true; - } - } - return false; } +static bool object_is_type(Object *obj, TypeImpl *target_type) +{ + return !target_type || type_is_ancestor(obj->class->type, target_type); +} + Object *object_dynamic_cast(Object *obj, const char *typename) { + TypeImpl *target_type = type_get_by_name(typename); GSList *i; - /* Check if typename is a direct ancestor */ - if (object_is_type(obj, typename)) { + /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT, + * we want to go back from interfaces to the parent. + */ + if (target_type && object_is_type(obj, target_type)) { + return obj; + } + + /* Check if obj is an interface and its containing object is a direct + * ancestor of typename. In principle we could do this test at the very + * beginning of object_dynamic_cast, avoiding a second call to + * object_is_type. However, casting between interfaces is relatively + * rare, and object_is_type(obj, type_interface) would fail almost always. + * + * Perhaps we could add a magic value to the object header for increased + * (run-time) type safety and to speed up tests like this one. If we ever + * do that we can revisit the order here. + */ + if (object_is_type(obj, type_interface)) { + assert(!obj->interfaces); + obj = INTERFACE(obj)->obj; + if (object_is_type(obj, target_type)) { + return obj; + } + } + + if (!target_type) { return obj; } @@ -408,26 +435,16 @@ Object *object_dynamic_cast(Object *obj, const char *typename) for (i = obj->interfaces; i; i = i->next) { Interface *iface = i->data; - if (object_is_type(OBJECT(iface), typename)) { + if (object_is_type(OBJECT(iface), target_type)) { return OBJECT(iface); } } - /* Check if obj is an interface and its containing object is a direct - * ancestor of typename */ - if (object_is_type(obj, TYPE_INTERFACE)) { - Interface *iface = INTERFACE(obj); - - if (object_is_type(iface->obj, typename)) { - return iface->obj; - } - } - return NULL; } -static void register_interface(void) +static void register_types(void) { static TypeInfo interface_info = { .name = TYPE_INTERFACE, @@ -435,10 +452,10 @@ static void register_interface(void) .abstract = true, }; - type_register_static(&interface_info); + 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) { @@ -648,6 +665,123 @@ void object_property_set(Object *obj, Visitor *v, const char *name, } } +void object_property_set_str(Object *obj, const char *value, + const char *name, Error **errp) +{ + QString *qstr = qstring_from_str(value); + object_property_set_qobject(obj, QOBJECT(qstr), name, errp); + + QDECREF(qstr); +} + +char *object_property_get_str(Object *obj, const char *name, + Error **errp) +{ + QObject *ret = object_property_get_qobject(obj, name, errp); + QString *qstring; + char *retval; + + if (!ret) { + return NULL; + } + qstring = qobject_to_qstring(ret); + if (!qstring) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); + retval = NULL; + } else { + retval = g_strdup(qstring_get_str(qstring)); + } + + QDECREF(qstring); + return retval; +} + +void object_property_set_link(Object *obj, Object *value, + const char *name, Error **errp) +{ + object_property_set_str(obj, object_get_canonical_path(value), + name, errp); +} + +Object *object_property_get_link(Object *obj, const char *name, + Error **errp) +{ + char *str = object_property_get_str(obj, name, errp); + Object *target = NULL; + + if (str && *str) { + target = object_resolve_path(str, NULL); + if (!target) { + error_set(errp, QERR_DEVICE_NOT_FOUND, str); + } + } + + g_free(str); + return target; +} + +void object_property_set_bool(Object *obj, bool value, + const char *name, Error **errp) +{ + QBool *qbool = qbool_from_int(value); + object_property_set_qobject(obj, QOBJECT(qbool), name, errp); + + QDECREF(qbool); +} + +bool object_property_get_bool(Object *obj, const char *name, + Error **errp) +{ + QObject *ret = object_property_get_qobject(obj, name, errp); + QBool *qbool; + bool retval; + + if (!ret) { + return false; + } + qbool = qobject_to_qbool(ret); + if (!qbool) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "boolean"); + retval = false; + } else { + retval = qbool_get_int(qbool); + } + + QDECREF(qbool); + return retval; +} + +void object_property_set_int(Object *obj, int64_t value, + const char *name, Error **errp) +{ + QInt *qint = qint_from_int(value); + object_property_set_qobject(obj, QOBJECT(qint), name, errp); + + QDECREF(qint); +} + +int64_t object_property_get_int(Object *obj, const char *name, + Error **errp) +{ + QObject *ret = object_property_get_qobject(obj, name, errp); + QInt *qint; + int64_t retval; + + if (!ret) { + return -1; + } + qint = qobject_to_qint(ret); + if (!qint) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int"); + retval = -1; + } else { + retval = qint_get_int(qint); + } + + QDECREF(qint); + return retval; +} + const char *object_property_get_type(Object *obj, const char *name, Error **errp) { ObjectProperty *prop = object_property_find(obj, name); @@ -695,6 +829,12 @@ void object_property_add_child(Object *obj, const char *name, { gchar *type; + /* Registering an interface object in the composition tree will mightily + * confuse object_get_canonical_path (which, on the other hand, knows how + * to get the canonical path of an interface object). + */ + assert(!object_is_type(obj, type_interface)); + type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child))); object_property_add(obj, name, type, object_get_child_property, @@ -730,6 +870,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, bool ambiguous = false; const char *type; char *path; + gchar *target_type; type = object_property_get_type(obj, name, NULL); @@ -737,31 +878,30 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, if (*child) { object_unref(*child); + *child = NULL; } if (strcmp(path, "") != 0) { Object *target; - target = object_resolve_path(path, &ambiguous); - if (target) { - gchar *target_type; - - target_type = g_strdup(&type[5]); - target_type[strlen(target_type) - 2] = 0; + /* Go from link<FOO> to FOO. */ + target_type = g_strndup(&type[5], strlen(type) - 6); + target = object_resolve_path_type(path, target_type, &ambiguous); - if (object_dynamic_cast(target, target_type)) { - object_ref(target); - *child = target; + if (ambiguous) { + error_set(errp, QERR_AMBIGUOUS_PATH, path); + } else if (target) { + object_ref(target); + *child = target; + } else { + target = object_resolve_path(path, &ambiguous); + if (target || ambiguous) { + error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type); } else { - error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type); + error_set(errp, QERR_DEVICE_NOT_FOUND, path); } - - g_free(target_type); - } else { - error_set(errp, QERR_DEVICE_NOT_FOUND, path); } - } else { - *child = NULL; + g_free(target_type); } g_free(path); @@ -788,6 +928,10 @@ gchar *object_get_canonical_path(Object *obj) Object *root = object_get_root(); char *newpath = NULL, *path = NULL; + if (object_is_type(obj, type_interface)) { + obj = INTERFACE(obj)->obj; + } + while (obj != root) { ObjectProperty *prop = NULL; @@ -823,17 +967,18 @@ gchar *object_get_canonical_path(Object *obj) static Object *object_resolve_abs_path(Object *parent, gchar **parts, + const char *typename, int index) { ObjectProperty *prop; Object *child; if (parts[index] == NULL) { - return parent; + return object_dynamic_cast(parent, typename); } if (strcmp(parts[index], "") == 0) { - return object_resolve_abs_path(parent, parts, index + 1); + return object_resolve_abs_path(parent, parts, typename, index + 1); } prop = object_property_find(parent, parts[index]); @@ -855,17 +1000,18 @@ static Object *object_resolve_abs_path(Object *parent, return NULL; } - return object_resolve_abs_path(child, parts, index + 1); + return object_resolve_abs_path(child, parts, typename, index + 1); } static Object *object_resolve_partial_path(Object *parent, gchar **parts, + const char *typename, bool *ambiguous) { Object *obj; ObjectProperty *prop; - obj = object_resolve_abs_path(parent, parts, 0); + obj = object_resolve_abs_path(parent, parts, typename, 0); QTAILQ_FOREACH(prop, &parent->properties, node) { Object *found; @@ -874,7 +1020,8 @@ static Object *object_resolve_partial_path(Object *parent, continue; } - found = object_resolve_partial_path(prop->opaque, parts, ambiguous); + found = object_resolve_partial_path(prop->opaque, parts, + typename, ambiguous); if (found) { if (obj) { if (ambiguous) { @@ -893,7 +1040,8 @@ static Object *object_resolve_partial_path(Object *parent, return obj; } -Object *object_resolve_path(const char *path, bool *ambiguous) +Object *object_resolve_path_type(const char *path, const char *typename, + bool *ambiguous) { bool partial_path = true; Object *obj; @@ -913,9 +1061,10 @@ Object *object_resolve_path(const char *path, bool *ambiguous) if (ambiguous) { *ambiguous = false; } - obj = object_resolve_partial_path(object_get_root(), parts, ambiguous); + obj = object_resolve_partial_path(object_get_root(), parts, + typename, ambiguous); } else { - obj = object_resolve_abs_path(object_get_root(), parts, 1); + obj = object_resolve_abs_path(object_get_root(), parts, typename, 1); } g_strfreev(parts); @@ -923,14 +1072,19 @@ Object *object_resolve_path(const char *path, bool *ambiguous) return obj; } +Object *object_resolve_path(const char *path, bool *ambiguous) +{ + return object_resolve_path_type(path, TYPE_OBJECT, ambiguous); +} + typedef struct StringProperty { char *(*get)(Object *, Error **); void (*set)(Object *, const char *, Error **); } StringProperty; -static void object_property_get_str(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void property_get_str(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { StringProperty *prop = opaque; char *value; @@ -942,8 +1096,8 @@ static void object_property_get_str(Object *obj, Visitor *v, void *opaque, } } -static void object_property_set_str(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void property_set_str(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { StringProperty *prop = opaque; char *value; @@ -959,8 +1113,8 @@ static void object_property_set_str(Object *obj, Visitor *v, void *opaque, g_free(value); } -static void object_property_release_str(Object *obj, const char *name, - void *opaque) +static void property_release_str(Object *obj, const char *name, + void *opaque) { StringProperty *prop = opaque; g_free(prop); @@ -977,8 +1131,8 @@ void object_property_add_str(Object *obj, const char *name, prop->set = set; object_property_add(obj, name, "string", - get ? object_property_get_str : NULL, - set ? object_property_set_str : NULL, - object_property_release_str, + get ? property_get_str : NULL, + set ? property_set_str : NULL, + property_release_str, prop, errp); } diff --git a/qom/qom-qobject.c b/qom/qom-qobject.c new file mode 100644 index 0000000000..0689914e15 --- /dev/null +++ b/qom/qom-qobject.c @@ -0,0 +1,44 @@ +/* + * QEMU Object Model - QObject wrappers + * + * Copyright (C) 2012 Red Hat, Inc. + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu-common.h" +#include "qemu/object.h" +#include "qemu/qom-qobject.h" +#include "qapi/qapi-visit-core.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/qmp-output-visitor.h" + +void object_property_set_qobject(Object *obj, QObject *value, + const char *name, Error **errp) +{ + QmpInputVisitor *mi; + mi = qmp_input_visitor_new(value); + object_property_set(obj, qmp_input_get_visitor(mi), name, errp); + + qmp_input_visitor_cleanup(mi); +} + +QObject *object_property_get_qobject(Object *obj, const char *name, + Error **errp) +{ + QObject *ret = NULL; + Error *local_err = NULL; + QmpOutputVisitor *mo; + + mo = qmp_output_visitor_new(); + object_property_get(obj, qmp_output_get_visitor(mo), name, &local_err); + if (!local_err) { + ret = qmp_output_get_qobject(mo); + } + error_propagate(errp, local_err); + qmp_output_visitor_cleanup(mo); + return ret; +} diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 4b43994dbc..5dbf21da9d 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -262,6 +262,11 @@ icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, #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 6c80e69685..3432fbfeb7 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -113,7 +113,6 @@ fork_exec(struct socket *so, const char *ex, int do_pty) 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 @@ fork_exec(struct socket *so, const char *ex, int do_pty) 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 @@ fork_exec(struct socket *so, const char *ex, int do_pty) 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-ppc/helper.c b/target-ppc/helper.c index e56fac8684..928fbcf3cb 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1293,11 +1293,8 @@ void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot) 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 5d05749643..9b26ce2304 100644 --- a/trace-events +++ b/trace-events @@ -67,6 +67,7 @@ bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" 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_need_check_timer_cb(void *s) "s %p" 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 5639c6f531..b4629f895b 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -753,8 +753,9 @@ static void spice_register_config(void) } 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) @@ -46,6 +46,30 @@ static VncDisplay *vnc_display; /* needed for info vnc */ 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 @@ static void vnc_disconnect_start(VncState *vs) { 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 @@ static void vnc_disconnect_finish(VncState *vs) 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 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) 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 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) 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_msg(VncState *vs, uint8_t *data, size_t len) 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 @@ static int vnc_refresh_server_surface(VncDisplay *vd) 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 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth) 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 @@ int vnc_display_open(DisplayState *ds, const char *display) 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 @@ int vnc_display_open(DisplayState *ds, const char *display) 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; + } } } @@ -122,9 +122,24 @@ struct VncSurface 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 @@ struct VncState int last_y; int client_width; int client_height; + VncShareMode share_mode; uint32_t vnc_encoding; @@ -214,7 +214,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo usb_host_dev_info = { .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 e7fc9ecd5c..24700fc1f7 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -137,7 +137,7 @@ static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p) [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 @@ static void async_complete(void *opaque) 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 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) 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 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) } } 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 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) 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 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) 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 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) 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 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, 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 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo usb_host_dev_info = { .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 303292acd6..a59b347f01 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 @@ struct USBRedirDevice { /* 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 USBRedirDevice { 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 @@ static int usbredir_handle_data(USBDevice *udev, USBPacket *p) 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 int usbredir_handle_control(USBDevice *udev, USBPacket *p, 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 @@ static void usbredir_open_close_bh(void *opaque) 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 @@ static int usbredir_initfn(USBDevice *udev) 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 @@ static void usbredir_handle_destroy(USBDevice *udev) 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 @@ static void usbredir_device_connect(void *priv, 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 @@ static void usbredir_device_connect(void *priv, 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 @@ static void usbredir_device_disconnect(void *priv) 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 void usbredir_interrupt_packet(void *priv, uint32_t id, 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 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) 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 @@ static TypeInfo usbredir_dev_info = { .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) @@ -2529,6 +2529,14 @@ int main(int argc, char **argv, char **envp) 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; @@ -3361,7 +3369,7 @@ int main(int argc, char **argv, char **envp) 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) { |