serial: add 2x + 4x pci variant
Add multiport serial card implementation, with two variants, one featuring two and one featuring four ports. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
		
							parent
							
								
									fe4f1793a6
								
							
						
					
					
						commit
						d66bbea4e0
					
				
							
								
								
									
										149
									
								
								hw/serial-pci.c
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								hw/serial-pci.c
									
									
									
									
									
								
							| @ -26,11 +26,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); | ||||
| @ -47,6 +59,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); | ||||
| @ -56,6 +118,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, | ||||
| @ -67,11 +145,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); | ||||
| @ -86,6 +191,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, | ||||
| @ -93,9 +226,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) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Gerd Hoffmann
						Gerd Hoffmann