[Hi3751V811][Android8.0]RC子系统

平台 内核版本 安卓版本
Hi3751V811 Linux4.1 Android8.0

系统键值是通用的,其知识点是通用的,因此通过本次学习可以举一反三。

文章目录

  • 1、Linux下RC子系统
    • 1.1、RC Decoders
    • 1.2、RC Keymaps
    • 1.3、RC 设备驱动
    • 1.4、RC 对按住按键时重复事件的处理

1、Linux下RC子系统

RC子系统的相关代码路径为:android/device/hisilicon/bigfish/sdk/source/kernel/linux.4.9.y/drivers/media/rc
[Hi3751V811][Android8.0]RC子系统_第1张图片

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 发送出去

1.1、RC Decoders

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)

1.2、RC Keymaps

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,
	}
};

1.3、RC 设备驱动

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)
  1. 分配一个 RC 设备, rc_allocate_device();
  2. 对 RC 设备进行一些初始化设置, 包括 input 设备的参数, RC 设备的驱动类型, 使用的 key_ma,支持的 IR decoder 协议;
  3. 将分配的 RC 设备结构的地址作为参数调用 rc_register_device()注册, 以后与 lirc 核心的交互都是通过这个 rc 设备结构的地址进行的。

1.4、RC 对按住按键时重复事件的处理

首先, 重复是自动的, 它使用了 input 子系统的 REP 功能。 当第一次向 RC core 报一个扫描码事件时,RC Core 会向 input 子系统报告相应的按键事件, 并启动一个定时器, 该定时器在超时后会上报对应按键的松开事件。 之后若在 250ms(这个值等于 input 子系统的 rep 延时的默认值)内该设备又报告了同一个扫描码, 这时只是将定时器再推后 250ms, 并不报告新的按键事件, 也就是说按键的重复由 input 系统处理。

你可能感兴趣的:([Hi3751V811][Android8.0]RC子系统)