概述
目录
- 分层分析
- 1.input核心层:input.c
- 2.input handler层:evdev.c
- 3.input device层:(自己写的simple_input.c)
- 4.分层分析框架
分层分析
1.input核心层:input.c
【1】模块入口:
subsys_initcall(input_init);
module_exit(input_exit);
【2】input_init主要实现的功能
- 1.注册类,类似于class_create()
class_register(&input_class);
- 2.在proc创建bus/input/devices handlers
input_proc_init();
- 3.申请设备号
register_chrdev(INPUT_MAJOR, "input", &input_fops);
【3】总结
- 1.注册了主设备号
- 2.注册了input class
2.input handler层:evdev.c
【1】模块入口
module_init(evdev_init);
module_exit(evdev_exit);
【2】evdev_init主要实现的功能
evdev_init()
input_register_handler(&evdev_handler);
//初始化h_list
INIT_LIST_HEAD(&handler->h_list);
//将当前的handler加入到一个input_handler_list中
list_add_tail(&handler->node, &input_handler_list);
//遍历链表input_dev_list
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
//将当前的handler和input dev进行匹配,event handler能够匹配所有的input dev
input_match_device(handler, dev);
//匹配成功之后要调用handler中的connect方法
//实际就是event handler ,实际就是调用了evdev_connect
handler->connect(handler, dev, id);
//将当前的handler加入到/proc/bus/input/handler
input_wakeup_procfs_readers();
【2.1】input_register_handler(&evdev_handler);的参数 evdev_handler
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE, //次设备号开始值64
.name = "evdev",
.id_table = evdev_ids,
};
【3】分析evdev_handler中的connect方法-----evdev_connect
static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id)
//找到一个没用被使用的次设备号,从64开始,65,66,67....
for (minor = 0; minor < EVDEV_MINORS; minor++)
if (!evdev_table[minor])
break;
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devicesn");
return -ENFILE;
}
//实例化一个evdev对象
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
//初始化evdev对象
INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
//等待队列是完成阻塞
init_waitqueue_head(&evdev->wait);
//创建设备文件/dev/event0,1,2....-------效果跟device_create是一样的
dev_set_name(&evdev->dev, "event%d", minor);
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
//利用handler记录input device和input handler
evdev->handle.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;
//你中有我,我中有你
evdev->handle.private = evdev;
//将儿子关联到父亲(input handler)和母亲(input dev)
input_register_handle(&evdev->handle);
evdev_install_chrdev(evdev);
device_add(&evdev->dev);
【3.1】input handler 和input dev 和evdev 三者的关系图
【3.2】evdev_connect 总结:
- 分配evdev,并初始化,记录input device 和handler的关系
- 创建设备结点/dev/input/evevt0,1,2…
- 注册cdev,并实现fpos
- 关系:多个input device可以对应一个event handler;一个input device对应一个evdev,对应于一个设备结点/dev/input/evevt0,1,2…
- 所有设备结点调用open,read…等文件io的时候实际是调用cdev中fops中各个接口,最终调用了
static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
.flush = evdev_flush
};
【4】input handler层总结
- 1.注册了evdev_handler
- 2.遍历input_dev_list,并进行恒匹配,匹配成功自动调用handler中的connect方法-----evdev_connect
3.input device层:(自己写的simple_input.c)
【1】模块入口
module_init(simple_input_init);
module_exit(simple_input_exit);
【2】simple_input_init
simple_input_init()
input_register_device(inputdev);
//将input dev加入到链表input_dev_list
list_add_tail(&dev->node, &input_dev_list);
//遍历input handler链表,进行匹配
list_for_each_entry(handler, &input_handler_list, node)
//调用跟handler层一样的匹配函数进行匹配
input_attach_handler(dev, handler);
//将当前的input deev加入到/proc/bus/input/input dev
input_wakeup_procfs_readers();
4.分层分析框架
最后
以上就是可爱蚂蚁为你收集整理的Linux驱动开发之input子系统(2)------- 输入子系统的分层分析分层分析的全部内容,希望文章能够帮你解决Linux驱动开发之input子系统(2)------- 输入子系统的分层分析分层分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复