blob: e81d6621c12da0fe66a3c4e876093fb461d84992 [file] [log] [blame]
Paul Brookaae94602009-05-14 22:35:06 +01001/*
2 * Dynamic device configuration and creation.
3 *
4 * Copyright (c) 2009 CodeSourcery
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Paul Brookaae94602009-05-14 22:35:06 +010018 */
19
20/* The theory here is that it should be possible to create a machine without
21 knowledge of specific devices. Historically board init routines have
22 passed a bunch of arguments to each device, requiring the board know
23 exactly which device it is dealing with. This file provides an abstract
24 API for device configuration and initialization. Devices will generally
25 inherit from a particular bus (e.g. PCI or I2C) rather than
26 this API directly. */
27
Paul Brook9d07d752009-05-14 22:35:07 +010028#include "net.h"
Paul Brookaae94602009-05-14 22:35:06 +010029#include "qdev.h"
30#include "sysemu.h"
Gerd Hoffmanncae49562009-06-05 15:53:17 +010031#include "monitor.h"
Paul Brookaae94602009-05-14 22:35:06 +010032
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020033static int qdev_hotplug = 0;
34
Gerd Hoffmanncdaed7c2009-10-06 21:17:52 +020035/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000036static BusState *main_system_bus;
Paul Brook4d6ae672009-05-14 22:35:06 +010037
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020038static DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010039
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +020040static BusState *qbus_find_recursive(BusState *bus, const char *name,
41 const BusInfo *info);
42static BusState *qbus_find(const char *path);
43
Paul Brookaae94602009-05-14 22:35:06 +010044/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020045void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010046{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020047 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020048 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010049
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020050 info->next = device_info_list;
51 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010052}
53
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020054static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
55{
56 DeviceInfo *info;
57
Gerd Hoffmann3320e562009-07-15 13:43:33 +020058 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020059 for (info = device_info_list; info != NULL; info = info->next) {
60 if (bus_info && info->bus_info != bus_info)
61 continue;
62 if (strcmp(info->name, name) != 0)
63 continue;
64 return info;
65 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020066
67 /* failing that check the aliases */
68 for (info = device_info_list; info != NULL; info = info->next) {
69 if (bus_info && info->bus_info != bus_info)
70 continue;
71 if (!info->alias)
72 continue;
73 if (strcmp(info->alias, name) != 0)
74 continue;
75 return info;
76 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020077 return NULL;
78}
79
Paul Brookaae94602009-05-14 22:35:06 +010080/* Create a new device. This only initializes the device state structure
81 and allows properties to be set. qdev_init should be called to
82 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010083DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010084{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020085 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010086 DeviceState *dev;
87
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020088 if (!bus) {
89 if (!main_system_bus) {
90 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010091 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020092 bus = main_system_bus;
93 }
94
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020095 info = qdev_find_info(bus->info, name);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020096 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020097 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010098 }
99
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200100 dev = qemu_mallocz(info->size);
101 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100102 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200103 qdev_prop_set_defaults(dev, dev->info->props);
104 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmannb6b61142009-07-15 13:48:21 +0200105 qdev_prop_set_compat(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000106 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200107 if (qdev_hotplug) {
108 assert(bus->allow_hotplug);
109 dev->hotplugged = 1;
110 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200111 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +0100112 return dev;
113}
114
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200115static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
116{
117 int pos = 0;
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200118 int ret;
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200119
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200120 ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
121 info->name, info->bus_info->name);
122 pos += MIN(len-pos,ret);
123 if (info->alias) {
124 ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
125 pos += MIN(len-pos,ret);
126 }
127 if (info->desc) {
128 ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
129 pos += MIN(len-pos,ret);
130 }
131 if (info->no_user) {
132 ret = snprintf(dest+pos, len-pos, ", no-user");
133 pos += MIN(len-pos,ret);
134 }
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200135 return pos;
136}
137
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200138static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200139{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200140 DeviceState *dev = opaque;
141
142 if (strcmp(name, "driver") == 0)
143 return 0;
144 if (strcmp(name, "bus") == 0)
145 return 0;
146
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100147 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200148 qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
149 name, value, dev->info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200150 return -1;
151 }
152 return 0;
153}
154
155DeviceState *qdev_device_add(QemuOpts *opts)
156{
157 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200158 DeviceInfo *info;
159 DeviceState *qdev;
160 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200161
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200162 driver = qemu_opt_get(opts, "driver");
163 if (!driver) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200164 qemu_error("-device: no driver specified\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200165 return NULL;
166 }
167 if (strcmp(driver, "?") == 0) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200168 char msg[256];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200169 for (info = device_info_list; info != NULL; info = info->next) {
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200170 qdev_print_devinfo(info, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200171 qemu_error("%s\n", msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200172 }
173 return NULL;
174 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200175
176 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200177 info = qdev_find_info(NULL, driver);
178 if (!info) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200179 qemu_error("Device \"%s\" not found. Try -device '?' for a list.\n",
180 driver);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200181 return NULL;
182 }
183 if (info->no_user) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200184 qemu_error("device \"%s\" can't be added via command line\n",
185 info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200186 return NULL;
187 }
188
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200189 /* find bus */
190 path = qemu_opt_get(opts, "bus");
191 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200192 bus = qbus_find(path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200193 } else {
194 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200195 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200196 if (!bus) {
197 qemu_error("Did not find %s bus for %s\n",
198 path ? path : info->bus_info->name, info->name);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200199 return NULL;
Gerd Hoffmann75570082009-08-31 14:23:58 +0200200 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200201 if (qdev_hotplug && !bus->allow_hotplug) {
202 qemu_error("Bus %s does not support hotplugging\n",
203 bus->name);
204 return NULL;
205 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200206
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200207 /* create device, set properties */
208 qdev = qdev_create(bus, driver);
209 id = qemu_opts_id(opts);
210 if (id) {
211 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200212 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200213 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
214 qdev_free(qdev);
215 return NULL;
216 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200217 if (qdev_init(qdev) < 0) {
Amit Shahc8cd1fc2009-09-29 15:51:03 +0530218 qemu_error("Error initializing device %s\n", driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200219 return NULL;
220 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200221 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200222 return qdev;
223}
224
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300225static void qdev_reset(void *opaque)
226{
227 DeviceState *dev = opaque;
228 if (dev->info->reset)
229 dev->info->reset(dev);
230}
231
Paul Brookaae94602009-05-14 22:35:06 +0100232/* Initialize a device. Device properties should be set before calling
233 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200234 calling this function.
235 On failure, destroy the device and return negative value.
236 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200237int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100238{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200239 int rc;
240
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200241 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200242 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200243 if (rc < 0) {
244 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200245 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200246 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300247 qemu_register_reset(qdev_reset, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200248 if (dev->info->vmsd)
249 vmstate_register(-1, dev->info->vmsd, dev);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200250 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200251 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100252}
253
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200254int qdev_unplug(DeviceState *dev)
255{
256 if (!dev->parent_bus->allow_hotplug) {
257 qemu_error("Bus %s does not support hotplugging\n",
258 dev->parent_bus->name);
259 return -1;
260 }
261 return dev->info->unplug(dev);
262}
263
264/* can be used as ->unplug() callback for the simple cases */
265int qdev_simple_unplug_cb(DeviceState *dev)
266{
267 /* just zap it */
268 qdev_free(dev);
269 return 0;
270}
271
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200272/* Like qdev_init(), but terminate program via hw_error() instead of
273 returning an error value. This is okay during machine creation.
274 Don't use for hotplug, because there callers need to recover from
275 failure. Exception: if you know the device's init() callback can't
276 fail, then qdev_init_nofail() can't fail either, and is therefore
277 usable even then. But relying on the device implementation that
278 way is somewhat unclean, and best avoided. */
279void qdev_init_nofail(DeviceState *dev)
280{
281 DeviceInfo *info = dev->info;
282
283 if (qdev_init(dev) < 0)
284 hw_error("Initialization of device %s failed\n", info->name);
285}
286
Paul Brook02e2da42009-05-23 00:05:19 +0100287/* Unlink device from bus and free the structure. */
288void qdev_free(DeviceState *dev)
289{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200290 BusState *bus;
291
292 if (dev->state == DEV_STATE_INITIALIZED) {
293 while (dev->num_child_bus) {
294 bus = QLIST_FIRST(&dev->child_bus);
295 qbus_free(bus);
296 }
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200297#if 0 /* FIXME: need sane vmstate_unregister function */
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200298 if (dev->info->vmsd)
299 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmann391a0792009-09-01 09:56:14 +0200300#endif
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200301 if (dev->info->exit)
302 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200303 if (dev->opts)
304 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200305 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300306 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000307 QLIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200308 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100309}
310
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200311void qdev_machine_creation_done(void)
312{
313 /*
314 * ok, initial machine setup is done, starting from now we can
315 * only create hotpluggable devices
316 */
317 qdev_hotplug = 1;
318}
319
Paul Brookaae94602009-05-14 22:35:06 +0100320/* Get a character (serial) device interface. */
321CharDriverState *qdev_init_chardev(DeviceState *dev)
322{
323 static int next_serial;
324 static int next_virtconsole;
325 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200326 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100327 return virtcon_hds[next_virtconsole++];
328 } else {
329 return serial_hds[next_serial++];
330 }
331}
332
Paul Brook02e2da42009-05-23 00:05:19 +0100333BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100334{
Paul Brook02e2da42009-05-23 00:05:19 +0100335 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100336}
337
Paul Brookaae94602009-05-14 22:35:06 +0100338void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
339{
340 assert(dev->num_gpio_in == 0);
341 dev->num_gpio_in = n;
342 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
343}
344
345void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
346{
347 assert(dev->num_gpio_out == 0);
348 dev->num_gpio_out = n;
349 dev->gpio_out = pins;
350}
351
352qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
353{
354 assert(n >= 0 && n < dev->num_gpio_in);
355 return dev->gpio_in[n];
356}
357
358void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
359{
360 assert(n >= 0 && n < dev->num_gpio_out);
361 dev->gpio_out[n] = pin;
362}
363
Paul Brook9d07d752009-05-14 22:35:07 +0100364VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100365 NetCanReceive *can_receive,
366 NetReceive *receive,
367 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100368 NetCleanup *cleanup,
369 void *opaque)
370{
371 NICInfo *nd = dev->nd;
372 assert(nd);
Mark McLoughlin283c7c62009-10-08 19:58:30 +0100373 nd->vc = qemu_new_vlan_client(nd->vlan, nd->netdev,
374 nd->model, nd->name,
375 can_receive, receive, receive_iov,
376 cleanup, opaque);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100377 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100378}
379
380
381void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
382{
383 memcpy(macaddr, dev->nd->macaddr, 6);
384}
385
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200386void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
387{
388 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
389 if (nd->vlan)
390 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
391 if (nd->netdev)
392 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200393 if (nd->nvectors != NIC_NVECTORS_UNSPECIFIED &&
394 qdev_prop_exists(dev, "vectors")) {
395 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
396 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200397}
398
Paul Brookaae94602009-05-14 22:35:06 +0100399static int next_block_unit[IF_COUNT];
400
401/* Get a block device. This should only be used for single-drive devices
402 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
403 appropriate bus. */
404BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
405{
406 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200407 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100408
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200409 dinfo = drive_get(type, 0, unit);
410 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100411}
Paul Brook4d6ae672009-05-14 22:35:06 +0100412
Paul Brook02e2da42009-05-23 00:05:19 +0100413BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100414{
Paul Brook02e2da42009-05-23 00:05:19 +0100415 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100416
Blue Swirl72cf2d42009-09-12 07:36:22 +0000417 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100418 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100419 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100420 }
421 }
422 return NULL;
423}
424
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200425static BusState *qbus_find_recursive(BusState *bus, const char *name,
426 const BusInfo *info)
427{
428 DeviceState *dev;
429 BusState *child, *ret;
430 int match = 1;
431
432 if (name && (strcmp(bus->name, name) != 0)) {
433 match = 0;
434 }
435 if (info && (bus->info != info)) {
436 match = 0;
437 }
438 if (match) {
439 return bus;
440 }
441
Blue Swirl72cf2d42009-09-12 07:36:22 +0000442 QLIST_FOREACH(dev, &bus->children, sibling) {
443 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200444 ret = qbus_find_recursive(child, name, info);
445 if (ret) {
446 return ret;
447 }
448 }
449 }
450 return NULL;
451}
452
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200453static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
454{
455 DeviceState *dev, *ret;
456 BusState *child;
457
458 QLIST_FOREACH(dev, &bus->children, sibling) {
459 if (dev->id && strcmp(dev->id, id) == 0)
460 return dev;
461 QLIST_FOREACH(child, &dev->child_bus, sibling) {
462 ret = qdev_find_recursive(child, id);
463 if (ret) {
464 return ret;
465 }
466 }
467 }
468 return NULL;
469}
470
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200471static void qbus_list_bus(DeviceState *dev, char *dest, int len)
472{
473 BusState *child;
474 const char *sep = " ";
475 int pos = 0;
476
477 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
478 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000479 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200480 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
481 sep = ", ";
482 }
483}
484
485static void qbus_list_dev(BusState *bus, char *dest, int len)
486{
487 DeviceState *dev;
488 const char *sep = " ";
489 int pos = 0;
490
491 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
492 bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000493 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200494 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
495 sep, dev->info->name);
496 if (dev->id)
497 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
498 sep = ", ";
499 }
500}
501
502static BusState *qbus_find_bus(DeviceState *dev, char *elem)
503{
504 BusState *child;
505
Blue Swirl72cf2d42009-09-12 07:36:22 +0000506 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200507 if (strcmp(child->name, elem) == 0) {
508 return child;
509 }
510 }
511 return NULL;
512}
513
514static DeviceState *qbus_find_dev(BusState *bus, char *elem)
515{
516 DeviceState *dev;
517
518 /*
519 * try to match in order:
520 * (1) instance id, if present
521 * (2) driver name
522 * (3) driver alias, if present
523 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000524 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200525 if (dev->id && strcmp(dev->id, elem) == 0) {
526 return dev;
527 }
528 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000529 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200530 if (strcmp(dev->info->name, elem) == 0) {
531 return dev;
532 }
533 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000534 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200535 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
536 return dev;
537 }
538 }
539 return NULL;
540}
541
542static BusState *qbus_find(const char *path)
543{
544 DeviceState *dev;
545 BusState *bus;
546 char elem[128], msg[256];
547 int pos, len;
548
549 /* find start element */
550 if (path[0] == '/') {
551 bus = main_system_bus;
552 pos = 0;
553 } else {
554 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200555 qemu_error("path parse error (\"%s\")\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200556 return NULL;
557 }
558 bus = qbus_find_recursive(main_system_bus, elem, NULL);
559 if (!bus) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200560 qemu_error("bus \"%s\" not found\n", elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200561 return NULL;
562 }
563 pos = len;
564 }
565
566 for (;;) {
567 if (path[pos] == '\0') {
568 /* we are done */
569 return bus;
570 }
571
572 /* find device */
573 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200574 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200575 return NULL;
576 }
577 pos += len;
578 dev = qbus_find_dev(bus, elem);
579 if (!dev) {
580 qbus_list_dev(bus, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200581 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200582 return NULL;
583 }
584 if (path[pos] == '\0') {
585 /* last specified element is a device. If it has exactly
586 * one child bus accept it nevertheless */
587 switch (dev->num_child_bus) {
588 case 0:
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200589 qemu_error("device has no child bus (%s)\n", path);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200590 return NULL;
591 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000592 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200593 default:
594 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200595 qemu_error("device has multiple child busses (%s)\n%s\n",
596 path, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200597 return NULL;
598 }
599 }
600
601 /* find bus */
602 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200603 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200604 return NULL;
605 }
606 pos += len;
607 bus = qbus_find_bus(dev, elem);
608 if (!bus) {
609 qbus_list_bus(dev, msg, sizeof(msg));
Gerd Hoffmann286c2322009-08-14 10:36:08 +0200610 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200611 return NULL;
612 }
613 }
614}
615
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200616void qbus_create_inplace(BusState *bus, BusInfo *info,
617 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100618{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200619 char *buf;
620 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100621
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200622 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100623 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200624
625 if (name) {
626 /* use supplied name */
627 bus->name = qemu_strdup(name);
628 } else if (parent && parent->id) {
629 /* parent device has id -> use it for bus name */
630 len = strlen(parent->id) + 16;
631 buf = qemu_malloc(len);
632 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
633 bus->name = buf;
634 } else {
635 /* no id -> use lowercase bus type for bus name */
636 len = strlen(info->name) + 16;
637 buf = qemu_malloc(len);
638 len = snprintf(buf, len, "%s.%d", info->name,
639 parent ? parent->num_child_bus : 0);
640 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200641 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200642 bus->name = buf;
643 }
644
Blue Swirl72cf2d42009-09-12 07:36:22 +0000645 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100646 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000647 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200648 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100649 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200650
651}
652
653BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
654{
655 BusState *bus;
656
657 bus = qemu_mallocz(info->size);
658 bus->qdev_allocated = 1;
659 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100660 return bus;
661}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100662
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200663void qbus_free(BusState *bus)
664{
665 DeviceState *dev;
666
667 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
668 qdev_free(dev);
669 }
670 if (bus->parent) {
671 QLIST_REMOVE(bus, sibling);
672 bus->parent->num_child_bus--;
673 }
674 if (bus->qdev_allocated) {
675 qemu_free(bus);
676 }
677}
678
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100679#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
680static void qbus_print(Monitor *mon, BusState *bus, int indent);
681
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200682static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
683 const char *prefix, int indent)
684{
685 char buf[64];
686
687 if (!props)
688 return;
689 while (props->name) {
690 if (props->info->print) {
691 props->info->print(dev, props, buf, sizeof(buf));
692 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
693 }
694 props++;
695 }
696}
697
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100698static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
699{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100700 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200701 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
702 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100703 indent += 2;
704 if (dev->num_gpio_in) {
705 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
706 }
707 if (dev->num_gpio_out) {
708 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
709 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200710 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
711 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200712 if (dev->parent_bus->info->print_dev)
713 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000714 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100715 qbus_print(mon, child, indent);
716 }
717}
718
719static void qbus_print(Monitor *mon, BusState *bus, int indent)
720{
721 struct DeviceState *dev;
722
723 qdev_printf("bus: %s\n", bus->name);
724 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200725 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000726 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100727 qdev_print(mon, dev, indent);
728 }
729}
730#undef qdev_printf
731
732void do_info_qtree(Monitor *mon)
733{
734 if (main_system_bus)
735 qbus_print(mon, main_system_bus, 0);
736}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200737
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200738void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200739{
740 DeviceInfo *info;
741 char msg[256];
742
743 for (info = device_info_list; info != NULL; info = info->next) {
744 qdev_print_devinfo(info, msg, sizeof(msg));
745 monitor_printf(mon, "%s\n", msg);
746 }
747}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200748
749void do_device_add(Monitor *mon, const QDict *qdict)
750{
751 QemuOpts *opts;
752
753 opts = qemu_opts_parse(&qemu_device_opts,
754 qdict_get_str(qdict, "config"), "driver");
755 if (opts)
756 qdev_device_add(opts);
757}
758
759void do_device_del(Monitor *mon, const QDict *qdict)
760{
761 const char *id = qdict_get_str(qdict, "id");
762 DeviceState *dev;
763
764 dev = qdev_find_recursive(main_system_bus, id);
765 if (NULL == dev) {
766 qemu_error("Device '%s' not found\n", id);
767 return;
768 }
769 qdev_unplug(dev);
770}