Diff for /qemu/hw/qdev.c between versions 1.1.1.1 and 1.1.1.5

version 1.1.1.1, 2018/04/24 17:23:47 version 1.1.1.5, 2018/04/24 18:59:52
Line 30 Line 30
 #include "sysemu.h"  #include "sysemu.h"
 #include "monitor.h"  #include "monitor.h"
   
   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 DeviceInfo *device_info_list;  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)  void qdev_register(DeviceInfo *info)
Line 71  static DeviceInfo *qdev_find_info(BusInf Line 79  static DeviceInfo *qdev_find_info(BusInf
     return NULL;      return NULL;
 }  }
   
   static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
   {
       DeviceState *dev;
   
       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;
           qdev_hot_added = true;
       }
       dev->instance_id_alias = -1;
       dev->state = DEV_STATE_CREATED;
       return dev;
   }
   
 /* Create a new device.  This only initializes the device state structure  /* Create a new device.  This only initializes the device state structure
    and allows properties to be set.  qdev_init should be called to     and allows properties to be set.  qdev_init should be called to
    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)
 {  {
     DeviceInfo *info;  
     DeviceState *dev;      DeviceState *dev;
   
       dev = qdev_try_create(bus, name);
       if (!dev) {
           hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name);
       }
   
       return dev;
   }
   
   DeviceState *qdev_try_create(BusState *bus, const char *name)
   {
       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;
     }      }
   
     dev = qemu_mallocz(info->size);      return qdev_create_from_info(bus, info);
     dev->info = info;  }
     dev->parent_bus = bus;  
     qdev_prop_set_defaults(dev, dev->info->props);  static void qdev_print_devinfo(DeviceInfo *info)
     qdev_prop_set_defaults(dev, dev->parent_bus->info->props);  {
     qdev_prop_set_compat(dev);      error_printf("name \"%s\", bus %s",
     LIST_INSERT_HEAD(&bus->children, dev, sibling);                   info->name, info->bus_info->name);
     return dev;      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)
   {
       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)
   {
       const char *driver;
       DeviceInfo *info;
       Property *prop;
   
       driver = qemu_opt_get(opts, "driver");
       if (driver && !strcmp(driver, "?")) {
           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, "?")) {
           return 0;
       }
   
       info = qdev_find_info(NULL, driver);
       if (!info) {
           return 0;
       }
   
       for (prop = info->props; prop && prop->name; prop++) {
           /*
            * TODO Properties without a parser are just for dirty hacks.
            * qdev_prop_ptr is the only such PropertyInfo.  It's marked
            * for removal.  This conditional should be removed along with
            * it.
            */
           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;
   }
   
   DeviceState *qdev_device_add(QemuOpts *opts)
   {
       const char *driver, *path, *id;
       DeviceInfo *info;
       DeviceState *qdev;
       BusState *bus;
   
       driver = qemu_opt_get(opts, "driver");
       if (!driver) {
           qerror_report(QERR_MISSING_PARAMETER, "driver");
           return NULL;
       }
   
       /* find driver */
       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;
       }
   
       /* find bus */
       path = qemu_opt_get(opts, "bus");
       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 = qdev_create_from_info(bus, info);
       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;
 }  }
   
 /* 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.
 void qdev_init(DeviceState *dev)     On failure, destroy the device and return negative value.
      Return 0 on success.  */
   int qdev_init(DeviceState *dev)
   {
       int rc;
   
       assert(dev->state == DEV_STATE_CREATED);
       rc = dev->info->init(dev, dev->info);
       if (rc < 0) {
           qdev_free(dev);
           return rc;
       }
       if (dev->info->vmsd) {
           vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
                                          dev->instance_id_alias,
                                          dev->alias_required_for_version);
       }
       dev->state = DEV_STATE_INITIALIZED;
       return 0;
   }
   
   void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
                                    int required_for_version)
   {
       assert(dev->state == DEV_STATE_CREATED);
       dev->instance_id_alias = alias_id;
       dev->alias_required_for_version = required_for_version;
   }
   
   int qdev_unplug(DeviceState *dev)
   {
       if (!dev->parent_bus->allow_hotplug) {
           qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
           return -1;
       }
       assert(dev->info->unplug != NULL);
   
       qdev_hot_removed = true;
   
       return dev->info->unplug(dev);
   }
   
   static int qdev_reset_one(DeviceState *dev, void *opaque)
 {  {
     dev->info->init(dev, dev->info);      if (dev->info->reset) {
           dev->info->reset(dev);
       }
   
       return 0;
   }
   
   BusState *sysbus_get_default(void)
   {
       if (!main_system_bus) {
           main_system_bus = qbus_create(&system_bus_info, NULL,
                                         "main-system-bus");
       }
       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 */
   int qdev_simple_unplug_cb(DeviceState *dev)
   {
       /* just zap it */
       qdev_free(dev);
       return 0;
   }
   
   
   /* Like qdev_init(), but terminate program via error_report() instead of
      returning an error value.  This is okay during machine creation.
      Don't use for hotplug, because there callers need to recover from
      failure.  Exception: if you know the device's init() callback can't
      fail, then qdev_init_nofail() can't fail either, and is therefore
      usable even then.  But relying on the device implementation that
      way is somewhat unclean, and best avoided.  */
   void qdev_init_nofail(DeviceState *dev)
   {
       DeviceInfo *info = dev->info;
   
       if (qdev_init(dev) < 0) {
           error_report("Initialization of device %s failed", info->name);
           exit(1);
       }
 }  }
   
 /* 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)
 {  {
     LIST_REMOVE(dev, sibling);      BusState *bus;
     qemu_free(dev->id);      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);
       }
       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);      qemu_free(dev);
 }  }
   
   void qdev_machine_creation_done(void)
   {
       /*
        * ok, initial machine setup is done, starting from now we can
        * only create hotpluggable devices
        */
       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)
 {  {
     static int next_serial;      static int next_serial;
     static int next_virtconsole;  
     /* FIXME: This is a nasty hack that needs to go away.  */      /* FIXME: This function needs to go away: use chardev properties!  */
     if (strncmp(dev->info->name, "virtio", 6) == 0) {      return serial_hds[next_serial++];
         return virtcon_hds[next_virtconsole++];  
     } else {  
         return serial_hds[next_serial++];  
     }  
 }  }
   
 BusState *qdev_get_parent_bus(DeviceState *dev)  BusState *qdev_get_parent_bus(DeviceState *dev)
Line 161  void qdev_connect_gpio_out(DeviceState * Line 457  void qdev_connect_gpio_out(DeviceState *
     dev->gpio_out[n] = pin;      dev->gpio_out[n] = pin;
 }  }
   
 VLANClientState *qdev_get_vlan_client(DeviceState *dev,  void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
                                       NetCanReceive *can_receive,  
                                       NetReceive *receive,  
                                       NetReceiveIOV *receive_iov,  
                                       NetCleanup *cleanup,  
                                       void *opaque)  
 {  {
     NICInfo *nd = dev->nd;      qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
     assert(nd);      if (nd->vlan)
     nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,          qdev_prop_set_vlan(dev, "vlan", nd->vlan);
                                   receive, receive_iov, cleanup, opaque);      if (nd->netdev)
     return nd->vc;          qdev_prop_set_netdev(dev, "netdev", nd->netdev);
       if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
           qdev_prop_exists(dev, "vectors")) {
           qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
       }
       nd->instantiated = 1;
 }  }
   
   BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
   {
       BusState *bus;
   
 void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)      QLIST_FOREACH(bus, &dev->child_bus, sibling) {
           if (strcmp(name, bus->name) == 0) {
               return bus;
           }
       }
       return NULL;
   }
   
   int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
                          qbus_walkerfn *busfn, void *opaque)
 {  {
     memcpy(macaddr, dev->nd->macaddr, 6);      DeviceState *dev;
       int err;
   
       if (busfn) {
           err = busfn(bus, opaque);
           if (err) {
               return err;
           }
       }
   
       QLIST_FOREACH(dev, &bus->children, sibling) {
           err = qdev_walk_children(dev, devfn, busfn, opaque);
           if (err < 0) {
               return err;
           }
       }
   
       return 0;
 }  }
   
 static int next_block_unit[IF_COUNT];  int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
                          qbus_walkerfn *busfn, void *opaque)
   {
       BusState *bus;
       int err;
   
       if (devfn) {
           err = devfn(dev, opaque);
           if (err) {
               return err;
           }
       }
   
 /* Get a block device.  This should only be used for single-drive devices      QLIST_FOREACH(bus, &dev->child_bus, sibling) {
    (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the          err = qbus_walk_children(bus, devfn, busfn, opaque);
    appropriate bus.  */          if (err < 0) {
 BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)              return err;
           }
       }
   
       return 0;
   }
   
   static BusState *qbus_find_recursive(BusState *bus, const char *name,
                                        const BusInfo *info)
 {  {
     int unit = next_block_unit[type]++;      DeviceState *dev;
     int index;      BusState *child, *ret;
       int match = 1;
   
     index = drive_get_index(type, 0, unit);      if (name && (strcmp(bus->name, name) != 0)) {
     if (index == -1) {          match = 0;
         return NULL;      }
       if (info && (bus->info != info)) {
           match = 0;
       }
       if (match) {
           return bus;
     }      }
     return drives_table[index].bdrv;  
       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;
 }  }
   
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)  DeviceState *qdev_find_recursive(BusState *bus, const char *id)
 {  {
     BusState *bus;      DeviceState *dev, *ret;
       BusState *child;
   
     LIST_FOREACH(bus, &dev->child_bus, sibling) {      QLIST_FOREACH(dev, &bus->children, sibling) {
         if (strcmp(name, bus->name) == 0) {          if (dev->id && strcmp(dev->id, id) == 0)
             return bus;              return dev;
           QLIST_FOREACH(child, &dev->child_bus, sibling) {
               ret = qdev_find_recursive(child, id);
               if (ret) {
                   return ret;
               }
         }          }
     }      }
     return NULL;      return NULL;
 }  }
   
 static int next_scsi_bus;  static void qbus_list_bus(DeviceState *dev)
   {
       BusState *child;
       const char *sep = " ";
   
 /* Create a scsi bus, and attach devices to it.  */      error_printf("child busses at \"%s\":",
 /* TODO: Actually create a scsi bus for hotplug to use.  */                   dev->id ? dev->id : dev->info->name);
 void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)      QLIST_FOREACH(child, &dev->child_bus, sibling) {
 {          error_printf("%s\"%s\"", sep, child->name);
    int bus = next_scsi_bus++;          sep = ", ";
    int unit;      }
    int index;      error_printf("\n");
   
    for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {  
        index = drive_get_index(IF_SCSI, bus, unit);  
        if (index == -1) {  
            continue;  
        }  
        attach(host, drives_table[index].bdrv, unit);  
    }  
 }  }
   
 BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)  static void qbus_list_dev(BusState *bus)
   {
       DeviceState *dev;
       const char *sep = " ";
   
       error_printf("devices at \"%s\":", bus->name);
       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)
 {  {
       BusState *child;
   
       QLIST_FOREACH(child, &dev->child_bus, sibling) {
           if (strcmp(child->name, elem) == 0) {
               return child;
           }
       }
       return NULL;
   }
   
   static DeviceState *qbus_find_dev(BusState *bus, char *elem)
   {
       DeviceState *dev;
   
       /*
        * 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;
   }
   
   static BusState *qbus_find(const char *path)
   {
       DeviceState *dev;
     BusState *bus;      BusState *bus;
       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 */
           if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
               assert(0);
               elem[0] = len = 0;
           }
           pos += len;
           bus = qbus_find_bus(dev, elem);
           if (!bus) {
               qerror_report(QERR_BUS_NOT_FOUND, elem);
               if (!monitor_cur_is_qmp()) {
                   qbus_list_bus(dev);
               }
               return NULL;
           }
       }
   }
   
   void qbus_create_inplace(BusState *bus, BusInfo *info,
                            DeviceState *parent, const char *name)
   {
       char *buf;
       int i,len;
   
     bus = qemu_mallocz(info->size);  
     bus->info = info;      bus->info = info;
     bus->parent = parent;      bus->parent = parent;
     bus->name = qemu_strdup(name);  
     LIST_INIT(&bus->children);      if (name) {
           /* use supplied name */
           bus->name = qemu_strdup(name);
       } else if (parent && parent->id) {
           /* parent device has id -> use it for bus name */
           len = strlen(parent->id) + 16;
           buf = qemu_malloc(len);
           snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
           bus->name = buf;
       } else {
           /* no id -> use lowercase bus type for bus name */
           len = strlen(info->name) + 16;
           buf = qemu_malloc(len);
           len = snprintf(buf, len, "%s.%d", info->name,
                          parent ? parent->num_child_bus : 0);
           for (i = 0; i < len; i++)
               buf[i] = qemu_tolower(buf[i]);
           bus->name = buf;
       }
   
       QLIST_INIT(&bus->children);
     if (parent) {      if (parent) {
         LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);          QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
           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 *bus;
   
       bus = qemu_mallocz(info->size);
       bus->qdev_allocated = 1;
       qbus_create_inplace(bus, info, parent, name);
     return bus;      return bus;
 }  }
   
   void qbus_free(BusState *bus)
   {
       DeviceState *dev;
   
       while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
           qdev_free(dev);
       }
       if (bus->parent) {
           QLIST_REMOVE(bus, sibling);
           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);
       if (bus->qdev_allocated) {
           qemu_free(bus);
       }
   }
   
 #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)  #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
 static void qbus_print(Monitor *mon, BusState *bus, int indent);  static void qbus_print(Monitor *mon, BusState *bus, int indent);
   
Line 255  static void qdev_print_props(Monitor *mo Line 812  static void qdev_print_props(Monitor *mo
     if (!props)      if (!props)
         return;          return;
     while (props->name) {      while (props->name) {
           /*
            * TODO Properties without a print method are just for dirty
            * hacks.  qdev_prop_ptr is the only such PropertyInfo.  It's
            * marked for removal.  The test props->info->print should be
            * removed along with it.
            */
         if (props->info->print) {          if (props->info->print) {
             props->info->print(dev, props, buf, sizeof(buf));              props->info->print(dev, props, buf, sizeof(buf));
             qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);              qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
Line 279  static void qdev_print(Monitor *mon, Dev Line 842  static void qdev_print(Monitor *mon, Dev
     qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);      qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
     if (dev->parent_bus->info->print_dev)      if (dev->parent_bus->info->print_dev)
         dev->parent_bus->info->print_dev(mon, dev, indent);          dev->parent_bus->info->print_dev(mon, dev, indent);
     LIST_FOREACH(child, &dev->child_bus, sibling) {      QLIST_FOREACH(child, &dev->child_bus, sibling) {
         qbus_print(mon, child, indent);          qbus_print(mon, child, indent);
     }      }
 }  }
Line 291  static void qbus_print(Monitor *mon, Bus Line 854  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);
     LIST_FOREACH(dev, &bus->children, sibling) {      QLIST_FOREACH(dev, &bus->children, sibling) {
         qdev_print(mon, dev, indent);          qdev_print(mon, dev, indent);
     }      }
 }  }
Line 302  void do_info_qtree(Monitor *mon) Line 865  void do_info_qtree(Monitor *mon)
     if (main_system_bus)      if (main_system_bus)
         qbus_print(mon, main_system_bus, 0);          qbus_print(mon, main_system_bus, 0);
 }  }
   
   void do_info_qdm(Monitor *mon)
   {
       DeviceInfo *info;
   
       for (info = device_info_list; info != NULL; info = info->next) {
           qdev_print_devinfo(info);
       }
   }
   
   int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
   {
       QemuOpts *opts;
   
       opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
       if (!opts) {
           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)
   {
       const char *id = qdict_get_str(qdict, "id");
       DeviceState *dev;
   
       dev = qdev_find_recursive(main_system_bus, id);
       if (NULL == dev) {
           qerror_report(QERR_DEVICE_NOT_FOUND, id);
           return -1;
       }
       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);
               qemu_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.1  
changed lines
  Added in v.1.1.1.5


unix.superglobalmegacorp.com