blob: 31eb464f23d505cea24ca58965442ab2252a1112 [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"
Blue Swirl24463332010-08-24 15:22:24 +000032#include "blockdev.h"
Paul Brookaae94602009-05-14 22:35:06 +010033
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020034static int qdev_hotplug = 0;
35
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020036/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000037static BusState *main_system_bus;
Paul Brook4d6ae672009-05-14 22:35:06 +010038
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010039DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010040
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020041static BusState *qbus_find_recursive(BusState *bus, const char *name,
42 const BusInfo *info);
43static BusState *qbus_find(const char *path);
44
Paul Brookaae94602009-05-14 22:35:06 +010045/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020046void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010047{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020048 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020049 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010050
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020051 info->next = device_info_list;
52 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010053}
54
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020055static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
56{
57 DeviceInfo *info;
58
Gerd Hoffmann3320e562009-07-15 13:43:33 +020059 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020060 for (info = device_info_list; info != NULL; info = info->next) {
61 if (bus_info && info->bus_info != bus_info)
62 continue;
63 if (strcmp(info->name, name) != 0)
64 continue;
65 return info;
66 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020067
68 /* failing that check the aliases */
69 for (info = device_info_list; info != NULL; info = info->next) {
70 if (bus_info && info->bus_info != bus_info)
71 continue;
72 if (!info->alias)
73 continue;
74 if (strcmp(info->alias, name) != 0)
75 continue;
76 return info;
77 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020078 return NULL;
79}
80
Markus Armbruster0c175422010-02-19 19:12:18 +010081static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010082{
Paul Brookaae94602009-05-14 22:35:06 +010083 DeviceState *dev;
84
Markus Armbruster0c175422010-02-19 19:12:18 +010085 assert(bus->info == info->bus_info);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020086 dev = qemu_mallocz(info->size);
87 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010088 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020089 qdev_prop_set_defaults(dev, dev->info->props);
90 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +010091 qdev_prop_set_globals(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +000092 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020093 if (qdev_hotplug) {
94 assert(bus->allow_hotplug);
95 dev->hotplugged = 1;
96 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +020097 dev->instance_id_alias = -1;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +020098 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +010099 return dev;
100}
101
Markus Armbruster0c175422010-02-19 19:12:18 +0100102/* Create a new device. This only initializes the device state structure
103 and allows properties to be set. qdev_init should be called to
104 initialize the actual device emulation. */
105DeviceState *qdev_create(BusState *bus, const char *name)
106{
107 DeviceInfo *info;
108
109 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100110 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100111 }
112
113 info = qdev_find_info(bus->info, name);
114 if (!info) {
115 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
116 }
117
118 return qdev_create_from_info(bus, info);
119}
120
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100121static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200122{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100123 error_printf("name \"%s\", bus %s",
124 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200125 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100126 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200127 }
128 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100129 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200130 }
131 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100132 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200133 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100134 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200135}
136
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200137static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200138{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200139 DeviceState *dev = opaque;
140
141 if (strcmp(name, "driver") == 0)
142 return 0;
143 if (strcmp(name, "bus") == 0)
144 return 0;
145
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100146 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200147 return -1;
148 }
149 return 0;
150}
151
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100152int qdev_device_help(QemuOpts *opts)
153{
154 const char *driver;
155 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100156 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100157
158 driver = qemu_opt_get(opts, "driver");
159 if (driver && !strcmp(driver, "?")) {
160 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100161 if (info->no_user) {
162 continue; /* not available, don't show */
163 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100164 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100165 }
166 return 1;
167 }
168
Markus Armbruster08350cf2010-01-29 19:49:00 +0100169 if (!qemu_opt_get(opts, "?")) {
170 return 0;
171 }
172
173 info = qdev_find_info(NULL, driver);
174 if (!info) {
175 return 0;
176 }
177
178 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100179 /*
180 * TODO Properties without a parser are just for dirty hacks.
181 * qdev_prop_ptr is the only such PropertyInfo. It's marked
182 * for removal. This conditional should be removed along with
183 * it.
184 */
185 if (!prop->info->parse) {
186 continue; /* no way to set it, don't show */
187 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100188 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100189 }
190 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100191}
192
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200193DeviceState *qdev_device_add(QemuOpts *opts)
194{
195 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200196 DeviceInfo *info;
197 DeviceState *qdev;
198 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200199
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200200 driver = qemu_opt_get(opts, "driver");
201 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100202 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200203 return NULL;
204 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200205
206 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200207 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100208 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100209 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100210 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200211 return NULL;
212 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200213
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200214 /* find bus */
215 path = qemu_opt_get(opts, "bus");
216 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200217 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100218 if (!bus) {
219 return NULL;
220 }
221 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100222 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
223 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100224 return NULL;
225 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200226 } else {
227 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100228 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100229 qerror_report(QERR_NO_BUS_FOR_DEVICE,
230 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100231 return NULL;
232 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200233 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200234 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100235 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200236 return NULL;
237 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200238
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200239 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100240 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200241 id = qemu_opts_id(opts);
242 if (id) {
243 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200244 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200245 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
246 qdev_free(qdev);
247 return NULL;
248 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200249 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100250 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200251 return NULL;
252 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200253 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200254 return qdev;
255}
256
Paul Brookaae94602009-05-14 22:35:06 +0100257/* Initialize a device. Device properties should be set before calling
258 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200259 calling this function.
260 On failure, destroy the device and return negative value.
261 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200262int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100263{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200264 int rc;
265
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200266 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200267 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200268 if (rc < 0) {
269 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200270 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200271 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200272 if (dev->info->vmsd) {
Alex Williamson0be71e32010-06-25 11:09:07 -0600273 vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200274 dev->instance_id_alias,
275 dev->alias_required_for_version);
276 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200277 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200278 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100279}
280
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200281void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
282 int required_for_version)
283{
284 assert(dev->state == DEV_STATE_CREATED);
285 dev->instance_id_alias = alias_id;
286 dev->alias_required_for_version = required_for_version;
287}
288
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200289int qdev_unplug(DeviceState *dev)
290{
291 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100292 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200293 return -1;
294 }
Amit Shah593831d2009-11-02 14:56:41 +0530295 assert(dev->info->unplug != NULL);
296
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200297 return dev->info->unplug(dev);
298}
299
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900300static int qdev_reset_one(DeviceState *dev, void *opaque)
301{
302 if (dev->info->reset) {
303 dev->info->reset(dev);
304 }
305
306 return 0;
307}
308
309BusState *sysbus_get_default(void)
310{
Stefan Weil68694892010-12-16 19:33:22 +0100311 if (!main_system_bus) {
312 main_system_bus = qbus_create(&system_bus_info, NULL,
313 "main-system-bus");
314 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900315 return main_system_bus;
316}
317
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900318static int qbus_reset_one(BusState *bus, void *opaque)
319{
320 if (bus->info->reset) {
321 return bus->info->reset(bus);
322 }
323 return 0;
324}
325
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900326void qdev_reset_all(DeviceState *dev)
327{
328 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
329}
330
Isaku Yamahata80376c32010-12-20 14:33:35 +0900331void qbus_reset_all_fn(void *opaque)
332{
333 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200334 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900335}
336
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200337/* can be used as ->unplug() callback for the simple cases */
338int qdev_simple_unplug_cb(DeviceState *dev)
339{
340 /* just zap it */
341 qdev_free(dev);
342 return 0;
343}
344
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200345/* Like qdev_init(), but terminate program via hw_error() instead of
346 returning an error value. This is okay during machine creation.
347 Don't use for hotplug, because there callers need to recover from
348 failure. Exception: if you know the device's init() callback can't
349 fail, then qdev_init_nofail() can't fail either, and is therefore
350 usable even then. But relying on the device implementation that
351 way is somewhat unclean, and best avoided. */
352void qdev_init_nofail(DeviceState *dev)
353{
354 DeviceInfo *info = dev->info;
355
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200356 if (qdev_init(dev) < 0) {
357 error_report("Initialization of device %s failed\n", info->name);
358 exit(1);
359 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200360}
361
Paul Brook02e2da42009-05-23 00:05:19 +0100362/* Unlink device from bus and free the structure. */
363void qdev_free(DeviceState *dev)
364{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200365 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200366 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200367
368 if (dev->state == DEV_STATE_INITIALIZED) {
369 while (dev->num_child_bus) {
370 bus = QLIST_FIRST(&dev->child_bus);
371 qbus_free(bus);
372 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200373 if (dev->info->vmsd)
Alex Williamson0be71e32010-06-25 11:09:07 -0600374 vmstate_unregister(dev, dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200375 if (dev->info->exit)
376 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200377 if (dev->opts)
378 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200379 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000380 QLIST_REMOVE(dev, sibling);
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200381 for (prop = dev->info->props; prop && prop->name; prop++) {
382 if (prop->info->free) {
383 prop->info->free(dev, prop);
384 }
385 }
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200386 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100387}
388
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200389void qdev_machine_creation_done(void)
390{
391 /*
392 * ok, initial machine setup is done, starting from now we can
393 * only create hotpluggable devices
394 */
395 qdev_hotplug = 1;
396}
397
Paul Brookaae94602009-05-14 22:35:06 +0100398/* Get a character (serial) device interface. */
399CharDriverState *qdev_init_chardev(DeviceState *dev)
400{
401 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530402
403 /* FIXME: This function needs to go away: use chardev properties! */
404 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100405}
406
Paul Brook02e2da42009-05-23 00:05:19 +0100407BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100408{
Paul Brook02e2da42009-05-23 00:05:19 +0100409 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100410}
411
Paul Brookaae94602009-05-14 22:35:06 +0100412void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
413{
414 assert(dev->num_gpio_in == 0);
415 dev->num_gpio_in = n;
416 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
417}
418
419void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
420{
421 assert(dev->num_gpio_out == 0);
422 dev->num_gpio_out = n;
423 dev->gpio_out = pins;
424}
425
426qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
427{
428 assert(n >= 0 && n < dev->num_gpio_in);
429 return dev->gpio_in[n];
430}
431
432void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
433{
434 assert(n >= 0 && n < dev->num_gpio_out);
435 dev->gpio_out[n] = pin;
436}
437
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200438void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
439{
440 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
441 if (nd->vlan)
442 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
443 if (nd->netdev)
444 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530445 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200446 qdev_prop_exists(dev, "vectors")) {
447 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
448 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200449}
450
Paul Brookaae94602009-05-14 22:35:06 +0100451static int next_block_unit[IF_COUNT];
452
453/* Get a block device. This should only be used for single-drive devices
454 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
455 appropriate bus. */
456BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
457{
458 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200459 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100460
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200461 dinfo = drive_get(type, 0, unit);
462 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100463}
Paul Brook4d6ae672009-05-14 22:35:06 +0100464
Paul Brook02e2da42009-05-23 00:05:19 +0100465BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100466{
Paul Brook02e2da42009-05-23 00:05:19 +0100467 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100468
Blue Swirl72cf2d42009-09-12 07:36:22 +0000469 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100470 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100471 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100472 }
473 }
474 return NULL;
475}
476
Anthony Liguori81699d82010-11-19 18:55:58 +0900477int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
478 qbus_walkerfn *busfn, void *opaque)
479{
480 DeviceState *dev;
481 int err;
482
483 if (busfn) {
484 err = busfn(bus, opaque);
485 if (err) {
486 return err;
487 }
488 }
489
490 QLIST_FOREACH(dev, &bus->children, sibling) {
491 err = qdev_walk_children(dev, devfn, busfn, opaque);
492 if (err < 0) {
493 return err;
494 }
495 }
496
497 return 0;
498}
499
500int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
501 qbus_walkerfn *busfn, void *opaque)
502{
503 BusState *bus;
504 int err;
505
506 if (devfn) {
507 err = devfn(dev, opaque);
508 if (err) {
509 return err;
510 }
511 }
512
513 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
514 err = qbus_walk_children(bus, devfn, busfn, opaque);
515 if (err < 0) {
516 return err;
517 }
518 }
519
520 return 0;
521}
522
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200523static BusState *qbus_find_recursive(BusState *bus, const char *name,
524 const BusInfo *info)
525{
526 DeviceState *dev;
527 BusState *child, *ret;
528 int match = 1;
529
530 if (name && (strcmp(bus->name, name) != 0)) {
531 match = 0;
532 }
533 if (info && (bus->info != info)) {
534 match = 0;
535 }
536 if (match) {
537 return bus;
538 }
539
Blue Swirl72cf2d42009-09-12 07:36:22 +0000540 QLIST_FOREACH(dev, &bus->children, sibling) {
541 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200542 ret = qbus_find_recursive(child, name, info);
543 if (ret) {
544 return ret;
545 }
546 }
547 }
548 return NULL;
549}
550
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900551DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200552{
553 DeviceState *dev, *ret;
554 BusState *child;
555
556 QLIST_FOREACH(dev, &bus->children, sibling) {
557 if (dev->id && strcmp(dev->id, id) == 0)
558 return dev;
559 QLIST_FOREACH(child, &dev->child_bus, sibling) {
560 ret = qdev_find_recursive(child, id);
561 if (ret) {
562 return ret;
563 }
564 }
565 }
566 return NULL;
567}
568
Markus Armbruster53db16b2010-02-18 18:55:59 +0100569static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200570{
571 BusState *child;
572 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200573
Markus Armbruster53db16b2010-02-18 18:55:59 +0100574 error_printf("child busses at \"%s\":",
575 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000576 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100577 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200578 sep = ", ";
579 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100580 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200581}
582
Markus Armbruster53db16b2010-02-18 18:55:59 +0100583static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200584{
585 DeviceState *dev;
586 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200587
Markus Armbruster53db16b2010-02-18 18:55:59 +0100588 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000589 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100590 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200591 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100592 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200593 sep = ", ";
594 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100595 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200596}
597
598static BusState *qbus_find_bus(DeviceState *dev, char *elem)
599{
600 BusState *child;
601
Blue Swirl72cf2d42009-09-12 07:36:22 +0000602 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200603 if (strcmp(child->name, elem) == 0) {
604 return child;
605 }
606 }
607 return NULL;
608}
609
610static DeviceState *qbus_find_dev(BusState *bus, char *elem)
611{
612 DeviceState *dev;
613
614 /*
615 * try to match in order:
616 * (1) instance id, if present
617 * (2) driver name
618 * (3) driver alias, if present
619 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000620 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200621 if (dev->id && strcmp(dev->id, elem) == 0) {
622 return dev;
623 }
624 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000625 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200626 if (strcmp(dev->info->name, elem) == 0) {
627 return dev;
628 }
629 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000630 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200631 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
632 return dev;
633 }
634 }
635 return NULL;
636}
637
638static BusState *qbus_find(const char *path)
639{
640 DeviceState *dev;
641 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100642 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200643 int pos, len;
644
645 /* find start element */
646 if (path[0] == '/') {
647 bus = main_system_bus;
648 pos = 0;
649 } else {
650 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100651 assert(!path[0]);
652 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200653 }
654 bus = qbus_find_recursive(main_system_bus, elem, NULL);
655 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100656 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200657 return NULL;
658 }
659 pos = len;
660 }
661
662 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100663 assert(path[pos] == '/' || !path[pos]);
664 while (path[pos] == '/') {
665 pos++;
666 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200667 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200668 return bus;
669 }
670
671 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100672 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
673 assert(0);
674 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200675 }
676 pos += len;
677 dev = qbus_find_dev(bus, elem);
678 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100679 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100680 if (!monitor_cur_is_qmp()) {
681 qbus_list_dev(bus);
682 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200683 return NULL;
684 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100685
686 assert(path[pos] == '/' || !path[pos]);
687 while (path[pos] == '/') {
688 pos++;
689 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200690 if (path[pos] == '\0') {
691 /* last specified element is a device. If it has exactly
692 * one child bus accept it nevertheless */
693 switch (dev->num_child_bus) {
694 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100695 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200696 return NULL;
697 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000698 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200699 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100700 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100701 if (!monitor_cur_is_qmp()) {
702 qbus_list_bus(dev);
703 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200704 return NULL;
705 }
706 }
707
708 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100709 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
710 assert(0);
711 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200712 }
713 pos += len;
714 bus = qbus_find_bus(dev, elem);
715 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100716 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100717 if (!monitor_cur_is_qmp()) {
718 qbus_list_bus(dev);
719 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200720 return NULL;
721 }
722 }
723}
724
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200725void qbus_create_inplace(BusState *bus, BusInfo *info,
726 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100727{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200728 char *buf;
729 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100730
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200731 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100732 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200733
734 if (name) {
735 /* use supplied name */
736 bus->name = qemu_strdup(name);
737 } else if (parent && parent->id) {
738 /* parent device has id -> use it for bus name */
739 len = strlen(parent->id) + 16;
740 buf = qemu_malloc(len);
741 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
742 bus->name = buf;
743 } else {
744 /* no id -> use lowercase bus type for bus name */
745 len = strlen(info->name) + 16;
746 buf = qemu_malloc(len);
747 len = snprintf(buf, len, "%s.%d", info->name,
748 parent ? parent->num_child_bus : 0);
749 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200750 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200751 bus->name = buf;
752 }
753
Blue Swirl72cf2d42009-09-12 07:36:22 +0000754 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100755 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000756 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200757 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900758 } else if (bus != main_system_bus) {
759 /* TODO: once all bus devices are qdevified,
760 only reset handler for main_system_bus should be registered here. */
761 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100762 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200763}
764
765BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
766{
767 BusState *bus;
768
769 bus = qemu_mallocz(info->size);
770 bus->qdev_allocated = 1;
771 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100772 return bus;
773}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100774
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200775void qbus_free(BusState *bus)
776{
777 DeviceState *dev;
778
779 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
780 qdev_free(dev);
781 }
782 if (bus->parent) {
783 QLIST_REMOVE(bus, sibling);
784 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900785 } else {
786 assert(bus != main_system_bus); /* main_system_bus is never freed */
787 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200788 }
Isaku Yamahatae163ae72010-05-27 14:35:58 +0900789 qemu_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200790 if (bus->qdev_allocated) {
791 qemu_free(bus);
792 }
793}
794
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100795#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
796static void qbus_print(Monitor *mon, BusState *bus, int indent);
797
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200798static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
799 const char *prefix, int indent)
800{
801 char buf[64];
802
803 if (!props)
804 return;
805 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100806 /*
807 * TODO Properties without a print method are just for dirty
808 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
809 * marked for removal. The test props->info->print should be
810 * removed along with it.
811 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200812 if (props->info->print) {
813 props->info->print(dev, props, buf, sizeof(buf));
814 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
815 }
816 props++;
817 }
818}
819
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100820static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
821{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100822 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200823 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
824 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100825 indent += 2;
826 if (dev->num_gpio_in) {
827 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
828 }
829 if (dev->num_gpio_out) {
830 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
831 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200832 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
833 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200834 if (dev->parent_bus->info->print_dev)
835 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000836 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100837 qbus_print(mon, child, indent);
838 }
839}
840
841static void qbus_print(Monitor *mon, BusState *bus, int indent)
842{
843 struct DeviceState *dev;
844
845 qdev_printf("bus: %s\n", bus->name);
846 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200847 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000848 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100849 qdev_print(mon, dev, indent);
850 }
851}
852#undef qdev_printf
853
854void do_info_qtree(Monitor *mon)
855{
856 if (main_system_bus)
857 qbus_print(mon, main_system_bus, 0);
858}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200859
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200860void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200861{
862 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200863
864 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100865 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200866 }
867}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200868
Markus Armbruster8bc27242010-02-10 20:52:01 +0100869int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200870{
871 QemuOpts *opts;
872
Gerd Hoffmann3329f072010-08-20 13:52:01 +0200873 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100874 if (!opts) {
875 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +0100876 }
Markus Armbruster8bc27242010-02-10 20:52:01 +0100877 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
878 qemu_opts_del(opts);
879 return 0;
880 }
881 if (!qdev_device_add(opts)) {
882 qemu_opts_del(opts);
883 return -1;
884 }
885 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200886}
887
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100888int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200889{
890 const char *id = qdict_get_str(qdict, "id");
891 DeviceState *dev;
892
893 dev = qdev_find_recursive(main_system_bus, id);
894 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100895 qerror_report(QERR_DEVICE_NOT_FOUND, id);
896 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200897 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100898 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200899}
Gleb Natapov1ca4d092010-12-08 13:35:05 +0200900
901static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
902{
903 int l = 0;
904
905 if (dev && dev->parent_bus) {
906 char *d;
907 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
908 if (dev->parent_bus->info->get_fw_dev_path) {
909 d = dev->parent_bus->info->get_fw_dev_path(dev);
910 l += snprintf(p + l, size - l, "%s", d);
911 qemu_free(d);
912 } else {
913 l += snprintf(p + l, size - l, "%s", dev->info->name);
914 }
915 }
916 l += snprintf(p + l , size - l, "/");
917
918 return l;
919}
920
921char* qdev_get_fw_dev_path(DeviceState *dev)
922{
923 char path[128];
924 int l;
925
926 l = qdev_get_fw_dev_path_helper(dev, path, 128);
927
928 path[l-1] = '\0';
929
930 return strdup(path);
931}