输入子系统
Posted -glb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了输入子系统相关的知识,希望对你有一定的参考价值。
输入子系统框架:
drivers/input/input.c
input_init > err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
static const struct file_operations input_fops =
.owner = THIS_MODULE,
.open = input_open_file,
.llseek = noop_llseek,
;
问:怎样读按键呢?
input_open_file
handler = input_table[iminor(inode) >> 5];
new_fops = fops_get(handler->fops);
file->f_op = new_fops; err = new_fops->open(inode, file)
app: read > .......>file->f_op->read
input_table[]数组由谁构造?
input_table数组是在input_register_handler函数中被构造的。那么input_register_handler函数又是被谁调用的?
搜索一下,发现是由evdev.c,keyboard.c, mousedev.c等这几个文件调用,它们通过调用input_register_handler函数向上注册handler。
注册input_handler
input_register_handler
input_table[handler->minor >> 5] = handler;
list_add_tail(&handler->node, &input_handler_list); //放入链表
list_for_each_entry(dev, &input_dev_list, node)//对于每一个input_dev,调用input_attach_handler
input_attach_handler(dev, handler);//根据input_handler中的id_table,判断能否支持这个设备。
注册输入设备:
input_register_device
//放入链表
list_add_tail(&dev->node, &input_dev_list);
//对于每一个handler,都调用input_attach_handler函数。
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);//根据input_handler的id_table判断能够支持这个input_dev
从上面可以看出,不管是先注册input_dev还是input_handler,都调用input_attach_handler进行两两匹配。
1 static const struct file_operations input_fops =
2 .owner = THIS_MODULE,
3 .open = input_open_file, //在该结构体中,只有一个input_open_file这个函数,这个函数只是起一个中转作用,在里面肯定还做了其他事情。
4 .llseek = noop_llseek,
5 ;
6
7 static int __init input_init(void)
8
9 int err;
10
11 err = class_register(&input_class);
12 if (err)
13 pr_err("unable to register input_dev class\n");
14 return err;
15
16
17 err = input_proc_init();
18 if (err)
19 goto fail1;
20
21 err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
22 if (err)
23 pr_err("unable to register char major %d", INPUT_MAJOR);
24 goto fail2;
25
26
27 return 0;
1 static int input_open_file(struct inode *inode, struct file *file)
2
3 struct input_handler *handler;
4 const struct file_operations *old_fops, *new_fops = NULL;
5 int err;
6
7 err = mutex_lock_interruptible(&input_mutex);
8 if (err)
9 return err;
10
11 /* No load-on-demand here? */
/*次设备号右移5位,即相当于除以32,以这个数为下标,从input_table数组中取出一项,赋给handler.*/
12 handler = input_table[iminor(inode) >> 5];
13 if (handler)/*handler中有一个file_operation结构体,把handler中的file_operation结构体取出来赋给new_fops.*/
14 new_fops = fops_get(handler->fops);
15
16 mutex_unlock(&input_mutex);
17
18 /*
19 * That‘s _really_ odd. Usually NULL ->open means "nothing special",
20 * not "no device". Oh, well...
21 */
22 if (!new_fops || !new_fops->open)
23 fops_put(new_fops);
24 err = -ENODEV;
25 goto out;
26
27
28 old_fops = file->f_op;
29 file->f_op = new_fops; /*打开的这个文件的f_op= 新的fops*/
30
31 err = new_fops->open(inode, file);/*调用新的fops中的open函数,以后如果读的话,就是用到了handler里面的新的fops*/
32 if (err)
33 fops_put(file->f_op);
34 file->f_op = fops_get(old_fops);
35
36 fops_put(old_fops);
37 out:
38 return err;
1 struct input_handler
2
3 void *private;
4
5 void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
6 bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
7 bool (*match)(struct input_handler *handler, struct input_dev *dev);
8 int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
9 void (*disconnect)(struct input_handle *handle);
10 void (*start)(struct input_handle *handle);
11
12 const struct file_operations *fops;
13 int minor;
14 const char *name;
15
16 const struct input_device_id *id_table;
17
18 struct list_head h_list;
19 struct list_head node;
20 ;
input_table[]数组是在input_register_handler这个函数中构造的。
1 int input_register_handler(struct input_handler *handler)
2
3 struct input_dev *dev;
4 int retval;
5
6 retval = mutex_lock_interruptible(&input_mutex);
7 if (retval)
8 return retval;
9
10 INIT_LIST_HEAD(&handler->h_list);
11
12 if (handler->fops != NULL)
13 if (input_table[handler->minor >> 5])
14 retval = -EBUSY;
15 goto out;
16
17 input_table[handler->minor >> 5] = handler;
18
19
20 list_add_tail(&handler->node, &input_handler_list);
21
22 list_for_each_entry(dev, &input_dev_list, node)
23 input_attach_handler(dev, handler);
24
25 input_wakeup_procfs_readers();
26
27 out:
28 mutex_unlock(&input_mutex);
29 return retval;
input_register_handler这个函数又是被谁调用的呢?选取evdev.c进行分析。
1 static struct input_handler evdev_handler =
2 .event = evdev_event,
3 .connect = evdev_connect,
4 .disconnect = evdev_disconnect,
5 .fops = &evdev_fops, /*这个fops以前是由我们自己构造,现在内核已经帮我们做好了。*/
6 .minor = EVDEV_MINOR_BASE,
7 .name = "evdev",
8 .id_table = evdev_ids,//表示该handler能够支持哪些输入设备。如果能够支持的话,就调用connect函数。
9 ;
10
11 static int __init evdev_init(void)
12
/*input_register_handler会将evdev_handler向上注册,通过上面的分析可知,就是把这个evdev_handler放入Input_table数组
中,以次设备号右移5位为下标。这样的话,在input_open_file中获得的handler就是evdev_handler这个结构体,new_fops就是evdev_handler
结构体中的fops
*/ 13 return input_register_handler(&evdev_handler); 14
以上是关于输入子系统的主要内容,如果未能解决你的问题,请参考以下文章