字符设备驱动内部实现原理解析以及分步注册流程和代码示例

news2024/11/14 15:27:05

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

原理:用户层调用 open() 函数打开设备文件,用ls-i查看inode号并找到与之对应的struct inode 结构体。在struct inode 结构体中,可以找到与文件关联的 struct cdev 设备驱动结构体。设备驱动结构体中包含了文件操作方法结构体的指针。根据文件打开的模式,比如读取模式、写入模式等,内核会回调操作方法结构体中相应的函数,例如 open() 函数。在设备驱动的 open() 函数中,可以进行对硬件设备寄存器的操作,以及初始化设备所需的其他操作。

open函数回调到驱动中open操作方法的路线:

open()->sys_open()->struct inode结构体->struct cdev结构体->struct file_operations结构体->mycdev_open

2、分步注册流程

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

struct cdev cdev;//直接分配一个变量空间
struct cdev *cdev=cdev_alloc();
struct cdev *cdev_alloc(void);//手动申请字符设备驱动对象空间
返回值:成功返回申请空间首地址,失败返回NULL

(2)字符设备驱动对象的初始化

 1、void cdev_init(struct cdev *cdev, const struct file_operations *fops);
    功能:实现字符设备驱动对象的部分初始化
    参数:
        cdev:字符设备驱动对象指针
        fops:操作方法结构体指针
    返回值:无
 2、 申请设备号
    int register_chrdev_region(dev_t from, unsigned count, const char *name)
      功能:   静态指定设备号
      参数:
          from:要申请的设备号
          count:要申请的设备资源的数量
          name:驱动名字
       返回值:成功返回0,失败返回 错误码
     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,失败返回错误码

(4)字符设备注销流程

void cdev_del(struct cdev *);
功能:字符设备驱动对象的注销
参数:字符设备驱动对象指针
返回值:无
//释放申请的设备号
void unregister_chrdev_region(dev_t from, unsigned count)
功能:释放申请的设备号
参数:
    from:要释放的设备号
    count:设备的数量
返回值:无
    
void kfree(void *p)//释放对象空间
参数:
    p:对象空间首地址

3、代码示例

#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"led.h"
struct cdev *cdev;
unsigned int major=500;
unsigned int 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 fops={

    .open=mycdev_open,
   .unlocked_ioctl=mycdev_ioctl,
    .release=mycdev_close,
};

static int __init mycdev_init(void)
{
    int ret,i;
    //1.分配对象空间
    cdev=cdev_alloc();
    if(cdev==NULL)
    {
        printk("分配字符设备驱动对象失败\n");
        ret=-EFAULT;
        goto OUT1;
    }
    printk("分配对象空间成功\n");
    //2.初始化对象
    cdev_init(cdev,&fops);
    //3.申请设备号
    if(major>0)//静态指定设备号
    {
        ret= register_chrdev_region(MKDEV(major,minor),3,"myled");
        if(ret)
        {
            printk("静态指定设备号失败\n");
            goto OUT2;
        }
    }
    else if(major==0)//动态申请设备号
    {
        ret=alloc_chrdev_region(&devno,minor,3,"myled");
        if(ret)
        {
            printk("动态申请设备号失败\n");
            goto OUT2;
        }
        //获取主设备号和次设备号
        major=MAJOR(devno);
        minor=MINOR(devno);
    }
    printk("申请设备号成功\n");
    //4.注册字符设备驱动对象
    ret=cdev_add(cdev,MKDEV(major,minor),3);
    if(ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto OUT3;
    }
    printk("注册字符设备驱动对象成功\n");
    //向上提交目录
    cls=class_create(THIS_MODULE,"myled");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret=-PTR_ERR(cls);
        goto OUT4;
    }
    printk("向上提交目录成功\n");
    //向上提交设备节点信息
    for(i=0;i<3;i++)
    {
         dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
         if(IS_ERR(dev))
         {
            ret=-PTR_ERR(dev);
            goto OUT5;
         }
    }
    printk("向上提交设备节点成功\n");
    //完成硬件寄存器地址的映射以及初始化
    return 0;
OUT5:
    //释放已经申请的设备节点信息
    for(--i;i>=0;i--)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //释放目录空间
    class_destroy(cls);
OUT4:
    //注销字符设备驱动对象
    cdev_del(cdev);
OUT3:
    //释放设备号
    unregister_chrdev_region(MKDEV(major,minor),3);
OUT2:
//释放对象空间
    kfree(cdev);
OUT1:
    return ret;
}
static void __exit mycdev_exit(void)
{
    //销毁设备节点
    int i;
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //释放目录空间
    class_destroy(cls);
    //1.注销字符设备驱动对象
     cdev_del(cdev);
    //2.释放设备号
     unregister_chrdev_region(MKDEV(major,minor),3);
    //3.释放对象空间
     kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

Spring6 数据校验 Validation

1、Spring Validation概述 在开发中&#xff0c;经常遇到参数校验的需求&#xff0c;比如用户注册的时候&#xff0c;要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式&#xff0c;会把校验的代码和真正的业务处理逻辑耦合在一…

FL Studio 21中文永久版网盘下载(含Key.reg注册表补丁)

FL Studio 21全称Fruity Loops Studio&#xff0c;就是大家熟悉的水果编曲软件&#xff0c;一个全能的音乐制作软件&#xff0c;包括编曲、录音、剪辑和混音等诸多功能&#xff0c;让你的电脑编程一个全能的录音室。FL Studio 21版本发布了&#xff0c;为我们带来了多种新功能&…

在Centos Stream 9上Docker的实操教程(八) - Docker可视化管理工具

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Micro麦可乐的博客 &#x1f425;《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程&#xff0c;入门到实战 &#x1f33a;《RabbitMQ》…

构建二叉树的两种情况【根据前序遍历和中序遍历 构造树】【根据后序遍历和中序遍历 构造树】

【根据前序遍历和中序遍历 构造树】【根据后序遍历和中序遍历 构造树】 6. 重建二叉树根据前序遍历和中序遍历 得到树 树的遍历 6. 重建二叉树 原题链接 根据前序遍历和中序遍历 得到树 过程如下&#xff1a; 首先根据前序遍历找到 根节点找到中序遍历中&#xff0c;该根节点…

C# Http 请求接口 Get / Post

目录 一、概述 二、创建 Web API 三、HttpRequestHelper 三、测试 结束 一、概述 get 和 post 请求&#xff0c;最早被用来做浏览器与服务器之间交互HTML和表单的通讯协议&#xff0c;后来又被广泛的扩充到接口格式的定义上&#xff0c;到目前为止&#xff0c;get / pos…

计算机网络综合实训——网络程序设计

计算机网络综合实训 网络程序设计 作者姓名 学号 所在院系 计算机与信息工程学院 学科专业名称 计算机科学与技术 导师及职称 柯宗武 教授 提交时间 2023/05/28 仿qq聊天的设计与实现 &#xff08;指导教师&#xff0c;柯宗武 教授&#xff09; &#xff08;湖北师范大学计…

【特征检测器】检测器

检测器 1. Shi-Tomasi 检测器1.1 算法特点&#xff1a;1.2算法步骤1.3 8-邻域非最大抑制算法 1. Shi-Tomasi 检测器 1.1 算法特点&#xff1a; Shi-Tomasi 检测器使用了 Harris 算法的改良版&#xff0c;在处理图像边缘时具有更好的性能表现&#xff0c;能够检测出更多的稳定…

【kali学习笔记】信息收集之搜索引擎的使用技巧

一、Google 搜索引擎的使用技巧 1、Google 常用语法说明 site 指定域名 inurl URL 中存在的关键字页面 intext 网页内容里面的关键字 Filetype 指定文件类型 intitle 网页标题中的关键字 link 返回你所有的指定域名链接 info 查找指定站点信息 cache 搜索 Google 里的内容缓存…

【账号篇】华硕电脑-华硕账号注销教程

【账号篇】华硕电脑-华硕账号注销教程 手机号和邮箱号注册的华硕账户无法合并&#xff0c;无法互相关联&#xff0c;需要数据同步的可以选择先注销删除其中一个账号再关联—【蘇小沐】 文章目录 【账号篇】华硕电脑-华硕账号注销教程1.实验环境 &#xff08;一&#xff09;华硕…

(二叉树) 116. 填充每个节点的下一个右侧节点指针 ——【Leetcode每日一题】

❓ 116. 填充每个节点的下一个右侧节点指针 难度&#xff1a;中等 给定一个 完美二叉树 &#xff0c;其所有叶子节点都在同一层&#xff0c;每个父节点都有两个子节点。二叉树定义如下&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; }填充它的每个 …

MySQL 高级语句二

目录 表连接查询内连接 inner join左连接 left join右连接 right join 表的自我连接 &#xff08;算排名&#xff09;view 的视图的运用union 联级union&#xff08;合并后去重&#xff09;union all &#xff08;合并后不去重&#xff09; 多种方式求表与表的交集值取两个SQL语…

基于spss的多元统计分析 之 实例1(挤压塑料胶卷的最优工艺研究)(6/8)

挤压塑料胶卷的最优工艺研究 摘要 多元方差分析是同时分析多个响应变量和一个共同预测变量集之间关系的检验。与方差分析一样&#xff0c;多元方差分析需要连续响应变量和类别预测变量。与运行多个方差分析&#xff08;一次一个响应变量&#xff09;相比&#xff0c;多元方差分…

综合专题学期实训IV综合报告

综合专题学期实训IV综合报告 题目 基于Java的聊天系统设计与实现 所在院系 计算机与信息工程学院 学科专业名称 计算机科学与技术 导师及职称 夏端峰&#xff08;副高&#xff09;、黄烜&#xff08;讲师&#xff09; 撰写时间 2023年6月16日 目 录 1 概述 1 2 相关技术 1 2.…

2-2 A pretrained model that fakes it until it makes it

1.The GAN game Let’s suppose, for a moment, that we’re career criminals who want to move into selling forgeries of “lost” paintings by famous artists. We’re criminals, not painters, so as we paint our fake Rembrandts and Picassos, it quickly becomes a…

【系统开发】尚硅谷 - 谷粒商城项目笔记(九):Sentinel高并发方法论

文章目录 Sentinel高并发方法论Sentinel是什么&#xff1f;基本概念及作用整合SpringBoot引入Sentinel依赖下载Sentinel控制台cmd启动Sentinel配置Sentinel控制台地址信息在控制台设置流控规则规则持久化流量监控自定义流控返回数据适配Feign&#xff0c;并加上熔断保护方法自定…

CorelDRAW2023最新工作室Win版矢量图形编辑与排版工具软件

CorelDRAW简称CDR,是一款专业的平面设计软件,专注于矢量图形编辑与排版。ps和cdr是常用的两款平面设计软件&#xff0c;一直以来深受广大设计师的喜爱&#xff0c;但仍然有很多小伙伴不知道它们之间的区别。那初学者先学ps还是cdr&#xff0c;初学者cdr哪个版本好&#xff1f;我…

【openGauss高级数据管理】--略有小成

【openGauss高级数据管理】--略有小成 &#x1f53b; 一、openGauss高级数据管理&#x1f530; 1.1 约束⛳ 1.1.1 NOT NULL约束⛳ 1.1.2 UNIQUE约束⛳ 1.1.3 PRIMARY KEY⛳ 1.1.4 FOREIGN KEY⛳ 1.1.5 CHECK约束 &#x1f530; 1.2 JOIN⛳ 2.3.1 CROSS JOIN---交叉连接⛳ 1.2.1…

基于spss的多元统计分析 之 实例2(挤压塑料胶卷的最优工艺研究)(7/8)

主成分分析 摘要 主成分分析是利用降维的思想&#xff0c;把多指标转化为少数几个综合指标的多元统计分析方法。 对同一个个体进行多项观察时&#xff0c;必定涉及多个随机变量&#xff0c;它们都是相关的&#xff0c;一时难以综合。这时就需要进行主成分分析来概括诸多信息…

7.延时消息与原理探究

highlight: arduino-light 4.3 延时消息 延迟消息对应的Topic是SCHEDULETOPICXXXX,注意就是SCHEDULETOPICXXXX,XXXX不是某某某的意思。 SCHEDULETOPICXXXX的队列名称是从2开始到17&#xff0c;对应的delayLevel为3到18&#xff0c;3对应10s&#xff0c;18对应2h&#xff0c;在类…

因为计算机中丢失mfc140.dll无法启动修复步骤分享

计算机报错提示mfc140.dll无法启动是怎么回事&#xff1f;mfc140.dll是什么文件&#xff0c;为什么会影响到软件程序的运行?相信你也有不少困惑&#xff0c;遇到这个情况不用慌&#xff0c;小编下面就分享关于mfc140.dll丢失的详细修复步骤以及mfc140.dll是什么。 mfc140.dll是…