input子系统简介
1、 Input驱动程序是linux输入设备的驱动程序,分成游戏杆(joystick)、鼠标(mouse和mice)、事件设备(event)。其中事件驱动程序是目前通用的驱动程序,可支持键盘、鼠标、触摸屏等多种输入设备。

2、 输入子系统驱动分成三层

3、 input驱动程序的主设备号是13、次设备号的分布如下:
a) joystick游戏杆:0~16
b) mouse鼠标: 32~62
c) mice鼠标: 63
d) 事件设备: 64~95

4、 2.6内核中定义的支持的类型

#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    //蜂鸣器,输入声音
#define EV_REP          0x14    //允许重复按键类型
#define EV_FF           0x15
#define EV_PWR          0x16    //电源管理事件
#define EV_FF_STATUS    0x17
#define EV_MAX          0x1f

5、 主要的结构体

a)   Input_device:代表着具体的输入设备,他直接从硬件中读取数据,并以事件的形式转发
b)  Handler:代表接收某一类事件的上层接口,对应于一类事件设备文件
c)  Handle:用于将input_device和handler连接起来,对应于某个具体的设备文件。
d)  Client:对应于用户程序对文件的访问接口,每open一次事件驱动,就创建一个client
e)  Handler:struct input_handler *input_table[8],最多有8中input驱动,比如/dev/input/eventX和/dev/input/mouseX就是两种常用的input驱动。
f)  Handle:以evdev.c为例,根据次设备号取值范围64-95,可以分别生成input/event0、input/event1,一直到input/event31共32个设备文件。每个设备文件对应一个handle
g)  Client:每个设备文件又可以同时对应多个client,当有多个应用程序同时调用设备文件时,他们会从不同的client中取数据。

6、 input子系统的核心层维护着两条中要的链表

a)   static LIST_HEAD(input_dev_list);        /* 记录所有的输入设备 */
b)  static LIST_HEAD(input_handler_list);    /* 记录所有的事件驱动 */

每当一个新的设备或者一个新的事件驱动被系统加载(调用input_register_device()或 input_register_driver()),都会扫描整个链表,并调用函数input_match_device(struct input_handler *handler, struct input_dev *dev) 尝试配对工作。Input_handler–>id_table 记录了需要匹配的特征。

编写input驱动需要的函数
1、 包含头文件<linux/input.h>,他是input子系统的接口,提供了必要的定义消息

2、 Input_allocate_device()分配了一个Input device的结构,设置他的bit field来告诉input子系统他能产生或者接收什么事件。

3、input_register_device(struct input_dev *dev)将dev结构体添加到input_dev_list全局链表中去,通过input_attach_handler
(struct input_dev *dev, struct input_handler *handler)来查找对应的handler,input_attach_handler里面实际调用了input_match_device(const struct
input_device_id *id,struct input_dev *dev)一旦input_attach_handler找到了对应的handler,就执行handler->connect。

4、input_report_key(struct input_dev *dev, unsigned int code, int value)上报按键事件

5、 input_sync(struct input_dev *dev)告诉事件的接收者,到此为止为一次完整的消息。比如我们在touch screen上获得了x、y的值,要使作为一次事件,那么将input_sync加在report x、y值得后面。

6、 其他的事件type,输出事件处理
其他的事件有:
EV_LED:用作键盘的LED灯
EV_SND:用作键盘的蜂鸣器
其他和键盘事件很相似,只不过键盘事件是INPUT_PASS_TO_DEVICE,而输出事件是INPUT_PASS_TO_HANDLERS,从系统到输入设备的驱动程序,如果你的驱动程序要处理这些事件,必须设置evbit中相应位,而且要实现一个回调函数。

7、 struct input_dev *button_dev;
8、 button_dev->event = button_event;这个便是处理输出事件的回调函数

普通按键实现input驱动例子
(一) module_init入口函数
a) 添加中断到内核

int request_irq(unsigned int irqno,irq_handler_t handler,unsigned long flags,const char * name,void * args)irqno:该对象的中断号handle: 该对象的方法flags:  指定中断触发方式     IRQ_TYPE_EDGE_FALLING(下降沿)IRQ_TYPE_EDGE_RISING(上升沿)IRQ_TYPE_EDGE_BOTH(上升、下降沿)IRQ_TYPE_LEVEL_HIGH(高电平)IRQ_TYPE_LEVEL_LOW(低电平)IRQ_TYPE_SIMPLE(Simple中断)IRQ_TYPE_PERCPU(Per CPU中断)name:中断对象的名字args:该对象的私有数据

b) 在内存中分配一个input_dev结构体

struct  input_dev  *input_allocate_device(void)

c) 初始化input_dev对象的一些值

const char *name;//设备名
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//用于记录支持的事件类型的位图
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//记录支持的按键值的位图
…………

d) 将input_dev结构体注册到输入子系统核心中

int input_register_device(struct input_dev *dev);

(二) 中断处理函数
a) 获取一个GPIO的pin value。

xxxx_gpio_getpin(xxxx_GPG(0))

b) 向输入子系统报告产生按键事件

input_report_key(button_dev, BTN_0, val);

c) 告诉事件的接收者,到此为止为一次完整的消息

input_sync(button_dev);

d) 中断处理结束

return IRQ_RETVAL(IRQ_HANDLED);

(三) module_exit模块出口
a) 注销输入设备函数:

void input_unregister_device(struct input_dev *dev)

b) 释放分配的空间:

void input_free_device(struct input_dev *dev)

c) 卸载中断:

void free_irq(unsigned int irq, void *dev_id)
/*****************************************************************
*   Copyright (C) 2019 Sangfor Ltd. All rights reserved.
*
*   文件名称:input.c
*   创 建 者:yinfei-hu
*   创建日期:
*   功能描述:触摸按键input上报
*
*****************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/input.h>static struct input_dev *button_dev;static irqreturn_t button_intr(int irq, void *dev_id)
{int val;val = gpio_getpin(GPG(0));   //获取一个GPIO的pin value。
//  printk(KERN_INFO "key value is %d\n", val);/************************************************************************************************************向输入子系统报告产生按键事件static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)参数value表示的是按键的按下还是没按下。0表示按键释放,非0表示按键按下。最终调用:void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)  static void input_handle_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)************************************************************************************************************/input_report_key(button_dev, BTN_0, val);   /************************************************************************************************************告诉事件的接收者,到此为止为一次完整的消息,同步用于告诉input core子系统报告结束。void input_sync(struct input_dev *dev);  ************************************************************************************************************/input_sync(button_dev);    /************************************************************************************************************#define IRQ_NONE (0)#define IRQ_HANDLED (1)IRQ_RETVAL这个宏只是返回0或非0   如果中断不是由本设备引起的,则返回IRQ_NONE,否则返回IRQ_HANDLED  ************************************************************************************************************/return IRQ_RETVAL(IRQ_HANDLED);
}static int __init button_init(void)
{int ret;/************************************************************************************************************将中断对象 添加到内核int request_irq(unsigned int irqno,irq_handler_t handler,unsigned long flags,const char * name,void * args)irqno:该对象的中断号handle: 该对象的方法flags:  指定中断触发方式     IRQ_TYPE_EDGE_FALLING(下降沿)IRQ_TYPE_EDGE_RISING(上升沿)IRQ_TYPE_EDGE_BOTH(上升、下降沿)IRQ_TYPE_LEVEL_HIGH(高电平)IRQ_TYPE_LEVEL_LOW(低电平)IRQ_TYPE_SIMPLE(Simple中断)IRQ_TYPE_PERCPU(Per CPU中断)name:中断对象的名字args:该对象的私有数据************************************************************************************************************/ret = request_irq(IRQ_EINT8, button_intr, IRQ_TYPE_EDGE_BOTH, "button0", NULL);  //注册中断if (ret) {printk(KERN_ERR "%s request failed\n", __func__);return -ENODEV;}button_dev = input_allocate_device(); //函数在内存中为输入设备结构体分配一个空间,并对其主要的成员进行了初始化.  if (!button_dev) {printk(KERN_ERR "button.c: Not enough memory\n");/************************************************************************************************************失败退出之前把之前注册的中断、其他的需要释放的也一并释放掉:申请的内存空间、映射的寄存器、注册的设备之类的void free_irq(unsigned int irq, void *dev_id);unsigned int  irq:要卸载的中断号void  *dev_id:这个是要卸载的中断action下的哪个服务函数编程注意:1.如果是采用非共享方式注册中断,则request_irq和free的最后一个参数都要为NULL。2.如果采用共享中断方式,所有使用request_irq注册的中断时flags都要加上IRQF_SHARED这个共享参数,表明其实共享中断。3.对于共享中断,每一个申请共享的中断,申请和释放时都要给request_irq和free_irq的最后一个参数dev和id_dev传递一个指针,将来来中断的时候,将会传递这个指针到每个中断函数中,而中断函数就可以用来区分到底是不是它的中断,是则执行,不是则判断后直接退出中断处理函数即可。同时在free_irq时也会使用这个指针,查找这个贡献中断链表上了所有注册的irq,只有在这个指针能对的上的时候,才会删除它所在的链表节点(如果是最后一个节点还要释放该中断)。所在在编写中断处理函数时该指针必须是唯一的,通常传的这个指针是该设备结构体的地址,这个每个设备不一样所以肯定是唯一的。************************************************************************************************************/free_irq(IRQ_EINT8, NULL);  return -ENOMEM;}/************************************************************************************************************初始化input_dev对象的一些值  const char *name;//设备名unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//用于记录支持的事件类型的位图#define EV_SYN          0x00    //表示设备支持所有的事件#define EV_KEY          0x01    //键盘或者按键,表示一个键码 #define EV_REL          0x02    //鼠标设备,表示一个相对的光标位置结果 #define EV_ABS          0x03    //手写板产生的值,其是一个绝对整数值 #define EV_MSC          0x04    //其他类型#define EV_LED          0x11    //LED灯设备#define EV_SND          0x12    //蜂鸣器,输入声音  #define EV_REP          0x14    //允许重复按键类型  #define EV_PWR          0x16    //电源管理事件unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//记录支持的按键值的位图按键类型(只有当事件类型为KEY时):BTN_0   BTN_LEFT  BTN_1 BIT_WORD宏用于计算nr个位占用多少个字,这里字的长度是BITS_PER_LONG,并且计算出来的字长比实际少一个,这也是一种向下对齐。参数nr代表bit的总数。函数将nr的值除以BITS_PER_LONG依次向下计算出nr个位占了多少个字。************************************************************************************************************/button_dev->name = "button0";button_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY);button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);/************************************************************************************************************int input_register_device(struct input_dev *dev);函数将input_dev结构体注册到输入子系统核心中,input_dev结构体必须由前面讲的input_allocate_device()函数来分配。input_register_device()函数如果注册失败,必须调用input_free_device()函数释放分配的空间。如果该函数注册成功,在卸载函数中应该调用input_unregister_device()函数来注销输入设备结构体。************************************************************************************************************/ret = input_register_device(button_dev);if (ret) {printk(KERN_ERR "button.c: Failed to register device\n");/************************************************************************************************************失败退出之前把之前注册的中断、其他的需要释放的也一并释放掉:申请的内存空间、映射的寄存器、注册的设备之类的释放分配的空间:void input_free_device(struct input_dev *dev);************************************************************************************************************/input_free_device(button_dev);free_irq(IRQ_EINT8, NULL);return -ENODEV;}printk(KERN_INFO "button init ok!\n");return 0;
}static void __exit button_exit(void)
{/************************************************************************************************************注销输入设备函数:void input_unregister_device(struct input_dev *dev)释放分配的空间:void input_free_device(struct input_dev *dev)卸载中断:void free_irq(unsigned int irq, void *dev_id)************************************************************************************************************/ input_unregister_device(button_dev);input_free_device(button_dev);free_irq(IRQ_EINT8, NULL);printk(KERN_INFO "button exit ok!\n");
}/*    内核模块入口    module_init 里面的参数,指向谁,谁就是模块入口函数*/
module_init(button_init);
/*    内核模块出口    module_exit 里面的参数,指向谁,谁就是模块出口函数*/
module_exit(button_exit);/*模块作者信息*/
MODULE_AUTHOR("YinFei.Hu <hu_yin_fei@163.com>");
/*模块信息*/
MODULE_DESCRIPTION("spi_driver");
/*告诉内核愿意遵守gpl协议*/
MODULE_LICENSE("GPL");

10.14、驱动开发 -- input子系统相关推荐

  1. linux按键驱动中的结构体,linux 驱动之input子系统(gpio-keys)实现

    1.概述 Gpio-keys 是基于input子系统实现的一个通用按键驱动,该驱动也符合linux驱动实现模型,即driver和device分离模型.一般按键驱动,都是基于gpio-keys进行开发的 ...

  2. linux 设备驱动 百度,Linux设备驱动之input子系统

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 作者:武汉华嵌嵌入式培训中心 讲师 李家凯 对于输入类设备如键盘.鼠标.触摸屏之类的Linux驱动,内核提供input子系统,使得这类设备的处理变得非常便 ...

  3. linux内核驱动子系统,Linux 驱动开发 / IIO子系统入门1

    1. 什么是 IIO 子系统? 1.1 IIO 概述 Industrial I/O 子系统旨在为某种意义上是模数或数模转换器 (ADC,DAC) 的设备提供支持,于2009年由 Huawei 的 Jo ...

  4. 【Linux驱动】input子系统与按键驱动

    input子系统架构总览 在网上能找到一些关于input子系统架构相关的示意图,大体表达的意思都差不多. linux输入子系统(linux input subsystem)从上到下由三层实现,分别为: ...

  5. (14)[驱动开发]配置环境 VS2019 + WDK10 写 xp驱动

    文章目录 安装SDK和WDK 创建项目 编写程序 其他工具 参考: 参考博客 安装SDK和WDK 我这里用的是VS2019.环境其实是早就配好了,只不过写一下而已.后来VS2019不能被visual ...

  6. Linux驱动之Input子系统要点分析

    ① Input_device与Input_handler的匹配过程 当Input_device与Input_handler->id中的位图信息全部一致,则匹配成功,然后调用Input_handl ...

  7. Linux驱动分析——input输入子系统

    stm32mp157  盘古开发板  Linux内核版本4.19 目录 1.朱有鹏老师的视频课程笔记和应用测试代码: 2.input子系统架构分析 2.1.输入核心层源码分析 2.1.1.首先是核心模 ...

  8. Android 开发之 ---- 底层驱动开发(一) 【转】

    转自:http://blog.csdn.net/jmq_0000/article/details/7372783 版权声明:本文为博主原创文章,未经博主允许不得转载. 驱动概述 说到 Android  ...

  9. Android 开发之 ---- 底层驱动开发

    说到 android 驱动是离不开Linux驱动的.Android内核采用的是Linux2.6内核(最近Linux 3.3已经包含了一些Android代码).但Android并没有完全照搬Linux系 ...

  10. 8.input子系统基础之按键

    转自 https://edu.csdn.net/lecturer/505 朱老师物联网大讲堂 <5.linux驱动开发-第5部分-5.8.input子系统基础之按键> 第一部分.章节目录 ...

最新文章

  1. 《适用于初学者的 Python》
  2. 002 在大数据中基础的llinux基本命令
  3. apache 禁用rc4_如何在Apache中禁用过时的TLS和SSL版本
  4. IATF16949:2016汽车质量管理体系认证办理流程
  5. 关于笔记本电脑网卡出问题的简单解决
  6. v4l2-ctl基本使用方法
  7. 在Windows本地安装ElasticSearch和Kibana
  8. jsp注册页面java代码_使用Servlet和JSP实现用户注册功能
  9. 随笔记:PPT渐变色
  10. GIS实验之制作核密度分析图
  11. 装机不求人,小白装机注意事项
  12. 身份证提取生日和性别
  13. 会话与会话技术(Session)
  14. Integrity check failed for “antd“ (computed integrity doesn‘t match our records
  15. 零基础入门天池NLP赛事之——新闻文本分类(5)
  16. python 通讯录系统_Python实现通讯录功能
  17. Jointjs初认识
  18. 标星 90 K!微软开源的 Web 开发课程!
  19. 单晶FCC金属纳米压痕的晶体塑性有限元仿真
  20. win7如何设置wifi热点_win7系统中怎么设置wifi热点?

热门文章

  1. Oracle排序查询语句
  2. ddm模型公式_绝对估值法DDM、DCF模型及RNAV简介
  3. Unity3D射击小游戏Demo开发
  4. 圣思园JavaWeb随手笔记
  5. 两根硬铜线并线接插座_两根硬铜线正确接法
  6. ANSYS 闪退问题解决办法
  7. OpenCV中集成目标跟踪算法介绍
  8. 27学java能找到工作吗_今年27,想自学Java,转行程序员,请问可行吗?
  9. PHP之tp3点击刷新验证码登录
  10. iOS 在CollectionView上做展开收起动画