Linux字符设备驱动中itcol的使用

文章目录

  • 前言
  • 一、ioctl
  • 二、代码解析
    • 2.1 驱动层
    • 2.2 应用层
  • 运行结果
  • 总结


前言

在Linux字符设备驱动中,ioctl是必须掌握一个函数,其实在软件层面它就是一个函数,但是我愿意称之为强大的硬件控制器!在应用中,让我深刻感受到了ioctl的魅力所在,既能够在软件层面实现应用层和驱动层的数据交互,也能够搭配一定的逻辑对硬件进行控制!


一、ioctl

long xxx_ioctl (struct file *filp, unsigned int cmd, unsigned long arg);
功能:对相应设备做指定的控制操作(各种属性的设置获取等等)
参数:filp:指向open产生的struct file类型的对象,表示本次ioctl对应的那次opencmd:用来表示做的是哪一个操作arg:和cmd配合用的参数
返回值:成功为0,失败-1

二、代码解析

2.1 驱动层

先来看一下头文件,下面是mychar.h中的头文件以及ioctl函数中需要用到的幻数,_IOR(MY_CHAR_MAGIC,1,int*)表示ioctl想要实现读操作。

#ifndef MY_CHAR_H
#define MY_CHAR_H#include <asm/ioctl.h>#define MY_CHAR_MAGIC 	'k'
#define MYCHAR_IOCTL_GET_MAXLEN _IOR(MY_CHAR_MAGIC,1,int*)
#define MYCHAR_IOCTL_GET_CURLEN _IOR(MY_CHAR_MAGIC,2,int*)
#endif

下面紧接着来看mychar.c中的内容:

#define MY_CHAR_MAGIC 	'k'
#define MYCHAR_IOCTL_GET_MAXLEN _IOR(MY_CHAR_MAGIC,1,int*)
#define MYCHAR_IOCTL_GET_CURLEN _IOR(MY_CHAR_MAGIC,2,int*)

在mychar.h中包含以上内容,MY_CHAR_MAGIC表示’魔数’或者’幻数’,
宏定义MYCHAR_IOCTL_GET_MAXLEN使用在ioctl的第二个参数中,
_IOR(MY_CHAR_MAGIC,1,int*)的第一个参数是魔数,
第二个参数表示_IOR第几个控制方式
第三个参数表示ioctl操作的内核数据类型

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include "mychar.h"
#define BUF_LEN 		100int major = 11; 		//主设备号
int minor = 0; 			//次设备号
int mychar_num = 1; 	//设备数量struct mychar_dev
{struct cdev mydev; 			//每一类设备都有一个cdev结构体char mydev_buf[BUF_LEN];  	//内核空间int curlen; 				//有效数字从零开始
};struct mychar_dev gmydev;int mychar_open(struct inode *pnode, struct file *pfile)
{pfile->private_data = (void *)container_of(pnode->i_cdev, struct mychar_dev, mydev);printk("mychar open is called!!!\n");return 0;
}ssize_t mychar_read(struct file *pfile, char __user *pbuf, size_t count, loff_t *ppos)
{int size = 0;int ret = 0;struct mychar_dev *pmydev = (struct mychar_dev *)pfile->private_data;if (count > pmydev->curlen){size = pmydev->curlen;}else{size = count;}ret = copy_to_user(pbuf, pmydev->mydev_buf, size);if (ret){printk("copy_to_user failed!\n");return -1;}memcpy(pmydev->mydev_buf, pmydev->mydev_buf + size, pmydev->curlen - size);   //把在mydev_buf中剩下有效数据存放在以mydev_buf的首地址中pmydev->curlen -= size; 			//读走的字节要被减去return size;
}ssize_t mychar_write(struct file *pfile, const char __user *pbuf, size_t count, loff_t *ppos)
{int size = 0;int ret = 0;struct mychar_dev *pmydev = (struct mychar_dev *)pfile->private_data;if (count < BUF_LEN - pmydev->curlen){size = count;}else{size = BUF_LEN - pmydev->curlen;}ret = copy_from_user(pmydev->mydev_buf + pmydev->curlen, pbuf, size);if (ret){printk("copy_from_user failed!\n");return -1;}pmydev->curlen += size;return size;
}long mychar_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{int __user *pret = (int *)arg;int maxlen = BUF_LEN;int ret = 0;struct mychar_dev *pmydev = (struct mychar_dev *)pfile->private_data;switch(cmd){case MYCHAR_IOCTL_GET_MAXLEN:ret = copy_to_user(pret, &maxlen, sizeof(int));if (ret){printk("fail to copy_to_user!\n");return -1;}break;case MYCHAR_IOCTL_GET_CURLEN:ret = copy_to_user(pret, &pmydev->curlen, sizeof(int));if (ret){printk("fail to copy_from_user!\n");return -1;}break;default:printk("the cmd is unknow!\n");return -1;}return 0;
}int mychar_close(struct inode *pnode, struct file *pfile)
{printk("mychar clsoe is called!!!\n");return 0;
}/* 对字符设备的操作函数 */
struct file_operations myops = {.owner = THIS_MODULE,.open = mychar_open,.write = mychar_write,.read = mychar_read,.unlocked_ioctl = mychar_ioctl,	.release = mychar_close,
};int __init mychar_init(void)
{int ret = 0;dev_t devno = MKDEV(major, minor); 										//组合设备号ret = register_chrdev_region(devno, mychar_num, "mychar"); 				//手动申请设备号if (ret) 																//返回值为0表示申请成功{ret = alloc_chrdev_region(&devno, 0, mychar_num, "mychar"); 	//申请失败则系统自动分配if (ret){printk("get devno failed!\n");return -1;}major = MAJOR(devno); 												//从系统分配的设备号中取出主设备号minor = MINOR(devno); 												//从系统分配的设备号中取出次设备号devno = MKDEV(major, minor); 										//组合设备号}/* 使得设备具有myops中的函数操作方法 */cdev_init(&gmydev.mydev, &myops);gmydev.mydev.owner = THIS_MODULE;/* 将设备号为devno的这个设备(mydev)添加到内核(内核hash链表中) */cdev_add(&gmydev.mydev, devno, mychar_num);printk("hello world!\n");return 0;
}void __exit mychar_exit(void)
{dev_t devno = MKDEV(major, minor); 					//组合设备号unregister_chrdev_region(devno, mychar_num); 		//注销设备号/* 从内核中删除mydev这个设备 */cdev_del(&gmydev.mydev);printk("bye bye!!!\n");
}MODULE_LICENSE("GPL");
module_init(mychar_init);
module_exit(mychar_exit);

2.2 应用层

以下代码的主要逻辑时:
1.以读写方式打开设备文件
2.使用ioctl从驱动层读取可以写入的最大字节数
3.将"hello"以字符串形式写入内核空间
4.使用ioctl从驱动层读取当前驱动层已经写入的字节数,也就是"hello"所占的6字节
5.最后读取并打印

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "mychar.h"int main(int argc, const char *argv[])
{int fd = -1;char buf[6];int max = 0;int cur = 0;if (argc < 2){printf("the arguement is too few!\n");return -1;}fd = open(argv[1], O_RDWR);if(fd < 0){printf("fail to open %s\n", argv[1]);return -1;}ioctl(fd, MYCHAR_IOCTL_GET_MAXLEN, &max);printf("max = %d\n", max);write(fd, "hello", 6);printf("max = %d\n", max);ioctl(fd, MYCHAR_IOCTL_GET_CURLEN, &cur);printf("cur = %d\n", cur);read(fd, buf, 6);printf("buf = %s\n", buf);close(fd);fd = -1;return 0;
}

运行结果

在这里插入图片描述


总结

本期分享的主要是ioctl在驱动程序中的使用,这是一个非常重要的函数,希望各位小伙伴们不仅能使用,也能够理解其底层原理!最后,各位小伙伴们如果有收获,可以点赞收藏哦,你们的认可是我创作的动力,一起加油!

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

C#常识篇(二)

委托和事件的区别 委托可以认为是对指定签名的函数的引用&#xff0c;通过委托可以实现将函数作为参数传递或者间接调用函数&#xff0c;委托是类型安全的&#xff0c;仅指向与其声明时指定签名相匹配的函数。委托可以分为单播委托和多播委托&#xff0c;二者的区别在于是对单个…

STM32单片机基本原理与应用(九)

SDIO/SD卡实验 实验内容 将SD卡插入实训平台并烧写程序&#xff0c;开机后TFTLCD屏幕上会显示是否成功初始化SD卡并显示SD卡容量。 电路原理图 实验原理 SD卡的通信方式有两种&#xff1a;SPI和SDIO。SD卡有五种寄存器&#xff0c;如下表 SD 卡的指令由 6 个字节组成&…

YOLOv5算法进阶改进(18)— 引入动态蛇形卷积DSConv(ICCV2023 | 用于管状结构分割)

前言:Hello大家好,我是小哥谈。动态蛇形卷积(Dynamic Snake Convolution,简称DSConv)是一种用于图像处理和计算机视觉任务的卷积神经网络(CNN)操作。它是在传统的卷积操作基础上引入了动态蛇形路径的概念,以更好地捕捉图像中的细节和边缘信息。传统的卷积操作是在固定的…

第三节:kafka sarama 遇到Bug?

文章目录 前言一、先上结果二、刨根问底总结 前言 前面两节&#xff0c;我们已经简单应用了sarama的两个类型Client和ClusterAdmin&#xff0c;其中有一个案例是获取集群的ControllerId&#xff0c;但是在后面的测试过程过程中&#xff0c;发现一个问题&#xff0c;返回的Cont…

SpringMVC 学习(四)之获取请求参数

目录 1 通过 HttpServletRequest 获取请求参数 2 通过控制器方法的形参获取请求参数 3 通过 POJO 获取请求参数&#xff08;重点&#xff09; 1 通过 HttpServletRequest 获取请求参数 public String handler1(HttpServletRequest request) <form action"${pageCont…

js:通过input标签或Drag拖拽文件实现浏览器文件上传获取File文件对象

文档 https://developer.mozilla.org/zh-CN/docs/Web/API/Filehttps://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/drag_event 通过读取文件可以获取File对象的信息 lastModified: 1707210706000 lastModifiedDate: Tue Feb 06 2024 17:11:46 GMT0800 (中国标准…

力扣--动态规划1027.最长等差数列

思路分析&#xff1a; 使用动态规划的思想&#xff0c;定义二维数组dp&#xff0c;其中dp[i][j]表示以nums[i]为结尾&#xff0c;公差为(j-1000)的等差数列长度。为了适应负数的情况&#xff0c;将公差的范围设为[-1000, 1000]&#xff0c;并且加上1000作为数组索引。 初始化r…

2.23 Day05

#include "mywidget.h" #include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget) {ui->setupUi(this);//居中ui->label02->setAlignment(Qt::AlignCenter);ui->Edit1->setAlignment(Qt::Alig…

【Flink精讲】Flink性能调优:内存调优

内存调优 内存模型 JVM 特定内存 JVM 本身使用的内存&#xff0c;包含 JVM 的 metaspace 和 over-head 1&#xff09; JVM metaspace&#xff1a; JVM 元空间 taskmanager.memory.jvm-metaspace.size&#xff0c;默认 256mb 2&#xff09; JVM over-head 执行开销&#xff1…

springboot219基于SpringBoot的网络海鲜市场系统的设计与实现

网络海鲜市场系统的设计与实现 摘 要 计算机网络发展到现在已经好几十年了&#xff0c;在理论上面已经有了很丰富的基础&#xff0c;并且在现实生活中也到处都在使用&#xff0c;可以说&#xff0c;经过几十年的发展&#xff0c;互联网技术已经把地域信息的隔阂给消除了&…

【数据结构和算法初阶(C语言)】空间复杂度(例题剖析一起探究空间如何评价算法)

目录 1.衔接前言-时间复杂度的回顾 2.关于算法复杂度 3.本文主角-空间复杂度 3.1大O的渐进表示方法 4.空间复杂度例题----实际感受空间复杂度 4.1冒泡排序的空间复杂度 4.2计算递归函数的空间复杂度 4.3动态开辟内存版本求斐波那契数列的空间复杂度 4.4&#xff08;…

TMGM外汇开户需要提供以下材料:

TMGM外汇开户需要提供以下材料&#xff1a; 身份证明&#xff1a;通常需要提供有效的身份证明文件&#xff0c;如身份证、护照或驾驶执照等。 居住证明&#xff1a;您需要提供能够证明您居住地址的文件&#xff0c;如水电费账单、房屋租赁合同、居住证明信等。 银行账户信息&a…

【MySQL】探索表结构、数据类型和基本操作

表、记录、字段 数据库的E-R&#xff08;entity-relationship&#xff0c;实体-关系&#xff09;模型中有三个主要概念&#xff1a; 实体集 、 属性 、 关系集 。 一个实体集对应于数据库中的一个表&#xff0c;一个实体则对应于数据库表 中的一行&#xff0c;也称为一条记录。…

数字电路 第三章—第三节(加法器)

一、二进制数的算术运算 1、两数绝对值之间的运算 &#xff08;1&#xff09;二进制数的加减乘除等算术运算的规则和十进制数类似&#xff0c;只是加法运算的规则为“逢二进一”&#xff0c;减法运算的规则为“借一当二”。 &#xff08;2&#xff09;二进制加法&#xff1a…

2024022201-并发控制

并发控制 多事务执行方式 (1)事务串行执行 每个时刻只有一个事务运行&#xff0c;其他事务必须等到这个事务结束以后方能运行不能充分利用系统资源&#xff0c;发挥数据库共享资源的特点 (2)交叉并发方式&#xff08;interleaved concurrency&#xff09; 事务的并行执行是…

JDK8新特性全解析:Java8变革之旅

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

go环境安装-基于vscode的Windows安装

1、vscode安装 官网链接&#xff1a;https://code.visualstudio.com/ 选择相应的版本&#xff0c;这里选择Windows下的 下载得到一个VSCodeUserSetUp-x64的可执行文件&#xff0c;双击执行&#xff0c;选择要安装的路径&#xff0c;下一步。 2、go语言安装 官网链接&#x…

设计模式学习笔记 - 面向对象 - 8.实践:贫血模型和充血模型的原理及实践

1.Web开发常用的贫血MVC架构违背OOP吗&#xff1f; 前面我们依据讲过了面向对象四大特性、接口和抽象类、面向对象和面向过程编程风格&#xff0c;基于接口而非实现编程和多用组合少用继承设计思想。接下来&#xff0c;通过实战来学习如何将这些理论应用到实际的开发中。 大部…

react中修改state中的值无效?

// 初始化state state {personArr:[{name:张三,id:1},{name:李四,id:2},{name:王五,id:3}] }componentDidMount(){const newName 赵六const indexUpdate 1const newArr this.state.personArr.map((item,index)>{if(indexUpdate index){return {...item,name:newName}}e…

【Java程序员面试专栏 算法思维】五 高频面试算法题:贪心算法

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,本篇主要聊聊贪心算法,所以放到一篇Blog中集中练习 题目关键字解题思路时间空间买卖股票的最佳时机 II贪心算法遍历整个股票交易日价格列表 price,并执行贪心策…