Annotation of qemu/hw/qdev.c, revision 1.1.1.1

1.1       root        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, see <http://www.gnu.org/licenses/>.
                     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: 
                     28: #include "net.h"
                     29: #include "qdev.h"
                     30: #include "sysemu.h"
                     31: #include "monitor.h"
                     32: 
                     33: /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
                     34: static BusState *main_system_bus;
                     35: 
                     36: static DeviceInfo *device_info_list;
                     37: 
                     38: /* Register a new device type.  */
                     39: void qdev_register(DeviceInfo *info)
                     40: {
                     41:     assert(info->size >= sizeof(DeviceState));
                     42:     assert(!info->next);
                     43: 
                     44:     info->next = device_info_list;
                     45:     device_info_list = info;
                     46: }
                     47: 
                     48: static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
                     49: {
                     50:     DeviceInfo *info;
                     51: 
                     52:     /* first check device names */
                     53:     for (info = device_info_list; info != NULL; info = info->next) {
                     54:         if (bus_info && info->bus_info != bus_info)
                     55:             continue;
                     56:         if (strcmp(info->name, name) != 0)
                     57:             continue;
                     58:         return info;
                     59:     }
                     60: 
                     61:     /* failing that check the aliases */
                     62:     for (info = device_info_list; info != NULL; info = info->next) {
                     63:         if (bus_info && info->bus_info != bus_info)
                     64:             continue;
                     65:         if (!info->alias)
                     66:             continue;
                     67:         if (strcmp(info->alias, name) != 0)
                     68:             continue;
                     69:         return info;
                     70:     }
                     71:     return NULL;
                     72: }
                     73: 
                     74: /* Create a new device.  This only initializes the device state structure
                     75:    and allows properties to be set.  qdev_init should be called to
                     76:    initialize the actual device emulation.  */
                     77: DeviceState *qdev_create(BusState *bus, const char *name)
                     78: {
                     79:     DeviceInfo *info;
                     80:     DeviceState *dev;
                     81: 
                     82:     if (!bus) {
                     83:         if (!main_system_bus) {
                     84:             main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
                     85:         }
                     86:         bus = main_system_bus;
                     87:     }
                     88: 
                     89:     info = qdev_find_info(bus->info, name);
                     90:     if (!info) {
                     91:         hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
                     92:     }
                     93: 
                     94:     dev = qemu_mallocz(info->size);
                     95:     dev->info = info;
                     96:     dev->parent_bus = bus;
                     97:     qdev_prop_set_defaults(dev, dev->info->props);
                     98:     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
                     99:     qdev_prop_set_compat(dev);
                    100:     LIST_INSERT_HEAD(&bus->children, dev, sibling);
                    101:     return dev;
                    102: }
                    103: 
                    104: /* Initialize a device.  Device properties should be set before calling
                    105:    this function.  IRQs and MMIO regions should be connected/mapped after
                    106:    calling this function.  */
                    107: void qdev_init(DeviceState *dev)
                    108: {
                    109:     dev->info->init(dev, dev->info);
                    110: }
                    111: 
                    112: /* Unlink device from bus and free the structure.  */
                    113: void qdev_free(DeviceState *dev)
                    114: {
                    115:     LIST_REMOVE(dev, sibling);
                    116:     qemu_free(dev->id);
                    117:     qemu_free(dev);
                    118: }
                    119: 
                    120: /* Get a character (serial) device interface.  */
                    121: CharDriverState *qdev_init_chardev(DeviceState *dev)
                    122: {
                    123:     static int next_serial;
                    124:     static int next_virtconsole;
                    125:     /* FIXME: This is a nasty hack that needs to go away.  */
                    126:     if (strncmp(dev->info->name, "virtio", 6) == 0) {
                    127:         return virtcon_hds[next_virtconsole++];
                    128:     } else {
                    129:         return serial_hds[next_serial++];
                    130:     }
                    131: }
                    132: 
                    133: BusState *qdev_get_parent_bus(DeviceState *dev)
                    134: {
                    135:     return dev->parent_bus;
                    136: }
                    137: 
                    138: void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
                    139: {
                    140:     assert(dev->num_gpio_in == 0);
                    141:     dev->num_gpio_in = n;
                    142:     dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
                    143: }
                    144: 
                    145: void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
                    146: {
                    147:     assert(dev->num_gpio_out == 0);
                    148:     dev->num_gpio_out = n;
                    149:     dev->gpio_out = pins;
                    150: }
                    151: 
                    152: qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
                    153: {
                    154:     assert(n >= 0 && n < dev->num_gpio_in);
                    155:     return dev->gpio_in[n];
                    156: }
                    157: 
                    158: void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
                    159: {
                    160:     assert(n >= 0 && n < dev->num_gpio_out);
                    161:     dev->gpio_out[n] = pin;
                    162: }
                    163: 
                    164: VLANClientState *qdev_get_vlan_client(DeviceState *dev,
                    165:                                       NetCanReceive *can_receive,
                    166:                                       NetReceive *receive,
                    167:                                       NetReceiveIOV *receive_iov,
                    168:                                       NetCleanup *cleanup,
                    169:                                       void *opaque)
                    170: {
                    171:     NICInfo *nd = dev->nd;
                    172:     assert(nd);
                    173:     nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
                    174:                                   receive, receive_iov, cleanup, opaque);
                    175:     return nd->vc;
                    176: }
                    177: 
                    178: 
                    179: void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
                    180: {
                    181:     memcpy(macaddr, dev->nd->macaddr, 6);
                    182: }
                    183: 
                    184: static int next_block_unit[IF_COUNT];
                    185: 
                    186: /* Get a block device.  This should only be used for single-drive devices
                    187:    (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
                    188:    appropriate bus.  */
                    189: BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
                    190: {
                    191:     int unit = next_block_unit[type]++;
                    192:     int index;
                    193: 
                    194:     index = drive_get_index(type, 0, unit);
                    195:     if (index == -1) {
                    196:         return NULL;
                    197:     }
                    198:     return drives_table[index].bdrv;
                    199: }
                    200: 
                    201: BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
                    202: {
                    203:     BusState *bus;
                    204: 
                    205:     LIST_FOREACH(bus, &dev->child_bus, sibling) {
                    206:         if (strcmp(name, bus->name) == 0) {
                    207:             return bus;
                    208:         }
                    209:     }
                    210:     return NULL;
                    211: }
                    212: 
                    213: static int next_scsi_bus;
                    214: 
                    215: /* Create a scsi bus, and attach devices to it.  */
                    216: /* TODO: Actually create a scsi bus for hotplug to use.  */
                    217: void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
                    218: {
                    219:    int bus = next_scsi_bus++;
                    220:    int unit;
                    221:    int index;
                    222: 
                    223:    for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
                    224:        index = drive_get_index(IF_SCSI, bus, unit);
                    225:        if (index == -1) {
                    226:            continue;
                    227:        }
                    228:        attach(host, drives_table[index].bdrv, unit);
                    229:    }
                    230: }
                    231: 
                    232: BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
                    233: {
                    234:     BusState *bus;
                    235: 
                    236:     bus = qemu_mallocz(info->size);
                    237:     bus->info = info;
                    238:     bus->parent = parent;
                    239:     bus->name = qemu_strdup(name);
                    240:     LIST_INIT(&bus->children);
                    241:     if (parent) {
                    242:         LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
                    243:     }
                    244:     return bus;
                    245: }
                    246: 
                    247: #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
                    248: static void qbus_print(Monitor *mon, BusState *bus, int indent);
                    249: 
                    250: static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
                    251:                              const char *prefix, int indent)
                    252: {
                    253:     char buf[64];
                    254: 
                    255:     if (!props)
                    256:         return;
                    257:     while (props->name) {
                    258:         if (props->info->print) {
                    259:             props->info->print(dev, props, buf, sizeof(buf));
                    260:             qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
                    261:         }
                    262:         props++;
                    263:     }
                    264: }
                    265: 
                    266: static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
                    267: {
                    268:     BusState *child;
                    269:     qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
                    270:                 dev->id ? dev->id : "");
                    271:     indent += 2;
                    272:     if (dev->num_gpio_in) {
                    273:         qdev_printf("gpio-in %d\n", dev->num_gpio_in);
                    274:     }
                    275:     if (dev->num_gpio_out) {
                    276:         qdev_printf("gpio-out %d\n", dev->num_gpio_out);
                    277:     }
                    278:     qdev_print_props(mon, dev, dev->info->props, "dev", indent);
                    279:     qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
                    280:     if (dev->parent_bus->info->print_dev)
                    281:         dev->parent_bus->info->print_dev(mon, dev, indent);
                    282:     LIST_FOREACH(child, &dev->child_bus, sibling) {
                    283:         qbus_print(mon, child, indent);
                    284:     }
                    285: }
                    286: 
                    287: static void qbus_print(Monitor *mon, BusState *bus, int indent)
                    288: {
                    289:     struct DeviceState *dev;
                    290: 
                    291:     qdev_printf("bus: %s\n", bus->name);
                    292:     indent += 2;
                    293:     qdev_printf("type %s\n", bus->info->name);
                    294:     LIST_FOREACH(dev, &bus->children, sibling) {
                    295:         qdev_print(mon, dev, indent);
                    296:     }
                    297: }
                    298: #undef qdev_printf
                    299: 
                    300: void do_info_qtree(Monitor *mon)
                    301: {
                    302:     if (main_system_bus)
                    303:         qbus_print(mon, main_system_bus, 0);
                    304: }

unix.superglobalmegacorp.com