blob: 6451b8a6d73c41a898d36b0a29b03b0d029ecd12 [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. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000034static BusState *main_system_bus;
Paul Brook4d6ae672009-05-14 22:35:06 +010035
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020036static DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010037
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020038static BusState *qbus_find_recursive(BusState *bus, const char *name,
39 const BusInfo *info);
40static BusState *qbus_find(const char *path);
41
Paul Brookaae94602009-05-14 22:35:06 +010042/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020043void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010044{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020045 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020046 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010047
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020048 info->next = device_info_list;
49 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010050}
51
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020052static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
53{
54 DeviceInfo *info;
55
Gerd Hoffmann3320e562009-07-15 13:43:33 +020056 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020057 for (info = device_info_list; info != NULL; info = info->next) {
58 if (bus_info && info->bus_info != bus_info)
59 continue;
60 if (strcmp(info->name, name) != 0)
61 continue;
62 return info;
63 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020064
65 /* failing that check the aliases */
66 for (info = device_info_list; info != NULL; info = info->next) {
67 if (bus_info && info->bus_info != bus_info)
68 continue;
69 if (!info->alias)
70 continue;
71 if (strcmp(info->alias, name) != 0)
72 continue;
73 return info;
74 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020075 return NULL;
76}
77
Paul Brookaae94602009-05-14 22:35:06 +010078/* Create a new device. This only initializes the device state structure
79 and allows properties to be set. qdev_init should be called to
80 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010081DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010082{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020083 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010084 DeviceState *dev;
85
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020086 if (!bus) {
87 if (!main_system_bus) {
88 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010089 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020090 bus = main_system_bus;
91 }
92
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020093 info = qdev_find_info(bus->info, name);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020094 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020095 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010096 }
97
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020098 dev = qemu_mallocz(info->size);
99 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100100 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200101 qdev_prop_set_defaults(dev, dev->info->props);
102 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmannb6b61142009-07-15 13:48:21 +0200103 qdev_prop_set_compat(dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100104 LIST_INSERT_HEAD(&bus->children, dev, sibling);
Paul Brookaae94602009-05-14 22:35:06 +0100105 return dev;
106}
107
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200108static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
109{
110 int pos = 0;
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200111 int ret;
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200112
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200113 ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
114 info->name, info->bus_info->name);
115 pos += MIN(len-pos,ret);
116 if (info->alias) {
117 ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
118 pos += MIN(len-pos,ret);
119 }
120 if (info->desc) {
121 ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
122 pos += MIN(len-pos,ret);
123 }
124 if (info->no_user) {
125 ret = snprintf(dest+pos, len-pos, ", no-user");
126 pos += MIN(len-pos,ret);
127 }
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200128 return pos;
129}
130
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200131static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200132{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200133 DeviceState *dev = opaque;
134
135 if (strcmp(name, "driver") == 0)
136 return 0;
137 if (strcmp(name, "bus") == 0)
138 return 0;
139
140 if (-1 == qdev_prop_parse(dev, name, value)) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200141 qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
142 name, value, dev->info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200143 return -1;
144 }
145 return 0;
146}
147
148DeviceState *qdev_device_add(QemuOpts *opts)
149{
150 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200151 DeviceInfo *info;
152 DeviceState *qdev;
153 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200154
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200155 driver = qemu_opt_get(opts, "driver");
156 if (!driver) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200157 qemu_error("-device: no driver specified\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200158 return NULL;
159 }
160 if (strcmp(driver, "?") == 0) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200161 char msg[256];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200162 for (info = device_info_list; info != NULL; info = info->next) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200163 qdev_print_devinfo(info, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200164 qemu_error("%s\n", msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200165 }
166 return NULL;
167 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200168
169 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200170 info = qdev_find_info(NULL, driver);
171 if (!info) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200172 qemu_error("Device \"%s\" not found. Try -device '?' for a list.\n",
173 driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200174 return NULL;
175 }
176 if (info->no_user) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200177 qemu_error("device \"%s\" can't be added via command line\n",
178 info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200179 return NULL;
180 }
181
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200182 /* find bus */
183 path = qemu_opt_get(opts, "bus");
184 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200185 bus = qbus_find(path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200186 } else {
187 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200188 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200189 if (!bus) {
190 qemu_error("Did not find %s bus for %s\n",
191 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200192 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200193 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200194
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200195 /* create device, set properties */
196 qdev = qdev_create(bus, driver);
197 id = qemu_opts_id(opts);
198 if (id) {
199 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200200 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200201 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
202 qdev_free(qdev);
203 return NULL;
204 }
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200205 if (qdev_init(qdev) != 0) {
206 qdev_free(qdev);
207 return NULL;
208 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200209 return qdev;
210}
211
Paul Brookaae94602009-05-14 22:35:06 +0100212/* Initialize a device. Device properties should be set before calling
213 this function. IRQs and MMIO regions should be connected/mapped after
214 calling this function. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200215int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100216{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200217 int rc;
218
219 rc = dev->info->init(dev, dev->info);
220 if (rc < 0)
221 return rc;
222 if (dev->info->reset)
223 qemu_register_reset(dev->info->reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200224 if (dev->info->vmsd)
225 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200226 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100227}
228
229/* Unlink device from bus and free the structure. */
230void qdev_free(DeviceState *dev)
231{
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200232#if 0 /* FIXME: need sane vmstate_unregister function */
233 if (dev->info->vmsd)
234 vmstate_unregister(dev->info->vmsd, dev);
235#endif
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200236 if (dev->info->reset)
237 qemu_unregister_reset(dev->info->reset, dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100238 LIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200239 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100240}
241
Paul Brookaae94602009-05-14 22:35:06 +0100242/* Get a character (serial) device interface. */
243CharDriverState *qdev_init_chardev(DeviceState *dev)
244{
245 static int next_serial;
246 static int next_virtconsole;
247 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200248 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100249 return virtcon_hds[next_virtconsole++];
250 } else {
251 return serial_hds[next_serial++];
252 }
253}
254
Paul Brook02e2da42009-05-23 00:05:19 +0100255BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100256{
Paul Brook02e2da42009-05-23 00:05:19 +0100257 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100258}
259
Paul Brookaae94602009-05-14 22:35:06 +0100260void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
261{
262 assert(dev->num_gpio_in == 0);
263 dev->num_gpio_in = n;
264 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
265}
266
267void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
268{
269 assert(dev->num_gpio_out == 0);
270 dev->num_gpio_out = n;
271 dev->gpio_out = pins;
272}
273
274qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
275{
276 assert(n >= 0 && n < dev->num_gpio_in);
277 return dev->gpio_in[n];
278}
279
280void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
281{
282 assert(n >= 0 && n < dev->num_gpio_out);
283 dev->gpio_out[n] = pin;
284}
285
Paul Brook9d07d752009-05-14 22:35:07 +0100286VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100287 NetCanReceive *can_receive,
288 NetReceive *receive,
289 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100290 NetCleanup *cleanup,
291 void *opaque)
292{
293 NICInfo *nd = dev->nd;
294 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100295 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
296 receive, receive_iov, cleanup, opaque);
297 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100298}
299
300
301void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
302{
303 memcpy(macaddr, dev->nd->macaddr, 6);
304}
305
Paul Brookaae94602009-05-14 22:35:06 +0100306static int next_block_unit[IF_COUNT];
307
308/* Get a block device. This should only be used for single-drive devices
309 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
310 appropriate bus. */
311BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
312{
313 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200314 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100315
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200316 dinfo = drive_get(type, 0, unit);
317 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100318}
Paul Brook4d6ae672009-05-14 22:35:06 +0100319
Paul Brook02e2da42009-05-23 00:05:19 +0100320BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100321{
Paul Brook02e2da42009-05-23 00:05:19 +0100322 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100323
Paul Brook02e2da42009-05-23 00:05:19 +0100324 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100325 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100326 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100327 }
328 }
329 return NULL;
330}
331
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200332static BusState *qbus_find_recursive(BusState *bus, const char *name,
333 const BusInfo *info)
334{
335 DeviceState *dev;
336 BusState *child, *ret;
337 int match = 1;
338
339 if (name && (strcmp(bus->name, name) != 0)) {
340 match = 0;
341 }
342 if (info && (bus->info != info)) {
343 match = 0;
344 }
345 if (match) {
346 return bus;
347 }
348
349 LIST_FOREACH(dev, &bus->children, sibling) {
350 LIST_FOREACH(child, &dev->child_bus, sibling) {
351 ret = qbus_find_recursive(child, name, info);
352 if (ret) {
353 return ret;
354 }
355 }
356 }
357 return NULL;
358}
359
360static void qbus_list_bus(DeviceState *dev, char *dest, int len)
361{
362 BusState *child;
363 const char *sep = " ";
364 int pos = 0;
365
366 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
367 dev->id ? dev->id : dev->info->name);
368 LIST_FOREACH(child, &dev->child_bus, sibling) {
369 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
370 sep = ", ";
371 }
372}
373
374static void qbus_list_dev(BusState *bus, char *dest, int len)
375{
376 DeviceState *dev;
377 const char *sep = " ";
378 int pos = 0;
379
380 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
381 bus->name);
382 LIST_FOREACH(dev, &bus->children, sibling) {
383 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
384 sep, dev->info->name);
385 if (dev->id)
386 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
387 sep = ", ";
388 }
389}
390
391static BusState *qbus_find_bus(DeviceState *dev, char *elem)
392{
393 BusState *child;
394
395 LIST_FOREACH(child, &dev->child_bus, sibling) {
396 if (strcmp(child->name, elem) == 0) {
397 return child;
398 }
399 }
400 return NULL;
401}
402
403static DeviceState *qbus_find_dev(BusState *bus, char *elem)
404{
405 DeviceState *dev;
406
407 /*
408 * try to match in order:
409 * (1) instance id, if present
410 * (2) driver name
411 * (3) driver alias, if present
412 */
413 LIST_FOREACH(dev, &bus->children, sibling) {
414 if (dev->id && strcmp(dev->id, elem) == 0) {
415 return dev;
416 }
417 }
418 LIST_FOREACH(dev, &bus->children, sibling) {
419 if (strcmp(dev->info->name, elem) == 0) {
420 return dev;
421 }
422 }
423 LIST_FOREACH(dev, &bus->children, sibling) {
424 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
425 return dev;
426 }
427 }
428 return NULL;
429}
430
431static BusState *qbus_find(const char *path)
432{
433 DeviceState *dev;
434 BusState *bus;
435 char elem[128], msg[256];
436 int pos, len;
437
438 /* find start element */
439 if (path[0] == '/') {
440 bus = main_system_bus;
441 pos = 0;
442 } else {
443 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200444 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200445 return NULL;
446 }
447 bus = qbus_find_recursive(main_system_bus, elem, NULL);
448 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200449 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200450 return NULL;
451 }
452 pos = len;
453 }
454
455 for (;;) {
456 if (path[pos] == '\0') {
457 /* we are done */
458 return bus;
459 }
460
461 /* find device */
462 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200463 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200464 return NULL;
465 }
466 pos += len;
467 dev = qbus_find_dev(bus, elem);
468 if (!dev) {
469 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200470 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200471 return NULL;
472 }
473 if (path[pos] == '\0') {
474 /* last specified element is a device. If it has exactly
475 * one child bus accept it nevertheless */
476 switch (dev->num_child_bus) {
477 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200478 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200479 return NULL;
480 case 1:
481 return LIST_FIRST(&dev->child_bus);
482 default:
483 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200484 qemu_error("device has multiple child busses (%s)\n%s\n",
485 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200486 return NULL;
487 }
488 }
489
490 /* find bus */
491 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200492 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200493 return NULL;
494 }
495 pos += len;
496 bus = qbus_find_bus(dev, elem);
497 if (!bus) {
498 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200499 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200500 return NULL;
501 }
502 }
503}
504
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200505BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100506{
507 BusState *bus;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200508 char *buf;
509 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100510
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200511 bus = qemu_mallocz(info->size);
512 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100513 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200514
515 if (name) {
516 /* use supplied name */
517 bus->name = qemu_strdup(name);
518 } else if (parent && parent->id) {
519 /* parent device has id -> use it for bus name */
520 len = strlen(parent->id) + 16;
521 buf = qemu_malloc(len);
522 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
523 bus->name = buf;
524 } else {
525 /* no id -> use lowercase bus type for bus name */
526 len = strlen(info->name) + 16;
527 buf = qemu_malloc(len);
528 len = snprintf(buf, len, "%s.%d", info->name,
529 parent ? parent->num_child_bus : 0);
530 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200531 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200532 bus->name = buf;
533 }
534
Paul Brook02e2da42009-05-23 00:05:19 +0100535 LIST_INIT(&bus->children);
536 if (parent) {
537 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200538 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100539 }
540 return bus;
541}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100542
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100543#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
544static void qbus_print(Monitor *mon, BusState *bus, int indent);
545
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200546static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
547 const char *prefix, int indent)
548{
549 char buf[64];
550
551 if (!props)
552 return;
553 while (props->name) {
554 if (props->info->print) {
555 props->info->print(dev, props, buf, sizeof(buf));
556 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
557 }
558 props++;
559 }
560}
561
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100562static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
563{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100564 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200565 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
566 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100567 indent += 2;
568 if (dev->num_gpio_in) {
569 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
570 }
571 if (dev->num_gpio_out) {
572 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
573 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200574 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
575 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200576 if (dev->parent_bus->info->print_dev)
577 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100578 LIST_FOREACH(child, &dev->child_bus, sibling) {
579 qbus_print(mon, child, indent);
580 }
581}
582
583static void qbus_print(Monitor *mon, BusState *bus, int indent)
584{
585 struct DeviceState *dev;
586
587 qdev_printf("bus: %s\n", bus->name);
588 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200589 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100590 LIST_FOREACH(dev, &bus->children, sibling) {
591 qdev_print(mon, dev, indent);
592 }
593}
594#undef qdev_printf
595
596void do_info_qtree(Monitor *mon)
597{
598 if (main_system_bus)
599 qbus_print(mon, main_system_bus, 0);
600}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200601
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200602void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200603{
604 DeviceInfo *info;
605 char msg[256];
606
607 for (info = device_info_list; info != NULL; info = info->next) {
608 qdev_print_devinfo(info, msg, sizeof(msg));
609 monitor_printf(mon, "%s\n", msg);
610 }
611}