xref: /openbmc/qemu/hw/isa/isa-bus.c (revision 90ce6e26)
1 /*
2  * isa bus support for qdev.
3  *
4  * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "qemu/osdep.h"
20 #include "hw/hw.h"
21 #include "monitor/monitor.h"
22 #include "hw/sysbus.h"
23 #include "sysemu/sysemu.h"
24 #include "hw/isa/isa.h"
25 #include "hw/i386/pc.h"
26 
27 static ISABus *isabus;
28 
29 static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
30 static char *isabus_get_fw_dev_path(DeviceState *dev);
31 
32 static void isa_bus_class_init(ObjectClass *klass, void *data)
33 {
34     BusClass *k = BUS_CLASS(klass);
35 
36     k->print_dev = isabus_dev_print;
37     k->get_fw_dev_path = isabus_get_fw_dev_path;
38 }
39 
40 static const TypeInfo isa_dma_info = {
41     .name = TYPE_ISADMA,
42     .parent = TYPE_INTERFACE,
43     .class_size = sizeof(IsaDmaClass),
44 };
45 
46 static const TypeInfo isa_bus_info = {
47     .name = TYPE_ISA_BUS,
48     .parent = TYPE_BUS,
49     .instance_size = sizeof(ISABus),
50     .class_init = isa_bus_class_init,
51 };
52 
53 ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space,
54                     MemoryRegion *address_space_io, Error **errp)
55 {
56     if (isabus) {
57         error_setg(errp, "Can't create a second ISA bus");
58         return NULL;
59     }
60     if (!dev) {
61         dev = qdev_create(NULL, "isabus-bridge");
62         qdev_init_nofail(dev);
63     }
64 
65     isabus = ISA_BUS(qbus_create(TYPE_ISA_BUS, dev, NULL));
66     isabus->address_space = address_space;
67     isabus->address_space_io = address_space_io;
68     return isabus;
69 }
70 
71 void isa_bus_irqs(ISABus *bus, qemu_irq *irqs)
72 {
73     bus->irqs = irqs;
74 }
75 
76 /*
77  * isa_get_irq() returns the corresponding qemu_irq entry for the i8259.
78  *
79  * This function is only for special cases such as the 'ferr', and
80  * temporary use for normal devices until they are converted to qdev.
81  */
82 qemu_irq isa_get_irq(ISADevice *dev, int isairq)
83 {
84     assert(!dev || ISA_BUS(qdev_get_parent_bus(DEVICE(dev))) == isabus);
85     if (isairq < 0 || isairq > 15) {
86         hw_error("isa irq %d invalid", isairq);
87     }
88     return isabus->irqs[isairq];
89 }
90 
91 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
92 {
93     assert(dev->nirqs < ARRAY_SIZE(dev->isairq));
94     dev->isairq[dev->nirqs] = isairq;
95     *p = isa_get_irq(dev, isairq);
96     dev->nirqs++;
97 }
98 
99 void isa_bus_dma(ISABus *bus, IsaDma *dma8, IsaDma *dma16)
100 {
101     assert(bus && dma8 && dma16);
102     assert(!bus->dma[0] && !bus->dma[1]);
103     bus->dma[0] = dma8;
104     bus->dma[1] = dma16;
105 }
106 
107 IsaDma *isa_get_dma(ISABus *bus, int nchan)
108 {
109     assert(bus);
110     return bus->dma[nchan > 3 ? 1 : 0];
111 }
112 
113 static inline void isa_init_ioport(ISADevice *dev, uint16_t ioport)
114 {
115     if (dev && (dev->ioport_id == 0 || ioport < dev->ioport_id)) {
116         dev->ioport_id = ioport;
117     }
118 }
119 
120 void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
121 {
122     memory_region_add_subregion(isabus->address_space_io, start, io);
123     isa_init_ioport(dev, start);
124 }
125 
126 void isa_register_portio_list(ISADevice *dev, uint16_t start,
127                               const MemoryRegionPortio *pio_start,
128                               void *opaque, const char *name)
129 {
130     PortioList piolist;
131 
132     /* START is how we should treat DEV, regardless of the actual
133        contents of the portio array.  This is how the old code
134        actually handled e.g. the FDC device.  */
135     isa_init_ioport(dev, start);
136 
137     /* FIXME: the device should store created PortioList in its state.  Note
138        that DEV can be NULL here and that single device can register several
139        portio lists.  Current implementation is leaking memory allocated
140        in portio_list_init.  The leak is not critical because it happens only
141        at initialization time.  */
142     portio_list_init(&piolist, OBJECT(dev), pio_start, opaque, name);
143     portio_list_add(&piolist, isabus->address_space_io, start);
144 }
145 
146 static void isa_device_init(Object *obj)
147 {
148     ISADevice *dev = ISA_DEVICE(obj);
149 
150     dev->isairq[0] = -1;
151     dev->isairq[1] = -1;
152 }
153 
154 ISADevice *isa_create(ISABus *bus, const char *name)
155 {
156     DeviceState *dev;
157 
158     dev = qdev_create(BUS(bus), name);
159     return ISA_DEVICE(dev);
160 }
161 
162 ISADevice *isa_try_create(ISABus *bus, const char *name)
163 {
164     DeviceState *dev;
165 
166     dev = qdev_try_create(BUS(bus), name);
167     return ISA_DEVICE(dev);
168 }
169 
170 ISADevice *isa_create_simple(ISABus *bus, const char *name)
171 {
172     ISADevice *dev;
173 
174     dev = isa_create(bus, name);
175     qdev_init_nofail(DEVICE(dev));
176     return dev;
177 }
178 
179 ISADevice *isa_vga_init(ISABus *bus)
180 {
181     switch (vga_interface_type) {
182     case VGA_CIRRUS:
183         return isa_create_simple(bus, "isa-cirrus-vga");
184     case VGA_QXL:
185         fprintf(stderr, "%s: qxl: no PCI bus\n", __func__);
186         return NULL;
187     case VGA_STD:
188         return isa_create_simple(bus, "isa-vga");
189     case VGA_VMWARE:
190         fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__);
191         return NULL;
192     case VGA_VIRTIO:
193         fprintf(stderr, "%s: virtio-vga: no PCI bus\n", __func__);
194         return NULL;
195     case VGA_NONE:
196     default:
197         return NULL;
198     }
199 }
200 
201 static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
202 {
203     ISADevice *d = ISA_DEVICE(dev);
204 
205     if (d->isairq[1] != -1) {
206         monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
207                        d->isairq[0], d->isairq[1]);
208     } else if (d->isairq[0] != -1) {
209         monitor_printf(mon, "%*sisa irq %d\n", indent, "",
210                        d->isairq[0]);
211     }
212 }
213 
214 static void isabus_bridge_class_init(ObjectClass *klass, void *data)
215 {
216     DeviceClass *dc = DEVICE_CLASS(klass);
217 
218     dc->fw_name = "isa";
219 }
220 
221 static const TypeInfo isabus_bridge_info = {
222     .name          = "isabus-bridge",
223     .parent        = TYPE_SYS_BUS_DEVICE,
224     .instance_size = sizeof(SysBusDevice),
225     .class_init    = isabus_bridge_class_init,
226 };
227 
228 static void isa_device_class_init(ObjectClass *klass, void *data)
229 {
230     DeviceClass *k = DEVICE_CLASS(klass);
231     k->bus_type = TYPE_ISA_BUS;
232 }
233 
234 static const TypeInfo isa_device_type_info = {
235     .name = TYPE_ISA_DEVICE,
236     .parent = TYPE_DEVICE,
237     .instance_size = sizeof(ISADevice),
238     .instance_init = isa_device_init,
239     .abstract = true,
240     .class_size = sizeof(ISADeviceClass),
241     .class_init = isa_device_class_init,
242 };
243 
244 static void isabus_register_types(void)
245 {
246     type_register_static(&isa_dma_info);
247     type_register_static(&isa_bus_info);
248     type_register_static(&isabus_bridge_info);
249     type_register_static(&isa_device_type_info);
250 }
251 
252 static char *isabus_get_fw_dev_path(DeviceState *dev)
253 {
254     ISADevice *d = ISA_DEVICE(dev);
255     char path[40];
256     int off;
257 
258     off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
259     if (d->ioport_id) {
260         snprintf(path + off, sizeof(path) - off, "@%04x", d->ioport_id);
261     }
262 
263     return g_strdup(path);
264 }
265 
266 MemoryRegion *isa_address_space(ISADevice *dev)
267 {
268     if (dev) {
269         return isa_bus_from_device(dev)->address_space;
270     }
271 
272     return isabus->address_space;
273 }
274 
275 MemoryRegion *isa_address_space_io(ISADevice *dev)
276 {
277     if (dev) {
278         return isa_bus_from_device(dev)->address_space_io;
279     }
280 
281     return isabus->address_space_io;
282 }
283 
284 type_init(isabus_register_types)
285 
286 static void parallel_init(ISABus *bus, int index, CharDriverState *chr)
287 {
288     DeviceState *dev;
289     ISADevice *isadev;
290 
291     isadev = isa_create(bus, "isa-parallel");
292     dev = DEVICE(isadev);
293     qdev_prop_set_uint32(dev, "index", index);
294     qdev_prop_set_chr(dev, "chardev", chr);
295     qdev_init_nofail(dev);
296 }
297 
298 void parallel_hds_isa_init(ISABus *bus, int n)
299 {
300     int i;
301 
302     assert(n <= MAX_PARALLEL_PORTS);
303 
304     for (i = 0; i < n; i++) {
305         if (parallel_hds[i]) {
306             parallel_init(bus, i, parallel_hds[i]);
307         }
308     }
309 }
310