Add exit callback to DeviceInfo.
[qemu.git] / hw / qdev.c
blob064389dcd032b3044356d9227d20c5e86ccfa84d
1 /*
2 * Dynamic device configuration and creation.
4 * Copyright (c) 2009 CodeSourcery
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.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
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. */
28 #include "net.h"
29 #include "qdev.h"
30 #include "sysemu.h"
31 #include "monitor.h"
33 /* This is a nasty hack to allow passing a NULL bus to qdev_create. */
34 static BusState *main_system_bus;
36 static DeviceInfo *device_info_list;
38 static BusState *qbus_find_recursive(BusState *bus, const char *name,
39 const BusInfo *info);
40 static BusState *qbus_find(const char *path);
42 /* Register a new device type. */
43 void qdev_register(DeviceInfo *info)
45 assert(info->size >= sizeof(DeviceState));
46 assert(!info->next);
48 info->next = device_info_list;
49 device_info_list = info;
52 static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
54 DeviceInfo *info;
56 /* first check device names */
57 for (info = device_info_list; info != NULL; info = info->next) {
58 if (bus_info && info->bus_info != bus_info)
59 continue;
60 if (strcmp(info->name, name) != 0)
61 continue;
62 return info;
65 /* failing that check the aliases */
66 for (info = device_info_list; info != NULL; info = info->next) {
67 if (bus_info && info->bus_info != bus_info)
68 continue;
69 if (!info->alias)
70 continue;
71 if (strcmp(info->alias, name) != 0)
72 continue;
73 return info;
75 return NULL;
78 /* Create a new device. This only initializes the device state structure
79 and allows properties to be set. qdev_init should be called to
80 initialize the actual device emulation. */
81 DeviceState *qdev_create(BusState *bus, const char *name)
83 DeviceInfo *info;
84 DeviceState *dev;
86 if (!bus) {
87 if (!main_system_bus) {
88 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
90 bus = main_system_bus;
93 info = qdev_find_info(bus->info, name);
94 if (!info) {
95 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
98 dev = qemu_mallocz(info->size);
99 dev->info = info;
100 dev->parent_bus = bus;
101 qdev_prop_set_defaults(dev, dev->info->props);
102 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
103 qdev_prop_set_compat(dev);
104 QLIST_INSERT_HEAD(&bus->children, dev, sibling);
105 dev->state = DEV_STATE_CREATED;
106 return dev;
109 static int qdev_print_devinfo(DeviceInfo *info, char *dest, int len)
111 int pos = 0;
112 int ret;
114 ret = snprintf(dest+pos, len-pos, "name \"%s\", bus %s",
115 info->name, info->bus_info->name);
116 pos += MIN(len-pos,ret);
117 if (info->alias) {
118 ret = snprintf(dest+pos, len-pos, ", alias \"%s\"", info->alias);
119 pos += MIN(len-pos,ret);
121 if (info->desc) {
122 ret = snprintf(dest+pos, len-pos, ", desc \"%s\"", info->desc);
123 pos += MIN(len-pos,ret);
125 if (info->no_user) {
126 ret = snprintf(dest+pos, len-pos, ", no-user");
127 pos += MIN(len-pos,ret);
129 return pos;
132 static int set_property(const char *name, const char *value, void *opaque)
134 DeviceState *dev = opaque;
136 if (strcmp(name, "driver") == 0)
137 return 0;
138 if (strcmp(name, "bus") == 0)
139 return 0;
141 if (qdev_prop_parse(dev, name, value) == -1) {
142 qemu_error("can't set property \"%s\" to \"%s\" for \"%s\"\n",
143 name, value, dev->info->name);
144 return -1;
146 return 0;
149 DeviceState *qdev_device_add(QemuOpts *opts)
151 const char *driver, *path, *id;
152 DeviceInfo *info;
153 DeviceState *qdev;
154 BusState *bus;
156 driver = qemu_opt_get(opts, "driver");
157 if (!driver) {
158 qemu_error("-device: no driver specified\n");
159 return NULL;
161 if (strcmp(driver, "?") == 0) {
162 char msg[256];
163 for (info = device_info_list; info != NULL; info = info->next) {
164 qdev_print_devinfo(info, msg, sizeof(msg));
165 qemu_error("%s\n", msg);
167 return NULL;
170 /* find driver */
171 info = qdev_find_info(NULL, driver);
172 if (!info) {
173 qemu_error("Device \"%s\" not found. Try -device '?' for a list.\n",
174 driver);
175 return NULL;
177 if (info->no_user) {
178 qemu_error("device \"%s\" can't be added via command line\n",
179 info->name);
180 return NULL;
183 /* find bus */
184 path = qemu_opt_get(opts, "bus");
185 if (path != NULL) {
186 bus = qbus_find(path);
187 } else {
188 bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
190 if (!bus) {
191 qemu_error("Did not find %s bus for %s\n",
192 path ? path : info->bus_info->name, info->name);
193 return NULL;
196 /* create device, set properties */
197 qdev = qdev_create(bus, driver);
198 id = qemu_opts_id(opts);
199 if (id) {
200 qdev->id = id;
202 if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
203 qdev_free(qdev);
204 return NULL;
206 if (qdev_init(qdev) != 0) {
207 qdev_free(qdev);
208 return NULL;
210 return qdev;
213 /* Initialize a device. Device properties should be set before calling
214 this function. IRQs and MMIO regions should be connected/mapped after
215 calling this function. */
216 int qdev_init(DeviceState *dev)
218 int rc;
220 assert(dev->state == DEV_STATE_CREATED);
221 rc = dev->info->init(dev, dev->info);
222 if (rc < 0)
223 return rc;
224 if (dev->info->reset)
225 qemu_register_reset(dev->info->reset, dev);
226 if (dev->info->vmsd)
227 vmstate_register(-1, dev->info->vmsd, dev);
228 dev->state = DEV_STATE_INITIALIZED;
229 return 0;
232 /* Unlink device from bus and free the structure. */
233 void qdev_free(DeviceState *dev)
235 BusState *bus;
237 if (dev->state == DEV_STATE_INITIALIZED) {
238 while (dev->num_child_bus) {
239 bus = QLIST_FIRST(&dev->child_bus);
240 qbus_free(bus);
242 #if 0 /* FIXME: need sane vmstate_unregister function */
243 if (dev->info->vmsd)
244 vmstate_unregister(dev->info->vmsd, dev);
245 #endif
246 if (dev->info->reset)
247 qemu_unregister_reset(dev->info->reset, dev);
248 if (dev->info->exit)
249 dev->info->exit(dev);
251 QLIST_REMOVE(dev, sibling);
252 qemu_free(dev);
255 /* Get a character (serial) device interface. */
256 CharDriverState *qdev_init_chardev(DeviceState *dev)
258 static int next_serial;
259 static int next_virtconsole;
260 /* FIXME: This is a nasty hack that needs to go away. */
261 if (strncmp(dev->info->name, "virtio", 6) == 0) {
262 return virtcon_hds[next_virtconsole++];
263 } else {
264 return serial_hds[next_serial++];
268 BusState *qdev_get_parent_bus(DeviceState *dev)
270 return dev->parent_bus;
273 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
275 assert(dev->num_gpio_in == 0);
276 dev->num_gpio_in = n;
277 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
280 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
282 assert(dev->num_gpio_out == 0);
283 dev->num_gpio_out = n;
284 dev->gpio_out = pins;
287 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
289 assert(n >= 0 && n < dev->num_gpio_in);
290 return dev->gpio_in[n];
293 void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
295 assert(n >= 0 && n < dev->num_gpio_out);
296 dev->gpio_out[n] = pin;
299 VLANClientState *qdev_get_vlan_client(DeviceState *dev,
300 NetCanReceive *can_receive,
301 NetReceive *receive,
302 NetReceiveIOV *receive_iov,
303 NetCleanup *cleanup,
304 void *opaque)
306 NICInfo *nd = dev->nd;
307 assert(nd);
308 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
309 receive, receive_iov, cleanup, opaque);
310 return nd->vc;
314 void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
316 memcpy(macaddr, dev->nd->macaddr, 6);
319 static int next_block_unit[IF_COUNT];
321 /* Get a block device. This should only be used for single-drive devices
322 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
323 appropriate bus. */
324 BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
326 int unit = next_block_unit[type]++;
327 DriveInfo *dinfo;
329 dinfo = drive_get(type, 0, unit);
330 return dinfo ? dinfo->bdrv : NULL;
333 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
335 BusState *bus;
337 QLIST_FOREACH(bus, &dev->child_bus, sibling) {
338 if (strcmp(name, bus->name) == 0) {
339 return bus;
342 return NULL;
345 static BusState *qbus_find_recursive(BusState *bus, const char *name,
346 const BusInfo *info)
348 DeviceState *dev;
349 BusState *child, *ret;
350 int match = 1;
352 if (name && (strcmp(bus->name, name) != 0)) {
353 match = 0;
355 if (info && (bus->info != info)) {
356 match = 0;
358 if (match) {
359 return bus;
362 QLIST_FOREACH(dev, &bus->children, sibling) {
363 QLIST_FOREACH(child, &dev->child_bus, sibling) {
364 ret = qbus_find_recursive(child, name, info);
365 if (ret) {
366 return ret;
370 return NULL;
373 static void qbus_list_bus(DeviceState *dev, char *dest, int len)
375 BusState *child;
376 const char *sep = " ";
377 int pos = 0;
379 pos += snprintf(dest+pos, len-pos,"child busses at \"%s\":",
380 dev->id ? dev->id : dev->info->name);
381 QLIST_FOREACH(child, &dev->child_bus, sibling) {
382 pos += snprintf(dest+pos, len-pos, "%s\"%s\"", sep, child->name);
383 sep = ", ";
387 static void qbus_list_dev(BusState *bus, char *dest, int len)
389 DeviceState *dev;
390 const char *sep = " ";
391 int pos = 0;
393 pos += snprintf(dest+pos, len-pos, "devices at \"%s\":",
394 bus->name);
395 QLIST_FOREACH(dev, &bus->children, sibling) {
396 pos += snprintf(dest+pos, len-pos, "%s\"%s\"",
397 sep, dev->info->name);
398 if (dev->id)
399 pos += snprintf(dest+pos, len-pos, "/\"%s\"", dev->id);
400 sep = ", ";
404 static BusState *qbus_find_bus(DeviceState *dev, char *elem)
406 BusState *child;
408 QLIST_FOREACH(child, &dev->child_bus, sibling) {
409 if (strcmp(child->name, elem) == 0) {
410 return child;
413 return NULL;
416 static DeviceState *qbus_find_dev(BusState *bus, char *elem)
418 DeviceState *dev;
421 * try to match in order:
422 * (1) instance id, if present
423 * (2) driver name
424 * (3) driver alias, if present
426 QLIST_FOREACH(dev, &bus->children, sibling) {
427 if (dev->id && strcmp(dev->id, elem) == 0) {
428 return dev;
431 QLIST_FOREACH(dev, &bus->children, sibling) {
432 if (strcmp(dev->info->name, elem) == 0) {
433 return dev;
436 QLIST_FOREACH(dev, &bus->children, sibling) {
437 if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
438 return dev;
441 return NULL;
444 static BusState *qbus_find(const char *path)
446 DeviceState *dev;
447 BusState *bus;
448 char elem[128], msg[256];
449 int pos, len;
451 /* find start element */
452 if (path[0] == '/') {
453 bus = main_system_bus;
454 pos = 0;
455 } else {
456 if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
457 qemu_error("path parse error (\"%s\")\n", path);
458 return NULL;
460 bus = qbus_find_recursive(main_system_bus, elem, NULL);
461 if (!bus) {
462 qemu_error("bus \"%s\" not found\n", elem);
463 return NULL;
465 pos = len;
468 for (;;) {
469 if (path[pos] == '\0') {
470 /* we are done */
471 return bus;
474 /* find device */
475 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
476 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
477 return NULL;
479 pos += len;
480 dev = qbus_find_dev(bus, elem);
481 if (!dev) {
482 qbus_list_dev(bus, msg, sizeof(msg));
483 qemu_error("device \"%s\" not found\n%s\n", elem, msg);
484 return NULL;
486 if (path[pos] == '\0') {
487 /* last specified element is a device. If it has exactly
488 * one child bus accept it nevertheless */
489 switch (dev->num_child_bus) {
490 case 0:
491 qemu_error("device has no child bus (%s)\n", path);
492 return NULL;
493 case 1:
494 return QLIST_FIRST(&dev->child_bus);
495 default:
496 qbus_list_bus(dev, msg, sizeof(msg));
497 qemu_error("device has multiple child busses (%s)\n%s\n",
498 path, msg);
499 return NULL;
503 /* find bus */
504 if (sscanf(path+pos, "/%127[^/]%n", elem, &len) != 1) {
505 qemu_error("path parse error (\"%s\" pos %d)\n", path, pos);
506 return NULL;
508 pos += len;
509 bus = qbus_find_bus(dev, elem);
510 if (!bus) {
511 qbus_list_bus(dev, msg, sizeof(msg));
512 qemu_error("child bus \"%s\" not found\n%s\n", elem, msg);
513 return NULL;
518 void qbus_create_inplace(BusState *bus, BusInfo *info,
519 DeviceState *parent, const char *name)
521 char *buf;
522 int i,len;
524 bus->info = info;
525 bus->parent = parent;
527 if (name) {
528 /* use supplied name */
529 bus->name = qemu_strdup(name);
530 } else if (parent && parent->id) {
531 /* parent device has id -> use it for bus name */
532 len = strlen(parent->id) + 16;
533 buf = qemu_malloc(len);
534 snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
535 bus->name = buf;
536 } else {
537 /* no id -> use lowercase bus type for bus name */
538 len = strlen(info->name) + 16;
539 buf = qemu_malloc(len);
540 len = snprintf(buf, len, "%s.%d", info->name,
541 parent ? parent->num_child_bus : 0);
542 for (i = 0; i < len; i++)
543 buf[i] = qemu_tolower(buf[i]);
544 bus->name = buf;
547 QLIST_INIT(&bus->children);
548 if (parent) {
549 QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
550 parent->num_child_bus++;
555 BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
557 BusState *bus;
559 bus = qemu_mallocz(info->size);
560 bus->qdev_allocated = 1;
561 qbus_create_inplace(bus, info, parent, name);
562 return bus;
565 void qbus_free(BusState *bus)
567 DeviceState *dev;
569 while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
570 qdev_free(dev);
572 if (bus->parent) {
573 QLIST_REMOVE(bus, sibling);
574 bus->parent->num_child_bus--;
576 if (bus->qdev_allocated) {
577 qemu_free(bus);
581 #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
582 static void qbus_print(Monitor *mon, BusState *bus, int indent);
584 static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
585 const char *prefix, int indent)
587 char buf[64];
589 if (!props)
590 return;
591 while (props->name) {
592 if (props->info->print) {
593 props->info->print(dev, props, buf, sizeof(buf));
594 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
596 props++;
600 static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
602 BusState *child;
603 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
604 dev->id ? dev->id : "");
605 indent += 2;
606 if (dev->num_gpio_in) {
607 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
609 if (dev->num_gpio_out) {
610 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
612 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
613 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
614 if (dev->parent_bus->info->print_dev)
615 dev->parent_bus->info->print_dev(mon, dev, indent);
616 QLIST_FOREACH(child, &dev->child_bus, sibling) {
617 qbus_print(mon, child, indent);
621 static void qbus_print(Monitor *mon, BusState *bus, int indent)
623 struct DeviceState *dev;
625 qdev_printf("bus: %s\n", bus->name);
626 indent += 2;
627 qdev_printf("type %s\n", bus->info->name);
628 QLIST_FOREACH(dev, &bus->children, sibling) {
629 qdev_print(mon, dev, indent);
632 #undef qdev_printf
634 void do_info_qtree(Monitor *mon)
636 if (main_system_bus)
637 qbus_print(mon, main_system_bus, 0);
640 void do_info_qdm(Monitor *mon)
642 DeviceInfo *info;
643 char msg[256];
645 for (info = device_info_list; info != NULL; info = info->next) {
646 qdev_print_devinfo(info, msg, sizeof(msg));
647 monitor_printf(mon, "%s\n", msg);