Hi3716C Android IR Remote control driver分析
http://blog.sina.com.cn/s/blog_602f877001019wtx.html
作者:Sam (甄峰) sam_code@hotmail.com
Sam之前一直认为Android各芯片厂商是利用UInput将红外遥控器(IR Remote Control)模拟为Input Device(Keyboard)的。 但今天在察看Hi3716C Android下driver信息时,突然发现ir_keyboad这样一个driver. 于是怀疑海思其实还是使用driver来模拟Input Device的。于是在其代码树内察看。在/froyo/device/hisi/Hi3716C/driver/sdk/msp/android_driver/hi_keypad中找到这个driver源码。
现分析如下:
1. driver入口:
module_init(IR_Keypad_Init);
insmod 时则调用IR_Keypad_Init.
2. 注册platform driver.
retval = platform_device_register(&ir_keypad_dev);
retval = platform_driver_register(&irevent_driver);
关键程序在irevent_driver中的probo中。
2.1:
分配device 资源。
2.2:指出此device会发送什么类型的信息
set_bit(EV_KEY, edev->input->evbit); //键盘。
set_bit(EV_REL, edev->input->evbit); //相对光标,鼠标
//Sam: 指出此Device支持键盘和鼠标设备消息。
// 允许Key为:1--0x1ff
//ESC-- 0x1ff的键和Button都支持。
for (i=1; i<= 0x1ff; i++) {
set_bit(i, edev->input->keybit);
}
//Sam:注意,此处和UInput的set_bit类似。都是指明我们会发送什么Key或者Button。
set_bit(EV_SYN, edev->input->relbit);
set_bit(EV_KEY, edev->input->relbit);
//Sam: 设置支持什么相对Event。但这里写的有点问题,虽然不影响结果。但容易误导自己。正确的写法应该是:
set_bit(REL_X, edev->input->relbit);
set_bit(REL_Y, edev->input->relbit);
2.3:注册input device
将edev->input 设置。之后再注册到input 子系统中
input_register_device(edev->input);
2.4: 注册中断处理程序:
request_irq(edev->irq, IR_Keypad_IntIsr, IRQF_SHARED, "irkeypad_events", edev)
当发生edev->irq中断时,调用IR_Keypak_IntIsr中断服务程序。
2.5:IR硬件初始化:
写一些寄存器。选定IR NEC具体方案等。
中断处理程序:
static irqreturn_t IR_Keypad_IntIsr(int irq, void *dev_id)
当有键按下是,中断处理程序被调用。此时,通过读取register中某些特定值得到按键值。翻译成为KeyCode并发送给Input子系统。
细节:
通过读取Register(#define IR_INTS (IR_REG_BASE + 0x2c))中内容, 判断遥控器是按下,抬起还是状态错误。如果是按下,且value值和上一次一致,则判断是保持。
然后将读出的Register_key与下表比较,如果有匹配,则发送具体的KeyEvent。
const hikeycode Key_Code[] =
{
{IR_KEY_UP ,KEY_UP },// 0x35caff00
{IR_KEY_DOWN ,KEY_DOWN },// 0x2dd2ff00
{IR_KEY_RIGHT ,KEY_LEFT },// 0x6699ff00
{IR_KEY_LEFT ,KEY_RIGHT },// 0x3ec1ff00
{IR_KEY_OK ,KEY_ENTER },// 0x31ceff00
{IR_KEY_BACK ,KEY_BACK },// 0x6f90ff00
{IR_KEY_MENU ,KEY_MENU },// 0x629dff00
{IR_KEY_POWER ,KEY_POWER },// 0x639cff00
{IR_KEY_HOME ,KEY_HOME },// 0x34cbff00
{IR_KEY_VOLADD ,KEY_VOLUMEUP },// 0x7f80ff00
{IR_KEY_VOLSUB ,KEY_VOLUMEDOWN },// 0x7e81ff00
{IR_KEY_MUTE ,KEY_MUTE },// 0x22ddff00
{IR_KEY_1 ,KEY_1 },// 0x6d92ff00
{IR_KEY_2 ,KEY_2 },// 0x6c93ff00
{IR_KEY_3 ,KEY_3 },// 0x33ccff00
{IR_KEY_4 ,KEY_4 },// 0x718eff00
{IR_KEY_5 ,KEY_5 },// 0x708fff00
{IR_KEY_6 ,KEY_6 },// 0x37c8ff00
{IR_KEY_7 ,KEY_7 },// 0x758aff00
{IR_KEY_8 ,KEY_8 },// 0x748bff00
{IR_KEY_9 ,KEY_9 },// 0x3bc4ff00
{IR_KEY_0 ,KEY_0 },// 0x7887ff00
{IR_KEY_F1 ,KEY_F1 },// 0x7b84ff00
{IR_KEY_F2 ,KEY_F2 },// 0x7689ff00
{IR_KEY_F3 ,KEY_F3 },// 0x26d9ff00
{IR_KEY_F4 ,KEY_F4 },// 0x6996ff00
{IR_KEY_SEARCH ,KEY_SEARCH },// 0x6897ff00
{IR_KEY_REWIND ,KEY_REWIND },// 0x25daff00
{IR_KEY_FORWARD ,KEY_FORWARD },// 0x29d6ff00
{IR_KEY_STOP ,KEY_STOP },// 0x2fd0ff00
{IR_KEY_SETUP ,KEY_SETUP },// 0x6a95ff00
{IR_KEY_INFO ,KEY_INFO },// 0x38c7ff00
{IR_KEY_AUDIO ,KEY_AUDIO },// 0x2ed1ff00
{IR_KEY_SUBTITLE ,KEY_SUBTITLE },// 0x738cff00
{IR_KEY_BACKSPACE ,KEY_BACKSPACE },// 0x7788ff00
{IR_KEY_PLAYPAUSE ,KEY_PLAYPAUSE },// 0x3cc3ff00
{IR_KEY_FAVORITES ,KEY_FAVORITES },// 0x6b94ff00
{IR_KEY_CHANNELUP ,KEY_CHANNELUP },// 0x7a85ff00
{IR_KEY_CHANNELDOWN ,KEY_CHANNELDOWN },// 0x7986ff00
{IR_KEY_PAGEDOWN ,KEY_PAGEDOWN },// 0x6798ff00
{IR_KEY_PAGEUP ,KEY_PAGEUP },// 0x30cfff00
{IR_KEY_IME ,KEY_FN_1 },// 0x609fff00
{IR_KEY_MORE ,KEY_FN_2 },// 0x39c6ff00
{IR_KEY_BTV ,KEY_FN_D },// 0x649bff00
{IR_KEY_VOD ,KEY_FN_E },// 0x659aff00
{IR_KEY_NVOD ,KEY_FN_F },// 0x3fc0ff00
{IR_KEY_NPVR ,KEY_FN_S },// 0x3dc2ff00
{IR_KEY_SEEK ,KEY_FN_B },// 0x7d82ff00
};
注1:
关于Platform driver的注册:
要用注册一个platform驱动的步骤:
1,注册设备platform_device_register
2,注册驱动platform_driver_register
注册时候的两个名字必须一样,才能匹配。
1,注册设备platform_device_register
2,注册驱动platform_driver_register
注册时候的两个名字必须一样,才能匹配。
platform_driver_register(&xx_driver)
会向系统注册xx_driver这个驱动程序,这个函数会以
xx_driver中的.name内容,搜索系统注册的device中有没有这个platform_device,如果有,就会执行
platform_driver(也就是xx_driver的类型)中的.probe函数。
注2:
input_dev 中内容讲解:
它用来描述一个Input
Device.
const
char *name;
//Device的名字
const char *phys;
//physical path to the device in the system
hierarchy
const char *uniq;
//唯一识别号。(如果设备存在)
struct input_id id; // id
of the device (struct input_id)
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
//指出这个device都支持哪种类型的event.
例如:EV_KEY,EV_REL (详见注3)
unsigned long
keybit[BITS_TO_LONGS(KEY_CNT)];
//这个device可以支持的Key和Button(如果evbit支持EV_KEY)
unsigned long
relbit[BITS_TO_LONGS(REL_CNT)];
//这个device可以支持的轴相对信息。(鼠标是相对)
unsigned long
absbit[BITS_TO_LONGS(ABS_CNT)]; //
这个device可以支持的轴绝对信息。(Touch是绝对)
unsigned long
mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long
ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long
sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long
ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long
swbit[BITS_TO_LONGS(SW_CNT)];
注3:不同类型的Input Event:
#define EV_SYN
0x00
表示设备支持所有的事件
#define EV_KEY
0x01
键盘或者按键,表示一个键码
#define EV_REL
0x02
鼠标设备,表示一个相对的光标位置结果
#define EV_ABS
0x03
手写板产生的值,其是一个绝对整数值
#define EV_MSC
0x04
其他类型
#define EV_LED
0x11
LED灯设备
#define EV_SND
0x12
蜂鸣器,输入声音
#define EV_REP
0x14
允许重复按键类型
#define EV_PWR
0x16
电源管理事件
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)

浙公网安备 33010602011771号