blob: f47f0cb973a8ebde8213183a58077898e76de6a9 [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
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
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100156int qdev_device_help(QemuOpts *opts)
157{
158 const char *driver;
159 DeviceInfo *info;
160 char msg[256];
161
162 driver = qemu_opt_get(opts, "driver");
163 if (driver && !strcmp(driver, "?")) {
164 for (info = device_info_list; info != NULL; info = info->next) {
165 qdev_print_devinfo(info, msg, sizeof(msg));
166 qemu_error("%s\n", msg);
167 }
168 return 1;
169 }
170
171 return 0;
172}
173
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200174DeviceState *qdev_device_add(QemuOpts *opts)
175{
176 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200177 DeviceInfo *info;
178 DeviceState *qdev;
179 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200180
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200181 driver = qemu_opt_get(opts, "driver");
182 if (!driver) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200183 qemu_error("-device: no driver specified\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200184 return NULL;
185 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200186
187 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200188 info = qdev_find_info(NULL, driver);
189 if (!info) {
Luiz Capitulino3ced9f72009-11-18 23:05:33 -0200190 qemu_error_new(QERR_DEVICE_NOT_FOUND, driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200191 return NULL;
192 }
193 if (info->no_user) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200194 qemu_error("device \"%s\" can't be added via command line\n",
195 info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200196 return NULL;
197 }
198
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200199 /* find bus */
200 path = qemu_opt_get(opts, "bus");
201 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200202 bus = qbus_find(path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200203 } else {
204 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200205 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200206 if (!bus) {
207 qemu_error("Did not find %s bus for %s\n",
208 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200209 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200210 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200211 if (qdev_hotplug && !bus->allow_hotplug) {
212 qemu_error("Bus %s does not support hotplugging\n",
213 bus->name);
214 return NULL;
215 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200216
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200217 /* create device, set properties */
218 qdev = qdev_create(bus, driver);
219 id = qemu_opts_id(opts);
220 if (id) {
221 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200222 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200223 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
224 qdev_free(qdev);
225 return NULL;
226 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200227 if (qdev_init(qdev) < 0) {
Amit Shahc8cd1fc2009-09-29 15:51:03 +0530228 qemu_error("Error initializing device %s\n", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200229 return NULL;
230 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200231 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200232 return qdev;
233}
234
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300235static void qdev_reset(void *opaque)
236{
237 DeviceState *dev = opaque;
238 if (dev->info->reset)
239 dev->info->reset(dev);
240}
241
Paul Brookaae94602009-05-14 22:35:06 +0100242/* Initialize a device. Device properties should be set before calling
243 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200244 calling this function.
245 On failure, destroy the device and return negative value.
246 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200247int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100248{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200249 int rc;
250
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200251 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200252 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200253 if (rc < 0) {
254 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200255 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200256 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300257 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200258 if (dev->info->vmsd)
259 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200260 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200261 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100262}
263
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200264int qdev_unplug(DeviceState *dev)
265{
266 if (!dev->parent_bus->allow_hotplug) {
267 qemu_error("Bus %s does not support hotplugging\n",
268 dev->parent_bus->name);
269 return -1;
270 }
Amit Shah593831d2009-11-02 14:56:41 +0530271 assert(dev->info->unplug != NULL);
272
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200273 return dev->info->unplug(dev);
274}
275
276/* can be used as ->unplug() callback for the simple cases */
277int qdev_simple_unplug_cb(DeviceState *dev)
278{
279 /* just zap it */
280 qdev_free(dev);
281 return 0;
282}
283
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200284/* Like qdev_init(), but terminate program via hw_error() instead of
285 returning an error value. This is okay during machine creation.
286 Don't use for hotplug, because there callers need to recover from
287 failure. Exception: if you know the device's init() callback can't
288 fail, then qdev_init_nofail() can't fail either, and is therefore
289 usable even then. But relying on the device implementation that
290 way is somewhat unclean, and best avoided. */
291void qdev_init_nofail(DeviceState *dev)
292{
293 DeviceInfo *info = dev->info;
294
295 if (qdev_init(dev) < 0)
296 hw_error("Initialization of device %s failed\n", info->name);
297}
298
Paul Brook02e2da42009-05-23 00:05:19 +0100299/* Unlink device from bus and free the structure. */
300void qdev_free(DeviceState *dev)
301{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200302 BusState *bus;
303
304 if (dev->state == DEV_STATE_INITIALIZED) {
305 while (dev->num_child_bus) {
306 bus = QLIST_FIRST(&dev->child_bus);
307 qbus_free(bus);
308 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200309 if (dev->info->vmsd)
310 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200311 if (dev->info->exit)
312 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200313 if (dev->opts)
314 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200315 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300316 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000317 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200318 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100319}
320
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200321void qdev_machine_creation_done(void)
322{
323 /*
324 * ok, initial machine setup is done, starting from now we can
325 * only create hotpluggable devices
326 */
327 qdev_hotplug = 1;
328}
329
Paul Brookaae94602009-05-14 22:35:06 +0100330/* Get a character (serial) device interface. */
331CharDriverState *qdev_init_chardev(DeviceState *dev)
332{
333 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530334
335 /* FIXME: This function needs to go away: use chardev properties! */
336 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100337}
338
Paul Brook02e2da42009-05-23 00:05:19 +0100339BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100340{
Paul Brook02e2da42009-05-23 00:05:19 +0100341 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100342}
343
Paul Brookaae94602009-05-14 22:35:06 +0100344void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
345{
346 assert(dev->num_gpio_in == 0);
347 dev->num_gpio_in = n;
348 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
349}
350
351void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
352{
353 assert(dev->num_gpio_out == 0);
354 dev->num_gpio_out = n;
355 dev->gpio_out = pins;
356}
357
358qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
359{
360 assert(n >= 0 && n < dev->num_gpio_in);
361 return dev->gpio_in[n];
362}
363
364void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
365{
366 assert(n >= 0 && n < dev->num_gpio_out);
367 dev->gpio_out[n] = pin;
368}
369
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200370void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
371{
372 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
373 if (nd->vlan)
374 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
375 if (nd->netdev)
376 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200377 if (nd->nvectors != NIC_NVECTORS_UNSPECIFIED &&
378 qdev_prop_exists(dev, "vectors")) {
379 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
380 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200381}
382
Paul Brookaae94602009-05-14 22:35:06 +0100383static int next_block_unit[IF_COUNT];
384
385/* Get a block device. This should only be used for single-drive devices
386 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
387 appropriate bus. */
388BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
389{
390 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200391 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100392
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200393 dinfo = drive_get(type, 0, unit);
394 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100395}
Paul Brook4d6ae672009-05-14 22:35:06 +0100396
Paul Brook02e2da42009-05-23 00:05:19 +0100397BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100398{
Paul Brook02e2da42009-05-23 00:05:19 +0100399 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100400
Blue Swirl72cf2d42009-09-12 07:36:22 +0000401 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100402 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100403 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100404 }
405 }
406 return NULL;
407}
408
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200409static BusState *qbus_find_recursive(BusState *bus, const char *name,
410 const BusInfo *info)
411{
412 DeviceState *dev;
413 BusState *child, *ret;
414 int match = 1;
415
416 if (name && (strcmp(bus->name, name) != 0)) {
417 match = 0;
418 }
419 if (info && (bus->info != info)) {
420 match = 0;
421 }
422 if (match) {
423 return bus;
424 }
425
Blue Swirl72cf2d42009-09-12 07:36:22 +0000426 QLIST_FOREACH(dev, &bus->children, sibling) {
427 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200428 ret = qbus_find_recursive(child, name, info);
429 if (ret) {
430 return ret;
431 }
432 }
433 }
434 return NULL;
435}
436
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200437static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
438{
439 DeviceState *dev, *ret;
440 BusState *child;
441
442 QLIST_FOREACH(dev, &bus->children, sibling) {
443 if (dev->id && strcmp(dev->id, id) == 0)
444 return dev;
445 QLIST_FOREACH(child, &dev->child_bus, sibling) {
446 ret = qdev_find_recursive(child, id);
447 if (ret) {
448 return ret;
449 }
450 }
451 }
452 return NULL;
453}
454
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200455static void qbus_list_bus(DeviceState *dev, char *dest, int len)
456{
457 BusState *child;
458 const char *sep = " ";
459 int pos = 0;
460
461 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
462 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000463 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200464 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
465 sep = ", ";
466 }
467}
468
469static void qbus_list_dev(BusState *bus, char *dest, int len)
470{
471 DeviceState *dev;
472 const char *sep = " ";
473 int pos = 0;
474
475 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
476 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000477 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200478 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
479 sep, dev->info->name);
480 if (dev->id)
481 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
482 sep = ", ";
483 }
484}
485
486static BusState *qbus_find_bus(DeviceState *dev, char *elem)
487{
488 BusState *child;
489
Blue Swirl72cf2d42009-09-12 07:36:22 +0000490 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200491 if (strcmp(child->name, elem) == 0) {
492 return child;
493 }
494 }
495 return NULL;
496}
497
498static DeviceState *qbus_find_dev(BusState *bus, char *elem)
499{
500 DeviceState *dev;
501
502 /*
503 * try to match in order:
504 * (1) instance id, if present
505 * (2) driver name
506 * (3) driver alias, if present
507 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000508 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200509 if (dev->id && strcmp(dev->id, elem) == 0) {
510 return dev;
511 }
512 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000513 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200514 if (strcmp(dev->info->name, elem) == 0) {
515 return dev;
516 }
517 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000518 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200519 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
520 return dev;
521 }
522 }
523 return NULL;
524}
525
526static BusState *qbus_find(const char *path)
527{
528 DeviceState *dev;
529 BusState *bus;
530 char elem[128], msg[256];
531 int pos, len;
532
533 /* find start element */
534 if (path[0] == '/') {
535 bus = main_system_bus;
536 pos = 0;
537 } else {
538 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200539 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200540 return NULL;
541 }
542 bus = qbus_find_recursive(main_system_bus, elem, NULL);
543 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200544 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200545 return NULL;
546 }
547 pos = len;
548 }
549
550 for (;;) {
551 if (path[pos] == '\0') {
552 /* we are done */
553 return bus;
554 }
555
556 /* find device */
557 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200558 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200559 return NULL;
560 }
561 pos += len;
562 dev = qbus_find_dev(bus, elem);
563 if (!dev) {
564 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200565 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200566 return NULL;
567 }
568 if (path[pos] == '\0') {
569 /* last specified element is a device. If it has exactly
570 * one child bus accept it nevertheless */
571 switch (dev->num_child_bus) {
572 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200573 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200574 return NULL;
575 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000576 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200577 default:
578 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200579 qemu_error("device has multiple child busses (%s)\n%s\n",
580 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200581 return NULL;
582 }
583 }
584
585 /* find bus */
586 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200587 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200588 return NULL;
589 }
590 pos += len;
591 bus = qbus_find_bus(dev, elem);
592 if (!bus) {
593 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200594 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200595 return NULL;
596 }
597 }
598}
599
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200600void qbus_create_inplace(BusState *bus, BusInfo *info,
601 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100602{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200603 char *buf;
604 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100605
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200606 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100607 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200608
609 if (name) {
610 /* use supplied name */
611 bus->name = qemu_strdup(name);
612 } else if (parent && parent->id) {
613 /* parent device has id -> use it for bus name */
614 len = strlen(parent->id) + 16;
615 buf = qemu_malloc(len);
616 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
617 bus->name = buf;
618 } else {
619 /* no id -> use lowercase bus type for bus name */
620 len = strlen(info->name) + 16;
621 buf = qemu_malloc(len);
622 len = snprintf(buf, len, "%s.%d", info->name,
623 parent ? parent->num_child_bus : 0);
624 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200625 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200626 bus->name = buf;
627 }
628
Blue Swirl72cf2d42009-09-12 07:36:22 +0000629 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100630 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000631 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200632 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100633 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200634
635}
636
637BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
638{
639 BusState *bus;
640
641 bus = qemu_mallocz(info->size);
642 bus->qdev_allocated = 1;
643 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100644 return bus;
645}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100646
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200647void qbus_free(BusState *bus)
648{
649 DeviceState *dev;
650
651 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
652 qdev_free(dev);
653 }
654 if (bus->parent) {
655 QLIST_REMOVE(bus, sibling);
656 bus->parent->num_child_bus--;
657 }
658 if (bus->qdev_allocated) {
659 qemu_free(bus);
660 }
661}
662
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100663#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
664static void qbus_print(Monitor *mon, BusState *bus, int indent);
665
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200666static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
667 const char *prefix, int indent)
668{
669 char buf[64];
670
671 if (!props)
672 return;
673 while (props->name) {
674 if (props->info->print) {
675 props->info->print(dev, props, buf, sizeof(buf));
676 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
677 }
678 props++;
679 }
680}
681
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100682static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
683{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100684 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200685 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
686 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100687 indent += 2;
688 if (dev->num_gpio_in) {
689 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
690 }
691 if (dev->num_gpio_out) {
692 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
693 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200694 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
695 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200696 if (dev->parent_bus->info->print_dev)
697 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000698 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100699 qbus_print(mon, child, indent);
700 }
701}
702
703static void qbus_print(Monitor *mon, BusState *bus, int indent)
704{
705 struct DeviceState *dev;
706
707 qdev_printf("bus: %s\n", bus->name);
708 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200709 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000710 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100711 qdev_print(mon, dev, indent);
712 }
713}
714#undef qdev_printf
715
716void do_info_qtree(Monitor *mon)
717{
718 if (main_system_bus)
719 qbus_print(mon, main_system_bus, 0);
720}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200721
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200722void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200723{
724 DeviceInfo *info;
725 char msg[256];
726
727 for (info = device_info_list; info != NULL; info = info->next) {
728 qdev_print_devinfo(info, msg, sizeof(msg));
729 monitor_printf(mon, "%s\n", msg);
730 }
731}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200732
733void do_device_add(Monitor *mon, const QDict *qdict)
734{
735 QemuOpts *opts;
736
737 opts = qemu_opts_parse(&qemu_device_opts,
738 qdict_get_str(qdict, "config"), "driver");
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100739 if (opts && !qdev_device_help(opts))
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200740 qdev_device_add(opts);
741}
742
743void do_device_del(Monitor *mon, const QDict *qdict)
744{
745 const char *id = qdict_get_str(qdict, "id");
746 DeviceState *dev;
747
748 dev = qdev_find_recursive(main_system_bus, id);
749 if (NULL == dev) {
750 qemu_error("Device '%s' not found\n", id);
751 return;
752 }
753 qdev_unplug(dev);
754}