我对linux理解之input 二
我们看下input从打开,到读写的过程:
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
static int __init input_init(void)
{
......
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);//所有input共同的一个操作,所有对主设备号为INPUT_MAJOR设备操作,都将转换为这个fops
......
}
所有对主设备号为INPUT_MAJOR设备操作,都将转换为input_fops,比如对/dev/input/event*的操作。那假如用户空间程序打开一个input节点,那么将会调用input_open_file:
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;
lock_kernel();
/* No load-on-demand here? */
handler = input_table[iminor(inode) >> 5];
if (!handler || !(new_fops = fops_get(handler->fops))) {
err = -ENODEV;
goto out;
}
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
if (!new_fops->open) {
fops_put(new_fops);
err = -ENODEV;
goto out;
}
old_fops = file->f_op;//此时的file的ops是该函数所属的ops,即input_fops
file->f_op = new_fops;//偷梁换柱!把file的ops换成了handler的ops,那后面对file的读写等操作就都变成了handler的操作
err = new_fops->open(inode, file);//handler的open
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);//如果发生错误,不能忘了换回来,否则就永远打不开了
}
fops_put(old_fops);
out:
unlock_kernel();
return err;
}
这里有个地方设计的很绝妙,它竟然来了一招偷梁换柱,把file的ops给换掉了,换成handler的ops了,这就意味着后面的file操作直接对应到handler的ops。为什么这么设计呢?
可能是为了架构之间的清晰,互不影响吧。你想假如把evdev的操作直接放到input_ops里面,那像joydev、mousedev怎么办呢?所以索性就分开。那下面我们就看下handler的ops:
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
我们看到handler的ops对应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
};
那对应的open就是evdev_open:
static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) -