/*
当用户空间调用open()的时候,这个函数最终会被调用。
这个函数主要:
将打开文件的f_op替换成了input_handler中定义的fops
如果以后用户层调用read、write、ioctl....系统调用,
那么input_handler中fops中定义的对应方法会被调用到
vfs_read:
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
....
if (file->f_op->read){
ret = file->f_op->read(file, buf, count, pos);
}
....
}
如: evdev中这些方法会被调用到。
static const struct file_operationsevdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
};
这个函数和v4l2、framebuffer子系统中的open函数有点类似 .
v4l2、framebuffer的一些函数以前博文中有分析过。这里就简单的列举一下。
比如 : v4l2:
当用户层调用open()的时候,v4l2_open()也会被调用
static int v4l2_open(struct inode *inode, struct file *filp)
{
struct video_device *vdev;
...
vdev = video_devdata(filp); 也是从一个数组中取出对应的video_device
if (vdev->fops->open) {
ret = vdev->fops->open(filp); //也是调用具体设备提供的操作方法
}
}
不一样的是,在open函数中没有替换file->f_op,它使用的是另外一种策略
在看fb
fb_open(struct inode *inode, struct file *file)
{
int fbidx = iminor(inode);
struct fb_info *info;
int res = 0;
info = get_fb_info(fbidx); //也是从一个数组中获取对应的fb_info
file->private_data = info;
//也是调用了具体设备提供的操作函数
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
}
}
*/
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;
/**
获取互斥锁----访问临界区----释放互斥锁
*/
//获取互斥锁,可以被信号打断,在等待锁的过程中
//如果有信号的到来,该函数返回-EINTR
err = mutex_lock_interruptible(&input_mutex);
if (err)
{
return err;
}
/**
minor(ionde) :获取次设备号
从input_table[]中获取对应的input_handler
好,看看input_table[]
一指针数组
static struct input_handler *input_table[8];
在什么时候被填充?
在时间处理层 向核心层 注册input_handler的时候
int input_register_handler(struct input_handler *handler)
{
//如果这个被注册的input_handler提供了file_operations
if (handler->fops != NULL) {
if (input_table[handler->minor >> 5])
{
retval = -EBUSY;
goto out;
}
//将这个被注册的input_handler依据次设备号位索引值放入到input_table[]中
//这个minor = input_table[]中空缺项的索引值
input_table[handler->minor >> 5] = handler;
}
}
在void input_unregister_handler(struct input_handler *handler)
{
....
//从input_table[]中删除
if (handler->fops != NULL){
input_table[handler->minor >> 5] = NULL;
}
}
*/
handler = input_table[minor(inode)>>5];
if (handler)
{
/**
将取出来的input_handler的fops赋值给new_fops
例如:evdev
input_handler:
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,
};
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,
};
*/
//比如 现在的new_fops 等价于 evdev_fops
new_fops = fops_get(handler->fops);
}
mutex_unlock(&input_mutex);//释放互斥体
/**
如果取出来的input_handler中没有定义fops
或者定义了fops,但是fops中没有定义open函数,那么会失败返回
*/
if (!new_fops || !new_fops->open)
{
fops_put(new_fops);
err = -ENODEV;
goto out;
}
old_fops = file->f_op;
/**
将取出来的input_handler的fops赋给 打开文件的f_op
如果是evdev :这样,以后使用到文件的f_op就变成了 evdev_fops
*/
file->f_op = new_fops;
/**
调用这个input_handler中定义的fops中的open函数
如果input_handler是evdev的话,evdev_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);
}
input_open_file()浅析
最新推荐文章于 2023-05-10 12:06:53 发布