input 子系统浅析

Input子系统内核

重要结构体解析:

struct input_dev {

         const char *name;

         const char *phys;

         const char *uniq;

         struct input_id id;

 

         unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

 

         unsigned long evbit[BITS_TO_LONGS(EV_CNT)];

         unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];

         unsigned long relbit[BITS_TO_LONGS(REL_CNT)];

         unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];

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

         unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

 

         unsigned int hint_events_per_packet;

//这个函数接口是用于计算每个数据包的大小。好准备好大小合适的数据包buffer.

 

         unsigned int keycodemax;

         unsigned int keycodesize;

         void *keycode;

 

         int (*setkeycode)(struct input_dev *dev,

                              const struct input_keymap_entry *ke,

                              unsigned int *old_keycode);

         int (*getkeycode)(struct input_dev *dev,

                              struct input_keymap_entry *ke);

 

         struct ff_device *ff;

 

         unsigned int repeat_key;

         struct timer_list timer;

 

         int rep[REP_CNT];

 

         struct input_mt_slot *mt;

         int mtsize;

         int slot;

         int trkid;

 

         struct input_absinfo *absinfo;

 

         unsigned long key[BITS_TO_LONGS(KEY_CNT)];

         unsigned long led[BITS_TO_LONGS(LED_CNT)];

         unsigned long snd[BITS_TO_LONGS(SND_CNT)];

         unsigned long sw[BITS_TO_LONGS(SW_CNT)];

 

         int (*open)(struct input_dev *dev);

         void (*close)(struct input_dev *dev);

         int (*flush)(struct input_dev *dev, struct file *file);

         int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

 

         struct input_handle __rcu *grab;

 

         spinlock_t event_lock;

         struct mutex mutex;

 

         unsigned int users;

         bool going_away;

 

         bool sync;

 

         struct device dev;

 

         struct list_head        h_list;

         struct list_head        node;

};

 

 

struct input_handler {

    //存放的是此handler的私有变量

         void *private;

//进行时间传递的函数接口,此时中断disable,获取dev->event_lock spinlock锁,因

此此时不进入睡眠

         void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

    //对某些时间进行特殊处理

         bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

    //devicehandler的匹配函数

         bool (*match)(struct input_handler *handler, struct input_dev *dev);

    //devicehandler匹配成功后的connect函数,在此产生对应的次设备号和注册handle

         int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

//取消devicehandler的链接

         void (*disconnect)(struct input_handle *handle);

    //通过给定的handle来启用对用的handler

         void (*start)(struct input_handle *handle);

 

         const struct file_operations *fops;//handler的文件操作接口

         int minor;//handler的次设备号基地址

    //handler的名字,通常显示在/proc/bus/input/handlers路径下

         const char *name;

//指向此handler能够处理的属性

/*通常属性包含以下几种:

struct input_device_id {

 

        kernel_ulong_t flags;

 

        __u16 bustype;

        __u16 vendor;

        __u16 product;

        __u16 version;

 

        kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];

 

        kernel_ulong_t driver_info;

};

*/

         const struct input_device_id *id_table;

    //这是handler自己的handle链表管理

    struct list_head        h_list;

    //代表此handler挂在在input_handler_list链表上面

         struct list_head        node;

};

 

struct input_handle {

    //handle的私有数据

         void *private;

    //标识此handle是否被打开

         int open;

    //handle的名字

         const char *name;

    //handle相关连的device

         struct input_dev *dev;

    //handle相关连的handler

         struct input_handler *handler;

         //将此handle挂载到device对应的管理handle的链表中

struct list_head        d_node;

//将此handle挂载到handler对应的管理handle的链表中

         struct list_head        h_node;

};

Input子系统解析

属性文件和设备文件的创建。

相关的属性文件

首先类文件夹创建:

路劲:/sys/class/input/里面有所有的设备文件和所有的handle文件。

设备文件:就是调用input_register_device()函数注册的设备

这样的文件一般命名方式为:"input%ld"

最终调用device_add函数注册,并生成一些相关的属性文件

Handle文件:就是device与相对应的handler相匹配后,调用handlerconnect函数,创建的文件

这样的文件一般命名方式为:以eventhandler为例:"event%d"对应的handler名称加ID

最终调用device_add函数注册,并生成一些相关的属性文件

NOTE:在创建一些对应的属性文件的同时,也会创建一系列的软link和硬link

 

调用input_proc_init()函数在proc文件系统中生成一些必备的文件

路劲:/proc/bus/input/

下面有deviceshandlers两个文件

Devices文件记录所有的input设备

Handlers记录input中所有的handler

 

 

Input子系统与hander:

设备文件:分主设备号和此设备号:

路劲:

/sys/dev/char  主设备号为13

次设备号对应各个handerl的设备

一共有256个次设备号,设计上每个handler占用32个次设备号。故最多有8handler,

1.EventHub.h中的

// Epoll FD list size hint.

static const int EPOLL_SIZE_HINT = 8;

也可以推得此信息。

2.input_register_handler()函数中input_table[handler->minor >> 5] = handler;

也可以推得此信息

3.static struct input_handler *input_table[8];数组也可以推得此信息

常见的几种handler:

Joydev

#define JOYDEV_MINOR_BASE       0

#define JOYDEV_MINORS                 16

Evdev

#define EVDEV_MINOR_BASE         64

#define EVDEV_MINORS                   32

Mousedev

#define MOUSEDEV_MINOR_BASE         32

#define MOUSEDEV_MINORS                   32

一般内核中形形色色的handler有很多,但是上层看到到一般最多只有八种,那么那些特征的handler上层可见呢?

Input子系统管理上层可见的handler是通过一个8 handler容量的数组

static struct input_handler *input_table[8];此数组是全局变量

此时我们看看hander的注册函数,什么条件的handler才会存进此数组中。

int input_register_handler(struct input_handler *handler)

{

if (handler->fops != NULL) {

                   if (input_table[handler->minor >> 5]) {

                            retval = -EBUSY;

                            goto out;

                   }

                   input_table[handler->minor >> 5] = handler;

         }

}

由此可知:只有满足带有文件操作接口的hander才会存进此全局数组中。

其他情况的handler只在内核里面进行链表似的管理。

Handerdevices:

在注册设备的时候会从链表中与handler进行匹配,匹配成功后会调用对应handlerconnect函数。在此函数中产生对应段的次设备号。和注册一个关联deviceshandlerhandle.

 

通常情况下:每一个handler也有一个全局的数组用来存放此handler关联成功的devices

通常都是调用xxxdev_install_chrdev()函数

Evdevstatic struct evdev *evdev_table[EVDEV_MINORS];

Mousedevstatic struct mousedev *mousedev_table[MOUSEDEV_MINORS];

Joydevstatic struct joydev *joydev_table[JOYDEV_MINORS];

 

Handler特性:

每一个handler都对应着多个client。也就是说上层可以有多个实例同时关注此handler,此handler对应的设备有时间产生的时候,会通报相关的所有client.

Client通常都是通过链表来管理的,机制是RCU

Client都是在对应handleropen函数中调用对应的XXXdev_attach_client函数进行注册。

 

Handler结构体通常需要填充的属性:

eventhandler为例:

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,

};

 

 

几种术语:

Device:input设备

Handler:处理设备时间的handler

Handle:关联devicehandler

下面从几个方面来了解input子系统。

注册流程

注销流程

消息上报流程

Handlerdevice匹配流程

生成handle流程

Device

device注册流程

/*

**1.device必须是函数input_allocate_device()申请的结构体

**2.devicecapabilities必须在注册之前就设置好

**3.如果注册device失败必须调用函数input_free_device()释放之前申请的device

**  的空间

**4.如果注册成功,需要注销的时候必须调用函数input_unregister_device()

**5.

**

**

*/

int input_register_device(struct input_dev *dev)

{

//首先是填充input_dev结构体的相关属性

//所有的device都得支持EV_SYN事件

__set_bit(EV_SYN, dev->evbit);

//所有的device都不支持KEY_RESERVED事件

__clear_bit(KEY_RESERVED, dev->keybit);

//将不支持的事件占有位都清零

input_cleanse_bitmasks(dev);

//计算每个数据包的事件数目

if (!dev->hint_events_per_packet)

                   dev->hint_events_per_packet =

                                     input_estimate_events_per_packet(dev);

//此处是处理重复按键的

//如果在驱动中设置了延迟事件和周期,在inputcore中就不进行处理了,由驱动//自己控制

init_timer(&dev->timer);

         if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {

                   dev->timer.data = (long) dev;

                   dev->timer.function = input_repeat_key;//处理重复按键的函数,上报事件

                   dev->rep[REP_DELAY] = 250;

                   dev->rep[REP_PERIOD] = 33;

}

//填充设置和获取keycode的函数

if (!dev->getkeycode)

                   dev->getkeycode = input_default_getkeycode;

 

         if (!dev->setkeycode)

                   dev->setkeycode = input_default_setkeycode;

 

//该函数对原子类型的变量V原子的增加1并且返回指向V的指针

//deviceinput+number的方式进行命名

dev_set_name(&dev->dev, "input%ld",

                        (unsigned long)atomic_inc_return(&input_no) - 1);

//将此device添加进经典模型中,在sys文件系统下面生成对应的文件

error = device_add(&dev->dev);

         if (error)

                   return error;

//将注册成功后产生的路劲获取打印出来

path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);

         pr_info("%s as %s\n",

                   dev->name ? dev->name : "Unspecified device",

                   path ? path : "N/A");

         kfree(path);

//加锁互斥变量,但是可被中断打断(这是我个人的了解,不一定正确)

error = mutex_lock_interruptible(&input_mutex);

         if (error) {

                   device_del(&dev->dev);

                   return error;

         }

//将此device添加进input-core全局的dev链表中

list_add_tail(&dev->node, &input_dev_list);

//遍历handler链表,调用input_attach_handler函数与handler进行匹配

list_for_each_entry(handler, &input_handler_list, node)

                   input_attach_handler(dev, handler);

 

//

//这个函数就是唤醒poll的等待队列,poll函数会返回return POLLIN | //POLLRDNORM;

//标识此设备有消息可读,这样就可以对此device进行读操作获取相关的信息了。

//此处就是一个poll模型的应用不多说,需要详细了解的关注下此模型

input_wakeup_procfs_readers();

//去锁互斥变量

mutex_unlock(&input_mutex);

 

Device注销流程

/*

**注销掉先前注册的设备

**

**

**

**

*/

void input_unregister_device(struct input_dev *dev)

{

//注销前的准备工作,详细信息见下面函数单独分析

input_disconnect_device(dev);

//互斥变量上锁

mutex_lock(&input_mutex);

//在注册的时候,会和handler匹配,如果匹配成功就会调用handlerconnect

//函数,在这里与前面相对应的是,注销的时候就会调用相应的disconnect//

list_for_each_entry_safe(handle, next, &dev->h_list, d_node)

handle->handler->disconnect(handle);

         WARN_ON(!list_empty(&dev->h_list));

//将设备的timer删除

del_timer_sync(&dev->timer);

//将设备从全局设备链表中删除

         list_del_init(&dev->node);

//此函数的功能已经在注册函数中描述清楚,这里就不再重复了

input_wakeup_procfs_readers();

//互斥变量解锁

mutex_unlock(&input_mutex);

            //之前的注册的时候有调用device_add()函数,这里就调用对应的device注销//函数,具体细节不描述,如果有兴趣,可详细研究设备驱动模型

         device_unregister(&dev->dev);

}

 

static void input_disconnect_device(struct input_dev *dev)

{

//添加此标识,标识设备已经离开

mutex_lock(&dev->mutex);

dev->going_away = true;

         mutex_unlock(&dev->mutex);

 

//加锁

spin_lock_irq(&dev->event_lock);

//在将设备移除之前模拟一个keyup消息,防止出现某些那件一直处于按下状//态,

 input_dev_release_keys(dev);

//遍历与device匹配成功的handler链表,将生成的handleopen属性置为0

//标识此handle没有被引用,引用计数为0device产生的事件不再传送到//handler中了,进行处理之后或许设备还有有事件产生,但是此时的事件已经//不传递到//handler中去了

list_for_each_entry(handle, &dev->h_list, d_node)

handle->open = 0;

//解锁

spin_unlock_irq(&dev->event_lock);

}

 二.Handler

     1.handler注册流程

     /*

     **1.注册一个新的handler,且与所有的devices进行适配

     */

     int input_register_handler(struct input_handler *handler)

     {

     //加锁互斥变量,但是可被中断打断(这是我个人的了解,不一定正确)

     retval = mutex_lock_interruptible(&input_mutex);

             if (retval)

                   return retval;

     //初始化handle链表,与此handler相关联的handle,都挂载在此链表上面

     INIT_LIST_HEAD(&handler->h_list);

     //前面已经提到过,handler分为带文件操作接口和不带文件操作接口,而且带文

//件操作接口的handler,最多只能有8个。

//input_table数组是全局的,大小为8,存放贷文件接口的handler.索引为次设备号//偏移5,这里与每个带文件操作接口handler,最多关联32个设备相对应,对应//32个次设备号

     if (handler->fops != NULL) {

                   if (input_table[handler->minor >> 5]) {

                            retval = -EBUSY;

                            goto out;

                   }

                   input_table[handler->minor >> 5] = handler;

         }

   //将此handler挂载进全局的handler管理链表中去

   list_add_tail(&handler->node, &input_handler_list);

   //遍历device全局链表,调用input_attach_handler进行匹配

   list_for_each_entry(dev, &input_dev_list, node)

                   input_attach_handler(dev, handler);

   //此函数在之前已经详细描述过,这里面不重复

         input_wakeup_procfs_readers();

     }

     2.handler注销流程

       /*

       **1.将之前注册的handler进行撤销

       */

void input_unregister_handler(struct input_handler *handler)

       {

        //互斥变量加锁

        mutex_lock(&input_mutex);

        //在注册的时候会和所有的device进行适配,如果适配成功就会调用对应//handlerconnect函数,这里面要调用对应的disconnect函数

        list_for_each_entry_safe(handle, next, &handler->h_list, h_node)

                      handler->disconnect(handle);

                WARN_ON(!list_empty(&handler->h_list));

        //将此handlerhandler的全局链表中删除

list_del_init(&handler->node);    

//前面注册的时候会填充input_table对应索引,此处应该将对应索引值赋为空

if (handler->fops != NULL)

                   input_table[handler->minor >> 5] = NULL;

//此函数不多解释,前面已经进行过详细的描述

input_wakeup_procfs_readers();

//互斥变量解锁

mutex_unlock(&input_mutex);

}

 三.Handle

    综述:handle的注册于注销都是在对应handlerconnectdisconnect函数中进行

         

 1.handle注册流程

     /*

     **注册一个handle进入对应handlerdevice链表中,用于关联二者

     **所以只要handleopen属性不为0,对应设备产生的事件就会通过它被传送到**上层去,此函数被handlerconnect函数调用

     */

      int input_register_handle(struct input_handle *handle)

      {

       //首先提取出与此handle相关联的handlerdevice

       struct input_handler *handler = handle->handler;

               struct input_dev *dev = handle->dev;

      //给互斥变量上锁(可被中断打断),主要为了防止input_release_device().在此期间//被调用

      error = mutex_lock_interruptible(&dev->mutex);

      //如果此handler带有filter功能则将handle加到设备链表头,否则加到设备链表//

      if (handler->filter)

                   list_add_rcu(&handle->d_node, &dev->h_list);

         else

                   list_add_tail_rcu(&handle->d_node, &dev->h_list);

      //互斥变量解锁

      mutex_unlock(&dev->mutex);

      //由于此函数是被connect函数调用,与disconnect函数式互斥的,不可能同时调//input_unregister_handle()函数,所以不需要独立的互斥变量

      //handle添加到handler链表的尾

      list_add_tail_rcu(&handle->h_node, &handler->h_list);

      //通过给定的handle,开始handler,(此处目前我也不怎么理解)

      //此函数通常被调用刚好在connect函数之后,也可以在一个进程grabbed一个设备然后释放他的时候调用例如函数:__input_release_device

      if (handler->start)

                   handler->start(handle);

      }

 2.handle注销流程

  /*

 **注销函数主要就是将handle的节点从handlerdevice的链表中删除

 */

void input_unregister_handle(struct input_handle *handle)

{

//handlehandler的链表中删除

list_del_rcu(&handle->h_node);

         /*

          * Take dev->mutex to prevent race with input_release_device().

          */

         mutex_lock(&dev->mutex);

 //handledevice的链表中删除

         list_del_rcu(&handle->d_node);

         mutex_unlock(&dev->mutex);

 //同步RCURCU小解:

       //RCU机制是Linux2.6之后提供的一种数据一致性访问的机制,从RCU//(read-copy-update)的名称上看,我们就能对他的实现机制有一个大//概的了解,在修改数据的时候,首先需要读取数据,然后生成一个副本,//对副本进行修改,修改完成之后再将老数据update成新的数据,此所

//谓RCU

         synchronize_rcu();

}

Handlerconnectdisconnect函数

这里面evdev这个handler进行举例分析

五:消息上报流程

首先从驱动中的上报消息函数开始开流程

input_report_key()àinput_event()àinput_handle_event()àdev->event()

【设备要监听消息】

                                                  input_pass_event()

                                                 handler监听消息】

下面主要看handler的消息流程:

input_pass_event()àhandler->event()会调用相应handlerevent函数

下面来显示看看这些函数流程

/*

**根据支持的事件传递事件类型,调用input-core的事件传递函数

*/

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)

{

    //事件类型是EV_KEY,,其他的类似

         input_event(dev, EV_KEY, code, !!value);

}

 

/*

**首先判断此device是否支持此事件,然后调用对应的handleevent传递函数

*/

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

{

         unsigned long flags;

         if (is_event_supported(type, dev->evbit, EV_MAX)) {

        //调用函数将事件锁锁住

                   spin_lock_irqsave(&dev->event_lock, flags);

            //此处之前我也不明白啥意思,从网上查阅了下,有人说此处没啥用处,就是//为系统提供一个随机的熵值,因为按键消息是一个随机的事件

                   add_input_randomness(type, code, value);

        //调用事件传递函数,继续input事件的传递

                   input_handle_event(dev, type, code, value);

        //解锁事件锁

                   spin_unlock_irqrestore(&dev->event_lock, flags);

         }

}

 

 

Note:

//每一个数据包的结束都会调用此函数进行同步标识

input_mt_sync()

//多点事件的结束时调用此函数进行标识同步(一整个事件中会有多个数据包)

input_sync()

/*

**1.根据事件类型进行判断事件disposition类型

**  a. #define INPUT_IGNORE_EVENT 0

**  b.#define INPUT_PASS_TO_HANDLERS  1

**  c.#define INPUT_PASS_TO_DEVICE         2

**d.#define INPUT_PASS_TO_ALL  (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)

**2.根据事件处置的三种类型分别:

**  a.忽略事件

**  b.将事件传递到deviceevent的处置函数中

**  c.将事件传递到handlerevent的处置函数中

*/

static void input_handle_event(struct input_dev *dev,

                                   unsigned int type, unsigned int code, int value)

{

    //标识以何种方式处理事件,默认处理方法是忽略

         int disposition = INPUT_IGNORE_EVENT;

         switch (type) {

         case EV_SYN:

                   switch (code) {

                   case SYN_CONFIG:

            //标识此种事件处置等级是TOALL

                            disposition = INPUT_PASS_TO_ALL;

                            break;

                   case SYN_REPORT:

                            if (!dev->sync) {

                //此处将设备的事件同步信号设置成true,完整事件的同步

                                     dev->sync = true;

                //标识此事件的处置等级是只传递给handlers

                                     disposition = INPUT_PASS_TO_HANDLERS;

                            }

                            break;

                   case SYN_MT_REPORT:

            //此处将设备的事件同步信号设置成true,数据包的同步

                            dev->sync = false;

            //标识此事件的处置等级是只传递给handlers

                            disposition = INPUT_PASS_TO_HANDLERS;

                            break;

                   }

                   break;

         case EV_KEY:

        //判断此设备是否支持此事件

                   if (is_event_supported(code, dev->keybit, KEY_MAX) &&

                       !!test_bit(code, dev->key) != value) {//测试按键状态是否改变

                            if (value != 2) {

                                     __change_bit(code, dev->key);//改变按键的状态

                                     if (value)

                //如果是重复按键,则自动调用重复按键的函数

                                               input_start_autorepeat(dev, code);

                                     else

                //停止自动报重复按键消息

                                               input_stop_autorepeat(dev);

                            }

                            disposition = INPUT_PASS_TO_HANDLERS;

                   }

                   break;

         case EV_SW:

        //与上面类似

                   if (is_event_supported(code, dev->swbit, SW_MAX) &&

                       !!test_bit(code, dev->sw) != value) {

                            __change_bit(code, dev->sw);

                            disposition = INPUT_PASS_TO_HANDLERS;

                   }

                   break;

         case EV_ABS:

                   if (is_event_supported(code, dev->absbit, ABS_MAX))

        //其实就是根据此种事件的特性,判断处理方式

                            disposition = input_handle_abs_event(dev, code, &value);

                   break;

         case EV_REL:

                   if (is_event_supported(code, dev->relbit, REL_MAX) && value)

                            disposition = INPUT_PASS_TO_HANDLERS;

                   break;

         case EV_MSC:

                   if (is_event_supported(code, dev->mscbit, MSC_MAX))

                            disposition = INPUT_PASS_TO_ALL;

                   break;

         case EV_LED:

                   if (is_event_supported(code, dev->ledbit, LED_MAX) &&

                       !!test_bit(code, dev->led) != value) {

                            __change_bit(code, dev->led);

                            disposition = INPUT_PASS_TO_ALL;

                   }

                   break;

         case EV_SND:

                   if (is_event_supported(code, dev->sndbit, SND_MAX)) {

                            if (!!test_bit(code, dev->snd) != !!value)

                                     __change_bit(code, dev->snd);

                            disposition = INPUT_PASS_TO_ALL;

                   }

                   break;

         case EV_REP:

                   if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {

                            dev->rep[code] = value;

                            disposition = INPUT_PASS_TO_ALL;

                   }

                   break;

         case EV_FF:

                   if (value >= 0)

                            disposition = INPUT_PASS_TO_ALL;

                   break;

         case EV_PWR:

                   disposition = INPUT_PASS_TO_ALL;

                   break;

         }

    //如果此事件处理类型为忽略,且不是EV_SYN同步事件,将同步信号设置成false

         if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)

                   dev->sync = false;

    //如果此device支持事件处理,而且事件处理方式为指向设备的

         if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)

                   dev->event(dev, type, code, value);

    //这是主流流程,事件处理方式是传向handler,则进入handler的事件流处理

         if (disposition & INPUT_PASS_TO_HANDLERS)

                   input_pass_event(dev, type, code, value);

}

 

下面以EVDEVhandler为例子来讲解handler的消息传递流程

在注册此handler的时候,已经初始化了event事件处理函数

函数为evdev_event

/*

**

*/

static void evdev_event(struct input_handle *handle,

                            unsigned int type, unsigned int code, int value)

{

         struct evdev *evdev = handle->private;

         struct evdev_client *client;

         struct input_event event;

         struct timespec ts;

   

   //首先获取事件的时间戳

         ktime_get_ts(&ts);

         //填充事件的属性参数

event.time.tv_sec = ts.tv_sec;

         event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;

         event.type = type;//事件类型

         event.code = code;//事件码

         event.value = value;//事件码

 

         rcu_read_lock();//获取读RCU

    //首先判断此handler是否被某个event_clientgrab

         client = rcu_dereference(evdev->grab);

         if (client)

                   evdev_pass_event(client, &event);//如果有,则将此事件只传给此client

         else

        //否则将此事件传递给所有相关联的client

                   list_for_each_entry_rcu(client, &evdev->client_list, node)

                            evdev_pass_event(client, &event);

 

         rcu_read_unlock();//释放读RCU

   

    //如果是同步事件,则唤醒等待队列

         if (type == EV_SYN && code == SYN_REPORT)

                   wake_up_interruptible(&evdev->wait);

}

 

下面进入函数:

/*

**

*/

static void evdev_pass_event(struct evdev_client *client,

                                 struct input_event *event)

{

         /* Interrupts are disabled, just acquire the lock. */

   //首先获取共享资源buffer的操作锁

         spin_lock(&client->buffer_lock);

    //将此事件,添加进buffer

         client->buffer[client->head++] = *event;

         client->head &= client->bufsize - 1;

 

         if (unlikely(client->head == client->tail)) {

                   /*

                    * This effectively "drops" all unconsumed events, leaving

                    * EV_SYN/SYN_DROPPED plus the newest event in the queue.

                    */

                   client->tail = (client->head - 2) & (client->bufsize - 1);

 

                   client->buffer[client->tail].time = event->time;

                   client->buffer[client->tail].type = EV_SYN;

                   client->buffer[client->tail].code = SYN_DROPPED;

                   client->buffer[client->tail].value = 0;

 

                   client->packet_head = client->tail;

                   if (client->use_wake_lock)

                            wake_unlock(&client->wake_lock);

         }

 

         if (event->type == EV_SYN && event->code == SYN_REPORT) {

                   client->packet_head = client->head;

                   if (client->use_wake_lock)

                            wake_lock(&client->wake_lock);

                   kill_fasync(&client->fasync, SIGIO, POLL_IN);

         }

 

         spin_unlock(&client->buffer_lock);

}

 

//inputmanager系统

 

Inputmanager系统

综述:此模型大致关系

      InputmanageràInputReaderInterface负责读取input子系统上报的事件

                  àInputDispatcherInterface负责将读取到的事件上报给上层

首先来看InputManager.cpp/.h

InputManager类有四个对外的公有成员函数

virtual status_t start();

virtual status_t stop();

virtual sp<InputReaderInterface> getReader();

virtual sp<InputDispatcherInterface> getDispatcher();

下面对这几个函数进行简单的解析

/*

**1.开启发送消息的线程

**2.开启获取消息的线程

*/

status_t InputManager::start() {

    status_t result=mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);

    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);

    return OK;

}

/*

**1.停止获取消息的线程

**2.停止发送消息的线程

*/

status_t InputManager::stop() {

    status_t result = mReaderThread->requestExitAndWait();

    result = mDispatcherThread->requestExitAndWait();

    return OK;

}

 

 

/*

**获取读消息的类实例

*/

sp<InputReaderInterface> InputManager::getReader() {

    return mReader;

}

 

/*

**获取发送消息的类实例

*/

sp<InputDispatcherInterface> InputManager::getDispatcher() {

    return mDispatcher;

}

 

下面进入类

InputReader

InputReaderThread

InputReaderThread类主要就是继承了系统thread的属性

/*

**类的构造函数,实例化继承的类threadmread

*/

InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :

        Thread(/*canCallJava*/ true), mReader(reader) {

}

/*

**类的析构函数

*/

InputReaderThread::~InputReaderThread() {

}

 

/**

**线程循环的回调函数,mread类对事件的获取函数式looponce,是事件获取的主脉络

*/

bool InputReaderThread::threadLoop() {

    mReader->loopOnce();

    return true;

}

 

下面进入到InputReader类中

主要来看对外的函数public函数:

/*

**构造函数

*/

InputReader(const sp<EventHubInterface>& eventHub,

            const sp<InputReaderPolicyInterface>& policy,

            const sp<InputListenerInterface>& listener);

/*

**析构函数

*/

virtual ~InputReader();

/*

**打印dumplog

*/

virtual void dump(String8& dump);

/*

**监测函数,防止死锁

*/

virtual void monitor();

/*

**线程回调函数

*/

virtual void loopOnce();

/*

**获得输入设备的配置信息

*/

virtual void getInputConfiguration(InputConfiguration* outConfiguration);

/*

**获取输入设备的信息

*/

virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo);

/*

**获取输入设备的ID

*/

virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds);

/*

**获取扫描码

*/

virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,

            int32_t scanCode);

/*

**获取key

*/

virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,

            int32_t keyCode);

/*

**获取switch状态

*/

virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,

            int32_t sw);

/*

**判断是否有KEY

*/

virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,

            size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags);

/*

**获取更新的配置

*/

virtual void requestRefreshConfiguration(uint32_t changes);

 

下面主要来看看线程的回调函数looponce

void InputReader::loopOnce() {

    int32_t timeoutMillis;

{ // acquire lock

   //加锁

        AutoMutex _l(mLock);

        //判断配置信息是否需要更新

        uint32_t changes = mConfigurationChangesToRefresh;

        if (changes) {

            mConfigurationChangesToRefresh = 0;

            refreshConfigurationLocked(changes);

        }

 

        timeoutMillis = -1;

        if (mNextTimeout != LLONG_MAX) {

            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);

        }

    } // release lock

    //调用eventhubgetevent函数来获取事件

    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

 

    { // acquire lock

        AutoMutex _l(mLock);

 

        if (count) {

            processEventsLocked(mEventBuffer, count);

        }

        if (!count || timeoutMillis == 0) {

            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

#if DEBUG_RAW_EVENTS

            LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);

#endif

            mNextTimeout = LLONG_MAX;

            timeoutExpiredLocked(now);

        }

    } // release lock

 

    // Flush queued events out to the listener.

    // This must happen outside of the lock because the listener could potentially call

    // back into the InputReader's methods, such as getScanCodeState, or become blocked

    // on another thread similarly waiting to acquire the InputReader lock thereby

    // resulting in a deadlock.  This situation is actually quite plausible because the

    // listener is actually the input dispatcher, which calls into the window manager,

    // which occasionally calls into the input reader.

    mQueuedListener->flush();

}

 

下面进入到eventhub类来进一步分析事件的获取流程

Eventhub.cpp

 

共管理了那些设备

管理了设备的那些状态

怎么管理的?怎么从底层获取数据?怎么上报给上层的!

所有的设备都是用一个devices结构体进行管理。

而这些所有的设备通过一个KeyedVector<int32_t, Device*> mDevices;模版类进行管理。其实就是一个适量的数据结构。

Device对应的数据结构为:

struct Device {

        Device* next;//维护一个device的链表

 

        int fd;//设备对应的文件句柄

        const int32_t id;//设备对应的ID

        const String8 path;//设备文件对应的路劲

        const InputDeviceIdentifier identifier;//设备标识

 

        uint32_t classes;//设备属于的类

       

        //设备通常支持的几种事件

        uint8_t keyBitmask[(KEY_MAX + 1) / 8];//key事件

        uint8_t absBitmask[(ABS_MAX + 1) / 8];//绝对坐标事件

        uint8_t relBitmask[(REL_MAX + 1) / 8];//相对坐标事件

        uint8_t swBitmask[(SW_MAX + 1) / 8];//switch事件

        uint8_t ledBitmask[(LED_MAX + 1) / 8];//led相关的事件

        uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];//设备的属性相关的事件

 

        String8 configurationFile; //目前的理解是对应的配置文件

        PropertyMap* configuration;

        VirtualKeyMap* virtualKeyMap;//虚拟按键映射

        KeyMap keyMap;//实体按键映射

 

        Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);//设备的构造函数接口

        ~Device();//设备的析构函数的接口

 

        void close();//设备的关闭函数接口

};

 

这个函数主要是通过ioctl函数接口与kernel的设备文件进行交互。

主要就是以上支持的几种事件,的一些属性状态的获取

主要的函数接口是geteventopenDeviceLocked两个函数,其他的函数主要就是对属性相关的进行设备和获取。

Open所有的设备。

Close所有的设备

GetEvent获取设备的事件

首先看openDeviceLocked函数,根据传进来的文件名称,通过ioct函数接口,获取次文件设备的一系列属性值。其实就是对device的结构体进行初始化。

opendevice的时候通过epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)机制来监听对应设备文件的事件变化。

closedevice的时候通过epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL))机制来删除之前建立的监听机制。

GetEvent函数中主要是通过epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);函数进行事件的监听。

InputReader.cpp解析

 

获取数据的方式:

通过一个线程InputReaderThread进行轮询,去调用EVENThubgetevent接口来获取事件。

Inputmanager.cpp

他是事件处理的核心,处于管理地位。

主要干两件事情:

开启mDispatcherThread线程进行数据发送。在队列上面等待事件的输入,并异步的将事件发送到对应的应用程序。

开启mReaderThread进行数据获取,负责数据原始数据进行处理最终发送到mDispatcherThread线程的队列上面去。

Note:两者间的通信时单方向的。不共享内部的状态

mReaderThreadàmDispatcherThread:通过InputDispatcherPolicyInterface类进行交互。

Note:inputmanager类从来都不和JAVA直接交互,与上层进行交互的是InputDispatcherPolicyInterface类,并且启用Dalvik虚拟机(DVM)

 

首先看看eventHub对外的接口函数

class EventHubInterface : public virtual RefBase {

protected:

    //构造函数

EventHubInterface() { }

//析构函数

    virtual ~EventHubInterface() { }

public:

    // Synthetic raw event type codes produced when devices are added or removed.

    enum {

        // Sent when a device is added.

        DEVICE_ADDED = 0x10000000,

        // Sent when a device is removed.

        DEVICE_REMOVED = 0x20000000,

       // Sent when all added/removed devices from the most recent scan have been reported.

        // This event is always sent at least once.

        FINISHED_DEVICE_SCAN = 0x30000000,

 

        FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,

    };

/*

**获取设备的类

*/

    virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;

/*

**获取设备的名字

*/

 

    virtual String8 getDeviceName(int32_t deviceId) const = 0;

/*

**获取设备的配置

*/

    virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;

 /*

**获取设备绝对坐标信息

*/

    virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,

            RawAbsoluteAxisInfo* outAxisInfo) const = 0;

 /*

**获取设备的相对坐标信息

*/

    virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0;

 /*

**判断是否具有输入性能

*/

    virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;

/*

**键值映射

*/

    virtual status_t mapKey(int32_t deviceId, int scancode,

            int32_t* outKeycode, uint32_t* outFlags) const = 0;

/*

**坐标轴映射

*/

    virtual status_t mapAxis(int32_t deviceId, int scancode,

            AxisInfo* outAxisInfo) const = 0;

 

    // Sets devices that are excluded from opening.

    // This can be used to ignore input devices for sensors.

    virtual void setExcludedDevices(const Vector<String8>& devices) = 0;

 

    /*

     * Wait for events to become available and returns them.

     * After returning, the EventHub holds onto a wake lock until the next call to getEvent.

     * This ensures that the device will not go to sleep while the event is being processed.

     * If the device needs to remain awake longer than that, then the caller is responsible

     * for taking care of it (say, by poking the power manager user activity timer).

     *

     * The timeout is advisory only.  If the device is asleep, it will not wake just to

     * service the timeout.

     *

     * Returns the number of events obtained, or 0 if the timeout expired.

     */

    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;

 

    /*

     * Query current input state.

     */

    virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;

    virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;

    virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;

    virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,

            int32_t* outValue) const = 0;

 

    /*

     * Examine key input devices for specific framework keycode support

     */

    virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,

            uint8_t* outFlags) const = 0;

 

    virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;

    virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;

    virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;

 

    virtual void getVirtualKeyDefinitions(int32_t deviceId,

            Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;

 

    virtual String8 getKeyCharacterMapFile(int32_t deviceId) const = 0;

 

    /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */

    virtual void requestReopenDevices() = 0;

 

    /* Wakes up getEvents() if it is blocked on a read. */

    virtual void wake() = 0;

 

    /* Dump EventHub state to a string. */

    virtual void dump(String8& dump) = 0;

 

    /* Called by the heatbeat to ensures that the reader has not deadlocked. */

    virtual void monitor() = 0;

};

整体来看这个类,核心的接口就是:

Opendevices()

Getevent()

其他的接口都是一些辅助性质的接口

首先看看此类是怎么管理设备的。

//存储所有设备的适量数据结构

KeyedVector<int32_t, Device*> mDevices;

//记录所有打开的设备

Device *mOpeningDevices;

//记录所有关闭的设备

Device *mClosingDevices;

下面首先来看

/*

**1.扫描文件夹,打开对应文件夹下面所有的设备文件

*/

status_t EventHub::scanDirLocked(const char *dirname)

{

    char devname[PATH_MAX];

    char *filename;

    DIR *dir;

struct dirent *de;

//打开对应的文件夹,获得文件夹的句柄

    dir = opendir(dirname);

    if(dir == NULL)

        return -1;

    strcpy(devname, dirname);

    filename = devname + strlen(devname);

*filename++ = '/';

//遍历文件夹下面的设备文件,将合适的设备文件打开

    while((de = readdir(dir))) {

        if(de->d_name[0] == '.' &&

           (de->d_name[1] == '\0' ||

            (de->d_name[1] == '.' && de->d_name[2] == '\0')))

            continue;

        strcpy(filename, de->d_name);

        openDeviceLocked(devname);

    }

    closedir(dir);

    return 0;

}

 

/*

**主要是填充device的结构体

**1.填充InputDeviceIdentifier结构体

**      String8 name;//设备名

**      String8 location;

**      String8 uniqueId;

**      uint16_t bus;

**      uint16_t vendor;

**      uint16_t product;

**      uint16_t version;

**2. 检查此设备是否在排除的列表中

**3.获取device driverversion

**4.获取设备标示符

   __u16 bustype;

__u16 vendor;

         __u16 product;

         __u16 version;

**5. 设备此设备文件以非阻塞的方式进行轮询

**6.

**7.

**8.

**9.

**10.

**11.

**12.

 

*/

status_t EventHub::openDeviceLocked(const char *devicePath) {

    char buffer[80];

    const char *temp1 = "Button Jack";

    //打开设备文件,获取文件句柄  

    int fd = open(devicePath, O_RDWR);

    InputDeviceIdentifier identifier;

 

// Get device name.

//获取设备的名字

    if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {

    //检查此设备是否在排除的列表中

    // Check to see if the device is on our excluded list

    for (size_t i = 0; i < mExcludedDevices.size(); i++) {

        const String8& item = mExcludedDevices.itemAt(i);

        if (identifier.name == item) {

            LOGI("ignoring event id %s driver %s\n", devicePath, item.string());

            close(fd);

            return -1;

        }

    }

 

// Get device driver version.

//设备设备驱动的版本号

    int driverVersion;

    if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {

 

// Get device identifier.

//获取设备标示符

    struct input_id inputId;

if(ioctl(fd, EVIOCGID, &inputId)) {

 

    identifier.bus = inputId.bustype;

    identifier.product = inputId.product;

    identifier.vendor = inputId.vendor;

    identifier.version = inputId.version;

 

// Get device physical location.

//获取设备的物理位置

    if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1)

 

// Get device unique id.

//获取设备独一无二的id

if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1)

//设备此设备文件以非阻塞的方式进行轮询

    // Make file descriptor non-blocking for use with poll().

if (fcntl(fd, F_SETFL, O_NONBLOCK))

//将获取的设备信息进行整合new一个新的device结构体此时此设备获取FD的所有权

    // Allocate device.  (The device object takes ownership of the fd at this point.)

    int32_t deviceId = mNextDeviceId++;

    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);

// Load the configuration file for the device.

//下载设备的配置信息

    loadConfigurationLocked(device);

 

// Figure out the kinds of events the device reports.

//算出此设备支持的事件类型

    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);

    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);

    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);

    ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);

    ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);

    ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);

 

    // See if this is a keyboard.  Ignore everything in the button range except for

// joystick and gamepad buttons which are handled like keyboards for the most part.

//判断此设备社否为keyboard,忽略button范围的所有信息,除了joystick(操纵杆)

    bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))

            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),

                                   sizeof_bit_array(BTN_9))

            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),

                    sizeof_bit_array(KEY_MAX + 1));

    bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),

                    sizeof_bit_array(BTN_MOUSE))

            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),

                    sizeof_bit_array(BTN_DIGI));

    if (haveKeyboardKeys || haveGamepadButtons) {

        device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;

    }

 

    // See if this is a cursor device such as a trackball or mouse.

    if (test_bit(BTN_MOUSE, device->keyBitmask)

            && test_bit(REL_X, device->relBitmask)

            && test_bit(REL_Y, device->relBitmask)) {

        device->classes |= INPUT_DEVICE_CLASS_CURSOR;

    }

 

    // See if this is a touch pad.

    // Is this a new modern multi-touch driver?

    if (test_bit(ABS_MT_POSITION_X, device->absBitmask)

            && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {

        // Some joysticks such as the PS3 controller report axes that conflict

        // with the ABS_MT range.  Try to confirm that the device really is

        // a touch screen.

        if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {

            device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;

        }

    // Is this an old style single-touch driver?

    } else if (test_bit(BTN_TOUCH, device->keyBitmask)

            && test_bit(ABS_X, device->absBitmask)

            && test_bit(ABS_Y, device->absBitmask)) {

        device->classes |= INPUT_DEVICE_CLASS_TOUCH;

    }

 

    // See if this device is a joystick.

    // Assumes that joysticks always have gamepad buttons in order to distinguish them

    // from other devices such as accelerometers that also have absolute axes.

    if (haveGamepadButtons) {

        uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;

        for (int i = 0; i <= ABS_MAX; i++) {

            if (test_bit(i, device->absBitmask)

                    && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {

                device->classes = assumedClasses;

                break;

            }

        }

    }

 

    // Check whether this device has switches.

    for (int i = 0; i <= SW_MAX; i++) {

        if (test_bit(i, device->swBitmask)) {

            device->classes |= INPUT_DEVICE_CLASS_SWITCH;

            break;

        }

    }

 

    // Configure virtual keys.

    if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {

        // Load the virtual keys for the touch screen, if any.

        // We do this now so that we can make sure to load the keymap if necessary.

        status_t status = loadVirtualKeyMapLocked(device);

        if (!status) {

            device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;

        }

    }

 

    // Load the key map.

    // We need to do this for joysticks too because the key layout may specify axes.

    status_t keyMapStatus = NAME_NOT_FOUND;

    if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {

        // Load the keymap for the device.

        keyMapStatus = loadKeyMapLocked(device);

    }

 

    // Configure the keyboard, gamepad or virtual keyboard.

    if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {

        // Register the keyboard as a built-in keyboard if it is eligible.

        if (!keyMapStatus

                && mBuiltInKeyboardId == -1

                && isEligibleBuiltInKeyboard(device->identifier,

                        device->configuration, &device->keyMap)) {

            mBuiltInKeyboardId = device->id;

        }

 

        // 'Q' key support = cheap test of whether this is an alpha-capable kbd

        if (hasKeycodeLocked(device, AKEYCODE_Q)) {

            device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;

        }

 

        // See if this device has a DPAD.

        if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&

                hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&

                hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&

                hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&

                hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {

            device->classes |= INPUT_DEVICE_CLASS_DPAD;

        }

 

        // See if this device has a gamepad.

        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {

            if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {

                device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;

                break;

            }

        }

    }

 

    // If the device isn't recognized as something we handle, don't monitor it.

    if (device->classes == 0) {

        LOGV("Dropping device: id=%d, path='%s', name='%s'",

                deviceId, devicePath, device->identifier.name.string());

        delete device;

        return -1;

    }

 

    // Determine whether the device is external or internal.

    if (isExternalDeviceLocked(device)) {

        device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;

    }

 

    // Register with epoll.

    struct epoll_event eventItem;

    memset(&eventItem, 0, sizeof(eventItem));

    eventItem.events = EPOLLIN;

    eventItem.data.u32 = deviceId;

    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {

        LOGE("Could not add device fd to epoll instance.  errno=%d", errno);

        delete device;

        return -1;

    }

 

    LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "

            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",

         deviceId, fd, devicePath, device->identifier.name.string(),

         device->classes,

         device->configurationFile.string(),

         device->keyMap.keyLayoutFile.string(),

         device->keyMap.keyCharacterMapFile.string(),

         toString(mBuiltInKeyboardId == deviceId));

 

    mDevices.add(deviceId, device);

 

    device->next = mOpeningDevices;

    mOpeningDevices = device;

    return 0;

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值