Statistics
| Branch: | Revision:

root / hw / qdev.c @ 042f84d0

History | View | Annotate | Download (10.1 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 "net.h"
30
#include "qdev.h"
31
#include "sysemu.h"
32
#include "monitor.h"
33

    
34
struct DeviceProperty {
35
    const char *name;
36
    DevicePropType type;
37
    union {
38
        uint64_t i;
39
        void *ptr;
40
    } value;
41
    DeviceProperty *next;
42
};
43

    
44
/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
45
static BusState *main_system_bus;
46
extern struct BusInfo system_bus_info;
47

    
48
static DeviceInfo *device_info_list;
49

    
50
/* Register a new device type.  */
51
void qdev_register(DeviceInfo *info)
52
{
53
    assert(info->size >= sizeof(DeviceState));
54
    assert(!info->next);
55

    
56
    info->next = device_info_list;
57
    device_info_list = info;
58
}
59

    
60
/* Create a new device.  This only initializes the device state structure
61
   and allows properties to be set.  qdev_init should be called to
62
   initialize the actual device emulation.  */
63
DeviceState *qdev_create(BusState *bus, const char *name)
64
{
65
    DeviceInfo *info;
66
    DeviceState *dev;
67

    
68
    if (!bus) {
69
        if (!main_system_bus) {
70
            main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
71
        }
72
        bus = main_system_bus;
73
    }
74

    
75
    for (info = device_info_list; info != NULL; info = info->next) {
76
        if (info->bus_info != bus->info)
77
            continue;
78
        if (strcmp(info->name, name) != 0)
79
            continue;
80
        break;
81
    }
82
    if (!info) {
83
        hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
84
    }
85

    
86
    dev = qemu_mallocz(info->size);
87
    dev->info = info;
88
    dev->parent_bus = bus;
89
    LIST_INSERT_HEAD(&bus->children, dev, sibling);
90
    return dev;
91
}
92

    
93
/* Initialize a device.  Device properties should be set before calling
94
   this function.  IRQs and MMIO regions should be connected/mapped after
95
   calling this function.  */
96
void qdev_init(DeviceState *dev)
97
{
98
    dev->info->init(dev, dev->info);
99
}
100

    
101
/* Unlink device from bus and free the structure.  */
102
void qdev_free(DeviceState *dev)
103
{
104
    LIST_REMOVE(dev, sibling);
105
    free(dev);
106
}
107

    
108
static DeviceProperty *create_prop(DeviceState *dev, const char *name,
109
                                   DevicePropType type)
110
{
111
    DeviceProperty *prop;
112

    
113
    /* TODO: Check for duplicate properties.  */
114
    prop = qemu_mallocz(sizeof(*prop));
115
    prop->name = qemu_strdup(name);
116
    prop->type = type;
117
    prop->next = dev->props;
118
    dev->props = prop;
119

    
120
    return prop;
121
}
122

    
123
void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value)
124
{
125
    DeviceProperty *prop;
126

    
127
    prop = create_prop(dev, name, PROP_TYPE_INT);
128
    prop->value.i = value;
129
}
130

    
131
void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value)
132
{
133
    DeviceProperty *prop;
134

    
135
    prop = create_prop(dev, name, PROP_TYPE_DEV);
136
    prop->value.ptr = value;
137
}
138

    
139
void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
140
{
141
    DeviceProperty *prop;
142

    
143
    prop = create_prop(dev, name, PROP_TYPE_PTR);
144
    prop->value.ptr = value;
145
}
146

    
147
void qdev_set_netdev(DeviceState *dev, NICInfo *nd)
148
{
149
    assert(!dev->nd);
150
    dev->nd = nd;
151
}
152

    
153

    
154
/* Get a character (serial) device interface.  */
155
CharDriverState *qdev_init_chardev(DeviceState *dev)
156
{
157
    static int next_serial;
158
    static int next_virtconsole;
159
    /* FIXME: This is a nasty hack that needs to go away.  */
160
    if (strncmp(dev->info->name, "virtio", 6) == 0) {
161
        return virtcon_hds[next_virtconsole++];
162
    } else {
163
        return serial_hds[next_serial++];
164
    }
165
}
166

    
167
BusState *qdev_get_parent_bus(DeviceState *dev)
168
{
169
    return dev->parent_bus;
170
}
171

    
172
static DeviceProperty *find_prop(DeviceState *dev, const char *name,
173
                                 DevicePropType type)
174
{
175
    DeviceProperty *prop;
176

    
177
    for (prop = dev->props; prop; prop = prop->next) {
178
        if (strcmp(prop->name, name) == 0) {
179
            assert (prop->type == type);
180
            return prop;
181
        }
182
    }
183
    return NULL;
184
}
185

    
186
uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def)
187
{
188
    DeviceProperty *prop;
189

    
190
    prop = find_prop(dev, name, PROP_TYPE_INT);
191
    if (!prop) {
192
        return def;
193
    }
194

    
195
    return prop->value.i;
196
}
197

    
198
void *qdev_get_prop_ptr(DeviceState *dev, const char *name)
199
{
200
    DeviceProperty *prop;
201

    
202
    prop = find_prop(dev, name, PROP_TYPE_PTR);
203
    assert(prop);
204
    return prop->value.ptr;
205
}
206

    
207
DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name)
208
{
209
    DeviceProperty *prop;
210

    
211
    prop = find_prop(dev, name, PROP_TYPE_DEV);
212
    if (!prop) {
213
        return NULL;
214
    }
215
    return prop->value.ptr;
216
}
217

    
218
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
219
{
220
    assert(dev->num_gpio_in == 0);
221
    dev->num_gpio_in = n;
222
    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
223
}
224

    
225
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
226
{
227
    assert(dev->num_gpio_out == 0);
228
    dev->num_gpio_out = n;
229
    dev->gpio_out = pins;
230
}
231

    
232
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
233
{
234
    assert(n >= 0 && n < dev->num_gpio_in);
235
    return dev->gpio_in[n];
236
}
237

    
238
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
239
{
240
    assert(n >= 0 && n < dev->num_gpio_out);
241
    dev->gpio_out[n] = pin;
242
}
243

    
244
VLANClientState *qdev_get_vlan_client(DeviceState *dev,
245
                                      NetCanReceive *can_receive,
246
                                      NetReceive *receive,
247
                                      NetReceiveIOV *receive_iov,
248
                                      NetCleanup *cleanup,
249
                                      void *opaque)
250
{
251
    NICInfo *nd = dev->nd;
252
    assert(nd);
253
    return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
254
                                receive, receive_iov, cleanup, opaque);
255
}
256

    
257

    
258
void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
259
{
260
    memcpy(macaddr, dev->nd->macaddr, 6);
261
}
262

    
263
static int next_block_unit[IF_COUNT];
264

    
265
/* Get a block device.  This should only be used for single-drive devices
266
   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
267
   appropriate bus.  */
268
BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
269
{
270
    int unit = next_block_unit[type]++;
271
    int index;
272

    
273
    index = drive_get_index(type, 0, unit);
274
    if (index == -1) {
275
        return NULL;
276
    }
277
    return drives_table[index].bdrv;
278
}
279

    
280
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
281
{
282
    BusState *bus;
283

    
284
    LIST_FOREACH(bus, &dev->child_bus, sibling) {
285
        if (strcmp(name, bus->name) == 0) {
286
            return bus;
287
        }
288
    }
289
    return NULL;
290
}
291

    
292
static int next_scsi_bus;
293

    
294
/* Create a scsi bus, and attach devices to it.  */
295
/* TODO: Actually create a scsi bus for hotplug to use.  */
296
void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
297
{
298
   int bus = next_scsi_bus++;
299
   int unit;
300
   int index;
301

    
302
   for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
303
       index = drive_get_index(IF_SCSI, bus, unit);
304
       if (index == -1) {
305
           continue;
306
       }
307
       attach(host, drives_table[index].bdrv, unit);
308
   }
309
}
310

    
311
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
312
{
313
    BusState *bus;
314

    
315
    bus = qemu_mallocz(info->size);
316
    bus->info = info;
317
    bus->parent = parent;
318
    bus->name = qemu_strdup(name);
319
    LIST_INIT(&bus->children);
320
    if (parent) {
321
        LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
322
    }
323
    return bus;
324
}
325

    
326
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
327
static void qbus_print(Monitor *mon, BusState *bus, int indent);
328

    
329
static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
330
{
331
    DeviceProperty *prop;
332
    BusState *child;
333
    qdev_printf("dev: %s\n", dev->info->name);
334
    indent += 2;
335
    if (dev->num_gpio_in) {
336
        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
337
    }
338
    if (dev->num_gpio_out) {
339
        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
340
    }
341
    for (prop = dev->props; prop; prop = prop->next) {
342
        switch (prop->type) {
343
        case PROP_TYPE_INT:
344
            qdev_printf("prop-int %s 0x%" PRIx64 "\n", prop->name,
345
                        prop->value.i);
346
            break;
347
        case PROP_TYPE_PTR:
348
            qdev_printf("prop-ptr %s\n", prop->name);
349
            break;
350
        case PROP_TYPE_DEV:
351
            qdev_printf("prop-dev %s %s\n", prop->name,
352
                        ((DeviceState *)prop->value.ptr)->info->name);
353
            break;
354
        default:
355
            qdev_printf("prop-unknown%d %s\n", prop->type, prop->name);
356
            break;
357
        }
358
    }
359
    if (dev->parent_bus->info->print_dev)
360
        dev->parent_bus->info->print_dev(mon, dev, indent);
361
    LIST_FOREACH(child, &dev->child_bus, sibling) {
362
        qbus_print(mon, child, indent);
363
    }
364
}
365

    
366
static void qbus_print(Monitor *mon, BusState *bus, int indent)
367
{
368
    struct DeviceState *dev;
369

    
370
    qdev_printf("bus: %s\n", bus->name);
371
    indent += 2;
372
    qdev_printf("type %s\n", bus->info->name);
373
    LIST_FOREACH(dev, &bus->children, sibling) {
374
        qdev_print(mon, dev, indent);
375
    }
376
}
377
#undef qdev_printf
378

    
379
void do_info_qtree(Monitor *mon)
380
{
381
    if (main_system_bus)
382
        qbus_print(mon, main_system_bus, 0);
383
}