Linux驱动学习—ioctl接口

1、unlock_ioctl和ioctl有什么区别?

kernel 2.6.36 中已经完全删除了struct file_operations 中的ioctl 函数指针,取而代之的是unlocked_ioctl 。ioctl是老的内核版本中的驱动API,unlock_ioctl是当下常用的驱动API。unlocked_ioctl 实际上取代了用了很久的ioctl,主要的改进就是不再需要上大内核锁(BKL) (调用之前不再先调用lock_kernel()然后再unlock_kernel())。

2、unlock_ioctl和read/write函数有什么相同点和不同点

相同点:都可以往内核里面写数据。

不同点:read函数只能完成读的功能,write只能完成写的功能。读取大数据的时候效率高。ioctrl既可以读也可以写。读取大数据的时候效率不高。

3、unlock_ioctl接口命令规则

第一个分区:0-7位,命令的编号,范围是0-255。

第二个分区:8-15位,命令的幻数。

注意:第一个分区个第二个分布主要作用是用来区分命令的。

第三个分区:16-29位表示传递的数据大小。

第四个分区:30-31位代表读写的方向。

00:表示用户程序和驱动程序没有数据传递。
10:表示用户程序从驱动里面读数据。
01:表示用户程序向驱动里面写数据。
11:表示先写数据到驱动里面,然后在从驱动里面把数据读出来。

这四个分区的示例图如下:

img

4、命令的合成宏与分解宏

4.1 合成宏

在include\uapi\asm-generic\ioctl.h

#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
注释如下:
_IO(type,nr)用来定义没有数据传递的命令
_IOR(type,nr,size)用来定义从驱动中读取数据的命令
IOW(type,nr,size)用来定义从驱动中写入数据的命令
_IOWR(type,nr,size)用来定义输一局交换类型的命令,先写入数据,在读取数据这类命令。
参数:
type:表示命令的组成的魔数,也就是8-15位。
nr:表示命令组成的编号,也就是0-7位。
size:表示命令组成的参数传递大小,注意这里不是传递数字,而是传递数据类型,如要传递4字节,就可以写成int.

4.2 分解宏

#define _IOC_DIR(nr)        (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr)     (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
注释如下:
_IOC_DIR(nr)是分解命令的方向,也就是上面说30-31位的值。
_IOC_TYPE(nr)分解命令的魔数,也就是上面说的8-15位的值。
_IOC_NR(nr)分解命令的编号,也就是上面说的0-7位。
_IOC_SIZE(nr)分解命令的复制数据大小,也就是上面说的16-29位。
参数说明:
nr:要分解的命令

5、实验:在应用层使用命令合成宏和命令分解宏

值得注意的是,内核中使用的合成宏和分解宏与应用层使用的是一样的。其实可以用户和内核空间共用的头文件,里面是ioctl命令的构成和头文件。但本实例在应用层演示其使用,所以就不定义共用的头文件了。

#incldue <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
​
#define CMD_TEST0 _IO("L",0)
#define CMD_TEST1 _IO("A",1)
#define CMD_TEST2 _IOW("L",2,int)
#define CMD_TEST3 _IOR("L",3,int)
​
int main(int argc, char *argv[])
{printf("30-31 is %d\n",_IOC_DIR(CMD_TEST0));printf("30-31 is %d\n",_IOC_DIR(CMD_TEST3));printf("8-15 is %d\n",_IOC_TYPE(CMD_TEST0));printf("8-15 is %d\n",_IOC_TYPE(CMD_TEST1));printf("0-7 is %d\n",_IOC_NR(CMD_TEST2));
}

6、实验:驱动层和应用层使用ioctl

6.1 驱动层代码

#include <linux/init.h>
#include <linux/module.h>//最基本的文件,支持动态添加和卸载模块
#include <linux/miscdevice.h>//注册杂项设备头文件
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
​
#define CMD_TEST0 _IO("L",0)
#define CMD_TEST1 _IO("A",1)
#define CMD_TEST2 _IOW("L",2,int)
#define CMD_TEST3 _IOW("L",3,int)
#define CMD_TEST4 _IOR("L",4,int)
​
ssize_t misc_read(struct file *file,char __user *ubuf, size_t size, loff_t *loff_t)
{char kbuf[64] = "heheh";if(copy_to_user(ubuf, kbuf, strlen(kbuf)) != 0) {printk("copy_to_user error\n");return -1;}return 0;
}
​
ssize_t misc_wirie(struct file *file,char __user *ubuf, size_t size, loff_t *loff_t)
{char kbuf[64] = {0};if(copy_form_user(kbuf, ubuf, strlen(kbuf)) != 0) {printk("copy_form_user error\n");return -1;}printk("kbuf is %s\n",kbuf);return 0;
}
​
int misc_open(struct inode *inode, struct file *file)
{printk("misc_open \n");return 0;
}
​
int misc_release(struct inode *inode, struct file *file)
{printk("misc_release \n");return 0;
}
​
long misc_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{int val = 0;switch(cmd){case CMD_TEST2:printk("LEN ON!\n");printk("value is %d!!\n",value);break;case CMD_TEST3:printk("LEN OFF!\n");printk("value is %d!!\n",value);break;case CMD_TEST4:val = 12;if(copy_to_user((int *)value, &val, sizeof(val)) != 0) {printk("copy_to_user error\n");return -1;}break;  }
}
struct file_operations misc_fops={.owner = THIS_MODULE,//owner 指针指向的就是你的模块.open  = misc_open,.release = misc_release,.read   = misc_read,.write  = misc_write,.unlocked_ioctrl = misc_ioctl 
};struct miscdevice misc_dev={.minor=MISC_DYNAMIC_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 register is error \n");return ret;}printk("misc register is succeed \n");return 0;
}
​
static void misc_exit(void)
{misc_deregister(&misc_dev);printk("misc_exit \n");
}
​
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

6.2应用层ioctl函数

和open read write函数同理,当在应用层代码中调用ioctl接口的时候,其实调用的内核file_operations的unlocked_ioctl结构体成员。

#include <sys/ioctl.h> 
int ioctl(int fd, int cmd, ...) ;
参数1:设备描述符
参数2:指令,如某一个命令对应驱动层的某一个功能
参数3:可变参数,跟命令有关,传递进入驱动层的参数或者是接收数据的缓存
返回值:成功:返回 0,失败:返回 -1,并设置全局变量 errorno 值

6.3应用层代码

#incldue <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
​
#define CMD_TEST0 _IO("L",0)
#define CMD_TEST1 _IO("A",1)
#define CMD_TEST2 _IOW("L",2,int)
#define CMD_TEST3 _IOW("L",3,int)
#define CMD_TEST4 _IOR("L",4,int)
​
int main(int argc, char *argv[])
{int fd; fd = open("/dev/hello_misc",O_RDWR);if (fd < 0) {perror("open error");return fd;}while (1) {ioctl(fd,CMD_TEST2,0);sleep(2);ioctl(fd,CMD_TEST3,1);sleep(2);}return 0;
}

6.4 修改应用层代码,使得用到宏IOR

#incldue <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
​
#define CMD_TEST0 _IO("L",0)
#define CMD_TEST1 _IO("A",1)
#define CMD_TEST2 _IOW("L",2,int)
#define CMD_TEST3 _IOW("L",3,int)
#define CMD_TEST4 _IOR("L",4,int)
​
int main(int argc, char *argv[])
{int fd; fd = open("/dev/hello_misc",O_RDWR);if (fd < 0) {perror("open error");return fd;}while (1) {ioctl(fd,CMD_TEST4,&value);printf("value is %d\n",value);sleep(2);}return 0;
}

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

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

相关文章

Obsidian笔记软件无公网远程同步数据到群辉Webdav

文章目录 1. 群晖开启Webdav服务2. 群晖安装Cpolar3. 配置Webdav远程地址4. Obsidian 安装Remotely Save5. Obsidian远程连接Webdav6. 固定Cpolar公网地址7. PC和移动端笔记同步演示 Obsidian是一款笔记软件&#xff0c;它基于Markdown&#xff0c;支持Windows、macOS、iOS和An…

机器学习三要素与拟合问题

1.如何构建机器学习模型&#xff1f; 机器学习工作流程总结 1.获取数据 2.数据基本处理 3.特征工程 4.机器学习(模型训练) 5.模型评估 结果达到要求&#xff0c;上线服务&#xff0c;没有达到要求&#xff0c;重新上面步骤 我们使用机器学习监督学习分类预测模型的工作流…

【大数据面试知识点】Spark中的累加器

Spark累加器 累加器用来把Executor端变量信息聚合到Driver端&#xff0c;在driver程序中定义的变量&#xff0c;在Executor端的每个task都会得到这个变量的一份新的副本&#xff0c;每个task更新这些副本的值后&#xff0c;传回driver端进行merge。 累加器一般是放在行动算子…

低成本TB级数据库技术选型之思考两三点

一、背景 前段时间在搞毕业论文的选题&#xff0c;最头疼的就是大量的文献检索和阅读&#xff0c;从研究的角度上我们可以将文献分为四类&#xff1a; 理论文献&#xff1a;为研究提供理论的框架和基础的文献。这些文献可能并不会和所做的研究直接相关&#xff0c;甚至由于理…

VUE项目运行失败原因以及解决办法

1.正常运行&#xff1a; Ctl J打开终端&#xff0c;并运行如下命令&#xff1a; npm run serve 正常情况下&#xff0c;就可以得到本地和网络链接&#xff0c;如下&#xff1a; 点击链接即可进入到编辑好的页面。 不过&#xff0c;你也可能遇到如下情况↓↓↓ 2.无法找到pac…

Access数据库C#读写验证

1、数据库简介 Access数据库是一个相当古老的文件型数据库&#xff0c;主打一个简单方便&#xff0c;没有复杂的安装过程&#xff0c;没有庞大的后端管理&#xff0c;整个数据库就是一个文件。可以像普通文件一样复制和修改&#xff0c;可以同时读写。 在小型系统中&#xff0c…

CSS 丝带形状效果

CSS 丝带形状效果如图&#xff1a; 通过CSS创建折叠丝带形状 这里代码应该比较清晰易懂&#xff0c;clip-path 的值应该也容易理解。要注意的是&#xff0c;我们使用了 color-mix() 函数&#xff0c;这个属性允许创建主颜色的深色版本。现在如果我们将元素旋转相反的方向&#…

web component - 使用HTML Templates和Shadow DOM构建现代UI组件

Web Component是一种用于构建可重用的UI组件的技术。它使用标准化的浏览器API&#xff0c;包括Custom Elements、Shadow DOM和HTML Templates来实现组件化开发方式。这些API都是现代浏览器原生支持的&#xff0c;因此不需要引入第三方库或框架即可使用。 在这篇博客中&#xf…

第7课 利用FFmpeg将摄像头画面与麦克风数据合成后推送到rtmp服务器

上节课我们已经拿到了摄像头数据和麦克风数据&#xff0c;这节课我们来看一下如何将二者合并起来推送到rtmp服务器。推送音视频合成流到rtmp服务器地址的流程如下&#xff1a; 1.创建输出流 //初始化输出流上下文 avformat_alloc_output_context2(&outFormatCtx, NULL, &…

极速文件搜索工具Everything结合内网穿透实现远程搜索本地文件

文章目录 前言1.软件安装完成后&#xff0c;打开Everything2.登录cpolar官网 设置空白数据隧道3.将空白数据隧道与本地Everything软件结合起来总结 前言 要搭建一个在线资料库&#xff0c;我们需要两个软件的支持&#xff0c;分别是cpolar&#xff08;用于搭建内网穿透数据隧道…

算法逆袭之路(1)

11.29 开始跟进算法题进度! 每天刷4题左右 ,一周之内一定要是统一类型 而且一定稍作总结, 了解他们的内在思路究竟是怎样的!! 12.24 一定要每天早中晚都要复习一下 早中午每段一两道, 而且一定要是同一个类型, 不然刷起来都没有意义 12.26/27&#xff1a; 斐波那契数 爬…

每日一题——LeetCode997

方法一 个人方法&#xff1a; 这题的意思就是1-n里面找到一个数&#xff0c;它不指向任何数&#xff0c;其他数都要指向它 找到没有指向任何数的那个idx&#xff0c;如果不存在这样的数那么就返回-1如果找到了这样的数&#xff0c;还要继续判断其它的所有数是否都指向它&…