转自:https://blog.csdn.net/qwaszx523/article/details/54139897

转自http://blog.csdn.net/coldsnow33/article/details/12841077

input事件处理流程 input driver -> input core ->event handler -> userspace 给应用程序。

一 事件分发跟踪

  核心层留给驱动层的上报接口是input_report_abs(),最终会调用input_event()。
  1. void input_event(struct input_dev *dev,
  2. unsigned int type, unsigned int code, int value)
  3. {
  4. unsigned long flags;
  5. if (is_event_supported(type, dev->evbit, EV_MAX)) {
  6. spin_lock_irqsave(&dev->event_lock, flags);
  7. input_handle_event(dev, type, code, value);
  8. spin_unlock_irqrestore(&dev->event_lock, flags);
  9. }
  10. }
  1.  
    void input_event(struct input_dev *dev,
  2.  
    unsigned int type, unsigned int code, int value)
  3.  
    {
  4.  
    unsigned long flags;
  5.  
     
  6.  
    if (is_event_supported(type, dev->evbit, EV_MAX)) {
  7.  
     
  8.  
    spin_lock_irqsave(&dev->event_lock, flags);
  9.  
    input_handle_event(dev, type, code, value);
  10.  
    spin_unlock_irqrestore(&dev->event_lock, flags);
  11.  
    }
  12.  
    }

  先判断type是否支持,接着进入处理核心。

  1. static void input_handle_event(struct input_dev *dev,
  2. unsigned int type, unsigned int code, int value)
  3. {
  4. int disposition;
  5. disposition = input_get_disposition(dev, type, code, value);
  6. if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
  7. dev->event(dev, type, code, value);
  8. if (!dev->vals)
  9. return;
  10. if (disposition & INPUT_PASS_TO_HANDLERS) {
  11. struct input_value *v;
  12. if (disposition & INPUT_SLOT) {
  13. v = &dev->vals[dev->num_vals++];
  14. v->type = EV_ABS;
  15. v->code = ABS_MT_SLOT;
  16. v->value = dev->mt->slot;
  17. }
  18. v = &dev->vals[dev->num_vals++];
  19. v->type = type;
  20. v->code = code;
  21. v->value = value;
  22. }
  23. if (disposition & INPUT_FLUSH) {
  24. if (dev->num_vals >= 2)
  25. input_pass_values(dev, dev->vals, dev->num_vals);
  26. dev->num_vals = 0;
  27. } else if (dev->num_vals >= dev->max_vals - 2) {
  28. dev->vals[dev->num_vals++] = input_value_sync;
  29. input_pass_values(dev, dev->vals, dev->num_vals);
  30. dev->num_vals = 0;
  31. }
  32. }
  1.  
    static void input_handle_event(struct input_dev *dev,
  2.  
    unsigned int type, unsigned int code, int value)
  3.  
    {
  4.  
    int disposition;
  5.  
     
  6.  
    disposition = input_get_disposition(dev, type, code, value);
  7.  
     
  8.  
    if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
  9.  
    dev->event(dev, type, code, value);
  10.  
     
  11.  
    if (!dev->vals)
  12.  
    return;
  13.  
     
  14.  
    if (disposition & INPUT_PASS_TO_HANDLERS) {
  15.  
    struct input_value *v;
  16.  
     
  17.  
    if (disposition & INPUT_SLOT) {
  18.  
    v = &dev->vals[dev->num_vals++];
  19.  
    v->type = EV_ABS;
  20.  
    v->code = ABS_MT_SLOT;
  21.  
    v->value = dev->mt->slot;
  22.  
    }
  23.  
     
  24.  
    v = &dev->vals[dev->num_vals++];
  25.  
    v->type = type;
  26.  
    v->code = code;
  27.  
    v->value = value;
  28.  
    }
  29.  
     
  30.  
    if (disposition & INPUT_FLUSH) {
  31.  
    if (dev->num_vals >= 2)
  32.  
    input_pass_values(dev, dev->vals, dev->num_vals);
  33.  
    dev->num_vals = 0;
  34.  
    } else if (dev->num_vals >= dev->max_vals - 2) {
  35.  
    dev->vals[dev->num_vals++] = input_value_sync;
  36.  
    input_pass_values(dev, dev->vals, dev->num_vals);
  37.  
    dev->num_vals = 0;
  38.  
    }
  39.  
     
  40.  
    }

  input_get_disposition()获得事件处理者身份。INPUT_PASS_TO_HANDLERS表示交给input hardler处理,INPUT_PASS_TO_DEVICE表示交给input device处理,INPUT_FLUSH表示需要handler立即处理。如果事件正常一般返回的是INPUT_PASS_TO_HANDLERS,只有code为SYN_REPORT时返回INPUT_PASS_TO_HANDLERS | INPUT_FLUSH。需要说明的是下面一段:

  1. case EV_ABS:
  2. if (is_event_supported(code, dev->absbit, ABS_MAX))
  3. disposition = input_handle_abs_event(dev, code, &value);
  1.  
    case EV_ABS:
  2.  
    if (is_event_supported(code, dev->absbit, ABS_MAX))
  3.  
    disposition = input_handle_abs_event(dev, code, &value);
  1. static int input_handle_abs_event(struct input_dev *dev,
  2. unsigned int code, int *pval)
  3. {
  4. struct input_mt *mt = dev->mt;
  5. bool is_mt_event;
  6. int *pold;
  7. if (code == ABS_MT_SLOT) {
  8. /*
  9. * "Stage" the event; we'll flush it later, when we
  10. * get actual touch data.
  11. */
  12. if (mt && *pval >= 0 && *pval < mt->num_slots)
  13. mt->slot = *pval;
  14. return INPUT_IGNORE_EVENT;
  15. }
  16. is_mt_event = input_is_mt_value(code);
  17. if (!is_mt_event) {
  18. pold = &dev->absinfo[code].value;
  19. } else if (mt) {
  20. pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
  21. } else {
  22. /*
  23. * Bypass filtering for multi-touch events when
  24. * not employing slots.
  25. */
  26. pold = NULL;
  27. }
  28. if (pold) {
  29. *pval = input_defuzz_abs_event(*pval, *pold,
  30. dev->absinfo[code].fuzz);
  31. if (*pold == *pval)
  32. return INPUT_IGNORE_EVENT;
  33. *pold = *pval;
  34. }
  35. /* Flush pending "slot" event */
  36. if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
  37. input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
  38. return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
  39. }
  40. return INPUT_PASS_TO_HANDLERS;
  41. }
  1.  
    static int input_handle_abs_event(struct input_dev *dev,
  2.  
    unsigned int code, int *pval)
  3.  
    {
  4.  
    struct input_mt *mt = dev->mt;
  5.  
    bool is_mt_event;
  6.  
    int *pold;
  7.  
     
  8.  
    if (code == ABS_MT_SLOT) {
  9.  
    /*
  10.  
    * "Stage" the event; we'll flush it later, when we
  11.  
    * get actual touch data.
  12.  
    */
  13.  
    if (mt && *pval >= 0 && *pval < mt->num_slots)
  14.  
    mt->slot = *pval;
  15.  
     
  16.  
    return INPUT_IGNORE_EVENT;
  17.  
    }
  18.  
     
  19.  
    is_mt_event = input_is_mt_value(code);
  20.  
     
  21.  
    if (!is_mt_event) {
  22.  
    pold = &dev->absinfo[code].value;
  23.  
    } else if (mt) {
  24.  
    pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
  25.  
    } else {
  26.  
    /*
  27.  
    * Bypass filtering for multi-touch events when
  28.  
    * not employing slots.
  29.  
    */
  30.  
    pold = NULL;
  31.  
    }
  32.  
     
  33.  
    if (pold) {
  34.  
    *pval = input_defuzz_abs_event(*pval, *pold,
  35.  
    dev->absinfo[code].fuzz);
  36.  
    if (*pold == *pval)
  37.  
    return INPUT_IGNORE_EVENT;
  38.  
     
  39.  
    *pold = *pval;
  40.  
    }
  41.  
     
  42.  
    /* Flush pending "slot" event */
  43.  
    if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
  44.  
    input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
  45.  
    return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
  46.  
    }
  47.  
     
  48.  
    return INPUT_PASS_TO_HANDLERS;
  49.  
    }

  首先说明的是过滤处理,如果code不是ABS_MT_FIRST到ABS_MT_LAST之间,那就是单点上报(比如ABS_X);否则符合多点上报;它们的事件值value存储的位置是不一样的,所以取pold指针的方式是不一样的。(这个pold是过滤之后存的*pold = *pval;)。input_defuzz_abs_event()会对比当前value和上一次的old value;如果一样就过滤掉;不产生事件,但是只针对type B进行处理;type B的framework层sync后是不会清除slot的,所以要确保上报数据的准确;type A的sync后会清除slot。

  if (code == ABS_MT_SLOT)只记录当前传输的slot,就是id;mt->slot = *pval;为什么这样做?这是对多点上报type B的处理,type B report首先report的就是type=EV_ABS,code=ABS_MT_SLOT,还有触点id为参数;一般type B接下来会依次report ABS_MT_TRACKING_ID、ABS_MT_TOOL_TYPE、ABS_MT_POSITION_X、ABS_MT_POSITION_Y等。所以此时记录下这个触点id,等下次report ABS_MT_TRACKING_ID时会处理这个code,如果只单一处理code=ABS_MT_SLOT,对用户来说没有意义。report ABS_MT_TRACKING_ID时会一直走到最后return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;input_handle_event()里会根据INPUT_SLOT标志填充input_value v = &dev->vals[dev->num_vals++];将later的ABS_MT_SLOT补上。再下一个report ABS_MT_TOOL_TYPE时,是否会再走到这里来来补填一个ABS_MT_SLOT呢?看input_handle_abs_event()中最后的判断条件上次mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)的时候,就input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);,既然上一次已经set了新值,那此时条件就不成立了,所以只return INPUT_PASS_TO_HANDLERS,而不会再次填充一个code为ABS_MT_SLOT的input_value。
  回到input_handle_event(),填充&dev->vals[dev->num_vals++]中的一个input_value结构。code为SYN_REPORT时返回INPUT_PASS_TO_HANDLERS | INPUT_FLUSH,所以会调用input_pass_values(dev, dev->vals, dev->num_vals)。如果指定了dev->grab指定了handle,就使用指定的;否则,遍历dev->h_list;找到dev上handle是open的,这个open什么时候设置?显然是应用层open的时候。dev->h_list的handle是在input device注册或者input handler注册的时候,匹配成功connect时,创建并初始化的,handle会把这两个结构联系到一起,继续执行input_to_handler()。
  1. static unsigned int input_to_handler(struct input_handle *handle,
  2. struct input_value *vals, unsigned int count)
  3. {
  4. struct input_handler *handler = handle->handler;
  5. struct input_value *end = vals;
  6. struct input_value *v;
  7. for (v = vals; v != vals + count; v++) {
  8. if (handler->filter &&
  9. handler->filter(handle, v->type, v->code, v->value))
  10. continue;
  11. if (end != v)
  12. *end = *v;
  13. end++;
  14. }
  15. count = end - vals;
  16. if (!count)
  17. return 0;
  18. if (handler->events)
  19. handler->events(handle, vals, count);
  20. else if (handler->event)
  21. for (v = vals; v != end; v++)
  22. handler->event(handle, v->type, v->code, v->value);
  23. return count;
  24. }
  1.  
    static unsigned int input_to_handler(struct input_handle *handle,
  2.  
    struct input_value *vals, unsigned int count)
  3.  
    {
  4.  
    struct input_handler *handler = handle->handler;
  5.  
    struct input_value *end = vals;
  6.  
    struct input_value *v;
  7.  
     
  8.  
    for (v = vals; v != vals + count; v++) {
  9.  
    if (handler->filter &&
  10.  
    handler->filter(handle, v->type, v->code, v->value))
  11.  
    continue;
  12.  
    if (end != v)
  13.  
    *end = *v;
  14.  
    end++;
  15.  
    }
  16.  
     
  17.  
    count = end - vals;
  18.  
    if (!count)
  19.  
    return 0;
  20.  
     
  21.  
    if (handler->events)
  22.  
    handler->events(handle, vals, count);
  23.  
    else if (handler->event)
  24.  
    for (v = vals; v != end; v++)
  25.  
    handler->event(handle, v->type, v->code, v->value);
  26.  
     
  27.  
    return count;
  28.  
    }

  首先过滤,相同事件都合并,然后交给handler->events或者handler->event处理;前者是成批处理,后者是单一事件处理。

  1. static void evdev_events(struct input_handle *handle,
  2. const struct input_value *vals, unsigned int count)
  3. {
  4. struct evdev *evdev = handle->private;
  5. struct evdev_client *client;
  6. ktime_t time_mono, time_real;
  7. time_mono = ktime_get();
  8. time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
  9. rcu_read_lock();
  10. client = rcu_dereference(evdev->grab);
  11. if (client)
  12. evdev_pass_values(client, vals, count, time_mono, time_real);
  13. else
  14. list_for_each_entry_rcu(client, &evdev->client_list, node)
  15. evdev_pass_values(client, vals, count,
  16. time_mono, time_real);
  17. rcu_read_unlock();
  18. }
  1.  
    static void evdev_events(struct input_handle *handle,
  2.  
    const struct input_value *vals, unsigned int count)
  3.  
    {
  4.  
    struct evdev *evdev = handle->private;
  5.  
    struct evdev_client *client;
  6.  
    ktime_t time_mono, time_real;
  7.  
     
  8.  
    time_mono = ktime_get();
  9.  
    time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
  10.  
     
  11.  
    rcu_read_lock();
  12.  
     
  13.  
    client = rcu_dereference(evdev->grab);
  14.  
     
  15.  
    if (client)
  16.  
    evdev_pass_values(client, vals, count, time_mono, time_real);
  17.  
    else
  18.  
    list_for_each_entry_rcu(client, &evdev->client_list, node)
  19.  
    evdev_pass_values(client, vals, count,
  20.  
    time_mono, time_real);
  21.  
     
  22.  
    rcu_read_unlock();
  23.  
    }

  如果指定了client就用指定的,这个client是指evdev_client,否则遍历evdev->client_list,放到client_list的client中。client_list中的client是什么时候挂上的?(evdev_open()->evdev_attach_client()->list_add_tail_rcu(&client->node, &evdev->client_list))接下来evdev_pass_values会把事情交给client处理。

  1. static void evdev_pass_values(struct evdev_client *client,
  2. const struct input_value *vals, unsigned int count,
  3. ktime_t mono, ktime_t real)
  4. {
  5. struct evdev *evdev = client->evdev;
  6. const struct input_value *v;
  7. struct input_event event;
  8. bool wakeup = false;
  9. event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
  10. mono : real);
  11. /* Interrupts are disabled, just acquire the lock. */
  12. spin_lock(&client->buffer_lock);
  13. for (v = vals; v != vals + count; v++) {
  14. event.type = v->type;
  15. event.code = v->code;
  16. event.value = v->value;
  17. __pass_event(client, &event);
  18. if (v->type == EV_SYN && v->code == SYN_REPORT)
  19. wakeup = true;
  20. }
  21. spin_unlock(&client->buffer_lock);
  22. if (wakeup)
  23. wake_up_interruptible(&evdev->wait);
  24. }
  1.  
    static void evdev_pass_values(struct evdev_client *client,
  2.  
    const struct input_value *vals, unsigned int count,
  3.  
    ktime_t mono, ktime_t real)
  4.  
    {
  5.  
    struct evdev *evdev = client->evdev;
  6.  
    const struct input_value *v;
  7.  
    struct input_event event;
  8.  
    bool wakeup = false;
  9.  
     
  10.  
    event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
  11.  
    mono : real);
  12.  
     
  13.  
    /* Interrupts are disabled, just acquire the lock. */
  14.  
    spin_lock(&client->buffer_lock);
  15.  
     
  16.  
    for (v = vals; v != vals + count; v++) {
  17.  
    event.type = v->type;
  18.  
    event.code = v->code;
  19.  
    event.value = v->value;
  20.  
    __pass_event(client, &event);
  21.  
    if (v->type == EV_SYN && v->code == SYN_REPORT)
  22.  
    wakeup = true;
  23.  
    }
  24.  
     
  25.  
    spin_unlock(&client->buffer_lock);
  26.  
     
  27.  
    if (wakeup)
  28.  
    wake_up_interruptible(&evdev->wait);
  29.  
    }

  此时input_value需要转换为input_event;目的是为了添加时间信息。每个input_event都会__pass_event;收到SYNC后会设置wakeup标志,唤醒evdev->wait。这个wait也是connect时候初始化的,init_waitqueue_head(&evdev->wait);唤醒它干什么呢?因为用户如果读不到数据根据open标志O_NONBLOCK会发生阻塞;就是需要client中有数据时来唤醒。

  1. static void __pass_event(struct evdev_client *client,
  2. const struct input_event *event)
  3. {
  4. client->buffer[client->head++] = *event;
  5. client->head &= client->bufsize - 1;
  6. if (unlikely(client->head == client->tail)) {
  7. /*
  8. * This effectively "drops" all unconsumed events, leaving
  9. * EV_SYN/SYN_DROPPED plus the newest event in the queue.
  10. */
  11. client->tail = (client->head - 2) & (client->bufsize - 1);
  12. client->buffer[client->tail].time = event->time;
  13. client->buffer[client->tail].type = EV_SYN;
  14. client->buffer[client->tail].code = SYN_DROPPED;
  15. client->buffer[client->tail].value = 0;
  16. client->packet_head = client->tail;
  17. if (client->use_wake_lock)
  18. wake_unlock(&client->wake_lock);
  19. }
  20. if (event->type == EV_SYN && event->code == SYN_REPORT) {
  21. client->packet_head = client->head;
  22. if (client->use_wake_lock)
  23. wake_lock(&client->wake_lock);
  24. kill_fasync(&client->fasync, SIGIO, POLL_IN);
  25. }
  26. }
  1.  
    static void __pass_event(struct evdev_client *client,
  2.  
    const struct input_event *event)
  3.  
    {
  4.  
    client->buffer[client->head++] = *event;
  5.  
    client->head &= client->bufsize - 1;
  6.  
     
  7.  
    if (unlikely(client->head == client->tail)) {
  8.  
    /*
  9.  
    * This effectively "drops" all unconsumed events, leaving
  10.  
    * EV_SYN/SYN_DROPPED plus the newest event in the queue.
  11.  
    */
  12.  
    client->tail = (client->head - 2) & (client->bufsize - 1);
  13.  
     
  14.  
    client->buffer[client->tail].time = event->time;
  15.  
    client->buffer[client->tail].type = EV_SYN;
  16.  
    client->buffer[client->tail].code = SYN_DROPPED;
  17.  
    client->buffer[client->tail].value = 0;
  18.  
     
  19.  
    client->packet_head = client->tail;
  20.  
    if (client->use_wake_lock)
  21.  
    wake_unlock(&client->wake_lock);
  22.  
    }
  23.  
     
  24.  
    if (event->type == EV_SYN && event->code == SYN_REPORT) {
  25.  
    client->packet_head = client->head;
  26.  
    if (client->use_wake_lock)
  27.  
    wake_lock(&client->wake_lock);
  28.  
    kill_fasync(&client->fasync, SIGIO, POLL_IN);
  29.  
    }
  30.  
    }

client中一些字段的含义:
  packet_head:一个数据包头;
  head:动态索引,每加入一个event到buffer中,head++;
  tail:也是动态索引,每取出一个buffer中的event,tail++;
  buffer:event存储器,是一个环形区域。
  __pass_event会把数据放到client->buffer中。
  个人猜想:client->bufsize是一个2的次幂值,client->head &= client->bufsize - 1是为防止溢出,client->head == client->tail时,说明用户读的太快了,读的也是无效的。如果收到SYNC说明一个包结束了,更新一个包头packet_head,再上个锁wake_lock(&client->wake_lock);,这把锁在用户读取的时候会打开;向内核发送SIGIO,POLL_IN表示可读。
  事件的传递过程:首先在驱动层调用inport_report_abs,然后调用input core层的input_event,input_event调用了input_handle_event对事件进行分派,调用input_pass_event,在这里他会把事件传递给具体的handler层,然后在相应handler的event处理函数中,封装一个event,然后把它投入evdev的那个client_list上的client的事件buffer中,等待用户空间来读取。

二 用户空间获取跟踪

  1. static const struct file_operations evdev_fops = {
  2. .owner      = THIS_MODULE,
  3. .read       = evdev_read,
  4. .write      = evdev_write,
  5. .poll       = evdev_poll,
  6. .open       = evdev_open,
  7. .release    = evdev_release,
  8. .unlocked_ioctl = evdev_ioctl,
  9. #ifdef CONFIG_COMPAT
  10. .compat_ioctl   = evdev_ioctl_compat,
  11. #endif
  12. .fasync     = evdev_fasync,
  13. .flush      = evdev_flush,
  14. .llseek     = no_llseek,
  15. };
  1.  
    static const struct file_operations evdev_fops = {
  2.  
    .owner = THIS_MODULE,
  3.  
    .read = evdev_read,
  4.  
    .write = evdev_write,
  5.  
    .poll = evdev_poll,
  6.  
    .open = evdev_open,
  7.  
    .release = evdev_release,
  8.  
    .unlocked_ioctl = evdev_ioctl,
  9.  
    #ifdef CONFIG_COMPAT
  10.  
    .compat_ioctl = evdev_ioctl_compat,
  11.  
    #endif
  12.  
    .fasync = evdev_fasync,
  13.  
    .flush = evdev_flush,
  14.  
    .llseek = no_llseek,
  15.  
    };
  evdev_connect()的时候,cdev_init(&evdev->cdev, &evdev_fops);初始化了eventx字符设备的操作函数集。
  1. static int evdev_open(struct inode *inode, struct file *file)
  2. {
  3. struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
  4. unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
  5. struct evdev_client *client;
  6. int error;
  7. client = kzalloc(sizeof(struct evdev_client) +
  8. bufsize * sizeof(struct input_event),
  9. GFP_KERNEL);
  10. if (!client)
  11. return -ENOMEM;
  12. client->bufsize = bufsize;
  13. spin_lock_init(&client->buffer_lock);
  14. snprintf(client->name, sizeof(client->name), "%s-%d",
  15. dev_name(&evdev->dev), task_tgid_vnr(current));
  16. client->evdev = evdev;
  17. evdev_attach_client(evdev, client);
  18. error = evdev_open_device(evdev);
  19. if (error)
  20. goto err_free_client;
  21. file->private_data = client;
  22. nonseekable_open(inode, file);
  23. return 0;
  24. err_free_client:
  25. evdev_detach_client(evdev, client);
  26. kfree(client);
  27. return error;
  28. }
  1.  
    static int evdev_open(struct inode *inode, struct file *file)
  2.  
    {
  3.  
    struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
  4.  
    unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
  5.  
    struct evdev_client *client;
  6.  
    int error;
  7.  
     
  8.  
    client = kzalloc(sizeof(struct evdev_client) +
  9.  
    bufsize * sizeof(struct input_event),
  10.  
    GFP_KERNEL);
  11.  
    if (!client)
  12.  
    return -ENOMEM;
  13.  
     
  14.  
    client->bufsize = bufsize;
  15.  
    spin_lock_init(&client->buffer_lock);
  16.  
    snprintf(client->name, sizeof(client->name), "%s-%d",
  17.  
    dev_name(&evdev->dev), task_tgid_vnr(current));
  18.  
    client->evdev = evdev;
  19.  
    evdev_attach_client(evdev, client);
  20.  
     
  21.  
    error = evdev_open_device(evdev);
  22.  
    if (error)
  23.  
    goto err_free_client;
  24.  
     
  25.  
    file->private_data = client;
  26.  
    nonseekable_open(inode, file);
  27.  
     
  28.  
    return 0;
  29.  
     
  30.  
    err_free_client:
  31.  
    evdev_detach_client(evdev, client);
  32.  
    kfree(client);
  33.  
    return error;
  34.  
    }

  evdev结构是怎么找到的?已知该结构中的cdev指针,找到这个结构;说明初始化evdev的时候,evdev->cdev就对应这个eventx;这也是connect做的事情。bufsize就是max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS, EVDEV_MIN_BUFFER_SIZE);之后转化成2的次幂。终于看到client登场了。evdev_attach_client()->list_add_tail_rcu(&client->node, &evdev->client_list);把自己挂到了evdev->client_list上。这样,pass event的时候才能找到对应的client。

  1. static int evdev_open_device(struct evdev *evdev)
  2. {
  3. int retval;
  4. retval = mutex_lock_interruptible(&evdev->mutex);
  5. if (retval)
  6. return retval;
  7. if (!evdev->exist)
  8. retval = -ENODEV;
  9. else if (!evdev->open++) {
  10. retval = input_open_device(&evdev->handle);
  11. if (retval)
  12. evdev->open--;
  13. }
  14. mutex_unlock(&evdev->mutex);
  15. return retval;
  16. }
  1.  
    static int evdev_open_device(struct evdev *evdev)
  2.  
    {
  3.  
    int retval;
  4.  
     
  5.  
    retval = mutex_lock_interruptible(&evdev->mutex);
  6.  
    if (retval)
  7.  
    return retval;
  8.  
     
  9.  
    if (!evdev->exist)
  10.  
    retval = -ENODEV;
  11.  
    else if (!evdev->open++) {
  12.  
    retval = input_open_device(&evdev->handle);
  13.  
    if (retval)
  14.  
    evdev->open--;
  15.  
    }
  16.  
     
  17.  
    mutex_unlock(&evdev->mutex);
  18.  
    return retval;
  19.  
    }

  显然evdev->exist = true;也是connect时候做的事情。如果open成功会更新evdev->open计数。

  1. int input_open_device(struct input_handle *handle)
  2. {
  3. struct input_dev *dev = handle->dev;
  4. int retval;
  5. retval = mutex_lock_interruptible(&dev->mutex);
  6. if (retval)
  7. return retval;
  8. if (dev->going_away) {
  9. retval = -ENODEV;
  10. goto out;
  11. }
  12. handle->open++;
  13. if (!dev->users++ && dev->open)
  14. retval = dev->open(dev);
  15. if (retval) {
  16. dev->users--;
  17. if (!--handle->open) {
  18. /*
  19. * Make sure we are not delivering any more events
  20. * through this handle
  21. */
  22. synchronize_rcu();
  23. }
  24. }
  25. out:
  26. mutex_unlock(&dev->mutex);
  27. return retval;
  28. }
  1.  
    int input_open_device(struct input_handle *handle)
  2.  
    {
  3.  
    struct input_dev *dev = handle->dev;
  4.  
    int retval;
  5.  
     
  6.  
    retval = mutex_lock_interruptible(&dev->mutex);
  7.  
    if (retval)
  8.  
    return retval;
  9.  
     
  10.  
    if (dev->going_away) {
  11.  
    retval = -ENODEV;
  12.  
    goto out;
  13.  
    }
  14.  
     
  15.  
    handle->open++;
  16.  
     
  17.  
    if (!dev->users++ && dev->open)
  18.  
    retval = dev->open(dev);
  19.  
     
  20.  
    if (retval) {
  21.  
    dev->users--;
  22.  
    if (!--handle->open) {
  23.  
    /*
  24.  
    * Make sure we are not delivering any more events
  25.  
    * through this handle
  26.  
    */
  27.  
    synchronize_rcu();
  28.  
    }
  29.  
    }
  30.  
     
  31.  
    out:
  32.  
    mutex_unlock(&dev->mutex);
  33.  
    return retval;
  34.  
    }
  回到了核心层,主要是更新handle->open和dev->users计数,成功open返回0,一层一层的返回0,返回到evdev_open()中file->private_data = client;猜测是为了read的时候找到这个client。
  1. static ssize_t evdev_read(struct file *file, char __user *buffer,
  2. size_t count, loff_t *ppos)
  3. {
  4. struct evdev_client *client = file->private_data;
  5. struct evdev *evdev = client->evdev;
  6. struct input_event event;
  7. size_t read = 0;
  8. int error;
  9. if (count != 0 && count < input_event_size())
  10. return -EINVAL;
  11. for (;;) {
  12. if (!evdev->exist)
  13. return -ENODEV;
  14. if (client->packet_head == client->tail &&
  15. (file->f_flags & O_NONBLOCK))
  16. return -EAGAIN;
  17. /*
  18. * count == 0 is special - no IO is done but we check
  19. * for error conditions (see above).
  20. */
  21. if (count == 0)
  22. break;
  23. while (read + input_event_size() <= count &&
  24. evdev_fetch_next_event(client, &event)) {
  25. if (input_event_to_user(buffer + read, &event))
  26. return -EFAULT;
  27. read += input_event_size();
  28. }
  29. if (read)
  30. break;
  31. if (!(file->f_flags & O_NONBLOCK)) {
  32. error = wait_event_interruptible(evdev->wait,
  33. client->packet_head != client->tail ||
  34. !evdev->exist);
  35. if (error)
  36. return error;
  37. }
  38. }
  39. return read;
  40. }
  1.  
    static ssize_t evdev_read(struct file *file, char __user *buffer,
  2.  
    size_t count, loff_t *ppos)
  3.  
    {
  4.  
    struct evdev_client *client = file->private_data;
  5.  
    struct evdev *evdev = client->evdev;
  6.  
    struct input_event event;
  7.  
    size_t read = 0;
  8.  
    int error;
  9.  
     
  10.  
    if (count != 0 && count < input_event_size())
  11.  
    return -EINVAL;
  12.  
     
  13.  
    for (;;) {
  14.  
    if (!evdev->exist)
  15.  
    return -ENODEV;
  16.  
     
  17.  
    if (client->packet_head == client->tail &&
  18.  
    (file->f_flags & O_NONBLOCK))
  19.  
    return -EAGAIN;
  20.  
     
  21.  
    /*
  22.  
    * count == 0 is special - no IO is done but we check
  23.  
    * for error conditions (see above).
  24.  
    */
  25.  
    if (count == 0)
  26.  
    break;
  27.  
     
  28.  
    while (read + input_event_size() <= count &&
  29.  
    evdev_fetch_next_event(client, &event)) {
  30.  
     
  31.  
    if (input_event_to_user(buffer + read, &event))
  32.  
    return -EFAULT;
  33.  
     
  34.  
    read += input_event_size();
  35.  
    }
  36.  
     
  37.  
    if (read)
  38.  
    break;
  39.  
     
  40.  
    if (!(file->f_flags & O_NONBLOCK)) {
  41.  
    error = wait_event_interruptible(evdev->wait,
  42.  
    client->packet_head != client->tail ||
  43.  
    !evdev->exist);
  44.  
    if (error)
  45.  
    return error;
  46.  
    }
  47.  
    }
  48.  
     
  49.  
    return read;
  50.  
    }

  果然第一件事就是找到evdev_client;就是evdev_open的时候记录的。*evdev = client->evdev也是evdev_open的时候记录的。input_event_size()是一个event的最小size,是input_event_compat或input_event结构的size,小于这个size的read操作无需理会。用了一个for循环,如果没有读到数据open的时候file->f_flags & O_NONBLOCK以非阻塞方式open会调用wait_event_interruptible()会阻塞到这里,等到client中有数据会唤醒它,前面已经说过了。如果evdev_open成功,evdev->exist会设置就继续走。一直走到了一个while循环,evdev_fetch_next_event()是从client中取出event。

  1. static int evdev_fetch_next_event(struct evdev_client *client,
  2. struct input_event *event)
  3. {
  4. int have_event;
  5. spin_lock_irq(&client->buffer_lock);
  6. have_event = client->packet_head != client->tail;
  7. if (have_event) {
  8. *event = client->buffer[client->tail++];
  9. client->tail &= client->bufsize - 1;
  10. if (client->use_wake_lock &&
  11. client->packet_head == client->tail)
  12. wake_unlock(&client->wake_lock);
  13. }
  14. spin_unlock_irq(&client->buffer_lock);
  15. return have_event;
  16. }
  1.  
    static int evdev_fetch_next_event(struct evdev_client *client,
  2.  
    struct input_event *event)
  3.  
    {
  4.  
    int have_event;
  5.  
     
  6.  
    spin_lock_irq(&client->buffer_lock);
  7.  
     
  8.  
    have_event = client->packet_head != client->tail;
  9.  
    if (have_event) {
  10.  
    *event = client->buffer[client->tail++];
  11.  
    client->tail &= client->bufsize - 1;
  12.  
    if (client->use_wake_lock &&
  13.  
    client->packet_head == client->tail)
  14.  
    wake_unlock(&client->wake_lock);
  15.  
    }
  16.  
     
  17.  
    spin_unlock_irq(&client->buffer_lock);
  18.  
     
  19.  
    return have_event;
  20.  
    }

  如果packet_head和tail不等,说明循环buffer里有数据,直接取出来,别忘了更新动态索引client->tail++。如果首尾相接了,说明数据读完了。wake_unlock(&client->wake_lock);;因为_pass_event中添加_event的时候上了一把锁wake_lock(&client->wake_lock);。
  接着evdev_read,已经取到event,就可以送到用户空间了。input_event_to_user()也是通过copy_to_user()实现的,这个函数很眼熟啊。一直read到读够了count个数据或者读完了一个包,client->packet_head == client->tail就表示这个包读完了。如果两个进程打开同一个文件,每个进程在open时都会生成一个evdev_client,evdev_client被挂在evdev的client_list上,在handle收到一个事件的时候,会把事件copy到挂在client_list上的所有evdev_client的buffer中。这样所有打开同一个设备的进程都会收到这个消息而唤醒。

 

input子系统四 input事件处理【转】的更多相关文章

  1. linux input输入子系统分析《四》:input子系统整体流程全面分析

    1      input输入子系统整体流程 本节分析input子系统在内核中的实现,包括输入子系统(Input Core),事件处理层(Event Handler)和设备驱动层.由于上节代码讲解了设备 ...

  2. input子系统分析

    ------------------------------------------ 本文系本站原创,欢迎转载! 转载请注明出处:http://ericxiao.cublog.cn/ -------- ...

  3. Linux input子系统简介

    1.前言 本文主要对Linux下的input子系统进行介绍 2. 软件架构 图 input子系统结构图 input子系统主要包括三个部分:设备驱动层.核心层和事件层.我们可以分别理解为:具体的输入设备 ...

  4. 【驱动】input子系统整体流程全面分析(触摸屏驱动为例)【转】

    转自:http://www.cnblogs.com/lcw/p/3294356.html input输入子系统整体流程 input子系统在内核中的实现,包括输入子系统(Input Core),事件处理 ...

  5. Linux--内核Uevent事件机制 与 Input子系统【转】

    转自:http://blog.csdn.net/lxl584685501/article/details/46379453 [-] 一Uevent机制 Uevent在kernel中的位置 Uevent ...

  6. input子系统驱动学习之中的一个

        刚開始学习linux这门课就被分配编写一个设备的input子系统驱动.这对我的确有点困难.只是实际的操作中发现困难远比我想象的要大的多.本以为依照老师课上的步骤就行非常快的完毕这项任务.后来发 ...

  7. linux输入子系统(input subsystem)之evdev.c事件处理过程

    1.代码 input_subsys.drv.c 在linux输入子系统(input subsystem)之按键输入和LED控制的基础上有小改动,input_subsys_test.c不变. input ...

  8. input子系统事件处理层(evdev)的环形缓冲区【转】

    在事件处理层(evdev.c)中结构体evdev_client定义了一个环形缓冲区(circular buffer),其原理是用数组的方式实现了一个先进先出的循环队列(circular queue), ...

  9. Linux input子系统分析

    输入输出是用户和产品交互的手段,因此输入驱动开发在Linux驱动开发中很常见.同时,input子系统的分层架构思想在Linux驱动设计中极具代表性和先进性,因此对Linux input子系统进行深入分 ...

随机推荐

  1. 系统设计与分析:Alpha版本2成绩汇总

    作业要求 1.作业内容 作业具体要求以及评分标准 2.评分细则 •给出开头和团队成员列表(10’) •给出发布地址以及安装手册(20’) •给出测试报告(40’) •给出项目情况总结(30’)   * ...

  2. python的pip安装时,使用国内Pypi源

    有时,国外的网速确实不理想. 想安装python库,还是国内快点. 参考URL: http://www.mamicode.com/info-detail-2248964.html 阿里云 http:/ ...

  3. while语句 break和continue

    1.whlie 循环 基本条件 :while 条件: 代码块(循环体) else: 当上面的条件为假的,才会执行 执行顺序: 判断条件是否为真,如果为真,执行循环体,然后判断条件,...直到循环条件为 ...

  4. [C2W3] Improving Deep Neural Networks : Hyperparameter tuning, Batch Normalization and Programming Frameworks

    第三周:Hyperparameter tuning, Batch Normalization and Programming Frameworks 调试处理(Tuning process) 目前为止, ...

  5. lua 4 使用table实现其他数据结构,并介绍遍历方法

    本文会以vector / map / set 这三种数据类型的角度来梳理 table 支持的不同遍历方式. table as std::vector 一般,C/C++中的 array / vector ...

  6. Appium自动化WebView中元素的操作

    在App开发过程中,很容易用到第三方的WebView控件,这个属于移动端混合型App.在我们做自动化测试的过程中,就要对这种情况进行处理,最通用的办法就是先将appium切换到webview模式然后按 ...

  7. Django CSRF

    CSRF(Cross-site request forgery)跨站请求伪造 django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewM ...

  8. SpringCloud微服务常见组件理解

    概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓 ...

  9. 使用system V实现读者写者问题

    #include <stdio.h> #include <sys/sem.h> #include <sys/ipc.h> #include <string.h ...

  10. mysqldump导表

    mysqldump全量导表 mysqldump -hlocalhost -uroot -P3306 -p --skip-add-locks --skip-triggers test > test ...