Linux Kernel 学习笔记16:总线设备驱动模型

来源:互联网 发布:2017年淘宝测黑号 编辑:程序博客网 时间:2024/05/22 01:29

(本章基于:Linux-3.13.0-32)

Linux总线设备驱动模型结构如下图:


设备(device)和驱动(driver)分别挂载在总线(bus)上,总线再通过自身的匹配函数(match)帮助device找到对应driver或者帮助driver找到对应的device;


数据结构

总线(bus)结构

struct bus_type {        //总线名const char*name;        //匹配函数int (*match)(struct device *dev, struct device_driver *drv);        ......}

驱动(driver)结构

struct device_driver {        //驱动名const char*name;        //需挂载的总线struct bus_type*bus;        //驱动处理函数int (*probe) (struct device *dev);        ........}
设备(device)结构

struct device {        //设备名const char*init_name;         //需挂载的总线struct bus_type*bus;        ......}


相关操作函数

bus注册注销

int bus_register(struct bus_type *bus);

int bus_unregister(struct bus_type *bus);

成功注册bus后可在/sys/bus下看到对应的目录;


driver注册注销

int driver_register(struct device_driver *drv);

int driver_unregister(struct device_driver *drv);

成功注册driver后可在/sys/bus下对应的总线目录下的drivers中看到此驱动;


device注册注销

int device_register(struct device *dev);

int device_unregister(struct device *dev);

成功注册device后可在/sys/bus/下对应的总线目录下的devices中看到此设备;


例:

本例分三个小模块bus、driver、device,bus使用名称匹配driver与device。依次挂载模块bus、driver、device,bus匹配device到对应的驱动driver并执行其中的驱动处理函数probe()。反之依次挂载bus、device、driver可以得到同样的效果;

注意:

1、注册device时我们将名称参数保存在成员init_name中,但在注册过程中会将init_name中的名称拷贝到kobj.name中,并将init_name置空。这点在匹配函数的编写中非常重要;

2、driver、device中均需要使用bus中使用EXPORT_SYMBOL导出的bus变量名,但事实上driver、device无法获取到这一变量,这是由于2.6.26之后产生的一个内核BUG,解决办法见:http://blog.csdn.net/stone8761/article/details/74744550


my_bus.c

#include <linux/init.h>#include <linux/module.h>#include <linux/device.h>int my_match(struct device *dev, struct device_driver *drv){        if(dev->kobj.name && drv->name) {                return !strncmp(dev->kobj.name, drv->name, strlen(drv->name));        } else {                return 0;        }}struct bus_type my_bus_type = {        .name = "my_bus",        .match = my_match,};EXPORT_SYMBOL_GPL(my_bus_type);static __init int hello_init(void){        bus_register(&my_bus_type);        return 0;}static __exit void hello_exit(void){        bus_unregister(&my_bus_type);}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Stone");
my_driver.c

#include <linux/init.h>#include <linux/module.h>#include <linux/device.h>int my_probe(struct device *dev){        printk(KERN_INFO "found the driver!!!!!\n");        return 0;}extern struct bus_type my_bus_type;struct device_driver my_driver = {        .name = "my_driver_device",        .bus = &my_bus_type,        .probe = my_probe,};static __init int hello_init(void){        if(driver_register(&my_driver)) {                printk(KERN_WARNING "driver_register error!\n");                return 1;        }        return 0;}static __exit void hello_exit(void){        driver_unregister(&my_driver);}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Stone");
my_device.c

#include <linux/init.h>#include <linux/module.h>#include <linux/device.h>extern struct bus_type my_bus_type;void my_release(struct device *dev){        return;}struct device my_device = {        .init_name = "my_driver_device",        .bus = &my_bus_type,        .release = my_release,};static __init int hello_init(void){        if(device_register(&my_device)) {                printk(KERN_WARNING "device_register error!\n");                return 1;        }        printk(KERN_INFO "device init!\n");        return 0;}static __exit void hello_exit(void){        device_unregister(&my_device);        printk(KERN_INFO "device exit!\n");}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Stone");











原创粉丝点击