blob: 064389dcd032b3044356d9227d20c5e86ccfa84d [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);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000104 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200105 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +0100106 return dev;
107}
108
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200109static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
110{
111 int pos = 0;
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200112 int ret;
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200113
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200114 ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
115 info->name, info->bus_info->name);
116 pos += MIN(len-pos,ret);
117 if (info->alias) {
118 ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
119 pos += MIN(len-pos,ret);
120 }
121 if (info->desc) {
122 ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
123 pos += MIN(len-pos,ret);
124 }
125 if (info->no_user) {
126 ret = snprintf(dest+pos, len-pos, ", no-user");
127 pos += MIN(len-pos,ret);
128 }
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200129 return pos;
130}
131
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200132static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200133{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200134 DeviceState *dev = opaque;
135
136 if (strcmp(name, "driver") == 0)
137 return 0;
138 if (strcmp(name, "bus") == 0)
139 return 0;
140
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100141 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200142 qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
143 name, value, dev->info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200144 return -1;
145 }
146 return 0;
147}
148
149DeviceState *qdev_device_add(QemuOpts *opts)
150{
151 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200152 DeviceInfo *info;
153 DeviceState *qdev;
154 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200155
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200156 driver = qemu_opt_get(opts, "driver");
157 if (!driver) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200158 qemu_error("-device: no driver specified\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200159 return NULL;
160 }
161 if (strcmp(driver, "?") == 0) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200162 char msg[256];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200163 for (info = device_info_list; info != NULL; info = info->next) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200164 qdev_print_devinfo(info, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200165 qemu_error("%s\n", msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200166 }
167 return NULL;
168 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200169
170 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200171 info = qdev_find_info(NULL, driver);
172 if (!info) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200173 qemu_error("Device \"%s\" not found. Try -device '?' for a list.\n",
174 driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200175 return NULL;
176 }
177 if (info->no_user) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200178 qemu_error("device \"%s\" can't be added via command line\n",
179 info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200180 return NULL;
181 }
182
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200183 /* find bus */
184 path = qemu_opt_get(opts, "bus");
185 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200186 bus = qbus_find(path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200187 } else {
188 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200189 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200190 if (!bus) {
191 qemu_error("Did not find %s bus for %s\n",
192 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200193 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200194 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200195
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200196 /* create device, set properties */
197 qdev = qdev_create(bus, driver);
198 id = qemu_opts_id(opts);
199 if (id) {
200 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200201 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200202 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
203 qdev_free(qdev);
204 return NULL;
205 }
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200206 if (qdev_init(qdev) != 0) {
207 qdev_free(qdev);
208 return NULL;
209 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200210 return qdev;
211}
212
Paul Brookaae94602009-05-14 22:35:06 +0100213/* Initialize a device. Device properties should be set before calling
214 this function. IRQs and MMIO regions should be connected/mapped after
215 calling this function. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200216int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100217{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200218 int rc;
219
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200220 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200221 rc = dev->info->init(dev, dev->info);
222 if (rc < 0)
223 return rc;
224 if (dev->info->reset)
225 qemu_register_reset(dev->info->reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200226 if (dev->info->vmsd)
227 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200228 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200229 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100230}
231
232/* Unlink device from bus and free the structure. */
233void qdev_free(DeviceState *dev)
234{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200235 BusState *bus;
236
237 if (dev->state == DEV_STATE_INITIALIZED) {
238 while (dev->num_child_bus) {
239 bus = QLIST_FIRST(&dev->child_bus);
240 qbus_free(bus);
241 }
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200242#if 0 /* FIXME: need sane vmstate_unregister function */
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200243 if (dev->info->vmsd)
244 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200245#endif
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200246 if (dev->info->reset)
247 qemu_unregister_reset(dev->info->reset, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200248 if (dev->info->exit)
249 dev->info->exit(dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200250 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000251 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200252 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100253}
254
Paul Brookaae94602009-05-14 22:35:06 +0100255/* Get a character (serial) device interface. */
256CharDriverState *qdev_init_chardev(DeviceState *dev)
257{
258 static int next_serial;
259 static int next_virtconsole;
260 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200261 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100262 return virtcon_hds[next_virtconsole++];
263 } else {
264 return serial_hds[next_serial++];
265 }
266}
267
Paul Brook02e2da42009-05-23 00:05:19 +0100268BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100269{
Paul Brook02e2da42009-05-23 00:05:19 +0100270 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100271}
272
Paul Brookaae94602009-05-14 22:35:06 +0100273void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
274{
275 assert(dev->num_gpio_in == 0);
276 dev->num_gpio_in = n;
277 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
278}
279
280void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
281{
282 assert(dev->num_gpio_out == 0);
283 dev->num_gpio_out = n;
284 dev->gpio_out = pins;
285}
286
287qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
288{
289 assert(n >= 0 && n < dev->num_gpio_in);
290 return dev->gpio_in[n];
291}
292
293void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
294{
295 assert(n >= 0 && n < dev->num_gpio_out);
296 dev->gpio_out[n] = pin;
297}
298
Paul Brook9d07d752009-05-14 22:35:07 +0100299VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100300 NetCanReceive *can_receive,
301 NetReceive *receive,
302 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100303 NetCleanup *cleanup,
304 void *opaque)
305{
306 NICInfo *nd = dev->nd;
307 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100308 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
309 receive, receive_iov, cleanup, opaque);
310 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100311}
312
313
314void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
315{
316 memcpy(macaddr, dev->nd->macaddr, 6);
317}
318
Paul Brookaae94602009-05-14 22:35:06 +0100319static int next_block_unit[IF_COUNT];
320
321/* Get a block device. This should only be used for single-drive devices
322 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
323 appropriate bus. */
324BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
325{
326 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200327 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100328
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200329 dinfo = drive_get(type, 0, unit);
330 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100331}
Paul Brook4d6ae672009-05-14 22:35:06 +0100332
Paul Brook02e2da42009-05-23 00:05:19 +0100333BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100334{
Paul Brook02e2da42009-05-23 00:05:19 +0100335 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100336
Blue Swirl72cf2d42009-09-12 07:36:22 +0000337 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100338 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100339 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100340 }
341 }
342 return NULL;
343}
344
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200345static BusState *qbus_find_recursive(BusState *bus, const char *name,
346 const BusInfo *info)
347{
348 DeviceState *dev;
349 BusState *child, *ret;
350 int match = 1;
351
352 if (name && (strcmp(bus->name, name) != 0)) {
353 match = 0;
354 }
355 if (info && (bus->info != info)) {
356 match = 0;
357 }
358 if (match) {
359 return bus;
360 }
361
Blue Swirl72cf2d42009-09-12 07:36:22 +0000362 QLIST_FOREACH(dev, &bus->children, sibling) {
363 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200364 ret = qbus_find_recursive(child, name, info);
365 if (ret) {
366 return ret;
367 }
368 }
369 }
370 return NULL;
371}
372
373static void qbus_list_bus(DeviceState *dev, char *dest, int len)
374{
375 BusState *child;
376 const char *sep = " ";
377 int pos = 0;
378
379 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
380 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000381 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200382 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
383 sep = ", ";
384 }
385}
386
387static void qbus_list_dev(BusState *bus, char *dest, int len)
388{
389 DeviceState *dev;
390 const char *sep = " ";
391 int pos = 0;
392
393 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
394 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000395 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200396 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
397 sep, dev->info->name);
398 if (dev->id)
399 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
400 sep = ", ";
401 }
402}
403
404static BusState *qbus_find_bus(DeviceState *dev, char *elem)
405{
406 BusState *child;
407
Blue Swirl72cf2d42009-09-12 07:36:22 +0000408 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200409 if (strcmp(child->name, elem) == 0) {
410 return child;
411 }
412 }
413 return NULL;
414}
415
416static DeviceState *qbus_find_dev(BusState *bus, char *elem)
417{
418 DeviceState *dev;
419
420 /*
421 * try to match in order:
422 * (1) instance id, if present
423 * (2) driver name
424 * (3) driver alias, if present
425 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000426 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200427 if (dev->id && strcmp(dev->id, elem) == 0) {
428 return dev;
429 }
430 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000431 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200432 if (strcmp(dev->info->name, elem) == 0) {
433 return dev;
434 }
435 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000436 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200437 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
438 return dev;
439 }
440 }
441 return NULL;
442}
443
444static BusState *qbus_find(const char *path)
445{
446 DeviceState *dev;
447 BusState *bus;
448 char elem[128], msg[256];
449 int pos, len;
450
451 /* find start element */
452 if (path[0] == '/') {
453 bus = main_system_bus;
454 pos = 0;
455 } else {
456 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200457 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200458 return NULL;
459 }
460 bus = qbus_find_recursive(main_system_bus, elem, NULL);
461 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200462 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200463 return NULL;
464 }
465 pos = len;
466 }
467
468 for (;;) {
469 if (path[pos] == '\0') {
470 /* we are done */
471 return bus;
472 }
473
474 /* find device */
475 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200476 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200477 return NULL;
478 }
479 pos += len;
480 dev = qbus_find_dev(bus, elem);
481 if (!dev) {
482 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200483 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200484 return NULL;
485 }
486 if (path[pos] == '\0') {
487 /* last specified element is a device. If it has exactly
488 * one child bus accept it nevertheless */
489 switch (dev->num_child_bus) {
490 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200491 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200492 return NULL;
493 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000494 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200495 default:
496 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200497 qemu_error("device has multiple child busses (%s)\n%s\n",
498 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200499 return NULL;
500 }
501 }
502
503 /* find bus */
504 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200505 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200506 return NULL;
507 }
508 pos += len;
509 bus = qbus_find_bus(dev, elem);
510 if (!bus) {
511 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200512 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200513 return NULL;
514 }
515 }
516}
517
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200518void qbus_create_inplace(BusState *bus, BusInfo *info,
519 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100520{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200521 char *buf;
522 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100523
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200524 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100525 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200526
527 if (name) {
528 /* use supplied name */
529 bus->name = qemu_strdup(name);
530 } else if (parent && parent->id) {
531 /* parent device has id -> use it for bus name */
532 len = strlen(parent->id) + 16;
533 buf = qemu_malloc(len);
534 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
535 bus->name = buf;
536 } else {
537 /* no id -> use lowercase bus type for bus name */
538 len = strlen(info->name) + 16;
539 buf = qemu_malloc(len);
540 len = snprintf(buf, len, "%s.%d", info->name,
541 parent ? parent->num_child_bus : 0);
542 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200543 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200544 bus->name = buf;
545 }
546
Blue Swirl72cf2d42009-09-12 07:36:22 +0000547 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100548 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000549 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200550 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100551 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200552
553}
554
555BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
556{
557 BusState *bus;
558
559 bus = qemu_mallocz(info->size);
560 bus->qdev_allocated = 1;
561 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100562 return bus;
563}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100564
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200565void qbus_free(BusState *bus)
566{
567 DeviceState *dev;
568
569 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
570 qdev_free(dev);
571 }
572 if (bus->parent) {
573 QLIST_REMOVE(bus, sibling);
574 bus->parent->num_child_bus--;
575 }
576 if (bus->qdev_allocated) {
577 qemu_free(bus);
578 }
579}
580
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100581#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
582static void qbus_print(Monitor *mon, BusState *bus, int indent);
583
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200584static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
585 const char *prefix, int indent)
586{
587 char buf[64];
588
589 if (!props)
590 return;
591 while (props->name) {
592 if (props->info->print) {
593 props->info->print(dev, props, buf, sizeof(buf));
594 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
595 }
596 props++;
597 }
598}
599
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100600static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
601{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100602 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200603 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
604 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100605 indent += 2;
606 if (dev->num_gpio_in) {
607 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
608 }
609 if (dev->num_gpio_out) {
610 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
611 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200612 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
613 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200614 if (dev->parent_bus->info->print_dev)
615 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000616 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100617 qbus_print(mon, child, indent);
618 }
619}
620
621static void qbus_print(Monitor *mon, BusState *bus, int indent)
622{
623 struct DeviceState *dev;
624
625 qdev_printf("bus: %s\n", bus->name);
626 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200627 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000628 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100629 qdev_print(mon, dev, indent);
630 }
631}
632#undef qdev_printf
633
634void do_info_qtree(Monitor *mon)
635{
636 if (main_system_bus)
637 qbus_print(mon, main_system_bus, 0);
638}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200639
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200640void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200641{
642 DeviceInfo *info;
643 char msg[256];
644
645 for (info = device_info_list; info != NULL; info = info->next) {
646 qdev_print_devinfo(info, msg, sizeof(msg));
647 monitor_printf(mon, "%s\n", msg);
648 }
649}