From bd9bdce694ccb76facc882363e4c337e8a88c918 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 25 Nov 2007 00:55:06 +0000 Subject: [PATCH] Add input buffer to mux chr (patch by Tristan Gingold). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3735 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mcf_uart.c | 1 + hw/pl011.c | 1 + hw/serial.c | 1 + hw/slavio_serial.c | 1 + qemu-char.h | 2 ++ vl.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 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; }