blob: de60108b1aaed237c79f06759a2c05d054567a89 [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"
Luiz Capitulino3ced9f72009-11-18 23:05:33 -020032#include "qerror.h"
Paul Brookaae94602009-05-14 22:35:06 +010033
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020034static int qdev_hotplug = 0;
35
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020036/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000037static BusState *main_system_bus;
Paul Brook4d6ae672009-05-14 22:35:06 +010038
Gerd Hoffmann0958b4c2009-10-26 15:56:45 +010039DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010040
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020041static BusState *qbus_find_recursive(BusState *bus, const char *name,
42 const BusInfo *info);
43static BusState *qbus_find(const char *path);
44
Paul Brookaae94602009-05-14 22:35:06 +010045/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020046void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010047{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020048 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020049 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010050
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020051 info->next = device_info_list;
52 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010053}
54
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020055static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
56{
57 DeviceInfo *info;
58
Gerd Hoffmann3320e562009-07-15 13:43:33 +020059 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020060 for (info = device_info_list; info != NULL; info = info->next) {
61 if (bus_info && info->bus_info != bus_info)
62 continue;
63 if (strcmp(info->name, name) != 0)
64 continue;
65 return info;
66 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020067
68 /* failing that check the aliases */
69 for (info = device_info_list; info != NULL; info = info->next) {
70 if (bus_info && info->bus_info != bus_info)
71 continue;
72 if (!info->alias)
73 continue;
74 if (strcmp(info->alias, name) != 0)
75 continue;
76 return info;
77 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020078 return NULL;
79}
80
Markus Armbruster0c175422010-02-19 19:12:18 +010081static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010082{
Paul Brookaae94602009-05-14 22:35:06 +010083 DeviceState *dev;
84
Markus Armbruster0c175422010-02-19 19:12:18 +010085 assert(bus->info == info->bus_info);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020086 dev = qemu_mallocz(info->size);
87 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010088 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020089 qdev_prop_set_defaults(dev, dev->info->props);
90 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +010091 qdev_prop_set_globals(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +000092 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020093 if (qdev_hotplug) {
94 assert(bus->allow_hotplug);
95 dev->hotplugged = 1;
96 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +020097 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +010098 return dev;
99}
100
Markus Armbruster0c175422010-02-19 19:12:18 +0100101/* Create a new device. This only initializes the device state structure
102 and allows properties to be set. qdev_init should be called to
103 initialize the actual device emulation. */
104DeviceState *qdev_create(BusState *bus, const char *name)
105{
106 DeviceInfo *info;
107
108 if (!bus) {
109 if (!main_system_bus) {
110 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
111 }
112 bus = main_system_bus;
113 }
114
115 info = qdev_find_info(bus->info, name);
116 if (!info) {
117 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
118 }
119
120 return qdev_create_from_info(bus, info);
121}
122
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100123static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200124{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100125 error_printf("name \"%s\", bus %s",
126 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200127 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100128 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200129 }
130 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100131 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200132 }
133 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100134 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200135 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100136 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200137}
138
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200139static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200140{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200141 DeviceState *dev = opaque;
142
143 if (strcmp(name, "driver") == 0)
144 return 0;
145 if (strcmp(name, "bus") == 0)
146 return 0;
147
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100148 if (qdev_prop_parse(dev, name, value) == -1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100149 error_report("can't set property \"%s\" to \"%s\" for \"%s\"",
150 name, value, dev->info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200151 return -1;
152 }
153 return 0;
154}
155
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100156int qdev_device_help(QemuOpts *opts)
157{
158 const char *driver;
159 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100160 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100161
162 driver = qemu_opt_get(opts, "driver");
163 if (driver && !strcmp(driver, "?")) {
164 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100165 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100166 }
167 return 1;
168 }
169
Markus Armbruster08350cf2010-01-29 19:49:00 +0100170 if (!qemu_opt_get(opts, "?")) {
171 return 0;
172 }
173
174 info = qdev_find_info(NULL, driver);
175 if (!info) {
176 return 0;
177 }
178
179 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100180 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100181 }
182 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100183}
184
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200185DeviceState *qdev_device_add(QemuOpts *opts)
186{
187 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200188 DeviceInfo *info;
189 DeviceState *qdev;
190 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200191
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200192 driver = qemu_opt_get(opts, "driver");
193 if (!driver) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100194 error_report("-device: no driver specified");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200195 return NULL;
196 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200197
198 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200199 info = qdev_find_info(NULL, driver);
200 if (!info) {
Markus Armbrusterab5b0272010-03-02 18:15:09 +0100201 qerror_report(QERR_DEVICE_NOT_FOUND, driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200202 return NULL;
203 }
204 if (info->no_user) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100205 error_report("device \"%s\" can't be added via command line",
206 info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200207 return NULL;
208 }
209
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200210 /* find bus */
211 path = qemu_opt_get(opts, "bus");
212 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200213 bus = qbus_find(path);
Markus Armbruster327867b2010-02-19 19:08:45 +0100214 if (bus && bus->info != info->bus_info) {
215 error_report("Device '%s' can't go on a %s bus",
216 driver, bus->info->name);
217 return NULL;
218 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200219 } else {
220 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200221 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200222 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100223 error_report("Did not find %s bus for %s",
224 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200225 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200226 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200227 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100228 error_report("Bus %s does not support hotplugging",
229 bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200230 return NULL;
231 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200232
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200233 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100234 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200235 id = qemu_opts_id(opts);
236 if (id) {
237 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200238 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200239 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
240 qdev_free(qdev);
241 return NULL;
242 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200243 if (qdev_init(qdev) < 0) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100244 error_report("Error initializing device %s", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200245 return NULL;
246 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200247 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200248 return qdev;
249}
250
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300251static void qdev_reset(void *opaque)
252{
253 DeviceState *dev = opaque;
254 if (dev->info->reset)
255 dev->info->reset(dev);
256}
257
Paul Brookaae94602009-05-14 22:35:06 +0100258/* Initialize a device. Device properties should be set before calling
259 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200260 calling this function.
261 On failure, destroy the device and return negative value.
262 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200263int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100264{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200265 int rc;
266
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200267 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200268 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200269 if (rc < 0) {
270 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200271 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200272 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300273 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200274 if (dev->info->vmsd)
275 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200276 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200277 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100278}
279
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200280int qdev_unplug(DeviceState *dev)
281{
282 if (!dev->parent_bus->allow_hotplug) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100283 error_report("Bus %s does not support hotplugging",
284 dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200285 return -1;
286 }
Amit Shah593831d2009-11-02 14:56:41 +0530287 assert(dev->info->unplug != NULL);
288
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200289 return dev->info->unplug(dev);
290}
291
292/* can be used as ->unplug() callback for the simple cases */
293int qdev_simple_unplug_cb(DeviceState *dev)
294{
295 /* just zap it */
296 qdev_free(dev);
297 return 0;
298}
299
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200300/* Like qdev_init(), but terminate program via hw_error() instead of
301 returning an error value. This is okay during machine creation.
302 Don't use for hotplug, because there callers need to recover from
303 failure. Exception: if you know the device's init() callback can't
304 fail, then qdev_init_nofail() can't fail either, and is therefore
305 usable even then. But relying on the device implementation that
306 way is somewhat unclean, and best avoided. */
307void qdev_init_nofail(DeviceState *dev)
308{
309 DeviceInfo *info = dev->info;
310
311 if (qdev_init(dev) < 0)
312 hw_error("Initialization of device %s failed\n", info->name);
313}
314
Paul Brook02e2da42009-05-23 00:05:19 +0100315/* Unlink device from bus and free the structure. */
316void qdev_free(DeviceState *dev)
317{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200318 BusState *bus;
319
320 if (dev->state == DEV_STATE_INITIALIZED) {
321 while (dev->num_child_bus) {
322 bus = QLIST_FIRST(&dev->child_bus);
323 qbus_free(bus);
324 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200325 if (dev->info->vmsd)
326 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200327 if (dev->info->exit)
328 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200329 if (dev->opts)
330 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200331 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300332 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000333 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200334 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100335}
336
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200337void qdev_machine_creation_done(void)
338{
339 /*
340 * ok, initial machine setup is done, starting from now we can
341 * only create hotpluggable devices
342 */
343 qdev_hotplug = 1;
344}
345
Paul Brookaae94602009-05-14 22:35:06 +0100346/* Get a character (serial) device interface. */
347CharDriverState *qdev_init_chardev(DeviceState *dev)
348{
349 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530350
351 /* FIXME: This function needs to go away: use chardev properties! */
352 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100353}
354
Paul Brook02e2da42009-05-23 00:05:19 +0100355BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100356{
Paul Brook02e2da42009-05-23 00:05:19 +0100357 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100358}
359
Paul Brookaae94602009-05-14 22:35:06 +0100360void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
361{
362 assert(dev->num_gpio_in == 0);
363 dev->num_gpio_in = n;
364 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
365}
366
367void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
368{
369 assert(dev->num_gpio_out == 0);
370 dev->num_gpio_out = n;
371 dev->gpio_out = pins;
372}
373
374qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
375{
376 assert(n >= 0 && n < dev->num_gpio_in);
377 return dev->gpio_in[n];
378}
379
380void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
381{
382 assert(n >= 0 && n < dev->num_gpio_out);
383 dev->gpio_out[n] = pin;
384}
385
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200386void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
387{
388 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
389 if (nd->vlan)
390 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
391 if (nd->netdev)
392 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530393 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200394 qdev_prop_exists(dev, "vectors")) {
395 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
396 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200397}
398
Paul Brookaae94602009-05-14 22:35:06 +0100399static int next_block_unit[IF_COUNT];
400
401/* Get a block device. This should only be used for single-drive devices
402 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
403 appropriate bus. */
404BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
405{
406 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200407 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100408
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200409 dinfo = drive_get(type, 0, unit);
410 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100411}
Paul Brook4d6ae672009-05-14 22:35:06 +0100412
Paul Brook02e2da42009-05-23 00:05:19 +0100413BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100414{
Paul Brook02e2da42009-05-23 00:05:19 +0100415 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100416
Blue Swirl72cf2d42009-09-12 07:36:22 +0000417 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100418 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100419 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100420 }
421 }
422 return NULL;
423}
424
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200425static BusState *qbus_find_recursive(BusState *bus, const char *name,
426 const BusInfo *info)
427{
428 DeviceState *dev;
429 BusState *child, *ret;
430 int match = 1;
431
432 if (name && (strcmp(bus->name, name) != 0)) {
433 match = 0;
434 }
435 if (info && (bus->info != info)) {
436 match = 0;
437 }
438 if (match) {
439 return bus;
440 }
441
Blue Swirl72cf2d42009-09-12 07:36:22 +0000442 QLIST_FOREACH(dev, &bus->children, sibling) {
443 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200444 ret = qbus_find_recursive(child, name, info);
445 if (ret) {
446 return ret;
447 }
448 }
449 }
450 return NULL;
451}
452
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200453static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
454{
455 DeviceState *dev, *ret;
456 BusState *child;
457
458 QLIST_FOREACH(dev, &bus->children, sibling) {
459 if (dev->id && strcmp(dev->id, id) == 0)
460 return dev;
461 QLIST_FOREACH(child, &dev->child_bus, sibling) {
462 ret = qdev_find_recursive(child, id);
463 if (ret) {
464 return ret;
465 }
466 }
467 }
468 return NULL;
469}
470
Markus Armbruster53db16b2010-02-18 18:55:59 +0100471static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200472{
473 BusState *child;
474 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200475
Markus Armbruster53db16b2010-02-18 18:55:59 +0100476 error_printf("child busses at \"%s\":",
477 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000478 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100479 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200480 sep = ", ";
481 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100482 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200483}
484
Markus Armbruster53db16b2010-02-18 18:55:59 +0100485static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200486{
487 DeviceState *dev;
488 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200489
Markus Armbruster53db16b2010-02-18 18:55:59 +0100490 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000491 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100492 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200493 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100494 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200495 sep = ", ";
496 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100497 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200498}
499
500static BusState *qbus_find_bus(DeviceState *dev, char *elem)
501{
502 BusState *child;
503
Blue Swirl72cf2d42009-09-12 07:36:22 +0000504 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200505 if (strcmp(child->name, elem) == 0) {
506 return child;
507 }
508 }
509 return NULL;
510}
511
512static DeviceState *qbus_find_dev(BusState *bus, char *elem)
513{
514 DeviceState *dev;
515
516 /*
517 * try to match in order:
518 * (1) instance id, if present
519 * (2) driver name
520 * (3) driver alias, if present
521 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000522 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200523 if (dev->id && strcmp(dev->id, elem) == 0) {
524 return dev;
525 }
526 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000527 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200528 if (strcmp(dev->info->name, elem) == 0) {
529 return dev;
530 }
531 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000532 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200533 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
534 return dev;
535 }
536 }
537 return NULL;
538}
539
540static BusState *qbus_find(const char *path)
541{
542 DeviceState *dev;
543 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100544 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200545 int pos, len;
546
547 /* find start element */
548 if (path[0] == '/') {
549 bus = main_system_bus;
550 pos = 0;
551 } else {
552 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100553 error_report("path parse error (\"%s\")", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200554 return NULL;
555 }
556 bus = qbus_find_recursive(main_system_bus, elem, NULL);
557 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100558 error_report("bus \"%s\" not found", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200559 return NULL;
560 }
561 pos = len;
562 }
563
564 for (;;) {
565 if (path[pos] == '\0') {
566 /* we are done */
567 return bus;
568 }
569
570 /* find device */
571 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100572 error_report("path parse error (\"%s\" pos %d)", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200573 return NULL;
574 }
575 pos += len;
576 dev = qbus_find_dev(bus, elem);
577 if (!dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100578 error_report("device \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100579 qbus_list_dev(bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200580 return NULL;
581 }
582 if (path[pos] == '\0') {
583 /* last specified element is a device. If it has exactly
584 * one child bus accept it nevertheless */
585 switch (dev->num_child_bus) {
586 case 0:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100587 error_report("device has no child bus (%s)", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200588 return NULL;
589 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000590 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200591 default:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100592 error_report("device has multiple child busses (%s)", path);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100593 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200594 return NULL;
595 }
596 }
597
598 /* find bus */
599 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100600 error_report("path parse error (\"%s\" pos %d)", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200601 return NULL;
602 }
603 pos += len;
604 bus = qbus_find_bus(dev, elem);
605 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100606 error_report("child bus \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100607 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200608 return NULL;
609 }
610 }
611}
612
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200613void qbus_create_inplace(BusState *bus, BusInfo *info,
614 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100615{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200616 char *buf;
617 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100618
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200619 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100620 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200621
622 if (name) {
623 /* use supplied name */
624 bus->name = qemu_strdup(name);
625 } else if (parent && parent->id) {
626 /* parent device has id -> use it for bus name */
627 len = strlen(parent->id) + 16;
628 buf = qemu_malloc(len);
629 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
630 bus->name = buf;
631 } else {
632 /* no id -> use lowercase bus type for bus name */
633 len = strlen(info->name) + 16;
634 buf = qemu_malloc(len);
635 len = snprintf(buf, len, "%s.%d", info->name,
636 parent ? parent->num_child_bus : 0);
637 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200638 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200639 bus->name = buf;
640 }
641
Blue Swirl72cf2d42009-09-12 07:36:22 +0000642 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100643 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000644 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200645 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100646 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200647
648}
649
650BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
651{
652 BusState *bus;
653
654 bus = qemu_mallocz(info->size);
655 bus->qdev_allocated = 1;
656 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100657 return bus;
658}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100659
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200660void qbus_free(BusState *bus)
661{
662 DeviceState *dev;
663
664 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
665 qdev_free(dev);
666 }
667 if (bus->parent) {
668 QLIST_REMOVE(bus, sibling);
669 bus->parent->num_child_bus--;
670 }
671 if (bus->qdev_allocated) {
672 qemu_free(bus);
673 }
674}
675
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100676#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
677static void qbus_print(Monitor *mon, BusState *bus, int indent);
678
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200679static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
680 const char *prefix, int indent)
681{
682 char buf[64];
683
684 if (!props)
685 return;
686 while (props->name) {
687 if (props->info->print) {
688 props->info->print(dev, props, buf, sizeof(buf));
689 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
690 }
691 props++;
692 }
693}
694
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100695static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
696{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100697 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200698 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
699 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100700 indent += 2;
701 if (dev->num_gpio_in) {
702 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
703 }
704 if (dev->num_gpio_out) {
705 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
706 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200707 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
708 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200709 if (dev->parent_bus->info->print_dev)
710 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000711 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100712 qbus_print(mon, child, indent);
713 }
714}
715
716static void qbus_print(Monitor *mon, BusState *bus, int indent)
717{
718 struct DeviceState *dev;
719
720 qdev_printf("bus: %s\n", bus->name);
721 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200722 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000723 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100724 qdev_print(mon, dev, indent);
725 }
726}
727#undef qdev_printf
728
729void do_info_qtree(Monitor *mon)
730{
731 if (main_system_bus)
732 qbus_print(mon, main_system_bus, 0);
733}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200734
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200735void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200736{
737 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200738
739 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100740 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200741 }
742}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200743
744void do_device_add(Monitor *mon, const QDict *qdict)
745{
746 QemuOpts *opts;
747
748 opts = qemu_opts_parse(&qemu_device_opts,
749 qdict_get_str(qdict, "config"), "driver");
Kevin Wolf0f853a32010-02-16 13:12:38 +0100750 if (opts) {
751 if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) {
752 qemu_opts_del(opts);
753 }
754 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200755}
756
757void do_device_del(Monitor *mon, const QDict *qdict)
758{
759 const char *id = qdict_get_str(qdict, "id");
760 DeviceState *dev;
761
762 dev = qdev_find_recursive(main_system_bus, id);
763 if (NULL == dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100764 error_report("Device '%s' not found", id);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200765 return;
766 }
767 qdev_unplug(dev);
768}