Android输入子系统浅析(一)

Linux输入子系统框架

1:Input输入子系统总体框架

    Linux内核的输入子系统是对分散的,多种不同类别的输入设备(如键盘,鼠标,触摸屏)等字符设备进行统一处理的一层抽象,就是在字符设备驱动上抽象出的一层。但是这些输入设备都各有不同,那么输入子系统也就只能实现他们的共性,差异性则由设备驱动来实现,而差异性最直观的表现在这些设备功能上的不同。但是,为了更好的理解Linux的输入子系统,我们有必要仔细研究下它的框架。

    Linux输入子系统将输入驱动抽象为三层:设备驱动层、核心层、事件处理层,其内在联系如下图所示:


下面先对这三个部分做一个简要的概括,后面的分析也是基于这三个部分:

        设备驱动层:主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层

        核心层:为设备驱动层提供了规范和接口。设备驱动层只关心如何驱动硬件并获得硬件数据,然后调用核心层提供的接口,核心层自动把数据提交给事件处理层

        事件处理层:是用户编程的接口(设备节点),并处理驱动层提交的数据处理

本篇博文所述均是基于linux 3.4.5内核,android 4.2.2版本,硬件平台基于MT6589平台.


2:Input子系统分层分析

        2.1:在分析这三部分之前,首先我们先看看input.h这个头文件,因为输入子系统的很多重要结构体都是在里面定义的。

        路径:kernel/include/linux/input.h

       重要结构体之input_dev:

  1. struct input_dev {
  2. const char *name; //设备名称
  3. const char *phys; //设备在系统的物理路径
  4. const char *uniq; //设备唯一识别符
  5. struct input_id id; //设备ID,包含总线ID(PCI,USB)、厂商ID,与input_handler匹配时用到
  6. unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; //bitmap of device properties and quirks
  7. unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //支持的所有 事件类型
  8. unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //支持的键盘事件
  9. unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //支持的鼠标相对值事件
  10. unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //支持的鼠标绝对值事件
  11. unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //支持的其他事件类型
  12. unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //支持的led灯事件
  13. unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //支持的声效事件
  14. unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //支持的力反馈事件
  15. unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //支持的开关事件
  16. unsigned int hint_events_per_packet;
  17. unsigned int keycodemax; //keycode表的大小
  18. unsigned int keycodesize; //keycode表中的元素个数
  19. void *keycode; //设备的键盘表
  20. //配置keycode表
  21. int (*setkeycode)(struct input_dev *dev,
  22. const struct input_keymap_entry *ke,
  23. unsigned int *old_keycode);
  24. //获取keycode表
  25. int (*getkeycode)(struct input_dev *dev,
  26. struct input_keymap_entry *ke);
  27. struct ff_device *ff;
  28. unsigned int repeat_key; //保存上一个键值
  29. struct timer_list timer; //定时器
  30. int rep[REP_CNT];
  31. struct input_mt_slot *mt;
  32. int mtsize;
  33. int slot;
  34. int trkid;
  35. struct input_absinfo *absinfo;
  36. unsigned long key[BITS_TO_LONGS(KEY_CNT)];
  37. unsigned long led[BITS_TO_LONGS(LED_CNT)];
  38. unsigned long snd[BITS_TO_LONGS(SND_CNT)];
  39. unsigned long sw[BITS_TO_LONGS(SW_CNT)];
  40. //操作接口
  41. int (*open)(struct input_dev *dev);
  42. void (*close)(struct input_dev *dev);
  43. int (*flush)(struct input_dev *dev, struct file *file);
  44. int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
  45. struct input_handle __rcu *grab; //当前使用的handle
  46. spinlock_t event_lock;
  47. struct mutex mutex;
  48. unsigned int users;
  49. bool going_away;
  50. bool sync;
  51. struct device dev;
  52. struct list_head h_list; //h_list是一个链表头,用来把handle挂载在这个上
  53. struct list_head node; //这个node是用来连到input_dev_list上的
  54. };

      重要结构体之input_handler:
  1. struct input_handler {
  2. void * private; //私有数据
  3. //操作接口
  4. void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
  5. bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
  6. bool (*match)(struct input_handler *handler, struct input_dev *dev);
  7. int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
  8. void (*disconnect)(struct input_handle *handle);
  9. void (*start)(struct input_handle *handle);
  10. const struct file_operations *fops;
  11. int minor; //次设备号
  12. const char *name;
  13. const struct input_device_id *id_table;
  14. struct list_head h_list; //h_list是一个链表头,用来把handle挂载在这个上
  15. struct list_head node; //这个node是用来连到input_handler_list上的
  16. };


重要结构体之input_handle

  1. struct input_handle {
  2. void * private; //私有数据
  3. int 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_dev的h_list
  8. struct list_head h_node; //连到input_handler的h_list
  9. };

重要结构体之evdev_client:

  1. /*在进程打开event设备的时候调用evdev的open方法,在open中创建和初始化*/
  2. struct evdev_client {
  3. unsigned int head; //针对buffer数组的索引
  4. unsigned int tail; //针对buffer数组的索引,当head和tail相等的时候,说明没事件
  5. unsigned int packet_head; /* [future] position of the first element of next packet */
  6. spinlock_t buffer_lock; /* protects access to buffer, head and tail */
  7. struct wake_lock wake_lock;
  8. bool use_wake_lock;
  9. char name[ 28];
  10. struct fasync_struct *fasync; //异步通知函数
  11. struct evdev *evdev; //evdev设备
  12. struct list_head node; //evdev_client链表项
  13. int clkid;
  14. unsigned int bufsize;
  15. struct input_event buffer[]; //一个input_event数据结构的数组,input_event代表一个事件
  16. };

重要结构体之evdev:

  1. <pre name= "code" class= "cpp"> /*evdev结构体在配对成功的时候生成,由handler_connect生成*/
  2. struct evdev {
  3. int open; //打开引用计数
  4. int minor; //次设备号
  5. struct input_handle handle; //关联的input_handle
  6. wait_queue_head_t wait; //等待队列
  7. struct evdev_client __rcu *grab;
  8. struct list_head client_list; //evdev_client链表,说明一个evdev设备可以处理多个evdev_client,可以有多个进程访问
  9. spinlock_t client_lock; /* protects client_list */
  10. struct mutex mutex;
  11. struct device dev;
  12. bool exist;
  13. };
 

 
 
另外,input.h中还定义了可以支持哪些事件类型,这些只是大类事件,每个事件下还有具体区分: 
 

  1. /*
  2. * Event types
  3. */
  4. #define EV_SYN 0x00 //同步时间
  5. #define EV_KEY 0x01 //绝对二进制值,如键盘或者按钮
  6. #define EV_REL 0x02 //绝对结果,如鼠标设备
  7. #define EV_ABS 0x03 //绝对整数值,如TP,操纵杆
  8. #define EV_MSC 0x04 //其他类
  9. #define EV_SW 0x05 //开关事件
  10. #define EV_LED 0x11 //led或其他指示设备
  11. #define EV_SND 0x12 //声音输出,如蜂鸣器
  12. #define EV_REP 0x14 //允许按键重复
  13. #define EV_FF 0x15 //力反馈
  14. #define EV_PWR 0x16 //电源管理
  15. #define EV_FF_STATUS 0x17
  16. #define EV_MAX 0x1f
  17. #define EV_CNT (EV_MAX+1)

2.2:input输入子系统的核心层input.c

路径:kernel/drivers/input/input.c

  1. //先分析入口函数:input_init(void)
  2. static int __ init input_init(void)
  3. {
  4. int err;
  5. //创建一个input_class类
  6. err = class_register(&input_class);
  7. if (err) {
  8. pr_err( "unable to register input_dev class\n");
  9. return err;
  10. }
  11. //在/proc下创建入口项
  12. err = input_proc_init();
  13. if (err)
  14. goto fail1;
  15. //注册主设备号为INPUT_MAJOR(13)的设备,并与input_fops关联
  16. err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
  17. if (err) {
  18. pr_err( "unable to register char major %d", INPUT_MAJOR);
  19. goto fail2;
  20. }
  21. return 0;
  22. fail2: input_proc_exit();
  23. fail1: class_unregister(&input_class);
  24. return err;
  25. }
下面继续看input子系统的关联的input_fops:
  1. static const struct file_operations input_fops = {
  2. .owner = THIS_MODULE,
  3. .open = input_open_file, //主要分析这个Open函数
  4. .llseek = noop_llseek,
  5. };
进入input_open_file函数体实现:
  1. static int input_open_file(struct inode *inode, struct file *file)
  2. {
  3. struct input_handler *handler;
  4. const struct file_operations *old_fops, *new_fops = NULL;
  5. //......省略部分内容
  6. //根据打开的文件次设备号来得到一个input_handler结构
  7. handler = input_table[iminor(inode) >> 5];
  8. //通过handler得到新的file_operations结构体
  9. if (handler)
  10. new_fops = fops_get(handler->fops);
  11. //......省略部分内容
  12. //保存文件之前的f_op
  13. old_fops = file->f_op;
  14. //将新的f_op赋值给当前文件的f_op
  15. file->f_op = new_fops;
  16. //调用open函数,当应用程序打开文件时会调用这个函数
  17. err = new_fops->open(inode, file);
  18. if (err) {
  19. fops_put(file->f_op);
  20. file->f_op = fops_get(old_fops);
  21. }
  22. fops_put(old_fops);
  23. }
上面的input_table是如何来的呢?下面我们来继续分析:
  1. static struct input_handler *input_table[8]; //定义
  2. int input_register_handler(struct input_handler *handler)
  3. {
  4. //......省略部分内容
  5. if (handler->fops != NULL) {
  6. if (input_table[handler->minor >> 5]) {
  7. retval = -EBUSY;
  8. goto out;
  9. }
  10. input_table[handler->minor >> 5] = handler;
  11. }
  12. //......省略部分内容
  13. }

    由上可知,input_table在input_register_handler()被赋值为handler。而input_register_handler()函数是在事件处理层中调用的,在2.3中我们会对其进行具体分析。当用户空间调用open时,实际上调用的就是handler fops中的open函数,而这个函数是在evdev.c中定义的,下面我们先看看这个open函数的实现(位于evdev.c中):

  1. static int evdev_open(struct inode *inode, struct file *file)
  2. {
  3. struct evdev *evdev;
  4. struct evdev_client *client;
  5. int i = iminor(inode) - EVDEV_MINOR_BASE;
  6. unsigned int bufsize;
  7. int error;
  8. if (i >= EVDEV_MINORS) //判断是否超出了能处理的最大设备数
  9. return -ENODEV;
  10. error = mutex_lock_interruptible(&evdev_table_mutex);
  11. if (error)
  12. return error;
  13. evdev = evdev_table[i]; //得到evdev设备结构,每次调用evdev_connect配对成功后都会把分配的evdev结构体以minor为索引保存在evdev_table中
  14. if (evdev)
  15. get_device(&evdev->dev); //增加device引用计数
  16. mutex_unlock(&evdev_table_mutex);
  17. if (!evdev)
  18. return -ENODEV;
  19. bufsize = evdev_compute_buffer_size(evdev->handle.dev);
  20. //分配用户端结构
  21. client = kzalloc( sizeof(struct evdev_client) +
  22. bufsize * sizeof(struct input_event),
  23. GFP_KERNEL);
  24. if (!client) {
  25. error = -ENOMEM;
  26. goto err_put_evdev;
  27. }
  28. client->bufsize = bufsize;
  29. spin_lock_init(&client->buffer_lock);
  30. snprintf(client->name, sizeof(client->name), "%s-%d",
  31. dev_name(&evdev->dev), task_tgid_vnr(current));
  32. client->evdev = evdev; //使用户端与evdev设备结构关联起来
  33. evdev_attach_client(evdev, client); //把client链接到evdev的client链表上
  34. error = evdev_open_device(evdev); //打开设备
  35. if (error)
  36. goto err_free_client;
  37. file->private_data = client;
  38. nonseekable_open(inode, file);
  39. return 0;
  40. err_free_client:
  41. evdev_detach_client(evdev, client);
  42. kfree(client);
  43. err_put_evdev:
  44. put_device(&evdev->dev);
  45. return error;
  46. }
再分析上面的evdev_open_device函数(位于evdev.c中):

  1. static int evdev_open_device(struct evdev *evdev)
  2. {
  3. int retval;
  4. retval = mutex_lock_interruptible(&evdev->mutex);
  5. if (retval)
  6. return retval;
  7. if (!evdev->exist) //判断evdev结构体是否存在,在evdev_conect中初始化成员为1
  8. retval = -ENODEV;
  9. else if (!evdev->open++) {
  10. retval = input_open_device(&evdev->handle); //打开设备
  11. if (retval)
  12. evdev->open--;
  13. }
  14. mutex_unlock(&evdev->mutex);
  15. return retval;
  16. }
上面的input_open_device函数(位于input.c)

  1. int input_open_device(struct input_handle *handle)
  2. {
  3. struct input_dev *dev = handle->dev;
  4. int retval;
  5. retval = mutex_lock_interruptible(&dev->mutex);
  6. if (retval)
  7. return retval;
  8. //判断设备是否在open期间被注销
  9. if (dev->going_away) {
  10. retval = -ENODEV;
  11. goto out;
  12. }
  13. handle->open++; //handle的打开计数加一
  14. if (!dev->users++ && dev->open) //如果输入设备没有进程引用,并定义了打开方法,就调用open方法
  15. retval = dev->open(dev);
  16. if (retval) { //如果没打开成功
  17. dev->users--;
  18. if (!--handle->open) { //说明有进程打开了这个handle
  19. /*
  20. * Make sure we are not delivering any more events
  21. * through this handle
  22. */
  23. synchronize_rcu();
  24. }
  25. }
  26. out:
  27. mutex_unlock(&dev->mutex);
  28. return retval;
  29. }

到这里,如果input_dev有定义open方法,打开函数最终会调用到input_dev下面的open函数,否者只是简单的增加打开引用计数。

2.3:input输入子系统的事件处理层

         这里我们以触摸屏的事件处理层代码进行分析,即:evdev.c  

         代码路径:kernel/drivers/input/evdev.c

  1. //先分析入口函数
  2. static int __ init evdev_init(void)
  3. {
  4. return input_register_handler(&evdev_handler); //此处调用input_register_handler(&evdev_handler);
  5. }
下面在具体看看int input_register_handler(struct input_handler *handler)函数(位于input.c中):

  1. int input_register_handler(struct input_handler *handler)
  2. {
  3. struct input_dev *dev;
  4. int retval;
  5. retval = mutex_lock_interruptible(&input_mutex);
  6. if (retval)
  7. return retval;
  8. //初始化handler的h_list
  9. INIT_LIST_HEAD(&handler->h_list);
  10. //根据handler的minor将handler放到相应的input_table位置中
  11. if (handler->fops != NULL) {
  12. if (input_table[handler->minor >> 5]) {
  13. retval = -EBUSY;
  14. goto out;
  15. }
  16. input_table[handler->minor >> 5] = handler;
  17. }
  18. //将handler通过node链接到input_handler_list链表中
  19. list_add_tail(&handler->node, &input_handler_list);
  20. //遍历input_dev_list链表,找出与这个handler匹配的input_dev,并和它connect,
  21. //匹配和connect的操作就是input_attach_handler所做的事情
  22. list_for_each_entry(dev, &input_dev_list, node)
  23. input_attach_handler(dev, handler);
  24. //唤醒input_devices_poll_wait的等待队列
  25. input_wakeup_procfs_readers();
  26. out:
  27. mutex_unlock(&input_mutex);
  28. return retval;
  29. }
  30. EXPORT_SYMBOL(input_register_handler);

在具体看下上面的input_attach_handler函数(位于 input.c中):
  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. //这个是主要的配对函数,主要比较id的各项
  6. id = input_match_device(handler, dev);
  7. if (!id)
  8. return -ENODEV;
  9. //配对成功调用handler的connect函数,这个函数在事件处理层
  10. //主要生成一个input_handle结构体,并初始化,还生成一个事件处理器相关的设备结构
  11. error = handler->connect(handler, dev, id);
  12. if (error && error != -ENODEV)
  13. pr_err( "failed to attach handler %s to device %s, error: %d\n",
  14. handler->name, kobject_name(&dev->dev.kobj), error);
  15. return error;
  16. }
由上面的input_attach_handler可知,其主要调用了input_match_device和handler->connect两个函数,下面继续分析这两个函数:

input_match_device函数(位于input.c里面):

  1. static const struct input_device_id *input_match_device(struct input_handler *handler,
  2. struct input_dev *dev)
  3. {
  4. const struct input_device_id *id;
  5. int i;
  6. //遍历handler的id_table与device进行匹配
  7. for (id = handler->id_table; id->flags || id->driver_info; id++) {
  8. //根据flags的标志位,按所需要匹配相应的字段
  9. if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
  10. if (id->bustype != dev->id.bustype) //总线类型不匹配
  11. continue;
  12. if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
  13. if (id->vendor != dev->id.vendor) //生产厂商不匹配
  14. continue;
  15. if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
  16. if (id->product != dev->id.product) //产品不匹配
  17. continue;
  18. if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) //版本不匹配
  19. if (id->version != dev->id.version)
  20. continue;
  21. MATCH_BIT(evbit, EV_MAX); //匹配所有的事件
  22. //下面匹配所有的子事件
  23. MATCH_BIT(keybit, KEY_MAX);
  24. MATCH_BIT(relbit, REL_MAX);
  25. MATCH_BIT(absbit, ABS_MAX);
  26. MATCH_BIT(mscbit, MSC_MAX);
  27. MATCH_BIT(ledbit, LED_MAX);
  28. MATCH_BIT(sndbit, SND_MAX);
  29. MATCH_BIT(ffbit, FF_MAX);
  30. MATCH_BIT(swbit, SW_MAX);
  31. //如果有定义handler->match则调用它
  32. //由于我们注册&evdev_handler时并没定义match函数,所以直接返回id
  33.   if (!handler->match || handler->match(handler, dev))
  34. return id;
  35. }
下面分析 handler->connect,这个函数在前面的模块入口函数input_register_handler(&evdev_handler)中的evdev_handler指定。

evdev_handler定义(位于evdev.c中):

  1. static struct input_handler evdev_handler = {
  2. .event = evdev_event,  //当有事件来的时候调用,把事件放入input_event数组,为用户空间读写事件做准备
  3. .connect = evdev_connect, //在input_dev和input_handler注册过程最终都会调用这个函数,完成handle的注册
  4. .disconnect = evdev_disconnect,  //在nput_dev和input_handler注销过程最终会调用这个函数,完成handle的注销
  5. .fops = &evdev_fops, //对事件的操作函数
  6. .minor = EVDEV_MINOR_BASE, //此设备号基数
  7. .name = "evdev",
  8. .id_table = evdev_ids, //匹配项
  9. };
由上可知,handler->connect函数即为evdev_connect函数,下面分析之:
  1. static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
  2. const struct input_device_id *id)
  3. {
  4. struct evdev *evdev;
  5. int minor;
  6. int error;
  7. //EVDEV_MINOR为32,说明evdev这个handler可以同时有32个输入设备
  8. //和它配对,evdev_table中以minor存放evdev结构体
  9. for (minor = 0; minor < EVDEV_MINORS; minor++)
  10. if (!evdev_table[minor])
  11. break;
  12. //判断32个位置是否被全部占用
  13. if (minor == EVDEV_MINORS) {
  14. pr_err( "no more free evdev devices\n");
  15. return -ENFILE;
  16. }
  17. //分配一个evdev结构体,这个结构体是evdev事件处理器持有的
  18. evdev = kzalloc( sizeof(struct evdev), GFP_KERNEL);
  19. if (!evdev)
  20. return -ENOMEM;
  21. INIT_LIST_HEAD(&evdev->client_list);
  22. spin_lock_init(&evdev->client_lock);
  23. mutex_init(&evdev->mutex);
  24. init_waitqueue_head(&evdev->wait);
  25. //设置evdev中device的名字
  26. dev_set_name(&evdev->dev, "event%d", minor);
  27. evdev->exist = true;
  28. evdev->minor = minor;
  29. //初始化evdev中的handle,这样就连接了input_handler and input_dev
  30. evdev->handle.dev = input_get_device(dev);
  31. evdev->handle.name = dev_name(&evdev->dev);
  32. evdev->handle.handler = handler;
  33. evdev->handle. private = evdev;
  34. evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
  35. evdev->dev.class = &input_class;
  36. //配对生成的device,父设备是与他相关联的 input_dev
  37. evdev->dev.parent = &dev->dev;
  38. evdev->dev.release = evdev_free;
  39. device_initialize(&evdev->dev);
  40. //注册handle结构体
  41. error = input_register_handle(&evdev->handle);
  42. if (error)
  43. goto err_free_evdev;
  44. //把evdev结构体保存在evdev_table中
  45. error = evdev_install_chrdev(evdev);
  46. if (error)
  47. goto err_unregister_handle;
  48. //注册到linux设备模型
  49. error = device_add(&evdev->dev);
  50. if (error)
  51. goto err_cleanup_evdev;
  52. return 0;
  53. err_cleanup_evdev:
  54. evdev_cleanup(evdev);
  55. err_unregister_handle:
  56. input_unregister_handle(&evdev->handle);
  57. err_free_evdev:
  58. put_device(&evdev->dev);
  59. return error;
  60. }
在分析其中的 input_register_handle(&evdev->handle)函数:
  1. int input_register_handle(struct input_handle *handle)
  2. {
  3. struct input_handler *handler = handle->handler;
  4. struct input_dev *dev = handle->dev;
  5. int error;
  6. /*
  7. * We take dev->mutex here to prevent race with
  8. * input_release_device().
  9. */
  10. error = mutex_lock_interruptible(&dev->mutex);
  11. if (error)
  12. return error;
  13. /*
  14. * Filters go to the head of the list, normal handlers
  15. * to the tail.
  16. */
  17. //将handle的d_node链接到其相关的input_dev的h_list链表中
  18. if (handler->filter)
  19. list_add_rcu(&handle->d_node, &dev->h_list);
  20. else
  21. list_add_tail_rcu(&handle->d_node, &dev->h_list);
  22. mutex_unlock(&dev->mutex);
  23. /*
  24. * Since we are supposed to be called from ->connect()
  25. * which is mutually exclusive with ->disconnect()
  26. * we can't be racing with input_unregister_handle()
  27. * and so separate lock is not needed here.
  28. */
  29. //将handle的h_node链接到其相关的input_handler的h_list链表中
  30. list_add_tail_rcu(&handle->h_node, &handler->h_list);
  31. if (handler->start)
  32. handler->start(handle);
  33. return 0;
  34. }

  这个函数基本没做什么事情,就是把一个handle结构体通过d_node链表项或h_node链表项,分别链接到input_dev的h_list,input_handler的h_list上。以后通过这个h_list就可以遍历相关的input_handle了。具体可参考下图:


2.4:input输入子系统的设备驱动层

          其实上面两层基本都是系统做好了,我们要用linux的输入子系统的话,其实只要编写符合输入子系统框架的驱动程序即可。那么何为符合输入子系统框架呢?简单的可以概括如下:

        ①分配一个input_dev结构体;

        ②设置能够支持哪类事件及类下具体的事件类型

        ③注册input_dev结构体

       ④硬件相关的代码:如在中断中上报事件

     在MTK 6589平台中,上面的前三步都是在mtk_tpd.c中完成,而第四步在中断中上报事件则是在具体的Touch Panel驱动中完成。下面先看mtk_tpd.c:

    代码路径:alps/mediatek/custom/common/kernel/touchpanel/src/mtk_tpd.c   

  1. /* called when loaded into kernel */
  2. //入口函数
  3. static int __ init tpd_device_init(void) {
  4. printk( "MediaTek touch panel driver init\n");
  5. //注册到platform总线上,匹配成功调用探测函数
  6. if(platform_driver_register(&tpd_driver)!= 0) {
  7. TPD_DMESG( "unable to register touch panel driver.\n");
  8. return -1;
  9. }
  10. return 0;
  11. }
继续看tpd_driver结构体:
  1. static struct platform_driver tpd_driver = {
  2. .remove = tpd_remove,
  3. .shutdown = NULL,
  4. .probe = tpd_probe, //探测函数
  5. #ifndef CONFIG_HAS_EARLYSUSPEND
  6. .suspend = NULL,
  7. .resume = NULL,
  8. #endif
  9. .driver = {
  10. .name = TPD_DEVICE,
  11. },
  12. };
上面的核心函数为tpd_probe(),在它里面完成了输入子系统前面的3个步骤。
  1. static int tpd_probe(struct platform_device *pdev)
  2. {
  3. //......省略部分内容
  4. //这里注册了一个misc设备
  5. if (misc_register(&tpd_misc_device))
  6. {
  7. printk( "mtk_tpd: tpd_misc_device register failed\n");
  8. }
  9. //为tpd_device分配空间,是一个自定义的结构体,里面包括
  10. //input_dev结构体
  11. if((tpd=(struct tpd_device*)kmalloc( sizeof(struct tpd_device), GFP_KERNEL))== NULL) return -ENOMEM;
  12. memset(tpd, 0, sizeof(struct tpd_device));
  13. /* allocate input device */
  14. //这里即是上面的第一步,分配了一个input_dev结构体
  15. if((tpd->dev=input_allocate_device())== NULL) { kfree(tpd); return -ENOMEM; }
  16. //......省略部分内容
  17. /* struct input_dev dev initialization and registration */
  18. //这里完成上面的第二步,设置支持哪些类事件及类下具体的事件类型
  19. tpd->dev->name = TPD_DEVICE;
  20. set_bit(EV_ABS, tpd->dev->evbit);
  21. set_bit(EV_KEY, tpd->dev->evbit);
  22. set_bit(ABS_X, tpd->dev->absbit);
  23. set_bit(ABS_Y, tpd->dev->absbit);
  24. set_bit(ABS_PRESSURE, tpd->dev->absbit);
  25. set_bit(BTN_TOUCH, tpd->dev->keybit);
  26. set_bit(INPUT_PROP_DIRECT, tpd->dev->propbit);
  27. //电容屏多点触控的一些设置
  28. set_bit(ABS_MT_TRACKING_ID, tpd->dev->absbit);
  29. set_bit(ABS_MT_TOUCH_MAJOR, tpd->dev->absbit);
  30. set_bit(ABS_MT_TOUCH_MINOR, tpd->dev->absbit);
  31. set_bit(ABS_MT_POSITION_X, tpd->dev->absbit);
  32. set_bit(ABS_MT_POSITION_Y, tpd->dev->absbit);
  33. //电容屏参数的一些设置
  34. input_set_abs_params(tpd->dev, ABS_X, 0, TPD_RES_X, 0, 0);
  35. input_set_abs_params(tpd->dev, ABS_Y, 0, TPD_RES_Y, 0, 0);
  36. input_abs_set_res(tpd->dev, ABS_X, TPD_RES_X);
  37. input_abs_set_res(tpd->dev, ABS_Y, TPD_RES_Y);
  38. input_set_abs_params(tpd->dev, ABS_PRESSURE, 0, 255, 0, 0);
  39. //注册input_dev结构体
  40. if(input_register_device(tpd->dev))
  41. TPD_DMESG( "input_register_device failed.(tpd)\n");
  42. }

接下来第四步的上报事件在驱动文件文件ft5316_driver.c中进行:

代码路径:alps/mediatek/custom/common/kernel/touchpanel/ft5316/ft5316_driver.c

  1. /* called when loaded into kernel */
  2. //驱动入口函数
  3. static int __ init tpd_driver_init(void) {
  4. //printk("MediaTek ft5316 touch panel driver init\n");
  5. //i2c_register_board_info用于注册一个i2c client
  6. i2c_register_board_info( 0, &ft5316_i2c_tpd, 1);
  7. //tpd_driver_add函数在mtk_tpd.c中实现
  8. if(tpd_driver_add(&tpd_device_driver) < 0)
  9. TPD_DMESG( "add ft5316 driver failed\n");
  10. return 0;
  11. }
下面我们回到mtk_tpd.c函数中来分析tpd_driver_add函数:

  1. /* Add driver: if find TPD_TYPE_CAPACITIVE driver sucessfully, loading it */
  2. int tpd_driver_add(struct tpd_driver_t *tpd_drv)
  3. {
  4. //省略部分内容
  5. for(i = 1; i < TP_DRV_MAX_COUNT; i++)
  6. {
  7. /* add tpd driver into list */
  8. //将我们注册的TP驱动添加到tpd_driver_list链表中
  9. if(tpd_driver_list[i].tpd_device_name == NULL)
  10. {
  11. tpd_driver_list[i].tpd_device_name = tpd_drv->tpd_device_name;
  12. tpd_driver_list[i].tpd_local_init = tpd_drv->tpd_local_init;
  13. tpd_driver_list[i].suspend = tpd_drv->suspend;
  14. tpd_driver_list[i].resume = tpd_drv->resume;
  15. tpd_driver_list[i].tpd_have_button = tpd_drv->tpd_have_button;
  16. #if 0
  17. if(tpd_drv->tpd_local_init()== 0)
  18. {
  19. TPD_DMESG( "load %s sucessfully\n", tpd_driver_list[i].tpd_device_name);
  20. g_tpd_drv = &tpd_driver_list[i];
  21. }
  22. #endif
  23. break;
  24. }
  25. if( strcmp(tpd_driver_list[i].tpd_device_name, tpd_drv->tpd_device_name) == 0)
  26. {
  27. return 1; // driver exist
  28. }
  29. }
  30. return 0;
  31. }
当touchpanel驱动中填充了这个链表后,在mtk_tpd.c中的tpd_probe()函数中会通过这个链表调用到驱动中注册的函数:

  1. for(i = 1; i < TP_DRV_MAX_COUNT; i++)
  2. {
  3. /* add tpd driver into list */
  4. if(tpd_driver_list[i].tpd_device_name != NULL)
  5. {
  6. //此处调用我们注册的tpd_local_init函数
  7. tpd_driver_list[i].tpd_local_init();
  8. //msleep(1);
  9. if(tpd_load_status == 1) {
  10. TPD_DMESG( "[mtk-tpd]tpd_probe, tpd_driver_name=%s\n", tpd_driver_list[i].tpd_device_name);
  11. g_tpd_drv = &tpd_driver_list[i];
  12. break;
  13. }
  14. }
  15. }
接下来我们回到tp驱动,注册的结构体,其中包括了local_init()函数:

  1. static struct tpd_driver_t tpd_device_driver = {
  2. .tpd_device_name = "ft5316",
  3. .tpd_local_init = tpd_local_init,
  4. .suspend = tpd_suspend,
  5. .resume = tpd_resume,
  6. #ifdef TPD_HAVE_BUTTON
  7. .tpd_have_button = 1,
  8. # else
  9. .tpd_have_button = 0,
  10. #endif
  11. };
local_init()函数:

  1. static int tpd_local_init(void)
  2. {
  3. TPD_DMESG( "Focaltech ft5316 I2C Touchscreen Driver (Built %s @ %s)\n", __DATE__, __TIME__);
  4. //注册i2c driver 这里会和i2c client匹配,然后进入i2c的probe函数
  5. if(i2c_add_driver(&tpd_i2c_driver)!= 0)
  6. {
  7. TPD_DMESG( "ft5316 unable to add i2c driver.\n");
  8. return -1;
  9. }
  10. if(tpd_load_status == 0)
  11. {
  12. TPD_DMESG( "ft5316 add error touch panel driver.\n");
  13. i2c_del_driver(&tpd_i2c_driver);
  14. return -1;
  15. }
  16. #ifdef TPD_HAVE_BUTTON    //虚拟按键的一些设置  
  17.     tpd_button_setting(TPD_KEY_COUNT, tpd_keys_local, tpd_keys_dim_local); // initialize tpd button data
  18. #endif  
  19.   //表示电容TP
  20. tpd_type_cap = 1;
  21. return 0;
  22. }
  23. <span style= "font-family:Microsoft YaHei;font-size:12px;">接下来看tp的i2c_probe()函数:</span>
  24. <pre name= "code" class= "cpp"> static struct i2c_driver tpd_i2c_driver = {
  25. .driver = {
  26. .name = "ft5316", //.name = TPD_DEVICE,
  27. // .owner = THIS_MODULE,
  28. },
  29. .probe = tpd_probe,
  30. .remove = __devexit_p(tpd_remove),
  31. .id_table = ft5316_tpd_id,
  32. .detect = tpd_detect,
  33. // .address_data = &addr_data,
  34. };
tpd_probe()函数:
  1. static int __ devinit tpd_probe(struct i2c_client *client, const struct i2c_device_id *id)
  2. {
  3. //......省略部分内容
  4. //reset管脚的配置
  5. mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO);
  6. mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT);
  7. mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE);
  8. msleep( 10);
  9. hwPowerOn(TPD_POWER_SOURCE,VOL_2800, "TP"); //TP在此处上电,TPD_POWER_SOURCE为电源脚
  10. msleep( 100);
  11. //中断脚的配置
  12. mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT);
  13. mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_IN);
  14. mt_set_gpio_pull_enable(GPIO_CTP_EINT_PIN, GPIO_PULL_ENABLE);
  15. mt_set_gpio_pull_select(GPIO_CTP_EINT_PIN, GPIO_PULL_UP);
  16. //中断及处理函数的注册
  17. mt65xx_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_SENSITIVE);
  18. mt65xx_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);
  19. mt65xx_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_EN, CUST_EINT_TOUCH_PANEL_POLARITY, tpd_eint_interrupt_handler, 0);
  20. mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
  21. //创建一个内核线程,这是TP工作的核心
  22. thread = kthread_run(touch_event_handler, 0, TPD_DEVICE);
  23. if (IS_ERR(thread))
  24. {
  25. retval = PTR_ERR(thread);
  26. TPD_DMESG(TPD_DEVICE " failed to create kernel thread: %d\n", retval);
  27. }
  28. //自动创建字符设备节点,用于调试
  29. #ifdef FTS_CTL_IIC
  30. if (ft_rw_iic_drv_init(client) < 0)
  31. dev_err(&client->dev, "%s:[FTS] create fts control iic driver failed\n",
  32. __func__);
  33. #endif
  34. }
下面我们就来分析这个非常重要的线程:
  1. static int touch_event_handler(void *unused)
  2. {
  3. //......省略部分内容
  4. do
  5. {
  6. mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
  7. set_current_state(TASK_INTERRUPTIBLE);
  8. //当TP无触摸动作时,线程在此处阻塞
  9. //当TP有触摸动作时,线程往下运行,标志位实在前面probe的中断函数中改变和唤醒的,
  10. //中断函数只进行标志位的改变和唤醒线程,比较简单,不在分析
  11. wait_event_interruptible(waiter,tpd_flag!= 0);
  12. //标志位清零
  13. tpd_flag = 0;
  14. set_current_state(TASK_RUNNING);
  15. //tpd_touchinfo函数用于获取触摸信息,此处不在祥解
  16. if (tpd_touchinfo(&cinfo, &pinfo))
  17. {
  18. //printk("point_num = %d\n",point_num);
  19. TPD_DEBUG_SET_TIME;
  20. //根据获取的触摸信息,进行相应的上报工作
  21. if(point_num > 0)
  22. {
  23. //printk("TPD Down!!!!!!!!!!!!!!!!!!\n");
  24. tpd_down(cinfo.x[ 0], cinfo.y[ 0], cinfo.p[ 0]);
  25. if(point_num> 1)
  26. {
  27. tpd_down(cinfo.x[ 1], cinfo.y[ 1], cinfo.p[ 1]);
  28. if(point_num > 2)
  29. {
  30. tpd_down(cinfo.x[ 2], cinfo.y[ 2], cinfo.p[ 2]);
  31. if(point_num > 3)
  32. {
  33. tpd_down(cinfo.x[ 3], cinfo.y[ 3], cinfo.p[ 3]);
  34. if(point_num > 4)
  35. {
  36. tpd_down(cinfo.x[ 4], cinfo.y[ 4], cinfo.p[ 4]);
  37. }
  38. }
  39. }
  40. }
  41. input_sync(tpd->dev); //上报完所有点后,再上报一个sync事件用于表示上报完
  42. //printk("press --->\n");
  43. }
  44. //当现在无触摸动作而上次有触摸,抬起上次触摸的所有点
  45. else if(p_point_num> 0)
  46. {
  47. int i;
  48. for(i= 0;i<p_point_num;i++)
  49. {
  50. tpd_up(pinfo.x[i], pinfo.y[i], 0);
  51. }
  52. input_sync(tpd->dev);
  53. }
  54. /* else
  55. {
  56. tpd_up(cinfo.x[0], cinfo.y[0], 0);
  57. //printk("Ghong_zguoqing_marked tpd point release --->\n");
  58. //input_mt_sync(tpd->dev);
  59. input_sync(tpd->dev);
  60. }*/ //Ghong_zguoqing
  61. }
  62. } while(!kthread_should_stop());
  63. }
下面重点看下上报函数,就拿tpd_down()函数分析:
  1. static void tpd_down(int x, int y, int p)
  2. {
  3. input_report_key(tpd->dev, BTN_TOUCH, 1);
  4. input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 1);
  5. //分别上报x,y轴坐标
  6.  input_report_abs(tpd->dev, ABS_MT_POSITION_X, x);
  7. input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y);
  8. input_mt_sync(tpd->dev);
  9. }
 分析input_report_abs()函数,其调用了input_event()函数:
  1. static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
  2. {
  3. input_event(dev, EV_ABS, code, value);
  4. }
  5. input_event()函数:
  6. <pre name= "code" class= "cpp"> void input_event(struct input_dev *dev,
  7. unsigned int type, unsigned int code, int value)
  8. {
  9. unsigned long flags;
  10. //判断是否支持这种类型的事件
  11. if (is_event_supported(type, dev->evbit, EV_MAX)) {
  12. spin_lock_irqsave(&dev->event_lock, flags);
  13. add_input_randomness(type, code, value);
  14. //对上报的事件进行处理
  15. input_handle_event(dev, type, code, value);
  16. spin_unlock_irqrestore(&dev->event_lock, flags);
  17. }
  18. }
然后调用input_handle_event()函数:
  1. static void input_handle_event(struct input_dev *dev,
  2. unsigned int type, unsigned int code, int value)
  3. {
  4. //......省略部分内容
  5. switch (type)
  6. {
  7. //......省略部分内容
  8. case EV_KEY:
  9. if (is_event_supported(code, dev->keybit, KEY_MAX) &&
  10. !!test_bit(code, dev->key) != value) {
  11. if (value != 2) {
  12. __change_bit(code, dev->key);
  13. if (value)
  14. input_start_autorepeat(dev, code);
  15. else
  16. input_stop_autorepeat(dev);
  17. }
  18. disposition = INPUT_PASS_TO_HANDLERS;
  19. }
  20. break;
  21. case EV_SW:
  22. if (is_event_supported(code, dev->swbit, SW_MAX) &&
  23. !!test_bit(code, dev->sw) != value) {
  24. __change_bit(code, dev->sw);
  25. disposition = INPUT_PASS_TO_HANDLERS;
  26. }
  27. break;
  28. //......省略部分内容
  29. if (disposition & INPUT_PASS_TO_HANDLERS)
  30. input_pass_event(dev, type, code, value);
  31. }
  32. }
然后调用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_handler *handler;
  5. struct input_handle *handle;
  6. rcu_read_lock();
  7. //判断是否是绑定的handle
  8. handle = rcu_dereference(dev->grab);
  9. if (handle)
  10. handle->handler->event(handle, type, code, value);
  11. else {
  12. //没有则遍历dev_list列表寻找handle
  13. bool filtered = false;
  14. list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
  15. //如果打开则将消息传递到input子系统去
  16. if (!handle->open)
  17. continue;
  18. handler = handle->handler;
  19. if (!handler->filter) {
  20. if (filtered)
  21. break;
  22. handler->event(handle, type, code, value);
  23. } else if (handler->filter(handle, type, code, value))
  24. filtered = true;
  25. }
  26. }
  27. rcu_read_unlock();
  28. }
这个函数里面会将产生的数据传递给之前初始化的evdev_handler中的evdev_event函数进行进一步处理:
  1. static void evdev_pass_event(struct evdev_client *client,
  2. struct input_event *event,
  3. ktime_t mono, ktime_t real)
  4. {
  5. event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
  6. mono : real);
  7. /* Interrupts are disabled, just acquire the lock. */
  8. spin_lock(&client->buffer_lock);
  9. //传递消息
  10. client->buffer[client->head++] = *event;
  11. client->head &= client->bufsize - 1;
  12. if (unlikely(client->head == client->tail)) {
  13. /*
  14. * This effectively "drops" all unconsumed events, leaving
  15. * EV_SYN/SYN_DROPPED plus the newest event in the queue.
  16. */
  17. client->tail = (client->head - 2) & (client->bufsize - 1);
  18. client->buffer[client->tail].time = event->time;
  19. client->buffer[client->tail].type = EV_SYN;
  20. client->buffer[client->tail].code = SYN_DROPPED;
  21. client->buffer[client->tail].value = 0;
  22. client->packet_head = client->tail;
  23. if (client->use_wake_lock)
  24. wake_unlock(&client->wake_lock);
  25. }
  26. if (event->type == EV_SYN && event->code == SYN_REPORT) {
  27. client->packet_head = client->head;
  28. if (client->use_wake_lock)
  29. wake_lock(&client->wake_lock);
  30. kill_fasync(&client->fasync, SIGIO, POLL_IN);
  31. }
  32. spin_unlock(&client->buffer_lock);
  33. }
evdev_pass_event函数最终将时间传递给了用户端的evdev_client结构中的input_event数组,之后将这个数组传递给用户空间。
至此,linux的输入子系统就先分析道此处.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值