]> git.proxmox.com Git - qemu.git/blame - hw/qdev.c
qdev: rework device properties.
[qemu.git] / hw / qdev.c
CommitLineData
aae9460e
PB
1/*
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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
aae9460e
PB
18 */
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
9d07d757 28#include "net.h"
aae9460e
PB
29#include "qdev.h"
30#include "sysemu.h"
cae4956e 31#include "monitor.h"
aae9460e 32
02e2da45 33/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
b9aaf7f8 34static BusState *main_system_bus;
10c4c98a 35extern struct BusInfo system_bus_info;
4d6ae674 36
042f84d0 37static DeviceInfo *device_info_list;
aae9460e
PB
38
39/* Register a new device type. */
074f2fff 40void qdev_register(DeviceInfo *info)
aae9460e 41{
074f2fff 42 assert(info->size >= sizeof(DeviceState));
042f84d0 43 assert(!info->next);
aae9460e 44
042f84d0
GH
45 info->next = device_info_list;
46 device_info_list = info;
aae9460e
PB
47}
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. */
02e2da45 52DeviceState *qdev_create(BusState *bus, const char *name)
aae9460e 53{
042f84d0 54 DeviceInfo *info;
aae9460e
PB
55 DeviceState *dev;
56
10c4c98a
GH
57 if (!bus) {
58 if (!main_system_bus) {
59 main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
aae9460e 60 }
10c4c98a
GH
61 bus = main_system_bus;
62 }
63
042f84d0
GH
64 for (info = device_info_list; info != NULL; info = info->next) {
65 if (info->bus_info != bus->info)
10c4c98a 66 continue;
042f84d0 67 if (strcmp(info->name, name) != 0)
10c4c98a
GH
68 continue;
69 break;
aae9460e 70 }
042f84d0 71 if (!info) {
10c4c98a 72 hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
aae9460e
PB
73 }
74
042f84d0
GH
75 dev = qemu_mallocz(info->size);
76 dev->info = info;
02e2da45 77 dev->parent_bus = bus;
ee6847d1
GH
78 qdev_prop_set_defaults(dev, dev->info->props);
79 qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
02e2da45 80 LIST_INSERT_HEAD(&bus->children, dev, sibling);
aae9460e
PB
81 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{
042f84d0 89 dev->info->init(dev, dev->info);
02e2da45
PB
90}
91
92/* Unlink device from bus and free the structure. */
93void qdev_free(DeviceState *dev)
94{
95 LIST_REMOVE(dev, sibling);
96 free(dev);
aae9460e
PB
97}
98
aae9460e
PB
99/* 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. */
042f84d0 105 if (strncmp(dev->info->name, "virtio", 6) == 0) {
aae9460e
PB
106 return virtcon_hds[next_virtconsole++];
107 } else {
108 return serial_hds[next_serial++];
109 }
110}
111
02e2da45 112BusState *qdev_get_parent_bus(DeviceState *dev)
aae9460e 113{
02e2da45 114 return dev->parent_bus;
aae9460e
PB
115}
116
aae9460e
PB
117void 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
9d07d757 143VLANClientState *qdev_get_vlan_client(DeviceState *dev,
cda9046b
MM
144 NetCanReceive *can_receive,
145 NetReceive *receive,
146 NetReceiveIOV *receive_iov,
9d07d757
PB
147 NetCleanup *cleanup,
148 void *opaque)
149{
150 NICInfo *nd = dev->nd;
151 assert(nd);
ae50b274
MM
152 nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
153 receive, receive_iov, cleanup, opaque);
154 return nd->vc;
9d07d757
PB
155}
156
157
158void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
159{
160 memcpy(macaddr, dev->nd->macaddr, 6);
161}
162
aae9460e
PB
163static 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}
4d6ae674 179
02e2da45 180BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
4d6ae674 181{
02e2da45 182 BusState *bus;
4d6ae674 183
02e2da45 184 LIST_FOREACH(bus, &dev->child_bus, sibling) {
4d6ae674 185 if (strcmp(name, bus->name) == 0) {
02e2da45 186 return bus;
4d6ae674
PB
187 }
188 }
189 return NULL;
190}
191
6f68ecb2
PB
192static 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}
02e2da45 210
10c4c98a 211BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
02e2da45
PB
212{
213 BusState *bus;
214
10c4c98a
GH
215 bus = qemu_mallocz(info->size);
216 bus->info = info;
02e2da45
PB
217 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}
cae4956e 225
cae4956e
GH
226#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
227static void qbus_print(Monitor *mon, BusState *bus, int indent);
228
ee6847d1
GH
229static 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
cae4956e
GH
245static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
246{
cae4956e 247 BusState *child;
042f84d0 248 qdev_printf("dev: %s\n", dev->info->name);
cae4956e
GH
249 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 }
ee6847d1
GH
256 qdev_print_props(mon, dev, dev->info->props, "dev", indent);
257 qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
10c4c98a
GH
258 if (dev->parent_bus->info->print_dev)
259 dev->parent_bus->info->print_dev(mon, dev, indent);
cae4956e
GH
260 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;
10c4c98a 271 qdev_printf("type %s\n", bus->info->name);
cae4956e
GH
272 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}