19c16fa79SAlberto Garcia /* 29c16fa79SAlberto Garcia * QEMU IndustryPack emulation 39c16fa79SAlberto Garcia * 49c16fa79SAlberto Garcia * Copyright (C) 2012 Igalia, S.L. 5b996aed5SAlberto Garcia * Author: Alberto Garcia <berto@igalia.com> 69c16fa79SAlberto Garcia * 79c16fa79SAlberto Garcia * This code is licensed under the GNU GPL v2 or (at your option) any 89c16fa79SAlberto Garcia * later version. 99c16fa79SAlberto Garcia */ 109c16fa79SAlberto Garcia 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" 189c16fa79SAlberto Garcia 199c16fa79SAlberto Garcia IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot) 209c16fa79SAlberto Garcia { 219c16fa79SAlberto Garcia BusChild *kid; 229c16fa79SAlberto Garcia 239c16fa79SAlberto Garcia QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) { 249c16fa79SAlberto Garcia DeviceState *qdev = kid->child; 259c16fa79SAlberto Garcia IPackDevice *ip = IPACK_DEVICE(qdev); 269c16fa79SAlberto Garcia if (ip->slot == slot) { 279c16fa79SAlberto Garcia return ip; 289c16fa79SAlberto Garcia } 299c16fa79SAlberto Garcia } 309c16fa79SAlberto Garcia return NULL; 319c16fa79SAlberto Garcia } 329c16fa79SAlberto Garcia 3377cbb28aSAndreas Färber void ipack_bus_new_inplace(IPackBus *bus, size_t bus_size, 3477cbb28aSAndreas Färber DeviceState *parent, 359c16fa79SAlberto Garcia const char *name, uint8_t n_slots, 369c16fa79SAlberto Garcia qemu_irq_handler handler) 379c16fa79SAlberto Garcia { 38fb17dfe0SAndreas Färber qbus_create_inplace(bus, bus_size, TYPE_IPACK_BUS, parent, name); 399c16fa79SAlberto Garcia bus->n_slots = n_slots; 409c16fa79SAlberto Garcia bus->set_irq = handler; 419c16fa79SAlberto Garcia } 429c16fa79SAlberto Garcia 435c570902SAndreas Färber static void ipack_device_realize(DeviceState *dev, Error **errp) 449c16fa79SAlberto Garcia { 455c570902SAndreas Färber IPackDevice *idev = IPACK_DEVICE(dev); 465c570902SAndreas Färber IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(dev)); 479c16fa79SAlberto Garcia IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); 489c16fa79SAlberto Garcia 495c570902SAndreas Färber if (idev->slot < 0) { 505c570902SAndreas Färber idev->slot = bus->free_slot; 519c16fa79SAlberto Garcia } 525c570902SAndreas Färber if (idev->slot >= bus->n_slots) { 535c570902SAndreas Färber error_setg(errp, "Only %" PRIu8 " slots available.", bus->n_slots); 545c570902SAndreas Färber return; 559c16fa79SAlberto Garcia } 565c570902SAndreas Färber bus->free_slot = idev->slot + 1; 579c16fa79SAlberto Garcia 585c570902SAndreas Färber idev->irq = qemu_allocate_irqs(bus->set_irq, idev, 2); 599c16fa79SAlberto Garcia 605c570902SAndreas Färber k->realize(dev, errp); 619c16fa79SAlberto Garcia } 629c16fa79SAlberto Garcia 635c570902SAndreas Färber static void ipack_device_unrealize(DeviceState *dev, Error **errp) 649c16fa79SAlberto Garcia { 655c570902SAndreas Färber IPackDevice *idev = IPACK_DEVICE(dev); 669c16fa79SAlberto Garcia IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); 675c570902SAndreas Färber Error *err = NULL; 689c16fa79SAlberto Garcia 695c570902SAndreas Färber if (k->unrealize) { 705c570902SAndreas Färber k->unrealize(dev, &err); 715c570902SAndreas Färber error_propagate(errp, err); 725c570902SAndreas Färber return; 739c16fa79SAlberto Garcia } 749c16fa79SAlberto Garcia 75f173d57aSPeter Crosthwaite qemu_free_irqs(idev->irq, 2); 769c16fa79SAlberto Garcia } 779c16fa79SAlberto Garcia 789c16fa79SAlberto Garcia static Property ipack_device_props[] = { 799c16fa79SAlberto Garcia DEFINE_PROP_INT32("slot", IPackDevice, slot, -1), 809c16fa79SAlberto Garcia DEFINE_PROP_END_OF_LIST() 819c16fa79SAlberto Garcia }; 829c16fa79SAlberto Garcia 839c16fa79SAlberto Garcia static void ipack_device_class_init(ObjectClass *klass, void *data) 849c16fa79SAlberto Garcia { 859c16fa79SAlberto Garcia DeviceClass *k = DEVICE_CLASS(klass); 865c570902SAndreas Färber 87125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_INPUT, k->categories); 889c16fa79SAlberto Garcia k->bus_type = TYPE_IPACK_BUS; 895c570902SAndreas Färber k->realize = ipack_device_realize; 905c570902SAndreas Färber k->unrealize = ipack_device_unrealize; 91*4f67d30bSMarc-André Lureau device_class_set_props(k, ipack_device_props); 929c16fa79SAlberto Garcia } 939c16fa79SAlberto Garcia 949c16fa79SAlberto Garcia const VMStateDescription vmstate_ipack_device = { 959c16fa79SAlberto Garcia .name = "ipack_device", 969c16fa79SAlberto Garcia .version_id = 1, 979c16fa79SAlberto Garcia .minimum_version_id = 1, 989c16fa79SAlberto Garcia .fields = (VMStateField[]) { 999c16fa79SAlberto Garcia VMSTATE_INT32(slot, IPackDevice), 1009c16fa79SAlberto Garcia VMSTATE_END_OF_LIST() 1019c16fa79SAlberto Garcia } 1029c16fa79SAlberto Garcia }; 1039c16fa79SAlberto Garcia 1049c16fa79SAlberto Garcia static const TypeInfo ipack_device_info = { 1059c16fa79SAlberto Garcia .name = TYPE_IPACK_DEVICE, 1069c16fa79SAlberto Garcia .parent = TYPE_DEVICE, 1079c16fa79SAlberto Garcia .instance_size = sizeof(IPackDevice), 1089c16fa79SAlberto Garcia .class_size = sizeof(IPackDeviceClass), 1099c16fa79SAlberto Garcia .class_init = ipack_device_class_init, 1109c16fa79SAlberto Garcia .abstract = true, 1119c16fa79SAlberto Garcia }; 1129c16fa79SAlberto Garcia 1139c16fa79SAlberto Garcia static const TypeInfo ipack_bus_info = { 1149c16fa79SAlberto Garcia .name = TYPE_IPACK_BUS, 1159c16fa79SAlberto Garcia .parent = TYPE_BUS, 1169c16fa79SAlberto Garcia .instance_size = sizeof(IPackBus), 1179c16fa79SAlberto Garcia }; 1189c16fa79SAlberto Garcia 1199c16fa79SAlberto Garcia static void ipack_register_types(void) 1209c16fa79SAlberto Garcia { 1219c16fa79SAlberto Garcia type_register_static(&ipack_device_info); 1229c16fa79SAlberto Garcia type_register_static(&ipack_bus_info); 1239c16fa79SAlberto Garcia } 1249c16fa79SAlberto Garcia 1259c16fa79SAlberto Garcia type_init(ipack_register_types) 126