Linux驱动学习之input子系统

news2024/11/24 8:50:12
  • 简介

  1. input 子系统就是管理输入的子系统,和pinctrl、gpio 子系统一样,都是 Linux 内核针对某一类设备而创建的框架。
  2. 按键、鼠标、键盘、触摸屏等都属于输入设备,linux内核为此专门做了一个叫做input子系统的框架来处理输入事件。
  3. 输入设备本质上还是字符设备,只是在此基础上套上了input框架,用户只需要负责上报输入事件,比如按键值、坐标等信息。
  4. 对于驱动编写者而言不需要去关心应用层的事情,我们只需要按照要求上报这些输入事件即可
  5. 为此input子系统分为 input驱动层、input 核心层、input 事件处理层,最终给用户空间提供可访问的设备节点

input子系统框架

                                         

编写input驱动我们只关心内核层,在内核层注册input子系统,然后进行事件上报就可以了。

  • input驱动实现 

  • 向内核注册input设备 

input子系统的所有设备主设备号都为 13,我们在使用input子系统处理输入设备的时候就不需要去注册字符设备了,我们只需要向系统注册一个input_device即可 

*****************input_dev****注册流程

  • 定义input_dev结构体
struct input_dev * input_dev;
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)];    //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;                    //设备关联的反馈结构,如果设备支持

	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)];    //反应设备当前的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 框架管理,不需要明确取消和释放

	ktime_t timestamp[INPUT_CLK_MAX];
}

  •  初始化input_dev结构体
input_dev=input_allocate_device();

 input_allocate_device()函数,给input_dev分配空间,并作了部分初始化。

  • 添加监测设备的信息
    set_bit(EV_KEY, input_dev->evbit);
    set_bit(EV_REP, input_dev->evbit);
    set_bit(KEY_1,input_dev->keybit);

事件类型

define EV_SYN            0x00    /* 同步事件     */ 
define EV_KEY            0x01    /* 按键事件     */ 
define EV_REL            0x02    /* 相对坐标事件   */ 
define EV_ABS            0x03    /* 绝对坐标事件   */ 
define EV_MSC            0x04    /* 杂项(其他)事件   */ 
define EV_SW             0x05    /* 开关事件     */ 
define EV_LED            0x11    /* LED       */ 
define EV_SND            0x12    /* sound(声音)   */ 
define EV_REP            0x14    /* 重复事件     */ 
define EV_FF             0x15    /* 压力事件     */ 
define EV_PWR            0x16    /* 电源事件     */ 
define EV_FF_STATUS      0x17    /* 压力状态事件   */ 

支持以下按键(部分) 

#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

向核心结构体里添加了按键,并且可连续触发,按键code为1。

  • 注册input设备
ret=input_register_device(input_dev);

参数为定义的input_dev结构体

返回值:成功0/失败非0

  • 上传事件
void input_event(struct input_dev *dev,
		 unsigned int type, unsigned int code, int value)

参数1:核心结构体,

参数2:事件类型,

参数3:事件编码,

参数4:事件值 

无返回值

  • 同步事件

此操作必须有,否则缓冲区不满,返回不了当前操作。

 void input_sync(struct input_dev *dev)

参数:核心结构体

无返回值

此函数也是调用了input_event(); 

代码实列

#include "linux/input.h"
#include "linux/gpio.h"
#include "linux/input-event-codes.h"
#include "linux/interrupt.h"
#include "linux/irq.h"
#include "linux/jiffies.h"
#include "linux/module.h"
#include "linux/of_gpio.h"
#include "linux/platform_device.h"
#include "linux/timer.h"
#include "linux/types.h"

int pin;
int irq;
struct input_dev * input_dev;
struct timer_list timer;
uint8_t value;
irqreturn_t fun_callback(int irq, void *arg)
{
     value=gpio_get_value(pin);
    mod_timer(&timer,jiffies+msecs_to_jiffies(10));
    return 0;
}
void func(struct timer_list *tl)
{
  
    if(value)
    {
        input_event(input_dev,EV_KEY,KEY_1,1);
    }
    else
    {
        input_event(input_dev,EV_KEY,KEY_1,0);
    }
    input_sync(input_dev);
}
static int probe(struct platform_device *pd)
{
    pin=of_get_named_gpio(pd->dev.of_node,"key_pin",0);
    printk("pin=%d\r\n",pin);
    gpio_request(pin,"key_pim");
    gpio_direction_input(pin);
    irq= platform_get_irq(pd,0);
    printk("irq=%d\r\n",irq);
    int ret=  devm_request_irq(&pd->dev, irq,fun_callback,IRQ_TYPE_EDGE_BOTH,"key_irq",NULL);
    if(ret)
    {

    }
    input_dev=input_allocate_device();
    set_bit(EV_KEY, input_dev->evbit);
    set_bit(EV_REP, input_dev->evbit);
    set_bit(KEY_1,input_dev->keybit);
    ret=input_register_device(input_dev);
    if(ret)
    {

    }
    timer_setup(&timer,func, 0);
    return 0;
}
struct of_device_id match={
    .compatible="key",

};
struct platform_driver drv={
    .driver = {
        .name = "key",
        .of_match_table=&match,
    },
    .probe=probe,
};
int __init input_init(void)
{
     
    return platform_driver_register(&drv);
}
void __exit input_exit(void)
{

}
module_init(input_init);
module_exit(input_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

day44——面向对象特征

一、封装 1.1 面向对象的三大特质 封装、继承、多态,如果问有四大特征,可以外加一个抽象 封装:将实现同一事物的所有的属性(成员变量)和行为(成员函数)封装到一个整体,我们称之为…

【Datawhale AI夏令营】从零上手CV竞赛Task2

文章目录 前言一、YOLO是什么?二、YOLO的历史三、性能指标四、 性能指标计算公式五、性能优化总结 前言 本文的Task2是对Task1的baseline代码进行优化的过程。 一、YOLO是什么? 首先简单介绍一下YOLO模型: 物体检测算法主要分为两类&#…

MSTP多实例生成树的配置

SW1配置: vlan batch 1 to 100 interface GigabitEthernet0/0/1 port link-type trunk port trunk allow-pass vlan 2 to 4094 interface GigabitEthernet0/0/2 port link-type trunk port trunk allow-pass vlan 2 to 4094 stp mode mstp //修改生成树的模式为…

【多线程】创建线程到底是多少种方法?

🥰🥰🥰来都来了,不妨点个关注叭! 👉博客主页:欢迎各位大佬!👈 文章目录 1. 创建线程的两种方式总结(最官方)1.1 继承 Thread 类1.2 实现 Runnable 接口1.3 优先考虑使用第二种 —— …

三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附+源代码流程)

三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附源代码流程) 文章目录 三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附源代码流程)1. Spring Boot 是继续支持了 Spring 当中的注解的1.2 Spring 当中的 Component,Controller…

通过visual studio进行dump文件调试和分析

0、前言 很多时候程序crash之后需要分析原因。对于C/C程序,一般最常见的场景和方法就是根据dump文件进行分析。 1、分析的前提条件 进行dump文件分析,需要以下文件: 进程crash时产生的dump文件程序源码进程对应的程序exe文件编译exe文件时产…

QT Quick QML 添加海康威视SDK云台控制模块

文章目录 1. 配置海康威视 SDK 下载SDK文件移植工程文件添加 2. 函数调用流程接口参考代码 3. 代码后端核心代码前端核心代码 GitHub 源码: QmlLearningPro ,选择子工程 HkwsDemo.pro (暂未上传) QML 其它文章请点击这里: QT QUICK …

Monibuca实战:如何用Go语言打造高效的直播后端

简介 Monibuca(简称:m7s) 是一个开源的实时流媒体服务器开发框架,使用 Go 语言编写。 它的设计目标是提供一个高性能、可扩展、易于定制的实时流媒体服务器解决方案。 Monibuca 的核心理念是模块化,允许开发者根据需…

文件禁止外发的方法有哪些?企业如何禁止文件外发:六个控制文件外发的小窍门!

想象一下,企业信息如同珍贵的宝藏,而文件外发就像不经意间打开的后门,让宝藏暴露在风雨之中!今天,我们就来聊聊如何给这扇后门加上六道坚实的锁,确保企业信息的安全无虞。让我们一起探索六个控制文件外发的…

Mask R-CNN论文原理讲解

论文:arxiv.org/pdf/1703.06870 代码:maskrcnn-benchmark:Fast, modular reference implementation of Instance Segmentation and Object Detection algorithms in PyTorch. - GitCode Mask R-CNN简介 Mask R-CNN是何凯明大神的新作。Mask R-CNN是一种在有效检测…

武器弹药制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

武器弹药制造领域作为国防工业的重要组成部分,其数字化转型更是关乎国家安全与军事实力提升的关键。随着5G、物联网、大数据、云计算及人工智能等先进技术的融合应用,武器弹药制造5G智能工厂物联数字孪生平台应运而生,正逐步成为推进制造业数…

分享5款支持论文写作网站先稿后付的网站!

在当今学术研究和学术写作领域,AI论文写作工具已经成为不可或缺的助手。这些工具不仅能够提高写作效率,还能帮助研究人员生成高质量的论文内容。特别是那些提供“先稿后付”服务模式的网站,更是为用户提供了极大的便利和保障。以下是五款值得…

记录|SPC公式小结

目录 前言一、基本缩写二、Xbar和R的控制线三、相关系数表更新时间 前言 参考文章: 参考视频: SPC公式小结 一、基本缩写 二、Xbar和R的控制线 三、相关系数表 更新时间 2024.08.29:创建

旗帜分田(华为od机考题)

一、题目 1.原题 从前有个村庄,村民们喜欢在各种田地上插上小旗子,旗子上标识了各种不同的数字。 某天集体村民决定将覆盖相同数字的最小矩阵形的土地的分配给为村里做出巨大贡献的村民, 请问,此次分配土地,做出贡献…

DevEco Studio5 新建项目

Deveco Studio安装结束之后,开始新建一个项目: 1.点击Create Project新建项目 2.选择空的项目–>点击next 3.配置项目信息–>点击Finish 4.进入项目 6.右上方目前处于No Devices(无设备)状态–>点击下拉三角–>点击Devide Manager管理设…

Life long learning

现象:一个model进行multi-task learning做的还可以,说明模型是可以同时学会多个任务的,但是如果训练过程是1个task 1个task的顺序进行,模型就会发生灾难性的遗忘现象,只会做刚学完的task。 目标:让模型不要…

94.WEB渗透测试-信息收集-Google语法(8)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容:93.WEB渗透测试-信息收集-Google语法(7) • Filetype • Filetype…

二叉树前序,中序,后序非递归遍历(Java)

1. 思路: 首先创建一个栈和顺序表,按照根左右的前序遍历顺序去遍历这棵树,一直往左孩子方向遍历,每遍历到一个结点就入栈并且加入到顺序表里,如果没有左孩子了,就拿出栈顶元素,看它是否有右孩子…

2024年牛客网最全1000道Java中高级面试题包含答案详解,看完稳了

我相信大多 Java 开发的程序员或多或少经历过 BAT 一些大厂的面试,也清楚一线互联网大厂 Java 面试是有一定难度的,小编经历过多次面试,有满意的也有备受打击的。因此呢小编想把自己这么多次面试经历以及近期的面试真题来个汇总分析&#xff…

JavaScript进阶指南之Event Loop

JavaScript进阶指南之Event Loop 引言 简要介绍主题: 在JavaScript的世界中,Event Loop是一个核心机制,它决定了代码的执行顺序,尤其是在处理异步任务时。对于初学者来说,理解Event Loop的工作原理是迈向JavaScript进…