一、input子系统
一、input子系统简介
1、input子系统是用于管理输入的子系统,是linux内核为了处理某一类设备的一种框架,这一类设备就是输入设备。
2、由于输入设备的种类有许许多多,不同的输入设备对应的输入信息不同,应用层中的处理方法也会有所不同,写驱动的时候只需要按要求上报输入事件。
3、input子系统可以分为input驱动层、input核心层、input事件处理层,还要提供给用户空间访问的设备节点。
二、驱动编写流程
input核心层会向linux内核注册一个字符设备,可以在板上linux系统内的sys/class目录下查看到有input文件夹。input子系统的所有设备的主设备号都是13,使用input子系统不需要去注册字符设备只需要注册一个input_device。
1、使用input子系统只需要注册一个inout设备使用起来十分方便,使用的是定义在内核文件include/linux/input.h中的input_dev结构体,以此来表示input设备,结构体定义部分如下:
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)]; //sound相关
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;
//省略其余代码
}
2、在input_dev结构体中定义了许多了的位图,上图中的evbit[BITS_TO_LONGS(EV_CNT)]是表示事件类型的位图,evbit表示输入事件类型,输入事件的类型可在内核代码include/upai/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 //压力状态事件
3、使用input_allocate_device函数申请一个input_dev,函数返回值就是是申请到的input_dev。函数原型为:
struct input_dev *input_allocate_device(void)
4、使用input_free_device函数释放申请到的input_dev,函数无返回值,函数原型为:
void input_free_device(struct input_dev *dev)
5、申请一个input_dev以后就需要初始化,初始化的内容主要涉及两种,一种是事件类型(evbit)另一种是事件值(keybit)这两种。
6、初始化后需要向内核注册,使用函数input_register_device,函数返回值为0表示注册成功,反之,函数参数为需要注册的input_dev。
int input_register_device(struct input_dev *dev)
7、注销input驱动使用函数input_unregister_device注销input_dev,函数无返回值,参数为要注销的input_dev。
void input_unregister_device(struct input_dev *dev)
8、总结:
1)使用input_allocate_device函数申请一个input_dev
2)初始化申请到的input_dev,包括事件类型与事件值
3)使用input_register_device函数向linux内核注册前面初始化的input_dev
4)卸载要先使用input_unregister_device函数注销input_dev,然后使用input_free_device函数释放申请的input_dev。
三、输入事件的上报
1、注册好input_dev以后还需要告诉内核输入事件是什么亦或是输入值是什么,需要将这些相关的信息上报给内核,内核才可以获取到正确的输入值,不同输入事件使用的API函数不同。
2、使用函数input_event函数上报指定的事件以及对应的值,此函数可以上报所有的事件类型与事件值,函数原型为:
void input_event(struct input_dev *dev, //需要上报的input_dev
unsigned int type, //上报的类型
unsigned int code, //事件码
int value) //事件值
3、上报事件后还需要使用函数input_sync函数通知内核input子系统上报完毕,参数是需要上报同步事件的input_dev,函数原型为:
void input_sync(struct input_dev *dev)
四、input_event结构体的作用
1、Linux内核中是用input_event结构体来表示所有输入事件的,用户应用程序通过input_event获取具体的输入事件及其值,结构体定义在内核文件中include/uapi/linux/input.h文件中:
/*
* The event structure itself
*/
struct input_event {
struct timeval time; //事件发生的时间
__u16 type; //事件类型
__u16 code; //事件码
__s32 value; //事件值
};
/*
*其中timeval结构体定义为:
* struct timeval {
* __kernel_time_t tv_sec; /* seconds 秒*/
* __kernel_suseconds_t tv_usec; /* microseconds 微秒*/
* };
*
*
*/
注:水平有限,这贴仅作笔记使用,侵权联系删,有错请指出,也可以让本人学习。