【linux驱动】用户空间程序与内核模块交互-- IOCTL和Netlink

创建自定义的IOCTL(输入/输出控制)或Netlink命令以便用户空间程序与内核模块交互涉及几个步骤。这里将分别介绍这两种方法。

一、IOCTL 方法

1. 定义IOCTL命令

在内核模块中,需要使用宏定义你的IOCTL命令。通常情况下,IOCTL命令包括了一个命令编号、请求类型的方向(读/写/两者)以及数据大小:

#include <linux/ioctl.h>#define MY_IOCTL_TYPE 'x'  // 通常是一个字符#define MY_IOCTL_CMD1 _IOR(MY_IOCTL_TYPE, 1, my_data_struct)
#define MY_IOCTL_CMD2 _IOW(MY_IOCTL_TYPE, 2, my_data_struct)
// ...

2. 实现ioctl函数

在你的内核模块中,实现ioctl系统调用的函数处理:

static long my_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {my_data_struct data;switch (cmd) {case MY_IOCTL_CMD1:if (copy_from_user(&data, (my_data_struct __user *)arg, sizeof(data)))return -EFAULT;// 处理MY_IOCTL_CMD1break;case MY_IOCTL_CMD2:// 处理MY_IOCTL_CMD2if (copy_to_user((my_data_struct __user *)arg, &data, sizeof(data)))return -EFAULT;break;default:return -ENOTTY; // 未知的命令}return 0; // 成功
}const struct file_operations fops = {.unlocked_ioctl = my_ioctl,// 其他的file_operations成员
};

3. 在用户空间调用IOCTL

应用程序使用`ioctl`系统调用与内核模块交流:

#include <sys/ioctl.h>
#include <fcntl.h>int fd = open("/dev/mydevice", O_RDWR);
my_data_struct data;
// 设置 data
ioctl(fd, MY_IOCTL_CMD2, &data);
// 读取 data
ioctl(fd, MY_IOCTL_CMD1, &data);
close(fd);

二、Netlink 方法

1. 初始化Netlink Socket

在内核模块中,创建并初始化Netlink Socket:

#include <net/sock.h>
struct sock *nl_sk = NULL;static void nl_recv_msg(struct sk_buff *skb) {// 从skb中解析出消息并处理
}static int __init my_module_init(void) {struct netlink_kernel_cfg cfg = {.input = nl_recv_msg,};nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);if (!nl_sk) {pr_err("Error creating socket.\n");return -10;}return 0;
}

2. 实现Netlink消息处理函数

如上所示,`nl_recv_msg`是在用户空间发送消息到内核时调用的接收消息处理函数。处理逻辑根据具体需求实现。

3. 用户空间程序

在用户空间程序中,使用Netlink进行通讯:

#include <sys/socket.h>
#include <linux/netlink.h>struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
int nl_sock;// 创建Netlink Socket
nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);// 初始化地址结构
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); // 自进程IDbind(nl_sock, (struct sockaddr*)&src_addr, sizeof(src_addr));memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0;   // 对端的ID,0表示内核
dest_addr.nl_groups = 0; // 无组播// 发送消息到内核

记得在模块中注册Netlink操作,并且在模块退出时释放Netlink Socket,用户空间程序需要负责构造和解码Netlink消息。以上只是一个概述,实现时往往需要处理更多的细节和错误情况。

三、创建一个字符设备让用户空间程序进行读写操作,内核模块可以对这些操作进行响应

在Linux中,字符设备是可以进行按字节流读写操作的设备。创建一个字符设备使得用户空间的程序可以打开、读写、关闭等操作,并使得内核模块能够对这些操作进行响应,通常是通过实现一个设备驱动来完成的。`ioctl`是一个系统调用,用于设备特定的操作,如配置或获取设备信息。在字符设备驱动中实现`ioctl`是可选的,取决于设备是否需要提供额外的设备控制功能。

以下是创建和注册字符设备的基本步骤:

1. 分配设备号:

使用`alloc_chrdev_region`来动态申请主设备号和从设备号,或者使用`register_chrdev_region`如果你希望静态指定设备号。

2. 创建设备类和设备节点:

通常采用`class_create`创建一个设备类,并使用`device_create`创建设备节点。设备节点是用户空间与设备交云的接口,在`/dev/`目录下创建。

3. 初始化`cdev`结构:

`cdev`结构代表字符设备的内核结构。使用`cdev_init`来初始化`cdev`结构,并关联该结构与之前定义的文件操作函数集合。

4. 添加 cdev 到内核中:

使用`cdev_add`将`cdev`结构添加到内核中,设备就会变为活跃状态,用户空间就可以访问它了。

5. 实现文件操作函数:

定义一个包含`open`、`release`、`read`、`write`等操作的`file_operations`结构,这样用户空间应用就可以通过系统调用来操作驱动。

例如,以下代码段演示了以上步骤的基本框架:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>static int major;
static struct class *my_class;
static struct cdev my_cdev;static int my_open(struct inode *inode, struct file *file)
{// 打开设备的代码return 0;
}static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
{// 读取设备的代码return 0; // 返回读取的字节数
}static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{// 写入设备的代码return count; // 返回写入的字节数
}static int my_release(struct inode *inode, struct file *file)
{// 关闭设备的代码return 0;
}static const struct file_operations my_fops = {.owner = THIS_MODULE,.open = my_open,.read = my_read,.write = my_write,.release = my_release,// 如果你需要使用ioctl,则在这里添加.unlocked_ioctl = my_ioctl,
};static int __init my_init(void)
{dev_t dev_id;// 1. 分配设备号if (alloc_chrdev_region(&dev_id, 0, 1, "my_device") < 0) {return -1;}major = MAJOR(dev_id);// 2. 创建设备类和设备节点my_class = class_create(THIS_MODULE, "my_device_class");device_create(my_class, NULL, dev_id, NULL, "mydevice");// 3. 初始化cdev结构cdev_init(&my_cdev, &my_fops);// 4. 添加cdev到内核中if (cdev_add(&my_cdev, dev_id, 1) < 0) {unregister_chrdev_region(dev_id, 1);return -1;}return 0;
}static void __exit my_exit(void)
{dev_t dev_id = MKDEV(major, 0);// 5. 从系统中删除cdevcdev_del(&my_cdev);// 销毁设备节点和设备类device_destroy(my_class, dev_id);class_destroy(my_class);// 释放设备号unregister_chrdev_region(dev_id, 1);
}module_init(my_init);
module_exit(my_exit);MODULE_LICENSE("GPL");

在`my_fops`中,你可以实现`.unlocked_ioctl`(或`.ioctl`,取决于内核版本)来响应`ioctl`调用。请注意,这只是一个简单的框架。在实际的驱动实现中,你将需要填充这些函数,处理错误情况,并且可能需要处理并发控制和同步问题。

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

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

相关文章

python 基础知识点(蓝桥杯python 科目个人复习计划22)

今日复习内容&#xff1a;基础算法中的时间复杂度 时间复杂度分析 时间复杂度是衡量算法执行时间随输入规模增长的增长率。通过分析算法中基本操作的执行次数来确定时间复杂度‘常见的时间复杂度包括&#xff1a;常数时间O(1)&#xff0c;线性时间O(n),对数时间O(log n)&…

[GN] Vue3.2 快速上手 ---- 核心语法(终章)_3

文章目录 路由器工作模式命名路由to的三种写法嵌套路由路由传参query参数params参数 路由的props配置replace 和 push编程式导航重定向 总结 路由器工作模式 history模式 优点&#xff1a;URL更加美观&#xff0c;不带有#&#xff0c;更接近传统的网站URL。 缺点&#xff1a;后…

UIElement编辑器扩展 组件 Inspector

UIElement编辑器扩展 组件 Inspector https://docs.unity.cn/cn/2021.3/Manual/UIE-create-a-binding-uxml-inspector.html 简单开始 声明序列化VisualTreeAsset [SerializeField] VisualTreeAsset visualTree; 声明完&#xff0c;直接在脚本的Inspector面板&#xff0c;把你…

水塘抽样算法

水塘抽样算法 1、问题描述 最近经常能看到面经中出现在大数据流中的随机抽样问题 即&#xff1a;当内存无法加载全部数据时&#xff0c;如何从包含未知大小的数据流中随机选取k个数据&#xff0c;并且要保证每个数据被抽取到的概率相等。 假设数据流含有N个数&#xff0c;我…

JS中运算符的算术、赋值、+、比较(不同类型之间比较)、逻辑

在JavaScript中&#xff0c;运算符用于执行各种计算和操作。 算术运算符&#xff1a; &#xff1a;用于加法运算。 javascriptlet a 5; let b 3; let sum a b; // 结果: 8 -&#xff1a;用于减法运算。 javascriptlet difference a - b; // 结果: 2 *&#xff1a;用于乘法…

树莓派挂载fat32 u盘

通过fdisk -l 查到设备是sda1 sudo nano /etc/fstab 文件末尾添加&#xff1a; /dev/sda1 /home/pi/mydic_mount auto defaults,noexec,umask0000 0 0 参考文章树莓派linux系统 挂载硬盘&#xff08;U盘&#xff09;相关知识总结&#xff08;五星推荐&#xff09;_树莓派挂…

Rancher部署k8s集群测试安装nginx(节点重新初始化方法,亲测)

目录 一、安装前准备工作计算机升级linux内核时间同步Hostname设置hosts设置关闭防火墙&#xff0c;selinux关闭swap安装docker 二、安装rancher部署rancher 三、安装k8s安装k8s集群易错点&#xff0c;重新初始化 四、安装kutectl五、测试安装nginx工作负载 一、安装前准备工作…

SD-WAN企业组网场景深度解析

在当前快速发展的企业网络环境中&#xff0c;SD-WAN技术不仅仅是实现企业站点之间网络互通的关键&#xff0c;更是满足不同站点对因特网、SaaS云应用、公有云等多种企业应用和业务访问的理想选择。从企业的WAN业务需求出发&#xff0c;我们可以对SD-WAN的组网场景进行深度解析&…

参数校验: spring-boot-starter-validation

参数校验: spring-boot-starter-validation pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>应用 PostMapping("/login")public Re…

VIM工程的编译 / VI的快捷键记录

文章目录 VIM工程的编译 / VI的快捷键记录概述笔记工程的编译工程的编译 - 命令行vim工程的编译 - GUI版vim备注VIM的帮助文件位置VIM官方教程vim 常用快捷键启动vi时, 指定要编辑哪个文件正常模式光标的移动退出不保存 退出保存只保存不退出另存到指定文件移动到行首移动到行尾…

替代堆叠的新技术M-lag

M-lag&#xff1a;跨设备链路聚合组&#xff0c;是一种实现跨设备链路聚合的机制。将一台设备与另外两台设备进行跨设备链路聚合&#xff0c;从而把链路的可靠性从单板级提升到设备级&#xff0c;组成双活系统。 基本概念&#xff1a; peer-link链路&#xff1a;是一条聚合链…

[C#]winform部署官方yolov8-rtdetr目标检测的onnx模型

【官方框架地址】 https://github.com/ultralytics/ultralytics 【算法介绍】 RTDETR&#xff0c;全称“Real-Time Detection with Transformer for Object Tracking and Detection”&#xff0c;是一种基于Transformer结构的实时目标检测和跟踪算法。它在目标检测和跟踪领域…

Android学习(五):常用控件

Android学习&#xff08;五&#xff09;&#xff1a;常用控件 常用控件 TextViewEditTextButtonRadioButtonImageView 1、TextView控件 1.1、简介 TextView是用于显示文字(字符串)的控件&#xff0c;可在代码中通过设置属性改变文字的大小、颜色、样式等功能。 1.2、示例…

力扣刷MySQL-第五弹(详细讲解)

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;力扣刷题讲解-MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出…

编程笔记 html5cssjs 048 CSS链接

编程笔记 html5&css&js 048 CSS链接 一、设置链接样式二、文本装饰三、背景色四、链接按钮五、练习小结 通过 CSS&#xff0c;可以用不同的方式设置链接的样式。 一、设置链接样式 链接可以使用任何 CSS 属性&#xff08;例如 color、font-family、background 等&…

数据库系统概论-00引言

引言 -数据库系统的发展经历了三代演变 层次/网状数据库系统&#xff0c;关系数据库系统&#xff0c;新一代数据库系统。 -造就了四位图灵奖得主 C.W.Bachman,E.F.Codd,James Gray,M.R.Stoebraker.。 -发展了一门计算机基础学科 数据建模和DBMS核心技术为主&#xff…

Java 面向对象02 封装 (黑马)

人画圆&#xff1a;画圆这个方法应该定义在园这个类里面。 人关门&#xff1a;是人给了门一个作用力&#xff0c;然后门自己关上了门&#xff0c;所以关门的方法是在门的类里面 封装对象的好处&#xff1a; 调用Java自带的方法举例实现&#xff1a; 在测试类中&#xff0c;对其…

电脑pdf如何转换成word格式?用它实现pdf文件一键转换

pdf转word格式可以用于提取和重用pdf文档中的内容&#xff0c;有时候&#xff0c;我们可能需要引用或引用pdf文档中的一些段落、表格或数据&#xff0c;通过将pdf转换为可编辑的Word文档&#xff0c;可以轻松地复制和粘贴所需内容&#xff0c;节省我们的时间&#xff0c;那么如…

Element-UI 多个el-upload组件自定义上传,不用上传url,并且携带自定义传参(文件序号)

1. 需求&#xff1a; 有多个&#xff08;不确定具体数量&#xff09;的upload组件&#xff0c;每个都需要单独上传获取文件&#xff08;JS File类型&#xff09;&#xff0c;不需要action上传到指定url&#xff0c;自定义上传动作和http操作。而且因为不确定组件数量&#xff0…

Oracle 经典练习题 50 题

文章目录 一 CreateTable二 练习题1 查询"01"课程比"02"课程成绩高的学生的信息及课程分数2 查询"01"课程比"02"课程成绩低的学生的信息及课程分数3 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩4 查询平均成绩小于…