blob: 292b52f8c542d3e7f2456cdeea9003f5c6284a52 [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;
Paul Brook4d6ae672009-05-14 22:35:06 +010039
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010040DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010041
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020042static BusState *qbus_find_recursive(BusState *bus, const char *name,
43 const BusInfo *info);
44static BusState *qbus_find(const char *path);
45
Paul Brookaae94602009-05-14 22:35:06 +010046/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020047void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010048{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020049 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020050 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010051
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020052 info->next = device_info_list;
53 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010054}
55
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020056static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
57{
58 DeviceInfo *info;
59
Gerd Hoffmann3320e562009-07-15 13:43:33 +020060 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020061 for (info = device_info_list; info != NULL; info = info->next) {
62 if (bus_info && info->bus_info != bus_info)
63 continue;
64 if (strcmp(info->name, name) != 0)
65 continue;
66 return info;
67 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020068
69 /* failing that check the aliases */
70 for (info = device_info_list; info != NULL; info = info->next) {
71 if (bus_info && info->bus_info != bus_info)
72 continue;
73 if (!info->alias)
74 continue;
75 if (strcmp(info->alias, name) != 0)
76 continue;
77 return info;
78 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020079 return NULL;
80}
81
Markus Armbruster0c175422010-02-19 19:12:18 +010082static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010083{
Paul Brookaae94602009-05-14 22:35:06 +010084 DeviceState *dev;
85
Markus Armbruster0c175422010-02-19 19:12:18 +010086 assert(bus->info == info->bus_info);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020087 dev = qemu_mallocz(info->size);
88 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010089 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020090 qdev_prop_set_defaults(dev, dev->info->props);
91 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +010092 qdev_prop_set_globals(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +000093 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020094 if (qdev_hotplug) {
95 assert(bus->allow_hotplug);
96 dev->hotplugged = 1;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070097 qdev_hot_added = true;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020098 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +020099 dev->instance_id_alias = -1;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200100 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +0100101 return dev;
102}
103
Markus Armbruster0c175422010-02-19 19:12:18 +0100104/* Create a new device. This only initializes the device state structure
105 and allows properties to be set. qdev_init should be called to
106 initialize the actual device emulation. */
107DeviceState *qdev_create(BusState *bus, const char *name)
108{
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000109 DeviceState *dev;
110
111 dev = qdev_try_create(bus, name);
112 if (!dev) {
113 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
114 }
115
116 return dev;
117}
118
119DeviceState *qdev_try_create(BusState *bus, const char *name)
120{
Markus Armbruster0c175422010-02-19 19:12:18 +0100121 DeviceInfo *info;
122
123 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100124 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100125 }
126
127 info = qdev_find_info(bus->info, name);
128 if (!info) {
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000129 return NULL;
Markus Armbruster0c175422010-02-19 19:12:18 +0100130 }
131
132 return qdev_create_from_info(bus, info);
133}
134
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100135static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200136{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100137 error_printf("name \"%s\", bus %s",
138 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200139 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100140 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200141 }
142 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100143 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200144 }
145 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100146 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200147 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100148 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200149}
150
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200151static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200152{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200153 DeviceState *dev = opaque;
154
155 if (strcmp(name, "driver") == 0)
156 return 0;
157 if (strcmp(name, "bus") == 0)
158 return 0;
159
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100160 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200161 return -1;
162 }
163 return 0;
164}
165
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100166int qdev_device_help(QemuOpts *opts)
167{
168 const char *driver;
169 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100170 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100171
172 driver = qemu_opt_get(opts, "driver");
173 if (driver && !strcmp(driver, "?")) {
174 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100175 if (info->no_user) {
176 continue; /* not available, don't show */
177 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100178 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100179 }
180 return 1;
181 }
182
Markus Armbruster08350cf2010-01-29 19:49:00 +0100183 if (!qemu_opt_get(opts, "?")) {
184 return 0;
185 }
186
187 info = qdev_find_info(NULL, driver);
188 if (!info) {
189 return 0;
190 }
191
192 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100193 /*
194 * TODO Properties without a parser are just for dirty hacks.
195 * qdev_prop_ptr is the only such PropertyInfo. It's marked
196 * for removal. This conditional should be removed along with
197 * it.
198 */
199 if (!prop->info->parse) {
200 continue; /* no way to set it, don't show */
201 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100202 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100203 }
204 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100205}
206
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200207DeviceState *qdev_device_add(QemuOpts *opts)
208{
209 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200210 DeviceInfo *info;
211 DeviceState *qdev;
212 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200213
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200214 driver = qemu_opt_get(opts, "driver");
215 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100216 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200217 return NULL;
218 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200219
220 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200221 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100222 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100223 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100224 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200225 return NULL;
226 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200227
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200228 /* find bus */
229 path = qemu_opt_get(opts, "bus");
230 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200231 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100232 if (!bus) {
233 return NULL;
234 }
235 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100236 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
237 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100238 return NULL;
239 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200240 } else {
241 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100242 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100243 qerror_report(QERR_NO_BUS_FOR_DEVICE,
244 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100245 return NULL;
246 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200247 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200248 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100249 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200250 return NULL;
251 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200252
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200253 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100254 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200255 id = qemu_opts_id(opts);
256 if (id) {
257 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200258 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200259 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
260 qdev_free(qdev);
261 return NULL;
262 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200263 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100264 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200265 return NULL;
266 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200267 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200268 return qdev;
269}
270
Paul Brookaae94602009-05-14 22:35:06 +0100271/* Initialize a device. Device properties should be set before calling
272 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200273 calling this function.
274 On failure, destroy the device and return negative value.
275 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200276int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100277{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200278 int rc;
279
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200280 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200281 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200282 if (rc < 0) {
283 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200284 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200285 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200286 if (dev->info->vmsd) {
Alex Williamson0be71e32010-06-25 11:09:07 -0600287 vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200288 dev->instance_id_alias,
289 dev->alias_required_for_version);
290 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200291 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200292 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100293}
294
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200295void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
296 int required_for_version)
297{
298 assert(dev->state == DEV_STATE_CREATED);
299 dev->instance_id_alias = alias_id;
300 dev->alias_required_for_version = required_for_version;
301}
302
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200303int qdev_unplug(DeviceState *dev)
304{
305 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100306 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200307 return -1;
308 }
Amit Shah593831d2009-11-02 14:56:41 +0530309 assert(dev->info->unplug != NULL);
310
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700311 qdev_hot_removed = true;
312
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200313 return dev->info->unplug(dev);
314}
315
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900316static int qdev_reset_one(DeviceState *dev, void *opaque)
317{
318 if (dev->info->reset) {
319 dev->info->reset(dev);
320 }
321
322 return 0;
323}
324
325BusState *sysbus_get_default(void)
326{
Stefan Weil68694892010-12-16 19:33:22 +0100327 if (!main_system_bus) {
328 main_system_bus = qbus_create(&system_bus_info, NULL,
329 "main-system-bus");
330 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900331 return main_system_bus;
332}
333
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900334static int qbus_reset_one(BusState *bus, void *opaque)
335{
336 if (bus->info->reset) {
337 return bus->info->reset(bus);
338 }
339 return 0;
340}
341
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900342void qdev_reset_all(DeviceState *dev)
343{
344 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
345}
346
Isaku Yamahata80376c32010-12-20 14:33:35 +0900347void qbus_reset_all_fn(void *opaque)
348{
349 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200350 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900351}
352
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200353/* can be used as ->unplug() callback for the simple cases */
354int qdev_simple_unplug_cb(DeviceState *dev)
355{
356 /* just zap it */
357 qdev_free(dev);
358 return 0;
359}
360
Michael Tokarev3b29a102011-04-06 17:51:59 +0400361
362/* Like qdev_init(), but terminate program via error_report() instead of
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200363 returning an error value. This is okay during machine creation.
364 Don't use for hotplug, because there callers need to recover from
365 failure. Exception: if you know the device's init() callback can't
366 fail, then qdev_init_nofail() can't fail either, and is therefore
367 usable even then. But relying on the device implementation that
368 way is somewhat unclean, and best avoided. */
369void qdev_init_nofail(DeviceState *dev)
370{
371 DeviceInfo *info = dev->info;
372
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200373 if (qdev_init(dev) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +0200374 error_report("Initialization of device %s failed", info->name);
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200375 exit(1);
376 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200377}
378
Paul Brook02e2da42009-05-23 00:05:19 +0100379/* Unlink device from bus and free the structure. */
380void qdev_free(DeviceState *dev)
381{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200382 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200383 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200384
385 if (dev->state == DEV_STATE_INITIALIZED) {
386 while (dev->num_child_bus) {
387 bus = QLIST_FIRST(&dev->child_bus);
388 qbus_free(bus);
389 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200390 if (dev->info->vmsd)
Alex Williamson0be71e32010-06-25 11:09:07 -0600391 vmstate_unregister(dev, dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200392 if (dev->info->exit)
393 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200394 if (dev->opts)
395 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200396 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000397 QLIST_REMOVE(dev, sibling);
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200398 for (prop = dev->info->props; prop && prop->name; prop++) {
399 if (prop->info->free) {
400 prop->info->free(dev, prop);
401 }
402 }
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200403 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100404}
405
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200406void qdev_machine_creation_done(void)
407{
408 /*
409 * ok, initial machine setup is done, starting from now we can
410 * only create hotpluggable devices
411 */
412 qdev_hotplug = 1;
413}
414
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700415bool qdev_machine_modified(void)
416{
417 return qdev_hot_added || qdev_hot_removed;
418}
419
Paul Brookaae94602009-05-14 22:35:06 +0100420/* Get a character (serial) device interface. */
421CharDriverState *qdev_init_chardev(DeviceState *dev)
422{
423 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530424
425 /* FIXME: This function needs to go away: use chardev properties! */
426 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100427}
428
Paul Brook02e2da42009-05-23 00:05:19 +0100429BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100430{
Paul Brook02e2da42009-05-23 00:05:19 +0100431 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100432}
433
Paul Brookaae94602009-05-14 22:35:06 +0100434void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
435{
436 assert(dev->num_gpio_in == 0);
437 dev->num_gpio_in = n;
438 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
439}
440
441void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
442{
443 assert(dev->num_gpio_out == 0);
444 dev->num_gpio_out = n;
445 dev->gpio_out = pins;
446}
447
448qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
449{
450 assert(n >= 0 && n < dev->num_gpio_in);
451 return dev->gpio_in[n];
452}
453
454void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
455{
456 assert(n >= 0 && n < dev->num_gpio_out);
457 dev->gpio_out[n] = pin;
458}
459
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200460void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
461{
462 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
463 if (nd->vlan)
464 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
465 if (nd->netdev)
466 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530467 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200468 qdev_prop_exists(dev, "vectors")) {
469 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
470 }
Peter Maydell48e2faf2011-05-20 16:50:01 +0100471 nd->instantiated = 1;
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200472}
473
Paul Brook02e2da42009-05-23 00:05:19 +0100474BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100475{
Paul Brook02e2da42009-05-23 00:05:19 +0100476 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100477
Blue Swirl72cf2d42009-09-12 07:36:22 +0000478 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100479 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100480 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100481 }
482 }
483 return NULL;
484}
485
Anthony Liguori81699d82010-11-19 18:55:58 +0900486int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
487 qbus_walkerfn *busfn, void *opaque)
488{
489 DeviceState *dev;
490 int err;
491
492 if (busfn) {
493 err = busfn(bus, opaque);
494 if (err) {
495 return err;
496 }
497 }
498
499 QLIST_FOREACH(dev, &bus->children, sibling) {
500 err = qdev_walk_children(dev, devfn, busfn, opaque);
501 if (err < 0) {
502 return err;
503 }
504 }
505
506 return 0;
507}
508
509int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
510 qbus_walkerfn *busfn, void *opaque)
511{
512 BusState *bus;
513 int err;
514
515 if (devfn) {
516 err = devfn(dev, opaque);
517 if (err) {
518 return err;
519 }
520 }
521
522 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
523 err = qbus_walk_children(bus, devfn, busfn, opaque);
524 if (err < 0) {
525 return err;
526 }
527 }
528
529 return 0;
530}
531
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200532static BusState *qbus_find_recursive(BusState *bus, const char *name,
533 const BusInfo *info)
534{
535 DeviceState *dev;
536 BusState *child, *ret;
537 int match = 1;
538
539 if (name && (strcmp(bus->name, name) != 0)) {
540 match = 0;
541 }
542 if (info && (bus->info != info)) {
543 match = 0;
544 }
545 if (match) {
546 return bus;
547 }
548
Blue Swirl72cf2d42009-09-12 07:36:22 +0000549 QLIST_FOREACH(dev, &bus->children, sibling) {
550 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200551 ret = qbus_find_recursive(child, name, info);
552 if (ret) {
553 return ret;
554 }
555 }
556 }
557 return NULL;
558}
559
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900560DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200561{
562 DeviceState *dev, *ret;
563 BusState *child;
564
565 QLIST_FOREACH(dev, &bus->children, sibling) {
566 if (dev->id && strcmp(dev->id, id) == 0)
567 return dev;
568 QLIST_FOREACH(child, &dev->child_bus, sibling) {
569 ret = qdev_find_recursive(child, id);
570 if (ret) {
571 return ret;
572 }
573 }
574 }
575 return NULL;
576}
577
Markus Armbruster53db16b2010-02-18 18:55:59 +0100578static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200579{
580 BusState *child;
581 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200582
Markus Armbruster53db16b2010-02-18 18:55:59 +0100583 error_printf("child busses at \"%s\":",
584 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000585 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100586 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200587 sep = ", ";
588 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100589 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200590}
591
Markus Armbruster53db16b2010-02-18 18:55:59 +0100592static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200593{
594 DeviceState *dev;
595 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200596
Markus Armbruster53db16b2010-02-18 18:55:59 +0100597 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000598 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100599 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200600 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100601 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200602 sep = ", ";
603 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100604 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200605}
606
607static BusState *qbus_find_bus(DeviceState *dev, char *elem)
608{
609 BusState *child;
610
Blue Swirl72cf2d42009-09-12 07:36:22 +0000611 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200612 if (strcmp(child->name, elem) == 0) {
613 return child;
614 }
615 }
616 return NULL;
617}
618
619static DeviceState *qbus_find_dev(BusState *bus, char *elem)
620{
621 DeviceState *dev;
622
623 /*
624 * try to match in order:
625 * (1) instance id, if present
626 * (2) driver name
627 * (3) driver alias, if present
628 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000629 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200630 if (dev->id && strcmp(dev->id, elem) == 0) {
631 return dev;
632 }
633 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000634 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200635 if (strcmp(dev->info->name, elem) == 0) {
636 return dev;
637 }
638 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000639 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200640 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
641 return dev;
642 }
643 }
644 return NULL;
645}
646
647static BusState *qbus_find(const char *path)
648{
649 DeviceState *dev;
650 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100651 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200652 int pos, len;
653
654 /* find start element */
655 if (path[0] == '/') {
656 bus = main_system_bus;
657 pos = 0;
658 } else {
659 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100660 assert(!path[0]);
661 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200662 }
663 bus = qbus_find_recursive(main_system_bus, elem, NULL);
664 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100665 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200666 return NULL;
667 }
668 pos = len;
669 }
670
671 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100672 assert(path[pos] == '/' || !path[pos]);
673 while (path[pos] == '/') {
674 pos++;
675 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200676 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200677 return bus;
678 }
679
680 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100681 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
682 assert(0);
683 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200684 }
685 pos += len;
686 dev = qbus_find_dev(bus, elem);
687 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100688 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100689 if (!monitor_cur_is_qmp()) {
690 qbus_list_dev(bus);
691 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200692 return NULL;
693 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100694
695 assert(path[pos] == '/' || !path[pos]);
696 while (path[pos] == '/') {
697 pos++;
698 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200699 if (path[pos] == '\0') {
700 /* last specified element is a device. If it has exactly
701 * one child bus accept it nevertheless */
702 switch (dev->num_child_bus) {
703 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100704 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200705 return NULL;
706 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000707 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200708 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100709 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100710 if (!monitor_cur_is_qmp()) {
711 qbus_list_bus(dev);
712 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200713 return NULL;
714 }
715 }
716
717 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100718 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
719 assert(0);
720 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200721 }
722 pos += len;
723 bus = qbus_find_bus(dev, elem);
724 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100725 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100726 if (!monitor_cur_is_qmp()) {
727 qbus_list_bus(dev);
728 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200729 return NULL;
730 }
731 }
732}
733
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200734void qbus_create_inplace(BusState *bus, BusInfo *info,
735 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100736{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200737 char *buf;
738 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100739
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200740 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100741 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200742
743 if (name) {
744 /* use supplied name */
745 bus->name = qemu_strdup(name);
746 } else if (parent && parent->id) {
747 /* parent device has id -> use it for bus name */
748 len = strlen(parent->id) + 16;
749 buf = qemu_malloc(len);
750 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
751 bus->name = buf;
752 } else {
753 /* no id -> use lowercase bus type for bus name */
754 len = strlen(info->name) + 16;
755 buf = qemu_malloc(len);
756 len = snprintf(buf, len, "%s.%d", info->name,
757 parent ? parent->num_child_bus : 0);
758 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200759 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200760 bus->name = buf;
761 }
762
Blue Swirl72cf2d42009-09-12 07:36:22 +0000763 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100764 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000765 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200766 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900767 } else if (bus != main_system_bus) {
768 /* TODO: once all bus devices are qdevified,
769 only reset handler for main_system_bus should be registered here. */
770 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100771 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200772}
773
774BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
775{
776 BusState *bus;
777
778 bus = qemu_mallocz(info->size);
779 bus->qdev_allocated = 1;
780 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100781 return bus;
782}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100783
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200784void qbus_free(BusState *bus)
785{
786 DeviceState *dev;
787
788 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
789 qdev_free(dev);
790 }
791 if (bus->parent) {
792 QLIST_REMOVE(bus, sibling);
793 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900794 } else {
795 assert(bus != main_system_bus); /* main_system_bus is never freed */
796 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200797 }
Isaku Yamahatae163ae72010-05-27 14:35:58 +0900798 qemu_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200799 if (bus->qdev_allocated) {
800 qemu_free(bus);
801 }
802}
803
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100804#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
805static void qbus_print(Monitor *mon, BusState *bus, int indent);
806
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200807static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
808 const char *prefix, int indent)
809{
810 char buf[64];
811
812 if (!props)
813 return;
814 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100815 /*
816 * TODO Properties without a print method are just for dirty
817 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
818 * marked for removal. The test props->info->print should be
819 * removed along with it.
820 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200821 if (props->info->print) {
822 props->info->print(dev, props, buf, sizeof(buf));
823 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
824 }
825 props++;
826 }
827}
828
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100829static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
830{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100831 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200832 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
833 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100834 indent += 2;
835 if (dev->num_gpio_in) {
836 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
837 }
838 if (dev->num_gpio_out) {
839 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
840 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200841 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
842 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200843 if (dev->parent_bus->info->print_dev)
844 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000845 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100846 qbus_print(mon, child, indent);
847 }
848}
849
850static void qbus_print(Monitor *mon, BusState *bus, int indent)
851{
852 struct DeviceState *dev;
853
854 qdev_printf("bus: %s\n", bus->name);
855 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200856 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000857 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100858 qdev_print(mon, dev, indent);
859 }
860}
861#undef qdev_printf
862
863void do_info_qtree(Monitor *mon)
864{
865 if (main_system_bus)
866 qbus_print(mon, main_system_bus, 0);
867}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200868
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200869void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200870{
871 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200872
873 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100874 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200875 }
876}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200877
Markus Armbruster8bc27242010-02-10 20:52:01 +0100878int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200879{
880 QemuOpts *opts;
881
Gerd Hoffmann3329f072010-08-20 13:52:01 +0200882 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100883 if (!opts) {
884 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +0100885 }
Markus Armbruster8bc27242010-02-10 20:52:01 +0100886 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
887 qemu_opts_del(opts);
888 return 0;
889 }
890 if (!qdev_device_add(opts)) {
891 qemu_opts_del(opts);
892 return -1;
893 }
894 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200895}
896
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100897int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200898{
899 const char *id = qdict_get_str(qdict, "id");
900 DeviceState *dev;
901
902 dev = qdev_find_recursive(main_system_bus, id);
903 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100904 qerror_report(QERR_DEVICE_NOT_FOUND, id);
905 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200906 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100907 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200908}
Gleb Natapov1ca4d092010-12-08 13:35:05 +0200909
910static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
911{
912 int l = 0;
913
914 if (dev && dev->parent_bus) {
915 char *d;
916 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
917 if (dev->parent_bus->info->get_fw_dev_path) {
918 d = dev->parent_bus->info->get_fw_dev_path(dev);
919 l += snprintf(p + l, size - l, "%s", d);
920 qemu_free(d);
921 } else {
922 l += snprintf(p + l, size - l, "%s", dev->info->name);
923 }
924 }
925 l += snprintf(p + l , size - l, "/");
926
927 return l;
928}
929
930char* qdev_get_fw_dev_path(DeviceState *dev)
931{
932 char path[128];
933 int l;
934
935 l = qdev_get_fw_dev_path_helper(dev, path, 128);
936
937 path[l-1] = '\0';
938
939 return strdup(path);
940}