xref: /openbmc/qemu/hw/isa/isa-bus.c (revision 46919512fcfec1e677733a16bc178898c524854f)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * isa bus support for qdev.
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
549ab747fSPaolo Bonzini  *
649ab747fSPaolo Bonzini  * This library is free software; you can redistribute it and/or
749ab747fSPaolo Bonzini  * modify it under the terms of the GNU Lesser General Public
849ab747fSPaolo Bonzini  * License as published by the Free Software Foundation; either
961f3c91aSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
1049ab747fSPaolo Bonzini  *
1149ab747fSPaolo Bonzini  * This library is distributed in the hope that it will be useful,
1249ab747fSPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1349ab747fSPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1449ab747fSPaolo Bonzini  * Lesser General Public License for more details.
1549ab747fSPaolo Bonzini  *
1649ab747fSPaolo Bonzini  * You should have received a copy of the GNU Lesser General Public
1749ab747fSPaolo Bonzini  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1849ab747fSPaolo Bonzini  */
190b8fa32fSMarkus Armbruster 
200430891cSPeter Maydell #include "qemu/osdep.h"
211081ed2cSAlistair Francis #include "qemu/error-report.h"
220b8fa32fSMarkus Armbruster #include "qemu/module.h"
23da34e65cSMarkus Armbruster #include "qapi/error.h"
2449ab747fSPaolo Bonzini #include "hw/sysbus.h"
2549ab747fSPaolo Bonzini #include "sysemu/sysemu.h"
2649ab747fSPaolo Bonzini #include "hw/isa/isa.h"
2749ab747fSPaolo Bonzini 
2849ab747fSPaolo Bonzini static ISABus *isabus;
2949ab747fSPaolo Bonzini 
3049ab747fSPaolo Bonzini static char *isabus_get_fw_dev_path(DeviceState *dev);
3149ab747fSPaolo Bonzini 
isa_bus_class_init(ObjectClass * klass,void * data)3249ab747fSPaolo Bonzini static void isa_bus_class_init(ObjectClass *klass, void *data)
3349ab747fSPaolo Bonzini {
3449ab747fSPaolo Bonzini     BusClass *k = BUS_CLASS(klass);
3549ab747fSPaolo Bonzini 
3649ab747fSPaolo Bonzini     k->get_fw_dev_path = isabus_get_fw_dev_path;
3749ab747fSPaolo Bonzini }
3849ab747fSPaolo Bonzini 
395484f30bSHervé Poussineau static const TypeInfo isa_dma_info = {
405484f30bSHervé Poussineau     .name = TYPE_ISADMA,
415484f30bSHervé Poussineau     .parent = TYPE_INTERFACE,
425484f30bSHervé Poussineau     .class_size = sizeof(IsaDmaClass),
435484f30bSHervé Poussineau };
445484f30bSHervé Poussineau 
4549ab747fSPaolo Bonzini static const TypeInfo isa_bus_info = {
4649ab747fSPaolo Bonzini     .name = TYPE_ISA_BUS,
4749ab747fSPaolo Bonzini     .parent = TYPE_BUS,
4849ab747fSPaolo Bonzini     .instance_size = sizeof(ISABus),
4949ab747fSPaolo Bonzini     .class_init = isa_bus_class_init,
5049ab747fSPaolo Bonzini };
5149ab747fSPaolo Bonzini 
isa_bus_new(DeviceState * dev,MemoryRegion * address_space,MemoryRegion * address_space_io,Error ** errp)52bb2ed009SHervé Poussineau ISABus *isa_bus_new(DeviceState *dev, MemoryRegion* address_space,
53d10e5432SMarkus Armbruster                     MemoryRegion *address_space_io, Error **errp)
5449ab747fSPaolo Bonzini {
55*675d717bSPhilippe Mathieu-Daudé     DeviceState *bridge = NULL;
56*675d717bSPhilippe Mathieu-Daudé 
5749ab747fSPaolo Bonzini     if (isabus) {
58d10e5432SMarkus Armbruster         error_setg(errp, "Can't create a second ISA bus");
5949ab747fSPaolo Bonzini         return NULL;
6049ab747fSPaolo Bonzini     }
61337a3e5cSGonglei     if (!dev) {
62*675d717bSPhilippe Mathieu-Daudé         bridge = qdev_new("isabus-bridge");
63*675d717bSPhilippe Mathieu-Daudé         dev = bridge;
6449ab747fSPaolo Bonzini     }
6549ab747fSPaolo Bonzini 
669388d170SPeter Maydell     isabus = ISA_BUS(qbus_new(TYPE_ISA_BUS, dev, NULL));
67bb2ed009SHervé Poussineau     isabus->address_space = address_space;
6849ab747fSPaolo Bonzini     isabus->address_space_io = address_space_io;
69*675d717bSPhilippe Mathieu-Daudé 
70*675d717bSPhilippe Mathieu-Daudé     if (bridge) {
71*675d717bSPhilippe Mathieu-Daudé         sysbus_realize_and_unref(SYS_BUS_DEVICE(bridge), &error_fatal);
72*675d717bSPhilippe Mathieu-Daudé     }
73*675d717bSPhilippe Mathieu-Daudé 
7449ab747fSPaolo Bonzini     return isabus;
7549ab747fSPaolo Bonzini }
7649ab747fSPaolo Bonzini 
isa_bus_register_input_irqs(ISABus * bus,qemu_irq * irqs_in)777067887eSPhilippe Mathieu-Daudé void isa_bus_register_input_irqs(ISABus *bus, qemu_irq *irqs_in)
7849ab747fSPaolo Bonzini {
797067887eSPhilippe Mathieu-Daudé     bus->irqs_in = irqs_in;
8049ab747fSPaolo Bonzini }
8149ab747fSPaolo Bonzini 
isa_bus_get_irq(ISABus * bus,unsigned irqnum)82d2fbec57SPhilippe Mathieu-Daudé qemu_irq isa_bus_get_irq(ISABus *bus, unsigned irqnum)
83d2fbec57SPhilippe Mathieu-Daudé {
84d2fbec57SPhilippe Mathieu-Daudé     assert(irqnum < ISA_NUM_IRQS);
85d2fbec57SPhilippe Mathieu-Daudé     assert(bus->irqs_in);
86d2fbec57SPhilippe Mathieu-Daudé     return bus->irqs_in[irqnum];
87d2fbec57SPhilippe Mathieu-Daudé }
88d2fbec57SPhilippe Mathieu-Daudé 
8949ab747fSPaolo Bonzini /*
907067887eSPhilippe Mathieu-Daudé  * isa_get_irq() returns the corresponding input qemu_irq entry for the i8259.
9149ab747fSPaolo Bonzini  *
9249ab747fSPaolo Bonzini  * This function is only for special cases such as the 'ferr', and
9349ab747fSPaolo Bonzini  * temporary use for normal devices until they are converted to qdev.
9449ab747fSPaolo Bonzini  */
isa_get_irq(ISADevice * dev,unsigned isairq)953c29e188SPaolo Bonzini qemu_irq isa_get_irq(ISADevice *dev, unsigned isairq)
9649ab747fSPaolo Bonzini {
972ae0e48dSAndreas Färber     assert(!dev || ISA_BUS(qdev_get_parent_bus(DEVICE(dev))) == isabus);
98d2fbec57SPhilippe Mathieu-Daudé     return isa_bus_get_irq(isabus, isairq);
9949ab747fSPaolo Bonzini }
10049ab747fSPaolo Bonzini 
isa_connect_gpio_out(ISADevice * isadev,int gpioirq,unsigned isairq)1013c29e188SPaolo Bonzini void isa_connect_gpio_out(ISADevice *isadev, int gpioirq, unsigned isairq)
10225026303SEfimov Vasily {
103d2fbec57SPhilippe Mathieu-Daudé     qemu_irq input_irq = isa_get_irq(isadev, isairq);
104d2fbec57SPhilippe Mathieu-Daudé     qdev_connect_gpio_out(DEVICE(isadev), gpioirq, input_irq);
10525026303SEfimov Vasily }
10625026303SEfimov Vasily 
isa_bus_dma(ISABus * bus,IsaDma * dma8,IsaDma * dma16)1075484f30bSHervé Poussineau void isa_bus_dma(ISABus *bus, IsaDma *dma8, IsaDma *dma16)
1085484f30bSHervé Poussineau {
1095484f30bSHervé Poussineau     assert(bus && dma8 && dma16);
1105484f30bSHervé Poussineau     assert(!bus->dma[0] && !bus->dma[1]);
1115484f30bSHervé Poussineau     bus->dma[0] = dma8;
1125484f30bSHervé Poussineau     bus->dma[1] = dma16;
1135484f30bSHervé Poussineau }
1145484f30bSHervé Poussineau 
isa_bus_get_dma(ISABus * bus,int nchan)115dc8d6cf2SPhilippe Mathieu-Daudé IsaDma *isa_bus_get_dma(ISABus *bus, int nchan)
1165484f30bSHervé Poussineau {
1175484f30bSHervé Poussineau     assert(bus);
1185484f30bSHervé Poussineau     return bus->dma[nchan > 3 ? 1 : 0];
1195484f30bSHervé Poussineau }
1205484f30bSHervé Poussineau 
isa_init_ioport(ISADevice * dev,uint16_t ioport)12149ab747fSPaolo Bonzini static inline void isa_init_ioport(ISADevice *dev, uint16_t ioport)
12249ab747fSPaolo Bonzini {
12349ab747fSPaolo Bonzini     if (dev && (dev->ioport_id == 0 || ioport < dev->ioport_id)) {
12449ab747fSPaolo Bonzini         dev->ioport_id = ioport;
12549ab747fSPaolo Bonzini     }
12649ab747fSPaolo Bonzini }
12749ab747fSPaolo Bonzini 
isa_register_ioport(ISADevice * dev,MemoryRegion * io,uint16_t start)12849ab747fSPaolo Bonzini void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
12949ab747fSPaolo Bonzini {
130e5bf2779SPhilippe Mathieu-Daudé     memory_region_add_subregion(isa_address_space_io(dev), start, io);
13149ab747fSPaolo Bonzini     isa_init_ioport(dev, start);
13249ab747fSPaolo Bonzini }
13349ab747fSPaolo Bonzini 
isa_register_portio_list(ISADevice * dev,PortioList * piolist,uint16_t start,const MemoryRegionPortio * pio_start,void * opaque,const char * name)1349405d87bSThomas Huth int isa_register_portio_list(ISADevice *dev,
135e305a165SMarc-André Lureau                              PortioList *piolist, uint16_t start,
13649ab747fSPaolo Bonzini                              const MemoryRegionPortio *pio_start,
13749ab747fSPaolo Bonzini                              void *opaque, const char *name)
13849ab747fSPaolo Bonzini {
139e305a165SMarc-André Lureau     assert(piolist && !piolist->owner);
14049ab747fSPaolo Bonzini 
1419405d87bSThomas Huth     if (!isabus) {
1429405d87bSThomas Huth         return -ENODEV;
1439405d87bSThomas Huth     }
1449405d87bSThomas Huth 
14549ab747fSPaolo Bonzini     /* START is how we should treat DEV, regardless of the actual
14649ab747fSPaolo Bonzini        contents of the portio array.  This is how the old code
14749ab747fSPaolo Bonzini        actually handled e.g. the FDC device.  */
14849ab747fSPaolo Bonzini     isa_init_ioport(dev, start);
14949ab747fSPaolo Bonzini 
150e305a165SMarc-André Lureau     portio_list_init(piolist, OBJECT(dev), pio_start, opaque, name);
151e5bf2779SPhilippe Mathieu-Daudé     portio_list_add(piolist, isa_address_space_io(dev), start);
1529405d87bSThomas Huth 
1539405d87bSThomas Huth     return 0;
15449ab747fSPaolo Bonzini }
15549ab747fSPaolo Bonzini 
isa_new(const char * name)1560fe9d901SMarkus Armbruster ISADevice *isa_new(const char *name)
1570fe9d901SMarkus Armbruster {
1580fe9d901SMarkus Armbruster     return ISA_DEVICE(qdev_new(name));
1590fe9d901SMarkus Armbruster }
1600fe9d901SMarkus Armbruster 
isa_try_new(const char * name)1610fe9d901SMarkus Armbruster ISADevice *isa_try_new(const char *name)
1620fe9d901SMarkus Armbruster {
1630fe9d901SMarkus Armbruster     return ISA_DEVICE(qdev_try_new(name));
1640fe9d901SMarkus Armbruster }
1650fe9d901SMarkus Armbruster 
isa_create_simple(ISABus * bus,const char * name)16649ab747fSPaolo Bonzini ISADevice *isa_create_simple(ISABus *bus, const char *name)
16749ab747fSPaolo Bonzini {
16849ab747fSPaolo Bonzini     ISADevice *dev;
16949ab747fSPaolo Bonzini 
17096927c74SMarkus Armbruster     dev = isa_new(name);
17196927c74SMarkus Armbruster     isa_realize_and_unref(dev, bus, &error_fatal);
17249ab747fSPaolo Bonzini     return dev;
17349ab747fSPaolo Bonzini }
17449ab747fSPaolo Bonzini 
isa_realize_and_unref(ISADevice * dev,ISABus * bus,Error ** errp)1750fe9d901SMarkus Armbruster bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp)
1760fe9d901SMarkus Armbruster {
1770fe9d901SMarkus Armbruster     return qdev_realize_and_unref(&dev->parent_obj, &bus->parent_obj, errp);
1780fe9d901SMarkus Armbruster }
1790fe9d901SMarkus Armbruster 
isa_bus_from_device(ISADevice * dev)18023c69bb8SPhilippe Mathieu-Daudé ISABus *isa_bus_from_device(ISADevice *dev)
18123c69bb8SPhilippe Mathieu-Daudé {
18223c69bb8SPhilippe Mathieu-Daudé     return ISA_BUS(qdev_get_parent_bus(DEVICE(dev)));
18323c69bb8SPhilippe Mathieu-Daudé }
18423c69bb8SPhilippe Mathieu-Daudé 
isa_vga_init(ISABus * bus)18549ab747fSPaolo Bonzini ISADevice *isa_vga_init(ISABus *bus)
18649ab747fSPaolo Bonzini {
187f9bcb2d6SGautam Agrawal     vga_interface_created = true;
18849ab747fSPaolo Bonzini     switch (vga_interface_type) {
18949ab747fSPaolo Bonzini     case VGA_CIRRUS:
19049ab747fSPaolo Bonzini         return isa_create_simple(bus, "isa-cirrus-vga");
19149ab747fSPaolo Bonzini     case VGA_QXL:
1921081ed2cSAlistair Francis         error_report("%s: qxl: no PCI bus", __func__);
19349ab747fSPaolo Bonzini         return NULL;
19449ab747fSPaolo Bonzini     case VGA_STD:
19549ab747fSPaolo Bonzini         return isa_create_simple(bus, "isa-vga");
19649ab747fSPaolo Bonzini     case VGA_VMWARE:
1971081ed2cSAlistair Francis         error_report("%s: vmware_vga: no PCI bus", __func__);
19849ab747fSPaolo Bonzini         return NULL;
199a94f0c5cSGerd Hoffmann     case VGA_VIRTIO:
2001081ed2cSAlistair Francis         error_report("%s: virtio-vga: no PCI bus", __func__);
201a94f0c5cSGerd Hoffmann         return NULL;
20249ab747fSPaolo Bonzini     case VGA_NONE:
20349ab747fSPaolo Bonzini     default:
20449ab747fSPaolo Bonzini         return NULL;
20549ab747fSPaolo Bonzini     }
20649ab747fSPaolo Bonzini }
20749ab747fSPaolo Bonzini 
isabus_bridge_class_init(ObjectClass * klass,void * data)20849ab747fSPaolo Bonzini static void isabus_bridge_class_init(ObjectClass *klass, void *data)
20949ab747fSPaolo Bonzini {
21049ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
21149ab747fSPaolo Bonzini 
2125658ffa3SThomas Huth     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
21349ab747fSPaolo Bonzini     dc->fw_name = "isa";
21449ab747fSPaolo Bonzini }
21549ab747fSPaolo Bonzini 
21649ab747fSPaolo Bonzini static const TypeInfo isabus_bridge_info = {
21749ab747fSPaolo Bonzini     .name          = "isabus-bridge",
21849ab747fSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
21949ab747fSPaolo Bonzini     .instance_size = sizeof(SysBusDevice),
22049ab747fSPaolo Bonzini     .class_init    = isabus_bridge_class_init,
22149ab747fSPaolo Bonzini };
22249ab747fSPaolo Bonzini 
isa_device_class_init(ObjectClass * klass,void * data)22349ab747fSPaolo Bonzini static void isa_device_class_init(ObjectClass *klass, void *data)
22449ab747fSPaolo Bonzini {
22549ab747fSPaolo Bonzini     DeviceClass *k = DEVICE_CLASS(klass);
22649ab747fSPaolo Bonzini     k->bus_type = TYPE_ISA_BUS;
22749ab747fSPaolo Bonzini }
22849ab747fSPaolo Bonzini 
22949ab747fSPaolo Bonzini static const TypeInfo isa_device_type_info = {
23049ab747fSPaolo Bonzini     .name = TYPE_ISA_DEVICE,
23149ab747fSPaolo Bonzini     .parent = TYPE_DEVICE,
23249ab747fSPaolo Bonzini     .instance_size = sizeof(ISADevice),
23349ab747fSPaolo Bonzini     .abstract = true,
23449ab747fSPaolo Bonzini     .class_init = isa_device_class_init,
23549ab747fSPaolo Bonzini };
23649ab747fSPaolo Bonzini 
isabus_register_types(void)23749ab747fSPaolo Bonzini static void isabus_register_types(void)
23849ab747fSPaolo Bonzini {
2395484f30bSHervé Poussineau     type_register_static(&isa_dma_info);
24049ab747fSPaolo Bonzini     type_register_static(&isa_bus_info);
24149ab747fSPaolo Bonzini     type_register_static(&isabus_bridge_info);
24249ab747fSPaolo Bonzini     type_register_static(&isa_device_type_info);
24349ab747fSPaolo Bonzini }
24449ab747fSPaolo Bonzini 
isabus_get_fw_dev_path(DeviceState * dev)24549ab747fSPaolo Bonzini static char *isabus_get_fw_dev_path(DeviceState *dev)
24649ab747fSPaolo Bonzini {
2474a17cc4fSAndreas Färber     ISADevice *d = ISA_DEVICE(dev);
24849ab747fSPaolo Bonzini     char path[40];
24949ab747fSPaolo Bonzini     int off;
25049ab747fSPaolo Bonzini 
25149ab747fSPaolo Bonzini     off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
25249ab747fSPaolo Bonzini     if (d->ioport_id) {
25349ab747fSPaolo Bonzini         snprintf(path + off, sizeof(path) - off, "@%04x", d->ioport_id);
25449ab747fSPaolo Bonzini     }
25549ab747fSPaolo Bonzini 
25649ab747fSPaolo Bonzini     return g_strdup(path);
25749ab747fSPaolo Bonzini }
25849ab747fSPaolo Bonzini 
isa_address_space(ISADevice * dev)25949ab747fSPaolo Bonzini MemoryRegion *isa_address_space(ISADevice *dev)
26049ab747fSPaolo Bonzini {
261bb2ed009SHervé Poussineau     if (dev) {
262bb2ed009SHervé Poussineau         return isa_bus_from_device(dev)->address_space;
263bb2ed009SHervé Poussineau     }
264bb2ed009SHervé Poussineau 
265bb2ed009SHervé Poussineau     return isabus->address_space;
26649ab747fSPaolo Bonzini }
26749ab747fSPaolo Bonzini 
isa_address_space_io(ISADevice * dev)26849ab747fSPaolo Bonzini MemoryRegion *isa_address_space_io(ISADevice *dev)
26949ab747fSPaolo Bonzini {
27049ab747fSPaolo Bonzini     if (dev) {
27149ab747fSPaolo Bonzini         return isa_bus_from_device(dev)->address_space_io;
27249ab747fSPaolo Bonzini     }
27349ab747fSPaolo Bonzini 
27449ab747fSPaolo Bonzini     return isabus->address_space_io;
27549ab747fSPaolo Bonzini }
27649ab747fSPaolo Bonzini 
27749ab747fSPaolo Bonzini type_init(isabus_register_types)
278