linux输入设备驱动实列

前言:

本实列是在mtk8685平台做的一个按键检测,实现长按与短按发送不同的键值给应用。
总体来说要实现一个输入设备驱动要通过如下过程:
1.分配一个input_dev设备
2.设置输入设备名称以及事件属性
3.注册设置好了的输入设备
4.监控输入事件,并上报键值

源码如下:


#include <linux/input.h>                                                                                                          
#include <linux/module.h>  
#include <linux/init.h>  
  
#include <asm/irq.h>  
#include <asm/io.h>  

#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/byteorder/generic.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/jiffies.h>
#include <linux/mtgpio.h>				//ioctl cmd 

#include <mach/mt_typedefs.h>

#include <mach/mt_gpio.h>
#include <mach/mt_gpio_core.h>


//the gpio has no interrupt function

static struct input_dev *button_dev=NULL;  
static struct task_struct *detect_task = NULL;


static int detect_key_kthread(void *data)
{
    struct sched_param param = { .sched_priority = RTPM_PRIO_CAMERA_PREVIEW };
    sched_setscheduler(current, SCHED_RR, ¶m);

	int curLevel=0,preLevel=0;
	unsigned start=0,stop=0;
    
    for( ;; ) {

		//printk(KERN_ERR"the detect key is runing!\n");

		curLevel = mt_get_gpio_in(GPIO52);
		if(!curLevel){
			
			//printk(KERN_ERR"key press !get key level =%d \n",level);
			//input_report_key(button_dev, KEY_VOLUMEUP, 1);  
			//input_sync(button_dev); 
			
			if(preLevel==1){
				
				start =jiffies_to_msecs(jiffies);
				printk(KERN_ERR"key press start =%d !\n",start);
			}

			preLevel=0;

		} 
		else{
			
				if(preLevel==0){
					
					stop =jiffies_to_msecs(jiffies);
					printk(KERN_ERR"key released stop=%d, stop -start =%d !\n",stop,stop -start);

				if((stop -start <1500)){
				
					printk(KERN_ERR"key KEY_DOWN pressed !\n");
					input_report_key(button_dev, KEY_DOWN, 1); //按键被按下
					input_sync(button_dev); //report到用户空间
					msleep(50);
					input_report_key(button_dev, KEY_DOWN, 0); 
					input_sync(button_dev); 
				}

				if((stop -start >2000)){
					printk(KERN_ERR"key KEY_ENTER pressed !\n");

					input_report_key(button_dev, KEY_ENTER, 1); 
					input_sync(button_dev); 
					msleep(50);
					input_report_key(button_dev, KEY_ENTER, 0); 
					input_sync(button_dev); 
				}
			
			}
			
			preLevel=1;
			//printk(KERN_ERR"no key press !get key level =%d \n",level);

		}
/*
		if((stop -start <1500)&&(preLevel==0)&&(curLevel==1)){
			
			printk(KERN_ERR"key KEY_DOWN pressed !\n");
			input_report_key(button_dev, KEY_DOWN, 1); 
			input_sync(button_dev); 
			msleep(100);
			input_report_key(button_dev, KEY_DOWN, 0); 
			input_sync(button_dev); 
		}

		if((stop -start >2000)&&(preLevel==0)&&(curLevel==1)){
			printk(KERN_ERR"key KEY_ENTER pressed !\n");

			input_report_key(button_dev, KEY_ENTER, 1); 
			input_sync(button_dev); 
			msleep(100);
			input_report_key(button_dev, KEY_ENTER, 0); 
			input_sync(button_dev); 
		}		
*/
		msleep(100);

        if (kthread_should_stop())
            break;
    }
	
    return 0;
}

                 
static int __init button_init(void)  {  
	
        int error;       
          
        button_dev = input_allocate_device();  	//分配一个输入设备 
        if (!button_dev) {  
			
                 printk(KERN_ERR" Not enough memory\n");  
                 error = -ENOMEM;  
                 goto err_free_dev;  
        }  

  		button_dev->name ="RecoveryKey";
      //  button_dev->evbit[0] = BIT(EV_KEY);  
       //button_dev->keybit[BITS_TO_LONGS(BTN_0)] = BIT(BTN_0);  
  		__set_bit(EV_KEY, button_dev->evbit);//注册设备支持的事件类型
	    __set_bit(KEY_DOWN, button_dev->keybit); //注册设备支持的按键
	    __set_bit(KEY_ENTER, button_dev->keybit);
		
        error = input_register_device(button_dev);  //注册输入设备
        if (error) { 
			
                 printk(KERN_ERR" Failed to register device\n");  
                 goto err_free_dev;  
        }  

		mt_set_gpio_mode(GPIO52,GPIO_MODE_00);
		mt_set_gpio_dir(GPIO52,GPIO_DIR_IN);

		detect_task = kthread_create(detect_key_kthread, NULL, "detect_key_kthread"); 		
		wake_up_process(detect_task);//创建监控gpio口的线程并启动
		
  
        return 0;  
  
 err_free_dev:  
        input_free_device(button_dev);  
        return error;  
		
 }  



static void __exit button_exit(void)  {  
	
       input_unregister_device(button_dev); 
	   kthread_stop(detect_task);
}  



module_init(button_init);  
module_exit(button_exit);  


MODULE_AUTHOR("Innoplay");
MODULE_DESCRIPTION("Recovery mode reboot");
MODULE_LICENSE("GPL");










你可能感兴趣的:(linux驱动)