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" 16*d6454270SMarkus Armbruster #include "migration/vmstate.h" 171f9c4cfdSAndreas Färber 181f9c4cfdSAndreas Färber IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot) 191f9c4cfdSAndreas Färber { 201f9c4cfdSAndreas Färber BusChild *kid; 211f9c4cfdSAndreas Färber 221f9c4cfdSAndreas Färber QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) { 231f9c4cfdSAndreas Färber DeviceState *qdev = kid->child; 241f9c4cfdSAndreas Färber IPackDevice *ip = IPACK_DEVICE(qdev); 251f9c4cfdSAndreas Färber if (ip->slot == slot) { 261f9c4cfdSAndreas Färber return ip; 271f9c4cfdSAndreas Färber } 281f9c4cfdSAndreas Färber } 291f9c4cfdSAndreas Färber return NULL; 301f9c4cfdSAndreas Färber } 311f9c4cfdSAndreas Färber 321f9c4cfdSAndreas Färber void ipack_bus_new_inplace(IPackBus *bus, size_t bus_size, 331f9c4cfdSAndreas Färber DeviceState *parent, 341f9c4cfdSAndreas Färber const char *name, uint8_t n_slots, 351f9c4cfdSAndreas Färber qemu_irq_handler handler) 361f9c4cfdSAndreas Färber { 371f9c4cfdSAndreas Färber qbus_create_inplace(bus, bus_size, TYPE_IPACK_BUS, parent, name); 381f9c4cfdSAndreas Färber bus->n_slots = n_slots; 391f9c4cfdSAndreas Färber bus->set_irq = handler; 401f9c4cfdSAndreas Färber } 411f9c4cfdSAndreas Färber 421f9c4cfdSAndreas Färber static void ipack_device_realize(DeviceState *dev, Error **errp) 431f9c4cfdSAndreas Färber { 441f9c4cfdSAndreas Färber IPackDevice *idev = IPACK_DEVICE(dev); 451f9c4cfdSAndreas Färber IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(dev)); 461f9c4cfdSAndreas Färber IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); 471f9c4cfdSAndreas Färber 481f9c4cfdSAndreas Färber if (idev->slot < 0) { 491f9c4cfdSAndreas Färber idev->slot = bus->free_slot; 501f9c4cfdSAndreas Färber } 511f9c4cfdSAndreas Färber if (idev->slot >= bus->n_slots) { 521f9c4cfdSAndreas Färber error_setg(errp, "Only %" PRIu8 " slots available.", bus->n_slots); 531f9c4cfdSAndreas Färber return; 541f9c4cfdSAndreas Färber } 551f9c4cfdSAndreas Färber bus->free_slot = idev->slot + 1; 561f9c4cfdSAndreas Färber 571f9c4cfdSAndreas Färber idev->irq = qemu_allocate_irqs(bus->set_irq, idev, 2); 581f9c4cfdSAndreas Färber 591f9c4cfdSAndreas Färber k->realize(dev, errp); 601f9c4cfdSAndreas Färber } 611f9c4cfdSAndreas Färber 621f9c4cfdSAndreas Färber static void ipack_device_unrealize(DeviceState *dev, Error **errp) 631f9c4cfdSAndreas Färber { 641f9c4cfdSAndreas Färber IPackDevice *idev = IPACK_DEVICE(dev); 651f9c4cfdSAndreas Färber IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); 661f9c4cfdSAndreas Färber Error *err = NULL; 671f9c4cfdSAndreas Färber 681f9c4cfdSAndreas Färber if (k->unrealize) { 691f9c4cfdSAndreas Färber k->unrealize(dev, &err); 701f9c4cfdSAndreas Färber error_propagate(errp, err); 711f9c4cfdSAndreas Färber return; 721f9c4cfdSAndreas Färber } 731f9c4cfdSAndreas Färber 74f173d57aSPeter Crosthwaite qemu_free_irqs(idev->irq, 2); 751f9c4cfdSAndreas Färber } 761f9c4cfdSAndreas Färber 771f9c4cfdSAndreas Färber static Property ipack_device_props[] = { 781f9c4cfdSAndreas Färber DEFINE_PROP_INT32("slot", IPackDevice, slot, -1), 791f9c4cfdSAndreas Färber DEFINE_PROP_END_OF_LIST() 801f9c4cfdSAndreas Färber }; 811f9c4cfdSAndreas Färber 821f9c4cfdSAndreas Färber static void ipack_device_class_init(ObjectClass *klass, void *data) 831f9c4cfdSAndreas Färber { 841f9c4cfdSAndreas Färber DeviceClass *k = DEVICE_CLASS(klass); 851f9c4cfdSAndreas Färber 861f9c4cfdSAndreas Färber set_bit(DEVICE_CATEGORY_INPUT, k->categories); 871f9c4cfdSAndreas Färber k->bus_type = TYPE_IPACK_BUS; 881f9c4cfdSAndreas Färber k->realize = ipack_device_realize; 891f9c4cfdSAndreas Färber k->unrealize = ipack_device_unrealize; 901f9c4cfdSAndreas Färber k->props = ipack_device_props; 911f9c4cfdSAndreas Färber } 921f9c4cfdSAndreas Färber 931f9c4cfdSAndreas Färber const VMStateDescription vmstate_ipack_device = { 941f9c4cfdSAndreas Färber .name = "ipack_device", 951f9c4cfdSAndreas Färber .version_id = 1, 961f9c4cfdSAndreas Färber .minimum_version_id = 1, 971f9c4cfdSAndreas Färber .fields = (VMStateField[]) { 981f9c4cfdSAndreas Färber VMSTATE_INT32(slot, IPackDevice), 991f9c4cfdSAndreas Färber VMSTATE_END_OF_LIST() 1001f9c4cfdSAndreas Färber } 1011f9c4cfdSAndreas Färber }; 1021f9c4cfdSAndreas Färber 1031f9c4cfdSAndreas Färber static const TypeInfo ipack_device_info = { 1041f9c4cfdSAndreas Färber .name = TYPE_IPACK_DEVICE, 1051f9c4cfdSAndreas Färber .parent = TYPE_DEVICE, 1061f9c4cfdSAndreas Färber .instance_size = sizeof(IPackDevice), 1071f9c4cfdSAndreas Färber .class_size = sizeof(IPackDeviceClass), 1081f9c4cfdSAndreas Färber .class_init = ipack_device_class_init, 1091f9c4cfdSAndreas Färber .abstract = true, 1101f9c4cfdSAndreas Färber }; 1111f9c4cfdSAndreas Färber 1121f9c4cfdSAndreas Färber static const TypeInfo ipack_bus_info = { 1131f9c4cfdSAndreas Färber .name = TYPE_IPACK_BUS, 1141f9c4cfdSAndreas Färber .parent = TYPE_BUS, 1151f9c4cfdSAndreas Färber .instance_size = sizeof(IPackBus), 1161f9c4cfdSAndreas Färber }; 1171f9c4cfdSAndreas Färber 1181f9c4cfdSAndreas Färber static void ipack_register_types(void) 1191f9c4cfdSAndreas Färber { 1201f9c4cfdSAndreas Färber type_register_static(&ipack_device_info); 1211f9c4cfdSAndreas Färber type_register_static(&ipack_bus_info); 1221f9c4cfdSAndreas Färber } 1231f9c4cfdSAndreas Färber 1241f9c4cfdSAndreas Färber type_init(ipack_register_types) 125