blob: 8bf86a5f1f2a2edc007da36a4eece111cd4aaa8b [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);
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) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100211 error_report("Did not find %s bus for %s",
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) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100216 error_report("Bus %s does not support hotplugging",
217 bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200218 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) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100232 error_report("Error initializing device %s", 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) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100271 error_report("Bus %s does not support hotplugging",
272 dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200273 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
Markus Armbruster53db16b2010-02-18 18:55:59 +0100459static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200460{
461 BusState *child;
462 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200463
Markus Armbruster53db16b2010-02-18 18:55:59 +0100464 error_printf("child busses at \"%s\":",
465 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000466 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100467 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200468 sep = ", ";
469 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100470 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200471}
472
Markus Armbruster53db16b2010-02-18 18:55:59 +0100473static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200474{
475 DeviceState *dev;
476 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200477
Markus Armbruster53db16b2010-02-18 18:55:59 +0100478 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000479 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100480 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200481 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100482 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200483 sep = ", ";
484 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100485 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200486}
487
488static BusState *qbus_find_bus(DeviceState *dev, char *elem)
489{
490 BusState *child;
491
Blue Swirl72cf2d42009-09-12 07:36:22 +0000492 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200493 if (strcmp(child->name, elem) == 0) {
494 return child;
495 }
496 }
497 return NULL;
498}
499
500static DeviceState *qbus_find_dev(BusState *bus, char *elem)
501{
502 DeviceState *dev;
503
504 /*
505 * try to match in order:
506 * (1) instance id, if present
507 * (2) driver name
508 * (3) driver alias, if present
509 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000510 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200511 if (dev->id && strcmp(dev->id, elem) == 0) {
512 return dev;
513 }
514 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000515 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200516 if (strcmp(dev->info->name, 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 (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
522 return dev;
523 }
524 }
525 return NULL;
526}
527
528static BusState *qbus_find(const char *path)
529{
530 DeviceState *dev;
531 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100532 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200533 int pos, len;
534
535 /* find start element */
536 if (path[0] == '/') {
537 bus = main_system_bus;
538 pos = 0;
539 } else {
540 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100541 error_report("path parse error (\"%s\")", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200542 return NULL;
543 }
544 bus = qbus_find_recursive(main_system_bus, elem, NULL);
545 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100546 error_report("bus \"%s\" not found", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200547 return NULL;
548 }
549 pos = len;
550 }
551
552 for (;;) {
553 if (path[pos] == '\0') {
554 /* we are done */
555 return bus;
556 }
557
558 /* find device */
559 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100560 error_report("path parse error (\"%s\" pos %d)", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200561 return NULL;
562 }
563 pos += len;
564 dev = qbus_find_dev(bus, elem);
565 if (!dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100566 error_report("device \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100567 qbus_list_dev(bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200568 return NULL;
569 }
570 if (path[pos] == '\0') {
571 /* last specified element is a device. If it has exactly
572 * one child bus accept it nevertheless */
573 switch (dev->num_child_bus) {
574 case 0:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100575 error_report("device has no child bus (%s)", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200576 return NULL;
577 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000578 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200579 default:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100580 error_report("device has multiple child busses (%s)", path);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100581 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200582 return NULL;
583 }
584 }
585
586 /* find bus */
587 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100588 error_report("path parse error (\"%s\" pos %d)", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200589 return NULL;
590 }
591 pos += len;
592 bus = qbus_find_bus(dev, elem);
593 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100594 error_report("child bus \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100595 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200596 return NULL;
597 }
598 }
599}
600
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200601void qbus_create_inplace(BusState *bus, BusInfo *info,
602 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100603{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200604 char *buf;
605 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100606
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200607 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100608 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200609
610 if (name) {
611 /* use supplied name */
612 bus->name = qemu_strdup(name);
613 } else if (parent && parent->id) {
614 /* parent device has id -> use it for bus name */
615 len = strlen(parent->id) + 16;
616 buf = qemu_malloc(len);
617 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
618 bus->name = buf;
619 } else {
620 /* no id -> use lowercase bus type for bus name */
621 len = strlen(info->name) + 16;
622 buf = qemu_malloc(len);
623 len = snprintf(buf, len, "%s.%d", info->name,
624 parent ? parent->num_child_bus : 0);
625 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200626 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200627 bus->name = buf;
628 }
629
Blue Swirl72cf2d42009-09-12 07:36:22 +0000630 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100631 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000632 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200633 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100634 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200635
636}
637
638BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
639{
640 BusState *bus;
641
642 bus = qemu_mallocz(info->size);
643 bus->qdev_allocated = 1;
644 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100645 return bus;
646}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100647
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200648void qbus_free(BusState *bus)
649{
650 DeviceState *dev;
651
652 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
653 qdev_free(dev);
654 }
655 if (bus->parent) {
656 QLIST_REMOVE(bus, sibling);
657 bus->parent->num_child_bus--;
658 }
659 if (bus->qdev_allocated) {
660 qemu_free(bus);
661 }
662}
663
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100664#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
665static void qbus_print(Monitor *mon, BusState *bus, int indent);
666
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200667static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
668 const char *prefix, int indent)
669{
670 char buf[64];
671
672 if (!props)
673 return;
674 while (props->name) {
675 if (props->info->print) {
676 props->info->print(dev, props, buf, sizeof(buf));
677 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
678 }
679 props++;
680 }
681}
682
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100683static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
684{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100685 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200686 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
687 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100688 indent += 2;
689 if (dev->num_gpio_in) {
690 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
691 }
692 if (dev->num_gpio_out) {
693 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
694 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200695 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
696 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200697 if (dev->parent_bus->info->print_dev)
698 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000699 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100700 qbus_print(mon, child, indent);
701 }
702}
703
704static void qbus_print(Monitor *mon, BusState *bus, int indent)
705{
706 struct DeviceState *dev;
707
708 qdev_printf("bus: %s\n", bus->name);
709 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200710 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000711 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100712 qdev_print(mon, dev, indent);
713 }
714}
715#undef qdev_printf
716
717void do_info_qtree(Monitor *mon)
718{
719 if (main_system_bus)
720 qbus_print(mon, main_system_bus, 0);
721}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200722
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200723void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200724{
725 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200726
727 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100728 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200729 }
730}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200731
732void do_device_add(Monitor *mon, const QDict *qdict)
733{
734 QemuOpts *opts;
735
736 opts = qemu_opts_parse(&qemu_device_opts,
737 qdict_get_str(qdict, "config"), "driver");
Kevin Wolf0f853a32010-02-16 13:12:38 +0100738 if (opts) {
739 if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) {
740 qemu_opts_del(opts);
741 }
742 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200743}
744
745void do_device_del(Monitor *mon, const QDict *qdict)
746{
747 const char *id = qdict_get_str(qdict, "id");
748 DeviceState *dev;
749
750 dev = qdev_find_recursive(main_system_bus, id);
751 if (NULL == dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100752 error_report("Device '%s' not found", id);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200753 return;
754 }
755 qdev_unplug(dev);
756}