aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/mcf_uart.c1
-rw-r--r--hw/pl011.c1
-rw-r--r--hw/serial.c1
-rw-r--r--hw/slavio_serial.c1
-rw-r--r--qemu-char.h2
-rw-r--r--vl.c43
6 files changed, 46 insertions, 3 deletions
diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
index 01973a02fd..a65cc772c2 100644
--- a/hw/mcf_uart.c
+++ b/hw/mcf_uart.c
@@ -88,6 +88,7 @@ uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
if (s->fifo_len == 0)
s->sr &= ~MCF_UART_RxRDY;
mcf_uart_update(s);
+ qemu_chr_accept_input(s->chr);
return val;
}
case 0x10:
diff --git a/hw/pl011.c b/hw/pl011.c
index 91c52cc318..9d8c6a3f58 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -78,6 +78,7 @@ static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
if (s->read_count == s->read_trigger - 1)
s->int_level &= ~ PL011_INT_RX;
pl011_update(s);
+ qemu_chr_accept_input(s->chr);
return c;
case 1: /* UARTCR */
return 0;
diff --git a/hw/serial.c b/hw/serial.c
index c5d9db5fa2..b1bd0ff36c 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -223,6 +223,7 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
ret = s->rbr;
s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
serial_update_irq(s);
+ qemu_chr_accept_input(s->chr);
}
break;
case 1:
diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c
index 534a438a19..9a8e340153 100644
--- a/hw/slavio_serial.c
+++ b/hw/slavio_serial.c
@@ -475,6 +475,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
else
ret = s->rx;
SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
+ qemu_chr_accept_input(s->chr);
return ret;
default:
break;
diff --git a/qemu-char.h b/qemu-char.h
index 5a36a36831..29de03df58 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -40,6 +40,7 @@ struct CharDriverState {
void *handler_opaque;
void (*chr_send_event)(struct CharDriverState *chr, int event);
void (*chr_close)(struct CharDriverState *chr);
+ void (*chr_accept_input)(struct CharDriverState *chr);
void *opaque;
int focus;
QEMUBH *bh;
@@ -59,6 +60,7 @@ int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
void qemu_chr_reset(CharDriverState *s);
int qemu_chr_can_read(CharDriverState *s);
void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
+void qemu_chr_accept_input(CharDriverState *s);
/* async I/O support */
diff --git a/vl.c b/vl.c
index d362536470..2ed7aecffb 100644
--- a/vl.c
+++ b/vl.c
@@ -1594,6 +1594,11 @@ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
s->chr_read(s->handler_opaque, buf, len);
}
+void qemu_chr_accept_input(CharDriverState *s)
+{
+ if (s->chr_accept_input)
+ s->chr_accept_input(s);
+}
void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
{
@@ -1645,12 +1650,17 @@ static CharDriverState *qemu_chr_open_null(void)
static int term_timestamps;
static int64_t term_timestamps_start;
#define MAX_MUX 4
+#define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */
+#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
typedef struct {
IOCanRWHandler *chr_can_read[MAX_MUX];
IOReadHandler *chr_read[MAX_MUX];
IOEventHandler *chr_event[MAX_MUX];
void *ext_opaque[MAX_MUX];
CharDriverState *drv;
+ unsigned char buffer[MUX_BUFFER_SIZE];
+ int prod;
+ int cons;
int mux_cnt;
int term_got_escape;
int max_size;
@@ -1779,12 +1789,28 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
return 0;
}
+static void mux_chr_accept_input(CharDriverState *chr)
+{
+ int m = chr->focus;
+ MuxDriver *d = chr->opaque;
+
+ while (d->prod != d->cons &&
+ d->chr_can_read[m] &&
+ d->chr_can_read[m](d->ext_opaque[m])) {
+ d->chr_read[m](d->ext_opaque[m],
+ &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1);
+ }
+}
+
static int mux_chr_can_read(void *opaque)
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
+
+ if ((d->prod - d->cons) < MUX_BUFFER_SIZE)
+ return 1;
if (d->chr_can_read[chr->focus])
- return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
+ return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
return 0;
}
@@ -1792,10 +1818,20 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
+ int m = chr->focus;
int i;
+
+ mux_chr_accept_input (opaque);
+
for(i = 0; i < size; i++)
- if (mux_proc_byte(chr, d, buf[i]))
- d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1);
+ if (mux_proc_byte(chr, d, buf[i])) {
+ if (d->prod == d->cons &&
+ d->chr_can_read[m] &&
+ d->chr_can_read[m](d->ext_opaque[m]))
+ d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
+ else
+ d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i];
+ }
}
static void mux_chr_event(void *opaque, int event)
@@ -1850,6 +1886,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
chr->focus = -1;
chr->chr_write = mux_chr_write;
chr->chr_update_read_handler = mux_chr_update_read_handler;
+ chr->chr_accept_input = mux_chr_accept_input;
return chr;
}