blob: faecc767af1517fc413243357fd247f524328374 [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;
Paul Brook4d6ae672009-05-14 22:35:06 +010035
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020036static DeviceInfo *device_info_list;
Paul Brookaae94602009-05-14 22:35:06 +010037
38/* Register a new device type. */
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020039void qdev_register(DeviceInfo *info)
Paul Brookaae94602009-05-14 22:35:06 +010040{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +020041 assert(info->size >= sizeof(DeviceState));
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020042 assert(!info->next);
Paul Brookaae94602009-05-14 22:35:06 +010043
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020044 info->next = device_info_list;
45 device_info_list = info;
Paul Brookaae94602009-05-14 22:35:06 +010046}
47
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020048static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
49{
50 DeviceInfo *info;
51
Gerd Hoffmann3320e562009-07-15 13:43:33 +020052 /* first check device names */
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020053 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 }
Gerd Hoffmann3320e562009-07-15 13:43:33 +020060
61 /* failing that check the aliases */
62 for (info = device_info_list; info != NULL; info = info->next) {
63 if (bus_info && info->bus_info != bus_info)
64 continue;
65 if (!info->alias)
66 continue;
67 if (strcmp(info->alias, name) != 0)
68 continue;
69 return info;
70 }
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020071 return NULL;
72}
73
Paul Brookaae94602009-05-14 22:35:06 +010074/* Create a new device. This only initializes the device state structure
75 and allows properties to be set. qdev_init should be called to
76 initialize the actual device emulation. */
Paul Brook02e2da42009-05-23 00:05:19 +010077DeviceState *qdev_create(BusState *bus, const char *name)
Paul Brookaae94602009-05-14 22:35:06 +010078{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020079 DeviceInfo *info;
Paul Brookaae94602009-05-14 22:35:06 +010080 DeviceState *dev;
81
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020082 if (!bus) {
83 if (!main_system_bus) {
84 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
Paul Brookaae94602009-05-14 22:35:06 +010085 }
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020086 bus = main_system_bus;
87 }
88
Gerd Hoffmann81ebb982009-07-15 13:43:32 +020089 info = qdev_find_info(bus->info, name);
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020090 if (!info) {
Gerd Hoffmann10c4c982009-06-30 14:12:08 +020091 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
Paul Brookaae94602009-05-14 22:35:06 +010092 }
93
Gerd Hoffmann042f84d2009-06-30 14:12:09 +020094 dev = qemu_mallocz(info->size);
95 dev->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +010096 dev->parent_bus = bus;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +020097 qdev_prop_set_defaults(dev, dev->info->props);
98 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
Gerd Hoffmannb6b61142009-07-15 13:48:21 +020099 qdev_prop_set_compat(dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100100 LIST_INSERT_HEAD(&bus->children, dev, sibling);
Paul Brookaae94602009-05-14 22:35:06 +0100101 return dev;
102}
103
104/* Initialize a device. Device properties should be set before calling
105 this function. IRQs and MMIO regions should be connected/mapped after
106 calling this function. */
107void qdev_init(DeviceState *dev)
108{
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200109 dev->info->init(dev, dev->info);
Paul Brook02e2da42009-05-23 00:05:19 +0100110}
111
112/* Unlink device from bus and free the structure. */
113void qdev_free(DeviceState *dev)
114{
115 LIST_REMOVE(dev, sibling);
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200116 qemu_free(dev->id);
117 qemu_free(dev);
Paul Brookaae94602009-05-14 22:35:06 +0100118}
119
Paul Brookaae94602009-05-14 22:35:06 +0100120/* Get a character (serial) device interface. */
121CharDriverState *qdev_init_chardev(DeviceState *dev)
122{
123 static int next_serial;
124 static int next_virtconsole;
125 /* FIXME: This is a nasty hack that needs to go away. */
Gerd Hoffmann042f84d2009-06-30 14:12:09 +0200126 if (strncmp(dev->info->name, "virtio", 6) == 0) {
Paul Brookaae94602009-05-14 22:35:06 +0100127 return virtcon_hds[next_virtconsole++];
128 } else {
129 return serial_hds[next_serial++];
130 }
131}
132
Paul Brook02e2da42009-05-23 00:05:19 +0100133BusState *qdev_get_parent_bus(DeviceState *dev)
Paul Brookaae94602009-05-14 22:35:06 +0100134{
Paul Brook02e2da42009-05-23 00:05:19 +0100135 return dev->parent_bus;
Paul Brookaae94602009-05-14 22:35:06 +0100136}
137
Paul Brookaae94602009-05-14 22:35:06 +0100138void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
139{
140 assert(dev->num_gpio_in == 0);
141 dev->num_gpio_in = n;
142 dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
143}
144
145void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
146{
147 assert(dev->num_gpio_out == 0);
148 dev->num_gpio_out = n;
149 dev->gpio_out = pins;
150}
151
152qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
153{
154 assert(n >= 0 && n < dev->num_gpio_in);
155 return dev->gpio_in[n];
156}
157
158void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
159{
160 assert(n >= 0 && n < dev->num_gpio_out);
161 dev->gpio_out[n] = pin;
162}
163
Paul Brook9d07d752009-05-14 22:35:07 +0100164VLANClientState *qdev_get_vlan_client(DeviceState *dev,
Mark McLoughlincda90462009-05-18 13:13:16 +0100165 NetCanReceive *can_receive,
166 NetReceive *receive,
167 NetReceiveIOV *receive_iov,
Paul Brook9d07d752009-05-14 22:35:07 +0100168 NetCleanup *cleanup,
169 void *opaque)
170{
171 NICInfo *nd = dev->nd;
172 assert(nd);
Mark McLoughlinae50b272009-07-01 16:46:38 +0100173 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
174 receive, receive_iov, cleanup, opaque);
175 return nd->vc;
Paul Brook9d07d752009-05-14 22:35:07 +0100176}
177
178
179void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
180{
181 memcpy(macaddr, dev->nd->macaddr, 6);
182}
183
Paul Brookaae94602009-05-14 22:35:06 +0100184static int next_block_unit[IF_COUNT];
185
186/* Get a block device. This should only be used for single-drive devices
187 (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
188 appropriate bus. */
189BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
190{
191 int unit = next_block_unit[type]++;
192 int index;
193
194 index = drive_get_index(type, 0, unit);
195 if (index == -1) {
196 return NULL;
197 }
198 return drives_table[index].bdrv;
199}
Paul Brook4d6ae672009-05-14 22:35:06 +0100200
Paul Brook02e2da42009-05-23 00:05:19 +0100201BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Paul Brook4d6ae672009-05-14 22:35:06 +0100202{
Paul Brook02e2da42009-05-23 00:05:19 +0100203 BusState *bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100204
Paul Brook02e2da42009-05-23 00:05:19 +0100205 LIST_FOREACH(bus, &dev->child_bus, sibling) {
Paul Brook4d6ae672009-05-14 22:35:06 +0100206 if (strcmp(name, bus->name) == 0) {
Paul Brook02e2da42009-05-23 00:05:19 +0100207 return bus;
Paul Brook4d6ae672009-05-14 22:35:06 +0100208 }
209 }
210 return NULL;
211}
212
Paul Brook6f68ecb2009-05-14 22:35:07 +0100213static int next_scsi_bus;
214
215/* Create a scsi bus, and attach devices to it. */
216/* TODO: Actually create a scsi bus for hotplug to use. */
217void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
218{
219 int bus = next_scsi_bus++;
220 int unit;
221 int index;
222
223 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
224 index = drive_get_index(IF_SCSI, bus, unit);
225 if (index == -1) {
226 continue;
227 }
228 attach(host, drives_table[index].bdrv, unit);
229 }
230}
Paul Brook02e2da42009-05-23 00:05:19 +0100231
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200232BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
Paul Brook02e2da42009-05-23 00:05:19 +0100233{
234 BusState *bus;
235
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200236 bus = qemu_mallocz(info->size);
237 bus->info = info;
Paul Brook02e2da42009-05-23 00:05:19 +0100238 bus->parent = parent;
239 bus->name = qemu_strdup(name);
240 LIST_INIT(&bus->children);
241 if (parent) {
242 LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
243 }
244 return bus;
245}
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100246
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100247#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
248static void qbus_print(Monitor *mon, BusState *bus, int indent);
249
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200250static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
251 const char *prefix, int indent)
252{
253 char buf[64];
254
255 if (!props)
256 return;
257 while (props->name) {
258 if (props->info->print) {
259 props->info->print(dev, props, buf, sizeof(buf));
260 qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
261 }
262 props++;
263 }
264}
265
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100266static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
267{
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100268 BusState *child;
Gerd Hoffmannccb63de2009-07-15 13:43:34 +0200269 qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
270 dev->id ? dev->id : "");
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100271 indent += 2;
272 if (dev->num_gpio_in) {
273 qdev_printf("gpio-in %d\n", dev->num_gpio_in);
274 }
275 if (dev->num_gpio_out) {
276 qdev_printf("gpio-out %d\n", dev->num_gpio_out);
277 }
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200278 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
279 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200280 if (dev->parent_bus->info->print_dev)
281 dev->parent_bus->info->print_dev(mon, dev, indent);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100282 LIST_FOREACH(child, &dev->child_bus, sibling) {
283 qbus_print(mon, child, indent);
284 }
285}
286
287static void qbus_print(Monitor *mon, BusState *bus, int indent)
288{
289 struct DeviceState *dev;
290
291 qdev_printf("bus: %s\n", bus->name);
292 indent += 2;
Gerd Hoffmann10c4c982009-06-30 14:12:08 +0200293 qdev_printf("type %s\n", bus->info->name);
Gerd Hoffmanncae49562009-06-05 15:53:17 +0100294 LIST_FOREACH(dev, &bus->children, sibling) {
295 qdev_print(mon, dev, indent);
296 }
297}
298#undef qdev_printf
299
300void do_info_qtree(Monitor *mon)
301{
302 if (main_system_bus)
303 qbus_print(mon, main_system_bus, 0);
304}