个人理解:
设备驱动:可分为设备(device)和驱动(driver)两个部分(个人理解)
设备:硬件外设相关信息的代码(固定的,如板子的网卡、中断地址,偏硬件)
驱动:对硬件相关的操作,一些机制的实现(偏软件)
按照这种的分离的思想的话,platform平台总线就非常适合。
platform总线概念:
platform的灵魂是:device(设备)driver(驱动)platform_bus(platform总线),其特点是设
备,驱动分层动态的管理和加载。
按照的总线的要求我们注册好device和driver后,bus会在内核启动的时候对二者进行匹配,按照我们定义的device_driver结构体中的.name和.of_match_table各项先后进行匹配。匹配上之后会去就调用driver驱动结构体里的.probe函数来使总线将设备和驱动联系起来。
通过查看/sys/bus/platform/目录,可以看到两个文件:devices和drivers。它们分别用来存放platform的设备和驱动。
就像现在的linux内核中有设备树这个东西,就是更加方便了。我们不需要再去专门去写一个platform_devcie 文件了,只需要设备树文件dts里面的根节点下,写一个自己的设备节点即可。然后我们再写一个plarform_driver与之匹配。
通用部分:
module_init();//修饰入口函数
__init xxxx();//入口函数
platform_driver_register();//注册platform_driver
static struct platform_driver //内部就包含.probe、.、.name、.of_match_table
.of_match_table = 全局的struct of_device_id;//struct of_device_id是结构体数组,可以用于表示多个设备
MODULE_DEVICE_TABLE(,struct of_device_id ....)//用于设备树的节点匹配
如上文说的,当driver和device匹配上之后会去调用调用driver驱动结构体里的.probe函数来使总线将设备和驱动联系起来。
自由发挥部分:
我们这里的应用场景:是AD芯片接CPU的GPIO管脚,
通常在设备树中以 reset-gpios = <&gpio1 15 1>;
来表示gpio,而在驱动中使用gpio号 = of_get_named_gpio(xxxnode, "reset-gpios", 0);
函数返回值来得到gpio号
gpio_request:驱动中要想使用某一个gpio,就必须先调用gpio_request接口来向内核申请,得到允许后才可以去使用这个gpio
gpio_to_irq()通过gpio号得到对应的软件中断号, 该中断号是request_irq()函数的第一个参数.
request_irq()根据软件中断号和中断处理函数,注册中断。
中断的内容这边就简单的描述一下,通过i2c读写相关的寄存器信息(类似分辨率、帧率信息、接口在位状态等)。
通过将这些信息反馈回到应用层,应用层设置判断对应的业务处理,模拟热插拔。
但是在实际的操作的过程中遇到了一个问题就是:i2c无法读取AD寄存器的信息。难道是i2c适配有问题。其实并不是,通过查阅资料发现i2c读写也是中断操作,那么问题就明显了。是中断的嵌套引起的i2c读写异常。
那要怎么解决这个问题呢?
笔者这里采用的是中断底半部机制中的工作队列的方式延迟处理i2c读写。gpio中断处理函数创建一个work 结构体,INIT_WORK()将work和工作处理函数建立关系。工作处理函数执行i2c读写。