平台 | 内核版本 | 安卓版本 |
---|---|---|
Hi3751V811 | Linux4.1 | Android8.0 |
系统键值是通用的,其知识点是通用的,因此通过本次学习可以举一反三。
RC子系统的相关代码路径为:android/device/hisilicon/bigfish/sdk/source/kernel/linux.4.9.y/drivers/media/rc
RC核心(RC Core) | RC Core 负责 RC 设备及事件管理 |
协议原始脉冲 解码器(RC Decoders) | RC Decoders 实现对 IR 数 据的解析并通过 Input 系统上报按键值 |
按键映射表(RC Keymaps) | 键值表 |
红外输入设备驱动(RC Device Driver) | 负责向 RC Core 报告脉冲 RAW 数据, 以及将红外数据调制成协议波形后通过硬件发送 |
LIRC(Linux Infrared Remote Control )接口 | LIRC Interface 实现与 user space 的交互,将接收到 IR RAW 数据提供给应用层,也可以将应用写入的数据发送给 RC Core,并通过 RC Device 发送出去 |
RC decoders
模块用软件的方法实现对原始脉冲进行解码。解码器用一个 ir_raw_handler
结构表示。
目录:android/device/hisilicon/bigfish/sdk/source/kernel/linux.4.9.y/drivers/media/rc/rc-core-priv.h
struct ir_raw_handler {
struct list_head list;
u64 protocols; /* which are handled by this handler */
int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
/* These two should only be used by the lirc decoder */
int (*raw_register)(struct rc_dev *dev);
int (*raw_unregister)(struct rc_dev *dev);
};
RC Decider 通过如下两个函数进行注册和卸载(android/device/hisilicon/bigfish/sdk/source/kernel/linux.4.9.y/drivers/media/rc/rc-ir-raw.c
)
/*
* Extension interface - used to register the IR decoders
*/
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
从函数原型可以看出所有注册的Decoder
放在一个全局链表ir_raw_handler->list
,
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
{
struct ir_raw_event_ctrl *raw;
mutex_lock(&ir_raw_handler_lock);
list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
if (ir_raw_handler->raw_register)
list_for_each_entry(raw, &ir_raw_client_list, list)
ir_raw_handler->raw_register(raw->dev);
mutex_lock(&available_protocols_lock);
available_protocols |= ir_raw_handler->protocols;
mutex_unlock(&available_protocols_lock);
mutex_unlock(&ir_raw_handler_lock);
return 0;
}
EXPORT_SYMBOL(ir_raw_handler_register);
注意, 此时当任何一个解码器返回一个错误, 后面的解码器不会被执行,所以不要将不使用的解码器加载到内核中。 LIRC Decoder
也做为一个特殊 Decoder
进行注册, 注册时raw_register
函数被调用创建 lirc dev
, 应用层边可以通过标准文件接口与 lirc
进行交互, 即前面提到
的 lirc interface
。
Decoder
的主体就是 一个 decode
函数, RC Core
会将驱动报告的每个脉冲都传递到 decode
函数, 而decode
函数的实现就是一个状态机,每一次输入导致进入下一状态, 直到一次解码完成, 然后返回起始状态进行下次解码。
LIRC
中, 每个脉冲(包括脉冲间隔)用一个 ir_raw_event
结构表示:android/device/hisilicon/bigfish/sdk/source/kernel/linux.4.9.y/include/media/rc-core.h
struct ir_raw_event {
union {
u32 duration; /*时间宽度, 以 ns 为单位, 一个 0ns 的脉冲表示重新开始解码 */
u32 carrier;
};
u8 duty_cycle;
unsigned pulse:1; //是脉冲, 还是空闲
unsigned reset:1;
unsigned timeout:1;
unsigned carrier_report:1;
};
lirc 中对于脉冲宽度的比较使用 eq_margin()、 geq_margin()函数, 它允许宽度值在二分之一单元上下波动。 RC Decoder 的完整实现可参考 NEC Decoder 的实现:
bool geq_margin(unsigned d1, unsigned d2, unsigned margin)
bool eq_margin(unsigned d1, unsigned d2, unsigned margin)
RC Keymaps
都放在rc/keymaps
目录下。 不同的遥控器有不同的按键映射, 按键映射模块的作用就是将扫描码与Linux input
系统的标准事件对应起来。 用户可以自己定义按键映射, 如android/device/hisilicon/bigfish/sdk/source/kernel/linux.4.9.y/drivers/media/rc/keymaps/rc-imon-mce.c
就是添加的自定义 NEC Code
映射表, 其主体就是一个 rc_map_table
结构数组, 每个元素是一对按键映射, 即扫描值和 input
系统的 key code
对应。
/* mce-mode imon mce remote key table */
static struct rc_map_table imon_mce[] = {
/* keys sorted mostly by frequency of use to optimize lookups */
{ 0x800ff415, KEY_REWIND },
{ 0x800ff414, KEY_FASTFORWARD },
{ 0x800ff41b, KEY_PREVIOUS },
{ 0x800ff41a, KEY_NEXT },
通过 rc_map_register
函数注册一个按键映射到 RC
系统中, rc_map_list
保存已注册的 rc_map
, 新定义 rc_map
时, rc_type
指定按键映射使用的 IR
协议, 在 RC Decoder
上报按键时, 会与这里定义的 IR
协议类型进行匹配, 如果匹配成功则取对应的按键上报。 RC
设备驱动中设定的 keymap name
对应此处定义的 name
成员, rc core
根据name
匹配当前使用的映射表。
static struct rc_map_list empty_map = {
.map = {
.scan = empty,
.size = ARRAY_SIZE(empty),
.rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_EMPTY,
}
};
RC(Remote Control)
设备驱动负责向 RC Core
报告脉冲 RAW
数据, 以及将红外数据调制成协议波形后通过硬件发送。 RC
设备用 rc_dev
结构描述:
文件目录:android/device/hisilicon/bigfish/sdk/source/kernel/linux.4.9.y/include/media/rc-core.h
struct rc_dev {
struct device dev;
atomic_t initialized;
const struct attribute_group *sysfs_groups[5];
const char *input_name;
const char *input_phys;
struct input_id input_id;
char *driver_name;
const char *map_name;
struct rc_map rc_map;
struct mutex lock;
unsigned int minor;
struct ir_raw_event_ctrl *raw;
struct input_dev *input_dev;
enum rc_driver_type driver_type;
bool idle;
u64 allowed_protocols;
u64 enabled_protocols;
u64 allowed_wakeup_protocols;
u64 enabled_wakeup_protocols;
struct rc_scancode_filter scancode_filter;
struct rc_scancode_filter scancode_wakeup_filter;
u32 scancode_mask;
u32 users;
void *priv;
spinlock_t keylock;
bool keypressed;
unsigned long keyup_jiffies;
struct timer_list timer_keyup;
u32 last_keycode;
enum rc_type last_protocol;
u32 last_scancode;
u8 last_toggle;
u32 timeout;
u32 min_timeout;
u32 max_timeout;
u32 rx_resolution;
u32 tx_resolution;
int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
int (*change_wakeup_protocol)(struct rc_dev *dev, u64 *rc_type);
int (*open)(struct rc_dev *dev);
void (*close)(struct rc_dev *dev);
int (*s_tx_mask)(struct rc_dev *dev, u32 mask);
int (*s_tx_carrier)(struct rc_dev *dev, u32 carrier);
int (*s_tx_duty_cycle)(struct rc_dev *dev, u32 duty_cycle);
int (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max);
int (*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n);
void (*s_idle)(struct rc_dev *dev, bool enable);
int (*s_learning_mode)(struct rc_dev *dev, int enable);
int (*s_carrier_report) (struct rc_dev *dev, int enable);
int (*s_filter)(struct rc_dev *dev,
struct rc_scancode_filter *filter);
int (*s_wakeup_filter)(struct rc_dev *dev,
struct rc_scancode_filter *filter);
int (*s_timeout)(struct rc_dev *dev,
unsigned int timeout);
};
设备注册和卸载:
int rc_register_device(struct rc_dev *dev)
void rc_unregister_device(struct rc_dev *dev)
首先, 重复是自动的, 它使用了 input 子系统的 REP 功能。 当第一次向 RC core 报一个扫描码事件时,RC Core 会向 input 子系统报告相应的按键事件, 并启动一个定时器, 该定时器在超时后会上报对应按键的松开事件。 之后若在 250ms(这个值等于 input 子系统的 rep 延时的默认值)内该设备又报告了同一个扫描码, 这时只是将定时器再推后 250ms, 并不报告新的按键事件, 也就是说按键的重复由 input 系统处理。