drivers\base\dd.c

 

小结:

 

文件的一开始就指出了这个文件的作用:

The core device/driver interactions

 

在阅读代码之前,建议先看看http://bbs.chinaunix.net/thread-2010492-1-1.html

首先要明确一个概念:一个设备只能对应一个驱动,一个驱动可以挂上很多设备,所以驱动有一个链表,上面挂着支持的设备:

 

这个文件的代码就是负责实现驱动与设备的关联与释放操作的

 

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

函数列表:

 

int   device_bind_driver(struct device *dev)

设备与驱动绑定

 

int   driver_probe_done(void)

探测是否有probe正在运行,没有则返回0。

探测的原理是读probe_count变量是否为0,这个变量在静态函数really_probe入口处加1,退出时减1

 

int   driver_probe_device(struct device_driver * drv, struct device * dev)

驱动的绑定,过程如下:

1、  检查dev是否注册,无注册则错误返回

2、  如果match函数存在则调用drv->bus->match(dev, drv),匹配失败则退出

3、  调用really_probe函数进行绑定,这个函数的实现如下:

1、    probe_count加1,用于表示有探测函数正在运行

2、    先将dev->driver = drv,如果出错再取消这个设置

3、    对dev创建link,实现dev和drive文件夹的链接

4、    调用dev->bus->probe或drv->probe进行探测

5、    探测成功则driver_bound(dev)完成绑定,driver_bound的实现如下:

1、    检测dev->knode_driver是否已经设置,设置则说明设备已经关联上驱动,错误返回

2、    klist_add_tail将dev->knode_driver挂到dev->driver->klist_devices链表下,在really_probe中,dev->driver设置为指定驱动,所以这里dev->driver->klist_devices是该驱动中已经关联的设备链表,而dev->knode_driver则是设备的驱动入口,后面应该是根据这个节点来获取dev的结构体。

 

int   device_attach(struct device * dev)

设备与驱动的关联函数

如果dev->driver已关联上驱动,则直接调用device_bind_driver(dev)来创建link及绑定驱动(将dev->knode_driver挂到dev->driver->klist_devices链表下)

如果dev->driver未关联,则调用bus.c中的bus_for_each_drv

 

int   driver_attach(struct device_driver        * drv)

同device_attach,区别是遍历的是drv->bus,即查找驱动所在的总线,将总线上的设备尝试关联成drv驱动

而上一个函数则是遍历dev->bus,即查找设备所在的总线,将挂在该总线上的驱动依次和指定设备进行匹配,所以查找完一个就扔一个,因为那个不符合要求

 

void       device_release_driver(struct device * dev)

删除设备对应的驱动,核心操作如下:

//1、删除link文件

//2、将dev->knode_driver从其driver->klist_devices链表中脱出

//3、调用总线或驱动的remove函数

//4、释放设备占用的资源,dev->drivers设置为NULL

 

void       driver_detach(struct device_driver * drv)

释放与指定驱动关联的所有设备

 

 

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//根据节点获取设备

#define   to_drv(node)         container_of(node, struct device_driver, kobj.entry)

 

struct device_driver {

       const char              * name;

       struct bus_type       * bus;

 

       struct kobject         kobj;                     //内嵌的目标

       struct klist             klist_devices;

       struct klist_node     knode_bus;

 

       struct module         * owner;

       const char             * mod_name; 

       struct module_kobject    * mkobj;

 

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

};

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//驱动与设备的绑定

static      void       driver_bound(struct device *dev)

{

       //设备的knode_driver已经指定了驱动链表,退出

       if (klist_node_attached(&dev->knode_driver))

              return;

 

       //通过bus通知设备有驱动绑定

       if (dev->bus)

              blocking_notifier_call_chain(&dev->bus->bus_notifier,

                                        BUS_NOTIFY_BOUND_DRIVER,   dev);

 

       //将dev->knode_driver驱动链表挂到dev->driver->klist_devices上

       //看完下面的really_probe函数的补注:

       //在really_probe中,dev->driver设置为指定驱动,所以这里dev->driver->klist_devices是该驱动中已经关联的设备链表,而dev->knode_driver则是设备的驱动入口,后面应该是根据这个节点来获取dev的结构体。

       klist_add_tail(&dev->knode_driver,     &dev->driver->klist_devices);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//添加驱动关联

static      int   driver_sysfs_add(struct device *dev)

{

       int ret;

 

       //创建链接

       ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,  kobject_name(&dev->kobj));

       if (ret == 0) {

              //双向链接

              ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj,  "driver");

              if (ret)     //创建失败则删除刚才的链接

                     sysfs_remove_link(&dev->driver->kobj,      kobject_name(&dev->kobj));

       }

       return ret;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//删除驱动关联

static      void       driver_sysfs_remove(struct device *dev)

{

       struct device_driver *drv = dev->driver;             //获取设备驱动

 

       if (drv) {        //删除驱动关联

              sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));

              sysfs_remove_link(&dev->kobj, "driver");

       }

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//设备绑定对应的驱动

int   device_bind_driver(struct device *dev)

{

       int ret;

 

       ret = driver_sysfs_add(dev);                //创建文件链接

       if (!ret)   driver_bound(dev);               //创建成功,驱动绑定

       return ret;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

static      atomic_t        probe_count = ATOMIC_INIT(0);                             //原子操作

static      DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);            //等待队列

 

//返回1则表示成功,返回0表示失败

//操作过程如下:

//1、创建驱动和设备的link文件

//2、调用dev->bus->probe或drv->probe进行探测(总线优先)

static      int   really_probe(struct device *dev,   struct device_driver *drv)

{

       int ret = 0;

 

       atomic_inc(&probe_count);                 //探测计数加1

       WARN_ON(!list_empty(&dev->devres_head));   //链表不为空,出警告

 

       dev->driver = drv;                              //设备的驱动为指定驱动

       if (driver_sysfs_add(dev))

              goto       probe_failed;                //添加驱动关联失败

 

       //总线的probe函数存在就调用总线的probe函数,否则调用驱动的probe函数

       if (dev->bus->probe)

       {

              ret = dev->bus->probe(dev);

              if (ret)     goto probe_failed;

       }

       else if (drv->probe)

       {

              ret = drv->probe(dev);

              if (ret)     goto probe_failed;

       }

 

       //探测成功,驱动绑定(设备节点挂到驱动的设备链表中)

       driver_bound(dev);

       ret = 1;

       goto done;

 

//添加驱动关联失败

probe_failed:

       devres_release_all(dev);                      //设备资源释放

       driver_sysfs_remove(dev);                  //删除驱动关联

       dev->driver = NULL;                         //设备的驱动挂空

       ret = 0;

 

done:

       atomic_dec(&probe_count);                //探测计数减1(类似put和get)

       wake_up(&probe_waitqueue);             //唤醒等待队列

       return ret;                                                 //返回

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//驱动探测是否完成,在really_probe的入口将probe_count加1,退出时减1,所以这个函数用来探测是否有really_probe函数正在运行

int   driver_probe_done(void)

{

       if (atomic_read(&probe_count))

              return -EBUSY;

       return 0;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//bus.c的driver_bind函数中调用

int   driver_probe_device(struct device_driver * drv, struct device * dev)

{

       int ret = 0;

 

       //如果设备没有注册,则出错返回

       if (!device_is_registered(dev))      return -ENODEV;

 

       //驱动的总线match函数调用失败,退出

       if (drv->bus->match && !drv->bus->match(dev, drv))

              goto done;

 

       //调用readlly_probe函数实现绑定

       ret = really_probe(dev, drv);

 

done:

       return ret;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

static      int   __device_attach(struct device_driver * drv,        void * data)

{

       struct device   * dev = data;

       return     driver_probe_device(drv,      dev);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//在bus.c中,总线探测设备时调用该函数

//设备与驱动的关联,成功返回1

int   device_attach(struct device * dev)

{

       int ret = 0;

 

       down(&dev->sem);

       if (dev->driver) {                 //设备的驱动已指定(really_probe成功执行)

              ret = device_bind_driver(dev);      //设备与驱动链表的绑定

              if (ret == 0)    ret = 1;    //成功

              else {                           //失败

                     dev->driver = NULL;

                     ret = 0;

              }

       } else {

              //没有为设备绑定驱动,则遍历设备所在的总线,尝试关联驱动,执行__device_attach函数

              //bus_for_each_drv在bus.c中

              ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

       }

       up(&dev->sem);

       return ret;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//驱动和设备的probe

static      int   __driver_attach(struct device * dev,     void * data)

{

       struct device_driver * drv = data;         //获取驱动

 

       if (dev->parent)     down(&dev->parent->sem);

       down(&dev->sem);

       if (!dev->driver)    driver_probe_device(drv, dev);

       up(&dev->sem);

       if (dev->parent)     up(&dev->parent->sem);

 

       return 0;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//遍历驱动所在的总线,对挂在该总线上的设备进行探测

int   driver_attach(struct device_driver        * drv)

{

       return     bus_for_each_dev(drv->bus, NULL, drv,    __driver_attach);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//从设备中删除驱动,主要步骤如下:

//1、删除link文件

//2、将dev->knode_driver从其driver->klist_devices链表中脱出

//3、调用总线或驱动的remove函数

//4、释放设备占用的资源,dev->drivers设置为NULL

static void      __device_release_driver(struct device * dev)

{

       struct device_driver * drv;

 

       drv = get_driver(dev->driver);             //设备关联的驱动引用加1

       if (drv) {                                           //驱动存在

              driver_sysfs_remove(dev);           //link文件删除

              sysfs_remove_link(&dev->kobj, "driver");   //设备与驱动的link删除

              klist_remove(&dev->knode_driver);            //将设备节点从驱动的dev->driver->klist_devices链表中脱出

 

              if (dev->bus)                              //发总线通知

                     blocking_notifier_call_chain(&dev->bus->bus_notifier,

                            BUS_NOTIFY_UNBIND_DRIVER,   dev);

 

              //调用总线或者驱动的remove函数

              if (dev->bus && dev->bus->remove)          dev->bus->remove(dev);

              else if (drv->remove)                                 drv->remove(dev);

 

              //释放设备资源

              devres_release_all(dev);

              dev->driver = NULL;                  //标记设备没有关联驱动

              put_driver(drv);                          //释放刚要的驱动计数

       }

}

 

//删除设备的驱动,其核心函数就是上面那个

void device_release_driver(struct device * dev)

{

       down(&dev->sem);

       __device_release_driver(dev);

       up(&dev->sem);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//释放与指定驱动关联的所有设备(一个驱动可以对应很多设备,这里是释放与这个驱动关联的每一个设备)

void       driver_detach(struct device_driver * drv)

{

       struct device * dev;

 

       for (;;) {

              spin_lock(&drv->klist_devices.k_lock);              //驱动的设备链表锁

 

              //驱动对应的与他关联的设备链表为空,退出

              if (list_empty(&drv->klist_devices.k_list)) {

                     spin_unlock(&drv->klist_devices.k_lock);

                     break;

              }

 

              //获取驱动链表中的一个设备

              dev = list_entry(drv->klist_devices.k_list.prev,

                            struct device, knode_driver.n_node);

              get_device(dev);                   //设备引用计数加1,方便操作

              spin_unlock(&drv->klist_devices.k_lock);

 

              if (dev->parent)     down(&dev->parent->sem);

              down(&dev->sem);

              if (dev->driver == drv)  __device_release_driver(dev);       //释放该设备的驱动

              up(&dev->sem);

              if (dev->parent)     up(&dev->parent->sem);

 

              put_device(dev);                  //释放设备计数

       }

}

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值