1.4设备树的引进与体验——总线设备驱动模型

本节使用总线设备驱动模型,点亮和熄灭led小灯。

上一节,在驱动程序中指定引脚,每次修改都需要重新编译内核并且需要查引脚,十分麻烦。使用总线设备驱动模型不用重新编译内核就可以改变引脚

总线设备驱动模型由以下三部分组成:

  1. 总线 —— Bus;
  2. 设备 —— Dev;
  3. 驱动 —— Drv;

其中 Dev 和 Drv 都依赖于Bus(纯软件概念,不涉及硬件设备)。

它们的用途如下:

  1. Dev:指定硬件资源;
  2. Drv:
    a.分配/设置/注册file_operations结构体;

    b.根据Dev指定的硬件资源来操作硬件;

问:在Dev中是如何指定硬件资源的?

答:以面向对象的思想,在内核中定义一个dev时,也是去分配/设置/注册一个结构体,这个结构体是一个平台设备

在\linux-4.19-rc3\include\linux\platform_device.h中,有一个platform_device结构体,dev中会分配/设置/注册这个结构体。

Drv中也是类似的操作,去分配/配置/注册platform_driver结构体。

问: 内核里面有很多Dev,也有很多Drv,怎么知道哪个Dev对应哪个Drv呢?

答:它们之间需要依靠一条总线(Bus)来匹配。

在Bus里面,我们常用的是平台总线(platform bus),在platform bus里面有一个match函数,这个match函数就是来比较匹配Drv和Dev

如果确定某个dev和某个drv匹配,则会调用drv的drv->probe函数。

问:match是怎么匹配Dev和Drv的?

答:在Dev设备的平台设备结构体platform_device中有一个name成员,它就是这个设备的名字

在Drv驱动的platform_driver结构体中有一个id_table成员,这是一个结构体指针,指针指向的结构体有两个成员namedriver_data;还有一个结构体成员driver,driver结构体中有一个name成员。

 

查看platform_match函数,其中of_driver_match_device函数的of是open firmware,开放固件,这个是使用设备树来匹配的,先不管。

后面pdrv->id_table,如果该驱动有id_table的话,就会调用platform_match_id函数。

在platform_match_id函数中,会将id_table的每一项,与dev设备的名字进行匹配。如果两个名字相同,就表示它们是匹配的。

 可以在id_table中添加多个设备名,表示这个驱动支持多款设备,比如:

 这样,即时设置不同的dev名,也可以选择相同的驱动

 如果没有id_table,则直接比较平台设备的名字驱动的drive成员中的名字

综上,优先比较id_table的名字,没有匹配则再比较driver的名字

一旦匹配成功,就调用drv里面的probe函数。

机制讲完,现在开始写代码。

Dev

首先是分配/设置/注册一个platform_device。

resource如下,其中flags设置为IORESOURCE_MEM,由于没有引脚资源,所以设置为mem资源,实际上我们不将它做mem资源使用,会在驱动程序中将引脚读出来,当做引脚使用。

release函数为空。

 

然后,与drv类似,有init函数和exit函数,在init函数中注册platform_device,在exit函数中卸载platform_device。

 

Drv

在之前的led_drv.c的基础上进行修改。

首先,不在代码中写死led_pin。

然后,创建一个platform_driver驱动。

增加probe函数,一旦dev和drv匹配成功,就会调用drv的probe函数。

在probe函数中,获取dev的MEM资源,其中0代表MEM资源的第0个,将start设为led_pin,然后和之前的入口函数一样,创建类和dev设备,删除以前的入口函数。

led_remove函数中卸载字符设备,销毁led_class,删除以前的出口函数。

 

同样需要注册和卸载平台驱动platform_driver。

 

测试

编译完成后将dev和drv的ko库推入板子,将app推入板子。

先insmod drv,可以看到这时候并没有led设备产生,因为bus没有检测到对应的dev设备。

insmod dev设备后,可以在dev目录下看到led设备了。

 然后调用app应用,可以看到根据不同的指令,可以通知小灯点亮或者熄灭。

现在如果需要控制另一个小灯,只要修改dev.c的代码就可以了,drv.c的代码可以不用改动

将控制的引脚改为F6。

重新编译上传,将原来的led_dev设备卸载掉。

 

加载新的led_dev,通过不同的指令可以控制另一个小灯的亮灭。

可以看到,总线设备驱动模型可以把代码分为devdrv两部分,其中drv比较固定的,dev则是用来指定硬件资源

最后,我们来看看注册platform_device和注册platform_driver所触发的match和probe过程是怎么进行的。

可以想象,当我们注册一个platform_device的时候,实际上是将一个platform_device加入到链表中,每次有新的platform_device加入时,就会把platform_driver的链表中的成员一一取出,和这个platform_device进行匹配;同理,platform_driver也是类似的。

所以,无论是先注册platform_device还是先注册platform_driver,都没有关系,结果都是一样的。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值