| Submitter | Gerd Hoffmann |
|---|---|
| Date | Oct. 15, 2012, 8:06 a.m. |
| Message ID | <1350288417-24350-5-git-send-email-kraxel@redhat.com> |
| Download | mbox | patch |
| Permalink | /patch/191487/ |
| State | New |
| Headers | show |
Comments
Gerd Hoffmann <kraxel@redhat.com> writes: > Add multiport serial card implementation, with two variants, > one featuring two and one featuring four ports. > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > docs/qemupciserial.inf | 2 + > hw/serial-pci.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 159 insertions(+), 0 deletions(-) > > diff --git a/docs/qemupciserial.inf b/docs/qemupciserial.inf > index c7cea99..3474310 100644 > --- a/docs/qemupciserial.inf > +++ b/docs/qemupciserial.inf > @@ -11,6 +11,8 @@ > ; (Com+Lpt)" from the list. Click "Have a disk". Select this file. > ; Procedure may vary a bit depending on the windows version. > > +; FIXME: This file covers the single port version only. > + > [Version] > Signature="$CHICAGO$" > Class=Ports > diff --git a/hw/serial-pci.c b/hw/serial-pci.c > index 17247a8..c89e8b0 100644 > --- a/hw/serial-pci.c > +++ b/hw/serial-pci.c > @@ -28,6 +28,14 @@ > * pci region 0 is a io bar, 8 bytes long, with the 16550 uart mapped to it. > * interrupt is wired to pin A. > * > + * pci-serial-4x spec: > + * pci region 0 is a io bar, with four 16550 uarts mapped after each other, > + * the first at offset 0, second at 8, third at 16 and fourth at 24. > + * interrupt is wired to pin A. > + * > + * pci-serial-2x spec: > + * same as pci-serial-4x but with two uarts only. > + * I know I neglected to respond to your previous note in this thread, but I'd prefer this be made a file in docs/. That way, you can look in docs and discover all of the QEMU-invented devices. Having to troll through hw/*.c to find which new devices were added is a bit painful. This is important for people looking to implement guest support for QEMU. Regards, Anthony Liguori > * [root@fedora ~]# lspci -vnse > * 00:0e.0 0700: 1b36:0002 (rev 01) (prog-if 00 [8250]) > * Subsystem: 1af4:1100 > @@ -40,11 +48,23 @@ > #include "serial.h" > #include "pci.h" > > +#define PCI_SERIAL_MAX_PORTS 4 > + > typedef struct PCISerialState { > PCIDevice dev; > SerialState state; > } PCISerialState; > > +typedef struct PCIMultiSerialState { > + PCIDevice dev; > + MemoryRegion iobar; > + uint32_t ports; > + char *name[PCI_SERIAL_MAX_PORTS]; > + SerialState state[PCI_SERIAL_MAX_PORTS]; > + uint32_t level[PCI_SERIAL_MAX_PORTS]; > + qemu_irq *irqs; > +} PCIMultiSerialState; > + > static int serial_pci_init(PCIDevice *dev) > { > PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); > @@ -61,6 +81,56 @@ static int serial_pci_init(PCIDevice *dev) > return 0; > } > > +static void multi_serial_irq_mux(void *opaque, int n, int level) > +{ > + PCIMultiSerialState *pci = opaque; > + int i, pending = 0; > + > + pci->level[n] = level; > + for (i = 0; i < pci->ports; i++) { > + if (pci->level[i]) { > + pending = 1; > + } > + } > + qemu_set_irq(pci->dev.irq[0], pending); > +} > + > +static int multi_serial_pci_init(PCIDevice *dev) > +{ > + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); > + PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); > + SerialState *s; > + int i; > + > + switch (pc->device_id) { > + case 0x0003: > + pci->ports = 2; > + break; > + case 0x0004: > + pci->ports = 4; > + break; > + } > + assert(pci->ports > 0); > + assert(pci->ports <= PCI_SERIAL_MAX_PORTS); > + > + pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; > + memory_region_init(&pci->iobar, "multiserial", 8 * pci->ports); > + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); > + pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, > + pci->ports); > + > + for (i = 0; i < pci->ports; i++) { > + s = pci->state + i; > + s->baudbase = 115200; > + serial_init_core(s); > + s->irq = pci->irqs[i]; > + pci->name[i] = g_strdup_printf("uart #%d", i+1); > + memory_region_init_io(&s->io, &serial_io_ops, s, pci->name[i], 8); > + memory_region_add_subregion(&pci->iobar, 8 * i, &s->io); > + } > + return 0; > +} > + > static void serial_pci_exit(PCIDevice *dev) > { > PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); > @@ -70,6 +140,22 @@ static void serial_pci_exit(PCIDevice *dev) > memory_region_destroy(&s->io); > } > > +static void multi_serial_pci_exit(PCIDevice *dev) > +{ > + PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); > + SerialState *s; > + int i; > + > + for (i = 0; i < pci->ports; i++) { > + s = pci->state + i; > + serial_exit_core(s); > + memory_region_destroy(&s->io); > + g_free(pci->name[i]); > + } > + memory_region_destroy(&pci->iobar); > + qemu_free_irqs(pci->irqs); > +} > + > static const VMStateDescription vmstate_pci_serial = { > .name = "pci-serial", > .version_id = 1, > @@ -81,11 +167,38 @@ static const VMStateDescription vmstate_pci_serial = { > } > }; > > +static const VMStateDescription vmstate_pci_multi_serial = { > + .name = "pci-serial-multi", > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState), > + VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS, > + 0, vmstate_serial, SerialState), > + VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS), > + VMSTATE_END_OF_LIST() > + } > +}; > + > static Property serial_pci_properties[] = { > DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), > DEFINE_PROP_END_OF_LIST(), > }; > > +static Property multi_2x_serial_pci_properties[] = { > + DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), > + DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static Property multi_4x_serial_pci_properties[] = { > + DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), > + DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), > + DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr), > + DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > static void serial_pci_class_initfn(ObjectClass *klass, void *data) > { > DeviceClass *dc = DEVICE_CLASS(klass); > @@ -100,6 +213,34 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data) > dc->props = serial_pci_properties; > } > > +static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); > + pc->init = multi_serial_pci_init; > + pc->exit = multi_serial_pci_exit; > + pc->vendor_id = 0x1b36; /* Red Hat */ > + pc->device_id = 0x0003; > + pc->revision = 1; > + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; > + dc->vmsd = &vmstate_pci_multi_serial; > + dc->props = multi_2x_serial_pci_properties; > +} > + > +static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); > + pc->init = multi_serial_pci_init; > + pc->exit = multi_serial_pci_exit; > + pc->vendor_id = 0x1b36; /* Red Hat */ > + pc->device_id = 0x0004; > + pc->revision = 1; > + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; > + dc->vmsd = &vmstate_pci_multi_serial; > + dc->props = multi_4x_serial_pci_properties; > +} > + > static TypeInfo serial_pci_info = { > .name = "pci-serial", > .parent = TYPE_PCI_DEVICE, > @@ -107,9 +248,25 @@ static TypeInfo serial_pci_info = { > .class_init = serial_pci_class_initfn, > }; > > +static TypeInfo multi_2x_serial_pci_info = { > + .name = "pci-serial-2x", > + .parent = TYPE_PCI_DEVICE, > + .instance_size = sizeof(PCIMultiSerialState), > + .class_init = multi_2x_serial_pci_class_initfn, > +}; > + > +static TypeInfo multi_4x_serial_pci_info = { > + .name = "pci-serial-4x", > + .parent = TYPE_PCI_DEVICE, > + .instance_size = sizeof(PCIMultiSerialState), > + .class_init = multi_4x_serial_pci_class_initfn, > +}; > + > static void serial_pci_register_types(void) > { > type_register_static(&serial_pci_info); > + type_register_static(&multi_2x_serial_pci_info); > + type_register_static(&multi_4x_serial_pci_info); > } > > type_init(serial_pci_register_types) > -- > 1.7.1
Patch
diff --git a/docs/qemupciserial.inf b/docs/qemupciserial.inf index c7cea99..3474310 100644 --- a/docs/qemupciserial.inf +++ b/docs/qemupciserial.inf @@ -11,6 +11,8 @@ ; (Com+Lpt)" from the list. Click "Have a disk". Select this file. ; Procedure may vary a bit depending on the windows version. +; FIXME: This file covers the single port version only. + [Version] Signature="$CHICAGO$" Class=Ports diff --git a/hw/serial-pci.c b/hw/serial-pci.c index 17247a8..c89e8b0 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -28,6 +28,14 @@ * pci region 0 is a io bar, 8 bytes long, with the 16550 uart mapped to it. * interrupt is wired to pin A. * + * pci-serial-4x spec: + * pci region 0 is a io bar, with four 16550 uarts mapped after each other, + * the first at offset 0, second at 8, third at 16 and fourth at 24. + * interrupt is wired to pin A. + * + * pci-serial-2x spec: + * same as pci-serial-4x but with two uarts only. + * * [root@fedora ~]# lspci -vnse * 00:0e.0 0700: 1b36:0002 (rev 01) (prog-if 00 [8250]) * Subsystem: 1af4:1100 @@ -40,11 +48,23 @@ #include "serial.h" #include "pci.h" +#define PCI_SERIAL_MAX_PORTS 4 + typedef struct PCISerialState { PCIDevice dev; SerialState state; } PCISerialState; +typedef struct PCIMultiSerialState { + PCIDevice dev; + MemoryRegion iobar; + uint32_t ports; + char *name[PCI_SERIAL_MAX_PORTS]; + SerialState state[PCI_SERIAL_MAX_PORTS]; + uint32_t level[PCI_SERIAL_MAX_PORTS]; + qemu_irq *irqs; +} PCIMultiSerialState; + static int serial_pci_init(PCIDevice *dev) { PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); @@ -61,6 +81,56 @@ static int serial_pci_init(PCIDevice *dev) return 0; } +static void multi_serial_irq_mux(void *opaque, int n, int level) +{ + PCIMultiSerialState *pci = opaque; + int i, pending = 0; + + pci->level[n] = level; + for (i = 0; i < pci->ports; i++) { + if (pci->level[i]) { + pending = 1; + } + } + qemu_set_irq(pci->dev.irq[0], pending); +} + +static int multi_serial_pci_init(PCIDevice *dev) +{ + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); + SerialState *s; + int i; + + switch (pc->device_id) { + case 0x0003: + pci->ports = 2; + break; + case 0x0004: + pci->ports = 4; + break; + } + assert(pci->ports > 0); + assert(pci->ports <= PCI_SERIAL_MAX_PORTS); + + pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + memory_region_init(&pci->iobar, "multiserial", 8 * pci->ports); + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); + pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, + pci->ports); + + for (i = 0; i < pci->ports; i++) { + s = pci->state + i; + s->baudbase = 115200; + serial_init_core(s); + s->irq = pci->irqs[i]; + pci->name[i] = g_strdup_printf("uart #%d", i+1); + memory_region_init_io(&s->io, &serial_io_ops, s, pci->name[i], 8); + memory_region_add_subregion(&pci->iobar, 8 * i, &s->io); + } + return 0; +} + static void serial_pci_exit(PCIDevice *dev) { PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); @@ -70,6 +140,22 @@ static void serial_pci_exit(PCIDevice *dev) memory_region_destroy(&s->io); } +static void multi_serial_pci_exit(PCIDevice *dev) +{ + PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); + SerialState *s; + int i; + + for (i = 0; i < pci->ports; i++) { + s = pci->state + i; + serial_exit_core(s); + memory_region_destroy(&s->io); + g_free(pci->name[i]); + } + memory_region_destroy(&pci->iobar); + qemu_free_irqs(pci->irqs); +} + static const VMStateDescription vmstate_pci_serial = { .name = "pci-serial", .version_id = 1, @@ -81,11 +167,38 @@ static const VMStateDescription vmstate_pci_serial = { } }; +static const VMStateDescription vmstate_pci_multi_serial = { + .name = "pci-serial-multi", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState), + VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS, + 0, vmstate_serial, SerialState), + VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS), + VMSTATE_END_OF_LIST() + } +}; + static Property serial_pci_properties[] = { DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), DEFINE_PROP_END_OF_LIST(), }; +static Property multi_2x_serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), + DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static Property multi_4x_serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), + DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), + DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr), + DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void serial_pci_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -100,6 +213,34 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data) dc->props = serial_pci_properties; } +static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); + pc->init = multi_serial_pci_init; + pc->exit = multi_serial_pci_exit; + pc->vendor_id = 0x1b36; /* Red Hat */ + pc->device_id = 0x0003; + pc->revision = 1; + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd = &vmstate_pci_multi_serial; + dc->props = multi_2x_serial_pci_properties; +} + +static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); + pc->init = multi_serial_pci_init; + pc->exit = multi_serial_pci_exit; + pc->vendor_id = 0x1b36; /* Red Hat */ + pc->device_id = 0x0004; + pc->revision = 1; + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd = &vmstate_pci_multi_serial; + dc->props = multi_4x_serial_pci_properties; +} + static TypeInfo serial_pci_info = { .name = "pci-serial", .parent = TYPE_PCI_DEVICE, @@ -107,9 +248,25 @@ static TypeInfo serial_pci_info = { .class_init = serial_pci_class_initfn, }; +static TypeInfo multi_2x_serial_pci_info = { + .name = "pci-serial-2x", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIMultiSerialState), + .class_init = multi_2x_serial_pci_class_initfn, +}; + +static TypeInfo multi_4x_serial_pci_info = { + .name = "pci-serial-4x", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIMultiSerialState), + .class_init = multi_4x_serial_pci_class_initfn, +}; + static void serial_pci_register_types(void) { type_register_static(&serial_pci_info); + type_register_static(&multi_2x_serial_pci_info); + type_register_static(&multi_4x_serial_pci_info); } type_init(serial_pci_register_types)
Add multiport serial card implementation, with two variants, one featuring two and one featuring four ports. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- docs/qemupciserial.inf | 2 + hw/serial-pci.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 0 deletions(-)