blob: c1a77790019935120effa48fca46c6498fbc9ef9 [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)) {
141 fprintf(stderr, "can't set property \"%s\" to \"%s\" for \"%s\"\n",
142 name, value, dev->info->name);
143 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) {
157 fprintf(stderr, "-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));
164 fprintf(stderr, "%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) {
172 fprintf(stderr, "Device \"%s\" not found. Try -device '?' for a list.\n",
173 driver);
174 return NULL;
175 }
176 if (info->no_user) {
177 fprintf(stderr, "device \"%s\" can't be added via command line\n",
178 info->name);
179 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 Hoffmannf31d07d2009-07-31 12:25:37 +0200189 if (!bus)
190 return NULL;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200191
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200192 /* create device, set properties */
193 qdev = qdev_create(bus, driver);
194 id = qemu_opts_id(opts);
195 if (id) {
196 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200197 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200198 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
199 qdev_free(qdev);
200 return NULL;
201 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200202 qdev_init(qdev);
203 return qdev;
204}
205
Paul Brookaae94602009-05-14 22:35:06 +0100206/* Initialize a device. Device properties should be set before calling
207 this function. IRQs and MMIO regions should be connected/mapped after
208 calling this function. */
209void qdev_init(DeviceState *dev)
210{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200211 dev->info->init(dev, dev->info);
Paul Brook02e2da42009-05-23 00:05:19 +0100212}
213
214/* Unlink device from bus and free the structure. */
215void qdev_free(DeviceState *dev)
216{
217 LIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200218 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100219}
220
Paul Brookaae94602009-05-14 22:35:06 +0100221/* Get a character (serial) device interface. */
222CharDriverState *qdev_init_chardev(DeviceState *dev)
223{
224 static int next_serial;
225 static int next_virtconsole;
226 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200227 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100228 return virtcon_hds[next_virtconsole++];
229 } else {
230 return serial_hds[next_serial++];
231 }
232}
233
Paul Brook02e2da42009-05-23 00:05:19 +0100234BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100235{
Paul Brook02e2da42009-05-23 00:05:19 +0100236 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100237}
238
Paul Brookaae94602009-05-14 22:35:06 +0100239void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
240{
241 assert(dev->num_gpio_in == 0);
242 dev->num_gpio_in = n;
243 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
244}
245
246void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
247{
248 assert(dev->num_gpio_out == 0);
249 dev->num_gpio_out = n;
250 dev->gpio_out = pins;
251}
252
253qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
254{
255 assert(n >= 0 && n < dev->num_gpio_in);
256 return dev->gpio_in[n];
257}
258
259void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
260{
261 assert(n >= 0 && n < dev->num_gpio_out);
262 dev->gpio_out[n] = pin;
263}
264
Paul Brook9d07d752009-05-14 22:35:07 +0100265VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100266 NetCanReceive *can_receive,
267 NetReceive *receive,
268 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100269 NetCleanup *cleanup,
270 void *opaque)
271{
272 NICInfo *nd = dev->nd;
273 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100274 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
275 receive, receive_iov, cleanup, opaque);
276 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100277}
278
279
280void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
281{
282 memcpy(macaddr, dev->nd->macaddr, 6);
283}
284
Paul Brookaae94602009-05-14 22:35:06 +0100285static int next_block_unit[IF_COUNT];
286
287/* Get a block device. This should only be used for single-drive devices
288 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
289 appropriate bus. */
290BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
291{
292 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200293 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100294
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200295 dinfo = drive_get(type, 0, unit);
296 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100297}
Paul Brook4d6ae672009-05-14 22:35:06 +0100298
Paul Brook02e2da42009-05-23 00:05:19 +0100299BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100300{
Paul Brook02e2da42009-05-23 00:05:19 +0100301 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100302
Paul Brook02e2da42009-05-23 00:05:19 +0100303 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100304 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100305 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100306 }
307 }
308 return NULL;
309}
310
Paul Brook6f68ecb2009-05-14 22:35:07 +0100311static int next_scsi_bus;
312
313/* Create a scsi bus, and attach devices to it. */
314/* TODO: Actually create a scsi bus for hotplug to use. */
315void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
316{
317 int bus = next_scsi_bus++;
318 int unit;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200319 DriveInfo *dinfo;
Paul Brook6f68ecb2009-05-14 22:35:07 +0100320
321 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200322 dinfo = drive_get(IF_SCSI, bus, unit);
323 if (!dinfo) {
Paul Brook6f68ecb2009-05-14 22:35:07 +0100324 continue;
325 }
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200326 attach(host, dinfo->bdrv, unit);
Paul Brook6f68ecb2009-05-14 22:35:07 +0100327 }
328}
Paul Brook02e2da42009-05-23 00:05:19 +0100329
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200330static BusState *qbus_find_recursive(BusState *bus, const char *name,
331 const BusInfo *info)
332{
333 DeviceState *dev;
334 BusState *child, *ret;
335 int match = 1;
336
337 if (name && (strcmp(bus->name, name) != 0)) {
338 match = 0;
339 }
340 if (info && (bus->info != info)) {
341 match = 0;
342 }
343 if (match) {
344 return bus;
345 }
346
347 LIST_FOREACH(dev, &bus->children, sibling) {
348 LIST_FOREACH(child, &dev->child_bus, sibling) {
349 ret = qbus_find_recursive(child, name, info);
350 if (ret) {
351 return ret;
352 }
353 }
354 }
355 return NULL;
356}
357
358static void qbus_list_bus(DeviceState *dev, char *dest, int len)
359{
360 BusState *child;
361 const char *sep = " ";
362 int pos = 0;
363
364 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
365 dev->id ? dev->id : dev->info->name);
366 LIST_FOREACH(child, &dev->child_bus, sibling) {
367 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
368 sep = ", ";
369 }
370}
371
372static void qbus_list_dev(BusState *bus, char *dest, int len)
373{
374 DeviceState *dev;
375 const char *sep = " ";
376 int pos = 0;
377
378 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
379 bus->name);
380 LIST_FOREACH(dev, &bus->children, sibling) {
381 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
382 sep, dev->info->name);
383 if (dev->id)
384 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
385 sep = ", ";
386 }
387}
388
389static BusState *qbus_find_bus(DeviceState *dev, char *elem)
390{
391 BusState *child;
392
393 LIST_FOREACH(child, &dev->child_bus, sibling) {
394 if (strcmp(child->name, elem) == 0) {
395 return child;
396 }
397 }
398 return NULL;
399}
400
401static DeviceState *qbus_find_dev(BusState *bus, char *elem)
402{
403 DeviceState *dev;
404
405 /*
406 * try to match in order:
407 * (1) instance id, if present
408 * (2) driver name
409 * (3) driver alias, if present
410 */
411 LIST_FOREACH(dev, &bus->children, sibling) {
412 if (dev->id && strcmp(dev->id, elem) == 0) {
413 return dev;
414 }
415 }
416 LIST_FOREACH(dev, &bus->children, sibling) {
417 if (strcmp(dev->info->name, elem) == 0) {
418 return dev;
419 }
420 }
421 LIST_FOREACH(dev, &bus->children, sibling) {
422 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
423 return dev;
424 }
425 }
426 return NULL;
427}
428
429static BusState *qbus_find(const char *path)
430{
431 DeviceState *dev;
432 BusState *bus;
433 char elem[128], msg[256];
434 int pos, len;
435
436 /* find start element */
437 if (path[0] == '/') {
438 bus = main_system_bus;
439 pos = 0;
440 } else {
441 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
442 fprintf(stderr, "path parse error (\"%s\")\n", path);
443 return NULL;
444 }
445 bus = qbus_find_recursive(main_system_bus, elem, NULL);
446 if (!bus) {
447 fprintf(stderr, "bus \"%s\" not found\n", elem);
448 return NULL;
449 }
450 pos = len;
451 }
452
453 for (;;) {
454 if (path[pos] == '\0') {
455 /* we are done */
456 return bus;
457 }
458
459 /* find device */
460 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
461 fprintf(stderr, "path parse error (\"%s\" pos %d)\n", path, pos);
462 return NULL;
463 }
464 pos += len;
465 dev = qbus_find_dev(bus, elem);
466 if (!dev) {
467 qbus_list_dev(bus, msg, sizeof(msg));
468 fprintf(stderr, "device \"%s\" not found\n%s\n", elem, msg);
469 return NULL;
470 }
471 if (path[pos] == '\0') {
472 /* last specified element is a device. If it has exactly
473 * one child bus accept it nevertheless */
474 switch (dev->num_child_bus) {
475 case 0:
476 fprintf(stderr, "device has no child bus (%s)\n", path);
477 return NULL;
478 case 1:
479 return LIST_FIRST(&dev->child_bus);
480 default:
481 qbus_list_bus(dev, msg, sizeof(msg));
482 fprintf(stderr, "device has multiple child busses (%s)\n%s\n",
483 path, msg);
484 return NULL;
485 }
486 }
487
488 /* find bus */
489 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
490 fprintf(stderr, "path parse error (\"%s\" pos %d)\n", path, pos);
491 return NULL;
492 }
493 pos += len;
494 bus = qbus_find_bus(dev, elem);
495 if (!bus) {
496 qbus_list_bus(dev, msg, sizeof(msg));
497 fprintf(stderr, "child bus \"%s\" not found\n%s\n", elem, msg);
498 return NULL;
499 }
500 }
501}
502
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200503BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100504{
505 BusState *bus;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200506 char *buf;
507 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100508
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200509 bus = qemu_mallocz(info->size);
510 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100511 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200512
513 if (name) {
514 /* use supplied name */
515 bus->name = qemu_strdup(name);
516 } else if (parent && parent->id) {
517 /* parent device has id -> use it for bus name */
518 len = strlen(parent->id) + 16;
519 buf = qemu_malloc(len);
520 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
521 bus->name = buf;
522 } else {
523 /* no id -> use lowercase bus type for bus name */
524 len = strlen(info->name) + 16;
525 buf = qemu_malloc(len);
526 len = snprintf(buf, len, "%s.%d", info->name,
527 parent ? parent->num_child_bus : 0);
528 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200529 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200530 bus->name = buf;
531 }
532
Paul Brook02e2da42009-05-23 00:05:19 +0100533 LIST_INIT(&bus->children);
534 if (parent) {
535 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200536 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100537 }
538 return bus;
539}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100540
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100541#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
542static void qbus_print(Monitor *mon, BusState *bus, int indent);
543
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200544static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
545 const char *prefix, int indent)
546{
547 char buf[64];
548
549 if (!props)
550 return;
551 while (props->name) {
552 if (props->info->print) {
553 props->info->print(dev, props, buf, sizeof(buf));
554 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
555 }
556 props++;
557 }
558}
559
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100560static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
561{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100562 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200563 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
564 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100565 indent += 2;
566 if (dev->num_gpio_in) {
567 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
568 }
569 if (dev->num_gpio_out) {
570 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
571 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200572 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
573 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200574 if (dev->parent_bus->info->print_dev)
575 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100576 LIST_FOREACH(child, &dev->child_bus, sibling) {
577 qbus_print(mon, child, indent);
578 }
579}
580
581static void qbus_print(Monitor *mon, BusState *bus, int indent)
582{
583 struct DeviceState *dev;
584
585 qdev_printf("bus: %s\n", bus->name);
586 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200587 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100588 LIST_FOREACH(dev, &bus->children, sibling) {
589 qdev_print(mon, dev, indent);
590 }
591}
592#undef qdev_printf
593
594void do_info_qtree(Monitor *mon)
595{
596 if (main_system_bus)
597 qbus_print(mon, main_system_bus, 0);
598}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200599
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200600void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200601{
602 DeviceInfo *info;
603 char msg[256];
604
605 for (info = device_info_list; info != NULL; info = info->next) {
606 qdev_print_devinfo(info, msg, sizeof(msg));
607 monitor_printf(mon, "%s\n", msg);
608 }
609}