zoukankan      html  css  js  c++  java
  • linux键盘input_event浅析【转】

    转自:http://blog.csdn.net/tdstds/article/details/18710965

    input_event(mxckbd_dev, EV_KEY, mxckpd_keycodes[scancode], 0);

    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);
        }
    }

    ***********************************************************************************************
    static inline int is_event_supported(unsigned int code, unsigned long *bm, unsigned int max)
    {
        return code <= max && test_bit(code, bm);
    }

    static inline int test_bit(int nr, const volatile unsigned long *addr)
    {
        return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
    }
    ***********************************************************************************************
    void add_input_randomness(unsigned int type, unsigned int code, unsigned int value)
    {
        static unsigned char last_value;

        /* ignore autorepeat and the like */
        if (value == last_value)
            return;

        DEBUG_ENT("input event ");
        last_value = value;
        add_timer_randomness(&input_timer_state, (type << 4) ^ code ^ (code >> 4) ^ value);
    }

    ***********************************************************************************************
    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_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);
                    }
                    
                    // INPUT_PASS_TO_HANDLERS: 事件处理的方式是传递给事件处理器    
                    disposition = INPUT_PASS_TO_HANDLERS;
                }
                break;
            ...
        }

        if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
            dev->sync = 0;

        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);
    }

    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);
        
        //如果是绑定的handle,则调用绑定的handler->event函数
        if (handle)
            handle->handler->event(handle, type, code, value);
        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;
                        
                    // 调用相关的事件处理器的event函数,进行事件的处理  
                    handler->event(handle, type, code, value);

                }
                else if(handler->filter(handle, type, code, value))
                    filtered = true;
            }
        }

        rcu_read_unlock();
    }

    static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)  // evdev.c
    {
        struct evdev *evdev = handle->private;
        struct evdev_client *client;
        struct input_event event;
        struct timespec ts;

        ktime_get_ts(&ts);
        
        // 将传过来的事件,赋值给input_event结构   
        event.time.tv_sec = ts.tv_sec;
        event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
        event.type = type;
        event.code = code;
        event.value = value;

        rcu_read_lock();

        client = rcu_dereference(evdev->grab);
        if (client) // 如果evdev绑定了client那么,处理这个客户端,触摸屏驱动没有绑定   
            evdev_pass_event(client, &event);
        else // // 遍历client链表,调用evdev_pass_event函数   
            list_for_each_entry_rcu(client, &evdev->client_list, node) 
                evdev_pass_event(client, &event);

        rcu_read_unlock();

        wake_up_interruptible(&evdev->wait); //唤醒等待的进程     
    }

    // evdev_pass_event函数最终将事件传递给了用户端的client结构中的input_event数组中,只需将这个input_event数组
    // 复制给用户空间,进程就能收到触摸屏按下的信息了。具体处理由具体的应用程序来完成。
    static void evdev_pass_event(struct evdev_client *client, struct input_event *event)  // evdev.c
    {
        /*
         * Interrupts are disabled, just acquire the lock
         */
        spin_lock(&client->buffer_lock);
        client->buffer[client->head++] = *event; // 将事件赋值给客户端的input_event 数组
        client->head &= EVDEV_BUFFER_SIZE - 1;
        spin_unlock(&client->buffer_lock);

        if (event->type == EV_SYN)
            kill_fasync(&client->fasync, SIGIO, POLL_IN);
    }
    ***********************************************************************************************

  • 相关阅读:
    sysbench测试
    ab压力测试
    kubernetes之Pod水平自动伸缩(HPA)
    JAVA实现Excel批量导入
    Json对象转为实体对象
    Java Web用Freemarker生成带图片的Word文档
    Spring3 MVC 深入核心研究
    SpringMVC深度探险(四) —— SpringMVC核心配置文件详解
    SpringMVC深度探险(三) —— DispatcherServlet与初始化主线
    SpringMVC深度探险(二) —— SpringMVC概览
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5109128.html
Copyright © 2011-2022 走看看