首页 > 系统相关 >Linux驱动学习之input子系统

Linux驱动学习之input子系统

时间:2024-08-30 14:54:38浏览次数:14  
标签:struct int unsigned dev Linux input 子系统 define

  • 简介

  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");

标签:struct,int,unsigned,dev,Linux,input,子系统,define
From: https://blog.csdn.net/m0_57485149/article/details/141682668

相关文章

  • 修改 Linux 默认 Shell 用 chsh -s /bin/zsh 命令不生效,提示 chsh: Shell not changed
    我想现在应该有很多人都已经使用zsh作为默认的Shell了,尤其是搭配oh-my-zsh之后,真是好用得飞起。一般,我们在切换系统默认的Shell的时候,都会使用 chsh-s/bin/zsh 命令来进行修改。今天我遇到一个问题,在某台老服务器上,使用这个命令无法修改,具体原因未知。始终提示——chsh:She......
  • Linux日志的查看方法
    使用cat命令:显示文件内容,适合快速查看文件开头部分或结合管道命令如grep进行过滤。cat/var/log/syslog|greperror使用tail命令:查看文件末尾部分,常用于查看最新的日志信息。-f选项可实时跟踪日志更新。tail-n50/var/log/syslogtail-f/var/log/syslog使用head......
  • 安全:linux禁止响应ping,不使用防火墙
    一,永久性关闭响应ping查看默认是否允许ping:[root@bloggsapi]#cat/proc/sys/net/ipv4/icmp_echo_ignore_all0 说明:(0表示允许,1表示禁止)编辑sysctl.conf[root@bloggsapi]#vi/etc/sysctl.conf增加一行:#ignorepingnet.ipv4.icmp_echo_ignore_all=1使生效:[root......
  • Linux中cd命令的基本用法!
    cd命令是Linux中最常见的命令之一,全拼changedirectory,其命令主要用于切换当前工作目录,本篇文章为大家介绍一下Linux中cd命令的常见用法,一起来看看吧。常见的cd命令用法:1、进入当前工作目录下的目录:cd./2、进入其他目录:cd/home/user/documents/3、......
  • linux系统加固一般包含那些方面?
    账户管理(1)禁用或删除无用账号:减少系统中不必要的用户账户数量,降低安全风险。(2)加强密码策略:确保密码强度足够,定期更换密码。(3)限制root登录:尽量避免直接使用root账户登录,而是使用sudo 或 su 命令切换到root用户。(4)最小权限原则:确保用户仅具有完成任务所需的最低权限。系统配......
  • PageOffice6国产Linux系统最简集成代码(Asp.Net)
    本文描述了PageOffice产品在普通的Asp.Net项目中如何集成调用。PageOffice国产版:支持信创系统,支持银河麒麟V10和统信UOS,支持X86(intel、兆芯、海光等)、ARM(飞腾、鲲鹏、麒麟等)、longarch芯片架构。新建Asp.Net项目:PageOffice6-Net-Simple在您的web项目的“依赖项-包-管理NuGet......
  • Linux--实现U盘,SD卡的自动挂载
    1.编辑/etc/init.d/rsC或S10mdev文件在/etc/init.d/rsC或S10mdev中加入以下语句:echo/sbin/mdev>/proc/sys/kernel/hotplug当有热插拔事件产生时,内核会调用/proc/sys/kernel/hotplug文件里指定的应用程序来处理热插拔事件。把/sbin/mdev写到/proc/sys/kernel/hotplug文件......
  • Linux基础软件-lvm
    作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。Linux进阶部分又分了很多小的部分,我们刚讲完了Linux日常运维。讲的那些东西都算是系统自带的,但是Linux作为一个服务器操作系统,肯定是要安装运行软件......
  • Linux内核中断
    头文件在vscode中,进行tasklet和work中断实验的时候,对于包含的头文件如下两个一直爆红:#include<linux/irq.h>#include<linux/of_irq.h>一路追查下来,发现是缺少头文件:#include<linux/irq.h> ->#include<asm/irq.h> ->#include<mach/irqs.h>(该头文件无法找到)......
  • Linux学习(15)-网络编程:滑动窗口、拥塞控制、udp
    本节学习内容1.滑动窗口(1.滑动窗口的作用2.如果如果接收端填充的接收窗口为0,发送端接下来怎么处理3.糊涂窗口综合征4.tcp中nagle算法是什么)2.拥塞控制3.udp协议特点及编程流程本节可能会用到的指令ifconfig查看自己的ip地址ping+ip地址验证通信是否连接netstat-natp显......