blob: 1b7d9636ce3022e35e61b9dc51f912e9e475cf58 [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 Hoffmann81a322d2009-08-14 10:36:05 +0200202 if (qdev_init(qdev) != 0) {
203 qdev_free(qdev);
204 return NULL;
205 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200206 return qdev;
207}
208
Paul Brookaae94602009-05-14 22:35:06 +0100209/* Initialize a device. Device properties should be set before calling
210 this function. IRQs and MMIO regions should be connected/mapped after
211 calling this function. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200212int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100213{
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200214 return dev->info->init(dev, dev->info);
Paul Brook02e2da42009-05-23 00:05:19 +0100215}
216
217/* Unlink device from bus and free the structure. */
218void qdev_free(DeviceState *dev)
219{
220 LIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200221 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100222}
223
Paul Brookaae94602009-05-14 22:35:06 +0100224/* Get a character (serial) device interface. */
225CharDriverState *qdev_init_chardev(DeviceState *dev)
226{
227 static int next_serial;
228 static int next_virtconsole;
229 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200230 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100231 return virtcon_hds[next_virtconsole++];
232 } else {
233 return serial_hds[next_serial++];
234 }
235}
236
Paul Brook02e2da42009-05-23 00:05:19 +0100237BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100238{
Paul Brook02e2da42009-05-23 00:05:19 +0100239 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100240}
241
Paul Brookaae94602009-05-14 22:35:06 +0100242void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
243{
244 assert(dev->num_gpio_in == 0);
245 dev->num_gpio_in = n;
246 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
247}
248
249void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
250{
251 assert(dev->num_gpio_out == 0);
252 dev->num_gpio_out = n;
253 dev->gpio_out = pins;
254}
255
256qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
257{
258 assert(n >= 0 && n < dev->num_gpio_in);
259 return dev->gpio_in[n];
260}
261
262void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
263{
264 assert(n >= 0 && n < dev->num_gpio_out);
265 dev->gpio_out[n] = pin;
266}
267
Paul Brook9d07d752009-05-14 22:35:07 +0100268VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100269 NetCanReceive *can_receive,
270 NetReceive *receive,
271 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100272 NetCleanup *cleanup,
273 void *opaque)
274{
275 NICInfo *nd = dev->nd;
276 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100277 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
278 receive, receive_iov, cleanup, opaque);
279 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100280}
281
282
283void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
284{
285 memcpy(macaddr, dev->nd->macaddr, 6);
286}
287
Paul Brookaae94602009-05-14 22:35:06 +0100288static int next_block_unit[IF_COUNT];
289
290/* Get a block device. This should only be used for single-drive devices
291 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
292 appropriate bus. */
293BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
294{
295 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200296 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100297
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200298 dinfo = drive_get(type, 0, unit);
299 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100300}
Paul Brook4d6ae672009-05-14 22:35:06 +0100301
Paul Brook02e2da42009-05-23 00:05:19 +0100302BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100303{
Paul Brook02e2da42009-05-23 00:05:19 +0100304 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100305
Paul Brook02e2da42009-05-23 00:05:19 +0100306 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100307 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100308 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100309 }
310 }
311 return NULL;
312}
313
Paul Brook6f68ecb2009-05-14 22:35:07 +0100314static int next_scsi_bus;
315
316/* Create a scsi bus, and attach devices to it. */
317/* TODO: Actually create a scsi bus for hotplug to use. */
318void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
319{
320 int bus = next_scsi_bus++;
321 int unit;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200322 DriveInfo *dinfo;
Paul Brook6f68ecb2009-05-14 22:35:07 +0100323
324 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200325 dinfo = drive_get(IF_SCSI, bus, unit);
326 if (!dinfo) {
Paul Brook6f68ecb2009-05-14 22:35:07 +0100327 continue;
328 }
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200329 attach(host, dinfo->bdrv, unit);
Paul Brook6f68ecb2009-05-14 22:35:07 +0100330 }
331}
Paul Brook02e2da42009-05-23 00:05:19 +0100332
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200333static BusState *qbus_find_recursive(BusState *bus, const char *name,
334 const BusInfo *info)
335{
336 DeviceState *dev;
337 BusState *child, *ret;
338 int match = 1;
339
340 if (name && (strcmp(bus->name, name) != 0)) {
341 match = 0;
342 }
343 if (info && (bus->info != info)) {
344 match = 0;
345 }
346 if (match) {
347 return bus;
348 }
349
350 LIST_FOREACH(dev, &bus->children, sibling) {
351 LIST_FOREACH(child, &dev->child_bus, sibling) {
352 ret = qbus_find_recursive(child, name, info);
353 if (ret) {
354 return ret;
355 }
356 }
357 }
358 return NULL;
359}
360
361static void qbus_list_bus(DeviceState *dev, char *dest, int len)
362{
363 BusState *child;
364 const char *sep = " ";
365 int pos = 0;
366
367 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
368 dev->id ? dev->id : dev->info->name);
369 LIST_FOREACH(child, &dev->child_bus, sibling) {
370 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
371 sep = ", ";
372 }
373}
374
375static void qbus_list_dev(BusState *bus, char *dest, int len)
376{
377 DeviceState *dev;
378 const char *sep = " ";
379 int pos = 0;
380
381 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
382 bus->name);
383 LIST_FOREACH(dev, &bus->children, sibling) {
384 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
385 sep, dev->info->name);
386 if (dev->id)
387 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
388 sep = ", ";
389 }
390}
391
392static BusState *qbus_find_bus(DeviceState *dev, char *elem)
393{
394 BusState *child;
395
396 LIST_FOREACH(child, &dev->child_bus, sibling) {
397 if (strcmp(child->name, elem) == 0) {
398 return child;
399 }
400 }
401 return NULL;
402}
403
404static DeviceState *qbus_find_dev(BusState *bus, char *elem)
405{
406 DeviceState *dev;
407
408 /*
409 * try to match in order:
410 * (1) instance id, if present
411 * (2) driver name
412 * (3) driver alias, if present
413 */
414 LIST_FOREACH(dev, &bus->children, sibling) {
415 if (dev->id && strcmp(dev->id, elem) == 0) {
416 return dev;
417 }
418 }
419 LIST_FOREACH(dev, &bus->children, sibling) {
420 if (strcmp(dev->info->name, elem) == 0) {
421 return dev;
422 }
423 }
424 LIST_FOREACH(dev, &bus->children, sibling) {
425 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
426 return dev;
427 }
428 }
429 return NULL;
430}
431
432static BusState *qbus_find(const char *path)
433{
434 DeviceState *dev;
435 BusState *bus;
436 char elem[128], msg[256];
437 int pos, len;
438
439 /* find start element */
440 if (path[0] == '/') {
441 bus = main_system_bus;
442 pos = 0;
443 } else {
444 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
445 fprintf(stderr, "path parse error (\"%s\")\n", path);
446 return NULL;
447 }
448 bus = qbus_find_recursive(main_system_bus, elem, NULL);
449 if (!bus) {
450 fprintf(stderr, "bus \"%s\" not found\n", elem);
451 return NULL;
452 }
453 pos = len;
454 }
455
456 for (;;) {
457 if (path[pos] == '\0') {
458 /* we are done */
459 return bus;
460 }
461
462 /* find device */
463 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
464 fprintf(stderr, "path parse error (\"%s\" pos %d)\n", path, pos);
465 return NULL;
466 }
467 pos += len;
468 dev = qbus_find_dev(bus, elem);
469 if (!dev) {
470 qbus_list_dev(bus, msg, sizeof(msg));
471 fprintf(stderr, "device \"%s\" not found\n%s\n", elem, msg);
472 return NULL;
473 }
474 if (path[pos] == '\0') {
475 /* last specified element is a device. If it has exactly
476 * one child bus accept it nevertheless */
477 switch (dev->num_child_bus) {
478 case 0:
479 fprintf(stderr, "device has no child bus (%s)\n", path);
480 return NULL;
481 case 1:
482 return LIST_FIRST(&dev->child_bus);
483 default:
484 qbus_list_bus(dev, msg, sizeof(msg));
485 fprintf(stderr, "device has multiple child busses (%s)\n%s\n",
486 path, msg);
487 return NULL;
488 }
489 }
490
491 /* find bus */
492 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
493 fprintf(stderr, "path parse error (\"%s\" pos %d)\n", path, pos);
494 return NULL;
495 }
496 pos += len;
497 bus = qbus_find_bus(dev, elem);
498 if (!bus) {
499 qbus_list_bus(dev, msg, sizeof(msg));
500 fprintf(stderr, "child bus \"%s\" not found\n%s\n", elem, msg);
501 return NULL;
502 }
503 }
504}
505
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200506BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100507{
508 BusState *bus;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200509 char *buf;
510 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100511
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200512 bus = qemu_mallocz(info->size);
513 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100514 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200515
516 if (name) {
517 /* use supplied name */
518 bus->name = qemu_strdup(name);
519 } else if (parent && parent->id) {
520 /* parent device has id -> use it for bus name */
521 len = strlen(parent->id) + 16;
522 buf = qemu_malloc(len);
523 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
524 bus->name = buf;
525 } else {
526 /* no id -> use lowercase bus type for bus name */
527 len = strlen(info->name) + 16;
528 buf = qemu_malloc(len);
529 len = snprintf(buf, len, "%s.%d", info->name,
530 parent ? parent->num_child_bus : 0);
531 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200532 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200533 bus->name = buf;
534 }
535
Paul Brook02e2da42009-05-23 00:05:19 +0100536 LIST_INIT(&bus->children);
537 if (parent) {
538 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200539 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100540 }
541 return bus;
542}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100543
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100544#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
545static void qbus_print(Monitor *mon, BusState *bus, int indent);
546
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200547static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
548 const char *prefix, int indent)
549{
550 char buf[64];
551
552 if (!props)
553 return;
554 while (props->name) {
555 if (props->info->print) {
556 props->info->print(dev, props, buf, sizeof(buf));
557 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
558 }
559 props++;
560 }
561}
562
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100563static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
564{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100565 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200566 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
567 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100568 indent += 2;
569 if (dev->num_gpio_in) {
570 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
571 }
572 if (dev->num_gpio_out) {
573 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
574 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200575 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
576 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200577 if (dev->parent_bus->info->print_dev)
578 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100579 LIST_FOREACH(child, &dev->child_bus, sibling) {
580 qbus_print(mon, child, indent);
581 }
582}
583
584static void qbus_print(Monitor *mon, BusState *bus, int indent)
585{
586 struct DeviceState *dev;
587
588 qdev_printf("bus: %s\n", bus->name);
589 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200590 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100591 LIST_FOREACH(dev, &bus->children, sibling) {
592 qdev_print(mon, dev, indent);
593 }
594}
595#undef qdev_printf
596
597void do_info_qtree(Monitor *mon)
598{
599 if (main_system_bus)
600 qbus_print(mon, main_system_bus, 0);
601}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200602
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200603void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200604{
605 DeviceInfo *info;
606 char msg[256];
607
608 for (info = device_info_list; info != NULL; info = info->next) {
609 qdev_print_devinfo(info, msg, sizeof(msg));
610 monitor_printf(mon, "%s\n", msg);
611 }
612}