From bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 Mon Sep 17 00:00:00 2001 From: RajithaY Date: Tue, 25 Apr 2017 03:31:15 -0700 Subject: Adding qemu as a submodule of KVMFORNFV This Patch includes the changes to add qemu as a submodule to kvmfornfv repo and make use of the updated latest qemu for the execution of all testcase Change-Id: I1280af507a857675c7f81d30c95255635667bdd7 Signed-off-by:RajithaY --- qemu/hw/char/Makefile.objs | 30 - qemu/hw/char/bcm2835_aux.c | 316 ----------- qemu/hw/char/cadence_uart.c | 540 ------------------ qemu/hw/char/debugcon.c | 142 ----- qemu/hw/char/digic-uart.c | 198 ------- qemu/hw/char/escc.c | 1056 ----------------------------------- qemu/hw/char/etraxfs_ser.c | 254 --------- qemu/hw/char/exynos4210_uart.c | 678 ---------------------- qemu/hw/char/grlib_apbuart.c | 299 ---------- qemu/hw/char/imx_serial.c | 367 ------------ qemu/hw/char/ipoctal232.c | 604 -------------------- qemu/hw/char/lm32_juart.c | 165 ------ qemu/hw/char/lm32_uart.c | 305 ---------- qemu/hw/char/mcf_uart.c | 308 ---------- qemu/hw/char/milkymist-uart.c | 256 --------- qemu/hw/char/omap_uart.c | 188 ------- qemu/hw/char/parallel.c | 645 --------------------- qemu/hw/char/pl011.c | 343 ------------ qemu/hw/char/sclpconsole-lm.c | 384 ------------- qemu/hw/char/sclpconsole.c | 286 ---------- qemu/hw/char/serial-isa.c | 147 ----- qemu/hw/char/serial-pci.c | 276 --------- qemu/hw/char/serial.c | 966 -------------------------------- qemu/hw/char/sh_serial.c | 409 -------------- qemu/hw/char/spapr_vty.c | 249 --------- qemu/hw/char/stm32f2xx_usart.c | 233 -------- qemu/hw/char/virtio-console.c | 218 -------- qemu/hw/char/virtio-serial-bus.c | 1149 -------------------------------------- qemu/hw/char/xen_console.c | 297 ---------- qemu/hw/char/xilinx_uartlite.c | 249 --------- 30 files changed, 11557 deletions(-) delete mode 100644 qemu/hw/char/Makefile.objs delete mode 100644 qemu/hw/char/bcm2835_aux.c delete mode 100644 qemu/hw/char/cadence_uart.c delete mode 100644 qemu/hw/char/debugcon.c delete mode 100644 qemu/hw/char/digic-uart.c delete mode 100644 qemu/hw/char/escc.c delete mode 100644 qemu/hw/char/etraxfs_ser.c delete mode 100644 qemu/hw/char/exynos4210_uart.c delete mode 100644 qemu/hw/char/grlib_apbuart.c delete mode 100644 qemu/hw/char/imx_serial.c delete mode 100644 qemu/hw/char/ipoctal232.c delete mode 100644 qemu/hw/char/lm32_juart.c delete mode 100644 qemu/hw/char/lm32_uart.c delete mode 100644 qemu/hw/char/mcf_uart.c delete mode 100644 qemu/hw/char/milkymist-uart.c delete mode 100644 qemu/hw/char/omap_uart.c delete mode 100644 qemu/hw/char/parallel.c delete mode 100644 qemu/hw/char/pl011.c delete mode 100644 qemu/hw/char/sclpconsole-lm.c delete mode 100644 qemu/hw/char/sclpconsole.c delete mode 100644 qemu/hw/char/serial-isa.c delete mode 100644 qemu/hw/char/serial-pci.c delete mode 100644 qemu/hw/char/serial.c delete mode 100644 qemu/hw/char/sh_serial.c delete mode 100644 qemu/hw/char/spapr_vty.c delete mode 100644 qemu/hw/char/stm32f2xx_usart.c delete mode 100644 qemu/hw/char/virtio-console.c delete mode 100644 qemu/hw/char/virtio-serial-bus.c delete mode 100644 qemu/hw/char/xen_console.c delete mode 100644 qemu/hw/char/xilinx_uartlite.c (limited to 'qemu/hw/char') diff --git a/qemu/hw/char/Makefile.objs b/qemu/hw/char/Makefile.objs deleted file mode 100644 index 69a553cd8..000000000 --- a/qemu/hw/char/Makefile.objs +++ /dev/null @@ -1,30 +0,0 @@ -common-obj-$(CONFIG_IPACK) += ipoctal232.o -common-obj-$(CONFIG_ESCC) += escc.o -common-obj-$(CONFIG_PARALLEL) += parallel.o -common-obj-$(CONFIG_PL011) += pl011.o -common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o -common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o -common-obj-$(CONFIG_VIRTIO) += virtio-console.o -common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o -common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o -common-obj-$(CONFIG_CADENCE) += cadence_uart.o - -obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o -obj-$(CONFIG_COLDFIRE) += mcf_uart.o -obj-$(CONFIG_OMAP) += omap_uart.o -obj-$(CONFIG_SH4) += sh_serial.o -obj-$(CONFIG_PSERIES) += spapr_vty.o -obj-$(CONFIG_DIGIC) += digic-uart.o -obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o -obj-$(CONFIG_RASPI) += bcm2835_aux.o - -common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o -common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o -common-obj-$(CONFIG_GRLIB) += grlib_apbuart.o -common-obj-$(CONFIG_IMX) += imx_serial.o -common-obj-$(CONFIG_LM32) += lm32_juart.o -common-obj-$(CONFIG_LM32) += lm32_uart.o -common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o -common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o - -obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o diff --git a/qemu/hw/char/bcm2835_aux.c b/qemu/hw/char/bcm2835_aux.c deleted file mode 100644 index 0394d11a8..000000000 --- a/qemu/hw/char/bcm2835_aux.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * BCM2835 (Raspberry Pi / Pi 2) Aux block (mini UART and SPI). - * Copyright (c) 2015, Microsoft - * Written by Andrew Baumann - * Based on pl011.c, copyright terms below: - * - * Arm PrimeCell PL011 UART - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - * - * At present only the core UART functions (data path for tx/rx) are - * implemented. The following features/registers are unimplemented: - * - Line/modem control - * - Scratch register - * - Extra control - * - Baudrate - * - SPI interfaces - */ - -#include "qemu/osdep.h" -#include "hw/char/bcm2835_aux.h" - -#define AUX_IRQ 0x0 -#define AUX_ENABLES 0x4 -#define AUX_MU_IO_REG 0x40 -#define AUX_MU_IER_REG 0x44 -#define AUX_MU_IIR_REG 0x48 -#define AUX_MU_LCR_REG 0x4c -#define AUX_MU_MCR_REG 0x50 -#define AUX_MU_LSR_REG 0x54 -#define AUX_MU_MSR_REG 0x58 -#define AUX_MU_SCRATCH 0x5c -#define AUX_MU_CNTL_REG 0x60 -#define AUX_MU_STAT_REG 0x64 -#define AUX_MU_BAUD_REG 0x68 - -/* bits in IER/IIR registers */ -#define TX_INT 0x1 -#define RX_INT 0x2 - -static void bcm2835_aux_update(BCM2835AuxState *s) -{ - /* signal an interrupt if either: - * 1. rx interrupt is enabled and we have a non-empty rx fifo, or - * 2. the tx interrupt is enabled (since we instantly drain the tx fifo) - */ - s->iir = 0; - if ((s->ier & RX_INT) && s->read_count != 0) { - s->iir |= RX_INT; - } - if (s->ier & TX_INT) { - s->iir |= TX_INT; - } - qemu_set_irq(s->irq, s->iir != 0); -} - -static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size) -{ - BCM2835AuxState *s = opaque; - uint32_t c, res; - - switch (offset) { - case AUX_IRQ: - return s->iir != 0; - - case AUX_ENABLES: - return 1; /* mini UART permanently enabled */ - - case AUX_MU_IO_REG: - /* "DLAB bit set means access baudrate register" is NYI */ - c = s->read_fifo[s->read_pos]; - if (s->read_count > 0) { - s->read_count--; - if (++s->read_pos == BCM2835_AUX_RX_FIFO_LEN) { - s->read_pos = 0; - } - } - if (s->chr) { - qemu_chr_accept_input(s->chr); - } - bcm2835_aux_update(s); - return c; - - case AUX_MU_IER_REG: - /* "DLAB bit set means access baudrate register" is NYI */ - return 0xc0 | s->ier; /* FIFO enables always read 1 */ - - case AUX_MU_IIR_REG: - res = 0xc0; /* FIFO enables */ - /* The spec is unclear on what happens when both tx and rx - * interrupts are active, besides that this cannot occur. At - * present, we choose to prioritise the rx interrupt, since - * the tx fifo is always empty. */ - if (s->read_count != 0) { - res |= 0x4; - } else { - res |= 0x2; - } - if (s->iir == 0) { - res |= 0x1; - } - return res; - - case AUX_MU_LCR_REG: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__); - return 0; - - case AUX_MU_MCR_REG: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__); - return 0; - - case AUX_MU_LSR_REG: - res = 0x60; /* tx idle, empty */ - if (s->read_count != 0) { - res |= 0x1; - } - return res; - - case AUX_MU_MSR_REG: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MSR_REG unsupported\n", __func__); - return 0; - - case AUX_MU_SCRATCH: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__); - return 0; - - case AUX_MU_CNTL_REG: - return 0x3; /* tx, rx enabled */ - - case AUX_MU_STAT_REG: - res = 0x30e; /* space in the output buffer, empty tx fifo, idle tx/rx */ - if (s->read_count > 0) { - res |= 0x1; /* data in input buffer */ - assert(s->read_count < BCM2835_AUX_RX_FIFO_LEN); - res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */ - } - return res; - - case AUX_MU_BAUD_REG: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__); - return 0; - - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", - __func__, offset); - return 0; - } -} - -static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - BCM2835AuxState *s = opaque; - unsigned char ch; - - switch (offset) { - case AUX_ENABLES: - if (value != 1) { - qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI " - "or disable UART\n", __func__); - } - break; - - case AUX_MU_IO_REG: - /* "DLAB bit set means access baudrate register" is NYI */ - ch = value; - if (s->chr) { - qemu_chr_fe_write(s->chr, &ch, 1); - } - break; - - case AUX_MU_IER_REG: - /* "DLAB bit set means access baudrate register" is NYI */ - s->ier = value & (TX_INT | RX_INT); - bcm2835_aux_update(s); - break; - - case AUX_MU_IIR_REG: - if (value & 0x2) { - s->read_count = 0; - } - break; - - case AUX_MU_LCR_REG: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__); - break; - - case AUX_MU_MCR_REG: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__); - break; - - case AUX_MU_SCRATCH: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__); - break; - - case AUX_MU_CNTL_REG: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_CNTL_REG unsupported\n", __func__); - break; - - case AUX_MU_BAUD_REG: - qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__); - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", - __func__, offset); - } - - bcm2835_aux_update(s); -} - -static int bcm2835_aux_can_receive(void *opaque) -{ - BCM2835AuxState *s = opaque; - - return s->read_count < BCM2835_AUX_RX_FIFO_LEN; -} - -static void bcm2835_aux_put_fifo(void *opaque, uint8_t value) -{ - BCM2835AuxState *s = opaque; - int slot; - - slot = s->read_pos + s->read_count; - if (slot >= BCM2835_AUX_RX_FIFO_LEN) { - slot -= BCM2835_AUX_RX_FIFO_LEN; - } - s->read_fifo[slot] = value; - s->read_count++; - if (s->read_count == BCM2835_AUX_RX_FIFO_LEN) { - /* buffer full */ - } - bcm2835_aux_update(s); -} - -static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size) -{ - bcm2835_aux_put_fifo(opaque, *buf); -} - -static const MemoryRegionOps bcm2835_aux_ops = { - .read = bcm2835_aux_read, - .write = bcm2835_aux_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid.min_access_size = 4, - .valid.max_access_size = 4, -}; - -static const VMStateDescription vmstate_bcm2835_aux = { - .name = TYPE_BCM2835_AUX, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8_ARRAY(read_fifo, BCM2835AuxState, - BCM2835_AUX_RX_FIFO_LEN), - VMSTATE_UINT8(read_pos, BCM2835AuxState), - VMSTATE_UINT8(read_count, BCM2835AuxState), - VMSTATE_UINT8(ier, BCM2835AuxState), - VMSTATE_UINT8(iir, BCM2835AuxState), - VMSTATE_END_OF_LIST() - } -}; - -static void bcm2835_aux_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - BCM2835AuxState *s = BCM2835_AUX(obj); - - memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_aux_ops, s, - TYPE_BCM2835_AUX, 0x100); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); -} - -static void bcm2835_aux_realize(DeviceState *dev, Error **errp) -{ - BCM2835AuxState *s = BCM2835_AUX(dev); - - if (s->chr) { - qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive, - bcm2835_aux_receive, NULL, s); - } -} - -static Property bcm2835_aux_props[] = { - DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void bcm2835_aux_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = bcm2835_aux_realize; - dc->vmsd = &vmstate_bcm2835_aux; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - dc->props = bcm2835_aux_props; -} - -static const TypeInfo bcm2835_aux_info = { - .name = TYPE_BCM2835_AUX, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(BCM2835AuxState), - .instance_init = bcm2835_aux_init, - .class_init = bcm2835_aux_class_init, -}; - -static void bcm2835_aux_register_types(void) -{ - type_register_static(&bcm2835_aux_info); -} - -type_init(bcm2835_aux_register_types) diff --git a/qemu/hw/char/cadence_uart.c b/qemu/hw/char/cadence_uart.c deleted file mode 100644 index 797787823..000000000 --- a/qemu/hw/char/cadence_uart.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Device model for Cadence UART - * - * Copyright (c) 2010 Xilinx Inc. - * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) - * Copyright (c) 2012 PetaLogix Pty Ltd. - * Written by Haibing Ma - * M.Habib - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "qemu/osdep.h" -#include "hw/char/cadence_uart.h" - -#ifdef CADENCE_UART_ERR_DEBUG -#define DB_PRINT(...) do { \ - fprintf(stderr, ": %s: ", __func__); \ - fprintf(stderr, ## __VA_ARGS__); \ - } while (0); -#else - #define DB_PRINT(...) -#endif - -#define UART_SR_INTR_RTRIG 0x00000001 -#define UART_SR_INTR_REMPTY 0x00000002 -#define UART_SR_INTR_RFUL 0x00000004 -#define UART_SR_INTR_TEMPTY 0x00000008 -#define UART_SR_INTR_TFUL 0x00000010 -/* somewhat awkwardly, TTRIG is misaligned between SR and ISR */ -#define UART_SR_TTRIG 0x00002000 -#define UART_INTR_TTRIG 0x00000400 -/* bits fields in CSR that correlate to CISR. If any of these bits are set in - * SR, then the same bit in CISR is set high too */ -#define UART_SR_TO_CISR_MASK 0x0000001F - -#define UART_INTR_ROVR 0x00000020 -#define UART_INTR_FRAME 0x00000040 -#define UART_INTR_PARE 0x00000080 -#define UART_INTR_TIMEOUT 0x00000100 -#define UART_INTR_DMSI 0x00000200 -#define UART_INTR_TOVR 0x00001000 - -#define UART_SR_RACTIVE 0x00000400 -#define UART_SR_TACTIVE 0x00000800 -#define UART_SR_FDELT 0x00001000 - -#define UART_CR_RXRST 0x00000001 -#define UART_CR_TXRST 0x00000002 -#define UART_CR_RX_EN 0x00000004 -#define UART_CR_RX_DIS 0x00000008 -#define UART_CR_TX_EN 0x00000010 -#define UART_CR_TX_DIS 0x00000020 -#define UART_CR_RST_TO 0x00000040 -#define UART_CR_STARTBRK 0x00000080 -#define UART_CR_STOPBRK 0x00000100 - -#define UART_MR_CLKS 0x00000001 -#define UART_MR_CHRL 0x00000006 -#define UART_MR_CHRL_SH 1 -#define UART_MR_PAR 0x00000038 -#define UART_MR_PAR_SH 3 -#define UART_MR_NBSTOP 0x000000C0 -#define UART_MR_NBSTOP_SH 6 -#define UART_MR_CHMODE 0x00000300 -#define UART_MR_CHMODE_SH 8 -#define UART_MR_UCLKEN 0x00000400 -#define UART_MR_IRMODE 0x00000800 - -#define UART_DATA_BITS_6 (0x3 << UART_MR_CHRL_SH) -#define UART_DATA_BITS_7 (0x2 << UART_MR_CHRL_SH) -#define UART_PARITY_ODD (0x1 << UART_MR_PAR_SH) -#define UART_PARITY_EVEN (0x0 << UART_MR_PAR_SH) -#define UART_STOP_BITS_1 (0x3 << UART_MR_NBSTOP_SH) -#define UART_STOP_BITS_2 (0x2 << UART_MR_NBSTOP_SH) -#define NORMAL_MODE (0x0 << UART_MR_CHMODE_SH) -#define ECHO_MODE (0x1 << UART_MR_CHMODE_SH) -#define LOCAL_LOOPBACK (0x2 << UART_MR_CHMODE_SH) -#define REMOTE_LOOPBACK (0x3 << UART_MR_CHMODE_SH) - -#define UART_INPUT_CLK 50000000 - -#define R_CR (0x00/4) -#define R_MR (0x04/4) -#define R_IER (0x08/4) -#define R_IDR (0x0C/4) -#define R_IMR (0x10/4) -#define R_CISR (0x14/4) -#define R_BRGR (0x18/4) -#define R_RTOR (0x1C/4) -#define R_RTRIG (0x20/4) -#define R_MCR (0x24/4) -#define R_MSR (0x28/4) -#define R_SR (0x2C/4) -#define R_TX_RX (0x30/4) -#define R_BDIV (0x34/4) -#define R_FDEL (0x38/4) -#define R_PMIN (0x3C/4) -#define R_PWID (0x40/4) -#define R_TTRIG (0x44/4) - - -static void uart_update_status(CadenceUARTState *s) -{ - s->r[R_SR] = 0; - - s->r[R_SR] |= s->rx_count == CADENCE_UART_RX_FIFO_SIZE ? UART_SR_INTR_RFUL - : 0; - s->r[R_SR] |= !s->rx_count ? UART_SR_INTR_REMPTY : 0; - s->r[R_SR] |= s->rx_count >= s->r[R_RTRIG] ? UART_SR_INTR_RTRIG : 0; - - s->r[R_SR] |= s->tx_count == CADENCE_UART_TX_FIFO_SIZE ? UART_SR_INTR_TFUL - : 0; - s->r[R_SR] |= !s->tx_count ? UART_SR_INTR_TEMPTY : 0; - s->r[R_SR] |= s->tx_count >= s->r[R_TTRIG] ? UART_SR_TTRIG : 0; - - s->r[R_CISR] |= s->r[R_SR] & UART_SR_TO_CISR_MASK; - s->r[R_CISR] |= s->r[R_SR] & UART_SR_TTRIG ? UART_INTR_TTRIG : 0; - qemu_set_irq(s->irq, !!(s->r[R_IMR] & s->r[R_CISR])); -} - -static void fifo_trigger_update(void *opaque) -{ - CadenceUARTState *s = opaque; - - s->r[R_CISR] |= UART_INTR_TIMEOUT; - - uart_update_status(s); -} - -static void uart_rx_reset(CadenceUARTState *s) -{ - s->rx_wpos = 0; - s->rx_count = 0; - if (s->chr) { - qemu_chr_accept_input(s->chr); - } -} - -static void uart_tx_reset(CadenceUARTState *s) -{ - s->tx_count = 0; -} - -static void uart_send_breaks(CadenceUARTState *s) -{ - int break_enabled = 1; - - if (s->chr) { - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, - &break_enabled); - } -} - -static void uart_parameters_setup(CadenceUARTState *s) -{ - QEMUSerialSetParams ssp; - unsigned int baud_rate, packet_size; - - baud_rate = (s->r[R_MR] & UART_MR_CLKS) ? - UART_INPUT_CLK / 8 : UART_INPUT_CLK; - - ssp.speed = baud_rate / (s->r[R_BRGR] * (s->r[R_BDIV] + 1)); - packet_size = 1; - - switch (s->r[R_MR] & UART_MR_PAR) { - case UART_PARITY_EVEN: - ssp.parity = 'E'; - packet_size++; - break; - case UART_PARITY_ODD: - ssp.parity = 'O'; - packet_size++; - break; - default: - ssp.parity = 'N'; - break; - } - - switch (s->r[R_MR] & UART_MR_CHRL) { - case UART_DATA_BITS_6: - ssp.data_bits = 6; - break; - case UART_DATA_BITS_7: - ssp.data_bits = 7; - break; - default: - ssp.data_bits = 8; - break; - } - - switch (s->r[R_MR] & UART_MR_NBSTOP) { - case UART_STOP_BITS_1: - ssp.stop_bits = 1; - break; - default: - ssp.stop_bits = 2; - break; - } - - packet_size += ssp.data_bits + ssp.stop_bits; - s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size; - if (s->chr) { - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); - } -} - -static int uart_can_receive(void *opaque) -{ - CadenceUARTState *s = opaque; - int ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE); - uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE; - - if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) { - ret = MIN(ret, CADENCE_UART_RX_FIFO_SIZE - s->rx_count); - } - if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) { - ret = MIN(ret, CADENCE_UART_TX_FIFO_SIZE - s->tx_count); - } - return ret; -} - -static void uart_ctrl_update(CadenceUARTState *s) -{ - if (s->r[R_CR] & UART_CR_TXRST) { - uart_tx_reset(s); - } - - if (s->r[R_CR] & UART_CR_RXRST) { - uart_rx_reset(s); - } - - s->r[R_CR] &= ~(UART_CR_TXRST | UART_CR_RXRST); - - if (s->r[R_CR] & UART_CR_STARTBRK && !(s->r[R_CR] & UART_CR_STOPBRK)) { - uart_send_breaks(s); - } -} - -static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) -{ - CadenceUARTState *s = opaque; - uint64_t new_rx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int i; - - if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { - return; - } - - if (s->rx_count == CADENCE_UART_RX_FIFO_SIZE) { - s->r[R_CISR] |= UART_INTR_ROVR; - } else { - for (i = 0; i < size; i++) { - s->rx_fifo[s->rx_wpos] = buf[i]; - s->rx_wpos = (s->rx_wpos + 1) % CADENCE_UART_RX_FIFO_SIZE; - s->rx_count++; - } - timer_mod(s->fifo_trigger_handle, new_rx_time + - (s->char_tx_time * 4)); - } - uart_update_status(s); -} - -static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond, - void *opaque) -{ - CadenceUARTState *s = opaque; - int ret; - - /* instant drain the fifo when there's no back-end */ - if (!s->chr) { - s->tx_count = 0; - return FALSE; - } - - if (!s->tx_count) { - return FALSE; - } - - ret = qemu_chr_fe_write(s->chr, s->tx_fifo, s->tx_count); - s->tx_count -= ret; - memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_count); - - if (s->tx_count) { - int r = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, - cadence_uart_xmit, s); - assert(r); - } - - uart_update_status(s); - return FALSE; -} - -static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf, - int size) -{ - if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) { - return; - } - - if (size > CADENCE_UART_TX_FIFO_SIZE - s->tx_count) { - size = CADENCE_UART_TX_FIFO_SIZE - s->tx_count; - /* - * This can only be a guest error via a bad tx fifo register push, - * as can_receive() should stop remote loop and echo modes ever getting - * us to here. - */ - qemu_log_mask(LOG_GUEST_ERROR, "cadence_uart: TxFIFO overflow"); - s->r[R_CISR] |= UART_INTR_ROVR; - } - - memcpy(s->tx_fifo + s->tx_count, buf, size); - s->tx_count += size; - - cadence_uart_xmit(NULL, G_IO_OUT, s); -} - -static void uart_receive(void *opaque, const uint8_t *buf, int size) -{ - CadenceUARTState *s = opaque; - uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE; - - if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) { - uart_write_rx_fifo(opaque, buf, size); - } - if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) { - uart_write_tx_fifo(s, buf, size); - } -} - -static void uart_event(void *opaque, int event) -{ - CadenceUARTState *s = opaque; - uint8_t buf = '\0'; - - if (event == CHR_EVENT_BREAK) { - uart_write_rx_fifo(opaque, &buf, 1); - } - - uart_update_status(s); -} - -static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c) -{ - if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { - return; - } - - if (s->rx_count) { - uint32_t rx_rpos = (CADENCE_UART_RX_FIFO_SIZE + s->rx_wpos - - s->rx_count) % CADENCE_UART_RX_FIFO_SIZE; - *c = s->rx_fifo[rx_rpos]; - s->rx_count--; - - if (s->chr) { - qemu_chr_accept_input(s->chr); - } - } else { - *c = 0; - } - - uart_update_status(s); -} - -static void uart_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - CadenceUARTState *s = opaque; - - DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value); - offset >>= 2; - if (offset >= CADENCE_UART_R_MAX) { - return; - } - switch (offset) { - case R_IER: /* ier (wts imr) */ - s->r[R_IMR] |= value; - break; - case R_IDR: /* idr (wtc imr) */ - s->r[R_IMR] &= ~value; - break; - case R_IMR: /* imr (read only) */ - break; - case R_CISR: /* cisr (wtc) */ - s->r[R_CISR] &= ~value; - break; - case R_TX_RX: /* UARTDR */ - switch (s->r[R_MR] & UART_MR_CHMODE) { - case NORMAL_MODE: - uart_write_tx_fifo(s, (uint8_t *) &value, 1); - break; - case LOCAL_LOOPBACK: - uart_write_rx_fifo(opaque, (uint8_t *) &value, 1); - break; - } - break; - default: - s->r[offset] = value; - } - - switch (offset) { - case R_CR: - uart_ctrl_update(s); - break; - case R_MR: - uart_parameters_setup(s); - break; - } - uart_update_status(s); -} - -static uint64_t uart_read(void *opaque, hwaddr offset, - unsigned size) -{ - CadenceUARTState *s = opaque; - uint32_t c = 0; - - offset >>= 2; - if (offset >= CADENCE_UART_R_MAX) { - c = 0; - } else if (offset == R_TX_RX) { - uart_read_rx_fifo(s, &c); - } else { - c = s->r[offset]; - } - - DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c); - return c; -} - -static const MemoryRegionOps uart_ops = { - .read = uart_read, - .write = uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void cadence_uart_reset(DeviceState *dev) -{ - CadenceUARTState *s = CADENCE_UART(dev); - - s->r[R_CR] = 0x00000128; - s->r[R_IMR] = 0; - s->r[R_CISR] = 0; - s->r[R_RTRIG] = 0x00000020; - s->r[R_BRGR] = 0x0000000F; - s->r[R_TTRIG] = 0x00000020; - - uart_rx_reset(s); - uart_tx_reset(s); - - uart_update_status(s); -} - -static void cadence_uart_realize(DeviceState *dev, Error **errp) -{ - CadenceUARTState *s = CADENCE_UART(dev); - - s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, - fifo_trigger_update, s); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - - if (s->chr) { - qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive, - uart_event, s); - } -} - -static void cadence_uart_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - CadenceUARTState *s = CADENCE_UART(obj); - - memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - - s->char_tx_time = (NANOSECONDS_PER_SECOND / 9600) * 10; -} - -static int cadence_uart_post_load(void *opaque, int version_id) -{ - CadenceUARTState *s = opaque; - - uart_parameters_setup(s); - uart_update_status(s); - return 0; -} - -static const VMStateDescription vmstate_cadence_uart = { - .name = "cadence_uart", - .version_id = 2, - .minimum_version_id = 2, - .post_load = cadence_uart_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(r, CadenceUARTState, CADENCE_UART_R_MAX), - VMSTATE_UINT8_ARRAY(rx_fifo, CadenceUARTState, - CADENCE_UART_RX_FIFO_SIZE), - VMSTATE_UINT8_ARRAY(tx_fifo, CadenceUARTState, - CADENCE_UART_TX_FIFO_SIZE), - VMSTATE_UINT32(rx_count, CadenceUARTState), - VMSTATE_UINT32(tx_count, CadenceUARTState), - VMSTATE_UINT32(rx_wpos, CadenceUARTState), - VMSTATE_TIMER_PTR(fifo_trigger_handle, CadenceUARTState), - VMSTATE_END_OF_LIST() - } -}; - -static void cadence_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = cadence_uart_realize; - dc->vmsd = &vmstate_cadence_uart; - dc->reset = cadence_uart_reset; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo cadence_uart_info = { - .name = TYPE_CADENCE_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(CadenceUARTState), - .instance_init = cadence_uart_init, - .class_init = cadence_uart_class_init, -}; - -static void cadence_uart_register_types(void) -{ - type_register_static(&cadence_uart_info); -} - -type_init(cadence_uart_register_types) diff --git a/qemu/hw/char/debugcon.c b/qemu/hw/char/debugcon.c deleted file mode 100644 index e7f025ec6..000000000 --- a/qemu/hw/char/debugcon.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * QEMU Bochs-style debug console ("port E9") emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * Copyright (c) 2008 Citrix Systems, Inc. - * Copyright (c) Intel Corporation; author: H. Peter Anvin - * - * 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. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "sysemu/char.h" -#include "hw/isa/isa.h" -#include "hw/i386/pc.h" - -#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" -#define ISA_DEBUGCON_DEVICE(obj) \ - OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE) - -//#define DEBUG_DEBUGCON - -typedef struct DebugconState { - MemoryRegion io; - CharDriverState *chr; - uint32_t readback; -} DebugconState; - -typedef struct ISADebugconState { - ISADevice parent_obj; - - uint32_t iobase; - DebugconState state; -} ISADebugconState; - -static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - DebugconState *s = opaque; - unsigned char ch = val; - -#ifdef DEBUG_DEBUGCON - printf(" [debugcon: write addr=0x%04" HWADDR_PRIx " val=0x%02" PRIx64 "]\n", addr, val); -#endif - - qemu_chr_fe_write(s->chr, &ch, 1); -} - - -static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width) -{ - DebugconState *s = opaque; - -#ifdef DEBUG_DEBUGCON - printf("debugcon: read addr=0x%04" HWADDR_PRIx "\n", addr); -#endif - - return s->readback; -} - -static const MemoryRegionOps debugcon_ops = { - .read = debugcon_ioport_read, - .write = debugcon_ioport_write, - .valid.min_access_size = 1, - .valid.max_access_size = 1, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void debugcon_realize_core(DebugconState *s, Error **errp) -{ - if (!s->chr) { - error_setg(errp, "Can't create debugcon device, empty char device"); - return; - } - - qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s); -} - -static void debugcon_isa_realizefn(DeviceState *dev, Error **errp) -{ - ISADevice *d = ISA_DEVICE(dev); - ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev); - DebugconState *s = &isa->state; - Error *err = NULL; - - debugcon_realize_core(s, &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - memory_region_init_io(&s->io, OBJECT(dev), &debugcon_ops, s, - TYPE_ISA_DEBUGCON_DEVICE, 1); - memory_region_add_subregion(isa_address_space_io(d), - isa->iobase, &s->io); -} - -static Property debugcon_isa_properties[] = { - DEFINE_PROP_UINT32("iobase", ISADebugconState, iobase, 0xe9), - DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr), - DEFINE_PROP_UINT32("readback", ISADebugconState, state.readback, 0xe9), - DEFINE_PROP_END_OF_LIST(), -}; - -static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = debugcon_isa_realizefn; - dc->props = debugcon_isa_properties; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -} - -static const TypeInfo debugcon_isa_info = { - .name = TYPE_ISA_DEBUGCON_DEVICE, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISADebugconState), - .class_init = debugcon_isa_class_initfn, -}; - -static void debugcon_register_types(void) -{ - type_register_static(&debugcon_isa_info); -} - -type_init(debugcon_register_types) diff --git a/qemu/hw/char/digic-uart.c b/qemu/hw/char/digic-uart.c deleted file mode 100644 index d3bc533d7..000000000 --- a/qemu/hw/char/digic-uart.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * QEMU model of the Canon DIGIC UART block. - * - * Copyright (C) 2013 Antony Pavlov - * - * This model is based on reverse engineering efforts - * made by CHDK (http://chdk.wikia.com) and - * Magic Lantern (http://www.magiclantern.fm) projects - * contributors. - * - * See "Serial terminal" docs here: - * http://magiclantern.wikia.com/wiki/Register_Map#Misc_Registers - * - * The QEMU model of the Milkymist UART block by Michael Walle - * is used as a template. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "sysemu/char.h" - -#include "hw/char/digic-uart.h" - -enum { - ST_RX_RDY = (1 << 0), - ST_TX_RDY = (1 << 1), -}; - -static uint64_t digic_uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - DigicUartState *s = opaque; - uint64_t ret = 0; - - addr >>= 2; - - switch (addr) { - case R_RX: - s->reg_st &= ~(ST_RX_RDY); - ret = s->reg_rx; - break; - - case R_ST: - ret = s->reg_st; - break; - - default: - qemu_log_mask(LOG_UNIMP, - "digic-uart: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - } - - return ret; -} - -static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - DigicUartState *s = opaque; - unsigned char ch = value; - - addr >>= 2; - - switch (addr) { - case R_TX: - if (s->chr) { - qemu_chr_fe_write_all(s->chr, &ch, 1); - } - break; - - case R_ST: - /* - * Ignore write to R_ST. - * - * The point is that this register is actively used - * during receiving and transmitting symbols, - * but we don't know the function of most of bits. - * - * Ignoring writes to R_ST is only a simplification - * of the model. It has no perceptible side effects - * for existing guests. - */ - break; - - default: - qemu_log_mask(LOG_UNIMP, - "digic-uart: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - } -} - -static const MemoryRegionOps uart_mmio_ops = { - .read = digic_uart_read, - .write = digic_uart_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int uart_can_rx(void *opaque) -{ - DigicUartState *s = opaque; - - return !(s->reg_st & ST_RX_RDY); -} - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - DigicUartState *s = opaque; - - assert(uart_can_rx(opaque)); - - s->reg_st |= ST_RX_RDY; - s->reg_rx = *buf; -} - -static void uart_event(void *opaque, int event) -{ -} - -static void digic_uart_reset(DeviceState *d) -{ - DigicUartState *s = DIGIC_UART(d); - - s->reg_rx = 0; - s->reg_st = ST_TX_RDY; -} - -static void digic_uart_realize(DeviceState *dev, Error **errp) -{ - DigicUartState *s = DIGIC_UART(dev); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - if (s->chr) { - qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); - } -} - -static void digic_uart_init(Object *obj) -{ - DigicUartState *s = DIGIC_UART(obj); - - memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s, - TYPE_DIGIC_UART, 0x18); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->regs_region); -} - -static const VMStateDescription vmstate_digic_uart = { - .name = "digic-uart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(reg_rx, DigicUartState), - VMSTATE_UINT32(reg_st, DigicUartState), - VMSTATE_END_OF_LIST() - } -}; - -static void digic_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = digic_uart_realize; - dc->reset = digic_uart_reset; - dc->vmsd = &vmstate_digic_uart; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo digic_uart_info = { - .name = TYPE_DIGIC_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(DigicUartState), - .instance_init = digic_uart_init, - .class_init = digic_uart_class_init, -}; - -static void digic_uart_register_types(void) -{ - type_register_static(&digic_uart_info); -} - -type_init(digic_uart_register_types) diff --git a/qemu/hw/char/escc.c b/qemu/hw/char/escc.c deleted file mode 100644 index 7bf09a007..000000000 --- a/qemu/hw/char/escc.c +++ /dev/null @@ -1,1056 +0,0 @@ -/* - * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * 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. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "hw/char/escc.h" -#include "sysemu/char.h" -#include "ui/console.h" -#include "ui/input.h" -#include "trace.h" - -/* - * Chipset docs: - * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual", - * http://www.zilog.com/docs/serial/scc_escc_um.pdf - * - * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001 - * (Slave I/O), also produced as NCR89C105. See - * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * - * The serial ports implement full AMD AM8530 or Zilog Z8530 chips, - * mouse and keyboard ports don't implement all functions and they are - * only asynchronous. There is no DMA. - * - * Z85C30 is also used on PowerMacs. There are some small differences - * between Sparc version (sunzilog) and PowerMac (pmac): - * Offset between control and data registers - * There is some kind of lockup bug, but we can ignore it - * CTS is inverted - * DMA on pmac using DBDMA chip - * pmac can do IRDA and faster rates, sunzilog can only do 38400 - * pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz - */ - -/* - * Modifications: - * 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented - * serial mouse queue. - * Implemented serial mouse protocol. - * - * 2010-May-23 Artyom Tarasenko: Reworked IUS logic - */ - -typedef enum { - chn_a, chn_b, -} ChnID; - -#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a') - -typedef enum { - ser, kbd, mouse, -} ChnType; - -#define SERIO_QUEUE_SIZE 256 - -typedef struct { - uint8_t data[SERIO_QUEUE_SIZE]; - int rptr, wptr, count; -} SERIOQueue; - -#define SERIAL_REGS 16 -typedef struct ChannelState { - qemu_irq irq; - uint32_t rxint, txint, rxint_under_svc, txint_under_svc; - struct ChannelState *otherchn; - uint32_t reg; - uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS]; - SERIOQueue queue; - CharDriverState *chr; - int e0_mode, led_mode, caps_lock_mode, num_lock_mode; - int disabled; - int clock; - uint32_t vmstate_dummy; - ChnID chn; // this channel, A (base+4) or B (base+0) - ChnType type; - uint8_t rx, tx; - QemuInputHandlerState *hs; -} ChannelState; - -#define ESCC(obj) OBJECT_CHECK(ESCCState, (obj), TYPE_ESCC) - -typedef struct ESCCState { - SysBusDevice parent_obj; - - struct ChannelState chn[2]; - uint32_t it_shift; - MemoryRegion mmio; - uint32_t disabled; - uint32_t frequency; -} ESCCState; - -#define SERIAL_CTRL 0 -#define SERIAL_DATA 1 - -#define W_CMD 0 -#define CMD_PTR_MASK 0x07 -#define CMD_CMD_MASK 0x38 -#define CMD_HI 0x08 -#define CMD_CLR_TXINT 0x28 -#define CMD_CLR_IUS 0x38 -#define W_INTR 1 -#define INTR_INTALL 0x01 -#define INTR_TXINT 0x02 -#define INTR_RXMODEMSK 0x18 -#define INTR_RXINT1ST 0x08 -#define INTR_RXINTALL 0x10 -#define W_IVEC 2 -#define W_RXCTRL 3 -#define RXCTRL_RXEN 0x01 -#define W_TXCTRL1 4 -#define TXCTRL1_PAREN 0x01 -#define TXCTRL1_PAREV 0x02 -#define TXCTRL1_1STOP 0x04 -#define TXCTRL1_1HSTOP 0x08 -#define TXCTRL1_2STOP 0x0c -#define TXCTRL1_STPMSK 0x0c -#define TXCTRL1_CLK1X 0x00 -#define TXCTRL1_CLK16X 0x40 -#define TXCTRL1_CLK32X 0x80 -#define TXCTRL1_CLK64X 0xc0 -#define TXCTRL1_CLKMSK 0xc0 -#define W_TXCTRL2 5 -#define TXCTRL2_TXEN 0x08 -#define TXCTRL2_BITMSK 0x60 -#define TXCTRL2_5BITS 0x00 -#define TXCTRL2_7BITS 0x20 -#define TXCTRL2_6BITS 0x40 -#define TXCTRL2_8BITS 0x60 -#define W_SYNC1 6 -#define W_SYNC2 7 -#define W_TXBUF 8 -#define W_MINTR 9 -#define MINTR_STATUSHI 0x10 -#define MINTR_RST_MASK 0xc0 -#define MINTR_RST_B 0x40 -#define MINTR_RST_A 0x80 -#define MINTR_RST_ALL 0xc0 -#define W_MISC1 10 -#define W_CLOCK 11 -#define CLOCK_TRXC 0x08 -#define W_BRGLO 12 -#define W_BRGHI 13 -#define W_MISC2 14 -#define MISC2_PLLDIS 0x30 -#define W_EXTINT 15 -#define EXTINT_DCD 0x08 -#define EXTINT_SYNCINT 0x10 -#define EXTINT_CTSINT 0x20 -#define EXTINT_TXUNDRN 0x40 -#define EXTINT_BRKINT 0x80 - -#define R_STATUS 0 -#define STATUS_RXAV 0x01 -#define STATUS_ZERO 0x02 -#define STATUS_TXEMPTY 0x04 -#define STATUS_DCD 0x08 -#define STATUS_SYNC 0x10 -#define STATUS_CTS 0x20 -#define STATUS_TXUNDRN 0x40 -#define STATUS_BRK 0x80 -#define R_SPEC 1 -#define SPEC_ALLSENT 0x01 -#define SPEC_BITS8 0x06 -#define R_IVEC 2 -#define IVEC_TXINTB 0x00 -#define IVEC_LONOINT 0x06 -#define IVEC_LORXINTA 0x0c -#define IVEC_LORXINTB 0x04 -#define IVEC_LOTXINTA 0x08 -#define IVEC_HINOINT 0x60 -#define IVEC_HIRXINTA 0x30 -#define IVEC_HIRXINTB 0x20 -#define IVEC_HITXINTA 0x10 -#define R_INTR 3 -#define INTR_EXTINTB 0x01 -#define INTR_TXINTB 0x02 -#define INTR_RXINTB 0x04 -#define INTR_EXTINTA 0x08 -#define INTR_TXINTA 0x10 -#define INTR_RXINTA 0x20 -#define R_IPEN 4 -#define R_TXCTRL1 5 -#define R_TXCTRL2 6 -#define R_BC 7 -#define R_RXBUF 8 -#define R_RXCTRL 9 -#define R_MISC 10 -#define R_MISC1 11 -#define R_BRGLO 12 -#define R_BRGHI 13 -#define R_MISC1I 14 -#define R_EXTINT 15 - -static void handle_kbd_command(ChannelState *s, int val); -static int serial_can_receive(void *opaque); -static void serial_receive_byte(ChannelState *s, int ch); - -static void clear_queue(void *opaque) -{ - ChannelState *s = opaque; - SERIOQueue *q = &s->queue; - q->rptr = q->wptr = q->count = 0; -} - -static void put_queue(void *opaque, int b) -{ - ChannelState *s = opaque; - SERIOQueue *q = &s->queue; - - trace_escc_put_queue(CHN_C(s), b); - if (q->count >= SERIO_QUEUE_SIZE) - return; - q->data[q->wptr] = b; - if (++q->wptr == SERIO_QUEUE_SIZE) - q->wptr = 0; - q->count++; - serial_receive_byte(s, 0); -} - -static uint32_t get_queue(void *opaque) -{ - ChannelState *s = opaque; - SERIOQueue *q = &s->queue; - int val; - - if (q->count == 0) { - return 0; - } else { - val = q->data[q->rptr]; - if (++q->rptr == SERIO_QUEUE_SIZE) - q->rptr = 0; - q->count--; - } - trace_escc_get_queue(CHN_C(s), val); - if (q->count > 0) - serial_receive_byte(s, 0); - return val; -} - -static int escc_update_irq_chn(ChannelState *s) -{ - if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) || - // tx ints enabled, pending - ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) || - ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) && - s->rxint == 1) || // rx ints enabled, pending - ((s->wregs[W_EXTINT] & EXTINT_BRKINT) && - (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p - return 1; - } - return 0; -} - -static void escc_update_irq(ChannelState *s) -{ - int irq; - - irq = escc_update_irq_chn(s); - irq |= escc_update_irq_chn(s->otherchn); - - trace_escc_update_irq(irq); - qemu_set_irq(s->irq, irq); -} - -static void escc_reset_chn(ChannelState *s) -{ - int i; - - s->reg = 0; - for (i = 0; i < SERIAL_REGS; i++) { - s->rregs[i] = 0; - s->wregs[i] = 0; - } - s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity - s->wregs[W_MINTR] = MINTR_RST_ALL; - s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC - s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled - s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT | - EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts - if (s->disabled) - s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC | - STATUS_CTS | STATUS_TXUNDRN; - else - s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN; - s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT; - - s->rx = s->tx = 0; - s->rxint = s->txint = 0; - s->rxint_under_svc = s->txint_under_svc = 0; - s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0; - clear_queue(s); -} - -static void escc_reset(DeviceState *d) -{ - ESCCState *s = ESCC(d); - - escc_reset_chn(&s->chn[0]); - escc_reset_chn(&s->chn[1]); -} - -static inline void set_rxint(ChannelState *s) -{ - s->rxint = 1; - /* XXX: missing daisy chainnig: chn_b rx should have a lower priority - than chn_a rx/tx/special_condition service*/ - s->rxint_under_svc = 1; - if (s->chn == chn_a) { - s->rregs[R_INTR] |= INTR_RXINTA; - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA; - else - s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA; - } else { - s->otherchn->rregs[R_INTR] |= INTR_RXINTB; - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->rregs[R_IVEC] = IVEC_HIRXINTB; - else - s->rregs[R_IVEC] = IVEC_LORXINTB; - } - escc_update_irq(s); -} - -static inline void set_txint(ChannelState *s) -{ - s->txint = 1; - if (!s->rxint_under_svc) { - s->txint_under_svc = 1; - if (s->chn == chn_a) { - if (s->wregs[W_INTR] & INTR_TXINT) { - s->rregs[R_INTR] |= INTR_TXINTA; - } - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA; - else - s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA; - } else { - s->rregs[R_IVEC] = IVEC_TXINTB; - if (s->wregs[W_INTR] & INTR_TXINT) { - s->otherchn->rregs[R_INTR] |= INTR_TXINTB; - } - } - escc_update_irq(s); - } -} - -static inline void clr_rxint(ChannelState *s) -{ - s->rxint = 0; - s->rxint_under_svc = 0; - if (s->chn == chn_a) { - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->otherchn->rregs[R_IVEC] = IVEC_HINOINT; - else - s->otherchn->rregs[R_IVEC] = IVEC_LONOINT; - s->rregs[R_INTR] &= ~INTR_RXINTA; - } else { - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->rregs[R_IVEC] = IVEC_HINOINT; - else - s->rregs[R_IVEC] = IVEC_LONOINT; - s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB; - } - if (s->txint) - set_txint(s); - escc_update_irq(s); -} - -static inline void clr_txint(ChannelState *s) -{ - s->txint = 0; - s->txint_under_svc = 0; - if (s->chn == chn_a) { - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->otherchn->rregs[R_IVEC] = IVEC_HINOINT; - else - s->otherchn->rregs[R_IVEC] = IVEC_LONOINT; - s->rregs[R_INTR] &= ~INTR_TXINTA; - } else { - s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB; - if (s->wregs[W_MINTR] & MINTR_STATUSHI) - s->rregs[R_IVEC] = IVEC_HINOINT; - else - s->rregs[R_IVEC] = IVEC_LONOINT; - s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB; - } - if (s->rxint) - set_rxint(s); - escc_update_irq(s); -} - -static void escc_update_parameters(ChannelState *s) -{ - int speed, parity, data_bits, stop_bits; - QEMUSerialSetParams ssp; - - if (!s->chr || s->type != ser) - return; - - if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) { - if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV) - parity = 'E'; - else - parity = 'O'; - } else { - parity = 'N'; - } - if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP) - stop_bits = 2; - else - stop_bits = 1; - switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) { - case TXCTRL2_5BITS: - data_bits = 5; - break; - case TXCTRL2_7BITS: - data_bits = 7; - break; - case TXCTRL2_6BITS: - data_bits = 6; - break; - default: - case TXCTRL2_8BITS: - data_bits = 8; - break; - } - speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2); - switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) { - case TXCTRL1_CLK1X: - break; - case TXCTRL1_CLK16X: - speed /= 16; - break; - case TXCTRL1_CLK32X: - speed /= 32; - break; - default: - case TXCTRL1_CLK64X: - speed /= 64; - break; - } - ssp.speed = speed; - ssp.parity = parity; - ssp.data_bits = data_bits; - ssp.stop_bits = stop_bits; - trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits); - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); -} - -static void escc_mem_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - ESCCState *serial = opaque; - ChannelState *s; - uint32_t saddr; - int newreg, channel; - - val &= 0xff; - saddr = (addr >> serial->it_shift) & 1; - channel = (addr >> (serial->it_shift + 1)) & 1; - s = &serial->chn[channel]; - switch (saddr) { - case SERIAL_CTRL: - trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff); - newreg = 0; - switch (s->reg) { - case W_CMD: - newreg = val & CMD_PTR_MASK; - val &= CMD_CMD_MASK; - switch (val) { - case CMD_HI: - newreg |= CMD_HI; - break; - case CMD_CLR_TXINT: - clr_txint(s); - break; - case CMD_CLR_IUS: - if (s->rxint_under_svc) { - s->rxint_under_svc = 0; - if (s->txint) { - set_txint(s); - } - } else if (s->txint_under_svc) { - s->txint_under_svc = 0; - } - escc_update_irq(s); - break; - default: - break; - } - break; - case W_INTR ... W_RXCTRL: - case W_SYNC1 ... W_TXBUF: - case W_MISC1 ... W_CLOCK: - case W_MISC2 ... W_EXTINT: - s->wregs[s->reg] = val; - break; - case W_TXCTRL1: - case W_TXCTRL2: - s->wregs[s->reg] = val; - escc_update_parameters(s); - break; - case W_BRGLO: - case W_BRGHI: - s->wregs[s->reg] = val; - s->rregs[s->reg] = val; - escc_update_parameters(s); - break; - case W_MINTR: - switch (val & MINTR_RST_MASK) { - case 0: - default: - break; - case MINTR_RST_B: - escc_reset_chn(&serial->chn[0]); - return; - case MINTR_RST_A: - escc_reset_chn(&serial->chn[1]); - return; - case MINTR_RST_ALL: - escc_reset(DEVICE(serial)); - return; - } - break; - default: - break; - } - if (s->reg == 0) - s->reg = newreg; - else - s->reg = 0; - break; - case SERIAL_DATA: - trace_escc_mem_writeb_data(CHN_C(s), val); - s->tx = val; - if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled - if (s->chr) - qemu_chr_fe_write(s->chr, &s->tx, 1); - else if (s->type == kbd && !s->disabled) { - handle_kbd_command(s, val); - } - } - s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty - s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent - set_txint(s); - break; - default: - break; - } -} - -static uint64_t escc_mem_read(void *opaque, hwaddr addr, - unsigned size) -{ - ESCCState *serial = opaque; - ChannelState *s; - uint32_t saddr; - uint32_t ret; - int channel; - - saddr = (addr >> serial->it_shift) & 1; - channel = (addr >> (serial->it_shift + 1)) & 1; - s = &serial->chn[channel]; - switch (saddr) { - case SERIAL_CTRL: - trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]); - ret = s->rregs[s->reg]; - s->reg = 0; - return ret; - case SERIAL_DATA: - s->rregs[R_STATUS] &= ~STATUS_RXAV; - clr_rxint(s); - if (s->type == kbd || s->type == mouse) - ret = get_queue(s); - else - ret = s->rx; - trace_escc_mem_readb_data(CHN_C(s), ret); - if (s->chr) - qemu_chr_accept_input(s->chr); - return ret; - default: - break; - } - return 0; -} - -static const MemoryRegionOps escc_mem_ops = { - .read = escc_mem_read, - .write = escc_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static int serial_can_receive(void *opaque) -{ - ChannelState *s = opaque; - int ret; - - if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled - || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV)) - // char already available - ret = 0; - else - ret = 1; - return ret; -} - -static void serial_receive_byte(ChannelState *s, int ch) -{ - trace_escc_serial_receive_byte(CHN_C(s), ch); - s->rregs[R_STATUS] |= STATUS_RXAV; - s->rx = ch; - set_rxint(s); -} - -static void serial_receive_break(ChannelState *s) -{ - s->rregs[R_STATUS] |= STATUS_BRK; - escc_update_irq(s); -} - -static void serial_receive1(void *opaque, const uint8_t *buf, int size) -{ - ChannelState *s = opaque; - serial_receive_byte(s, buf[0]); -} - -static void serial_event(void *opaque, int event) -{ - ChannelState *s = opaque; - if (event == CHR_EVENT_BREAK) - serial_receive_break(s); -} - -static const VMStateDescription vmstate_escc_chn = { - .name ="escc_chn", - .version_id = 2, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(vmstate_dummy, ChannelState), - VMSTATE_UINT32(reg, ChannelState), - VMSTATE_UINT32(rxint, ChannelState), - VMSTATE_UINT32(txint, ChannelState), - VMSTATE_UINT32(rxint_under_svc, ChannelState), - VMSTATE_UINT32(txint_under_svc, ChannelState), - VMSTATE_UINT8(rx, ChannelState), - VMSTATE_UINT8(tx, ChannelState), - VMSTATE_BUFFER(wregs, ChannelState), - VMSTATE_BUFFER(rregs, ChannelState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_escc = { - .name ="escc", - .version_id = 2, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(chn, ESCCState, 2, 2, vmstate_escc_chn, - ChannelState), - VMSTATE_END_OF_LIST() - } -}; - -MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, - CharDriverState *chrA, CharDriverState *chrB, - int clock, int it_shift) -{ - DeviceState *dev; - SysBusDevice *s; - ESCCState *d; - - dev = qdev_create(NULL, TYPE_ESCC); - qdev_prop_set_uint32(dev, "disabled", 0); - qdev_prop_set_uint32(dev, "frequency", clock); - qdev_prop_set_uint32(dev, "it_shift", it_shift); - qdev_prop_set_chr(dev, "chrB", chrB); - qdev_prop_set_chr(dev, "chrA", chrA); - qdev_prop_set_uint32(dev, "chnBtype", ser); - qdev_prop_set_uint32(dev, "chnAtype", ser); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, irqB); - sysbus_connect_irq(s, 1, irqA); - if (base) { - sysbus_mmio_map(s, 0, base); - } - - d = ESCC(s); - return &d->mmio; -} - -static const uint8_t qcode_to_keycode[Q_KEY_CODE__MAX] = { - [Q_KEY_CODE_SHIFT] = 99, - [Q_KEY_CODE_SHIFT_R] = 110, - [Q_KEY_CODE_ALT] = 19, - [Q_KEY_CODE_ALT_R] = 13, - [Q_KEY_CODE_ALTGR] = 13, - [Q_KEY_CODE_CTRL] = 76, - [Q_KEY_CODE_CTRL_R] = 76, - [Q_KEY_CODE_ESC] = 29, - [Q_KEY_CODE_1] = 30, - [Q_KEY_CODE_2] = 31, - [Q_KEY_CODE_3] = 32, - [Q_KEY_CODE_4] = 33, - [Q_KEY_CODE_5] = 34, - [Q_KEY_CODE_6] = 35, - [Q_KEY_CODE_7] = 36, - [Q_KEY_CODE_8] = 37, - [Q_KEY_CODE_9] = 38, - [Q_KEY_CODE_0] = 39, - [Q_KEY_CODE_MINUS] = 40, - [Q_KEY_CODE_EQUAL] = 41, - [Q_KEY_CODE_BACKSPACE] = 43, - [Q_KEY_CODE_TAB] = 53, - [Q_KEY_CODE_Q] = 54, - [Q_KEY_CODE_W] = 55, - [Q_KEY_CODE_E] = 56, - [Q_KEY_CODE_R] = 57, - [Q_KEY_CODE_T] = 58, - [Q_KEY_CODE_Y] = 59, - [Q_KEY_CODE_U] = 60, - [Q_KEY_CODE_I] = 61, - [Q_KEY_CODE_O] = 62, - [Q_KEY_CODE_P] = 63, - [Q_KEY_CODE_BRACKET_LEFT] = 64, - [Q_KEY_CODE_BRACKET_RIGHT] = 65, - [Q_KEY_CODE_RET] = 89, - [Q_KEY_CODE_A] = 77, - [Q_KEY_CODE_S] = 78, - [Q_KEY_CODE_D] = 79, - [Q_KEY_CODE_F] = 80, - [Q_KEY_CODE_G] = 81, - [Q_KEY_CODE_H] = 82, - [Q_KEY_CODE_J] = 83, - [Q_KEY_CODE_K] = 84, - [Q_KEY_CODE_L] = 85, - [Q_KEY_CODE_SEMICOLON] = 86, - [Q_KEY_CODE_APOSTROPHE] = 87, - [Q_KEY_CODE_GRAVE_ACCENT] = 42, - [Q_KEY_CODE_BACKSLASH] = 88, - [Q_KEY_CODE_Z] = 100, - [Q_KEY_CODE_X] = 101, - [Q_KEY_CODE_C] = 102, - [Q_KEY_CODE_V] = 103, - [Q_KEY_CODE_B] = 104, - [Q_KEY_CODE_N] = 105, - [Q_KEY_CODE_M] = 106, - [Q_KEY_CODE_COMMA] = 107, - [Q_KEY_CODE_DOT] = 108, - [Q_KEY_CODE_SLASH] = 109, - [Q_KEY_CODE_ASTERISK] = 47, - [Q_KEY_CODE_SPC] = 121, - [Q_KEY_CODE_CAPS_LOCK] = 119, - [Q_KEY_CODE_F1] = 5, - [Q_KEY_CODE_F2] = 6, - [Q_KEY_CODE_F3] = 8, - [Q_KEY_CODE_F4] = 10, - [Q_KEY_CODE_F5] = 12, - [Q_KEY_CODE_F6] = 14, - [Q_KEY_CODE_F7] = 16, - [Q_KEY_CODE_F8] = 17, - [Q_KEY_CODE_F9] = 18, - [Q_KEY_CODE_F10] = 7, - [Q_KEY_CODE_NUM_LOCK] = 98, - [Q_KEY_CODE_SCROLL_LOCK] = 23, - [Q_KEY_CODE_KP_DIVIDE] = 46, - [Q_KEY_CODE_KP_MULTIPLY] = 47, - [Q_KEY_CODE_KP_SUBTRACT] = 71, - [Q_KEY_CODE_KP_ADD] = 125, - [Q_KEY_CODE_KP_ENTER] = 90, - [Q_KEY_CODE_KP_DECIMAL] = 50, - [Q_KEY_CODE_KP_0] = 94, - [Q_KEY_CODE_KP_1] = 112, - [Q_KEY_CODE_KP_2] = 113, - [Q_KEY_CODE_KP_3] = 114, - [Q_KEY_CODE_KP_4] = 91, - [Q_KEY_CODE_KP_5] = 92, - [Q_KEY_CODE_KP_6] = 93, - [Q_KEY_CODE_KP_7] = 68, - [Q_KEY_CODE_KP_8] = 69, - [Q_KEY_CODE_KP_9] = 70, - [Q_KEY_CODE_LESS] = 124, - [Q_KEY_CODE_F11] = 9, - [Q_KEY_CODE_F12] = 11, - [Q_KEY_CODE_HOME] = 52, - [Q_KEY_CODE_PGUP] = 96, - [Q_KEY_CODE_PGDN] = 123, - [Q_KEY_CODE_END] = 74, - [Q_KEY_CODE_LEFT] = 24, - [Q_KEY_CODE_UP] = 20, - [Q_KEY_CODE_DOWN] = 27, - [Q_KEY_CODE_RIGHT] = 28, - [Q_KEY_CODE_INSERT] = 44, - [Q_KEY_CODE_DELETE] = 66, - [Q_KEY_CODE_STOP] = 1, - [Q_KEY_CODE_AGAIN] = 3, - [Q_KEY_CODE_PROPS] = 25, - [Q_KEY_CODE_UNDO] = 26, - [Q_KEY_CODE_FRONT] = 49, - [Q_KEY_CODE_COPY] = 51, - [Q_KEY_CODE_OPEN] = 72, - [Q_KEY_CODE_PASTE] = 73, - [Q_KEY_CODE_FIND] = 95, - [Q_KEY_CODE_CUT] = 97, - [Q_KEY_CODE_LF] = 111, - [Q_KEY_CODE_HELP] = 118, - [Q_KEY_CODE_META_L] = 120, - [Q_KEY_CODE_META_R] = 122, - [Q_KEY_CODE_COMPOSE] = 67, - [Q_KEY_CODE_PRINT] = 22, - [Q_KEY_CODE_SYSRQ] = 21, -}; - -static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - ChannelState *s = (ChannelState *)dev; - int qcode, keycode; - InputKeyEvent *key; - - assert(evt->type == INPUT_EVENT_KIND_KEY); - key = evt->u.key.data; - qcode = qemu_input_key_value_to_qcode(key->key); - trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode], - key->down); - - if (qcode == Q_KEY_CODE_CAPS_LOCK) { - if (key->down) { - s->caps_lock_mode ^= 1; - if (s->caps_lock_mode == 2) { - return; /* Drop second press */ - } - } else { - s->caps_lock_mode ^= 2; - if (s->caps_lock_mode == 3) { - return; /* Drop first release */ - } - } - } - - if (qcode == Q_KEY_CODE_NUM_LOCK) { - if (key->down) { - s->num_lock_mode ^= 1; - if (s->num_lock_mode == 2) { - return; /* Drop second press */ - } - } else { - s->num_lock_mode ^= 2; - if (s->num_lock_mode == 3) { - return; /* Drop first release */ - } - } - } - - keycode = qcode_to_keycode[qcode]; - if (!key->down) { - keycode |= 0x80; - } - trace_escc_sunkbd_event_out(keycode); - put_queue(s, keycode); -} - -static QemuInputHandler sunkbd_handler = { - .name = "sun keyboard", - .mask = INPUT_EVENT_MASK_KEY, - .event = sunkbd_handle_event, -}; - -static void handle_kbd_command(ChannelState *s, int val) -{ - trace_escc_kbd_command(val); - if (s->led_mode) { // Ignore led byte - s->led_mode = 0; - return; - } - switch (val) { - case 1: // Reset, return type code - clear_queue(s); - put_queue(s, 0xff); - put_queue(s, 4); // Type 4 - put_queue(s, 0x7f); - break; - case 0xe: // Set leds - s->led_mode = 1; - break; - case 7: // Query layout - case 0xf: - clear_queue(s); - put_queue(s, 0xfe); - put_queue(s, 0x21); /* en-us layout */ - break; - default: - break; - } -} - -static void sunmouse_event(void *opaque, - int dx, int dy, int dz, int buttons_state) -{ - ChannelState *s = opaque; - int ch; - - trace_escc_sunmouse_event(dx, dy, buttons_state); - ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */ - - if (buttons_state & MOUSE_EVENT_LBUTTON) - ch ^= 0x4; - if (buttons_state & MOUSE_EVENT_MBUTTON) - ch ^= 0x2; - if (buttons_state & MOUSE_EVENT_RBUTTON) - ch ^= 0x1; - - put_queue(s, ch); - - ch = dx; - - if (ch > 127) - ch = 127; - else if (ch < -127) - ch = -127; - - put_queue(s, ch & 0xff); - - ch = -dy; - - if (ch > 127) - ch = 127; - else if (ch < -127) - ch = -127; - - put_queue(s, ch & 0xff); - - // MSC protocol specify two extra motion bytes - - put_queue(s, 0); - put_queue(s, 0); -} - -void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq, - int disabled, int clock, int it_shift) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, TYPE_ESCC); - qdev_prop_set_uint32(dev, "disabled", disabled); - qdev_prop_set_uint32(dev, "frequency", clock); - qdev_prop_set_uint32(dev, "it_shift", it_shift); - qdev_prop_set_chr(dev, "chrB", NULL); - qdev_prop_set_chr(dev, "chrA", NULL); - qdev_prop_set_uint32(dev, "chnBtype", mouse); - qdev_prop_set_uint32(dev, "chnAtype", kbd); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, irq); - sysbus_connect_irq(s, 1, irq); - sysbus_mmio_map(s, 0, base); -} - -static int escc_init1(SysBusDevice *dev) -{ - ESCCState *s = ESCC(dev); - unsigned int i; - - s->chn[0].disabled = s->disabled; - s->chn[1].disabled = s->disabled; - for (i = 0; i < 2; i++) { - sysbus_init_irq(dev, &s->chn[i].irq); - s->chn[i].chn = 1 - i; - s->chn[i].clock = s->frequency / 2; - if (s->chn[i].chr) { - qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, - serial_receive1, serial_event, &s->chn[i]); - } - } - s->chn[0].otherchn = &s->chn[1]; - s->chn[1].otherchn = &s->chn[0]; - - memory_region_init_io(&s->mmio, OBJECT(s), &escc_mem_ops, s, "escc", - ESCC_SIZE << s->it_shift); - sysbus_init_mmio(dev, &s->mmio); - - if (s->chn[0].type == mouse) { - qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, - "QEMU Sun Mouse"); - } - if (s->chn[1].type == kbd) { - s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]), - &sunkbd_handler); - } - - return 0; -} - -static Property escc_properties[] = { - DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0), - DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0), - DEFINE_PROP_UINT32("disabled", ESCCState, disabled, 0), - DEFINE_PROP_UINT32("chnBtype", ESCCState, chn[0].type, 0), - DEFINE_PROP_UINT32("chnAtype", ESCCState, chn[1].type, 0), - DEFINE_PROP_CHR("chrB", ESCCState, chn[0].chr), - DEFINE_PROP_CHR("chrA", ESCCState, chn[1].chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void escc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = escc_init1; - dc->reset = escc_reset; - dc->vmsd = &vmstate_escc; - dc->props = escc_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static const TypeInfo escc_info = { - .name = TYPE_ESCC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ESCCState), - .class_init = escc_class_init, -}; - -static void escc_register_types(void) -{ - type_register_static(&escc_info); -} - -type_init(escc_register_types) diff --git a/qemu/hw/char/etraxfs_ser.c b/qemu/hw/char/etraxfs_ser.c deleted file mode 100644 index 146b387e7..000000000 --- a/qemu/hw/char/etraxfs_ser.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * QEMU ETRAX System Emulator - * - * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. - * - * 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. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "sysemu/char.h" -#include "qemu/log.h" - -#define D(x) - -#define RW_TR_CTRL (0x00 / 4) -#define RW_TR_DMA_EN (0x04 / 4) -#define RW_REC_CTRL (0x08 / 4) -#define RW_DOUT (0x1c / 4) -#define RS_STAT_DIN (0x20 / 4) -#define R_STAT_DIN (0x24 / 4) -#define RW_INTR_MASK (0x2c / 4) -#define RW_ACK_INTR (0x30 / 4) -#define R_INTR (0x34 / 4) -#define R_MASKED_INTR (0x38 / 4) -#define R_MAX (0x3c / 4) - -#define STAT_DAV 16 -#define STAT_TR_IDLE 22 -#define STAT_TR_RDY 24 - -#define TYPE_ETRAX_FS_SERIAL "etraxfs,serial" -#define ETRAX_SERIAL(obj) \ - OBJECT_CHECK(ETRAXSerial, (obj), TYPE_ETRAX_FS_SERIAL) - -typedef struct ETRAXSerial { - SysBusDevice parent_obj; - - MemoryRegion mmio; - CharDriverState *chr; - qemu_irq irq; - - int pending_tx; - - uint8_t rx_fifo[16]; - unsigned int rx_fifo_pos; - unsigned int rx_fifo_len; - - /* Control registers. */ - uint32_t regs[R_MAX]; -} ETRAXSerial; - -static void ser_update_irq(ETRAXSerial *s) -{ - - if (s->rx_fifo_len) { - s->regs[R_INTR] |= 8; - } else { - s->regs[R_INTR] &= ~8; - } - - s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK]; - qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]); -} - -static uint64_t -ser_read(void *opaque, hwaddr addr, unsigned int size) -{ - ETRAXSerial *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) - { - case R_STAT_DIN: - r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15]; - if (s->rx_fifo_len) { - r |= 1 << STAT_DAV; - } - r |= 1 << STAT_TR_RDY; - r |= 1 << STAT_TR_IDLE; - break; - case RS_STAT_DIN: - r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15]; - if (s->rx_fifo_len) { - r |= 1 << STAT_DAV; - s->rx_fifo_len--; - } - r |= 1 << STAT_TR_RDY; - r |= 1 << STAT_TR_IDLE; - break; - default: - r = s->regs[addr]; - D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r)); - break; - } - return r; -} - -static void -ser_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - ETRAXSerial *s = opaque; - uint32_t value = val64; - unsigned char ch = val64; - - D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, value)); - addr >>= 2; - switch (addr) - { - case RW_DOUT: - qemu_chr_fe_write(s->chr, &ch, 1); - s->regs[R_INTR] |= 3; - s->pending_tx = 1; - s->regs[addr] = value; - break; - case RW_ACK_INTR: - if (s->pending_tx) { - value &= ~1; - s->pending_tx = 0; - D(qemu_log("fixedup value=%x r_intr=%x\n", - value, s->regs[R_INTR])); - } - s->regs[addr] = value; - s->regs[R_INTR] &= ~value; - D(printf("r_intr=%x\n", s->regs[R_INTR])); - break; - default: - s->regs[addr] = value; - break; - } - ser_update_irq(s); -} - -static const MemoryRegionOps ser_ops = { - .read = ser_read, - .write = ser_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static void serial_receive(void *opaque, const uint8_t *buf, int size) -{ - ETRAXSerial *s = opaque; - int i; - - /* Got a byte. */ - if (s->rx_fifo_len >= 16) { - D(qemu_log("WARNING: UART dropped char.\n")); - return; - } - - for (i = 0; i < size; i++) { - s->rx_fifo[s->rx_fifo_pos] = buf[i]; - s->rx_fifo_pos++; - s->rx_fifo_pos &= 15; - s->rx_fifo_len++; - } - - ser_update_irq(s); -} - -static int serial_can_receive(void *opaque) -{ - ETRAXSerial *s = opaque; - - /* Is the receiver enabled? */ - if (!(s->regs[RW_REC_CTRL] & (1 << 3))) { - return 0; - } - - return sizeof(s->rx_fifo) - s->rx_fifo_len; -} - -static void serial_event(void *opaque, int event) -{ - -} - -static void etraxfs_ser_reset(DeviceState *d) -{ - ETRAXSerial *s = ETRAX_SERIAL(d); - - /* transmitter begins ready and idle. */ - s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY); - s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE); - - s->regs[RW_REC_CTRL] = 0x10000; - -} - -static int etraxfs_ser_init(SysBusDevice *dev) -{ - ETRAXSerial *s = ETRAX_SERIAL(dev); - - sysbus_init_irq(dev, &s->irq); - memory_region_init_io(&s->mmio, OBJECT(s), &ser_ops, s, - "etraxfs-serial", R_MAX * 4); - sysbus_init_mmio(dev, &s->mmio); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - if (s->chr) { - qemu_chr_add_handlers(s->chr, - serial_can_receive, serial_receive, - serial_event, s); - } - return 0; -} - -static void etraxfs_ser_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = etraxfs_ser_init; - dc->reset = etraxfs_ser_reset; - /* Reason: init() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo etraxfs_ser_info = { - .name = TYPE_ETRAX_FS_SERIAL, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ETRAXSerial), - .class_init = etraxfs_ser_class_init, -}; - -static void etraxfs_serial_register_types(void) -{ - type_register_static(&etraxfs_ser_info); -} - -type_init(etraxfs_serial_register_types) diff --git a/qemu/hw/char/exynos4210_uart.c b/qemu/hw/char/exynos4210_uart.c deleted file mode 100644 index 885ecc027..000000000 --- a/qemu/hw/char/exynos4210_uart.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Exynos4210 UART Emulation - * - * Copyright (C) 2011 Samsung Electronics Co Ltd. - * Maksim Kozlov, - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/error-report.h" -#include "sysemu/sysemu.h" -#include "sysemu/char.h" - -#include "hw/arm/exynos4210.h" - -#undef DEBUG_UART -#undef DEBUG_UART_EXTEND -#undef DEBUG_IRQ -#undef DEBUG_Rx_DATA -#undef DEBUG_Tx_DATA - -#define DEBUG_UART 0 -#define DEBUG_UART_EXTEND 0 -#define DEBUG_IRQ 0 -#define DEBUG_Rx_DATA 0 -#define DEBUG_Tx_DATA 0 - -#if DEBUG_UART -#define PRINT_DEBUG(fmt, args...) \ - do { \ - fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ - } while (0) - -#if DEBUG_UART_EXTEND -#define PRINT_DEBUG_EXTEND(fmt, args...) \ - do { \ - fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ - } while (0) -#else -#define PRINT_DEBUG_EXTEND(fmt, args...) \ - do {} while (0) -#endif /* EXTEND */ - -#else -#define PRINT_DEBUG(fmt, args...) \ - do {} while (0) -#define PRINT_DEBUG_EXTEND(fmt, args...) \ - do {} while (0) -#endif - -#define PRINT_ERROR(fmt, args...) \ - do { \ - fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \ - } while (0) - -/* - * Offsets for UART registers relative to SFR base address - * for UARTn - * - */ -#define ULCON 0x0000 /* Line Control */ -#define UCON 0x0004 /* Control */ -#define UFCON 0x0008 /* FIFO Control */ -#define UMCON 0x000C /* Modem Control */ -#define UTRSTAT 0x0010 /* Tx/Rx Status */ -#define UERSTAT 0x0014 /* UART Error Status */ -#define UFSTAT 0x0018 /* FIFO Status */ -#define UMSTAT 0x001C /* Modem Status */ -#define UTXH 0x0020 /* Transmit Buffer */ -#define URXH 0x0024 /* Receive Buffer */ -#define UBRDIV 0x0028 /* Baud Rate Divisor */ -#define UFRACVAL 0x002C /* Divisor Fractional Value */ -#define UINTP 0x0030 /* Interrupt Pending */ -#define UINTSP 0x0034 /* Interrupt Source Pending */ -#define UINTM 0x0038 /* Interrupt Mask */ - -/* - * for indexing register in the uint32_t array - * - * 'reg' - register offset (see offsets definitions above) - * - */ -#define I_(reg) (reg / sizeof(uint32_t)) - -typedef struct Exynos4210UartReg { - const char *name; /* the only reason is the debug output */ - hwaddr offset; - uint32_t reset_value; -} Exynos4210UartReg; - -static Exynos4210UartReg exynos4210_uart_regs[] = { - {"ULCON", ULCON, 0x00000000}, - {"UCON", UCON, 0x00003000}, - {"UFCON", UFCON, 0x00000000}, - {"UMCON", UMCON, 0x00000000}, - {"UTRSTAT", UTRSTAT, 0x00000006}, /* RO */ - {"UERSTAT", UERSTAT, 0x00000000}, /* RO */ - {"UFSTAT", UFSTAT, 0x00000000}, /* RO */ - {"UMSTAT", UMSTAT, 0x00000000}, /* RO */ - {"UTXH", UTXH, 0x5c5c5c5c}, /* WO, undefined reset value*/ - {"URXH", URXH, 0x00000000}, /* RO */ - {"UBRDIV", UBRDIV, 0x00000000}, - {"UFRACVAL", UFRACVAL, 0x00000000}, - {"UINTP", UINTP, 0x00000000}, - {"UINTSP", UINTSP, 0x00000000}, - {"UINTM", UINTM, 0x00000000}, -}; - -#define EXYNOS4210_UART_REGS_MEM_SIZE 0x3C - -/* UART FIFO Control */ -#define UFCON_FIFO_ENABLE 0x1 -#define UFCON_Rx_FIFO_RESET 0x2 -#define UFCON_Tx_FIFO_RESET 0x4 -#define UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT 8 -#define UFCON_Tx_FIFO_TRIGGER_LEVEL (7 << UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT) -#define UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT 4 -#define UFCON_Rx_FIFO_TRIGGER_LEVEL (7 << UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT) - -/* Uart FIFO Status */ -#define UFSTAT_Rx_FIFO_COUNT 0xff -#define UFSTAT_Rx_FIFO_FULL 0x100 -#define UFSTAT_Rx_FIFO_ERROR 0x200 -#define UFSTAT_Tx_FIFO_COUNT_SHIFT 16 -#define UFSTAT_Tx_FIFO_COUNT (0xff << UFSTAT_Tx_FIFO_COUNT_SHIFT) -#define UFSTAT_Tx_FIFO_FULL_SHIFT 24 -#define UFSTAT_Tx_FIFO_FULL (1 << UFSTAT_Tx_FIFO_FULL_SHIFT) - -/* UART Interrupt Source Pending */ -#define UINTSP_RXD 0x1 /* Receive interrupt */ -#define UINTSP_ERROR 0x2 /* Error interrupt */ -#define UINTSP_TXD 0x4 /* Transmit interrupt */ -#define UINTSP_MODEM 0x8 /* Modem interrupt */ - -/* UART Line Control */ -#define ULCON_IR_MODE_SHIFT 6 -#define ULCON_PARITY_SHIFT 3 -#define ULCON_STOP_BIT_SHIFT 1 - -/* UART Tx/Rx Status */ -#define UTRSTAT_TRANSMITTER_EMPTY 0x4 -#define UTRSTAT_Tx_BUFFER_EMPTY 0x2 -#define UTRSTAT_Rx_BUFFER_DATA_READY 0x1 - -/* UART Error Status */ -#define UERSTAT_OVERRUN 0x1 -#define UERSTAT_PARITY 0x2 -#define UERSTAT_FRAME 0x4 -#define UERSTAT_BREAK 0x8 - -typedef struct { - uint8_t *data; - uint32_t sp, rp; /* store and retrieve pointers */ - uint32_t size; -} Exynos4210UartFIFO; - -#define TYPE_EXYNOS4210_UART "exynos4210.uart" -#define EXYNOS4210_UART(obj) \ - OBJECT_CHECK(Exynos4210UartState, (obj), TYPE_EXYNOS4210_UART) - -typedef struct Exynos4210UartState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - uint32_t reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)]; - Exynos4210UartFIFO rx; - Exynos4210UartFIFO tx; - - CharDriverState *chr; - qemu_irq irq; - - uint32_t channel; - -} Exynos4210UartState; - - -#if DEBUG_UART -/* Used only for debugging inside PRINT_DEBUG_... macros */ -static const char *exynos4210_uart_regname(hwaddr offset) -{ - - int i; - - for (i = 0; i < ARRAY_SIZE(exynos4210_uart_regs); i++) { - if (offset == exynos4210_uart_regs[i].offset) { - return exynos4210_uart_regs[i].name; - } - } - - return NULL; -} -#endif - - -static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch) -{ - q->data[q->sp] = ch; - q->sp = (q->sp + 1) % q->size; -} - -static uint8_t fifo_retrieve(Exynos4210UartFIFO *q) -{ - uint8_t ret = q->data[q->rp]; - q->rp = (q->rp + 1) % q->size; - return ret; -} - -static int fifo_elements_number(Exynos4210UartFIFO *q) -{ - if (q->sp < q->rp) { - return q->size - q->rp + q->sp; - } - - return q->sp - q->rp; -} - -static int fifo_empty_elements_number(Exynos4210UartFIFO *q) -{ - return q->size - fifo_elements_number(q); -} - -static void fifo_reset(Exynos4210UartFIFO *q) -{ - g_free(q->data); - q->data = NULL; - - q->data = (uint8_t *)g_malloc0(q->size); - - q->sp = 0; - q->rp = 0; -} - -static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s) -{ - uint32_t level = 0; - uint32_t reg; - - reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >> - UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT; - - switch (s->channel) { - case 0: - level = reg * 32; - break; - case 1: - case 4: - level = reg * 8; - break; - case 2: - case 3: - level = reg * 2; - break; - default: - level = 0; - PRINT_ERROR("Wrong UART channel number: %d\n", s->channel); - } - - return level; -} - -static void exynos4210_uart_update_irq(Exynos4210UartState *s) -{ - /* - * The Tx interrupt is always requested if the number of data in the - * transmit FIFO is smaller than the trigger level. - */ - if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) { - - uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >> - UFSTAT_Tx_FIFO_COUNT_SHIFT; - - if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) { - s->reg[I_(UINTSP)] |= UINTSP_TXD; - } - } - - s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)]; - - if (s->reg[I_(UINTP)]) { - qemu_irq_raise(s->irq); - -#if DEBUG_IRQ - fprintf(stderr, "UART%d: IRQ has been raised: %08x\n", - s->channel, s->reg[I_(UINTP)]); -#endif - - } else { - qemu_irq_lower(s->irq); - } -} - -static void exynos4210_uart_update_parameters(Exynos4210UartState *s) -{ - int speed, parity, data_bits, stop_bits, frame_size; - QEMUSerialSetParams ssp; - uint64_t uclk_rate; - - if (s->reg[I_(UBRDIV)] == 0) { - return; - } - - frame_size = 1; /* start bit */ - if (s->reg[I_(ULCON)] & 0x20) { - frame_size++; /* parity bit */ - if (s->reg[I_(ULCON)] & 0x28) { - parity = 'E'; - } else { - parity = 'O'; - } - } else { - parity = 'N'; - } - - if (s->reg[I_(ULCON)] & 0x4) { - stop_bits = 2; - } else { - stop_bits = 1; - } - - data_bits = (s->reg[I_(ULCON)] & 0x3) + 5; - - frame_size += data_bits + stop_bits; - - uclk_rate = 24000000; - - speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) + - (s->reg[I_(UFRACVAL)] & 0x7) + 16); - - ssp.speed = speed; - ssp.parity = parity; - ssp.data_bits = data_bits; - ssp.stop_bits = stop_bits; - - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); - - PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n", - s->channel, speed, parity, data_bits, stop_bits); -} - -static void exynos4210_uart_write(void *opaque, hwaddr offset, - uint64_t val, unsigned size) -{ - Exynos4210UartState *s = (Exynos4210UartState *)opaque; - uint8_t ch; - - PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel, - offset, exynos4210_uart_regname(offset), (long long unsigned int)val); - - switch (offset) { - case ULCON: - case UBRDIV: - case UFRACVAL: - s->reg[I_(offset)] = val; - exynos4210_uart_update_parameters(s); - break; - case UFCON: - s->reg[I_(UFCON)] = val; - if (val & UFCON_Rx_FIFO_RESET) { - fifo_reset(&s->rx); - s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET; - PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel); - } - if (val & UFCON_Tx_FIFO_RESET) { - fifo_reset(&s->tx); - s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET; - PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel); - } - break; - - case UTXH: - if (s->chr) { - s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY | - UTRSTAT_Tx_BUFFER_EMPTY); - ch = (uint8_t)val; - qemu_chr_fe_write(s->chr, &ch, 1); -#if DEBUG_Tx_DATA - fprintf(stderr, "%c", ch); -#endif - s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY | - UTRSTAT_Tx_BUFFER_EMPTY; - s->reg[I_(UINTSP)] |= UINTSP_TXD; - exynos4210_uart_update_irq(s); - } - break; - - case UINTP: - s->reg[I_(UINTP)] &= ~val; - s->reg[I_(UINTSP)] &= ~val; - PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n", - s->channel, offset, s->reg[I_(UINTP)]); - exynos4210_uart_update_irq(s); - break; - case UTRSTAT: - case UERSTAT: - case UFSTAT: - case UMSTAT: - case URXH: - PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n", - s->channel, exynos4210_uart_regname(offset), offset); - break; - case UINTSP: - s->reg[I_(UINTSP)] &= ~val; - break; - case UINTM: - s->reg[I_(UINTM)] = val; - exynos4210_uart_update_irq(s); - break; - case UCON: - case UMCON: - default: - s->reg[I_(offset)] = val; - break; - } -} -static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset, - unsigned size) -{ - Exynos4210UartState *s = (Exynos4210UartState *)opaque; - uint32_t res; - - switch (offset) { - case UERSTAT: /* Read Only */ - res = s->reg[I_(UERSTAT)]; - s->reg[I_(UERSTAT)] = 0; - return res; - case UFSTAT: /* Read Only */ - s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff; - if (fifo_empty_elements_number(&s->rx) == 0) { - s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL; - s->reg[I_(UFSTAT)] &= ~0xff; - } - return s->reg[I_(UFSTAT)]; - case URXH: - if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) { - if (fifo_elements_number(&s->rx)) { - res = fifo_retrieve(&s->rx); -#if DEBUG_Rx_DATA - fprintf(stderr, "%c", res); -#endif - if (!fifo_elements_number(&s->rx)) { - s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY; - } else { - s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY; - } - } else { - s->reg[I_(UINTSP)] |= UINTSP_ERROR; - exynos4210_uart_update_irq(s); - res = 0; - } - } else { - s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY; - res = s->reg[I_(URXH)]; - } - return res; - case UTXH: - PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n", - s->channel, exynos4210_uart_regname(offset), offset); - break; - default: - return s->reg[I_(offset)]; - } - - return 0; -} - -static const MemoryRegionOps exynos4210_uart_ops = { - .read = exynos4210_uart_read, - .write = exynos4210_uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .max_access_size = 4, - .unaligned = false - }, -}; - -static int exynos4210_uart_can_receive(void *opaque) -{ - Exynos4210UartState *s = (Exynos4210UartState *)opaque; - - return fifo_empty_elements_number(&s->rx); -} - - -static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size) -{ - Exynos4210UartState *s = (Exynos4210UartState *)opaque; - int i; - - if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) { - if (fifo_empty_elements_number(&s->rx) < size) { - for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) { - fifo_store(&s->rx, buf[i]); - } - s->reg[I_(UINTSP)] |= UINTSP_ERROR; - s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY; - } else { - for (i = 0; i < size; i++) { - fifo_store(&s->rx, buf[i]); - } - s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY; - } - /* XXX: Around here we maybe should check Rx trigger level */ - s->reg[I_(UINTSP)] |= UINTSP_RXD; - } else { - s->reg[I_(URXH)] = buf[0]; - s->reg[I_(UINTSP)] |= UINTSP_RXD; - s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY; - } - - exynos4210_uart_update_irq(s); -} - - -static void exynos4210_uart_event(void *opaque, int event) -{ - Exynos4210UartState *s = (Exynos4210UartState *)opaque; - - if (event == CHR_EVENT_BREAK) { - /* When the RxDn is held in logic 0, then a null byte is pushed into the - * fifo */ - fifo_store(&s->rx, '\0'); - s->reg[I_(UERSTAT)] |= UERSTAT_BREAK; - exynos4210_uart_update_irq(s); - } -} - - -static void exynos4210_uart_reset(DeviceState *dev) -{ - Exynos4210UartState *s = EXYNOS4210_UART(dev); - int i; - - for (i = 0; i < ARRAY_SIZE(exynos4210_uart_regs); i++) { - s->reg[I_(exynos4210_uart_regs[i].offset)] = - exynos4210_uart_regs[i].reset_value; - } - - fifo_reset(&s->rx); - fifo_reset(&s->tx); - - PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size); -} - -static const VMStateDescription vmstate_exynos4210_uart_fifo = { - .name = "exynos4210.uart.fifo", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(sp, Exynos4210UartFIFO), - VMSTATE_UINT32(rp, Exynos4210UartFIFO), - VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, 0, size), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_exynos4210_uart = { - .name = "exynos4210.uart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(rx, Exynos4210UartState, 1, - vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO), - VMSTATE_UINT32_ARRAY(reg, Exynos4210UartState, - EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)), - VMSTATE_END_OF_LIST() - } -}; - -DeviceState *exynos4210_uart_create(hwaddr addr, - int fifo_size, - int channel, - CharDriverState *chr, - qemu_irq irq) -{ - DeviceState *dev; - SysBusDevice *bus; - - const char chr_name[] = "serial"; - char label[ARRAY_SIZE(chr_name) + 1]; - - dev = qdev_create(NULL, TYPE_EXYNOS4210_UART); - - if (!chr) { - if (channel >= MAX_SERIAL_PORTS) { - error_report("Only %d serial ports are supported by QEMU", - MAX_SERIAL_PORTS); - exit(1); - } - chr = serial_hds[channel]; - if (!chr) { - snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel); - chr = qemu_chr_new(label, "null", NULL); - if (!(chr)) { - error_report("Can't assign serial port to UART%d", channel); - exit(1); - } - } - } - - qdev_prop_set_chr(dev, "chardev", chr); - qdev_prop_set_uint32(dev, "channel", channel); - qdev_prop_set_uint32(dev, "rx-size", fifo_size); - qdev_prop_set_uint32(dev, "tx-size", fifo_size); - - bus = SYS_BUS_DEVICE(dev); - qdev_init_nofail(dev); - if (addr != (hwaddr)-1) { - sysbus_mmio_map(bus, 0, addr); - } - sysbus_connect_irq(bus, 0, irq); - - return dev; -} - -static int exynos4210_uart_init(SysBusDevice *dev) -{ - Exynos4210UartState *s = EXYNOS4210_UART(dev); - - /* memory mapping */ - memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_uart_ops, s, - "exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE); - sysbus_init_mmio(dev, &s->iomem); - - sysbus_init_irq(dev, &s->irq); - - qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive, - exynos4210_uart_receive, exynos4210_uart_event, s); - - return 0; -} - -static Property exynos4210_uart_properties[] = { - DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr), - DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0), - DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16), - DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16), - DEFINE_PROP_END_OF_LIST(), -}; - -static void exynos4210_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = exynos4210_uart_init; - dc->reset = exynos4210_uart_reset; - dc->props = exynos4210_uart_properties; - dc->vmsd = &vmstate_exynos4210_uart; -} - -static const TypeInfo exynos4210_uart_info = { - .name = TYPE_EXYNOS4210_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210UartState), - .class_init = exynos4210_uart_class_init, -}; - -static void exynos4210_uart_register(void) -{ - type_register_static(&exynos4210_uart_info); -} - -type_init(exynos4210_uart_register) diff --git a/qemu/hw/char/grlib_apbuart.c b/qemu/hw/char/grlib_apbuart.c deleted file mode 100644 index 871524c82..000000000 --- a/qemu/hw/char/grlib_apbuart.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * QEMU GRLIB APB UART Emulator - * - * Copyright (c) 2010-2011 AdaCore - * - * 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. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "sysemu/char.h" - -#include "trace.h" - -#define UART_REG_SIZE 20 /* Size of memory mapped registers */ - -/* UART status register fields */ -#define UART_DATA_READY (1 << 0) -#define UART_TRANSMIT_SHIFT_EMPTY (1 << 1) -#define UART_TRANSMIT_FIFO_EMPTY (1 << 2) -#define UART_BREAK_RECEIVED (1 << 3) -#define UART_OVERRUN (1 << 4) -#define UART_PARITY_ERROR (1 << 5) -#define UART_FRAMING_ERROR (1 << 6) -#define UART_TRANSMIT_FIFO_HALF (1 << 7) -#define UART_RECEIVE_FIFO_HALF (1 << 8) -#define UART_TRANSMIT_FIFO_FULL (1 << 9) -#define UART_RECEIVE_FIFO_FULL (1 << 10) - -/* UART control register fields */ -#define UART_RECEIVE_ENABLE (1 << 0) -#define UART_TRANSMIT_ENABLE (1 << 1) -#define UART_RECEIVE_INTERRUPT (1 << 2) -#define UART_TRANSMIT_INTERRUPT (1 << 3) -#define UART_PARITY_SELECT (1 << 4) -#define UART_PARITY_ENABLE (1 << 5) -#define UART_FLOW_CONTROL (1 << 6) -#define UART_LOOPBACK (1 << 7) -#define UART_EXTERNAL_CLOCK (1 << 8) -#define UART_RECEIVE_FIFO_INTERRUPT (1 << 9) -#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10) -#define UART_FIFO_DEBUG_MODE (1 << 11) -#define UART_OUTPUT_ENABLE (1 << 12) -#define UART_FIFO_AVAILABLE (1 << 31) - -/* Memory mapped register offsets */ -#define DATA_OFFSET 0x00 -#define STATUS_OFFSET 0x04 -#define CONTROL_OFFSET 0x08 -#define SCALER_OFFSET 0x0C /* not supported */ -#define FIFO_DEBUG_OFFSET 0x10 /* not supported */ - -#define FIFO_LENGTH 1024 - -#define TYPE_GRLIB_APB_UART "grlib,apbuart" -#define GRLIB_APB_UART(obj) \ - OBJECT_CHECK(UART, (obj), TYPE_GRLIB_APB_UART) - -typedef struct UART { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - - CharDriverState *chr; - - /* registers */ - uint32_t status; - uint32_t control; - - /* FIFO */ - char buffer[FIFO_LENGTH]; - int len; - int current; -} UART; - -static int uart_data_to_read(UART *uart) -{ - return uart->current < uart->len; -} - -static char uart_pop(UART *uart) -{ - char ret; - - if (uart->len == 0) { - uart->status &= ~UART_DATA_READY; - return 0; - } - - ret = uart->buffer[uart->current++]; - - if (uart->current >= uart->len) { - /* Flush */ - uart->len = 0; - uart->current = 0; - } - - if (!uart_data_to_read(uart)) { - uart->status &= ~UART_DATA_READY; - } - - return ret; -} - -static void uart_add_to_fifo(UART *uart, - const uint8_t *buffer, - int length) -{ - if (uart->len + length > FIFO_LENGTH) { - abort(); - } - memcpy(uart->buffer + uart->len, buffer, length); - uart->len += length; -} - -static int grlib_apbuart_can_receive(void *opaque) -{ - UART *uart = opaque; - - return FIFO_LENGTH - uart->len; -} - -static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size) -{ - UART *uart = opaque; - - if (uart->control & UART_RECEIVE_ENABLE) { - uart_add_to_fifo(uart, buf, size); - - uart->status |= UART_DATA_READY; - - if (uart->control & UART_RECEIVE_INTERRUPT) { - qemu_irq_pulse(uart->irq); - } - } -} - -static void grlib_apbuart_event(void *opaque, int event) -{ - trace_grlib_apbuart_event(event); -} - - -static uint64_t grlib_apbuart_read(void *opaque, hwaddr addr, - unsigned size) -{ - UART *uart = opaque; - - addr &= 0xff; - - /* Unit registers */ - switch (addr) { - case DATA_OFFSET: - case DATA_OFFSET + 3: /* when only one byte read */ - return uart_pop(uart); - - case STATUS_OFFSET: - /* Read Only */ - return uart->status; - - case CONTROL_OFFSET: - return uart->control; - - case SCALER_OFFSET: - /* Not supported */ - return 0; - - default: - trace_grlib_apbuart_readl_unknown(addr); - return 0; - } -} - -static void grlib_apbuart_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - UART *uart = opaque; - unsigned char c = 0; - - addr &= 0xff; - - /* Unit registers */ - switch (addr) { - case DATA_OFFSET: - case DATA_OFFSET + 3: /* When only one byte write */ - /* Transmit when character device available and transmitter enabled */ - if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) { - c = value & 0xFF; - qemu_chr_fe_write(uart->chr, &c, 1); - /* Generate interrupt */ - if (uart->control & UART_TRANSMIT_INTERRUPT) { - qemu_irq_pulse(uart->irq); - } - } - return; - - case STATUS_OFFSET: - /* Read Only */ - return; - - case CONTROL_OFFSET: - uart->control = value; - return; - - case SCALER_OFFSET: - /* Not supported */ - return; - - default: - break; - } - - trace_grlib_apbuart_writel_unknown(addr, value); -} - -static const MemoryRegionOps grlib_apbuart_ops = { - .write = grlib_apbuart_write, - .read = grlib_apbuart_read, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int grlib_apbuart_init(SysBusDevice *dev) -{ - UART *uart = GRLIB_APB_UART(dev); - - qemu_chr_add_handlers(uart->chr, - grlib_apbuart_can_receive, - grlib_apbuart_receive, - grlib_apbuart_event, - uart); - - sysbus_init_irq(dev, &uart->irq); - - memory_region_init_io(&uart->iomem, OBJECT(uart), &grlib_apbuart_ops, uart, - "uart", UART_REG_SIZE); - - sysbus_init_mmio(dev, &uart->iomem); - - return 0; -} - -static void grlib_apbuart_reset(DeviceState *d) -{ - UART *uart = GRLIB_APB_UART(d); - - /* Transmitter FIFO and shift registers are always empty in QEMU */ - uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY; - /* Everything is off */ - uart->control = 0; - /* Flush receive FIFO */ - uart->len = 0; - uart->current = 0; -} - -static Property grlib_apbuart_properties[] = { - DEFINE_PROP_CHR("chrdev", UART, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void grlib_apbuart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = grlib_apbuart_init; - dc->reset = grlib_apbuart_reset; - dc->props = grlib_apbuart_properties; -} - -static const TypeInfo grlib_apbuart_info = { - .name = TYPE_GRLIB_APB_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(UART), - .class_init = grlib_apbuart_class_init, -}; - -static void grlib_apbuart_register_types(void) -{ - type_register_static(&grlib_apbuart_info); -} - -type_init(grlib_apbuart_register_types) diff --git a/qemu/hw/char/imx_serial.c b/qemu/hw/char/imx_serial.c deleted file mode 100644 index 6df74ac7c..000000000 --- a/qemu/hw/char/imx_serial.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * IMX31 UARTS - * - * Copyright (c) 2008 OKL - * Originally Written by Hans Jiang - * Copyright (c) 2011 NICTA Pty Ltd. - * Updated by Jean-Christophe Dubois - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - * This is a `bare-bones' implementation of the IMX series serial ports. - * TODO: - * -- implement FIFOs. The real hardware has 32 word transmit - * and receive FIFOs; we currently use a 1-char buffer - * -- implement DMA - * -- implement BAUD-rate and modem lines, for when the backend - * is a real serial device. - */ - -#include "qemu/osdep.h" -#include "hw/char/imx_serial.h" -#include "sysemu/sysemu.h" -#include "sysemu/char.h" - -#ifndef DEBUG_IMX_UART -#define DEBUG_IMX_UART 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_UART) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_SERIAL, \ - __func__, ##args); \ - } \ - } while (0) - -static const VMStateDescription vmstate_imx_serial = { - .name = TYPE_IMX_SERIAL, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(readbuff, IMXSerialState), - VMSTATE_UINT32(usr1, IMXSerialState), - VMSTATE_UINT32(usr2, IMXSerialState), - VMSTATE_UINT32(ucr1, IMXSerialState), - VMSTATE_UINT32(uts1, IMXSerialState), - VMSTATE_UINT32(onems, IMXSerialState), - VMSTATE_UINT32(ufcr, IMXSerialState), - VMSTATE_UINT32(ubmr, IMXSerialState), - VMSTATE_UINT32(ubrc, IMXSerialState), - VMSTATE_UINT32(ucr3, IMXSerialState), - VMSTATE_END_OF_LIST() - }, -}; - -static void imx_update(IMXSerialState *s) -{ - uint32_t flags; - - flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY); - if (s->ucr1 & UCR1_TXMPTYEN) { - flags |= (s->uts1 & UTS1_TXEMPTY); - } else { - flags &= ~USR1_TRDY; - } - - qemu_set_irq(s->irq, !!flags); -} - -static void imx_serial_reset(IMXSerialState *s) -{ - - s->usr1 = USR1_TRDY | USR1_RXDS; - /* - * Fake attachment of a terminal: assert RTS. - */ - s->usr1 |= USR1_RTSS; - s->usr2 = USR2_TXFE | USR2_TXDC | USR2_DCDIN; - s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY; - s->ucr1 = 0; - s->ucr2 = UCR2_SRST; - s->ucr3 = 0x700; - s->ubmr = 0; - s->ubrc = 4; - s->readbuff = URXD_ERR; -} - -static void imx_serial_reset_at_boot(DeviceState *dev) -{ - IMXSerialState *s = IMX_SERIAL(dev); - - imx_serial_reset(s); - - /* - * enable the uart on boot, so messages from the linux decompresser - * are visible. On real hardware this is done by the boot rom - * before anything else is loaded. - */ - s->ucr1 = UCR1_UARTEN; - s->ucr2 = UCR2_TXEN; - -} - -static uint64_t imx_serial_read(void *opaque, hwaddr offset, - unsigned size) -{ - IMXSerialState *s = (IMXSerialState *)opaque; - uint32_t c; - - DPRINTF("read(offset=0x%" HWADDR_PRIx ")\n", offset); - - switch (offset >> 2) { - case 0x0: /* URXD */ - c = s->readbuff; - if (!(s->uts1 & UTS1_RXEMPTY)) { - /* Character is valid */ - c |= URXD_CHARRDY; - s->usr1 &= ~USR1_RRDY; - s->usr2 &= ~USR2_RDR; - s->uts1 |= UTS1_RXEMPTY; - imx_update(s); - if (s->chr) { - qemu_chr_accept_input(s->chr); - } - } - return c; - - case 0x20: /* UCR1 */ - return s->ucr1; - - case 0x21: /* UCR2 */ - return s->ucr2; - - case 0x25: /* USR1 */ - return s->usr1; - - case 0x26: /* USR2 */ - return s->usr2; - - case 0x2A: /* BRM Modulator */ - return s->ubmr; - - case 0x2B: /* Baud Rate Count */ - return s->ubrc; - - case 0x2d: /* Test register */ - return s->uts1; - - case 0x24: /* UFCR */ - return s->ufcr; - - case 0x2c: - return s->onems; - - case 0x22: /* UCR3 */ - return s->ucr3; - - case 0x23: /* UCR4 */ - case 0x29: /* BRM Incremental */ - return 0x0; /* TODO */ - - default: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset); - return 0; - } -} - -static void imx_serial_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - IMXSerialState *s = (IMXSerialState *)opaque; - unsigned char ch; - - DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n", - offset, (unsigned int)value, s->chr ? s->chr->label : "NODEV"); - - switch (offset >> 2) { - case 0x10: /* UTXD */ - ch = value; - if (s->ucr2 & UCR2_TXEN) { - if (s->chr) { - qemu_chr_fe_write(s->chr, &ch, 1); - } - s->usr1 &= ~USR1_TRDY; - imx_update(s); - s->usr1 |= USR1_TRDY; - imx_update(s); - } - break; - - case 0x20: /* UCR1 */ - s->ucr1 = value & 0xffff; - - DPRINTF("write(ucr1=%x)\n", (unsigned int)value); - - imx_update(s); - break; - - case 0x21: /* UCR2 */ - /* - * Only a few bits in control register 2 are implemented as yet. - * If it's intended to use a real serial device as a back-end, this - * register will have to be implemented more fully. - */ - if (!(value & UCR2_SRST)) { - imx_serial_reset(s); - imx_update(s); - value |= UCR2_SRST; - } - if (value & UCR2_RXEN) { - if (!(s->ucr2 & UCR2_RXEN)) { - if (s->chr) { - qemu_chr_accept_input(s->chr); - } - } - } - s->ucr2 = value & 0xffff; - break; - - case 0x25: /* USR1 */ - value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM | - USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER; - s->usr1 &= ~value; - break; - - case 0x26: /* USR2 */ - /* - * Writing 1 to some bits clears them; all other - * values are ignored - */ - value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST | - USR2_RIDELT | USR2_IRINT | USR2_WAKE | - USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE; - s->usr2 &= ~value; - break; - - /* - * Linux expects to see what it writes to these registers - * We don't currently alter the baud rate - */ - case 0x29: /* UBIR */ - s->ubrc = value & 0xffff; - break; - - case 0x2a: /* UBMR */ - s->ubmr = value & 0xffff; - break; - - case 0x2c: /* One ms reg */ - s->onems = value & 0xffff; - break; - - case 0x24: /* FIFO control register */ - s->ufcr = value & 0xffff; - break; - - case 0x22: /* UCR3 */ - s->ucr3 = value & 0xffff; - break; - - case 0x2d: /* UTS1 */ - case 0x23: /* UCR4 */ - qemu_log_mask(LOG_UNIMP, "[%s]%s: Unimplemented reg 0x%" - HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset); - /* TODO */ - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset); - } -} - -static int imx_can_receive(void *opaque) -{ - IMXSerialState *s = (IMXSerialState *)opaque; - return !(s->usr1 & USR1_RRDY); -} - -static void imx_put_data(void *opaque, uint32_t value) -{ - IMXSerialState *s = (IMXSerialState *)opaque; - - DPRINTF("received char\n"); - - s->usr1 |= USR1_RRDY; - s->usr2 |= USR2_RDR; - s->uts1 &= ~UTS1_RXEMPTY; - s->readbuff = value; - imx_update(s); -} - -static void imx_receive(void *opaque, const uint8_t *buf, int size) -{ - imx_put_data(opaque, *buf); -} - -static void imx_event(void *opaque, int event) -{ - if (event == CHR_EVENT_BREAK) { - imx_put_data(opaque, URXD_BRK); - } -} - - -static const struct MemoryRegionOps imx_serial_ops = { - .read = imx_serial_read, - .write = imx_serial_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void imx_serial_realize(DeviceState *dev, Error **errp) -{ - IMXSerialState *s = IMX_SERIAL(dev); - - if (s->chr) { - qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive, - imx_event, s); - } else { - DPRINTF("No char dev for uart\n"); - } -} - -static void imx_serial_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - IMXSerialState *s = IMX_SERIAL(obj); - - memory_region_init_io(&s->iomem, obj, &imx_serial_ops, s, - TYPE_IMX_SERIAL, 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); -} - -static Property imx_serial_properties[] = { - DEFINE_PROP_CHR("chardev", IMXSerialState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void imx_serial_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = imx_serial_realize; - dc->vmsd = &vmstate_imx_serial; - dc->reset = imx_serial_reset_at_boot; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - dc->desc = "i.MX series UART"; - dc->props = imx_serial_properties; -} - -static const TypeInfo imx_serial_info = { - .name = TYPE_IMX_SERIAL, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMXSerialState), - .instance_init = imx_serial_init, - .class_init = imx_serial_class_init, -}; - -static void imx_serial_register_types(void) -{ - type_register_static(&imx_serial_info); -} - -type_init(imx_serial_register_types) diff --git a/qemu/hw/char/ipoctal232.c b/qemu/hw/char/ipoctal232.c deleted file mode 100644 index bc0ae4980..000000000 --- a/qemu/hw/char/ipoctal232.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * QEMU GE IP-Octal 232 IndustryPack emulation - * - * Copyright (C) 2012 Igalia, S.L. - * Author: Alberto Garcia - * - * This code is licensed under the GNU GPL v2 or (at your option) any - * later version. - */ - -#include "qemu/osdep.h" -#include "hw/ipack/ipack.h" -#include "qemu/bitops.h" -#include "sysemu/char.h" - -/* #define DEBUG_IPOCTAL */ - -#ifdef DEBUG_IPOCTAL -#define DPRINTF2(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF2(fmt, ...) do { } while (0) -#endif - -#define DPRINTF(fmt, ...) DPRINTF2("IP-Octal: " fmt, ## __VA_ARGS__) - -#define RX_FIFO_SIZE 3 - -/* The IP-Octal has 8 channels (a-h) - divided into 4 blocks (A-D) */ -#define N_CHANNELS 8 -#define N_BLOCKS 4 - -#define REG_MRa 0x01 -#define REG_MRb 0x11 -#define REG_SRa 0x03 -#define REG_SRb 0x13 -#define REG_CSRa 0x03 -#define REG_CSRb 0x13 -#define REG_CRa 0x05 -#define REG_CRb 0x15 -#define REG_RHRa 0x07 -#define REG_RHRb 0x17 -#define REG_THRa 0x07 -#define REG_THRb 0x17 -#define REG_ACR 0x09 -#define REG_ISR 0x0B -#define REG_IMR 0x0B -#define REG_OPCR 0x1B - -#define CR_ENABLE_RX BIT(0) -#define CR_DISABLE_RX BIT(1) -#define CR_ENABLE_TX BIT(2) -#define CR_DISABLE_TX BIT(3) -#define CR_CMD(cr) ((cr) >> 4) -#define CR_NO_OP 0 -#define CR_RESET_MR 1 -#define CR_RESET_RX 2 -#define CR_RESET_TX 3 -#define CR_RESET_ERR 4 -#define CR_RESET_BRKINT 5 -#define CR_START_BRK 6 -#define CR_STOP_BRK 7 -#define CR_ASSERT_RTSN 8 -#define CR_NEGATE_RTSN 9 -#define CR_TIMEOUT_ON 10 -#define CR_TIMEOUT_OFF 12 - -#define SR_RXRDY BIT(0) -#define SR_FFULL BIT(1) -#define SR_TXRDY BIT(2) -#define SR_TXEMT BIT(3) -#define SR_OVERRUN BIT(4) -#define SR_PARITY BIT(5) -#define SR_FRAMING BIT(6) -#define SR_BREAK BIT(7) - -#define ISR_TXRDYA BIT(0) -#define ISR_RXRDYA BIT(1) -#define ISR_BREAKA BIT(2) -#define ISR_CNTRDY BIT(3) -#define ISR_TXRDYB BIT(4) -#define ISR_RXRDYB BIT(5) -#define ISR_BREAKB BIT(6) -#define ISR_MPICHG BIT(7) -#define ISR_TXRDY(CH) (((CH) & 1) ? BIT(4) : BIT(0)) -#define ISR_RXRDY(CH) (((CH) & 1) ? BIT(5) : BIT(1)) -#define ISR_BREAK(CH) (((CH) & 1) ? BIT(6) : BIT(2)) - -typedef struct IPOctalState IPOctalState; -typedef struct SCC2698Channel SCC2698Channel; -typedef struct SCC2698Block SCC2698Block; - -struct SCC2698Channel { - IPOctalState *ipoctal; - CharDriverState *dev; - bool rx_enabled; - uint8_t mr[2]; - uint8_t mr_idx; - uint8_t sr; - uint8_t rhr[RX_FIFO_SIZE]; - uint8_t rhr_idx; - uint8_t rx_pending; -}; - -struct SCC2698Block { - uint8_t imr; - uint8_t isr; -}; - -struct IPOctalState { - IPackDevice parent_obj; - - SCC2698Channel ch[N_CHANNELS]; - SCC2698Block blk[N_BLOCKS]; - uint8_t irq_vector; -}; - -#define TYPE_IPOCTAL "ipoctal232" - -#define IPOCTAL(obj) \ - OBJECT_CHECK(IPOctalState, (obj), TYPE_IPOCTAL) - -static const VMStateDescription vmstate_scc2698_channel = { - .name = "scc2698_channel", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_BOOL(rx_enabled, SCC2698Channel), - VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2), - VMSTATE_UINT8(mr_idx, SCC2698Channel), - VMSTATE_UINT8(sr, SCC2698Channel), - VMSTATE_UINT8_ARRAY(rhr, SCC2698Channel, RX_FIFO_SIZE), - VMSTATE_UINT8(rhr_idx, SCC2698Channel), - VMSTATE_UINT8(rx_pending, SCC2698Channel), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_scc2698_block = { - .name = "scc2698_block", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(imr, SCC2698Block), - VMSTATE_UINT8(isr, SCC2698Block), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_ipoctal = { - .name = "ipoctal232", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_IPACK_DEVICE(parent_obj, IPOctalState), - VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1, - vmstate_scc2698_channel, SCC2698Channel), - VMSTATE_STRUCT_ARRAY(blk, IPOctalState, N_BLOCKS, 1, - vmstate_scc2698_block, SCC2698Block), - VMSTATE_UINT8(irq_vector, IPOctalState), - VMSTATE_END_OF_LIST() - } -}; - -/* data[10] is 0x0C, not 0x0B as the doc says */ -static const uint8_t id_prom_data[] = { - 0x49, 0x50, 0x41, 0x43, 0xF0, 0x22, - 0xA1, 0x00, 0x00, 0x00, 0x0C, 0xCC -}; - -static void update_irq(IPOctalState *dev, unsigned block) -{ - IPackDevice *idev = IPACK_DEVICE(dev); - /* Blocks A and B interrupt on INT0#, C and D on INT1#. - Thus, to get the status we have to check two blocks. */ - SCC2698Block *blk0 = &dev->blk[block]; - SCC2698Block *blk1 = &dev->blk[block^1]; - unsigned intno = block / 2; - - if ((blk0->isr & blk0->imr) || (blk1->isr & blk1->imr)) { - qemu_irq_raise(idev->irq[intno]); - } else { - qemu_irq_lower(idev->irq[intno]); - } -} - -static void write_cr(IPOctalState *dev, unsigned channel, uint8_t val) -{ - SCC2698Channel *ch = &dev->ch[channel]; - SCC2698Block *blk = &dev->blk[channel / 2]; - - DPRINTF("Write CR%c %u: ", channel + 'a', val); - - /* The lower 4 bits are used to enable and disable Tx and Rx */ - if (val & CR_ENABLE_RX) { - DPRINTF2("Rx on, "); - ch->rx_enabled = true; - } - if (val & CR_DISABLE_RX) { - DPRINTF2("Rx off, "); - ch->rx_enabled = false; - } - if (val & CR_ENABLE_TX) { - DPRINTF2("Tx on, "); - ch->sr |= SR_TXRDY | SR_TXEMT; - blk->isr |= ISR_TXRDY(channel); - } - if (val & CR_DISABLE_TX) { - DPRINTF2("Tx off, "); - ch->sr &= ~(SR_TXRDY | SR_TXEMT); - blk->isr &= ~ISR_TXRDY(channel); - } - - DPRINTF2("cmd: "); - - /* The rest of the bits implement different commands */ - switch (CR_CMD(val)) { - case CR_NO_OP: - DPRINTF2("none"); - break; - case CR_RESET_MR: - DPRINTF2("reset MR"); - ch->mr_idx = 0; - break; - case CR_RESET_RX: - DPRINTF2("reset Rx"); - ch->rx_enabled = false; - ch->rx_pending = 0; - ch->sr &= ~SR_RXRDY; - blk->isr &= ~ISR_RXRDY(channel); - break; - case CR_RESET_TX: - DPRINTF2("reset Tx"); - ch->sr &= ~(SR_TXRDY | SR_TXEMT); - blk->isr &= ~ISR_TXRDY(channel); - break; - case CR_RESET_ERR: - DPRINTF2("reset err"); - ch->sr &= ~(SR_OVERRUN | SR_PARITY | SR_FRAMING | SR_BREAK); - break; - case CR_RESET_BRKINT: - DPRINTF2("reset brk ch int"); - blk->isr &= ~(ISR_BREAKA | ISR_BREAKB); - break; - default: - DPRINTF2("unsupported 0x%x", CR_CMD(val)); - } - - DPRINTF2("\n"); -} - -static uint16_t io_read(IPackDevice *ip, uint8_t addr) -{ - IPOctalState *dev = IPOCTAL(ip); - uint16_t ret = 0; - /* addr[7:6]: block (A-D) - addr[7:5]: channel (a-h) - addr[5:0]: register */ - unsigned block = addr >> 5; - unsigned channel = addr >> 4; - /* Big endian, accessed using 8-bit bytes at odd locations */ - unsigned offset = (addr & 0x1F) ^ 1; - SCC2698Channel *ch = &dev->ch[channel]; - SCC2698Block *blk = &dev->blk[block]; - uint8_t old_isr = blk->isr; - - switch (offset) { - - case REG_MRa: - case REG_MRb: - ret = ch->mr[ch->mr_idx]; - DPRINTF("Read MR%u%c: 0x%x\n", ch->mr_idx + 1, channel + 'a', ret); - ch->mr_idx = 1; - break; - - case REG_SRa: - case REG_SRb: - ret = ch->sr; - DPRINTF("Read SR%c: 0x%x\n", channel + 'a', ret); - break; - - case REG_RHRa: - case REG_RHRb: - ret = ch->rhr[ch->rhr_idx]; - if (ch->rx_pending > 0) { - ch->rx_pending--; - if (ch->rx_pending == 0) { - ch->sr &= ~SR_RXRDY; - blk->isr &= ~ISR_RXRDY(channel); - if (ch->dev) { - qemu_chr_accept_input(ch->dev); - } - } else { - ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE; - } - if (ch->sr & SR_BREAK) { - ch->sr &= ~SR_BREAK; - blk->isr |= ISR_BREAK(channel); - } - } - DPRINTF("Read RHR%c (0x%x)\n", channel + 'a', ret); - break; - - case REG_ISR: - ret = blk->isr; - DPRINTF("Read ISR%c: 0x%x\n", block + 'A', ret); - break; - - default: - DPRINTF("Read unknown/unsupported register 0x%02x\n", offset); - } - - if (old_isr != blk->isr) { - update_irq(dev, block); - } - - return ret; -} - -static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val) -{ - IPOctalState *dev = IPOCTAL(ip); - unsigned reg = val & 0xFF; - /* addr[7:6]: block (A-D) - addr[7:5]: channel (a-h) - addr[5:0]: register */ - unsigned block = addr >> 5; - unsigned channel = addr >> 4; - /* Big endian, accessed using 8-bit bytes at odd locations */ - unsigned offset = (addr & 0x1F) ^ 1; - SCC2698Channel *ch = &dev->ch[channel]; - SCC2698Block *blk = &dev->blk[block]; - uint8_t old_isr = blk->isr; - uint8_t old_imr = blk->imr; - - switch (offset) { - - case REG_MRa: - case REG_MRb: - ch->mr[ch->mr_idx] = reg; - DPRINTF("Write MR%u%c 0x%x\n", ch->mr_idx + 1, channel + 'a', reg); - ch->mr_idx = 1; - break; - - /* Not implemented */ - case REG_CSRa: - case REG_CSRb: - DPRINTF("Write CSR%c: 0x%x\n", channel + 'a', reg); - break; - - case REG_CRa: - case REG_CRb: - write_cr(dev, channel, reg); - break; - - case REG_THRa: - case REG_THRb: - if (ch->sr & SR_TXRDY) { - DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg); - if (ch->dev) { - uint8_t thr = reg; - qemu_chr_fe_write(ch->dev, &thr, 1); - } - } else { - DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg); - } - break; - - /* Not implemented */ - case REG_ACR: - DPRINTF("Write ACR%c 0x%x\n", block + 'A', val); - break; - - case REG_IMR: - DPRINTF("Write IMR%c 0x%x\n", block + 'A', val); - blk->imr = reg; - break; - - /* Not implemented */ - case REG_OPCR: - DPRINTF("Write OPCR%c 0x%x\n", block + 'A', val); - break; - - default: - DPRINTF("Write unknown/unsupported register 0x%02x %u\n", offset, val); - } - - if (old_isr != blk->isr || old_imr != blk->imr) { - update_irq(dev, block); - } -} - -static uint16_t id_read(IPackDevice *ip, uint8_t addr) -{ - uint16_t ret = 0; - unsigned pos = addr / 2; /* The ID PROM data is stored every other byte */ - - if (pos < ARRAY_SIZE(id_prom_data)) { - ret = id_prom_data[pos]; - } else { - DPRINTF("Attempt to read unavailable PROM data at 0x%x\n", addr); - } - - return ret; -} - -static void id_write(IPackDevice *ip, uint8_t addr, uint16_t val) -{ - IPOctalState *dev = IPOCTAL(ip); - if (addr == 1) { - DPRINTF("Write IRQ vector: %u\n", (unsigned) val); - dev->irq_vector = val; /* Undocumented, but the hw works like that */ - } else { - DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr); - } -} - -static uint16_t int_read(IPackDevice *ip, uint8_t addr) -{ - IPOctalState *dev = IPOCTAL(ip); - /* Read address 0 to ACK INT0# and address 2 to ACK INT1# */ - if (addr != 0 && addr != 2) { - DPRINTF("Attempt to read from 0x%x\n", addr); - return 0; - } else { - /* Update interrupts if necessary */ - update_irq(dev, addr); - return dev->irq_vector; - } -} - -static void int_write(IPackDevice *ip, uint8_t addr, uint16_t val) -{ - DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr); -} - -static uint16_t mem_read16(IPackDevice *ip, uint32_t addr) -{ - DPRINTF("Attempt to read from 0x%x\n", addr); - return 0; -} - -static void mem_write16(IPackDevice *ip, uint32_t addr, uint16_t val) -{ - DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr); -} - -static uint8_t mem_read8(IPackDevice *ip, uint32_t addr) -{ - DPRINTF("Attempt to read from 0x%x\n", addr); - return 0; -} - -static void mem_write8(IPackDevice *ip, uint32_t addr, uint8_t val) -{ - IPOctalState *dev = IPOCTAL(ip); - if (addr == 1) { - DPRINTF("Write IRQ vector: %u\n", (unsigned) val); - dev->irq_vector = val; - } else { - DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr); - } -} - -static int hostdev_can_receive(void *opaque) -{ - SCC2698Channel *ch = opaque; - int available_bytes = RX_FIFO_SIZE - ch->rx_pending; - return ch->rx_enabled ? available_bytes : 0; -} - -static void hostdev_receive(void *opaque, const uint8_t *buf, int size) -{ - SCC2698Channel *ch = opaque; - IPOctalState *dev = ch->ipoctal; - unsigned pos = ch->rhr_idx + ch->rx_pending; - int i; - - assert(size + ch->rx_pending <= RX_FIFO_SIZE); - - /* Copy data to the RxFIFO */ - for (i = 0; i < size; i++) { - pos %= RX_FIFO_SIZE; - ch->rhr[pos++] = buf[i]; - } - - ch->rx_pending += size; - - /* If the RxFIFO was empty raise an interrupt */ - if (!(ch->sr & SR_RXRDY)) { - unsigned block, channel = 0; - /* Find channel number to update the ISR register */ - while (&dev->ch[channel] != ch) { - channel++; - } - block = channel / 2; - dev->blk[block].isr |= ISR_RXRDY(channel); - ch->sr |= SR_RXRDY; - update_irq(dev, block); - } -} - -static void hostdev_event(void *opaque, int event) -{ - SCC2698Channel *ch = opaque; - switch (event) { - case CHR_EVENT_OPENED: - DPRINTF("Device %s opened\n", ch->dev->label); - break; - case CHR_EVENT_BREAK: { - uint8_t zero = 0; - DPRINTF("Device %s received break\n", ch->dev->label); - - if (!(ch->sr & SR_BREAK)) { - IPOctalState *dev = ch->ipoctal; - unsigned block, channel = 0; - - while (&dev->ch[channel] != ch) { - channel++; - } - block = channel / 2; - - ch->sr |= SR_BREAK; - dev->blk[block].isr |= ISR_BREAK(channel); - } - - /* Put a zero character in the buffer */ - hostdev_receive(ch, &zero, 1); - } - break; - default: - DPRINTF("Device %s received event %d\n", ch->dev->label, event); - } -} - -static void ipoctal_realize(DeviceState *dev, Error **errp) -{ - IPOctalState *s = IPOCTAL(dev); - unsigned i; - - for (i = 0; i < N_CHANNELS; i++) { - SCC2698Channel *ch = &s->ch[i]; - ch->ipoctal = s; - - /* Redirect IP-Octal channels to host character devices */ - if (ch->dev) { - qemu_chr_add_handlers(ch->dev, hostdev_can_receive, - hostdev_receive, hostdev_event, ch); - DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label); - } else { - DPRINTF("Could not redirect channel %u, no chardev set\n", i); - } - } -} - -static Property ipoctal_properties[] = { - DEFINE_PROP_CHR("chardev0", IPOctalState, ch[0].dev), - DEFINE_PROP_CHR("chardev1", IPOctalState, ch[1].dev), - DEFINE_PROP_CHR("chardev2", IPOctalState, ch[2].dev), - DEFINE_PROP_CHR("chardev3", IPOctalState, ch[3].dev), - DEFINE_PROP_CHR("chardev4", IPOctalState, ch[4].dev), - DEFINE_PROP_CHR("chardev5", IPOctalState, ch[5].dev), - DEFINE_PROP_CHR("chardev6", IPOctalState, ch[6].dev), - DEFINE_PROP_CHR("chardev7", IPOctalState, ch[7].dev), - DEFINE_PROP_END_OF_LIST(), -}; - -static void ipoctal_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass); - - ic->realize = ipoctal_realize; - ic->io_read = io_read; - ic->io_write = io_write; - ic->id_read = id_read; - ic->id_write = id_write; - ic->int_read = int_read; - ic->int_write = int_write; - ic->mem_read16 = mem_read16; - ic->mem_write16 = mem_write16; - ic->mem_read8 = mem_read8; - ic->mem_write8 = mem_write8; - - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - dc->desc = "GE IP-Octal 232 8-channel RS-232 IndustryPack"; - dc->props = ipoctal_properties; - dc->vmsd = &vmstate_ipoctal; -} - -static const TypeInfo ipoctal_info = { - .name = TYPE_IPOCTAL, - .parent = TYPE_IPACK_DEVICE, - .instance_size = sizeof(IPOctalState), - .class_init = ipoctal_class_init, -}; - -static void ipoctal_register_types(void) -{ - type_register_static(&ipoctal_info); -} - -type_init(ipoctal_register_types) diff --git a/qemu/hw/char/lm32_juart.c b/qemu/hw/char/lm32_juart.c deleted file mode 100644 index 5bf8acfe8..000000000 --- a/qemu/hw/char/lm32_juart.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * LatticeMico32 JTAG UART model. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "sysemu/char.h" - -#include "hw/char/lm32_juart.h" - -enum { - LM32_JUART_MIN_SAVE_VERSION = 0, - LM32_JUART_CURRENT_SAVE_VERSION = 0, - LM32_JUART_MAX_SAVE_VERSION = 0, -}; - -enum { - JTX_FULL = (1<<8), -}; - -enum { - JRX_FULL = (1<<8), -}; - -#define LM32_JUART(obj) OBJECT_CHECK(LM32JuartState, (obj), TYPE_LM32_JUART) - -struct LM32JuartState { - SysBusDevice parent_obj; - - CharDriverState *chr; - - uint32_t jtx; - uint32_t jrx; -}; -typedef struct LM32JuartState LM32JuartState; - -uint32_t lm32_juart_get_jtx(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_get_jtx(s->jtx); - return s->jtx; -} - -uint32_t lm32_juart_get_jrx(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_get_jrx(s->jrx); - return s->jrx; -} - -void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx) -{ - LM32JuartState *s = LM32_JUART(d); - unsigned char ch = jtx & 0xff; - - trace_lm32_juart_set_jtx(s->jtx); - - s->jtx = jtx; - if (s->chr) { - qemu_chr_fe_write_all(s->chr, &ch, 1); - } -} - -void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_set_jrx(s->jrx); - s->jrx &= ~JRX_FULL; -} - -static void juart_rx(void *opaque, const uint8_t *buf, int size) -{ - LM32JuartState *s = opaque; - - s->jrx = *buf | JRX_FULL; -} - -static int juart_can_rx(void *opaque) -{ - LM32JuartState *s = opaque; - - return !(s->jrx & JRX_FULL); -} - -static void juart_event(void *opaque, int event) -{ -} - -static void juart_reset(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - s->jtx = 0; - s->jrx = 0; -} - -static int lm32_juart_init(SysBusDevice *dev) -{ - LM32JuartState *s = LM32_JUART(dev); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - if (s->chr) { - qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); - } - - return 0; -} - -static const VMStateDescription vmstate_lm32_juart = { - .name = "lm32-juart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(jtx, LM32JuartState), - VMSTATE_UINT32(jrx, LM32JuartState), - VMSTATE_END_OF_LIST() - } -}; - -static void lm32_juart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = lm32_juart_init; - dc->reset = juart_reset; - dc->vmsd = &vmstate_lm32_juart; - /* Reason: init() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo lm32_juart_info = { - .name = TYPE_LM32_JUART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32JuartState), - .class_init = lm32_juart_class_init, -}; - -static void lm32_juart_register_types(void) -{ - type_register_static(&lm32_juart_info); -} - -type_init(lm32_juart_register_types) diff --git a/qemu/hw/char/lm32_uart.c b/qemu/hw/char/lm32_uart.c deleted file mode 100644 index 036813d0f..000000000 --- a/qemu/hw/char/lm32_uart.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * QEMU model of the LatticeMico32 UART block. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://www.latticesemi.com/documents/mico32uart.pdf - */ - - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "sysemu/char.h" -#include "qemu/error-report.h" - -enum { - R_RXTX = 0, - R_IER, - R_IIR, - R_LCR, - R_MCR, - R_LSR, - R_MSR, - R_DIV, - R_MAX -}; - -enum { - IER_RBRI = (1<<0), - IER_THRI = (1<<1), - IER_RLSI = (1<<2), - IER_MSI = (1<<3), -}; - -enum { - IIR_STAT = (1<<0), - IIR_ID0 = (1<<1), - IIR_ID1 = (1<<2), -}; - -enum { - LCR_WLS0 = (1<<0), - LCR_WLS1 = (1<<1), - LCR_STB = (1<<2), - LCR_PEN = (1<<3), - LCR_EPS = (1<<4), - LCR_SP = (1<<5), - LCR_SB = (1<<6), -}; - -enum { - MCR_DTR = (1<<0), - MCR_RTS = (1<<1), -}; - -enum { - LSR_DR = (1<<0), - LSR_OE = (1<<1), - LSR_PE = (1<<2), - LSR_FE = (1<<3), - LSR_BI = (1<<4), - LSR_THRE = (1<<5), - LSR_TEMT = (1<<6), -}; - -enum { - MSR_DCTS = (1<<0), - MSR_DDSR = (1<<1), - MSR_TERI = (1<<2), - MSR_DDCD = (1<<3), - MSR_CTS = (1<<4), - MSR_DSR = (1<<5), - MSR_RI = (1<<6), - MSR_DCD = (1<<7), -}; - -#define TYPE_LM32_UART "lm32-uart" -#define LM32_UART(obj) OBJECT_CHECK(LM32UartState, (obj), TYPE_LM32_UART) - -struct LM32UartState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - CharDriverState *chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; -}; -typedef struct LM32UartState LM32UartState; - -static void uart_update_irq(LM32UartState *s) -{ - unsigned int irq; - - if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) - && (s->regs[R_IER] & IER_RLSI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID1 | IIR_ID0; - } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID1; - } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID0; - } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) { - irq = 1; - s->regs[R_IIR] = 0; - } else { - irq = 0; - s->regs[R_IIR] = IIR_STAT; - } - - trace_lm32_uart_irq_state(irq); - qemu_set_irq(s->irq, irq); -} - -static uint64_t uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - LM32UartState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_RXTX: - r = s->regs[R_RXTX]; - s->regs[R_LSR] &= ~LSR_DR; - uart_update_irq(s); - qemu_chr_accept_input(s->chr); - break; - case R_IIR: - case R_LSR: - case R_MSR: - r = s->regs[addr]; - break; - case R_IER: - case R_LCR: - case R_MCR: - case R_DIV: - error_report("lm32_uart: read access to write only register 0x" - TARGET_FMT_plx, addr << 2); - break; - default: - error_report("lm32_uart: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_lm32_uart_memory_read(addr << 2, r); - return r; -} - -static void uart_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - LM32UartState *s = opaque; - unsigned char ch = value; - - trace_lm32_uart_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_RXTX: - if (s->chr) { - qemu_chr_fe_write_all(s->chr, &ch, 1); - } - break; - case R_IER: - case R_LCR: - case R_MCR: - case R_DIV: - s->regs[addr] = value; - break; - case R_IIR: - case R_LSR: - case R_MSR: - error_report("lm32_uart: write access to read only register 0x" - TARGET_FMT_plx, addr << 2); - break; - default: - error_report("lm32_uart: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - uart_update_irq(s); -} - -static const MemoryRegionOps uart_ops = { - .read = uart_read, - .write = uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - LM32UartState *s = opaque; - - if (s->regs[R_LSR] & LSR_DR) { - s->regs[R_LSR] |= LSR_OE; - } - - s->regs[R_LSR] |= LSR_DR; - s->regs[R_RXTX] = *buf; - - uart_update_irq(s); -} - -static int uart_can_rx(void *opaque) -{ - LM32UartState *s = opaque; - - return !(s->regs[R_LSR] & LSR_DR); -} - -static void uart_event(void *opaque, int event) -{ -} - -static void uart_reset(DeviceState *d) -{ - LM32UartState *s = LM32_UART(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* defaults */ - s->regs[R_LSR] = LSR_THRE | LSR_TEMT; -} - -static int lm32_uart_init(SysBusDevice *dev) -{ - LM32UartState *s = LM32_UART(dev); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->iomem, OBJECT(s), &uart_ops, s, - "uart", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - if (s->chr) { - qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); - } - - return 0; -} - -static const VMStateDescription vmstate_lm32_uart = { - .name = "lm32-uart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void lm32_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = lm32_uart_init; - dc->reset = uart_reset; - dc->vmsd = &vmstate_lm32_uart; - /* Reason: init() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo lm32_uart_info = { - .name = TYPE_LM32_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32UartState), - .class_init = lm32_uart_class_init, -}; - -static void lm32_uart_register_types(void) -{ - type_register_static(&lm32_uart_info); -} - -type_init(lm32_uart_register_types) diff --git a/qemu/hw/char/mcf_uart.c b/qemu/hw/char/mcf_uart.c deleted file mode 100644 index 3c0438fd7..000000000 --- a/qemu/hw/char/mcf_uart.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * ColdFire UART emulation. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/m68k/mcf.h" -#include "sysemu/char.h" -#include "exec/address-spaces.h" - -typedef struct { - MemoryRegion iomem; - uint8_t mr[2]; - uint8_t sr; - uint8_t isr; - uint8_t imr; - uint8_t bg1; - uint8_t bg2; - uint8_t fifo[4]; - uint8_t tb; - int current_mr; - int fifo_len; - int tx_enabled; - int rx_enabled; - qemu_irq irq; - CharDriverState *chr; -} mcf_uart_state; - -/* UART Status Register bits. */ -#define MCF_UART_RxRDY 0x01 -#define MCF_UART_FFULL 0x02 -#define MCF_UART_TxRDY 0x04 -#define MCF_UART_TxEMP 0x08 -#define MCF_UART_OE 0x10 -#define MCF_UART_PE 0x20 -#define MCF_UART_FE 0x40 -#define MCF_UART_RB 0x80 - -/* Interrupt flags. */ -#define MCF_UART_TxINT 0x01 -#define MCF_UART_RxINT 0x02 -#define MCF_UART_DBINT 0x04 -#define MCF_UART_COSINT 0x80 - -/* UMR1 flags. */ -#define MCF_UART_BC0 0x01 -#define MCF_UART_BC1 0x02 -#define MCF_UART_PT 0x04 -#define MCF_UART_PM0 0x08 -#define MCF_UART_PM1 0x10 -#define MCF_UART_ERR 0x20 -#define MCF_UART_RxIRQ 0x40 -#define MCF_UART_RxRTS 0x80 - -static void mcf_uart_update(mcf_uart_state *s) -{ - s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT); - if (s->sr & MCF_UART_TxRDY) - s->isr |= MCF_UART_TxINT; - if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ) - ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0) - s->isr |= MCF_UART_RxINT; - - qemu_set_irq(s->irq, (s->isr & s->imr) != 0); -} - -uint64_t mcf_uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - mcf_uart_state *s = (mcf_uart_state *)opaque; - switch (addr & 0x3f) { - case 0x00: - return s->mr[s->current_mr]; - case 0x04: - return s->sr; - case 0x0c: - { - uint8_t val; - int i; - - if (s->fifo_len == 0) - return 0; - - val = s->fifo[0]; - s->fifo_len--; - for (i = 0; i < s->fifo_len; i++) - s->fifo[i] = s->fifo[i + 1]; - s->sr &= ~MCF_UART_FFULL; - if (s->fifo_len == 0) - s->sr &= ~MCF_UART_RxRDY; - mcf_uart_update(s); - qemu_chr_accept_input(s->chr); - return val; - } - case 0x10: - /* TODO: Implement IPCR. */ - return 0; - case 0x14: - return s->isr; - case 0x18: - return s->bg1; - case 0x1c: - return s->bg2; - default: - return 0; - } -} - -/* Update TxRDY flag and set data if present and enabled. */ -static void mcf_uart_do_tx(mcf_uart_state *s) -{ - if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { - if (s->chr) - qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1); - s->sr |= MCF_UART_TxEMP; - } - if (s->tx_enabled) { - s->sr |= MCF_UART_TxRDY; - } else { - s->sr &= ~MCF_UART_TxRDY; - } -} - -static void mcf_do_command(mcf_uart_state *s, uint8_t cmd) -{ - /* Misc command. */ - switch ((cmd >> 4) & 7) { - case 0: /* No-op. */ - break; - case 1: /* Reset mode register pointer. */ - s->current_mr = 0; - break; - case 2: /* Reset receiver. */ - s->rx_enabled = 0; - s->fifo_len = 0; - s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL); - break; - case 3: /* Reset transmitter. */ - s->tx_enabled = 0; - s->sr |= MCF_UART_TxEMP; - s->sr &= ~MCF_UART_TxRDY; - break; - case 4: /* Reset error status. */ - break; - case 5: /* Reset break-change interrupt. */ - s->isr &= ~MCF_UART_DBINT; - break; - case 6: /* Start break. */ - case 7: /* Stop break. */ - break; - } - - /* Transmitter command. */ - switch ((cmd >> 2) & 3) { - case 0: /* No-op. */ - break; - case 1: /* Enable. */ - s->tx_enabled = 1; - mcf_uart_do_tx(s); - break; - case 2: /* Disable. */ - s->tx_enabled = 0; - mcf_uart_do_tx(s); - break; - case 3: /* Reserved. */ - fprintf(stderr, "mcf_uart: Bad TX command\n"); - break; - } - - /* Receiver command. */ - switch (cmd & 3) { - case 0: /* No-op. */ - break; - case 1: /* Enable. */ - s->rx_enabled = 1; - break; - case 2: - s->rx_enabled = 0; - break; - case 3: /* Reserved. */ - fprintf(stderr, "mcf_uart: Bad RX command\n"); - break; - } -} - -void mcf_uart_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - mcf_uart_state *s = (mcf_uart_state *)opaque; - switch (addr & 0x3f) { - case 0x00: - s->mr[s->current_mr] = val; - s->current_mr = 1; - break; - case 0x04: - /* CSR is ignored. */ - break; - case 0x08: /* Command Register. */ - mcf_do_command(s, val); - break; - case 0x0c: /* Transmit Buffer. */ - s->sr &= ~MCF_UART_TxEMP; - s->tb = val; - mcf_uart_do_tx(s); - break; - case 0x10: - /* ACR is ignored. */ - break; - case 0x14: - s->imr = val; - break; - default: - break; - } - mcf_uart_update(s); -} - -static void mcf_uart_reset(mcf_uart_state *s) -{ - s->fifo_len = 0; - s->mr[0] = 0; - s->mr[1] = 0; - s->sr = MCF_UART_TxEMP; - s->tx_enabled = 0; - s->rx_enabled = 0; - s->isr = 0; - s->imr = 0; -} - -static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data) -{ - /* Break events overwrite the last byte if the fifo is full. */ - if (s->fifo_len == 4) - s->fifo_len--; - - s->fifo[s->fifo_len] = data; - s->fifo_len++; - s->sr |= MCF_UART_RxRDY; - if (s->fifo_len == 4) - s->sr |= MCF_UART_FFULL; - - mcf_uart_update(s); -} - -static void mcf_uart_event(void *opaque, int event) -{ - mcf_uart_state *s = (mcf_uart_state *)opaque; - - switch (event) { - case CHR_EVENT_BREAK: - s->isr |= MCF_UART_DBINT; - mcf_uart_push_byte(s, 0); - break; - default: - break; - } -} - -static int mcf_uart_can_receive(void *opaque) -{ - mcf_uart_state *s = (mcf_uart_state *)opaque; - - return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0; -} - -static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) -{ - mcf_uart_state *s = (mcf_uart_state *)opaque; - - mcf_uart_push_byte(s, buf[0]); -} - -void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) -{ - mcf_uart_state *s; - - s = g_malloc0(sizeof(mcf_uart_state)); - s->chr = chr; - s->irq = irq; - if (chr) { - qemu_chr_fe_claim_no_fail(chr); - qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, - mcf_uart_event, s); - } - mcf_uart_reset(s); - return s; -} - -static const MemoryRegionOps mcf_uart_ops = { - .read = mcf_uart_read, - .write = mcf_uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -void mcf_uart_mm_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, - CharDriverState *chr) -{ - mcf_uart_state *s; - - s = mcf_uart_init(irq, chr); - memory_region_init_io(&s->iomem, NULL, &mcf_uart_ops, s, "uart", 0x40); - memory_region_add_subregion(sysmem, base, &s->iomem); -} diff --git a/qemu/hw/char/milkymist-uart.c b/qemu/hw/char/milkymist-uart.c deleted file mode 100644 index 03b36b223..000000000 --- a/qemu/hw/char/milkymist-uart.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * QEMU model of the Milkymist UART block. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://www.milkymist.org/socdoc/uart.pdf - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "sysemu/char.h" -#include "qemu/error-report.h" - -enum { - R_RXTX = 0, - R_DIV, - R_STAT, - R_CTRL, - R_DBG, - R_MAX -}; - -enum { - STAT_THRE = (1<<0), - STAT_RX_EVT = (1<<1), - STAT_TX_EVT = (1<<2), -}; - -enum { - CTRL_RX_IRQ_EN = (1<<0), - CTRL_TX_IRQ_EN = (1<<1), - CTRL_THRU_EN = (1<<2), -}; - -enum { - DBG_BREAK_EN = (1<<0), -}; - -#define TYPE_MILKYMIST_UART "milkymist-uart" -#define MILKYMIST_UART(obj) \ - OBJECT_CHECK(MilkymistUartState, (obj), TYPE_MILKYMIST_UART) - -struct MilkymistUartState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - CharDriverState *chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; -}; -typedef struct MilkymistUartState MilkymistUartState; - -static void uart_update_irq(MilkymistUartState *s) -{ - int rx_event = s->regs[R_STAT] & STAT_RX_EVT; - int tx_event = s->regs[R_STAT] & STAT_TX_EVT; - int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN; - int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN; - - if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) { - trace_milkymist_uart_raise_irq(); - qemu_irq_raise(s->irq); - } else { - trace_milkymist_uart_lower_irq(); - qemu_irq_lower(s->irq); - } -} - -static uint64_t uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistUartState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_RXTX: - r = s->regs[addr]; - break; - case R_DIV: - case R_STAT: - case R_CTRL: - case R_DBG: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_uart: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_uart_memory_read(addr << 2, r); - - return r; -} - -static void uart_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistUartState *s = opaque; - unsigned char ch = value; - - trace_milkymist_uart_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_RXTX: - if (s->chr) { - qemu_chr_fe_write_all(s->chr, &ch, 1); - } - s->regs[R_STAT] |= STAT_TX_EVT; - break; - case R_DIV: - case R_CTRL: - case R_DBG: - s->regs[addr] = value; - break; - - case R_STAT: - /* write one to clear bits */ - s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT)); - qemu_chr_accept_input(s->chr); - break; - - default: - error_report("milkymist_uart: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - uart_update_irq(s); -} - -static const MemoryRegionOps uart_mmio_ops = { - .read = uart_read, - .write = uart_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - MilkymistUartState *s = opaque; - - assert(!(s->regs[R_STAT] & STAT_RX_EVT)); - - s->regs[R_STAT] |= STAT_RX_EVT; - s->regs[R_RXTX] = *buf; - - uart_update_irq(s); -} - -static int uart_can_rx(void *opaque) -{ - MilkymistUartState *s = opaque; - - return !(s->regs[R_STAT] & STAT_RX_EVT); -} - -static void uart_event(void *opaque, int event) -{ -} - -static void milkymist_uart_reset(DeviceState *d) -{ - MilkymistUartState *s = MILKYMIST_UART(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* THRE is always set */ - s->regs[R_STAT] = STAT_THRE; -} - -static void milkymist_uart_realize(DeviceState *dev, Error **errp) -{ - MilkymistUartState *s = MILKYMIST_UART(dev); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - if (s->chr) { - qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); - } -} - -static void milkymist_uart_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - MilkymistUartState *s = MILKYMIST_UART(obj); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s, - "milkymist-uart", R_MAX * 4); - sysbus_init_mmio(sbd, &s->regs_region); -} - -static const VMStateDescription vmstate_milkymist_uart = { - .name = "milkymist-uart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_uart_realize; - dc->reset = milkymist_uart_reset; - dc->vmsd = &vmstate_milkymist_uart; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo milkymist_uart_info = { - .name = TYPE_MILKYMIST_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistUartState), - .instance_init = milkymist_uart_init, - .class_init = milkymist_uart_class_init, -}; - -static void milkymist_uart_register_types(void) -{ - type_register_static(&milkymist_uart_info); -} - -type_init(milkymist_uart_register_types) diff --git a/qemu/hw/char/omap_uart.c b/qemu/hw/char/omap_uart.c deleted file mode 100644 index 415bec5fa..000000000 --- a/qemu/hw/char/omap_uart.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * TI OMAP processors UART emulation. - * - * Copyright (C) 2006-2008 Andrzej Zaborowski - * Copyright (C) 2007-2009 Nokia Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ -#include "qemu/osdep.h" -#include "sysemu/char.h" -#include "hw/hw.h" -#include "hw/arm/omap.h" -#include "hw/char/serial.h" -#include "exec/address-spaces.h" - -/* UARTs */ -struct omap_uart_s { - MemoryRegion iomem; - hwaddr base; - SerialState *serial; /* TODO */ - struct omap_target_agent_s *ta; - omap_clk fclk; - qemu_irq irq; - - uint8_t eblr; - uint8_t syscontrol; - uint8_t wkup; - uint8_t cfps; - uint8_t mdr[2]; - uint8_t scr; - uint8_t clksel; -}; - -void omap_uart_reset(struct omap_uart_s *s) -{ - s->eblr = 0x00; - s->syscontrol = 0; - s->wkup = 0x3f; - s->cfps = 0x69; - s->clksel = 0; -} - -struct omap_uart_s *omap_uart_init(hwaddr base, - qemu_irq irq, omap_clk fclk, omap_clk iclk, - qemu_irq txdma, qemu_irq rxdma, - const char *label, CharDriverState *chr) -{ - struct omap_uart_s *s = g_new0(struct omap_uart_s, 1); - - s->base = base; - s->fclk = fclk; - s->irq = irq; - s->serial = serial_mm_init(get_system_memory(), base, 2, irq, - omap_clk_getrate(fclk)/16, - chr ?: qemu_chr_new(label, "null", NULL), - DEVICE_NATIVE_ENDIAN); - return s; -} - -static uint64_t omap_uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - struct omap_uart_s *s = (struct omap_uart_s *) opaque; - - if (size == 4) { - return omap_badwidth_read8(opaque, addr); - } - - switch (addr) { - case 0x20: /* MDR1 */ - return s->mdr[0]; - case 0x24: /* MDR2 */ - return s->mdr[1]; - case 0x40: /* SCR */ - return s->scr; - case 0x44: /* SSR */ - return 0x0; - case 0x48: /* EBLR (OMAP2) */ - return s->eblr; - case 0x4C: /* OSC_12M_SEL (OMAP1) */ - return s->clksel; - case 0x50: /* MVR */ - return 0x30; - case 0x54: /* SYSC (OMAP2) */ - return s->syscontrol; - case 0x58: /* SYSS (OMAP2) */ - return 1; - case 0x5c: /* WER (OMAP2) */ - return s->wkup; - case 0x60: /* CFPS (OMAP2) */ - return s->cfps; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_uart_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - struct omap_uart_s *s = (struct omap_uart_s *) opaque; - - if (size == 4) { - omap_badwidth_write8(opaque, addr, value); - return; - } - - switch (addr) { - case 0x20: /* MDR1 */ - s->mdr[0] = value & 0x7f; - break; - case 0x24: /* MDR2 */ - s->mdr[1] = value & 0xff; - break; - case 0x40: /* SCR */ - s->scr = value & 0xff; - break; - case 0x48: /* EBLR (OMAP2) */ - s->eblr = value & 0xff; - break; - case 0x4C: /* OSC_12M_SEL (OMAP1) */ - s->clksel = value & 1; - break; - case 0x44: /* SSR */ - case 0x50: /* MVR */ - case 0x58: /* SYSS (OMAP2) */ - OMAP_RO_REG(addr); - break; - case 0x54: /* SYSC (OMAP2) */ - s->syscontrol = value & 0x1d; - if (value & 2) - omap_uart_reset(s); - break; - case 0x5c: /* WER (OMAP2) */ - s->wkup = value & 0x7f; - break; - case 0x60: /* CFPS (OMAP2) */ - s->cfps = value & 0xff; - break; - default: - OMAP_BAD_REG(addr); - } -} - -static const MemoryRegionOps omap_uart_ops = { - .read = omap_uart_read, - .write = omap_uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem, - struct omap_target_agent_s *ta, - qemu_irq irq, omap_clk fclk, omap_clk iclk, - qemu_irq txdma, qemu_irq rxdma, - const char *label, CharDriverState *chr) -{ - hwaddr base = omap_l4_attach(ta, 0, NULL); - struct omap_uart_s *s = omap_uart_init(base, irq, - fclk, iclk, txdma, rxdma, label, chr); - - memory_region_init_io(&s->iomem, NULL, &omap_uart_ops, s, "omap.uart", 0x100); - - s->ta = ta; - - memory_region_add_subregion(sysmem, base + 0x20, &s->iomem); - - return s; -} - -void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr) -{ - /* TODO: Should reuse or destroy current s->serial */ - s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq, - omap_clk_getrate(s->fclk) / 16, - chr ?: qemu_chr_new("null", "null", NULL), - DEVICE_NATIVE_ENDIAN); -} diff --git a/qemu/hw/char/parallel.c b/qemu/hw/char/parallel.c deleted file mode 100644 index 11c78fed8..000000000 --- a/qemu/hw/char/parallel.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * QEMU Parallel PORT emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * Copyright (c) 2007 Marko Kohtala - * - * 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. - */ -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "sysemu/char.h" -#include "hw/isa/isa.h" -#include "hw/i386/pc.h" -#include "sysemu/sysemu.h" - -//#define DEBUG_PARALLEL - -#ifdef DEBUG_PARALLEL -#define pdebug(fmt, ...) printf("pp: " fmt, ## __VA_ARGS__) -#else -#define pdebug(fmt, ...) ((void)0) -#endif - -#define PARA_REG_DATA 0 -#define PARA_REG_STS 1 -#define PARA_REG_CTR 2 -#define PARA_REG_EPP_ADDR 3 -#define PARA_REG_EPP_DATA 4 - -/* - * These are the definitions for the Printer Status Register - */ -#define PARA_STS_BUSY 0x80 /* Busy complement */ -#define PARA_STS_ACK 0x40 /* Acknowledge */ -#define PARA_STS_PAPER 0x20 /* Out of paper */ -#define PARA_STS_ONLINE 0x10 /* Online */ -#define PARA_STS_ERROR 0x08 /* Error complement */ -#define PARA_STS_TMOUT 0x01 /* EPP timeout */ - -/* - * These are the definitions for the Printer Control Register - */ -#define PARA_CTR_DIR 0x20 /* Direction (1=read, 0=write) */ -#define PARA_CTR_INTEN 0x10 /* IRQ Enable */ -#define PARA_CTR_SELECT 0x08 /* Select In complement */ -#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */ -#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */ -#define PARA_CTR_STROBE 0x01 /* Strobe complement */ - -#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE) - -typedef struct ParallelState { - MemoryRegion iomem; - uint8_t dataw; - uint8_t datar; - uint8_t status; - uint8_t control; - qemu_irq irq; - int irq_pending; - CharDriverState *chr; - int hw_driver; - int epp_timeout; - uint32_t last_read_offset; /* For debugging */ - /* Memory-mapped interface */ - int it_shift; -} ParallelState; - -#define TYPE_ISA_PARALLEL "isa-parallel" -#define ISA_PARALLEL(obj) \ - OBJECT_CHECK(ISAParallelState, (obj), TYPE_ISA_PARALLEL) - -typedef struct ISAParallelState { - ISADevice parent_obj; - - uint32_t index; - uint32_t iobase; - uint32_t isairq; - ParallelState state; -} ISAParallelState; - -static void parallel_update_irq(ParallelState *s) -{ - if (s->irq_pending) - qemu_irq_raise(s->irq); - else - qemu_irq_lower(s->irq); -} - -static void -parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val) -{ - ParallelState *s = opaque; - - pdebug("write addr=0x%02x val=0x%02x\n", addr, val); - - addr &= 7; - switch(addr) { - case PARA_REG_DATA: - s->dataw = val; - parallel_update_irq(s); - break; - case PARA_REG_CTR: - val |= 0xc0; - if ((val & PARA_CTR_INIT) == 0 ) { - s->status = PARA_STS_BUSY; - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_ONLINE; - s->status |= PARA_STS_ERROR; - } - else if (val & PARA_CTR_SELECT) { - if (val & PARA_CTR_STROBE) { - s->status &= ~PARA_STS_BUSY; - if ((s->control & PARA_CTR_STROBE) == 0) - qemu_chr_fe_write(s->chr, &s->dataw, 1); - } else { - if (s->control & PARA_CTR_INTEN) { - s->irq_pending = 1; - } - } - } - parallel_update_irq(s); - s->control = val; - break; - } -} - -static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val) -{ - ParallelState *s = opaque; - uint8_t parm = val; - int dir; - - /* Sometimes programs do several writes for timing purposes on old - HW. Take care not to waste time on writes that do nothing. */ - - s->last_read_offset = ~0U; - - addr &= 7; - switch(addr) { - case PARA_REG_DATA: - if (s->dataw == val) - return; - pdebug("wd%02x\n", val); - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm); - s->dataw = val; - break; - case PARA_REG_STS: - pdebug("ws%02x\n", val); - if (val & PARA_STS_TMOUT) - s->epp_timeout = 0; - break; - case PARA_REG_CTR: - val |= 0xc0; - if (s->control == val) - return; - pdebug("wc%02x\n", val); - - if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) { - if (val & PARA_CTR_DIR) { - dir = 1; - } else { - dir = 0; - } - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir); - parm &= ~PARA_CTR_DIR; - } - - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm); - s->control = val; - break; - case PARA_REG_EPP_ADDR: - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) - /* Controls not correct for EPP address cycle, so do nothing */ - pdebug("wa%02x s\n", val); - else { - struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; - if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) { - s->epp_timeout = 1; - pdebug("wa%02x t\n", val); - } - else - pdebug("wa%02x\n", val); - } - break; - case PARA_REG_EPP_DATA: - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("we%02x s\n", val); - else { - struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; - if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) { - s->epp_timeout = 1; - pdebug("we%02x t\n", val); - } - else - pdebug("we%02x\n", val); - } - break; - } -} - -static void -parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val) -{ - ParallelState *s = opaque; - uint16_t eppdata = cpu_to_le16(val); - int err; - struct ParallelIOArg ioarg = { - .buffer = &eppdata, .count = sizeof(eppdata) - }; - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) { - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("we%04x s\n", val); - return; - } - err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); - if (err) { - s->epp_timeout = 1; - pdebug("we%04x t\n", val); - } - else - pdebug("we%04x\n", val); -} - -static void -parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val) -{ - ParallelState *s = opaque; - uint32_t eppdata = cpu_to_le32(val); - int err; - struct ParallelIOArg ioarg = { - .buffer = &eppdata, .count = sizeof(eppdata) - }; - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) { - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("we%08x s\n", val); - return; - } - err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); - if (err) { - s->epp_timeout = 1; - pdebug("we%08x t\n", val); - } - else - pdebug("we%08x\n", val); -} - -static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr) -{ - ParallelState *s = opaque; - uint32_t ret = 0xff; - - addr &= 7; - switch(addr) { - case PARA_REG_DATA: - if (s->control & PARA_CTR_DIR) - ret = s->datar; - else - ret = s->dataw; - break; - case PARA_REG_STS: - ret = s->status; - s->irq_pending = 0; - if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { - /* XXX Fixme: wait 5 microseconds */ - if (s->status & PARA_STS_ACK) - s->status &= ~PARA_STS_ACK; - else { - /* XXX Fixme: wait 5 microseconds */ - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_BUSY; - } - } - parallel_update_irq(s); - break; - case PARA_REG_CTR: - ret = s->control; - break; - } - pdebug("read addr=0x%02x val=0x%02x\n", addr, ret); - return ret; -} - -static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr) -{ - ParallelState *s = opaque; - uint8_t ret = 0xff; - addr &= 7; - switch(addr) { - case PARA_REG_DATA: - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret); - if (s->last_read_offset != addr || s->datar != ret) - pdebug("rd%02x\n", ret); - s->datar = ret; - break; - case PARA_REG_STS: - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret); - ret &= ~PARA_STS_TMOUT; - if (s->epp_timeout) - ret |= PARA_STS_TMOUT; - if (s->last_read_offset != addr || s->status != ret) - pdebug("rs%02x\n", ret); - s->status = ret; - break; - case PARA_REG_CTR: - /* s->control has some bits fixed to 1. It is zero only when - it has not been yet written to. */ - if (s->control == 0) { - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret); - if (s->last_read_offset != addr) - pdebug("rc%02x\n", ret); - s->control = ret; - } - else { - ret = s->control; - if (s->last_read_offset != addr) - pdebug("rc%02x\n", ret); - } - break; - case PARA_REG_EPP_ADDR: - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) - /* Controls not correct for EPP addr cycle, so do nothing */ - pdebug("ra%02x s\n", ret); - else { - struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; - if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) { - s->epp_timeout = 1; - pdebug("ra%02x t\n", ret); - } - else - pdebug("ra%02x\n", ret); - } - break; - case PARA_REG_EPP_DATA: - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("re%02x s\n", ret); - else { - struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; - if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) { - s->epp_timeout = 1; - pdebug("re%02x t\n", ret); - } - else - pdebug("re%02x\n", ret); - } - break; - } - s->last_read_offset = addr; - return ret; -} - -static uint32_t -parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr) -{ - ParallelState *s = opaque; - uint32_t ret; - uint16_t eppdata = ~0; - int err; - struct ParallelIOArg ioarg = { - .buffer = &eppdata, .count = sizeof(eppdata) - }; - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) { - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("re%04x s\n", eppdata); - return eppdata; - } - err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); - ret = le16_to_cpu(eppdata); - - if (err) { - s->epp_timeout = 1; - pdebug("re%04x t\n", ret); - } - else - pdebug("re%04x\n", ret); - return ret; -} - -static uint32_t -parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr) -{ - ParallelState *s = opaque; - uint32_t ret; - uint32_t eppdata = ~0U; - int err; - struct ParallelIOArg ioarg = { - .buffer = &eppdata, .count = sizeof(eppdata) - }; - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) { - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("re%08x s\n", eppdata); - return eppdata; - } - err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); - ret = le32_to_cpu(eppdata); - - if (err) { - s->epp_timeout = 1; - pdebug("re%08x t\n", ret); - } - else - pdebug("re%08x\n", ret); - return ret; -} - -static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val) -{ - pdebug("wecp%d=%02x\n", addr & 7, val); -} - -static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr) -{ - uint8_t ret = 0xff; - - pdebug("recp%d:%02x\n", addr & 7, ret); - return ret; -} - -static void parallel_reset(void *opaque) -{ - ParallelState *s = opaque; - - s->datar = ~0; - s->dataw = ~0; - s->status = PARA_STS_BUSY; - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_ONLINE; - s->status |= PARA_STS_ERROR; - s->status |= PARA_STS_TMOUT; - s->control = PARA_CTR_SELECT; - s->control |= PARA_CTR_INIT; - s->control |= 0xc0; - s->irq_pending = 0; - s->hw_driver = 0; - s->epp_timeout = 0; - s->last_read_offset = ~0U; -} - -static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; - -static const MemoryRegionPortio isa_parallel_portio_hw_list[] = { - { 0, 8, 1, - .read = parallel_ioport_read_hw, - .write = parallel_ioport_write_hw }, - { 4, 1, 2, - .read = parallel_ioport_eppdata_read_hw2, - .write = parallel_ioport_eppdata_write_hw2 }, - { 4, 1, 4, - .read = parallel_ioport_eppdata_read_hw4, - .write = parallel_ioport_eppdata_write_hw4 }, - { 0x400, 8, 1, - .read = parallel_ioport_ecp_read, - .write = parallel_ioport_ecp_write }, - PORTIO_END_OF_LIST(), -}; - -static const MemoryRegionPortio isa_parallel_portio_sw_list[] = { - { 0, 8, 1, - .read = parallel_ioport_read_sw, - .write = parallel_ioport_write_sw }, - PORTIO_END_OF_LIST(), -}; - - -static const VMStateDescription vmstate_parallel_isa = { - .name = "parallel_isa", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(state.dataw, ISAParallelState), - VMSTATE_UINT8(state.datar, ISAParallelState), - VMSTATE_UINT8(state.status, ISAParallelState), - VMSTATE_UINT8(state.control, ISAParallelState), - VMSTATE_INT32(state.irq_pending, ISAParallelState), - VMSTATE_INT32(state.epp_timeout, ISAParallelState), - VMSTATE_END_OF_LIST() - } -}; - - -static void parallel_isa_realizefn(DeviceState *dev, Error **errp) -{ - static int index; - ISADevice *isadev = ISA_DEVICE(dev); - ISAParallelState *isa = ISA_PARALLEL(dev); - ParallelState *s = &isa->state; - int base; - uint8_t dummy; - - if (!s->chr) { - error_setg(errp, "Can't create parallel device, empty char device"); - return; - } - - if (isa->index == -1) { - isa->index = index; - } - if (isa->index >= MAX_PARALLEL_PORTS) { - error_setg(errp, "Max. supported number of parallel ports is %d.", - MAX_PARALLEL_PORTS); - return; - } - if (isa->iobase == -1) { - isa->iobase = isa_parallel_io[isa->index]; - } - index++; - - base = isa->iobase; - isa_init_irq(isadev, &s->irq, isa->isairq); - qemu_register_reset(parallel_reset, s); - - if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) { - s->hw_driver = 1; - s->status = dummy; - } - - isa_register_portio_list(isadev, base, - (s->hw_driver - ? &isa_parallel_portio_hw_list[0] - : &isa_parallel_portio_sw_list[0]), - s, "parallel"); -} - -/* Memory mapped interface */ -static uint32_t parallel_mm_readb (void *opaque, hwaddr addr) -{ - ParallelState *s = opaque; - - return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFF; -} - -static void parallel_mm_writeb (void *opaque, - hwaddr addr, uint32_t value) -{ - ParallelState *s = opaque; - - parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF); -} - -static uint32_t parallel_mm_readw (void *opaque, hwaddr addr) -{ - ParallelState *s = opaque; - - return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFFFF; -} - -static void parallel_mm_writew (void *opaque, - hwaddr addr, uint32_t value) -{ - ParallelState *s = opaque; - - parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF); -} - -static uint32_t parallel_mm_readl (void *opaque, hwaddr addr) -{ - ParallelState *s = opaque; - - return parallel_ioport_read_sw(s, addr >> s->it_shift); -} - -static void parallel_mm_writel (void *opaque, - hwaddr addr, uint32_t value) -{ - ParallelState *s = opaque; - - parallel_ioport_write_sw(s, addr >> s->it_shift, value); -} - -static const MemoryRegionOps parallel_mm_ops = { - .old_mmio = { - .read = { parallel_mm_readb, parallel_mm_readw, parallel_mm_readl }, - .write = { parallel_mm_writeb, parallel_mm_writew, parallel_mm_writel }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* If fd is zero, it means that the parallel device uses the console */ -bool parallel_mm_init(MemoryRegion *address_space, - hwaddr base, int it_shift, qemu_irq irq, - CharDriverState *chr) -{ - ParallelState *s; - - s = g_malloc0(sizeof(ParallelState)); - s->irq = irq; - s->chr = chr; - s->it_shift = it_shift; - qemu_register_reset(parallel_reset, s); - - memory_region_init_io(&s->iomem, NULL, ¶llel_mm_ops, s, - "parallel", 8 << it_shift); - memory_region_add_subregion(address_space, base, &s->iomem); - return true; -} - -static Property parallel_isa_properties[] = { - DEFINE_PROP_UINT32("index", ISAParallelState, index, -1), - DEFINE_PROP_UINT32("iobase", ISAParallelState, iobase, -1), - DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7), - DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void parallel_isa_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = parallel_isa_realizefn; - dc->vmsd = &vmstate_parallel_isa; - dc->props = parallel_isa_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static const TypeInfo parallel_isa_info = { - .name = TYPE_ISA_PARALLEL, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISAParallelState), - .class_init = parallel_isa_class_initfn, -}; - -static void parallel_register_types(void) -{ - type_register_static(¶llel_isa_info); -} - -type_init(parallel_register_types) diff --git a/qemu/hw/char/pl011.c b/qemu/hw/char/pl011.c deleted file mode 100644 index 210c87b4c..000000000 --- a/qemu/hw/char/pl011.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Arm PrimeCell PL011 UART - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "sysemu/char.h" - -#define TYPE_PL011 "pl011" -#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011) - -typedef struct PL011State { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t readbuff; - uint32_t flags; - uint32_t lcr; - uint32_t rsr; - uint32_t cr; - uint32_t dmacr; - uint32_t int_enabled; - uint32_t int_level; - uint32_t read_fifo[16]; - uint32_t ilpr; - uint32_t ibrd; - uint32_t fbrd; - uint32_t ifl; - int read_pos; - int read_count; - int read_trigger; - CharDriverState *chr; - qemu_irq irq; - const unsigned char *id; -} PL011State; - -#define PL011_INT_TX 0x20 -#define PL011_INT_RX 0x10 - -#define PL011_FLAG_TXFE 0x80 -#define PL011_FLAG_RXFF 0x40 -#define PL011_FLAG_TXFF 0x20 -#define PL011_FLAG_RXFE 0x10 - -static const unsigned char pl011_id_arm[8] = - { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; -static const unsigned char pl011_id_luminary[8] = - { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; - -static void pl011_update(PL011State *s) -{ - uint32_t flags; - - flags = s->int_level & s->int_enabled; - qemu_set_irq(s->irq, flags != 0); -} - -static uint64_t pl011_read(void *opaque, hwaddr offset, - unsigned size) -{ - PL011State *s = (PL011State *)opaque; - uint32_t c; - - if (offset >= 0xfe0 && offset < 0x1000) { - return s->id[(offset - 0xfe0) >> 2]; - } - switch (offset >> 2) { - case 0: /* UARTDR */ - s->flags &= ~PL011_FLAG_RXFF; - c = s->read_fifo[s->read_pos]; - if (s->read_count > 0) { - s->read_count--; - if (++s->read_pos == 16) - s->read_pos = 0; - } - if (s->read_count == 0) { - s->flags |= PL011_FLAG_RXFE; - } - if (s->read_count == s->read_trigger - 1) - s->int_level &= ~ PL011_INT_RX; - s->rsr = c >> 8; - pl011_update(s); - if (s->chr) { - qemu_chr_accept_input(s->chr); - } - return c; - case 1: /* UARTRSR */ - return s->rsr; - case 6: /* UARTFR */ - return s->flags; - case 8: /* UARTILPR */ - return s->ilpr; - case 9: /* UARTIBRD */ - return s->ibrd; - case 10: /* UARTFBRD */ - return s->fbrd; - case 11: /* UARTLCR_H */ - return s->lcr; - case 12: /* UARTCR */ - return s->cr; - case 13: /* UARTIFLS */ - return s->ifl; - case 14: /* UARTIMSC */ - return s->int_enabled; - case 15: /* UARTRIS */ - return s->int_level; - case 16: /* UARTMIS */ - return s->int_level & s->int_enabled; - case 18: /* UARTDMACR */ - return s->dmacr; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl011_read: Bad offset %x\n", (int)offset); - return 0; - } -} - -static void pl011_set_read_trigger(PL011State *s) -{ -#if 0 - /* The docs say the RX interrupt is triggered when the FIFO exceeds - the threshold. However linux only reads the FIFO in response to an - interrupt. Triggering the interrupt when the FIFO is non-empty seems - to make things work. */ - if (s->lcr & 0x10) - s->read_trigger = (s->ifl >> 1) & 0x1c; - else -#endif - s->read_trigger = 1; -} - -static void pl011_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PL011State *s = (PL011State *)opaque; - unsigned char ch; - - switch (offset >> 2) { - case 0: /* UARTDR */ - /* ??? Check if transmitter is enabled. */ - ch = value; - if (s->chr) - qemu_chr_fe_write(s->chr, &ch, 1); - s->int_level |= PL011_INT_TX; - pl011_update(s); - break; - case 1: /* UARTRSR/UARTECR */ - s->rsr = 0; - break; - case 6: /* UARTFR */ - /* Writes to Flag register are ignored. */ - break; - case 8: /* UARTUARTILPR */ - s->ilpr = value; - break; - case 9: /* UARTIBRD */ - s->ibrd = value; - break; - case 10: /* UARTFBRD */ - s->fbrd = value; - break; - case 11: /* UARTLCR_H */ - /* Reset the FIFO state on FIFO enable or disable */ - if ((s->lcr ^ value) & 0x10) { - s->read_count = 0; - s->read_pos = 0; - } - s->lcr = value; - pl011_set_read_trigger(s); - break; - case 12: /* UARTCR */ - /* ??? Need to implement the enable and loopback bits. */ - s->cr = value; - break; - case 13: /* UARTIFS */ - s->ifl = value; - pl011_set_read_trigger(s); - break; - case 14: /* UARTIMSC */ - s->int_enabled = value; - pl011_update(s); - break; - case 17: /* UARTICR */ - s->int_level &= ~value; - pl011_update(s); - break; - case 18: /* UARTDMACR */ - s->dmacr = value; - if (value & 3) { - qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n"); - } - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl011_write: Bad offset %x\n", (int)offset); - } -} - -static int pl011_can_receive(void *opaque) -{ - PL011State *s = (PL011State *)opaque; - - if (s->lcr & 0x10) - return s->read_count < 16; - else - return s->read_count < 1; -} - -static void pl011_put_fifo(void *opaque, uint32_t value) -{ - PL011State *s = (PL011State *)opaque; - int slot; - - slot = s->read_pos + s->read_count; - if (slot >= 16) - slot -= 16; - s->read_fifo[slot] = value; - s->read_count++; - s->flags &= ~PL011_FLAG_RXFE; - if (!(s->lcr & 0x10) || s->read_count == 16) { - s->flags |= PL011_FLAG_RXFF; - } - if (s->read_count == s->read_trigger) { - s->int_level |= PL011_INT_RX; - pl011_update(s); - } -} - -static void pl011_receive(void *opaque, const uint8_t *buf, int size) -{ - pl011_put_fifo(opaque, *buf); -} - -static void pl011_event(void *opaque, int event) -{ - if (event == CHR_EVENT_BREAK) - pl011_put_fifo(opaque, 0x400); -} - -static const MemoryRegionOps pl011_ops = { - .read = pl011_read, - .write = pl011_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_pl011 = { - .name = "pl011", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(readbuff, PL011State), - VMSTATE_UINT32(flags, PL011State), - VMSTATE_UINT32(lcr, PL011State), - VMSTATE_UINT32(rsr, PL011State), - VMSTATE_UINT32(cr, PL011State), - VMSTATE_UINT32(dmacr, PL011State), - VMSTATE_UINT32(int_enabled, PL011State), - VMSTATE_UINT32(int_level, PL011State), - VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16), - VMSTATE_UINT32(ilpr, PL011State), - VMSTATE_UINT32(ibrd, PL011State), - VMSTATE_UINT32(fbrd, PL011State), - VMSTATE_UINT32(ifl, PL011State), - VMSTATE_INT32(read_pos, PL011State), - VMSTATE_INT32(read_count, PL011State), - VMSTATE_INT32(read_trigger, PL011State), - VMSTATE_END_OF_LIST() - } -}; - -static void pl011_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - PL011State *s = PL011(obj); - - memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - - s->read_trigger = 1; - s->ifl = 0x12; - s->cr = 0x300; - s->flags = 0x90; - - s->id = pl011_id_arm; -} - -static void pl011_realize(DeviceState *dev, Error **errp) -{ - PL011State *s = PL011(dev); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - - if (s->chr) { - qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, - pl011_event, s); - } -} - -static void pl011_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = pl011_realize; - dc->vmsd = &vmstate_pl011; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo pl011_arm_info = { - .name = TYPE_PL011, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PL011State), - .instance_init = pl011_init, - .class_init = pl011_class_init, -}; - -static void pl011_luminary_init(Object *obj) -{ - PL011State *s = PL011(obj); - - s->id = pl011_id_luminary; -} - -static const TypeInfo pl011_luminary_info = { - .name = "pl011_luminary", - .parent = TYPE_PL011, - .instance_init = pl011_luminary_init, -}; - -static void pl011_register_types(void) -{ - type_register_static(&pl011_arm_info); - type_register_static(&pl011_luminary_info); -} - -type_init(pl011_register_types) diff --git a/qemu/hw/char/sclpconsole-lm.c b/qemu/hw/char/sclpconsole-lm.c deleted file mode 100644 index 7d4ff8120..000000000 --- a/qemu/hw/char/sclpconsole-lm.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * SCLP event types - * Operations Command - Line Mode input - * Message - Line Mode output - * - * Copyright IBM, Corp. 2013 - * - * Authors: - * Heinz Graalfs - * - * This work is licensed under the terms of the GNU GPL, version 2 or (at your - * option) any later version. See the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "hw/qdev.h" -#include "qemu/thread.h" -#include "qemu/error-report.h" -#include "sysemu/char.h" - -#include "hw/s390x/sclp.h" -#include "hw/s390x/event-facility.h" -#include "hw/s390x/ebcdic.h" - -#define SIZE_BUFFER 4096 -#define NEWLINE "\n" - -typedef struct OprtnsCommand { - EventBufferHeader header; - MDMSU message_unit; - char data[0]; -} QEMU_PACKED OprtnsCommand; - -/* max size for line-mode data in 4K SCCB page */ -#define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand)) - -typedef struct SCLPConsoleLM { - SCLPEvent event; - CharDriverState *chr; - bool echo; /* immediate echo of input if true */ - uint32_t write_errors; /* errors writing to char layer */ - uint32_t length; /* length of byte stream in buffer */ - uint8_t buf[SIZE_CONSOLE_BUFFER]; -} SCLPConsoleLM; - -/* -* Character layer call-back functions - * - * Allow 1 character at a time - * - * Accumulate bytes from character layer in console buffer, - * event_pending is set when a newline character is encountered - * - * The maximum command line length is limited by the maximum - * space available in an SCCB. Line mode console input is sent - * truncated to the guest in case it doesn't fit into the SCCB. - */ - -static int chr_can_read(void *opaque) -{ - SCLPConsoleLM *scon = opaque; - - if (scon->event.event_pending) { - return 0; - } - return 1; -} - -static void chr_read(void *opaque, const uint8_t *buf, int size) -{ - SCLPConsoleLM *scon = opaque; - - assert(size == 1); - - if (*buf == '\r' || *buf == '\n') { - scon->event.event_pending = true; - sclp_service_interrupt(0); - return; - } - if (scon->length == SIZE_CONSOLE_BUFFER) { - /* Eat the character, but still process CR and LF. */ - return; - } - scon->buf[scon->length] = *buf; - scon->length += 1; - if (scon->echo) { - qemu_chr_fe_write(scon->chr, buf, size); - } -} - -/* functions to be called by event facility */ - -static bool can_handle_event(uint8_t type) -{ - return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD; -} - -static unsigned int send_mask(void) -{ - return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD; -} - -static unsigned int receive_mask(void) -{ - return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD; -} - -/* - * Triggered by SCLP's read_event_data - * - convert ASCII byte stream to EBCDIC and - * - copy converted data into provided (SCLP) buffer - */ -static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, - int avail) -{ - int len; - - SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event); - - len = cons->length; - /* data need to fit into provided SCLP buffer */ - if (len > avail) { - return 1; - } - - ebcdic_put(buf, (char *)&cons->buf, len); - *size = len; - cons->length = 0; - /* data provided and no more data pending */ - event->event_pending = false; - qemu_notify_event(); - return 0; -} - -static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, - int *slen) -{ - int avail, rc; - size_t src_len; - uint8_t *to; - OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr; - - if (!event->event_pending) { - /* no data pending */ - return 0; - } - - to = (uint8_t *)&oc->data; - avail = *slen - sizeof(OprtnsCommand); - rc = get_console_data(event, to, &src_len, avail); - if (rc) { - /* data didn't fit, try next SCCB */ - return 1; - } - - oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU; - oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU)); - - oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU; - oc->message_unit.cpmsu.length = - cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector)); - - oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD; - oc->message_unit.text_command.length = - cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector))); - - oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG; - oc->message_unit.self_def_text_message.length = - cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector))); - - oc->message_unit.text_message.key = GDS_KEY_TEXTMSG; - oc->message_unit.text_message.length = - cpu_to_be16(sizeof(GdsSubvector) + src_len); - - oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len); - oc->header.type = SCLP_EVENT_OPRTNS_COMMAND; - *slen = avail - src_len; - - return 1; -} - -/* - * Triggered by SCLP's write_event_data - * - write console data to character layer - * returns < 0 if an error occurred - */ -static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) -{ - int ret = 0; - const uint8_t *buf_offset; - - SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); - - if (!scon->chr) { - /* If there's no backend, we can just say we consumed all data. */ - return len; - } - - buf_offset = buf; - while (len > 0) { - ret = qemu_chr_fe_write(scon->chr, buf, len); - if (ret == 0) { - /* a pty doesn't seem to be connected - no error */ - len = 0; - } else if (ret == -EAGAIN || (ret > 0 && ret < len)) { - len -= ret; - buf_offset += ret; - } else { - len = 0; - } - } - - return ret; -} - -static int process_mdb(SCLPEvent *event, MDBO *mdbo) -{ - int rc; - int len; - uint8_t buffer[SIZE_BUFFER]; - - len = be16_to_cpu(mdbo->length); - len -= sizeof(mdbo->length) + sizeof(mdbo->type) - + sizeof(mdbo->mto.line_type_flags) - + sizeof(mdbo->mto.alarm_control) - + sizeof(mdbo->mto._reserved); - - assert(len <= SIZE_BUFFER); - - /* convert EBCDIC SCLP contents to ASCII console message */ - ascii_put(buffer, mdbo->mto.message, len); - rc = write_console_data(event, (uint8_t *)NEWLINE, 1); - if (rc < 0) { - return rc; - } - return write_console_data(event, buffer, len); -} - -static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh) -{ - int len; - int written; - int errors = 0; - MDBO *mdbo; - SclpMsg *data = (SclpMsg *) ebh; - SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); - - len = be16_to_cpu(data->mdb.header.length); - if (len < sizeof(data->mdb.header)) { - return SCLP_RC_INCONSISTENT_LENGTHS; - } - len -= sizeof(data->mdb.header); - - /* first check message buffers */ - mdbo = data->mdb.mdbo; - while (len > 0) { - if (be16_to_cpu(mdbo->length) > len - || be16_to_cpu(mdbo->length) == 0) { - return SCLP_RC_INCONSISTENT_LENGTHS; - } - len -= be16_to_cpu(mdbo->length); - mdbo = (void *) mdbo + be16_to_cpu(mdbo->length); - } - - /* then execute */ - len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header); - mdbo = data->mdb.mdbo; - while (len > 0) { - switch (be16_to_cpu(mdbo->type)) { - case MESSAGE_TEXT: - /* message text object */ - written = process_mdb(event, mdbo); - if (written < 0) { - /* character layer error */ - errors++; - } - break; - default: /* ignore */ - break; - } - len -= be16_to_cpu(mdbo->length); - mdbo = (void *) mdbo + be16_to_cpu(mdbo->length); - } - if (errors) { - scon->write_errors += errors; - } - data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED; - - return SCLP_RC_NORMAL_COMPLETION; -} - -/* functions for live migration */ - -static const VMStateDescription vmstate_sclplmconsole = { - .name = "sclplmconsole", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_BOOL(event.event_pending, SCLPConsoleLM), - VMSTATE_UINT32(write_errors, SCLPConsoleLM), - VMSTATE_UINT32(length, SCLPConsoleLM), - VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER), - VMSTATE_END_OF_LIST() - } -}; - -/* qemu object creation and initialization functions */ - -/* tell character layer our call-back functions */ - -static int console_init(SCLPEvent *event) -{ - static bool console_available; - - SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); - - if (console_available) { - error_report("Multiple line-mode operator consoles are not supported"); - return -1; - } - console_available = true; - - if (scon->chr) { - qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon); - } - - return 0; -} - -static int console_exit(SCLPEvent *event) -{ - return 0; -} - -static void console_reset(DeviceState *dev) -{ - SCLPEvent *event = SCLP_EVENT(dev); - SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); - - event->event_pending = false; - scon->length = 0; - scon->write_errors = 0; -} - -static Property console_properties[] = { - DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr), - DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0), - DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true), - DEFINE_PROP_END_OF_LIST(), -}; - -static void console_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); - - dc->props = console_properties; - dc->reset = console_reset; - dc->vmsd = &vmstate_sclplmconsole; - ec->init = console_init; - ec->exit = console_exit; - ec->get_send_mask = send_mask; - ec->get_receive_mask = receive_mask; - ec->can_handle_event = can_handle_event; - ec->read_event_data = read_event_data; - ec->write_event_data = write_event_data; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static const TypeInfo sclp_console_info = { - .name = "sclplmconsole", - .parent = TYPE_SCLP_EVENT, - .instance_size = sizeof(SCLPConsoleLM), - .class_init = console_class_init, - .class_size = sizeof(SCLPEventClass), -}; - -static void register_types(void) -{ - type_register_static(&sclp_console_info); -} - -type_init(register_types) diff --git a/qemu/hw/char/sclpconsole.c b/qemu/hw/char/sclpconsole.c deleted file mode 100644 index 45997ff4a..000000000 --- a/qemu/hw/char/sclpconsole.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * SCLP event type - * Ascii Console Data (VT220 Console) - * - * Copyright IBM, Corp. 2012 - * - * Authors: - * Heinz Graalfs - * - * This work is licensed under the terms of the GNU GPL, version 2 or (at your - * option) any later version. See the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include -#include "qemu/thread.h" -#include "qemu/error-report.h" - -#include "hw/s390x/sclp.h" -#include "hw/s390x/event-facility.h" -#include "sysemu/char.h" - -typedef struct ASCIIConsoleData { - EventBufferHeader ebh; - char data[0]; -} QEMU_PACKED ASCIIConsoleData; - -/* max size for ASCII data in 4K SCCB page */ -#define SIZE_BUFFER_VT220 4080 - -typedef struct SCLPConsole { - SCLPEvent event; - CharDriverState *chr; - uint8_t iov[SIZE_BUFFER_VT220]; - uint32_t iov_sclp; /* offset in buf for SCLP read operation */ - uint32_t iov_bs; /* offset in buf for char layer read operation */ - uint32_t iov_data_len; /* length of byte stream in buffer */ - uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */ - bool notify; /* qemu_notify_event() req'd if true */ -} SCLPConsole; - -/* character layer call-back functions */ - -/* Return number of bytes that fit into iov buffer */ -static int chr_can_read(void *opaque) -{ - SCLPConsole *scon = opaque; - int avail = SIZE_BUFFER_VT220 - scon->iov_data_len; - - if (avail == 0) { - scon->notify = true; - } - return avail; -} - -/* Send data from a char device over to the guest */ -static void chr_read(void *opaque, const uint8_t *buf, int size) -{ - SCLPConsole *scon = opaque; - - assert(scon); - /* read data must fit into current buffer */ - assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len); - - /* put byte-stream from character layer into buffer */ - memcpy(&scon->iov[scon->iov_bs], buf, size); - scon->iov_data_len += size; - scon->iov_sclp_rest += size; - scon->iov_bs += size; - scon->event.event_pending = true; - sclp_service_interrupt(0); -} - -/* functions to be called by event facility */ - -static bool can_handle_event(uint8_t type) -{ - return type == SCLP_EVENT_ASCII_CONSOLE_DATA; -} - -static unsigned int send_mask(void) -{ - return SCLP_EVENT_MASK_MSG_ASCII; -} - -static unsigned int receive_mask(void) -{ - return SCLP_EVENT_MASK_MSG_ASCII; -} - -/* triggered by SCLP's read_event_data - - * copy console data byte-stream into provided (SCLP) buffer - */ -static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, - int avail) -{ - SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event); - - /* first byte is hex 0 saying an ascii string follows */ - *buf++ = '\0'; - avail--; - /* if all data fit into provided SCLP buffer */ - if (avail >= cons->iov_sclp_rest) { - /* copy character byte-stream to SCLP buffer */ - memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest); - *size = cons->iov_sclp_rest + 1; - cons->iov_sclp = 0; - cons->iov_bs = 0; - cons->iov_data_len = 0; - cons->iov_sclp_rest = 0; - event->event_pending = false; - /* data provided and no more data pending */ - } else { - /* if provided buffer is too small, just copy part */ - memcpy(buf, &cons->iov[cons->iov_sclp], avail); - *size = avail + 1; - cons->iov_sclp_rest -= avail; - cons->iov_sclp += avail; - /* more data pending */ - } - if (cons->notify) { - cons->notify = false; - qemu_notify_event(); - } -} - -static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, - int *slen) -{ - int avail; - size_t src_len; - uint8_t *to; - ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; - - if (!event->event_pending) { - /* no data pending */ - return 0; - } - - to = (uint8_t *)&acd->data; - avail = *slen - sizeof(ASCIIConsoleData); - get_console_data(event, to, &src_len, avail); - - acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len); - acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; - acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; - *slen = avail - src_len; - - return 1; -} - -/* triggered by SCLP's write_event_data - * - write console data to character layer - * returns < 0 if an error occurred - */ -static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, - size_t len) -{ - SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); - - if (!scon->chr) { - /* If there's no backend, we can just say we consumed all data. */ - return len; - } - - return qemu_chr_fe_write_all(scon->chr, buf, len); -} - -static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr) -{ - int rc; - int length; - ssize_t written; - ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; - - length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader); - written = write_console_data(event, (uint8_t *)acd->data, length); - - rc = SCLP_RC_NORMAL_COMPLETION; - /* set event buffer accepted flag */ - evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED; - - /* written will be zero if a pty is not connected - don't treat as error */ - if (written < 0) { - /* event buffer not accepted due to error in character layer */ - evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED); - rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK; - } - - return rc; -} - -static const VMStateDescription vmstate_sclpconsole = { - .name = "sclpconsole", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_BOOL(event.event_pending, SCLPConsole), - VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220), - VMSTATE_UINT32(iov_sclp, SCLPConsole), - VMSTATE_UINT32(iov_bs, SCLPConsole), - VMSTATE_UINT32(iov_data_len, SCLPConsole), - VMSTATE_UINT32(iov_sclp_rest, SCLPConsole), - VMSTATE_END_OF_LIST() - } -}; - -/* qemu object creation and initialization functions */ - -/* tell character layer our call-back functions */ - -static int console_init(SCLPEvent *event) -{ - static bool console_available; - - SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); - - if (console_available) { - error_report("Multiple VT220 operator consoles are not supported"); - return -1; - } - console_available = true; - if (scon->chr) { - qemu_chr_add_handlers(scon->chr, chr_can_read, - chr_read, NULL, scon); - } - - return 0; -} - -static void console_reset(DeviceState *dev) -{ - SCLPEvent *event = SCLP_EVENT(dev); - SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); - - event->event_pending = false; - scon->iov_sclp = 0; - scon->iov_bs = 0; - scon->iov_data_len = 0; - scon->iov_sclp_rest = 0; - scon->notify = false; -} - -static int console_exit(SCLPEvent *event) -{ - return 0; -} - -static Property console_properties[] = { - DEFINE_PROP_CHR("chardev", SCLPConsole, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void console_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); - - dc->props = console_properties; - dc->reset = console_reset; - dc->vmsd = &vmstate_sclpconsole; - ec->init = console_init; - ec->exit = console_exit; - ec->get_send_mask = send_mask; - ec->get_receive_mask = receive_mask; - ec->can_handle_event = can_handle_event; - ec->read_event_data = read_event_data; - ec->write_event_data = write_event_data; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static const TypeInfo sclp_console_info = { - .name = "sclpconsole", - .parent = TYPE_SCLP_EVENT, - .instance_size = sizeof(SCLPConsole), - .class_init = console_class_init, - .class_size = sizeof(SCLPEventClass), -}; - -static void register_types(void) -{ - type_register_static(&sclp_console_info); -} - -type_init(register_types) diff --git a/qemu/hw/char/serial-isa.c b/qemu/hw/char/serial-isa.c deleted file mode 100644 index 1594ec4db..000000000 --- a/qemu/hw/char/serial-isa.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * QEMU 16550A UART emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * Copyright (c) 2008 Citrix Systems, Inc. - * - * 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. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/char/serial.h" -#include "hw/isa/isa.h" - -#define ISA_SERIAL(obj) OBJECT_CHECK(ISASerialState, (obj), TYPE_ISA_SERIAL) - -typedef struct ISASerialState { - ISADevice parent_obj; - - uint32_t index; - uint32_t iobase; - uint32_t isairq; - SerialState state; -} ISASerialState; - -static const int isa_serial_io[MAX_SERIAL_PORTS] = { - 0x3f8, 0x2f8, 0x3e8, 0x2e8 -}; -static const int isa_serial_irq[MAX_SERIAL_PORTS] = { - 4, 3, 4, 3 -}; - -static void serial_isa_realizefn(DeviceState *dev, Error **errp) -{ - static int index; - ISADevice *isadev = ISA_DEVICE(dev); - ISASerialState *isa = ISA_SERIAL(dev); - SerialState *s = &isa->state; - - if (isa->index == -1) { - isa->index = index; - } - if (isa->index >= MAX_SERIAL_PORTS) { - error_setg(errp, "Max. supported number of ISA serial ports is %d.", - MAX_SERIAL_PORTS); - return; - } - if (isa->iobase == -1) { - isa->iobase = isa_serial_io[isa->index]; - } - if (isa->isairq == -1) { - isa->isairq = isa_serial_irq[isa->index]; - } - index++; - - s->baudbase = 115200; - isa_init_irq(isadev, &s->irq, isa->isairq); - serial_realize_core(s, errp); - qdev_set_legacy_instance_id(dev, isa->iobase, 3); - - memory_region_init_io(&s->io, OBJECT(isa), &serial_io_ops, s, "serial", 8); - isa_register_ioport(isadev, &s->io, isa->iobase); -} - -static const VMStateDescription vmstate_isa_serial = { - .name = "serial", - .version_id = 3, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState), - VMSTATE_END_OF_LIST() - } -}; - -static Property serial_isa_properties[] = { - DEFINE_PROP_UINT32("index", ISASerialState, index, -1), - DEFINE_PROP_UINT32("iobase", ISASerialState, iobase, -1), - DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), - DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), - DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void serial_isa_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = serial_isa_realizefn; - dc->vmsd = &vmstate_isa_serial; - dc->props = serial_isa_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static const TypeInfo serial_isa_info = { - .name = TYPE_ISA_SERIAL, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISASerialState), - .class_init = serial_isa_class_initfn, -}; - -static void serial_register_types(void) -{ - type_register_static(&serial_isa_info); -} - -type_init(serial_register_types) - -static void serial_isa_init(ISABus *bus, int index, CharDriverState *chr) -{ - DeviceState *dev; - ISADevice *isadev; - - isadev = isa_create(bus, TYPE_ISA_SERIAL); - dev = DEVICE(isadev); - qdev_prop_set_uint32(dev, "index", index); - qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); -} - -void serial_hds_isa_init(ISABus *bus, int n) -{ - int i; - - assert(n <= MAX_SERIAL_PORTS); - - for (i = 0; i < n; ++i) { - if (serial_hds[i]) { - serial_isa_init(bus, i, serial_hds[i]); - } - } -} diff --git a/qemu/hw/char/serial-pci.c b/qemu/hw/char/serial-pci.c deleted file mode 100644 index 303104dd1..000000000 --- a/qemu/hw/char/serial-pci.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * QEMU 16550A UART emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * Copyright (c) 2008 Citrix Systems, Inc. - * - * 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. - */ - -/* see docs/specs/pci-serial.txt */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/char/serial.h" -#include "hw/pci/pci.h" - -#define PCI_SERIAL_MAX_PORTS 4 - -typedef struct PCISerialState { - PCIDevice dev; - SerialState state; - uint8_t prog_if; -} PCISerialState; - -typedef struct PCIMultiSerialState { - PCIDevice dev; - MemoryRegion iobar; - uint32_t ports; - char *name[PCI_SERIAL_MAX_PORTS]; - SerialState state[PCI_SERIAL_MAX_PORTS]; - uint32_t level[PCI_SERIAL_MAX_PORTS]; - qemu_irq *irqs; - uint8_t prog_if; -} PCIMultiSerialState; - -static void multi_serial_pci_exit(PCIDevice *dev); - -static void serial_pci_realize(PCIDevice *dev, Error **errp) -{ - PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); - SerialState *s = &pci->state; - Error *err = NULL; - - s->baudbase = 115200; - serial_realize_core(s, &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - - pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; - pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; - s->irq = pci_allocate_irq(&pci->dev); - - memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8); - pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); -} - -static void multi_serial_irq_mux(void *opaque, int n, int level) -{ - PCIMultiSerialState *pci = opaque; - int i, pending = 0; - - pci->level[n] = level; - for (i = 0; i < pci->ports; i++) { - if (pci->level[i]) { - pending = 1; - } - } - pci_set_irq(&pci->dev, pending); -} - -static void multi_serial_pci_realize(PCIDevice *dev, Error **errp) -{ - PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); - PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); - SerialState *s; - Error *err = NULL; - int i, nr_ports = 0; - - switch (pc->device_id) { - case 0x0003: - nr_ports = 2; - break; - case 0x0004: - nr_ports = 4; - break; - } - assert(nr_ports > 0); - assert(nr_ports <= PCI_SERIAL_MAX_PORTS); - - pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; - pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; - memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nr_ports); - pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); - pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, - nr_ports); - - for (i = 0; i < nr_ports; i++) { - s = pci->state + i; - s->baudbase = 115200; - serial_realize_core(s, &err); - if (err != NULL) { - error_propagate(errp, err); - multi_serial_pci_exit(dev); - return; - } - s->irq = pci->irqs[i]; - pci->name[i] = g_strdup_printf("uart #%d", i+1); - memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, - pci->name[i], 8); - memory_region_add_subregion(&pci->iobar, 8 * i, &s->io); - pci->ports++; - } -} - -static void serial_pci_exit(PCIDevice *dev) -{ - PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); - SerialState *s = &pci->state; - - serial_exit_core(s); - qemu_free_irq(s->irq); -} - -static void multi_serial_pci_exit(PCIDevice *dev) -{ - PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); - SerialState *s; - int i; - - for (i = 0; i < pci->ports; i++) { - s = pci->state + i; - serial_exit_core(s); - memory_region_del_subregion(&pci->iobar, &s->io); - g_free(pci->name[i]); - } - qemu_free_irqs(pci->irqs, pci->ports); -} - -static const VMStateDescription vmstate_pci_serial = { - .name = "pci-serial", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, PCISerialState), - VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_pci_multi_serial = { - .name = "pci-serial-multi", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState), - VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS, - 0, vmstate_serial, SerialState), - VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS), - VMSTATE_END_OF_LIST() - } -}; - -static Property serial_pci_properties[] = { - DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), - DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02), - DEFINE_PROP_END_OF_LIST(), -}; - -static Property multi_2x_serial_pci_properties[] = { - DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), - DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), - DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), - DEFINE_PROP_END_OF_LIST(), -}; - -static Property multi_4x_serial_pci_properties[] = { - DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), - DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), - DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr), - DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr), - DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), - DEFINE_PROP_END_OF_LIST(), -}; - -static void serial_pci_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); - pc->realize = serial_pci_realize; - pc->exit = serial_pci_exit; - pc->vendor_id = PCI_VENDOR_ID_REDHAT; - pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL; - pc->revision = 1; - pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; - dc->vmsd = &vmstate_pci_serial; - dc->props = serial_pci_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); - pc->realize = multi_serial_pci_realize; - pc->exit = multi_serial_pci_exit; - pc->vendor_id = PCI_VENDOR_ID_REDHAT; - pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2; - pc->revision = 1; - pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; - dc->vmsd = &vmstate_pci_multi_serial; - dc->props = multi_2x_serial_pci_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); - pc->realize = multi_serial_pci_realize; - pc->exit = multi_serial_pci_exit; - pc->vendor_id = PCI_VENDOR_ID_REDHAT; - pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4; - pc->revision = 1; - pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; - dc->vmsd = &vmstate_pci_multi_serial; - dc->props = multi_4x_serial_pci_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static const TypeInfo serial_pci_info = { - .name = "pci-serial", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCISerialState), - .class_init = serial_pci_class_initfn, -}; - -static const TypeInfo multi_2x_serial_pci_info = { - .name = "pci-serial-2x", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIMultiSerialState), - .class_init = multi_2x_serial_pci_class_initfn, -}; - -static const TypeInfo multi_4x_serial_pci_info = { - .name = "pci-serial-4x", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIMultiSerialState), - .class_init = multi_4x_serial_pci_class_initfn, -}; - -static void serial_pci_register_types(void) -{ - type_register_static(&serial_pci_info); - type_register_static(&multi_2x_serial_pci_info); - type_register_static(&multi_4x_serial_pci_info); -} - -type_init(serial_pci_register_types) diff --git a/qemu/hw/char/serial.c b/qemu/hw/char/serial.c deleted file mode 100644 index 6d815b5c6..000000000 --- a/qemu/hw/char/serial.c +++ /dev/null @@ -1,966 +0,0 @@ -/* - * QEMU 16550A UART emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * Copyright (c) 2008 Citrix Systems, Inc. - * - * 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. - */ - -#include "qemu/osdep.h" -#include "hw/char/serial.h" -#include "sysemu/char.h" -#include "qapi/error.h" -#include "qemu/timer.h" -#include "exec/address-spaces.h" -#include "qemu/error-report.h" - -//#define DEBUG_SERIAL - -#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ - -#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ -#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ -#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ -#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ - -#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ -#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ - -#define UART_IIR_MSI 0x00 /* Modem status interrupt */ -#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ -#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ -#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ -#define UART_IIR_CTI 0x0C /* Character Timeout Indication */ - -#define UART_IIR_FENF 0x80 /* Fifo enabled, but not functionning */ -#define UART_IIR_FE 0xC0 /* Fifo enabled */ - -/* - * These are the definitions for the Modem Control Register - */ -#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ -#define UART_MCR_OUT2 0x08 /* Out2 complement */ -#define UART_MCR_OUT1 0x04 /* Out1 complement */ -#define UART_MCR_RTS 0x02 /* RTS complement */ -#define UART_MCR_DTR 0x01 /* DTR complement */ - -/* - * These are the definitions for the Modem Status Register - */ -#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ -#define UART_MSR_RI 0x40 /* Ring Indicator */ -#define UART_MSR_DSR 0x20 /* Data Set Ready */ -#define UART_MSR_CTS 0x10 /* Clear to Send */ -#define UART_MSR_DDCD 0x08 /* Delta DCD */ -#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ -#define UART_MSR_DDSR 0x02 /* Delta DSR */ -#define UART_MSR_DCTS 0x01 /* Delta CTS */ -#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ - -#define UART_LSR_TEMT 0x40 /* Transmitter empty */ -#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ -#define UART_LSR_BI 0x10 /* Break interrupt indicator */ -#define UART_LSR_FE 0x08 /* Frame error indicator */ -#define UART_LSR_PE 0x04 /* Parity error indicator */ -#define UART_LSR_OE 0x02 /* Overrun error indicator */ -#define UART_LSR_DR 0x01 /* Receiver data ready */ -#define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */ - -/* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */ - -#define UART_FCR_ITL_1 0x00 /* 1 byte ITL */ -#define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */ -#define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */ -#define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */ - -#define UART_FCR_DMS 0x08 /* DMA Mode Select */ -#define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */ -#define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ -#define UART_FCR_FE 0x01 /* FIFO Enable */ - -#define MAX_XMIT_RETRY 4 - -#ifdef DEBUG_SERIAL -#define DPRINTF(fmt, ...) \ -do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ -do {} while (0) -#endif - -static void serial_receive1(void *opaque, const uint8_t *buf, int size); - -static inline void recv_fifo_put(SerialState *s, uint8_t chr) -{ - /* Receive overruns do not overwrite FIFO contents. */ - if (!fifo8_is_full(&s->recv_fifo)) { - fifo8_push(&s->recv_fifo, chr); - } else { - s->lsr |= UART_LSR_OE; - } -} - -static void serial_update_irq(SerialState *s) -{ - uint8_t tmp_iir = UART_IIR_NO_INT; - - if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) { - tmp_iir = UART_IIR_RLSI; - } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) { - /* Note that(s->ier & UART_IER_RDI) can mask this interrupt, - * this is not in the specification but is observed on existing - * hardware. */ - tmp_iir = UART_IIR_CTI; - } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) && - (!(s->fcr & UART_FCR_FE) || - s->recv_fifo.num >= s->recv_fifo_itl)) { - tmp_iir = UART_IIR_RDI; - } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) { - tmp_iir = UART_IIR_THRI; - } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) { - tmp_iir = UART_IIR_MSI; - } - - s->iir = tmp_iir | (s->iir & 0xF0); - - if (tmp_iir != UART_IIR_NO_INT) { - qemu_irq_raise(s->irq); - } else { - qemu_irq_lower(s->irq); - } -} - -static void serial_update_parameters(SerialState *s) -{ - int speed, parity, data_bits, stop_bits, frame_size; - QEMUSerialSetParams ssp; - - if (s->divider == 0) - return; - - /* Start bit. */ - frame_size = 1; - if (s->lcr & 0x08) { - /* Parity bit. */ - frame_size++; - if (s->lcr & 0x10) - parity = 'E'; - else - parity = 'O'; - } else { - parity = 'N'; - } - if (s->lcr & 0x04) - stop_bits = 2; - else - stop_bits = 1; - - data_bits = (s->lcr & 0x03) + 5; - frame_size += data_bits + stop_bits; - speed = s->baudbase / s->divider; - ssp.speed = speed; - ssp.parity = parity; - ssp.data_bits = data_bits; - ssp.stop_bits = stop_bits; - s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size; - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); - - DPRINTF("speed=%d parity=%c data=%d stop=%d\n", - speed, parity, data_bits, stop_bits); -} - -static void serial_update_msl(SerialState *s) -{ - uint8_t omsr; - int flags; - - timer_del(s->modem_status_poll); - - if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) { - s->poll_msl = -1; - return; - } - - omsr = s->msr; - - s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS; - s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR; - s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD; - s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI; - - if (s->msr != omsr) { - /* Set delta bits */ - s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4)); - /* UART_MSR_TERI only if change was from 1 -> 0 */ - if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI)) - s->msr &= ~UART_MSR_TERI; - serial_update_irq(s); - } - - /* The real 16550A apparently has a 250ns response latency to line status changes. - We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */ - - if (s->poll_msl) { - timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - NANOSECONDS_PER_SECOND / 100); - } -} - -static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) -{ - SerialState *s = opaque; - - do { - assert(!(s->lsr & UART_LSR_TEMT)); - if (s->tsr_retry <= 0) { - assert(!(s->lsr & UART_LSR_THRE)); - - if (s->fcr & UART_FCR_FE) { - assert(!fifo8_is_empty(&s->xmit_fifo)); - s->tsr = fifo8_pop(&s->xmit_fifo); - if (!s->xmit_fifo.num) { - s->lsr |= UART_LSR_THRE; - } - } else { - s->tsr = s->thr; - s->lsr |= UART_LSR_THRE; - } - if ((s->lsr & UART_LSR_THRE) && !s->thr_ipending) { - s->thr_ipending = 1; - serial_update_irq(s); - } - } - - if (s->mcr & UART_MCR_LOOP) { - /* 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 && - qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, - serial_xmit, s) > 0) { - s->tsr_retry++; - return FALSE; - } - s->tsr_retry = 0; - } else { - s->tsr_retry = 0; - } - - /* Transmit another byte if it is already available. It is only - possible when FIFO is enabled and not empty. */ - } while (!(s->lsr & UART_LSR_THRE)); - - s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->lsr |= UART_LSR_TEMT; - - return FALSE; -} - - -/* Setter for FCR. - is_load flag means, that value is set while loading VM state - and interrupt should not be invoked */ -static void serial_write_fcr(SerialState *s, uint8_t val) -{ - /* Set fcr - val only has the bits that are supposed to "stick" */ - s->fcr = val; - - if (val & UART_FCR_FE) { - s->iir |= UART_IIR_FE; - /* Set recv_fifo trigger Level */ - switch (val & 0xC0) { - case UART_FCR_ITL_1: - s->recv_fifo_itl = 1; - break; - case UART_FCR_ITL_2: - s->recv_fifo_itl = 4; - break; - case UART_FCR_ITL_3: - s->recv_fifo_itl = 8; - break; - case UART_FCR_ITL_4: - s->recv_fifo_itl = 14; - break; - } - } else { - s->iir &= ~UART_IIR_FE; - } -} - -static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - SerialState *s = opaque; - - addr &= 7; - DPRINTF("write addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 "\n", addr, val); - switch(addr) { - default: - case 0: - if (s->lcr & UART_LCR_DLAB) { - s->divider = (s->divider & 0xff00) | val; - serial_update_parameters(s); - } else { - s->thr = (uint8_t) val; - if(s->fcr & UART_FCR_FE) { - /* xmit overruns overwrite data, so make space if needed */ - if (fifo8_is_full(&s->xmit_fifo)) { - fifo8_pop(&s->xmit_fifo); - } - fifo8_push(&s->xmit_fifo, s->thr); - } - s->thr_ipending = 0; - s->lsr &= ~UART_LSR_THRE; - s->lsr &= ~UART_LSR_TEMT; - serial_update_irq(s); - if (s->tsr_retry <= 0) { - serial_xmit(NULL, G_IO_OUT, s); - } - } - break; - case 1: - if (s->lcr & UART_LCR_DLAB) { - s->divider = (s->divider & 0x00ff) | (val << 8); - serial_update_parameters(s); - } else { - uint8_t changed = (s->ier ^ val) & 0x0f; - s->ier = val & 0x0f; - /* If the backend device is a real serial port, turn polling of the modem - * status lines on physical port on or off depending on UART_IER_MSI state. - */ - if ((changed & UART_IER_MSI) && s->poll_msl >= 0) { - if (s->ier & UART_IER_MSI) { - s->poll_msl = 1; - serial_update_msl(s); - } else { - timer_del(s->modem_status_poll); - s->poll_msl = 0; - } - } - - /* Turning on the THRE interrupt on IER can trigger the interrupt - * if LSR.THRE=1, even if it had been masked before by reading IIR. - * This is not in the datasheet, but Windows relies on it. It is - * unclear if THRE has to be resampled every time THRI becomes - * 1, or only on the rising edge. Bochs does the latter, and Windows - * always toggles IER to all zeroes and back to all ones, so do the - * same. - * - * If IER.THRI is zero, thr_ipending is not used. Set it to zero - * so that the thr_ipending subsection is not migrated. - */ - if (changed & UART_IER_THRI) { - if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) { - s->thr_ipending = 1; - } else { - s->thr_ipending = 0; - } - } - - if (changed) { - serial_update_irq(s); - } - } - break; - case 2: - /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */ - if ((val ^ s->fcr) & UART_FCR_FE) { - val |= UART_FCR_XFR | UART_FCR_RFR; - } - - /* FIFO clear */ - - if (val & UART_FCR_RFR) { - s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); - timer_del(s->fifo_timeout_timer); - s->timeout_ipending = 0; - fifo8_reset(&s->recv_fifo); - } - - if (val & UART_FCR_XFR) { - s->lsr |= UART_LSR_THRE; - s->thr_ipending = 1; - fifo8_reset(&s->xmit_fifo); - } - - serial_write_fcr(s, val & 0xC9); - serial_update_irq(s); - break; - case 3: - { - int break_enable; - s->lcr = val; - serial_update_parameters(s); - break_enable = (val >> 6) & 1; - if (break_enable != s->last_break_enable) { - s->last_break_enable = break_enable; - qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, - &break_enable); - } - } - break; - case 4: - { - int flags; - int old_mcr = s->mcr; - s->mcr = val & 0x1f; - if (val & UART_MCR_LOOP) - break; - - if (s->poll_msl >= 0 && old_mcr != s->mcr) { - - qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); - - flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR); - - if (val & UART_MCR_RTS) - flags |= CHR_TIOCM_RTS; - if (val & UART_MCR_DTR) - flags |= CHR_TIOCM_DTR; - - qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); - /* Update the modem status after a one-character-send wait-time, since there may be a response - from the device/computer at the other end of the serial line */ - timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time); - } - } - break; - case 5: - break; - case 6: - break; - case 7: - s->scr = val; - break; - } -} - -static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) -{ - SerialState *s = opaque; - uint32_t ret; - - addr &= 7; - switch(addr) { - default: - case 0: - if (s->lcr & UART_LCR_DLAB) { - ret = s->divider & 0xff; - } else { - if(s->fcr & UART_FCR_FE) { - ret = fifo8_is_empty(&s->recv_fifo) ? - 0 : fifo8_pop(&s->recv_fifo); - if (s->recv_fifo.num == 0) { - s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); - } else { - timer_mod(s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 4); - } - s->timeout_ipending = 0; - } else { - ret = s->rbr; - s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); - } - serial_update_irq(s); - if (!(s->mcr & UART_MCR_LOOP)) { - /* in loopback mode, don't receive any data */ - qemu_chr_accept_input(s->chr); - } - } - break; - case 1: - if (s->lcr & UART_LCR_DLAB) { - ret = (s->divider >> 8) & 0xff; - } else { - ret = s->ier; - } - break; - case 2: - ret = s->iir; - if ((ret & UART_IIR_ID) == UART_IIR_THRI) { - s->thr_ipending = 0; - serial_update_irq(s); - } - break; - case 3: - ret = s->lcr; - break; - case 4: - ret = s->mcr; - break; - case 5: - ret = s->lsr; - /* Clear break and overrun interrupts */ - if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) { - s->lsr &= ~(UART_LSR_BI|UART_LSR_OE); - serial_update_irq(s); - } - break; - case 6: - if (s->mcr & UART_MCR_LOOP) { - /* in loopback, the modem output pins are connected to the - inputs */ - ret = (s->mcr & 0x0c) << 4; - ret |= (s->mcr & 0x02) << 3; - ret |= (s->mcr & 0x01) << 5; - } else { - if (s->poll_msl >= 0) - serial_update_msl(s); - ret = s->msr; - /* Clear delta bits & msr int after read, if they were set */ - if (s->msr & UART_MSR_ANY_DELTA) { - s->msr &= 0xF0; - serial_update_irq(s); - } - } - break; - case 7: - ret = s->scr; - break; - } - DPRINTF("read addr=0x%" HWADDR_PRIx " val=0x%02x\n", addr, ret); - return ret; -} - -static int serial_can_receive(SerialState *s) -{ - if(s->fcr & UART_FCR_FE) { - if (s->recv_fifo.num < UART_FIFO_LENGTH) { - /* - * Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 - * if above. If UART_FIFO_LENGTH - fifo.count is advertised the - * effect will be to almost always fill the fifo completely before - * the guest has a chance to respond, effectively overriding the ITL - * that the guest has set. - */ - return (s->recv_fifo.num <= s->recv_fifo_itl) ? - s->recv_fifo_itl - s->recv_fifo.num : 1; - } else { - return 0; - } - } else { - return !(s->lsr & UART_LSR_DR); - } -} - -static void serial_receive_break(SerialState *s) -{ - s->rbr = 0; - /* When the LSR_DR is set a null byte is pushed into the fifo */ - recv_fifo_put(s, '\0'); - s->lsr |= UART_LSR_BI | UART_LSR_DR; - serial_update_irq(s); -} - -/* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */ -static void fifo_timeout_int (void *opaque) { - SerialState *s = opaque; - if (s->recv_fifo.num) { - s->timeout_ipending = 1; - serial_update_irq(s); - } -} - -static int serial_can_receive1(void *opaque) -{ - SerialState *s = opaque; - return serial_can_receive(s); -} - -static void serial_receive1(void *opaque, const uint8_t *buf, int size) -{ - SerialState *s = opaque; - - if (s->wakeup) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - } - if(s->fcr & UART_FCR_FE) { - int i; - for (i = 0; i < size; i++) { - recv_fifo_put(s, buf[i]); - } - s->lsr |= UART_LSR_DR; - /* call the timeout receive callback in 4 char transmit time */ - timer_mod(s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 4); - } else { - if (s->lsr & UART_LSR_DR) - s->lsr |= UART_LSR_OE; - s->rbr = buf[0]; - s->lsr |= UART_LSR_DR; - } - serial_update_irq(s); -} - -static void serial_event(void *opaque, int event) -{ - SerialState *s = opaque; - DPRINTF("event %x\n", event); - if (event == CHR_EVENT_BREAK) - serial_receive_break(s); -} - -static void serial_pre_save(void *opaque) -{ - SerialState *s = opaque; - s->fcr_vmstate = s->fcr; -} - -static int serial_pre_load(void *opaque) -{ - SerialState *s = opaque; - s->thr_ipending = -1; - s->poll_msl = -1; - return 0; -} - -static int serial_post_load(void *opaque, int version_id) -{ - SerialState *s = opaque; - - if (version_id < 3) { - s->fcr_vmstate = 0; - } - if (s->thr_ipending == -1) { - s->thr_ipending = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); - } - s->last_break_enable = (s->lcr >> 6) & 1; - /* Initialize fcr via setter to perform essential side-effects */ - serial_write_fcr(s, s->fcr_vmstate); - serial_update_parameters(s); - return 0; -} - -static bool serial_thr_ipending_needed(void *opaque) -{ - SerialState *s = opaque; - - if (s->ier & UART_IER_THRI) { - bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); - return s->thr_ipending != expected_value; - } else { - /* LSR.THRE will be sampled again when the interrupt is - * enabled. thr_ipending is not used in this case, do - * not migrate it. - */ - return false; - } -} - -static const VMStateDescription vmstate_serial_thr_ipending = { - .name = "serial/thr_ipending", - .version_id = 1, - .minimum_version_id = 1, - .needed = serial_thr_ipending_needed, - .fields = (VMStateField[]) { - VMSTATE_INT32(thr_ipending, SerialState), - VMSTATE_END_OF_LIST() - } -}; - -static bool serial_tsr_needed(void *opaque) -{ - SerialState *s = (SerialState *)opaque; - return s->tsr_retry != 0; -} - -static const VMStateDescription vmstate_serial_tsr = { - .name = "serial/tsr", - .version_id = 1, - .minimum_version_id = 1, - .needed = serial_tsr_needed, - .fields = (VMStateField[]) { - VMSTATE_INT32(tsr_retry, SerialState), - VMSTATE_UINT8(thr, SerialState), - VMSTATE_UINT8(tsr, SerialState), - VMSTATE_END_OF_LIST() - } -}; - -static bool serial_recv_fifo_needed(void *opaque) -{ - SerialState *s = (SerialState *)opaque; - return !fifo8_is_empty(&s->recv_fifo); - -} - -static const VMStateDescription vmstate_serial_recv_fifo = { - .name = "serial/recv_fifo", - .version_id = 1, - .minimum_version_id = 1, - .needed = serial_recv_fifo_needed, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(recv_fifo, SerialState, 1, vmstate_fifo8, Fifo8), - VMSTATE_END_OF_LIST() - } -}; - -static bool serial_xmit_fifo_needed(void *opaque) -{ - SerialState *s = (SerialState *)opaque; - return !fifo8_is_empty(&s->xmit_fifo); -} - -static const VMStateDescription vmstate_serial_xmit_fifo = { - .name = "serial/xmit_fifo", - .version_id = 1, - .minimum_version_id = 1, - .needed = serial_xmit_fifo_needed, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(xmit_fifo, SerialState, 1, vmstate_fifo8, Fifo8), - VMSTATE_END_OF_LIST() - } -}; - -static bool serial_fifo_timeout_timer_needed(void *opaque) -{ - SerialState *s = (SerialState *)opaque; - return timer_pending(s->fifo_timeout_timer); -} - -static const VMStateDescription vmstate_serial_fifo_timeout_timer = { - .name = "serial/fifo_timeout_timer", - .version_id = 1, - .minimum_version_id = 1, - .needed = serial_fifo_timeout_timer_needed, - .fields = (VMStateField[]) { - VMSTATE_TIMER_PTR(fifo_timeout_timer, SerialState), - VMSTATE_END_OF_LIST() - } -}; - -static bool serial_timeout_ipending_needed(void *opaque) -{ - SerialState *s = (SerialState *)opaque; - return s->timeout_ipending != 0; -} - -static const VMStateDescription vmstate_serial_timeout_ipending = { - .name = "serial/timeout_ipending", - .version_id = 1, - .minimum_version_id = 1, - .needed = serial_timeout_ipending_needed, - .fields = (VMStateField[]) { - VMSTATE_INT32(timeout_ipending, SerialState), - VMSTATE_END_OF_LIST() - } -}; - -static bool serial_poll_needed(void *opaque) -{ - SerialState *s = (SerialState *)opaque; - return s->poll_msl >= 0; -} - -static const VMStateDescription vmstate_serial_poll = { - .name = "serial/poll", - .version_id = 1, - .needed = serial_poll_needed, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(poll_msl, SerialState), - VMSTATE_TIMER_PTR(modem_status_poll, SerialState), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_serial = { - .name = "serial", - .version_id = 3, - .minimum_version_id = 2, - .pre_save = serial_pre_save, - .pre_load = serial_pre_load, - .post_load = serial_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT16_V(divider, SerialState, 2), - VMSTATE_UINT8(rbr, SerialState), - VMSTATE_UINT8(ier, SerialState), - VMSTATE_UINT8(iir, SerialState), - VMSTATE_UINT8(lcr, SerialState), - VMSTATE_UINT8(mcr, SerialState), - VMSTATE_UINT8(lsr, SerialState), - VMSTATE_UINT8(msr, SerialState), - VMSTATE_UINT8(scr, SerialState), - VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_serial_thr_ipending, - &vmstate_serial_tsr, - &vmstate_serial_recv_fifo, - &vmstate_serial_xmit_fifo, - &vmstate_serial_fifo_timeout_timer, - &vmstate_serial_timeout_ipending, - &vmstate_serial_poll, - NULL - } -}; - -static void serial_reset(void *opaque) -{ - SerialState *s = opaque; - - s->rbr = 0; - s->ier = 0; - s->iir = UART_IIR_NO_INT; - s->lcr = 0; - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; - s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; - /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */ - s->divider = 0x0C; - s->mcr = UART_MCR_OUT2; - s->scr = 0; - s->tsr_retry = 0; - s->char_transmit_time = (NANOSECONDS_PER_SECOND / 9600) * 10; - s->poll_msl = 0; - - s->timeout_ipending = 0; - timer_del(s->fifo_timeout_timer); - timer_del(s->modem_status_poll); - - fifo8_reset(&s->recv_fifo); - fifo8_reset(&s->xmit_fifo); - - s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - s->thr_ipending = 0; - s->last_break_enable = 0; - qemu_irq_lower(s->irq); - - serial_update_msl(s); - s->msr &= ~UART_MSR_ANY_DELTA; -} - -void serial_realize_core(SerialState *s, Error **errp) -{ - if (!s->chr) { - error_setg(errp, "Can't create serial device, empty char device"); - return; - } - - s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s); - - s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s); - qemu_register_reset(serial_reset, s); - - qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, - serial_event, s); - fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH); - fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH); - serial_reset(s); -} - -void serial_exit_core(SerialState *s) -{ - qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); - qemu_unregister_reset(serial_reset, s); -} - -/* Change the main reference oscillator frequency. */ -void serial_set_frequency(SerialState *s, uint32_t frequency) -{ - s->baudbase = frequency; - serial_update_parameters(s); -} - -const MemoryRegionOps serial_io_ops = { - .read = serial_ioport_read, - .write = serial_ioport_write, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -SerialState *serial_init(int base, qemu_irq irq, int baudbase, - CharDriverState *chr, MemoryRegion *system_io) -{ - SerialState *s; - - s = g_malloc0(sizeof(SerialState)); - - s->irq = irq; - s->baudbase = baudbase; - s->chr = chr; - serial_realize_core(s, &error_fatal); - - vmstate_register(NULL, base, &vmstate_serial, s); - - memory_region_init_io(&s->io, NULL, &serial_io_ops, s, "serial", 8); - memory_region_add_subregion(system_io, base, &s->io); - - return s; -} - -/* Memory mapped interface */ -static uint64_t serial_mm_read(void *opaque, hwaddr addr, - unsigned size) -{ - SerialState *s = opaque; - return serial_ioport_read(s, addr >> s->it_shift, 1); -} - -static void serial_mm_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - SerialState *s = opaque; - value &= ~0u >> (32 - (size * 8)); - serial_ioport_write(s, addr >> s->it_shift, value, 1); -} - -static const MemoryRegionOps serial_mm_ops[3] = { - [DEVICE_NATIVE_ENDIAN] = { - .read = serial_mm_read, - .write = serial_mm_write, - .endianness = DEVICE_NATIVE_ENDIAN, - }, - [DEVICE_LITTLE_ENDIAN] = { - .read = serial_mm_read, - .write = serial_mm_write, - .endianness = DEVICE_LITTLE_ENDIAN, - }, - [DEVICE_BIG_ENDIAN] = { - .read = serial_mm_read, - .write = serial_mm_write, - .endianness = DEVICE_BIG_ENDIAN, - }, -}; - -SerialState *serial_mm_init(MemoryRegion *address_space, - hwaddr base, int it_shift, - qemu_irq irq, int baudbase, - CharDriverState *chr, enum device_endian end) -{ - SerialState *s; - - s = g_malloc0(sizeof(SerialState)); - - s->it_shift = it_shift; - s->irq = irq; - s->baudbase = baudbase; - s->chr = chr; - - serial_realize_core(s, &error_fatal); - vmstate_register(NULL, base, &vmstate_serial, s); - - memory_region_init_io(&s->io, NULL, &serial_mm_ops[end], s, - "serial", 8 << it_shift); - memory_region_add_subregion(address_space, base, &s->io); - return s; -} diff --git a/qemu/hw/char/sh_serial.c b/qemu/hw/char/sh_serial.c deleted file mode 100644 index 4c55dcb7d..000000000 --- a/qemu/hw/char/sh_serial.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * QEMU SCI/SCIF serial port emulation - * - * Copyright (c) 2007 Magnus Damm - * - * Based on serial.c - QEMU 16450 UART emulation - * Copyright (c) 2003-2004 Fabrice Bellard - * - * 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. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sh4/sh.h" -#include "sysemu/char.h" -#include "exec/address-spaces.h" - -//#define DEBUG_SERIAL - -#define SH_SERIAL_FLAG_TEND (1 << 0) -#define SH_SERIAL_FLAG_TDE (1 << 1) -#define SH_SERIAL_FLAG_RDF (1 << 2) -#define SH_SERIAL_FLAG_BRK (1 << 3) -#define SH_SERIAL_FLAG_DR (1 << 4) - -#define SH_RX_FIFO_LENGTH (16) - -typedef struct { - MemoryRegion iomem; - MemoryRegion iomem_p4; - MemoryRegion iomem_a7; - uint8_t smr; - uint8_t brr; - uint8_t scr; - uint8_t dr; /* ftdr / tdr */ - uint8_t sr; /* fsr / ssr */ - uint16_t fcr; - uint8_t sptr; - - uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */ - uint8_t rx_cnt; - uint8_t rx_tail; - uint8_t rx_head; - - int freq; - int feat; - int flags; - int rtrg; - - CharDriverState *chr; - - qemu_irq eri; - qemu_irq rxi; - qemu_irq txi; - qemu_irq tei; - qemu_irq bri; -} sh_serial_state; - -static void sh_serial_clear_fifo(sh_serial_state * s) -{ - memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH); - s->rx_cnt = 0; - s->rx_head = 0; - s->rx_tail = 0; -} - -static void sh_serial_write(void *opaque, hwaddr offs, - uint64_t val, unsigned size) -{ - sh_serial_state *s = opaque; - unsigned char ch; - -#ifdef DEBUG_SERIAL - printf("sh_serial: write offs=0x%02x val=0x%02x\n", - offs, val); -#endif - switch(offs) { - case 0x00: /* SMR */ - s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff); - return; - case 0x04: /* BRR */ - s->brr = val; - return; - case 0x08: /* SCR */ - /* TODO : For SH7751, SCIF mask should be 0xfb. */ - s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); - if (!(val & (1 << 5))) - s->flags |= SH_SERIAL_FLAG_TEND; - if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) { - qemu_set_irq(s->txi, val & (1 << 7)); - } - if (!(val & (1 << 6))) { - qemu_set_irq(s->rxi, 0); - } - return; - case 0x0c: /* FTDR / TDR */ - if (s->chr) { - ch = val; - qemu_chr_fe_write(s->chr, &ch, 1); - } - s->dr = val; - s->flags &= ~SH_SERIAL_FLAG_TDE; - return; -#if 0 - case 0x14: /* FRDR / RDR */ - ret = 0; - break; -#endif - } - if (s->feat & SH_SERIAL_FEAT_SCIF) { - switch(offs) { - case 0x10: /* FSR */ - if (!(val & (1 << 6))) - s->flags &= ~SH_SERIAL_FLAG_TEND; - if (!(val & (1 << 5))) - s->flags &= ~SH_SERIAL_FLAG_TDE; - if (!(val & (1 << 4))) - s->flags &= ~SH_SERIAL_FLAG_BRK; - if (!(val & (1 << 1))) - s->flags &= ~SH_SERIAL_FLAG_RDF; - if (!(val & (1 << 0))) - s->flags &= ~SH_SERIAL_FLAG_DR; - - if (!(val & (1 << 1)) || !(val & (1 << 0))) { - if (s->rxi) { - qemu_set_irq(s->rxi, 0); - } - } - return; - case 0x18: /* FCR */ - s->fcr = val; - switch ((val >> 6) & 3) { - case 0: - s->rtrg = 1; - break; - case 1: - s->rtrg = 4; - break; - case 2: - s->rtrg = 8; - break; - case 3: - s->rtrg = 14; - break; - } - if (val & (1 << 1)) { - sh_serial_clear_fifo(s); - s->sr &= ~(1 << 1); - } - - return; - case 0x20: /* SPTR */ - s->sptr = val & 0xf3; - return; - case 0x24: /* LSR */ - return; - } - } - else { - switch(offs) { -#if 0 - case 0x0c: - ret = s->dr; - break; - case 0x10: - ret = 0; - break; -#endif - case 0x1c: - s->sptr = val & 0x8f; - return; - } - } - - fprintf(stderr, "sh_serial: unsupported write to 0x%02" - HWADDR_PRIx "\n", offs); - abort(); -} - -static uint64_t sh_serial_read(void *opaque, hwaddr offs, - unsigned size) -{ - sh_serial_state *s = opaque; - uint32_t ret = ~0; - -#if 0 - switch(offs) { - case 0x00: - ret = s->smr; - break; - case 0x04: - ret = s->brr; - break; - case 0x08: - ret = s->scr; - break; - case 0x14: - ret = 0; - break; - } -#endif - if (s->feat & SH_SERIAL_FEAT_SCIF) { - switch(offs) { - case 0x00: /* SMR */ - ret = s->smr; - break; - case 0x08: /* SCR */ - ret = s->scr; - break; - case 0x10: /* FSR */ - ret = 0; - if (s->flags & SH_SERIAL_FLAG_TEND) - ret |= (1 << 6); - if (s->flags & SH_SERIAL_FLAG_TDE) - ret |= (1 << 5); - if (s->flags & SH_SERIAL_FLAG_BRK) - ret |= (1 << 4); - if (s->flags & SH_SERIAL_FLAG_RDF) - ret |= (1 << 1); - if (s->flags & SH_SERIAL_FLAG_DR) - ret |= (1 << 0); - - if (s->scr & (1 << 5)) - s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; - - break; - case 0x14: - if (s->rx_cnt > 0) { - ret = s->rx_fifo[s->rx_tail++]; - s->rx_cnt--; - if (s->rx_tail == SH_RX_FIFO_LENGTH) - s->rx_tail = 0; - if (s->rx_cnt < s->rtrg) - s->flags &= ~SH_SERIAL_FLAG_RDF; - } - break; - case 0x18: - ret = s->fcr; - break; - case 0x1c: - ret = s->rx_cnt; - break; - case 0x20: - ret = s->sptr; - break; - case 0x24: - ret = 0; - break; - } - } - else { - switch(offs) { -#if 0 - case 0x0c: - ret = s->dr; - break; - case 0x10: - ret = 0; - break; - case 0x14: - ret = s->rx_fifo[0]; - break; -#endif - case 0x1c: - ret = s->sptr; - break; - } - } -#ifdef DEBUG_SERIAL - printf("sh_serial: read offs=0x%02x val=0x%x\n", - offs, ret); -#endif - - if (ret & ~((1 << 16) - 1)) { - fprintf(stderr, "sh_serial: unsupported read from 0x%02" - HWADDR_PRIx "\n", offs); - abort(); - } - - return ret; -} - -static int sh_serial_can_receive(sh_serial_state *s) -{ - return s->scr & (1 << 4); -} - -static void sh_serial_receive_break(sh_serial_state *s) -{ - if (s->feat & SH_SERIAL_FEAT_SCIF) - s->sr |= (1 << 4); -} - -static int sh_serial_can_receive1(void *opaque) -{ - sh_serial_state *s = opaque; - return sh_serial_can_receive(s); -} - -static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) -{ - sh_serial_state *s = opaque; - - if (s->feat & SH_SERIAL_FEAT_SCIF) { - int i; - for (i = 0; i < size; i++) { - if (s->rx_cnt < SH_RX_FIFO_LENGTH) { - s->rx_fifo[s->rx_head++] = buf[i]; - if (s->rx_head == SH_RX_FIFO_LENGTH) { - s->rx_head = 0; - } - s->rx_cnt++; - if (s->rx_cnt >= s->rtrg) { - s->flags |= SH_SERIAL_FLAG_RDF; - if (s->scr & (1 << 6) && s->rxi) { - qemu_set_irq(s->rxi, 1); - } - } - } - } - } else { - s->rx_fifo[0] = buf[0]; - } -} - -static void sh_serial_event(void *opaque, int event) -{ - sh_serial_state *s = opaque; - if (event == CHR_EVENT_BREAK) - sh_serial_receive_break(s); -} - -static const MemoryRegionOps sh_serial_ops = { - .read = sh_serial_read, - .write = sh_serial_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -void sh_serial_init(MemoryRegion *sysmem, - hwaddr base, int feat, - uint32_t freq, CharDriverState *chr, - qemu_irq eri_source, - qemu_irq rxi_source, - qemu_irq txi_source, - qemu_irq tei_source, - qemu_irq bri_source) -{ - sh_serial_state *s; - - s = g_malloc0(sizeof(sh_serial_state)); - - s->feat = feat; - s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; - s->rtrg = 1; - - s->smr = 0; - s->brr = 0xff; - s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */ - s->sptr = 0; - - if (feat & SH_SERIAL_FEAT_SCIF) { - s->fcr = 0; - } - else { - s->dr = 0xff; - } - - sh_serial_clear_fifo(s); - - memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s, - "serial", 0x100000000ULL); - - memory_region_init_alias(&s->iomem_p4, NULL, "serial-p4", &s->iomem, - 0, 0x28); - memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4); - - memory_region_init_alias(&s->iomem_a7, NULL, "serial-a7", &s->iomem, - 0, 0x28); - memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); - - s->chr = chr; - - if (chr) { - qemu_chr_fe_claim_no_fail(chr); - qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, - sh_serial_event, s); - } - - s->eri = eri_source; - s->rxi = rxi_source; - s->txi = txi_source; - s->tei = tei_source; - s->bri = bri_source; -} diff --git a/qemu/hw/char/spapr_vty.c b/qemu/hw/char/spapr_vty.c deleted file mode 100644 index 3498d7b05..000000000 --- a/qemu/hw/char/spapr_vty.c +++ /dev/null @@ -1,249 +0,0 @@ -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/qdev.h" -#include "sysemu/char.h" -#include "hw/ppc/spapr.h" -#include "hw/ppc/spapr_vio.h" - -#define VTERM_BUFSIZE 16 - -typedef struct VIOsPAPRVTYDevice { - VIOsPAPRDevice sdev; - CharDriverState *chardev; - uint32_t in, out; - uint8_t buf[VTERM_BUFSIZE]; -} VIOsPAPRVTYDevice; - -#define TYPE_VIO_SPAPR_VTY_DEVICE "spapr-vty" -#define VIO_SPAPR_VTY_DEVICE(obj) \ - OBJECT_CHECK(VIOsPAPRVTYDevice, (obj), TYPE_VIO_SPAPR_VTY_DEVICE) - -static int vty_can_receive(void *opaque) -{ - VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque); - - return (dev->in - dev->out) < VTERM_BUFSIZE; -} - -static void vty_receive(void *opaque, const uint8_t *buf, int size) -{ - VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque); - int i; - - if ((dev->in == dev->out) && size) { - /* toggle line to simulate edge interrupt */ - qemu_irq_pulse(spapr_vio_qirq(&dev->sdev)); - } - for (i = 0; i < size; i++) { - assert((dev->in - dev->out) < VTERM_BUFSIZE); - dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i]; - } -} - -static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max) -{ - VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); - int n = 0; - - while ((n < max) && (dev->out != dev->in)) { - buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE]; - } - - qemu_chr_accept_input(dev->chardev); - - return n; -} - -void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) -{ - VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); - - /* FIXME: should check the qemu_chr_fe_write() return value */ - qemu_chr_fe_write(dev->chardev, buf, len); -} - -static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp) -{ - VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); - - if (!dev->chardev) { - error_setg(errp, "chardev property not set"); - return; - } - - qemu_chr_add_handlers(dev->chardev, vty_can_receive, - vty_receive, NULL, dev); -} - -/* Forward declaration */ -static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong reg = args[0]; - target_ulong len = args[1]; - target_ulong char0_7 = args[2]; - target_ulong char8_15 = args[3]; - VIOsPAPRDevice *sdev; - uint8_t buf[16]; - - sdev = vty_lookup(spapr, reg); - if (!sdev) { - return H_PARAMETER; - } - - if (len > 16) { - return H_PARAMETER; - } - - *((uint64_t *)buf) = cpu_to_be64(char0_7); - *((uint64_t *)buf + 1) = cpu_to_be64(char8_15); - - vty_putchars(sdev, buf, len); - - return H_SUCCESS; -} - -static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong reg = args[0]; - target_ulong *len = args + 0; - target_ulong *char0_7 = args + 1; - target_ulong *char8_15 = args + 2; - VIOsPAPRDevice *sdev; - uint8_t buf[16]; - - sdev = vty_lookup(spapr, reg); - if (!sdev) { - return H_PARAMETER; - } - - *len = vty_getchars(sdev, buf, sizeof(buf)); - if (*len < 16) { - memset(buf + *len, 0, 16 - *len); - } - - *char0_7 = be64_to_cpu(*((uint64_t *)buf)); - *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1)); - - return H_SUCCESS; -} - -void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev) -{ - DeviceState *dev; - - dev = qdev_create(&bus->bus, "spapr-vty"); - qdev_prop_set_chr(dev, "chardev", chardev); - qdev_init_nofail(dev); -} - -static Property spapr_vty_properties[] = { - DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev), - DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev), - DEFINE_PROP_END_OF_LIST(), -}; - -static const VMStateDescription vmstate_spapr_vty = { - .name = "spapr_vty", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVTYDevice), - - VMSTATE_UINT32(in, VIOsPAPRVTYDevice), - VMSTATE_UINT32(out, VIOsPAPRVTYDevice), - VMSTATE_BUFFER(buf, VIOsPAPRVTYDevice), - VMSTATE_END_OF_LIST() - }, -}; - -static void spapr_vty_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); - - k->realize = spapr_vty_realize; - k->dt_name = "vty"; - k->dt_type = "serial"; - k->dt_compatible = "hvterm1"; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - dc->props = spapr_vty_properties; - dc->vmsd = &vmstate_spapr_vty; -} - -static const TypeInfo spapr_vty_info = { - .name = TYPE_VIO_SPAPR_VTY_DEVICE, - .parent = TYPE_VIO_SPAPR_DEVICE, - .instance_size = sizeof(VIOsPAPRVTYDevice), - .class_init = spapr_vty_class_init, -}; - -VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) -{ - VIOsPAPRDevice *sdev, *selected; - BusChild *kid; - - /* - * To avoid the console bouncing around we want one VTY to be - * the "default". We haven't really got anything to go on, so - * arbitrarily choose the one with the lowest reg value. - */ - - selected = NULL; - QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { - DeviceState *iter = kid->child; - - /* Only look at VTY devices */ - if (!object_dynamic_cast(OBJECT(iter), TYPE_VIO_SPAPR_VTY_DEVICE)) { - continue; - } - - sdev = VIO_SPAPR_DEVICE(iter); - - /* First VTY we've found, so it is selected for now */ - if (!selected) { - selected = sdev; - continue; - } - - /* Choose VTY with lowest reg value */ - if (sdev->reg < selected->reg) { - selected = sdev; - } - } - - return selected; -} - -VIOsPAPRDevice *vty_lookup(sPAPRMachineState *spapr, target_ulong reg) -{ - VIOsPAPRDevice *sdev; - - sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - if (!sdev && reg == 0) { - /* Hack for kernel early debug, which always specifies reg==0. - * We search all VIO devices, and grab the vty with the lowest - * reg. This attempts to mimic existing PowerVM behaviour - * (early debug does work there, despite having no vty with - * reg==0. */ - return spapr_vty_get_default(spapr->vio_bus); - } - - if (!object_dynamic_cast(OBJECT(sdev), TYPE_VIO_SPAPR_VTY_DEVICE)) { - return NULL; - } - - return sdev; -} - -static void spapr_vty_register_types(void) -{ - spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); - spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); - type_register_static(&spapr_vty_info); -} - -type_init(spapr_vty_register_types) diff --git a/qemu/hw/char/stm32f2xx_usart.c b/qemu/hw/char/stm32f2xx_usart.c deleted file mode 100644 index a94d61ceb..000000000 --- a/qemu/hw/char/stm32f2xx_usart.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * STM32F2XX USART - * - * Copyright (c) 2014 Alistair Francis - * - * 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. - */ - -#include "qemu/osdep.h" -#include "hw/char/stm32f2xx_usart.h" - -#ifndef STM_USART_ERR_DEBUG -#define STM_USART_ERR_DEBUG 0 -#endif - -#define DB_PRINT_L(lvl, fmt, args...) do { \ - if (STM_USART_ERR_DEBUG >= lvl) { \ - qemu_log("%s: " fmt, __func__, ## args); \ - } \ -} while (0); - -#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) - -static int stm32f2xx_usart_can_receive(void *opaque) -{ - STM32F2XXUsartState *s = opaque; - - if (!(s->usart_sr & USART_SR_RXNE)) { - return 1; - } - - return 0; -} - -static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size) -{ - STM32F2XXUsartState *s = opaque; - - s->usart_dr = *buf; - - if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) { - /* USART not enabled - drop the chars */ - DB_PRINT("Dropping the chars\n"); - return; - } - - s->usart_sr |= USART_SR_RXNE; - - if (s->usart_cr1 & USART_CR1_RXNEIE) { - qemu_set_irq(s->irq, 1); - } - - DB_PRINT("Receiving: %c\n", s->usart_dr); -} - -static void stm32f2xx_usart_reset(DeviceState *dev) -{ - STM32F2XXUsartState *s = STM32F2XX_USART(dev); - - s->usart_sr = USART_SR_RESET; - s->usart_dr = 0x00000000; - s->usart_brr = 0x00000000; - s->usart_cr1 = 0x00000000; - s->usart_cr2 = 0x00000000; - s->usart_cr3 = 0x00000000; - s->usart_gtpr = 0x00000000; - - qemu_set_irq(s->irq, 0); -} - -static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr, - unsigned int size) -{ - STM32F2XXUsartState *s = opaque; - uint64_t retvalue; - - DB_PRINT("Read 0x%"HWADDR_PRIx"\n", addr); - - switch (addr) { - case USART_SR: - retvalue = s->usart_sr; - s->usart_sr &= ~USART_SR_TC; - if (s->chr) { - qemu_chr_accept_input(s->chr); - } - return retvalue; - case USART_DR: - DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr); - s->usart_sr |= USART_SR_TXE; - s->usart_sr &= ~USART_SR_RXNE; - if (s->chr) { - qemu_chr_accept_input(s->chr); - } - qemu_set_irq(s->irq, 0); - return s->usart_dr & 0x3FF; - case USART_BRR: - return s->usart_brr; - case USART_CR1: - return s->usart_cr1; - case USART_CR2: - return s->usart_cr2; - case USART_CR3: - return s->usart_cr3; - case USART_GTPR: - return s->usart_gtpr; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); - return 0; - } - - return 0; -} - -static void stm32f2xx_usart_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - STM32F2XXUsartState *s = opaque; - uint32_t value = val64; - unsigned char ch; - - DB_PRINT("Write 0x%" PRIx32 ", 0x%"HWADDR_PRIx"\n", value, addr); - - switch (addr) { - case USART_SR: - if (value <= 0x3FF) { - s->usart_sr = value; - } else { - s->usart_sr &= value; - } - if (!(s->usart_sr & USART_SR_RXNE)) { - qemu_set_irq(s->irq, 0); - } - return; - case USART_DR: - if (value < 0xF000) { - ch = value; - if (s->chr) { - qemu_chr_fe_write_all(s->chr, &ch, 1); - } - s->usart_sr |= USART_SR_TC; - s->usart_sr &= ~USART_SR_TXE; - } - return; - case USART_BRR: - s->usart_brr = value; - return; - case USART_CR1: - s->usart_cr1 = value; - if (s->usart_cr1 & USART_CR1_RXNEIE && - s->usart_sr & USART_SR_RXNE) { - qemu_set_irq(s->irq, 1); - } - return; - case USART_CR2: - s->usart_cr2 = value; - return; - case USART_CR3: - s->usart_cr3 = value; - return; - case USART_GTPR: - s->usart_gtpr = value; - return; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); - } -} - -static const MemoryRegionOps stm32f2xx_usart_ops = { - .read = stm32f2xx_usart_read, - .write = stm32f2xx_usart_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void stm32f2xx_usart_init(Object *obj) -{ - STM32F2XXUsartState *s = STM32F2XX_USART(obj); - - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); - - memory_region_init_io(&s->mmio, obj, &stm32f2xx_usart_ops, s, - TYPE_STM32F2XX_USART, 0x2000); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - - if (s->chr) { - qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive, - stm32f2xx_usart_receive, NULL, s); - } -} - -static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = stm32f2xx_usart_reset; - /* Reason: instance_init() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo stm32f2xx_usart_info = { - .name = TYPE_STM32F2XX_USART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(STM32F2XXUsartState), - .instance_init = stm32f2xx_usart_init, - .class_init = stm32f2xx_usart_class_init, -}; - -static void stm32f2xx_usart_register_types(void) -{ - type_register_static(&stm32f2xx_usart_info); -} - -type_init(stm32f2xx_usart_register_types) diff --git a/qemu/hw/char/virtio-console.c b/qemu/hw/char/virtio-console.c deleted file mode 100644 index 2e36481a7..000000000 --- a/qemu/hw/char/virtio-console.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Virtio Console and Generic Serial Port Devices - * - * Copyright Red Hat, Inc. 2009, 2010 - * - * Authors: - * Amit Shah - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "sysemu/char.h" -#include "qemu/error-report.h" -#include "trace.h" -#include "hw/virtio/virtio-serial.h" -#include "qapi-event.h" - -#define TYPE_VIRTIO_CONSOLE_SERIAL_PORT "virtserialport" -#define VIRTIO_CONSOLE(obj) \ - OBJECT_CHECK(VirtConsole, (obj), TYPE_VIRTIO_CONSOLE_SERIAL_PORT) - -typedef struct VirtConsole { - VirtIOSerialPort parent_obj; - - CharDriverState *chr; - guint watch; -} 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; - - vcon->watch = 0; - virtio_serial_throttle_port(VIRTIO_SERIAL_PORT(vcon), 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, ssize_t len) -{ - VirtConsole *vcon = VIRTIO_CONSOLE(port); - ssize_t ret; - - if (!vcon->chr) { - /* If there's no backend, we can just say we consumed all data. */ - return len; - } - - ret = qemu_chr_fe_write(vcon->chr, buf, len); - trace_virtio_console_flush_buf(port->id, len, ret); - - if (ret < len) { - 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. - */ - if (ret < 0) - ret = 0; - if (!k->is_console) { - virtio_serial_throttle_port(port, true); - if (!vcon->watch) { - vcon->watch = qemu_chr_fe_add_watch(vcon->chr, - G_IO_OUT|G_IO_HUP, - chr_write_unblocked, vcon); - } - } - } - return ret; -} - -/* Callback function that's called when the guest opens/closes the port */ -static void set_guest_connected(VirtIOSerialPort *port, int guest_connected) -{ - VirtConsole *vcon = VIRTIO_CONSOLE(port); - DeviceState *dev = DEVICE(port); - - if (vcon->chr) { - qemu_chr_fe_set_open(vcon->chr, guest_connected); - } - - if (dev->id) { - qapi_event_send_vserport_change(dev->id, guest_connected, - &error_abort); - } -} - -static void guest_writable(VirtIOSerialPort *port) -{ - VirtConsole *vcon = VIRTIO_CONSOLE(port); - - if (vcon->chr) { - qemu_chr_accept_input(vcon->chr); - } -} - -/* Readiness of the guest to accept data on a port */ -static int chr_can_read(void *opaque) -{ - VirtConsole *vcon = opaque; - - return virtio_serial_guest_ready(VIRTIO_SERIAL_PORT(vcon)); -} - -/* Send data from a char device over to the guest */ -static void chr_read(void *opaque, const uint8_t *buf, int size) -{ - VirtConsole *vcon = opaque; - VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon); - - trace_virtio_console_chr_read(port->id, size); - virtio_serial_write(port, buf, size); -} - -static void chr_event(void *opaque, int event) -{ - VirtConsole *vcon = opaque; - VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon); - - trace_virtio_console_chr_event(port->id, event); - switch (event) { - case CHR_EVENT_OPENED: - virtio_serial_open(port); - break; - case CHR_EVENT_CLOSED: - if (vcon->watch) { - g_source_remove(vcon->watch); - vcon->watch = 0; - } - virtio_serial_close(port); - break; - } -} - -static void virtconsole_realize(DeviceState *dev, Error **errp) -{ - VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); - VirtConsole *vcon = VIRTIO_CONSOLE(dev); - VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev); - - if (port->id == 0 && !k->is_console) { - error_setg(errp, "Port number 0 on virtio-serial devices reserved " - "for virtconsole devices for backward compatibility."); - return; - } - - if (vcon->chr) { - vcon->chr->explicit_fe_open = 1; - qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, - vcon); - } -} - -static void virtconsole_unrealize(DeviceState *dev, Error **errp) -{ - VirtConsole *vcon = VIRTIO_CONSOLE(dev); - - if (vcon->watch) { - g_source_remove(vcon->watch); - } -} - -static void virtconsole_class_init(ObjectClass *klass, void *data) -{ - VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); - - k->is_console = true; -} - -static const TypeInfo virtconsole_info = { - .name = "virtconsole", - .parent = TYPE_VIRTIO_CONSOLE_SERIAL_PORT, - .class_init = virtconsole_class_init, -}; - -static Property virtserialport_properties[] = { - DEFINE_PROP_CHR("chardev", VirtConsole, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtserialport_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); - - k->realize = virtconsole_realize; - k->unrealize = virtconsole_unrealize; - k->have_data = flush_buf; - k->set_guest_connected = set_guest_connected; - k->guest_writable = guest_writable; - dc->props = virtserialport_properties; -} - -static const TypeInfo virtserialport_info = { - .name = TYPE_VIRTIO_CONSOLE_SERIAL_PORT, - .parent = TYPE_VIRTIO_SERIAL_PORT, - .instance_size = sizeof(VirtConsole), - .class_init = virtserialport_class_init, -}; - -static void virtconsole_register_types(void) -{ - type_register_static(&virtserialport_info); - type_register_static(&virtconsole_info); -} - -type_init(virtconsole_register_types) diff --git a/qemu/hw/char/virtio-serial-bus.c b/qemu/hw/char/virtio-serial-bus.c deleted file mode 100644 index 6e5de6dec..000000000 --- a/qemu/hw/char/virtio-serial-bus.c +++ /dev/null @@ -1,1149 +0,0 @@ -/* - * A bus for connecting virtio serial and console ports - * - * Copyright (C) 2009, 2010 Red Hat, Inc. - * - * Author(s): - * Amit Shah - * - * Some earlier parts are: - * Copyright IBM, Corp. 2008 - * authored by - * Christian Ehrhardt - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/iov.h" -#include "monitor/monitor.h" -#include "qemu/error-report.h" -#include "qemu/queue.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "hw/virtio/virtio-serial.h" -#include "hw/virtio/virtio-access.h" - -static struct VirtIOSerialDevices { - QLIST_HEAD(, VirtIOSerial) devices; -} vserdevices; - -static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id) -{ - VirtIOSerialPort *port; - - if (id == VIRTIO_CONSOLE_BAD_ID) { - return NULL; - } - - QTAILQ_FOREACH(port, &vser->ports, next) { - if (port->id == id) - return port; - } - return NULL; -} - -static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq) -{ - VirtIOSerialPort *port; - - QTAILQ_FOREACH(port, &vser->ports, next) { - if (port->ivq == vq || port->ovq == vq) - return port; - } - return NULL; -} - -static VirtIOSerialPort *find_port_by_name(char *name) -{ - VirtIOSerial *vser; - - QLIST_FOREACH(vser, &vserdevices.devices, next) { - VirtIOSerialPort *port; - - QTAILQ_FOREACH(port, &vser->ports, next) { - if (port->name && !strcmp(port->name, name)) { - return port; - } - } - } - return NULL; -} - -static bool use_multiport(VirtIOSerial *vser) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(vser); - return virtio_vdev_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT); -} - -static size_t write_to_port(VirtIOSerialPort *port, - const uint8_t *buf, size_t size) -{ - VirtQueueElement *elem; - VirtQueue *vq; - size_t offset; - - vq = port->ivq; - if (!virtio_queue_ready(vq)) { - return 0; - } - - offset = 0; - while (offset < size) { - size_t len; - - elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); - if (!elem) { - break; - } - - len = iov_from_buf(elem->in_sg, elem->in_num, 0, - buf + offset, size - offset); - offset += len; - - virtqueue_push(vq, elem, len); - g_free(elem); - } - - virtio_notify(VIRTIO_DEVICE(port->vser), vq); - return offset; -} - -static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev) -{ - VirtQueueElement *elem; - - if (!virtio_queue_ready(vq)) { - return; - } - for (;;) { - elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); - if (!elem) { - break; - } - virtqueue_push(vq, elem, 0); - g_free(elem); - } - virtio_notify(vdev, vq); -} - -static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, - VirtIODevice *vdev) -{ - VirtIOSerialPortClass *vsc; - - assert(port); - assert(virtio_queue_ready(vq)); - - vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); - - while (!port->throttled) { - unsigned int i; - - /* Pop an elem only if we haven't left off a previous one mid-way */ - if (!port->elem) { - port->elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); - if (!port->elem) { - break; - } - port->iov_idx = 0; - port->iov_offset = 0; - } - - for (i = port->iov_idx; i < port->elem->out_num; i++) { - size_t buf_size; - ssize_t ret; - - buf_size = port->elem->out_sg[i].iov_len - port->iov_offset; - ret = vsc->have_data(port, - port->elem->out_sg[i].iov_base - + port->iov_offset, - buf_size); - if (port->throttled) { - port->iov_idx = i; - if (ret > 0) { - port->iov_offset += ret; - } - break; - } - port->iov_offset = 0; - } - if (port->throttled) { - break; - } - virtqueue_push(vq, port->elem, 0); - g_free(port->elem); - port->elem = NULL; - } - virtio_notify(vdev, vq); -} - -static void flush_queued_data(VirtIOSerialPort *port) -{ - assert(port); - - if (!virtio_queue_ready(port->ovq)) { - return; - } - do_flush_queued_data(port, port->ovq, VIRTIO_DEVICE(port->vser)); -} - -static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len) -{ - VirtQueueElement *elem; - VirtQueue *vq; - - vq = vser->c_ivq; - if (!virtio_queue_ready(vq)) { - return 0; - } - - elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); - if (!elem) { - return 0; - } - - /* TODO: detect a buffer that's too short, set NEEDS_RESET */ - iov_from_buf(elem->in_sg, elem->in_num, 0, buf, len); - - virtqueue_push(vq, elem, len); - virtio_notify(VIRTIO_DEVICE(vser), vq); - g_free(elem); - - return len; -} - -static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id, - uint16_t event, uint16_t value) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(vser); - struct virtio_console_control cpkt; - - virtio_stl_p(vdev, &cpkt.id, port_id); - virtio_stw_p(vdev, &cpkt.event, event); - virtio_stw_p(vdev, &cpkt.value, value); - - trace_virtio_serial_send_control_event(port_id, event, value); - return send_control_msg(vser, &cpkt, sizeof(cpkt)); -} - -/* Functions for use inside qemu to open and read from/write to ports */ -int virtio_serial_open(VirtIOSerialPort *port) -{ - /* Don't allow opening an already-open port */ - if (port->host_connected) { - return 0; - } - /* Send port open notification to the guest */ - port->host_connected = true; - send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1); - - return 0; -} - -int virtio_serial_close(VirtIOSerialPort *port) -{ - port->host_connected = false; - /* - * If there's any data the guest sent which the app didn't - * consume, reset the throttling flag and discard the data. - */ - port->throttled = false; - discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser)); - - send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0); - - return 0; -} - -/* Individual ports/apps call this function to write to the guest. */ -ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf, - size_t size) -{ - if (!port || !port->host_connected || !port->guest_connected) { - return 0; - } - return write_to_port(port, buf, size); -} - -/* - * Readiness of the guest to accept data on a port. - * Returns max. data the guest can receive - */ -size_t virtio_serial_guest_ready(VirtIOSerialPort *port) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(port->vser); - VirtQueue *vq = port->ivq; - unsigned int bytes; - - if (!virtio_queue_ready(vq) || - !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) || - virtio_queue_empty(vq)) { - return 0; - } - if (use_multiport(port->vser) && !port->guest_connected) { - return 0; - } - virtqueue_get_avail_bytes(vq, &bytes, NULL, 4096, 0); - return bytes; -} - -static void flush_queued_data_bh(void *opaque) -{ - VirtIOSerialPort *port = opaque; - - flush_queued_data(port); -} - -void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle) -{ - if (!port) { - return; - } - - trace_virtio_serial_throttle_port(port->id, throttle); - port->throttled = throttle; - if (throttle) { - return; - } - qemu_bh_schedule(port->bh); -} - -/* Guest wants to notify us of some event */ -static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(vser); - struct VirtIOSerialPort *port; - VirtIOSerialPortClass *vsc; - struct virtio_console_control cpkt, *gcpkt; - uint8_t *buffer; - size_t buffer_len; - - gcpkt = buf; - - if (len < sizeof(cpkt)) { - /* The guest sent an invalid control packet */ - return; - } - - cpkt.event = virtio_lduw_p(vdev, &gcpkt->event); - cpkt.value = virtio_lduw_p(vdev, &gcpkt->value); - - trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value); - - if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) { - if (!cpkt.value) { - error_report("virtio-serial-bus: Guest failure in adding device %s", - vser->bus.qbus.name); - return; - } - /* - * The device is up, we can now tell the device about all the - * ports we have here. - */ - QTAILQ_FOREACH(port, &vser->ports, next) { - send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_ADD, 1); - } - return; - } - - port = find_port_by_id(vser, virtio_ldl_p(vdev, &gcpkt->id)); - if (!port) { - error_report("virtio-serial-bus: Unexpected port id %u for device %s", - virtio_ldl_p(vdev, &gcpkt->id), vser->bus.qbus.name); - return; - } - - trace_virtio_serial_handle_control_message_port(port->id); - - vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); - - switch(cpkt.event) { - case VIRTIO_CONSOLE_PORT_READY: - if (!cpkt.value) { - error_report("virtio-serial-bus: Guest failure in adding port %u for device %s", - port->id, vser->bus.qbus.name); - break; - } - /* - * Now that we know the guest asked for the port name, we're - * sure the guest has initialised whatever state is necessary - * for this port. Now's a good time to let the guest know if - * this port is a console port so that the guest can hook it - * up to hvc. - */ - if (vsc->is_console) { - send_control_event(vser, port->id, VIRTIO_CONSOLE_CONSOLE_PORT, 1); - } - - if (port->name) { - virtio_stl_p(vdev, &cpkt.id, port->id); - virtio_stw_p(vdev, &cpkt.event, VIRTIO_CONSOLE_PORT_NAME); - virtio_stw_p(vdev, &cpkt.value, 1); - - buffer_len = sizeof(cpkt) + strlen(port->name) + 1; - buffer = g_malloc(buffer_len); - - memcpy(buffer, &cpkt, sizeof(cpkt)); - memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name)); - buffer[buffer_len - 1] = 0; - - send_control_msg(vser, buffer, buffer_len); - g_free(buffer); - } - - if (port->host_connected) { - send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1); - } - - /* - * When the guest has asked us for this information it means - * the guest is all setup and has its virtqueues - * initialised. If some app is interested in knowing about - * this event, let it know. - */ - if (vsc->guest_ready) { - vsc->guest_ready(port); - } - break; - - case VIRTIO_CONSOLE_PORT_OPEN: - port->guest_connected = cpkt.value; - if (vsc->set_guest_connected) { - /* Send the guest opened notification if an app is interested */ - vsc->set_guest_connected(port, cpkt.value); - } - break; - } -} - -static void control_in(VirtIODevice *vdev, VirtQueue *vq) -{ -} - -static void control_out(VirtIODevice *vdev, VirtQueue *vq) -{ - VirtQueueElement *elem; - VirtIOSerial *vser; - uint8_t *buf; - size_t len; - - vser = VIRTIO_SERIAL(vdev); - - len = 0; - buf = NULL; - for (;;) { - size_t cur_len; - - elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); - if (!elem) { - break; - } - - cur_len = iov_size(elem->out_sg, elem->out_num); - /* - * Allocate a new buf only if we didn't have one previously or - * if the size of the buf differs - */ - if (cur_len > len) { - g_free(buf); - - buf = g_malloc(cur_len); - len = cur_len; - } - iov_to_buf(elem->out_sg, elem->out_num, 0, buf, cur_len); - - handle_control_message(vser, buf, cur_len); - virtqueue_push(vq, elem, 0); - g_free(elem); - } - g_free(buf); - virtio_notify(vdev, vq); -} - -/* Guest wrote something to some port. */ -static void handle_output(VirtIODevice *vdev, VirtQueue *vq) -{ - VirtIOSerial *vser; - VirtIOSerialPort *port; - - vser = VIRTIO_SERIAL(vdev); - port = find_port_by_vq(vser, vq); - - if (!port || !port->host_connected) { - discard_vq_data(vq, vdev); - return; - } - - if (!port->throttled) { - do_flush_queued_data(port, vq, vdev); - return; - } -} - -static void handle_input(VirtIODevice *vdev, VirtQueue *vq) -{ - /* - * Users of virtio-serial would like to know when guest becomes - * writable again -- i.e. if a vq had stuff queued up and the - * guest wasn't reading at all, the host would not be able to - * write to the vq anymore. Once the guest reads off something, - * we can start queueing things up again. However, this call is - * made for each buffer addition by the guest -- even though free - * buffers existed prior to the current buffer addition. This is - * done so as not to maintain previous state, which will need - * additional live-migration-related changes. - */ - VirtIOSerial *vser; - VirtIOSerialPort *port; - VirtIOSerialPortClass *vsc; - - vser = VIRTIO_SERIAL(vdev); - port = find_port_by_vq(vser, vq); - - if (!port) { - return; - } - vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); - - /* - * If guest_connected is false, this call is being made by the - * early-boot queueing up of descriptors, which is just noise for - * the host apps -- don't disturb them in that case. - */ - if (port->guest_connected && port->host_connected && vsc->guest_writable) { - vsc->guest_writable(port); - } -} - -static uint64_t get_features(VirtIODevice *vdev, uint64_t features, - Error **errp) -{ - VirtIOSerial *vser; - - vser = VIRTIO_SERIAL(vdev); - - if (vser->bus.max_nr_ports > 1) { - virtio_add_feature(&features, VIRTIO_CONSOLE_F_MULTIPORT); - } - return features; -} - -/* Guest requested config info */ -static void get_config(VirtIODevice *vdev, uint8_t *config_data) -{ - VirtIOSerial *vser = VIRTIO_SERIAL(vdev); - struct virtio_console_config *config = - (struct virtio_console_config *)config_data; - - config->cols = 0; - config->rows = 0; - config->max_nr_ports = virtio_tswap32(vdev, - vser->serial.max_virtserial_ports); -} - -static void guest_reset(VirtIOSerial *vser) -{ - VirtIOSerialPort *port; - VirtIOSerialPortClass *vsc; - - QTAILQ_FOREACH(port, &vser->ports, next) { - vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); - if (port->guest_connected) { - port->guest_connected = false; - if (vsc->set_guest_connected) { - vsc->set_guest_connected(port, false); - } - } - } -} - -static void set_status(VirtIODevice *vdev, uint8_t status) -{ - VirtIOSerial *vser; - VirtIOSerialPort *port; - - vser = VIRTIO_SERIAL(vdev); - port = find_port_by_id(vser, 0); - - if (port && !use_multiport(port->vser) - && (status & VIRTIO_CONFIG_S_DRIVER_OK)) { - /* - * Non-multiport guests won't be able to tell us guest - * open/close status. Such guests can only have a port at id - * 0, so set guest_connected for such ports as soon as guest - * is up. - */ - port->guest_connected = true; - } - if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { - guest_reset(vser); - } -} - -static void vser_reset(VirtIODevice *vdev) -{ - VirtIOSerial *vser; - - vser = VIRTIO_SERIAL(vdev); - guest_reset(vser); -} - -static void virtio_serial_save(QEMUFile *f, void *opaque) -{ - /* The virtio device */ - virtio_save(VIRTIO_DEVICE(opaque), f); -} - -static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) -{ - VirtIOSerial *s = VIRTIO_SERIAL(vdev); - VirtIOSerialPort *port; - uint32_t nr_active_ports; - unsigned int i, max_nr_ports; - struct virtio_console_config config; - - /* The config space (ignored on the far end in current versions) */ - get_config(vdev, (uint8_t *)&config); - qemu_put_be16s(f, &config.cols); - qemu_put_be16s(f, &config.rows); - qemu_put_be32s(f, &config.max_nr_ports); - - /* The ports map */ - max_nr_ports = s->serial.max_virtserial_ports; - for (i = 0; i < (max_nr_ports + 31) / 32; i++) { - qemu_put_be32s(f, &s->ports_map[i]); - } - - /* Ports */ - - nr_active_ports = 0; - QTAILQ_FOREACH(port, &s->ports, next) { - nr_active_ports++; - } - - qemu_put_be32s(f, &nr_active_ports); - - /* - * Items in struct VirtIOSerialPort. - */ - QTAILQ_FOREACH(port, &s->ports, next) { - uint32_t elem_popped; - - qemu_put_be32s(f, &port->id); - qemu_put_byte(f, port->guest_connected); - qemu_put_byte(f, port->host_connected); - - elem_popped = 0; - if (port->elem) { - elem_popped = 1; - } - qemu_put_be32s(f, &elem_popped); - if (elem_popped) { - qemu_put_be32s(f, &port->iov_idx); - qemu_put_be64s(f, &port->iov_offset); - qemu_put_virtqueue_element(f, port->elem); - } - } -} - -static void virtio_serial_post_load_timer_cb(void *opaque) -{ - uint32_t i; - VirtIOSerial *s = VIRTIO_SERIAL(opaque); - VirtIOSerialPort *port; - uint8_t host_connected; - VirtIOSerialPortClass *vsc; - - if (!s->post_load) { - return; - } - for (i = 0 ; i < s->post_load->nr_active_ports; ++i) { - port = s->post_load->connected[i].port; - host_connected = s->post_load->connected[i].host_connected; - if (host_connected != port->host_connected) { - /* - * We have to let the guest know of the host connection - * status change - */ - send_control_event(s, port->id, VIRTIO_CONSOLE_PORT_OPEN, - port->host_connected); - } - vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); - if (vsc->set_guest_connected) { - vsc->set_guest_connected(port, port->guest_connected); - } - } - g_free(s->post_load->connected); - timer_free(s->post_load->timer); - g_free(s->post_load); - s->post_load = NULL; -} - -static int fetch_active_ports_list(QEMUFile *f, int version_id, - VirtIOSerial *s, uint32_t nr_active_ports) -{ - uint32_t i; - - s->post_load = g_malloc0(sizeof(*s->post_load)); - s->post_load->nr_active_ports = nr_active_ports; - s->post_load->connected = - g_malloc0(sizeof(*s->post_load->connected) * nr_active_ports); - - s->post_load->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - virtio_serial_post_load_timer_cb, - s); - - /* Items in struct VirtIOSerialPort */ - for (i = 0; i < nr_active_ports; i++) { - VirtIOSerialPort *port; - uint32_t id; - - id = qemu_get_be32(f); - port = find_port_by_id(s, id); - if (!port) { - return -EINVAL; - } - - port->guest_connected = qemu_get_byte(f); - s->post_load->connected[i].port = port; - s->post_load->connected[i].host_connected = qemu_get_byte(f); - - if (version_id > 2) { - uint32_t elem_popped; - - qemu_get_be32s(f, &elem_popped); - if (elem_popped) { - qemu_get_be32s(f, &port->iov_idx); - qemu_get_be64s(f, &port->iov_offset); - - port->elem = - qemu_get_virtqueue_element(f, sizeof(VirtQueueElement)); - - /* - * Port was throttled on source machine. Let's - * unthrottle it here so data starts flowing again. - */ - virtio_serial_throttle_port(port, false); - } - } - } - timer_mod(s->post_load->timer, 1); - return 0; -} - -static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) -{ - if (version_id > 3) { - return -EINVAL; - } - - /* The virtio device */ - return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); -} - -static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, - int version_id) -{ - VirtIOSerial *s = VIRTIO_SERIAL(vdev); - uint32_t max_nr_ports, nr_active_ports, ports_map; - unsigned int i; - int ret; - uint32_t tmp; - - if (version_id < 2) { - return 0; - } - - /* Unused */ - qemu_get_be16s(f, (uint16_t *) &tmp); - qemu_get_be16s(f, (uint16_t *) &tmp); - qemu_get_be32s(f, &tmp); - - max_nr_ports = s->serial.max_virtserial_ports; - for (i = 0; i < (max_nr_ports + 31) / 32; i++) { - qemu_get_be32s(f, &ports_map); - - if (ports_map != s->ports_map[i]) { - /* - * Ports active on source and destination don't - * match. Fail migration. - */ - return -EINVAL; - } - } - - qemu_get_be32s(f, &nr_active_ports); - - if (nr_active_ports) { - ret = fetch_active_ports_list(f, version_id, s, nr_active_ports); - if (ret) { - return ret; - } - } - return 0; -} - -static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); - -static Property virtser_props[] = { - DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID), - DEFINE_PROP_STRING("name", VirtIOSerialPort, name), - DEFINE_PROP_END_OF_LIST() -}; - -#define TYPE_VIRTIO_SERIAL_BUS "virtio-serial-bus" -#define VIRTIO_SERIAL_BUS(obj) \ - OBJECT_CHECK(VirtIOSerialBus, (obj), TYPE_VIRTIO_SERIAL_BUS) - -static void virtser_bus_class_init(ObjectClass *klass, void *data) -{ - BusClass *k = BUS_CLASS(klass); - k->print_dev = virtser_bus_dev_print; -} - -static const TypeInfo virtser_bus_info = { - .name = TYPE_VIRTIO_SERIAL_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(VirtIOSerialBus), - .class_init = virtser_bus_class_init, -}; - -static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) -{ - VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(qdev); - - monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n", - indent, "", port->id, - port->guest_connected ? "on" : "off", - port->host_connected ? "on" : "off", - port->throttled ? "on" : "off"); -} - -/* This function is only used if a port id is not provided by the user */ -static uint32_t find_free_port_id(VirtIOSerial *vser) -{ - unsigned int i, max_nr_ports; - - max_nr_ports = vser->serial.max_virtserial_ports; - for (i = 0; i < (max_nr_ports + 31) / 32; i++) { - uint32_t map, zeroes; - - map = vser->ports_map[i]; - zeroes = ctz32(~map); - if (zeroes != 32) { - return zeroes + i * 32; - } - } - return VIRTIO_CONSOLE_BAD_ID; -} - -static void mark_port_added(VirtIOSerial *vser, uint32_t port_id) -{ - unsigned int i; - - i = port_id / 32; - vser->ports_map[i] |= 1U << (port_id % 32); -} - -static void add_port(VirtIOSerial *vser, uint32_t port_id) -{ - mark_port_added(vser, port_id); - send_control_event(vser, port_id, VIRTIO_CONSOLE_PORT_ADD, 1); -} - -static void remove_port(VirtIOSerial *vser, uint32_t port_id) -{ - VirtIOSerialPort *port; - - /* - * Don't mark port 0 removed -- we explicitly reserve it for - * backward compat with older guests, ensure a virtconsole device - * unplug retains the reservation. - */ - if (port_id) { - unsigned int i; - - i = port_id / 32; - vser->ports_map[i] &= ~(1U << (port_id % 32)); - } - - port = find_port_by_id(vser, port_id); - /* - * This function is only called from qdev's unplug callback; if we - * get a NULL port here, we're in trouble. - */ - assert(port); - - /* Flush out any unconsumed buffers first */ - discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser)); - - send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1); -} - -static void virtser_port_device_realize(DeviceState *dev, Error **errp) -{ - VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); - VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); - VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev)); - int max_nr_ports; - bool plugging_port0; - Error *err = NULL; - - port->vser = bus->vser; - port->bh = qemu_bh_new(flush_queued_data_bh, port); - - assert(vsc->have_data); - - /* - * Is the first console port we're seeing? If so, put it up at - * location 0. This is done for backward compatibility (old - * kernel, new qemu). - */ - plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0); - - if (find_port_by_id(port->vser, port->id)) { - error_setg(errp, "virtio-serial-bus: A port already exists at id %u", - port->id); - return; - } - - if (port->name != NULL && find_port_by_name(port->name)) { - error_setg(errp, "virtio-serial-bus: A port already exists by name %s", - port->name); - return; - } - - if (port->id == VIRTIO_CONSOLE_BAD_ID) { - if (plugging_port0) { - port->id = 0; - } else { - port->id = find_free_port_id(port->vser); - if (port->id == VIRTIO_CONSOLE_BAD_ID) { - error_setg(errp, "virtio-serial-bus: Maximum port limit for " - "this device reached"); - return; - } - } - } - - max_nr_ports = port->vser->serial.max_virtserial_ports; - if (port->id >= max_nr_ports) { - error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, " - "max. allowed: %u", max_nr_ports - 1); - return; - } - - vsc->realize(dev, &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - - port->elem = NULL; -} - -static void virtser_port_device_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); - - QTAILQ_INSERT_TAIL(&port->vser->ports, port, next); - port->ivq = port->vser->ivqs[port->id]; - port->ovq = port->vser->ovqs[port->id]; - - add_port(port->vser, port->id); - - /* Send an update to the guest about this new port added */ - virtio_notify_config(VIRTIO_DEVICE(hotplug_dev)); -} - -static void virtser_port_device_unrealize(DeviceState *dev, Error **errp) -{ - VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); - VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(dev); - VirtIOSerial *vser = port->vser; - - qemu_bh_delete(port->bh); - remove_port(port->vser, port->id); - - QTAILQ_REMOVE(&vser->ports, port, next); - - if (vsc->unrealize) { - vsc->unrealize(dev, errp); - } -} - -static void virtio_serial_device_realize(DeviceState *dev, Error **errp) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VirtIOSerial *vser = VIRTIO_SERIAL(dev); - uint32_t i, max_supported_ports; - - if (!vser->serial.max_virtserial_ports) { - error_setg(errp, "Maximum number of serial ports not specified"); - return; - } - - /* Each port takes 2 queues, and one pair is for the control queue */ - max_supported_ports = VIRTIO_QUEUE_MAX / 2 - 1; - - if (vser->serial.max_virtserial_ports > max_supported_ports) { - error_setg(errp, "maximum ports supported: %u", max_supported_ports); - return; - } - - /* We don't support emergency write, skip it for now. */ - /* TODO: cleaner fix, depending on host features. */ - virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE, - offsetof(struct virtio_console_config, emerg_wr)); - - /* Spawn a new virtio-serial bus on which the ports will ride as devices */ - qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS, - dev, vdev->bus_name); - qbus_set_hotplug_handler(BUS(&vser->bus), DEVICE(vser), errp); - vser->bus.vser = vser; - QTAILQ_INIT(&vser->ports); - - vser->bus.max_nr_ports = vser->serial.max_virtserial_ports; - vser->ivqs = g_malloc(vser->serial.max_virtserial_ports - * sizeof(VirtQueue *)); - vser->ovqs = g_malloc(vser->serial.max_virtserial_ports - * sizeof(VirtQueue *)); - - /* Add a queue for host to guest transfers for port 0 (backward compat) */ - vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input); - /* Add a queue for guest to host transfers for port 0 (backward compat) */ - vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output); - - /* TODO: host to guest notifications can get dropped - * if the queue fills up. Implement queueing in host, - * this might also make it possible to reduce the control - * queue size: as guest preposts buffers there, - * this will save 4Kbyte of guest memory per entry. */ - - /* control queue: host to guest */ - vser->c_ivq = virtio_add_queue(vdev, 32, control_in); - /* control queue: guest to host */ - vser->c_ovq = virtio_add_queue(vdev, 32, control_out); - - for (i = 1; i < vser->bus.max_nr_ports; i++) { - /* Add a per-port queue for host to guest transfers */ - vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input); - /* Add a per-per queue for guest to host transfers */ - vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output); - } - - vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32) - * sizeof(vser->ports_map[0])); - /* - * Reserve location 0 for a console port for backward compat - * (old kernel, new qemu) - */ - mark_port_added(vser, 0); - - vser->post_load = NULL; - - /* - * Register for the savevm section with the virtio-console name - * to preserve backward compat - */ - register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save, - virtio_serial_load, vser); - - QLIST_INSERT_HEAD(&vserdevices.devices, vser, next); -} - -static void virtio_serial_port_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *k = DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_INPUT, k->categories); - k->bus_type = TYPE_VIRTIO_SERIAL_BUS; - k->realize = virtser_port_device_realize; - k->unrealize = virtser_port_device_unrealize; - k->props = virtser_props; -} - -static const TypeInfo virtio_serial_port_type_info = { - .name = TYPE_VIRTIO_SERIAL_PORT, - .parent = TYPE_DEVICE, - .instance_size = sizeof(VirtIOSerialPort), - .abstract = true, - .class_size = sizeof(VirtIOSerialPortClass), - .class_init = virtio_serial_port_class_init, -}; - -static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - VirtIOSerial *vser = VIRTIO_SERIAL(dev); - - QLIST_REMOVE(vser, next); - - unregister_savevm(dev, "virtio-console", vser); - - g_free(vser->ivqs); - g_free(vser->ovqs); - g_free(vser->ports_map); - if (vser->post_load) { - g_free(vser->post_load->connected); - timer_del(vser->post_load->timer); - timer_free(vser->post_load->timer); - g_free(vser->post_load); - } - virtio_cleanup(vdev); -} - -static Property virtio_serial_properties[] = { - DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports, - 31), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_serial_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - - QLIST_INIT(&vserdevices.devices); - - dc->props = virtio_serial_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - vdc->realize = virtio_serial_device_realize; - vdc->unrealize = virtio_serial_device_unrealize; - vdc->get_features = get_features; - vdc->get_config = get_config; - vdc->set_status = set_status; - vdc->reset = vser_reset; - vdc->save = virtio_serial_save_device; - vdc->load = virtio_serial_load_device; - hc->plug = virtser_port_device_plug; - hc->unplug = qdev_simple_device_unplug_cb; -} - -static const TypeInfo virtio_device_info = { - .name = TYPE_VIRTIO_SERIAL, - .parent = TYPE_VIRTIO_DEVICE, - .instance_size = sizeof(VirtIOSerial), - .class_init = virtio_serial_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { } - } -}; - -static void virtio_serial_register_types(void) -{ - type_register_static(&virtser_bus_info); - type_register_static(&virtio_serial_port_type_info); - type_register_static(&virtio_device_info); -} - -type_init(virtio_serial_register_types) diff --git a/qemu/hw/char/xen_console.c b/qemu/hw/char/xen_console.c deleted file mode 100644 index cbf1dccbb..000000000 --- a/qemu/hw/char/xen_console.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) International Business Machines Corp., 2005 - * Author(s): Anthony Liguori - * - * Copyright (C) Red Hat 2007 - * - * Xen Console - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - */ - -#include "qemu/osdep.h" -#include -#include -#include - -#include "hw/hw.h" -#include "sysemu/char.h" -#include "hw/xen/xen_backend.h" - -#include - -struct buffer { - uint8_t *data; - size_t consumed; - size_t size; - size_t capacity; - size_t max_capacity; -}; - -struct XenConsole { - struct XenDevice xendev; /* must be first */ - struct buffer buffer; - char console[XEN_BUFSIZE]; - int ring_ref; - void *sring; - CharDriverState *chr; - int backlog; -}; - -static void buffer_append(struct XenConsole *con) -{ - struct buffer *buffer = &con->buffer; - XENCONS_RING_IDX cons, prod, size; - struct xencons_interface *intf = con->sring; - - cons = intf->out_cons; - prod = intf->out_prod; - xen_mb(); - - size = prod - cons; - if ((size == 0) || (size > sizeof(intf->out))) - return; - - if ((buffer->capacity - buffer->size) < size) { - buffer->capacity += (size + 1024); - buffer->data = g_realloc(buffer->data, buffer->capacity); - } - - while (cons != prod) - buffer->data[buffer->size++] = intf->out[ - MASK_XENCONS_IDX(cons++, intf->out)]; - - xen_mb(); - intf->out_cons = cons; - xen_be_send_notify(&con->xendev); - - if (buffer->max_capacity && - buffer->size > buffer->max_capacity) { - /* Discard the middle of the data. */ - - size_t over = buffer->size - buffer->max_capacity; - uint8_t *maxpos = buffer->data + buffer->max_capacity; - - memmove(maxpos - over, maxpos, over); - buffer->data = g_realloc(buffer->data, buffer->max_capacity); - buffer->size = buffer->capacity = buffer->max_capacity; - - if (buffer->consumed > buffer->max_capacity - over) - buffer->consumed = buffer->max_capacity - over; - } -} - -static void buffer_advance(struct buffer *buffer, size_t len) -{ - buffer->consumed += len; - if (buffer->consumed == buffer->size) { - buffer->consumed = 0; - buffer->size = 0; - } -} - -static int ring_free_bytes(struct XenConsole *con) -{ - struct xencons_interface *intf = con->sring; - XENCONS_RING_IDX cons, prod, space; - - cons = intf->in_cons; - prod = intf->in_prod; - xen_mb(); - - space = prod - cons; - if (space > sizeof(intf->in)) - return 0; /* ring is screwed: ignore it */ - - return (sizeof(intf->in) - space); -} - -static int xencons_can_receive(void *opaque) -{ - struct XenConsole *con = opaque; - return ring_free_bytes(con); -} - -static void xencons_receive(void *opaque, const uint8_t *buf, int len) -{ - struct XenConsole *con = opaque; - struct xencons_interface *intf = con->sring; - XENCONS_RING_IDX prod; - int i, max; - - max = ring_free_bytes(con); - /* The can_receive() func limits this, but check again anyway */ - if (max < len) - len = max; - - prod = intf->in_prod; - for (i = 0; i < len; i++) { - intf->in[MASK_XENCONS_IDX(prod++, intf->in)] = - buf[i]; - } - xen_wmb(); - intf->in_prod = prod; - xen_be_send_notify(&con->xendev); -} - -static void xencons_send(struct XenConsole *con) -{ - ssize_t len, size; - - size = con->buffer.size - con->buffer.consumed; - if (con->chr) - len = qemu_chr_fe_write(con->chr, con->buffer.data + con->buffer.consumed, - size); - else - len = size; - if (len < 1) { - if (!con->backlog) { - con->backlog = 1; - xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n"); - } - } else { - buffer_advance(&con->buffer, len); - if (con->backlog && len == size) { - con->backlog = 0; - xen_be_printf(&con->xendev, 1, "backlog is gone\n"); - } - } -} - -/* -------------------------------------------------------------------- */ - -static int con_init(struct XenDevice *xendev) -{ - struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); - char *type, *dom, label[32]; - int ret = 0; - const char *output; - - /* setup */ - dom = xs_get_domain_path(xenstore, con->xendev.dom); - if (!xendev->dev) { - snprintf(con->console, sizeof(con->console), "%s/console", dom); - } else { - snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev); - } - free(dom); - - type = xenstore_read_str(con->console, "type"); - if (!type || strcmp(type, "ioemu") != 0) { - xen_be_printf(xendev, 1, "not for me (type=%s)\n", type); - ret = -1; - goto out; - } - - output = xenstore_read_str(con->console, "output"); - - /* no Xen override, use qemu output device */ - if (output == NULL) { - con->chr = serial_hds[con->xendev.dev]; - } else { - snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); - con->chr = qemu_chr_new(label, output, NULL); - } - - xenstore_store_pv_console_info(con->xendev.dev, con->chr); - -out: - g_free(type); - return ret; -} - -static int con_initialise(struct XenDevice *xendev) -{ - struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); - int limit; - - if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1) - return -1; - if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1) - return -1; - if (xenstore_read_int(con->console, "limit", &limit) == 0) - con->buffer.max_capacity = limit; - - if (!xendev->dev) { - xen_pfn_t mfn = con->ring_ref; - con->sring = xenforeignmemory_map(xen_fmem, con->xendev.dom, - PROT_READ|PROT_WRITE, - 1, &mfn, NULL); - } else { - con->sring = xengnttab_map_grant_ref(xendev->gnttabdev, con->xendev.dom, - con->ring_ref, - PROT_READ|PROT_WRITE); - } - if (!con->sring) - return -1; - - xen_be_bind_evtchn(&con->xendev); - if (con->chr) { - if (qemu_chr_fe_claim(con->chr) == 0) { - qemu_chr_add_handlers(con->chr, xencons_can_receive, - xencons_receive, NULL, con); - } else { - xen_be_printf(xendev, 0, - "xen_console_init error chardev %s already used\n", - con->chr->label); - con->chr = NULL; - } - } - - xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n", - con->ring_ref, - con->xendev.remote_port, - con->xendev.local_port, - con->buffer.max_capacity); - return 0; -} - -static void con_disconnect(struct XenDevice *xendev) -{ - struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); - - if (con->chr) { - qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL); - qemu_chr_fe_release(con->chr); - } - xen_be_unbind_evtchn(&con->xendev); - - if (con->sring) { - if (!xendev->dev) { - xenforeignmemory_unmap(xen_fmem, con->sring, 1); - } else { - xengnttab_unmap(xendev->gnttabdev, con->sring, 1); - } - con->sring = NULL; - } -} - -static void con_event(struct XenDevice *xendev) -{ - struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); - - buffer_append(con); - if (con->buffer.size - con->buffer.consumed) - xencons_send(con); -} - -/* -------------------------------------------------------------------- */ - -struct XenDevOps xen_console_ops = { - .size = sizeof(struct XenConsole), - .flags = DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV, - .init = con_init, - .initialise = con_initialise, - .event = con_event, - .disconnect = con_disconnect, -}; diff --git a/qemu/hw/char/xilinx_uartlite.c b/qemu/hw/char/xilinx_uartlite.c deleted file mode 100644 index 911af4a0d..000000000 --- a/qemu/hw/char/xilinx_uartlite.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * QEMU model of Xilinx uartlite. - * - * Copyright (c) 2009 Edgar E. Iglesias. - * - * 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. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "sysemu/char.h" - -#define DUART(x) - -#define R_RX 0 -#define R_TX 1 -#define R_STATUS 2 -#define R_CTRL 3 -#define R_MAX 4 - -#define STATUS_RXVALID 0x01 -#define STATUS_RXFULL 0x02 -#define STATUS_TXEMPTY 0x04 -#define STATUS_TXFULL 0x08 -#define STATUS_IE 0x10 -#define STATUS_OVERRUN 0x20 -#define STATUS_FRAME 0x40 -#define STATUS_PARITY 0x80 - -#define CONTROL_RST_TX 0x01 -#define CONTROL_RST_RX 0x02 -#define CONTROL_IE 0x10 - -#define TYPE_XILINX_UARTLITE "xlnx.xps-uartlite" -#define XILINX_UARTLITE(obj) \ - OBJECT_CHECK(XilinxUARTLite, (obj), TYPE_XILINX_UARTLITE) - -typedef struct XilinxUARTLite { - SysBusDevice parent_obj; - - MemoryRegion mmio; - CharDriverState *chr; - qemu_irq irq; - - uint8_t rx_fifo[8]; - unsigned int rx_fifo_pos; - unsigned int rx_fifo_len; - - uint32_t regs[R_MAX]; -} XilinxUARTLite; - -static void uart_update_irq(XilinxUARTLite *s) -{ - unsigned int irq; - - if (s->rx_fifo_len) - s->regs[R_STATUS] |= STATUS_IE; - - irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE); - qemu_set_irq(s->irq, irq); -} - -static void uart_update_status(XilinxUARTLite *s) -{ - uint32_t r; - - r = s->regs[R_STATUS]; - r &= ~7; - r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */ - r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1; - r |= (!!s->rx_fifo_len); - s->regs[R_STATUS] = r; -} - -static void xilinx_uartlite_reset(DeviceState *dev) -{ - uart_update_status(XILINX_UARTLITE(dev)); -} - -static uint64_t -uart_read(void *opaque, hwaddr addr, unsigned int size) -{ - XilinxUARTLite *s = opaque; - uint32_t r = 0; - addr >>= 2; - switch (addr) - { - case R_RX: - r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7]; - if (s->rx_fifo_len) - s->rx_fifo_len--; - uart_update_status(s); - uart_update_irq(s); - qemu_chr_accept_input(s->chr); - break; - - default: - if (addr < ARRAY_SIZE(s->regs)) - r = s->regs[addr]; - DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r)); - break; - } - return r; -} - -static void -uart_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - XilinxUARTLite *s = opaque; - uint32_t value = val64; - unsigned char ch = value; - - addr >>= 2; - switch (addr) - { - case R_STATUS: - hw_error("write to UART STATUS?\n"); - break; - - case R_CTRL: - if (value & CONTROL_RST_RX) { - s->rx_fifo_pos = 0; - s->rx_fifo_len = 0; - } - s->regs[addr] = value; - break; - - case R_TX: - if (s->chr) - qemu_chr_fe_write(s->chr, &ch, 1); - - s->regs[addr] = value; - - /* hax. */ - s->regs[R_STATUS] |= STATUS_IE; - break; - - default: - DUART(printf("%s addr=%x v=%x\n", __func__, addr, value)); - if (addr < ARRAY_SIZE(s->regs)) - s->regs[addr] = value; - break; - } - uart_update_status(s); - uart_update_irq(s); -} - -static const MemoryRegionOps uart_ops = { - .read = uart_read, - .write = uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4 - } -}; - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - XilinxUARTLite *s = opaque; - - /* Got a byte. */ - if (s->rx_fifo_len >= 8) { - printf("WARNING: UART dropped char.\n"); - return; - } - s->rx_fifo[s->rx_fifo_pos] = *buf; - s->rx_fifo_pos++; - s->rx_fifo_pos &= 0x7; - s->rx_fifo_len++; - - uart_update_status(s); - uart_update_irq(s); -} - -static int uart_can_rx(void *opaque) -{ - XilinxUARTLite *s = opaque; - - return s->rx_fifo_len < sizeof(s->rx_fifo); -} - -static void uart_event(void *opaque, int event) -{ - -} - -static void xilinx_uartlite_realize(DeviceState *dev, Error **errp) -{ - XilinxUARTLite *s = XILINX_UARTLITE(dev); - - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - if (s->chr) - qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); -} - -static void xilinx_uartlite_init(Object *obj) -{ - XilinxUARTLite *s = XILINX_UARTLITE(obj); - - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); - - memory_region_init_io(&s->mmio, obj, &uart_ops, s, - "xlnx.xps-uartlite", R_MAX * 4); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); -} - -static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = xilinx_uartlite_reset; - dc->realize = xilinx_uartlite_realize; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo xilinx_uartlite_info = { - .name = TYPE_XILINX_UARTLITE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(XilinxUARTLite), - .instance_init = xilinx_uartlite_init, - .class_init = xilinx_uartlite_class_init, -}; - -static void xilinx_uart_register_types(void) -{ - type_register_static(&xilinx_uartlite_info); -} - -type_init(xilinx_uart_register_types) -- cgit 1.2.3-korg