Merge branch 'eflags3' of git://github.com/rth7680/qemu
authorBlue Swirl <blauwirbel@gmail.com>
Sat, 23 Feb 2013 17:21:41 +0000 (17:21 +0000)
committerBlue Swirl <blauwirbel@gmail.com>
Sat, 23 Feb 2013 17:21:41 +0000 (17:21 +0000)
* 'eflags3' of git://github.com/rth7680/qemu: (61 commits)
  target-i386: Use movcond to implement shiftd.
  target-i386: Discard CC_OP computation in set_cc_op also
  target-i386: Use movcond to implement rotate flags.
  target-i386: Use movcond to implement shift flags.
  target-i386: Add CC_OP_CLR
  target-i386: Implement tzcnt and fix lzcnt
  target-i386: Use clz/ctz for bsf/bsr helpers
  target-i386: Implement ADX extension
  target-i386: Implement RORX
  target-i386: Implement SHLX, SARX, SHRX
  target-i386: Implement PDEP, PEXT
  target-i386: Implement MULX
  target-i386: Implement BZHI
  target-i386: Implement BLSR, BLSMSK, BLSI
  target-i386: Implement BEXTR
  target-i386: Implement ANDN
  target-i386: Implement MOVBE
  target-i386: Decode the VEX prefixes
  target-i386: Tidy prefix parsing
  target-i386: Use CC_SRC2 for ADC and SBB
  ...

101 files changed:
.gitignore
Makefile
TODO [deleted file]
aio-posix.c
async.c
configure
coroutine-sigaltstack.c
coroutine-ucontext.c
cpu-exec.c
default-configs/alpha-softmmu.mak
default-configs/arm-softmmu.mak
default-configs/i386-softmmu.mak
default-configs/m68k-softmmu.mak
default-configs/mips-softmmu.mak
default-configs/mips64-softmmu.mak
default-configs/mips64el-softmmu.mak
default-configs/mipsel-softmmu.mak
default-configs/ppc-softmmu.mak
default-configs/ppc64-softmmu.mak
default-configs/ppcemb-softmmu.mak
default-configs/sh4-softmmu.mak
default-configs/sh4eb-softmmu.mak
default-configs/sparc64-softmmu.mak
default-configs/usb.mak [new file with mode: 0644]
default-configs/x86_64-softmmu.mak
disas/i386.c
disas/m68k.c
hw/Makefile.objs
hw/grlib_apbuart.c
hw/ppc4xx_devs.c
hw/qxl-render.c
hw/usb.h
hw/usb/Makefile.objs
hw/usb/core.c
hw/usb/desc.c
hw/usb/dev-bluetooth.c
hw/usb/dev-hid.c
hw/usb/dev-hub.c
hw/usb/dev-network.c
hw/usb/dev-smartcard-reader.c
hw/usb/dev-storage.c
hw/usb/dev-uas.c
hw/usb/dev-wacom.c
hw/usb/hcd-ehci.c
hw/usb/hcd-musb.c
hw/usb/hcd-ohci.c
hw/usb/hcd-uhci.c
hw/usb/hcd-xhci.c
hw/usb/host-bsd.c
hw/usb/host-legacy.c [new file with mode: 0644]
hw/usb/host-linux.c
hw/usb/host-stub.c
hw/usb/host.h [new file with mode: 0644]
hw/usb/redirect.c
hw/vga.c
hw/vmware_vga.c
hw/xenfb.c
hw/xilinx_axienet.c
include/block/aio.h
include/exec/cpu-defs.h
include/qemu/log.h
include/qemu/main-loop.h
include/sysemu/os-win32.h
include/sysemu/sysemu.h
include/ui/console.h
iohandler.c
main-loop.c
monitor.c
po/Makefile [new file with mode: 0644]
po/de_DE.po [new file with mode: 0644]
po/it.po [new file with mode: 0644]
po/messages.po [new file with mode: 0644]
qapi-schema.json
qemu-char.c
qemu-options.hx
qom/object.c
scripts/make_device_config.sh
slirp/libslirp.h
slirp/main.h
slirp/slirp.c
slirp/socket.c
slirp/socket.h
stubs/slirp.c
target-cris/translate.c
target-lm32/translate.c
target-microblaze/translate.c
target-openrisc/translate.c
target-sparc/cpu.c
target-sparc/cpu.h
target-sparc/helper.c
target-sparc/helper.h
target-sparc/ldst_helper.c
target-sparc/translate.c
tests/.gitignore
tests/rtc-test.c
trace-events
ui/Makefile.objs
ui/console.c
ui/gtk.c [new file with mode: 0644]
user-exec.c
vl.c

index 53fe9c30787ddee1a038657d51365bbfb813dddd..27ad002970dc980a75e032ef024a97bcd1ff9529 100644 (file)
@@ -83,12 +83,15 @@ fsdev/virtfs-proxy-helper.pod
 patches
 pc-bios/bios-pq/status
 pc-bios/vgabios-pq/status
+pc-bios/optionrom/linuxboot.asm
 pc-bios/optionrom/linuxboot.bin
 pc-bios/optionrom/linuxboot.raw
 pc-bios/optionrom/linuxboot.img
+pc-bios/optionrom/multiboot.asm
 pc-bios/optionrom/multiboot.bin
 pc-bios/optionrom/multiboot.raw
 pc-bios/optionrom/multiboot.img
+pc-bios/optionrom/kvmvapic.asm
 pc-bios/optionrom/kvmvapic.bin
 pc-bios/optionrom/kvmvapic.raw
 pc-bios/optionrom/kvmvapic.img
index 0d9099a47306d174479dc738d3fe1f584cb245ae..2262410f0fe42915b0c0402b166e3a95b137497b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -313,6 +313,9 @@ ifneq ($(BLOBS),)
        set -e; for x in $(BLOBS); do \
                $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
        done
+endif
+ifeq ($(CONFIG_GTK),y)
+       $(MAKE) -C po $@
 endif
        $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
        set -e; for x in $(KEYMAPS); do \
diff --git a/TODO b/TODO
deleted file mode 100644 (file)
index 1d4c638..0000000
--- a/TODO
+++ /dev/null
@@ -1,37 +0,0 @@
-General:
--------
-- cycle counter for all archs
-- cpu_interrupt() win32/SMP fix
-- merge PIC spurious interrupt patch
-- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
-- config file (at least for windows/Mac OS X)
-- update doc: PCI infos.
-- basic VGA optimizations
-- better code fetch
-- do not resize vga if invalid size.
-- TLB code protection support for PPC
-- disable SMC handling for ARM/SPARC/PPC (not finished)
-- see undefined flags for BTx insn
-- keyboard output buffer filling timing emulation
-- tests for each target CPU
-- fix all remaining thread lock issues (must put TBs in a specific invalid
-  state, find a solution for tb_flush()).
-
-ppc specific:
-------------
-- TLB invalidate not needed if msr_pr changes
-- enable shift optimizations ?
-
-linux-user specific:
--------------------
-- remove threading support as it cannot work at this point
-- improve IPC syscalls
-- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
-  issues, fix 16 bit uid issues)
-- use kernel traps for unaligned accesses on ARM ?
-
-
-lower priority:
---------------
-- int15 ah=86: use better timing
-- use -msoft-float on ARM
index fe4dbb4523e6fcc8272ff5f19c2ef07c9160fd25..b68eccd40ccc6d4c2af25349f61694f3cddb4d16 100644 (file)
@@ -25,6 +25,7 @@ struct AioHandler
     IOHandler *io_write;
     AioFlushHandler *io_flush;
     int deleted;
+    int pollfds_idx;
     void *opaque;
     QLIST_ENTRY(AioHandler) node;
 };
@@ -85,9 +86,10 @@ void aio_set_fd_handler(AioContext *ctx,
         node->io_write = io_write;
         node->io_flush = io_flush;
         node->opaque = opaque;
+        node->pollfds_idx = -1;
 
-        node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
-        node->pfd.events |= (io_write ? G_IO_OUT : 0);
+        node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
+        node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
     }
 
     aio_notify(ctx);
@@ -110,13 +112,6 @@ bool aio_pending(AioContext *ctx)
     QLIST_FOREACH(node, &ctx->aio_handlers, node) {
         int revents;
 
-        /*
-         * FIXME: right now we cannot get G_IO_HUP and G_IO_ERR because
-         * main-loop.c is still select based (due to the slirp legacy).
-         * If main-loop.c ever switches to poll, G_IO_ERR should be
-         * tested too.  Dispatching G_IO_ERR to both handlers should be
-         * okay, since handlers need to be ready for spurious wakeups.
-         */
         revents = node->pfd.revents & node->pfd.events;
         if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
             return true;
@@ -129,30 +124,12 @@ bool aio_pending(AioContext *ctx)
     return false;
 }
 
-bool aio_poll(AioContext *ctx, bool blocking)
+static bool aio_dispatch(AioContext *ctx)
 {
-    static struct timeval tv0;
     AioHandler *node;
-    fd_set rdfds, wrfds;
-    int max_fd = -1;
-    int ret;
-    bool busy, progress;
-
-    progress = false;
-
-    /*
-     * If there are callbacks left that have been queued, we need to call then.
-     * Do not call select in this case, because it is possible that the caller
-     * does not need a complete flush (as is the case for qemu_aio_wait loops).
-     */
-    if (aio_bh_poll(ctx)) {
-        blocking = false;
-        progress = true;
-    }
+    bool progress = false;
 
     /*
-     * Then dispatch any pending callbacks from the GSource.
-     *
      * We have to walk very carefully in case qemu_aio_set_fd_handler is
      * called while we're walking.
      */
@@ -166,12 +143,15 @@ bool aio_poll(AioContext *ctx, bool blocking)
         revents = node->pfd.revents & node->pfd.events;
         node->pfd.revents = 0;
 
-        /* See comment in aio_pending.  */
-        if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
+        if (!node->deleted &&
+            (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
+            node->io_read) {
             node->io_read(node->opaque);
             progress = true;
         }
-        if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
+        if (!node->deleted &&
+            (revents & (G_IO_OUT | G_IO_ERR)) &&
+            node->io_write) {
             node->io_write(node->opaque);
             progress = true;
         }
@@ -186,6 +166,30 @@ bool aio_poll(AioContext *ctx, bool blocking)
             g_free(tmp);
         }
     }
+    return progress;
+}
+
+bool aio_poll(AioContext *ctx, bool blocking)
+{
+    AioHandler *node;
+    int ret;
+    bool busy, progress;
+
+    progress = false;
+
+    /*
+     * If there are callbacks left that have been queued, we need to call them.
+     * Do not call select in this case, because it is possible that the caller
+     * does not need a complete flush (as is the case for qemu_aio_wait loops).
+     */
+    if (aio_bh_poll(ctx)) {
+        blocking = false;
+        progress = true;
+    }
+
+    if (aio_dispatch(ctx)) {
+        progress = true;
+    }
 
     if (progress && !blocking) {
         return true;
@@ -193,12 +197,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
 
     ctx->walking_handlers++;
 
-    FD_ZERO(&rdfds);
-    FD_ZERO(&wrfds);
+    g_array_set_size(ctx->pollfds, 0);
 
-    /* fill fd sets */
+    /* fill pollfds */
     busy = false;
     QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+        node->pollfds_idx = -1;
+
         /* If there aren't pending AIO operations, don't invoke callbacks.
          * Otherwise, if there are no AIO requests, qemu_aio_wait() would
          * wait indefinitely.
@@ -209,13 +214,13 @@ bool aio_poll(AioContext *ctx, bool blocking)
             }
             busy = true;
         }
-        if (!node->deleted && node->io_read) {
-            FD_SET(node->pfd.fd, &rdfds);
-            max_fd = MAX(max_fd, node->pfd.fd + 1);
-        }
-        if (!node->deleted && node->io_write) {
-            FD_SET(node->pfd.fd, &wrfds);
-            max_fd = MAX(max_fd, node->pfd.fd + 1);
+        if (!node->deleted && node->pfd.events) {
+            GPollFD pfd = {
+                .fd = node->pfd.fd,
+                .events = node->pfd.events,
+            };
+            node->pollfds_idx = ctx->pollfds->len;
+            g_array_append_val(ctx->pollfds, pfd);
         }
     }
 
@@ -227,41 +232,22 @@ bool aio_poll(AioContext *ctx, bool blocking)
     }
 
     /* wait until next event */
-    ret = select(max_fd, &rdfds, &wrfds, NULL, blocking ? NULL : &tv0);
+    ret = g_poll((GPollFD *)ctx->pollfds->data,
+                 ctx->pollfds->len,
+                 blocking ? -1 : 0);
 
     /* if we have any readable fds, dispatch event */
     if (ret > 0) {
-        /* we have to walk very carefully in case
-         * qemu_aio_set_fd_handler is called while we're walking */
-        node = QLIST_FIRST(&ctx->aio_handlers);
-        while (node) {
-            AioHandler *tmp;
-
-            ctx->walking_handlers++;
-
-            if (!node->deleted &&
-                FD_ISSET(node->pfd.fd, &rdfds) &&
-                node->io_read) {
-                node->io_read(node->opaque);
-                progress = true;
-            }
-            if (!node->deleted &&
-                FD_ISSET(node->pfd.fd, &wrfds) &&
-                node->io_write) {
-                node->io_write(node->opaque);
-                progress = true;
-            }
-
-            tmp = node;
-            node = QLIST_NEXT(node, node);
-
-            ctx->walking_handlers--;
-
-            if (!ctx->walking_handlers && tmp->deleted) {
-                QLIST_REMOVE(tmp, node);
-                g_free(tmp);
+        QLIST_FOREACH(node, &ctx->aio_handlers, node) {
+            if (node->pollfds_idx != -1) {
+                GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD,
+                                              node->pollfds_idx);
+                node->pfd.revents = pfd->revents;
             }
         }
+        if (aio_dispatch(ctx)) {
+            progress = true;
+        }
     }
 
     assert(progress || busy);
diff --git a/async.c b/async.c
index 72d268ae352510c0c0ca49a43e05d197e23c0d98..f2d47ba96d1b8044eb565b1c3138a67301caae5e 100644 (file)
--- a/async.c
+++ b/async.c
@@ -174,6 +174,7 @@ aio_ctx_finalize(GSource     *source)
 
     aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
     event_notifier_cleanup(&ctx->notifier);
+    g_array_free(ctx->pollfds, TRUE);
 }
 
 static GSourceFuncs aio_source_funcs = {
@@ -198,6 +199,7 @@ AioContext *aio_context_new(void)
 {
     AioContext *ctx;
     ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
+    ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
     event_notifier_init(&ctx->notifier, false);
     aio_set_event_notifier(ctx, &ctx->notifier, 
                            (EventNotifierHandler *)
index bf5970f74bc365a4a49b305006529b4f06bddc55..dcaa67c6d3093cafd5f5add9ee5a82c5e465908e 100755 (executable)
--- a/configure
+++ b/configure
@@ -226,6 +226,7 @@ coroutine=""
 seccomp=""
 glusterfs=""
 virtio_blk_data_plane=""
+gtk=""
 
 # parse CC options first
 for opt do
@@ -897,6 +898,10 @@ for opt do
   ;;
   --enable-virtio-blk-data-plane) virtio_blk_data_plane="yes"
   ;;
+  --disable-gtk) gtk="no"
+  ;;
+  --enable-gtk) gtk="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -1635,6 +1640,26 @@ if test "$sparse" != "no" ; then
   fi
 fi
 
+##########################################
+# GTK probe
+
+if test "$gtk" != "no"; then
+    if $pkg_config --exists 'gtk+-2.0 >= 2.18.0' && \
+       $pkg_config --exists 'vte >= 0.24.0'; then
+       gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null`
+       gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null`
+       vte_cflags=`$pkg_config --cflags vte 2>/dev/null`
+       vte_libs=`$pkg_config --libs vte 2>/dev/null`
+       libs_softmmu="$gtk_libs $vte_libs $libs_softmmu"
+       gtk="yes"
+    else
+       if test "$gtk" = "yes" ; then
+           feature_not_found "gtk"
+       fi
+       gtk="no"
+    fi
+fi
+
 ##########################################
 # SDL probe
 
@@ -3090,20 +3115,27 @@ if compile_prog "" "" ; then
 fi
 
 ########################################
-# check whether we can disable the -Wunused-but-set-variable
-# option with a pragma (this is needed to silence a warning in
-# some versions of the valgrind VALGRIND_STACK_DEREGISTER macro.)
-# This test has to be compiled with -Werror as otherwise an
-# unknown pragma is only a warning.
+# check whether we can disable warning option with a pragma (this is needed
+# to silence warnings in the headers of some versions of external libraries).
+# This test has to be compiled with -Werror as otherwise an unknown pragma is
+# only a warning.
+#
+# If we can't selectively disable warning in the code, disable -Werror so that
+# the build doesn't fail anyway.
+
 pragma_disable_unused_but_set=no
 cat > $TMPC << EOF
 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+
 int main(void) {
     return 0;
 }
 EOF
 if compile_prog "-Werror" "" ; then
     pragma_diagnostic_available=yes
+else
+    werror=no
 fi
 
 ########################################
@@ -3218,6 +3250,7 @@ fi
 
 qemu_confdir=$sysconfdir$confsuffix
 qemu_datadir=$datadir$confsuffix
+qemu_localedir="$datadir/locale"
 
 tools=""
 if test "$want_tools" = "yes" ; then
@@ -3301,6 +3334,7 @@ if test "$darwin" = "yes" ; then
 fi
 echo "pixman            $pixman"
 echo "SDL support       $sdl"
+echo "GTK support       $gtk"
 echo "curses support    $curses"
 echo "curl support      $curl"
 echo "mingw32 support   $mingw32"
@@ -3390,6 +3424,7 @@ echo "qemu_localstatedir=$local_statedir" >> $config_host_mak
 echo "qemu_helperdir=$libexecdir" >> $config_host_mak
 echo "extra_cflags=$EXTRA_CFLAGS" >> $config_host_mak
 echo "extra_ldflags=$EXTRA_LDFLAGS" >> $config_host_mak
+echo "qemu_localedir=$qemu_localedir" >> $config_host_mak
 
 echo "ARCH=$ARCH" >> $config_host_mak
 if test "$debug_tcg" = "yes" ; then
@@ -3591,6 +3626,11 @@ if test "$bluez" = "yes" ; then
   echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
 fi
 echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
+if test "$gtk" = "yes" ; then
+  echo "CONFIG_GTK=y" >> $config_host_mak
+  echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
+  echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
+fi
 if test "$xen" = "yes" ; then
   echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
   echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
@@ -3723,7 +3763,7 @@ fi
 # USB host support
 case "$usb" in
 linux)
-  echo "HOST_USB=linux" >> $config_host_mak
+  echo "HOST_USB=linux legacy" >> $config_host_mak
 ;;
 bsd)
   echo "HOST_USB=bsd" >> $config_host_mak
@@ -4305,7 +4345,7 @@ DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS qapi-generated"
 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"
+FILES="$FILES tests/tcg/lm32/Makefile po/Makefile"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
 FILES="$FILES pc-bios/spapr-rtas/Makefile"
 FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
index e37ebac9c449e6469d47234640b43a4f9e261e7c..1fb41c9f14bab73a28c71a484773bd56928db1ab 100644 (file)
@@ -45,7 +45,7 @@ static unsigned int pool_size;
 typedef struct {
     Coroutine base;
     void *stack;
-    jmp_buf env;
+    sigjmp_buf env;
 } CoroutineUContext;
 
 /**
@@ -59,7 +59,7 @@ typedef struct {
     CoroutineUContext leader;
 
     /** Information for the signal handler (trampoline) */
-    jmp_buf tr_reenter;
+    sigjmp_buf tr_reenter;
     volatile sig_atomic_t tr_called;
     void *tr_handler;
 } CoroutineThreadState;
@@ -115,8 +115,8 @@ static void __attribute__((constructor)) coroutine_init(void)
 static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co)
 {
     /* Initialize longjmp environment and switch back the caller */
-    if (!setjmp(self->env)) {
-        longjmp(*(jmp_buf *)co->entry_arg, 1);
+    if (!sigsetjmp(self->env, 0)) {
+        siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
     }
 
     while (true) {
@@ -145,14 +145,14 @@ static void coroutine_trampoline(int signal)
     /*
      * Here we have to do a bit of a ping pong between the caller, given that
      * this is a signal handler and we have to do a return "soon". Then the
-     * caller can reestablish everything and do a longjmp here again.
+     * caller can reestablish everything and do a siglongjmp here again.
      */
-    if (!setjmp(coTS->tr_reenter)) {
+    if (!sigsetjmp(coTS->tr_reenter, 0)) {
         return;
     }
 
     /*
-     * Ok, the caller has longjmp'ed back to us, so now prepare
+     * Ok, the caller has siglongjmp'ed back to us, so now prepare
      * us for the real machine state switching. We have to jump
      * into another function here to get a new stack context for
      * the auto variables (which have to be auto-variables
@@ -179,7 +179,7 @@ static Coroutine *coroutine_new(void)
 
     /* The way to manipulate stack is with the sigaltstack function. We
      * prepare a stack, with it delivering a signal to ourselves and then
-     * put setjmp/longjmp where needed.
+     * put sigsetjmp/siglongjmp where needed.
      * This has been done keeping coroutine-ucontext as a model and with the
      * pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics
      * of the coroutines and see pth_mctx.c (from the pth project) for the
@@ -220,7 +220,7 @@ static Coroutine *coroutine_new(void)
 
     /*
      * Now transfer control onto the signal stack and set it up.
-     * It will return immediately via "return" after the setjmp()
+     * It will return immediately via "return" after the sigsetjmp()
      * was performed. Be careful here with race conditions.  The
      * signal can be delivered the first time sigsuspend() is
      * called.
@@ -261,8 +261,8 @@ static Coroutine *coroutine_new(void)
      * type-conversion warnings related to the `volatile' qualifier and
      * the fact that `jmp_buf' usually is an array type.
      */
-    if (!setjmp(old_env)) {
-        longjmp(coTS->tr_reenter, 1);
+    if (!sigsetjmp(old_env, 0)) {
+        siglongjmp(coTS->tr_reenter, 1);
     }
 
     /*
@@ -311,9 +311,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
 
     s->current = to_;
 
-    ret = setjmp(from->env);
+    ret = sigsetjmp(from->env, 0);
     if (ret == 0) {
-        longjmp(to->env, action);
+        siglongjmp(to->env, action);
     }
     return ret;
 }
index a9c30e9df412b39cd0f26bfd540469d5390add56..bd20e384b7b7c2339d712d5c8f23552b7d90466b 100644 (file)
@@ -46,7 +46,7 @@ static unsigned int pool_size;
 typedef struct {
     Coroutine base;
     void *stack;
-    jmp_buf env;
+    sigjmp_buf env;
 
 #ifdef CONFIG_VALGRIND_H
     unsigned int valgrind_stack_id;
@@ -130,8 +130,8 @@ static void coroutine_trampoline(int i0, int i1)
     co = &self->base;
 
     /* Initialize longjmp environment and switch back the caller */
-    if (!setjmp(self->env)) {
-        longjmp(*(jmp_buf *)co->entry_arg, 1);
+    if (!sigsetjmp(self->env, 0)) {
+        siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
     }
 
     while (true) {
@@ -145,14 +145,15 @@ static Coroutine *coroutine_new(void)
     const size_t stack_size = 1 << 20;
     CoroutineUContext *co;
     ucontext_t old_uc, uc;
-    jmp_buf old_env;
+    sigjmp_buf old_env;
     union cc_arg arg = {0};
 
-    /* The ucontext functions preserve signal masks which incurs a system call
-     * overhead.  setjmp()/longjmp() does not preserve signal masks but only
-     * works on the current stack.  Since we need a way to create and switch to
-     * a new stack, use the ucontext functions for that but setjmp()/longjmp()
-     * for everything else.
+    /* The ucontext functions preserve signal masks which incurs a
+     * system call overhead.  sigsetjmp(buf, 0)/siglongjmp() does not
+     * preserve signal masks but only works on the current stack.
+     * Since we need a way to create and switch to a new stack, use
+     * the ucontext functions for that but sigsetjmp()/siglongjmp() for
+     * everything else.
      */
 
     if (getcontext(&uc) == -1) {
@@ -178,8 +179,8 @@ static Coroutine *coroutine_new(void)
     makecontext(&uc, (void (*)(void))coroutine_trampoline,
                 2, arg.i[0], arg.i[1]);
 
-    /* swapcontext() in, longjmp() back out */
-    if (!setjmp(old_env)) {
+    /* swapcontext() in, siglongjmp() back out */
+    if (!sigsetjmp(old_env, 0)) {
         swapcontext(&old_uc, &uc);
     }
     return &co->base;
@@ -242,9 +243,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
 
     s->current = to_;
 
-    ret = setjmp(from->env);
+    ret = sigsetjmp(from->env, 0);
     if (ret == 0) {
-        longjmp(to->env, action);
+        siglongjmp(to->env, action);
     }
     return ret;
 }
index 9fcfe9e0dbeff241761db23b6ca1151134221188..afbe4977ab18b8c3dce98e6d25d167fb37609ac7 100644 (file)
@@ -35,7 +35,7 @@ void cpu_loop_exit(CPUArchState *env)
     CPUState *cpu = ENV_GET_CPU(env);
 
     cpu->current_tb = NULL;
-    longjmp(env->jmp_env, 1);
+    siglongjmp(env->jmp_env, 1);
 }
 
 /* exit the current TB from a signal handler. The host registers are
@@ -47,7 +47,7 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc)
     /* XXX: restore cpu registers saved in host registers */
 
     env->exception_index = -1;
-    longjmp(env->jmp_env, 1);
+    siglongjmp(env->jmp_env, 1);
 }
 #endif
 
@@ -234,7 +234,7 @@ int cpu_exec(CPUArchState *env)
 
     /* prepare setjmp context for exception handling */
     for(;;) {
-        if (setjmp(env->jmp_env) == 0) {
+        if (sigsetjmp(env->jmp_env, 0) == 0) {
             /* if an exception is pending, we execute it here */
             if (env->exception_index >= 0) {
                 if (env->exception_index >= EXCP_INTERRUPT) {
index 501dd413b74ab05542356d6783301736770abfd6..2dbee94c89d8fb26077754d886866a4ba6ccf582 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for alpha-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_SERIAL=y
 CONFIG_I8254=y
 CONFIG_PCKBD=y
index 2f1a5c994300871165ed7240133ce890bf061b28..b40f7b08e2e6a4840eb8888c56a4873e539c41ea 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for arm-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_VGA=y
 CONFIG_ISA_MMIO=y
index 2c78175ae7405aea494675af23f799dfabbde2e1..1b23025a98598e2683ad5fc281b8099b5d56de55 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for i386-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
index 3e2ec3716c5222c2c6459a55d6d5de76ed43fb39..778ea82a10fb7311252c54a84223c13c5bd1ec9a 100644 (file)
@@ -1,5 +1,6 @@
 # Default configuration for m68k-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_PTIMER=y
index a271b1c6da23b9707771308f540a2c9d0d3769a4..4f04a337324f89fe37c30323c9bc4d3da64a0f97 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for mips-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA=y
index 0510bb6a5336b73fa54d7ec189a71c701ec0f525..a5b6c3c36a4fbff34bae61fb8af706d8b9393575 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for mips64-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA=y
index ed3bed3b8d276788540c038b518fee961cbb98e1..a0e6de8e68db02da5c93c532c01d72a369520df8 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for mips64el-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA=y
index fa3a2cacdd39f19010f81176d31148b054c5a83a..753dd76a218da6272e05ea5aa1be533df3a6d1d3 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for mipsel-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA=y
index 1f4a1cff61d0bd7b6dabb1d6c8306ffd50adbf9c..f9f8a8159b4ad0a5deafbaf77f2e37e4f8f20408 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for ppc-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
index 5ff406caa518f328774f7bb2846a569c00d72b24..dc4429437838f01f17984dadbcb7575d19531745 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for ppc64-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
index aaa9cdc1f76d824b44936c4fb8efc940bcca721c..1c6bcf93fc129d7523702e55244a1998f65aae5c 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for ppcemb-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
index 5c69acc5f53762a5406d5e6b9490ee8128303f2c..e08b2ee1064ca3a56d1187022f7f9f174a025115 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for sh4-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI02=y
index 7cdc122201d2094c83fe47c2efc325cf5b178140..3a8453552bdc10342841405cc1ec06f5089e76cf 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for sh4eb-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI02=y
index 03e8b4271244a782a905859cec75f102dc7fc304..2145b6b29f4232e066ada1ecb79f4c15e096b8b9 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for sparc64-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_ISA_MMIO=y
 CONFIG_M48T59=y
 CONFIG_PTIMER=y
diff --git a/default-configs/usb.mak b/default-configs/usb.mak
new file mode 100644 (file)
index 0000000..1bf9075
--- /dev/null
@@ -0,0 +1,8 @@
+CONFIG_USB_TABLET_WACOM=y
+CONFIG_USB_STORAGE_BOT=y
+CONFIG_USB_STORAGE_UAS=y
+CONFIG_USB_SMARTCARD=y
+CONFIG_USB_AUDIO=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_NETWORK=y
+CONFIG_USB_BLUETOOTH=y
index 233a8564ebc4b74ecf38f3180cc6bbaa3f6b30cd..3392f5abd6531a49009a3897ae77280de600e446 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for x86_64-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_VGA=y
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
index 3b006b13e098dcfddf24b018611ce30f365cac98..73cc06f1c37e583b7e620a19cfb13ab26260de05 100644 (file)
@@ -226,7 +226,7 @@ struct dis_private {
   bfd_byte the_buffer[MAX_MNEM_SIZE];
   bfd_vma insn_start;
   int orig_sizeflag;
-  jmp_buf bailout;
+  sigjmp_buf bailout;
 };
 
 enum address_mode
@@ -303,7 +303,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr)
         STATUS.  */
       if (priv->max_fetched == priv->the_buffer)
        (*info->memory_error_func) (status, start, info);
-      longjmp (priv->bailout, 1);
+      siglongjmp(priv->bailout, 1);
     }
   else
     priv->max_fetched = addr;
@@ -3661,7 +3661,7 @@ print_insn (bfd_vma pc, disassemble_info *info)
   start_codep = priv.the_buffer;
   codep = priv.the_buffer;
 
-  if (setjmp (priv.bailout) != 0)
+  if (sigsetjmp(priv.bailout, 0) != 0)
     {
       const char *name;
 
@@ -4720,7 +4720,8 @@ print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp)
          buf[0] = '0';
          buf[1] = 'x';
           snprintf_vma (tmp, sizeof(tmp), disp);
-         for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++);
+          for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++) {
+          }
           pstrcpy (buf + 2, bufsize - 2, tmp + i);
        }
       else
index c950241f79005cf5040e33bd068bcf6368b01348..cc0db96cae0c83e04a7c988b79284b374596090d 100644 (file)
@@ -624,7 +624,7 @@ struct private
   bfd_byte *max_fetched;
   bfd_byte the_buffer[MAXLEN];
   bfd_vma insn_start;
-  jmp_buf bailout;
+  sigjmp_buf bailout;
 };
 
 /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
@@ -644,7 +644,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr)
   if (status != 0)
     {
       (*info->memory_error_func) (status, start, info);
-      longjmp (priv->bailout, 1);
+      siglongjmp(priv->bailout, 1);
     }
   else
     priv->max_fetched = addr;
@@ -1912,9 +1912,10 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
   priv.max_fetched = priv.the_buffer;
   priv.insn_start = memaddr;
 
-  if (setjmp (priv.bailout) != 0)
-    /* Error return.  */
-    return -1;
+  if (sigsetjmp(priv.bailout, 0) != 0) {
+      /* Error return.  */
+      return -1;
+  }
 
   switch (info->mach)
     {
index 447e32a42e3a52b0ca9b68eedcc4862a9bb2f736..a1f3a808acced8356fae309835105e8e75fce15b 100644 (file)
@@ -38,8 +38,10 @@ common-obj-$(CONFIG_DMA) += dma.o
 common-obj-$(CONFIG_I82374) += i82374.o
 common-obj-$(CONFIG_HPET) += hpet.o
 common-obj-$(CONFIG_APPLESMC) += applesmc.o
+ifeq ($(CONFIG_USB_SMARTCARD),y)
 common-obj-y += ccid-card-passthru.o
 common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
+endif
 common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
 common-obj-y += fifo.o
 common-obj-y += pam.o
index 760bed0b72a4228d8ea3d0705e1749a83ab51c47..ba1685afd1946ce4b2d8f1c7dd360e805df0f3d4 100644 (file)
@@ -75,7 +75,6 @@ typedef struct UART {
     CharDriverState *chr;
 
     /* registers */
-    uint32_t receive;
     uint32_t status;
     uint32_t control;
 
@@ -136,12 +135,14 @@ static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
 {
     UART *uart = opaque;
 
-    uart_add_to_fifo(uart, buf, size);
+    if (uart->control & UART_RECEIVE_ENABLE) {
+        uart_add_to_fifo(uart, buf, size);
 
-    uart->status |= UART_DATA_READY;
+        uart->status |= UART_DATA_READY;
 
-    if (uart->control & UART_RECEIVE_INTERRUPT) {
-        qemu_irq_pulse(uart->irq);
+        if (uart->control & UART_RECEIVE_INTERRUPT) {
+            qemu_irq_pulse(uart->irq);
+        }
     }
 }
 
@@ -193,8 +194,15 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr,
     switch (addr) {
     case DATA_OFFSET:
     case DATA_OFFSET + 3:       /* When only one byte write */
-        c = value & 0xFF;
-        qemu_chr_fe_write(uart->chr, &c, 1);
+        /* Transmit when character device available and transmitter enabled */
+        if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
+            c = value & 0xFF;
+            qemu_chr_fe_write(uart->chr, &c, 1);
+            /* Generate interrupt */
+            if (uart->control & UART_TRANSMIT_INTERRUPT) {
+                qemu_irq_pulse(uart->irq);
+            }
+        }
         return;
 
     case STATUS_OFFSET:
@@ -242,30 +250,44 @@ static int grlib_apbuart_init(SysBusDevice *dev)
     return 0;
 }
 
-static Property grlib_gptimer_properties[] = {
+static void grlib_apbuart_reset(DeviceState *d)
+{
+    UART *uart = container_of(d, UART, busdev.qdev);
+
+    /* Transmitter FIFO and shift registers are always empty in QEMU */
+    uart->status =  UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
+    /* Everything is off */
+    uart->control = 0;
+    /* Flush receive FIFO */
+    uart->len = 0;
+    uart->current = 0;
+}
+
+static Property grlib_apbuart_properties[] = {
     DEFINE_PROP_CHR("chrdev", UART, chr),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
     k->init = grlib_apbuart_init;
-    dc->props = grlib_gptimer_properties;
+    dc->reset = grlib_apbuart_reset;
+    dc->props = grlib_apbuart_properties;
 }
 
-static const TypeInfo grlib_gptimer_info = {
+static const TypeInfo grlib_apbuart_info = {
     .name          = "grlib,apbuart",
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(UART),
-    .class_init    = grlib_gptimer_class_init,
+    .class_init    = grlib_apbuart_class_init,
 };
 
-static void grlib_gptimer_register_types(void)
+static void grlib_apbuart_register_types(void)
 {
-    type_register_static(&grlib_gptimer_info);
+    type_register_static(&grlib_apbuart_info);
 }
 
-type_init(grlib_gptimer_register_types)
+type_init(grlib_apbuart_register_types)
index 5e491bc0b4cb8cdcaf86613f6603b51bca255513..b6bb0e166a0b83e0c8d4528de2b8ce5733e5d1cd 100644 (file)
@@ -700,7 +700,7 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
                 vmstate_register_ram_global(&ram_memories[i]);
                 ram_bases[i] = base;
                 ram_sizes[i] = bank_size;
-                base += ram_size;
+                base += bank_size;
                 size_left -= bank_size;
                 break;
             }
index 88e63f8085469fd220c54cb1be3b9a4b26bbd4a6..455fb91269b0d95151320523e095e413d2c6045d 100644 (file)
@@ -118,7 +118,8 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
                  qxl->guest_primary.surface.height,
                  qxl->guest_primary.bits_pp,
                  qxl->guest_primary.abs_stride,
-                 qxl->guest_primary.data);
+                 qxl->guest_primary.data,
+                 false);
         } else {
             qemu_resize_displaysurface(vga->ds,
                     qxl->guest_primary.surface.width,
index bc42639b167aed356c37eaa4f069f416ea5b61c1..382496cf8230730ba1cbe37306dfa8932a6d7be1 100644 (file)
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -361,6 +361,7 @@ struct USBPacket {
     int pid;
     uint64_t id;
     USBEndpoint *ep;
+    unsigned int stream;
     QEMUIOVector iov;
     uint64_t parameter; /* control transfers */
     bool short_not_ok;
@@ -383,13 +384,15 @@ struct USBCombinedPacket {
 void usb_packet_init(USBPacket *p);
 void usb_packet_set_state(USBPacket *p, USBPacketState state);
 void usb_packet_check_state(USBPacket *p, USBPacketState expected);
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
-                      bool short_not_ok, bool int_req);
+void usb_packet_setup(USBPacket *p, int pid,
+                      USBEndpoint *ep, unsigned int stream,
+                      uint64_t id, bool short_not_ok, bool int_req);
 void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
 int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
 void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl);
 void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
 void usb_packet_skip(USBPacket *p, size_t bytes);
+size_t usb_packet_size(USBPacket *p);
 void usb_packet_cleanup(USBPacket *p);
 
 static inline bool usb_packet_is_inflight(USBPacket *p)
@@ -417,6 +420,7 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
                                 uint16_t raw);
 int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
 void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled);
+void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted);
 USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
                                     uint64_t id);
 
@@ -428,13 +432,12 @@ void usb_attach(USBPort *port);
 void usb_detach(USBPort *port);
 void usb_port_reset(USBPort *port);
 void usb_device_reset(USBDevice *dev);
-void usb_wakeup(USBEndpoint *ep);
+void usb_wakeup(USBEndpoint *ep, unsigned int stream);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
 
 /* usb-linux.c */
 USBDevice *usb_host_device_open(USBBus *bus, const char *devname);
-int usb_host_device_close(const char *devname);
 void usb_host_info(Monitor *mon, const QDict *qdict);
 
 /* usb-bt.c */
@@ -488,7 +491,7 @@ struct USBBus {
 struct USBBusOps {
     int (*register_companion)(USBBus *bus, USBPort *ports[],
                               uint32_t portcount, uint32_t firstport);
-    void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep);
+    void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep, unsigned int stream);
 };
 
 void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
index d1bbbc06e7e490563cf0fea53e2e65da21977776..e63e287ce0db32d46246c09a3f890af674af978b 100644 (file)
@@ -1,14 +1,30 @@
+# usb subsystem core
+common-obj-y += core.o combined-packet.o bus.o desc.o
+common-obj-y += libhw.o
+
+# usb host adapters
 common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
 common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
 common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o
 common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
-common-obj-y += libhw.o
 
+# emulated usb devices
+common-obj-y += dev-hub.o
+common-obj-y += dev-hid.o
+common-obj-$(CONFIG_USB_TABLET_WACOM) += dev-wacom.o
+common-obj-$(CONFIG_USB_STORAGE_BOT)  += dev-storage.o
+common-obj-$(CONFIG_USB_STORAGE_UAS)  += dev-uas.o
+common-obj-$(CONFIG_USB_AUDIO)        += dev-audio.o
+common-obj-$(CONFIG_USB_SERIAL)       += dev-serial.o
+common-obj-$(CONFIG_USB_NETWORK)      += dev-network.o
+
+# FIXME: make configurable too
+CONFIG_USB_BLUETOOTH := y
+common-obj-$(CONFIG_USB_BLUETOOTH)    += dev-bluetooth.o
+common-obj-$(CONFIG_USB_SMARTCARD)    += dev-smartcard-reader.o
+
+# usb redirection
 common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
 
-common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o
-common-obj-y += host-$(HOST_USB).o dev-bluetooth.o
-common-obj-y += dev-hid.o dev-storage.o dev-wacom.o
-common-obj-y += dev-serial.o dev-network.o dev-audio.o
-common-obj-y += dev-smartcard-reader.o
-common-obj-y += dev-uas.o
+# usb pass-through
+common-obj-y += $(patsubst %,host-%.o,$(HOST_USB))
index d057aab90000eb87dae2995e2156337ce0631fbf..15a150aea03806fded1adbb193bb0b41505aef6d 100644 (file)
@@ -71,7 +71,7 @@ void usb_device_reset(USBDevice *dev)
     usb_device_handle_reset(dev);
 }
 
-void usb_wakeup(USBEndpoint *ep)
+void usb_wakeup(USBEndpoint *ep, unsigned int stream)
 {
     USBDevice *dev = ep->dev;
     USBBus *bus = usb_bus_from_device(dev);
@@ -80,7 +80,7 @@ void usb_wakeup(USBEndpoint *ep)
         dev->port->ops->wakeup(dev->port);
     }
     if (bus->ops->wakeup_endpoint) {
-        bus->ops->wakeup_endpoint(bus, ep);
+        bus->ops->wakeup_endpoint(bus, ep, stream);
     }
 }
 
@@ -545,14 +545,16 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state)
     p->state = state;
 }
 
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
-                      bool short_not_ok, bool int_req)
+void usb_packet_setup(USBPacket *p, int pid,
+                      USBEndpoint *ep, unsigned int stream,
+                      uint64_t id, bool short_not_ok, bool int_req)
 {
     assert(!usb_packet_is_inflight(p));
     assert(p->iov.iov != NULL);
     p->id = id;
     p->pid = pid;
     p->ep = ep;
+    p->stream = stream;
     p->status = USB_RET_SUCCESS;
     p->actual_length = 0;
     p->parameter = 0;
@@ -570,15 +572,17 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
 
 void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
 {
+    QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
+
     assert(p->actual_length >= 0);
-    assert(p->actual_length + bytes <= p->iov.size);
+    assert(p->actual_length + bytes <= iov->size);
     switch (p->pid) {
     case USB_TOKEN_SETUP:
     case USB_TOKEN_OUT:
-        iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
+        iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
         break;
     case USB_TOKEN_IN:
-        iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
+        iov_from_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
         break;
     default:
         fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
@@ -589,14 +593,21 @@ void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
 
 void usb_packet_skip(USBPacket *p, size_t bytes)
 {
+    QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
+
     assert(p->actual_length >= 0);
-    assert(p->actual_length + bytes <= p->iov.size);
+    assert(p->actual_length + bytes <= iov->size);
     if (p->pid == USB_TOKEN_IN) {
-        iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes);
+        iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes);
     }
     p->actual_length += bytes;
 }
 
+size_t usb_packet_size(USBPacket *p)
+{
+    return p->combined ? p->combined->iov.size : p->iov.size;
+}
+
 void usb_packet_cleanup(USBPacket *p)
 {
     assert(!usb_packet_is_inflight(p));
@@ -755,6 +766,12 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled)
     uep->pipeline = enabled;
 }
 
+void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted)
+{
+    struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+    uep->halted = halted;
+}
+
 USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
                                     uint64_t id)
 {
index b7c32333d70032a98fdff56f17006ba6e7af9c72..b38938132699f352f151f3a7b04ac57949f82161 100644 (file)
@@ -225,12 +225,9 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
         d->u.endpoint.bRefresh      = ep->bRefresh;
         d->u.endpoint.bSynchAddress = ep->bSynchAddress;
     }
-    if (ep->extra) {
-        memcpy(dest + bLength, ep->extra, extralen);
-    }
 
     if (superlen) {
-        USBDescriptor *d = (void *)(dest + bLength + extralen);
+        USBDescriptor *d = (void *)(dest + bLength);
 
         d->bLength                       = 0x06;
         d->bDescriptorType               = USB_DT_ENDPOINT_COMPANION;
@@ -243,6 +240,10 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
             usb_hi(ep->wBytesPerInterval);
     }
 
+    if (ep->extra) {
+        memcpy(dest + bLength + superlen, ep->extra, extralen);
+    }
+
     return bLength + extralen + superlen;
 }
 
index adbf9d46970d9b6f527f4baa875f6638c7f11508..0f8aa48c85a8d411c3fa1553eb4e1feb8cf38441 100644 (file)
@@ -478,7 +478,7 @@ static void usb_bt_out_hci_packet_event(void *opaque,
     struct USBBtState *s = (struct USBBtState *) opaque;
 
     if (s->evt.len == 0) {
-        usb_wakeup(s->intr);
+        usb_wakeup(s->intr, 0);
     }
     usb_bt_fifo_enqueue(&s->evt, data, len);
 }
index 29b64819abdbaf6b549b90c38d4f135e202a9b37..97010488872cacd0aa529a17da07b1ca004e14de 100644 (file)
@@ -423,7 +423,7 @@ static void usb_hid_changed(HIDState *hs)
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    usb_wakeup(us->intr);
+    usb_wakeup(us->intr, 0);
 }
 
 static void usb_hid_handle_reset(USBDevice *dev)
index 79f2f46d554d4f65a3c1f6e25791485e501b3443..504c98c35008f0f0490967fc9343d36300e59322 100644 (file)
@@ -164,7 +164,7 @@ static void usb_hub_attach(USBPort *port1)
     } else {
         port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
     }
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static void usb_hub_detach(USBPort *port1)
@@ -173,7 +173,7 @@ static void usb_hub_detach(USBPort *port1)
     USBHubPort *port = &s->ports[port1->index];
 
     trace_usb_hub_detach(s->dev.addr, port1->index + 1);
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 
     /* Let upstream know the device on this port is gone */
     s->dev.port->ops->child_detach(s->dev.port, port1->dev);
@@ -184,7 +184,7 @@ static void usb_hub_detach(USBPort *port1)
         port->wPortStatus &= ~PORT_STAT_ENABLE;
         port->wPortChange |= PORT_STAT_C_ENABLE;
     }
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
@@ -202,7 +202,7 @@ static void usb_hub_wakeup(USBPort *port1)
 
     if (port->wPortStatus & PORT_STAT_SUSPEND) {
         port->wPortChange |= PORT_STAT_C_SUSPEND;
-        usb_wakeup(s->intr);
+        usb_wakeup(s->intr, 0);
     }
 }
 
@@ -364,7 +364,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                     port->wPortChange |= PORT_STAT_C_RESET;
                     /* set enable bit */
                     port->wPortStatus |= PORT_STAT_ENABLE;
-                    usb_wakeup(s->intr);
+                    usb_wakeup(s->intr, 0);
                 }
                 break;
             case PORT_POWER:
index a01a5e793a7733d1691c3fe8169d554ef74b6d39..c08718b6791daf023f88a4a19eb87b4898be37fc 100644 (file)
@@ -855,7 +855,7 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length)
             g_malloc0(sizeof(struct rndis_response) + length);
 
     if (QTAILQ_EMPTY(&s->rndis_resp)) {
-        usb_wakeup(s->intr);
+        usb_wakeup(s->intr, 0);
     }
 
     QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
index 979a473b37813f01109a8d807a263ab0b11dcb54..caebc1c3fffa8e27476184bb41b564a960a141cb 100644 (file)
@@ -839,7 +839,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full)
         s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
     }
     s->notify_slot_change = true;
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static void ccid_write_data_block_error(
index b89d00f7cf1aa4cd22479898677bffcf97232a86..d3f01aa2a75d531570865c5d5f2db8f73cdbc6dc 100644 (file)
@@ -400,6 +400,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
     struct usb_msd_cbw cbw;
     uint8_t devep = p->ep->nr;
     SCSIDevice *scsi_dev;
+    uint32_t len;
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
@@ -441,8 +442,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
 #ifdef DEBUG_MSD
             scsi_req_print(s->req);
 #endif
-            scsi_req_enqueue(s->req);
-            if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
+            len = scsi_req_enqueue(s->req);
+            if (len) {
                 scsi_req_continue(s->req);
             }
             break;
index d904d1a40b9238bab18d17ab121097bf2230b5dc..1ac5117ba77f8e3efef39a50b667d50fef349886 100644 (file)
@@ -99,6 +99,9 @@ typedef struct {
 
 /* --------------------------------------------------------------------- */
 
+#define UAS_STREAM_BM_ATTR  4
+#define UAS_MAX_STREAMS     (1 << UAS_STREAM_BM_ATTR)
+
 typedef struct UASDevice UASDevice;
 typedef struct UASRequest UASRequest;
 typedef struct UASStatus UASStatus;
@@ -106,12 +109,18 @@ typedef struct UASStatus UASStatus;
 struct UASDevice {
     USBDevice                 dev;
     SCSIBus                   bus;
-    UASRequest                *datain;
-    UASRequest                *dataout;
-    USBPacket                 *status;
     QEMUBH                    *status_bh;
     QTAILQ_HEAD(, UASStatus)  results;
     QTAILQ_HEAD(, UASRequest) requests;
+
+    /* usb 2.0 only */
+    USBPacket                 *status2;
+    UASRequest                *datain2;
+    UASRequest                *dataout2;
+
+    /* usb 3.0 only */
+    USBPacket                 *data3[UAS_MAX_STREAMS];
+    USBPacket                 *status3[UAS_MAX_STREAMS];
 };
 
 struct UASRequest {
@@ -132,6 +141,7 @@ struct UASRequest {
 };
 
 struct UASStatus {
+    uint32_t                  stream;
     uas_ui                    status;
     uint32_t                  length;
     QTAILQ_ENTRY(UASStatus)   next;
@@ -144,6 +154,7 @@ enum {
     STR_PRODUCT,
     STR_SERIALNUMBER,
     STR_CONFIG_HIGH,
+    STR_CONFIG_SUPER,
 };
 
 static const USBDescStrings desc_strings = {
@@ -151,6 +162,7 @@ static const USBDescStrings desc_strings = {
     [STR_PRODUCT]      = "USB Attached SCSI HBA",
     [STR_SERIALNUMBER] = "27842",
     [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
+    [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
 };
 
 static const USBDescIface desc_iface_high = {
@@ -204,6 +216,64 @@ static const USBDescIface desc_iface_high = {
     }
 };
 
+static const USBDescIface desc_iface_super = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 4,
+    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
+    .bInterfaceSubClass            = 0x06, /* SCSI */
+    .bInterfaceProtocol            = 0x62, /* UAS  */
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 1024,
+            .bMaxBurst             = 15,
+            .extra = (uint8_t[]) {
+                0x04,  /*  u8  bLength */
+                0x24,  /*  u8  bDescriptorType */
+                UAS_PIPE_ID_COMMAND,
+                0x00,  /*  u8  bReserved */
+            },
+        },{
+            .bEndpointAddress      = USB_DIR_IN | UAS_PIPE_ID_STATUS,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 1024,
+            .bMaxBurst             = 15,
+            .bmAttributes_super    = UAS_STREAM_BM_ATTR,
+            .extra = (uint8_t[]) {
+                0x04,  /*  u8  bLength */
+                0x24,  /*  u8  bDescriptorType */
+                UAS_PIPE_ID_STATUS,
+                0x00,  /*  u8  bReserved */
+            },
+        },{
+            .bEndpointAddress      = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 1024,
+            .bMaxBurst             = 15,
+            .bmAttributes_super    = UAS_STREAM_BM_ATTR,
+            .extra = (uint8_t[]) {
+                0x04,  /*  u8  bLength */
+                0x24,  /*  u8  bDescriptorType */
+                UAS_PIPE_ID_DATA_IN,
+                0x00,  /*  u8  bReserved */
+            },
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 1024,
+            .bMaxBurst             = 15,
+            .bmAttributes_super    = UAS_STREAM_BM_ATTR,
+            .extra = (uint8_t[]) {
+                0x04,  /*  u8  bLength */
+                0x24,  /*  u8  bDescriptorType */
+                UAS_PIPE_ID_DATA_OUT,
+                0x00,  /*  u8  bReserved */
+            },
+        },
+    }
+};
+
 static const USBDescDevice desc_device_high = {
     .bcdUSB                        = 0x0200,
     .bMaxPacketSize0               = 64,
@@ -220,6 +290,22 @@ static const USBDescDevice desc_device_high = {
     },
 };
 
+static const USBDescDevice desc_device_super = {
+    .bcdUSB                        = 0x0300,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_SUPER,
+            .bmAttributes          = 0xc0,
+            .nif = 1,
+            .ifs = &desc_iface_super,
+        },
+    },
+};
+
 static const USBDesc desc = {
     .id = {
         .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
@@ -229,45 +315,68 @@ static const USBDesc desc = {
         .iProduct          = STR_PRODUCT,
         .iSerialNumber     = STR_SERIALNUMBER,
     },
-    .high = &desc_device_high,
-    .str  = desc_strings,
+    .high  = &desc_device_high,
+    .super = &desc_device_super,
+    .str   = desc_strings,
 };
 
 /* --------------------------------------------------------------------- */
 
-static UASStatus *usb_uas_alloc_status(uint8_t id, uint16_t tag)
+static bool uas_using_streams(UASDevice *uas)
+{
+    return uas->dev.speed == USB_SPEED_SUPER;
+}
+
+/* --------------------------------------------------------------------- */
+
+static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
 {
     UASStatus *st = g_new0(UASStatus, 1);
 
     st->status.hdr.id = id;
     st->status.hdr.tag = cpu_to_be16(tag);
     st->length = sizeof(uas_ui_header);
+    if (uas_using_streams(uas)) {
+        st->stream = tag;
+    }
     return st;
 }
 
 static void usb_uas_send_status_bh(void *opaque)
 {
     UASDevice *uas = opaque;
-    UASStatus *st = QTAILQ_FIRST(&uas->results);
-    USBPacket *p = uas->status;
+    UASStatus *st;
+    USBPacket *p;
 
-    assert(p != NULL);
-    assert(st != NULL);
+    while ((st = QTAILQ_FIRST(&uas->results)) != NULL) {
+        if (uas_using_streams(uas)) {
+            p = uas->status3[st->stream];
+            uas->status3[st->stream] = NULL;
+        } else {
+            p = uas->status2;
+            uas->status2 = NULL;
+        }
+        if (p == NULL) {
+            break;
+        }
 
-    uas->status = NULL;
-    usb_packet_copy(p, &st->status, st->length);
-    QTAILQ_REMOVE(&uas->results, st, next);
-    g_free(st);
+        usb_packet_copy(p, &st->status, 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);
+        p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
+        usb_packet_complete(&uas->dev, p);
+    }
 }
 
 static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
 {
+    USBPacket *p = uas_using_streams(uas) ?
+        uas->status3[st->stream] : uas->status2;
+
     st->length += length;
     QTAILQ_INSERT_TAIL(&uas->results, st, next);
-    if (uas->status) {
+    if (p) {
         /*
          * Just schedule bh make sure any in-flight data transaction
          * is finished before completing (sending) the status packet.
@@ -276,14 +385,14 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
     } else {
         USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN,
                                      UAS_PIPE_ID_STATUS);
-        usb_wakeup(ep);
+        usb_wakeup(ep, st->stream);
     }
 }
 
 static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
                                    uint8_t code, uint16_t add_info)
 {
-    UASStatus *st = usb_uas_alloc_status(UAS_UI_RESPONSE, tag);
+    UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
 
     trace_usb_uas_response(uas->dev.addr, tag, code);
     st->status.response.response_code = code;
@@ -293,7 +402,7 @@ static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
 
 static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
 {
-    UASStatus *st = usb_uas_alloc_status(UAS_UI_SENSE, req->tag);
+    UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_SENSE, req->tag);
     int len, slen = 0;
 
     trace_usb_uas_sense(req->uas->dev.addr, req->tag, status);
@@ -310,7 +419,8 @@ static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
 
 static void usb_uas_queue_read_ready(UASRequest *req)
 {
-    UASStatus *st = usb_uas_alloc_status(UAS_UI_READ_READY, req->tag);
+    UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY,
+                                         req->tag);
 
     trace_usb_uas_read_ready(req->uas->dev.addr, req->tag);
     usb_uas_queue_status(req->uas, st, 0);
@@ -318,7 +428,8 @@ static void usb_uas_queue_read_ready(UASRequest *req)
 
 static void usb_uas_queue_write_ready(UASRequest *req)
 {
-    UASStatus *st = usb_uas_alloc_status(UAS_UI_WRITE_READY, req->tag);
+    UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_WRITE_READY,
+                                         req->tag);
 
     trace_usb_uas_write_ready(req->uas->dev.addr, req->tag);
     usb_uas_queue_status(req->uas, st, 0);
@@ -381,18 +492,22 @@ static void usb_uas_start_next_transfer(UASDevice *uas)
 {
     UASRequest *req;
 
+    if (uas_using_streams(uas)) {
+        return;
+    }
+
     QTAILQ_FOREACH(req, &uas->requests, next) {
         if (req->active || req->complete) {
             continue;
         }
-        if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain == NULL) {
-            uas->datain = req;
+        if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain2 == NULL) {
+            uas->datain2 = req;
             usb_uas_queue_read_ready(req);
             req->active = true;
             return;
         }
-        if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout == NULL) {
-            uas->dataout = req;
+        if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout2 == NULL) {
+            uas->dataout2 = req;
             usb_uas_queue_write_ready(req);
             req->active = true;
             return;
@@ -417,11 +532,11 @@ static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
     UASRequest *req = priv;
     UASDevice *uas = req->uas;
 
-    if (req == uas->datain) {
-        uas->datain = NULL;
+    if (req == uas->datain2) {
+        uas->datain2 = NULL;
     }
-    if (req == uas->dataout) {
-        uas->dataout = NULL;
+    if (req == uas->dataout2) {
+        uas->dataout2 = NULL;
     }
     QTAILQ_REMOVE(&uas->requests, req, next);
     g_free(req);
@@ -522,12 +637,25 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
 {
     UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
     UASRequest *req, *nreq;
+    int i;
 
-    if (uas->status == p) {
-        uas->status = NULL;
+    if (uas->status2 == p) {
+        uas->status2 = NULL;
         qemu_bh_cancel(uas->status_bh);
         return;
     }
+    if (uas_using_streams(uas)) {
+        for (i = 0; i < UAS_MAX_STREAMS; i++) {
+            if (uas->status3[i] == p) {
+                uas->status3[i] = NULL;
+                return;
+            }
+            if (uas->data3[i] == p) {
+                uas->data3[i] = NULL;
+                return;
+            }
+        }
+    }
     QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
         if (req->data == p) {
             req->data = NULL;
@@ -555,9 +683,18 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui)
                           usb_uas_get_lun(req->lun),
                           req->lun >> 32, req->lun & 0xffffffff);
     QTAILQ_INSERT_TAIL(&uas->requests, req, next);
+    if (uas_using_streams(uas) && uas->data3[req->tag] != NULL) {
+        req->data = uas->data3[req->tag];
+        req->data_async = true;
+        uas->data3[req->tag] = NULL;
+    }
+
     req->req = scsi_req_new(req->dev, req->tag,
                             usb_uas_get_lun(req->lun),
                             ui->command.cdb, req);
+#if 1
+    scsi_req_print(req->req);
+#endif
     len = scsi_req_enqueue(req->req);
     if (len) {
         req->data_size = len;
@@ -669,12 +806,26 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
         }
         break;
     case UAS_PIPE_ID_STATUS:
-        st = QTAILQ_FIRST(&uas->results);
-        if (st == NULL) {
-            assert(uas->status == NULL);
-            uas->status = p;
-            p->status = USB_RET_ASYNC;
-            break;
+        if (p->stream) {
+            QTAILQ_FOREACH(st, &uas->results, next) {
+                if (st->stream == p->stream) {
+                    break;
+                }
+            }
+            if (st == NULL) {
+                assert(uas->status3[p->stream] == NULL);
+                uas->status3[p->stream] = p;
+                p->status = USB_RET_ASYNC;
+                break;
+            }
+        } else {
+            st = QTAILQ_FIRST(&uas->results);
+            if (st == NULL) {
+                assert(uas->status2 == NULL);
+                uas->status2 = p;
+                p->status = USB_RET_ASYNC;
+                break;
+            }
         }
         usb_packet_copy(p, &st->status, st->length);
         QTAILQ_REMOVE(&uas->results, st, next);
@@ -682,11 +833,23 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
         break;
     case UAS_PIPE_ID_DATA_IN:
     case UAS_PIPE_ID_DATA_OUT:
-        req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout;
+        if (p->stream) {
+            req = usb_uas_find_request(uas, p->stream);
+        } else {
+            req = (p->ep->nr == UAS_PIPE_ID_DATA_IN)
+                ? uas->datain2 : uas->dataout2;
+        }
         if (req == NULL) {
-            fprintf(stderr, "%s: no inflight request\n", __func__);
-            p->status = USB_RET_STALL;
-            break;
+            if (p->stream) {
+                assert(uas->data3[p->stream] == NULL);
+                uas->data3[p->stream] = p;
+                p->status = USB_RET_ASYNC;
+                break;
+            } else {
+                fprintf(stderr, "%s: no inflight request\n", __func__);
+                p->status = USB_RET_STALL;
+                break;
+            }
         }
         scsi_req_ref(req->req);
         req->data = p;
index ab9fa2ef48923bd20b8d7d035dbd9b14f0f32a05..3be5cdefdaa722e43b04140fd685ba9c2567187c 100644 (file)
@@ -138,7 +138,7 @@ static void usb_mouse_event(void *opaque,
     s->dz += dz1;
     s->buttons_state = buttons_state;
     s->changed = 1;
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static void usb_wacom_event(void *opaque,
@@ -152,7 +152,7 @@ static void usb_wacom_event(void *opaque,
     s->dz += dz;
     s->buttons_state = buttons_state;
     s->changed = 1;
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static inline int int_clamp(int val, int vmin, int vmax)
index 70406592ef47fa3c396adc1fda05c7a592aa83d4..5176251cb44640d358206c382225f5dffcccf803 100644 (file)
@@ -874,7 +874,8 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
     return 0;
 }
 
-static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
+static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
+                                 unsigned int stream)
 {
     EHCIState *s = container_of(bus, EHCIState, bus);
     uint32_t portsc = s->portsc[ep->dev->port->index];
@@ -1420,7 +1421,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
         }
 
         spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
-        usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr, spd,
+        usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd,
                          (p->qtd.token & QTD_TOKEN_IOC) != 0);
         usb_packet_map(&p->packet, &p->sgl);
         p->async = EHCI_ASYNC_INITIALIZED;
@@ -1493,7 +1494,7 @@ static int ehci_process_itd(EHCIState *ehci,
             dev = ehci_find_device(ehci, devaddr);
             ep = usb_ep_get(dev, pid, endp);
             if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
-                usb_packet_setup(&ehci->ipacket, pid, ep, addr, false,
+                usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
                                  (itd->transact[i] & ITD_XACT_IOC) != 0);
                 usb_packet_map(&ehci->ipacket, &ehci->isgl);
                 usb_handle_packet(dev, &ehci->ipacket);
index 64e9e834bf150d14ff20e64d3cc4ae4d33abe0b3..7968e17c3474027b3add19ae584a16130be67eb5 100644 (file)
@@ -625,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
     /* A wild guess on the FADDR semantics... */
     dev = usb_find_device(&s->port, ep->faddr[idx]);
     uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
-    usb_packet_setup(&ep->packey[dir].p, pid, uep,
+    usb_packet_setup(&ep->packey[dir].p, pid, uep, 0,
                      (dev->addr << 16) | (uep->nr << 8) | pid, false, true);
     usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
     ep->packey[dir].ep = ep;
index dd9967b13d888776c4d37b2e0219b4d3d92f566f..51241cda78cca93ed580938b13baf9b990ad0a36 100644 (file)
@@ -830,7 +830,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
                        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_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
         usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
         usb_handle_packet(dev, &ohci->usb_packet);
         if (ohci->usb_packet.status == USB_RET_ASYNC) {
@@ -1034,7 +1034,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
         }
         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, !flag_r,
+        usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
                          OHCI_BM(td.flags, TD_DI) == 0);
         usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
         usb_handle_packet(dev, &ohci->usb_packet);
index 60645aa21ff1566ee7b17760942d62a2432307ee..f8c42864d14acf8f8b0f7f5027762fc34807d116 100644 (file)
@@ -879,7 +879,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
 
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
-    usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd,
+    usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
                      (td->ctrl & TD_CTRL_IOC) != 0);
     qemu_sglist_add(&async->sgl, td->buffer, max_len);
     usb_packet_map(&async->packet, &async->sgl);
index 5fb0c488e815a486060d6b883ec9a30ad24370b7..07afdeef5b8d074f066e6f5003fed512fb0a4033 100644 (file)
@@ -34,8 +34,8 @@
 #else
 #define DPRINTF(...) do {} while (0)
 #endif
-#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
-                             __func__, __LINE__); abort(); } while (0)
+#define FIXME(_msg) do { fprintf(stderr, "FIXME %s:%d %s\n", \
+                                 __func__, __LINE__, _msg); abort(); } while (0)
 
 #define MAXPORTS_2 15
 #define MAXPORTS_3 15
@@ -301,6 +301,8 @@ typedef enum TRBCCode {
 #define SLOT_CONTEXT_ENTRIES_SHIFT 27
 
 typedef struct XHCIState XHCIState;
+typedef struct XHCIStreamContext XHCIStreamContext;
+typedef struct XHCIEPContext XHCIEPContext;
 
 #define get_field(data, field)                  \
     (((data) >> field##_SHIFT) & field##_MASK)
@@ -351,6 +353,7 @@ typedef struct XHCITransfer {
     unsigned int iso_pkts;
     unsigned int slotid;
     unsigned int epid;
+    unsigned int streamid;
     bool in_xfer;
     bool iso_xfer;
 
@@ -367,7 +370,14 @@ typedef struct XHCITransfer {
     uint64_t mfindex_kick;
 } XHCITransfer;
 
-typedef struct XHCIEPContext {
+struct XHCIStreamContext {
+    dma_addr_t pctx;
+    unsigned int sct;
+    XHCIRing ring;
+    XHCIStreamContext *sstreams;
+};
+
+struct XHCIEPContext {
     XHCIState *xhci;
     unsigned int slotid;
     unsigned int epid;
@@ -382,11 +392,17 @@ typedef struct XHCIEPContext {
     unsigned int max_psize;
     uint32_t state;
 
+    /* streams */
+    unsigned int max_pstreams;
+    bool         lsa;
+    unsigned int nr_pstreams;
+    XHCIStreamContext *pstreams;
+
     /* iso xfer scheduling */
     unsigned int interval;
     int64_t mfindex_last;
     QEMUTimer *kick_timer;
-} XHCIEPContext;
+};
 
 typedef struct XHCISlot {
     bool enabled;
@@ -482,7 +498,7 @@ enum xhci_flags {
 };
 
 static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
-                         unsigned int epid);
+                         unsigned int epid, unsigned int streamid);
 static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
                                 unsigned int epid);
 static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
@@ -1068,18 +1084,116 @@ static void xhci_stop(XHCIState *xhci)
     xhci->crcr_low &= ~CRCR_CRR;
 }
 
+static XHCIStreamContext *xhci_alloc_stream_contexts(unsigned count,
+                                                     dma_addr_t base)
+{
+    XHCIStreamContext *stctx;
+    unsigned int i;
+
+    stctx = g_new0(XHCIStreamContext, count);
+    for (i = 0; i < count; i++) {
+        stctx[i].pctx = base + i * 16;
+        stctx[i].sct = -1;
+    }
+    return stctx;
+}
+
+static void xhci_reset_streams(XHCIEPContext *epctx)
+{
+    unsigned int i;
+
+    for (i = 0; i < epctx->nr_pstreams; i++) {
+        epctx->pstreams[i].sct = -1;
+        g_free(epctx->pstreams[i].sstreams);
+    }
+}
+
+static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base)
+{
+    assert(epctx->pstreams == NULL);
+    epctx->nr_pstreams = 2 << epctx->max_pstreams;
+    epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base);
+}
+
+static void xhci_free_streams(XHCIEPContext *epctx)
+{
+    int i;
+
+    assert(epctx->pstreams != NULL);
+
+    if (!epctx->lsa) {
+        for (i = 0; i < epctx->nr_pstreams; i++) {
+            g_free(epctx->pstreams[i].sstreams);
+        }
+    }
+    g_free(epctx->pstreams);
+    epctx->pstreams = NULL;
+    epctx->nr_pstreams = 0;
+}
+
+static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
+                                           unsigned int streamid,
+                                           uint32_t *cc_error)
+{
+    XHCIStreamContext *sctx;
+    dma_addr_t base;
+    uint32_t ctx[2], sct;
+
+    assert(streamid != 0);
+    if (epctx->lsa) {
+        if (streamid >= epctx->nr_pstreams) {
+            *cc_error = CC_INVALID_STREAM_ID_ERROR;
+            return NULL;
+        }
+        sctx = epctx->pstreams + streamid;
+    } else {
+        FIXME("secondary streams not implemented yet");
+    }
+
+    if (sctx->sct == -1) {
+        xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx));
+        fprintf(stderr, "%s: init sctx #%d @ " DMA_ADDR_FMT ": %08x %08x\n",
+                __func__, streamid, sctx->pctx, ctx[0], ctx[1]);
+        sct = (ctx[0] >> 1) & 0x07;
+        if (epctx->lsa && sct != 1) {
+            *cc_error = CC_INVALID_STREAM_TYPE_ERROR;
+            return NULL;
+        }
+        sctx->sct = sct;
+        base = xhci_addr64(ctx[0] & ~0xf, ctx[1]);
+        xhci_ring_init(epctx->xhci, &sctx->ring, base);
+    }
+    return sctx;
+}
+
 static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
-                              uint32_t state)
+                              XHCIStreamContext *sctx, uint32_t state)
 {
     uint32_t ctx[5];
+    uint32_t ctx2[2];
 
+    fprintf(stderr, "%s: epid %d, state %d\n",
+            __func__, epctx->epid, state);
     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]);
+
+    /* update ring dequeue ptr */
+    if (epctx->nr_pstreams) {
+        if (sctx != NULL) {
+            xhci_dma_read_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
+            ctx2[0] &= 0xe;
+            ctx2[0] |= sctx->ring.dequeue | sctx->ring.ccs;
+            ctx2[1] = (sctx->ring.dequeue >> 16) >> 16;
+            xhci_dma_write_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
+        }
+    } else {
+        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]);
+    }
+
     xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
     epctx->state = state;
 }
@@ -1087,7 +1201,7 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
 static void xhci_ep_kick_timer(void *opaque)
 {
     XHCIEPContext *epctx = opaque;
-    xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid);
+    xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0);
 }
 
 static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
@@ -1117,16 +1231,22 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
     slot->eps[epid-1] = epctx;
 
     dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
-    xhci_ring_init(xhci, &epctx->ring, dequeue);
-    epctx->ring.ccs = ctx[2] & 1;
 
     epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
     DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type);
     epctx->pctx = pctx;
     epctx->max_psize = ctx[1]>>16;
     epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
+    epctx->max_pstreams = (ctx[0] >> 10) & 0xf;
+    epctx->lsa = (ctx[0] >> 15) & 1;
     DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
             epid/2, epid%2, epctx->max_psize);
+    if (epctx->max_pstreams) {
+        xhci_alloc_streams(epctx, dequeue);
+    } else {
+        xhci_ring_init(xhci, &epctx->ring, dequeue);
+        epctx->ring.ccs = ctx[2] & 1;
+    }
     for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
         usb_packet_init(&epctx->transfers[i].packet);
     }
@@ -1227,7 +1347,11 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
 
     epctx = slot->eps[epid-1];
 
-    xhci_set_ep_state(xhci, epctx, EP_DISABLED);
+    if (epctx->nr_pstreams) {
+        xhci_free_streams(epctx);
+    }
+
+    xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED);
 
     qemu_free_timer(epctx->kick_timer);
     g_free(epctx);
@@ -1264,7 +1388,11 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
 
     epctx = slot->eps[epid-1];
 
-    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+    xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
+
+    if (epctx->nr_pstreams) {
+        xhci_reset_streams(epctx);
+    }
 
     return CC_SUCCESS;
 }
@@ -1315,16 +1443,22 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
         return CC_USB_TRANSACTION_ERROR;
     }
 
-    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+    xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
+
+    if (epctx->nr_pstreams) {
+        xhci_reset_streams(epctx);
+    }
 
     return CC_SUCCESS;
 }
 
 static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
-                                    unsigned int epid, uint64_t pdequeue)
+                                    unsigned int epid, unsigned int streamid,
+                                    uint64_t pdequeue)
 {
     XHCISlot *slot;
     XHCIEPContext *epctx;
+    XHCIStreamContext *sctx;
     dma_addr_t dequeue;
 
     assert(slotid >= 1 && slotid <= xhci->numslots);
@@ -1334,7 +1468,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
         return CC_TRB_ERROR;
     }
 
-    trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue);
+    trace_usb_xhci_ep_set_dequeue(slotid, epid, streamid, pdequeue);
     dequeue = xhci_mask64(pdequeue);
 
     slot = &xhci->slots[slotid-1];
@@ -1346,16 +1480,26 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
 
     epctx = slot->eps[epid-1];
 
-
     if (epctx->state != EP_STOPPED) {
         fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
         return CC_CONTEXT_STATE_ERROR;
     }
 
-    xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
-    epctx->ring.ccs = dequeue & 1;
+    if (epctx->nr_pstreams) {
+        uint32_t err;
+        sctx = xhci_find_stream(epctx, streamid, &err);
+        if (sctx == NULL) {
+            return err;
+        }
+        xhci_ring_init(xhci, &sctx->ring, dequeue & ~0xf);
+        sctx->ring.ccs = dequeue & 1;
+    } else {
+        sctx = NULL;
+        xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
+        epctx->ring.ccs = dequeue & 1;
+    }
 
-    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+    xhci_set_ep_state(xhci, epctx, sctx, EP_STOPPED);
 
     return CC_SUCCESS;
 }
@@ -1484,12 +1628,22 @@ static void xhci_stall_ep(XHCITransfer *xfer)
     XHCIState *xhci = xfer->xhci;
     XHCISlot *slot = &xhci->slots[xfer->slotid-1];
     XHCIEPContext *epctx = slot->eps[xfer->epid-1];
+    uint32_t err;
+    XHCIStreamContext *sctx;
 
-    epctx->ring.dequeue = xfer->trbs[0].addr;
-    epctx->ring.ccs = xfer->trbs[0].ccs;
-    xhci_set_ep_state(xhci, epctx, EP_HALTED);
-    DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid);
-    DPRINTF("xhci: will continue at "DMA_ADDR_FMT"\n", epctx->ring.dequeue);
+    if (epctx->nr_pstreams) {
+        sctx = xhci_find_stream(epctx, xfer->streamid, &err);
+        if (sctx == NULL) {
+            return;
+        }
+        sctx->ring.dequeue = xfer->trbs[0].addr;
+        sctx->ring.ccs = xfer->trbs[0].ccs;
+        xhci_set_ep_state(xhci, epctx, sctx, EP_HALTED);
+    } else {
+        epctx->ring.dequeue = xfer->trbs[0].addr;
+        epctx->ring.ccs = xfer->trbs[0].ccs;
+        xhci_set_ep_state(xhci, epctx, NULL, EP_HALTED);
+    }
 }
 
 static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
@@ -1518,8 +1672,8 @@ static int xhci_setup_packet(XHCITransfer *xfer)
     }
 
     xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
-    usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr, false,
-                     xfer->int_req);
+    usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid,
+                     xfer->trbs[0].addr, false, xfer->int_req);
     usb_packet_map(&xfer->packet, &xfer->sgl);
     DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
             xfer->packet.pid, dev->addr, ep->nr);
@@ -1572,7 +1726,7 @@ static int xhci_complete_packet(XHCITransfer *xfer)
     default:
         fprintf(stderr, "%s: FIXME: status = %d\n", __func__,
                 xfer->packet.status);
-        FIXME();
+        FIXME("unhandled USB_RET_*");
     }
     return 0;
 }
@@ -1585,7 +1739,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
     trb_setup = &xfer->trbs[0];
     trb_status = &xfer->trbs[xfer->trb_count-1];
 
-    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
+    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
 
     /* at most one Event Data TRB allowed after STATUS */
     if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
@@ -1627,7 +1781,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
 
     xhci_complete_packet(xfer);
     if (!xfer->running_async && !xfer->running_retry) {
-        xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+        xhci_kick_ep(xhci, xfer->slotid, xfer->epid, 0);
     }
     return 0;
 }
@@ -1710,26 +1864,29 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
 
     xhci_complete_packet(xfer);
     if (!xfer->running_async && !xfer->running_retry) {
-        xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+        xhci_kick_ep(xhci, xfer->slotid, xfer->epid, xfer->streamid);
     }
     return 0;
 }
 
 static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
 {
-    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
+    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
     return xhci_submit(xhci, xfer, epctx);
 }
 
-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
+                         unsigned int epid, unsigned int streamid)
 {
+    XHCIStreamContext *stctx;
     XHCIEPContext *epctx;
+    XHCIRing *ring;
     USBEndpoint *ep = NULL;
     uint64_t mfindex;
     int length;
     int i;
 
-    trace_usb_xhci_ep_kick(slotid, epid);
+    trace_usb_xhci_ep_kick(slotid, epid, streamid);
     assert(slotid >= 1 && slotid <= xhci->numslots);
     assert(epid >= 1 && epid <= 31);
 
@@ -1782,14 +1939,28 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
         return;
     }
 
-    xhci_set_ep_state(xhci, epctx, EP_RUNNING);
+
+    if (epctx->nr_pstreams) {
+        uint32_t err;
+        stctx = xhci_find_stream(epctx, streamid, &err);
+        if (stctx == NULL) {
+            return;
+        }
+        ring = &stctx->ring;
+        xhci_set_ep_state(xhci, epctx, stctx, EP_RUNNING);
+    } else {
+        ring = &epctx->ring;
+        streamid = 0;
+        xhci_set_ep_state(xhci, epctx, NULL, EP_RUNNING);
+    }
+    assert(ring->base != 0);
 
     while (1) {
         XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
         if (xfer->running_async || xfer->running_retry) {
             break;
         }
-        length = xhci_ring_chain_length(xhci, &epctx->ring);
+        length = xhci_ring_chain_length(xhci, ring);
         if (length < 0) {
             break;
         } else if (length == 0) {
@@ -1808,11 +1979,12 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
         xfer->trb_count = length;
 
         for (i = 0; i < length; i++) {
-            assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL));
+            assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL));
         }
         xfer->xhci = xhci;
         xfer->epid = epid;
         xfer->slotid = slotid;
+        xfer->streamid = streamid;
 
         if (epid == 1) {
             if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
@@ -1977,7 +2149,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
         DPRINTF("xhci: device address is %d\n", slot->devaddr);
         usb_device_reset(dev);
         usb_packet_setup(&p, USB_TOKEN_OUT,
-                         usb_ep_get(dev, USB_TOKEN_OUT, 0),
+                         usb_ep_get(dev, USB_TOKEN_OUT, 0), 0,
                          0, false, false);
         usb_device_handle_control(dev, &p,
                                   DeviceOutRequest | USB_REQ_SET_ADDRESS,
@@ -2357,11 +2529,14 @@ static void xhci_process_commands(XHCIState *xhci)
             }
             break;
         case CR_SET_TR_DEQUEUE:
+            fprintf(stderr, "%s: CR_SET_TR_DEQUEUE\n", __func__);
             slotid = xhci_get_slot(xhci, &event, &trb);
             if (slotid) {
                 unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
                     & TRB_CR_EPID_MASK;
-                event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid,
+                unsigned int streamid = (trb.status >> 16) & 0xffff;
+                event.ccode = xhci_set_ep_dequeue(xhci, slotid,
+                                                  epid, streamid,
                                                   trb.parameter);
             }
             break;
@@ -2554,9 +2729,9 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
         break;
     case 0x10: /* HCCPARAMS */
         if (sizeof(dma_addr_t) == 4) {
-            ret = 0x00081000;
+            ret = 0x00087000;
         } else {
-            ret = 0x00081001;
+            ret = 0x00087001;
         }
         break;
     case 0x14: /* DBOFF */
@@ -2880,6 +3055,7 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
                                 uint64_t val, unsigned size)
 {
     XHCIState *xhci = ptr;
+    unsigned int epid, streamid;
 
     trace_usb_xhci_doorbell_write(reg, val);
 
@@ -2898,13 +3074,15 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
                     (uint32_t)val);
         }
     } else {
+        epid = val & 0xff;
+        streamid = (val >> 16) & 0xffff;
         if (reg > xhci->numslots) {
             fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg);
-        } else if (val > 31) {
+        } else if (epid > 31) {
             fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n",
                     (int)reg, (uint32_t)val);
         } else {
-            xhci_kick_ep(xhci, reg, val);
+            xhci_kick_ep(xhci, reg, epid, streamid);
         }
     }
 }
@@ -2988,7 +3166,7 @@ static void xhci_complete(USBPort *port, USBPacket *packet)
         return;
     }
     xhci_complete_packet(xfer);
-    xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
+    xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid);
 }
 
 static void xhci_child_detach(USBPort *uport, USBDevice *child)
@@ -3033,7 +3211,8 @@ static int xhci_find_epid(USBEndpoint *ep)
     }
 }
 
-static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
+static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
+                                 unsigned int stream)
 {
     XHCIState *xhci = container_of(bus, XHCIState, bus);
     int slotid;
@@ -3044,7 +3223,7 @@ static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
         DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
         return;
     }
-    xhci_kick_ep(xhci, slotid, xhci_find_epid(ep));
+    xhci_kick_ep(xhci, slotid, xhci_find_epid(ep), stream);
 }
 
 static USBBusOps xhci_bus_ops = {
index 07f0e01cc004296295a8beda816437d5207cbaf7..39f22810b394db0909f99b932509ef82eb4ddb41 100644 (file)
@@ -637,9 +637,3 @@ void usb_host_info(Monitor *mon, const QDict *qdict)
 {
     usb_host_scan(mon, usb_host_info_device);
 }
-
-/* XXX add this */
-int usb_host_device_close(const char *devname)
-{
-    return 0;
-}
diff --git a/hw/usb/host-legacy.c b/hw/usb/host-legacy.c
new file mode 100644 (file)
index 0000000..3a5f705
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Linux host USB redirector
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Copyright (c) 2008 Max Krasnyansky
+ *      Support for host device auto connect & disconnect
+ *      Major rewrite to support fully async operation
+ *
+ * Copyright 2008 TJ <linux@tjworld.net>
+ *      Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
+ *      to the legacy /proc/bus/usb USB device discovery and handling
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "hw/usb.h"
+#include "hw/usb/host.h"
+
+/*
+ * Autoconnect filter
+ * Format:
+ *    auto:bus:dev[:vid:pid]
+ *    auto:bus.dev[:vid:pid]
+ *
+ *    bus  - bus number    (dec, * means any)
+ *    dev  - device number (dec, * means any)
+ *    vid  - vendor id     (hex, * means any)
+ *    pid  - product id    (hex, * means any)
+ *
+ *    See 'lsusb' output.
+ */
+static int parse_filter(const char *spec, struct USBAutoFilter *f)
+{
+    enum { BUS, DEV, VID, PID, DONE };
+    const char *p = spec;
+    int i;
+
+    f->bus_num    = 0;
+    f->addr       = 0;
+    f->vendor_id  = 0;
+    f->product_id = 0;
+
+    for (i = BUS; i < DONE; i++) {
+        p = strpbrk(p, ":.");
+        if (!p) {
+            break;
+        }
+        p++;
+
+        if (*p == '*') {
+            continue;
+        }
+        switch (i) {
+        case BUS:
+            f->bus_num = strtol(p, NULL, 10);
+            break;
+        case DEV:
+            f->addr    = strtol(p, NULL, 10);
+            break;
+        case VID:
+            f->vendor_id  = strtol(p, NULL, 16);
+            break;
+        case PID:
+            f->product_id = strtol(p, NULL, 16);
+            break;
+        }
+    }
+
+    if (i < DEV) {
+        fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
+        return -1;
+    }
+
+    return 0;
+}
+
+USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
+{
+    struct USBAutoFilter filter;
+    USBDevice *dev;
+    char *p;
+
+    dev = usb_create(bus, "usb-host");
+
+    if (strstr(devname, "auto:")) {
+        if (parse_filter(devname, &filter) < 0) {
+            goto fail;
+        }
+    } else {
+        p = strchr(devname, '.');
+        if (p) {
+            filter.bus_num    = strtoul(devname, NULL, 0);
+            filter.addr       = strtoul(p + 1, NULL, 0);
+            filter.vendor_id  = 0;
+            filter.product_id = 0;
+        } else {
+            p = strchr(devname, ':');
+            if (p) {
+                filter.bus_num    = 0;
+                filter.addr       = 0;
+                filter.vendor_id  = strtoul(devname, NULL, 16);
+                filter.product_id = strtoul(p + 1, NULL, 16);
+            } else {
+                goto fail;
+            }
+        }
+    }
+
+    qdev_prop_set_uint32(&dev->qdev, "hostbus",   filter.bus_num);
+    qdev_prop_set_uint32(&dev->qdev, "hostaddr",  filter.addr);
+    qdev_prop_set_uint32(&dev->qdev, "vendorid",  filter.vendor_id);
+    qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
+    qdev_init_nofail(&dev->qdev);
+    return dev;
+
+fail:
+    qdev_free(&dev->qdev);
+    return NULL;
+}
+
+static void usb_host_register_types(void)
+{
+    usb_legacy_register("usb-host", "host", usb_host_device_open);
+}
+
+type_init(usb_host_register_types)
index a2cff8a74dd426139183dfe6a7a893081996b651..b67aeba0964a6756fbe0754e551bbd54f9a315b1 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/version.h>
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
+#include "hw/usb/host.h"
 
 /* We redefine it to avoid version problems */
 struct usb_ctrltransfer {
@@ -87,14 +88,6 @@ struct endp_data {
     int inflight;
 };
 
-struct USBAutoFilter {
-    uint32_t bus_num;
-    uint32_t addr;
-    char     *port;
-    uint32_t vendor_id;
-    uint32_t product_id;
-};
-
 enum USBHostDeviceOptions {
     USB_HOST_OPT_PIPELINE,
 };
@@ -131,7 +124,6 @@ typedef struct USBHostDevice {
 static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
 
 static int usb_host_close(USBHostDevice *dev);
-static int parse_filter(const char *spec, struct USBAutoFilter *f);
 static void usb_host_auto_check(void *unused);
 static int usb_host_read_file(char *line, size_t line_size,
                             const char *device_file, const char *device_name);
@@ -1544,75 +1536,10 @@ static const TypeInfo usb_host_dev_info = {
 static void usb_host_register_types(void)
 {
     type_register_static(&usb_host_dev_info);
-    usb_legacy_register("usb-host", "host", usb_host_device_open);
 }
 
 type_init(usb_host_register_types)
 
-USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
-{
-    struct USBAutoFilter filter;
-    USBDevice *dev;
-    char *p;
-
-    dev = usb_create(bus, "usb-host");
-
-    if (strstr(devname, "auto:")) {
-        if (parse_filter(devname, &filter) < 0) {
-            goto fail;
-        }
-    } else {
-        if ((p = strchr(devname, '.'))) {
-            filter.bus_num    = strtoul(devname, NULL, 0);
-            filter.addr       = strtoul(p + 1, NULL, 0);
-            filter.vendor_id  = 0;
-            filter.product_id = 0;
-        } else if ((p = strchr(devname, ':'))) {
-            filter.bus_num    = 0;
-            filter.addr       = 0;
-            filter.vendor_id  = strtoul(devname, NULL, 16);
-            filter.product_id = strtoul(p + 1, NULL, 16);
-        } else {
-            goto fail;
-        }
-    }
-
-    qdev_prop_set_uint32(&dev->qdev, "hostbus",   filter.bus_num);
-    qdev_prop_set_uint32(&dev->qdev, "hostaddr",  filter.addr);
-    qdev_prop_set_uint32(&dev->qdev, "vendorid",  filter.vendor_id);
-    qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
-    qdev_init_nofail(&dev->qdev);
-    return dev;
-
-fail:
-    qdev_free(&dev->qdev);
-    return NULL;
-}
-
-int usb_host_device_close(const char *devname)
-{
-#if 0
-    char product_name[PRODUCT_NAME_SZ];
-    int bus_num, addr;
-    USBHostDevice *s;
-
-    if (strstr(devname, "auto:")) {
-        return usb_host_auto_del(devname);
-    }
-    if (usb_host_find_device(&bus_num, &addr, product_name,
-                                    sizeof(product_name), devname) < 0) {
-        return -1;
-    }
-    s = hostdev_find(bus_num, addr);
-    if (s) {
-        usb_device_delete_addr(s->bus_num, s->dev.addr);
-        return 0;
-    }
-#endif
-
-    return -1;
-}
-
 /*
  * Read sys file-system device file
  *
@@ -1840,56 +1767,6 @@ static void usb_host_auto_check(void *unused)
     qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
 }
 
-/*
- * Autoconnect filter
- * Format:
- *    auto:bus:dev[:vid:pid]
- *    auto:bus.dev[:vid:pid]
- *
- *    bus  - bus number    (dec, * means any)
- *    dev  - device number (dec, * means any)
- *    vid  - vendor id     (hex, * means any)
- *    pid  - product id    (hex, * means any)
- *
- *    See 'lsusb' output.
- */
-static int parse_filter(const char *spec, struct USBAutoFilter *f)
-{
-    enum { BUS, DEV, VID, PID, DONE };
-    const char *p = spec;
-    int i;
-
-    f->bus_num    = 0;
-    f->addr       = 0;
-    f->vendor_id  = 0;
-    f->product_id = 0;
-
-    for (i = BUS; i < DONE; i++) {
-        p = strpbrk(p, ":.");
-        if (!p) {
-            break;
-        }
-        p++;
-
-        if (*p == '*') {
-            continue;
-        }
-        switch(i) {
-        case BUS: f->bus_num = strtol(p, NULL, 10);    break;
-        case DEV: f->addr    = strtol(p, NULL, 10);    break;
-        case VID: f->vendor_id  = strtol(p, NULL, 16); break;
-        case PID: f->product_id = strtol(p, NULL, 16); break;
-        }
-    }
-
-    if (i < DEV) {
-        fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
-        return -1;
-    }
-
-    return 0;
-}
-
 /**********************/
 /* USB host device info */
 
index 8affba76c1f18eb80f5e4b2e2e76d002bae1dc81..28d8032caf7e968a440a179ce6edcd81782181f3 100644 (file)
@@ -45,8 +45,3 @@ USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
 {
     return NULL;
 }
-
-int usb_host_device_close(const char *devname)
-{
-    return 0;
-}
diff --git a/hw/usb/host.h b/hw/usb/host.h
new file mode 100644 (file)
index 0000000..048ff3b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Linux host USB redirector
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Copyright (c) 2008 Max Krasnyansky
+ *      Support for host device auto connect & disconnect
+ *      Major rewrite to support fully async operation
+ *
+ * Copyright 2008 TJ <linux@tjworld.net>
+ *      Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
+ *      to the legacy /proc/bus/usb USB device discovery and handling
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_USB_HOST_H
+#define QEMU_USB_HOST_H
+
+struct USBAutoFilter {
+    uint32_t bus_num;
+    uint32_t addr;
+    char     *port;
+    uint32_t vendor_id;
+    uint32_t product_id;
+};
+
+#endif /* QEMU_USB_HOST_H */
index 8c0ead07c5f45494ac6ae8f709af14025be7913c..c519b9b92a650429a8da7fbf3dc83ca294dbdf71 100644 (file)
@@ -737,7 +737,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
                                       uint8_t ep)
 {
     struct usb_redir_bulk_packet_header bulk_packet;
-    size_t size = (p->combined) ? p->combined->iov.size : p->iov.size;
+    size_t size = usb_packet_size(p);
     const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
 
     if (usbredir_already_in_flight(dev, p->id)) {
@@ -771,12 +771,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
                                         &bulk_packet, NULL, 0);
     } else {
         uint8_t buf[size];
-        if (p->combined) {
-            iov_to_buf(p->combined->iov.iov, p->combined->iov.niov,
-                       0, buf, size);
-        } else {
-            usb_packet_copy(p, buf, size);
-        }
+        usb_packet_copy(p, buf, size);
         usbredir_log_data(dev, "bulk data out:", buf, size);
         usbredirparser_send_bulk_packet(dev->parser, p->id,
                                         &bulk_packet, buf, size);
@@ -1830,7 +1825,7 @@ 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;
+        size_t size = usb_packet_size(p);
         usbredir_handle_status(dev, p, bulk_packet->status);
         if (data_len > 0) {
             usbredir_log_data(dev, "bulk data in:", data, data_len);
@@ -1840,12 +1835,7 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
                 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);
-            }
+            usb_packet_copy(p, data, data_len);
         }
         p->actual_length = len;
         if (p->pid == USB_TOKEN_IN && p->ep->pipeline) {
@@ -1907,7 +1897,7 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
         }
 
         if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
-            usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f));
+            usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
         }
 
         /* bufp_alloc also adds the packet to the ep queue */
index e2ba7f208c6b06a25f9e3a58a031181daa63136d..1caf23d7b6561ea2d9ad47c064b56cf1b0e7a897 100644 (file)
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1643,6 +1643,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     uint8_t *d;
     uint32_t v, addr1, addr;
     vga_draw_line_func *vga_draw_line;
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    static const bool byteswap = false;
+#else
+    static const bool byteswap = true;
+#endif
 
     full_update |= update_basic_params(s);
 
@@ -1685,18 +1690,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         disp_width != s->last_width ||
         height != s->last_height ||
         s->last_depth != depth) {
-#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
-        if (depth == 16 || depth == 32) {
-#else
-        if (depth == 32) {
-#endif
+        if (depth == 32 || (depth == 16 && !byteswap)) {
             qemu_free_displaysurface(s->ds);
             s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
                     s->line_offset,
-                    s->vram_ptr + (s->start_addr * 4));
-#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
-            s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
-#endif
+                    s->vram_ptr + (s->start_addr * 4), byteswap);
             dpy_gfx_resize(s->ds);
         } else {
             qemu_console_resize(s->ds, disp_width, height);
@@ -1715,7 +1713,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         s->ds->surface = qemu_create_displaysurface_from(disp_width,
                 height, depth,
                 s->line_offset,
-                s->vram_ptr + (s->start_addr * 4));
+                s->vram_ptr + (s->start_addr * 4), byteswap);
         dpy_gfx_setdata(s->ds);
     }
 
index cd15ee40a8775966e7f98dc88d5c8c5e843b14a5..8fc201bfb96ed54f1ff28aa7750f9b44095364db 100644 (file)
@@ -1074,7 +1074,7 @@ static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch,
                                  ds_get_height(s->vga.ds),
                                  32,
                                  ds_get_linesize(s->vga.ds),
-                                 s->vga.vram_ptr);
+                                 s->vga.vram_ptr, false);
         ppm_save(filename, ds, errp);
         g_free(ds);
     }
index 903efd30736d905be7b42ebc9ff804f302a1f6eb..7f1f6b464324a677949627613ed482789719ebf6 100644 (file)
@@ -756,7 +756,8 @@ static void xenfb_update(void *opaque)
             qemu_free_displaysurface(xenfb->c.ds);
             xenfb->c.ds->surface = qemu_create_displaysurface_from
                 (xenfb->width, xenfb->height, xenfb->depth,
-                 xenfb->row_stride, xenfb->pixels + xenfb->offset);
+                 xenfb->row_stride, xenfb->pixels + xenfb->offset,
+                 false);
             break;
         default:
             /* we must convert stuff */
index 34e344ce2c5fae286c430b6ceb7fd649717013c6..e5d9251b8b6f51847a88380b9a6ea5e63137ea09 100644 (file)
@@ -869,9 +869,11 @@ static int xilinx_enet_init(SysBusDevice *dev)
 static void xilinx_enet_initfn(Object *obj)
 {
     struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+    Error *errp = NULL;
 
     object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
-                             (Object **) &s->tx_dev, NULL);
+                             (Object **) &s->tx_dev, &errp);
+    assert_no_error(errp);
 }
 
 static Property xilinx_enet_properties[] = {
index 8eda9245990121966c387c80c3d8ba031fa43f34..5b54d383fcbabc517c8ba8cbadd71fca05127d80 100644 (file)
@@ -63,6 +63,9 @@ typedef struct AioContext {
 
     /* Used for aio_notify.  */
     EventNotifier notifier;
+
+    /* GPollFDs for aio_poll() */
+    GArray *pollfds;
 } AioContext;
 
 /* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
index ae64590cdfa69b6bd44889cc17ce0aa2b8122480..3dc96568ac49cc9b669e07fc014f6137a8f80517 100644 (file)
@@ -184,7 +184,7 @@ typedef struct CPUWatchpoint {
     struct GDBRegisterState *gdb_regs;                                  \
                                                                         \
     /* Core interrupt code */                                           \
-    jmp_buf jmp_env;                                                    \
+    sigjmp_buf jmp_env;                                                 \
     int exception_index;                                                \
                                                                         \
     CPUArchState *next_cpu; /* next CPU sharing TB cache */                 \
index 5a46555112aa8c8ed98767dad3a93b795a31b6fe..452700329e59912e5e058b40e8acb30bbb8e7497 100644 (file)
@@ -126,14 +126,6 @@ static inline void qemu_log_set_file(FILE *f)
     qemu_logfile = f;
 }
 
-/* Set up a new log file, only if none is set */
-static inline void qemu_log_try_set_file(FILE *f)
-{
-    if (!qemu_logfile) {
-        qemu_logfile = f;
-    }
-}
-
 /* define log items */
 typedef struct QEMULogItem {
     int mask;
index e8059c3d0a72d4063ec5b2454684964eafd32348..09952885a90d1cf6eced481fc4d9e1314fd4e09c 100644 (file)
@@ -297,8 +297,8 @@ void qemu_mutex_unlock_iothread(void);
 /* internal interfaces */
 
 void qemu_fd_register(int fd);
-void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
-void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
+void qemu_iohandler_fill(GArray *pollfds);
+void qemu_iohandler_poll(GArray *pollfds, int rc);
 
 QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
 void qemu_bh_schedule_idle(QEMUBH *bh);
index bf9edeb9ab39e86d51f2da275bccdd97184e9cb8..71f5fa0a9166c17c0ed76621cdd851fb6e9e2cac 100644 (file)
 # undef setjmp
 # define setjmp(env) _setjmp(env, NULL)
 #endif
+/* QEMU uses sigsetjmp()/siglongjmp() as the portable way to specify
+ * "longjmp and don't touch the signal masks". Since we know that the
+ * savemask parameter will always be zero we can safely define these
+ * in terms of setjmp/longjmp on Win32.
+ */
+#define sigjmp_buf jmp_buf
+#define sigsetjmp(env, savemask) setjmp(env)
+#define siglongjmp(env, val) longjmp(env, val)
 
 /* Declaration of ffs() is missing in MinGW's strings.h. */
 int ffs(int i);
index 1d9599e5f497e6d281fc32ac790efcf87152e316..b19ec952b4196c88cf2ca2ae9bbef2bbb158bb25 100644 (file)
@@ -89,12 +89,12 @@ typedef enum DisplayType
     DT_DEFAULT,
     DT_CURSES,
     DT_SDL,
+    DT_GTK,
     DT_NOGRAPHIC,
     DT_NONE,
 } DisplayType;
 
 extern int autostart;
-extern int bios_size;
 
 typedef enum {
     VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
index fc23baa06b35c911b2ace381d90be92850b3c21d..c42bca6efe99ca1bad373ebbc2bb2a373e4b5241 100644 (file)
@@ -184,7 +184,8 @@ struct DisplayState {
 void register_displaystate(DisplayState *ds);
 DisplayState *get_displaystate(void);
 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
-                                                int linesize, uint8_t *data);
+                                                int linesize, uint8_t *data,
+                                                bool byteswap);
 PixelFormat qemu_different_endianness_pixelformat(int bpp);
 PixelFormat qemu_default_pixelformat(int bpp);
 
@@ -442,7 +443,6 @@ void vga_hw_text_update(console_ch_t *chardata);
 
 int is_graphic_console(void);
 int is_fixedsize_console(void);
-CharDriverState *text_console_init(QemuOpts *opts);
 void text_consoles_set_display(DisplayState *ds);
 void console_select(unsigned int index);
 void console_color_init(DisplayState *ds);
@@ -450,6 +450,11 @@ void qemu_console_resize(DisplayState *ds, int width, int height);
 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
                        int dst_x, int dst_y, int w, int h);
 
+typedef CharDriverState *(VcHandler)(QemuOpts *);
+
+CharDriverState *vc_init(QemuOpts *opts);
+void register_vc_handler(VcHandler *handler);
+
 /* sdl.c */
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
 
@@ -482,4 +487,8 @@ void curses_display_init(DisplayState *ds, int full_screen);
 int index_from_key(const char *key);
 int index_from_keycode(int code);
 
+/* gtk.c */
+void early_gtk_display_init(void);
+void gtk_display_init(DisplayState *ds);
+
 #endif
index 2523adc11d62ce9549e35254a7b92390564afbb6..ae2ef8f9669db23dd004337f382a257e84044ad5 100644 (file)
@@ -39,6 +39,7 @@ typedef struct IOHandlerRecord {
     void *opaque;
     QLIST_ENTRY(IOHandlerRecord) next;
     int fd;
+    int pollfds_idx;
     bool deleted;
 } IOHandlerRecord;
 
@@ -78,6 +79,7 @@ int qemu_set_fd_handler2(int fd,
         ioh->fd_read = fd_read;
         ioh->fd_write = fd_write;
         ioh->opaque = opaque;
+        ioh->pollfds_idx = -1;
         ioh->deleted = 0;
         qemu_notify_event();
     }
@@ -92,38 +94,56 @@ int qemu_set_fd_handler(int fd,
     return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
 }
 
-void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds)
+void qemu_iohandler_fill(GArray *pollfds)
 {
     IOHandlerRecord *ioh;
 
     QLIST_FOREACH(ioh, &io_handlers, next) {
+        int events = 0;
+
         if (ioh->deleted)
             continue;
         if (ioh->fd_read &&
             (!ioh->fd_read_poll ||
              ioh->fd_read_poll(ioh->opaque) != 0)) {
-            FD_SET(ioh->fd, readfds);
-            if (ioh->fd > *pnfds)
-                *pnfds = ioh->fd;
+            events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
         }
         if (ioh->fd_write) {
-            FD_SET(ioh->fd, writefds);
-            if (ioh->fd > *pnfds)
-                *pnfds = ioh->fd;
+            events |= G_IO_OUT | G_IO_ERR;
+        }
+        if (events) {
+            GPollFD pfd = {
+                .fd = ioh->fd,
+                .events = events,
+            };
+            ioh->pollfds_idx = pollfds->len;
+            g_array_append_val(pollfds, pfd);
+        } else {
+            ioh->pollfds_idx = -1;
         }
     }
 }
 
-void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret)
+void qemu_iohandler_poll(GArray *pollfds, int ret)
 {
     if (ret > 0) {
         IOHandlerRecord *pioh, *ioh;
 
         QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
-            if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) {
+            int revents = 0;
+
+            if (!ioh->deleted && ioh->pollfds_idx != -1) {
+                GPollFD *pfd = &g_array_index(pollfds, GPollFD,
+                                              ioh->pollfds_idx);
+                revents = pfd->revents;
+            }
+
+            if (!ioh->deleted && ioh->fd_read &&
+                (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
                 ioh->fd_read(ioh->opaque);
             }
-            if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) {
+            if (!ioh->deleted && ioh->fd_write &&
+                (revents & (G_IO_OUT | G_IO_ERR))) {
                 ioh->fd_write(ioh->opaque);
             }
 
index 6f52ac39bc7f6bfede652230bbad4a80ce44b6c5..8c9b58c14c897766313558bd8839d612fb5749c9 100644 (file)
@@ -117,6 +117,8 @@ void qemu_notify_event(void)
     aio_notify(qemu_aio_context);
 }
 
+static GArray *gpollfds;
+
 int qemu_init_main_loop(void)
 {
     int ret;
@@ -133,6 +135,7 @@ int qemu_init_main_loop(void)
         return ret;
     }
 
+    gpollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
     qemu_aio_context = aio_context_new();
     src = aio_get_g_source(qemu_aio_context);
     g_source_attach(src, NULL);
@@ -140,100 +143,63 @@ int qemu_init_main_loop(void)
     return 0;
 }
 
-static fd_set rfds, wfds, xfds;
-static int nfds;
-static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
-static int n_poll_fds;
 static int max_priority;
 
 #ifndef _WIN32
-static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
-                             fd_set *xfds, uint32_t *cur_timeout)
+static int glib_pollfds_idx;
+static int glib_n_poll_fds;
+
+static void glib_pollfds_fill(uint32_t *cur_timeout)
 {
     GMainContext *context = g_main_context_default();
-    int i;
     int timeout = 0;
+    int n;
 
     g_main_context_prepare(context, &max_priority);
 
-    n_poll_fds = g_main_context_query(context, max_priority, &timeout,
-                                      poll_fds, ARRAY_SIZE(poll_fds));
-    g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
-
-    for (i = 0; i < n_poll_fds; i++) {
-        GPollFD *p = &poll_fds[i];
-
-        if ((p->events & G_IO_IN)) {
-            FD_SET(p->fd, rfds);
-            *max_fd = MAX(*max_fd, p->fd);
-        }
-        if ((p->events & G_IO_OUT)) {
-            FD_SET(p->fd, wfds);
-            *max_fd = MAX(*max_fd, p->fd);
-        }
-        if ((p->events & G_IO_ERR)) {
-            FD_SET(p->fd, xfds);
-            *max_fd = MAX(*max_fd, p->fd);
-        }
-    }
+    glib_pollfds_idx = gpollfds->len;
+    n = glib_n_poll_fds;
+    do {
+        GPollFD *pfds;
+        glib_n_poll_fds = n;
+        g_array_set_size(gpollfds, glib_pollfds_idx + glib_n_poll_fds);
+        pfds = &g_array_index(gpollfds, GPollFD, glib_pollfds_idx);
+        n = g_main_context_query(context, max_priority, &timeout, pfds,
+                                 glib_n_poll_fds);
+    } while (n != glib_n_poll_fds);
 
     if (timeout >= 0 && timeout < *cur_timeout) {
         *cur_timeout = timeout;
     }
 }
 
-static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
-                             bool err)
+static void glib_pollfds_poll(void)
 {
     GMainContext *context = g_main_context_default();
+    GPollFD *pfds = &g_array_index(gpollfds, GPollFD, glib_pollfds_idx);
 
-    if (!err) {
-        int i;
-
-        for (i = 0; i < n_poll_fds; i++) {
-            GPollFD *p = &poll_fds[i];
-
-            if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
-                p->revents |= G_IO_IN;
-            }
-            if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
-                p->revents |= G_IO_OUT;
-            }
-            if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
-                p->revents |= G_IO_ERR;
-            }
-        }
-    }
-
-    if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
+    if (g_main_context_check(context, max_priority, pfds, glib_n_poll_fds)) {
         g_main_context_dispatch(context);
     }
 }
 
 static int os_host_main_loop_wait(uint32_t timeout)
 {
-    struct timeval tv, *tvarg = NULL;
     int ret;
 
-    glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
-
-    if (timeout < UINT32_MAX) {
-        tvarg = &tv;
-        tv.tv_sec = timeout / 1000;
-        tv.tv_usec = (timeout % 1000) * 1000;
-    }
+    glib_pollfds_fill(&timeout);
 
     if (timeout > 0) {
         qemu_mutex_unlock_iothread();
     }
 
-    ret = select(nfds + 1, &rfds, &wfds, &xfds, tvarg);
+    ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout);
 
     if (timeout > 0) {
         qemu_mutex_lock_iothread();
     }
 
-    glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+    glib_pollfds_poll();
     return ret;
 }
 #else
@@ -327,14 +293,67 @@ void qemu_fd_register(int fd)
                    FD_CONNECT | FD_WRITE | FD_OOB);
 }
 
+static int pollfds_fill(GArray *pollfds, fd_set *rfds, fd_set *wfds,
+                        fd_set *xfds)
+{
+    int nfds = -1;
+    int i;
+
+    for (i = 0; i < pollfds->len; i++) {
+        GPollFD *pfd = &g_array_index(pollfds, GPollFD, i);
+        int fd = pfd->fd;
+        int events = pfd->events;
+        if (events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
+            FD_SET(fd, rfds);
+            nfds = MAX(nfds, fd);
+        }
+        if (events & (G_IO_OUT | G_IO_ERR)) {
+            FD_SET(fd, wfds);
+            nfds = MAX(nfds, fd);
+        }
+        if (events & G_IO_PRI) {
+            FD_SET(fd, xfds);
+            nfds = MAX(nfds, fd);
+        }
+    }
+    return nfds;
+}
+
+static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds,
+                         fd_set *wfds, fd_set *xfds)
+{
+    int i;
+
+    for (i = 0; i < pollfds->len; i++) {
+        GPollFD *pfd = &g_array_index(pollfds, GPollFD, i);
+        int fd = pfd->fd;
+        int revents = 0;
+
+        if (FD_ISSET(fd, rfds)) {
+            revents |= G_IO_IN | G_IO_HUP | G_IO_ERR;
+        }
+        if (FD_ISSET(fd, wfds)) {
+            revents |= G_IO_OUT | G_IO_ERR;
+        }
+        if (FD_ISSET(fd, xfds)) {
+            revents |= G_IO_PRI;
+        }
+        pfd->revents = revents & pfd->events;
+    }
+}
+
 static int os_host_main_loop_wait(uint32_t timeout)
 {
     GMainContext *context = g_main_context_default();
-    int select_ret, g_poll_ret, ret, i;
+    GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
+    int select_ret = 0;
+    int g_poll_ret, ret, i, n_poll_fds;
     PollingEntry *pe;
     WaitObjects *w = &wait_objects;
     gint poll_timeout;
     static struct timeval tv0;
+    fd_set rfds, wfds, xfds;
+    int nfds;
 
     /* XXX: need to suppress polling by better using win32 events */
     ret = 0;
@@ -381,11 +400,18 @@ static int os_host_main_loop_wait(uint32_t timeout)
      * improve socket latency.
      */
 
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+    nfds = pollfds_fill(gpollfds, &rfds, &wfds, &xfds);
     if (nfds >= 0) {
         select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0);
         if (select_ret != 0) {
             timeout = 0;
         }
+        if (select_ret > 0) {
+            pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds);
+        }
     }
 
     return select_ret || g_poll_ret;
@@ -402,21 +428,17 @@ int main_loop_wait(int nonblocking)
     }
 
     /* poll any events */
+    g_array_set_size(gpollfds, 0); /* reset for new iteration */
     /* XXX: separate device handlers from system ones */
-    nfds = -1;
-    FD_ZERO(&rfds);
-    FD_ZERO(&wfds);
-    FD_ZERO(&xfds);
-
 #ifdef CONFIG_SLIRP
     slirp_update_timeout(&timeout);
-    slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+    slirp_pollfds_fill(gpollfds);
 #endif
-    qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
+    qemu_iohandler_fill(gpollfds);
     ret = os_host_main_loop_wait(timeout);
-    qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
+    qemu_iohandler_poll(gpollfds, ret);
 #ifdef CONFIG_SLIRP
-    slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+    slirp_pollfds_poll(gpollfds, (ret < 0));
 #endif
 
     qemu_run_all_timers();
index 6a0f2573f5f248a21a8fde53df0f16c0c511d18d..32a6e74fd951748e4e7d2297c165d5f72622604b 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -2740,7 +2740,7 @@ static const mon_cmd_t qmp_cmds[] = {
 /*******************************************************************/
 
 static const char *pch;
-static jmp_buf expr_env;
+static sigjmp_buf expr_env;
 
 #define MD_TLONG 0
 #define MD_I32   1
@@ -3135,7 +3135,7 @@ static const MonitorDef monitor_defs[] = {
 static void expr_error(Monitor *mon, const char *msg)
 {
     monitor_printf(mon, "%s\n", msg);
-    longjmp(expr_env, 1);
+    siglongjmp(expr_env, 1);
 }
 
 /* return 0 if OK, -1 if not found */
@@ -3345,7 +3345,7 @@ static int64_t expr_sum(Monitor *mon)
 static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
 {
     pch = *pp;
-    if (setjmp(expr_env)) {
+    if (sigsetjmp(expr_env, 0)) {
         *pp = pch;
         return -1;
     }
diff --git a/po/Makefile b/po/Makefile
new file mode 100644 (file)
index 0000000..2b4420f
--- /dev/null
@@ -0,0 +1,46 @@
+# This makefile is very special as it's meant to build as part of the build
+# process and also within the source tree to update the translation files.
+
+VERSION=$(shell cat ../VERSION)
+TRANSLATIONS=de_DE it
+SRCS=$(addsuffix .po, $(TRANSLATIONS))
+OBJS=$(addsuffix .mo, $(TRANSLATIONS))
+
+SRC_PATH=..
+
+-include ../config-host.mak
+
+vpath %.po $(SRC_PATH)/po
+
+all:
+       @echo Use 'make update' to update translation files
+       @echo or us 'make build' or 'make install' to build and install
+       @echo the translation files
+
+update: $(SRCS)
+
+build: $(OBJS)
+
+clean:
+       $(RM) $(OBJS)
+
+install: $(OBJS)
+       for obj in $(OBJS); do \
+           base=`basename $$obj .mo`; \
+           $(INSTALL) -d $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES; \
+           $(INSTALL) -m644 $$obj $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES/qemu.mo; \
+       done
+
+%.mo:
+       @msgfmt -o $@ $(SRC_PATH)/po/`basename $@ .mo`.po
+
+messages.po: $(SRC_PATH)/ui/gtk.c
+       @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=1.0.50 --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $<
+
+de_DE.po: messages.po $(SRC_PATH)/ui/gtk.c
+       @msgmerge $@ $< > $@.bak && mv $@.bak $@
+
+it.po: messages.po $(SRC_PATH)/ui/gtk.c
+       @msgmerge $@ $< > $@.bak && mv $@.bak $@
+
+.PHONY: $(SRCS) clean all
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644 (file)
index 0000000..8755783
--- /dev/null
@@ -0,0 +1,41 @@
+# German translation for QEMU.
+# This file is put in the public domain.
+# Kevin Wolf <kwolf@redhat.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"PO-Revision-Date: 2012-02-28 16:00+0100\n"
+"Last-Translator: Kevin Wolf <kwolf@redhat.com>\n"
+"Language-Team: Deutsch <de@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
+
+#: ../ui/gtk.c:990
+msgid "_File"
+msgstr "_Datei"
+
+#: ../ui/gtk.c:1000
+msgid "_View"
+msgstr "_Ansicht"
+
+#: ../ui/gtk.c:1029
+msgid "Zoom To _Fit"
+msgstr "Auf _Fenstergröße skalieren"
+
+#: ../ui/gtk.c:1035
+msgid "Grab On _Hover"
+msgstr "Tastatur _automatisch einfangen"
+
+#: ../ui/gtk.c:1038
+msgid "_Grab Input"
+msgstr "_Eingabegeräte einfangen"
+
+#: ../ui/gtk.c:1064
+msgid "Show _Tabs"
+msgstr "_Tableiste anzeigen"
diff --git a/po/it.po b/po/it.po
new file mode 100644 (file)
index 0000000..7d77fff
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,41 @@
+# Italian translation for QEMU.
+# This file is put in the public domain.
+# Paolo Bonzini <pbonzini@redhat.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"PO-Revision-Date: 2012-02-27 08:23+0100\n"
+"Last-Translator: Paolo Bonzini <pbonzini@redhat.com>\n"
+"Language-Team: Italian <it@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: ../ui/gtk.c:990
+msgid "_File"
+msgstr "_File"
+
+#: ../ui/gtk.c:1000
+msgid "_View"
+msgstr "_Visualizza"
+
+#: ../ui/gtk.c:1029
+msgid "Zoom To _Fit"
+msgstr "Adatta alla _finestra"
+
+#: ../ui/gtk.c:1035
+msgid "Grab On _Hover"
+msgstr "Cattura _automatica input"
+
+#: ../ui/gtk.c:1038
+msgid "_Grab Input"
+msgstr "_Cattura input"
+
+#: ../ui/gtk.c:1064
+msgid "Show _Tabs"
+msgstr "Mostra _tab"
diff --git a/po/messages.po b/po/messages.po
new file mode 100644 (file)
index 0000000..191e81c
--- /dev/null
@@ -0,0 +1,41 @@
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2013-02-08 09:21-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../ui/gtk.c:990
+msgid "_File"
+msgstr ""
+
+#: ../ui/gtk.c:1000
+msgid "_View"
+msgstr ""
+
+#: ../ui/gtk.c:1029
+msgid "Zoom To _Fit"
+msgstr ""
+
+#: ../ui/gtk.c:1035
+msgid "Grab On _Hover"
+msgstr ""
+
+#: ../ui/gtk.c:1038
+msgid "_Grab Input"
+msgstr ""
+
+#: ../ui/gtk.c:1064
+msgid "Show _Tabs"
+msgstr ""
index 7275b5dd6a5b2b0a2f35de1059432dadf968d301..cd7ea25e4c6eb2436fe1e97b3b4e23736e4ec6bb 100644 (file)
 #
 # @fd: #optional file descriptor of an already opened tap
 #
+# @fds: #optional multiple file descriptors of already opened multiqueue capable
+# tap
+#
 # @script: #optional script to initialize the interface
 #
 # @downscript: #optional script to shut down the interface
 #
 # @vhostfd: #optional file descriptor of an already opened vhost net device
 #
+# @vhostfds: #optional file descriptors of multiple already opened vhost net
+# devices
+#
 # @vhostforce: #optional vhost on for non-MSIX virtio guests
 #
 # Since 1.2
index e4b0f5304f505f838fbf7a0d66b4a668a7dedc7d..160decc2f07311d8b37c107266468765c92490c7 100644 (file)
@@ -2980,7 +2980,7 @@ static const struct {
     { .name = "socket",    .open = qemu_chr_open_socket },
     { .name = "udp",       .open = qemu_chr_open_udp },
     { .name = "msmouse",   .open = qemu_chr_open_msmouse },
-    { .name = "vc",        .open = text_console_init },
+    { .name = "vc",        .open = vc_init },
     { .name = "memory",    .open = qemu_chr_open_ringbuf },
 #ifdef _WIN32
     { .name = "file",      .open = qemu_chr_open_win_file_out },
index 4bc9c85d9e8f82fc8949d51031d9aa76eb2785af..2832d821484d1a63703f45c8ac01cfc2d0bd4485 100644 (file)
@@ -1354,7 +1354,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "-net tap[,vlan=n][,name=str],ifname=name\n"
     "                connect the host TAP network interface to VLAN 'n'\n"
 #else
-    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
+    "-net tap[,vlan=n][,name=str][,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off]\n"
     "                connect the host TAP network interface to VLAN 'n'\n"
     "                use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
     "                to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
@@ -1363,6 +1363,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "                use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n"
     "                configure it\n"
     "                use 'fd=h' to connect to an already opened TAP interface\n"
+    "                use 'fds=x:y:...:z' to connect to already opened multiqueue capable TAP interfaces\n"
     "                use 'sndbuf=nbytes' to limit the size of the send buffer (the\n"
     "                default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576')\n"
     "                use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag\n"
@@ -1371,6 +1372,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "                    (only has effect for virtio guests which use MSIX)\n"
     "                use vhostforce=on to force vhost on for non-MSIX virtio guests\n"
     "                use 'vhostfd=h' to connect to an already opened vhost net device\n"
+    "                use 'vhostfds=x:y:...:z to connect to multiple already opened vhost net devices\n"
     "-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper]\n"
     "                connects a host TAP network interface to a host bridge device 'br'\n"
     "                (default=" DEFAULT_BRIDGE_INTERFACE ") using the program 'helper'\n"
index 563e45b0cc0f70d0a1ff1a9df44fee537eb14fa7..3d638ff273e80464ab7d06b890d92dee7a91a3c8 100644 (file)
@@ -245,6 +245,7 @@ static void type_initialize(TypeImpl *ti)
 
         g_assert(parent->class_size <= ti->class_size);
         memcpy(ti->class, parent->class, parent->class_size);
+        ti->class->interfaces = NULL;
 
         for (e = parent->class->interfaces; e; e = e->next) {
             ObjectClass *iface = e->data;
@@ -448,7 +449,8 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
     TypeImpl *type = class->type;
     ObjectClass *ret = NULL;
 
-    if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) {
+    if (type->class->interfaces &&
+            type_is_ancestor(target_type, type_interface)) {
         int found = 0;
         GSList *i;
 
index 0778fe2a420148934ee51a7378b9b82c8e8fa02e..81fe94259d6561074d4f9ee01ca7ab5067ee42fa 100644 (file)
@@ -18,7 +18,7 @@ process_includes () {
 
 f=$src
 while [ -n "$f" ] ; do
-  f=`tr -d '\r' < $f | awk '/^include / {printf "'$src_dir'/%s", $2}'`
+  f=`cat $f | tr -d '\r' | awk '/^include / {printf "'$src_dir'/%s ", $2}'`
   [ $? = 0 ] || exit 1
   all_includes="$all_includes $f"
 done
index 49609c2ad7b424d0114729c1c60a163c587324c2..ceabff81b2cc85f4453a262ddb0a6285bd2aac33 100644 (file)
@@ -17,11 +17,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
 void slirp_cleanup(Slirp *slirp);
 
 void slirp_update_timeout(uint32_t *timeout);
-void slirp_select_fill(int *pnfds,
-                       fd_set *readfds, fd_set *writefds, fd_set *xfds);
+void slirp_pollfds_fill(GArray *pollfds);
 
-void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
-                       int select_error);
+void slirp_pollfds_poll(GArray *pollfds, int select_error);
 
 void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
 
index 66e4f9252fe162052a1c1fc243fb28d0f5cdd361..f2e58cfe2d98268ea4d67af1a7484499506c0519 100644 (file)
@@ -31,7 +31,6 @@ extern int ctty_closed;
 extern char *slirp_tty;
 extern char *exec_shell;
 extern u_int curtime;
-extern fd_set *global_readfds, *global_writefds, *global_xfds;
 extern struct in_addr loopback_addr;
 extern unsigned long loopback_mask;
 extern char *username;
index 0e6e232789cdd5b52c2ca698bfcda00c713a490b..bd9b7cb64436f612083d467899057ede29a25a87 100644 (file)
@@ -39,9 +39,6 @@ static const uint8_t special_ethaddr[ETH_ALEN] = {
 
 static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
 
-/* XXX: suppress those select globals */
-fd_set *global_readfds, *global_writefds, *global_xfds;
-
 u_int curtime;
 static u_int time_fasttimo, last_slowtimo;
 static int do_slowtimo;
@@ -261,7 +258,6 @@ void slirp_cleanup(Slirp *slirp)
 
 #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
 #define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
 
 void slirp_update_timeout(uint32_t *timeout)
 {
@@ -270,156 +266,179 @@ void slirp_update_timeout(uint32_t *timeout)
     }
 }
 
-void slirp_select_fill(int *pnfds,
-                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
+void slirp_pollfds_fill(GArray *pollfds)
 {
     Slirp *slirp;
     struct socket *so, *so_next;
-    int nfds;
 
     if (QTAILQ_EMPTY(&slirp_instances)) {
         return;
     }
 
-    /* fail safe */
-    global_readfds = NULL;
-    global_writefds = NULL;
-    global_xfds = NULL;
-
-    nfds = *pnfds;
-       /*
-        * First, TCP sockets
-        */
-       do_slowtimo = 0;
-
-       QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
-               /*
-                * *_slowtimo needs calling if there are IP fragments
-                * in the fragment queue, or there are TCP connections active
-                */
-               do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
-                   (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
-
-               for (so = slirp->tcb.so_next; so != &slirp->tcb;
-                    so = so_next) {
-                       so_next = so->so_next;
-
-                       /*
-                        * See if we need a tcp_fasttimo
-                        */
-                       if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
-                          time_fasttimo = curtime; /* Flag when we want a fasttimo */
-
-                       /*
-                        * NOFDREF can include still connecting to local-host,
-                        * newly socreated() sockets etc. Don't want to select these.
-                        */
-                       if (so->so_state & SS_NOFDREF || so->s == -1)
-                          continue;
-
-                       /*
-                        * Set for reading sockets which are accepting
-                        */
-                       if (so->so_state & SS_FACCEPTCONN) {
-                                FD_SET(so->s, readfds);
-                               UPD_NFDS(so->s);
-                               continue;
-                       }
-
-                       /*
-                        * Set for writing sockets which are connecting
-                        */
-                       if (so->so_state & SS_ISFCONNECTING) {
-                               FD_SET(so->s, writefds);
-                               UPD_NFDS(so->s);
-                               continue;
-                       }
-
-                       /*
-                        * Set for writing if we are connected, can send more, and
-                        * we have something to send
-                        */
-                       if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
-                               FD_SET(so->s, writefds);
-                               UPD_NFDS(so->s);
-                       }
-
-                       /*
-                        * Set for reading (and urgent data) if we are connected, can
-                        * receive more, and we have room for it XXX /2 ?
-                        */
-                       if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
-                               FD_SET(so->s, readfds);
-                               FD_SET(so->s, xfds);
-                               UPD_NFDS(so->s);
-                       }
-               }
-
-               /*
-                * UDP sockets
-                */
-               for (so = slirp->udb.so_next; so != &slirp->udb;
-                    so = so_next) {
-                       so_next = so->so_next;
-
-                       /*
-                        * See if it's timed out
-                        */
-                       if (so->so_expire) {
-                               if (so->so_expire <= curtime) {
-                                       udp_detach(so);
-                                       continue;
-                               } else
-                                       do_slowtimo = 1; /* Let socket expire */
-                       }
-
-                       /*
-                        * When UDP packets are received from over the
-                        * link, they're sendto()'d straight away, so
-                        * no need for setting for writing
-                        * Limit the number of packets queued by this session
-                        * to 4.  Note that even though we try and limit this
-                        * to 4 packets, the session could have more queued
-                        * if the packets needed to be fragmented
-                        * (XXX <= 4 ?)
-                        */
-                       if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
-                               FD_SET(so->s, readfds);
-                               UPD_NFDS(so->s);
-                       }
-               }
+    /*
+     * First, TCP sockets
+     */
+    do_slowtimo = 0;
 
-                /*
-                 * ICMP sockets
-                 */
-                for (so = slirp->icmp.so_next; so != &slirp->icmp;
-                     so = so_next) {
-                    so_next = so->so_next;
+    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
+        /*
+         * *_slowtimo needs calling if there are IP fragments
+         * in the fragment queue, or there are TCP connections active
+         */
+        do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
+                (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
+
+        for (so = slirp->tcb.so_next; so != &slirp->tcb;
+                so = so_next) {
+            int events = 0;
+
+            so_next = so->so_next;
+
+            so->pollfds_idx = -1;
+
+            /*
+             * See if we need a tcp_fasttimo
+             */
+            if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) {
+                time_fasttimo = curtime; /* Flag when we want a fasttimo */
+            }
 
-                    /*
-                     * See if it's timed out
-                     */
-                    if (so->so_expire) {
-                        if (so->so_expire <= curtime) {
-                            icmp_detach(so);
-                            continue;
-                        } else {
-                            do_slowtimo = 1; /* Let socket expire */
-                        }
-                    }
+            /*
+             * NOFDREF can include still connecting to local-host,
+             * newly socreated() sockets etc. Don't want to select these.
+             */
+            if (so->so_state & SS_NOFDREF || so->s == -1) {
+                continue;
+            }
 
-                    if (so->so_state & SS_ISFCONNECTED) {
-                        FD_SET(so->s, readfds);
-                        UPD_NFDS(so->s);
-                    }
+            /*
+             * Set for reading sockets which are accepting
+             */
+            if (so->so_state & SS_FACCEPTCONN) {
+                GPollFD pfd = {
+                    .fd = so->s,
+                    .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+                };
+                so->pollfds_idx = pollfds->len;
+                g_array_append_val(pollfds, pfd);
+                continue;
+            }
+
+            /*
+             * Set for writing sockets which are connecting
+             */
+            if (so->so_state & SS_ISFCONNECTING) {
+                GPollFD pfd = {
+                    .fd = so->s,
+                    .events = G_IO_OUT | G_IO_ERR,
+                };
+                so->pollfds_idx = pollfds->len;
+                g_array_append_val(pollfds, pfd);
+                continue;
+            }
+
+            /*
+             * Set for writing if we are connected, can send more, and
+             * we have something to send
+             */
+            if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+                events |= G_IO_OUT | G_IO_ERR;
+            }
+
+            /*
+             * Set for reading (and urgent data) if we are connected, can
+             * receive more, and we have room for it XXX /2 ?
+             */
+            if (CONN_CANFRCV(so) &&
+                (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+                events |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
+            }
+
+            if (events) {
+                GPollFD pfd = {
+                    .fd = so->s,
+                    .events = events,
+                };
+                so->pollfds_idx = pollfds->len;
+                g_array_append_val(pollfds, pfd);
+            }
+        }
+
+        /*
+         * UDP sockets
+         */
+        for (so = slirp->udb.so_next; so != &slirp->udb;
+                so = so_next) {
+            so_next = so->so_next;
+
+            so->pollfds_idx = -1;
+
+            /*
+             * See if it's timed out
+             */
+            if (so->so_expire) {
+                if (so->so_expire <= curtime) {
+                    udp_detach(so);
+                    continue;
+                } else {
+                    do_slowtimo = 1; /* Let socket expire */
+                }
+            }
+
+            /*
+             * When UDP packets are received from over the
+             * link, they're sendto()'d straight away, so
+             * no need for setting for writing
+             * Limit the number of packets queued by this session
+             * to 4.  Note that even though we try and limit this
+             * to 4 packets, the session could have more queued
+             * if the packets needed to be fragmented
+             * (XXX <= 4 ?)
+             */
+            if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
+                GPollFD pfd = {
+                    .fd = so->s,
+                    .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+                };
+                so->pollfds_idx = pollfds->len;
+                g_array_append_val(pollfds, pfd);
+            }
+        }
+
+        /*
+         * ICMP sockets
+         */
+        for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                so = so_next) {
+            so_next = so->so_next;
+
+            so->pollfds_idx = -1;
+
+            /*
+             * See if it's timed out
+             */
+            if (so->so_expire) {
+                if (so->so_expire <= curtime) {
+                    icmp_detach(so);
+                    continue;
+                } else {
+                    do_slowtimo = 1; /* Let socket expire */
                 }
-       }
+            }
 
-        *pnfds = nfds;
+            if (so->so_state & SS_ISFCONNECTED) {
+                GPollFD pfd = {
+                    .fd = so->s,
+                    .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+                };
+                so->pollfds_idx = pollfds->len;
+                g_array_append_val(pollfds, pfd);
+            }
+        }
+    }
 }
 
-void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
-                       int select_error)
+void slirp_pollfds_poll(GArray *pollfds, int select_error)
 {
     Slirp *slirp;
     struct socket *so, *so_next;
@@ -429,184 +448,202 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
         return;
     }
 
-    global_readfds = readfds;
-    global_writefds = writefds;
-    global_xfds = xfds;
-
     curtime = qemu_get_clock_ms(rt_clock);
 
     QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
-       /*
-        * See if anything has timed out
-        */
-               if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
-                       tcp_fasttimo(slirp);
-                       time_fasttimo = 0;
-               }
-               if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
-                       ip_slowtimo(slirp);
-                       tcp_slowtimo(slirp);
-                       last_slowtimo = curtime;
-               }
-
-       /*
-        * Check sockets
-        */
-       if (!select_error) {
-               /*
-                * Check TCP sockets
-                */
-               for (so = slirp->tcb.so_next; so != &slirp->tcb;
-                    so = so_next) {
-                       so_next = so->so_next;
-
-                       /*
-                        * FD_ISSET is meaningless on these sockets
-                        * (and they can crash the program)
-                        */
-                       if (so->so_state & SS_NOFDREF || so->s == -1)
-                          continue;
-
-                       /*
-                        * Check for URG data
-                        * This will soread as well, so no need to
-                        * test for readfds below if this succeeds
-                        */
-                       if (FD_ISSET(so->s, xfds))
-                          sorecvoob(so);
-                       /*
-                        * Check sockets for reading
-                        */
-                       else if (FD_ISSET(so->s, readfds)) {
-                               /*
-                                * Check for incoming connections
-                                */
-                               if (so->so_state & SS_FACCEPTCONN) {
-                                       tcp_connect(so);
-                                       continue;
-                               } /* else */
-                               ret = soread(so);
-
-                               /* Output it if we read something */
-                               if (ret > 0)
-                                  tcp_output(sototcpcb(so));
-                       }
-
-                       /*
-                        * Check sockets for writing
-                        */
-                       if (FD_ISSET(so->s, writefds)) {
-                         /*
-                          * Check for non-blocking, still-connecting sockets
-                          */
-                         if (so->so_state & SS_ISFCONNECTING) {
-                           /* Connected */
-                           so->so_state &= ~SS_ISFCONNECTING;
-
-                           ret = send(so->s, (const void *) &ret, 0, 0);
-                           if (ret < 0) {
-                             /* XXXXX Must fix, zero bytes is a NOP */
-                             if (errno == EAGAIN || errno == EWOULDBLOCK ||
-                                 errno == EINPROGRESS || errno == ENOTCONN)
-                               continue;
-
-                             /* else failed */
-                             so->so_state &= SS_PERSISTENT_MASK;
-                             so->so_state |= SS_NOFDREF;
-                           }
-                           /* else so->so_state &= ~SS_ISFCONNECTING; */
-
-                           /*
-                            * Continue tcp_input
-                            */
-                           tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
-                           /* continue; */
-                         } else
-                           ret = sowrite(so);
-                         /*
-                          * XXXXX If we wrote something (a lot), there
-                          * could be a need for a window update.
-                          * In the worst case, the remote will send
-                          * a window probe to get things going again
-                          */
-                       }
-
-                       /*
-                        * Probe a still-connecting, non-blocking socket
-                        * to check if it's still alive
-                        */
-#ifdef PROBE_CONN
-                       if (so->so_state & SS_ISFCONNECTING) {
-                          ret = qemu_recv(so->s, &ret, 0,0);
-
-                         if (ret < 0) {
-                           /* XXX */
-                           if (errno == EAGAIN || errno == EWOULDBLOCK ||
-                               errno == EINPROGRESS || errno == ENOTCONN)
-                             continue; /* Still connecting, continue */
-
-                           /* else failed */
-                           so->so_state &= SS_PERSISTENT_MASK;
-                           so->so_state |= SS_NOFDREF;
-
-                           /* tcp_input will take care of it */
-                         } else {
-                           ret = send(so->s, &ret, 0,0);
-                           if (ret < 0) {
-                             /* XXX */
-                             if (errno == EAGAIN || errno == EWOULDBLOCK ||
-                                 errno == EINPROGRESS || errno == ENOTCONN)
-                               continue;
-                             /* else failed */
-                             so->so_state &= SS_PERSISTENT_MASK;
-                             so->so_state |= SS_NOFDREF;
-                           } else
-                             so->so_state &= ~SS_ISFCONNECTING;
-
-                         }
-                         tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
-                       } /* SS_ISFCONNECTING */
-#endif
-               }
-
-               /*
-                * Now UDP sockets.
-                * Incoming packets are sent straight away, they're not buffered.
-                * Incoming UDP data isn't buffered either.
-                */
-               for (so = slirp->udb.so_next; so != &slirp->udb;
-                    so = so_next) {
-                       so_next = so->so_next;
-
-                       if (so->s != -1 && FD_ISSET(so->s, readfds)) {
-                            sorecvfrom(so);
+        /*
+         * See if anything has timed out
+         */
+        if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
+            tcp_fasttimo(slirp);
+            time_fasttimo = 0;
+        }
+        if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
+            ip_slowtimo(slirp);
+            tcp_slowtimo(slirp);
+            last_slowtimo = curtime;
+        }
+
+        /*
+         * Check sockets
+         */
+        if (!select_error) {
+            /*
+             * Check TCP sockets
+             */
+            for (so = slirp->tcb.so_next; so != &slirp->tcb;
+                    so = so_next) {
+                int revents;
+
+                so_next = so->so_next;
+
+                revents = 0;
+                if (so->pollfds_idx != -1) {
+                    revents = g_array_index(pollfds, GPollFD,
+                                            so->pollfds_idx).revents;
+                }
+
+                if (so->so_state & SS_NOFDREF || so->s == -1) {
+                    continue;
+                }
+
+                /*
+                 * Check for URG data
+                 * This will soread as well, so no need to
+                 * test for G_IO_IN below if this succeeds
+                 */
+                if (revents & G_IO_PRI) {
+                    sorecvoob(so);
+                }
+                /*
+                 * Check sockets for reading
+                 */
+                else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
+                    /*
+                     * Check for incoming connections
+                     */
+                    if (so->so_state & SS_FACCEPTCONN) {
+                        tcp_connect(so);
+                        continue;
+                    } /* else */
+                    ret = soread(so);
+
+                    /* Output it if we read something */
+                    if (ret > 0) {
+                        tcp_output(sototcpcb(so));
+                    }
+                }
+
+                /*
+                 * Check sockets for writing
+                 */
+                if (!(so->so_state & SS_NOFDREF) &&
+                        (revents & (G_IO_OUT | G_IO_ERR))) {
+                    /*
+                     * Check for non-blocking, still-connecting sockets
+                     */
+                    if (so->so_state & SS_ISFCONNECTING) {
+                        /* Connected */
+                        so->so_state &= ~SS_ISFCONNECTING;
+
+                        ret = send(so->s, (const void *) &ret, 0, 0);
+                        if (ret < 0) {
+                            /* XXXXX Must fix, zero bytes is a NOP */
+                            if (errno == EAGAIN || errno == EWOULDBLOCK ||
+                                errno == EINPROGRESS || errno == ENOTCONN) {
+                                continue;
+                            }
+
+                            /* else failed */
+                            so->so_state &= SS_PERSISTENT_MASK;
+                            so->so_state |= SS_NOFDREF;
                         }
-               }
+                        /* else so->so_state &= ~SS_ISFCONNECTING; */
+
+                        /*
+                         * Continue tcp_input
+                         */
+                        tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+                        /* continue; */
+                    } else {
+                        ret = sowrite(so);
+                    }
+                    /*
+                     * XXXXX If we wrote something (a lot), there
+                     * could be a need for a window update.
+                     * In the worst case, the remote will send
+                     * a window probe to get things going again
+                     */
+                }
 
                 /*
-                 * Check incoming ICMP relies.
+                 * Probe a still-connecting, non-blocking socket
+                 * to check if it's still alive
                  */
-                for (so = slirp->icmp.so_next; so != &slirp->icmp;
-                     so = so_next) {
-                     so_next = so->so_next;
+#ifdef PROBE_CONN
+                if (so->so_state & SS_ISFCONNECTING) {
+                    ret = qemu_recv(so->s, &ret, 0, 0);
+
+                    if (ret < 0) {
+                        /* XXX */
+                        if (errno == EAGAIN || errno == EWOULDBLOCK ||
+                            errno == EINPROGRESS || errno == ENOTCONN) {
+                            continue; /* Still connecting, continue */
+                        }
+
+                        /* else failed */
+                        so->so_state &= SS_PERSISTENT_MASK;
+                        so->so_state |= SS_NOFDREF;
+
+                        /* tcp_input will take care of it */
+                    } else {
+                        ret = send(so->s, &ret, 0, 0);
+                        if (ret < 0) {
+                            /* XXX */
+                            if (errno == EAGAIN || errno == EWOULDBLOCK ||
+                                errno == EINPROGRESS || errno == ENOTCONN) {
+                                continue;
+                            }
+                            /* else failed */
+                            so->so_state &= SS_PERSISTENT_MASK;
+                            so->so_state |= SS_NOFDREF;
+                        } else {
+                            so->so_state &= ~SS_ISFCONNECTING;
+                        }
 
-                    if (so->s != -1 && FD_ISSET(so->s, readfds)) {
-                        icmp_receive(so);
                     }
+                    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+                } /* SS_ISFCONNECTING */
+#endif
+            }
+
+            /*
+             * Now UDP sockets.
+             * Incoming packets are sent straight away, they're not buffered.
+             * Incoming UDP data isn't buffered either.
+             */
+            for (so = slirp->udb.so_next; so != &slirp->udb;
+                    so = so_next) {
+                int revents;
+
+                so_next = so->so_next;
+
+                revents = 0;
+                if (so->pollfds_idx != -1) {
+                    revents = g_array_index(pollfds, GPollFD,
+                            so->pollfds_idx).revents;
+                }
+
+                if (so->s != -1 &&
+                    (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
+                    sorecvfrom(so);
                 }
-       }
+            }
+
+            /*
+             * Check incoming ICMP relies.
+             */
+            for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                    so = so_next) {
+                    int revents;
+
+                    so_next = so->so_next;
+
+                    revents = 0;
+                    if (so->pollfds_idx != -1) {
+                        revents = g_array_index(pollfds, GPollFD,
+                                                so->pollfds_idx).revents;
+                    }
+
+                    if (so->s != -1 &&
+                        (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
+                    icmp_receive(so);
+                }
+            }
+        }
 
         if_start(slirp);
     }
-
-       /* clear global file descriptor sets.
-        * these reside on the stack in vl.c
-        * so they're unusable if we're not in
-        * slirp_select_fill or slirp_select_poll.
-        */
-        global_readfds = NULL;
-        global_writefds = NULL;
-        global_xfds = NULL;
 }
 
 static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
@@ -827,12 +864,12 @@ int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
 
 ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
 {
-       if (so->s == -1 && so->extra) {
-               qemu_chr_fe_write(so->extra, buf, len);
-               return len;
-       }
+    if (so->s == -1 && so->extra) {
+        qemu_chr_fe_write(so->extra, buf, len);
+        return len;
+    }
 
-       return send(so->s, buf, len, flags);
+    return send(so->s, buf, len, flags);
 }
 
 static struct socket *
@@ -852,18 +889,20 @@ slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
 size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
                              int guest_port)
 {
-       struct iovec iov[2];
-       struct socket *so;
+    struct iovec iov[2];
+    struct socket *so;
 
-       so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
+    so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
 
-       if (!so || so->so_state & SS_NOFDREF)
-               return 0;
+    if (!so || so->so_state & SS_NOFDREF) {
+        return 0;
+    }
 
-       if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
-               return 0;
+    if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) {
+        return 0;
+    }
 
-       return sopreprbuf(so, iov, NULL);
+    return sopreprbuf(so, iov, NULL);
 }
 
 void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
index 77b0c9819785342087b63b8d55de92ce76872ddb..a7ab933c4359fddb47be926cd3a8ca23b62df733 100644 (file)
@@ -680,9 +680,6 @@ sofcantrcvmore(struct socket *so)
 {
        if ((so->so_state & SS_NOFDREF) == 0) {
                shutdown(so->s,0);
-               if(global_writefds) {
-                 FD_CLR(so->s,global_writefds);
-               }
        }
        so->so_state &= ~(SS_ISFCONNECTING);
        if (so->so_state & SS_FCANTSENDMORE) {
@@ -698,12 +695,6 @@ sofcantsendmore(struct socket *so)
 {
        if ((so->so_state & SS_NOFDREF) == 0) {
             shutdown(so->s,1);           /* send FIN to fhost */
-            if (global_readfds) {
-                FD_CLR(so->s,global_readfds);
-            }
-            if (global_xfds) {
-                FD_CLR(so->s,global_xfds);
-            }
        }
        so->so_state &= ~(SS_ISFCONNECTING);
        if (so->so_state & SS_FCANTRCVMORE) {
index 857b0da311b12caba5753b3fcc7155ace1c58172..57e0407ebcf8acd69644dd4e2249597b4b7af926 100644 (file)
@@ -20,6 +20,8 @@ struct socket {
 
   int s;                           /* The actual socket */
 
+  int pollfds_idx;                 /* GPollFD GArray index */
+
   Slirp *slirp;                           /* managing slirp instance */
 
                        /* XXX union these with not-yet-used sbuf params */
index 9a3309a2b9b18c12042d259b7069d50637b7edd6..f1fc833f7aa9e981e2b9913e87bff2749af5f8a9 100644 (file)
@@ -5,13 +5,11 @@ void slirp_update_timeout(uint32_t *timeout)
 {
 }
 
-void slirp_select_fill(int *pnfds, fd_set *readfds,
-                       fd_set *writefds, fd_set *xfds)
+void slirp_pollfds_fill(GArray *pollfds)
 {
 }
 
-void slirp_select_poll(fd_set *readfds, fd_set *writefds,
-                       fd_set *xfds, int select_error)
+void slirp_pollfds_poll(GArray *pollfds, int select_error)
 {
 }
 
index 04a5379775b9bbe2ee4541c7c8f96e69f0f21b7e..2cf01a52e719c44c61b2947fb3d17982df536987 100644 (file)
@@ -3215,8 +3215,6 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb,
     int num_insns;
     int max_insns;
 
-    qemu_log_try_set_file(stderr);
-
     if (env->pregs[PR_VR] == 32) {
         dc->decoder = crisv32_decoder;
         dc->clear_locked_irq = 0;
index 6b873401747e1e75a4825785f27c48aa74f83684..ccaf838afa8635984b46733bbe9608be6a27896d 100644 (file)
@@ -1012,8 +1012,6 @@ static void gen_intermediate_code_internal(CPULM32State *env,
     int num_insns;
     int max_insns;
 
-    qemu_log_try_set_file(stderr);
-
     pc_start = tb->pc;
     dc->env = env;
     dc->tb = tb;
index 12ea820522166b7d0a3da80ab9de6f67189ddc8c..687b7d14335fc14c70f7ca4e9437891b3f0ce667 100644 (file)
@@ -1734,8 +1734,6 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb,
     int num_insns;
     int max_insns;
 
-    qemu_log_try_set_file(stderr);
-
     pc_start = tb->pc;
     dc->env = env;
     dc->tb = tb;
index 1e1b30cdcb1ff7c2fc220546699c1c18f3fadff0..23e853e48882d47488ffbca28d4851d7ff63f245 100644 (file)
@@ -1670,8 +1670,6 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu,
     int num_insns;
     int max_insns;
 
-    qemu_log_try_set_file(stderr);
-
     pc_start = tb->pc;
     dc->tb = tb;
 
index ef52df6d74882204f576dcfd93ed72f4eaf5ecf5..50def618480098a0d028fde7806e35bbebcd48e6 100644 (file)
@@ -580,13 +580,13 @@ static const sparc_def_t sparc_defs[] = {
         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
         .mmu_version = 0xf3000000,
         .mmu_bm = 0x00000000,
-        .mmu_ctpr_mask = 0x007ffff0,
-        .mmu_cxr_mask = 0x0000003f,
+        .mmu_ctpr_mask = 0xfffffffc,
+        .mmu_cxr_mask = 0x000000ff,
         .mmu_sfsr_mask = 0xffffffff,
         .mmu_trcr_mask = 0xffffffff,
         .nwindows = 8,
         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
-        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
+        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN,
     },
 #endif
 };
index 7389b03514e5be52ba48b07fbbf8e5f0523e6ca1..a2f2cc89892cb40386caaaf7dff51f6764d95a00 100644 (file)
@@ -270,6 +270,7 @@ typedef struct sparc_def_t {
 #define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
 #define CPU_FEATURE_ASR17        (1 << 15)
 #define CPU_FEATURE_CACHE_CTRL   (1 << 16)
+#define CPU_FEATURE_POWERDOWN    (1 << 17)
 
 #ifndef TARGET_SPARC64
 #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
index 91ecfc7aa85d9e559a4a81f275a0a61a98969ad7..58e7efe567221472118f2e780e218f79bad8ec5f 100644 (file)
@@ -225,3 +225,14 @@ target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
     cpu_restore_state(env, GETPC());
     helper_raise_exception(env, TT_TOVF);
 }
+
+#ifndef TARGET_SPARC64
+void helper_power_down(CPUSPARCState *env)
+{
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+    env->pc = env->npc;
+    env->npc = env->pc + 4;
+    cpu_loop_exit(env);
+}
+#endif
index cfcdab1ea4f916139ba58f13e37af4db878276f0..15f73283fae651b91eac40f5c5a30b7390581343 100644 (file)
@@ -4,6 +4,7 @@
 DEF_HELPER_1(rett, void, env)
 DEF_HELPER_2(wrpsr, void, env, tl)
 DEF_HELPER_1(rdpsr, tl, env)
+DEF_HELPER_1(power_down, void, env)
 #else
 DEF_HELPER_2(wrpil, void, env, tl)
 DEF_HELPER_2(wrpstate, void, env, tl)
index 7decd66d0bb27670c62e14a15e35ac79ead72adc..6d767fb45a643f6c74e8cc159abbe2e4d7d3a332 100644 (file)
@@ -514,6 +514,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
 #endif
         break;
     case 3: /* MMU probe */
+    case 0x18: /* LEON3 MMU probe */
         {
             int mmulev;
 
@@ -528,6 +529,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
         }
         break;
     case 4: /* read MMU regs */
+    case 0x19: /* LEON3 read MMU regs */
         {
             int reg = (addr >> 8) & 0x1f;
 
@@ -603,6 +605,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
     case 0xf: /* D-cache data */
         break;
     case 0x20: /* MMU passthrough */
+    case 0x1c: /* LEON MMU passthrough */
         switch (size) {
         case 1:
             ret = ldub_phys(addr);
@@ -844,6 +847,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
 #endif
         break;
     case 3: /* MMU flush */
+    case 0x18: /* LEON3 MMU flush */
         {
             int mmulev;
 
@@ -868,6 +872,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
         }
         break;
     case 4: /* write MMU regs */
+    case 0x19: /* LEON3 write MMU regs */
         {
             int reg = (addr >> 8) & 0x1f;
             uint32_t oldreg;
@@ -996,6 +1001,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
         }
         break;
     case 0x20: /* MMU passthrough */
+    case 0x1c: /* LEON MMU passthrough */
         {
             switch (size) {
             case 1:
index ca75e1aa4845aa5523d5cae5b23ca7120c7d8ff6..26c2056b93bbf60f1f29eb231ebf37dda549c2ae 100644 (file)
@@ -3642,6 +3642,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                                                    in the SPARCv8
                                                    manual, nop on the
                                                    microSPARC II */
+                                if ((rd == 0x13) && (dc->def->features &
+                                                     CPU_FEATURE_POWERDOWN)) {
+                                    /* LEON3 power-down */
+                                    gen_helper_power_down(cpu_env);
+                                }
                                 break;
 #else
                             case 0x2: /* V9 wrccr */
index 38c94ef1da3abec91dd2b6551c04f779858d6b8b..fb05c2ae87cd397194f7b18b64c5817fc2819083 100644 (file)
@@ -4,11 +4,18 @@ check-qint
 check-qjson
 check-qlist
 check-qstring
+test-aio
+test-cutils
+test-hbitmap
+test-iov
+test-mul64
 test-qapi-types.[ch]
 test-qapi-visit.[ch]
 test-qmp-commands.h
 test-qmp-commands
 test-qmp-input-strict
 test-qmp-marshal.c
+test-thread-pool
 test-x86-cpuid
+test-xbzrle
 *-test
index 203c0fc363bb9466d67c5b591e62dc27889984b3..c5fd042610f81fad3a91ae5450676c8317e38159 100644 (file)
@@ -26,11 +26,6 @@ static int bcd2dec(int value)
     return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
 }
 
-static int dec2bcd(int value)
-{
-    return ((value / 10) << 4) | (value % 10);
-}
-
 static uint8_t cmos_read(uint8_t reg)
 {
     outb(base + 0, reg);
@@ -184,7 +179,7 @@ static int wiggle = 2;
 static void set_year_20xx(void)
 {
     /* Set BCD mode */
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
+    cmos_write(RTC_REG_B, REG_B_24H);
     cmos_write(RTC_REG_A, 0x76);
     cmos_write(RTC_YEAR, 0x11);
     cmos_write(RTC_CENTURY, 0x20);
@@ -236,7 +231,7 @@ static void set_year_20xx(void)
 static void set_year_1980(void)
 {
     /* Set BCD mode */
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
+    cmos_write(RTC_REG_B, REG_B_24H);
     cmos_write(RTC_REG_A, 0x76);
     cmos_write(RTC_YEAR, 0x80);
     cmos_write(RTC_CENTURY, 0x19);
@@ -259,32 +254,17 @@ static void set_year_1980(void)
 static void bcd_check_time(void)
 {
     /* Set BCD mode */
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
+    cmos_write(RTC_REG_B, REG_B_24H);
     check_time(wiggle);
 }
 
 static void dec_check_time(void)
 {
     /* Set DEC mode */
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM);
+    cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
     check_time(wiggle);
 }
 
-static void set_alarm_time(struct tm *tm)
-{
-    int sec;
-
-    sec = tm->tm_sec;
-
-    if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
-        sec = dec2bcd(sec);
-    }
-
-    cmos_write(RTC_SECONDS_ALARM, sec);
-    cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
-    cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
-}
-
 static void alarm_time(void)
 {
     struct tm now;
@@ -295,13 +275,15 @@ static void alarm_time(void)
     gmtime_r(&ts, &now);
 
     /* set DEC mode */
-    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM);
+    cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
 
     g_assert(!get_irq(RTC_ISA_IRQ));
     cmos_read(RTC_REG_C);
 
     now.tm_sec = (now.tm_sec + 2) % 60;
-    set_alarm_time(&now);
+    cmos_write(RTC_SECONDS_ALARM, now.tm_sec);
+    cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
+    cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
     cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
 
     for (i = 0; i < 2 + wiggle; i++) {
@@ -317,6 +299,197 @@ static void alarm_time(void)
     g_assert(cmos_read(RTC_REG_C) == 0);
 }
 
+static void set_time(int mode, int h, int m, int s)
+{
+    /* set BCD 12 hour mode */
+    cmos_write(RTC_REG_B, mode);
+
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_HOURS, h);
+    cmos_write(RTC_MINUTES, m);
+    cmos_write(RTC_SECONDS, s);
+    cmos_write(RTC_REG_A, 0x26);
+}
+
+#define assert_time(h, m, s) \
+    do { \
+        g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \
+        g_assert_cmpint(cmos_read(RTC_MINUTES), ==, m); \
+        g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
+    } while(0)
+
+static void basic_12h_bcd(void)
+{
+    /* set BCD 12 hour mode */
+    set_time(0, 0x81, 0x59, 0x00);
+    clock_step(1000000000LL);
+    assert_time(0x81, 0x59, 0x01);
+    clock_step(59000000000LL);
+    assert_time(0x82, 0x00, 0x00);
+
+    /* test BCD wraparound */
+    set_time(0, 0x09, 0x59, 0x59);
+    clock_step(60000000000LL);
+    assert_time(0x10, 0x00, 0x59);
+
+    /* 12 AM -> 1 AM */
+    set_time(0, 0x12, 0x59, 0x59);
+    clock_step(1000000000LL);
+    assert_time(0x01, 0x00, 0x00);
+
+    /* 12 PM -> 1 PM */
+    set_time(0, 0x92, 0x59, 0x59);
+    clock_step(1000000000LL);
+    assert_time(0x81, 0x00, 0x00);
+
+    /* 11 AM -> 12 PM */
+    set_time(0, 0x11, 0x59, 0x59);
+    clock_step(1000000000LL);
+    assert_time(0x92, 0x00, 0x00);
+    /* TODO: test day wraparound */
+
+    /* 11 PM -> 12 AM */
+    set_time(0, 0x91, 0x59, 0x59);
+    clock_step(1000000000LL);
+    assert_time(0x12, 0x00, 0x00);
+    /* TODO: test day wraparound */
+}
+
+static void basic_12h_dec(void)
+{
+    /* set decimal 12 hour mode */
+    set_time(REG_B_DM, 0x81, 59, 0);
+    clock_step(1000000000LL);
+    assert_time(0x81, 59, 1);
+    clock_step(59000000000LL);
+    assert_time(0x82, 0, 0);
+
+    /* 12 PM -> 1 PM */
+    set_time(REG_B_DM, 0x8c, 59, 59);
+    clock_step(1000000000LL);
+    assert_time(0x81, 0, 0);
+
+    /* 12 AM -> 1 AM */
+    set_time(REG_B_DM, 0x0c, 59, 59);
+    clock_step(1000000000LL);
+    assert_time(0x01, 0, 0);
+
+    /* 11 AM -> 12 PM */
+    set_time(REG_B_DM, 0x0b, 59, 59);
+    clock_step(1000000000LL);
+    assert_time(0x8c, 0, 0);
+
+    /* 11 PM -> 12 AM */
+    set_time(REG_B_DM, 0x8b, 59, 59);
+    clock_step(1000000000LL);
+    assert_time(0x0c, 0, 0);
+    /* TODO: test day wraparound */
+}
+
+static void basic_24h_bcd(void)
+{
+    /* set BCD 24 hour mode */
+    set_time(REG_B_24H, 0x09, 0x59, 0x00);
+    clock_step(1000000000LL);
+    assert_time(0x09, 0x59, 0x01);
+    clock_step(59000000000LL);
+    assert_time(0x10, 0x00, 0x00);
+
+    /* test BCD wraparound */
+    set_time(REG_B_24H, 0x09, 0x59, 0x00);
+    clock_step(60000000000LL);
+    assert_time(0x10, 0x00, 0x00);
+
+    /* TODO: test day wraparound */
+    set_time(REG_B_24H, 0x23, 0x59, 0x00);
+    clock_step(60000000000LL);
+    assert_time(0x00, 0x00, 0x00);
+}
+
+static void basic_24h_dec(void)
+{
+    /* set decimal 24 hour mode */
+    set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
+    clock_step(1000000000LL);
+    assert_time(9, 59, 1);
+    clock_step(59000000000LL);
+    assert_time(10, 0, 0);
+
+    /* test BCD wraparound */
+    set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
+    clock_step(60000000000LL);
+    assert_time(10, 0, 0);
+
+    /* TODO: test day wraparound */
+    set_time(REG_B_24H | REG_B_DM, 23, 59, 0);
+    clock_step(60000000000LL);
+    assert_time(0, 0, 0);
+}
+
+static void am_pm_alarm(void)
+{
+    cmos_write(RTC_MINUTES_ALARM, 0xC0);
+    cmos_write(RTC_SECONDS_ALARM, 0xC0);
+
+    /* set BCD 12 hour mode */
+    cmos_write(RTC_REG_B, 0);
+
+    /* Set time and alarm hour.  */
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_HOURS_ALARM, 0x82);
+    cmos_write(RTC_HOURS, 0x81);
+    cmos_write(RTC_MINUTES, 0x59);
+    cmos_write(RTC_SECONDS, 0x00);
+    cmos_read(RTC_REG_C);
+    cmos_write(RTC_REG_A, 0x26);
+
+    /* Check that alarm triggers when AM/PM is set.  */
+    clock_step(60000000000LL);
+    g_assert(cmos_read(RTC_HOURS) == 0x82);
+    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+
+    /*
+     * Each of the following two tests takes over 60 seconds due to the time
+     * needed to report the PIT interrupts.  Unfortunately, our PIT device
+     * model keeps counting even when GATE=0, so we cannot simply disable
+     * it in main().
+     */
+    if (g_test_quick()) {
+        return;
+    }
+
+    /* set DEC 12 hour mode */
+    cmos_write(RTC_REG_B, REG_B_DM);
+
+    /* Set time and alarm hour.  */
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_HOURS_ALARM, 0x82);
+    cmos_write(RTC_HOURS, 3);
+    cmos_write(RTC_MINUTES, 0);
+    cmos_write(RTC_SECONDS, 0);
+    cmos_read(RTC_REG_C);
+    cmos_write(RTC_REG_A, 0x26);
+
+    /* Check that alarm triggers.  */
+    clock_step(3600 * 11 * 1000000000LL);
+    g_assert(cmos_read(RTC_HOURS) == 0x82);
+    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+
+    /* Same as above, with inverted HOURS and HOURS_ALARM.  */
+    cmos_write(RTC_REG_A, 0x76);
+    cmos_write(RTC_HOURS_ALARM, 2);
+    cmos_write(RTC_HOURS, 3);
+    cmos_write(RTC_MINUTES, 0);
+    cmos_write(RTC_SECONDS, 0);
+    cmos_read(RTC_REG_C);
+    cmos_write(RTC_REG_A, 0x26);
+
+    /* Check that alarm does not trigger if hours differ only by AM/PM.  */
+    clock_step(3600 * 11 * 1000000000LL);
+    g_assert(cmos_read(RTC_HOURS) == 0x82);
+    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) == 0);
+}
+
 /* success if no crash or abort */
 static void fuzz_registers(void)
 {
@@ -336,7 +509,7 @@ static void fuzz_registers(void)
 static void register_b_set_flag(void)
 {
     /* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/
-    cmos_write(RTC_REG_B, (cmos_read(RTC_REG_B) & ~REG_B_DM) | REG_B_SET);
+    cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET);
 
     cmos_write(RTC_REG_A, 0x76);
     cmos_write(RTC_YEAR, 0x11);
@@ -382,9 +555,14 @@ int main(int argc, char **argv)
     s = qtest_start("-display none -rtc clock=vm");
     qtest_irq_intercept_in(s, "ioapic");
 
-    qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
-    qtest_add_func("/rtc/dec/check-time", dec_check_time);
-    qtest_add_func("/rtc/alarm-time", alarm_time);
+    qtest_add_func("/rtc/check-time/bcd", bcd_check_time);
+    qtest_add_func("/rtc/check-time/dec", dec_check_time);
+    qtest_add_func("/rtc/alarm/interrupt", alarm_time);
+    qtest_add_func("/rtc/alarm/am-pm", am_pm_alarm);
+    qtest_add_func("/rtc/basic/dec-24h", basic_24h_dec);
+    qtest_add_func("/rtc/basic/bcd-24h", basic_24h_bcd);
+    qtest_add_func("/rtc/basic/dec-12h", basic_12h_dec);
+    qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd);
     qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
     qtest_add_func("/rtc/set-year/1980", set_year_1980);
     qtest_add_func("/rtc/register_b_set_flag", register_b_set_flag);
index 1011f27676609e6d9b0ba13ab44c652aedb7f6d2..a27ae430320722901f769aeccc0f2fecf37fc983 100644 (file)
@@ -370,11 +370,11 @@ usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d"
 usb_xhci_slot_reset(uint32_t slotid) "slotid %d"
 usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
 usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
-usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint64_t param) "slotid %d, epid %d, ptr %016" PRIx64
-usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
+usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint32_t streamid, uint64_t param) "slotid %d, epid %d, streamid %d, ptr %016" PRIx64
+usb_xhci_ep_kick(uint32_t slotid, uint32_t epid, uint32_t streamid) "slotid %d, epid %d, streamid %d"
 usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
 usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
-usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d"
+usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t streamid) "%p: slotid %d, epid %d, streamid %d"
 usb_xhci_xfer_async(void *xfer) "%p"
 usb_xhci_xfer_nak(void *xfer) "%p"
 usb_xhci_xfer_retry(void *xfer) "%p"
index d9db0735843d6009bccb578335369e76a008544d..85c50cd89beaacf4b1d6aede916e244ee5a20ec3 100644 (file)
@@ -13,7 +13,10 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
 common-obj-$(CONFIG_COCOA) += cocoa.o
 common-obj-$(CONFIG_CURSES) += curses.o
 common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
+common-obj-$(CONFIG_GTK) += gtk.o
 
 $(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS) 
 
 $(obj)/cocoa.o: $(SRC_PATH)/$(obj)/cocoa.m
+
+$(obj)/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
index 0a68836d506b45929b0df41c5a9bb7bf3e6c098f..0d95f321234084f9350431953f43b867a9abf7f8 100644 (file)
@@ -1339,11 +1339,16 @@ DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
 }
 
 DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
-                                                int linesize, uint8_t *data)
+                                                int linesize, uint8_t *data,
+                                                bool byteswap)
 {
     DisplaySurface *surface = g_new0(DisplaySurface, 1);
 
-    surface->pf = qemu_default_pixelformat(bpp);
+    if (byteswap) {
+        surface->pf = qemu_different_endianness_pixelformat(bpp);
+    } else {
+        surface->pf = qemu_default_pixelformat(bpp);
+    }
 
     surface->format = qemu_pixman_get_format(&surface->pf);
     assert(surface->format != 0);
@@ -1532,7 +1537,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         chr->init(chr);
 }
 
-CharDriverState *text_console_init(QemuOpts *opts)
+static CharDriverState *text_console_init(QemuOpts *opts)
 {
     CharDriverState *chr;
     QemuConsole *s;
@@ -1568,6 +1573,18 @@ CharDriverState *text_console_init(QemuOpts *opts)
     return chr;
 }
 
+static VcHandler *vc_handler = text_console_init;
+
+CharDriverState *vc_init(QemuOpts *opts)
+{
+    return vc_handler(opts);
+}
+
+void register_vc_handler(VcHandler *handler)
+{
+    vc_handler = handler;
+}
+
 void text_consoles_set_display(DisplayState *ds)
 {
     int i;
diff --git a/ui/gtk.c b/ui/gtk.c
new file mode 100644 (file)
index 0000000..dcce36d
--- /dev/null
+++ b/ui/gtk.c
@@ -0,0 +1,1217 @@
+/*
+ * GTK UI
+ *
+ * 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.
+ *
+ * Portions from gtk-vnc:
+ *
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#define GETTEXT_PACKAGE "qemu"
+#define LOCALEDIR "po"
+
+#include "qemu-common.h"
+
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+/* Work around an -Wstrict-prototypes warning in GTK headers */
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+#include <gtk/gtk.h>
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#pragma GCC diagnostic error "-Wstrict-prototypes"
+#endif
+
+
+#include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
+#include <locale.h>
+#include <vte/vte.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <pty.h>
+#include <math.h>
+
+#include "ui/console.h"
+#include "sysemu/sysemu.h"
+#include "qmp-commands.h"
+#include "x_keymap.h"
+#include "keymaps.h"
+#include "char/char.h"
+
+//#define DEBUG_GTK
+
+#ifdef DEBUG_GTK
+#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define MAX_VCS 10
+
+typedef struct VirtualConsole
+{
+    GtkWidget *menu_item;
+    GtkWidget *terminal;
+    GtkWidget *scrolled_window;
+    CharDriverState *chr;
+    int fd;
+} VirtualConsole;
+
+typedef struct GtkDisplayState
+{
+    GtkWidget *window;
+
+    GtkWidget *menu_bar;
+
+    GtkAccelGroup *accel_group;
+
+    GtkWidget *machine_menu_item;
+    GtkWidget *machine_menu;
+    GtkWidget *pause_item;
+    GtkWidget *reset_item;
+    GtkWidget *powerdown_item;
+    GtkWidget *quit_item;
+
+    GtkWidget *view_menu_item;
+    GtkWidget *view_menu;
+    GtkWidget *full_screen_item;
+    GtkWidget *zoom_in_item;
+    GtkWidget *zoom_out_item;
+    GtkWidget *zoom_fixed_item;
+    GtkWidget *zoom_fit_item;
+    GtkWidget *grab_item;
+    GtkWidget *grab_on_hover_item;
+    GtkWidget *vga_item;
+
+    int nb_vcs;
+    VirtualConsole vc[MAX_VCS];
+
+    GtkWidget *show_tabs_item;
+
+    GtkWidget *vbox;
+    GtkWidget *notebook;
+    GtkWidget *drawing_area;
+    cairo_surface_t *surface;
+    DisplayChangeListener dcl;
+    DisplayState *ds;
+    int button_mask;
+    int last_x;
+    int last_y;
+
+    double scale_x;
+    double scale_y;
+    gboolean full_screen;
+
+    GdkCursor *null_cursor;
+    Notifier mouse_mode_notifier;
+    gboolean free_scale;
+
+    bool external_pause_update;
+} GtkDisplayState;
+
+static GtkDisplayState *global_state;
+
+/** Utility Functions **/
+
+static bool gd_is_grab_active(GtkDisplayState *s)
+{
+    return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_item));
+}
+
+static bool gd_grab_on_hover(GtkDisplayState *s)
+{
+    return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_on_hover_item));
+}
+
+static bool gd_on_vga(GtkDisplayState *s)
+{
+    return gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0;
+}
+
+static void gd_update_cursor(GtkDisplayState *s, gboolean override)
+{
+    GdkWindow *window;
+    bool on_vga;
+
+    window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
+
+    on_vga = gd_on_vga(s);
+
+    if ((override || on_vga) &&
+        (s->full_screen || kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
+        gdk_window_set_cursor(window, s->null_cursor);
+    } else {
+        gdk_window_set_cursor(window, NULL);
+    }
+}
+
+static void gd_update_caption(GtkDisplayState *s)
+{
+    const char *status = "";
+    gchar *title;
+    const char *grab = "";
+    bool is_paused = !runstate_is_running();
+
+    if (gd_is_grab_active(s)) {
+        grab = " - Press Ctrl+Alt+G to release grab";
+    }
+
+    if (is_paused) {
+        status = " [Paused]";
+    }
+    s->external_pause_update = true;
+    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->pause_item),
+                                   is_paused);
+    s->external_pause_update = false;
+
+    if (qemu_name) {
+        title = g_strdup_printf("QEMU (%s)%s%s", qemu_name, status, grab);
+    } else {
+        title = g_strdup_printf("QEMU%s%s", status, grab);
+    }
+
+    gtk_window_set_title(GTK_WINDOW(s->window), title);
+
+    g_free(title);
+}
+
+/** DisplayState Callbacks **/
+
+static void gd_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    GtkDisplayState *s = ds->opaque;
+    int x1, x2, y1, y2;
+    int mx, my;
+    int fbw, fbh;
+    int ww, wh;
+
+    DPRINTF("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h);
+
+    x1 = floor(x * s->scale_x);
+    y1 = floor(y * s->scale_y);
+
+    x2 = ceil(x * s->scale_x + w * s->scale_x);
+    y2 = ceil(y * s->scale_y + h * s->scale_y);
+
+    fbw = ds_get_width(s->ds) * s->scale_x;
+    fbh = ds_get_height(s->ds) * s->scale_y;
+
+    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+
+    mx = my = 0;
+    if (ww > fbw) {
+        mx = (ww - fbw) / 2;
+    }
+    if (wh > fbh) {
+        my = (wh - fbh) / 2;
+    }
+
+    gtk_widget_queue_draw_area(s->drawing_area, mx + x1, my + y1, (x2 - x1), (y2 - y1));
+}
+
+static void gd_refresh(DisplayState *ds)
+{
+    vga_hw_update();
+}
+
+static void gd_resize(DisplayState *ds)
+{
+    GtkDisplayState *s = ds->opaque;
+    cairo_format_t kind;
+    int stride;
+
+    DPRINTF("resize(width=%d, height=%d)\n",
+            ds_get_width(ds), ds_get_height(ds));
+
+    if (s->surface) {
+        cairo_surface_destroy(s->surface);
+    }
+
+    switch (ds->surface->pf.bits_per_pixel) {
+    case 8:
+        kind = CAIRO_FORMAT_A8;
+        break;
+    case 16:
+        kind = CAIRO_FORMAT_RGB16_565;
+        break;
+    case 32:
+        kind = CAIRO_FORMAT_RGB24;
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+
+    stride = cairo_format_stride_for_width(kind, ds_get_width(ds));
+    g_assert(ds_get_linesize(ds) == stride);
+
+    s->surface = cairo_image_surface_create_for_data(ds_get_data(ds),
+                                                     kind,
+                                                     ds_get_width(ds),
+                                                     ds_get_height(ds),
+                                                     ds_get_linesize(ds));
+
+    if (!s->full_screen) {
+        GtkRequisition req;
+        double sx, sy;
+
+        if (s->free_scale) {
+            sx = s->scale_x;
+            sy = s->scale_y;
+
+            s->scale_y = 1.0;
+            s->scale_x = 1.0;
+        } else {
+            sx = 1.0;
+            sy = 1.0;
+        }
+
+        gtk_widget_set_size_request(s->drawing_area,
+                                    ds_get_width(ds) * s->scale_x,
+                                    ds_get_height(ds) * s->scale_y);
+        gtk_widget_size_request(s->vbox, &req);
+
+        gtk_window_resize(GTK_WINDOW(s->window),
+                          req.width * sx, req.height * sy);
+    }
+}
+
+/** QEMU Events **/
+
+static void gd_change_runstate(void *opaque, int running, RunState state)
+{
+    GtkDisplayState *s = opaque;
+
+    gd_update_caption(s);
+}
+
+static void gd_mouse_mode_change(Notifier *notify, void *data)
+{
+    gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
+                     FALSE);
+}
+
+/** GTK Events **/
+
+static gboolean gd_window_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    GtkAccelGroupEntry *entries;
+    guint n_entries = 0;
+    gboolean propagate_accel = TRUE;
+    gboolean handled = FALSE;
+
+    entries = gtk_accel_group_query(s->accel_group, key->keyval,
+                                    key->state, &n_entries);
+    if (n_entries) {
+        const char *quark = g_quark_to_string(entries[0].accel_path_quark);
+
+        if (gd_is_grab_active(s) && strstart(quark, "<QEMU>/File/", NULL)) {
+            propagate_accel = FALSE;
+        }
+    }
+
+    if (!handled && propagate_accel) {
+        handled = gtk_window_activate_key(GTK_WINDOW(widget), key);
+    }
+
+    if (!handled) {
+        handled = gtk_window_propagate_key_event(GTK_WINDOW(widget), key);
+    }
+
+    return handled;
+}
+
+static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
+                                void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (!no_quit) {
+        unregister_displaychangelistener(s->ds, &s->dcl);
+        qmp_quit(NULL);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    int mx, my;
+    int ww, wh;
+    int fbw, fbh;
+
+    if (!gtk_widget_get_realized(widget)) {
+        return FALSE;
+    }
+
+    fbw = ds_get_width(s->ds);
+    fbh = ds_get_height(s->ds);
+
+    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
+
+    if (s->full_screen) {
+        s->scale_x = (double)ww / fbw;
+        s->scale_y = (double)wh / fbh;
+    } else if (s->free_scale) {
+        double sx, sy;
+
+        sx = (double)ww / fbw;
+        sy = (double)wh / fbh;
+
+        s->scale_x = s->scale_y = MIN(sx, sy);
+    }
+
+    fbw *= s->scale_x;
+    fbh *= s->scale_y;
+
+    mx = my = 0;
+    if (ww > fbw) {
+        mx = (ww - fbw) / 2;
+    }
+    if (wh > fbh) {
+        my = (wh - fbh) / 2;
+    }
+
+    cairo_rectangle(cr, 0, 0, ww, wh);
+
+    /* Optionally cut out the inner area where the pixmap
+       will be drawn. This avoids 'flashing' since we're
+       not double-buffering. Note we're using the undocumented
+       behaviour of drawing the rectangle from right to left
+       to cut out the whole */
+    cairo_rectangle(cr, mx + fbw, my,
+                    -1 * fbw, fbh);
+    cairo_fill(cr);
+
+    cairo_scale(cr, s->scale_x, s->scale_y);
+    cairo_set_source_surface(cr, s->surface, mx / s->scale_x, my / s->scale_y);
+    cairo_paint(cr);
+
+    return TRUE;
+}
+
+static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
+                                void *opaque)
+{
+    cairo_t *cr;
+    gboolean ret;
+
+    cr = gdk_cairo_create(gtk_widget_get_window(widget));
+    cairo_rectangle(cr,
+                    expose->area.x,
+                    expose->area.y,
+                    expose->area.width,
+                    expose->area.height);
+    cairo_clip(cr);
+
+    ret = gd_draw_event(widget, cr, opaque);
+
+    cairo_destroy(cr);
+
+    return ret;
+}
+
+static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
+                                void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    int dx, dy;
+    int x, y;
+    int mx, my;
+    int fbh, fbw;
+    int ww, wh;
+
+    fbw = ds_get_width(s->ds) * s->scale_x;
+    fbh = ds_get_height(s->ds) * s->scale_y;
+
+    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+
+    mx = my = 0;
+    if (ww > fbw) {
+        mx = (ww - fbw) / 2;
+    }
+    if (wh > fbh) {
+        my = (wh - fbh) / 2;
+    }
+
+    x = (motion->x - mx) / s->scale_x;
+    y = (motion->y - my) / s->scale_y;
+
+    if (x < 0 || y < 0 ||
+        x >= ds_get_width(s->ds) ||
+        y >= ds_get_height(s->ds)) {
+        return TRUE;
+    }
+
+    if (kbd_mouse_is_absolute()) {
+        dx = x * 0x7FFF / (ds_get_width(s->ds) - 1);
+        dy = y * 0x7FFF / (ds_get_height(s->ds) - 1);
+    } else if (s->last_x == -1 || s->last_y == -1) {
+        dx = 0;
+        dy = 0;
+    } else {
+        dx = x - s->last_x;
+        dy = y - s->last_y;
+    }
+
+    s->last_x = x;
+    s->last_y = y;
+
+    if (kbd_mouse_is_absolute() || gd_is_grab_active(s)) {
+        kbd_mouse_event(dx, dy, 0, s->button_mask);
+    }
+
+    if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) {
+        GdkDrawable *drawable = GDK_DRAWABLE(gtk_widget_get_window(s->drawing_area));
+        GdkDisplay *display = gdk_drawable_get_display(drawable);
+        GdkScreen *screen = gdk_drawable_get_screen(drawable);
+        int x = (int)motion->x_root;
+        int y = (int)motion->y_root;
+
+        /* In relative mode check to see if client pointer hit
+         * one of the screen edges, and if so move it back by
+         * 200 pixels. This is important because the pointer
+         * in the server doesn't correspond 1-for-1, and so
+         * may still be only half way across the screen. Without
+         * this warp, the server pointer would thus appear to hit
+         * an invisible wall */
+        if (x == 0) {
+            x += 200;
+        }
+        if (y == 0) {
+            y += 200;
+        }
+        if (x == (gdk_screen_get_width(screen) - 1)) {
+            x -= 200;
+        }
+        if (y == (gdk_screen_get_height(screen) - 1)) {
+            y -= 200;
+        }
+
+        if (x != (int)motion->x_root || y != (int)motion->y_root) {
+            gdk_display_warp_pointer(display, screen, x, y);
+            s->last_x = -1;
+            s->last_y = -1;
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
+                                void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    int dx, dy;
+    int n;
+
+    if (button->button == 1) {
+        n = 0x01;
+    } else if (button->button == 2) {
+        n = 0x04;
+    } else if (button->button == 3) {
+        n = 0x02;
+    } else {
+        n = 0x00;
+    }
+
+    if (button->type == GDK_BUTTON_PRESS) {
+        s->button_mask |= n;
+    } else if (button->type == GDK_BUTTON_RELEASE) {
+        s->button_mask &= ~n;
+    }
+
+    if (kbd_mouse_is_absolute()) {
+        dx = s->last_x * 0x7FFF / (ds_get_width(s->ds) - 1);
+        dy = s->last_y * 0x7FFF / (ds_get_height(s->ds) - 1);
+    } else {
+        dx = 0;
+        dy = 0;
+    }
+
+    kbd_mouse_event(dx, dy, 0, s->button_mask);
+        
+    return TRUE;
+}
+
+static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
+{
+    int gdk_keycode;
+    int qemu_keycode;
+
+    gdk_keycode = key->hardware_keycode;
+
+    if (gdk_keycode < 9) {
+        qemu_keycode = 0;
+    } else if (gdk_keycode < 97) {
+        qemu_keycode = gdk_keycode - 8;
+    } else if (gdk_keycode < 158) {
+        qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
+    } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
+        qemu_keycode = 0x70;
+    } else if (gdk_keycode == 211) { /* backslash */
+        qemu_keycode = 0x73;
+    } else {
+        qemu_keycode = 0;
+    }
+
+    DPRINTF("translated GDK keycode %d to QEMU keycode %d (%s)\n",
+            gdk_keycode, qemu_keycode,
+            (key->type == GDK_KEY_PRESS) ? "down" : "up");
+
+    if (qemu_keycode & SCANCODE_GREY) {
+        kbd_put_keycode(SCANCODE_EMUL0);
+    }
+
+    if (key->type == GDK_KEY_PRESS) {
+        kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
+    } else if (key->type == GDK_KEY_RELEASE) {
+        kbd_put_keycode(qemu_keycode | SCANCODE_UP);
+    } else {
+        g_assert_not_reached();
+    }
+
+    return TRUE;
+}
+
+/** Window Menu Actions **/
+
+static void gd_menu_pause(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (s->external_pause_update) {
+        return;
+    }
+    if (runstate_is_running()) {
+        qmp_stop(NULL);
+    } else {
+        qmp_cont(NULL);
+    }
+}
+
+static void gd_menu_reset(GtkMenuItem *item, void *opaque)
+{
+    qmp_system_reset(NULL);
+}
+
+static void gd_menu_powerdown(GtkMenuItem *item, void *opaque)
+{
+    qmp_system_powerdown(NULL);
+}
+
+static void gd_menu_quit(GtkMenuItem *item, void *opaque)
+{
+    qmp_quit(NULL);
+}
+
+static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
+        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
+    } else {
+        int i;
+
+        for (i = 0; i < s->nb_vcs; i++) {
+            if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vc[i].menu_item))) {
+                gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), i + 1);
+                break;
+            }
+        }
+    }
+}
+
+static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) {
+        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE);
+    } else {
+        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+    }
+}
+
+static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (!s->full_screen) {
+        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+        gtk_widget_set_size_request(s->menu_bar, 0, 0);
+        gtk_widget_set_size_request(s->drawing_area, -1, -1);
+        gtk_window_fullscreen(GTK_WINDOW(s->window));
+        if (gd_on_vga(s)) {
+            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE);
+        }
+        s->full_screen = TRUE;
+    } else {
+        gtk_window_unfullscreen(GTK_WINDOW(s->window));
+        gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s);
+        gtk_widget_set_size_request(s->menu_bar, -1, -1);
+        gtk_widget_set_size_request(s->drawing_area,
+                                    ds_get_width(s->ds), ds_get_height(s->ds));
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE);
+        s->full_screen = FALSE;
+        s->scale_x = 1.0;
+        s->scale_y = 1.0;
+    }
+
+    gd_update_cursor(s, FALSE);
+}
+
+static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item),
+                                   FALSE);
+
+    s->scale_x += .25;
+    s->scale_y += .25;
+
+    gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item),
+                                   FALSE);
+
+    s->scale_x -= .25;
+    s->scale_y -= .25;
+
+    s->scale_x = MAX(s->scale_x, .25);
+    s->scale_y = MAX(s->scale_y, .25);
+
+    gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    s->scale_x = 1.0;
+    s->scale_y = 1.0;
+
+    gd_resize(s->ds);
+}
+
+static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    int ww, wh;
+
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item))) {
+        s->free_scale = TRUE;
+    } else {
+        s->free_scale = FALSE;
+    }
+
+    gd_resize(s->ds);
+
+    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+    gtk_widget_queue_draw_area(s->drawing_area, 0, 0, ww, wh);
+}
+
+static void gd_grab_keyboard(GtkDisplayState *s)
+{
+    gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
+                      FALSE,
+                      GDK_CURRENT_TIME);
+}
+
+static void gd_ungrab_keyboard(GtkDisplayState *s)
+{
+    gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+}
+
+static void gd_menu_grab_input(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (gd_is_grab_active(s)) {
+        gd_grab_keyboard(s);
+        gdk_pointer_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)),
+                         FALSE, /* All events to come to our window directly */
+                         GDK_POINTER_MOTION_MASK |
+                         GDK_BUTTON_PRESS_MASK |
+                         GDK_BUTTON_RELEASE_MASK |
+                         GDK_BUTTON_MOTION_MASK |
+                         GDK_SCROLL_MASK,
+                         NULL, /* Allow cursor to move over entire desktop */
+                         s->null_cursor,
+                         GDK_CURRENT_TIME);
+    } else {
+        gd_ungrab_keyboard(s);
+        gdk_pointer_ungrab(GDK_CURRENT_TIME);
+    }
+
+    gd_update_caption(s);
+    gd_update_cursor(s, FALSE);
+}
+
+static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
+                           gpointer data)
+{
+    GtkDisplayState *s = data;
+    guint last_page;
+    gboolean on_vga;
+
+    if (!gtk_widget_get_realized(s->notebook)) {
+        return;
+    }
+
+    last_page = gtk_notebook_get_current_page(nb);
+
+    if (last_page) {
+        gtk_widget_set_size_request(s->vc[last_page - 1].terminal, -1, -1);
+    }
+
+    on_vga = arg2 == 0;
+
+    if (!on_vga) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+                                       FALSE);
+    } else if (s->full_screen) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+                                       TRUE);
+    }
+
+    if (arg2 == 0) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE);
+    } else {
+        VirtualConsole *vc = &s->vc[arg2 - 1];
+        VteTerminal *term = VTE_TERMINAL(vc->terminal);
+        int width, height;
+
+        width = 80 * vte_terminal_get_char_width(term);
+        height = 25 * vte_terminal_get_char_height(term);
+
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE);
+        gtk_widget_set_size_request(vc->terminal, width, height);
+    }
+
+    gtk_widget_set_sensitive(s->grab_item, on_vga);
+
+    gd_update_cursor(s, TRUE);
+}
+
+static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data)
+{
+    GtkDisplayState *s = data;
+
+    if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) {
+        gd_grab_keyboard(s);
+    }
+
+    return TRUE;
+}
+
+static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data)
+{
+    GtkDisplayState *s = data;
+
+    if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) {
+        gd_ungrab_keyboard(s);
+    }
+
+    return TRUE;
+}
+
+/** Virtual Console Callbacks **/
+
+static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    VirtualConsole *vc = chr->opaque;
+
+    return write(vc->fd, buf, len);
+}
+
+static int nb_vcs;
+static CharDriverState *vcs[MAX_VCS];
+
+static CharDriverState *gd_vc_handler(QemuOpts *opts)
+{
+    CharDriverState *chr;
+
+    chr = g_malloc0(sizeof(*chr));
+    chr->chr_write = gd_vc_chr_write;
+
+    vcs[nb_vcs++] = chr;
+
+    return chr;
+}
+
+void early_gtk_display_init(void)
+{
+    register_vc_handler(gd_vc_handler);
+}
+
+static gboolean gd_vc_in(GIOChannel *chan, GIOCondition cond, void *opaque)
+{
+    VirtualConsole *vc = opaque;
+    uint8_t buffer[1024];
+    ssize_t len;
+
+    len = read(vc->fd, buffer, sizeof(buffer));
+    if (len <= 0) {
+        return FALSE;
+    }
+
+    qemu_chr_be_write(vc->chr, buffer, len);
+
+    return TRUE;
+}
+
+static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSList *group)
+{
+    const char *label;
+    char buffer[32];
+    char path[32];
+#if VTE_CHECK_VERSION(0, 26, 0)
+    VtePty *pty;
+#endif
+    GIOChannel *chan;
+    GtkWidget *scrolled_window;
+    GtkAdjustment *vadjustment;
+    int master_fd, slave_fd, ret;
+    struct termios tty;
+
+    snprintf(buffer, sizeof(buffer), "vc%d", index);
+    snprintf(path, sizeof(path), "<QEMU>/View/VC%d", index);
+
+    vc->chr = vcs[index];
+
+    if (vc->chr->label) {
+        label = vc->chr->label;
+    } else {
+        label = buffer;
+    }
+
+    vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, label);
+    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path);
+    gtk_accel_map_add_entry(path, GDK_KEY_2 + index, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+
+    vc->terminal = vte_terminal_new();
+
+    ret = openpty(&master_fd, &slave_fd, NULL, NULL, NULL);
+    g_assert(ret != -1);
+
+    /* Set raw attributes on the pty. */
+    tcgetattr(slave_fd, &tty);
+    cfmakeraw(&tty);
+    tcsetattr(slave_fd, TCSAFLUSH, &tty);
+
+#if VTE_CHECK_VERSION(0, 26, 0)
+    pty = vte_pty_new_foreign(master_fd, NULL);
+    vte_terminal_set_pty_object(VTE_TERMINAL(vc->terminal), pty);
+#else
+    vte_terminal_set_pty(VTE_TERMINAL(vc->terminal), master_fd);
+#endif
+
+    vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->terminal), -1);
+
+    vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->terminal));
+
+    scrolled_window = gtk_scrolled_window_new(NULL, vadjustment);
+    gtk_container_add(GTK_CONTAINER(scrolled_window), vc->terminal);
+
+    vte_terminal_set_size(VTE_TERMINAL(vc->terminal), 80, 25);
+
+    vc->fd = slave_fd;
+    vc->chr->opaque = vc;
+    vc->scrolled_window = scrolled_window;
+
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vc->scrolled_window),
+                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), scrolled_window, gtk_label_new(label));
+    g_signal_connect(vc->menu_item, "activate",
+                     G_CALLBACK(gd_menu_switch_vc), s);
+
+    gtk_menu_append(GTK_MENU(s->view_menu), vc->menu_item);
+
+    qemu_chr_generic_open(vc->chr);
+    if (vc->chr->init) {
+        vc->chr->init(vc->chr);
+    }
+
+    chan = g_io_channel_unix_new(vc->fd);
+    g_io_add_watch(chan, G_IO_IN, gd_vc_in, vc);
+
+    return group;
+}
+
+/** Window Creation **/
+
+static void gd_connect_signals(GtkDisplayState *s)
+{
+    g_signal_connect(s->show_tabs_item, "activate",
+                     G_CALLBACK(gd_menu_show_tabs), s);
+
+    g_signal_connect(s->window, "key-press-event",
+                     G_CALLBACK(gd_window_key_event), s);
+    g_signal_connect(s->window, "delete-event",
+                     G_CALLBACK(gd_window_close), s);
+
+    g_signal_connect(s->drawing_area, "expose-event",
+                     G_CALLBACK(gd_expose_event), s);
+    g_signal_connect(s->drawing_area, "motion-notify-event",
+                     G_CALLBACK(gd_motion_event), s);
+    g_signal_connect(s->drawing_area, "button-press-event",
+                     G_CALLBACK(gd_button_event), s);
+    g_signal_connect(s->drawing_area, "button-release-event",
+                     G_CALLBACK(gd_button_event), s);
+    g_signal_connect(s->drawing_area, "key-press-event",
+                     G_CALLBACK(gd_key_event), s);
+    g_signal_connect(s->drawing_area, "key-release-event",
+                     G_CALLBACK(gd_key_event), s);
+
+    g_signal_connect(s->pause_item, "activate",
+                     G_CALLBACK(gd_menu_pause), s);
+    g_signal_connect(s->reset_item, "activate",
+                     G_CALLBACK(gd_menu_reset), s);
+    g_signal_connect(s->powerdown_item, "activate",
+                     G_CALLBACK(gd_menu_powerdown), s);
+    g_signal_connect(s->quit_item, "activate",
+                     G_CALLBACK(gd_menu_quit), s);
+    g_signal_connect(s->full_screen_item, "activate",
+                     G_CALLBACK(gd_menu_full_screen), s);
+    g_signal_connect(s->zoom_in_item, "activate",
+                     G_CALLBACK(gd_menu_zoom_in), s);
+    g_signal_connect(s->zoom_out_item, "activate",
+                     G_CALLBACK(gd_menu_zoom_out), s);
+    g_signal_connect(s->zoom_fixed_item, "activate",
+                     G_CALLBACK(gd_menu_zoom_fixed), s);
+    g_signal_connect(s->zoom_fit_item, "activate",
+                     G_CALLBACK(gd_menu_zoom_fit), s);
+    g_signal_connect(s->vga_item, "activate",
+                     G_CALLBACK(gd_menu_switch_vc), s);
+    g_signal_connect(s->grab_item, "activate",
+                     G_CALLBACK(gd_menu_grab_input), s);
+    g_signal_connect(s->notebook, "switch-page",
+                     G_CALLBACK(gd_change_page), s);
+    g_signal_connect(s->drawing_area, "enter-notify-event",
+                     G_CALLBACK(gd_enter_event), s);
+    g_signal_connect(s->drawing_area, "leave-notify-event",
+                     G_CALLBACK(gd_leave_event), s);
+}
+
+static void gd_create_menus(GtkDisplayState *s)
+{
+    GtkStockItem item;
+    GtkAccelGroup *accel_group;
+    GSList *group = NULL;
+    GtkWidget *separator;
+    int i;
+
+    accel_group = gtk_accel_group_new();
+    s->machine_menu = gtk_menu_new();
+    gtk_menu_set_accel_group(GTK_MENU(s->machine_menu), accel_group);
+    s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine"));
+
+    s->pause_item = gtk_check_menu_item_new_with_mnemonic(_("_Pause"));
+    gtk_menu_append(GTK_MENU(s->machine_menu), s->pause_item);
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->machine_menu), separator);
+
+    s->reset_item = gtk_image_menu_item_new_with_mnemonic(_("_Reset"));
+    gtk_menu_append(GTK_MENU(s->machine_menu), s->reset_item);
+
+    s->powerdown_item = gtk_image_menu_item_new_with_mnemonic(_("Power _Down"));
+    gtk_menu_append(GTK_MENU(s->machine_menu), s->powerdown_item);
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->machine_menu), separator);
+
+    s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
+    gtk_stock_lookup(GTK_STOCK_QUIT, &item);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
+                                 "<QEMU>/Machine/Quit");
+    gtk_accel_map_add_entry("<QEMU>/Machine/Quit", item.keyval, item.modifier);
+    gtk_menu_append(GTK_MENU(s->machine_menu), s->quit_item);
+
+    s->view_menu = gtk_menu_new();
+    gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
+    s->view_menu_item = gtk_menu_item_new_with_mnemonic(_("_View"));
+
+    s->full_screen_item =
+        gtk_image_menu_item_new_from_stock(GTK_STOCK_FULLSCREEN, NULL);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item),
+                                 "<QEMU>/View/Full Screen");
+    gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->full_screen_item);
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+    s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item),
+                                 "<QEMU>/View/Zoom In");
+    gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_in_item);
+
+    s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item),
+                                 "<QEMU>/View/Zoom Out");
+    gtk_accel_map_add_entry("<QEMU>/View/Zoom Out", GDK_KEY_minus, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_out_item);
+
+    s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL);
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item),
+                                 "<QEMU>/View/Zoom Fixed");
+    gtk_accel_map_add_entry("<QEMU>/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fixed_item);
+
+    s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic(_("Zoom To _Fit"));
+    gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fit_item);
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+    s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic(_("Grab On _Hover"));
+    gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item);
+
+    s->grab_item = gtk_check_menu_item_new_with_mnemonic(_("_Grab Input"));
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item),
+                                 "<QEMU>/View/Grab Input");
+    gtk_accel_map_add_entry("<QEMU>/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->grab_item);
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
+    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
+                                 "<QEMU>/View/VGA");
+    gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
+
+    for (i = 0; i < nb_vcs; i++) {
+        VirtualConsole *vc = &s->vc[i];
+
+        group = gd_vc_init(s, vc, i, group);
+        s->nb_vcs++;
+    }
+
+    separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(s->view_menu), separator);
+
+    s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic(_("Show _Tabs"));
+    gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item);
+
+    g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
+    gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
+    s->accel_group = accel_group;
+
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item),
+                              s->machine_menu);
+    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->machine_menu_item);
+
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
+    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
+}
+
+void gtk_display_init(DisplayState *ds)
+{
+    GtkDisplayState *s = g_malloc0(sizeof(*s));
+
+    gtk_init(NULL, NULL);
+
+    ds->opaque = s;
+    s->ds = ds;
+    s->dcl.dpy_gfx_update = gd_update;
+    s->dcl.dpy_gfx_resize = gd_resize;
+    s->dcl.dpy_refresh = gd_refresh;
+
+    s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    s->vbox = gtk_vbox_new(FALSE, 0);
+    s->notebook = gtk_notebook_new();
+    s->drawing_area = gtk_drawing_area_new();
+    s->menu_bar = gtk_menu_bar_new();
+
+    s->scale_x = 1.0;
+    s->scale_y = 1.0;
+    s->free_scale = FALSE;
+
+    setlocale(LC_ALL, "");
+    bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR);
+    textdomain("qemu");
+
+    s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
+
+    s->mouse_mode_notifier.notify = gd_mouse_mode_change;
+    qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
+    qemu_add_vm_change_state_handler(gd_change_runstate, s);
+
+    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
+
+    gd_create_menus(s);
+
+    gd_connect_signals(s);
+
+    gtk_widget_add_events(s->drawing_area,
+                          GDK_POINTER_MOTION_MASK |
+                          GDK_BUTTON_PRESS_MASK |
+                          GDK_BUTTON_RELEASE_MASK |
+                          GDK_BUTTON_MOTION_MASK |
+                          GDK_ENTER_NOTIFY_MASK |
+                          GDK_LEAVE_NOTIFY_MASK |
+                          GDK_SCROLL_MASK |
+                          GDK_KEY_PRESS_MASK);
+    gtk_widget_set_double_buffered(s->drawing_area, FALSE);
+    gtk_widget_set_can_focus(s->drawing_area, TRUE);
+
+    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
+    gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
+
+    gd_update_caption(s);
+
+    gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0);
+
+    gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
+
+    gtk_widget_show_all(s->window);
+
+    register_displaychangelistener(ds, &s->dcl);
+
+    global_state = s;
+}
index c71acbc5031b97d389a987b8df4e3e1318ecceaa..71bd6c531c85363a9b9bcfda402fca85784d1041 100644 (file)
@@ -70,7 +70,7 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc)
 #endif
     }
     env1->exception_index = -1;
-    longjmp(env1->jmp_env, 1);
+    siglongjmp(env1->jmp_env, 1);
 }
 
 /* 'pc' is the host PC at which the exception was raised. 'address' is
diff --git a/vl.c b/vl.c
index c5b0eea29b6a37bb95f0ebdd8197acb51bec2bac..0da156e8b4892822cabbcd5025654438e22a2fcb 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -1427,8 +1427,9 @@ static int usb_device_del(const char *devname)
     int bus_num, addr;
     const char *p;
 
-    if (strstart(devname, "host:", &p))
-        return usb_host_device_close(p);
+    if (strstart(devname, "host:", &p)) {
+        return -1;
+    }
 
     if (!usb_enabled(false)) {
         return -1;
@@ -2205,6 +2206,13 @@ static DisplayType select_display(const char *p)
 #else
         fprintf(stderr, "Curses support is disabled\n");
         exit(1);
+#endif
+    } else if (strstart(p, "gtk", &opts)) {
+#ifdef CONFIG_GTK
+        display = DT_GTK;
+#else
+        fprintf(stderr, "GTK support is disabled\n");
+        exit(1);
 #endif
     } else if (strstart(p, "none", &opts)) {
         display = DT_NONE;
@@ -3998,6 +4006,28 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+    if (using_spice) {
+        display_remote++;
+    }
+    if (display_type == DT_DEFAULT && !display_remote) {
+#if defined(CONFIG_GTK)
+        display_type = DT_GTK;
+#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+        display_type = DT_SDL;
+#elif defined(CONFIG_VNC)
+        vnc_display = "localhost:0,to=99";
+        show_vnc_port = 1;
+#else
+        display_type = DT_NONE;
+#endif
+    }
+
+#if defined(CONFIG_GTK)
+    if (display_type == DT_GTK) {
+        early_gtk_display_init();
+    }
+#endif
+
     socket_init();
 
     if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0)
@@ -4226,20 +4256,6 @@ int main(int argc, char **argv, char **envp)
     /* just use the first displaystate for the moment */
     ds = get_displaystate();
 
-    if (using_spice)
-        display_remote++;
-    if (display_type == DT_DEFAULT && !display_remote) {
-#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
-        display_type = DT_SDL;
-#elif defined(CONFIG_VNC)
-        vnc_display = "localhost:0,to=99";
-        show_vnc_port = 1;
-#else
-        display_type = DT_NONE;
-#endif
-    }
-
-
     /* init local displays */
     switch (display_type) {
     case DT_NOGRAPHIC:
@@ -4257,6 +4273,11 @@ int main(int argc, char **argv, char **envp)
     case DT_SDL:
         cocoa_display_init(ds, full_screen);
         break;
+#endif
+#if defined(CONFIG_GTK)
+    case DT_GTK:
+        gtk_display_init(ds);
+        break;
 #endif
     default:
         break;