blob: 253e255647a797dbfbc225451ba2055fdc04c1e4 [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
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020033static int qdev_hotplug = 0;
34
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020035/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
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) {
Amit Shahc8cd1fc2009-09-29 15:51:03 +0530218 qemu_error("Error initializing device %s\n", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200219 qdev_free(qdev);
220 return NULL;
221 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200222 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200223 return qdev;
224}
225
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300226static void qdev_reset(void *opaque)
227{
228 DeviceState *dev = opaque;
229 if (dev->info->reset)
230 dev->info->reset(dev);
231}
232
Paul Brookaae94602009-05-14 22:35:06 +0100233/* Initialize a device. Device properties should be set before calling
234 this function. IRQs and MMIO regions should be connected/mapped after
235 calling this function. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200236int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100237{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200238 int rc;
239
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200240 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200241 rc = dev->info->init(dev, dev->info);
242 if (rc < 0)
243 return rc;
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300244 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200245 if (dev->info->vmsd)
246 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200247 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200248 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100249}
250
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200251int qdev_unplug(DeviceState *dev)
252{
253 if (!dev->parent_bus->allow_hotplug) {
254 qemu_error("Bus %s does not support hotplugging\n",
255 dev->parent_bus->name);
256 return -1;
257 }
258 return dev->info->unplug(dev);
259}
260
261/* can be used as ->unplug() callback for the simple cases */
262int qdev_simple_unplug_cb(DeviceState *dev)
263{
264 /* just zap it */
265 qdev_free(dev);
266 return 0;
267}
268
Paul Brook02e2da42009-05-23 00:05:19 +0100269/* Unlink device from bus and free the structure. */
270void qdev_free(DeviceState *dev)
271{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200272 BusState *bus;
273
274 if (dev->state == DEV_STATE_INITIALIZED) {
275 while (dev->num_child_bus) {
276 bus = QLIST_FIRST(&dev->child_bus);
277 qbus_free(bus);
278 }
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200279#if 0 /* FIXME: need sane vmstate_unregister function */
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200280 if (dev->info->vmsd)
281 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200282#endif
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200283 if (dev->info->exit)
284 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200285 if (dev->opts)
286 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200287 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300288 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000289 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200290 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100291}
292
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200293void qdev_machine_creation_done(void)
294{
295 /*
296 * ok, initial machine setup is done, starting from now we can
297 * only create hotpluggable devices
298 */
299 qdev_hotplug = 1;
300}
301
Paul Brookaae94602009-05-14 22:35:06 +0100302/* Get a character (serial) device interface. */
303CharDriverState *qdev_init_chardev(DeviceState *dev)
304{
305 static int next_serial;
306 static int next_virtconsole;
307 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200308 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100309 return virtcon_hds[next_virtconsole++];
310 } else {
311 return serial_hds[next_serial++];
312 }
313}
314
Paul Brook02e2da42009-05-23 00:05:19 +0100315BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100316{
Paul Brook02e2da42009-05-23 00:05:19 +0100317 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100318}
319
Paul Brookaae94602009-05-14 22:35:06 +0100320void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
321{
322 assert(dev->num_gpio_in == 0);
323 dev->num_gpio_in = n;
324 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
325}
326
327void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
328{
329 assert(dev->num_gpio_out == 0);
330 dev->num_gpio_out = n;
331 dev->gpio_out = pins;
332}
333
334qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
335{
336 assert(n >= 0 && n < dev->num_gpio_in);
337 return dev->gpio_in[n];
338}
339
340void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
341{
342 assert(n >= 0 && n < dev->num_gpio_out);
343 dev->gpio_out[n] = pin;
344}
345
Paul Brook9d07d752009-05-14 22:35:07 +0100346VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100347 NetCanReceive *can_receive,
348 NetReceive *receive,
349 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100350 NetCleanup *cleanup,
351 void *opaque)
352{
353 NICInfo *nd = dev->nd;
354 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100355 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
356 receive, receive_iov, cleanup, opaque);
357 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100358}
359
360
361void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
362{
363 memcpy(macaddr, dev->nd->macaddr, 6);
364}
365
Paul Brookaae94602009-05-14 22:35:06 +0100366static int next_block_unit[IF_COUNT];
367
368/* Get a block device. This should only be used for single-drive devices
369 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
370 appropriate bus. */
371BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
372{
373 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200374 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100375
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200376 dinfo = drive_get(type, 0, unit);
377 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100378}
Paul Brook4d6ae672009-05-14 22:35:06 +0100379
Paul Brook02e2da42009-05-23 00:05:19 +0100380BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100381{
Paul Brook02e2da42009-05-23 00:05:19 +0100382 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100383
Blue Swirl72cf2d42009-09-12 07:36:22 +0000384 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100385 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100386 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100387 }
388 }
389 return NULL;
390}
391
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200392static BusState *qbus_find_recursive(BusState *bus, const char *name,
393 const BusInfo *info)
394{
395 DeviceState *dev;
396 BusState *child, *ret;
397 int match = 1;
398
399 if (name && (strcmp(bus->name, name) != 0)) {
400 match = 0;
401 }
402 if (info && (bus->info != info)) {
403 match = 0;
404 }
405 if (match) {
406 return bus;
407 }
408
Blue Swirl72cf2d42009-09-12 07:36:22 +0000409 QLIST_FOREACH(dev, &bus->children, sibling) {
410 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200411 ret = qbus_find_recursive(child, name, info);
412 if (ret) {
413 return ret;
414 }
415 }
416 }
417 return NULL;
418}
419
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200420static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
421{
422 DeviceState *dev, *ret;
423 BusState *child;
424
425 QLIST_FOREACH(dev, &bus->children, sibling) {
426 if (dev->id && strcmp(dev->id, id) == 0)
427 return dev;
428 QLIST_FOREACH(child, &dev->child_bus, sibling) {
429 ret = qdev_find_recursive(child, id);
430 if (ret) {
431 return ret;
432 }
433 }
434 }
435 return NULL;
436}
437
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200438static void qbus_list_bus(DeviceState *dev, char *dest, int len)
439{
440 BusState *child;
441 const char *sep = " ";
442 int pos = 0;
443
444 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
445 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000446 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200447 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
448 sep = ", ";
449 }
450}
451
452static void qbus_list_dev(BusState *bus, char *dest, int len)
453{
454 DeviceState *dev;
455 const char *sep = " ";
456 int pos = 0;
457
458 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
459 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000460 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200461 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
462 sep, dev->info->name);
463 if (dev->id)
464 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
465 sep = ", ";
466 }
467}
468
469static BusState *qbus_find_bus(DeviceState *dev, char *elem)
470{
471 BusState *child;
472
Blue Swirl72cf2d42009-09-12 07:36:22 +0000473 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200474 if (strcmp(child->name, elem) == 0) {
475 return child;
476 }
477 }
478 return NULL;
479}
480
481static DeviceState *qbus_find_dev(BusState *bus, char *elem)
482{
483 DeviceState *dev;
484
485 /*
486 * try to match in order:
487 * (1) instance id, if present
488 * (2) driver name
489 * (3) driver alias, if present
490 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000491 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200492 if (dev->id && strcmp(dev->id, elem) == 0) {
493 return dev;
494 }
495 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000496 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200497 if (strcmp(dev->info->name, elem) == 0) {
498 return dev;
499 }
500 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000501 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200502 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
503 return dev;
504 }
505 }
506 return NULL;
507}
508
509static BusState *qbus_find(const char *path)
510{
511 DeviceState *dev;
512 BusState *bus;
513 char elem[128], msg[256];
514 int pos, len;
515
516 /* find start element */
517 if (path[0] == '/') {
518 bus = main_system_bus;
519 pos = 0;
520 } else {
521 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200522 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200523 return NULL;
524 }
525 bus = qbus_find_recursive(main_system_bus, elem, NULL);
526 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200527 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200528 return NULL;
529 }
530 pos = len;
531 }
532
533 for (;;) {
534 if (path[pos] == '\0') {
535 /* we are done */
536 return bus;
537 }
538
539 /* find device */
540 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200541 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200542 return NULL;
543 }
544 pos += len;
545 dev = qbus_find_dev(bus, elem);
546 if (!dev) {
547 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200548 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200549 return NULL;
550 }
551 if (path[pos] == '\0') {
552 /* last specified element is a device. If it has exactly
553 * one child bus accept it nevertheless */
554 switch (dev->num_child_bus) {
555 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200556 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200557 return NULL;
558 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000559 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200560 default:
561 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200562 qemu_error("device has multiple child busses (%s)\n%s\n",
563 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200564 return NULL;
565 }
566 }
567
568 /* find bus */
569 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200570 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200571 return NULL;
572 }
573 pos += len;
574 bus = qbus_find_bus(dev, elem);
575 if (!bus) {
576 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200577 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200578 return NULL;
579 }
580 }
581}
582
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200583void qbus_create_inplace(BusState *bus, BusInfo *info,
584 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100585{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200586 char *buf;
587 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100588
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200589 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100590 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200591
592 if (name) {
593 /* use supplied name */
594 bus->name = qemu_strdup(name);
595 } else if (parent && parent->id) {
596 /* parent device has id -> use it for bus name */
597 len = strlen(parent->id) + 16;
598 buf = qemu_malloc(len);
599 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
600 bus->name = buf;
601 } else {
602 /* no id -> use lowercase bus type for bus name */
603 len = strlen(info->name) + 16;
604 buf = qemu_malloc(len);
605 len = snprintf(buf, len, "%s.%d", info->name,
606 parent ? parent->num_child_bus : 0);
607 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200608 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200609 bus->name = buf;
610 }
611
Blue Swirl72cf2d42009-09-12 07:36:22 +0000612 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100613 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000614 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200615 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100616 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200617
618}
619
620BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
621{
622 BusState *bus;
623
624 bus = qemu_mallocz(info->size);
625 bus->qdev_allocated = 1;
626 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100627 return bus;
628}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100629
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200630void qbus_free(BusState *bus)
631{
632 DeviceState *dev;
633
634 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
635 qdev_free(dev);
636 }
637 if (bus->parent) {
638 QLIST_REMOVE(bus, sibling);
639 bus->parent->num_child_bus--;
640 }
641 if (bus->qdev_allocated) {
642 qemu_free(bus);
643 }
644}
645
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100646#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
647static void qbus_print(Monitor *mon, BusState *bus, int indent);
648
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200649static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
650 const char *prefix, int indent)
651{
652 char buf[64];
653
654 if (!props)
655 return;
656 while (props->name) {
657 if (props->info->print) {
658 props->info->print(dev, props, buf, sizeof(buf));
659 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
660 }
661 props++;
662 }
663}
664
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100665static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
666{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100667 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200668 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
669 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100670 indent += 2;
671 if (dev->num_gpio_in) {
672 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
673 }
674 if (dev->num_gpio_out) {
675 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
676 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200677 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
678 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200679 if (dev->parent_bus->info->print_dev)
680 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000681 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100682 qbus_print(mon, child, indent);
683 }
684}
685
686static void qbus_print(Monitor *mon, BusState *bus, int indent)
687{
688 struct DeviceState *dev;
689
690 qdev_printf("bus: %s\n", bus->name);
691 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200692 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000693 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100694 qdev_print(mon, dev, indent);
695 }
696}
697#undef qdev_printf
698
699void do_info_qtree(Monitor *mon)
700{
701 if (main_system_bus)
702 qbus_print(mon, main_system_bus, 0);
703}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200704
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200705void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200706{
707 DeviceInfo *info;
708 char msg[256];
709
710 for (info = device_info_list; info != NULL; info = info->next) {
711 qdev_print_devinfo(info, msg, sizeof(msg));
712 monitor_printf(mon, "%s\n", msg);
713 }
714}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200715
716void do_device_add(Monitor *mon, const QDict *qdict)
717{
718 QemuOpts *opts;
719
720 opts = qemu_opts_parse(&qemu_device_opts,
721 qdict_get_str(qdict, "config"), "driver");
722 if (opts)
723 qdev_device_add(opts);
724}
725
726void do_device_del(Monitor *mon, const QDict *qdict)
727{
728 const char *id = qdict_get_str(qdict, "id");
729 DeviceState *dev;
730
731 dev = qdev_find_recursive(main_system_bus, id);
732 if (NULL == dev) {
733 qemu_error("Device '%s' not found\n", id);
734 return;
735 }
736 qdev_unplug(dev);
737}