7.2.5. 设计说明¶
7.2.5.1. 源码说明¶
CIR模块的源码位于:linux-5.10/drivers/media/rc/artinchip-cir.c
7.2.5.2. 模块架构¶
linux内核中rc的基本框架如下图所示:
 
红外信号的编码和解码工作由内核负责完成。在完成编码后,应用层需要发送的信号被编码为一系列的带有宽度的高低电平(pulse/space),CIR driver在发送端就是需要将这一系列的pulse/space写入发送FIFO,发送出去。在接收红外信号时,CIR driver需要将接收到的一系列高低电平送入到rc core进行解码,最终将解码得到的scancode和keycode反馈到输入子系统,最终送给app程序完成红外信号的接收。所以,CIR驱动的主要任务有:
- 将编码得到的高低电平信号以游码的形式写入TX-FIFO,发送红外信号 
- 将CIR模块接收的RX-FIFO中的游码正确表示为高低电平的形式,相邻的高电平或低电平需要进行合并。 
- 根据用户空间传递的红外参数,对CIR的底层寄存器进行配置,如配置载波频率,配置占空比等 
由于红外信号的数据量都很少,所以在红外信号的发送端,一般是利用循环将所有的数据一次性全部发送出去,而不会采用中断或DMA的方式。在红外信号的接收端,一般是采用中断的方式进行数据的接收,在接收完成后,调用相应的解码函数进行解码。CIR模块可以支持任何的红外协议,对不同红外协议的支持可以通过对载波配置寄存器的设置来实现。CIR驱动中默认配置的是支持NEC协议。
7.2.5.3. 关键流程设计¶
7.2.5.3.1. 初始化流程¶
CIR模块的初始化流程如下:
- 释放clock和reset信号 
- 调用rc_allocate_device为rc_dev结构体分配空间 
- 设置载波的占空比为33%。读取dts中linux,rc-map-name的属性值。若为空,则默认使用内核中的空表 
- 注册红外设备 
- 读取dts中的rx-level属性值,设置RX空闲时的状态 
- 设置噪声阈值,激活阈值,空闲阈值等底层配置 
- 设置载波配置寄存器,驱动中默认配置的是38K载波(NEC协议) 
- 使能CIR中断,发送器,接收器 
7.2.5.3.2. 中断处理流程¶
CIR模块使能RX的溢出中断、RXFIFO可用中断、接收完成中断。
中断执行流程如下:
- 读取中断状态寄存器和接收状态寄存器 
- 清空所有中断标志位 
- 若为RXFIFO可用中断或接收完成中断,判断RXFIFO是否为空,非空则读取RXFIFO中数据个数,并逐个从RXFIFO中读取数据。若不是这两个中断,则跳转到5 
- 将每次从RXFIFO中读出的游码解析为正确的高低电平宽度,并调用ir_raw_event_store_with_filter将解析后的数据存储到kfifo中 
- 若为接收溢出中断,则调用ir_raw_event_reset,清空kfifo中的数据 
- 若为接收完成中断,此处以完成对所有数据的接收,调用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 | 
| 注意事项 |