Statistics
| Branch: | Revision:

root / hw / char / serial-pci.c @ 49ab747f

History | View | Annotate | Download (7.9 kB)

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
} PCISerialState;
37

    
38
typedef struct PCIMultiSerialState {
39
    PCIDevice    dev;
40
    MemoryRegion iobar;
41
    uint32_t     ports;
42
    char         *name[PCI_SERIAL_MAX_PORTS];
43
    SerialState  state[PCI_SERIAL_MAX_PORTS];
44
    uint32_t     level[PCI_SERIAL_MAX_PORTS];
45
    qemu_irq     *irqs;
46
} PCIMultiSerialState;
47

    
48
static int serial_pci_init(PCIDevice *dev)
49
{
50
    PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
51
    SerialState *s = &pci->state;
52

    
53
    s->baudbase = 115200;
54
    serial_init_core(s);
55

    
56
    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
57
    s->irq = pci->dev.irq[0];
58

    
59
    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
60
    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
61
    return 0;
62
}
63

    
64
static void multi_serial_irq_mux(void *opaque, int n, int level)
65
{
66
    PCIMultiSerialState *pci = opaque;
67
    int i, pending = 0;
68

    
69
    pci->level[n] = level;
70
    for (i = 0; i < pci->ports; i++) {
71
        if (pci->level[i]) {
72
            pending = 1;
73
        }
74
    }
75
    qemu_set_irq(pci->dev.irq[0], pending);
76
}
77

    
78
static int multi_serial_pci_init(PCIDevice *dev)
79
{
80
    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
81
    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
82
    SerialState *s;
83
    int i;
84

    
85
    switch (pc->device_id) {
86
    case 0x0003:
87
        pci->ports = 2;
88
        break;
89
    case 0x0004:
90
        pci->ports = 4;
91
        break;
92
    }
93
    assert(pci->ports > 0);
94
    assert(pci->ports <= PCI_SERIAL_MAX_PORTS);
95

    
96
    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
97
    memory_region_init(&pci->iobar, "multiserial", 8 * pci->ports);
98
    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
99
    pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
100
                                   pci->ports);
101

    
102
    for (i = 0; i < pci->ports; i++) {
103
        s = pci->state + i;
104
        s->baudbase = 115200;
105
        serial_init_core(s);
106
        s->irq = pci->irqs[i];
107
        pci->name[i] = g_strdup_printf("uart #%d", i+1);
108
        memory_region_init_io(&s->io, &serial_io_ops, s, pci->name[i], 8);
109
        memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
110
    }
111
    return 0;
112
}
113

    
114
static void serial_pci_exit(PCIDevice *dev)
115
{
116
    PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
117
    SerialState *s = &pci->state;
118

    
119
    serial_exit_core(s);
120
    memory_region_destroy(&s->io);
121
}
122

    
123
static void multi_serial_pci_exit(PCIDevice *dev)
124
{
125
    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
126
    SerialState *s;
127
    int i;
128

    
129
    for (i = 0; i < pci->ports; i++) {
130
        s = pci->state + i;
131
        serial_exit_core(s);
132
        memory_region_destroy(&s->io);
133
        g_free(pci->name[i]);
134
    }
135
    memory_region_destroy(&pci->iobar);
136
    qemu_free_irqs(pci->irqs);
137
}
138

    
139
static const VMStateDescription vmstate_pci_serial = {
140
    .name = "pci-serial",
141
    .version_id = 1,
142
    .minimum_version_id = 1,
143
    .fields      = (VMStateField[]) {
144
        VMSTATE_PCI_DEVICE(dev, PCISerialState),
145
        VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState),
146
        VMSTATE_END_OF_LIST()
147
    }
148
};
149

    
150
static const VMStateDescription vmstate_pci_multi_serial = {
151
    .name = "pci-serial-multi",
152
    .version_id = 1,
153
    .minimum_version_id = 1,
154
    .fields      = (VMStateField[]) {
155
        VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState),
156
        VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS,
157
                             0, vmstate_serial, SerialState),
158
        VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS),
159
        VMSTATE_END_OF_LIST()
160
    }
161
};
162

    
163
static Property serial_pci_properties[] = {
164
    DEFINE_PROP_CHR("chardev",  PCISerialState, state.chr),
165
    DEFINE_PROP_END_OF_LIST(),
166
};
167

    
168
static Property multi_2x_serial_pci_properties[] = {
169
    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
170
    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
171
    DEFINE_PROP_END_OF_LIST(),
172
};
173

    
174
static Property multi_4x_serial_pci_properties[] = {
175
    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
176
    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
177
    DEFINE_PROP_CHR("chardev3",  PCIMultiSerialState, state[2].chr),
178
    DEFINE_PROP_CHR("chardev4",  PCIMultiSerialState, state[3].chr),
179
    DEFINE_PROP_END_OF_LIST(),
180
};
181

    
182
static void serial_pci_class_initfn(ObjectClass *klass, void *data)
183
{
184
    DeviceClass *dc = DEVICE_CLASS(klass);
185
    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
186
    pc->init = serial_pci_init;
187
    pc->exit = serial_pci_exit;
188
    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
189
    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL;
190
    pc->revision = 1;
191
    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
192
    dc->vmsd = &vmstate_pci_serial;
193
    dc->props = serial_pci_properties;
194
}
195

    
196
static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
197
{
198
    DeviceClass *dc = DEVICE_CLASS(klass);
199
    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
200
    pc->init = multi_serial_pci_init;
201
    pc->exit = multi_serial_pci_exit;
202
    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
203
    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2;
204
    pc->revision = 1;
205
    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
206
    dc->vmsd = &vmstate_pci_multi_serial;
207
    dc->props = multi_2x_serial_pci_properties;
208
}
209

    
210
static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
211
{
212
    DeviceClass *dc = DEVICE_CLASS(klass);
213
    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
214
    pc->init = multi_serial_pci_init;
215
    pc->exit = multi_serial_pci_exit;
216
    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
217
    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4;
218
    pc->revision = 1;
219
    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
220
    dc->vmsd = &vmstate_pci_multi_serial;
221
    dc->props = multi_4x_serial_pci_properties;
222
}
223

    
224
static const TypeInfo serial_pci_info = {
225
    .name          = "pci-serial",
226
    .parent        = TYPE_PCI_DEVICE,
227
    .instance_size = sizeof(PCISerialState),
228
    .class_init    = serial_pci_class_initfn,
229
};
230

    
231
static const TypeInfo multi_2x_serial_pci_info = {
232
    .name          = "pci-serial-2x",
233
    .parent        = TYPE_PCI_DEVICE,
234
    .instance_size = sizeof(PCIMultiSerialState),
235
    .class_init    = multi_2x_serial_pci_class_initfn,
236
};
237

    
238
static const TypeInfo multi_4x_serial_pci_info = {
239
    .name          = "pci-serial-4x",
240
    .parent        = TYPE_PCI_DEVICE,
241
    .instance_size = sizeof(PCIMultiSerialState),
242
    .class_init    = multi_4x_serial_pci_class_initfn,
243
};
244

    
245
static void serial_pci_register_types(void)
246
{
247
    type_register_static(&serial_pci_info);
248
    type_register_static(&multi_2x_serial_pci_info);
249
    type_register_static(&multi_4x_serial_pci_info);
250
}
251

    
252
type_init(serial_pci_register_types)