-  
简介
 
- input 子系统就是管理输入的子系统,和pinctrl、gpio 子系统一样,都是 Linux 内核针对某一类设备而创建的框架。
 - 按键、鼠标、键盘、触摸屏等都属于输入设备,linux内核为此专门做了一个叫做input子系统的框架来处理输入事件。
 - 输入设备本质上还是字符设备,只是在此基础上套上了input框架,用户只需要负责上报输入事件,比如按键值、坐标等信息。
 - 对于驱动编写者而言不需要去关心应用层的事情,我们只需要按照要求上报这些输入事件即可
 - 为此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"); 
 
                



















