Merge remote-tracking branch 'origin/master' into xbox

This commit is contained in:
espes 2012-11-19 12:29:57 +11:00
commit 17d4dd207a
127 changed files with 5493 additions and 3992 deletions

View File

@ -122,7 +122,7 @@ subdir-pixman: pixman/Makefile
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,)
pixman/Makefile: $(SRC_PATH)/pixman/configure
(cd pixman; $(SRC_PATH)/pixman/configure --disable-shared --enable-static)
(cd pixman; CFLAGS="$(CFLAGS) -fPIC" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static)
$(SRC_PATH)/pixman/configure:
(cd $(SRC_PATH)/pixman; autoreconf -v --install)
@ -157,6 +157,12 @@ version.o: $(SRC_PATH)/version.rc config-host.h
$(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@")
version-obj-$(CONFIG_WIN32) += version.o
######################################################################
# Build library with stubs
libqemustub.a: $(stub-obj-y)
######################################################################
# Support building shared library libcacard
@ -183,13 +189,13 @@ tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
main-loop.o iohandler.o error.o
tools-obj-$(CONFIG_POSIX) += compatfd.o
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemustub.a
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemustub.a
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o libqemustub.a
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@")
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
@ -232,7 +238,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemustub.a
QEMULIBS=libuser libdis libdis-user
@ -278,6 +284,7 @@ distclean: clean
for d in $(TARGET_DIRS) $(QEMULIBS); do \
rm -rf $$d || exit 1 ; \
done
test -f pixman/config.log && make -C pixman distclean
KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
ar de en-us fi fr-be hr it lv nl pl ru th \

View File

@ -1,3 +1,7 @@
#######################################################################
# Stub library, linked in tools
stub-obj-y = stubs/
#######################################################################
# Target-independent parts used in system and user emulation
universal-obj-y =
@ -78,7 +82,6 @@ common-obj-y += input.o
common-obj-y += buffered_file.o migration.o migration-tcp.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += pflib.o
common-obj-y += bitmap.o bitops.o
common-obj-y += page_cache.o
@ -101,6 +104,8 @@ common-obj-y += vl.o
common-obj-$(CONFIG_SLIRP) += slirp/
common-obj-y += backends/
######################################################################
# libseccomp
ifeq ($(CONFIG_SECCOMP),y)
@ -238,6 +243,7 @@ vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
QEMU_CFLAGS+=$(GLIB_CFLAGS)
nested-vars += \
stub-obj-y \
qga-obj-y \
qom-obj-y \
qapi-obj-y \

View File

@ -162,12 +162,12 @@ endif #CONFIG_LINUX_USER
ifdef QEMU_PROGW
# The linker builds a windows executable. Make also a console executable.
$(QEMU_PROGW): $(all-obj-y)
$(QEMU_PROGW): $(all-obj-y) ../libqemustub.a
$(call LINK,$^)
$(QEMU_PROG): $(QEMU_PROGW)
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
else
$(QEMU_PROG): $(all-obj-y)
$(QEMU_PROG): $(all-obj-y) ../libqemustub.a
$(call LINK,$^)
endif

View File

@ -122,11 +122,9 @@ aio_ctx_prepare(GSource *source, gint *timeout)
{
AioContext *ctx = (AioContext *) source;
QEMUBH *bh;
bool scheduled = false;
for (bh = ctx->first_bh; bh; bh = bh->next) {
if (!bh->deleted && bh->scheduled) {
scheduled = true;
if (bh->idle) {
/* idle bottom halves will be polled at least
* every 10ms */
@ -135,12 +133,12 @@ aio_ctx_prepare(GSource *source, gint *timeout)
/* non-idle bottom halves will be executed
* immediately */
*timeout = 0;
break;
return true;
}
}
}
return scheduled;
return false;
}
static gboolean

1
backends/Makefile.objs Normal file
View File

@ -0,0 +1 @@
common-obj-y += rng.o rng-random.o rng-egd.o

224
backends/rng-egd.c Normal file
View File

@ -0,0 +1,224 @@
/*
* QEMU Random Number Generator Backend
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/rng.h"
#include "qemu-char.h"
#include "qerror.h"
#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */
#define TYPE_RNG_EGD "rng-egd"
#define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)
typedef struct RngEgd
{
RngBackend parent;
CharDriverState *chr;
char *chr_name;
GSList *requests;
} RngEgd;
typedef struct RngRequest
{
EntropyReceiveFunc *receive_entropy;
uint8_t *data;
void *opaque;
size_t offset;
size_t size;
} RngRequest;
static void rng_egd_request_entropy(RngBackend *b, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque)
{
RngEgd *s = RNG_EGD(b);
RngRequest *req;
req = g_malloc(sizeof(*req));
req->offset = 0;
req->size = size;
req->receive_entropy = receive_entropy;
req->opaque = opaque;
req->data = g_malloc(req->size);
while (size > 0) {
uint8_t header[2];
uint8_t len = MIN(size, 255);
/* synchronous entropy request */
header[0] = 0x02;
header[1] = len;
qemu_chr_fe_write(s->chr, header, sizeof(header));
size -= len;
}
s->requests = g_slist_append(s->requests, req);
}
static void rng_egd_free_request(RngRequest *req)
{
g_free(req->data);
g_free(req);
}
static int rng_egd_chr_can_read(void *opaque)
{
RngEgd *s = RNG_EGD(opaque);
GSList *i;
int size = 0;
for (i = s->requests; i; i = i->next) {
RngRequest *req = i->data;
size += req->size - req->offset;
}
return size;
}
static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
{
RngEgd *s = RNG_EGD(opaque);
while (size > 0 && s->requests) {
RngRequest *req = s->requests->data;
int len = MIN(size, req->size - req->offset);
memcpy(req->data + req->offset, buf, len);
req->offset += len;
size -= len;
if (req->offset == req->size) {
s->requests = g_slist_remove_link(s->requests, s->requests);
req->receive_entropy(req->opaque, req->data, req->size);
rng_egd_free_request(req);
}
}
}
static void rng_egd_free_requests(RngEgd *s)
{
GSList *i;
for (i = s->requests; i; i = i->next) {
rng_egd_free_request(i->data);
}
g_slist_free(s->requests);
s->requests = NULL;
}
static void rng_egd_cancel_requests(RngBackend *b)
{
RngEgd *s = RNG_EGD(b);
/* We simply delete the list of pending requests. If there is data in the
* queue waiting to be read, this is okay, because there will always be
* more data than we requested originally
*/
rng_egd_free_requests(s);
}
static void rng_egd_opened(RngBackend *b, Error **errp)
{
RngEgd *s = RNG_EGD(b);
if (s->chr_name == NULL) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
"chardev", "a valid character device");
return;
}
s->chr = qemu_chr_find(s->chr_name);
if (s->chr == NULL) {
error_set(errp, QERR_DEVICE_NOT_FOUND, s->chr_name);
return;
}
/* FIXME we should resubmit pending requests when the CDS reconnects. */
qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read,
NULL, s);
}
static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
{
RngBackend *b = RNG_BACKEND(obj);
RngEgd *s = RNG_EGD(b);
if (b->opened) {
error_set(errp, QERR_PERMISSION_DENIED);
} else {
g_free(s->chr_name);
s->chr_name = g_strdup(value);
}
}
static char *rng_egd_get_chardev(Object *obj, Error **errp)
{
RngEgd *s = RNG_EGD(obj);
if (s->chr && s->chr->label) {
return g_strdup(s->chr->label);
}
return NULL;
}
static void rng_egd_init(Object *obj)
{
object_property_add_str(obj, "chardev",
rng_egd_get_chardev, rng_egd_set_chardev,
NULL);
}
static void rng_egd_finalize(Object *obj)
{
RngEgd *s = RNG_EGD(obj);
if (s->chr) {
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
}
g_free(s->chr_name);
rng_egd_free_requests(s);
}
static void rng_egd_class_init(ObjectClass *klass, void *data)
{
RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
rbc->request_entropy = rng_egd_request_entropy;
rbc->cancel_requests = rng_egd_cancel_requests;
rbc->opened = rng_egd_opened;
}
static TypeInfo rng_egd_info = {
.name = TYPE_RNG_EGD,
.parent = TYPE_RNG_BACKEND,
.instance_size = sizeof(RngEgd),
.class_init = rng_egd_class_init,
.instance_init = rng_egd_init,
.instance_finalize = rng_egd_finalize,
};
static void register_types(void)
{
type_register_static(&rng_egd_info);
}
type_init(register_types);

161
backends/rng-random.c Normal file
View File

@ -0,0 +1,161 @@
/*
* QEMU Random Number Generator Backend
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/rng-random.h"
#include "qemu/rng.h"
#include "qerror.h"
#include "main-loop.h"
struct RndRandom
{
RngBackend parent;
int fd;
char *filename;
EntropyReceiveFunc *receive_func;
void *opaque;
size_t size;
};
/**
* A simple and incomplete backend to request entropy from /dev/random.
*
* This backend exposes an additional "filename" property that can be used to
* set the filename to use to open the backend.
*/
static void entropy_available(void *opaque)
{
RndRandom *s = RNG_RANDOM(opaque);
uint8_t buffer[s->size];
ssize_t len;
len = read(s->fd, buffer, s->size);
g_assert(len != -1);
s->receive_func(s->opaque, buffer, len);
s->receive_func = NULL;
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
}
static void rng_random_request_entropy(RngBackend *b, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque)
{
RndRandom *s = RNG_RANDOM(b);
if (s->receive_func) {
s->receive_func(s->opaque, NULL, 0);
}
s->receive_func = receive_entropy;
s->opaque = opaque;
s->size = size;
qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
}
static void rng_random_opened(RngBackend *b, Error **errp)
{
RndRandom *s = RNG_RANDOM(b);
if (s->filename == NULL) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE,
"filename", "a valid filename");
} else {
s->fd = open(s->filename, O_RDONLY | O_NONBLOCK);
if (s->fd == -1) {
error_set(errp, QERR_OPEN_FILE_FAILED, s->filename);
}
}
}
static char *rng_random_get_filename(Object *obj, Error **errp)
{
RndRandom *s = RNG_RANDOM(obj);
if (s->filename) {
return g_strdup(s->filename);
}
return NULL;
}
static void rng_random_set_filename(Object *obj, const char *filename,
Error **errp)
{
RngBackend *b = RNG_BACKEND(obj);
RndRandom *s = RNG_RANDOM(obj);
if (b->opened) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
if (s->filename) {
g_free(s->filename);
}
s->filename = g_strdup(filename);
}
static void rng_random_init(Object *obj)
{
RndRandom *s = RNG_RANDOM(obj);
object_property_add_str(obj, "filename",
rng_random_get_filename,
rng_random_set_filename,
NULL);
s->filename = g_strdup("/dev/random");
}
static void rng_random_finalize(Object *obj)
{
RndRandom *s = RNG_RANDOM(obj);
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
if (s->fd != -1) {
close(s->fd);
}
g_free(s->filename);
}
static void rng_random_class_init(ObjectClass *klass, void *data)
{
RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
rbc->request_entropy = rng_random_request_entropy;
rbc->opened = rng_random_opened;
}
static TypeInfo rng_random_info = {
.name = TYPE_RNG_RANDOM,
.parent = TYPE_RNG_BACKEND,
.instance_size = sizeof(RndRandom),
.class_init = rng_random_class_init,
.instance_init = rng_random_init,
.instance_finalize = rng_random_finalize,
};
static void register_types(void)
{
type_register_static(&rng_random_info);
}
type_init(register_types);

93
backends/rng.c Normal file
View File

@ -0,0 +1,93 @@
/*
* QEMU Random Number Generator Backend
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/rng.h"
#include "qerror.h"
void rng_backend_request_entropy(RngBackend *s, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque)
{
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
if (k->request_entropy) {
k->request_entropy(s, size, receive_entropy, opaque);
}
}
void rng_backend_cancel_requests(RngBackend *s)
{
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
if (k->cancel_requests) {
k->cancel_requests(s);
}
}
static bool rng_backend_prop_get_opened(Object *obj, Error **errp)
{
RngBackend *s = RNG_BACKEND(obj);
return s->opened;
}
void rng_backend_open(RngBackend *s, Error **errp)
{
object_property_set_bool(OBJECT(s), true, "opened", errp);
}
static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
{
RngBackend *s = RNG_BACKEND(obj);
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
if (value == s->opened) {
return;
}
if (!value && s->opened) {
error_set(errp, QERR_PERMISSION_DENIED);
return;
}
if (k->opened) {
k->opened(s, errp);
}
if (!error_is_set(errp)) {
s->opened = value;
}
}
static void rng_backend_init(Object *obj)
{
object_property_add_bool(obj, "opened",
rng_backend_prop_get_opened,
rng_backend_prop_set_opened,
NULL);
}
static TypeInfo rng_backend_info = {
.name = TYPE_RNG_BACKEND,
.parent = TYPE_OBJECT,
.instance_size = sizeof(RngBackend),
.instance_init = rng_backend_init,
.class_size = sizeof(RngBackendClass),
.abstract = true,
};
static void register_types(void)
{
type_register_static(&rng_backend_info);
}
type_init(register_types);

View File

@ -28,6 +28,7 @@
#include "qemu-common.h"
#include "nbd.h"
#include "uri.h"
#include "block_int.h"
#include "module.h"
#include "qemu_socket.h"
@ -55,7 +56,6 @@ typedef struct BDRVNBDState {
uint32_t nbdflags;
off_t size;
size_t blocksize;
char *export_name; /* An NBD server may export several devices */
CoMutex send_mutex;
CoMutex free_sema;
@ -65,13 +65,75 @@ typedef struct BDRVNBDState {
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
struct nbd_reply reply;
/* If it begins with '/', this is a UNIX domain socket. Otherwise,
* it's a string of the form <hostname|ip4|\[ip6\]>:port
*/
int is_unix;
char *host_spec;
char *export_name; /* An NBD server may export several devices */
} BDRVNBDState;
static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
static int nbd_parse_uri(BDRVNBDState *s, const char *filename)
{
URI *uri;
const char *p;
QueryParams *qp = NULL;
int ret = 0;
uri = uri_parse(filename);
if (!uri) {
return -EINVAL;
}
/* transport */
if (!strcmp(uri->scheme, "nbd")) {
s->is_unix = false;
} else if (!strcmp(uri->scheme, "nbd+tcp")) {
s->is_unix = false;
} else if (!strcmp(uri->scheme, "nbd+unix")) {
s->is_unix = true;
} else {
ret = -EINVAL;
goto out;
}
p = uri->path ? uri->path : "/";
p += strspn(p, "/");
if (p[0]) {
s->export_name = g_strdup(p);
}
qp = query_params_parse(uri->query);
if (qp->n > 1 || (s->is_unix && !qp->n) || (!s->is_unix && qp->n)) {
ret = -EINVAL;
goto out;
}
if (s->is_unix) {
/* nbd+unix:///export?socket=path */
if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) {
ret = -EINVAL;
goto out;
}
s->host_spec = g_strdup(qp->p[0].value);
} else {
/* nbd[+tcp]://host:port/export */
if (!uri->server) {
ret = -EINVAL;
goto out;
}
if (!uri->port) {
uri->port = NBD_DEFAULT_PORT;
}
s->host_spec = g_strdup_printf("%s:%d", uri->server, uri->port);
}
out:
if (qp) {
query_params_free(qp);
}
uri_free(uri);
return ret;
}
static int nbd_config(BDRVNBDState *s, const char *filename)
{
char *file;
char *export_name;
@ -79,6 +141,10 @@ static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
const char *unixpath;
int err = -EINVAL;
if (strstr(filename, "://")) {
return nbd_parse_uri(s, filename);
}
file = g_strdup(filename);
export_name = strstr(file, EN_OPTSTR);
@ -98,11 +164,10 @@ static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
/* are we a UNIX or TCP socket? */
if (strstart(host_spec, "unix:", &unixpath)) {
if (unixpath[0] != '/') { /* We demand an absolute path*/
goto out;
}
s->is_unix = true;
s->host_spec = g_strdup(unixpath);
} else {
s->is_unix = false;
s->host_spec = g_strdup(host_spec);
}
@ -262,7 +327,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
off_t size;
size_t blocksize;
if (s->host_spec[0] == '/') {
if (s->is_unix) {
sock = unix_socket_outgoing(s->host_spec);
} else {
sock = tcp_socket_outgoing_spec(s->host_spec);
@ -320,7 +385,7 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
qemu_co_mutex_init(&s->free_sema);
/* Pop the config into our state object. Exit if invalid. */
result = nbd_config(s, filename, flags);
result = nbd_config(s, filename);
if (result != 0) {
return result;
}
@ -498,6 +563,33 @@ static int64_t nbd_getlength(BlockDriverState *bs)
static BlockDriver bdrv_nbd = {
.format_name = "nbd",
.protocol_name = "nbd",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
.bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
};
static BlockDriver bdrv_nbd_tcp = {
.format_name = "nbd",
.protocol_name = "nbd+tcp",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
.bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
};
static BlockDriver bdrv_nbd_unix = {
.format_name = "nbd",
.protocol_name = "nbd+unix",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
@ -506,12 +598,13 @@ static BlockDriver bdrv_nbd = {
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
.protocol_name = "nbd",
};
static void bdrv_nbd_init(void)
{
bdrv_register(&bdrv_nbd);
bdrv_register(&bdrv_nbd_tcp);
bdrv_register(&bdrv_nbd_unix);
}
block_init(bdrv_nbd_init);

View File

@ -82,6 +82,11 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
NBDExport *exp;
NBDCloseNotifier *n;
if (server_fd == -1) {
error_setg(errp, "NBD server not running");
return;
}
if (nbd_export_find(device)) {
error_setg(errp, "NBD server already exporting device '%s'", device);
return;
@ -93,6 +98,13 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
return;
}
if (!has_writable) {
writable = true;
}
if (bdrv_is_read_only(bs)) {
writable = false;
}
exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY,
nbd_server_put_ref);
@ -113,7 +125,9 @@ void qmp_nbd_server_stop(Error **errp)
nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp));
}
qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL);
close(server_fd);
server_fd = -1;
if (server_fd != -1) {
qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL);
close(server_fd);
server_fd = -1;
}
}

View File

@ -50,20 +50,9 @@
# define __printf__ __gnu_printf__
# endif
# endif
# if defined(__APPLE__)
# define QEMU_WEAK_ALIAS(newname, oldname) \
static typeof(oldname) weak_##newname __attribute__((unused, weakref(#oldname)))
# define QEMU_WEAK_REF(newname, oldname) (weak_##newname ? weak_##newname : oldname)
# else
# define QEMU_WEAK_ALIAS(newname, oldname) \
typeof(oldname) newname __attribute__((weak, alias (#oldname)))
# define QEMU_WEAK_REF(newname, oldname) newname
# endif
#else
#define GCC_ATTR /**/
#define GCC_FMT_ATTR(n, m)
#define QEMU_WEAK_ALIAS(newname, oldname) \
_Pragma("weak " #newname "=" #oldname)
#endif
#endif /* COMPILER_H */

31
configure vendored
View File

@ -1383,7 +1383,7 @@ fi
# libseccomp check
if test "$seccomp" != "no" ; then
if $pkg_config libseccomp --modversion >/dev/null 2>&1; then
if $pkg_config --atleast-version=1.0.0 libseccomp --modversion >/dev/null 2>&1; then
LIBS=`$pkg_config --libs libseccomp`
seccomp="yes"
else
@ -2121,11 +2121,10 @@ else
echo " git submodule update --init pixman"
exit 1
fi
pixman_cflags="-I${source_path}/pixman/pixman"
pixman_libs="-Lpixman/pixman/.libs -lpixman-1"
mkdir -p pixman/pixman
pixman_cflags="-I\$(SRC_PATH)/pixman/pixman -I\$(BUILD_DIR)/pixman/pixman"
pixman_libs="-L\$(BUILD_DIR)/pixman/pixman/.libs -lpixman-1"
fi
QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
libs_softmmu="$libs_softmmu $pixman_libs"
##########################################
# libcap probe
@ -3150,6 +3149,10 @@ if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then
roms="$roms spapr-rtas"
fi
# add pixman flags after all config tests are done
QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
libs_softmmu="$libs_softmmu $pixman_libs"
echo "Install prefix $prefix"
echo "BIOS directory `eval echo $qemu_datadir`"
echo "binary directory `eval echo $bindir`"
@ -3659,6 +3662,11 @@ if test "$sparse" = "yes" ; then
echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak
echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak
fi
if test "$cross_prefix" != ""; then
echo "AUTOCONF_HOST := --host=${cross_prefix%-}" >> $config_host_mak
else
echo "AUTOCONF_HOST := " >> $config_host_mak
fi
echo "LDFLAGS=$LDFLAGS" >> $config_host_mak
echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak
echo "ARLIBS_END=$arlibs_end" >> $config_host_mak
@ -3895,7 +3903,10 @@ upper() {
case "$cpu" in
i386|x86_64|ppc)
echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_target_mak
# The TCG interpreter currently does not support ld/st optimization.
if test "$tcg_interpreter" = "no" ; then
echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_target_mak
fi
;;
esac
@ -3960,9 +3971,6 @@ if test "$target_softmmu" = "yes" ; then
if test "$smartcard_nss" = "yes" ; then
echo "subdir-$target: subdir-libcacard" >> $config_host_mak
fi
if test "$pixman" = "internal" ; then
echo "subdir-$target: subdir-pixman" >> $config_host_mak
fi
case "$target_arch2" in
i386|x86_64)
echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak
@ -4160,13 +4168,16 @@ echo "QEMU_INCLUDES+=$includes" >> $config_target_mak
done # for target in $targets
if [ "$pixman" = "internal" ]; then
echo "config-host.h: subdir-pixman" >> $config_host_mak
fi
# build tree in object directory in case the source is not in the current directory
DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32"
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS qapi-generated"
DIRS="$DIRS libcacard libcacard/libcacard libcacard/trace"
DIRS="$DIRS pixman"
FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile"

View File

@ -377,6 +377,11 @@ static inline pixman_format_code_t ds_get_format(DisplayState *ds)
return ds->surface->format;
}
static inline pixman_image_t *ds_get_image(DisplayState *ds)
{
return ds->surface->image;
}
static inline int ds_get_depth(DisplayState *ds)
{
return ds->surface->pf.depth;

5
dma.h
View File

@ -68,6 +68,11 @@ struct DMAContext {
DMAUnmapFunc *unmap;
};
/* A global DMA context corresponding to the address_space_memory
* AddressSpace, for sysbus devices which do DMA.
*/
extern DMAContext dma_context_memory;
static inline void dma_barrier(DMAContext *dma, DMADirection dir)
{
/*

View File

@ -36,7 +36,8 @@ IO ports used
03c0 - 03df : standard vga ports
01ce : bochs vbe interface index port
01cf : bochs vbe interface data port
01cf : bochs vbe interface data port (x86 only)
01d0 : bochs vbe interface data port
Memory regions used

View File

@ -290,10 +290,11 @@ extern int tb_invalidated_flag;
/* The return address may point to the start of the next instruction.
Subtracting one gets us the call instruction itself. */
#if defined(CONFIG_TCG_INTERPRETER)
/* Alpha and SH4 user mode emulations and Softmmu call GETPC().
/* Softmmu, Alpha, MIPS, SH4 and SPARC user mode emulations call GETPC().
For all others, GETPC remains undefined (which makes TCI a little faster. */
# if defined(CONFIG_SOFTMMU) || defined(TARGET_ALPHA) || defined(TARGET_SH4) \
|| defined(TARGET_SPARC)
# if defined(CONFIG_SOFTMMU) || \
defined(TARGET_ALPHA) || defined(TARGET_MIPS) || \
defined(TARGET_SH4) || defined(TARGET_SPARC)
extern uintptr_t tci_tb_ptr;
# define GETPC() tci_tb_ptr
# endif

5
exec.c
View File

@ -34,6 +34,7 @@
#include "hw/xen.h"
#include "qemu-timer.h"
#include "memory.h"
#include "dma.h"
#include "exec-memory.h"
#if defined(CONFIG_USER_ONLY)
#include <qemu.h>
@ -103,6 +104,7 @@ static MemoryRegion *system_io;
AddressSpace address_space_io;
AddressSpace address_space_memory;
DMAContext dma_context_memory;
MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty;
static MemoryRegion io_mem_subpage_ram;
@ -3294,6 +3296,9 @@ static void memory_map_init(void)
memory_listener_register(&core_memory_listener, &address_space_memory);
memory_listener_register(&io_memory_listener, &address_space_io);
memory_listener_register(&tcg_memory_listener, &address_space_memory);
dma_context_init(&dma_context_memory, &address_space_memory,
NULL, NULL, NULL);
}
MemoryRegion *get_system_memory(void)

View File

@ -16,7 +16,7 @@ static inline void gen_icount_start(void)
count = tcg_temp_local_new_i32();
tcg_gen_ld_i32(count, cpu_env, offsetof(CPUArchState, icount_decr.u32));
/* This is a horrid hack to allow fixing up the value later. */
icount_arg = gen_opparam_ptr + 1;
icount_arg = tcg_ctx.gen_opparam_ptr + 1;
tcg_gen_subi_i32(count, count, 0xdeadbeef);
tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);

View File

@ -1310,6 +1310,51 @@ Remove all matches from the access control list, and set the default
policy back to @code{deny}.
ETEXI
{
.name = "nbd_server_start",
.args_type = "all:-a,writable:-w,uri:s",
.params = "nbd_server_start [-a] [-w] host:port",
.help = "serve block devices on the given host and port",
.mhandler.cmd = hmp_nbd_server_start,
},
STEXI
@item nbd_server_start @var{host}:@var{port}
@findex nbd_server_start
Start an NBD server on the given host and/or port. If the @option{-a}
option is included, all of the virtual machine's block devices that
have an inserted media on them are automatically exported; in this case,
the @option{-w} option makes the devices writable too.
ETEXI
{
.name = "nbd_server_add",
.args_type = "writable:-w,device:B",
.params = "nbd_server_add [-w] device",
.help = "export a block device via NBD",
.mhandler.cmd = hmp_nbd_server_add,
},
STEXI
@item nbd_server_add @var{device}
@findex nbd_server_add
Export a block device through QEMU's NBD server, which must be started
beforehand with @command{nbd_server_start}. The @option{-w} option makes the
exported device writable too.
ETEXI
{
.name = "nbd_server_stop",
.args_type = "",
.params = "nbd_server_stop",
.help = "stop serving block devices using the NBD protocol",
.mhandler.cmd = hmp_nbd_server_stop,
},
STEXI
@item nbd_server_stop
@findex nbd_server_stop
Stop the QEMU embedded NBD server.
ETEXI
#if defined(TARGET_I386)
{

76
hmp.c
View File

@ -18,6 +18,7 @@
#include "qemu-option.h"
#include "qemu-timer.h"
#include "qmp-commands.h"
#include "qemu_socket.h"
#include "monitor.h"
#include "console.h"
@ -1259,3 +1260,78 @@ void hmp_screen_dump(Monitor *mon, const QDict *qdict)
qmp_screendump(filename, &err);
hmp_handle_error(mon, &err);
}
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
{
const char *uri = qdict_get_str(qdict, "uri");
int writable = qdict_get_try_bool(qdict, "writable", 0);
int all = qdict_get_try_bool(qdict, "all", 0);
Error *local_err = NULL;
BlockInfoList *block_list, *info;
SocketAddress *addr;
if (writable && !all) {
error_setg(&local_err, "-w only valid together with -a");
goto exit;
}
/* First check if the address is valid and start the server. */
addr = socket_parse(uri, &local_err);
if (local_err != NULL) {
goto exit;
}
qmp_nbd_server_start(addr, &local_err);
qapi_free_SocketAddress(addr);
if (local_err != NULL) {
goto exit;
}
if (!all) {
return;
}
/* Then try adding all block devices. If one fails, close all and
* exit.
*/
block_list = qmp_query_block(NULL);
for (info = block_list; info; info = info->next) {
if (!info->value->has_inserted) {
continue;
}
qmp_nbd_server_add(info->value->device, true, writable, &local_err);
if (local_err != NULL) {
qmp_nbd_server_stop(NULL);
break;
}
}
qapi_free_BlockInfoList(block_list);
exit:
hmp_handle_error(mon, &local_err);
}
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
{
const char *device = qdict_get_str(qdict, "device");
int writable = qdict_get_try_bool(qdict, "writable", 0);
Error *local_err = NULL;
qmp_nbd_server_add(device, true, writable, &local_err);
if (local_err != NULL) {
hmp_handle_error(mon, &local_err);
}
}
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
{
Error *errp = NULL;
qmp_nbd_server_stop(&errp);
hmp_handle_error(mon, &errp);
}

3
hmp.h
View File

@ -77,5 +77,8 @@ void hmp_getfd(Monitor *mon, const QDict *qdict);
void hmp_closefd(Monitor *mon, const QDict *qdict);
void hmp_send_key(Monitor *mon, const QDict *qdict);
void hmp_screen_dump(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
#endif

View File

@ -1,6 +1,7 @@
common-obj-y = usb/ ide/
common-obj-y += loader.o
common-obj-$(CONFIG_VIRTIO) += virtio-console.o
common-obj-$(CONFIG_VIRTIO) += virtio-rng.o
common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-y += fw_cfg.o
common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o

View File

@ -25,7 +25,6 @@
#include "iov.h"
#include "scsi.h"
#include "scsi-defs.h"
#include "block_int.h"
#include "trace.h"
#include "mfi.h"
@ -1080,6 +1079,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
/* Logical device size is in blocks */
bdrv_get_geometry(conf->bs, &ld_size);
info.ld_list[num_ld_disks].ld.v.target_id = sdev->id;
info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun;
info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size);
num_ld_disks++;

View File

@ -1085,7 +1085,7 @@ struct mfi_pd_list {
union mfi_ld_ref {
struct {
uint8_t target_id;
uint8_t reserved;
uint8_t lun_id;
uint16_t seq;
} v;
uint32_t ref;

View File

@ -861,7 +861,8 @@ void mips_malta_init(QEMUMachineInitArgs *args)
be = 0;
#endif
/* FPGA */
malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[2], serial_hds[2]);
/* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]);
/* Load firmware in flash / BIOS. */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);

View File

@ -76,6 +76,7 @@
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
#define FMT_PCIBUS PRIx64

View File

@ -293,6 +293,10 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
qemu_mutex_lock(&qxl->track_lock);
qxl->guest_cursor = 0;
qemu_mutex_unlock(&qxl->track_lock);
if (qxl->ssd.cursor) {
cursor_put(qxl->ssd.cursor);
}
qxl->ssd.cursor = cursor_builtin_hidden();
}
@ -447,6 +451,12 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
qxl->ssd.num_surfaces);
return 1;
}
if (cmd->type == QXL_SURFACE_CMD_CREATE &&
(cmd->u.surface_create.stride & 0x03) != 0) {
qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n",
cmd->u.surface_create.stride);
return 1;
}
qemu_mutex_lock(&qxl->track_lock);
if (cmd->type == QXL_SURFACE_CMD_CREATE) {
qxl->guest_surfaces.cmds[id] = ext->cmd.data;
@ -1059,7 +1069,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
trace_qxl_enter_vga_mode(d->id);
qemu_spice_create_host_primary(&d->ssd);
d->mode = QXL_MODE_VGA;
memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
dpy_gfx_resize(d->ssd.ds);
vga_dirty_log_start(&d->vga);
}
@ -1357,6 +1367,12 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type,
sc->flags);
if ((surface.stride & 0x3) != 0) {
qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0",
surface.stride);
return;
}
surface.mouse_mode = true;
surface.group_id = MEMSLOT_GROUP_GUEST;
if (loadvm) {
@ -1689,7 +1705,13 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
uint32_t le_events = cpu_to_le32(events);
trace_qxl_send_events(d->id, events);
assert(qemu_spice_display_is_running(&d->ssd));
if (!qemu_spice_display_is_running(&d->ssd)) {
/* spice-server tracks guest running state and should not do this */
fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n",
__func__);
trace_qxl_send_events_vm_stopped(d->id, events);
return;
}
old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
if ((old_pending & le_events) == le_events) {
return;
@ -2027,6 +2049,7 @@ static int qxl_init_primary(PCIDevice *dev)
PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
VGACommonState *vga = &qxl->vga;
PortioList *qxl_vga_port_list = g_new(PortioList, 1);
int rc;
qxl->id = 0;
qxl_init_ramsize(qxl);
@ -2041,9 +2064,14 @@ static int qxl_init_primary(PCIDevice *dev)
qemu_spice_display_init_common(&qxl->ssd, vga->ds);
qxl0 = qxl;
register_displaychangelistener(vga->ds, &display_listener);
return qxl_init_common(qxl);
rc = qxl_init_common(qxl);
if (rc != 0) {
return rc;
}
register_displaychangelistener(vga->ds, &display_listener);
return rc;
}
static int qxl_init_secondary(PCIDevice *dev)

View File

@ -26,6 +26,7 @@
#include "loader.h"
#include "elf.h"
#include "hw/virtio.h"
#include "hw/virtio-rng.h"
#include "hw/virtio-serial.h"
#include "hw/virtio-net.h"
#include "hw/sysbus.h"
@ -206,6 +207,18 @@ static int s390_virtio_scsi_init(VirtIOS390Device *dev)
return s390_virtio_device_init(dev, vdev);
}
static int s390_virtio_rng_init(VirtIOS390Device *dev)
{
VirtIODevice *vdev;
vdev = virtio_rng_init((DeviceState *)dev, &dev->rng);
if (!vdev) {
return -1;
}
return s390_virtio_device_init(dev, vdev);
}
static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
{
ram_addr_t token_off;
@ -448,6 +461,29 @@ static TypeInfo s390_virtio_serial = {
.class_init = s390_virtio_serial_class_init,
};
static void s390_virtio_rng_initfn(Object *obj)
{
VirtIOS390Device *dev = VIRTIO_S390_DEVICE(obj);
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
(Object **)&dev->rng.rng, NULL);
}
static void s390_virtio_rng_class_init(ObjectClass *klass, void *data)
{
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
k->init = s390_virtio_rng_init;
}
static TypeInfo s390_virtio_rng = {
.name = "virtio-rng-s390",
.parent = TYPE_VIRTIO_S390_DEVICE,
.instance_size = sizeof(VirtIOS390Device),
.instance_init = s390_virtio_rng_initfn,
.class_init = s390_virtio_rng_class_init,
};
static int s390_virtio_busdev_init(DeviceState *dev)
{
VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
@ -528,6 +564,7 @@ static void s390_virtio_register_types(void)
type_register_static(&s390_virtio_blk);
type_register_static(&s390_virtio_net);
type_register_static(&s390_virtio_scsi);
type_register_static(&s390_virtio_rng);
type_register_static(&s390_virtio_bridge_info);
}

View File

@ -19,6 +19,7 @@
#include "virtio-blk.h"
#include "virtio-net.h"
#include "virtio-rng.h"
#include "virtio-serial.h"
#include "virtio-scsi.h"
@ -75,6 +76,7 @@ struct VirtIOS390Device {
virtio_serial_conf serial;
virtio_net_conf net;
VirtIOSCSIConf scsi;
VirtIORNGConf rng;
};
typedef struct VirtIOS390Bus {

View File

@ -652,7 +652,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
if (buflen > SCSI_MAX_INQUIRY_LEN) {
buflen = SCSI_MAX_INQUIRY_LEN;
}
memset(outbuf, 0, buflen);
outbuf[0] = s->qdev.type & 0x1f;
outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;
@ -1388,6 +1387,7 @@ invalid_param_len:
static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint8_t *p = inbuf;
int cmd = r->req.cmd.buf[0];
int len = r->req.cmd.xfer;
@ -1424,6 +1424,14 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
return;
}
}
if (!bdrv_enable_write_cache(s->qdev.conf.bs)) {
/* The request is used as the AIO opaque value, so add a ref. */
scsi_req_ref(&r->req);
bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
return;
}
scsi_req_complete(&r->req, GOOD);
return;
@ -1596,24 +1604,26 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
break;
}
/*
* FIXME: we shouldn't return anything bigger than 4k, but the code
* requires the buffer to be as big as req->cmd.xfer in several
* places. So, do not allow CDBs with a very large ALLOCATION
* LENGTH. The real fix would be to modify scsi_read_data and
* dma_buf_read, so that they return data beyond the buflen
* as all zeros.
*/
if (req->cmd.xfer > 65536) {
goto illegal_request;
}
r->buflen = MAX(4096, req->cmd.xfer);
if (!r->iov.iov_base) {
/*
* FIXME: we shouldn't return anything bigger than 4k, but the code
* requires the buffer to be as big as req->cmd.xfer in several
* places. So, do not allow CDBs with a very large ALLOCATION
* LENGTH. The real fix would be to modify scsi_read_data and
* dma_buf_read, so that they return data beyond the buflen
* as all zeros.
*/
if (req->cmd.xfer > 65536) {
goto illegal_request;
}
r->buflen = MAX(4096, req->cmd.xfer);
r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
}
buflen = req->cmd.xfer;
outbuf = r->iov.iov_base;
memset(outbuf, 0, r->buflen);
switch (req->cmd.buf[0]) {
case TEST_UNIT_READY:
assert(!s->tray_open && bdrv_is_inserted(s->qdev.conf.bs));
@ -1694,12 +1704,14 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
outbuf[5] = 0;
outbuf[6] = s->qdev.blocksize >> 8;
outbuf[7] = 0;
buflen = 8;
break;
case REQUEST_SENSE:
/* Just return "NO SENSE". */
buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
(req->cmd.buf[1] & 1) == 0);
if (buflen < 0) {
goto illegal_request;
}
break;
case MECHANISM_STATUS:
buflen = scsi_emulate_mechanism_status(s, outbuf);
@ -1770,7 +1782,6 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
}
/* Protection, exponent and lowest lba field left blank. */
buflen = req->cmd.xfer;
break;
}
DPRINTF("Unsupported Service Action In\n");
@ -1827,7 +1838,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
assert(!r->req.aiocb);
r->iov.iov_len = MIN(buflen, req->cmd.xfer);
r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
if (r->iov.iov_len == 0) {
scsi_req_complete(&r->req, GOOD);
}
@ -1962,7 +1973,6 @@ static void scsi_disk_resize_cb(void *opaque)
* direct-access devices.
*/
if (s->qdev.type == TYPE_DISK) {
scsi_device_set_ua(&s->qdev, SENSE_CODE(CAPACITY_CHANGED));
scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED));
}
}

View File

@ -38,6 +38,7 @@
#define USB_TOKEN_IN 0x69 /* device -> host */
#define USB_TOKEN_OUT 0xe1 /* host -> device */
#define USB_RET_SUCCESS (0)
#define USB_RET_NODEV (-1)
#define USB_RET_NAK (-2)
#define USB_RET_STALL (-3)
@ -280,18 +281,20 @@ typedef struct USBDeviceClass {
* Process control request.
* Called from handle_packet().
*
* Returns length or one of the USB_RET_ codes.
* Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
* then the number of bytes transfered is stored in p->actual_length
*/
int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
int index, int length, uint8_t *data);
void (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
int index, int length, uint8_t *data);
/*
* Process data transfers (both BULK and ISOC).
* Called from handle_packet().
*
* Returns length or one of the USB_RET_ codes.
* Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
* then the number of bytes transfered is stored in p->actual_length
*/
int (*handle_data)(USBDevice *dev, USBPacket *p);
void (*handle_data)(USBDevice *dev, USBPacket *p);
void (*set_interface)(USBDevice *dev, int interface,
int alt_old, int alt_new);
@ -354,7 +357,8 @@ struct USBPacket {
uint64_t parameter; /* control transfers */
bool short_not_ok;
bool int_req;
int result; /* transfer length or USB_RET_* status code */
int status; /* USB_RET_* status code */
int actual_length; /* Number of bytes actually transfered */
/* Internal use by the USB layer. */
USBPacketState state;
USBCombinedPacket *combined;
@ -388,7 +392,7 @@ static inline bool usb_packet_is_inflight(USBPacket *p)
USBDevice *usb_find_device(USBPort *port, uint8_t addr);
int usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_packet_complete_one(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
@ -523,10 +527,10 @@ void usb_device_handle_attach(USBDevice *dev);
void usb_device_handle_reset(USBDevice *dev);
int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value,
int index, int length, uint8_t *data);
void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
int val, int index, int length, uint8_t *data);
int usb_device_handle_data(USBDevice *dev, USBPacket *p);
void usb_device_handle_data(USBDevice *dev, USBPacket *p);
void usb_device_set_interface(USBDevice *dev, int interface,
int alt_old, int alt_new);

View File

@ -140,24 +140,21 @@ void usb_device_handle_reset(USBDevice *dev)
}
}
int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
int value, int index, int length, uint8_t *data)
void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
int value, int index, int length, uint8_t *data)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
if (klass->handle_control) {
return klass->handle_control(dev, p, request, value, index, length,
data);
klass->handle_control(dev, p, request, value, index, length, data);
}
return -ENOSYS;
}
int usb_device_handle_data(USBDevice *dev, USBPacket *p)
void usb_device_handle_data(USBDevice *dev, USBPacket *p)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
if (klass->handle_data) {
return klass->handle_data(dev, p);
klass->handle_data(dev, p);
}
return -ENOSYS;
}
const char *usb_device_get_product_desc(USBDevice *dev)

View File

@ -31,12 +31,16 @@ static void usb_combined_packet_add(USBCombinedPacket *combined, USBPacket *p)
p->combined = combined;
}
/* Note will free combined when the last packet gets removed */
static void usb_combined_packet_remove(USBCombinedPacket *combined,
USBPacket *p)
{
assert(p->combined == combined);
p->combined = NULL;
QTAILQ_REMOVE(&combined->packets, p, combined_entry);
if (QTAILQ_EMPTY(&combined->packets)) {
g_free(combined);
}
}
/* Also handles completion of non combined packets for pipelined input eps */
@ -45,9 +49,8 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
USBCombinedPacket *combined = p->combined;
USBEndpoint *ep = p->ep;
USBPacket *next;
enum { completing, complete, leftover };
int result, state = completing;
bool short_not_ok;
int status, actual_length;
bool short_not_ok, done = false;
if (combined == NULL) {
usb_packet_complete_one(dev, p);
@ -56,37 +59,39 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
assert(combined->first == p && p == QTAILQ_FIRST(&combined->packets));
result = combined->first->result;
status = combined->first->status;
actual_length = combined->first->actual_length;
short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok;
QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) {
if (state == completing) {
if (!done) {
/* Distribute data over uncombined packets */
if (result >= p->iov.size) {
p->result = p->iov.size;
if (actual_length >= p->iov.size) {
p->actual_length = p->iov.size;
} else {
/* Send short or error packet to complete the transfer */
p->result = result;
state = complete;
p->actual_length = actual_length;
done = true;
}
/* Report status on the last packet */
if (done || next == NULL) {
p->status = status;
} else {
p->status = USB_RET_SUCCESS;
}
p->short_not_ok = short_not_ok;
/* Note will free combined when the last packet gets removed! */
usb_combined_packet_remove(combined, p);
usb_packet_complete_one(dev, p);
result -= p->result;
actual_length -= p->actual_length;
} else {
/* Remove any leftover packets from the queue */
state = leftover;
p->result = USB_RET_REMOVE_FROM_QUEUE;
p->status = USB_RET_REMOVE_FROM_QUEUE;
/* Note will free combined on the last packet! */
dev->port->ops->complete(dev->port, p);
}
}
/*
* If we had leftover packets the hcd driver will have cancelled them
* and usb_combined_packet_cancel has already freed combined!
*/
if (state != leftover) {
g_free(combined);
}
/* Do not use combined here, it has been freed! */
leave:
/* Check if there are packets in the queue waiting for our completion */
usb_ep_combine_input_packets(ep);
@ -97,14 +102,13 @@ void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p)
{
USBCombinedPacket *combined = p->combined;
assert(combined != NULL);
USBPacket *first = p->combined->first;
/* Note will free combined on the last packet! */
usb_combined_packet_remove(combined, p);
if (p == combined->first) {
if (p == first) {
usb_device_cancel_packet(dev, p);
}
if (QTAILQ_EMPTY(&combined->packets)) {
g_free(combined);
}
}
/*
@ -117,7 +121,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
{
USBPacket *p, *u, *next, *prev = NULL, *first = NULL;
USBPort *port = ep->dev->port;
int ret, totalsize;
int totalsize;
assert(ep->pipeline);
assert(ep->pid == USB_TOKEN_IN);
@ -125,7 +129,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
QTAILQ_FOREACH_SAFE(p, &ep->queue, queue, next) {
/* Empty the queue on a halt */
if (ep->halted) {
p->result = USB_RET_REMOVE_FROM_QUEUE;
p->status = USB_RET_REMOVE_FROM_QUEUE;
port->ops->complete(port, p);
continue;
}
@ -166,8 +170,8 @@ void usb_ep_combine_input_packets(USBEndpoint *ep)
next == NULL ||
/* Work around for Linux usbfs bulk splitting + migration */
(totalsize == 16348 && p->int_req)) {
ret = usb_device_handle_data(ep->dev, first);
assert(ret == USB_RET_ASYNC);
usb_device_handle_data(ep->dev, first);
assert(first->status == USB_RET_ASYNC);
if (first->combined) {
QTAILQ_FOREACH(u, &first->combined->packets, combined_entry) {
usb_packet_set_state(u, USB_PACKET_ASYNC);

View File

@ -97,17 +97,17 @@ void usb_wakeup(USBEndpoint *ep)
#define SETUP_STATE_ACK 3
#define SETUP_STATE_PARAM 4
static int do_token_setup(USBDevice *s, USBPacket *p)
static void do_token_setup(USBDevice *s, USBPacket *p)
{
int request, value, index;
int ret = 0;
if (p->iov.size != 8) {
return USB_RET_STALL;
p->status = USB_RET_STALL;
return;
}
usb_packet_copy(p, s->setup_buf, p->iov.size);
p->result = 0;
p->actual_length = 0;
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
s->setup_index = 0;
@ -116,24 +116,26 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
if (s->setup_buf[0] & USB_DIR_IN) {
ret = usb_device_handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
s->setup_state = SETUP_STATE_SETUP;
return USB_RET_ASYNC;
usb_device_handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (p->status == USB_RET_ASYNC) {
s->setup_state = SETUP_STATE_SETUP;
}
if (p->status != USB_RET_SUCCESS) {
return;
}
if (ret < 0)
return ret;
if (ret < s->setup_len)
s->setup_len = ret;
if (p->actual_length < s->setup_len) {
s->setup_len = p->actual_length;
}
s->setup_state = SETUP_STATE_DATA;
} else {
if (s->setup_len > sizeof(s->data_buf)) {
fprintf(stderr,
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
s->setup_len, sizeof(s->data_buf));
return USB_RET_STALL;
p->status = USB_RET_STALL;
return;
}
if (s->setup_len == 0)
s->setup_state = SETUP_STATE_ACK;
@ -141,13 +143,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
s->setup_state = SETUP_STATE_DATA;
}
return ret;
p->actual_length = 8;
}
static int do_token_in(USBDevice *s, USBPacket *p)
static void do_token_in(USBDevice *s, USBPacket *p)
{
int request, value, index;
int ret = 0;
assert(p->ep->nr == 0);
@ -158,19 +159,15 @@ static int do_token_in(USBDevice *s, USBPacket *p)
switch(s->setup_state) {
case SETUP_STATE_ACK:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
ret = usb_device_handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
return USB_RET_ASYNC;
usb_device_handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (p->status == USB_RET_ASYNC) {
return;
}
s->setup_state = SETUP_STATE_IDLE;
if (ret > 0)
return 0;
return ret;
p->actual_length = 0;
}
/* return 0 byte */
return 0;
break;
case SETUP_STATE_DATA:
if (s->setup_buf[0] & USB_DIR_IN) {
@ -180,20 +177,21 @@ static int do_token_in(USBDevice *s, USBPacket *p)
}
usb_packet_copy(p, s->data_buf + s->setup_index, len);
s->setup_index += len;
if (s->setup_index >= s->setup_len)
if (s->setup_index >= s->setup_len) {
s->setup_state = SETUP_STATE_ACK;
return len;
}
return;
}
s->setup_state = SETUP_STATE_IDLE;
return USB_RET_STALL;
p->status = USB_RET_STALL;
break;
default:
return USB_RET_STALL;
p->status = USB_RET_STALL;
}
}
static int do_token_out(USBDevice *s, USBPacket *p)
static void do_token_out(USBDevice *s, USBPacket *p)
{
assert(p->ep->nr == 0);
@ -205,7 +203,7 @@ static int do_token_out(USBDevice *s, USBPacket *p)
} else {
/* ignore additional output */
}
return 0;
break;
case SETUP_STATE_DATA:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
@ -215,23 +213,23 @@ static int do_token_out(USBDevice *s, USBPacket *p)
}
usb_packet_copy(p, s->data_buf + s->setup_index, len);
s->setup_index += len;
if (s->setup_index >= s->setup_len)
if (s->setup_index >= s->setup_len) {
s->setup_state = SETUP_STATE_ACK;
return len;
}
return;
}
s->setup_state = SETUP_STATE_IDLE;
return USB_RET_STALL;
p->status = USB_RET_STALL;
break;
default:
return USB_RET_STALL;
p->status = USB_RET_STALL;
}
}
static int do_parameter(USBDevice *s, USBPacket *p)
static void do_parameter(USBDevice *s, USBPacket *p)
{
int request, value, index;
int i, ret = 0;
int i, request, value, index;
for (i = 0; i < 8; i++) {
s->setup_buf[i] = p->parameter >> (i*8);
@ -249,27 +247,27 @@ static int do_parameter(USBDevice *s, USBPacket *p)
fprintf(stderr,
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
s->setup_len, sizeof(s->data_buf));
return USB_RET_STALL;
p->status = USB_RET_STALL;
return;
}
if (p->pid == USB_TOKEN_OUT) {
usb_packet_copy(p, s->data_buf, s->setup_len);
}
ret = usb_device_handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (ret < 0) {
return ret;
usb_device_handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (p->status == USB_RET_ASYNC) {
return;
}
if (ret < s->setup_len) {
s->setup_len = ret;
if (p->actual_length < s->setup_len) {
s->setup_len = p->actual_length;
}
if (p->pid == USB_TOKEN_IN) {
p->actual_length = 0;
usb_packet_copy(p, s->data_buf, s->setup_len);
}
return ret;
}
/* ctrl complete function for devices which use usb_generic_handle_packet and
@ -278,30 +276,30 @@ static int do_parameter(USBDevice *s, USBPacket *p)
usb_packet_complete to complete their async control packets. */
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
{
if (p->result < 0) {
if (p->status < 0) {
s->setup_state = SETUP_STATE_IDLE;
}
switch (s->setup_state) {
case SETUP_STATE_SETUP:
if (p->result < s->setup_len) {
s->setup_len = p->result;
if (p->actual_length < s->setup_len) {
s->setup_len = p->actual_length;
}
s->setup_state = SETUP_STATE_DATA;
p->result = 8;
p->actual_length = 8;
break;
case SETUP_STATE_ACK:
s->setup_state = SETUP_STATE_IDLE;
p->result = 0;
p->actual_length = 0;
break;
case SETUP_STATE_PARAM:
if (p->result < s->setup_len) {
s->setup_len = p->result;
if (p->actual_length < s->setup_len) {
s->setup_len = p->actual_length;
}
if (p->pid == USB_TOKEN_IN) {
p->result = 0;
p->actual_length = 0;
usb_packet_copy(p, s->data_buf, s->setup_len);
}
break;
@ -342,40 +340,57 @@ USBDevice *usb_find_device(USBPort *port, uint8_t addr)
return usb_device_find_device(dev, addr);
}
static int usb_process_one(USBPacket *p)
static void usb_process_one(USBPacket *p)
{
USBDevice *dev = p->ep->dev;
/*
* Handlers expect status to be initialized to USB_RET_SUCCESS, but it
* can be USB_RET_NAK here from a previous usb_process_one() call,
* or USB_RET_ASYNC from going through usb_queue_one().
*/
p->status = USB_RET_SUCCESS;
if (p->ep->nr == 0) {
/* control pipe */
if (p->parameter) {
return do_parameter(dev, p);
do_parameter(dev, p);
return;
}
switch (p->pid) {
case USB_TOKEN_SETUP:
return do_token_setup(dev, p);
do_token_setup(dev, p);
break;
case USB_TOKEN_IN:
return do_token_in(dev, p);
do_token_in(dev, p);
break;
case USB_TOKEN_OUT:
return do_token_out(dev, p);
do_token_out(dev, p);
break;
default:
return USB_RET_STALL;
p->status = USB_RET_STALL;
}
} else {
/* data pipe */
return usb_device_handle_data(dev, p);
usb_device_handle_data(dev, p);
}
}
/* Hand over a packet to a device for processing. Return value
static void usb_queue_one(USBPacket *p)
{
usb_packet_set_state(p, USB_PACKET_QUEUED);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
p->status = USB_RET_ASYNC;
}
/* Hand over a packet to a device for processing. p->status ==
USB_RET_ASYNC indicates the processing isn't finished yet, the
driver will call usb_packet_complete() when done processing it. */
int usb_handle_packet(USBDevice *dev, USBPacket *p)
void usb_handle_packet(USBDevice *dev, USBPacket *p)
{
int ret;
if (dev == NULL) {
return USB_RET_NODEV;
p->status = USB_RET_NODEV;
return;
}
assert(dev == p->ep->dev);
assert(dev->state == USB_STATE_DEFAULT);
@ -389,32 +404,26 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
}
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
ret = usb_process_one(p);
if (ret == USB_RET_ASYNC) {
usb_process_one(p);
if (p->status == USB_RET_ASYNC) {
assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
usb_packet_set_state(p, USB_PACKET_ASYNC);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
} else if (ret == USB_RET_ADD_TO_QUEUE) {
usb_packet_set_state(p, USB_PACKET_QUEUED);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
ret = USB_RET_ASYNC;
} else if (p->status == USB_RET_ADD_TO_QUEUE) {
usb_queue_one(p);
} else {
/*
* When pipelining is enabled usb-devices must always return async,
* otherwise packets can complete out of order!
*/
assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue));
if (ret != USB_RET_NAK) {
p->result = ret;
if (p->status != USB_RET_NAK) {
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);
usb_queue_one(p);
}
return ret;
}
void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
@ -422,9 +431,10 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
USBEndpoint *ep = p->ep;
assert(QTAILQ_FIRST(&ep->queue) == p);
assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);
assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK);
if (p->result < 0 || (p->short_not_ok && (p->result < p->iov.size))) {
if (p->status != USB_RET_SUCCESS ||
(p->short_not_ok && (p->actual_length < p->iov.size))) {
ep->halted = true;
}
usb_packet_set_state(p, USB_PACKET_COMPLETE);
@ -438,7 +448,6 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
USBEndpoint *ep = p->ep;
int ret;
usb_packet_check_state(p, USB_PACKET_ASYNC);
usb_packet_complete_one(dev, p);
@ -447,7 +456,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
p = QTAILQ_FIRST(&ep->queue);
if (ep->halted) {
/* Empty the queue on a halt */
p->result = USB_RET_REMOVE_FROM_QUEUE;
p->status = USB_RET_REMOVE_FROM_QUEUE;
dev->port->ops->complete(dev->port, p);
continue;
}
@ -455,12 +464,11 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
break;
}
usb_packet_check_state(p, USB_PACKET_QUEUED);
ret = usb_process_one(p);
if (ret == USB_RET_ASYNC) {
usb_process_one(p);
if (p->status == USB_RET_ASYNC) {
usb_packet_set_state(p, USB_PACKET_ASYNC);
break;
}
p->result = ret;
usb_packet_complete_one(ep->dev, p);
}
}
@ -541,7 +549,8 @@ void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
p->id = id;
p->pid = pid;
p->ep = ep;
p->result = 0;
p->status = USB_RET_SUCCESS;
p->actual_length = 0;
p->parameter = 0;
p->short_not_ok = short_not_ok;
p->int_req = int_req;
@ -557,31 +566,31 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
{
assert(p->result >= 0);
assert(p->result + bytes <= p->iov.size);
assert(p->actual_length >= 0);
assert(p->actual_length + bytes <= p->iov.size);
switch (p->pid) {
case USB_TOKEN_SETUP:
case USB_TOKEN_OUT:
iov_to_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes);
iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
break;
case USB_TOKEN_IN:
iov_from_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes);
iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
break;
default:
fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
abort();
}
p->result += bytes;
p->actual_length += bytes;
}
void usb_packet_skip(USBPacket *p, size_t bytes)
{
assert(p->result >= 0);
assert(p->result + bytes <= p->iov.size);
assert(p->actual_length >= 0);
assert(p->actual_length + bytes <= p->iov.size);
if (p->pid == USB_TOKEN_IN) {
iov_memset(p->iov.iov, p->iov.niov, p->result, 0, bytes);
iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes);
}
p->result += bytes;
p->actual_length += bytes;
}
void usb_packet_cleanup(USBPacket *p)

View File

@ -626,7 +626,8 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
return pos;
}
int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
int value, uint8_t *dest, size_t len)
{
const USBDesc *desc = usb_device_get_usb_desc(dev);
const USBDescDevice *other_dev;
@ -696,6 +697,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
ret = len;
}
memcpy(dest, buf, ret);
p->actual_length = ret;
ret = 0;
}
return ret;
}
@ -715,7 +718,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
break;
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
ret = usb_desc_get_descriptor(dev, value, data, length);
ret = usb_desc_get_descriptor(dev, p, value, data, length);
break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
@ -724,7 +727,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
* the non zero value of bConfigurationValue.
*/
data[0] = dev->config ? dev->config->bConfigurationValue : 0;
ret = 1;
p->actual_length = 1;
ret = 0;
break;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
ret = usb_desc_set_config(dev, value);
@ -749,7 +753,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
}
data[1] = 0x00;
ret = 2;
p->actual_length = 2;
ret = 0;
break;
}
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
@ -772,7 +777,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
break;
}
data[0] = dev->altsetting[index];
ret = 1;
p->actual_length = 1;
ret = 0;
break;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
ret = usb_desc_set_interface(dev, index, value);

View File

@ -216,7 +216,8 @@ void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
void usb_desc_create_serial(USBDevice *dev);
const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len);
int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
int value, uint8_t *dest, size_t len);
int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data);

View File

@ -503,7 +503,7 @@ static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
return ret;
}
static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
static void usb_audio_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index,
int length, uint8_t *data)
{
@ -518,7 +518,7 @@ static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
switch (request) {
@ -534,6 +534,7 @@ static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
}
goto fail;
}
p->actual_length = ret;
break;
case ClassInterfaceOutRequest | CR_SET_CUR:
@ -557,10 +558,9 @@ fail:
"request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
request, value, index, length);
}
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void usb_audio_set_interface(USBDevice *dev, int iface,
@ -583,50 +583,35 @@ static void usb_audio_handle_reset(USBDevice *dev)
usb_audio_set_output_altset(s, ALTSET_OFF);
}
static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
{
int rc;
if (s->out.altset == ALTSET_OFF) {
return USB_RET_STALL;
p->status = USB_RET_STALL;
return;
}
rc = streambuf_put(&s->out.buf, p);
if (rc < p->iov.size && s->debug > 1) {
streambuf_put(&s->out.buf, p);
if (p->actual_length < p->iov.size && s->debug > 1) {
fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
p->iov.size - rc);
p->iov.size - p->actual_length);
}
return 0;
}
static int usb_audio_handle_data(USBDevice *dev, USBPacket *p)
static void usb_audio_handle_data(USBDevice *dev, USBPacket *p)
{
USBAudioState *s = (USBAudioState *) dev;
int ret = 0;
switch (p->pid) {
case USB_TOKEN_OUT:
switch (p->ep->nr) {
case 1:
ret = usb_audio_handle_dataout(s, p);
break;
default:
goto fail;
}
break;
default:
fail:
ret = USB_RET_STALL;
break;
if (p->pid == USB_TOKEN_OUT && p->ep->nr == 1) {
usb_audio_handle_dataout(s, p);
return;
}
if (ret == USB_RET_STALL && s->debug) {
p->status = USB_RET_STALL;
if (s->debug) {
fprintf(stderr, "usb-audio: failed data transaction: "
"pid 0x%x ep 0x%x len 0x%zx\n",
p->pid, p->ep->nr, p->iov.size);
}
return ret;
}
static void usb_audio_handle_destroy(USBDevice *dev)

View File

@ -285,13 +285,15 @@ static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo,
fifo->fifo[off].len = len;
}
static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
USBPacket *p)
{
int len;
if (likely(!fifo->len))
return USB_RET_STALL;
if (likely(!fifo->len)) {
p->status = USB_RET_STALL;
return;
}
len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
@ -310,8 +312,6 @@ static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
fifo->dstart = 0;
fifo->dsize = DFIFO_LEN_MASK + 1;
}
return len;
}
static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
@ -363,7 +363,7 @@ static void usb_bt_handle_reset(USBDevice *dev)
s->outsco.len = 0;
}
static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
static void usb_bt_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
struct USBBtState *s = (struct USBBtState *) dev->opaque;
@ -382,16 +382,15 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
usb_bt_fifo_reset(&s->sco);
break;
}
return ret;
return;
}
ret = 0;
switch (request) {
case InterfaceRequest | USB_REQ_GET_STATUS:
case EndpointRequest | USB_REQ_GET_STATUS:
data[0] = 0x00;
data[1] = 0x00;
ret = 2;
p->actual_length = 2;
break;
case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE:
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
@ -407,16 +406,14 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
break;
default:
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
static void usb_bt_handle_data(USBDevice *dev, USBPacket *p)
{
struct USBBtState *s = (struct USBBtState *) dev->opaque;
int ret = 0;
if (!s->config)
goto fail;
@ -425,15 +422,15 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
case USB_TOKEN_IN:
switch (p->ep->nr) {
case USB_EVT_EP:
ret = usb_bt_fifo_dequeue(&s->evt, p);
usb_bt_fifo_dequeue(&s->evt, p);
break;
case USB_ACL_EP:
ret = usb_bt_fifo_dequeue(&s->acl, p);
usb_bt_fifo_dequeue(&s->acl, p);
break;
case USB_SCO_EP:
ret = usb_bt_fifo_dequeue(&s->sco, p);
usb_bt_fifo_dequeue(&s->sco, p);
break;
default:
@ -460,11 +457,9 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
default:
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void usb_bt_out_hci_packet_event(void *opaque,

View File

@ -371,7 +371,7 @@ static void usb_hid_handle_reset(USBDevice *dev)
hid_reset(&us->hid);
}
static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
@ -380,10 +380,9 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
ret = 0;
switch (request) {
/* hid specific requests */
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
@ -392,15 +391,15 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
if (hs->kind == HID_MOUSE) {
memcpy(data, qemu_mouse_hid_report_descriptor,
sizeof(qemu_mouse_hid_report_descriptor));
ret = sizeof(qemu_mouse_hid_report_descriptor);
p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
} else if (hs->kind == HID_TABLET) {
memcpy(data, qemu_tablet_hid_report_descriptor,
sizeof(qemu_tablet_hid_report_descriptor));
ret = sizeof(qemu_tablet_hid_report_descriptor);
p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
} else if (hs->kind == HID_KEYBOARD) {
memcpy(data, qemu_keyboard_hid_report_descriptor,
sizeof(qemu_keyboard_hid_report_descriptor));
ret = sizeof(qemu_keyboard_hid_report_descriptor);
p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
}
break;
default:
@ -409,14 +408,14 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
break;
case GET_REPORT:
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
ret = hid_pointer_poll(hs, data, length);
p->actual_length = hid_pointer_poll(hs, data, length);
} else if (hs->kind == HID_KEYBOARD) {
ret = hid_keyboard_poll(hs, data, length);
p->actual_length = hid_keyboard_poll(hs, data, length);
}
break;
case SET_REPORT:
if (hs->kind == HID_KEYBOARD) {
ret = hid_keyboard_write(hs, data, length);
p->actual_length = hid_keyboard_write(hs, data, length);
} else {
goto fail;
}
@ -425,19 +424,18 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
goto fail;
}
ret = 1;
data[0] = hs->protocol;
p->actual_length = 1;
break;
case SET_PROTOCOL:
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
goto fail;
}
ret = 0;
hs->protocol = value;
break;
case GET_IDLE:
ret = 1;
data[0] = hs->idle;
p->actual_length = 1;
break;
case SET_IDLE:
hs->idle = (uint8_t) (value >> 8);
@ -445,22 +443,20 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
hid_pointer_activate(hs);
}
ret = 0;
break;
default:
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
{
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
HIDState *hs = &us->hid;
uint8_t buf[p->iov.size];
int ret = 0;
int len = 0;
switch (p->pid) {
case USB_TOKEN_IN:
@ -471,15 +467,16 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
}
if (!hid_has_events(hs) &&
(!hs->idle || hs->next_idle_clock - curtime > 0)) {
return USB_RET_NAK;
p->status = USB_RET_NAK;
return;
}
hid_set_next_idle(hs, curtime);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
ret = hid_pointer_poll(hs, buf, p->iov.size);
len = hid_pointer_poll(hs, buf, p->iov.size);
} else if (hs->kind == HID_KEYBOARD) {
ret = hid_keyboard_poll(hs, buf, p->iov.size);
len = hid_keyboard_poll(hs, buf, p->iov.size);
}
usb_packet_copy(p, buf, ret);
usb_packet_copy(p, buf, len);
} else {
goto fail;
}
@ -487,10 +484,9 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
case USB_TOKEN_OUT:
default:
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void usb_hid_handle_destroy(USBDevice *dev)

View File

@ -288,7 +288,7 @@ static const char *feature_name(int feature)
return name[feature] ?: "?";
}
static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHubState *s = (USBHubState *)dev;
@ -298,7 +298,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
switch(request) {
@ -306,7 +306,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
if (value == 0 && index != 0x81) { /* clear ep halt */
goto fail;
}
ret = 0;
break;
/* usb specific requests */
case GetHubStatus:
@ -314,7 +313,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
data[1] = 0;
data[2] = 0;
data[3] = 0;
ret = 4;
p->actual_length = 4;
break;
case GetPortStatus:
{
@ -331,16 +330,14 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
data[1] = port->wPortStatus >> 8;
data[2] = port->wPortChange;
data[3] = port->wPortChange >> 8;
ret = 4;
p->actual_length = 4;
}
break;
case SetHubFeature:
case ClearHubFeature:
if (value == 0 || value == 1) {
} else {
if (value != 0 && value != 1) {
goto fail;
}
ret = 0;
break;
case SetPortFeature:
{
@ -373,7 +370,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
default:
goto fail;
}
ret = 0;
}
break;
case ClearPortFeature:
@ -413,7 +409,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
default:
goto fail;
}
ret = 0;
}
break;
case GetHubDescriptor:
@ -437,22 +432,20 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
var_hub_size++;
}
ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
data[0] = ret;
p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
data[0] = p->actual_length;
break;
}
default:
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
{
USBHubState *s = (USBHubState *)dev;
int ret;
switch(p->pid) {
case USB_TOKEN_IN:
@ -465,7 +458,8 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
if (p->iov.size == 1) { /* FreeBSD workaround */
n = 1;
} else if (n > p->iov.size) {
return USB_RET_BABBLE;
p->status = USB_RET_BABBLE;
return;
}
status = 0;
for(i = 0; i < NUM_PORTS; i++) {
@ -478,9 +472,8 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
buf[i] = status >> (8 * i);
}
usb_packet_copy(p, buf, n);
ret = n;
} else {
ret = USB_RET_NAK; /* usb11 11.13.1 */
p->status = USB_RET_NAK; /* usb11 11.13.1 */
}
} else {
goto fail;
@ -489,10 +482,9 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
case USB_TOKEN_OUT:
default:
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void usb_hub_handle_destroy(USBDevice *dev)

View File

@ -1048,7 +1048,7 @@ static void usb_net_handle_reset(USBDevice *dev)
{
}
static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
static void usb_net_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBNetState *s = (USBNetState *) dev;
@ -1056,10 +1056,9 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
ret = 0;
switch(request) {
case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
if (!is_rndis(s) || value || index != 0) {
@ -1078,22 +1077,25 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
}
#endif
ret = rndis_parse(s, data, length);
if (ret < 0) {
p->status = ret;
}
break;
case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE:
if (!is_rndis(s) || value || index != 0) {
goto fail;
}
ret = rndis_get_response(s, data);
if (!ret) {
p->actual_length = rndis_get_response(s, data);
if (p->actual_length == 0) {
data[0] = 0;
ret = 1;
p->actual_length = 1;
}
#ifdef TRAFFIC_DEBUG
{
unsigned int i;
fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:");
for (i = 0; i < ret; i++) {
for (i = 0; i < p->actual_length; i++) {
if (!(i & 15))
fprintf(stderr, "\n%04x:", i);
fprintf(stderr, " %02x", data[i]);
@ -1108,72 +1110,67 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
fprintf(stderr, "usbnet: failed control transaction: "
"request 0x%x value 0x%x index 0x%x length 0x%x\n",
request, value, index, length);
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
static void usb_net_handle_statusin(USBNetState *s, USBPacket *p)
{
le32 buf[2];
int ret = 8;
if (p->iov.size < 8) {
return USB_RET_STALL;
p->status = USB_RET_STALL;
return;
}
buf[0] = cpu_to_le32(1);
buf[1] = cpu_to_le32(0);
usb_packet_copy(p, buf, 8);
if (!s->rndis_resp.tqh_first)
ret = USB_RET_NAK;
if (!s->rndis_resp.tqh_first) {
p->status = USB_RET_NAK;
}
#ifdef TRAFFIC_DEBUG
fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
p->iov.size, ret);
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
p->iov.size, p->status);
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->status);
#endif
return ret;
}
static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
static void usb_net_handle_datain(USBNetState *s, USBPacket *p)
{
int ret = USB_RET_NAK;
int len;
if (s->in_ptr > s->in_len) {
usb_net_reset_in_buf(s);
ret = USB_RET_NAK;
return ret;
p->status = USB_RET_NAK;
return;
}
if (!s->in_len) {
ret = USB_RET_NAK;
return ret;
p->status = USB_RET_NAK;
return;
}
ret = s->in_len - s->in_ptr;
if (ret > p->iov.size) {
ret = p->iov.size;
len = s->in_len - s->in_ptr;
if (len > p->iov.size) {
len = p->iov.size;
}
usb_packet_copy(p, &s->in_buf[s->in_ptr], ret);
s->in_ptr += ret;
usb_packet_copy(p, &s->in_buf[s->in_ptr], len);
s->in_ptr += len;
if (s->in_ptr >= s->in_len &&
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
(is_rndis(s) || (s->in_len & (64 - 1)) || !len)) {
/* no short packet necessary */
usb_net_reset_in_buf(s);
}
#ifdef TRAFFIC_DEBUG
fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret);
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, len);
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", len);
#endif
return ret;
}
static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
{
int ret = p->iov.size;
int sz = sizeof(s->out_buf) - s->out_ptr;
struct rndis_packet_msg_type *msg =
(struct rndis_packet_msg_type *) s->out_buf;
@ -1184,21 +1181,23 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
#endif
if (sz > ret)
sz = ret;
if (sz > p->iov.size) {
sz = p->iov.size;
}
usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
s->out_ptr += sz;
if (!is_rndis(s)) {
if (ret < 64) {
if (p->iov.size < 64) {
qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr);
s->out_ptr = 0;
}
return ret;
return;
}
len = le32_to_cpu(msg->MessageLength);
if (s->out_ptr < 8 || s->out_ptr < len)
return ret;
if (s->out_ptr < 8 || s->out_ptr < len) {
return;
}
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
uint32_t size = le32_to_cpu(msg->DataLength);
@ -1207,24 +1206,21 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
}
s->out_ptr -= len;
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
return ret;
}
static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
static void usb_net_handle_data(USBDevice *dev, USBPacket *p)
{
USBNetState *s = (USBNetState *) dev;
int ret = 0;
switch(p->pid) {
case USB_TOKEN_IN:
switch (p->ep->nr) {
case 1:
ret = usb_net_handle_statusin(s, p);
usb_net_handle_statusin(s, p);
break;
case 2:
ret = usb_net_handle_datain(s, p);
usb_net_handle_datain(s, p);
break;
default:
@ -1235,7 +1231,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
case USB_TOKEN_OUT:
switch (p->ep->nr) {
case 2:
ret = usb_net_handle_dataout(s, p);
usb_net_handle_dataout(s, p);
break;
default:
@ -1245,14 +1241,15 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
default:
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
if (ret == USB_RET_STALL)
if (p->status == USB_RET_STALL) {
fprintf(stderr, "usbnet: failed data transaction: "
"pid 0x%x ep 0x%x len 0x%zx\n",
p->pid, p->ep->nr, p->iov.size);
return ret;
}
}
static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)

View File

@ -219,7 +219,7 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
return ret;
}
static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBSerialState *s = (USBSerialState *)dev;
@ -228,13 +228,11 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
DPRINTF("got control %x, value %x\n",request, value);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
ret = 0;
switch (request) {
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
ret = 0;
break;
/* Class specific requests. */
@ -323,7 +321,7 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
case DeviceInVendor | FTDI_GET_MDM_ST:
data[0] = usb_get_modem_lines(s) | 1;
data[1] = 0;
ret = 2;
p->actual_length = 2;
break;
case DeviceOutVendor | FTDI_SET_EVENT_CHR:
/* TODO: handle it */
@ -338,25 +336,23 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
break;
case DeviceInVendor | FTDI_GET_LATENCY:
data[0] = s->latency;
ret = 1;
p->actual_length = 1;
break;
default:
fail:
DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
{
USBSerialState *s = (USBSerialState *)dev;
int i, ret = 0;
uint8_t devep = p->ep->nr;
struct iovec *iov;
uint8_t header[2];
int first_len, len;
int i, first_len, len;
switch (p->pid) {
case USB_TOKEN_OUT:
@ -366,6 +362,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
iov = p->iov.iov + i;
qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
}
p->actual_length = p->iov.size;
break;
case USB_TOKEN_IN:
@ -374,7 +371,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
first_len = RECV_BUF - s->recv_ptr;
len = p->iov.size;
if (len <= 2) {
ret = USB_RET_NAK;
p->status = USB_RET_NAK;
break;
}
header[0] = usb_get_modem_lines(s) | 1;
@ -384,7 +381,6 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
s->event_trigger &= ~FTDI_BI;
header[1] = FTDI_BI;
usb_packet_copy(p, header, 2);
ret = 2;
break;
} else {
header[1] = 0;
@ -393,7 +389,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
if (len > s->recv_used)
len = s->recv_used;
if (!len) {
ret = USB_RET_NAK;
p->status = USB_RET_NAK;
break;
}
if (first_len > len)
@ -404,17 +400,14 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
usb_packet_copy(p, s->recv_buf, len - first_len);
s->recv_used -= len;
s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
ret = len + 2;
break;
default:
DPRINTF("Bad token\n");
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void usb_serial_handle_destroy(USBDevice *dev)

View File

@ -635,39 +635,38 @@ static void ccid_handle_reset(USBDevice *dev)
ccid_reset(s);
}
static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
int value, int index, int length, uint8_t *data)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
int ret = 0;
int ret;
DPRINTF(s, 1, "got control %x, value %x\n", request, value);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
switch (request) {
/* Class specific requests. */
case InterfaceOutClass | CCID_CONTROL_ABORT:
DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n");
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES:
DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n");
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
default:
DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
request, value);
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static bool ccid_card_inserted(USBCCIDState *s)
@ -870,18 +869,13 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
}
}
/*
* Handle a single USB_TOKEN_OUT, return value returned to guest.
* Return value:
* 0 - all ok
* USB_RET_STALL - failed to handle packet
*/
static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
{
CCID_Header *ccid_header;
if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
return USB_RET_STALL;
p->status = USB_RET_STALL;
return;
}
ccid_header = (CCID_Header *)s->bulk_out_data;
usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
@ -890,7 +884,7 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
DPRINTF(s, D_VERBOSE,
"usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
p->iov.size, ccid_header->dwLength);
return 0;
return;
}
if (s->bulk_out_pos < 10) {
DPRINTF(s, 1,
@ -949,60 +943,52 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
}
}
s->bulk_out_pos = 0;
return 0;
}
static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
{
int ret = 0;
int len = 0;
assert(p->iov.size > 0);
ccid_bulk_in_get(s);
if (s->current_bulk_in != NULL) {
ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
p->iov.size);
usb_packet_copy(p, s->current_bulk_in->data +
s->current_bulk_in->pos, ret);
s->current_bulk_in->pos += ret;
s->current_bulk_in->pos, len);
s->current_bulk_in->pos += len;
if (s->current_bulk_in->pos == s->current_bulk_in->len) {
ccid_bulk_in_release(s);
}
} else {
/* return when device has no data - usb 2.0 spec Table 8-4 */
ret = USB_RET_NAK;
p->status = USB_RET_NAK;
}
if (ret > 0) {
if (len) {
DPRINTF(s, D_MORE_INFO,
"%s: %zd/%d req/act to guest (BULK_IN)\n",
__func__, p->iov.size, ret);
__func__, p->iov.size, len);
}
if (ret != USB_RET_NAK && ret < p->iov.size) {
if (len < p->iov.size) {
DPRINTF(s, 1,
"%s: returning short (EREMOTEIO) %d < %zd\n",
__func__, ret, p->iov.size);
__func__, len, p->iov.size);
}
return ret;
}
static int ccid_handle_data(USBDevice *dev, USBPacket *p)
static void ccid_handle_data(USBDevice *dev, USBPacket *p)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
int ret = 0;
uint8_t buf[2];
switch (p->pid) {
case USB_TOKEN_OUT:
ret = ccid_handle_bulk_out(s, p);
ccid_handle_bulk_out(s, p);
break;
case USB_TOKEN_IN:
switch (p->ep->nr) {
case CCID_BULK_IN_EP:
if (!p->iov.size) {
ret = USB_RET_NAK;
} else {
ret = ccid_bulk_in_copy_to_guest(s, p);
}
ccid_bulk_in_copy_to_guest(s, p);
break;
case CCID_INT_IN_EP:
if (s->notify_slot_change) {
@ -1010,7 +996,6 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
buf[1] = s->bmSlotICCState;
usb_packet_copy(p, buf, 2);
ret = 2;
s->notify_slot_change = false;
s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
DPRINTF(s, D_INFO,
@ -1021,17 +1006,15 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
break;
default:
DPRINTF(s, 1, "Bad endpoint\n");
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
break;
default:
DPRINTF(s, 1, "Bad token\n");
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void ccid_handle_destroy(USBDevice *dev)

View File

@ -215,7 +215,7 @@ static const USBDesc desc = {
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
{
uint32_t len;
len = p->iov.size - p->result;
len = p->iov.size - p->actual_length;
if (len > s->scsi_len)
len = s->scsi_len;
usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
@ -263,7 +263,8 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
if (p) {
usb_msd_copy_data(s, p);
p = s->packet;
if (p && p->result == p->iov.size) {
if (p && p->actual_length == p->iov.size) {
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
usb_msd_packet_complete(s);
}
}
@ -292,7 +293,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
s->mode = USB_MSDM_CBW;
} else {
if (s->data_len) {
int len = (p->iov.size - p->result);
int len = (p->iov.size - p->actual_length);
usb_packet_skip(p, len);
s->data_len -= len;
}
@ -300,6 +301,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
s->mode = USB_MSDM_CSW;
}
}
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
usb_msd_packet_complete(s);
} else if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
@ -330,14 +332,14 @@ static void usb_msd_handle_reset(USBDevice *dev)
assert(s->req == NULL);
if (s->packet) {
s->packet->result = USB_RET_STALL;
s->packet->status = USB_RET_STALL;
usb_msd_packet_complete(s);
}
s->mode = USB_MSDM_CBW;
}
static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
MSDState *s = (MSDState *)dev;
@ -345,29 +347,25 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
ret = 0;
switch (request) {
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
ret = 0;
break;
/* Class specific requests. */
case ClassInterfaceOutRequest | MassStorageReset:
/* Reset state ready for the next CBW. */
s->mode = USB_MSDM_CBW;
ret = 0;
break;
case ClassInterfaceRequest | GetMaxLun:
data[0] = 0;
ret = 1;
p->actual_length = 1;
break;
default:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
@ -382,11 +380,10 @@ static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
}
}
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
{
MSDState *s = (MSDState *)dev;
uint32_t tag;
int ret = 0;
struct usb_msd_cbw cbw;
uint8_t devep = p->ep->nr;
@ -433,7 +430,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
scsi_req_continue(s->req);
}
ret = p->result;
break;
case USB_MSDM_DATAOUT:
@ -446,7 +442,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
usb_msd_copy_data(s, p);
}
if (le32_to_cpu(s->csw.residue)) {
int len = p->iov.size - p->result;
int len = p->iov.size - p->actual_length;
if (len) {
usb_packet_skip(p, len);
s->data_len -= len;
@ -455,12 +451,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
}
}
}
if (p->result < p->iov.size) {
if (p->actual_length < p->iov.size) {
DPRINTF("Deferring packet %p [wait data-out]\n", p);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
ret = p->result;
p->status = USB_RET_ASYNC;
}
break;
@ -481,7 +475,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
}
/* Waiting for SCSI write to complete. */
s->packet = p;
ret = USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
break;
case USB_MSDM_CSW:
@ -493,11 +487,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
/* still in flight */
DPRINTF("Deferring packet %p [wait status]\n", p);
s->packet = p;
ret = USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
} else {
usb_msd_send_status(s, p);
s->mode = USB_MSDM_CBW;
ret = 13;
}
break;
@ -508,7 +501,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
usb_msd_copy_data(s, p);
}
if (le32_to_cpu(s->csw.residue)) {
int len = p->iov.size - p->result;
int len = p->iov.size - p->actual_length;
if (len) {
usb_packet_skip(p, len);
s->data_len -= len;
@ -517,12 +510,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
}
}
}
if (p->result < p->iov.size) {
if (p->actual_length < p->iov.size) {
DPRINTF("Deferring packet %p [wait data-in]\n", p);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
ret = p->result;
p->status = USB_RET_ASYNC;
}
break;
@ -535,11 +526,9 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
default:
DPRINTF("Bad token\n");
fail:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void usb_msd_password_cb(void *opaque, int err)

View File

@ -256,10 +256,10 @@ static void usb_uas_send_status_bh(void *opaque)
uas->status = NULL;
usb_packet_copy(p, &st->status, st->length);
p->result = st->length;
QTAILQ_REMOVE(&uas->results, st, next);
g_free(st);
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
usb_packet_complete(&uas->dev, p);
}
@ -349,6 +349,7 @@ static void usb_uas_complete_data_packet(UASRequest *req)
p = req->data;
req->data = NULL;
req->data_async = false;
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
usb_packet_complete(&req->uas->dev, p);
}
@ -357,16 +358,16 @@ static void usb_uas_copy_data(UASRequest *req)
uint32_t length;
length = MIN(req->buf_size - req->buf_off,
req->data->iov.size - req->data->result);
req->data->iov.size - req->data->actual_length);
trace_usb_uas_xfer_data(req->uas->dev.addr, req->tag, length,
req->data->result, req->data->iov.size,
req->data->actual_length, req->data->iov.size,
req->buf_off, req->buf_size);
usb_packet_copy(req->data, scsi_req_get_buf(req->req) + req->buf_off,
length);
req->buf_off += length;
req->data_off += length;
if (req->data->result == req->data->iov.size) {
if (req->data->actual_length == req->data->iov.size) {
usb_uas_complete_data_packet(req);
}
if (req->buf_size && req->buf_off == req->buf_size) {
@ -504,17 +505,17 @@ static void usb_uas_handle_reset(USBDevice *dev)
}
}
static int usb_uas_handle_control(USBDevice *dev, USBPacket *p,
static void usb_uas_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
int ret;
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
fprintf(stderr, "%s: unhandled control request\n", __func__);
return USB_RET_STALL;
p->status = USB_RET_STALL;
}
static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
@ -641,13 +642,13 @@ incorrect_lun:
usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0);
}
static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
{
UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
uas_ui ui;
UASStatus *st;
UASRequest *req;
int length, ret = 0;
int length;
switch (p->ep->nr) {
case UAS_PIPE_ID_COMMAND:
@ -656,16 +657,14 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
switch (ui.hdr.id) {
case UAS_UI_COMMAND:
usb_uas_command(uas, &ui);
ret = length;
break;
case UAS_UI_TASK_MGMT:
usb_uas_task(uas, &ui);
ret = length;
break;
default:
fprintf(stderr, "%s: unknown command ui: id 0x%x\n",
__func__, ui.hdr.id);
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
break;
@ -674,11 +673,10 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
if (st == NULL) {
assert(uas->status == NULL);
uas->status = p;
ret = USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
break;
}
usb_packet_copy(p, &st->status, st->length);
ret = st->length;
QTAILQ_REMOVE(&uas->results, st, next);
g_free(st);
break;
@ -687,28 +685,26 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout;
if (req == NULL) {
fprintf(stderr, "%s: no inflight request\n", __func__);
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
scsi_req_ref(req->req);
req->data = p;
usb_uas_copy_data(req);
if (p->result == p->iov.size || req->complete) {
if (p->actual_length == p->iov.size || req->complete) {
req->data = NULL;
ret = p->result;
} else {
req->data_async = true;
ret = USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
scsi_req_unref(req->req);
usb_uas_start_next_transfer(uas);
break;
default:
fprintf(stderr, "%s: invalid endpoint %d\n", __func__, p->ep->nr);
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static void usb_uas_handle_destroy(USBDevice *dev)

View File

@ -250,7 +250,7 @@ static void usb_wacom_handle_reset(USBDevice *dev)
s->mode = WACOM_MODE_HID;
}
static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBWacomState *s = (USBWacomState *) dev;
@ -258,10 +258,9 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
return;
}
ret = 0;
switch (request) {
case WACOM_SET_REPORT:
if (s->mouse_grabbed) {
@ -269,61 +268,58 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
s->mouse_grabbed = 0;
}
s->mode = data[0];
ret = 0;
break;
case WACOM_GET_REPORT:
data[0] = 0;
data[1] = s->mode;
ret = 2;
p->actual_length = 2;
break;
/* USB HID requests */
case HID_GET_REPORT:
if (s->mode == WACOM_MODE_HID)
ret = usb_mouse_poll(s, data, length);
p->actual_length = usb_mouse_poll(s, data, length);
else if (s->mode == WACOM_MODE_WACOM)
ret = usb_wacom_poll(s, data, length);
p->actual_length = usb_wacom_poll(s, data, length);
break;
case HID_GET_IDLE:
ret = 1;
data[0] = s->idle;
p->actual_length = 1;
break;
case HID_SET_IDLE:
s->idle = (uint8_t) (value >> 8);
ret = 0;
break;
default:
ret = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return ret;
}
static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
{
USBWacomState *s = (USBWacomState *) dev;
uint8_t buf[p->iov.size];
int ret = 0;
int len = 0;
switch (p->pid) {
case USB_TOKEN_IN:
if (p->ep->nr == 1) {
if (!(s->changed || s->idle))
return USB_RET_NAK;
if (!(s->changed || s->idle)) {
p->status = USB_RET_NAK;
return;
}
s->changed = 0;
if (s->mode == WACOM_MODE_HID)
ret = usb_mouse_poll(s, buf, p->iov.size);
len = usb_mouse_poll(s, buf, p->iov.size);
else if (s->mode == WACOM_MODE_WACOM)
ret = usb_wacom_poll(s, buf, p->iov.size);
usb_packet_copy(p, buf, ret);
len = usb_wacom_poll(s, buf, p->iov.size);
usb_packet_copy(p, buf, len);
break;
}
/* Fall through. */
case USB_TOKEN_OUT:
default:
ret = USB_RET_STALL;
break;
p->status = USB_RET_STALL;
}
return ret;
}
static void usb_wacom_handle_destroy(USBDevice *dev)

View File

@ -91,6 +91,7 @@ static const VMStateDescription vmstate_ehci_pci = {
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
VMSTATE_END_OF_LIST()
}
};
@ -105,7 +106,7 @@ static void ehci_class_init(ObjectClass *klass, void *data)
k->device_id = i->device_id;
k->revision = i->revision;
k->class_id = PCI_CLASS_SERIAL_USB;
dc->vmsd = &vmstate_ehci;
dc->vmsd = &vmstate_ehci_pci;
dc->props = ehci_pci_properties;
}

View File

@ -29,9 +29,6 @@
#include "hw/usb/hcd-ehci.h"
/* internal processing - reset HC to try and recover */
#define USB_RET_PROCERR (-99)
/* Capability Registers Base Address - section 2.2 */
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
@ -1111,7 +1108,7 @@ static int ehci_init_transfer(EHCIPacket *p)
while (bytes > 0) {
if (cpage > 4) {
fprintf(stderr, "cpage out of range (%d)\n", cpage);
return USB_RET_PROCERR;
return -1;
}
page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK;
@ -1129,16 +1126,16 @@ static int ehci_init_transfer(EHCIPacket *p)
return 0;
}
static void ehci_finish_transfer(EHCIQueue *q, int status)
static void ehci_finish_transfer(EHCIQueue *q, int len)
{
uint32_t cpage, offset;
if (status > 0) {
if (len > 0) {
/* update cpage & offset */
cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
offset += status;
offset += len;
cpage += offset >> QTD_BUFPTR_SH;
offset &= ~QTD_BUFPTR_MASK;
@ -1163,7 +1160,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
p = container_of(packet, EHCIPacket, packet);
assert(p->async == EHCI_ASYNC_INFLIGHT);
if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
trace_usb_ehci_packet_action(p->queue, p, "remove");
ehci_free_packet(p);
return;
@ -1171,7 +1168,6 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
trace_usb_ehci_packet_action(p->queue, p, "wakeup");
p->async = EHCI_ASYNC_FINISHED;
p->usb_status = packet->result;
if (p->queue->async) {
qemu_bh_schedule(p->queue->ehci->async_bh);
@ -1181,58 +1177,60 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
static void ehci_execute_complete(EHCIQueue *q)
{
EHCIPacket *p = QTAILQ_FIRST(&q->packets);
uint32_t tbytes;
assert(p != NULL);
assert(p->qtdaddr == q->qtdaddr);
assert(p->async == EHCI_ASYNC_INITIALIZED ||
p->async == EHCI_ASYNC_FINISHED);
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
DPRINTF("execute_complete: qhaddr 0x%x, next 0x%x, qtdaddr 0x%x, "
"status %d, actual_length %d\n",
q->qhaddr, q->qh.next, q->qtdaddr,
p->packet.status, p->packet.actual_length);
if (p->usb_status < 0) {
switch (p->usb_status) {
case USB_RET_IOERROR:
case USB_RET_NODEV:
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_STALL:
q->qh.token |= QTD_TOKEN_HALT;
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_NAK:
set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
return; /* We're not done yet with this transaction */
case USB_RET_BABBLE:
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
break;
default:
/* should not be triggerable */
fprintf(stderr, "USB invalid response %d\n", p->usb_status);
assert(0);
break;
switch (p->packet.status) {
case USB_RET_SUCCESS:
break;
case USB_RET_IOERROR:
case USB_RET_NODEV:
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_STALL:
q->qh.token |= QTD_TOKEN_HALT;
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_NAK:
set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
return; /* We're not done yet with this transaction */
case USB_RET_BABBLE:
q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
ehci_raise_irq(q->ehci, USBSTS_ERRINT);
break;
default:
/* should not be triggerable */
fprintf(stderr, "USB invalid response %d\n", p->packet.status);
assert(0);
break;
}
/* TODO check 4.12 for splits */
tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
if (tbytes && p->pid == USB_TOKEN_IN) {
tbytes -= p->packet.actual_length;
if (tbytes) {
/* 4.15.1.2 must raise int on a short input packet */
ehci_raise_irq(q->ehci, USBSTS_INT);
}
} else {
// TODO check 4.12 for splits
uint32_t tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
if (tbytes && p->pid == USB_TOKEN_IN) {
tbytes -= p->usb_status;
if (tbytes) {
/* 4.15.1.2 must raise int on a short input packet */
ehci_raise_irq(q->ehci, USBSTS_INT);
}
} else {
tbytes = 0;
}
DPRINTF("updating tbytes to %d\n", tbytes);
set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);
tbytes = 0;
}
ehci_finish_transfer(q, p->usb_status);
DPRINTF("updating tbytes to %d\n", tbytes);
set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);
ehci_finish_transfer(q, p->packet.actual_length);
usb_packet_unmap(&p->packet, &p->sgl);
qemu_sglist_destroy(&p->sgl);
p->async = EHCI_ASYNC_NONE;
@ -1248,12 +1246,10 @@ static void ehci_execute_complete(EHCIQueue *q)
}
}
// 4.10.3
/* 4.10.3 returns "again" */
static int ehci_execute(EHCIPacket *p, const char *action)
{
USBEndpoint *ep;
int ret;
int endp;
bool spd;
@ -1262,13 +1258,13 @@ static int ehci_execute(EHCIPacket *p, const char *action)
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
fprintf(stderr, "Attempting to execute inactive qtd\n");
return USB_RET_PROCERR;
return -1;
}
if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) {
ehci_trace_guest_bug(p->queue->ehci,
"guest requested more bytes than allowed");
return USB_RET_PROCERR;
return -1;
}
p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
@ -1292,7 +1288,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
if (p->async == EHCI_ASYNC_NONE) {
if (ehci_init_transfer(p) != 0) {
return USB_RET_PROCERR;
return -1;
}
spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
@ -1303,17 +1299,18 @@ static int ehci_execute(EHCIPacket *p, const char *action)
}
trace_usb_ehci_packet_action(p->queue, p, action);
ret = usb_handle_packet(p->queue->dev, &p->packet);
DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd endp %x ret %d\n",
q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
q->packet.iov.size, endp, ret);
usb_handle_packet(p->queue->dev, &p->packet);
DPRINTF("submit: qh 0x%x next 0x%x qtd 0x%x pid 0x%x len %zd endp 0x%x "
"status %d actual_length %d\n", p->queue->qhaddr, p->qtd.next,
p->qtdaddr, p->pid, p->packet.iov.size, endp, p->packet.status,
p->packet.actual_length);
if (ret > BUFF_SIZE) {
if (p->packet.actual_length > BUFF_SIZE) {
fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
return USB_RET_PROCERR;
return -1;
}
return ret;
return 1;
}
/* 4.7.2
@ -1325,7 +1322,6 @@ static int ehci_process_itd(EHCIState *ehci,
{
USBDevice *dev;
USBEndpoint *ep;
int ret;
uint32_t i, len, pid, dir, devaddr, endp;
uint32_t pg, off, ptr1, ptr2, max, mult;
@ -1348,7 +1344,7 @@ static int ehci_process_itd(EHCIState *ehci,
}
if (len > BUFF_SIZE) {
return USB_RET_PROCERR;
return -1;
}
qemu_sglist_init(&ehci->isgl, 2, ehci->dma);
@ -1370,45 +1366,45 @@ static int ehci_process_itd(EHCIState *ehci,
usb_packet_setup(&ehci->ipacket, pid, ep, addr, false,
(itd->transact[i] & ITD_XACT_IOC) != 0);
usb_packet_map(&ehci->ipacket, &ehci->isgl);
ret = usb_handle_packet(dev, &ehci->ipacket);
usb_handle_packet(dev, &ehci->ipacket);
usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
} else {
DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
ret = USB_RET_NAK;
ehci->ipacket.status = USB_RET_NAK;
ehci->ipacket.actual_length = 0;
}
qemu_sglist_destroy(&ehci->isgl);
if (ret < 0) {
switch (ret) {
default:
fprintf(stderr, "Unexpected iso usb result: %d\n", ret);
/* Fall through */
case USB_RET_IOERROR:
case USB_RET_NODEV:
/* 3.3.2: XACTERR is only allowed on IN transactions */
if (dir) {
itd->transact[i] |= ITD_XACT_XACTERR;
ehci_raise_irq(ehci, USBSTS_ERRINT);
}
break;
case USB_RET_BABBLE:
itd->transact[i] |= ITD_XACT_BABBLE;
switch (ehci->ipacket.status) {
case USB_RET_SUCCESS:
break;
default:
fprintf(stderr, "Unexpected iso usb result: %d\n",
ehci->ipacket.status);
/* Fall through */
case USB_RET_IOERROR:
case USB_RET_NODEV:
/* 3.3.2: XACTERR is only allowed on IN transactions */
if (dir) {
itd->transact[i] |= ITD_XACT_XACTERR;
ehci_raise_irq(ehci, USBSTS_ERRINT);
break;
case USB_RET_NAK:
/* no data for us, so do a zero-length transfer */
ret = 0;
break;
}
break;
case USB_RET_BABBLE:
itd->transact[i] |= ITD_XACT_BABBLE;
ehci_raise_irq(ehci, USBSTS_ERRINT);
break;
case USB_RET_NAK:
/* no data for us, so do a zero-length transfer */
ehci->ipacket.actual_length = 0;
break;
}
if (ret >= 0) {
if (!dir) {
/* OUT */
set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
} else {
/* IN */
set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
}
if (!dir) {
set_field(&itd->transact[i], len - ehci->ipacket.actual_length,
ITD_XACT_LENGTH); /* OUT */
} else {
set_field(&itd->transact[i], ehci->ipacket.actual_length,
ITD_XACT_LENGTH); /* IN */
}
if (itd->transact[i] & ITD_XACT_IOC) {
ehci_raise_irq(ehci, USBSTS_INT);
@ -1746,8 +1742,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
break;
case EHCI_ASYNC_INFLIGHT:
/* Check if the guest has added new tds to the queue */
again = (ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)) ==
USB_RET_PROCERR) ? -1 : 1;
again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head));
/* Unfinished async handled packet, go horizontal */
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
break;
@ -1784,6 +1779,7 @@ static int ehci_state_horizqh(EHCIQueue *q)
return again;
}
/* Returns "again" */
static int ehci_fill_queue(EHCIPacket *p)
{
USBEndpoint *ep = p->packet.ep;
@ -1812,17 +1808,14 @@ static int ehci_fill_queue(EHCIPacket *p)
p = ehci_alloc_packet(q);
p->qtdaddr = qtdaddr;
p->qtd = qtd;
p->usb_status = ehci_execute(p, "queue");
if (p->usb_status == USB_RET_PROCERR) {
break;
if (ehci_execute(p, "queue") == -1) {
return -1;
}
assert(p->usb_status == USB_RET_ASYNC);
assert(p->packet.status == USB_RET_ASYNC);
p->async = EHCI_ASYNC_INFLIGHT;
}
if (p->usb_status != USB_RET_PROCERR) {
usb_device_flush_ep_queue(ep->dev, ep);
}
return p->usb_status;
usb_device_flush_ep_queue(ep->dev, ep);
return 1;
}
static int ehci_state_execute(EHCIQueue *q)
@ -1851,18 +1844,17 @@ static int ehci_state_execute(EHCIQueue *q)
ehci_set_usbsts(q->ehci, USBSTS_REC);
}
p->usb_status = ehci_execute(p, "process");
if (p->usb_status == USB_RET_PROCERR) {
again = -1;
again = ehci_execute(p, "process");
if (again == -1) {
goto out;
}
if (p->usb_status == USB_RET_ASYNC) {
if (p->packet.status == USB_RET_ASYNC) {
ehci_flush_qh(q);
trace_usb_ehci_packet_action(p->queue, p, "async");
p->async = EHCI_ASYNC_INFLIGHT;
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
if (q->async) {
again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
again = ehci_fill_queue(p);
} else {
again = 1;
}
@ -1891,7 +1883,7 @@ static int ehci_state_executing(EHCIQueue *q)
}
/* 4.10.5 */
if (p->usb_status == USB_RET_NAK) {
if (p->packet.status == USB_RET_NAK) {
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
} else {
ehci_set_state(q->ehci, q->async, EST_WRITEBACK);

View File

@ -230,7 +230,6 @@ struct EHCIPacket {
QEMUSGList sgl;
int pid;
enum async_state async;
int usb_status;
};
struct EHCIQueue {

View File

@ -607,7 +607,6 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
{
USBDevice *dev;
USBEndpoint *uep;
int ret;
int idx = epnum && dir;
int ttype;
@ -632,15 +631,19 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
ret = usb_handle_packet(dev, &ep->packey[dir].p);
usb_handle_packet(dev, &ep->packey[dir].p);
if (ret == USB_RET_ASYNC) {
if (ep->packey[dir].p.status == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, uep);
ep->status[dir] = len;
return;
}
ep->status[dir] = ret;
if (ep->packey[dir].p.status == USB_RET_SUCCESS) {
ep->status[dir] = ep->packey[dir].p.actual_length;
} else {
ep->status[dir] = ep->packey[dir].p.status;
}
musb_schedule_cb(&s->port, &ep->packey[dir].p);
}
@ -754,7 +757,6 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
if (ep->status[1] == USB_RET_STALL) {
ep->status[1] = 0;
packey->result = 0;
ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
if (!epnum)
@ -793,14 +795,12 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
/* TODO: check len for over/underruns of an OUT packet? */
/* TODO: perhaps make use of e->ext_size[1] here. */
packey->result = ep->status[1];
if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
if (!epnum)
ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */
ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
/* In DMA mode: assert DMA request for this EP */
}

View File

@ -807,21 +807,24 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
DMA_DIRECTION_TO_DEVICE);
}
if (completion) {
ret = ohci->usb_packet.result;
} else {
if (!completion) {
bool int_req = relative_frame_number == frame_count &&
OHCI_BM(iso_td.flags, TD_DI) == 0;
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, addr, false, int_req);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret == USB_RET_ASYNC) {
usb_handle_packet(dev, &ohci->usb_packet);
if (ohci->usb_packet.status == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, ep);
return 1;
}
}
if (ohci->usb_packet.status == USB_RET_SUCCESS) {
ret = ohci->usb_packet.actual_length;
} else {
ret = ohci->usb_packet.status;
}
#ifdef DEBUG_ISOCH
printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",
@ -997,7 +1000,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
#endif
if (completion) {
ret = ohci->usb_packet.result;
ohci->async_td = 0;
ohci->async_complete = 0;
} else {
@ -1017,16 +1019,22 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
usb_packet_setup(&ohci->usb_packet, pid, ep, addr, !flag_r,
OHCI_BM(td.flags, TD_DI) == 0);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
ret = usb_handle_packet(dev, &ohci->usb_packet);
usb_handle_packet(dev, &ohci->usb_packet);
#ifdef DEBUG_PACKET
DPRINTF("ret=%d\n", ret);
DPRINTF("status=%d\n", ohci->usb_packet.status);
#endif
if (ret == USB_RET_ASYNC) {
if (ohci->usb_packet.status == USB_RET_ASYNC) {
usb_device_flush_ep_queue(dev, ep);
ohci->async_td = addr;
return 1;
}
}
if (ohci->usb_packet.status == USB_RET_SUCCESS) {
ret = ohci->usb_packet.actual_length;
} else {
ret = ohci->usb_packet.status;
}
if (ret >= 0) {
if (dir == OHCI_TD_DIR_IN) {
ohci_copy_td(ohci, &td, ohci->usb_buf, ret,
@ -1851,7 +1859,7 @@ static int ohci_init_pxa(SysBusDevice *dev)
/* Cannot fail as we pass NULL for masterbus */
usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0,
NULL);
&dma_context_memory);
sysbus_init_irq(dev, &s->ohci.irq);
sysbus_init_mmio(dev, &s->ohci.mem);

View File

@ -780,22 +780,21 @@ static int uhci_handle_td_error(UHCIState *s, UHCI_TD *td, uint32_t td_addr,
static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)
{
int len = 0, max_len, ret;
int len = 0, max_len;
uint8_t pid;
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
ret = async->packet.result;
if (td->ctrl & TD_CTRL_IOS)
td->ctrl &= ~TD_CTRL_ACTIVE;
if (ret < 0) {
return uhci_handle_td_error(s, td, async->td_addr, ret, int_mask);
if (async->packet.status != USB_RET_SUCCESS) {
return uhci_handle_td_error(s, td, async->td_addr,
async->packet.status, int_mask);
}
len = async->packet.result;
len = async->packet.actual_length;
td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
/* The NAK bit may have been set by a previous frame, so clear it
@ -824,7 +823,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask)
{
int len = 0, max_len;
int ret, max_len;
bool spd;
bool queuing = (q != NULL);
uint8_t pid = td->token & 0xff;
@ -915,13 +914,14 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
switch(pid) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
len = usb_handle_packet(q->ep->dev, &async->packet);
if (len >= 0)
len = max_len;
usb_handle_packet(q->ep->dev, &async->packet);
if (async->packet.status == USB_RET_SUCCESS) {
async->packet.actual_length = max_len;
}
break;
case USB_TOKEN_IN:
len = usb_handle_packet(q->ep->dev, &async->packet);
usb_handle_packet(q->ep->dev, &async->packet);
break;
default:
@ -932,8 +932,8 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
uhci_update_irq(s);
return TD_RESULT_STOP_FRAME;
}
if (len == USB_RET_ASYNC) {
if (async->packet.status == USB_RET_ASYNC) {
uhci_async_link(async);
if (!queuing) {
uhci_queue_fill(q, td);
@ -941,13 +941,11 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
return TD_RESULT_ASYNC_START;
}
async->packet.result = len;
done:
len = uhci_complete_td(s, td, async, int_mask);
ret = uhci_complete_td(s, td, async, int_mask);
usb_packet_unmap(&async->packet, &async->sgl);
uhci_async_free(async);
return len;
return ret;
}
static void uhci_async_complete(USBPort *port, USBPacket *packet)
@ -955,7 +953,7 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet)
UHCIAsync *async = container_of(packet, UHCIAsync, packet);
UHCIState *s = async->queue->uhci;
if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
uhci_async_unlink(async);
uhci_async_cancel(async);
return;

View File

@ -634,6 +634,34 @@ static inline dma_addr_t xhci_mask64(uint64_t addr)
}
}
static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr,
uint32_t *buf, size_t len)
{
int i;
assert((len % sizeof(uint32_t)) == 0);
pci_dma_read(&xhci->pci_dev, addr, buf, len);
for (i = 0; i < (len / sizeof(uint32_t)); i++) {
buf[i] = le32_to_cpu(buf[i]);
}
}
static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr,
uint32_t *buf, size_t len)
{
int i;
uint32_t tmp[len / sizeof(uint32_t)];
assert((len % sizeof(uint32_t)) == 0);
for (i = 0; i < (len / sizeof(uint32_t)); i++) {
tmp[i] = cpu_to_le32(buf[i]);
}
pci_dma_write(&xhci->pci_dev, addr, tmp, len);
}
static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
{
int index;
@ -1045,14 +1073,14 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
{
uint32_t ctx[5];
pci_dma_read(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx));
xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
ctx[0] &= ~EP_STATE_MASK;
ctx[0] |= state;
ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
epctx->pctx, state, ctx[3], ctx[2]);
pci_dma_write(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx));
xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
epctx->state = state;
}
@ -1388,7 +1416,7 @@ static void xhci_xfer_report(XHCITransfer *xfer)
XHCIState *xhci = xfer->xhci;
int i;
left = xfer->packet.result < 0 ? 0 : xfer->packet.result;
left = xfer->packet.actual_length;
for (i = 0; i < xfer->trb_count; i++) {
XHCITRB *trb = &xfer->trbs[i];
@ -1416,7 +1444,7 @@ static void xhci_xfer_report(XHCITransfer *xfer)
if (!reported && ((trb->control & TRB_TR_IOC) ||
(shortpkt && (trb->control & TRB_TR_ISP)) ||
(xfer->status != CC_SUCCESS))) {
(xfer->status != CC_SUCCESS && left == 0))) {
event.slotid = xfer->slotid;
event.epid = xfer->epid;
event.length = (trb->status & 0x1ffff) - chunk;
@ -1490,16 +1518,16 @@ static int xhci_setup_packet(XHCITransfer *xfer)
return 0;
}
static int xhci_complete_packet(XHCITransfer *xfer, int ret)
static int xhci_complete_packet(XHCITransfer *xfer)
{
if (ret == USB_RET_ASYNC) {
if (xfer->packet.status == USB_RET_ASYNC) {
trace_usb_xhci_xfer_async(xfer);
xfer->running_async = 1;
xfer->running_retry = 0;
xfer->complete = 0;
xfer->cancelled = 0;
return 0;
} else if (ret == USB_RET_NAK) {
} else if (xfer->packet.status == USB_RET_NAK) {
trace_usb_xhci_xfer_nak(xfer);
xfer->running_async = 0;
xfer->running_retry = 1;
@ -1513,16 +1541,16 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
xhci_xfer_unmap(xfer);
}
if (ret >= 0) {
trace_usb_xhci_xfer_success(xfer, ret);
if (xfer->packet.status == USB_RET_SUCCESS) {
trace_usb_xhci_xfer_success(xfer, xfer->packet.actual_length);
xfer->status = CC_SUCCESS;
xhci_xfer_report(xfer);
return 0;
}
/* error */
trace_usb_xhci_xfer_error(xfer, ret);
switch (ret) {
trace_usb_xhci_xfer_error(xfer, xfer->packet.status);
switch (xfer->packet.status) {
case USB_RET_NODEV:
xfer->status = CC_USB_TRANSACTION_ERROR;
xhci_xfer_report(xfer);
@ -1534,7 +1562,8 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
xhci_stall_ep(xfer);
break;
default:
fprintf(stderr, "%s: FIXME: ret = %d\n", __FUNCTION__, ret);
fprintf(stderr, "%s: FIXME: status = %d\n", __func__,
xfer->packet.status);
FIXME();
}
return 0;
@ -1544,7 +1573,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
{
XHCITRB *trb_setup, *trb_status;
uint8_t bmRequestType;
int ret;
trb_setup = &xfer->trbs[0];
trb_status = &xfer->trbs[xfer->trb_count-1];
@ -1587,9 +1615,9 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
}
xfer->packet.parameter = trb_setup->parameter;
ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
xhci_complete_packet(xfer, ret);
xhci_complete_packet(xfer);
if (!xfer->running_async && !xfer->running_retry) {
xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
}
@ -1636,7 +1664,6 @@ static void xhci_check_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
{
uint64_t mfindex;
int ret;
DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
@ -1671,9 +1698,9 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
if (xhci_setup_packet(xfer) < 0) {
return -1;
}
ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
xhci_complete_packet(xfer, ret);
xhci_complete_packet(xfer);
if (!xfer->running_async && !xfer->running_retry) {
xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
}
@ -1711,7 +1738,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
if (epctx->retry) {
XHCITransfer *xfer = epctx->retry;
int result;
trace_usb_xhci_xfer_retry(xfer);
assert(xfer->running_retry);
@ -1725,19 +1751,19 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
if (xhci_setup_packet(xfer) < 0) {
return;
}
result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
assert(result != USB_RET_NAK);
xhci_complete_packet(xfer, result);
usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
assert(xfer->packet.status != USB_RET_NAK);
xhci_complete_packet(xfer);
} else {
/* retry nak'ed transfer */
if (xhci_setup_packet(xfer) < 0) {
return;
}
result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
if (result == USB_RET_NAK) {
usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
if (xfer->packet.status == USB_RET_NAK) {
return;
}
xhci_complete_packet(xfer, result);
xhci_complete_packet(xfer);
}
assert(!xfer->running_retry);
epctx->retry = NULL;
@ -1883,14 +1909,14 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
assert(slotid >= 1 && slotid <= xhci->numslots);
dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx));
poctx = ldq_le_pci_dma(&xhci->pci_dev, dcbaap + 8*slotid);
ictx = xhci_mask64(pictx);
octx = xhci_mask64(le64_to_cpu(poctx));
octx = xhci_mask64(poctx);
DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
@ -1898,8 +1924,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
return CC_TRB_ERROR;
}
pci_dma_read(&xhci->pci_dev, ictx+32, slot_ctx, sizeof(slot_ctx));
pci_dma_read(&xhci->pci_dev, ictx+64, ep0_ctx, sizeof(ep0_ctx));
xhci_dma_read_u32s(xhci, ictx+32, slot_ctx, sizeof(slot_ctx));
xhci_dma_read_u32s(xhci, ictx+64, ep0_ctx, sizeof(ep0_ctx));
DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
@ -1953,8 +1979,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
return res;
}
@ -1987,17 +2013,17 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
}
}
pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
return CC_SUCCESS;
}
pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
@ -2005,8 +2031,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
return CC_TRB_ERROR;
}
pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx));
pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx));
xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]);
@ -2018,8 +2044,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
xhci_disable_ep(xhci, slotid, i);
}
if (ictl_ctx[1] & (1<<i)) {
pci_dma_read(&xhci->pci_dev, ictx+32+(32*i), ep_ctx,
sizeof(ep_ctx));
xhci_dma_read_u32s(xhci, ictx+32+(32*i), ep_ctx, sizeof(ep_ctx));
DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
ep_ctx[3], ep_ctx[4]);
@ -2031,7 +2056,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
ep_ctx[3], ep_ctx[4]);
pci_dma_write(&xhci->pci_dev, octx+(32*i), ep_ctx, sizeof(ep_ctx));
xhci_dma_write_u32s(xhci, octx+(32*i), ep_ctx, sizeof(ep_ctx));
}
}
@ -2043,7 +2068,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
return CC_SUCCESS;
}
@ -2068,7 +2093,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
@ -2077,12 +2102,12 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
}
if (ictl_ctx[1] & 0x1) {
pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx));
xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx));
DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
slot_ctx[1] &= ~0xFFFF; /* max exit latency */
slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
@ -2092,17 +2117,17 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
}
if (ictl_ctx[1] & 0x2) {
pci_dma_read(&xhci->pci_dev, ictx+64, iep0_ctx, sizeof(iep0_ctx));
xhci_dma_read_u32s(xhci, ictx+64, iep0_ctx, sizeof(iep0_ctx));
DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
iep0_ctx[3], iep0_ctx[4]);
pci_dma_read(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
xhci_dma_read_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
@ -2110,7 +2135,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
}
return CC_SUCCESS;
@ -2135,12 +2160,12 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
}
}
pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
return CC_SUCCESS;
}
@ -2922,11 +2947,11 @@ static void xhci_complete(USBPort *port, USBPacket *packet)
{
XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
xhci_ep_nuke_one_xfer(xfer);
return;
}
xhci_complete_packet(xfer, packet->result);
xhci_complete_packet(xfer);
xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
}

View File

@ -121,7 +121,7 @@ static void usb_host_handle_reset(USBDevice *dev)
* -check device states against transfer requests
* and return appropriate response
*/
static int usb_host_handle_control(USBDevice *dev,
static void usb_host_handle_control(USBDevice *dev,
USBPacket *p,
int request,
int value,
@ -139,7 +139,6 @@ static int usb_host_handle_control(USBDevice *dev,
/* specific SET_ADDRESS support */
dev->addr = value;
return 0;
} else if ((request >> 8) == UT_WRITE_DEVICE &&
(request & 0xff) == UR_SET_CONFIG) {
@ -151,10 +150,8 @@ static int usb_host_handle_control(USBDevice *dev,
printf("handle_control: failed to set configuration - %s\n",
strerror(errno));
#endif
return USB_RET_STALL;
p->status = USB_RET_STALL;
}
return 0;
} else if ((request >> 8) == UT_WRITE_INTERFACE &&
(request & 0xff) == UR_SET_INTERFACE) {
@ -168,10 +165,8 @@ static int usb_host_handle_control(USBDevice *dev,
printf("handle_control: failed to set alternate interface - %s\n",
strerror(errno));
#endif
return USB_RET_STALL;
p->status = USB_RET_STALL;
}
return 0;
} else {
req.ucr_request.bmRequestType = request >> 8;
req.ucr_request.bRequest = request & 0xff;
@ -201,14 +196,14 @@ static int usb_host_handle_control(USBDevice *dev,
printf("handle_control: error after request - %s\n",
strerror(errno));
#endif
return USB_RET_NAK; // STALL
p->status = USB_RET_NAK; /* STALL */
} else {
return req.ucr_actlen;
p->actual_length = req.ucr_actlen;
}
}
}
static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
static void usb_host_handle_data(USBDevice *dev, USBPacket *p)
{
USBHostDevice *s = (USBHostDevice *)dev;
int ret, fd, mode;
@ -232,7 +227,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
fd = ensure_ep_open(s, devep, mode);
if (fd < 0) {
sigprocmask(SIG_SETMASK, &old_mask, NULL);
return USB_RET_NODEV;
p->status = USB_RET_NODEV;
return;
}
if (ioctl(fd, USB_SET_TIMEOUT, &timeout) < 0) {
@ -267,12 +263,13 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
switch(errno) {
case ETIMEDOUT:
case EINTR:
return USB_RET_NAK;
p->status = USB_RET_NAK;
break;
default:
return USB_RET_STALL;
p->status = USB_RET_STALL;
}
} else {
return ret;
p->actual_length = ret;
}
}

View File

@ -366,28 +366,29 @@ static void async_complete(void *opaque)
if (p) {
switch (aurb->urb.status) {
case 0:
p->result += aurb->urb.actual_length;
p->actual_length = aurb->urb.actual_length;
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
break;
case -EPIPE:
set_halt(s, p->pid, p->ep->nr);
p->result = USB_RET_STALL;
p->status = USB_RET_STALL;
break;
case -EOVERFLOW:
p->result = USB_RET_BABBLE;
p->status = USB_RET_BABBLE;
break;
default:
p->result = USB_RET_IOERROR;
p->status = USB_RET_IOERROR;
break;
}
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status);
usb_generic_async_ctrl_complete(&s->dev, p);
} else if (!aurb->more) {
trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status);
usb_packet_complete(&s->dev, p);
}
}
@ -733,27 +734,31 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
clear_iso_started(s, pid, ep);
}
static int urb_status_to_usb_ret(int status)
static void urb_status_to_usb_ret(int status, USBPacket *p)
{
switch (status) {
case -EPIPE:
return USB_RET_STALL;
p->status = USB_RET_STALL;
break;
case -EOVERFLOW:
return USB_RET_BABBLE;
p->status = USB_RET_BABBLE;
break;
default:
return USB_RET_IOERROR;
p->status = USB_RET_IOERROR;
}
}
static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
static void usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
{
AsyncURB *aurb;
int i, j, ret, max_packet_size, offset, len = 0;
int i, j, max_packet_size, offset, len;
uint8_t *buf;
max_packet_size = p->ep->max_packet_size;
if (max_packet_size == 0)
return USB_RET_NAK;
if (max_packet_size == 0) {
p->status = USB_RET_NAK;
return;
}
aurb = get_iso_urb(s, p->pid, p->ep->nr);
if (!aurb) {
@ -766,18 +771,17 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
if (in) {
/* Check urb status */
if (aurb[i].urb.status) {
len = urb_status_to_usb_ret(aurb[i].urb.status);
urb_status_to_usb_ret(aurb[i].urb.status, p);
/* Move to the next urb */
aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
/* Check frame status */
} else if (aurb[i].urb.iso_frame_desc[j].status) {
len = urb_status_to_usb_ret(
aurb[i].urb.iso_frame_desc[j].status);
urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status, p);
/* Check the frame fits */
} else if (aurb[i].urb.iso_frame_desc[j].actual_length
> p->iov.size) {
printf("husb: received iso data is larger then packet\n");
len = USB_RET_BABBLE;
p->status = USB_RET_BABBLE;
/* All good copy data over */
} else {
len = aurb[i].urb.iso_frame_desc[j].actual_length;
@ -792,7 +796,8 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
/* Check the frame fits */
if (len > max_packet_size) {
printf("husb: send iso data is larger then max packet size\n");
return USB_RET_NAK;
p->status = USB_RET_NAK;
return;
}
/* All good copy data over */
@ -823,17 +828,16 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
/* (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) {
ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
if (ret < 0) {
if (ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]) < 0) {
perror("USBDEVFS_SUBMITURB");
if (!in || len == 0) {
if (!in || p->status == USB_RET_SUCCESS) {
switch(errno) {
case ETIMEDOUT:
len = USB_RET_NAK;
p->status = USB_RET_NAK;
break;
case EPIPE:
default:
len = USB_RET_STALL;
p->status = USB_RET_STALL;
}
}
break;
@ -843,11 +847,9 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
}
}
}
return len;
}
static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
static void usb_host_handle_data(USBDevice *dev, USBPacket *p)
{
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
struct usbdevfs_urb *urb;
@ -862,7 +864,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
if (!is_valid(s, p->pid, p->ep->nr)) {
trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
return USB_RET_NAK;
p->status = USB_RET_NAK;
return;
}
if (p->pid == USB_TOKEN_IN) {
@ -877,13 +880,15 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
if (ret < 0) {
perror("USBDEVFS_CLEAR_HALT");
trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
return USB_RET_NAK;
p->status = USB_RET_NAK;
return;
}
clear_halt(s, p->pid, p->ep->nr);
}
if (is_isoc(s, p->pid, p->ep->nr)) {
return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
return;
}
v = 0;
@ -933,17 +938,19 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
case ETIMEDOUT:
trace_usb_host_req_complete(s->bus_num, s->addr, p,
USB_RET_NAK);
return USB_RET_NAK;
p->status = USB_RET_NAK;
break;
case EPIPE:
default:
trace_usb_host_req_complete(s->bus_num, s->addr, p,
USB_RET_STALL);
return USB_RET_STALL;
p->status = USB_RET_STALL;
}
return;
}
} while (rem > 0);
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
static int ctrl_error(void)
@ -955,14 +962,13 @@ static int ctrl_error(void)
}
}
static int usb_host_set_address(USBHostDevice *s, int addr)
static void usb_host_set_address(USBHostDevice *s, int addr)
{
trace_usb_host_set_address(s->bus_num, s->addr, addr);
s->dev.addr = addr;
return 0;
}
static int usb_host_set_config(USBHostDevice *s, int config)
static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p)
{
int ret, first = 1;
@ -987,14 +993,15 @@ again:
}
if (ret < 0) {
return ctrl_error();
p->status = ctrl_error();
return;
}
usb_host_claim_interfaces(s, config);
usb_linux_update_endp_table(s);
return 0;
}
static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
static void usb_host_set_interface(USBHostDevice *s, int iface, int alt,
USBPacket *p)
{
struct usbdevfs_setinterface si;
int i, ret;
@ -1011,7 +1018,8 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
}
if (iface >= USB_MAX_INTERFACES) {
return USB_RET_STALL;
p->status = USB_RET_STALL;
return;
}
si.interface = iface;
@ -1022,15 +1030,15 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
iface, alt, ret, errno);
if (ret < 0) {
return ctrl_error();
p->status = ctrl_error();
return;
}
s->dev.altsetting[iface] = alt;
usb_linux_update_endp_table(s);
return 0;
}
static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
static void usb_host_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
@ -1048,19 +1056,19 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
ret = usb_host_set_address(s, value);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
usb_host_set_address(s, value);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
return;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
ret = usb_host_set_config(s, value & 0xff);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
usb_host_set_config(s, value & 0xff, p);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
return;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
ret = usb_host_set_interface(s, index, value);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
usb_host_set_interface(s, index, value, p);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
return;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == 0) { /* clear halt */
@ -1068,17 +1076,16 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index);
clear_halt(s, pid, index & 0x0f);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0);
return 0;
return;
}
}
/* The rest are asynchronous */
assert(p && p->result == 0);
if (length > sizeof(dev->data_buf)) {
fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
length, sizeof(dev->data_buf));
return USB_RET_STALL;
p->status = USB_RET_STALL;
return;
}
aurb = async_alloc(s);
@ -1112,14 +1119,17 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
switch(errno) {
case ETIMEDOUT:
return USB_RET_NAK;
p->status = USB_RET_NAK;
break;
case EPIPE:
default:
return USB_RET_STALL;
p->status = USB_RET_STALL;
break;
}
return;
}
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
/* returns 1 on problem encountered or 0 for success */

View File

@ -141,8 +141,8 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
struct usb_redir_interrupt_packet_header *interrupt_header,
uint8_t *data, int data_len);
static int usbredir_handle_status(USBRedirDevice *dev,
int status, int actual_len);
static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
int status);
#define VERSION "qemu usb-redir guest " QEMU_VERSION
@ -443,7 +443,7 @@ static void usbredir_handle_reset(USBDevice *udev)
usbredirparser_do_write(dev->parser);
}
static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
uint8_t ep)
{
int status, len;
@ -500,7 +500,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
!dev->endpoint[EP2I(ep)].bufpq_prefilled) {
if (dev->endpoint[EP2I(ep)].bufpq_size <
dev->endpoint[EP2I(ep)].bufpq_target_size) {
return usbredir_handle_status(dev, 0, 0);
return;
}
dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
}
@ -514,27 +514,23 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
/* Check iso_error for stream errors, otherwise its an underrun */
status = dev->endpoint[EP2I(ep)].iso_error;
dev->endpoint[EP2I(ep)].iso_error = 0;
return status ? USB_RET_IOERROR : 0;
p->status = status ? USB_RET_IOERROR : USB_RET_SUCCESS;
return;
}
DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
status = isop->status;
if (status != usb_redir_success) {
bufp_free(dev, isop, ep);
return USB_RET_IOERROR;
}
len = isop->len;
if (len > p->iov.size) {
ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
ep, len, (int)p->iov.size);
bufp_free(dev, isop, ep);
return USB_RET_BABBLE;
len = p->iov.size;
status = usb_redir_babble;
}
usb_packet_copy(p, isop->data, len);
bufp_free(dev, isop, ep);
return len;
usbredir_handle_status(dev, p, status);
} else {
/* If the stream was not started because of a pending error don't
send the packet to the usb-host */
@ -554,7 +550,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
dev->endpoint[EP2I(ep)].iso_error = 0;
DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status,
p->iov.size);
return usbredir_handle_status(dev, status, p->iov.size);
usbredir_handle_status(dev, p, status);
}
}
@ -572,7 +568,7 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
usbredir_free_bufpq(dev, ep);
}
static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
uint8_t ep)
{
struct usb_redir_bulk_packet_header bulk_packet;
@ -581,7 +577,8 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id);
if (usbredir_already_in_flight(dev, p->id)) {
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
return;
}
bulk_packet.endpoint = ep;
@ -608,10 +605,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
&bulk_packet, buf, size);
}
usbredirparser_do_write(dev->parser);
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
static void usbredir_handle_interrupt_data(USBRedirDevice *dev,
USBPacket *p, uint8_t ep)
{
if (ep & USB_DIR_IN) {
@ -643,28 +640,25 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
status = dev->endpoint[EP2I(ep)].interrupt_error;
dev->endpoint[EP2I(ep)].interrupt_error = 0;
if (status) {
return usbredir_handle_status(dev, status, 0);
usbredir_handle_status(dev, p, status);
} else {
p->status = USB_RET_NAK;
}
return USB_RET_NAK;
return;
}
DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
intp->status, intp->len);
status = intp->status;
if (status != usb_redir_success) {
bufp_free(dev, intp, ep);
return usbredir_handle_status(dev, status, 0);
}
len = intp->len;
if (len > p->iov.size) {
ERROR("received int data is larger then packet ep %02X\n", ep);
bufp_free(dev, intp, ep);
return USB_RET_BABBLE;
len = p->iov.size;
status = usb_redir_babble;
}
usb_packet_copy(p, intp->data, len);
bufp_free(dev, intp, ep);
return len;
usbredir_handle_status(dev, p, status);
} else {
/* Output interrupt endpoint, normal async operation */
struct usb_redir_interrupt_packet_header interrupt_packet;
@ -674,7 +668,8 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
p->iov.size, p->id);
if (usbredir_already_in_flight(dev, p->id)) {
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
return;
}
interrupt_packet.endpoint = ep;
@ -685,7 +680,7 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
usbredirparser_send_interrupt_packet(dev->parser, p->id,
&interrupt_packet, buf, p->iov.size);
usbredirparser_do_write(dev->parser);
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
}
@ -705,7 +700,7 @@ static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
usbredir_free_bufpq(dev, ep);
}
static int usbredir_handle_data(USBDevice *udev, USBPacket *p)
static void usbredir_handle_data(USBDevice *udev, USBPacket *p)
{
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
uint8_t ep;
@ -718,21 +713,26 @@ static int usbredir_handle_data(USBDevice *udev, USBPacket *p)
switch (dev->endpoint[EP2I(ep)].type) {
case USB_ENDPOINT_XFER_CONTROL:
ERROR("handle_data called for control transfer on ep %02X\n", ep);
return USB_RET_NAK;
p->status = USB_RET_NAK;
break;
case USB_ENDPOINT_XFER_ISOC:
return usbredir_handle_iso_data(dev, p, ep);
usbredir_handle_iso_data(dev, p, ep);
break;
case USB_ENDPOINT_XFER_BULK:
if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN &&
p->ep->pipeline) {
return USB_RET_ADD_TO_QUEUE;
p->status = USB_RET_ADD_TO_QUEUE;
break;
}
return usbredir_handle_bulk_data(dev, p, ep);
usbredir_handle_bulk_data(dev, p, ep);
break;
case USB_ENDPOINT_XFER_INT:
return usbredir_handle_interrupt_data(dev, p, ep);
usbredir_handle_interrupt_data(dev, p, ep);
break;
default:
ERROR("handle_data ep %02X has unknown type %d\n", ep,
dev->endpoint[EP2I(ep)].type);
return USB_RET_NAK;
p->status = USB_RET_NAK;
}
}
@ -743,7 +743,7 @@ static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
}
}
static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
int config)
{
struct usb_redir_set_configuration_header set_config;
@ -768,19 +768,19 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
set_config.configuration = config;
usbredirparser_send_set_configuration(dev->parser, p->id, &set_config);
usbredirparser_do_write(dev->parser);
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
static void usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
{
DPRINTF("get config id %"PRIu64"\n", p->id);
usbredirparser_send_get_configuration(dev->parser, p->id);
usbredirparser_do_write(dev->parser);
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
int interface, int alt)
{
struct usb_redir_set_alt_setting_header set_alt;
@ -808,10 +808,10 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
set_alt.alt = alt;
usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt);
usbredirparser_do_write(dev->parser);
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
static void usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
int interface)
{
struct usb_redir_get_alt_setting_header get_alt;
@ -821,17 +821,18 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
get_alt.interface = interface;
usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt);
usbredirparser_do_write(dev->parser);
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
static void usbredir_handle_control(USBDevice *udev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
struct usb_redir_control_packet_header control_packet;
if (usbredir_already_in_flight(dev, p->id)) {
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
return;
}
/* Special cases for certain standard device requests */
@ -839,15 +840,19 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
DPRINTF("set address %d\n", value);
dev->dev.addr = value;
return 0;
return;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
return usbredir_set_config(dev, p, value & 0xff);
usbredir_set_config(dev, p, value & 0xff);
return;
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
return usbredir_get_config(dev, p);
usbredir_get_config(dev, p);
return;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
return usbredir_set_interface(dev, p, index, value);
usbredir_set_interface(dev, p, index, value);
return;
case InterfaceRequest | USB_REQ_GET_INTERFACE:
return usbredir_get_interface(dev, p, index);
usbredir_get_interface(dev, p, index);
return;
}
/* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */
@ -871,7 +876,7 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
&control_packet, data, length);
}
usbredirparser_do_write(dev->parser);
return USB_RET_ASYNC;
p->status = USB_RET_ASYNC;
}
/*
@ -1159,29 +1164,34 @@ error:
* usbredirparser packet complete callbacks
*/
static int usbredir_handle_status(USBRedirDevice *dev,
int status, int actual_len)
static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
int status)
{
switch (status) {
case usb_redir_success:
return actual_len;
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
break;
case usb_redir_stall:
return USB_RET_STALL;
p->status = USB_RET_STALL;
break;
case usb_redir_cancelled:
/*
* When the usbredir-host unredirects a device, it will report a status
* of cancelled for all pending packets, followed by a disconnect msg.
*/
return USB_RET_IOERROR;
p->status = USB_RET_IOERROR;
break;
case usb_redir_inval:
WARNING("got invalid param error from usb-host?\n");
return USB_RET_IOERROR;
p->status = USB_RET_IOERROR;
break;
case usb_redir_babble:
return USB_RET_BABBLE;
p->status = USB_RET_BABBLE;
break;
case usb_redir_ioerror:
case usb_redir_timeout:
default:
return USB_RET_IOERROR;
p->status = USB_RET_IOERROR;
}
}
@ -1412,7 +1422,6 @@ static void usbredir_configuration_status(void *priv, uint64_t id,
{
USBRedirDevice *dev = priv;
USBPacket *p;
int len = 0;
DPRINTF("set config status %d config %d id %"PRIu64"\n",
config_status->status, config_status->configuration, id);
@ -1421,9 +1430,9 @@ static void usbredir_configuration_status(void *priv, uint64_t id,
if (p) {
if (dev->dev.setup_buf[0] & USB_DIR_IN) {
dev->dev.data_buf[0] = config_status->configuration;
len = 1;
p->actual_length = 1;
}
p->result = usbredir_handle_status(dev, config_status->status, len);
usbredir_handle_status(dev, p, config_status->status);
usb_generic_async_ctrl_complete(&dev->dev, p);
}
}
@ -1433,7 +1442,6 @@ static void usbredir_alt_setting_status(void *priv, uint64_t id,
{
USBRedirDevice *dev = priv;
USBPacket *p;
int len = 0;
DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n",
alt_setting_status->status, alt_setting_status->interface,
@ -1443,10 +1451,9 @@ static void usbredir_alt_setting_status(void *priv, uint64_t id,
if (p) {
if (dev->dev.setup_buf[0] & USB_DIR_IN) {
dev->dev.data_buf[0] = alt_setting_status->alt;
len = 1;
p->actual_length = 1;
}
p->result =
usbredir_handle_status(dev, alt_setting_status->status, len);
usbredir_handle_status(dev, p, alt_setting_status->status);
usb_generic_async_ctrl_complete(&dev->dev, p);
}
}
@ -1522,18 +1529,18 @@ static void usbredir_control_packet(void *priv, uint64_t id,
p = usbredir_find_packet_by_id(dev, 0, id);
if (p) {
len = usbredir_handle_status(dev, control_packet->status, len);
if (len > 0) {
usbredir_handle_status(dev, p, control_packet->status);
if (data_len > 0) {
usbredir_log_data(dev, "ctrl data in:", data, data_len);
if (data_len <= sizeof(dev->dev.data_buf)) {
memcpy(dev->dev.data_buf, data, data_len);
} else {
if (data_len > sizeof(dev->dev.data_buf)) {
ERROR("ctrl buffer too small (%d > %zu)\n",
data_len, sizeof(dev->dev.data_buf));
len = USB_RET_STALL;
p->status = USB_RET_STALL;
data_len = len = sizeof(dev->dev.data_buf);
}
memcpy(dev->dev.data_buf, data, data_len);
}
p->result = len;
p->actual_length = len;
usb_generic_async_ctrl_complete(&dev->dev, p);
}
free(data);
@ -1554,23 +1561,23 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
p = usbredir_find_packet_by_id(dev, ep, id);
if (p) {
size_t size = (p->combined) ? p->combined->iov.size : p->iov.size;
len = usbredir_handle_status(dev, bulk_packet->status, len);
if (len > 0) {
usbredir_handle_status(dev, p, bulk_packet->status);
if (data_len > 0) {
usbredir_log_data(dev, "bulk data in:", data, data_len);
if (data_len <= size) {
if (p->combined) {
iov_from_buf(p->combined->iov.iov, p->combined->iov.niov,
0, data, data_len);
} else {
usb_packet_copy(p, data, data_len);
}
} else {
if (data_len > size) {
ERROR("bulk got more data then requested (%d > %zd)\n",
data_len, p->iov.size);
len = USB_RET_BABBLE;
p->status = USB_RET_BABBLE;
data_len = len = size;
}
if (p->combined) {
iov_from_buf(p->combined->iov.iov, p->combined->iov.niov,
0, data, data_len);
} else {
usb_packet_copy(p, data, data_len);
}
}
p->result = len;
p->actual_length = len;
if (p->pid == USB_TOKEN_IN && p->ep->pipeline) {
usb_combined_input_packet_complete(&dev->dev, p);
} else {
@ -1632,12 +1639,10 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
/* bufp_alloc also adds the packet to the ep queue */
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
} else {
int len = interrupt_packet->length;
USBPacket *p = usbredir_find_packet_by_id(dev, ep, id);
if (p) {
p->result = usbredir_handle_status(dev,
interrupt_packet->status, len);
usbredir_handle_status(dev, p, interrupt_packet->status);
p->actual_length = interrupt_packet->length;
usb_packet_complete(&dev->dev, p);
}
}

View File

@ -185,6 +185,21 @@ static void vfio_unmask_intx(VFIODevice *vdev)
ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
}
#ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */
static void vfio_mask_intx(VFIODevice *vdev)
{
struct vfio_irq_set irq_set = {
.argsz = sizeof(irq_set),
.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
.index = VFIO_PCI_INTX_IRQ_INDEX,
.start = 0,
.count = 1,
};
ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
}
#endif
/*
* Disabling BAR mmaping can be slow, but toggling it around INTx can
* also be a huge overhead. We try to get the best of both worlds by
@ -248,6 +263,161 @@ static void vfio_eoi(VFIODevice *vdev)
vfio_unmask_intx(vdev);
}
static void vfio_enable_intx_kvm(VFIODevice *vdev)
{
#ifdef CONFIG_KVM
struct kvm_irqfd irqfd = {
.fd = event_notifier_get_fd(&vdev->intx.interrupt),
.gsi = vdev->intx.route.irq,
.flags = KVM_IRQFD_FLAG_RESAMPLE,
};
struct vfio_irq_set *irq_set;
int ret, argsz;
int32_t *pfd;
if (!kvm_irqchip_in_kernel() ||
vdev->intx.route.mode != PCI_INTX_ENABLED ||
!kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) {
return;
}
/* Get to a known interrupt state */
qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev);
vfio_mask_intx(vdev);
vdev->intx.pending = false;
qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
/* Get an eventfd for resample/unmask */
if (event_notifier_init(&vdev->intx.unmask, 0)) {
error_report("vfio: Error: event_notifier_init failed eoi\n");
goto fail;
}
/* KVM triggers it, VFIO listens for it */
irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask);
if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
error_report("vfio: Error: Failed to setup resample irqfd: %m\n");
goto fail_irqfd;
}
argsz = sizeof(*irq_set) + sizeof(*pfd);
irq_set = g_malloc0(argsz);
irq_set->argsz = argsz;
irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK;
irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
irq_set->start = 0;
irq_set->count = 1;
pfd = (int32_t *)&irq_set->data;
*pfd = irqfd.resamplefd;
ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
if (ret) {
error_report("vfio: Error: Failed to setup INTx unmask fd: %m\n");
goto fail_vfio;
}
/* Let'em rip */
vfio_unmask_intx(vdev);
vdev->intx.kvm_accel = true;
DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel enabled\n",
__func__, vdev->host.domain, vdev->host.bus,
vdev->host.slot, vdev->host.function);
return;
fail_vfio:
irqfd.flags = KVM_IRQFD_FLAG_DEASSIGN;
kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd);
fail_irqfd:
event_notifier_cleanup(&vdev->intx.unmask);
fail:
qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
vfio_unmask_intx(vdev);
#endif
}
static void vfio_disable_intx_kvm(VFIODevice *vdev)
{
#ifdef CONFIG_KVM
struct kvm_irqfd irqfd = {
.fd = event_notifier_get_fd(&vdev->intx.interrupt),
.gsi = vdev->intx.route.irq,
.flags = KVM_IRQFD_FLAG_DEASSIGN,
};
if (!vdev->intx.kvm_accel) {
return;
}
/*
* Get to a known state, hardware masked, QEMU ready to accept new
* interrupts, QEMU IRQ de-asserted.
*/
vfio_mask_intx(vdev);
vdev->intx.pending = false;
qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
/* Tell KVM to stop listening for an INTx irqfd */
if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
error_report("vfio: Error: Failed to disable INTx irqfd: %m\n");
}
/* We only need to close the eventfd for VFIO to cleanup the kernel side */
event_notifier_cleanup(&vdev->intx.unmask);
/* QEMU starts listening for interrupt events. */
qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
vdev->intx.kvm_accel = false;
/* If we've missed an event, let it re-fire through QEMU */
vfio_unmask_intx(vdev);
DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n",
__func__, vdev->host.domain, vdev->host.bus,
vdev->host.slot, vdev->host.function);
#endif
}
static void vfio_update_irq(PCIDevice *pdev)
{
VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
PCIINTxRoute route;
if (vdev->interrupt != VFIO_INT_INTx) {
return;
}
route = pci_device_route_intx_to_irq(&vdev->pdev, vdev->intx.pin);
if (!pci_intx_route_changed(&vdev->intx.route, &route)) {
return; /* Nothing changed */
}
DPRINTF("%s(%04x:%02x:%02x.%x) IRQ moved %d -> %d\n", __func__,
vdev->host.domain, vdev->host.bus, vdev->host.slot,
vdev->host.function, vdev->intx.route.irq, route.irq);
vfio_disable_intx_kvm(vdev);
vdev->intx.route = route;
if (route.mode != PCI_INTX_ENABLED) {
return;
}
vfio_enable_intx_kvm(vdev);
/* Re-enable the interrupt in cased we missed an EOI */
vfio_eoi(vdev);
}
static int vfio_enable_intx(VFIODevice *vdev)
{
uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1);
@ -262,6 +432,18 @@ static int vfio_enable_intx(VFIODevice *vdev)
vfio_disable_interrupts(vdev);
vdev->intx.pin = pin - 1; /* Pin A (1) -> irq[0] */
#ifdef CONFIG_KVM
/*
* Only conditional to avoid generating error messages on platforms
* where we won't actually use the result anyway.
*/
if (kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) {
vdev->intx.route = pci_device_route_intx_to_irq(&vdev->pdev,
vdev->intx.pin);
}
#endif
ret = event_notifier_init(&vdev->intx.interrupt, 0);
if (ret) {
error_report("vfio: Error: event_notifier_init failed\n");
@ -290,6 +472,8 @@ static int vfio_enable_intx(VFIODevice *vdev)
return -errno;
}
vfio_enable_intx_kvm(vdev);
vdev->interrupt = VFIO_INT_INTx;
DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
@ -303,6 +487,7 @@ static void vfio_disable_intx(VFIODevice *vdev)
int fd;
qemu_del_timer(vdev->intx.mmap_timer);
vfio_disable_intx_kvm(vdev);
vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX);
vdev->intx.pending = false;
qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
@ -503,28 +688,6 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
vector->use = false;
}
/* TODO This should move to msi.c */
static MSIMessage msi_get_msg(PCIDevice *pdev, unsigned int vector)
{
uint16_t flags = pci_get_word(pdev->config + pdev->msi_cap + PCI_MSI_FLAGS);
bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
MSIMessage msg;
if (msi64bit) {
msg.address = pci_get_quad(pdev->config +
pdev->msi_cap + PCI_MSI_ADDRESS_LO);
} else {
msg.address = pci_get_long(pdev->config +
pdev->msi_cap + PCI_MSI_ADDRESS_LO);
}
msg.data = pci_get_word(pdev->config + pdev->msi_cap +
(msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32));
msg.data += vector;
return msg;
}
static void vfio_enable_msix(VFIODevice *vdev)
{
vfio_disable_interrupts(vdev);
@ -563,7 +726,7 @@ retry:
error_report("vfio: Error: event_notifier_init failed\n");
}
msg = msi_get_msg(&vdev->pdev, i);
msg = msi_get_message(&vdev->pdev, i);
/*
* Attempt to enable route through KVM irqchip,
@ -1839,6 +2002,7 @@ static int vfio_initfn(PCIDevice *pdev)
if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) {
vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock,
vfio_intx_mmap_enable, vdev);
pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_update_irq);
ret = vfio_enable_intx(vdev);
if (ret) {
goto out_teardown;

View File

@ -84,9 +84,10 @@ static void pci_vga_ioport_write(void *ptr, hwaddr addr,
uint64_t val, unsigned size)
{
PCIVGAState *d = ptr;
switch (size) {
case 1:
vga_ioport_write(&d->vga, addr, val);
vga_ioport_write(&d->vga, addr + 0x3c0, val);
break;
case 2:
/*
@ -94,8 +95,8 @@ static void pci_vga_ioport_write(void *ptr, hwaddr addr,
* indexed registers with a single word write because the
* index byte is updated first.
*/
vga_ioport_write(&d->vga, addr, val & 0xff);
vga_ioport_write(&d->vga, addr+1, (val >> 8) & 0xff);
vga_ioport_write(&d->vga, addr + 0x3c0, val & 0xff);
vga_ioport_write(&d->vga, addr + 0x3c1, (val >> 8) & 0xff);
break;
}
}

View File

@ -2321,9 +2321,8 @@ static const MemoryRegionPortio vbe_portio_list[] = {
{ 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
# ifdef TARGET_I386
{ 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
# else
{ 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
# endif
{ 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
PORTIO_END_OF_LIST(),
};

View File

@ -852,6 +852,41 @@ static void virtio_balloon_exit_pci(PCIDevice *pci_dev)
virtio_exit_pci(pci_dev);
}
static int virtio_rng_init_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
VirtIODevice *vdev;
if (proxy->rng.rng == NULL) {
proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
object_property_add_child(OBJECT(pci_dev),
"default-backend",
OBJECT(proxy->rng.default_backend),
NULL);
object_property_set_link(OBJECT(pci_dev),
OBJECT(proxy->rng.default_backend),
"rng", NULL);
}
vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng);
if (!vdev) {
return -1;
}
virtio_init_pci(proxy, vdev);
return 0;
}
static void virtio_rng_exit_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
virtio_pci_stop_ioeventfd(proxy);
virtio_rng_exit(proxy->vdev);
virtio_exit_pci(pci_dev);
}
static Property virtio_blk_properties[] = {
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf),
@ -982,6 +1017,50 @@ static TypeInfo virtio_balloon_info = {
.class_init = virtio_balloon_class_init,
};
static void virtio_rng_initfn(Object *obj)
{
PCIDevice *pci_dev = PCI_DEVICE(obj);
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
(Object **)&proxy->rng.rng, NULL);
}
static Property virtio_rng_properties[] = {
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
/* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If
you have an entropy source capable of generating more entropy than this
and you can pass it through via virtio-rng, then hats off to you. Until
then, this is unlimited for all practical purposes.
*/
DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX),
DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16),
DEFINE_PROP_END_OF_LIST(),
};
static void virtio_rng_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = virtio_rng_init_pci;
k->exit = virtio_rng_exit_pci;
k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
k->revision = VIRTIO_PCI_ABI_VERSION;
k->class_id = PCI_CLASS_OTHERS;
dc->reset = virtio_pci_reset;
dc->props = virtio_rng_properties;
}
static TypeInfo virtio_rng_info = {
.name = "virtio-rng-pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VirtIOPCIProxy),
.instance_init = virtio_rng_initfn,
.class_init = virtio_rng_class_init,
};
static int virtio_scsi_init_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
@ -1046,6 +1125,7 @@ static void virtio_pci_register_types(void)
type_register_static(&virtio_serial_info);
type_register_static(&virtio_balloon_info);
type_register_static(&virtio_scsi_info);
type_register_static(&virtio_rng_info);
}
type_init(virtio_pci_register_types)

View File

@ -17,6 +17,7 @@
#include "virtio-blk.h"
#include "virtio-net.h"
#include "virtio-rng.h"
#include "virtio-serial.h"
#include "virtio-scsi.h"
@ -46,6 +47,7 @@ typedef struct {
virtio_serial_conf serial;
virtio_net_conf net;
VirtIOSCSIConf scsi;
VirtIORNGConf rng;
bool ioeventfd_disabled;
bool ioeventfd_started;
VirtIOIRQFD *vector_irqfd;

258
hw/virtio-rng.c Normal file
View File

@ -0,0 +1,258 @@
/*
* A virtio device implementing a hardware random number generator.
*
* Copyright 2012 Red Hat, Inc.
* Copyright 2012 Amit Shah <amit.shah@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*/
#include "iov.h"
#include "qdev.h"
#include "virtio.h"
#include "virtio-rng.h"
#include "qemu/rng.h"
typedef struct VirtIORNG {
VirtIODevice vdev;
DeviceState *qdev;
/* Only one vq - guest puts buffer(s) on it when it needs entropy */
VirtQueue *vq;
VirtQueueElement elem;
/* Config data for the device -- currently only chardev */
VirtIORNGConf *conf;
/* Whether we've popped a vq element into 'elem' above */
bool popped;
RngBackend *rng;
/* We purposefully don't migrate this state. The quota will reset on the
* destination as a result. Rate limiting is host state, not guest state.
*/
QEMUTimer *rate_limit_timer;
int64_t quota_remaining;
} VirtIORNG;
static bool is_guest_ready(VirtIORNG *vrng)
{
if (virtio_queue_ready(vrng->vq)
&& (vrng->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
return true;
}
return false;
}
static size_t pop_an_elem(VirtIORNG *vrng)
{
size_t size;
if (!vrng->popped && !virtqueue_pop(vrng->vq, &vrng->elem)) {
return 0;
}
vrng->popped = true;
size = iov_size(vrng->elem.in_sg, vrng->elem.in_num);
return size;
}
static void virtio_rng_process(VirtIORNG *vrng);
/* Send data from a char device over to the guest */
static void chr_read(void *opaque, const void *buf, size_t size)
{
VirtIORNG *vrng = opaque;
size_t len;
int offset;
if (!is_guest_ready(vrng)) {
return;
}
vrng->quota_remaining -= size;
offset = 0;
while (offset < size) {
if (!pop_an_elem(vrng)) {
break;
}
len = iov_from_buf(vrng->elem.in_sg, vrng->elem.in_num,
0, buf + offset, size - offset);
offset += len;
virtqueue_push(vrng->vq, &vrng->elem, len);
vrng->popped = false;
}
virtio_notify(&vrng->vdev, vrng->vq);
/*
* Lastly, if we had multiple elems queued by the guest, and we
* didn't have enough data to fill them all, indicate we want more
* data.
*/
virtio_rng_process(vrng);
}
static void virtio_rng_process(VirtIORNG *vrng)
{
ssize_t size;
if (!is_guest_ready(vrng)) {
return;
}
size = pop_an_elem(vrng);
size = MIN(vrng->quota_remaining, size);
if (size > 0) {
rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
}
}
static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
virtio_rng_process(vrng);
}
static uint32_t get_features(VirtIODevice *vdev, uint32_t f)
{
return f;
}
static void virtio_rng_save(QEMUFile *f, void *opaque)
{
VirtIORNG *vrng = opaque;
virtio_save(&vrng->vdev, f);
qemu_put_byte(f, vrng->popped);
if (vrng->popped) {
int i;
qemu_put_be32(f, vrng->elem.index);
qemu_put_be32(f, vrng->elem.in_num);
for (i = 0; i < vrng->elem.in_num; i++) {
qemu_put_be64(f, vrng->elem.in_addr[i]);
}
qemu_put_be32(f, vrng->elem.out_num);
for (i = 0; i < vrng->elem.out_num; i++) {
qemu_put_be64(f, vrng->elem.out_addr[i]);
}
}
}
static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
{
VirtIORNG *vrng = opaque;
if (version_id != 1) {
return -EINVAL;
}
virtio_load(&vrng->vdev, f);
vrng->popped = qemu_get_byte(f);
if (vrng->popped) {
int i;
vrng->elem.index = qemu_get_be32(f);
vrng->elem.in_num = qemu_get_be32(f);
g_assert(vrng->elem.in_num < VIRTQUEUE_MAX_SIZE);
for (i = 0; i < vrng->elem.in_num; i++) {
vrng->elem.in_addr[i] = qemu_get_be64(f);
}
vrng->elem.out_num = qemu_get_be32(f);
g_assert(vrng->elem.out_num < VIRTQUEUE_MAX_SIZE);
for (i = 0; i < vrng->elem.out_num; i++) {
vrng->elem.out_addr[i] = qemu_get_be64(f);
}
virtqueue_map_sg(vrng->elem.in_sg, vrng->elem.in_addr,
vrng->elem.in_num, 1);
virtqueue_map_sg(vrng->elem.out_sg, vrng->elem.out_addr,
vrng->elem.out_num, 0);
}
/* We may have an element ready but couldn't process it due to a quota
limit. Make sure to try again after live migration when the quota may
have been reset.
*/
virtio_rng_process(vrng);
return 0;
}
static void check_rate_limit(void *opaque)
{
VirtIORNG *s = opaque;
s->quota_remaining = s->conf->max_bytes;
virtio_rng_process(s);
qemu_mod_timer(s->rate_limit_timer,
qemu_get_clock_ms(vm_clock) + s->conf->period_ms);
}
VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
{
VirtIORNG *vrng;
VirtIODevice *vdev;
Error *local_err = NULL;
vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0,
sizeof(VirtIORNG));
vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
vrng->rng = conf->rng;
if (vrng->rng == NULL) {
qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
return NULL;
}
rng_backend_open(vrng->rng, &local_err);
if (local_err) {
qerror_report_err(local_err);
error_free(local_err);
return NULL;
}
vrng->vq = virtio_add_queue(vdev, 8, handle_input);
vrng->vdev.get_features = get_features;
vrng->qdev = dev;
vrng->conf = conf;
vrng->popped = false;
vrng->quota_remaining = vrng->conf->max_bytes;
g_assert_cmpint(vrng->conf->max_bytes, <=, INT64_MAX);
vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock,
check_rate_limit, vrng);
qemu_mod_timer(vrng->rate_limit_timer,
qemu_get_clock_ms(vm_clock) + vrng->conf->period_ms);
register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
virtio_rng_load, vrng);
return vdev;
}
void virtio_rng_exit(VirtIODevice *vdev)
{
VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
unregister_savevm(vrng->qdev, "virtio-rng", vrng);
virtio_cleanup(vdev);
}

28
hw/virtio-rng.h Normal file
View File

@ -0,0 +1,28 @@
/*
* Virtio RNG Support
*
* Copyright Red Hat, Inc. 2012
* Copyright Amit Shah <amit.shah@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*/
#ifndef _QEMU_VIRTIO_RNG_H
#define _QEMU_VIRTIO_RNG_H
#include "qemu/rng.h"
#include "qemu/rng-random.h"
/* The Virtio ID for the virtio rng device */
#define VIRTIO_ID_RNG 4
struct VirtIORNGConf {
RngBackend *rng;
uint64_t max_bytes;
uint32_t period_ms;
RndRandom *default_backend;
};
#endif

View File

@ -204,7 +204,7 @@ static void virtio_scsi_bad_req(void)
static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg,
hwaddr *addr, int num)
{
memset(qsgl, 0, sizeof(*qsgl));
qemu_sglist_init(qsgl, num, &dma_context_memory);
while (num--) {
qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len);
}
@ -596,6 +596,10 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
VirtIOSCSIEvent *evt;
int in_size;
if (!(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
return;
}
if (!req) {
s->events_dropped = true;
return;
@ -648,7 +652,6 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
if (((s->vdev.guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) &&
(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) &&
dev->type != TYPE_ROM) {
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
sense.asc | (sense.ascq << 8));
@ -659,8 +662,7 @@ static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev)
{
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
if (((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) &&
(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
if ((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_RESCAN);
}

View File

@ -203,6 +203,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
VirtIODevice *virtio_balloon_init(DeviceState *dev);
typedef struct VirtIOSCSIConf VirtIOSCSIConf;
VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
typedef struct VirtIORNGConf VirtIORNGConf;
VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf);
#ifdef CONFIG_LINUX
VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
#endif
@ -213,6 +215,7 @@ void virtio_blk_exit(VirtIODevice *vdev);
void virtio_serial_exit(VirtIODevice *vdev);
void virtio_balloon_exit(VirtIODevice *vdev);
void virtio_scsi_exit(VirtIODevice *vdev);
void virtio_rng_exit(VirtIODevice *vdev);
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
DEFINE_PROP_BIT("indirect_desc", _state, _field, \

View File

@ -946,6 +946,22 @@ void object_property_add_str(Object *obj, const char *name,
void (*set)(Object *, const char *, struct Error **),
struct Error **errp);
/**
* object_property_add_bool:
* @obj: the object to add a property to
* @name: the name of the property
* @get: the getter or NULL if the property is write-only.
* @set: the setter or NULL if the property is read-only
* @errp: if an error occurs, a pointer to an area to store the error
*
* Add a bool property using getters/setters. This function will add a
* property of type 'bool'.
*/
void object_property_add_bool(Object *obj, const char *name,
bool (*get)(Object *, struct Error **),
void (*set)(Object *, bool, struct Error **),
struct Error **errp);
/**
* object_child_foreach:
* @obj: the object whose children will be navigated

22
include/qemu/rng-random.h Normal file
View File

@ -0,0 +1,22 @@
/*
* QEMU Random Number Generator Backend
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_RNG_RANDOM_H
#define QEMU_RNG_RANDOM_H
#include "qemu/object.h"
#define TYPE_RNG_RANDOM "rng-random"
#define RNG_RANDOM(obj) OBJECT_CHECK(RndRandom, (obj), TYPE_RNG_RANDOM)
typedef struct RndRandom RndRandom;
#endif

93
include/qemu/rng.h Normal file
View File

@ -0,0 +1,93 @@
/*
* QEMU Random Number Generator Backend
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_RNG_H
#define QEMU_RNG_H
#include "qemu/object.h"
#include "qemu-common.h"
#include "error.h"
#define TYPE_RNG_BACKEND "rng-backend"
#define RNG_BACKEND(obj) \
OBJECT_CHECK(RngBackend, (obj), TYPE_RNG_BACKEND)
#define RNG_BACKEND_GET_CLASS(obj) \
OBJECT_GET_CLASS(RngBackendClass, (obj), TYPE_RNG_BACKEND)
#define RNG_BACKEND_CLASS(klass) \
OBJECT_CLASS_CHECK(RngBackendClass, (klass), TYPE_RNG_BACKEND)
typedef struct RngBackendClass RngBackendClass;
typedef struct RngBackend RngBackend;
typedef void (EntropyReceiveFunc)(void *opaque,
const void *data,
size_t size);
struct RngBackendClass
{
ObjectClass parent_class;
void (*request_entropy)(RngBackend *s, size_t size,
EntropyReceiveFunc *recieve_entropy, void *opaque);
void (*cancel_requests)(RngBackend *s);
void (*opened)(RngBackend *s, Error **errp);
};
struct RngBackend
{
Object parent;
/*< protected >*/
bool opened;
};
/**
* rng_backend_request_entropy:
* @s: the backend to request entropy from
* @size: the number of bytes of data to request
* @receive_entropy: a function to be invoked when entropy is available
* @opaque: data that should be passed to @receive_entropy
*
* This function is used by the front-end to request entropy from an entropy
* source. This function can be called multiple times before @receive_entropy
* is invoked with different values of @receive_entropy and @opaque. The
* backend will queue each request and handle appropriate.
*
* The backend does not need to pass the full amount of data to @receive_entropy
* but will pass at a value greater than 0.
*/
void rng_backend_request_entropy(RngBackend *s, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque);
/**
* rng_backend_cancel_requests:
* @s: the backend to cancel all pending requests in
*
* Cancels all pending requests submitted by @rng_backend_request_entropy. This
* should be used by a device during reset or in preparation for live migration
* to stop tracking any request.
*/
void rng_backend_cancel_requests(RngBackend *s);
/**
* rng_backend_open:
* @s: the backend to open
* @errp: a pointer to return the #Error object if an error occurs.
*
* This function will open the backend if it is not already open. Calling this
* function on an already opened backend will not result in an error.
*/
void rng_backend_open(RngBackend *s, Error **errp);
#endif

View File

@ -17,8 +17,8 @@
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
#ifndef __POWERPC_KVM_PARA_H__
#define __POWERPC_KVM_PARA_H__
#ifndef _UAPI__POWERPC_KVM_PARA_H__
#define _UAPI__POWERPC_KVM_PARA_H__
#include <linux/types.h>
@ -87,4 +87,4 @@ struct kvm_vcpu_arch_shared {
#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
#endif /* __POWERPC_KVM_PARA_H__ */
#endif /* _UAPI__POWERPC_KVM_PARA_H__ */

View File

@ -1,5 +1,5 @@
/*
* definition for paravirtual devices on s390
* User API definitions for paravirtual devices on s390
*
* Copyright IBM Corp. 2008
*
@ -9,9 +9,3 @@
*
* Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
*/
#ifndef __S390_KVM_PARA_H
#define __S390_KVM_PARA_H
#endif /* __S390_KVM_PARA_H */

View File

@ -9,6 +9,22 @@
#include <linux/types.h>
#include <linux/ioctl.h>
#define DE_VECTOR 0
#define DB_VECTOR 1
#define BP_VECTOR 3
#define OF_VECTOR 4
#define BR_VECTOR 5
#define UD_VECTOR 6
#define NM_VECTOR 7
#define DF_VECTOR 8
#define TS_VECTOR 10
#define NP_VECTOR 11
#define SS_VECTOR 12
#define GP_VECTOR 13
#define PF_VECTOR 14
#define MF_VECTOR 16
#define MC_VECTOR 18
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_PIT
#define __KVM_HAVE_IOAPIC
@ -25,6 +41,7 @@
#define __KVM_HAVE_DEBUGREGS
#define __KVM_HAVE_XSAVE
#define __KVM_HAVE_XCRS
#define __KVM_HAVE_READONLY_MEM
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256

View File

@ -101,9 +101,13 @@ struct kvm_userspace_memory_region {
__u64 userspace_addr; /* start of the userspace allocated memory */
};
/* for kvm_memory_region::flags */
#define KVM_MEM_LOG_DIRTY_PAGES 1UL
#define KVM_MEMSLOT_INVALID (1UL << 1)
/*
* The bit 0 ~ bit 15 of kvm_memory_region::flags are visible for userspace,
* other bits are reserved for kvm internal use which are defined in
* include/linux/kvm_host.h.
*/
#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0)
#define KVM_MEM_READONLY (1UL << 1)
/* for KVM_IRQ_LINE */
struct kvm_irq_level {
@ -618,6 +622,10 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_PPC_GET_SMMU_INFO 78
#define KVM_CAP_S390_COW 79
#define KVM_CAP_PPC_ALLOC_HTAB 80
#ifdef __KVM_HAVE_READONLY_MEM
#define KVM_CAP_READONLY_MEM 81
#endif
#define KVM_CAP_IRQFD_RESAMPLE 82
#ifdef KVM_CAP_IRQ_ROUTING
@ -683,12 +691,21 @@ struct kvm_xen_hvm_config {
#endif
#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
/*
* Available with KVM_CAP_IRQFD_RESAMPLE
*
* KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies
* the irqfd to operate in resampling mode for level triggered interrupt
* emlation. See Documentation/virtual/kvm/api.txt.
*/
#define KVM_IRQFD_FLAG_RESAMPLE (1 << 1)
struct kvm_irqfd {
__u32 fd;
__u32 gsi;
__u32 flags;
__u8 pad[20];
__u32 resamplefd;
__u8 pad[16];
};
struct kvm_clock_data {

View File

@ -1,5 +1,5 @@
#ifndef __LINUX_KVM_PARA_H
#define __LINUX_KVM_PARA_H
#ifndef _UAPI__LINUX_KVM_PARA_H
#define _UAPI__LINUX_KVM_PARA_H
/*
* This header file provides a method for making a hypercall to the host
@ -25,4 +25,4 @@
*/
#include <asm/kvm_para.h>
#endif /* __LINUX_KVM_PARA_H */
#endif /* _UAPI__LINUX_KVM_PARA_H */

View File

@ -8,8 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef VFIO_H
#define VFIO_H
#ifndef _UAPIVFIO_H
#define _UAPIVFIO_H
#include <linux/types.h>
#include <linux/ioctl.h>
@ -365,4 +365,4 @@ struct vfio_iommu_type1_dma_unmap {
#define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
#endif /* VFIO_H */
#endif /* _UAPIVFIO_H */

View File

@ -1,5 +1,5 @@
#ifndef _LINUX_VIRTIO_CONFIG_H
#define _LINUX_VIRTIO_CONFIG_H
#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H
#define _UAPI_LINUX_VIRTIO_CONFIG_H
/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
* anyone can use the definitions to implement compatible drivers/servers.
*
@ -51,4 +51,4 @@
* suppressed them? */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
#endif /* _LINUX_VIRTIO_CONFIG_H */
#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */

View File

@ -1,5 +1,5 @@
#ifndef _LINUX_VIRTIO_RING_H
#define _LINUX_VIRTIO_RING_H
#ifndef _UAPI_LINUX_VIRTIO_RING_H
#define _UAPI_LINUX_VIRTIO_RING_H
/* An interface for efficient virtio implementation, currently for use by KVM
* and lguest, but hopefully others soon. Do NOT change this since it will
* break existing servers and clients.
@ -160,4 +160,4 @@ static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old
return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
}
#endif /* _LINUX_VIRTIO_RING_H */
#endif /* _UAPI_LINUX_VIRTIO_RING_H */

23
nbd.c
View File

@ -596,24 +596,23 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
return -serrno;
}
if (flags & NBD_FLAG_READ_ONLY) {
int read_only = 1;
TRACE("Setting readonly attribute");
if (ioctl(fd, NBD_SET_FLAGS, flags) < 0) {
if (errno == ENOTTY) {
int read_only = (flags & NBD_FLAG_READ_ONLY) != 0;
TRACE("Setting readonly attribute");
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
int serrno = errno;
LOG("Failed setting read-only attribute");
return -serrno;
}
} else {
int serrno = errno;
LOG("Failed setting read-only attribute");
LOG("Failed setting flags");
return -serrno;
}
}
if (ioctl(fd, NBD_SET_FLAGS, flags) < 0
&& errno != ENOTTY) {
int serrno = errno;
LOG("Failed setting flags");
return -serrno;
}
TRACE("Negotiation ended");
return 0;

32
osdep.c
View File

@ -54,38 +54,6 @@ static bool fips_enabled = false;
static const char *qemu_version = QEMU_VERSION;
static int default_fdset_get_fd(int64_t fdset_id, int flags)
{
return -1;
}
QEMU_WEAK_ALIAS(monitor_fdset_get_fd, default_fdset_get_fd);
#define monitor_fdset_get_fd \
QEMU_WEAK_REF(monitor_fdset_get_fd, default_fdset_get_fd)
static int default_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
{
return -1;
}
QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add);
#define monitor_fdset_dup_fd_add \
QEMU_WEAK_REF(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add)
static int default_fdset_dup_fd_remove(int dup_fd)
{
return -1;
}
QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove);
#define monitor_fdset_dup_fd_remove \
QEMU_WEAK_REF(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove)
static int default_fdset_dup_fd_find(int dup_fd)
{
return -1;
}
QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_find, default_fdset_dup_fd_find);
#define monitor_fdset_dup_fd_find \
QEMU_WEAK_REF(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_find)
int socket_set_cork(int fd, int v)
{
#if defined(SOL_TCP) && defined(TCP_CORK)

View File

@ -32,13 +32,6 @@
#include "trace.h"
#include "qemu_socket.h"
static void default_qemu_fd_register(int fd)
{
}
QEMU_WEAK_ALIAS(qemu_fd_register, default_qemu_fd_register);
#define qemu_fd_register \
QEMU_WEAK_REF(qemu_fd_register, default_qemu_fd_register)
void *qemu_oom_check(void *ptr)
{
if (ptr == NULL) {

215
pflib.c
View File

@ -1,215 +0,0 @@
/*
* PixelFormat conversion library.
*
* Author: Gerd Hoffmann <kraxel@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu-common.h"
#include "console.h"
#include "pflib.h"
typedef struct QemuPixel QemuPixel;
typedef void (*pf_convert)(QemuPfConv *conv,
void *dst, void *src, uint32_t cnt);
typedef void (*pf_convert_from)(PixelFormat *pf,
QemuPixel *dst, void *src, uint32_t cnt);
typedef void (*pf_convert_to)(PixelFormat *pf,
void *dst, QemuPixel *src, uint32_t cnt);
struct QemuPfConv {
pf_convert convert;
PixelFormat src;
PixelFormat dst;
/* for copy_generic() */
pf_convert_from conv_from;
pf_convert_to conv_to;
QemuPixel *conv_buf;
uint32_t conv_cnt;
};
struct QemuPixel {
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
};
/* ----------------------------------------------------------------------- */
/* PixelFormat -> QemuPixel conversions */
static void conv_16_to_pixel(PixelFormat *pf,
QemuPixel *dst, void *src, uint32_t cnt)
{
uint16_t *src16 = src;
while (cnt > 0) {
dst->red = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
dst->blue = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits);
dst++, src16++, cnt--;
}
}
/* assumes pf->{r,g,b,a}bits == 8 */
static void conv_32_to_pixel_fast(PixelFormat *pf,
QemuPixel *dst, void *src, uint32_t cnt)
{
uint32_t *src32 = src;
while (cnt > 0) {
dst->red = (*src32 & pf->rmask) >> pf->rshift;
dst->green = (*src32 & pf->gmask) >> pf->gshift;
dst->blue = (*src32 & pf->bmask) >> pf->bshift;
dst->alpha = (*src32 & pf->amask) >> pf->ashift;
dst++, src32++, cnt--;
}
}
static void conv_32_to_pixel_generic(PixelFormat *pf,
QemuPixel *dst, void *src, uint32_t cnt)
{
uint32_t *src32 = src;
while (cnt > 0) {
if (pf->rbits < 8) {
dst->red = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
} else {
dst->red = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8);
}
if (pf->gbits < 8) {
dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
} else {
dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8);
}
if (pf->bbits < 8) {
dst->blue = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
} else {
dst->blue = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8);
}
if (pf->abits < 8) {
dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits);
} else {
dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8);
}
dst++, src32++, cnt--;
}
}
/* ----------------------------------------------------------------------- */
/* QemuPixel -> PixelFormat conversions */
static void conv_pixel_to_16(PixelFormat *pf,
void *dst, QemuPixel *src, uint32_t cnt)
{
uint16_t *dst16 = dst;
while (cnt > 0) {
*dst16 = ((uint16_t)src->red >> (8 - pf->rbits)) << pf->rshift;
*dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift;
*dst16 |= ((uint16_t)src->blue >> (8 - pf->bbits)) << pf->bshift;
*dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
dst16++, src++, cnt--;
}
}
static void conv_pixel_to_32(PixelFormat *pf,
void *dst, QemuPixel *src, uint32_t cnt)
{
uint32_t *dst32 = dst;
while (cnt > 0) {
*dst32 = ((uint32_t)src->red >> (8 - pf->rbits)) << pf->rshift;
*dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift;
*dst32 |= ((uint32_t)src->blue >> (8 - pf->bbits)) << pf->bshift;
*dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
dst32++, src++, cnt--;
}
}
/* ----------------------------------------------------------------------- */
/* PixelFormat -> PixelFormat conversions */
static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
{
uint32_t bytes = cnt * conv->src.bytes_per_pixel;
memcpy(dst, src, bytes);
}
static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
{
if (conv->conv_cnt < cnt) {
conv->conv_cnt = cnt;
conv->conv_buf = g_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt);
}
conv->conv_from(&conv->src, conv->conv_buf, src, cnt);
conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt);
}
/* ----------------------------------------------------------------------- */
/* public interface */
QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src)
{
QemuPfConv *conv = g_malloc0(sizeof(QemuPfConv));
conv->src = *src;
conv->dst = *dst;
if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) {
/* formats identical, can simply copy */
conv->convert = convert_copy;
} else {
/* generic two-step conversion: src -> QemuPixel -> dst */
switch (conv->src.bytes_per_pixel) {
case 2:
conv->conv_from = conv_16_to_pixel;
break;
case 4:
if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) {
conv->conv_from = conv_32_to_pixel_fast;
} else {
conv->conv_from = conv_32_to_pixel_generic;
}
break;
default:
goto err;
}
switch (conv->dst.bytes_per_pixel) {
case 2:
conv->conv_to = conv_pixel_to_16;
break;
case 4:
conv->conv_to = conv_pixel_to_32;
break;
default:
goto err;
}
conv->convert = convert_generic;
}
return conv;
err:
g_free(conv);
return NULL;
}
void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
{
conv->convert(conv, dst, src, cnt);
}
void qemu_pf_conv_put(QemuPfConv *conv)
{
if (conv) {
g_free(conv->conv_buf);
g_free(conv);
}
}

20
pflib.h
View File

@ -1,20 +0,0 @@
#ifndef __QEMU_PFLIB_H
#define __QEMU_PFLIB_H
/*
* PixelFormat conversion library.
*
* Author: Gerd Hoffmann <kraxel@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
typedef struct QemuPfConv QemuPfConv;
QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src);
void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt);
void qemu_pf_conv_put(QemuPfConv *conv);
#endif

View File

@ -686,6 +686,15 @@ static QemuOptsList qemu_add_fd_opts = {
},
};
static QemuOptsList qemu_object_opts = {
.name = "object",
.implied_opt_name = "qom-type",
.head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
.desc = {
{ }
},
};
static QemuOptsList *vm_config_groups[32] = {
&qemu_drive_opts,
&qemu_chardev_opts,
@ -703,6 +712,7 @@ static QemuOptsList *vm_config_groups[32] = {
&qemu_iscsi_opts,
&qemu_sandbox_opts,
&qemu_add_fd_opts,
&qemu_object_opts,
NULL,
};

View File

@ -610,14 +610,14 @@ QEMU can access directly to block device exported using the Network Block Device
protocol.
@example
qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
qemu-system-i386 linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/
@end example
If the NBD server is located on the same host, you can use an unix socket instead
of an inet socket:
@example
qemu-system-i386 linux.img -hdb nbd:unix:/tmp/my_socket
qemu-system-i386 linux.img -hdb nbd+unix://?socket=/tmp/my_socket
@end example
In this case, the block device must be exported using qemu-nbd:
@ -631,17 +631,26 @@ The use of qemu-nbd allows to share a disk between several guests:
qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
@end example
@noindent
and then you can use it with two guests:
@example
qemu-system-i386 linux1.img -hdb nbd:unix:/tmp/my_socket
qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket
qemu-system-i386 linux1.img -hdb nbd+unix://?socket=/tmp/my_socket
qemu-system-i386 linux2.img -hdb nbd+unix://?socket=/tmp/my_socket
@end example
If the nbd-server uses named exports (since NBD 2.9.18), you must use the
"exportname" option:
If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's
own embedded NBD server), you must specify an export name in the URI:
@example
qemu-system-i386 -cdrom nbd:localhost:exportname=debian-500-ppc-netinst
qemu-system-i386 -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst
qemu-system-i386 -cdrom nbd://localhost/debian-500-ppc-netinst
qemu-system-i386 -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst
@end example
The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is
also available. Here are some example of the older syntax:
@example
qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket
qemu-system-i386 -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst
@end example
@node disk_images_sheepdog

View File

@ -539,6 +539,7 @@ int main(int argc, char **argv)
snprintf(sockpath, 128, SOCKET_PATH, basename(device));
}
qemu_init_main_loop();
bdrv_init();
atexit(bdrv_close_all);
@ -584,7 +585,6 @@ int main(int argc, char **argv)
memset(&client_thread, 0, sizeof(client_thread));
}
qemu_init_main_loop();
qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL,
(void *)(uintptr_t)fd);

View File

@ -2904,6 +2904,14 @@ DEF("no-kvm-irqchip", HAS_ARG, QEMU_OPTION_no_kvm_irqchip, "", QEMU_ARCH_I386)
HXCOMM Deprecated (ignored)
DEF("tdf", 0, QEMU_OPTION_tdf,"", QEMU_ARCH_ALL)
DEF("object", HAS_ARG, QEMU_OPTION_object,
"-object TYPENAME[,PROP1=VALUE1,...]\n"
" create an new object of type TYPENAME setting properties\n"
" in the order they are specified. Note that the 'id'\n"
" property must be set. These objects are placed in the\n"
" '/objects' path.\n",
QEMU_ARCH_ALL)
HXCOMM This is the last statement. Insert new options before this line!
STEXI
@end table

View File

@ -1,3 +1,8 @@
/*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu-pixman.h"
int qemu_pixman_get_type(int rshift, int gshift, int bshift)
@ -51,6 +56,19 @@ void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
0, y, 0, 0, 0, 0, width, 1);
}
pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format,
pixman_image_t *image)
{
pixman_image_t *mirror;
mirror = pixman_image_create_bits(format,
pixman_image_get_width(image),
pixman_image_get_height(image),
NULL,
pixman_image_get_stride(image));
return mirror;
}
void qemu_pixman_image_unref(pixman_image_t *image)
{
if (image == NULL) {

View File

@ -1,3 +1,8 @@
/*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_PIXMAN_H
#define QEMU_PIXMAN_H
@ -27,6 +32,8 @@ pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
int width);
void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
int width, int y);
pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format,
pixman_image_t *image);
void qemu_pixman_image_unref(pixman_image_t *image);
#endif /* QEMU_PIXMAN_H */

View File

@ -61,28 +61,6 @@ static QemuOptsList dummy_opts = {
},
};
static int default_monitor_get_fd(Monitor *mon, const char *name, Error **errp)
{
error_setg(errp, "only QEMU supports file descriptor passing");
return -1;
}
QEMU_WEAK_ALIAS(monitor_get_fd, default_monitor_get_fd);
#define monitor_get_fd \
QEMU_WEAK_REF(monitor_get_fd, default_monitor_get_fd)
static int default_qemu_set_fd_handler2(int fd,
IOCanReadHandler *fd_read_poll,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque)
{
abort();
}
QEMU_WEAK_ALIAS(qemu_set_fd_handler2, default_qemu_set_fd_handler2);
#define qemu_set_fd_handler2 \
QEMU_WEAK_REF(qemu_set_fd_handler2, default_qemu_set_fd_handler2)
static int inet_getport(struct addrinfo *e)
{
struct sockaddr_in *i4;

9
qmp.c
View File

@ -471,15 +471,6 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
return prop_list;
}
static CpuDefinitionInfoList *default_arch_query_cpu_definitions(Error **errp)
{
error_set(errp, QERR_NOT_SUPPORTED);
return NULL;
}
QEMU_WEAK_ALIAS(arch_query_cpu_definitions, default_arch_query_cpu_definitions);
#define arch_query_cpu_definitions \
QEMU_WEAK_REF(arch_query_cpu_definitions, default_arch_query_cpu_definitions)
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
{
return arch_query_cpu_definitions(errp);

View File

@ -1183,6 +1183,62 @@ void object_property_add_str(Object *obj, const char *name,
prop, errp);
}
typedef struct BoolProperty
{
bool (*get)(Object *, Error **);
void (*set)(Object *, bool, Error **);
} BoolProperty;
static void property_get_bool(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
BoolProperty *prop = opaque;
bool value;
value = prop->get(obj, errp);
visit_type_bool(v, &value, name, errp);
}
static void property_set_bool(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
BoolProperty *prop = opaque;
bool value;
Error *local_err = NULL;
visit_type_bool(v, &value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
prop->set(obj, value, errp);
}
static void property_release_bool(Object *obj, const char *name,
void *opaque)
{
BoolProperty *prop = opaque;
g_free(prop);
}
void object_property_add_bool(Object *obj, const char *name,
bool (*get)(Object *, Error **),
void (*set)(Object *, bool, Error **),
Error **errp)
{
BoolProperty *prop = g_malloc0(sizeof(*prop));
prop->get = get;
prop->set = set;
object_property_add(obj, name, "bool",
get ? property_get_bool : NULL,
set ? property_set_bool : NULL,
property_release_bool,
prop, errp);
}
static char *qdev_get_type(Object *obj, Error **errp)
{
return g_strdup(object_get_typename(obj));

View File

@ -31,7 +31,7 @@ endif
%.o: %.m
$(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@")
LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(sort $(1)) $(LIBS)," LINK $(TARGET_DIR)$@")
LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(LIBS)," LINK $(TARGET_DIR)$@")
%$(EXESUF): %.o
$(call LINK,$^)

8
stubs/Makefile.objs Normal file
View File

@ -0,0 +1,8 @@
stub-obj-y += arch-query-cpu-def.o
stub-obj-y += fdset-add-fd.o
stub-obj-y += fdset-find-fd.o
stub-obj-y += fdset-get-fd.o
stub-obj-y += fdset-remove-fd.o
stub-obj-y += get-fd.o
stub-obj-y += set-fd-handler.o
stub-obj-$(CONFIG_WIN32) += fd-register.o

View File

@ -0,0 +1,9 @@
#include "qemu-common.h"
#include "arch_init.h"
#include "qerror.h"
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
{
error_set(errp, QERR_NOT_SUPPORTED);
return NULL;
}

6
stubs/fd-register.c Normal file
View File

@ -0,0 +1,6 @@
#include "qemu-common.h"
#include "main-loop.h"
void qemu_fd_register(int fd)
{
}

7
stubs/fdset-add-fd.c Normal file
View File

@ -0,0 +1,7 @@
#include "qemu-common.h"
#include "monitor.h"
int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
{
return -1;
}

7
stubs/fdset-find-fd.c Normal file
View File

@ -0,0 +1,7 @@
#include "qemu-common.h"
#include "monitor.h"
int monitor_fdset_dup_fd_find(int dup_fd)
{
return -1;
}

7
stubs/fdset-get-fd.c Normal file
View File

@ -0,0 +1,7 @@
#include "qemu-common.h"
#include "monitor.h"
int monitor_fdset_get_fd(int64_t fdset_id, int flags)
{
return -1;
}

7
stubs/fdset-remove-fd.c Normal file
View File

@ -0,0 +1,7 @@
#include "qemu-common.h"
#include "monitor.h"
int monitor_fdset_dup_fd_remove(int dupfd)
{
return -1;
}

8
stubs/get-fd.c Normal file
View File

@ -0,0 +1,8 @@
#include "qemu-common.h"
#include "monitor.h"
int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
{
error_setg(errp, "only QEMU supports file descriptor passing");
return -1;
}

11
stubs/set-fd-handler.c Normal file
View File

@ -0,0 +1,11 @@
#include "qemu-common.h"
#include "main-loop.h"
int qemu_set_fd_handler2(int fd,
IOCanReadHandler *fd_read_poll,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque)
{
abort();
}

Some files were not shown because too many files have changed in this diff Show More