【转载】LINUX输入设备驱动

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);


   

你可能感兴趣的:(ARM-LINUX驱动学习)