blob: 4d491f109e96f26e11fef9e86fd237aa305b1a34 [file] [log] [blame]
Paul Brookaae94602009-05-14 22:35:06 +01001/*
2 * Dynamic device configuration and creation.
3 *
4 * Copyright (c) 2009 CodeSourcery
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Paul Brookaae94602009-05-14 22:35:06 +010018 */
19
20/* The theory here is that it should be possible to create a machine without
21 knowledge of specific devices. Historically board init routines have
22 passed a bunch of arguments to each device, requiring the board know
23 exactly which device it is dealing with. This file provides an abstract
24 API for device configuration and initialization. Devices will generally
25 inherit from a particular bus (e.g. PCI or I2C) rather than
26 this API directly. */
27
Paul Brook9d07d752009-05-14 22:35:07 +010028#include "net.h"
Paul Brookaae94602009-05-14 22:35:06 +010029#include "qdev.h"
30#include "sysemu.h"
Gerd Hoffmanncae49562009-06-05 15:53:17 +010031#include "monitor.h"
Paul Brookaae94602009-05-14 22:35:06 +010032
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020033static int qdev_hotplug = 0;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070034static bool qdev_hot_added = false;
35static bool qdev_hot_removed = false;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020036
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020037/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000038static BusState *main_system_bus;
Isaku Yamahata2da8bb92011-08-02 10:59:13 +090039static void main_system_bus_create(void);
Paul Brook4d6ae672009-05-14 22:35:06 +010040
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010041DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010042
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020043static BusState *qbus_find_recursive(BusState *bus, const char *name,
44 const BusInfo *info);
45static BusState *qbus_find(const char *path);
46
Paul Brookaae94602009-05-14 22:35:06 +010047/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020048void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010049{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020050 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020051 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010052
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020053 info->next = device_info_list;
54 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010055}
56
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020057static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
58{
59 DeviceInfo *info;
60
Gerd Hoffmann3320e562009-07-15 13:43:33 +020061 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020062 for (info = device_info_list; info != NULL; info = info->next) {
63 if (bus_info && info->bus_info != bus_info)
64 continue;
65 if (strcmp(info->name, name) != 0)
66 continue;
67 return info;
68 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020069
70 /* failing that check the aliases */
71 for (info = device_info_list; info != NULL; info = info->next) {
72 if (bus_info && info->bus_info != bus_info)
73 continue;
74 if (!info->alias)
75 continue;
76 if (strcmp(info->alias, name) != 0)
77 continue;
78 return info;
79 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020080 return NULL;
81}
82
Markus Armbruster0c175422010-02-19 19:12:18 +010083static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010084{
Paul Brookaae94602009-05-14 22:35:06 +010085 DeviceState *dev;
Anthony Liguoria5296ca2011-12-12 14:29:27 -060086 Property *prop;
Paul Brookaae94602009-05-14 22:35:06 +010087
Markus Armbruster0c175422010-02-19 19:12:18 +010088 assert(bus->info == info->bus_info);
Anthony Liguori7267c092011-08-20 22:09:37 -050089 dev = g_malloc0(info->size);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020090 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010091 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020092 qdev_prop_set_defaults(dev, dev->info->props);
93 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +010094 qdev_prop_set_globals(dev);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +020095 QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020096 if (qdev_hotplug) {
97 assert(bus->allow_hotplug);
98 dev->hotplugged = 1;
Alex Williamson0ac8ef72011-01-04 12:37:50 -070099 qdev_hot_added = true;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200100 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200101 dev->instance_id_alias = -1;
Anthony Liguori44677de2011-12-12 14:29:26 -0600102 QTAILQ_INIT(&dev->properties);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200103 dev->state = DEV_STATE_CREATED;
Anthony Liguoria5296ca2011-12-12 14:29:27 -0600104
105 for (prop = dev->info->props; prop && prop->name; prop++) {
106 qdev_property_add_legacy(dev, prop, NULL);
107 }
108
109 for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
110 qdev_property_add_legacy(dev, prop, NULL);
111 }
112
Paul Brookaae94602009-05-14 22:35:06 +0100113 return dev;
114}
115
Markus Armbruster0c175422010-02-19 19:12:18 +0100116/* Create a new device. This only initializes the device state structure
117 and allows properties to be set. qdev_init should be called to
118 initialize the actual device emulation. */
119DeviceState *qdev_create(BusState *bus, const char *name)
120{
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000121 DeviceState *dev;
122
123 dev = qdev_try_create(bus, name);
124 if (!dev) {
Peter Maydelle92714c2011-08-03 23:49:04 +0100125 if (bus) {
126 hw_error("Unknown device '%s' for bus '%s'\n", name,
127 bus->info->name);
128 } else {
129 hw_error("Unknown device '%s' for default sysbus\n", name);
130 }
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000131 }
132
133 return dev;
134}
135
136DeviceState *qdev_try_create(BusState *bus, const char *name)
137{
Markus Armbruster0c175422010-02-19 19:12:18 +0100138 DeviceInfo *info;
139
140 if (!bus) {
Stefan Weil68694892010-12-16 19:33:22 +0100141 bus = sysbus_get_default();
Markus Armbruster0c175422010-02-19 19:12:18 +0100142 }
143
144 info = qdev_find_info(bus->info, name);
145 if (!info) {
Blue Swirl0bcdeda2011-02-05 14:34:25 +0000146 return NULL;
Markus Armbruster0c175422010-02-19 19:12:18 +0100147 }
148
149 return qdev_create_from_info(bus, info);
150}
151
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100152static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200153{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100154 error_printf("name \"%s\", bus %s",
155 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200156 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100157 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200158 }
159 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100160 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200161 }
162 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100163 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200164 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100165 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200166}
167
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200168static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200169{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200170 DeviceState *dev = opaque;
171
172 if (strcmp(name, "driver") == 0)
173 return 0;
174 if (strcmp(name, "bus") == 0)
175 return 0;
176
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100177 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200178 return -1;
179 }
180 return 0;
181}
182
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100183int qdev_device_help(QemuOpts *opts)
184{
185 const char *driver;
186 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100187 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100188
189 driver = qemu_opt_get(opts, "driver");
190 if (driver && !strcmp(driver, "?")) {
191 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100192 if (info->no_user) {
193 continue; /* not available, don't show */
194 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100195 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100196 }
197 return 1;
198 }
199
Markus Armbruster542379f2011-11-08 11:00:38 +0100200 if (!driver || !qemu_opt_get(opts, "?")) {
Markus Armbruster08350cf2010-01-29 19:49:00 +0100201 return 0;
202 }
203
204 info = qdev_find_info(NULL, driver);
205 if (!info) {
206 return 0;
207 }
208
209 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100210 /*
211 * TODO Properties without a parser are just for dirty hacks.
212 * qdev_prop_ptr is the only such PropertyInfo. It's marked
213 * for removal. This conditional should be removed along with
214 * it.
215 */
216 if (!prop->info->parse) {
217 continue; /* no way to set it, don't show */
218 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100219 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100220 }
Gerd Hoffmanna8467c72011-09-16 11:25:05 +0200221 for (prop = info->bus_info->props; prop && prop->name; prop++) {
222 if (!prop->info->parse) {
223 continue; /* no way to set it, don't show */
224 }
225 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
226 }
Markus Armbruster08350cf2010-01-29 19:49:00 +0100227 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100228}
229
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600230static DeviceState *qdev_get_peripheral(void)
231{
232 static DeviceState *dev;
233
234 if (dev == NULL) {
235 dev = qdev_create(NULL, "container");
236 qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
237 qdev_init_nofail(dev);
238 }
239
240 return dev;
241}
242
Anthony Liguori8eb02832011-12-12 14:29:37 -0600243static DeviceState *qdev_get_peripheral_anon(void)
244{
245 static DeviceState *dev;
246
247 if (dev == NULL) {
248 dev = qdev_create(NULL, "container");
249 qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
250 qdev_init_nofail(dev);
251 }
252
253 return dev;
254}
255
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200256DeviceState *qdev_device_add(QemuOpts *opts)
257{
258 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200259 DeviceInfo *info;
260 DeviceState *qdev;
261 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200262
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200263 driver = qemu_opt_get(opts, "driver");
264 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100265 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200266 return NULL;
267 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200268
269 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200270 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100271 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100272 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100273 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200274 return NULL;
275 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200276
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200277 /* find bus */
278 path = qemu_opt_get(opts, "bus");
279 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200280 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100281 if (!bus) {
282 return NULL;
283 }
284 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100285 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
286 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100287 return NULL;
288 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200289 } else {
290 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100291 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100292 qerror_report(QERR_NO_BUS_FOR_DEVICE,
293 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100294 return NULL;
295 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200296 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200297 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100298 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200299 return NULL;
300 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200301
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200302 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100303 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200304 id = qemu_opts_id(opts);
305 if (id) {
306 qdev->id = id;
Anthony Liguori1bdaacb2011-12-12 14:29:36 -0600307 qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
Anthony Liguori8eb02832011-12-12 14:29:37 -0600308 } else {
309 static int anon_count;
310 gchar *name = g_strdup_printf("device[%d]", anon_count++);
311 qdev_property_add_child(qdev_get_peripheral_anon(), name,
312 qdev, NULL);
313 g_free(name);
314 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200315 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
316 qdev_free(qdev);
317 return NULL;
318 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200319 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100320 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200321 return NULL;
322 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200323 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200324 return qdev;
325}
326
Paul Brookaae94602009-05-14 22:35:06 +0100327/* Initialize a device. Device properties should be set before calling
328 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200329 calling this function.
330 On failure, destroy the device and return negative value.
331 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200332int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100333{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200334 int rc;
335
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200336 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200337 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200338 if (rc < 0) {
339 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200340 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200341 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200342 if (dev->info->vmsd) {
Alex Williamson0be71e32010-06-25 11:09:07 -0600343 vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200344 dev->instance_id_alias,
345 dev->alias_required_for_version);
346 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200347 dev->state = DEV_STATE_INITIALIZED;
Jan Kiszka5ab28c82011-07-24 19:38:36 +0200348 if (dev->hotplugged && dev->info->reset) {
349 dev->info->reset(dev);
350 }
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200351 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100352}
353
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200354void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
355 int required_for_version)
356{
357 assert(dev->state == DEV_STATE_CREATED);
358 dev->instance_id_alias = alias_id;
359 dev->alias_required_for_version = required_for_version;
360}
361
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200362int qdev_unplug(DeviceState *dev)
363{
364 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100365 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200366 return -1;
367 }
Amit Shah593831d2009-11-02 14:56:41 +0530368 assert(dev->info->unplug != NULL);
369
Anthony Liguori85ed3032011-12-12 14:29:25 -0600370 if (dev->ref != 0) {
371 qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
372 return -1;
373 }
374
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700375 qdev_hot_removed = true;
376
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200377 return dev->info->unplug(dev);
378}
379
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900380static int qdev_reset_one(DeviceState *dev, void *opaque)
381{
382 if (dev->info->reset) {
383 dev->info->reset(dev);
384 }
385
386 return 0;
387}
388
389BusState *sysbus_get_default(void)
390{
Stefan Weil68694892010-12-16 19:33:22 +0100391 if (!main_system_bus) {
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900392 main_system_bus_create();
Stefan Weil68694892010-12-16 19:33:22 +0100393 }
Anthony Liguoriec990eb2010-11-19 18:55:59 +0900394 return main_system_bus;
395}
396
Isaku Yamahatab4694b72010-11-19 18:56:00 +0900397static int qbus_reset_one(BusState *bus, void *opaque)
398{
399 if (bus->info->reset) {
400 return bus->info->reset(bus);
401 }
402 return 0;
403}
404
Isaku Yamahata5af0a042010-11-19 18:56:01 +0900405void qdev_reset_all(DeviceState *dev)
406{
407 qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
408}
409
Isaku Yamahata80376c32010-12-20 14:33:35 +0900410void qbus_reset_all_fn(void *opaque)
411{
412 BusState *bus = opaque;
Michael S. Tsirkinf530cce2010-12-20 15:17:10 +0200413 qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
Isaku Yamahata80376c32010-12-20 14:33:35 +0900414}
415
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200416/* can be used as ->unplug() callback for the simple cases */
417int qdev_simple_unplug_cb(DeviceState *dev)
418{
419 /* just zap it */
420 qdev_free(dev);
421 return 0;
422}
423
Michael Tokarev3b29a102011-04-06 17:51:59 +0400424
425/* Like qdev_init(), but terminate program via error_report() instead of
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200426 returning an error value. This is okay during machine creation.
427 Don't use for hotplug, because there callers need to recover from
428 failure. Exception: if you know the device's init() callback can't
429 fail, then qdev_init_nofail() can't fail either, and is therefore
430 usable even then. But relying on the device implementation that
431 way is somewhat unclean, and best avoided. */
432void qdev_init_nofail(DeviceState *dev)
433{
434 DeviceInfo *info = dev->info;
435
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200436 if (qdev_init(dev) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +0200437 error_report("Initialization of device %s failed", info->name);
Markus Armbrusterbd6c9a62010-05-27 21:23:08 +0200438 exit(1);
439 }
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200440}
441
Anthony Liguori44677de2011-12-12 14:29:26 -0600442static void qdev_property_del_all(DeviceState *dev)
443{
444 while (!QTAILQ_EMPTY(&dev->properties)) {
445 DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
446
447 QTAILQ_REMOVE(&dev->properties, prop, node);
448
449 if (prop->release) {
450 prop->release(dev, prop->name, prop->opaque);
451 }
452
453 g_free(prop->name);
454 g_free(prop->type);
455 g_free(prop);
456 }
457}
458
Paul Brook02e2da42009-05-23 00:05:19 +0100459/* Unlink device from bus and free the structure. */
460void qdev_free(DeviceState *dev)
461{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200462 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200463 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200464
Anthony Liguori44677de2011-12-12 14:29:26 -0600465 qdev_property_del_all(dev);
466
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200467 if (dev->state == DEV_STATE_INITIALIZED) {
468 while (dev->num_child_bus) {
469 bus = QLIST_FIRST(&dev->child_bus);
470 qbus_free(bus);
471 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200472 if (dev->info->vmsd)
Alex Williamson0be71e32010-06-25 11:09:07 -0600473 vmstate_unregister(dev, dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200474 if (dev->info->exit)
475 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200476 if (dev->opts)
477 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200478 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200479 QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200480 for (prop = dev->info->props; prop && prop->name; prop++) {
481 if (prop->info->free) {
482 prop->info->free(dev, prop);
483 }
484 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500485 g_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100486}
487
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200488void qdev_machine_creation_done(void)
489{
490 /*
491 * ok, initial machine setup is done, starting from now we can
492 * only create hotpluggable devices
493 */
494 qdev_hotplug = 1;
495}
496
Alex Williamson0ac8ef72011-01-04 12:37:50 -0700497bool qdev_machine_modified(void)
498{
499 return qdev_hot_added || qdev_hot_removed;
500}
501
Paul Brookaae94602009-05-14 22:35:06 +0100502/* Get a character (serial) device interface. */
503CharDriverState *qdev_init_chardev(DeviceState *dev)
504{
505 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530506
507 /* FIXME: This function needs to go away: use chardev properties! */
508 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100509}
510
Paul Brook02e2da42009-05-23 00:05:19 +0100511BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100512{
Paul Brook02e2da42009-05-23 00:05:19 +0100513 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100514}
515
Paul Brookaae94602009-05-14 22:35:06 +0100516void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
517{
518 assert(dev->num_gpio_in == 0);
519 dev->num_gpio_in = n;
520 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
521}
522
523void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
524{
525 assert(dev->num_gpio_out == 0);
526 dev->num_gpio_out = n;
527 dev->gpio_out = pins;
528}
529
530qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
531{
532 assert(n >= 0 && n < dev->num_gpio_in);
533 return dev->gpio_in[n];
534}
535
536void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
537{
538 assert(n >= 0 && n < dev->num_gpio_out);
539 dev->gpio_out[n] = pin;
540}
541
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200542void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
543{
Jan Kiszka6eed1852011-07-20 12:20:22 +0200544 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200545 if (nd->vlan)
546 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
547 if (nd->netdev)
548 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530549 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200550 qdev_prop_exists(dev, "vectors")) {
551 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
552 }
Peter Maydell48e2faf2011-05-20 16:50:01 +0100553 nd->instantiated = 1;
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200554}
555
Paul Brook02e2da42009-05-23 00:05:19 +0100556BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100557{
Paul Brook02e2da42009-05-23 00:05:19 +0100558 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100559
Blue Swirl72cf2d42009-09-12 07:36:22 +0000560 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100561 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100562 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100563 }
564 }
565 return NULL;
566}
567
Anthony Liguori81699d82010-11-19 18:55:58 +0900568int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
569 qbus_walkerfn *busfn, void *opaque)
570{
571 DeviceState *dev;
572 int err;
573
574 if (busfn) {
575 err = busfn(bus, opaque);
576 if (err) {
577 return err;
578 }
579 }
580
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200581 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Anthony Liguori81699d82010-11-19 18:55:58 +0900582 err = qdev_walk_children(dev, devfn, busfn, opaque);
583 if (err < 0) {
584 return err;
585 }
586 }
587
588 return 0;
589}
590
591int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
592 qbus_walkerfn *busfn, void *opaque)
593{
594 BusState *bus;
595 int err;
596
597 if (devfn) {
598 err = devfn(dev, opaque);
599 if (err) {
600 return err;
601 }
602 }
603
604 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
605 err = qbus_walk_children(bus, devfn, busfn, opaque);
606 if (err < 0) {
607 return err;
608 }
609 }
610
611 return 0;
612}
613
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200614static BusState *qbus_find_recursive(BusState *bus, const char *name,
615 const BusInfo *info)
616{
617 DeviceState *dev;
618 BusState *child, *ret;
619 int match = 1;
620
621 if (name && (strcmp(bus->name, name) != 0)) {
622 match = 0;
623 }
624 if (info && (bus->info != info)) {
625 match = 0;
626 }
627 if (match) {
628 return bus;
629 }
630
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200631 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000632 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200633 ret = qbus_find_recursive(child, name, info);
634 if (ret) {
635 return ret;
636 }
637 }
638 }
639 return NULL;
640}
641
Isaku Yamahataa2ee6b42010-12-24 12:14:12 +0900642DeviceState *qdev_find_recursive(BusState *bus, const char *id)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200643{
644 DeviceState *dev, *ret;
645 BusState *child;
646
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200647 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200648 if (dev->id && strcmp(dev->id, id) == 0)
649 return dev;
650 QLIST_FOREACH(child, &dev->child_bus, sibling) {
651 ret = qdev_find_recursive(child, id);
652 if (ret) {
653 return ret;
654 }
655 }
656 }
657 return NULL;
658}
659
Markus Armbruster53db16b2010-02-18 18:55:59 +0100660static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200661{
662 BusState *child;
663 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200664
Markus Armbruster53db16b2010-02-18 18:55:59 +0100665 error_printf("child busses at \"%s\":",
666 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000667 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100668 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200669 sep = ", ";
670 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100671 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200672}
673
Markus Armbruster53db16b2010-02-18 18:55:59 +0100674static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200675{
676 DeviceState *dev;
677 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200678
Markus Armbruster53db16b2010-02-18 18:55:59 +0100679 error_printf("devices at \"%s\":", bus->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200680 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100681 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200682 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100683 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200684 sep = ", ";
685 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100686 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200687}
688
689static BusState *qbus_find_bus(DeviceState *dev, char *elem)
690{
691 BusState *child;
692
Blue Swirl72cf2d42009-09-12 07:36:22 +0000693 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200694 if (strcmp(child->name, elem) == 0) {
695 return child;
696 }
697 }
698 return NULL;
699}
700
701static DeviceState *qbus_find_dev(BusState *bus, char *elem)
702{
703 DeviceState *dev;
704
705 /*
706 * try to match in order:
707 * (1) instance id, if present
708 * (2) driver name
709 * (3) driver alias, if present
710 */
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200711 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200712 if (dev->id && strcmp(dev->id, elem) == 0) {
713 return dev;
714 }
715 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200716 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200717 if (strcmp(dev->info->name, elem) == 0) {
718 return dev;
719 }
720 }
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200721 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200722 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
723 return dev;
724 }
725 }
726 return NULL;
727}
728
729static BusState *qbus_find(const char *path)
730{
731 DeviceState *dev;
732 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100733 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200734 int pos, len;
735
736 /* find start element */
737 if (path[0] == '/') {
738 bus = main_system_bus;
739 pos = 0;
740 } else {
741 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100742 assert(!path[0]);
743 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200744 }
745 bus = qbus_find_recursive(main_system_bus, elem, NULL);
746 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100747 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200748 return NULL;
749 }
750 pos = len;
751 }
752
753 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100754 assert(path[pos] == '/' || !path[pos]);
755 while (path[pos] == '/') {
756 pos++;
757 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200758 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200759 return bus;
760 }
761
762 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100763 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
764 assert(0);
765 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200766 }
767 pos += len;
768 dev = qbus_find_dev(bus, elem);
769 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100770 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100771 if (!monitor_cur_is_qmp()) {
772 qbus_list_dev(bus);
773 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200774 return NULL;
775 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100776
777 assert(path[pos] == '/' || !path[pos]);
778 while (path[pos] == '/') {
779 pos++;
780 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200781 if (path[pos] == '\0') {
782 /* last specified element is a device. If it has exactly
783 * one child bus accept it nevertheless */
784 switch (dev->num_child_bus) {
785 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100786 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200787 return NULL;
788 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000789 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200790 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100791 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100792 if (!monitor_cur_is_qmp()) {
793 qbus_list_bus(dev);
794 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200795 return NULL;
796 }
797 }
798
799 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100800 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
801 assert(0);
802 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200803 }
804 pos += len;
805 bus = qbus_find_bus(dev, elem);
806 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100807 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100808 if (!monitor_cur_is_qmp()) {
809 qbus_list_bus(dev);
810 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200811 return NULL;
812 }
813 }
814}
815
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200816void qbus_create_inplace(BusState *bus, BusInfo *info,
817 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100818{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200819 char *buf;
820 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100821
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200822 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100823 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200824
825 if (name) {
826 /* use supplied name */
Anthony Liguori7267c092011-08-20 22:09:37 -0500827 bus->name = g_strdup(name);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200828 } else if (parent && parent->id) {
829 /* parent device has id -> use it for bus name */
830 len = strlen(parent->id) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500831 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200832 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
833 bus->name = buf;
834 } else {
835 /* no id -> use lowercase bus type for bus name */
836 len = strlen(info->name) + 16;
Anthony Liguori7267c092011-08-20 22:09:37 -0500837 buf = g_malloc(len);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200838 len = snprintf(buf, len, "%s.%d", info->name,
839 parent ? parent->num_child_bus : 0);
840 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200841 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200842 bus->name = buf;
843 }
844
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200845 QTAILQ_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100846 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000847 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200848 parent->num_child_bus++;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900849 } else if (bus != main_system_bus) {
850 /* TODO: once all bus devices are qdevified,
851 only reset handler for main_system_bus should be registered here. */
852 qemu_register_reset(qbus_reset_all_fn, bus);
Paul Brook02e2da42009-05-23 00:05:19 +0100853 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200854}
855
856BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
857{
858 BusState *bus;
859
Anthony Liguori7267c092011-08-20 22:09:37 -0500860 bus = g_malloc0(info->size);
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200861 bus->qdev_allocated = 1;
862 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100863 return bus;
864}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100865
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900866static void main_system_bus_create(void)
867{
868 /* assign main_system_bus before qbus_create_inplace()
869 * in order to make "if (bus != main_system_bus)" work */
Anthony Liguori7267c092011-08-20 22:09:37 -0500870 main_system_bus = g_malloc0(system_bus_info.size);
Isaku Yamahata2da8bb92011-08-02 10:59:13 +0900871 main_system_bus->qdev_allocated = 1;
872 qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
873 "main-system-bus");
874}
875
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200876void qbus_free(BusState *bus)
877{
878 DeviceState *dev;
879
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200880 while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200881 qdev_free(dev);
882 }
883 if (bus->parent) {
884 QLIST_REMOVE(bus, sibling);
885 bus->parent->num_child_bus--;
Isaku Yamahata80376c32010-12-20 14:33:35 +0900886 } else {
887 assert(bus != main_system_bus); /* main_system_bus is never freed */
888 qemu_unregister_reset(qbus_reset_all_fn, bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200889 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500890 g_free((void*)bus->name);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200891 if (bus->qdev_allocated) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500892 g_free(bus);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200893 }
894}
895
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100896#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
897static void qbus_print(Monitor *mon, BusState *bus, int indent);
898
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200899static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
900 const char *prefix, int indent)
901{
902 char buf[64];
903
904 if (!props)
905 return;
906 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100907 /*
908 * TODO Properties without a print method are just for dirty
909 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
910 * marked for removal. The test props->info->print should be
911 * removed along with it.
912 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200913 if (props->info->print) {
914 props->info->print(dev, props, buf, sizeof(buf));
915 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
916 }
917 props++;
918 }
919}
920
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100921static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
922{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100923 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200924 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
925 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100926 indent += 2;
927 if (dev->num_gpio_in) {
928 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
929 }
930 if (dev->num_gpio_out) {
931 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
932 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200933 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
934 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200935 if (dev->parent_bus->info->print_dev)
936 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000937 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100938 qbus_print(mon, child, indent);
939 }
940}
941
942static void qbus_print(Monitor *mon, BusState *bus, int indent)
943{
944 struct DeviceState *dev;
945
946 qdev_printf("bus: %s\n", bus->name);
947 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200948 qdev_printf("type %s\n", bus->info->name);
Paolo Bonzinid8bb00d2011-09-14 09:28:06 +0200949 QTAILQ_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100950 qdev_print(mon, dev, indent);
951 }
952}
953#undef qdev_printf
954
955void do_info_qtree(Monitor *mon)
956{
957 if (main_system_bus)
958 qbus_print(mon, main_system_bus, 0);
959}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200960
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200961void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200962{
963 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200964
965 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100966 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200967 }
968}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200969
Markus Armbruster8bc27242010-02-10 20:52:01 +0100970int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200971{
972 QemuOpts *opts;
973
Gerd Hoffmann3329f072010-08-20 13:52:01 +0200974 opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100975 if (!opts) {
976 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +0100977 }
Markus Armbruster8bc27242010-02-10 20:52:01 +0100978 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
979 qemu_opts_del(opts);
980 return 0;
981 }
982 if (!qdev_device_add(opts)) {
983 qemu_opts_del(opts);
984 return -1;
985 }
986 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200987}
988
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100989int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200990{
991 const char *id = qdict_get_str(qdict, "id");
992 DeviceState *dev;
993
994 dev = qdev_find_recursive(main_system_bus, id);
995 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100996 qerror_report(QERR_DEVICE_NOT_FOUND, id);
997 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200998 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100999 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +02001000}
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001001
1002static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
1003{
1004 int l = 0;
1005
1006 if (dev && dev->parent_bus) {
1007 char *d;
1008 l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
1009 if (dev->parent_bus->info->get_fw_dev_path) {
1010 d = dev->parent_bus->info->get_fw_dev_path(dev);
1011 l += snprintf(p + l, size - l, "%s", d);
Anthony Liguori7267c092011-08-20 22:09:37 -05001012 g_free(d);
Gleb Natapov1ca4d092010-12-08 13:35:05 +02001013 } else {
1014 l += snprintf(p + l, size - l, "%s", dev->info->name);
1015 }
1016 }
1017 l += snprintf(p + l , size - l, "/");
1018
1019 return l;
1020}
1021
1022char* qdev_get_fw_dev_path(DeviceState *dev)
1023{
1024 char path[128];
1025 int l;
1026
1027 l = qdev_get_fw_dev_path_helper(dev, path, 128);
1028
1029 path[l-1] = '\0';
1030
1031 return strdup(path);
1032}
Anthony Liguori85ed3032011-12-12 14:29:25 -06001033
1034void qdev_ref(DeviceState *dev)
1035{
1036 dev->ref++;
1037}
1038
1039void qdev_unref(DeviceState *dev)
1040{
1041 g_assert(dev->ref > 0);
1042 dev->ref--;
1043}
Anthony Liguori44677de2011-12-12 14:29:26 -06001044
1045void qdev_property_add(DeviceState *dev, const char *name, const char *type,
1046 DevicePropertyAccessor *get, DevicePropertyAccessor *set,
1047 DevicePropertyRelease *release,
1048 void *opaque, Error **errp)
1049{
1050 DeviceProperty *prop = g_malloc0(sizeof(*prop));
1051
1052 prop->name = g_strdup(name);
1053 prop->type = g_strdup(type);
1054
1055 prop->get = get;
1056 prop->set = set;
1057 prop->release = release;
1058 prop->opaque = opaque;
1059
1060 QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
1061}
1062
1063static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
1064{
1065 DeviceProperty *prop;
1066
1067 QTAILQ_FOREACH(prop, &dev->properties, node) {
1068 if (strcmp(prop->name, name) == 0) {
1069 return prop;
1070 }
1071 }
1072
1073 return NULL;
1074}
1075
1076void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
1077 Error **errp)
1078{
1079 DeviceProperty *prop = qdev_property_find(dev, name);
1080
1081 if (prop == NULL) {
1082 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1083 return;
1084 }
1085
1086 if (!prop->get) {
1087 error_set(errp, QERR_PERMISSION_DENIED);
1088 } else {
1089 prop->get(dev, v, prop->opaque, name, errp);
1090 }
1091}
1092
1093void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
1094 Error **errp)
1095{
1096 DeviceProperty *prop = qdev_property_find(dev, name);
1097
1098 if (prop == NULL) {
1099 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1100 return;
1101 }
1102
1103 if (!prop->set) {
1104 error_set(errp, QERR_PERMISSION_DENIED);
1105 } else {
1106 prop->set(dev, prop->opaque, v, name, errp);
1107 }
1108}
1109
1110const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
1111{
1112 DeviceProperty *prop = qdev_property_find(dev, name);
1113
1114 if (prop == NULL) {
1115 error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
1116 return NULL;
1117 }
1118
1119 return prop->type;
1120}
Anthony Liguoria5296ca2011-12-12 14:29:27 -06001121
1122/**
1123 * Legacy property handling
1124 */
1125
1126static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1127 const char *name, Error **errp)
1128{
1129 Property *prop = opaque;
1130
1131 if (prop->info->print) {
1132 char buffer[1024];
1133 char *ptr = buffer;
1134
1135 prop->info->print(dev, prop, buffer, sizeof(buffer));
1136 visit_type_str(v, &ptr, name, errp);
1137 } else {
1138 error_set(errp, QERR_PERMISSION_DENIED);
1139 }
1140}
1141
1142static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
1143 const char *name, Error **errp)
1144{
1145 Property *prop = opaque;
1146
1147 if (dev->state != DEV_STATE_CREATED) {
1148 error_set(errp, QERR_PERMISSION_DENIED);
1149 return;
1150 }
1151
1152 if (prop->info->parse) {
1153 Error *local_err = NULL;
1154 char *ptr = NULL;
1155
1156 visit_type_str(v, &ptr, name, &local_err);
1157 if (!local_err) {
1158 int ret;
1159 ret = prop->info->parse(dev, prop, ptr);
1160 if (ret != 0) {
1161 error_set(errp, QERR_INVALID_PARAMETER_VALUE,
1162 name, prop->info->name);
1163 }
1164 g_free(ptr);
1165 } else {
1166 error_propagate(errp, local_err);
1167 }
1168 } else {
1169 error_set(errp, QERR_PERMISSION_DENIED);
1170 }
1171}
1172
1173/**
1174 * @qdev_add_legacy_property - adds a legacy property
1175 *
1176 * Do not use this is new code! Properties added through this interface will
1177 * be given types in the "legacy<>" type namespace.
1178 *
1179 * Legacy properties are always processed as strings. The format of the string
1180 * depends on the property type.
1181 */
1182void qdev_property_add_legacy(DeviceState *dev, Property *prop,
1183 Error **errp)
1184{
1185 gchar *type;
1186
1187 type = g_strdup_printf("legacy<%s>", prop->info->name);
1188
1189 qdev_property_add(dev, prop->name, type,
1190 qdev_get_legacy_property,
1191 qdev_set_legacy_property,
1192 NULL,
1193 prop, errp);
1194
1195 g_free(type);
1196}
Anthony Liguoria10f07a2011-12-12 14:29:28 -06001197
1198DeviceState *qdev_get_root(void)
1199{
1200 static DeviceState *qdev_root;
1201
1202 if (!qdev_root) {
1203 qdev_root = qdev_create(NULL, "container");
1204 qdev_init_nofail(qdev_root);
1205 }
1206
1207 return qdev_root;
1208}
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001209
Anthony Liguori3de1c3e2011-12-12 14:29:31 -06001210static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
1211 const char *name, Error **errp)
1212{
1213 DeviceState *child = opaque;
1214 gchar *path;
1215
1216 path = qdev_get_canonical_path(child);
1217 visit_type_str(v, &path, name, errp);
1218 g_free(path);
1219}
1220
1221void qdev_property_add_child(DeviceState *dev, const char *name,
1222 DeviceState *child, Error **errp)
1223{
1224 gchar *type;
1225
1226 type = g_strdup_printf("child<%s>", child->info->name);
1227
1228 qdev_property_add(dev, name, type, qdev_get_child_property,
1229 NULL, NULL, child, errp);
1230
1231 qdev_ref(child);
1232
1233 g_free(type);
1234}
1235
Anthony Liguori83e94fb2011-12-12 14:29:32 -06001236static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
1237 const char *name, Error **errp)
1238{
1239 DeviceState **child = opaque;
1240 gchar *path;
1241
1242 if (*child) {
1243 path = qdev_get_canonical_path(*child);
1244 visit_type_str(v, &path, name, errp);
1245 g_free(path);
1246 } else {
1247 path = (gchar *)"";
1248 visit_type_str(v, &path, name, errp);
1249 }
1250}
1251
1252static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
1253 const char *name, Error **errp)
1254{
1255 DeviceState **child = opaque;
1256 bool ambiguous = false;
1257 const char *type;
1258 char *path;
1259
1260 type = qdev_property_get_type(dev, name, NULL);
1261
1262 visit_type_str(v, &path, name, errp);
1263
1264 if (*child) {
1265 qdev_unref(*child);
1266 }
1267
1268 if (strcmp(path, "") != 0) {
1269 DeviceState *target;
1270
1271 target = qdev_resolve_path(path, &ambiguous);
1272 if (target) {
1273 gchar *target_type;
1274
1275 target_type = g_strdup_printf("link<%s>", target->info->name);
1276 if (strcmp(target_type, type) == 0) {
1277 *child = target;
1278 qdev_ref(target);
1279 } else {
1280 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
1281 }
1282
1283 g_free(target_type);
1284 } else {
1285 error_set(errp, QERR_DEVICE_NOT_FOUND, path);
1286 }
1287 } else {
1288 *child = NULL;
1289 }
1290
1291 g_free(path);
1292}
1293
1294void qdev_property_add_link(DeviceState *dev, const char *name,
1295 const char *type, DeviceState **child,
1296 Error **errp)
1297{
1298 gchar *full_type;
1299
1300 full_type = g_strdup_printf("link<%s>", type);
1301
1302 qdev_property_add(dev, name, full_type,
1303 qdev_get_link_property,
1304 qdev_set_link_property,
1305 NULL, child, errp);
1306
1307 g_free(full_type);
1308}
1309
Anthony Liguorif9fbd2f2011-12-12 14:29:29 -06001310static gchar *qdev_get_path_in(DeviceState *parent, DeviceState *dev)
1311{
1312 DeviceProperty *prop;
1313
1314 if (parent == dev) {
1315 return g_strdup("");
1316 }
1317
1318 QTAILQ_FOREACH(prop, &parent->properties, node) {
1319 gchar *subpath;
1320
1321 if (!strstart(prop->type, "child<", NULL)) {
1322 continue;
1323 }
1324
1325 /* Check to see if the device is one of parent's children */
1326 if (prop->opaque == dev) {
1327 return g_strdup(prop->name);
1328 }
1329
1330 /* Check to see if the device is a child of our child */
1331 subpath = qdev_get_path_in(prop->opaque, dev);
1332 if (subpath) {
1333 gchar *path;
1334
1335 path = g_strdup_printf("%s/%s", prop->name, subpath);
1336 g_free(subpath);
1337
1338 return path;
1339 }
1340 }
1341
1342 return NULL;
1343}
1344
1345gchar *qdev_get_canonical_path(DeviceState *dev)
1346{
1347 gchar *path, *newpath;
1348
1349 path = qdev_get_path_in(qdev_get_root(), dev);
1350 g_assert(path != NULL);
1351
1352 newpath = g_strdup_printf("/%s", path);
1353 g_free(path);
1354
1355 return newpath;
1356}
Anthony Liguoridc45c212011-12-12 14:29:30 -06001357
1358static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
1359 gchar **parts,
1360 int index)
1361{
1362 DeviceProperty *prop;
1363 DeviceState *child;
1364
1365 if (parts[index] == NULL) {
1366 return parent;
1367 }
1368
1369 if (strcmp(parts[index], "") == 0) {
1370 return qdev_resolve_abs_path(parent, parts, index + 1);
1371 }
1372
1373 prop = qdev_property_find(parent, parts[index]);
1374 if (prop == NULL) {
1375 return NULL;
1376 }
1377
1378 child = NULL;
1379 if (strstart(prop->type, "link<", NULL)) {
1380 DeviceState **pchild = prop->opaque;
1381 if (*pchild) {
1382 child = *pchild;
1383 }
1384 } else if (strstart(prop->type, "child<", NULL)) {
1385 child = prop->opaque;
1386 }
1387
1388 if (!child) {
1389 return NULL;
1390 }
1391
1392 return qdev_resolve_abs_path(child, parts, index + 1);
1393}
1394
1395static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
1396 gchar **parts,
1397 bool *ambiguous)
1398{
1399 DeviceState *dev;
1400 DeviceProperty *prop;
1401
1402 dev = qdev_resolve_abs_path(parent, parts, 0);
1403
1404 QTAILQ_FOREACH(prop, &parent->properties, node) {
1405 DeviceState *found;
1406
1407 if (!strstart(prop->type, "child<", NULL)) {
1408 continue;
1409 }
1410
1411 found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
1412 if (found) {
1413 if (dev) {
1414 if (ambiguous) {
1415 *ambiguous = true;
1416 }
1417 return NULL;
1418 }
1419 dev = found;
1420 }
1421
1422 if (ambiguous && *ambiguous) {
1423 return NULL;
1424 }
1425 }
1426
1427 return dev;
1428}
1429
1430DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
1431{
1432 bool partial_path = true;
1433 DeviceState *dev;
1434 gchar **parts;
1435
1436 parts = g_strsplit(path, "/", 0);
1437 if (parts == NULL || parts[0] == NULL) {
1438 g_strfreev(parts);
1439 return qdev_get_root();
1440 }
1441
1442 if (strcmp(parts[0], "") == 0) {
1443 partial_path = false;
1444 }
1445
1446 if (partial_path) {
1447 if (ambiguous) {
1448 *ambiguous = false;
1449 }
1450 dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
1451 } else {
1452 dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
1453 }
1454
1455 g_strfreev(parts);
1456
1457 return dev;
1458}
1459