linux输入子系统(3)

1.4       input_dev 的注册

在输入设备驱动的初始化函数的最后一步就是调用 input_register_device 注册设备。这个函数如 程序清单 1 .9 所示。

程序清单 1 . 9   input_register_device

/* driver/input/input.c */

int input_register_device(struct input_dev *dev)

{

         static atomic_t input_no = ATOMIC_INIT(0);

         struct input_handler *handler;

         const char *path;

         int error;

 

         __set_bit(EV_SYN, dev->evbit);                                                                                                

 

         init_timer(&dev->timer);                                                                                                             

         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)                                                                                                                  

                   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)

                   return error;

 

         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);

                   return error;

         }

 

         list_add_tail(&dev->node, &input_dev_list);                                                                              

 

         list_for_each_entry(handler, &input_handler_list, node)                                                             

                   input_attach_handler(dev, handler);

 

         input_wakeup_procfs_readers();

 

         mutex_unlock(&input_mutex);

         return 0;

}

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

⑴ 注册同步事件为支持的类型,任何设备都默认支持同步事件。

⑵ 初始化设备连击计时器,如果驱动没有填写连击参数就使用默认值。

⑶ 如果驱动没有实现映射修改和查看的函数,填充默认函数。

⑷ 将本设备加入设备链表 ( 这个链表是全局的 )

⑸ 将本设备和已经存在的 handler 进行比较,与 id 相匹配的 handler 建立连接。需要说明的是设备可能跟多个 handler 连接,这样此设备产生的事件会分发给所有连接的 handler

可以看出上面第五步是最重要的一步,下面继续分析 input_attach_handler 这个函数。它的代码如 程序清单 1 .10 所示。

程序清单 1 . 10     input_attach_handler

/* driver/input/input.c */

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

{

         const struct input_device_id *id;

         int error;

 

         if (handler->blacklist && input_match_device(handler->blacklist, dev))                                    

                   return -ENODEV;

 

         id = input_match_device(handler->id_table, dev);                                                                       

         if (!id)

                   return -ENODEV;

 

         error = handler->connect(handler, dev, id);                                                                                 

         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);

 

         return error;

}

需要说明的地方有三点:

handler->blacklist 中存储的是禁止连接的设备 id ,因此首先查看该设备是否允许连接。

handler->id_table 存储 handler 支持的设备 id 。如果能够找到匹配的 id ,则建立 devhandler 之间的连接。

⑶ 建立 devhandler 之间的连接。

connect 函数的实现下章再讲,下面看看 input_match_device 的实现。代码如 程序清单 1 .11 所示。

程序清单 1 . 11   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]) /                                                               

                                     break; /

                   if (i != BITS_TO_LONGS(max)) /

                            continue;

 

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

                                                                 struct input_dev *dev)

{

         int i;

 

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

                   if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)                                                    

                            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);                                                                                            

                   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);

                   return id;

         }

         return NULL;

}

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

⑵ 根据 id->flag 检查 id 是否匹配。 id->flag 记录需要匹配哪些域。

⑶ 检查支持的事件种类是否一致。

第二种检查用到的宏 MATCH_BIT 定义在 ⑴ 处。其中最重要的一句是“ 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 。下面继续分析事件的传递。

基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究(Matlab代码实现)内容概要:本文围绕“基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究”展开,提出了一种结合数据驱动方法与Koopman算子理论的递归神经网络(RNN)模型线性化方法,旨在提升纳米定位系统的预测控制精度与动态响应能力。研究通过构建数据驱动的线性化模型,克服了传统非线性系统建模复杂、计算开销大的问题,并在Matlab平台上实现了完整的算法仿真与验证,展示了该方法在高精度定位控制中的有效性与实用性。; 适合人群:具备一定自动化、控制理论或机器学习背景的科研人员与工程技术人员,尤其是从事精密定位、智能控制、非线性系统建模与预测控制相关领域的研究生与研究人员。; 使用场景及目标:①应用于纳米级精密定位系统(如原子力显微镜、半导体制造设备)中的高性能预测控制;②为复杂非线性系统的数据驱动建模与线性化提供新思路;③结合深度学习与经典控制理论,推动智能控制算法的实际落地。; 阅读建议:建议读者结合Matlab代码实现部分,深入理解Koopman算子与RNN结合的建模范式,重点关注数据预处理、模型训练与控制系统集成等关键环节,并可通过替换实际系统数据进行迁移验证,以掌握该方法的核心思想与工程应用技巧。
基于粒子群算法优化Kmeans聚类的居民用电行为分析研究(Matlb代码实现)内容概要:本文围绕基于粒子群算法(PSO)优化Kmeans聚类的居民用电行为分析展开研究,提出了一种结合智能优化算法与传统聚类方法的技术路径。通过使用粒子群算法优化Kmeans聚类的初始聚类中心,有效克服了传统Kmeans算法易陷入局部最优、对初始值敏感的问题,提升了聚类的稳定性和准确性。研究利用Matlab实现了该算法,并应用于居民用电数据的行为模式识别与分类,有助于精细化电力需求管理、用户画像构建及个性化用电服务设计。文档还提及相关应用场景如负荷预测、电力系统优化等,并提供了配套代码资源。; 适合人群:具备一定Matlab编程基础,从事电力系统、智能优化算法、数据分析等相关领域的研究人员或工程技术人员,尤其适合研究生及科研人员。; 使用场景及目标:①用于居民用电行为的高效聚类分析,挖掘典型用电模式;②提升Kmeans聚类算法的性能,避免局部最优问题;③为电力公司开展需求响应、负荷预测和用户分群管理提供技术支持;④作为智能优化算法与机器学习结合应用的教学与科研案例。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,深入理解PSO优化Kmeans的核心机制,关注参数设置对聚类效果的影响,并尝试将其应用于其他相似的数据聚类问题中,以加深理解和拓展应用能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值