From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:46937) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THbH0-0001ng-1i for qemu-devel@nongnu.org; Fri, 28 Sep 2012 10:10:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1THbGt-0008Cd-VF for qemu-devel@nongnu.org; Fri, 28 Sep 2012 10:10:33 -0400 Received: from plane.gmane.org ([80.91.229.3]:36290) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1THbGt-0008An-LD for qemu-devel@nongnu.org; Fri, 28 Sep 2012 10:10:27 -0400 Received: from list by plane.gmane.org with local (Exim 4.69) (envelope-from ) id 1THbGp-00055O-ED for qemu-devel@nongnu.org; Fri, 28 Sep 2012 16:10:23 +0200 Received: from 93-34-169-1.ip50.fastwebnet.it ([93.34.169.1]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Fri, 28 Sep 2012 16:10:23 +0200 Received: from pbonzini by 93-34-169-1.ip50.fastwebnet.it with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Fri, 28 Sep 2012 16:10:23 +0200 From: Paolo Bonzini Date: Fri, 28 Sep 2012 16:08:35 +0200 Message-ID: References: <1348661674-16722-1-git-send-email-kraxel@redhat.com> <1348661674-16722-5-git-send-email-kraxel@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit In-Reply-To: <1348661674-16722-5-git-send-email-kraxel@redhat.com> Subject: Re: [Qemu-devel] [PATCH v2 4/4] serial: add 2x + 4x pci variant List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 > --- > 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) >