一、开发环境
1、内核:Linux 2.6.22.6;
2、JZ2440
3、ubuntu 9.10
二、过程
1、分配input_dev结构体
使用input_allocate_device函数,如:
先定义一个input_dev 结构体类型变量:static struct input_dev *key_dev;
使用input_allocate_device函数分配:key_dev=input_allocate_device();
2、设置input_dev
input_dev结构体成员有:
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long evbit[NBITS(EV_MAX)]; // 表示能产生哪类事件
unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键
unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮
unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y
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)];
...
}
先设置哪类操作,再设置这类操作的哪些事件,如
/* 2.1 设置按键能产生哪类事件 */
set_bit(EV_KEY,key_dev->evbit);//EV_KEY表示按键操作
set_bit(EV_REP,key_dev->evbit);//EV_REP表示按键重复操作
/* 2.2 设置能产生这类操作的哪些事件 */
set_bit(KEY_L,key_dev->keybit);//KEY_L表示按了L键
set_bit(KEY_S,key_dev->keybit);//KEY_S表示按了S键
set_bit(KEY_ENTER,key_dev->keybit);//ENTER表示按了ENTER键
set_bit(KEY_LEFTSHIFT,key_dev->keybit);//KEY_LEFTSHIFT表示按了左边的SHIFT键
另外:
input.h里有以下类
#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
#define EV_CNT (EV_MAX+1)
3、注册
使用input_register_device(struct input_dev *dev)函数来注册,如:input_register_device(key_dev);
4、硬件相关操作
具体应用具体写了。比如本实验中使用到定时器,初始化定时器,使用按键注册中断等。
5、程序
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct key_desc{
int irq;
char *name;
unsigned int pin;
unsigned int key_val;
};
struct key_desc key_desc[4]={
{IRQ_EINT0,"s2",S3C2410_GPF0,KEY_L},
{IRQ_EINT2,"s3",S3C2410_GPF2,KEY_S},
{IRQ_EINT11,"s4",S3C2410_GPG3,KEY_ENTER},
{IRQ_EINT19,"s5",S3C2410_GPG11,KEY_LEFTSHIFT},
};
static struct input_dev *key_dev;
static struct key_desc *irq_tmp;
static struct timer_list key_timer;
static irqreturn_t key_irq(int irq, void *dev_id)
{
// printk("key_irq!irq=%d \n",irq);
irq_tmp=(struct key_desc*)dev_id;
mod_timer(&key_timer, jiffies + HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static void key_timer_func(unsigned long __data)
{
struct key_desc * keysdesc=irq_tmp;
unsigned int keyval;
//printk("key_timer_func! \n");
if (!keysdesc)
{
//printk("keysdesc\n");
return;
}
keyval=s3c2410_gpio_getpin(keysdesc->pin);
if(keyval)
{//松开
input_event(key_dev,EV_KEY,keysdesc->key_val,0);
input_sync(key_dev);
// printk("input_event0! \n");
}
else
{//按下
input_event(key_dev,EV_KEY,keysdesc->key_val,1);
input_sync(key_dev);
// printk("input_event1! \n");
}
}
static int key_init(void)
{
int i;
printk("key_init! \n");
//分配一个input_dev结构体
key_dev=input_allocate_device();
//设置
set_bit(EV_KEY,key_dev->evbit);
set_bit(EV_REP,key_dev->evbit);
set_bit(KEY_L,key_dev->keybit);
set_bit(KEY_S,key_dev->keybit);
set_bit(KEY_ENTER,key_dev->keybit);
set_bit(KEY_LEFTSHIFT,key_dev->keybit);
//注册
input_register_device(key_dev);
//硬件相关操作
//定时器初始化
init_timer(&key_timer);
key_timer.function = key_timer_func;
add_timer(&key_timer);
for(i=0;i<4;i++)
{
request_irq(key_desc[i].irq,key_irq ,IRQT_BOTHEDGE,key_desc[i].name,&key_desc[i]);
}
return 0;
}
static void key_exit(void)
{
int i;
printk("key_exit! \n");
for(i=0;i<4;i++)
{
free_irq(key_desc[i].irq,&key_desc[i]);
}
del_timer(&key_timer);
input_unregister_device(key_dev);
input_free_device(key_dev);
}
module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");
1、驱动中按键松开、按下时调用input_event()函数把keysdesc->key_val即结构体
struct key_desc key_desc[4]={
{IRQ_EINT0,"s1",S3C2410_GPF0,KEY_L},
{IRQ_EINT2,"s2",S3C2410_GPF2,KEY_S},
{IRQ_EINT11,"s3",S3C2410_GPG3,KEY_ENTER},
{IRQ_EINT19,"s4",S3C2410_GPG11,KEY_LEFTSHIFT},
};
中的KEY_L,KEY_S,KEY_ENTER,KEY_LEFTSHIFT,传递给内核。
在input_event()函数中有:
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);
实现了从input_dev到input_handle到input_handler的调用。即从硬件层到两者的连接层到驱动层的调用。我们写的程序调用input_event()函数,input_event中通过dev->h_list找到input_handle,input_handle通过其成员handler找到event。
2、韦分层框架截图
四、命令
hexdump /dev/event1 hex显示/dev/event1
exec 0
五、问题
1、加载模块后,没有event,如下
# ls -l /dev/event*
ls: /dev/event*: No such file or directory
解决:配置内核时选上Device Drivers->Input device support->Event interface && Event debugging。下载新内核到板子上。再重新make下编写的输入子系统。
加载子系统后,结果如下
六、结果