• Linux 学习笔记:input 子系统


    一、概述

    input 子系统是管理输入的子系统,和pinctrl、gpio 子系统一样,都是Linux 内核针对某一类设备而创建的框架。

    input 子系统分为 input 驱动层、input 核心层、input 事件处理层,最终给用户空间提供可访问的设备节点。

    二、使用input 子系统编写设备驱动的流程

    2.1 驱动入口

    2.1.1 申请 input_dev

    struct input_dev *input_allocate_device(void)
    
    • 1

    返回值:申请到的input_dev

    2.1.2 初始化 input_dev

    需要初始化的内容主要为事件类型(evbit) 和 事件值(keybit)这两种。

    keyinputdev.inputdev = input_allocate_device();
    keyinputdev.inputdev->name = KEYINPUT_NAME;
    keyinputdev.inputdev->evbit[0] = BIT_MASK( EV_KEY ) | BIT_MASK( EV_REP );
    input_set_capability( keyinputdev.inputdev, EV_KEY, KEY_3 );
    
    • 1
    • 2
    • 3
    • 4

    2.1.3 注册 input_dev

    int input_register_device(struct input_dev *dev)
    
    • 1

    dev : 要注册的input_dev

    返回值:0,input_dev 注册成功;负值,input_dev 注册失败。

    2.2 上报事件

    2.2.1 上报事件的时机

    利用input 子系统编写按键驱动,input 子系统并不负责按键按下的检测。为了实现按键的检测,我们还是需要:

    1. 读取设备树,获取按键的GPIO;
    2. 为这个IO申请中断;
    3. 在中断处理函数,开启定时器,进行防抖处理。
    4. 在定时器处理函数,读取gpio 的输入状态。

    在上面的第4步,读取到gpio 的输入值之后,调用input 子系统的上报函数,上报输入事件。

    2.2.2 上报按键事件的API

    不同的事件,其上报事件的API 函数不同。按键事件的上报API 如下:

    static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
    {
    		 input_event(dev, EV_KEY, code, !!value);
    }
    
    • 1
    • 2
    • 3
    • 4

    2.2.3 上报同步事件

    我们需要上报同步事件,告知input 子系统 上报结束

    static inline void input_sync(struct input_dev *dev)
    {
    	input_event(dev, EV_SYN, SYN_REPORT, 0);
    }
    
    • 1
    • 2
    • 3
    • 4

    2.2.4 上报事件的底层实现函数 input_event

    从上面可以看到,上报按键事件和上报同步事件,调用的都是input_event 函数。input_event 函数可以上报所有的事件类型和事件值。下面是input_event 的声明:

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

    函数参数和返回值含义如下:

    dev : 需要上报的input_dev 。

    type: 上报的事件类型,比如:EV_KEY 。

    code : 事件码,也就是我们注册的按键编号,比如:KEY_0

    value : 事件值,比如1表示按键按下,0表示按键松开。

    2.3 驱动出口

    卸载input 驱动的时候,需要先注销input_dev

    void input_unregister_device( struct input_dev *dev );
    
    • 1

    然后释放 input_dev

    void input_free_device( struct input_dev *dev );
    
    • 1

    三、应用层读取input event

    3. 1 input_event 结构体

    Linux 内核使用input_event 这个结构体来表示所有的输入事件,结构体定义在 include/uapi/linux/input.h 文件中。

    struct input_event {
    	struct timeval time;
    	__u16 type;
    	__u16 code;
    	__s32 value;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • time : 时间,也就是此事件发生的时间。
    • type : 事件类型,比如EV_KEY, 表示此次时间为按键事件。
    • code : 事件码,比如在EV_KEY 事件中,code 就表示具体的按键码,如:KEY_0,KEY_1
    • value : 值,比如EV_KEY 事件中value 就是按键值。为1表示按键按下,为0表示按键松开。

    3.2 应用层读取

    err = read( fd, &inputevent, sizeof( inputevent ) );
    //读取数据成功
    if ( err > 0 )
    {
         switch ( inputevent.type )
         {
              case EV_KEY:
                   if ( inputevent.code < BTN_MISC )
                   {
                       printf( "key %d %s\r\n", inputevent.code, inputevent.value ? "press": "release" );
                    }
                    else
                    {
                       printf( "button %d %s\r\n", inputevent.code, inputevent.value ? "press": "release" );
                     }
                    break;
                
         }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    深度克隆和浅拷贝的区别
    crsctl stop crs -f 停止不成功 (SYSTEMDG in QUIESCING state)
    RabbitMQ自学笔记——消息可靠性问题
    vue多条件查询
    美食主题HTM5网页设计作业成品 HTML+CSS+JavaScript蛋糕甜品棕色蛋糕甜品店网页设计(4页)
    后悔怎么没早点看到!腾讯T3整理实战书籍:(Spring MVC +MyBatis快速开发与项目实战pdf)
    025-从零搭建微服务-文件服务(一)
    在各种开发项目中使用公用类库的扩展方法,通过上下文方式快速调用处理函数
    hexo建站新手入门
    Matter 系列 #10|Matter 的证书吊销机制
  • 原文地址:https://blog.csdn.net/gdut_liujiangyi/article/details/128097028