blob: 29f6e9fcd5af0c3f5553e2e4fce0f5c05ad8d01e [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 Hoffmann0958b4c2009-10-26 15:56:45 +010038DeviceInfo *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
Markus Armbruster0c175422010-02-19 19:12:18 +010080static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010081{
Paul Brookaae94602009-05-14 22:35:06 +010082 DeviceState *dev;
83
Markus Armbruster0c175422010-02-19 19:12:18 +010084 assert(bus->info == info->bus_info);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020085 dev = qemu_mallocz(info->size);
86 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010087 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020088 qdev_prop_set_defaults(dev, dev->info->props);
89 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmann458fb672009-12-08 13:11:33 +010090 qdev_prop_set_globals(dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +000091 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +020092 if (qdev_hotplug) {
93 assert(bus->allow_hotplug);
94 dev->hotplugged = 1;
95 }
Jan Kiszka4d2ffa02010-05-15 13:32:40 +020096 dev->instance_id_alias = -1;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +020097 dev->state = DEV_STATE_CREATED;
Paul Brookaae94602009-05-14 22:35:06 +010098 return dev;
99}
100
Markus Armbruster0c175422010-02-19 19:12:18 +0100101/* Create a new device. This only initializes the device state structure
102 and allows properties to be set. qdev_init should be called to
103 initialize the actual device emulation. */
104DeviceState *qdev_create(BusState *bus, const char *name)
105{
106 DeviceInfo *info;
107
108 if (!bus) {
109 if (!main_system_bus) {
110 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
111 }
112 bus = main_system_bus;
113 }
114
115 info = qdev_find_info(bus->info, name);
116 if (!info) {
117 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
118 }
119
120 return qdev_create_from_info(bus, info);
121}
122
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100123static void qdev_print_devinfo(DeviceInfo *info)
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200124{
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100125 error_printf("name \"%s\", bus %s",
126 info->name, info->bus_info->name);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200127 if (info->alias) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100128 error_printf(", alias \"%s\"", info->alias);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200129 }
130 if (info->desc) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100131 error_printf(", desc \"%s\"", info->desc);
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200132 }
133 if (info->no_user) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100134 error_printf(", no-user");
Gerd Hoffmann22f2e342009-08-03 11:26:48 +0200135 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100136 error_printf("\n");
Gerd Hoffmann1b524b02009-07-29 13:12:23 +0200137}
138
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200139static int set_property(const char *name, const char *value, void *opaque)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200140{
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200141 DeviceState *dev = opaque;
142
143 if (strcmp(name, "driver") == 0)
144 return 0;
145 if (strcmp(name, "bus") == 0)
146 return 0;
147
Mark McLoughlin3df04ac2009-09-23 11:24:05 +0100148 if (qdev_prop_parse(dev, name, value) == -1) {
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200149 return -1;
150 }
151 return 0;
152}
153
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100154int qdev_device_help(QemuOpts *opts)
155{
156 const char *driver;
157 DeviceInfo *info;
Markus Armbruster08350cf2010-01-29 19:49:00 +0100158 Property *prop;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100159
160 driver = qemu_opt_get(opts, "driver");
161 if (driver && !strcmp(driver, "?")) {
162 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100163 if (info->no_user) {
164 continue; /* not available, don't show */
165 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100166 qdev_print_devinfo(info);
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100167 }
168 return 1;
169 }
170
Markus Armbruster08350cf2010-01-29 19:49:00 +0100171 if (!qemu_opt_get(opts, "?")) {
172 return 0;
173 }
174
175 info = qdev_find_info(NULL, driver);
176 if (!info) {
177 return 0;
178 }
179
180 for (prop = info->props; prop && prop->name; prop++) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100181 /*
182 * TODO Properties without a parser are just for dirty hacks.
183 * qdev_prop_ptr is the only such PropertyInfo. It's marked
184 * for removal. This conditional should be removed along with
185 * it.
186 */
187 if (!prop->info->parse) {
188 continue; /* no way to set it, don't show */
189 }
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100190 error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
Markus Armbruster08350cf2010-01-29 19:49:00 +0100191 }
192 return 1;
Markus Armbrusterff952ba2010-01-29 19:48:57 +0100193}
194
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200195DeviceState *qdev_device_add(QemuOpts *opts)
196{
197 const char *driver, *path, *id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200198 DeviceInfo *info;
199 DeviceState *qdev;
200 BusState *bus;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200201
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200202 driver = qemu_opt_get(opts, "driver");
203 if (!driver) {
Markus Armbruster02042762010-02-19 14:17:34 +0100204 qerror_report(QERR_MISSING_PARAMETER, "driver");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200205 return NULL;
206 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200207
208 /* find driver */
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200209 info = qdev_find_info(NULL, driver);
Markus Armbrusterc64eafa2010-02-19 13:31:49 +0100210 if (!info || info->no_user) {
Markus Armbrustere17ba872010-03-25 17:22:36 +0100211 qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
Markus Armbruster02042762010-02-19 14:17:34 +0100212 error_printf_unless_qmp("Try with argument '?' for a list.\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200213 return NULL;
214 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200215
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200216 /* find bus */
217 path = qemu_opt_get(opts, "bus");
218 if (path != NULL) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200219 bus = qbus_find(path);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100220 if (!bus) {
221 return NULL;
222 }
223 if (bus->info != info->bus_info) {
Markus Armbruster02042762010-02-19 14:17:34 +0100224 qerror_report(QERR_BAD_BUS_FOR_DEVICE,
225 driver, bus->info->name);
Markus Armbruster327867b2010-02-19 19:08:45 +0100226 return NULL;
227 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200228 } else {
229 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100230 if (!bus) {
Markus Armbruster02042762010-02-19 14:17:34 +0100231 qerror_report(QERR_NO_BUS_FOR_DEVICE,
232 info->name, info->bus_info->name);
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100233 return NULL;
234 }
Gerd Hoffmann75570082009-08-31 14:23:58 +0200235 }
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200236 if (qdev_hotplug && !bus->allow_hotplug) {
Markus Armbruster02042762010-02-19 14:17:34 +0100237 qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200238 return NULL;
239 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200240
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200241 /* create device, set properties */
Markus Armbruster0c175422010-02-19 19:12:18 +0100242 qdev = qdev_create_from_info(bus, info);
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200243 id = qemu_opts_id(opts);
244 if (id) {
245 qdev->id = id;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200246 }
Gerd Hoffmannf31d07d2009-07-31 12:25:37 +0200247 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
248 qdev_free(qdev);
249 return NULL;
250 }
Markus Armbruster5c17ca22009-10-07 01:16:01 +0200251 if (qdev_init(qdev) < 0) {
Markus Armbruster02042762010-02-19 14:17:34 +0100252 qerror_report(QERR_DEVICE_INIT_FAILED, driver);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200253 return NULL;
254 }
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200255 qdev->opts = opts;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200256 return qdev;
257}
258
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300259static void qdev_reset(void *opaque)
260{
261 DeviceState *dev = opaque;
262 if (dev->info->reset)
263 dev->info->reset(dev);
264}
265
Paul Brookaae94602009-05-14 22:35:06 +0100266/* Initialize a device. Device properties should be set before calling
267 this function. IRQs and MMIO regions should be connected/mapped after
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200268 calling this function.
269 On failure, destroy the device and return negative value.
270 Return 0 on success. */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200271int qdev_init(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100272{
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200273 int rc;
274
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200275 assert(dev->state == DEV_STATE_CREATED);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200276 rc = dev->info->init(dev, dev->info);
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200277 if (rc < 0) {
278 qdev_free(dev);
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200279 return rc;
Markus Armbruster18cfeb52009-10-07 01:15:56 +0200280 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300281 qemu_register_reset(qdev_reset, dev);
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200282 if (dev->info->vmsd) {
283 vmstate_register_with_alias_id(-1, dev->info->vmsd, dev,
284 dev->instance_id_alias,
285 dev->alias_required_for_version);
286 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200287 dev->state = DEV_STATE_INITIALIZED;
Gerd Hoffmann959f7332009-09-01 09:56:12 +0200288 return 0;
Paul Brook02e2da42009-05-23 00:05:19 +0100289}
290
Jan Kiszka4d2ffa02010-05-15 13:32:40 +0200291void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
292 int required_for_version)
293{
294 assert(dev->state == DEV_STATE_CREATED);
295 dev->instance_id_alias = alias_id;
296 dev->alias_required_for_version = required_for_version;
297}
298
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200299int qdev_unplug(DeviceState *dev)
300{
301 if (!dev->parent_bus->allow_hotplug) {
Markus Armbrustercc601cb2010-03-22 11:38:13 +0100302 qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200303 return -1;
304 }
Amit Shah593831d2009-11-02 14:56:41 +0530305 assert(dev->info->unplug != NULL);
306
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200307 return dev->info->unplug(dev);
308}
309
310/* can be used as ->unplug() callback for the simple cases */
311int qdev_simple_unplug_cb(DeviceState *dev)
312{
313 /* just zap it */
314 qdev_free(dev);
315 return 0;
316}
317
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200318/* Like qdev_init(), but terminate program via hw_error() instead of
319 returning an error value. This is okay during machine creation.
320 Don't use for hotplug, because there callers need to recover from
321 failure. Exception: if you know the device's init() callback can't
322 fail, then qdev_init_nofail() can't fail either, and is therefore
323 usable even then. But relying on the device implementation that
324 way is somewhat unclean, and best avoided. */
325void qdev_init_nofail(DeviceState *dev)
326{
327 DeviceInfo *info = dev->info;
328
329 if (qdev_init(dev) < 0)
330 hw_error("Initialization of device %s failed\n", info->name);
331}
332
Paul Brook02e2da42009-05-23 00:05:19 +0100333/* Unlink device from bus and free the structure. */
334void qdev_free(DeviceState *dev)
335{
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200336 BusState *bus;
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200337 Property *prop;
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200338
339 if (dev->state == DEV_STATE_INITIALIZED) {
340 while (dev->num_child_bus) {
341 bus = QLIST_FIRST(&dev->child_bus);
342 qbus_free(bus);
343 }
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200344 if (dev->info->vmsd)
345 vmstate_unregister(dev->info->vmsd, dev);
Gerd Hoffmannd29275f2009-09-25 21:42:35 +0200346 if (dev->info->exit)
347 dev->info->exit(dev);
Gerd Hoffmannef80b462009-09-25 21:42:49 +0200348 if (dev->opts)
349 qemu_opts_del(dev->opts);
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200350 }
Michael S. Tsirkin7f23f812009-09-16 13:40:27 +0300351 qemu_unregister_reset(qdev_reset, dev);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000352 QLIST_REMOVE(dev, sibling);
Markus Armbrusterd21357d2010-06-01 20:32:31 +0200353 for (prop = dev->info->props; prop && prop->name; prop++) {
354 if (prop->info->free) {
355 prop->info->free(dev, prop);
356 }
357 }
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200358 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100359}
360
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200361void qdev_machine_creation_done(void)
362{
363 /*
364 * ok, initial machine setup is done, starting from now we can
365 * only create hotpluggable devices
366 */
367 qdev_hotplug = 1;
368}
369
Paul Brookaae94602009-05-14 22:35:06 +0100370/* Get a character (serial) device interface. */
371CharDriverState *qdev_init_chardev(DeviceState *dev)
372{
373 static int next_serial;
Amit Shah98b19252010-01-20 00:36:52 +0530374
375 /* FIXME: This function needs to go away: use chardev properties! */
376 return serial_hds[next_serial++];
Paul Brookaae94602009-05-14 22:35:06 +0100377}
378
Paul Brook02e2da42009-05-23 00:05:19 +0100379BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100380{
Paul Brook02e2da42009-05-23 00:05:19 +0100381 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100382}
383
Paul Brookaae94602009-05-14 22:35:06 +0100384void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
385{
386 assert(dev->num_gpio_in == 0);
387 dev->num_gpio_in = n;
388 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
389}
390
391void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
392{
393 assert(dev->num_gpio_out == 0);
394 dev->num_gpio_out = n;
395 dev->gpio_out = pins;
396}
397
398qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
399{
400 assert(n >= 0 && n < dev->num_gpio_in);
401 return dev->gpio_in[n];
402}
403
404void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
405{
406 assert(n >= 0 && n < dev->num_gpio_out);
407 dev->gpio_out[n] = pin;
408}
409
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200410void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
411{
412 qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
413 if (nd->vlan)
414 qdev_prop_set_vlan(dev, "vlan", nd->vlan);
415 if (nd->netdev)
416 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
Amit Shah75422b02010-02-25 17:24:43 +0530417 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
Gerd Hoffmann97b15622009-10-21 15:25:35 +0200418 qdev_prop_exists(dev, "vectors")) {
419 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
420 }
Gerd Hoffmanned16ab52009-10-21 15:25:26 +0200421}
422
Paul Brookaae94602009-05-14 22:35:06 +0100423static int next_block_unit[IF_COUNT];
424
425/* Get a block device. This should only be used for single-drive devices
426 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
427 appropriate bus. */
428BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
429{
430 int unit = next_block_unit[type]++;
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200431 DriveInfo *dinfo;
Paul Brookaae94602009-05-14 22:35:06 +0100432
Gerd Hoffmann751c6a12009-07-22 16:42:57 +0200433 dinfo = drive_get(type, 0, unit);
434 return dinfo ? dinfo->bdrv : NULL;
Paul Brookaae94602009-05-14 22:35:06 +0100435}
Paul Brook4d6ae672009-05-14 22:35:06 +0100436
Paul Brook02e2da42009-05-23 00:05:19 +0100437BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100438{
Paul Brook02e2da42009-05-23 00:05:19 +0100439 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100440
Blue Swirl72cf2d42009-09-12 07:36:22 +0000441 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100442 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100443 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100444 }
445 }
446 return NULL;
447}
448
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200449static BusState *qbus_find_recursive(BusState *bus, const char *name,
450 const BusInfo *info)
451{
452 DeviceState *dev;
453 BusState *child, *ret;
454 int match = 1;
455
456 if (name && (strcmp(bus->name, name) != 0)) {
457 match = 0;
458 }
459 if (info && (bus->info != info)) {
460 match = 0;
461 }
462 if (match) {
463 return bus;
464 }
465
Blue Swirl72cf2d42009-09-12 07:36:22 +0000466 QLIST_FOREACH(dev, &bus->children, sibling) {
467 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200468 ret = qbus_find_recursive(child, name, info);
469 if (ret) {
470 return ret;
471 }
472 }
473 }
474 return NULL;
475}
476
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200477static DeviceState *qdev_find_recursive(BusState *bus, const char *id)
478{
479 DeviceState *dev, *ret;
480 BusState *child;
481
482 QLIST_FOREACH(dev, &bus->children, sibling) {
483 if (dev->id && strcmp(dev->id, id) == 0)
484 return dev;
485 QLIST_FOREACH(child, &dev->child_bus, sibling) {
486 ret = qdev_find_recursive(child, id);
487 if (ret) {
488 return ret;
489 }
490 }
491 }
492 return NULL;
493}
494
Markus Armbruster53db16b2010-02-18 18:55:59 +0100495static void qbus_list_bus(DeviceState *dev)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200496{
497 BusState *child;
498 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200499
Markus Armbruster53db16b2010-02-18 18:55:59 +0100500 error_printf("child busses at \"%s\":",
501 dev->id ? dev->id : dev->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000502 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100503 error_printf("%s\"%s\"", sep, child->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200504 sep = ", ";
505 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100506 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200507}
508
Markus Armbruster53db16b2010-02-18 18:55:59 +0100509static void qbus_list_dev(BusState *bus)
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200510{
511 DeviceState *dev;
512 const char *sep = " ";
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200513
Markus Armbruster53db16b2010-02-18 18:55:59 +0100514 error_printf("devices at \"%s\":", bus->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000515 QLIST_FOREACH(dev, &bus->children, sibling) {
Markus Armbruster53db16b2010-02-18 18:55:59 +0100516 error_printf("%s\"%s\"", sep, dev->info->name);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200517 if (dev->id)
Markus Armbruster53db16b2010-02-18 18:55:59 +0100518 error_printf("/\"%s\"", dev->id);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200519 sep = ", ";
520 }
Markus Armbruster53db16b2010-02-18 18:55:59 +0100521 error_printf("\n");
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200522}
523
524static BusState *qbus_find_bus(DeviceState *dev, char *elem)
525{
526 BusState *child;
527
Blue Swirl72cf2d42009-09-12 07:36:22 +0000528 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200529 if (strcmp(child->name, elem) == 0) {
530 return child;
531 }
532 }
533 return NULL;
534}
535
536static DeviceState *qbus_find_dev(BusState *bus, char *elem)
537{
538 DeviceState *dev;
539
540 /*
541 * try to match in order:
542 * (1) instance id, if present
543 * (2) driver name
544 * (3) driver alias, if present
545 */
Blue Swirl72cf2d42009-09-12 07:36:22 +0000546 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200547 if (dev->id && strcmp(dev->id, elem) == 0) {
548 return dev;
549 }
550 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000551 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200552 if (strcmp(dev->info->name, elem) == 0) {
553 return dev;
554 }
555 }
Blue Swirl72cf2d42009-09-12 07:36:22 +0000556 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200557 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
558 return dev;
559 }
560 }
561 return NULL;
562}
563
564static BusState *qbus_find(const char *path)
565{
566 DeviceState *dev;
567 BusState *bus;
Markus Armbruster53db16b2010-02-18 18:55:59 +0100568 char elem[128];
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200569 int pos, len;
570
571 /* find start element */
572 if (path[0] == '/') {
573 bus = main_system_bus;
574 pos = 0;
575 } else {
576 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100577 assert(!path[0]);
578 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200579 }
580 bus = qbus_find_recursive(main_system_bus, elem, NULL);
581 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100582 qerror_report(QERR_BUS_NOT_FOUND, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200583 return NULL;
584 }
585 pos = len;
586 }
587
588 for (;;) {
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100589 assert(path[pos] == '/' || !path[pos]);
590 while (path[pos] == '/') {
591 pos++;
592 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200593 if (path[pos] == '\0') {
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200594 return bus;
595 }
596
597 /* find device */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100598 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
599 assert(0);
600 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200601 }
602 pos += len;
603 dev = qbus_find_dev(bus, elem);
604 if (!dev) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100605 qerror_report(QERR_DEVICE_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100606 if (!monitor_cur_is_qmp()) {
607 qbus_list_dev(bus);
608 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200609 return NULL;
610 }
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100611
612 assert(path[pos] == '/' || !path[pos]);
613 while (path[pos] == '/') {
614 pos++;
615 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200616 if (path[pos] == '\0') {
617 /* last specified element is a device. If it has exactly
618 * one child bus accept it nevertheless */
619 switch (dev->num_child_bus) {
620 case 0:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100621 qerror_report(QERR_DEVICE_NO_BUS, elem);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200622 return NULL;
623 case 1:
Blue Swirl72cf2d42009-09-12 07:36:22 +0000624 return QLIST_FIRST(&dev->child_bus);
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200625 default:
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100626 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100627 if (!monitor_cur_is_qmp()) {
628 qbus_list_bus(dev);
629 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200630 return NULL;
631 }
632 }
633
634 /* find bus */
Markus Armbrusterfc98eb42010-02-19 16:09:25 +0100635 if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
636 assert(0);
637 elem[0] = len = 0;
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200638 }
639 pos += len;
640 bus = qbus_find_bus(dev, elem);
641 if (!bus) {
Markus Armbrusterac8dae62010-02-19 18:09:33 +0100642 qerror_report(QERR_BUS_NOT_FOUND, elem);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100643 if (!monitor_cur_is_qmp()) {
644 qbus_list_bus(dev);
645 }
Gerd Hoffmann8ffb1bc2009-07-15 13:59:25 +0200646 return NULL;
647 }
648 }
649}
650
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200651void qbus_create_inplace(BusState *bus, BusInfo *info,
652 DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100653{
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200654 char *buf;
655 int i,len;
Paul Brook02e2da42009-05-23 00:05:19 +0100656
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200657 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100658 bus->parent = parent;
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200659
660 if (name) {
661 /* use supplied name */
662 bus->name = qemu_strdup(name);
663 } else if (parent && parent->id) {
664 /* parent device has id -> use it for bus name */
665 len = strlen(parent->id) + 16;
666 buf = qemu_malloc(len);
667 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
668 bus->name = buf;
669 } else {
670 /* no id -> use lowercase bus type for bus name */
671 len = strlen(info->name) + 16;
672 buf = qemu_malloc(len);
673 len = snprintf(buf, len, "%s.%d", info->name,
674 parent ? parent->num_child_bus : 0);
675 for (i = 0; i < len; i++)
Christoph Eggerbb87ece2009-07-30 15:28:45 +0200676 buf[i] = qemu_tolower(buf[i]);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200677 bus->name = buf;
678 }
679
Blue Swirl72cf2d42009-09-12 07:36:22 +0000680 QLIST_INIT(&bus->children);
Paul Brook02e2da42009-05-23 00:05:19 +0100681 if (parent) {
Blue Swirl72cf2d42009-09-12 07:36:22 +0000682 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
Gerd Hoffmannd271de92009-07-15 13:59:24 +0200683 parent->num_child_bus++;
Paul Brook02e2da42009-05-23 00:05:19 +0100684 }
Gerd Hoffmanncd739fb2009-09-16 22:25:27 +0200685
686}
687
688BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
689{
690 BusState *bus;
691
692 bus = qemu_mallocz(info->size);
693 bus->qdev_allocated = 1;
694 qbus_create_inplace(bus, info, parent, name);
Paul Brook02e2da42009-05-23 00:05:19 +0100695 return bus;
696}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100697
Gerd Hoffmann131ec1b2009-09-25 21:42:34 +0200698void qbus_free(BusState *bus)
699{
700 DeviceState *dev;
701
702 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
703 qdev_free(dev);
704 }
705 if (bus->parent) {
706 QLIST_REMOVE(bus, sibling);
707 bus->parent->num_child_bus--;
708 }
709 if (bus->qdev_allocated) {
710 qemu_free(bus);
711 }
712}
713
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100714#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
715static void qbus_print(Monitor *mon, BusState *bus, int indent);
716
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200717static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
718 const char *prefix, int indent)
719{
720 char buf[64];
721
722 if (!props)
723 return;
724 while (props->name) {
Markus Armbruster036f7162010-02-19 11:47:06 +0100725 /*
726 * TODO Properties without a print method are just for dirty
727 * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
728 * marked for removal. The test props->info->print should be
729 * removed along with it.
730 */
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200731 if (props->info->print) {
732 props->info->print(dev, props, buf, sizeof(buf));
733 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
734 }
735 props++;
736 }
737}
738
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100739static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
740{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100741 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200742 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
743 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100744 indent += 2;
745 if (dev->num_gpio_in) {
746 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
747 }
748 if (dev->num_gpio_out) {
749 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
750 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200751 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
752 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200753 if (dev->parent_bus->info->print_dev)
754 dev->parent_bus->info->print_dev(mon, dev, indent);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000755 QLIST_FOREACH(child, &dev->child_bus, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100756 qbus_print(mon, child, indent);
757 }
758}
759
760static void qbus_print(Monitor *mon, BusState *bus, int indent)
761{
762 struct DeviceState *dev;
763
764 qdev_printf("bus: %s\n", bus->name);
765 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200766 qdev_printf("type %s\n", bus->info->name);
Blue Swirl72cf2d42009-09-12 07:36:22 +0000767 QLIST_FOREACH(dev, &bus->children, sibling) {
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100768 qdev_print(mon, dev, indent);
769 }
770}
771#undef qdev_printf
772
773void do_info_qtree(Monitor *mon)
774{
775 if (main_system_bus)
776 qbus_print(mon, main_system_bus, 0);
777}
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200778
Gerd Hoffmannf6c64e02009-08-03 15:03:09 +0200779void do_info_qdm(Monitor *mon)
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200780{
781 DeviceInfo *info;
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200782
783 for (info = device_info_list; info != NULL; info = info->next) {
Markus Armbruster8a9662c2010-02-18 18:44:15 +0100784 qdev_print_devinfo(info);
Gerd Hoffmann9316d302009-07-29 13:12:24 +0200785 }
786}
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200787
Markus Armbruster8bc27242010-02-10 20:52:01 +0100788int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200789{
790 QemuOpts *opts;
791
Markus Armbrusterc7e4e8c2010-02-10 20:47:28 +0100792 opts = qemu_opts_from_qdict(&qemu_device_opts, qdict);
Markus Armbruster8bc27242010-02-10 20:52:01 +0100793 if (!opts) {
794 return -1;
Kevin Wolf0f853a32010-02-16 13:12:38 +0100795 }
Markus Armbruster8bc27242010-02-10 20:52:01 +0100796 if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
797 qemu_opts_del(opts);
798 return 0;
799 }
800 if (!qdev_device_add(opts)) {
801 qemu_opts_del(opts);
802 return -1;
803 }
804 return 0;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200805}
806
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100807int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200808{
809 const char *id = qdict_get_str(qdict, "id");
810 DeviceState *dev;
811
812 dev = qdev_find_recursive(main_system_bus, id);
813 if (NULL == dev) {
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100814 qerror_report(QERR_DEVICE_NOT_FOUND, id);
815 return -1;
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200816 }
Markus Armbruster17a38ea2010-03-22 11:38:14 +0100817 return qdev_unplug(dev);
Gerd Hoffmann3418bd22009-09-25 21:42:41 +0200818}