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,区分普通的event和filters
bool(*match)(struct input_handler *handler, struct input_dev *dev);
//当handler的table ID与dev的id匹配成功后调用
int(*connect)(struct input_handler *handler, struct input_dev *dev, const structinput_device_id *id);//当匹配handler和devic时调用
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; //关联handler的input 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联系起来。也就是说在注册handler和dev时都会去调用该函数。
………
}
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 device的h_list链表上.还将handle挂到对应的handler的hlist链表上.如果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中的数据写入到用户空间的缓存区中
- android input子系统之三:事件层
- android input子系统分析---事件层
- android input子系统之二:核心层
- Android之Input子系统事件分发流程
- Android之Input子系统事件分发流程
- Android之Input子系统事件分发流程
- Android之Input子系统事件分发流程
- input子系统事件处理层evdev分析
- Android 4.2 之Input子系统事件分发流程
- input子系统框架、核心层、输入事件驱动层详解
- android input子系统分析---驱动层
- Android Framework------之Input子系统
- Android Framework------之Input子系统
- Android Framework------之Input子系统
- Android Framework------之Input子系统
- Android Framework------之Input子系统
- Android Framework------之Input子系统
- Linux input子系统分析---4、事件处理层分析
- linux常用命令—— 网络通信(九)
- 程序的加载
- 使用runOnUiThread更新UI
- x265-1.7版本-common/cudata.cpp注释
- 第一行代码
- android input子系统之三:事件层
- Linux下errno错误信息对照
- Linux workqueue工作原理
- 试客小兵是真的吗?试客小兵下载,试客小兵什么时候刷新任务?
- 标准库 bitset
- 解决触控点击事件和手势的冲突
- AngularJS 详解
- 这十二行代码让浏览器爆炸
- struts常用标签(包括特殊的表单标签)使用