qemu/hw/isa/isa-bus.c
<<
>>
Prefs
   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
  28static ISABus *isabus;
  29
  30static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
  31static char *isabus_get_fw_dev_path(DeviceState *dev);
  32
  33static 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
  41static const TypeInfo isa_dma_info = {
  42    .name = TYPE_ISADMA,
  43    .parent = TYPE_INTERFACE,
  44    .class_size = sizeof(IsaDmaClass),
  45};
  46
  47static 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
  54ISABus *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
  72void 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 */
  83qemu_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
  92void 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
 100void 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
 108IsaDma *isa_get_dma(ISABus *bus, int nchan)
 109{
 110    assert(bus);
 111    return bus->dma[nchan > 3 ? 1 : 0];
 112}
 113
 114static 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
 121void 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
 127void 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
 147static 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
 155ISADevice *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
 163ISADevice *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
 171ISADevice *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
 180ISADevice *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
 202static 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
 215static void isabus_bridge_class_init(ObjectClass *klass, void *data)
 216{
 217    DeviceClass *dc = DEVICE_CLASS(klass);
 218
 219    dc->fw_name = "isa";
 220}
 221
 222static 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
 229static 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
 235static 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
 245static 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
 253static 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
 267MemoryRegion *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
 276MemoryRegion *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
 285type_init(isabus_register_types)
 286
 287static 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
 299void 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