Statistics
| Branch: | Revision:

root / hw / qdev.c @ aae9460e

History | View | Annotate | Download (6 kB)

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
}