evdev输入事件驱动分析

evdev[输入事件驱动],为输入子系统提供了一个默认的事件处理方法。其接收来自底层驱动的大多数事件,并使用相应的逻辑对其进行处理。

evdev从底层接收事件信息,将其反映到sys文件系统中,用户程序通过对sys文件系统的操作,就能够达到处理事件的能力。

1. evdev的初始化
evdev以模块的方式被组织在内核中,也具有初始化函数和卸载函数。evdev的初始化主要完成一些注册工作,使内核认识evdev的存在。
evdev模块定义在/drivers/input/evdev.c文件中,该模块的初始化函数是evdev_init()。在初始化函数中注册了一个evdev_handler结构体,用来对一些通用的抽象事件进行统一处理,函数的代码如下

static int __init evdev_init(void)
{
    /*将evdev_handler注册到系统中*/
    return input_register_handler(&evdev_handler);
}
static void __exit evdev_exit(void)
{
    input_unregister_handler(&evdev_handler);
}
module_init(evdev_init);
module_exit(evdev_exit);

第03行,调用input_register_handler()函数注册了evdev_handler事件处理器,input_register_handler()函数在前面已经详细解释过,这里将对其参数evdev_handler进行分析,其定义如下:

static struct input_handler evdev_handler = {
    .event      = evdev_event,
    .connect    = evdev_connect,
    .disconnect = evdev_disconnect,
    .fops       = &evdev_fops,
    .minor      = EVDEV_MINOR_BASE,
    .name       = "evdev",
    .id_table   = evdev_ids,
    };

第06行,定义了minor为EVDEV_MINOR_BASE(64)。因为一个handler可以处理32个设备,所以evdev_handler所能处理的设备文件范围为(13,64)~(13,64+32),其中13是所有输入设备的主设备号。

第08行,定义了id_table结构。回忆前面几节的内容,由input_attach_handler()函数可知,input_dev与handler匹配成功的关键,在于handler中的blacklist和id_talbe.。Evdev_handler只定义了id_table,其定义如下:

static const struct input_device_id evdev_ids[] = { 
    {iver_info = 1 },   /* Matches all devices */      
        { },            /* Terminating zero entry */      
};

evdev_ids没有定义flags,也没有定义匹配属性值。这个evdev_ids的意思就是:evdev_handler可以匹配所有input_dev设备,也就是所有的input_dev发出的事件,都可以由evdev_handler来处理。
先来看两个结构体struct evdev, struct evdev_client:

struct evdev {
    int open;
    int minor;   //在evdev_table中的索引
    struct input_handle handle;  //连接input_dev和input_handler
    wait_queue_head_t wait;
    struct evdev_client __rcu *grab;   // 用户每调用一次open,将创建一个evdev_client
    struct list_head client_list;
    spinlock_t client_lock; /* protects client_list */
    struct mutex mutex;
    struct device dev;
    bool exist;
};

struct evdev_client {
    unsigned int head;
    unsigned int tail;
    unsigned int packet_head; /* [future] position of the first element of next packet */
    spinlock_t buffer_lock; /* protects access to buffer, head and tail */
    struct wake_lock wake_lock;
    char name[28];
    struct fasync_struct *fasync;
    struct evdev *evdev;
    struct list_head node;
    unsigned int bufsize;
    struct input_event buffer[];  //存放所有这个设备产生的input_event,由evdev_event写入
};

另外,从前面的分析可以知道,匹配成功之后会调用handler->connect()函数,对该函数的介绍如下:

static int evdev_connect(str
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值