blob: 3ce69be47e7a4d68cd1ba068dce6402ac9eb1fdf [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"
Paul Brookaae94602009-05-14 22:35:06 +010032
Paul Brook02e2da42009-05-23 00:05:19 +010033/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020034static int qdev_hotplug = 0;
35
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000036static BusState *main_system_bus;
Paul Brook4d6ae672009-05-14 22:35:06 +010037
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020038static DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010039
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020040static BusState *qbus_find_recursive(BusState *bus, const char *name,
41 const BusInfo *info);
42static BusState *qbus_find(const char *path);
43
Paul Brookaae94602009-05-14 22:35:06 +010044/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020045void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010046{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020047 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020048 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010049
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020050 info->next = device_info_list;
51 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010052}
53
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020054static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
55{
56 DeviceInfo *info;
57
Gerd Hoffmann3320e562009-07-15 13:43:33 +020058 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020059 for (info = device_info_list; info != NULL; info = info->next) {
60 if (bus_info && info->bus_info != bus_info)
61 continue;
62 if (strcmp(info->name, name) != 0)
63 continue;
64 return info;
65 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020066
67 /* failing that check the aliases */
68 for (info = device_info_list; info != NULL; info = info->next) {
69 if (bus_info && info->bus_info != bus_info)
70 continue;
71 if (!info->alias)
72 continue;
73 if (strcmp(info->alias, name) != 0)
74 continue;
75 return info;
76 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020077 return NULL;
78}
79
Paul Brookaae94602009-05-14 22:35:06 +010080/* Create a new device. This only initializes the device state structure
81 and allows properties to be set. qdev_init should be called to
82 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010083DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010084{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020085 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010086 DeviceState *dev;
87
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020088 if (!bus) {
89 if (!main_system_bus) {
90 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010091 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020092 bus = main_system_bus;
93 }
94
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020095 info = qdev_find_info(bus->info, name);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020096 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020097 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010098 }
99
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200100 dev = qemu_mallocz(info->size);
101 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100102 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200103 qdev_prop_set_defaults(dev, dev->info->props);
104 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmannb6b61142009-07-15 13:48:21 +0200105 qdev_prop_set_compat(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000106 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200107 if (qdev_hotplug) {
108 assert(bus->allow_hotplug);
109 dev->hotplugged = 1;
110 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200111 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +0100112 return dev;
113}
114
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200115static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
116{
117 int pos = 0;
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200118 int ret;
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200119
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200120 ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
121 info->name, info->bus_info->name);
122 pos += MIN(len-pos,ret);
123 if (info->alias) {
124 ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
125 pos += MIN(len-pos,ret);
126 }
127 if (info->desc) {
128 ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
129 pos += MIN(len-pos,ret);
130 }
131 if (info->no_user) {
132 ret = snprintf(dest+pos, len-pos, ", no-user");
133 pos += MIN(len-pos,ret);
134 }
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200135 return pos;
136}
137
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200138static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200139{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200140 DeviceState *dev = opaque;
141
142 if (strcmp(name, "driver") == 0)
143 return 0;
144 if (strcmp(name, "bus") == 0)
145 return 0;
146
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100147 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200148 qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
149 name, value, dev->info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200150 return -1;
151 }
152 return 0;
153}
154
155DeviceState *qdev_device_add(QemuOpts *opts)
156{
157 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200158 DeviceInfo *info;
159 DeviceState *qdev;
160 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200161
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200162 driver = qemu_opt_get(opts, "driver");
163 if (!driver) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200164 qemu_error("-device: no driver specified\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200165 return NULL;
166 }
167 if (strcmp(driver, "?") == 0) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200168 char msg[256];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200169 for (info = device_info_list; info != NULL; info = info->next) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200170 qdev_print_devinfo(info, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200171 qemu_error("%s\n", msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200172 }
173 return NULL;
174 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200175
176 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200177 info = qdev_find_info(NULL, driver);
178 if (!info) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200179 qemu_error("Device \"%s\" not found. Try -device '?' for a list.\n",
180 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 }
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200217 if (qdev_init(qdev) != 0) {
218 qdev_free(qdev);
219 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
Paul Brookaae94602009-05-14 22:35:06 +0100225/* Initialize a device. Device properties should be set before calling
226 this function. IRQs and MMIO regions should be connected/mapped after
227 calling this function. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200228int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100229{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200230 int rc;
231
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200232 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200233 rc = dev->info->init(dev, dev->info);
234 if (rc < 0)
235 return rc;
236 if (dev->info->reset)
237 qemu_register_reset(dev->info->reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200238 if (dev->info->vmsd)
239 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200240 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200241 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100242}
243
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200244int qdev_unplug(DeviceState *dev)
245{
246 if (!dev->parent_bus->allow_hotplug) {
247 qemu_error("Bus %s does not support hotplugging\n",
248 dev->parent_bus->name);
249 return -1;
250 }
251 return dev->info->unplug(dev);
252}
253
254/* can be used as ->unplug() callback for the simple cases */
255int qdev_simple_unplug_cb(DeviceState *dev)
256{
257 /* just zap it */
258 qdev_free(dev);
259 return 0;
260}
261
Paul Brook02e2da42009-05-23 00:05:19 +0100262/* Unlink device from bus and free the structure. */
263void qdev_free(DeviceState *dev)
264{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200265 BusState *bus;
266
267 if (dev->state == DEV_STATE_INITIALIZED) {
268 while (dev->num_child_bus) {
269 bus = QLIST_FIRST(&dev->child_bus);
270 qbus_free(bus);
271 }
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200272#if 0 /* FIXME: need sane vmstate_unregister function */
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200273 if (dev->info->vmsd)
274 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200275#endif
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200276 if (dev->info->reset)
277 qemu_unregister_reset(dev->info->reset, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200278 if (dev->info->exit)
279 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200280 if (dev->opts)
281 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200282 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000283 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200284 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100285}
286
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200287void qdev_machine_creation_done(void)
288{
289 /*
290 * ok, initial machine setup is done, starting from now we can
291 * only create hotpluggable devices
292 */
293 qdev_hotplug = 1;
294}
295
Paul Brookaae94602009-05-14 22:35:06 +0100296/* Get a character (serial) device interface. */
297CharDriverState *qdev_init_chardev(DeviceState *dev)
298{
299 static int next_serial;
300 static int next_virtconsole;
301 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200302 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100303 return virtcon_hds[next_virtconsole++];
304 } else {
305 return serial_hds[next_serial++];
306 }
307}
308
Paul Brook02e2da42009-05-23 00:05:19 +0100309BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100310{
Paul Brook02e2da42009-05-23 00:05:19 +0100311 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100312}
313
Paul Brookaae94602009-05-14 22:35:06 +0100314void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
315{
316 assert(dev->num_gpio_in == 0);
317 dev->num_gpio_in = n;
318 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
319}
320
321void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
322{
323 assert(dev->num_gpio_out == 0);
324 dev->num_gpio_out = n;
325 dev->gpio_out = pins;
326}
327
328qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
329{
330 assert(n >= 0 && n < dev->num_gpio_in);
331 return dev->gpio_in[n];
332}
333
334void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
335{
336 assert(n >= 0 && n < dev->num_gpio_out);
337 dev->gpio_out[n] = pin;
338}
339
Paul Brook9d07d752009-05-14 22:35:07 +0100340VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100341 NetCanReceive *can_receive,
342 NetReceive *receive,
343 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100344 NetCleanup *cleanup,
345 void *opaque)
346{
347 NICInfo *nd = dev->nd;
348 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100349 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
350 receive, receive_iov, cleanup, opaque);
351 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100352}
353
354
355void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
356{
357 memcpy(macaddr, dev->nd->macaddr, 6);
358}
359
Paul Brookaae94602009-05-14 22:35:06 +0100360static int next_block_unit[IF_COUNT];
361
362/* Get a block device. This should only be used for single-drive devices
363 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
364 appropriate bus. */
365BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
366{
367 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200368 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100369
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200370 dinfo = drive_get(type, 0, unit);
371 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100372}
Paul Brook4d6ae672009-05-14 22:35:06 +0100373
Paul Brook02e2da42009-05-23 00:05:19 +0100374BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100375{
Paul Brook02e2da42009-05-23 00:05:19 +0100376 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100377
Blue Swirl72cf2d42009-09-12 07:36:22 +0000378 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100379 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100380 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100381 }
382 }
383 return NULL;
384}
385
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200386static BusState *qbus_find_recursive(BusState *bus, const char *name,
387 const BusInfo *info)
388{
389 DeviceState *dev;
390 BusState *child, *ret;
391 int match = 1;
392
393 if (name && (strcmp(bus->name, name) != 0)) {
394 match = 0;
395 }
396 if (info && (bus->info != info)) {
397 match = 0;
398 }
399 if (match) {
400 return bus;
401 }
402
Blue Swirl72cf2d42009-09-12 07:36:22 +0000403 QLIST_FOREACH(dev, &bus->children, sibling) {
404 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200405 ret = qbus_find_recursive(child, name, info);
406 if (ret) {
407 return ret;
408 }
409 }
410 }
411 return NULL;
412}
413
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200414static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
415{
416 DeviceState *dev, *ret;
417 BusState *child;
418
419 QLIST_FOREACH(dev, &bus->children, sibling) {
420 if (dev->id && strcmp(dev->id, id) == 0)
421 return dev;
422 QLIST_FOREACH(child, &dev->child_bus, sibling) {
423 ret = qdev_find_recursive(child, id);
424 if (ret) {
425 return ret;
426 }
427 }
428 }
429 return NULL;
430}
431
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200432static void qbus_list_bus(DeviceState *dev, char *dest, int len)
433{
434 BusState *child;
435 const char *sep = " ";
436 int pos = 0;
437
438 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
439 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000440 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200441 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
442 sep = ", ";
443 }
444}
445
446static void qbus_list_dev(BusState *bus, char *dest, int len)
447{
448 DeviceState *dev;
449 const char *sep = " ";
450 int pos = 0;
451
452 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
453 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000454 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200455 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
456 sep, dev->info->name);
457 if (dev->id)
458 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
459 sep = ", ";
460 }
461}
462
463static BusState *qbus_find_bus(DeviceState *dev, char *elem)
464{
465 BusState *child;
466
Blue Swirl72cf2d42009-09-12 07:36:22 +0000467 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200468 if (strcmp(child->name, elem) == 0) {
469 return child;
470 }
471 }
472 return NULL;
473}
474
475static DeviceState *qbus_find_dev(BusState *bus, char *elem)
476{
477 DeviceState *dev;
478
479 /*
480 * try to match in order:
481 * (1) instance id, if present
482 * (2) driver name
483 * (3) driver alias, if present
484 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000485 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200486 if (dev->id && strcmp(dev->id, elem) == 0) {
487 return dev;
488 }
489 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000490 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200491 if (strcmp(dev->info->name, elem) == 0) {
492 return dev;
493 }
494 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000495 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200496 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
497 return dev;
498 }
499 }
500 return NULL;
501}
502
503static BusState *qbus_find(const char *path)
504{
505 DeviceState *dev;
506 BusState *bus;
507 char elem[128], msg[256];
508 int pos, len;
509
510 /* find start element */
511 if (path[0] == '/') {
512 bus = main_system_bus;
513 pos = 0;
514 } else {
515 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200516 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200517 return NULL;
518 }
519 bus = qbus_find_recursive(main_system_bus, elem, NULL);
520 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200521 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200522 return NULL;
523 }
524 pos = len;
525 }
526
527 for (;;) {
528 if (path[pos] == '\0') {
529 /* we are done */
530 return bus;
531 }
532
533 /* find device */
534 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200535 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200536 return NULL;
537 }
538 pos += len;
539 dev = qbus_find_dev(bus, elem);
540 if (!dev) {
541 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200542 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200543 return NULL;
544 }
545 if (path[pos] == '\0') {
546 /* last specified element is a device. If it has exactly
547 * one child bus accept it nevertheless */
548 switch (dev->num_child_bus) {
549 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200550 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200551 return NULL;
552 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000553 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200554 default:
555 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200556 qemu_error("device has multiple child busses (%s)\n%s\n",
557 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200558 return NULL;
559 }
560 }
561
562 /* find bus */
563 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200564 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200565 return NULL;
566 }
567 pos += len;
568 bus = qbus_find_bus(dev, elem);
569 if (!bus) {
570 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200571 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200572 return NULL;
573 }
574 }
575}
576
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200577void qbus_create_inplace(BusState *bus, BusInfo *info,
578 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100579{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200580 char *buf;
581 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100582
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200583 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100584 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200585
586 if (name) {
587 /* use supplied name */
588 bus->name = qemu_strdup(name);
589 } else if (parent && parent->id) {
590 /* parent device has id -> use it for bus name */
591 len = strlen(parent->id) + 16;
592 buf = qemu_malloc(len);
593 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
594 bus->name = buf;
595 } else {
596 /* no id -> use lowercase bus type for bus name */
597 len = strlen(info->name) + 16;
598 buf = qemu_malloc(len);
599 len = snprintf(buf, len, "%s.%d", info->name,
600 parent ? parent->num_child_bus : 0);
601 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200602 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200603 bus->name = buf;
604 }
605
Blue Swirl72cf2d42009-09-12 07:36:22 +0000606 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100607 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000608 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200609 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100610 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200611
612}
613
614BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
615{
616 BusState *bus;
617
618 bus = qemu_mallocz(info->size);
619 bus->qdev_allocated = 1;
620 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100621 return bus;
622}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100623
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200624void qbus_free(BusState *bus)
625{
626 DeviceState *dev;
627
628 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
629 qdev_free(dev);
630 }
631 if (bus->parent) {
632 QLIST_REMOVE(bus, sibling);
633 bus->parent->num_child_bus--;
634 }
635 if (bus->qdev_allocated) {
636 qemu_free(bus);
637 }
638}
639
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100640#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
641static void qbus_print(Monitor *mon, BusState *bus, int indent);
642
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200643static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
644 const char *prefix, int indent)
645{
646 char buf[64];
647
648 if (!props)
649 return;
650 while (props->name) {
651 if (props->info->print) {
652 props->info->print(dev, props, buf, sizeof(buf));
653 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
654 }
655 props++;
656 }
657}
658
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100659static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
660{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100661 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200662 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
663 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100664 indent += 2;
665 if (dev->num_gpio_in) {
666 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
667 }
668 if (dev->num_gpio_out) {
669 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
670 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200671 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
672 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200673 if (dev->parent_bus->info->print_dev)
674 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000675 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100676 qbus_print(mon, child, indent);
677 }
678}
679
680static void qbus_print(Monitor *mon, BusState *bus, int indent)
681{
682 struct DeviceState *dev;
683
684 qdev_printf("bus: %s\n", bus->name);
685 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200686 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000687 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100688 qdev_print(mon, dev, indent);
689 }
690}
691#undef qdev_printf
692
693void do_info_qtree(Monitor *mon)
694{
695 if (main_system_bus)
696 qbus_print(mon, main_system_bus, 0);
697}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200698
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200699void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200700{
701 DeviceInfo *info;
702 char msg[256];
703
704 for (info = device_info_list; info != NULL; info = info->next) {
705 qdev_print_devinfo(info, msg, sizeof(msg));
706 monitor_printf(mon, "%s\n", msg);
707 }
708}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200709
710void do_device_add(Monitor *mon, const QDict *qdict)
711{
712 QemuOpts *opts;
713
714 opts = qemu_opts_parse(&qemu_device_opts,
715 qdict_get_str(qdict, "config"), "driver");
716 if (opts)
717 qdev_device_add(opts);
718}
719
720void do_device_del(Monitor *mon, const QDict *qdict)
721{
722 const char *id = qdict_get_str(qdict, "id");
723 DeviceState *dev;
724
725 dev = qdev_find_recursive(main_system_bus, id);
726 if (NULL == dev) {
727 qemu_error("Device '%s' not found\n", id);
728 return;
729 }
730 qdev_unplug(dev);
731}