1 /* 2 * QEMU 16550A UART emulation 3 * 4 * Copyright (c) 2003-2004 Fabrice Bellard 5 * Copyright (c) 2008 Citrix Systems, Inc. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 26 /* see docs/specs/pci-serial.txt */ 27 28 #include "hw/char/serial.h" 29 #include "hw/pci/pci.h" 30 31 #define PCI_SERIAL_MAX_PORTS 4 32 33 typedef struct PCISerialState { 34 PCIDevice dev; 35 SerialState state; 36 uint8_t prog_if; 37 } PCISerialState; 38 39 typedef struct PCIMultiSerialState { 40 PCIDevice dev; 41 MemoryRegion iobar; 42 uint32_t ports; 43 char *name[PCI_SERIAL_MAX_PORTS]; 44 SerialState state[PCI_SERIAL_MAX_PORTS]; 45 uint32_t level[PCI_SERIAL_MAX_PORTS]; 46 qemu_irq *irqs; 47 uint8_t prog_if; 48 } PCIMultiSerialState; 49 50 static void multi_serial_pci_exit(PCIDevice *dev); 51 52 static void serial_pci_realize(PCIDevice *dev, Error **errp) 53 { 54 PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); 55 SerialState *s = &pci->state; 56 Error *err = NULL; 57 58 s->baudbase = 115200; 59 serial_realize_core(s, &err); 60 if (err != NULL) { 61 error_propagate(errp, err); 62 return; 63 } 64 65 pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; 66 pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; 67 s->irq = pci_allocate_irq(&pci->dev); 68 69 memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8); 70 pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); 71 } 72 73 static void multi_serial_irq_mux(void *opaque, int n, int level) 74 { 75 PCIMultiSerialState *pci = opaque; 76 int i, pending = 0; 77 78 pci->level[n] = level; 79 for (i = 0; i < pci->ports; i++) { 80 if (pci->level[i]) { 81 pending = 1; 82 } 83 } 84 pci_set_irq(&pci->dev, pending); 85 } 86 87 static void multi_serial_pci_realize(PCIDevice *dev, Error **errp) 88 { 89 PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); 90 PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); 91 SerialState *s; 92 Error *err = NULL; 93 int i, nr_ports = 0; 94 95 switch (pc->device_id) { 96 case 0x0003: 97 nr_ports = 2; 98 break; 99 case 0x0004: 100 nr_ports = 4; 101 break; 102 } 103 assert(nr_ports > 0); 104 assert(nr_ports <= PCI_SERIAL_MAX_PORTS); 105 106 pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; 107 pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; 108 memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nr_ports); 109 pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); 110 pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, 111 nr_ports); 112 113 for (i = 0; i < nr_ports; i++) { 114 s = pci->state + i; 115 s->baudbase = 115200; 116 serial_realize_core(s, &err); 117 if (err != NULL) { 118 error_propagate(errp, err); 119 multi_serial_pci_exit(dev); 120 return; 121 } 122 s->irq = pci->irqs[i]; 123 pci->name[i] = g_strdup_printf("uart #%d", i+1); 124 memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, 125 pci->name[i], 8); 126 memory_region_add_subregion(&pci->iobar, 8 * i, &s->io); 127 pci->ports++; 128 } 129 } 130 131 static void serial_pci_exit(PCIDevice *dev) 132 { 133 PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); 134 SerialState *s = &pci->state; 135 136 serial_exit_core(s); 137 qemu_free_irq(s->irq); 138 } 139 140 static void multi_serial_pci_exit(PCIDevice *dev) 141 { 142 PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); 143 SerialState *s; 144 int i; 145 146 for (i = 0; i < pci->ports; i++) { 147 s = pci->state + i; 148 serial_exit_core(s); 149 memory_region_del_subregion(&pci->iobar, &s->io); 150 g_free(pci->name[i]); 151 } 152 qemu_free_irqs(pci->irqs, pci->ports); 153 } 154 155 static const VMStateDescription vmstate_pci_serial = { 156 .name = "pci-serial", 157 .version_id = 1, 158 .minimum_version_id = 1, 159 .fields = (VMStateField[]) { 160 VMSTATE_PCI_DEVICE(dev, PCISerialState), 161 VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState), 162 VMSTATE_END_OF_LIST() 163 } 164 }; 165 166 static const VMStateDescription vmstate_pci_multi_serial = { 167 .name = "pci-serial-multi", 168 .version_id = 1, 169 .minimum_version_id = 1, 170 .fields = (VMStateField[]) { 171 VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState), 172 VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS, 173 0, vmstate_serial, SerialState), 174 VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS), 175 VMSTATE_END_OF_LIST() 176 } 177 }; 178 179 static Property serial_pci_properties[] = { 180 DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), 181 DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02), 182 DEFINE_PROP_END_OF_LIST(), 183 }; 184 185 static Property multi_2x_serial_pci_properties[] = { 186 DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), 187 DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), 188 DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), 189 DEFINE_PROP_END_OF_LIST(), 190 }; 191 192 static Property multi_4x_serial_pci_properties[] = { 193 DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), 194 DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), 195 DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr), 196 DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr), 197 DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), 198 DEFINE_PROP_END_OF_LIST(), 199 }; 200 201 static void serial_pci_class_initfn(ObjectClass *klass, void *data) 202 { 203 DeviceClass *dc = DEVICE_CLASS(klass); 204 PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); 205 pc->realize = serial_pci_realize; 206 pc->exit = serial_pci_exit; 207 pc->vendor_id = PCI_VENDOR_ID_REDHAT; 208 pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL; 209 pc->revision = 1; 210 pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; 211 dc->vmsd = &vmstate_pci_serial; 212 dc->props = serial_pci_properties; 213 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 214 } 215 216 static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) 217 { 218 DeviceClass *dc = DEVICE_CLASS(klass); 219 PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); 220 pc->realize = multi_serial_pci_realize; 221 pc->exit = multi_serial_pci_exit; 222 pc->vendor_id = PCI_VENDOR_ID_REDHAT; 223 pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2; 224 pc->revision = 1; 225 pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; 226 dc->vmsd = &vmstate_pci_multi_serial; 227 dc->props = multi_2x_serial_pci_properties; 228 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 229 } 230 231 static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) 232 { 233 DeviceClass *dc = DEVICE_CLASS(klass); 234 PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); 235 pc->realize = multi_serial_pci_realize; 236 pc->exit = multi_serial_pci_exit; 237 pc->vendor_id = PCI_VENDOR_ID_REDHAT; 238 pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4; 239 pc->revision = 1; 240 pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; 241 dc->vmsd = &vmstate_pci_multi_serial; 242 dc->props = multi_4x_serial_pci_properties; 243 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 244 } 245 246 static const TypeInfo serial_pci_info = { 247 .name = "pci-serial", 248 .parent = TYPE_PCI_DEVICE, 249 .instance_size = sizeof(PCISerialState), 250 .class_init = serial_pci_class_initfn, 251 }; 252 253 static const TypeInfo multi_2x_serial_pci_info = { 254 .name = "pci-serial-2x", 255 .parent = TYPE_PCI_DEVICE, 256 .instance_size = sizeof(PCIMultiSerialState), 257 .class_init = multi_2x_serial_pci_class_initfn, 258 }; 259 260 static const TypeInfo multi_4x_serial_pci_info = { 261 .name = "pci-serial-4x", 262 .parent = TYPE_PCI_DEVICE, 263 .instance_size = sizeof(PCIMultiSerialState), 264 .class_init = multi_4x_serial_pci_class_initfn, 265 }; 266 267 static void serial_pci_register_types(void) 268 { 269 type_register_static(&serial_pci_info); 270 type_register_static(&multi_2x_serial_pci_info); 271 type_register_static(&multi_4x_serial_pci_info); 272 } 273 274 type_init(serial_pci_register_types) 275