blob: cb3fc6e56dd1a7dc1cf8c25c3f8987023747d80c [file] [log] [blame]
Paul Brookaae94602009-05-14 22:35:06 +01001/*
2 * Dynamic device configuration and creation.
3 *
4 * Copyright (c) 2009 CodeSourcery
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Paul Brookaae94602009-05-14 22:35:06 +010018 */
19
20/* The theory here is that it should be possible to create a machine without
21 knowledge of specific devices. Historically board init routines have
22 passed a bunch of arguments to each device, requiring the board know
23 exactly which device it is dealing with. This file provides an abstract
24 API for device configuration and initialization. Devices will generally
25 inherit from a particular bus (e.g. PCI or I2C) rather than
26 this API directly. */
27
Paul Brook9d07d752009-05-14 22:35:07 +010028#include "net.h"
Paul Brookaae94602009-05-14 22:35:06 +010029#include "qdev.h"
30#include "sysemu.h"
Gerd Hoffmanncae49562009-06-05 15:53:17 +010031#include "monitor.h"
Paul Brookaae94602009-05-14 22:35:06 +010032
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020033static int qdev_hotplug = 0;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070034static bool qdev_hot_added = false;
35static bool qdev_hot_removed = false;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020036
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020037/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000038static BusState *main_system_bus;
Isaku Yamahata2da8bb92011-08-02 10:59:13 +090039static void main_system_bus_create(void);
Paul Brook4d6ae672009-05-14 22:35:06 +010040
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010041DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010042
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020043static BusState *qbus_find_recursive(BusState *bus, const char *name,
44 const BusInfo *info);
45static BusState *qbus_find(const char *path);
46
Paul Brookaae94602009-05-14 22:35:06 +010047/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020048void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010049{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020050 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020051 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010052
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020053 info->next = device_info_list;
54 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010055}
56
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020057static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
58{
59 DeviceInfo *info;
60
Gerd Hoffmann3320e562009-07-15 13:43:33 +020061 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020062 for (info = device_info_list; info != NULL; info = info->next) {
63 if (bus_info && info->bus_info != bus_info)
64 continue;
65 if (strcmp(info->name, name) != 0)
66 continue;
67 return info;
68 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020069
70 /* failing that check the aliases */
71 for (info = device_info_list; info != NULL; info = info->next) {
72 if (bus_info && info->bus_info != bus_info)
73 continue;
74 if (!info->alias)
75 continue;
76 if (strcmp(info->alias, name) != 0)
77 continue;
78 return info;
79 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020080 return NULL;
81}
82
Markus Armbruster0c175422010-02-19 19:12:18 +010083static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010084{
Paul Brookaae94602009-05-14 22:35:06 +010085 DeviceState *dev;
Anthony Liguoria5296ca2011-12-12 14:29:27 -060086 Property *prop;
Paul Brookaae94602009-05-14 22:35:06 +010087
Markus Armbruster0c175422010-02-19 19:12:18 +010088 assert(bus->info == info->bus_info);
Anthony Liguori7267c092011-08-20 22:09:37 -050089 dev = g_malloc0(info->size);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020090 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010091 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020092 qdev_prop_set_defaults(dev, dev->info->props);
93 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +010094 qdev_prop_set_globals(dev);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +020095 QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020096 if (qdev_hotplug) {
97 assert(bus->allow_hotplug);
98 dev->hotplugged = 1;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070099 qdev_hot_added = true;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200100 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200101 dev->instance_id_alias = -1;
Anthony Liguori44677de2011-12-12 14:29:26 -0600102 QTAILQ_INIT(&dev->properties);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200103 dev->state = DEV_STATE_CREATED;
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600104
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
Paul Brookaae94602009-05-14 22:35:06 +0100113 return dev;
114}
115
Markus Armbruster0c175422010-02-19 19:12:18 +0100116/* 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. */
119DeviceState *qdev_create(BusState *bus, const char *name)
120{
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000121 DeviceState *dev;
122
123 dev = qdev_try_create(bus, name);
124 if (!dev) {
Peter Maydelle92714c2011-08-03 23:49:04 +0100125 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 }
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000131 }
132
133 return dev;
134}
135
136DeviceState *qdev_try_create(BusState *bus, const char *name)
137{
Markus Armbruster0c175422010-02-19 19:12:18 +0100138 DeviceInfo *info;
139
140 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100141 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100142 }
143
144 info = qdev_find_info(bus->info, name);
145 if (!info) {
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000146 return NULL;
Markus Armbruster0c175422010-02-19 19:12:18 +0100147 }
148
149 return qdev_create_from_info(bus, info);
150}
151
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100152static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200153{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100154 error_printf("name \"%s\", bus %s",
155 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200156 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100157 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200158 }
159 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100160 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200161 }
162 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100163 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200164 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100165 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200166}
167
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200168static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200169{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200170 DeviceState *dev = opaque;
171
172 if (strcmp(name, "driver") == 0)
173 return 0;
174 if (strcmp(name, "bus") == 0)
175 return 0;
176
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100177 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200178 return -1;
179 }
180 return 0;
181}
182
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100183int qdev_device_help(QemuOpts *opts)
184{
185 const char *driver;
186 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100187 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100188
189 driver = qemu_opt_get(opts, "driver");
190 if (driver && !strcmp(driver, "?")) {
191 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100192 if (info->no_user) {
193 continue; /* not available, don't show */
194 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100195 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100196 }
197 return 1;
198 }
199
Markus Armbruster542379f2011-11-08 11:00:38 +0100200 if (!driver || !qemu_opt_get(opts, "?")) {
Markus Armbruster08350cf2010-01-29 19:49:00 +0100201 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++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100210 /*
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 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100219 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100220 }
Gerd Hoffmanna8467c72011-09-16 11:25:05 +0200221 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 }
225 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
226 }
Markus Armbruster08350cf2010-01-29 19:49:00 +0100227 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100228}
229
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600230static 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
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200243DeviceState *qdev_device_add(QemuOpts *opts)
244{
245 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200246 DeviceInfo *info;
247 DeviceState *qdev;
248 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200249
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200250 driver = qemu_opt_get(opts, "driver");
251 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100252 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200253 return NULL;
254 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200255
256 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200257 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100258 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100259 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100260 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200261 return NULL;
262 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200263
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200264 /* find bus */
265 path = qemu_opt_get(opts, "bus");
266 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200267 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100268 if (!bus) {
269 return NULL;
270 }
271 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100272 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
273 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100274 return NULL;
275 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200276 } else {
277 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100278 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100279 qerror_report(QERR_NO_BUS_FOR_DEVICE,
280 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100281 return NULL;
282 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200283 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200284 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100285 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200286 return NULL;
287 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200288
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200289 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100290 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200291 id = qemu_opts_id(opts);
292 if (id) {
293 qdev->id = id;
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600294 qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200295 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200296 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
297 qdev_free(qdev);
298 return NULL;
299 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200300 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100301 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200302 return NULL;
303 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200304 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200305 return qdev;
306}
307
Paul Brookaae94602009-05-14 22:35:06 +0100308/* Initialize a device. Device properties should be set before calling
309 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200310 calling this function.
311 On failure, destroy the device and return negative value.
312 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200313int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100314{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200315 int rc;
316
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200317 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200318 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200319 if (rc < 0) {
320 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200321 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200322 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200323 if (dev->info->vmsd) {
Alex Williamson0be71e32010-06-25 11:09:07 -0600324 vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200325 dev->instance_id_alias,
326 dev->alias_required_for_version);
327 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200328 dev->state = DEV_STATE_INITIALIZED;
Jan Kiszka5ab28c82011-07-24 19:38:36 +0200329 if (dev->hotplugged && dev->info->reset) {
330 dev->info->reset(dev);
331 }
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200332 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100333}
334
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200335void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
336 int required_for_version)
337{
338 assert(dev->state == DEV_STATE_CREATED);
339 dev->instance_id_alias = alias_id;
340 dev->alias_required_for_version = required_for_version;
341}
342
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200343int qdev_unplug(DeviceState *dev)
344{
345 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100346 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200347 return -1;
348 }
Amit Shah593831d2009-11-02 14:56:41 +0530349 assert(dev->info->unplug != NULL);
350
Anthony Liguori85ed3032011-12-12 14:29:25 -0600351 if (dev->ref != 0) {
352 qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
353 return -1;
354 }
355
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700356 qdev_hot_removed = true;
357
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200358 return dev->info->unplug(dev);
359}
360
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900361static int qdev_reset_one(DeviceState *dev, void *opaque)
362{
363 if (dev->info->reset) {
364 dev->info->reset(dev);
365 }
366
367 return 0;
368}
369
370BusState *sysbus_get_default(void)
371{
Stefan Weil68694892010-12-16 19:33:22 +0100372 if (!main_system_bus) {
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900373 main_system_bus_create();
Stefan Weil68694892010-12-16 19:33:22 +0100374 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900375 return main_system_bus;
376}
377
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900378static int qbus_reset_one(BusState *bus, void *opaque)
379{
380 if (bus->info->reset) {
381 return bus->info->reset(bus);
382 }
383 return 0;
384}
385
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900386void qdev_reset_all(DeviceState *dev)
387{
388 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
389}
390
Isaku Yamahata80376c32010-12-20 14:33:35 +0900391void qbus_reset_all_fn(void *opaque)
392{
393 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200394 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900395}
396
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200397/* can be used as ->unplug() callback for the simple cases */
398int qdev_simple_unplug_cb(DeviceState *dev)
399{
400 /* just zap it */
401 qdev_free(dev);
402 return 0;
403}
404
Michael Tokarev3b29a102011-04-06 17:51:59 +0400405
406/* Like qdev_init(), but terminate program via error_report() instead of
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200407 returning an error value. This is okay during machine creation.
408 Don't use for hotplug, because there callers need to recover from
409 failure. Exception: if you know the device's init() callback can't
410 fail, then qdev_init_nofail() can't fail either, and is therefore
411 usable even then. But relying on the device implementation that
412 way is somewhat unclean, and best avoided. */
413void qdev_init_nofail(DeviceState *dev)
414{
415 DeviceInfo *info = dev->info;
416
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200417 if (qdev_init(dev) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +0200418 error_report("Initialization of device %s failed", info->name);
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200419 exit(1);
420 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200421}
422
Anthony Liguori44677de2011-12-12 14:29:26 -0600423static void qdev_property_del_all(DeviceState *dev)
424{
425 while (!QTAILQ_EMPTY(&dev->properties)) {
426 DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
427
428 QTAILQ_REMOVE(&dev->properties, prop, node);
429
430 if (prop->release) {
431 prop->release(dev, prop->name, prop->opaque);
432 }
433
434 g_free(prop->name);
435 g_free(prop->type);
436 g_free(prop);
437 }
438}
439
Paul Brook02e2da42009-05-23 00:05:19 +0100440/* Unlink device from bus and free the structure. */
441void qdev_free(DeviceState *dev)
442{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200443 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200444 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200445
Anthony Liguori44677de2011-12-12 14:29:26 -0600446 qdev_property_del_all(dev);
447
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200448 if (dev->state == DEV_STATE_INITIALIZED) {
449 while (dev->num_child_bus) {
450 bus = QLIST_FIRST(&dev->child_bus);
451 qbus_free(bus);
452 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200453 if (dev->info->vmsd)
Alex Williamson0be71e32010-06-25 11:09:07 -0600454 vmstate_unregister(dev, dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200455 if (dev->info->exit)
456 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200457 if (dev->opts)
458 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200459 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200460 QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200461 for (prop = dev->info->props; prop && prop->name; prop++) {
462 if (prop->info->free) {
463 prop->info->free(dev, prop);
464 }
465 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500466 g_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100467}
468
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200469void qdev_machine_creation_done(void)
470{
471 /*
472 * ok, initial machine setup is done, starting from now we can
473 * only create hotpluggable devices
474 */
475 qdev_hotplug = 1;
476}
477
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700478bool qdev_machine_modified(void)
479{
480 return qdev_hot_added || qdev_hot_removed;
481}
482
Paul Brookaae94602009-05-14 22:35:06 +0100483/* Get a character (serial) device interface. */
484CharDriverState *qdev_init_chardev(DeviceState *dev)
485{
486 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530487
488 /* FIXME: This function needs to go away: use chardev properties! */
489 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100490}
491
Paul Brook02e2da42009-05-23 00:05:19 +0100492BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100493{
Paul Brook02e2da42009-05-23 00:05:19 +0100494 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100495}
496
Paul Brookaae94602009-05-14 22:35:06 +0100497void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
498{
499 assert(dev->num_gpio_in == 0);
500 dev->num_gpio_in = n;
501 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
502}
503
504void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
505{
506 assert(dev->num_gpio_out == 0);
507 dev->num_gpio_out = n;
508 dev->gpio_out = pins;
509}
510
511qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
512{
513 assert(n >= 0 && n < dev->num_gpio_in);
514 return dev->gpio_in[n];
515}
516
517void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
518{
519 assert(n >= 0 && n < dev->num_gpio_out);
520 dev->gpio_out[n] = pin;
521}
522
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200523void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
524{
Jan Kiszka6eed1852011-07-20 12:20:22 +0200525 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200526 if (nd->vlan)
527 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
528 if (nd->netdev)
529 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530530 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200531 qdev_prop_exists(dev, "vectors")) {
532 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
533 }
Peter Maydell48e2faf2011-05-20 16:50:01 +0100534 nd->instantiated = 1;
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200535}
536
Paul Brook02e2da42009-05-23 00:05:19 +0100537BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100538{
Paul Brook02e2da42009-05-23 00:05:19 +0100539 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100540
Blue Swirl72cf2d42009-09-12 07:36:22 +0000541 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100542 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100543 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100544 }
545 }
546 return NULL;
547}
548
Anthony Liguori81699d82010-11-19 18:55:58 +0900549int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
550 qbus_walkerfn *busfn, void *opaque)
551{
552 DeviceState *dev;
553 int err;
554
555 if (busfn) {
556 err = busfn(bus, opaque);
557 if (err) {
558 return err;
559 }
560 }
561
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200562 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori81699d82010-11-19 18:55:58 +0900563 err = qdev_walk_children(dev, devfn, busfn, opaque);
564 if (err < 0) {
565 return err;
566 }
567 }
568
569 return 0;
570}
571
572int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
573 qbus_walkerfn *busfn, void *opaque)
574{
575 BusState *bus;
576 int err;
577
578 if (devfn) {
579 err = devfn(dev, opaque);
580 if (err) {
581 return err;
582 }
583 }
584
585 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
586 err = qbus_walk_children(bus, devfn, busfn, opaque);
587 if (err < 0) {
588 return err;
589 }
590 }
591
592 return 0;
593}
594
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200595static BusState *qbus_find_recursive(BusState *bus, const char *name,
596 const BusInfo *info)
597{
598 DeviceState *dev;
599 BusState *child, *ret;
600 int match = 1;
601
602 if (name && (strcmp(bus->name, name) != 0)) {
603 match = 0;
604 }
605 if (info && (bus->info != info)) {
606 match = 0;
607 }
608 if (match) {
609 return bus;
610 }
611
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200612 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000613 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200614 ret = qbus_find_recursive(child, name, info);
615 if (ret) {
616 return ret;
617 }
618 }
619 }
620 return NULL;
621}
622
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900623DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200624{
625 DeviceState *dev, *ret;
626 BusState *child;
627
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200628 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200629 if (dev->id && strcmp(dev->id, id) == 0)
630 return dev;
631 QLIST_FOREACH(child, &dev->child_bus, sibling) {
632 ret = qdev_find_recursive(child, id);
633 if (ret) {
634 return ret;
635 }
636 }
637 }
638 return NULL;
639}
640
Markus Armbruster53db16b2010-02-18 18:55:59 +0100641static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200642{
643 BusState *child;
644 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200645
Markus Armbruster53db16b2010-02-18 18:55:59 +0100646 error_printf("child busses at \"%s\":",
647 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000648 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100649 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200650 sep = ", ";
651 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100652 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200653}
654
Markus Armbruster53db16b2010-02-18 18:55:59 +0100655static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200656{
657 DeviceState *dev;
658 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200659
Markus Armbruster53db16b2010-02-18 18:55:59 +0100660 error_printf("devices at \"%s\":", bus->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200661 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100662 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200663 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100664 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200665 sep = ", ";
666 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100667 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200668}
669
670static BusState *qbus_find_bus(DeviceState *dev, char *elem)
671{
672 BusState *child;
673
Blue Swirl72cf2d42009-09-12 07:36:22 +0000674 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200675 if (strcmp(child->name, elem) == 0) {
676 return child;
677 }
678 }
679 return NULL;
680}
681
682static DeviceState *qbus_find_dev(BusState *bus, char *elem)
683{
684 DeviceState *dev;
685
686 /*
687 * try to match in order:
688 * (1) instance id, if present
689 * (2) driver name
690 * (3) driver alias, if present
691 */
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200692 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200693 if (dev->id && strcmp(dev->id, elem) == 0) {
694 return dev;
695 }
696 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200697 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200698 if (strcmp(dev->info->name, elem) == 0) {
699 return dev;
700 }
701 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200702 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200703 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
704 return dev;
705 }
706 }
707 return NULL;
708}
709
710static BusState *qbus_find(const char *path)
711{
712 DeviceState *dev;
713 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100714 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200715 int pos, len;
716
717 /* find start element */
718 if (path[0] == '/') {
719 bus = main_system_bus;
720 pos = 0;
721 } else {
722 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100723 assert(!path[0]);
724 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200725 }
726 bus = qbus_find_recursive(main_system_bus, elem, NULL);
727 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100728 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200729 return NULL;
730 }
731 pos = len;
732 }
733
734 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100735 assert(path[pos] == '/' || !path[pos]);
736 while (path[pos] == '/') {
737 pos++;
738 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200739 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200740 return bus;
741 }
742
743 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100744 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
745 assert(0);
746 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200747 }
748 pos += len;
749 dev = qbus_find_dev(bus, elem);
750 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100751 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100752 if (!monitor_cur_is_qmp()) {
753 qbus_list_dev(bus);
754 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200755 return NULL;
756 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100757
758 assert(path[pos] == '/' || !path[pos]);
759 while (path[pos] == '/') {
760 pos++;
761 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200762 if (path[pos] == '\0') {
763 /* last specified element is a device. If it has exactly
764 * one child bus accept it nevertheless */
765 switch (dev->num_child_bus) {
766 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100767 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200768 return NULL;
769 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000770 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200771 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100772 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100773 if (!monitor_cur_is_qmp()) {
774 qbus_list_bus(dev);
775 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200776 return NULL;
777 }
778 }
779
780 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100781 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
782 assert(0);
783 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200784 }
785 pos += len;
786 bus = qbus_find_bus(dev, elem);
787 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100788 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100789 if (!monitor_cur_is_qmp()) {
790 qbus_list_bus(dev);
791 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200792 return NULL;
793 }
794 }
795}
796
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200797void qbus_create_inplace(BusState *bus, BusInfo *info,
798 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100799{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200800 char *buf;
801 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100802
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200803 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100804 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200805
806 if (name) {
807 /* use supplied name */
Anthony Liguori7267c092011-08-20 22:09:37 -0500808 bus->name = g_strdup(name);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200809 } else if (parent && parent->id) {
810 /* parent device has id -> use it for bus name */
811 len = strlen(parent->id) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500812 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200813 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
814 bus->name = buf;
815 } else {
816 /* no id -> use lowercase bus type for bus name */
817 len = strlen(info->name) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500818 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200819 len = snprintf(buf, len, "%s.%d", info->name,
820 parent ? parent->num_child_bus : 0);
821 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200822 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200823 bus->name = buf;
824 }
825
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200826 QTAILQ_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100827 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000828 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200829 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900830 } else if (bus != main_system_bus) {
831 /* TODO: once all bus devices are qdevified,
832 only reset handler for main_system_bus should be registered here. */
833 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100834 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200835}
836
837BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
838{
839 BusState *bus;
840
Anthony Liguori7267c092011-08-20 22:09:37 -0500841 bus = g_malloc0(info->size);
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200842 bus->qdev_allocated = 1;
843 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100844 return bus;
845}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100846
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900847static void main_system_bus_create(void)
848{
849 /* assign main_system_bus before qbus_create_inplace()
850 * in order to make "if (bus != main_system_bus)" work */
Anthony Liguori7267c092011-08-20 22:09:37 -0500851 main_system_bus = g_malloc0(system_bus_info.size);
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900852 main_system_bus->qdev_allocated = 1;
853 qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
854 "main-system-bus");
855}
856
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200857void qbus_free(BusState *bus)
858{
859 DeviceState *dev;
860
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200861 while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200862 qdev_free(dev);
863 }
864 if (bus->parent) {
865 QLIST_REMOVE(bus, sibling);
866 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900867 } else {
868 assert(bus != main_system_bus); /* main_system_bus is never freed */
869 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200870 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500871 g_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200872 if (bus->qdev_allocated) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500873 g_free(bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200874 }
875}
876
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100877#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
878static void qbus_print(Monitor *mon, BusState *bus, int indent);
879
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200880static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
881 const char *prefix, int indent)
882{
883 char buf[64];
884
885 if (!props)
886 return;
887 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100888 /*
889 * TODO Properties without a print method are just for dirty
890 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
891 * marked for removal. The test props->info->print should be
892 * removed along with it.
893 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200894 if (props->info->print) {
895 props->info->print(dev, props, buf, sizeof(buf));
896 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
897 }
898 props++;
899 }
900}
901
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100902static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
903{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100904 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200905 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
906 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100907 indent += 2;
908 if (dev->num_gpio_in) {
909 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
910 }
911 if (dev->num_gpio_out) {
912 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
913 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200914 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
915 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200916 if (dev->parent_bus->info->print_dev)
917 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000918 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100919 qbus_print(mon, child, indent);
920 }
921}
922
923static void qbus_print(Monitor *mon, BusState *bus, int indent)
924{
925 struct DeviceState *dev;
926
927 qdev_printf("bus: %s\n", bus->name);
928 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200929 qdev_printf("type %s\n", bus->info->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200930 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100931 qdev_print(mon, dev, indent);
932 }
933}
934#undef qdev_printf
935
936void do_info_qtree(Monitor *mon)
937{
938 if (main_system_bus)
939 qbus_print(mon, main_system_bus, 0);
940}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200941
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200942void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200943{
944 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200945
946 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100947 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200948 }
949}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200950
Markus Armbruster8bc27242010-02-10 20:52:01 +0100951int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200952{
953 QemuOpts *opts;
954
Gerd Hoffmann3329f072010-08-20 13:52:01 +0200955 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100956 if (!opts) {
957 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +0100958 }
Markus Armbruster8bc27242010-02-10 20:52:01 +0100959 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
960 qemu_opts_del(opts);
961 return 0;
962 }
963 if (!qdev_device_add(opts)) {
964 qemu_opts_del(opts);
965 return -1;
966 }
967 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200968}
969
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100970int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200971{
972 const char *id = qdict_get_str(qdict, "id");
973 DeviceState *dev;
974
975 dev = qdev_find_recursive(main_system_bus, id);
976 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100977 qerror_report(QERR_DEVICE_NOT_FOUND, id);
978 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200979 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100980 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200981}
Gleb Natapov1ca4d092010-12-08 13:35:05 +0200982
983static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
984{
985 int l = 0;
986
987 if (dev && dev->parent_bus) {
988 char *d;
989 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
990 if (dev->parent_bus->info->get_fw_dev_path) {
991 d = dev->parent_bus->info->get_fw_dev_path(dev);
992 l += snprintf(p + l, size - l, "%s", d);
Anthony Liguori7267c092011-08-20 22:09:37 -0500993 g_free(d);
Gleb Natapov1ca4d092010-12-08 13:35:05 +0200994 } else {
995 l += snprintf(p + l, size - l, "%s", dev->info->name);
996 }
997 }
998 l += snprintf(p + l , size - l, "/");
999
1000 return l;
1001}
1002
1003char* qdev_get_fw_dev_path(DeviceState *dev)
1004{
1005 char path[128];
1006 int l;
1007
1008 l = qdev_get_fw_dev_path_helper(dev, path, 128);
1009
1010 path[l-1] = '\0';
1011
1012 return strdup(path);
1013}
Anthony Liguori85ed3032011-12-12 14:29:25 -06001014
1015void qdev_ref(DeviceState *dev)
1016{
1017 dev->ref++;
1018}
1019
1020void qdev_unref(DeviceState *dev)
1021{
1022 g_assert(dev->ref > 0);
1023 dev->ref--;
1024}
Anthony Liguori44677de2011-12-12 14:29:26 -06001025
1026void qdev_property_add(DeviceState *dev, const char *name, const char *type,
1027 DevicePropertyAccessor *get, DevicePropertyAccessor *set,
1028 DevicePropertyRelease *release,
1029 void *opaque, Error **errp)
1030{
1031 DeviceProperty *prop = g_malloc0(sizeof(*prop));
1032
1033 prop->name = g_strdup(name);
1034 prop->type = g_strdup(type);
1035
1036 prop->get = get;
1037 prop->set = set;
1038 prop->release = release;
1039 prop->opaque = opaque;
1040
1041 QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
1042}
1043
1044static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
1045{
1046 DeviceProperty *prop;
1047
1048 QTAILQ_FOREACH(prop, &dev->properties, node) {
1049 if (strcmp(prop->name, name) == 0) {
1050 return prop;
1051 }
1052 }
1053
1054 return NULL;
1055}
1056
1057void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
1058 Error **errp)
1059{
1060 DeviceProperty *prop = qdev_property_find(dev, name);
1061
1062 if (prop == NULL) {
1063 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1064 return;
1065 }
1066
1067 if (!prop->get) {
1068 error_set(errp, QERR_PERMISSION_DENIED);
1069 } else {
1070 prop->get(dev, v, prop->opaque, name, errp);
1071 }
1072}
1073
1074void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
1075 Error **errp)
1076{
1077 DeviceProperty *prop = qdev_property_find(dev, name);
1078
1079 if (prop == NULL) {
1080 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1081 return;
1082 }
1083
1084 if (!prop->set) {
1085 error_set(errp, QERR_PERMISSION_DENIED);
1086 } else {
1087 prop->set(dev, prop->opaque, v, name, errp);
1088 }
1089}
1090
1091const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
1092{
1093 DeviceProperty *prop = qdev_property_find(dev, name);
1094
1095 if (prop == NULL) {
1096 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1097 return NULL;
1098 }
1099
1100 return prop->type;
1101}
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001102
1103/**
1104 * Legacy property handling
1105 */
1106
1107static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1108 const char *name, Error **errp)
1109{
1110 Property *prop = opaque;
1111
1112 if (prop->info->print) {
1113 char buffer[1024];
1114 char *ptr = buffer;
1115
1116 prop->info->print(dev, prop, buffer, sizeof(buffer));
1117 visit_type_str(v, &ptr, name, errp);
1118 } else {
1119 error_set(errp, QERR_PERMISSION_DENIED);
1120 }
1121}
1122
1123static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1124 const char *name, Error **errp)
1125{
1126 Property *prop = opaque;
1127
1128 if (dev->state != DEV_STATE_CREATED) {
1129 error_set(errp, QERR_PERMISSION_DENIED);
1130 return;
1131 }
1132
1133 if (prop->info->parse) {
1134 Error *local_err = NULL;
1135 char *ptr = NULL;
1136
1137 visit_type_str(v, &ptr, name, &local_err);
1138 if (!local_err) {
1139 int ret;
1140 ret = prop->info->parse(dev, prop, ptr);
1141 if (ret != 0) {
1142 error_set(errp, QERR_INVALID_PARAMETER_VALUE,
1143 name, prop->info->name);
1144 }
1145 g_free(ptr);
1146 } else {
1147 error_propagate(errp, local_err);
1148 }
1149 } else {
1150 error_set(errp, QERR_PERMISSION_DENIED);
1151 }
1152}
1153
1154/**
1155 * @qdev_add_legacy_property - adds a legacy property
1156 *
1157 * Do not use this is new code! Properties added through this interface will
1158 * be given types in the "legacy<>" type namespace.
1159 *
1160 * Legacy properties are always processed as strings. The format of the string
1161 * depends on the property type.
1162 */
1163void qdev_property_add_legacy(DeviceState *dev, Property *prop,
1164 Error **errp)
1165{
1166 gchar *type;
1167
1168 type = g_strdup_printf("legacy<%s>", prop->info->name);
1169
1170 qdev_property_add(dev, prop->name, type,
1171 qdev_get_legacy_property,
1172 qdev_set_legacy_property,
1173 NULL,
1174 prop, errp);
1175
1176 g_free(type);
1177}
Anthony Liguoria10f07a2011-12-12 14:29:28 -06001178
1179DeviceState *qdev_get_root(void)
1180{
1181 static DeviceState *qdev_root;
1182
1183 if (!qdev_root) {
1184 qdev_root = qdev_create(NULL, "container");
1185 qdev_init_nofail(qdev_root);
1186 }
1187
1188 return qdev_root;
1189}
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001190
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001191static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
1192 const char *name, Error **errp)
1193{
1194 DeviceState *child = opaque;
1195 gchar *path;
1196
1197 path = qdev_get_canonical_path(child);
1198 visit_type_str(v, &path, name, errp);
1199 g_free(path);
1200}
1201
1202void qdev_property_add_child(DeviceState *dev, const char *name,
1203 DeviceState *child, Error **errp)
1204{
1205 gchar *type;
1206
1207 type = g_strdup_printf("child<%s>", child->info->name);
1208
1209 qdev_property_add(dev, name, type, qdev_get_child_property,
1210 NULL, NULL, child, errp);
1211
1212 qdev_ref(child);
1213
1214 g_free(type);
1215}
1216
Anthony Liguori83e94fb2011-12-12 14:29:32 -06001217static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
1218 const char *name, Error **errp)
1219{
1220 DeviceState **child = opaque;
1221 gchar *path;
1222
1223 if (*child) {
1224 path = qdev_get_canonical_path(*child);
1225 visit_type_str(v, &path, name, errp);
1226 g_free(path);
1227 } else {
1228 path = (gchar *)"";
1229 visit_type_str(v, &path, name, errp);
1230 }
1231}
1232
1233static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
1234 const char *name, Error **errp)
1235{
1236 DeviceState **child = opaque;
1237 bool ambiguous = false;
1238 const char *type;
1239 char *path;
1240
1241 type = qdev_property_get_type(dev, name, NULL);
1242
1243 visit_type_str(v, &path, name, errp);
1244
1245 if (*child) {
1246 qdev_unref(*child);
1247 }
1248
1249 if (strcmp(path, "") != 0) {
1250 DeviceState *target;
1251
1252 target = qdev_resolve_path(path, &ambiguous);
1253 if (target) {
1254 gchar *target_type;
1255
1256 target_type = g_strdup_printf("link<%s>", target->info->name);
1257 if (strcmp(target_type, type) == 0) {
1258 *child = target;
1259 qdev_ref(target);
1260 } else {
1261 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
1262 }
1263
1264 g_free(target_type);
1265 } else {
1266 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
1267 }
1268 } else {
1269 *child = NULL;
1270 }
1271
1272 g_free(path);
1273}
1274
1275void qdev_property_add_link(DeviceState *dev, const char *name,
1276 const char *type, DeviceState **child,
1277 Error **errp)
1278{
1279 gchar *full_type;
1280
1281 full_type = g_strdup_printf("link<%s>", type);
1282
1283 qdev_property_add(dev, name, full_type,
1284 qdev_get_link_property,
1285 qdev_set_link_property,
1286 NULL, child, errp);
1287
1288 g_free(full_type);
1289}
1290
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001291static gchar *qdev_get_path_in(DeviceState *parent, DeviceState *dev)
1292{
1293 DeviceProperty *prop;
1294
1295 if (parent == dev) {
1296 return g_strdup("");
1297 }
1298
1299 QTAILQ_FOREACH(prop, &parent->properties, node) {
1300 gchar *subpath;
1301
1302 if (!strstart(prop->type, "child<", NULL)) {
1303 continue;
1304 }
1305
1306 /* Check to see if the device is one of parent's children */
1307 if (prop->opaque == dev) {
1308 return g_strdup(prop->name);
1309 }
1310
1311 /* Check to see if the device is a child of our child */
1312 subpath = qdev_get_path_in(prop->opaque, dev);
1313 if (subpath) {
1314 gchar *path;
1315
1316 path = g_strdup_printf("%s/%s", prop->name, subpath);
1317 g_free(subpath);
1318
1319 return path;
1320 }
1321 }
1322
1323 return NULL;
1324}
1325
1326gchar *qdev_get_canonical_path(DeviceState *dev)
1327{
1328 gchar *path, *newpath;
1329
1330 path = qdev_get_path_in(qdev_get_root(), dev);
1331 g_assert(path != NULL);
1332
1333 newpath = g_strdup_printf("/%s", path);
1334 g_free(path);
1335
1336 return newpath;
1337}
Anthony Liguoridc45c212011-12-12 14:29:30 -06001338
1339static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
1340 gchar **parts,
1341 int index)
1342{
1343 DeviceProperty *prop;
1344 DeviceState *child;
1345
1346 if (parts[index] == NULL) {
1347 return parent;
1348 }
1349
1350 if (strcmp(parts[index], "") == 0) {
1351 return qdev_resolve_abs_path(parent, parts, index + 1);
1352 }
1353
1354 prop = qdev_property_find(parent, parts[index]);
1355 if (prop == NULL) {
1356 return NULL;
1357 }
1358
1359 child = NULL;
1360 if (strstart(prop->type, "link<", NULL)) {
1361 DeviceState **pchild = prop->opaque;
1362 if (*pchild) {
1363 child = *pchild;
1364 }
1365 } else if (strstart(prop->type, "child<", NULL)) {
1366 child = prop->opaque;
1367 }
1368
1369 if (!child) {
1370 return NULL;
1371 }
1372
1373 return qdev_resolve_abs_path(child, parts, index + 1);
1374}
1375
1376static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
1377 gchar **parts,
1378 bool *ambiguous)
1379{
1380 DeviceState *dev;
1381 DeviceProperty *prop;
1382
1383 dev = qdev_resolve_abs_path(parent, parts, 0);
1384
1385 QTAILQ_FOREACH(prop, &parent->properties, node) {
1386 DeviceState *found;
1387
1388 if (!strstart(prop->type, "child<", NULL)) {
1389 continue;
1390 }
1391
1392 found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
1393 if (found) {
1394 if (dev) {
1395 if (ambiguous) {
1396 *ambiguous = true;
1397 }
1398 return NULL;
1399 }
1400 dev = found;
1401 }
1402
1403 if (ambiguous && *ambiguous) {
1404 return NULL;
1405 }
1406 }
1407
1408 return dev;
1409}
1410
1411DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
1412{
1413 bool partial_path = true;
1414 DeviceState *dev;
1415 gchar **parts;
1416
1417 parts = g_strsplit(path, "/", 0);
1418 if (parts == NULL || parts[0] == NULL) {
1419 g_strfreev(parts);
1420 return qdev_get_root();
1421 }
1422
1423 if (strcmp(parts[0], "") == 0) {
1424 partial_path = false;
1425 }
1426
1427 if (partial_path) {
1428 if (ambiguous) {
1429 *ambiguous = false;
1430 }
1431 dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
1432 } else {
1433 dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
1434 }
1435
1436 g_strfreev(parts);
1437
1438 return dev;
1439}
1440