第12章--Linux设备驱动的软件架构思想

一、Linux驱动的软件架构

Linux设备驱动非常重视软件的可重用和跨平台能力。
在Linux总线、设备和驱动模型中,驱动只管驱动,设备只管设备,总线则负责匹配设备和驱动,而驱动则以标准途径拿到板级信息。
将软件进行分层设计应该是软件工程最基本的一个思想,如果提炼一个input的核心层出来,把跟Linux接口以及整个一套input事件的汇报机制都在这里面实现,显然是非常好的。
在Linux设备驱动框架的设计中,除了有分层设计以外,还有分离的思想。

二、platform设备驱动

1. platform总线、设备与驱动

在Linux2.6以后的设备驱动模型中,需关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。
在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
Linux发明了一种虚拟的总线,成为platfrom总线,相应的设备称为platform_device,而驱动成为platform_driver。

  • 对于Linux2.6 ARM平台而言,对platform_device的定义通常在BSP的板文件中实现,
    在板文件中,将platform_device归纳为一个数组,最终通过platform_add_devices()函数统一注册。
    platform_add_devices()函数可以将平台设备添加到系统中,这个函数的原型为:

    int platform_add_devices(struct platform_device **devs, int num);
    
  • Linux3.x之后,ARM Linux不太喜欢人们以编程的形式去填写platform_device和注册,而倾向于根据设备树中的内容自动展开platfrom_device。

2. platfrom设备资源和数据

在platform_device结构体中resource结构体描述了platform_device的资源,其定义如下所示。

struct resource {
    resource_size_t start;  //资源的开始值
    resource_size_t end;    //资源的结束值
    const char *name;
    unsigned long flags;    //资源的类型
    struct resource *parent, *sibling, *child;
};

设备除了可以定义资源以外,还可以附加一些数据信息platform_data,platform_data的形式是由每个驱动自定义的。

三、设备驱动的分层思想

Linux内核完全是由C语言和汇编语言写成,但是却频繁地使用了面向对象的设计思想。
在设备驱动方面,往往为同类的设备设计了一个框架,而框架中的核心层则实现了该设备通用的一些功能。

1. 输入设备驱动

输入设备(键盘、鼠标和触摸屏等)是典型的字符设备,其一般的工作机理是底层在按键、触摸等动作发生时产生一个中断(或驱动通过Timer定时查询),然后CPU通过SPI、IIC或外部存储器总线读取键值、坐标等数据,并将它们放入一个缓冲区,字符设备驱动管理该缓冲区,而驱动的read()接口让用户可以读取键值、坐标等数据。
显然,在这些工作中,只是中断、读键值/坐标值是与设备相关的,而输入事件的缓冲区管理以及字符设备驱动的file_operations接口则对输入设备是通用的。
基于此,内核设计了输入子系统,由核心层处理公共的工作。输入核心提供了底层输入设备驱动程序所需的API:
① 分配/释放一个输入设备

struct input_dev *input_allocate_device(void);
void input_free_device(struct input_dev *dev);

② 注册/注销输入设备

int __must_check input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *);

③ 报告输入事件

/* 报告指定type、code的输入事件 */
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
/* 报告键值 */
void input_report_key(struct input_dev *dev, unsigned int code, int value);
/* 报告相对坐标 */
void input_report_rel(struct input_dev *dev, unsigned int code, int value);
/* 报告绝对坐标 */
void input_report_abs(struct input_dev *dev, unsigned int code, int value);
/* 报告同步事件 */
void input_sync(struct input_dev *dev);

2. RTC设备驱动

RTC(实时钟)借助电池供电,在系统掉电的情况下依然可以正常计时。它通常还具有产生周期性中断以及闹钟中断的能力,是一种典型的字符设备。
作为一种字符设备驱动,RTC需要有file_operations中接口函数的实现,而这些对于所有的RTC是通用的,只有底层的具体实现是与设备相关的。
因此,drivers/rtc/rtc-dev.c实现了RTC驱动通用的字符设备驱动层,它实现了file_operations的成员函数以及一些通用的关于RTC的控制代码,并向底层导出rtc_device_register()、rtc_device_unregister()以注册和注销RTC;导出rtc_class_ops结构体以描述底层的RTC硬件操作。

3. Framebuffer设备驱动

Framebuffer(帧缓冲)是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。
对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域内写入颜色值,对应的颜色会自动在屏幕上显示。
帧缓冲设备提供给用户空间的file_operations结构体由drivers/video/fbdev/core/fbmem.c中的file_operations提供,而特定帧缓冲设备fb_info结构体的注册、注销以及其中成员的维护,尤其是fb_ops中成员函数的实现则由对应的xxxfb.c文件实现,fb_ops中的成员函数最终会操作LCD控制其硬件寄存器。

4. 终端设备驱动

在Linux系统中,终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端设备。对于嵌入式系统而言,最普遍采用的是UART串行端口,日常生活中简称串口。
Linux内核中tty的层次结构包括tty核心tty_io.c、tty线路规程n_tty.c和tty驱动实例xxx_tty.c,
tty线路规程的工作是以特殊的方式格式化从一个用户或者硬件收到的数据,这种格式化常常采用一个协议转换的形式。

5. misc设备驱动

在Linux驱动中,存在部分字符设备不知道他属于什么类型,这时一般采用miscdevice框架结构。
miscdevice驱动的注册和注销分别用下面两个API:

int misc_register(struct miscdevice *misc);
int misc_deregister(struct miscdevice *misc);

四、主机驱动与外设驱动分离的思想

Linux中的SPI、IIC、USB等子系统都利用了典型的主机驱动和外设驱动分离的想法,让主机端只负责产生总线上的传输波形,而外设端只是通过标准的API来让主机端以适当的波形访问自身。
因此这里面就涉及了4个软件模块:

  1. 主机端的驱动
    根据具体的SPI、IIC、USB等控制器的硬件手册,操作具体的SPI、IIC、USB等控制器,产生总线的各种波形。
  2. 连接主机和外设的纽带
    外设不直接调用主机端的驱动来产生波形,而是调一个标准的API。由这个标准的API把这个波形的传输请求间接的“转发”给了具体的主机端驱动。
  3. 外设端的驱动
    外设接在SPI、IIC、USB这样的总线上,但是它们本身可以是触摸屏、网卡、声卡或者任意一种类型的设备。
    我们在相关的i2c_driver、spi_driver、usb_driver这种xxx_driver的probe()函数中去注册他具体的类型。当这些外设要求SPI、IIC、USB等去访问它的时候,它调用标准API。
  4. 板级逻辑
    板级逻辑用于描述主机和外设是如何互联的,它相当于一个“路由表”。管理互联关系,既不是主机端的责任,也不是外设端的责任,这属于板级逻辑的责任。
    这部分通常出现在arch/arm/mach-xxx下面或者arch/arm/boot/dts下面。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值