[Spice-commits] 47 commits - .gitignore Makefile TODO aio-posix.c async.c configure 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 default-configs/x86_64-softmmu.mak hw/Makefile.objs hw/ppc4xx_devs.c hw/qxl-render.c hw/usb hw/usb.h hw/vga.c hw/vmware_vga.c hw/xenfb.c hw/xilinx_axienet.c include/block include/qemu include/sysemu include/ui iohandler.c main-loop.c po/Makefile po/de_DE.po po/it.po po/messages.po 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 tests/.gitignore tests/rtc-test.c trace-events ui/Makefile.objs ui/console.c ui/gtk.c vl.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Fri Feb 22 03:10:01 PST 2013


 .gitignore                           |    3 
 Makefile                             |    3 
 TODO                                 |   37 -
 aio-posix.c                          |  130 +--
 async.c                              |    2 
 configure                            |   39 +
 default-configs/alpha-softmmu.mak    |    1 
 default-configs/arm-softmmu.mak      |    1 
 default-configs/i386-softmmu.mak     |    1 
 default-configs/m68k-softmmu.mak     |    1 
 default-configs/mips-softmmu.mak     |    1 
 default-configs/mips64-softmmu.mak   |    1 
 default-configs/mips64el-softmmu.mak |    1 
 default-configs/mipsel-softmmu.mak   |    1 
 default-configs/ppc-softmmu.mak      |    1 
 default-configs/ppc64-softmmu.mak    |    1 
 default-configs/ppcemb-softmmu.mak   |    1 
 default-configs/sh4-softmmu.mak      |    1 
 default-configs/sh4eb-softmmu.mak    |    1 
 default-configs/sparc64-softmmu.mak  |    1 
 default-configs/usb.mak              |    8 
 default-configs/x86_64-softmmu.mak   |    1 
 hw/Makefile.objs                     |    2 
 hw/ppc4xx_devs.c                     |    2 
 hw/qxl-render.c                      |    3 
 hw/usb.h                             |   13 
 hw/usb/Makefile.objs                 |   30 
 hw/usb/core.c                        |   35 -
 hw/usb/desc.c                        |    9 
 hw/usb/dev-bluetooth.c               |    2 
 hw/usb/dev-hid.c                     |    2 
 hw/usb/dev-hub.c                     |   10 
 hw/usb/dev-network.c                 |    2 
 hw/usb/dev-smartcard-reader.c        |    2 
 hw/usb/dev-storage.c                 |    5 
 hw/usb/dev-uas.c                     |  247 ++++++-
 hw/usb/dev-wacom.c                   |    4 
 hw/usb/hcd-ehci.c                    |    7 
 hw/usb/hcd-musb.c                    |    2 
 hw/usb/hcd-ohci.c                    |    4 
 hw/usb/hcd-uhci.c                    |    2 
 hw/usb/hcd-xhci.c                    |  275 ++++++--
 hw/usb/host-bsd.c                    |    6 
 hw/usb/host-legacy.c                 |  144 ++++
 hw/usb/host-linux.c                  |  125 ---
 hw/usb/host-stub.c                   |    5 
 hw/usb/host.h                        |   44 +
 hw/usb/redirect.c                    |   18 
 hw/vga.c                             |   18 
 hw/vmware_vga.c                      |    2 
 hw/xenfb.c                           |    3 
 hw/xilinx_axienet.c                  |    4 
 include/block/aio.h                  |    3 
 include/qemu/main-loop.h             |    4 
 include/sysemu/sysemu.h              |    2 
 include/ui/console.h                 |   13 
 iohandler.c                          |   40 -
 main-loop.c                          |  158 ++--
 po/Makefile                          |   46 +
 po/de_DE.po                          |   45 +
 po/it.po                             |   45 +
 po/messages.po                       |   45 +
 qapi-schema.json                     |    6 
 qemu-char.c                          |    2 
 qemu-options.hx                      |    4 
 qom/object.c                         |    4 
 scripts/make_device_config.sh        |    2 
 slirp/libslirp.h                     |    6 
 slirp/main.h                         |    1 
 slirp/slirp.c                        |  673 ++++++++++----------
 slirp/socket.c                       |    9 
 slirp/socket.h                       |    2 
 stubs/slirp.c                        |    6 
 tests/.gitignore                     |    7 
 tests/rtc-test.c                     |  238 ++++++-
 trace-events                         |    6 
 ui/Makefile.objs                     |    3 
 ui/console.c                         |   23 
 ui/gtk.c                             | 1144 +++++++++++++++++++++++++++++++++++
 vl.c                                 |   53 +
 80 files changed, 2969 insertions(+), 885 deletions(-)

New commits:
commit 73d4dc71f3a41131541c73b3ac2a8b160a51842b
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:26 2013 -0600

    gtk: suppress accelerators from the File menu when grab is active
    
    If you're full screen, you probably expect Ctrl-Q to go to the guest,
    not the host.  I think restricting certain menus is the right way to
    handle this generally speaking.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-10-git-send-email-aliguori at us.ibm.com

diff --git a/ui/gtk.c b/ui/gtk.c
index ffa9baa..29156be 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -78,6 +78,8 @@ typedef struct GtkDisplayState
 
     GtkWidget *menu_bar;
 
+    GtkAccelGroup *accel_group;
+
     GtkWidget *file_menu_item;
     GtkWidget *file_menu;
     GtkWidget *quit_item;
@@ -296,6 +298,35 @@ static void gd_mouse_mode_change(Notifier *notify, void *data)
 
 /** 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)
 {
@@ -903,6 +934,8 @@ 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);
 
@@ -1033,6 +1066,7 @@ static void gd_create_menus(GtkDisplayState *s)
 
     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_append(GTK_MENU(s->file_menu), s->quit_item);
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu);
commit 15546425c5527ebb08ede399373b705866f1ff84
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:25 2013 -0600

    gtk: make default UI (v5)
    
    A user can still enable SDL with '-sdl' or '-display sdl' but start making the
    default display GTK by default.
    
    I'd also like to deprecate the SDL display and remove it in a few releases.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-9-git-send-email-aliguori at us.ibm.com

diff --git a/vl.c b/vl.c
index 955d2ff..0da156e 100644
--- a/vl.c
+++ b/vl.c
@@ -2207,6 +2207,13 @@ static DisplayType select_display(const char *p)
         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;
     } else {
@@ -3999,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)
@@ -4227,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:
@@ -4259,6 +4274,11 @@ int main(int argc, char **argv, char **envp)
         cocoa_display_init(ds, full_screen);
         break;
 #endif
+#if defined(CONFIG_GTK)
+    case DT_GTK:
+        gtk_display_init(ds);
+        break;
+#endif
     default:
         break;
     }
commit 834574ea89fa9c3ee0a557a13ad3f50db2509054
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:24 2013 -0600

    gtk: add translation support (v5)
    
    This includes a de_DE translation from Kevin Wolf and an it translation from
    Paolo Bonzini.
    
    Cc: Paolo Bonzini <pbonzini at redhat.com>
    Cc: Kevin Wolf <kwolf at redhat.com>
    Cc: Stefan Hajnoczi <stefanha at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-8-git-send-email-aliguori at us.ibm.com

diff --git a/Makefile b/Makefile
index 0d9099a..2262410 100644
--- a/Makefile
+++ b/Makefile
@@ -314,6 +314,9 @@ ifneq ($(BLOBS),)
 		$(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 \
 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
diff --git a/configure b/configure
index 5ea760b..0dadd31 100755
--- a/configure
+++ b/configure
@@ -3243,6 +3243,7 @@ fi
 
 qemu_confdir=$sysconfdir$confsuffix
 qemu_datadir=$datadir$confsuffix
+qemu_localedir="$datadir/locale"
 
 tools=""
 if test "$want_tools" = "yes" ; then
@@ -3416,6 +3417,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
@@ -4336,7 +4338,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"
diff --git a/po/Makefile b/po/Makefile
new file mode 100644
index 0000000..2b4420f
--- /dev/null
+++ b/po/Makefile
@@ -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 at 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
index 0000000..cb74d7c
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,45 @@
+# German translation for QEMU.
+# This file is put in the public domain.
+# Kevin Wolf <kwolf at redhat.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel at 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 at redhat.com>\n"
+"Language-Team: Deutsch <de at 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:1002
+msgid "_Full Screen"
+msgstr "Voll_bild"
+
+#: ../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
index 0000000..2b23491
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,45 @@
+# Italian translation for QEMU.
+# This file is put in the public domain.
+# Paolo Bonzini <pbonzini at redhat.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel at 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 at redhat.com>\n"
+"Language-Team: Italian <it at 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:1002
+msgid "_Full Screen"
+msgstr "_Schermo intero"
+
+#: ../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
index 0000000..a90cd6f
--- /dev/null
+++ b/po/messages.po
@@ -0,0 +1,45 @@
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 1.4.50\n"
+"Report-Msgid-Bugs-To: qemu-devel at 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 at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at 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:1002
+msgid "_Full Screen"
+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 ""
diff --git a/ui/gtk.c b/ui/gtk.c
index 01a1777..ffa9baa 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -31,8 +31,12 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
+#define GETTEXT_PACKAGE "qemu"
+#define LOCALEDIR "po"
+
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
 #include <vte/vte.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -950,7 +954,7 @@ static void gd_create_menus(GtkDisplayState *s)
     accel_group = gtk_accel_group_new();
     s->file_menu = gtk_menu_new();
     gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
-    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
+    s->file_menu_item = gtk_menu_item_new_with_mnemonic(_("_File"));
 
     s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
     gtk_stock_lookup(GTK_STOCK_QUIT, &item);
@@ -960,9 +964,9 @@ static void gd_create_menus(GtkDisplayState *s)
 
     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->view_menu_item = gtk_menu_item_new_with_mnemonic(_("_View"));
 
-    s->full_screen_item = gtk_check_menu_item_new_with_mnemonic("_Full Screen");
+    s->full_screen_item = gtk_check_menu_item_new_with_mnemonic(_("_Full Screen"));
     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);
@@ -989,16 +993,16 @@ static void gd_create_menus(GtkDisplayState *s)
     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");
+    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");
+    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");
+    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);
@@ -1024,7 +1028,7 @@ static void gd_create_menus(GtkDisplayState *s)
     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");
+    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);
@@ -1060,6 +1064,10 @@ void gtk_display_init(DisplayState *ds)
     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;
commit c61584833c579cd7bf800499124ce3d0e15bfb37
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:23 2013 -0600

    gtk: add support for screen scaling and full screen (v5)
    
    Basic menu items to enter full screen mode and zoom in/out.  Unlike SDL, we
    don't allow arbitrary scaling based on window resizing.  The current behavior
    with SDL causes a lot of problems for me.
    
    Sometimes I accidentally resize the window a tiny bit while trying to move it
    (Ubuntu's 1-pixel window decorations don't help here).  After that, scaling is
    now active and if the screen changes size again, badness ensues since the
    aspect ratio is skewed.
    
    Allowing zooming by 25% in and out should cover most use cases.  We can add a
    more flexible scaling later but for now, I think this is a more friendly
    behavior.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-7-git-send-email-aliguori at us.ibm.com

diff --git a/ui/gtk.c b/ui/gtk.c
index 0c1ec4d..01a1777 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -80,6 +80,11 @@ typedef struct GtkDisplayState
 
     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;
@@ -101,9 +106,11 @@ typedef struct GtkDisplayState
 
     double scale_x;
     double scale_y;
+    gboolean full_screen;
 
     GdkCursor *null_cursor;
     Notifier mouse_mode_notifier;
+    gboolean free_scale;
 } GtkDisplayState;
 
 static GtkDisplayState *global_state;
@@ -135,7 +142,7 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override)
     on_vga = gd_on_vga(s);
 
     if ((override || on_vga) &&
-        (kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
+        (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);
@@ -173,6 +180,9 @@ 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);
 
@@ -182,7 +192,20 @@ static void gd_update(DisplayState *ds, int x, int y, int w, int h)
     x2 = ceil(x * s->scale_x + w * s->scale_x);
     y2 = ceil(y * s->scale_y + h * s->scale_y);
 
-    gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1));
+    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)
@@ -227,9 +250,29 @@ static void gd_resize(DisplayState *ds)
                                                      ds_get_height(ds),
                                                      ds_get_linesize(ds));
 
-    gtk_widget_set_size_request(s->drawing_area,
-                                ds_get_width(ds) * s->scale_x,
-                                ds_get_height(ds) * s->scale_y);
+    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 **/
@@ -266,29 +309,55 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
 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);
 
-    cairo_rectangle(cr, 0, 0, ww, wh);
-
-    if (ww != fbw || wh != fbh) {
+    if (s->full_screen) {
         s->scale_x = (double)ww / fbw;
         s->scale_y = (double)wh / fbh;
-        cairo_scale(cr, s->scale_x, s->scale_y);
-    } else {
-        s->scale_x = 1.0;
-        s->scale_y = 1.0;
+    } 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;
 
-    cairo_set_source_surface(cr, s->surface, 0, 0);
+    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;
@@ -321,9 +390,31 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
     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;
 
-    x = motion->x / s->scale_x;
-    y = motion->y / 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);
@@ -492,6 +583,90 @@ static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
     }
 }
 
+static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->full_screen_item))) {
+        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)),
@@ -551,6 +726,9 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
     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) {
@@ -739,6 +917,16 @@ static void gd_connect_signals(GtkDisplayState *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",
@@ -774,6 +962,39 @@ static void gd_create_menus(GtkDisplayState *s)
     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_check_menu_item_new_with_mnemonic("_Full Screen");
+    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);
 
@@ -837,6 +1058,7 @@ void gtk_display_init(DisplayState *ds)
 
     s->scale_x = 1.0;
     s->scale_y = 1.0;
+    s->free_scale = FALSE;
 
     s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
 
@@ -865,8 +1087,6 @@ void gtk_display_init(DisplayState *ds)
     gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
     gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
 
-    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
-
     gd_update_caption(s);
 
     gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0);
commit 5104a1f65088285ddf870aa641b9061064e8757d
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:22 2013 -0600

    gtk: add support for input grabbing (v2)
    
    There is a small deviation from SDL's behavior here.  Instead of Ctrl+Alt
    triggering grab, we now use Ctrl-Alt-g to trigger grab.
    
    GTK will not accept Ctrl+Alt as an accelerator since it just consists of
    modifiers.  Having grab as a proper accelerator is important as it allows a user
    to override the accelerator for accessibility purposes.
    
    We also are not automatically grabbing on left-click.  Besides the inability to
    tie mouse clicks to an accelerator, I think this behavior is hard to discover
    and since it only happens depending on the guest state, it can lead to confusing
    behavior.
    
    This can be changed in the future if there's a strong resistence to dropping
    left-click-to-grab, but I think we're better off dropping it.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-6-git-send-email-aliguori at us.ibm.com

diff --git a/ui/gtk.c b/ui/gtk.c
index 94f0461..0c1ec4d 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -80,6 +80,8 @@ typedef struct GtkDisplayState
 
     GtkWidget *view_menu_item;
     GtkWidget *view_menu;
+    GtkWidget *grab_item;
+    GtkWidget *grab_on_hover_item;
     GtkWidget *vga_item;
 
     int nb_vcs;
@@ -108,6 +110,21 @@ 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;
@@ -115,9 +132,10 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override)
 
     window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
 
-    on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
+    on_vga = gd_on_vga(s);
 
-    if ((override || on_vga) && kbd_mouse_is_absolute()) {
+    if ((override || on_vga) &&
+        (kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
         gdk_window_set_cursor(window, s->null_cursor);
     } else {
         gdk_window_set_cursor(window, NULL);
@@ -128,15 +146,20 @@ static void gd_update_caption(GtkDisplayState *s)
 {
     const char *status = "";
     gchar *title;
+    const char *grab = "";
+
+    if (gd_is_grab_active(s)) {
+        grab = " - Press Ctrl+Alt+G to release grab";
+    }
 
     if (!runstate_is_running()) {
         status = " [Stopped]";
     }
 
     if (qemu_name) {
-        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
+        title = g_strdup_printf("QEMU (%s)%s%s", qemu_name, status, grab);
     } else {
-        title = g_strdup_printf("QEMU%s", status);
+        title = g_strdup_printf("QEMU%s%s", status, grab);
     }
 
     gtk_window_set_title(GTK_WINDOW(s->window), title);
@@ -262,6 +285,9 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
         s->scale_y = 1.0;
     }
 
+    fbw *= s->scale_x;
+    fbh *= s->scale_y;
+
     cairo_set_source_surface(cr, s->surface, 0, 0);
     cairo_paint(cr);
 
@@ -313,10 +339,44 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
     s->last_x = x;
     s->last_y = y;
 
-    if (kbd_mouse_is_absolute()) {
+    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;
 }
 
@@ -432,11 +492,49 @@ static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
     }
 }
 
+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;
@@ -448,6 +546,13 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
         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);
+    }
+
     if (arg2 == 0) {
         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE);
     } else {
@@ -462,9 +567,33 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
         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)
@@ -612,8 +741,14 @@ static void gd_connect_signals(GtkDisplayState *s)
                      G_CALLBACK(gd_menu_quit), 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)
@@ -639,6 +774,15 @@ static void gd_create_menus(GtkDisplayState *s)
     gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group);
     s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View");
 
+    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);
 
@@ -711,6 +855,8 @@ void gtk_display_init(DisplayState *ds)
                           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);
commit d861def367b516055dc4c46dc1305143ee653c84
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:21 2013 -0600

    gtk: add virtual console support (v2)
    
    This enables VteTerminal to be used to render the text consoles.  VteTerminal is
    the same widget used by gnome-terminal which means it's VT100 emulation is as
    good as they come.
    
    It's also screen reader accessible, supports copy/paste, proper scrolling and
    most of the other features you would expect from a terminal widget.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-5-git-send-email-aliguori at us.ibm.com

diff --git a/ui/gtk.c b/ui/gtk.c
index 85e7999..94f0461 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -47,6 +47,7 @@
 #include "qmp-commands.h"
 #include "x_keymap.h"
 #include "keymaps.h"
+#include "char/char.h"
 
 //#define DEBUG_GTK
 
@@ -56,6 +57,8 @@
 #define DPRINTF(fmt, ...) do { } while (0)
 #endif
 
+#define MAX_VCS 10
+
 typedef struct VirtualConsole
 {
     GtkWidget *menu_item;
@@ -79,6 +82,9 @@ typedef struct GtkDisplayState
     GtkWidget *view_menu;
     GtkWidget *vga_item;
 
+    int nb_vcs;
+    VirtualConsole vc[MAX_VCS];
+
     GtkWidget *show_tabs_item;
 
     GtkWidget *vbox;
@@ -403,6 +409,15 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *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;
+            }
+        }
     }
 }
 
@@ -421,16 +436,153 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
                            gpointer data)
 {
     GtkDisplayState *s = data;
+    guint last_page;
 
     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);
+    }
+
+    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);
+    }
+
     gd_update_cursor(s, 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];
+    VtePty *pty;
+    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);
+
+    pty = vte_pty_new_foreign(master_fd, NULL);
+
+    vte_terminal_set_pty_object(VTE_TERMINAL(vc->terminal), pty);
+
+    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 **/
@@ -470,6 +622,7 @@ static void gd_create_menus(GtkDisplayState *s)
     GtkAccelGroup *accel_group;
     GSList *group = NULL;
     GtkWidget *separator;
+    int i;
 
     accel_group = gtk_accel_group_new();
     s->file_menu = gtk_menu_new();
@@ -496,6 +649,13 @@ static void gd_create_menus(GtkDisplayState *s)
     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);
 
commit a4ccabcf6deaeb42c65d5d6d84ba0ceff8003876
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:20 2013 -0600

    ui: add basic GTK gui (v5)
    
    This is minimalistic and just contains the basic widget infrastructure.  The GUI
    consists of a menu and a GtkNotebook.  To start with, the notebook has its tabs
    hidden which provides a UI that looks very similar to SDL with the exception of
    the menu bar.
    
    The menu bar allows a user to toggle the visibility of the tabs.  Cairo is used
    for rendering.
    
    I used gtk-vnc as a reference.  gtk-vnc solves the same basic problems as QEMU
    since it was originally written as a remote display for QEMU.  So for the most
    part, the approach to rendering and keyboard handling should be pretty solid for
    GTK.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-4-git-send-email-aliguori at us.ibm.com

diff --git a/configure b/configure
index 2008978..5ea760b 100755
--- 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
@@ -1636,6 +1641,26 @@ if test "$sparse" != "no" ; then
 fi
 
 ##########################################
+# GTK probe
+
+if test "$gtk" != "no"; then
+    if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \
+       $pkg_config vte --modversion >/dev/null 2>/dev/null; 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
 
 # Look for sdl configuration program (pkg-config or sdl-config).  Try
@@ -3301,6 +3326,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"
@@ -3591,6 +3617,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
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index ae49088..b19ec95 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -89,6 +89,7 @@ typedef enum DisplayType
     DT_DEFAULT,
     DT_CURSES,
     DT_SDL,
+    DT_GTK,
     DT_NOGRAPHIC,
     DT_NONE,
 } DisplayType;
diff --git a/include/ui/console.h b/include/ui/console.h
index 694994b..c42bca6 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -487,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
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index d9db073..85c50cd 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -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)
diff --git a/ui/gtk.c b/ui/gtk.c
new file mode 100644
index 0000000..85e7999
--- /dev/null
+++ b/ui/gtk.c
@@ -0,0 +1,576 @@
+/*
+ * GTK UI
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at 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 at codemonkey.ws>
+ * Copyright (C) 2009-2010 Daniel P. Berrange <dan at 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
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.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 "qemu-common.h"
+#include "ui/console.h"
+#include "sysemu/sysemu.h"
+#include "qmp-commands.h"
+#include "x_keymap.h"
+#include "keymaps.h"
+
+//#define DEBUG_GTK
+
+#ifdef DEBUG_GTK
+#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+typedef struct VirtualConsole
+{
+    GtkWidget *menu_item;
+    GtkWidget *terminal;
+    GtkWidget *scrolled_window;
+    CharDriverState *chr;
+    int fd;
+} VirtualConsole;
+
+typedef struct GtkDisplayState
+{
+    GtkWidget *window;
+
+    GtkWidget *menu_bar;
+
+    GtkWidget *file_menu_item;
+    GtkWidget *file_menu;
+    GtkWidget *quit_item;
+
+    GtkWidget *view_menu_item;
+    GtkWidget *view_menu;
+    GtkWidget *vga_item;
+
+    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;
+
+    GdkCursor *null_cursor;
+    Notifier mouse_mode_notifier;
+} GtkDisplayState;
+
+static GtkDisplayState *global_state;
+
+/** Utility Functions **/
+
+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 = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0);
+
+    if ((override || on_vga) && kbd_mouse_is_absolute()) {
+        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;
+
+    if (!runstate_is_running()) {
+        status = " [Stopped]";
+    }
+
+    if (qemu_name) {
+        title = g_strdup_printf("QEMU (%s)%s", qemu_name, status);
+    } else {
+        title = g_strdup_printf("QEMU%s", status);
+    }
+
+    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;
+
+    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);
+
+    gtk_widget_queue_draw_area(s->drawing_area, x1, 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));
+
+    gtk_widget_set_size_request(s->drawing_area,
+                                ds_get_width(ds) * s->scale_x,
+                                ds_get_height(ds) * s->scale_y);
+}
+
+/** 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_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 ww, wh;
+    int fbw, fbh;
+
+    fbw = ds_get_width(s->ds);
+    fbh = ds_get_height(s->ds);
+
+    gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
+
+    cairo_rectangle(cr, 0, 0, ww, wh);
+
+    if (ww != fbw || wh != fbh) {
+        s->scale_x = (double)ww / fbw;
+        s->scale_y = (double)wh / fbh;
+        cairo_scale(cr, s->scale_x, s->scale_y);
+    } else {
+        s->scale_x = 1.0;
+        s->scale_y = 1.0;
+    }
+
+    cairo_set_source_surface(cr, s->surface, 0, 0);
+    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;
+
+    x = motion->x / s->scale_x;
+    y = motion->y / s->scale_y;
+
+    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()) {
+        kbd_mouse_event(dx, dy, 0, s->button_mask);
+    }
+
+    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_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);
+    }
+}
+
+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_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
+                           gpointer data)
+{
+    GtkDisplayState *s = data;
+
+    if (!gtk_widget_get_realized(s->notebook)) {
+        return;
+    }
+
+    gd_update_cursor(s, TRUE);
+}
+
+void early_gtk_display_init(void)
+{
+}
+
+/** 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, "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->quit_item, "activate",
+                     G_CALLBACK(gd_menu_quit), s);
+    g_signal_connect(s->vga_item, "activate",
+                     G_CALLBACK(gd_menu_switch_vc), s);
+    g_signal_connect(s->notebook, "switch-page",
+                     G_CALLBACK(gd_change_page), s);
+}
+
+static void gd_create_menus(GtkDisplayState *s)
+{
+    GtkStockItem item;
+    GtkAccelGroup *accel_group;
+    GSList *group = NULL;
+    GtkWidget *separator;
+
+    accel_group = gtk_accel_group_new();
+    s->file_menu = gtk_menu_new();
+    gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group);
+    s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File");
+
+    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>/File/Quit");
+    gtk_accel_map_add_entry("<QEMU>/File/Quit", item.keyval, item.modifier);
+
+    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");
+
+    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);
+
+    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);
+
+    gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item);
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu);
+    gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_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->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_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);
+
+    gtk_window_set_resizable(GTK_WINDOW(s->window), 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;
+}
commit d82831dbc5471d72785c49b33710436af49bf9ca
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:19 2013 -0600

    console: allow VCs to be overridden by UI
    
    We want to expose VCs using a VteTerminal widget.  We need access to provide our
    own CharDriverState in order to do this.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-3-git-send-email-aliguori at us.ibm.com

diff --git a/include/ui/console.h b/include/ui/console.h
index 18012f1..694994b 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -443,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);
@@ -451,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);
 
diff --git a/qemu-char.c b/qemu-char.c
index e4b0f53..160decc 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -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 },
diff --git a/ui/console.c b/ui/console.c
index 25e06a5..0d95f32 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1537,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;
@@ -1573,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;
commit 22bc9a46bda8f5f88626d3fb578f5d55953c9743
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Feb 20 07:43:18 2013 -0600

    build: disable Wstrict-prototypes
    
    GTK won't build with strict-prototypes due to gtkitemfactory.h:
    
        /* We use () here to mean unspecified arguments. This is deprecated
         * as of C99, but we can't change it without breaking compatibility.
         * (Note that if we are included from a C++ program () will mean
         * (void) so an explicit cast will be needed.)
         */
        typedef	void	(*GtkItemFactoryCallback)  ();
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Message-id: 1361367806-4599-2-git-send-email-aliguori at us.ibm.com

diff --git a/configure b/configure
index 42cb314..2008978 100755
--- a/configure
+++ b/configure
@@ -283,7 +283,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
 # default flags for all hosts
 QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
 QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
-QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
+QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS"
 QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
 QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/include"
 if test "$debug_info" = "yes"; then
commit 00e2ceae6c55bef40f5128a3e606f5c44351e0f9
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date:   Tue Feb 19 14:02:10 2013 +1000

    qom/object.c: Allow itf cast with num_itfs = 0
    
    num_interfaces only tells you how many interfaces the concrete child class has
    (as defined in the TypeInfo). This means if you have a child class which defines
    no interfaces of its own, but its parent has interfaces you cannot cast to those
    parent interfaces.
    
    Fixed changing the guard to check the class->interfaces list instead (which is
    a complete flattened list of implemented interfaces).
    
    Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
    Message-id: a8c2db3b9b1f3c4bb81aca352b69e33260f36545.1361246206.git.peter.crosthwaite at xilinx.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qom/object.c b/qom/object.c
index 4b72a64..3d638ff 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -449,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;
 
commit 3e407de47700cce4babbe0f3ac35677e7b852cf6
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date:   Tue Feb 19 14:02:09 2013 +1000

    qom/object.c: Reset interface list on inheritance
    
    The QOM framework will attempt the recreate a classes interface list from
    scratch for each class. This means that a child class should zero out the
    list of interfaces when cloned from the parent class.
    
    Currently the list is memcpy()d from the parent to the child. As the interface
    list is just a pointer to a list, this means the parent and child will share
    the same list of interfaces. When the child inits, it will append its own
    interfaces to the parents list. This is incorrect as the parent should not pick
    up its childs interfaces.
    
    This actually causes an infinite loop at class init time, as the child will
    iterate through the parent interface list adding each itf to its own list(in
    type_initialize()). As the list is (erroneously) shared, the new interface
    instances for the child are appended to the parent, and the iterator never hits
    the tail and loops forever.
    
    Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Message-id: 1f58d2b629d82865dbb2fd5ba8445854049c4382.1361246206.git.peter.crosthwaite at xilinx.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qom/object.c b/qom/object.c
index 563e45b..4b72a64 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -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;
commit b1424e0381a7f1c9969079eca4458d5f20bf1859
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Feb 20 09:37:12 2013 +0100

    vga: fix byteswapping.
    
    In case host and guest endianness differ the vga code first creates
    a shared surface (using qemu_create_displaysurface_from), then goes
    patch the surface format to indicate that the bytes must be swapped.
    
    The switch to pixman broke that hack as the format patching isn't
    propagated into the pixman image, so ui code using the pixman image
    directly (such as vnc) uses the wrong format.
    
    Fix that by adding a byteswap parameter to
    qemu_create_displaysurface_from, so we'll use the correct format
    when creating the surface (and the pixman image) and don't have
    to patch the format afterwards.
    
    [ v2: unbreak xen build ]
    
    Cc: qemu-stable at nongnu.org
    Cc: mark.cave-ayland at ilande.co.uk
    Cc: agraf at suse.de
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Message-id: 1361349432-23884-1-git-send-email-kraxel at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 88e63f8..455fb91 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -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,
diff --git a/hw/vga.c b/hw/vga.c
index e2ba7f2..1caf23d 100644
--- 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);
     }
 
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index cd15ee4..8fc201b 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -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);
     }
diff --git a/hw/xenfb.c b/hw/xenfb.c
index 903efd3..7f1f6b4 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -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 */
diff --git a/include/ui/console.h b/include/ui/console.h
index fc23baa..18012f1 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -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);
 
diff --git a/ui/console.c b/ui/console.c
index 0a68836..25e06a5 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -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);
commit ba43da36983a0bff2778abfa2338697da129030c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Feb 20 16:24:22 2013 +0000

    Remove elderly top level TODO file
    
    The top level TODO file hasn't been touched since 2008, so it's now
    an unhelpful and out of date mix of things that have already been done,
    things that don't make sense any more and things which could in theory
    be done but are not in practice important enough (or we'd have done
    them some time in the last five years). Remove it. The bug tracking
    system is probably a better place to track TODO items if we want to
    do so.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Message-id: 1361377462-19816-1-git-send-email-peter.maydell at linaro.org
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/TODO b/TODO
deleted file mode 100644
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
commit 2ca81baa0b3363d57de94f8b80c02a003b361161
Author: Jason Wang <jasowang at redhat.com>
Date:   Wed Feb 20 18:04:01 2013 +0800

    help: add docs for multiqueue tap options
    
    Cc: Markus Armbruster <armbru at redhat.com>
    Cc: Jason Wang <jasowang at redhat.com>
    Signed-off-by: Jason Wang <jasowang at redhat.com>
    Message-id: 1361354641-51969-1-git-send-email-jasowang at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 7275b5d..cd7ea25 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2504,6 +2504,9 @@
 #
 # @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
@@ -2518,6 +2521,9 @@
 #
 # @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
diff --git a/qemu-options.hx b/qemu-options.hx
index 4bc9c85..2832d82 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -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"
commit b5a01a70ad49b518c2c4b0f0a37f5435f01ce716
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:33 2013 +0100

    aio: support G_IO_HUP and G_IO_ERR
    
    aio-posix.c could not take advantage of G_IO_HUP and G_IO_ERR because
    select(2) does not have equivalent events.  Now that g_poll(3) is used
    we can support G_IO_HUP and G_IO_ERR.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-11-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/aio-posix.c b/aio-posix.c
index d755e16..b68eccd 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -88,8 +88,8 @@ void aio_set_fd_handler(AioContext *ctx,
         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);
@@ -112,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;
@@ -150,7 +143,6 @@ static bool aio_dispatch(AioContext *ctx)
         revents = node->pfd.revents & node->pfd.events;
         node->pfd.revents = 0;
 
-        /* See comment in aio_pending.  */
         if (!node->deleted &&
             (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
             node->io_read) {
commit 6b5f876252b7aeec43e319afdf17705f512be2bc
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:32 2013 +0100

    aio: convert aio_poll() to g_poll(3)
    
    AioHandler already has a GPollFD so we can directly use its
    events/revents.
    
    Add the int pollfds_idx field to AioContext so we can map g_poll(3)
    results back to AioHandlers.
    
    Reuse aio_dispatch() to invoke handlers after g_poll(3).
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-10-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/aio-posix.c b/aio-posix.c
index 35131a3..d755e16 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -25,6 +25,7 @@ struct AioHandler
     IOHandler *io_write;
     AioFlushHandler *io_flush;
     int deleted;
+    int pollfds_idx;
     void *opaque;
     QLIST_ENTRY(AioHandler) node;
 };
@@ -85,6 +86,7 @@ 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);
@@ -177,10 +179,7 @@ static bool aio_dispatch(AioContext *ctx)
 
 bool aio_poll(AioContext *ctx, bool blocking)
 {
-    static struct timeval tv0;
     AioHandler *node;
-    fd_set rdfds, wrfds;
-    int max_fd = -1;
     int ret;
     bool busy, progress;
 
@@ -206,12 +205,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.
@@ -222,13 +222,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);
         }
     }
 
@@ -240,41 +240,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 72d268a..f2d47ba 100644
--- 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 *)
diff --git a/include/block/aio.h b/include/block/aio.h
index 8eda924..5b54d38 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -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 */
commit d0c8d2c05f67a1a007d87fa3b99254abfa42d06d
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:31 2013 +0100

    aio: extract aio_dispatch() from aio_poll()
    
    We will need to loop over AioHandlers calling ->io_read()/->io_write()
    when aio_poll() is converted from select(2) to g_poll(2).
    
    Luckily the code for this already exists, extract it into the new
    aio_dispatch() function.
    
    Two small changes:
    
     * aio_poll() checks !node->deleted to avoid calling handlers that have
       been deleted.
    
     * Fix typo 'then' -> 'them' in aio_poll() comment.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-9-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/aio-posix.c b/aio-posix.c
index fe4dbb4..35131a3 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -129,30 +129,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.
      */
@@ -167,11 +149,15 @@ bool aio_poll(AioContext *ctx, bool blocking)
         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 +172,33 @@ bool aio_poll(AioContext *ctx, bool blocking)
             g_free(tmp);
         }
     }
+    return progress;
+}
+
+bool aio_poll(AioContext *ctx, bool blocking)
+{
+    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 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;
commit 9cbaacf999b01b27dc3a22502705178057af66de
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:30 2013 +0100

    main-loop: drop rfds/wfds/xfds for good
    
    Now that all *_fill() and *_poll() functions use GPollFD we no longer
    need rfds/wfds/xfds or pollfds_from_select()/pollfds_to_select().
    
    >From now on everything uses GPollFD.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-8-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/main-loop.c b/main-loop.c
index 800868a..8c9b58c 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -143,66 +143,8 @@ int qemu_init_main_loop(void)
     return 0;
 }
 
-static fd_set rfds, wfds, xfds;
-static int nfds;
 static int max_priority;
 
-/* Load rfds/wfds/xfds into gpollfds.  Will be removed a few commits later. */
-static void gpollfds_from_select(void)
-{
-    int fd;
-    for (fd = 0; fd <= nfds; fd++) {
-        int events = 0;
-        if (FD_ISSET(fd, &rfds)) {
-            events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
-        }
-        if (FD_ISSET(fd, &wfds)) {
-            events |= G_IO_OUT | G_IO_ERR;
-        }
-        if (FD_ISSET(fd, &xfds)) {
-            events |= G_IO_PRI;
-        }
-        if (events) {
-            GPollFD pfd = {
-                .fd = fd,
-                .events = events,
-            };
-            g_array_append_val(gpollfds, pfd);
-        }
-    }
-}
-
-/* Store gpollfds revents into rfds/wfds/xfds.  Will be removed a few commits
- * later.
- */
-static void gpollfds_to_select(int ret)
-{
-    int i;
-
-    FD_ZERO(&rfds);
-    FD_ZERO(&wfds);
-    FD_ZERO(&xfds);
-
-    if (ret <= 0) {
-        return;
-    }
-
-    for (i = 0; i < gpollfds->len; i++) {
-        int fd = g_array_index(gpollfds, GPollFD, i).fd;
-        int revents = g_array_index(gpollfds, GPollFD, i).revents;
-
-        if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
-            FD_SET(fd, &rfds);
-        }
-        if (revents & (G_IO_OUT | G_IO_ERR)) {
-            FD_SET(fd, &wfds);
-        }
-        if (revents & G_IO_PRI) {
-            FD_SET(fd, &xfds);
-        }
-    }
-}
-
 #ifndef _WIN32
 static int glib_pollfds_idx;
 static int glib_n_poll_fds;
@@ -251,15 +193,8 @@ static int os_host_main_loop_wait(uint32_t timeout)
         qemu_mutex_unlock_iothread();
     }
 
-    /* We'll eventually drop fd_set completely.  But for now we still have
-     * *_fill() and *_poll() functions that use rfds/wfds/xfds.
-     */
-    gpollfds_from_select();
-
     ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout);
 
-    gpollfds_to_select(ret);
-
     if (timeout > 0) {
         qemu_mutex_lock_iothread();
     }
@@ -417,6 +352,8 @@ static int os_host_main_loop_wait(uint32_t timeout)
     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;
@@ -463,10 +400,6 @@ static int os_host_main_loop_wait(uint32_t timeout)
      * improve socket latency.
      */
 
-    /* This back-and-forth between GPollFDs and select(2) is temporary.  We'll
-     * drop it in a couple of patches, I promise :).
-     */
-    gpollfds_from_select();
     FD_ZERO(&rfds);
     FD_ZERO(&wfds);
     FD_ZERO(&xfds);
@@ -480,7 +413,6 @@ static int os_host_main_loop_wait(uint32_t timeout)
             pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds);
         }
     }
-    gpollfds_to_select(select_ret);
 
     return select_ret || g_poll_ret;
 }
@@ -498,11 +430,6 @@ 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_pollfds_fill(gpollfds);
commit a3e4b4a8091cc4fcf7cb619570c72c54c2d6a6e9
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:29 2013 +0100

    iohandler: switch to GPollFD
    
    Convert iohandler_select_fill() and iohandler_select_poll() to use
    GPollFD instead of rfds/wfds/xfds.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-7-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index e8059c3..0995288 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -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);
diff --git a/iohandler.c b/iohandler.c
index 2523adc..ae2ef8f 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -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);
             }
 
diff --git a/main-loop.c b/main-loop.c
index 839e98f..800868a 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -507,9 +507,9 @@ int main_loop_wait(int nonblocking)
     slirp_update_timeout(&timeout);
     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_pollfds_poll(gpollfds, (ret < 0));
 #endif
commit 8917c3bdba37d6fe4393db0fad3fabbde9530d6b
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:28 2013 +0100

    slirp: switch to GPollFD
    
    Slirp uses rfds/wfds/xfds more extensively than other QEMU components.
    
    The rarely-used out-of-band TCP data feature is used.  That means we
    need the full table of select(2) to g_poll(3) events:
    
      rfds -> G_IO_IN | G_IO_HUP | G_IO_ERR
      wfds -> G_IO_OUT | G_IO_ERR
      xfds -> G_IO_PRI
    
    I came up with this table by looking at Linux fs/select.c which maps
    select(2) to poll(2) internally.
    
    Another detail to watch out for are the global variables that reference
    rfds/wfds/xfds during slirp_select_poll().  sofcantrcvmore() and
    sofcantsendmore() use these globals to clear fd_set bits.  When
    sofcantrcvmore() is called, the wfds bit is cleared so that the write
    handler will no longer be run for this iteration of the event loop.
    
    This actually seems buggy to me since TCP connections can be half-closed
    and we'd still want to handle data in half-duplex fashion.  I think the
    real intention is to avoid running the read/write handler when the
    socket has been fully closed.  This is indicated with the SS_NOFDREF
    state bit so we now check for it before invoking the TCP write handler.
    Note that UDP/ICMP code paths don't care because they are
    connectionless.
    
    Note that slirp/ has a lot of tabs and sometimes mixed tabs with spaces.
    I followed the style of the surrounding code.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-6-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/main-loop.c b/main-loop.c
index c2ede99..839e98f 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -505,13 +505,13 @@ int main_loop_wait(int nonblocking)
 
 #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);
     ret = os_host_main_loop_wait(timeout);
     qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
 #ifdef CONFIG_SLIRP
-    slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+    slirp_pollfds_poll(gpollfds, (ret < 0));
 #endif
 
     qemu_run_all_timers();
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 49609c2..ceabff8 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -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);
 
diff --git a/slirp/main.h b/slirp/main.h
index 66e4f92..f2e58cf 100644
--- a/slirp/main.h
+++ b/slirp/main.h
@@ -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;
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 5d14e7f..bd9b7cb 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -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,23 +266,15 @@ 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
      */
@@ -302,8 +290,12 @@ void slirp_select_fill(int *pnfds,
 
         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
              */
@@ -323,8 +315,12 @@ void slirp_select_fill(int *pnfds,
              * Set for reading sockets which are accepting
              */
             if (so->so_state & SS_FACCEPTCONN) {
-                FD_SET(so->s, readfds);
-                UPD_NFDS(so->s);
+                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;
             }
 
@@ -332,8 +328,12 @@ void slirp_select_fill(int *pnfds,
              * Set for writing sockets which are connecting
              */
             if (so->so_state & SS_ISFCONNECTING) {
-                FD_SET(so->s, writefds);
-                UPD_NFDS(so->s);
+                GPollFD pfd = {
+                    .fd = so->s,
+                    .events = G_IO_OUT | G_IO_ERR,
+                };
+                so->pollfds_idx = pollfds->len;
+                g_array_append_val(pollfds, pfd);
                 continue;
             }
 
@@ -342,8 +342,7 @@ void slirp_select_fill(int *pnfds,
              * we have something to send
              */
             if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
-                FD_SET(so->s, writefds);
-                UPD_NFDS(so->s);
+                events |= G_IO_OUT | G_IO_ERR;
             }
 
             /*
@@ -352,9 +351,16 @@ void slirp_select_fill(int *pnfds,
              */
             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);
+                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);
             }
         }
 
@@ -365,6 +371,8 @@ void slirp_select_fill(int *pnfds,
                 so = so_next) {
             so_next = so->so_next;
 
+            so->pollfds_idx = -1;
+
             /*
              * See if it's timed out
              */
@@ -388,8 +396,12 @@ void slirp_select_fill(int *pnfds,
              * (XXX <= 4 ?)
              */
             if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
-                FD_SET(so->s, readfds);
-                UPD_NFDS(so->s);
+                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);
             }
         }
 
@@ -400,6 +412,8 @@ void slirp_select_fill(int *pnfds,
                 so = so_next) {
             so_next = so->so_next;
 
+            so->pollfds_idx = -1;
+
             /*
              * See if it's timed out
              */
@@ -413,17 +427,18 @@ void slirp_select_fill(int *pnfds,
             }
 
             if (so->so_state & SS_ISFCONNECTED) {
-                FD_SET(so->s, readfds);
-                UPD_NFDS(so->s);
+                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);
             }
         }
     }
-
-    *pnfds = nfds;
 }
 
-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;
@@ -433,10 +448,6 @@ 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) {
@@ -462,12 +473,16 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
              */
             for (so = slirp->tcb.so_next; so != &slirp->tcb;
                     so = so_next) {
+                int revents;
+
                 so_next = so->so_next;
 
-                /*
-                 * FD_ISSET is meaningless on these sockets
-                 * (and they can crash the program)
-                 */
+                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;
                 }
@@ -475,15 +490,15 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
                 /*
                  * Check for URG data
                  * This will soread as well, so no need to
-                 * test for readfds below if this succeeds
+                 * test for G_IO_IN below if this succeeds
                  */
-                if (FD_ISSET(so->s, xfds)) {
+                if (revents & G_IO_PRI) {
                     sorecvoob(so);
                 }
                 /*
                  * Check sockets for reading
                  */
-                else if (FD_ISSET(so->s, readfds)) {
+                else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
                     /*
                      * Check for incoming connections
                      */
@@ -502,7 +517,8 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
                 /*
                  * Check sockets for writing
                  */
-                if (FD_ISSET(so->s, writefds)) {
+                if (!(so->so_state & SS_NOFDREF) &&
+                        (revents & (G_IO_OUT | G_IO_ERR))) {
                     /*
                      * Check for non-blocking, still-connecting sockets
                      */
@@ -588,9 +604,18 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
              */
             for (so = slirp->udb.so_next; so != &slirp->udb;
                     so = so_next) {
+                int revents;
+
                 so_next = so->so_next;
 
-                if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                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);
                 }
             }
@@ -600,9 +625,18 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
              */
             for (so = slirp->icmp.so_next; so != &slirp->icmp;
                     so = so_next) {
-                so_next = 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 && FD_ISSET(so->s, readfds)) {
+                    if (so->s != -1 &&
+                        (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
                     icmp_receive(so);
                 }
             }
@@ -610,15 +644,6 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
 
         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)
diff --git a/slirp/socket.c b/slirp/socket.c
index 77b0c98..a7ab933 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -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) {
diff --git a/slirp/socket.h b/slirp/socket.h
index 857b0da..57e0407 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -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 */
diff --git a/stubs/slirp.c b/stubs/slirp.c
index 9a3309a..f1fc833 100644
--- a/stubs/slirp.c
+++ b/stubs/slirp.c
@@ -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)
 {
 }
 
commit cf1d078e4ea094e516faab49678fbea3a34b7848
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:27 2013 +0100

    slirp: slirp/slirp.c coding style cleanup
    
    The slirp glue code uses tabs in some places.  Since the next patch will
    modify the file, convert tabs to spaces and fix checkpatch.pl issues.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-5-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/slirp/slirp.c b/slirp/slirp.c
index 0e6e232..5d14e7f 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -287,135 +287,139 @@ void slirp_select_fill(int *pnfds,
     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) {
+            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 */
+            }
 
-                    /*
-                     * 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) {
+                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);
+            }
+        }
 
-        *pnfds = nfds;
+        /*
+         * ICMP sockets
+         */
+        for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                so = so_next) {
+            so_next = so->so_next;
+
+            /*
+             * 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 */
+                }
+            }
+
+            if (so->so_state & SS_ISFCONNECTED) {
+                FD_SET(so->s, readfds);
+                UPD_NFDS(so->s);
+            }
+        }
+    }
+
+    *pnfds = nfds;
 }
 
 void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
@@ -436,177 +440,185 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *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) {
+                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
+                     */
+                }
 
                 /*
-                 * 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) {
+                so_next = so->so_next;
+
+                if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                    sorecvfrom(so);
                 }
-	}
+            }
+
+            /*
+             * Check incoming ICMP relies.
+             */
+            for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                    so = so_next) {
+                so_next = so->so_next;
+
+                if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                    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;
+    /* 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 +839,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 +864,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,
commit 48ce11ff972c733afaed3e2a2613a2e56081ec92
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:26 2013 +0100

    main-loop: switch POSIX glib integration to GPollFD
    
    Convert glib file descriptor polling from rfds/wfds/xfds to GPollFD.
    
    The Windows code still needs poll_fds[] and n_poll_fds but they can now
    become local variables.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-4-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/main-loop.c b/main-loop.c
index 489b27c..c2ede99 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -145,8 +145,6 @@ int qemu_init_main_loop(void)
 
 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;
 
 /* Load rfds/wfds/xfds into gpollfds.  Will be removed a few commits later. */
@@ -206,65 +204,39 @@ static void gpollfds_to_select(int ret)
 }
 
 #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);
     }
 }
@@ -273,7 +245,7 @@ static int os_host_main_loop_wait(uint32_t timeout)
 {
     int ret;
 
-    glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
+    glib_pollfds_fill(&timeout);
 
     if (timeout > 0) {
         qemu_mutex_unlock_iothread();
@@ -292,7 +264,7 @@ static int os_host_main_loop_wait(uint32_t timeout)
         qemu_mutex_lock_iothread();
     }
 
-    glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
+    glib_pollfds_poll();
     return ret;
 }
 #else
@@ -438,8 +410,9 @@ static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds,
 static int os_host_main_loop_wait(uint32_t timeout)
 {
     GMainContext *context = g_main_context_default();
+    GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
     int select_ret = 0;
-    int g_poll_ret, ret, i;
+    int g_poll_ret, ret, i, n_poll_fds;
     PollingEntry *pe;
     WaitObjects *w = &wait_objects;
     gint poll_timeout;
commit cbff4b342b000a7642125dbdabf61113e05eee44
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:25 2013 +0100

    main-loop: switch to g_poll() on POSIX hosts
    
    Use g_poll(3) instead of select(2).  Well, this is kind of a cheat.
    It's true that we're now using g_poll(3) on POSIX hosts but the *_fill()
    and *_poll() functions are still using rfds/wfds/xfds.
    
    We've set the scene to start converting *_fill() and *_poll() functions
    step-by-step until no more rfds/wfds/xfds users remain.  Then we'll drop
    the temporary gpollfds_from_select() and gpollfds_to_select() functions
    and be left with native g_poll(2).
    
    On Windows things are a little crazy: convert from rfds/wfds/xfds to
    GPollFDs, back to rfds/wfds/xfds, call select(2), rfds/wfds/xfds back to
    GPollFDs, and finally back to rfds/wfds/xfds again.  This is only
    temporary and keeps the Windows build working through the following
    patches.  We'll drop this excessive conversion later and be left with a
    single GPollFDs -> select(2) -> GPollFDs sequence that allows Windows to
    use select(2) while the rest of QEMU only knows about GPollFD.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-3-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/main-loop.c b/main-loop.c
index d0d8fe4..489b27c 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -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);
@@ -146,6 +149,62 @@ static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
 static int n_poll_fds;
 static int max_priority;
 
+/* Load rfds/wfds/xfds into gpollfds.  Will be removed a few commits later. */
+static void gpollfds_from_select(void)
+{
+    int fd;
+    for (fd = 0; fd <= nfds; fd++) {
+        int events = 0;
+        if (FD_ISSET(fd, &rfds)) {
+            events |= G_IO_IN | G_IO_HUP | G_IO_ERR;
+        }
+        if (FD_ISSET(fd, &wfds)) {
+            events |= G_IO_OUT | G_IO_ERR;
+        }
+        if (FD_ISSET(fd, &xfds)) {
+            events |= G_IO_PRI;
+        }
+        if (events) {
+            GPollFD pfd = {
+                .fd = fd,
+                .events = events,
+            };
+            g_array_append_val(gpollfds, pfd);
+        }
+    }
+}
+
+/* Store gpollfds revents into rfds/wfds/xfds.  Will be removed a few commits
+ * later.
+ */
+static void gpollfds_to_select(int ret)
+{
+    int i;
+
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+
+    if (ret <= 0) {
+        return;
+    }
+
+    for (i = 0; i < gpollfds->len; i++) {
+        int fd = g_array_index(gpollfds, GPollFD, i).fd;
+        int revents = g_array_index(gpollfds, GPollFD, i).revents;
+
+        if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
+            FD_SET(fd, &rfds);
+        }
+        if (revents & (G_IO_OUT | G_IO_ERR)) {
+            FD_SET(fd, &wfds);
+        }
+        if (revents & G_IO_PRI) {
+            FD_SET(fd, &xfds);
+        }
+    }
+}
+
 #ifndef _WIN32
 static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
                              fd_set *xfds, uint32_t *cur_timeout)
@@ -212,22 +271,22 @@ static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
 
 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;
-    }
-
     if (timeout > 0) {
         qemu_mutex_unlock_iothread();
     }
 
-    ret = select(nfds + 1, &rfds, &wfds, &xfds, tvarg);
+    /* We'll eventually drop fd_set completely.  But for now we still have
+     * *_fill() and *_poll() functions that use rfds/wfds/xfds.
+     */
+    gpollfds_from_select();
+
+    ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout);
+
+    gpollfds_to_select(ret);
 
     if (timeout > 0) {
         qemu_mutex_lock_iothread();
@@ -327,6 +386,55 @@ 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();
@@ -382,12 +490,24 @@ static int os_host_main_loop_wait(uint32_t timeout)
      * improve socket latency.
      */
 
+    /* This back-and-forth between GPollFDs and select(2) is temporary.  We'll
+     * drop it in a couple of patches, I promise :).
+     */
+    gpollfds_from_select();
+    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);
+        }
     }
+    gpollfds_to_select(select_ret);
 
     return select_ret || g_poll_ret;
 }
@@ -403,6 +523,7 @@ 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);
commit 134a03e0b3d34b01b68107104c525c3bff1211d4
Author: Stefan Hajnoczi <stefanha at redhat.com>
Date:   Wed Feb 20 11:28:24 2013 +0100

    main-loop: fix select_ret uninitialized variable warning
    
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
    Reviewed-by: Laszlo Ersek <lersek at redhat.com>
    Message-id: 1361356113-11049-2-git-send-email-stefanha at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/main-loop.c b/main-loop.c
index 6f52ac3..d0d8fe4 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -330,7 +330,8 @@ void qemu_fd_register(int fd)
 static int os_host_main_loop_wait(uint32_t timeout)
 {
     GMainContext *context = g_main_context_default();
-    int select_ret, g_poll_ret, ret, i;
+    int select_ret = 0;
+    int g_poll_ret, ret, i;
     PollingEntry *pe;
     WaitObjects *w = &wait_objects;
     gint poll_timeout;
commit 70aa41b56ce3f34fceac44e828ba2d8cc19523ee
Merge: 259dc0c 89a453d
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Feb 21 09:39:17 2013 -0600

    Merge remote-tracking branch 'kraxel/usb.78' into staging
    
    # By Gerd Hoffmann
    # Via Gerd Hoffmann
    * kraxel/usb.78:
      uas-uas: usb3 streams
      usb-xhci: usb3 streams
      usb-core: usb3 streams
      usb: fix endpoint descriptor ordering
      usb-redir: simplify packet copy
      usb: make usb_packet_copy operate on combined packets
      usb: add usb_ep_set_halted
      usb-host: remove usb_host_device_close
      usb-host: move legacy cmd line bits
      usb-storage: use scsi_req_enqueue return value
      allow disabling usb smartcard support
      make usb devices configurable
      fix scripts/make_device_config.sh
      usb: Makefile cleanup

commit 259dc0c1ce8eef14e5e0c349bc68ba05c9d5d82f
Merge: cc2832a 159c983
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Feb 21 09:38:27 2013 -0600

    Merge remote-tracking branch 'stefanha/trivial-patches' into staging
    
    # By Alin Tomescu (1) and others
    # Via Stefan Hajnoczi
    * stefanha/trivial-patches:
      .gitignore: Ignore optionrom/*.asm
      ppc: fix bamboo >256MB RAM initialization in hw/ppc4xx_devs.c
      Add some missing qtest binaries to .gitignore
      xilinx_axienet.c: Assert no error when making link
      Remove forward declaration of non-existant variable

commit 159c9836d057d8990e71399e8a431b2b911e2885
Author: Cole Robinson <crobinso at redhat.com>
Date:   Tue Feb 19 17:41:28 2013 -0500

    .gitignore: Ignore optionrom/*.asm
    
    Signed-off-by: Cole Robinson <crobinso at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>

diff --git a/.gitignore b/.gitignore
index 53fe9c3..27ad002 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
commit 11e5d738a4c68cd20e90477fa8b7ee873bf3e2c0
Author: Alin Tomescu <tomescu.alin at gmail.com>
Date:   Wed Feb 20 21:36:09 2013 -0500

    ppc: fix bamboo >256MB RAM initialization in hw/ppc4xx_devs.c
    
    I was trying to launch a PowerPC "bamboo" machine with more than 256MB of RAM
    with qemu-system-ppc -M bamboo -kernel $kernel -initrd $ramdisk -m 512, but QEMU
    would just hang. However, when I used -m 256, the machine would boot.
    
    I looked through the code in hw/ and it seems there is an error when the
    RAM memory is setup (if my understanding is correct).
    
    After patching it, the machine launched and booted successfully with 512MB of
    RAM.
    
    Signed-off-by: Alin Tomescu <tomescu.alin at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>

diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
index 5e491bc..b6bb0e1 100644
--- a/hw/ppc4xx_devs.c
+++ b/hw/ppc4xx_devs.c
@@ -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;
             }
commit 499a6165bef56ce3f5297fa7b1abaab32858a34f
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Thu Feb 21 13:34:40 2013 +1100

    Add some missing qtest binaries to .gitignore
    
    These binaries are generated during make check on at least some
    configurations, so att them to .gitignore.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>

diff --git a/tests/.gitignore b/tests/.gitignore
index 38c94ef..fb05c2a 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -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
commit b15aaca4303fe009870842dd922a0128b332a2fd
Author: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
Date:   Mon Feb 11 17:16:05 2013 +1000

    xilinx_axienet.c: Assert no error when making link
    
    This gives an awful silent failure when it doesn't work. Assert against link
    creation failure.
    
    Signed-off-by: Peter Crosthwaite <peter.crosthwaite at xilinx.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>

diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index 34e344c..e5d9251 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -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[] = {
commit 87f1361c193c77dad428a7aa9bdce7ae2b76871f
Author: Hervé Poussineau <hpoussin at reactos.org>
Date:   Sun Feb 10 23:11:05 2013 +0100

    Remove forward declaration of non-existant variable
    
    This variable has been removed 5 years ago in 970ac5a3082428dca91171f270dcd95d6f4b2636.
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>

diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 1d9599e..ae49088 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -94,7 +94,6 @@ typedef enum DisplayType
 } DisplayType;
 
 extern int autostart;
-extern int bios_size;
 
 typedef enum {
     VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
commit 89a453d4a5c195e6d0a3c3d4fcaacb447447115f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 25 17:38:59 2013 +0100

    uas-uas: usb3 streams
    
    Add usb3 streams support to the uas (usb attached scsi) emulation.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index 316c388..1ac5117 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -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, 0);
+        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;
commit 024426acc0a2707a85faa1983499647649d6d2db
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jan 25 17:23:44 2013 +0100

    usb-xhci: usb3 streams
    
    Add streams support to the xhci emulation.  No secondary streams yet,
    only linear stream arays are supported for now.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index b8247f3..5796102 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -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 @ %lx: %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,7 +1672,7 @@ 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, 0,
+    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",
@@ -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) {
@@ -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)
@@ -3045,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 = {
diff --git a/trace-events b/trace-events
index 1011f27..a27ae43 100644
--- a/trace-events
+++ b/trace-events
@@ -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"
commit 8550a02d1239415342959f6a32d178bc05c557cc
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 29 12:44:35 2013 +0100

    usb-core: usb3 streams
    
    This patch adds support for usb3 streams to the usb subsystem core.
    This is just adding a streams field / parameter in a number of places.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.h b/hw/usb.h
index 0d09e02..382496c 100644
--- 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,8 +384,9 @@ 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);
@@ -430,7 +432,7 @@ 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);
 
@@ -489,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);
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 674fef8..15a150a 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -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;
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index adbf9d4..0f8aa48 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -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);
 }
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 29b6481..9701048 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -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)
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 79f2f46..504c98c 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -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:
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index a01a5e7..c08718b 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -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);
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 979a473..caebc1c 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -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(
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index d904d1a..316c388 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -276,7 +276,7 @@ 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, 0);
     }
 }
 
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index ab9fa2e..3be5cde 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -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)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 7040659..5176251 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -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);
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
index 64e9e83..7968e17 100644
--- a/hw/usb/hcd-musb.c
+++ b/hw/usb/hcd-musb.c
@@ -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;
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index dd9967b..51241cd 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -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);
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 60645aa..f8c4286 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -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);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 5fb0c48..b8247f3 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1518,8 +1518,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, 0,
+                     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);
@@ -1977,7 +1977,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,
@@ -3033,7 +3033,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;
commit 2e5df36df8d0c3ffe59de254ef016508b27562bb
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Jan 28 15:52:57 2013 +0100

    usb: fix endpoint descriptor ordering
    
    Fix the ordering of the endpoint descriptors for superspeed endpoints:
    The superspeed companion must come first, possible additional
    descriptors for the endpoint after that.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index b7c3233..b389381 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -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;
 }
 
commit 6ef3ccd18f881a7bece556ff0fe1b0bf70ac2262
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 24 15:40:37 2013 +0100

    usb-redir: simplify packet copy
    
    usb_packet_copy can handle combined packets now,
    so it isn't needed to special-case them any more.
    
    Also use the new usb_packet_size() function.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 8c0ead0..7078403 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -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) {
commit 6a98d1c0f9e4f6a95d6ecd730ae6fdc70d15c73f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 24 15:38:23 2013 +0100

    usb: make usb_packet_copy operate on combined packets
    
    Likewise usb_packet_skip.
    Also usb_packet_size.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.h b/hw/usb.h
index af86fbd..0d09e02 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -390,6 +390,7 @@ 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)
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 5517797..674fef8 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -570,15 +570,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 +591,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));
commit e382d966d06d2989fc28eec8cfdcc2fd99ebfbb7
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Dec 12 13:40:59 2012 +0100

    usb: add usb_ep_set_halted
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.h b/hw/usb.h
index 90024a4..af86fbd 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -417,6 +417,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);
 
diff --git a/hw/usb/core.c b/hw/usb/core.c
index d057aab..5517797 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -755,6 +755,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)
 {
commit 1a3973b33d36583d7194798f789a37759a13e269
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Nov 30 13:02:47 2012 +0100

    usb-host: remove usb_host_device_close
    
    Nobody implements that anyway.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.h b/hw/usb.h
index bc42639..90024a4 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -434,7 +434,6 @@ 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 */
diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c
index 07f0e01..39f2281 100644
--- a/hw/usb/host-bsd.c
+++ b/hw/usb/host-bsd.c
@@ -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-linux.c b/hw/usb/host-linux.c
index c18a6c8..b67aeba 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -1540,30 +1540,6 @@ static void usb_host_register_types(void)
 
 type_init(usb_host_register_types)
 
-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
  *
diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c
index 8affba7..28d8032 100644
--- a/hw/usb/host-stub.c
+++ b/hw/usb/host-stub.c
@@ -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/vl.c b/vl.c
index c5b0eea..955d2ff 100644
--- 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;
commit 4075975d832c55abdfc951726e54f9a28a2421c8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jan 23 14:15:38 2013 +0100

    usb-host: move legacy cmd line bits
    
    The code handling the "-usbdevice host:..." legacy command line
    syntax is moved to the new hw/usb/host-legacy.c file.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/configure b/configure
index bf5970f..42cb314 100755
--- a/configure
+++ b/configure
@@ -3723,7 +3723,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
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index c1e40d7..e63e287 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -27,4 +27,4 @@ common-obj-$(CONFIG_USB_SMARTCARD)    += dev-smartcard-reader.o
 common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
 
 # usb pass-through
-common-obj-y += host-$(HOST_USB).o
+common-obj-y += $(patsubst %,host-%.o,$(HOST_USB))
diff --git a/hw/usb/host-legacy.c b/hw/usb/host-legacy.c
new file mode 100644
index 0000000..3a5f705
--- /dev/null
+++ b/hw/usb/host-legacy.c
@@ -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 at 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)
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index a2cff8a..c18a6c8 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -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,51 +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
@@ -1840,56 +1791,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 */
 
diff --git a/hw/usb/host.h b/hw/usb/host.h
new file mode 100644
index 0000000..048ff3b
--- /dev/null
+++ b/hw/usb/host.h
@@ -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 at 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 */
commit 9db7c41419e89adee5650a5868ac91e83614abf5
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jan 22 14:17:05 2013 +0100

    usb-storage: use scsi_req_enqueue return value
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index b89d00f..d3f01aa 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -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;
commit 07d17e772095ee2b1171498536e5671a97920149
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Feb 1 11:08:24 2013 +0100

    allow disabling usb smartcard support
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 447e32a..a1f3a80 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -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
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 00998b5..c1e40d7 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -20,7 +20,6 @@ common-obj-$(CONFIG_USB_NETWORK)      += dev-network.o
 
 # FIXME: make configurable too
 CONFIG_USB_BLUETOOTH := y
-CONFIG_USB_SMARTCARD := y
 common-obj-$(CONFIG_USB_BLUETOOTH)    += dev-bluetooth.o
 common-obj-$(CONFIG_USB_SMARTCARD)    += dev-smartcard-reader.o
 
commit 6c83f81542e4fda1777a74e4647a69086e44357c
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Feb 1 10:49:43 2013 +0100

    make usb devices configurable
    
    Leave the core usb devices (usb hub, tablet, mouse, keyboard)
    enabled unconditionally.  Make the other ones configurable.
    
    Exceptions:
      - bluetooth: not qdevified yet, has a vl.c dependency because
        of that, thus disabling isn't as easy as not linking the
        object file.
      - smardcard: ccid-card-emulated depends on that one *and*
        CONFIG_SMARTCARD_NSS.  So it isn't a one-liner and comes
        as separate patch because of that.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
index 501dd41..2dbee94 100644
--- a/default-configs/alpha-softmmu.mak
+++ b/default-configs/alpha-softmmu.mak
@@ -1,6 +1,7 @@
 # Default configuration for alpha-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_SERIAL=y
 CONFIG_I8254=y
 CONFIG_PCKBD=y
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 2f1a5c9..b40f7b0 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -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
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 2c78175..1b23025 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -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
diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
index 3e2ec37..778ea82 100644
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for m68k-softmmu
 
 include pci.mak
+include usb.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_PTIMER=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index a271b1c..4f04a33 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -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
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index 0510bb6..a5b6c3c 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -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
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index ed3bed3..a0e6de8 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -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
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index fa3a2ca..753dd76 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -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
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 1f4a1cf..f9f8a81 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -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
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index 5ff406c..dc44294 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -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
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index aaa9cdc..1c6bcf9 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -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
diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak
index 5c69acc..e08b2ee 100644
--- a/default-configs/sh4-softmmu.mak
+++ b/default-configs/sh4-softmmu.mak
@@ -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
diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak
index 7cdc122..3a84535 100644
--- a/default-configs/sh4eb-softmmu.mak
+++ b/default-configs/sh4eb-softmmu.mak
@@ -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
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index 03e8b42..2145b6b 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -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
index 0000000..1bf9075
--- /dev/null
+++ b/default-configs/usb.mak
@@ -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
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 233a856..3392f5a 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -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
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index bfe5e5f..00998b5 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -11,14 +11,18 @@ common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
 # emulated usb devices
 common-obj-y += dev-hub.o
 common-obj-y += dev-hid.o
-common-obj-y += dev-wacom.o
-common-obj-y += dev-storage.o
-common-obj-y += dev-uas.o
-common-obj-y += dev-smartcard-reader.o
-common-obj-y += dev-audio.o
-common-obj-y += dev-serial.o
-common-obj-y += dev-network.o
-common-obj-y += dev-bluetooth.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
+CONFIG_USB_SMARTCARD := 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
commit f4ece4046344230a3a030ef1e494599eaf0a5935
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Feb 1 10:48:34 2013 +0100

    fix scripts/make_device_config.sh
    
    Make it handle multiple include statements in a file:
    
     (1) The printf needs a space so the include files will be separated.
     (2) Also $f can contain multiple failes, so redirection will not work
         and we have to use cat to process all files.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh
index 0778fe2..81fe942 100644
--- a/scripts/make_device_config.sh
+++ b/scripts/make_device_config.sh
@@ -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
commit 62162fff598f941c198b16b4e8814015ec5a0bef
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Feb 1 09:53:17 2013 +0100

    usb: Makefile cleanup
    
    Group files, sprinkle in some comments.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index d1bbbc0..bfe5e5f 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -1,14 +1,27 @@
+# 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-y += dev-wacom.o
+common-obj-y += dev-storage.o
+common-obj-y += dev-uas.o
+common-obj-y += dev-smartcard-reader.o
+common-obj-y += dev-audio.o
+common-obj-y += dev-serial.o
+common-obj-y += dev-network.o
+common-obj-y += dev-bluetooth.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 += host-$(HOST_USB).o
commit cc2832a51c8ce43349967ab1b6c7aafd510e55b2
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 11 17:46:57 2013 +0100

    rtc-test: add testcases for alarms in 12hour mode
    
    Trying (unsuccessfully) to break the device model as mentioned in
    https://bugs.launchpad.net/qemu/+bug/1090558.
    
    At least if someone tries to fix that, it won't break what works...
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Message-id: 1357922817-17584-3-git-send-email-pbonzini at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index c55215c..c5fd042 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -299,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)
 {
@@ -364,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);
commit f9b3ed401c5cf3df9689f74c15a7b4d91566a3ac
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Jan 11 17:46:56 2013 +0100

    rtc-test: always set register B in its entirety
    
    Eliminate dependencies between one test and the others.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Message-id: 1357922817-17584-2-git-send-email-pbonzini at redhat.com
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index 203c0fc..c55215c 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -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++) {
@@ -336,7 +318,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);


More information about the Spice-commits mailing list