qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

serial-pci-multi.c (7550B)


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