11f9c4cfdSAndreas Färber /* 21f9c4cfdSAndreas Färber * QEMU IndustryPack emulation 31f9c4cfdSAndreas Färber * 41f9c4cfdSAndreas Färber * Copyright (C) 2012 Igalia, S.L. 5b996aed5SAlberto Garcia * Author: Alberto Garcia <berto@igalia.com> 61f9c4cfdSAndreas Färber * 71f9c4cfdSAndreas Färber * This code is licensed under the GNU GPL v2 or (at your option) any 81f9c4cfdSAndreas Färber * later version. 91f9c4cfdSAndreas Färber */ 101f9c4cfdSAndreas Färber 110430891cSPeter Maydell #include "qemu/osdep.h" 12da34e65cSMarkus Armbruster #include "qapi/error.h" 130b8fa32fSMarkus Armbruster #include "qemu/module.h" 141f9c4cfdSAndreas Färber #include "hw/ipack/ipack.h" 1564552b6bSMarkus Armbruster #include "hw/irq.h" 16a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 17d6454270SMarkus Armbruster #include "migration/vmstate.h" 181f9c4cfdSAndreas Färber 191f9c4cfdSAndreas Färber IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot) 201f9c4cfdSAndreas Färber { 211f9c4cfdSAndreas Färber BusChild *kid; 221f9c4cfdSAndreas Färber 231f9c4cfdSAndreas Färber QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) { 241f9c4cfdSAndreas Färber DeviceState *qdev = kid->child; 251f9c4cfdSAndreas Färber IPackDevice *ip = IPACK_DEVICE(qdev); 261f9c4cfdSAndreas Färber if (ip->slot == slot) { 271f9c4cfdSAndreas Färber return ip; 281f9c4cfdSAndreas Färber } 291f9c4cfdSAndreas Färber } 301f9c4cfdSAndreas Färber return NULL; 311f9c4cfdSAndreas Färber } 321f9c4cfdSAndreas Färber 331f9c4cfdSAndreas Färber void ipack_bus_new_inplace(IPackBus *bus, size_t bus_size, 341f9c4cfdSAndreas Färber DeviceState *parent, 351f9c4cfdSAndreas Färber const char *name, uint8_t n_slots, 361f9c4cfdSAndreas Färber qemu_irq_handler handler) 371f9c4cfdSAndreas Färber { 381f9c4cfdSAndreas Färber qbus_create_inplace(bus, bus_size, TYPE_IPACK_BUS, parent, name); 391f9c4cfdSAndreas Färber bus->n_slots = n_slots; 401f9c4cfdSAndreas Färber bus->set_irq = handler; 411f9c4cfdSAndreas Färber } 421f9c4cfdSAndreas Färber 431f9c4cfdSAndreas Färber static void ipack_device_realize(DeviceState *dev, Error **errp) 441f9c4cfdSAndreas Färber { 451f9c4cfdSAndreas Färber IPackDevice *idev = IPACK_DEVICE(dev); 461f9c4cfdSAndreas Färber IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(dev)); 471f9c4cfdSAndreas Färber IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); 481f9c4cfdSAndreas Färber 491f9c4cfdSAndreas Färber if (idev->slot < 0) { 501f9c4cfdSAndreas Färber idev->slot = bus->free_slot; 511f9c4cfdSAndreas Färber } 521f9c4cfdSAndreas Färber if (idev->slot >= bus->n_slots) { 531f9c4cfdSAndreas Färber error_setg(errp, "Only %" PRIu8 " slots available.", bus->n_slots); 541f9c4cfdSAndreas Färber return; 551f9c4cfdSAndreas Färber } 561f9c4cfdSAndreas Färber bus->free_slot = idev->slot + 1; 571f9c4cfdSAndreas Färber 581f9c4cfdSAndreas Färber idev->irq = qemu_allocate_irqs(bus->set_irq, idev, 2); 591f9c4cfdSAndreas Färber 601f9c4cfdSAndreas Färber k->realize(dev, errp); 611f9c4cfdSAndreas Färber } 621f9c4cfdSAndreas Färber 63*b69c3c21SMarkus Armbruster static void ipack_device_unrealize(DeviceState *dev) 641f9c4cfdSAndreas Färber { 651f9c4cfdSAndreas Färber IPackDevice *idev = IPACK_DEVICE(dev); 661f9c4cfdSAndreas Färber IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); 671f9c4cfdSAndreas Färber 681f9c4cfdSAndreas Färber if (k->unrealize) { 69*b69c3c21SMarkus Armbruster k->unrealize(dev); 701f9c4cfdSAndreas Färber return; 711f9c4cfdSAndreas Färber } 721f9c4cfdSAndreas Färber 73f173d57aSPeter Crosthwaite qemu_free_irqs(idev->irq, 2); 741f9c4cfdSAndreas Färber } 751f9c4cfdSAndreas Färber 761f9c4cfdSAndreas Färber static Property ipack_device_props[] = { 771f9c4cfdSAndreas Färber DEFINE_PROP_INT32("slot", IPackDevice, slot, -1), 781f9c4cfdSAndreas Färber DEFINE_PROP_END_OF_LIST() 791f9c4cfdSAndreas Färber }; 801f9c4cfdSAndreas Färber 811f9c4cfdSAndreas Färber static void ipack_device_class_init(ObjectClass *klass, void *data) 821f9c4cfdSAndreas Färber { 831f9c4cfdSAndreas Färber DeviceClass *k = DEVICE_CLASS(klass); 841f9c4cfdSAndreas Färber 851f9c4cfdSAndreas Färber set_bit(DEVICE_CATEGORY_INPUT, k->categories); 861f9c4cfdSAndreas Färber k->bus_type = TYPE_IPACK_BUS; 871f9c4cfdSAndreas Färber k->realize = ipack_device_realize; 881f9c4cfdSAndreas Färber k->unrealize = ipack_device_unrealize; 894f67d30bSMarc-André Lureau device_class_set_props(k, ipack_device_props); 901f9c4cfdSAndreas Färber } 911f9c4cfdSAndreas Färber 921f9c4cfdSAndreas Färber const VMStateDescription vmstate_ipack_device = { 931f9c4cfdSAndreas Färber .name = "ipack_device", 941f9c4cfdSAndreas Färber .version_id = 1, 951f9c4cfdSAndreas Färber .minimum_version_id = 1, 961f9c4cfdSAndreas Färber .fields = (VMStateField[]) { 971f9c4cfdSAndreas Färber VMSTATE_INT32(slot, IPackDevice), 981f9c4cfdSAndreas Färber VMSTATE_END_OF_LIST() 991f9c4cfdSAndreas Färber } 1001f9c4cfdSAndreas Färber }; 1011f9c4cfdSAndreas Färber 1021f9c4cfdSAndreas Färber static const TypeInfo ipack_device_info = { 1031f9c4cfdSAndreas Färber .name = TYPE_IPACK_DEVICE, 1041f9c4cfdSAndreas Färber .parent = TYPE_DEVICE, 1051f9c4cfdSAndreas Färber .instance_size = sizeof(IPackDevice), 1061f9c4cfdSAndreas Färber .class_size = sizeof(IPackDeviceClass), 1071f9c4cfdSAndreas Färber .class_init = ipack_device_class_init, 1081f9c4cfdSAndreas Färber .abstract = true, 1091f9c4cfdSAndreas Färber }; 1101f9c4cfdSAndreas Färber 1111f9c4cfdSAndreas Färber static const TypeInfo ipack_bus_info = { 1121f9c4cfdSAndreas Färber .name = TYPE_IPACK_BUS, 1131f9c4cfdSAndreas Färber .parent = TYPE_BUS, 1141f9c4cfdSAndreas Färber .instance_size = sizeof(IPackBus), 1151f9c4cfdSAndreas Färber }; 1161f9c4cfdSAndreas Färber 1171f9c4cfdSAndreas Färber static void ipack_register_types(void) 1181f9c4cfdSAndreas Färber { 1191f9c4cfdSAndreas Färber type_register_static(&ipack_device_info); 1201f9c4cfdSAndreas Färber type_register_static(&ipack_bus_info); 1211f9c4cfdSAndreas Färber } 1221f9c4cfdSAndreas Färber 1231f9c4cfdSAndreas Färber type_init(ipack_register_types) 124