Annotation of qemu/hw/qdev.c, revision 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