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