blob: d7d5fb946ac715ab2b2a40e9da836220831b463b [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"
Luiz Capitulino3ced9f72009-11-18 23:05:33 -020032#include "qerror.h"
Paul Brookaae94602009-05-14 22:35:06 +010033
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020034static int qdev_hotplug = 0;
35
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020036/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000037static BusState *main_system_bus;
Paul Brook4d6ae672009-05-14 22:35:06 +010038
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010039DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010040
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020041static BusState *qbus_find_recursive(BusState *bus, const char *name,
42 const BusInfo *info);
43static BusState *qbus_find(const char *path);
44
Paul Brookaae94602009-05-14 22:35:06 +010045/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020046void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010047{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020048 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020049 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010050
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020051 info->next = device_info_list;
52 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010053}
54
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020055static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
56{
57 DeviceInfo *info;
58
Gerd Hoffmann3320e562009-07-15 13:43:33 +020059 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020060 for (info = device_info_list; info != NULL; info = info->next) {
61 if (bus_info && info->bus_info != bus_info)
62 continue;
63 if (strcmp(info->name, name) != 0)
64 continue;
65 return info;
66 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020067
68 /* failing that check the aliases */
69 for (info = device_info_list; info != NULL; info = info->next) {
70 if (bus_info && info->bus_info != bus_info)
71 continue;
72 if (!info->alias)
73 continue;
74 if (strcmp(info->alias, name) != 0)
75 continue;
76 return info;
77 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020078 return NULL;
79}
80
Paul Brookaae94602009-05-14 22:35:06 +010081/* Create a new device. This only initializes the device state structure
82 and allows properties to be set. qdev_init should be called to
83 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010084DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010085{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020086 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010087 DeviceState *dev;
88
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020089 if (!bus) {
90 if (!main_system_bus) {
91 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010092 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020093 bus = main_system_bus;
94 }
95
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020096 info = qdev_find_info(bus->info, name);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020097 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020098 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010099 }
100
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200101 dev = qemu_mallocz(info->size);
102 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100103 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200104 qdev_prop_set_defaults(dev, dev->info->props);
105 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +0100106 qdev_prop_set_globals(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000107 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200108 if (qdev_hotplug) {
109 assert(bus->allow_hotplug);
110 dev->hotplugged = 1;
111 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200112 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +0100113 return dev;
114}
115
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100116static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200117{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100118 error_printf("name \"%s\", bus %s",
119 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200120 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100121 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200122 }
123 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100124 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200125 }
126 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100127 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200128 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100129 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200130}
131
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200132static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200133{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200134 DeviceState *dev = opaque;
135
136 if (strcmp(name, "driver") == 0)
137 return 0;
138 if (strcmp(name, "bus") == 0)
139 return 0;
140
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100141 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200142 qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
143 name, value, dev->info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200144 return -1;
145 }
146 return 0;
147}
148
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100149int qdev_device_help(QemuOpts *opts)
150{
151 const char *driver;
152 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100153 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100154
155 driver = qemu_opt_get(opts, "driver");
156 if (driver && !strcmp(driver, "?")) {
157 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100158 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100159 }
160 return 1;
161 }
162
Markus Armbruster08350cf2010-01-29 19:49:00 +0100163 if (!qemu_opt_get(opts, "?")) {
164 return 0;
165 }
166
167 info = qdev_find_info(NULL, driver);
168 if (!info) {
169 return 0;
170 }
171
172 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100173 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100174 }
175 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100176}
177
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200178DeviceState *qdev_device_add(QemuOpts *opts)
179{
180 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200181 DeviceInfo *info;
182 DeviceState *qdev;
183 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200184
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200185 driver = qemu_opt_get(opts, "driver");
186 if (!driver) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200187 qemu_error("-device: no driver specified\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200188 return NULL;
189 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200190
191 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200192 info = qdev_find_info(NULL, driver);
193 if (!info) {
Luiz Capitulino3ced9f72009-11-18 23:05:33 -0200194 qemu_error_new(QERR_DEVICE_NOT_FOUND, driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200195 return NULL;
196 }
197 if (info->no_user) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200198 qemu_error("device \"%s\" can't be added via command line\n",
199 info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200200 return NULL;
201 }
202
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200203 /* find bus */
204 path = qemu_opt_get(opts, "bus");
205 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200206 bus = qbus_find(path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200207 } else {
208 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200209 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200210 if (!bus) {
211 qemu_error("Did not find %s bus for %s\n",
212 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200213 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200214 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200215 if (qdev_hotplug && !bus->allow_hotplug) {
216 qemu_error("Bus %s does not support hotplugging\n",
217 bus->name);
218 return NULL;
219 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200220
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200221 /* create device, set properties */
222 qdev = qdev_create(bus, driver);
223 id = qemu_opts_id(opts);
224 if (id) {
225 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200226 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200227 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
228 qdev_free(qdev);
229 return NULL;
230 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200231 if (qdev_init(qdev) < 0) {
Amit Shahc8cd1fc2009-09-29 15:51:03 +0530232 qemu_error("Error initializing device %s\n", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200233 return NULL;
234 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200235 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200236 return qdev;
237}
238
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300239static void qdev_reset(void *opaque)
240{
241 DeviceState *dev = opaque;
242 if (dev->info->reset)
243 dev->info->reset(dev);
244}
245
Paul Brookaae94602009-05-14 22:35:06 +0100246/* Initialize a device. Device properties should be set before calling
247 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200248 calling this function.
249 On failure, destroy the device and return negative value.
250 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200251int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100252{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200253 int rc;
254
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200255 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200256 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200257 if (rc < 0) {
258 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200259 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200260 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300261 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200262 if (dev->info->vmsd)
263 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200264 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200265 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100266}
267
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200268int qdev_unplug(DeviceState *dev)
269{
270 if (!dev->parent_bus->allow_hotplug) {
271 qemu_error("Bus %s does not support hotplugging\n",
272 dev->parent_bus->name);
273 return -1;
274 }
Amit Shah593831d2009-11-02 14:56:41 +0530275 assert(dev->info->unplug != NULL);
276
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200277 return dev->info->unplug(dev);
278}
279
280/* can be used as ->unplug() callback for the simple cases */
281int qdev_simple_unplug_cb(DeviceState *dev)
282{
283 /* just zap it */
284 qdev_free(dev);
285 return 0;
286}
287
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200288/* Like qdev_init(), but terminate program via hw_error() instead of
289 returning an error value. This is okay during machine creation.
290 Don't use for hotplug, because there callers need to recover from
291 failure. Exception: if you know the device's init() callback can't
292 fail, then qdev_init_nofail() can't fail either, and is therefore
293 usable even then. But relying on the device implementation that
294 way is somewhat unclean, and best avoided. */
295void qdev_init_nofail(DeviceState *dev)
296{
297 DeviceInfo *info = dev->info;
298
299 if (qdev_init(dev) < 0)
300 hw_error("Initialization of device %s failed\n", info->name);
301}
302
Paul Brook02e2da42009-05-23 00:05:19 +0100303/* Unlink device from bus and free the structure. */
304void qdev_free(DeviceState *dev)
305{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200306 BusState *bus;
307
308 if (dev->state == DEV_STATE_INITIALIZED) {
309 while (dev->num_child_bus) {
310 bus = QLIST_FIRST(&dev->child_bus);
311 qbus_free(bus);
312 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200313 if (dev->info->vmsd)
314 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200315 if (dev->info->exit)
316 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200317 if (dev->opts)
318 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200319 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300320 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000321 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200322 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100323}
324
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200325void qdev_machine_creation_done(void)
326{
327 /*
328 * ok, initial machine setup is done, starting from now we can
329 * only create hotpluggable devices
330 */
331 qdev_hotplug = 1;
332}
333
Paul Brookaae94602009-05-14 22:35:06 +0100334/* Get a character (serial) device interface. */
335CharDriverState *qdev_init_chardev(DeviceState *dev)
336{
337 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530338
339 /* FIXME: This function needs to go away: use chardev properties! */
340 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100341}
342
Paul Brook02e2da42009-05-23 00:05:19 +0100343BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100344{
Paul Brook02e2da42009-05-23 00:05:19 +0100345 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100346}
347
Paul Brookaae94602009-05-14 22:35:06 +0100348void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
349{
350 assert(dev->num_gpio_in == 0);
351 dev->num_gpio_in = n;
352 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
353}
354
355void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
356{
357 assert(dev->num_gpio_out == 0);
358 dev->num_gpio_out = n;
359 dev->gpio_out = pins;
360}
361
362qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
363{
364 assert(n >= 0 && n < dev->num_gpio_in);
365 return dev->gpio_in[n];
366}
367
368void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
369{
370 assert(n >= 0 && n < dev->num_gpio_out);
371 dev->gpio_out[n] = pin;
372}
373
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200374void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
375{
376 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
377 if (nd->vlan)
378 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
379 if (nd->netdev)
380 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530381 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200382 qdev_prop_exists(dev, "vectors")) {
383 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
384 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200385}
386
Paul Brookaae94602009-05-14 22:35:06 +0100387static int next_block_unit[IF_COUNT];
388
389/* Get a block device. This should only be used for single-drive devices
390 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
391 appropriate bus. */
392BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
393{
394 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200395 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100396
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200397 dinfo = drive_get(type, 0, unit);
398 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100399}
Paul Brook4d6ae672009-05-14 22:35:06 +0100400
Paul Brook02e2da42009-05-23 00:05:19 +0100401BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100402{
Paul Brook02e2da42009-05-23 00:05:19 +0100403 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100404
Blue Swirl72cf2d42009-09-12 07:36:22 +0000405 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100406 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100407 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100408 }
409 }
410 return NULL;
411}
412
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200413static BusState *qbus_find_recursive(BusState *bus, const char *name,
414 const BusInfo *info)
415{
416 DeviceState *dev;
417 BusState *child, *ret;
418 int match = 1;
419
420 if (name && (strcmp(bus->name, name) != 0)) {
421 match = 0;
422 }
423 if (info && (bus->info != info)) {
424 match = 0;
425 }
426 if (match) {
427 return bus;
428 }
429
Blue Swirl72cf2d42009-09-12 07:36:22 +0000430 QLIST_FOREACH(dev, &bus->children, sibling) {
431 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200432 ret = qbus_find_recursive(child, name, info);
433 if (ret) {
434 return ret;
435 }
436 }
437 }
438 return NULL;
439}
440
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200441static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
442{
443 DeviceState *dev, *ret;
444 BusState *child;
445
446 QLIST_FOREACH(dev, &bus->children, sibling) {
447 if (dev->id && strcmp(dev->id, id) == 0)
448 return dev;
449 QLIST_FOREACH(child, &dev->child_bus, sibling) {
450 ret = qdev_find_recursive(child, id);
451 if (ret) {
452 return ret;
453 }
454 }
455 }
456 return NULL;
457}
458
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200459static void qbus_list_bus(DeviceState *dev, char *dest, int len)
460{
461 BusState *child;
462 const char *sep = " ";
463 int pos = 0;
464
465 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
466 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000467 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200468 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
469 sep = ", ";
470 }
471}
472
473static void qbus_list_dev(BusState *bus, char *dest, int len)
474{
475 DeviceState *dev;
476 const char *sep = " ";
477 int pos = 0;
478
479 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
480 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000481 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200482 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
483 sep, dev->info->name);
484 if (dev->id)
485 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
486 sep = ", ";
487 }
488}
489
490static BusState *qbus_find_bus(DeviceState *dev, char *elem)
491{
492 BusState *child;
493
Blue Swirl72cf2d42009-09-12 07:36:22 +0000494 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200495 if (strcmp(child->name, elem) == 0) {
496 return child;
497 }
498 }
499 return NULL;
500}
501
502static DeviceState *qbus_find_dev(BusState *bus, char *elem)
503{
504 DeviceState *dev;
505
506 /*
507 * try to match in order:
508 * (1) instance id, if present
509 * (2) driver name
510 * (3) driver alias, if present
511 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000512 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200513 if (dev->id && strcmp(dev->id, elem) == 0) {
514 return dev;
515 }
516 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000517 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200518 if (strcmp(dev->info->name, elem) == 0) {
519 return dev;
520 }
521 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000522 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200523 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
524 return dev;
525 }
526 }
527 return NULL;
528}
529
530static BusState *qbus_find(const char *path)
531{
532 DeviceState *dev;
533 BusState *bus;
534 char elem[128], msg[256];
535 int pos, len;
536
537 /* find start element */
538 if (path[0] == '/') {
539 bus = main_system_bus;
540 pos = 0;
541 } else {
542 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200543 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200544 return NULL;
545 }
546 bus = qbus_find_recursive(main_system_bus, elem, NULL);
547 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200548 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200549 return NULL;
550 }
551 pos = len;
552 }
553
554 for (;;) {
555 if (path[pos] == '\0') {
556 /* we are done */
557 return bus;
558 }
559
560 /* find device */
561 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200562 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200563 return NULL;
564 }
565 pos += len;
566 dev = qbus_find_dev(bus, elem);
567 if (!dev) {
568 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200569 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200570 return NULL;
571 }
572 if (path[pos] == '\0') {
573 /* last specified element is a device. If it has exactly
574 * one child bus accept it nevertheless */
575 switch (dev->num_child_bus) {
576 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200577 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200578 return NULL;
579 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000580 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200581 default:
582 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200583 qemu_error("device has multiple child busses (%s)\n%s\n",
584 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200585 return NULL;
586 }
587 }
588
589 /* find bus */
590 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200591 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200592 return NULL;
593 }
594 pos += len;
595 bus = qbus_find_bus(dev, elem);
596 if (!bus) {
597 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200598 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200599 return NULL;
600 }
601 }
602}
603
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200604void qbus_create_inplace(BusState *bus, BusInfo *info,
605 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100606{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200607 char *buf;
608 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100609
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200610 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100611 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200612
613 if (name) {
614 /* use supplied name */
615 bus->name = qemu_strdup(name);
616 } else if (parent && parent->id) {
617 /* parent device has id -> use it for bus name */
618 len = strlen(parent->id) + 16;
619 buf = qemu_malloc(len);
620 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
621 bus->name = buf;
622 } else {
623 /* no id -> use lowercase bus type for bus name */
624 len = strlen(info->name) + 16;
625 buf = qemu_malloc(len);
626 len = snprintf(buf, len, "%s.%d", info->name,
627 parent ? parent->num_child_bus : 0);
628 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200629 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200630 bus->name = buf;
631 }
632
Blue Swirl72cf2d42009-09-12 07:36:22 +0000633 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100634 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000635 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200636 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100637 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200638
639}
640
641BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
642{
643 BusState *bus;
644
645 bus = qemu_mallocz(info->size);
646 bus->qdev_allocated = 1;
647 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100648 return bus;
649}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100650
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200651void qbus_free(BusState *bus)
652{
653 DeviceState *dev;
654
655 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
656 qdev_free(dev);
657 }
658 if (bus->parent) {
659 QLIST_REMOVE(bus, sibling);
660 bus->parent->num_child_bus--;
661 }
662 if (bus->qdev_allocated) {
663 qemu_free(bus);
664 }
665}
666
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100667#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
668static void qbus_print(Monitor *mon, BusState *bus, int indent);
669
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200670static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
671 const char *prefix, int indent)
672{
673 char buf[64];
674
675 if (!props)
676 return;
677 while (props->name) {
678 if (props->info->print) {
679 props->info->print(dev, props, buf, sizeof(buf));
680 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
681 }
682 props++;
683 }
684}
685
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100686static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
687{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100688 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200689 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
690 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100691 indent += 2;
692 if (dev->num_gpio_in) {
693 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
694 }
695 if (dev->num_gpio_out) {
696 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
697 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200698 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
699 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200700 if (dev->parent_bus->info->print_dev)
701 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000702 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100703 qbus_print(mon, child, indent);
704 }
705}
706
707static void qbus_print(Monitor *mon, BusState *bus, int indent)
708{
709 struct DeviceState *dev;
710
711 qdev_printf("bus: %s\n", bus->name);
712 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200713 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000714 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100715 qdev_print(mon, dev, indent);
716 }
717}
718#undef qdev_printf
719
720void do_info_qtree(Monitor *mon)
721{
722 if (main_system_bus)
723 qbus_print(mon, main_system_bus, 0);
724}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200725
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200726void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200727{
728 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200729
730 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100731 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200732 }
733}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200734
735void do_device_add(Monitor *mon, const QDict *qdict)
736{
737 QemuOpts *opts;
738
739 opts = qemu_opts_parse(&qemu_device_opts,
740 qdict_get_str(qdict, "config"), "driver");
Kevin Wolf0f853a32010-02-16 13:12:38 +0100741 if (opts) {
742 if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) {
743 qemu_opts_del(opts);
744 }
745 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200746}
747
748void do_device_del(Monitor *mon, const QDict *qdict)
749{
750 const char *id = qdict_get_str(qdict, "id");
751 DeviceState *dev;
752
753 dev = qdev_find_recursive(main_system_bus, id);
754 if (NULL == dev) {
755 qemu_error("Device '%s' not found\n", id);
756 return;
757 }
758 qdev_unplug(dev);
759}