android - IR 遥控器无效

本文分析了一次因SDK升级导致红外遥控器无法使用的故障。通过检查驱动代码、设备节点和输入事件处理流程,最终发现问题是由于错误地设置了按键状态值。文章详细记录了问题定位与解决过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

由于升级了SDK导致遥控器无法使用,对于ir驱动的代码没有进行修改,完全一致,升级前遥控器可以使用,但升级使用不了。

问题分析:

1、驱动加打印,确认按键消息是否有发送

void ir_input_event_irCallback(void *pParam, int iParam)

        调用了input_report_key及input_sync进行按键发送了,这块应该没有问题 


2、上层利用android系统自带的 getevent 获取键值 

D:\hisi-tools\sdk-tools>adb shell

	# getevent
	getevent
	add device 1: /dev/input/event1
	name: "nexus ir input"
	could not get driver version for /dev/input/mouse1, Not a typewriter
	add device 2: /dev/input/event0
	name: "Darfon USB Optical Mouse"

logcat 打印:

I/EventHub( 1794): New keyboard: device->id=0x10000 devname='nexus ir input' propName='hw.keyboards.65536.devname'keylayout='/system/usr/keylayout/qwerty.kl'
I/EventHub( 1794): New device: path=/dev/input/event1 name=nexus ir input id=0x10000 (of 0x1) index=1 fd=102 classes=0x1


说明设备创建成功,不存在没有设备结点的问题,基本上可确认发送端及接收端的设备注册没有问题

   

 3、确认struct input_dev结构中关于key的相关设定

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];

unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];

key_dev->evbit[0] = BIT_MASK(EV_KEY);
for (i = 0; nexus_ir_input_inputkeys[i].inputev; i++)

set_bit(nexus_ir_input_inputkeys[i].inputev, key_dev->keybit);

没有问题。。。这到低是哪里的问题呢???


4、在linux kernel发送流程中加打印

看看 input_sync 及 input_report_key 的执行流程

代码路径:

drivers/input/input.c 

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{

input_event(dev, EV_KEY, code, !!value);

}


static inline void input_sync(struct input_dev *dev)
{

input_event(dev, EV_SYN, SYN_REPORT, 0);

}


都是调用 input_event --> input_handle_event() --> 这里需要重点关注,这就是真正处理键case点:

static void input_handle_event(struct input_dev *dev,
			       unsigned int type, unsigned int code, int value)
{
	int disposition = INPUT_IGNORE_EVENT;

	printk(KERN_ERR "input_handle_event call..(type=%d,code=%d) \n",type,code);
	switch (type) {

	case EV_SYN:
		switch (code) {
		case SYN_CONFIG:
			disposition = INPUT_PASS_TO_ALL;
			break;

		case SYN_REPORT:
			if (!dev->sync) {
				dev->sync = 1;
				disposition = INPUT_PASS_TO_HANDLERS;
			}
			break;
		case SYN_MT_REPORT:
			dev->sync = 0;
			disposition = INPUT_PASS_TO_HANDLERS;
			break;
		}
		break;

	case EV_KEY:
		if (is_event_supported(code, dev->keybit, KEY_MAX) &&
		    !!test_bit(code, dev->key) != value) {

			if (value != 2) {
				__change_bit(code, dev->key);
				if (value)
					input_start_autorepeat(dev, code);
				else
					input_stop_autorepeat(dev);
			}

			disposition = INPUT_PASS_TO_HANDLERS;
		}
		break;
		
		...
	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN){
		printk(KERN_ERR "input_handle_event INPUT_IGNORE_EVENT");
		dev->sync = 0;
	}


	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event){
		printk(KERN_ERR "input_handle_event INPUT_PASS_TO_DEVICE");
		dev->event(dev, type, code, value);
	}


	if (disposition & INPUT_PASS_TO_HANDLERS){
		printk(KERN_ERR "input_handle_event INPUT_PASS_TO_HANDLERS");
		input_pass_event(dev, type, code, value);
	}	
}


在 EV_KEY 及 最后面的三个if条件加打印,即可找到问题所在了。

原因:

input_report_key(nexus_ir_input_event_device.input_key_dev, nexus_ir_input_inputkeys[i].inputev, irEvent.repeat);
input_sync(nexus_ir_input_event_device.input_key_dev);
input_report_key(nexus_ir_input_event_device.input_key_dev, nexus_ir_input_inputkeys[i].inputev, 0);
input_sync(nexus_ir_input_event_device.input_key_dev);


irEvent.repeat 这个值为false即0,导致 

case EV_KEY:
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
    !!test_bit(code, dev->key) != value) {

里判定失败,不会进入,,,,从而引发后面三个if条件全部错了。。


正确流程:

<3>input_handle_event call..(type=2,code=0) 
<3>input_handle_event INPUT_IGNORE_EVENT
<3>input_handle_event INPUT_PASS_TO_HANDLERS
<3>input_handle_event call..(type=2,code=1) 
<3>input_handle_event call..(type=2,code=8) 
<3>input_handle_event call..(type=0,code=0) 
<3>input_handle_event INPUT_PASS_TO_HANDLERS


问题解决:

input_report_key(nexus_ir_input_event_device.input_key_dev, nexus_ir_input_inputkeys[i].inputev,1); 

非常容易撒,,,,哈哈,可这个问题花了我1个小时过10分钟,再记录下这个问题记录20分钟,哈哈。。。。


### Android IR Pass 实现与使用 在Android开发中,IR(Intermediate Representation)Pass 的实现通常涉及到编译器优化阶段中的中间表示形式。LLVM 是一种常用的编译框架,在其 JIT 编译过程中可以通过 ORC API 来构建自定义的 JIT 引擎[^1]。这些工具可以被用来动态生成和优化代码。 #### 什么是IR Pass? IR Pass 是指对程序的中间表示进行的一系列转换操作。它可以在编译的不同阶段应用,目的是改进代码性能或者满足特定需求。例如,通过 LLVM 提供的功能,开发者能够编写自己的 Pass 来修改或增强目标平台上的二进制文件行为。 #### Android 中的应用场景 虽然 Android 平台主要依赖于 Dalvik 或 ART 进行字节码解释和运行时优化,但在某些高级用例下也可能涉及 IR Pass 技术。比如: - **NDK 开发**: 当利用 NDK 构建高性能原生模块时,可能会借助 LLVM 对 C/C++ 源代码进行更深层次的优化。 - **JIT/AOT 编译**: 类似于 BuildingAJIT 教程所描述的内容,ART 使用 AOT 和 JIT 结合的方式来提升应用程序启动速度以及整体效率。 下面是一个简单的例子展示如何基于 LLVM 创建一个基本的 Function Pass: ```cpp #include "llvm/IR/Function.h" #include "llvm/Pass.h" using namespace llvm; struct MyCustomPass : public FunctionPass { static char ID; MyCustomPass() : FunctionPass(ID) {} bool runOnFunction(Function &F) override { errs() << "Visiting function: " << F.getName() << "\n"; // Add your transformation logic here. return false; // Return true if you modify the function. } }; char MyCustomPass::ID = 0; static RegisterPass<MyCustomPass> X("my-pass", "My Custom LLVM Pass"); ``` 此代码片段展示了怎样注册一个新的函数级 pass,并打印出正在访问的所有函数名称作为演示目的。实际项目里可以根据具体业务逻辑扩展此类功能。 另外需要注意的是,尽管 Chi API 主要针对相机管道配置进行了设计[^2],但它体现了灵活适配不同硬件特性的设计理念;这同样适用于其他领域内的定制化解决方案——包括但不限于引入新的编译期变换规则以适应移动设备资源约束条件下的最佳实践。 最后关于指令加载位置问题,一般情况下取址后的指令会被存放到指令寄存器(IR)[^3]而非程序计数器(PC),因为后者负责记录即将被执行的下一条指令地址而不是当前正待解析的数据本身。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值