字符设备ioctl接口详解
Posted 正在起飞的蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符设备ioctl接口详解相关的知识,希望对你有一定的参考价值。
1、为什么要引入ioctl接口?
(1)读写操作只是很基础的功能,有的设备需要支持另外的命令去控制;比如串口需要提供设置波特率、数据位、终止位等操作;
(2)如果不同的命令操作,都在write和read中去做判断,对于支持命令比较多的设备,那write和read函数就会很大,不利于维护;
(3)ioctl函数是专门用来处理上层发给驱动程序的命令,设备有需要就去实现,如果没有需要就不实现这个函数,将函数指针赋值为NULL;
2、应用层系统调用
#include <sys/ioctl.h>
/*
* fd:打开设备文件时得到的文件描述符
* cmd:给驱动层传递的命令,这个命令会事先规定号;
* "···":这是C语言的可变参数
*/
int ioctl(int fd, int cmd, ...);
(1)在linux系统中用man手册可以查询到ioctl函数原型: man 2 ioctl;
3、驱动层实现ioctl函数接口
struct file_operations
······
/*
*file:对应ioctl函数的fd文件描述符
*cmd:对应ioctl函数的cmd命令
*data:对应ioctl函数的可变参数,可以没有值,也可以是指针或者整数值等
*/
long (*unlocked_ioctl) (struct file * file, unsigned int cmd, unsigned long data);
······
应用层调用的ioctl函数对应到驱动层的unlocked_ioctl函数指针;
4、ioctl函数的命令介绍
4.1、命令的格式组成
(1)设备类型:类型或者叫幻数,表示这是一类设备,可以用一个字符或者8bit表示;
(2)序列号:表示这是设备的第几个命令;
(3)方向:读写方向,这是从应用层的角度来说的,比如"读"表示应用层从设备驱动读数据;
(4)数据尺寸:有的命令是带数据的,这里表明数据的长度;
4.2、命令的构造
//传输方向
#define _IOC_NONE 0U //无数据传输
#define _IOC_WRITE 1U //向驱动中写数据
#define _IOC_READ 2U //从驱动中读数据
_IOC_READ | _IOC_WRITE //双向传送
/*
*type:设备类型
*nr:序列号
*size:这里传数据的格式,宏定义会自动去计算数据的长度
*/
//没有数据传递的命令
#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)))
(1)构建命令都是用上面的宏,具体每个字段占多少位其实我们不管关心;
(2)(注意在上面的宏定义中size是传数据的格式,宏定义会自动去计算数据的长度
4.3、检查命令和地址的合法性
/* used to decode ioctl numbers.. */
//从命令中解析出传输方向
#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)
(1)在驱动的unlocked_ioctl函数实现中,需要对应用层下发的命令进行检查,避免因为应用层发生错误的命令导致程序出问题;
(2)上面宏定义里的nr,是应用层传递下来的命令;
以上是关于字符设备ioctl接口详解的主要内容,如果未能解决你的问题,请参考以下文章