现在的位置: 首页 > 综合 > 正文

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

2013年06月08日 ⁄ 综合 ⁄ 共 5006字 ⁄ 字号 评论关闭

最近有这样一个事情: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。

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

抱歉!评论已关闭.