diff options
Diffstat (limited to 'hw/char/serial.c')
-rw-r--r-- | hw/char/serial.c | 186 |
1 files changed, 152 insertions, 34 deletions
diff --git a/hw/char/serial.c b/hw/char/serial.c index b4aa250950..6c327183c7 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -34,6 +34,7 @@ #include "sysemu/runstate.h" #include "qemu/error-report.h" #include "trace.h" +#include "hw/qdev-properties.h" //#define DEBUG_SERIAL @@ -933,8 +934,10 @@ static int serial_be_change(void *opaque) return 0; } -void serial_realize_core(SerialState *s, Error **errp) +static void serial_realize(DeviceState *dev, Error **errp) { + SerialState *s = SERIAL(dev); + s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s); s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s); @@ -947,8 +950,10 @@ void serial_realize_core(SerialState *s, Error **errp) serial_reset(s); } -void serial_exit_core(SerialState *s) +static void serial_unrealize(DeviceState *dev, Error **errp) { + SerialState *s = SERIAL(dev); + qemu_chr_fe_deinit(&s->chr, false); timer_del(s->modem_status_poll); @@ -980,40 +985,89 @@ const MemoryRegionOps serial_io_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -SerialState *serial_init(int base, qemu_irq irq, int baudbase, - Chardev *chr, MemoryRegion *system_io) +static void serial_io_realize(DeviceState *dev, Error **errp) { - SerialState *s; + SerialIO *sio = SERIAL_IO(dev); + SerialState *s = &sio->serial; + Error *local_err = NULL; + + object_property_set_bool(OBJECT(s), true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + memory_region_init_io(&s->io, NULL, &serial_io_ops, s, "serial", 8); + sysbus_init_mmio(SYS_BUS_DEVICE(sio), &s->io); + sysbus_init_irq(SYS_BUS_DEVICE(sio), &s->irq); +} - s = g_malloc0(sizeof(SerialState)); +static void serial_io_class_init(ObjectClass *klass, void* data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); - s->irq = irq; - s->baudbase = baudbase; - qemu_chr_fe_init(&s->chr, chr, &error_abort); - serial_realize_core(s, &error_fatal); + dc->realize = serial_io_realize; + /* No dc->vmsd: class has no migratable state */ +} - vmstate_register(NULL, base, &vmstate_serial, s); +static void serial_io_instance_init(Object *o) +{ + SerialIO *sio = SERIAL_IO(o); - memory_region_init_io(&s->io, NULL, &serial_io_ops, s, "serial", 8); - memory_region_add_subregion(system_io, base, &s->io); + object_initialize_child(o, "serial", &sio->serial, sizeof(sio->serial), + TYPE_SERIAL, &error_abort, NULL); - return s; + qdev_alias_all_properties(DEVICE(&sio->serial), o); } + +static const TypeInfo serial_io_info = { + .name = TYPE_SERIAL_IO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SerialIO), + .instance_init = serial_io_instance_init, + .class_init = serial_io_class_init, +}; + +static Property serial_properties[] = { + DEFINE_PROP_CHR("chardev", SerialState, chr), + DEFINE_PROP_UINT32("baudbase", SerialState, baudbase, 115200), + DEFINE_PROP_END_OF_LIST(), +}; + +static void serial_class_init(ObjectClass *klass, void* data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + /* internal device for serialio/serialmm, not user-creatable */ + dc->user_creatable = false; + dc->realize = serial_realize; + dc->unrealize = serial_unrealize; + dc->vmsd = &vmstate_serial; + dc->props = serial_properties; +} + +static const TypeInfo serial_info = { + .name = TYPE_SERIAL, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SerialState), + .class_init = serial_class_init, +}; + /* Memory mapped interface */ static uint64_t serial_mm_read(void *opaque, hwaddr addr, unsigned size) { - SerialState *s = opaque; - return serial_ioport_read(s, addr >> s->it_shift, 1); + 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) { - SerialState *s = opaque; + SerialMM *s = SERIAL_MM(opaque); value &= 255; - serial_ioport_write(s, addr >> s->it_shift, value, 1); + serial_ioport_write(&s->serial, addr >> s->regshift, value, 1); } static const MemoryRegionOps serial_mm_ops[3] = { @@ -1040,25 +1094,89 @@ static const MemoryRegionOps serial_mm_ops[3] = { }, }; -SerialState *serial_mm_init(MemoryRegion *address_space, - hwaddr base, int it_shift, - qemu_irq irq, int baudbase, - Chardev *chr, enum device_endian end) +static void serial_mm_realize(DeviceState *dev, Error **errp) { - SerialState *s; + SerialMM *smm = SERIAL_MM(dev); + SerialState *s = &smm->serial; + Error *local_err = NULL; - s = g_malloc0(sizeof(SerialState)); + object_property_set_bool(OBJECT(s), true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + memory_region_init_io(&s->io, NULL, &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); +} + +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_create(NULL, TYPE_SERIAL_MM)); + MemoryRegion *mr; - s->it_shift = it_shift; - s->irq = irq; - s->baudbase = baudbase; - qemu_chr_fe_init(&s->chr, chr, &error_abort); + 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); + qdev_init_nofail(DEVICE(smm)); - serial_realize_core(s, &error_fatal); - vmstate_register(NULL, base, &vmstate_serial, s); + 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); - memory_region_init_io(&s->io, NULL, &serial_mm_ops[end], s, - "serial", 8 << it_shift); - memory_region_add_subregion(address_space, base, &s->io); - return s; + return smm; } + +static void serial_mm_instance_init(Object *o) +{ + SerialMM *smm = SERIAL_MM(o); + + object_initialize_child(o, "serial", &smm->serial, sizeof(smm->serial), + TYPE_SERIAL, &error_abort, NULL); + + 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); + + dc->props = serial_mm_properties; + dc->realize = serial_mm_realize; +} + +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), + .class_init = serial_mm_class_init, +}; + +static void serial_register_types(void) +{ + type_register_static(&serial_info); + type_register_static(&serial_io_info); + type_register_static(&serial_mm_info); +} + +type_init(serial_register_types) |