blob: a53125dd8889efa0bcb3871c69e37286f5490a9e [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
53 for (info = device_info_list; info != NULL; info = info->next) {
54 if (bus_info && info->bus_info != bus_info)
55 continue;
56 if (strcmp(info->name, name) != 0)
57 continue;
58 return info;
59 }
60 return NULL;
61}
62
Paul Brookaae94602009-05-14 22:35:06 +010063/* Create a new device. This only initializes the device state structure
64 and allows properties to be set. qdev_init should be called to
65 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010066DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010067{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020068 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010069 DeviceState *dev;
70
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020071 if (!bus) {
72 if (!main_system_bus) {
73 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010074 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020075 bus = main_system_bus;
76 }
77
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020078 info = qdev_find_info(bus->info, name);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020079 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020080 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010081 }
82
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020083 dev = qemu_mallocz(info->size);
84 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010085 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020086 qdev_prop_set_defaults(dev, dev->info->props);
87 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Paul Brook02e2da42009-05-23 00:05:19 +010088 LIST_INSERT_HEAD(&bus->children, dev, sibling);
Paul Brookaae94602009-05-14 22:35:06 +010089 return dev;
90}
91
92/* Initialize a device. Device properties should be set before calling
93 this function. IRQs and MMIO regions should be connected/mapped after
94 calling this function. */
95void qdev_init(DeviceState *dev)
96{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020097 dev->info->init(dev, dev->info);
Paul Brook02e2da42009-05-23 00:05:19 +010098}
99
100/* Unlink device from bus and free the structure. */
101void qdev_free(DeviceState *dev)
102{
103 LIST_REMOVE(dev, sibling);
104 free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100105}
106
Paul Brookaae94602009-05-14 22:35:06 +0100107/* Get a character (serial) device interface. */
108CharDriverState *qdev_init_chardev(DeviceState *dev)
109{
110 static int next_serial;
111 static int next_virtconsole;
112 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200113 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100114 return virtcon_hds[next_virtconsole++];
115 } else {
116 return serial_hds[next_serial++];
117 }
118}
119
Paul Brook02e2da42009-05-23 00:05:19 +0100120BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100121{
Paul Brook02e2da42009-05-23 00:05:19 +0100122 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100123}
124
Paul Brookaae94602009-05-14 22:35:06 +0100125void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
126{
127 assert(dev->num_gpio_in == 0);
128 dev->num_gpio_in = n;
129 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
130}
131
132void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
133{
134 assert(dev->num_gpio_out == 0);
135 dev->num_gpio_out = n;
136 dev->gpio_out = pins;
137}
138
139qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
140{
141 assert(n >= 0 && n < dev->num_gpio_in);
142 return dev->gpio_in[n];
143}
144
145void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
146{
147 assert(n >= 0 && n < dev->num_gpio_out);
148 dev->gpio_out[n] = pin;
149}
150
Paul Brook9d07d752009-05-14 22:35:07 +0100151VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100152 NetCanReceive *can_receive,
153 NetReceive *receive,
154 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100155 NetCleanup *cleanup,
156 void *opaque)
157{
158 NICInfo *nd = dev->nd;
159 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100160 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
161 receive, receive_iov, cleanup, opaque);
162 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100163}
164
165
166void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
167{
168 memcpy(macaddr, dev->nd->macaddr, 6);
169}
170
Paul Brookaae94602009-05-14 22:35:06 +0100171static int next_block_unit[IF_COUNT];
172
173/* Get a block device. This should only be used for single-drive devices
174 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
175 appropriate bus. */
176BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
177{
178 int unit = next_block_unit[type]++;
179 int index;
180
181 index = drive_get_index(type, 0, unit);
182 if (index == -1) {
183 return NULL;
184 }
185 return drives_table[index].bdrv;
186}
Paul Brook4d6ae672009-05-14 22:35:06 +0100187
Paul Brook02e2da42009-05-23 00:05:19 +0100188BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100189{
Paul Brook02e2da42009-05-23 00:05:19 +0100190 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100191
Paul Brook02e2da42009-05-23 00:05:19 +0100192 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100193 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100194 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100195 }
196 }
197 return NULL;
198}
199
Paul Brook6f68ecb2009-05-14 22:35:07 +0100200static int next_scsi_bus;
201
202/* Create a scsi bus, and attach devices to it. */
203/* TODO: Actually create a scsi bus for hotplug to use. */
204void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
205{
206 int bus = next_scsi_bus++;
207 int unit;
208 int index;
209
210 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
211 index = drive_get_index(IF_SCSI, bus, unit);
212 if (index == -1) {
213 continue;
214 }
215 attach(host, drives_table[index].bdrv, unit);
216 }
217}
Paul Brook02e2da42009-05-23 00:05:19 +0100218
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200219BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100220{
221 BusState *bus;
222
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200223 bus = qemu_mallocz(info->size);
224 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100225 bus->parent = parent;
226 bus->name = qemu_strdup(name);
227 LIST_INIT(&bus->children);
228 if (parent) {
229 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
230 }
231 return bus;
232}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100233
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100234#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
235static void qbus_print(Monitor *mon, BusState *bus, int indent);
236
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200237static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
238 const char *prefix, int indent)
239{
240 char buf[64];
241
242 if (!props)
243 return;
244 while (props->name) {
245 if (props->info->print) {
246 props->info->print(dev, props, buf, sizeof(buf));
247 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
248 }
249 props++;
250 }
251}
252
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100253static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
254{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100255 BusState *child;
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200256 qdev_printf("dev: %s\n", dev->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100257 indent += 2;
258 if (dev->num_gpio_in) {
259 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
260 }
261 if (dev->num_gpio_out) {
262 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
263 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200264 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
265 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200266 if (dev->parent_bus->info->print_dev)
267 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100268 LIST_FOREACH(child, &dev->child_bus, sibling) {
269 qbus_print(mon, child, indent);
270 }
271}
272
273static void qbus_print(Monitor *mon, BusState *bus, int indent)
274{
275 struct DeviceState *dev;
276
277 qdev_printf("bus: %s\n", bus->name);
278 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200279 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100280 LIST_FOREACH(dev, &bus->children, sibling) {
281 qdev_print(mon, dev, indent);
282 }
283}
284#undef qdev_printf
285
286void do_info_qtree(Monitor *mon)
287{
288 if (main_system_bus)
289 qbus_print(mon, main_system_bus, 0);
290}