blob: 64461e7eb2e3ff36f2867a42185493bcb3669ff9 [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
49/* Create a new device. This only initializes the device state structure
50 and allows properties to be set. qdev_init should be called to
51 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010052DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010053{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020054 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010055 DeviceState *dev;
56
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020057 if (!bus) {
58 if (!main_system_bus) {
59 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010060 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020061 bus = main_system_bus;
62 }
63
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020064 for (info = device_info_list; info != NULL; info = info->next) {
65 if (info->bus_info != bus->info)
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020066 continue;
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020067 if (strcmp(info->name, name) != 0)
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020068 continue;
69 break;
Paul Brookaae94602009-05-14 22:35:06 +010070 }
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020071 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020072 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010073 }
74
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020075 dev = qemu_mallocz(info->size);
76 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010077 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020078 qdev_prop_set_defaults(dev, dev->info->props);
79 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Paul Brook02e2da42009-05-23 00:05:19 +010080 LIST_INSERT_HEAD(&bus->children, dev, sibling);
Paul Brookaae94602009-05-14 22:35:06 +010081 return dev;
82}
83
84/* Initialize a device. Device properties should be set before calling
85 this function. IRQs and MMIO regions should be connected/mapped after
86 calling this function. */
87void qdev_init(DeviceState *dev)
88{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020089 dev->info->init(dev, dev->info);
Paul Brook02e2da42009-05-23 00:05:19 +010090}
91
92/* Unlink device from bus and free the structure. */
93void qdev_free(DeviceState *dev)
94{
95 LIST_REMOVE(dev, sibling);
96 free(dev);
Paul Brookaae94602009-05-14 22:35:06 +010097}
98
Paul Brookaae94602009-05-14 22:35:06 +010099/* Get a character (serial) device interface. */
100CharDriverState *qdev_init_chardev(DeviceState *dev)
101{
102 static int next_serial;
103 static int next_virtconsole;
104 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200105 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100106 return virtcon_hds[next_virtconsole++];
107 } else {
108 return serial_hds[next_serial++];
109 }
110}
111
Paul Brook02e2da42009-05-23 00:05:19 +0100112BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100113{
Paul Brook02e2da42009-05-23 00:05:19 +0100114 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100115}
116
Paul Brookaae94602009-05-14 22:35:06 +0100117void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
118{
119 assert(dev->num_gpio_in == 0);
120 dev->num_gpio_in = n;
121 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
122}
123
124void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
125{
126 assert(dev->num_gpio_out == 0);
127 dev->num_gpio_out = n;
128 dev->gpio_out = pins;
129}
130
131qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
132{
133 assert(n >= 0 && n < dev->num_gpio_in);
134 return dev->gpio_in[n];
135}
136
137void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
138{
139 assert(n >= 0 && n < dev->num_gpio_out);
140 dev->gpio_out[n] = pin;
141}
142
Paul Brook9d07d752009-05-14 22:35:07 +0100143VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100144 NetCanReceive *can_receive,
145 NetReceive *receive,
146 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100147 NetCleanup *cleanup,
148 void *opaque)
149{
150 NICInfo *nd = dev->nd;
151 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100152 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
153 receive, receive_iov, cleanup, opaque);
154 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100155}
156
157
158void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
159{
160 memcpy(macaddr, dev->nd->macaddr, 6);
161}
162
Paul Brookaae94602009-05-14 22:35:06 +0100163static int next_block_unit[IF_COUNT];
164
165/* Get a block device. This should only be used for single-drive devices
166 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
167 appropriate bus. */
168BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
169{
170 int unit = next_block_unit[type]++;
171 int index;
172
173 index = drive_get_index(type, 0, unit);
174 if (index == -1) {
175 return NULL;
176 }
177 return drives_table[index].bdrv;
178}
Paul Brook4d6ae672009-05-14 22:35:06 +0100179
Paul Brook02e2da42009-05-23 00:05:19 +0100180BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100181{
Paul Brook02e2da42009-05-23 00:05:19 +0100182 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100183
Paul Brook02e2da42009-05-23 00:05:19 +0100184 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100185 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100186 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100187 }
188 }
189 return NULL;
190}
191
Paul Brook6f68ecb2009-05-14 22:35:07 +0100192static int next_scsi_bus;
193
194/* Create a scsi bus, and attach devices to it. */
195/* TODO: Actually create a scsi bus for hotplug to use. */
196void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
197{
198 int bus = next_scsi_bus++;
199 int unit;
200 int index;
201
202 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
203 index = drive_get_index(IF_SCSI, bus, unit);
204 if (index == -1) {
205 continue;
206 }
207 attach(host, drives_table[index].bdrv, unit);
208 }
209}
Paul Brook02e2da42009-05-23 00:05:19 +0100210
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200211BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100212{
213 BusState *bus;
214
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200215 bus = qemu_mallocz(info->size);
216 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100217 bus->parent = parent;
218 bus->name = qemu_strdup(name);
219 LIST_INIT(&bus->children);
220 if (parent) {
221 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
222 }
223 return bus;
224}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100225
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100226#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
227static void qbus_print(Monitor *mon, BusState *bus, int indent);
228
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200229static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
230 const char *prefix, int indent)
231{
232 char buf[64];
233
234 if (!props)
235 return;
236 while (props->name) {
237 if (props->info->print) {
238 props->info->print(dev, props, buf, sizeof(buf));
239 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
240 }
241 props++;
242 }
243}
244
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100245static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
246{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100247 BusState *child;
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200248 qdev_printf("dev: %s\n", dev->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100249 indent += 2;
250 if (dev->num_gpio_in) {
251 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
252 }
253 if (dev->num_gpio_out) {
254 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
255 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200256 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
257 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200258 if (dev->parent_bus->info->print_dev)
259 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100260 LIST_FOREACH(child, &dev->child_bus, sibling) {
261 qbus_print(mon, child, indent);
262 }
263}
264
265static void qbus_print(Monitor *mon, BusState *bus, int indent)
266{
267 struct DeviceState *dev;
268
269 qdev_printf("bus: %s\n", bus->name);
270 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200271 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100272 LIST_FOREACH(dev, &bus->children, sibling) {
273 qdev_print(mon, dev, indent);
274 }
275}
276#undef qdev_printf
277
278void do_info_qtree(Monitor *mon)
279{
280 if (main_system_bus)
281 qbus_print(mon, main_system_bus, 0);
282}