linux驱动摸索-- 输入系统(按键输入)

输入子系统框架的驱动程序步骤:

1. 分配一个input_dev结构体
2. 设置
3. 注册
4. 硬件相关的代码,比如中断注册,定时器注册等等。

下面分别介绍下相关实现代码

1.分配一个input_dev结构体

input_dev在<linux/input.h>文件定义,结构体原型如下:

struct input_dev {
	const char *name;
	const char *phys;
	const char *uniq;
	struct input_id id;

	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
.......
}

使用input_allocate_device()函数分配

	/*1.分配一个input_dev结构*/
	buttons_dev = input_allocate_device();
	if (!buttons_dev) 
	{
	    printk("input_allocate failed!\n");
		error = -ENOMEM;
	    return error;
	}

2.设置:

    /*2.设置 
	  2.1 设置按键能产生哪类事件   */
	set_bit(EV_KEY, buttons_dev->evbit);
	set_bit(EV_REP, buttons_dev->evbit);

	/* 2.2 设置能产生这类操作的哪些事件 */ 
	set_bit(KEY_A, buttons_dev->keybit);
	set_bit(KEY_B, buttons_dev->keybit);
	set_bit(KEY_L, buttons_dev->keybit);
	set_bit(KEY_S, buttons_dev->keybit);
	set_bit(KEY_ENTER, buttons_dev->keybit);
	set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);
EV_KEY & EV_REP表示按键类,可重复


3.注册

	error = input_register_device(buttons_dev);
	if (error) 
	{
		printk("input_register_device failed!\n");
		error = -ENOMEM;
	    return error;
	}

4.硬件相关注册

	/*3.硬件相关配置*/
	/*3.1初始化定时器*/
	init_timer(&buttons_timer);
    buttons_timer.function = mini2440_timer_handler;
	add_timer(&buttons_timer);
	
	/*3.2中断配置*/
	for(i=0;i<BUTTON_NUM;i++)
	{
		error = request_irq(button_irqs[i].irq, button_irq,IRQ_TYPE_EDGE_BOTH,\
			        button_irqs[i].name,&button_irqs[i]);
		if (error) 
		{
			printk("request_irq failed!\n");
			error = -ENOMEM;
		    return error;
		}
    }  

输入驱动源码如下:

#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/gpio_keys.h>
#include <linux/workqueue.h>

#include <asm/gpio.h>


static struct input_dev *buttons_dev;
static struct timer_list buttons_timer;

#define BUTTON_NUM  6

struct button_irq_desc {
    int irq;
    int pin;
    int pin_val;
    char *name;	
};
static struct button_irq_desc button_irqs [] = {
    {IRQ_EINT8 , S3C2410_GPG(0) , KEY_A ,        "KEY0"},
    {IRQ_EINT11, S3C2410_GPG(3) , KEY_B ,        "KEY1"},
    {IRQ_EINT13, S3C2410_GPG(5) , KEY_L ,        "KEY2"},
    {IRQ_EINT14, S3C2410_GPG(6) , KEY_S ,        "KEY3"},
    {IRQ_EINT15, S3C2410_GPG(7) , KEY_ENTER,     "KEY4"},
    {IRQ_EINT19, S3C2410_GPG(11), KEY_LEFTSHIFT, "KEY5"},
};

struct button_irq_desc * irq_pq;

static irqreturn_t button_irq(int irq, void *dev_id)
{
    irq_pq = (struct button_irq_desc *)dev_id;
	mod_timer(&buttons_timer,jiffies+HZ/100);
	return IRQ_RETVAL(IRQ_HANDLED);
} 


static void mini2440_timer_handler(unsigned long dat)
{
	struct button_irq_desc * pindesc = irq_pq;
		unsigned int pinval;

		if(!pindesc)
			return;
		pinval = s3c2410_gpio_getpin(pindesc->pin);
	
		if (pinval)
		{
			/* 松开 ,最后一个参数设置为0*/
			input_event(buttons_dev,EV_KEY,pindesc->pin_val,0);
			input_sync(buttons_dev);
		}
		else
		{
			/* 按下 ,最后一个参数设置为1*/
			input_event(buttons_dev,EV_KEY,pindesc->pin_val,1);
			input_sync(buttons_dev);
		}
	

}


static int mini2440_buttons_init(void)
{
	int error,i;

	/*1.分配一个input_dev结构*/
	buttons_dev = input_allocate_device();
	if (!buttons_dev) 
	{
	    printk("input_allocate failed!\n");
		error = -ENOMEM;
	    return error;
	}
    /*2.设置 
	  2.1 设置按键能产生哪类事件   */
	set_bit(EV_KEY, buttons_dev->evbit);
	set_bit(EV_REP, buttons_dev->evbit);

	/* 2.2 设置能产生这类操作的哪些事件 */ 
	set_bit(KEY_A, buttons_dev->keybit);
	set_bit(KEY_B, buttons_dev->keybit);
	set_bit(KEY_L, buttons_dev->keybit);
	set_bit(KEY_S, buttons_dev->keybit);
	set_bit(KEY_ENTER, buttons_dev->keybit);
	set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);

	error = input_register_device(buttons_dev);
	if (error) 
	{
		printk("input_register_device failed!\n");
		error = -ENOMEM;
	    return error;
	}

	/*3.硬件相关配置*/
	/*3.1初始化定时器*/
	init_timer(&buttons_timer);
    buttons_timer.function = mini2440_timer_handler;
	add_timer(&buttons_timer);
	
	/*3.2中断配置*/
	for(i=0;i<BUTTON_NUM;i++)
	{
		error = request_irq(button_irqs[i].irq, button_irq,IRQ_TYPE_EDGE_BOTH,\
			        button_irqs[i].name,&button_irqs[i]);
		if (error) 
		{
			printk("request_irq failed!\n");
			error = -ENOMEM;
		    return error;
		}
    }  
    return 0;
}


static void mini2440_buttons_exit(void)
{
	int i;
	for(i=0;i<BUTTON_NUM;i++)
	{
		free_irq(button_irqs[i].irq,&button_irqs[i]);

    }  
	del_timer(&buttons_timer);
	input_unregister_device(buttons_dev);
	input_free_device(buttons_dev);

}


/* 这两行指定驱动程序的初始化函数和卸载函数 */
module_init(mini2440_buttons_init);
module_exit(mini2440_buttons_exit);

/* 描述驱动程序的一些信息,不是必须的 */

MODULE_LICENSE("GPL");

测试相关:

linux驱动摸索-- 输入系统(按键输入)_第1张图片

注意此时的event1路径在/dev/input下,非韦老师视频中的/dev/目录下。


使用hexdump命令测试


linux驱动摸索-- 输入系统(按键输入)_第2张图片


hexdump相关代码:

struct input_event {  
    struct timeval time; //时间  
    __u16 type;          //类  
    __u16 code;          //类下事件的值  
    __s32 value;         //0-松开, 1-按下,2-重复  
};  
  
struct timeval {  
    __kernel_time_t     tv_sec;         //秒   
    __kernel_suseconds_t    tv_usec;    //微秒  
};


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