在drivers/input/input.c中:
进入模块入口函数input_init :
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
而input_fops只有open和llseek函数:
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
.llseek = noop_llseek,
};
那么没有read函数的话该怎么读数据呢?
进入 input_open_file函数:
struct input_handler *handler;//定义一个input_handler指针
handler = input_table[iminor(inode) >> 5];//根据传入文件的次设备号从
//input_table中提取出一个input_handler
if (handler)
new_fops = fops_get(handler->fops);//从input_handler中提取出new_fops
file->f_op = new_fops;//将new_fops赋值给当前文件的file_operations
err = new_fops->open(inode, file);
经过这些操作后,当app再来调用read,write,open等函数时,最终都会调用到file->f_op 中的read,write,open等函数。
那么input_open_file函数中的input_table 又是从何而来的呢?
搜索代码可知,
在input.c的input_register_handler函数中构造了input_table:
if (handler->fops != NULL) {
if (input_table[handler->minor >> 5]) {
retval = -EBUSY;
goto out;
}
//给input_table中的 第handler->minor >> 5项赋值
input_table[handler->minor >> 5] = handler;
}
又是谁在调用input_register_handler呢?
搜索内核可知:
evdev.c,tsdev.c,joydev.c,keyboard.c,mousedev.c等文件调用了 input_register_handler,我们以evdev.c为例
在drivers/input/evdev.c中:
进入模块入口函数evdev_init:
return 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,//前面所用到的 new_fops指的就是这里定义的的fops
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
这里需要插入的讲解一下输入子系统的架构!如图:
当通过input_register_device注册一个input_dev设备或者通过 input_register_handler注册一个input_handler时,input_dev与input_handler 会进行匹配,如何匹配?
在input_handler中有一个id_table,里面包含的就是这个input_handler能处 理的input_dev,当input_handler与input_dev匹配成功的话,则会调用 input_handler里 的connect函数。
下面我们来看下input_register_device和input_register_handler分别做了什么:
input_register_device:
//将刚注册的input_dev放入input_dev_list链表
list_add_tail(&dev->node, &input_dev_list);
/*对 input_handler_list中的每一个input_handler都调用
进入模块入口函数input_init :
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
而input_fops只有open和llseek函数:
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
.llseek = noop_llseek,
};
那么没有read函数的话该怎么读数据呢?
进入 input_open_file函数:
struct input_handler *handler;//定义一个input_handler指针
handler = input_table[iminor(inode) >> 5];//根据传入文件的次设备号从
//input_table中提取出一个input_handler
if (handler)
new_fops = fops_get(handler->fops);//从input_handler中提取出new_fops
file->f_op = new_fops;//将new_fops赋值给当前文件的file_operations
err = new_fops->open(inode, file);
经过这些操作后,当app再来调用read,write,open等函数时,最终都会调用到file->f_op 中的read,write,open等函数。
那么input_open_file函数中的input_table 又是从何而来的呢?
搜索代码可知,
在input.c的input_register_handler函数中构造了input_table:
if (handler->fops != NULL) {
if (input_table[handler->minor >> 5]) {
retval = -EBUSY;
goto out;
}
//给input_table中的 第handler->minor >> 5项赋值
input_table[handler->minor >> 5] = handler;
}
又是谁在调用input_register_handler呢?
搜索内核可知:
evdev.c,tsdev.c,joydev.c,keyboard.c,mousedev.c等文件调用了 input_register_handler,我们以evdev.c为例
在drivers/input/evdev.c中:
进入模块入口函数evdev_init:
return 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,//前面所用到的 new_fops指的就是这里定义的的fops
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
这里需要插入的讲解一下输入子系统的架构!如图:
当通过input_register_device注册一个input_dev设备或者通过 input_register_handler注册一个input_handler时,input_dev与input_handler 会进行匹配,如何匹配?
在input_handler中有一个id_table,里面包含的就是这个input_handler能处 理的input_dev,当input_handler与input_dev匹配成功的话,则会调用 input_handler里 的connect函数。
下面我们来看下input_register_device和input_register_handler分别做了什么:
input_register_device:
//将刚注册的input_dev放入input_dev_list链表
list_add_tail(&dev->node, &input_dev_list);
/*对 input_handler_list中的每一个input_handler都调用