blob: 539b5a2009b740cd24778303206888795551410b [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
Paul Brookaae94602009-05-14 22:35:06 +010081/* Create a new device. This only initializes the device state structure
82 and allows properties to be set. qdev_init should be called to
83 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010084DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010085{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020086 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010087 DeviceState *dev;
88
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020089 if (!bus) {
90 if (!main_system_bus) {
91 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010092 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020093 bus = main_system_bus;
94 }
95
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020096 info = qdev_find_info(bus->info, name);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020097 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020098 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010099 }
100
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200101 dev = qemu_mallocz(info->size);
102 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100103 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200104 qdev_prop_set_defaults(dev, dev->info->props);
105 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +0100106 qdev_prop_set_globals(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000107 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200108 if (qdev_hotplug) {
109 assert(bus->allow_hotplug);
110 dev->hotplugged = 1;
111 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200112 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +0100113 return dev;
114}
115
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200116static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
117{
118 int pos = 0;
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200119 int ret;
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200120
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200121 ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
122 info->name, info->bus_info->name);
123 pos += MIN(len-pos,ret);
124 if (info->alias) {
125 ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
126 pos += MIN(len-pos,ret);
127 }
128 if (info->desc) {
129 ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
130 pos += MIN(len-pos,ret);
131 }
132 if (info->no_user) {
133 ret = snprintf(dest+pos, len-pos, ", no-user");
134 pos += MIN(len-pos,ret);
135 }
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200136 return pos;
137}
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 Hoffmann286c2322009-08-14 10:36:08 +0200149 qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
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;
160 char msg[256];
Markus Armbruster08350cf2010-01-29 19:49:00 +0100161 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100162
163 driver = qemu_opt_get(opts, "driver");
164 if (driver && !strcmp(driver, "?")) {
165 for (info = device_info_list; info != NULL; info = info->next) {
166 qdev_print_devinfo(info, msg, sizeof(msg));
167 qemu_error("%s\n", msg);
168 }
169 return 1;
170 }
171
Markus Armbruster08350cf2010-01-29 19:49:00 +0100172 if (!qemu_opt_get(opts, "?")) {
173 return 0;
174 }
175
176 info = qdev_find_info(NULL, driver);
177 if (!info) {
178 return 0;
179 }
180
181 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster117f8eb2010-01-29 19:49:02 +0100182 qemu_error("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100183 }
184 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100185}
186
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200187DeviceState *qdev_device_add(QemuOpts *opts)
188{
189 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200190 DeviceInfo *info;
191 DeviceState *qdev;
192 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200193
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200194 driver = qemu_opt_get(opts, "driver");
195 if (!driver) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200196 qemu_error("-device: no driver specified\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200197 return NULL;
198 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200199
200 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200201 info = qdev_find_info(NULL, driver);
202 if (!info) {
Luiz Capitulino3ced9f72009-11-18 23:05:33 -0200203 qemu_error_new(QERR_DEVICE_NOT_FOUND, driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200204 return NULL;
205 }
206 if (info->no_user) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200207 qemu_error("device \"%s\" can't be added via command line\n",
208 info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200209 return NULL;
210 }
211
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200212 /* find bus */
213 path = qemu_opt_get(opts, "bus");
214 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200215 bus = qbus_find(path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200216 } else {
217 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200218 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200219 if (!bus) {
220 qemu_error("Did not find %s bus for %s\n",
221 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200222 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200223 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200224 if (qdev_hotplug && !bus->allow_hotplug) {
225 qemu_error("Bus %s does not support hotplugging\n",
226 bus->name);
227 return NULL;
228 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200229
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200230 /* create device, set properties */
231 qdev = qdev_create(bus, driver);
232 id = qemu_opts_id(opts);
233 if (id) {
234 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200235 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200236 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
237 qdev_free(qdev);
238 return NULL;
239 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200240 if (qdev_init(qdev) < 0) {
Amit Shahc8cd1fc2009-09-29 15:51:03 +0530241 qemu_error("Error initializing device %s\n", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200242 return NULL;
243 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200244 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200245 return qdev;
246}
247
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300248static void qdev_reset(void *opaque)
249{
250 DeviceState *dev = opaque;
251 if (dev->info->reset)
252 dev->info->reset(dev);
253}
254
Paul Brookaae94602009-05-14 22:35:06 +0100255/* Initialize a device. Device properties should be set before calling
256 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200257 calling this function.
258 On failure, destroy the device and return negative value.
259 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200260int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100261{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200262 int rc;
263
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200264 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200265 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200266 if (rc < 0) {
267 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200268 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200269 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300270 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200271 if (dev->info->vmsd)
272 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200273 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200274 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100275}
276
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200277int qdev_unplug(DeviceState *dev)
278{
279 if (!dev->parent_bus->allow_hotplug) {
280 qemu_error("Bus %s does not support hotplugging\n",
281 dev->parent_bus->name);
282 return -1;
283 }
Amit Shah593831d2009-11-02 14:56:41 +0530284 assert(dev->info->unplug != NULL);
285
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200286 return dev->info->unplug(dev);
287}
288
289/* can be used as ->unplug() callback for the simple cases */
290int qdev_simple_unplug_cb(DeviceState *dev)
291{
292 /* just zap it */
293 qdev_free(dev);
294 return 0;
295}
296
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200297/* Like qdev_init(), but terminate program via hw_error() instead of
298 returning an error value. This is okay during machine creation.
299 Don't use for hotplug, because there callers need to recover from
300 failure. Exception: if you know the device's init() callback can't
301 fail, then qdev_init_nofail() can't fail either, and is therefore
302 usable even then. But relying on the device implementation that
303 way is somewhat unclean, and best avoided. */
304void qdev_init_nofail(DeviceState *dev)
305{
306 DeviceInfo *info = dev->info;
307
308 if (qdev_init(dev) < 0)
309 hw_error("Initialization of device %s failed\n", info->name);
310}
311
Paul Brook02e2da42009-05-23 00:05:19 +0100312/* Unlink device from bus and free the structure. */
313void qdev_free(DeviceState *dev)
314{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200315 BusState *bus;
316
317 if (dev->state == DEV_STATE_INITIALIZED) {
318 while (dev->num_child_bus) {
319 bus = QLIST_FIRST(&dev->child_bus);
320 qbus_free(bus);
321 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200322 if (dev->info->vmsd)
323 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200324 if (dev->info->exit)
325 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200326 if (dev->opts)
327 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200328 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300329 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000330 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200331 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100332}
333
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200334void qdev_machine_creation_done(void)
335{
336 /*
337 * ok, initial machine setup is done, starting from now we can
338 * only create hotpluggable devices
339 */
340 qdev_hotplug = 1;
341}
342
Paul Brookaae94602009-05-14 22:35:06 +0100343/* Get a character (serial) device interface. */
344CharDriverState *qdev_init_chardev(DeviceState *dev)
345{
346 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530347
348 /* FIXME: This function needs to go away: use chardev properties! */
349 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100350}
351
Paul Brook02e2da42009-05-23 00:05:19 +0100352BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100353{
Paul Brook02e2da42009-05-23 00:05:19 +0100354 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100355}
356
Paul Brookaae94602009-05-14 22:35:06 +0100357void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
358{
359 assert(dev->num_gpio_in == 0);
360 dev->num_gpio_in = n;
361 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
362}
363
364void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
365{
366 assert(dev->num_gpio_out == 0);
367 dev->num_gpio_out = n;
368 dev->gpio_out = pins;
369}
370
371qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
372{
373 assert(n >= 0 && n < dev->num_gpio_in);
374 return dev->gpio_in[n];
375}
376
377void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
378{
379 assert(n >= 0 && n < dev->num_gpio_out);
380 dev->gpio_out[n] = pin;
381}
382
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200383void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
384{
385 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
386 if (nd->vlan)
387 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
388 if (nd->netdev)
389 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200390 if (nd->nvectors != NIC_NVECTORS_UNSPECIFIED &&
391 qdev_prop_exists(dev, "vectors")) {
392 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
393 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200394}
395
Paul Brookaae94602009-05-14 22:35:06 +0100396static int next_block_unit[IF_COUNT];
397
398/* Get a block device. This should only be used for single-drive devices
399 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
400 appropriate bus. */
401BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
402{
403 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200404 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100405
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200406 dinfo = drive_get(type, 0, unit);
407 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100408}
Paul Brook4d6ae672009-05-14 22:35:06 +0100409
Paul Brook02e2da42009-05-23 00:05:19 +0100410BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100411{
Paul Brook02e2da42009-05-23 00:05:19 +0100412 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100413
Blue Swirl72cf2d42009-09-12 07:36:22 +0000414 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100415 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100416 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100417 }
418 }
419 return NULL;
420}
421
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200422static BusState *qbus_find_recursive(BusState *bus, const char *name,
423 const BusInfo *info)
424{
425 DeviceState *dev;
426 BusState *child, *ret;
427 int match = 1;
428
429 if (name && (strcmp(bus->name, name) != 0)) {
430 match = 0;
431 }
432 if (info && (bus->info != info)) {
433 match = 0;
434 }
435 if (match) {
436 return bus;
437 }
438
Blue Swirl72cf2d42009-09-12 07:36:22 +0000439 QLIST_FOREACH(dev, &bus->children, sibling) {
440 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200441 ret = qbus_find_recursive(child, name, info);
442 if (ret) {
443 return ret;
444 }
445 }
446 }
447 return NULL;
448}
449
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200450static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
451{
452 DeviceState *dev, *ret;
453 BusState *child;
454
455 QLIST_FOREACH(dev, &bus->children, sibling) {
456 if (dev->id && strcmp(dev->id, id) == 0)
457 return dev;
458 QLIST_FOREACH(child, &dev->child_bus, sibling) {
459 ret = qdev_find_recursive(child, id);
460 if (ret) {
461 return ret;
462 }
463 }
464 }
465 return NULL;
466}
467
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200468static void qbus_list_bus(DeviceState *dev, char *dest, int len)
469{
470 BusState *child;
471 const char *sep = " ";
472 int pos = 0;
473
474 pos += snprintf(dest+pos, len-pos,"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) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200477 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
478 sep = ", ";
479 }
480}
481
482static void qbus_list_dev(BusState *bus, char *dest, int len)
483{
484 DeviceState *dev;
485 const char *sep = " ";
486 int pos = 0;
487
488 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
489 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000490 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200491 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
492 sep, dev->info->name);
493 if (dev->id)
494 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
495 sep = ", ";
496 }
497}
498
499static BusState *qbus_find_bus(DeviceState *dev, char *elem)
500{
501 BusState *child;
502
Blue Swirl72cf2d42009-09-12 07:36:22 +0000503 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200504 if (strcmp(child->name, elem) == 0) {
505 return child;
506 }
507 }
508 return NULL;
509}
510
511static DeviceState *qbus_find_dev(BusState *bus, char *elem)
512{
513 DeviceState *dev;
514
515 /*
516 * try to match in order:
517 * (1) instance id, if present
518 * (2) driver name
519 * (3) driver alias, if present
520 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000521 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200522 if (dev->id && strcmp(dev->id, elem) == 0) {
523 return dev;
524 }
525 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000526 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200527 if (strcmp(dev->info->name, elem) == 0) {
528 return dev;
529 }
530 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000531 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200532 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
533 return dev;
534 }
535 }
536 return NULL;
537}
538
539static BusState *qbus_find(const char *path)
540{
541 DeviceState *dev;
542 BusState *bus;
543 char elem[128], msg[256];
544 int pos, len;
545
546 /* find start element */
547 if (path[0] == '/') {
548 bus = main_system_bus;
549 pos = 0;
550 } else {
551 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200552 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200553 return NULL;
554 }
555 bus = qbus_find_recursive(main_system_bus, elem, NULL);
556 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200557 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200558 return NULL;
559 }
560 pos = len;
561 }
562
563 for (;;) {
564 if (path[pos] == '\0') {
565 /* we are done */
566 return bus;
567 }
568
569 /* find device */
570 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200571 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200572 return NULL;
573 }
574 pos += len;
575 dev = qbus_find_dev(bus, elem);
576 if (!dev) {
577 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200578 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200579 return NULL;
580 }
581 if (path[pos] == '\0') {
582 /* last specified element is a device. If it has exactly
583 * one child bus accept it nevertheless */
584 switch (dev->num_child_bus) {
585 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200586 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200587 return NULL;
588 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000589 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200590 default:
591 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200592 qemu_error("device has multiple child busses (%s)\n%s\n",
593 path, msg);
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) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200600 qemu_error("path parse error (\"%s\" pos %d)\n", 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) {
606 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200607 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
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;
738 char msg[256];
739
740 for (info = device_info_list; info != NULL; info = info->next) {
741 qdev_print_devinfo(info, msg, sizeof(msg));
742 monitor_printf(mon, "%s\n", msg);
743 }
744}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200745
746void do_device_add(Monitor *mon, const QDict *qdict)
747{
748 QemuOpts *opts;
749
750 opts = qemu_opts_parse(&qemu_device_opts,
751 qdict_get_str(qdict, "config"), "driver");
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100752 if (opts && !qdev_device_help(opts))
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200753 qdev_device_add(opts);
754}
755
756void do_device_del(Monitor *mon, const QDict *qdict)
757{
758 const char *id = qdict_get_str(qdict, "id");
759 DeviceState *dev;
760
761 dev = qdev_find_recursive(main_system_bus, id);
762 if (NULL == dev) {
763 qemu_error("Device '%s' not found\n", id);
764 return;
765 }
766 qdev_unplug(dev);
767}