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

(本章基于: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");











  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stone8761

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值