Linux驱动之总线

1、总线存在意义

在Linux内核中,编写驱动一般都要经历:申请注册设备号、注册操作方法集、硬件初始化、创建设备节点,虽然设备不同,但是每个设备驱动的编写都要经历这几步,在这些流程步骤中,只有硬件初始化随着设备不同,会存在很大差异,但是其他步骤都是一模一样的,为了提高代码重用,降低驱动开发的复杂度,引入了总线概念:在编写代码时,将设备硬件信息和操作逻辑剥离,硬件信息独立在device中,操作逻辑在driver中,这样在设备硬件信息变动时,只需要修改device就可以了

2、总线结构

总线框架将整个驱动分成3个部分,每个部分都定义了响应的结构体:device、bus、driver:

/*
bus_type类型中关于总线的属性成员不止下列这些,但是这里只以常用的作说明
*/

struct bus_type {
	const char		*name; //总线名称,最后driver和device是不是属于同一总线,就全看他相不相同
	int (*match)(struct device *dev, struct device_driver *drv);//需要我们在自定义总线的时候去实现的匹配规则函数,也就是说driver和device互相匹配规则的实现
	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);//生成/sys/bus下的结构,不需要我们关心,由内核提供
	int (*probe)(struct device *dev); //当match匹配成功返回1的时候,才会调用该函数
	int (*remove)(struct device *dev);//当总线卸载时调用
};

驱动结构体:

/*
总线中对驱动的常见描述
*/
struct device_driver {
	const char		*name; //驱动和设备用来匹配的名称
	struct bus_type		*bus; //该驱动所属的总线名称
	int (*probe) (struct device *dev); //当驱动注册的时候,和设备匹配之后调用的探测函数,一般用来完成对设备的硬件初始化、方法注册
	int (*remove) (struct device *dev);//卸载驱动的时候执行,和probe执行内容相反
};

设备结构体:

/*
描述设备对象信息
*/
struct device {
	const char		*init_name; /* 设备匹配名称 */
	struct bus_type	*bus;		/* 设备所属总线名称 */
	void	(*release)(struct device *dev);/*设备注销时调用的回收数据函数*/
    void		*platform_data;	/* 描述设备信息的自定义结构体指针 */	
};

3、创建流程

(1)单独创建自定义总线的模块并注册

注意对描述总线结构体的变量进行符号导出

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <debug.h>//自己定义的dbgprintk调试打印接口,这里要注意,如果在Ubuntu里面使用内核打印的时候,Ubuntu12.04默认将内核输出对应的超级终端为1(切换时直接ctrl+alt+f1-f6,终端1就是f1)


int mybus_match(struct device *dev, struct device_driver *drv)
{
	dbgprintk("in mybus_match");

	return 1;
}


struct bus_type mybus = {
	.name = "mybus",
	.match = mybus_match,
};


static int __init mybus_init(void)
{
	int ret = 0;

	//1、注册总线
	ret = bus_register(&mybus);
	if(ret){
		dbgprintk("bus register err!");
	}

	dbgprintk("mybus init !");

	return ret;
}

static void __exit mybus_exit(void)
{
	dbgprintk("mybus exit !");
	bus_unregister(&mybus);
}

EXPORT_SYMBOL(mybus); //一定要导出,driver和device需要使用

module_init(mybus_init);
module_exit(mybus_exit);
MODULE_LICENSE("GPL");

(2)创建驱动模块并注册

注意外部声明描述总线结构体的变量,在编译模块的时候和总线定义模块在一个Makefile中编译(使用到总线模块导出符号)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <debug.h>

extern struct bus_type mybus; //声明,而这时候需要用到总线模块中的符号导出,这需要将二者放在一个Makefile中编译

int mydrv_probe (struct device *dev)
{
	dbgprintk("driver matched device successed!");
	return 0;
}
int mydrv_remove (struct device *dev)
{
	dbgprintk("remove device !");
	return 0;
}

static struct device_driver mydrv = {
	.name = "mybus",
	.bus = &mybus,
	.probe = mydrv_probe,
	.remove = mydrv_remove,
};

static int __init mybus_drv_init(void)
{
	int ret = 0;
	dbgprintk("mybus drv init !");
	
	//1、注册driver
	ret = driver_register(&mydrv);
	if(ret){
		dbgprintk("driver register error !");
		return ret;
	}

	return ret;
}

static void __exit mybus_drv_exit(void)
{
	dbgprintk("mybus is exit!");
	driver_unregister(&mydrv);
}

module_init(mybus_drv_init);
module_exit(mybus_drv_exit);
MODULE_LICENSE("GPL");

(3)创建设备模块并注册

注意外部声明描述总线结构体的变量,同时自定义设备数据,在编译模块的时候和总线定义模块在一个Makefile中编译(使用到总线模块导出符号)

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

extern struct bus_type mybus;

struct mydev_desc{
	char *name;
	int irqno;
	unsigned long addr;
};

struct mydev_desc devinfo = {
	.name = "mybus",
	.irqno = 999,
	.addr = 0x40008000,
};

void mydev_release(struct device *dev)
{
	dbgprintk("device release !");
}

struct device mydev = {
	.init_name = "my_device",
	.bus = &mybus,
	.release = mydev_release,
	.platform_data = &devinfo,
};

static int __init mybus_init(void)
{
	int ret = 0;

	//1、注册总线
	ret = device_register(&mydev);
	if(ret<0){
		dbgprintk("device register err!");
	}

	dbgprintk("mydev init !");

	return ret;
}

static void __exit mybus_exit(void)
{
	dbgprintk("mydev  exit !");
	device_unregister(&mydev);
}

EXPORT_SYMBOL(mybus);

module_init(mybus_init);
module_exit(mybus_exit);
MODULE_LICENSE("GPL");

猜你喜欢

转载自blog.csdn.net/CSDNmianfeixiazai001/article/details/83893856