blob: 6819537648f22694a9d14e1379b309706c0dd546 [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);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020088 dev = qemu_mallocz(info->size);
89 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) {
114 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
115 }
116
117 return dev;
118}
119
120DeviceState *qdev_try_create(BusState *bus, const char *name)
121{
Markus Armbruster0c175422010-02-19 19:12:18 +0100122 DeviceInfo *info;
123
124 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100125 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100126 }
127
128 info = qdev_find_info(bus->info, name);
129 if (!info) {
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000130 return NULL;
Markus Armbruster0c175422010-02-19 19:12:18 +0100131 }
132
133 return qdev_create_from_info(bus, info);
134}
135
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100136static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200137{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100138 error_printf("name \"%s\", bus %s",
139 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200140 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100141 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200142 }
143 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100144 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200145 }
146 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100147 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200148 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100149 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200150}
151
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200152static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200153{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200154 DeviceState *dev = opaque;
155
156 if (strcmp(name, "driver") == 0)
157 return 0;
158 if (strcmp(name, "bus") == 0)
159 return 0;
160
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100161 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200162 return -1;
163 }
164 return 0;
165}
166
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100167int qdev_device_help(QemuOpts *opts)
168{
169 const char *driver;
170 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100171 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100172
173 driver = qemu_opt_get(opts, "driver");
174 if (driver && !strcmp(driver, "?")) {
175 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100176 if (info->no_user) {
177 continue; /* not available, don't show */
178 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100179 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100180 }
181 return 1;
182 }
183
Markus Armbruster08350cf2010-01-29 19:49:00 +0100184 if (!qemu_opt_get(opts, "?")) {
185 return 0;
186 }
187
188 info = qdev_find_info(NULL, driver);
189 if (!info) {
190 return 0;
191 }
192
193 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100194 /*
195 * TODO Properties without a parser are just for dirty hacks.
196 * qdev_prop_ptr is the only such PropertyInfo. It's marked
197 * for removal. This conditional should be removed along with
198 * it.
199 */
200 if (!prop->info->parse) {
201 continue; /* no way to set it, don't show */
202 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100203 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100204 }
205 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100206}
207
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200208DeviceState *qdev_device_add(QemuOpts *opts)
209{
210 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200211 DeviceInfo *info;
212 DeviceState *qdev;
213 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200214
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200215 driver = qemu_opt_get(opts, "driver");
216 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100217 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200218 return NULL;
219 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200220
221 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200222 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100223 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100224 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100225 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200226 return NULL;
227 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200228
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200229 /* find bus */
230 path = qemu_opt_get(opts, "bus");
231 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200232 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100233 if (!bus) {
234 return NULL;
235 }
236 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100237 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
238 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100239 return NULL;
240 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200241 } else {
242 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100243 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100244 qerror_report(QERR_NO_BUS_FOR_DEVICE,
245 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100246 return NULL;
247 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200248 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200249 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100250 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200251 return NULL;
252 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200253
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200254 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100255 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200256 id = qemu_opts_id(opts);
257 if (id) {
258 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200259 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200260 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
261 qdev_free(qdev);
262 return NULL;
263 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200264 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100265 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200266 return NULL;
267 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200268 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200269 return qdev;
270}
271
Paul Brookaae94602009-05-14 22:35:06 +0100272/* Initialize a device. Device properties should be set before calling
273 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200274 calling this function.
275 On failure, destroy the device and return negative value.
276 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200277int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100278{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200279 int rc;
280
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200281 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200282 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200283 if (rc < 0) {
284 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200285 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200286 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200287 if (dev->info->vmsd) {
Alex Williamson0be71e32010-06-25 11:09:07 -0600288 vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200289 dev->instance_id_alias,
290 dev->alias_required_for_version);
291 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200292 dev->state = DEV_STATE_INITIALIZED;
Jan Kiszka5ab28c82011-07-24 19:38:36 +0200293 if (dev->hotplugged && dev->info->reset) {
294 dev->info->reset(dev);
295 }
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200296 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100297}
298
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200299void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
300 int required_for_version)
301{
302 assert(dev->state == DEV_STATE_CREATED);
303 dev->instance_id_alias = alias_id;
304 dev->alias_required_for_version = required_for_version;
305}
306
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200307int qdev_unplug(DeviceState *dev)
308{
309 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100310 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200311 return -1;
312 }
Amit Shah593831d2009-11-02 14:56:41 +0530313 assert(dev->info->unplug != NULL);
314
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700315 qdev_hot_removed = true;
316
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200317 return dev->info->unplug(dev);
318}
319
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900320static int qdev_reset_one(DeviceState *dev, void *opaque)
321{
322 if (dev->info->reset) {
323 dev->info->reset(dev);
324 }
325
326 return 0;
327}
328
329BusState *sysbus_get_default(void)
330{
Stefan Weil68694892010-12-16 19:33:22 +0100331 if (!main_system_bus) {
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900332 main_system_bus_create();
Stefan Weil68694892010-12-16 19:33:22 +0100333 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900334 return main_system_bus;
335}
336
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900337static int qbus_reset_one(BusState *bus, void *opaque)
338{
339 if (bus->info->reset) {
340 return bus->info->reset(bus);
341 }
342 return 0;
343}
344
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900345void qdev_reset_all(DeviceState *dev)
346{
347 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
348}
349
Isaku Yamahata80376c32010-12-20 14:33:35 +0900350void qbus_reset_all_fn(void *opaque)
351{
352 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200353 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900354}
355
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200356/* can be used as ->unplug() callback for the simple cases */
357int qdev_simple_unplug_cb(DeviceState *dev)
358{
359 /* just zap it */
360 qdev_free(dev);
361 return 0;
362}
363
Michael Tokarev3b29a102011-04-06 17:51:59 +0400364
365/* Like qdev_init(), but terminate program via error_report() instead of
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200366 returning an error value. This is okay during machine creation.
367 Don't use for hotplug, because there callers need to recover from
368 failure. Exception: if you know the device's init() callback can't
369 fail, then qdev_init_nofail() can't fail either, and is therefore
370 usable even then. But relying on the device implementation that
371 way is somewhat unclean, and best avoided. */
372void qdev_init_nofail(DeviceState *dev)
373{
374 DeviceInfo *info = dev->info;
375
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200376 if (qdev_init(dev) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +0200377 error_report("Initialization of device %s failed", info->name);
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200378 exit(1);
379 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200380}
381
Paul Brook02e2da42009-05-23 00:05:19 +0100382/* Unlink device from bus and free the structure. */
383void qdev_free(DeviceState *dev)
384{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200385 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200386 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200387
388 if (dev->state == DEV_STATE_INITIALIZED) {
389 while (dev->num_child_bus) {
390 bus = QLIST_FIRST(&dev->child_bus);
391 qbus_free(bus);
392 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200393 if (dev->info->vmsd)
Alex Williamson0be71e32010-06-25 11:09:07 -0600394 vmstate_unregister(dev, dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200395 if (dev->info->exit)
396 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200397 if (dev->opts)
398 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200399 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000400 QLIST_REMOVE(dev, sibling);
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200401 for (prop = dev->info->props; prop && prop->name; prop++) {
402 if (prop->info->free) {
403 prop->info->free(dev, prop);
404 }
405 }
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200406 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100407}
408
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200409void qdev_machine_creation_done(void)
410{
411 /*
412 * ok, initial machine setup is done, starting from now we can
413 * only create hotpluggable devices
414 */
415 qdev_hotplug = 1;
416}
417
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700418bool qdev_machine_modified(void)
419{
420 return qdev_hot_added || qdev_hot_removed;
421}
422
Paul Brookaae94602009-05-14 22:35:06 +0100423/* Get a character (serial) device interface. */
424CharDriverState *qdev_init_chardev(DeviceState *dev)
425{
426 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530427
428 /* FIXME: This function needs to go away: use chardev properties! */
429 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100430}
431
Paul Brook02e2da42009-05-23 00:05:19 +0100432BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100433{
Paul Brook02e2da42009-05-23 00:05:19 +0100434 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100435}
436
Paul Brookaae94602009-05-14 22:35:06 +0100437void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
438{
439 assert(dev->num_gpio_in == 0);
440 dev->num_gpio_in = n;
441 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
442}
443
444void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
445{
446 assert(dev->num_gpio_out == 0);
447 dev->num_gpio_out = n;
448 dev->gpio_out = pins;
449}
450
451qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
452{
453 assert(n >= 0 && n < dev->num_gpio_in);
454 return dev->gpio_in[n];
455}
456
457void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
458{
459 assert(n >= 0 && n < dev->num_gpio_out);
460 dev->gpio_out[n] = pin;
461}
462
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200463void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
464{
Jan Kiszka6eed1852011-07-20 12:20:22 +0200465 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200466 if (nd->vlan)
467 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
468 if (nd->netdev)
469 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530470 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200471 qdev_prop_exists(dev, "vectors")) {
472 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
473 }
Peter Maydell48e2faf2011-05-20 16:50:01 +0100474 nd->instantiated = 1;
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200475}
476
Paul Brook02e2da42009-05-23 00:05:19 +0100477BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100478{
Paul Brook02e2da42009-05-23 00:05:19 +0100479 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100480
Blue Swirl72cf2d42009-09-12 07:36:22 +0000481 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100482 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100483 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100484 }
485 }
486 return NULL;
487}
488
Anthony Liguori81699d82010-11-19 18:55:58 +0900489int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
490 qbus_walkerfn *busfn, void *opaque)
491{
492 DeviceState *dev;
493 int err;
494
495 if (busfn) {
496 err = busfn(bus, opaque);
497 if (err) {
498 return err;
499 }
500 }
501
502 QLIST_FOREACH(dev, &bus->children, sibling) {
503 err = qdev_walk_children(dev, devfn, busfn, opaque);
504 if (err < 0) {
505 return err;
506 }
507 }
508
509 return 0;
510}
511
512int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
513 qbus_walkerfn *busfn, void *opaque)
514{
515 BusState *bus;
516 int err;
517
518 if (devfn) {
519 err = devfn(dev, opaque);
520 if (err) {
521 return err;
522 }
523 }
524
525 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
526 err = qbus_walk_children(bus, devfn, busfn, opaque);
527 if (err < 0) {
528 return err;
529 }
530 }
531
532 return 0;
533}
534
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200535static BusState *qbus_find_recursive(BusState *bus, const char *name,
536 const BusInfo *info)
537{
538 DeviceState *dev;
539 BusState *child, *ret;
540 int match = 1;
541
542 if (name && (strcmp(bus->name, name) != 0)) {
543 match = 0;
544 }
545 if (info && (bus->info != info)) {
546 match = 0;
547 }
548 if (match) {
549 return bus;
550 }
551
Blue Swirl72cf2d42009-09-12 07:36:22 +0000552 QLIST_FOREACH(dev, &bus->children, sibling) {
553 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200554 ret = qbus_find_recursive(child, name, info);
555 if (ret) {
556 return ret;
557 }
558 }
559 }
560 return NULL;
561}
562
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900563DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200564{
565 DeviceState *dev, *ret;
566 BusState *child;
567
568 QLIST_FOREACH(dev, &bus->children, sibling) {
569 if (dev->id && strcmp(dev->id, id) == 0)
570 return dev;
571 QLIST_FOREACH(child, &dev->child_bus, sibling) {
572 ret = qdev_find_recursive(child, id);
573 if (ret) {
574 return ret;
575 }
576 }
577 }
578 return NULL;
579}
580
Markus Armbruster53db16b2010-02-18 18:55:59 +0100581static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200582{
583 BusState *child;
584 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200585
Markus Armbruster53db16b2010-02-18 18:55:59 +0100586 error_printf("child busses at \"%s\":",
587 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000588 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100589 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200590 sep = ", ";
591 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100592 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200593}
594
Markus Armbruster53db16b2010-02-18 18:55:59 +0100595static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200596{
597 DeviceState *dev;
598 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200599
Markus Armbruster53db16b2010-02-18 18:55:59 +0100600 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000601 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100602 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200603 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100604 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200605 sep = ", ";
606 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100607 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200608}
609
610static BusState *qbus_find_bus(DeviceState *dev, char *elem)
611{
612 BusState *child;
613
Blue Swirl72cf2d42009-09-12 07:36:22 +0000614 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200615 if (strcmp(child->name, elem) == 0) {
616 return child;
617 }
618 }
619 return NULL;
620}
621
622static DeviceState *qbus_find_dev(BusState *bus, char *elem)
623{
624 DeviceState *dev;
625
626 /*
627 * try to match in order:
628 * (1) instance id, if present
629 * (2) driver name
630 * (3) driver alias, if present
631 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000632 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200633 if (dev->id && strcmp(dev->id, elem) == 0) {
634 return dev;
635 }
636 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000637 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200638 if (strcmp(dev->info->name, 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 (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
644 return dev;
645 }
646 }
647 return NULL;
648}
649
650static BusState *qbus_find(const char *path)
651{
652 DeviceState *dev;
653 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100654 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200655 int pos, len;
656
657 /* find start element */
658 if (path[0] == '/') {
659 bus = main_system_bus;
660 pos = 0;
661 } else {
662 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100663 assert(!path[0]);
664 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200665 }
666 bus = qbus_find_recursive(main_system_bus, elem, NULL);
667 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100668 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200669 return NULL;
670 }
671 pos = len;
672 }
673
674 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100675 assert(path[pos] == '/' || !path[pos]);
676 while (path[pos] == '/') {
677 pos++;
678 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200679 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200680 return bus;
681 }
682
683 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100684 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
685 assert(0);
686 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200687 }
688 pos += len;
689 dev = qbus_find_dev(bus, elem);
690 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100691 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100692 if (!monitor_cur_is_qmp()) {
693 qbus_list_dev(bus);
694 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200695 return NULL;
696 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100697
698 assert(path[pos] == '/' || !path[pos]);
699 while (path[pos] == '/') {
700 pos++;
701 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200702 if (path[pos] == '\0') {
703 /* last specified element is a device. If it has exactly
704 * one child bus accept it nevertheless */
705 switch (dev->num_child_bus) {
706 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100707 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200708 return NULL;
709 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000710 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200711 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100712 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100713 if (!monitor_cur_is_qmp()) {
714 qbus_list_bus(dev);
715 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200716 return NULL;
717 }
718 }
719
720 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100721 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
722 assert(0);
723 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200724 }
725 pos += len;
726 bus = qbus_find_bus(dev, elem);
727 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100728 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100729 if (!monitor_cur_is_qmp()) {
730 qbus_list_bus(dev);
731 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200732 return NULL;
733 }
734 }
735}
736
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200737void qbus_create_inplace(BusState *bus, BusInfo *info,
738 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100739{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200740 char *buf;
741 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100742
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200743 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100744 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200745
746 if (name) {
747 /* use supplied name */
748 bus->name = qemu_strdup(name);
749 } else if (parent && parent->id) {
750 /* parent device has id -> use it for bus name */
751 len = strlen(parent->id) + 16;
752 buf = qemu_malloc(len);
753 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
754 bus->name = buf;
755 } else {
756 /* no id -> use lowercase bus type for bus name */
757 len = strlen(info->name) + 16;
758 buf = qemu_malloc(len);
759 len = snprintf(buf, len, "%s.%d", info->name,
760 parent ? parent->num_child_bus : 0);
761 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200762 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200763 bus->name = buf;
764 }
765
Blue Swirl72cf2d42009-09-12 07:36:22 +0000766 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100767 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000768 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200769 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900770 } else if (bus != main_system_bus) {
771 /* TODO: once all bus devices are qdevified,
772 only reset handler for main_system_bus should be registered here. */
773 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100774 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200775}
776
777BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
778{
779 BusState *bus;
780
781 bus = qemu_mallocz(info->size);
782 bus->qdev_allocated = 1;
783 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100784 return bus;
785}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100786
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900787static void main_system_bus_create(void)
788{
789 /* assign main_system_bus before qbus_create_inplace()
790 * in order to make "if (bus != main_system_bus)" work */
791 main_system_bus = qemu_mallocz(system_bus_info.size);
792 main_system_bus->qdev_allocated = 1;
793 qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
794 "main-system-bus");
795}
796
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200797void qbus_free(BusState *bus)
798{
799 DeviceState *dev;
800
801 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
802 qdev_free(dev);
803 }
804 if (bus->parent) {
805 QLIST_REMOVE(bus, sibling);
806 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900807 } else {
808 assert(bus != main_system_bus); /* main_system_bus is never freed */
809 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200810 }
Isaku Yamahatae163ae72010-05-27 14:35:58 +0900811 qemu_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200812 if (bus->qdev_allocated) {
813 qemu_free(bus);
814 }
815}
816
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100817#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
818static void qbus_print(Monitor *mon, BusState *bus, int indent);
819
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200820static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
821 const char *prefix, int indent)
822{
823 char buf[64];
824
825 if (!props)
826 return;
827 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100828 /*
829 * TODO Properties without a print method are just for dirty
830 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
831 * marked for removal. The test props->info->print should be
832 * removed along with it.
833 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200834 if (props->info->print) {
835 props->info->print(dev, props, buf, sizeof(buf));
836 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
837 }
838 props++;
839 }
840}
841
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100842static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
843{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100844 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200845 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
846 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100847 indent += 2;
848 if (dev->num_gpio_in) {
849 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
850 }
851 if (dev->num_gpio_out) {
852 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
853 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200854 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
855 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200856 if (dev->parent_bus->info->print_dev)
857 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000858 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100859 qbus_print(mon, child, indent);
860 }
861}
862
863static void qbus_print(Monitor *mon, BusState *bus, int indent)
864{
865 struct DeviceState *dev;
866
867 qdev_printf("bus: %s\n", bus->name);
868 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200869 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000870 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100871 qdev_print(mon, dev, indent);
872 }
873}
874#undef qdev_printf
875
876void do_info_qtree(Monitor *mon)
877{
878 if (main_system_bus)
879 qbus_print(mon, main_system_bus, 0);
880}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200881
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200882void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200883{
884 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200885
886 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100887 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200888 }
889}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200890
Markus Armbruster8bc27242010-02-10 20:52:01 +0100891int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200892{
893 QemuOpts *opts;
894
Gerd Hoffmann3329f072010-08-20 13:52:01 +0200895 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100896 if (!opts) {
897 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +0100898 }
Markus Armbruster8bc27242010-02-10 20:52:01 +0100899 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
900 qemu_opts_del(opts);
901 return 0;
902 }
903 if (!qdev_device_add(opts)) {
904 qemu_opts_del(opts);
905 return -1;
906 }
907 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200908}
909
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100910int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200911{
912 const char *id = qdict_get_str(qdict, "id");
913 DeviceState *dev;
914
915 dev = qdev_find_recursive(main_system_bus, id);
916 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100917 qerror_report(QERR_DEVICE_NOT_FOUND, id);
918 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200919 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100920 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200921}
Gleb Natapov1ca4d092010-12-08 13:35:05 +0200922
923static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
924{
925 int l = 0;
926
927 if (dev && dev->parent_bus) {
928 char *d;
929 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
930 if (dev->parent_bus->info->get_fw_dev_path) {
931 d = dev->parent_bus->info->get_fw_dev_path(dev);
932 l += snprintf(p + l, size - l, "%s", d);
933 qemu_free(d);
934 } else {
935 l += snprintf(p + l, size - l, "%s", dev->info->name);
936 }
937 }
938 l += snprintf(p + l , size - l, "/");
939
940 return l;
941}
942
943char* qdev_get_fw_dev_path(DeviceState *dev)
944{
945 char path[128];
946 int l;
947
948 l = qdev_get_fw_dev_path_helper(dev, path, 128);
949
950 path[l-1] = '\0';
951
952 return strdup(path);
953}