传统写法:
按照字符驱动编写步骤一一编写。每个引脚的配置都要单独写一个函数,或者映射它的物理内存到一个虚拟内存中
设备总线驱动模型:
(1)将使用led的引脚配置单独写成一个结构体,只需要提供要配置哪个引脚(如GPIO1_3)即可完成GPIO的配置
(2)但是这样子 每种资源都要定义一个resource如:led_resource、key_resource等,这样子不现实
(3)统一用一个platform_device结构体来定义资源,定义用哪个引脚、寄存器是多少
(4)对于硬件的操作也用一个platform_driver结构体来定义,固定的驱动程序放在该结构体内,如何write\read等
如下所示,led_device会对应led_drv, 每种资源都去对应它相应的驱动程序
每种资源的device都会有一个.c,每次修改不同的引脚时,都会去改动到,会有大量的重复的.c,更换单板后需要修改的更多
设备树由此产生:(位于内核之外)
设备树:
内核之外给每个单板定义一个配置文件dts:会说明灯用哪个引脚,对于硬件资源会在该文件中指定
dtb:由dts编译成后,会传给内核,内核会解析dtb文件,构建出一系列的 platform_device结构体,(相当于自动加载了硬件资源信息)
但是对于引脚寄存器的操作依旧需要自己编写。
但无论是直接定义platform_device结构体还是由设备树来定义,最后都要和相应的platform_driver匹配
共有三种方式(有先后):
先看platform_device,去platform_driver中找,不管谁先注册,device和driver都会两两比较
①derver_override:若指定了驱动的名字,则非这个驱动不嫁
②name:去驱动的id_table中找,id_table中说明了该驱动能支持的设备
③name:最后去找driver.name,看名字是否匹配
(由bus中platform_match判断)
匹配成功后probe被调用:
(1)分配/设置/注册file_operations; (应用程序会依据主次设备号来找到要用的file_operations)
(2)根据Dev确定硬件(Dev会提供配置哪个IO口、哪些寄存器的地址等)
(3)使用ioremap映射寄存器;
(4)操作寄存器(给寄存器赋值配置)
resource中指定平台中包含资源IO、中断、DMA、LED等等: