在我们平常的TV,商显,等电子类产品很多是需要遥控器操作的。首先遥控器也是一款标准的设备驱动,一起分享一下M平台遥控器驱动。

设备树

在配置文件m7221_an.dts,中定义了遥控器设备

ir {
		compatible = "mstar-ir";
	};

这里只配置遥控器设备驱动的名称。

注册驱动

通过设备驱动的名称,可以找到平台驱动code。

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)
        .of_match_table = mstarir_of_device_ids,
#endif
        .name   = "Mstar-ir",
        .owner  = THIS_MODULE,
        .bus   = &platform_bus_type,
    }
};

static int __init mstar_ir_drv_init_module(void)
{
    int ret = 0;
    //  注册平台驱动
    ret = platform_driver_register(&Mstar_ir_driver);
    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();
    init_key_map_cultraview_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
#endif
    return ret;
}

注册完设备驱动之后,紧接着有注册了多款遥控器,最终通过MIRC_Map_Register将按键映射表添加到链表keymap_list中,
方便后面通过scancode 寻找keycode。

设备探测

/**===============end IR ATTR Functions ==================**/
static int mstar_ir_drv_probe(struct platform_device *pdev)
{
    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);
    if (ret < 0)
    {
        IRDBG_ERR("mstar_ir_register_device Failed! \n");
    }

    pdev->dev.platform_data=&IRDev;

    mstar_ir_customer_config();

#ifdef CONFIG_MIRC_INPUT_DEVICE
    mstar_ir_init(0);
    IRDev.u32IRFlag |= (IRFLAG_IRENABLE|IRFLAG_HWINITED);
#endif
    return ret;
}

mstar_ir_cdev_init 创建字符设备,mstar_ir_creat_sysfs_attr创建硬件设备驱动信息,mstar_ir_register_device 注册遥控器设备,mstar_ir_customer_config设置客户配置,mstar_ir_init 设置遥控器解码方式,注册中断。

注册设备

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
    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);
    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();
    if (!dev->input_dev)
    {
        ret = -ENOMEM;
        goto out_kfifo;
    }
    input_set_drvdata(dev->input_dev, dev);
    dev->input_name = MSTAR_IR_DEVICE_NAME;
    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
    dev->input_dev->id.bustype = BUS_I2C;
    dev->input_dev->id.vendor = INPUTID_VENDOR;
    dev->input_dev->id.product = INPUTID_PRODUCT;
    dev->input_dev->id.version = INPUTID_VERSION;
    set_bit(EV_KEY, dev->input_dev->evbit);
    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;
    dev->input_dev->name = dev->input_name;
    for (i = 0; i<KEY_CNT; i++)
    {
        __set_bit(i, dev->input_dev->keybit);
    }
    __clear_bit(BTN_TOUCH,dev->input_dev->keybit);// IR device without this case

    ret = input_register_device(dev->input_dev);
#endif
    //7. register IR Data ctrl
    ret = MIRC_Data_Ctrl_Init(dev);
    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;
}
  1. 创建锁
  2. 创建read fifo
  3. 创建wiatqueue
  4. 创建sme
  5. 创建,注册输入设备,input_allocate_device,input_register_device
    设置vendor id , product id 分别为0x3697,0x0001,这一步是所有输入设
    备。通过cat /proc/bus/input/devices,dumpsys input 指令查看注册的
    所有输入设备,touch ,ir,mouse,keypad等等
  6. MIRC_Data_Ctrl_Init注册IR 数据kthread线程MIRC_Data_Ctrl_Thread
    从kfifo中获取原始的按键数据

设置遥控器配置

#define    NUM_KEYMAP_MSTAR_TV                0x807F
#define    NUM_KEYMAP_CULTRAVIEW_TV           0x41FB
#define    NUM_KEYMAP_HHT_TV                  0x03FF
#define    NUM_KEYMAP_TCL_TV                  0x00F0
#define    NUM_KEYMAP_CHANGHONG_TV            0x40BF
#define    NUM_KEYMAP_HISENSE_TV              0x00BF
#define    NUM_KEYMAP_HAIER_TV                0x1818
#define    NUM_KEYMAP_KONKA_TV                0x0002
#define    NUM_KEYMAP_SKYWORTH_TV             0x0E0E
#define    NUM_KEYMAP_P7051_STB               0x484E5958
#define    NUM_KEYMAP_KATHREIN_TV             0x8046
#define    NUM_KEYMAP_TCL_RCA_TV              0xF000
#define    NUM_KEYMAP_RC5_TV                  0x0008
#define    NUM_KEYMAP_METZ_RM18_TV            0x0609
#define    NUM_KEYMAP_METZ_RM19_TV            0x0708

#define IR_SUPPORT_NUM 2

//Add & Modify Customer IR with Differ Headcode Here
static IR_Profile_t ir_config[IR_SUPPORT_NUM]=
{
    // {IR_TYPE_NEC,NUM_KEYMAP_MSTAR_TV,0},         // Mstar IR customer code
	{IR_TYPE_NEC,NUM_KEYMAP_HHT_TV,0},                // hht IR customer code
    {IR_TYPE_NEC,NUM_KEYMAP_CULTRAVIEW_TV,0},   // cultraview 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_RC6,NUM_KEYMAP_KATHREIN_TV,0},   //Kathrein RC6 customer code
    //{IR_TYPE_KONKA,NUM_KEYMAP_KONKA_TV,2},
};
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
   REG(REG_IR_CTRL) &= (0xFF00); //disable IR ctrl regs
   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))
        {
            ......
        }
        else
        {
            ret = request_irq(INT_NUM_IR_ALL, _MDrv_IR_ISR, SA_INTERRUPT, "IR", &IRDev);
            ir_irq_sel = 0;
        }

        ......
    }
    return ;
}

根据配置的遥控器解码方式,做好寄存器配置;接着request_irq(INT_NUM_IR_ALL, _MDrv_IR_ISR, SA_INTERRUPT, “IR”, &IRDev);申请中断。

中断处理

irqreturn_t _MDrv_IR_ISR(int irq, void *dev_id)
{
    IRModHandle *mstar_dev = dev_id;
    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;
}

中断触发后,获取按键值数据,然后写进fifo,最后唤醒线程。
下面以IR_TYPE_FULLDECODE_MODE 说明

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;

    //   duration =  head code | keyCode
    ev.duration = (u32IRHeaderCode[u8Ir_Index]<<8) | u8Keycode;
    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);
    if (ret < 0)
    {
        IRDBG_ERR("Store IR data Error!\n");
    }
    mstar_ir_nec_clearfifo();
    return ret;
}

int MIRC_Data_Store(struct mstar_ir_dev *dev, struct ir_raw_data *ev)
{
    if (!dev->raw)
        return -EINVAL;
    // 按键数据写入fifo
    if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
        return -ENOMEM;

    return 0;
}

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);
    spin_unlock_irqrestore(&dev->raw->lock, flags);
}

唤醒线程MIRC_Data_Ctrl_Thread往fifo 读取数据,接着解析。

数据解析

中断回调收取原始数据,转发值fifo 后,线程从fifo 读取数据并解析数据

static int MIRC_Data_Ctrl_Thread(void *data)
{
    struct ir_raw_data ev;
    struct ir_raw_data_ctrl *raw = (struct ir_raw_data_ctrl *)data;
    int retval;
    int get_scancode;

    while (!kthread_should_stop())
    {
        get_scancode = 0;
        spin_lock_irq(&raw->lock);
        retval = kfifo_len(&raw->kfifo);

        if (retval < sizeof(ev))
        {
            set_current_state(TASK_INTERRUPTIBLE);

            if (kthread_should_stop())
                set_current_state(TASK_RUNNING);
            spin_unlock_irq(&raw->lock);
            schedule();
            continue;
        }
       //  获取fifo 的数据
        retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
        spin_unlock_irq(&raw->lock);

        mutex_lock(&ir_decoder_lock);
        //  软解吗
        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;
                }
            }
        }
        else //hw decoder 硬解码
        {
            raw->this_sc.scancode = ev.duration;
            raw->u8RepeatFlag = ev.pulse;
            get_scancode = 1;
            IRDBG_MSG("keycode =%x  repeatflag =%d \n",raw->this_sc.scancode,raw->u8RepeatFlag);
        }

        if (get_scancode)
        {

            //diff protocol
            if(raw->u8RepeatFlag == 1)
            {
                eventtimeout = IR_DEFAULT_TIMEOUT;
            }
            else
            {
                eventtimeout = IR_FIRST_REPEAT_TIMEOUT;
            }
            _ulLastKeyPresentTime = MIRC_Get_System_Time();
            if(raw->dev->filter_flag == 0)
            {
    #ifdef CONFIG_MIRC_INPUT_DEVICE
                //diff protocol
                if (raw->this_sc.scancode_protocol!= raw->prev_sc.scancode_protocol)
                {
                    //if before timeout send keyup + keydown
                    if (time_after_eq((raw->keyup_jiffies+msecs_to_jiffies(eventtimeout)),jiffies))
                    {
                        MIRC_Keyup(raw->dev);
                    }
                    IRDBG_INFO("[2]========= Down First!\n");
                    MIRC_Keydown(raw->dev, raw->this_sc.scancode);//first keydown
                }
                else// same protocol
                {
                    if (raw->this_sc.scancode != raw->prev_sc.scancode)// diff key press
                    {
                        //if before timeout send keyup + keydown
                        if (time_after_eq((raw->keyup_jiffies+msecs_to_jiffies(eventtimeout)),jiffies))
                        {
                            MIRC_Keyup(raw->dev);
                        }
                        IRDBG_INFO("[1]========= Down First!\n");
                        MIRC_Keydown(raw->dev, raw->this_sc.scancode);//first keydown
                    }
                    else
                    {
                        if((raw->u8RepeatFlag == 0)&& (!raw->dev->keypressed ))// press the same fast
                        {
                            MIRC_Keydown(raw->dev, raw->this_sc.scancode);
                        }
                        else
                        {
                            IRDBG_INFO("========= Repeat!\n");
                        }
                    }
                }
            }

            del_timer(&(raw->timer_keyup));
            raw->timer_keyup.expires = jiffies + msecs_to_jiffies(eventtimeout);
            raw->keyup_jiffies = jiffies;
            raw->timer_keyup.data = (unsigned long)raw->dev;
            add_timer(&(raw->timer_keyup));
#else
            // for DFB polling read   /dev/ir
            if (down_trylock(&raw->dev->sem)==0)
            {
                IRDBG_INFO("scancode =%x \n",raw->this_sc.scancode);
                if (kfifo_in(&raw->dev->read_fifo, &raw->this_sc.scancode, sizeof(u32)) != sizeof(u32))
                {
                    up(&raw->dev->sem);
                    mutex_unlock(&ir_decoder_lock);
                    return -ENOMEM;
                }
                up(&raw->dev->sem);
                wake_up_interruptible(&raw->dev->read_wait);
            }
#endif
            //record IR last scancode
            raw->prev_sc.scancode_protocol = raw->this_sc.scancode_protocol;
            raw->prev_sc.scancode = raw->this_sc.scancode;
            raw->this_sc.scancode_protocol = 0;
            raw->this_sc.scancode = 0x0;
            raw->u8RepeatFlag = 0;
        }
        mutex_unlock(&ir_decoder_lock);
    }

    return 0;
}

MIRC_Keydown 解析分发数据

void MIRC_Keydown(struct mstar_ir_dev *dev, int scancode)
{
    unsigned long flags;
    u32 keycode = MIRC_Keycode_From_Map(dev->map_num, scancode);
    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);
    spin_unlock_irqrestore(&dev->keylock, flags);
}

MIRC_Keycode_From_Map从注册key map 链表keymap_list 中遍历,去匹配遥控器头码。

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)
    {
      ......
    }
    spin_unlock(&key_map_lock);
    return keycode;
}

MIRC_Do_Keydown 拼接成标注的输入事件,通过/dev/input/eventX
发往上层。

static void MIRC_Do_Keydown(struct mstar_ir_dev *dev, int scancode,u32 keycode)
{
    bool new_event = !dev->keypressed ||
        dev->last_scancode != scancode;

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

    input_sync(dev->input_dev);
}

例如home键

androidtv 遥控器 code_#if


添加一款遥控器

ir_config.h

androidtv 遥控器 code_#if_02


ir_common.h

androidtv 遥控器 code_#endif_03


mstar_ir.h

androidtv 遥控器 code_androidtv 遥控器 code_04


keymap-cultraview-tv.c,定义key_map_table ,添加scancode,和keycode 的映射。

#include <linux/kernel.h>
#include <linux/module.h>
#include "../ir_core.h"
#include "../ir_common.h"

static struct key_map_table cultraview_tv[] = {
    // 2nd IR controller.
    { 0xfb82, KEY_POWER },
    { 0xfb9b, KEY_CHANNELUP },
    { 0xfb8f, KEY_CHANNELDOWN },
    { 0xfb97, KEY_MENU },
    .........
    { 0xfbFC, KEY_POWER2 },
};

static struct key_map_list cultraview_tv_map = {
    .map = {
        .scan    = cultraview_tv,
        .size    = ARRAY_SIZE(cultraview_tv),
        .name    = NAME_KEYMAP_CULTRAVIEW_TV,
        .headcode     = NUM_KEYMAP_CULTRAVIEW_TV,
    }
};

int init_key_map_cultraview_tv(void)
{
    return MIRC_Map_Register(&cultraview_tv_map);
}
EXPORT_SYMBOL(init_key_map_cultraview_tv);

void exit_key_map_cultraview_tv(void)
{
    MIRC_Map_UnRegister(&cultraview_tv_map);
}
EXPORT_SYMBOL(exit_key_map_cultraview_tv);

mdrv_ir.c 添加key code 与字符串的映射,getevent -l 时,可以正确知道底层映射关系

static const str2key_map_t str2key_map[] =
{
    { "KEY_POWER", KEY_POWER },
    { "KEY_MUTE", KEY_MUTE },
    { "KEY_HOME", KEY_HOME },
    { "KEY_ENTER", KEY_ENTER },
    { "KEY_UP", KEY_UP },
    { "KEY_DOWN", KEY_DOWN },
    { "KEY_LEFT", KEY_LEFT },
    { "KEY_RIGHT", KEY_RIGHT },
    { "KEY_BACK", KEY_BACK},
    { "KEY_MENU", KEY_MENU },
    ......
    }

mstar_ir.c 注册新增key map

static int __init mstar_ir_drv_init_module(void)
{
    int ret = 0;
	......
    init_key_map_cultraview_tv();
    ......
    return ret;
 }
static void __exit mstar_ir_drv_exit_module(void)
{
	......
    exit_key_map_cultraview_tv();
 }

添加说明:

  1. 遥控器头码要正确;
  2. 注意key_map_table 中的scancode 中前面8位为headcode ,scancode
    为后面8位,keycode 是值在
    vendor\mstar\kernel\linaro\include\uapi\linux\input-event-codes.h中定
    义,getevent 无打印响应时,就有key map 没有配置正确;
  3. getevnet 收到按键的信息之后,就需要在android层映射keycode 到应用
    层的keyevent code
    例如kl 文件第一列是keycode 的值(十进制),第二列则是对应frameworks\native\include\android\keycodes.h 文件中的枚举去掉AKEYCODE_前缀之后的字符串。注意kl 文件中如果有定义的配置找不到
    就有可能是按键不响应,或者到没有使用配置的kl文件,而使用了系统默认Generic.kl.
  4. IR调试方法,echo 4 > ./sys/bus/platform/drivers/Mstar-ir/ir/IRDebug
    打开IR模块驱动打印,记得printk 节点也要为7。