Input子系统

Input子系统

设备驱动层(input_dev,驱动probe函数里面创建初始化)

核心层(input_handle,文件input.c)

事件处理层(input_handler,eg:evdev.c)

input_dev和input_hander匹配成功后调用handler->connect,在这创建事件处理器结构体struct evdev,并分配、初始化file_operations结构体。给用户空间提供读写等操作

在input子系统中,每个事件的发生都使用:事件(type)--> 子事件(code)--> 值(value)

所有的输入设备的主设备号都是13,input-core通过次设备来将输入设备进行分类,如0-31是游戏杆,32-63是鼠标(对应Mouse Handler)、64-95是事件设备(如触摸屏,对应Event Handler)。

事件类型编码含义
EV_SYN0x00同步事件
EV_KEY0x01按键事件(鼠标,键盘等)
EV_REL0x02相对坐标(如:鼠标移动,报告相对最后一次位置的偏移)
EV_ABS0x03绝对坐标(如:触摸屏或操作杆,报告绝对的坐标位置)
EV_MSC0x04其它
EV_SW0x05开关
EV_LED0x11按键/设备灯
EV_SND0x12声音/警报
EV_REP0x14重复
EV_FF0x15力反馈
EV_PWR0x16电源
EV_FF_STATUS0x17力反馈状态
EV_MAX0x1f事件类型最大个数和提供位掩码支持

定义的按键值

#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
...

input_dev:是硬件驱动层,代表一个input设备。
input_handler:是事件处理层,代表一个事件处理器。
input_handle:属于核心层,代表一个配对的input设备与input事件处理器。
input_dev 通过全局的input_dev_list链接在一起,设备注册的时候完成这个操作。
nput_handler 通过全局的input_handler_list链接在一起。事件处理器注册的时候实现了这个操作(事件处理器一般内核自带,不需要我们来写)

事件语义

  • ABS_MT_TOUCH_MAJOR

触点主轴的长度。长度应以表面单位给出。如果表面具有 X 倍 Y 分辨率,则 ABS_MT_TOUCH_MAJOR 的最大可能值为 sqrt(X^2 + Y^2),对角线4

  • ABS_MT_TOUCH_MINOR

接触短轴的长度,以表面为单位。如果接触是循环的,这个事件可以省略4

  • ABS_MT_WIDTH_MAJOR

接近工具主轴的长度,以表面为单位。这应该理解为工具本身的大小。假设接触和接近工具的方向相同4

  • ABS_MT_WIDTH_MINOR

接近工具的短轴的长度,以表面为单位。如果循环4则省略。

上述四个值可用于获取有关联系人的附加信息。比率 ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR 近似于压力的概念。手和手掌的手指都有不同的特征宽度。

  • ABS_MT_PRESSURE

接触面积上的压力,以任意单位表示。对于基于压力的设备或任何具有空间信号强度分布的设备,可以使用它来代替 TOUCH 和 WIDTH。

如果分辨率为零,则压力数据采用任意单位。如果分辨率不为零,则压力数据以单位/克为单位。

  • ABS_MT_ORIENTATION

接触椭圆的方向。

  • ABS_MT_POSITION_X

接触椭圆中心的表面 X 坐标。

  • ABS_MT_POSITION_Y

接触椭圆中心的表面 Y 坐标。

  • ABS_MT_TOOL_TYPE

接近工具的类型。许多内核驱动程序无法区分不同的工具类型,例如手指或笔。在这种情况下,应省略该事件。该协议目前主要支持 MT_TOOL_FINGER、

MT_TOOL_PEN 和 MT_TOOL_PALM 2。对于 B 类设备,此事件由输入内核处理;驱动程序应改为使用input_mt_report_slot_state() 。联系人的

ABS_MT_TOOL_TYPE 可能会随着时间的推移而改变,但仍会触摸设备,因为固件可能无法在首次出现时确定正在使用的工具。

相关结构体

Input_dev---输入设备

/* include/linux/input.h */
struct input_dev {
        const char *name;  /* 设备名称 */
        const char *phys;  /* 设备在系统中的路径 */
        const char *uniq;  /* 设备唯一id */
        struct input_id id;  /* input设备id号 */
​
        unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
​
        unsigned long evbit[BITS_TO_LONGS(EV_CNT)];  /* 设备支持的事件类型,主要有EV_SYNC,EV_KEY,EV_KEY,EV_REL,EV_ABS等*/ 
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;  /* 设备关联的反馈结构,如果设备支持 */
​
        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 框架管理,不需要明确取消和释放*/
};
​
​

Input_handler---处理具体输入事件的具体函数

/* include/linux/input.h */
struct input_handler {
​
        void *private;  /* 存放handle数据 */
​
void (*event)(struct input_handle *handle, unsigned int type, unsigned  int code, int value);
        void (*events)(struct input_handle *handle,
                   const struct input_value *vals, unsigned int count);
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
        bool (*match)(struct input_handler *handler, struct input_dev *dev);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const  struct input_device_id *id);
        void (*disconnect)(struct input_handle *handle);
        void (*start)(struct input_handle *handle);
​
        bool legacy_minors;
        int minor;
        const char *name;  /* 名字 */
​
        const struct input_device_id *id_table;  /* input_dev匹配用的id */
​
struct list_head    h_list; /* 用于链接和handler相关的handle,input_dev与input_handler配对之后就会生成一个input_handle结构 */
        struct list_head    node;  /* 用于将该handler链入input_handler_list,链接所有注册到内核的所有注册到内核的事件处理器 */
};
​
Input_handle---连接输入设备和处理函数

/* include/linux/input.h */
struct input_handle {
        void *private;  /* 数据指针 */
​
        int open;  /* 打开标志,每个input_handle 打开后才能操作 */
        const char *name;  /* 设备名称 */
​
        struct input_dev *dev;  /* 指向所属的input_dev */
        struct input_handler *handler;  /* 指向所属的input_handler */
​
        struct list_head    d_node;  /* 用于链入所指向的input_dev的handle链表 */
        struct list_head    h_node;  /* 用于链入所指向的input_handler的handle链表 */
};
 

Evdev---字符设备事件

/* drivers/input/evdev.c */
struct evdev {
        int open;    /* 设备被打开的计数 */
        struct input_handle handle;  /* 关联的input_handle */ 
        wait_queue_head_t wait;  /* 等待队列,当前进程读取设备,没有事件产生时,
进程就会sleep */
        struct evdev_client __rcu *grab;  /* event响应 */
struct list_head client_list;  /* evdev_client链表,说明evdev设备可以处理多个 evdev _client,可以有多个进程访问evdev设备 */
        spinlock_t client_lock;
        struct mutex mutex;
        struct device dev;
        struct cdev cdev;
        bool exist;   /* 设备存在判断 */
};

evdev_client---字符设备响应

/* drivers/input/evdev.c */
struct evdev_client {
        unsigned int head;  /* 动态索引,每加入一个event到buffer中,head++ */
        unsigned int tail;  /* 动态索引,每取出一个buffer中到event,tail++ */
        unsigned int packet_head;  /* 数据包头部 */
        spinlock_t buffer_lock;  
        struct fasync_struct *fasync;  /* 异步通知函数 */
        struct evdev *evdev;  
        struct list_head node;  /* evdev_client链表项 */
        int clkid;
        unsigned int bufsize;
        struct input_event buffer[];  /* 用来存放input_dev事件缓冲区 */
};
​

Evdev_handler---事件处理函数

/* drivers/input/input.c */
static struct input_handler evdev_handler = {
        .event      = evdev_event,   /* 事件处理函数, */  
        .events = evdev_events,  /* 事件处理函数, */
        .connect    = evdev_connect, /* 连接函数,将事件处理和输入设备联系起来 */
        .disconnect = evdev_disconnect,  /* 断开该链接 */
        .legacy_minors  = true,
        .minor      = EVDEV_MINOR_BASE,
        .name       = "evdev", /* handler名称 */
        .id_table   = evdev_ids, /* 可以连接的input_dev */
};
​

input_event---标准事件编码信息

/* drivers/input/evdev.c */
struct input_event {                                                            
    struct timeval time;   /* 事件发生的时间  */                                
    __u16 type;             /* 事件类型 */                                      
    __u16 code;             /* 事件码 */                                        
    __s32 value;            /* 事件值 */                                        
};   

input_device_id

/* include/uapi/linux/input.h */
struct input_device_id {
​
        kernel_ulong_t flags;
​
        __u16 bustype;  /* 总线类型 */
        __u16 vendor;  /* 生产厂商 */
        __u16 product;  /* 产品类型 */
        __u16 version;  /* 版本 */
​
        kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
        kernel_ulong_t propbit[INPUT_DEVICE_ID_PROP_MAX / BITS_PER_LONG + 1];
​
        kernel_ulong_t driver_info;
};

input_event---输入事件的传递以input_event为单位

struct input_event {
    struct timeval time; //时间戳
        __u16 type; //事件总类型
        __u16 code; //事件子类型
        __s32 value; //事件值
};
​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值