IR框架分为四层:IR Driver层,IR core层, Decoder层, Keymap层。
iput_dev层 input_core层 input_handle层 映射层
红外遥控器驱动 类似于输入子系统中的 input_device层 硬件初始化,fops操作
IR Driver层: 需要实现IR Driver的一些init,interrupt处理,file_operations操作等。
IR core层:需要实现提供给decoder层,keymap层的相关接口,raw数据处理接口,input相关接口等。
Decoder层:需要实现不同protocols的解析函数。
Keymap层:需要实现针对不同IR的keymap映射关系。
这里我们根据公司的中性遥控器 为例
IR Driver层代码: kernel\mstar2\drv\ir_mirc\mstar_ir.c
IR CORE层代码: kernel\mstar2\drv\ir_mirc\ir_core.c
protocols: kernel\mstar2\drv\ir_mirc\protocols\ir-nec-decoder.c ==>nec解码 Decoder层
keymaps: kernel\mstar2\drv\ir_mirc\keymaps\keymap-mstar-tv.c ==>把按键的扫描值映射成keycode值 keycode值是上报给android层处理的
IR 的配置有两种:
- Ir_config.h 进行配置,在编译阶段配置好客户要使用的遥控器。 ==>我们公司是使用了这种配置方式
- Ir_config.ini进行配置,可以动态配置客户要使用的遥控器。
两种配置方式可以单独配置使用,也可以同时配置使用。
1> 分析配置文件
文件路径: mstar2/drv/ir_mirc/lr_config.h
#ifndef _IR_CONFIG_H_
#define _IR_CONFIG_H_
#include "mstar_ir.h" //==>这3个.h文件 前两个就是驱动文件的.h文件,ir_common.h文件是我们公司对应的配置文件之一 (定义了头码,解码类型...)
#include "ir_core.h"
#include "ir_common.h"
/****************** For Customer Config Start [can modify by customers] ********************/
//Number of IR should this chip supported 该芯片应支持的IR数: ==> 表示该系统支持2款遥控器
#define IR_SUPPORT_NUM 2
//Add & Modify Customer IR with Differ Headcode Here 在这里添加和修改不同头码的客户IR ==> ir_config这个结构体中的成员就是一种遥控器的信息
static IR_Profile_t ir_config[IR_SUPPORT_NUM]=
{
// {IR_TYPE_NEC,NUM_KEYMAP_MSTAR_TV,0}, // Mstar IR customer code
//{IR_TYPE_TOSHIBA,NUM_KEYMAP_SKYWORTH_TV,0}, // skyworth toshiba ir
//{IR_TYPE_NEC,NUM_KEYMAP_CHANGHONG_TV,0}, // changhong_RL78B /Toshiba CT-90436 IR customer code
//{IR_TYPE_NEC,NUM_KEYMAP_HISENSE_TV,0}, // Hisense IR customer code
//{IR_TYPE_RCA,NUM_KEYMAP_TCL_RCA_TV,0}, // TCL RCA customer code
//{IR_TYPE_P7051,NUM_KEYMAP_P7051_STB,0}, // Panasonic 7051 IR customer code
//{IR_TYPE_RC5, NUM_KEYMAP_RC5_TV, 0}, // RC5 customer code
{IR_TYPE_NEC, NUM_KEYMAP_MSTAR_TV, 0},
//{IR_TYPE_RC6,NUM_KEYMAP_KATHREIN_TV,0}, // Kathrein RC6 customer code
//{IR_TYPE_KONKA,NUM_KEYMAP_KONKA_TV,2},
{IR_TYPE_PANASONIC,NUM_KEYMAP_PANASONIC_TV,2},
};
//IR Debug level for customer setting
static IR_DBG_LEVEL_e ir_dbglevel = IR_DBG_ERR;
//IR Speed level for customer setting
static IR_SPEED_LEVEL_e ir_speed = IR_SPEED_FAST_H;
/****************** For Customer Config End [can modify by customers] ********************/
#endif
代码分析 ir_config:
//Description of IR
typedef struct IR_Profile_s {
IR_Type_e eIRType; //协议类型
u32 u32HeadCode; //头码值
u32 u32IRSpeed; //遥控器灵敏度
}IR_Profile_t;
我们这里配置了两种遥控器{IR_TYPE_NEC, NUM_KEYMAP_MSTAR_TV, 0}, {IR_TYPE_PANASONIC,NUM_KEYMAP_PANASONIC_TV,2},
我们通常使用的是{IR_TYPE_NEC, NUM_KEYMAP_MSTAR_TV, 0}, 即NEC编码协议
NUM_KEYMAP_MSTAR_TV值的来源
|
mstar2/drv/ir_mirc/ir_common.h 文件中定义的 ==>3个头文件之一 ****************** 这就是我们在配置kernel 遥控器信息中的一个步骤
在ir_common.h中为了实现客户的定制化遥控器功能 我们通过宏来区分客户不同的NEC协议的头码
//每个宏定义对应一个客户遥控器
#define CUSTOMER_IR_MSTAR 0
#define CUSTOMER_IR_SYKJWB 1 //中性
#define CUSTOMER_IR_PROMETH_EN 2
#define CONFIG_CUSTOMER_VIEWSONIC 3
#define CONFIG_CUSTOMER_PROWISE 4
#define CONFIG_CUSTOMER_WJCIRTEXT 5
#define CUSTOMER_IR_SELECT CONFIG_CUSTOMER_WJCIRTEXT //CUSTOMER_IR_MSTAR 最终宏
//不同的客户有主见不同的NEC遥控器的头码
#if(CUSTOMER_IR_SELECT == CUSTOMER_IR_SYKJWB)
#define NUM_KEYMAP_MSTAR_TV 0x4040
#elif(CUSTOMER_IR_SELECT == CUSTOMER_IR_PROMETH_EN)
#define NUM_KEYMAP_MSTAR_TV 0x01FE
#elif(CUSTOMER_IR_SELECT == CONFIG_CUSTOMER_VIEWSONIC )
#define NUM_KEYMAP_MSTAR_TV 0x0000
#elif(CUSTOMER_IR_SELECT == CONFIG_CUSTOMER_PROWISE)
#define NUM_KEYMAP_MSTAR_TV 0x20DF
#elif(CUSTOMER_IR_SELECT == CONFIG_CUSTOMER_WJCIRTEXT)
#define NUM_KEYMAP_MSTAR_TV 0x4040
#else
#define NUM_KEYMAP_MSTAR_TV 0x807F
代码分析: 配置IR debug 级别
//IR Debug level for customer setting
static IR_DBG_LEVEL_e ir_dbglevel = IR_DBG_ERR;
==> 默认设置成error打印
关键点: 在IR驱动中 除了在_MDrv_IR_ISR中不能加log打印外,其他地方都能加log进行打印
修改打印级别的方法: *********** *****************
先找到存放打印级别的属性文件,这个属性文件是在 mstar_ir.c中实现的 mstar_ir_drv_probe() --> mstar_ir_creat_sysfs_attr() --> device_create_file(dev, &dev_attr_IRDebug)
find / -name IRDebug ==>先找到该属性文件的路径
echo 4 > xxx/IRDebug ==>修改该属性文件的打印级别
cat xxx/IRDebug ==>查看属性文件的当前打印级别和支持的打印级别
==> 其实这个实现方法 不就是printk中设置7个级别的打印方法吗?
具体操作
IFP:/ #su
IFP:/ # find / -name IRDebug
/sys/devices/ir/IRDebug
IFP:/sys/devices/ir # ls
IRDebug IRProtocols driver modalias subsystem
IREnable IRSpeed driver_override of_node uevent
IREvent IRTimeout input power
开头是大写的文件都是通过函数mstar_ir_creat_sysfs_attr创建的
查看 打印级别
IFP:/sys/devices/ir # cat IRDebug
Current Debug Level: 1
修改打印级别为 4
IFP:/sys/devices/ir #echo 4 > IRDebug
代码分析: 配置IR Speed
//IR Speed level for customer setting
static IR_SPEED_LEVEL_e ir_speed = IR_SPEED_FAST_H; // IR_SPEED_FAST_H == 0 ==> 表示不会附带重复波形,按一下就发送一个波形
ir_speed:要设置的原因 ,因为不同的遥控器的灵敏度可能不同,也许你短按一下按键,发送出去的是好几个重复波形,如果不做处理会就会造成,我按一下,上层相应几下的情况
故需要设置这个属性来过滤附带的重复波形, ir_speed = 2 ==> 过滤两个波形
2> 分析ir_driver驱动文件 mstar_ir.c
//驱动入口函数
module_init(mstar_ir_drv_init_module);
//加载函数
static int __init mstar_ir_drv_init_module(void)
{
int ret = 0;
ret = platform_driver_register(&Mstar_ir_driver); //注册设备驱动 使用了platform框架来实现 input_dev层
if (ret)
{
IRDBG_ERR("Register Mstar IR Platform Driver Failed!");
}
#ifdef CONFIG_MIRC_INPUT_DEVICE
#if(CONFIG_IR_KEYMAP_MSTAR_NEC)
init_key_map_mstar_tv();
#endif
#if(CONFIG_IR_KEYMAP_TCL_RCA)
init_key_map_tcl_tv();
#endif
#if(CONFIG_IR_KEYMAP_TCL)
init_key_map_tcl_tv();
#endif
#if(CONFIG_IR_KEYMAP_CHANGHONG)
init_key_map_changhong_tv();
#endif
#if(CONFIG_IR_KEYMAP_HISENSE)
init_key_map_hisense_tv();
#endif
#if (CONFIG_IR_KEYMAP_HAIER)
init_key_map_haier_tv();
#endif
#if(CONFIG_IR_KEYMAP_KONKA)
init_key_map_konka_tv();
#endif
#if(CONFIG_IR_KEYMAP_SKYWORTH)
init_key_map_skyworth_tv();
#endif
#if(CONFIG_IR_KEYMAP_PANASONIC_7051)
init_key_map_p7051_stb();
#endif
#if(CONFIG_IR_KEYMAP_KATHREIN)
init_key_map_rc6_kathrein();
#endif
#if(CONFIG_IR_KEYMAP_RC5)
init_key_map_rc5_tv();
#endif
#if(CONFIG_IR_KEYMAP_METZ)
init_key_map_metz_rm18();
init_key_map_metz_rm19();
#endif
#if(CONFIG_IR_KEYMAP_PANASONIC)
init_key_map_panasonic_tv();
#endif
#endif
return ret;
}
==>
注册完设备驱动之后,紧接着有注册了多款遥控器,最终通过MIRC_Map_Register将按键映射表添加到链表keymap_list中,方便后面通过scancode 寻找keycode。
#ifdef CONFIG_MIRC_INPUT_DEVICE 这个宏=1
==> kernel根目录下的 .config文件中有如下定义
#
# Mstar IR Config
#
# CONFIG_IR_DYNAMIC_CONFIG is not set
CONFIG_MIRC_INPUT_DEVICE=y
除了直接修改.config文件外,还可以通过make menuconfig来修改配置
查看 ir_mirc目录下的Kconfig文件,内容如下
config MSTAR_IR_REFACTOR
tristate "Mstar IR Driver"
default y
help
Mstar IR decoder driver function
menu "Mstar IR Config"
depends on MSTAR_IR_REFACTOR
config IR_DYNAMIC_CONFIG
depends on MIRC_INPUT_DEVICE
tristate "load ir config(header,protocol,keymap) from /config/ir_config"
default n ==> 对应CONFIG_IR_DYNAMIC_CONFIG is not set
config MIRC_INPUT_DEVICE
bool "IR Key send to input subsystem"
default y ==> 对应CONFIG_MIRC_INPUT_DEVICE=y
if MIRC_INPUT_DEVICE
source "drivers/mstar2/drv/ir_mirc/keymaps/Kconfig"
endif
endmenu
CONFIG_IR_KEYMAP_MSTAR_NEC这个宏 同理查看.config文件有如下定义
CONFIG_IR_KEYMAP_MSTAR_NEC=y
CONFIG_IR_KEYMAP_TCL_RCA=y
CONFIG_IR_KEYMAP_TCL=y
CONFIG_IR_KEYMAP_CHANGHONG=y
CONFIG_IR_KEYMAP_HISENSE=y
CONFIG_IR_KEYMAP_HAIER=y
CONFIG_IR_KEYMAP_KONKA=y
CONFIG_IR_KEYMAP_SKYWORTH=y
CONFIG_IR_KEYMAP_PANASONIC_7051=y
CONFIG_IR_KEYMAP_KATHREIN=y
CONFIG_IR_KEYMAP_RC5=y
CONFIG_IR_KEYMAP_METZ=y
CONFIG_IR_KEYMAP_PANASONIC=y
CONFIG_MSTAR_IOMAP=y
然后配置: 前面的ir_mirc目录下的Kconfig文件中说明如果对应CONFIG_MIRC_INPUT_DEVICE=y就执行mstar2/drv/ir_mirc/keymaps/Kconfig这个文件
mstar2/drv/ir_mirc/keymaps/Kconfig文件的内容
menu "Mstar IR Keymap Select"
depends on MIRC_INPUT_DEVICE
config IR_KEYMAP_MSTAR_NEC
bool "Mstar NEC keymaps"
default y
help
Mstar nec keymap
config IR_KEYMAP_TCL_RCA
bool "TCL RCA keymaps"
default y
help
TCL RCA keymaps
config IR_KEYMAP_TCL
bool "TCL keymaps"
default y
help
TCL tv keymaps
config IR_KEYMAP_CHANGHONG
bool "Changhong IR keymaps"
default y
help
Changhong tv keymaps
config IR_KEYMAP_HISENSE
bool "Hisense IR keymaps"
default y
help
Hisense tv keymaps
config IR_KEYMAP_HAIER
bool "Haier IR keymaps"
default y
help
Haier tv keymaps
config IR_KEYMAP_KONKA
bool "Konka IR keymaps"
default y
help
Konka tv keymaps
config IR_KEYMAP_SKYWORTH
bool "Skyworth IR keymaps"
default y
help
Skyworth tv keymaps
config IR_KEYMAP_PANASONIC_7051
bool "Pnasonic 7051 IR keymaps"
default y
help
panasonic tv keymaps
config IR_KEYMAP_KATHREIN
bool "Kathrein RC6 MODE_6A IR keymaps"
default y
help
Kathrein tv keymaps
config IR_KEYMAP_RC5
bool "RC5 IR keymaps"
default y
help
RC5 tv keymaps
config IR_KEYMAP_METZ
bool "metz IR keymaps"
default y
help
metz tv keymaps
config IR_KEYMAP_PANASONIC
bool "Panasonic IR keymaps"
default y
help
Panasonic tv keymaps
endmenu
==> 显然这里就是要我们配置要注册哪些遥控器了
这里我们以我们公司现在的映射文件keymap-mstar-tv.c为例简单跟读
#if(CONFIG_IR_KEYMAP_MSTAR_NEC)
init_key_map_mstar_tv();
#endif
这里init_key_map_mstar_tv函数就是keymap-mstar-tv.c文件中的加载函数 故这里就相当于加载了keymap-mstar-tv.c文件对应的映射驱动
******** ************************************这里开始分析keymap-mstar-tv.c文件 即映射文件: 扫描码映射成keycode,然后将映射表注册到ir_core中的存放所有映射表的链表中
int init_key_map_mstar_tv(void)
{
return MIRC_Map_Register(&mstar_tv_map); //将该文件配置的映射表添加到ir_core中统一存放映射表的链表keymap_list中, 目的是为了方便后面通过scancode 寻找keycode 即后面 有按键按下,我知道了它的扫描码,直接去这个链表中寻找它对应的keycode值即可
}
keymap-mstar-tv.c文件的按键映射表 mstar_tv_map
static struct key_map_list mstar_tv_map = {
.map = {
.scan = mstar_tv, //具体的映射关系表
.size = ARRAY_SIZE(mstar_tv), //多少个按键映射对
.name = NAME_KEYMAP_MSTAR_TV, //该按键映射表的名称 在ir_common.h中定义 #define NAME_KEYMAP_MSTAR_TV "ir-mstar-tv"
.headcode = NUM_KEYMAP_MSTAR_TV, //头码 在ir_common.h中定义 #define NUM_KEYMAP_MSTAR_TV 0x4040
}
};
具体的映射关系表的定义
static struct key_map_table mstar_tv[] = {
#if(CUSTOMER_IR_SELECT == CUSTOMER_IR_SYKJWB)
{ 0x0A, KEY_POWER }, //POWER
{ 0x0F, KEY_MUTE }, //MUTE
{ 0x40, KEY_MENU }, //MENU
{ 0x18, KEY_BACK }, //RETURN
{ 0x0B, KEY_UP }, //UP
{ 0x0E, KEY_DOWN }, //DOWN
{ 0x10, KEY_LEFT }, //LEFT
{ 0x11, KEY_RIGHT }, //RIGHT
{ 0x0D, KEY_ENTER }, //OK
{ 0x15, KEY_VOLUMEUP }, //V+
{ 0x1C, KEY_VOLUMEDOWN }, //V-
{ 0x1B, KEY_HOME }, //HOME no result
{ 0x33, KEY_FN_F1 }, //OPS
{ 0x37, KEY_FN_F2 }, //WB
{ 0x41, KEY_KP1 }, //SOURCE
{ 0x0C, KEY_FN_F6 }, //SCREENSHOT
{ 0x00, KEY_F1}, //F1
{ 0x00, KEY_F1}, //F1
#elif (CUSTOMER_IR_SELECT == CONFIG_CUSTOMER_PROWISE)
{ 0x52, KEY_POWER }, //POWER
{ 0x0D, KEY_MENU }, //MENU
{ 0x47, KEY_UP }, //UP
{ 0x4D, KEY_DOWN }, //DOWN
{ 0x49, KEY_LEFT }, //LEFT
{ 0x4B, KEY_RIGHT }, //RIGHT
{ 0x4A, KEY_ENTER }, //OK
{ 0x07, KEY_KP1 }, //SOURCE
{ 0x48, KEY_HOME }, //HOME
{ 0x03, KEY_VOLUMEUP }, //V+
{ 0x4E, KEY_F10}, //FREEZE
{ 0x0A, KEY_FN_F5 }, //SETTING
{ 0x41, KEY_VOLUMEDOWN }, //V-
{ 0x5C, KEY_KP8 }, //TOUCH
{ 0x40, KEY_BACK }, //RETURN
{ 0x53, KEY_MUTE }, //MUTE
... ...
}
==> 会进行客制化处理,不同的客户遥控器通过定义宏区分,最后通过宏CUSTOMER_IR_SELECT来表示选择哪个客户遥控器 **** 这些宏在ir_common.h中定义
分析映射对
{ 0x0A, KEY_POWER }, //POWER
0x0A: 按键的扫描码 ,在遥控器规格书中得到
KEY_POWER: keycode按键值,即该按键代表的作用
当遥控器按下POWER键,触发中断,中断会上报 0x0A这个值到ir_core层,ir_core会把这个值发送给解码驱动ir-nec-decoder.c ,然后按键解码驱动会匹配keymap链表中的那些映射表,然后找到该扫描码对应的keycode值,
然后就会将keycode值上报给Android。
分析是如何将每一个遥控器的映射表注册到keymap_list链表中的?
MIRC_Map_Register(&mstar_tv_map);
|
//key map functions ******** 这个函数是定义在 ir_core.c中 所以keymap_list应该也是在这里定义的 *** static LIST_HEAD(keymap_list); *************** ir_core.c中记录了所有映射表 **********
int MIRC_Map_Register(struct key_map_list *map)
{
spin_lock(&key_map_lock);
list_add_tail(&map->list, &keymap_list); //把keymap-mstar-tv.c文件配置的映射表添加到keymap_list中
spin_unlock(&key_map_lock);
return 0;
}
********** 重新回到 mstar_ir.c 文件
mstar_ir_drv_init_module函数
1. 注册设备驱动 2. 注册遥控器映射表到ir_core层
因为在mstar_ir.c中通过platform框架实现设备驱动,所以下面按照平台驱动分析代码
static struct platform_driver Mstar_ir_driver = {
.probe = mstar_ir_drv_probe,
.remove = mstar_ir_drv_remove,
.suspend = mstar_ir_drv_suspend,
.resume = mstar_ir_drv_resume,
.driver = {
#if defined(CONFIG_OF) //设备树匹配 在.config文件中有如下定义: CONFIG_OF=y ==> 说明该系统支持设备树
.of_match_table = mstarir_of_device_ids,
#endif
.name = "Mstar-ir",
.owner = THIS_MODULE,
.bus = &platform_bus_type,
}
};
设备树匹配表
static struct of_device_id mstarir_of_device_ids[] = {
{.compatible = "Mstar-ir"},
{},
};
设备树配置文件 arch/arm/boot/dts/m7221_an.dts中有如下配置
ir {
compatible = "mstar-ir";
};
************ 好像匹配是区分大小写的啊 这里大小写不一样。。? ?????????????????
猜测是非设备树匹配
848_pm_mboot_kernel/kernel$ grep -rn "Mstar-ir" ./
==>
./mstar2/hal/m7221/cpu/arm/chip_arch.c:161: .name = "Mstar-ir",
匹配成功调用probe函数
static int mstar_ir_drv_probe(struct platform_device *pdev)
{
//判断是否匹配成功 !(pdev->name): 传统模式 ,strcmp(pdev->name,"Mstar-ir"):匹配name字段;pdev->id!=0:匹配设备树
IRDBG_ERR("wjc_ir mstar_ir.c mstar_ir_drv_probe \n");
int ret=0;
if (!(pdev->name) || strcmp(pdev->name,"Mstar-ir")|| pdev->id!=0)
{
ret = -ENXIO;
}
IRDev.u32IRFlag = 0;
ret = mstar_ir_cdev_init(); //创建字符设备
if (ret < 0)
{
IRDBG_ERR("mstar_ir_cdev_init Failed! \n");
}
ret = mstar_ir_creat_sysfs_attr(pdev); //创建属性文件
if (ret < 0)
{
IRDBG_ERR("mstar_ir_creat_sysfs_attr Failed! \n");
}
ret = mstar_ir_register_device(pdev); //********* 这里就非常重要了 这个是input子系统操作的地方 这里实现了input子系统3步骤,
if (ret < 0)
{
IRDBG_ERR("mstar_ir_register_device Failed! \n");
}
pdev->dev.platform_data=&IRDev; //将IR设备驱动对应的设备信息全局变量保存到platform_device中
mstar_ir_customer_config(); //加载遥控器配置 即把我们在ir_config.h中配置的信息加载进来
#ifdef CONFIG_MIRC_INPUT_DEVICE
mstar_ir_init(0); //中断操作 ********
IRDev.u32IRFlag |= (IRFLAG_IRENABLE|IRFLAG_HWINITED);
#endif
return ret;
}
驱动基本框架_创建字符设备
static int mstar_ir_cdev_init(void)
{
int ret;
dev_t dev;
IR_PRINT("##### Mstar IR Cdev Init #####\n");
//注册设备号
if (IRDev.s32IRMajor) {
dev = MKDEV(IRDev.s32IRMajor, IRDev.s32IRMinor);
ret = register_chrdev_region(dev, MOD_IR_DEVICE_COUNT, MDRV_NAME_IR);
} else {
ret = alloc_chrdev_region(&dev, IRDev.s32IRMinor, MOD_IR_DEVICE_COUNT, MDRV_NAME_IR);
IRDev.s32IRMajor = MAJOR(dev);
}
if ( 0 > ret) {
IRDBG_ERR("Unable to get major %d\n", IRDev.s32IRMajor);
return ret;
}
//cdev操作 将fops和设备号建立联系
cdev_init(&IRDev.cDevice, &IRDev.IRFop);
if (0!= (ret= cdev_add(&IRDev.cDevice, dev, MOD_IR_DEVICE_COUNT))) {
IRDBG_ERR("Unable add a character device\n");
unregister_chrdev_region(dev, MOD_IR_DEVICE_COUNT);
return ret;
}
return 0;
}
创建属性文件
static int mstar_ir_creat_sysfs_attr(struct platform_device *pdev)
{
struct device *dev = &(pdev->dev);
int ret = 0;
IRDBG_INFO("Debug Mstar IR Creat Sysfs\n");
if ((ret = device_create_file(dev, &dev_attr_IRProtocols))) //系统采用什么协议
goto err_out;
if ((ret = device_create_file(dev, &dev_attr_IRDebug))) //打印等级 默认error级别 等级1
goto err_out;
if ((ret = device_create_file(dev, &dev_attr_IRSpeed))) //灵敏度,过滤多少个波形 默认0
goto err_out;
if ((ret = device_create_file(dev, &dev_attr_IREnable)))
goto err_out;
if ((ret = device_create_file(dev, &dev_attr_IREvent)))
goto err_out;
#ifdef CONFIG_MIRC_INPUT_DEVICE
if ((ret = device_create_file(dev, &dev_attr_IRTimeout)))
goto err_out;
#endif
return 0;
err_out:
return ret;
}
测试现象:
IFP:/sys/devices/ir # ls
IRDebug IRProtocols driver modalias subsystem
IREnable IRSpeed driver_override of_node uevent
IREvent IRTimeout input power
dev_attr_IRProtocols ==> IRProtocols文件 ==>猜测生成的文件名称就是dev_attr_IRProtocols后面的这个字符串
IFP:/sys/devices/ir # cat IRProtocols
Eenable Protocols Name:NEC
input子系统操作
int mstar_ir_register_device(struct platform_device *pdev)
{
struct mstar_ir_dev *dev = NULL;
int ret;
#ifdef CONFIG_MIRC_INPUT_DEVICE
int i = 0;
#endif
//1. alloc struct ir_dev ==> mstar_ir_dev即定义了一个红外遥控器的信息结构体
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
//2. init locks 初始化自旋锁和互斥体
spin_lock_init(&dev->keylock);
spin_lock_init(&irq_read_lock);
mutex_init(&dev->lock);
mutex_lock(&dev->lock);
//3. init other args
dev->priv = &IRDev;
//4. init readfifo & sem & waitqueue
ret= kfifo_alloc(&dev->read_fifo,MAX_IR_DATA_SIZE,GFP_KERNEL); //申请空间 dev->read_fifo: 猜测是用于存放按键中断中读取到的按键扫描码
if (ret<0)
{
IRDBG_ERR("ERROR kfifo_alloc!\n");
goto out_dev;
}
sema_init(&dev->sem, 1); //信号量
init_waitqueue_head(&dev->read_wait);
#ifdef CONFIG_MIRC_INPUT_DEVICE
//5. alloc struct input_dev
dev->input_dev = input_allocate_device(); //***************** input_dev层 步骤1: 申请一个input_dev对象
if (!dev->input_dev)
{
ret = -ENOMEM;
goto out_kfifo;
}
input_set_drvdata(dev->input_dev, dev); // dev_set_drvdata(&dev->dev, data) ==> dev->driver_data = data ==> dev->input_dev->dev->driver_data = dev 相当于在input_dev中保存它父类mstar_ir_dev的信息
dev->input_name = MSTAR_IR_DEVICE_NAME; //#define MSTAR_IR_DEVICE_NAME "MStar Smart TV IR Receiver"
dev->input_phys = "/dev/ir";
dev->driver_name = MSTAR_IR_DRIVER_NAME;
dev->map_num = NUM_KEYMAP_MSTAR_TV; //default :mstar keymap
//6. init®ister input device ===> *************** input_dev层步骤2 初始化input_dev对象
dev->input_dev->id.bustype = BUS_I2C; //input_dev结构体成员分析: https://blog.csdn.net/ielife/article/details/7814108
dev->input_dev->id.vendor = INPUTID_VENDOR; //#define INPUTID_VENDOR 0x3697UL; 这4个属性bustype,vendor,product,vendor是input_dev和input_handler匹配的条件
dev->input_dev->id.product = INPUTID_PRODUCT; //#define INPUTID_PRODUCT 0x0001; 也决定了我们android中对应的kl文件的命名 Vendor_3697_Product_0001.kl
dev->input_dev->id.version = INPUTID_VERSION; //#define INPUTID_VERSION 0x0001;
set_bit(EV_KEY, dev->input_dev->evbit); //表示该input设备要上报的事件类型包括: EV_KEY(按键事件),EV_REP(重复事件),EV_MSC中的MSC_SCAN表示扫描按键 ==>表示可以向上上报一个scancode(scancode==遥控器规格书中的值)
set_bit(EV_REP, dev->input_dev->evbit);
set_bit(EV_MSC, dev->input_dev->evbit);
set_bit(MSC_SCAN, dev->input_dev->mscbit);
dev->input_dev->dev.parent = &(pdev->dev);
dev->input_dev->phys = dev->input_phys; //input_phys: 设备节点名称 ******* "/dev/ir"
dev->input_dev->name = dev->input_name; //输入设备的名称 "MStar Smart TV IR Receiver"
for (i = 0; i<KEY_CNT; i++) //注册所有按键
{
__set_bit(i, dev->input_dev->keybit); //设置遥控器按键对应的按键值 input.h中定义的那个按键值
}
__clear_bit(BTN_TOUCH,dev->input_dev->keybit);// IR device without this case
ret = input_register_device(dev->input_dev); //***************** input_dev层 步骤3: 注册input_dev对象到input_core层中存放所有input_dev对象的链表中,并尝试去driver_list中匹配该device对应的driver,匹配成功执行connect函数,然后创建一个handled对象将device和driver建立联系
#endif
//7. register IR Data ctrl
ret = MIRC_Data_Ctrl_Init(dev); //********** 非常关键 注册IR 数据kthread线程MIRC_Data_Ctrl_Thread从kfifo中获取原始的按键数据,并将数据发送给匹配的decoder文件去解析
if (ret < 0)
{
IRDBG_ERR("Init IR Raw Data Ctrl Failed!\n");
goto out_unlock;
return -EINVAL;
}
IRDev.pIRDev= dev;
mutex_unlock(&dev->lock);
return 0;
out_unlock:
mutex_unlock(&dev->lock);
#ifdef CONFIG_MIRC_INPUT_DEVICE
input_unregister_device(dev->input_dev);
dev->input_dev = NULL;
#endif
out_kfifo:
kfifo_free(&dev->read_fifo);
out_dev:
kfree(dev);
return ret;
}
struct mstar_ir_dev {
struct mutex lock; //lock for handle mstar_ir_dev menber variables
struct ir_raw_data_ctrl *raw; //shot count handle struct
u64 enabled_protocols; //surport decoders
spinlock_t keylock; //spinlock
void *priv; //
IR_SPEED_LEVEL_e speed; //ir speed level
u8 filter_flag;
struct semaphore sem;
wait_queue_head_t read_wait;
struct kfifo_rec_ptr_1 read_fifo; //for user space read
#ifdef CONFIG_MIRC_INPUT_DEVICE
struct input_dev *input_dev;
bool keypressed;
u32 last_keycode;
u32 last_scancode;
const char *input_name;
const char *input_phys;
char *driver_name;
u32 map_num;
#endif
IR_Mode_e ir_mode;
IR_Profile_t support_ir[IR_SUPPORT_MAX];
u8 support_num;
};
/*
* Used to (un)register raw event clients 用于(un)注册原始事件客户端
*/
int MIRC_Data_Ctrl_Init(struct mstar_ir_dev *dev)
{
int ret;
if (!dev)
return -EINVAL;
dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL); //申请raw内存空间 ,raw中存放原始按键信息
if (!dev->raw)
return -ENOMEM;
dev->raw->dev = dev;
dev->enabled_protocols = 0; //支持的解码协议
ret= kfifo_alloc(&dev->raw->kfifo,
sizeof(struct ir_raw_data) * MAX_IR_DATA_SIZE,
GFP_KERNEL);
if (ret < 0)
goto out;
spin_lock_init(&dev->raw->lock); //初始化自旋锁
dev->raw->thread = kthread_run(MIRC_Data_Ctrl_Thread, dev->raw,"Mstar_ir"); //kthread_run是一个宏定义,功能是创建并启动内核线程 创建一个名为"Mstar_ir"的线程,将dev->raw作为参数传递给该线程对应的线程函数MIRC_Data_Ctrl_Thread
if (IS_ERR(dev->raw->thread)) {
ret = PTR_ERR(dev->raw->thread);
goto out;
}
#ifdef CONFIG_MIRC_INPUT_DEVICE
// init timer event up 初始化一个定时器
dev->raw->keyup_jiffies = jiffies;//record timeout for event up
init_timer(&(dev->raw->timer_keyup));
dev->raw->timer_keyup.function = MIRC_Timer_Proc; //超时处理函数
dev->raw->timer_keyup.expires =jiffies+ msecs_to_jiffies(eventtimeout); //设置的定时时间
dev->raw->timer_keyup.data = (unsigned long)dev; //传递给超时函数的参数
#endif
return 0;
out:
kfree(dev->raw);
dev->raw = NULL;
return ret;
}
raw成员: 保存着原始按键值
struct ir_raw_data_ctrl {
struct task_struct *thread; //线程
spinlock_t lock;
struct kfifo_rec_ptr_1 kfifo; /* fifo for the pulse/space durations 脉冲/空间持续时间的fifo*/
struct mstar_ir_dev *dev;
struct ir_scancode prev_sc; //前一个扫描码
struct ir_scancode this_sc; //当前扫描码
u8 u8RepeatFlag;
#ifdef CONFIG_MIRC_INPUT_DEVICE
unsigned long keyup_jiffies; //time record
struct timer_list timer_keyup; //定时器 事件发生定时器
#endif
};
"Mstar_ir"线程分析: 关键步骤总结分析 该函数定义在ir_core.c
static int MIRC_Data_Ctrl_Thread(void *data)
{
//1. 从raw->kfifo中获取数据到ev中,获取的元素数量为sizeof(ev) ==这个fifo中的数据就是按键的原始值
retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
//2. 将获取到的数据发送给对应的decoder匹配协议解析数据
mutex_lock(&ir_decoder_lock);
else //hw decoder //对应IR_TYPE_FULLDECODE_MODE NEC full解码 支持两个头码的遥控器 在IR_MSTAR_DTV.h 中有如下定义:#define IR_MODE_SEL IR_TYPE_FULLDECODE_MODE
{
raw->this_sc.scancode = ev.duration;
raw->u8RepeatFlag = ev.pulse;
get_scancode = 1; //是否获取到扫描值的标志 1=获取扫描值,读后面就是对这个获取到的按键扫描值进行处理
IRDBG_MSG("keycode =%x repeatflag =%d \n",raw->this_sc.scancode,raw->u8RepeatFlag);
}
//3. 匹配映射表,获取映射后按键对应的keycode值,上报event事件
MIRC_Keydown(raw->dev, raw->this_sc.scancode);
MIRC_Keyup(raw->dev);
}
//设置遥控器配置 就是ir_config.h中的配置 配置遥控器的打印级别,速率,支持的遥控器的协议和头码
static void mstar_ir_customer_config(void)
{
MIRC_Set_IRDBG_Level(ir_dbglevel);
MIRC_Set_IRSpeed_Level(ir_speed);
MIRC_IRCustomer_Config(ir_config,IR_SUPPORT_NUM);
return ;
}
//中断操作
static void mstar_ir_init(int bResumeInit)
{
int ret = 0;
struct mstar_ir_dev *dev = IRDev.pIRDev;
//Prevent residual value exist in sw fifo when system wakeup from standby status 防止系统从待机状态唤醒时sw fifo中存在剩余值
REG(REG_IR_CTRL) &= (0xFF00); //disable IR ctrl regs 失能IR控制寄存器
REG(REG_IR_SEPR_BIT_FIFO_CTRL) &= (0xFF); //disable IR FIFO settings
if(NULL == dev)
return ;
switch(dev->ir_mode) //根据不同的解码模式来做好相应的寄存器配置
{
case IR_TYPE_FULLDECODE_MODE: //我们代码中设置的是硬解码
{
mstar_ir_hw_fulldecode_config();
}
break;
case IR_TYPE_RAWDATA_MODE :
{
mstar_ir_hw_rawdecode_config();
}
break;
case IR_TYPE_HWRC5_MODE :
{
mstar_ir_hw_rc5decode_config();
}
break;
case IR_TYPE_HWRC5X_MODE :
{
mstar_ir_hw_rc5decode_config();
}
break;
case IR_TYPE_HWRC6_MODE :
{
mstar_ir_hw_rc6decode_config();
}
break;
case IR_TYPE_SWDECODE_MODE :
{
mstar_ir_sw_decode_config();
}
break;
default:
IRDBG_INFO("No IR Mode Support!\n");
break;
}
}
if ((!bResumeInit) &&(ir_irq_sel ==0xFF)) //这里猜测是如果这个解码方式前面没有配置过,在这里配置中断
{
ir_irq_enable = 0;
if((dev->ir_mode == IR_TYPE_HWRC5_MODE)||(dev->ir_mode == IR_TYPE_HWRC5X_MODE)||(dev->ir_mode == IR_TYPE_HWRC6_MODE))
{
#ifdef E_FIQEXPL_IR_INT_RC
ret = request_irq(E_FIQEXPL_IR_INT_RC, _MDrv_IR_RC_ISR, SA_INTERRUPT, "IR_RC", &IRDev);
ir_irq_sel = 1;
#else
printk("E_FIQEXPL_IR_INT_RC IRQ not Found\n");
#endif
}
else
{
//申请中断
ret = request_irq(INT_NUM_IR_ALL, _MDrv_IR_ISR, SA_INTERRUPT, "IR", &IRDev);
ir_irq_sel = 0; //这次申请了说明该解码方式以及配置好了,防止后面再次配置
}
if (ret < 0)
{
IRDBG_ERR("IR IRQ registartion ERROR!\n");
}
else
{
ir_irq_enable = 1;
IRDBG_INFO("IR IRQ registartion OK!\n");
}
}
return ;
}
//做好硬解码的寄存器配置 头码 + NEC解码的时序
static void mstar_ir_hw_fulldecode_config(void)
{
//1. set customer code0
REG(REG_IR_CCODE) = ((u32IRHeaderCode[0]&0xff)<<8)|((u32IRHeaderCode[0]>>8) &0xff);
//2. set customer code1
REG(REG_IR_CCODE1) =((u32IRHeaderCode[1]&0xff)<<8)|((u32IRHeaderCode[1]>>8) &0xff);
if(ir_config_mode == IR_TYPE_FULLDECODE_MODE)
{
return ;
}
ir_config_mode = IR_TYPE_FULLDECODE_MODE; //表示现在这个系统的解码配置为: 硬解码
IR_PRINT("##### Mstar IR HW Full Decode Config #####\n");
//3. set NEC timing & FIFO depth 16 bytes
_MDrv_IR_Timing();
REG(REG_IR_SEPR_BIT_FIFO_CTRL) = 0xF00UL;//[10:8]: FIFO depth, [11]:Enable FIFO full
REG(REG_IR_CCODE1_CHK_EN) |= IR_CCODE1_CHK_EN;
//4. Glitch Remove (for prevent Abnormal waves) reg_ir_glhrm_num = 4拢卢reg_ir_glhrm_en = 1
REG(REG_IR_GLHRM_NUM) = 0x804UL;
//5.set full decode mode
REG(REG_IR_GLHRM_NUM) |= (0x3UL <<12);
//6.set Data bits ===>two byte customer code +IR DATA bits(32bits)+timeout clear+timeout value 4 high bits
REG(REG_IR_TIMEOUT_CYC_H_CODE_BYTE) = IR_CCB_CB | 0x30UL | ((IR_RP_TIMEOUT >> 16) & 0x0FUL);
//7.set IR clock DIV
REG(REG_IR_CKDIV_NUM_KEY_DATA) = IR_CKDIV_NUM; //set clock div --->IR clock =1MHZ
//8.reg_ir_wkup_key_sel ---> out key value
REG(REG_IR_FIFO_RD_PULSE) |= 0x0020UL; //wakeup key sel
//9. set ctrl enable IR
REG(REG_IR_CTRL) = IR_TIMEOUT_CHK_EN |
IR_INV |
IR_RPCODE_EN |
IR_LG01H_CHK_EN |
IR_DCODE_PCHK_EN |
IR_CCODE_CHK_EN |
IR_LDCCHK_EN |
IR_EN;
}
NEC红外编码的发送波形
//Time, upper bound, low bound
{9000,20,(-20)},// header code time
{4500,20,(-20)},//off code time
{2500,20,(-20)}, // off code repeat time
{560,35,(-30)}, // logical 0/1 high time
{1120,20,(-20)}, // logical 0 time
{2240,20,(-20)}, // logical 1 time
0代表低电平,1=高电平
引导码: 0:9ms,1:4.5ms
引导重复码: 0:9ms,1:2.24ms
数据1: 0:0.56ms.1:(2.25-0.56)ms
数据0: 0:0.56ms.1:(1.12-0.56)ms
一个完整的数据波形
引导码/引导重复码 地址 地址取反 数据 数据取反
硬解码模式中配置中断: 申请一个中断号为INT_NUM_IR_ALL,中断名称为"IR",中断处理函数为_MDrv_IR_ISR的中断
ret = request_irq(INT_NUM_IR_ALL, _MDrv_IR_ISR, SA_INTERRUPT, "IR", &IRDev);
SA_INTERRUPT: 中断处理的属性,若设置SA_INTERRUPT,标明中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断 //将遥控器按键中断设置成快速中断,为了对按键进行快速响应
分析中断处理函数 **************************
irqreturn_t _MDrv_IR_ISR(int irq, void *dev_id)
{
IRModHandle *mstar_dev = dev_id; //获取申请中断时传递进来的参数 IRDev指针 IR设备驱动信息结构体
int ret = 0;
if (NULL == mstar_dev)
return -EINVAL;
if(mstar_dev->pIRDev->ir_mode == IR_TYPE_FULLDECODE_MODE) //硬解码
ret = mstar_ir_isr_getdata_fulldecode(mstar_dev);
else if(mstar_dev->pIRDev->ir_mode == IR_TYPE_RAWDATA_MODE)
ret = mstar_ir_isr_getdata_rawdecode(mstar_dev);
else
{
spin_lock(&irq_read_lock);
while ( ((REG(REG_IR_SHOT_CNT_H_FIFO_STATUS) & IR_FIFO_EMPTY) != IR_FIFO_EMPTY))
{
ret = mstar_ir_isr_getdata_swdecode(mstar_dev);
if(ret < 0)
{
spin_unlock(&irq_read_lock);
return IRQ_HANDLED;
}
REG(REG_IR_FIFO_RD_PULSE) |= 0x0001;
}
spin_unlock(&irq_read_lock);
}
if(ret >= 0)
MIRC_Data_Wakeup(mstar_dev->pIRDev);
return IRQ_HANDLED;
}
mstar_ir_isr_getdata_fulldecode(mstar_dev) //获取触发中断的按键值,并将按键值写入到fifo中*******
|
int mstar_ir_isr_getdata_fulldecode(IRModHandle *mstar_dev)
{
int ret = 0;
u8 u8Ir_Index = 0;
u8 u8Keycode = 0;
u8 u8Repeat = 0;
u32 u32IRSpeed = 0;
if(REG(REG_IR_SHOT_CNT_H_FIFO_STATUS) & IR_FIFO_EMPTY)
{
return -1;
}
DEFINE_IR_RAW_DATA(ev);
u8Keycode = REG(REG_IR_CKDIV_NUM_KEY_DATA) >> 8;
u8Repeat = (REG(REG_IR_SHOT_CNT_H_FIFO_STATUS) & IR_RPT_FLAG)? 1 : 0;
u8Ir_Index = REG(REG_IR_SHOT_CNT_H_FIFO_STATUS) & 0x40? 1 : 0;//IR remote controller TX1 send flag
REG(REG_IR_FIFO_RD_PULSE) |= 0x0001;
ev.duration = (u32IRHeaderCode[u8Ir_Index]<<8) | u8Keycode; //ev中保存了该中断触发导致的按键的原始按键值(扫描值)
ev.pulse = u8Repeat;
IRDBG_INFO(" u8Ir_Index = %d\n",u8Ir_Index);
IRDBG_INFO("[Full Decode] Headcode =%x Key =%x\n",u32IRHeaderCode[u8Ir_Index],u8Keycode);
mstar_dev->pIRDev->map_num = mstar_dev->pIRDev->support_ir[u8Ir_Index].u32HeadCode;
u32IRSpeed = mstar_dev->pIRDev->support_ir[u8Ir_Index].u32IRSpeed;
if(u8Repeat)
{
if (((u32IRSpeed != 0)&&( u8RepeatCount < (u32IRSpeed - 1)))
|| ((u32IRSpeed == 0)&&(u8RepeatCount < mstar_dev->pIRDev->speed)))
{
u8RepeatCount ++;
mstar_ir_nec_clearfifo();
return -1;
}
}
else
{
u8RepeatCount = 0;
}
ret = MIRC_Data_Store(mstar_dev->pIRDev, &ev); //********** 非常关键 将触发中断的按键值写入fifo中
if (ret < 0)
{
IRDBG_ERR("Store IR data Error!\n");
}
mstar_ir_nec_clearfifo();
return ret;
}
//ir_core.c文件 *********** 这里就失ir_core层中保存了按键中断触发分按键值了 前面在mstar_ir.c中的驱动入口函数中将解码映射表也注册到了ir_core中 ***** 所以在ir_core中万事俱备(有原始值,有映射表),开始解码
int MIRC_Data_Store(struct mstar_ir_dev *dev, struct ir_raw_data *ev)
{
if (!dev->raw)
return -EINVAL;
if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) //kfifo_in函数就是将数据写入到fifo中 / kfifo_in函数就是读取fifo中的数据
return -ENOMEM;
return 0;
}
MIRC_Data_Wakeup(mstar_dev->pIRDev); //唤醒"mstar_ir"线程来读取fifo中的按键值,然后解析获取keycode,然后input_event上报数据到eventX文件
|
void MIRC_Data_Wakeup(struct mstar_ir_dev *dev)
{
unsigned long flags;
if (!dev->raw)
return;
spin_lock_irqsave(&dev->raw->lock, flags);
wake_up_process(dev->raw->thread); //唤醒执行dev->raw->thread线程 在 mstar_ir_register_device()-> MIRC_Data_Ctrl_Init(dev) --> dev->raw->thread = kthread_run(MIRC_Data_Ctrl_Thread, dev->raw,"Mstar_ir ; ===>所以这里就会执行Mstar_ir线程对应的MIRC_Data_Ctrl_Thread函数
spin_unlock_irqrestore(&dev->raw->lock, flags);
}
//再次具体分析 读取fifo中按键原始值,匹配映射表,解析数据,input系统上报数据的实现 ****************
static int MIRC_Data_Ctrl_Thread(void *data)
{
//1. 读取fifo中按键原始值
retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); //kfifo_out函数就是读取fifo中的数据,并将读取到的数据保存在ev中
//2. 获取原始值之后就需要解析原始值 解析按键按下时的原始值
MIRC_Keydown(raw->dev, raw->this_sc.scancode);
}
//解析按键按下时的原始值
void MIRC_Keydown(struct mstar_ir_dev *dev, int scancode)
{
unsigned long flags;
u32 keycode = MIRC_Keycode_From_Map(dev->map_num, scancode); //非常重要 这里就是匹配映射表,获取该原始扫描按键扫描值对应的keycode值
if (keycode == KEY_RESERVED)
{
IRDBG_ERR("Key Map Match scancode Failed!\n");
return ;
}
spin_lock_irqsave(&dev->keylock, flags);
MIRC_Do_Keydown(dev, scancode, keycode); //获取keycode之后上报按键按下的数据
spin_unlock_irqrestore(&dev->keylock, flags);
}
u32 keycode = MIRC_Keycode_From_Map(dev->map_num, scancode);
|
static u32 MIRC_Keycode_From_Map(u32 keymapnum,u32 scancode)
{
struct key_map_list *map = NULL;
u32 keycode = KEY_RESERVED;
u8 i=0;
bool match_flag = false;
spin_lock(&key_map_lock);
list_for_each_entry(map, &keymap_list, list) //匹配映射表
{
if (((scancode>>8) == map->map.headcode) || (keymapnum == map->map.headcode))
{
IRDBG_INFO("[Match] Keymap Name: %s\n",map->map.name);
match_flag = true;
break;//find IR map
}
}
if (match_flag) //获取原始值映射后的keycode值
{
for (i = 0; i<map->map.size; i++) //map.size:映射表中的映射对数量
{
if (((map->map.scan[i].scancode&0xff) == (scancode&0xff)) && ((scancode>>8) == map->map.headcode)) //选这里 (map->map.scan[i].scancode&0xff) == (scancode&0xff)) 在映射表中找到匹配的scancode
{
IRDBG_INFO("[Match 8bit Scancode] Scancode =%x -----> Keycode= %x\n",scancode,map->map.scan[i].keycode); //,map->map.scan[i].keycode: 就是该scancode对应的keycode值
keycode = map->map.scan[i].keycode;
break;//match scancode, and return keycode
}
if ( ((map->map.scan[i].scancode&0xffff) == (scancode&0xffff)) && (keymapnum == map->map.headcode))
{
IRDBG_INFO("[Match 16bit Scancode] Scancode =%x -----> Keycode= %x\n",scancode,map->map.scan[i].keycode);
keycode = map->map.scan[i].keycode;
break;//match scancode, and return keycode
}
}
}
spin_unlock(&key_map_lock);
return keycode;
}
keymapnum的值?
mstar_ir_register_device() 中dev->map_num = NUM_KEYMAP_MSTAR_TV; //default :mstar keymap 这里就一直调即可
所以keymapnum == NUM_KEYMAP_MSTAR_TV //#define NUM_KEYMAP_MSTAR_TV 0x4040 这个值就是我们在ir_common.h中定义的不同客户的头码值,与ir_config.h中定义的遥控器头码值相同 {IR_TYPE_NEC, NUM_KEYMAP_MSTAR_TV, 0},
在驱动入口函数中有如下步骤 加载解码驱动,在该解码驱动中有如下操作,将映射包添加到ir_core层的key_map_list链表中
int MIRC_Map_Register(struct key_map_list *map)
{
spin_lock(&key_map_lock);
list_add_tail(&map->list, &keymap_list); //把keymap-mstar-tv.c文件配置的映射表map添加到keymap_list中 在ir_core层中创建了keymap_list链表:static LIST_HEAD(keymap_list);
spin_unlock(&key_map_lock);
return 0;
}
匹配映射表
list_for_each_entry(map, &keymap_list, list) //遍历映射表
{
if (((scancode>>8) == map->map.headcode) || (keymapnum == map->map.headcode)) //匹配头码 keymapnum == map->map.headcode
{
IRDBG_INFO("[Match] Keymap Name: %s\n",map->map.name);
match_flag = true; //匹配成功标志位置ture
break;//find IR map
}
}
==> 例如:nec解码驱动 我们注册的映射表:mstar_tv_map 故: map->map.headcode == NUM_KEYMAP_MSTAR_TV ************* 这不就匹配上了吗?
static struct key_map_list mstar_tv_map = {
.map = {
.scan = mstar_tv, //具体的映射关系表
.size = ARRAY_SIZE(mstar_tv), //多少个按键映射对
.name = NAME_KEYMAP_MSTAR_TV, //该按键映射表的名称 在ir_common.h中定义 #define NAME_KEYMAP_MSTAR_TV "ir-mstar-tv"
.headcode = NUM_KEYMAP_MSTAR_TV, //头码 在ir_common.h中定义 #define NUM_KEYMAP_MSTAR_TV 0x4040
}
};
匹配成功开始解码,获取keycode,这个看前面的代码注释
获取keycode值之后,就需要把keycode值上报
MIRC_Do_Keydown(dev, scancode, keycode);
|
static void MIRC_Do_Keydown(struct mstar_ir_dev *dev, int scancode,u32 keycode)
{
bool new_event = !dev->keypressed ||
dev->last_scancode != scancode; //new_event表示该按键是否为新按键 (是否和上一个按键不同)
if (new_event && dev->keypressed)
MIRC_Do_Keyup(dev, false);
input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); // ************ 底层需要我们自己实现的驱动的最后一步 上报扫描码
if (new_event && keycode != KEY_RESERVED) { //非常
/* Register a keypress */
dev->keypressed = true;
dev->last_scancode = scancode;
dev->last_keycode = keycode;
input_report_key(dev->input_dev, keycode, 1); //这个就是当是新按键被按下,需要重新上报一下新的keycode值 1:代表按键按下
}
input_sync(dev->input_dev); //上报同步事件 即将上报信息立刻方法出去
}
后面的流程就是input子系统的流程了: 大概流程为
上报的数据,分发给订阅了该input_dev的input_handle,然后input_handle在此将数据分发给与它相关的input_handle,最后在input_handle中的event方法中将数据分发给所有打开该设备文件的缓冲区中
所以现在 你可以通过 getevent -l /dev/input/event0来查看上报信息 input子系统的设备文件就是eventX类型,主设备号13,这些都是在input_hander层就写死的
总结: 遥控器上报数据的流程 ***************
加载遥控器驱动 Mstar_ir.c,加载解码驱动将映射表注册到ir_core层中的keymap_list链表中
遥控器按键按下;进入中断处理函数,获取按键scancode值,并将值保存在fifo缓冲区中,好像"MSTAR_IR"线程; "MSTAR_IR"线程读取fifo中的数据,然后开始解析数据,先获取该遥控器驱动匹配的映射表,然后根据scancode值找到相应的keycode值,最后input上报按键值
调试方法: mstar_遥控器文档 :设置printk和IRDEUG的打印等级
查看打印信息
IFP:/ # [ 310.833687] [IR ERR ]: _MDrv_IR_ISR[629]: [ 310.838228] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] _MDrv_IR_ISR enter request_irq
[ 310.847193] [ 310.848861] [IR ERR ]: _MDrv_IR_ISR[635]:
[ 310.853571] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] _MDrv_IR_ISR mstar_dev->pIRDev->ir_mode = 5
*********** WTF ir_mode不是IR_TYPE_FULLDECODE_MODE,而是IR_TYPE_SWDECODE_MODE,
typedef enum{
IR_TYPE_FULLDECODE_MODE = 0, /* NEC full deocoder mode */ nec full解码,支持两个头码遥控器 他只会解NEC编码的遥控器
IR_TYPE_RAWDATA_MODE, /* NEC raw decoder mode*/
IR_TYPE_HWRC5_MODE, /* RC5 decoder mode*/
IR_TYPE_HWRC5X_MODE, /* RC5_ext decoder mode*/
IR_TYPE_HWRC6_MODE, /* RC6_mode0 decoder mode*/
IR_TYPE_SWDECODE_MODE, /* SW decoder mode*/ 软解码,支持多种不同协议
IR_TYPE_MAX_MODE
}IR_Mode_e;
在ir_config.h中 我们定义了两种编码的遥控器 ==> 所以应该采用IR_TYPE_SWDECODE_MODE 解码方式
#define IR_SUPPORT_NUM 2
static IR_Profile_t ir_config[IR_SUPPORT_NUM]=
{
// {IR_TYPE_NEC,NUM_KEYMAP_MSTAR_TV,0}, // Mstar IR customer code
//{IR_TYPE_TOSHIBA,NUM_KEYMAP_SKYWORTH_TV,0}, // skyworth toshiba ir
//{IR_TYPE_NEC,NUM_KEYMAP_CHANGHONG_TV,0}, // changhong_RL78B /Toshiba CT-90436 IR customer code
//{IR_TYPE_NEC,NUM_KEYMAP_HISENSE_TV,0}, // Hisense IR customer code
//{IR_TYPE_RCA,NUM_KEYMAP_TCL_RCA_TV,0}, // TCL RCA customer code
//{IR_TYPE_P7051,NUM_KEYMAP_P7051_STB,0}, // Panasonic 7051 IR customer code
//{IR_TYPE_RC5, NUM_KEYMAP_RC5_TV, 0}, // RC5 customer code
{IR_TYPE_NEC, NUM_KEYMAP_MSTAR_TV, 0},
//{IR_TYPE_RC6,NUM_KEYMAP_KATHREIN_TV,0}, // Kathrein RC6 customer code
//{IR_TYPE_KONKA,NUM_KEYMAP_KONKA_TV,2},
{IR_TYPE_PANASONIC,NUM_KEYMAP_PANASONIC_TV,2},
};
//Description of IR
typedef struct IR_Profile_s {
IR_Type_e eIRType;
u32 u32HeadCode;
u32 u32IRSpeed;
}IR_Profile_t;
代码具体实现流程如下 即_MDrv_IR_ISR mstar_dev->pIRDev->ir_mode = 5 这个的来源
在遥控器驱动 Mstar_ir.c中
驱动入口函数 ret = platform_driver_register(&Mstar_ir_driver);
probe函数 mstar_ir_customer_config();
|
MIRC_IRCustomer_Config(ir_config,IR_SUPPORT_NUM);
|
MIRC_IRCustomer_Init();
int MIRC_IRCustomer_Init(void)
{
struct mstar_ir_dev *dev = IRDev.pIRDev;
IR_Type_e IrType = IR_TYPE_MAX;
u8 i = 0;
bool bIsDiffType = false;
if (NULL == dev)
return -EINVAL;
for(i = 0; i<dev->support_num; i++) //#define IR_SUPPORT_NUM 2
{
if(dev->support_ir[i].eIRType == dev->support_ir[i+1].eIRType)
{
IrType = dev->support_ir[i].eIRType;
bIsDiffType = false;
}
else //会执行这里的代码 因为IR_TYPE_PANASONIC != IR_TYPE_NEC
{
dev->ir_mode = IR_TYPE_SWDECODE_MODE; //这里就是ir_mode的来来源
bIsDiffType = true;
break;
}
}
if(bIsDiffType == false) //不走这里
{
if(IrType == IR_TYPE_NEC)
{
if(dev->support_num <=2)
{
//set customer code0
u32IRHeaderCode[0] = dev->support_ir[0].u32HeadCode;
u32IRHeaderCode[1] = dev->support_ir[1].u32HeadCode;
dev->ir_mode = IR_TYPE_FULLDECODE_MODE;
}
else
{
dev->ir_mode = IR_TYPE_RAWDATA_MODE;
}
}
else if(IrType == IR_TYPE_RC5)
{
dev->ir_mode = IR_TYPE_HWRC5_MODE;
}
else if(IrType == IR_TYPE_RC5X)
{
dev->ir_mode = IR_TYPE_HWRC5X_MODE;
}
else if(IrType == IR_TYPE_RC6_MODE0)
{
dev->ir_mode = IR_TYPE_HWRC6_MODE;
}
else
{
dev->ir_mode = IR_TYPE_SWDECODE_MODE;
}
}
if(IR_TYPE_SWDECODE_MODE == dev->ir_mode) //这里要走路
{
for(i = 0;i<(dev->support_num);i++)
{
switch(dev->support_ir[i].eIRType)
{
case IR_TYPE_NEC :
nec_decode_init(); //这个解码驱动有加载 我们中性的是nec编码,等等如何解码后面在分析 这个解码 == 根据接收到的遥控器发送的波形的时序,如何根据NEC协议解码 *******
break;
case IR_TYPE_RCA:
rca_decode_init();
break;
case IR_TYPE_P7051:
p7051_decode_init();
break;
case IR_TYPE_RC5:
case IR_TYPE_RC5X:
rc5_decode_init();
break;
case IR_TYPE_RC6_MODE0:
case IR_TYPE_RC6:
rc6_decode_init();
break;
case IR_TYPE_TOSHIBA:
toshiba_decode_init();
break;
case IR_TYPE_RCMM:
rcmm_decode_init();
break;
case IR_TYPE_KONKA:
konka_decode_init();
break;
case IR_TYPE_PANASONIC:
panasonic_decode_init(); //这个解码驱动要加载
break;
default :
IRDBG_ERR("IR TYPE not define,please check!!!\n");
break;
}
}
}
return 0;
}
故前面的代码跟读就有误了 ******************** WTF
先按下source按键,在按下menu按键后,menu按键的log分析,******我们这里只是跟踪了按键按下时的流程 **** ****** wjc_ir是我们添加的打印 第一次尝试 没有进入到按键按下处理的函数的log
IFP:/ # [ 281.707665] [IR ERR ]: _MDrv_IR_ISR[630]:
[ 281.712385] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] _MDrv_IR_ISR enter request_irq
[ 281.721347] [ 281.723015] [IR ERR ]: _MDrv_IR_ISR[636]:
[ 281.727724] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] _MDrv_IR_ISR mstar_dev->pIRDev->ir_mode = 5 //软解码
[ 281.737728] [ 281.739398] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 281.745582] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode //获取按下menu键,遥控器发送的波形 duration/pulse值
[ 281.754544] [ 281.756214] [IR ERR ]: MIRC_Data_Store[247]:
[ 281.761184] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode //将获取到的波形数据存放在fifo中 循环处理9次
[ 281.769971] [ 281.771644] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 281.777829] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode
[ 281.786791] [ 281.788462] [IR ERR ]: MIRC_Data_Store[247]:
[ 281.793430] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode
[ 281.802217] [ 281.803890] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 281.810075] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode
[ 281.819036] [ 281.820707] [IR ERR ]: MIRC_Data_Store[247]:
[ 281.825676] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode
[ 281.834462] [ 281.836132] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 281.842317] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode
[ 281.851280] [ 281.852951] [IR ERR ]: MIRC_Data_Store[247]:
[ 281.857920] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode
[ 281.866707] [ 281.868377] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 281.874561] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode
[ 281.883523] [ 281.885192] [IR ERR ]: MIRC_Data_Store[247]:
[ 281.890162] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode
[ 281.898951] [ 281.900621] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 281.906806] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode
[ 281.915772] [ 281.917442] [IR ERR ]: MIRC_Data_Store[247]:
[ 281.922411] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode
[ 281.931199] [ 281.932869] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 281.939055] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode
[ 281.948017] [ 281.949685] [IR ERR ]: MIRC_Data_Store[247]:
[ 281.954654] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode
[ 281.963443] [ 281.965113] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 281.971298] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode
[ 281.980261] [ 281.981930] [IR ERR ]: MIRC_Data_Store[247]:
[ 281.986899] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode
[ 281.995687] [ 281.997357] [IR ERR ]: mstar_ir_isr_getdata_swdecode[597]:
[ 282.003542] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] mstar_ir_isr_getdata_swdecode
[ 282.012504] [ 282.014174] [IR ERR ]: MIRC_Data_Store[247]:
[ 282.019142] ************* ^_^ ************* [wjc_ir] [mstar_ir.c] MIRC_Data_Store add scancode
[ 282.027929] [ 282.029602] [IR ERR ]: MIRC_Data_Wakeup[264]:
[ 282.034657] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Wakeup Wakeup thread //将数据都存放在fifo之后,唤醒线程去处理数据
[ 282.043532] [ 282.045232] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.050900] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 15 //这里就是将前面存放在fifo中的数据取出来 这个数据不是scancode 而是duration,实际上应该会有pulse值
[ 282.061299] [ 282.062997] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.068523] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 575
[ 282.078899] [ 282.080583] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.086094] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 495
[ 282.096466] [ 282.098134] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.103635] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 1615
[ 282.114081] [ 282.115747] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.121260] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 495
[ 282.131862] [ 282.133541] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.139047] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 16383
[ 282.149822] [ 282.151491] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.156996] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 8319
[ 282.170418] [ 282.172151] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.177860] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 2175
[ 282.188571] [ 282.190242] [IR ERR ]: MIRC_Data_Ctrl_Thread[147]:
[ 282.195766] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread thread_get_scancode = 495
加get_scancode的打印
[ 253.961074] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread ev.duration = 495 , ev.pulse = 1 ,get_scancode = 0
所以前面的解析,上报的代码跟踪就不对了,前面的那种是nec full解码方式的数据解析和上报, 队员软解码的解析应该为下面代码的操作
static int MIRC_Data_Ctrl_Thread(void *data)
{
...
if(raw->dev->ir_mode == IR_TYPE_SWDECODE_MODE) //sw decoder
{
struct ir_decoder_handler *handler;
IRDBG_MSG("shotcount[ %5d %d ]\n",ev.duration, ev.pulse);
list_for_each_entry(handler, &ir_decoder_list, list){
if(handler->decode(raw->dev, ev) > 0){
get_scancode = 1;
break;
}
}
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir_core.c] %s ev.duration = %d , ev.pulse = %d ,get_scancode = %d \n",__FUNCTION__,ev.duration,ev.pulse,get_scancode);
}
...
}
调用NEC遥控器编码对应的解码驱动
if(handler->decode(raw->dev, ev) > 0)
先分析在Mstar_ir.c中probe函数执行的加载nec解码驱动 //调用关系 和前面分析ir_mode来源一致
nec_decode_init();
|
int nec_decode_init(void) //ir-nec0decoder.c文件
{
if(u8InitFlag_nec == FALSE) //还没有初始化就执行这里
{
scancode = 0;
mapnum = 0;
KeyTime = 0;
memset(&nec,0,sizeof(IR_NEC_Spec_t));
MIRC_Decoder_Register(&nec_handler);
IR_PRINT("[IR Log] NEC Spec Protocol Init\n");
u8InitFlag_nec = TRUE;
}
else
{
IR_PRINT("[IR Log] NEC Spec Protocol Has been Initialized\n");
}
return 0;
}
MIRC_Decoder_Register(&nec_handler);
|
/*
* Extension interface - used to register the IR decoders 扩展接口-用于注册红外解码器
*/
int MIRC_Decoder_Register(struct ir_decoder_handler *handler) //ir_core.c文件
{
mutex_lock(&ir_decoder_lock);
list_add_tail(&handler->list, &ir_decoder_list); //将nec红外解码器注册到ir_decoder_list链表中 , static LIST_HEAD(ir_decoder_list); 在ir_core.c中创建了该链表
protocols |= handler->protocols;
MIRC_Set_Protocols(protocols);
mutex_unlock(&ir_decoder_lock);
return 0;
}
MIRC_Set_Protocols(protocols);
|
void MIRC_Set_Protocols(u64 data) //设置IRDev.pIRDev->enabled_protocols 成员变量的值
{
protocols = data;
IRDev.pIRDev->enabled_protocols = protocols;
}
static struct ir_decoder_handler nec_handler = { //这就是nec解码器的信息
.protocols = (1<<IR_TYPE_NEC),
.decode = ir_nec_decode,
};
IRDev.pIRDev->enabled_protocols = protocols; ==> IRDev.pIRDev->enabled_protocols = 1<<IR_TYPE_NEC == 1<<0 == 1 //这个就成员代表的是当前遥控器可以用那些解码器来解码,一个位代表一种解码器
分析解码*********** ************
list_for_each_entry(handler, &ir_decoder_list, list){ //遍历ir_decoder_list链表,该链表中存放了nec_handler这个解码器,
if(handler->decode(raw->dev, ev) > 0){
get_scancode = 1;
break;
}
}
handler->decode(raw->dev, ev)
|
static int ir_nec_decode(struct mstar_ir_dev *dev, struct ir_raw_data ev) //NEC协议详解: https://www.cnblogs.com/lifexy/p/9783694.html
{
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] %s \n",__FUNCTION__);
IR_NEC_Spec_t *data = &nec;
struct ir_scancode *sc = &dev->raw->this_sc;
struct ir_scancode *prevsc = &dev->raw->prev_sc;
u8 i = 0;
u8 u8Addr = 0; //地址
u8 u8AddrInv =0; //地址取反
u8 u8Cmd =0; //数据
u8 u8CmdInv =0; //数据取反 NEC协议中一个完整的数据波形为: 引导码 地址 地址取反 数据 数据取反
if (!(dev->enabled_protocols & (1<<IR_TYPE_NEC))) //判断是否为NEC编码
return -EINVAL;
switch (data->eStatus)
{
case STATE_INACTIVE: //判断是否为9ms,是则进入下一个判断,判断是引导码还是重复码
if (!ev.pulse)
break;
if (eq_margin(ev.duration,NEC_HEADER_PULSE_LWB,NEC_HEADER_PULSE_UPB)) //NEC_HEADER_PULSE_LWB = NEC_HEADER_PULSE_UPB = 9ms
{
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] %s ev.duration = %d 1. [case STATE_INACTIVE] jx_ydm:9ms\n",__FUNCTION__,ev.duration);
data->u8BitCount = 0;
data->eStatus = STATE_HEADER_SPACE;
//IRDBG_INFO("NEC_HEADER_PULSE\n");
return 0;
}
else
break;
case STATE_HEADER_SPACE: //判断是引导码,还是重复码
if (ev.pulse)
break;
if (eq_margin(ev.duration,NEC_HEADER_SPACE_LWB,NEC_HEADER_SPACE_UPB)) //NEC_HEADER_SPACE_LWB = NEC_HEADER_SPACE_UPB = 4.5ms 判断是否为4.5ms,是则为引导码,是引导码接下来就去判断数据的值
{
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] %s ev.duration = %d 2.1 HEADER [case STATE_HEADER_SPACE] if HEADER(4.5ms)/REPORT(2.25ms) \n",__FUNCTION__,ev.duration);
data->eStatus = STATE_BIT_PULSE;
return 0;
}
else if (eq_margin(ev.duration,NEC_REPEAT_SPACE_LWB,NEC_REPEAT_SPACE_UPB)) //重复码 这里就将u8RepeatFlag值置为1 *********** 连续按键时的情况
{//repeat
//IRDBG_INFO("[NEC] TIME =%ld\n",(MIRC_Get_System_Time()-KeyTime));
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] %s ev.duration = %d 2.2 REPEAT [case STATE_HEADER_SPACE] if HEADER(4.5ms)/REPORT(2.25ms) \n",__FUNCTION__,ev.duration);
if (prevsc->scancode_protocol == (1<<IR_TYPE_NEC) && ((u32)(MIRC_Get_System_Time()- KeyTime) <= NEC_REPEAT_TIMEOUT))
{
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] 111111111111 \n");
KeyTime = MIRC_Get_System_Time();
if (((speed != 0)&&( data->u8RepeatTimes >= (speed - 1)))
|| ((speed == 0)&&(data->u8RepeatTimes >= dev->speed)))
{
#ifdef CONFIG_MIRC_INPUT_DEVICE
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] 2222222 \n");
sc->scancode = scancode;
sc->scancode_protocol = (1<<IR_TYPE_NEC);
dev->map_num = mapnum;
dev->raw->u8RepeatFlag = 1;
#else
sc->scancode_protocol = (1<<IR_TYPE_NEC);
sc->scancode = scancode|0x01;//repeat
#endif
memset(data,0,sizeof(IR_NEC_Spec_t));
return 1;
}
data->u8RepeatTimes ++;
//IRDBG_INFO("[NEC] repeattimes =%d \n",data->u8RepeatTimes);
}
else
{
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] 333333333 \n");
scancode = 0;
mapnum = NUM_KEYMAP_MAX;
}
data->eStatus = STATE_INACTIVE;
return 0;
}
break;
case STATE_BIT_PULSE: //判断是否为0.56ms,如果是在判断是数据1还是0
if (!ev.pulse)
break;
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] %s ev.duration = %d 3. [case STATE_BIT_PULSE] if data_duration(0.56ms) \n",__FUNCTION__,ev.duration);
if (!eq_margin(ev.duration,NEC_BIT_PULSE_LWB,NEC_BIT_PULSE_UPB))
break;
data->eStatus = STATE_BIT_SPACE;
return 0;
case STATE_BIT_SPACE: //判断是数据1还是0
if (ev.pulse)
break;
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] %s ev.pulse = %d 4. [case STATE_BIT_SPACE] if data_space(1=2.25-0.56,0=1.12-0.56) \n",__FUNCTION__,ev.pulse);
//printk("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] text_printk \n");
data->u32DataBits <<= 1;
if (eq_margin(ev.duration,NEC_BIT_1_SPACE_LWB,NEC_BIT_1_SPACE_UPB)) //如果为2.25-0.56ms,就是数据1
data->u32DataBits |= 1; //配合前面的移位操作实现对最终上报数据的拼接获取工作
else if (!eq_margin(ev.duration,NEC_BIT_0_SPACE_LWB,NEC_BIT_0_SPACE_UPB)) //如果为1.12-0.56ms就是数据0
break;
data->u8BitCount++;
if (data->u8BitCount == NEC_NBITS) //NEC_NBITS =32,=32表示数据接收完成了
{
IRDBG_ERR("************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] %s decode_data_finish 5. [case STATE_BIT_SPACE] \n",__FUNCTION__);
u8Addr = bitrev8((data->u32DataBits >> 24) & 0xff);
u8AddrInv = bitrev8((data->u32DataBits >> 16) & 0xff);
u8Cmd = bitrev8((data->u32DataBits >> 8) & 0xff);
u8CmdInv = bitrev8((data->u32DataBits >> 0) & 0xff);
IRDBG_INFO("[NEC] u8Addr = %x u8AddrInv = %x u8Cmd = %x u8CmdInv = %x\n",u8Addr,u8AddrInv,u8Cmd,u8CmdInv);
IRDBG_ERR("[wjc_ir] [ir-nec-decoder.c] u8Addr = %x u8AddrInv = %x u8Cmd = %x u8CmdInv = %x\n",u8Addr,u8AddrInv,u8Cmd,u8CmdInv);
for (i= 0;i<dev->support_num;i++)
{
if(dev->support_ir[i].eIRType == IR_TYPE_NEC)
{
if((((u8Addr<<8) | u8AddrInv) == dev->support_ir[i].u32HeadCode))
{
IRDBG_ERR("[wjc_ir] [ir-nec-decoder.c] match_headcode_ok headcode = %x \n",dev->support_ir[i].u32HeadCode);
if (u8Cmd == (u8)~u8CmdInv)
{
#ifdef CONFIG_MIRC_INPUT_DEVICE //执行这里 ************
sc->scancode = (u8Addr<<16) | (u8AddrInv<<8) | u8Cmd; //u8Cmd 就是声明值,遥控器开发文档中的值
sc->scancode_protocol = (1<<IR_TYPE_NEC);
scancode = sc->scancode;
speed = dev->support_ir[i].u32IRSpeed;
dev->map_num = dev->support_ir[i].u32HeadCode;
mapnum = dev->map_num;
dev->raw->u8RepeatFlag = 0; //非重复码即非相同按键
IRDBG_ERR("[wjc_ir] [ir-nec-decoder.c] jiaoyan_data_ok sc->scancode = %d \n",scancode);
#else
sc->scancode = (u8Cmd<<8) |0x00;
sc->scancode |= (0x01UL << 28);
sc->scancode_protocol = (1<<IR_TYPE_NEC);
scancode = sc->scancode;
speed = dev->support_ir[i].u32IRSpeed;
#endif
KeyTime = MIRC_Get_System_Time();
memset(data,0,sizeof(IR_NEC_Spec_t));
return 1; /*********** 非常关键,返回值大于0,实现get_scancode=1,下面的代码就是前面分析的根据scancode的值匹配映射表,获取keycode,然后上报数据
}
}
}
}
}
else
data->eStatus = STATE_BIT_PULSE;
return 0;
default:
break;
}
data->eStatus = STATE_INACTIVE;
return -EINVAL;
}
******************** 重中之重:不能在中断函数:_MDrv_IR_ISR中添加打印,会导致程序出现问题 **************************
打印分析: 因为中断中不能添加打印所以,从唤醒线程,即从线程中开始分析打印 *********** 最终版 按下音量+ 按键
duration:持续时间
pulse: 高低电平 ev.pulse = 1表示低电平,ev.pulse = 0表示高电平 *******非常重要
[ 164.202167] [ 164.203854] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 164.209349] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 16383 , ev.pulse = 0 ,get_scancode = 0 //???????????? 还不知道16383代表什么意思 。。
[ 164.223195] [ 164.224862] [IR ERR ]: ir_nec_decode[36]:
[ 164.229575] ************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 164.237682] [ 164.239355] [IR ERR ]: ir_nec_decode[56]:
[ 164.244081] ************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode ev.duration = 8319 1. [case STATE_INACTIVE] jx_ydm:9ms //9ms
[ 164.256800] [ 164.258467] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 164.263976] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 8319 , ev.pulse = 1 ,get_scancode = 0
[ 164.278842] [ 164.280524] [IR ERR ]: ir_nec_decode[36]:
[ 164.285236] ************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 164.293346] [ 164.295011] [IR ERR ]: ir_nec_decode[70]:
[ 164.299723] ************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode ev.duration = 4223 2.1 HEADER [case STATE_HEADER_SPACE] if HEADER(4.5ms)/REPORT(2.25ms) //4.5ms ,9ms+4.5ms表示是引导码 下面开始判断数据是1还是0
[ 164.315568] [ 164.317234] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 164.322728] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 4223 , ev.pulse = 0 ,get_scancode = 0
[ 164.336480] [ 164.338146] [IR ERR ]: ir_nec_decode[36]:
[ 164.342862] ************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 164.350975] [ 164.352646] [IR ERR ]: ir_nec_decode[117]:
[ 164.357444] ************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode ev.duration = 527 3. [case STATE_BIT_PULSE] if data_duration(0.56ms) //0.56ms 数据波形前缀正确
[ 164.371546] [ 164.373211] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 164.378707] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 527 , ev.pulse = 1 ,get_scancode = 0
[ 164.392378] [ 164.394044] [IR ERR ]: ir_nec_decode[36]:
[ 164.398756] ************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 164.406863] [ 164.408532] [IR ERR ]: ir_nec_decode[127]:
[ 164.413329] ************* ^_^ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode ev.duration = 559 4. [case STATE_BIT_SPACE] if data_space(1=2.25-0.56,0=1.12-0.56)
[ 164.428644] [ 164.430310] *** ^_^ *** [wjc_ir] [ir-nec-decoder.c] bit0 = 0 //0.56ms 数据0
[ 164.435979] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]: [ 164.441313] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 559 , ev.pulse = 0 ,get_scancode = 0
... .... 下面就开始一直解析数据 即解析32个数据波形中分别代码的值
bit0 = 0 bit8 = 0 bit16 = 1 bit24 = 0
bit1 = 0 bit9 = 0 bit17 = 0 bit25 = 1
bit2 = 0 bit10 = 0 bit18 = 1 bit26 = 0
bit3 = 0 bit11 = 0 bit19 = 0 bit27 = 1
bit4 = 0 bit12 = 0 bit20 = 1 bit28 = 0
bit5 = 0 bit13 = 0 bit21 = 0 bit29 = 1
bit6 = 1 bit14 = 1 bit22 = 0 bit30 = 1
bit7 = 0 bit15 = 0 bit23 = 0 bit31 = 1
==> ==> ==> ==>
0x40 0x40 0x15 0xea
[ 168.217732] [wjc_ir] [ir-nec-decoder.c] u8Addr = 40 u8AddrInv = 40 u8Cmd = 15 u8CmdInv = ea //刚刚好就是前面得到的4个值 *******xixi ^_^
[ 168.226152] [ 168.227828] [IR ERR ]: ir_nec_decode[161]:
[ 168.232631] [wjc_ir] [ir-nec-decoder.c] match_headcode_ok headcode = 4040 //这个就是u8Addr<<8 | u8AddrInv的值 ,这不就是头码吗? *******
[ 168.239531] [ 168.241249] [IR ERR ]: ir_nec_decode[173]:
[ 168.246051] [wjc_ir] [ir-nec-decoder.c] jiaoyan_data_ok sc->scancode = 4210709 //这个是校验数据ok的打印 **************** 4210709 >> 8 ==0x4040 头码, sc->scancode = (u8Addr<<16) | (u8AddrInv<<8) | u8Cmd;
[ 168.253459] [ 168.255190] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 168.260686] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 1615 , ev.pulse = 0 ,get_scancode = 1 //32bit数据全部解析完 get_scancode置1 然后开始通过scancode值获取keycode值然后input上报
[ 168.274448] [ 168.276175] [IR ERR ]: MIRC_Data_Ctrl_Thread[160]:
[ 168.281672] ***** ^_^ ******* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread raw->u8RepeatFlag = 0
[ 168.290389] [ 168.292111] [IR ERR ]: MIRC_Data_Ctrl_Thread[173]:
[ 168.297611] ***** ^_^ ******* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread raw->dev->filter_flag == 0
[ 168.306848] [ 168.308566] [IR ERR ]: MIRC_Data_Ctrl_Thread[184]:
[ 168.314064] ***** ^_^ ******* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread diff protocol //第一次按按键是不同的协议 后面按应该就是相同的协议了
[ 168.322180] [ 168.323910] [IR ERR ]: MIRC_Keydown[642]:
[ 168.328623] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Keydown process_key_press //进入MIRC_Keydown函数
[ 168.337500] [ 168.339220] [IR ERR ]: MIRC_Keycode_From_Map[594]:
[ 168.344720] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Keycode_From_Map match_keymap_ok keycode= 115 //MIRC_Keycode_From_Map函数中 按键的扫描值 = c->scancode中的低8位即可 代码实现: if (((map->map.scan[i].scancode&0xff) == (scancode&0xff)) && ((scancode>>8) == map->map.headcode))
[ 49.100590] ************* ^_^ ************* [wjc_ir] [ir_core.c] MIRC_Do_Keydown input data input_keycode = 115 ,keyvalue = 1 //这就是 最终input上报的数据
如果是开机之后按键按了好几次 ==> 相同协议条件达成
+
按同一个按键的打印 开机之后,间隔的按下v+
前面32bit打印就不展示了 都是一样的 *********
[ 85.654837] [IR ERR ]: ir_nec_decode[154]:
[ 85.654838] [wjc_ir] [ir-nec-decoder.c] u8Addr = 40 u8AddrInv = 40 u8Cmd = 15 u8CmdInv = ea
[ 85.654840]
[ 85.654841] [IR ERR ]: ir_nec_decode[161]:
[ 85.654841] [wjc_ir] [ir-nec-decoder.c] match_headcode_ok headcode = 4040
[ 85.654843]
[ 85.654844] [IR ERR ]: ir_nec_decode[173]:
[ 85.654844] [wjc_ir] [ir-nec-decoder.c] jiaoyan_data_ok sc->scancode = 4210709
[ 85.654846]
[ 85.654848] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 85.654848] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 1615 , ev.pulse = 0 ,get_scancode = 1
[ 85.654850]
[ 85.654851] [IR ERR ]: MIRC_Data_Ctrl_Thread[160]:
[ 85.654851] ***** _ ******* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread raw->u8RepeatFlag = 0
[ 85.654853]
[ 85.654854] [IR ERR ]: MIRC_Data_Ctrl_Thread[173]:
[ 85.654854] ***** _ ******* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread raw->dev->filter_flag == 0
[ 85.654856]
[ 85.654858] [IR ERR ]: MIRC_Data_Ctrl_Thread[192]:
[ 85.654858] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread same protocol diff key press = 1615
[ 85.654860]
[ 85.654861] [IR ERR ]: MIRC_Data_Ctrl_Thread[199]:
[ 85.654861] ***** _ ******* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread same protocol + diff key press //这个是按键按下
[ 85.654863]
[ 85.654864] [IR ERR ]: MIRC_Keydown[642]:
[ 85.654865] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Keydown process_key_press
[ 85.654867]
[ 85.654868] [IR ERR ]: MIRC_Keycode_From_Map[594]:
[ 85.654869] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Keycode_From_Map match_keymap_ok keycode= 115
[ 85.654905]
[ 85.654918] [IR ERR ]: MIRC_Do_Keydown[637]:
[ 85.654918] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Do_Keydown input data input_keycode = 115 ,keyvalue = 1
[ 85.655012]
[ 85.655014] [IR ERR ]: ir_nec_decode[36]:
[ 85.655014] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 85.655017]
[ 85.655019] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 85.655019] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 495 , ev.pulse = 1 ,get_scancode = 0
[ 85.655021]
[ 85.655022] [IR ERR ]: ir_nec_decode[36]:
[ 85.655023] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 85.655024]
[ 85.655026] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 85.655027] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 16383 , ev.pulse = 0 ,get_scancode = 0
[ 85.655029]
[ 85.655030] [IR ERR ]: ir_nec_decode[36]:
[ 85.655030] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 85.655032]
[ 85.655033] [IR ERR ]: ir_nec_decode[56]:
[ 85.655033] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode ev.duration = 8319 1. [case STATE_INACTIVE] jx_ydm:9ms //这里就会在一次判断,最终发现是相同协议,相同按键按下
[ 85.655035]
[ 85.655037] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 85.655037] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 8319 , ev.pulse = 1 ,get_scancode = 0
[ 85.655039]
[ 85.655040] [IR ERR ]: ir_nec_decode[36]:
[ 85.655040] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 85.655042]
[ 85.655044] [IR ERR ]: ir_nec_decode[77]:
[ 85.655044] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode ev.duration = 2175 2.2 REPEAT [case STATE_HEADER_SPACE] if HEADER(4.5ms)/REPORT(2.25ms)
[ 85.655046]
[ 85.655047] [IR ERR ]: ir_nec_decode[80]:
[ 85.655047] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] 111111111111
[ 85.655048]
[ 85.655049] [IR ERR ]: ir_nec_decode[86]:
[ 85.655050] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] 2222222
[ 85.655051]
[ 85.655053] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 85.655053] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 2175 , ev.pulse = 0 ,get_scancode = 1
[ 85.655055]
[ 85.655056] [IR ERR ]: MIRC_Data_Ctrl_Thread[160]:
[ 85.655056] ***** _ ******* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread raw->u8RepeatFlag = 1
[ 85.655058]
[ 85.655059] [IR ERR ]: MIRC_Data_Ctrl_Thread[173]:
[ 85.655060] ***** _ ******* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread raw->dev->filter_flag == 0
[ 85.655061]
[ 85.655063] [IR ERR ]: MIRC_Data_Ctrl_Thread[204]:
[ 85.655063] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread same protocol Repeat key press = 2175 //*********** 相同协议 相同按键
[ 85.655066]
[ 85.655067] [IR ERR ]: ir_nec_decode[36]:
[ 85.655067] ************* _ ************* [wjc_ir] [ir-nec-decoder.c] ir_nec_decode
[ 85.655069]
[ 85.655071] [IR ERR ]: MIRC_Data_Ctrl_Thread[148]:
[ 85.655071] ************* _ ************* [wjc_ir] [ir_core.c] MIRC_Data_Ctrl_Thread [sw_decoder] ev.duration = 495 , ev.pulse = 1 ,get_scancode = 0
************** 没了 说明前面一开始的分析是ok 的。。