当前位置: 首页 > news >正文

Linux系统调用怎么和内核或底层驱动交互的

学习Linux系统下驱动程序开发已有大半年时间,心中一直有个疑惑:那就是诸如open、write、read等系统调用是怎么和
内核或底层驱动建立起联系的呢?今天将自己的一些粗略的理解总结如下。  
   
       学过Linux系统下驱动程序开发的都知道,大部分的基础性的驱动操作都包括3个重要的内核数据结构,称为file_operations,
file,和inode。我们需要对这些结构有个基本了解才能够做大量感兴趣的事情。

1、struct file_operations是一个把字符设备驱动的操作和设备号联系在一起的纽带,是一系列指针的集合,每个被打开的文件
都对应于一系列的操作,这就是file_operations,用来执行一系列的系统调用。

2、struct file代表一个打开的文件,在执行file_operation中的open操作时被创建,这里需要注意的是与用户空间inode指针的区
别,一个在内核,而file指针在用户空间,由c库来定义。
      3、struct inode被内核用来代表一个文件,注意和struct file的区别,struct inode一个是代表文件,struct file一个是代表打开的文件
            struct inode 包括很重要的两个成员:
            dev_t       i_rdev     设备文件的设备号
            struct cdev *i_cdev 代表字符设备的数据结构,struct inode结构是用来在内核内部表示文件的。同一个文件可以被打开好多
次,所
以可以对应很多struct file,但是只对应一个struct inode.

  

       应用层调用open函数,首先会发出open系统调用,然后进入 内核,调用sys_open函数,打开文件系统中的/dev/fs文件,这个文件要么
你是用mknod建立的,要么就直接在内核中用devfs方式来建立的,无论你用哪种方式建立,最终都会读取其文件属性,如果发现其是设备
文件,就会调用LINUX内核中的设备管理部分,根据其属性的主设备号(在建立设备节点时已经把主设备号写入文件属性当中,如果你仔细
看过mknod的用法就明白了),查找内核中相关联的file_operations,最终找到你的test_open函数。
       所以说 "在LINUX中设备即是文件 ",设备驱动首先会走文件系统这一条路(比如最先的 "/dev/fs "),然后根据设备文件的属性最终找
到相关联的file_operations,从而调用你的设备驱动例程.假如发现这个文件不是设备文件而只是磁盘文件,就继续走文件系统,高速缓冲
与磁盘调度这一条路了。

 
        sys_open(内核函数)就直接到VFS层了,open过程中会得到设备文件的inode(通过传进来的文件名参数),(参考我的博文里
关于inode介绍),其file_operations结构体会赋给file结构体(含此成员fops)中相应成员,且当open方法不为空调用之。不过特殊文件
的inode里的file_operations都是一样的,比如字符设备文件inode之file_operations只定义了一个open方法,open方法根据inode中的设备
号在已注册的字符设备驱动中查找cdev,这个cdev里的fops才是驱动提供的。它会赋给file结构体中相应成员(file_operations结构体)
(覆盖了之前的一次赋值),其open方法不为空则调用之。

现在我们就演示一下用户使用write函数将数据写到设备里面这个过程到底是怎么实现的: 
    1,insmod驱动程序。驱动程序申请设备名和主设备号,这些可以在/proc/devieces中获得。 
    2,从/proc/devices中获得主设备号,并使用mknod命令建立设备节点文件。这是通过主设备号将设备节点文件和设备驱动程序联系在
一起。设备节点文件中的file属性中指明了驱动程序中fops方法实现的函数指针。 
    3,用户程序使用open打开设备节点文件,这时操作系统内核知道该驱动程序工作了,就调用fops方法中的open函数进行相应的工作。
open方法一般返回的是文件标示符,实际上并不是直接对它进行操作的,而是由操作系统的系统调用在背后工作。 
    4,当用户使用write函数操作设备文件时,操作系统调用sys_write函数,该函数首先通过文件标示符得到设备节点文件对应的inode指针
和flip指针。inode指针中有设备号信息,能够告诉操作系统应该使用哪一个设备驱动程序,flip指针中有fops信息,可以告诉操作系统相应
的fops方法函数在那里可以找到。 
    5,然后这时sys_write才会调用驱动程序中的write方法来对设备进行写的操作。 

    其中1-3都是在用户空间进行的,4-5是在核心空间进行的。用户的write函数和操作系统的write函数通过系统调用sys_write联系在了一起。 
    注意:

          总的来说:设备文件通过设备号绑定了设备驱动,fops绑定了应用层的write和驱动层的write。当应用层写一个设备文件的时候,系统
找到对应的设备驱动,再通过fops找到对应的驱动write函数。

    int open(const char *pathname, int flags, mode_t mode);  --系统调用
                                ||
                                \/
    long sys_open(const char __user *filename, int flags, int mode)  -- fs/open.c
    /*对应内核中的open接口函数*/
                                ||
                                \/
    long do_sys_open(int dfd, const char __user *filename, int flags, int mode) --fs/open.c
    /*用户空间的filename被拷贝到内核空间,获取当前可用的文件描述符*/
                                ||
                                \/
    static struct file *do_filp_open(int dfd, const char *filename, int flags, int mode) --fs/open.c 
                                ||
                                \/
    int open_namei(int dfd, const char *pathname, int flag,
                                                                                    int mode, struct nameidata *nd)
    /*获取该文件对应的nameidata结构.该函数执行完毕,接着调用下面函数。这两个函数是顺序被do_filp_open调用*/
                                ||
                                \/
    struct file *nameidata_to_filp(struct nameidata *nd, int flags) --fs/open.c
        /*将nameidata 结构转换为打开的struct file结构*/
                                ||
                                \/
    static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
                                 int flags, struct file *f,
                                                                     int (*open)(struct inode *, struct file *)) --fs/open.c
                                ||
                                \/
                f->f_op = fops_get(inode->i_fop);  --fs/open.c
    /*这里将系统调用中需要对应打开文件对应到内核中的file_operations结构体获取到,然后根据其函数指针就可以找到该结构体中对
该种文件操作的所有方法。scull对应的结构体是在scull_init的时候向内核注册的。
                                ||
                                \/
    open = f->f_op->open; 
    open(inode, f);    --fs/open.c
    /*以上两行代码分别完成了open系统调用时执行实际文件对应内核的open方法,即scull_open。

 

转载于:https://www.cnblogs.com/Ph-one/p/8482919.html

相关文章:

  • linux系统调用是通过软中断实现的吗
  • linux块设备读写流程
  • linux 块设备-整理(一)
  • 22.Linux-块设备驱动之框架详细分析(详解)
  • linux input输入子系统分析《四》:input子系统整体流程全面分析
  • 形参传递关键点
  • Calling Convention的总结
  • unsigned short A = 10; printf(~A = %u\n, ~A); char c=128; printf(c=%d\n,c); 输出多少?
  • linux中断的下半部机制
  • linux下.so、.ko、.a的区别
  • platform_device和platform_driver的注册过程,及probe函数何时调用的分析 ⭐⭐⭐
  • Linux文件系统学习(一)之相关概念⭐⭐⭐
  • 系统调用彻底理解
  • Linux内存管理的基本框架⭐⭐
  • c语言数据类型字节长度
  • 【译】JS基础算法脚本:字符串结尾
  • 时间复杂度分析经典问题——最大子序列和
  • 【前端学习】-粗谈选择器
  • 30秒的PHP代码片段(1)数组 - Array
  • Android交互
  • go语言学习初探(一)
  • Javascript Math对象和Date对象常用方法详解
  • js对象的深浅拷贝
  • js正则,这点儿就够用了
  • Mybatis初体验
  • opencv python Meanshift 和 Camshift
  • PHP面试之三:MySQL数据库
  • React组件设计模式(一)
  • SQLServer之创建数据库快照
  • Vue全家桶实现一个Web App
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 从零开始在ubuntu上搭建node开发环境
  • 免费小说阅读小程序
  • 前端路由实现-history
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ​520就是要宠粉,你的心头书我买单
  • # Maven错误Error executing Maven
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • $ git push -u origin master 推送到远程库出错
  • (02)Hive SQL编译成MapReduce任务的过程
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (算法)Game
  • (算法)前K大的和
  • (转)linux 命令大全
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]