blob: 3fe811f6323401da64baaf8aad79177ce7017e2a [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) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100142 error_report("can't set property \"%s\" to \"%s\" for \"%s\"",
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) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100187 error_report("-device: no driver specified");
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) {
Markus Armbrusterab5b0272010-03-02 18:15:09 +0100194 qerror_report(QERR_DEVICE_NOT_FOUND, driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200195 return NULL;
196 }
197 if (info->no_user) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100198 error_report("device \"%s\" can't be added via command line",
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);
Markus Armbruster327867b2010-02-19 19:08:45 +0100207 if (bus && bus->info != info->bus_info) {
208 error_report("Device '%s' can't go on a %s bus",
209 driver, bus->info->name);
210 return NULL;
211 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200212 } else {
213 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200214 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200215 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100216 error_report("Did not find %s bus for %s",
217 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200218 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200219 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200220 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100221 error_report("Bus %s does not support hotplugging",
222 bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200223 return NULL;
224 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200225
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200226 /* create device, set properties */
227 qdev = qdev_create(bus, driver);
228 id = qemu_opts_id(opts);
229 if (id) {
230 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200231 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200232 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
233 qdev_free(qdev);
234 return NULL;
235 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200236 if (qdev_init(qdev) < 0) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100237 error_report("Error initializing device %s", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200238 return NULL;
239 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200240 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200241 return qdev;
242}
243
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300244static void qdev_reset(void *opaque)
245{
246 DeviceState *dev = opaque;
247 if (dev->info->reset)
248 dev->info->reset(dev);
249}
250
Paul Brookaae94602009-05-14 22:35:06 +0100251/* Initialize a device. Device properties should be set before calling
252 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200253 calling this function.
254 On failure, destroy the device and return negative value.
255 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200256int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100257{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200258 int rc;
259
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200260 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200261 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200262 if (rc < 0) {
263 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200264 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200265 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300266 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200267 if (dev->info->vmsd)
268 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200269 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200270 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100271}
272
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200273int qdev_unplug(DeviceState *dev)
274{
275 if (!dev->parent_bus->allow_hotplug) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100276 error_report("Bus %s does not support hotplugging",
277 dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200278 return -1;
279 }
Amit Shah593831d2009-11-02 14:56:41 +0530280 assert(dev->info->unplug != NULL);
281
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200282 return dev->info->unplug(dev);
283}
284
285/* can be used as ->unplug() callback for the simple cases */
286int qdev_simple_unplug_cb(DeviceState *dev)
287{
288 /* just zap it */
289 qdev_free(dev);
290 return 0;
291}
292
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200293/* Like qdev_init(), but terminate program via hw_error() instead of
294 returning an error value. This is okay during machine creation.
295 Don't use for hotplug, because there callers need to recover from
296 failure. Exception: if you know the device's init() callback can't
297 fail, then qdev_init_nofail() can't fail either, and is therefore
298 usable even then. But relying on the device implementation that
299 way is somewhat unclean, and best avoided. */
300void qdev_init_nofail(DeviceState *dev)
301{
302 DeviceInfo *info = dev->info;
303
304 if (qdev_init(dev) < 0)
305 hw_error("Initialization of device %s failed\n", info->name);
306}
307
Paul Brook02e2da42009-05-23 00:05:19 +0100308/* Unlink device from bus and free the structure. */
309void qdev_free(DeviceState *dev)
310{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200311 BusState *bus;
312
313 if (dev->state == DEV_STATE_INITIALIZED) {
314 while (dev->num_child_bus) {
315 bus = QLIST_FIRST(&dev->child_bus);
316 qbus_free(bus);
317 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200318 if (dev->info->vmsd)
319 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200320 if (dev->info->exit)
321 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200322 if (dev->opts)
323 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200324 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300325 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000326 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200327 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100328}
329
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200330void qdev_machine_creation_done(void)
331{
332 /*
333 * ok, initial machine setup is done, starting from now we can
334 * only create hotpluggable devices
335 */
336 qdev_hotplug = 1;
337}
338
Paul Brookaae94602009-05-14 22:35:06 +0100339/* Get a character (serial) device interface. */
340CharDriverState *qdev_init_chardev(DeviceState *dev)
341{
342 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530343
344 /* FIXME: This function needs to go away: use chardev properties! */
345 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100346}
347
Paul Brook02e2da42009-05-23 00:05:19 +0100348BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100349{
Paul Brook02e2da42009-05-23 00:05:19 +0100350 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100351}
352
Paul Brookaae94602009-05-14 22:35:06 +0100353void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
354{
355 assert(dev->num_gpio_in == 0);
356 dev->num_gpio_in = n;
357 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
358}
359
360void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
361{
362 assert(dev->num_gpio_out == 0);
363 dev->num_gpio_out = n;
364 dev->gpio_out = pins;
365}
366
367qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
368{
369 assert(n >= 0 && n < dev->num_gpio_in);
370 return dev->gpio_in[n];
371}
372
373void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
374{
375 assert(n >= 0 && n < dev->num_gpio_out);
376 dev->gpio_out[n] = pin;
377}
378
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200379void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
380{
381 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
382 if (nd->vlan)
383 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
384 if (nd->netdev)
385 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530386 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200387 qdev_prop_exists(dev, "vectors")) {
388 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
389 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200390}
391
Paul Brookaae94602009-05-14 22:35:06 +0100392static int next_block_unit[IF_COUNT];
393
394/* Get a block device. This should only be used for single-drive devices
395 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
396 appropriate bus. */
397BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
398{
399 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200400 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100401
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200402 dinfo = drive_get(type, 0, unit);
403 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100404}
Paul Brook4d6ae672009-05-14 22:35:06 +0100405
Paul Brook02e2da42009-05-23 00:05:19 +0100406BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100407{
Paul Brook02e2da42009-05-23 00:05:19 +0100408 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100409
Blue Swirl72cf2d42009-09-12 07:36:22 +0000410 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100411 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100412 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100413 }
414 }
415 return NULL;
416}
417
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200418static BusState *qbus_find_recursive(BusState *bus, const char *name,
419 const BusInfo *info)
420{
421 DeviceState *dev;
422 BusState *child, *ret;
423 int match = 1;
424
425 if (name && (strcmp(bus->name, name) != 0)) {
426 match = 0;
427 }
428 if (info && (bus->info != info)) {
429 match = 0;
430 }
431 if (match) {
432 return bus;
433 }
434
Blue Swirl72cf2d42009-09-12 07:36:22 +0000435 QLIST_FOREACH(dev, &bus->children, sibling) {
436 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200437 ret = qbus_find_recursive(child, name, info);
438 if (ret) {
439 return ret;
440 }
441 }
442 }
443 return NULL;
444}
445
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200446static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
447{
448 DeviceState *dev, *ret;
449 BusState *child;
450
451 QLIST_FOREACH(dev, &bus->children, sibling) {
452 if (dev->id && strcmp(dev->id, id) == 0)
453 return dev;
454 QLIST_FOREACH(child, &dev->child_bus, sibling) {
455 ret = qdev_find_recursive(child, id);
456 if (ret) {
457 return ret;
458 }
459 }
460 }
461 return NULL;
462}
463
Markus Armbruster53db16b2010-02-18 18:55:59 +0100464static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200465{
466 BusState *child;
467 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200468
Markus Armbruster53db16b2010-02-18 18:55:59 +0100469 error_printf("child busses at \"%s\":",
470 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000471 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100472 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200473 sep = ", ";
474 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100475 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200476}
477
Markus Armbruster53db16b2010-02-18 18:55:59 +0100478static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200479{
480 DeviceState *dev;
481 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200482
Markus Armbruster53db16b2010-02-18 18:55:59 +0100483 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000484 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100485 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200486 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100487 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200488 sep = ", ";
489 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100490 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200491}
492
493static BusState *qbus_find_bus(DeviceState *dev, char *elem)
494{
495 BusState *child;
496
Blue Swirl72cf2d42009-09-12 07:36:22 +0000497 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200498 if (strcmp(child->name, elem) == 0) {
499 return child;
500 }
501 }
502 return NULL;
503}
504
505static DeviceState *qbus_find_dev(BusState *bus, char *elem)
506{
507 DeviceState *dev;
508
509 /*
510 * try to match in order:
511 * (1) instance id, if present
512 * (2) driver name
513 * (3) driver alias, if present
514 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000515 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200516 if (dev->id && strcmp(dev->id, elem) == 0) {
517 return dev;
518 }
519 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000520 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200521 if (strcmp(dev->info->name, elem) == 0) {
522 return dev;
523 }
524 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000525 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200526 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
527 return dev;
528 }
529 }
530 return NULL;
531}
532
533static BusState *qbus_find(const char *path)
534{
535 DeviceState *dev;
536 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100537 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200538 int pos, len;
539
540 /* find start element */
541 if (path[0] == '/') {
542 bus = main_system_bus;
543 pos = 0;
544 } else {
545 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100546 error_report("path parse error (\"%s\")", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200547 return NULL;
548 }
549 bus = qbus_find_recursive(main_system_bus, elem, NULL);
550 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100551 error_report("bus \"%s\" not found", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200552 return NULL;
553 }
554 pos = len;
555 }
556
557 for (;;) {
558 if (path[pos] == '\0') {
559 /* we are done */
560 return bus;
561 }
562
563 /* find device */
564 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100565 error_report("path parse error (\"%s\" pos %d)", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200566 return NULL;
567 }
568 pos += len;
569 dev = qbus_find_dev(bus, elem);
570 if (!dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100571 error_report("device \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100572 qbus_list_dev(bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200573 return NULL;
574 }
575 if (path[pos] == '\0') {
576 /* last specified element is a device. If it has exactly
577 * one child bus accept it nevertheless */
578 switch (dev->num_child_bus) {
579 case 0:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100580 error_report("device has no child bus (%s)", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200581 return NULL;
582 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000583 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200584 default:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100585 error_report("device has multiple child busses (%s)", path);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100586 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200587 return NULL;
588 }
589 }
590
591 /* find bus */
592 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100593 error_report("path parse error (\"%s\" pos %d)", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200594 return NULL;
595 }
596 pos += len;
597 bus = qbus_find_bus(dev, elem);
598 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100599 error_report("child bus \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100600 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200601 return NULL;
602 }
603 }
604}
605
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200606void qbus_create_inplace(BusState *bus, BusInfo *info,
607 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100608{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200609 char *buf;
610 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100611
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200612 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100613 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200614
615 if (name) {
616 /* use supplied name */
617 bus->name = qemu_strdup(name);
618 } else if (parent && parent->id) {
619 /* parent device has id -> use it for bus name */
620 len = strlen(parent->id) + 16;
621 buf = qemu_malloc(len);
622 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
623 bus->name = buf;
624 } else {
625 /* no id -> use lowercase bus type for bus name */
626 len = strlen(info->name) + 16;
627 buf = qemu_malloc(len);
628 len = snprintf(buf, len, "%s.%d", info->name,
629 parent ? parent->num_child_bus : 0);
630 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200631 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200632 bus->name = buf;
633 }
634
Blue Swirl72cf2d42009-09-12 07:36:22 +0000635 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100636 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000637 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200638 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100639 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200640
641}
642
643BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
644{
645 BusState *bus;
646
647 bus = qemu_mallocz(info->size);
648 bus->qdev_allocated = 1;
649 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100650 return bus;
651}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100652
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200653void qbus_free(BusState *bus)
654{
655 DeviceState *dev;
656
657 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
658 qdev_free(dev);
659 }
660 if (bus->parent) {
661 QLIST_REMOVE(bus, sibling);
662 bus->parent->num_child_bus--;
663 }
664 if (bus->qdev_allocated) {
665 qemu_free(bus);
666 }
667}
668
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100669#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
670static void qbus_print(Monitor *mon, BusState *bus, int indent);
671
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200672static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
673 const char *prefix, int indent)
674{
675 char buf[64];
676
677 if (!props)
678 return;
679 while (props->name) {
680 if (props->info->print) {
681 props->info->print(dev, props, buf, sizeof(buf));
682 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
683 }
684 props++;
685 }
686}
687
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100688static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
689{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100690 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200691 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
692 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100693 indent += 2;
694 if (dev->num_gpio_in) {
695 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
696 }
697 if (dev->num_gpio_out) {
698 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
699 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200700 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
701 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200702 if (dev->parent_bus->info->print_dev)
703 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000704 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100705 qbus_print(mon, child, indent);
706 }
707}
708
709static void qbus_print(Monitor *mon, BusState *bus, int indent)
710{
711 struct DeviceState *dev;
712
713 qdev_printf("bus: %s\n", bus->name);
714 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200715 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000716 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100717 qdev_print(mon, dev, indent);
718 }
719}
720#undef qdev_printf
721
722void do_info_qtree(Monitor *mon)
723{
724 if (main_system_bus)
725 qbus_print(mon, main_system_bus, 0);
726}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200727
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200728void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200729{
730 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200731
732 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100733 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200734 }
735}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200736
737void do_device_add(Monitor *mon, const QDict *qdict)
738{
739 QemuOpts *opts;
740
741 opts = qemu_opts_parse(&qemu_device_opts,
742 qdict_get_str(qdict, "config"), "driver");
Kevin Wolf0f853a32010-02-16 13:12:38 +0100743 if (opts) {
744 if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) {
745 qemu_opts_del(opts);
746 }
747 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200748}
749
750void do_device_del(Monitor *mon, const QDict *qdict)
751{
752 const char *id = qdict_get_str(qdict, "id");
753 DeviceState *dev;
754
755 dev = qdev_find_recursive(main_system_bus, id);
756 if (NULL == dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100757 error_report("Device '%s' not found", id);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200758 return;
759 }
760 qdev_unplug(dev);
761}