驱动学习(六)ioctl

2023-11-16

驱动学习(六)ioctl


linux内核给用户提供了两类系统调用函数:一类是数据操作函数,比如read、write…。 另外一类函数是非数据操作函数,比如ioctl…,用户程序可以用ioctl给底层设备发送指令。

1. ioctl

ioctl是一个系统调用函数,应用程序可以用它给内核发送指令。

int ioctl(int d, int request, ...);
	d:文件描述符
	request:命令码。
	...:可变参数,可有可无,若有,该参数传送内核驱动
	返回值:成功为0
2. 命令码
2.1 自定义命令码
2.2 标准命令码
标准命令码(u32)
	30-31:数据的控制方向(2bit get/set)
	16-29:数据的大小(14bit)
	8-15:设备类型(8bit)
	0-7:cmd(命令码)(区分命名的顺序序号)
2.2.1 合成标准命令码的宏函数
 #define _IOC(dir,type,nr,size) \
	(((dir)  << _IOC_DIRSHIFT) | \  方向(左移30位)
	((type) << _IOC_TYPESHIFT) | \  设备类型(左移8位)
	((nr)   << _IOC_NRSHIFT) | \    命令码(低8位)
	((size) << _IOC_SIZESHIFT))     数据大小(左移16位)
不同类型的标准命令码合成宏函数
	#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
    #define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),sizeof(size))
    #define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
    #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
3. 测试ioctl

环境 ubuntu 20.04

思路:在test.c中调用ioctl函数发送cmd,在驱动模块中让对应的cmd打印不同的信息

#####ioctl.c

  1 #include <linux/module.h>           //模块驱动的头文件
  2 #include <linux/cdev.h>             //设备信息描述的头文件
  3 #include <linux/fs.h>               //静态申请设备号头文件
  4 #include <linux/kdev_t.h>           //设备号用到的头文件和宏函数
  5 #include <linux/uaccess.h>
  6 #include <linux/device.h>
  7 #include "common.h"
  8 
  9 #define BUF_SIZE 100
 10 
 11 int major = 0;                      //主设备号
 12 int min = 0;                        //次设备号
 13 int deviceNum = 0;                  //完整设备号
 14 struct cdev* pCdev = NULL;          //描述设备信息的结构体
 15 char *deviceName = "ioctl";//设备名
 16 char buff[BUF_SIZE] = "chrdev-test-2022-7-12";
 17 struct class *pClass = NULL;        //设备文件类指针
 18 int devNum = 2;                     //设备文件数量
 19 
 20 int testOpen(struct inode *pNode,struct file *pFile)
 21 {
 22         printk("------into test open------\n");
 23         printk("------leave test open------\n");
 24         return 0;
 25 }
 26 int testClose(struct inode *pNode,struct file *pFile)
 27 {
 28         printk("------into test close------\n");
 29         printk("------leave test close------\n");
 30         return 0;
 31 }
 32 ssize_t testRead(struct file *pFile,char __user *buf,size_t count,loff_t *pOffset)
 33 {
 34         int res = -1;
 35         printk("------into testRead------\n");
 36         if(count > BUF_SIZE-1)
 37         {
 38                 count = BUF_SIZE - 1;
 39         }
 40         res = copy_to_user(buf,buff,count);
 41         if(res)
 42         {
 43                 printk("copy_to_user error\n");
 44                 return -EFAULT;
 45         }
 46         printk("copy_to_user ok\n");
 47         printk("\t buff = %s\t\n",buff);
 48         printk("------leave testRead------\n");
 49         return count;
 50 }
 51 
 52 ssize_t testWrite(struct file *pFile,const char __user *buf,size_t count,loff_t *pOffset)
 53 {
 54         int res = -1;
 55         printk("------into testWrite------\n");
 56         if(count > BUF_SIZE-1)
 57         {
 58                 count = BUF_SIZE - 1;
 59         }
 60         res = copy_from_user(buff,buf,count);
 61         if(res)
 62         {
 63                 printk("copy_from_user error\n");
 64                 return -EFAULT;
 65         }
 66         printk("copy_from_user ok\n");
 67         printk("\t buff = %s\t\n",buff);
 68         printk("------leave testWrite------\n");
 69         return count;
 70 }
 71 
 72 long testIoctl(struct file *pFile,unsigned int cmd,unsigned long arg)
 73 {
 74         switch(cmd)
 75         {
 76                 case TEST_CMD:
 77                         {
 78                                 printk("test cmd-------arg = %ld \n",arg);
 79                         }
 80                         break;
 81                 case TEST_CMD1:
 82                         {
 83                                 printk("test cmd1-------arg = %ld \n",arg);
 84                         }
 85                         break;
 86                 case TEST_CMD2:
 87                         {
 88                                 printk("test cmd2-------arg = %ld \n",arg);
 89                         }
 90                         break;
 91                 default:
 92                         printk("error cmd \n");
 93         }
 94         return 0;
 95 }
 96 
 97 struct file_operations fp_arr =
 98 {
 99         .owner = THIS_MODULE,
100         .open = testOpen,
101         .read = testRead,
102         .write = testWrite,
103         .release = testClose,
104         .unlocked_ioctl = testIoctl
105 };
106 
107 int driverr_init(void)               //模块初始化函数
108 {
109         int res = 0;
110         int i = 0;
111         struct device *pDevTmp = NULL;
112         printk("*********into driver init\n");
113         //动态申请设备号
114         res = alloc_chrdev_region(&deviceNum,min,devNum,deviceName);
115         if(res)
116         {
117                 printk("alloc_chrdev_region error\n");
118                 return res;
119         }
120         printk("alloc_chrdev_region OK!\n");
121         printk("major = %d minor = %d \n",MAJOR(deviceNum),MINOR(deviceNum));
122         major = MAJOR(deviceNum);
123         //创建设备
124         pCdev = cdev_alloc();
125         if(NULL == pCdev)
126         {
127                 printk("cdev_alloc error\n");
128                 unregister_chrdev_region(deviceNum,devNum);
129                 return -1;
130         }
131         printk("cdev_alloc ok\n");
132         //设备初始化
133         cdev_init(pCdev,&fp_arr);
134         printk("cdev_init ok\n");
135         //设备与设备号关联
136         res = cdev_add(pCdev,deviceNum,devNum);
137         if(res)
138         {
139                 printk("cdev_add error\n");
140                 cdev_del(pCdev);
141         }
142         printk("cdev_add ok\n");
143         //创建设备文件类
144         pClass = class_create(THIS_MODULE,"ioctl");
145         if(NULL == pClass)
146         {
147                 printk("class_create error\n");
148                 cdev_del(pCdev);
149         }
150         printk("class_create ok\n");
151         //创建设备文件
152         for(;i < devNum;i++)
153         {
154                 pDevTmp = device_create(pClass,NULL,MKDEV(major,i),NULL,"ioctl%d",i);
155                 if(IS_ERR(pDevTmp))
156                 {
157                         printk("device_create error\n");
158                         for(i = 0;i < devNum;i++)
159                         {
160                                 device_destroy(pClass,MKDEV(major,i));
161                         }
162                         class_destroy(pClass);
163                         return -2;
164                 }
165         }
166         printk("device_create ok\n");
167         printk("*********leave driver init\n");
168         return 0;
169 }
170 
171 void driver_clear(void)             //模块清除函数
172 {
173         int i = 0;
174         printk("*********into driver clear\n");
175         for(;i < devNum; i++)
176         {
177                 device_destroy(pClass,MKDEV(major,i));
178         }
179         class_destroy(pClass);
180         cdev_del(pCdev);
181         unregister_chrdev_region(deviceNum,devNum);
182         printk("*********leave driver clear\n");
183 }
184 
185 module_init(driverr_init);           //模块加载函数
186 module_exit(driver_clear);          //模块卸载函数
187 
188 
189 MODULE_LICENSE("GPL");
190 MODULE_AUTHOR("cfy");
191 MODULE_ALIAS("liangzai");
192 MODULE_DESCRIPTION("2022-7-12");

  #####test.c
  
  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <unistd.h>
  6 #include <string.h>
  7 #include <sys/ioctl.h>
  8 #include "common.h"
  9 #define BUF_SIZE 100
 10 
 11 int main()
 12 {
 13         int fd = open("/dev/ioctl0",O_RDWR);
 14         if(fd < 0)
 15         {
 16                 printf("open ioctl0 err\n");
 17                 return -1;
 18         }
 19         printf("open ioctl0 ok\n");
 20 
 21         ioctl(fd,TEST_CMD);
 22         ioctl(fd,TEST_CMD1,123456);
 23         ioctl(fd,TEST_CMD2);
 24 
 25         close(fd);
 26         return 0;
 27 
 28 
 29 }

编译、查看设备文件、查看内核打印

在这里插入图片描述

添加设备文件权限

sudo chmod 777 /dev/ioctl0 /dev/ioctl1

执行测试程序,查看内核打印信息

在这里插入图片描述

可以看到第一次的cmd没有传参,arg为0;第二次传参了为123456;第三次未传参arg被第二次的赋值为123456,验证完毕。

接下来是驱动互斥

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

驱动学习(六)ioctl 的相关文章

随机推荐

  • 2023高教社杯 国赛数学建模C题思路 - 蔬菜类商品的自动定价与补货决策

    1 赛题 在生鲜商超中 一般蔬菜类商品的保鲜期都比较短 且品相随销售时间的增加而变差 大部分品种如当日未售出 隔日就无法再售 因此 商超通常会根据各商品的历史销售和需 求情况每天进行补货 由于商超销售的蔬菜品种众多 产地不尽相同 而蔬菜的进
  • Leetcode[数组] 买卖股票的最佳时机 -- 动态规划

    0 题目描述 leetcode原题链接 买卖股票的最佳时机 1 动态规划 假设给定的数组为 7 1 5 3 6 4 如果我们在图表上绘制给定数组中的数字 我们将会得到 我们来假设自己来购买股票 随着时间的推移 每天我们都可以选择出售股票与否
  • pycharm快速注释快捷键

    1 多行注释 用鼠标选中需要注释的代码 三次按下 shift 即可快速注释 2 单行注释 选中该行 按下 ctrl 即可单行注释
  • 【LeetCode】MySQL:数据库简单题(586 订单最多的客户)

    586 订单最多的客户 1 题目描述 2 具体实现 Write your MySQL query statement below 为下了最多订单的客户查找customer number 分组 排序 Limit select customer
  • 使用BiseNet从头训练&&微调自己的数据集

    一 代码链接 本次训练采用的是pytorch版本的BiseNet 代码链接为GitHub CoinCheung BiSeNet Add bisenetv2 My implementation of BiSeNet 二 数据格式 数据集分为原
  • Linux下安装Git

    文章目录 一 Git 安装 1 下载Git安装包 2 将Git安装包上传到服务器 3 解压Git安装包 4 安装Git所需依赖 5 编译与安装Git 6 设置环境变量 7 执行profile文件 使配置立即生效 一 Git 安装 如果觉得下
  • 笔记:几个基本数据结构——Ndarray、Series和Dataframe

    目录 一 Ndarray 1 创建 1 直接使用 np array创建 2 使用NumPy中函数 array func lt gt 2 索引 1 一维数组 array start end step 2 多维数组 3 基本操作 运算 操作 如
  • idea配置备份到GitHub

    目录 普通导入导出到本地 备份到GitHub 普通导入导出到本地 备份 File gt Export Settings 恢复 File gt Import Settings 2020版本 自定义Intellij idea配置和插件存放目录
  • CTP 穿透测试程序

    CTP穿透测试程序 修改配置文件后即可进行运行测试 方便简单 https download csdn net download someonemt5 11215587
  • redis开启过期监听

    java项目中 场景 订单没有付款到期取消订单 使用的是redis过期监听来做的 做个笔记 首先使用该功能需要下载2 8 0及以上的版本 这一部分详细内容可以访问redis官网 http redis io topics notificati
  • Rsync命令参数以及配置使用

    原文链接 参考原文笔记 https www cnblogs com koushuige p 9162920 html https www cnblogs com koushuige p 9162895 html https www cnbl
  • HttpRunner--自定义输出报告

    httprunner版本 2 5 4 jinja2版本 2 11 httprunner输出的html测试报告 默认的模板文件的路劲为 python安装路径 Lib site packages httprunner templates rep
  • 阻止冒泡(例:a标签上面绝对定位的文字标签【×】

    如何阻止冒泡 直接上图 js如下
  • python+selenium+实战(6)

    web 自动化脚本生成方式 1 selenium IDE 直接录屏 录制完成生成脚本 缺点 容易产生很多错误 解决错误的时间成本太高 2 自己写 remote复用已有浏览器 相当于开启浏览器调试模式 1 配置复用浏览器 注意要关闭浏览器 包
  • 浏览器的渲染原理简介

    http cloudbbs org forum php mod viewthread tid 16940 浏览器的渲染原理简介 复制链接 遇见sharon 超级版主 串个门 加好友 打招呼 发消息 电梯直达 楼主 发表于 昨天 15 48
  • RT1010 PWM 组成配置和 PWMX 的使用

    1 前言 本篇博文将着眼于 i MX RT1010 内部的 eFlexPWM 介绍其各个功能模块 以及 PWM 产生的原理 2 功能模块组成 以下是 RT1010 内部 PWM 的一个 Submoudle 的组成框图 从框图中我们可以看到
  • 操作系统——分页和分段

    连续分配方式会产生很多 碎片 而紧凑方式会将碎片合成可以使用的较大空间 但是代价比较大 所以产生了散列式存储 主要有一下三种方式 目录 分页 分段 段页式 分页和分段的区别 分页 分页式存储管理 将用户程序的地址空间分成若干个固定大小的区域
  • 【代码随想录】——回溯算法理论基础

    回溯是递归的副产品 只要有递归就会有回溯 虽然回溯法很难 很不好理解 但是回溯法并不是什么高效的算法 因为回溯的本质是穷举 穷举所有可能 然后选出我们想要的答案 如果想让回溯法高效一些 可以加一些剪枝的操作 但也改不了回溯法就是穷举的本质
  • AbstractExecutorService 抽象类

    java util concurrent AbstractExecutorService 是 Java 并发编程中的一个抽象类 它定义了 ExecutorService 接口的基本行为 ExecutorService 是一个接口 它提供了一
  • 驱动学习(六)ioctl

    驱动学习 六 ioctl 文章目录 驱动学习 六 ioctl 1 ioctl 2 命令码 2 1 自定义命令码 2 2 标准命令码 2 2 1 合成标准命令码的宏函数 3 测试ioctl linux内核给用户提供了两类系统调用函数 一类是数