驱动开发(六):应用层通过文件系统与内核层交互

驱动开发相关文章:

驱动开发(一):驱动代码的基本框架

驱动开发(二):创建字符设备驱动

驱动开发(三):内核层控制硬件层

驱动开发(四):Linux内核中断

驱动开发(五):Linux内核定时器

驱动开发(六):应用层通过文件系统与内核层交互

驱动开发(应用):设计一个社区饮水机控制系统

目录

 应用层与内核层的交互方式

通过文件系统交互

file_operations 结构体

应用程序将数据传递给驱动

从用户空间拷贝数据到内核空间

从内核空间拷贝数据到用户空间

示例代码

驱动代码(hello.c)

应用层(main.c)


 应用层与内核层的交互方式

在Linux驱动开发中,应用层可以通过以下几种方式来控制内核层:

  1. 文件系统接口:应用程序可以通过文件系统接口来与内核驱动进行通信。应用程序可以通过打开、读取、写入和关闭文件等操作来发送控制命令或获取设备状态。

  2. 系统调用:应用程序可以通过系统调用来请求内核执行某些操作。例如,应用程序可以使用ioctl()系统调用来发送特定的命令给内核驱动。

  3. proc文件系统:proc文件系统提供了一种特殊的文件系统接口,允许应用程序通过读写虚拟文件来与内核进行通信。应用程序可以通过读写/proc文件系统中的特定文件来发送控制命令或获取设备状态。

  4. sysfs文件系统:sysfs文件系统是Linux内核提供的一种特殊文件系统,用于向用户空间提供硬件设备的信息。应用程序可以通过读写sysfs文件来控制设备的行为。

  5. netlink套接字:Netlink是一种用于内核与用户空间之间进行通信的机制。应用程序可以通过创建和使用Netlink套接字来与内核驱动进行通信。

这些方式都可以让应用层与内核层进行交互和控制,具体选择哪种方式取决于应用的需求和设备的特性。

通过文件系统交互

在Linux驱动开发中,通过文件系统进行应用层和内核层的交互涉及以下几个步骤:

  1. 定义设备节点:在内核驱动中,需要定义设备节点,即创建一个特殊的文件。这可以通过调用 register_chrdev()函数来完成。该函数会分配一个主设备号和次设备号,并创建对应的设备节点。

  2. 实现设备文件操作函数:在内核驱动中,需要实现设备文件操作函数,包括 open()、 read()write()release()这些函数会在应用程序对设备文件执行相应操作时被内核调用。

  3. 注册设备文件操作函数:通过调用 file_operations 结构体中的相应函数指针来注册设备文件操作函数,这样内核就会在对设备文件执行相应操作时调用相应的函数。

  4. 用户空间操作设备文件:在应用层,应用程序可以通过文件系统接口(如open()、read()、write()和close()等函数)来操作设备文件。例如,应用程序可以使用open()函数打开设备文件,使用write()函数向设备发送命令,使用read()函数读取设备的状态,并使用close()函数关闭设备文件。

  5. 内核层处理设备文件操作:当应用程序调用文件系统接口函数时,内核会相应地调用对应的设备文件操作函数。在这些设备文件操作函数中,可以对设备进行相应处理,如处理读写请求、控制设备的操作等。

通过以上步骤,应用层和内核层就可以通过文件系统进行交互了。应用程序通过操作设备文件,触发设备文件操作函数的调用,从而实现与内核驱动的通信和控制。

file_operations 结构体

file_operations结构体是Linux内核中用于注册设备文件操作函数的重要结构体。它定义在 <linux/fs.h> 头文件中。file_operations结构体可以在内核驱动中使用,将设备文件操作函数与对应的设备文件关联起来。

file_operations结构体的常用函数及注释如下:

struct file_operations {struct module *owner; // 拥有此结构体的模块的指针,用于管理模块的引用计数loff_t (*llseek) (struct file *, loff_t, int);// 设置文件指针位置的函数,可用于在读写文件时跳过一定的字节数// 参数://   - struct file *:文件描述符指针//   - loff_t:偏移量,表示需要移动的字节数//   - int:位置标志,用于确定移动的起始位置(SEEK_SET,SEEK_CUR,SEEK_END)// 返回值://   - loff_t:调整后的文件指针位置ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);// 读取设备文件内容的函数,在read系统调用中被调用// 参数://   - struct file *:文件描述符指针//   - char __user *:用户空间缓冲区指针,用于存储读取的数据//   - size_t:读取的数据大小//   - loff_t *:文件指针位置的指针,用于更新读取后的文件指针位置// 返回值://   - ssize_t:实际读取的数据大小,若失败则返回错误码ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);// 写入数据到设备文件的函数,在write系统调用中被调用// 参数://   - struct file *:文件描述符指针//   - const char __user *:用户空间缓冲区指针,包含要写入的数据//   - size_t:要写入的数据大小//   - loff_t *:文件指针位置的指针,用于更新写入后的文件指针位置// 返回值://   - ssize_t:实际写入的数据大小,若失败则返回错误码int (*open) (struct inode *, struct file *);// 打开设备文件时被调用的函数,在open系统调用中被调用// 参数://   - struct inode *:文件的inode节点指针//   - struct file *:文件描述符指针// 返回值://   - int:成功返回0,否则返回错误码int (*release) (struct inode *, struct file *);// 关闭设备文件时被调用的函数,在close系统调用中被调用// 参数://   - struct inode *:文件的inode节点指针//   - struct file *:文件描述符指针// 返回值://   - int:成功返回0,否则返回错误码// 其他成员函数...
};

除了上述函数外,file_operations结构体还包括其他一些函数指针,如pollioctlmmap等,用于实现更高级的设备文件操作。

在内核驱动中,可以通过定义一个自定义的file_operations结构体,并将其与设备文件关联起来,以注册设备文件操作函数。这样,在应用程序通过文件系统接口操作设备文件时,相应的设备文件操作函数将会被内核调用,实现设备的处理和控制。例如,可以通过调用cdev_init()函数将自定义的file_operations结构体注册到字符设备驱动中。

应用程序将数据传递给驱动

从用户空间拷贝数据到内核空间

#include <linux/uaccess.h>
int copy_from_user(void *to, const void __user *from, int n)功能:从用户空间拷贝数据到内核空间参数:@to  :内核中内存的首地址@from:用户空间的首地址@n   :拷贝数据的长度(字节)返回值:成功返回0,失败返回未拷贝的字节的个数

从内核空间拷贝数据到用户空间

int copy_to_user(void __user *to, const void *from, int n)功能:从内核空间拷贝数据到用户空间参数:@to  :用户空间内存的首地址@from:内核空间的首地址 __user需要加作用是告诉编译器这是用户空间地址@n   :拷贝数据的长度(字节)返回值:成功返回0,失败返回未拷贝的字节的个数

示例代码

驱动代码(hello.c)
#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#define CNAME "hello"
int copy_size = 0;
char kbuf[128] = {0};
unsigned int major = 0;
ssize_t mycdv_read(struct file *file, char __user *ubuf, size_t len, loff_t *loff)
{if (len > sizeof(kbuf))    //len是用户需要的,有可能大于内核传的{len = sizeof(kbuf);    //大于的时候,有多少就给它多少}copy_size = copy_to_user(ubuf, kbuf, len);if (copy_size){printk(KERN_ERR "copy_to_user error\n");return copy_size;}return 0;
}
ssize_t mycdv_write(struct file *file, const char __user *ubuf, size_t len, loff_t *lo)
{if (len > sizeof(kbuf)){len = sizeof(kbuf);}copy_size = copy_from_user(kbuf, ubuf, len);if (copy_size){printk(KERN_ERR "copy_from_user error\n");return copy_size;}return 0;
}
int mycdv_open(struct inode *inode, struct file *file)
{printk(KERN_ERR "mycdv open ok\n");return 0;
}
int mycdv_release(struct inode *inode, struct file *file)
{printk(KERN_ERR "mycdv release ok\n");return 0;
}const struct file_operations fops ={.read = mycdv_read,.write = mycdv_write,.open = mycdv_open,.release = mycdv_release,
};static int __init hello_init(void)
{major = register_chrdev(major, CNAME, &fops);if (major < 0){printk(KERN_ERR "register chrdev ERR\n");return major;}return 0;
}
static void __exit hello_exit(void)
{unregister_chrdev(major, CNAME);
}module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
应用层(main.c)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>char buf[128]="this is my_cdev";
int main(int argc, char const *argv[])
{int fd;fd = open("./hello",O_RDWR);if(fd<0){perror("open err");return -1;}write(fd,buf,sizeof(buf));memset(buf,0,sizeof(buf));read(fd,buf,sizeof(buf));printf("这是读出来的:%s\n",buf);close(fd);return 0;
}

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

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

相关文章

Redis数据结构-跳跃表 skiplist

跳跃表&#xff08;Skiplist&#xff09;是一种用于高效查找的概率型数据结构&#xff0c;它在插入、删除、搜索操作上具有较高的性能&#xff0c;接近于平衡树。Redis使用跳跃表来实现有序集合&#xff08;sorted sets&#xff09;中的范围查询。 ### 跳跃表的基本结构 跳跃…

借助TheGraph 查询ENS信息

关于ENS (以太坊域名服务) ENS 全称是 Ethereum Name Service,它是一个建立在以太坊区块链上的去中心化域名系统。 ENS 在 Web3 领域发挥着重要作用,主要有以下几个方面: 可读性更好的地址: ENS 允许用户将复杂的以太坊地址(如 0x12345…) 映射为更简单易记的域名。这极大地提…

数据分析-------面试相关

数据分析面试到底在面什么 在寻找合适的数据分析师时&#xff0c;一般招聘方的目标是确保候选人的专业技能和工作经验与岗位要求紧密对应。 关键在于两个方面:岗位的具体需求和数据分析师的职业素质。 首先&#xff0c;招聘方要确保应聘者的专业背景和技能与职位需求相匹配。…

解决微信小程序中input框被禁用后,电脑端小程序点击事件无效,手机端开发者工作和手机端正常

问题&#xff1a;input框被禁用后&#xff0c;电脑端小程序点击事件无效&#xff0c;手机端开发者工作和手机端正常。 解决方法&#xff1a;使用view包裹input标签&#xff0c;在view添加点击事件&#xff0c;input添加css:pointer-events:none; // 禁止鼠标事件 <view bin…

中国车牌检测数据集VOC+YOLO格式2001张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2001 标注数量(xml文件个数)&#xff1a;2001 标注数量(txt文件个数)&#xff1a;2001 标注…

Java 中的 Optional 类及其在避免空指针异常中的作用?如何使用它们来过滤重复元素?

在Java编程的世界里&#xff0c;NullPointerException&#xff08;空指针异常&#xff09;恐怕是每个开发者都不陌生的“老朋友”。它通常发生在尝试访问或操作一个为null的对象的成员时&#xff0c;这不仅会导致程序崩溃&#xff0c;还可能隐藏了代码中的逻辑错误。为了优雅地…

【Linux进阶】UNIX体系结构分解——操作系统,内核,shell

1.什么是操作系统&#xff1f; 从严格意义上说&#xff0c;可将操作系统定义为一种软件&#xff0c;它控制计算机硬件资源&#xff0c;提供程序运行环境。我们通常将这种软件称为内核&#xff08;kerel)&#xff0c;因为它相对较小&#xff0c;而且位于环境的核心。 从广义上…

【TensorFlow深度学习】完整项目案例:从零搭建自然语言问答系统

完整项目案例:从零搭建自然语言问答系统 完整项目案例:从零搭建自然语言问答系统1. 项目概览2. 技术栈与环境准备3. 数据准备4. 模型选择与加载5. 数据预处理6. 模型预测7. 性能优化与评估8. 部署与应用结语完整项目案例:从零搭建自然语言问答系统 随着人工智能技术的飞速发…

用python打印——九九乘法表2

for i in range(1, 10):for j in range(1, i 1):print(f"{j} * {i} {j * i}\t", end)j 1print()外层的 for 循环从 1 到 9 遍历 i。对于每个 i&#xff0c;内层的 for 循环从 1 到 i 遍历 j。在每次循环中&#xff0c;打印出 j 乘以 i 的结果&#xff0c;并以制表…

数据安全和数据加密

数据安全 数据安全是信息技术领域的一个核心议题&#xff0c;涉及到保护数字资料免受未经授权的访问和攻击。它主要包含三个关键方面&#xff1a;可用性、完整性和机密性&#xff0c;这三个要素共同构成了所谓的“信息安全三原则”。 可用性 可用性意味着授权用户能够及时地…

STM32介绍和资料地址

STM32标准外设软件库 https://www.st.com.cn/zh/embedded-software/stm32-standard-peripheral-libraries.html 支持标准外设库的产品系列&#xff1a;

XMLTomcatHttp协议

XML&Tomcat&Http协议 目录 XML&Tomcat&Http协议 1. xml解析(了解) 1.1 配置文件 1.1.1 配置文件的作用 1.1.2 常见的配置文件类型 1.2 properties文件 1.2.1 文件示例 1.2.2 语法规范 1.3 XML文件 1.3.1 文件示例 1.3.2 概念介绍 1.3.3 XML的基本语…

【Android】记录在自己的AMD处理器无法使用Android studio 虚拟机处理过程

文章目录 问题&#xff1a;无法在AMD平台打开Android studio 虚拟机&#xff0c;已解决平台&#xff1a;AMD 5700g系统&#xff1a;win10专业版1、在 amd平台上使用安卓虚拟机需要安装硬件加速器2、关闭win10上的系统服务 问题&#xff1a;无法在AMD平台打开Android studio 虚拟…

前端 CSS 经典:鼠标位置信息

前言&#xff1a;当监听鼠标事件时&#xff0c;需要了解鼠标属性所代表的位置信息 dom.addEventListener("click", (e) > {e.pageX;e.clientX;e.offsetX;e.movementX; }); 1. pageX 表示鼠标距离整个页面左边缘的距离&#xff0c;就算有滚动条&#xff0c;最左…

数据结构与算法-【算法专项】Hash算法-1(散列表+散列函数+Hash冲突解决办法)

数据结构与算法-Hash算法-1 1 前置2 散列表3 散列函数4 Hash冲突4.1 开放寻址&#xff1a;4.2 链路地址 在这里插入图片描述 1 前置 给你N&#xff08;1<N<10&#xff09;个自然数,每个数的范围为&#xff08;1~100&#xff09;。现在让你以最快的速度判断某一个数是否…

怎样选择合适的O型密封圈?

O型密封圈在机械和工业应用中起到至关重要的密封作用。选择合适的O型密封圈不仅能提高设备的运行效率&#xff0c;还能延长其使用寿命。本文将从多个角度详细介绍如何选择适合不同应用场景的O型密封圈。 1、识别操作条件 温度范围&#xff1a;不同材料的O型密封圈在不同温度下…

LabVIEW电机故障监测系统

电机作为工业生产中的关键设备&#xff0c;其故障会导致生产停滞和经济损失。因此&#xff0c;开发一个能实时监控电机状态并预测潜在故障的系统具有重要意义。通过高效的数据采集和分析技术&#xff0c;提升故障诊断的准确性和及时性。 系统组成 该系统由以下部分组成&#…

分布式系统_跨域问题

跨域&#xff1a;域名不一致就是跨域&#xff0c;主要包括&#xff1a; 域名不同&#xff1a; www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com 域名相同&#xff0c;端口不同&#xff1a;localhost:8080和localhost:8081 跨域问题&#xff1a;浏览器禁止…

Eureka区域感知路由:优化微服务架构的地理感知负载均衡

Eureka是Netflix开源的服务发现框架&#xff0c;它是Spring Cloud体系中的核心组件之一。在构建分布式系统和微服务架构时&#xff0c;服务发现是确保不同服务实例能够相互通信的关键机制。Eureka区域感知路由&#xff08;Zone-Aware Routing&#xff09;是Eureka中一个重要的特…

目标跟踪——KCF源码用python实现

from numpy.fft import fft2, ifft2, fftshift import cv2 import numpy as npclass HOG:def __init__(self, winSize):""":param winSize: 检测窗口的大小"""self.winSize winSizeself.blockSize (8, 8)self.blockStride (4, 4)self.cellSiz…