open 如何适用于普通文件和设备驱动程序

Posted

技术标签:

【中文标题】open 如何适用于普通文件和设备驱动程序【英文标题】:how does open works for normal file and device drivers 【发布时间】:2013-01-08 05:08:57 【问题描述】:

目前,我正在学习 Linux 设备驱动程序。并且对打开设备文件的工作方式感到困惑?

我到现在为止... 考虑一个打开普通文件的简单代码..

#incldue<stdio.h>
int main() 
   FILE fp;
   char buffer[20];
   fp = fopen(/home/yoggi/foo.txt, "r");
   fread(buffer, 5, 1, fp);

在上面的程序中,c库函数fopen()是系统调用open()的包装函数,实习生调用sys_open()或file_open() VFS 层 功能。由于 linux 支持许多文件系统,虚拟文件​​系统然后将控制权转移到实际文件系统处理程序以打开该文件。

1) How does virtual file system(VFS) get to know on which file system the 
   underline file resides?
2) How does it then calls the file_open or open function of that particular
   filesystem to open file.

如果设备驱动程序发生类似的事情。假设一个简单的设备驱动程序。

#include <linux/module.h>
// othher includes... 
static dev_t first; // Global variable for the first device number 
static struct cdev c_dev; // Global variable for the character device structure
static struct class *cl; // Global variable for the device class
static int my_open(struct inode *i, struct file *f)

   printk(KERN_INFO "Driver: open()\n");
   return 0;
 
static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off)

   printk(KERN_INFO "Driver: read()\n");
   return 0;

struct file_operations pugs_fops =

 .owner = THIS_MODULE,
 .open = my_open,
 .read = my_read,
;

static int __init ofcd_init(void) /* Constructor */

  printk(KERN_INFO "Namaskar: ofcd registered");
  if (alloc_chrdev_region(&first, 0, 1, "Shweta") < 0)
  
    return -1;
  
  if ((cl = class_create(THIS_MODULE, "chardrv")) == NULL)
  
     unregister_chrdev_region(first, 1);
     return -1;
 
 if (device_create(cl, NULL, first, NULL, "mynull") == NULL)
 
    class_destroy(cl);
    unregister_chrdev_region(first, 1);
    return -1;
 
   cdev_init(&c_dev, &pugs_fops);
 if (cdev_add(&c_dev, first, 1) == -1)
 
   device_destroy(cl, first);
   class_destroy(cl);
   unregister_chrdev_region(first, 1);
   return -1;
 
  return 0;


static void __exit ofcd_exit(void) /* Destructor */

 cdev_del(&c_dev);
 device_destroy(cl, first);
 class_destroy(cl);
 unregister_chrdev_region(first, 1);
 printk(KERN_INFO "Alvida: ofcd unregistered");
 
module_init(ofcd_init);
module_exit(ofcd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <email_at_sarika-pugs_dot_com>");
MODULE_DESCRIPTION("Our First Character Driver");

首先我们为设备分配主要次要编号。注册设备文件的范围并将设备文件操作链接到设备驱动程序函数。

我没有得到的一些术语是..

1) What does actually cdev_add() do? in terms of registering a device to the 
   kernel.
2) Registering a device to the kernel means?
3) How does a open(/dev/mynull, O_RONLY); called on a device file actually calls 
   the open function of driver which is mapped while initializing the device 
   by calling routine cdev_init(&c_dev, &pugs_fops); ?

【问题讨论】:

【参考方案1】:

1) 虚拟文件系统(VFS)如何知道在哪个文件系统上 下划线文件在哪里?

您必须通过完整路径名(或当前工作目录)指定要尝试打开的文件。 所以通过向后遍历这个目录路径,第一个匹配(最深的路径)到一个挂载点将提供挂载的文件系统、文件系统的类型和设备。

每个文件系统在挂载时都会提供此信息并保存在挂载表中。 您可以使用mount 命令查看此(当前状态)信息。

2) 然后它如何调用该特定文件的 file_open 或 open 函数 文件系统来打开文件。

一旦知道文件系统,就会检索该 fs 的 ops 结构,并且可以调用 open() 入口点。

1) cdev_add() 实际上是做什么的?在将设备注册到 内核。

驱动程序注册(例如,cdev_init() 用于 char 设备)安装驱动程序的 ops 结构,该结构列出了驱动程序可以执行的功能的入口点。cdev_add() 通知内核驱动程序可以控制特定的该 char 设备类型的实例。该设备实例被分配了一个次要编号,该次编号将/dev 中的设备名称与驱动程序中的状态信息相关联。 请注意,除 char 之外的设备类型(如网络或平台(总线)设备)属于不同的子系统,并使用不同的注册过程。

2) 将设备注册到内核意味着什么?

现在已启用对该设备的访问。

3) 如何打开(/dev/mynull, O_RONLY);在设备文件上调用实际上调用 初始化设备时映射的驱动程序的open函数 通过调用例程 cdev_init(&c_dev, &pugs_fops); ?

驱动程序的init() 例程只应在驱动程序加载时调用一次。该例程应该探测设备所有实例的存在和操作状态。应获取中断线、DMA 通道和 I/O 端口和/或内存空间等资源。驱动程序向内核注册其ops 结构。驱动程序向内核注册设备的每个实例。

用户空间中的open() 调用由C 库处理。 /dev 设备名称被翻译成设备主设备号(它标识哪个设备子系统或类,例如 ttyaudio,必须处理请求)和次设备号编号(标识要使用的设备驱动程序以及访问的设备实例)。处理器切换到超级用户模式,以便可以调用内核驱动程序的open() 例程,该例程从驱动程序的ops 结构中检索。有关ops 结构的更多信息,请参阅此other answer。

【讨论】:

以上是关于open 如何适用于普通文件和设备驱动程序的主要内容,如果未能解决你的问题,请参考以下文章

适用于华为设备的视频的APEZProvider RuntimeException

适用于移动设备和 Web 的安全 API

在设备上运行但适用于模拟器时的 iOS 配置文件问题

SOAP Web 服务不仅适用于 IOS 设备,它还适用于 soap ui 和 Android 设备

设备上的应用程序崩溃,但适用于模拟器 iOS

适用于桌面和移动设备的 jQuery Mobile