ioctl 函数详解

ioctl 是 Linux 系统中用于设备控制的函数,它允许用户空间程序对设备进行特殊操作。ioctl 不属于传统的读写操作,而是用于配置设备参数或执行特定操作。在驱动程序开发中,ioctl 用于处理那些不适合归类到 read 或 write 的设备控制任务。本文深入讲解 ioctl 的使用,包括用户空间和驱动程序的实现,并通过实例分析了如何定义命令、驱动程序的实现以及用户空间的测试。
摘要由CSDN通过智能技术生成

概述

类 UNIX 操作系统将所有设备都看成文件

每个设备都对应一个文件,在内核中也有一个相应的索引结点

对文件操作的系统调用也适用于对设备文件的操作,例如 open()

设备文件逻辑空间是一个线性空间

ioctl是iocontrol的缩写,就是IO控制。ioctl 是设备驱动程序中对设备的 I/O 通道进行管理的函数,简言之就是对设备的一些特性进行管理,例如传感器的数据采集、串口波特率等等。

适用范围

行为上

简单来说,如果你在写驱动程序时候,碰到一些IO操作,在逻辑上不能归类到read,不能归类到write,那就可以认为是ioctl的部分。

read和write应该是写入和读出数据的,应该是作为单纯的数据交换的方式来处理。而ioctl则是控制read和write一些选项的。

比如:你做了一个通用的读写IO端口的驱动模块。read和write是从端口读写数据的,但是更改读写的端口,这个操作应该如何处理呢?显然用ioctl来实现比较合理。

比如你的read和write是可以阻塞的,或者不能阻塞的,或者对设备文件的读写是可以并发的,或者是不可以并发的,这些都可以写成可以用ioctl来配置的情况。后面为了可以用ioctl来实现模块不同的IO特点。

参数上

ioctl的一般参数格式就是命令字(常量)+命令参数的方式。

read和write的参数格式都是数据缓冲区+数据目的地指针+长度。

ioctl的必要性

如果不用ioctl的话,也可以实现对设备I/O通道的控制。例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数据流通过,如果有的话,那么后面就跟着控制命令(一般在socket编程中常常这样做)。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员自己也会头昏眼花的。所以,我们就使用ioctl来实现控制的功能。

如何实现ioctl

本文将以驱动开发为侧重点,从用户空间到内核空间纵向分析 ioctl 函数。
在这里插入图片描述

用户空间 ioctl

用户程序只需要通过命令码告诉驱动程序,需要做什么,具体的命令解释以及方法实现,是驱动程序要做的事情。ioctl 函数在用户态中定义如下

#include<sys/ioctl.h>
int ioctl(int fd, int cmd, ...);	// 成功返回0;失败返回-1

fd:文件描述符

cmd:用户程序对设备的控制命令(用命令码表示)

可变参数:依赖于 cmd 命令。cmd 参数由一些宏根据设备类型、序列号、传输方向等生成,通过系统调用传递到内核中的驱动程序

ioctl() 函数执行成功时返回 0,失败则返回 -1 并设置全局变量 errorno 值,如下:

EBADF d is not a valid descriptor.

EFAULT argp references an inaccessible memory area.

EINVAL Request or argp is not valid.

ENOTTY d is not associated with a character special device.

ENOTTY The specified request does not apply to the kind of object that
the descriptor d references.

因此,在用户空间使用 ioctl 时,可以做如下的出错判断以及处理:

int ret;
ret = ioctl(fd, MYCMD);
if (ret == -1) {
  printf("ioctl: %s\n", strerror(errno));
}

在实际应用中,ioctl 最常见的 errorno 值为 ENOTTY(error not a typewriter),顾名思义,即第一个参数 fd 指向的不是一个字符设备,不支持 ioctl 操作,这时候应该检查前面的 open 函数是否出错或者设备路径是否正确

驱动程序 ioctl

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

unlocked_ioctl,顾名思义,应该在无大内核锁(BKL&#x

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ioctl函数是Linux系统中用于设备控制的函数,它可以用来向设备发送控制命令,或者获取设备状态信息等。 ioctl函数的原型如下: ```c int ioctl(int fd, unsigned long request, ...); ``` 其中,fd表示设备文件描述符,request表示设备控制命令,后面的可变参数用于传递控制命令的参数。 request参数一般是一个32位的整数,由四个部分组成: ```c ioctl命令 = (魔数 << 8) | 命令序号 | 方向 | 大小 ``` 其中,魔数是一个16位的数,用于标识该ioctl命令所属的设备类型;命令序号是一个8位的数,用于标识该ioctl命令的具体含义;方向用于表示该ioctl命令是读操作还是写操作;大小用于表示该ioctl命令的参数大小。 例如,下面是一个ioctl命令: ```c #define MY_IOCTL _IOW('k', 1, int) ``` 其中,'k'是魔数,1是命令序号,_IOW表示该ioctl命令是写操作,int表示该ioctl命令参数的大小。 在应用程序中调用ioctl函数时,需要传入一个指向控制命令参数的指针,如下: ```c int val = 10; ioctl(fd, MY_IOCTL, &val); ``` 在设备驱动中,可以通过switch语句来处理ioctl命令,如下: ```c long my_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int val; switch (cmd) { case MY_IOCTL: if (copy_from_user(&val, (int __user *)arg, sizeof(val))) return -EFAULT; // 处理MY_IOCTL命令 break; // 处理其他命令 default: return -ENOTTY; } return 0; } ``` 其中,copy_from_user函数用于将用户空间中的数据拷贝到内核空间,sizeof(val)表示拷贝的数据大小。处理完命令后,需要返回0代表成功,或者返回一个负数代表错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值