闲聊linux中的input设备(3)如果不认识他们仨,故事继续不下去了

来源:互联网 发布:freecodecamp java 编辑:程序博客网 时间:2024/05/16 23:42

       http://blog.csdn.net/lmm670/article/details/6081019

         最近有这样一个事情:18名上海某名牌大学学生为了寻求刺激,到某险地进行探险,后迷失森林,然后肚子饿了,衣服穿少了冷,于是与打电话求助当地警员。最后这帮大学生都得以救出,然后饭也吃饱了,衣服也加上了,不过在救援的途中,人民的儿子,年轻的张宁海警员永远离我们而去了。好好地大学生放着课不上,去外地探险……

好了废话不多说。继续我们的input设备之旅。
从前一节来看,在linux内核中添加一个input设备变得很简单了。我们再也不必须去动手写那些该死的接口函数了。可是你有没有想过,是谁让我们的工作变得这么简单了呢?答案是linux内核中的input core。她总是那么痴情,默默地不求回报地为你做许许多多的事情,在你背后默默的支持你爱着你。是的,你所想到的大多数事情,我们的input core都已经为你做好。除了感动,我们还能说什么呢?(input core对应的实体在linux内核源码目录linux-2.6.29/drivers/input/input.c文件)
在正式接触我们可爱的input core之前,有必要了解一下几个重要的结构体,这几个结构体是我们这个故事的主体。

        第一个数据结构 struct input_dev。悟性高的哥们马上就会想到,它就是我们input 设备在linux内核中的模拟,即里面记录了一个input设备的所有信息。定义于linux-2.6.29/include/linux/input.h中

struct input_dev { const char *name;       const char *phys;       const char *uniq;       struct input_id id;       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 keycodemax;       unsigned int keycodesize;       void *keycode;       int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);       int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);       struct ff_device *ff;       unsigned int repeat_key;       struct timer_list timer;       int sync;       int abs[ABS_MAX + 1];       int rep[REP_MAX + 1];       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 absmax[ABS_MAX + 1];       int absmin[ABS_MAX + 1];       int absfuzz[ABS_MAX + 1];       int absflat[ABS_MAX + 1];        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 *grab;       spinlock_t event_lock;       struct mutex mutex;       unsigned int users;       int going_away;       struct device dev;       struct list_head  h_list;       struct list_head  node;};
很强大的一个结构体,因为她把所有的input设备的信息都考虑到了,真的是很无私。不过对于我们的akm驱动来说只需要关注几个小细节,结构中的加粗部分。unsigned long evbit[BITS_TO_LONGS(EV_CNT)]表示此input设备支持的事件,比如前面的第二节中的set_bit(EV_ABS, akm->input_dev->evbit)设置input_dev->evbit中的相应位让它支持绝对值坐标。类似的还有以下这些事件:EV_KEY -按键, EV_REL -相对坐标EV_ABS -绝对坐标,EV_LED - LED,EV_FF- 力反馈。unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];设置相应的位以支持某一类绝对值坐标。比如第二节中的input_set_abs_params(akm->input_dev, ABS_RX, 0, 23040, 0, 0);它的函数体如下:

static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat){       dev->absmin[axis] = min;       dev->absmax[axis] = max;       dev->absfuzz[axis] = fuzz;       dev->absflat[axis] = flat;        dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);}
表示支持绝对值x坐标,并设置它在坐标系中的最大值和最小值,以及干扰值和平焊位置等。
struct list_head h_list;表示的是和该设备相关的所有input handle的结构体链表(input handle为何物下文马上会讲到)。struct list_head node;所有input设备组成的链表结构(后面将会知道它对应于input_dev_list)。

Ok 马上进入第二个结构体struct input_handler(还是来自linux-2.6.29/include/linux/input.h)

struct input_handler {        void *private;        void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);       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);        const struct file_operations *fops;       int minor;       const char *name;        const struct input_device_id *id_table;       const struct input_device_id *blacklist;        struct list_head  h_list;       struct list_head  node;};
顾名思义:用来处理input设备的一个结构体。struct list_head h_list表示的是和该设备相关的所有input handle的结构体链表和前面那个一样;struct list_head node所有input_handle组成的结构体连链表(后面将会知道它对应于input_handler_list)。每一个input设备在注册时,他都会遍历input_handler_list链表上的每一个input_handler,去找寻他心中的那个她,同理每一个input_handler在注册时,他也会去input_dev_list上找寻那个属于他的她。有时候事情往往不会那么尽如人意,当input_handler还没出生时,你这个input_dev就一直在那等吧,等到天荒地老,等到海枯石烂。最后来一句,我等到花儿也谢了,你丫到底还来不来啊。注意这里的input_handler和input_dev并不是一一对应的关系,有时一个input_handler对应好几个input_dev。于是乎,作为看代码的我就在想,linux内核开发者的思想怎么这么不单纯呢,这不明摆着教育我们搞一夫多妻制吗,不过管怎样,还是得记住公司的企业文化,本分点。如果你丫说你同时拥有两个马子,我将会无情的向你抛出那句话:“出来混,迟早要还的!”。

前面多次提到那个input_handle(注意区别input_handler),她到底是何方神圣。好吧,就让我们来一层一层揭开她那神秘的面纱,当你第一次看到她完完全全展现在你面前时,那时候你的满足感和兴奋度和她的害羞度是成正比的。
同样来自linux-2.6.29/include/linux/input.h

struct input_handle {        void *private;        int open;       const char *name;        struct input_dev *dev;       struct input_handler *handler;        struct list_head  d_node;       struct list_head  h_node;};
怎么啦?是不是很失望,原来就这么回事啊。嗯,没错,兄弟,就这么回事。人往往都这样,得到了某样东西,想想觉得就那么回事,没得到呢,那叫一个好奇,那叫一个盼望。好了既然看到她的庐山真面目了,就坦然面对她,作为一个负责的男人,我还是来好好研究一下。
Input_Handle其实也好理解,它就是input_dev和 input_handler粘合剂,通过Input_Handle这么一搅和,input_dev就和 input_handler发生了点关系,至于什么样的关系我们后文将会知道的一清二楚。struct input_dev *dev对应的input设备。struct input_handler *handler对应该设备的handler。struct list_head d_node和struct list_head h_node则分别关联上前面两个结构体中的struct list_head h_list。

终于告一段落了,休息,休息一下!