Basic qdev infrastructure.
[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 "qdev.h"
30 #include "sysemu.h"
31
32 struct DeviceProperty {
33     const char *name;
34     union {
35         int i;
36         void *ptr;
37     } value;
38     DeviceProperty *next;
39 };
40
41 struct DeviceType {
42     const char *name;
43     qdev_initfn init;
44     void *opaque;
45     int size;
46     DeviceType *next;
47 };
48
49 static DeviceType *device_type_list;
50
51 /* Register a new device type.  */
52 DeviceType *qdev_register(const char *name, int size, qdev_initfn init,
53                           void *opaque)
54 {
55     DeviceType *t;
56
57     assert(size >= sizeof(DeviceState));
58
59     t = qemu_mallocz(sizeof(DeviceType));
60     t->next = device_type_list;
61     device_type_list = t;
62     t->name = qemu_strdup(name);
63     t->size = size;
64     t->init = init;
65     t->opaque = opaque;
66
67     return t;
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(void *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         fprintf(stderr, "Unknown device '%s'\n", name);
85         exit(1);
86     }
87
88     dev = qemu_mallocz(t->size);
89     dev->name = name;
90     dev->type = t;
91     dev->bus = bus;
92     return dev;
93 }
94
95 /* Initialize a device.  Device properties should be set before calling
96    this function.  IRQs and MMIO regions should be connected/mapped after
97    calling this function.  */
98 void qdev_init(DeviceState *dev)
99 {
100     dev->type->init(dev, dev->type->opaque);
101 }
102
103 static DeviceProperty *create_prop(DeviceState *dev, const char *name)
104 {
105     DeviceProperty *prop;
106
107     /* TODO: Check for duplicate properties.  */
108     prop = qemu_mallocz(sizeof(*prop));
109     prop->name = qemu_strdup(name);
110     prop->next = dev->props;
111     dev->props = prop;
112
113     return prop;
114 }
115
116 void qdev_set_prop_int(DeviceState *dev, const char *name, int value)
117 {
118     DeviceProperty *prop;
119
120     prop = create_prop(dev, name);
121     prop->value.i = value;
122 }
123
124 void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
125 {
126     DeviceProperty *prop;
127
128     prop = create_prop(dev, name);
129     prop->value.ptr = value;
130 }
131
132
133 qemu_irq qdev_get_irq_sink(DeviceState *dev, int n)
134 {
135     assert(n >= 0 && n < dev->num_irq_sink);
136     return dev->irq_sink[n];
137 }
138
139 /* Register device IRQ sinks.  */
140 void qdev_init_irq_sink(DeviceState *dev, qemu_irq_handler handler, int nirq)
141 {
142     dev->num_irq_sink = nirq;
143     dev->irq_sink = qemu_allocate_irqs(handler, dev, nirq);
144 }
145
146 /* Get a character (serial) device interface.  */
147 CharDriverState *qdev_init_chardev(DeviceState *dev)
148 {
149     static int next_serial;
150     static int next_virtconsole;
151     /* FIXME: This is a nasty hack that needs to go away.  */
152     if (strncmp(dev->name, "virtio", 6) == 0) {
153         return virtcon_hds[next_virtconsole++];
154     } else {
155         return serial_hds[next_serial++];
156     }
157 }
158
159 void *qdev_get_bus(DeviceState *dev)
160 {
161     return dev->bus;
162 }
163
164 static DeviceProperty *find_prop(DeviceState *dev, const char *name)
165 {
166     DeviceProperty *prop;
167
168     for (prop = dev->props; prop; prop = prop->next) {
169         if (strcmp(prop->name, name) == 0) {
170             return prop;
171         }
172     }
173     return NULL;
174 }
175
176 uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def)
177 {
178     DeviceProperty *prop;
179
180     prop = find_prop(dev, name);
181     if (!prop)
182         return def;
183
184     return prop->value.i;
185 }
186
187 void *qdev_get_prop_ptr(DeviceState *dev, const char *name)
188 {
189     DeviceProperty *prop;
190
191     prop = find_prop(dev, name);
192     assert(prop);
193     return prop->value.ptr;
194 }
195
196 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
197 {
198     assert(dev->num_gpio_in == 0);
199     dev->num_gpio_in = n;
200     dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
201 }
202
203 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
204 {
205     assert(dev->num_gpio_out == 0);
206     dev->num_gpio_out = n;
207     dev->gpio_out = pins;
208 }
209
210 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
211 {
212     assert(n >= 0 && n < dev->num_gpio_in);
213     return dev->gpio_in[n];
214 }
215
216 void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
217 {
218     assert(n >= 0 && n < dev->num_gpio_out);
219     dev->gpio_out[n] = pin;
220 }
221
222 static int next_block_unit[IF_COUNT];
223
224 /* Get a block device.  This should only be used for single-drive devices
225    (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
226    appropriate bus.  */
227 BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
228 {
229     int unit = next_block_unit[type]++;
230     int index;
231
232     index = drive_get_index(type, 0, unit);
233     if (index == -1) {
234         return NULL;
235     }
236     return drives_table[index].bdrv;
237 }