Input子系统

input 就是输入的意思,因此 input 子系统就是管理输入的子系统,和 pinctrl、gpio 子系统

一样,都是 Linux 内核针对某一类设备而创建的框架。比如按键输入、键盘、鼠标、触摸屏等
等这些都属于输入设备,不同的输入设备所代表的含义不同,按键和键盘就是代表按键信息,
鼠标和触摸屏代表坐标信息,因此在应用层的处理就不同,对于驱动编写者而言不需要去关心
应用层的事情,我们只需要按照要求上报这些输入事件即可。

统一管理外部输入设备

- 按键
- 键盘
- 鼠标
- 触摸屏

对应的用户空间接口

- /dev/input/event0/1/2/...
- /dev/input/mouse0/1/2/...
- /dev/input/sj0/1/2/...
- ...


input子系统软件框架

linux input输入子系统分析《四》:input子系统整体流程全面分析_比特人生的博客-CSDN博客主要讲述本人在学习Linux内核input子系统的全部过程,如有分析不当,多谢指正。以下方式均可联系,文章欢迎转载,保留联系信息,以便交流。邮箱:eabi010@gmail.com主页:www.ielife.cn(爱嵌论坛——嵌入式技术学习交流)博客:blog.csdn.net/ielife1      input输入子系统整体流程本节分析input子系统在内核中的https://blog.csdn.net/ielife/article/details/7814108上面这篇一定要看!

input 子系统(evdev,input_core,input_handler,input_dev)_carl_wang_123的博客-CSDN博客文章目录概述input-coreinput_dev 以及handlerinput_eventevbug关于slot A/B协议(本段为摘抄)常用写input 驱动的步骤测试代码(ubuntu16.04下测试通过)驱动代码应用代码概述input子系统框架图1.input-core 输入核心2.input-event-dev 输入事件驱动程序3.input-driver 输入设备驱动程...https://blog.csdn.net/u013256018/article/details/105257846

在这里插入图片描述

input子系统的核心

一个输入事件,如手指触摸,键盘按键按下,横竖屏转动等等通过1. input driver -> 2.Input core -> 3.Event handler -> userspace 到达用户空间传给应用程序

  1.  设备驱动层:对应 input_dev结构体 负责读取原始数据,如触摸屏的驱动,g_sensor的驱动等。

调用核心层input.c提供的接口,注册输入设备、上报事件

  2.输入子系统核心层(input core):其对下提供了设备驱动的接口,对上提供了事件处理层的编程接口。创建了input class。

输入核心层input.c提供了注册设备驱动以及事件驱动的API接口。

维护着事件驱动的链表(input_handler_list)以及设备驱动的链表(input_dev_list)!

  3.  事件处理层(event handler)对应input_handler结构体 负责将事件上报,将键值、坐标等数据上报的对应的设备节点,也就是上报给应用程序。(Linux中在用户空间将所有的设备都当初文件来处理,由于在一般的驱动程序中都有提供fops接口,以及在/dev下会生成相应的设备文件nod,这些操作在输入子系统中由事件处理层完成)

  - 通用事件处理器(drivers/input/evdev.c)

  - 鼠标事件处理器(drivers/input/mousedev.c)
  - 摇杆事件处理器(drivers/input/joydev.c)等 (常使用的是通用事件处理器)

对应input_handler,负责创建设备节点,负责和应用层进行数据交互以及上报
设备驱动与事件驱动通过id_table进行match,match之后通过connect函数创建事件驱动,事件驱动负责创建设备节点,提供open,close 等文件操作函数包括/dev/input/eventX,或者mouse等,然后通过input_handle进行绑定。维护着client(上层用户)的链表,将数据传递给用户层以及每一个打开文件的client


在核心层 也就是input.c 文件中有如下代码:

input.c 编译进了内核,只要系统启动就会运行input.c中的程序,就会执行到下面的代码,在/dev/目录下创建 一个input目录 主设备号为13

struct class input_class{
    .name = "input",
    .devnode = input_devnode,
};
……
static int __init input_init(void){
    int err;
    err = class_register(&input_class);
    if(err){
        pr_err(unable to register input_dev clsaa!\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;
}
#define INPUT_MAJOR        13

可见核心层向内核注册了一个主设备号为13的驱动程序,但没有创建设备节点。也没有注册cdev结构体到内核中,也就是没有绑定cdev和指定的次设备号范围,也可以说没有绑定主设备号为13的设备节点和对应的驱动程序

input 核心层(也就是 drivers/input/input.c 这个文件)会向 Linux 内核注册一个字符设备驱程序对应主设备号为13 !

input 子系统的所有input设备主设备号都为 13 ,我们在使用 input 子系统处理输入设备
的时候就不需要去注册字符设备驱动程序了,只需要向系统注册一个 input_device 既具体设备对应的设备节点即可。
也就是说  根据input设备来注册的设备节点 主设备号已经定下来是13了 !
(也就是说在input.c中 就已经调用register_chrdev_region()在chrdevs数组中 添加了chrdevs[13]这个数组成员了)

如下图所示:

输入事件是标准的,对于所有输入设备都应该是可以用的,要实现的是输入设备驱动程序。输入设备驱动程序可以选择合适的输入事件驱动程序,通过输入核心以及输入事件驱动程序,向用户层输入数据
通俗讲解:
输入核心:输入核心提供了注册设备驱动以及事件驱动的API,维护着事件驱动的链表以及设备驱动的链表
设备驱动 :对应input_dev 负责实际的设备数据读取,通过input core 将数据传递到事件驱动程序,上报给用户层
事件驱动:对应input_handler,负责创建设备节点,负责和应用层进行数据交互以及上报
设备驱动与事件驱动通过id_table进行match,match之后通过connect函数创建事件驱动,事件驱动负责创建设备节点,提供open,close 等文件操作函数包括/dev/input/eventX,或者mouse等,然后通过input_handle进行绑定。维护着client(上层用户)的链表,将数据传递给用户层以及每一个打开文件的client
 


input_dev和input_handler 以及input_handle

Linux input子系统分析之二 相关数据结构及其关联说明_jerry_chg的博客-CSDN博客在上一章我们介绍了input子系统的总体框架,本章则主要说明input相关的数据结构结构,以及这些数据结构之间的关联。对于linux内核而言,只要我们理解了其数据结构之间的关联,基本上也就大致了解其子系统的实现。一、input子系统数据结构及其关联 针对input子系统而言,其数据结构主要包括input_device、input_handler、input_handle,其中input_dev用于对一个input device的抽象,而一个input_handler则可...https://jerry-cheng.blog.csdn.net/article/details/106449071?spm=1001.2014.3001.5502

1.input_dev

类似于platform_device 用来描述输入设备

Input_dev的定义如下,主要包括如下几个部分:

  1. evbit、keybit、relbit、absbit等变量标识该input device的类型、支持事件的code类型等;
  2. keycode相关的参数及函数指针等;
  3. *** open、event、close、flush为操作接口,如针对event则处理input_handler发送的事件,一般input设备而言,都是input_dev将接收的事件发送给input_handler,而针对led灯这类设备,需要处理input_handler发送的event,用于进行led灯的控制;***也就是说一般来说是 input_dev上报事件给Input_handler然后调用 input_handler中的函数接口 但是比如LED灯控制就是特殊情况 需要input_handler给 input_dev 发送event 也就是使用Input_dev的event接口)
  4. users、going_away为该input device的打开及关联相关的引用计数及状态;
  5. num_vals、max_vals、vals、hint_events_per_packet则表示该input_dev单次分发事件时可发送的最大事件数、当前事件数、存储待分发事件的缓存等内容;
  6. 针对grab变量。其实现input_device与input_handle的1对1绑定操作,若执行了该操作,则所有该input_device产生的事件,则只分发给其绑定的input_handle对应的input_handler,而不再分发给其他的input_handler。若需要执行该绑定操作,则通过EVIOCGRAB ioctl命令即可设置。
     
struct input_dev {
 
	void *private;				//输入设备私有指针,一般指向用于描述设备驱动层的设备结构
 
	const char *name;			//提供给用户的输入设备的名称
	const char *phys;			//提供给编程者的设备节点的名称
	const char *uniq;			//指定唯一的ID号,就像MAC地址一样
	struct input_id id;			//输入设备标识ID,用于和事件处理层进行匹配
 
	unsigned long evbit[NBITS(EV_MAX)];		//位图,记录设备支持的事件类型
	unsigned long keybit[NBITS(KEY_MAX)];		//位图,记录设备支持的按键类型
	unsigned long relbit[NBITS(REL_MAX)];		//位图,记录设备支持的相对坐标
	unsigned long absbit[NBITS(ABS_MAX)];		//位图,记录设备支持的绝对坐标
	unsigned long mscbit[NBITS(MSC_MAX)];	//位图,记录设备支持的其他功能
	unsigned long ledbit[NBITS(LED_MAX)];		//位图,记录设备支持的指示灯
	unsigned long sndbit[NBITS(SND_MAX)];		//位图,记录设备支持的声音或警报
	unsigned long ffbit[NBITS(FF_MAX)];		//位图,记录设备支持的作用力功能
	unsigned long swbit[NBITS(SW_MAX)];		//位图,记录设备支持的开关功能
 
	unsigned int keycodemax;		//设备支持的最大按键值个数
	unsigned int keycodesize;		//每个按键的字节大小
	void *keycode;				//指向按键池,即指向按键值数组首地址
	int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);	//修改按键值
	int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);	//获取按键值
 
	struct ff_device *ff;			//用于强制更新输入设备的部分内容
 
	unsigned int repeat_key;		//重复按键的键值
	struct timer_list timer;		//设置当有连击时的延时定时器
 
	int state;		//设备状态
 
	int sync;		//同步事件完成标识,为1说明事件同步完成
 
	int abs[ABS_MAX + 1];		//记录坐标的值
	int rep[REP_MAX + 1];		//记录重复按键的参数值
 
	unsigned long key[NBITS(KEY_MAX)];		//位图,按键的状态
	unsigned long led[NBITS(LED_MAX)];		//位图,led的状态
	unsigned long snd[NBITS(SND_MAX)];		//位图,声音的状态
	unsigned long sw[NBITS(SW_MAX)];			//位图,开关的状态
 
	int absmax[ABS_MAX + 1];					//位图,记录坐标的最大值
	int absmin[ABS_MAX + 1];					//位图,记录坐标的最小值
	int absfuzz[ABS_MAX + 1];					//位图,记录坐标的分辨率
	int absflat[ABS_MAX + 1];					//位图,记录坐标的基准值
 
	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 *grab;		//类似私有指针,可以直接访问到事件处理接口event
 
	struct mutex mutex;		//用于open、close函数的连续访问互斥
	unsigned int users;		//设备使用计数
 
	struct class_device cdev;	//输入设备的类信息
	union {				//设备结构体
		struct device *parent;
	} dev;
 
	struct list_head	h_list;	用来挂接input_dev 设备连接的所有handle 的一个链表头
	struct list_head	node;	//input_dev链表
};

1.h_list成员

struct list_head h_list 是一个链表头,这个链表头对应的链表上挂载了所有和该input_dev结构体相对应的input_handle结构体(这个链表是用来保存所有和这个input_dev结构体对应的input_handle结构体的,每个节点都对应一个input_handle结构体)input_handle结构体是如何挂载在这个链表上的呢?通过input_handle的d_node成员(它是一个struct list_head d_node)作为链表的节点挂载在链表上

2.node成员

内核链表是将链表嵌入数据结构!list_head node成员 是该input_dev结构体在input_dev_list中对应的链表节点

有个问题:input_dev中的 open、close函数有什么用?

2.input_handler

*****(通常来说不需要我们创建input_handler,我们一般使用内核自带的input_handler,比如evdev_handler:evdev_handler是最常用的input_handler ,它可以对应所有的 input_dev ,也就是说可以对应所有的输入设备,所以在我们后面的编写输入设备驱动时 不需要创建input_handler 只需要创建注册input_dev和上报事件给evdev_handler就可以了。我们只需要使用evdev.c中实现的evdev_handler就足够了,也就是说我们创建的input_dev会和 evdev_handler 匹配 成功后调用其中的evdev_connect函数!

类似于platform_driver 描述事件

  1. Input_handler可以理解为input_device的方法/驱动,下面我们详细说明;
  2. event、events接口用于接收input_device上报的事件,并处理这些事件(如将这些事件发送给应用程序)一般来说是 input_dev上报事件给Input_handler然后调用 input_hand
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值