drivers\base\bus.c

 

小结:

 

1、热插拔模块

这个模块的函数主要实现的是驱动和设备的绑定,解除,以及驱动的自动探测等功能

 

2、看本代码前最好先看一次/lib/klist.c,否则代码中关于klist和node的操作会把你绕晕

 

3、bus的模型:

Ø         系统一启动就会自动执行buses_init来注册总线子系统(bus_subsys),这个子系统设置了总线的过滤,show,store操作。

Ø         bus的注册是将bus挂到这个子系统上,

Ø         设备device和驱动driver分别挂在bus的kset和klist对应的地方,

 

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

函数列表:

 

int   bus_for_each_dev(struct bus_type * bus,     struct device * start,

                   void * data, int (*fn)(struct device *, void *))

//从start开始,查找bus->klist_devices中的每一个设备,并执行fn函数

//每执行完一个函数,就把该设备从总线上脱开

 

struct device   * bus_find_device(struct bus_type *bus,

                            struct device *start,       void *data,

                            int (*match)(struct device *, void *))

和buf_for_each_dev类似,只是这个函数是调用match,找到匹配的设备后就退出了

 

int   bus_for_each_drv(struct bus_type * bus, struct device_driver * start,

                   void * data, int (*fn)(struct device_driver *, void *))

和bus_for_each_dev函数的实现类似,只是查找的链表是bus->klist_drivers

 

@@@@@@

int   bus_add_device(struct device * dev)

设备挂载到总线上,实际操作就是sysfs_create_link创建几个link链接

 

void       bus_attach_device(struct device * dev)

设备关联到总线上,实际操作是调用db.c中的device_attach(dev)固定设备,如果成功就klist_add_tail将dev->knode_bus节点挂到bus->klist_devices设备总线上

 

void       bus_remove_device(struct device * dev)

从总线上移走设备,其操作就是bus_add_device函数出错后的处理

 

@@@@@@

int   bus_add_driver(struct device_driver    *drv)

//将驱动关联到总线上,在driver.c文件中,驱动的注册最后是调用该函数,具体的操作如下:

//1、将驱动kobj的父kset设置为bus->drivers,完成与bus的obj关联

//2、kobj在对应的kset上注册

//3、如果总线drivers_autoprobe,则执行driver_attach函数关联驱动和设备

//4、将驱动节点knode挂到总线的drivers_klist链表下

//5、为驱动创建属性文件,包括:驱动自己的属性driver_attr_uevent,总线继承下来的属性,bind和unbind属性

 

void       bus_remove_driver(struct device_driver * drv)

从总线上移除驱动,是add的反过程

 

int          bus_rescan_devices(struct bus_type      * bus)

遍历总线上的设备,调用bus_rescan_devices_helper函数来关联设备

 

int          device_reprobe(struct device *dev)

设备的重新探测:释放设备之前关联的驱动,然后bus_rescan_devices_helper重新探测设备驱动

 

@@@@@@

int   bus_register(struct bus_type * bus)

总线的注册

//1、总线子系统的kobj命名为bus->name

//2、将总线kobj.kset设置为bus_subsys,并完成bus_subsys的注册

//3、为bus总线创建uevent属性文件(操作)

//4、设置总线上的设备链表(kobj命名,父设备指定为bus_subsys.kobj,kset节点的注册)

//5、设置总线上驱动链表,方法同设备链表,只是多了ktype操作(show,store设置probe)

//6、初始化总线上的设备和驱动klist,设备klist上挂有get和put

//7、初始化bus带autoprobe属性,为总线加上probe和autoprobe操作

//8、为bus加上bus_attrs[]属性

 

总线的unregister则相反

 

@@@@@@

int   __init     buses_init(void)

总线的初始化,在系统启动时调用,作用是注册总线子系统bus_subsys

 

 

 

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

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

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

//获取bus属性,获取bus类型

#define   to_bus_attr(_attr)   container_of(_attr,        struct bus_attribute,      attr)

#define   to_bus(obj)           container_of(obj,   struct bus_type,            subsys.kobj)

 

struct bus_attribute {

       struct attribute        attr;

       ssize_t (*show)(struct bus_type *, char * buf);

       ssize_t (*store)(struct bus_type *, const char * buf, size_t count);

};

 

struct attribute {

       const char              *name;

       struct module         *owner;

       mode_t                  mode;

};

 

struct bus_type {

       const char              * name;

       struct module         * owner;

 

       struct kset              subsys;                  //子系统

       struct kset              drivers;

       struct kset              devices;

       struct klist             klist_devices;

       struct klist             klist_drivers;

 

       struct blocking_notifier_head bus_notifier;

 

       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 (*suspend_late)(struct device * dev, pm_message_t state);

       int (*resume_early)(struct device * dev);

       int (*resume)(struct device * dev);

 

       unsigned int drivers_autoprobe:1;         //是否支持自动探测

};

 

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

//获取驱动属性和设备驱动

#define to_drv_attr(_attr)     container_of(_attr,        struct driver_attribute,   attr)

#define to_driver(obj)          container_of(obj,   struct device_driver,      kobj)

 

struct      driver_attribute {

       struct attribute        attr;

       ssize_t (*show)(struct device_driver *, char * buf);

       ssize_t (*store)(struct device_driver *, const char * buf, size_t count);

};

 

struct device_driver {

       其他成员…

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

};

 

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

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

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

//总线的引用计数,实际是引用bus_type->subsys的计数

static struct bus_type     *bus_get(struct bus_type *bus)

{

       return     bus ? container_of(kset_get(&bus->subsys),

                            struct bus_type,     subsys) : NULL;

}

 

static void bus_put(struct bus_type      *bus)

{

       kset_put(&bus->subsys);

}

 

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

//类似的代码我们其实已经很熟悉了,show的执行函数(driver_attribute)

static      ssize_t     drv_attr_show(struct kobject * kobj,    struct attribute * attr, char * buf)

{

       struct driver_attribute *        drv_attr = to_drv_attr(attr);

       struct device_driver *    drv = to_driver(kobj);

       drv_attr->show(drv, buf);

}

 

static      ssize_t    drv_attr_store

类似的函数就不重复了

 

static      struct sysfs_ops     driver_sysfs_ops = {

       .show      = drv_attr_show,

       .store      = drv_attr_store,

};

 

//驱动的ktype操作

static      struct kobj_type     driver_ktype = {

       .sysfs_ops       = &driver_sysfs_ops,

       .release    = driver_release,                  //这个函数是一个空函数,所以没有COPY

};

 

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

//总线的show函数(bus_attribute)

static      ssize_t     bus_attr_show(struct kobject * kobj,    struct attribute * attr,     char * buf)

static      ssize_t     bus_attr_store

 

static      struct sysfs_ops            bus_sysfs_ops = {

       .show      = bus_attr_show,

       .store      = bus_attr_store,

};

 

//总线的ktype操作

static      truct kobj_type             bus_ktype = {

       .sysfs_ops       = &bus_sysfs_ops,

};

 

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

//在总线上创建和删除属性文件

int   bus_create_file(struct bus_type * bus,         struct bus_attribute * attr)

{

       int error;

       if (bus_get(bus)) {         //总线引用加1,创建一个属性文件

              error = sysfs_create_file(&bus->subsys.kobj,      &attr->attr);

              bus_put(bus);         //释放总线引用

       } else

              error = -EINVAL;

       return error;

}

 

void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)

{

       sysfs_remove_file(&bus->subsys.kobj, &attr->attr);

}

 

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

//判断kobj中的ktype是否是系统默认的bus_ktype

//参数kset未使用

static      int   bus_uevent_filter(struct kset *kset,      struct kobject *kobj)

{

       struct kobj_type     *ktype = get_ktype(kobj);

 

       if (ktype == &bus_ktype)

              return 1;

       return 0;

}

 

static struct kset_uevent_ops               bus_uevent_ops = {

       .filter = bus_uevent_filter,

};

 

//声明了bus_subsys——总线子系统

static      decl_subsys(bus, &bus_ktype,      &bus_uevent_ops);

 

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

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

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

//热插拔模块的支持函数

//这个模块的函数主要实现的是驱动和设备的绑定,解除,以及驱动的自动探测等功能

 

//这个函数名有点看似为帮助文件,实际是比较dev->bus_id(即kobj的名字)与data是否一致,是就返回1

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

 

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

//解除驱动的绑定,其核心操作是调用db.c文件中的device_release_driver函数

static      ssize_t    driver_unbind(

       struct device_driver      *drv,

       const char                    *buf,

       size_t                          count)

{

       struct bus_type      *bus = bus_get(drv->bus);            //获取设备驱动中的总线

       struct device          *dev;

       int                        err = -ENODEV;

 

       //这个函数的实现在后面,从函数名我们不难猜出,这个函数的作用是从总线中找出和buf同名的设备来

       dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);

 

       //设备找到,且设备的驱动是指定驱动

       if (dev && dev->driver == drv) {

              //设备的父设备存在,锁一下信号量

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

              device_release_driver(dev);          //这个函数的实现在db.c文件中,看函数的注解,其作用是手动将驱动driver和设备device的连接断开

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

              err = count;

       }

 

       //释放引用计数

       put_device(dev);

       bus_put(bus);

       return err;

}

 

//定义driver_attr_unbind属性

static      DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);

#define   DRIVER_ATTR(_name,_mode,_show,_store)             \

struct driver_attribute    driver_attr_##_name = __ATTR(_name,_mode,_show,_store)

 

#define __ATTR(_name,_mode,_show,_store) { \

       .attr = {.name = __stringify(_name), .mode = _mode },     \

       .show      = _show,                             \

       .store      = _store,                              \

}

 

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

//驱动的绑定操作,其核心操作是调用db.c文件中的driver_probe_device函数

static      ssize_t    driver_bind(

       struct device_driver      *drv,

       const char                    *buf,

       size_t                          count)

{

       struct bus_type      *bus = bus_get(drv->bus);

       struct device          *dev;

       int                        err = -ENODEV;

 

       //从总线中找出buf指定名字的设备来

       dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);

 

       //设备存在且没有绑定驱动

       if (dev && dev->driver == NULL) {

              //操作前锁信号量

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

              down(&dev->sem);

              err = driver_probe_device(drv, dev);    //为驱动探测对应的设备,函数的实现在db.c中,我们在分析这个文件的时候再做具体分析

              up(&dev->sem);

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

 

              if (err > 0)            /* success */

                     err = count;

              else if (err == 0)    /* driver didn't accept device */

                     err = -ENODEV;

       }

 

       //释放计数

       put_device(dev);

       bus_put(bus);

       return err;

}

 

//定义driver_attr_bind属性

static      DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);

 

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

//bus->drivers_autoprobe是一个位,标记总线是否支持驱动的自动探测功能

//这个函数将该功能的支持打印进buf中

static      ssize_t    show_drivers_autoprobe(struct bus_type *bus,    char *buf)

{

       return     sprintf(buf, "%d\n", bus->drivers_autoprobe);

}

 

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

//根据buf设置总线的drivers_autoprobe属性

static      ssize_t    store_drivers_autoprobe(

       struct bus_type      *bus,

       const char             *buf,

       size_t                   count)

{

       if (buf[0] == '0')     bus->drivers_autoprobe = 0;

       else                       bus->drivers_autoprobe = 1;

 

       return count;

}

 

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

//在bus总线上探测buf指定名字的驱动是否存在

static      ssize_t    store_drivers_probe(

       struct bus_type      *bus,

       const char             *buf,

       size_t                   count)

{

       struct device *dev;

 

       //在bus总线上找到buf指定的设备

       dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);

 

       //设备不存在,错误返回

       if (!dev)  return -ENODEV;

 

       //查找设备的驱动是否存在,存在就返回0,不存在就返回非0

       //如果设备之前没有挂驱动,则这个函数中会调用device_attach(dev)来探测驱动

       if (bus_rescan_devices_helper(dev, NULL) != 0)        return -EINVAL;

       return count;

}

 

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

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

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

struct      klist_iter {

       struct klist             * i_klist;

       struct list_head       * i_head;

       struct klist_node     * i_cur;

};

 

//找下一个设备,详细的执行代码在lib/klist.c文件中

//由于下面的代码将大量应用这个文件中的函数,所以先停下来看看这个文件的具体操作

static      struct device   *next_device(struct klist_iter       * i)

{

       struct klist_node    * n = klist_next(i);        //找到下一个节点

       //节点存在则返回该节点所在的设备结构体宿主

       return     n ? container_of(n,       struct device, knode_bus) : NULL;

}

 

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

//从start开始,查找bus->klist_devices中的每一个设备,并执行fn函数

//每执行完一个函数,就把该设备从总线上脱开

int   bus_for_each_dev(

       struct bus_type      * bus,                   //总线

       struct device          * start,                  //开始设备

       void                     * data,                   //fn的参数

       int (*fn)(struct device *, void *))

{

       struct klist_iter i;

       struct device * dev;

       int error = 0;

 

       //总线为空,错误返回

       if (!bus)  return -EINVAL;

 

       //初始化容器i,其klist为bus->klist_devices设备链表,当前设备为start设备

       klist_iter_init_node(&bus->klist_devices,    &i,

                          (start ? &start->knode_bus : NULL));

 

       //找到下一个设备,执行fn函数

       while ((dev = next_device(&i)) && !error)

              error = fn(dev, data);

 

       //释放当前设备

       klist_iter_exit(&i);

       return error;

}

 

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

//调用match函数,找到指定设备

struct device   * bus_find_device(

       struct bus_type      *bus,

       struct device          *start,

       void                     *data,

       int (*match)(struct device *, void *))

{

       struct klist_iter i;

       struct device *dev;

 

       klist_iter_init_node(&bus->klist_devices, &i,

                          (start ? &start->knode_bus : NULL));

 

       while ((dev = next_device(&i)))

              if (match(dev, data) && get_device(dev))

                     break;

 

       klist_iter_exit(&i);

       return     dev;

}

 

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

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

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

//同next_device,查找下一个驱动

static struct device_driver     * next_driver(struct klist_iter * i)

{

       struct klist_node    * n = klist_next(i);        //获取下一个node节点

       return     n ? container_of(n, struct device_driver, knode_bus) : NULL;

}

 

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

//这个函数和bus_for_each_dev很像,不同的是他是从bus->klist_drivers链表中找驱动

int   bus_for_each_drv(

       struct bus_type             * bus,

       struct device_driver      * start,

       void * data,

       int (*fn)(struct device_driver *, void *))

{

}

 

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

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

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

//为设备创建属性(一个设备可以挂在多条总线上?)

static      int device_add_attrs(struct bus_type *bus,   struct device *dev)

{

       int error = 0;

       int i;

 

       //总线的设备属性指针不存在,返回

       if (!bus->dev_attrs)              return 0;

 

       //查找所有设置了name的attrs属性,执行create函数

       for (i = 0; attr_name(bus->dev_attrs[i]); i++) {

              error = device_create_file(dev,      &bus->dev_attrs[i]);

              if (error) {

                     while (--i >= 0)

                            device_remove_file(dev, &bus->dev_attrs[i]);

                     break;

              }

       }

       return error;

}

 

//删除设备属性

static void device_remove_attrs(struct bus_type * bus, struct device * dev)

{

       if (bus->dev_attrs) {

              for (i = 0; attr_name(bus->dev_attrs[i]); i++)

                     device_remove_file(dev,&bus->dev_attrs[i]);

       }

}

 

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

//在总线上加设备,实际操作就是用sysfs_create_link函数创建链接

int   bus_add_device(struct device * dev)

{

       struct bus_type      * bus = bus_get(dev->bus);          //bus引用计数加1

       int error = 0;

 

       if (bus) {        //只有总线存在时,这个函数才有意义

              error = device_add_attrs(bus, dev);                    //添加设备属性

              if (error)        goto out_put;

 

              //为两个obj创建连接

              error = sysfs_create_link(&bus->devices.kobj,

                                          &dev->kobj, dev->bus_id);

              if (error)        goto out_id;

 

              //在sub子系统上创建链接

              error = sysfs_create_link(&dev->kobj,

                            &dev->bus->subsys.kobj, "subsystem");

              if (error)        goto out_subsys;

 

              //这是一个恒返回0的空函数

              error = make_deprecated_bus_links(dev);

              if (error)        goto out_deprecated;

       }

       return 0;

 

out_deprecated:

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

out_subsys:            //subsystem子系统挂接失败

       sysfs_remove_link(&bus->devices.kobj, dev->bus_id);

out_id:                  //创建链接失败

       device_remove_attrs(bus, dev);

out_put:                //添加设备属性失败

       bus_put(dev->bus);

       return error;

}

 

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

void       bus_attach_device(struct device * dev)

{

       struct bus_type      *bus = dev->bus;

       int ret = 0;

 

       //有指定总线才进行以下操作

       if (bus) {

              dev->is_registered = 1;                //标记设备已注册

              if (bus->drivers_autoprobe)

                     ret = device_attach(dev);       //如果总线带有自动探测属性,则执行attach函数,该函数的实现在db.c中

 

              //attach(固定)成功,ret大于0

              //初始化dev->knode_bus节点,并将其挂到bus总线上

              if (ret >= 0)                               

                     klist_add_tail(&dev->knode_bus, &bus->klist_devices);

              else

                     dev->is_registered = 0;         //设备没有固定到bus总线上,取消已注册标记

       }

}

 

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

//从总线上移走指定的设备,其操作就是add操作出错后的操作

void       bus_remove_device(struct device * dev)

{

       if (dev->bus) {

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

              remove_deprecated_bus_links(dev);

              sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);

              device_remove_attrs(dev->bus, dev);

              if (dev->is_registered) {

                     dev->is_registered = 0;

                     klist_del(&dev->knode_bus);

              }

              device_release_driver(dev);          //释放驱动

              bus_put(dev->bus);

       }

}

 

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

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

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

//关联驱动的属性,挂在指定总线下的驱动都会继承总线的全部attr属性

static int        driver_add_attrs(struct bus_type * bus, struct device_driver * drv)

{

       int error = 0;

       int i;

 

       if (bus->drv_attrs) {

              for (i = 0; attr_name(bus->drv_attrs[i]); i++) {

                     error = driver_create_file(drv, &bus->drv_attrs[i]);

                     if (error)        goto Err;

              }

       }

 Done:

       return error;

 Err:

       while (--i >= 0)      driver_remove_file(drv, &bus->drv_attrs[i]);

       goto Done;

}

 

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

static void      driver_remove_attrs(struct bus_type * bus, struct device_driver * drv)

驱动的移除,操作就是add操作的出错处理

 

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

//创建驱动的属性文件

static int        add_bind_files(struct device_driver     *drv)

{

       int ret;

 

       //为驱动创建属性文件

       ret = driver_create_file(drv, &driver_attr_unbind);

       if (ret == 0) {

              ret = driver_create_file(drv, &driver_attr_bind);

              if (ret)     driver_remove_file(drv, &driver_attr_unbind);

       }

       return ret;

}

 

//删除驱动的属性文件

static void      remove_bind_files(struct device_driver *drv)

{

       driver_remove_file(drv, &driver_attr_bind);

       driver_remove_file(drv, &driver_attr_unbind);

}

 

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

//创建两个属性:bus_attr_drivers_probe和bus_attr_drivers_autoprobe

static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);

static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,

              show_drivers_autoprobe,      store_drivers_autoprobe);

//显示是否支持自动探测, 设置是否支持自动探测

 

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

//为指定总线创建属性文件

static int        add_probe_files(struct bus_type *bus)

{

       int retval;

 

       //bus_attr_drivers_probe和bus_attr_drivers_autoprobe这两个属性文件就在上面一点定义

       retval = bus_create_file(bus, &bus_attr_drivers_probe);

       if (retval)              goto out;

 

       retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);

       if (retval)              bus_remove_file(bus, &bus_attr_drivers_probe);

 

out:

       return retval;

}

 

//删除指定总线上的探测属性文件

static void      remove_probe_files(struct bus_type *bus)

{

       bus_remove_file(bus, &bus_attr_drivers_autoprobe);

       bus_remove_file(bus, &bus_attr_drivers_probe);

}

 

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

//根据buf指定的动作,执行驱动drv->uevent函数

static      ssize_t    driver_uevent_store(

       struct device_driver      *drv,              //驱动

       const char                    *buf,             //指定的uevent动作

       size_t                          count)            //buf长度

{

       enum kobject_action     action;

 

       if (kobject_action_type(buf, count, &action) == 0)

              kobject_uevent(&drv->kobj, action);

 

       return count;

}

 

//创建驱动属性driver_attr_uevent,关联上的设置函数是上面那个

static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);

 

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

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

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

//将驱动关联到总线上,具体的操作如下:

//1、将驱动kobj的父kset设置为bus->drivers,完成与bus的obj关联

//2、kobj在kset上注册

//3、如果总线drivers_autoprobe,则执行driver_attach函数关联驱动和设备

//4、将驱动节点knode挂到总线的drivers_klist链表下

//5、为驱动创建属性文件,包括:驱动自己的属性driver_attr_uevent,总线继承下来的属性,bind和unbind属性

int   bus_add_driver(struct device_driver    *drv)

{

       struct bus_type * bus = bus_get(drv->bus);         //总线引用加1

       int error = 0;

 

       if (!bus)         return -EINVAL;                         //驱动没有挂上总线,失败

 

       //给驱动的kobj赋名

       error = kobject_set_name(&drv->kobj, "%s", drv->name);

       if (error)        goto out_put_bus;

 

       //指定kobj的父kset,注册kobj到父kset中

       drv->kobj.kset = &bus->drivers;                        //kobj的kset宿主指向总线的驱动宿主

       error = kobject_register(&drv->kobj);                //注册kobj到kset中(bus->drivers)

       if (error)        goto out_put_bus;

 

       //总线带有驱动的自动探测属性

       if (drv->bus->drivers_autoprobe) {

              error = driver_attach(drv);                         //自动执行驱动的固定函数

              if (error) goto out_unregister;                     //驱动固定失败

       }

 

       //将驱动的节点挂到总线的驱动链表上

       klist_add_tail(&drv->knode_bus,        &bus->klist_drivers);

 

       //这个函数应该是挂载模块的,我们暂时忽略

       module_add_driver(drv->owner, drv);

 

       //为驱动创建属性文件,主要是创建driver_uevent_store关联

       error = driver_create_file(drv, &driver_attr_uevent);

 

       //将总线上的属性关联到驱动中(挂在总线下的驱动都要继承总线的attr)

       error = driver_add_attrs(bus, drv);

      

       //为驱动创建bind和unbind属性

       error = add_bind_files(drv);

      

       //返回

       return error;

 

out_unregister:              //驱动在总线上关联失败

       kobject_unregister(&drv->kobj);

out_put_bus:                 //驱动的kobj赋名失败, 注册kobj失败

       bus_put(bus);         //释放总线引用

       return error;

}

 

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

//从总线上移除驱动

void       bus_remove_driver(struct device_driver * drv)

{

       if (!drv->bus)        return;

 

       remove_bind_files(drv);

       driver_remove_attrs(drv->bus, drv);

       driver_remove_file(drv, &driver_attr_uevent);

       klist_remove(&drv->knode_bus);

       driver_detach(drv);

       module_remove_driver(drv);

       kobject_unregister(&drv->kobj);

       bus_put(drv->bus);

}

 

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

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

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

//重新扫描设备,具体的操作是,如果设备的驱动没有指定,则调用device_attach

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

{

       int ret = 0;

 

       if (!dev->driver)

              ret = device_attach(dev);      

 

       return ret < 0 ? ret : 0;

}

 

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

//遍历总线上的每一个设备,调用他的rescan函数

int   bus_rescan_devices(struct bus_type      * bus)

{

       return     bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);

}

 

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

//设备的重新探测:释放设备之前关联的驱动,然后bus_rescan_devices_helper重新探测设备驱动

int   device_reprobe(struct device *dev)

{

       if (dev->driver) {

              device_release_driver(dev);

       }

 

       return     bus_rescan_devices_helper(dev,    NULL);

}

 

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

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

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

//为总线创建属性文件

static      int   bus_add_attrs(struct bus_type       * bus)

{

       int error = 0;

      

       if (bus->bus_attrs) {

              for (i = 0; attr_name(bus->bus_attrs[i]); i++) {

                     error = bus_create_file(bus,&bus->bus_attrs[i]);

                     if (error)        goto Err;

              }

       }

 Done:

       return error;

 Err:

       while (--i >= 0)      bus_remove_file(bus,&bus->bus_attrs[i]);

       goto Done;

}

 

//删除总线的属性文件

static void      bus_remove_attrs(struct bus_type * bus)

{

       int i;

 

       if (bus->bus_attrs) {

              for (i = 0; attr_name(bus->bus_attrs[i]); i++)

                     bus_remove_file(bus,&bus->bus_attrs[i]);

       }

}

 

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

//通过node获得设备,然后引用/释放设备计数

static void klist_devices_get(struct klist_node *n)

{

       struct device   *dev = container_of(n, struct device, knode_bus);

       get_device(dev);

}

 

static void klist_devices_put(struct klist_node *n)

{

       struct device *dev = container_of(n, struct device, knode_bus);

       put_device(dev);

}

 

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

//执行总线的uevent函数

static      ssize_t    bus_uevent_store(

       struct bus_type      *bus,

       const char             *buf,

       size_t                   count)

{

       enum kobject_action action;

 

       if (kobject_action_type(buf, count, &action) == 0)

              kobject_uevent(&bus->subsys.kobj,     action);

       return count;

}

 

//声明bus_attr_uevent属性

static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);

 

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

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

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

//总线的注册,主要操作如下:

//1、总线子系统的kobj命名为bus->name

//2、将总线kobj.kset设置为bus_subsys,并完成bus_subsys的注册

//3、为bus总线创建uevent属性文件(操作)

//4、设置总线上的设备链表(kobj命名,父设备指定为bus_subsys.kobj,kset节点的注册)

//5、设置总线上驱动链表,方法同设备链表,只是多了ktype操作(show,store设置probe)

//6、初始化总线上的设备和驱动klist,设备klist上挂有get和put

//7、初始化bus带autoprobe属性,为总线加上probe和autoprobe操作

//8、为bus加上bus_attrs[]属性

int   bus_register(struct bus_type * bus)

{

       int retval;

 

       //网上查了下这个宏,无果。从宏名可以看出,这个宏应该是初始化通知头的

       BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);

 

       //kobj命名bus->name

       retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);

       if (retval)              goto out;

 

       //设置父kset为总线子系统

       bus->subsys.kobj.kset = &bus_subsys;

 

       //注册子系统

       retval = subsystem_register(&bus->subsys);

       if (retval)              goto out;

      

       //创建bus的属性文件

       retval = bus_create_file(bus, &bus_attr_uevent);

       if (retval)              goto bus_uevent_fail;

 

       //设置总线中设备节点的名字

       kobject_set_name(&bus->devices.kobj, "devices");

       //设备节点的父节点为总线子系统

       bus->devices.kobj.parent = &bus->subsys.kobj;

       //注册设备节点的kset

       retval = kset_register(&bus->devices);

       if (retval)              goto bus_devices_fail;

 

       //设置总线中的驱动节点,操作同设备节点

       kobject_set_name(&bus->drivers.kobj, "drivers");

       bus->drivers.kobj.parent = &bus->subsys.kobj;

       bus->drivers.ktype = &driver_ktype;    //驱动有关联ktype

       retval = kset_register(&bus->drivers);

       if (retval)              goto bus_drivers_fail;

 

       //初始化设备链表和驱动链表

       klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);

       klist_init(&bus->klist_drivers, NULL, NULL);

 

       //设置总线的驱动自动探测属性

       bus->drivers_autoprobe = 1;

       retval = add_probe_files(bus);             //为总线加上probe和autoprobe属性

       if (retval)              goto bus_probe_files_fail;

 

       //为总线加上bus_attrs[]属性

       retval = bus_add_attrs(bus);

       if (retval)              goto bus_attrs_fail;

 

       return 0;

 

bus_attrs_fail:               //attrs属性加载失败

       remove_probe_files(bus);

bus_probe_files_fail:     //probe属性加载失败

       kset_unregister(&bus->drivers);

bus_drivers_fail:           //驱动节点注册失败

       kset_unregister(&bus->devices);

bus_devices_fail:           //设备节点注册失败

       bus_remove_file(bus, &bus_attr_uevent);

bus_uevent_fail:            //属性文件创建失败

       subsystem_unregister(&bus->subsys);

out:                              //kobj命名失败,子系统注册失败

       return retval;

}

 

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

void       bus_unregister(struct bus_type * bus)

{

       bus_remove_attrs(bus);

       remove_probe_files(bus);

       kset_unregister(&bus->drivers);

       kset_unregister(&bus->devices);

       bus_remove_file(bus, &bus_attr_uevent);           //删除总线属性

       subsystem_unregister(&bus->subsys);

}

 

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

//注册总线通知(通过代码关联,调用这个函数的地方似乎没有)

int   bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)

{

       return     blocking_notifier_chain_register(&bus->bus_notifier, nb);

}

 

//反注册总线通知

int   bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)

{

       return blocking_notifier_chain_unregister(&bus->bus_notifier, nb);

}

 

 

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

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

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

//总线的初始化,系统启动时调用

//操作是注册总线子系统

int   __init     buses_init(void)

{

       return     subsystem_register(&bus_subsys);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值