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

3.用户程序与驱动交互

驱动程序请使用第二章https://blog.csdn.net/chenhequanlalala/article/details/140034424

用户app与驱动交互最常见的做法是insmod驱动后,生成一个设备节点,app通过open,read等系统调用去操作这个设备节点,这里先用mknode命令调试。

mknod 设备名 设备类型(b块设备/c字符设备/p管道) 主设备号 次设备号

mknod /dev/hello c 240 0

 使用mknode后生成了/dev/hello节点,写入数据到hello节点中,查看dmesg的输出发现调用了驱动的open write release

echo 1 > /dev/hello

[  802.771723] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_open 48
[  802.773196] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_write 40
[  802.773285] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_release 56
 

 这里写一个C程序来读写这个设备节点

#include "linux/string.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>/*
读数据 ./hello_test xxx(设备节点名字)
写数据 ./hello_test xxx(设备节点名字) string
*/int main(int argc, char **argv)
{int fd;int len;char buf[1024];if(argc < 2){printf("Usage :\n");printf("%s <dev> [str]\n", argv[0]);return -1;}//openfd = open(argv[1], O_RDWR);if(fd < 0){printf("open %s failed\n", argv[1]);return -1;}//readif(argc == 2){len = read(fd, buf, sizeof(buf));printf("%s\n", buf);}//writeelse if(argc == 3){len = write(fd, argv[2], strlen(argv[2]));}else{printf("Too many parameters\n");}close(fd);
}

分别调用 ./hello_test /dev/hello 123 和 ./hello_test /dev/hello 后,查看dmesg输出显示

[ 2770.434595] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_open 48
[ 2770.434664] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_write 40
[ 2770.434705] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_release 56
[ 2772.388372] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_open 48
[ 2772.388439] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_read 32
[ 2772.389257] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_release 56

 app的open write read release都一一对应上了。

这里的./hello_test /dev/hello其实没有读到数据,因为驱动程序中并没有和app交互数据。

[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello
read size = 1024 data = 
 

 app与驱动交换数据通过copy_from_user和copy_to_user来实现

copy_to_user(void __user *to, const void *from, unsigned long n);
copy_from_user(void *to, const void __user *from, unsigned long n);

在驱动程序中添加一个buf用来保存用户的数据,用copy_from_user保存数据,用copy_to_user读取数据。

#include "asm/uaccess.h"
#include "linux/scatterlist.h"
#include "linux/types.h"
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/backing-dev.h>
#include <linux/shmem_fs.h>
#include <linux/splice.h>
#include <linux/pfn.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/uio.h>
#include <linux/module.h>#include <linux/uaccess.h>#define DEVICE_NAME "hello_device"
static int major;
#define hello_buf_size 100
static unsigned char hello_buf[hello_buf_size];//ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
//参数含义依次为 要读取的文件指针 用户保存数据的buf 读取数据大小 文件内容的偏移量
static ssize_t hello_read (struct file * filp, char __user *buf, size_t size, loff_t *offset)
{unsigned long len = size > hello_buf_size ? hello_buf_size : size;copy_to_user(buf, hello_buf, len);printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return len;
}//ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
//参数含义依次为 要写入的文件指针 用户要写入的数据buf 写入数据大小 文件内容的偏移量
static ssize_t hello_write (struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{unsigned long len = size > hello_buf_size ? hello_buf_size : size;copy_from_user(hello_buf, buf, len);printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return len;
}//int (*open) (struct inode *, struct file *);
//参数含义依次为 文件索引节点 文件指针
static int hello_open (struct inode *node, struct file *filp)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}//int (*release) (struct inode *, struct file *);
//参数含义依次为 文件索引节点 文件指针
static int hello_release (struct inode *node, struct file *filp)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0; 
}/*构建file_operations结构体*/
static const struct file_operations hello_fops = {.owner      = THIS_MODULE,.read		= hello_read,.write		= hello_write,.open		= hello_open,.release    = hello_release,
};/*init函数,实现register_chrdev*/
static int __init hello_init(void)
{//数含义依次为 主设备号,如果为0,内核会自动分配一个可用的。设备名,会在/proc/devices中显示。 file_operations结构体//注册成功就返回主设备号major = register_chrdev(0, DEVICE_NAME, &hello_fops);printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/*exit函数unregister_chrdev*/
static void __exit hello_exit(void)
{//数含义依次为 主设备号 设备名unregister_chrdev(major, DEVICE_NAME);printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}module_init(hello_init);
module_exit(hello_exit);
//遵循GPL协议
MODULE_LICENSE("GPL");

重新insmod驱动后,执行测试程序

[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello 123456
[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello       
read size = 100 data = 123456
[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello hello
[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello 
read size = 100 data = hello6
 

 这里第二次输出hello6,是因为copy_from_user只是写入指定长度的数据,第一次写入的123456只覆盖了前5字节。

相关文章:

3.用户程序与驱动交互

驱动程序请使用第二章https://blog.csdn.net/chenhequanlalala/article/details/140034424 用户app与驱动交互最常见的做法是insmod驱动后&#xff0c;生成一个设备节点&#xff0c;app通过open&#xff0c;read等系统调用去操作这个设备节点&#xff0c;这里先用mknode命令调…...

尽量不写一行if...elseif...写出高质量可持续迭代的项目代码

背景 无论是前端代码还是后端代码&#xff0c;都存在着定位困难&#xff0c;不好抽离&#xff0c;改造困难的问题&#xff0c;造成代码开发越来越慢&#xff0c;此外因为代码耦合较高&#xff0c;总是出现改了一处地方&#xff0c;然后影响其他地方&#xff0c;要么就是要修改…...

xcrun: error: unable to find utility “simctl“, not a developer tool or in PATH

目录 前言 一、问题详情 二、解决方案 1.确认Xcode已安装 2.安装Xcode命令行工具 3.指定正确的开发者目录 4. 确认命令行工具路径 5. 更新PATH环境变量 前言 今天使用cocoapods更新私有库的时候&#xff0c;遇到了"xcrun: error: unable to find utility &…...

【linux高级IO(一)】理解五种IO模型

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux高级IO 1. 前言2. 重谈对…...

前端引用vue/element/echarts资源等引用方法Blob下载HTML

前端引用下载vue/element/echarts资源等引用方法 功能需求 需求是在HTML页面中集成Vue.js、Element Plus&#xff08;Element UI的Vue 3版本&#xff09;、ECharts等前端资源&#xff0c;使用Blob下载HTML。 解决方案概述 直接访问线上CDN地址&#xff1a;简单直接&#xff0c…...

昇思MindSpore学习笔记2-01 LLM原理和实践 --基于 MindSpore 实现 BERT 对话情绪识别

摘要&#xff1a; 通过识别BERT对话情绪状态的实例&#xff0c;展现在昇思MindSpore AI框架中大语言模型的原理和实际使用方法、步骤。 一、环境配置 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下…...

uniapp实现图片懒加载 封装组件

想要的效果就是窗口滑动到哪里&#xff0c;哪里的图片进行展示 主要原理使用IntersectionObserver <template><view><image error"HandlerError" :style"imgStyle" :src"imageSrc" :id"randomId" :mode"mode&quo…...

持续交付:自动化测试与发布流程的变革

目录 前言1. 持续交付的概念1.1 持续交付的定义1.2 持续交付的核心原则 2. 持续交付的优势2.1 提高交付速度2.2 提高软件质量2.3 降低发布风险2.4 提高团队协作 3. 实施持续交付的步骤3.1 构建自动化测试体系3.1.1 单元测试3.1.2 集成测试3.1.3 功能测试3.1.4 性能测试 3.2 构建…...

VBA常用的字符串内置函数

前言 在VBA程序中&#xff0c;常用的内置函数可以按照功能分为字符串函数、数字函数、转换函数等等&#xff0c;本节主要会介绍常用的字符串的内置函数&#xff0c;包括Len()、Left()、Mid()、Right()、Split()、String()、StrConV()等。 本节的练习数据表以下表为例&#xff…...

大数据面试题之Spark(7)

目录 Spark实现wordcount Spark Streaming怎么实现数据持久化保存? Spark SQL读取文件&#xff0c;内存不够使用&#xff0c;如何处理? Spark的lazy体现在哪里? Spark中的并行度等于什么 Spark运行时并行度的设署 Spark SQL的数据倾斜 Spark的exactly-once Spark的…...

AI绘画 Stable Diffusion图像的脸部细节控制——采样器全解析

大家好&#xff0c;我是画画的小强 我们在运用AI绘画 Stable Diffusion 这一功能强大的AI绘图工具时&#xff0c;我们往往会发现自己对提示词的使用还不够充分。在这种情形下&#xff0c;我们应当如何调整自己的策略&#xff0c;以便更加精确、全面地塑造出理想的人物形象呢&a…...

liunx离线安装Firefox

在Linux系统中离线安装Firefox浏览器&#xff0c;您需要先从Mozilla的官方网站下载Firefox的安装包&#xff0c;然后通过终端进行安装。以下是详细的步骤&#xff1a; 准备工作 下载Firefox安装包&#xff1a; 首先&#xff0c;在一台可以上网的电脑上访问Firefox官方下载页面…...

UNet进行病理图像分割

数据集链接&#xff1a;https://pan.baidu.com/s/1IBe_P0AyHgZC39NqzOxZhA?pwdnztc 提取码&#xff1a;nztc UNet模型 import torch import torch.nn as nnclass conv_block(nn.Module):def __init__(self, ch_in, ch_out):super(conv_block, self).__init__()self.conv nn…...

初二数学基础差从哪开始补?附深度解析!

有时候&#xff0c;当你推不开一扇门的时候&#xff0c;不要着急&#xff0c;试着反方向拉一下&#xff0c;或者横向拉一下。下面是小偏整理的初二数学基础差从哪开始补2021年&#xff0c;感谢您的每一次阅读。   初二数学基础差从哪开始补2021年   第一个问题是很多同学都…...

【C语言】return 关键字

在C语言中&#xff0c;return是一个关键字&#xff0c;用于从函数中返回值或者结束函数的执行。它是函数的重要组成部分&#xff0c;负责将函数的计算结果返回给调用者&#xff0c;并可以提前终止函数的执行。 主要用途和原理&#xff1a; 返回值给调用者&#xff1a; 当函数执…...

华为机试HJ13句子逆序

华为机试HJ13句子逆序 题目&#xff1a; 将一个英文语句以单词为单位逆序排放。例如“I am a boy”&#xff0c;逆序排放后为“boy a am I”所有单词之间用一个空格隔开&#xff0c;语句中除了英文字母外&#xff0c;不再包含其他字符 想法&#xff1a; 将输入的字符串通过…...

代码随想录day40 动态规划(5)

52. 携带研究材料&#xff08;第七期模拟笔试&#xff09; (kamacoder.com) 完全背包&#xff0c;可重复放入物品&#xff0c;需要用一维滚动数组从前往后遍历。 由于第0个物品和后面物品的转移方程没有区别&#xff0c;可以不额外初始化dp数组&#xff0c;直接用元素全0的d…...

FFmpeg 命令行 音视频格式转换

&#x1f4da;&#xff1a;FFmpeg 提供了丰富的命令行选项和功能&#xff0c;可以用来处理音视频文件、流媒体等&#xff0c;掌握命令行的使用&#xff0c;可以有效提高工作效率。 目录 一、视频转换和格式转换 &#x1f535; 将视频文件转换为另一种格式 &#x1f535; 指定…...

Jmeter使用JSON Extractor提取多个变量

1.当正则不好使时&#xff0c;用json extractor 2.提取多个值时&#xff0c;默认值必填&#xff0c;否则读不到变量...

c++ 设计模式 的课本范例(下)

&#xff08;19&#xff09; 桥接模式 Bridge&#xff0c;不是采用类继承&#xff0c;而是采用类组合&#xff0c;一个类的数据成员是类对象&#xff0c;来扩展类的功能。源码如下&#xff1a; class OS // 操作系统负责绘图 { public:virtual ~OS() {}virtual void draw(cha…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...

【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析

1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器&#xff08;TI&#xff09;推出的一款 汽车级同步降压转换器&#xff08;DC-DC开关稳压器&#xff09;&#xff0c;属于高性能电源管理芯片。核心特性包括&#xff1a; 输入电压范围&#xff1a;2.95V–6V&#xff0c;输…...

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)

之前都是使用react-pdf来渲染pdf文件&#xff0c;这次有个需求是要兼容xp环境&#xff0c;xp上chrome最高支持到49&#xff0c;虽然说iframe或者embed都可以实现预览pdf&#xff0c;但为了后续的定制化需求&#xff0c;还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...