当前位置: 首页 > news >正文

【linux kernel 常用数据结构和设计模式】【数据结构 3】【模拟input子系统input_dev和input_handler之间的多对多关系】

一、背景

上节内容我们介绍了 内核中 一对一、一对多、多对多 的数据结构, 本节我们参照内核 input 子系统来模拟 input 子系统里
input_devinput_handler 多对多关系,用中间对象 input_handle 把两者连起来。
加载模块后,可以在 dmesg 里看到设备和处理器的绑定关系。

二、驱动

2.1 code

// demo_input_m2m.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>struct my_input_dev;
struct my_input_handler;
struct my_input_handle;/* 中间关系对象 */
struct my_input_handle {struct my_input_dev *dev;struct my_input_handler *handler;struct list_head d_node; /* 挂到 dev->h_list */struct list_head h_node; /* 挂到 handler->h_list */
};/* 设备 */
struct my_input_dev {const char *name;struct list_head h_list; /* 所有关联的 handle */struct list_head node;   /* 挂到全局 dev_list */
};/* 处理器 */
struct my_input_handler {const char *name;struct list_head h_list; /* 所有关联的 handle */struct list_head node;   /* 挂到全局 handler_list */
};/* 全局链表 */
static LIST_HEAD(dev_list);
static LIST_HEAD(handler_list);/* 工具函数:创建 handle 并建立关联 */
static void connect_dev_handler(struct my_input_dev *dev,struct my_input_handler *handler)
{struct my_input_handle *handle;handle = kzalloc(sizeof(*handle), GFP_KERNEL);if (!handle)return;handle->dev = dev;handle->handler = handler;INIT_LIST_HEAD(&handle->d_node);INIT_LIST_HEAD(&handle->h_node);/* 双向挂接 */list_add(&handle->d_node, &dev->h_list);list_add(&handle->h_node, &handler->h_list);pr_info("Connect: dev=%s <-> handler=%s\n", dev->name, handler->name);
}/* 初始化 demo */
static int __init demo_init(void)
{struct my_input_dev *kbd, *mouse;struct my_input_handler *evdev, *mousedev;struct my_input_handle *h;pr_info("demo_input_m2m init\n");/* 创建设备 */kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);mouse = kzalloc(sizeof(*mouse), GFP_KERNEL);kbd->name = "keyboard";mouse->name = "mouse";INIT_LIST_HEAD(&kbd->h_list);INIT_LIST_HEAD(&mouse->h_list);list_add(&kbd->node, &dev_list);list_add(&mouse->node, &dev_list);/* 创建 handler */evdev = kzalloc(sizeof(*evdev), GFP_KERNEL);mousedev = kzalloc(sizeof(*mousedev), GFP_KERNEL);evdev->name = "evdev";mousedev->name = "mousedev";INIT_LIST_HEAD(&evdev->h_list);INIT_LIST_HEAD(&mousedev->h_list);list_add(&evdev->node, &handler_list);list_add(&mousedev->node, &handler_list);/* 建立绑定关系 */connect_dev_handler(kbd, evdev);     // keyboard -> evdevconnect_dev_handler(kbd, mousedev);  // keyboard -> mousedevconnect_dev_handler(mouse, evdev);   // mouse -> evdev/* 打印绑定关系 */list_for_each_entry(kbd, &dev_list, node) {pr_info("Device %s bound to: ", kbd->name);list_for_each_entry(h, &kbd->h_list, d_node) {pr_cont("%s ", h->handler->name);}pr_cont("\n");}return 0;
}/* 清理 */
static void __exit demo_exit(void)
{struct my_input_dev *d, *d_tmp;struct my_input_handler *h, *h_tmp;struct my_input_handle *hdl, *hdl_tmp;/* 释放 handle */list_for_each_entry(d, &dev_list, node) {list_for_each_entry_safe(hdl, hdl_tmp, &d->h_list, d_node) {list_del(&hdl->d_node);list_del(&hdl->h_node);kfree(hdl);}}/* 释放 dev */list_for_each_entry_safe(d, d_tmp, &dev_list, node) {list_del(&d->node);kfree(d);}/* 释放 handler */list_for_each_entry_safe(h, h_tmp, &handler_list, node) {list_del(&h->node);kfree(h);}pr_info("demo_input_m2m exit\n");
}module_init(demo_init);
module_exit(demo_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("leo demo");
MODULE_DESCRIPTION("Demo: input_dev <-> input_handler many-to-many");

2.2 允许

/test # insmod demo_input_m2m.ko 
[   30.580747] demo_input_m2m init
[   30.581018] Connect: dev=keyboard <-> handler=evdev
[   30.581140] Connect: dev=keyboard <-> handler=mousedev
[   30.581275] Connect: dev=mouse <-> handler=evdev
[   30.581404] Device mouse bound to: evdev 
[   30.581569] Device keyboard bound to: mousedev evdev 
/test # 
/test # 

三、对比 input 子系统的真实实现

  • 真正的 input 子系统用 input_handle 作为中间结构,和上面 demo 一样。

  • input_register_device() 时,遍历所有 handler,看谁能处理这个 dev,就创建 handle 挂上。

  • input_register_handler() 时,也会遍历所有 dev,看谁能被处理,建立 handle。

  • 多对多关系由 双向链表 + 中间对象 管理,支持设备和处理器的 动态添加删除


文章转载自:

http://WihqawoM.fgsct.cn
http://FcT5UJkx.fgsct.cn
http://6fT1xPby.fgsct.cn
http://BjCLtvTN.fgsct.cn
http://SZjokg80.fgsct.cn
http://X7eTX6SK.fgsct.cn
http://rrYQZnUf.fgsct.cn
http://nJW7nASW.fgsct.cn
http://k7lEg0Wt.fgsct.cn
http://o0aKU6Sq.fgsct.cn
http://o1n5YXgw.fgsct.cn
http://HR0wdV9o.fgsct.cn
http://FAh3aVwR.fgsct.cn
http://aH339HNS.fgsct.cn
http://EhiSirmv.fgsct.cn
http://hVDjbpy8.fgsct.cn
http://h5mEFEus.fgsct.cn
http://5P6X7gAZ.fgsct.cn
http://AKSCp85c.fgsct.cn
http://4dfzWLUA.fgsct.cn
http://cLaeER27.fgsct.cn
http://PFYMp0zy.fgsct.cn
http://Ru0F7zVn.fgsct.cn
http://F9RdC0pl.fgsct.cn
http://koVs2CYa.fgsct.cn
http://t6WoHaGb.fgsct.cn
http://PjTuVzTD.fgsct.cn
http://KfDNEoxJ.fgsct.cn
http://Rd1vmqx4.fgsct.cn
http://7RLofQEl.fgsct.cn
http://www.dtcms.com/a/371370.html

相关文章:

  • 怎么用CXL加速数据库?· SIGMOD‘25
  • Day23_【机器学习—聚类算法—K-Means聚类 及评估指标SSE、SC、CH】
  • Uniapp 怎么修改项目图标和启动页
  • macos安装openjdk17
  • 像素图生成小程序开发全解析:从图片上传到Excel图纸
  • 运维服务方案,运维巡检方案,运维安全保障方案文件
  • 计算机网络相关
  • 【代码讲解】北通手柄遥控 + Mujoco 仿真 SO-ARM100 机械臂末端位姿
  • ARM 体系结构
  • 云平台面试内容(一)
  • React Hooks 钩子
  • js逆向之JSEncrypt的加密
  • Balabolka:免费高效的文字转语音软件
  • 第3天-Jenkins详解-3
  • Linux内核进程管理子系统有什么第四十三回 —— 进程主结构详解(39)
  • Apache 2.0 开源协议详解:自由、责任与商业化的完美平衡-优雅草卓伊凡
  • 【iOS】多界面传值
  • 【C++】简单介绍lambda表达式
  • uv 包管理器:优势解析与使用指南
  • Android studio的adb和终端的adb互相抢占端口
  • 同类软件对比(四):Jupyter vs PyCharm vs VS Code:Python开发工具终极选择指南
  • 【MySQL】数据库的基本操作
  • PaddlePaddle——飞桨深度学习实现手写数字识别任务
  • Docker Compose 运行 Milvus (Mac) 并与 python 连接测试
  • 03-Redis 安装指南:从版本选择到多系统部署(Windows+macOS+Linux)
  • 路由策略实验配置
  • 【高并发内存池】五、页缓存的设计
  • PHP - OPcache 字节码缓存 - 学习/实践
  • redis学习——七
  • nginx反向代理不转发静态文件的解决办法