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