7.2.5. 设计说明

7.2.5.1. 源码说明

CIR模块的源码位于:linux-5.10/drivers/media/rc/zx-cir.c

7.2.5.2. 模块架构

linux内核中rc的基本框架如下图所示:

../../../_images/rc_arch.png

红外信号的编码和解码工作由内核负责完成。在完成编码后,应用层需要发送的信号被编码为一系列的带有宽度的高低电平(pulse/space),CIR driver在发送端就是需要将这一系列的pulse/space写入发送FIFO,发送出去。在接收红外信号时,CIR driver需要将接收到的一系列高低电平送入到rc core进行解码,最终将解码得到的scancode和keycode反馈到输入子系统,最终送给app程序完成红外信号的接收。所以,CIR驱动的主要任务有:

  1. 将编码得到的高低电平信号以游码的形式写入TX-FIFO,发送红外信号

  2. 将CIR模块接收的RX-FIFO中的游码正确表示为高低电平的形式,相邻的高电平或低电平需要进行合并。

  3. 根据用户空间传递的红外参数,对CIR的底层寄存器进行配置,如配置载波频率,配置占空比等

由于红外信号的数据量都很少,所以在红外信号的发送端,一般是利用循环将所有的数据一次性全部发送出去,而不会采用中断或DMA的方式。在红外信号的接收端,一般是采用中断的方式进行数据的接收,在接收完成后,调用相应的解码函数进行解码。CIR模块可以支持任何的红外协议,对不同红外协议的支持可以通过对载波配置寄存器的设置来实现。CIR驱动中默认配置的是支持NEC协议。

7.2.5.3. 关键流程设计

7.2.5.3.1. 初始化流程

CIR模块的初始化流程如下:

  1. 释放clock和reset信号

  2. 调用rc_allocate_device为rc_dev结构体分配空间

  3. 设置载波的占空比为33%。读取dts中linux,rc-map-name的属性值。若为空,则默认使用内核中的空表

  4. 注册红外设备

  5. 读取dts中的rx-level属性值,设置RX空闲时的状态

  6. 设置噪声阈值,激活阈值,空闲阈值等底层配置

  7. 设置载波配置寄存器,驱动中默认配置的是38K载波(NEC协议)

  8. 使能CIR中断,发送器,接收器

7.2.5.3.2. 中断处理流程

CIR模块使能RX的溢出中断、RXFIFO可用中断、接收完成中断。

中断执行流程如下:

  1. 读取中断状态寄存器和接收状态寄存器

  2. 清空所有中断标志位

  3. 若为RXFIFO可用中断或接收完成中断,判断RXFIFO是否为空,非空则读取RXFIFO中数据个数,并逐个从RXFIFO中读取数据。若不是这两个中断,则跳转到5

  4. 将每次从RXFIFO中读出的游码解析为正确的高低电平宽度,并调用ir_raw_event_store_with_filter将解析后的数据存储到kfifo中

  5. 若为接收溢出中断,则调用ir_raw_event_reset,清空kfifo中的数据

  6. 若为接收完成中断,此处以完成对所有数据的接收,调用ir_raw_event_handle开始解码

7.2.5.4. 数据结构设计

struct aic_ir {
    spinlock_t      ir_lock;
    struct rc_dev   *rc;
    void __iomem    *base;
    struct clk      *clk;
    struct reset_control *rst;
    const char      *map_name;        /*CIR模块使用的keycode-scancode映射表*/
    unsigned int    tx_duty;      /*发送红外信号时的占空比*/
    int             irq;
    u32             rx_level;             /*指示空闲状态下RX的电平状态*/
    u8              rx_flag;              /*指示RXFIFO中是否已接收到数据*/
};

7.2.5.5. 接口设计

7.2.5.5.1. aic_set_rx_carrier_range

函数原型

static int aic_set_rx_carrier_range(struct rc_dev *rcdev, u32 min, u32 max)

功能说明

设置CIR模块接收器的采样频率

参数定义

rcdev:指向红外设备的指针
min:设置的采样频率最小值
max:设置的采样频率最大值

返回值

执行成功返回0

注意事项

7.2.5.5.2. aic_set_tx_duty_cycle

函数原型

static int aic_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle)

功能说明

设置CIR模块发送红外信号的占空比

参数定义

rcdev:指向红外设备的指针
duty_cycle:需要设置的占空比

返回值

执行成功返回0

注意事项

7.2.5.5.3. aic_set_tx_carrier

函数原型

static int aic_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)

功能说明

设置CIR模块发送信号的载波频率

参数定义

rcdev:指向红外设备的指针
carrier:需要设置的载波频率大小

返回值

执行成功返回0

注意事项

7.2.5.5.4. aic_tx_ir

函数原型

static int aic_tx_ir(struct rc_dev *rcdev, unsigned int *txbuf, unsigned int count)

功能说明

CIR模块发送红外信号的函数

参数定义

rcdev:指向红外设备的指针
txbuf:需要发送的红外信号的缓存
count:需要发送的红外信号在缓存中的个数

返回值

执行成功返回0

注意事项