1 /* 2 * QDev Hotplug handlers 3 * 4 * Copyright (c) Red Hat 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 * See the COPYING file in the top-level directory. 10 */ 11 12 #include "qemu/osdep.h" 13 #include "hw/qdev-core.h" 14 #include "hw/boards.h" 15 #include "qapi/error.h" 16 17 HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev) 18 { 19 MachineState *machine; 20 MachineClass *mc; 21 Object *m_obj = qdev_get_machine(); 22 23 if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { 24 machine = MACHINE(m_obj); 25 mc = MACHINE_GET_CLASS(machine); 26 if (mc->get_hotplug_handler) { 27 return mc->get_hotplug_handler(machine, dev); 28 } 29 } 30 31 return NULL; 32 } 33 34 static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus, 35 Error **errp) 36 { 37 DeviceClass *dc = DEVICE_GET_CLASS(dev); 38 39 if (!dc->hotpluggable) { 40 error_setg(errp, "Device '%s' does not support hotplugging", 41 object_get_typename(OBJECT(dev))); 42 return false; 43 } 44 45 if (bus) { 46 if (!qbus_is_hotpluggable(bus)) { 47 error_setg(errp, "Bus '%s' does not support hotplugging", 48 bus->name); 49 return false; 50 } 51 } else { 52 if (!qdev_get_machine_hotplug_handler(dev)) { 53 /* 54 * No bus, no machine hotplug handler --> device is not hotpluggable 55 */ 56 error_setg(errp, 57 "Device '%s' can not be hotplugged on this machine", 58 object_get_typename(OBJECT(dev))); 59 return false; 60 } 61 } 62 63 return true; 64 } 65 66 bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp) 67 { 68 MachineState *machine; 69 MachineClass *mc; 70 Object *m_obj = qdev_get_machine(); 71 72 if (!qdev_hotplug_unplug_allowed_common(dev, bus, errp)) { 73 return false; 74 } 75 76 if (object_dynamic_cast(m_obj, TYPE_MACHINE)) { 77 machine = MACHINE(m_obj); 78 mc = MACHINE_GET_CLASS(machine); 79 if (mc->hotplug_allowed) { 80 return mc->hotplug_allowed(machine, dev, errp); 81 } 82 } 83 84 return true; 85 } 86 87 bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp) 88 { 89 return !qdev_unplug_blocked(dev, errp) && 90 qdev_hotplug_unplug_allowed_common(dev, dev->parent_bus, errp); 91 } 92 93 HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev) 94 { 95 if (dev->parent_bus) { 96 return dev->parent_bus->hotplug_handler; 97 } 98 return NULL; 99 } 100 101 HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev) 102 { 103 HotplugHandler *hotplug_ctrl = qdev_get_machine_hotplug_handler(dev); 104 105 if (hotplug_ctrl == NULL && dev->parent_bus) { 106 hotplug_ctrl = qdev_get_bus_hotplug_handler(dev); 107 } 108 return hotplug_ctrl; 109 } 110 111 /* can be used as ->unplug() callback for the simple cases */ 112 void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, 113 DeviceState *dev, Error **errp) 114 { 115 qdev_unrealize(dev); 116 } 117