Linux驱动开发之BUS总线编程

一,设备驱动模型


1.Linux设备驱动模型的由来


首先回顾设备驱动编写的一般流程
【1】实现入口函数module_init()和模块卸载函数module_exit();
【2】申请设备号,register_chrdev(); -----> (与内核相关)
【3】利用udev/mdev机制创建设备文件结点class_create(),device_create(); ------>(与内核相关)
【4】硬件初始化:1.io资源映射ioremap(),内核提供gpio库函数 ; 2.注册中断。------->(与硬件相关)
【5】构建file_operation结构体-------->(与内核相关)
【6】实现操作硬件的方法xxx_open(),xxx_write()…

结论:整个流程除了第四部分与硬件有关,其他都是相似的操作方法,为了方便的(不重复造轮子)编写设备驱动,节省人力,所以提出了设备驱动模型,简化了设备驱动编写的流程。


2.设备驱动模型框架


在这里插入图片描述

可以通过sysfs虚拟文件系统查看总线对象(以usb为例)
在这里插入图片描述


二,BUS总线模型编程


概念图
在这里插入图片描述


1.总线对象


【1】 struct bus_type:总线对象,描述一个总线,管理device和driver,完匹配。

   struct bus_type {        //只列举重要成员
	const char		*name;   //总线名字
	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】构建一个总线

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

//实例化一个bus对象
struct bus_type mybus = {
	.name = "mybus",
	.match = mybus_match,
};

EXPORT_SYMBOL(mybus);       //导出总线对象,让device对象和driver对象使用
	
static int __init mybus_init(void)
{
	printk("------%s---------\n",__FUNCTION__);
	int ret;
	
	//构建一个总线  结果:/sys/bus/mybus
	ret = bus_register(&mybus);
	if(ret != 0)
	{
		printk("bus_register error\n");
		return ret;
	}
	return 0;
}

static void __exit mybus_exit(void)
{
	printk("------%s---------\n",__FUNCTION__);
	bus_unregister(&mybus);
}

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

2.device对象


【1】device对象:设备对象,描述设备信息,包括地址,中断等其他数据

struct device {                  //只列举重要成员
	struct kobject kobj;         //所有对象的父类
	const char *init_name;      //在/sys/bus/mybus/device的名字,用于在总线中匹配
	struct bus_type	*bus;		 //指向该device对象依附的总线对象
	void *platform_data;	 //自定义的数据,指向任何类型的数据
};

【2】注册和注销总线

int device_register(struct device *dev);
void device_unregister(struct device *dev);

【3】编写设备对象
定义一个描述设备的信息的结构体,匹配成功之后让driver对象在总线中拿到device对象的信息,实现分离

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

extern struct bus_type mybus;

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

};

struct mydev_desc deviofo = {
	.name = "hqs",
	.irqno = 8877,
	.addr = 0x12345678,
};

void mydev_release(struct device* dev)
{
	printk("------%s---------\n",__FUNCTION__);
}

//构建一个device对象
struct device mydev = {
	.init_name = "fsdev_drv",
	.bus = &mybus,
	.release = mydev_release,
	.platform_data = &deviofo,
};
static int __init mydev_init(void)
{
	printk("------%s---------\n",__FUNCTION__);
	int ret;
	//将device注册到总线中
	ret = device_register(&mydev);
	if(ret < 0)
	{
		printk("device_register error\n");
		return ret;
	}
	return 0;
}

static void __exit mydev_exit(void)
{
	printk("------%s---------\n",__FUNCTION__);
	device_unregister(&mydev);
}

module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");


3.driver对象


【1】driver对象:描述设备驱动发的方法

struct device_driver {          //只列举重要成员
	const char		*name;      //在/sys/bus/mybus/driver的名字,用于在总线中匹配
	struct bus_type		*bus;    //指向该device对象依附的总线对象
	int (*probe) (struct device *dev);   //device和driver匹配之后要做的事情
	int (*remove) (struct device *dev);   //device和driver分离之后要做的事情
};

【2】注册和注销总线

int driver_register(struct device_driver *drv);
void driver_unregister(struct device_driver *drv);

【3】编写driver对象
匹配成功之后可以在总线中拿到device对象的数据,具体实现在probe函数里

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

extern struct bus_type mybus;

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

struct mydev_desc* pdesc;

int mydrv_probe(struct device *dev)
{
	printk("------%s---------\n",__FUNCTION__);
	pdesc = (struct mydev_desc*)dev->platform_data;

	printk("name =%s\n",pdesc->name);
	printk("irqno = %d\n",pdesc->irqno);
	unsigned long * paddr = ioremap(pdesc->addr, 8);
	return 0;
}

int mydrv_remove (struct device *dev)
{
	printk("------%s---------\n",__FUNCTION__);
	return 0;
}

//构建一个driver对象
struct device_driver mydrv = {
	.name = "fsdev_drv",
	.bus = &mybus,
	.probe = mydrv_probe,
	.remove = mydrv_remove,
};

static int __init mydrv_init(void)
{
	printk("------%s---------\n",__FUNCTION__);
	int ret;
	//将device注册到总线中
	ret = driver_register(&mydrv);
	if(ret < 0)
	{
		printk("driver_register error\n");
		return ret;
	}
	return 0;
}

static void __exit mydrv_exit(void)
{
	printk("------%s---------\n",__FUNCTION__);
	driver_unregister(&mydrv);	
}

module_init(mydrv_init);
module_exit(mydrv_exit);
MODULE_LICENSE("GPL");


4.device对象和driver对象匹配


【1】实现BUS对象中的match方法(按device对象的名字和driver对象中的名字相匹配)
要注意的是不能直接用device对象中的init_name,而要用device对象中继承的struct kobject kobj;里面的成员name不然会报错

int mybus_match(struct device *dev, struct device_driver *drv)
{
	//如果匹配成功,match方法一定要返回一个1,失败返回0
	if(! strncmp(drv->name,dev->kobj.name,strlen(drv->name)))
	{
		printk("match ok\n");
		return 1;
	}
	else
	{	
		printk("match failed\n");
		return 0;	 
	}
	return 0;
}

//实例化一个bus对象
struct bus_type mybus = {
	.name = "mybus",
	.match = mybus_match,
};

【2】保证device对象和driver对象的名字一样:比如这里都使用"fsdev_drv"就能保证能匹配成功

//构建一个device对象
struct device mydev = {
	.init_name = "fsdev_drv",
	.bus = &mybus,
	.release = mydev_release,
	.platform_data = &deviofo,
};
//构建一个driver对象
struct device_driver mydrv = {
	.name = "fsdev_drv",
	.bus = &mybus,
	.probe = mydrv_probe,
	.remove = mydrv_remove,
};
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值