输入子系统(二)
来源:互联网 发布:虚拟社交网络弊大于利 编辑:程序博客网 时间:2024/06/06 11:36
一、输入子系统初始化过程:
kernel/drivers/input/input.c
1.1、input_init( )初始化
static int __init input_init(void){ int err; err = class_register(&input_class); if (err) { pr_err("unable to register input_dev class\n"); return err; } /* 注册input_class类,所有input_device均为此类 struct class input_class = { .name = "input", .devnode = input_devnode, }; */ /* 在/proc下建立相关交互文件 */ err = input_proc_init(); if (err) goto fail1; /* 注册主设备号为INPUT_MAJOR,此设备好为0~255的字符设备 * 操作指针为input_fops。 */ err = register_chrdev(INPUT_MAJOR, "input", &input_fops); if (err) { pr_err("unable to register char major %d", INPUT_MAJOR); goto fail2; } return 0; fail2: input_proc_exit(); fail1: class_unregister(&input_class); return err;}
1.2、input_open_file( )文件打开函数
static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, .llseek = noop_llseek,};/* 此处将控制转到input_handler中定义的fops文件指针的open()函数, * 该函数在input_handler中实现, 因此不同的handler处理器对应不同的文件打开方法. */static int input_open_file(struct inode *inode, struct file *file){ struct input_handler *handler; const struct file_operations *old_fops, *new_fops = NULL; int err; err = mutex_lock_interruptible(&input_mutex); if (err) return err; /* 将设备节点的次设备号右移5位作为索引值到input_table中去对应项, * 一个handler代表32(1<<5)个设备节点, 即一个handler最多可以处理32个设备节点. * 因为在input_table中的取值是以次设备号右移5位为索引的, 即第5位相同的次设备号对应的是同一个索引. */ handler = input_table[iminor(inode) >> 5]; if (handler) new_fops = fops_get(handler->fops); mutex_unlock(&input_mutex); /* 在input_handler中找到对应的handler后,就会检验该handler否存在, * 判断new_fops->open函数是否定义, 如未定义则表示设备不存在. * 在存在的情况下, 从handler->fops中获得新的文件操作指针file_operation, * 并增加引用. 此后, 对设备的操作都通过新的文件操作指针new_fops来完成. */ if (!new_fops || !new_fops->open) { fops_put(new_fops); err = -ENODEV; goto out; } old_fops = file->f_op; file->f_op = new_fops; /* 使用新的open函数,重新打开设备 */ err = new_fops->open(inode, file); if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } fops_put(old_fops);out: return err;}
1.3、input_register_handler( )
int input_register_handler(struct input_handler *handler){ struct input_dev *dev; int retval; retval = mutex_lock_interruptible(&input_mutex); if (retval) return retval; INIT_LIST_HEAD(&handler->h_list); if (handler->fops != NULL) { if (input_table[handler->minor >> 5]) { retval = -EBUSY; goto out; } input_table[handler->minor >> 5] = handler; /* 将handler赋给input_table数组(右移5位作为索引) */ } list_add_tail(&handler->node, &input_handler_list); list_for_each_entry(dev, &input_dev_list, node) input_attach_handler(dev, handler); input_wakeup_procfs_readers(); out: mutex_unlock(&input_mutex); return retval;}
二、evdev输入事件:
kernel/drivers/input/evdev.c
2.1、evdev_init( )初始化函数
/* evdev_ids中没有定义id->flags, 也没有配置属性值, * 表明所有input_dev发出的事件均可以由evdev_handler来处理. * 并且此处匹配成功后回调用handler->connect()即evdev_connect()函数. */static const struct input_device_id evdev_ids[] = { { .driver_info = 1 }, /* Matches all devices */ { }, /* Terminating zero entry */};static struct input_handler evdev_handler = { .event = evdev_event, .connect = evdev_connect, .disconnect = evdev_disconnect, .fops = &evdev_fops, .minor = EVDEV_MINOR_BASE, /* evdev_handler的设备文件索引范围为(13, 64)~(13, 64+32) */ .name = "evdev", .id_table = evdev_ids, /* 此处只定义了id_table */};static int __init evdev_init(void){ return input_register_handler(&evdev_handler); /* handler注册 */}/* 在input_attach_handler( )的input_match_device( )函数中 * input_dev与handler匹配的关键在于, handler中的blacklist和id_table. * */
2.2、evdev_connect( )
/* * evdev_connect()函数用于连接input_dev和input_handler,这样事件的流通链才算建立。 * 流通链建立后,事件才知道被谁处理,或者处理后将向谁返回结果。 */static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id){ struct evdev *evdev; int minor; int error; for (minor = 0; minor < EVDEV_MINORS; minor++) if (!evdev_table[minor]) /* 找到evdev_table为空的那一项 */ break; if (minor == EVDEV_MINORS) { pr_err("no more free evdev devices\n"); return -ENFILE; } evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); if (!evdev) return -ENOMEM; /* 对分配的evdev结构进行初始化,包括链表、互斥锁和等待队列 */ INIT_LIST_HEAD(&evdev->client_list); spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); /* 对evdev设备进行命名,在/dev/input目录下显示 */ dev_set_name(&evdev->dev, "event%d", minor); evdev->exist = true; evdev->minor = minor; evdev->handle.dev = input_get_device(dev); evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; 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结构体 */ error = input_register_handle(&evdev->handle); if (error) goto err_free_evdev; /* 注册成功,则调用evdev_install_chrdev将evdev_table的minor项指向evdev */ error = evdev_install_chrdev(evdev); if (error) goto err_unregister_handle; /* 将evdev->device注册到sysfs文件系统中 */ error = device_add(&evdev->dev); if (error) goto err_cleanup_evdev; return 0; err_cleanup_evdev: evdev_cleanup(evdev); err_unregister_handle: input_unregister_handle(&evdev->handle); err_free_evdev: put_device(&evdev->dev); return error;}
2.3、evdev_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, .llseek = no_llseek,};
2.3.1、evdev_open( )
static int evdev_open(struct inode *inode, struct file *file){ struct evdev *evdev; struct evdev_client *client; int i = iminor(inode) - EVDEV_MINOR_BASE; /* 得到在evdev_table[]中序列号 */ unsigned int bufsize; int error; if (i >= EVDEV_MINORS) return -ENODEV; error = mutex_lock_interruptible(&evdev_table_mutex); if (error) return error; evdev = evdev_table[i]; if (evdev) /* 调用get_device()增加引用计数 */ get_device(&evdev->dev); mutex_unlock(&evdev_table_mutex); if (!evdev) return -ENODEV; bufsize = evdev_compute_buffer_size(evdev->handle.dev); client = kzalloc(sizeof(struct evdev_client) + bufsize * sizeof(struct input_event), GFP_KERNEL); if (!client) { error = -ENOMEM; goto err_put_evdev; } client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); snprintf(client->name, sizeof(client->name), "%s-%d", dev_name(&evdev->dev), task_tgid_vnr(current)); client->evdev = evdev; evdev_attach_client(evdev, client);/* 将client挂到evdev->client_list上 */ error = evdev_open_device(evdev); if (error) goto err_free_client; file->private_data = client; nonseekable_open(inode, file); return 0; err_free_client: evdev_detach_client(evdev, client); kfree(client); err_put_evdev: put_device(&evdev->dev); return error;}
2.3.2、evdev_open_device( )
/* 打开相应的输入设备,使设备准备好接收或者发送数据。 * 线获取互斥锁,然后检查设备是否存在,并判断设备是否已经被打开。 */static int evdev_open_device(struct evdev *evdev){ int retval; retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; if (!evdev->exist) retval = -ENODEV; else if (!evdev->open++) { /* 第一次打开evdev */ retval = input_open_device(&evdev->handle); if (retval) evdev->open--; } mutex_unlock(&evdev->mutex); return retval;}
2.3.3、input_open_device( )
/* 递增handler的打开计数, 如果是第一次打开, 则调用input_dev的open()函数 */int input_open_device(struct input_handle *handle){ struct input_dev *dev = handle->dev; int retval; retval = mutex_lock_interruptible(&dev->mutex); if (retval) return retval; if (dev->going_away) { retval = -ENODEV; goto out; } handle->open++; if (!dev->users++ && dev->open) retval = dev->open(dev); if (retval) { dev->users--; if (!--handle->open) { /* * Make sure we are not delivering any more events * through this handle */ synchronize_rcu(); } } out: mutex_unlock(&dev->mutex); return retval;}
0 0
- 输入子系统二
- 输入子系统(二)
- Linux输入子系统分析二
- LINUX设备驱动之输入子系统(二)
- LINUX设备驱动之输入子系统(二)
- LINUX设备驱动之输入子系统(二)
- [input] Linux 输入子系统(二)
- Linux输入子系统分析(二)
- Linux输入子系统分析(二)
- 输入子系统
- 输入子系统
- 输入子系统
- 输入子系统
- 输入子系统
- 输入子系统
- 输入子系统
- 输入子系统
- 输入子系统
- leetcode Insert Interval
- bzoj 1096: [ZJOI2007]仓库建设
- Java基础之翻转单链表
- shell学习 - awk入门
- Categories Add Methods to Existing Classes
- 输入子系统(二)
- c# UserControl 如何在父窗口中显示Scroll
- 牛顿迭代法快速寻找平方根
- python编码详解
- AES之ECB/CBC/CFB/OFB
- python 模块导入问题
- Android 身份证正则表达式
- 希尔排序的C++实现
- JavaFx 简易弹出提示框