接着上次AD7879-I2C对事件的处理过程分析
1.设置事件
2.上报事件
先看设置事件部分
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit);
__set_bit(ABS_PRESSURE, input_dev->absbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X,
pdata->x_min ? : 0,
pdata->x_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_Y,
pdata->y_min ? : 0,
pdata->y_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE,
pdata->pressure_min, pdata->pressure_max, 0, 0);
上面的代码可以看到主要设置input_dev结构体下面的evbit和absbit两个成员数组。
evbit:这个数组以位掩码的形式,代表这个设备支持事件的类型。
absbit:这个数组以位掩码的形式,代表这个这个事件支持的编码。具体设置这个事件编码可以通过 input_set_abs_params来设置。
Abs这个事件编码可以由下面这个结构体描述
struct input_absinfo {
__s32 value;
__s32 minimum;
__s32 maximum;
__s32 fuzz;
__s32 flat;
__s32 resolution;
};
所以input_set_abs_params主要是完成 input_absinfo的设置
void input_set_abs_params(struct input_dev *dev, unsigned int axis,
int min, int max, int fuzz, int flat)
{
struct input_absinfo *absinfo;
input_alloc_absinfo(dev);
if (!dev->absinfo)
return;
absinfo = &dev->absinfo[axis];
absinfo->minimum = min;
absinfo->maximum = max;
absinfo->fuzz = fuzz;
absinfo->flat = flat;
dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
}
EXPORT_SYMBOL(input_set_abs_params);
接着看上报事件部分
input_report_key(input_dev, BTN_TOUCH, 1);
input_report_abs(input_dev, ABS_X, ts->x);
input_report_abs(input_dev, ABS_Y, ts->y);
input_report_abs(input_dev, ABS_PRESSURE, ts->Rt);
input_sync(input_dev);
主要完成了相应事件的上报,最后input_sync主要完成事件的同步上报,static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
在input.h中可以看到,真正完成上报的是函数 input_event,这个函数在input.c中
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_handle_event(dev, type, code, value);//事件处理函数
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
EXPORT_SYMBOL(input_event);
事件的处理在 input_handle_event完成的
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:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
if (!dev->sync) {
dev->sync = true;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case SYN_MT_REPORT:
dev->sync = false;
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;
}
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = false;
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
if (disposition & INPUT_PASS_TO_HANDLERS)
input_pass_event(dev, type, code, value);
}
通过对事件类型的判断分别进行相应的处理,互不干扰,首先看这几个东东
#define INPUT_IGNORE_EVENT 0
#define INPUT_PASS_TO_HANDLERS 1
#define INPUT_PASS_TO_DEVICE 2
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
它们是事件传递的方式,系统默认是INPUT_IGNORE_EVENT,忽略这个事件, INPUT_PASS_TO_HANDLERS表示事件传递给处理器, INPUT_PASS_TO_DEVICE表示事件传递给设备。触摸屏是通过input_handle_abs_event函数来设置的
static int input_handle_abs_event(struct input_dev *dev,
unsigned int code, int *pval)
{
bool is_mt_event;
int *pold;
if (code == ABS_MT_SLOT) {
/*
* "Stage" the event; we'll flush it later, when we
* get actual touch data.
*/
if (*pval >= 0 && *pval < dev->mtsize)
dev->slot = *pval;
return INPUT_IGNORE_EVENT;
}
is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
if (!is_mt_event) {//单点触控
pold = &dev->absinfo[code].value;
} else if (dev->mt) {//多点触控
struct input_mt_slot *mtslot = &dev->mt[dev->slot];
pold = &mtslot->abs[code - ABS_MT_FIRST];
} else {
/*
* Bypass filtering for multi-touch events when
* not employing slots.
*/
pold = NULL;
}
if (pold) {
*pval = input_defuzz_abs_event(*pval, *pold,
dev->absinfo[code].fuzz);
if (*pold == *pval)
return INPUT_IGNORE_EVENT;
*pold = *pval;
}
/* Flush pending "slot" event */
if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
}
return INPUT_PASS_TO_HANDLERS;
}
这里主要看 input_pass_event描述事件是怎么被处理的,还有看返回值INPUT_PASS_TO_HANDLERS
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
if (handle)//如果是绑定的handle
handle->handler->event(handle, type, code, value);//调用绑定的handle->handler->event函数
else {//如果没有绑定 ,则遍历dev的h_list链表,寻找handle,如果handle已经打开,说明有进程读取关联的evdev
bool filtered = false;
list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
if (!handle->open)
continue;
handler = handle->handler;
if (!handler->filter) {
if (filtered)
break;
handler->event(handle, type, code, value);//调用事件处理器的event函数,进行事件处理
} else if (handler->filter(handle, type, code, value))
filtered = true;
}
}
rcu_read_unlock();
}
这里看到真正完成事件处理是由evdev中的event来完成的。对于触摸屏来说,对应的事件处理器是evdev,所以到evdev.c中找到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;
/*将传过来的事件,赋值给input_event结构*/
do_gettimeofday(&event.time);
event.type = type;
event.code = code;
event.value = value;
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event);//如果evdev绑定了client,那么处理这个客户端,触摸屏没有绑定
else
list_for_each_entry_rcu(client, &evdev->client_list, node)//遍历client链表,调用evdev_pass_event函数
evdev_pass_event(client, &event);
rcu_read_unlock();
if (type == EV_SYN && code == SYN_REPORT)
wake_up_interruptible(&evdev->wait);//唤醒等待的进程
}
这个函数主要完成client和event的绑定,然后调用 evdev_pass_event函数
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
client->buffer[client->head++] = *event;//将事件赋值给客户端的input_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 (event->type == EV_SYN && event->code == SYN_REPORT) {
client->packet_head = client->head;
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
spin_unlock(&client->buffer_lock);
}
这个函数中最重要的意见事情就是把事件赋值给了client的input_event数组,只需要将这个数组传给用户空间,进程就能收到触摸屏按下的信息了。下面看evdev.c下面提供的操作函数集
static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
.flush = evdev_flush,
.llseek = no_llseek,
};
其中 evdev_read的具体实现如下
static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;//client在打开的时候分配并保存再file->private_data中
struct evdev *evdev = client->evdev;
struct input_event event;
int retval = 0;
if (count < input_event_size())//每次读取的字节数,不要少于input_event结构的大小
return -EINVAL;
if (!(file->f_flags & O_NONBLOCK)) {//如果设置了事件阻塞操作
retval = wait_event_interruptible(evdev->wait,//没有事件就会睡眠在evdev的等待队列上 ,等待条件是有事件来或者evdev不存在了,即设备关闭了
client->packet_head != client->tail ||
!evdev->exist);
if (retval)//说明有事件传来或者设备被关闭了,或者内核发过来终止信号
return retval;
}
if (!evdev->exist)
return -ENODEV;
while (retval + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) {//evdev_fetch_next_event遍历client里面的input_event buffer数组
if (input_event_to_user(buffer + retval, &event))//将事件复制到用户空间
return -EFAULT;
retval += input_event_size();
}
if (retval == 0 && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
return retval;//返回复制的数据字节数
}
当有事件传过来的时候,会调用event函数,对input_event buffer进行赋值,然后会通过evdev提供的操作函数集和用户空间进行交互。