Chinaunix首页 | 论坛 | 博客
  • 博客访问: 290426
  • 博文数量: 47
  • 博客积分: 568
  • 博客等级: 下士
  • 技术积分: 543
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-05 12:51
文章分类

全部博文(47)

文章存档

2012年(47)

分类: LINUX

2012-04-14 12:17:07

   在Input子系统三层框架对应3个结构体,现在由下到上对三个层次的主要结构体进行分析。文本以触摸设备为例进行重点分析。
   1.驱动层中表示硬件的结构体struct input_dev.

点击(此处)折叠或打开

  1. struct input_dev {
  2.     const char *name;
  3.     const char *phys;
  4.     const char *uniq;
  5.     struct input_id id;//与handler进行匹配时,将此结构体与handler中的id_table和blacklist进行对比,对于触摸设备这个结构体设置无关紧要,其他设备的设置比较重要。

  6.     unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//输入设备支持的事件,对于一个事件有三种属性,分别为type、code、value。此位掩码的数组用于设置设备支持的类型。触摸屏设备需要设置
  7.     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//按键事件支持的事件码
  8.     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];//相对坐标事件支持的事件码
  9.     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//绝对坐标事件支持的事件码,触摸屏设备需要设置
  10.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];//杂项事件支持的事件码
  11.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];//LED事件支持的事件码
  12.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];//声音事件支持的事件码
  13.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];//压力事件支持的事件码
  14.     unsigned long swbit[BITS_TO_LONGS(SW_CNT)];//开关事件支持的事件码

  15.     unsigned int keycodemax;
  16.     unsigned int keycodesize;
  17.     void *keycode;
  18.     int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
  19.     int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
  20. struct ff_device *ff;

  21.     unsigned int repeat_key;
  22.     struct timer_list timer;

  23.     int sync;

  24.     int abs[ABS_MAX + 1];
  25.     int rep[REP_MAX + 1];

  26.     unsigned long key[BITS_TO_LONGS(KEY_CNT)];//按键事件的事件值
  27.     unsigned long led[BITS_TO_LONGS(LED_CNT)];//LED事件的事件值
  28.     unsigned long snd[BITS_TO_LONGS(SND_CNT)];//声音事件的事件值
  29.     unsigned long sw[BITS_TO_LONGS(SW_CNT)];//开关事件的事件值

  30.     int absmax[ABS_MAX + 1];//绝对坐标事件的最大事件值,上报坐标时触摸屏设备设置
  31.     int absmin[ABS_MAX + 1];];//绝对坐标事件的最大事件值,上报坐标时触摸屏设备设置
  32.     int absfuzz[ABS_MAX + 1];];//绝对坐标事件的噪声值,上报坐标时触摸屏设备设置
  33.     int absflat[ABS_MAX + 1];];//绝对坐标事件的中间平面位置值,joydev需要设置
  34.     int absres[ABS_MAX + 1];];


  35.     int (*open)(struct input_dev *dev);//上层调用input_open_device()时,底层调用此函数打开设备
  36.     void (*close)(struct input_dev *dev););//上层调用input_close_device()时,底层调用此函数关闭设备
  37.     int (*flush)(struct input_dev *dev, struct file *file);//清空设备。
  38.     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);//由上层handler传给底层需要处理的事件。

  39.     struct input_handle *grab;//绑定的handle

  40.     spinlock_t event_lock;
  41.     struct mutex mutex;

  42.     unsigned int users;
  43.     bool going_away;

  44.     struct device dev;//设备的抽象结构体,表示是一个设备

  45.     struct list_head    h_list;//与此设备相关的handle列表
  46.     struct list_head    node;// 在input_dev_list(全局结构体)中的节点
  47. };

    1.1在发生输入事件时,向子系统报告事件

    用于报告EV_KEY、EV_REL、EV_ABS等事件的函数有:

点击(此处)折叠或打开

  1. void input_report_key(struct input_dev *dev, unsigned int code, int value)
  2. void input_report_rel(struct input_dev *dev, unsigned int code, int value)
  3. void input_report_abs(struct input_dev *dev, unsigned int code, int value)

    触摸屏设备使用函数void input_report_abs(struct input_dev *dev, unsigned int code, int value)进行上报事件。
    比如,触摸屏驱动中是这样调用:

点击(此处)折叠或打开

  1. input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0)//这个是设置ad转换的x坐标
  2. input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0); //这个是设置ad转换的y坐标
  3. input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0); //这个是设置触摸屏是否按下的标志

   1.2、分配、注册、注销input设备

点击(此处)折叠或打开

  1. struct input_dev *input_allocate_device(void)
  2. int input_register_device(struct input_dev *dev)
  3. void input_unregister_device(struct input_dev *dev)

   2.核心层表示连接杆的结构体struct input_handle.

点击(此处)折叠或打开

  1. struct input_handle {
  2. void *private; //handle指定的私有数据,触摸设备为evdev
  3. int open; //打开与否的标志
  4. const char *name;
  5. struct input_dev *dev; //指向相关的底层设备
  6. struct input_handler *handler; //指向相关的上层时间处理器
  7. struct list_head d_node; //作为节点连接到input_dev的h_list链表上
  8. struct list_head h_node; //作为节点连接到handler的h_list链表上
  9. };
     结构体input_handle作为输入子系统的核心层体现在其成员的表示上。俩个节点d_node和h_node可以对下层和上层索引,俩个指针dev和handler表示指向相关的下层设备和上层事件处理设备。这样通过链表可以由上层找到底层,上层的open,close函数就要进行此类查找;底层要上报事件也是通过链表将事件传递给上层。
    3.事件处理层表示事件处理器的结构体struct input_handler.

点击(此处)折叠或打开

  1. struct input_handler {

  2.     void *private;//驱动指定的私有数据

  3.     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);//对handle传来的事件处理
  4.     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);//当handler与底层input_dev建立连接时调用
  5.     void (*disconnect)(struct input_handle *handle);//handler与底层input_dev解除连接时调用
  6.     void (*start)(struct input_handle *handle);//当建立连接后对于给定的handle启动handler

  7.     const struct file_operations *fops;//文件操作实现,open、read、write等
  8.     int minor;//次设备号
  9.     const char *name;

  10.     const struct input_device_id *id_table;//支持的设备表
  11.     const struct input_device_id *blacklist;//不支持是设备表

  12.     struct list_head    h_list;//相关的handle的链表
  13.     struct list_head    node;//作为节点,连接到input_handler_list(全局链表)链表上
  14. };
    3.1对于触摸设备需要struct input_handler evdev_handler.定义在evdev.c中

点击(此处)折叠或打开

  1. static struct input_handler evdev_handler = {
  2.     .event        = evdev_event,
  3.     .connect    = evdev_connect,
  4.     .disconnect    = evdev_disconnect,
  5.     .fops        = &evdev_fops,
  6.     .minor        = EVDEV_MINOR_BASE,
  7.     .name        = "evdev",
  8.     .id_table    = evdev_ids,
  9. };
   

点击(此处)折叠或打开

  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. };
    在注册handler时调用:
    input_register_handler(&evdev_handler);
    此函数调用evdev_connect函数生产struct evdev类型的设备,将其保持在evdev_table全局数组中,以次设备号为数组索引,open,read,write函数以此找到创建的设备。
    3.2对于触摸设备创建struct evdev类型的设备,用于设备模型的管理

点击(此处)折叠或打开

  1. struct evdev {
  2.     int exist;
  3.     int open;
  4.     int minor;
  5.     struct input_handle handle;//内嵌的handle
  6.     wait_queue_head_t wait;
  7.     struct evdev_client *grab;
  8.     struct list_head client_list;//连接的client,表示需要处理的事件队列
  9.     spinlock_t client_lock; /* protects client_list */
  10.     struct mutex mutex;
  11.     struct device dev;//表示是一个设备
  12. };

点击(此处)折叠或打开

  1. struct evdev_client {
  2.     struct input_event buffer[EVDEV_BUFFER_SIZE];//事件缓冲区
  3.     int head;
  4.     int tail;
  5.     spinlock_t buffer_lock; /* protects access to buffer, head and tail */
  6.     struct fasync_struct *fasync;
  7.     struct evdev *evdev;
  8.     struct list_head node;//作为节点连接到client_list链表中
  9.     struct wake_lock wake_lock;
  10.     char name[28];
  11. };

点击(此处)折叠或打开

  1. struct input_event {
  2.     struct timeval time;
  3.     __u16 type;//事件类型
  4.     __u16 code;//事件码
  5.     __s32 value;//事件码
  6. };
注:基于linux-kernel2.6.32
参考:linux内核input子系统解析.
linux输入子系统分析一.http://blog.chinaunix.net/uid-26620753-id-3132688.html




 

 


 

阅读(2363) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~