xref: /openbmc/qemu/hw/isa/isa-bus.c (revision ed7f5f1d)
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_bus_info = {
41     .name = TYPE_ISA_BUS,
42     .parent = TYPE_BUS,
43     .instance_size = sizeof(ISABus),
44     .class_init = isa_bus_class_init,
45 };
46 
47 ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space,
48                     MemoryRegion *address_space_io, Error **errp)
49 {
50     if (isabus) {
51         error_setg(errp, "Can't create a second ISA bus");
52         return NULL;
53     }
54     if (!dev) {
55         dev = qdev_create(NULL, "isabus-bridge");
56         qdev_init_nofail(dev);
57     }
58 
59     isabus = ISA_BUS(qbus_create(TYPE_ISA_BUS, dev, NULL));
60     isabus->address_space = address_space;
61     isabus->address_space_io = address_space_io;
62     return isabus;
63 }
64 
65 void isa_bus_irqs(ISABus *bus, qemu_irq *irqs)
66 {
67     bus->irqs = irqs;
68 }
69 
70 /*
71  * isa_get_irq() returns the corresponding qemu_irq entry for the i8259.
72  *
73  * This function is only for special cases such as the 'ferr', and
74  * temporary use for normal devices until they are converted to qdev.
75  */
76 qemu_irq isa_get_irq(ISADevice *dev, int isairq)
77 {
78     assert(!dev || ISA_BUS(qdev_get_parent_bus(DEVICE(dev))) == isabus);
79     if (isairq < 0 || isairq > 15) {
80         hw_error("isa irq %d invalid", isairq);
81     }
82     return isabus->irqs[isairq];
83 }
84 
85 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
86 {
87     assert(dev->nirqs < ARRAY_SIZE(dev->isairq));
88     dev->isairq[dev->nirqs] = isairq;
89     *p = isa_get_irq(dev, isairq);
90     dev->nirqs++;
91 }
92 
93 static inline void isa_init_ioport(ISADevice *dev, uint16_t ioport)
94 {
95     if (dev && (dev->ioport_id == 0 || ioport < dev->ioport_id)) {
96         dev->ioport_id = ioport;
97     }
98 }
99 
100 void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
101 {
102     memory_region_add_subregion(isabus->address_space_io, start, io);
103     isa_init_ioport(dev, start);
104 }
105 
106 void isa_register_portio_list(ISADevice *dev, uint16_t start,
107                               const MemoryRegionPortio *pio_start,
108                               void *opaque, const char *name)
109 {
110     PortioList piolist;
111 
112     /* START is how we should treat DEV, regardless of the actual
113        contents of the portio array.  This is how the old code
114        actually handled e.g. the FDC device.  */
115     isa_init_ioport(dev, start);
116 
117     /* FIXME: the device should store created PortioList in its state.  Note
118        that DEV can be NULL here and that single device can register several
119        portio lists.  Current implementation is leaking memory allocated
120        in portio_list_init.  The leak is not critical because it happens only
121        at initialization time.  */
122     portio_list_init(&piolist, OBJECT(dev), pio_start, opaque, name);
123     portio_list_add(&piolist, isabus->address_space_io, start);
124 }
125 
126 static void isa_device_init(Object *obj)
127 {
128     ISADevice *dev = ISA_DEVICE(obj);
129 
130     dev->isairq[0] = -1;
131     dev->isairq[1] = -1;
132 }
133 
134 ISADevice *isa_create(ISABus *bus, const char *name)
135 {
136     DeviceState *dev;
137 
138     dev = qdev_create(BUS(bus), name);
139     return ISA_DEVICE(dev);
140 }
141 
142 ISADevice *isa_try_create(ISABus *bus, const char *name)
143 {
144     DeviceState *dev;
145 
146     dev = qdev_try_create(BUS(bus), name);
147     return ISA_DEVICE(dev);
148 }
149 
150 ISADevice *isa_create_simple(ISABus *bus, const char *name)
151 {
152     ISADevice *dev;
153 
154     dev = isa_create(bus, name);
155     qdev_init_nofail(DEVICE(dev));
156     return dev;
157 }
158 
159 ISADevice *isa_vga_init(ISABus *bus)
160 {
161     switch (vga_interface_type) {
162     case VGA_CIRRUS:
163         return isa_create_simple(bus, "isa-cirrus-vga");
164     case VGA_QXL:
165         fprintf(stderr, "%s: qxl: no PCI bus\n", __func__);
166         return NULL;
167     case VGA_STD:
168         return isa_create_simple(bus, "isa-vga");
169     case VGA_VMWARE:
170         fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__);
171         return NULL;
172     case VGA_VIRTIO:
173         fprintf(stderr, "%s: virtio-vga: no PCI bus\n", __func__);
174         return NULL;
175     case VGA_NONE:
176     default:
177         return NULL;
178     }
179 }
180 
181 static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
182 {
183     ISADevice *d = ISA_DEVICE(dev);
184 
185     if (d->isairq[1] != -1) {
186         monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
187                        d->isairq[0], d->isairq[1]);
188     } else if (d->isairq[0] != -1) {
189         monitor_printf(mon, "%*sisa irq %d\n", indent, "",
190                        d->isairq[0]);
191     }
192 }
193 
194 static void isabus_bridge_class_init(ObjectClass *klass, void *data)
195 {
196     DeviceClass *dc = DEVICE_CLASS(klass);
197 
198     dc->fw_name = "isa";
199 }
200 
201 static const TypeInfo isabus_bridge_info = {
202     .name          = "isabus-bridge",
203     .parent        = TYPE_SYS_BUS_DEVICE,
204     .instance_size = sizeof(SysBusDevice),
205     .class_init    = isabus_bridge_class_init,
206 };
207 
208 static void isa_device_class_init(ObjectClass *klass, void *data)
209 {
210     DeviceClass *k = DEVICE_CLASS(klass);
211     k->bus_type = TYPE_ISA_BUS;
212 }
213 
214 static const TypeInfo isa_device_type_info = {
215     .name = TYPE_ISA_DEVICE,
216     .parent = TYPE_DEVICE,
217     .instance_size = sizeof(ISADevice),
218     .instance_init = isa_device_init,
219     .abstract = true,
220     .class_size = sizeof(ISADeviceClass),
221     .class_init = isa_device_class_init,
222 };
223 
224 static void isabus_register_types(void)
225 {
226     type_register_static(&isa_bus_info);
227     type_register_static(&isabus_bridge_info);
228     type_register_static(&isa_device_type_info);
229 }
230 
231 static char *isabus_get_fw_dev_path(DeviceState *dev)
232 {
233     ISADevice *d = ISA_DEVICE(dev);
234     char path[40];
235     int off;
236 
237     off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
238     if (d->ioport_id) {
239         snprintf(path + off, sizeof(path) - off, "@%04x", d->ioport_id);
240     }
241 
242     return g_strdup(path);
243 }
244 
245 MemoryRegion *isa_address_space(ISADevice *dev)
246 {
247     if (dev) {
248         return isa_bus_from_device(dev)->address_space;
249     }
250 
251     return isabus->address_space;
252 }
253 
254 MemoryRegion *isa_address_space_io(ISADevice *dev)
255 {
256     if (dev) {
257         return isa_bus_from_device(dev)->address_space_io;
258     }
259 
260     return isabus->address_space_io;
261 }
262 
263 type_init(isabus_register_types)
264 
265 static void parallel_init(ISABus *bus, int index, CharDriverState *chr)
266 {
267     DeviceState *dev;
268     ISADevice *isadev;
269 
270     isadev = isa_create(bus, "isa-parallel");
271     dev = DEVICE(isadev);
272     qdev_prop_set_uint32(dev, "index", index);
273     qdev_prop_set_chr(dev, "chardev", chr);
274     qdev_init_nofail(dev);
275 }
276 
277 void parallel_hds_isa_init(ISABus *bus, int n)
278 {
279     int i;
280 
281     assert(n <= MAX_PARALLEL_PORTS);
282 
283     for (i = 0; i < n; i++) {
284         if (parallel_hds[i]) {
285             parallel_init(bus, i, parallel_hds[i]);
286         }
287     }
288 }
289