blob: 875ca501b6f771259d43b1309ee0d8525cf34e13 [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 Hoffmannb6b61142009-07-15 13:48:21 +0200106 qdev_prop_set_compat(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
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200116static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
117{
118 int pos = 0;
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200119 int ret;
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200120
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200121 ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
122 info->name, info->bus_info->name);
123 pos += MIN(len-pos,ret);
124 if (info->alias) {
125 ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
126 pos += MIN(len-pos,ret);
127 }
128 if (info->desc) {
129 ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
130 pos += MIN(len-pos,ret);
131 }
132 if (info->no_user) {
133 ret = snprintf(dest+pos, len-pos, ", no-user");
134 pos += MIN(len-pos,ret);
135 }
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200136 return pos;
137}
138
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200139static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200140{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200141 DeviceState *dev = opaque;
142
143 if (strcmp(name, "driver") == 0)
144 return 0;
145 if (strcmp(name, "bus") == 0)
146 return 0;
147
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100148 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200149 qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
150 name, value, dev->info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200151 return -1;
152 }
153 return 0;
154}
155
156DeviceState *qdev_device_add(QemuOpts *opts)
157{
158 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200159 DeviceInfo *info;
160 DeviceState *qdev;
161 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200162
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200163 driver = qemu_opt_get(opts, "driver");
164 if (!driver) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200165 qemu_error("-device: no driver specified\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200166 return NULL;
167 }
168 if (strcmp(driver, "?") == 0) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200169 char msg[256];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200170 for (info = device_info_list; info != NULL; info = info->next) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200171 qdev_print_devinfo(info, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200172 qemu_error("%s\n", msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200173 }
174 return NULL;
175 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200176
177 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200178 info = qdev_find_info(NULL, driver);
179 if (!info) {
Luiz Capitulino3ced9f72009-11-18 23:05:33 -0200180 qemu_error_new(QERR_DEVICE_NOT_FOUND, driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200181 return NULL;
182 }
183 if (info->no_user) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200184 qemu_error("device \"%s\" can't be added via command line\n",
185 info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200186 return NULL;
187 }
188
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200189 /* find bus */
190 path = qemu_opt_get(opts, "bus");
191 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200192 bus = qbus_find(path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200193 } else {
194 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200195 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200196 if (!bus) {
197 qemu_error("Did not find %s bus for %s\n",
198 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200199 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200200 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200201 if (qdev_hotplug && !bus->allow_hotplug) {
202 qemu_error("Bus %s does not support hotplugging\n",
203 bus->name);
204 return NULL;
205 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200206
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200207 /* create device, set properties */
208 qdev = qdev_create(bus, driver);
209 id = qemu_opts_id(opts);
210 if (id) {
211 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200212 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200213 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
214 qdev_free(qdev);
215 return NULL;
216 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200217 if (qdev_init(qdev) < 0) {
Amit Shahc8cd1fc2009-09-29 15:51:03 +0530218 qemu_error("Error initializing device %s\n", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200219 return NULL;
220 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200221 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200222 return qdev;
223}
224
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300225static void qdev_reset(void *opaque)
226{
227 DeviceState *dev = opaque;
228 if (dev->info->reset)
229 dev->info->reset(dev);
230}
231
Paul Brookaae94602009-05-14 22:35:06 +0100232/* Initialize a device. Device properties should be set before calling
233 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200234 calling this function.
235 On failure, destroy the device and return negative value.
236 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200237int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100238{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200239 int rc;
240
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200241 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200242 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200243 if (rc < 0) {
244 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200245 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200246 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300247 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200248 if (dev->info->vmsd)
249 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200250 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200251 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100252}
253
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200254int qdev_unplug(DeviceState *dev)
255{
256 if (!dev->parent_bus->allow_hotplug) {
257 qemu_error("Bus %s does not support hotplugging\n",
258 dev->parent_bus->name);
259 return -1;
260 }
Amit Shah593831d2009-11-02 14:56:41 +0530261 assert(dev->info->unplug != NULL);
262
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200263 return dev->info->unplug(dev);
264}
265
266/* can be used as ->unplug() callback for the simple cases */
267int qdev_simple_unplug_cb(DeviceState *dev)
268{
269 /* just zap it */
270 qdev_free(dev);
271 return 0;
272}
273
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200274/* Like qdev_init(), but terminate program via hw_error() instead of
275 returning an error value. This is okay during machine creation.
276 Don't use for hotplug, because there callers need to recover from
277 failure. Exception: if you know the device's init() callback can't
278 fail, then qdev_init_nofail() can't fail either, and is therefore
279 usable even then. But relying on the device implementation that
280 way is somewhat unclean, and best avoided. */
281void qdev_init_nofail(DeviceState *dev)
282{
283 DeviceInfo *info = dev->info;
284
285 if (qdev_init(dev) < 0)
286 hw_error("Initialization of device %s failed\n", info->name);
287}
288
Paul Brook02e2da42009-05-23 00:05:19 +0100289/* Unlink device from bus and free the structure. */
290void qdev_free(DeviceState *dev)
291{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200292 BusState *bus;
293
294 if (dev->state == DEV_STATE_INITIALIZED) {
295 while (dev->num_child_bus) {
296 bus = QLIST_FIRST(&dev->child_bus);
297 qbus_free(bus);
298 }
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200299#if 0 /* FIXME: need sane vmstate_unregister function */
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200300 if (dev->info->vmsd)
301 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200302#endif
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200303 if (dev->info->exit)
304 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200305 if (dev->opts)
306 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200307 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300308 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000309 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200310 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100311}
312
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200313void qdev_machine_creation_done(void)
314{
315 /*
316 * ok, initial machine setup is done, starting from now we can
317 * only create hotpluggable devices
318 */
319 qdev_hotplug = 1;
320}
321
Paul Brookaae94602009-05-14 22:35:06 +0100322/* Get a character (serial) device interface. */
323CharDriverState *qdev_init_chardev(DeviceState *dev)
324{
325 static int next_serial;
326 static int next_virtconsole;
327 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200328 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100329 return virtcon_hds[next_virtconsole++];
330 } else {
331 return serial_hds[next_serial++];
332 }
333}
334
Paul Brook02e2da42009-05-23 00:05:19 +0100335BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100336{
Paul Brook02e2da42009-05-23 00:05:19 +0100337 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100338}
339
Paul Brookaae94602009-05-14 22:35:06 +0100340void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
341{
342 assert(dev->num_gpio_in == 0);
343 dev->num_gpio_in = n;
344 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
345}
346
347void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
348{
349 assert(dev->num_gpio_out == 0);
350 dev->num_gpio_out = n;
351 dev->gpio_out = pins;
352}
353
354qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
355{
356 assert(n >= 0 && n < dev->num_gpio_in);
357 return dev->gpio_in[n];
358}
359
360void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
361{
362 assert(n >= 0 && n < dev->num_gpio_out);
363 dev->gpio_out[n] = pin;
364}
365
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200366void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
367{
368 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
369 if (nd->vlan)
370 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
371 if (nd->netdev)
372 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200373 if (nd->nvectors != NIC_NVECTORS_UNSPECIFIED &&
374 qdev_prop_exists(dev, "vectors")) {
375 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
376 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200377}
378
Paul Brookaae94602009-05-14 22:35:06 +0100379static int next_block_unit[IF_COUNT];
380
381/* Get a block device. This should only be used for single-drive devices
382 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
383 appropriate bus. */
384BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
385{
386 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200387 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100388
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200389 dinfo = drive_get(type, 0, unit);
390 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100391}
Paul Brook4d6ae672009-05-14 22:35:06 +0100392
Paul Brook02e2da42009-05-23 00:05:19 +0100393BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100394{
Paul Brook02e2da42009-05-23 00:05:19 +0100395 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100396
Blue Swirl72cf2d42009-09-12 07:36:22 +0000397 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100398 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100399 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100400 }
401 }
402 return NULL;
403}
404
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200405static BusState *qbus_find_recursive(BusState *bus, const char *name,
406 const BusInfo *info)
407{
408 DeviceState *dev;
409 BusState *child, *ret;
410 int match = 1;
411
412 if (name && (strcmp(bus->name, name) != 0)) {
413 match = 0;
414 }
415 if (info && (bus->info != info)) {
416 match = 0;
417 }
418 if (match) {
419 return bus;
420 }
421
Blue Swirl72cf2d42009-09-12 07:36:22 +0000422 QLIST_FOREACH(dev, &bus->children, sibling) {
423 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200424 ret = qbus_find_recursive(child, name, info);
425 if (ret) {
426 return ret;
427 }
428 }
429 }
430 return NULL;
431}
432
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200433static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
434{
435 DeviceState *dev, *ret;
436 BusState *child;
437
438 QLIST_FOREACH(dev, &bus->children, sibling) {
439 if (dev->id && strcmp(dev->id, id) == 0)
440 return dev;
441 QLIST_FOREACH(child, &dev->child_bus, sibling) {
442 ret = qdev_find_recursive(child, id);
443 if (ret) {
444 return ret;
445 }
446 }
447 }
448 return NULL;
449}
450
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200451static void qbus_list_bus(DeviceState *dev, char *dest, int len)
452{
453 BusState *child;
454 const char *sep = " ";
455 int pos = 0;
456
457 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
458 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000459 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200460 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
461 sep = ", ";
462 }
463}
464
465static void qbus_list_dev(BusState *bus, char *dest, int len)
466{
467 DeviceState *dev;
468 const char *sep = " ";
469 int pos = 0;
470
471 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
472 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000473 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200474 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
475 sep, dev->info->name);
476 if (dev->id)
477 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
478 sep = ", ";
479 }
480}
481
482static BusState *qbus_find_bus(DeviceState *dev, char *elem)
483{
484 BusState *child;
485
Blue Swirl72cf2d42009-09-12 07:36:22 +0000486 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200487 if (strcmp(child->name, elem) == 0) {
488 return child;
489 }
490 }
491 return NULL;
492}
493
494static DeviceState *qbus_find_dev(BusState *bus, char *elem)
495{
496 DeviceState *dev;
497
498 /*
499 * try to match in order:
500 * (1) instance id, if present
501 * (2) driver name
502 * (3) driver alias, if present
503 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000504 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200505 if (dev->id && strcmp(dev->id, elem) == 0) {
506 return dev;
507 }
508 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000509 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200510 if (strcmp(dev->info->name, elem) == 0) {
511 return dev;
512 }
513 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000514 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200515 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
516 return dev;
517 }
518 }
519 return NULL;
520}
521
522static BusState *qbus_find(const char *path)
523{
524 DeviceState *dev;
525 BusState *bus;
526 char elem[128], msg[256];
527 int pos, len;
528
529 /* find start element */
530 if (path[0] == '/') {
531 bus = main_system_bus;
532 pos = 0;
533 } else {
534 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200535 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200536 return NULL;
537 }
538 bus = qbus_find_recursive(main_system_bus, elem, NULL);
539 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200540 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200541 return NULL;
542 }
543 pos = len;
544 }
545
546 for (;;) {
547 if (path[pos] == '\0') {
548 /* we are done */
549 return bus;
550 }
551
552 /* find device */
553 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200554 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200555 return NULL;
556 }
557 pos += len;
558 dev = qbus_find_dev(bus, elem);
559 if (!dev) {
560 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200561 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200562 return NULL;
563 }
564 if (path[pos] == '\0') {
565 /* last specified element is a device. If it has exactly
566 * one child bus accept it nevertheless */
567 switch (dev->num_child_bus) {
568 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200569 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200570 return NULL;
571 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000572 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200573 default:
574 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200575 qemu_error("device has multiple child busses (%s)\n%s\n",
576 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200577 return NULL;
578 }
579 }
580
581 /* find bus */
582 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200583 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200584 return NULL;
585 }
586 pos += len;
587 bus = qbus_find_bus(dev, elem);
588 if (!bus) {
589 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200590 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200591 return NULL;
592 }
593 }
594}
595
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200596void qbus_create_inplace(BusState *bus, BusInfo *info,
597 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100598{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200599 char *buf;
600 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100601
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200602 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100603 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200604
605 if (name) {
606 /* use supplied name */
607 bus->name = qemu_strdup(name);
608 } else if (parent && parent->id) {
609 /* parent device has id -> use it for bus name */
610 len = strlen(parent->id) + 16;
611 buf = qemu_malloc(len);
612 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
613 bus->name = buf;
614 } else {
615 /* no id -> use lowercase bus type for bus name */
616 len = strlen(info->name) + 16;
617 buf = qemu_malloc(len);
618 len = snprintf(buf, len, "%s.%d", info->name,
619 parent ? parent->num_child_bus : 0);
620 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200621 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200622 bus->name = buf;
623 }
624
Blue Swirl72cf2d42009-09-12 07:36:22 +0000625 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100626 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000627 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200628 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100629 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200630
631}
632
633BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
634{
635 BusState *bus;
636
637 bus = qemu_mallocz(info->size);
638 bus->qdev_allocated = 1;
639 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100640 return bus;
641}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100642
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200643void qbus_free(BusState *bus)
644{
645 DeviceState *dev;
646
647 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
648 qdev_free(dev);
649 }
650 if (bus->parent) {
651 QLIST_REMOVE(bus, sibling);
652 bus->parent->num_child_bus--;
653 }
654 if (bus->qdev_allocated) {
655 qemu_free(bus);
656 }
657}
658
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100659#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
660static void qbus_print(Monitor *mon, BusState *bus, int indent);
661
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200662static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
663 const char *prefix, int indent)
664{
665 char buf[64];
666
667 if (!props)
668 return;
669 while (props->name) {
670 if (props->info->print) {
671 props->info->print(dev, props, buf, sizeof(buf));
672 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
673 }
674 props++;
675 }
676}
677
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100678static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
679{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100680 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200681 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
682 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100683 indent += 2;
684 if (dev->num_gpio_in) {
685 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
686 }
687 if (dev->num_gpio_out) {
688 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
689 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200690 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
691 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200692 if (dev->parent_bus->info->print_dev)
693 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000694 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100695 qbus_print(mon, child, indent);
696 }
697}
698
699static void qbus_print(Monitor *mon, BusState *bus, int indent)
700{
701 struct DeviceState *dev;
702
703 qdev_printf("bus: %s\n", bus->name);
704 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200705 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000706 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100707 qdev_print(mon, dev, indent);
708 }
709}
710#undef qdev_printf
711
712void do_info_qtree(Monitor *mon)
713{
714 if (main_system_bus)
715 qbus_print(mon, main_system_bus, 0);
716}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200717
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200718void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200719{
720 DeviceInfo *info;
721 char msg[256];
722
723 for (info = device_info_list; info != NULL; info = info->next) {
724 qdev_print_devinfo(info, msg, sizeof(msg));
725 monitor_printf(mon, "%s\n", msg);
726 }
727}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200728
729void do_device_add(Monitor *mon, const QDict *qdict)
730{
731 QemuOpts *opts;
732
733 opts = qemu_opts_parse(&qemu_device_opts,
734 qdict_get_str(qdict, "config"), "driver");
735 if (opts)
736 qdev_device_add(opts);
737}
738
739void do_device_del(Monitor *mon, const QDict *qdict)
740{
741 const char *id = qdict_get_str(qdict, "id");
742 DeviceState *dev;
743
744 dev = qdev_find_recursive(main_system_bus, id);
745 if (NULL == dev) {
746 qemu_error("Device '%s' not found\n", id);
747 return;
748 }
749 qdev_unplug(dev);
750}