Diff for /qemu/hw/qdev.c between versions 1.1.1.3 and 1.1.1.7

version 1.1.1.3, 2018/04/24 18:28:31 version 1.1.1.7, 2018/04/24 19:47:15
Line 28 Line 28
 #include "net.h"  #include "net.h"
 #include "qdev.h"  #include "qdev.h"
 #include "sysemu.h"  #include "sysemu.h"
 #include "monitor.h"  #include "error.h"
   
 static int qdev_hotplug = 0;  int qdev_hotplug = 0;
   static bool qdev_hot_added = false;
   static bool qdev_hot_removed = false;
   
 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */  /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
 static BusState *main_system_bus;  static BusState *main_system_bus;
   static void main_system_bus_create(void);
 DeviceInfo *device_info_list;  
   
 static BusState *qbus_find_recursive(BusState *bus, const char *name,  
                                      const BusInfo *info);  
 static BusState *qbus_find(const char *path);  
   
 /* Register a new device type.  */  /* Register a new device type.  */
 void qdev_register(DeviceInfo *info)  const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
 {  {
     assert(info->size >= sizeof(DeviceState));      DeviceClass *dc = DEVICE_GET_CLASS(dev);
     assert(!info->next);      return dc->vmsd;
   
     info->next = device_info_list;  
     device_info_list = info;  
 }  }
   
 static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)  BusInfo *qdev_get_bus_info(DeviceState *dev)
 {  {
     DeviceInfo *info;      DeviceClass *dc = DEVICE_GET_CLASS(dev);
       return dc->bus_info;
     /* first check device names */  
     for (info = device_info_list; info != NULL; info = info->next) {  
         if (bus_info && info->bus_info != bus_info)  
             continue;  
         if (strcmp(info->name, name) != 0)  
             continue;  
         return info;  
     }  
   
     /* failing that check the aliases */  
     for (info = device_info_list; info != NULL; info = info->next) {  
         if (bus_info && info->bus_info != bus_info)  
             continue;  
         if (!info->alias)  
             continue;  
         if (strcmp(info->alias, name) != 0)  
             continue;  
         return info;  
     }  
     return NULL;  
 }  }
   
 static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)  Property *qdev_get_props(DeviceState *dev)
 {  {
     DeviceState *dev;      DeviceClass *dc = DEVICE_GET_CLASS(dev);
       return dc->props;
     assert(bus->info == info->bus_info);  
     dev = qemu_mallocz(info->size);  
     dev->info = info;  
     dev->parent_bus = bus;  
     qdev_prop_set_defaults(dev, dev->info->props);  
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);  
     qdev_prop_set_globals(dev);  
     QLIST_INSERT_HEAD(&bus->children, dev, sibling);  
     if (qdev_hotplug) {  
         assert(bus->allow_hotplug);  
         dev->hotplugged = 1;  
     }  
     dev->instance_id_alias = -1;  
     dev->state = DEV_STATE_CREATED;  
     return dev;  
 }  }
   
 /* Create a new device.  This only initializes the device state structure  const char *qdev_fw_name(DeviceState *dev)
    and allows properties to be set.  qdev_init should be called to  
    initialize the actual device emulation.  */  
 DeviceState *qdev_create(BusState *bus, const char *name)  
 {  {
     DeviceInfo *info;      DeviceClass *dc = DEVICE_GET_CLASS(dev);
   
     if (!bus) {      if (dc->fw_name) {
         if (!main_system_bus) {          return dc->fw_name;
             main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");  
         }  
         bus = main_system_bus;  
     }      }
   
     info = qdev_find_info(bus->info, name);      return object_get_typename(OBJECT(dev));
     if (!info) {  
         hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);  
     }  
   
     return qdev_create_from_info(bus, info);  
 }  }
   
 static void qdev_print_devinfo(DeviceInfo *info)  bool qdev_exists(const char *name)
 {  {
     error_printf("name \"%s\", bus %s",      return !!object_class_by_name(name);
                  info->name, info->bus_info->name);  
     if (info->alias) {  
         error_printf(", alias \"%s\"", info->alias);  
     }  
     if (info->desc) {  
         error_printf(", desc \"%s\"", info->desc);  
     }  
     if (info->no_user) {  
         error_printf(", no-user");  
     }  
     error_printf("\n");  
 }  }
   
 static int set_property(const char *name, const char *value, void *opaque)  static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
 {                                       Error **errp);
     DeviceState *dev = opaque;  
   
     if (strcmp(name, "driver") == 0)  
         return 0;  
     if (strcmp(name, "bus") == 0)  
         return 0;  
   
     if (qdev_prop_parse(dev, name, value) == -1) {  
         return -1;  
     }  
     return 0;  
 }  
   
 int qdev_device_help(QemuOpts *opts)  void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
 {  {
     const char *driver;  
     DeviceInfo *info;  
     Property *prop;      Property *prop;
   
     driver = qemu_opt_get(opts, "driver");      if (qdev_hotplug) {
     if (driver && !strcmp(driver, "?")) {          assert(bus->allow_hotplug);
         for (info = device_info_list; info != NULL; info = info->next) {  
             if (info->no_user) {  
                 continue;       /* not available, don't show */  
             }  
             qdev_print_devinfo(info);  
         }  
         return 1;  
     }      }
   
     if (!qemu_opt_get(opts, "?")) {      dev->parent_bus = bus;
         return 0;      QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
     }  
   
     info = qdev_find_info(NULL, driver);      for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
     if (!info) {          qdev_property_add_legacy(dev, prop, NULL);
         return 0;          qdev_property_add_static(dev, prop, NULL);
     }      }
       qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
   }
   
   /* Create a new device.  This only initializes the device state structure
      and allows properties to be set.  qdev_init should be called to
      initialize the actual device emulation.  */
   DeviceState *qdev_create(BusState *bus, const char *name)
   {
       DeviceState *dev;
   
     for (prop = info->props; prop && prop->name; prop++) {      dev = qdev_try_create(bus, name);
         /*      if (!dev) {
          * TODO Properties without a parser are just for dirty hacks.          if (bus) {
          * qdev_prop_ptr is the only such PropertyInfo.  It's marked              hw_error("Unknown device '%s' for bus '%s'\n", name,
          * for removal.  This conditional should be removed along with                       bus->info->name);
          * it.          } else {
          */              hw_error("Unknown device '%s' for default sysbus\n", name);
         if (!prop->info->parse) {  
             continue;           /* no way to set it, don't show */  
         }          }
         error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);  
     }      }
     return 1;  
       return dev;
 }  }
   
 DeviceState *qdev_device_add(QemuOpts *opts)  DeviceState *qdev_try_create(BusState *bus, const char *type)
 {  {
     const char *driver, *path, *id;      DeviceState *dev;
     DeviceInfo *info;  
     DeviceState *qdev;  
     BusState *bus;  
   
     driver = qemu_opt_get(opts, "driver");      if (object_class_by_name(type) == NULL) {
     if (!driver) {  
         qerror_report(QERR_MISSING_PARAMETER, "driver");  
         return NULL;          return NULL;
     }      }
       dev = DEVICE(object_new(type));
     /* find driver */      if (!dev) {
     info = qdev_find_info(NULL, driver);  
     if (!info || info->no_user) {  
         qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");  
         error_printf_unless_qmp("Try with argument '?' for a list.\n");  
         return NULL;          return NULL;
     }      }
   
     /* find bus */      if (!bus) {
     path = qemu_opt_get(opts, "bus");          bus = sysbus_get_default();
     if (path != NULL) {  
         bus = qbus_find(path);  
         if (!bus) {  
             return NULL;  
         }  
         if (bus->info != info->bus_info) {  
             qerror_report(QERR_BAD_BUS_FOR_DEVICE,  
                            driver, bus->info->name);  
             return NULL;  
         }  
     } else {  
         bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);  
         if (!bus) {  
             qerror_report(QERR_NO_BUS_FOR_DEVICE,  
                            info->name, info->bus_info->name);  
             return NULL;  
         }  
     }  
     if (qdev_hotplug && !bus->allow_hotplug) {  
         qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);  
         return NULL;  
     }      }
   
     /* create device, set properties */      qdev_set_parent_bus(dev, bus);
     qdev = qdev_create_from_info(bus, info);      qdev_prop_set_globals(dev);
     id = qemu_opts_id(opts);  
     if (id) {  
         qdev->id = id;  
     }  
     if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {  
         qdev_free(qdev);  
         return NULL;  
     }  
     if (qdev_init(qdev) < 0) {  
         qerror_report(QERR_DEVICE_INIT_FAILED, driver);  
         return NULL;  
     }  
     qdev->opts = opts;  
     return qdev;  
 }  
   
 static void qdev_reset(void *opaque)      return dev;
 {  
     DeviceState *dev = opaque;  
     if (dev->info->reset)  
         dev->info->reset(dev);  
 }  }
   
 /* Initialize a device.  Device properties should be set before calling  /* Initialize a device.  Device properties should be set before calling
Line 270  static void qdev_reset(void *opaque) Line 143  static void qdev_reset(void *opaque)
    Return 0 on success.  */     Return 0 on success.  */
 int qdev_init(DeviceState *dev)  int qdev_init(DeviceState *dev)
 {  {
       DeviceClass *dc = DEVICE_GET_CLASS(dev);
     int rc;      int rc;
   
     assert(dev->state == DEV_STATE_CREATED);      assert(dev->state == DEV_STATE_CREATED);
     rc = dev->info->init(dev, dev->info);  
       rc = dc->init(dev);
     if (rc < 0) {      if (rc < 0) {
           object_unparent(OBJECT(dev));
         qdev_free(dev);          qdev_free(dev);
         return rc;          return rc;
     }      }
     qemu_register_reset(qdev_reset, dev);  
     if (dev->info->vmsd) {      if (!OBJECT(dev)->parent) {
         vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,          static int unattached_count = 0;
           gchar *name = g_strdup_printf("device[%d]", unattached_count++);
   
           object_property_add_child(container_get(qdev_get_machine(),
                                                   "/unattached"),
                                     name, OBJECT(dev), NULL);
           g_free(name);
       }
   
       if (qdev_get_vmsd(dev)) {
           vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
                                        dev->instance_id_alias,                                         dev->instance_id_alias,
                                        dev->alias_required_for_version);                                         dev->alias_required_for_version);
     }      }
     dev->state = DEV_STATE_INITIALIZED;      dev->state = DEV_STATE_INITIALIZED;
       if (dev->hotplugged) {
           device_reset(dev);
       }
     return 0;      return 0;
 }  }
   
Line 296  void qdev_set_legacy_instance_id(DeviceS Line 185  void qdev_set_legacy_instance_id(DeviceS
     dev->alias_required_for_version = required_for_version;      dev->alias_required_for_version = required_for_version;
 }  }
   
 int qdev_unplug(DeviceState *dev)  void qdev_unplug(DeviceState *dev, Error **errp)
 {  {
       DeviceClass *dc = DEVICE_GET_CLASS(dev);
   
     if (!dev->parent_bus->allow_hotplug) {      if (!dev->parent_bus->allow_hotplug) {
         qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);          error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
         return -1;          return;
       }
       assert(dc->unplug != NULL);
   
       qdev_hot_removed = true;
   
       if (dc->unplug(dev) < 0) {
           error_set(errp, QERR_UNDEFINED_ERROR);
           return;
       }
   }
   
   static int qdev_reset_one(DeviceState *dev, void *opaque)
   {
       device_reset(dev);
   
       return 0;
   }
   
   BusState *sysbus_get_default(void)
   {
       if (!main_system_bus) {
           main_system_bus_create();
     }      }
     assert(dev->info->unplug != NULL);      return main_system_bus;
   }
   
     return dev->info->unplug(dev);  static int qbus_reset_one(BusState *bus, void *opaque)
   {
       if (bus->info->reset) {
           return bus->info->reset(bus);
       }
       return 0;
   }
   
   void qdev_reset_all(DeviceState *dev)
   {
       qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
   }
   
   void qbus_reset_all_fn(void *opaque)
   {
       BusState *bus = opaque;
       qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
 }  }
   
 /* can be used as ->unplug() callback for the simple cases */  /* can be used as ->unplug() callback for the simple cases */
 int qdev_simple_unplug_cb(DeviceState *dev)  int qdev_simple_unplug_cb(DeviceState *dev)
 {  {
     /* just zap it */      /* just zap it */
       object_unparent(OBJECT(dev));
     qdev_free(dev);      qdev_free(dev);
     return 0;      return 0;
 }  }
   
 /* Like qdev_init(), but terminate program via hw_error() instead of  
   /* Like qdev_init(), but terminate program via error_report() instead of
    returning an error value.  This is okay during machine creation.     returning an error value.  This is okay during machine creation.
    Don't use for hotplug, because there callers need to recover from     Don't use for hotplug, because there callers need to recover from
    failure.  Exception: if you know the device's init() callback can't     failure.  Exception: if you know the device's init() callback can't
Line 324  int qdev_simple_unplug_cb(DeviceState *d Line 256  int qdev_simple_unplug_cb(DeviceState *d
    way is somewhat unclean, and best avoided.  */     way is somewhat unclean, and best avoided.  */
 void qdev_init_nofail(DeviceState *dev)  void qdev_init_nofail(DeviceState *dev)
 {  {
     DeviceInfo *info = dev->info;  
   
     if (qdev_init(dev) < 0) {      if (qdev_init(dev) < 0) {
         error_report("Initialization of device %s failed\n", info->name);          error_report("Initialization of device %s failed",
                        object_get_typename(OBJECT(dev)));
         exit(1);          exit(1);
     }      }
 }  }
Line 335  void qdev_init_nofail(DeviceState *dev) Line 266  void qdev_init_nofail(DeviceState *dev)
 /* Unlink device from bus and free the structure.  */  /* Unlink device from bus and free the structure.  */
 void qdev_free(DeviceState *dev)  void qdev_free(DeviceState *dev)
 {  {
     BusState *bus;      object_delete(OBJECT(dev));
     Property *prop;  
   
     if (dev->state == DEV_STATE_INITIALIZED) {  
         while (dev->num_child_bus) {  
             bus = QLIST_FIRST(&dev->child_bus);  
             qbus_free(bus);  
         }  
         if (dev->info->vmsd)  
             vmstate_unregister(dev, dev->info->vmsd, dev);  
         if (dev->info->exit)  
             dev->info->exit(dev);  
         if (dev->opts)  
             qemu_opts_del(dev->opts);  
     }  
     qemu_unregister_reset(qdev_reset, dev);  
     QLIST_REMOVE(dev, sibling);  
     for (prop = dev->info->props; prop && prop->name; prop++) {  
         if (prop->info->free) {  
             prop->info->free(dev, prop);  
         }  
     }  
     qemu_free(dev);  
 }  }
   
 void qdev_machine_creation_done(void)  void qdev_machine_creation_done(void)
Line 369  void qdev_machine_creation_done(void) Line 278  void qdev_machine_creation_done(void)
     qdev_hotplug = 1;      qdev_hotplug = 1;
 }  }
   
 /* Get a character (serial) device interface.  */  bool qdev_machine_modified(void)
 CharDriverState *qdev_init_chardev(DeviceState *dev)  
 {  {
     static int next_serial;      return qdev_hot_added || qdev_hot_removed;
   
     /* FIXME: This function needs to go away: use chardev properties!  */  
     return serial_hds[next_serial++];  
 }  }
   
 BusState *qdev_get_parent_bus(DeviceState *dev)  BusState *qdev_get_parent_bus(DeviceState *dev)
Line 411  void qdev_connect_gpio_out(DeviceState * Line 316  void qdev_connect_gpio_out(DeviceState *
   
 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)  void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
 {  {
     qdev_prop_set_macaddr(dev, "mac", nd->macaddr);      qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
     if (nd->vlan)      if (nd->vlan)
         qdev_prop_set_vlan(dev, "vlan", nd->vlan);          qdev_prop_set_vlan(dev, "vlan", nd->vlan);
     if (nd->netdev)      if (nd->netdev)
Line 420  void qdev_set_nic_properties(DeviceState Line 325  void qdev_set_nic_properties(DeviceState
         qdev_prop_exists(dev, "vectors")) {          qdev_prop_exists(dev, "vectors")) {
         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);          qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
     }      }
 }      nd->instantiated = 1;
   
 static int next_block_unit[IF_COUNT];  
   
 /* Get a block device.  This should only be used for single-drive devices  
    (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the  
    appropriate bus.  */  
 BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)  
 {  
     int unit = next_block_unit[type]++;  
     DriveInfo *dinfo;  
   
     dinfo = drive_get(type, 0, unit);  
     return dinfo ? dinfo->bdrv : NULL;  
 }  }
   
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)  BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
Line 448  BusState *qdev_get_child_bus(DeviceState Line 340  BusState *qdev_get_child_bus(DeviceState
     return NULL;      return NULL;
 }  }
   
 static BusState *qbus_find_recursive(BusState *bus, const char *name,  int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
                                      const BusInfo *info)                         qbus_walkerfn *busfn, void *opaque)
 {  {
     DeviceState *dev;      DeviceState *dev;
     BusState *child, *ret;      int err;
     int match = 1;  
   
     if (name && (strcmp(bus->name, name) != 0)) {      if (busfn) {
         match = 0;          err = busfn(bus, opaque);
     }          if (err) {
     if (info && (bus->info != info)) {              return err;
         match = 0;  
     }  
     if (match) {  
         return bus;  
     }  
   
     QLIST_FOREACH(dev, &bus->children, sibling) {  
         QLIST_FOREACH(child, &dev->child_bus, sibling) {  
             ret = qbus_find_recursive(child, name, info);  
             if (ret) {  
                 return ret;  
             }  
         }          }
     }      }
     return NULL;  
 }  
   
 static DeviceState *qdev_find_recursive(BusState *bus, const char *id)  
 {  
     DeviceState *dev, *ret;  
     BusState *child;  
   
     QLIST_FOREACH(dev, &bus->children, sibling) {      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->id && strcmp(dev->id, id) == 0)          err = qdev_walk_children(dev, devfn, busfn, opaque);
             return dev;          if (err < 0) {
         QLIST_FOREACH(child, &dev->child_bus, sibling) {              return err;
             ret = qdev_find_recursive(child, id);  
             if (ret) {  
                 return ret;  
             }  
         }          }
     }      }
     return NULL;  
 }  
   
 static void qbus_list_bus(DeviceState *dev)  
 {  
     BusState *child;  
     const char *sep = " ";  
   
     error_printf("child busses at \"%s\":",  
                  dev->id ? dev->id : dev->info->name);  
     QLIST_FOREACH(child, &dev->child_bus, sibling) {  
         error_printf("%s\"%s\"", sep, child->name);  
         sep = ", ";  
     }  
     error_printf("\n");  
 }  
   
 static void qbus_list_dev(BusState *bus)  
 {  
     DeviceState *dev;  
     const char *sep = " ";  
   
     error_printf("devices at \"%s\":", bus->name);      return 0;
     QLIST_FOREACH(dev, &bus->children, sibling) {  
         error_printf("%s\"%s\"", sep, dev->info->name);  
         if (dev->id)  
             error_printf("/\"%s\"", dev->id);  
         sep = ", ";  
     }  
     error_printf("\n");  
 }  }
   
 static BusState *qbus_find_bus(DeviceState *dev, char *elem)  int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
                          qbus_walkerfn *busfn, void *opaque)
 {  {
     BusState *child;      BusState *bus;
       int err;
   
     QLIST_FOREACH(child, &dev->child_bus, sibling) {      if (devfn) {
         if (strcmp(child->name, elem) == 0) {          err = devfn(dev, opaque);
             return child;          if (err) {
               return err;
         }          }
     }      }
     return NULL;  
 }  
   
 static DeviceState *qbus_find_dev(BusState *bus, char *elem)      QLIST_FOREACH(bus, &dev->child_bus, sibling) {
 {          err = qbus_walk_children(bus, devfn, busfn, opaque);
     DeviceState *dev;          if (err < 0) {
               return err;
     /*  
      * try to match in order:  
      *   (1) instance id, if present  
      *   (2) driver name  
      *   (3) driver alias, if present  
      */  
     QLIST_FOREACH(dev, &bus->children, sibling) {  
         if (dev->id  &&  strcmp(dev->id, elem) == 0) {  
             return dev;  
         }  
     }  
     QLIST_FOREACH(dev, &bus->children, sibling) {  
         if (strcmp(dev->info->name, elem) == 0) {  
             return dev;  
         }  
     }  
     QLIST_FOREACH(dev, &bus->children, sibling) {  
         if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {  
             return dev;  
         }          }
     }      }
     return NULL;  
       return 0;
 }  }
   
 static BusState *qbus_find(const char *path)  DeviceState *qdev_find_recursive(BusState *bus, const char *id)
 {  {
     DeviceState *dev;      DeviceState *dev, *ret;
     BusState *bus;      BusState *child;
     char elem[128];  
     int pos, len;  
   
     /* find start element */  
     if (path[0] == '/') {  
         bus = main_system_bus;  
         pos = 0;  
     } else {  
         if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {  
             assert(!path[0]);  
             elem[0] = len = 0;  
         }  
         bus = qbus_find_recursive(main_system_bus, elem, NULL);  
         if (!bus) {  
             qerror_report(QERR_BUS_NOT_FOUND, elem);  
             return NULL;  
         }  
         pos = len;  
     }  
   
     for (;;) {  
         assert(path[pos] == '/' || !path[pos]);  
         while (path[pos] == '/') {  
             pos++;  
         }  
         if (path[pos] == '\0') {  
             return bus;  
         }  
   
         /* find device */  
         if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {  
             assert(0);  
             elem[0] = len = 0;  
         }  
         pos += len;  
         dev = qbus_find_dev(bus, elem);  
         if (!dev) {  
             qerror_report(QERR_DEVICE_NOT_FOUND, elem);  
             if (!monitor_cur_is_qmp()) {  
                 qbus_list_dev(bus);  
             }  
             return NULL;  
         }  
   
         assert(path[pos] == '/' || !path[pos]);  
         while (path[pos] == '/') {  
             pos++;  
         }  
         if (path[pos] == '\0') {  
             /* last specified element is a device.  If it has exactly  
              * one child bus accept it nevertheless */  
             switch (dev->num_child_bus) {  
             case 0:  
                 qerror_report(QERR_DEVICE_NO_BUS, elem);  
                 return NULL;  
             case 1:  
                 return QLIST_FIRST(&dev->child_bus);  
             default:  
                 qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);  
                 if (!monitor_cur_is_qmp()) {  
                     qbus_list_bus(dev);  
                 }  
                 return NULL;  
             }  
         }  
   
         /* find bus */      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {          if (dev->id && strcmp(dev->id, id) == 0)
             assert(0);              return dev;
             elem[0] = len = 0;          QLIST_FOREACH(child, &dev->child_bus, sibling) {
         }              ret = qdev_find_recursive(child, id);
         pos += len;              if (ret) {
         bus = qbus_find_bus(dev, elem);                  return ret;
         if (!bus) {  
             qerror_report(QERR_BUS_NOT_FOUND, elem);  
             if (!monitor_cur_is_qmp()) {  
                 qbus_list_bus(dev);  
             }              }
             return NULL;  
         }          }
     }      }
       return NULL;
 }  }
   
 void qbus_create_inplace(BusState *bus, BusInfo *info,  void qbus_create_inplace(BusState *bus, BusInfo *info,
Line 661  void qbus_create_inplace(BusState *bus,  Line 415  void qbus_create_inplace(BusState *bus, 
   
     if (name) {      if (name) {
         /* use supplied name */          /* use supplied name */
         bus->name = qemu_strdup(name);          bus->name = g_strdup(name);
     } else if (parent && parent->id) {      } else if (parent && parent->id) {
         /* parent device has id -> use it for bus name */          /* parent device has id -> use it for bus name */
         len = strlen(parent->id) + 16;          len = strlen(parent->id) + 16;
         buf = qemu_malloc(len);          buf = g_malloc(len);
         snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);          snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
         bus->name = buf;          bus->name = buf;
     } else {      } else {
         /* no id -> use lowercase bus type for bus name */          /* no id -> use lowercase bus type for bus name */
         len = strlen(info->name) + 16;          len = strlen(info->name) + 16;
         buf = qemu_malloc(len);          buf = g_malloc(len);
         len = snprintf(buf, len, "%s.%d", info->name,          len = snprintf(buf, len, "%s.%d", info->name,
                        parent ? parent->num_child_bus : 0);                         parent ? parent->num_child_bus : 0);
         for (i = 0; i < len; i++)          for (i = 0; i < len; i++)
Line 679  void qbus_create_inplace(BusState *bus,  Line 433  void qbus_create_inplace(BusState *bus, 
         bus->name = buf;          bus->name = buf;
     }      }
   
     QLIST_INIT(&bus->children);      QTAILQ_INIT(&bus->children);
     if (parent) {      if (parent) {
         QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);          QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
         parent->num_child_bus++;          parent->num_child_bus++;
       } else if (bus != main_system_bus) {
           /* TODO: once all bus devices are qdevified,
              only reset handler for main_system_bus should be registered here. */
           qemu_register_reset(qbus_reset_all_fn, bus);
     }      }
   
 }  }
   
 BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)  BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
 {  {
     BusState *bus;      BusState *bus;
   
     bus = qemu_mallocz(info->size);      bus = g_malloc0(info->size);
     bus->qdev_allocated = 1;      bus->qdev_allocated = 1;
     qbus_create_inplace(bus, info, parent, name);      qbus_create_inplace(bus, info, parent, name);
     return bus;      return bus;
 }  }
   
   static void main_system_bus_create(void)
   {
       /* assign main_system_bus before qbus_create_inplace()
        * in order to make "if (bus != main_system_bus)" work */
       main_system_bus = g_malloc0(system_bus_info.size);
       main_system_bus->qdev_allocated = 1;
       qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
                           "main-system-bus");
   }
   
 void qbus_free(BusState *bus)  void qbus_free(BusState *bus)
 {  {
     DeviceState *dev;      DeviceState *dev;
   
     while ((dev = QLIST_FIRST(&bus->children)) != NULL) {      while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
         qdev_free(dev);          qdev_free(dev);
     }      }
     if (bus->parent) {      if (bus->parent) {
         QLIST_REMOVE(bus, sibling);          QLIST_REMOVE(bus, sibling);
         bus->parent->num_child_bus--;          bus->parent->num_child_bus--;
       } else {
           assert(bus != main_system_bus); /* main_system_bus is never freed */
           qemu_unregister_reset(qbus_reset_all_fn, bus);
     }      }
     qemu_free((void*)bus->name);      g_free((void*)bus->name);
     if (bus->qdev_allocated) {      if (bus->qdev_allocated) {
         qemu_free(bus);          g_free(bus);
     }      }
 }  }
   
 #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)  static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
 static void qbus_print(Monitor *mon, BusState *bus, int indent);  
   
 static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,  
                              const char *prefix, int indent)  
 {  {
     char buf[64];      int l = 0;
   
     if (!props)      if (dev && dev->parent_bus) {
         return;          char *d;
     while (props->name) {          l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
         /*          if (dev->parent_bus->info->get_fw_dev_path) {
          * TODO Properties without a print method are just for dirty              d = dev->parent_bus->info->get_fw_dev_path(dev);
          * hacks.  qdev_prop_ptr is the only such PropertyInfo.  It's              l += snprintf(p + l, size - l, "%s", d);
          * marked for removal.  The test props->info->print should be              g_free(d);
          * removed along with it.          } else {
          */              l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
         if (props->info->print) {  
             props->info->print(dev, props, buf, sizeof(buf));  
             qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);  
         }          }
         props++;  
     }      }
       l += snprintf(p + l , size - l, "/");
   
       return l;
 }  }
   
 static void qdev_print(Monitor *mon, DeviceState *dev, int indent)  char* qdev_get_fw_dev_path(DeviceState *dev)
 {  {
     BusState *child;      char path[128];
     qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,      int l;
                 dev->id ? dev->id : "");  
     indent += 2;      l = qdev_get_fw_dev_path_helper(dev, path, 128);
     if (dev->num_gpio_in) {  
         qdev_printf("gpio-in %d\n", dev->num_gpio_in);      path[l-1] = '\0';
   
       return strdup(path);
   }
   
   static char *qdev_get_type(Object *obj, Error **errp)
   {
       return g_strdup(object_get_typename(obj));
   }
   
   /**
    * Legacy property handling
    */
   
   static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
                                        const char *name, Error **errp)
   {
       DeviceState *dev = DEVICE(obj);
       Property *prop = opaque;
   
       char buffer[1024];
       char *ptr = buffer;
   
       prop->info->print(dev, prop, buffer, sizeof(buffer));
       visit_type_str(v, &ptr, name, errp);
   }
   
   static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
                                        const char *name, Error **errp)
   {
       DeviceState *dev = DEVICE(obj);
       Property *prop = opaque;
       Error *local_err = NULL;
       char *ptr = NULL;
       int ret;
   
       if (dev->state != DEV_STATE_CREATED) {
           error_set(errp, QERR_PERMISSION_DENIED);
           return;
     }      }
     if (dev->num_gpio_out) {  
         qdev_printf("gpio-out %d\n", dev->num_gpio_out);      visit_type_str(v, &ptr, name, &local_err);
       if (local_err) {
           error_propagate(errp, local_err);
           return;
     }      }
     qdev_print_props(mon, dev, dev->info->props, "dev", indent);  
     qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);      ret = prop->info->parse(dev, prop, ptr);
     if (dev->parent_bus->info->print_dev)      error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
         dev->parent_bus->info->print_dev(mon, dev, indent);      g_free(ptr);
     QLIST_FOREACH(child, &dev->child_bus, sibling) {  }
         qbus_print(mon, child, indent);  
   /**
    * @qdev_add_legacy_property - adds a legacy property
    *
    * Do not use this is new code!  Properties added through this interface will
    * be given names and types in the "legacy" namespace.
    *
    * Legacy properties are string versions of other OOM properties.  The format
    * of the string depends on the property type.
    */
   void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                                 Error **errp)
   {
       gchar *name, *type;
   
       /* Register pointer properties as legacy properties */
       if (!prop->info->print && !prop->info->parse &&
           (prop->info->set || prop->info->get)) {
           return;
     }      }
 }  
   
 static void qbus_print(Monitor *mon, BusState *bus, int indent)      name = g_strdup_printf("legacy-%s", prop->name);
       type = g_strdup_printf("legacy<%s>",
                              prop->info->legacy_name ?: prop->info->name);
   
       object_property_add(OBJECT(dev), name, type,
                           prop->info->print ? qdev_get_legacy_property : prop->info->get,
                           prop->info->parse ? qdev_set_legacy_property : prop->info->set,
                           NULL,
                           prop, errp);
   
       g_free(type);
       g_free(name);
   }
   
   /**
    * @qdev_property_add_static - add a @Property to a device.
    *
    * Static properties access data in a struct.  The actual type of the
    * property and the field depends on the property type.
    */
   void qdev_property_add_static(DeviceState *dev, Property *prop,
                                 Error **errp)
 {  {
     struct DeviceState *dev;      /*
        * TODO qdev_prop_ptr does not have getters or setters.  It must
     qdev_printf("bus: %s\n", bus->name);       * go now that it can be replaced with links.  The test should be
     indent += 2;       * removed along with it: all static properties are read/write.
     qdev_printf("type %s\n", bus->info->name);       */
     QLIST_FOREACH(dev, &bus->children, sibling) {      if (!prop->info->get && !prop->info->set) {
         qdev_print(mon, dev, indent);          return;
     }      }
   
       object_property_add(OBJECT(dev), prop->name, prop->info->name,
                           prop->info->get, prop->info->set,
                           prop->info->release,
                           prop, errp);
 }  }
 #undef qdev_printf  
   
 void do_info_qtree(Monitor *mon)  static void device_initfn(Object *obj)
 {  {
     if (main_system_bus)      DeviceState *dev = DEVICE(obj);
         qbus_print(mon, main_system_bus, 0);      Property *prop;
   
       if (qdev_hotplug) {
           dev->hotplugged = 1;
           qdev_hot_added = true;
       }
   
       dev->instance_id_alias = -1;
       dev->state = DEV_STATE_CREATED;
   
       for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
           qdev_property_add_legacy(dev, prop, NULL);
           qdev_property_add_static(dev, prop, NULL);
       }
   
       object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
       qdev_prop_set_defaults(dev, qdev_get_props(dev));
 }  }
   
 void do_info_qdm(Monitor *mon)  /* Unlink device from bus and free the structure.  */
   static void device_finalize(Object *obj)
 {  {
     DeviceInfo *info;      DeviceState *dev = DEVICE(obj);
       BusState *bus;
       DeviceClass *dc = DEVICE_GET_CLASS(dev);
   
     for (info = device_info_list; info != NULL; info = info->next) {      if (dev->state == DEV_STATE_INITIALIZED) {
         qdev_print_devinfo(info);          while (dev->num_child_bus) {
               bus = QLIST_FIRST(&dev->child_bus);
               qbus_free(bus);
           }
           if (qdev_get_vmsd(dev)) {
               vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
           }
           if (dc->exit) {
               dc->exit(dev);
           }
           if (dev->opts) {
               qemu_opts_del(dev->opts);
           }
     }      }
       QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
 }  }
   
 int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)  void device_reset(DeviceState *dev)
 {  {
     QemuOpts *opts;      DeviceClass *klass = DEVICE_GET_CLASS(dev);
   
     opts = qemu_opts_from_qdict(&qemu_device_opts, qdict);      if (klass->reset) {
     if (!opts) {          klass->reset(dev);
         return -1;  
     }  
     if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {  
         qemu_opts_del(opts);  
         return 0;  
     }      }
     if (!qdev_device_add(opts)) {  
         qemu_opts_del(opts);  
         return -1;  
     }  
     return 0;  
 }  }
   
 int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)  Object *qdev_get_machine(void)
 {  {
     const char *id = qdict_get_str(qdict, "id");      static Object *dev;
     DeviceState *dev;  
   
     dev = qdev_find_recursive(main_system_bus, id);      if (dev == NULL) {
     if (NULL == dev) {          dev = container_get(object_get_root(), "/machine");
         qerror_report(QERR_DEVICE_NOT_FOUND, id);  
         return -1;  
     }      }
     return qdev_unplug(dev);  
       return dev;
   }
   
   static TypeInfo device_type_info = {
       .name = TYPE_DEVICE,
       .parent = TYPE_OBJECT,
       .instance_size = sizeof(DeviceState),
       .instance_init = device_initfn,
       .instance_finalize = device_finalize,
       .abstract = true,
       .class_size = sizeof(DeviceClass),
   };
   
   static void qdev_register_types(void)
   {
       type_register_static(&device_type_info);
 }  }
   
   type_init(qdev_register_types)

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.7


unix.superglobalmegacorp.com