Linux驱动---输入子系统

1.概述

1.1 什么叫做输入子系统

        简单来说,输入子系统就是统一各种各样的输入设备的系统;

        常见的输入设备比如: 键盘、触摸屏、按键、鼠标。

1.2 为什么要引入输入子系统

        每个人写驱动代码都有自己的风格和习惯,导致代码会有一定的差异,举个简单的例子:

同样的人写一个驱动,当按键按下时,有人给应用层返回1,有些人就会返回0;

        输入子系统就是为了统一这个输入。当按键按下去之后 ,驱动层不直接给应用层返回一个信息,而是告诉输入子系统,由输入子系统做了统一之后再告诉应用层。

2.相关API

2.1 向内核注册一个输入子系统

函数的头文件: <linux/input.h>

函数的原型:int input_register_device(struct input_dev *dev)

函数的参数:struct input_dev *dev:输入子系统的核心的结构体

函数的返回值:

        成功返回 0     

        失败返回  非零

2.2 输入子系统的核心结构体的注册

这个结构体不允许自己定义,需要通过内核注册;

函数的头文件:<linux/input.h>

函数的原型:struct input_dev *input_allocate_device(void)

函数的参数:无

函数的返回值:

        成功返回 输入子系统的核心结构体的指针

        失败返回 NULL

下边是输入子系统的核心结构体,可以看到里面包含的内容非常多,所以需要向内核注册。

struct input_dev {

        const char *name;   //设备名(sys目录下的设备)

        const char *phys;   //sys目录下的设备路径  不需要用户填充

        const char *uniq;  //设备的唯一识别码

        struct input_id id;  //用于匹配事件处理层handler(事件处理者)

        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;

        unsigned int repeat_key;  //最近一次键值,用于连击

        struct timer_list timer;  //自动连击计时器

        int sync;   //最后一次同步后没有新的事件置1

        int abs[REP_CNT];  //当前各个坐标的值

        int rep[REP_CNT];  //自动连击的参数

        struct input_mt_slot *mt;

        int mtsize;

        int slot;

        int trkid;

        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)];//反映当前 beep 状态的位图

        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;

        bool sync;

        struct device dev;

        struct list_head h_list;//handle 链表

        struct list_head node;//input_dev 链表

};

evbit:支持的事件的类型

        set_bit(EV_KEY,evbit);    //表示设置事件为按键事件

        set_bit(EV_REP,evbit);    //表示设置的事件为重复事件

输入子系统支持的事件的宏定义:

        #define EV_SYN  0x00   //同步事件

        #define EV_KEY  0x01   //按键事件  使用的比较多

        #define EV_REL  0x02   //相对事件

        #define EV_ABS  33      //绝对事件

        #define EV_MSC  0x04  //其他事件

        #define EV_SW  0x05   //开关事件

        #define EV_LED  0x11   //按键LED灯事件

        #define EV_SND 0x12   //按键声音事件

        #define EV_REP 0x14   //重复事件   比较常用的

        #define EV_FF  0x15  //力反馈事件

        #define EV_PWR 0x16 /*电源事件*/

        #define EV_FF_STATUS 0x17 /*受压状态*/

keybit:输入子系统支持的按键

        设置按键支持第一个按键:set_bit(KEY_1,keybit);

2.3 输入子系统事件的上报

函数的头文件:<linux/input.h>

函数的原型:

void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)

函数的参数:

        struct input_dev *dev:输入子系统的核心结构体

        unsigned int type:上报的事件的类型(EV_KEY  按键事件)

        unsigned int code, :按键   也就是是哪个按键(KEY_1 KEY_2)

        int value:按键的值

假如是按键事件:

        0:表示按键松开

        1:表示按键按下

函数的返回值:无

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

例如上报一个按键事件:

函数的头文件:<linux/input.h>

函数的原型:void input_report_key(struct input_dev *dev, unsigned int code, int value)

函数的参数:

        struct input_dev *dev:输入子系统的核心结构体

        unsigned int code:哪个按键

int value:

        0表示按键松开

        1表示按键按下

函数的返回:无

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

2.4 报告同步事件

函数的头文件: <linux/input.h>

函数的原型:void input_sync(struct input_dev *dev);

函数的参数:struct input_dev *dev:输入子系统的核心的结构体

函数的返回值:无

3.下边是练习的一个例子,仅供参考

内核层:

//内核层代码:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/timer.h>struct input_dev *myinput=NULL;
int my_irq;       //中断号
struct timer_list mytime;//定时器1回调函数
void my_fun(unsigned long data)
{int val=0;val=gpio_get_value(EXYNOS4_GPX3(2));if(val==0){//printk("按键按下了,事件上报1");input_report_key(myinput,KEY_1,1);}else if(val==1){//printk("按键松开了,事件上报0");input_report_key(myinput,KEY_1,0);}//报告同步事件input_sync(myinput);//printk("我被调用了\n");
}irqreturn_t func(int num, void *arg)
{	//定时器1mod_timer(&mytime, jiffies+msecs_to_jiffies(10)); //延时10msreturn 0;
}static int __init test_init(void)
{int ret,ret1;//定时器1mytime.expires=jiffies+msecs_to_jiffies(20); //20msmytime.function=my_fun;init_timer(&mytime);        //初始化定时器add_timer(&mytime);         //向内核注册一个定时器  并运行//1:中断号转换my_irq=gpio_to_irq(EXYNOS4_GPX3(2)); //key1//2:使能中断号enable_irq(my_irq);//3:注册中断ret1=request_irq(my_irq,func,IRQ_TYPE_EDGE_BOTH, "mykey", NULL);//向内核注册一个输入子系统myinput=input_allocate_device();//输入子系统的核心结构体的注册myinput->name="key";set_bit(EV_KEY,myinput->evbit);//表示设置事件为按键事件set_bit(EV_REP,myinput->evbit);//表示设置的事件为重复事件set_bit(KEY_1,myinput->keybit);//设置按键支持第一个按键ret=input_register_device(myinput);return 0;
}static void __exit test_exit(void)
{//取消注册input_unregister_device(myinput); 
}module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");

应用层:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>struct input_event mydata;
int main()
{int fd;fd=open("/dev/input/event3",O_RDWR);while(1){read(fd,&mydata,sizeof(mydata));if(mydata.code == 2){if(mydata.value == 1){printf("应用层:key1按下了\n");}else if(mydata.value == 0){printf("应用层:key1松开了\n");}}}return 0;
}

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

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

相关文章

qt面试经验

目录 1.qt底层原理2.connect的第五个参数3.信号槽的原理4.qt的智能指针QPointerQSharedPointerQScopedPointerQWeakPointerQSharedDataPointerQScopedArrayPointer 5.线程6.事件监听全局事件监听某一类控件的事件监听某一个控件的事件Qt的事件循环事件与信号的区别 7.设计模式单…

python工程打包为一个可执行的exe文件

文章目录 背景步骤安装 PyInstaller打包python脚本生成的文件特殊情况 示例 背景 打包一个Python工程为一个可执行的exe文件&#xff0c;效果是&#xff1a;打包完成之后&#xff0c;这个exe文件在没有python环境的电脑也能运行&#xff0c;不需要安装额外的环境 步骤 安装 P…

vscode添加代办相关插件,提高开发效率

这里写目录标题 前言插件添加添加TODO Highlight安装TODO Highlight在项目中自定义需要高亮显示的关键字 TODO Tree安装TODO Tree插件 单行注释快捷键 前言 在前端开发中&#xff0c;我们经常会遇到一些未完成、有问题或需要修复的部分&#xff0c;但又暂时未完成或未确定如何处…

kafka监控配置和告警配置

Kafka的监控配置和告警配置是确保Kafka集群稳定运行的关键部分。以下是一些关于Kafka监控配置和告警配置的建议&#xff1a; 一、Kafka监控配置 集群级别参数监控&#xff1a; log.retention.hours&#xff1a;用于控制消息在日志中保留的时间。监控此参数的值&#xff0c;确…

【MySQL精通之路】AdminAPI-使用

目录 1.使用 1.1 使用场景 1.2 使用模式 官方文档&#xff1a; MySQL :: MySQL Shell 8.0 :: 6.1 Using MySQL AdminAPI 本文介绍MySQL SHELL提供的MySQL AdminAPI&#xff0c;使您能够管理MySQL实例&#xff0c;使用它们创建InnoDB Cluster、InnoDB ClusterSet和InnoDB R…

合约的值类型

基本数据类型&#xff1a;整数、枚举、布尔&#xff08;类似java的数据类型&#xff09;Address、Contract&#xff08;这两种是solidity特有的数据类型&#xff09;Fixed byte array&#xff08;定长字节数组&#xff09; Integer(int/uint) int/uint 以8位字节递增&#xf…

推荐ChatGPT4.0——数学建模

1.建模助手 2. 可直接上传文档分析 3.获取途径 现在商家有活动&#xff0c;仅仅需要19.9&#xff01;&#xff01;&#xff01;&#xff01; 现在有优惠&#xff1a; 推荐人写&#xff1a;love 周卡&#xff0c;半月卡&#xff0c;月卡优惠码是love&#xff0c; 会优惠10元…

一篇讲透排序算法之插入排序and选择排序

1.插入排序 1.1算法思想 先将数组的第一个元素当作有序&#xff0c;让其后一个元素与其比较&#xff0c;如果比第一个元素小则互换位置&#xff0c;之后再将前两个元素当作有序的&#xff0c;让第三个元素与前两个元素倒着依次进行比较&#xff0c;如果第三个元素比第二个元素…

表现层框架设计之表现层设计模式_1.MVC模式

1.MVC模式三个核心模块 MVC是一种目前广泛流行的软件设计模式。近年来&#xff0c;随着Java EE的成熟&#xff0c;MVC成为了Java EE平台上推荐的一种设计模式。MVC强制性地把一个应用的输入、处理、输出流程按照视图、控制、模型的方式进行分离&#xff0c;形成了控制器…

Github上传时报错The file path is empty的解决办法

问题截图 文件夹明明不是空的&#xff0c;却怎么都上传不上去。 解决方案&#xff1a; 打开隐藏文件的开关&#xff0c;删除原作者的.git文件 如图所示&#xff1a; 上传成功&#xff01;

全面掌握深度学习:从基础到前沿

引言&#xff1a;深入探索深度学习的世界 在人工智能&#xff08;AI&#xff09;的广阔领域中&#xff0c;深度学习已经成为最令人瞩目的技术之一。它不仅推动了科技的许多突破性进展&#xff0c;也正在改变我们的工作和生活方式。本博客旨在全面总结深度学习的关键知识点&…

Rust面试宝典第14题:旋转数组

题目 给定一个数组&#xff0c;将数组中的元素向右移动k个位置&#xff0c;其中k是非负数。要求如下&#xff1a; &#xff08;1&#xff09;尽可能想出更多的解决方案&#xff0c;至少有三种不同的方法可以解决这个问题。 &#xff08;2&#xff09;使用时间复杂度为O(n)和空间…

4、设计模式之工厂模式

文章目录 开始之前简单工厂模式工厂方法模式抽象工厂模式总结 开始之前 本章节是一个系列&#xff0c;里面用的的代码实例都是连贯的。在实现某一种设计模式时&#xff0c;为了减少代码篇幅&#xff0c;前面博客出现model类&#xff08;仅限公用的model类&#xff0c;比如comp…

RAW转换和图像编辑工具:Capture One 23 Pro (win/mac)中文专业版

Capture One 23是一款功能强大的桌面版照片编辑软件&#xff0c;由丹麦PHASE ONE飞思数码公司开发。 以下是该软件的一些主要特点&#xff1a; 强大的RAW处理功能&#xff1a;Capture One 23支持多种品牌的相机和镜头&#xff0c;提供了丰富的RAW处理工具&#xff0c;包括曝光、…

安装ollama并部署大模型并测试

Ollama介绍 项目地址&#xff1a;ollama 官网地址&#xff1a; https://ollama.com 模型仓库&#xff1a;https://ollama.com/library API接口&#xff1a;api接口 Ollama 是一个基于 Go 语言开发的简单易用的本地大语言模型运行框架。可以将其类比为 docker&#xff08;同基…

基于Hadoop技术的智慧图书馆海量数据储存系统研究

基于Hadoop技术的智慧图书馆海量数据储存系统研究 “A study on the intelligent library’s massive data storage system based on Hadoop technology” 完整下载链接:基于Hadoop技术的智慧图书馆海量数据储存系统研究 文章目录 基于Hadoop技术的智慧图书馆海量数据储存系统…

【vue-3】动态属性绑定v-bind

1、文本动态绑定&#xff1a; <input type"text" v-bind:value"web.url"> 简写&#xff1a; <input type"text" :value"web.url"> 2、文字样式动态绑定 <b :class"{textColor:web.fontStatus}">vue学…

word页眉线如何置于文字上方

然后 敲黑板&#xff0c;点这里

为什么说kafka没办法保证数据不丢?

Kafka设计为高吞吐量和分布式环境中的数据流处理系统&#xff0c;但在某些情况下&#xff0c;它无法完全保证数据不丢失。这种情况可能由以下几个方面引起&#xff1a; Acknowledgment机制 Kafka的生产者在发送消息时&#xff0c;可以通过设置不同的acks参数来决定消息确认的…

SpringBoot前置知识01-SPI接口

SpringBoot前置知识-SPI接口 介绍 Java中SPI是一种服务发现机制&#xff0c;或者说是一种思想&#xff0c;亦是一种约定。其实JDK中的JDBC就是使用了这种用思想&#xff0c;JDBC在JDK中只定义了接口&#xff0c;并没有实现类&#xff0c;连接什么数据库就要引入什么数据库的驱…