Linux驱动----总线

总线

在这里插入图片描述

总线的作用是将设备与驱动关联起来,或者称为管理起来,完成匹配
总线是在sys/bus目录下的,linux文件系统已经预设了一些总线,例如IIC总线,SPI总线,USB总线等,我们也可以自己创建自己的总线,以下是创建自己的总线需要注意的地方:

struct bus_type  : 总线对象,描述一个总线,管理device和driver
struct bus_type {
	const char *name;
	int (*match)(struct device *dev, struct device_driver *drv);
}

注册和注销总线

int bus_register(struct bus_type *bus);
void bus_unregister(struct bus_type *bus);

注册总线和注销总线需要分别写在模块初始化和模块退出的部分,这里不再赘述。

需要将device和driver分别放入我们的总线中进行匹配,因此需要先创建device和driver对象

device对象----描述设备信息,包括地址,中断号和其他的一些自定义数据

设备对象,用于描述设备信息,包括地址,中断号和其他的一些自定义数据。

struct device{
	struct kobject kobj,  //所有对象的父类
	const char *init_name,  //在总线中的名字,用于做匹配,在sys/bus/mybus/device/名字
	struct bus_type *bus,  //依附于总线的对象,也就是在哪个bus中
	void *platform_data, //自定义的数据,可以指向任何数据类型
	.....
}

注册和注销device对象----指将device注册到mybus总线

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

driver对象----描述设备驱动的方法(操作地址和中断)

struct device_driver{
	const char *name,  //driver的名字, 用于匹配 sys/bus/mybus/driver/名字
	struct bus_type, //指向该对象依附于哪个总线的
	int (*probe)(struct device* dev); //如果device和driver匹配后,driver要做的事情
	int (*remove)(struct device* dev); //如果device和driver从总线移除之后,driver要做的事情
}

注册和注销driver对象----指将driver注册到mybus总线

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

总线匹配成功之后,如何自动调用driver的probe方法

1、实现bus对象中的match方法

int match_mybus(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;
}

2、保证driver和device中的名字一致,总线中调用match去匹配,匹配成功才能自动执行drv中的probe方法执行匹配成功后的操作

struct device_driver my_driver = {
	.name = "fs_dev_drv", 
	.bus = &mybus,
	.probe = my_drvprobe,
};

struct my_devinfo deviceinfo = {
	.name = "testdev",
	.irqno = 0000,
	.addr = 0x8888,
};
struct device my_device = {
	.init_name = "fs_dev_drv",
	.bus = &mybus,
	.platform_data = &deviceinfo,  //通过platform指向一个描述硬件设备的结构体
};
int probe(struct device* dev);  //可以实现例如通过probe函数获取dev中某个设备的中断号,地址等

struct my_devinfo *pdesc;
int my_drvprobe(struct device* dev){
	pdesc = (struct my_devinfo* )dev->platform_data;
	printk("name = %s\n", pdesc->name);
	printk("irqno = %d\n", pdesc->irqno);
	unsigned long *paddr = ioremap(pdesc->addr, 8);
	return 0;
}

平台总线

平台总线作用

用于平台升级:当soc升级的时候,相似的驱动代码需要编写很多次,其中会有大量重复,因此需要平台总线

device(中断/地址)和driver(操作逻辑)分离,这样就可以在平台升/级的时候修改device中的信息(中断/地址)即可,实现一个driver驱动多个相似的模块,并且修改的代码量很少。

平台总线中的三元素

1、bus:platform_bus不需要自己创建,开机的时候自动创建

struct bus_type platform_bus_type = {
	.name = "platform",
	.dev_group = platform_dev_groups,
	.match = platform_match,
	.uevent = platform_uevent,
	.pm = &platform_dev_pm_ops,
};

匹配方法:
优先匹配driver中的id_table, 里面包含了支持不同平台的名字,
直接匹配driver中的名字和device中的名字

int platform_match(struct device* dev, struct device_driver* drv);
int platform_match(pdev, pdrv){
	if(pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev)  != NULL; //先匹配driver中的id_table
	return (strcmp(pdev->name, drv->name) == 0);匹配driver中的名字和device中的名字
}

2、device对象

struct platform_device{
	const char *name, //用于做匹配
	int id, //一般直接给-1
	struct device dev, //继承了device父类
	u32	num_resources, //资源的个数
	struct resource *resource, // 资源:包括了一个设备的地址和中断
}

3、driver对象

struct platform_driver {
	int (*probe)(struct platform_device *),  //匹配成功后调用的函数
	int (*remove)(struct platform_device *),  //device移除后调用的函数
	const struct platform_device_id *id_table,  //如果driver支持多个平台,在列表中写出来
	struct device_driver driver,  //继承了drvier父类
};
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值