• Input子系统 - Kernel驱动程序 - Android


    android-goldfish-5.4-dev
    AOSP > 文档 > 核心主题 > 输入

    https://www.kernel.org/doc/Documentation/input/input.txt
    https://www.kernel.org/doc/Documentation/input/event-codes.txt
    https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt


    1、Input子系统相关定义

    在这里插入图片描述

    1.1 代码位置

    Android_Kernel\goldfish\drivers\input
    Android_Kernel\goldfish\include\linux\input.h 定义了一组标准事件类型和代码
    在这里插入图片描述

    1.2 input_dev结构体:表示输入设备

    Name: 设备名称
    Phys: 系统层次结构中设备的物理路径
    Uniq: 设备的唯一标识码(如果设备有)
    Id: 设备的Id(struct input_Id
    Propbit: 设备属性和怪癖的位图。
    Evbit: 设备支持的事件类型的位图(EV_KEYEV_REL等)
    Keybit: 此设备具有的keys/buttons位图
    Relbit: 设备的相对轴位图
    Absbit: 设备的绝对轴位图
    Mscbit: 设备支持的杂项事件的位图
    Ledbit: 设备上存在的LED位图
    Sndbit: 设备支持的音效位图
    Ffbit: 设备支持的力反馈效果位图
    Swbit: 设备上存在的开关位图
    Hint_events_per_packet: 设备在数据包中生成的平均事件数(EV_SYN/SYN_REPORT事件之间)。由事件处理程序用于估计容纳事件所需的缓冲区大小。
    Keycodemax: 键代码表的大小
    Keycodesize: 键代码表中元素的大小
    Keycode: 此设备的扫描码到密钥码的映射
    Getkeycode: 用于检索当前密钥映射的可选遗留方法。
    Setkeycode: 更改当前密钥映射的可选方法,用于实现稀疏密钥映射。如果未提供,将使用默认机制。该方法在保持event_lock时被调用,因此不能休眠
    Ff: 如果设备支持力反馈效应,则与设备相关的力反馈结构
    Poller: 如果设备设置为使用轮询模式,则与设备关联的轮询器结构
    Repeat_key: 存储上次按键的按键代码;用于实现软件自动监管
    Timer: 软件自动恢复的计时器
    Rep: 自动回放参数的当前值(延迟、速率)
    Mt: 指向多点触摸状态的指针
    Absinfo: 包含绝对轴信息(当前值、最小值、最大值、平坦值、模糊值、分辨率)的&struct input_Absinfo元素数组
    Key: 反映设备按键/按钮的当前状态
    Led: 反映设备Led的当前状态
    Snd: 反映音效的当前状态
    Sw: 反映设备开关的当前状态
    Open: 当第一个用户调用input_Open_device()时,会调用此方法。驱动程序必须准备设备开始生成事件(启动轮询线程、请求IRQ、提交URB等)
    Close: 当最后一个用户调用input_Close_device()时,会调用此方法。
    Flush: 清除设备。最常用于消除与设备断开连接时加载到设备中的力反馈效应
    Event: 发送到设备的事件的事件处理程序,如EV_LEDEV_SND。该设备应执行请求的操作(打开LED、播放声音等)呼叫受保护
    Event_lock:并且不能休眠
    Grab: 当前抓取设备的输入句柄(通过EVIOCGRAB ioctl)。当句柄抓取设备时,它将成为来自该设备的所有输入事件的唯一接收者
    Event_lock:input core接收并处理设备的新事件时(在input_Event()中),将获取此spinlock。在设备向输入核心注册后,访问和/或修改设备参数(如keymapabsminabsmaxabsfuzz等)的代码必须使用此锁。
    Mutex: 序列化对open()close()flush()方法的调用
    Users: 存储打开此设备的用户数(输入处理程序)。input_open_device()input_close_device()使用它来确保dev->open()仅在第一个用户打开设备时调用,dev->close()在最后一个用户关闭设备时调用
    Going_away: 标记正在注销的设备,并使用-ENODEV导致input_open_device*()失败。
    Dev: 此设备的驱动程序模型视图
    H_list: 与设备相关联的输入句柄列表。访问列表时,必须持有dev->mutex
    Node: 用于将设备放置在input_dev_list
    Num_vals: 当前帧中排队的值数
    Max_vals: 帧中排队的最大值数
    Vals: 当前帧中排队的值数组
    Devres_managed: 表示设备使用Devres框架进行管理,不需要显式注销或释放。
    Timestamp: 存储由驱动程序调用的input_set_Timestamp设置的时间戳

    include/linux/input.h

    struct input_dev {
    	const char *name;
    	const char *phys;
    	const char *uniq;
    	struct input_id id;
    
    	unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
    
    	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
    	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
    	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
    	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
    	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
    	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
    	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
    	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
    	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
    
    	unsigned int hint_events_per_packet;
    
    	unsigned int keycodemax;
    	unsigned int keycodesize;
    	void *keycode;
    
    	int (*setkeycode)(struct input_dev *dev,
    			  const struct input_keymap_entry *ke,
    			  unsigned int *old_keycode);
    	int (*getkeycode)(struct input_dev *dev,
    			  struct input_keymap_entry *ke);
    
    	struct ff_device *ff;
    
    	struct input_dev_poller *poller;
    
    	unsigned int repeat_key;
    	struct timer_list timer;
    
    	int rep[REP_CNT];
    
    	struct input_mt *mt;
    
    	struct input_absinfo *absinfo;
    
    	unsigned long key[BITS_TO_LONGS(KEY_CNT)];
    	unsigned long led[BITS_TO_LONGS(LED_CNT)];
    	unsigned long snd[BITS_TO_LONGS(SND_CNT)];
    	unsigned long sw[BITS_TO_LONGS(SW_CNT)];
    
    	int (*open)(struct input_dev *dev);
    	void (*close)(struct input_dev *dev);
    	int (*flush)(struct input_dev *dev, struct file *file);
    	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
    
    	struct input_handle __rcu *grab;
    
    	spinlock_t event_lock;
    	struct mutex mutex;
    
    	unsigned int users;
    	bool going_away;
    
    	struct device dev;
    
    	struct list_head	h_list;
    	struct list_head	node;
    
    	unsigned int num_vals;
    	unsigned int max_vals;
    	struct input_value *vals;
    
    	bool devres_managed;
    
    	ktime_t timestamp[INPUT_CLK_MAX];
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    1.3 input_handler结构体:struct input_handler - implements one of interfaces for input devices

    Private: 驱动程序特定数据
    Event: 事件处理程序。此方法由输入核心调用,同时禁用中断并保持dev->event_lock spinlock,因此它可能不会休眠
    Events: 事件序列处理程序。此方法由输入核心调用,同时禁用中断并保持dev->event_lock spinlock,因此它可能不会休眠
    Filter: 类似于event;将普通事件处理程序与“Filter”分离。
    Match: 在比较设备的id和处理程序的id_table后调用,以便在设备和处理程序之间进行细粒度匹配
    Connect: 在将处理程序附加到输入设备时调用
    Disconnect: 断开处理程序与输入设备的连接
    **Start:**启动给定句柄的处理程序。这个函数是在connect()方法之后由输入核心调用的,当“抓取”设备的进程释放它时也是如此
    Legacy_minors: 由使用旧版次要范围的驱动程序设置为%true
    Minor: 此驱动程序可以提供的设备的32个遗留次要范围的开始
    Name: 处理程序的名称,显示在/proc/bus/input/handlers
    Id_table: 指向此驱动程序可以处理的input_device_Id表的指针
    H_list: 与处理程序关联的输入处理程序列表
    Node: 用于将驱动程序放置到input_handler_list


    Input handlers附加到input devices并创建input handles。可能有多个处理程序同时连接到任何给定的输入设备。他们所有人都将获得设备生成的输入事件的副本。使用完全相同的结构来实现输入过滤器。 Input core允许过滤器首先运行,并且如果任何过滤器指示应该过滤事件(通过从其filter()方法返回%true),则不会将事件传递给常规处理程序。请注意,输入核心序列化对connect()disconnect()方法的调用。

    include/linux/input.h

    struct input_handler {
    
    	void *private;
    
    	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
    	void (*events)(struct input_handle *handle,
    		       const struct input_value *vals, unsigned int count);
    	bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
    	bool (*match)(struct input_handler *handler, struct input_dev *dev);
    	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);
    
    	bool legacy_minors;
    	int minor;
    	const char *name;
    
    	const struct input_device_id *id_table;
    
    	struct list_head	h_list;
    	struct list_head	node;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    1.4 input_handle结构体:将输入设备与输入处理程序链接

    一个input_dev上报的事件可以被多个input_handler接收处理,一个input_handler也可以处理多个input_dev上报的事件,这样多个input_dev和多个input_handler之间可能会形成交织的网状。在这种情况下,需要一个桥梁来搭建两者之间的联系,两边的函数调用都可以通过这个“中介”进行,input_handle就是这个桥梁。

    Private: 特定于处理程序的数据
    Open: 显示句柄是否“打开”的计数器,即应从其设备传递事件
    Name: 创建句柄的处理程序赋予句柄的名称
    Dev: 句柄所连接的输入设备
    Handler: 通过该句柄与设备一起工作的句柄
    D_node: 用于将句柄放在设备的附加句柄列表中
    H_node: 用于将句柄放在处理程序的句柄列表中,从中获取事件

    include/linux/input.h

    struct input_handle {
    
    	void *private;
    
    	int open;
    	const char *name;
    
    	struct input_dev *dev;
    	struct input_handler *handler;
    
    	struct list_head	d_node;
    	struct list_head	h_node;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2、input core 初始化

    include/linux/input.h
    drivers/input/input.c

    • sybsys_initcall注册设定启动等级,保证其初始化会早于input设备和input_handler的注册
    • module_init方式注册input设备input_handler
    subsys_initcall(input_init);
    module_exit(input_exit);
    
    • 1
    • 2

    2.1 input_init 初始化入口

    drivers/input/input.c

    class_register(&input_class) input类注册,放在/sys/class
    input_proc_init(); 主要用于input_handlerdevices信息查看,Proc文件创建
    register_chrdev_region(MKDEV(INPUT_MAJOR, 0), INPUT_MAX_CHAR_DEVICES, "input") 注册字符设备

    static int __init input_init(void)
    {
    	int err;
    
    	err = class_register(&input_class);
    	if (err) {
    		pr_err("unable to register input_dev class\n");
    		return err;
    	}
    
    	err = input_proc_init();
    	if (err)
    		goto fail1;
    
    	err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
    				     INPUT_MAX_CHAR_DEVICES, "input");
    	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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    2.1.1 class_register

    class_register(&input_class) input类注册,放在/sys/class
    在这里插入图片描述
    Linux内核API class_register|极客笔记

    drivers/input/input.c

    struct class input_class = {
    	.name		= "input",
    	.devnode	= input_devnode,
    };
    EXPORT_SYMBOL_GPL(input_class);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    include/linux/device.h
    drivers/base/class.c

    /* This is a #define to keep the compiler from merging different
     * instances of the __key variable */
    #define class_register(class)			\
    ({						\
    	static struct lock_class_key __key;	\
    	__class_register(class, &__key);	\
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.1.2 input_proc_init

    input_proc_init() 主要用于input_handlerdevices信息查看,Proc文件创建
    在这里插入图片描述

    static int __init input_proc_init(void)
    {
    	struct proc_dir_entry *entry;
    
    	proc_bus_input_dir = proc_mkdir("bus/input", NULL);
    	if (!proc_bus_input_dir)
    		return -ENOMEM;
    
    	entry = proc_create("devices", 0, proc_bus_input_dir,
    			    &input_devices_fileops);
    	if (!entry)
    		goto fail1;
    
    	entry = proc_create("handlers", 0, proc_bus_input_dir,
    			    &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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2.1.3 register_chrdev_region

    register_chrdev_region(MKDEV(INPUT_MAJOR, 0), INPUT_MAX_CHAR_DEVICES, "input") 注册字符设备;创建一个主设备为13的“input”设备

    include/uapi/linux/major.h

    #define INPUT_MAJOR		13
    
    • 1

    drivers/input/input.c

    #define INPUT_MAX_CHAR_DEVICES		1024
    
    • 1

    fs/char_dev.c

    /**
     * register_chrdev_region() - register a range of device numbers
     * @from: the first in the desired range of device numbers; must include
     *        the major number.
     * @count: the number of consecutive device numbers required
     * @name: the name of the device or driver.
     *
     * Return value is zero on success, a negative error code on failure.
     */
    int register_chrdev_region(dev_t from, unsigned count, const char *name)
    {
    	struct char_device_struct *cd;
    	dev_t to = from + count;
    	dev_t n, next;
    
    	for (n = from; n < to; n = next) {
    		next = MKDEV(MAJOR(n)+1, 0);
    		if (next > to)
    			next = to;
    		cd = __register_chrdev_region(MAJOR(n), MINOR(n),
    			       next - n, name);
    		if (IS_ERR(cd))
    			goto fail;
    	}
    	return 0;
    fail:
    	to = n;
    	for (n = from; n < to; n = next) {
    		next = MKDEV(MAJOR(n)+1, 0);
    		kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
    	}
    	return PTR_ERR(cd);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    3、 input_dev设备注册

    3.1 input_allocate_device:分配input_dev结构体内存

    input_allocate_device-为新的输入设备分配内存
    返回准备好的结构input_dev%NULL
    注意:使用input_free_device()释放尚未注册的设备;input_unregister_device()应用于已注册的设备。

    drivers/input/input.c

    struct input_dev *devm_input_allocate_device(struct device *dev)
    {
    	struct input_dev *input;
    	struct input_devres *devres;
    
    	devres = devres_alloc(devm_input_device_release,
    			      sizeof(*devres), GFP_KERNEL);
    	if (!devres)
    		return NULL;
    
    	input = input_allocate_device();
    	if (!input) {
    		devres_free(devres);
    		return NULL;
    	}
    
    	input->dev.parent = dev;
    	input->devres_managed = true;
    
    	devres->input = input;
    	devres_add(dev, devres);
    
    	return input;
    }
    EXPORT_SYMBOL(devm_input_allocate_device);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    /**
     * input_allocate_device - allocate memory for new input device
     *
     * Returns prepared struct input_dev or %NULL.
     *
     * NOTE: Use input_free_device() to free devices that have not been
     * registered; input_unregister_device() should be used for already
     * registered devices.
     */
    struct input_dev *input_allocate_device(void)
    {
    	static atomic_t input_no = ATOMIC_INIT(-1);
    	struct input_dev *dev;
    
    	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    	if (dev) {
    		dev->dev.type = &input_dev_type;
    		dev->dev.class = &input_class;
    		device_initialize(&dev->dev);
    		mutex_init(&dev->mutex);
    		spin_lock_init(&dev->event_lock);
    		timer_setup(&dev->timer, NULL, 0);
    		INIT_LIST_HEAD(&dev->h_list);
    		INIT_LIST_HEAD(&dev->node);
    
    		dev_set_name(&dev->dev, "input%lu",
    			     (unsigned long)atomic_inc_return(&input_no));
    
    		__module_get(THIS_MODULE);
    	}
    
    	return dev;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    3.2 input_register_device:带输入核心的寄存器设备

    此函数将设备注册到 input core 。在注册之前,必须为设备分配input_allocate_device()及其所有功能。如果函数失败,则必须使用input_free_device()释放设备。一旦设备成功注册,就可以使用input_unregister_device()进行注销;在这种情况下,不应调用input_free_device()。请注意,此函数还用于注册托管输入设备(使用devm_input_allocate_device()分配的设备)。这样的托管输入设备不需要明确地注销或释放,它们的拆除由devres基础设施控制。同样值得注意的是,删除托管输入设备在内部是一个两步过程:注册的托管输入设备首先未注册,但保留在内存中,并且仍然可以处理input_event()调用(尽管事件不会传递到任何地方)。稍后,当devres堆栈展开到进行设备分配的点时,将释放托管输入设备。

    • device_add(&dev->dev):将设备注册为linux设备
    • list_add_tail(&dev->node, &input_dev_list):将设备添加到linux内核全局列表input_dev_list
    • list_for_each_entry(handler, &input_handler_list, node)
      input_attach_handler(dev, handler);:遍历input_handler_list,为设备找到自己的handler

    drivers/input/input.c

    int input_register_device(struct input_dev *dev)
    {
    	struct input_devres *devres = NULL;
    	struct input_handler *handler;
    	unsigned int packet_size;
    	const char *path;
    	int error;
    
    	if (test_bit(EV_ABS, dev->evbit) && !dev->absinfo) {
    		dev_err(&dev->dev,
    			"Absolute device without dev->absinfo, refusing to register\n");
    		return -EINVAL;
    	}
    
    	if (dev->devres_managed) {
    		devres = devres_alloc(devm_input_device_unregister,
    				      sizeof(*devres), GFP_KERNEL);
    		if (!devres)
    			return -ENOMEM;
    
    		devres->input = dev;
    	}
    
    	/* Every input device generates EV_SYN/SYN_REPORT events. */
    	__set_bit(EV_SYN, dev->evbit);
    
    	/* KEY_RESERVED is not supposed to be transmitted to userspace. */
    	__clear_bit(KEY_RESERVED, dev->keybit);
    
    	/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
    	input_cleanse_bitmasks(dev);
    
    	packet_size = input_estimate_events_per_packet(dev);
    	if (dev->hint_events_per_packet < packet_size)
    		dev->hint_events_per_packet = packet_size;
    
    	dev->max_vals = dev->hint_events_per_packet + 2;
    	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
    	if (!dev->vals) {
    		error = -ENOMEM;
    		goto err_devres_free;
    	}
    
    	/*
    	 * 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.
    	 */
    	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
    		input_enable_softrepeat(dev, 250, 33);
    
    	if (!dev->getkeycode)
    		dev->getkeycode = input_default_getkeycode;
    
    	if (!dev->setkeycode)
    		dev->setkeycode = input_default_setkeycode;
    
    	if (dev->poller)
    		input_dev_poller_finalize(dev->poller);
    
    	error = device_add(&dev->dev);
    	if (error)
    		goto err_free_vals;
    
    	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)
    		goto err_device_del;
    
    	list_add_tail(&dev->node, &input_dev_list);
    
    	list_for_each_entry(handler, &input_handler_list, node)
    		input_attach_handler(dev, handler);
    
    	input_wakeup_procfs_readers();
    
    	mutex_unlock(&input_mutex);
    
    	if (dev->devres_managed) {
    		dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
    			__func__, dev_name(&dev->dev));
    		devres_add(dev->dev.parent, devres);
    	}
    	return 0;
    
    err_device_del:
    	device_del(&dev->dev);
    err_free_vals:
    	kfree(dev->vals);
    	dev->vals = NULL;
    err_devres_free:
    	devres_free(devres);
    	return error;
    }
    EXPORT_SYMBOL(input_register_device);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    3.3 案例:"gpio-keys"设备注册

    在这里插入图片描述

    drivers/input/keyboard/gpio_keys.c
    “gpio-keys”: platform_driver_register(&gpio_keys_device_driver) -> gpio_keys_probe -> devm_input_allocate_device -> input_register_device


    如其它案例等查看如下等目录:
    drivers/input/gameport
    drivers/input/joystick
    drivers/input/keyboard
    drivers/input/misc
    drivers/input/mouse
    drivers/input/rmi4
    drivers/input/serio
    drivers/input/tablet
    drivers/input/touchscreen

    static struct platform_driver gpio_keys_device_driver = {
    	.probe		= gpio_keys_probe,
    	.shutdown	= gpio_keys_shutdown,
    	.driver		= {
    		.name	= "gpio-keys",
    		.pm	= &gpio_keys_pm_ops,
    		.of_match_table = gpio_keys_of_match,
    		.dev_groups	= gpio_keys_groups,
    	}
    };
    
    static int __init gpio_keys_init(void)
    {
    	return platform_driver_register(&gpio_keys_device_driver);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    static int gpio_keys_probe(struct platform_device *pdev)
    {
    	struct device *dev = &pdev->dev;
    	const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
    	struct fwnode_handle *child = NULL;
    	struct gpio_keys_drvdata *ddata;
    	struct input_dev *input;
    	int i, error;
    	int wakeup = 0;
    
    	if (!pdata) {
    		pdata = gpio_keys_get_devtree_pdata(dev);
    		if (IS_ERR(pdata))
    			return PTR_ERR(pdata);
    	}
    
    	ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons),
    			     GFP_KERNEL);
    	if (!ddata) {
    		dev_err(dev, "failed to allocate state\n");
    		return -ENOMEM;
    	}
    
    	ddata->keymap = devm_kcalloc(dev,
    				     pdata->nbuttons, sizeof(ddata->keymap[0]),
    				     GFP_KERNEL);
    	if (!ddata->keymap)
    		return -ENOMEM;
    
    	input = devm_input_allocate_device(dev);
    	if (!input) {
    		dev_err(dev, "failed to allocate input device\n");
    		return -ENOMEM;
    	}
    
    	ddata->pdata = pdata;
    	ddata->input = input;
    	mutex_init(&ddata->disable_lock);
    
    	platform_set_drvdata(pdev, ddata);
    	input_set_drvdata(input, ddata);
    
    	input->name = pdata->name ? : pdev->name;
    	input->phys = "gpio-keys/input0";
    	input->dev.parent = dev;
    	input->open = gpio_keys_open;
    	input->close = gpio_keys_close;
    
    	input->id.bustype = BUS_HOST;
    	input->id.vendor = 0x0001;
    	input->id.product = 0x0001;
    	input->id.version = 0x0100;
    
    	input->keycode = ddata->keymap;
    	input->keycodesize = sizeof(ddata->keymap[0]);
    	input->keycodemax = pdata->nbuttons;
    
    	/* Enable auto repeat feature of Linux input subsystem */
    	if (pdata->rep)
    		__set_bit(EV_REP, input->evbit);
    
    	for (i = 0; i < pdata->nbuttons; i++) {
    		const struct gpio_keys_button *button = &pdata->buttons[i];
    
    		if (!dev_get_platdata(dev)) {
    			child = device_get_next_child_node(dev, child);
    			if (!child) {
    				dev_err(dev,
    					"missing child device node for entry %d\n",
    					i);
    				return -EINVAL;
    			}
    		}
    
    		error = gpio_keys_setup_key(pdev, input, ddata,
    					    button, i, child);
    		if (error) {
    			fwnode_handle_put(child);
    			return error;
    		}
    
    		if (button->wakeup)
    			wakeup = 1;
    	}
    
    	fwnode_handle_put(child);
    
    	error = input_register_device(input);
    	if (error) {
    		dev_err(dev, "Unable to register input device, error: %d\n",
    			error);
    		return error;
    	}
    
    	device_init_wakeup(dev, wakeup);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    4、input_handler注册

    4.1 常见的input_handler

    一般来说input_handler注册会在input_dev设备注册之前,常见的input_handler

    • evdev_handler:响应绝大部分事件,默认input处理事件
    • mousedev_handler:鼠标类input事件
    • joydev_handler :游戏遥感类input事件
    • kbd_handler:键盘类事件
    • input_leds_handler
    • apmpower_handler

    drivers/input/evdev.c

    static struct input_handler evdev_handler = {
    	.event		= evdev_event,
    	.events		= evdev_events,
    	.connect	= evdev_connect,
    	.disconnect	= evdev_disconnect,
    	.legacy_minors	= true,
    	.minor		= EVDEV_MINOR_BASE,
    	.name		= "evdev",
    	.id_table	= evdev_ids,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    drivers/tty/vt/keyboard.c

    static struct input_handler kbd_handler = {
    	.event		= kbd_event,
    	.match		= kbd_match,
    	.connect	= kbd_connect,
    	.disconnect	= kbd_disconnect,
    	.start		= kbd_start,
    	.name		= "kbd",
    	.id_table	= kbd_ids,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    drivers/input/mousedev.c

    static struct input_handler mousedev_handler = {
    	.event		= mousedev_event,
    	.connect	= mousedev_connect,
    	.disconnect	= mousedev_disconnect,
    	.legacy_minors	= true,
    	.minor		= MOUSEDEV_MINOR_BASE,
    	.name		= "mousedev",
    	.id_table	= mousedev_ids,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    drivers/input/joydev.c

    static struct input_handler joydev_handler = {
    	.event		= joydev_event,
    	.match		= joydev_match,
    	.connect	= joydev_connect,
    	.disconnect	= joydev_disconnect,
    	.legacy_minors	= true,
    	.minor		= JOYDEV_MINOR_BASE,
    	.name		= "joydev",
    	.id_table	= joydev_ids,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    drivers/input/input-leds.c

    static struct input_handler input_leds_handler = {
    	.event =	input_leds_event,
    	.connect =	input_leds_connect,
    	.disconnect =	input_leds_disconnect,
    	.name =		"leds",
    	.id_table =	input_leds_ids,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    drivers/input/apm-power.c

    static struct input_handler apmpower_handler = {
    	.event =	apmpower_event,
    	.connect =	apmpower_connect,
    	.disconnect =	apmpower_disconnect,
    	.name =		"apm-power",
    	.id_table =	apmpower_ids,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.2 input_register_handler注册函数

    此函数为系统中的输入设备注册一个新的input_handler(接口),并将其连接到与该处理程序兼容的所有input devices

    • INIT_LIST_HEAD(&handler->h_list):初始化在Linux的内核链表
    • list_add_tail(&handler->node, &input_handler_list):将handler添加到linux内核全局列表input_handler_list
    • list_for_each_entry(handler, &input_handler_list, node)
      input_attach_handler(dev, handler);:遍历input_handler_list,为设备找到自己的handler
    /**
     * input_register_handler - register a new input handler
     * @handler: handler to be registered
     *
     * This function registers a new input handler (interface) for input
     * devices in the system and attaches it to all input devices that
     * are compatible with the handler.
     */
    int input_register_handler(struct input_handler *handler)
    {
    	struct input_dev *dev;
    	int error;
    
    	error = mutex_lock_interruptible(&input_mutex);
    	if (error)
    		return error;
    
    	INIT_LIST_HEAD(&handler->h_list);
    
    	list_add_tail(&handler->node, &input_handler_list);
    
    	list_for_each_entry(dev, &input_dev_list, node)
    		input_attach_handler(dev, handler);
    
    	input_wakeup_procfs_readers();
    
    	mutex_unlock(&input_mutex);
    	return 0;
    }
    EXPORT_SYMBOL(input_register_handler);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    5、input_dev和input_handler匹配input_handle

    5.1 input_match_device匹配

    input_dev设备注册input_handler注册都会调用input_attach_handler

    • input_match_device:匹配成功返回handler->id_table,即input_device_id
    • handler->connect(handler, dev, id):匹配成功调用connect函数,如drivers/input/evdev.c#evdev_connectdrivers/input/mousedev.c#mousedev_connect
    static const struct input_device_id *input_match_device(struct input_handler *handler,
    							struct input_dev *dev)
    {
    	const struct input_device_id *id;
    
    	for (id = handler->id_table; id->flags || id->driver_info; id++) {
    		if (input_match_device_id(dev, id) &&
    		    (!handler->match || handler->match(handler, dev))) {
    			return id;
    		}
    	}
    
    	return NULL;
    }
    
    static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
    {
    	const struct input_device_id *id;
    	int error;
    
    	id = input_match_device(handler, dev);
    	if (!id)
    		return -ENODEV;
    
    	error = handler->connect(handler, dev, id);
    	if (error && error != -ENODEV)
    		pr_err("failed to attach handler %s to device %s, error: %d\n",
    		       handler->name, kobject_name(&dev->dev.kobj), error);
    
    	return error;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    5.2 connect函数

    drivers/input/evdev.c#evdev_connectdrivers/input/mousedev.c#mousedev_connect等;查看通用事件处理evdev.c

    • .driver_info = 1: 其中evdev_ids匹配所有设备,
    • evdev_connect:一旦注册就会evdev的connect
      1》input_register_handle注册一个新的input_handle,主要将handle分别挂载在input_devinput_handler成员链表;
      (evdev->handle.dev = input_get_device(dev);evdev->handle.handler = handler;)
      2》input_get_new_minor最多能创建32个event设备#define EVDEV_MINORS 32
      3》cdev_device_add最终调用device_add,向Linux系统新创建一个event设备/dev/input/eventX
      在这里插入图片描述

    drivers/input/evdev.c

    struct evdev {
    	int open;
    	struct input_handle handle;
    	wait_queue_head_t wait;
    	struct evdev_client __rcu *grab;
    	struct list_head client_list;
    	spinlock_t client_lock; /* protects client_list */
    	struct mutex mutex;
    	struct device dev;
    	struct cdev cdev;
    	bool exist;
    };
    
    /*
     * Create new evdev device. Note that input core serializes calls
     * to connect and disconnect.
     */
    static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
    			 const struct input_device_id *id)
    {
    	struct evdev *evdev;
    	int minor;
    	int dev_no;
    	int error;
    
    	minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
    	if (minor < 0) {
    		error = minor;
    		pr_err("failed to reserve new minor: %d\n", error);
    		return error;
    	}
    
    	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
    	if (!evdev) {
    		error = -ENOMEM;
    		goto err_free_minor;
    	}
    
    	INIT_LIST_HEAD(&evdev->client_list);
    	spin_lock_init(&evdev->client_lock);
    	mutex_init(&evdev->mutex);
    	init_waitqueue_head(&evdev->wait);
    	evdev->exist = true;
    
    	dev_no = minor;
    	/* Normalize device number if it falls into legacy range */
    	if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
    		dev_no -= EVDEV_MINOR_BASE;
    	dev_set_name(&evdev->dev, "event%d", dev_no);
    
    	evdev->handle.dev = input_get_device(dev);
    	evdev->handle.name = dev_name(&evdev->dev);
    	evdev->handle.handler = handler;
    	evdev->handle.private = evdev;
    
    	evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
    	evdev->dev.class = &input_class;
    	evdev->dev.parent = &dev->dev;
    	evdev->dev.release = evdev_free;
    	device_initialize(&evdev->dev);
    
    	error = input_register_handle(&evdev->handle);
    	if (error)
    		goto err_free_evdev;
    
    	cdev_init(&evdev->cdev, &evdev_fops);
    
    	error = cdev_device_add(&evdev->cdev, &evdev->dev);
    	if (error)
    		goto err_cleanup_evdev;
    
    	return 0;
    
     err_cleanup_evdev:
    	evdev_cleanup(evdev);
    	input_unregister_handle(&evdev->handle);
     err_free_evdev:
    	put_device(&evdev->dev);
     err_free_minor:
    	input_free_minor(minor);
    	return error;
    }
    
    static const struct input_device_id evdev_ids[] = {
    	{ .driver_info = 1 },	/* Matches all devices */
    	{ },			/* Terminating zero entry */
    };
    
    MODULE_DEVICE_TABLE(input, evdev_ids);
    
    static struct input_handler evdev_handler = {
    	.event		= evdev_event,
    	.events		= evdev_events,
    	.connect	= evdev_connect,
    	.disconnect	= evdev_disconnect,
    	.legacy_minors	= true,
    	.minor		= EVDEV_MINOR_BASE,
    	.name		= "evdev",
    	.id_table	= evdev_ids,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    5.3 input_register_handle

    input_register_handle-注册一个新的输入句柄


    Handle:用于注册的Handle


    这个函数将一个新的输入句柄放在input_devinput_handler的列表中,这样,一旦使用input_open_device()打开它,事件就可以在其中流动。这个函数应该从处理程序的connect()方法调用。

    /**
     * input_register_handle - register a new input handle
     * @handle: handle to register
     *
     * This function puts a new input handle onto device's
     * and handler's lists so that events can flow through
     * it once it is opened using input_open_device().
     *
     * This function is supposed to be called from handler's
     * connect() method.
     */
    int input_register_handle(struct input_handle *handle)
    {
    	struct input_handler *handler = handle->handler;
    	struct input_dev *dev = handle->dev;
    	int error;
    
    	/*
    	 * We take dev->mutex here to prevent race with
    	 * input_release_device().
    	 */
    	error = mutex_lock_interruptible(&dev->mutex);
    	if (error)
    		return error;
    
    	/*
    	 * Filters go to the head of the list, normal handlers
    	 * to the tail.
    	 */
    	if (handler->filter)
    		list_add_rcu(&handle->d_node, &dev->h_list);
    	else
    		list_add_tail_rcu(&handle->d_node, &dev->h_list);
    
    	mutex_unlock(&dev->mutex);
    
    	/*
    	 * Since we are supposed to be called from ->connect()
    	 * which is mutually exclusive with ->disconnect()
    	 * we can't be racing with input_unregister_handle()
    	 * and so separate lock is not needed here.
    	 */
    	list_add_tail_rcu(&handle->h_node, &handler->h_list);
    
    	if (handler->start)
    		handler->start(handle);
    
    	return 0;
    }
    EXPORT_SYMBOL(input_register_handle);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    5.4 input_dev \ input_handler \ input_handle 关系

    在这里插入图片描述

    input_dev 是硬件驱动层,代表一个input设备
    input_handler 是事件处理层,代表一个事件处理器
    input_handle 属于核心层,代表一个配对的input设备与input事件处理器

    input_dev 通过全局的input_dev_list链接在一起。设备注册的时候实现这个操作。
    input_handler 通过全局的input_handler_list链接在一起。事件处理器注册的时候实现这个操作。

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

    6、input事件上报

    input事件一般采用中断方式上报,相关方法input_report_absinput_report_keyinput_sync等。最终input_sync来表示一次事件上报,最终调用input_event处理。

    6.1 底层Input事件上报

    AOSP > 文档 > 核心主题 > 键盘设备AOSP > 文档 > 核心主题 > 触摸设备

    不同的input设备上报的input事件的格式不同,常用的按键或者触摸屏采用的中断方式上报。
    比如触摸屏上报input事件时一般需要上报手指的id、x坐标、y坐标等信息。


    https://www.kernel.org/doc/Documentation/input/input.txt
    https://www.kernel.org/doc/Documentation/input/event-codes.txt
    https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt

    input_report_abs(input, ABS_MT_POSITION_X, x);
    input_report_abs(input, ABS_MT_POSITION_Y, y);
    input_sync(input);
    
    • 1
    • 2
    • 3
    -typecodevalue
    第1个点EV_ABSABS_MT_SLOT0
    \EV_ABSABS_MT_TRACKING_IDid
    \EV_ABSABS_MT_POSITION_Xx
    \EV_ABSABS_MT_POSITION_Yy
    第2个点EV_ABSABS_MT_SLOTn
    \EV_ABSABS_MT_TRACKING_IDid
    \EV_ABSABS_MT_POSITION_Xx
    \EV_ABSABS_MT_POSITION_Yy

    6.2 input_event 报告新的input事件

    实现各种输入设备的驱动程序应使用此功能来报告输入事件。另请参见input_inject_event()
    注意:input_event()可以在使用input_allocate_device()分配输入设备之后立即安全使用,甚至在使用input_register_device()注册之前也是如此,但该事件不会到达任何输入处理程序。input_event()的这种早期调用可以用于“种子”开关的初始状态或绝对轴的初始位置等

    • input_handle_event:每一个事件上报都是通过input_event接口来完成,在判定事件类型是否支持后,主要是调用input_handle_event来完成
    • input_get_disposition:根据上报信息判断怎么处理
    • handler->events()/handler->event()input_dev对应input_handler,如evdev_handler等(input_event -> input_handle_event -> input_pass_values -> input_to_handler -> handler->events()/handler->event())

    drivers/input/input.c

    /*
     * Pass event first through all filters and then, if event has not been
     * filtered out, through all open handles. This function is called with
     * dev->event_lock held and interrupts disabled.
     */
    static unsigned int input_to_handler(struct input_handle *handle,
    			struct input_value *vals, unsigned int count)
    {
    	struct input_handler *handler = handle->handler;
    	struct input_value *end = vals;
    	struct input_value *v;
    
    	if (handler->filter) {
    		for (v = vals; v != vals + count; v++) {
    			if (handler->filter(handle, v->type, v->code, v->value))
    				continue;
    			if (end != v)
    				*end = *v;
    			end++;
    		}
    		count = end - vals;
    	}
    
    	if (!count)
    		return 0;
    
    	if (handler->events)
    		handler->events(handle, vals, count);
    	else if (handler->event)
    		for (v = vals; v != vals + count; v++)
    			handler->event(handle, v->type, v->code, v->value);
    
    	return count;
    }
    
    
    /*
     * Pass values first through all filters and then, if event has not been
     * filtered out, through all open handles. This function is called with
     * dev->event_lock held and interrupts disabled.
     */
    static void input_pass_values(struct input_dev *dev,
    			      struct input_value *vals, unsigned int count)
    {
    	struct input_handle *handle;
    	struct input_value *v;
    
    	if (!count)
    		return;
    
    	rcu_read_lock();
    
    	handle = rcu_dereference(dev->grab);
    	if (handle) {
    		count = input_to_handler(handle, vals, count);
    	} else {
    		list_for_each_entry_rcu(handle, &dev->h_list, d_node)
    			if (handle->open) {
    				count = input_to_handler(handle, vals, count);
    				if (!count)
    					break;
    			}
    	}
    
    	rcu_read_unlock();
    
    	/* trigger auto repeat for key events */
    	if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) {
    		for (v = vals; v != vals + count; v++) {
    			if (v->type == EV_KEY && v->value != 2) {
    				if (v->value)
    					input_start_autorepeat(dev, v->code);
    				else
    					input_stop_autorepeat(dev);
    			}
    		}
    	}
    }
    
    
    /**
     * input_event() - report new input event
     * @dev: device that generated the event
     * @type: type of the event
     * @code: event code
     * @value: value of the event
     *
     * This function should be used by drivers implementing various input
     * devices to report input events. See also input_inject_event().
     *
     * NOTE: input_event() may be safely used right after input device was
     * allocated with input_allocate_device(), even before it is registered
     * with input_register_device(), but the event will not reach any of the
     * input handlers. Such early invocation of input_event() may be used
     * to 'seed' initial state of a switch or initial position of absolute
     * axis, etc.
     */
    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);
    		input_handle_event(dev, type, code, value);
    		spin_unlock_irqrestore(&dev->event_lock, flags);
    	}
    }
    EXPORT_SYMBOL(input_event);
    
    
    static void input_handle_event(struct input_dev *dev,
    			       unsigned int type, unsigned int code, int value)
    {
    	int disposition = input_get_disposition(dev, type, code, &value);
    
    	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
    		add_input_randomness(type, code, value);
    
    	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
    		dev->event(dev, type, code, value);
    
    	if (!dev->vals)
    		return;
    
    	if (disposition & INPUT_PASS_TO_HANDLERS) {
    		struct input_value *v;
    
    		if (disposition & INPUT_SLOT) {
    			v = &dev->vals[dev->num_vals++];
    			v->type = EV_ABS;
    			v->code = ABS_MT_SLOT;
    			v->value = dev->mt->slot;
    		}
    
    		v = &dev->vals[dev->num_vals++];
    		v->type = type;
    		v->code = code;
    		v->value = value;
    	}
    
    	if (disposition & INPUT_FLUSH) {
    		if (dev->num_vals >= 2)
    			input_pass_values(dev, dev->vals, dev->num_vals);
    		dev->num_vals = 0;
    		/*
    		 * Reset the timestamp on flush so we won't end up
    		 * with a stale one. Note we only need to reset the
    		 * monolithic one as we use its presence when deciding
    		 * whether to generate a synthetic timestamp.
    		 */
    		dev->timestamp[INPUT_CLK_MONO] = ktime_set(0, 0);
    	} else if (dev->num_vals >= dev->max_vals - 2) {
    		dev->vals[dev->num_vals++] = input_value_sync;
    		input_pass_values(dev, dev->vals, dev->num_vals);
    		dev->num_vals = 0;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160

    6.3 evdev_handler中evdev_events处理

    evdev_events将传入事件传递给所有连接的客户端
    evdev_event/evdev_events -> evdev_pass_values -> __pass_event ->


    input事件存储在client->buffer中;kill_fasync用于发送通知事件,告诉上层client->buffer中有数据可以读了。

    drivers/input/evdev.c

    static void __pass_event(struct evdev_client *client,
    			 const struct input_event *event)
    {
    	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] = (struct input_event) {
    			.input_event_sec = event->input_event_sec,
    			.input_event_usec = event->input_event_usec,
    			.type = EV_SYN,
    			.code = SYN_DROPPED,
    			.value = 0,
    		};
    
    		client->packet_head = client->tail;
    	}
    
    	if (event->type == EV_SYN && event->code == SYN_REPORT) {
    		client->packet_head = client->head;
    		kill_fasync(&client->fasync, SIGIO, POLL_IN);
    	}
    }
    
    static void evdev_pass_values(struct evdev_client *client,
    			const struct input_value *vals, unsigned int count,
    			ktime_t *ev_time)
    {
    	struct evdev *evdev = client->evdev;
    	const struct input_value *v;
    	struct input_event event;
    	struct timespec64 ts;
    	bool wakeup = false;
    
    	if (client->revoked)
    		return;
    
    	ts = ktime_to_timespec64(ev_time[client->clk_type]);
    	event.input_event_sec = ts.tv_sec;
    	event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
    
    	/* Interrupts are disabled, just acquire the lock. */
    	spin_lock(&client->buffer_lock);
    
    	for (v = vals; v != vals + count; v++) {
    		if (__evdev_is_filtered(client, v->type, v->code))
    			continue;
    
    		if (v->type == EV_SYN && v->code == SYN_REPORT) {
    			/* drop empty SYN_REPORT */
    			if (client->packet_head == client->head)
    				continue;
    
    			wakeup = true;
    		}
    
    		event.type = v->type;
    		event.code = v->code;
    		event.value = v->value;
    		__pass_event(client, &event);
    	}
    
    	spin_unlock(&client->buffer_lock);
    
    	if (wakeup)
    		wake_up_interruptible(&evdev->wait);
    }
    
    /*
     * Pass incoming events to all connected clients.
     */
    static void evdev_events(struct input_handle *handle,
    			 const struct input_value *vals, unsigned int count)
    {
    	struct evdev *evdev = handle->private;
    	struct evdev_client *client;
    	ktime_t *ev_time = input_get_timestamp(handle->dev);
    
    	rcu_read_lock();
    
    	client = rcu_dereference(evdev->grab);
    
    	if (client)
    		evdev_pass_values(client, vals, count, ev_time);
    	else
    		list_for_each_entry_rcu(client, &evdev->client_list, node)
    			evdev_pass_values(client, vals, count, ev_time);
    
    	rcu_read_unlock();
    }
    
    /*
     * Pass incoming event to all connected clients.
     */
    static void evdev_event(struct input_handle *handle,
    			unsigned int type, unsigned int code, int value)
    {
    	struct input_value vals[] = { { type, code, value } };
    
    	evdev_events(handle, vals, 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107

    7、Input事件内核空间传递到用户空间

    • EventHub::getEvents -> resdinput事件存储在client->buffer中,当应用层或框架层调用read函数读取/dev/input/event*文件时,例如evdev.c会调用evdev_read返回数据,
    • event_fetch_next_event:判断client->buffer这个循环缓冲区中的头尾指针是否相等(相等时buffer中没有数据),不相等时取出一个input_event类型的事件放入到event中;
    • input_event_to_user:将此事件copy到应用层,input_event_size函数是用来获取一个input_event事件的大小,循环复制client->buffer中的事件到应用层的buffer中。

    frameworks/native/services/inputflinger/reader/EventHub.cpp

    size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
        ALOG_ASSERT(bufferSize >= 1);
    
        std::scoped_lock _l(mLock);
    
        struct input_event readBuffer[bufferSize];
    
        RawEvent* event = buffer;
        size_t capacity = bufferSize;
        bool awoken = false;
        for (;;) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    
            // Reopen input devices if needed.
            if (mNeedToReopenDevices) {
                mNeedToReopenDevices = false;
    
                ALOGI("Reopening all input devices due to a configuration change.");
    
                closeAllDevicesLocked();
                mNeedToScanDevices = true;
                break; // return to the caller before we actually rescan
            }
    
            // Report any devices that had last been added/removed.
            for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {
                std::unique_ptr<Device> device = std::move(*it);
                ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
                event->when = now;
                event->deviceId = (device->id == mBuiltInKeyboardId)
                        ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
                        : device->id;
                event->type = DEVICE_REMOVED;
                event += 1;
                it = mClosingDevices.erase(it);
                mNeedToSendFinishedDeviceScan = true;
                if (--capacity == 0) {
                    break;
                }
            }
    
            if (mNeedToScanDevices) {
                mNeedToScanDevices = false;
                scanDevicesLocked();
                mNeedToSendFinishedDeviceScan = true;
            }
    
            while (!mOpeningDevices.empty()) {
                std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());
                mOpeningDevices.pop_back();
                ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
                event->when = now;
                event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
                event->type = DEVICE_ADDED;
                event += 1;
    
                // Try to find a matching video device by comparing device names
                for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();
                     it++) {
                    std::unique_ptr<TouchVideoDevice>& videoDevice = *it;
                    if (tryAddVideoDeviceLocked(*device, videoDevice)) {
                        // videoDevice was transferred to 'device'
                        it = mUnattachedVideoDevices.erase(it);
                        break;
                    }
                }
    
                auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));
                if (!inserted) {
                    ALOGW("Device id %d exists, replaced.", device->id);
                }
                mNeedToSendFinishedDeviceScan = true;
                if (--capacity == 0) {
                    break;
                }
            }
    
            if (mNeedToSendFinishedDeviceScan) {
                mNeedToSendFinishedDeviceScan = false;
                event->when = now;
                event->type = FINISHED_DEVICE_SCAN;
                event += 1;
                if (--capacity == 0) {
                    break;
                }
            }
    
            // Grab the next input event.
            bool deviceChanged = false;
            while (mPendingEventIndex < mPendingEventCount) {
                const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
                if (eventItem.data.fd == mINotifyFd) {
                    if (eventItem.events & EPOLLIN) {
                        mPendingINotify = true;
                    } else {
                        ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                    }
                    continue;
                }
    
                if (eventItem.data.fd == mWakeReadPipeFd) {
                    if (eventItem.events & EPOLLIN) {
                        ALOGV("awoken after wake()");
                        awoken = true;
                        char wakeReadBuffer[16];
                        ssize_t nRead;
                        do {
                            nRead = read(mWakeReadPipeFd, wakeReadBuffer, sizeof(wakeReadBuffer));
                        } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(wakeReadBuffer));
                    } else {
                        ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
                              eventItem.events);
                    }
                    continue;
                }
    
                Device* device = getDeviceByFdLocked(eventItem.data.fd);
                if (device == nullptr) {
                    ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
                          eventItem.data.fd);
                    ALOG_ASSERT(!DEBUG);
                    continue;
                }
                if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {
                    if (eventItem.events & EPOLLIN) {
                        size_t numFrames = device->videoDevice->readAndQueueFrames();
                        if (numFrames == 0) {
                            ALOGE("Received epoll event for video device %s, but could not read frame",
                                  device->videoDevice->getName().c_str());
                        }
                    } else if (eventItem.events & EPOLLHUP) {
                        // TODO(b/121395353) - consider adding EPOLLRDHUP
                        ALOGI("Removing video device %s due to epoll hang-up event.",
                              device->videoDevice->getName().c_str());
                        unregisterVideoDeviceFromEpollLocked(*device->videoDevice);
                        device->videoDevice = nullptr;
                    } else {
                        ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
                              device->videoDevice->getName().c_str());
                        ALOG_ASSERT(!DEBUG);
                    }
                    continue;
                }
                // This must be an input event
                if (eventItem.events & EPOLLIN) {
                    int32_t readSize =
                            read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
                    if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                        // Device was removed before INotify noticed.
                        ALOGW("could not get event, removed? (fd: %d size: %" PRId32
                              " bufferSize: %zu capacity: %zu errno: %d)\n",
                              device->fd, readSize, bufferSize, capacity, errno);
                        deviceChanged = true;
                        closeDeviceLocked(*device);
                    } else if (readSize < 0) {
                        if (errno != EAGAIN && errno != EINTR) {
                            ALOGW("could not get event (errno=%d)", errno);
                        }
                    } else if ((readSize % sizeof(struct input_event)) != 0) {
                        ALOGE("could not get event (wrong size: %d)", readSize);
                    } else {
                        int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
    
                        size_t count = size_t(readSize) / sizeof(struct input_event);
                        for (size_t i = 0; i < count; i++) {
                            struct input_event& iev = readBuffer[i];
                            event->when = processEventTimestamp(iev);
                            event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);
                            event->deviceId = deviceId;
                            event->type = iev.type;
                            event->code = iev.code;
                            event->value = iev.value;
                            event += 1;
                            capacity -= 1;
                        }
                        if (capacity == 0) {
                            // The result buffer is full.  Reset the pending event index
                            // so we will try to read the device again on the next iteration.
                            mPendingEventIndex -= 1;
                            break;
                        }
                    }
                } else if (eventItem.events & EPOLLHUP) {
                    ALOGI("Removing device %s due to epoll hang-up event.",
                          device->identifier.name.c_str());
                    deviceChanged = true;
                    closeDeviceLocked(*device);
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
                          device->identifier.name.c_str());
                }
            }
    
            // readNotify() will modify the list of devices so this must be done after
            // processing all other events to ensure that we read all remaining events
            // before closing the devices.
            if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
                mPendingINotify = false;
                readNotifyLocked();
                deviceChanged = true;
            }
    
            // Report added or removed devices immediately.
            if (deviceChanged) {
                continue;
            }
    
            // Return now if we have collected any events or if we were explicitly awoken.
            if (event != buffer || awoken) {
                break;
            }
    
            // Poll for events.
            // When a device driver has pending (unread) events, it acquires
            // a kernel wake lock.  Once the last pending event has been read, the device
            // driver will release the kernel wake lock, but the epoll will hold the wakelock,
            // since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait
            // is called again for the same fd that produced the event.
            // Thus the system can only sleep if there are no events pending or
            // currently being processed.
            //
            // The timeout is advisory only.  If the device is asleep, it will not wake just to
            // service the timeout.
            mPendingEventIndex = 0;
    
            mLock.unlock(); // release lock before poll
    
            int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    
            mLock.lock(); // reacquire lock after poll
    
            if (pollResult == 0) {
                // Timed out.
                mPendingEventCount = 0;
                break;
            }
    
            if (pollResult < 0) {
                // An error occurred.
                mPendingEventCount = 0;
    
                // Sleep after errors to avoid locking up the system.
                // Hopefully the error is transient.
                if (errno != EINTR) {
                    ALOGW("poll failed (errno=%d)\n", errno);
                    usleep(100000);
                }
            } else {
                // Some events occurred.
                mPendingEventCount = size_t(pollResult);
            }
        }
    
        // All done, return the number of events we read.
        return event - buffer;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256

    drivers/input/evdev.c

    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;
    	size_t read = 0;
    	int error;
    
    	if (count != 0 && count < input_event_size())
    		return -EINVAL;
    
    	for (;;) {
    		if (!evdev->exist || client->revoked)
    			return -ENODEV;
    
    		if (client->packet_head == client->tail &&
    		    (file->f_flags & O_NONBLOCK))
    			return -EAGAIN;
    
    		/*
    		 * count == 0 is special - no IO is done but we check
    		 * for error conditions (see above).
    		 */
    		if (count == 0)
    			break;
    
    		while (read + input_event_size() <= count &&
    		       evdev_fetch_next_event(client, &event)) {
    
    			if (input_event_to_user(buffer + read, &event))
    				return -EFAULT;
    
    			read += input_event_size();
    		}
    
    		if (read)
    			break;
    
    		if (!(file->f_flags & O_NONBLOCK)) {
    			error = wait_event_interruptible(evdev->wait,
    					client->packet_head != client->tail ||
    					!evdev->exist || client->revoked);
    			if (error)
    				return error;
    		}
    	}
    
    	return read;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    7.1 evdev_fetch_next_event

    event_fetch_next_event:判断client->buffer这个循环缓冲区中的头尾指针是否相等(相等时buffer中没有数据),不相等时取出一个input_event类型的事件放入到event中

    drivers/input/evdev.c

    static int evdev_fetch_next_event(struct evdev_client *client,
    				  struct input_event *event)
    {
    	int have_event;
    
    	spin_lock_irq(&client->buffer_lock);
    
    	have_event = client->packet_head != client->tail;
    	if (have_event) {
    		*event = client->buffer[client->tail++];
    		client->tail &= client->bufsize - 1;
    	}
    
    	spin_unlock_irq(&client->buffer_lock);
    
    	return have_event;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.2 input_event_to_user

    input_event_to_user:将此事件copy到应用层,input_event_size函数是用来获取一个input_event事件的大小,循环复制client->buffer中的事件到应用层的buffer中

    drivers/input/input-compat.c

    #ifdef CONFIG_COMPAT
    
    int input_event_to_user(char __user *buffer,
    			const struct input_event *event)
    {
    	if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
    		struct input_event_compat compat_event;
    
    		compat_event.sec = event->input_event_sec;
    		compat_event.usec = event->input_event_usec;
    		compat_event.type = event->type;
    		compat_event.code = event->code;
    		compat_event.value = event->value;
    
    		if (copy_to_user(buffer, &compat_event,
    				 sizeof(struct input_event_compat)))
    			return -EFAULT;
    
    	} else {
    		if (copy_to_user(buffer, event, sizeof(struct input_event)))
    			return -EFAULT;
    	}
    
    	return 0;
    }
    
    #else
    
    int input_event_to_user(char __user *buffer,
    			const struct input_event *event)
    {
    	if (copy_to_user(buffer, event, sizeof(struct input_event)))
    		return -EFAULT;
    
    	return 0;
    }
    
    #endif /* CONFIG_COMPAT */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    参考文献

    https://www.kernel.org/doc/Documentation/input/input.txt
    Linux值输入子系统分析(详解)
    input输入子系统

  • 相关阅读:
    图文精灵升级离线版本
    JavaScript面试题整理(一)
    数商云经销商系统促销功能解析,灵活定义促销方案助力家居建材企业抢占市场
    SSM学习52:SSM三大技术整合案例
    Android 底部导航栏(三、ViewPager+TabLayout+Fragment)简单易懂
    Vert.X CompositeFuture 用法
    零基础如何入门Web性能测试?
    多线程编程
    No version of NDK matched the requested version xxx 问题解决
    深入了解 Axios 的 put 请求:使用技巧与最佳实践
  • 原文地址:https://blog.csdn.net/qq_23452385/article/details/132859426