输入子系统学习笔记之按键实例编程

输入子系统由3部分组成:input core, input handler ,input dev。其中我们要写代码去实现的是input dev,因为输入子系统实现了输入设备大部分相同的功能,因此input dev写少量与硬件相关的代码和调用input core提供的接口。

1 input dev的编写要点

1.1 分配、注册、注销input设备

/* 分配/释放一个输入设备*/
struct input_dev *input_allocate_device(void)
struct input_dev *input_free_device(void)
/* 注册/注销一个输入设备*/
int input_register_device(struct input_dev *dev)
void input_unregister_device(struct input_dev *dev)

1.2 设置input 设备支持的事件类型、事件码、事件值的范围、input_id等信息

include/linux/input.h中定义了支持的类型(下面列出的是2.6.22内核的情况#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f

一个设备可以支持一个或多个事件类型。每个事件类型下面还需要设置具体的触发事件码。比如:EV_KEY事件,需要定义其支持哪些按键事件码

1.3 在发生输入事件时,向子系统报告事件

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

下面根据这个3个步骤写一个基于输入子系统的按键设备驱动程序:

#include <linux/module.h>
#include <linux/version.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/irq.h>
#include <linux/gpio_keys.h>
#include <asm/gpio.h>

struct pin_desc{
    int irq;
	char *name;
	unsigned int pin;
	unsigned int key_val;
};

struct pin_desc pins_desc[4] = {
	{IRQ_EINT1, "k1", S3C2410_GPF1, KEY_L},
	{IRQ_EINT4, "k2", S3C2410_GPF4, KEY_S},
	{IRQ_EINT2, "k3", S3C2410_GPF2, KEY_ENTER},
	{IRQ_EINT0, "k4", S3C2410_GPF0, KEY_LEFTSHIFT},
};
static struct input_dev *buttons_dev;
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
	/* 10ms后启动定时器 */
	irq_pd = (struct pin_desc *)dev_id;
	mod_timer(&buttons_timer, jiffies+HZ/100);
	return IRQ_RETVAL(IRQ_HANDLED);
}
static void buttons_timer_function(unsigned long data)
{
    struct pin_desc * pindesc = irq_pd;
	unsigned int pinval;

	if (!pindesc)
		return;
	/* 有按键按下,获取按键值*/
	pinval = s3c2410_gpio_getpin(pindesc->pin);

	if (pinval)
	{
		/* 松开  上报事件给子系统*/
		input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);
        /* 发出一个同步时间,表明消息报告完毕*/  
		input_sync(buttons_dev);
	}
	else
	{
		/* 按下 上报事件给子系统*/
		input_event(buttons_dev, EV_KEY, pindesc->key_val, 1);
        /* 发出一个同步时间,表明消息报告完毕*/  
		input_sync(buttons_dev);
	}
}
static int buttons_init(void)
{ 
	int i;
    /* 1. 分配一个input_dev 结构体*/
	buttons_dev = input_allocate_device();
    /* 2. 设置事件类型*/
	/* 2.1 能够产生哪类事件*/
	set_bit(EV_KEY, buttons_dev->evbit);
    /* 2.2 能产生这类操作里的哪些事件*/
	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);
	
	/* 3. 注册输入设备*/
	input_register_device(buttons_dev);
    /* 4. 硬件相关的操作*/
	init_timer(&buttons_timer);// 初始化定时器
	buttons_timer.function = buttons_timer_function; // 关联定时器中断函数
	add_timer(&buttons_timer);
	/*  注册中断*/
	for (i = 0; i < 4; i++){
	    request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
	}
	return 0;
}
static void buttons_exit(void)
{
	int i;
	for (i = 0; i < 4; i++){
	    free_irq(pins_desc[i].irq, &pins_desc[i]);
	}
	/* 释放申请的资源*/
	del_timer(&buttons_timer);
	input_unregister_device(buttons_dev);
	input_free_device(buttons_dev);
}
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");

驱动测试:
1.
hexdump /dev/event1  (open(/dev/event1), read(), )
                   秒            微秒      类   code    value
0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000
0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000
0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
0000030 0bb2 0000 581f 000e 0000 0000 0000 0000

2. 如果没有启动QT:
cat /dev/tty1
按:s2,s3,s4
就可以得到ls

或者:
exec 0</dev/tty1  // 将标准输入改为tty1 输入
然后可以使用按键来输入

3. 如果已经启动了QT:
可以点开记事本
然后按:s2,s3,s4

posted @ 2013-03-22 17:33  lsx_007  阅读(417)  评论(0编辑  收藏  举报