linux驱动学习加强版-2(文件驱动的书写)

news/2024/4/29 12:38:29/文章来源:https://blog.csdn.net/weixin_51178981/article/details/129563935

文章目录

  • 一、驱动的外设
  • 二、驱动操作文件原理
  • 三、编写一个驱动程序
    • 3.1 编写驱动程序的步骤
    • 3.1.2 确定主设备号以及注册驱动
    • 3.1.3 实现对应的函数
  • 四、一些错误现象

一、驱动的外设

我们的设备硬件都需要驱动才能工作,没有驱动的硬件可以称之为废铁,没有硬件的驱动也是没有实际意义的。
所以两者是要相辅相成的。
因为我们在ubuntu上进行的一些验证,我们可以外接一个SD卡当作硬件,实际上我们也可以放一个文件当作硬件,这样大家就可以不需要其余的东西了。

二、驱动操作文件原理

我们都知道,在Linux系统中,有种说法叫做一切皆文件,那么我们硬件也可以当作文件,我们用户想要直接操作文件是不可以的,就比如我们直接去open、read、write好像是只有open是可以的,但是read,write这些都是不可以的。
open可以的原因我已经忘了,大家可以去看韦东山的视频复习以下,而read、write这写都是没有权限的,为啥呢,因为内核机制问题,内核为了保证安全,就允许用户空间直接对底层硬件进行操作,只有通过驱动提供接口,然后对文件进行读写操作。
linux通过设备号对相应的文件进行操作

在这里插入图片描述

主设备号和次设备号统称为设备号,主设备号代表是的设备的类型,次设备号代表是的具体的设备,随着内核的更新,可以支持的主设备和次设备的数量也越来越多。

在这里插入图片描述

三、编写一个驱动程序

3.1 编写驱动程序的步骤

  1. 确定主设备号
  2. 定义自己的 file_operations 结构体
  3. 实现对应的 open/read/write函数,填写入结构体
  4. 把file_operations 结构体告诉内核,注册驱动程序
  5. 谁来注册驱动程序?需要一个入口函数;安装驱动程序时,就会调用这个入口函数
  6. 卸载驱动程序,调用出口函数
  7. 其他,提供设备信息,创建设备节点

3.1.2 确定主设备号以及注册驱动

为了方便,我这边就和注册一起写了。
source code:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kmod.h>static int major = 0; //确定主设备号,0默认系统分配static struct file_operations filectl_ops = {.owner   = THIS_MODULE,
};static int __init filectl_init(void)
{// 在初始化的时候进行驱动注册,设备号major = register_chrdev(0,"filectl",&filectl_ops);if(major < 0) {printk("[%s %d] filectl error\n", __FUNCTION__, __LINE__); // 注册失败return -1;}filectl_class = class_create(THIS_MODULE, "filectl"); // class_create 动态创建dev的类// IS_ERR 查看指针是否有错误if(IS_ERR(filectl_class)) {printk("[%s %d] class_create error\n", __FUNCTION__, __LINE__);unregister_chrdev(major,"filectl");return -1;}// 创建字符设备device_create(filectl_class, NULL, MKDEV(major, 0),NULL, "filectl");printk("[%s %d] filectl driver create success\n", __FUNCTION__, __LINE__);return 0;
}static void __exit filectl_exit(void) {device_destroy(filectl_class, MKDEV(major, 0));class_destroy(filectl_class);// 注销字符设备unregister_chrdev(major,"filectl");printk("[%s %d]goodbye filectl driver\n",  __FUNCTION__, __LINE__);
}module_init(filectl_init);
module_exit(filectl_exit);
MODULE_LICENSE      ("GPL");
MODULE_AUTHOR       ("cong.luo");
MODULE_DESCRIPTION  ("First file contrl module");

然后编译,加载模块:

在这里插入图片描述

然后我们就可以在dev下面看到我们字符设备了 。

3.1.3 实现对应的函数

实现汉函数就是在对应的ops操作集合里。

// 定义自己的驱动的 file_operations
// file_operations是一个函数指针的集合,用于存放我们定义的用于操作设备的函数的指针,如果我们不定义,它默认保留为NULL
static struct file_operations filectl_ops = {.owner   = THIS_MODULE,.read    = filectl_read,.write   = filectl_write,.open    = filectl_open,.release = filectl_close, // 好像没有close这个函数
};

这样我们就定义好了,定义好了过后我们就是完善这些函数了,不然会编译不过,

如下

ssize_t filectl_read(struct file *file, char __user *buf, size_t size, loff_t *pops)
{printk("[%s %d]\n", __FUNCTION__, __LINE__);return 1;
}ssize_t filectl_write(struct file *file,const char __user *buf, size_t size, loff_t *pops)
{printk("[%s %d]\n", __FUNCTION__, __LINE__);return 1;
}int filectl_open(struct inode *inode, struct file *file)
{printk("[%s %d]\n", __FUNCTION__, __LINE__);return 0;
}int filectl_close(struct inode *inode, struct file *file)
{printk("[%s %d]\n", __FUNCTION__, __LINE__);return 0;
}

这里对于初学者来说可能比较难的参数的传递,这些参数是怎么来的。
其实根本原因就是,虽然这些filectl_open, filectl_read, filectl_write函数是我们定的,但是实际上我们调用的函数还是底层的 open write这些,所以我们需要满足底层open write这些函数的参数结构。

struct inode *inode   

索引, 直白一点就是 文件的存放的地址

struct file *file

操作文件的结构体指针, 描述进程中打开的文件,进程中只要调用了open就有一个该对象。具体描述了打开文件的路径,权限,标志,内部偏移。file结构体是用来维护打开的文件的.

其实比较起来和我们正常的open close这些函数传递的参数是一样的,只不过在内核里面,可能有一些变换, 上面的read和write也都是一样的原理。

完整的code:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/kmod.h>static int major = 0; //确定主设备号,0默认系统分配
static struct class *filectl_class;ssize_t filectl_read(struct file *file, char __user *buf, size_t size, loff_t *pops)
{printk("[%s %d]\n", __FUNCTION__, __LINE__);return 1;
}ssize_t filectl_write(struct file *file,const char __user *buf, size_t size, loff_t *pops)
{printk("[%s %d]\n", __FUNCTION__, __LINE__);return 1;
}int filectl_open(struct inode *inode, struct file *file)
{printk("[%s %d]\n", __FUNCTION__, __LINE__);return 0;
}int filectl_close(struct inode *inode, struct file *file)
{printk("[%s %d]\n", __FUNCTION__, __LINE__);return 0;
}// 定义自己的驱动的 file_operations
static struct file_operations filectl_ops = {.owner	 = THIS_MODULE,.read    = filectl_read,.write   = filectl_write,.open    = filectl_open,.release = filectl_close, // 好像没有close这个函数
};static int __init filectl_init(void)
{// 在初始化的时候进行驱动注册,设备号major = register_chrdev(0,"filectl",&filectl_ops);if(major < 0) {printk("[%s %d] filectl error\n", __FUNCTION__, __LINE__); // 注册失败return -1;}filectl_class = class_create(THIS_MODULE, "filectl"); // class_create 动态创建dev的类// IS_ERR 查看指针是否有错误if(IS_ERR(filectl_class)) {printk("[%s %d] class_create error\n", __FUNCTION__, __LINE__);unregister_chrdev(major,"filectl");return -1;}// 创建字符设备device_create(filectl_class, NULL, MKDEV(major, 0),NULL, "filectl");printk("[%s %d] filectl driver create success\n", __FUNCTION__, __LINE__);return 0;
}static void __exit filectl_exit(void) {device_destroy(filectl_class, MKDEV(major, 0));class_destroy(filectl_class);// 注销字符设备unregister_chrdev(major,"filectl");printk("[%s %d]goodbye filectl driver\n",  __FUNCTION__, __LINE__);
}module_init(filectl_init);
module_exit(filectl_exit);
MODULE_LICENSE		("GPL");
MODULE_AUTHOR		("cong.luo");
MODULE_DESCRIPTION	("First file contrl module");

这样我们的接口就好了。下一步就是去验证这几个read wrte函数了。

四、一些错误现象

错误现象:

/home/thundersoft/work_test/driver/filectl.c: In function ‘filectl_init’:
/home/thundersoft/work_test/driver/filectl.c:74:20: error: invalid storage class for function ‘filectl_exit’static void __exit filectl_exit(void) {^~~~~~~~~~~~
/home/thundersoft/work_test/driver/filectl.c:74:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]static void __exit filectl_exit(void) {^~~~~~
In file included from /home/thundersoft/work_test/driver/filectl.c:1:0:
./include/linux/module.h:128:42: error: invalid storage class for function ‘__inittest’static inline initcall_t __maybe_unused __inittest(void)  \^
/home/thundersoft/work_test/driver/filectl.c:81:1: note: in expansion of macro ‘module_init’module_init(filectl_init);

一般有这种的情况都是 多写了一个 } 或者 少写了一个 { 这个需要自己检查下就好

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spacesniffer文件大小查看工具安装和使用

软件描述 spacesniffer是一块可以快速查看电脑中所有文件大小的工具&#xff0c;当电脑空间不够时&#xff0c;可以迅速找出不需要的大提及文件。 一、软件下载 1、从网盘下载 spacesniffer文件大小查看工具 2、从官网下载 http://www.uderzo.it/main_products/space_sni…

供水管网微观水力模型

国外在管网建模方面起步于20世纪60年代。20世纪80年代&#xff0c;随着计算机及相应技术的发展&#xff0c;遥测远传设备的应用进入了实用化阶段&#xff0c;国内已有很多供水企业实现了供水管网建模。给水管网系统建模&#xff0c;就是为仿真模拟管网系统动态实时运行情况建立…

【论文阅读总结】用于目标检测的特征金字塔网络(FPN)

Feature Pyramid Networks for Object Detection1.摘要2.引言2.1 低级特征对于检测小物体很重要2.2 算法目标3. 文献综述3.1 Hand-engineered features and early neural networks3.2 Deep ConvNet object detectors3.3 Methods using multiple layers4.Feature Pyramid Networ…

LangChain:Prompt Templates介绍及应用

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

WPF+WebView2+react/vue/angular

创建WPF项目 安装WbeView2 Nuget包 在窗体中添加命名空间 xmlns:wv2"clr-namespace:Microsoft.Web.WebView2.Wpf;assemblyMicrosoft.Web.WebView2.Wpf"使用控件 <wv2:WebView2 x:Name"webview"/>在MainWindow中初始化 public MainWindow(){Initia…

什么是语法糖?Java中有哪些语法糖?

本文从 Java 编译原理角度&#xff0c;深入字节码及 class 文件&#xff0c;抽丝剥茧&#xff0c;了解 Java 中的语法糖原理及用法&#xff0c;帮助大家在学会如何使用 Java 语法糖的同时&#xff0c;了解这些语法糖背后的原理1 语法糖语法糖&#xff08;Syntactic Sugar&#…

Linux syslog 日志服务

文章目录Syslog 概述syslog 协议标准syslog APIsyslog 日志文件日志文件介绍日志配置产生本地日志参考文章Syslog 概述 syslog 常被称为系统日志或系统记录&#xff0c;系统日志通过 syslog 进程记录系统的有关事件&#xff0c;也可以记录应用程序运作事件。通过适当配置&…

Python批量删除或移动指定图像

Python批量删除或移动指定图像前言一、批量删除指定名称的图像二、批量移动指定名称的图像前言 笔者的研究方向为计算机视觉&#xff0c;因此经常和大量图像打交道&#xff0c;有时需要批量删除一些图像&#xff0c;有时需要批量移动一些图像&#xff0c;因此编写了下述代码。下…

flink 读取文件数据写入ElasticSearch

前言 es是大数据存储的必备中间件之一,通过flink可以读取来自日志文件,kafka等外部数据源的数据,然后写入到es中,本篇将通过实例演示下完整的操作过程; 一、前置准备 1、提前搭建并开启es服务(本文使用docker搭建的es7.6的服务); 2、提前搭建并开启kibana服务(便于操…

【Java 】Java NIO 底层原理

文章目录1、 Java IO读写原理1.1 内核缓冲与进程缓冲区1.2 java IO读写的底层流程2、 四种主要的IO模型3、 同步阻塞IO&#xff08;Blocking IO&#xff09;4、 同步非阻塞NIO&#xff08;None Blocking IO&#xff09;5、 IO多路复用模型(I/O multiplexing&#xff09;6、 异步…

Cursor编程初体验,搭载GPT-4大模型,你的AI助手,自然语言编程来了

背景 这两天体验了下最新生产力工具Cursor&#xff0c;基于最新的 GPT-4 大模型&#xff0c;目前免费&#xff0c;国内可访问&#xff0c;不限次数&#xff0c;跨平台&#xff0c;你确定不来体验一把&#xff1f;官方的 Slogan &#xff1a; Build Software. Fast. Write, edi…

差速巡线机器人设计-良好(80+)的报告-2023

如何提分&#xff1f;将一篇报告提升20分以上呢&#xff1f;差速巡线机器人设计-及格&#xff08;60&#xff09;的报告-2023_zhangrelay的博客-CSDN博客姓名&#xff1a; 学号&#xff1a; 实践项目1名称&#xff1a;差速巡线机器人设计 60分&#xff1a;缺乏思考、没有对比、…

攻防世界-first

题目下载&#xff1a;下载 IDA载入 __int64 __fastcall main(int a1, char **a2, char **a3) {__useconds_t *v3; // rbpunsigned int v4; // eaxint *v5; // rcxint v6; // edxunsigned int v7; // eaxsigned __int64 v8; // rcx__int64 v9; // raxchar v10; // blchar v11;…

为知笔记私有化部署

前言 原来一直买的为知笔记vip&#xff0c;但是随着内容越来越&#xff0c;并且不好整理。同时还不能一键全部导出&#xff0c;最后决定将数据迁移到自己服务器上。为止笔记提供了docker镜像&#xff0c;这也方便了部署&#xff08;其实吧&#xff0c;从产品层面&#xff0c;可…

C++ Lambda表达式的常见用法

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的在读研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三…

【Django 网页Web开发】05. 数据库操作,实战用户管理(保姆级图文)

目录1. 安装第三方模块2. ORM2.1 自己手动创建数据库2.2 django连接数据库2.3 建表语句写在哪里&#xff1f;2.4 建表语句写好后如何运行生效&#xff1f;3. 操作表3.1 创建数据表3.2 修改数据表4. 操作数据4.1 插入数据4.2 删除数据4.3 修改数据4.4 查询数据5. 实战&#xff1…

pytest学习和使用22-allure特性 丨总览中的Environment、Categories设置以及Flaky test使用

22-allure特性 丨总览中的Environment和Categories设置1 Environment设置1.1 设置方法1.2 创建文件2 Categories设置2.1 设置方式2.2 创建文件3 关于Flaky test3.1 Flaky test介绍3.2 产生Flaky Tests的原因3.3 Flaky安装3.4 Flaky使用3.5 小结小结1小结2如下图&#xff0c;我们…

开始学习HTML5

HTML5 简介 HTML5是HTML最新的修订版本&#xff0c;2014年10月由万维网联盟&#xff08;W3C&#xff09;完成标准制定。 HTML5的设计目的是为了在移动设备上支持多媒体。 HTML5简单易学。 什么是 HTML5? HTML5 是下一代 HTML 标准。 HTML , HTML 4.01的上一个版本诞生于 1…

如何将3张图片横向拼在一起

如何将3张图片横向拼在一起&#xff1f;遇到这个情况你可能马上就会说出很多图片处理的app&#xff0c;比如用某秀秀来操作&#xff0c;但是也有很多时候某秀秀也处理不了的。当我们的图片非常大&#xff0c;图片数量很多&#xff0c;图片的格式不是jpg那种通用的格式&#xff…

如何监控和诊断JVM堆内和堆外内存使用?

第26讲 | 如何监控和诊断JVM堆内和堆外内存使用&#xff1f; 上一讲我介绍了 JVM 内存区域的划分&#xff0c;总结了相关的一些概念&#xff0c;今天我将结合 JVM 参数、工具等方面&#xff0c;进一步分析 JVM 内存结构&#xff0c;包括外部资料相对较少的堆外部分。 今天我要…