1899fe063SPekka Enberg #include "kvm/8250-serial.h" 213a7760fSPekka Enberg 313a7760fSPekka Enberg #include "kvm/ioport.h" 446aa8d69SPekka Enberg #include "kvm/util.h" 5e557eef9SPekka Enberg #include "kvm/kvm.h" 613a7760fSPekka Enberg 74e49b05bSCyrill Gorcunov #include <linux/serial_reg.h> 84e49b05bSCyrill Gorcunov 946aa8d69SPekka Enberg #include <stdbool.h> 1076b4a122SPekka Enberg #include <poll.h> 1113a7760fSPekka Enberg 1246aa8d69SPekka Enberg struct serial8250_device { 1346aa8d69SPekka Enberg uint16_t iobase; 14e557eef9SPekka Enberg uint8_t irq; 1576b4a122SPekka Enberg 1676b4a122SPekka Enberg uint8_t thr; 1746aa8d69SPekka Enberg uint8_t dll; 1846aa8d69SPekka Enberg uint8_t dlm; 19e557eef9SPekka Enberg uint8_t iir; 2046aa8d69SPekka Enberg uint8_t ier; 2146aa8d69SPekka Enberg uint8_t fcr; 2246aa8d69SPekka Enberg uint8_t lcr; 2346aa8d69SPekka Enberg uint8_t mcr; 2476b4a122SPekka Enberg uint8_t lsr; 2546aa8d69SPekka Enberg uint8_t scr; 2646aa8d69SPekka Enberg }; 2746aa8d69SPekka Enberg 2846aa8d69SPekka Enberg static struct serial8250_device device = { 2946aa8d69SPekka Enberg .iobase = 0x3f8, /* ttyS0 */ 30e557eef9SPekka Enberg .irq = 4, 31e557eef9SPekka Enberg 3276b4a122SPekka Enberg .iir = UART_IIR_NO_INT, 33*6d620acbSCyrill Gorcunov .lsr = UART_LSR_TEMT | UART_LSR_THRE, 3446aa8d69SPekka Enberg }; 3546aa8d69SPekka Enberg 3676b4a122SPekka Enberg static int read_char(int fd) 3776b4a122SPekka Enberg { 3876b4a122SPekka Enberg int c; 3976b4a122SPekka Enberg 4076b4a122SPekka Enberg if (read(fd, &c, 1) < 0) 4176b4a122SPekka Enberg return -1; 4276b4a122SPekka Enberg 4376b4a122SPekka Enberg return c; 4476b4a122SPekka Enberg } 4576b4a122SPekka Enberg 4676b4a122SPekka Enberg static bool is_readable(int fd) 4776b4a122SPekka Enberg { 486d54df74SCyrill Gorcunov struct pollfd pollfd = (struct pollfd) { 4976b4a122SPekka Enberg .fd = fd, 5076b4a122SPekka Enberg .events = POLLIN, 5176b4a122SPekka Enberg }; 5276b4a122SPekka Enberg 536d54df74SCyrill Gorcunov return poll(&pollfd, 1, 0) > 0; 5476b4a122SPekka Enberg } 5576b4a122SPekka Enberg 568bb34e0dSPekka Enberg void serial8250__interrupt(struct kvm *self) 578bb34e0dSPekka Enberg { 5876b4a122SPekka Enberg if (!(device.lsr & UART_LSR_DR) && is_readable(fileno(stdin))) { 5976b4a122SPekka Enberg int c; 6076b4a122SPekka Enberg 6176b4a122SPekka Enberg c = read_char(fileno(stdin)); 6276b4a122SPekka Enberg if (c >= 0) { 6376b4a122SPekka Enberg device.thr = c; 6476b4a122SPekka Enberg device.lsr |= UART_LSR_DR; 6576b4a122SPekka Enberg } 6676b4a122SPekka Enberg } 6776b4a122SPekka Enberg 6876b4a122SPekka Enberg if (device.ier & UART_IER_THRI || device.lsr & UART_LSR_DR) { 69e557eef9SPekka Enberg device.iir &= ~UART_IIR_NO_INT; 70e557eef9SPekka Enberg kvm__irq_line(self, device.irq, 1); 71e557eef9SPekka Enberg } 728bb34e0dSPekka Enberg } 738bb34e0dSPekka Enberg 7446aa8d69SPekka Enberg static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 7513a7760fSPekka Enberg { 7646aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 7746aa8d69SPekka Enberg 789a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) { 7946aa8d69SPekka Enberg switch (offset) { 804e49b05bSCyrill Gorcunov case UART_DLL: 8146aa8d69SPekka Enberg device.dll = ioport__read8(data); 8246aa8d69SPekka Enberg break; 834e49b05bSCyrill Gorcunov case UART_DLM: 8446aa8d69SPekka Enberg device.dlm = ioport__read8(data); 8546aa8d69SPekka Enberg break; 864e49b05bSCyrill Gorcunov case UART_FCR: 8746aa8d69SPekka Enberg device.fcr = ioport__read8(data); 8846aa8d69SPekka Enberg break; 894e49b05bSCyrill Gorcunov case UART_LCR: 9046aa8d69SPekka Enberg device.lcr = ioport__read8(data); 9146aa8d69SPekka Enberg break; 9246aa8d69SPekka Enberg default: 9346aa8d69SPekka Enberg return false; 9446aa8d69SPekka Enberg } 9546aa8d69SPekka Enberg } else { 9646aa8d69SPekka Enberg switch (offset) { 974e49b05bSCyrill Gorcunov case UART_TX: { 9813a7760fSPekka Enberg char *p = data; 99f2d8dc88SCyrill Gorcunov int i; 10013a7760fSPekka Enberg 101f2d8dc88SCyrill Gorcunov while (count--) { 102f2d8dc88SCyrill Gorcunov for (i = 0; i < size; i++) 103b7475544SPekka Enberg fprintf(stdout, "%c", *p++); 1045b9d0b58SAsias He } 105b7475544SPekka Enberg fflush(stdout); 106e557eef9SPekka Enberg 107e557eef9SPekka Enberg device.iir |= UART_IIR_NO_INT; 108e557eef9SPekka Enberg kvm__irq_line(self, device.irq, 0); 109e557eef9SPekka Enberg 11046aa8d69SPekka Enberg break; 11146aa8d69SPekka Enberg } 1124e49b05bSCyrill Gorcunov case UART_IER: 11346aa8d69SPekka Enberg device.ier = ioport__read8(data); 11446aa8d69SPekka Enberg break; 1154e49b05bSCyrill Gorcunov case UART_FCR: 11646aa8d69SPekka Enberg device.fcr = ioport__read8(data); 11746aa8d69SPekka Enberg break; 1184e49b05bSCyrill Gorcunov case UART_LCR: 11946aa8d69SPekka Enberg device.lcr = ioport__read8(data); 12046aa8d69SPekka Enberg break; 1214e49b05bSCyrill Gorcunov case UART_MCR: 12246aa8d69SPekka Enberg device.mcr = ioport__read8(data); 12346aa8d69SPekka Enberg break; 1244e49b05bSCyrill Gorcunov case UART_SCR: 12546aa8d69SPekka Enberg device.scr = ioport__read8(data); 12646aa8d69SPekka Enberg break; 12746aa8d69SPekka Enberg default: 12846aa8d69SPekka Enberg return false; 12946aa8d69SPekka Enberg } 13046aa8d69SPekka Enberg } 13113a7760fSPekka Enberg 13213a7760fSPekka Enberg return true; 13313a7760fSPekka Enberg } 13413a7760fSPekka Enberg 13546aa8d69SPekka Enberg static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 13625af6674SPekka Enberg { 13746aa8d69SPekka Enberg uint16_t offset = port - device.iobase; 13846aa8d69SPekka Enberg 1399a7428ddSPekka Enberg if (device.lcr & UART_LCR_DLAB) 14046aa8d69SPekka Enberg return false; 14146aa8d69SPekka Enberg 14246aa8d69SPekka Enberg switch (offset) { 1434e49b05bSCyrill Gorcunov case UART_TX: 14476b4a122SPekka Enberg if (device.lsr & UART_LSR_DR) { 14576b4a122SPekka Enberg device.lsr &= ~UART_LSR_DR; 14676b4a122SPekka Enberg ioport__write8(data, device.thr); 14776b4a122SPekka Enberg 14876b4a122SPekka Enberg device.iir |= UART_IIR_NO_INT; 14976b4a122SPekka Enberg kvm__irq_line(self, device.irq, 0); 15076b4a122SPekka Enberg } 15146aa8d69SPekka Enberg break; 1524e49b05bSCyrill Gorcunov case UART_IER: 15346aa8d69SPekka Enberg ioport__write8(data, device.ier); 15446aa8d69SPekka Enberg break; 1554e49b05bSCyrill Gorcunov case UART_IIR: 156e557eef9SPekka Enberg ioport__write8(data, device.iir); 15746aa8d69SPekka Enberg break; 1584e49b05bSCyrill Gorcunov case UART_LCR: 15946aa8d69SPekka Enberg ioport__write8(data, device.lcr); 16046aa8d69SPekka Enberg break; 1614e49b05bSCyrill Gorcunov case UART_MCR: 16246aa8d69SPekka Enberg ioport__write8(data, device.mcr); 16346aa8d69SPekka Enberg break; 1644e49b05bSCyrill Gorcunov case UART_LSR: 16576b4a122SPekka Enberg ioport__write8(data, device.lsr); 16646aa8d69SPekka Enberg break; 1674e49b05bSCyrill Gorcunov case UART_MSR: 1689a7428ddSPekka Enberg ioport__write8(data, UART_MSR_CTS); 16946aa8d69SPekka Enberg break; 1704e49b05bSCyrill Gorcunov case UART_SCR: 17146aa8d69SPekka Enberg ioport__write8(data, device.scr); 17246aa8d69SPekka Enberg break; 17346aa8d69SPekka Enberg default: 17446aa8d69SPekka Enberg return false; 17525af6674SPekka Enberg } 17625af6674SPekka Enberg 17713a7760fSPekka Enberg return true; 17813a7760fSPekka Enberg } 17913a7760fSPekka Enberg 18046aa8d69SPekka Enberg static struct ioport_operations serial8250_ops = { 18146aa8d69SPekka Enberg .io_in = serial8250_in, 18246aa8d69SPekka Enberg .io_out = serial8250_out, 183a93ec68bSPekka Enberg }; 184a93ec68bSPekka Enberg 185899fe063SPekka Enberg void serial8250__init(void) 18613a7760fSPekka Enberg { 18746aa8d69SPekka Enberg ioport__register(device.iobase, &serial8250_ops, 8); 18813a7760fSPekka Enberg } 189