LINUX的输入驱动由下面几个部分组成:
1. 系统内核:实现了输入法设备的管理,事件的获取接口,并汇报到应用程序。
这部分代码提供了统一的接口供驱动开发人员创建输入设备,注册输入设备,回报输入事件到系统。
主要的实现文件是INPUT.C, evdev.c, mousedev.c
2. 不同硬件设备上的键盘、按键、触摸板驱动。
这部分主要是初始化按键的硬件实现,注册中断服务程序。并调用系统内核的接口来创建输入设备,
注册设备类型,并将设备注册到输入系统管理内核中。
中断服务程序主要检测输入(按键、触摸屏、鼠标),并通过系统提供的接口将事件回报到系统中。
3. 输入设备的类型
LINUx上的输入设备分为:同步输入设备SYNC,相对输入设备REL(鼠标),绝对输入设备ABS(触摸屏),
按键输入设备KEY(键盘)
不同的输入设备都采用统一的接口创建、注册设备、汇报输入事件。
4. 输入设备创建过程
a. 创建输入设备
struct input_dev *qw_key_dev;
qw_key_dev = input_allocate_device();
这一步骤通常包括初始化输入设备的硬件寄存器,比如配置按键的pin复用等等。
b. 设置输入设备类型(这里是EV_KEY)
set_bit(EV_KEY, qw_key_dev->evbit);
for (i=0; i<QW_KEY_COUNT; i++)
{
set_bit(qw_key_codes[i], qw_key_dev->keybit);
}
c. 注册按键处理中断
retval = request_irq(irq, mxc_kpp_interrupt, 0, MOD_NAME, MOD_NAME);
mxc_kpp_interrupt:中断处理函数检测按键情况,并调用input_event汇报事件到系统
d. 注册输入设备
input_register_device(qw_key_dev);
5。知道了一个输入设备的创建过程,我们就可以在没有事件硬件输入设备的情况下,在系统模拟一个输入设备。
这通常用在远程输入,如遥控输入。
步骤和前面相同。只是因为没有真实中断处理程序应该在收到远程数据包时产生中断,在中断中将数据汇报
给系统。附示例源码:
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("drawer");
static int howmany = 1;
module_param(howmany, int, S_IRUGO);
struct input_dev *qw_key_dev;
#define QW_KEY_DEBUG 1
#define QW_MOUSE_DEBUG 0
static int qw_key_codes[] = {
KEY_ESC,
KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
};
static int QW_KEY_COUNT = 37;
void key_timeout(unsigned long unused/*UNUSED*/)
{
#if (QW_KEY_DEBUG)
int x;
for (x=0;x<4;x++) {
// letter a or A */
input_report_key(qw_key_dev, KEY_A, 1);
input_sync(qw_key_dev);
input_report_key(qw_key_dev, KEY_A, 0);
input_sync(qw_key_dev);
}
for (x=0;x<4;x++) {
/* letter b or B */
input_report_key(qw_key_dev, KEY_B, 1);
input_sync(qw_key_dev);
input_report_key(qw_key_dev, KEY_B, 0);
input_sync(qw_key_dev);
}
/* set timer for (howmany) seconds */
mod_timer(&(qw_key_dev->timer),jiffies+howmany*HZ);
#endif
}
static int __init qw_remote_init(void)
{
int i;
howmany = howmany > 4 ? howmany : 4;
/////////////////////////////////////////////////////////////////////////
// intializing qw_key_dev
/* extra safe initialization */
//memset(&qw_key_dev, 0, sizeof(struct input_dev));
qw_key_dev = input_allocate_device();
/* set up descriptive labels */
qw_key_dev->name = "toy_remoteCtrl_device";
/* phys is unique on a running system */
qw_key_dev->phys = "/dev/input/toy_keyinput";
qw_key_dev->id.bustype = BUS_HOST;
qw_key_dev->id.vendor = 0x0001;
qw_key_dev->id.product = 0x0001;
qw_key_dev->id.version = 0x0100;
/* this device has 37 keys (A and B) */
set_bit(EV_KEY, qw_key_dev->evbit);
for (i=0; i<QW_KEY_COUNT; i++)
{
set_bit(qw_key_codes[i], qw_key_dev->keybit);
}
/* and finally register with the input core */
input_register_device(qw_key_dev);
/* set up a repeating timer */
init_timer(&(qw_key_dev->timer));
qw_key_dev->timer.function = key_timeout;
qw_key_dev->timer.expires = jiffies+HZ;
add_timer(&(qw_key_dev->timer));
// initializing qw_key_dev end
/////////////////////////////////////////////////////////////////////////
return 0;
}
static void __exit qw_remote_exit(void)
{
del_timer_sync(&(qw_key_dev->timer));
input_unregister_device(qw_key_dev);
input_free_device(qw_key_dev);
}
module_init(qw_remote_init);
module_exit(qw_remote_exit);