在上篇中有一个基本的input的设备的简介,这里我们在说一下input core相关的东东。
先来个开胃菜,先看看struct input_dev
struct input_dev { const char *name; //device的name const char *phys; //设备的物理路径 const char *uniq; //设备唯一的id编码 struct input_id id; //设备id unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //设备支持的events类型的bitmap(EV_KEY, EV_REL, etc) unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //设备使用的keys/buttons的bitmap unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //设备相关轴心的bitmap??? unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //设备绝对轴心的bitmap?? unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //设备支持的混合evetns的bitmap unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //设备上存在的leds的bitmap unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //设备支持的音效的bitmap unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //设备支持的回馈效果的bitmap unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //设备上是否有开关的bitmap unsigned int keycodemax; //keycode table的大小 unsigned int keycodesize; //size of elements in keycode table void *keycode; //设备扫描到的keycodes的映射 int (*setkeycode)(struct input_dev *dev, int scancode, int keycode); //可选的方法来改变当前的keymap,用来修改少量的keymaps。如果不使用,则会有默认的途径来使用 int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode); //可选的方法来恢复(retrieve)当前的keymap。 struct ff_device *ff; //如果设备支持力反馈,则这个结构体要关联 unsigned int repeat_key; //存储上次按下的按键值,用来实现软件的自动重复 struct timer_list timer; //软件自动重复的定时时间 int sync; //从上次的EV_SYNC后没有新的events就设置为1 int abs[ABS_MAX + 1]; //来自绝对轴的当前值 int rep[REP_MAX + 1]; //当前值的自动重复参数例如(delay,rate) unsigned long key[BITS_TO_LONGS(KEY_CNT)]; //设备的按键的当前状态 unsigned long led[BITS_TO_LONGS(LED_CNT)]; //设备的leds的当前状态 unsigned long snd[BITS_TO_LONGS(SND_CNT)]; //音效的当前状态 unsigned long sw[BITS_TO_LONGS(SW_CNT)]; //设备开关的当前状态 int absmax[ABS_MAX + 1]; //来自绝对坐标的最大events值 int absmin[ABS_MAX + 1]; //来自绝对坐标的最小events值 int absfuzz[ABS_MAX + 1]; //描述轴的噪声 int absflat[ABS_MAX + 1]; //中心位置的大小(used by joydev) int absres[ABS_MAX + 1]; int (*open)(struct input_dev *dev); //input_open_device。驱动必须已经可以产生events(通过polling,IRQ,etc) void (*close)(struct input_dev *dev); //input_close_device int (*flush)(struct input_dev *dev, struct file *file);//清除设备 int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);//这个在这个结构体中比较的重要,是上报events的入口。 struct input_handle *grab; spinlock_t event_lock; //当input core接收或者产生一个events的时候,spinlock起作用 struct mutex mutex; //会串行执行open(),close()和flush()方法 unsigned int users; //存储打开此设备的用户数量,这个来有助于知道谁是第一个打开设备的用户,谁是最后一个关闭设备的用户 bool going_away; // struct device dev; struct list_head h_list; //设备的input handles的列表 struct list_head node; //用来在input_dev_list中放置设备 }
下面开始进入正文
1、input device初始化中几个主要的地方
input_register_handler//这里来注册input的handler,在handler中声明了event,这个event就是在input事件上报时的入口函数,下面的代码流程中我们可以看到 keypad_input_dev = input_allocate_device(); //通过调用kzalloc()来申请一块内存区域。 //当然在以后的注册过程中出错,要注意通过input_free_device释放申请到的此块区域 __set_bit(xxx, keypad_input_dev); //通过set bit来设置input_dev的相关的bit,这里就要看自己的设备中到底是使用哪些, //这个可以看看linux/input.h文件中的input_dev input_register_device(); //注册input设备 //与之相对应的是input_unregister_device()
2、上报过程
这里我们跳过keypad的函数,从input开始
input_report_key(struct input_dev *dev, unsigned int code, int value); //上报所读取到的按键值,这里其实是封装了input_event(struct input_dev *dev, unsigend int type, unsigend int code, int value); -----if(is_event_supported(type,dev->evbit, EV_MAX); //根据dev->evbit来判断是否支持当前的type -----add_input_randomness(type,code,value); //这个主要是给系统加入随机数产生来使用的,这个与input core无关,但是对系统产生随机数很重要 -----input_handle_event(dev,type,code,value); ----input_pass_event(struct input_dev *dev, unsigned int type, unsigend int code, int value) 在这个函数中则调用了handle->handler->event,这个event就是我们在上述结构体中要注意的 在这里我们的keypad的event就是kbd_event。 kbd_event(struct input_handle *handle, unsigned int event_type, unsigned int event_code, int value) ----kbd_keycode(unsigned int keycode, int down, int hw_raw) ---put_queue(struct vc_data *vc, int ch)//看到这里,我们可以发现将我们所扫描到的keycode传递给了tty设备,关于tty设备和input设备的关系后面在讲
3、应用层如何获得
下面我们看看上面应用层是如何取得的。
首先是framework_base/base/libs/ui/EventHub.cpp
bool EventhHub::getEvent(int32_t* outDevciceId,int32_t* outType, int32_t* outScancode, int32_t* outKeycode, uint32_t* outFlags, int32_t* outValue, nsecs_t* outWhen) -----bool EventHub::openPlatformInput() //打开platform中的input设备 ----scan_dir() //扫描input下的设备,当然这里会涉及到系统的一个通知进程inotify,这个后续查看
在这里的getEvent是来获得evnet事件,相当于加了一层过滤,当有新的数据时候,则返回了,应用的thread也开始读取。
其上是jni传递给上层的,最后通过WindowManagerService中开始分发给相关的应用去做处理。
一个简单的图:
看了之后才发现内核中的哪个部分也不能小看,小设备,大文章。看来对内核的理解还是不够呀,慢慢的过程呀。。。
Have fun!