现在的位置: 首页 > 综合 > 正文

个人分析:input结构分析_zzhere2007

2018年02月07日 ⁄ 综合 ⁄ 共 8088字 ⁄ 字号 评论关闭

在input系统中,先是下面这张图片

之后是这样图片,呵呵先熟悉一下环境,再介绍。

在input中有三个结构体要注意,如下

  1. 1.input_dev 这是input设备基本的设备结构,每个input驱动程序中都必须分配初始化这样一个结构,成员比较多   
  2. struct input_dev {   
  3.     const char *name;   
  4.     const char *phys;   
  5.     const char *uniq;   
  6.     struct input_id id;//与input_handler匹配用的id,包括   
  7.     /*struct input_id {  
  8.      __u16 bustype; //总线类型  
  9.      __u16 vendor; //生产厂商  
  10.      __u16 product; //产品类型  
  11.      __u16 version; //版本  
  12.          }; */  
  13.          /* 
  14.       #define EV_SYN 0x00 //同步事件 
  15.     #define EV_KEY 0x01 //绝对二进制值,如键盘或按钮 
  16.     #define EV_REL 0x02 //绝对结果,如鼠标设备 
  17.     #define EV_ABS 0x03 //绝对整数值,如操纵杆或书写板 
  18.     #define EV_MSC 0x04 //其它类 
  19.     #define EV_SW 0x05 //开关事件 
  20.     #define EV_LED 0x11 //LED或其它指示设备 
  21.     #define EV_SND 0x12 //声音输出,如蜂鸣器 
  22.     #define EV_REP 0x14 //允许按键自重复 
  23.     #define EV_FF 0x15 //力反馈 
  24.     #define EV_PWR 0x16 //电源管理事件 
  25.     */  
  26.     unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //设备支持的事件类型如上   
  27.     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按键事件支持的子事件类型   
  28.     unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相对坐标事件支持的子事件类型   
  29.     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对坐标事件支持的子事件类型   
  30.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];   
  31.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];   
  32.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];   
  33.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];   
  34.     unsigned long swbit[BITS_TO_LONGS(SW_CNT)];   
  35.     
  36.     unsigned int keycodemax;   
  37.     unsigned int keycodesize;   
  38.     void *keycode;   
  39.     int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);   
  40.     int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);   
  41.     
  42.     struct ff_device *ff;   
  43.     
  44.     unsigned int repeat_key; //最近一次的按键值   
  45.     struct timer_list timer;   
  46.     
  47.     int sync;   
  48.     
  49.     int abs[ABS_MAX + 1];   
  50.     int rep[REP_MAX + 1];   
  51.     
  52.     unsigned long key[BITS_TO_LONGS(KEY_CNT)];//反应设备当前的按键状态   
  53.     unsigned long led[BITS_TO_LONGS(LED_CNT)];//反应设备当前的led状态   
  54.     unsigned long snd[BITS_TO_LONGS(SND_CNT)];//反应设备当前的声音输入状态   
  55.     unsigned long sw[BITS_TO_LONGS(SW_CNT)]; //反应设备当前的开关状态   
  56.     
  57.     int absmax[ABS_MAX + 1];//来自绝对坐标事件的最大键值   
  58.     int absmin[ABS_MAX + 1];//来自绝对坐标事件的最小键值   
  59.     int absfuzz[ABS_MAX + 1];   
  60.     int absflat[ABS_MAX + 1];   
  61.     
  62.     int (*open)(struct input_dev *dev); //第一次打开设备时调用,初始化设备用   
  63.     void (*close)(struct input_dev *dev);//最后一个应用程序释放设备时用,关闭设备   
  64.     int (*flush)(struct input_dev *dev, struct file *file);   
  65.     /*用于处理传递给设备的事件,如LED事件和声音事件*/   
  66.     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);   
  67.     
  68.     struct input_handle *grab;//当前占有该设备的input_handle   
  69.     
  70.     spinlock_t event_lock;   
  71.     struct mutex mutex;   
  72.     
  73.     unsigned int users;//打开该设备的用户数量(input handlers)   
  74.     int going_away;   
  75.     
  76.     struct device dev;   
  77.     
  78.     struct list_head h_list;//该链表头用于链接此设备所关联的input_handle   
  79.     struct list_head node; //用于将此设备链接到input_dev_list   
  80. }  
  81.   
  82. 2. input_handler 这是事件处理器的数据结构,代表一个事件处理器  
  83. struct input_handler {   
  84.     void *private;   
  85.     /*event用于处理事件*/   
  86.     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);   
  87.     /*connect用于建立handler和device的联系*/   
  88.     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);   
  89.     /*disconnect用于解除handler和device的联系*/   
  90.     void (*disconnect)(struct input_handle *handle);   
  91.     void (*start)(struct input_handle *handle);   
  92.     const struct file_operations *fops;//handler的一些处理函数   
  93.     int minor;//次设备号   
  94.     const char *name;   
  95.     const struct input_device_id *id_table;//用于和device匹配 ,这个是事件处理器所支持的input设备  
  96.     const struct input_device_id *blacklist;//匹配黑名单,这个是事件处理器应该忽略的input设备   
  97.     struct list_head h_list;//这个链表用来链接他所支持的input_handle结构,input_dev与input_handler配对之后就会生成一个input_handle结构   
  98.     struct list_head node; //链接到input_handler_list,这个链表链接了所有注册到内核的事件处理器   
  99. };   
  100.   
  101. 3.input_handle 结构体代表一个成功配对的input_dev和input_handler  
  102. struct input_handle {   
  103.     void *private//每个配对的事件处理器都会分配一个对应的设备结构,如evdev事件处理器的evdev结构,注意这个结构与设备驱动层的input_dev不同,初始化handle时,保存到这里。   
  104.     int open; //打开标志,每个input_handle 打开后才能操作,这个一般通过事件处理器的open方法间接设置   
  105.     const char *name;   
  106.     struct input_dev *dev//关联的input_dev结构   
  107.     struct input_handler *handler; //关联的input_handler结构   
  108.     struct list_head d_node; //input_handle通过d_node连接到了input_dev上的h_list链表上   
  109.     struct list_head h_node; //input_handle通过h_node连接到了input_handler的h_list链表上   
  110. };   
  111.  

    1. 三个数据结构之间的关系  
    2. input_dev 是硬件驱动层,代表一个input设备  
    3. input_handler 是事件处理层,代表一个事件处理器  
    4. input_handle 个人认为属于核心层,代表一个配对的input设备与input事件处理器  
    5. input_dev 通过全局的input_dev_list链接在一起。设备注册的时候实现这个操作。  
    6. input_handler 通过全局的input_handler_list链接在一起。事件处理器注册的时候实现这个操作(事件处理器一般内核自带,一般不需要我们来写)  
    7. input_hande 没有一个全局的链表,它注册的时候将自己分别挂在了input_dev 和 input_handler 的h_list上了。通过input_dev 和input_handler就可以找到input_handle在设备注册和事件处理器,注册的时候都要进行配对工作,配对后就会实现链接。通过input_handle也可以找到input_dev和input_handler。  
    8.        
    9. 我们可以看到,input_device和input_handler中都有一个h_list,而input_handle拥有指向input_dev和input_handler的指针,也就是说input_handle是用来关联input_dev和input_handler的。  
    10. 那么为什么一个input_device和input_handler中拥有的是h_list而不是一个handle呢?因为一个device可能对应多个handler,而一个handler也不能只处理一个device,比如说一个鼠标,它可以对应even handler,也可以对应mouse handler,因此当其注册时与系统中的handler进行匹配,就有可能产生两个实例,一个是evdev,另一个是mousedev,而任何一个实例中都只有一个handle。至于以何种方式来传递事件,就由用户程序打开哪个实例来决定。后面一个情况很容易理解,一个事件驱动不能只为一个甚至一种设备服务,系统中可能有多种设备都能使用这类handler,比如event handler就可以匹配所有的设备。在input子系统中,有8种事件驱动,每种事件驱动最多可以对应32个设备,因此dev实例总数最多可以达到256个。
       

    注意: input_handle,才是使用的时候的核心



之后 继续介绍用户层使用的时候,在core里面的结构体

  1. 主要数据结构  
  2. (1) evdev设备结构  
  3. struct evdev {   
  4.     int exist;   
  5.     int open; //打开标志   
  6.     int minor; //次设备号   
  7.     struct input_handle handle//关联的input_handle   
  8.     wait_queue_head_t wait; //等待队列,当进程读取设备,而没有事件产生的时候,进程就会睡在其上面   
  9.     struct evdev_client *grab; //强制绑定的evdev_client结构,这个结构后面再分析   
  10.     struct list_head client_list; //evdev_client 链表,这说明一个evdev设备可以处理多个evdev_client,可以有多个进程访问evdev设备   
  11.     spinlock_t client_lock; /* protects client_list */   
  12.     struct mutex mutex;   
  13.     struct device dev; //device结构,说明这是一个设备结构   
  14. };   
  15. //evdev结构体在配对成功的时候生成,由handler->connect生成,对应设备文件为/class/input/event(n),如触摸屏驱动的event0,这个设备是用户空间要访问的设备,可以理解它是一个虚拟设备,因为没有对应的硬件,但是通过handle->dev 就可以找到input_dev结构,而它对应着触摸屏,设备文件为/class/input/input0。这个设备结构生成之后保存在evdev_table中,索引值是minor。  
  16.   
  17. (2)evdev用户端结构  
  18. struct evdev_client {   
  19.     struct input_event buffer[EVDEV_BUFFER_SIZE];//这个是一个input_event数据结构的数组,input_event代表一个事件,基本成员:类型(type),编码(code),值(value)   
  20.     int head; //针对buffer数组的索引   
  21.     int tail; //针对buffer数组的索引,当head与tail相等的时候,说明没有事件   
  22.     spinlock_t buffer_lock; /* protects access to buffer, head and tail */   
  23.     struct fasync_struct *fasync; //异步通知函数   
  24.     struct evdev *evdev; //evdev设备   
  25.     struct list_head node; // evdev_client 链表项   
  26. };   
  27. //这个结构在进程打开event0设备的时候调用evdev的open方法,在open中创建这个结构,并初始化。在关闭设备文件的时候释放这个结构。  
  28.   
  29. (3)input_event结构  
  30. struct input_event {   
  31.     struct timeval time; //事件发生的时间   
  32.     __u16 type; //事件类型   
  33.     __u16 code; //子事件   
  34.     __s32 value; //事件的value   
  35. };   
这个三个结构体的关系也和特殊:
evdev是在驱动创建的时候生成的,关键要看里面的struct input_handle handle;,在这里指定了这个结构体关联的驱动。也可以这样理解,有了它就有了驱动的数据和操作
evdev_client
这个结构体是在用户层调用和input核心里面的open函数的时候申请成功的,在close的时候会被释放。要注意里面的struct evdev *evdev;,
哈哈,明白了吧

input_event
这个结构体在evdev_client 里面,具体标示一个具体的事件


之后呢再介绍一个结构体,它是input核心跟用户层的ops,用户使用下面完成对input设备的读取

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

分析open:

evdev_open(struct inode *inode, struct file *file)
 ——>static int evdev_open_device(struct evdev *evdev) 
——>int input_open_device(struct input_handle *handle)
——>dev->open(dev); 

分析read:
ssize_t evdev_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos) 
——>wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist);
//等待数据 

当中断发生并有数据的时候,会调用事件处理,唤醒这个等待的


最后呢
看一下上面结构体evdev_client
evdev  里面的list_head
项,这里表示了一个驱动可以对应多个用户

抱歉!评论已关闭.