]> git.proxmox.com Git - mirror_qemu.git/blame - hw/qdev.c
qom: add vga node to the pc composition tree
[mirror_qemu.git] / hw / qdev.c
CommitLineData
aae9460e
PB
1/*
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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
aae9460e
PB
18 */
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
9d07d757 28#include "net.h"
aae9460e
PB
29#include "qdev.h"
30#include "sysemu.h"
cae4956e 31#include "monitor.h"
aae9460e 32
3418bd25 33static int qdev_hotplug = 0;
0ac8ef71
AW
34static bool qdev_hot_added = false;
35static bool qdev_hot_removed = false;
3418bd25 36
cdaed7c7 37/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
b9aaf7f8 38static BusState *main_system_bus;
2da8bb92 39static void main_system_bus_create(void);
4d6ae674 40
0958b4cc 41DeviceInfo *device_info_list;
aae9460e 42
8ffb1bcf
GH
43static BusState *qbus_find_recursive(BusState *bus, const char *name,
44 const BusInfo *info);
45static BusState *qbus_find(const char *path);
46
aae9460e 47/* Register a new device type. */
074f2fff 48void qdev_register(DeviceInfo *info)
aae9460e 49{
074f2fff 50 assert(info->size >= sizeof(DeviceState));
042f84d0 51 assert(!info->next);
aae9460e 52
042f84d0
GH
53 info->next = device_info_list;
54 device_info_list = info;
aae9460e
PB
55}
56
81ebb98b
GH
57static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
58{
59 DeviceInfo *info;
60
3320e56e 61 /* first check device names */
81ebb98b
GH
62 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 }
3320e56e
GH
69
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 }
81ebb98b
GH
80 return NULL;
81}
82
0c17542d
MA
83static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
84{
85 DeviceState *dev;
a5296ca9 86 Property *prop;
0c17542d
MA
87
88 assert(bus->info == info->bus_info);
7267c094 89 dev = g_malloc0(info->size);
0c17542d
MA
90 dev->info = info;
91 dev->parent_bus = bus;
92 qdev_prop_set_defaults(dev, dev->info->props);
93 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
94 qdev_prop_set_globals(dev);
d8bb00d6 95 QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
0c17542d
MA
96 if (qdev_hotplug) {
97 assert(bus->allow_hotplug);
98 dev->hotplugged = 1;
0ac8ef71 99 qdev_hot_added = true;
0c17542d 100 }
4d2ffa08 101 dev->instance_id_alias = -1;
44677ded 102 QTAILQ_INIT(&dev->properties);
0c17542d 103 dev->state = DEV_STATE_CREATED;
a5296ca9
AL
104
105 for (prop = dev->info->props; prop && prop->name; prop++) {
106 qdev_property_add_legacy(dev, prop, NULL);
107 }
108
109 for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
110 qdev_property_add_legacy(dev, prop, NULL);
111 }
112
0c17542d
MA
113 return dev;
114}
115
aae9460e
PB
116/* Create a new device. This only initializes the device state structure
117 and allows properties to be set. qdev_init should be called to
118 initialize the actual device emulation. */
02e2da45 119DeviceState *qdev_create(BusState *bus, const char *name)
0bcdeda7
BS
120{
121 DeviceState *dev;
122
123 dev = qdev_try_create(bus, name);
124 if (!dev) {
e92714c7
PM
125 if (bus) {
126 hw_error("Unknown device '%s' for bus '%s'\n", name,
127 bus->info->name);
128 } else {
129 hw_error("Unknown device '%s' for default sysbus\n", name);
130 }
0bcdeda7
BS
131 }
132
133 return dev;
134}
135
136DeviceState *qdev_try_create(BusState *bus, const char *name)
aae9460e 137{
042f84d0 138 DeviceInfo *info;
aae9460e 139
10c4c98a 140 if (!bus) {
68694897 141 bus = sysbus_get_default();
10c4c98a
GH
142 }
143
81ebb98b 144 info = qdev_find_info(bus->info, name);
042f84d0 145 if (!info) {
0bcdeda7 146 return NULL;
aae9460e
PB
147 }
148
0c17542d 149 return qdev_create_from_info(bus, info);
aae9460e
PB
150}
151
8a9662ca 152static void qdev_print_devinfo(DeviceInfo *info)
1b524b04 153{
8a9662ca
MA
154 error_printf("name \"%s\", bus %s",
155 info->name, info->bus_info->name);
22f2e344 156 if (info->alias) {
8a9662ca 157 error_printf(", alias \"%s\"", info->alias);
22f2e344
GH
158 }
159 if (info->desc) {
8a9662ca 160 error_printf(", desc \"%s\"", info->desc);
22f2e344
GH
161 }
162 if (info->no_user) {
8a9662ca 163 error_printf(", no-user");
22f2e344 164 }
8a9662ca 165 error_printf("\n");
1b524b04
GH
166}
167
f31d07d1 168static int set_property(const char *name, const char *value, void *opaque)
8ffb1bcf 169{
f31d07d1
GH
170 DeviceState *dev = opaque;
171
172 if (strcmp(name, "driver") == 0)
173 return 0;
174 if (strcmp(name, "bus") == 0)
175 return 0;
176
3df04ac3 177 if (qdev_prop_parse(dev, name, value) == -1) {
f31d07d1
GH
178 return -1;
179 }
180 return 0;
181}
182
ff952ba2
MA
183int qdev_device_help(QemuOpts *opts)
184{
185 const char *driver;
186 DeviceInfo *info;
08350cf0 187 Property *prop;
ff952ba2
MA
188
189 driver = qemu_opt_get(opts, "driver");
190 if (driver && !strcmp(driver, "?")) {
191 for (info = device_info_list; info != NULL; info = info->next) {
c64eafaf
MA
192 if (info->no_user) {
193 continue; /* not available, don't show */
194 }
8a9662ca 195 qdev_print_devinfo(info);
ff952ba2
MA
196 }
197 return 1;
198 }
199
542379f4 200 if (!driver || !qemu_opt_get(opts, "?")) {
08350cf0
MA
201 return 0;
202 }
203
204 info = qdev_find_info(NULL, driver);
205 if (!info) {
206 return 0;
207 }
208
209 for (prop = info->props; prop && prop->name; prop++) {
036f7166
MA
210 /*
211 * TODO Properties without a parser are just for dirty hacks.
212 * qdev_prop_ptr is the only such PropertyInfo. It's marked
213 * for removal. This conditional should be removed along with
214 * it.
215 */
216 if (!prop->info->parse) {
217 continue; /* no way to set it, don't show */
218 }
a8467c7a
GH
219 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
220 }
221 for (prop = info->bus_info->props; prop && prop->name; prop++) {
222 if (!prop->info->parse) {
223 continue; /* no way to set it, don't show */
224 }
8a9662ca 225 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
08350cf0
MA
226 }
227 return 1;
ff952ba2
MA
228}
229
1bdaacb1
AL
230static DeviceState *qdev_get_peripheral(void)
231{
232 static DeviceState *dev;
233
234 if (dev == NULL) {
235 dev = qdev_create(NULL, "container");
236 qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
237 qdev_init_nofail(dev);
238 }
239
240 return dev;
241}
242
8eb02831
AL
243static DeviceState *qdev_get_peripheral_anon(void)
244{
245 static DeviceState *dev;
246
247 if (dev == NULL) {
248 dev = qdev_create(NULL, "container");
249 qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
250 qdev_init_nofail(dev);
251 }
252
253 return dev;
254}
255
f31d07d1
GH
256DeviceState *qdev_device_add(QemuOpts *opts)
257{
258 const char *driver, *path, *id;
8ffb1bcf
GH
259 DeviceInfo *info;
260 DeviceState *qdev;
261 BusState *bus;
8ffb1bcf 262
f31d07d1
GH
263 driver = qemu_opt_get(opts, "driver");
264 if (!driver) {
0204276b 265 qerror_report(QERR_MISSING_PARAMETER, "driver");
8ffb1bcf
GH
266 return NULL;
267 }
f31d07d1
GH
268
269 /* find driver */
8ffb1bcf 270 info = qdev_find_info(NULL, driver);
c64eafaf 271 if (!info || info->no_user) {
e17ba87c 272 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
0204276b 273 error_printf_unless_qmp("Try with argument '?' for a list.\n");
8ffb1bcf
GH
274 return NULL;
275 }
8ffb1bcf 276
f31d07d1
GH
277 /* find bus */
278 path = qemu_opt_get(opts, "bus");
279 if (path != NULL) {
8ffb1bcf 280 bus = qbus_find(path);
ac8dae67
MA
281 if (!bus) {
282 return NULL;
283 }
284 if (bus->info != info->bus_info) {
0204276b
MA
285 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
286 driver, bus->info->name);
327867b6
MA
287 return NULL;
288 }
8ffb1bcf
GH
289 } else {
290 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
ac8dae67 291 if (!bus) {
0204276b
MA
292 qerror_report(QERR_NO_BUS_FOR_DEVICE,
293 info->name, info->bus_info->name);
ac8dae67
MA
294 return NULL;
295 }
75570088 296 }
3418bd25 297 if (qdev_hotplug && !bus->allow_hotplug) {
0204276b 298 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
3418bd25
GH
299 return NULL;
300 }
8ffb1bcf 301
f31d07d1 302 /* create device, set properties */
0c17542d 303 qdev = qdev_create_from_info(bus, info);
f31d07d1
GH
304 id = qemu_opts_id(opts);
305 if (id) {
306 qdev->id = id;
1bdaacb1 307 qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
8eb02831
AL
308 } else {
309 static int anon_count;
310 gchar *name = g_strdup_printf("device[%d]", anon_count++);
311 qdev_property_add_child(qdev_get_peripheral_anon(), name,
312 qdev, NULL);
313 g_free(name);
314 }
f31d07d1
GH
315 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
316 qdev_free(qdev);
317 return NULL;
8ffb1bcf 318 }
5c17ca25 319 if (qdev_init(qdev) < 0) {
0204276b 320 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
81a322d4
GH
321 return NULL;
322 }
ef80b466 323 qdev->opts = opts;
8ffb1bcf
GH
324 return qdev;
325}
326
aae9460e
PB
327/* Initialize a device. Device properties should be set before calling
328 this function. IRQs and MMIO regions should be connected/mapped after
18cfeb52
MA
329 calling this function.
330 On failure, destroy the device and return negative value.
331 Return 0 on success. */
81a322d4 332int qdev_init(DeviceState *dev)
aae9460e 333{
959f733a
GH
334 int rc;
335
131ec1bd 336 assert(dev->state == DEV_STATE_CREATED);
959f733a 337 rc = dev->info->init(dev, dev->info);
18cfeb52
MA
338 if (rc < 0) {
339 qdev_free(dev);
959f733a 340 return rc;
18cfeb52 341 }
4d2ffa08 342 if (dev->info->vmsd) {
0be71e32 343 vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
4d2ffa08
JK
344 dev->instance_id_alias,
345 dev->alias_required_for_version);
346 }
131ec1bd 347 dev->state = DEV_STATE_INITIALIZED;
5ab28c83
JK
348 if (dev->hotplugged && dev->info->reset) {
349 dev->info->reset(dev);
350 }
959f733a 351 return 0;
02e2da45
PB
352}
353
4d2ffa08
JK
354void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
355 int required_for_version)
356{
357 assert(dev->state == DEV_STATE_CREATED);
358 dev->instance_id_alias = alias_id;
359 dev->alias_required_for_version = required_for_version;
360}
361
3418bd25
GH
362int qdev_unplug(DeviceState *dev)
363{
364 if (!dev->parent_bus->allow_hotplug) {
cc601cb7 365 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
3418bd25
GH
366 return -1;
367 }
593831de
AS
368 assert(dev->info->unplug != NULL);
369
85ed303b
AL
370 if (dev->ref != 0) {
371 qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
372 return -1;
373 }
374
0ac8ef71
AW
375 qdev_hot_removed = true;
376
3418bd25
GH
377 return dev->info->unplug(dev);
378}
379
ec990eb6
AL
380static int qdev_reset_one(DeviceState *dev, void *opaque)
381{
382 if (dev->info->reset) {
383 dev->info->reset(dev);
384 }
385
386 return 0;
387}
388
389BusState *sysbus_get_default(void)
390{
68694897 391 if (!main_system_bus) {
2da8bb92 392 main_system_bus_create();
68694897 393 }
ec990eb6
AL
394 return main_system_bus;
395}
396
b4694b7c
IY
397static int qbus_reset_one(BusState *bus, void *opaque)
398{
399 if (bus->info->reset) {
400 return bus->info->reset(bus);
401 }
402 return 0;
403}
404
5af0a04b
IY
405void qdev_reset_all(DeviceState *dev)
406{
407 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
408}
409
80376c3f
IY
410void qbus_reset_all_fn(void *opaque)
411{
412 BusState *bus = opaque;
f530cce3 413 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
80376c3f
IY
414}
415
3418bd25
GH
416/* can be used as ->unplug() callback for the simple cases */
417int qdev_simple_unplug_cb(DeviceState *dev)
418{
419 /* just zap it */
420 qdev_free(dev);
421 return 0;
422}
423
3b29a101
MT
424
425/* Like qdev_init(), but terminate program via error_report() instead of
e23a1b33
MA
426 returning an error value. This is okay during machine creation.
427 Don't use for hotplug, because there callers need to recover from
428 failure. Exception: if you know the device's init() callback can't
429 fail, then qdev_init_nofail() can't fail either, and is therefore
430 usable even then. But relying on the device implementation that
431 way is somewhat unclean, and best avoided. */
432void qdev_init_nofail(DeviceState *dev)
433{
434 DeviceInfo *info = dev->info;
435
bd6c9a61 436 if (qdev_init(dev) < 0) {
6daf194d 437 error_report("Initialization of device %s failed", info->name);
bd6c9a61
MA
438 exit(1);
439 }
e23a1b33
MA
440}
441
44677ded
AL
442static void qdev_property_del_all(DeviceState *dev)
443{
444 while (!QTAILQ_EMPTY(&dev->properties)) {
445 DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
446
447 QTAILQ_REMOVE(&dev->properties, prop, node);
448
449 if (prop->release) {
450 prop->release(dev, prop->name, prop->opaque);
451 }
452
453 g_free(prop->name);
454 g_free(prop->type);
455 g_free(prop);
456 }
457}
458
02e2da45
PB
459/* Unlink device from bus and free the structure. */
460void qdev_free(DeviceState *dev)
461{
131ec1bd 462 BusState *bus;
d21357df 463 Property *prop;
131ec1bd 464
44677ded
AL
465 qdev_property_del_all(dev);
466
131ec1bd
GH
467 if (dev->state == DEV_STATE_INITIALIZED) {
468 while (dev->num_child_bus) {
469 bus = QLIST_FIRST(&dev->child_bus);
470 qbus_free(bus);
471 }
131ec1bd 472 if (dev->info->vmsd)
0be71e32 473 vmstate_unregister(dev, dev->info->vmsd, dev);
d29275f1
GH
474 if (dev->info->exit)
475 dev->info->exit(dev);
ef80b466
GH
476 if (dev->opts)
477 qemu_opts_del(dev->opts);
131ec1bd 478 }
d8bb00d6 479 QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
d21357df
MA
480 for (prop = dev->info->props; prop && prop->name; prop++) {
481 if (prop->info->free) {
482 prop->info->free(dev, prop);
483 }
484 }
7267c094 485 g_free(dev);
aae9460e
PB
486}
487
3418bd25
GH
488void qdev_machine_creation_done(void)
489{
490 /*
491 * ok, initial machine setup is done, starting from now we can
492 * only create hotpluggable devices
493 */
494 qdev_hotplug = 1;
495}
496
0ac8ef71
AW
497bool qdev_machine_modified(void)
498{
499 return qdev_hot_added || qdev_hot_removed;
500}
501
aae9460e
PB
502/* Get a character (serial) device interface. */
503CharDriverState *qdev_init_chardev(DeviceState *dev)
504{
505 static int next_serial;
98b19252
AS
506
507 /* FIXME: This function needs to go away: use chardev properties! */
508 return serial_hds[next_serial++];
aae9460e
PB
509}
510
02e2da45 511BusState *qdev_get_parent_bus(DeviceState *dev)
aae9460e 512{
02e2da45 513 return dev->parent_bus;
aae9460e
PB
514}
515
aae9460e
PB
516void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
517{
518 assert(dev->num_gpio_in == 0);
519 dev->num_gpio_in = n;
520 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
521}
522
523void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
524{
525 assert(dev->num_gpio_out == 0);
526 dev->num_gpio_out = n;
527 dev->gpio_out = pins;
528}
529
530qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
531{
532 assert(n >= 0 && n < dev->num_gpio_in);
533 return dev->gpio_in[n];
534}
535
536void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
537{
538 assert(n >= 0 && n < dev->num_gpio_out);
539 dev->gpio_out[n] = pin;
540}
541
ed16ab5a
GH
542void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
543{
6eed1856 544 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
ed16ab5a
GH
545 if (nd->vlan)
546 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
547 if (nd->netdev)
548 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
75422b0d 549 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
97b15621
GH
550 qdev_prop_exists(dev, "vectors")) {
551 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
552 }
48e2faf2 553 nd->instantiated = 1;
ed16ab5a
GH
554}
555
02e2da45 556BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
4d6ae674 557{
02e2da45 558 BusState *bus;
4d6ae674 559
72cf2d4f 560 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
4d6ae674 561 if (strcmp(name, bus->name) == 0) {
02e2da45 562 return bus;
4d6ae674
PB
563 }
564 }
565 return NULL;
566}
567
81699d8a
AL
568int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
569 qbus_walkerfn *busfn, void *opaque)
570{
571 DeviceState *dev;
572 int err;
573
574 if (busfn) {
575 err = busfn(bus, opaque);
576 if (err) {
577 return err;
578 }
579 }
580
d8bb00d6 581 QTAILQ_FOREACH(dev, &bus->children, sibling) {
81699d8a
AL
582 err = qdev_walk_children(dev, devfn, busfn, opaque);
583 if (err < 0) {
584 return err;
585 }
586 }
587
588 return 0;
589}
590
591int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
592 qbus_walkerfn *busfn, void *opaque)
593{
594 BusState *bus;
595 int err;
596
597 if (devfn) {
598 err = devfn(dev, opaque);
599 if (err) {
600 return err;
601 }
602 }
603
604 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
605 err = qbus_walk_children(bus, devfn, busfn, opaque);
606 if (err < 0) {
607 return err;
608 }
609 }
610
611 return 0;
612}
613
8ffb1bcf
GH
614static BusState *qbus_find_recursive(BusState *bus, const char *name,
615 const BusInfo *info)
616{
617 DeviceState *dev;
618 BusState *child, *ret;
619 int match = 1;
620
621 if (name && (strcmp(bus->name, name) != 0)) {
622 match = 0;
623 }
624 if (info && (bus->info != info)) {
625 match = 0;
626 }
627 if (match) {
628 return bus;
629 }
630
d8bb00d6 631 QTAILQ_FOREACH(dev, &bus->children, sibling) {
72cf2d4f 632 QLIST_FOREACH(child, &dev->child_bus, sibling) {
8ffb1bcf
GH
633 ret = qbus_find_recursive(child, name, info);
634 if (ret) {
635 return ret;
636 }
637 }
638 }
639 return NULL;
640}
641
a2ee6b4f 642DeviceState *qdev_find_recursive(BusState *bus, const char *id)
3418bd25
GH
643{
644 DeviceState *dev, *ret;
645 BusState *child;
646
d8bb00d6 647 QTAILQ_FOREACH(dev, &bus->children, sibling) {
3418bd25
GH
648 if (dev->id && strcmp(dev->id, id) == 0)
649 return dev;
650 QLIST_FOREACH(child, &dev->child_bus, sibling) {
651 ret = qdev_find_recursive(child, id);
652 if (ret) {
653 return ret;
654 }
655 }
656 }
657 return NULL;
658}
659
53db16b5 660static void qbus_list_bus(DeviceState *dev)
8ffb1bcf
GH
661{
662 BusState *child;
663 const char *sep = " ";
8ffb1bcf 664
53db16b5
MA
665 error_printf("child busses at \"%s\":",
666 dev->id ? dev->id : dev->info->name);
72cf2d4f 667 QLIST_FOREACH(child, &dev->child_bus, sibling) {
53db16b5 668 error_printf("%s\"%s\"", sep, child->name);
8ffb1bcf
GH
669 sep = ", ";
670 }
53db16b5 671 error_printf("\n");
8ffb1bcf
GH
672}
673
53db16b5 674static void qbus_list_dev(BusState *bus)
8ffb1bcf
GH
675{
676 DeviceState *dev;
677 const char *sep = " ";
8ffb1bcf 678
53db16b5 679 error_printf("devices at \"%s\":", bus->name);
d8bb00d6 680 QTAILQ_FOREACH(dev, &bus->children, sibling) {
53db16b5 681 error_printf("%s\"%s\"", sep, dev->info->name);
8ffb1bcf 682 if (dev->id)
53db16b5 683 error_printf("/\"%s\"", dev->id);
8ffb1bcf
GH
684 sep = ", ";
685 }
53db16b5 686 error_printf("\n");
8ffb1bcf
GH
687}
688
689static BusState *qbus_find_bus(DeviceState *dev, char *elem)
690{
691 BusState *child;
692
72cf2d4f 693 QLIST_FOREACH(child, &dev->child_bus, sibling) {
8ffb1bcf
GH
694 if (strcmp(child->name, elem) == 0) {
695 return child;
696 }
697 }
698 return NULL;
699}
700
701static DeviceState *qbus_find_dev(BusState *bus, char *elem)
702{
703 DeviceState *dev;
704
705 /*
706 * try to match in order:
707 * (1) instance id, if present
708 * (2) driver name
709 * (3) driver alias, if present
710 */
d8bb00d6 711 QTAILQ_FOREACH(dev, &bus->children, sibling) {
8ffb1bcf
GH
712 if (dev->id && strcmp(dev->id, elem) == 0) {
713 return dev;
714 }
715 }
d8bb00d6 716 QTAILQ_FOREACH(dev, &bus->children, sibling) {
8ffb1bcf
GH
717 if (strcmp(dev->info->name, elem) == 0) {
718 return dev;
719 }
720 }
d8bb00d6 721 QTAILQ_FOREACH(dev, &bus->children, sibling) {
8ffb1bcf
GH
722 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
723 return dev;
724 }
725 }
726 return NULL;
727}
728
729static BusState *qbus_find(const char *path)
730{
731 DeviceState *dev;
732 BusState *bus;
53db16b5 733 char elem[128];
8ffb1bcf
GH
734 int pos, len;
735
736 /* find start element */
737 if (path[0] == '/') {
738 bus = main_system_bus;
739 pos = 0;
740 } else {
741 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
fc98eb43
MA
742 assert(!path[0]);
743 elem[0] = len = 0;
8ffb1bcf
GH
744 }
745 bus = qbus_find_recursive(main_system_bus, elem, NULL);
746 if (!bus) {
ac8dae67 747 qerror_report(QERR_BUS_NOT_FOUND, elem);
8ffb1bcf
GH
748 return NULL;
749 }
750 pos = len;
751 }
752
753 for (;;) {
fc98eb43
MA
754 assert(path[pos] == '/' || !path[pos]);
755 while (path[pos] == '/') {
756 pos++;
757 }
8ffb1bcf 758 if (path[pos] == '\0') {
8ffb1bcf
GH
759 return bus;
760 }
761
762 /* find device */
fc98eb43
MA
763 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
764 assert(0);
765 elem[0] = len = 0;
8ffb1bcf
GH
766 }
767 pos += len;
768 dev = qbus_find_dev(bus, elem);
769 if (!dev) {
ac8dae67 770 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
8bc27249
MA
771 if (!monitor_cur_is_qmp()) {
772 qbus_list_dev(bus);
773 }
8ffb1bcf
GH
774 return NULL;
775 }
fc98eb43
MA
776
777 assert(path[pos] == '/' || !path[pos]);
778 while (path[pos] == '/') {
779 pos++;
780 }
8ffb1bcf
GH
781 if (path[pos] == '\0') {
782 /* last specified element is a device. If it has exactly
783 * one child bus accept it nevertheless */
784 switch (dev->num_child_bus) {
785 case 0:
ac8dae67 786 qerror_report(QERR_DEVICE_NO_BUS, elem);
8ffb1bcf
GH
787 return NULL;
788 case 1:
72cf2d4f 789 return QLIST_FIRST(&dev->child_bus);
8ffb1bcf 790 default:
ac8dae67 791 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
8bc27249
MA
792 if (!monitor_cur_is_qmp()) {
793 qbus_list_bus(dev);
794 }
8ffb1bcf
GH
795 return NULL;
796 }
797 }
798
799 /* find bus */
fc98eb43
MA
800 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
801 assert(0);
802 elem[0] = len = 0;
8ffb1bcf
GH
803 }
804 pos += len;
805 bus = qbus_find_bus(dev, elem);
806 if (!bus) {
ac8dae67 807 qerror_report(QERR_BUS_NOT_FOUND, elem);
8bc27249
MA
808 if (!monitor_cur_is_qmp()) {
809 qbus_list_bus(dev);
810 }
8ffb1bcf
GH
811 return NULL;
812 }
813 }
814}
815
cd739fb6
GH
816void qbus_create_inplace(BusState *bus, BusInfo *info,
817 DeviceState *parent, const char *name)
02e2da45 818{
d271de9f
GH
819 char *buf;
820 int i,len;
02e2da45 821
10c4c98a 822 bus->info = info;
02e2da45 823 bus->parent = parent;
d271de9f
GH
824
825 if (name) {
826 /* use supplied name */
7267c094 827 bus->name = g_strdup(name);
d271de9f
GH
828 } else if (parent && parent->id) {
829 /* parent device has id -> use it for bus name */
830 len = strlen(parent->id) + 16;
7267c094 831 buf = g_malloc(len);
d271de9f
GH
832 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
833 bus->name = buf;
834 } else {
835 /* no id -> use lowercase bus type for bus name */
836 len = strlen(info->name) + 16;
7267c094 837 buf = g_malloc(len);
d271de9f
GH
838 len = snprintf(buf, len, "%s.%d", info->name,
839 parent ? parent->num_child_bus : 0);
840 for (i = 0; i < len; i++)
bb87ece5 841 buf[i] = qemu_tolower(buf[i]);
d271de9f
GH
842 bus->name = buf;
843 }
844
d8bb00d6 845 QTAILQ_INIT(&bus->children);
02e2da45 846 if (parent) {
72cf2d4f 847 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
d271de9f 848 parent->num_child_bus++;
80376c3f
IY
849 } else if (bus != main_system_bus) {
850 /* TODO: once all bus devices are qdevified,
851 only reset handler for main_system_bus should be registered here. */
852 qemu_register_reset(qbus_reset_all_fn, bus);
02e2da45 853 }
cd739fb6
GH
854}
855
856BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
857{
858 BusState *bus;
859
7267c094 860 bus = g_malloc0(info->size);
cd739fb6
GH
861 bus->qdev_allocated = 1;
862 qbus_create_inplace(bus, info, parent, name);
02e2da45
PB
863 return bus;
864}
cae4956e 865
2da8bb92
IY
866static void main_system_bus_create(void)
867{
868 /* assign main_system_bus before qbus_create_inplace()
869 * in order to make "if (bus != main_system_bus)" work */
7267c094 870 main_system_bus = g_malloc0(system_bus_info.size);
2da8bb92
IY
871 main_system_bus->qdev_allocated = 1;
872 qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
873 "main-system-bus");
874}
875
131ec1bd
GH
876void qbus_free(BusState *bus)
877{
878 DeviceState *dev;
879
d8bb00d6 880 while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
131ec1bd
GH
881 qdev_free(dev);
882 }
883 if (bus->parent) {
884 QLIST_REMOVE(bus, sibling);
885 bus->parent->num_child_bus--;
80376c3f
IY
886 } else {
887 assert(bus != main_system_bus); /* main_system_bus is never freed */
888 qemu_unregister_reset(qbus_reset_all_fn, bus);
131ec1bd 889 }
7267c094 890 g_free((void*)bus->name);
131ec1bd 891 if (bus->qdev_allocated) {
7267c094 892 g_free(bus);
131ec1bd
GH
893 }
894}
895
cae4956e
GH
896#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
897static void qbus_print(Monitor *mon, BusState *bus, int indent);
898
ee6847d1
GH
899static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
900 const char *prefix, int indent)
901{
902 char buf[64];
903
904 if (!props)
905 return;
906 while (props->name) {
036f7166
MA
907 /*
908 * TODO Properties without a print method are just for dirty
909 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
910 * marked for removal. The test props->info->print should be
911 * removed along with it.
912 */
ee6847d1
GH
913 if (props->info->print) {
914 props->info->print(dev, props, buf, sizeof(buf));
915 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
916 }
917 props++;
918 }
919}
920
cae4956e
GH
921static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
922{
cae4956e 923 BusState *child;
ccb63de3
GH
924 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
925 dev->id ? dev->id : "");
cae4956e
GH
926 indent += 2;
927 if (dev->num_gpio_in) {
928 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
929 }
930 if (dev->num_gpio_out) {
931 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
932 }
ee6847d1
GH
933 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
934 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
10c4c98a
GH
935 if (dev->parent_bus->info->print_dev)
936 dev->parent_bus->info->print_dev(mon, dev, indent);
72cf2d4f 937 QLIST_FOREACH(child, &dev->child_bus, sibling) {
cae4956e
GH
938 qbus_print(mon, child, indent);
939 }
940}
941
942static void qbus_print(Monitor *mon, BusState *bus, int indent)
943{
944 struct DeviceState *dev;
945
946 qdev_printf("bus: %s\n", bus->name);
947 indent += 2;
10c4c98a 948 qdev_printf("type %s\n", bus->info->name);
d8bb00d6 949 QTAILQ_FOREACH(dev, &bus->children, sibling) {
cae4956e
GH
950 qdev_print(mon, dev, indent);
951 }
952}
953#undef qdev_printf
954
955void do_info_qtree(Monitor *mon)
956{
957 if (main_system_bus)
958 qbus_print(mon, main_system_bus, 0);
959}
9316d30f 960
f6c64e0e 961void do_info_qdm(Monitor *mon)
9316d30f
GH
962{
963 DeviceInfo *info;
9316d30f
GH
964
965 for (info = device_info_list; info != NULL; info = info->next) {
8a9662ca 966 qdev_print_devinfo(info);
9316d30f
GH
967 }
968}
3418bd25 969
8bc27249 970int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
3418bd25
GH
971{
972 QemuOpts *opts;
973
3329f07b 974 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
8bc27249
MA
975 if (!opts) {
976 return -1;
977 }
978 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
979 qemu_opts_del(opts);
980 return 0;
0f853a38 981 }
8bc27249
MA
982 if (!qdev_device_add(opts)) {
983 qemu_opts_del(opts);
984 return -1;
985 }
986 return 0;
3418bd25
GH
987}
988
17a38eaa 989int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
3418bd25
GH
990{
991 const char *id = qdict_get_str(qdict, "id");
992 DeviceState *dev;
993
994 dev = qdev_find_recursive(main_system_bus, id);
995 if (NULL == dev) {
17a38eaa
MA
996 qerror_report(QERR_DEVICE_NOT_FOUND, id);
997 return -1;
3418bd25 998 }
17a38eaa 999 return qdev_unplug(dev);
3418bd25 1000}
1ca4d09a
GN
1001
1002static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
1003{
1004 int l = 0;
1005
1006 if (dev && dev->parent_bus) {
1007 char *d;
1008 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
1009 if (dev->parent_bus->info->get_fw_dev_path) {
1010 d = dev->parent_bus->info->get_fw_dev_path(dev);
1011 l += snprintf(p + l, size - l, "%s", d);
7267c094 1012 g_free(d);
1ca4d09a
GN
1013 } else {
1014 l += snprintf(p + l, size - l, "%s", dev->info->name);
1015 }
1016 }
1017 l += snprintf(p + l , size - l, "/");
1018
1019 return l;
1020}
1021
1022char* qdev_get_fw_dev_path(DeviceState *dev)
1023{
1024 char path[128];
1025 int l;
1026
1027 l = qdev_get_fw_dev_path_helper(dev, path, 128);
1028
1029 path[l-1] = '\0';
1030
1031 return strdup(path);
1032}
85ed303b
AL
1033
1034void qdev_ref(DeviceState *dev)
1035{
1036 dev->ref++;
1037}
1038
1039void qdev_unref(DeviceState *dev)
1040{
1041 g_assert(dev->ref > 0);
1042 dev->ref--;
1043}
44677ded
AL
1044
1045void qdev_property_add(DeviceState *dev, const char *name, const char *type,
1046 DevicePropertyAccessor *get, DevicePropertyAccessor *set,
1047 DevicePropertyRelease *release,
1048 void *opaque, Error **errp)
1049{
1050 DeviceProperty *prop = g_malloc0(sizeof(*prop));
1051
1052 prop->name = g_strdup(name);
1053 prop->type = g_strdup(type);
1054
1055 prop->get = get;
1056 prop->set = set;
1057 prop->release = release;
1058 prop->opaque = opaque;
1059
1060 QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
1061}
1062
1063static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
1064{
1065 DeviceProperty *prop;
1066
1067 QTAILQ_FOREACH(prop, &dev->properties, node) {
1068 if (strcmp(prop->name, name) == 0) {
1069 return prop;
1070 }
1071 }
1072
1073 return NULL;
1074}
1075
1076void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
1077 Error **errp)
1078{
1079 DeviceProperty *prop = qdev_property_find(dev, name);
1080
1081 if (prop == NULL) {
1082 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1083 return;
1084 }
1085
1086 if (!prop->get) {
1087 error_set(errp, QERR_PERMISSION_DENIED);
1088 } else {
1089 prop->get(dev, v, prop->opaque, name, errp);
1090 }
1091}
1092
1093void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
1094 Error **errp)
1095{
1096 DeviceProperty *prop = qdev_property_find(dev, name);
1097
1098 if (prop == NULL) {
1099 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1100 return;
1101 }
1102
1103 if (!prop->set) {
1104 error_set(errp, QERR_PERMISSION_DENIED);
1105 } else {
1106 prop->set(dev, prop->opaque, v, name, errp);
1107 }
1108}
1109
1110const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
1111{
1112 DeviceProperty *prop = qdev_property_find(dev, name);
1113
1114 if (prop == NULL) {
1115 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1116 return NULL;
1117 }
1118
1119 return prop->type;
1120}
a5296ca9
AL
1121
1122/**
1123 * Legacy property handling
1124 */
1125
1126static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1127 const char *name, Error **errp)
1128{
1129 Property *prop = opaque;
1130
1131 if (prop->info->print) {
1132 char buffer[1024];
1133 char *ptr = buffer;
1134
1135 prop->info->print(dev, prop, buffer, sizeof(buffer));
1136 visit_type_str(v, &ptr, name, errp);
1137 } else {
1138 error_set(errp, QERR_PERMISSION_DENIED);
1139 }
1140}
1141
1142static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1143 const char *name, Error **errp)
1144{
1145 Property *prop = opaque;
1146
1147 if (dev->state != DEV_STATE_CREATED) {
1148 error_set(errp, QERR_PERMISSION_DENIED);
1149 return;
1150 }
1151
1152 if (prop->info->parse) {
1153 Error *local_err = NULL;
1154 char *ptr = NULL;
1155
1156 visit_type_str(v, &ptr, name, &local_err);
1157 if (!local_err) {
1158 int ret;
1159 ret = prop->info->parse(dev, prop, ptr);
1160 if (ret != 0) {
1161 error_set(errp, QERR_INVALID_PARAMETER_VALUE,
1162 name, prop->info->name);
1163 }
1164 g_free(ptr);
1165 } else {
1166 error_propagate(errp, local_err);
1167 }
1168 } else {
1169 error_set(errp, QERR_PERMISSION_DENIED);
1170 }
1171}
1172
1173/**
1174 * @qdev_add_legacy_property - adds a legacy property
1175 *
1176 * Do not use this is new code! Properties added through this interface will
1177 * be given types in the "legacy<>" type namespace.
1178 *
1179 * Legacy properties are always processed as strings. The format of the string
1180 * depends on the property type.
1181 */
1182void qdev_property_add_legacy(DeviceState *dev, Property *prop,
1183 Error **errp)
1184{
1185 gchar *type;
1186
1187 type = g_strdup_printf("legacy<%s>", prop->info->name);
1188
1189 qdev_property_add(dev, prop->name, type,
1190 qdev_get_legacy_property,
1191 qdev_set_legacy_property,
1192 NULL,
1193 prop, errp);
1194
1195 g_free(type);
1196}
a10f07a7
AL
1197
1198DeviceState *qdev_get_root(void)
1199{
1200 static DeviceState *qdev_root;
1201
1202 if (!qdev_root) {
1203 qdev_root = qdev_create(NULL, "container");
1204 qdev_init_nofail(qdev_root);
1205 }
1206
1207 return qdev_root;
1208}
f9fbd2fd 1209
3de1c3e8
AL
1210static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
1211 const char *name, Error **errp)
1212{
1213 DeviceState *child = opaque;
1214 gchar *path;
1215
1216 path = qdev_get_canonical_path(child);
1217 visit_type_str(v, &path, name, errp);
1218 g_free(path);
1219}
1220
1221void qdev_property_add_child(DeviceState *dev, const char *name,
1222 DeviceState *child, Error **errp)
1223{
1224 gchar *type;
1225
1226 type = g_strdup_printf("child<%s>", child->info->name);
1227
1228 qdev_property_add(dev, name, type, qdev_get_child_property,
1229 NULL, NULL, child, errp);
1230
1231 qdev_ref(child);
b2b6c39a
AL
1232 g_assert(child->parent == NULL);
1233 child->parent = dev;
3de1c3e8
AL
1234
1235 g_free(type);
1236}
1237
83e94fb8
AL
1238static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
1239 const char *name, Error **errp)
1240{
1241 DeviceState **child = opaque;
1242 gchar *path;
1243
1244 if (*child) {
1245 path = qdev_get_canonical_path(*child);
1246 visit_type_str(v, &path, name, errp);
1247 g_free(path);
1248 } else {
1249 path = (gchar *)"";
1250 visit_type_str(v, &path, name, errp);
1251 }
1252}
1253
1254static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
1255 const char *name, Error **errp)
1256{
1257 DeviceState **child = opaque;
1258 bool ambiguous = false;
1259 const char *type;
1260 char *path;
1261
1262 type = qdev_property_get_type(dev, name, NULL);
1263
1264 visit_type_str(v, &path, name, errp);
1265
1266 if (*child) {
1267 qdev_unref(*child);
1268 }
1269
1270 if (strcmp(path, "") != 0) {
1271 DeviceState *target;
1272
1273 target = qdev_resolve_path(path, &ambiguous);
1274 if (target) {
1275 gchar *target_type;
1276
1277 target_type = g_strdup_printf("link<%s>", target->info->name);
1278 if (strcmp(target_type, type) == 0) {
1279 *child = target;
1280 qdev_ref(target);
1281 } else {
1282 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
1283 }
1284
1285 g_free(target_type);
1286 } else {
1287 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
1288 }
1289 } else {
1290 *child = NULL;
1291 }
1292
1293 g_free(path);
1294}
1295
1296void qdev_property_add_link(DeviceState *dev, const char *name,
1297 const char *type, DeviceState **child,
1298 Error **errp)
1299{
1300 gchar *full_type;
1301
1302 full_type = g_strdup_printf("link<%s>", type);
1303
1304 qdev_property_add(dev, name, full_type,
1305 qdev_get_link_property,
1306 qdev_set_link_property,
1307 NULL, child, errp);
1308
1309 g_free(full_type);
1310}
1311
b2b6c39a 1312gchar *qdev_get_canonical_path(DeviceState *dev)
f9fbd2fd 1313{
b2b6c39a
AL
1314 DeviceState *root = qdev_get_root();
1315 char *newpath = NULL, *path = NULL;
f9fbd2fd 1316
b2b6c39a
AL
1317 while (dev != root) {
1318 DeviceProperty *prop = NULL;
f9fbd2fd 1319
b2b6c39a 1320 g_assert(dev->parent != NULL);
f9fbd2fd 1321
b2b6c39a
AL
1322 QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
1323 if (!strstart(prop->type, "child<", NULL)) {
1324 continue;
1325 }
f9fbd2fd 1326
b2b6c39a
AL
1327 if (prop->opaque == dev) {
1328 if (path) {
1329 newpath = g_strdup_printf("%s/%s", prop->name, path);
1330 g_free(path);
1331 path = newpath;
1332 } else {
1333 path = g_strdup(prop->name);
1334 }
1335 break;
1336 }
f9fbd2fd
AL
1337 }
1338
b2b6c39a 1339 g_assert(prop != NULL);
f9fbd2fd 1340
b2b6c39a 1341 dev = dev->parent;
f9fbd2fd
AL
1342 }
1343
f9fbd2fd
AL
1344 newpath = g_strdup_printf("/%s", path);
1345 g_free(path);
1346
1347 return newpath;
1348}
dc45c21f
AL
1349
1350static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
1351 gchar **parts,
1352 int index)
1353{
1354 DeviceProperty *prop;
1355 DeviceState *child;
1356
1357 if (parts[index] == NULL) {
1358 return parent;
1359 }
1360
1361 if (strcmp(parts[index], "") == 0) {
1362 return qdev_resolve_abs_path(parent, parts, index + 1);
1363 }
1364
1365 prop = qdev_property_find(parent, parts[index]);
1366 if (prop == NULL) {
1367 return NULL;
1368 }
1369
1370 child = NULL;
1371 if (strstart(prop->type, "link<", NULL)) {
1372 DeviceState **pchild = prop->opaque;
1373 if (*pchild) {
1374 child = *pchild;
1375 }
1376 } else if (strstart(prop->type, "child<", NULL)) {
1377 child = prop->opaque;
1378 }
1379
1380 if (!child) {
1381 return NULL;
1382 }
1383
1384 return qdev_resolve_abs_path(child, parts, index + 1);
1385}
1386
1387static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
1388 gchar **parts,
1389 bool *ambiguous)
1390{
1391 DeviceState *dev;
1392 DeviceProperty *prop;
1393
1394 dev = qdev_resolve_abs_path(parent, parts, 0);
1395
1396 QTAILQ_FOREACH(prop, &parent->properties, node) {
1397 DeviceState *found;
1398
1399 if (!strstart(prop->type, "child<", NULL)) {
1400 continue;
1401 }
1402
1403 found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
1404 if (found) {
1405 if (dev) {
1406 if (ambiguous) {
1407 *ambiguous = true;
1408 }
1409 return NULL;
1410 }
1411 dev = found;
1412 }
1413
1414 if (ambiguous && *ambiguous) {
1415 return NULL;
1416 }
1417 }
1418
1419 return dev;
1420}
1421
1422DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
1423{
1424 bool partial_path = true;
1425 DeviceState *dev;
1426 gchar **parts;
1427
1428 parts = g_strsplit(path, "/", 0);
1429 if (parts == NULL || parts[0] == NULL) {
1430 g_strfreev(parts);
1431 return qdev_get_root();
1432 }
1433
1434 if (strcmp(parts[0], "") == 0) {
1435 partial_path = false;
1436 }
1437
1438 if (partial_path) {
1439 if (ambiguous) {
1440 *ambiguous = false;
1441 }
1442 dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
1443 } else {
1444 dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
1445 }
1446
1447 g_strfreev(parts);
1448
1449 return dev;
1450}
1451