您的位置:首页 > 运维架构 > Linux

Linux Kernel设备驱动模型之 设备添加

2017-03-12 12:21 246 查看
对于设备模型来说,设备添加是向设备模型层添加一个设备。


/**
 * device_add - add device to device hierarchy.
 * @dev: device.
 *
 * This is part 2 of device_register(), though may be called
 * separately _iff_ device_initialize() has been called separately.
 *
 * This adds @dev to the kobject hierarchy via kobject_add(), adds it
 * to the global and sibling lists for the device, then
 * adds it to the other relevant subsystems of the driver model.
 *
 * Do not call this routine or device_register() more than once for
 * any device structure.  The driver model core is not designed to work
 * with devices that get unregistered and then spring back to life.
 * (Among other things, it's very hard to guarantee that all references
 * to the previous incarnation of @dev have been dropped.)  Allocate
 * and register a fresh new struct device instead.
 *
 * NOTE: _Never_ directly free @dev after calling this function, even
 * if it returned an error! Always use put_device() to give up your
 * reference instead.
 */
int device_add(struct device *dev)
{
 struct device *parent = NULL;
 struct kobject *kobj;
 struct class_interface *class_intf;
 int error = -EINVAL;
 struct kobject *glue_dir = NULL;
 dev = get_device(dev);
 if (!dev)
  goto done;
 if (!dev->p) {
  error = device_private_init(dev);
  if (error)
   goto done;
 }
 /*
  * for statically allocated devices, which should all be converted
  * some day, we need to initialize the name. We prevent reading back
  * the name, and force the use of dev_name()
  */
 if (dev->init_name) {
  dev_set_name(dev, "%s", dev->init_name);
  dev->init_name = NULL;
 }
 /* subsystems can specify simple device enumeration */
 if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
  dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
 if (!dev_name(dev)) {
  error = -EINVAL;
  goto name_error;
 }
 pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
 parent = get_device(dev->parent);
 kobj = get_device_parent(dev, parent);
 if (kobj)
  dev->kobj.parent = kobj;
 /* use parent numa_node */
 if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
  set_dev_node(dev, dev_to_node(parent));
 /* first, register with generic layer. */
 /* we require the name to be set before, and pass NULL */
 error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
 if (error) {
  glue_dir = get_glue_dir(dev);
  goto Error;
 }
 /* notify platform of device entry */
 if (platform_notify)
  platform_notify(dev);
 error = device_create_file(dev, &dev_attr_uevent);
 if (error)
  goto attrError;
 error = device_add_class_symlinks(dev);
 if (error)
  goto SymlinkError;
 error = device_add_attrs(dev);
 if (error)
  goto AttrsError;
 error = bus_add_device(dev);
 if (error)
  goto BusError;
 error = dpm_sysfs_add(dev);
 if (error)
  goto DPMError;
 device_pm_add(dev);
 if (MAJOR(dev->devt)) {
  error = device_create_file(dev, &dev_attr_dev);
  if (error)
   goto DevAttrError;
  error = device_create_sys_dev_entry(dev);
  if (error)
   goto SysEntryError;
  devtmpfs_create_node(dev);
 }
 /* Notify clients of device addition.  This call must come
  * after dpm_sysfs_add() and before kobject_uevent().
  */
 if (dev->bus)
  blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
          BUS_NOTIFY_ADD_DEVICE, dev);
 kobject_uevent(&dev->kobj, KOBJ_ADD);
 bus_probe_device(dev);
 if (parent)
  klist_add_tail(&dev->p->knode_parent,
          &parent->p->klist_children);
 if (dev->class) {
  mutex_lock(&dev->class->p->mutex);
  /* tie the class to the device */
  klist_add_tail(&dev->knode_class,
          &dev->class->p->klist_devices);
  /* notify any interfaces that the device is here */
  list_for_each_entry(class_intf,
        &dev->class->p->interfaces, node)
   if (class_intf->add_dev)
    class_intf->add_dev(dev, class_intf);
  mutex_unlock(&dev->class->p->mutex);
 }
done:
 put_device(dev);
 return error;
 SysEntryError:
 if (MAJOR(dev->devt))
  device_remove_file(dev, &dev_attr_dev);
 DevAttrError:
 device_pm_remove(dev);
 dpm_sysfs_remove(dev);
 DPMError:
 bus_remove_device(dev);
 BusError:
 device_remove_attrs(dev);
 AttrsError:
 device_remove_class_symlinks(dev);
 SymlinkError:
 device_remove_file(dev, &dev_attr_uevent);
 attrError:
 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 glue_dir = get_glue_dir(dev);
 kobject_del(&dev->kobj);
 Error:
 cleanup_glue_dir(dev, glue_dir);
 put_device(parent);
name_error:
 kfree(dev->p);
 dev->p = NULL;
 goto done;
}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: