blob: cca242f8eeb859a994b5677ebea478e076ec9599 [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);
Gerd Hoffmannb6b61142009-07-15 13:48:21 +020088 qdev_prop_set_compat(dev);
Paul Brook02e2da42009-05-23 00:05:19 +010089 LIST_INSERT_HEAD(&bus->children, dev, sibling);
Paul Brookaae94602009-05-14 22:35:06 +010090 return dev;
91}
92
93/* Initialize a device. Device properties should be set before calling
94 this function. IRQs and MMIO regions should be connected/mapped after
95 calling this function. */
96void qdev_init(DeviceState *dev)
97{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020098 dev->info->init(dev, dev->info);
Paul Brook02e2da42009-05-23 00:05:19 +010099}
100
101/* Unlink device from bus and free the structure. */
102void qdev_free(DeviceState *dev)
103{
104 LIST_REMOVE(dev, sibling);
105 free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100106}
107
Paul Brookaae94602009-05-14 22:35:06 +0100108/* Get a character (serial) device interface. */
109CharDriverState *qdev_init_chardev(DeviceState *dev)
110{
111 static int next_serial;
112 static int next_virtconsole;
113 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200114 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100115 return virtcon_hds[next_virtconsole++];
116 } else {
117 return serial_hds[next_serial++];
118 }
119}
120
Paul Brook02e2da42009-05-23 00:05:19 +0100121BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100122{
Paul Brook02e2da42009-05-23 00:05:19 +0100123 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100124}
125
Paul Brookaae94602009-05-14 22:35:06 +0100126void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
127{
128 assert(dev->num_gpio_in == 0);
129 dev->num_gpio_in = n;
130 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
131}
132
133void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
134{
135 assert(dev->num_gpio_out == 0);
136 dev->num_gpio_out = n;
137 dev->gpio_out = pins;
138}
139
140qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
141{
142 assert(n >= 0 && n < dev->num_gpio_in);
143 return dev->gpio_in[n];
144}
145
146void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
147{
148 assert(n >= 0 && n < dev->num_gpio_out);
149 dev->gpio_out[n] = pin;
150}
151
Paul Brook9d07d752009-05-14 22:35:07 +0100152VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100153 NetCanReceive *can_receive,
154 NetReceive *receive,
155 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100156 NetCleanup *cleanup,
157 void *opaque)
158{
159 NICInfo *nd = dev->nd;
160 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100161 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
162 receive, receive_iov, cleanup, opaque);
163 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100164}
165
166
167void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
168{
169 memcpy(macaddr, dev->nd->macaddr, 6);
170}
171
Paul Brookaae94602009-05-14 22:35:06 +0100172static int next_block_unit[IF_COUNT];
173
174/* Get a block device. This should only be used for single-drive devices
175 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
176 appropriate bus. */
177BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
178{
179 int unit = next_block_unit[type]++;
180 int index;
181
182 index = drive_get_index(type, 0, unit);
183 if (index == -1) {
184 return NULL;
185 }
186 return drives_table[index].bdrv;
187}
Paul Brook4d6ae672009-05-14 22:35:06 +0100188
Paul Brook02e2da42009-05-23 00:05:19 +0100189BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100190{
Paul Brook02e2da42009-05-23 00:05:19 +0100191 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100192
Paul Brook02e2da42009-05-23 00:05:19 +0100193 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100194 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100195 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100196 }
197 }
198 return NULL;
199}
200
Paul Brook6f68ecb2009-05-14 22:35:07 +0100201static int next_scsi_bus;
202
203/* Create a scsi bus, and attach devices to it. */
204/* TODO: Actually create a scsi bus for hotplug to use. */
205void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
206{
207 int bus = next_scsi_bus++;
208 int unit;
209 int index;
210
211 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
212 index = drive_get_index(IF_SCSI, bus, unit);
213 if (index == -1) {
214 continue;
215 }
216 attach(host, drives_table[index].bdrv, unit);
217 }
218}
Paul Brook02e2da42009-05-23 00:05:19 +0100219
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200220BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100221{
222 BusState *bus;
223
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200224 bus = qemu_mallocz(info->size);
225 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100226 bus->parent = parent;
227 bus->name = qemu_strdup(name);
228 LIST_INIT(&bus->children);
229 if (parent) {
230 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
231 }
232 return bus;
233}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100234
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100235#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
236static void qbus_print(Monitor *mon, BusState *bus, int indent);
237
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200238static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
239 const char *prefix, int indent)
240{
241 char buf[64];
242
243 if (!props)
244 return;
245 while (props->name) {
246 if (props->info->print) {
247 props->info->print(dev, props, buf, sizeof(buf));
248 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
249 }
250 props++;
251 }
252}
253
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100254static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
255{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100256 BusState *child;
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200257 qdev_printf("dev: %s\n", dev->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100258 indent += 2;
259 if (dev->num_gpio_in) {
260 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
261 }
262 if (dev->num_gpio_out) {
263 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
264 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200265 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
266 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200267 if (dev->parent_bus->info->print_dev)
268 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100269 LIST_FOREACH(child, &dev->child_bus, sibling) {
270 qbus_print(mon, child, indent);
271 }
272}
273
274static void qbus_print(Monitor *mon, BusState *bus, int indent)
275{
276 struct DeviceState *dev;
277
278 qdev_printf("bus: %s\n", bus->name);
279 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200280 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100281 LIST_FOREACH(dev, &bus->children, sibling) {
282 qdev_print(mon, dev, indent);
283 }
284}
285#undef qdev_printf
286
287void do_info_qtree(Monitor *mon)
288{
289 if (main_system_bus)
290 qbus_print(mon, main_system_bus, 0);
291}