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);
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,
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);
}
}
*/
void *bounce_buffer;
+ BlockDriver *drv = bs->drv;
struct iovec iov;
QEMUIOVector bounce_qiov;
int64_t cluster_sector_num;
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.
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;
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);
{
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);
}
/**
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);
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,
}
}
+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>
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) {
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,
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;
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;
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;
return 0;
failed:
+ if (initiator_name != NULL) {
+ g_free(initiator_name);
+ }
if (iscsi_url != NULL) {
iscsi_destroy_url(iscsi_url);
}
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);
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;
}
}
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)
{
return ret;
fail:
+ cleanup_unknown_header_ext(bs);
qcow2_free_snapshots(bs);
qcow2_refcount_close(bs);
g_free(s->l1_table);
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);
}
}
+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)
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;
QCowSnapshot *snapshots;
int flags;
+ QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
} BDRVQcowState;
/* XXX: use std qcow open function ? */
/* 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);
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);
/**
* 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;
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 */
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
*
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);
}
}
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;
}
}
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
*
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)) {
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);
}
}
*/
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);
{
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);
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;
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,
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,
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;
.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,
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 */
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;
}
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;
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);
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);
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);
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);
}
}
-
// Prepare the Dynamic Disk Header
memset(buf, 0, 1024);
}
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;
.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 }
};
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,
# 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)
# 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)
}
}
+/*
+ * 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)
.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)
.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)
.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)
.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)
{
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
};
-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)
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++) {
}
}
-device_init(eepro100_register_devices)
+type_init(eepro100_register_types)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
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);
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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;
.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)
.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)
.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)
.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)
.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)
.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)
.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);
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) {
break;
case PORT_IRQ_STAT:
pr->irq_stat &= ~val;
+ ahci_check_irq(s);
break;
case PORT_IRQ_MASK:
pr->irq_mask = val & 0xfdc000ff;
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;
}
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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,
.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)
.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)
.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:
.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);
return get_system_memory();
}
-device_init(isabus_register_devices)
+type_init(isabus_register_types)
.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)
.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)
}
}
-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)
.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)
.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)
.class_init = lan9118_class_init,
};
-static void lan9118_register_devices(void)
+static void lan9118_register_types(void)
{
type_register_static(&lan9118_info);
}
sysbus_connect_irq(s, 0, irq);
}
-device_init(lan9118_register_devices)
+type_init(lan9118_register_types)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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,
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.is_default = 1,
};
-static void mips_malta_device_init(void)
+static void mips_malta_register_types(void)
{
type_register_static(&mips_malta_device);
}
qemu_register_machine(&mips_malta_machine);
}
-device_init(mips_malta_device_init);
+type_init(mips_malta_register_types)
machine_init(mips_malta_machine_init);
.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)
.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)
.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)
.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);
type_register_static(&musicpal_key_info);
}
-device_init(musicpal_register_devices)
+type_init(musicpal_register_types)
.class_init = nand_class_init,
};
-static void nand_create_device(void)
+static void nand_register_types(void)
{
type_register_static(&nand_info);
}
return dev;
}
-device_init(nand_create_device)
+type_init(nand_register_types)
#else
.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)
.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)
.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)
.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)
.class_init = onenand_class_init,
};
-static void onenand_register_device(void)
+static void onenand_register_types(void)
{
type_register_static(&onenand_info);
}
return FROM_SYSBUS(OneNANDState, sysbus_from_qdev(onenand_device))->otp;
}
-device_init(onenand_register_device)
+type_init(onenand_register_types)
.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)
.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)
.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)
{
.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)
.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)
.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)
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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
/* 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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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);
type_register_static(&pxa2xx_rtc_sysbus_info);
}
-device_init(pxa2xx_register_devices)
+type_init(pxa2xx_register_types)
.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)
.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)
.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)
.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)
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 {
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;
}
}
if (!*str) {
g_free(str);
- error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+ *ptr = NULL;
return;
}
ret = parse(dev, str, ptr);
{
Error *errp = NULL;
object_property_set_bool(OBJECT(dev), value, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
{
Error *errp = NULL;
object_property_set_int(OBJECT(dev), value, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
{
Error *errp = NULL;
object_property_set_int(OBJECT(dev), value, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
{
Error *errp = NULL;
object_property_set_int(OBJECT(dev), value, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
{
Error *errp = NULL;
object_property_set_int(OBJECT(dev), value, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
{
Error *errp = NULL;
object_property_set_int(OBJECT(dev), value, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
{
Error *errp = NULL;
object_property_set_str(OBJECT(dev), value, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
{
Error *errp = NULL;
- object_property_set_str(OBJECT(dev), bdrv_get_device_name(value),
+ const char *bdrv_name = value ? bdrv_get_device_name(value) : "";
+ object_property_set_str(OBJECT(dev), bdrv_name,
name, &errp);
if (errp) {
qerror_report_err(errp);
void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value)
{
Error *errp = NULL;
- assert(value->label);
- object_property_set_str(OBJECT(dev), value->label, name, &errp);
- assert(!errp);
+ assert(!value || value->label);
+ object_property_set_str(OBJECT(dev),
+ value ? value->label : "", name, &errp);
+ assert_no_error(errp);
}
void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value)
{
Error *errp = NULL;
- assert(value->name);
- object_property_set_str(OBJECT(dev), value->name, name, &errp);
- assert(!errp);
+ assert(!value || value->name);
+ object_property_set_str(OBJECT(dev),
+ value ? value->name : "", name, &errp);
+ assert_no_error(errp);
}
void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value)
{
Error *errp = NULL;
object_property_set_int(OBJECT(dev), value ? value->id : -1, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
value[0], value[1], value[2], value[3], value[4], value[5]);
object_property_set_str(OBJECT(dev), str, name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
prop = qdev_prop_find(dev, name);
object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
name, &errp);
- assert(!errp);
+ assert_no_error(errp);
}
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
} else if (props->qtype == QTYPE_QINT) {
object_property_set_int(obj, props->defval, props->name, &errp);
}
- assert(!errp);
+ assert_no_error(errp);
}
}
.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)
.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)
.class_init = realview_i2c_class_init,
};
-static void realview_register_devices(void)
+static void realview_register_types(void)
{
type_register_static(&realview_i2c_info);
}
}
machine_init(realview_machine_init);
-device_init(realview_register_devices)
+type_init(realview_register_types)
.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)
.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)
.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 */
.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)
.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)
.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)
.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)
.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);
#endif
type_register_static(&scsi_disk_info);
}
-device_init(scsi_disk_register_devices)
+
+type_init(scsi_disk_register_types)
.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__ */
.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)
.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)
.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)
.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)
.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)
.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)
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) {
.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)
.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)
.class_init = smc91c111_class_init,
};
-static void smc91c111_register_devices(void)
+static void smc91c111_register_types(void)
{
type_register_static(&smc91c111_info);
}
sysbus_connect_irq(s, 0, irq);
}
-device_init(smc91c111_register_devices)
+type_init(smc91c111_register_types)
return H_FUNCTION;
}
-static void hypercall_init(void)
+static void hypercall_register_types(void)
{
/* hcall-pft */
spapr_register_hypercall(H_ENTER, h_enter);
/* qemu/KVM-PPC specific hcalls */
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
}
-device_init(hypercall_init);
+
+type_init(hypercall_register_types)
.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);
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)
.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)
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);
rtas_query_cpu_stopped_state);
spapr_rtas_register("start-cpu", rtas_start_cpu);
}
-device_init(register_core_rtas);
+
+type_init(core_rtas_register_types)
.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)
.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)
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)
.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)
.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);
type_register_static(&sl_nand_info);
}
-device_init(spitz_register_devices)
+type_init(spitz_register_types)
.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)
.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)
.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)
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)
.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);
type_register_static(&stellaris_ssi_bus_info);
}
-device_init(stellaris_register_devices)
+type_init(stellaris_register_types)
.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)
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);
type_register_static(&strongarm_uart_info);
type_register_static(&strongarm_ssp_info);
}
-device_init(strongarm_register_devices)
+
+type_init(strongarm_register_types)
.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)
.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;
.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;
.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;
.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)
{
.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);
qemu_register_machine(&ss2_machine);
}
+type_init(sun4m_register_types)
machine_init(ss2_machine_init);
.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)
.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;
.class_init = prom_class_init,
};
-static void prom_register_devices(void)
-{
- type_register_static(&prom_info);
-}
-
-device_init(prom_register_devices);
-
typedef struct RamDevice
{
.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;
.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);
qemu_register_machine(&niagara_machine);
}
+type_init(sun4u_register_types)
machine_init(sun4u_machine_init);
.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)
.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)
.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)
.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)
.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)
.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)
.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);
type_register_static(&pci_unin_internal_info);
}
-device_init(unin_register_devices)
+type_init(unin_register_types)
switch (p->pid) {
case USB_TOKEN_OUT:
- switch (p->devep) {
+ switch (p->ep->nr) {
case 1:
ret = usb_audio_handle_dataout(s, p);
break;
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;
}
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;
.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)
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;
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);
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;
.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)
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)
.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)
*/
typedef struct USBCCIDState {
USBDevice dev;
+ USBEndpoint *intr;
CCIDBus bus;
CCIDCardState *card;
BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
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(
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;
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;
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;
.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)
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);
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;
}
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)
{
}
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);
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;
}
static int ehci_execute(EHCIQueue *q)
{
- USBPort *port;
USBDevice *dev;
+ USBEndpoint *ep;
int ret;
- int i;
int endp;
int devadr;
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");
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);
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);
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
typedef struct USBHIDState {
USBDevice dev;
+ USBEndpoint *intr;
HIDState hid;
} USBHIDState;
{
USBHIDState *us = container_of(hs, USBHIDState, hid);
- usb_wakeup(&us->dev);
+ usb_wakeup(us->intr);
}
static void usb_hid_handle_reset(USBDevice *dev)
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)) {
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;
}
{
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;
.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);
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)
typedef struct USBHubState {
USBDevice dev;
+ USBEndpoint *intr;
USBHubPort ports[NUM_PORTS];
} USBHubState;
} else {
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
}
- usb_wakeup(&s->dev);
+ usb_wakeup(s->intr);
}
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);
if (port->wPortStatus & PORT_STAT_SUSPEND) {
port->wPortChange |= PORT_STAT_C_SUSPEND;
- usb_wakeup(&s->dev);
+ usb_wakeup(s->intr);
}
}
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);
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;
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];
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;
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),
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;
.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)
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:
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;
.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)
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;
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;
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);
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)
switch(p->pid) {
case USB_TOKEN_IN:
- switch (p->devep) {
+ switch (p->ep->nr) {
case 1:
ret = usb_net_handle_statusin(s, p);
break;
break;
case USB_TOKEN_OUT:
- switch (p->devep) {
+ switch (p->ep->nr) {
case 2:
ret = usb_net_handle_dataout(s, p);
break;
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;
}
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;
.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)
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)
{
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) {
int ret;
int i;
USBDevice *dev;
+ USBEndpoint *ep;
struct ohci_iso_td iso_td;
uint32_t addr;
uint16_t starting_frame;
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;
}
int ret;
int i;
USBDevice *dev;
+ USBEndpoint *ep;
struct ohci_td td;
uint32_t addr;
int flag_r;
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
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;
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;
}
.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)
{
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;
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;
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;
.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)
#define FRAME_TIMER_FREQ 1000
-#define FRAME_MAX_LOOPS 100
+#define FRAME_MAX_LOOPS 256
#define NB_PORTS 2
#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;
/*
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);
port = &s->ports[i];
port->ctrl = 0x0080;
if (port->port.dev && port->port.dev->attached) {
- usb_reset(&port->port);
+ usb_port_reset(&port->port);
}
}
}
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;
/* 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;
}
}
-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);
int len = 0, max_len;
uint8_t pid, isoc;
uint32_t token;
+ USBDevice *dev;
+ USBEndpoint *ep;
/* Is active ? */
if (!(td->ctrl & TD_CTRL_ACTIVE))
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:
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;
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));
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 */
.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);
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)
{
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;
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;
.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)
typedef struct XHCITransfer {
XHCIState *xhci;
USBPacket packet;
- bool running;
+ bool running_async;
+ bool running_retry;
bool cancelled;
bool complete;
bool backgrounded;
unsigned int next_xfer;
unsigned int comp_xfer;
XHCITransfer transfers[TD_QUEUE];
+ XHCITransfer *retry;
bool bg_running;
bool bg_updating;
unsigned int next_bg;
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);
}
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);
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;
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;
}
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++;
}
}
#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;
}
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;
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);
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);
}
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;
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;
}
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:
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;
}
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;
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;
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) {
}
}
+ 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;
}
/* 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;
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);
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)
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;
.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)
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)
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);
+ }
}
/**********************/
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];
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:
}
}
-/*
- * 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
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
{
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;
}
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
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);
+ }
}
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)
void usb_packet_cleanup(USBPacket *p)
{
+ assert(!usb_packet_is_inflight(p));
qemu_iovec_destroy(&p->iov);
}
{
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);
}
}
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;
}
#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)
#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 */
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.
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;
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);
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);
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);
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);
.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);
.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)
.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)
.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)
.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)
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) {
.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(),
.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)
.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);
type_register_static(&virtio_balloon_info);
}
-device_init(virtio_pci_register_devices)
+type_init(virtio_pci_register_types)
.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)
.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)
.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)
.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)
.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);
.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)
{
.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,
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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)
.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:
.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)
/*
.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. */
* .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>
*
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);
}
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);
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);
},
};
+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",
&qemu_option_rom_opts,
&qemu_machine_opts,
&qemu_boot_opts,
+ &qemu_iscsi_opts,
NULL,
};
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
-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
return 0;
}
-/*
- * 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.
*/
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;
}
/*
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) {
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);
" -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");
}
.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,
};
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;
pflag = 1;
break;
case 'P':
+ Pflag = 1;
pattern = parse_pattern(optarg);
if (pattern < 0) {
return 0;
case 'q':
qflag = 1;
break;
+ case 'z':
+ zflag = 1;
+ break;
default:
return command_usage(&write_cmd);
}
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;
}
}
}
- 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);
}
print_report("wrote", &t2, offset, count, total, cnt, Cflag);
out:
- qemu_io_free(buf);
+ if (!zflag) {
+ qemu_io_free(buf);
+ }
return 0;
}
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
}
}
+void assert_no_error(Error *err)
+{
+ if (err) {
+ qerror_report_err(err);
+ abort();
+ }
+}
+
/**
* qobject_to_qerror(): Convert a QObject into a 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__)
.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)
}
-static void register_interface(void)
+static void register_types(void)
{
static TypeInfo interface_info = {
.name = TYPE_INTERFACE,
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)
{
#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) {
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;
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);
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 */
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;
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"
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"
}
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)
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);
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;
.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)
{
[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];
}
break;
case -EPIPE:
- set_halt(s, p->pid, p->devep);
+ set_halt(s, p->pid, p->ep->nr);
p->result = USB_RET_STALL;
break;
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) {
}
} 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) {
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) {
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);
}
}
}
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) {
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);
}
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;
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;
.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)
{
#include <sys/ioctl.h>
#include <signal.h>
#include <usbredirparser.h>
+#include <usbredirfilter.h>
#include "hw/usb.h"
/* 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;
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 {
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;
}
static void usbredir_open_close_bh(void *opaque)
{
USBRedirDevice *dev = opaque;
+ uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
usbredir_device_disconnect(dev);
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);
}
}
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);
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;
}
/*
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");
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);
}
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,
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(),
};
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;
.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)
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;
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) {