linux输入子系统(3)

============================================
作者:yuanlulu
http://blog.csdn.net/yuanlulu


版权没有,但是转载请保留此段声明
============================================


1.4      input_dev的注册

在输入设备驱动的初始化函数的最后一步就是调用input_register_device注册设备。这个函数如<!--[if supportFields]> REF _Ref282018491 /h <![endif]-->程序清单 1.9<!--[if gte mso 9]><![endif]--><!--[if supportFields]><![endif]-->所示。

程序清单 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->1<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程序清单 /* ARABIC /s 1 <![endif]-->9<!--[if supportFields]><![endif]-->  input_register_device

/* driver/input/input.c */

int input_register_device(struct input_dev *dev)

{

         staticatomic_t input_no = ATOMIC_INIT(0);

         structinput_handler *handler;

         constchar *path;

         interror;

 

         __set_bit(EV_SYN,dev->evbit);                                                                                                 <!--[if supportFields]> = 1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->

 

         init_timer(&dev->timer);                                                                                                              <!--[if supportFields]> = 2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->

         if(!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {

                   dev->timer.data= (long) dev;

                   dev->timer.function= input_repeat_key;

                   dev->rep[REP_DELAY]= 250;

                   dev->rep[REP_PERIOD]= 33;

         }

 

         if(!dev->getkeycode)                                                                                                                   <!--[if supportFields]> = 3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->

                   dev->getkeycode= input_default_getkeycode;

         if(!dev->setkeycode)

                   dev->setkeycode= input_default_setkeycode;

 

         snprintf(dev->dev.bus_id,sizeof(dev->dev.bus_id),

                    "input%ld", (unsigned long)atomic_inc_return(&input_no) - 1);

 

         error =device_add(&dev->dev);

         if(error)

                   returnerror;

 

         path =kobject_get_path(&dev->dev.kobj, GFP_KERNEL);

         printk(KERN_INFO"input: %s as %s/n",

                   dev->name? dev->name : "Unspecified device", path ? path :"N/A");

         kfree(path);

 

         error =mutex_lock_interruptible(&input_mutex);

         if(error) {

                   device_del(&dev->dev);

                   returnerror;

         }

 

         list_add_tail(&dev->node,&input_dev_list);                                                                               <!--[if supportFields]> = 4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->

 

         list_for_each_entry(handler,&input_handler_list, node)                                                              <!--[if supportFields]> = 5 /* GB2 <![endif]-->⑸<!--[if supportFields]><![endif]-->

                   input_attach_handler(dev,handler);

 

         input_wakeup_procfs_readers();

 

         mutex_unlock(&input_mutex);

         return0;

}

下面就标记的几点进行说明:

<!--[if supportFields]> =1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->注册同步事件为支持的类型,任何设备都默认支持同步事件。

<!--[if supportFields]> =2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->初始化设备连击计时器,如果驱动没有填写连击参数就使用默认值。

<!--[if supportFields]> =3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->如果驱动没有实现映射修改和查看的函数,填充默认函数。

<!--[if supportFields]> =4 /* GB2 <![endif]-->⑷<!--[if supportFields]><![endif]-->将本设备加入设备链表(这个链表是全局的)

<!--[if supportFields]> =5 /* GB2 <![endif]-->⑸<!--[if supportFields]><![endif]-->将本设备和已经存在的handler进行比较,与id相匹配的handler建立连接。需要说明的是设备可能跟多个handler连接,这样此设备产生的事件会分发给所有连接的handler

可以看出上面第五步是最重要的一步,下面继续分析input_attach_handler这个函数。它的代码如<!--[if supportFields]> REF _Ref282020091 /h <![endif]-->程序清单 1.10<!--[if gte mso 9]><![endif]--><!--[if supportFields]><![endif]-->所示。

程序清单 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->1<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程序清单 /* ARABIC /s 1 <![endif]-->10<!--[if supportFields]><![endif]-->   input_attach_handler

/* driver/input/input.c */

static int input_attach_handler(struct input_dev *dev,struct input_handler *handler)

{

         conststruct input_device_id *id;

         interror;

 

         if(handler->blacklist && input_match_device(handler->blacklist,dev))                                     <!--[if supportFields]> = 1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->

                   return-ENODEV;

 

         id =input_match_device(handler->id_table, dev);                                                                        <!--[if supportFields]> = 2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->

         if (!id)

                   return-ENODEV;

 

         error =handler->connect(handler, dev, id);                                                                                  <!--[if supportFields]> = 3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->

         if(error && error != -ENODEV)

                   printk(KERN_ERR

                            "input:failed to attach handler %s to device %s, "

                            "error:%d/n",

                            handler->name,kobject_name(&dev->dev.kobj), error);

 

         returnerror;

}

需要说明的地方有三点:

<!--[if supportFields]> =1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->handler->blacklist中存储的是禁止连接的设备id,因此首先查看该设备是否允许连接。

<!--[if supportFields]> =2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]--> handler->id_table存储handler支持的设备id。如果能够找到匹配的id,则建立devhandler之间的连接。

<!--[if supportFields]> =3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->建立devhandler之间的连接。

connect函数的实现下章再讲,下面看看input_match_device的实现。代码如<!--[if supportFields]> REF _Ref282020868 /h <![endif]-->程序清单 1.11<!--[if gte mso 9]><![endif]--><!--[if supportFields]><![endif]-->所示。

程序清单 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->1<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程序清单 /* ARABIC /s 1 <![endif]-->11<!--[if supportFields]><![endif]-->  input_match_device

/* driver/input/input.c */

#define MATCH_BIT(bit, max) /

                   for(i = 0; i < BITS_TO_LONGS(max); i++) /                                                                 

                            if((id->bit[i] & dev->bit[i]) != id->bit[i]) /                                                                <!--[if supportFields]> = 1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->

                                     break;/

                   if(i != BITS_TO_LONGS(max)) /

                            continue;

 

static const struct input_device_id*input_match_device(const struct input_device_id *id,

                                                                 structinput_dev *dev)

{

         int i;

 

         for (;id->flags || id->driver_info; id++) {

                   if(id->flags & INPUT_DEVICE_ID_MATCH_BUS)                                                     <!--[if supportFields]> = 2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->

                            if(id->bustype != dev->id.bustype)

                                     continue;

 

                   if(id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)

                            if(id->vendor != dev->id.vendor)

                                     continue;

 

                   if(id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)

                            if(id->product != dev->id.product)

                                     continue;

 

                   if(id->flags & INPUT_DEVICE_ID_MATCH_VERSION)

                            if(id->version != dev->id.version)

                                     continue;

 

                   MATCH_BIT(evbit,  EV_MAX);                                                                                             <!--[if supportFields]> = 3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->

                   MATCH_BIT(keybit,KEY_MAX);

                   MATCH_BIT(relbit,REL_MAX);

                   MATCH_BIT(absbit,ABS_MAX);

                   MATCH_BIT(mscbit,MSC_MAX);

                   MATCH_BIT(ledbit,LED_MAX);

                   MATCH_BIT(sndbit,SND_MAX);

                   MATCH_BIT(ffbit,  FF_MAX);

                   MATCH_BIT(swbit,  SW_MAX);

                   returnid;

         }

         returnNULL;

}

匹配的过程主要做了两件事:

<!--[if supportFields]> =2 /* GB2 <![endif]-->⑵<!--[if supportFields]><![endif]-->根据id->flag检查id是否匹配。id->flag记录需要匹配哪些域。

<!--[if supportFields]> =3 /* GB2 <![endif]-->⑶<!--[if supportFields]><![endif]-->检查支持的事件种类是否一致。

第二种检查用到的宏MATCH_BIT定义在<!--[if supportFields]> = 1 /* GB2 <![endif]-->⑴<!--[if supportFields]><![endif]-->处。其中最重要的一句是“if ((id->bit[i] &dev->bit[i]) != id->bit[i])”,这句话意味着id支持的事件种类是dev支持的事件的子集就算匹配了。如果某个handlerid除了id->driver_info之外的域都为0,那么此handler可以和任意dev匹配。实际上<内核>/driver/input/evdev.c中就是这么初始化id的。

现在总结一下input_dev注册的过程:一个input_dev注册的过程主要是在将自己加入input_dev_list,然后在input_handler_list中找到id和事件种类相匹配的handler并与之建立连接的过程。

input_dev产生的事件会分发给所有建立连接的handler。下面继续分析事件的传递。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值