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

version 1.1.1.3, 2018/04/24 18:28:31 version 1.1.1.6, 2018/04/24 19:27:28
Line 31 Line 31
 #include "monitor.h"  #include "monitor.h"
   
 static int qdev_hotplug = 0;  static 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;  DeviceInfo *device_info_list;
   
Line 82  static DeviceState *qdev_create_from_inf Line 85  static DeviceState *qdev_create_from_inf
     DeviceState *dev;      DeviceState *dev;
   
     assert(bus->info == info->bus_info);      assert(bus->info == info->bus_info);
     dev = qemu_mallocz(info->size);      dev = g_malloc0(info->size);
     dev->info = info;      dev->info = info;
     dev->parent_bus = bus;      dev->parent_bus = bus;
     qdev_prop_set_defaults(dev, dev->info->props);      qdev_prop_set_defaults(dev, dev->info->props);
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);      qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
     qdev_prop_set_globals(dev);      qdev_prop_set_globals(dev);
     QLIST_INSERT_HEAD(&bus->children, dev, sibling);      QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
     if (qdev_hotplug) {      if (qdev_hotplug) {
         assert(bus->allow_hotplug);          assert(bus->allow_hotplug);
         dev->hotplugged = 1;          dev->hotplugged = 1;
           qdev_hot_added = true;
     }      }
     dev->instance_id_alias = -1;      dev->instance_id_alias = -1;
     dev->state = DEV_STATE_CREATED;      dev->state = DEV_STATE_CREATED;
Line 103  static DeviceState *qdev_create_from_inf Line 107  static DeviceState *qdev_create_from_inf
    initialize the actual device emulation.  */     initialize the actual device emulation.  */
 DeviceState *qdev_create(BusState *bus, const char *name)  DeviceState *qdev_create(BusState *bus, const char *name)
 {  {
       DeviceState *dev;
   
       dev = qdev_try_create(bus, name);
       if (!dev) {
           if (bus) {
               hw_error("Unknown device '%s' for bus '%s'\n", name,
                        bus->info->name);
           } else {
               hw_error("Unknown device '%s' for default sysbus\n", name);
           }
       }
   
       return dev;
   }
   
   DeviceState *qdev_try_create(BusState *bus, const char *name)
   {
     DeviceInfo *info;      DeviceInfo *info;
   
     if (!bus) {      if (!bus) {
         if (!main_system_bus) {          bus = sysbus_get_default();
             main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");  
         }  
         bus = main_system_bus;  
     }      }
   
     info = qdev_find_info(bus->info, name);      info = qdev_find_info(bus->info, name);
     if (!info) {      if (!info) {
         hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);          return NULL;
     }      }
   
     return qdev_create_from_info(bus, info);      return qdev_create_from_info(bus, info);
Line 168  int qdev_device_help(QemuOpts *opts) Line 186  int qdev_device_help(QemuOpts *opts)
         return 1;          return 1;
     }      }
   
     if (!qemu_opt_get(opts, "?")) {      if (!driver || !qemu_opt_get(opts, "?")) {
         return 0;          return 0;
     }      }
   
Line 189  int qdev_device_help(QemuOpts *opts) Line 207  int qdev_device_help(QemuOpts *opts)
         }          }
         error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);          error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
     }      }
       for (prop = info->bus_info->props; prop && prop->name; prop++) {
           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 1;
 }  }
   
Line 256  DeviceState *qdev_device_add(QemuOpts *o Line 280  DeviceState *qdev_device_add(QemuOpts *o
     return qdev;      return qdev;
 }  }
   
 static void qdev_reset(void *opaque)  
 {  
     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
    this function.  IRQs and MMIO regions should be connected/mapped after     this function.  IRQs and MMIO regions should be connected/mapped after
    calling this function.     calling this function.
Line 278  int qdev_init(DeviceState *dev) Line 295  int qdev_init(DeviceState *dev)
         qdev_free(dev);          qdev_free(dev);
         return rc;          return rc;
     }      }
     qemu_register_reset(qdev_reset, dev);  
     if (dev->info->vmsd) {      if (dev->info->vmsd) {
         vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,          vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, 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 && dev->info->reset) {
           dev->info->reset(dev);
       }
     return 0;      return 0;
 }  }
   
Line 304  int qdev_unplug(DeviceState *dev) Line 323  int qdev_unplug(DeviceState *dev)
     }      }
     assert(dev->info->unplug != NULL);      assert(dev->info->unplug != NULL);
   
       qdev_hot_removed = true;
   
     return dev->info->unplug(dev);      return dev->info->unplug(dev);
 }  }
   
   static int qdev_reset_one(DeviceState *dev, void *opaque)
   {
       if (dev->info->reset) {
           dev->info->reset(dev);
       }
   
       return 0;
   }
   
   BusState *sysbus_get_default(void)
   {
       if (!main_system_bus) {
           main_system_bus_create();
       }
       return main_system_bus;
   }
   
   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)
 {  {
Line 315  int qdev_simple_unplug_cb(DeviceState *d Line 372  int qdev_simple_unplug_cb(DeviceState *d
     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 327  void qdev_init_nofail(DeviceState *dev) Line 385  void qdev_init_nofail(DeviceState *dev)
     DeviceInfo *info = dev->info;      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", info->name);
         exit(1);          exit(1);
     }      }
 }  }
Line 350  void qdev_free(DeviceState *dev) Line 408  void qdev_free(DeviceState *dev)
         if (dev->opts)          if (dev->opts)
             qemu_opts_del(dev->opts);              qemu_opts_del(dev->opts);
     }      }
     qemu_unregister_reset(qdev_reset, dev);      QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
     QLIST_REMOVE(dev, sibling);  
     for (prop = dev->info->props; prop && prop->name; prop++) {      for (prop = dev->info->props; prop && prop->name; prop++) {
         if (prop->info->free) {          if (prop->info->free) {
             prop->info->free(dev, prop);              prop->info->free(dev, prop);
         }          }
     }      }
     qemu_free(dev);      g_free(dev);
 }  }
   
 void qdev_machine_creation_done(void)  void qdev_machine_creation_done(void)
Line 369  void qdev_machine_creation_done(void) Line 426  void qdev_machine_creation_done(void)
     qdev_hotplug = 1;      qdev_hotplug = 1;
 }  }
   
   bool qdev_machine_modified(void)
   {
       return qdev_hot_added || qdev_hot_removed;
   }
   
 /* Get a character (serial) device interface.  */  /* Get a character (serial) device interface.  */
 CharDriverState *qdev_init_chardev(DeviceState *dev)  CharDriverState *qdev_init_chardev(DeviceState *dev)
 {  {
Line 411  void qdev_connect_gpio_out(DeviceState * Line 473  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 482  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];  BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
   {
       BusState *bus;
   
       QLIST_FOREACH(bus, &dev->child_bus, sibling) {
           if (strcmp(name, bus->name) == 0) {
               return bus;
           }
       }
       return NULL;
   }
   
 /* Get a block device.  This should only be used for single-drive devices  int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
    (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the                         qbus_walkerfn *busfn, void *opaque)
    appropriate bus.  */  
 BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)  
 {  {
     int unit = next_block_unit[type]++;      DeviceState *dev;
     DriveInfo *dinfo;      int err;
   
       if (busfn) {
           err = busfn(bus, opaque);
           if (err) {
               return err;
           }
       }
   
       QTAILQ_FOREACH(dev, &bus->children, sibling) {
           err = qdev_walk_children(dev, devfn, busfn, opaque);
           if (err < 0) {
               return err;
           }
       }
   
     dinfo = drive_get(type, 0, unit);      return 0;
     return dinfo ? dinfo->bdrv : NULL;  
 }  }
   
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)  int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
                          qbus_walkerfn *busfn, void *opaque)
 {  {
     BusState *bus;      BusState *bus;
       int err;
   
       if (devfn) {
           err = devfn(dev, opaque);
           if (err) {
               return err;
           }
       }
   
     QLIST_FOREACH(bus, &dev->child_bus, sibling) {      QLIST_FOREACH(bus, &dev->child_bus, sibling) {
         if (strcmp(name, bus->name) == 0) {          err = qbus_walk_children(bus, devfn, busfn, opaque);
             return bus;          if (err < 0) {
               return err;
         }          }
     }      }
     return NULL;  
       return 0;
 }  }
   
 static BusState *qbus_find_recursive(BusState *bus, const char *name,  static BusState *qbus_find_recursive(BusState *bus, const char *name,
Line 465  static BusState *qbus_find_recursive(Bus Line 560  static BusState *qbus_find_recursive(Bus
         return bus;          return bus;
     }      }
   
     QLIST_FOREACH(dev, &bus->children, sibling) {      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         QLIST_FOREACH(child, &dev->child_bus, sibling) {          QLIST_FOREACH(child, &dev->child_bus, sibling) {
             ret = qbus_find_recursive(child, name, info);              ret = qbus_find_recursive(child, name, info);
             if (ret) {              if (ret) {
Line 476  static BusState *qbus_find_recursive(Bus Line 571  static BusState *qbus_find_recursive(Bus
     return NULL;      return NULL;
 }  }
   
 static DeviceState *qdev_find_recursive(BusState *bus, const char *id)  DeviceState *qdev_find_recursive(BusState *bus, const char *id)
 {  {
     DeviceState *dev, *ret;      DeviceState *dev, *ret;
     BusState *child;      BusState *child;
   
     QLIST_FOREACH(dev, &bus->children, sibling) {      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->id && strcmp(dev->id, id) == 0)          if (dev->id && strcmp(dev->id, id) == 0)
             return dev;              return dev;
         QLIST_FOREACH(child, &dev->child_bus, sibling) {          QLIST_FOREACH(child, &dev->child_bus, sibling) {
Line 514  static void qbus_list_dev(BusState *bus) Line 609  static void qbus_list_dev(BusState *bus)
     const char *sep = " ";      const char *sep = " ";
   
     error_printf("devices at \"%s\":", bus->name);      error_printf("devices at \"%s\":", bus->name);
     QLIST_FOREACH(dev, &bus->children, sibling) {      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         error_printf("%s\"%s\"", sep, dev->info->name);          error_printf("%s\"%s\"", sep, dev->info->name);
         if (dev->id)          if (dev->id)
             error_printf("/\"%s\"", dev->id);              error_printf("/\"%s\"", dev->id);
Line 545  static DeviceState *qbus_find_dev(BusSta Line 640  static DeviceState *qbus_find_dev(BusSta
      *   (2) driver name       *   (2) driver name
      *   (3) driver alias, if present       *   (3) driver alias, if present
      */       */
     QLIST_FOREACH(dev, &bus->children, sibling) {      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->id  &&  strcmp(dev->id, elem) == 0) {          if (dev->id  &&  strcmp(dev->id, elem) == 0) {
             return dev;              return dev;
         }          }
     }      }
     QLIST_FOREACH(dev, &bus->children, sibling) {      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (strcmp(dev->info->name, elem) == 0) {          if (strcmp(dev->info->name, elem) == 0) {
             return dev;              return dev;
         }          }
     }      }
     QLIST_FOREACH(dev, &bus->children, sibling) {      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {          if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
             return dev;              return dev;
         }          }
Line 661  void qbus_create_inplace(BusState *bus,  Line 756  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 774  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);
     }      }
 }  }
   
Line 767  static void qbus_print(Monitor *mon, Bus Line 878  static void qbus_print(Monitor *mon, Bus
     qdev_printf("bus: %s\n", bus->name);      qdev_printf("bus: %s\n", bus->name);
     indent += 2;      indent += 2;
     qdev_printf("type %s\n", bus->info->name);      qdev_printf("type %s\n", bus->info->name);
     QLIST_FOREACH(dev, &bus->children, sibling) {      QTAILQ_FOREACH(dev, &bus->children, sibling) {
         qdev_print(mon, dev, indent);          qdev_print(mon, dev, indent);
     }      }
 }  }
Line 792  int do_device_add(Monitor *mon, const QD Line 903  int do_device_add(Monitor *mon, const QD
 {  {
     QemuOpts *opts;      QemuOpts *opts;
   
     opts = qemu_opts_from_qdict(&qemu_device_opts, qdict);      opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
     if (!opts) {      if (!opts) {
         return -1;          return -1;
     }      }
Line 819  int do_device_del(Monitor *mon, const QD Line 930  int do_device_del(Monitor *mon, const QD
     }      }
     return qdev_unplug(dev);      return qdev_unplug(dev);
 }  }
   
   static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
   {
       int l = 0;
   
       if (dev && dev->parent_bus) {
           char *d;
           l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
           if (dev->parent_bus->info->get_fw_dev_path) {
               d = dev->parent_bus->info->get_fw_dev_path(dev);
               l += snprintf(p + l, size - l, "%s", d);
               g_free(d);
           } else {
               l += snprintf(p + l, size - l, "%s", dev->info->name);
           }
       }
       l += snprintf(p + l , size - l, "/");
   
       return l;
   }
   
   char* qdev_get_fw_dev_path(DeviceState *dev)
   {
       char path[128];
       int l;
   
       l = qdev_get_fw_dev_path_helper(dev, path, 128);
   
       path[l-1] = '\0';
   
       return strdup(path);
   }

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


unix.superglobalmegacorp.com