Linux设备驱动--input输入子系统

常见输入设备

常见输入设备:按键、键盘、触摸屏、鼠标 等。典型的字符设备驱动。

内核中一个通用的按键驱动:

drivers/input/keyboard/gpio_keys.c基于input架构实现了一个通用的GPIO按键驱动

用户空间接口
  • /dev/input/event0/1/2/…
  • /dev/input/mouse0/1/2/…
  • /dev/input/sj0/1/2/…
输入子系统框架

在这里插入图片描述
—— 《linux设备驱动开发详解》

输入子系统实现内核文件:drivers\input\input.c

分层模型
  • 核心层
    • drivers/input/input.c, 创建input设备类,input设备的主设备号为#define INPUT_MAJOR 13
    • 根据输入设备种类、分发事件到不同事件处理器
  • 事件处理层

    提供具体设备的操作接口,为输入设备(input_dev)创建具体设备文件

    • 通用事件处理器(drivers/input/evdev.c)

    • 鼠标事件处理器(drivers/input/mousedev.c)

    • 摇杆事件处理器(drivers/input/joydev.c)

核心数据结构

linux中使用struct input_dev描述输入设备
include\linux\input.h

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

	struct input_handle __rcu *grab;

	spinlock_t event_lock;
	struct mutex mutex;

	unsigned int users;
	bool going_away;

	struct device dev;

	struct list_head	h_list;
	struct list_head	node;

	unsigned int num_vals;
	unsigned int max_vals;
	struct input_value *vals;

	bool devres_managed;
};
  • evbit 表示输入事件类型,事件类型定义 include/uapi/linux/input.h
#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    /* 压力状态事件   */ 
linux使用struct input_event统一描述输入事件

include\uapi\linux\input.h

struct input_event {
#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
	struct timeval time;
#define input_event_sec time.tv_sec
#define input_event_usec time.tv_usec
#else
	__kernel_ulong_t __sec;
#if defined(__sparc__) && defined(__arch64__)
	unsigned int __usec;
#else
	__kernel_ulong_t __usec;
#endif
#define input_event_sec  __sec
#define input_event_usec __usec
#endif
	__u16 type;
	__u16 code;
	__s32 value;
};
  • time,事件发生的事件
  • type,事件的类型,例如按键、触摸
  • code,事件编码,比如事件类型是按键的话,这就是按键编码值
  • value,事件值,如按键事件,value为0表示释放,1表示按下。

输入核心层提供了底层设备驱动所需要的API

分配/释放输入设备
struct input_dev *input_allocate_device(void);
void input_free_device(struct input_dev *dev);
注册/注销输入设备
int __must_check input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *);
向系统报告事件
/*  报告指定 type 、 code 的输入事件  */
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
/*  报告键值  */
void input_report_key(struct input_dev *dev, unsigned int code, int value);
/*  报告相对坐标  */
void input_report_rel(struct input_dev *dev, unsigned int code, int value);
/*  报告绝对坐标  */

void input_report_abs(struct input_dev *dev, unsigned int code, int value);
/*  报告同步事件  */
void input_sync(struct input_dev *dev);

Linux VFS接口与字符设备相关的file_operations字符设备操作结构体相关的代码在drivers/input/evdev.c实现。所以使用输入子系统后,不需要驱动工程师去实现输入设备那些open、read等操作函数。

应用层读取输入子系统输入

示例:


#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <linux/input.h>

#define DEV_NAME "/dev/input/event0"

static struct input_event in_event; 

int main(int argc, char *argv[])
{
    int fd;
    int ret = 0;

    fd = open(DEV_NAME, O_RDWR);
    if (fd < 0) {
        printf("Can't open file %s\r\n", DEV_NAME);
        return -1;
    }

    while (1) 
    {
        ret = read(fd, &in_event, sizeof(in_event));
        if (ret == sizeof(in_event))      /* 读取数据成功 */
        {
            switch (in_event.type) 
            {
            case EV_KEY:     /* 按键事件类型 */
                if (inputevent.code < BTN_MISC) 
                { 
                    printf("button %d %s\r\n", in_event.code,  
                        inputevent.value ? "pressed" : "release"); 
                } 
                else 
                { 
                    printf("button %d %s\r\n", in_event.code,  
                        in_event.value ? "press" : "release"); 
                } 
                break;

            /* 其他类型的事件,自行处理 */ 
            case EV_REL: 

                break; 
            case EV_ABS: 

                break; 
            case EV_MSC: 

                break; 
            case EV_SW: 

                break; 
            } 
        }
        else
        { 
            printf("读取数据失败\r\n"); 
        } 
    }  
    return 0; 
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欲盖弥彰1314

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值