blob: 9488dba33f9fe9b34f229eb7c055009d0e230e0d [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;
111
112 pos += snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
113 info->name, info->bus_info->name);
114 if (info->alias)
115 pos += snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
116 if (info->desc)
117 pos += snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
118 if (info->no_user)
119 pos += snprintf(dest+pos, len-pos, ", no-user");
120 return pos;
121}
122
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200123DeviceState *qdev_device_add(const char *cmdline)
124{
125 DeviceInfo *info;
126 DeviceState *qdev;
127 BusState *bus;
128 char driver[32], path[128] = "";
129 char tag[32], value[256];
130 const char *params = NULL;
131 int n = 0;
132
133 if (1 != sscanf(cmdline, "%32[^,],%n", driver, &n)) {
134 fprintf(stderr, "device parse error: \"%s\"\n", cmdline);
135 return NULL;
136 }
137 if (strcmp(driver, "?") == 0) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200138 char msg[256];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200139 for (info = device_info_list; info != NULL; info = info->next) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200140 qdev_print_devinfo(info, msg, sizeof(msg));
141 fprintf(stderr, "%s\n", msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200142 }
143 return NULL;
144 }
145 if (n) {
146 params = cmdline + n;
147 get_param_value(path, sizeof(path), "bus", params);
148 }
149 info = qdev_find_info(NULL, driver);
150 if (!info) {
151 fprintf(stderr, "Device \"%s\" not found. Try -device '?' for a list.\n",
152 driver);
153 return NULL;
154 }
155 if (info->no_user) {
156 fprintf(stderr, "device \"%s\" can't be added via command line\n",
157 info->name);
158 return NULL;
159 }
160
161 if (strlen(path)) {
162 bus = qbus_find(path);
163 if (!bus)
164 return NULL;
165 qdev = qdev_create(bus, driver);
166 } else {
167 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
168 if (!bus)
169 return NULL;
170 qdev = qdev_create(bus, driver);
171 }
172
173 if (params) {
174 while (params[0]) {
175 if (2 != sscanf(params, "%31[^=]=%255[^,]%n", tag, value, &n)) {
176 fprintf(stderr, "parse error at \"%s\"\n", params);
177 break;
178 }
179 params += n;
180 if (params[0] == ',')
181 params++;
182 if (strcmp(tag, "bus") == 0)
183 continue;
184 if (strcmp(tag, "id") == 0) {
185 qdev->id = qemu_strdup(value);
186 continue;
187 }
188 if (-1 == qdev_prop_parse(qdev, tag, value)) {
189 fprintf(stderr, "can't set property \"%s\" to \"%s\" for \"%s\"\n",
190 tag, value, driver);
191 }
192 }
193 }
194
195 qdev_init(qdev);
196 return qdev;
197}
198
Paul Brookaae94602009-05-14 22:35:06 +0100199/* Initialize a device. Device properties should be set before calling
200 this function. IRQs and MMIO regions should be connected/mapped after
201 calling this function. */
202void qdev_init(DeviceState *dev)
203{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200204 dev->info->init(dev, dev->info);
Paul Brook02e2da42009-05-23 00:05:19 +0100205}
206
207/* Unlink device from bus and free the structure. */
208void qdev_free(DeviceState *dev)
209{
210 LIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200211 qemu_free(dev->id);
212 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100213}
214
Paul Brookaae94602009-05-14 22:35:06 +0100215/* Get a character (serial) device interface. */
216CharDriverState *qdev_init_chardev(DeviceState *dev)
217{
218 static int next_serial;
219 static int next_virtconsole;
220 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200221 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100222 return virtcon_hds[next_virtconsole++];
223 } else {
224 return serial_hds[next_serial++];
225 }
226}
227
Paul Brook02e2da42009-05-23 00:05:19 +0100228BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100229{
Paul Brook02e2da42009-05-23 00:05:19 +0100230 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100231}
232
Paul Brookaae94602009-05-14 22:35:06 +0100233void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
234{
235 assert(dev->num_gpio_in == 0);
236 dev->num_gpio_in = n;
237 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
238}
239
240void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
241{
242 assert(dev->num_gpio_out == 0);
243 dev->num_gpio_out = n;
244 dev->gpio_out = pins;
245}
246
247qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
248{
249 assert(n >= 0 && n < dev->num_gpio_in);
250 return dev->gpio_in[n];
251}
252
253void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
254{
255 assert(n >= 0 && n < dev->num_gpio_out);
256 dev->gpio_out[n] = pin;
257}
258
Paul Brook9d07d752009-05-14 22:35:07 +0100259VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100260 NetCanReceive *can_receive,
261 NetReceive *receive,
262 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100263 NetCleanup *cleanup,
264 void *opaque)
265{
266 NICInfo *nd = dev->nd;
267 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100268 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
269 receive, receive_iov, cleanup, opaque);
270 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100271}
272
273
274void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
275{
276 memcpy(macaddr, dev->nd->macaddr, 6);
277}
278
Paul Brookaae94602009-05-14 22:35:06 +0100279static int next_block_unit[IF_COUNT];
280
281/* Get a block device. This should only be used for single-drive devices
282 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
283 appropriate bus. */
284BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
285{
286 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200287 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100288
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200289 dinfo = drive_get(type, 0, unit);
290 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100291}
Paul Brook4d6ae672009-05-14 22:35:06 +0100292
Paul Brook02e2da42009-05-23 00:05:19 +0100293BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100294{
Paul Brook02e2da42009-05-23 00:05:19 +0100295 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100296
Paul Brook02e2da42009-05-23 00:05:19 +0100297 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100298 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100299 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100300 }
301 }
302 return NULL;
303}
304
Paul Brook6f68ecb2009-05-14 22:35:07 +0100305static int next_scsi_bus;
306
307/* Create a scsi bus, and attach devices to it. */
308/* TODO: Actually create a scsi bus for hotplug to use. */
309void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
310{
311 int bus = next_scsi_bus++;
312 int unit;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200313 DriveInfo *dinfo;
Paul Brook6f68ecb2009-05-14 22:35:07 +0100314
315 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200316 dinfo = drive_get(IF_SCSI, bus, unit);
317 if (!dinfo) {
Paul Brook6f68ecb2009-05-14 22:35:07 +0100318 continue;
319 }
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200320 attach(host, dinfo->bdrv, unit);
Paul Brook6f68ecb2009-05-14 22:35:07 +0100321 }
322}
Paul Brook02e2da42009-05-23 00:05:19 +0100323
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200324static BusState *qbus_find_recursive(BusState *bus, const char *name,
325 const BusInfo *info)
326{
327 DeviceState *dev;
328 BusState *child, *ret;
329 int match = 1;
330
331 if (name && (strcmp(bus->name, name) != 0)) {
332 match = 0;
333 }
334 if (info && (bus->info != info)) {
335 match = 0;
336 }
337 if (match) {
338 return bus;
339 }
340
341 LIST_FOREACH(dev, &bus->children, sibling) {
342 LIST_FOREACH(child, &dev->child_bus, sibling) {
343 ret = qbus_find_recursive(child, name, info);
344 if (ret) {
345 return ret;
346 }
347 }
348 }
349 return NULL;
350}
351
352static void qbus_list_bus(DeviceState *dev, char *dest, int len)
353{
354 BusState *child;
355 const char *sep = " ";
356 int pos = 0;
357
358 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
359 dev->id ? dev->id : dev->info->name);
360 LIST_FOREACH(child, &dev->child_bus, sibling) {
361 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
362 sep = ", ";
363 }
364}
365
366static void qbus_list_dev(BusState *bus, char *dest, int len)
367{
368 DeviceState *dev;
369 const char *sep = " ";
370 int pos = 0;
371
372 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
373 bus->name);
374 LIST_FOREACH(dev, &bus->children, sibling) {
375 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
376 sep, dev->info->name);
377 if (dev->id)
378 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
379 sep = ", ";
380 }
381}
382
383static BusState *qbus_find_bus(DeviceState *dev, char *elem)
384{
385 BusState *child;
386
387 LIST_FOREACH(child, &dev->child_bus, sibling) {
388 if (strcmp(child->name, elem) == 0) {
389 return child;
390 }
391 }
392 return NULL;
393}
394
395static DeviceState *qbus_find_dev(BusState *bus, char *elem)
396{
397 DeviceState *dev;
398
399 /*
400 * try to match in order:
401 * (1) instance id, if present
402 * (2) driver name
403 * (3) driver alias, if present
404 */
405 LIST_FOREACH(dev, &bus->children, sibling) {
406 if (dev->id && strcmp(dev->id, elem) == 0) {
407 return dev;
408 }
409 }
410 LIST_FOREACH(dev, &bus->children, sibling) {
411 if (strcmp(dev->info->name, elem) == 0) {
412 return dev;
413 }
414 }
415 LIST_FOREACH(dev, &bus->children, sibling) {
416 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
417 return dev;
418 }
419 }
420 return NULL;
421}
422
423static BusState *qbus_find(const char *path)
424{
425 DeviceState *dev;
426 BusState *bus;
427 char elem[128], msg[256];
428 int pos, len;
429
430 /* find start element */
431 if (path[0] == '/') {
432 bus = main_system_bus;
433 pos = 0;
434 } else {
435 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
436 fprintf(stderr, "path parse error (\"%s\")\n", path);
437 return NULL;
438 }
439 bus = qbus_find_recursive(main_system_bus, elem, NULL);
440 if (!bus) {
441 fprintf(stderr, "bus \"%s\" not found\n", elem);
442 return NULL;
443 }
444 pos = len;
445 }
446
447 for (;;) {
448 if (path[pos] == '\0') {
449 /* we are done */
450 return bus;
451 }
452
453 /* find device */
454 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
455 fprintf(stderr, "path parse error (\"%s\" pos %d)\n", path, pos);
456 return NULL;
457 }
458 pos += len;
459 dev = qbus_find_dev(bus, elem);
460 if (!dev) {
461 qbus_list_dev(bus, msg, sizeof(msg));
462 fprintf(stderr, "device \"%s\" not found\n%s\n", elem, msg);
463 return NULL;
464 }
465 if (path[pos] == '\0') {
466 /* last specified element is a device. If it has exactly
467 * one child bus accept it nevertheless */
468 switch (dev->num_child_bus) {
469 case 0:
470 fprintf(stderr, "device has no child bus (%s)\n", path);
471 return NULL;
472 case 1:
473 return LIST_FIRST(&dev->child_bus);
474 default:
475 qbus_list_bus(dev, msg, sizeof(msg));
476 fprintf(stderr, "device has multiple child busses (%s)\n%s\n",
477 path, msg);
478 return NULL;
479 }
480 }
481
482 /* find bus */
483 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
484 fprintf(stderr, "path parse error (\"%s\" pos %d)\n", path, pos);
485 return NULL;
486 }
487 pos += len;
488 bus = qbus_find_bus(dev, elem);
489 if (!bus) {
490 qbus_list_bus(dev, msg, sizeof(msg));
491 fprintf(stderr, "child bus \"%s\" not found\n%s\n", elem, msg);
492 return NULL;
493 }
494 }
495}
496
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200497BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100498{
499 BusState *bus;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200500 char *buf;
501 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100502
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200503 bus = qemu_mallocz(info->size);
504 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100505 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200506
507 if (name) {
508 /* use supplied name */
509 bus->name = qemu_strdup(name);
510 } else if (parent && parent->id) {
511 /* parent device has id -> use it for bus name */
512 len = strlen(parent->id) + 16;
513 buf = qemu_malloc(len);
514 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
515 bus->name = buf;
516 } else {
517 /* no id -> use lowercase bus type for bus name */
518 len = strlen(info->name) + 16;
519 buf = qemu_malloc(len);
520 len = snprintf(buf, len, "%s.%d", info->name,
521 parent ? parent->num_child_bus : 0);
522 for (i = 0; i < len; i++)
523 buf[i] = tolower(buf[i]);
524 bus->name = buf;
525 }
526
Paul Brook02e2da42009-05-23 00:05:19 +0100527 LIST_INIT(&bus->children);
528 if (parent) {
529 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200530 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100531 }
532 return bus;
533}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100534
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100535#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
536static void qbus_print(Monitor *mon, BusState *bus, int indent);
537
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200538static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
539 const char *prefix, int indent)
540{
541 char buf[64];
542
543 if (!props)
544 return;
545 while (props->name) {
546 if (props->info->print) {
547 props->info->print(dev, props, buf, sizeof(buf));
548 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
549 }
550 props++;
551 }
552}
553
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100554static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
555{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100556 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200557 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
558 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100559 indent += 2;
560 if (dev->num_gpio_in) {
561 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
562 }
563 if (dev->num_gpio_out) {
564 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
565 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200566 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
567 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200568 if (dev->parent_bus->info->print_dev)
569 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100570 LIST_FOREACH(child, &dev->child_bus, sibling) {
571 qbus_print(mon, child, indent);
572 }
573}
574
575static void qbus_print(Monitor *mon, BusState *bus, int indent)
576{
577 struct DeviceState *dev;
578
579 qdev_printf("bus: %s\n", bus->name);
580 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200581 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100582 LIST_FOREACH(dev, &bus->children, sibling) {
583 qdev_print(mon, dev, indent);
584 }
585}
586#undef qdev_printf
587
588void do_info_qtree(Monitor *mon)
589{
590 if (main_system_bus)
591 qbus_print(mon, main_system_bus, 0);
592}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200593
594void do_info_qdrv(Monitor *mon)
595{
596 DeviceInfo *info;
597 char msg[256];
598
599 for (info = device_info_list; info != NULL; info = info->next) {
600 qdev_print_devinfo(info, msg, sizeof(msg));
601 monitor_printf(mon, "%s\n", msg);
602 }
603}