blob: 81996bbc3662af80cda655cf8d48376423e3c3b2 [file] [log] [blame]
Paul Brookaae94602009-05-14 22:35:06 +01001/*
2 * Dynamic device configuration and creation.
3 *
4 * Copyright (c) 2009 CodeSourcery
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Paul Brookaae94602009-05-14 22:35:06 +010018 */
19
20/* The theory here is that it should be possible to create a machine without
21 knowledge of specific devices. Historically board init routines have
22 passed a bunch of arguments to each device, requiring the board know
23 exactly which device it is dealing with. This file provides an abstract
24 API for device configuration and initialization. Devices will generally
25 inherit from a particular bus (e.g. PCI or I2C) rather than
26 this API directly. */
27
Paul Brook9d07d752009-05-14 22:35:07 +010028#include "net.h"
Paul Brookaae94602009-05-14 22:35:06 +010029#include "qdev.h"
30#include "sysemu.h"
Gerd Hoffmanncae49562009-06-05 15:53:17 +010031#include "monitor.h"
Paul Brookaae94602009-05-14 22:35:06 +010032
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020033static int qdev_hotplug = 0;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070034static bool qdev_hot_added = false;
35static bool qdev_hot_removed = false;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020036
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020037/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000038static BusState *main_system_bus;
Isaku Yamahata2da8bb92011-08-02 10:59:13 +090039static void main_system_bus_create(void);
Paul Brook4d6ae672009-05-14 22:35:06 +010040
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010041DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010042
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020043static BusState *qbus_find_recursive(BusState *bus, const char *name,
44 const BusInfo *info);
45static BusState *qbus_find(const char *path);
46
Paul Brookaae94602009-05-14 22:35:06 +010047/* Register a new device type. */
Anthony Liguori30fbb9f2011-12-04 11:08:36 -060048static void qdev_subclass_init(ObjectClass *klass, void *data)
49{
50 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori94afdad2011-12-04 11:36:01 -060051
Anthony Liguori30fbb9f2011-12-04 11:08:36 -060052 dc->info = data;
Anthony Liguori94afdad2011-12-04 11:36:01 -060053 dc->reset = dc->info->reset;
54
55 /* Poison to try to detect future uses */
56 dc->info->reset = NULL;
Anthony Liguori3dde52d2011-12-04 14:37:06 -060057
58 if (dc->info->class_init) {
59 dc->info->class_init(klass, data);
60 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -060061}
62
63DeviceInfo *qdev_get_info(DeviceState *dev)
64{
65 return DEVICE_GET_CLASS(dev)->info;
66}
67
Anthony Liguori3cc90eb2011-12-15 14:40:29 -060068void qdev_register_subclass(DeviceInfo *info, const char *parent)
Paul Brookaae94602009-05-14 22:35:06 +010069{
Anthony Liguori32fea402011-12-16 14:34:46 -060070 TypeInfo type_info = {};
71
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020072 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020073 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010074
Anthony Liguori32fea402011-12-16 14:34:46 -060075 type_info.name = info->name;
Anthony Liguori3cc90eb2011-12-15 14:40:29 -060076 type_info.parent = parent;
Anthony Liguori32fea402011-12-16 14:34:46 -060077 type_info.instance_size = info->size;
Anthony Liguori30fbb9f2011-12-04 11:08:36 -060078 type_info.class_init = qdev_subclass_init;
79 type_info.class_data = info;
Anthony Liguori32fea402011-12-16 14:34:46 -060080
81 type_register_static(&type_info);
82
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020083 info->next = device_info_list;
84 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010085}
86
Anthony Liguori3cc90eb2011-12-15 14:40:29 -060087void qdev_register(DeviceInfo *info)
88{
89 qdev_register_subclass(info, TYPE_DEVICE);
90}
91
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020092static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
93{
94 DeviceInfo *info;
95
Gerd Hoffmann3320e562009-07-15 13:43:33 +020096 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020097 for (info = device_info_list; info != NULL; info = info->next) {
98 if (bus_info && info->bus_info != bus_info)
99 continue;
100 if (strcmp(info->name, name) != 0)
101 continue;
102 return info;
103 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +0200104
105 /* failing that check the aliases */
106 for (info = device_info_list; info != NULL; info = info->next) {
107 if (bus_info && info->bus_info != bus_info)
108 continue;
109 if (!info->alias)
110 continue;
111 if (strcmp(info->alias, name) != 0)
112 continue;
113 return info;
114 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +0200115 return NULL;
116}
117
Blue Swirla369da52011-09-27 19:15:42 +0000118bool qdev_exists(const char *name)
119{
120 return !!qdev_find_info(NULL, name);
121}
Paolo Bonzinica2cc782011-12-18 17:05:11 +0100122static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
123 Error **errp);
124
Markus Armbruster0c175422010-02-19 19:12:18 +0100125static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +0100126{
Paul Brookaae94602009-05-14 22:35:06 +0100127 DeviceState *dev;
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600128 Property *prop;
Paul Brookaae94602009-05-14 22:35:06 +0100129
Markus Armbruster0c175422010-02-19 19:12:18 +0100130 assert(bus->info == info->bus_info);
Anthony Liguori32fea402011-12-16 14:34:46 -0600131 dev = DEVICE(object_new(info->name));
Paul Brook02e2da42009-05-23 00:05:19 +0100132 dev->parent_bus = bus;
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600133 qdev_prop_set_defaults(dev, qdev_get_info(dev)->props);
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200134 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +0100135 qdev_prop_set_globals(dev);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200136 QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200137 if (qdev_hotplug) {
138 assert(bus->allow_hotplug);
139 dev->hotplugged = 1;
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700140 qdev_hot_added = true;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200141 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200142 dev->instance_id_alias = -1;
Anthony Liguori44677de2011-12-12 14:29:26 -0600143 QTAILQ_INIT(&dev->properties);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200144 dev->state = DEV_STATE_CREATED;
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600145
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600146 for (prop = qdev_get_info(dev)->props; prop && prop->name; prop++) {
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600147 qdev_property_add_legacy(dev, prop, NULL);
Paolo Bonzinica2cc782011-12-18 17:05:11 +0100148 qdev_property_add_static(dev, prop, NULL);
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600149 }
150
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600151 for (prop = qdev_get_info(dev)->bus_info->props; prop && prop->name; prop++) {
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600152 qdev_property_add_legacy(dev, prop, NULL);
Paolo Bonzinica2cc782011-12-18 17:05:11 +0100153 qdev_property_add_static(dev, prop, NULL);
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600154 }
155
Anthony Liguoricd34d662011-12-12 14:29:43 -0600156 qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
157
Paul Brookaae94602009-05-14 22:35:06 +0100158 return dev;
159}
160
Markus Armbruster0c175422010-02-19 19:12:18 +0100161/* Create a new device. This only initializes the device state structure
162 and allows properties to be set. qdev_init should be called to
163 initialize the actual device emulation. */
164DeviceState *qdev_create(BusState *bus, const char *name)
165{
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000166 DeviceState *dev;
167
168 dev = qdev_try_create(bus, name);
169 if (!dev) {
Peter Maydelle92714c2011-08-03 23:49:04 +0100170 if (bus) {
171 hw_error("Unknown device '%s' for bus '%s'\n", name,
172 bus->info->name);
173 } else {
174 hw_error("Unknown device '%s' for default sysbus\n", name);
175 }
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000176 }
177
178 return dev;
179}
180
181DeviceState *qdev_try_create(BusState *bus, const char *name)
182{
Markus Armbruster0c175422010-02-19 19:12:18 +0100183 DeviceInfo *info;
184
185 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100186 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100187 }
188
189 info = qdev_find_info(bus->info, name);
190 if (!info) {
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000191 return NULL;
Markus Armbruster0c175422010-02-19 19:12:18 +0100192 }
193
194 return qdev_create_from_info(bus, info);
195}
196
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100197static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200198{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100199 error_printf("name \"%s\", bus %s",
200 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200201 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100202 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200203 }
204 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100205 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200206 }
207 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100208 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200209 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100210 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200211}
212
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200213static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200214{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200215 DeviceState *dev = opaque;
216
217 if (strcmp(name, "driver") == 0)
218 return 0;
219 if (strcmp(name, "bus") == 0)
220 return 0;
221
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100222 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200223 return -1;
224 }
225 return 0;
226}
227
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100228int qdev_device_help(QemuOpts *opts)
229{
230 const char *driver;
231 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100232 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100233
234 driver = qemu_opt_get(opts, "driver");
235 if (driver && !strcmp(driver, "?")) {
236 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100237 if (info->no_user) {
238 continue; /* not available, don't show */
239 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100240 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100241 }
242 return 1;
243 }
244
Markus Armbruster542379f2011-11-08 11:00:38 +0100245 if (!driver || !qemu_opt_get(opts, "?")) {
Markus Armbruster08350cf2010-01-29 19:49:00 +0100246 return 0;
247 }
248
249 info = qdev_find_info(NULL, driver);
250 if (!info) {
251 return 0;
252 }
253
254 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100255 /*
256 * TODO Properties without a parser are just for dirty hacks.
257 * qdev_prop_ptr is the only such PropertyInfo. It's marked
258 * for removal. This conditional should be removed along with
259 * it.
260 */
261 if (!prop->info->parse) {
262 continue; /* no way to set it, don't show */
263 }
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +0100264 error_printf("%s.%s=%s\n", info->name, prop->name,
265 prop->info->legacy_name ?: prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100266 }
Gerd Hoffmanna8467c72011-09-16 11:25:05 +0200267 for (prop = info->bus_info->props; prop && prop->name; prop++) {
268 if (!prop->info->parse) {
269 continue; /* no way to set it, don't show */
270 }
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +0100271 error_printf("%s.%s=%s\n", info->name, prop->name,
272 prop->info->legacy_name ?: prop->info->name);
Gerd Hoffmanna8467c72011-09-16 11:25:05 +0200273 }
Markus Armbruster08350cf2010-01-29 19:49:00 +0100274 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100275}
276
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600277static DeviceState *qdev_get_peripheral(void)
278{
279 static DeviceState *dev;
280
281 if (dev == NULL) {
282 dev = qdev_create(NULL, "container");
283 qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
284 qdev_init_nofail(dev);
285 }
286
287 return dev;
288}
289
Anthony Liguori8eb02832011-12-12 14:29:37 -0600290static DeviceState *qdev_get_peripheral_anon(void)
291{
292 static DeviceState *dev;
293
294 if (dev == NULL) {
295 dev = qdev_create(NULL, "container");
296 qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
297 qdev_init_nofail(dev);
298 }
299
300 return dev;
301}
302
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200303DeviceState *qdev_device_add(QemuOpts *opts)
304{
305 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200306 DeviceInfo *info;
307 DeviceState *qdev;
308 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200309
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200310 driver = qemu_opt_get(opts, "driver");
311 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100312 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200313 return NULL;
314 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200315
316 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200317 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100318 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100319 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100320 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200321 return NULL;
322 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200323
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200324 /* find bus */
325 path = qemu_opt_get(opts, "bus");
326 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200327 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100328 if (!bus) {
329 return NULL;
330 }
331 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100332 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
333 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100334 return NULL;
335 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200336 } else {
337 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100338 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100339 qerror_report(QERR_NO_BUS_FOR_DEVICE,
340 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100341 return NULL;
342 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200343 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200344 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100345 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200346 return NULL;
347 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200348
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200349 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100350 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200351 id = qemu_opts_id(opts);
352 if (id) {
353 qdev->id = id;
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600354 qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
Anthony Liguori8eb02832011-12-12 14:29:37 -0600355 } else {
356 static int anon_count;
357 gchar *name = g_strdup_printf("device[%d]", anon_count++);
358 qdev_property_add_child(qdev_get_peripheral_anon(), name,
359 qdev, NULL);
360 g_free(name);
361 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200362 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
363 qdev_free(qdev);
364 return NULL;
365 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200366 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100367 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200368 return NULL;
369 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200370 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200371 return qdev;
372}
373
Paul Brookaae94602009-05-14 22:35:06 +0100374/* Initialize a device. Device properties should be set before calling
375 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200376 calling this function.
377 On failure, destroy the device and return negative value.
378 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200379int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100380{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200381 int rc;
382
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200383 assert(dev->state == DEV_STATE_CREATED);
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600384 rc = qdev_get_info(dev)->init(dev, qdev_get_info(dev));
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200385 if (rc < 0) {
386 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200387 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200388 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600389 if (qdev_get_info(dev)->vmsd) {
390 vmstate_register_with_alias_id(dev, -1, qdev_get_info(dev)->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200391 dev->instance_id_alias,
392 dev->alias_required_for_version);
393 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200394 dev->state = DEV_STATE_INITIALIZED;
Anthony Liguori94afdad2011-12-04 11:36:01 -0600395 if (dev->hotplugged) {
396 device_reset(dev);
Jan Kiszka5ab28c82011-07-24 19:38:36 +0200397 }
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200398 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100399}
400
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200401void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
402 int required_for_version)
403{
404 assert(dev->state == DEV_STATE_CREATED);
405 dev->instance_id_alias = alias_id;
406 dev->alias_required_for_version = required_for_version;
407}
408
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200409int qdev_unplug(DeviceState *dev)
410{
411 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100412 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200413 return -1;
414 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600415 assert(qdev_get_info(dev)->unplug != NULL);
Amit Shah593831d2009-11-02 14:56:41 +0530416
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700417 qdev_hot_removed = true;
418
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600419 return qdev_get_info(dev)->unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200420}
421
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900422static int qdev_reset_one(DeviceState *dev, void *opaque)
423{
Anthony Liguori94afdad2011-12-04 11:36:01 -0600424 device_reset(dev);
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900425
426 return 0;
427}
428
429BusState *sysbus_get_default(void)
430{
Stefan Weil68694892010-12-16 19:33:22 +0100431 if (!main_system_bus) {
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900432 main_system_bus_create();
Stefan Weil68694892010-12-16 19:33:22 +0100433 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900434 return main_system_bus;
435}
436
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900437static int qbus_reset_one(BusState *bus, void *opaque)
438{
439 if (bus->info->reset) {
440 return bus->info->reset(bus);
441 }
442 return 0;
443}
444
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900445void qdev_reset_all(DeviceState *dev)
446{
447 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
448}
449
Isaku Yamahata80376c32010-12-20 14:33:35 +0900450void qbus_reset_all_fn(void *opaque)
451{
452 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200453 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900454}
455
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200456/* can be used as ->unplug() callback for the simple cases */
457int qdev_simple_unplug_cb(DeviceState *dev)
458{
459 /* just zap it */
460 qdev_free(dev);
461 return 0;
462}
463
Michael Tokarev3b29a102011-04-06 17:51:59 +0400464
465/* Like qdev_init(), but terminate program via error_report() instead of
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200466 returning an error value. This is okay during machine creation.
467 Don't use for hotplug, because there callers need to recover from
468 failure. Exception: if you know the device's init() callback can't
469 fail, then qdev_init_nofail() can't fail either, and is therefore
470 usable even then. But relying on the device implementation that
471 way is somewhat unclean, and best avoided. */
472void qdev_init_nofail(DeviceState *dev)
473{
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600474 DeviceInfo *info = qdev_get_info(dev);
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200475
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200476 if (qdev_init(dev) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +0200477 error_report("Initialization of device %s failed", info->name);
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200478 exit(1);
479 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200480}
481
Anthony Liguori44677de2011-12-12 14:29:26 -0600482static void qdev_property_del_all(DeviceState *dev)
483{
484 while (!QTAILQ_EMPTY(&dev->properties)) {
485 DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
486
487 QTAILQ_REMOVE(&dev->properties, prop, node);
488
489 if (prop->release) {
490 prop->release(dev, prop->name, prop->opaque);
491 }
492
493 g_free(prop->name);
494 g_free(prop->type);
495 g_free(prop);
496 }
497}
498
Anthony Liguori024a6fb2012-01-13 07:45:55 -0600499static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp)
500{
501 DeviceProperty *prop;
502
503 QTAILQ_FOREACH(prop, &dev->properties, node) {
504 if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
505 break;
506 }
507 }
508
509 g_assert(prop != NULL);
510
511 QTAILQ_REMOVE(&dev->properties, prop, node);
512
513 if (prop->release) {
514 prop->release(dev, prop->name, prop->opaque);
515 }
516
517 g_free(prop->name);
518 g_free(prop->type);
519 g_free(prop);
520}
521
Paul Brook02e2da42009-05-23 00:05:19 +0100522/* Unlink device from bus and free the structure. */
523void qdev_free(DeviceState *dev)
524{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200525 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200526 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200527
Anthony Liguori44677de2011-12-12 14:29:26 -0600528 qdev_property_del_all(dev);
529
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200530 if (dev->state == DEV_STATE_INITIALIZED) {
531 while (dev->num_child_bus) {
532 bus = QLIST_FIRST(&dev->child_bus);
533 qbus_free(bus);
534 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600535 if (qdev_get_info(dev)->vmsd)
536 vmstate_unregister(dev, qdev_get_info(dev)->vmsd, dev);
537 if (qdev_get_info(dev)->exit)
538 qdev_get_info(dev)->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200539 if (dev->opts)
540 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200541 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200542 QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600543 for (prop = qdev_get_info(dev)->props; prop && prop->name; prop++) {
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200544 if (prop->info->free) {
545 prop->info->free(dev, prop);
546 }
547 }
Anthony Liguori024a6fb2012-01-13 07:45:55 -0600548 if (dev->parent) {
549 qdev_property_del_child(dev->parent, dev, NULL);
550 }
551 if (dev->ref != 0) {
552 qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
553 }
Anthony Liguori32fea402011-12-16 14:34:46 -0600554 object_delete(OBJECT(dev));
Paul Brookaae94602009-05-14 22:35:06 +0100555}
556
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200557void qdev_machine_creation_done(void)
558{
559 /*
560 * ok, initial machine setup is done, starting from now we can
561 * only create hotpluggable devices
562 */
563 qdev_hotplug = 1;
564}
565
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700566bool qdev_machine_modified(void)
567{
568 return qdev_hot_added || qdev_hot_removed;
569}
570
Paul Brookaae94602009-05-14 22:35:06 +0100571/* Get a character (serial) device interface. */
572CharDriverState *qdev_init_chardev(DeviceState *dev)
573{
574 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530575
576 /* FIXME: This function needs to go away: use chardev properties! */
577 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100578}
579
Paul Brook02e2da42009-05-23 00:05:19 +0100580BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100581{
Paul Brook02e2da42009-05-23 00:05:19 +0100582 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100583}
584
Paul Brookaae94602009-05-14 22:35:06 +0100585void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
586{
587 assert(dev->num_gpio_in == 0);
588 dev->num_gpio_in = n;
589 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
590}
591
592void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
593{
594 assert(dev->num_gpio_out == 0);
595 dev->num_gpio_out = n;
596 dev->gpio_out = pins;
597}
598
599qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
600{
601 assert(n >= 0 && n < dev->num_gpio_in);
602 return dev->gpio_in[n];
603}
604
605void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
606{
607 assert(n >= 0 && n < dev->num_gpio_out);
608 dev->gpio_out[n] = pin;
609}
610
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200611void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
612{
Jan Kiszka6eed1852011-07-20 12:20:22 +0200613 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200614 if (nd->vlan)
615 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
616 if (nd->netdev)
617 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530618 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200619 qdev_prop_exists(dev, "vectors")) {
620 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
621 }
Peter Maydell48e2faf2011-05-20 16:50:01 +0100622 nd->instantiated = 1;
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200623}
624
Paul Brook02e2da42009-05-23 00:05:19 +0100625BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100626{
Paul Brook02e2da42009-05-23 00:05:19 +0100627 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100628
Blue Swirl72cf2d42009-09-12 07:36:22 +0000629 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100630 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100631 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100632 }
633 }
634 return NULL;
635}
636
Anthony Liguori81699d82010-11-19 18:55:58 +0900637int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
638 qbus_walkerfn *busfn, void *opaque)
639{
640 DeviceState *dev;
641 int err;
642
643 if (busfn) {
644 err = busfn(bus, opaque);
645 if (err) {
646 return err;
647 }
648 }
649
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200650 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori81699d82010-11-19 18:55:58 +0900651 err = qdev_walk_children(dev, devfn, busfn, opaque);
652 if (err < 0) {
653 return err;
654 }
655 }
656
657 return 0;
658}
659
660int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
661 qbus_walkerfn *busfn, void *opaque)
662{
663 BusState *bus;
664 int err;
665
666 if (devfn) {
667 err = devfn(dev, opaque);
668 if (err) {
669 return err;
670 }
671 }
672
673 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
674 err = qbus_walk_children(bus, devfn, busfn, opaque);
675 if (err < 0) {
676 return err;
677 }
678 }
679
680 return 0;
681}
682
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200683static BusState *qbus_find_recursive(BusState *bus, const char *name,
684 const BusInfo *info)
685{
686 DeviceState *dev;
687 BusState *child, *ret;
688 int match = 1;
689
690 if (name && (strcmp(bus->name, name) != 0)) {
691 match = 0;
692 }
693 if (info && (bus->info != info)) {
694 match = 0;
695 }
696 if (match) {
697 return bus;
698 }
699
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200700 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000701 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200702 ret = qbus_find_recursive(child, name, info);
703 if (ret) {
704 return ret;
705 }
706 }
707 }
708 return NULL;
709}
710
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900711DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200712{
713 DeviceState *dev, *ret;
714 BusState *child;
715
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200716 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200717 if (dev->id && strcmp(dev->id, id) == 0)
718 return dev;
719 QLIST_FOREACH(child, &dev->child_bus, sibling) {
720 ret = qdev_find_recursive(child, id);
721 if (ret) {
722 return ret;
723 }
724 }
725 }
726 return NULL;
727}
728
Markus Armbruster53db16b2010-02-18 18:55:59 +0100729static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200730{
731 BusState *child;
732 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200733
Markus Armbruster53db16b2010-02-18 18:55:59 +0100734 error_printf("child busses at \"%s\":",
Anthony Liguorif79f2bf2011-12-04 11:17:51 -0600735 dev->id ? dev->id : object_get_typename(OBJECT(dev)));
Blue Swirl72cf2d42009-09-12 07:36:22 +0000736 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100737 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200738 sep = ", ";
739 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100740 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200741}
742
Markus Armbruster53db16b2010-02-18 18:55:59 +0100743static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200744{
745 DeviceState *dev;
746 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200747
Markus Armbruster53db16b2010-02-18 18:55:59 +0100748 error_printf("devices at \"%s\":", bus->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200749 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguorif79f2bf2011-12-04 11:17:51 -0600750 error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200751 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100752 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200753 sep = ", ";
754 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100755 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200756}
757
758static BusState *qbus_find_bus(DeviceState *dev, char *elem)
759{
760 BusState *child;
761
Blue Swirl72cf2d42009-09-12 07:36:22 +0000762 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200763 if (strcmp(child->name, elem) == 0) {
764 return child;
765 }
766 }
767 return NULL;
768}
769
770static DeviceState *qbus_find_dev(BusState *bus, char *elem)
771{
772 DeviceState *dev;
773
774 /*
775 * try to match in order:
776 * (1) instance id, if present
777 * (2) driver name
778 * (3) driver alias, if present
779 */
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200780 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200781 if (dev->id && strcmp(dev->id, elem) == 0) {
782 return dev;
783 }
784 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200785 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguorif79f2bf2011-12-04 11:17:51 -0600786 if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200787 return dev;
788 }
789 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200790 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori30fbb9f2011-12-04 11:08:36 -0600791 if (qdev_get_info(dev)->alias && strcmp(qdev_get_info(dev)->alias, elem) == 0) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200792 return dev;
793 }
794 }
795 return NULL;
796}
797
798static BusState *qbus_find(const char *path)
799{
800 DeviceState *dev;
801 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100802 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200803 int pos, len;
804
805 /* find start element */
806 if (path[0] == '/') {
807 bus = main_system_bus;
808 pos = 0;
809 } else {
810 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100811 assert(!path[0]);
812 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200813 }
814 bus = qbus_find_recursive(main_system_bus, elem, NULL);
815 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100816 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200817 return NULL;
818 }
819 pos = len;
820 }
821
822 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100823 assert(path[pos] == '/' || !path[pos]);
824 while (path[pos] == '/') {
825 pos++;
826 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200827 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200828 return bus;
829 }
830
831 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100832 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
833 assert(0);
834 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200835 }
836 pos += len;
837 dev = qbus_find_dev(bus, elem);
838 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100839 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100840 if (!monitor_cur_is_qmp()) {
841 qbus_list_dev(bus);
842 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200843 return NULL;
844 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100845
846 assert(path[pos] == '/' || !path[pos]);
847 while (path[pos] == '/') {
848 pos++;
849 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200850 if (path[pos] == '\0') {
851 /* last specified element is a device. If it has exactly
852 * one child bus accept it nevertheless */
853 switch (dev->num_child_bus) {
854 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100855 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200856 return NULL;
857 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000858 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200859 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100860 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100861 if (!monitor_cur_is_qmp()) {
862 qbus_list_bus(dev);
863 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200864 return NULL;
865 }
866 }
867
868 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100869 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
870 assert(0);
871 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200872 }
873 pos += len;
874 bus = qbus_find_bus(dev, elem);
875 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100876 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100877 if (!monitor_cur_is_qmp()) {
878 qbus_list_bus(dev);
879 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200880 return NULL;
881 }
882 }
883}
884
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200885void qbus_create_inplace(BusState *bus, BusInfo *info,
886 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100887{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200888 char *buf;
889 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100890
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200891 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100892 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200893
894 if (name) {
895 /* use supplied name */
Anthony Liguori7267c092011-08-20 22:09:37 -0500896 bus->name = g_strdup(name);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200897 } else if (parent && parent->id) {
898 /* parent device has id -> use it for bus name */
899 len = strlen(parent->id) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500900 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200901 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
902 bus->name = buf;
903 } else {
904 /* no id -> use lowercase bus type for bus name */
905 len = strlen(info->name) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500906 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200907 len = snprintf(buf, len, "%s.%d", info->name,
908 parent ? parent->num_child_bus : 0);
909 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200910 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200911 bus->name = buf;
912 }
913
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200914 QTAILQ_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100915 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000916 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200917 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900918 } else if (bus != main_system_bus) {
919 /* TODO: once all bus devices are qdevified,
920 only reset handler for main_system_bus should be registered here. */
921 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100922 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200923}
924
925BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
926{
927 BusState *bus;
928
Anthony Liguori7267c092011-08-20 22:09:37 -0500929 bus = g_malloc0(info->size);
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200930 bus->qdev_allocated = 1;
931 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100932 return bus;
933}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100934
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900935static void main_system_bus_create(void)
936{
937 /* assign main_system_bus before qbus_create_inplace()
938 * in order to make "if (bus != main_system_bus)" work */
Anthony Liguori7267c092011-08-20 22:09:37 -0500939 main_system_bus = g_malloc0(system_bus_info.size);
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900940 main_system_bus->qdev_allocated = 1;
941 qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
942 "main-system-bus");
943}
944
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200945void qbus_free(BusState *bus)
946{
947 DeviceState *dev;
948
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200949 while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200950 qdev_free(dev);
951 }
952 if (bus->parent) {
953 QLIST_REMOVE(bus, sibling);
954 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900955 } else {
956 assert(bus != main_system_bus); /* main_system_bus is never freed */
957 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200958 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500959 g_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200960 if (bus->qdev_allocated) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500961 g_free(bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200962 }
963}
964
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100965#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
966static void qbus_print(Monitor *mon, BusState *bus, int indent);
967
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200968static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
969 const char *prefix, int indent)
970{
971 char buf[64];
972
973 if (!props)
974 return;
975 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100976 /*
977 * TODO Properties without a print method are just for dirty
978 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
979 * marked for removal. The test props->info->print should be
980 * removed along with it.
981 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200982 if (props->info->print) {
983 props->info->print(dev, props, buf, sizeof(buf));
984 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
985 }
986 props++;
987 }
988}
989
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100990static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
991{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100992 BusState *child;
Anthony Liguorif79f2bf2011-12-04 11:17:51 -0600993 qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200994 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100995 indent += 2;
996 if (dev->num_gpio_in) {
997 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
998 }
999 if (dev->num_gpio_out) {
1000 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
1001 }
Anthony Liguori30fbb9f2011-12-04 11:08:36 -06001002 qdev_print_props(mon, dev, qdev_get_info(dev)->props, "dev", indent);
Gerd Hoffmannee6847d2009-07-15 13:43:31 +02001003 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +02001004 if (dev->parent_bus->info->print_dev)
1005 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +00001006 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +01001007 qbus_print(mon, child, indent);
1008 }
1009}
1010
1011static void qbus_print(Monitor *mon, BusState *bus, int indent)
1012{
1013 struct DeviceState *dev;
1014
1015 qdev_printf("bus: %s\n", bus->name);
1016 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +02001017 qdev_printf("type %s\n", bus->info->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +02001018 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +01001019 qdev_print(mon, dev, indent);
1020 }
1021}
1022#undef qdev_printf
1023
1024void do_info_qtree(Monitor *mon)
1025{
1026 if (main_system_bus)
1027 qbus_print(mon, main_system_bus, 0);
1028}
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001029
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +02001030void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001031{
1032 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001033
1034 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +01001035 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +02001036 }
1037}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001038
Markus Armbruster8bc27242010-02-10 20:52:01 +01001039int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001040{
1041 QemuOpts *opts;
1042
Gerd Hoffmann3329f072010-08-20 13:52:01 +02001043 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +01001044 if (!opts) {
1045 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +01001046 }
Markus Armbruster8bc27242010-02-10 20:52:01 +01001047 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
1048 qemu_opts_del(opts);
1049 return 0;
1050 }
1051 if (!qdev_device_add(opts)) {
1052 qemu_opts_del(opts);
1053 return -1;
1054 }
1055 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001056}
1057
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001058int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001059{
1060 const char *id = qdict_get_str(qdict, "id");
1061 DeviceState *dev;
1062
1063 dev = qdev_find_recursive(main_system_bus, id);
1064 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001065 qerror_report(QERR_DEVICE_NOT_FOUND, id);
1066 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001067 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +01001068 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001069}
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001070
1071static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
1072{
1073 int l = 0;
1074
1075 if (dev && dev->parent_bus) {
1076 char *d;
1077 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
1078 if (dev->parent_bus->info->get_fw_dev_path) {
1079 d = dev->parent_bus->info->get_fw_dev_path(dev);
1080 l += snprintf(p + l, size - l, "%s", d);
Anthony Liguori7267c092011-08-20 22:09:37 -05001081 g_free(d);
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001082 } else {
Anthony Liguorif79f2bf2011-12-04 11:17:51 -06001083 l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001084 }
1085 }
1086 l += snprintf(p + l , size - l, "/");
1087
1088 return l;
1089}
1090
1091char* qdev_get_fw_dev_path(DeviceState *dev)
1092{
1093 char path[128];
1094 int l;
1095
1096 l = qdev_get_fw_dev_path_helper(dev, path, 128);
1097
1098 path[l-1] = '\0';
1099
1100 return strdup(path);
1101}
Anthony Liguori85ed3032011-12-12 14:29:25 -06001102
Anthony Liguoricd34d662011-12-12 14:29:43 -06001103char *qdev_get_type(DeviceState *dev, Error **errp)
1104{
Anthony Liguorif79f2bf2011-12-04 11:17:51 -06001105 return g_strdup(object_get_typename(OBJECT(dev)));
Anthony Liguoricd34d662011-12-12 14:29:43 -06001106}
1107
Anthony Liguori85ed3032011-12-12 14:29:25 -06001108void qdev_ref(DeviceState *dev)
1109{
1110 dev->ref++;
1111}
1112
1113void qdev_unref(DeviceState *dev)
1114{
1115 g_assert(dev->ref > 0);
1116 dev->ref--;
1117}
Anthony Liguori44677de2011-12-12 14:29:26 -06001118
1119void qdev_property_add(DeviceState *dev, const char *name, const char *type,
1120 DevicePropertyAccessor *get, DevicePropertyAccessor *set,
1121 DevicePropertyRelease *release,
1122 void *opaque, Error **errp)
1123{
1124 DeviceProperty *prop = g_malloc0(sizeof(*prop));
1125
1126 prop->name = g_strdup(name);
1127 prop->type = g_strdup(type);
1128
1129 prop->get = get;
1130 prop->set = set;
1131 prop->release = release;
1132 prop->opaque = opaque;
1133
1134 QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
1135}
1136
1137static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
1138{
1139 DeviceProperty *prop;
1140
1141 QTAILQ_FOREACH(prop, &dev->properties, node) {
1142 if (strcmp(prop->name, name) == 0) {
1143 return prop;
1144 }
1145 }
1146
1147 return NULL;
1148}
1149
1150void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
1151 Error **errp)
1152{
1153 DeviceProperty *prop = qdev_property_find(dev, name);
1154
1155 if (prop == NULL) {
1156 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1157 return;
1158 }
1159
1160 if (!prop->get) {
1161 error_set(errp, QERR_PERMISSION_DENIED);
1162 } else {
1163 prop->get(dev, v, prop->opaque, name, errp);
1164 }
1165}
1166
1167void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
1168 Error **errp)
1169{
1170 DeviceProperty *prop = qdev_property_find(dev, name);
1171
1172 if (prop == NULL) {
1173 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1174 return;
1175 }
1176
1177 if (!prop->set) {
1178 error_set(errp, QERR_PERMISSION_DENIED);
1179 } else {
Paolo Bonzini0d41d9a2011-12-18 17:05:05 +01001180 prop->set(dev, v, prop->opaque, name, errp);
Anthony Liguori44677de2011-12-12 14:29:26 -06001181 }
1182}
1183
1184const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
1185{
1186 DeviceProperty *prop = qdev_property_find(dev, name);
1187
1188 if (prop == NULL) {
1189 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1190 return NULL;
1191 }
1192
1193 return prop->type;
1194}
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001195
1196/**
1197 * Legacy property handling
1198 */
1199
1200static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1201 const char *name, Error **errp)
1202{
1203 Property *prop = opaque;
1204
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001205 char buffer[1024];
1206 char *ptr = buffer;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001207
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001208 prop->info->print(dev, prop, buffer, sizeof(buffer));
1209 visit_type_str(v, &ptr, name, errp);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001210}
1211
1212static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1213 const char *name, Error **errp)
1214{
1215 Property *prop = opaque;
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001216 Error *local_err = NULL;
1217 char *ptr = NULL;
1218 int ret;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001219
1220 if (dev->state != DEV_STATE_CREATED) {
1221 error_set(errp, QERR_PERMISSION_DENIED);
1222 return;
1223 }
1224
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001225 visit_type_str(v, &ptr, name, &local_err);
1226 if (local_err) {
1227 error_propagate(errp, local_err);
1228 return;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001229 }
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001230
1231 ret = prop->info->parse(dev, prop, ptr);
Paolo Bonzini7db4c4e2011-12-18 17:05:07 +01001232 error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001233 g_free(ptr);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001234}
1235
1236/**
1237 * @qdev_add_legacy_property - adds a legacy property
1238 *
1239 * Do not use this is new code! Properties added through this interface will
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001240 * be given names and types in the "legacy" namespace.
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001241 *
1242 * Legacy properties are always processed as strings. The format of the string
1243 * depends on the property type.
1244 */
1245void qdev_property_add_legacy(DeviceState *dev, Property *prop,
1246 Error **errp)
1247{
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001248 gchar *name, *type;
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001249
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001250 name = g_strdup_printf("legacy-%s", prop->name);
Paolo Bonzinicafe5bd2011-12-18 17:05:10 +01001251 type = g_strdup_printf("legacy<%s>",
1252 prop->info->legacy_name ?: prop->info->name);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001253
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001254 qdev_property_add(dev, name, type,
Paolo Bonzinie3cb6ba2011-12-18 17:05:06 +01001255 prop->info->print ? qdev_get_legacy_property : NULL,
1256 prop->info->parse ? qdev_set_legacy_property : NULL,
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001257 NULL,
1258 prop, errp);
1259
1260 g_free(type);
Paolo Bonzinica2cc782011-12-18 17:05:11 +01001261 g_free(name);
1262}
1263
1264/**
1265 * @qdev_property_add_static - add a @Property to a device.
1266 *
1267 * Static properties access data in a struct. The actual type of the
1268 * property and the field depends on the property type.
1269 */
1270void qdev_property_add_static(DeviceState *dev, Property *prop,
1271 Error **errp)
1272{
1273 qdev_property_add(dev, prop->name, prop->info->name,
1274 prop->info->get, prop->info->set,
1275 NULL,
1276 prop, errp);
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001277}
Anthony Liguoria10f07a2011-12-12 14:29:28 -06001278
1279DeviceState *qdev_get_root(void)
1280{
1281 static DeviceState *qdev_root;
1282
1283 if (!qdev_root) {
1284 qdev_root = qdev_create(NULL, "container");
1285 qdev_init_nofail(qdev_root);
1286 }
1287
1288 return qdev_root;
1289}
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001290
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001291static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
1292 const char *name, Error **errp)
1293{
1294 DeviceState *child = opaque;
1295 gchar *path;
1296
1297 path = qdev_get_canonical_path(child);
1298 visit_type_str(v, &path, name, errp);
1299 g_free(path);
1300}
1301
Anthony Liguori024a6fb2012-01-13 07:45:55 -06001302static void qdev_release_child_property(DeviceState *dev, const char *name,
1303 void *opaque)
1304{
1305 DeviceState *child = opaque;
1306
1307 qdev_unref(child);
1308}
1309
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001310void qdev_property_add_child(DeviceState *dev, const char *name,
1311 DeviceState *child, Error **errp)
1312{
1313 gchar *type;
1314
Anthony Liguorif79f2bf2011-12-04 11:17:51 -06001315 type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001316
1317 qdev_property_add(dev, name, type, qdev_get_child_property,
Anthony Liguori024a6fb2012-01-13 07:45:55 -06001318 NULL, qdev_release_child_property,
1319 child, errp);
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001320
1321 qdev_ref(child);
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001322 g_assert(child->parent == NULL);
1323 child->parent = dev;
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001324
1325 g_free(type);
1326}
1327
Anthony Liguori83e94fb2011-12-12 14:29:32 -06001328static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
1329 const char *name, Error **errp)
1330{
1331 DeviceState **child = opaque;
1332 gchar *path;
1333
1334 if (*child) {
1335 path = qdev_get_canonical_path(*child);
1336 visit_type_str(v, &path, name, errp);
1337 g_free(path);
1338 } else {
1339 path = (gchar *)"";
1340 visit_type_str(v, &path, name, errp);
1341 }
1342}
1343
1344static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
1345 const char *name, Error **errp)
1346{
1347 DeviceState **child = opaque;
1348 bool ambiguous = false;
1349 const char *type;
1350 char *path;
1351
1352 type = qdev_property_get_type(dev, name, NULL);
1353
1354 visit_type_str(v, &path, name, errp);
1355
1356 if (*child) {
1357 qdev_unref(*child);
1358 }
1359
1360 if (strcmp(path, "") != 0) {
1361 DeviceState *target;
1362
1363 target = qdev_resolve_path(path, &ambiguous);
1364 if (target) {
1365 gchar *target_type;
1366
Anthony Liguorif79f2bf2011-12-04 11:17:51 -06001367 target_type = g_strdup_printf("link<%s>", object_get_typename(OBJECT(target)));
Anthony Liguori83e94fb2011-12-12 14:29:32 -06001368 if (strcmp(target_type, type) == 0) {
1369 *child = target;
1370 qdev_ref(target);
1371 } else {
1372 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
1373 }
1374
1375 g_free(target_type);
1376 } else {
1377 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
1378 }
1379 } else {
1380 *child = NULL;
1381 }
1382
1383 g_free(path);
1384}
1385
1386void qdev_property_add_link(DeviceState *dev, const char *name,
1387 const char *type, DeviceState **child,
1388 Error **errp)
1389{
1390 gchar *full_type;
1391
1392 full_type = g_strdup_printf("link<%s>", type);
1393
1394 qdev_property_add(dev, name, full_type,
1395 qdev_get_link_property,
1396 qdev_set_link_property,
1397 NULL, child, errp);
1398
1399 g_free(full_type);
1400}
1401
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001402gchar *qdev_get_canonical_path(DeviceState *dev)
1403{
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001404 DeviceState *root = qdev_get_root();
1405 char *newpath = NULL, *path = NULL;
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001406
Anthony Liguorib2b6c392011-12-12 14:29:40 -06001407 while (dev != root) {
1408 DeviceProperty *prop = NULL;
1409
1410 g_assert(dev->parent != NULL);
1411
1412 QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
1413 if (!strstart(prop->type, "child<", NULL)) {
1414 continue;
1415 }
1416
1417 if (prop->opaque == dev) {
1418 if (path) {
1419 newpath = g_strdup_printf("%s/%s", prop->name, path);
1420 g_free(path);
1421 path = newpath;
1422 } else {
1423 path = g_strdup(prop->name);
1424 }
1425 break;
1426 }
1427 }
1428
1429 g_assert(prop != NULL);
1430
1431 dev = dev->parent;
1432 }
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001433
1434 newpath = g_strdup_printf("/%s", path);
1435 g_free(path);
1436
1437 return newpath;
1438}
Anthony Liguoridc45c212011-12-12 14:29:30 -06001439
1440static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
1441 gchar **parts,
1442 int index)
1443{
1444 DeviceProperty *prop;
1445 DeviceState *child;
1446
1447 if (parts[index] == NULL) {
1448 return parent;
1449 }
1450
1451 if (strcmp(parts[index], "") == 0) {
1452 return qdev_resolve_abs_path(parent, parts, index + 1);
1453 }
1454
1455 prop = qdev_property_find(parent, parts[index]);
1456 if (prop == NULL) {
1457 return NULL;
1458 }
1459
1460 child = NULL;
1461 if (strstart(prop->type, "link<", NULL)) {
1462 DeviceState **pchild = prop->opaque;
1463 if (*pchild) {
1464 child = *pchild;
1465 }
1466 } else if (strstart(prop->type, "child<", NULL)) {
1467 child = prop->opaque;
1468 }
1469
1470 if (!child) {
1471 return NULL;
1472 }
1473
1474 return qdev_resolve_abs_path(child, parts, index + 1);
1475}
1476
1477static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
1478 gchar **parts,
1479 bool *ambiguous)
1480{
1481 DeviceState *dev;
1482 DeviceProperty *prop;
1483
1484 dev = qdev_resolve_abs_path(parent, parts, 0);
1485
1486 QTAILQ_FOREACH(prop, &parent->properties, node) {
1487 DeviceState *found;
1488
1489 if (!strstart(prop->type, "child<", NULL)) {
1490 continue;
1491 }
1492
1493 found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
1494 if (found) {
1495 if (dev) {
1496 if (ambiguous) {
1497 *ambiguous = true;
1498 }
1499 return NULL;
1500 }
1501 dev = found;
1502 }
1503
1504 if (ambiguous && *ambiguous) {
1505 return NULL;
1506 }
1507 }
1508
1509 return dev;
1510}
1511
1512DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
1513{
1514 bool partial_path = true;
1515 DeviceState *dev;
1516 gchar **parts;
1517
1518 parts = g_strsplit(path, "/", 0);
1519 if (parts == NULL || parts[0] == NULL) {
1520 g_strfreev(parts);
1521 return qdev_get_root();
1522 }
1523
1524 if (strcmp(parts[0], "") == 0) {
1525 partial_path = false;
1526 }
1527
1528 if (partial_path) {
1529 if (ambiguous) {
1530 *ambiguous = false;
1531 }
1532 dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
1533 } else {
1534 dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
1535 }
1536
1537 g_strfreev(parts);
1538
1539 return dev;
1540}
1541
Anthony Liguori6a146eb2011-12-12 14:29:42 -06001542typedef struct StringProperty
1543{
1544 char *(*get)(DeviceState *, Error **);
1545 void (*set)(DeviceState *, const char *, Error **);
1546} StringProperty;
1547
1548static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque,
1549 const char *name, Error **errp)
1550{
1551 StringProperty *prop = opaque;
1552 char *value;
1553
1554 value = prop->get(dev, errp);
1555 if (value) {
1556 visit_type_str(v, &value, name, errp);
1557 g_free(value);
1558 }
1559}
1560
1561static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque,
1562 const char *name, Error **errp)
1563{
1564 StringProperty *prop = opaque;
1565 char *value;
1566 Error *local_err = NULL;
1567
1568 visit_type_str(v, &value, name, &local_err);
1569 if (local_err) {
1570 error_propagate(errp, local_err);
1571 return;
1572 }
1573
1574 prop->set(dev, value, errp);
1575 g_free(value);
1576}
1577
1578static void qdev_property_release_str(DeviceState *dev, const char *name,
1579 void *opaque)
1580{
1581 StringProperty *prop = opaque;
1582 g_free(prop);
1583}
1584
1585void qdev_property_add_str(DeviceState *dev, const char *name,
1586 char *(*get)(DeviceState *, Error **),
1587 void (*set)(DeviceState *, const char *, Error **),
1588 Error **errp)
1589{
1590 StringProperty *prop = g_malloc0(sizeof(*prop));
1591
1592 prop->get = get;
1593 prop->set = set;
1594
1595 qdev_property_add(dev, name, "string",
1596 get ? qdev_property_get_str : NULL,
1597 set ? qdev_property_set_str : NULL,
1598 qdev_property_release_str,
1599 prop, errp);
1600}
Anthony Liguori1de81d22011-12-19 16:37:46 -06001601
1602void qdev_machine_init(void)
1603{
1604 qdev_get_peripheral_anon();
1605 qdev_get_peripheral();
1606}
Anthony Liguori32fea402011-12-16 14:34:46 -06001607
Anthony Liguori94afdad2011-12-04 11:36:01 -06001608void device_reset(DeviceState *dev)
1609{
1610 DeviceClass *klass = DEVICE_GET_CLASS(dev);
1611
1612 if (klass->reset) {
1613 klass->reset(dev);
1614 }
1615}
1616
Anthony Liguori32fea402011-12-16 14:34:46 -06001617static TypeInfo device_type_info = {
1618 .name = TYPE_DEVICE,
1619 .parent = TYPE_OBJECT,
1620 .instance_size = sizeof(DeviceState),
1621 .abstract = true,
1622 .class_size = sizeof(DeviceClass),
1623};
1624
1625static void init_qdev(void)
1626{
1627 type_register_static(&device_type_info);
1628}
1629
1630device_init(init_qdev);