blob: 790e90f55248c93ab87831df820eefb082e6e2cd [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) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200149 return -1;
150 }
151 return 0;
152}
153
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100154int qdev_device_help(QemuOpts *opts)
155{
156 const char *driver;
157 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100158 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100159
160 driver = qemu_opt_get(opts, "driver");
161 if (driver && !strcmp(driver, "?")) {
162 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100163 if (info->no_user) {
164 continue; /* not available, don't show */
165 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100166 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100167 }
168 return 1;
169 }
170
Markus Armbruster08350cf2010-01-29 19:49:00 +0100171 if (!qemu_opt_get(opts, "?")) {
172 return 0;
173 }
174
175 info = qdev_find_info(NULL, driver);
176 if (!info) {
177 return 0;
178 }
179
180 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100181 /*
182 * TODO Properties without a parser are just for dirty hacks.
183 * qdev_prop_ptr is the only such PropertyInfo. It's marked
184 * for removal. This conditional should be removed along with
185 * it.
186 */
187 if (!prop->info->parse) {
188 continue; /* no way to set it, don't show */
189 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100190 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100191 }
192 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100193}
194
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200195DeviceState *qdev_device_add(QemuOpts *opts)
196{
197 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200198 DeviceInfo *info;
199 DeviceState *qdev;
200 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200201
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200202 driver = qemu_opt_get(opts, "driver");
203 if (!driver) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100204 error_report("-device: no driver specified");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200205 return NULL;
206 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200207
208 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200209 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100210 if (!info || info->no_user) {
Markus Armbrusterab5b0272010-03-02 18:15:09 +0100211 qerror_report(QERR_DEVICE_NOT_FOUND, driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200212 return NULL;
213 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200214
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200215 /* find bus */
216 path = qemu_opt_get(opts, "bus");
217 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200218 bus = qbus_find(path);
Markus Armbruster327867b2010-02-19 19:08:45 +0100219 if (bus && bus->info != info->bus_info) {
220 error_report("Device '%s' can't go on a %s bus",
221 driver, bus->info->name);
222 return NULL;
223 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200224 } else {
225 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200226 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200227 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100228 error_report("Did not find %s bus for %s",
229 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200230 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200231 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200232 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100233 error_report("Bus %s does not support hotplugging",
234 bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200235 return NULL;
236 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200237
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200238 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100239 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200240 id = qemu_opts_id(opts);
241 if (id) {
242 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200243 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200244 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
245 qdev_free(qdev);
246 return NULL;
247 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200248 if (qdev_init(qdev) < 0) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100249 error_report("Error initializing device %s", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200250 return NULL;
251 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200252 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200253 return qdev;
254}
255
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300256static void qdev_reset(void *opaque)
257{
258 DeviceState *dev = opaque;
259 if (dev->info->reset)
260 dev->info->reset(dev);
261}
262
Paul Brookaae94602009-05-14 22:35:06 +0100263/* Initialize a device. Device properties should be set before calling
264 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200265 calling this function.
266 On failure, destroy the device and return negative value.
267 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200268int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100269{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200270 int rc;
271
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200272 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200273 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200274 if (rc < 0) {
275 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200276 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200277 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300278 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200279 if (dev->info->vmsd)
280 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200281 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200282 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100283}
284
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200285int qdev_unplug(DeviceState *dev)
286{
287 if (!dev->parent_bus->allow_hotplug) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100288 error_report("Bus %s does not support hotplugging",
289 dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200290 return -1;
291 }
Amit Shah593831d2009-11-02 14:56:41 +0530292 assert(dev->info->unplug != NULL);
293
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200294 return dev->info->unplug(dev);
295}
296
297/* can be used as ->unplug() callback for the simple cases */
298int qdev_simple_unplug_cb(DeviceState *dev)
299{
300 /* just zap it */
301 qdev_free(dev);
302 return 0;
303}
304
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200305/* Like qdev_init(), but terminate program via hw_error() instead of
306 returning an error value. This is okay during machine creation.
307 Don't use for hotplug, because there callers need to recover from
308 failure. Exception: if you know the device's init() callback can't
309 fail, then qdev_init_nofail() can't fail either, and is therefore
310 usable even then. But relying on the device implementation that
311 way is somewhat unclean, and best avoided. */
312void qdev_init_nofail(DeviceState *dev)
313{
314 DeviceInfo *info = dev->info;
315
316 if (qdev_init(dev) < 0)
317 hw_error("Initialization of device %s failed\n", info->name);
318}
319
Paul Brook02e2da42009-05-23 00:05:19 +0100320/* Unlink device from bus and free the structure. */
321void qdev_free(DeviceState *dev)
322{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200323 BusState *bus;
324
325 if (dev->state == DEV_STATE_INITIALIZED) {
326 while (dev->num_child_bus) {
327 bus = QLIST_FIRST(&dev->child_bus);
328 qbus_free(bus);
329 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200330 if (dev->info->vmsd)
331 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200332 if (dev->info->exit)
333 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200334 if (dev->opts)
335 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200336 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300337 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000338 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200339 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100340}
341
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200342void qdev_machine_creation_done(void)
343{
344 /*
345 * ok, initial machine setup is done, starting from now we can
346 * only create hotpluggable devices
347 */
348 qdev_hotplug = 1;
349}
350
Paul Brookaae94602009-05-14 22:35:06 +0100351/* Get a character (serial) device interface. */
352CharDriverState *qdev_init_chardev(DeviceState *dev)
353{
354 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530355
356 /* FIXME: This function needs to go away: use chardev properties! */
357 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100358}
359
Paul Brook02e2da42009-05-23 00:05:19 +0100360BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100361{
Paul Brook02e2da42009-05-23 00:05:19 +0100362 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100363}
364
Paul Brookaae94602009-05-14 22:35:06 +0100365void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
366{
367 assert(dev->num_gpio_in == 0);
368 dev->num_gpio_in = n;
369 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
370}
371
372void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
373{
374 assert(dev->num_gpio_out == 0);
375 dev->num_gpio_out = n;
376 dev->gpio_out = pins;
377}
378
379qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
380{
381 assert(n >= 0 && n < dev->num_gpio_in);
382 return dev->gpio_in[n];
383}
384
385void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
386{
387 assert(n >= 0 && n < dev->num_gpio_out);
388 dev->gpio_out[n] = pin;
389}
390
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200391void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
392{
393 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
394 if (nd->vlan)
395 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
396 if (nd->netdev)
397 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530398 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200399 qdev_prop_exists(dev, "vectors")) {
400 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
401 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200402}
403
Paul Brookaae94602009-05-14 22:35:06 +0100404static int next_block_unit[IF_COUNT];
405
406/* Get a block device. This should only be used for single-drive devices
407 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
408 appropriate bus. */
409BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
410{
411 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200412 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100413
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200414 dinfo = drive_get(type, 0, unit);
415 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100416}
Paul Brook4d6ae672009-05-14 22:35:06 +0100417
Paul Brook02e2da42009-05-23 00:05:19 +0100418BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100419{
Paul Brook02e2da42009-05-23 00:05:19 +0100420 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100421
Blue Swirl72cf2d42009-09-12 07:36:22 +0000422 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100423 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100424 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100425 }
426 }
427 return NULL;
428}
429
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200430static BusState *qbus_find_recursive(BusState *bus, const char *name,
431 const BusInfo *info)
432{
433 DeviceState *dev;
434 BusState *child, *ret;
435 int match = 1;
436
437 if (name && (strcmp(bus->name, name) != 0)) {
438 match = 0;
439 }
440 if (info && (bus->info != info)) {
441 match = 0;
442 }
443 if (match) {
444 return bus;
445 }
446
Blue Swirl72cf2d42009-09-12 07:36:22 +0000447 QLIST_FOREACH(dev, &bus->children, sibling) {
448 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200449 ret = qbus_find_recursive(child, name, info);
450 if (ret) {
451 return ret;
452 }
453 }
454 }
455 return NULL;
456}
457
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200458static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
459{
460 DeviceState *dev, *ret;
461 BusState *child;
462
463 QLIST_FOREACH(dev, &bus->children, sibling) {
464 if (dev->id && strcmp(dev->id, id) == 0)
465 return dev;
466 QLIST_FOREACH(child, &dev->child_bus, sibling) {
467 ret = qdev_find_recursive(child, id);
468 if (ret) {
469 return ret;
470 }
471 }
472 }
473 return NULL;
474}
475
Markus Armbruster53db16b2010-02-18 18:55:59 +0100476static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200477{
478 BusState *child;
479 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200480
Markus Armbruster53db16b2010-02-18 18:55:59 +0100481 error_printf("child busses at \"%s\":",
482 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000483 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100484 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200485 sep = ", ";
486 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100487 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200488}
489
Markus Armbruster53db16b2010-02-18 18:55:59 +0100490static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200491{
492 DeviceState *dev;
493 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200494
Markus Armbruster53db16b2010-02-18 18:55:59 +0100495 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000496 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100497 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200498 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100499 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200500 sep = ", ";
501 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100502 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200503}
504
505static BusState *qbus_find_bus(DeviceState *dev, char *elem)
506{
507 BusState *child;
508
Blue Swirl72cf2d42009-09-12 07:36:22 +0000509 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200510 if (strcmp(child->name, elem) == 0) {
511 return child;
512 }
513 }
514 return NULL;
515}
516
517static DeviceState *qbus_find_dev(BusState *bus, char *elem)
518{
519 DeviceState *dev;
520
521 /*
522 * try to match in order:
523 * (1) instance id, if present
524 * (2) driver name
525 * (3) driver alias, if present
526 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000527 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200528 if (dev->id && strcmp(dev->id, 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 (strcmp(dev->info->name, elem) == 0) {
534 return dev;
535 }
536 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000537 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200538 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
539 return dev;
540 }
541 }
542 return NULL;
543}
544
545static BusState *qbus_find(const char *path)
546{
547 DeviceState *dev;
548 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100549 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200550 int pos, len;
551
552 /* find start element */
553 if (path[0] == '/') {
554 bus = main_system_bus;
555 pos = 0;
556 } else {
557 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100558 assert(!path[0]);
559 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200560 }
561 bus = qbus_find_recursive(main_system_bus, elem, NULL);
562 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100563 error_report("bus \"%s\" not found", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200564 return NULL;
565 }
566 pos = len;
567 }
568
569 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100570 assert(path[pos] == '/' || !path[pos]);
571 while (path[pos] == '/') {
572 pos++;
573 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200574 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200575 return bus;
576 }
577
578 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100579 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
580 assert(0);
581 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200582 }
583 pos += len;
584 dev = qbus_find_dev(bus, elem);
585 if (!dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100586 error_report("device \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100587 qbus_list_dev(bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200588 return NULL;
589 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100590
591 assert(path[pos] == '/' || !path[pos]);
592 while (path[pos] == '/') {
593 pos++;
594 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200595 if (path[pos] == '\0') {
596 /* last specified element is a device. If it has exactly
597 * one child bus accept it nevertheless */
598 switch (dev->num_child_bus) {
599 case 0:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100600 error_report("device has no child bus (%s)", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200601 return NULL;
602 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000603 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200604 default:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100605 error_report("device has multiple child busses (%s)", path);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100606 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200607 return NULL;
608 }
609 }
610
611 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100612 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
613 assert(0);
614 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200615 }
616 pos += len;
617 bus = qbus_find_bus(dev, elem);
618 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100619 error_report("child bus \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100620 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200621 return NULL;
622 }
623 }
624}
625
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200626void qbus_create_inplace(BusState *bus, BusInfo *info,
627 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100628{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200629 char *buf;
630 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100631
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200632 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100633 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200634
635 if (name) {
636 /* use supplied name */
637 bus->name = qemu_strdup(name);
638 } else if (parent && parent->id) {
639 /* parent device has id -> use it for bus name */
640 len = strlen(parent->id) + 16;
641 buf = qemu_malloc(len);
642 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
643 bus->name = buf;
644 } else {
645 /* no id -> use lowercase bus type for bus name */
646 len = strlen(info->name) + 16;
647 buf = qemu_malloc(len);
648 len = snprintf(buf, len, "%s.%d", info->name,
649 parent ? parent->num_child_bus : 0);
650 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200651 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200652 bus->name = buf;
653 }
654
Blue Swirl72cf2d42009-09-12 07:36:22 +0000655 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100656 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000657 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200658 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100659 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200660
661}
662
663BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
664{
665 BusState *bus;
666
667 bus = qemu_mallocz(info->size);
668 bus->qdev_allocated = 1;
669 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100670 return bus;
671}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100672
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200673void qbus_free(BusState *bus)
674{
675 DeviceState *dev;
676
677 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
678 qdev_free(dev);
679 }
680 if (bus->parent) {
681 QLIST_REMOVE(bus, sibling);
682 bus->parent->num_child_bus--;
683 }
684 if (bus->qdev_allocated) {
685 qemu_free(bus);
686 }
687}
688
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100689#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
690static void qbus_print(Monitor *mon, BusState *bus, int indent);
691
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200692static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
693 const char *prefix, int indent)
694{
695 char buf[64];
696
697 if (!props)
698 return;
699 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100700 /*
701 * TODO Properties without a print method are just for dirty
702 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
703 * marked for removal. The test props->info->print should be
704 * removed along with it.
705 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200706 if (props->info->print) {
707 props->info->print(dev, props, buf, sizeof(buf));
708 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
709 }
710 props++;
711 }
712}
713
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100714static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
715{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100716 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200717 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
718 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100719 indent += 2;
720 if (dev->num_gpio_in) {
721 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
722 }
723 if (dev->num_gpio_out) {
724 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
725 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200726 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
727 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200728 if (dev->parent_bus->info->print_dev)
729 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000730 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100731 qbus_print(mon, child, indent);
732 }
733}
734
735static void qbus_print(Monitor *mon, BusState *bus, int indent)
736{
737 struct DeviceState *dev;
738
739 qdev_printf("bus: %s\n", bus->name);
740 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200741 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000742 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100743 qdev_print(mon, dev, indent);
744 }
745}
746#undef qdev_printf
747
748void do_info_qtree(Monitor *mon)
749{
750 if (main_system_bus)
751 qbus_print(mon, main_system_bus, 0);
752}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200753
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200754void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200755{
756 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200757
758 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100759 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200760 }
761}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200762
763void do_device_add(Monitor *mon, const QDict *qdict)
764{
765 QemuOpts *opts;
766
767 opts = qemu_opts_parse(&qemu_device_opts,
768 qdict_get_str(qdict, "config"), "driver");
Kevin Wolf0f853a32010-02-16 13:12:38 +0100769 if (opts) {
770 if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) {
771 qemu_opts_del(opts);
772 }
773 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200774}
775
776void do_device_del(Monitor *mon, const QDict *qdict)
777{
778 const char *id = qdict_get_str(qdict, "id");
779 DeviceState *dev;
780
781 dev = qdev_find_recursive(main_system_bus, id);
782 if (NULL == dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100783 error_report("Device '%s' not found", id);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200784 return;
785 }
786 qdev_unplug(dev);
787}