Linux 标准ioctl接口

版本 颁布日期 修订章节
0.1 2015.08.17 撰写草稿
0.2 2015.12.11 整理内容
0.3 2016.03.06 整理文档,排序
1.0 2016.04.17 验证程序,正式发布

特征

输出输入的控制命令
一般是用来写非标准接口功能可以实现的功能,编写标准接口不能实现的功能。

例:一个eeprom驱动,需要设置地址,这个功能来说,系统上调用的接口没有合适的函数,
像这样的功能就可以把它归为ioctl接口功能
所以ioctl接口可以看出是系统给我们进行功能扩展的专用接口。

应用程序接口ioctl原型

应用程序头文件

#include <sys/ioctl.h>

命令查看:man ioctl

int ioctl(int d, int request, …);

这个函数是一个可变参数函数,最少需要2个参数
参数:

d     	:文件描述符
request	:通常是cmd(命令)
…    	:可变参数(可以有,也可以没有,根据request情况而定)
例:
一个命令:所有灯全开,只需要一个全开等的命令,
一个命令:指定灯开,需要一个开灯命令,还需要指定那盏灯开的命令。

返回值:
成功:通常返回0,少数ioctl返回非负数,
自定义非标准cmd,返回用户自定义的一个正数(可以用这个函数实现lseek功能)
失败:返回负数,-1

驱动程序ioctl接口驱动原型:

使用ioctl没有头文件, 驱动程序头文件在文件操作方法中。

#include <linux/fs.h>

3.0以上内核
在文件操作集合file_operations中。

ioctl函数原型

long (*unlocked_ioctl) (struct file * pfile, unsigned int cmd, unsigned long arg);
2. 6内核是ioctl
参数:

pfile	:文件描述符VFS转换而来
cmd		:应用程序传递下来的request参数
arg		:对应于应用程序传递下来的第三个参数(变参)

ioctl的命令代码

实例代码:

long chrdev_unlocked_ioctl (struct file *pfile, unsigned int cmd, unsigned long arg)
{
   
	switch ( cmd ) {
   
	case 0 :
	  printk("line:%d,cmd:%d,arg:%ld",__LINE__,cmd,arg);
	  break;
	case 1 :
	  printk("line:%d,cmd:%d,arg:%ld",__LINE__,cmd,arg);
	  break;
	case 2 :
	  printk("line:%d,cmd:%d,arg:%ld",__LINE__,cmd,arg);
	  break;
	case 3 :
	  printk("line:%d,cmd:%d,arg:%ld",__LINE__,cmd,arg);
	  break;
	case 4 :               
	  printk("line:%d,cmd:%d,arg:%ld",__LINE__,cmd,arg);                   
	  break;
	default:            
	  printk("line:%d,cmd:%d,arg:%ld",__LINE__,cmd,arg);
	  return - EINVAL;
	}
	
	return arg;
}

应用程序代码:

for(i=0;i<6;i++) {
   
	int ret = ioctl(fd,i,10+i);      //args 从10开始,该参数现在无意义
	sleep(1);  	
	printf("\nret = %d\n",ret);	
}

结果显示,当cmd值为2时,程序没有执行
ioctl接口比较特殊,不是像其他接口通过fd直接找到驱动,接口的cmd值在内核中有规范,不是随便使用一个数字就可以,有特定的编码规则,当cmd值和系统一些预定义的命令相同时,代码所执行的不会是我们的驱动代码中的ioctl,而是被拦截了,去执行相同的预定义命令去了,
从2.6到现在,cmd为2这个命令的值都不能使用

ioctl命令在内核中定义

想要正确使用ioctl接口,必须使用内核规定的定义方法来使用。
从内核文档有说明:ioctl-decoding.txt

把cmd拆分成32位

31-30位

00 - no parameters: uses _IO macro 
当cmd值的30、31位为00时,应该不能带arg三个参数,否则[可能]和其他命令冲突。
函数形式为ioctl(fd,cmd)。
10 - read: _IOR 
表示读方向
代表想通过ioctl从驱动中读取数据回来,存放在 ioctl(fd,cmd,arg)中的argr所代表的内存空间中(arg应该是一个可写内存地址)。
01 - write: _IOW 
表示写方向。
代表想通过ioctl从向驱动中写入数据,数据存放在 ioctl(fd,cmd,arg)中的arg所指向内存空间中(arg应该是一个可读内存地址)。 
11 - read/write: _IOWR
表示双向,数据交换

29-16位

29-16	 size of arguments 
参数大小,16位,最多只能传递16K数据
当cmd 30、31不为零,调用方法ioctl(fd,cmd,arg)表示有数据传递。

Q:应该写多少个字符?
A:read,write有参数指明要读写几个字节。把要读写的数量存放在cmd的 29~16位中。

15- 8位

15-8	ascii character supposedly unique to each driver
驱动魔数,幻数,8位:范围0~255 0~FF。
用来标识一个驱动,原则上讲一个驱动有着唯一的值,只要这个值不同,就不会和其他命令冲突。
内核已经占用大部分的魔数,原则上可以由用户定义

7- 0位

7-0	function 
命令功能,8位:范围0~255
真正的命令码,像例子中的0,1,2,3,4,

内核文档指明那些命令被使用

内核文档:ioctl-number.txt
例:

Code  Seq#(hex)	Include File		Comments ========================================================
0x00	00-1F	  linux/fs.h		conflict! 
0x00	00-1F	  scsi/scsi_ioctl.h	conflict! 
0x00	00-1F	  linux/fb.h		conflict! 
0x00	00-1F	  linux/wavefront.h	conflict! 
0x02	all		  linux/fd.h 
0x03	all	 	  linux/hdreg.h 
0x04	D2-DC	  linux/umsdos_fs.h	Dead since 2.6.11, but don't reuse these. 
0x06	all	  	  linux/lp.h 
0x09	all	 	  linux/raid/md_u.h 
0x10	00-0F	  drivers/char/s390/vmcp.h 
0x12	all	 	  linux/fs.h

从表可以看出,
02冲突的几率很大
01,05,07,08比较安全

内核为用户定义的命令宏

注意:参数定义宏在应用程序和驱动两边都要定义,也可以将定义的命令宏放在一个头文件中,应用程序和驱动都将这个头文件包含在内。

参数定义宏

//定义一个没有参数的命令
#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)))

参数

参数:
type		:魔数,幻数
nr			:功能码(自己定义)
size		:参数大小,其实是应该传递参数类型(非指针)

例:两种定义方法,第

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值