03_fops_write 应用层向内核层写数据

2023-10-13 03:08

本文主要是介绍03_fops_write 应用层向内核层写数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

源码

#include <linux/init.h>       //初始化头文件
#include <linux/module.h>     //最基本的文件, 支持动态添加和卸载模块
#include <linux/miscdevice.h> //注册杂项设备头文件
#include <linux/fs.h>         //注册设备节点的文件结构体
#include <linux/uaccess.h>    //copy_to_user/**
* @name: misc_read
* @test: 从设备中读取数据, 当用户层调用函数 read 时, 对应的, 内核驱动就会调用这个函数。
* @msg:
* @param {structfile} *file file 结构体
* @param {char__user} *ubuf 这是对应用户层的 read 函数的第二个参数 void *buf
* @param {size_t} size 对应应用层的 read 函数的第三个参数
* @param {loff_t} *loff_t 这是用于存放文件的偏移量的, 回想一下系统编程时, 读写文件的操
作都会使偏移量往后移。
* @return {*} 当返回正数时, 内核会把值传给应用程序的返回值。 一般的, 调用成功会返回成功
读取的字节数。 如果返回负数, 内核就会认为这是错误, 应用程序返回-1
*/
ssize_t misc_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{char kbuf[] = "role_2099";if(copy_to_user(ubuf,kbuf,strlen(kbuf))!=0){printk("copy_to_user error\n ");return -1;}printk("execute misc_read\n");return 0;
}/**
* @name: misc_write
* @test: 往设备写入数据, 当用户层调用函数 write 时, 对应的, 内核驱动就会调用这个函数。
* @msg:
* @param {structfile} * filefile 结构体
* @param {constchar__user} *ubuf 这是对应用户层的 write 函数的第二个参数const void *buf
* @param {size_t} size 对应用户层的 write 函数的第三个参数 count。
* @param {loff_t} *loff_t 这是用于存放文件的偏移量的, 回想一下系统编程时, 读写文件的操
作都会使偏移量往后移。
* @return {*} 当返回正数时, 内核会把值传给应用程序的返回值。 一般的, 调用成功会返回成功
读取的字节数。 如果返回负数, 内核就会认为这是错误, 应用程序返回-1。
*/
ssize_t misc_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{char kbuf[64]={0};if(copy_from_user(kbuf,ubuf,size)!=0){printk("copy_from_user error\n ");return -1;}printk("kbuf is %s\n ",kbuf);printk("execute misc_write\n");return 0;
}/**
* @name: misc_release
* @test: 当设备文件被关闭时内核会调用这个操作, 当然这也可以不实现, 函数默认为 NULL。 关
闭设备永远成功。
* @msg:
* @param {structinode} *inode 设备节点
* @param {structfile} *file filefile 结构体
* @return {0}
*/
int misc_release(struct inode *inode,struct file *file){ //printk("execute misc_release\n");return 0;
}/**
* @name: misc_open
* @test: 在操作设备前必须先调用 open 函数打开文件, 可以干一些需要的初始化操作。
* @msg:
* @param {structinode} *inode 设备节点
* @param {structfile} *file filefile 结构体
* @return {0}
*/
int misc_open(struct inode *inode,struct file *file){printk("execute misc_open\n");return 0;
}//文件操作集
struct file_operations misc_fops={.owner = THIS_MODULE,.open = misc_open,.release = misc_release,.read = misc_read,.write = misc_write,
};//miscdevice 结构体
struct miscdevice misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "hello_misc",.fops = &misc_fops,
};static int misc_init(void)
{int ret;ret = misc_register(&misc_dev);//注册杂项设备if(ret < 0){printk("misc registe is error\n");}printk("misc registe is succeed\n");return 0;
}static void misc_exit(void){misc_deregister(&misc_dev); //卸载杂项设备printk(" misc exit is succeed\n");
}module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

编写Makefile

obj-m += fops_write.o #先写生成的中间文件的名字是什么, -m 的意思是把我们的驱动编译成模块
KDIR:=/home/myzr/my-work/02_source/linux-4.1.15/
PWD?=$(shell pwd) #获取当前目录的变量
all:make -C $(KDIR) M=$(PWD) modules #make 会进入内核源码的路径, 然后把当前路径下的代码编译成模块

输入make编译

把fops_write.ko拷贝到共享目录

sudo cp fops_write.ko /home/nfs/

编写应用程序app.c

源码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc,char *argv[])
{int fd;char buf[64] = "12345";fd = open("/dev/hello_misc",O_RDWR);//打开设备节点if(fd < 0){perror("open error \n");return fd;}//read(fd,buf,sizeof(buf));write(fd,buf,sizeof(buf)); //向内核层写数据//printf("buf is %s\n",buf);close(fd);return 0;
}

输入arm-none-linux-gnueabi-gcc app.c -o app -static编译app

把应用程序app拷贝到共享目录

sudo cp app /home/nfs/

在开发板上加载驱动模块

insmod fops_write.ko

驱动加载成功后,输入以下命令,查看注册的设备节点是否存在,如下图所示,设备节点存在。

ls /dev/h*

执行应用程序

./app

卸载驱动模块

rmmod fops_write

这篇关于03_fops_write 应用层向内核层写数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/200341

相关文章

MySQL数据目录迁移的完整过程

《MySQL数据目录迁移的完整过程》文章详细介绍了将MySQL数据目录迁移到新硬盘的整个过程,包括新硬盘挂载、创建新的数据目录、迁移数据(推荐使用两遍rsync方案)、修改MySQL配置文件和重启验证... 目录1,新硬盘挂载(如果有的话)2,创建新的 mysql 数据目录3,迁移 MySQL 数据(推荐两

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

Linux内核定时器使用及说明

《Linux内核定时器使用及说明》文章详细介绍了Linux内核定时器的特性、核心数据结构、时间相关转换函数以及操作API,通过示例展示了如何编写和使用定时器,包括按键消抖的应用... 目录1.linux内核定时器特征2.Linux内核定时器核心数据结构3.Linux内核时间相关转换函数4.Linux内核定时

MySQL快速复制一张表的四种核心方法(包括表结构和数据)

《MySQL快速复制一张表的四种核心方法(包括表结构和数据)》本文详细介绍了四种复制MySQL表(结构+数据)的方法,并对每种方法进行了对比分析,适用于不同场景和数据量的复制需求,特别是针对超大表(1... 目录一、mysql 复制表(结构+数据)的 4 种核心方法(面试结构化回答)方法 1:CREATE

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

MySQL中的DELETE删除数据及注意事项

《MySQL中的DELETE删除数据及注意事项》MySQL的DELETE语句是数据库操作中不可或缺的一部分,通过合理使用索引、批量删除、避免全表删除、使用TRUNCATE、使用ORDERBY和LIMI... 目录1. 基本语法单表删除2. 高级用法使用子查询删除删除多表3. 性能优化策略使用索引批量删除避免

MySQL 数据库进阶之SQL 数据操作与子查询操作大全

《MySQL数据库进阶之SQL数据操作与子查询操作大全》本文详细介绍了SQL中的子查询、数据添加(INSERT)、数据修改(UPDATE)和数据删除(DELETE、TRUNCATE、DROP)操作... 目录一、子查询:嵌套在查询中的查询1.1 子查询的基本语法1.2 子查询的实战示例二、数据添加:INSE

Linux服务器数据盘移除并重新挂载的全过程

《Linux服务器数据盘移除并重新挂载的全过程》:本文主要介绍在Linux服务器上移除并重新挂载数据盘的整个过程,分为三大步:卸载文件系统、分离磁盘和重新挂载,每一步都有详细的步骤和注意事项,确保... 目录引言第一步:卸载文件系统第二步:分离磁盘第三步:重新挂载引言在 linux 服务器上移除并重新挂p

使用MyBatis TypeHandler实现数据加密与解密的具体方案

《使用MyBatisTypeHandler实现数据加密与解密的具体方案》在我们日常的开发工作中,经常会遇到一些敏感数据需要存储,比如用户的手机号、身份证号、银行卡号等,为了保障数据安全,我们通常会对... 目录1. 核心概念:什么是 TypeHandler?2. 实战场景3. 代码实现步骤步骤 1:定义 E

使用C#导出Excel数据并保存多种格式的完整示例

《使用C#导出Excel数据并保存多种格式的完整示例》在现代企业信息化管理中,Excel已经成为最常用的数据存储和分析工具,从员工信息表、销售数据报表到财务分析表,几乎所有部门都离不开Excel,本文... 目录引言1. 安装 Spire.XLS2. 创建工作簿和填充数据3. 保存为不同格式4. 效果展示5