Driver 驱动程序中的文件操作

Driver 驱动程序中的文件操作,driver,linux-device-driver,Driver,Linux Device Driver,我试图弄清楚驱动程序中的文件操作是如何工作的。我知道有几个文件操作,但是这些操作的函数是用几个参数调用的,而操作本身是在没有任何参数的情况下定义的 所以如果我有这个- static const struct file_operations proc_myled_operations = { .open = proc_myled_open, .read = seq_read, .write = proc_myled_write, .llseek =

我试图弄清楚驱动程序中的文件操作是如何工作的。我知道有几个文件操作,但是这些操作的函数是用几个参数调用的,而操作本身是在没有任何参数的情况下定义的

所以如果我有这个-

static const struct file_operations proc_myled_operations = { 
     .open = proc_myled_open, 
     .read = seq_read, 
     .write = proc_myled_write, 
     .llseek = seq_lseek, 
     .release = single_release 
 };
现在我知道内核级驱动程序只能作为来自用户应用程序的文件进行访问。这是一个嵌入式系统,所以我有一些LED,我可以通过写入它们的内存映射寄存器来打开

因此,当我打开led时,.write或“proc_myled_write”调用将执行,我可以使用fopen打开此文件,然后使用FPUT写入。但是如果.write被映射为“proc_myled_write”,并且这个函数有如下参数-

static ssize_t proc_myled_write(struct file *file, const char __user * buf, 
size_t count, loff_t * ppos)
这些参数会发生什么情况?上面的函数没有使用这些参数的函数调用。我在几个驱动程序中看到过这一点。我之所以使用这个,是因为它是一个简单的示例。文件操作如何映射到这些函数?例如,用户空间中的“write”如何跟踪驱动程序中的write


谢谢。

我不太清楚您所说的“上面的函数没有带这些参数的函数调用”是什么意思

这些函数的原型在中定义

以下是struct声明的前几行:

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ...
虽然声明中没有命名参数,但您可以清楚地看到
write()
函数声明时有4个参数与您在问题中提到的类型匹配

将函数分配到相应字段(
proc\u myled\u operations.write=proc\u myled\u write
)时,只需传递一个指向在模块中声明和定义的写函数的指针。指向函数本身的指针不需要参数


好的,你们的问题是:“用户空间系统最终如何调用模块中的write函数?”这是个好问题!我建议编辑你们的问题,以便将来的读者更清楚地了解这个问题

好的,让我们看看我是否可以遵循书面记录。我发现给我一个开始位置,以便查找
write()
系统调用的代码。它非常非常旧,但是,嘿,内核中并不是所有东西都会改变!我们从
write()
系统调用声明开始我们的旅程,在:

它使用文件描述符
fd
获取注册角色驱动程序时创建的
struct文件
。然后获取文件中的当前位置并调用

在这个函数中,请参见:

就在那里

为了消除对
文件->f_op
类型的任何疑问,我们查看并查看:

因此,它必须是注册驱动程序时传入的
结构文件\u操作


如果您感到好奇,希望所有这些链接都能告诉您如何跟踪其他系统调用。

我不太清楚您所说的“上面的函数没有带这些参数的函数调用”是什么意思

这些函数的原型在中定义

以下是struct声明的前几行:

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ...
虽然声明中没有命名参数,但您可以清楚地看到
write()
函数声明时有4个参数与您在问题中提到的类型匹配

将函数分配到相应字段(
proc\u myled\u operations.write=proc\u myled\u write
)时,只需传递一个指向在模块中声明和定义的写函数的指针。指向函数本身的指针不需要参数


好的,你们的问题是:“用户空间系统最终如何调用模块中的write函数?”这是个好问题!我建议编辑你们的问题,以便将来的读者更清楚地了解这个问题

好的,让我们看看我是否可以遵循书面记录。我发现给我一个开始位置,以便查找
write()
系统调用的代码。它非常非常旧,但是,嘿,内核中并不是所有东西都会改变!我们从
write()
系统调用声明开始我们的旅程,在:

它使用文件描述符
fd
获取注册角色驱动程序时创建的
struct文件
。然后获取文件中的当前位置并调用

在这个函数中,请参见:

就在那里

为了消除对
文件->f_op
类型的任何疑问,我们查看并查看:

因此,它必须是注册驱动程序时传入的
结构文件\u操作


如果你好奇的话,希望所有这些链接都能告诉你如何跟踪其他系统调用。

@Maverick,在内核中编写原型或签名是ssize\u t(*write)(struct file*,const char\u user*,size\u t,loff\u t*)。在用户空间应用程序中,您将发出打开写入系统调用以打开/关闭LED。在用户空间中写入系统调用签名是int-write(int-fd,const-char*buf,size\u-t-count)。因此,当您从用户空间调用write时,fd(文件描述符)通过访问虚拟文件系统(vfs),维护打开的文件描述符表(OFDT)的链接列表,因此根据fd,OFDT有一个指针filp(文件指针),该指针指向为例如:设备节点/dev/xxx打开的文件“或与此相关的任何其他文件。其余的buf和count是从用户空间传递到内核空间的相同参数。如果要查找文件,最后一个loff\u t*fpos出现在图片中,例如:在打开的文件上使用lseek或fseek
,如果查找,则文件指针(loff\u t fpos)位置
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
ret = file->f_op->write(file, buf, count, pos);
    const struct file_operations    *f_op;