aboutsummaryrefslogtreecommitdiff
path: root/hw/char
diff options
context:
space:
mode:
Diffstat (limited to 'hw/char')
-rw-r--r--hw/char/Kconfig18
-rw-r--r--hw/char/avr_usart.c9
-rw-r--r--hw/char/bcm2835_aux.c15
-rw-r--r--hw/char/cadence_uart.c5
-rw-r--r--hw/char/cmsdk-apb-uart.c7
-rw-r--r--hw/char/debugcon.c5
-rw-r--r--hw/char/digic-uart.c7
-rw-r--r--hw/char/diva-gsp.c295
-rw-r--r--hw/char/escc.c95
-rw-r--r--hw/char/etraxfs_ser.c267
-rw-r--r--hw/char/exynos4210_uart.c7
-rw-r--r--hw/char/goldfish_tty.c21
-rw-r--r--hw/char/grlib_apbuart.c7
-rw-r--r--hw/char/ibex_uart.c7
-rw-r--r--hw/char/imx_serial.c80
-rw-r--r--hw/char/ipoctal232.c9
-rw-r--r--hw/char/mcf_uart.c23
-rw-r--r--hw/char/mchp_pfsoc_mmuart.c4
-rw-r--r--hw/char/meson.build7
-rw-r--r--hw/char/nrf51_uart.c7
-rw-r--r--hw/char/omap_uart.c117
-rw-r--r--hw/char/parallel-isa.c2
-rw-r--r--hw/char/parallel.c11
-rw-r--r--hw/char/pl011.c250
-rw-r--r--hw/char/renesas_sci.c7
-rw-r--r--hw/char/riscv_htif.c47
-rw-r--r--hw/char/sclpconsole-lm.c9
-rw-r--r--hw/char/sclpconsole.c7
-rw-r--r--hw/char/serial-isa.c10
-rw-r--r--hw/char/serial-mm.c156
-rw-r--r--hw/char/serial-pci-multi.c30
-rw-r--r--hw/char/serial-pci.c15
-rw-r--r--hw/char/serial.c142
-rw-r--r--hw/char/sh_serial.c61
-rw-r--r--hw/char/shakti_uart.c7
-rw-r--r--hw/char/sifive_uart.c137
-rw-r--r--hw/char/spapr_vty.c5
-rw-r--r--hw/char/stm32f2xx_usart.c56
-rw-r--r--hw/char/stm32l4x5_usart.c28
-rw-r--r--hw/char/terminal3270.c5
-rw-r--r--hw/char/trace-events24
-rw-r--r--hw/char/virtio-console.c7
-rw-r--r--hw/char/virtio-serial-bus.c17
-rw-r--r--hw/char/xen_console.c63
-rw-r--r--hw/char/xilinx_uartlite.c41
45 files changed, 1175 insertions, 974 deletions
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 4fd74ea..9d517f3 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -11,6 +11,12 @@ config PARALLEL
config PL011
bool
+ # The PL011 has both a Rust and a C implementation
+ select PL011_C if !HAVE_RUST
+ select X_PL011_RUST if HAVE_RUST
+
+config PL011_C
+ bool
config SERIAL
bool
@@ -21,6 +27,10 @@ config SERIAL_ISA
depends on ISA_BUS
select SERIAL
+config SERIAL_MM
+ bool
+ select SERIAL
+
config SERIAL_PCI
bool
default y if PCI_DEVICES
@@ -62,6 +72,9 @@ config RENESAS_SCI
config AVR_USART
bool
+config DIVA_GSP
+ bool
+
config MCHP_PFSOC_MMUART
bool
select SERIAL
@@ -74,3 +87,8 @@ config GOLDFISH_TTY
config SHAKTI_UART
bool
+
+config IP_OCTAL_232
+ bool
+ default y
+ depends on IPACK
diff --git a/hw/char/avr_usart.c b/hw/char/avr_usart.c
index 5bcf9db..fae1521 100644
--- a/hw/char/avr_usart.c
+++ b/hw/char/avr_usart.c
@@ -86,7 +86,7 @@ static void update_char_mask(AVRUsartState *usart)
usart->char_mask = 0b11111111;
break;
default:
- assert(0);
+ g_assert_not_reached();
}
}
@@ -259,9 +259,8 @@ static const MemoryRegionOps avr_usart_ops = {
.impl = {.min_access_size = 1, .max_access_size = 1}
};
-static Property avr_usart_properties[] = {
+static const Property avr_usart_properties[] = {
DEFINE_PROP_CHR("chardev", AVRUsartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void avr_usart_pr(void *opaque, int irq, int level)
@@ -296,11 +295,11 @@ static void avr_usart_realize(DeviceState *dev, Error **errp)
avr_usart_reset(dev);
}
-static void avr_usart_class_init(ObjectClass *klass, void *data)
+static void avr_usart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = avr_usart_reset;
+ device_class_set_legacy_reset(dc, avr_usart_reset);
device_class_set_props(dc, avr_usart_properties);
dc->realize = avr_usart_realize;
}
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index 83990e2..2b397f2 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -98,7 +98,7 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
* 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) {
+ if ((s->iir & RX_INT) && s->read_count != 0) {
res |= 0x4;
} else {
res |= 0x2;
@@ -138,7 +138,7 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
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);
+ assert(s->read_count <= BCM2835_AUX_RX_FIFO_LEN);
res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */
}
return res;
@@ -221,7 +221,7 @@ static int bcm2835_aux_can_receive(void *opaque)
{
BCM2835AuxState *s = opaque;
- return s->read_count < BCM2835_AUX_RX_FIFO_LEN;
+ return BCM2835_AUX_RX_FIFO_LEN - s->read_count;
}
static void bcm2835_aux_put_fifo(void *opaque, uint8_t value)
@@ -243,7 +243,9 @@ static void bcm2835_aux_put_fifo(void *opaque, uint8_t value)
static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size)
{
- bcm2835_aux_put_fifo(opaque, *buf);
+ for (int i = 0; i < size; i++) {
+ bcm2835_aux_put_fifo(opaque, buf[i]);
+ }
}
static const MemoryRegionOps bcm2835_aux_ops = {
@@ -290,12 +292,11 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
bcm2835_aux_receive, NULL, NULL, s, NULL, true);
}
-static Property bcm2835_aux_props[] = {
+static const 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)
+static void bcm2835_aux_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index 77d9a2a..0dfa356 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -617,12 +617,11 @@ static const VMStateDescription vmstate_cadence_uart = {
},
};
-static Property cadence_uart_properties[] = {
+static const Property cadence_uart_properties[] = {
DEFINE_PROP_CHR("chardev", CadenceUARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cadence_uart_class_init(ObjectClass *klass, void *data)
+static void cadence_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/char/cmsdk-apb-uart.c b/hw/char/cmsdk-apb-uart.c
index d07cca1..32090f3 100644
--- a/hw/char/cmsdk-apb-uart.c
+++ b/hw/char/cmsdk-apb-uart.c
@@ -377,19 +377,18 @@ static const VMStateDescription cmsdk_apb_uart_vmstate = {
}
};
-static Property cmsdk_apb_uart_properties[] = {
+static const Property cmsdk_apb_uart_properties[] = {
DEFINE_PROP_CHR("chardev", CMSDKAPBUART, chr),
DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBUART, pclk_frq, 0),
- DEFINE_PROP_END_OF_LIST(),
};
-static void cmsdk_apb_uart_class_init(ObjectClass *klass, void *data)
+static void cmsdk_apb_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cmsdk_apb_uart_realize;
dc->vmsd = &cmsdk_apb_uart_vmstate;
- dc->reset = cmsdk_apb_uart_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_uart_reset);
device_class_set_props(dc, cmsdk_apb_uart_properties);
}
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index fdb04fe..bf44aaf 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -114,14 +114,13 @@ static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
isa->iobase, &s->io);
}
-static Property debugcon_isa_properties[] = {
+static const 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)
+static void debugcon_isa_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index ef2d762..0f6af51 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -172,17 +172,16 @@ static const VMStateDescription vmstate_digic_uart = {
}
};
-static Property digic_uart_properties[] = {
+static const Property digic_uart_properties[] = {
DEFINE_PROP_CHR("chardev", DigicUartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void digic_uart_class_init(ObjectClass *klass, void *data)
+static void digic_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = digic_uart_realize;
- dc->reset = digic_uart_reset;
+ device_class_set_legacy_reset(dc, digic_uart_reset);
dc->vmsd = &vmstate_digic_uart;
device_class_set_props(dc, digic_uart_properties);
}
diff --git a/hw/char/diva-gsp.c b/hw/char/diva-gsp.c
new file mode 100644
index 0000000..e1f0713
--- /dev/null
+++ b/hw/char/diva-gsp.c
@@ -0,0 +1,295 @@
+/*
+ * HP Diva GSP controller
+ *
+ * The Diva PCI boards are Remote Management cards for PA-RISC machines.
+ * They come with built-in 16550A multi UARTs for serial consoles
+ * and a mailbox-like memory area for hardware auto-reboot functionality.
+ * GSP stands for "Guardian Service Processor". Later products were marketed
+ * "Management Processor" (MP).
+ *
+ * Diva cards are multifunctional cards. The first part, the aux port,
+ * is on physical machines not useable but we still try to mimic it here.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2025 Helge Deller <deller@gmx.de>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "hw/char/serial.h"
+#include "hw/irq.h"
+#include "hw/pci/pci_device.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "migration/vmstate.h"
+
+#define PCI_DEVICE_ID_HP_DIVA 0x1048
+/* various DIVA GSP cards: */
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A
+#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B
+#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1
+#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223
+#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226
+#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227
+#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282
+#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290
+#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301
+#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a
+
+
+#define PCI_SERIAL_MAX_PORTS 4
+
+typedef struct PCIDivaSerialState {
+ PCIDevice dev;
+ MemoryRegion membar; /* for serial ports */
+ MemoryRegion mailboxbar; /* for hardware mailbox */
+ uint32_t subvendor;
+ 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;
+ bool disable;
+} PCIDivaSerialState;
+
+static void diva_pci_exit(PCIDevice *dev)
+{
+ PCIDivaSerialState *pci = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ SerialState *s;
+ int i;
+
+ for (i = 0; i < pci->ports; i++) {
+ s = pci->state + i;
+ qdev_unrealize(DEVICE(s));
+ memory_region_del_subregion(&pci->membar, &s->io);
+ g_free(pci->name[i]);
+ }
+ qemu_free_irqs(pci->irqs, pci->ports);
+}
+
+static void multi_serial_irq_mux(void *opaque, int n, int level)
+{
+ PCIDivaSerialState *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);
+}
+
+struct diva_info {
+ unsigned int nports:4; /* number of serial ports */
+ unsigned int omask:12; /* offset mask: BIT(1) -> offset 8 */
+};
+
+static struct diva_info diva_get_diva_info(PCIDeviceClass *pc)
+{
+ switch (pc->subsystem_id) {
+ case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
+ case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
+ return (struct diva_info) { .nports = 1,
+ .omask = BIT(0) };
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
+ return (struct diva_info) { .nports = 2,
+ .omask = BIT(0) | BIT(1) };
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
+ case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
+ case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
+ return (struct diva_info) { .nports = 3,
+ .omask = BIT(0) | BIT(1) | BIT(2) };
+ case PCI_DEVICE_ID_HP_DIVA_EVEREST: /* e.g. in rp3410 */
+ return (struct diva_info) { .nports = 3,
+ .omask = BIT(0) | BIT(2) | BIT(7) };
+ case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+ return (struct diva_info) { .nports = 4,
+ .omask = BIT(0) | BIT(1) | BIT(2) | BIT(7) };
+ }
+ g_assert_not_reached();
+}
+
+
+static void diva_pci_realize(PCIDevice *dev, Error **errp)
+{
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ PCIDivaSerialState *pci = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ SerialState *s;
+ struct diva_info di = diva_get_diva_info(pc);
+ size_t i, offset = 0;
+ size_t portmask = di.omask;
+
+ pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */
+ pci->dev.config[PCI_INTERRUPT_PIN] = 1;
+ memory_region_init(&pci->membar, OBJECT(pci), "serial_ports", 4096);
+ pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->membar);
+ pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, di.nports);
+
+ for (i = 0; i < di.nports; i++) {
+ s = pci->state + i;
+ if (!qdev_realize(DEVICE(s), NULL, errp)) {
+ diva_pci_exit(dev);
+ return;
+ }
+ s->irq = pci->irqs[i];
+ pci->name[i] = g_strdup_printf("uart #%zu", i + 1);
+ memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
+ pci->name[i], 8);
+
+ /* calculate offset of given port based on bitmask */
+ while ((portmask & BIT(0)) == 0) {
+ offset += 8;
+ portmask >>= 1;
+ }
+ memory_region_add_subregion(&pci->membar, offset, &s->io);
+ offset += 8;
+ portmask >>= 1;
+ pci->ports++;
+ }
+
+ /* mailbox bar */
+ memory_region_init(&pci->mailboxbar, OBJECT(pci), "mailbox", 128 * KiB);
+ pci_register_bar(&pci->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &pci->mailboxbar);
+}
+
+static const VMStateDescription vmstate_pci_diva = {
+ .name = "pci-diva-serial",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, PCIDivaSerialState),
+ VMSTATE_STRUCT_ARRAY(state, PCIDivaSerialState, PCI_SERIAL_MAX_PORTS,
+ 0, vmstate_serial, SerialState),
+ VMSTATE_UINT32_ARRAY(level, PCIDivaSerialState, PCI_SERIAL_MAX_PORTS),
+ VMSTATE_BOOL(disable, PCIDivaSerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const Property diva_serial_properties[] = {
+ DEFINE_PROP_BOOL("disable", PCIDivaSerialState, disable, false),
+ DEFINE_PROP_CHR("chardev1", PCIDivaSerialState, state[0].chr),
+ DEFINE_PROP_CHR("chardev2", PCIDivaSerialState, state[1].chr),
+ DEFINE_PROP_CHR("chardev3", PCIDivaSerialState, state[2].chr),
+ DEFINE_PROP_CHR("chardev4", PCIDivaSerialState, state[3].chr),
+ DEFINE_PROP_UINT32("subvendor", PCIDivaSerialState, subvendor,
+ PCI_DEVICE_ID_HP_DIVA_TOSCA1),
+};
+
+static void diva_serial_class_initfn(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+ pc->realize = diva_pci_realize;
+ pc->exit = diva_pci_exit;
+ pc->vendor_id = PCI_VENDOR_ID_HP;
+ pc->device_id = PCI_DEVICE_ID_HP_DIVA;
+ pc->subsystem_vendor_id = PCI_VENDOR_ID_HP;
+ pc->subsystem_id = PCI_DEVICE_ID_HP_DIVA_TOSCA1;
+ pc->revision = 3;
+ pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
+ dc->vmsd = &vmstate_pci_diva;
+ device_class_set_props(dc, diva_serial_properties);
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static void diva_serial_init(Object *o)
+{
+ PCIDevice *dev = PCI_DEVICE(o);
+ PCIDivaSerialState *pms = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ struct diva_info di = diva_get_diva_info(PCI_DEVICE_GET_CLASS(dev));
+ size_t i;
+
+ for (i = 0; i < di.nports; i++) {
+ object_initialize_child(o, "serial[*]", &pms->state[i], TYPE_SERIAL);
+ }
+}
+
+
+/* Diva-aux is the driver for portion 0 of the multifunction PCI device */
+
+struct DivaAuxState {
+ PCIDevice dev;
+ MemoryRegion mem;
+ qemu_irq irq;
+};
+
+#define TYPE_DIVA_AUX "diva-aux"
+OBJECT_DECLARE_SIMPLE_TYPE(DivaAuxState, DIVA_AUX)
+
+static void diva_aux_realize(PCIDevice *dev, Error **errp)
+{
+ DivaAuxState *pci = DO_UPCAST(DivaAuxState, dev, dev);
+
+ pci->dev.config[PCI_CLASS_PROG] = 0x02;
+ pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+ pci->irq = pci_allocate_irq(&pci->dev);
+
+ memory_region_init(&pci->mem, OBJECT(pci), "mem", 16);
+ pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->mem);
+}
+
+static void diva_aux_exit(PCIDevice *dev)
+{
+ DivaAuxState *pci = DO_UPCAST(DivaAuxState, dev, dev);
+ qemu_free_irq(pci->irq);
+}
+
+static void diva_aux_class_initfn(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+ pc->realize = diva_aux_realize;
+ pc->exit = diva_aux_exit;
+ pc->vendor_id = PCI_VENDOR_ID_HP;
+ pc->device_id = PCI_DEVICE_ID_HP_DIVA_AUX;
+ pc->subsystem_vendor_id = PCI_VENDOR_ID_HP;
+ pc->subsystem_id = 0x1291;
+ pc->revision = 1;
+ pc->class_id = PCI_CLASS_COMMUNICATION_MULTISERIAL;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->user_creatable = false;
+}
+
+static void diva_aux_init(Object *o)
+{
+}
+
+static const TypeInfo diva_aux_info = {
+ .name = TYPE_DIVA_AUX,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(DivaAuxState),
+ .instance_init = diva_aux_init,
+ .class_init = diva_aux_class_initfn,
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+
+
+static const TypeInfo diva_serial_pci_info = {
+ .name = "diva-gsp",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDivaSerialState),
+ .instance_init = diva_serial_init,
+ .class_init = diva_serial_class_initfn,
+ .interfaces = (const InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+static void diva_pci_register_type(void)
+{
+ type_register_static(&diva_serial_pci_info);
+ type_register_static(&diva_aux_info);
+}
+
+type_init(diva_pci_register_type)
diff --git a/hw/char/escc.c b/hw/char/escc.c
index d450d70..afe4ca4 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -287,6 +287,7 @@ static void escc_reset_chn(ESCCChannelState *s)
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;
+ s->sunmouse_dx = s->sunmouse_dy = s->sunmouse_buttons = 0;
clear_queue(s);
}
@@ -952,53 +953,96 @@ static void handle_kbd_command(ESCCChannelState *s, int val)
}
}
-static void sunmouse_event(void *opaque,
- int dx, int dy, int dz, int buttons_state)
+static void sunmouse_handle_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- ESCCChannelState *s = opaque;
- int ch;
+ ESCCChannelState *s = (ESCCChannelState *)dev;
+ InputMoveEvent *move;
+ InputBtnEvent *btn;
+ static const int bmap[INPUT_BUTTON__MAX] = {
+ [INPUT_BUTTON_LEFT] = 0x4,
+ [INPUT_BUTTON_MIDDLE] = 0x2,
+ [INPUT_BUTTON_RIGHT] = 0x1,
+ };
+
+ switch (evt->type) {
+ case INPUT_EVENT_KIND_REL:
+ move = evt->u.rel.data;
+ if (move->axis == INPUT_AXIS_X) {
+ s->sunmouse_dx += move->value;
+ } else if (move->axis == INPUT_AXIS_Y) {
+ s->sunmouse_dy -= move->value;
+ }
+ break;
- trace_escc_sunmouse_event(dx, dy, buttons_state);
- ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
+ case INPUT_EVENT_KIND_BTN:
+ btn = evt->u.btn.data;
+ if (bmap[btn->button]) {
+ if (btn->down) {
+ s->sunmouse_buttons |= bmap[btn->button];
+ } else {
+ s->sunmouse_buttons &= ~bmap[btn->button];
+ }
+ /* Indicate we have a supported button event */
+ s->sunmouse_buttons |= 0x80;
+ }
+ break;
- if (buttons_state & MOUSE_EVENT_LBUTTON) {
- ch ^= 0x4;
- }
- if (buttons_state & MOUSE_EVENT_MBUTTON) {
- ch ^= 0x2;
+ default:
+ /* keep gcc happy */
+ break;
}
- if (buttons_state & MOUSE_EVENT_RBUTTON) {
- ch ^= 0x1;
+}
+
+static void sunmouse_sync(DeviceState *dev)
+{
+ ESCCChannelState *s = (ESCCChannelState *)dev;
+ int ch;
+
+ if (s->sunmouse_dx == 0 && s->sunmouse_dy == 0 &&
+ (s->sunmouse_buttons & 0x80) == 0) {
+ /* Nothing to do after button event filter */
+ return;
}
+ /* Clear our button event flag */
+ s->sunmouse_buttons &= ~0x80;
+ trace_escc_sunmouse_event(s->sunmouse_dx, s->sunmouse_dy,
+ s->sunmouse_buttons);
+ ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
+ ch ^= s->sunmouse_buttons;
put_queue(s, ch);
- ch = dx;
-
+ ch = s->sunmouse_dx;
if (ch > 127) {
ch = 127;
} else if (ch < -127) {
ch = -127;
}
-
put_queue(s, ch & 0xff);
+ s->sunmouse_dx -= ch;
- ch = -dy;
-
+ ch = s->sunmouse_dy;
if (ch > 127) {
ch = 127;
} else if (ch < -127) {
ch = -127;
}
-
put_queue(s, ch & 0xff);
+ s->sunmouse_dy -= ch;
/* MSC protocol specifies two extra motion bytes */
-
put_queue(s, 0);
put_queue(s, 0);
}
+static const QemuInputHandler sunmouse_handler = {
+ .name = "QEMU Sun Mouse",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+ .event = sunmouse_handle_event,
+ .sync = sunmouse_sync,
+};
+
static void escc_init1(Object *obj)
{
ESCCState *s = ESCC(obj);
@@ -1036,8 +1080,8 @@ static void escc_realize(DeviceState *dev, Error **errp)
}
if (s->chn[0].type == escc_mouse) {
- qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
- "QEMU Sun Mouse");
+ s->chn[0].hs = qemu_input_handler_register((DeviceState *)(&s->chn[0]),
+ &sunmouse_handler);
}
if (s->chn[1].type == escc_kbd) {
s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]),
@@ -1045,7 +1089,7 @@ static void escc_realize(DeviceState *dev, Error **errp)
}
}
-static Property escc_properties[] = {
+static const Property escc_properties[] = {
DEFINE_PROP_UINT32("frequency", ESCCState, frequency, 0),
DEFINE_PROP_UINT32("it_shift", ESCCState, it_shift, 0),
DEFINE_PROP_BOOL("bit_swap", ESCCState, bit_swap, false),
@@ -1055,14 +1099,13 @@ static Property escc_properties[] = {
DEFINE_PROP_CHR("chrB", ESCCState, chn[0].chr),
DEFINE_PROP_CHR("chrA", ESCCState, chn[1].chr),
DEFINE_PROP_STRING("chnA-sunkbd-layout", ESCCState, chn[1].sunkbd_layout),
- DEFINE_PROP_END_OF_LIST(),
};
-static void escc_class_init(ObjectClass *klass, void *data)
+static void escc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = escc_reset;
+ device_class_set_legacy_reset(dc, escc_reset);
dc->realize = escc_realize;
dc->vmsd = &vmstate_escc;
device_class_set_props(dc, escc_properties);
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
deleted file mode 100644
index 8d6422d..0000000
--- a/hw/char/etraxfs_ser.c
+++ /dev/null
@@ -1,267 +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/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/sysbus.h"
-#include "chardev/char-fe.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.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"
-typedef struct ETRAXSerial ETRAXSerial;
-DECLARE_INSTANCE_CHECKER(ETRAXSerial, ETRAX_SERIAL,
- TYPE_ETRAX_FS_SERIAL)
-
-struct ETRAXSerial {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- CharBackend 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];
-};
-
-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 " HWADDR_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 " HWADDR_FMT_plx "=%x\n", __func__, addr, value));
- addr >>= 2;
- switch (addr)
- {
- case RW_DOUT:
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&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 Property etraxfs_ser_properties[] = {
- DEFINE_PROP_CHR("chardev", ETRAXSerial, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-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, QEMUChrEvent 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 void etraxfs_ser_init(Object *obj)
-{
- ETRAXSerial *s = ETRAX_SERIAL(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->mmio, obj, &ser_ops, s,
- "etraxfs-serial", R_MAX * 4);
- sysbus_init_mmio(dev, &s->mmio);
-}
-
-static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
-{
- ETRAXSerial *s = ETRAX_SERIAL(dev);
-
- qemu_chr_fe_set_handlers(&s->chr,
- serial_can_receive, serial_receive,
- serial_event, NULL, s, NULL, true);
-}
-
-static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = etraxfs_ser_reset;
- device_class_set_props(dc, etraxfs_ser_properties);
- dc->realize = etraxfs_ser_realize;
-}
-
-static const TypeInfo etraxfs_ser_info = {
- .name = TYPE_ETRAX_FS_SERIAL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXSerial),
- .instance_init = etraxfs_ser_init,
- .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/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 8cdd42e..6521b4c 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -704,20 +704,19 @@ static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
NULL, s, NULL, true);
}
-static Property exynos4210_uart_properties[] = {
+static const 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)
+static void exynos4210_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = exynos4210_uart_realize;
- dc->reset = exynos4210_uart_reset;
+ device_class_set_legacy_reset(dc, exynos4210_uart_reset);
device_class_set_props(dc, exynos4210_uart_properties);
dc->vmsd = &vmstate_exynos4210_uart;
}
diff --git a/hw/char/goldfish_tty.c b/hw/char/goldfish_tty.c
index f8ff043..a37408a 100644
--- a/hw/char/goldfish_tty.c
+++ b/hw/char/goldfish_tty.c
@@ -15,7 +15,8 @@
#include "chardev/char-fe.h"
#include "qemu/log.h"
#include "trace.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
+#include "system/dma.h"
#include "hw/char/goldfish_tty.h"
#define GOLDFISH_TTY_VERSION 1
@@ -69,7 +70,6 @@ static uint64_t goldfish_tty_read(void *opaque, hwaddr addr,
static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
{
uint32_t to_copy;
- uint8_t *buf;
uint8_t data_out[GOLFISH_TTY_BUFFER_SIZE];
int len;
uint64_t ptr;
@@ -97,8 +97,8 @@ static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
while (len) {
to_copy = MIN(GOLFISH_TTY_BUFFER_SIZE, len);
- address_space_rw(&address_space_memory, ptr,
- MEMTXATTRS_UNSPECIFIED, data_out, to_copy, 0);
+ dma_memory_read_relaxed(&address_space_memory, ptr,
+ data_out, to_copy);
qemu_chr_fe_write_all(&s->chr, data_out, to_copy);
len -= to_copy;
@@ -109,9 +109,9 @@ static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
len = s->data_len;
ptr = s->data_ptr;
while (len && !fifo8_is_empty(&s->rx_fifo)) {
- buf = (uint8_t *)fifo8_pop_buf(&s->rx_fifo, len, &to_copy);
- address_space_rw(&address_space_memory, ptr,
- MEMTXATTRS_UNSPECIFIED, buf, to_copy, 1);
+ const uint8_t *buf = fifo8_pop_bufptr(&s->rx_fifo, len, &to_copy);
+
+ dma_memory_write_relaxed(&address_space_memory, ptr, buf, to_copy);
len -= to_copy;
ptr += to_copy;
@@ -241,9 +241,8 @@ static const VMStateDescription vmstate_goldfish_tty = {
}
};
-static Property goldfish_tty_properties[] = {
+static const Property goldfish_tty_properties[] = {
DEFINE_PROP_CHR("chardev", GoldfishTTYState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void goldfish_tty_instance_init(Object *obj)
@@ -257,12 +256,12 @@ static void goldfish_tty_instance_init(Object *obj)
sysbus_init_irq(dev, &s->irq);
}
-static void goldfish_tty_class_init(ObjectClass *oc, void *data)
+static void goldfish_tty_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, goldfish_tty_properties);
- dc->reset = goldfish_tty_reset;
+ device_class_set_legacy_reset(dc, goldfish_tty_reset);
dc->realize = goldfish_tty_realize;
dc->unrealize = goldfish_tty_unrealize;
dc->vmsd = &vmstate_goldfish_tty;
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index 515b65b..81c26e3 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -277,17 +277,16 @@ static void grlib_apbuart_reset(DeviceState *d)
uart->current = 0;
}
-static Property grlib_apbuart_properties[] = {
+static const 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)
+static void grlib_apbuart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = grlib_apbuart_realize;
- dc->reset = grlib_apbuart_reset;
+ device_class_set_legacy_reset(dc, grlib_apbuart_reset);
device_class_set_props(dc, grlib_apbuart_properties);
}
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
index 63aae6d..d6f0d18 100644
--- a/hw/char/ibex_uart.c
+++ b/hw/char/ibex_uart.c
@@ -508,9 +508,8 @@ static const VMStateDescription vmstate_ibex_uart = {
}
};
-static Property ibex_uart_properties[] = {
+static const Property ibex_uart_properties[] = {
DEFINE_PROP_CHR("chardev", IbexUartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void ibex_uart_init(Object *obj)
@@ -543,11 +542,11 @@ static void ibex_uart_realize(DeviceState *dev, Error **errp)
s, NULL, true);
}
-static void ibex_uart_class_init(ObjectClass *klass, void *data)
+static void ibex_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ibex_uart_reset;
+ device_class_set_legacy_reset(dc, ibex_uart_reset);
dc->realize = ibex_uart_realize;
dc->vmsd = &vmstate_ibex_uart;
device_class_set_props(dc, ibex_uart_properties);
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index ba37be6..509b014 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -27,6 +27,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/fifo32.h"
+#include "trace.h"
#ifndef DEBUG_IMX_UART
#define DEBUG_IMX_UART 0
@@ -159,6 +160,7 @@ static void imx_serial_reset(IMXSerialState *s)
s->ucr3 = 0x700;
s->ubmr = 0;
s->ubrc = 4;
+ s->ufcr = BIT(11) | BIT(0);
fifo32_reset(&s->rx_fifo);
timer_del(&s->ageing_timer);
@@ -184,10 +186,10 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
unsigned size)
{
IMXSerialState *s = (IMXSerialState *)opaque;
+ Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
uint32_t c, rx_used;
uint8_t rxtl = s->ufcr & TL_MASK;
-
- DPRINTF("read(offset=0x%" HWADDR_PRIx ")\n", offset);
+ uint64_t value;
switch (offset >> 2) {
case 0x0: /* URXD */
@@ -208,49 +210,67 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
imx_serial_rx_fifo_ageing_timer_restart(s);
qemu_chr_fe_accept_input(&s->chr);
}
- return c;
+ value = c;
+ break;
case 0x20: /* UCR1 */
- return s->ucr1;
+ value = s->ucr1;
+ break;
case 0x21: /* UCR2 */
- return s->ucr2;
+ value = s->ucr2;
+ break;
case 0x25: /* USR1 */
- return s->usr1;
+ value = s->usr1;
+ break;
case 0x26: /* USR2 */
- return s->usr2;
+ value = s->usr2;
+ break;
case 0x2A: /* BRM Modulator */
- return s->ubmr;
+ value = s->ubmr;
+ break;
case 0x2B: /* Baud Rate Count */
- return s->ubrc;
+ value = s->ubrc;
+ break;
case 0x2d: /* Test register */
- return s->uts1;
+ value = s->uts1;
+ break;
case 0x24: /* UFCR */
- return s->ufcr;
+ value = s->ufcr;
+ break;
case 0x2c:
- return s->onems;
+ value = s->onems;
+ break;
case 0x22: /* UCR3 */
- return s->ucr3;
+ value = s->ucr3;
+ break;
case 0x23: /* UCR4 */
- return s->ucr4;
+ value = s->ucr4;
+ break;
case 0x29: /* BRM Incremental */
- return 0x0; /* TODO */
+ value = 0x0; /* TODO */
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
- return 0;
+ value = 0;
+ break;
}
+
+ trace_imx_serial_read(chr ? chr->label : "NODEV", offset, value);
+
+ return value;
}
static void imx_serial_write(void *opaque, hwaddr offset,
@@ -260,8 +280,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
unsigned char ch;
- DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n",
- offset, (unsigned int)value, chr ? chr->label : "NODEV");
+ trace_imx_serial_write(chr ? chr->label : "NODEV", offset, value);
switch (offset >> 2) {
case 0x10: /* UTXD */
@@ -367,27 +386,30 @@ static void imx_serial_write(void *opaque, hwaddr offset,
static int imx_can_receive(void *opaque)
{
IMXSerialState *s = (IMXSerialState *)opaque;
- return s->ucr2 & UCR2_RXEN && fifo32_num_used(&s->rx_fifo) < FIFO_SIZE;
+
+ return s->ucr2 & UCR2_RXEN ? fifo32_num_free(&s->rx_fifo) : 0;
}
static void imx_put_data(void *opaque, uint32_t value)
{
IMXSerialState *s = (IMXSerialState *)opaque;
+ Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
uint8_t rxtl = s->ufcr & TL_MASK;
- DPRINTF("received char\n");
+ trace_imx_serial_put_data(chr ? chr->label : "NODEV", value);
+
imx_serial_rx_fifo_push(s, value);
if (fifo32_num_used(&s->rx_fifo) >= rxtl) {
s->usr1 |= USR1_RRDY;
}
-
- imx_serial_rx_fifo_ageing_timer_restart(s);
-
s->usr2 |= USR2_RDR;
s->uts1 &= ~UTS1_RXEMPTY;
if (value & URXD_BRK) {
s->usr2 |= USR2_BRCD;
}
+
+ imx_serial_rx_fifo_ageing_timer_restart(s);
+
imx_update(s);
}
@@ -396,7 +418,10 @@ static void imx_receive(void *opaque, const uint8_t *buf, int size)
IMXSerialState *s = (IMXSerialState *)opaque;
s->usr2 |= USR2_WAKE;
- imx_put_data(opaque, *buf);
+
+ for (int i = 0; i < size; i++) {
+ imx_put_data(opaque, buf[i]);
+ }
}
static void imx_event(void *opaque, QEMUChrEvent event)
@@ -438,18 +463,17 @@ static void imx_serial_init(Object *obj)
sysbus_init_irq(sbd, &s->irq);
}
-static Property imx_serial_properties[] = {
+static const 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)
+static void imx_serial_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_serial_realize;
dc->vmsd = &vmstate_imx_serial;
- dc->reset = imx_serial_reset_at_boot;
+ device_class_set_legacy_reset(dc, imx_serial_reset_at_boot);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->desc = "i.MX series UART";
device_class_set_props(dc, imx_serial_properties);
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 64be522..752c6c8 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -184,9 +184,9 @@ static void update_irq(IPOctalState *dev, unsigned block)
unsigned intno = block / 2;
if ((blk0->isr & blk0->imr) || (blk1->isr & blk1->imr)) {
- qemu_irq_raise(idev->irq[intno]);
+ qemu_irq_raise(&idev->irq[intno]);
} else {
- qemu_irq_lower(idev->irq[intno]);
+ qemu_irq_lower(&idev->irq[intno]);
}
}
@@ -558,7 +558,7 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
}
}
-static Property ipoctal_properties[] = {
+static const 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),
@@ -567,10 +567,9 @@ static Property ipoctal_properties[] = {
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)
+static void ipoctal_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass);
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index f9cbc9b..87bfcbe 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -17,6 +17,8 @@
#include "chardev/char-fe.h"
#include "qom/object.h"
+#define FIFO_DEPTH 4
+
struct mcf_uart_state {
SysBusDevice parent_obj;
@@ -27,7 +29,7 @@ struct mcf_uart_state {
uint8_t imr;
uint8_t bg1;
uint8_t bg2;
- uint8_t fifo[4];
+ uint8_t fifo[FIFO_DEPTH];
uint8_t tb;
int current_mr;
int fifo_len;
@@ -247,14 +249,16 @@ static void mcf_uart_reset(DeviceState *dev)
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)
+ if (s->fifo_len == FIFO_DEPTH) {
s->fifo_len--;
+ }
s->fifo[s->fifo_len] = data;
s->fifo_len++;
s->sr |= MCF_UART_RxRDY;
- if (s->fifo_len == 4)
+ if (s->fifo_len == FIFO_DEPTH) {
s->sr |= MCF_UART_FFULL;
+ }
mcf_uart_update(s);
}
@@ -277,14 +281,16 @@ 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;
+ return s->rx_enabled ? FIFO_DEPTH - s->fifo_len : 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]);
+ for (int i = 0; i < size; i++) {
+ mcf_uart_push_byte(s, buf[i]);
+ }
}
static const MemoryRegionOps mcf_uart_ops = {
@@ -312,17 +318,16 @@ static void mcf_uart_realize(DeviceState *dev, Error **errp)
mcf_uart_event, NULL, s, NULL, true);
}
-static Property mcf_uart_properties[] = {
+static const Property mcf_uart_properties[] = {
DEFINE_PROP_CHR("chardev", mcf_uart_state, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void mcf_uart_class_init(ObjectClass *oc, void *data)
+static void mcf_uart_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mcf_uart_realize;
- dc->reset = mcf_uart_reset;
+ device_class_set_legacy_reset(dc, mcf_uart_reset);
device_class_set_props(dc, mcf_uart_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
diff --git a/hw/char/mchp_pfsoc_mmuart.c b/hw/char/mchp_pfsoc_mmuart.c
index e7908bb..6149f9d 100644
--- a/hw/char/mchp_pfsoc_mmuart.c
+++ b/hw/char/mchp_pfsoc_mmuart.c
@@ -121,12 +121,12 @@ static const VMStateDescription mchp_pfsoc_mmuart_vmstate = {
}
};
-static void mchp_pfsoc_mmuart_class_init(ObjectClass *oc, void *data)
+static void mchp_pfsoc_mmuart_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mchp_pfsoc_mmuart_realize;
- dc->reset = mchp_pfsoc_mmuart_reset;
+ device_class_set_legacy_reset(dc, mchp_pfsoc_mmuart_reset);
dc->vmsd = &mchp_pfsoc_mmuart_vmstate;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
diff --git a/hw/char/meson.build b/hw/char/meson.build
index e5b13b6..4e439da 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -1,25 +1,26 @@
system_ss.add(when: 'CONFIG_CADENCE', if_true: files('cadence_uart.c'))
system_ss.add(when: 'CONFIG_CMSDK_APB_UART', if_true: files('cmsdk-apb-uart.c'))
system_ss.add(when: 'CONFIG_ESCC', if_true: files('escc.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_ser.c'))
system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_apbuart.c'))
system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_uart.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_serial.c'))
-system_ss.add(when: 'CONFIG_IPACK', if_true: files('ipoctal232.c'))
+system_ss.add(when: 'CONFIG_IP_OCTAL_232', if_true: files('ipoctal232.c'))
system_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('parallel-isa.c'))
system_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugcon.c'))
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_uart.c'))
system_ss.add(when: 'CONFIG_PARALLEL', if_true: files('parallel.c'))
-system_ss.add(when: 'CONFIG_PL011', if_true: files('pl011.c'))
+system_ss.add(when: 'CONFIG_PL011_C', if_true: files('pl011.c'))
system_ss.add(when: 'CONFIG_SCLPCONSOLE', if_true: files('sclpconsole.c', 'sclpconsole-lm.c'))
system_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c'))
system_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c'))
+system_ss.add(when: 'CONFIG_SERIAL_MM', if_true: files('serial-mm.c'))
system_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files('serial-pci.c'))
system_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci-multi.c'))
system_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files('shakti_uart.c'))
system_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c'))
system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen_console.c'))
system_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c'))
+system_ss.add(when: 'CONFIG_DIVA_GSP', if_true: files('diva-gsp.c'))
system_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c'))
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_uart.c'))
diff --git a/hw/char/nrf51_uart.c b/hw/char/nrf51_uart.c
index c2cd6bb..41d4234 100644
--- a/hw/char/nrf51_uart.c
+++ b/hw/char/nrf51_uart.c
@@ -304,16 +304,15 @@ static const VMStateDescription nrf51_uart_vmstate = {
}
};
-static Property nrf51_uart_properties[] = {
+static const Property nrf51_uart_properties[] = {
DEFINE_PROP_CHR("chardev", NRF51UARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void nrf51_uart_class_init(ObjectClass *klass, void *data)
+static void nrf51_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = nrf51_uart_reset;
+ device_class_set_legacy_reset(dc, nrf51_uart_reset);
dc->realize = nrf51_uart_realize;
device_class_set_props(dc, nrf51_uart_properties);
dc->vmsd = &nrf51_uart_vmstate;
diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c
index c2ef4c1..8cbf6ce 100644
--- a/hw/char/omap_uart.c
+++ b/hw/char/omap_uart.c
@@ -20,15 +20,14 @@
#include "qemu/osdep.h"
#include "chardev/char.h"
#include "hw/arm/omap.h"
-#include "hw/char/serial.h"
-#include "exec/address-spaces.h"
+#include "hw/char/serial-mm.h"
+#include "system/address-spaces.h"
/* UARTs */
struct omap_uart_s {
MemoryRegion iomem;
hwaddr base;
SerialMM *serial; /* TODO */
- struct omap_target_agent_s *ta;
omap_clk fclk;
qemu_irq irq;
@@ -36,8 +35,6 @@ struct omap_uart_s {
uint8_t syscontrol;
uint8_t wkup;
uint8_t cfps;
- uint8_t mdr[2];
- uint8_t scr;
uint8_t clksel;
};
@@ -66,113 +63,3 @@ struct omap_uart_s *omap_uart_init(hwaddr base,
DEVICE_NATIVE_ENDIAN);
return s;
}
-
-static uint64_t omap_uart_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_uart_s *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 = 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, Chardev *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;
-}
diff --git a/hw/char/parallel-isa.c b/hw/char/parallel-isa.c
index a5ce6ee..b6dfb6c 100644
--- a/hw/char/parallel-isa.c
+++ b/hw/char/parallel-isa.c
@@ -10,7 +10,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
#include "hw/char/parallel-isa.h"
diff --git a/hw/char/parallel.c b/hw/char/parallel.c
index c394635..8732e4e 100644
--- a/hw/char/parallel.c
+++ b/hw/char/parallel.c
@@ -33,8 +33,8 @@
#include "migration/vmstate.h"
#include "hw/char/parallel-isa.h"
#include "hw/char/parallel.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
+#include "system/reset.h"
+#include "system/system.h"
#include "trace.h"
#include "qom/object.h"
@@ -603,15 +603,14 @@ bool parallel_mm_init(MemoryRegion *address_space,
return true;
}
-static Property parallel_isa_properties[] = {
+static const 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)
+static void parallel_isa_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
@@ -628,7 +627,7 @@ static const TypeInfo parallel_isa_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(ISAParallelState),
.class_init = parallel_isa_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 8753b84..01335d9 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -85,7 +85,16 @@ DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr)
#define CR_OUT1 (1 << 12)
#define CR_RTS (1 << 11)
#define CR_DTR (1 << 10)
+#define CR_RXE (1 << 9)
+#define CR_TXE (1 << 8)
#define CR_LBE (1 << 7)
+#define CR_UARTEN (1 << 0)
+
+/* Integer Baud Rate Divider, UARTIBRD */
+#define IBRD_MASK 0xffff
+
+/* Fractional Baud Rate Divider, UARTFBRD */
+#define FBRD_MASK 0x3f
static const unsigned char pl011_id_arm[8] =
{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
@@ -132,6 +141,11 @@ static void pl011_update(PL011State *s)
}
}
+static bool pl011_loopback_enabled(PL011State *s)
+{
+ return !!(s->cr & CR_LBE);
+}
+
static bool pl011_is_fifo_enabled(PL011State *s)
{
return (s->lcr & LCR_FEN) != 0;
@@ -143,41 +157,127 @@ static inline unsigned pl011_get_fifo_depth(PL011State *s)
return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1;
}
-static inline void pl011_reset_fifo(PL011State *s)
+static inline void pl011_reset_rx_fifo(PL011State *s)
{
s->read_count = 0;
s->read_pos = 0;
/* Reset FIFO flags */
- s->flags &= ~(PL011_FLAG_RXFF | PL011_FLAG_TXFF);
- s->flags |= PL011_FLAG_RXFE | PL011_FLAG_TXFE;
+ s->flags &= ~PL011_FLAG_RXFF;
+ s->flags |= PL011_FLAG_RXFE;
+}
+
+static inline void pl011_reset_tx_fifo(PL011State *s)
+{
+ /* Reset FIFO flags */
+ s->flags &= ~PL011_FLAG_TXFF;
+ s->flags |= PL011_FLAG_TXFE;
+}
+
+static void pl011_fifo_rx_put(void *opaque, uint32_t value)
+{
+ PL011State *s = (PL011State *)opaque;
+ int slot;
+ unsigned pipe_depth;
+
+ pipe_depth = pl011_get_fifo_depth(s);
+ slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
+ s->read_fifo[slot] = value;
+ s->read_count++;
+ s->flags &= ~PL011_FLAG_RXFE;
+ trace_pl011_fifo_rx_put(value, s->read_count, pipe_depth);
+ if (s->read_count == pipe_depth) {
+ trace_pl011_fifo_rx_full();
+ s->flags |= PL011_FLAG_RXFF;
+ }
+ if (s->read_count == s->read_trigger) {
+ s->int_level |= INT_RX;
+ pl011_update(s);
+ }
+}
+
+static void pl011_loopback_tx(PL011State *s, uint32_t value)
+{
+ if (!pl011_loopback_enabled(s)) {
+ return;
+ }
+
+ /*
+ * Caveat:
+ *
+ * In real hardware, TX loopback happens at the serial-bit level
+ * and then reassembled by the RX logics back into bytes and placed
+ * into the RX fifo. That is, loopback happens after TX fifo.
+ *
+ * Because the real hardware TX fifo is time-drained at the frame
+ * rate governed by the configured serial format, some loopback
+ * bytes in TX fifo may still be able to get into the RX fifo
+ * that could be full at times while being drained at software
+ * pace.
+ *
+ * In such scenario, the RX draining pace is the major factor
+ * deciding which loopback bytes get into the RX fifo, unless
+ * hardware flow-control is enabled.
+ *
+ * For simplicity, the above described is not emulated.
+ */
+ pl011_fifo_rx_put(s, value);
+}
+
+static void pl011_write_txdata(PL011State *s, uint8_t data)
+{
+ if (!(s->cr & CR_UARTEN)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "PL011 data written to disabled UART\n");
+ }
+ if (!(s->cr & CR_TXE)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "PL011 data written to disabled TX UART\n");
+ }
+
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &data, 1);
+ pl011_loopback_tx(s, data);
+ s->int_level |= INT_TX;
+ pl011_update(s);
+}
+
+static uint32_t pl011_read_rxdata(PL011State *s)
+{
+ uint32_t c;
+ unsigned fifo_depth = pl011_get_fifo_depth(s);
+
+ s->flags &= ~PL011_FLAG_RXFF;
+ c = s->read_fifo[s->read_pos];
+ if (s->read_count > 0) {
+ s->read_count--;
+ s->read_pos = (s->read_pos + 1) & (fifo_depth - 1);
+ }
+ if (s->read_count == 0) {
+ s->flags |= PL011_FLAG_RXFE;
+ }
+ if (s->read_count == s->read_trigger - 1) {
+ s->int_level &= ~INT_RX;
+ }
+ trace_pl011_read_fifo(s->read_count, fifo_depth);
+ s->rsr = c >> 8;
+ pl011_update(s);
+ qemu_chr_fe_accept_input(&s->chr);
+ return c;
}
static uint64_t pl011_read(void *opaque, hwaddr offset,
unsigned size)
{
PL011State *s = (PL011State *)opaque;
- uint32_t c;
uint64_t r;
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--;
- s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1);
- }
- if (s->read_count == 0) {
- s->flags |= PL011_FLAG_RXFE;
- }
- if (s->read_count == s->read_trigger - 1)
- s->int_level &= ~ INT_RX;
- trace_pl011_read_fifo(s->read_count);
- s->rsr = c >> 8;
- pl011_update(s);
- qemu_chr_fe_accept_input(&s->chr);
- r = c;
+ r = pl011_read_rxdata(s);
break;
case 1: /* UARTRSR */
r = s->rsr;
@@ -262,11 +362,6 @@ static void pl011_trace_baudrate_change(const PL011State *s)
s->ibrd, s->fbrd);
}
-static bool pl011_loopback_enabled(PL011State *s)
-{
- return !!(s->cr & CR_LBE);
-}
-
static void pl011_loopback_mdmctrl(PL011State *s)
{
uint32_t cr, fr, il;
@@ -308,36 +403,6 @@ static void pl011_loopback_mdmctrl(PL011State *s)
pl011_update(s);
}
-static void pl011_put_fifo(void *opaque, uint32_t value);
-
-static void pl011_loopback_tx(PL011State *s, uint32_t value)
-{
- if (!pl011_loopback_enabled(s)) {
- return;
- }
-
- /*
- * Caveat:
- *
- * In real hardware, TX loopback happens at the serial-bit level
- * and then reassembled by the RX logics back into bytes and placed
- * into the RX fifo. That is, loopback happens after TX fifo.
- *
- * Because the real hardware TX fifo is time-drained at the frame
- * rate governed by the configured serial format, some loopback
- * bytes in TX fifo may still be able to get into the RX fifo
- * that could be full at times while being drained at software
- * pace.
- *
- * In such scenario, the RX draining pace is the major factor
- * deciding which loopback bytes get into the RX fifo, unless
- * hardware flow-control is enabled.
- *
- * For simplicity, the above described is not emulated.
- */
- pl011_put_fifo(s, value);
-}
-
static void pl011_loopback_break(PL011State *s, int brk_enable)
{
if (brk_enable) {
@@ -355,14 +420,8 @@ static void pl011_write(void *opaque, hwaddr offset,
switch (offset >> 2) {
case 0: /* UARTDR */
- /* ??? Check if transmitter is enabled. */
ch = value;
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, &ch, 1);
- pl011_loopback_tx(s, ch);
- s->int_level |= INT_TX;
- pl011_update(s);
+ pl011_write_txdata(s, ch);
break;
case 1: /* UARTRSR/UARTECR */
s->rsr = 0;
@@ -374,17 +433,18 @@ static void pl011_write(void *opaque, hwaddr offset,
s->ilpr = value;
break;
case 9: /* UARTIBRD */
- s->ibrd = value;
+ s->ibrd = value & IBRD_MASK;
pl011_trace_baudrate_change(s);
break;
case 10: /* UARTFBRD */
- s->fbrd = value;
+ s->fbrd = value & FBRD_MASK;
pl011_trace_baudrate_change(s);
break;
case 11: /* UARTLCR_H */
/* Reset the FIFO state on FIFO enable or disable */
if ((s->lcr ^ value) & LCR_FEN) {
- pl011_reset_fifo(s);
+ pl011_reset_rx_fifo(s);
+ pl011_reset_tx_fifo(s);
}
if ((s->lcr ^ value) & LCR_BRK) {
int break_enable = value & LCR_BRK;
@@ -427,37 +487,26 @@ static void pl011_write(void *opaque, hwaddr offset,
static int pl011_can_receive(void *opaque)
{
PL011State *s = (PL011State *)opaque;
- int r;
-
- r = s->read_count < pl011_get_fifo_depth(s);
- trace_pl011_can_receive(s->lcr, s->read_count, r);
- return r;
-}
+ unsigned fifo_depth = pl011_get_fifo_depth(s);
+ unsigned fifo_available = fifo_depth - s->read_count;
-static void pl011_put_fifo(void *opaque, uint32_t value)
-{
- PL011State *s = (PL011State *)opaque;
- int slot;
- unsigned pipe_depth;
+ /*
+ * In theory we should check the UART and RX enable bits here and
+ * return 0 if they are not set (so the guest can't receive data
+ * until you have enabled the UART). In practice we suspect there
+ * is at least some guest code out there which has been tested only
+ * on QEMU and which never bothers to enable the UART because we
+ * historically never enforced that. So we effectively keep the
+ * UART continuously enabled regardless of the enable bits.
+ */
- pipe_depth = pl011_get_fifo_depth(s);
- slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
- s->read_fifo[slot] = value;
- s->read_count++;
- s->flags &= ~PL011_FLAG_RXFE;
- trace_pl011_put_fifo(value, s->read_count);
- if (s->read_count == pipe_depth) {
- trace_pl011_put_fifo_full();
- s->flags |= PL011_FLAG_RXFF;
- }
- if (s->read_count == s->read_trigger) {
- s->int_level |= INT_RX;
- pl011_update(s);
- }
+ trace_pl011_can_receive(s->lcr, s->read_count, fifo_depth, fifo_available);
+ return fifo_available;
}
static void pl011_receive(void *opaque, const uint8_t *buf, int size)
{
+ trace_pl011_receive(size);
/*
* In loopback mode, the RX input signal is internally disconnected
* from the entire receiving logics; thus, all inputs are ignored,
@@ -467,13 +516,15 @@ static void pl011_receive(void *opaque, const uint8_t *buf, int size)
return;
}
- pl011_put_fifo(opaque, *buf);
+ for (int i = 0; i < size; i++) {
+ pl011_fifo_rx_put(opaque, buf[i]);
+ }
}
static void pl011_event(void *opaque, QEMUChrEvent event)
{
if (event == CHR_EVENT_BREAK && !pl011_loopback_enabled(opaque)) {
- pl011_put_fifo(opaque, DR_BE);
+ pl011_fifo_rx_put(opaque, DR_BE);
}
}
@@ -531,6 +582,9 @@ static int pl011_post_load(void *opaque, int version_id)
s->read_pos = 0;
}
+ s->ibrd &= IBRD_MASK;
+ s->fbrd &= FBRD_MASK;
+
return 0;
}
@@ -540,7 +594,7 @@ static const VMStateDescription vmstate_pl011 = {
.minimum_version_id = 2,
.post_load = pl011_post_load,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32(readbuff, PL011State),
+ VMSTATE_UNUSED(sizeof(uint32_t)),
VMSTATE_UINT32(flags, PL011State),
VMSTATE_UINT32(lcr, PL011State),
VMSTATE_UINT32(rsr, PL011State),
@@ -564,10 +618,9 @@ static const VMStateDescription vmstate_pl011 = {
}
};
-static Property pl011_properties[] = {
+static const Property pl011_properties[] = {
DEFINE_PROP_CHR("chardev", PL011State, chr),
DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true),
- DEFINE_PROP_END_OF_LIST(),
};
static void pl011_init(Object *obj)
@@ -612,15 +665,16 @@ static void pl011_reset(DeviceState *dev)
s->ifl = 0x12;
s->cr = 0x300;
s->flags = 0;
- pl011_reset_fifo(s);
+ pl011_reset_rx_fifo(s);
+ pl011_reset_tx_fifo(s);
}
-static void pl011_class_init(ObjectClass *oc, void *data)
+static void pl011_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = pl011_realize;
- dc->reset = pl011_reset;
+ device_class_set_legacy_reset(dc, pl011_reset);
dc->vmsd = &vmstate_pl011;
device_class_set_props(dc, pl011_properties);
}
diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c
index 5cb7335..b9d0ed1 100644
--- a/hw/char/renesas_sci.c
+++ b/hw/char/renesas_sci.c
@@ -319,19 +319,18 @@ static const VMStateDescription vmstate_rsci = {
}
};
-static Property rsci_properties[] = {
+static const Property rsci_properties[] = {
DEFINE_PROP_UINT64("input-freq", RSCIState, input_freq, 0),
DEFINE_PROP_CHR("chardev", RSCIState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void rsci_class_init(ObjectClass *klass, void *data)
+static void rsci_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = rsci_realize;
dc->vmsd = &vmstate_rsci;
- dc->reset = rsci_reset;
+ device_class_set_legacy_reset(dc, rsci_reset);
device_class_set_props(dc, rsci_properties);
}
diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c
index 9bef60d..c884be5 100644
--- a/hw/char/riscv_htif.c
+++ b/hw/char/riscv_htif.c
@@ -24,23 +24,15 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "hw/char/riscv_htif.h"
-#include "hw/char/serial.h"
#include "chardev/char.h"
#include "chardev/char-fe.h"
#include "qemu/timer.h"
#include "qemu/error-report.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "exec/tswap.h"
-#include "sysemu/dma.h"
-#include "sysemu/runstate.h"
-
-#define RISCV_DEBUG_HTIF 0
-#define HTIF_DEBUG(fmt, ...) \
- do { \
- if (RISCV_DEBUG_HTIF) { \
- qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\
- } \
- } while (0)
+#include "system/dma.h"
+#include "system/runstate.h"
+#include "trace.h"
#define HTIF_DEV_SHIFT 56
#define HTIF_CMD_SHIFT 48
@@ -160,8 +152,7 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
uint64_t payload = val_written & 0xFFFFFFFFFFFFULL;
int resp = 0;
- HTIF_DEBUG("mtohost write: device: %d cmd: %d what: %02" PRIx64
- " -payload: %016" PRIx64 "\n", device, cmd, payload & 0xFF, payload);
+ trace_htif_uart_write_to_host(device, cmd, payload);
/*
* Currently, there is a fixed mapping of devices:
@@ -213,12 +204,16 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
} else {
uint64_t syscall[8];
cpu_physical_memory_read(payload, syscall, sizeof(syscall));
- if (tswap64(syscall[0]) == PK_SYS_WRITE &&
- tswap64(syscall[1]) == HTIF_DEV_CONSOLE &&
- tswap64(syscall[3]) == HTIF_CONSOLE_CMD_PUTC) {
+ if (le64_to_cpu(syscall[0]) == PK_SYS_WRITE &&
+ le64_to_cpu(syscall[1]) == HTIF_DEV_CONSOLE &&
+ le64_to_cpu(syscall[3]) == HTIF_CONSOLE_CMD_PUTC) {
uint8_t ch;
- cpu_physical_memory_read(tswap64(syscall[2]), &ch, 1);
- qemu_chr_fe_write(&s->chr, &ch, 1);
+ cpu_physical_memory_read(le64_to_cpu(syscall[2]), &ch, 1);
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &ch, 1);
resp = 0x100 | (uint8_t)payload;
} else {
qemu_log_mask(LOG_UNIMP,
@@ -237,15 +232,18 @@ static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
return;
} else if (cmd == HTIF_CONSOLE_CMD_PUTC) {
uint8_t ch = (uint8_t)payload;
- qemu_chr_fe_write(&s->chr, &ch, 1);
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &ch, 1);
resp = 0x100 | (uint8_t)payload;
} else {
qemu_log("HTIF device %d: unknown command\n", device);
}
} else {
qemu_log("HTIF unknown device or command\n");
- HTIF_DEBUG("device: %d cmd: %d what: %02" PRIx64
- " payload: %016" PRIx64, device, cmd, payload & 0xFF, payload);
+ trace_htif_uart_unknown_device_command(device, cmd, payload);
}
/*
* Latest bbl does not set fromhost to 0 if there is a value in tohost.
@@ -317,6 +315,11 @@ static void htif_mm_write(void *opaque, hwaddr addr,
static const MemoryRegionOps htif_mm_ops = {
.read = htif_mm_read,
.write = htif_mm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
};
HTIFState *htif_mm_init(MemoryRegion *address_space, Chardev *chr,
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 7719f43..3e40d5e 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -214,7 +214,7 @@ static int process_mdb(SCLPEvent *event, MDBO *mdbo)
{
int rc;
int len;
- uint8_t buffer[SIZE_BUFFER];
+ QEMU_UNINITIALIZED uint8_t buffer[SIZE_BUFFER];
len = be16_to_cpu(mdbo->length);
len -= sizeof(mdbo->length) + sizeof(mdbo->type)
@@ -333,20 +333,19 @@ static void console_reset(DeviceState *dev)
scon->write_errors = 0;
}
-static Property console_properties[] = {
+static const 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)
+static void console_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
device_class_set_props(dc, console_properties);
- dc->reset = console_reset;
+ device_class_set_legacy_reset(dc, console_reset);
dc->vmsd = &vmstate_sclplmconsole;
ec->init = console_init;
ec->get_send_mask = send_mask;
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index 5d630b0..95e3045 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -251,18 +251,17 @@ static void console_reset(DeviceState *dev)
scon->notify = false;
}
-static Property console_properties[] = {
+static const Property console_properties[] = {
DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void console_class_init(ObjectClass *klass, void *data)
+static void console_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
device_class_set_props(dc, console_properties);
- dc->reset = console_reset;
+ device_class_set_legacy_reset(dc, console_reset);
dc->vmsd = &vmstate_sclpconsole;
ec->init = console_init;
ec->get_send_mask = send_mask;
diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c
index 329b352..0ea59a3 100644
--- a/hw/char/serial-isa.c
+++ b/hw/char/serial-isa.c
@@ -26,9 +26,10 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@@ -112,14 +113,13 @@ static const VMStateDescription vmstate_isa_serial = {
}
};
-static Property serial_isa_properties[] = {
+static const 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_END_OF_LIST(),
};
-static void serial_isa_class_initfn(ObjectClass *klass, void *data)
+static void serial_isa_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
@@ -146,7 +146,7 @@ static const TypeInfo serial_isa_info = {
.instance_size = sizeof(ISASerialState),
.instance_init = serial_isa_initfn,
.class_init = serial_isa_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/char/serial-mm.c b/hw/char/serial-mm.c
new file mode 100644
index 0000000..13aba78
--- /dev/null
+++ b/hw/char/serial-mm.c
@@ -0,0 +1,156 @@
+/*
+ * 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-mm.h"
+#include "exec/cpu-common.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+
+static uint64_t serial_mm_read(void *opaque, hwaddr addr, unsigned size)
+{
+ SerialMM *s = SERIAL_MM(opaque);
+ return serial_io_ops.read(&s->serial, addr >> s->regshift, 1);
+}
+
+static void serial_mm_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ SerialMM *s = SERIAL_MM(opaque);
+ value &= 255;
+ serial_io_ops.write(&s->serial, addr >> s->regshift, value, 1);
+}
+
+static const MemoryRegionOps serial_mm_ops[3] = {
+ [DEVICE_NATIVE_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+ [DEVICE_LITTLE_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+ [DEVICE_BIG_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+};
+
+static void serial_mm_realize(DeviceState *dev, Error **errp)
+{
+ SerialMM *smm = SERIAL_MM(dev);
+ SerialState *s = &smm->serial;
+
+ if (!qdev_realize(DEVICE(s), NULL, errp)) {
+ return;
+ }
+
+ memory_region_init_io(&s->io, OBJECT(dev),
+ &serial_mm_ops[smm->endianness], smm, "serial",
+ 8 << smm->regshift);
+ sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
+ sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
+}
+
+static const VMStateDescription vmstate_serial_mm = {
+ .name = "serial",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT(serial, SerialMM, 0, vmstate_serial, SerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+SerialMM *serial_mm_init(MemoryRegion *address_space,
+ hwaddr base, int regshift,
+ qemu_irq irq, int baudbase,
+ Chardev *chr, enum device_endian end)
+{
+ SerialMM *smm = SERIAL_MM(qdev_new(TYPE_SERIAL_MM));
+ MemoryRegion *mr;
+
+ qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift);
+ qdev_prop_set_uint32(DEVICE(smm), "baudbase", baudbase);
+ qdev_prop_set_chr(DEVICE(smm), "chardev", chr);
+ qdev_set_legacy_instance_id(DEVICE(smm), base, 2);
+ qdev_prop_set_uint8(DEVICE(smm), "endianness", end);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(smm), &error_fatal);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0);
+ memory_region_add_subregion(address_space, base, mr);
+
+ return smm;
+}
+
+static void serial_mm_instance_init(Object *o)
+{
+ SerialMM *smm = SERIAL_MM(o);
+
+ object_initialize_child(o, "serial", &smm->serial, TYPE_SERIAL);
+
+ qdev_alias_all_properties(DEVICE(&smm->serial), o);
+}
+
+static const Property serial_mm_properties[] = {
+ /*
+ * Set the spacing between adjacent memory-mapped UART registers.
+ * Each register will be at (1 << regshift) bytes after the previous one.
+ */
+ DEFINE_PROP_UINT8("regshift", SerialMM, regshift, 0),
+ DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN),
+};
+
+static void serial_mm_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ device_class_set_props(dc, serial_mm_properties);
+ dc->realize = serial_mm_realize;
+ dc->vmsd = &vmstate_serial_mm;
+}
+
+static const TypeInfo types[] = {
+ {
+ .name = TYPE_SERIAL_MM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = serial_mm_class_init,
+ .instance_init = serial_mm_instance_init,
+ .instance_size = sizeof(SerialMM),
+ },
+};
+
+DEFINE_TYPES(types)
diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c
index 28b2757..13df272 100644
--- a/hw/char/serial-pci-multi.c
+++ b/hw/char/serial-pci-multi.c
@@ -45,8 +45,7 @@ typedef struct PCIMultiSerialState {
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;
+ IRQState irqs[PCI_SERIAL_MAX_PORTS];
} PCIMultiSerialState;
static void multi_serial_pci_exit(PCIDevice *dev)
@@ -61,7 +60,6 @@ static void multi_serial_pci_exit(PCIDevice *dev)
memory_region_del_subregion(&pci->iobar, &s->io);
g_free(pci->name[i]);
}
- qemu_free_irqs(pci->irqs, pci->ports);
}
static void multi_serial_irq_mux(void *opaque, int n, int level)
@@ -98,11 +96,10 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
SerialState *s;
size_t i, nports = multi_serial_get_port_count(pc);
- pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
- pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+ pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */
+ pci->dev.config[PCI_INTERRUPT_PIN] = 1;
memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nports);
pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
- pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, nports);
for (i = 0; i < nports; i++) {
s = pci->state + i;
@@ -110,7 +107,7 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
multi_serial_pci_exit(dev);
return;
}
- s->irq = pci->irqs[i];
+ s->irq = &pci->irqs[i];
pci->name[i] = g_strdup_printf("uart #%zu", i + 1);
memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
pci->name[i], 8);
@@ -132,23 +129,20 @@ static const VMStateDescription vmstate_pci_multi_serial = {
}
};
-static Property multi_2x_serial_pci_properties[] = {
+static const 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[] = {
+static const 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 multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
+static void multi_2x_serial_pci_class_initfn(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
@@ -163,7 +157,8 @@ static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
-static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
+static void multi_4x_serial_pci_class_initfn(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
@@ -185,6 +180,7 @@ static void multi_serial_init(Object *o)
size_t i, nports = multi_serial_get_port_count(PCI_DEVICE_GET_CLASS(dev));
for (i = 0; i < nports; i++) {
+ qemu_init_irq(&pms->irqs[i], multi_serial_irq_mux, pms, i);
object_initialize_child(o, "serial[*]", &pms->state[i], TYPE_SERIAL);
}
}
@@ -195,7 +191,7 @@ static const TypeInfo multi_2x_serial_pci_info = {
.instance_size = sizeof(PCIMultiSerialState),
.instance_init = multi_serial_init,
.class_init = multi_2x_serial_pci_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
@@ -207,7 +203,7 @@ static const TypeInfo multi_4x_serial_pci_info = {
.instance_size = sizeof(PCIMultiSerialState),
.instance_init = multi_serial_init,
.class_init = multi_4x_serial_pci_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c
index f8a1a94..46efabc 100644
--- a/hw/char/serial-pci.c
+++ b/hw/char/serial-pci.c
@@ -38,7 +38,6 @@
struct PCISerialState {
PCIDevice dev;
SerialState state;
- uint8_t prog_if;
};
#define TYPE_PCI_SERIAL "pci-serial"
@@ -53,8 +52,8 @@ static void serial_pci_realize(PCIDevice *dev, Error **errp)
return;
}
- pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
- pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+ pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */
+ pci->dev.config[PCI_INTERRUPT_PIN] = 1;
s->irq = pci_allocate_irq(&pci->dev);
memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8);
@@ -81,12 +80,7 @@ static const VMStateDescription vmstate_pci_serial = {
}
};
-static Property serial_pci_properties[] = {
- DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_pci_class_initfn(ObjectClass *klass, void *data)
+static void serial_pci_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
@@ -97,7 +91,6 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data)
pc->revision = 1;
pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
dc->vmsd = &vmstate_pci_serial;
- device_class_set_props(dc, serial_pci_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
@@ -116,7 +109,7 @@ static const TypeInfo serial_pci_info = {
.instance_size = sizeof(PCISerialState),
.instance_init = serial_pci_init,
.class_init = serial_pci_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/char/serial.c b/hw/char/serial.c
index d8b2db5..03fec3f 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -31,8 +31,8 @@
#include "chardev/char-serial.h"
#include "qapi/error.h"
#include "qemu/timer.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
+#include "system/reset.h"
+#include "system/runstate.h"
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/qdev-properties.h"
@@ -951,13 +951,6 @@ static void serial_unrealize(DeviceState *dev)
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,
@@ -971,14 +964,13 @@ const MemoryRegionOps serial_io_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static Property serial_properties[] = {
+static const Property serial_properties[] = {
DEFINE_PROP_CHR("chardev", SerialState, chr),
DEFINE_PROP_UINT32("baudbase", SerialState, baudbase, 115200),
DEFINE_PROP_BOOL("wakeup", SerialState, wakeup, false),
- DEFINE_PROP_END_OF_LIST(),
};
-static void serial_class_init(ObjectClass *klass, void* data)
+static void serial_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -996,135 +988,9 @@ static const TypeInfo serial_info = {
.class_init = serial_class_init,
};
-/* Memory mapped interface */
-static uint64_t serial_mm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SerialMM *s = SERIAL_MM(opaque);
- return serial_ioport_read(&s->serial, addr >> s->regshift, 1);
-}
-
-static void serial_mm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SerialMM *s = SERIAL_MM(opaque);
- value &= 255;
- serial_ioport_write(&s->serial, addr >> s->regshift, value, 1);
-}
-
-static const MemoryRegionOps serial_mm_ops[3] = {
- [DEVICE_NATIVE_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
- [DEVICE_LITTLE_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
- [DEVICE_BIG_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
-};
-
-static void serial_mm_realize(DeviceState *dev, Error **errp)
-{
- SerialMM *smm = SERIAL_MM(dev);
- SerialState *s = &smm->serial;
-
- if (!qdev_realize(DEVICE(s), NULL, errp)) {
- return;
- }
-
- memory_region_init_io(&s->io, OBJECT(dev),
- &serial_mm_ops[smm->endianness], smm, "serial",
- 8 << smm->regshift);
- sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
- sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
-}
-
-static const VMStateDescription vmstate_serial_mm = {
- .name = "serial",
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_STRUCT(serial, SerialMM, 0, vmstate_serial, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-SerialMM *serial_mm_init(MemoryRegion *address_space,
- hwaddr base, int regshift,
- qemu_irq irq, int baudbase,
- Chardev *chr, enum device_endian end)
-{
- SerialMM *smm = SERIAL_MM(qdev_new(TYPE_SERIAL_MM));
- MemoryRegion *mr;
-
- qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift);
- qdev_prop_set_uint32(DEVICE(smm), "baudbase", baudbase);
- qdev_prop_set_chr(DEVICE(smm), "chardev", chr);
- qdev_set_legacy_instance_id(DEVICE(smm), base, 2);
- qdev_prop_set_uint8(DEVICE(smm), "endianness", end);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(smm), &error_fatal);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq);
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0);
- memory_region_add_subregion(address_space, base, mr);
-
- return smm;
-}
-
-static void serial_mm_instance_init(Object *o)
-{
- SerialMM *smm = SERIAL_MM(o);
-
- object_initialize_child(o, "serial", &smm->serial, TYPE_SERIAL);
-
- qdev_alias_all_properties(DEVICE(&smm->serial), o);
-}
-
-static Property serial_mm_properties[] = {
- /*
- * Set the spacing between adjacent memory-mapped UART registers.
- * Each register will be at (1 << regshift) bytes after the
- * previous one.
- */
- DEFINE_PROP_UINT8("regshift", SerialMM, regshift, 0),
- DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_mm_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- device_class_set_props(dc, serial_mm_properties);
- dc->realize = serial_mm_realize;
- dc->vmsd = &vmstate_serial_mm;
-}
-
-static const TypeInfo serial_mm_info = {
- .name = TYPE_SERIAL_MM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .class_init = serial_mm_class_init,
- .instance_init = serial_mm_instance_init,
- .instance_size = sizeof(SerialMM),
-};
-
static void serial_register_types(void)
{
type_register_static(&serial_info);
- type_register_static(&serial_mm_info);
}
type_init(serial_register_types)
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 355886e..30447fa 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -78,10 +78,6 @@ struct SHSerialState {
qemu_irq bri;
};
-typedef struct {} SHSerialStateClass;
-
-OBJECT_DEFINE_TYPE(SHSerialState, sh_serial, SH_SERIAL, SYS_BUS_DEVICE)
-
static void sh_serial_clear_fifo(SHSerialState *s)
{
memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
@@ -320,7 +316,7 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
static int sh_serial_can_receive(SHSerialState *s)
{
- return s->scr & (1 << 4);
+ return s->scr & (1 << 4) ? SH_RX_FIFO_LENGTH - s->rx_head : 0;
}
static void sh_serial_receive_break(SHSerialState *s)
@@ -353,22 +349,20 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
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) {
- timer_del(&s->fifo_timeout_timer);
- qemu_set_irq(s->rxi, 1);
- }
- } else {
- timer_mod(&s->fifo_timeout_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
+ 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) {
+ timer_del(&s->fifo_timeout_timer);
+ qemu_set_irq(s->rxi, 1);
}
+ } else {
+ timer_mod(&s->fifo_timeout_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
}
}
} else {
@@ -436,30 +430,37 @@ static void sh_serial_realize(DeviceState *d, Error **errp)
s->etu = NANOSECONDS_PER_SECOND / 9600;
}
-static void sh_serial_finalize(Object *obj)
+static void sh_serial_unrealize(DeviceState *dev)
{
- SHSerialState *s = SH_SERIAL(obj);
+ SHSerialState *s = SH_SERIAL(dev);
timer_del(&s->fifo_timeout_timer);
}
-static void sh_serial_init(Object *obj)
-{
-}
-
-static Property sh_serial_properties[] = {
+static const Property sh_serial_properties[] = {
DEFINE_PROP_CHR("chardev", SHSerialState, chr),
DEFINE_PROP_UINT8("features", SHSerialState, feat, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void sh_serial_class_init(ObjectClass *oc, void *data)
+static void sh_serial_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, sh_serial_properties);
dc->realize = sh_serial_realize;
- dc->reset = sh_serial_reset;
+ dc->unrealize = sh_serial_unrealize;
+ device_class_set_legacy_reset(dc, sh_serial_reset);
/* Reason: part of SuperH CPU/SoC, needs to be wired up */
dc->user_creatable = false;
}
+
+static const TypeInfo sh_serial_types[] = {
+ {
+ .name = TYPE_SH_SERIAL,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SHSerialState),
+ .class_init = sh_serial_class_init,
+ },
+};
+
+DEFINE_TYPES(sh_serial_types)
diff --git a/hw/char/shakti_uart.c b/hw/char/shakti_uart.c
index 98b142c..6e216ed 100644
--- a/hw/char/shakti_uart.c
+++ b/hw/char/shakti_uart.c
@@ -157,15 +157,14 @@ static void shakti_uart_instance_init(Object *obj)
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &sus->mmio);
}
-static Property shakti_uart_properties[] = {
+static const Property shakti_uart_properties[] = {
DEFINE_PROP_CHR("chardev", ShaktiUartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void shakti_uart_class_init(ObjectClass *klass, void *data)
+static void shakti_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = shakti_uart_reset;
+ device_class_set_legacy_reset(dc, shakti_uart_reset);
dc->realize = shakti_uart_realize;
device_class_set_props(dc, shakti_uart_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c
index 7fc6787..0fc89e7 100644
--- a/hw/char/sifive_uart.c
+++ b/hw/char/sifive_uart.c
@@ -26,6 +26,8 @@
#include "hw/char/sifive_uart.h"
#include "hw/qdev-properties-system.h"
+#define TX_INTERRUPT_TRIGGER_DELAY_NS 100
+
/*
* Not yet implemented:
*
@@ -64,6 +66,72 @@ static void sifive_uart_update_irq(SiFiveUARTState *s)
}
}
+static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
+ void *opaque)
+{
+ SiFiveUARTState *s = opaque;
+ int ret;
+ const uint8_t *characters;
+ uint32_t numptr = 0;
+
+ /* instant drain the fifo when there's no back-end */
+ if (!qemu_chr_fe_backend_connected(&s->chr)) {
+ fifo8_reset(&s->tx_fifo);
+ return G_SOURCE_REMOVE;
+ }
+
+ if (fifo8_is_empty(&s->tx_fifo)) {
+ return G_SOURCE_REMOVE;
+ }
+
+ /* Don't pop the FIFO in case the write fails */
+ characters = fifo8_peek_bufptr(&s->tx_fifo,
+ fifo8_num_used(&s->tx_fifo), &numptr);
+ ret = qemu_chr_fe_write(&s->chr, characters, numptr);
+
+ if (ret >= 0) {
+ /* We wrote the data, actually pop the fifo */
+ fifo8_pop_bufptr(&s->tx_fifo, ret, NULL);
+ }
+
+ if (!fifo8_is_empty(&s->tx_fifo)) {
+ guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
+ sifive_uart_xmit, s);
+ if (!r) {
+ fifo8_reset(&s->tx_fifo);
+ return G_SOURCE_REMOVE;
+ }
+ }
+
+ /* Clear the TX Full bit */
+ if (!fifo8_is_full(&s->tx_fifo)) {
+ s->txfifo &= ~SIFIVE_UART_TXFIFO_FULL;
+ }
+
+ sifive_uart_update_irq(s);
+ return G_SOURCE_REMOVE;
+}
+
+static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
+ int size)
+{
+ uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ if (size > fifo8_num_free(&s->tx_fifo)) {
+ size = fifo8_num_free(&s->tx_fifo);
+ qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow");
+ }
+
+ fifo8_push_all(&s->tx_fifo, buf, size);
+
+ if (fifo8_is_full(&s->tx_fifo)) {
+ s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
+ }
+
+ timer_mod(s->fifo_trigger_handle, current_time +
+ TX_INTERRUPT_TRIGGER_DELAY_NS);
+}
+
static uint64_t
sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
{
@@ -82,7 +150,7 @@ sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
return 0x80000000;
case SIFIVE_UART_TXFIFO:
- return 0; /* Should check tx fifo */
+ return s->txfifo;
case SIFIVE_UART_IE:
return s->ie;
case SIFIVE_UART_IP:
@@ -106,12 +174,11 @@ sifive_uart_write(void *opaque, hwaddr addr,
{
SiFiveUARTState *s = opaque;
uint32_t value = val64;
- unsigned char ch = value;
+ uint8_t ch = value;
switch (addr) {
case SIFIVE_UART_TXFIFO:
- qemu_chr_fe_write(&s->chr, &ch, 1);
- sifive_uart_update_irq(s);
+ sifive_uart_write_tx_fifo(s, &ch, 1);
return;
case SIFIVE_UART_IE:
s->ie = val64;
@@ -131,6 +198,13 @@ sifive_uart_write(void *opaque, hwaddr addr,
__func__, (int)addr, (int)value);
}
+static void fifo_trigger_update(void *opaque)
+{
+ SiFiveUARTState *s = opaque;
+
+ sifive_uart_xmit(NULL, G_IO_OUT, s);
+}
+
static const MemoryRegionOps sifive_uart_ops = {
.read = sifive_uart_read,
.write = sifive_uart_write,
@@ -177,9 +251,25 @@ static int sifive_uart_be_change(void *opaque)
return 0;
}
-static Property sifive_uart_properties[] = {
+static void sifive_uart_reset_enter(Object *obj, ResetType type)
+{
+ SiFiveUARTState *s = SIFIVE_UART(obj);
+
+ s->txfifo = 0;
+ s->ie = 0;
+ s->ip = 0;
+ s->txctrl = 0;
+ s->rxctrl = 0;
+ s->div = 0;
+
+ s->rx_fifo_len = 0;
+
+ memset(s->rx_fifo, 0, SIFIVE_UART_RX_FIFO_SIZE);
+ fifo8_reset(&s->tx_fifo);
+}
+
+static const Property sifive_uart_properties[] = {
DEFINE_PROP_CHR("chardev", SiFiveUARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void sifive_uart_init(Object *obj)
@@ -197,21 +287,24 @@ static void sifive_uart_realize(DeviceState *dev, Error **errp)
{
SiFiveUARTState *s = SIFIVE_UART(dev);
- qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
- sifive_uart_event, sifive_uart_be_change, s,
- NULL, true);
+ fifo8_create(&s->tx_fifo, SIFIVE_UART_TX_FIFO_SIZE);
+
+ s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ fifo_trigger_update, s);
+
+ if (qemu_chr_fe_backend_connected(&s->chr)) {
+ qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
+ sifive_uart_event, sifive_uart_be_change, s,
+ NULL, true);
+ }
}
-static void sifive_uart_reset_enter(Object *obj, ResetType type)
+static void sifive_uart_unrealize(DeviceState *dev)
{
- SiFiveUARTState *s = SIFIVE_UART(obj);
- s->ie = 0;
- s->ip = 0;
- s->txctrl = 0;
- s->rxctrl = 0;
- s->div = 0;
- s->rx_fifo_len = 0;
+ SiFiveUARTState *s = SIFIVE_UART(dev);
+
+ fifo8_destroy(&s->tx_fifo);
}
static void sifive_uart_reset_hold(Object *obj, ResetType type)
@@ -222,8 +315,8 @@ static void sifive_uart_reset_hold(Object *obj, ResetType type)
static const VMStateDescription vmstate_sifive_uart = {
.name = TYPE_SIFIVE_UART,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT8_ARRAY(rx_fifo, SiFiveUARTState,
SIFIVE_UART_RX_FIFO_SIZE),
@@ -233,17 +326,21 @@ static const VMStateDescription vmstate_sifive_uart = {
VMSTATE_UINT32(txctrl, SiFiveUARTState),
VMSTATE_UINT32(rxctrl, SiFiveUARTState),
VMSTATE_UINT32(div, SiFiveUARTState),
+ VMSTATE_UINT32(txfifo, SiFiveUARTState),
+ VMSTATE_FIFO8(tx_fifo, SiFiveUARTState),
+ VMSTATE_TIMER_PTR(fifo_trigger_handle, SiFiveUARTState),
VMSTATE_END_OF_LIST()
},
};
-static void sifive_uart_class_init(ObjectClass *oc, void *data)
+static void sifive_uart_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
dc->realize = sifive_uart_realize;
+ dc->unrealize = sifive_uart_unrealize;
dc->vmsd = &vmstate_sifive_uart;
rc->phases.enter = sifive_uart_reset_enter;
rc->phases.hold = sifive_uart_reset_hold;
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 3e23d9c..fc8ea60 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -163,10 +163,9 @@ void spapr_vty_create(SpaprVioBus *bus, Chardev *chardev)
qdev_realize_and_unref(dev, &bus->bus, &error_fatal);
}
-static Property spapr_vty_properties[] = {
+static const Property spapr_vty_properties[] = {
DEFINE_SPAPR_PROPERTIES(SpaprVioVty, sdev),
DEFINE_PROP_CHR("chardev", SpaprVioVty, chardev),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_spapr_vty = {
@@ -183,7 +182,7 @@ static const VMStateDescription vmstate_spapr_vty = {
},
};
-static void spapr_vty_class_init(ObjectClass *klass, void *data)
+static void spapr_vty_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 8753afe..45c3064 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -30,17 +30,7 @@
#include "qemu/log.h"
#include "qemu/module.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)
+#include "trace.h"
static int stm32f2xx_usart_can_receive(void *opaque)
{
@@ -67,10 +57,11 @@ static void stm32f2xx_update_irq(STM32F2XXUsartState *s)
static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
{
STM32F2XXUsartState *s = opaque;
+ DeviceState *d = DEVICE(s);
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");
+ trace_stm32f2xx_usart_drop(d->id);
return;
}
@@ -79,7 +70,7 @@ static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
stm32f2xx_update_irq(s);
- DB_PRINT("Receiving: %c\n", s->usart_dr);
+ trace_stm32f2xx_usart_receive(d->id, *buf);
}
static void stm32f2xx_usart_reset(DeviceState *dev)
@@ -101,49 +92,55 @@ 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);
+ DeviceState *d = DEVICE(s);
+ uint64_t retvalue = 0;
switch (addr) {
case USART_SR:
retvalue = s->usart_sr;
qemu_chr_fe_accept_input(&s->chr);
- return retvalue;
+ break;
case USART_DR:
- DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
retvalue = s->usart_dr & 0x3FF;
s->usart_sr &= ~USART_SR_RXNE;
qemu_chr_fe_accept_input(&s->chr);
stm32f2xx_update_irq(s);
- return retvalue;
+ break;
case USART_BRR:
- return s->usart_brr;
+ retvalue = s->usart_brr;
+ break;
case USART_CR1:
- return s->usart_cr1;
+ retvalue = s->usart_cr1;
+ break;
case USART_CR2:
- return s->usart_cr2;
+ retvalue = s->usart_cr2;
+ break;
case USART_CR3:
- return s->usart_cr3;
+ retvalue = s->usart_cr3;
+ break;
case USART_GTPR:
- return s->usart_gtpr;
+ retvalue = s->usart_gtpr;
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
return 0;
}
- return 0;
+ trace_stm32f2xx_usart_read(d->id, size, addr, retvalue);
+
+ return retvalue;
}
static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
uint64_t val64, unsigned int size)
{
STM32F2XXUsartState *s = opaque;
+ DeviceState *d = DEVICE(s);
uint32_t value = val64;
unsigned char ch;
- DB_PRINT("Write 0x%" PRIx32 ", 0x%"HWADDR_PRIx"\n", value, addr);
+ trace_stm32f2xx_usart_write(d->id, size, addr, val64);
switch (addr) {
case USART_SR:
@@ -199,9 +196,8 @@ static const MemoryRegionOps stm32f2xx_usart_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static Property stm32f2xx_usart_properties[] = {
+static const Property stm32f2xx_usart_properties[] = {
DEFINE_PROP_CHR("chardev", STM32F2XXUsartState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void stm32f2xx_usart_init(Object *obj)
@@ -224,11 +220,11 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
s, NULL, true);
}
-static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
+static void stm32f2xx_usart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_usart_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_usart_reset);
device_class_set_props(dc, stm32f2xx_usart_properties);
dc->realize = stm32f2xx_usart_realize;
}
diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
index fc5dcac..afbe4ba 100644
--- a/hw/char/stm32l4x5_usart.c
+++ b/hw/char/stm32l4x5_usart.c
@@ -154,6 +154,21 @@ REG32(RDR, 0x24)
REG32(TDR, 0x28)
FIELD(TDR, TDR, 0, 9)
+static void stm32l4x5_update_isr(Stm32l4x5UsartBaseState *s)
+{
+ if (s->cr1 & R_CR1_TE_MASK) {
+ s->isr |= R_ISR_TEACK_MASK;
+ } else {
+ s->isr &= ~R_ISR_TEACK_MASK;
+ }
+
+ if (s->cr1 & R_CR1_RE_MASK) {
+ s->isr |= R_ISR_REACK_MASK;
+ } else {
+ s->isr &= ~R_ISR_REACK_MASK;
+ }
+}
+
static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s)
{
if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) ||
@@ -456,6 +471,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
case A_CR1:
s->cr1 = value;
stm32l4x5_update_params(s);
+ stm32l4x5_update_isr(s);
stm32l4x5_update_irq(s);
return;
case A_CR2:
@@ -518,9 +534,8 @@ static const MemoryRegionOps stm32l4x5_usart_base_ops = {
},
};
-static Property stm32l4x5_usart_base_properties[] = {
+static const Property stm32l4x5_usart_base_properties[] = {
DEFINE_PROP_CHR("chardev", Stm32l4x5UsartBaseState, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void stm32l4x5_usart_base_init(Object *obj)
@@ -579,7 +594,8 @@ static void stm32l4x5_usart_base_realize(DeviceState *dev, Error **errp)
s, NULL, true);
}
-static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data)
+static void stm32l4x5_usart_base_class_init(ObjectClass *klass,
+ const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -590,21 +606,21 @@ static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_stm32l4x5_usart_base;
}
-static void stm32l4x5_usart_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5_usart_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
subc->type = STM32L4x5_USART;
}
-static void stm32l4x5_uart_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5_uart_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
subc->type = STM32L4x5_UART;
}
-static void stm32l4x5_lpuart_class_init(ObjectClass *oc, void *data)
+static void stm32l4x5_lpuart_class_init(ObjectClass *oc, const void *data)
{
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c
index 82e85fa..d950c17 100644
--- a/hw/char/terminal3270.c
+++ b/hw/char/terminal3270.c
@@ -283,9 +283,8 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd)
return (retval <= 0) ? 0 : get_cds(t)->count;
}
-static Property terminal_properties[] = {
+static const Property terminal_properties[] = {
DEFINE_PROP_CHR("chardev", Terminal3270, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription terminal3270_vmstate = {
@@ -293,7 +292,7 @@ static const VMStateDescription terminal3270_vmstate = {
.unmigratable = 1,
};
-static void terminal_class_init(ObjectClass *klass, void *data)
+static void terminal_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_CLASS(klass);
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 8875758..05a3303 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -52,15 +52,21 @@ escc_sunkbd_event_out(int ch) "Translated keycode 0x%2.2x"
escc_kbd_command(int val) "Command %d"
escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=0x%01x"
+# imx_serial.c
+imx_serial_read(const char *chrname, uint64_t addr, uint64_t value) "%s:[0x%03" PRIu64 "] -> 0x%08" PRIx64
+imx_serial_write(const char *chrname, uint64_t addr, uint64_t value) "%s:[0x%03" PRIu64 "] <- 0x%08" PRIx64
+imx_serial_put_data(const char *chrname, uint32_t value) "%s: 0x%" PRIx32
+
# pl011.c
pl011_irq_state(int level) "irq state %d"
pl011_read(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s"
-pl011_read_fifo(int read_count) "FIFO read, read_count now %d"
+pl011_read_fifo(unsigned rx_fifo_used, size_t rx_fifo_depth) "RX FIFO read, used %u/%zu"
pl011_write(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s"
-pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d"
-pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d"
-pl011_put_fifo_full(void) "FIFO now full, RXFF set"
+pl011_can_receive(uint32_t lcr, unsigned rx_fifo_used, size_t rx_fifo_depth, unsigned rx_fifo_available) "LCR 0x%02x, RX FIFO used %u/%zu, can_receive %u chars"
+pl011_fifo_rx_put(uint32_t c, unsigned read_count, size_t rx_fifo_depth) "RX FIFO push char [0x%02x] %d/%zu depth used"
+pl011_fifo_rx_full(void) "RX FIFO now full, RXFF set"
pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
+pl011_receive(int size) "recv %d chars"
# cmsdk-apb-uart.c
cmsdk_apb_uart_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
@@ -125,3 +131,13 @@ xen_console_unrealize(unsigned int idx) "idx %u"
xen_console_realize(unsigned int idx, const char *chrdev) "idx %u chrdev %s"
xen_console_device_create(unsigned int idx) "idx %u"
xen_console_device_destroy(unsigned int idx) "idx %u"
+
+# stm32f2xx_usart.c
+stm32f2xx_usart_read(char *id, unsigned size, uint64_t ofs, uint64_t val) " %s size %d ofs 0x%02" PRIx64 " -> 0x%02" PRIx64
+stm32f2xx_usart_write(char *id, unsigned size, uint64_t ofs, uint64_t val) "%s size %d ofs 0x%02" PRIx64 " <- 0x%02" PRIx64
+stm32f2xx_usart_drop(char *id) " %s dropping the chars"
+stm32f2xx_usart_receive(char *id, uint8_t chr) " %s receiving '%c'"
+
+# riscv_htif.c
+htif_uart_write_to_host(uint8_t device, uint8_t cmd, uint64_t payload) "device: %u cmd: %02u payload: %016" PRIx64
+htif_uart_unknown_device_command(uint8_t device, uint8_t cmd, uint64_t payload) "device: %u cmd: %02u payload: %016" PRIx64
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index dbe0b28..0932a35 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -261,7 +261,7 @@ static void virtconsole_unrealize(DeviceState *dev)
}
}
-static void virtconsole_class_init(ObjectClass *klass, void *data)
+static void virtconsole_class_init(ObjectClass *klass, const void *data)
{
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
@@ -274,12 +274,11 @@ static const TypeInfo virtconsole_info = {
.class_init = virtconsole_class_init,
};
-static Property virtserialport_properties[] = {
+static const Property virtserialport_properties[] = {
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtserialport_class_init(ObjectClass *klass, void *data)
+static void virtserialport_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 2094d21..673c50f 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -622,7 +622,7 @@ static void guest_reset(VirtIOSerial *vser)
}
}
-static void set_status(VirtIODevice *vdev, uint8_t status)
+static int set_status(VirtIODevice *vdev, uint8_t status)
{
VirtIOSerial *vser;
VirtIOSerialPort *port;
@@ -650,6 +650,7 @@ static void set_status(VirtIODevice *vdev, uint8_t status)
vsc->enable_backend(port, vdev->vm_running);
}
}
+ return 0;
}
static void vser_reset(VirtIODevice *vdev)
@@ -835,13 +836,12 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
-static Property virtser_props[] = {
+static const Property virtser_props[] = {
DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
- DEFINE_PROP_END_OF_LIST()
};
-static void virtser_bus_class_init(ObjectClass *klass, void *data)
+static void virtser_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
k->print_dev = virtser_bus_dev_print;
@@ -1093,7 +1093,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
QLIST_INSERT_HEAD(&vserdevices.devices, vser, next);
}
-static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
+static void virtio_serial_port_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
@@ -1153,15 +1153,14 @@ static const VMStateDescription vmstate_virtio_console = {
},
};
-static Property virtio_serial_properties[] = {
+static const Property virtio_serial_properties[] = {
DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports,
31),
DEFINE_PROP_BIT64("emergency-write", VirtIOSerial, host_features,
VIRTIO_CONSOLE_F_EMERG_WRITE, true),
- DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_serial_class_init(ObjectClass *klass, void *data)
+static void virtio_serial_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
@@ -1190,7 +1189,7 @@ static const TypeInfo virtio_device_info = {
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOSerial),
.class_init = virtio_serial_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 683c92a..9c34a55 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -25,7 +25,7 @@
#include <termios.h>
#include "qapi/error.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "chardev/char-fe.h"
#include "hw/xen/xen-backend.h"
#include "hw/xen/xen-bus-helper.h"
@@ -367,28 +367,28 @@ static char *xen_console_get_name(XenDevice *xendev, Error **errp)
if (con->dev == -1) {
XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
- char fe_path[XENSTORE_ABS_PATH_MAX + 1];
int idx = (xen_mode == XEN_EMULATE) ? 0 : 1;
+ Error *local_err = NULL;
char *value;
/* Theoretically we could go up to INT_MAX here but that's overkill */
while (idx < 100) {
if (!idx) {
- snprintf(fe_path, sizeof(fe_path),
- "/local/domain/%u/console", xendev->frontend_id);
+ value = xs_node_read(xenbus->xsh, XBT_NULL, NULL, &local_err,
+ "/local/domain/%u/console",
+ xendev->frontend_id);
} else {
- snprintf(fe_path, sizeof(fe_path),
- "/local/domain/%u/device/console/%u",
- xendev->frontend_id, idx);
+ value = xs_node_read(xenbus->xsh, XBT_NULL, NULL, &local_err,
+ "/local/domain/%u/device/console/%u",
+ xendev->frontend_id, idx);
}
- value = qemu_xen_xs_read(xenbus->xsh, XBT_NULL, fe_path, NULL);
if (!value) {
if (errno == ENOENT) {
con->dev = idx;
+ error_free(local_err);
goto found;
}
- error_setg(errp, "cannot read %s: %s", fe_path,
- strerror(errno));
+ error_propagate(errp, local_err);
return NULL;
}
free(value);
@@ -487,13 +487,12 @@ static char *xen_console_get_frontend_path(XenDevice *xendev, Error **errp)
}
-static Property xen_console_properties[] = {
+static const Property xen_console_properties[] = {
DEFINE_PROP_CHR("chardev", XenConsole, chr),
DEFINE_PROP_INT32("idx", XenConsole, dev, -1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void xen_console_class_init(ObjectClass *class, void *data)
+static void xen_console_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
@@ -551,7 +550,8 @@ static void xen_console_device_create(XenBackendInstance *backend,
goto fail;
}
- if (xs_node_scanf(xsh, XBT_NULL, fe, "type", errp, "%ms", &type) != 1) {
+ type = xs_node_read(xsh, XBT_NULL, NULL, errp, "%s/%s", fe, "type");
+ if (!type) {
error_prepend(errp, "failed to read console device type: ");
goto fail;
}
@@ -569,7 +569,8 @@ static void xen_console_device_create(XenBackendInstance *backend,
snprintf(label, sizeof(label), "xencons%ld", number);
- if (xs_node_scanf(xsh, XBT_NULL, fe, "output", NULL, "%ms", &output) == 1) {
+ output = xs_node_read(xsh, XBT_NULL, NULL, errp, "%s/%s", fe, "output");
+ if (output) {
/*
* FIXME: sure we want to support implicit
* muxed monitors here?
@@ -580,19 +581,27 @@ static void xen_console_device_create(XenBackendInstance *backend,
output);
goto fail;
}
- } else if (number) {
- cd = serial_hd(number);
- if (!cd) {
- error_prepend(errp, "console: No serial device #%ld found: ",
- number);
- goto fail;
- }
+ } else if (errno != ENOENT) {
+ error_prepend(errp, "console: No valid chardev found: ");
+ goto fail;
} else {
- /* No 'output' node on primary console: use null. */
- cd = qemu_chr_new(label, "null", NULL);
- if (!cd) {
- error_setg(errp, "console: failed to create null device");
- goto fail;
+ error_free(*errp);
+ *errp = NULL;
+
+ if (number) {
+ cd = serial_hd(number);
+ if (!cd) {
+ error_setg(errp, "console: No serial device #%ld found",
+ number);
+ goto fail;
+ }
+ } else {
+ /* No 'output' node on primary console: use null. */
+ cd = qemu_chr_new(label, "null", NULL);
+ if (!cd) {
+ error_setg(errp, "console: failed to create null device");
+ goto fail;
+ }
}
}
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index 180bb97..8008171 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qapi/error.h"
#include "hw/char/xilinx_uartlite.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
@@ -57,6 +58,7 @@
struct XilinxUARTLite {
SysBusDevice parent_obj;
+ EndianMode model_endianness;
MemoryRegion mmio;
CharBackend chr;
qemu_irq irq;
@@ -166,19 +168,22 @@ uart_write(void *opaque, hwaddr addr,
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 const MemoryRegionOps uart_ops[2] = {
+ [0 ... 1] = {
+ .read = uart_read,
+ .write = uart_write,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+ },
+ [0].endianness = DEVICE_LITTLE_ENDIAN,
+ [1].endianness = DEVICE_BIG_ENDIAN,
};
-static Property xilinx_uartlite_properties[] = {
+static const Property xilinx_uartlite_properties[] = {
+ DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XilinxUARTLite, model_endianness),
DEFINE_PROP_CHR("chardev", XilinxUARTLite, chr),
- DEFINE_PROP_END_OF_LIST(),
};
static void uart_rx(void *opaque, const uint8_t *buf, int size)
@@ -215,6 +220,15 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
{
XilinxUARTLite *s = XILINX_UARTLITE(dev);
+ if (s->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
+ error_setg(errp, TYPE_XILINX_UARTLITE " property 'endianness'"
+ " must be set to 'big' or 'little'");
+ return;
+ }
+
+ memory_region_init_io(&s->mmio, OBJECT(dev),
+ &uart_ops[s->model_endianness == ENDIAN_MODE_BIG],
+ s, "xlnx.xps-uartlite", R_MAX * 4);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
uart_event, NULL, s, NULL, true);
}
@@ -224,17 +238,14 @@ 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)
+static void xilinx_uartlite_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xilinx_uartlite_reset;
+ device_class_set_legacy_reset(dc, xilinx_uartlite_reset);
dc->realize = xilinx_uartlite_realize;
device_class_set_props(dc, xilinx_uartlite_properties);
}