android4.0 input子系统分析(kernel部分)

一、前言
   前面我们分析了android的input子系统的android部分的代码,下面我们继续来分析kernel部分的,对于这个系统kernel部分和标准linux差别不大,
   google在原linux基础上增加了一些代码以使其更适合手持设备,比如支持多点触控设备,支持android特有的4个按键等等。我们会一步一步的分析
   内核代码,来分析出input系统的工作原理。
二、input设备类的注册
    在input系统android部分我们知道了,在android层的eventhub中,建立了一个epoll,来监控/dev/input目录下有效的input设备所有事件,如果有
    事件输入的话就会读出当前事件,然后交给android上层处理。所使用的方法也是 open(),read(),close()的标准方法。因此我们要分析这个input
    系统的话,要从/dev/input下的设备文件分的实现析其,他的实现代码在android\kernel\drivers\input\input.c文件中,input也是内核的一个模块
    我们从模块的初始化看起subsys_initcall(input_init);

    static int __init input_init(void)
    {
        int err;
    
        err = class_register(&input_class);    //注册input设备类--------
        if (err) {                                                  |
            pr_err("unable to register input_dev class\n");         |
            return err;                                             |    
        }                                                           V
        /****************************************************************
        struct class input_class = {
            .name        = "input",
            .devnode    = input_devnode,
        };
        ********************************************************************/
        err = input_proc_init();    //建立input类proc文件系统   见下面
        if (err)
            goto fail1;
    
        err = register_chrdev(INPUT_MAJOR, "input", &input_fops);//注册字符设备驱动,此中包含了设备的具体操作函数 见下面
        if (err) {
            pr_err("unable to register char major %d", INPUT_MAJOR);
            goto fail2;
        }
    
        return 0;
    
     fail2:    input_proc_exit();
     fail1:    class_unregister(&input_class);
        return err;
    }

1.proc文件系统建立

   我们首先对proc文件系统做一个介绍:/proc 文件系统是一个特殊的软件创建的文件系统, 内核用来输出消息到外界./proc 下的每个
   文件都绑到一个内核函数上, 当文件被读的时候即时产生文件内容. 我们已经见到一些这样的文件起作用; 例如, /proc/modules, 常
   常返回当前已加载的模块列表./proc 在 Linux 系统中非常多地应用. 很多现代 Linux 发布中的工具, 例如ps, top, 以及 uptime, 
   从 /proc 中获取它们的信息. 一些设备驱动也通过/proc 输出信息, 你的也可以这样做. /proc 文件系统是动态的, 因此你的模块
   可以在任何时候添加或去除条目.-------Linux 设备驱动 第三版
   input_proc_init()代码在android\kernel\drivers\input\input.c中

  
    static int __init input_proc_init(void)
    {
        struct proc_dir_entry *entry;
    
        proc_bus_input_dir = proc_mkdir("bus/input", NULL);//为input类创建/proc/bus/input目录
        if (!proc_bus_input_dir)        |
            return -ENOMEM;             V
    /*********************************************************************************
    proc_mkdir()函数定义在android\kernel_imx\fs\proc\generic.c中,这个函数调用
    调用proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent);
    这个函数定义也在这个文件中
    struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
    struct proc_dir_entry *parent)
       {
           struct proc_dir_entry *ent;
       
           ent = __proc_create(&parent, name, S_IFDIR | mode, 2);
           if (ent) {
               if (proc_register(parent, ent) < 0) {
                   kfree(ent);
                   ent = NULL;
               }
           }
           return ent;
       }
    函数调用__proc_create()定义在本文件中
        
    static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
                          const char *name,
                          mode_t mode,
                          nlink_t nlink)
    {
        ..................
        if (xlate_proc_name(name, parent, &fn) != 0)//将name整理成/proc/name
            goto out;
    ...................
        //分配内存
        ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
        if (!ent) goto out;
        //初始化这个这个proc子系统
        memset(ent, 0, sizeof(struct proc_dir_entry));
        memcpy(((char *) ent) + sizeof(struct proc_dir_entry), fn, len + 1);
        ent->name = ((char *) ent) + sizeof(*ent);
        ent->namelen = len;
        ent->mode = mode;
        ent->nlink = nlink;
        atomic_set(&ent->count, 1);
        ent->pde_users = 0;
        spin_lock_init(&ent->pde_unload_lock);
        ent->pde_unload_completion = NULL;
        INIT_LIST_HEAD(&ent->pde_openers);//得到队列回首地址
     out:
        return ent;
    }
    到了这里我们就创建好了这个proc文件系统的子目录,下面继续创建设备文件
    **************************************************************************************/
        entry = proc_create("devices", 0, proc_bus_input_dir,   //创建devices这个设备文件
                    &input_devices_fileops);
        if (!entry)
            goto fail1;
    
        entry = proc_create("handlers", 0, proc_bus_input_dir,//创建handlers这个设备文件
                    &input_handlers_fileops);
        if (!entry)
            goto fail2;
    
        return 0;
    
     fail2:    remove_proc_entry("devices", proc_bus_input_dir);
     fail1: remove_proc_entry("bus/input", NULL);
        return -ENOMEM;
    }
    
    这里创建了两个proc文件

a)  我们先看entry = proc_create("devices", 0, proc_bus_input_dir,&input_devices_fileops);
    proc_create()是在proc_bus_input_dir创建名字为"devices"的proc文件,这个文件支持的操作由
    input_devices_fileops来定义。当我们对这个文件读、写、查找时就是调用了他里面相应的函数,因
    此我们重点来看这个参数
    static const struct file_operations input_devices_fileops = {
    .owner        = THIS_MODULE,
    .open        = input_proc_devices_open,
    .poll        = input_proc_devices_poll,
    .read        = seq_read,
    .llseek        = seq_lseek,
    .release    = seq_release,
    };
   从这里看出,这个文件支持open poll read  seek release这5个操作,这里还涉及到seq_file这个内核文件接口
   我们再来介绍一下它:由于特殊性, 在/proc 下的大文件的实现有点麻烦.一直以来, /proc 方法因为当输出数量
   变大时的错误实现变得声名狼藉. 作为一种清理 /proc 代码以及使内核开发者活得轻松些的方法, 添加了 seq_file
    接口. 这个接口提供了简单的一套函数来实现大内核虚拟文件.set_file 接口假定你在创建一个虚拟文件, 它涉及
    一系列的必须返回给用户空间的项. 为使用 seq_file, 你必须创建一个简单的 "iterator" 对象, 它能在
    序列里建立一个位置, 向前进, 并且输出序列里的一个项.---------摘自LDD3
    总的来讲seq_file是小的的proc文件以链表的形式合成一个大的文件,而方便用户使用。
   下面我们一一来分析这几个函数

 .open   = input_proc_devices_open 打开文件
    static int input_proc_devices_open(struct inode *inode, struct file *file)
    {
	return seq_open(file, &input_devices_seq_ops);//根据input_devices_seq_ops 初始化一个seq_file
    }                           
        input_devices_seq_ops的定义
    static const struct seq_operations input_devices_seq_ops = {
	.start	= input_devices_seq_start,  //起始位输入设备链表input_dev_list的首地址. input_dev_list是系统维护的所有输入设备的一个链表,
	                                    //通过这个链表可以访问系统所有的input设备
	.next	= input_devices_seq_next,   //根据input_dev_list链表查找下个设备
	.stop	= input_seq_stop,       
	.show	= input_devices_seq_show,   //从设备连表里提取出哪些内容到seq_file中
    };                  |
                        V
    static int input_devices_seq_show(struct seq_file *seq, void *v)
    {
    。。。。。。
    	seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",  //首先会是设备厂家ID ,产品ID,驱动版本
    		   dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);
    
    	seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");    //设备名字
    	seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");    //设备物理设备文件路径
    	seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");             //设备sysfs中的路径
    	seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");    //啥东西不认识
    	seq_printf(seq, "H: Handlers=");                                    // input链表中的路径
    
    	list_for_each_entry(handle, &dev->h_list, d_node)
    		seq_printf(seq, "%s ", handle->name);
    	seq_putc(seq, '\n');
    
    	input_seq_print_bitmap(seq, "PROP", dev->propbit, INPUT_PROP_MAX);  //设备的各种信息
    
    	input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);
    	if (test_bit(EV_KEY, dev->evbit))
    		input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
    	if (test_bit(EV_REL, dev->evbit))
    		input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
    	if (test_bit(EV_ABS, dev->evbit))
    		input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
    	if (test_bit(EV_MSC, dev->evbit))
    		input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
    	if (test_bit(EV_LED, dev->evbit))
    		input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX);
    	if (test_bit(EV_SND, dev->evbit))
    		input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX);
    	if (test_bit(EV_FF, dev->evbit))
    		input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX);
    	if (test_bit(EV_SW, dev->evbit))
    		input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX);
    
    	seq_putc(seq, '\n');
    
    	kfree(path);
    	return 0;
    }

    也就是说当我们打开devices这个文件的时候,应该可以读到所有设备的上面这些配置信息。

     .poll        = input_proc_devices_poll,//poll查询等待
  
  static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
    {
	poll_wait(file, &input_devices_poll_wait, wait);
	if (file->f_version != input_devices_state) {
		file->f_version = input_devices_state;
		return POLLIN | POLLRDNORM;
	}


	return 0;
    }

    .read        = seq_read,
    .llseek        = seq_lseek,
    .release    = seq_release,
    这三个都是seq_file的标准操作函数,实现文件的读取查找和关闭,不多做说明。
    
    总结来看,这个device这个文件就是input设备的描述文件,他从input_dev_list中读取设备信息,然后放到seq_file中
    供使用者方便的查看设备。
b)  entry = proc_create("handlers", 0, proc_bus_input_dir,&input_handlers_fileops);
    这个proc文件还是看参数input_handlers_fileops
   
  static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
    };


    同样的
    .read = seq_read,
.llseek = seq_lseek,
.release = seq_release
这三个都是seq_file的标准操作函数不做说明,重点来看
.open = input_proc_handlers_open,
  
  static int input_proc_handlers_open(struct inode *inode, struct file *file)
    {
    	return seq_open(file, &input_handlers_seq_ops);
    }
    参数input_handlers_seq_ops的定义
       static const struct seq_operations input_handlers_seq_ops = {
	.start	= input_handlers_seq_start, //返回input_handler_list的首地址。每个input设备的输入事件,都可以附加它的处理程序,这个处理程序可以通过input_handler连接到设备上
	                                    //同一时间可以有不同的程序连接到不同的输入设备上,这个链表就是维护不同设备和其处理事件的连接结构体的链表    
	.next	= input_handlers_seq_next,  //链表下一个节点
	.stop	= input_seq_stop,
	.show	= input_handlers_seq_show, //打开这个文件所显示的信息
    };                      |
                            V
    static int input_handlers_seq_show(struct seq_file *seq, void *v)
    {
    	struct input_handler *handler = container_of(v, struct input_handler, node);
    	union input_seq_state *state = (union input_seq_state *)&seq->private;
    
    	seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);//编号 和 handler的名字
    	if (handler->filter)
    		seq_puts(seq, " (filter)");             //有没有filter
    	if (handler->fops)
    		seq_printf(seq, " Minor=%d", handler->minor);//表示 handler 实现的文件操作集,这里不是很重要。  
    	seq_putc(seq, '\n');
    
    	return 0;
    }


到了这里input设备类的proc文件系统已经建立完成了,总结一下,这个文件系统,提供了设备查询,设备事件处理程序关联方法,就是为了方便用户使用的一个接口。


2.注册字符设备
    err = register_chrdev(INPUT_MAJOR, "input", &input_fops);注册一个字符设备,其主设备号为INPUT_MAJOR input设备,此设备号在0~256之间,由系统自动指定
    这个字符设备的操作函数集input_fops:
    static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
.llseek = noop_llseek,
    };
    input设备支持open 和 seek两种操作。
    
到了这里整个input设备类的注册已经完成了。总结一下,input设备类注册过程,首先注册一个类,然后注册proc文件系统,最后注册input的字符设备。


二、input设备注册
    一个输入设备要加载到系统中,需要调用int input_register_device(struct input_dev *dev)
        
  
  int input_register_device(struct input_dev *dev)
    {
    	static atomic_t input_no = ATOMIC_INIT(0);
    	struct input_handler *handler;
    	const char *path;
    	int error;
    
    	/* Every input device generates EV_SYN/SYN_REPORT events. */
    	__set_bit(EV_SYN, dev->evbit);  //强制加入 EV_SYN 事件
    
    	/* KEY_RESERVED is not supposed to be transmitted to userspace. */
    	__clear_bit(KEY_RESERVED, dev->keybit); //用户空间不支持KEY_RESERVED
    
    	/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
    	input_cleanse_bitmasks(dev);
    
    	if (!dev->hint_events_per_packet)
    		dev->hint_events_per_packet =
    				input_estimate_events_per_packet(dev);
    
    	/*
    	 * If delay and period are pre-set by the driver, then autorepeating
    	 * is handled by the driver itself and we don't do it in input.c.
    	 *//初始化设备连击计时器,如果驱动没有填写连击参数就使用默认值
    	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;
    	}
    
    	if (!dev->getkeycode)
    		dev->getkeycode = input_default_getkeycode;//得到键编码
    
    	if (!dev->setkeycode)
    		dev->setkeycode = input_default_setkeycode;
    
    	dev_set_name(&dev->dev, "input%ld",             //input设备的名字叫 input0 input1 input2.。。。。
    		     (unsigned long) atomic_inc_return(&input_no) - 1);
    
    	error = device_add(&dev->dev);  //使用device_add()函数将input_dev包含的device结构注册到Linux设备模型中,并可以在sysfs文件系统中表现出来。
    	if (error)
    		return error;
    
    	path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
    	pr_info("%s as %s\n",
    		dev->name ? dev->name : "Unspecified device",   //打印调试信息
    		path ? path : "N/A");
    	kfree(path);
    
    	error = mutex_lock_interruptible(&input_mutex);
    	if (error) {
    		device_del(&dev->dev);
    		return error;
    	}
    
    	list_add_tail(&dev->node, &input_dev_list); //将设备加入到device_add中
    
    	list_for_each_entry(handler, &input_handler_list, node) //将设备和handler连接起来
    		input_attach_handler(dev, handler);
    
    	input_wakeup_procfs_readers();
    
    	mutex_unlock(&input_mutex);
    
    	return 0;
    }


到了这里input设备的注册已经完成了。设备注册就是生成设备文件,建立好各个目录中的设备连接,然后将handler 与之相连接


三、事件处理
    在驱动中我们报告事件调用的是input_event()函数
    
    
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);
    	}
    }


    主要来看input_handle_event这个函数是,上报事件的进一步传递
   
    
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_SYN:
    		switch (code) {
    		case SYN_CONFIG:
    			disposition = INPUT_PASS_TO_ALL;
    			break;
    
    		case SYN_REPORT:
    			if (!dev->sync) {
    				dev->sync = true;
    				disposition = INPUT_PASS_TO_HANDLERS;
    			}
    			break;
    		case SYN_MT_REPORT:
    			dev->sync = false;
    			disposition = INPUT_PASS_TO_HANDLERS;
    			break;
    		}
    		break;
    
    	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);
    			}
    
    			disposition = INPUT_PASS_TO_HANDLERS;
    		}
    		break;
    
    	case EV_SW:
    		if (is_event_supported(code, dev->swbit, SW_MAX) &&
    		    !!test_bit(code, dev->sw) != value) {
    
    			__change_bit(code, dev->sw);
    			disposition = INPUT_PASS_TO_HANDLERS;
    		}
    		break;
    
    	case EV_ABS:
    		if (is_event_supported(code, dev->absbit, ABS_MAX))
    			disposition = input_handle_abs_event(dev, code, &value);
    
    		break;
    
    	case EV_REL:
    		if (is_event_supported(code, dev->relbit, REL_MAX) && value)
    			disposition = INPUT_PASS_TO_HANDLERS;
    
    		break;
    
    	case EV_MSC:
    		if (is_event_supported(code, dev->mscbit, MSC_MAX))
    			disposition = INPUT_PASS_TO_ALL;
    
    		break;
    
    	case EV_LED:
    		if (is_event_supported(code, dev->ledbit, LED_MAX) &&
    		    !!test_bit(code, dev->led) != value) {
    
    			__change_bit(code, dev->led);
    			disposition = INPUT_PASS_TO_ALL;
    		}
    		break;
    
    	case EV_SND:
    		if (is_event_supported(code, dev->sndbit, SND_MAX)) {
    
    			if (!!test_bit(code, dev->snd) != !!value)
    				__change_bit(code, dev->snd);
    			disposition = INPUT_PASS_TO_ALL;
    		}
    		break;
    
    	case EV_REP:
    		if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
    			dev->rep[code] = value;
    			disposition = INPUT_PASS_TO_ALL;
    		}
    		break;
    
    	case EV_FF:
    		if (value >= 0)
    			disposition = INPUT_PASS_TO_ALL;
    		break;
    
    	case EV_PWR:
    		disposition = INPUT_PASS_TO_ALL;
    		break;
    	}
       
    	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
    		dev->sync = false;
    		
         //上面是检测上报事件的有效性
         
    	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)//如果需要设备处理参与的话
    		dev->event(dev, type, code, value);     //设备的事件处理函数是用户自定义的一个处理事件的函数。比如摁下caps lock键  键盘上会有一个灯打开和关闭 用的就是这个原理
    
    	if (disposition & INPUT_PASS_TO_HANDLERS)//如果需要handler参与
    		input_pass_event(dev, type, code, value);   //进行下一步的传递
        }   
        我们看input_pass_event
    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);
    	if (handle)
    		handle->handler->event(handle, type, code, value);
    	else {
    		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;
    
    				handler->event(handle, type, code, value);
    
    			} else if (handler->filter(handle, type, code, value))
    				filtered = true;
    		}
    	}
    
    	rcu_read_unlock();
    }



    input_pass_event这个函数如果dev指定了handler的话就执行这个handler->event 如果没有的话就遍历所有handler_list 来查找合适handler->event
    从这里可以看出如果我们要处理input_event的话,必须制定一个handler->event,事实上,我们从/dev/input目录下的设备文件读取事件也是这么做的,
    我们接下来继续看。
    首先我们必须找到设备 handler注册地方
    我们知道读取事件都是在/dev/input/event0 ...设备上读去的,我们找到event设备的 创建函数在
    android\kernel_imx\drivers\input\evdev.c中
     
static int __init evdev_init(void)
    {
    	return input_register_handler(&evdev_handler);
    }
    我们看到这里调用input_register_handler注册了handler,重点来看这个参数
    static struct input_handler evdev_handler = {
    	.event		= evdev_event,
    	.connect	= evdev_connect,
    	.disconnect	= evdev_disconnect,
    	.fops		= &evdev_fops,
    	.minor		= EVDEV_MINOR_BASE,
    	.name		= "evdev",
    	.id_table	= evdev_ids,
    };
    这里event=evdev_event,这就是处理事件的函数具体的
        
    static void evdev_event(struct input_handle *handle,
    			unsigned int type, unsigned int code, int value)
    {
    	struct evdev *evdev = handle->private;
    	struct evdev_client *client;
    	struct input_event event;
    	struct timespec ts;
    
    	ktime_get_ts(&ts);
    	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);  //得到一个client 
    	if (client)
    		evdev_pass_event(client, &event);   //把事件传递过去
    	else
    		list_for_each_entry_rcu(client, &evdev->client_list, node)
    			evdev_pass_event(client, &event);
    
    	rcu_read_unlock();
    
    	if (type == EV_SYN && code == SYN_REPORT)
    		wake_up_interruptible(&evdev->wait);
    }



    我们继续看evdev_pass_event
        
    
static void evdev_pass_event(struct evdev_client *client,
    			     struct input_event *event)
    {
    	/* Interrupts are disabled, just acquire the lock. */
    	spin_lock(&client->buffer_lock);
    
    	client->buffer[client->head++] = *event;
    	client->head &= client->bufsize - 1;
    
    	if (unlikely(client->head == client->tail)) {
    		/*
    		 * This effectively "drops" all unconsumed events, leaving
    		 * EV_SYN/SYN_DROPPED plus the newest event in the queue.
    		 */
    		client->tail = (client->head - 2) & (client->bufsize - 1);
    
    		client->buffer[client->tail].time = event->time;
    		client->buffer[client->tail].type = EV_SYN;
    		client->buffer[client->tail].code = SYN_DROPPED;
    		client->buffer[client->tail].value = 0;
    
    		client->packet_head = client->tail;
    		if (client->use_wake_lock)
    			wake_unlock(&client->wake_lock);
    	}
    
    	if (event->type == EV_SYN && event->code == SYN_REPORT) {
    		client->packet_head = client->head;
    		if (client->use_wake_lock)
    			wake_lock(&client->wake_lock);
    		kill_fasync(&client->fasync, SIGIO, POLL_IN);
    	}
    
    	spin_unlock(&client->buffer_lock);
    }


    这个函数就是把相应的input_event放入到 client->buffer 的队列中。到了这里,我们看到输入设备的事件处理,被放到一个队列里,那么然后呢?
    我从event中读事件,是调用的 evdev的read函数,我们来看
    evdev的操作集.fops = &evdev_fops,
   
 static const struct file_operations evdev_fops = {
    	.owner		= THIS_MODULE,
    	.read		= evdev_read,
    	.write		= evdev_write,
    	.poll		= evdev_poll,
    	.open		= evdev_open,
    	.release	= evdev_release,
    	.unlocked_ioctl	= evdev_ioctl,
    #ifdef CONFIG_COMPAT
    	.compat_ioctl	= evdev_ioctl_compat,
    #endif
    	.fasync		= evdev_fasync,
    	.flush		= evdev_flush,
    	.llseek		= no_llseek,
    };


     可以看到读取函数为evdev_read 我们继续看
     
   
 static ssize_t evdev_read(struct file *file, char __user *buffer,
    			  size_t count, loff_t *ppos)
    {
    	struct evdev_client *client = file->private_data;
    	struct evdev *evdev = client->evdev;
    	struct input_event event;
    	int retval = 0;
    
    	if (count < input_event_size())
    		return -EINVAL;
    
    	if (!(file->f_flags & O_NONBLOCK)) {
    		retval = wait_event_interruptible(evdev->wait,
    			 client->packet_head != client->tail || !evdev->exist);
    		if (retval)
    			return retval;
    	}
    
    	if (!evdev->exist)
    		return -ENODEV;
    
    	while (retval + input_event_size() <= count &&  //事件不为
    	       evdev_fetch_next_event(client, &event)) {
    
    		if (input_event_to_user(buffer + retval, &event))//把事件拷贝到 usr的buff中
    			return -EFAULT;
    
    		retval += input_event_size();
    	}
    
    	if (retval == 0 && file->f_flags & O_NONBLOCK)
    		retval = -EAGAIN;
    	return retval;
    }


    
到了这里所有的事件处理已经完成了。总结一下,事件读取设备文件evdev 是独立于input_device的一个内核模块,两者通过input_handler联系起来
当input_device收到驱动发送的event以后,会回调evdev的处理函数,把event复制到一个缓存中,当我们从evdev读取数据时,相应的处理函数会把
event复制到buff中,因此我们就读取到了事件。android读取到事件以后,就会进行android层面的input_event处理
        

你可能感兴趣的:(android)