1:APP打开的文件在内核中如何表示

1.1

        APP 打开文件时,可以得到一个整数,这个整数被称为文件句柄。对于 APP 的每一个文件句柄,在内核里面都有一个“struct file ”与之对应

        当我们使用 open 打开文件时,传入的 flags mode 等参数会被记 录在内核中对应的 struct file 结构体里 (f_flags f_mode)
int open(const char *pathname, int flags, mode_t mode);
例如: fd = open(argv[1], O_RDWR);
       读写文件时,文件的当前偏移地址也会保存在 struct file 结构体的 f_pos 成员里。

1.2 打开字符设备节点时,内核中也有对应的 struct file

        这个结构体中的结构体:struct file_operations *f_op,这是由驱动程序提供的。

        结构体 struct file_operations 的定义如下:包含了open,write,read等文件函数。

2:如何编写驱动程序

1:确定主设备号,也可以让内核分配

2:定义自己的 file_operations 结构体

3:实现对应的 drv_open/drv_read/drv_write 等函数,填入 file_operations 结构体

4:把 file_operations 结构体告诉内核:register_chrdev

5:谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数

6:有入口函数就应该有出口函数:卸载驱动程序时,出口函数调用unregister_chrdev

7:其他完善:提供设备信息,自动创建设备节点:class_create, device_create

3:代码编写

参考 driver/char 中的程序,包含头文件,写框架,传输数据:
驱动中实现 open, read, write, release APP 调用这些函数时,都打印内核信息
APP 调用 write 函数时,传入的数据保存在驱动中
APP 调用 read 函数时,把驱动中保存的数据返回给 APP

3.1:主要代码分析

3.1.1:确定主设备号。

        /* 1. 确定主设备号*/

static int major = 0;       

        //后续在入口函数中,使用下列代码:注册函数进行分配

major = register_chrdev(0, "hello", &hello_drv);

3.1.2:定义自己的 file_operations 结构体

/* 2. 定义自己的file_operations结构体                                              */

static struct file_operations hello_drv = {

    .owner = THIS_MODULE,    //必须存在

    .open = hello_drv_open,     //hello驱动程序的open函数,后续我们需要自己实现这个函数

    .read = hello_drv_read,    //hello驱动程序的read函数,后续我们需要自己实现这个函数

    .write = hello_drv_write,    //hello驱动程序的write函数,后续我们需要自己实现这个函数 

    .release = hello_drv_close, //hello驱动程序的clos函数,后续我们需要自己实现这个函数

};

3.1.3:实现对应的 drv_open/drv_read/drv_write 等函数,  

注:我们现在编写的函数属于驱动函数,那么我们在串口掉用这些函数时,

        串口那边,我们属于APP

        而这些驱动属于 “内核”

        我们串口调用read函数  len = read(fd, buf, 1024);时,我们是需要把kernel_buf的数据读到buf中。所以在这read代码中,我们使用  err = copy_to_user(buf, kernel_buf, MIN(1024, size));这行代码,将kernel_buf写入到buf中。

        我们串口调用write函数 write(fd, argv[2], len);时,是把argv[2]的数据写入到kernel_buf中。所以在这write代码中,我们使用  err = copy_from_user(kernel_buf, buf, MIN(1024, size));这行代码,将buf也就是argv[2]写入到kernel_buf中。

        open函数和close函数只是打印一下内核信息,不做数据处理。

/* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */

static char kernel_buf[1024];

static ssize_t hello_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)

{

    int err;

    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    err = copy_to_user(buf, kernel_buf, MIN(1024, size));

    return MIN(1024, size);

}

static ssize_t hello_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)

{

    int err;

    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    err = copy_from_user(kernel_buf, buf, MIN(1024, size));

    return MIN(1024, size);

}

static int hello_drv_open(struct inode *node, struct file *file)

{

    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    return 0;

}

static int hello_drv_close(struct inode *node, struct file *file)

{

    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    return 0;

}

3.1.4:把 file_operations 结构体告诉内核:register_chrdev

3.1.5. 谁来注册驱动程序啊?得有一个入口函数: 

        3.4和3.5可同时在入口函数中实现,安装驱动程序时,系统去调用这个入口函数,这是直接在入口函数中直接将结构体告诉内核

static int __init hello_init(void)

{

    int err;

    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

//3.4也就是这行代码。在入口函数中进行 注册驱动程序

    major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */

//  下面的代码属于自动创建设备节点,这里先抄着使用

    hello_class = class_create(THIS_MODULE, "hello_class");

    err = PTR_ERR(hello_class);

    if (IS_ERR(hello_class))

    {

        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

        unregister_chrdev(major, "hello");

        return -1;

    }

    device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */

    return 0;

}

3.1.6:有入口函数就应该有出口函数:卸载驱动程序时,出口函数调用unregister_chrdev

static void __exit hello_exit(void)

{

    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

//销毁创建的节点,以及卸载驱动程序

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

    class_destroy(hello_class);

    unregister_chrdev(major, "hello");

}

3.1.7:其他完善:提供设备信息,自动创建设备节点:class_create, device_create

/* 7. 其他完善:提供设备信息,自动创建设备节点 */

module_init(hello_init);

module_exit(hello_exit);

MODULE_LICENSE("GPL");

3.2:全部代码

3.2.1:hello_drv.c

#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>/* 1. 确定主设备号                                                                 */
static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;#define MIN(a, b) (a < b ? a : b)/* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t hello_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);err = copy_to_user(buf, kernel_buf, MIN(1024, size));return MIN(1024, size);
}static ssize_t hello_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);err = copy_from_user(kernel_buf, buf, MIN(1024, size));return MIN(1024, size);
}static int hello_drv_open(struct inode *node, struct file *file)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}static int hello_drv_close(struct inode *node, struct file *file)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/* 2. 定义自己的file_operations结构体                                              */
static struct file_operations hello_drv = {.owner = THIS_MODULE,.open = hello_drv_open,.read = hello_drv_read,.write = hello_drv_write,.release = hello_drv_close,
};/* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init hello_init(void)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */hello_class = class_create(THIS_MODULE, "hello_class");err = PTR_ERR(hello_class);if (IS_ERR(hello_class)){printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "hello");return -1;}device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */return 0;
}/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
static void __exit hello_exit(void)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);device_destroy(hello_class, MKDEV(major, 0));class_destroy(hello_class);unregister_chrdev(major, "hello");
}/* 7. 其他完善:提供设备信息,自动创建设备节点 */module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");

3.2.2 hello_drv_test.c


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>/** ./hello_drv_test -w abc* ./hello_drv_test -r*/
int main(int argc, char **argv)
{int fd;char buf[1024];int len;/* 1. 判断参数 */if (argc < 2) {printf("Usage: %s -w <string>\n", argv[0]);printf("       %s -r\n", argv[0]);return -1;}/* 2. 打开文件 */fd = open("/dev/hello", O_RDWR);if (fd == -1){printf("can not open file /dev/hello\n");return -1;}/* 3. 写文件或读文件 */if ((0 == strcmp(argv[1], "-w")) && (argc == 3)){len = strlen(argv[2]) + 1;len = len < 1024 ? len : 1024;write(fd, argv[2], len);}else{len = read(fd, buf, 1024);		buf[1023] = '\0';printf("APP read : %s\n", buf);}close(fd);return 0;
}

3.3:测试

./hello_drv_test -w www.100ask.net // 把字符串“www.100ask.net”发给驱动程序
./hello_drv_test -r // 把驱动中保存的字符串读回

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

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

相关文章

目标跟踪存在问题以及解决方案

3D 跟踪 一、数据特性引发的跟踪挑战 1. 点云稀疏性与远距离特征缺失 问题表现&#xff1a; 激光雷达点云密度随距离平方衰减&#xff08;如 100 米外车辆点云数不足近距离的 1/10&#xff09;&#xff0c;导致远距离目标几何特征&#xff08;如车轮、车顶轮廓&#xff09;不…

JavaSE-JDK安装

目录 一.在官网下载安装包 二.安装JDK 三.检测JDK是否安装成功 四.配置系统环境变量 一.在官网下载安装包 Oracle官网https://www.oracle.com/cn/java/technologies/downloads/ 二.安装JDK 1.首先在C盘以为的其他盘中创建一个自己可以找到的存放JDK路径&#xff1a; 2.双击下…

使用docker搭建redis主从架构,一主2从

使用Docker搭建Redis主从架构&#xff08;一主两从&#xff09; Redis主从架构是提高系统可用性和读取性能的重要方案&#xff0c;通过Docker可以快速搭建该架构。下面将详细介绍搭建步骤。 架构设计 我们将搭建包含以下组件的架构&#xff1a; 1个主节点&#xff08;Maste…

机器学习3——参数估计之极大似然估计

参数估计 问题背景&#xff1a; P ( ω i ∣ x ) p ( x ∣ ω i ) P ( ω i ) p ( x ) p ( x ) ∑ j 1 c p ( x ∣ ω j ) P ( ω j ) \begin{aligned} & P\left(\omega_i \mid \mathbf{x}\right)\frac{p\left(\mathbf{x} \mid \omega_i\right) P\left(\omega_i\right)…

Spring AOP Pointcut 表达式的语法是怎样的?(execution(...) 是最常用的,还有哪些

Pointcut 表达式是 AOP 的核心&#xff0c;我将详细解析最常用的 execution 表达式&#xff0c;并介绍其他几种同样非常有用的表达式。 1. execution 指示符 (最常用&#xff0c;最强大) execution 用于匹配方法的执行&#xff08;Join Point&#xff09;。它的语法结构最为完…

基于 SpringBoot+Vue 的台球厅管理系统的设计与实现(毕业论文)

基于 SpringBootVue 的台球厅管理系统的设计与实现&#xff08;模板&#xff09;[三号宋体加粗&#xff0c;居中] 摘 要[首行缩进2字符&#xff0c;五号黑体加粗]&#xff1a;摘要内容[五号楷体]本文所提出的基于J2EE/EJB标准的电子化采购平台及其CRM组件综合解决方案&#xf…

运营医疗信息化建设的思路

医疗机构加强运营管理&#xff0c;必须依赖强有力的医院信息系统。信息化很重要&#xff0c;但不能为了信息化而信息化。运营信息化必须有明确的建设目标。 运营信息化建设的目标&#xff0c;包括几个方面&#xff1a; 1.实时反映业务&#xff1b; 2.体现内控思维&#xff1b…

6.24_JAVA_微服务day07_RabbitMQ高级

1、 RabbitListener(queuesToDeclare/*此处是固定写法&#xff0c;只能写这个玩意儿&#xff0c;因为这里是库里的方法*/ Queue(name "lazy.queue",//如果不存在就创建lazy.queue队列durable "true",//把耐用打开arguments Argument(name "x-que…

Python打卡:Day38

知识点回顾&#xff1a; Dataset类的__getitem__和__len__方法&#xff08;本质是python的特殊方法&#xff09;Dataloader类minist手写数据集的了解 浙大疏锦行

质量管理五大核心工具之SPC

SPC&#xff08;Statistical Process Control&#xff0c;统计过程控制&#xff09;是一种基于统计学的质量控制方法&#xff0c;旨在通过监控和分析生产过程数据&#xff0c;识别异常波动并消除异常因素&#xff0c;从而确保过程稳定受控&#xff0c;提升产品质量一致性145。以…

【世纪龙科技】新能源汽车VR虚拟体验展示馆-解锁认知新维度

解锁新能源汽车深度认知新维度&#xff1a;沉浸式 VR 虚拟体验展示馆 在科技不断突破边界的当下&#xff0c;人们对新能源汽车的探索渴望愈发强烈。无论是希望深入了解行业发展脉络的求知者&#xff0c;还是想要直观掌握汽车技术原理的学习者&#xff0c;传统的展示方式似乎总…

oracle基础审计管理

Oracle数据库审计功能详解(简单易懂!) 更新时间&#xff1a;2024年01月30日 16:21:27 作者&#xff1a;前程的前程也迷茫 Oracle审计查询是一项重要的任务,可以帮助DBA更好的管理Oracle数据库,下面这篇文章主要给大家介绍了关于Oracle数据库审计功能的相关资料,文中通过代码介绍…

Day44 预训练模型

目录 一、预训练的概念 二、常见的分类预训练模型 2.1 CNN架构预训练模型 2.2 Transformer类预训练模型 2.3 自监督预训练模型 三、图像预训练模型的发展史 四、预训练的策略 五、预训练代码实战&#xff1a;resnet18 六、尝试在cifar10对比alexnet 七、尝试通过ctrl进…

寻找两个正序数组的中位数:二分查找的终极算法

引言&#xff1a;中位数的「C位之争」 如果把数组比作排队买奶茶的队伍&#xff0c;中位数就是那个站在正中间的幸运儿——不需要知道所有人的位置&#xff0c;只需要找到那个「刚刚好」的中间位置。这个问题看似简单&#xff0c;却藏着算法世界的「效率密码」&#xff0c;尤其…

使用tensorflow的线性回归的例子(一)

拟合y2x1 import matplotlib.pyplot as plt import numpy as np import tensorflow as tf print(tf.__version__) %matplotlib inline #载入随机种子 np.random.seed(5) #生成100个等差序列&#xff0c;每个值在-1 - 1 之间 x_data np.linspace(-1,1,100) #y 2x …

OpenLayers 渲染之矢量影像图层

前言 :::block-1 对于像GeoJSON、KML等地理数据格式的文件&#xff0c;最常用的方法都是通过VectorLayer进行渲染。除此之外&#xff0c;还可以使用VectorImage&#xff08;矢量影像图层&#xff09;进行渲染。本文主要介绍在客户端拖动上传GeoJSON、KML等文件&#xff0c;并采…

Feign 实战指南:从 REST 替代到性能优化与最佳实践

Feign 实战指南&#xff1a;从 REST 替代到性能优化与最佳实践 一 . Feign 替代 RestTemplate1.1 RestTemplate 方式调用存在的问题1.2 Feign 的介绍1.3 定义和使用 Feign 客户端1.3.1 引入依赖1.3.2 添加注解1.3.3 编写 Feign 的客户端进行接口声明1.3.4 测试小结 1.4 通过 PO…

什么是国际期货?期货交易平台搭建

国际期货&#xff08;International Futures&#xff09;&#xff0c;又称外盘期货或全球期货&#xff0c;是指在中国大陆以外的交易所进行标准化合约交易的金融衍生品市场。其核心特征、功能及与国内期货的区别如下&#xff1a; &#x1f4cd; 一、定义与核心特征 全球化交易…

考取华为HCIE-AI有什么用?

在人工智能技术重塑各行各业的浪潮中&#xff0c;掌握核心AI能力成为专业人士的制胜关键。华为推出的HCIE-AI Solution Architect&#xff08;华为认证ICT专家-AI解决方案架构师&#xff09;&#xff0c;正是面向这一领域顶尖人才设立的最高级别认证。主要是为了培养和认证掌握…

Maven 使用说明和配置

作者&#xff1a;小凯 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; 一、前言 Apache Maven (opens new window)是一个软件项目管理、构建和依赖工具。基于项目对象模型 (POM) 的概念&#xff0c;Maven 可以通过中央信息来管理项目的构建、…