blob: e59f3455d78cc94dce10195cb7f4b1d7d6535cc2 [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
Paolo Bonzinica2cc782011-12-18 17:05:11 +010083static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
84 Error **errp);
85
Markus Armbruster0c175422010-02-19 19:12:18 +010086static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010087{
Paul Brookaae94602009-05-14 22:35:06 +010088 DeviceState *dev;
Anthony Liguoria5296ca2011-12-12 14:29:27 -060089 Property *prop;
Paul Brookaae94602009-05-14 22:35:06 +010090
Markus Armbruster0c175422010-02-19 19:12:18 +010091 assert(bus->info == info->bus_info);
Anthony Liguori7267c092011-08-20 22:09:37 -050092 dev = g_malloc0(info->size);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020093 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010094 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020095 qdev_prop_set_defaults(dev, dev->info->props);
96 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +010097 qdev_prop_set_globals(dev);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +020098 QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020099 if (qdev_hotplug) {
100 assert(bus->allow_hotplug);
101 dev->hotplugged = 1;
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700102 qdev_hot_added = true;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200103 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200104 dev->instance_id_alias = -1;
Anthony Liguori44677de2011-12-12 14:29:26 -0600105 QTAILQ_INIT(&dev->properties);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200106 dev->state = DEV_STATE_CREATED;
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600107
108 for (prop = dev->info->props; prop && prop->name; prop++) {
109 qdev_property_add_legacy(dev, prop, NULL);
Paolo Bonzinica2cc782011-12-18 17:05:11 +0100110 qdev_property_add_static(dev, prop, NULL);
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600111 }
112
113 for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
114 qdev_property_add_legacy(dev, prop, NULL);
Paolo Bonzinica2cc782011-12-18 17:05:11 +0100115 qdev_property_add_static(dev, prop, NULL);
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600116 }
117
Anthony Liguoricd34d662011-12-12 14:29:43 -0600118 qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
119
Paul Brookaae94602009-05-14 22:35:06 +0100120 return dev;
121}
122
Markus Armbruster0c175422010-02-19 19:12:18 +0100123/* Create a new device. This only initializes the device state structure
124 and allows properties to be set. qdev_init should be called to
125 initialize the actual device emulation. */
126DeviceState *qdev_create(BusState *bus, const char *name)
127{
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000128 DeviceState *dev;
129
130 dev = qdev_try_create(bus, name);
131 if (!dev) {
Peter Maydelle92714c2011-08-03 23:49:04 +0100132 if (bus) {
133 hw_error("Unknown device '%s' for bus '%s'\n", name,
134 bus->info->name);
135 } else {
136 hw_error("Unknown device '%s' for default sysbus\n", name);
137 }
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000138 }
139
140 return dev;
141}
142
143DeviceState *qdev_try_create(BusState *bus, const char *name)
144{
Markus Armbruster0c175422010-02-19 19:12:18 +0100145 DeviceInfo *info;
146
147 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100148 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100149 }
150
151 info = qdev_find_info(bus->info, name);
152 if (!info) {
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000153 return NULL;
Markus Armbruster0c175422010-02-19 19:12:18 +0100154 }
155
156 return qdev_create_from_info(bus, info);
157}
158
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100159static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200160{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100161 error_printf("name \"%s\", bus %s",
162 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200163 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100164 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200165 }
166 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100167 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200168 }
169 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100170 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200171 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100172 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200173}
174
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200175static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200176{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200177 DeviceState *dev = opaque;
178
179 if (strcmp(name, "driver") == 0)
180 return 0;
181 if (strcmp(name, "bus") == 0)
182 return 0;
183
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100184 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200185 return -1;
186 }
187 return 0;
188}
189
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100190int qdev_device_help(QemuOpts *opts)
191{
192 const char *driver;
193 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100194 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100195
196 driver = qemu_opt_get(opts, "driver");
197 if (driver && !strcmp(driver, "?")) {
198 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100199 if (info->no_user) {
200 continue; /* not available, don't show */
201 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100202 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100203 }
204 return 1;
205 }
206
Markus Armbruster542379f2011-11-08 11:00:38 +0100207 if (!driver || !qemu_opt_get(opts, "?")) {
Markus Armbruster08350cf2010-01-29 19:49:00 +0100208 return 0;
209 }
210
211 info = qdev_find_info(NULL, driver);
212 if (!info) {
213 return 0;
214 }
215
216 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100217 /*
218 * TODO Properties without a parser are just for dirty hacks.
219 * qdev_prop_ptr is the only such PropertyInfo. It's marked
220 * for removal. This conditional should be removed along with
221 * it.
222 */
223 if (!prop->info->parse) {
224 continue; /* no way to set it, don't show */
225 }
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +0100226 error_printf("%s.%s=%s\n", info->name, prop->name,
227 prop->info->legacy_name ?: prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100228 }
Gerd Hoffmanna8467c72011-09-16 11:25:05 +0200229 for (prop = info->bus_info->props; prop && prop->name; prop++) {
230 if (!prop->info->parse) {
231 continue; /* no way to set it, don't show */
232 }
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +0100233 error_printf("%s.%s=%s\n", info->name, prop->name,
234 prop->info->legacy_name ?: prop->info->name);
Gerd Hoffmanna8467c72011-09-16 11:25:05 +0200235 }
Markus Armbruster08350cf2010-01-29 19:49:00 +0100236 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100237}
238
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600239static DeviceState *qdev_get_peripheral(void)
240{
241 static DeviceState *dev;
242
243 if (dev == NULL) {
244 dev = qdev_create(NULL, "container");
245 qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
246 qdev_init_nofail(dev);
247 }
248
249 return dev;
250}
251
Anthony Liguori8eb02832011-12-12 14:29:37 -0600252static DeviceState *qdev_get_peripheral_anon(void)
253{
254 static DeviceState *dev;
255
256 if (dev == NULL) {
257 dev = qdev_create(NULL, "container");
258 qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
259 qdev_init_nofail(dev);
260 }
261
262 return dev;
263}
264
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200265DeviceState *qdev_device_add(QemuOpts *opts)
266{
267 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200268 DeviceInfo *info;
269 DeviceState *qdev;
270 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200271
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200272 driver = qemu_opt_get(opts, "driver");
273 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100274 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200275 return NULL;
276 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200277
278 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200279 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100280 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100281 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100282 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200283 return NULL;
284 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200285
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200286 /* find bus */
287 path = qemu_opt_get(opts, "bus");
288 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200289 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100290 if (!bus) {
291 return NULL;
292 }
293 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100294 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
295 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100296 return NULL;
297 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200298 } else {
299 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100300 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100301 qerror_report(QERR_NO_BUS_FOR_DEVICE,
302 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100303 return NULL;
304 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200305 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200306 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100307 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200308 return NULL;
309 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200310
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200311 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100312 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200313 id = qemu_opts_id(opts);
314 if (id) {
315 qdev->id = id;
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600316 qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
Anthony Liguori8eb02832011-12-12 14:29:37 -0600317 } else {
318 static int anon_count;
319 gchar *name = g_strdup_printf("device[%d]", anon_count++);
320 qdev_property_add_child(qdev_get_peripheral_anon(), name,
321 qdev, NULL);
322 g_free(name);
323 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200324 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
325 qdev_free(qdev);
326 return NULL;
327 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200328 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100329 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200330 return NULL;
331 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200332 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200333 return qdev;
334}
335
Paul Brookaae94602009-05-14 22:35:06 +0100336/* Initialize a device. Device properties should be set before calling
337 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200338 calling this function.
339 On failure, destroy the device and return negative value.
340 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200341int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100342{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200343 int rc;
344
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200345 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200346 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200347 if (rc < 0) {
348 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200349 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200350 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200351 if (dev->info->vmsd) {
Alex Williamson0be71e32010-06-25 11:09:07 -0600352 vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200353 dev->instance_id_alias,
354 dev->alias_required_for_version);
355 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200356 dev->state = DEV_STATE_INITIALIZED;
Jan Kiszka5ab28c82011-07-24 19:38:36 +0200357 if (dev->hotplugged && dev->info->reset) {
358 dev->info->reset(dev);
359 }
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200360 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100361}
362
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200363void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
364 int required_for_version)
365{
366 assert(dev->state == DEV_STATE_CREATED);
367 dev->instance_id_alias = alias_id;
368 dev->alias_required_for_version = required_for_version;
369}
370
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200371int qdev_unplug(DeviceState *dev)
372{
373 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100374 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200375 return -1;
376 }
Amit Shah593831d2009-11-02 14:56:41 +0530377 assert(dev->info->unplug != NULL);
378
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700379 qdev_hot_removed = true;
380
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200381 return dev->info->unplug(dev);
382}
383
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900384static int qdev_reset_one(DeviceState *dev, void *opaque)
385{
386 if (dev->info->reset) {
387 dev->info->reset(dev);
388 }
389
390 return 0;
391}
392
393BusState *sysbus_get_default(void)
394{
Stefan Weil68694892010-12-16 19:33:22 +0100395 if (!main_system_bus) {
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900396 main_system_bus_create();
Stefan Weil68694892010-12-16 19:33:22 +0100397 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900398 return main_system_bus;
399}
400
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900401static int qbus_reset_one(BusState *bus, void *opaque)
402{
403 if (bus->info->reset) {
404 return bus->info->reset(bus);
405 }
406 return 0;
407}
408
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900409void qdev_reset_all(DeviceState *dev)
410{
411 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
412}
413
Isaku Yamahata80376c32010-12-20 14:33:35 +0900414void qbus_reset_all_fn(void *opaque)
415{
416 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200417 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900418}
419
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200420/* can be used as ->unplug() callback for the simple cases */
421int qdev_simple_unplug_cb(DeviceState *dev)
422{
423 /* just zap it */
424 qdev_free(dev);
425 return 0;
426}
427
Michael Tokarev3b29a102011-04-06 17:51:59 +0400428
429/* Like qdev_init(), but terminate program via error_report() instead of
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200430 returning an error value. This is okay during machine creation.
431 Don't use for hotplug, because there callers need to recover from
432 failure. Exception: if you know the device's init() callback can't
433 fail, then qdev_init_nofail() can't fail either, and is therefore
434 usable even then. But relying on the device implementation that
435 way is somewhat unclean, and best avoided. */
436void qdev_init_nofail(DeviceState *dev)
437{
438 DeviceInfo *info = dev->info;
439
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200440 if (qdev_init(dev) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +0200441 error_report("Initialization of device %s failed", info->name);
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200442 exit(1);
443 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200444}
445
Anthony Liguori44677de2011-12-12 14:29:26 -0600446static void qdev_property_del_all(DeviceState *dev)
447{
448 while (!QTAILQ_EMPTY(&dev->properties)) {
449 DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
450
451 QTAILQ_REMOVE(&dev->properties, prop, node);
452
453 if (prop->release) {
454 prop->release(dev, prop->name, prop->opaque);
455 }
456
457 g_free(prop->name);
458 g_free(prop->type);
459 g_free(prop);
460 }
461}
462
Anthony Liguori024a6fb2012-01-13 07:45:55 -0600463static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp)
464{
465 DeviceProperty *prop;
466
467 QTAILQ_FOREACH(prop, &dev->properties, node) {
468 if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
469 break;
470 }
471 }
472
473 g_assert(prop != NULL);
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
Paul Brook02e2da42009-05-23 00:05:19 +0100486/* Unlink device from bus and free the structure. */
487void qdev_free(DeviceState *dev)
488{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200489 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200490 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200491
Anthony Liguori44677de2011-12-12 14:29:26 -0600492 qdev_property_del_all(dev);
493
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200494 if (dev->state == DEV_STATE_INITIALIZED) {
495 while (dev->num_child_bus) {
496 bus = QLIST_FIRST(&dev->child_bus);
497 qbus_free(bus);
498 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200499 if (dev->info->vmsd)
Alex Williamson0be71e32010-06-25 11:09:07 -0600500 vmstate_unregister(dev, dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200501 if (dev->info->exit)
502 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200503 if (dev->opts)
504 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200505 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200506 QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200507 for (prop = dev->info->props; prop && prop->name; prop++) {
508 if (prop->info->free) {
509 prop->info->free(dev, prop);
510 }
511 }
Anthony Liguori024a6fb2012-01-13 07:45:55 -0600512 if (dev->parent) {
513 qdev_property_del_child(dev->parent, dev, NULL);
514 }
515 if (dev->ref != 0) {
516 qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
517 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500518 g_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100519}
520
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200521void qdev_machine_creation_done(void)
522{
523 /*
524 * ok, initial machine setup is done, starting from now we can
525 * only create hotpluggable devices
526 */
527 qdev_hotplug = 1;
528}
529
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700530bool qdev_machine_modified(void)
531{
532 return qdev_hot_added || qdev_hot_removed;
533}
534
Paul Brookaae94602009-05-14 22:35:06 +0100535/* Get a character (serial) device interface. */
536CharDriverState *qdev_init_chardev(DeviceState *dev)
537{
538 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530539
540 /* FIXME: This function needs to go away: use chardev properties! */
541 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100542}
543
Paul Brook02e2da42009-05-23 00:05:19 +0100544BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100545{
Paul Brook02e2da42009-05-23 00:05:19 +0100546 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100547}
548
Paul Brookaae94602009-05-14 22:35:06 +0100549void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
550{
551 assert(dev->num_gpio_in == 0);
552 dev->num_gpio_in = n;
553 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
554}
555
556void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
557{
558 assert(dev->num_gpio_out == 0);
559 dev->num_gpio_out = n;
560 dev->gpio_out = pins;
561}
562
563qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
564{
565 assert(n >= 0 && n < dev->num_gpio_in);
566 return dev->gpio_in[n];
567}
568
569void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
570{
571 assert(n >= 0 && n < dev->num_gpio_out);
572 dev->gpio_out[n] = pin;
573}
574
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200575void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
576{
Jan Kiszka6eed1852011-07-20 12:20:22 +0200577 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200578 if (nd->vlan)
579 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
580 if (nd->netdev)
581 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530582 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200583 qdev_prop_exists(dev, "vectors")) {
584 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
585 }
Peter Maydell48e2faf2011-05-20 16:50:01 +0100586 nd->instantiated = 1;
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200587}
588
Paul Brook02e2da42009-05-23 00:05:19 +0100589BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100590{
Paul Brook02e2da42009-05-23 00:05:19 +0100591 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100592
Blue Swirl72cf2d42009-09-12 07:36:22 +0000593 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100594 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100595 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100596 }
597 }
598 return NULL;
599}
600
Anthony Liguori81699d82010-11-19 18:55:58 +0900601int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
602 qbus_walkerfn *busfn, void *opaque)
603{
604 DeviceState *dev;
605 int err;
606
607 if (busfn) {
608 err = busfn(bus, opaque);
609 if (err) {
610 return err;
611 }
612 }
613
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200614 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori81699d82010-11-19 18:55:58 +0900615 err = qdev_walk_children(dev, devfn, busfn, opaque);
616 if (err < 0) {
617 return err;
618 }
619 }
620
621 return 0;
622}
623
624int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
625 qbus_walkerfn *busfn, void *opaque)
626{
627 BusState *bus;
628 int err;
629
630 if (devfn) {
631 err = devfn(dev, opaque);
632 if (err) {
633 return err;
634 }
635 }
636
637 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
638 err = qbus_walk_children(bus, devfn, busfn, opaque);
639 if (err < 0) {
640 return err;
641 }
642 }
643
644 return 0;
645}
646
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200647static BusState *qbus_find_recursive(BusState *bus, const char *name,
648 const BusInfo *info)
649{
650 DeviceState *dev;
651 BusState *child, *ret;
652 int match = 1;
653
654 if (name && (strcmp(bus->name, name) != 0)) {
655 match = 0;
656 }
657 if (info && (bus->info != info)) {
658 match = 0;
659 }
660 if (match) {
661 return bus;
662 }
663
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200664 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000665 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200666 ret = qbus_find_recursive(child, name, info);
667 if (ret) {
668 return ret;
669 }
670 }
671 }
672 return NULL;
673}
674
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900675DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200676{
677 DeviceState *dev, *ret;
678 BusState *child;
679
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200680 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200681 if (dev->id && strcmp(dev->id, id) == 0)
682 return dev;
683 QLIST_FOREACH(child, &dev->child_bus, sibling) {
684 ret = qdev_find_recursive(child, id);
685 if (ret) {
686 return ret;
687 }
688 }
689 }
690 return NULL;
691}
692
Markus Armbruster53db16b2010-02-18 18:55:59 +0100693static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200694{
695 BusState *child;
696 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200697
Markus Armbruster53db16b2010-02-18 18:55:59 +0100698 error_printf("child busses at \"%s\":",
699 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000700 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100701 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200702 sep = ", ";
703 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100704 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200705}
706
Markus Armbruster53db16b2010-02-18 18:55:59 +0100707static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200708{
709 DeviceState *dev;
710 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200711
Markus Armbruster53db16b2010-02-18 18:55:59 +0100712 error_printf("devices at \"%s\":", bus->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200713 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100714 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200715 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100716 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200717 sep = ", ";
718 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100719 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200720}
721
722static BusState *qbus_find_bus(DeviceState *dev, char *elem)
723{
724 BusState *child;
725
Blue Swirl72cf2d42009-09-12 07:36:22 +0000726 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200727 if (strcmp(child->name, elem) == 0) {
728 return child;
729 }
730 }
731 return NULL;
732}
733
734static DeviceState *qbus_find_dev(BusState *bus, char *elem)
735{
736 DeviceState *dev;
737
738 /*
739 * try to match in order:
740 * (1) instance id, if present
741 * (2) driver name
742 * (3) driver alias, if present
743 */
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200744 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200745 if (dev->id && strcmp(dev->id, elem) == 0) {
746 return dev;
747 }
748 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200749 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200750 if (strcmp(dev->info->name, elem) == 0) {
751 return dev;
752 }
753 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200754 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200755 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
756 return dev;
757 }
758 }
759 return NULL;
760}
761
762static BusState *qbus_find(const char *path)
763{
764 DeviceState *dev;
765 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100766 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200767 int pos, len;
768
769 /* find start element */
770 if (path[0] == '/') {
771 bus = main_system_bus;
772 pos = 0;
773 } else {
774 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100775 assert(!path[0]);
776 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200777 }
778 bus = qbus_find_recursive(main_system_bus, elem, NULL);
779 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100780 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200781 return NULL;
782 }
783 pos = len;
784 }
785
786 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100787 assert(path[pos] == '/' || !path[pos]);
788 while (path[pos] == '/') {
789 pos++;
790 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200791 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200792 return bus;
793 }
794
795 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100796 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
797 assert(0);
798 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200799 }
800 pos += len;
801 dev = qbus_find_dev(bus, elem);
802 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100803 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100804 if (!monitor_cur_is_qmp()) {
805 qbus_list_dev(bus);
806 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200807 return NULL;
808 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100809
810 assert(path[pos] == '/' || !path[pos]);
811 while (path[pos] == '/') {
812 pos++;
813 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200814 if (path[pos] == '\0') {
815 /* last specified element is a device. If it has exactly
816 * one child bus accept it nevertheless */
817 switch (dev->num_child_bus) {
818 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100819 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200820 return NULL;
821 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000822 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200823 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100824 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100825 if (!monitor_cur_is_qmp()) {
826 qbus_list_bus(dev);
827 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200828 return NULL;
829 }
830 }
831
832 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100833 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
834 assert(0);
835 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200836 }
837 pos += len;
838 bus = qbus_find_bus(dev, elem);
839 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100840 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100841 if (!monitor_cur_is_qmp()) {
842 qbus_list_bus(dev);
843 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200844 return NULL;
845 }
846 }
847}
848
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200849void qbus_create_inplace(BusState *bus, BusInfo *info,
850 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100851{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200852 char *buf;
853 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100854
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200855 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100856 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200857
858 if (name) {
859 /* use supplied name */
Anthony Liguori7267c092011-08-20 22:09:37 -0500860 bus->name = g_strdup(name);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200861 } else if (parent && parent->id) {
862 /* parent device has id -> use it for bus name */
863 len = strlen(parent->id) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500864 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200865 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
866 bus->name = buf;
867 } else {
868 /* no id -> use lowercase bus type for bus name */
869 len = strlen(info->name) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500870 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200871 len = snprintf(buf, len, "%s.%d", info->name,
872 parent ? parent->num_child_bus : 0);
873 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200874 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200875 bus->name = buf;
876 }
877
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200878 QTAILQ_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100879 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000880 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200881 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900882 } else if (bus != main_system_bus) {
883 /* TODO: once all bus devices are qdevified,
884 only reset handler for main_system_bus should be registered here. */
885 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100886 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200887}
888
889BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
890{
891 BusState *bus;
892
Anthony Liguori7267c092011-08-20 22:09:37 -0500893 bus = g_malloc0(info->size);
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200894 bus->qdev_allocated = 1;
895 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100896 return bus;
897}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100898
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900899static void main_system_bus_create(void)
900{
901 /* assign main_system_bus before qbus_create_inplace()
902 * in order to make "if (bus != main_system_bus)" work */
Anthony Liguori7267c092011-08-20 22:09:37 -0500903 main_system_bus = g_malloc0(system_bus_info.size);
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900904 main_system_bus->qdev_allocated = 1;
905 qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
906 "main-system-bus");
907}
908
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200909void qbus_free(BusState *bus)
910{
911 DeviceState *dev;
912
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200913 while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200914 qdev_free(dev);
915 }
916 if (bus->parent) {
917 QLIST_REMOVE(bus, sibling);
918 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900919 } else {
920 assert(bus != main_system_bus); /* main_system_bus is never freed */
921 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200922 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500923 g_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200924 if (bus->qdev_allocated) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500925 g_free(bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200926 }
927}
928
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100929#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
930static void qbus_print(Monitor *mon, BusState *bus, int indent);
931
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200932static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
933 const char *prefix, int indent)
934{
935 char buf[64];
936
937 if (!props)
938 return;
939 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100940 /*
941 * TODO Properties without a print method are just for dirty
942 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
943 * marked for removal. The test props->info->print should be
944 * removed along with it.
945 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200946 if (props->info->print) {
947 props->info->print(dev, props, buf, sizeof(buf));
948 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
949 }
950 props++;
951 }
952}
953
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100954static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
955{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100956 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200957 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
958 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100959 indent += 2;
960 if (dev->num_gpio_in) {
961 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
962 }
963 if (dev->num_gpio_out) {
964 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
965 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200966 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
967 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200968 if (dev->parent_bus->info->print_dev)
969 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000970 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100971 qbus_print(mon, child, indent);
972 }
973}
974
975static void qbus_print(Monitor *mon, BusState *bus, int indent)
976{
977 struct DeviceState *dev;
978
979 qdev_printf("bus: %s\n", bus->name);
980 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200981 qdev_printf("type %s\n", bus->info->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200982 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100983 qdev_print(mon, dev, indent);
984 }
985}
986#undef qdev_printf
987
988void do_info_qtree(Monitor *mon)
989{
990 if (main_system_bus)
991 qbus_print(mon, main_system_bus, 0);
992}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200993
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200994void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200995{
996 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200997
998 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100999 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001000 }
1001}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001002
Markus Armbruster8bc27242010-02-10 20:52:01 +01001003int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001004{
1005 QemuOpts *opts;
1006
Gerd Hoffmann3329f072010-08-20 13:52:01 +02001007 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +01001008 if (!opts) {
1009 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +01001010 }
Markus Armbruster8bc27242010-02-10 20:52:01 +01001011 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
1012 qemu_opts_del(opts);
1013 return 0;
1014 }
1015 if (!qdev_device_add(opts)) {
1016 qemu_opts_del(opts);
1017 return -1;
1018 }
1019 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001020}
1021
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001022int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001023{
1024 const char *id = qdict_get_str(qdict, "id");
1025 DeviceState *dev;
1026
1027 dev = qdev_find_recursive(main_system_bus, id);
1028 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001029 qerror_report(QERR_DEVICE_NOT_FOUND, id);
1030 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001031 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001032 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001033}
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001034
1035static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
1036{
1037 int l = 0;
1038
1039 if (dev && dev->parent_bus) {
1040 char *d;
1041 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
1042 if (dev->parent_bus->info->get_fw_dev_path) {
1043 d = dev->parent_bus->info->get_fw_dev_path(dev);
1044 l += snprintf(p + l, size - l, "%s", d);
Anthony Liguori7267c092011-08-20 22:09:37 -05001045 g_free(d);
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001046 } else {
1047 l += snprintf(p + l, size - l, "%s", dev->info->name);
1048 }
1049 }
1050 l += snprintf(p + l , size - l, "/");
1051
1052 return l;
1053}
1054
1055char* qdev_get_fw_dev_path(DeviceState *dev)
1056{
1057 char path[128];
1058 int l;
1059
1060 l = qdev_get_fw_dev_path_helper(dev, path, 128);
1061
1062 path[l-1] = '\0';
1063
1064 return strdup(path);
1065}
Anthony Liguori85ed3032011-12-12 14:29:25 -06001066
Anthony Liguoricd34d662011-12-12 14:29:43 -06001067char *qdev_get_type(DeviceState *dev, Error **errp)
1068{
1069 return g_strdup(dev->info->name);
1070}
1071
Anthony Liguori85ed3032011-12-12 14:29:25 -06001072void qdev_ref(DeviceState *dev)
1073{
1074 dev->ref++;
1075}
1076
1077void qdev_unref(DeviceState *dev)
1078{
1079 g_assert(dev->ref > 0);
1080 dev->ref--;
1081}
Anthony Liguori44677de2011-12-12 14:29:26 -06001082
1083void qdev_property_add(DeviceState *dev, const char *name, const char *type,
1084 DevicePropertyAccessor *get, DevicePropertyAccessor *set,
1085 DevicePropertyRelease *release,
1086 void *opaque, Error **errp)
1087{
1088 DeviceProperty *prop = g_malloc0(sizeof(*prop));
1089
1090 prop->name = g_strdup(name);
1091 prop->type = g_strdup(type);
1092
1093 prop->get = get;
1094 prop->set = set;
1095 prop->release = release;
1096 prop->opaque = opaque;
1097
1098 QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
1099}
1100
1101static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
1102{
1103 DeviceProperty *prop;
1104
1105 QTAILQ_FOREACH(prop, &dev->properties, node) {
1106 if (strcmp(prop->name, name) == 0) {
1107 return prop;
1108 }
1109 }
1110
1111 return NULL;
1112}
1113
1114void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
1115 Error **errp)
1116{
1117 DeviceProperty *prop = qdev_property_find(dev, name);
1118
1119 if (prop == NULL) {
1120 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1121 return;
1122 }
1123
1124 if (!prop->get) {
1125 error_set(errp, QERR_PERMISSION_DENIED);
1126 } else {
1127 prop->get(dev, v, prop->opaque, name, errp);
1128 }
1129}
1130
1131void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
1132 Error **errp)
1133{
1134 DeviceProperty *prop = qdev_property_find(dev, name);
1135
1136 if (prop == NULL) {
1137 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1138 return;
1139 }
1140
1141 if (!prop->set) {
1142 error_set(errp, QERR_PERMISSION_DENIED);
1143 } else {
Paolo Bonzini0d41d9a2011-12-18 17:05:05 +01001144 prop->set(dev, v, prop->opaque, name, errp);
Anthony Liguori44677de2011-12-12 14:29:26 -06001145 }
1146}
1147
1148const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
1149{
1150 DeviceProperty *prop = qdev_property_find(dev, name);
1151
1152 if (prop == NULL) {
1153 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1154 return NULL;
1155 }
1156
1157 return prop->type;
1158}
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001159
1160/**
1161 * Legacy property handling
1162 */
1163
1164static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1165 const char *name, Error **errp)
1166{
1167 Property *prop = opaque;
1168
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001169 char buffer[1024];
1170 char *ptr = buffer;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001171
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001172 prop->info->print(dev, prop, buffer, sizeof(buffer));
1173 visit_type_str(v, &ptr, name, errp);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001174}
1175
1176static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1177 const char *name, Error **errp)
1178{
1179 Property *prop = opaque;
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001180 Error *local_err = NULL;
1181 char *ptr = NULL;
1182 int ret;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001183
1184 if (dev->state != DEV_STATE_CREATED) {
1185 error_set(errp, QERR_PERMISSION_DENIED);
1186 return;
1187 }
1188
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001189 visit_type_str(v, &ptr, name, &local_err);
1190 if (local_err) {
1191 error_propagate(errp, local_err);
1192 return;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001193 }
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001194
1195 ret = prop->info->parse(dev, prop, ptr);
Paolo Bonzini7db4c4e2011-12-18 17:05:07 +01001196 error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001197 g_free(ptr);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001198}
1199
1200/**
1201 * @qdev_add_legacy_property - adds a legacy property
1202 *
1203 * Do not use this is new code! Properties added through this interface will
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001204 * be given names and types in the "legacy" namespace.
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001205 *
1206 * Legacy properties are always processed as strings. The format of the string
1207 * depends on the property type.
1208 */
1209void qdev_property_add_legacy(DeviceState *dev, Property *prop,
1210 Error **errp)
1211{
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001212 gchar *name, *type;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001213
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001214 name = g_strdup_printf("legacy-%s", prop->name);
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +01001215 type = g_strdup_printf("legacy<%s>",
1216 prop->info->legacy_name ?: prop->info->name);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001217
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001218 qdev_property_add(dev, name, type,
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001219 prop->info->print ? qdev_get_legacy_property : NULL,
1220 prop->info->parse ? qdev_set_legacy_property : NULL,
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001221 NULL,
1222 prop, errp);
1223
1224 g_free(type);
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001225 g_free(name);
1226}
1227
1228/**
1229 * @qdev_property_add_static - add a @Property to a device.
1230 *
1231 * Static properties access data in a struct. The actual type of the
1232 * property and the field depends on the property type.
1233 */
1234void qdev_property_add_static(DeviceState *dev, Property *prop,
1235 Error **errp)
1236{
1237 qdev_property_add(dev, prop->name, prop->info->name,
1238 prop->info->get, prop->info->set,
1239 NULL,
1240 prop, errp);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001241}
Anthony Liguoria10f07a2011-12-12 14:29:28 -06001242
1243DeviceState *qdev_get_root(void)
1244{
1245 static DeviceState *qdev_root;
1246
1247 if (!qdev_root) {
1248 qdev_root = qdev_create(NULL, "container");
1249 qdev_init_nofail(qdev_root);
1250 }
1251
1252 return qdev_root;
1253}
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001254
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001255static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
1256 const char *name, Error **errp)
1257{
1258 DeviceState *child = opaque;
1259 gchar *path;
1260
1261 path = qdev_get_canonical_path(child);
1262 visit_type_str(v, &path, name, errp);
1263 g_free(path);
1264}
1265
Anthony Liguori024a6fb2012-01-13 07:45:55 -06001266static void qdev_release_child_property(DeviceState *dev, const char *name,
1267 void *opaque)
1268{
1269 DeviceState *child = opaque;
1270
1271 qdev_unref(child);
1272}
1273
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001274void qdev_property_add_child(DeviceState *dev, const char *name,
1275 DeviceState *child, Error **errp)
1276{
1277 gchar *type;
1278
1279 type = g_strdup_printf("child<%s>", child->info->name);
1280
1281 qdev_property_add(dev, name, type, qdev_get_child_property,
Anthony Liguori024a6fb2012-01-13 07:45:55 -06001282 NULL, qdev_release_child_property,
1283 child, errp);
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001284
1285 qdev_ref(child);
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001286 g_assert(child->parent == NULL);
1287 child->parent = dev;
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001288
1289 g_free(type);
1290}
1291
Anthony Liguori83e94fb2011-12-12 14:29:32 -06001292static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
1293 const char *name, Error **errp)
1294{
1295 DeviceState **child = opaque;
1296 gchar *path;
1297
1298 if (*child) {
1299 path = qdev_get_canonical_path(*child);
1300 visit_type_str(v, &path, name, errp);
1301 g_free(path);
1302 } else {
1303 path = (gchar *)"";
1304 visit_type_str(v, &path, name, errp);
1305 }
1306}
1307
1308static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
1309 const char *name, Error **errp)
1310{
1311 DeviceState **child = opaque;
1312 bool ambiguous = false;
1313 const char *type;
1314 char *path;
1315
1316 type = qdev_property_get_type(dev, name, NULL);
1317
1318 visit_type_str(v, &path, name, errp);
1319
1320 if (*child) {
1321 qdev_unref(*child);
1322 }
1323
1324 if (strcmp(path, "") != 0) {
1325 DeviceState *target;
1326
1327 target = qdev_resolve_path(path, &ambiguous);
1328 if (target) {
1329 gchar *target_type;
1330
1331 target_type = g_strdup_printf("link<%s>", target->info->name);
1332 if (strcmp(target_type, type) == 0) {
1333 *child = target;
1334 qdev_ref(target);
1335 } else {
1336 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
1337 }
1338
1339 g_free(target_type);
1340 } else {
1341 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
1342 }
1343 } else {
1344 *child = NULL;
1345 }
1346
1347 g_free(path);
1348}
1349
1350void qdev_property_add_link(DeviceState *dev, const char *name,
1351 const char *type, DeviceState **child,
1352 Error **errp)
1353{
1354 gchar *full_type;
1355
1356 full_type = g_strdup_printf("link<%s>", type);
1357
1358 qdev_property_add(dev, name, full_type,
1359 qdev_get_link_property,
1360 qdev_set_link_property,
1361 NULL, child, errp);
1362
1363 g_free(full_type);
1364}
1365
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001366gchar *qdev_get_canonical_path(DeviceState *dev)
1367{
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001368 DeviceState *root = qdev_get_root();
1369 char *newpath = NULL, *path = NULL;
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001370
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001371 while (dev != root) {
1372 DeviceProperty *prop = NULL;
1373
1374 g_assert(dev->parent != NULL);
1375
1376 QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
1377 if (!strstart(prop->type, "child<", NULL)) {
1378 continue;
1379 }
1380
1381 if (prop->opaque == dev) {
1382 if (path) {
1383 newpath = g_strdup_printf("%s/%s", prop->name, path);
1384 g_free(path);
1385 path = newpath;
1386 } else {
1387 path = g_strdup(prop->name);
1388 }
1389 break;
1390 }
1391 }
1392
1393 g_assert(prop != NULL);
1394
1395 dev = dev->parent;
1396 }
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001397
1398 newpath = g_strdup_printf("/%s", path);
1399 g_free(path);
1400
1401 return newpath;
1402}
Anthony Liguoridc45c212011-12-12 14:29:30 -06001403
1404static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
1405 gchar **parts,
1406 int index)
1407{
1408 DeviceProperty *prop;
1409 DeviceState *child;
1410
1411 if (parts[index] == NULL) {
1412 return parent;
1413 }
1414
1415 if (strcmp(parts[index], "") == 0) {
1416 return qdev_resolve_abs_path(parent, parts, index + 1);
1417 }
1418
1419 prop = qdev_property_find(parent, parts[index]);
1420 if (prop == NULL) {
1421 return NULL;
1422 }
1423
1424 child = NULL;
1425 if (strstart(prop->type, "link<", NULL)) {
1426 DeviceState **pchild = prop->opaque;
1427 if (*pchild) {
1428 child = *pchild;
1429 }
1430 } else if (strstart(prop->type, "child<", NULL)) {
1431 child = prop->opaque;
1432 }
1433
1434 if (!child) {
1435 return NULL;
1436 }
1437
1438 return qdev_resolve_abs_path(child, parts, index + 1);
1439}
1440
1441static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
1442 gchar **parts,
1443 bool *ambiguous)
1444{
1445 DeviceState *dev;
1446 DeviceProperty *prop;
1447
1448 dev = qdev_resolve_abs_path(parent, parts, 0);
1449
1450 QTAILQ_FOREACH(prop, &parent->properties, node) {
1451 DeviceState *found;
1452
1453 if (!strstart(prop->type, "child<", NULL)) {
1454 continue;
1455 }
1456
1457 found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
1458 if (found) {
1459 if (dev) {
1460 if (ambiguous) {
1461 *ambiguous = true;
1462 }
1463 return NULL;
1464 }
1465 dev = found;
1466 }
1467
1468 if (ambiguous && *ambiguous) {
1469 return NULL;
1470 }
1471 }
1472
1473 return dev;
1474}
1475
1476DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
1477{
1478 bool partial_path = true;
1479 DeviceState *dev;
1480 gchar **parts;
1481
1482 parts = g_strsplit(path, "/", 0);
1483 if (parts == NULL || parts[0] == NULL) {
1484 g_strfreev(parts);
1485 return qdev_get_root();
1486 }
1487
1488 if (strcmp(parts[0], "") == 0) {
1489 partial_path = false;
1490 }
1491
1492 if (partial_path) {
1493 if (ambiguous) {
1494 *ambiguous = false;
1495 }
1496 dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
1497 } else {
1498 dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
1499 }
1500
1501 g_strfreev(parts);
1502
1503 return dev;
1504}
1505
Anthony Liguori6a146eb2011-12-12 14:29:42 -06001506typedef struct StringProperty
1507{
1508 char *(*get)(DeviceState *, Error **);
1509 void (*set)(DeviceState *, const char *, Error **);
1510} StringProperty;
1511
1512static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque,
1513 const char *name, Error **errp)
1514{
1515 StringProperty *prop = opaque;
1516 char *value;
1517
1518 value = prop->get(dev, errp);
1519 if (value) {
1520 visit_type_str(v, &value, name, errp);
1521 g_free(value);
1522 }
1523}
1524
1525static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque,
1526 const char *name, Error **errp)
1527{
1528 StringProperty *prop = opaque;
1529 char *value;
1530 Error *local_err = NULL;
1531
1532 visit_type_str(v, &value, name, &local_err);
1533 if (local_err) {
1534 error_propagate(errp, local_err);
1535 return;
1536 }
1537
1538 prop->set(dev, value, errp);
1539 g_free(value);
1540}
1541
1542static void qdev_property_release_str(DeviceState *dev, const char *name,
1543 void *opaque)
1544{
1545 StringProperty *prop = opaque;
1546 g_free(prop);
1547}
1548
1549void qdev_property_add_str(DeviceState *dev, const char *name,
1550 char *(*get)(DeviceState *, Error **),
1551 void (*set)(DeviceState *, const char *, Error **),
1552 Error **errp)
1553{
1554 StringProperty *prop = g_malloc0(sizeof(*prop));
1555
1556 prop->get = get;
1557 prop->set = set;
1558
1559 qdev_property_add(dev, name, "string",
1560 get ? qdev_property_get_str : NULL,
1561 set ? qdev_property_set_str : NULL,
1562 qdev_property_release_str,
1563 prop, errp);
1564}
Anthony Liguori1de81d22011-12-19 16:37:46 -06001565
1566void qdev_machine_init(void)
1567{
1568 qdev_get_peripheral_anon();
1569 qdev_get_peripheral();
1570}