Il 26/09/2012 14:14, Gerd Hoffmann ha scritto: > Add multiport serial card implementation, with two variants, > one featuring two and one featuring four ports. > > Signed-off-by: Gerd Hoffmann <kra...@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 905a929..911eaa6 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. > +
Looks like this is what you want for Windows: http://msdn.microsoft.com/en-us/library/windows/hardware/ff542737%28v=vs.85%29.aspx It's a special "splitter" driver that makes a fake bus with multiple devices on it, out of a single device Paolo > [Version] > Signature="$CHICAGO$" > Class=Ports > diff --git a/hw/serial-pci.c b/hw/serial-pci.c > index 88b71f5..54bd4eb 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; > + qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); > + 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) >