Linux驱动之设备模型(4)

来源:互联网 发布:528雾化器做丝数据 编辑:程序博客网 时间:2024/06/08 02:52

Linux驱动之设备模型(4)

 (2013-02-21 11:08:52)
转载
标签: 

设备模型

 

linux

分类: 设备模型


原文地址:  http://blog.csdn.net/hsly_support/article/details/7366592

5.总线

5.1  overview

前面我们介绍了设备模型的底层部分,下面我们来看下设备模型的高层部分,总线、设备和驱动

 

5.2 总线

 总线,是处理器与一个或者多个设备之间的通道。在Linux设备模型中,用bus_type结构来表示

struct  bus_type{

         const  char                  *name;          

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

 

         struct  subsys_private  *p;    

};

Match函数  注册驱动或设备时被用来完成匹配

Uevent函数 用于热插拔,添加环境变量

Probe函数  匹配成功时调用,完成相应工作

P    私有数据,包含内嵌的kset,设备kset和链表,驱动kset和链表等

 

5.3  总线属性

 总线属性用bus_attribute结构来表示

struct  bus_attribute {

         struct attribute      attr;

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

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

};

BUS_ATTR(_name,_mode, _show, _store)

 

 属性操作

     创建属性

    int bus_create_file(structbus_type *, struct bus_attribute *);

     删除属性

    void  bus_remove_file(struct bus_type *, struct bus_attribute *);

 

5.4  总线基本操作

 总线注册和注销函数

     int bus_register(struct bus_type *bus);

     void bus_unregister(struct bus_type *bus);

 

 遍历总线

     遍历总线上每个驱动,并执行fn函数

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

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

     遍历总线上每个设备,并执行fn函数

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

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

 

 总线注册分析

    int  bus_register(struct bus_type *bus)        //包括创建 与bus同名的kset、devices、driver、probe文件

{

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

 

         priv->subsys.kobj.kset = bus_kset;

         priv->subsys.kobj.ktype =&bus_ktype;

         priv->drivers_autoprobe = 1;

 

        

         retval = kset_register(&priv->subsys);

 

         retval = bus_create_file(bus,&bus_attr_uevent);

 

        

         priv->devices_kset =kset_create_and_add("devices", NULL,

                                                         &priv->subsys.kobj);

 

        

         priv->drivers_kset =kset_create_and_add("drivers", NULL,

                                                         &priv->subsys.kobj);

 

        

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

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

 

         retval = add_probe_files(bus);

 

         retval = bus_add_attrs(bus);

}

Klist_drivers和klist_devices这两条链非常重要,用来遍历drivers_kset和devices_kset,drivers_kset和devices_kset分别是总线上所有driver和device的集合。

 

5.5  实例分析

创建一条scbus总线,并添加版本属性。实际中我们并不需要自己创建总线,此试验仅用来学习

 

#include

#include

#include

#include

 

static char * Version  = "revision 1.0,scbus";

 

 

static int  scbus_match(struct device *dev,struct device_driver  *driver)

{

         printk("\n%s,%s\n", dev_name(dev), driver->name);

         return  !strncmp(dev_name(dev), driver->name, strlen(driver->name));

}

 

static void scbus_release(struct device*dev)

{

         printk("scbusrelease\n");

}

 

struct bus_type scbus_type = {

         .name       = "scbus",

         .match   = scbus_match,

};

EXPORT_SYMBOL_GPL(scbus_type);

 

struct device scbus = {

         .init_name        = "scbus0",

         .release   = scbus_release,

};

EXPORT_SYMBOL_GPL(scbus);

 

 

static ssize_t  show_bus_version(structbus_type *bus, char *buf)

{

         return  snprintf(buf, PAGE_SIZE, "%s\n", Version );

}

static BUS_ATTR(version, S_IRUGO,show_bus_version, NULL);

 

static int  __init scbus_init(void)

{

         int ret;

         ret= bus_register(&scbus_type);

         if(ret)

                   return ret;

          ret= bus_create_file(&scbus_type, &bus_attr_version);

         if(ret)

                   gotocreate_error;

 

         ret= device_register(&scbus);            // 产生 /sys/devices/scbus0           devices目录下第一级一般为总线设备,一般把他们作为其他设备的parent

         if(ret)

                   goto  device_error;

 

         printk("Createa scbus\n");

         return  0;

 

device_error:

         bus_remove_file(&scbus_type,&bus_attr_version);

create_error:

         bus_unregister(&scbus_type);

         return  ret;

}

 

static void __exit scbus_exit(void)

{

         device_unregister(&scbus);

         bus_remove_file(&scbus_type,&bus_attr_version);

         bus_unregister(&scbus_type);

         printk("Removea scbus\n");

}

 

module_init(scbus_init);

module_exit(scbus_exit);

 

MODULE_LICENSE("Dual BSD/GPL");

MODULE_AUTHOR("CJOK");

 

试验结果:

Linux驱动之设备模型(4)

0 0
原创粉丝点击