blob: 233480e12dda709f3276ea1381a190ece5666fe5 [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 Armbrusterc64eafa2010-02-19 13:31:49 +0100165 if (info->no_user) {
166 continue; /* not available, don't show */
167 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100168 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100169 }
170 return 1;
171 }
172
Markus Armbruster08350cf2010-01-29 19:49:00 +0100173 if (!qemu_opt_get(opts, "?")) {
174 return 0;
175 }
176
177 info = qdev_find_info(NULL, driver);
178 if (!info) {
179 return 0;
180 }
181
182 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100183 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100184 }
185 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100186}
187
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200188DeviceState *qdev_device_add(QemuOpts *opts)
189{
190 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200191 DeviceInfo *info;
192 DeviceState *qdev;
193 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200194
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200195 driver = qemu_opt_get(opts, "driver");
196 if (!driver) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100197 error_report("-device: no driver specified");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200198 return NULL;
199 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200200
201 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200202 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100203 if (!info || info->no_user) {
Markus Armbrusterab5b0272010-03-02 18:15:09 +0100204 qerror_report(QERR_DEVICE_NOT_FOUND, driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200205 return NULL;
206 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200207
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200208 /* find bus */
209 path = qemu_opt_get(opts, "bus");
210 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200211 bus = qbus_find(path);
Markus Armbruster327867b2010-02-19 19:08:45 +0100212 if (bus && bus->info != info->bus_info) {
213 error_report("Device '%s' can't go on a %s bus",
214 driver, bus->info->name);
215 return NULL;
216 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200217 } else {
218 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200219 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200220 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100221 error_report("Did not find %s bus for %s",
222 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200223 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200224 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200225 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100226 error_report("Bus %s does not support hotplugging",
227 bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200228 return NULL;
229 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200230
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200231 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100232 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200233 id = qemu_opts_id(opts);
234 if (id) {
235 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200236 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200237 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
238 qdev_free(qdev);
239 return NULL;
240 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200241 if (qdev_init(qdev) < 0) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100242 error_report("Error initializing device %s", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200243 return NULL;
244 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200245 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200246 return qdev;
247}
248
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300249static void qdev_reset(void *opaque)
250{
251 DeviceState *dev = opaque;
252 if (dev->info->reset)
253 dev->info->reset(dev);
254}
255
Paul Brookaae94602009-05-14 22:35:06 +0100256/* Initialize a device. Device properties should be set before calling
257 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200258 calling this function.
259 On failure, destroy the device and return negative value.
260 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200261int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100262{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200263 int rc;
264
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200265 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200266 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200267 if (rc < 0) {
268 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200269 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200270 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300271 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200272 if (dev->info->vmsd)
273 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200274 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200275 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100276}
277
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200278int qdev_unplug(DeviceState *dev)
279{
280 if (!dev->parent_bus->allow_hotplug) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100281 error_report("Bus %s does not support hotplugging",
282 dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200283 return -1;
284 }
Amit Shah593831d2009-11-02 14:56:41 +0530285 assert(dev->info->unplug != NULL);
286
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200287 return dev->info->unplug(dev);
288}
289
290/* can be used as ->unplug() callback for the simple cases */
291int qdev_simple_unplug_cb(DeviceState *dev)
292{
293 /* just zap it */
294 qdev_free(dev);
295 return 0;
296}
297
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200298/* Like qdev_init(), but terminate program via hw_error() instead of
299 returning an error value. This is okay during machine creation.
300 Don't use for hotplug, because there callers need to recover from
301 failure. Exception: if you know the device's init() callback can't
302 fail, then qdev_init_nofail() can't fail either, and is therefore
303 usable even then. But relying on the device implementation that
304 way is somewhat unclean, and best avoided. */
305void qdev_init_nofail(DeviceState *dev)
306{
307 DeviceInfo *info = dev->info;
308
309 if (qdev_init(dev) < 0)
310 hw_error("Initialization of device %s failed\n", info->name);
311}
312
Paul Brook02e2da42009-05-23 00:05:19 +0100313/* Unlink device from bus and free the structure. */
314void qdev_free(DeviceState *dev)
315{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200316 BusState *bus;
317
318 if (dev->state == DEV_STATE_INITIALIZED) {
319 while (dev->num_child_bus) {
320 bus = QLIST_FIRST(&dev->child_bus);
321 qbus_free(bus);
322 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200323 if (dev->info->vmsd)
324 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200325 if (dev->info->exit)
326 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200327 if (dev->opts)
328 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200329 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300330 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000331 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200332 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100333}
334
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200335void qdev_machine_creation_done(void)
336{
337 /*
338 * ok, initial machine setup is done, starting from now we can
339 * only create hotpluggable devices
340 */
341 qdev_hotplug = 1;
342}
343
Paul Brookaae94602009-05-14 22:35:06 +0100344/* Get a character (serial) device interface. */
345CharDriverState *qdev_init_chardev(DeviceState *dev)
346{
347 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530348
349 /* FIXME: This function needs to go away: use chardev properties! */
350 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100351}
352
Paul Brook02e2da42009-05-23 00:05:19 +0100353BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100354{
Paul Brook02e2da42009-05-23 00:05:19 +0100355 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100356}
357
Paul Brookaae94602009-05-14 22:35:06 +0100358void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
359{
360 assert(dev->num_gpio_in == 0);
361 dev->num_gpio_in = n;
362 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
363}
364
365void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
366{
367 assert(dev->num_gpio_out == 0);
368 dev->num_gpio_out = n;
369 dev->gpio_out = pins;
370}
371
372qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
373{
374 assert(n >= 0 && n < dev->num_gpio_in);
375 return dev->gpio_in[n];
376}
377
378void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
379{
380 assert(n >= 0 && n < dev->num_gpio_out);
381 dev->gpio_out[n] = pin;
382}
383
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200384void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
385{
386 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
387 if (nd->vlan)
388 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
389 if (nd->netdev)
390 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530391 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200392 qdev_prop_exists(dev, "vectors")) {
393 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
394 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200395}
396
Paul Brookaae94602009-05-14 22:35:06 +0100397static int next_block_unit[IF_COUNT];
398
399/* Get a block device. This should only be used for single-drive devices
400 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
401 appropriate bus. */
402BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
403{
404 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200405 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100406
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200407 dinfo = drive_get(type, 0, unit);
408 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100409}
Paul Brook4d6ae672009-05-14 22:35:06 +0100410
Paul Brook02e2da42009-05-23 00:05:19 +0100411BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100412{
Paul Brook02e2da42009-05-23 00:05:19 +0100413 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100414
Blue Swirl72cf2d42009-09-12 07:36:22 +0000415 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100416 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100417 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100418 }
419 }
420 return NULL;
421}
422
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200423static BusState *qbus_find_recursive(BusState *bus, const char *name,
424 const BusInfo *info)
425{
426 DeviceState *dev;
427 BusState *child, *ret;
428 int match = 1;
429
430 if (name && (strcmp(bus->name, name) != 0)) {
431 match = 0;
432 }
433 if (info && (bus->info != info)) {
434 match = 0;
435 }
436 if (match) {
437 return bus;
438 }
439
Blue Swirl72cf2d42009-09-12 07:36:22 +0000440 QLIST_FOREACH(dev, &bus->children, sibling) {
441 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200442 ret = qbus_find_recursive(child, name, info);
443 if (ret) {
444 return ret;
445 }
446 }
447 }
448 return NULL;
449}
450
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200451static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
452{
453 DeviceState *dev, *ret;
454 BusState *child;
455
456 QLIST_FOREACH(dev, &bus->children, sibling) {
457 if (dev->id && strcmp(dev->id, id) == 0)
458 return dev;
459 QLIST_FOREACH(child, &dev->child_bus, sibling) {
460 ret = qdev_find_recursive(child, id);
461 if (ret) {
462 return ret;
463 }
464 }
465 }
466 return NULL;
467}
468
Markus Armbruster53db16b2010-02-18 18:55:59 +0100469static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200470{
471 BusState *child;
472 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200473
Markus Armbruster53db16b2010-02-18 18:55:59 +0100474 error_printf("child busses at \"%s\":",
475 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000476 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100477 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200478 sep = ", ";
479 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100480 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200481}
482
Markus Armbruster53db16b2010-02-18 18:55:59 +0100483static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200484{
485 DeviceState *dev;
486 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200487
Markus Armbruster53db16b2010-02-18 18:55:59 +0100488 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000489 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100490 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200491 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100492 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200493 sep = ", ";
494 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100495 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200496}
497
498static BusState *qbus_find_bus(DeviceState *dev, char *elem)
499{
500 BusState *child;
501
Blue Swirl72cf2d42009-09-12 07:36:22 +0000502 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200503 if (strcmp(child->name, elem) == 0) {
504 return child;
505 }
506 }
507 return NULL;
508}
509
510static DeviceState *qbus_find_dev(BusState *bus, char *elem)
511{
512 DeviceState *dev;
513
514 /*
515 * try to match in order:
516 * (1) instance id, if present
517 * (2) driver name
518 * (3) driver alias, if present
519 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000520 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200521 if (dev->id && strcmp(dev->id, elem) == 0) {
522 return dev;
523 }
524 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000525 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200526 if (strcmp(dev->info->name, elem) == 0) {
527 return dev;
528 }
529 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000530 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200531 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
532 return dev;
533 }
534 }
535 return NULL;
536}
537
538static BusState *qbus_find(const char *path)
539{
540 DeviceState *dev;
541 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100542 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200543 int pos, len;
544
545 /* find start element */
546 if (path[0] == '/') {
547 bus = main_system_bus;
548 pos = 0;
549 } else {
550 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100551 error_report("path parse error (\"%s\")", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200552 return NULL;
553 }
554 bus = qbus_find_recursive(main_system_bus, elem, NULL);
555 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100556 error_report("bus \"%s\" not found", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200557 return NULL;
558 }
559 pos = len;
560 }
561
562 for (;;) {
563 if (path[pos] == '\0') {
564 /* we are done */
565 return bus;
566 }
567
568 /* find device */
569 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100570 error_report("path parse error (\"%s\" pos %d)", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200571 return NULL;
572 }
573 pos += len;
574 dev = qbus_find_dev(bus, elem);
575 if (!dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100576 error_report("device \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100577 qbus_list_dev(bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200578 return NULL;
579 }
580 if (path[pos] == '\0') {
581 /* last specified element is a device. If it has exactly
582 * one child bus accept it nevertheless */
583 switch (dev->num_child_bus) {
584 case 0:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100585 error_report("device has no child bus (%s)", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200586 return NULL;
587 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000588 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200589 default:
Markus Armbruster1ecda022010-02-18 17:25:24 +0100590 error_report("device has multiple child busses (%s)", path);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100591 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200592 return NULL;
593 }
594 }
595
596 /* find bus */
597 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100598 error_report("path parse error (\"%s\" pos %d)", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200599 return NULL;
600 }
601 pos += len;
602 bus = qbus_find_bus(dev, elem);
603 if (!bus) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100604 error_report("child bus \"%s\" not found", elem);
Markus Armbruster53db16b2010-02-18 18:55:59 +0100605 qbus_list_bus(dev);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200606 return NULL;
607 }
608 }
609}
610
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200611void qbus_create_inplace(BusState *bus, BusInfo *info,
612 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100613{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200614 char *buf;
615 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100616
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200617 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100618 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200619
620 if (name) {
621 /* use supplied name */
622 bus->name = qemu_strdup(name);
623 } else if (parent && parent->id) {
624 /* parent device has id -> use it for bus name */
625 len = strlen(parent->id) + 16;
626 buf = qemu_malloc(len);
627 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
628 bus->name = buf;
629 } else {
630 /* no id -> use lowercase bus type for bus name */
631 len = strlen(info->name) + 16;
632 buf = qemu_malloc(len);
633 len = snprintf(buf, len, "%s.%d", info->name,
634 parent ? parent->num_child_bus : 0);
635 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200636 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200637 bus->name = buf;
638 }
639
Blue Swirl72cf2d42009-09-12 07:36:22 +0000640 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100641 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000642 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200643 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100644 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200645
646}
647
648BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
649{
650 BusState *bus;
651
652 bus = qemu_mallocz(info->size);
653 bus->qdev_allocated = 1;
654 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100655 return bus;
656}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100657
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200658void qbus_free(BusState *bus)
659{
660 DeviceState *dev;
661
662 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
663 qdev_free(dev);
664 }
665 if (bus->parent) {
666 QLIST_REMOVE(bus, sibling);
667 bus->parent->num_child_bus--;
668 }
669 if (bus->qdev_allocated) {
670 qemu_free(bus);
671 }
672}
673
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100674#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
675static void qbus_print(Monitor *mon, BusState *bus, int indent);
676
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200677static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
678 const char *prefix, int indent)
679{
680 char buf[64];
681
682 if (!props)
683 return;
684 while (props->name) {
685 if (props->info->print) {
686 props->info->print(dev, props, buf, sizeof(buf));
687 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
688 }
689 props++;
690 }
691}
692
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100693static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
694{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100695 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200696 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
697 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100698 indent += 2;
699 if (dev->num_gpio_in) {
700 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
701 }
702 if (dev->num_gpio_out) {
703 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
704 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200705 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
706 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200707 if (dev->parent_bus->info->print_dev)
708 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000709 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100710 qbus_print(mon, child, indent);
711 }
712}
713
714static void qbus_print(Monitor *mon, BusState *bus, int indent)
715{
716 struct DeviceState *dev;
717
718 qdev_printf("bus: %s\n", bus->name);
719 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200720 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000721 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100722 qdev_print(mon, dev, indent);
723 }
724}
725#undef qdev_printf
726
727void do_info_qtree(Monitor *mon)
728{
729 if (main_system_bus)
730 qbus_print(mon, main_system_bus, 0);
731}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200732
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200733void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200734{
735 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200736
737 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100738 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200739 }
740}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200741
742void do_device_add(Monitor *mon, const QDict *qdict)
743{
744 QemuOpts *opts;
745
746 opts = qemu_opts_parse(&qemu_device_opts,
747 qdict_get_str(qdict, "config"), "driver");
Kevin Wolf0f853a32010-02-16 13:12:38 +0100748 if (opts) {
749 if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) {
750 qemu_opts_del(opts);
751 }
752 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200753}
754
755void do_device_del(Monitor *mon, const QDict *qdict)
756{
757 const char *id = qdict_get_str(qdict, "id");
758 DeviceState *dev;
759
760 dev = qdev_find_recursive(main_system_bus, id);
761 if (NULL == dev) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100762 error_report("Device '%s' not found", id);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200763 return;
764 }
765 qdev_unplug(dev);
766}