Linux遥控器设备驱动程序源代码研究


遥控器设备驱动程序源代码分析


1.源代码位置

\kernel\drivers\input\remotectl

 

2.源代码分析

2.1 程序头部
 

/*

 * Driver for keys onGPIO lines capable of generating interrupts.

 *

 * Copyright 2005Phil Blundell

 *

 * This program isfree software; you can redistribute it and/or modify

 * it under the termsof the GNU General Public License version 2 as

 * published by theFree Software Foundation.

 */

 

/*

NEC遥控器命令格式:

8位地址和8位命令长度

为提高可靠性每次传输两遍地址(用户码)和命令(按键值)

通过脉冲串之间的时间间隔来实现信号的调制

38Khz载波

每位的周期为1.12ms或者2.25ms. 分别表示0和1.

9+4.5ms表示起始位.

 

起始码+用户码+命令码

*/

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <linux/interrupt.h>

#include <linux/irq.h>

#include <linux/sched.h>

#include <linux/pm.h>

#include <linux/sysctl.h>

#include <linux/proc_fs.h>

#include <linux/delay.h>

#include <linux/platform_device.h>

#include <linux/input.h>

#include <linux/workqueue.h>

#include <linux/adc.h>

#include <asm/gpio.h>

#include <mach/remotectl.h>

#include <mach/iomux.h>

#include <linux/wakelock.h>

#include <linux/suspend.h>

 

 

#if 1

#define remotectl_dbg(bdata, format, arg...)      \

dev_printk(KERN_INFO, &bdata->input->dev , format , ## arg)

#else

#define remotectl_dbg(bdata, format, arg...) 

#endif

 

extern suspend_state_t get_suspend_state(void);

 

#ifdef CONFIG_RK30_KEYBOARD_LED_CTL

extern int rk29_keyboard_led_init(void);

extern int rk29_keyboard_led_suspend(void);

extern int rk29_keyboard_led_resume(void);

#endif

 

struct rkxx_remotectl_suspend_data{

    int suspend_flag;

    int cnt;

    longscanTime[50];

};

 

struct rkxx_remote_key_table{

    int scanCode;

int keyCode;     

};

 

struct rkxx_remotectl_button { 

    int usercode;

    int nbuttons;

    structrkxx_remote_key_table *key_table;

};


2.2 遥控器驱动数据块
/* 遥控器驱动的核心结构体

里面包含用户码, 遥控器的扫描码等信息*/

struct rkxx_remotectl_drvdata {

    int state;

int nbuttons;

int result;

    unsigned longpre_time;

    unsigned longcur_time;

    long period;

    int scanData;/*被扫描到的位值. 命令码为2字节*/

    int count;

    int keybdNum;

    int keycode;

    int press;/*当remotectl_do_something检测到有按键被按下时, 置为1*/

    int pre_press;/*恒为0*/

   

    struct input_dev*input;

    struct timer_listtimer;

    structtasklet_struct remote_tasklet;

    struct wake_lockremotectl_wake_lock;

    structrkxx_remotectl_suspend_data remotectl_suspend_data;

};

 


 

2.3 功能键值
//特殊功能键值定义

    //193      //photo

    //194      //video

    //195      //music

    //196      //IE

    //197      //

    //198

    //199

    //200

   

    //183      //rorate_left

    //184      //rorate_right

    //185      //zoom out

    //186      //zoom in

   

static struct rkxx_remote_key_tableremote_key_table_meiyu_202[] = {

    {0xB0,KEY_REPLY},//ok = DPAD CENTER

    {0xA2, KEY_BACK},

    {0xD0, KEY_UP},

    {0x70, KEY_DOWN},

    {0x08, KEY_LEFT},

    {0x88,KEY_RIGHT},  

    {0x42,KEY_HOME},     //home

    {0xA8,KEY_VOLUMEUP},

    {0x38,KEY_VOLUMEDOWN},

    {0xE2,KEY_SEARCH},     //search

    {0xB2,KEY_POWER},     //power off

    {0xC2, KEY_MUTE},      //mute

    {0xC8, KEY_MENU},

 

//media ctrl

    {0x78,   0x190},     //play pause

    {0xF8,   0x191},     //pre

    {0x02,   0x192},     //next

 

//pic

    {0xB8, 183},          //rorate left

    {0x58, 184},          //rorate right

    {0x68, 185},          //zoom out

    {0x98, 186},          //zoom in

//mouse switch

    {0xf0,388},

//display switch

    {0x82,   0x175},

};

 

static struct rkxx_remote_key_table remote_key_table_df[] ={

    {0xf8,KEY_REPLY},

    {0xc0, KEY_BACK},

    {0xf0, KEY_UP},

    {0xd8, KEY_DOWN},

    {0xd0, KEY_LEFT},

   {0xe8,KEY_RIGHT},  

    {0x90,KEY_VOLUMEDOWN},

    {0x60,KEY_VOLUMEUP},

    {0x80,KEY_HOME},     //home

    {0xe0, 183},          //rorate left

    {0x10, 184},          //rorate right

    {0x20, 185},          //zoom out

    {0xa0, 186},          //zoom in

    {0x70,KEY_MUTE},       //mute

    {0x50,KEY_POWER},     //power off

    {0x40,KEY_SEARCH},     //search

};

 

 

static struct rkxx_remote_key_table remote_key_table_1fe[]= {

    {0x00, KEY_POWER},

{0x80, KEY_MUTE},

{0x20,KEY_1},

{0xc0,KEY_2},

{0x40,KEY_3},

{0xa0,KEY_4},

{0x60,KEY_5},

{0xe0,KEY_6},

{0x50,KEY_7},

{0x90,KEY_8},

{0x10,KEY_9},

{0xd0,KEY_PLAYPAUSE},   

{0x30,KEY_0},

{0xb0,KEY_DELETE},  

{0x08,KEY_MODE},

{0xf0,KEY_SEARCH},  

{0x70,KEY_F1},

{0x88,KEY_VOLUMEUP},

{0xe8,KEY_VOLUMEDOWN},  

{0x48,KEY_UP},   

{0x18,KEY_DOWN},

{0x68,KEY_LEFT},

{0x28,KEY_RIGHT},

{0xa8,KEY_REPLY},

{0xd8,KEY_MENU}, 

    {0x58,KEY_BACK},    

{0xb8,KEY_HOME}, 

{0x38,KEY_F2},   

{0x78,KEY_PREVIOUS},

{0xf8,KEY_NEXT},

{0xc8, 185},          //zoom out

    {0x98, 186},          //zoom in

      

};

 

extern suspend_state_t get_suspend_state(void);

 

/* 三种类型的遥控器, 分别对应不同的用户码

用户码是用于区分设备的厂家的,

避免不同厂家设备遥控键值混淆*/

static struct rkxx_remotectl_button remotectl_button[] =

{

    { 

       .usercode =0x202,

       .nbuttons=  22,

       .key_table =&remote_key_table_meiyu_202[0],

    },

    { 

       .usercode =0xdf,

       .nbuttons=  16,

       .key_table =&remote_key_table_df[0],

    },

    { 

       .usercode =0x1fe,

       .nbuttons =32,

       .key_table =&remote_key_table_1fe[0],

    },

};

 


2.4 遥控器类型键值查询函数
/* 从遥控参数查找对应的遥控器类型*/

static int remotectl_keybdNum_lookup(structrkxx_remotectl_drvdata *ddata)

{  

    int i;

 

    for (i = 0; i< sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button); i++){  

        if(remotectl_button[i].usercode == (ddata->scanData&0xFFFF)){       

           ddata->keybdNum = i;

            return 1;

        }

    }

    return 0;

}

 

/* 从遥控参数查找遥控键值*/

static int remotectl_keycode_lookup(structrkxx_remotectl_drvdata *ddata)

{  

    int i;

    unsigned charkeyData = ((ddata->scanData >> 8) & 0xff);

 

    for (i = 0; i< remotectl_button[ddata->keybdNum].nbuttons; i++){

        if(remotectl_button[ddata->keybdNum].key_table[i].scanCode == keyData){       

           ddata->keycode = remotectl_button[ddata->keybdNum].key_table[i].keyCode;

            return 1;

        }

    }

    return 0;

}


 

2.5 遥控器驱动流程处理函数
/*遥控器的主要通信处理函数*/

static void remotectl_do_something(unsigned long  data)

{

    structrkxx_remotectl_drvdata *ddata = (struct rkxx_remotectl_drvdata *)data;

 

    switch(ddata->state)

    {

        caseRMC_IDLE:

        {

            ;

        }

        break;

        /*如果当前状态是起始状态 */

        caseRMC_PRELOAD:

        {

        /*起始码NEC为9+4.5ms*/

            if((TIME_PRE_MIN < ddata->period) && (ddata->period <TIME_PRE_MAX)){

               

               ddata->scanData = 0;

                ddata->count = 0;

               ddata->state = RMC_USERCODE;/*设置为准备接收用户码状态*/

            }else{

               ddata->state = RMC_PRELOAD;

            }

           ddata->pre_time = ddata->cur_time;

           //mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));

        }

        break;

        /*如果当前状态是用户码状态

    这里处理的数据为接收用户码*/

        caseRMC_USERCODE:

        {

           ddata->scanData <<= 1;

           ddata->count ++;

 

    /*当前的时间间隔是否表明当前位为1?*/

            if((TIME_BIT1_MIN < ddata->period) && (ddata->period <TIME_BIT1_MAX)){

               ddata->scanData |= 0x01;

            }

 

    /*如果16位用户码接收完成

    进一步根据用户码判断遥控器类型*/

            if(ddata->count == 0x10){//16 bit user code

               //printk("u=0x%x\n",((ddata->scanData)&0xFFFF));

                if(remotectl_keybdNum_lookup(ddata)){/* 查找遥控器类型 */

                   ddata->state = RMC_GETDATA;/*遥控器类型已找到, 准备接收命令码*/

                   ddata->scanData = 0;

                   ddata->count = 0;

               }else{                /*user code error 用户码没有找到, 则其后的命令也没有意义了, 回到接收起始码状态. */

                   ddata->state = RMC_PRELOAD;

                }

            }

        }

        break;

        /*如果当前状态是接收命令码状态*/

        caseRMC_GETDATA:

        {

           ddata->count ++;

           ddata->scanData <<= 1;

 

          /*当前的时间间隔是否表明当前位为1?*/

            if((TIME_BIT1_MIN < ddata->period) && (ddata->period <TIME_BIT1_MAX)){

               ddata->scanData |= 0x01;

            }          

    /*如果16位命令码接收完成*/

            if(ddata->count == 0x10){

               //printk(KERN_ERR "d=%x\n",(ddata->scanData&0xFFFF));

        /*命令码的高8位与低8位是反码关系, 用于验证命令码是否正确*/

                if((ddata->scanData&0x0ff) == ((~ddata->scanData >>8)&0x0ff)){

              

               #ifdefCONFIG_RK30_KEYBOARD_LED_CTL

               rk29_keyboard_led_suspend();

               #endif

        /*查找键值*/

                   if (remotectl_keycode_lookup(ddata)){

                       ddata->press = 1;

           /*区分是否待机状态, 对遥控器键值作出不同的响应

           input_event之后就不管了, 交给input.c去进行逻辑处理*/

                         if (get_suspend_state()==0){

                               input_event(ddata->input, EV_KEY, ddata->keycode, 1);

                               input_sync(ddata->input);

                           }else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){

                               input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);

                               input_sync(ddata->input);

                           }

                       //input_event(ddata->input, EV_KEY, ddata->keycode,ddata->press);

                    //input_sync(ddata->input);

                       ddata->state = RMC_SEQUENCE;

                   }else{

                       ddata->state = RMC_PRELOAD;

                    }

               }else{

                    ddata->state = RMC_PRELOAD;

                }

            }

        }

        break;

 

        caseRMC_SEQUENCE:{

 

            //printk("S\n");

           

            if((TIME_RPT_MIN < ddata->period) && (ddata->period <TIME_RPT_MAX)){

                ;

            }else if((TIME_SEQ_MIN < ddata->period) && (ddata->period <TIME_SEQ_MAX)){

            if (ddata->press == 1){

                   ddata->press = 3;

                }elseif (ddata->press & 0x2){

                   ddata->press = 2;

               //input_event(ddata->input, EV_KEY, ddata->keycode, 2);

                //input_sync(ddata->input);

                }

               //mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));

               //ddata->state = RMC_PRELOAD;

            }

        }

        break;

      

        default:

            break;

    }

return;

}

 

 

#ifdef CONFIG_PM

void remotectl_wakeup(unsigned long _data)

{

    structrkxx_remotectl_drvdata *ddata =  (structrkxx_remotectl_drvdata*)_data;

    long *time;

    int i;

 

    time =ddata->remotectl_suspend_data.scanTime;

 

/*如果是待机状态*/

    if(get_suspend_state()){

       

        static intcnt;

      

       ddata->remotectl_suspend_data.suspend_flag = 0;

       ddata->count = 0;

       ddata->state = RMC_USERCODE;

       ddata->scanData = 0;

 

    /*如果是用户码/命令码, 则得到起始位置*/

        for(i=0;i<ddata->remotectl_suspend_data.cnt;i++){

            if(((TIME_BIT1_MIN<time[i])&&(TIME_BIT1_MAX>time[i]))||((TIME_BIT0_MIN<time[i])&&(TIME_BIT0_MAX>time[i]))){

                cnt =i;

               break;;

            }

        }

 

    /*用户码/命令码之后的32个位都要处理*/

        for(;i<cnt+32;i++){

           ddata->scanData <<= 1;

           ddata->count ++;

 

    /*如果位值是1*/

            if((TIME_BIT1_MIN < time[i]) && (time[i] < TIME_BIT1_MAX)){

               ddata->scanData |= 0x01;

            }

 

    /*得到一个完整的用户码/命令码*/

            if(ddata->count == 0x10){//16 bit user code

 

        /*如果是用户码, 则查找遥控器类型*/

                if(ddata->state == RMC_USERCODE){

//                   printk(KERN_ERR"d=%x\n",(ddata->scanData&0xFFFF)); 

                    if (remotectl_keybdNum_lookup(ddata)){

                       ddata->scanData = 0;

                       ddata->count = 0;

                       ddata->state = RMC_GETDATA;

                   }else{

                       ddata->state = RMC_PRELOAD;

                    }

                }elseif (ddata->state == RMC_GETDATA){

                /*如果是命令码, 则先反码校验数据是否正确, 然后查找遥控器键值*/

           /*如果是待机键, 则唤醒*/

                   if ((ddata->scanData&0x0ff) == ((~ddata->scanData >>8)&0x0ff)){

//                       printk(KERN_ERR "d=%x\n",(ddata->scanData&0xFFFF));

                        if (remotectl_keycode_lookup(ddata)){

                            if (ddata->keycode==KEY_POWER){

                               input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);

                               input_sync(ddata->input);

                                input_event(ddata->input,EV_KEY, KEY_WAKEUP, 0);

                               input_sync(ddata->input);

                           }

           /*回到接收起始码状态*/

                           ddata->state = RMC_PRELOAD;

                       }else{

                           ddata->state = RMC_PRELOAD;

                       }

                   }else{

                       ddata->state = RMC_PRELOAD;

                    }

               }else{

                   ddata->state = RMC_PRELOAD;

                }

            }

        }

    }

   memset(ddata->remotectl_suspend_data.scanTime,0,50*sizeof(long));

   ddata->remotectl_suspend_data.cnt= 0;

    ddata->state =RMC_PRELOAD;

   

}

 

#endif

 


2.6 按键弹起定时器
/*这个定时器似乎有问题啊,

因为前面检测到按键之后, 就将键值给了input_event了

这里的remotectl_timer再给一次, 相当于重复的键值了!!!!*/

 

/*这个函数应该是用来处理重复按键的, 但是这种处理方式有问题

或者应该判断ddata->press不为1的情况, 即在处理SEQUENCE的情况.

press的取值为1, 3, 2顺序.

但是input_event的最后一个参数值是0, 似乎是del_timer. */

/*

XX在报遥控器有重复按键的问题, 是否这里造成的?????

研究一下input_event的最后一个参数1, 和0的区别.

===

1是发送键值, 0是del_timer, 什么意思???移除定时器. 那remotectl_timer不就没有意义了???

*/

/*明白了, 原来传0是表示释放的意思. mod_timer就是表示多久之后自动释放.

remotectl_timer也是用于处理按键释放事件的. */

 

/*这是自动连击计时器吗??????????????????????????????????????????????????????????????????*/

static void remotectl_timer(unsigned long _data)

{

    structrkxx_remotectl_drvdata *ddata =  (structrkxx_remotectl_drvdata*)_data;

   

   //printk("to\n");

   

#ifdefCONFIG_RK30_KEYBOARD_LED_CTL

rk29_keyboard_led_resume();

#endif

/*当有遥控器按键被按下时, press将被置为1*/

   if(ddata->press != ddata->pre_press) {

       ddata->pre_press = ddata->press = 0;

 

/*正常状态下, 发送遥控码*/

        if(get_suspend_state()==0){

           //input_event(ddata->input, EV_KEY, ddata->keycode, 1);

            //input_sync(ddata->input);

           input_event(ddata->input, EV_KEY, ddata->keycode, 0);

        input_sync(ddata->input);

/*如果是待机状态, 且遥控码是电源键, 则开机*/

        }else if((get_suspend_state())&&(ddata->keycode==KEY_POWER)){

           //input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1);

           //input_sync(ddata->input);

           input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0);

           input_sync(ddata->input);

        }

    }

/*PM是Power Management的意思? 电源管理? 如果是, 此处将是电源定时开机*/

#ifdef CONFIG_PM

   remotectl_wakeup(_data);

#endif

    ddata->state =RMC_PRELOAD;

}


 

2.7 遥控中断处理函数
/*一个中断就是一个位.

遥控器的电平每发生一次完整的变化, 产生一个中断

在这个中断里只负责判断这个电平中断所占用的时间

在remotectl_do_something中会根据这个时间判断位的值,

进而得到遥控器的键值.

*/

static irqreturn_t remotectl_isr(int irq, void *dev_id)

{

    structrkxx_remotectl_drvdata *ddata =  (structrkxx_remotectl_drvdata*)dev_id;

    structtimeval  ts;

 

 

   ddata->pre_time = ddata->cur_time;

   do_gettimeofday(&ts);

   ddata->cur_time = ts.tv_usec;

 

    if(ddata->cur_time && ddata->pre_time)

       ddata->period = ddata->cur_time - ddata->pre_time;

 

   tasklet_hi_schedule(&ddata->remote_tasklet);

/*在起始码时激活定时器. 自动连击计时器???*/

    if((ddata->state==RMC_PRELOAD)||(ddata->state==RMC_SEQUENCE))

        mod_timer(&ddata->timer,jiffies + msecs_to_jiffies(130));

#ifdef CONFIG_PM

   //wake_lock_timeout(&ddata->remotectl_wake_lock, HZ);

    /*待机状态下的遥控按键, 全部保存到数组中, 最多保存50个

每一个中断保存一次, 计数器增加一个. */

   if((get_suspend_state())&&(ddata->remotectl_suspend_data.cnt<50))

      ddata->remotectl_suspend_data.scanTime[ddata->remotectl_suspend_data.cnt++]= ddata->period;

#endif

 

    returnIRQ_HANDLED;

}


2.8 遥控设备驱动初始化函数
/*初始化遥控器驱动程序*/

static int __devinit remotectl_probe(struct platform_device*pdev)

{

    structRKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;

    structrkxx_remotectl_drvdata *ddata;

    struct input_dev*input;

    int i, j;

    int irq;

    int error = 0;

 

   printk("++++++++remotectl_probe\n");

 

    if(!pdata)

        return-EINVAL;

#ifdefCONFIG_RK30_KEYBOARD_LED_CTL   

rk29_keyboard_led_init();

#endif

    ddata =kzalloc(sizeof(struct rkxx_remotectl_drvdata),GFP_KERNEL);

   memset(ddata,0,sizeof(struct rkxx_remotectl_drvdata));

 

    ddata->state =RMC_PRELOAD;

    input =input_allocate_device();

   

    if (!ddata ||!input) {

        error =-ENOMEM;

        goto fail0;

    }

 

   platform_set_drvdata(pdev, ddata);

 

    input->name =pdev->name;

    input->phys ="gpio-keys/input0";

   input->dev.parent = &pdev->dev;

 

   input->id.bustype = BUS_HOST;

    input->id.vendor= 0x0001;

   input->id.product = 0x0001;

   input->id.version = 0x0100;

 

/* Enable auto repeatfeature of Linux input subsystem */

if (pdata->rep)

    __set_bit(EV_REP,input->evbit);

   

ddata->nbuttons =pdata->nbuttons;

ddata->input =input;

 wake_lock_init(&ddata->remotectl_wake_lock, WAKE_LOCK_SUSPEND,"rk29_remote");

  if(pdata->set_iomux){

    pdata->set_iomux();

  }

  error =gpio_request(pdata->gpio, "remotectl");

if (error < 0) {

    printk("gpio-keys:failed to request GPIO %d,"

    " error%d\n", pdata->gpio, error);

    //goto fail1;

}

error =gpio_direction_input(pdata->gpio);

if (error < 0) {

    pr_err("gpio-keys:failed to configure input"

        "direction for GPIO %d, error %d\n",

    pdata->gpio,error);

    gpio_free(pdata->gpio);

    //goto fail1;

}

    irq =gpio_to_irq(pdata->gpio);

if (irq < 0) {

    error = irq;

    pr_err("gpio-keys:Unable to get irq number for GPIO %d, error %d\n",

    pdata->gpio,error);

    gpio_free(pdata->gpio);

    goto fail1;

}

error =request_irq(irq, remotectl_isr,   IRQF_TRIGGER_FALLING, "remotectl", ddata);

if (error) {

    pr_err("gpio-remotectl:Unable to claim irq %d; error %d\n", irq, error);

    gpio_free(pdata->gpio);

    goto fail1;

}

   setup_timer(&ddata->timer,remotectl_timer, (unsigned long)ddata);

   

   tasklet_init(&ddata->remote_tasklet, remotectl_do_something,(unsigned long)ddata);

   

    for(j=0;j<sizeof(remotectl_button)/sizeof(struct rkxx_remotectl_button);j++){

        printk("remotectl probej=0x%x\n",j);

    for (i = 0; i <remotectl_button[j].nbuttons; i++) {

        unsigned inttype = EV_KEY;

       

        input_set_capability(input,type, remotectl_button[j].key_table[i].keyCode);

    }

  }

error =input_register_device(input);

if (error) {

    pr_err("gpio-keys:Unable to register input device, error: %d\n", error);

    goto fail2;

}

   

   input_set_capability(input, EV_KEY, KEY_WAKEUP);

 

device_init_wakeup(&pdev->dev,1);

 

return 0;

 

fail2:

   pr_err("gpio-remotectl input_allocate_device fail\n");

input_free_device(input);

kfree(ddata);

fail1:

   pr_err("gpio-remotectl gpio irq request fail\n");

   free_irq(gpio_to_irq(pdata->gpio), ddata);

   del_timer_sync(&ddata->timer);

   tasklet_kill(&ddata->remote_tasklet);

   gpio_free(pdata->gpio);

fail0:

   pr_err("gpio-remotectl input_register_device fail\n");

   platform_set_drvdata(pdev, NULL);

 

return error;

}

 

static int __devexit remotectl_remove(structplatform_device *pdev)

{

structRKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;

struct rkxx_remotectl_drvdata*ddata = platform_get_drvdata(pdev);

struct input_dev*input = ddata->input;

    int irq;

 

device_init_wakeup(&pdev->dev,0);

    irq =gpio_to_irq(pdata->gpio);

    free_irq(irq,ddata);

   tasklet_kill(&ddata->remote_tasklet);

    gpio_free(pdata->gpio);

 

input_unregister_device(input);

 

return 0;

}

 

 

#ifdef CONFIG_PM

static int remotectl_suspend(struct device *dev)

{

structplatform_device *pdev = to_platform_device(dev);

structRKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;

    structrkxx_remotectl_drvdata *ddata = platform_get_drvdata(pdev);

   

   //ddata->remotectl_suspend_data.suspend_flag = 1;

   ddata->remotectl_suspend_data.cnt = 0;

 

if(device_may_wakeup(&pdev->dev)) {

    if(pdata->wakeup) {

        int irq = gpio_to_irq(pdata->gpio);

        enable_irq_wake(irq);

    }

}

   

return 0;

}

 

static int remotectl_resume(struct device *dev)

{

structplatform_device *pdev = to_platform_device(dev);

structRKxx_remotectl_platform_data *pdata = pdev->dev.platform_data;

 

    if (device_may_wakeup(&pdev->dev)) {

        if(pdata->wakeup) {

            int irq =gpio_to_irq(pdata->gpio);

           disable_irq_wake(irq);

        }

    }

 

return 0;

}

 

static const struct dev_pm_ops remotectl_pm_ops = {

.suspend   = remotectl_suspend,

.resume       = remotectl_resume,

};

#endif

 

 

 

static struct platform_driver remotectl_device_driver = {

.probe     = remotectl_probe,

.remove       = __devexit_p(remotectl_remove),

.driver       = {

    .name  = "rkxx-remotectl",

    .owner = THIS_MODULE,

#ifdef CONFIG_PM

    .pm    =&remotectl_pm_ops,

#endif

},

 

};

 

static int remotectl_init(void)

{

    printk(KERN_INFO"++++++++remotectl_init\n");

    returnplatform_driver_register(&remotectl_device_driver);

}

 

 

static void remotectl_exit(void)

{

platform_driver_unregister(&remotectl_device_driver);

    printk(KERN_INFO"++++++++remotectl_init\n");

}

 

module_init(remotectl_init);

module_exit(remotectl_exit);

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("rockchip");

MODULE_DESCRIPTION("Keyboard driver for CPUGPIOs");

MODULE_ALIAS("platform:gpio-keys1");

 


 

3.遗留问题

3.1自动连击计时器原理.

  Kernel中有事件驱动程序设备驱动程序,这是两类不同的驱动程序。

  事件驱动程序处理所有输入设备的具有共性的流程,设备驱动程序则针对硬件、中断、寄存器等进行相应的处理。一个面向上层,一个面向硬件。

  连击计时是由事件驱动程序自动处理的.

  就是说, 如果在指定时间内, 比如250毫秒内, 如果事件驱动程序没有收到input_event(, , 0)消息, 则事件驱动程序自动生成连击事件.

  如果在250毫秒内, 设备驱动程序(RKXX_remotectl.c)发送了input_event(, , 0)消息, 则事件驱动将调用input_stop_autorepeat结束自动连击生成.

  自动连击生成函数是由事件驱动程序创建的, 函数名称是input_repeat_key. 与设备驱动程序无关.

  出错可能与设备驱动程序(RKXX_remotectl.c)没有及时发出input_event(, , 0)消息有关系.

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值