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

LINUX设备模型BUS,DEVICE,DRIVER

2016-01-05 11:04 736 查看
虽然看了上面一篇转载的《使用/sys/访问系统》对总线,驱动,设备都讲得比较细但还是没有太多的感觉。在此就先把自己今天所学回忆一下。

  为了满足新的要求,linux2.6提供了新的设备模型:总线、驱动、设备。基本关系简要的概括如下:
驱动核心可以注册多种类型的总线。
每种总线下面可以挂载许多设备。(通过kset devices)
每种总线下可以用很多设备驱动。(通过包含一个kset drivers)}
每个驱动可以处理一组设备。按照我的理解就是所有的设备都挂载到总线上,当加载驱动时,驱动就支总线上找到自己对应的设备。或者先把驱动加载上,来了一个设备就去总线找驱动。

一:总线

  总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连

(1)bus_type.

struct bus_type {

 const char  * name;//设备名称


 struct subsystem subsys;//代表自身

 struct kset  drivers;   //当前总线的设备驱动集合

 struct kset  devices; //所有设备集合

 struct klist  klist_devices;

 struct klist  klist_drivers;


 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, char **envp,   

      int num_envp, char *buffer, int buffer_size);//热拔插事件

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

};


在后面的实例当中用到了里面的两个成员

1:const char *name;

2: int  (*match)(struct device * dev, struct device_driver * drv);//设备驱动匹配函数

这个匹配函数是很关键的东西,这是建立总线上设备与驱动的桥梁,当一个新的设备或驱动被添加到一个总线上时被调用。

(2)总线的操作:

注册:int bus_register(struct bus_type * bus)

注销:void bus_unregister(struct bus_type *bus);

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

这个宏声明一个结构, 产生它的名子通过前缀字符串 bus_attr_ 到给定的名子.

任何属于一个总线的属性应当明确使用 bus_create_file 来创建:

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

属性也可被去除, 使用:

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

lddbus 驱动创建一个简单属性文件, 再次, 包含源码版本号. show 方法和 bus_attribute 结构设置如下:

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

{

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

}

这个总线属性现目前为止我还没有发现它的作用。


(4)总线实例:

其实在这个程序中操作很简单:

1:首先是要准备一个总线bus_type.也就是定义一个bus_type,然后给它填上一些成员。

定义如下:

struct bus_type my_bus_type = {

 .name = "my_bus",

 .match = my_match,

};


这里就对其两个成员赋值了。一个是名称。另一个则是匹配函数:

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

{

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

}


这是匹配的逻辑则是设备的名字与驱动的名字一样。

准备好了总线后就在模块初始化函数中注册:

        /*注册总线*/

 ret = bus_register(&my_bus_type);

 if (ret)

  return ret;


然后在模块退出函数中注解总线:

总线操作完后还要为总线创建属性文件:

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);这句话就定义了一个总线属性文件。BUS_ATTR宏的定义如下:

bus_unregister(&my_bus_type);

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

struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)


show_bus_version定义如下:

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

{

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

}


定义好之后就是调用 函数创建文件

 /*创建属性文件*/ 

 if (bus_create_file(&my_bus_type, &bus_attr_version))

  printk(KERN_NOTICE "Fail to create version attribute!\n");


总线本身也是要对应一个设备的。还要为总线创建设备。

static void my_bus_release(struct device *dev)

{

 printk(KERN_DEBUG "my bus release\n");

}

 

struct device my_bus = {

 .bus_id   = "my_bus0",

 .release  = my_bus_release

};


 /*注册总线设备*/

 ret = device_register(&my_bus);

 if (ret)

  printk(KERN_NOTICE "Fail to register device:my_bus!\n");


可是这是有疑问,我还没有找到这个总线设备,和刚才的总线的联系。

源代码:

#include <linux/device.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/string.h>

MODULE_AUTHOR("David Xie");

MODULE_LICENSE("Dual BSD/GPL");

static char *Version = "$Revision: 1.9 $";

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

{

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

}

static void my_bus_release(struct device *dev)

{

 printk(KERN_DEBUG "my bus release\n");

}

 

struct device my_bus = {

 .bus_id   = "my_bus0",

 .release  = my_bus_release

};

struct bus_type my_bus_type = {

 .name = "my_bus",

 .match = my_match,

};

EXPORT_SYMBOL(my_bus);

EXPORT_SYMBOL(my_bus_type);

/*

 * Export a simple attribute.

 */

static ssize_t show_bus_version(struct bus_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 my_bus_init(void)

{

 int ret;

        

        /*注册总线*/

 ret = bus_register(&my_bus_type);

 if (ret)

  return ret;

  

 /*创建属性文件*/ 

 if (bus_create_file(&my_bus_type, &bus_attr_version))

  printk(KERN_NOTICE "Fail to create version attribute!\n");

 

 /*注册总线设备*/

 ret = device_register(&my_bus);

 if (ret)

  printk(KERN_NOTICE "Fail to register device:my_bus!\n");

  

 return ret;

}

static void my_bus_exit(void)

{

 device_unregister(&my_bus);

 bus_unregister(&my_bus_type);

}

module_init(my_bus_init);

module_exit(my_bus_exit);

二:设备:

1:

struct device {

struct device  * parent; //父设备,一般一个bus也对应一个设备。
struct kobject kobj;//代表自身

char bus_id[BUS_ID_SIZE]; 

struct bus_type * bus;  /* 所属的总线 */

struct device_driver *driver; /* 匹配的驱动*/


void  *driver_data; /* data private to the driver 指向驱动 */

 void  *platform_data; /* Platform specific data,由驱动定义并使用*/


///更多字段忽略了

};

注册设备:int device_register(sruct device *dev)

注销设备:void device_unregister(struct device *dev);

2:设备属性:

sysfs 中的设备入口可有属性. 相关的结构是:

struct device_attribute {

struct attribute attr;

ssize_t (*show)(struct device *dev, char *buf);

ssize_t (*store)(struct device *dev, const char *buf,

size_t count);

};

这些属性结构可在编译时建立, 使用这些宏:

DEVICE_ATTR(name, mode, show, store);

结果结构通过前缀 dev_attr_ 到给定名子上来命名. 属性文件的实际管理使用通常的函数对来处理:

int device_create_file(struct device *device, struct device_attribute *entry);

void device_remove_file(struct device *dev, struct device_attribute *attr);

struct bus_type 的 dev_attrs 成员指向一个缺省的属性列表, 这些属性给添加到总线的每个设备创建.


3:创建设备实例:

创建设备和创建总线基本一样这里只贴出程序:

#include <linux/device.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/string.h>

MODULE_AUTHOR("David Xie");

MODULE_LICENSE("Dual BSD/GPL");

extern struct device my_bus; 

extern struct bus_type my_bus_type;

/* Why need this ?*/

static void my_dev_release(struct device *dev)



 

}

struct device my_dev = {

 .bus = &my_bus_type,//与总线接上关系 

 .parent = &my_bus,//与总线设备接上关系

 .release = my_dev_release,

};

/*

 * Export a simple attribute.

 */

static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, char *buf)

{

 return sprintf(buf, "%s\n", "This is my device!");

}

static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);

static int __init my_device_init(void)

{

 int ret = 0;

        

        /* 初始化设备 */

 strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);

        

        /*注册设备*/

 device_register(&my_dev);

  

 /*创建属性文件*/

 device_create_file(&my_dev, &dev_attr_dev);

 

 return ret; 

}

static void my_device_exit(void)

{

 device_unregister(&my_dev);

}

module_init(my_device_init);

module_exit(my_device_exit);

三:设备驱动:

在总线上挂载了设备后就要为其准备驱动程序。

驱动程序的实现与设备的实现类似,代码如下:

#include <linux/device.h>

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/string.h>

MODULE_AUTHOR("David Xie");

MODULE_LICENSE("Dual BSD/GPL");

extern struct bus_type my_bus_type;

static int my_probe(struct device *dev)

{

    printk("Driver found device which my driver can handle!\n");

    return 0;

}

static int my_remove(struct device *dev)

{

    printk("Driver found device unpluged!\n");

    return 0;

}

struct device_driver my_driver = {

 .name = "my_dev",//对应的设备名称

 .bus = &my_bus_type,//挂载的总线

 .probe = my_probe,//这个函数就是在找到与自己对应的设备时被调用。

        .remove = my_remove,

};

/*

 * Export a simple attribute.

 */

static ssize_t mydriver_show(struct device_driver *driver, char *buf)

{

 return sprintf(buf, "%s\n", "This is my driver!");

}

static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);

static int __init my_driver_init(void)

{

 int ret = 0;

        

        /*注册驱动*/

 driver_register(&my_driver);

  

 /*创建属性文件*/

 driver_create_file(&my_driver, &driver_attr_drv);

 

 return ret; 

}

static void my_driver_exit(void)

{

 driver_unregister(&my_driver);

}

module_init(my_driver_init);

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