Linux 驱动框架---input子系统框架
前面从具体(Linux 驱动框架---input子系统)的工作过程学习了Linux的input子系统相关的架构知识,但是前面的学习比较实际缺少总结,所以今天就来总结一下输入子系统的架构分层,站到远处来看输入子系统。总得来说输入子系统由设备驱动层(input_dev的注册),输入子系统核心层(input core),事件处理层(handler),和用户空间四部分。这一部分类别platform驱动框架的内容来学习。
设备驱动层(类似于platform_device)
就是前面描述的gpio_keys.c 中的probe接口中的处理过程主要负责不同硬件的底层相关的中断,IO等具体硬件相关的配置和对应接口的开发,并负责将不同硬件设备的数据转换为统一的事件,
通过子系统提供的API接口向输入核心汇报。
输入核心参(类似platform_bus)
承上启下的作用上到用户空间的lient,同时提供设备注册和事件层注册并负责设备和事件层的匹配,同时负责通知事件层处理事件,并在、proc等目录下产生相应的信息文件接口。
事件层(platform_drivers)
负责对设备上报的事件进行处理,中间还引入了input_client的概念,input设备的时间层负责上对接用户空间下对接输入核心层,一个输入设备每次被打开依次设备驱动驱动层就会创建一个client,
事件处理层就负责将设备上报的事件放到每个client然后由用户读写。
中间链接件
输入子系统的几个部分其中的input_dev(输入设备)和input_handler(事件处理层),当他们俩任何一个新注册进子系统时由子系统核心进行匹配,如果匹配成功将创建一个handle用来绑定dev和handler
这里要注意区分handler和handle 这两个太像了。
总体用一个图片来表示就是:
参考:https://www.sohu.com/a/128794317_610671
再来看一点输入子系统core的相关内容----事件和事件map等相关的宏的含义及设置方法。
事件省略了一些内容:
struct input_dev { 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)]; 。 。 。 };
具体是怎么描述的设备的的可以从如下接口“可见一斑”:
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code) { switch (type) { case EV_KEY: __set_bit(code, dev->keybit); break; case EV_REL: __set_bit(code, dev->relbit); break; case EV_ABS: input_alloc_absinfo(dev); if (!dev->absinfo) return; __set_bit(code, dev->absbit); break; case EV_MSC: __set_bit(code, dev->mscbit); break; case EV_SW: __set_bit(code, dev->swbit); break; case EV_LED: __set_bit(code, dev->ledbit); break; case EV_SND: __set_bit(code, dev->sndbit); break; case EV_FF: __set_bit(code, dev->ffbit); break; case EV_PWR: /* do nothing */ break; default: pr_err("input_set_capability: unknown type %u (code %u)\n", type, code); dump_stack(); return; } __set_bit(type, dev->evbit); }
可以从输入设备的结构体定义内容看到,输入系统共支持的输入类型有事件设备,按键设备,相对坐标,,,,声音控制,,开关等类型事件。也可以从头文件中的定义看到
#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 #define EV_CNT (EV_MAX+1) /*所以通过上面的接口我盟知道设备支持的时间类型是由evbit位图来标记的,对于具体设备的code则有具体的设备类型的位图来记录。比如前面的gpio_key调用传入的事件类型是按键,而code就是具体按键的键值这个有设备平台信息携带。接下来看一下常见类型的code首先是容易理解的按键当然code就是键值如下不完全列出也不详细解释具体含义。*/ #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 REL_X 0x00 //这个代表x轴位移 #define REL_Y 0x01 //这个代表y轴位移 #define REL_Z 0x02 //代表z轴位移 #define REL_RX 0x03 //也是一种轴吧 #define REL_RY 0x04 #define REL_RZ 0x05 #define REL_HWHEEL 0x06 #define REL_DIAL 0x07 #define REL_WHEEL 0x08 #define REL_MISC 0x09 //绝对坐标,具体含义基本可以通过名字看出来也不完全列出来 #define ABS_X 0x00 #define ABS_Y 0x01 #define ABS_Z 0x02 #define ABS_RX 0x03 #define ABS_RY 0x04 #define ABS_RZ 0x05 #define ABS_THROTTLE 0x06 #define ABS_RUDDER 0x07 #define ABS_WHEEL 0x08 #define ABS_GAS 0x09 #define ABS_BRAKE 0x0a #define ABS_HAT0X 0x10 //其余的还有开关类的,杂项类,LED的等,同时设备的总线输入子系统也定义了就如下几种类型 #define BUS_PCI 0x01 #define BUS_ISAPNP 0x02 #define BUS_USB 0x03 #define BUS_HIL 0x04 #define BUS_BLUETOOTH 0x05 #define BUS_VIRTUAL 0x06 #define BUS_ISA 0x10 #define BUS_I8042 0x11 #define BUS_XTKBD 0x12 #define BUS_RS232 0x13 #define BUS_GAMEPORT 0x14 #define BUS_PARPORT 0x15 #define BUS_AMIGA 0x16 #define BUS_ADB 0x17 #define BUS_I2C 0x18 #define BUS_HOST 0x19 #define BUS_GSC 0x1A #define BUS_ATARI 0x1B #define BUS_SPI 0x1C
最后再来看一下输入子系统上报的事件的封装结构体,这结构体定义在\include\uapi\linux\input.h 说明用户也是可以使用上面这些内容和定义的如事件
struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; };
其中type和code就是前面提及的时间类型和code最后的value就是事件的具体值,到这里输入子系统的相关内容就算基本结束了,很多细节没有去仔细的看还是我自己的习惯
学习时关注重点粗线条,使用中熟悉细节。