a7025da9a7568ec57f34daa1d217302704390d0d
[qemu] / hw / qdev.c
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
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
19  */
20
21 /* The theory here is that it should be possible to create a machine without
22    knowledge of specific devices.  Historically board init routines have
23    passed a bunch of arguments to each device, requiring the board know
24    exactly which device it is dealing with.  This file provides an abstract
25    API for device configuration and initialization.  Devices will generally
26    inherit from a particular bus (e.g. PCI or I2C) rather than
27    this API directly.  */
28
29 #include "net.h"
30 #include "qdev.h"
31 #include "sysemu.h"
32
33 struct DeviceProperty {
34     const char *name;
35     DevicePropType type;
36     union {
37         uint64_t i;
38         void *ptr;
39     } value;
40     DeviceProperty *next;
41 };
42
43 struct DeviceType {
44     const char *name;
45     DeviceInfo *info;
46     int size;
47     DeviceType *next;
48 };
49
50 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
51 BusState *main_system_bus;
52
53 static DeviceType *device_type_list;
54
55 /* Register a new device type.  */
56 void qdev_register(const char *name, int size, DeviceInfo *info)
57 {
58     DeviceType *t;
59
60     assert(size >= sizeof(DeviceState));
61
62     t = qemu_mallocz(sizeof(DeviceType));
63     t->next = device_type_list;
64     device_type_list = t;
65     t->name = qemu_strdup(name);
66     t->size = size;
67     t->info = info;
68 }
69
70 /* Create a new device.  This only initializes the device state structure
71    and allows properties to be set.  qdev_init should be called to
72    initialize the actual device emulation.  */
73 DeviceState *qdev_create(BusState *bus, const char *name)
74 {
75     DeviceType *t;
76     DeviceState *dev;
77
78     for (t = device_type_list; t; t = t->next) {
79         if (strcmp(t->name, name) == 0) {
80             break;
81         }
82     }
83     if (!t) {
84         hw_error("Unknown device '%s'\n", name);
85     }
86
87     dev = qemu_mallocz(t->size);
88     dev->type = t;
89
90     if (!bus) {
91         /* ???: This assumes system busses have no additional state.  */
92         if (!main_system_bus) {
93             main_system_bus = qbus_create(BUS_TYPE_SYSTEM, sizeof(BusState),
94                                           NULL, "main-system-bus");
95         }
96         bus = main_system_bus;
97     }
98     if (t->info->bus_type != bus->type) {
99         /* TODO: Print bus type names.  */
100         hw_error("Device '%s' on wrong bus type (%d/%d)", name,
101                  t->info->bus_type, bus->type);
102     }
103     dev->parent_bus = bus;
104     LIST_INSERT_HEAD(&bus->children, dev, sibling);
105     return dev;
106 }
107
108 /* Initialize a device.  Device properties should be set before calling
109    this function.  IRQs and MMIO regions should be connected/mapped after
110    calling this function.  */
111 void qdev_init(DeviceState *dev)
112 {
113     dev->type->info->init(dev, dev->type->info);
114 }
115
116 /* Unlink device from bus and free the structure.  */
117 void qdev_free(DeviceState *dev)
118 {
119     LIST_REMOVE(dev, sibling);
120     free(dev);
121 }
122
123 static DeviceProperty *create_prop(DeviceState *dev, const char *name,
124                                    DevicePropType type)
125 {
126     DeviceProperty *prop;
127
128     /* TODO: Check for duplicate properties.  */
129     prop = qemu_mallocz(sizeof(*prop));
130     prop->name = qemu_strdup(name);
131     prop->type = type;
132     prop->next = dev->props;
133     dev->props = prop;
134
135     return prop;
136 }
137
138 void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value)
139 {
140     DeviceProperty *prop;
141
142     prop = create_prop(dev, name, PROP_TYPE_INT);
143     prop->value.i = value;
144 }
145
146 void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value)
147 {
148     DeviceProperty *prop;
149
150     prop = create_prop(dev, name, PROP_TYPE_DEV);
151     prop->value.ptr = value;
152 }
153
154 void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
155 {
156     DeviceProperty *prop;
157
158     prop = create_prop(dev, name, PROP_TYPE_INT);
159     prop->value.ptr = value;
160 }
161
162 void qdev_set_netdev(DeviceState *dev, NICInfo *nd)
163 {
164     assert(!dev->nd);
165     dev->nd = nd;
166 }
167
168
169 /* Get a character (serial) device interface.  */
170 CharDriverState *qdev_init_chardev(DeviceState *dev)
171 {
172     static int next_serial;
173     static int next_virtconsole;
174     /* FIXME: This is a nasty hack that needs to go away.  */
175     if (strncmp(dev->type->name, "virtio", 6) == 0) {
176         return virtcon_hds[next_virtconsole++];
177     } else {
178         return serial_hds[next_serial++];
179     }
180 }
181
182 BusState *qdev_get_parent_bus(DeviceState *dev)
183 {
184     return dev->parent_bus;
185 }
186
187 static DeviceProperty *find_prop(DeviceState *dev, const char *name,
188                                  DevicePropType type)
189 {
190     DeviceProperty *prop;
191
192     for (prop = dev->props; prop; prop = prop->next) {
193         if (strcmp(prop->name, name) == 0) {
194             assert (prop->type == type);
195             return prop;
196         }
197     }
198     return NULL;
199 }
200
201 uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def)
202 {
203     DeviceProperty *prop;
204
205     prop = find_prop(dev, name, PROP_TYPE_INT);
206     if (!prop) {
207         return def;
208     }
209
210     return prop->value.i;
211 }
212
213 void *qdev_get_prop_ptr(DeviceState *dev, const char *name)
214 {
215     DeviceProperty *prop;
216
217     prop = find_prop(dev, name, PROP_TYPE_PTR);
218     assert(prop);
219     return prop->value.ptr;
220 }
221
222 DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name)
223 {
224     DeviceProperty *prop;
225
226     prop = find_prop(dev, name, PROP_TYPE_DEV);
227     if (!prop) {
228         return NULL;
229     }
230     return prop->value.ptr;
231 }
232
233 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
234 {
235     assert(dev->num_gpio_in == 0);
236     dev->num_gpio_in = n;
237     dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
238 }
239
240 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
241 {
242     assert(dev->num_gpio_out == 0);
243     dev->num_gpio_out = n;
244     dev->gpio_out = pins;
245 }
246
247 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
248 {
249     assert(n >= 0 && n < dev->num_gpio_in);
250     return dev->gpio_in[n];
251 }
252
253 void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
254 {
255     assert(n >= 0 && n < dev->num_gpio_out);
256     dev->gpio_out[n] = pin;
257 }
258
259 VLANClientState *qdev_get_vlan_client(DeviceState *dev,
260                                       IOReadHandler *fd_read,
261                                       IOCanRWHandler *fd_can_read,
262                                       NetCleanup *cleanup,
263                                       void *opaque)
264 {
265     NICInfo *nd = dev->nd;
266     assert(nd);
267     return qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
268                                 fd_read, fd_can_read, cleanup, opaque);
269 }
270
271
272 void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
273 {
274     memcpy(macaddr, dev->nd->macaddr, 6);
275 }
276
277 static int next_block_unit[IF_COUNT];
278
279 /* Get a block device.  This should only be used for single-drive devices
280    (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
281    appropriate bus.  */
282 BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
283 {
284     int unit = next_block_unit[type]++;
285     int index;
286
287     index = drive_get_index(type, 0, unit);
288     if (index == -1) {
289         return NULL;
290     }
291     return drives_table[index].bdrv;
292 }
293
294 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
295 {
296     BusState *bus;
297
298     LIST_FOREACH(bus, &dev->child_bus, sibling) {
299         if (strcmp(name, bus->name) == 0) {
300             return bus;
301         }
302     }
303     return NULL;
304 }
305
306 static int next_scsi_bus;
307
308 /* Create a scsi bus, and attach devices to it.  */
309 /* TODO: Actually create a scsi bus for hotplug to use.  */
310 void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
311 {
312    int bus = next_scsi_bus++;
313    int unit;
314    int index;
315
316    for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
317        index = drive_get_index(IF_SCSI, bus, unit);
318        if (index == -1) {
319            continue;
320        }
321        attach(host, drives_table[index].bdrv, unit);
322    }
323 }
324
325 BusState *qbus_create(BusType type, size_t size,
326                       DeviceState *parent, const char *name)
327 {
328     BusState *bus;
329
330     bus = qemu_mallocz(size);
331     bus->type = type;
332     bus->parent = parent;
333     bus->name = qemu_strdup(name);
334     LIST_INIT(&bus->children);
335     if (parent) {
336         LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
337     }
338     return bus;
339 }