Linux内核(十四)Input 子系统详解 I —— 子系统介绍以及相关结构体解析

news2024/11/24 6:16:09

文章目录

    • 概述
    • input 子系统框架
    • input 子系统相关结构体介绍
      • input_dev结构体
      • input_handler结构体
      • input_handle结构体
      • Evdev事件相关结构体
      • input_event结构体(标准按键编码信息)
      • 设备相关信息结构体


概述

  • input子系统就是管理输入的子系统,和Linux其他子系统一样,都是Linux内核针对某一类设备而创建的框架。
  • 鼠标、键盘、触摸屏等都属于输入设备,Linux将这些设备的共同特性抽象出来,这就形成了input子系统的框架。
  • Linux内核只需要通过input框架向用户层上报输入事件(如:按键值,坐标等),不需要关心应用层的事情
  • 输入设备本质上就是字符设备,经过input框架后,最终给用户空间提供可以访问的设备节点

input 子系统框架

在这里插入图片描述
Linux Input 子系统框架

硬件输入设备: 最底层具体设备(如:触摸屏、键盘、鼠标等)

内核空间:

  • 驱动层: 输入设备的具体驱动程序。负责将底层的硬件输入转化为统一的事件形式,向input核心层传达。
  • 核心层: 连接驱动层和事件层之间。负责双向提供接口,向下提供驱动层接口,向上提供事件处理的接口。
  • 事件层: 底层的设备抽象出对应的接口提供给应用层。将底层设备的触发的事件通过这个接口传达给应用层。

input 子系统相关结构体介绍

input_dev结构体

input_dev结构体是硬件驱动层,代表一个input设备。
最底层具体设备,都会抽象出一个input_dev结构体。

// include/linux/input.h 
struct input_dev {
    const char *name;            /* 设备名称 */
    const char *phys;            /* 设备在系统中的路径 */
    const char *uniq;            /* 设备唯一id */
    struct input_id id;          /* input设备id号 */

    unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; 

    unsigned long evbit[BITS_TO_LONGS(EV_CNT)];        /* 设备支持的事件类型,主要有EV_SYNC,EV_KEY,EV_KEY,EV_REL,EV_ABS等*/    
    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)];        /* 支持led事件 */
    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;        /* 设备关联的反馈结构,如果设备支持 */

    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)];    /* 反应设备当前的led状态 */
    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);    /* 事件处理函数,主要是接收用户下发的命令,如点亮led */

    struct input_handle __rcu *grab;        /* 当前占有设备的input_handle */

    spinlock_t event_lock;        /* 事件锁 */
    struct mutex mutex;            /* 互斥体 */

    unsigned int users;        /* 打开该设备的用户数量(input_handle) */
    bool going_away;            /* 标记正在销毁的设备 */

    struct device dev;        /* 一般设备 */

    struct list_head    h_list;        /* 设备所支持的input handle */
    struct list_head    node;        /* 用于将此input_dev连接到input_dev_list */

    unsigned int num_vals;        /* 当前帧中排队的值数 */
    unsigned int max_vals;        /*  队列最大的帧数*/
    struct input_value *vals;    /*  当前帧中排队的数组*/

    bool devres_managed;        /* 表示设备被devres 框架管理,不需要明确取消和释放*/
};

Linux下设备支持的事件类型:

编码事件描述
EV_SYN0x00同步事件
EV_KEY0x01按键事件(鼠标,键盘等)
EV_REL0x02相对坐标(如:鼠标移动,报告相对最后一次位置的偏移)
EV_ABS0x03绝对坐标(如:触摸屏或操作杆,报告绝对的坐标位置)
EV_MSC0x04其它
EV_SW0x05开关
EV_LED0x11按键/设备灯
EV_SND0x12声音/警报
EV_REP0x14重复
EV_FF0x15力反馈
EV_PWR0x16电源
EV_FF_STATUS0x17力反馈状态
EV_MAX0x1f事件类型最大个数和提供位掩码支持

Linux下定义按键值(列出部分):

#define KEY_RESERVED        0
#define KEY_ESC         1
#define KEY_1           2
#define KEY_2           3
#define KEY_3           4
#define KEY_4           5
#define KEY_5           6
#define KEY_6           7
#define KEY_7           8
#define KEY_8           9
#define KEY_9           10
#define KEY_0           11

input_handler结构体

input_handler结构体是事件层,代表一个事件处理器。

// include/linux/input.h 
struct input_handler {

    void *private;        /* 存放handle数据 */

    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;        /* input_dev匹配用的id */

    struct list_head    h_list;    /* 用于链接和handler相关的handle,input_dev与input_handler配对之后就会生成一个input_handle结构 */
    struct list_head    node;    /* 用于将该handler链入input_handler_list,链接所有注册到内核的所有注册到内核的事件处理器 */
};

input_handle结构体

input_handle结构体属于核心层,代表一个配对的input设备与input事件处理器。

// include/linux/input.h 
struct input_handle {

    void *private;                /* 数据指针 */

    int open;                    /* 打开标志,每个input_handle 打开后才能操作 */
    const char *name;            /* 设备名称 */

    struct input_dev *dev;            /* 指向所属的input_dev */
    struct input_handler *handler;    /* 指向所属的input_handler */

    struct list_head    d_node;        /* 用于链入所指向的input_dev的handle链表 */
    struct list_head    h_node;        /* 用于链入所指向的input_handler的handle链表 */
};

以上三个结构体在input子系统扮演重要角色,从结构体成员能看出有两个链表。
input_dev和input_handler链表。三张表连接图如下。

在这里插入图片描述
input-dev 、 input-handler、input-handle三结构体关系

input_dev和input_handler各自内部链表图
在这里插入图片描述

  • input_handler 通过全局的input_handler_list链接在一起。

  • input_hande 没有一个全局的链表,它注册的时候将自己分别挂在了input_dev 和 input_handler 的h_list上了。

  • 通过input_dev 和input_handler就可以找到input_handle在设备注册和事件处理器,注册的时候都要进行配对工作,配对后就会实现链接。

  • 通过input_handle也可以找到input_dev和input_handler。input_handle是用来关联input_dev和input_handler的。


Evdev事件相关结构体

1、Evdev(字符设备事件)结构体

/* drivers/input/evdev.c */
struct evdev {
        int open;    /* 设备被打开的计数 */
        struct input_handle handle;  /* 关联的input_handle */ 
        wait_queue_head_t wait;  /* 等待队列,当前进程读取设备,没有事件产生时,
进程就会sleep */
        struct evdev_client __rcu *grab;  /* event响应 */
struct list_head client_list;  /* evdev_client链表,说明evdev设备可以处理多个 evdev _client,可以有多个进程访问evdev设备 */
        spinlock_t client_lock;
        struct mutex mutex;
        struct device dev;
        struct cdev cdev;
        bool exist;   /* 设备存在判断 */
};

2、evdev_client(字符设备事件响应)结构体

struct evdev_client {
    unsigned int head;                 /* 动态索引,每加入一个event到buffer中,head++ */
    unsigned int tail;                /* 动态索引,每取出一个buffer中到event,tail++ */
    unsigned int packet_head;         /* 数据包头部 */
    spinlock_t buffer_lock; 
    struct fasync_struct *fasync;     /* 异步通知函数 */
    struct evdev *evdev;
    struct list_head node;            /* evdev_client链表项 */
    int clkid;
    bool revoked;
    unsigned int bufsize;
    struct input_event buffer[];        /* 用来存放input_dev事件缓冲区 */
};

3、evdev_handler(事件处理函数)结构体

/* drivers/input/input.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", /* handler名称 */
        .id_table    = evdev_ids, /* 断开该链接 */
};

input_event结构体(标准按键编码信息)

/* drivers/input/evdev.c */
struct input_event {                                                            
    struct timeval time;   /* 事件发生的时间  */                                
    __u16 type;             /* 事件类型 */                                      
    __u16 code;             /* 事件码 */                                        
    __s32 value;            /* 事件值 */                                        
}; 

设备相关信息结构体

/* include/uapi/linux/input.h */
struct input_id {  
    __u16 bustype;  /* 总线类型 */  
    __u16 vendor;  /* 生产厂商 */  
    __u16 product;  /* 产品类型 */ 
    __u16 version;  /* 版本 */
 };
/* include/uapi/linux/input.h */
struct input_device_id {

        kernel_ulong_t flags;

        __u16 bustype;  /* 总线类型 */
        __u16 vendor;  /* 生产厂商 */
        __u16 product;  /* 产品类型 */
        __u16 version;  /* 版本 */

        kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t propbit[INPUT_DEVICE_ID_PROP_MAX / BITS_PER_LONG + 1];

        kernel_ulong_t driver_info;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/477239.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML中的常用标签

HTML中的常用标签 🔎注释标签🔎标题标签🔎段落标签🔎换行标签🔎格式化标签🔎图片标签🔎超链接标签🔎表格标签合并单元格 🔎列表标签无序列表有序列表自定义列表 &#x1…

新手如何快速学会Python?

在本文中,我们将介绍如何有效地学习 Python 。你应该知道「数据科学」是用于解决、探究问题并从数据中提取有价值信息的科学。 为了有效地做到这一点,你需要整理数据集、训练机器学习模型、可视化结果等等。 这是学习 Python 的最佳时机。 事实上&#x…

【五一创作】数据可视化之美 ( 三 ) - 动图展示 ( Python Matlab )

1 Introduction 在我们科研学习、工作生产中,将数据完美展现出来尤为重要。 数据可视化是以数据为视角,探索世界。我们真正想要的是 — 数据视觉,以数据为工具,以可视化为手段,目的是描述真实,探索世界。 …

[创新工具和方法论]-01- DOE课程基础知识

文章目录 1.DOE实验设计的介绍1.1 什么是实验设计DOE?1.2 DOE的优势有哪些?1.3 如何开展DoE研究?步骤 2.DOE实验培训3.数据分析步骤4.实验的随机化5.偏差6.R方 相关系数假设检验 7.三因子二水平全因子设计 1.DOE实验设计的介绍 实验设计是一种安排实验和分析实验数…

【网络进阶】服务器模型Reactor与Proactor

文章目录 1. Reactor模型2. Proactor模型3. 同步IO模拟Proactor模型 在高并发编程和网络连接的消息处理中,通常可分为两个阶段:等待消息就绪和消息处理。当使用默认的阻塞套接字时(例如每个线程专门处理一个连接),这两…

Ubantu docker学习笔记(八)私有仓库

文章目录 一、建立HTTPS链接1.在仓库服务器上获取TLS证书1.1 生成证书颁发机构证书1.2 生成服务器证书1.3 利用证书运行仓库容器 2.让私有仓库支持HTTPS3.客户端端配置 二、基本身份验证三、对外隐藏仓库服务器3.1 在服务器端3.2 在客户端进行 四、仓库可视化 在前面的学习中&a…

数据库三范式与反范式详解

🏆今日学习目标: 🍀数据库三范式与反范式详解 ✅创作者:林在闪闪发光 ⏰预计时间:30分钟 🎉个人主页:林在闪闪发光的个人主页 🍁林在闪闪发光的个人社区,欢迎你的加入: 林…

阿里云服务器通用算力u1性能测评CPU处理器网络PPS

阿里云服务器u1通用算力型Universal实例高性价比,CPU采用Intel(R) Xeon(R) Platinum,主频是2.5 GHz,云服务器U1实例的基准vCPU算力与5代企业级实例持平,最高vCPU算力与6代企业级实例持平,提供2c-32c规格和1:1/2/4/8丰富…

贪心算法讲解

文章目录 1. 贪心算法的概念2. 讲解贪心 1. 贪心算法的概念 贪心算法是:用一种局部最功利的标准,总是做出当前看来是最好的选择。如果局部最优解可以得出全局最优解,说明贪心假设成立,否则就失败。 举个例子: 这里有…

尚融宝26-投标

目录 一、需求 (一)投资人投标 (二)流程 二、标的详情 (一)需求 (二)后端 (三)前端 三、计算收益 (一)四种还款方式 &#…

基于 A* 搜索算法来优化无线传感器节点网络的平均电池寿命(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 💥1 概述 A*(念做:A Star)算法是一种很常用的路径查找和图形遍历算法。它有较好的性能和准确度。本文…

一篇带你快速入门DDD领域驱动设计

一、什么是领域驱动 领域驱动设计 Domain-Driven Design,简称DDD。软件对于行业并没有这么高的要求,他本身就是帮助其他行业更好的发展,赋能其他行业的。各个行业都有软件的身影,但是他们的业务场景是不同的,所以就需…

【MYSQL】数据类型和约束

目录 数据类型 1.数值类型 1.1.位--类型bit(M) 1.2. 整数类型--tinyint,smallint,int,bigint 1.3.小数类型--float、decimal 2.字符类型--char、varchar 3.日期类型--datetime、timestamp 4.string类型--enum和set mysql的约束 1.空…

Mybatis 知识总结2(基于注解的增删改查操作)

3.3 MyBatis 增删改查(注解方式) MyBatis 的增删改查是最基础最核心的功能,需要重点掌握。 需求说明 对员工信息进行增删改查操作。 查询(查询结果分页展示后续实现) 根据主键ID查询根据条件查询 新增更新删除 根据主…

海思芯片(hi3536av100)启动模式选择

1、支持多种模式可配置 (1)支持BootRom启动 (2)支持从 SPI NOR Flash 启动 (3)支持从 SPI NAND Flash 启动 (4)支持从 eMMC 启动 (5)支持 PCIe 从片启动 2、启动方式的选择 BOOT_SEL[1:0]SFC_EMMC_BOOT_MODEMODE000SPI Nor Flash 3 Byte001SPI Nor Flash 4 Byte010SPI Nand Fl…

2005-2020全国及各省家庭承包耕地流转总面积及经营耕地面积

2005-2020全国及各省家庭承包耕地流转总面积及经营耕地面积 1、时间:时间:2005-2020年 2、范围:包括全国及30个省份不包括西藏 3、指标包括:家庭承包耕地流转总面积(亩)、家庭承包经营耕地面积(亩) 4、来源:农村经…

荔枝派Zero(全志V3S) tftp下载 kernel 和 nfs 挂载文件系统

文章目录 前言一、U-Boot 适配 Ethernet1、配置 U-Boot2、修改 dts 文件3、编译4、烧写到 SD 卡5、测试<1>、查看启动打印信息<2>、ping 测试 二、Kernel 适配 Ethernet1、配置 kernel2、修改 dts 文件3、编译4、拷贝到 SD 卡5、测试<1>、启动网络接口&#…

【嵌入式环境下linux内核及驱动学习笔记-(7-内核 I/O)-多路复用】

目录 2、多路复用2.1 函数select相关2.1.1 应用层select()2.1.2 FD_ZERO2.1.3 FD_SET2.1.4 FD_ISSET 2.2 函数poll相关2.2.1 poll函数 2.3 驱动层 函数2.4 实例 接上篇&#xff0c;继续内核 I/O的五种模式的解读。 2、多路复用 select&#xff0c;poll&#xff0c;epoll都是IO…

常见的接口优化技巧思路

一、背景 针对老项目&#xff0c;去年做了许多降本增效的事情&#xff0c;其中发现最多的就是接口耗时过长的问题&#xff0c;就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案。 二、接口优化方案总结 1.批处理 批量思想&#xff1a;批量操作数据…

windows如何确认服务器上程序端口是否正常

方式1&#xff1a;ping命令 ping命令说明 ping命令是个使用频率极高的网络诊断工具&#xff0c;在Windows、Unix和Linux系统下均适用。它是TCP/IP协议的一部分&#xff0c;用于确定本地主机是否能与另一台主机交换数据报。根据返回的信息&#xff0c;我们可以推断TCP/IP参数设…