字符设备驱动内部实现原理解析

news2024/12/22 22:20:51

字符设备驱动内部实现原理解析

  • 一. 字符设备驱动对象内部实现原理解析
  • 二. 字符设备驱动的注册流程
  • 三. 代码示例

一. 字符设备驱动对象内部实现原理解析

img
用户层:

​ 当用户打开(open)一个文件时,会生成一个文件描述符表

内核层:

  1. 内核层的VFS虚拟文件系统层,根据open传递的文件路径找到文件的inode 结构体
    • inode号是存在文件系统的唯一标识,同时也是索引当前文件的inode的索引号
  2. 根据inode结构体找到文件对应的驱动对象指针(struct cdev)
  3. 根据驱动对象指针找到驱动对象的操作方法结构体指针(struct file_operations *ops)
  4. 回调操作方法结构体指针中的open

二. 字符设备驱动的注册流程

  1. 为字符设备驱动对象申请空间

    1. struct cdev cdev;//直接分配一个变量空间

    2. struct cdev *cdev_alloc(void);//手动申请字符设备驱动对象空间
      返回值:成功返回申请空间首地址,失败返回NULL
      
  2. 字符设备驱动对象的初始化

    1. 实现字符设备驱动对象的部分初始化

      void cdev_init(struct cdev *cdev, const struct file_operations *fops);
      功能:实现字符设备驱动对象的部分初始化
      参数:
      cdev:字符设备驱动对象指针
      fops:操作方法结构体指针
      返回值:无

    2. 申请设备号

      1. 静态指定设备号

        int register_chrdev_region(dev_t from, unsigned count, const char *name)
        参数:
        from:要申请的设备号
        count:要申请的设备资源的数量
        name:驱动名字
        返回值:成功返回0,失败返回 错误码

      2. 动态申请一定范围的设备号

        int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
        const char *name)
        参数:
        dev:申请的设备号填充在这个变量中
        baseminor:次设备号的起始值
        count:要申请的设备资源的数量
        name:驱动名字
        返回值:成功返回0,失败返回 错误码

    3. 将字符设备驱动对象注册进内核

    int cdev_add(struct cdev *cdev, dev_t dev, unsigned count);
    参数:
    cdev:字符设备驱动对象指针
    dev:申请的设备号的起始值
    count:设备数量
    返回值:成功返回0,失败返回错误码

    1. 注销流程

      1. 字符设备驱动对象的注销

      void cdev_del(struct cdev *);
      功能:字符设备驱动对象的注销
      参数:字符设备驱动对象指针
      返回值:无

      1. 释放申请的设备号

      unregister_chrdev_region(MKDEV(major,minor),3);

      1. 释放对象空间

        kfree(cdev);

三. 代码示例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>

#include <linux/init.h>
#include <linux/module.h>

struct cdev *cdev;
int major, minor; // 设备号,全局为0
dev_t devno;
struct class *cls;
struct device *dev;

int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
struct file_operations ops = {
    .open = mycdev_open,
    .unlocked_ioctl = mycdev_ioctl,
    .release = mycdev_close,
};
static int __init mycdev_init(void)
{
    int ret;
    // 分配对象空间
    cdev = cdev_alloc();
    if (NULL == cdev)
    {
        printk("字符设备驱动对象分配失败\n");
        ret = -EFAULT;
        goto OUT1;
    }
    printk("字符设备驱动对象分配成功\n");
    // 初始化对象
    cdev_init(cdev, &ops);
    // 申请设备号,采用动态申请的方式
    ret = alloc_chrdev_region(&devno, minor, 1, "mycdev");
    if (ret)
    {
        printk("申请设备号失败\n");
        goto OUT2;
    }
    major = MAJOR(devno);
    minor = MINOR(devno);
    printk("设备号申请成功\n");
    // 注册字符设备驱动对象
    ret = cdev_add(cdev, MKDEV(major, minor), 1);
    if (ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto OUT3;
    }
    printk("注册字符设备驱动对象成功\n");
    // 向上提交目录
    cls = class_create(THIS_MODULE, "mycdev");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret = -PTR_ERR(cls);
        goto OUT4;
    }
    // 向上提交结点信息
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mycdev");
    if (IS_ERR(dev))
    {
        ret = -PTR_ERR(dev);
        goto OUT5;
    }
OUT5:
    // 释放已经申请的设备节点信息

    device_destroy(cls, MKDEV(major, 0));

    // 释放目录空间
    class_destroy(cls);
OUT4:
    // 注销字符设备驱动对象
    cdev_del(cdev);
OUT3:
    // 释放设备号
    unregister_chrdev_region(MKDEV(major, minor), 1);
OUT2:
    kfree(cdev);
OUT1:
    return ret;
}
static void __exit mycdev_exit(void)
{
    // 销毁设备节点
    device_destroy(cls, MKDEV(major, 0));
    // 释放目录空间
    class_destroy(cls);
    // 1.注销字符设备驱动对象
    cdev_del(cdev);
    // 2.释放设备号
    unregister_chrdev_region(MKDEV(major, minor), 0);
    // 3.释放对象空间
    kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/674721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

极致呈现系列之:Echarts散点图的数据魔力

目录 什么是散点图散点图的特点及应用场景散点图的特点散点图的应用场景 Echarts中散点图的常用属性Vue3中创建散点图美化散点图样式 在数据分析和可视化过程中&#xff0c;散点图是一种常见且重要的工具。散点图可以帮助我们直观地观察两个变量之间的关系&#xff0c;并发现其…

MySQL实战解析底层---“order by“是怎么工作的

目录 前言 全字段排序 rowid排序 全字段排序 VS rowid排序 前言 在开发应用的时候&#xff0c;一定会经常碰到需要根据指定的字段排序来显示结果的需求以举例市民表为例&#xff0c;假设你要查询城市是“杭州”的所有人名字&#xff0c;并且按照姓名排序返回前1000个人的姓…

20230622作业:字符设备驱动内部实现原理及流程

1.1字符设备驱动内部实现原理 1>用户打开设备open("~/dev/mycdev",O_RDWR);("路径"&#xff0c;打开方式)2>在内核的虚拟文件系统层会同步执行sys_open函数,实现如下操作3>根据open函数的路径&#xff0c;找到struct inode结构体4>在struct…

深入理解深度学习——GPT(Generative Pre-Trained Transformer):GPT-3与Few-shot Learning

分类目录&#xff1a;《深入理解深度学习》总目录 相关文章&#xff1a; GPT&#xff08;Generative Pre-Trained Transformer&#xff09;&#xff1a;基础知识 GPT&#xff08;Generative Pre-Trained Transformer&#xff09;&#xff1a;在不同任务中使用GPT GPT&#x…

单点登录设计方案介绍及用OAuth完整实现一个单点登录系统

文章目录 一、单点登录系统的意义1.1 提高用户体验1.2 提高安全性1.3 降低开发成本1.4 提高操作效率 二、单点登录的实现方式2.1 基于共享cookie的方式2.2 基于代理服务器的方式2.3 基于SAML协议的方式2.4 基于OAuth协议的方式 三、用OAuth实现单点登录3.1 OAuth 2.0 协议简介3…

【计组】微指令 微操作 微命令 微程序

区分四个概念 &#xff08;1&#xff09;微命令:微命令是构成控制信号序列的最小单位。通常是指那些直接作用于部件或控制门电路的控制命令。 &#xff08;2&#xff09;微操作:由微命令控制实现的最基本的操作称为微操作。 &#xff08;3&#xff09;微指令:以产生一组微命令&…

ubuntu20.4服务器安装mysql社区版并开放3306端口

您可以按照以下步骤在Ubuntu上安装MySQL社区版&#xff1a; 更新软件包列表&#xff1a; sudo apt-get update下载MySQL社区版的APT存储库配置文件&#xff1a; wget https://dev.mysql.com/get/mysql-apt-config_0.8.19-1_all.deb安装APT存储库配置文件&#xff1a; sudo …

Python基础篇(三):基本语句的示例和说明

基本语句的示例和说明 前言1. 赋值语句2. 条件语句3. 循环语句3.1 for循环示例3.2 while循环示例 4. 函数定义语句5. 函数调用语句6. 异常处理语句7. 导入语句 前言 本文是Python中常见基本语句的示例和说明。这些语句是构建Python程序逻辑和控制流的基础&#xff0c;可以根据…

【T+】畅捷通T+直接升级后,原端口无法使用提示端口占用。

【问题描述】 在使用畅捷通T软件过程中&#xff0c;由于软件可以直接升级&#xff0c; 即&#xff1a;原软件是T16.0版本&#xff0c;可以直接运行T18.0的程序进行软件、数据升级。无需将16.0进行卸载&#xff0c;再安装18.0进行数据升级。 但这样直接升级后&#xff0c;原来的…

Shell编程从入门到实践——入门篇

欢迎关注 「Android茶话会」 回 「学习之路」 取Android技术路线经典电子书回 「pdf」 取阿里&字节经典面试题、Android、算法、Java等系列武功秘籍。回 「天涯」 取天涯论坛200精彩博文,包括小说、玄学等 Shell是一种命令行解释器&#xff0c;它是在Unix和Linux操作系统中…

强化历程3-JavaWeb及Spring,SpringMVC,SpringBoot系列(2023.6.22)

文章目录 强化历程3-JavaWeb及SSM,SpringBoot系列(2023.6.22第一次更新)习题汇总1 JSP页面内容组成?2 cookie和session的区别?3 web应用中如何利用session来维持客户端和服务端的关系&#xff1f;4 session销毁的方式?5 请求转发和重定向的区别?6 什么是servelt&#xff1f…

基于Web的数字家庭网站设计与实现【附开题报告和万字文档(Lun文)】

主要功能 前台登录&#xff1a; ①主页&#xff1a;新闻信息展示、最新动态、家庭亲子视频展示、亲友动态展示 ②论坛&#xff1a;发布帖子 ③家庭亲自视频&#xff1a;视频类型分类、亲子视频标题 ④家庭日记&#xff1a;日记类型分类、日记标题 ⑤新闻信息&#xff1a;新闻类…

vue3+vite+js+router+vueX+组件一键导入(源码)

一、前言 一直想自己做一个简单脚手架&#xff0c;方便自己做点简单的demo网上开源也找不到&#xff0c;大多数都是太重了&#xff0c;或者又太轻了今天把这个几个都揉在一起&#xff0c;方便后面做点小玩意 二、项目包 vite-project.zip - 蓝奏云文件大小&#xff1a;8.8 M|ht…

SCTF2023 Barter 复现

题目描述&#xff1a; chal_sage部分&#xff1a; from Crypto.Util.number import * from random import * from secrets import flagdef gen_random(seed, P, Q, r_list, times):s seedfor i in range(times):s int((s * P)[0])r int((s * Q)[0])r_list.append(r)return…

E. Round Dance(dfs分辨特殊联通块)

Problem - 1833E - Codeforces 有 n 个人来到一个节日并决定跳几个“圆舞”。每个圆舞至少有 2 个人&#xff0c;且每个人恰好有两个邻居。如果圆舞中只有 2 个人&#xff0c;则它们在两侧拥有相同的邻居。 你想要确定有多少个“圆舞”可以跳。但是每个参与者只记得一个邻居。…

【自注意力机制必学】BERT类预训练语言模型(含Python实例)

BERT类预训练语言模型 文章目录 BERT类预训练语言模型1. BERT简介1.1 BERT简介及特点1.2 传统方法和预训练方法1.3 BERT的性质 2. BERT结构2.1 输入层以及位置编码2.2 Transformer编码器层2.3 前馈神经网络层2.4 残差连接层2.5 输出层 3. BERT类模型简要笔记4. 代码工程实践 1.…

利用python绘制端午节的各种图案,例如粽子,赛龙舟等,以及一些端午节的感人小故事

这里写目录标题 1、关于端午节的有趣故事2、关于端午节的趣闻3、利用python绘制龙舟3.1. 代码如下3.2 图形展示 4、利用python绘制大公鸡5、利用python来进行端午节的诗词对弈总结 1、关于端午节的有趣故事 端午节是一个历史悠久的中国传统节日&#xff0c;有很多有趣的故事与…

内存不够用,那你的内存去哪了?

一、前言 近几年开发了一些大型的应用程序&#xff0c;在程序性能调优或者解决一些疑难杂症问题的过程中&#xff0c;遇到最多的还是与内存相关的一些问题。例如glibc内存分配器ptmalloc&#xff0c;google的内存分配器tcmalloc都存在“内存泄漏”&#xff0c;即内存不归还操作…

原来Flutter代码是这样运行在原生系统的!快来了解Flutter标准模板,感受原生系统中Flutter的魅力!

通过Android Studio创建的Flutter应用模板&#xff0c;了解Flutter项目结构&#xff0c;分析Flutter工程与原生Android和iOS工程有哪些联系&#xff0c;体验一个有着基本功能的Flutter应用是如何运转的&#xff0c;从而加深你对构建Flutter应用的关键概念和技术的理解。 Dart只…