Linux 设备驱动分离和分层

本文讨论了Linux驱动程序的管理和优化,重点介绍了驱动的分离与分隔技术,如I2C控制器的统一接口和设备驱动的简化。此外,文章还涵盖了平台总线模型如何提高代码重用性和减少重复,以及编写probe函数时获取硬件资源的方法。
摘要由CSDN通过智能技术生成

        当你失败的时候,身边会有一群关心你的人,他们会问你发生什么事,听听你的失败经验,然后心满意足地离开。

                                                                                                                                        ---- 小新

一.驱动的分离与分隔 

   (1)分离

        对于 Linux 这样一个成熟、庞大、复杂的操作系统,代码的重用性非常重要,否则的话就
会在 Linux 内核中存在大量无意义的重复代码。尤其是驱动程序,因为驱动程序占用了 Linux
内核代码量的大头,如果不对驱动程序加以管理,任由重复的代码肆意增加,那么用不了多久
Linux 内核的文件数量就庞大到无法接受的地步。

 

        显然在 Linux 驱 动程序中这种写法是不推荐的,最好的做法就是每个平台的 I2C 控制器都提供一个统一的接口 (也叫做主机驱动 ) ,每个设备的话也只提供一个驱动程序 ( 设备驱动 ) ,每个设备通过统一的 I2C 接口驱动来访问,这样就可以大大简化驱动文件。

   (2)分隔

        分隔,也就是将主机驱动和设备驱动分隔开来,比如 I2C SPI 等等都会采 用驱动分隔的方式来简化驱动的开发。在实际的驱动开发中,一般 I2C 主机控制器驱动已经由 半导体厂家编写好了,而设备驱动一般也由设备器件的厂家编写好了,我们只需要提供设备信 息即可,比如 I2C 设备的话提供设备连接到了哪个 I2C 接口上, I2C 的速度是多少等等。相当 于将设备信息从设备驱动中剥离开来,驱动使用标准方法去获取到设备信息( 比如从设备树中获 取到设备信息) ,然后根据获取到的设备信息来初始化设备。 这样就相当于驱动只负责驱动, 设备只负责设备,想办法将两者进行匹配即可。这个就是 Linux 中的总线 (bus) 、驱动 (driver) 和 设备(device) 模型,也就是常说的驱动分离。总线就是驱动和设备信息的月老,负责给两者牵线搭桥。
        如图所示:

 

二.驱动分层 

        Linux 下的驱动往往也是分层的,分层的目 的也是为了在不同的层处理不同的内容。以其他书籍或者资料常常使用到的input( 输入子系统, 后面会有专门的章节详细的讲解) 为例,简单介绍一下驱动的分层。 input 子系统负责管理所有 跟输入有关的驱动,包括键盘、鼠标、触摸等,最底层的就是设备原始驱动,负责获取输入设 备的原始值,获取到的输入事件上报给 input 核心层。 input 核心层会处理各种 IO 模型,并且提 供 file_operations 操作集合。我们在编写输入设备驱动的时候只需要处理好输入事件的上报即 可,至于如何处理这些上报的输入事件那是上层去考虑的,我们不用管。可以看出借助分层模 型可以极大的简化我们的驱动编写,对于驱动编写来说非常的友好。

三.Platform 平台驱动模型

        设备驱动模型中,需关心总线、设备和驱动这 3 个实体,总线将设备和驱动绑定。 在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
        
        平台总线模型就是把原来的驱 动 C 文件给分成了俩个 C 文件,一个是 device.c ,一个是 driver.c 把稳定不变的放在 driver.c 里面,需要变得就放在了 device.c 里面。

        1. 平台总线模型就很好地解决了这俩个问题

        (1 )可以提高代码的重用性
        (2 )减少重复性代码。

        2.平台总线模型将设备代码和驱动代码分离

        如图所示:

 

         3.Platform内核源码

22 struct platform_device {
23 const char *name;
24 int id;
25 bool id_auto;
26 struct device dev;
27 u32 num_resources;
28 struct resource *resource;
29
30 const struct platform_device_id *id_entry;
31 char *driver_override; /* Driver name to force a match */
32
33 /* MFD cell pointer */
34 struct mfd_cell *mfd_cell;
35
36 /* arch specific additions */
37 struct pdev_archdata archdata;
38 };

 四.编写 probe 函数的思路

        (1 )从 device.c 里面获得硬件资源,因为我们的平台总线将驱动拆成了俩部分,第一部分是 device.c ,另一 部分是 driver.c 。那么匹配成功了之后, driver.c 要从 device.c 中获得硬件资源,那么 driver.c 就是在 probe 函 数中获得的。
        (2 )获得硬件资源之后,就可以在 probe 函数中注册杂项 / 字符设备,完善 file_operation 结构体,并生成设备节点。
获得硬件资源有两种方法:
        方法一: 直接获取,不推荐
       下面是一段  device.c的内容:
struct resource beep_res[] = {
[0] ={
    .start = 0x020AC000, 
    .end = 0x020AC003, 
    .flags = IORESOURCE_MEM, 
    .name = "GPIO5_DR", }
};
struct platform_device beep_device = {
    .name = "beep_test", 
    .id = -1, 
    .resource=beep_res, 
    .num_resources =ARRAY_SIZE(beep_res), 
    .dev = {
                .release = beep_release
            }
};
        在 driver.c直接通过指针的方式结构体访问里面的参数:
int beep_probe(struct platform_device *pdev){
printk("beep_probe\n");
printk("beep_res is %s\n",pdev->resource[0].name);
return 0;
}
方法二:使用函数来获取资源
         使用函数来获取资源:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我来挖坑啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值