zoukankan      html  css  js  c++  java
  • input子系统四 input事件处理【转】

    转自: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()。
    [cpp] view plain copy
     
     
    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. }  
    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是否支持,接着进入处理核心。

    [cpp] view plain copy
     
     
    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. }  
    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。需要说明的是下面一段:
    [cpp] view plain copy
     
     
    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);
    [cpp] view plain copy
     
     
    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. }  
    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()。
    [cpp] view plain copy
     
     
    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. }  
    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处理;前者是成批处理,后者是单一事件处理。
    [cpp] view plain copy
     
     
    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. }  
    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处理。
    [cpp] view plain copy
     
     
    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. }  
    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中有数据时来唤醒。
    [cpp] view plain copy
     
     
    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. }  
    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中,等待用户空间来读取。

    二 用户空间获取跟踪

    [cpp] view plain copy
     
     
    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字符设备的操作函数集。
    [cpp] view plain copy
     
     
    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. }  
    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。
    [cpp] view plain copy
     
     
    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. }  
    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计数。
    [cpp] view plain copy
     
     
    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. }  
    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。
    [cpp] view plain copy
     
     
    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. }  
    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。
    [cpp] view plain copy
     
     
    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. }  
    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中。这样所有打开同一个设备的进程都会收到这个消息而唤醒。
     
  • 相关阅读:
    时间加减天数
    时间加减秒数
    什么BOM?
    js 事件基础
    js 九九乘法
    CSS3 动画基础单词语法
    css3 3D转换 基础语法
    css3 2D 转换 基础语法
    js onchange案例
    js之冒泡排序
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/11007947.html
Copyright © 2011-2022 走看看