blob: 49d26a28b34a1bb24063c4f437923236c26407d3 [file] [log] [blame]
Paul Brookaae94602009-05-14 22:35:06 +01001/*
2 * Dynamic device configuration and creation.
3 *
4 * Copyright (c) 2009 CodeSourcery
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Paul Brookaae94602009-05-14 22:35:06 +010018 */
19
20/* The theory here is that it should be possible to create a machine without
21 knowledge of specific devices. Historically board init routines have
22 passed a bunch of arguments to each device, requiring the board know
23 exactly which device it is dealing with. This file provides an abstract
24 API for device configuration and initialization. Devices will generally
25 inherit from a particular bus (e.g. PCI or I2C) rather than
26 this API directly. */
27
Paul Brook9d07d752009-05-14 22:35:07 +010028#include "net.h"
Paul Brookaae94602009-05-14 22:35:06 +010029#include "qdev.h"
30#include "sysemu.h"
Gerd Hoffmanncae49562009-06-05 15:53:17 +010031#include "monitor.h"
Paul Brookaae94602009-05-14 22:35:06 +010032
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020033static int qdev_hotplug = 0;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070034static bool qdev_hot_added = false;
35static bool qdev_hot_removed = false;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020036
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020037/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000038static BusState *main_system_bus;
Isaku Yamahata2da8bb92011-08-02 10:59:13 +090039static void main_system_bus_create(void);
Paul Brook4d6ae672009-05-14 22:35:06 +010040
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010041DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010042
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020043static BusState *qbus_find_recursive(BusState *bus, const char *name,
44 const BusInfo *info);
45static BusState *qbus_find(const char *path);
46
Paul Brookaae94602009-05-14 22:35:06 +010047/* Register a new device type. */
Anthony Liguori30fbb9f2011-12-04 11:08:36 -060048static void qdev_subclass_init(ObjectClass *klass, void *data)
49{
50 DeviceClass *dc = DEVICE_CLASS(klass);
51 dc->info = data;
52}
53
54DeviceInfo *qdev_get_info(DeviceState *dev)
55{
56 return DEVICE_GET_CLASS(dev)->info;
57}
58
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020059void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010060{
Anthony Liguori32fea402011-12-16 14:34:46 -060061 TypeInfo type_info = {};
62
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020063 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020064 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010065
Anthony Liguori32fea402011-12-16 14:34:46 -060066 type_info.name = info->name;
67 type_info.parent = TYPE_DEVICE;
68 type_info.instance_size = info->size;
Anthony Liguori30fbb9f2011-12-04 11:08:36 -060069 type_info.class_init = qdev_subclass_init;
70 type_info.class_data = info;
Anthony Liguori32fea402011-12-16 14:34:46 -060071
72 type_register_static(&type_info);
73
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020074 info->next = device_info_list;
75 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010076}
77
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020078static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
79{
80 DeviceInfo *info;
81
Gerd Hoffmann3320e562009-07-15 13:43:33 +020082 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020083 for (info = device_info_list; info != NULL; info = info->next) {
84 if (bus_info && info->bus_info != bus_info)
85 continue;
86 if (strcmp(info->name, name) != 0)
87 continue;
88 return info;
89 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020090
91 /* failing that check the aliases */
92 for (info = device_info_list; info != NULL; info = info->next) {
93 if (bus_info && info->bus_info != bus_info)
94 continue;
95 if (!info->alias)
96 continue;
97 if (strcmp(info->alias, name) != 0)
98 continue;
99 return info;
100 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +0200101 return NULL;
102}
103
Blue Swirla369da52011-09-27 19:15:42 +0000104bool qdev_exists(const char *name)
105{
106 return !!qdev_find_info(NULL, name);
107}
Paolo Bonzinica2cc782011-12-18 17:05:11 +0100108static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
109 Error **errp);
110
Markus Armbruster0c175422010-02-19 19:12:18 +0100111static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +0100112{
Paul Brookaae94602009-05-14 22:35:06 +0100113 DeviceState *dev;
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600114 Property *prop;
Paul Brookaae94602009-05-14 22:35:06 +0100115
Markus Armbruster0c175422010-02-19 19:12:18 +0100116 assert(bus->info == info->bus_info);
Anthony Liguori32fea402011-12-16 14:34:46 -0600117 dev = DEVICE(object_new(info->name));
Paul Brook02e2da42009-05-23 00:05:19 +0100118 dev->parent_bus = bus;
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600119 qdev_prop_set_defaults(dev, qdev_get_info(dev)->props);
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200120 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +0100121 qdev_prop_set_globals(dev);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200122 QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200123 if (qdev_hotplug) {
124 assert(bus->allow_hotplug);
125 dev->hotplugged = 1;
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700126 qdev_hot_added = true;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200127 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200128 dev->instance_id_alias = -1;
Anthony Liguori44677de2011-12-12 14:29:26 -0600129 QTAILQ_INIT(&dev->properties);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200130 dev->state = DEV_STATE_CREATED;
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600131
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600132 for (prop = qdev_get_info(dev)->props; prop && prop->name; prop++) {
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600133 qdev_property_add_legacy(dev, prop, NULL);
Paolo Bonzinica2cc782011-12-18 17:05:11 +0100134 qdev_property_add_static(dev, prop, NULL);
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600135 }
136
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600137 for (prop = qdev_get_info(dev)->bus_info->props; prop && prop->name; prop++) {
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600138 qdev_property_add_legacy(dev, prop, NULL);
Paolo Bonzinica2cc782011-12-18 17:05:11 +0100139 qdev_property_add_static(dev, prop, NULL);
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600140 }
141
Anthony Liguoricd34d662011-12-12 14:29:43 -0600142 qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
143
Paul Brookaae94602009-05-14 22:35:06 +0100144 return dev;
145}
146
Markus Armbruster0c175422010-02-19 19:12:18 +0100147/* Create a new device. This only initializes the device state structure
148 and allows properties to be set. qdev_init should be called to
149 initialize the actual device emulation. */
150DeviceState *qdev_create(BusState *bus, const char *name)
151{
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000152 DeviceState *dev;
153
154 dev = qdev_try_create(bus, name);
155 if (!dev) {
Peter Maydelle92714c2011-08-03 23:49:04 +0100156 if (bus) {
157 hw_error("Unknown device '%s' for bus '%s'\n", name,
158 bus->info->name);
159 } else {
160 hw_error("Unknown device '%s' for default sysbus\n", name);
161 }
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000162 }
163
164 return dev;
165}
166
167DeviceState *qdev_try_create(BusState *bus, const char *name)
168{
Markus Armbruster0c175422010-02-19 19:12:18 +0100169 DeviceInfo *info;
170
171 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100172 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100173 }
174
175 info = qdev_find_info(bus->info, name);
176 if (!info) {
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000177 return NULL;
Markus Armbruster0c175422010-02-19 19:12:18 +0100178 }
179
180 return qdev_create_from_info(bus, info);
181}
182
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100183static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200184{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100185 error_printf("name \"%s\", bus %s",
186 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200187 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100188 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200189 }
190 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100191 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200192 }
193 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100194 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200195 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100196 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200197}
198
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200199static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200200{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200201 DeviceState *dev = opaque;
202
203 if (strcmp(name, "driver") == 0)
204 return 0;
205 if (strcmp(name, "bus") == 0)
206 return 0;
207
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100208 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200209 return -1;
210 }
211 return 0;
212}
213
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100214int qdev_device_help(QemuOpts *opts)
215{
216 const char *driver;
217 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100218 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100219
220 driver = qemu_opt_get(opts, "driver");
221 if (driver && !strcmp(driver, "?")) {
222 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100223 if (info->no_user) {
224 continue; /* not available, don't show */
225 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100226 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100227 }
228 return 1;
229 }
230
Markus Armbruster542379f2011-11-08 11:00:38 +0100231 if (!driver || !qemu_opt_get(opts, "?")) {
Markus Armbruster08350cf2010-01-29 19:49:00 +0100232 return 0;
233 }
234
235 info = qdev_find_info(NULL, driver);
236 if (!info) {
237 return 0;
238 }
239
240 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100241 /*
242 * TODO Properties without a parser are just for dirty hacks.
243 * qdev_prop_ptr is the only such PropertyInfo. It's marked
244 * for removal. This conditional should be removed along with
245 * it.
246 */
247 if (!prop->info->parse) {
248 continue; /* no way to set it, don't show */
249 }
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +0100250 error_printf("%s.%s=%s\n", info->name, prop->name,
251 prop->info->legacy_name ?: prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100252 }
Gerd Hoffmanna8467c72011-09-16 11:25:05 +0200253 for (prop = info->bus_info->props; prop && prop->name; prop++) {
254 if (!prop->info->parse) {
255 continue; /* no way to set it, don't show */
256 }
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +0100257 error_printf("%s.%s=%s\n", info->name, prop->name,
258 prop->info->legacy_name ?: prop->info->name);
Gerd Hoffmanna8467c72011-09-16 11:25:05 +0200259 }
Markus Armbruster08350cf2010-01-29 19:49:00 +0100260 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100261}
262
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600263static DeviceState *qdev_get_peripheral(void)
264{
265 static DeviceState *dev;
266
267 if (dev == NULL) {
268 dev = qdev_create(NULL, "container");
269 qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
270 qdev_init_nofail(dev);
271 }
272
273 return dev;
274}
275
Anthony Liguori8eb02832011-12-12 14:29:37 -0600276static DeviceState *qdev_get_peripheral_anon(void)
277{
278 static DeviceState *dev;
279
280 if (dev == NULL) {
281 dev = qdev_create(NULL, "container");
282 qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
283 qdev_init_nofail(dev);
284 }
285
286 return dev;
287}
288
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200289DeviceState *qdev_device_add(QemuOpts *opts)
290{
291 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200292 DeviceInfo *info;
293 DeviceState *qdev;
294 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200295
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200296 driver = qemu_opt_get(opts, "driver");
297 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100298 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200299 return NULL;
300 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200301
302 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200303 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100304 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100305 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100306 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200307 return NULL;
308 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200309
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200310 /* find bus */
311 path = qemu_opt_get(opts, "bus");
312 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200313 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100314 if (!bus) {
315 return NULL;
316 }
317 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100318 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
319 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100320 return NULL;
321 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200322 } else {
323 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100324 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100325 qerror_report(QERR_NO_BUS_FOR_DEVICE,
326 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100327 return NULL;
328 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200329 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200330 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100331 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200332 return NULL;
333 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200334
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200335 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100336 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200337 id = qemu_opts_id(opts);
338 if (id) {
339 qdev->id = id;
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600340 qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
Anthony Liguori8eb02832011-12-12 14:29:37 -0600341 } else {
342 static int anon_count;
343 gchar *name = g_strdup_printf("device[%d]", anon_count++);
344 qdev_property_add_child(qdev_get_peripheral_anon(), name,
345 qdev, NULL);
346 g_free(name);
347 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200348 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
349 qdev_free(qdev);
350 return NULL;
351 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200352 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100353 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200354 return NULL;
355 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200356 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200357 return qdev;
358}
359
Paul Brookaae94602009-05-14 22:35:06 +0100360/* Initialize a device. Device properties should be set before calling
361 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200362 calling this function.
363 On failure, destroy the device and return negative value.
364 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200365int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100366{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200367 int rc;
368
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200369 assert(dev->state == DEV_STATE_CREATED);
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600370 rc = qdev_get_info(dev)->init(dev, qdev_get_info(dev));
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200371 if (rc < 0) {
372 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200373 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200374 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600375 if (qdev_get_info(dev)->vmsd) {
376 vmstate_register_with_alias_id(dev, -1, qdev_get_info(dev)->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200377 dev->instance_id_alias,
378 dev->alias_required_for_version);
379 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200380 dev->state = DEV_STATE_INITIALIZED;
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600381 if (dev->hotplugged && qdev_get_info(dev)->reset) {
382 qdev_get_info(dev)->reset(dev);
Jan Kiszka5ab28c82011-07-24 19:38:36 +0200383 }
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200384 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100385}
386
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200387void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
388 int required_for_version)
389{
390 assert(dev->state == DEV_STATE_CREATED);
391 dev->instance_id_alias = alias_id;
392 dev->alias_required_for_version = required_for_version;
393}
394
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200395int qdev_unplug(DeviceState *dev)
396{
397 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100398 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200399 return -1;
400 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600401 assert(qdev_get_info(dev)->unplug != NULL);
Amit Shah593831d2009-11-02 14:56:41 +0530402
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700403 qdev_hot_removed = true;
404
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600405 return qdev_get_info(dev)->unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200406}
407
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900408static int qdev_reset_one(DeviceState *dev, void *opaque)
409{
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600410 if (qdev_get_info(dev)->reset) {
411 qdev_get_info(dev)->reset(dev);
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900412 }
413
414 return 0;
415}
416
417BusState *sysbus_get_default(void)
418{
Stefan Weil68694892010-12-16 19:33:22 +0100419 if (!main_system_bus) {
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900420 main_system_bus_create();
Stefan Weil68694892010-12-16 19:33:22 +0100421 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900422 return main_system_bus;
423}
424
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900425static int qbus_reset_one(BusState *bus, void *opaque)
426{
427 if (bus->info->reset) {
428 return bus->info->reset(bus);
429 }
430 return 0;
431}
432
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900433void qdev_reset_all(DeviceState *dev)
434{
435 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
436}
437
Isaku Yamahata80376c32010-12-20 14:33:35 +0900438void qbus_reset_all_fn(void *opaque)
439{
440 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200441 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900442}
443
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200444/* can be used as ->unplug() callback for the simple cases */
445int qdev_simple_unplug_cb(DeviceState *dev)
446{
447 /* just zap it */
448 qdev_free(dev);
449 return 0;
450}
451
Michael Tokarev3b29a102011-04-06 17:51:59 +0400452
453/* Like qdev_init(), but terminate program via error_report() instead of
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200454 returning an error value. This is okay during machine creation.
455 Don't use for hotplug, because there callers need to recover from
456 failure. Exception: if you know the device's init() callback can't
457 fail, then qdev_init_nofail() can't fail either, and is therefore
458 usable even then. But relying on the device implementation that
459 way is somewhat unclean, and best avoided. */
460void qdev_init_nofail(DeviceState *dev)
461{
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600462 DeviceInfo *info = qdev_get_info(dev);
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200463
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200464 if (qdev_init(dev) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +0200465 error_report("Initialization of device %s failed", info->name);
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200466 exit(1);
467 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200468}
469
Anthony Liguori44677de2011-12-12 14:29:26 -0600470static void qdev_property_del_all(DeviceState *dev)
471{
472 while (!QTAILQ_EMPTY(&dev->properties)) {
473 DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
474
475 QTAILQ_REMOVE(&dev->properties, prop, node);
476
477 if (prop->release) {
478 prop->release(dev, prop->name, prop->opaque);
479 }
480
481 g_free(prop->name);
482 g_free(prop->type);
483 g_free(prop);
484 }
485}
486
Anthony Liguori024a6fb2012-01-13 07:45:55 -0600487static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp)
488{
489 DeviceProperty *prop;
490
491 QTAILQ_FOREACH(prop, &dev->properties, node) {
492 if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
493 break;
494 }
495 }
496
497 g_assert(prop != NULL);
498
499 QTAILQ_REMOVE(&dev->properties, prop, node);
500
501 if (prop->release) {
502 prop->release(dev, prop->name, prop->opaque);
503 }
504
505 g_free(prop->name);
506 g_free(prop->type);
507 g_free(prop);
508}
509
Paul Brook02e2da42009-05-23 00:05:19 +0100510/* Unlink device from bus and free the structure. */
511void qdev_free(DeviceState *dev)
512{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200513 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200514 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200515
Anthony Liguori44677de2011-12-12 14:29:26 -0600516 qdev_property_del_all(dev);
517
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200518 if (dev->state == DEV_STATE_INITIALIZED) {
519 while (dev->num_child_bus) {
520 bus = QLIST_FIRST(&dev->child_bus);
521 qbus_free(bus);
522 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600523 if (qdev_get_info(dev)->vmsd)
524 vmstate_unregister(dev, qdev_get_info(dev)->vmsd, dev);
525 if (qdev_get_info(dev)->exit)
526 qdev_get_info(dev)->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200527 if (dev->opts)
528 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200529 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200530 QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600531 for (prop = qdev_get_info(dev)->props; prop && prop->name; prop++) {
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200532 if (prop->info->free) {
533 prop->info->free(dev, prop);
534 }
535 }
Anthony Liguori024a6fb2012-01-13 07:45:55 -0600536 if (dev->parent) {
537 qdev_property_del_child(dev->parent, dev, NULL);
538 }
539 if (dev->ref != 0) {
540 qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
541 }
Anthony Liguori32fea402011-12-16 14:34:46 -0600542 object_delete(OBJECT(dev));
Paul Brookaae94602009-05-14 22:35:06 +0100543}
544
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200545void qdev_machine_creation_done(void)
546{
547 /*
548 * ok, initial machine setup is done, starting from now we can
549 * only create hotpluggable devices
550 */
551 qdev_hotplug = 1;
552}
553
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700554bool qdev_machine_modified(void)
555{
556 return qdev_hot_added || qdev_hot_removed;
557}
558
Paul Brookaae94602009-05-14 22:35:06 +0100559/* Get a character (serial) device interface. */
560CharDriverState *qdev_init_chardev(DeviceState *dev)
561{
562 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530563
564 /* FIXME: This function needs to go away: use chardev properties! */
565 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100566}
567
Paul Brook02e2da42009-05-23 00:05:19 +0100568BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100569{
Paul Brook02e2da42009-05-23 00:05:19 +0100570 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100571}
572
Paul Brookaae94602009-05-14 22:35:06 +0100573void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
574{
575 assert(dev->num_gpio_in == 0);
576 dev->num_gpio_in = n;
577 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
578}
579
580void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
581{
582 assert(dev->num_gpio_out == 0);
583 dev->num_gpio_out = n;
584 dev->gpio_out = pins;
585}
586
587qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
588{
589 assert(n >= 0 && n < dev->num_gpio_in);
590 return dev->gpio_in[n];
591}
592
593void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
594{
595 assert(n >= 0 && n < dev->num_gpio_out);
596 dev->gpio_out[n] = pin;
597}
598
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200599void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
600{
Jan Kiszka6eed1852011-07-20 12:20:22 +0200601 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200602 if (nd->vlan)
603 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
604 if (nd->netdev)
605 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530606 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200607 qdev_prop_exists(dev, "vectors")) {
608 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
609 }
Peter Maydell48e2faf2011-05-20 16:50:01 +0100610 nd->instantiated = 1;
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200611}
612
Paul Brook02e2da42009-05-23 00:05:19 +0100613BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100614{
Paul Brook02e2da42009-05-23 00:05:19 +0100615 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100616
Blue Swirl72cf2d42009-09-12 07:36:22 +0000617 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100618 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100619 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100620 }
621 }
622 return NULL;
623}
624
Anthony Liguori81699d82010-11-19 18:55:58 +0900625int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
626 qbus_walkerfn *busfn, void *opaque)
627{
628 DeviceState *dev;
629 int err;
630
631 if (busfn) {
632 err = busfn(bus, opaque);
633 if (err) {
634 return err;
635 }
636 }
637
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200638 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori81699d82010-11-19 18:55:58 +0900639 err = qdev_walk_children(dev, devfn, busfn, opaque);
640 if (err < 0) {
641 return err;
642 }
643 }
644
645 return 0;
646}
647
648int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
649 qbus_walkerfn *busfn, void *opaque)
650{
651 BusState *bus;
652 int err;
653
654 if (devfn) {
655 err = devfn(dev, opaque);
656 if (err) {
657 return err;
658 }
659 }
660
661 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
662 err = qbus_walk_children(bus, devfn, busfn, opaque);
663 if (err < 0) {
664 return err;
665 }
666 }
667
668 return 0;
669}
670
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200671static BusState *qbus_find_recursive(BusState *bus, const char *name,
672 const BusInfo *info)
673{
674 DeviceState *dev;
675 BusState *child, *ret;
676 int match = 1;
677
678 if (name && (strcmp(bus->name, name) != 0)) {
679 match = 0;
680 }
681 if (info && (bus->info != info)) {
682 match = 0;
683 }
684 if (match) {
685 return bus;
686 }
687
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200688 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000689 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200690 ret = qbus_find_recursive(child, name, info);
691 if (ret) {
692 return ret;
693 }
694 }
695 }
696 return NULL;
697}
698
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900699DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200700{
701 DeviceState *dev, *ret;
702 BusState *child;
703
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200704 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200705 if (dev->id && strcmp(dev->id, id) == 0)
706 return dev;
707 QLIST_FOREACH(child, &dev->child_bus, sibling) {
708 ret = qdev_find_recursive(child, id);
709 if (ret) {
710 return ret;
711 }
712 }
713 }
714 return NULL;
715}
716
Markus Armbruster53db16b2010-02-18 18:55:59 +0100717static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200718{
719 BusState *child;
720 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200721
Markus Armbruster53db16b2010-02-18 18:55:59 +0100722 error_printf("child busses at \"%s\":",
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600723 dev->id ? dev->id : qdev_get_info(dev)->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000724 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100725 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200726 sep = ", ";
727 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100728 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200729}
730
Markus Armbruster53db16b2010-02-18 18:55:59 +0100731static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200732{
733 DeviceState *dev;
734 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200735
Markus Armbruster53db16b2010-02-18 18:55:59 +0100736 error_printf("devices at \"%s\":", bus->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200737 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600738 error_printf("%s\"%s\"", sep, qdev_get_info(dev)->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200739 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100740 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200741 sep = ", ";
742 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100743 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200744}
745
746static BusState *qbus_find_bus(DeviceState *dev, char *elem)
747{
748 BusState *child;
749
Blue Swirl72cf2d42009-09-12 07:36:22 +0000750 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200751 if (strcmp(child->name, elem) == 0) {
752 return child;
753 }
754 }
755 return NULL;
756}
757
758static DeviceState *qbus_find_dev(BusState *bus, char *elem)
759{
760 DeviceState *dev;
761
762 /*
763 * try to match in order:
764 * (1) instance id, if present
765 * (2) driver name
766 * (3) driver alias, if present
767 */
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200768 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200769 if (dev->id && strcmp(dev->id, elem) == 0) {
770 return dev;
771 }
772 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200773 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600774 if (strcmp(qdev_get_info(dev)->name, elem) == 0) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200775 return dev;
776 }
777 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200778 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600779 if (qdev_get_info(dev)->alias && strcmp(qdev_get_info(dev)->alias, elem) == 0) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200780 return dev;
781 }
782 }
783 return NULL;
784}
785
786static BusState *qbus_find(const char *path)
787{
788 DeviceState *dev;
789 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100790 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200791 int pos, len;
792
793 /* find start element */
794 if (path[0] == '/') {
795 bus = main_system_bus;
796 pos = 0;
797 } else {
798 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100799 assert(!path[0]);
800 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200801 }
802 bus = qbus_find_recursive(main_system_bus, elem, NULL);
803 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100804 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200805 return NULL;
806 }
807 pos = len;
808 }
809
810 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100811 assert(path[pos] == '/' || !path[pos]);
812 while (path[pos] == '/') {
813 pos++;
814 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200815 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200816 return bus;
817 }
818
819 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100820 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
821 assert(0);
822 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200823 }
824 pos += len;
825 dev = qbus_find_dev(bus, elem);
826 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100827 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100828 if (!monitor_cur_is_qmp()) {
829 qbus_list_dev(bus);
830 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200831 return NULL;
832 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100833
834 assert(path[pos] == '/' || !path[pos]);
835 while (path[pos] == '/') {
836 pos++;
837 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200838 if (path[pos] == '\0') {
839 /* last specified element is a device. If it has exactly
840 * one child bus accept it nevertheless */
841 switch (dev->num_child_bus) {
842 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100843 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200844 return NULL;
845 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000846 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200847 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100848 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100849 if (!monitor_cur_is_qmp()) {
850 qbus_list_bus(dev);
851 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200852 return NULL;
853 }
854 }
855
856 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100857 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
858 assert(0);
859 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200860 }
861 pos += len;
862 bus = qbus_find_bus(dev, elem);
863 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100864 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100865 if (!monitor_cur_is_qmp()) {
866 qbus_list_bus(dev);
867 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200868 return NULL;
869 }
870 }
871}
872
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200873void qbus_create_inplace(BusState *bus, BusInfo *info,
874 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100875{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200876 char *buf;
877 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100878
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200879 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100880 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200881
882 if (name) {
883 /* use supplied name */
Anthony Liguori7267c092011-08-20 22:09:37 -0500884 bus->name = g_strdup(name);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200885 } else if (parent && parent->id) {
886 /* parent device has id -> use it for bus name */
887 len = strlen(parent->id) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500888 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200889 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
890 bus->name = buf;
891 } else {
892 /* no id -> use lowercase bus type for bus name */
893 len = strlen(info->name) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500894 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200895 len = snprintf(buf, len, "%s.%d", info->name,
896 parent ? parent->num_child_bus : 0);
897 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200898 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200899 bus->name = buf;
900 }
901
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200902 QTAILQ_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100903 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000904 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200905 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900906 } else if (bus != main_system_bus) {
907 /* TODO: once all bus devices are qdevified,
908 only reset handler for main_system_bus should be registered here. */
909 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100910 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200911}
912
913BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
914{
915 BusState *bus;
916
Anthony Liguori7267c092011-08-20 22:09:37 -0500917 bus = g_malloc0(info->size);
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200918 bus->qdev_allocated = 1;
919 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100920 return bus;
921}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100922
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900923static void main_system_bus_create(void)
924{
925 /* assign main_system_bus before qbus_create_inplace()
926 * in order to make "if (bus != main_system_bus)" work */
Anthony Liguori7267c092011-08-20 22:09:37 -0500927 main_system_bus = g_malloc0(system_bus_info.size);
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900928 main_system_bus->qdev_allocated = 1;
929 qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
930 "main-system-bus");
931}
932
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200933void qbus_free(BusState *bus)
934{
935 DeviceState *dev;
936
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200937 while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200938 qdev_free(dev);
939 }
940 if (bus->parent) {
941 QLIST_REMOVE(bus, sibling);
942 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900943 } else {
944 assert(bus != main_system_bus); /* main_system_bus is never freed */
945 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200946 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500947 g_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200948 if (bus->qdev_allocated) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500949 g_free(bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200950 }
951}
952
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100953#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
954static void qbus_print(Monitor *mon, BusState *bus, int indent);
955
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200956static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
957 const char *prefix, int indent)
958{
959 char buf[64];
960
961 if (!props)
962 return;
963 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100964 /*
965 * TODO Properties without a print method are just for dirty
966 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
967 * marked for removal. The test props->info->print should be
968 * removed along with it.
969 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200970 if (props->info->print) {
971 props->info->print(dev, props, buf, sizeof(buf));
972 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
973 }
974 props++;
975 }
976}
977
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100978static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
979{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100980 BusState *child;
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600981 qdev_printf("dev: %s, id \"%s\"\n", qdev_get_info(dev)->name,
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200982 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100983 indent += 2;
984 if (dev->num_gpio_in) {
985 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
986 }
987 if (dev->num_gpio_out) {
988 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
989 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600990 qdev_print_props(mon, dev, qdev_get_info(dev)->props, "dev", indent);
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200991 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200992 if (dev->parent_bus->info->print_dev)
993 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000994 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100995 qbus_print(mon, child, indent);
996 }
997}
998
999static void qbus_print(Monitor *mon, BusState *bus, int indent)
1000{
1001 struct DeviceState *dev;
1002
1003 qdev_printf("bus: %s\n", bus->name);
1004 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +02001005 qdev_printf("type %s\n", bus->info->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +02001006 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +01001007 qdev_print(mon, dev, indent);
1008 }
1009}
1010#undef qdev_printf
1011
1012void do_info_qtree(Monitor *mon)
1013{
1014 if (main_system_bus)
1015 qbus_print(mon, main_system_bus, 0);
1016}
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001017
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +02001018void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001019{
1020 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001021
1022 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +01001023 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001024 }
1025}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001026
Markus Armbruster8bc27242010-02-10 20:52:01 +01001027int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001028{
1029 QemuOpts *opts;
1030
Gerd Hoffmann3329f072010-08-20 13:52:01 +02001031 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +01001032 if (!opts) {
1033 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +01001034 }
Markus Armbruster8bc27242010-02-10 20:52:01 +01001035 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
1036 qemu_opts_del(opts);
1037 return 0;
1038 }
1039 if (!qdev_device_add(opts)) {
1040 qemu_opts_del(opts);
1041 return -1;
1042 }
1043 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001044}
1045
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001046int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001047{
1048 const char *id = qdict_get_str(qdict, "id");
1049 DeviceState *dev;
1050
1051 dev = qdev_find_recursive(main_system_bus, id);
1052 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001053 qerror_report(QERR_DEVICE_NOT_FOUND, id);
1054 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001055 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001056 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001057}
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001058
1059static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
1060{
1061 int l = 0;
1062
1063 if (dev && dev->parent_bus) {
1064 char *d;
1065 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
1066 if (dev->parent_bus->info->get_fw_dev_path) {
1067 d = dev->parent_bus->info->get_fw_dev_path(dev);
1068 l += snprintf(p + l, size - l, "%s", d);
Anthony Liguori7267c092011-08-20 22:09:37 -05001069 g_free(d);
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001070 } else {
Anthony Liguori30fbb9f2011-12-04 11:08:36 -06001071 l += snprintf(p + l, size - l, "%s", qdev_get_info(dev)->name);
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001072 }
1073 }
1074 l += snprintf(p + l , size - l, "/");
1075
1076 return l;
1077}
1078
1079char* qdev_get_fw_dev_path(DeviceState *dev)
1080{
1081 char path[128];
1082 int l;
1083
1084 l = qdev_get_fw_dev_path_helper(dev, path, 128);
1085
1086 path[l-1] = '\0';
1087
1088 return strdup(path);
1089}
Anthony Liguori85ed3032011-12-12 14:29:25 -06001090
Anthony Liguoricd34d662011-12-12 14:29:43 -06001091char *qdev_get_type(DeviceState *dev, Error **errp)
1092{
Anthony Liguori30fbb9f2011-12-04 11:08:36 -06001093 return g_strdup(qdev_get_info(dev)->name);
Anthony Liguoricd34d662011-12-12 14:29:43 -06001094}
1095
Anthony Liguori85ed3032011-12-12 14:29:25 -06001096void qdev_ref(DeviceState *dev)
1097{
1098 dev->ref++;
1099}
1100
1101void qdev_unref(DeviceState *dev)
1102{
1103 g_assert(dev->ref > 0);
1104 dev->ref--;
1105}
Anthony Liguori44677de2011-12-12 14:29:26 -06001106
1107void qdev_property_add(DeviceState *dev, const char *name, const char *type,
1108 DevicePropertyAccessor *get, DevicePropertyAccessor *set,
1109 DevicePropertyRelease *release,
1110 void *opaque, Error **errp)
1111{
1112 DeviceProperty *prop = g_malloc0(sizeof(*prop));
1113
1114 prop->name = g_strdup(name);
1115 prop->type = g_strdup(type);
1116
1117 prop->get = get;
1118 prop->set = set;
1119 prop->release = release;
1120 prop->opaque = opaque;
1121
1122 QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
1123}
1124
1125static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
1126{
1127 DeviceProperty *prop;
1128
1129 QTAILQ_FOREACH(prop, &dev->properties, node) {
1130 if (strcmp(prop->name, name) == 0) {
1131 return prop;
1132 }
1133 }
1134
1135 return NULL;
1136}
1137
1138void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
1139 Error **errp)
1140{
1141 DeviceProperty *prop = qdev_property_find(dev, name);
1142
1143 if (prop == NULL) {
1144 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1145 return;
1146 }
1147
1148 if (!prop->get) {
1149 error_set(errp, QERR_PERMISSION_DENIED);
1150 } else {
1151 prop->get(dev, v, prop->opaque, name, errp);
1152 }
1153}
1154
1155void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
1156 Error **errp)
1157{
1158 DeviceProperty *prop = qdev_property_find(dev, name);
1159
1160 if (prop == NULL) {
1161 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1162 return;
1163 }
1164
1165 if (!prop->set) {
1166 error_set(errp, QERR_PERMISSION_DENIED);
1167 } else {
Paolo Bonzini0d41d9a2011-12-18 17:05:05 +01001168 prop->set(dev, v, prop->opaque, name, errp);
Anthony Liguori44677de2011-12-12 14:29:26 -06001169 }
1170}
1171
1172const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
1173{
1174 DeviceProperty *prop = qdev_property_find(dev, name);
1175
1176 if (prop == NULL) {
1177 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1178 return NULL;
1179 }
1180
1181 return prop->type;
1182}
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001183
1184/**
1185 * Legacy property handling
1186 */
1187
1188static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1189 const char *name, Error **errp)
1190{
1191 Property *prop = opaque;
1192
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001193 char buffer[1024];
1194 char *ptr = buffer;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001195
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001196 prop->info->print(dev, prop, buffer, sizeof(buffer));
1197 visit_type_str(v, &ptr, name, errp);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001198}
1199
1200static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1201 const char *name, Error **errp)
1202{
1203 Property *prop = opaque;
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001204 Error *local_err = NULL;
1205 char *ptr = NULL;
1206 int ret;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001207
1208 if (dev->state != DEV_STATE_CREATED) {
1209 error_set(errp, QERR_PERMISSION_DENIED);
1210 return;
1211 }
1212
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001213 visit_type_str(v, &ptr, name, &local_err);
1214 if (local_err) {
1215 error_propagate(errp, local_err);
1216 return;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001217 }
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001218
1219 ret = prop->info->parse(dev, prop, ptr);
Paolo Bonzini7db4c4e2011-12-18 17:05:07 +01001220 error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001221 g_free(ptr);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001222}
1223
1224/**
1225 * @qdev_add_legacy_property - adds a legacy property
1226 *
1227 * Do not use this is new code! Properties added through this interface will
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001228 * be given names and types in the "legacy" namespace.
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001229 *
1230 * Legacy properties are always processed as strings. The format of the string
1231 * depends on the property type.
1232 */
1233void qdev_property_add_legacy(DeviceState *dev, Property *prop,
1234 Error **errp)
1235{
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001236 gchar *name, *type;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001237
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001238 name = g_strdup_printf("legacy-%s", prop->name);
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +01001239 type = g_strdup_printf("legacy<%s>",
1240 prop->info->legacy_name ?: prop->info->name);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001241
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001242 qdev_property_add(dev, name, type,
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001243 prop->info->print ? qdev_get_legacy_property : NULL,
1244 prop->info->parse ? qdev_set_legacy_property : NULL,
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001245 NULL,
1246 prop, errp);
1247
1248 g_free(type);
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001249 g_free(name);
1250}
1251
1252/**
1253 * @qdev_property_add_static - add a @Property to a device.
1254 *
1255 * Static properties access data in a struct. The actual type of the
1256 * property and the field depends on the property type.
1257 */
1258void qdev_property_add_static(DeviceState *dev, Property *prop,
1259 Error **errp)
1260{
1261 qdev_property_add(dev, prop->name, prop->info->name,
1262 prop->info->get, prop->info->set,
1263 NULL,
1264 prop, errp);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001265}
Anthony Liguoria10f07a2011-12-12 14:29:28 -06001266
1267DeviceState *qdev_get_root(void)
1268{
1269 static DeviceState *qdev_root;
1270
1271 if (!qdev_root) {
1272 qdev_root = qdev_create(NULL, "container");
1273 qdev_init_nofail(qdev_root);
1274 }
1275
1276 return qdev_root;
1277}
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001278
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001279static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
1280 const char *name, Error **errp)
1281{
1282 DeviceState *child = opaque;
1283 gchar *path;
1284
1285 path = qdev_get_canonical_path(child);
1286 visit_type_str(v, &path, name, errp);
1287 g_free(path);
1288}
1289
Anthony Liguori024a6fb2012-01-13 07:45:55 -06001290static void qdev_release_child_property(DeviceState *dev, const char *name,
1291 void *opaque)
1292{
1293 DeviceState *child = opaque;
1294
1295 qdev_unref(child);
1296}
1297
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001298void qdev_property_add_child(DeviceState *dev, const char *name,
1299 DeviceState *child, Error **errp)
1300{
1301 gchar *type;
1302
Anthony Liguori30fbb9f2011-12-04 11:08:36 -06001303 type = g_strdup_printf("child<%s>", qdev_get_info(child)->name);
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001304
1305 qdev_property_add(dev, name, type, qdev_get_child_property,
Anthony Liguori024a6fb2012-01-13 07:45:55 -06001306 NULL, qdev_release_child_property,
1307 child, errp);
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001308
1309 qdev_ref(child);
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001310 g_assert(child->parent == NULL);
1311 child->parent = dev;
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001312
1313 g_free(type);
1314}
1315
Anthony Liguori83e94fb2011-12-12 14:29:32 -06001316static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
1317 const char *name, Error **errp)
1318{
1319 DeviceState **child = opaque;
1320 gchar *path;
1321
1322 if (*child) {
1323 path = qdev_get_canonical_path(*child);
1324 visit_type_str(v, &path, name, errp);
1325 g_free(path);
1326 } else {
1327 path = (gchar *)"";
1328 visit_type_str(v, &path, name, errp);
1329 }
1330}
1331
1332static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
1333 const char *name, Error **errp)
1334{
1335 DeviceState **child = opaque;
1336 bool ambiguous = false;
1337 const char *type;
1338 char *path;
1339
1340 type = qdev_property_get_type(dev, name, NULL);
1341
1342 visit_type_str(v, &path, name, errp);
1343
1344 if (*child) {
1345 qdev_unref(*child);
1346 }
1347
1348 if (strcmp(path, "") != 0) {
1349 DeviceState *target;
1350
1351 target = qdev_resolve_path(path, &ambiguous);
1352 if (target) {
1353 gchar *target_type;
1354
Anthony Liguori30fbb9f2011-12-04 11:08:36 -06001355 target_type = g_strdup_printf("link<%s>", qdev_get_info(target)->name);
Anthony Liguori83e94fb2011-12-12 14:29:32 -06001356 if (strcmp(target_type, type) == 0) {
1357 *child = target;
1358 qdev_ref(target);
1359 } else {
1360 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
1361 }
1362
1363 g_free(target_type);
1364 } else {
1365 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
1366 }
1367 } else {
1368 *child = NULL;
1369 }
1370
1371 g_free(path);
1372}
1373
1374void qdev_property_add_link(DeviceState *dev, const char *name,
1375 const char *type, DeviceState **child,
1376 Error **errp)
1377{
1378 gchar *full_type;
1379
1380 full_type = g_strdup_printf("link<%s>", type);
1381
1382 qdev_property_add(dev, name, full_type,
1383 qdev_get_link_property,
1384 qdev_set_link_property,
1385 NULL, child, errp);
1386
1387 g_free(full_type);
1388}
1389
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001390gchar *qdev_get_canonical_path(DeviceState *dev)
1391{
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001392 DeviceState *root = qdev_get_root();
1393 char *newpath = NULL, *path = NULL;
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001394
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001395 while (dev != root) {
1396 DeviceProperty *prop = NULL;
1397
1398 g_assert(dev->parent != NULL);
1399
1400 QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
1401 if (!strstart(prop->type, "child<", NULL)) {
1402 continue;
1403 }
1404
1405 if (prop->opaque == dev) {
1406 if (path) {
1407 newpath = g_strdup_printf("%s/%s", prop->name, path);
1408 g_free(path);
1409 path = newpath;
1410 } else {
1411 path = g_strdup(prop->name);
1412 }
1413 break;
1414 }
1415 }
1416
1417 g_assert(prop != NULL);
1418
1419 dev = dev->parent;
1420 }
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001421
1422 newpath = g_strdup_printf("/%s", path);
1423 g_free(path);
1424
1425 return newpath;
1426}
Anthony Liguoridc45c212011-12-12 14:29:30 -06001427
1428static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
1429 gchar **parts,
1430 int index)
1431{
1432 DeviceProperty *prop;
1433 DeviceState *child;
1434
1435 if (parts[index] == NULL) {
1436 return parent;
1437 }
1438
1439 if (strcmp(parts[index], "") == 0) {
1440 return qdev_resolve_abs_path(parent, parts, index + 1);
1441 }
1442
1443 prop = qdev_property_find(parent, parts[index]);
1444 if (prop == NULL) {
1445 return NULL;
1446 }
1447
1448 child = NULL;
1449 if (strstart(prop->type, "link<", NULL)) {
1450 DeviceState **pchild = prop->opaque;
1451 if (*pchild) {
1452 child = *pchild;
1453 }
1454 } else if (strstart(prop->type, "child<", NULL)) {
1455 child = prop->opaque;
1456 }
1457
1458 if (!child) {
1459 return NULL;
1460 }
1461
1462 return qdev_resolve_abs_path(child, parts, index + 1);
1463}
1464
1465static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
1466 gchar **parts,
1467 bool *ambiguous)
1468{
1469 DeviceState *dev;
1470 DeviceProperty *prop;
1471
1472 dev = qdev_resolve_abs_path(parent, parts, 0);
1473
1474 QTAILQ_FOREACH(prop, &parent->properties, node) {
1475 DeviceState *found;
1476
1477 if (!strstart(prop->type, "child<", NULL)) {
1478 continue;
1479 }
1480
1481 found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
1482 if (found) {
1483 if (dev) {
1484 if (ambiguous) {
1485 *ambiguous = true;
1486 }
1487 return NULL;
1488 }
1489 dev = found;
1490 }
1491
1492 if (ambiguous && *ambiguous) {
1493 return NULL;
1494 }
1495 }
1496
1497 return dev;
1498}
1499
1500DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
1501{
1502 bool partial_path = true;
1503 DeviceState *dev;
1504 gchar **parts;
1505
1506 parts = g_strsplit(path, "/", 0);
1507 if (parts == NULL || parts[0] == NULL) {
1508 g_strfreev(parts);
1509 return qdev_get_root();
1510 }
1511
1512 if (strcmp(parts[0], "") == 0) {
1513 partial_path = false;
1514 }
1515
1516 if (partial_path) {
1517 if (ambiguous) {
1518 *ambiguous = false;
1519 }
1520 dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
1521 } else {
1522 dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
1523 }
1524
1525 g_strfreev(parts);
1526
1527 return dev;
1528}
1529
Anthony Liguori6a146eb2011-12-12 14:29:42 -06001530typedef struct StringProperty
1531{
1532 char *(*get)(DeviceState *, Error **);
1533 void (*set)(DeviceState *, const char *, Error **);
1534} StringProperty;
1535
1536static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque,
1537 const char *name, Error **errp)
1538{
1539 StringProperty *prop = opaque;
1540 char *value;
1541
1542 value = prop->get(dev, errp);
1543 if (value) {
1544 visit_type_str(v, &value, name, errp);
1545 g_free(value);
1546 }
1547}
1548
1549static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque,
1550 const char *name, Error **errp)
1551{
1552 StringProperty *prop = opaque;
1553 char *value;
1554 Error *local_err = NULL;
1555
1556 visit_type_str(v, &value, name, &local_err);
1557 if (local_err) {
1558 error_propagate(errp, local_err);
1559 return;
1560 }
1561
1562 prop->set(dev, value, errp);
1563 g_free(value);
1564}
1565
1566static void qdev_property_release_str(DeviceState *dev, const char *name,
1567 void *opaque)
1568{
1569 StringProperty *prop = opaque;
1570 g_free(prop);
1571}
1572
1573void qdev_property_add_str(DeviceState *dev, const char *name,
1574 char *(*get)(DeviceState *, Error **),
1575 void (*set)(DeviceState *, const char *, Error **),
1576 Error **errp)
1577{
1578 StringProperty *prop = g_malloc0(sizeof(*prop));
1579
1580 prop->get = get;
1581 prop->set = set;
1582
1583 qdev_property_add(dev, name, "string",
1584 get ? qdev_property_get_str : NULL,
1585 set ? qdev_property_set_str : NULL,
1586 qdev_property_release_str,
1587 prop, errp);
1588}
Anthony Liguori1de81d22011-12-19 16:37:46 -06001589
1590void qdev_machine_init(void)
1591{
1592 qdev_get_peripheral_anon();
1593 qdev_get_peripheral();
1594}
Anthony Liguori32fea402011-12-16 14:34:46 -06001595
1596static TypeInfo device_type_info = {
1597 .name = TYPE_DEVICE,
1598 .parent = TYPE_OBJECT,
1599 .instance_size = sizeof(DeviceState),
1600 .abstract = true,
1601 .class_size = sizeof(DeviceClass),
1602};
1603
1604static void init_qdev(void)
1605{
1606 type_register_static(&device_type_info);
1607}
1608
1609device_init(init_qdev);