Add "enabled" qdev property, and implement enable and disable callbacks.
Incorporate ISA VMState as well as I/O base and IRQ as subsection, and implement pre_load and post_load callbacks. Cc: Gerd Hoffmann <kra...@redhat.com> Cc: Markus Armbruster <arm...@redhat.com> Cc: Juan Quintela <quint...@redhat.com> Signed-off-by: Andreas Färber <andreas.faer...@web.de> --- hw/serial.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 86 insertions(+), 5 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index 0ee61dd..7a63b7d 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -161,6 +161,8 @@ typedef struct ISASerialState { uint32_t iobase; uint32_t isairq; SerialState state; + uint32_t initial_iobase; + uint32_t initial_isairq; } ISASerialState; static void serial_receive1(void *opaque, const uint8_t *buf, int size); @@ -752,6 +754,31 @@ void serial_set_frequency(SerialState *s, uint32_t frequency) serial_update_parameters(s); } +static int serial_isa_enable(ISADevice *dev) +{ + ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev); + SerialState *s = &isa->state; + + isa_init_irq(dev, &s->irq, isa->isairq); + + register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s); + register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s); + isa_init_ioport_range(dev, isa->iobase, 8); + return 0; +} + +static int serial_isa_disable(ISADevice *dev) +{ + ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev); + SerialState *s = &isa->state; + + isa_uninit_irq(dev, &s->irq, isa->isairq); + + isa_discard_ioport_range(dev, isa->iobase, 8); + isa_unassign_ioport(isa->iobase, 8); + return 0; +} + static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; @@ -771,25 +798,76 @@ static int serial_isa_initfn(ISADevice *dev) isa->isairq = isa_serial_irq[isa->index]; index++; + isa->initial_iobase = isa->iobase; + isa->initial_isairq = isa->isairq; + s->baudbase = 115200; - isa_init_irq(dev, &s->irq, isa->isairq); serial_init_core(s); qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3); - register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s); - register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s); - isa_init_ioport_range(dev, isa->iobase, 8); + if (dev->enabled) { + serial_isa_enable(dev); + } return 0; } +static int serial_isa_pre_load(void *opaque) +{ + ISASerialState *s = opaque; + + isa_set_state(&s->dev, false); + return 0; +} + +static int serial_isa_post_load(void *opaque, int version_id) +{ + ISASerialState *s = opaque; + ISADevice *dev = &s->dev; + + if (dev->enabled) { + serial_isa_enable(dev); + } + return 0; +} + +static bool serial_isa_config_needed(void *opaque) +{ + ISASerialState *s = opaque; + + return isa_vmstate_needed(&s->dev) || + s->initial_iobase != s->iobase || + s->initial_isairq != s->isairq; +} + +static const VMStateDescription vmstate_isa_serial_isaconfig = { + .name = "serial/isa-config", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField []) { + VMSTATE_ISA_DEVICE(dev, ISASerialState), + VMSTATE_UINT32(iobase, ISASerialState), + VMSTATE_UINT32(isairq, ISASerialState), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_isa_serial = { .name = "serial", .version_id = 3, .minimum_version_id = 2, + .pre_load = serial_isa_pre_load, + .post_load = serial_isa_post_load, .fields = (VMStateField []) { VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState), VMSTATE_END_OF_LIST() - } + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_isa_serial_isaconfig, + .needed = serial_isa_config_needed, + }, { + } + }, }; SerialState *serial_init(int base, qemu_irq irq, int baudbase, @@ -962,11 +1040,14 @@ static ISADeviceInfo serial_isa_info = { .qdev.size = sizeof(ISASerialState), .qdev.vmsd = &vmstate_isa_serial, .init = serial_isa_initfn, + .enable = serial_isa_enable, + .disable = serial_isa_disable, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("index", ISASerialState, index, -1), DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), + DEFINE_PROP_BOOL("enabled", ISASerialState, dev.enabled, true), DEFINE_PROP_END_OF_LIST(), }, }; -- 1.7.5.3