[qemu] Add USB redirect patches
Justin M. Forbes
jforbes at fedoraproject.org
Fri Jan 13 19:46:36 UTC 2012
commit d4cdad5451e941e780fb81709edcaa102f273dfd
Author: Justin M. Forbes <jforbes at redhat.com>
Date: Fri Jan 13 13:46:23 2012 -0600
Add USB redirect patches
...lear-iso-irq-error-when-stopping-the-stre.patch | 56 ++
...ynamically-adjust-iso-buffering-size-base.patch | 102 +++
...re-fill-our-isoc-input-buffer-before-send.patch | 74 ++
...ry-to-keep-our-buffer-size-near-the-targe.patch | 87 ++
...usb-redir-Improve-some-debugging-messages.patch | 58 ++
...out-tcp-socket-close-code-in-a-separate-f.patch | 57 ++
...QemuChrHandlers-struct-to-initialise-char.patch | 871 ++++++++++++++++++++
...Add-enable-disable_write_fd_handler-funct.patch | 77 ++
...-framework-for-a-write-unblocked-callback.patch | 61 ++
...-send_all-to-handle-nonblocking-chardev-w.patch | 188 +++++
...the-unix-tcp-backend-to-handle-nonblockin.patch | 81 ++
...har-Throttle-when-host-connection-is-down.patch | 56 ++
...ole-Enable-port-throttling-when-chardev-i.patch | 49 ++
0114-spice-qemu-char.c-add-throttling.patch | 133 +++
...ce-qemu-char.c-remove-intermediate-buffer.patch | 71 ++
0116-usb-redir-Add-flow-control-support.patch | 65 ++
...serial-bus-replay-guest_open-on-migration.patch | 50 ++
...e-write-callback-if-throttled-chardev-is-.patch | 36 +
qemu.spec | 46 +-
19 files changed, 2216 insertions(+), 2 deletions(-)
---
diff --git a/0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch b/0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch
new file mode 100644
index 0000000..324f9e4
--- /dev/null
+++ b/0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch
@@ -0,0 +1,56 @@
+From 01936dfd5b9fa8117fc1d63ce92198dd28422773 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Mon, 19 Dec 2011 14:59:45 +0100
+Subject: [PATCH 101/118] usb-redir: Clear iso / irq error when stopping the
+ stream
+
+And ignore status messages from the client which arrive after stream
+stop (the stream stop send to the client and an error status reported by
+the client my cross each other due to network latency).
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c | 6 ++++--
+ 1 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index fb91c92..7678f1a 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -410,6 +410,7 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
+ DPRINTF("iso stream stopped ep %02X\n", ep);
+ dev->endpoint[EP2I(ep)].iso_started = 0;
+ }
++ dev->endpoint[EP2I(ep)].iso_error = 0;
+ usbredir_free_bufpq(dev, ep);
+ }
+
+@@ -522,6 +523,7 @@ static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
+ DPRINTF("interrupt recv stopped ep %02X\n", ep);
+ dev->endpoint[EP2I(ep)].interrupt_started = 0;
+ }
++ dev->endpoint[EP2I(ep)].interrupt_error = 0;
+ usbredir_free_bufpq(dev, ep);
+ }
+
+@@ -1029,7 +1031,7 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id,
+ DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status,
+ ep, id);
+
+- if (!dev->dev.attached) {
++ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) {
+ return;
+ }
+
+@@ -1050,7 +1052,7 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
+ DPRINTF("interrupt recv status %d ep %02X id %u\n",
+ interrupt_receiving_status->status, ep, id);
+
+- if (!dev->dev.attached) {
++ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) {
+ return;
+ }
+
+--
+1.7.7.5
+
diff --git a/0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch b/0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch
new file mode 100644
index 0000000..297fa9b
--- /dev/null
+++ b/0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch
@@ -0,0 +1,102 @@
+From cc5740ae8aa68dbbdc690f694b0e55d70f9c49ee Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Mon, 19 Dec 2011 13:42:40 +0100
+Subject: [PATCH 102/118] usb-redir: Dynamically adjust iso buffering size
+ based on ep interval
+
+Note the bufpq_target_size id stored in the endpoint info struct,
+even though it only used once. This is done because it will be
+referenced from other code in a follow up patch.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 files changed, 47 insertions(+), 5 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index 7678f1a..ab2c8fa 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -61,6 +61,7 @@ struct endp_data {
+ uint8_t interrupt_started;
+ uint8_t interrupt_error;
+ QTAILQ_HEAD(, buf_packet) bufpq;
++ int bufpq_target_size;
+ };
+
+ struct USBRedirDevice {
+@@ -332,15 +333,41 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+ uint8_t ep)
+ {
+ int status, len;
+-
+ if (!dev->endpoint[EP2I(ep)].iso_started &&
+ !dev->endpoint[EP2I(ep)].iso_error) {
+ struct usb_redir_start_iso_stream_header start_iso = {
+ .endpoint = ep,
+- /* TODO maybe do something with these depending on ep interval? */
+- .pkts_per_urb = 32,
+- .no_urbs = 3,
+ };
++ int pkts_per_sec;
++
++ if (dev->dev.speed == USB_SPEED_HIGH)
++ pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval;
++ else
++ pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval;
++ /* Testing has shown that we need circa 60 ms buffer */
++ dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000;
++
++ /* Aim for approx 100 interrupts / second on the client to
++ balance latency and interrupt load */
++ start_iso.pkts_per_urb = pkts_per_sec / 100;
++ if (start_iso.pkts_per_urb < 1) {
++ start_iso.pkts_per_urb = 1;
++ } else if (start_iso.pkts_per_urb > 32) {
++ start_iso.pkts_per_urb = 32;
++ }
++
++ start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size +
++ start_iso.pkts_per_urb - 1) /
++ start_iso.pkts_per_urb;
++ /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest
++ as overflow buffer. Also see the usbredir protocol documentation */
++ if (!(ep & USB_DIR_IN)) {
++ start_iso.no_urbs *= 2;
++ }
++ if (start_iso.no_urbs > 16) {
++ start_iso.no_urbs = 16;
++ }
++
+ /* No id, we look at the ep when receiving a status back */
+ usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
+ usbredirparser_do_write(dev->parser);
+@@ -961,9 +988,24 @@ static void usbredir_ep_info(void *priv,
+ dev->endpoint[i].type = ep_info->type[i];
+ dev->endpoint[i].interval = ep_info->interval[i];
+ dev->endpoint[i].interface = ep_info->interface[i];
+- if (dev->endpoint[i].type != usb_redir_type_invalid) {
++ switch (dev->endpoint[i].type) {
++ case usb_redir_type_invalid:
++ break;
++ case usb_redir_type_iso:
++ case usb_redir_type_interrupt:
++ if (dev->endpoint[i].interval == 0) {
++ ERROR("Received 0 interval for isoc or irq endpoint\n");
++ usbredir_device_disconnect(dev);
++ }
++ /* Fall through */
++ case usb_redir_type_control:
++ case usb_redir_type_bulk:
+ DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
+ dev->endpoint[i].type, dev->endpoint[i].interface);
++ break;
++ default:
++ ERROR("Received invalid endpoint type\n");
++ usbredir_device_disconnect(dev);
+ }
+ }
+ }
+--
+1.7.7.5
+
diff --git a/0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch b/0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch
new file mode 100644
index 0000000..56daa98
--- /dev/null
+++ b/0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch
@@ -0,0 +1,74 @@
+From 577aff1f1df0a41fd5e21f5ff2b470c36565211b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Mon, 19 Dec 2011 14:55:15 +0100
+Subject: [PATCH 103/118] usb-redir: Pre-fill our isoc input buffer before
+ sending pkts to the host
+
+This is something which should have been done from the first version of
+usb-redir, but wasn't.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c | 16 ++++++++++++++++
+ 1 files changed, 16 insertions(+), 0 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index ab2c8fa..17ea7a7 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -60,7 +60,9 @@ struct endp_data {
+ uint8_t iso_error; /* For reporting iso errors to the HC */
+ uint8_t interrupt_started;
+ uint8_t interrupt_error;
++ uint8_t bufpq_prefilled;
+ QTAILQ_HEAD(, buf_packet) bufpq;
++ int bufpq_size;
+ int bufpq_target_size;
+ };
+
+@@ -296,6 +298,7 @@ static struct buf_packet *bufp_alloc(USBRedirDevice *dev,
+ bufp->len = len;
+ bufp->status = status;
+ QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
++ dev->endpoint[EP2I(ep)].bufpq_size++;
+ return bufp;
+ }
+
+@@ -303,6 +306,7 @@ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
+ uint8_t ep)
+ {
+ QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
++ dev->endpoint[EP2I(ep)].bufpq_size--;
+ free(bufp->data);
+ g_free(bufp);
+ }
+@@ -373,14 +377,26 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+ usbredirparser_do_write(dev->parser);
+ DPRINTF("iso stream started ep %02X\n", ep);
+ dev->endpoint[EP2I(ep)].iso_started = 1;
++ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
+ }
+
+ if (ep & USB_DIR_IN) {
+ struct buf_packet *isop;
+
++ if (dev->endpoint[EP2I(ep)].iso_started &&
++ !dev->endpoint[EP2I(ep)].bufpq_prefilled) {
++ if (dev->endpoint[EP2I(ep)].bufpq_size <
++ dev->endpoint[EP2I(ep)].bufpq_target_size) {
++ return usbredir_handle_status(dev, 0, 0);
++ }
++ dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
++ }
++
+ isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+ if (isop == NULL) {
+ DPRINTF2("iso-token-in ep %02X, no isop\n", ep);
++ /* Re-fill the buffer */
++ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
+ /* Check iso_error for stream errors, otherwise its an underrun */
+ status = dev->endpoint[EP2I(ep)].iso_error;
+ dev->endpoint[EP2I(ep)].iso_error = 0;
+--
+1.7.7.5
+
diff --git a/0104-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch b/0104-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch
new file mode 100644
index 0000000..0f826d3
--- /dev/null
+++ b/0104-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch
@@ -0,0 +1,87 @@
+From b8e632d175063770655e75507de85ae873fa6c2d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Tue, 20 Dec 2011 16:54:25 +0100
+Subject: [PATCH 104/118] usb-redir: Try to keep our buffer size near the
+ target size
+
+Before this patch we would allow the (iso) buffer to grow unlimited
+(and it would under certain circumstances) leading to way too high
+latencies for iso data streams.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c | 30 +++++++++++++++++++++++++++---
+ 1 files changed, 27 insertions(+), 3 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index 17ea7a7..88d941a 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -61,6 +61,7 @@ struct endp_data {
+ uint8_t interrupt_started;
+ uint8_t interrupt_error;
+ uint8_t bufpq_prefilled;
++ uint8_t bufpq_dropping_packets;
+ QTAILQ_HEAD(, buf_packet) bufpq;
+ int bufpq_size;
+ int bufpq_target_size;
+@@ -290,16 +291,34 @@ static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
+ }
+ }
+
+-static struct buf_packet *bufp_alloc(USBRedirDevice *dev,
++static void bufp_alloc(USBRedirDevice *dev,
+ uint8_t *data, int len, int status, uint8_t ep)
+ {
+- struct buf_packet *bufp = g_malloc(sizeof(struct buf_packet));
++ struct buf_packet *bufp;
++
++ if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets &&
++ dev->endpoint[EP2I(ep)].bufpq_size >
++ 2 * dev->endpoint[EP2I(ep)].bufpq_target_size) {
++ DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep);
++ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1;
++ }
++ /* Since we're interupting the stream anyways, drop enough packets to get
++ back to our target buffer size */
++ if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) {
++ if (dev->endpoint[EP2I(ep)].bufpq_size >
++ dev->endpoint[EP2I(ep)].bufpq_target_size) {
++ free(data);
++ return;
++ }
++ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
++ }
++
++ bufp = g_malloc(sizeof(struct buf_packet));
+ bufp->data = data;
+ bufp->len = len;
+ bufp->status = status;
+ QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+ dev->endpoint[EP2I(ep)].bufpq_size++;
+- return bufp;
+ }
+
+ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
+@@ -378,6 +397,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+ DPRINTF("iso stream started ep %02X\n", ep);
+ dev->endpoint[EP2I(ep)].iso_started = 1;
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
++ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
+ }
+
+ if (ep & USB_DIR_IN) {
+@@ -504,6 +524,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
+ usbredirparser_do_write(dev->parser);
+ DPRINTF("interrupt recv started ep %02X\n", ep);
+ dev->endpoint[EP2I(ep)].interrupt_started = 1;
++ /* We don't really want to drop interrupt packets ever, but
++ having some upper limit to how much we buffer is good. */
++ dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
++ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
+ }
+
+ intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+--
+1.7.7.5
+
diff --git a/0105-usb-redir-Improve-some-debugging-messages.patch b/0105-usb-redir-Improve-some-debugging-messages.patch
new file mode 100644
index 0000000..8c5bda6
--- /dev/null
+++ b/0105-usb-redir-Improve-some-debugging-messages.patch
@@ -0,0 +1,58 @@
+From ba411ef969f3dcd8e82929e5577c0e06a60a5707 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Tue, 20 Dec 2011 16:21:34 +0100
+Subject: [PATCH 105/118] usb-redir: Improve some debugging messages
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c | 13 ++++++++-----
+ 1 files changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index 88d941a..86bccf8 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -394,7 +394,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+ /* No id, we look at the ep when receiving a status back */
+ usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
+ usbredirparser_do_write(dev->parser);
+- DPRINTF("iso stream started ep %02X\n", ep);
++ DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n",
++ pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep);
+ dev->endpoint[EP2I(ep)].iso_started = 1;
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
+@@ -414,7 +415,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+
+ isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+ if (isop == NULL) {
+- DPRINTF2("iso-token-in ep %02X, no isop\n", ep);
++ DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n",
++ ep, dev->endpoint[EP2I(ep)].iso_error);
+ /* Re-fill the buffer */
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
+ /* Check iso_error for stream errors, otherwise its an underrun */
+@@ -422,8 +424,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+ dev->endpoint[EP2I(ep)].iso_error = 0;
+ return usbredir_handle_status(dev, status, 0);
+ }
+- DPRINTF2("iso-token-in ep %02X status %d len %d\n", ep, isop->status,
+- isop->len);
++ DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
++ isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
+
+ status = isop->status;
+ if (status != usb_redir_success) {
+@@ -433,7 +435,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+
+ len = isop->len;
+ if (len > p->iov.size) {
+- ERROR("received iso data is larger then packet ep %02X\n", ep);
++ ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
++ ep, len, (int)p->iov.size);
+ bufp_free(dev, isop, ep);
+ return USB_RET_NAK;
+ }
+--
+1.7.7.5
+
diff --git a/0106-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch b/0106-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch
new file mode 100644
index 0000000..bb37bd7
--- /dev/null
+++ b/0106-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch
@@ -0,0 +1,57 @@
+From 34736b9b6690054152ae2b9b37f75f7ed720590a Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Mon, 21 Mar 2011 21:57:47 +0100
+Subject: [PATCH 106/118] char: Split out tcp socket close code in a separate
+ function
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ qemu-char.c | 25 ++++++++++++++++---------
+ 1 files changed, 16 insertions(+), 9 deletions(-)
+
+diff --git a/qemu-char.c b/qemu-char.c
+index 27abcb9..a5ca611 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -2163,6 +2163,21 @@ typedef struct {
+
+ static void tcp_chr_accept(void *opaque);
+
++static void tcp_closed(void *opaque)
++{
++ CharDriverState *chr = opaque;
++ TCPCharDriver *s = chr->opaque;
++
++ s->connected = 0;
++ if (s->listen_fd >= 0) {
++ qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
++ }
++ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
++ closesocket(s->fd);
++ s->fd = -1;
++ qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
++}
++
+ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+ TCPCharDriver *s = chr->opaque;
+@@ -2313,15 +2328,7 @@ static void tcp_chr_read(void *opaque)
+ len = s->max_size;
+ size = tcp_chr_recv(chr, (void *)buf, len);
+ if (size == 0) {
+- /* connection closed */
+- s->connected = 0;
+- if (s->listen_fd >= 0) {
+- qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
+- }
+- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+- closesocket(s->fd);
+- s->fd = -1;
+- qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
++ tcp_closed(chr);
+ } else if (size > 0) {
+ if (s->do_telnetopt)
+ tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+--
+1.7.7.5
+
diff --git a/0107-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch b/0107-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch
new file mode 100644
index 0000000..48acb6a
--- /dev/null
+++ b/0107-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch
@@ -0,0 +1,871 @@
+From 61efa48e1973eaac16615c85198d9d74e36a3124 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Mon, 21 Mar 2011 20:31:45 +0100
+Subject: [PATCH 107/118] char: Add a QemuChrHandlers struct to initialise
+ chardev handlers
+
+Instead of passing each handler in the qemu_add_handlers() function,
+create a struct of handlers that can be passed to the function instead.
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ gdbstub.c | 9 +++++++--
+ hw/ccid-card-passthru.c | 11 +++++++----
+ hw/debugcon.c | 2 +-
+ hw/escc.c | 9 +++++++--
+ hw/etraxfs_ser.c | 13 +++++++++----
+ hw/grlib_apbuart.c | 12 +++++++-----
+ hw/ivshmem.c | 28 ++++++++++++++++++++++------
+ hw/lm32_juart.c | 8 +++++++-
+ hw/lm32_uart.c | 8 +++++++-
+ hw/mcf_uart.c | 9 +++++++--
+ hw/milkymist-uart.c | 8 +++++++-
+ hw/pl011.c | 9 +++++++--
+ hw/pxa2xx.c | 13 +++++++++----
+ hw/serial.c | 9 +++++++--
+ hw/sh_serial.c | 12 +++++++++---
+ hw/spapr_vty.c | 8 ++++++--
+ hw/strongarm.c | 12 +++++++-----
+ hw/syborg_serial.c | 9 +++++++--
+ hw/usb-serial.c | 9 +++++++--
+ hw/virtio-console.c | 11 ++++++++---
+ hw/xen_console.c | 16 +++++++++++-----
+ hw/xilinx_uartlite.c | 11 +++++++++--
+ monitor.c | 18 ++++++++++++++----
+ net/slirp.c | 8 ++++++--
+ qemu-char.c | 32 ++++++++++++++++++++++----------
+ qemu-char.h | 13 +++++++++----
+ usb-redir.c | 9 +++++++--
+ 27 files changed, 233 insertions(+), 83 deletions(-)
+
+diff --git a/gdbstub.c b/gdbstub.c
+index 640cf4e..b984e12 100644
+--- a/gdbstub.c
++++ b/gdbstub.c
+@@ -2860,6 +2860,12 @@ static void gdb_sigterm_handler(int signal)
+ }
+ #endif
+
++static const QemuChrHandlers gdb_handlers = {
++ .fd_can_read = gdb_chr_can_receive,
++ .fd_read = gdb_chr_receive,
++ .fd_event = gdb_chr_event,
++};
++
+ int gdbserver_start(const char *device)
+ {
+ GDBState *s;
+@@ -2889,8 +2895,7 @@ int gdbserver_start(const char *device)
+ if (!chr)
+ return -1;
+
+- qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
+- gdb_chr_event, NULL);
++ qemu_chr_add_handlers(chr, &gdb_handlers, NULL);
+ }
+
+ s = gdbserver_state;
+diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
+index 9f51c6c..c5bff01 100644
+--- a/hw/ccid-card-passthru.c
++++ b/hw/ccid-card-passthru.c
+@@ -274,6 +274,12 @@ static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
+ return card->atr;
+ }
+
++static const QemuChrHandlers passthru_handlers = {
++ .fd_can_read = ccid_card_vscard_can_read,
++ .fd_read = ccid_card_vscard_read,
++ .fd_event = ccid_card_vscard_event,
++};
++
+ static int passthru_initfn(CCIDCardState *base)
+ {
+ PassthruState *card = DO_UPCAST(PassthruState, base, base);
+@@ -282,10 +288,7 @@ static int passthru_initfn(CCIDCardState *base)
+ card->vscard_in_hdr = 0;
+ if (card->cs) {
+ DPRINTF(card, D_INFO, "initing chardev\n");
+- qemu_chr_add_handlers(card->cs,
+- ccid_card_vscard_can_read,
+- ccid_card_vscard_read,
+- ccid_card_vscard_event, card);
++ qemu_chr_add_handlers(card->cs, &passthru_handlers, card);
+ ccid_card_vscard_send_init(card);
+ } else {
+ error_report("missing chardev");
+diff --git a/hw/debugcon.c b/hw/debugcon.c
+index c9ee6d9..1d3c3ca 100644
+--- a/hw/debugcon.c
++++ b/hw/debugcon.c
+@@ -73,7 +73,7 @@ static void debugcon_init_core(DebugconState *s)
+ exit(1);
+ }
+
+- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
++ qemu_chr_add_handlers(s->chr, NULL, s);
+ }
+
+ static int debugcon_isa_initfn(ISADevice *dev)
+diff --git a/hw/escc.c b/hw/escc.c
+index 13c7e66..997377e 100644
+--- a/hw/escc.c
++++ b/hw/escc.c
+@@ -867,6 +867,12 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
+ sysbus_mmio_map(s, 0, base);
+ }
+
++static const QemuChrHandlers serial_handlers = {
++ .fd_can_read = serial_can_receive,
++ .fd_read = serial_receive1,
++ .fd_event = serial_event,
++};
++
+ static int escc_init1(SysBusDevice *dev)
+ {
+ SerialState *s = FROM_SYSBUS(SerialState, dev);
+@@ -879,8 +885,7 @@ static int escc_init1(SysBusDevice *dev)
+ s->chn[i].chn = 1 - i;
+ s->chn[i].clock = s->frequency / 2;
+ if (s->chn[i].chr) {
+- qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
+- serial_receive1, serial_event, &s->chn[i]);
++ qemu_chr_add_handlers(s->chn[i].chr, &serial_handlers, &s->chn[i]);
+ }
+ }
+ s->chn[0].otherchn = &s->chn[1];
+diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
+index 298b985..29d486e 100644
+--- a/hw/etraxfs_ser.c
++++ b/hw/etraxfs_ser.c
+@@ -208,6 +208,12 @@ static void etraxfs_ser_reset(DeviceState *d)
+
+ }
+
++static const QemuChrHandlers serial_handlers = {
++ .fd_can_read = serial_can_receive,
++ .fd_read = serial_receive,
++ .fd_event = serial_event,
++};
++
+ static int etraxfs_ser_init(SysBusDevice *dev)
+ {
+ struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
+@@ -217,10 +223,9 @@ static int etraxfs_ser_init(SysBusDevice *dev)
+ sysbus_init_mmio_region(dev, &s->mmio);
+
+ s->chr = qdev_init_chardev(&dev->qdev);
+- if (s->chr)
+- qemu_chr_add_handlers(s->chr,
+- serial_can_receive, serial_receive,
+- serial_event, s);
++ if (s->chr) {
++ qemu_chr_add_handlers(s->chr, &serial_handlers, s);
++ }
+ return 0;
+ }
+
+diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
+index c90b810..ac6c33b 100644
+--- a/hw/grlib_apbuart.c
++++ b/hw/grlib_apbuart.c
+@@ -144,16 +144,18 @@ static CPUWriteMemoryFunc * const grlib_apbuart_write[] = {
+ NULL, NULL, grlib_apbuart_writel,
+ };
+
++static const QemuChrHandlers grlib_handlers = {
++ .fd_can_read = grlib_apbuart_can_receive,
++ .fd_read = grlib_apbuart_receive,
++ .fd_event = grlib_apbuart_event,
++};
++
+ static int grlib_apbuart_init(SysBusDevice *dev)
+ {
+ UART *uart = FROM_SYSBUS(typeof(*uart), dev);
+ int uart_regs = 0;
+
+- qemu_chr_add_handlers(uart->chr,
+- grlib_apbuart_can_receive,
+- grlib_apbuart_receive,
+- grlib_apbuart_event,
+- uart);
++ qemu_chr_add_handlers(uart->chr, &grlib_handlers, uart);
+
+ sysbus_init_irq(dev, &uart->irq);
+
+diff --git a/hw/ivshmem.c b/hw/ivshmem.c
+index 7b4dbf6..ee78576 100644
+--- a/hw/ivshmem.c
++++ b/hw/ivshmem.c
+@@ -276,6 +276,18 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
+ msix_notify(pdev, entry->vector);
+ }
+
++static const QemuChrHandlers ivshmem_handlers = {
++ .fd_can_read = ivshmem_can_receive,
++ .fd_read = ivshmem_receive,
++ .fd_event = ivshmem_event,
++};
++
++static const QemuChrHandlers ivshmem_msi_handlers = {
++ .fd_can_read = ivshmem_can_receive,
++ .fd_read = fake_irqfd,
++ .fd_event = ivshmem_event,
++};
++
+ static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
+ int vector)
+ {
+@@ -295,11 +307,10 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
+ s->eventfd_table[vector].pdev = &s->dev;
+ s->eventfd_table[vector].vector = vector;
+
+- qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
+- ivshmem_event, &s->eventfd_table[vector]);
++ qemu_chr_add_handlers(chr, &ivshmem_msi_handlers,
++ &s->eventfd_table[vector]);
+ } else {
+- qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
+- ivshmem_event, s);
++ qemu_chr_add_handlers(chr, &ivshmem_handlers, s);
+ }
+
+ return chr;
+@@ -614,6 +625,12 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
+ return 0;
+ }
+
++static const QemuChrHandlers ivshmem_server_handlers = {
++ .fd_can_read = ivshmem_can_receive,
++ .fd_read = ivshmem_read,
++ .fd_event = ivshmem_event,
++};
++
+ static int pci_ivshmem_init(PCIDevice *dev)
+ {
+ IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+@@ -703,8 +720,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
+
+ s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
+
+- qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
+- ivshmem_event, s);
++ qemu_chr_add_handlers(s->server_chr, &ivshmem_server_handlers, s);
+ } else {
+ /* just map the file immediately, we're not using a server */
+ int fd;
+diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
+index 5454aa4..1b9fa07 100644
+--- a/hw/lm32_juart.c
++++ b/hw/lm32_juart.c
+@@ -110,13 +110,19 @@ static void juart_reset(DeviceState *d)
+ s->jrx = 0;
+ }
+
++static const QemuChrHandlers juart_handlers = {
++ .fd_can_read = juart_can_rx,
++ .fd_read = juart_rx,
++ .fd_event = juart_event,
++};
++
+ static int lm32_juart_init(SysBusDevice *dev)
+ {
+ LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+ s->chr = qdev_init_chardev(&dev->qdev);
+ if (s->chr) {
+- qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
++ qemu_chr_add_handlers(s->chr, juart_handlers, s);
+ }
+
+ return 0;
+diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
+index 3678545..ccaf88c 100644
+--- a/hw/lm32_uart.c
++++ b/hw/lm32_uart.c
+@@ -242,6 +242,12 @@ static void uart_reset(DeviceState *d)
+ s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
+ }
+
++static const QemuChrHandlers uart_handlers = {
++ .fd_can_read = uart_can_rx,
++ .fd_read = uart_rx,
++ .fd_event = uart_event,
++};
++
+ static int lm32_uart_init(SysBusDevice *dev)
+ {
+ LM32UartState *s = FROM_SYSBUS(typeof(*s), dev);
+@@ -255,7 +261,7 @@ static int lm32_uart_init(SysBusDevice *dev)
+
+ s->chr = qdev_init_chardev(&dev->qdev);
+ if (s->chr) {
+- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
++ qemu_chr_add_handlers(s->chr, uart_handlers, s);
+ }
+
+ return 0;
+diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
+index e6b2ab0..2870683 100644
+--- a/hw/mcf_uart.c
++++ b/hw/mcf_uart.c
+@@ -268,6 +268,12 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
+ mcf_uart_push_byte(s, buf[0]);
+ }
+
++static const QemuChrHandlers mcf_uart_handlers = {
++ .fd_can_read = mcf_uart_can_receive,
++ .fd_read = mcf_uart_receive,
++ .fd_event = mcf_uart_event,
++};
++
+ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
+ {
+ mcf_uart_state *s;
+@@ -276,8 +282,7 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
+ s->chr = chr;
+ s->irq = irq;
+ if (chr) {
+- qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
+- mcf_uart_event, s);
++ qemu_chr_add_handlers(chr, &mcf_uart_handlers, s);
+ }
+ mcf_uart_reset(s);
+ return s;
+diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
+index 5404ca9..fd10e12 100644
+--- a/hw/milkymist-uart.c
++++ b/hw/milkymist-uart.c
+@@ -189,6 +189,12 @@ static void milkymist_uart_reset(DeviceState *d)
+ s->regs[R_STAT] = STAT_THRE;
+ }
+
++static const QemuChrHandlers uart_handlers = {
++ .fd_can_read = uart_can_rx,
++ .fd_read = uart_rx,
++ .fd_event = uart_event,
++};
++
+ static int milkymist_uart_init(SysBusDevice *dev)
+ {
+ MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
+@@ -201,7 +207,7 @@ static int milkymist_uart_init(SysBusDevice *dev)
+
+ s->chr = qdev_init_chardev(&dev->qdev);
+ if (s->chr) {
+- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
++ qemu_chr_add_handlers(s->chr, uart_handlers, s);
+ }
+
+ return 0;
+diff --git a/hw/pl011.c b/hw/pl011.c
+index 707a161..7482246 100644
+--- a/hw/pl011.c
++++ b/hw/pl011.c
+@@ -260,6 +260,12 @@ static const VMStateDescription vmstate_pl011 = {
+ }
+ };
+
++static const QemuChrHandlers pl011_handlers = {
++ .fd_can_read = pl011_can_receive,
++ .fd_read = pl011_receive,
++ .fd_event = pl011_event,
++};
++
+ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
+ {
+ int iomemtype;
+@@ -278,8 +284,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
+ s->cr = 0x300;
+ s->flags = 0x90;
+ if (s->chr) {
+- qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
+- pl011_event, s);
++ qemu_chr_add_handlers(s->chr, &pl011_handlers, s);
+ }
+ vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
+ return 0;
+diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
+index e9a507e..24925b6 100644
+--- a/hw/pxa2xx.c
++++ b/hw/pxa2xx.c
+@@ -1984,6 +1984,12 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id)
+ return 0;
+ }
+
++static const QemuChrHandlers pxa2xx_handlers = {
++ .fd_can_read = pxa2xx_fir_is_empty,
++ .fd_read = pxa2xx_fir_rx,
++ .fd_event = pxa2xx_fir_event,
++};
++
+ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
+ target_phys_addr_t base,
+ qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma,
+@@ -2002,10 +2008,9 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
+ memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000);
+ memory_region_add_subregion(sysmem, base, &s->iomem);
+
+- if (chr)
+- qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
+- pxa2xx_fir_rx, pxa2xx_fir_event, s);
+-
++ if (chr) {
++ qemu_chr_add_handlers(chr, &pxa2xx_handlers, s);
++ }
+ register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save,
+ pxa2xx_fir_load, s);
+
+diff --git a/hw/serial.c b/hw/serial.c
+index d35c7a9..6499d4a 100644
+--- a/hw/serial.c
++++ b/hw/serial.c
+@@ -728,6 +728,12 @@ static void serial_reset(void *opaque)
+ qemu_irq_lower(s->irq);
+ }
+
++static const QemuChrHandlers serial_handlers = {
++ .fd_can_read = serial_can_receive1,
++ .fd_read = serial_receive1,
++ .fd_event = serial_event,
++};
++
+ static void serial_init_core(SerialState *s)
+ {
+ if (!s->chr) {
+@@ -742,8 +748,7 @@ static void serial_init_core(SerialState *s)
+
+ qemu_register_reset(serial_reset, s);
+
+- qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
+- serial_event, s);
++ qemu_chr_add_handlers(s->chr, &serial_handlers, s);
+ }
+
+ /* Change the main reference oscillator frequency. */
+diff --git a/hw/sh_serial.c b/hw/sh_serial.c
+index a20c59e..470ce7a 100644
+--- a/hw/sh_serial.c
++++ b/hw/sh_serial.c
+@@ -350,6 +350,12 @@ static CPUWriteMemoryFunc * const sh_serial_writefn[] = {
+ &sh_serial_write,
+ };
+
++static const QemuChrHandlers sh_serial_handlers = {
++ .fd_can_read = sh_serial_can_receive1,
++ .fd_read = sh_serial_receive1,
++ .fd_event = sh_serial_event,
++};
++
+ void sh_serial_init (target_phys_addr_t base, int feat,
+ uint32_t freq, CharDriverState *chr,
+ qemu_irq eri_source,
+@@ -389,9 +395,9 @@ void sh_serial_init (target_phys_addr_t base, int feat,
+
+ s->chr = chr;
+
+- if (chr)
+- qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
+- sh_serial_event, s);
++ if (chr) {
++ qemu_chr_add_handlers(chr, &sh_serial_handlers, s);
++ }
+
+ s->eri = eri_source;
+ s->rxi = rxi_source;
+diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
+index f23cc36..0d9cd59 100644
+--- a/hw/spapr_vty.c
++++ b/hw/spapr_vty.c
+@@ -54,6 +54,11 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
+ qemu_chr_fe_write(dev->chardev, buf, len);
+ }
+
++static const QemuChrHandlers vty_handlers = {
++ .fd_can_read = vty_can_receive,
++ .fd_read = vty_receive,
++};
++
+ static int spapr_vty_init(VIOsPAPRDevice *sdev)
+ {
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+@@ -63,8 +68,7 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev)
+ exit(1);
+ }
+
+- qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+- vty_receive, NULL, dev);
++ qemu_chr_add_handlers(dev->chardev, vty_handlers, dev);
+
+ return 0;
+ }
+diff --git a/hw/strongarm.c b/hw/strongarm.c
+index a3d9080..8a8a219 100644
+--- a/hw/strongarm.c
++++ b/hw/strongarm.c
+@@ -1160,6 +1160,12 @@ static const MemoryRegionOps strongarm_uart_ops = {
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ };
+
++static const QemuChrHandlers strongarm_uart_handlers = {
++ .fd_can_read = strongarm_uart_can_receive,
++ .fd_read = strongarm_uart_receive,
++ .fd_event = strongarm_uart_event,
++};
++
+ static int strongarm_uart_init(SysBusDevice *dev)
+ {
+ StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev);
+@@ -1172,11 +1178,7 @@ static int strongarm_uart_init(SysBusDevice *dev)
+ s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s);
+
+ if (s->chr) {
+- qemu_chr_add_handlers(s->chr,
+- strongarm_uart_can_receive,
+- strongarm_uart_receive,
+- strongarm_uart_event,
+- s);
++ qemu_chr_add_handlers(s->chr, &strongarm_uart_handlers, s);
+ }
+
+ return 0;
+diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c
+index c83f82c..fff76da 100644
+--- a/hw/syborg_serial.c
++++ b/hw/syborg_serial.c
+@@ -292,6 +292,12 @@ static const VMStateDescription vmstate_syborg_serial = {
+ }
+ };
+
++static const QemuChrHandlers syborg_serial_handlers = {
++ .fd_can_read = syborg_serial_can_receive,
++ .fd_read = syborg_serial_receive,
++ .fd_event = syborg_serial_event,
++};
++
+ static int syborg_serial_init(SysBusDevice *dev)
+ {
+ SyborgSerialState *s = FROM_SYSBUS(SyborgSerialState, dev);
+@@ -304,8 +310,7 @@ static int syborg_serial_init(SysBusDevice *dev)
+ sysbus_init_mmio(dev, 0x1000, iomemtype);
+ s->chr = qdev_init_chardev(&dev->qdev);
+ if (s->chr) {
+- qemu_chr_add_handlers(s->chr, syborg_serial_can_receive,
+- syborg_serial_receive, syborg_serial_event, s);
++ qemu_chr_add_handlers(s->chr, &syborg_serial_handlers, s);
+ }
+ if (s->fifo_size <= 0) {
+ fprintf(stderr, "syborg_serial: fifo too small\n");
+diff --git a/hw/usb-serial.c b/hw/usb-serial.c
+index 7dbf6df..bcf6622 100644
+--- a/hw/usb-serial.c
++++ b/hw/usb-serial.c
+@@ -482,6 +482,12 @@ static void usb_serial_event(void *opaque, int event)
+ }
+ }
+
++static const QemuChrHandlers usb_serial_handlers = {
++ .fd_can_read = usb_serial_can_read,
++ .fd_read = usb_serial_read,
++ .fd_event = usb_serial_event,
++};
++
+ static int usb_serial_initfn(USBDevice *dev)
+ {
+ USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
+@@ -493,8 +499,7 @@ static int usb_serial_initfn(USBDevice *dev)
+ return -1;
+ }
+
+- qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
+- usb_serial_event, s);
++ qemu_chr_add_handlers(s->cs, &usb_serial_handlers, s);
+ usb_serial_handle_reset(dev);
+ return 0;
+ }
+diff --git a/hw/virtio-console.c b/hw/virtio-console.c
+index d3351c8..6d6f3ef 100644
+--- a/hw/virtio-console.c
++++ b/hw/virtio-console.c
+@@ -95,6 +95,12 @@ static void chr_event(void *opaque, int event)
+ }
+ }
+
++static const QemuChrHandlers chr_handlers = {
++ .fd_can_read = chr_can_read,
++ .fd_read = chr_read,
++ .fd_event = chr_event,
++};
++
+ static int virtconsole_initfn(VirtIOSerialPort *port)
+ {
+ VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+@@ -107,8 +113,7 @@ static int virtconsole_initfn(VirtIOSerialPort *port)
+ }
+
+ if (vcon->chr) {
+- qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
+- vcon);
++ qemu_chr_add_handlers(vcon->chr, &chr_handlers, vcon);
+ info->have_data = flush_buf;
+ info->guest_open = guest_open;
+ info->guest_close = guest_close;
+@@ -126,7 +131,7 @@ static int virtconsole_exitfn(VirtIOSerialPort *port)
+ * Instead of closing the chardev, free it so it can be used
+ * for other purposes.
+ */
+- qemu_chr_add_handlers(vcon->chr, NULL, NULL, NULL, NULL);
++ qemu_chr_add_handlers(vcon->chr, NULL, NULL);
+ }
+
+ return 0;
+diff --git a/hw/xen_console.c b/hw/xen_console.c
+index edcb31c..2ba74f0 100644
+--- a/hw/xen_console.c
++++ b/hw/xen_console.c
+@@ -212,6 +212,11 @@ out:
+ return ret;
+ }
+
++static const QemuChrHandlers xencons_handlers = {
++ .fd_can_read = xencons_can_receive,
++ .fd_read = xencons_receive,
++};
++
+ static int con_initialise(struct XenDevice *xendev)
+ {
+ struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+@@ -232,9 +237,9 @@ static int con_initialise(struct XenDevice *xendev)
+ return -1;
+
+ xen_be_bind_evtchn(&con->xendev);
+- if (con->chr)
+- qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
+- NULL, con);
++ if (con->chr) {
++ qemu_chr_add_handlers(con->chr, &xencons_handlers, con);
++ }
+
+ xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
+ con->ring_ref,
+@@ -248,8 +253,9 @@ static void con_disconnect(struct XenDevice *xendev)
+ {
+ struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+- if (con->chr)
+- qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
++ if (con->chr) {
++ qemu_chr_add_handlers(con->chr, NULL, NULL);
++ }
+ xen_be_unbind_evtchn(&con->xendev);
+
+ if (con->sring) {
+diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
+index ceb7b4d..69f7191 100644
+--- a/hw/xilinx_uartlite.c
++++ b/hw/xilinx_uartlite.c
+@@ -195,6 +195,12 @@ static void uart_event(void *opaque, int event)
+
+ }
+
++static const QemuChrHandlers uart_handlers = {
++ .fd_can_read = uart_can_rx,
++ .fd_read = uart_rx,
++ .fd_event = uart_event,
++};
++
+ static int xilinx_uartlite_init(SysBusDevice *dev)
+ {
+ struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
+@@ -206,8 +212,9 @@ static int xilinx_uartlite_init(SysBusDevice *dev)
+ sysbus_init_mmio_region(dev, &s->mmio);
+
+ s->chr = qdev_init_chardev(&dev->qdev);
+- if (s->chr)
+- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
++ if (s->chr) {
++ qemu_chr_add_handlers(s->chr, &uart_handlers, s);
++ }
+ return 0;
+ }
+
+diff --git a/monitor.c b/monitor.c
+index f956eb7..a82fda3 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -4882,6 +4882,18 @@ static void sortcmdlist(void)
+ * End:
+ */
+
++static const QemuChrHandlers monitor_handlers = {
++ .fd_can_read = monitor_can_read,
++ .fd_read = monitor_read,
++ .fd_event = monitor_event,
++};
++
++static const QemuChrHandlers monitor_control_handlers = {
++ .fd_can_read = monitor_can_read,
++ .fd_read = monitor_control_read,
++ .fd_event = monitor_control_event,
++};
++
+ void monitor_init(CharDriverState *chr, int flags)
+ {
+ static int is_first_init = 1;
+@@ -4904,12 +4916,10 @@ void monitor_init(CharDriverState *chr, int flags)
+ if (monitor_ctrl_mode(mon)) {
+ mon->mc = g_malloc0(sizeof(MonitorControl));
+ /* Control mode requires special handlers */
+- qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
+- monitor_control_event, mon);
++ qemu_chr_add_handlers(chr, &monitor_control_handlers, mon);
+ qemu_chr_fe_set_echo(chr, true);
+ } else {
+- qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
+- monitor_event, mon);
++ qemu_chr_add_handlers(chr, &monitor_handlers, mon);
+ }
+
+ QLIST_INSERT_HEAD(&mon_list, mon, entry);
+diff --git a/net/slirp.c b/net/slirp.c
+index 6646ecb..05405ff 100644
+--- a/net/slirp.c
++++ b/net/slirp.c
+@@ -576,6 +576,11 @@ static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
+ slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
+ }
+
++static const QemuChrHandlers guestfwd_handlers = {
++ .fd_can_read = guestfwd_can_read,
++ .fd_read = guestfwd_read,
++};
++
+ static int slirp_guestfwd(SlirpState *s, const char *config_str,
+ int legacy_format)
+ {
+@@ -632,8 +637,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
+ fwd->port = port;
+ fwd->slirp = s->slirp;
+
+- qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
+- NULL, fwd);
++ qemu_chr_add_handlers(fwd->hd, &guestfwd_handlers, fwd);
+ return 0;
+
+ fail_syntax:
+diff --git a/qemu-char.c b/qemu-char.c
+index a5ca611..d2a99a6 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -189,19 +189,26 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
+ va_end(ap);
+ }
+
++static const QemuChrHandlers null_handlers = {
++ /* All handlers are initialised to NULL */
++};
++
+ void qemu_chr_add_handlers(CharDriverState *s,
+- IOCanReadHandler *fd_can_read,
+- IOReadHandler *fd_read,
+- IOEventHandler *fd_event,
+- void *opaque)
++ const QemuChrHandlers *handlers, void *opaque)
+ {
+- if (!opaque && !fd_can_read && !fd_read && !fd_event) {
++ if (!s) {
++ return;
++ }
++ if (!opaque && !handlers) {
+ /* chr driver being released. */
+ ++s->avail_connections;
+ }
+- s->chr_can_read = fd_can_read;
+- s->chr_read = fd_read;
+- s->chr_event = fd_event;
++ if (!handlers) {
++ handlers = &null_handlers;
++ }
++ s->chr_can_read = handlers->fd_can_read;
++ s->chr_read = handlers->fd_read;
++ s->chr_event = handlers->fd_event;
+ s->handler_opaque = opaque;
+ if (s->chr_update_read_handler)
+ s->chr_update_read_handler(s);
+@@ -441,6 +448,12 @@ static void mux_chr_event(void *opaque, int event)
+ mux_chr_send_event(d, i, event);
+ }
+
++static const QemuChrHandlers mux_chr_handlers = {
++ .fd_can_read = mux_chr_can_read,
++ .fd_read = mux_chr_read,
++ .fd_event = mux_chr_event,
++};
++
+ static void mux_chr_update_read_handler(CharDriverState *chr)
+ {
+ MuxDriver *d = chr->opaque;
+@@ -455,8 +468,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr)
+ d->chr_event[d->mux_cnt] = chr->chr_event;
+ /* Fix up the real driver with mux routines */
+ if (d->mux_cnt == 0) {
+- qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
+- mux_chr_event, chr);
++ qemu_chr_add_handlers(d->drv, &mux_chr_handlers, chr);
+ }
+ if (d->focus != -1) {
+ mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
+diff --git a/qemu-char.h b/qemu-char.h
+index 8ca1e2d..564e688 100644
+--- a/qemu-char.h
++++ b/qemu-char.h
+@@ -222,10 +222,15 @@ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len);
+ */
+ void qemu_chr_be_event(CharDriverState *s, int event);
+
+-void qemu_chr_add_handlers(CharDriverState *s,
+- IOCanReadHandler *fd_can_read,
+- IOReadHandler *fd_read,
+- IOEventHandler *fd_event,
++
++typedef struct QemuChrHandlers {
++ IOCanReadHandler *fd_can_read;
++ IOReadHandler *fd_read;
++ IOHandler *fd_write_unblocked;
++ IOEventHandler *fd_event;
++} QemuChrHandlers;
++
++void qemu_chr_add_handlers(CharDriverState *s, const QemuChrHandlers *handlers,
+ void *opaque);
+
+ void qemu_chr_generic_open(CharDriverState *s);
+diff --git a/usb-redir.c b/usb-redir.c
+index 86bccf8..e421cff 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -865,6 +865,12 @@ static void usbredir_chardev_event(void *opaque, int event)
+ }
+ }
+
++static const QemuChrHandlers usbredir_chr_handlers = {
++ .fd_can_read = usbredir_chardev_can_read,
++ .fd_read = usbredir_chardev_read,
++ .fd_event = usbredir_chardev_event,
++};
++
+ /*
+ * init + destroy
+ */
+@@ -892,8 +898,7 @@ static int usbredir_initfn(USBDevice *udev)
+
+ /* Let the backend know we are ready */
+ qemu_chr_fe_open(dev->cs);
+- qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
+- usbredir_chardev_read, usbredir_chardev_event, dev);
++ qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev);
+
+ return 0;
+ }
+--
+1.7.7.5
+
diff --git a/0108-iohandlers-Add-enable-disable_write_fd_handler-funct.patch b/0108-iohandlers-Add-enable-disable_write_fd_handler-funct.patch
new file mode 100644
index 0000000..a02a798
--- /dev/null
+++ b/0108-iohandlers-Add-enable-disable_write_fd_handler-funct.patch
@@ -0,0 +1,77 @@
+From f896c023201863927853c5d97e62916e0753fede Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Mon, 21 Mar 2011 20:32:58 +0100
+Subject: [PATCH 108/118] iohandlers: Add enable/disable_write_fd_handler()
+ functions
+
+These will be used to provide a cleaner API for the nonblocking case.
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ iohandler.c | 35 +++++++++++++++++++++++++++++++++++
+ main-loop.h | 3 +++
+ 2 files changed, 38 insertions(+), 0 deletions(-)
+
+diff --git a/iohandler.c b/iohandler.c
+index 5640d49..a9a62cb 100644
+--- a/iohandler.c
++++ b/iohandler.c
+@@ -45,6 +45,41 @@ typedef struct IOHandlerRecord {
+ static QLIST_HEAD(, IOHandlerRecord) io_handlers =
+ QLIST_HEAD_INITIALIZER(io_handlers);
+
++static IOHandlerRecord *find_iohandler(int fd)
++{
++ IOHandlerRecord *ioh;
++
++ QLIST_FOREACH(ioh, &io_handlers, next) {
++ if (ioh->fd == fd) {
++ return ioh;
++ }
++ }
++ return NULL;
++}
++
++void enable_write_fd_handler(int fd, IOHandler *fd_write)
++{
++ IOHandlerRecord *ioh;
++
++ ioh = find_iohandler(fd);
++ if (!ioh) {
++ return;
++ }
++
++ ioh->fd_write = fd_write;
++}
++
++void disable_write_fd_handler(int fd)
++{
++ IOHandlerRecord *ioh;
++
++ ioh = find_iohandler(fd);
++ if (!ioh) {
++ return;
++ }
++
++ ioh->fd_write = NULL;
++}
+
+ /* XXX: fd_read_poll should be suppressed, but an API change is
+ necessary in the character devices to suppress fd_can_read(). */
+diff --git a/main-loop.h b/main-loop.h
+index 8a716b1..c5a96cd 100644
+--- a/main-loop.h
++++ b/main-loop.h
+@@ -167,6 +167,9 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+ typedef int IOCanReadHandler(void *opaque);
+ typedef void IOHandler(void *opaque);
+
++void enable_write_fd_handler(int fd, IOHandler *fd_write);
++void disable_write_fd_handler(int fd);
++
+ /**
+ * qemu_set_fd_handler2: Register a file descriptor with the main loop
+ *
+--
+1.7.7.5
+
diff --git a/0109-char-Add-framework-for-a-write-unblocked-callback.patch b/0109-char-Add-framework-for-a-write-unblocked-callback.patch
new file mode 100644
index 0000000..2599187
--- /dev/null
+++ b/0109-char-Add-framework-for-a-write-unblocked-callback.patch
@@ -0,0 +1,61 @@
+From 6d5337e1dc8d926f9183e2f5eb5e97c438203527 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Mon, 21 Mar 2011 21:41:42 +0100
+Subject: [PATCH 109/118] char: Add framework for a 'write unblocked' callback
+
+The char layer can let users know that the driver will block on further
+input. For users interested in not blocking, they can assign a function
+pointer that will be called back when the driver becomes writable. This
+patch just adds the function pointers to the CharDriverState structure,
+future patches will enable the nonblocking and callback functionality.
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ qemu-char.c | 3 +++
+ qemu-char.h | 4 ++++
+ 2 files changed, 7 insertions(+), 0 deletions(-)
+
+diff --git a/qemu-char.c b/qemu-char.c
+index d2a99a6..66b5887 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -208,11 +208,14 @@ void qemu_chr_add_handlers(CharDriverState *s,
+ }
+ s->chr_can_read = handlers->fd_can_read;
+ s->chr_read = handlers->fd_read;
++ s->chr_write_unblocked = handlers->fd_write_unblocked;
+ s->chr_event = handlers->fd_event;
+ s->handler_opaque = opaque;
+ if (s->chr_update_read_handler)
+ s->chr_update_read_handler(s);
+
++ s->write_blocked = false;
++
+ /* We're connecting to an already opened device, so let's make sure we
+ also get the open event */
+ if (s->opened) {
+diff --git a/qemu-char.h b/qemu-char.h
+index 564e688..2628bee 100644
+--- a/qemu-char.h
++++ b/qemu-char.h
+@@ -62,6 +62,9 @@ struct CharDriverState {
+ IOEventHandler *chr_event;
+ IOCanReadHandler *chr_can_read;
+ IOReadHandler *chr_read;
++ IOHandler *chr_write_unblocked;
++ void (*chr_enable_write_fd_handler)(struct CharDriverState *chr);
++ void (*chr_disable_write_fd_handler)(struct CharDriverState *chr);
+ void *handler_opaque;
+ void (*chr_close)(struct CharDriverState *chr);
+ void (*chr_accept_input)(struct CharDriverState *chr);
+@@ -74,6 +77,7 @@ struct CharDriverState {
+ char *filename;
+ int opened;
+ int avail_connections;
++ bool write_blocked; /* Are we in a blocked state? */
+ QTAILQ_ENTRY(CharDriverState) next;
+ };
+
+--
+1.7.7.5
+
diff --git a/0110-char-Update-send_all-to-handle-nonblocking-chardev-w.patch b/0110-char-Update-send_all-to-handle-nonblocking-chardev-w.patch
new file mode 100644
index 0000000..c694ebf
--- /dev/null
+++ b/0110-char-Update-send_all-to-handle-nonblocking-chardev-w.patch
@@ -0,0 +1,188 @@
+From 9ca6b87b877fa46c81ce8e5b5a97dca4f522a727 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Mon, 21 Mar 2011 22:00:27 +0100
+Subject: [PATCH 110/118] char: Update send_all() to handle nonblocking
+ chardev write requests
+
+The send_all function is modified to return to the caller in case the
+driver cannot handle any more data. It returns -EAGAIN or
+WSAEWOULDBLOCK on non-Windows and Windows platforms respectively. This
+is only done when the caller sets a callback function handler indicating
+it's not interested in blocking till the driver has written out all the
+data.
+
+Currently there's no driver or caller that supports this. Future
+commits will add such capability.
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ net/socket.c | 4 +-
+ qemu-char.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
+ qemu_socket.h | 2 +-
+ 3 files changed, 66 insertions(+), 9 deletions(-)
+
+diff --git a/net/socket.c b/net/socket.c
+index e9ef128..0d53dce 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -56,8 +56,8 @@ static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_
+ uint32_t len;
+ len = htonl(size);
+
+- send_all(s->fd, (const uint8_t *)&len, sizeof(len));
+- return send_all(s->fd, buf, size);
++ send_all(NULL, s->fd, (const uint8_t *)&len, sizeof(len));
++ return send_all(NULL, s->fd, buf, size);
+ }
+
+ static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size)
+diff --git a/qemu-char.c b/qemu-char.c
+index 66b5887..5e7f68e 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -507,7 +507,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+
+
+ #ifdef _WIN32
+-int send_all(int fd, const void *buf, int len1)
++static int do_send(int fd, const void *buf, int len1, bool nonblock)
+ {
+ int ret, len;
+
+@@ -515,9 +515,14 @@ int send_all(int fd, const void *buf, int len1)
+ while (len > 0) {
+ ret = send(fd, buf, len, 0);
+ if (ret < 0) {
++ if (nonblock && len1 - len) {
++ return len1 - len;
++ }
+ errno = WSAGetLastError();
+ if (errno != WSAEWOULDBLOCK) {
+ return -1;
++ } else if (errno == WSAEWOULDBLOCK && nonblock) {
++ return WSAEWOULDBLOCK;
+ }
+ } else if (ret == 0) {
+ break;
+@@ -531,7 +536,7 @@ int send_all(int fd, const void *buf, int len1)
+
+ #else
+
+-int send_all(int fd, const void *_buf, int len1)
++static int do_send(int fd, const void *_buf, int len1, bool nonblock)
+ {
+ int ret, len;
+ const uint8_t *buf = _buf;
+@@ -540,8 +545,15 @@ int send_all(int fd, const void *_buf, int len1)
+ while (len > 0) {
+ ret = write(fd, buf, len);
+ if (ret < 0) {
+- if (errno != EINTR && errno != EAGAIN)
++ if (nonblock && len1 - len) {
++ return len1 - len;
++ }
++ if (errno == EAGAIN && nonblock) {
++ return -EAGAIN;
++ }
++ if (errno != EINTR && errno != EAGAIN) {
+ return -1;
++ }
+ } else if (ret == 0) {
+ break;
+ } else {
+@@ -556,6 +568,44 @@ int send_all(int fd, const void *_buf, int len1)
+ #define STDIO_MAX_CLIENTS 1
+ static int stdio_nb_clients;
+
++int send_all(CharDriverState *chr, int fd, const void *_buf, int len1)
++{
++ int ret, eagain_errno;
++ bool nonblock;
++
++ if (chr && chr->write_blocked) {
++ /*
++ * The caller should not send us data while we're blocked,
++ * but this can happen when multiple writers are woken at once,
++ * so simply return -EAGAIN.
++ */
++ return -EAGAIN;
++ }
++
++ nonblock = false;
++ /*
++ * Ensure the char backend is able to receive and handle the
++ * 'write unblocked' event before we turn on nonblock support.
++ */
++ if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
++ nonblock = true;
++ }
++ ret = do_send(fd, _buf, len1, nonblock);
++
++#ifdef _WIN32
++ eagain_errno = WSAEWOULDBLOCK;
++#else
++ eagain_errno = -EAGAIN;
++#endif
++
++ if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) {
++ /* Update fd handler to wake up when chr becomes writable */
++ chr->chr_enable_write_fd_handler(chr);
++ chr->write_blocked = true;
++ }
++ return ret;
++}
++
+ #ifndef _WIN32
+
+ typedef struct {
+@@ -567,7 +617,7 @@ typedef struct {
+ static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+ FDCharDriver *s = chr->opaque;
+- return send_all(s->fd_out, buf, len);
++ return send_all(chr, s->fd_out, buf, len);
+ }
+
+ static int fd_chr_read_poll(void *opaque)
+@@ -892,7 +942,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ pty_chr_update_read_handler(chr);
+ return 0;
+ }
+- return send_all(s->fd, buf, len);
++ return send_all(chr, s->fd, buf, len);
+ }
+
+ static int pty_chr_read_poll(void *opaque)
+@@ -2196,8 +2246,15 @@ static void tcp_closed(void *opaque)
+ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+ TCPCharDriver *s = chr->opaque;
++
+ if (s->connected) {
+- return send_all(s->fd, buf, len);
++ int ret;
++
++ ret = send_all(chr, s->fd, buf, len);
++ if (ret == -1 && errno == EPIPE) {
++ tcp_closed(chr);
++ }
++ return ret;
+ } else {
+ /* XXX: indicate an error ? */
+ return len;
+diff --git a/qemu_socket.h b/qemu_socket.h
+index 9e32fac..9ea33fe 100644
+--- a/qemu_socket.h
++++ b/qemu_socket.h
+@@ -37,7 +37,7 @@ int qemu_socket(int domain, int type, int protocol);
+ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+ void socket_set_block(int fd);
+ void socket_set_nonblock(int fd);
+-int send_all(int fd, const void *buf, int len1);
++int send_all(CharDriverState *chr, int fd, const void *buf, int len1);
+
+ /* New, ipv6-ready socket helper functions, see qemu-sockets.c */
+ int inet_listen_opts(QemuOpts *opts, int port_offset);
+--
+1.7.7.5
+
diff --git a/0111-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch b/0111-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch
new file mode 100644
index 0000000..10ccf75
--- /dev/null
+++ b/0111-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch
@@ -0,0 +1,81 @@
+From b235c039fbab104ab582922f0083625564e177b1 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Mon, 21 Mar 2011 22:02:47 +0100
+Subject: [PATCH 111/118] char: Equip the unix/tcp backend to handle
+ nonblocking writes#
+
+Now that the infrastructure is in place to return -EAGAIN to callers,
+individual char drivers can set their update_fd_handlers() function to
+set or remove an fd's write handler. This handler checks if the driver
+became writable.
+
+A generic callback routine is used for unblocking writes and letting
+users of chardevs know that a driver became writable again.
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ qemu-char.c | 34 ++++++++++++++++++++++++++++++++++
+ 1 files changed, 34 insertions(+), 0 deletions(-)
+
+diff --git a/qemu-char.c b/qemu-char.c
+index 5e7f68e..f98b240 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -106,6 +106,19 @@
+ static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
+ QTAILQ_HEAD_INITIALIZER(chardevs);
+
++/*
++ * Generic routine that gets called when chardev becomes writable.
++ * Lets chardev user know it's OK to send more data.
++ */
++static void char_write_unblocked(void *opaque)
++{
++ CharDriverState *chr = opaque;
++
++ chr->write_blocked = false;
++ chr->chr_disable_write_fd_handler(chr);
++ chr->chr_write_unblocked(chr->handler_opaque);
++}
++
+ void qemu_chr_be_event(CharDriverState *s, int event)
+ {
+ /* Keep track if the char device is open */
+@@ -2515,6 +2528,25 @@ static void tcp_chr_close(CharDriverState *chr)
+ qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+ }
+
++static void tcp_enable_write_fd_handler(CharDriverState *chr)
++{
++ TCPCharDriver *s = chr->opaque;
++
++ /*
++ * This function is called only after tcp_chr_connect() is called
++ * (either in 'server' mode or client mode. So we're sure of
++ * s->fd being initialised.
++ */
++ enable_write_fd_handler(s->fd, char_write_unblocked);
++}
++
++static void tcp_disable_write_fd_handler(CharDriverState *chr)
++{
++ TCPCharDriver *s = chr->opaque;
++
++ disable_write_fd_handler(s->fd);
++}
++
+ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
+ {
+ CharDriverState *chr = NULL;
+@@ -2571,6 +2603,8 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
+ chr->chr_close = tcp_chr_close;
+ chr->get_msgfd = tcp_get_msgfd;
+ chr->chr_add_client = tcp_chr_add_client;
++ chr->chr_enable_write_fd_handler = tcp_enable_write_fd_handler;
++ chr->chr_disable_write_fd_handler = tcp_disable_write_fd_handler;
+
+ if (is_listen) {
+ s->listen_fd = fd;
+--
+1.7.7.5
+
diff --git a/0112-char-Throttle-when-host-connection-is-down.patch b/0112-char-Throttle-when-host-connection-is-down.patch
new file mode 100644
index 0000000..f8d29af
--- /dev/null
+++ b/0112-char-Throttle-when-host-connection-is-down.patch
@@ -0,0 +1,56 @@
+From e5eb5b185d39942a2011b21114bb7f0b8e11427a Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Mon, 21 Mar 2011 22:05:10 +0100
+Subject: [PATCH 112/118] char: Throttle when host connection is down#
+
+When the host-side connection goes down, throttle the virtio-serial bus
+and later unthrottle when a connection gets established. This helps
+prevent any lost IO (guest->host) while the host connection was down.
+
+Bugzilla: 621484
+
+This commit actually helps the bug mentioned above as no writes will now
+get lost because of the throttling done here. With just the patches
+sent earlier for that bug, one write will end up getting lost in the
+worst case (host d/c, guest write, host connect).
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ qemu-char.c | 14 ++++++++++++++
+ 1 files changed, 14 insertions(+), 0 deletions(-)
+
+diff --git a/qemu-char.c b/qemu-char.c
+index f98b240..5f67652 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -140,6 +140,9 @@ static void qemu_chr_generic_open_bh(void *opaque)
+ {
+ CharDriverState *s = opaque;
+ qemu_chr_be_event(s, CHR_EVENT_OPENED);
++ if (s->write_blocked) {
++ char_write_unblocked(s);
++ }
+ qemu_bh_delete(s->bh);
+ s->bh = NULL;
+ }
+@@ -2266,6 +2269,17 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ ret = send_all(chr, s->fd, buf, len);
+ if (ret == -1 && errno == EPIPE) {
+ tcp_closed(chr);
++
++ if (chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) {
++ /*
++ * Since we haven't written out anything, let's say
++ * we're throttled. This will prevent any output from
++ * the guest getting lost if host-side chardev goes
++ * down. Unthrottle when we re-connect.
++ */
++ chr->write_blocked = true;
++ return 0;
++ }
+ }
+ return ret;
+ } else {
+--
+1.7.7.5
+
diff --git a/0113-virtio-console-Enable-port-throttling-when-chardev-i.patch b/0113-virtio-console-Enable-port-throttling-when-chardev-i.patch
new file mode 100644
index 0000000..73dfcb6
--- /dev/null
+++ b/0113-virtio-console-Enable-port-throttling-when-chardev-i.patch
@@ -0,0 +1,49 @@
+From 71108acb189f5fda923013ed72270642199ab50d Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Mon, 21 Mar 2011 22:06:41 +0100
+Subject: [PATCH 113/118] virtio-console: Enable port throttling when chardev
+ is slow to consume data
+
+When a chardev indicates it can't accept more data, we tell the
+virtio-serial code to stop sending us any more data till we tell
+otherwise. This helps in guests continuing to run normally while the vq
+keeps getting full and eventually the guest stops queueing more data.
+As soon as the chardev indicates it can accept more data, start pushing!
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ hw/virtio-console.c | 11 +++++++++++
+ 1 files changed, 11 insertions(+), 0 deletions(-)
+
+diff --git a/hw/virtio-console.c b/hw/virtio-console.c
+index 6d6f3ef..da68211 100644
+--- a/hw/virtio-console.c
++++ b/hw/virtio-console.c
+@@ -20,6 +20,16 @@ typedef struct VirtConsole {
+ CharDriverState *chr;
+ } VirtConsole;
+
++/*
++ * Callback function that's called from chardevs when backend becomes
++ * writable.
++ */
++static void chr_write_unblocked(void *opaque)
++{
++ VirtConsole *vcon = opaque;
++
++ virtio_serial_throttle_port(&vcon->port, false);
++}
+
+ /* Callback function that's called when the guest sends us data */
+ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
+@@ -99,6 +109,7 @@ static const QemuChrHandlers chr_handlers = {
+ .fd_can_read = chr_can_read,
+ .fd_read = chr_read,
+ .fd_event = chr_event,
++ .fd_write_unblocked = chr_write_unblocked,
+ };
+
+ static int virtconsole_initfn(VirtIOSerialPort *port)
+--
+1.7.7.5
+
diff --git a/0114-spice-qemu-char.c-add-throttling.patch b/0114-spice-qemu-char.c-add-throttling.patch
new file mode 100644
index 0000000..00c7580
--- /dev/null
+++ b/0114-spice-qemu-char.c-add-throttling.patch
@@ -0,0 +1,133 @@
+From d4066655fc866ac0e57420b32dec3b37277b374c Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Tue, 22 Mar 2011 12:27:59 +0200
+Subject: [PATCH 114/118] spice-qemu-char.c: add throttling
+
+BZ: 672191
+
+upstream: not submitted (explained below)
+
+Adds throttling support to spicevmc chardev. Uses a timer to avoid recursing:
+1. spice-server: reds.c: read_from_vdi_port
+2. qemu: spice-qemu-char.c: vmc_read
+3. chr_write_unblocked
+ (calls virtio_serial_throttle_port(port, false))
+4. qemu: virtio ...
+5. qemu: spice-qemu-char.c: spice_chr_write
+6. qemu: spice-qemu-char.c: wakeup (calls into spice-server)
+7. spice-server: ...
+8. qemu: spice-qemu-char.c: vmc_read
+
+Instead, in vmc_read if we were throttled and we are just about to return
+all the bytes we will set a timer to be triggered immediately to call
+chr_write_unblocked. Then we return after 2 above, and 3 is called from the
+timer callback. This also means we can later remove some ugly recursion protection
+from spice-server.
+
+The other tricky point in this patch is not returning the leftover chunk twice.
+When we throttle, by definition we have data that spice server didn't consume.
+It is being kept by virtio-serial, and by us. The next vmc_read callback needs
+to not return it, but just do unthrottling. Then virtio will give us the remaining
+chunk as usual in spice_chr_write, and we will pass it to spice server in the
+next vmc_read.
+
+This patch relies on Amit's series to expose throttling to chardev's, which
+was not accepted upstream, and will not be accepted upstream until the mainloop
+is reworked to use glib.
+---
+ spice-qemu-char.c | 39 +++++++++++++++++++++++++++++++++++----
+ 1 files changed, 35 insertions(+), 4 deletions(-)
+
+diff --git a/spice-qemu-char.c b/spice-qemu-char.c
+index 7e8eaa9..eeeb32e 100644
+--- a/spice-qemu-char.c
++++ b/spice-qemu-char.c
+@@ -1,4 +1,6 @@
+ #include "config-host.h"
++#include "qemu-common.h"
++#include "qemu-timer.h"
+ #include "trace.h"
+ #include "ui/qemu-spice.h"
+ #include <spice.h>
+@@ -25,6 +27,7 @@ typedef struct SpiceCharDriver {
+ uint8_t *datapos;
+ ssize_t bufsize, datalen;
+ uint32_t debug;
++ QEMUTimer *unblock_timer;
+ } SpiceCharDriver;
+
+ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
+@@ -50,6 +53,17 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
+ return out;
+ }
+
++static void spice_chr_unblock(void *opaque)
++{
++ SpiceCharDriver *scd = opaque;
++
++ if (scd->chr->chr_write_unblocked == NULL) {
++ dprintf(scd, 1, "%s: backend doesn't support unthrottling.\n", __func__);
++ return;
++ }
++ scd->chr->chr_write_unblocked(scd->chr->handler_opaque);
++}
++
+ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
+ {
+ SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+@@ -61,9 +75,16 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
+ scd->datapos += bytes;
+ scd->datalen -= bytes;
+ assert(scd->datalen >= 0);
+- if (scd->datalen == 0) {
+- scd->datapos = 0;
+- }
++ }
++ if (scd->datalen == 0 && scd->chr->write_blocked) {
++ dprintf(scd, 1, "%s: unthrottling (%d)\n", __func__, bytes);
++ scd->chr->write_blocked = false;
++ /*
++ * set a timer instead of calling scd->chr->chr_write_unblocked directly,
++ * because that will call back into spice_chr_write (see
++ * virtio-console.c:chr_write_unblocked), which is unwanted.
++ */
++ qemu_mod_timer(scd->unblock_timer, 0);
+ }
+ trace_spice_vmc_read(bytes, len);
+ return bytes;
+@@ -135,6 +156,7 @@ static void vmc_unregister_interface(SpiceCharDriver *scd)
+ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+ SpiceCharDriver *s = chr->opaque;
++ int read_bytes;
+
+ dprintf(s, 2, "%s: %d\n", __func__, len);
+ vmc_register_interface(s);
+@@ -147,7 +169,15 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ s->datapos = s->buffer;
+ s->datalen = len;
+ spice_server_char_device_wakeup(&s->sin);
+- return len;
++ read_bytes = len - s->datalen;
++ if (read_bytes != len) {
++ dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__,
++ read_bytes, len, s->bufsize);
++ s->chr->write_blocked = true;
++ /* We'll get passed in the unconsumed data with the next call */
++ s->datalen = 0;
++ }
++ return read_bytes;
+ }
+
+ static void spice_chr_close(struct CharDriverState *chr)
+@@ -225,6 +255,7 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
+ chr->chr_close = spice_chr_close;
+ chr->chr_guest_open = spice_chr_guest_open;
+ chr->chr_guest_close = spice_chr_guest_close;
++ s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s);
+
+ #if SPICE_SERVER_VERSION < 0x000901
+ /* See comment in vmc_state() */
+--
+1.7.7.5
+
diff --git a/0115-spice-qemu-char.c-remove-intermediate-buffer.patch b/0115-spice-qemu-char.c-remove-intermediate-buffer.patch
new file mode 100644
index 0000000..2ec2e2f
--- /dev/null
+++ b/0115-spice-qemu-char.c-remove-intermediate-buffer.patch
@@ -0,0 +1,71 @@
+From 9d965c99311c6f3d5c7ba9b66a72398814175865 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Tue, 22 Mar 2011 12:28:00 +0200
+Subject: [PATCH 115/118] spice-qemu-char.c: remove intermediate buffer
+
+BZ: 672191
+upstream: not submitted (explained below)
+
+virtio-serial's buffer is valid when it calls us, and we don't
+access it otherwise: vmc_read is only called in response to wakeup,
+or else we set datalen=0 and throttle. Then vmc_read is called back,
+we return 0 (not accessing the buffer) and set the timer to unthrottle.
+
+Also make datalen int and not ssize_t (to fit spice_chr_write signature).
+
+This relied on the previous patch that introduces throttling, which
+can't go upstream right now as explained in that patch.
+---
+ spice-qemu-char.c | 18 ++++++------------
+ 1 files changed, 6 insertions(+), 12 deletions(-)
+
+diff --git a/spice-qemu-char.c b/spice-qemu-char.c
+index eeeb32e..70a83bf 100644
+--- a/spice-qemu-char.c
++++ b/spice-qemu-char.c
+@@ -23,9 +23,8 @@ typedef struct SpiceCharDriver {
+ SpiceCharDeviceInstance sin;
+ char *subtype;
+ bool active;
+- uint8_t *buffer;
+- uint8_t *datapos;
+- ssize_t bufsize, datalen;
++ const uint8_t *datapos;
++ int datalen;
+ uint32_t debug;
+ QEMUTimer *unblock_timer;
+ } SpiceCharDriver;
+@@ -69,7 +68,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
+ SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
+ int bytes = MIN(len, scd->datalen);
+
+- dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
++ dprintf(scd, 2, "%s: %p %d/%d/%d\n", __func__, scd->datapos, len, bytes, scd->datalen);
+ if (bytes > 0) {
+ memcpy(buf, scd->datapos, bytes);
+ scd->datapos += bytes;
+@@ -161,18 +160,13 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ dprintf(s, 2, "%s: %d\n", __func__, len);
+ vmc_register_interface(s);
+ assert(s->datalen == 0);
+- if (s->bufsize < len) {
+- s->bufsize = len;
+- s->buffer = g_realloc(s->buffer, s->bufsize);
+- }
+- memcpy(s->buffer, buf, len);
+- s->datapos = s->buffer;
++ s->datapos = buf;
+ s->datalen = len;
+ spice_server_char_device_wakeup(&s->sin);
+ read_bytes = len - s->datalen;
+ if (read_bytes != len) {
+- dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__,
+- read_bytes, len, s->bufsize);
++ dprintf(s, 1, "%s: throttling: %d < %d\n", __func__,
++ read_bytes, len);
+ s->chr->write_blocked = true;
+ /* We'll get passed in the unconsumed data with the next call */
+ s->datalen = 0;
+--
+1.7.7.5
+
diff --git a/0116-usb-redir-Add-flow-control-support.patch b/0116-usb-redir-Add-flow-control-support.patch
new file mode 100644
index 0000000..94d10ef
--- /dev/null
+++ b/0116-usb-redir-Add-flow-control-support.patch
@@ -0,0 +1,65 @@
+From 80aafc63c842ee902cc9e32d692efed8952a1e14 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Tue, 19 Jul 2011 10:56:19 +0200
+Subject: [PATCH 116/118] usb-redir: Add flow control support
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c | 26 ++++++++++++++++++++++++--
+ 1 files changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index e421cff..1289506 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -228,12 +228,22 @@ static int usbredir_read(void *priv, uint8_t *data, int count)
+ static int usbredir_write(void *priv, uint8_t *data, int count)
+ {
+ USBRedirDevice *dev = priv;
++ int r;
+
+- if (!dev->cs->opened) {
++ if (!dev->cs->opened || dev->cs->write_blocked) {
+ return 0;
+ }
+
+- return qemu_chr_fe_write(dev->cs, data, count);
++ r = qemu_chr_fe_write(dev->cs, data, count);
++
++ if (r < 0) {
++ if (dev->cs->write_blocked) {
++ return 0;
++ }
++ return -1;
++ }
++
++ return r;
+ }
+
+ /*
+@@ -865,10 +875,22 @@ static void usbredir_chardev_event(void *opaque, int event)
+ }
+ }
+
++static void usbredir_chardev_write_unblocked(void *opaque)
++{
++ USBRedirDevice *dev = opaque;
++
++ if (dev->parser == NULL) {
++ /* usbredir_open_close_bh hasn't handled the open event yet */
++ return;
++ }
++ usbredirparser_do_write(dev->parser);
++}
++
+ static const QemuChrHandlers usbredir_chr_handlers = {
+ .fd_can_read = usbredir_chardev_can_read,
+ .fd_read = usbredir_chardev_read,
+ .fd_event = usbredir_chardev_event,
++ .fd_write_unblocked = usbredir_chardev_write_unblocked,
+ };
+
+ /*
+--
+1.7.7.5
+
diff --git a/0117-virtio-serial-bus-replay-guest_open-on-migration.patch b/0117-virtio-serial-bus-replay-guest_open-on-migration.patch
new file mode 100644
index 0000000..2e76feb
--- /dev/null
+++ b/0117-virtio-serial-bus-replay-guest_open-on-migration.patch
@@ -0,0 +1,50 @@
+From 8e92fe9feebc319c019feb8c28941e322524932f Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Thu, 28 Jul 2011 15:08:48 +0300
+Subject: [PATCH 117/118] virtio-serial-bus: replay guest_open on migration
+
+When migrating a host with with a spice agent running the mouse becomes
+non operational after the migration. This is rhbz #725965.
+
+The problem is that after migration spice doesn't know the guest agent is open.
+Spice is just a char dev here. And a chardev cannot query it's device, the
+device has to let the chardev know when it is open. Right now after migration
+the chardev which is recreated is in it's default state, which assumes the
+guest is disconnected.
+
+Char devices carry no information across migration, but the virtio-serial does
+already carry the guest_connected state. This patch passes that bit to the
+chardev.
+
+Signed-off-by: Alon Levy <alevy at redhat.com>
+---
+ hw/virtio-serial-bus.c | 6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
+index a4825b9..e5f343f 100644
+--- a/hw/virtio-serial-bus.c
++++ b/hw/virtio-serial-bus.c
+@@ -618,6 +618,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+ for (i = 0; i < nr_active_ports; i++) {
+ uint32_t id;
+ bool host_connected;
++ VirtIOSerialPortInfo *info;
+
+ id = qemu_get_be32(f);
+ port = find_port_by_id(s, id);
+@@ -626,6 +627,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+ }
+
+ port->guest_connected = qemu_get_byte(f);
++ info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
++ if (port->guest_connected && info->guest_open) {
++ /* replay guest open */
++ info->guest_open(port);
++ }
+ host_connected = qemu_get_byte(f);
+ if (host_connected != port->host_connected) {
+ /*
+--
+1.7.7.5
+
diff --git a/0118-char-Disable-write-callback-if-throttled-chardev-is-.patch b/0118-char-Disable-write-callback-if-throttled-chardev-is-.patch
new file mode 100644
index 0000000..757fb21
--- /dev/null
+++ b/0118-char-Disable-write-callback-if-throttled-chardev-is-.patch
@@ -0,0 +1,36 @@
+From fad276489cbc04f228d52b7019bee9e7a88c8a86 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah at redhat.com>
+Date: Fri, 2 Dec 2011 15:42:55 +0530
+Subject: [PATCH 118/118] char: Disable write callback if throttled chardev is
+ detached
+
+If a throttled chardev is detached from the frontend device, all future
+callbacks should be suppressed. Not doing this results in a segfault.
+
+Bugzilla: 745758
+Upstream: Not applicable, since throttling is a RHEL6-only feature.
+
+Signed-off-by: Amit Shah <amit.shah at redhat.com>
+---
+ qemu-char.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/qemu-char.c b/qemu-char.c
+index 5f67652..5a94919 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -220,6 +220,11 @@ void qemu_chr_add_handlers(CharDriverState *s,
+ ++s->avail_connections;
+ }
+ if (!handlers) {
++ if (s->write_blocked) {
++ /* Ensure we disable the callback if we were throttled */
++ s->chr_disable_write_fd_handler(s);
++ /* s->write_blocked is cleared below */
++ }
+ handlers = &null_handlers;
+ }
+ s->chr_can_read = handlers->fd_can_read;
+--
+1.7.7.5
+
diff --git a/qemu.spec b/qemu.spec
index 7d510e0..30a5f71 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1,7 +1,7 @@
Summary: QEMU is a FAST! processor emulator
Name: qemu
Version: 1.0
-Release: 1%{?dist}
+Release: 2%{?dist}
# Epoch because we pushed a qemu-1.0 package
Epoch: 2
License: GPLv2+ and LGPLv2+ and BSD
@@ -66,6 +66,26 @@ Patch24: 0024-Documentation-Add-qemu-img-t-parameter-in-man-page.patch
Patch25: 0025-rbd-always-set-out-parameter-in-qemu_rbd_snap_list.patch
Patch26: virtio-blk_refuse_SG_IO_requests_with_scsi_off.patch
+# USB Redirect patches should go upstream soon!
+Patch101: 0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch
+Patch102: 0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch
+Patch103: 0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch
+Patch104: 0104-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch
+Patch105: 0105-usb-redir-Improve-some-debugging-messages.patch
+Patch106: 0106-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch
+Patch107: 0107-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch
+Patch108: 0108-iohandlers-Add-enable-disable_write_fd_handler-funct.patch
+Patch109: 0109-char-Add-framework-for-a-write-unblocked-callback.patch
+Patch110: 0110-char-Update-send_all-to-handle-nonblocking-chardev-w.patch
+Patch111: 0111-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch
+Patch112: 0112-char-Throttle-when-host-connection-is-down.patch
+Patch113: 0113-virtio-console-Enable-port-throttling-when-chardev-i.patch
+Patch114: 0114-spice-qemu-char.c-add-throttling.patch
+Patch115: 0115-spice-qemu-char.c-remove-intermediate-buffer.patch
+Patch116: 0116-usb-redir-Add-flow-control-support.patch
+Patch117: 0117-virtio-serial-bus-replay-guest_open-on-migration.patch
+Patch118: 0118-char-Disable-write-callback-if-throttled-chardev-is-.patch
+
# General bug fixes
Patch201: Fix_save-restore_of_in-kernel_i8259.patch
@@ -314,6 +334,25 @@ such as kvm_stat.
%patch25 -p1
%patch26 -p1
+%patch101 -p1
+%patch102 -p1
+%patch103 -p1
+%patch104 -p1
+%patch105 -p1
+%patch106 -p1
+%patch107 -p1
+%patch108 -p1
+%patch109 -p1
+%patch110 -p1
+%patch111 -p1
+%patch112 -p1
+%patch113 -p1
+%patch114 -p1
+%patch115 -p1
+%patch116 -p1
+%patch117 -p1
+%patch118 -p1
+
%patch201 -p1
%build
@@ -601,7 +640,6 @@ fi
%{_datadir}/systemtap/tapset/qemu-i386.stp
%{_datadir}/systemtap/tapset/qemu-x86_64.stp
%if !%{with_x86only}
-%{_datadir}/%{name}/palcode-clipper
%{_datadir}/systemtap/tapset/qemu-alpha.stp
%{_datadir}/systemtap/tapset/qemu-arm.stp
%{_datadir}/systemtap/tapset/qemu-armeb.stp
@@ -694,6 +732,10 @@ fi
%{_mandir}/man1/qemu-img.1*
%changelog
+* Fri Jan 13 2012 Justin M. Forbes <jforbes at redhat.com> - 2:1.0-2
+- Add patches for USB redirect bits
+- Remove palcode-clipper, we don't build it
+
* Wed Jan 11 2012 Justin M. Forbes <jforbes at redhat.com> - 2:1.0-1
- Add patches from 1.0.1 queue
More information about the scm-commits
mailing list