首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ok6410学习笔记(13.总线设备驱动)

ok6410学习笔记(13.总线设备驱动)

本节知识点:基础知识:1.总线结构:


name是总线的名称,即总线在bus目录下面  文件夹的名称
bus_attribute   device_attribute     driver_attribute分别是总线  设备  驱动三者的属性文件的描述   如图






他们分别是通过三个宏完成赋值的   下面详细说明
2.设备结构:


kobject kobj是device自身的文件夹名字   来源init_name的赋值
3.驱动结构:

name驱动名称  在my_bus中drives里面的文件夹名

probe当bus模块调用match匹配成功的时候  调用probe函数
4.三个重要的宏:
BUS_ATTR  在linux内核中源码为
[cpp] view plaincopy


  • #define BUS_ATTR(_name, _mode, _show, _store)   \
  • struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)  


DRIVER_ATTR 在linux内核中源码为

[cpp] view plaincopy


  • #define DRIVER_ATTR(_name, _mode, _show, _store)    \
  • struct driver_attribute driver_attr_##_name =       \  
  •     __ATTR(_name, _mode, _show, _store)  


DEVICE_ATTR 在linux内核中源码为

[cpp] view plaincopy


  • #define DEVICE_ATTR(_name, _mode, _show, _store) \
  • struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)  


他们都是在给自己的attribute结构赋值   这个结构是用来创建属性文件的    name是属性文件的名字  /sys/bus目录中my_bus(自己给bus_type.name赋的值)  下面的属性文件

mode为文件读写属性  show为读该文件时调用的函数   store为写该文件时调用的函数   这里还创建出了bus_attr_##_name结构体  是在bus_create_file创建属性文件函数参数中使用的  注意连接符##  所有一定要匹配好
创建的my_bus总线里面有:



其中devices是用来存放设备的    drives是用来存放驱动的    mybus就是刚刚说的属性文件  是通过宏创建的

创建的driver模块里面有:


这个路径是 /sys/bus/my_bus/drivers/my_dev里面的内容  目录本身的my_dev是在driver结构体中给name赋值得到的    mydriver是 在创建属性文件的宏中的_name得到的

创建的device模块里面有:


这个my_dev是在device结构中给 init_name 赋值得到的目录  跟在bus中match比较函数中的kobject的值是一个   他本身是一个连接  连接到/sys/devices/my_bus_dev/my_dev目录中
/sys/devices/my_bus_dev/my_dev目录:




这个连接到的目录中的mydevice就是 利用宏创建的属性文件 名字跟宏中的_name是一个值
5.对于安装driver模块和device模块的顺序问题:先安装那个都可以  都是在有新设备或者新驱动的时候  总线中的match函数进行匹配(这里我觉得是利用了热插拔性质)  然后匹配成功调用driver里面的probe函数
6.注意:bus模块  device模块  driver模块是三个内核模块  而不是简单的三个文件之间的函数调用那么简单,所有在device模块 和 driver模块 中想利用bus模块中的my_bus_dev和my_bus_type的时候,应该使用EXPORT_SYMBOL(my_bus_dev);    EXPORT_SYMBOL(my_bus_type);   
7.这里面有一个不懂的地方,在调用match的时候dev->init_name这个值总是NULL  不是很理解  我觉得应该是device模块中我赋的值啊~~~~~
8.bus模块和device模块中的release函数就算是空函数,也必须要有,因为在卸载两个设备的的时候要调用的   貌似driver模块中的remove函数可以没有的
重点函数:1. bus_register(&my_bus_type)注册总线进入系统
2.bus_unregister(&my_bus_type) 注销总线
3.bus_create_file(&my_bus_type, &bus_attr_mybus) 创建总线设备文件
4.bus_remove_file(&my_bus_type, &bus_attr_mybus) 删除总线设备文件
5.int my_match (struct device *dev, struct device_driver *driver) 匹配指定的驱动程序能否处理指定的设备
6.device_register(&my_dev)  注册设备
7.device_unregister(&my_dev) 删除设备
8.device_create_file(&my_dev, &dev_attr_mydevice)  给device模块创建设备文件
9.device_remove_file(&my_dev, &dev_attr_mydevice)  给device模块删除设备文件
10.driver_register(&my_driver)   注册驱动
11.driver_unregister(&my_driver)   删除驱动
12.driver_create_file(&my_driver, &driver_attr_mydriver)    创建驱动属性文件
13.driver_remove_file(&my_driver, &driver_attr_mydriver)    删除驱动属性文件
驱动结构:bus模块:
1.先在bus模块中  填写 struct bus_type my_bus_type和struct device my_bus_dev   确定总线的名字 即总线目录的名字  即match函数的名字
2.bus_register(&my_bus_type)  注册总线设备     my_match (struct device *dev, struct device_driver *driver)写match函数  注意判断匹配成功的条件   一旦成功在driver模块中则调用probe函数
3.利用宏BUS_ATTR(mybus, S_IRUGO, show_bus_mybus, NULL)  和   bus_create_file(&my_bus_type, &bus_attr_mybus)创建总线属性文件   mybus为属性文件的名字
4.总线也是一个设备,所有要创建总线设备device_register(&my_bus_dev)   设备中的内容来自第一步中struct device my_bus_dev结构   其实这个结构中总线设备的名字.name = "my_bus"  我觉得没什么用


device模块:
5.填写struct device_driver my_driver  设备结构  包括.init_name = "my_dev"即设备目录的名字 ,.bus = &my_bus_type所属总线,.parent = &my_bus_dev所属父对象,.release = my_dev_release 卸载函数
6.device_register(&my_dev)创建设备
7.DEVICE_ATTR(mydevice, S_IRUGO, mydev_show, NULL)和device_create_file(&my_dev, &dev_attr_mydevice)创建属性文件  文件名叫mydevice

driver模块:
8.填写struct device_driver my_driver  驱动结构 包括.name = "my_dev"驱动目录的名字 一般用来 和device设备名字一起用作bus模块中match函数 ,.bus = &my_bus_type所属总线   .probe = my_probe  probe函数
9.driver_register(&my_driver)  注册一个驱动
10.DRIVER_ATTR(mydriver, S_IRUGO, mydriver_show, NULL)和driver_create_file(&my_driver, &driver_attr_mydriver)创建一个驱动的属性文件   文件名为mydriver
本节代码:bus.c:
[cpp] view plaincopy


  • #include <linux/device.h>
  • #include <linux/module.h>
  • #include <linux/kernel.h>
  • #include <linux/init.h>
  • #include <linux/string.h>


  • MODULE_AUTHOR("Hao");  
  • MODULE_LICENSE("Dual BSD/GPL");  

  • static
    void my_bus_release(struct device *dev)  
  • {  
  •             printk("call my_bus_release\n");  
  • }  

  • static
    int my_match (struct device *dev, struct device_driver *driver)  //处理Device和driver两个结构
  • {  
  •             printk("call my_match\n");  
  •             printk("dev->init_name = %s\n", dev->init_name);   
  •             printk("dev->kobj.name = %s\n", dev->kobj.name); //很好奇想看看这个值是什么   这里面的文件即目录直接的关系弄的很乱  
  •             printk("driver->name = %s\n", driver->name);  
  •           if(strcmp(dev->kobj.name, driver->name))  
  •                 return 0;   
  •             else
  •                 return 1;  
  • }  

  • struct bus_type my_bus_type = { //总线的结构体
  •                 .name = "my_bus",   //总线的名字  sys下面bus中的总线名字
  •                 .match = my_match,  //用来比较设备和驱动的对应关系的
  • };  

  • struct device my_bus_dev = {   //总线设备的结构体
  •     .init_name = "my_bus_dev",  //这个是 设备的名字  
  •     .release   = my_bus_release    //这个应该是移除设备的时候调用的函数  就算是空函数也一定要有的
  • };  

  • EXPORT_SYMBOL(my_bus_dev);//这两个是 内核模块之间传递的参数    这个传递给device模块的  赋值给parent父设备的
  • EXPORT_SYMBOL(my_bus_type);  //这个是传递给driver和device两个模块的  让他们知道所属的总线

  • static ssize_t show_bus_mybus(struct bus_type *bus, char *buf)  
  • {  
  •         strcpy(buf,"catting the my_bus\n"); //这个应该是在读取my_bus下面属性文件的时候 传递给用户空间的
  •         return strlen(buf);  //这里应该返回buf的大小  愿意跟kobject那里说的一样
  • }  

  • static BUS_ATTR(mybus, S_IRUGO, show_bus_mybus, NULL);//这个宏的第一个参数是名字是bus_attr_mybus结构体的名字 第二个参数是文件属性  第三个show函数  第四个store函数

  • static
    int __init my_bus_init(void)  
  • {  
  •             int ret;  
  •             printk("call my_bus_init!!!\n");  
  •             ret = bus_register(&my_bus_type); //注册总线进入系统
  •             if (ret)  
  •                 return ret;  
  •             if (bus_create_file(&my_bus_type, &bus_attr_mybus)) //创建属性文件  在my_bus_type这个总线上面创建属性文件  属性文件取决于bus_attr_mybus这个结构体   这个结构体应该看这个BUS_ATTR宏
  •                 printk("Fail to create version attribute!\n");  
  •             ret = device_register(&my_bus_dev);  //总线也是一个设备  所以应该注册总线设备
  •             if (ret)  
  •                 printk("Fail to register device : my_bus!\n");  
  •             return ret;  
  • }  

  • static
    void __exit my_bus_exit(void)  
  • {  
  •             printk("call my_bus_exit\n");  
  •             device_unregister(&my_bus_dev);  
  •             bus_unregister(&my_bus_type);  
  • }  

  • module_init(my_bus_init);  
  • module_exit(my_bus_exit);  


device.c:

[cpp] view plaincopy


  • #include <linux/device.h>
  • #include <linux/module.h>
  • #include <linux/kernel.h>
  • #include <linux/init.h>
  • #include <linux/string.h>

  • MODULE_AUTHOR("Hao");  
  • MODULE_LICENSE("Dual BSD/GPL");  

  • extern
    struct device my_bus_dev;   
  • extern
    struct bus_type my_bus_type;  

  • static
    void my_dev_release(struct device *dev)  
  • {  
  •             printk("call my_bus_release\n");  
  • }  

  • struct device my_dev = {  
  •     .init_name = "my_dev",  //my_bus中设备的名字  是个连接  连接到sys/device目录下
  •     .bus = &my_bus_type,    //所属总线
  •     .parent = &my_bus_dev,  //总线自身就是设备  即父设备
  •     .release = my_dev_release,  
  • };  

  • static ssize_t mydev_show(struct device *dev, struct device_attribute *attr, char *buf)  //这里的struct device_attribute *attr  应该是来自 DEVICE_ATTR这个宏传递给内核的
  • {  

  •         strcpy(buf,"catting the my_dev\n"); //这个应该是在读取my_bus下面属性文件的时候 传递给用户空间的
  •         return strlen(buf);  //这里应该返回buf的大小  愿意跟kobject那里说的一样
  • }  

  • static DEVICE_ATTR(mydevice, S_IRUGO, mydev_show, NULL);  //mydevice貌似是文件名

  • static
    int __init my_device_init(void)  
  • {  
  •         int ret = 0;  
  •         ret = device_register(&my_dev); //注册设备
  •         if (ret)  
  •             return ret;  

  •         ret =device_create_file(&my_dev, &dev_attr_mydevice); //创建device的设备文件   方式跟bus的一样 也是通过一个宏

  •         return ret;   
  • }  
  • static
    void my_device_exit(void)  
  • {  
  •         device_unregister(&my_dev);  
  • }  

  • module_init(my_device_init);  
  • module_exit(my_device_exit);  


driver.c:

[cpp] view plaincopy


  • #include <linux/device.h>
  • #include <linux/module.h>
  • #include <linux/kernel.h>
  • #include <linux/init.h>
  • #include <linux/string.h>

  • MODULE_AUTHOR("Hao");  
  • 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",   //驱动的名字   这个要跟设备的名字一样 不然不匹配probe不能触发的
  •     .bus = &my_bus_type,  //所属的总线
  •     .probe = my_probe,   //如果匹配到设备   匹配的是通过总线中match函数进行的   则触发这个函数
  •     .remove = my_remove,  //如果移除这个驱动则调用这个函数
  • };  

  • static ssize_t mydriver_show(struct device_driver *driver, char *buf)  
  • {  
  •         strcpy(buf,"catting the my_driver\n"); //这个应该是在读取my_bus下面属性文件的时候 传递给用户空间的
  •         return strlen(buf);  //这里应该返回buf的大小  愿意跟kobject那里说的一样
  • }  


  • static DRIVER_ATTR(mydriver, S_IRUGO, mydriver_show, NULL);  

  • static
    int __init my_driver_init(void)  
  • {  
  •         int ret = 0;  
  •         ret = driver_register(&my_driver); //注册驱动
  •         if (ret)  
  •                 return ret;  

  •         ret = driver_create_file(&my_driver, &driver_attr_mydriver);  //创建驱动属性文件
  •       return ret;     
  • }  

  • static
    void my_driver_exit(void)  
  • {  
  •     driver_unregister(&my_driver);  
  • }  

  • module_init(my_driver_init);  
  • module_exit(my_driver_exit);  


Makefile:

[cpp] view plaincopy


  • ifneq ($(KERNELRELEASE),)  

  • obj-m := bus.o devices.o driver.o  

  • else

  • KDIR := /guoqian/linux/linux-2.6.36  
  • all:  
  •     make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-  
  • clean:  
  •     rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul*  

  • endif  

返回列表