字符设备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,是应用层传递下来的命令;

5、Documentation/ioctl/ioctl-number.txt

Code  	Seq#(hex)	Include File		Comments
========================================================
······
'i'		80-8F		linux/i8k.h
'j'		00-3F		linux/joystick.h
'k'		00-0F		linux/spi/spidev.h	conflict!
'k'		00-05		video/kyro.h		conflict!
······

ioctl-number.txt文件记录了内核中已经使用的ioctl命令,我们在构建自己的ioctl命令时尽量不要和内核已经使用的命令冲突;
(1)Code:命令中的设备类型字段;
(2)Seq:命令中的序列号字段;
(3)Include File:这些命令被哪个文件占用;
(4)Comments:命令的说明,比如conflict就说明这个命令和其他的文件的定义冲突了;
补充:不同文件中ioctl命令定义冲突并不影响功能,只要在你的驱动程序中命令是唯一的即可(内核自己都有冲突的),但是不建议这么做,尽量不要冲突;

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值