blob: 001c74ce0e69a72264c13019b6a4cbb2e7140a81 [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
Paul Brook02e2da42009-05-23 00:05:19 +010033/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
Blue Swirlb9aaf7f2009-06-09 18:38:51 +000034static BusState *main_system_bus;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020035extern struct BusInfo system_bus_info;
Paul Brook4d6ae672009-05-14 22:35:06 +010036
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020037static DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010038
39/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020040void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010041{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020042 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020043 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010044
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020045 info->next = device_info_list;
46 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010047}
48
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020049static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
50{
51 DeviceInfo *info;
52
Gerd Hoffmann3320e562009-07-15 13:43:33 +020053 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020054 for (info = device_info_list; info != NULL; info = info->next) {
55 if (bus_info && info->bus_info != bus_info)
56 continue;
57 if (strcmp(info->name, name) != 0)
58 continue;
59 return info;
60 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020061
62 /* failing that check the aliases */
63 for (info = device_info_list; info != NULL; info = info->next) {
64 if (bus_info && info->bus_info != bus_info)
65 continue;
66 if (!info->alias)
67 continue;
68 if (strcmp(info->alias, name) != 0)
69 continue;
70 return info;
71 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020072 return NULL;
73}
74
Paul Brookaae94602009-05-14 22:35:06 +010075/* Create a new device. This only initializes the device state structure
76 and allows properties to be set. qdev_init should be called to
77 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010078DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010079{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020080 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010081 DeviceState *dev;
82
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020083 if (!bus) {
84 if (!main_system_bus) {
85 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010086 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020087 bus = main_system_bus;
88 }
89
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020090 info = qdev_find_info(bus->info, name);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020091 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020092 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010093 }
94
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020095 dev = qemu_mallocz(info->size);
96 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010097 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020098 qdev_prop_set_defaults(dev, dev->info->props);
99 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmannb6b61142009-07-15 13:48:21 +0200100 qdev_prop_set_compat(dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100101 LIST_INSERT_HEAD(&bus->children, dev, sibling);
Paul Brookaae94602009-05-14 22:35:06 +0100102 return dev;
103}
104
105/* Initialize a device. Device properties should be set before calling
106 this function. IRQs and MMIO regions should be connected/mapped after
107 calling this function. */
108void qdev_init(DeviceState *dev)
109{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200110 dev->info->init(dev, dev->info);
Paul Brook02e2da42009-05-23 00:05:19 +0100111}
112
113/* Unlink device from bus and free the structure. */
114void qdev_free(DeviceState *dev)
115{
116 LIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200117 qemu_free(dev->id);
118 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100119}
120
Paul Brookaae94602009-05-14 22:35:06 +0100121/* Get a character (serial) device interface. */
122CharDriverState *qdev_init_chardev(DeviceState *dev)
123{
124 static int next_serial;
125 static int next_virtconsole;
126 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200127 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100128 return virtcon_hds[next_virtconsole++];
129 } else {
130 return serial_hds[next_serial++];
131 }
132}
133
Paul Brook02e2da42009-05-23 00:05:19 +0100134BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100135{
Paul Brook02e2da42009-05-23 00:05:19 +0100136 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100137}
138
Paul Brookaae94602009-05-14 22:35:06 +0100139void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
140{
141 assert(dev->num_gpio_in == 0);
142 dev->num_gpio_in = n;
143 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
144}
145
146void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
147{
148 assert(dev->num_gpio_out == 0);
149 dev->num_gpio_out = n;
150 dev->gpio_out = pins;
151}
152
153qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
154{
155 assert(n >= 0 && n < dev->num_gpio_in);
156 return dev->gpio_in[n];
157}
158
159void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
160{
161 assert(n >= 0 && n < dev->num_gpio_out);
162 dev->gpio_out[n] = pin;
163}
164
Paul Brook9d07d752009-05-14 22:35:07 +0100165VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100166 NetCanReceive *can_receive,
167 NetReceive *receive,
168 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100169 NetCleanup *cleanup,
170 void *opaque)
171{
172 NICInfo *nd = dev->nd;
173 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100174 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
175 receive, receive_iov, cleanup, opaque);
176 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100177}
178
179
180void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
181{
182 memcpy(macaddr, dev->nd->macaddr, 6);
183}
184
Paul Brookaae94602009-05-14 22:35:06 +0100185static int next_block_unit[IF_COUNT];
186
187/* Get a block device. This should only be used for single-drive devices
188 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
189 appropriate bus. */
190BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
191{
192 int unit = next_block_unit[type]++;
193 int index;
194
195 index = drive_get_index(type, 0, unit);
196 if (index == -1) {
197 return NULL;
198 }
199 return drives_table[index].bdrv;
200}
Paul Brook4d6ae672009-05-14 22:35:06 +0100201
Paul Brook02e2da42009-05-23 00:05:19 +0100202BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100203{
Paul Brook02e2da42009-05-23 00:05:19 +0100204 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100205
Paul Brook02e2da42009-05-23 00:05:19 +0100206 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100207 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100208 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100209 }
210 }
211 return NULL;
212}
213
Paul Brook6f68ecb2009-05-14 22:35:07 +0100214static int next_scsi_bus;
215
216/* Create a scsi bus, and attach devices to it. */
217/* TODO: Actually create a scsi bus for hotplug to use. */
218void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
219{
220 int bus = next_scsi_bus++;
221 int unit;
222 int index;
223
224 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
225 index = drive_get_index(IF_SCSI, bus, unit);
226 if (index == -1) {
227 continue;
228 }
229 attach(host, drives_table[index].bdrv, unit);
230 }
231}
Paul Brook02e2da42009-05-23 00:05:19 +0100232
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200233BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100234{
235 BusState *bus;
236
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200237 bus = qemu_mallocz(info->size);
238 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100239 bus->parent = parent;
240 bus->name = qemu_strdup(name);
241 LIST_INIT(&bus->children);
242 if (parent) {
243 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
244 }
245 return bus;
246}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100247
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100248#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
249static void qbus_print(Monitor *mon, BusState *bus, int indent);
250
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200251static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
252 const char *prefix, int indent)
253{
254 char buf[64];
255
256 if (!props)
257 return;
258 while (props->name) {
259 if (props->info->print) {
260 props->info->print(dev, props, buf, sizeof(buf));
261 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
262 }
263 props++;
264 }
265}
266
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100267static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
268{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100269 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200270 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
271 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100272 indent += 2;
273 if (dev->num_gpio_in) {
274 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
275 }
276 if (dev->num_gpio_out) {
277 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
278 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200279 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
280 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200281 if (dev->parent_bus->info->print_dev)
282 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100283 LIST_FOREACH(child, &dev->child_bus, sibling) {
284 qbus_print(mon, child, indent);
285 }
286}
287
288static void qbus_print(Monitor *mon, BusState *bus, int indent)
289{
290 struct DeviceState *dev;
291
292 qdev_printf("bus: %s\n", bus->name);
293 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200294 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100295 LIST_FOREACH(dev, &bus->children, sibling) {
296 qdev_print(mon, dev, indent);
297 }
298}
299#undef qdev_printf
300
301void do_info_qtree(Monitor *mon)
302{
303 if (main_system_bus)
304 qbus_print(mon, main_system_bus, 0);
305}