summary refs log tree commit diff stats
path: root/hw/usb/redirect.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-04-08 10:36:40 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2013-04-08 10:36:40 -0500
commit2a7a239ff09aa87cc3682a976c7a57d9ea1321d7 (patch)
treee0043f932da9fac985bcd3c9ba03e700f82f04ad /hw/usb/redirect.c
parent9196dd411d580c27f85daa209ff9a501d719ebc0 (diff)
parentaa1c9e971e80d25b92908dce3dec7c38b49480ea (diff)
downloadfocaccia-qemu-2a7a239ff09aa87cc3682a976c7a57d9ea1321d7.tar.gz
focaccia-qemu-2a7a239ff09aa87cc3682a976c7a57d9ea1321d7.zip
Merge remote-tracking branch 'kraxel/usb.79' into staging
# By Gerd Hoffmann (7) and Hans de Goede (3)
# Via Gerd Hoffmann
* kraxel/usb.79:
  usb-tablet: Don't claim wakeup capability for USB-2 version
  usb: update docs for bus name change
  usb-hub: report status changes only once
  usb-hub: limit chain length
  xhci: zap unused name field
  xhci: remove unimplemented printfs
  xhci: remove leftover debug printf
  xhci: fix numintrs sanity checks
  usb-redir: Add flow control support
  usb-redir: Fix crash on migration with no client connected
Diffstat (limited to 'hw/usb/redirect.c')
-rw-r--r--hw/usb/redirect.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index d02a7b94c4..0ddb0818d8 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -104,6 +104,8 @@ struct USBRedirDevice {
     /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
     const uint8_t *read_buf;
     int read_buf_size;
+    /* Active chardev-watch-tag */
+    guint watch;
     /* For async handling of close */
     QEMUBH *chardev_close_bh;
     /* To delay the usb attach in case of quick chardev close + open */
@@ -254,9 +256,21 @@ static int usbredir_read(void *priv, uint8_t *data, int count)
     return count;
 }
 
+static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
+                                         void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    dev->watch = 0;
+    usbredirparser_do_write(dev->parser);
+
+    return FALSE;
+}
+
 static int usbredir_write(void *priv, uint8_t *data, int count)
 {
     USBRedirDevice *dev = priv;
+    int r;
 
     if (!dev->cs->be_open) {
         return 0;
@@ -267,7 +281,17 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
         return 0;
     }
 
-    return qemu_chr_fe_write(dev->cs, data, count);
+    r = qemu_chr_fe_write(dev->cs, data, count);
+    if (r < count) {
+        if (!dev->watch) {
+            dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT,
+                                               usbredir_write_unblocked, dev);
+        }
+        if (r < 0) {
+            r = 0;
+        }
+    }
+    return r;
 }
 
 /*
@@ -1085,6 +1109,10 @@ static void usbredir_chardev_close_bh(void *opaque)
         usbredirparser_destroy(dev->parser);
         dev->parser = NULL;
     }
+    if (dev->watch) {
+        g_source_remove(dev->watch);
+        dev->watch = 0;
+    }
 }
 
 static void usbredir_create_parser(USBRedirDevice *dev)
@@ -1317,6 +1345,9 @@ static void usbredir_handle_destroy(USBDevice *udev)
     if (dev->parser) {
         usbredirparser_destroy(dev->parser);
     }
+    if (dev->watch) {
+        g_source_remove(dev->watch);
+    }
 
     free(dev->filter_rules);
 }
@@ -1973,6 +2004,10 @@ static int usbredir_post_load(void *priv, int version_id)
 {
     USBRedirDevice *dev = priv;
 
+    if (dev->parser == NULL) {
+        return 0;
+    }
+
     switch (dev->device_info.speed) {
     case usb_redir_speed_low:
         dev->dev.speed = USB_SPEED_LOW;