platform机制实现驱动层分离

1.我们之前学习的input子系统的分层解构如下
在这里插入图片描述
如上图所示,分层就是将一个复杂的工作分成了4层, 分而做之,降低难度,每一层专注于自己的事情, 系统只将其中的核心层和事件处理层写好了,所以我们只需要来写驱动层即可,接下来我们来分析platform机制以及分离概念

2.分离概念
优点:
1)将所有设备挂接到一个虚拟的总线上,方便sysfs节点和设备电源的管理

2)使得驱动代码,具有更好的扩展性和跨平台性,就不会因为新的平台而再次编写驱动
介绍:
分离就是在驱动层中使用platform机制把硬件相关的代码(固定的,如板子的网卡、中断地址)和驱动(会根据程序作变动,如点哪一个灯)分离开来,即要编写两个文件:dev.c和drv.c(platform设备和platform驱动)

3.platform机制
基本内容:
platform会存在/sys/bus/里面

如下图所示, platform目录下会有两个文件,分别就是platform设备和platform驱动
在这里插入图片描述

  1. device设备
    挂接在platform总线下的设备, platform_device结构体类型
  2. driver驱动
    挂接在platform总线下,是个与某种设备相对于的驱动, platform_driver结构体类型
  3. platform总线
    是个全局变量,为platform_bus_type,属于虚拟设备总线,通过这个总线将设备和驱动联系起来,属于Linux中bus的一种
    该platform_bus_type的结构体定义如下所示(位于drivers/base):
struct bus_type platform_bus_type = {              
.name              = "platform",             //设备名称
.dev_attrs        = platform_dev_attrs,                 //设备属性、含获取sys文件名,该总线会放在/sys/bus下
.match              = platform_match,   //匹配设备和驱动,匹配成功就调用driver的.probe函数
.uevent             = platform_uevent,  //消息传递,比如热插拔操作
.suspend         = platform_suspend,     //电源管理的低功耗挂起
.suspend_late          = platform_suspend_late,  
.resume_early         = platform_resume_early,
.resume           = platform_resume,    //恢复
};

驱动、设备注册匹配图如下所示:
在这里插入图片描述
只要有一方注册,就会调用platform_bus_type的.match匹配函数,来找对方,成功就调用driver驱动结构体里的.probe函数来使总线将设备和驱动联系起来

4.实例-分析driver驱动:
我们以/drivers/input/keybard/gpio_keys.c内核自带的示例程序为例,
它的代码中只有driver驱动,因为是个示例程序,所以没有device硬件设备代码

4.1发现在gpio_keys.c中有1个全局变量driver驱动:

struct platform_driver gpio_keys_device_driver = {  //定义一个platform_driver类型驱动

    .probe      = gpio_keys_probe,                //设备的检测,当匹配成功就会调用这个函数(需要自己编写)   
    .remove     = __devexit_p(gpio_keys_remove), //删除设备(需要自己编写)
    .driver     = {
            .name  = "gpio-keys",               //驱动名称,用来与设备名称匹配用的
         }
};

4.2然后来找找这个gpio_keys_device_driver被谁用到
发现在驱动层init入口函数中通过platform_driver_register()来注册diver驱动
在驱动层exit出口函数中通过platform_driver_unregister()函数来注销diver驱动
代码如下:

static int __init gpio_keys_init(void)    //init出口函数
{
   return platform_driver_register(&gpio_keys_device_driver);   //注册driver驱动
}
static void __exit gpio_keys_exit(void)   //exit出口函数
{
   platform_driver_unregister(&gpio_keys_device_driver);   //注销driver驱动
}

4.3我们进来platform_driver_register(),看它是如何注册diver的,注册到哪里?、
platform_driver_register()函数如下:

int platform_driver_register(struct platform_driver *drv)
{
   drv->driver.bus = &platform_bus_type;                //(1)挂接到虚拟总线platform_bus_type上
   if (drv->probe)
         drv->driver.probe = platform_drv_probe;
   if (drv->remove)
        drv->driver.remove = platform_drv_remove;
   if (drv->shutdown)
        drv->driver.shutdown = platform_drv_shutdown;
   if (drv->suspend)
        drv->driver.suspend = platform_drv_suspend;
    if (drv->resume)
        drv->driver.resume = platform_drv_resume;

   return driver_register(&drv->driver);              //(2) 注册到driver目录下
}

(1) 挂接到虚拟总线platform_bus_type上,然后会调用platform_bus_type下的platform_match匹配函数,来匹配device和driver的名字,其中driver的名字
platform_match()匹配函数如下所示:

static int platform_match(struct device * dev, struct device_driver * drv)
{
/*找到所有的device设备*/
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); //找BUS_ID_SIZE次
}

若名字匹配成功,则调用drvice的.probe成员函数

(2)然后放到/sys/bus/platform/driver目录下,其中driver_register()函数就是用来创建dirver目录的

补充
在这里插入图片描述
一边的“device”结构体和另一边的“较稳定的 drivice 代码”的联系:
“device_add()”除了将“devcie”结构放到 bus 的“dev 链表”之外,还会从另一边的“drv”
链表中取表元即某个“driver”结构,用总线里的一个(.match)函数来作比较,看另一边的
“driver”是否支持一边的“device”。若是能够支持,则接着调用软件驱动部分的“.probe”
函数。
"driver_register()"会将“bus_drv_dev”模型中的较稳定代码“driver”结构体放到虚拟总线的
某个链表(drv 链表)中。从另一边的“dev”链表中取出每一个“device”结构用 bus 中的
“.match”函数来作比较,若支持则调用“.probe”函数。

在这里插入图片描述
左右两个注册就建立起来的一种机制。在“.probe”函数中做的事件由自已决定,
打印一句话,或注册一个字符设备,再或注册一个“input_dev”结构体等等都是由自已决定。
强制的把一个驱动程序分为左右两边这种机制而已,可以把这套东西放在任何地方,这里的
“driver”只是个结构体不要被这个名字迷惑,“device”也只是个结构体,里面放什么内容
都是由自已决定的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值