From b8261205bf776d7f180c70626666434fadb21dc4 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 10 Jan 2011 21:12:03 +0200 Subject: [PATCH] kvm: Support for more than one serial ttys Signed-off-by: Pekka Enberg --- tools/kvm/8250-serial.c | 114 +++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 37 deletions(-) diff --git a/tools/kvm/8250-serial.c b/tools/kvm/8250-serial.c index 6046c6b14dcc..f5e66a601785 100644 --- a/tools/kvm/8250-serial.c +++ b/tools/kvm/8250-serial.c @@ -25,11 +25,14 @@ struct serial8250_device { uint8_t scr; }; -static struct serial8250_device device = { - .iobase = 0x3f8, /* ttyS0 */ - .irq = 4, - - .lsr = UART_LSR_TEMT | UART_LSR_THRE, +static struct serial8250_device devices[1] = { + /* ttyS0 */ + [0] = { + .iobase = 0x3f8, + .irq = 4, + + .lsr = UART_LSR_TEMT | UART_LSR_THRE, + }, }; static int read_char(int fd) @@ -52,59 +55,83 @@ static bool is_readable(int fd) return poll(&pollfd, 1, 0) > 0; } +/* + * Interrupts are injected for ttyS0 only. + */ void serial8250__interrupt(struct kvm *self) { + struct serial8250_device *dev = &devices[0]; uint8_t new_iir; - device.iir = UART_IIR_NO_INT; + dev->iir = UART_IIR_NO_INT; /* No interrupts enabled. Exit... */ - if (!(device.ier & (UART_IER_THRI|UART_IER_RDI))) + if (!(dev->ier & (UART_IER_THRI|UART_IER_RDI))) return; new_iir = 0; /* We're always good for guest sending data. */ - if (device.ier & UART_IER_THRI) + if (dev->ier & UART_IER_THRI) new_iir |= UART_IIR_THRI; /* Is there input in stdin to send to the guest? */ - if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { + if (!(dev->lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { int c; c = read_char(fileno(stdin)); if (c >= 0) { - device.thr = c; - device.lsr |= UART_LSR_DR; + dev->thr = c; + dev->lsr |= UART_LSR_DR; new_iir |= UART_IIR_RDI; } } /* Only send an IRQ if there's work to do. */ if (new_iir) { - device.iir = new_iir; - kvm__irq_line(self, device.irq, 0); - kvm__irq_line(self, device.irq, 1); + dev->iir = new_iir; + kvm__irq_line(self, dev->irq, 0); + kvm__irq_line(self, dev->irq, 1); + } +} + +static struct serial8250_device *find_device(uint16_t port) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(devices); i++) { + struct serial8250_device *dev = &devices[i]; + + if (dev->iobase == (port & ~0x7)) + return dev; } + return NULL; } static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) { - uint16_t offset = port - device.iobase; + struct serial8250_device *dev; + uint16_t offset; + + dev = find_device(port); + if (!dev) + return false; + + offset = port - dev->iobase; - if (device.lcr & UART_LCR_DLAB) { + if (dev->lcr & UART_LCR_DLAB) { switch (offset) { case UART_DLL: - device.dll = ioport__read8(data); + dev->dll = ioport__read8(data); break; case UART_DLM: - device.dlm = ioport__read8(data); + dev->dlm = ioport__read8(data); break; case UART_FCR: - device.fcr = ioport__read8(data); + dev->fcr = ioport__read8(data); break; case UART_LCR: - device.lcr = ioport__read8(data); + dev->lcr = ioport__read8(data); break; default: return false; @@ -124,19 +151,19 @@ static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size break; } case UART_IER: - device.ier = ioport__read8(data); + dev->ier = ioport__read8(data); break; case UART_FCR: - device.fcr = ioport__read8(data); + dev->fcr = ioport__read8(data); break; case UART_LCR: - device.lcr = ioport__read8(data); + dev->lcr = ioport__read8(data); break; case UART_MCR: - device.mcr = ioport__read8(data); + dev->mcr = ioport__read8(data); break; case UART_SCR: - device.scr = ioport__read8(data); + dev->scr = ioport__read8(data); break; default: return false; @@ -148,38 +175,45 @@ static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) { - uint16_t offset = port - device.iobase; + struct serial8250_device *dev; + uint16_t offset; + + dev = find_device(port); + if (!dev) + return false; - if (device.lcr & UART_LCR_DLAB) + offset = port - dev->iobase; + + if (dev->lcr & UART_LCR_DLAB) return false; switch (offset) { case UART_TX: - if (device.lsr & UART_LSR_DR) { - device.lsr &= ~UART_LSR_DR; - ioport__write8(data, device.thr); + if (dev->lsr & UART_LSR_DR) { + dev->lsr &= ~UART_LSR_DR; + ioport__write8(data, dev->thr); } break; case UART_IER: - ioport__write8(data, device.ier); + ioport__write8(data, dev->ier); break; case UART_IIR: - ioport__write8(data, device.iir); + ioport__write8(data, dev->iir); break; case UART_LCR: - ioport__write8(data, device.lcr); + ioport__write8(data, dev->lcr); break; case UART_MCR: - ioport__write8(data, device.mcr); + ioport__write8(data, dev->mcr); break; case UART_LSR: - ioport__write8(data, device.lsr); + ioport__write8(data, dev->lsr); break; case UART_MSR: ioport__write8(data, UART_MSR_CTS); break; case UART_SCR: - ioport__write8(data, device.scr); + ioport__write8(data, dev->scr); break; default: return false; @@ -195,5 +229,11 @@ static struct ioport_operations serial8250_ops = { void serial8250__init(void) { - ioport__register(device.iobase, &serial8250_ops, 8); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(devices); i++) { + struct serial8250_device *dev = &devices[i]; + + ioport__register(dev->iobase, &serial8250_ops, 8); + } } -- 2.39.5