blob: 86cf81be9b107a23ec4af0a55f5e45118fc31839 [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
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
234 calling this function. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200235int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100236{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200237 int rc;
238
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200239 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200240 rc = dev->info->init(dev, dev->info);
241 if (rc < 0)
242 return rc;
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300243 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200244 if (dev->info->vmsd)
245 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200246 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200247 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100248}
249
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200250int qdev_unplug(DeviceState *dev)
251{
252 if (!dev->parent_bus->allow_hotplug) {
253 qemu_error("Bus %s does not support hotplugging\n",
254 dev->parent_bus->name);
255 return -1;
256 }
257 return dev->info->unplug(dev);
258}
259
260/* can be used as ->unplug() callback for the simple cases */
261int qdev_simple_unplug_cb(DeviceState *dev)
262{
263 /* just zap it */
264 qdev_free(dev);
265 return 0;
266}
267
Paul Brook02e2da42009-05-23 00:05:19 +0100268/* Unlink device from bus and free the structure. */
269void qdev_free(DeviceState *dev)
270{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200271 BusState *bus;
272
273 if (dev->state == DEV_STATE_INITIALIZED) {
274 while (dev->num_child_bus) {
275 bus = QLIST_FIRST(&dev->child_bus);
276 qbus_free(bus);
277 }
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200278#if 0 /* FIXME: need sane vmstate_unregister function */
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200279 if (dev->info->vmsd)
280 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200281#endif
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200282 if (dev->info->exit)
283 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200284 if (dev->opts)
285 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200286 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300287 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000288 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200289 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100290}
291
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200292void qdev_machine_creation_done(void)
293{
294 /*
295 * ok, initial machine setup is done, starting from now we can
296 * only create hotpluggable devices
297 */
298 qdev_hotplug = 1;
299}
300
Paul Brookaae94602009-05-14 22:35:06 +0100301/* Get a character (serial) device interface. */
302CharDriverState *qdev_init_chardev(DeviceState *dev)
303{
304 static int next_serial;
305 static int next_virtconsole;
306 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200307 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100308 return virtcon_hds[next_virtconsole++];
309 } else {
310 return serial_hds[next_serial++];
311 }
312}
313
Paul Brook02e2da42009-05-23 00:05:19 +0100314BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100315{
Paul Brook02e2da42009-05-23 00:05:19 +0100316 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100317}
318
Paul Brookaae94602009-05-14 22:35:06 +0100319void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
320{
321 assert(dev->num_gpio_in == 0);
322 dev->num_gpio_in = n;
323 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
324}
325
326void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
327{
328 assert(dev->num_gpio_out == 0);
329 dev->num_gpio_out = n;
330 dev->gpio_out = pins;
331}
332
333qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
334{
335 assert(n >= 0 && n < dev->num_gpio_in);
336 return dev->gpio_in[n];
337}
338
339void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
340{
341 assert(n >= 0 && n < dev->num_gpio_out);
342 dev->gpio_out[n] = pin;
343}
344
Paul Brook9d07d752009-05-14 22:35:07 +0100345VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100346 NetCanReceive *can_receive,
347 NetReceive *receive,
348 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100349 NetCleanup *cleanup,
350 void *opaque)
351{
352 NICInfo *nd = dev->nd;
353 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100354 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
355 receive, receive_iov, cleanup, opaque);
356 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100357}
358
359
360void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
361{
362 memcpy(macaddr, dev->nd->macaddr, 6);
363}
364
Paul Brookaae94602009-05-14 22:35:06 +0100365static int next_block_unit[IF_COUNT];
366
367/* Get a block device. This should only be used for single-drive devices
368 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
369 appropriate bus. */
370BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
371{
372 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200373 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100374
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200375 dinfo = drive_get(type, 0, unit);
376 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100377}
Paul Brook4d6ae672009-05-14 22:35:06 +0100378
Paul Brook02e2da42009-05-23 00:05:19 +0100379BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100380{
Paul Brook02e2da42009-05-23 00:05:19 +0100381 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100382
Blue Swirl72cf2d42009-09-12 07:36:22 +0000383 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100384 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100385 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100386 }
387 }
388 return NULL;
389}
390
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200391static BusState *qbus_find_recursive(BusState *bus, const char *name,
392 const BusInfo *info)
393{
394 DeviceState *dev;
395 BusState *child, *ret;
396 int match = 1;
397
398 if (name && (strcmp(bus->name, name) != 0)) {
399 match = 0;
400 }
401 if (info && (bus->info != info)) {
402 match = 0;
403 }
404 if (match) {
405 return bus;
406 }
407
Blue Swirl72cf2d42009-09-12 07:36:22 +0000408 QLIST_FOREACH(dev, &bus->children, sibling) {
409 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200410 ret = qbus_find_recursive(child, name, info);
411 if (ret) {
412 return ret;
413 }
414 }
415 }
416 return NULL;
417}
418
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200419static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
420{
421 DeviceState *dev, *ret;
422 BusState *child;
423
424 QLIST_FOREACH(dev, &bus->children, sibling) {
425 if (dev->id && strcmp(dev->id, id) == 0)
426 return dev;
427 QLIST_FOREACH(child, &dev->child_bus, sibling) {
428 ret = qdev_find_recursive(child, id);
429 if (ret) {
430 return ret;
431 }
432 }
433 }
434 return NULL;
435}
436
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200437static void qbus_list_bus(DeviceState *dev, char *dest, int len)
438{
439 BusState *child;
440 const char *sep = " ";
441 int pos = 0;
442
443 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
444 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000445 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200446 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
447 sep = ", ";
448 }
449}
450
451static void qbus_list_dev(BusState *bus, char *dest, int len)
452{
453 DeviceState *dev;
454 const char *sep = " ";
455 int pos = 0;
456
457 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
458 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000459 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200460 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
461 sep, dev->info->name);
462 if (dev->id)
463 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
464 sep = ", ";
465 }
466}
467
468static BusState *qbus_find_bus(DeviceState *dev, char *elem)
469{
470 BusState *child;
471
Blue Swirl72cf2d42009-09-12 07:36:22 +0000472 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200473 if (strcmp(child->name, elem) == 0) {
474 return child;
475 }
476 }
477 return NULL;
478}
479
480static DeviceState *qbus_find_dev(BusState *bus, char *elem)
481{
482 DeviceState *dev;
483
484 /*
485 * try to match in order:
486 * (1) instance id, if present
487 * (2) driver name
488 * (3) driver alias, if present
489 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000490 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200491 if (dev->id && strcmp(dev->id, 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 (strcmp(dev->info->name, elem) == 0) {
497 return dev;
498 }
499 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000500 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200501 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
502 return dev;
503 }
504 }
505 return NULL;
506}
507
508static BusState *qbus_find(const char *path)
509{
510 DeviceState *dev;
511 BusState *bus;
512 char elem[128], msg[256];
513 int pos, len;
514
515 /* find start element */
516 if (path[0] == '/') {
517 bus = main_system_bus;
518 pos = 0;
519 } else {
520 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200521 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200522 return NULL;
523 }
524 bus = qbus_find_recursive(main_system_bus, elem, NULL);
525 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200526 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200527 return NULL;
528 }
529 pos = len;
530 }
531
532 for (;;) {
533 if (path[pos] == '\0') {
534 /* we are done */
535 return bus;
536 }
537
538 /* find device */
539 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200540 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200541 return NULL;
542 }
543 pos += len;
544 dev = qbus_find_dev(bus, elem);
545 if (!dev) {
546 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200547 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200548 return NULL;
549 }
550 if (path[pos] == '\0') {
551 /* last specified element is a device. If it has exactly
552 * one child bus accept it nevertheless */
553 switch (dev->num_child_bus) {
554 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200555 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200556 return NULL;
557 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000558 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200559 default:
560 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200561 qemu_error("device has multiple child busses (%s)\n%s\n",
562 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200563 return NULL;
564 }
565 }
566
567 /* find bus */
568 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200569 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200570 return NULL;
571 }
572 pos += len;
573 bus = qbus_find_bus(dev, elem);
574 if (!bus) {
575 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200576 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200577 return NULL;
578 }
579 }
580}
581
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200582void qbus_create_inplace(BusState *bus, BusInfo *info,
583 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100584{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200585 char *buf;
586 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100587
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200588 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100589 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200590
591 if (name) {
592 /* use supplied name */
593 bus->name = qemu_strdup(name);
594 } else if (parent && parent->id) {
595 /* parent device has id -> use it for bus name */
596 len = strlen(parent->id) + 16;
597 buf = qemu_malloc(len);
598 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
599 bus->name = buf;
600 } else {
601 /* no id -> use lowercase bus type for bus name */
602 len = strlen(info->name) + 16;
603 buf = qemu_malloc(len);
604 len = snprintf(buf, len, "%s.%d", info->name,
605 parent ? parent->num_child_bus : 0);
606 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200607 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200608 bus->name = buf;
609 }
610
Blue Swirl72cf2d42009-09-12 07:36:22 +0000611 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100612 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000613 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200614 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100615 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200616
617}
618
619BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
620{
621 BusState *bus;
622
623 bus = qemu_mallocz(info->size);
624 bus->qdev_allocated = 1;
625 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100626 return bus;
627}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100628
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200629void qbus_free(BusState *bus)
630{
631 DeviceState *dev;
632
633 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
634 qdev_free(dev);
635 }
636 if (bus->parent) {
637 QLIST_REMOVE(bus, sibling);
638 bus->parent->num_child_bus--;
639 }
640 if (bus->qdev_allocated) {
641 qemu_free(bus);
642 }
643}
644
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100645#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
646static void qbus_print(Monitor *mon, BusState *bus, int indent);
647
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200648static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
649 const char *prefix, int indent)
650{
651 char buf[64];
652
653 if (!props)
654 return;
655 while (props->name) {
656 if (props->info->print) {
657 props->info->print(dev, props, buf, sizeof(buf));
658 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
659 }
660 props++;
661 }
662}
663
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100664static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
665{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100666 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200667 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
668 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100669 indent += 2;
670 if (dev->num_gpio_in) {
671 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
672 }
673 if (dev->num_gpio_out) {
674 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
675 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200676 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
677 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200678 if (dev->parent_bus->info->print_dev)
679 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000680 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100681 qbus_print(mon, child, indent);
682 }
683}
684
685static void qbus_print(Monitor *mon, BusState *bus, int indent)
686{
687 struct DeviceState *dev;
688
689 qdev_printf("bus: %s\n", bus->name);
690 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200691 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000692 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100693 qdev_print(mon, dev, indent);
694 }
695}
696#undef qdev_printf
697
698void do_info_qtree(Monitor *mon)
699{
700 if (main_system_bus)
701 qbus_print(mon, main_system_bus, 0);
702}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200703
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200704void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200705{
706 DeviceInfo *info;
707 char msg[256];
708
709 for (info = device_info_list; info != NULL; info = info->next) {
710 qdev_print_devinfo(info, msg, sizeof(msg));
711 monitor_printf(mon, "%s\n", msg);
712 }
713}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200714
715void do_device_add(Monitor *mon, const QDict *qdict)
716{
717 QemuOpts *opts;
718
719 opts = qemu_opts_parse(&qemu_device_opts,
720 qdict_get_str(qdict, "config"), "driver");
721 if (opts)
722 qdev_device_add(opts);
723}
724
725void do_device_del(Monitor *mon, const QDict *qdict)
726{
727 const char *id = qdict_get_str(qdict, "id");
728 DeviceState *dev;
729
730 dev = qdev_find_recursive(main_system_bus, id);
731 if (NULL == dev) {
732 qemu_error("Device '%s' not found\n", id);
733 return;
734 }
735 qdev_unplug(dev);
736}