Merge remote-tracking branch 'bonzini/scsi-next' into staging
# By Paolo Bonzini (4) and Peter Lieven (2)
# Via Paolo Bonzini
* bonzini/scsi-next:
scsi-disk: handle io_canceled uniformly and correctly
scsi-disk: do not complete canceled UNMAP requests
scsi: do not call scsi_read_data/scsi_write_data for a canceled request
iscsi: look for pkg-config file too
iscsi: add iscsi_truncate support
iscsi: retry read, write, flush and unmap on unit attention check conditions
diff --git a/hw/baum.c b/hw/baum.c
index 09dcb9c..d8919d5 100644
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -25,7 +25,6 @@
#include "char/char.h"
#include "qemu/timer.h"
#include "usb.h"
-#include "baum.h"
#include <brlapi.h>
#include <brlapi_constants.h>
#include <brlapi_keycodes.h>
@@ -562,7 +561,7 @@
g_free(baum);
}
-CharDriverState *chr_baum_init(QemuOpts *opts)
+static CharDriverState *chr_baum_init(QemuOpts *opts)
{
BaumDriverState *baum;
CharDriverState *chr;
@@ -625,3 +624,10 @@
g_free(baum);
return NULL;
}
+
+static void register_types(void)
+{
+ register_char_driver("braille", chr_baum_init);
+}
+
+type_init(register_types);
diff --git a/hw/baum.h b/hw/baum.h
deleted file mode 100644
index 7635884..0000000
--- a/hw/baum.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * QEMU Baum
- *
- * Copyright (c) 2008 Samuel Thibault
- *
- * 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 HW_BAUM_H
-#define HW_BAUM_H 1
-
-/* char device */
-CharDriverState *chr_baum_init(QemuOpts *opts);
-
-#endif
diff --git a/hw/msmouse.c b/hw/msmouse.c
index ef47aed..407ec87 100644
--- a/hw/msmouse.c
+++ b/hw/msmouse.c
@@ -25,7 +25,6 @@
#include "qemu-common.h"
#include "char/char.h"
#include "ui/console.h"
-#include "msmouse.h"
#define MSMOUSE_LO6(n) ((n) & 0x3f)
#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
@@ -64,7 +63,7 @@
g_free (chr);
}
-CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
{
CharDriverState *chr;
@@ -76,3 +75,10 @@
return chr;
}
+
+static void register_types(void)
+{
+ register_char_driver("msmouse", qemu_chr_open_msmouse);
+}
+
+type_init(register_types);
diff --git a/hw/msmouse.h b/hw/msmouse.h
deleted file mode 100644
index 8cff3a7..0000000
--- a/hw/msmouse.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef HW_MSMOUSE_H
-#define HW_MSMOUSE_H 1
-
-/* msmouse.c */
-CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts);
-
-#endif
diff --git a/hw/nand.c b/hw/nand.c
index 4a71265..61e918f 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -46,7 +46,7 @@
# define NAND_IOSTATUS_PLANE1 (1 << 2)
# define NAND_IOSTATUS_PLANE2 (1 << 3)
# define NAND_IOSTATUS_PLANE3 (1 << 4)
-# define NAND_IOSTATUS_BUSY (1 << 6)
+# define NAND_IOSTATUS_READY (1 << 6)
# define NAND_IOSTATUS_UNPROTCT (1 << 7)
# define MAX_PAGE 0x800
@@ -231,6 +231,7 @@
s->iolen = 0;
s->offset = 0;
s->status &= NAND_IOSTATUS_UNPROTCT;
+ s->status |= NAND_IOSTATUS_READY;
}
static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
diff --git a/hw/serial.c b/hw/serial.c
index f0ce9b0..eb38f22 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -256,16 +256,17 @@
qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
}
-static void serial_xmit(void *opaque)
+static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
{
SerialState *s = opaque;
- uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
if (s->tsr_retry <= 0) {
if (s->fcr & UART_FCR_FE) {
s->tsr = fifo_get(s,XMIT_FIFO);
if (!s->xmit_fifo.count)
s->lsr |= UART_LSR_THRE;
+ } else if ((s->lsr & UART_LSR_THRE)) {
+ return FALSE;
} else {
s->tsr = s->thr;
s->lsr |= UART_LSR_THRE;
@@ -277,30 +278,25 @@
/* in loopback mode, say that we just received a char */
serial_receive1(s, &s->tsr, 1);
} else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) {
- if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) {
+ if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY &&
+ qemu_chr_fe_add_watch(s->chr, G_IO_OUT, serial_xmit, s) > 0) {
s->tsr_retry++;
- qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time);
- return;
- } else if (s->poll_msl < 0) {
- /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then
- drop any further failed writes instantly, until we get one that goes through.
- This is to prevent guests that log to unconnected pipes or pty's from stalling. */
- s->tsr_retry = -1;
+ return FALSE;
}
- }
- else {
+ s->tsr_retry = 0;
+ } else {
s->tsr_retry = 0;
}
s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
- if (!(s->lsr & UART_LSR_THRE))
- qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time);
if (s->lsr & UART_LSR_THRE) {
s->lsr |= UART_LSR_TEMT;
s->thr_ipending = 1;
serial_update_irq(s);
}
+
+ return FALSE;
}
@@ -330,7 +326,7 @@
s->lsr &= ~UART_LSR_THRE;
serial_update_irq(s);
}
- serial_xmit(s);
+ serial_xmit(NULL, G_IO_OUT, s);
}
break;
case 1:
@@ -684,8 +680,6 @@
s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s);
s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s);
- s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s);
-
qemu_register_reset(serial_reset, s);
qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
diff --git a/hw/serial.h b/hw/serial.h
index 98ee424..e57375d 100644
--- a/hw/serial.h
+++ b/hw/serial.h
@@ -72,8 +72,6 @@
struct QEMUTimer *fifo_timeout_timer;
int timeout_ipending; /* timeout interrupt pending state */
- struct QEMUTimer *transmit_timer;
-
uint64_t char_transmit_time; /* time to transmit a char in ticks */
int poll_msl;
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 46072a0..194de64 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -20,6 +20,18 @@
CharDriverState *chr;
} VirtConsole;
+/*
+ * Callback function that's called from chardevs when backend becomes
+ * writable.
+ */
+static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
+ void *opaque)
+{
+ VirtConsole *vcon = opaque;
+
+ virtio_serial_throttle_port(&vcon->port, false);
+ return 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)
@@ -35,19 +47,21 @@
ret = qemu_chr_fe_write(vcon->chr, buf, len);
trace_virtio_console_flush_buf(port->id, len, ret);
- if (ret < 0) {
+ if (ret <= 0) {
+ VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+
/*
* Ideally we'd get a better error code than just -1, but
* that's what the chardev interface gives us right now. If
* we had a finer-grained message, like -EPIPE, we could close
- * this connection. Absent such error messages, the most we
- * can do is to return 0 here.
- *
- * This will prevent stray -1 values to go to
- * virtio-serial-bus.c and cause abort()s in
- * do_flush_queued_data().
+ * this connection.
*/
ret = 0;
+ if (!k->is_console) {
+ virtio_serial_throttle_port(port, true);
+ qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked,
+ vcon);
+ }
}
return ret;
}
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index aa7d0d7..f76c505 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -172,24 +172,7 @@
port->elem.out_sg[i].iov_base
+ port->iov_offset,
buf_size);
- if (ret < 0 && ret != -EAGAIN) {
- /* We don't handle any other type of errors here */
- abort();
- }
- if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) {
- /*
- * this is a temporary check until chardevs can signal to
- * frontends that they are writable again. This prevents
- * the console from going into throttled mode (forever)
- * if virtio-console is connected to a pty without a
- * listener. Otherwise the guest spins forever.
- * We can revert this if
- * 1: chardevs can notify frondends
- * 2: the guest driver does not spin in these cases
- */
- if (!vsc->is_console) {
- virtio_serial_throttle_port(port, true);
- }
+ if (port->throttled) {
port->iov_idx = i;
if (ret > 0) {
port->iov_offset += ret;
diff --git a/include/char/char.h b/include/char/char.h
index c91ce3c..2e24270 100644
--- a/include/char/char.h
+++ b/include/char/char.h
@@ -56,6 +56,7 @@
struct CharDriverState {
void (*init)(struct CharDriverState *s);
int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
+ GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond);
void (*chr_update_read_handler)(struct CharDriverState *s);
int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
int (*get_msgfd)(struct CharDriverState *s);
@@ -70,7 +71,7 @@
void (*chr_guest_open)(struct CharDriverState *chr);
void (*chr_guest_close)(struct CharDriverState *chr);
void *opaque;
- QEMUTimer *open_timer;
+ int idle_tag;
char *label;
char *filename;
int opened;
@@ -152,6 +153,9 @@
void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
GCC_FMT_ATTR(2, 3);
+guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
+ GIOFunc func, void *user_data);
+
/**
* @qemu_chr_fe_write:
*
@@ -240,6 +244,8 @@
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
+void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *));
+
/* add an eventfd to the qemu devices that are polled */
CharDriverState *qemu_chr_open_eventfd(int eventfd);
diff --git a/qemu-char.c b/qemu-char.c
index 36295b1..04aa589 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -28,8 +28,6 @@
#include "qemu/timer.h"
#include "char/char.h"
#include "hw/usb.h"
-#include "hw/baum.h"
-#include "hw/msmouse.h"
#include "qmp-commands.h"
#include <unistd.h>
@@ -122,20 +120,18 @@
s->chr_event(s->handler_opaque, event);
}
-static void qemu_chr_fire_open_event(void *opaque)
+static gboolean qemu_chr_generic_open_bh(gpointer opaque)
{
CharDriverState *s = opaque;
qemu_chr_be_event(s, CHR_EVENT_OPENED);
- qemu_free_timer(s->open_timer);
- s->open_timer = NULL;
+ s->idle_tag = 0;
+ return FALSE;
}
void qemu_chr_generic_open(CharDriverState *s)
{
- if (s->open_timer == NULL) {
- s->open_timer = qemu_new_timer_ms(rt_clock,
- qemu_chr_fire_open_event, s);
- qemu_mod_timer(s->open_timer, qemu_get_clock_ms(rt_clock) - 1);
+ if (s->idle_tag == 0) {
+ s->idle_tag = g_idle_add(qemu_chr_generic_open_bh, s);
}
}
@@ -539,21 +535,215 @@
}
#endif /* !_WIN32 */
-#define STDIO_MAX_CLIENTS 1
-static int stdio_nb_clients;
+typedef struct IOWatchPoll
+{
+ GSource *src;
+ int max_size;
+
+ IOCanReadHandler *fd_can_read;
+ void *opaque;
+
+ QTAILQ_ENTRY(IOWatchPoll) node;
+} IOWatchPoll;
+
+static QTAILQ_HEAD(, IOWatchPoll) io_watch_poll_list =
+ QTAILQ_HEAD_INITIALIZER(io_watch_poll_list);
+
+static IOWatchPoll *io_watch_poll_from_source(GSource *source)
+{
+ IOWatchPoll *i;
+
+ QTAILQ_FOREACH(i, &io_watch_poll_list, node) {
+ if (i->src == source) {
+ return i;
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
+{
+ IOWatchPoll *iwp = io_watch_poll_from_source(source);
+
+ iwp->max_size = iwp->fd_can_read(iwp->opaque);
+ if (iwp->max_size == 0) {
+ return FALSE;
+ }
+
+ return g_io_watch_funcs.prepare(source, timeout_);
+}
+
+static gboolean io_watch_poll_check(GSource *source)
+{
+ IOWatchPoll *iwp = io_watch_poll_from_source(source);
+
+ if (iwp->max_size == 0) {
+ return FALSE;
+ }
+
+ return g_io_watch_funcs.check(source);
+}
+
+static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
+ gpointer user_data)
+{
+ return g_io_watch_funcs.dispatch(source, callback, user_data);
+}
+
+static void io_watch_poll_finalize(GSource *source)
+{
+ IOWatchPoll *iwp = io_watch_poll_from_source(source);
+ QTAILQ_REMOVE(&io_watch_poll_list, iwp, node);
+ g_io_watch_funcs.finalize(source);
+}
+
+static GSourceFuncs io_watch_poll_funcs = {
+ .prepare = io_watch_poll_prepare,
+ .check = io_watch_poll_check,
+ .dispatch = io_watch_poll_dispatch,
+ .finalize = io_watch_poll_finalize,
+};
+
+/* Can only be used for read */
+static guint io_add_watch_poll(GIOChannel *channel,
+ IOCanReadHandler *fd_can_read,
+ GIOFunc fd_read,
+ gpointer user_data)
+{
+ IOWatchPoll *iwp;
+ GSource *src;
+ guint tag;
+
+ src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
+ g_source_set_funcs(src, &io_watch_poll_funcs);
+ g_source_set_callback(src, (GSourceFunc)fd_read, user_data, NULL);
+ tag = g_source_attach(src, NULL);
+ g_source_unref(src);
+
+ iwp = g_malloc0(sizeof(*iwp));
+ iwp->src = src;
+ iwp->max_size = 0;
+ iwp->fd_can_read = fd_can_read;
+ iwp->opaque = user_data;
+
+ QTAILQ_INSERT_HEAD(&io_watch_poll_list, iwp, node);
+
+ return tag;
+}
+
+#ifndef _WIN32
+static GIOChannel *io_channel_from_fd(int fd)
+{
+ GIOChannel *chan;
+
+ if (fd == -1) {
+ return NULL;
+ }
+
+ chan = g_io_channel_unix_new(fd);
+
+ g_io_channel_set_encoding(chan, NULL, NULL);
+ g_io_channel_set_buffered(chan, FALSE);
+
+ return chan;
+}
+#endif
+
+static GIOChannel *io_channel_from_socket(int fd)
+{
+ GIOChannel *chan;
+
+ if (fd == -1) {
+ return NULL;
+ }
+
+#ifdef _WIN32
+ chan = g_io_channel_win32_new_socket(fd);
+#else
+ chan = g_io_channel_unix_new(fd);
+#endif
+
+ g_io_channel_set_encoding(chan, NULL, NULL);
+ g_io_channel_set_buffered(chan, FALSE);
+
+ return chan;
+}
+
+static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1)
+{
+ GIOStatus status;
+ gsize bytes_written;
+ int len;
+ const uint8_t *buf = _buf;
+
+ len = len1;
+ while (len > 0) {
+ status = g_io_channel_write_chars(fd, (const gchar *)buf, len,
+ &bytes_written, NULL);
+ if (status != G_IO_STATUS_NORMAL) {
+ if (status == G_IO_STATUS_AGAIN) {
+ errno = EAGAIN;
+ return -1;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+ } else if (status == G_IO_STATUS_EOF) {
+ break;
+ } else {
+ buf += bytes_written;
+ len -= bytes_written;
+ }
+ }
+ return len1 - len;
+}
#ifndef _WIN32
-typedef struct {
- int fd_in, fd_out;
+typedef struct FDCharDriver {
+ CharDriverState *chr;
+ GIOChannel *fd_in, *fd_out;
+ guint fd_in_tag;
int max_size;
+ QTAILQ_ENTRY(FDCharDriver) node;
} FDCharDriver;
-
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 io_channel_send_all(s->fd_out, buf, len);
+}
+
+static gboolean fd_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
+{
+ CharDriverState *chr = opaque;
+ FDCharDriver *s = chr->opaque;
+ int len;
+ uint8_t buf[READ_BUF_LEN];
+ GIOStatus status;
+ gsize bytes_read;
+
+ len = sizeof(buf);
+ if (len > s->max_size) {
+ len = s->max_size;
+ }
+ if (len == 0) {
+ return FALSE;
+ }
+
+ status = g_io_channel_read_chars(chan, (gchar *)buf,
+ len, &bytes_read, NULL);
+ if (status == G_IO_STATUS_EOF) {
+ qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+ return FALSE;
+ }
+ if (status == G_IO_STATUS_NORMAL) {
+ qemu_chr_be_write(chr, buf, bytes_read);
+ }
+
+ return TRUE;
}
static int fd_chr_read_poll(void *opaque)
@@ -565,40 +755,22 @@
return s->max_size;
}
-static void fd_chr_read(void *opaque)
+static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond)
{
- CharDriverState *chr = opaque;
FDCharDriver *s = chr->opaque;
- int size, len;
- uint8_t buf[READ_BUF_LEN];
-
- len = sizeof(buf);
- if (len > s->max_size)
- len = s->max_size;
- if (len == 0)
- return;
- size = read(s->fd_in, buf, len);
- if (size == 0) {
- /* FD has been closed. Remove it from the active list. */
- qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
- qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
- return;
- }
- if (size > 0) {
- qemu_chr_be_write(chr, buf, size);
- }
+ return g_io_create_watch(s->fd_out, cond);
}
static void fd_chr_update_read_handler(CharDriverState *chr)
{
FDCharDriver *s = chr->opaque;
- if (s->fd_in >= 0) {
- if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
- } else {
- qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
- fd_chr_read, NULL, chr);
- }
+ if (s->fd_in_tag) {
+ g_source_remove(s->fd_in_tag);
+ }
+
+ if (s->fd_in) {
+ s->fd_in_tag = io_add_watch_poll(s->fd_in, fd_chr_read_poll, fd_chr_read, chr);
}
}
@@ -606,11 +778,16 @@
{
FDCharDriver *s = chr->opaque;
- if (s->fd_in >= 0) {
- if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
- } else {
- qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
- }
+ if (s->fd_in_tag) {
+ g_source_remove(s->fd_in_tag);
+ s->fd_in_tag = 0;
+ }
+
+ if (s->fd_in) {
+ g_io_channel_unref(s->fd_in);
+ }
+ if (s->fd_out) {
+ g_io_channel_unref(s->fd_out);
}
g_free(s);
@@ -625,9 +802,12 @@
chr = g_malloc0(sizeof(CharDriverState));
s = g_malloc0(sizeof(FDCharDriver));
- s->fd_in = fd_in;
- s->fd_out = fd_out;
+ s->fd_in = io_channel_from_fd(fd_in);
+ s->fd_out = io_channel_from_fd(fd_out);
+ fcntl(fd_out, F_SETFL, O_NONBLOCK);
+ s->chr = chr;
chr->opaque = s;
+ chr->chr_add_watch = fd_chr_add_watch;
chr->chr_write = fd_chr_write;
chr->chr_update_read_handler = fd_chr_update_read_handler;
chr->chr_close = fd_chr_close;
@@ -677,53 +857,6 @@
return qemu_chr_open_fd(fd_in, fd_out);
}
-
-/* for STDIO, we handle the case where several clients use it
- (nographic mode) */
-
-#define TERM_FIFO_MAX_SIZE 1
-
-static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
-static int term_fifo_size;
-
-static int stdio_read_poll(void *opaque)
-{
- CharDriverState *chr = opaque;
-
- /* try to flush the queue if needed */
- if (term_fifo_size != 0 && qemu_chr_be_can_write(chr) > 0) {
- qemu_chr_be_write(chr, term_fifo, 1);
- term_fifo_size = 0;
- }
- /* see if we can absorb more chars */
- if (term_fifo_size == 0)
- return 1;
- else
- return 0;
-}
-
-static void stdio_read(void *opaque)
-{
- int size;
- uint8_t buf[1];
- CharDriverState *chr = opaque;
-
- size = read(0, buf, 1);
- if (size == 0) {
- /* stdin has been closed. Remove it from the active list. */
- qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
- qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
- return;
- }
- if (size > 0) {
- if (qemu_chr_be_can_write(chr) > 0) {
- qemu_chr_be_write(chr, buf, 1);
- } else if (term_fifo_size == 0) {
- term_fifo[term_fifo_size++] = buf[0];
- }
- }
-}
-
/* init terminal so that we can grab keys */
static struct termios oldtty;
static int old_fd0_flags;
@@ -760,8 +893,6 @@
static void qemu_chr_close_stdio(struct CharDriverState *chr)
{
term_exit();
- stdio_nb_clients--;
- qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
fd_chr_close(chr);
}
@@ -769,25 +900,18 @@
{
CharDriverState *chr;
- if (stdio_nb_clients >= STDIO_MAX_CLIENTS) {
- return NULL;
- }
if (is_daemonized()) {
error_report("cannot use stdio with -daemonize");
return NULL;
}
- if (stdio_nb_clients == 0) {
- old_fd0_flags = fcntl(0, F_GETFL);
- tcgetattr (0, &oldtty);
- fcntl(0, F_SETFL, O_NONBLOCK);
- atexit(term_exit);
- }
+ old_fd0_flags = fcntl(0, F_GETFL);
+ tcgetattr (0, &oldtty);
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ atexit(term_exit);
chr = qemu_chr_open_fd(0, 1);
chr->chr_close = qemu_chr_close_stdio;
chr->chr_set_echo = qemu_chr_set_echo_stdio;
- qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
- stdio_nb_clients++;
stdio_allow_signal = qemu_opt_get_bool(opts, "signal",
display_type != DT_NOGRAPHIC);
qemu_chr_fe_set_echo(chr, false);
@@ -859,16 +983,55 @@
#define HAVE_CHARDEV_TTY 1
typedef struct {
- int fd;
+ GIOChannel *fd;
+ guint fd_tag;
int connected;
int polling;
int read_bytes;
- QEMUTimer *timer;
+ guint timer_tag;
} PtyCharDriver;
static void pty_chr_update_read_handler(CharDriverState *chr);
static void pty_chr_state(CharDriverState *chr, int connected);
+static gboolean pty_chr_timer(gpointer opaque)
+{
+ struct CharDriverState *chr = opaque;
+ PtyCharDriver *s = chr->opaque;
+
+ if (s->connected) {
+ goto out;
+ }
+ if (s->polling) {
+ /* If we arrive here without polling being cleared due
+ * read returning -EIO, then we are (re-)connected */
+ pty_chr_state(chr, 1);
+ goto out;
+ }
+
+ /* Next poll ... */
+ pty_chr_update_read_handler(chr);
+
+out:
+ return FALSE;
+}
+
+static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
+{
+ PtyCharDriver *s = chr->opaque;
+
+ if (s->timer_tag) {
+ g_source_remove(s->timer_tag);
+ s->timer_tag = 0;
+ }
+
+ if (ms == 1000) {
+ s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr);
+ } else {
+ s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr);
+ }
+}
+
static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
PtyCharDriver *s = chr->opaque;
@@ -878,7 +1041,13 @@
pty_chr_update_read_handler(chr);
return 0;
}
- return send_all(s->fd, buf, len);
+ return io_channel_send_all(s->fd, buf, len);
+}
+
+static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
+{
+ PtyCharDriver *s = chr->opaque;
+ return g_io_create_watch(s->fd, cond);
}
static int pty_chr_read_poll(void *opaque)
@@ -890,36 +1059,39 @@
return s->read_bytes;
}
-static void pty_chr_read(void *opaque)
+static gboolean pty_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
{
CharDriverState *chr = opaque;
PtyCharDriver *s = chr->opaque;
- int size, len;
+ gsize size, len;
uint8_t buf[READ_BUF_LEN];
+ GIOStatus status;
len = sizeof(buf);
if (len > s->read_bytes)
len = s->read_bytes;
if (len == 0)
- return;
- size = read(s->fd, buf, len);
- if ((size == -1 && errno == EIO) ||
- (size == 0)) {
+ return FALSE;
+ status = g_io_channel_read_chars(s->fd, (gchar *)buf, len, &size, NULL);
+ if (status != G_IO_STATUS_NORMAL) {
pty_chr_state(chr, 0);
- return;
- }
- if (size > 0) {
+ return FALSE;
+ } else {
pty_chr_state(chr, 1);
qemu_chr_be_write(chr, buf, size);
}
+ return TRUE;
}
static void pty_chr_update_read_handler(CharDriverState *chr)
{
PtyCharDriver *s = chr->opaque;
- qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
- pty_chr_read, NULL, chr);
+ if (s->fd_tag) {
+ g_source_remove(s->fd_tag);
+ }
+
+ s->fd_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, pty_chr_read, chr);
s->polling = 1;
/*
* Short timeout here: just need wait long enougth that qemu makes
@@ -929,7 +1101,7 @@
* timeout to the normal (much longer) poll interval before the
* timer triggers.
*/
- qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 10);
+ pty_chr_rearm_timer(chr, 10);
}
static void pty_chr_state(CharDriverState *chr, int connected)
@@ -937,13 +1109,14 @@
PtyCharDriver *s = chr->opaque;
if (!connected) {
- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+ g_source_remove(s->fd_tag);
+ s->fd_tag = 0;
s->connected = 0;
s->polling = 0;
/* (re-)connect poll interval for idle guests: once per second.
* We check more frequently in case the guests sends data to
* the virtual device linked to our pty. */
- qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 1000);
+ pty_chr_rearm_timer(chr, 1000);
} else {
if (!s->connected)
qemu_chr_generic_open(chr);
@@ -951,32 +1124,21 @@
}
}
-static void pty_chr_timer(void *opaque)
-{
- struct CharDriverState *chr = opaque;
- PtyCharDriver *s = chr->opaque;
-
- if (s->connected)
- return;
- if (s->polling) {
- /* If we arrive here without polling being cleared due
- * read returning -EIO, then we are (re-)connected */
- pty_chr_state(chr, 1);
- return;
- }
-
- /* Next poll ... */
- pty_chr_update_read_handler(chr);
-}
static void pty_chr_close(struct CharDriverState *chr)
{
PtyCharDriver *s = chr->opaque;
+ int fd;
- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
- close(s->fd);
- qemu_del_timer(s->timer);
- qemu_free_timer(s->timer);
+ if (s->fd_tag) {
+ g_source_remove(s->fd_tag);
+ }
+ fd = g_io_channel_unix_get_fd(s->fd);
+ g_io_channel_unref(s->fd);
+ close(fd);
+ if (s->timer_tag) {
+ g_source_remove(s->timer_tag);
+ }
g_free(s);
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
@@ -1025,9 +1187,10 @@
chr->chr_write = pty_chr_write;
chr->chr_update_read_handler = pty_chr_update_read_handler;
chr->chr_close = pty_chr_close;
+ chr->chr_add_watch = pty_chr_add_watch;
- s->fd = master_fd;
- s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr);
+ s->fd = io_channel_from_fd(master_fd);
+ s->timer_tag = 0;
return chr;
}
@@ -1155,22 +1318,24 @@
case CHR_IOCTL_SERIAL_SET_PARAMS:
{
QEMUSerialSetParams *ssp = arg;
- tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
+ tty_serial_init(g_io_channel_unix_get_fd(s->fd_in),
+ ssp->speed, ssp->parity,
ssp->data_bits, ssp->stop_bits);
}
break;
case CHR_IOCTL_SERIAL_SET_BREAK:
{
int enable = *(int *)arg;
- if (enable)
- tcsendbreak(s->fd_in, 1);
+ if (enable) {
+ tcsendbreak(g_io_channel_unix_get_fd(s->fd_in), 1);
+ }
}
break;
case CHR_IOCTL_SERIAL_GET_TIOCM:
{
int sarg = 0;
int *targ = (int *)arg;
- ioctl(s->fd_in, TIOCMGET, &sarg);
+ ioctl(g_io_channel_unix_get_fd(s->fd_in), TIOCMGET, &sarg);
*targ = 0;
if (sarg & TIOCM_CTS)
*targ |= CHR_TIOCM_CTS;
@@ -1190,7 +1355,7 @@
{
int sarg = *(int *)arg;
int targ = 0;
- ioctl(s->fd_in, TIOCMGET, &targ);
+ ioctl(g_io_channel_unix_get_fd(s->fd_in), TIOCMGET, &targ);
targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
| CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
if (sarg & CHR_TIOCM_CTS)
@@ -1205,7 +1370,7 @@
targ |= TIOCM_DTR;
if (sarg & CHR_TIOCM_RTS)
targ |= TIOCM_RTS;
- ioctl(s->fd_in, TIOCMSET, &targ);
+ ioctl(g_io_channel_unix_get_fd(s->fd_in), TIOCMSET, &targ);
}
break;
default:
@@ -1220,7 +1385,7 @@
int fd = -1;
if (s) {
- fd = s->fd_in;
+ fd = g_io_channel_unix_get_fd(s->fd_in);
}
fd_chr_close(chr);
@@ -1448,8 +1613,6 @@
#else /* _WIN32 */
-static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
-
typedef struct {
int max_size;
HANDLE hcom, hrecv, hsend;
@@ -1951,7 +2114,6 @@
g_free(chr->opaque);
g_free(chr);
- stdio_nb_clients--;
}
static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts)
@@ -1961,11 +2123,6 @@
DWORD dwMode;
int is_console = 0;
- if (stdio_nb_clients >= STDIO_MAX_CLIENTS
- || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) {
- return NULL;
- }
-
chr = g_malloc0(sizeof(CharDriverState));
stdio = g_malloc0(sizeof(WinStdioCharState));
@@ -1981,37 +2138,34 @@
chr->chr_write = win_stdio_write;
chr->chr_close = win_stdio_close;
- if (stdio_nb_clients == 0) {
- if (is_console) {
- if (qemu_add_wait_object(stdio->hStdIn,
- win_stdio_wait_func, chr)) {
- fprintf(stderr, "qemu_add_wait_object: failed\n");
- }
- } else {
- DWORD dwId;
+ if (is_console) {
+ if (qemu_add_wait_object(stdio->hStdIn,
+ win_stdio_wait_func, chr)) {
+ fprintf(stderr, "qemu_add_wait_object: failed\n");
+ }
+ } else {
+ DWORD dwId;
+
+ stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread,
+ chr, 0, &dwId);
- stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread,
- chr, 0, &dwId);
-
- if (stdio->hInputThread == INVALID_HANDLE_VALUE
- || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
- || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "cannot create stdio thread or event\n");
- exit(1);
- }
- if (qemu_add_wait_object(stdio->hInputReadyEvent,
- win_stdio_thread_wait_func, chr)) {
- fprintf(stderr, "qemu_add_wait_object: failed\n");
- }
+ if (stdio->hInputThread == INVALID_HANDLE_VALUE
+ || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
+ || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "cannot create stdio thread or event\n");
+ exit(1);
+ }
+ if (qemu_add_wait_object(stdio->hInputReadyEvent,
+ win_stdio_thread_wait_func, chr)) {
+ fprintf(stderr, "qemu_add_wait_object: failed\n");
}
}
dwMode |= ENABLE_LINE_INPUT;
- stdio_clients[stdio_nb_clients++] = chr;
- if (stdio_nb_clients == 1 && is_console) {
+ if (is_console) {
/* set the terminal in raw mode */
/* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
dwMode |= ENABLE_PROCESSED_INPUT;
@@ -2026,11 +2180,14 @@
}
#endif /* !_WIN32 */
+
/***********************************************************/
/* UDP Net console */
typedef struct {
int fd;
+ GIOChannel *chan;
+ guint tag;
uint8_t buf[READ_BUF_LEN];
int bufcnt;
int bufptr;
@@ -2040,8 +2197,17 @@
static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
NetCharDriver *s = chr->opaque;
+ gsize bytes_written;
+ GIOStatus status;
- return send(s->fd, (const void *)buf, len, 0);
+ status = g_io_channel_write_chars(s->chan, (const gchar *)buf, len, &bytes_written, NULL);
+ if (status == G_IO_STATUS_EOF) {
+ return 0;
+ } else if (status != G_IO_STATUS_NORMAL) {
+ return -1;
+ }
+
+ return bytes_written;
}
static int udp_chr_read_poll(void *opaque)
@@ -2062,17 +2228,22 @@
return s->max_size;
}
-static void udp_chr_read(void *opaque)
+static gboolean udp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
{
CharDriverState *chr = opaque;
NetCharDriver *s = chr->opaque;
+ gsize bytes_read = 0;
+ GIOStatus status;
if (s->max_size == 0)
- return;
- s->bufcnt = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0);
+ return FALSE;
+ status = g_io_channel_read_chars(s->chan, (gchar *)s->buf, sizeof(s->buf),
+ &bytes_read, NULL);
+ s->bufcnt = bytes_read;
s->bufptr = s->bufcnt;
- if (s->bufcnt <= 0)
- return;
+ if (status != G_IO_STATUS_NORMAL) {
+ return FALSE;
+ }
s->bufptr = 0;
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
@@ -2080,23 +2251,32 @@
s->bufptr++;
s->max_size = qemu_chr_be_can_write(chr);
}
+
+ return TRUE;
}
static void udp_chr_update_read_handler(CharDriverState *chr)
{
NetCharDriver *s = chr->opaque;
- if (s->fd >= 0) {
- qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
- udp_chr_read, NULL, chr);
+ if (s->tag) {
+ g_source_remove(s->tag);
+ s->tag = 0;
+ }
+
+ if (s->chan) {
+ s->tag = io_add_watch_poll(s->chan, udp_chr_read_poll, udp_chr_read, chr);
}
}
static void udp_chr_close(CharDriverState *chr)
{
NetCharDriver *s = chr->opaque;
- if (s->fd >= 0) {
- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+ if (s->tag) {
+ g_source_remove(s->tag);
+ }
+ if (s->chan) {
+ g_io_channel_unref(s->chan);
closesocket(s->fd);
}
g_free(s);
@@ -2119,6 +2299,7 @@
}
s->fd = fd;
+ s->chan = io_channel_from_socket(s->fd);
s->bufcnt = 0;
s->bufptr = 0;
chr->opaque = s;
@@ -2144,6 +2325,9 @@
/* TCP Net console */
typedef struct {
+
+ GIOChannel *chan, *listen_chan;
+ guint tag, listen_tag;
int fd, listen_fd;
int connected;
int max_size;
@@ -2153,13 +2337,13 @@
int msgfd;
} TCPCharDriver;
-static void tcp_chr_accept(void *opaque);
+static gboolean tcp_chr_accept(GIOChannel *chan, GIOCondition cond, 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);
+ return io_channel_send_all(s->chan, buf, len);
} else {
/* XXX: indicate an error ? */
return len;
@@ -2299,15 +2483,22 @@
}
#endif
-static void tcp_chr_read(void *opaque)
+static GSource *tcp_chr_add_watch(CharDriverState *chr, GIOCondition cond)
+{
+ TCPCharDriver *s = chr->opaque;
+ return g_io_create_watch(s->chan, cond);
+}
+
+static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
{
CharDriverState *chr = opaque;
TCPCharDriver *s = chr->opaque;
uint8_t buf[READ_BUF_LEN];
int len, size;
- if (!s->connected || s->max_size <= 0)
- return;
+ if (!s->connected || s->max_size <= 0) {
+ return FALSE;
+ }
len = sizeof(buf);
if (len > s->max_size)
len = s->max_size;
@@ -2315,10 +2506,13 @@
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);
+ if (s->listen_chan) {
+ s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr);
}
- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+ g_source_remove(s->tag);
+ s->tag = 0;
+ g_io_channel_unref(s->chan);
+ s->chan = NULL;
closesocket(s->fd);
s->fd = -1;
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
@@ -2328,6 +2522,8 @@
if (size > 0)
qemu_chr_be_write(chr, buf, size);
}
+
+ return TRUE;
}
#ifndef _WIN32
@@ -2343,9 +2539,8 @@
TCPCharDriver *s = chr->opaque;
s->connected = 1;
- if (s->fd >= 0) {
- qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
- tcp_chr_read, NULL, chr);
+ if (s->chan) {
+ s->tag = io_add_watch_poll(s->chan, tcp_chr_read_poll, tcp_chr_read, chr);
}
qemu_chr_generic_open(chr);
}
@@ -2375,13 +2570,15 @@
if (s->do_nodelay)
socket_set_nodelay(fd);
s->fd = fd;
- qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
+ s->chan = io_channel_from_socket(fd);
+ g_source_remove(s->listen_tag);
+ s->listen_tag = 0;
tcp_chr_connect(chr);
return 0;
}
-static void tcp_chr_accept(void *opaque)
+static gboolean tcp_chr_accept(GIOChannel *channel, GIOCondition cond, void *opaque)
{
CharDriverState *chr = opaque;
TCPCharDriver *s = chr->opaque;
@@ -2406,7 +2603,7 @@
}
fd = qemu_accept(s->listen_fd, addr, &len);
if (fd < 0 && errno != EINTR) {
- return;
+ return FALSE;
} else if (fd >= 0) {
if (s->do_telnetopt)
tcp_chr_telnet_init(fd);
@@ -2415,17 +2612,29 @@
}
if (tcp_chr_add_client(chr, fd) < 0)
close(fd);
+
+ return TRUE;
}
static void tcp_chr_close(CharDriverState *chr)
{
TCPCharDriver *s = chr->opaque;
if (s->fd >= 0) {
- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+ if (s->tag) {
+ g_source_remove(s->tag);
+ }
+ if (s->chan) {
+ g_io_channel_unref(s->chan);
+ }
closesocket(s->fd);
}
if (s->listen_fd >= 0) {
- qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
+ if (s->listen_tag) {
+ g_source_remove(s->listen_tag);
+ }
+ if (s->listen_chan) {
+ g_io_channel_unref(s->listen_chan);
+ }
closesocket(s->listen_fd);
}
g_free(s);
@@ -2488,10 +2697,12 @@
chr->chr_close = tcp_chr_close;
chr->get_msgfd = tcp_get_msgfd;
chr->chr_add_client = tcp_chr_add_client;
+ chr->chr_add_watch = tcp_chr_add_watch;
if (is_listen) {
s->listen_fd = fd;
- qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
+ s->listen_chan = io_channel_from_socket(s->listen_fd);
+ s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr);
if (is_telnet) {
s->do_telnetopt = 1;
}
@@ -2499,13 +2710,14 @@
s->connected = 1;
s->fd = fd;
socket_set_nodelay(fd);
+ s->chan = io_channel_from_socket(s->fd);
tcp_chr_connect(chr);
}
if (is_listen && is_waitconnect) {
printf("QEMU waiting for connection on: %s\n",
chr->filename);
- tcp_chr_accept(chr);
+ tcp_chr_accept(s->listen_chan, G_IO_IN, chr);
socket_set_nonblock(s->listen_fd);
}
return chr;
@@ -2966,53 +3178,31 @@
#endif
-static const struct {
+typedef struct CharDriver {
const char *name;
CharDriverState *(*open)(QemuOpts *opts);
-} backend_table[] = {
- { .name = "null", .open = qemu_chr_open_null },
- { .name = "socket", .open = qemu_chr_open_socket },
- { .name = "udp", .open = qemu_chr_open_udp },
- { .name = "msmouse", .open = qemu_chr_open_msmouse },
- { .name = "vc", .open = vc_init },
- { .name = "memory", .open = qemu_chr_open_ringbuf },
-#ifdef _WIN32
- { .name = "file", .open = qemu_chr_open_win_file_out },
- { .name = "pipe", .open = qemu_chr_open_win_pipe },
- { .name = "console", .open = qemu_chr_open_win_con },
- { .name = "serial", .open = qemu_chr_open_win },
- { .name = "stdio", .open = qemu_chr_open_win_stdio },
-#else
- { .name = "file", .open = qemu_chr_open_file_out },
- { .name = "pipe", .open = qemu_chr_open_pipe },
- { .name = "stdio", .open = qemu_chr_open_stdio },
-#endif
-#ifdef CONFIG_BRLAPI
- { .name = "braille", .open = chr_baum_init },
-#endif
-#ifdef HAVE_CHARDEV_TTY
- { .name = "tty", .open = qemu_chr_open_tty },
- { .name = "serial", .open = qemu_chr_open_tty },
- { .name = "pty", .open = qemu_chr_open_pty },
-#endif
-#ifdef HAVE_CHARDEV_PARPORT
- { .name = "parallel", .open = qemu_chr_open_pp },
- { .name = "parport", .open = qemu_chr_open_pp },
-#endif
-#ifdef CONFIG_SPICE
- { .name = "spicevmc", .open = qemu_chr_open_spice },
-#if SPICE_SERVER_VERSION >= 0x000c02
- { .name = "spiceport", .open = qemu_chr_open_spice_port },
-#endif
-#endif
-};
+} CharDriver;
+
+static GSList *backends;
+
+void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *))
+{
+ CharDriver *s;
+
+ s = g_malloc0(sizeof(*s));
+ s->name = g_strdup(name);
+ s->open = open;
+
+ backends = g_slist_append(backends, s);
+}
CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
void (*init)(struct CharDriverState *s),
Error **errp)
{
+ CharDriver *cd;
CharDriverState *chr;
- int i;
+ GSList *i;
if (qemu_opts_id(opts) == NULL) {
error_setg(errp, "chardev: no id specified");
@@ -3024,17 +3214,20 @@
qemu_opts_id(opts));
goto err;
}
- for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
- if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
+ for (i = backends; i; i = i->next) {
+ cd = i->data;
+
+ if (strcmp(cd->name, qemu_opt_get(opts, "backend")) == 0) {
break;
+ }
}
- if (i == ARRAY_SIZE(backend_table)) {
+ if (i == NULL) {
error_setg(errp, "chardev: backend \"%s\" not found",
qemu_opt_get(opts, "backend"));
- goto err;
+ return NULL;
}
- chr = backend_table[i].open(opts);
+ chr = cd->open(opts);
if (!chr) {
error_setg(errp, "chardev: opening backend \"%s\" failed",
qemu_opt_get(opts, "backend"));
@@ -3114,6 +3307,24 @@
}
}
+guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
+ GIOFunc func, void *user_data)
+{
+ GSource *src;
+ guint tag;
+
+ if (s->chr_add_watch == NULL) {
+ return -ENOSYS;
+ }
+
+ src = s->chr_add_watch(s, cond);
+ g_source_set_callback(src, (GSourceFunc)func, user_data, NULL);
+ tag = g_source_attach(src, NULL);
+ g_source_unref(src);
+
+ return tag;
+}
+
void qemu_chr_delete(CharDriverState *chr)
{
QTAILQ_REMOVE(&chardevs, chr, next);
@@ -3448,3 +3659,33 @@
}
qemu_chr_delete(chr);
}
+
+static void register_types(void)
+{
+ register_char_driver("null", qemu_chr_open_null);
+ register_char_driver("socket", qemu_chr_open_socket);
+ register_char_driver("udp", qemu_chr_open_udp);
+ register_char_driver("memory", qemu_chr_open_ringbuf);
+#ifdef _WIN32
+ register_char_driver("file", qemu_chr_open_win_file_out);
+ register_char_driver("pipe", qemu_chr_open_win_pipe);
+ register_char_driver("console", qemu_chr_open_win_con);
+ register_char_driver("serial", qemu_chr_open_win);
+ register_char_driver("stdio", qemu_chr_open_win_stdio);
+#else
+ register_char_driver("file", qemu_chr_open_file_out);
+ register_char_driver("pipe", qemu_chr_open_pipe);
+ register_char_driver("stdio", qemu_chr_open_stdio);
+#endif
+#ifdef HAVE_CHARDEV_TTY
+ register_char_driver("tty", qemu_chr_open_tty);
+ register_char_driver("serial", qemu_chr_open_tty);
+ register_char_driver("pty", qemu_chr_open_pty);
+#endif
+#ifdef HAVE_CHARDEV_PARPORT
+ register_char_driver("parallel", qemu_chr_open_pp);
+ register_char_driver("parport", qemu_chr_open_pp);
+#endif
+}
+
+type_init(register_types);
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index a4d7de8..aea3d24 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -307,3 +307,13 @@
}
}
#endif
+
+static void register_types(void)
+{
+ register_char_driver("spicevmc", qemu_chr_open_spice);
+#if SPICE_SERVER_VERSION >= 0x000c02
+ register_char_driver("spiceport", qemu_chr_open_spice_port);
+#endif
+}
+
+type_init(register_types);
diff --git a/ui/console.c b/ui/console.c
index 0d95f32..83a6fa3 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1739,3 +1739,10 @@
}
return pf;
}
+
+static void register_types(void)
+{
+ register_char_driver("vc", text_console_init);
+}
+
+type_init(register_types);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 1350ccc..3f12296 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -373,6 +373,10 @@
}
for (e = res; e != NULL; e = e->ai_next) {
+ if (error_is_set(errp)) {
+ error_free(*errp);
+ *errp = NULL;
+ }
if (connect_state != NULL) {
connect_state->current_addr = e;
}
diff --git a/vl.c b/vl.c
index c03edf1..5dc0558 100644
--- a/vl.c
+++ b/vl.c
@@ -119,7 +119,6 @@
#include "hw/pcmcia.h"
#include "hw/pc.h"
#include "hw/isa.h"
-#include "hw/baum.h"
#include "hw/bt.h"
#include "hw/watchdog.h"
#include "hw/smbios.h"