Linux input子系统分析---5、事件传递过程

来源:互联网 发布:小站雅思mac版 编辑:程序博客网 时间:2024/05/16 17:17
三. 事件传递过程(以s3c2410_ts为例)
   1. 事件产生
    当按下触摸屏时,进入触摸屏按下中断,开始ad转换,ad转换完成进入ad完成中断,在这个终端中将事件发送出去,调用
    input_report_abs(dev, ABS_X, xp);
    input_report_abs(dev, ABS_Y, yp); 这两个函数调用了 input_event(dev, EV_ABS, code, value)
    所有的事件报告函数都调用这个函数。
   2. 事件报告
   (1) input_event 函数分析,这个函数定义在input.c中
 
  1. void input_event(struct input_dev *dev,  
  2.          unsigned int type, unsigned int code, int value)  
  3. {  
  4.     unsigned long flags;  
  5.   
  6.   
  7.     if (is_event_supported(type, dev->evbit, EV_MAX)) {  
  8.         //判断是否支持此种事件类型和事件类型中的编码类型   
  9.         spin_lock_irqsave(&dev->event_lock, flags);  
  10.         add_input_randomness(type, code, value);  
  11.         //对系统随机熵池有贡献,因为这个也是一个随机过程   
  12.         input_handle_event(dev, type, code, value);  
  13.         //这个函数是事件处理的关键函数,下面详细分析   
  14.         spin_unlock_irqrestore(&dev->event_lock, flags);  
  15.     }  
  16. }   
   (2) input_handle_event 函数分析,这个函数定义在input.c中
 
  1. static void input_handle_event(struct input_dev *dev,  
  2.                    unsigned int type, unsigned int code, int value)  
  3. {  
  4.     int disposition = INPUT_IGNORE_EVENT;  
  5.   
  6.   
  7.     switch (type) {  
  8.         ......  
  9.     case EV_KEY:  
  10.         if (is_event_supported(code, dev->keybit, KEY_MAX) &&  
  11.             !!test_bit(code, dev->key) != value) {  
  12.   
  13.   
  14.             if (value != 2) {  
  15.                 __change_bit(code, dev->key);  
  16.                 if (value)  
  17.                     input_start_autorepeat(dev, code);  
  18.                 else  
  19.                     input_stop_autorepeat(dev);  
  20.             }  
  21.             disposition = INPUT_PASS_TO_HANDLERS;  
  22.         }  
  23.         break;  
  24.         ......  
  25.     if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)  
  26.         dev->sync = 0;  
  27.   
  28.   
  29.     if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)  
  30.         dev->event(dev, type, code, value);  
  31.   
  32.   
  33.     if (disposition & INPUT_PASS_TO_HANDLERS)  
  34.         input_pass_event(dev, type, code, value);  
  35. }  
   这个函数主要是根据事件类型的不同,做相应的处理。这里之关心EV_KEY类型,其他函数和事件传递关系不大,只要关心,disposition这个是事件处理的方式,默认的是INPUT_IGNORE_EVENT,忽略这个事件,如果是INPUT_PASS_TO_HANDLERS则是传递给事件处理器,如果是INPUT_PASS_TO_DEVICE,则是传递给设备处理,触摸屏驱动没有定义这个。下面分析input_pass_event函数。
 
  1. static void input_pass_event(struct input_dev *dev,  
  2.                  unsigned int type, unsigned int code, int value)  
  3. {  
  4.     struct input_handle *handle;  
  5.   
  6.   
  7.     rcu_read_lock();  
  8.   
  9.   
  10.     handle = rcu_dereference(dev->grab);  //如果是绑定的handle,则调用绑定的handler->event函数   
  11.     if (handle)  
  12.         handle->handler->event(handle, type, code, value);  
  13.     else  
  14.         //如果没有绑定,则遍历dev的h_list链表,寻找handle,如果handle已经打开,说明有进程读取设备关联的evdev。   
  15.         list_for_each_entry_rcu(handle, &dev->h_list, d_node)  
  16.             if (handle->open)  
  17.                 handle->handler->event(handle,  
  18.                             type, code, value);  
  19.         // 调用相关的事件处理器的event函数,进行事件的处理   
  20.     rcu_read_unlock();  
  21. }  
下面分析 evdev事件处理器的event函数
 
  1. static void evdev_event(struct input_handle *handle,  
  2.             unsigned int type, unsigned int code, int value)  
  3. {  
  4.     struct evdev *evdev = handle->private;  
  5.     struct evdev_client *client;  
  6.     struct input_event event;  
  7.   
  8.   
  9.     do_gettimeofday(&event.time);  
  10.     event.type = type;  
  11.     event.code = code;  
  12.     event.value = value;  
  13.         //将传过来的事件,赋值给input_event结构   
  14.     rcu_read_lock();  
  15.   
  16.   
  17.     client = rcu_dereference(evdev->grab);  
  18.         //如果evdev绑定了client那么,处理这个客户端,触摸屏驱动没有绑定   
  19.     if (client)  
  20.         evdev_pass_event(client, &event);  
  21.     else  
  22.         //遍历client链表,调用evdev_pass_event函数   
  23.         list_for_each_entry_rcu(client, &evdev->client_list, node)  
  24.             evdev_pass_event(client, &event);  
  25.   
  26.   
  27.     rcu_read_unlock();  
  28.   
  29.   
  30.     wake_up_interruptible(&evdev->wait); //唤醒等待的进程   
  31. }  
下面分析 evdev_pass_event 函数
 
  1. static void evdev_pass_event(struct evdev_client *client,  
  2.                  struct input_event *event)  
  3. {  
  4.     /* 
  5.      * Interrupts are disabled, just acquire the lock 
  6.      */  
  7.     spin_lock(&client->buffer_lock);  
  8.     client->buffer[client->head++] = *event;   //将事件赋值给客户端的input_event 数组   
  9.     client->head &= EVDEV_BUFFER_SIZE - 1;  
  10.     spin_unlock(&client->buffer_lock);  
  11.   
  12.   
  13.     kill_fasync(&client->fasync, SIGIO, POLL_IN);  
  14. }  

可以看出, evdev_pass_event函数最终将事件传递给了用户端的client结构中的input_event数组中,只需将这个input_event数组复制给用户空间,进程就能收到触摸屏按下的信息了。具体处理由具体的应用程序来完成。


转载:http://www.linuxidc.com/Linux/2011-09/43187p5.htm

原创粉丝点击