总线控制器驱动(Linux驱动中的platform总线详解)
平台总线是学习linux驱动必须掌握的知识点。
一、概念
嵌入式系统中有很多物理总线:I2c、SPI、USB、uart、PCIE、APB、AHB。
Linux从2.6开始加入了驱动管理和注册的新机制。平台总线是虚拟总线,不是物理总线。
与PCI和USB相比,它主要用于描述SOC上的片上资源。平台中描述的资源有一个共同点:直接访问CPU总线。
平台设备被分配一个名称(用于驱动程序绑定)和一系列资源,如地址和中断请求号(IRQ)。
设备由platform_device表示,驱动程序由platform_driver注册。
与传统的总线/设备/驱动机制相比,平台由内核管理,使用驱动中的资源,提高了代码的安全性和可移植性。
二、平台
1.站台总线的两种最重要的结构。
平台维护的所有驱动程序必须由以下结构定义:
平台_驱动程序
结构平台_驱动程序{
int (*probe)(结构平台_设备*);//
int (*remove)(结构平台_设备*);
void (*shutdown)(结构平台_设备*);
int (*suspend)(结构平台_设备*,pm _消息_t状态);
int (*resume)(结构平台_设备*);
结构设备驱动程序驱动程序;
const struct platform _ device _ id * id _ table;
bool prevent _ deferred _ probe
};
该结构用于对站台总线进行注册和驱动,
成员含义
Probe当驱动和硬件信息匹配成功时,会调用probe函数,驱动资源的所有注册和初始化都会放在probe函数中。
Remove硬件信息已经删除,或者驱动已经卸载,这些都要释放,释放资源的操作放在这个函数里。
struct device_driver驱动内核维护的所有驱动都必须包含这个成员,通常使用driver-"名称来匹配设备。
const struct platform _ device _ id * id _ table往往一个驱动可能同时支持多个硬件,这些硬件的名字都放在结构数组中。
我们在写驱动的时候经常需要填写上面的成员。
平台_设备
平台总线用于描述设备硬件信息的结构,包括硬件的所有资源(io、内存、中断、DMA等。).
结构平台_设备{
const char * name
int id
bool id _ auto
结构设备开发;
u32数量_资源;
结构资源*资源;
构造结构platform _ device _ id * id _ entry
struct mfd _ cell * mfd _ cell
struct pdev _ archdata archdata
};
成员含义
const char*name设备的名称,用于匹配驱动程序。
struct devicedev内核中维护的所有设备都必须包含此成员。
u32num_resources资源的数量
Struct resource*resource描述资源。
必须实现struct devicedev-》release()。
其中描述了硬件信息的成员结构资源。
0x139d0000
结构资源{
resource_size_t开始;//指示资源的起始值,
resource_size_t结束;//指示资源最后一个字节的地址。如果是中断,end和satrt是一样的。
const char * name//不要写
无符号长标志;//资源的类型
结构资源*父级,*同级,*子级;
};
标志的类型描述
#定义io资源_内存0x 00000200//内存
#定义io资源_ IRQ0x 00000400//中断
内核管理的所有驱动都必须包含一个名为struct device_driver,men描述的硬件的成员,并且必须包含struct device结构的成员。//女性
结构设备驱动程序{
const char * name
struct bus _ type * bus
结构模块*所有者;
const char * mod _ name
bool suppress _ bind _ attrs
_match_table的_ device _ id *的const struct
const结构acpi _ device _ id * acpi _ match _ table;
int (*probe)(结构设备*开发);
int(* remove)(struct device * dev);
void (*shutdown)(结构设备*开发);
int(*暂停)(结构设备*dev,pm_message_t状态);
int(* resume)(struct device * dev);
const struct attribute _ group * * groups;
构造结构dev _ pm _ ops * pm
struct driver _ private * p;
};
其中:
常量字符*名称
用于和硬件进行匹配。
内核描述硬件,必须包含结构设备结构体成员:
结构设备{
结构设备*父设备;
struct device _ private * p;
结构对象
const char * init _ name
构造结构设备类型*类型
结构互斥体互斥体;/*要同步调用的互斥体
*它的驱动程序。
*/
结构总线类型*总线
结构设备驱动程序*驱动程序
void *平台_数据
结构开发_项目管理_信息能力
结构开发_项目管理_域*项目管理_域
#ifdef CONFIG_PINCTRL
结构开发引脚信息*引脚;
#endif
#ifdef配置_NUMA
int numa _ node
#endif
u64 * dma _ mask
u64相干_ dma _ mask
结构设备_ dma _参数* dma _参数;
struct list _ head dma _ pools
struct DMA _ coherent _ mem * DMA _ mem;
#ifdef CONFIG_DMA_CMA
结构cma * cma _ area
#endif
结构开发_建筑数据建筑数据
结构设备节点*的节点
结构acpi _开发_节点acpi _节点
dev _ t devt
u32 id
自旋锁_ t devres _ lock
结构列表_头设备_头
结构列表_节点节点_类
结构类*类
const struct attribute _ group * * groups;
无效(*释放)(结构设备*开发);
结构iommu _ group * iommu _ group
bool offline _ disabled:1;
弯曲件离线:1;
};
其中:
无效(*释放)(结构设备*开发);
不能为空。
2.如何注册
要用注册一个平台驱动的步骤
1)注册驱动平台_设备_寄存器
/**
*平台设备注册-添加平台级设备
* @pdev:我们正在添加的平台设备
*/
(同Internationalorganizations)国际组织平台设备寄存器(结构平台设备*pdev)
{
device _ initialize(pdev-》dev);
arch _ setup _ pdev _ arch数据(pdev);
返回平台_设备_添加(pdev);
}
2) 注册设备平台_驱动程序_寄存器
#定义平台_驱动程序_寄存器(drv)
_ _平台驱动程序寄存器(drv,THIS _模块)
三、举例
1.开发步骤
平台总线下驱动的开发步骤是:
设备
需要实现的结构体是:平台_设备。
1)初始化资源结构变量
2)初始化平台_设备结构变量
3)向系统注册设备:平台_设备_寄存器。
以上三步,必须在设备驱动加载前完成,即执行平台_驱动_寄存器()之前,原因是驱动注册时需要匹配内核中所有已注册的设备名。
平台_驱动_寄存器()中添加设备到内核最终还是调用的设备_添加函数。
平台_设备_添加和设备_添加最主要的区别是多了一步插入资源(p,r),即将平台资源(资源)添加进内核,由内核统一管理。
驱动
驱动注册中,需要实现的结构体是:平台驱动程序。
在驱动程序的初始化函数中,调用了平台_驱动_寄存器()注册平台_驱动程序。
需要注意的是:平台驱动程序和平台_设备中的名字变量的值必须是相同的【在不考虑设备树情况下,关于设备树,后面会写新的文章详细讲述】 。
这样在平台_驱动_寄存器()注册时,会将当前注册的平台_驱动程序中的名字变量的值和已注册的所有平台_设备中的名字变量的值进行比较,只有找到具有相同名称的平台_设备才能注册成功。
当注册成功时,会调用平台_驱动程序结构元素调查函数指针。
实例一
本例比较简单,只用于测试平台_驱动程序和平台_设备是否可以匹配成功。
左边是平台_设备结构体注册的代码,右边是平台_驱动程序结构体注册的代码。
平台_驱动程序定义和注册:
1 #包括《linux/init.h》
2 #包括《linux/module.h》
3 #包括《linux/platform_device.h》
4 #包括《linux/ioport.h》
5
6静态int hello_probe(结构平台设备*pdev)
7 {
8 printk(“匹配正常
");
9返回0;
10 }
11静态int hello _ remove(结构平台设备* pdev)
12 {
13 printk(“你好_删除
");
14返回0;
15 }
16静态结构平台_驱动程序hello_driver=
17 {
18 .probe=hello_probe,
19 .driver.name="duang",
20 .remove=hello_remove,
21 };
22静态int hello_init(void)
23 {
24 printk("hello_init
");
25返回平台_驱动_注册(hello _ driver);
26 }
27静态void hello_exit(void)
28 {
29 printk("hello_exit
");
30平台_驱动_注销(你好_驱动);
31返回;
32 }
33模块_许可证(“GPL”);
34模块_初始化(hello _ init);
35模块_出口(hello _ exit);
平台_设备定义和注册:
1 #包括《linux/init.h》
2 #包括《linux/module.h》
3 #包括《linux/platform_device.h》
4 #包括《linux/ioport.h》
5
6静态void hello_release(结构设备*开发)
7 {
8返回;
9 }
10静态结构平台_设备你好设备=
11 {
12 .name="duang",
13 .id=-1,
14 .dev.release=hello_release,
15 };
16
17
18静态int hello_init(void)
19 {
20 printk("hello_init
");
21返回平台_设备_寄存器(hello _ device);
22
23 }
24静态void hello_exit(void)
25 {
26 printk("hello_exit
");
27平台_设备_注销(你好_设备);
28返回;
29 }
30 MODULE _ LICENSE(“GPL”);
31模块_初始化(hello _ init);
32模块_出口(hello _ exit);
该程序只用于测试平台框架是否可以成功匹配,结构平台_设备你好_设备并没有设置任何硬件信息。
Makfile
1 ifneq ($(KERNELRELEASE),)
2 obj-m:=device.o driver.o
3其他
4 KDIR:=/lib/modules/$(shell uname-r)/build
5 PWD :=$(壳牌PWD)
6所有:
七个make -C $(KDIR) M=$(PWD)模块
8清洁:
9 rm -f * .ko * .o * .西蒙兹*。cmd *.mod.c * .命令
10 endif
该生成文件可以同时将两个C文件编译成击倒文件。
编译:
编译
编译生成的文件:
在这里插入图片描述
加载模块
清空原木信息
sudo dmesg -c
匹配成功
实例2
给结构体平台_设备增加硬件信息,并在内核中能够读取出来。本例向结构体你好设备增加信息如下:
基址寄存器地址0x139d0000,该地址的空间是0x4
中断号199【注意】实际的内核中会把外设的中断号根据硬件id(通常社会学厂商设备社会学的时候会给每一个中断源定义好唯一的ID)计算出一个新的中断号,该中断号会被中央处理器所识别。
设备。c
结构资源res[]={
[0]={。start=0x139d0000。end=0x139d00000x3。flags=IORESOURCE_MEM,
},
[1]={。start=199。end=199。flags=IORESOURCE_IRQ,
},
};
静态结构平台_设备你好设备=
{。name="duang"。id=-1。dev.release=hello_release。数量资源=数组大小(res)。资源=资源,
};
司机。c
静态int hello_probe(结构平台设备*pdev)
{
printk(“匹配正常
");
printk("mem=%x
》,pdev-《资源[0]。开始);
printk("irq=%d
》,pdev-《资源[1]。开始);
//注册中断、申请内存
返回0;
}
重新编译,卸载第一个例子的模块,并清除日志:
制造
sudo rmmod设备
sudo rmmod驱动程序
sudo dmesg -c
执行
由结果可知,探针函数正确读取到了硬件信息。
四、平台_设备是如何管理的?
1.没有设备树
在没有设备树的时候,以三星Cortex-A8 s5pc100为例,硬件信息放在以下位置
archarmmach-s5pc 100 mach-SMD KC 100。c
archarmplat-三星
注册平台_设备
平台_设备定义
这个数组存储了内核启动时需要初始化的硬件的信息。
2.如果有设备树。
内核会有设备初始化的完整代码,在内核启动时会解析并初始化设备树信息,并将硬件信息初始化到相应的链表中。总线匹配成功后,硬件信息将被传递给probe()函数。
四、其他与公交相关的知识点
1.内核总线相关的结构变量
内核维护的所有总线都需要用下面的结构注册一个变量。
结构总线类型{
const char * name
const char * dev _ name
结构设备* dev _ root
struct device _ attribute * dev _ attrs;/*改用dev _ groups
const结构attribute _ group * * bus _ groups
const结构attribute _ group * * dev _ groups
const struct attribute _ group * * drv _ groups;
int (*match)(struct device *dev,struct device _ driver * drv);
int (*uevent)(struct device *dev,struct kobj _ u event _ env * env);
int (*probe)(结构设备*开发);
int(* remove)(struct device * dev);
void (*shutdown)(结构设备*开发);
int(* online)(struct device * dev);
int(* offline)(struct device * dev);
int (*suspend)(结构设备*dev,pm_message_t状态);
int(* resume)(struct device * dev);
const struct dev _ pm _ ops * pm
struct iommu _ ops * iommu _ ops
struct subsys _ private * p;
struct lock _ class _ key lock _ key
};
平台总线变量struct Bus _ Type的定义平台总线类型定义如下:
结构总线类型平台总线类型={。name="平台"。开发组=平台开发组。匹配=平台_匹配。uevent=platform_uevent。pm=平台_开发_ pm _操作,
};
最重要的成员是**。匹配**。
当一个设备的硬件信息注册到platform_bus_type总线时,所有由平台总线维护的驱动程序都将被遍历并按名称匹配。如果硬件信息和驱动相同,则调用驱动的platform_driver -》probe函数,初始化驱动的所有资源,使驱动生效。
当在platform_bus_type总线上注册设备驱动程序时,它将遍历由平台总线维护的所有硬件信息,并按名称匹配它。如果相同,说明硬件信息与驱动匹配,会调用驱动的platform_driver -》probe函数,初始化驱动的所有资源,使驱动生效。
注册位置
driversasePlatform.c
平台_总线_类型的注册
五、注册码流程的详细说明
平滑架构的好处是可以帮助我们定位问题。
1.什么时候调用match函数?
2.什么时候调用探测函数?
以下是上述两个问题代码的调用过程:
代码调用过程
原标题:详细教Linux驱动10平台总线
文章来源:【微信微信官方账号:Linux爱好者】欢迎添加关注!请注明文章出处。
标签:设备平台_
- 1bat的大数据(BAT的大数据来源)
- 2三星s8屏幕上端2(三星s8屏幕上端2个按键)
- 3三星屏幕坏了如何导出(三星屏幕摔坏了如何导出数据么)
- 4红米3x怎么关闭自动更新(红米k40s怎么关闭自动更新)
- 5微信上防止app自动下载软件怎么办(微信上防止app自动下载软件怎么办啊)
- 6押镖多少钱(押镖一个月有多少储备金)
- 7瑞星个人防火墙胡功能(瑞星个人防火墙协议类型有哪些)
- 8cf现在等级是多少(cf等级2020最新)
- 9老滑头多少条鱼(钓鱼老滑头有什么用)
- 10WPS自动调整语法(wps如何修改语法)
- 11dell控制面板防火墙(dell的防火墙怎么关闭)
- 12丑女技能升多少(丑女技能需要满级吗)
- 13智能家居系统怎么样(智能家居系统好吗)
- 14戴尔屏幕(戴尔屏幕闪烁)
- 15y85屏幕信息(vivoy85息屏显示时间怎么设置)
- 16魅蓝note3屏幕出现方格(魅蓝note屏幕竖条纹)
- 17v8手指按屏幕(触屏手指)
- 18金为液晶广告机(液晶广告机lb420)
- 19三星显示器怎么校色(三星显示器 调色)
- 20hkc显示器dvi音频(hkc显示器有音响么)
- 21康佳液晶智能电视机(康佳液晶智能电视机怎么样)
- 22做液晶画板电脑(做液晶画板电脑怎么操作)
- 23液晶屏极化现象原理(液晶屏极化现象原理是什么)
- 24企业网络安全防火墙(企业网络防护)
- 256splus黑屏屏幕不亮(苹果6s plus屏幕突然黑屏)
- 26充电导致屏幕失灵(充电导致屏幕失灵怎么办)
- 27超极本屏幕旋转(笔记本电脑屏幕旋转,怎么转过来?)
- 28igmp防火墙(防火墙配置ipv6)
- 29荣耀王者多少经验(王者荣耀经验多少一级)
- 30lol老将还剩多少(qg老将)