android input子系统之三:事件层

来源:互联网 发布:centos搭建l2tp服务器 编辑:程序博客网 时间:2024/05/01 01:39

四 事件层

struct input_dev物理输入设备的基本数据结构,包含设备相关的一些信息

structinput_handler 事件处理结构体,定义怎么处理事件的逻辑

struct input_handle用来创建input_dev 和 input_handler 之间关系的结构体
input_handler详细定义如下:

struct input_handler {

         void*private;  //driver-specific data

 

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

         //event句柄,当input core关闭中断获取自旋锁后奖杯调用

         void(*events)(struct input_handle *handle, const struct input_value *vals, unsignedint count);// events句柄,当input core关闭中断获取自旋锁后奖杯调用

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

         //类似于event,区分普通的eventfilters

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

         //handlertable IDdevid匹配成功后调用

         int(*connect)(struct input_handler *handler, struct input_dev *dev, const structinput_device_id *id);//当匹配handlerdevic时调用

         void(*disconnect)(struct input_handle *handle);//input device中断开一个handler

         void(*start)(struct input_handle *handle);// startshandler for given handle.

 

Bool  legacy_minors;

         intminor;

         constchar *name; //handler名称,在/proc/bus/input/handlers显示

         conststruct input_device_id *id_table;//指向input_device_ids设备表的指针

         structlist_head        h_list; //关联handlerinput handles列表

         structlist_head        node;// for placing the driver onto input_handler_list

};

static struct input_handler evdev_handler ={

         .event                = evdev_event,

         .events              = evdev_events,

         .connect  = evdev_connect,

         .disconnect      = evdev_disconnect,

         .legacy_minors         = true,

         .minor                = EVDEV_MINOR_BASE,

         .name                = "evdev",

         .id_table  = evdev_ids,

};

 

module_init(evdev_init);

static int __init evdev_init(void)

{

         returninput_register_handler(&evdev_handler);

}

int input_register_handler(structinput_handler *handler)

{………

         INIT_LIST_HEAD(&handler->h_list);

         list_add_tail(&handler->node,&input_handler_list);//handler加入全局的 input_handler_list链表中,该链表包含了系统中所有的input_handler

         list_for_each_entry(dev,&input_dev_list, node)

    input_attach_handler(dev,handler);//input_attach_handler()函数的作用是匹配 input_dev_list链表中的 input_dev handler。如果成功会将 input_dev handler联系起来。也就是说在注册handlerdev时都会去调用该函数。

         ………

}

static int evdev_connect(structinput_handler *handler, struct input_dev *dev,

                             const struct input_device_id *id)

{………

evdev = kzalloc(sizeof(struct evdev),GFP_KERNEL);

………

INIT_LIST_HEAD(&evdev->client_list);

………

init_waitqueue_head(&evdev->wait);

evdev->exist = true;

dev_no = minor;

dev_set_name(&evdev->dev,"event%d", dev_no);

         evdev->handle.dev= input_get_device(dev);

         evdev->handle.name= dev_name(&evdev->dev);

         evdev->handle.handler= handler;

         evdev->handle.private= evdev;

//分配了一个 evdev结构 ,并对这个结构进行初始化 .在这里我们可以看到 ,这个结构封装了一个 handle结构 ,这结构与我们之前所讨论的 handler是不相同的 .注意有一个字母的差别哦 .我们可以把 handle看成是 handler input device的信息集合体 .在这个结构里集合了匹配成功的 handler input device

 

         evdev->dev.devt= MKDEV(INPUT_MAJOR, minor);

         evdev->dev.class= &input_class;

         evdev->dev.parent= &dev->dev;

         evdev->dev.release= evdev_free;

         device_initialize(&evdev->dev);

//在这段代码里主要完成 evdev封装的 device的初始化 .注意在这里 ,使它所属的类指向 input_class.这样在 /sysfs中创建的设备目录就会在 /sys/class/input/下面显示 .

 

         error= input_register_handle(&evdev->handle);

cdev_init(&evdev->cdev, &evdev_fops);

         evdev->cdev.kobj.parent= &evdev->dev.kobj;

         error= cdev_add(&evdev->cdev, evdev->dev.devt, 1);

error = device_add(&evdev->dev);

………}

 

int input_register_handle(structinput_handle *handle){ ………

struct input_handler *handler =handle->handler;

         structinput_dev *dev = handle->dev;

………

/*

          * Filters go to the head of the list, normalhandlers

          * to the tail.

          */

         if(handler->filter)

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

         else

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

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

// handle挂到所对应input deviceh_list链表上.还将handle挂到对应的handlerhlist链表上.如果handler定义了start函数,将调用之

………}

到这里,我们已经看到了input device, handler和handle是怎么关联起来的了。

 

上报信息是调用的  .event       = evdev_event   。每当input device上报一个事件时,会将其交给和它匹配的handler的event函数处理.在evdev中这个event函数。

static void evdev_event(struct input_handle*handle,

                            unsignedint type, unsigned int code, int value)

{

         structinput_value vals[] = { { type, code, value } };

         evdev_events(handle, vals, 1);

static void evdev_events(struct input_handle*handle,

                             const struct input_value *vals, unsigned intcount)

{

         structevdev *evdev = handle->private;

………

client = rcu_dereference(evdev->grab);

         if(client)

                   evdev_pass_values(client, vals, count, time_mono, time_real);

         else

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

                   evdev_pass_values(client, vals, count,  time_mono, time_real);

………}

 

static void evdev_pass_values(structevdev_client *client,

                            conststruct input_value *vals, unsigned int count,

                            ktime_tmono, ktime_t real)

{

         structevdev *evdev = client->evdev;

………

for (v = vals; v != vals + count; v++) {

                   event.type= v->type;

                   event.code= v->code;

                   event.value= v->value;

                  __pass_event(client,&event);

                   if(v->type == EV_SYN && v->code == SYN_REPORT)

                            wakeup= true;

         }

………}

static void __pass_event(structevdev_client *client,

                             const struct input_event *event)

{

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

………

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

                   /*

                    * This effectively "drops" allunconsumed events, leaving

                    * EV_SYN/SYN_DROPPED plus the newest event inthe 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;

                   ……...        }

………}

这里的操作很简单.就是将event(上传数据)保存到client->buffer中.而client->head就是当前的数据位置.注意这里是一个环形缓存区.写数据是从client->head写.而读数据则是从client->tail中读.

 

最后我们看下handler的相关操作函数    .fops   =&evdev_fops,  我们知道.对主设备号为INPUT_MAJOR的设备节点进行操作,会将操作集转换成handler的操作集.在evdev中,这个操作集就是evdev_fops.对应的open函数如下: 

static int evdev_open(struct inode *inode,struct file *file)

{

         structevdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);

………

struct evdev_client *client;

………

         client->clkid= CLOCK_MONOTONIC;

         client->bufsize= bufsize;

         spin_lock_init(&client->buffer_lock);

         snprintf(client->name,sizeof(client->name), "%s-%d",

                            dev_name(&evdev->dev),task_tgid_vnr(current));

         client->evdev= evdev;

         evdev_attach_client(evdev, client);

         error= evdev_open_device(evdev);

………}

static int evdev_open_device(struct evdev*evdev)

{………

retval = input_open_device(&evdev->handle);

………}

 evdev_open_device()函数用来打开相应的输入设备,使设备准备好接收或者发送数据。evdev_open_device()函数先获得互斥锁,然后检查设备是否存在,并判断设备是否已经被打开。如果没有打开,则调用 input_open_device()函数打开设备.

int input_open_device(struct input_handle*handle)

{

         structinput_dev *dev = handle->dev;

………

if (!dev->users++ && dev->open)

                   retval= dev->open(dev);

………}

 

对于evdev设备节点的read操作都会由evdev_read()完成.它的代码如下: 

static ssize_t evdev_read(struct file*file, char __user *buffer,

                              size_t count, loff_t *ppos)

{

         structevdev_client *client = file->private_data;

         structevdev *evdev = client->evdev;

         structinput_event event;

         size_tread = 0;

………

while (read + input_event_size() <=count && evdev_fetch_next_event(client, &event)) {

         if(input_event_to_user(buffer + read, &event))

                   return-EFAULT;

                   read+= input_event_size();

                   }

………}

input_event_to_user 将client中的数据写入到用户空间的缓存区中


0 0