blob: c463c52150a1f71e83345c9668d87a1c7d93c730 [file] [log] [blame]
Paul Brookaae94602009-05-14 22:35:06 +01001/*
2 * Dynamic device configuration and creation.
3 *
4 * Copyright (c) 2009 CodeSourcery
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
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Paul Brookaae94602009-05-14 22:35:06 +010018 */
19
20/* The theory here is that it should be possible to create a machine without
21 knowledge of specific devices. Historically board init routines have
22 passed a bunch of arguments to each device, requiring the board know
23 exactly which device it is dealing with. This file provides an abstract
24 API for device configuration and initialization. Devices will generally
25 inherit from a particular bus (e.g. PCI or I2C) rather than
26 this API directly. */
27
Paul Brook9d07d752009-05-14 22:35:07 +010028#include "net.h"
Paul Brookaae94602009-05-14 22:35:06 +010029#include "qdev.h"
30#include "sysemu.h"
Gerd Hoffmanncae49562009-06-05 15:53:17 +010031#include "monitor.h"
Paul Brookaae94602009-05-14 22:35:06 +010032
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020033static int qdev_hotplug = 0;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070034static bool qdev_hot_added = false;
35static bool qdev_hot_removed = false;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020036
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020037/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000038static BusState *main_system_bus;
Isaku Yamahata2da8bb92011-08-02 10:59:13 +090039static void main_system_bus_create(void);
Paul Brook4d6ae672009-05-14 22:35:06 +010040
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010041DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010042
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020043static BusState *qbus_find_recursive(BusState *bus, const char *name,
44 const BusInfo *info);
45static BusState *qbus_find(const char *path);
46
Paul Brookaae94602009-05-14 22:35:06 +010047/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020048void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010049{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020050 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020051 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010052
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020053 info->next = device_info_list;
54 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010055}
56
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020057static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
58{
59 DeviceInfo *info;
60
Gerd Hoffmann3320e562009-07-15 13:43:33 +020061 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020062 for (info = device_info_list; info != NULL; info = info->next) {
63 if (bus_info && info->bus_info != bus_info)
64 continue;
65 if (strcmp(info->name, name) != 0)
66 continue;
67 return info;
68 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020069
70 /* failing that check the aliases */
71 for (info = device_info_list; info != NULL; info = info->next) {
72 if (bus_info && info->bus_info != bus_info)
73 continue;
74 if (!info->alias)
75 continue;
76 if (strcmp(info->alias, name) != 0)
77 continue;
78 return info;
79 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020080 return NULL;
81}
82
Markus Armbruster0c175422010-02-19 19:12:18 +010083static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010084{
Paul Brookaae94602009-05-14 22:35:06 +010085 DeviceState *dev;
86
Markus Armbruster0c175422010-02-19 19:12:18 +010087 assert(bus->info == info->bus_info);
Anthony Liguori7267c092011-08-20 22:09:37 -050088 dev = g_malloc0(info->size);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020089 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010090 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020091 qdev_prop_set_defaults(dev, dev->info->props);
92 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +010093 qdev_prop_set_globals(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +000094 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020095 if (qdev_hotplug) {
96 assert(bus->allow_hotplug);
97 dev->hotplugged = 1;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070098 qdev_hot_added = true;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020099 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200100 dev->instance_id_alias = -1;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200101 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +0100102 return dev;
103}
104
Markus Armbruster0c175422010-02-19 19:12:18 +0100105/* Create a new device. This only initializes the device state structure
106 and allows properties to be set. qdev_init should be called to
107 initialize the actual device emulation. */
108DeviceState *qdev_create(BusState *bus, const char *name)
109{
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000110 DeviceState *dev;
111
112 dev = qdev_try_create(bus, name);
113 if (!dev) {
Peter Maydelle92714c2011-08-03 23:49:04 +0100114 if (bus) {
115 hw_error("Unknown device '%s' for bus '%s'\n", name,
116 bus->info->name);
117 } else {
118 hw_error("Unknown device '%s' for default sysbus\n", name);
119 }
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000120 }
121
122 return dev;
123}
124
125DeviceState *qdev_try_create(BusState *bus, const char *name)
126{
Markus Armbruster0c175422010-02-19 19:12:18 +0100127 DeviceInfo *info;
128
129 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100130 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100131 }
132
133 info = qdev_find_info(bus->info, name);
134 if (!info) {
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000135 return NULL;
Markus Armbruster0c175422010-02-19 19:12:18 +0100136 }
137
138 return qdev_create_from_info(bus, info);
139}
140
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100141static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200142{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100143 error_printf("name \"%s\", bus %s",
144 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200145 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100146 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200147 }
148 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100149 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200150 }
151 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100152 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200153 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100154 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200155}
156
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200157static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200158{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200159 DeviceState *dev = opaque;
160
161 if (strcmp(name, "driver") == 0)
162 return 0;
163 if (strcmp(name, "bus") == 0)
164 return 0;
165
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100166 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200167 return -1;
168 }
169 return 0;
170}
171
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100172int qdev_device_help(QemuOpts *opts)
173{
174 const char *driver;
175 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100176 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100177
178 driver = qemu_opt_get(opts, "driver");
179 if (driver && !strcmp(driver, "?")) {
180 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100181 if (info->no_user) {
182 continue; /* not available, don't show */
183 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100184 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100185 }
186 return 1;
187 }
188
Markus Armbruster08350cf2010-01-29 19:49:00 +0100189 if (!qemu_opt_get(opts, "?")) {
190 return 0;
191 }
192
193 info = qdev_find_info(NULL, driver);
194 if (!info) {
195 return 0;
196 }
197
198 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100199 /*
200 * TODO Properties without a parser are just for dirty hacks.
201 * qdev_prop_ptr is the only such PropertyInfo. It's marked
202 * for removal. This conditional should be removed along with
203 * it.
204 */
205 if (!prop->info->parse) {
206 continue; /* no way to set it, don't show */
207 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100208 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100209 }
210 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100211}
212
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200213DeviceState *qdev_device_add(QemuOpts *opts)
214{
215 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200216 DeviceInfo *info;
217 DeviceState *qdev;
218 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200219
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200220 driver = qemu_opt_get(opts, "driver");
221 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100222 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200223 return NULL;
224 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200225
226 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200227 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100228 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100229 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100230 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200231 return NULL;
232 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200233
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200234 /* find bus */
235 path = qemu_opt_get(opts, "bus");
236 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200237 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100238 if (!bus) {
239 return NULL;
240 }
241 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100242 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
243 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100244 return NULL;
245 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200246 } else {
247 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100248 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100249 qerror_report(QERR_NO_BUS_FOR_DEVICE,
250 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100251 return NULL;
252 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200253 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200254 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100255 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200256 return NULL;
257 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200258
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200259 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100260 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200261 id = qemu_opts_id(opts);
262 if (id) {
263 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200264 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200265 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
266 qdev_free(qdev);
267 return NULL;
268 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200269 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100270 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200271 return NULL;
272 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200273 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200274 return qdev;
275}
276
Paul Brookaae94602009-05-14 22:35:06 +0100277/* Initialize a device. Device properties should be set before calling
278 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200279 calling this function.
280 On failure, destroy the device and return negative value.
281 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200282int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100283{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200284 int rc;
285
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200286 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200287 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200288 if (rc < 0) {
289 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200290 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200291 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200292 if (dev->info->vmsd) {
Alex Williamson0be71e32010-06-25 11:09:07 -0600293 vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200294 dev->instance_id_alias,
295 dev->alias_required_for_version);
296 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200297 dev->state = DEV_STATE_INITIALIZED;
Jan Kiszka5ab28c82011-07-24 19:38:36 +0200298 if (dev->hotplugged && dev->info->reset) {
299 dev->info->reset(dev);
300 }
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200301 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100302}
303
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200304void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
305 int required_for_version)
306{
307 assert(dev->state == DEV_STATE_CREATED);
308 dev->instance_id_alias = alias_id;
309 dev->alias_required_for_version = required_for_version;
310}
311
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200312int qdev_unplug(DeviceState *dev)
313{
314 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100315 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200316 return -1;
317 }
Amit Shah593831d2009-11-02 14:56:41 +0530318 assert(dev->info->unplug != NULL);
319
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700320 qdev_hot_removed = true;
321
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200322 return dev->info->unplug(dev);
323}
324
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900325static int qdev_reset_one(DeviceState *dev, void *opaque)
326{
327 if (dev->info->reset) {
328 dev->info->reset(dev);
329 }
330
331 return 0;
332}
333
334BusState *sysbus_get_default(void)
335{
Stefan Weil68694892010-12-16 19:33:22 +0100336 if (!main_system_bus) {
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900337 main_system_bus_create();
Stefan Weil68694892010-12-16 19:33:22 +0100338 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900339 return main_system_bus;
340}
341
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900342static int qbus_reset_one(BusState *bus, void *opaque)
343{
344 if (bus->info->reset) {
345 return bus->info->reset(bus);
346 }
347 return 0;
348}
349
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900350void qdev_reset_all(DeviceState *dev)
351{
352 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
353}
354
Isaku Yamahata80376c32010-12-20 14:33:35 +0900355void qbus_reset_all_fn(void *opaque)
356{
357 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200358 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900359}
360
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200361/* can be used as ->unplug() callback for the simple cases */
362int qdev_simple_unplug_cb(DeviceState *dev)
363{
364 /* just zap it */
365 qdev_free(dev);
366 return 0;
367}
368
Michael Tokarev3b29a102011-04-06 17:51:59 +0400369
370/* Like qdev_init(), but terminate program via error_report() instead of
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200371 returning an error value. This is okay during machine creation.
372 Don't use for hotplug, because there callers need to recover from
373 failure. Exception: if you know the device's init() callback can't
374 fail, then qdev_init_nofail() can't fail either, and is therefore
375 usable even then. But relying on the device implementation that
376 way is somewhat unclean, and best avoided. */
377void qdev_init_nofail(DeviceState *dev)
378{
379 DeviceInfo *info = dev->info;
380
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200381 if (qdev_init(dev) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +0200382 error_report("Initialization of device %s failed", info->name);
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200383 exit(1);
384 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200385}
386
Paul Brook02e2da42009-05-23 00:05:19 +0100387/* Unlink device from bus and free the structure. */
388void qdev_free(DeviceState *dev)
389{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200390 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200391 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200392
393 if (dev->state == DEV_STATE_INITIALIZED) {
394 while (dev->num_child_bus) {
395 bus = QLIST_FIRST(&dev->child_bus);
396 qbus_free(bus);
397 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200398 if (dev->info->vmsd)
Alex Williamson0be71e32010-06-25 11:09:07 -0600399 vmstate_unregister(dev, dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200400 if (dev->info->exit)
401 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200402 if (dev->opts)
403 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200404 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000405 QLIST_REMOVE(dev, sibling);
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200406 for (prop = dev->info->props; prop && prop->name; prop++) {
407 if (prop->info->free) {
408 prop->info->free(dev, prop);
409 }
410 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500411 g_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100412}
413
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200414void qdev_machine_creation_done(void)
415{
416 /*
417 * ok, initial machine setup is done, starting from now we can
418 * only create hotpluggable devices
419 */
420 qdev_hotplug = 1;
421}
422
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700423bool qdev_machine_modified(void)
424{
425 return qdev_hot_added || qdev_hot_removed;
426}
427
Paul Brookaae94602009-05-14 22:35:06 +0100428/* Get a character (serial) device interface. */
429CharDriverState *qdev_init_chardev(DeviceState *dev)
430{
431 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530432
433 /* FIXME: This function needs to go away: use chardev properties! */
434 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100435}
436
Paul Brook02e2da42009-05-23 00:05:19 +0100437BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100438{
Paul Brook02e2da42009-05-23 00:05:19 +0100439 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100440}
441
Paul Brookaae94602009-05-14 22:35:06 +0100442void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
443{
444 assert(dev->num_gpio_in == 0);
445 dev->num_gpio_in = n;
446 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
447}
448
449void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
450{
451 assert(dev->num_gpio_out == 0);
452 dev->num_gpio_out = n;
453 dev->gpio_out = pins;
454}
455
456qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
457{
458 assert(n >= 0 && n < dev->num_gpio_in);
459 return dev->gpio_in[n];
460}
461
462void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
463{
464 assert(n >= 0 && n < dev->num_gpio_out);
465 dev->gpio_out[n] = pin;
466}
467
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200468void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
469{
Jan Kiszka6eed1852011-07-20 12:20:22 +0200470 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200471 if (nd->vlan)
472 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
473 if (nd->netdev)
474 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530475 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200476 qdev_prop_exists(dev, "vectors")) {
477 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
478 }
Peter Maydell48e2faf2011-05-20 16:50:01 +0100479 nd->instantiated = 1;
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200480}
481
Paul Brook02e2da42009-05-23 00:05:19 +0100482BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100483{
Paul Brook02e2da42009-05-23 00:05:19 +0100484 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100485
Blue Swirl72cf2d42009-09-12 07:36:22 +0000486 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100487 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100488 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100489 }
490 }
491 return NULL;
492}
493
Anthony Liguori81699d82010-11-19 18:55:58 +0900494int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
495 qbus_walkerfn *busfn, void *opaque)
496{
497 DeviceState *dev;
498 int err;
499
500 if (busfn) {
501 err = busfn(bus, opaque);
502 if (err) {
503 return err;
504 }
505 }
506
507 QLIST_FOREACH(dev, &bus->children, sibling) {
508 err = qdev_walk_children(dev, devfn, busfn, opaque);
509 if (err < 0) {
510 return err;
511 }
512 }
513
514 return 0;
515}
516
517int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
518 qbus_walkerfn *busfn, void *opaque)
519{
520 BusState *bus;
521 int err;
522
523 if (devfn) {
524 err = devfn(dev, opaque);
525 if (err) {
526 return err;
527 }
528 }
529
530 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
531 err = qbus_walk_children(bus, devfn, busfn, opaque);
532 if (err < 0) {
533 return err;
534 }
535 }
536
537 return 0;
538}
539
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200540static BusState *qbus_find_recursive(BusState *bus, const char *name,
541 const BusInfo *info)
542{
543 DeviceState *dev;
544 BusState *child, *ret;
545 int match = 1;
546
547 if (name && (strcmp(bus->name, name) != 0)) {
548 match = 0;
549 }
550 if (info && (bus->info != info)) {
551 match = 0;
552 }
553 if (match) {
554 return bus;
555 }
556
Blue Swirl72cf2d42009-09-12 07:36:22 +0000557 QLIST_FOREACH(dev, &bus->children, sibling) {
558 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200559 ret = qbus_find_recursive(child, name, info);
560 if (ret) {
561 return ret;
562 }
563 }
564 }
565 return NULL;
566}
567
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900568DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200569{
570 DeviceState *dev, *ret;
571 BusState *child;
572
573 QLIST_FOREACH(dev, &bus->children, sibling) {
574 if (dev->id && strcmp(dev->id, id) == 0)
575 return dev;
576 QLIST_FOREACH(child, &dev->child_bus, sibling) {
577 ret = qdev_find_recursive(child, id);
578 if (ret) {
579 return ret;
580 }
581 }
582 }
583 return NULL;
584}
585
Markus Armbruster53db16b2010-02-18 18:55:59 +0100586static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200587{
588 BusState *child;
589 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200590
Markus Armbruster53db16b2010-02-18 18:55:59 +0100591 error_printf("child busses at \"%s\":",
592 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000593 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100594 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200595 sep = ", ";
596 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100597 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200598}
599
Markus Armbruster53db16b2010-02-18 18:55:59 +0100600static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200601{
602 DeviceState *dev;
603 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200604
Markus Armbruster53db16b2010-02-18 18:55:59 +0100605 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000606 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100607 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200608 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100609 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200610 sep = ", ";
611 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100612 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200613}
614
615static BusState *qbus_find_bus(DeviceState *dev, char *elem)
616{
617 BusState *child;
618
Blue Swirl72cf2d42009-09-12 07:36:22 +0000619 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200620 if (strcmp(child->name, elem) == 0) {
621 return child;
622 }
623 }
624 return NULL;
625}
626
627static DeviceState *qbus_find_dev(BusState *bus, char *elem)
628{
629 DeviceState *dev;
630
631 /*
632 * try to match in order:
633 * (1) instance id, if present
634 * (2) driver name
635 * (3) driver alias, if present
636 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000637 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200638 if (dev->id && strcmp(dev->id, elem) == 0) {
639 return dev;
640 }
641 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000642 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200643 if (strcmp(dev->info->name, elem) == 0) {
644 return dev;
645 }
646 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000647 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200648 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
649 return dev;
650 }
651 }
652 return NULL;
653}
654
655static BusState *qbus_find(const char *path)
656{
657 DeviceState *dev;
658 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100659 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200660 int pos, len;
661
662 /* find start element */
663 if (path[0] == '/') {
664 bus = main_system_bus;
665 pos = 0;
666 } else {
667 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100668 assert(!path[0]);
669 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200670 }
671 bus = qbus_find_recursive(main_system_bus, elem, NULL);
672 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100673 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200674 return NULL;
675 }
676 pos = len;
677 }
678
679 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100680 assert(path[pos] == '/' || !path[pos]);
681 while (path[pos] == '/') {
682 pos++;
683 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200684 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200685 return bus;
686 }
687
688 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100689 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
690 assert(0);
691 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200692 }
693 pos += len;
694 dev = qbus_find_dev(bus, elem);
695 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100696 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100697 if (!monitor_cur_is_qmp()) {
698 qbus_list_dev(bus);
699 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200700 return NULL;
701 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100702
703 assert(path[pos] == '/' || !path[pos]);
704 while (path[pos] == '/') {
705 pos++;
706 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200707 if (path[pos] == '\0') {
708 /* last specified element is a device. If it has exactly
709 * one child bus accept it nevertheless */
710 switch (dev->num_child_bus) {
711 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100712 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200713 return NULL;
714 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000715 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200716 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100717 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100718 if (!monitor_cur_is_qmp()) {
719 qbus_list_bus(dev);
720 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200721 return NULL;
722 }
723 }
724
725 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100726 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
727 assert(0);
728 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200729 }
730 pos += len;
731 bus = qbus_find_bus(dev, elem);
732 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100733 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100734 if (!monitor_cur_is_qmp()) {
735 qbus_list_bus(dev);
736 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200737 return NULL;
738 }
739 }
740}
741
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200742void qbus_create_inplace(BusState *bus, BusInfo *info,
743 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100744{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200745 char *buf;
746 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100747
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200748 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100749 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200750
751 if (name) {
752 /* use supplied name */
Anthony Liguori7267c092011-08-20 22:09:37 -0500753 bus->name = g_strdup(name);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200754 } else if (parent && parent->id) {
755 /* parent device has id -> use it for bus name */
756 len = strlen(parent->id) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500757 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200758 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
759 bus->name = buf;
760 } else {
761 /* no id -> use lowercase bus type for bus name */
762 len = strlen(info->name) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500763 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200764 len = snprintf(buf, len, "%s.%d", info->name,
765 parent ? parent->num_child_bus : 0);
766 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200767 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200768 bus->name = buf;
769 }
770
Blue Swirl72cf2d42009-09-12 07:36:22 +0000771 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100772 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000773 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200774 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900775 } else if (bus != main_system_bus) {
776 /* TODO: once all bus devices are qdevified,
777 only reset handler for main_system_bus should be registered here. */
778 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100779 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200780}
781
782BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
783{
784 BusState *bus;
785
Anthony Liguori7267c092011-08-20 22:09:37 -0500786 bus = g_malloc0(info->size);
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200787 bus->qdev_allocated = 1;
788 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100789 return bus;
790}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100791
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900792static void main_system_bus_create(void)
793{
794 /* assign main_system_bus before qbus_create_inplace()
795 * in order to make "if (bus != main_system_bus)" work */
Anthony Liguori7267c092011-08-20 22:09:37 -0500796 main_system_bus = g_malloc0(system_bus_info.size);
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900797 main_system_bus->qdev_allocated = 1;
798 qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
799 "main-system-bus");
800}
801
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200802void qbus_free(BusState *bus)
803{
804 DeviceState *dev;
805
806 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
807 qdev_free(dev);
808 }
809 if (bus->parent) {
810 QLIST_REMOVE(bus, sibling);
811 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900812 } else {
813 assert(bus != main_system_bus); /* main_system_bus is never freed */
814 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200815 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500816 g_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200817 if (bus->qdev_allocated) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500818 g_free(bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200819 }
820}
821
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100822#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
823static void qbus_print(Monitor *mon, BusState *bus, int indent);
824
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200825static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
826 const char *prefix, int indent)
827{
828 char buf[64];
829
830 if (!props)
831 return;
832 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100833 /*
834 * TODO Properties without a print method are just for dirty
835 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
836 * marked for removal. The test props->info->print should be
837 * removed along with it.
838 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200839 if (props->info->print) {
840 props->info->print(dev, props, buf, sizeof(buf));
841 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
842 }
843 props++;
844 }
845}
846
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100847static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
848{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100849 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200850 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
851 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100852 indent += 2;
853 if (dev->num_gpio_in) {
854 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
855 }
856 if (dev->num_gpio_out) {
857 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
858 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200859 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
860 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200861 if (dev->parent_bus->info->print_dev)
862 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000863 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100864 qbus_print(mon, child, indent);
865 }
866}
867
868static void qbus_print(Monitor *mon, BusState *bus, int indent)
869{
870 struct DeviceState *dev;
871
872 qdev_printf("bus: %s\n", bus->name);
873 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200874 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000875 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100876 qdev_print(mon, dev, indent);
877 }
878}
879#undef qdev_printf
880
881void do_info_qtree(Monitor *mon)
882{
883 if (main_system_bus)
884 qbus_print(mon, main_system_bus, 0);
885}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200886
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200887void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200888{
889 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200890
891 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100892 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200893 }
894}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200895
Markus Armbruster8bc27242010-02-10 20:52:01 +0100896int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200897{
898 QemuOpts *opts;
899
Gerd Hoffmann3329f072010-08-20 13:52:01 +0200900 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100901 if (!opts) {
902 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +0100903 }
Markus Armbruster8bc27242010-02-10 20:52:01 +0100904 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
905 qemu_opts_del(opts);
906 return 0;
907 }
908 if (!qdev_device_add(opts)) {
909 qemu_opts_del(opts);
910 return -1;
911 }
912 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200913}
914
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100915int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200916{
917 const char *id = qdict_get_str(qdict, "id");
918 DeviceState *dev;
919
920 dev = qdev_find_recursive(main_system_bus, id);
921 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100922 qerror_report(QERR_DEVICE_NOT_FOUND, id);
923 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200924 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100925 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200926}
Gleb Natapov1ca4d092010-12-08 13:35:05 +0200927
928static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
929{
930 int l = 0;
931
932 if (dev && dev->parent_bus) {
933 char *d;
934 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
935 if (dev->parent_bus->info->get_fw_dev_path) {
936 d = dev->parent_bus->info->get_fw_dev_path(dev);
937 l += snprintf(p + l, size - l, "%s", d);
Anthony Liguori7267c092011-08-20 22:09:37 -0500938 g_free(d);
Gleb Natapov1ca4d092010-12-08 13:35:05 +0200939 } else {
940 l += snprintf(p + l, size - l, "%s", dev->info->name);
941 }
942 }
943 l += snprintf(p + l , size - l, "/");
944
945 return l;
946}
947
948char* qdev_get_fw_dev_path(DeviceState *dev)
949{
950 char path[128];
951 int l;
952
953 l = qdev_get_fw_dev_path_helper(dev, path, 128);
954
955 path[l-1] = '\0';
956
957 return strdup(path);
958}