Statistics
| Branch: | Revision:

root / hw / char / serial-pci.c @ f53f81e0

History | View | Annotate | Download (8.5 kB)

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