精华内容
下载资源
问答
  • input子系统

    2016-05-07 10:39:31
    input子系统
  • Input子系统

    2013-05-07 23:16:12
    Input子系统处理输入事务,任何输入设备的驱动程序都可以通过Input输入子系统提供的接口注册到内核,利用子系统提供的功能来与用户空间交互。输 入设备一般包括键盘,鼠标,触摸屏等,在内核中都是以输入设备出现的...
    Input子系统处理输入事务,任何输入设备的驱动程序都可以通过Input输入子系统提供的接口注册到内核,利用子系统提供的功能来与用户空间交互。输 入设备一般包括键盘,鼠标,触摸屏等,在内核中都是以输入设备出现的。下面分析input输入子系统的结构,以及功能实现。
    一. Input子系统结构与功能实现
      1. Input子系统是分层结构的,总共分为三层: 硬件驱动层,子系统核心层,事件处理层。 
        (1)其中硬件驱动层负责操作具体的硬件设备,这层的代码是针对具体的驱动程序的,需要驱动程序的作者来编写。
        (2)子系统核心层是链接其他两个层之间的纽带与桥梁,向下提供驱动层的接口,向上提供事件处理层的接口。
        (3)事件处理层负责与用户程序打交道,将硬件驱动层传来的事件报告给用户程序。
      2. 各层之间通信的基本单位就是事件,任何一个输入设备的动作都可以抽象成一种事件,如键盘的按下,触摸屏的按下,鼠标的移动等。事件有三种属性:类型(type),编码(code),值(value),Input子系统支持的所有事件都定义在input.h中,包括所有支持的类型,所属类型支持的编码等。事件传送的方向是 硬件驱动层-->子系统核心-->事件处理层-->用户空间
      3. 以触摸屏为例说明输入子系统的工作流程:
         注:mini2440的触摸屏驱动所用驱动层对应的模块文件为:s3c2410_ts.c,事件处理层对应的模块文件为 evdev.c
        (1)s3c2410_ts模块初始化函数中将触摸屏注册到了输入子系统中,于此同时,注册函数在事件处理层链表中寻找事件处理器,这里找到的是 evdev,并且将驱动与事件处理器挂载。并且在/dev/input中生成设备文件event0,以后我们访问这个文件就会找的我们的触摸屏驱动程序。
        (2)应用程序打开设备文件/dev/input/event0,读取设备文件,调用evdev模块中read,如果没有事件进程就会睡眠。  
        (3)当触摸屏按下,驱动层通过子系统核心将事件(就是X,Y坐标),传给事件处理层也就是evdev,evdev唤醒睡眠的进程,将事件传给进程处理。

    二.主要input通用数据结构
      1.input_dev 这是input设备基本的设备结构,每个input驱动程序中都必须分配初始化这样一个结构,成员比较多 
        (1)有以下几个数组:

     

    1. unsigned long evbit[BITS_TO_LONGS(EV_CNT)];   //事件支持的类型  
    2.         // 下面是每种类型支持的编码  
    3.     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];   //按键    
    4.     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];     
    5.     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];   //绝对坐标,其中触摸屏驱动使用的就是这个  
    6.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];  
    7.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];  
    8.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];  
    9.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];  
    10.     unsigned long swbit[BITS_TO_LONGS(SW_CNT)];  

        evbit[BITS_TO_LONGS(EV_CNT)]; 这个数组以位掩码的形式,代表了这个设备支持的事件的类型。设置方式如:
        dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS)
        absbit[BITS_TO_LONGS(ABS_CNT)]; 这个数组也是以位掩码的形式,代表这个类型的事件支持的编码
        触摸屏驱动支持EV_ABS,所以要设置这个数组, 有一个专门设置这个数组的函数input_set_abs_params,代码如下:

    1. static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)  
    2. {  
    3.     dev->absmin[axis] = min;  
    4.     dev->absmax[axis] = max;  
    5.     dev->absfuzz[axis] = fuzz;  
    6.     dev->absflat[axis] = flat;  
    7.   
    8.     dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);  //填充了absbit这个数组  
    9. }  

       触摸屏驱动中是这样调用的
        input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);   //这个是设置ad转换的x坐标
        input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);   //这个是设置ad转换的y坐标
        input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0); //这个是设置触摸屏是否按下的标志
        设置ABS_X编码值范围为0-0x3ff,因为mini2440的AD转换出的数据最大为10位,所以不会超过0x3ff。

      (2) struct input_id id 成员
         这个是标识设备驱动特征的

     

    1. struct input_id {  
    2.     __u16 bustype;   //总线类型  
    3.     __u16 vendor;    //生产厂商  
    4.     __u16 product;   //产品类型  
    5.     __u16 version;   //版本  
    6.  };  

        如果需要特定的事件处理器来处理这个设备的话,这几个就非常重要,因为子系统核心是通过他们,将设备驱动与事件处理层联系起来的。但是因为触摸屏驱动所用的事件处理器为evdev,匹配所有,所有这个初始化
        也无关紧要。
      (3) 还有其他一些成员,也比较重要,但是驱动程序可以不用管,都是由子系统核心来处理的。
      (4) 可以看出input_dev 结构所属层为硬件驱动层,以后就用input_dev来表示输入设备。
      2. input_handler 这是事件处理器的数据结构,代表一个事件处理器
       (1)几个操作函数
        void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
        int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
        void (*disconnect)(struct input_handle *handle);
        void (*start)(struct input_handle *handle);
        event 函数是当事件处理器接收到了来自input设备传来的事件时调用的处理函数,负责处理事件,非常重要,在事件传递过程中会详细分析。
        connect 函数是当一个input设备模块注册到内核的时候调用的,将事件处理器与输入设备联系起来的函数,也就是将input_dev和input_handler配对的函数。
        disconnect 函数实现connect相反的功能。
        start 暂时没有发现有什么作用。
      (2) 两个id
        const struct input_device_id *id_table; //这个是事件处理器所支持的input设备
        const struct input_device_id *blacklist; //这个是事件处理器应该忽略的input设备
         这两个数组都会用在connect函数中,input_device_id结构与input_id结构类似,但是input_device_id有一个flag,用来让程序选择比较哪项,如:busytype,vendor还是其他。
       (3) 两个链表
        struct list_headh_list;  //这个链表用来链接他所支持的input_handle结构,input_dev与input_handler配对之后就会生成一个input_handle结构
        struct list_headnode;    //链接到input_handler_list,这个链表链接了所有注册到内核的事件处理器
       (4) 其他的成员一看代码就知道是什么意思,这里就不说明了。
      3.  input_handle 结构体代表一个成功配对的input_dev和input_handler

    1. struct input_handle {  
    2.     void *private;   //每个配对的事件处理器都会分配一个对应的设备结构,如evdev事件处理器的evdev结构,注意这个结构与设备驱动层的input_dev不同,初始化handle时,保存到这里。  
    3.     int open;        //打开标志,每个input_handle 打开后才能操作,这个一般通过事件处理器的open方法间接设置  
    4.     const char *name;   
    5.     struct input_dev *dev;  //关联的input_dev结构  
    6.     struct input_handler *handler; //关联的input_handler结构  
    7.     struct list_head    d_node;  //input_handle通过d_node连接到了input_dev上的h_list链表上  
    8.     struct list_head    h_node;  //input_handle通过h_node连接到了input_handler的h_list链表上  
    9. };  

      4. 三个数据结构之间的关系
         input_dev 是硬件驱动层,代表一个input设备
         input_handler 是事件处理层,代表一个事件处理器
         input_handle 个人认为属于核心层,代表一个配对的input设备与input事件处理器
         input_dev 通过全局的input_dev_list链接在一起。设备注册的时候实现这个操作。
         input_handler 通过全局的input_handler_list链接在一起。事件处理器注册的时候实现这个操作(事件处理器一般内核自带,一般不需要我们来写)

         input_hande 没有一个全局的链表,它注册的时候将自己分别挂在了input_dev 和 input_handler 的h_list上了。通过input_dev 和input_handler就可以找到input_handle 在设备注册和事件处理器, 注册的时候都要进行配对工作,配对后就会实现链接。通过input_handle也可以找到input_dev和 input_handler。

     

     

    linux input子系统分析--主要函数

     一. 各种注册函数

        因为分析一所讲的每种数据结构都代表一类对象,所以每种数据结构都会对应一个注册函数,他们都定义在子系统核心的input.c文件中。主要有三个注册函数
         input_register_device    向内核注册一个input设备
         input_register_handle    向内核注册一个handle结构
         input_register_handler   注册一个事件处理器
      1. input_register_device 注册一个input输入设备,这个注册函数在三个注册函数中是驱动程序唯一调用的。下面分析这个函数:

    1. int input_register_device(struct input_dev *dev)  
    2. {  
    3.     static atomic_t input_no = ATOMIC_INIT(0);    
    4.         //这个原子变量,代表总共注册的input设备,每注册一个加1,因为是静态变量,所以每次调用都不会清零的  
    5.     struct input_handler *handler;  
    6.     const char *path;  
    7.     int error;  
    8.   
    9.     __set_bit(EV_SYN, dev->evbit);  //EN_SYN 这个是设备都要支持的事件类型,所以要设置  
    10.   
    11.     /* 
    12.      * If delay and period are pre-set by the driver, then autorepeating 
    13.      * is handled by the driver itself and we don't do it in input.c. 
    14.      */  
    15.         // 这个内核定时器是为了重复按键而设置的  
    16.     init_timer(&dev->timer);  
    17.     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {  
    18.         dev->timer.data = (long) dev;  
    19.         dev->timer.function = input_repeat_key;  
    20.         dev->rep[REP_DELAY] = 250;  
    21.         dev->rep[REP_PERIOD] = 33;  
    22.         //如果没有定义有关重复按键的相关值,就用内核默认的  
    23.     }  
    24.   
    25.     if (!dev->getkeycode)  
    26.         dev->getkeycode = input_default_getkeycode;  
    27.     if (!dev->setkeycode)  
    28.         dev->setkeycode = input_default_setkeycode;  
    29.         //以上设置的默认函数由input核心提供  
    30.     dev_set_name(&dev->dev, "input%ld",  
    31.              (unsigned long) atomic_inc_return(&input_no) - 1);  
    32.         //设置input_dev中device的名字,这个名字会在/class/input中出现  
    33.     error = device_add(&dev->dev);  
    34.         //将device加入到linux设备模型中去  
    35.     if (error)  
    36.         return error;  
    37.   
    38.     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);  
    39.     printk(KERN_INFO "input: %s as %s\n",  
    40.         dev->name ? dev->name : "Unspecified device", path ? path : "N/A");  
    41.     kfree(path);  
    42.         //这个得到路径名称,并打印出来  
    43.     error = mutex_lock_interruptible(&input_mutex);  
    44.     if (error) {  
    45.         device_del(&dev->dev);  
    46.         return error;  
    47.     }  
    48.   
    49.     list_add_tail(&dev->node, &input_dev_list);  
    50.         // 将新分配的input设备连接到input_dev_list链表上  
    51.     list_for_each_entry(handler, &input_handler_list, node)  
    52.         input_attach_handler(dev, handler);  
    53.         //遍历input_handler_list链表,配对 input_dev 和 input_handler  
    54.         //input_attach_handler 这个函数是配对的关键,下面将详细分析  
    55.     input_wakeup_procfs_readers();  
    56.         // 和proc文件系统有关,暂时不考虑  
    57.     mutex_unlock(&input_mutex);  
    58.   
    59.     return 0;  
    60.    }  

       input_register_device完成的主要功能就是:初始化一些默认的值,将自己的device结构添加到linux设备模型当中,将 input_dev添加到input_dev_list链表中,然后寻找合适的handler与input_handler配对,配对的核心函数是 input_attach_handler。下面分析input_attach_handler函数:

    1. static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)  
    2. {  
    3.     const struct input_device_id *id;  
    4.     int error;  
    5.   
    6.     if (handler->blacklist && input_match_device(handler->blacklist, dev))  
    7.         return -ENODEV;  
    8.         //blacklist是handler因该忽略的input设备类型,如果应该忽略的input设备也配对上了,那就出错了  
    9.     id = input_match_device(handler->id_table, dev);  
    10.         //这个是主要的配对函数,主要比较id中的各项,下面详细分析  
    11.     if (!id)  
    12.         return -ENODEV;  
    13.   
    14.     error = handler->connect(handler, dev, id);  
    15.         //配对成功调用handler的connect函数,这个函数在事件处理器中定义,主要生成一个input_handle结构,并初始化,还生成一个事件处理器相关的设备结构,后面详细分析  
    16.     if (error && error != -ENODEV)  
    17.         printk(KERN_ERR  
    18.             "input: failed to attach handler %s to device %s, "  
    19.             "error: %d\n",  
    20.             handler->name, kobject_name(&dev->dev.kobj), error);  
    21.         //出错处理  
    22.     return error;  
    23.  }  

        input_attach_handler的主要功能就是调用了两个函数,一个input_match_device进行配对,一个connect处理配对成功后续工作。
       下面分析input_match_device函数:

    展开全文
  • Input 子系统

    2012-08-22 21:21:07
    Linux的input子系统提供了输入设备的驱动框架,比如鼠标、键盘、触摸屏等就属于输入设备。Linux中关于input子系统的文档在Documentation/input目录,input的核心代码在input.c和input.h中。 本文没有涉及input的...
    
    

    Linux的input子系统提供了输入设备的驱动框架,比如鼠标、键盘、触摸屏等就属于输入设备。Linux中关于input子系统的文档在Documentation/input目录,input的核心代码在input.c和input.h中。

    本文没有涉及input的一些细节实现,比如input_dev->grab,以及按键的定时事件等。

    1.     input_handle, input_handler, input_dev

    input_handle, input_handler, input_dev是input子系统中最重要的3个数据结构。

    l         input_handler用于上层应用获取输入事件。上层应用打开输入设备的设备节点,然后对节点进行读写操作以获得鼠标移动信息,或者键盘信息等等。这里对设备节点的文件操作函数就是由input_handler提供。

    l         input_dev代表的是具体的设备,比如鼠标、键盘等等。

    l         对于一台Linux电脑,可能会连着多个鼠标、多个键盘。每一个鼠标都能控制光标的运动,每一个键盘也都能正常使用。这在input子系统中,体现为一个input_handler关联多个input_dev,能够同时从多个input_dev获取输入消息。与此同时,linux中可能会有多个input_handler同时与一个input_dev关联,这样,应用程序通过任何一个input_handler,都可以获得例如鼠标、键盘等具体设备的输入信息。所以,input_dev和input_handler之间是多对多的关联关系,而这些关联就是由input_handle表示。

    1.1           handler与dev之间关联的建立

    input_handle中包含一个input_dev的指针,和一个input_handler的指针,所以能建立handler和dev之间的一个一对一的关联。在input_handler中,有一个链表h_list,指向和这个handler关联的所有input_handle,通过这些handle就可以找到与handler关联的所有dev。同样的,在input_dev中,也有一个链表h_list,指向与dev关联的所有input_handle,通过这些handle可以找到与dev相关的所有handler。通过这两个链表和input_handle,input_handler和input_dev之间建立了一个复杂的网状结构。

    那么,input_handler和input_dev之间建立关联的规则是什么?即在什么情况下需要建立关联,什么时候不需要建立关联?这就需要handler和dev之间有一个匹配机制。

    input_handler中有两个指针,id_table和blacklist,其中blacklist是黑名单,凡是与之匹配的dev都将被强制过滤;而与id_table中任意一项匹配的dev才能与handler建立关联。

           const struct input_device_id *id_table;

           const struct input_device_id *blacklist;

           struct input_device_id {

                  kernel_ulong_t flags;

                  __u16 bustype;

                  __u16 vendor;

                  __u16 product;

                  __u16 version;

                  kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];

                  kernel_ulong_t driver_info;

           };

    在这个结构体中,flags中包含一些掩码:

    #define INPUT_DEVICE_ID_MATCH_BUS 1

    #define INPUT_DEVICE_ID_MATCH_VENDOR       2

    #define INPUT_DEVICE_ID_MATCH_PRODUCT     4

    #define INPUT_DEVICE_ID_MATCH_VERSION      8

    这些掩码用来匹配bus类型、厂商、产品号、版本号等。如果选择不匹配这些信息,那么driver_info需要置位,以跳过flags的匹配过程。

    evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1]中包含支持的事件掩码。input子系统支持以下事件:

    #define EV_SYN                  0x00              // EV_SYN用于标记一系列输入的结束

    #define EV_KEY                  0x01              // 键盘输入

    #define EV_REL                   0x02              // 鼠标的相对位移

    #define EV_ABS                   0x03              // 触摸屏的绝对坐标

    #define EV_MSC                  0x04

    #define EV_SW                    0x05

    #define EV_LED                  0x11              // 比如键盘的LED控制

    #define EV_SND                  0x12

    #define EV_REP                   0x14

    #define EV_FF                     0x15

    #define EV_PWR                 0x16

    #define EV_FF_STATUS              0x17

    如果handler支持某一种事件,那么evbit的对应位会置位。如果evbit的某一位置位了,那么结构体中与具体事件对应的掩码数组就会有效。例如,EV_KEY置位了,那么对应的keybit数组就有效,该数组里面定义了handler支持的具体key的类型。如果handler和dev需要匹配,那么dev必须能支持所有handler支持的事件;但是,handler却不一定要处理所有dev能提供的事件。

    #define MATCH_BIT(bit, max) /

                  for (i = 0; i < BITS_TO_LONGS(max); i++) /

                         if ((id->bit[i] & dev->bit[i]) != id->bit[i]) /

                                break; /

                  if (i != BITS_TO_LONGS(max)) /

                         continue;

    关于匹配的具体过程,可以参考函数input_match_device。

    2.     input_dev

    所有的input_dev都是虚拟设备,其class名为”input”,class的登记函数:

           class_register(&input_class);

    所以,需要先注册一个物理设备,已此物理设备为父设备注册input_dev。

    2.1           input_dev的注册

    input_dev的注册由input_register_device函数完成。

    int input_register_device(struct input_dev *dev)

           __set_bit(EV_SYN, dev->evbit);   // 强制设置EV_SYN位

           // 初始化定时器,REP_DELAY是第一次延时的超时值,REP_PERIOD是第一次延时            // 之后的超时值

           init_timer(&dev->timer);

           if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {

                  dev->timer.data = (long) dev;

                  dev->timer.function = input_repeat_key;

                  dev->rep[REP_DELAY] = 250;

                  dev->rep[REP_PERIOD] = 33;

           }

           // 设置默认的get key和set key函数

           if (!dev->getkeycode)    dev->getkeycode = input_default_getkeycode;

           if (!dev->setkeycode)    dev->setkeycode = input_default_setkeycode;

           // 设置设备名称,然后注册设备

           snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),

                   "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);

           device_add(&dev->dev);

           list_add_tail(&dev->node, &input_dev_list);       // 将设备加入input_dev_list链表

           // 对每一个已注册的handler,调用input_attach_handler

           list_for_each_entry(handler, &input_handler_list, node)

                  input_attach_handler(dev, handler);      // 见下节

           // proc有关的操作

           input_wakeup_procfs_readers();

    3        input_handler

    struct input_handler {

           void *private;

           void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

           int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

           void (*disconnect)(struct input_handle *handle);

           void (*start)(struct input_handle *handle);

           const struct file_operations *fops;

           int minor;

           const char *name;

           const struct input_device_id *id_table;

           const struct input_device_id *blacklist;

           struct list_head       h_list;

           struct list_head       node;

    };

    3.1           input_handler的注册

    int input_register_handler(struct input_handler *handler)

           // 将fops域登记到全局变量input_table

           input_table[handler->minor >> 5] = handler;

           // 将handler登记到链表input_handler_list

           list_add_tail(&handler->node, &input_handler_list);

           // 遍历已经登记的dev,对每个dev调用input_attach_handler(chapter 2.2)

           list_for_each_entry(dev, &input_dev_list, node)

                  input_attach_handler(dev, handler);

           // proc有关的操作

           input_wakeup_procfs_readers();

    3.2           input_attach_handler

    static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)

           // 匹配黑名单,如果设备在handler的黑名单里,返回

           …

           // 匹配handler中的id_table,如果匹配,则需要建立handler与dev之间的关联,于              // 是调用handler->connect

    handler的connect函数中,会malloc一个handle,把handler和dev填到handle中对应的域,然后调用input_register_handle函数,以及input_open_file函数。

    4.   input_handle

    struct input_handle {

           void *private;

           int open;

           const char *name;                       // handle的名称

           struct input_dev *dev;                 // 关联的dev

           struct input_handler *handler;       // 关联的handler

           struct list_head       d_node;          // 通过这个域挂到dev的handle链表

           struct list_head       h_node;          // 通过这个域挂到handler的handle链表

    };

    4.1           input_handle的注册

    int input_register_handle(struct input_handle *handle);

    input_register_handle会在handler的connect函数中被调用,它会将handler挂到dev和handler的链表中。最后会调用handler->start函数。

    5.   设备层

    上层应用通过设备节点访问input子系统提供的服务,而input_handler为上层应用提供了接口,所以设备节点的文件访问函数理所当然由handler提供,这就是handler中的fops域。

     

    input子系统本身也提供了一组文件读写操作函数,input_fops。

           register_chrdev(INPUT_MAJOR, "input", &input_fops);

    这里的input_fops中仅包含open函数,open函数的作用是根据子设备号重新设置设备文件的file->f_op域(这个机制在LDD的书中有提及),被更新的fops保存在全局数组input_table中。

     

    在注册handler时,会将handler登记到一个全局数组input_table,具体代码在input_register_handler中:

           input_table[handler->minor >> 5] = handler;

    这个数组主要是保存了handler中的fops。另外,数组的下标是handler->minor >> 5,也就是说,一个handler可以占有32个子设备号(1 << 5)。

    6.   事件的传递

    input子系统的主要作用就是控制输入事件在handler和dev之间的传递。输入事件在input系统中的定义如下:

    struct input_event {

           struct timeval time;

           __u16 type;

           __u16 code;

           __s32 value;

    };

    input_dev可以通过函数input_event传递消息。

    void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

           // 加锁、消息检验等

           …

           input_handle_event(dev, type, code, value);

     

    void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

           判断消息是否需要传给handler和dev

           如果需要传给dev,调用dev->event(dev, type, code, value);  

           如果需要传给handler,调用input_pass_event(dev, type, code, value);

           input_pass_event遍历dev中所有handle列表,对每一个handle,调用event函数。

     

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,779
精华内容 1,511
关键字:

input子系统