linux设备驱动模型 - device/bus/driver 流程分析



1.在linux驱动模型中,为了便于管理各种设备,我们把不同设备分别挂在他们对应的总线上,设备对应的驱动程序也在总线上找,这样就提出了deivce-bus-driver的模型,硬件上有许多设备总线,那么我们就在设备模型上抽象出bus概念,相应的device就代表设备,driver表示驱动,在代码中它们对应的结构体下面介绍,对于实际的设备及总线,这些结构体就可以嵌入到实际总线上。

1.  bus 结构体分析  基于Linux 3.7 x 内核分析

struct bus_type {
 const char  *name;    //总线名称
 const char  *dev_name;
 struct device  *dev_root;
 struct bus_attribute *bus_attrs;
 struct device_attribute *dev_attrs;
 struct driver_attribute *drv_attrs;

 int (*match)(struct device *dev, struct device_driver *drv);
 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
 int (*probe)(struct device *dev);
 int (*remove)(struct device *dev);
 void (*shutdown)(struct device *dev);

 int (*suspend)(struct device *dev, pm_message_t state);
 int (*resume)(struct device *dev);

 const struct dev_pm_ops *pm;

 struct iommu_ops *iommu_ops;

}

注册接口bus_register(subsys)

注销接口 bus_unregister(struct bus_type *bus);

2.  struct device  //设备

 struct device {
 struct device  *parent;

 struct device_private *p;

 struct kobject kobj;
 const char  *init_name; /* initial name of the device */
 const struct device_type *type;

 struct mutex  mutex; /* mutex to synchronize calls to
      * its driver.
      */

 struct bus_type *bus;  /* type of bus device is on */
 struct device_driver *driver; /* which driver has allocated this
        device */
 void  *platform_data; /* Platform specific data, device
        core doesn't touch it */
 struct dev_pm_info power;
 struct dev_pm_domain *pm_domain;

#ifdef CONFIG_NUMA
 int  numa_node; /* NUMA node this device is close to */
#endif
 u64  *dma_mask; /* dma mask (if dma'able device) */
 u64  coherent_dma_mask;/* Like dma_mask, but for
          alloc_coherent mappings as
          not all hardware supports
          64 bit addresses for consistent
          allocations such descriptors. */

 struct device_dma_parameters *dma_parms;

 struct list_head dma_pools; /* dma pools (if dma'ble) */

 struct dma_coherent_mem *dma_mem; /* internal for coherent mem
          override */
 /* arch specific additions */
 struct dev_archdata archdata;

 struct device_node *of_node; /* associated device tree node */

 dev_t   devt; /* dev_t, creates the sysfs "dev" */
 u32   id; /* device instance */

 spinlock_t  devres_lock;
 struct list_head devres_head;

 struct klist_node knode_class;
 struct class  *class;
 const struct attribute_group **groups; /* optional groups */

 void (*release)(struct device *dev);
};

接口 :device_register(struct device *dev);
           device_unregister(struct device *dev);

device的注册函数device_register分两步,先初始化device_initialize,主要是初始化所属的kset为/sys/devices目录,及其他(如PM相关),然后再注册,函数为device_add .具体device如何匹配到对应的driver在函数__device_attach中进行,加入开始device没有driver,那么会在bus中找到对应的driver

看看device_register函数实现

int device_register(struct device *dev)
{
 device_initialize(dev);
 return device_add(dev);
}

int device_add(struct device *dev)
{
 struct device *parent = NULL;
 struct kobject *kobj;
 struct class_interface *class_intf;
 int error = -EINVAL;

 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)
  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)
  goto Error;

 /* notify platform of device entry */
 if (platform_notify)
  platform_notify(dev);

 error = device_create_file(dev, &uevent_attr);
 if (error)
  goto attrError;

 if (MAJOR(dev->devt)) {
  error = device_create_file(dev, &devt_attr);
  if (error)
   goto ueventattrError;

  error = device_create_sys_dev_entry(dev);
  if (error)
   goto devtattrError;

  devtmpfs_create_node(dev);
 }

 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);

 /* 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);       ///***********************************进入函数@cyl
 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;
 DPMError:
 bus_remove_device(dev);
 BusError:
 device_remove_attrs(dev);
 AttrsError:
 device_remove_class_symlinks(dev);
 SymlinkError:
 if (MAJOR(dev->devt))
  devtmpfs_delete_node(dev);
 if (MAJOR(dev->devt))
  device_remove_sys_dev_entry(dev);
 devtattrError:
 if (MAJOR(dev->devt))
  device_remove_file(dev, &devt_attr);
 ueventattrError:
 device_remove_file(dev, &uevent_attr);
 attrError:
 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 kobject_del(&dev->kobj);
 Error:
 cleanup_device_parent(dev);
 if (parent)
  put_device(parent);
name_error:
 kfree(dev->p);
 dev->p = NULL;
 goto done;
}

void bus_probe_device(struct device *dev)
{
 struct bus_type *bus = dev->bus;
 struct subsys_interface *sif;
 int ret;

 if (!bus)
  return;

 if (bus->p->drivers_autoprobe) {
  ret = device_attach(dev);               ///进入device——attch 函数@cyl
  WARN_ON(ret < 0);
 }

 mutex_lock(&bus->p->mutex);
 list_for_each_entry(sif, &bus->p->interfaces, node)
  if (sif->add_dev)
   sif->add_dev(dev, sif);
 mutex_unlock(&bus->p->mutex);
}

int device_attach(struct device *dev)
{
 int ret = 0;

 device_lock(dev);
 if (dev->driver) {
  if (klist_node_attached(&dev->p->knode_driver)) {
   ret = 1;
   goto out_unlock;
  }
  ret = device_bind_driver(dev);
  if (ret == 0)
   ret = 1;
  else {
   dev->driver = NULL;
   ret = 0;
  }
 } else {
  pm_runtime_get_noresume(dev);
  ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);     // _device_attach 函数
  pm_runtime_put_sync(dev);
 }
out_unlock:
 device_unlock(dev);
 return ret;
}

static int __device_attach(struct device_driver *drv, void *data)
{
 struct device *dev = data;

 if (!driver_match_device(drv, dev))   //  调用总线bus match 函数
  return 0;

 return driver_probe_device(drv, dev);   // 调用driver probe 函数
}

3. struct device_driver   // device_driver 函数

struct device_driver {
 const char  *name;
 struct bus_type  *bus;

 struct module  *owner;
 const char  *mod_name; /* used for built-in modules */

 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */

 const struct of_device_id *of_match_table;

 int (*probe) (struct device *dev);
 int (*remove) (struct device *dev);
 void (*shutdown) (struct device *dev);
 int (*suspend) (struct device *dev, pm_message_t state);
 int (*resume) (struct device *dev);
 const struct attribute_group **groups;

 const struct dev_pm_ops *pm;

 struct driver_private *p;
};

相关接口driver_register(struct device_driver *drv);
             driver_unregister(struct device_driver *drv);

那 么驱动是如何匹配到对应的device的,我们分析发现__driver_attach函数进行匹配,接下来我们一起分析注册流程

int driver_register(struct device_driver *drv)
{
 int ret;
 struct device_driver *other;

 BUG_ON(!drv->bus->p);

 if ((drv->bus->probe && drv->probe) ||
     (drv->bus->remove && drv->remove) ||
     (drv->bus->shutdown && drv->shutdown))
  printk(KERN_WARNING "Driver '%s' needs updating - please use "
   "bus_type methods\n", drv->name);

 other = driver_find(drv->name, drv->bus);
 if (other) {
  printk(KERN_ERR "Error: Driver '%s' is already registered, "
   "aborting...\n", drv->name);
  return -EBUSY;
 }

 ret = bus_add_driver(drv);       // 驱动添加@cyl
 if (ret)
  return ret;
 ret = driver_add_groups(drv, drv->groups);
 if (ret)
  bus_remove_driver(drv);
 return ret;
}

int bus_add_driver(struct device_driver *drv)
{
 struct bus_type *bus;
 struct driver_private *priv;
 int error = 0;

 bus = bus_get(drv->bus);
 if (!bus)
  return -EINVAL;

 pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 if (!priv) {
  error = -ENOMEM;
  goto out_put_bus;
 }
 klist_init(&priv->klist_devices, NULL, NULL);
 priv->driver = drv;
 drv->p = priv;
 priv->kobj.kset = bus->p->drivers_kset;
 error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
         "%s", drv->name);
 if (error)
  goto out_unregister;

 if (drv->bus->p->drivers_autoprobe) {
  error = driver_attach(drv);          @进入此函数进行匹配 int bus_add_driver(struct device_driver *drv)
{
 struct bus_type *bus;
 struct driver_private *priv;
 int error = 0;

 bus = bus_get(drv->bus);
 if (!bus)
  return -EINVAL;

 pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 if (!priv) {
  error = -ENOMEM;
  goto out_put_bus;
 }
 klist_init(&priv->klist_devices, NULL, NULL);
 priv->driver = drv;
 drv->p = priv;
 priv->kobj.kset = bus->p->drivers_kset;
 error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
         "%s", drv->name);
 if (error)
  goto out_unregister;

 if (drv->bus->p->drivers_autoprobe) {
  error = driver_attach(drv);          // 进入此函数匹配函数@cyl
  if (error)
   goto out_unregister;
 }
 klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
 module_add_driver(drv->owner, drv);

 error = driver_create_file(drv, &driver_attr_uevent);
 if (error) {
  printk(KERN_ERR "%s: uevent attr (%s) failed\n",
   __func__, drv->name);
 }
 error = driver_add_attrs(bus, drv);
 if (error) {
  /* How the hell do we get out of this pickle? Give up */
  printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
   __func__, drv->name);
 }

 if (!drv->suppress_bind_attrs) {
  error = add_bind_files(drv);
  if (error) {
   /* Ditto */
   printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
    __func__, drv->name);
  }
 }

 kobject_uevent(&priv->kobj, KOBJ_ADD);
 return 0;

out_unregister:
 kobject_put(&priv->kobj);
 kfree(drv->p);
 drv->p = NULL;
out_put_bus:
 bus_put(bus);
 return error;
}

  if (error)
   goto out_unregister;
 }
 klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
 module_add_driver(drv->owner, drv);

 error = driver_create_file(drv, &driver_attr_uevent);
 if (error) {
  printk(KERN_ERR "%s: uevent attr (%s) failed\n",
   __func__, drv->name);
 }
 error = driver_add_attrs(bus, drv);
 if (error) {
  /* How the hell do we get out of this pickle? Give up */
  printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
   __func__, drv->name);
 }

 if (!drv->suppress_bind_attrs) {
  error = add_bind_files(drv);
  if (error) {
   /* Ditto */
   printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
    __func__, drv->name);
  }
 }

 kobject_uevent(&priv->kobj, KOBJ_ADD);
 return 0;

out_unregister:
 kobject_put(&priv->kobj);
 kfree(drv->p);
 drv->p = NULL;
out_put_bus:
 bus_put(bus);
 return error;
}

int driver_attach(struct device_driver *drv)
{
 return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);  // 遍历总线上所有的设备
}


static int __driver_attach(struct device *dev, void *data)
{
 struct device_driver *drv = data;

 /*
  * Lock device and try to bind to it. We drop the error
  * here and always return 0, because we need to keep trying
  * to bind to devices and some drivers will return an error
  * simply if it didn't support the device.
  *
  * driver_probe_device() will spit a warning if there
  * is an error.
  */

 if (!driver_match_device(drv, dev))
  return 0;

 if (dev->parent) /* Needed for USB */
  device_lock(dev->parent);
 device_lock(dev);
 if (!dev->driver)
  driver_probe_device(drv, dev);           // 调用驱动driver 上probe 函数进行初始@cyl
 device_unlock(dev);
 if (dev->parent)
  device_unlock(dev->parent);

 return 0;
}












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值