**
linux的ioctl的驱动和应用的用法
**
很多时候,linux驱动编写一般只要有read和write函数就行,但有些驱动需要同时读写,并且还能控制参数,那么如果采用ioctl将是比较好的解决方案。
使用ioctl是极其自由的,只要学会驱动和应用的用法即可。
关于ioctl的cmd定义
在驱动程序中,ioctl()函数上传送的变量cmd是应用程序用于区别设备驱动程序请求处理内容的值,cmd除了可区别数字外,还包含有助于处理的几种相应信息。cmd的大小为32位,共分为4个域
bit31 ~ bit30 2位为“区别读写”区,作用是区分是读取命令还是写入命令
bit29 ~ bit15 14位为 “数据大小” 区,表示 ioctl() 中的 arg 变量传送的内存大小。
bit20 ~ bit08 8位为 “魔数"(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。
bit07 ~ bit00 8位为 “区别序号” 区,是区分命令的命令顺序序号。
cmd的宏定义以及示例代码(宏定义可以方便直接填充数据)
在asm-generic/ioctl.h中还有如下宏定义
//构造无参数的命令编号
#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)))
举例:
#define CLOSE_CMD _IO(0xab,1)
#define OPEN_CMD _IO(0xab,2)
#define WRDATA_CMD _IOW(0xab,4,int) //设置数据
static long your_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
struct your_dev_t *dev = (struct your_dev_t*)filp->private_data;//私有数据地址传递
switch(cmd)
{
case CLOSE_CMD:
{
//add your code...
}
break;
case OPEN_CMD:
{
//add your code...
}
break;
case WRDATA_CMD:
{
//add your code...
}
break;
}
return 0;
}
//fops函数回调
static struct file_operations your_fops = {
.owner = THIS_MODULE,
.open = your_open,
.read = your_read,
.write = your_write,
...
.unlocked_ioctl = your_ioctl,
.release = your_release,
};
函数原型以及说明:
头文件:#include <linux/ioctl.h>
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
1)unlocked_ioctl,顾名思义,应该在无大内核锁(BKL)的情况下调用;如果是64位的用户程序运行在64位的kernel上,调用的是unlocked_ioctl,如果是32位的用户程序运行在32位的kernel上,调用的也是unlocked_ioctl
2)compat_ioctl,,主要目的是为 64 位系统提供 32 位 ioctl
的兼容方法,也是在无大内核锁的情况下调用。当有32bit的userspace application call 64bit
kernel的ioctl的时候,这个callback会被调用到。如果没有实现compat_ioctl,那么32位的用户程序在64位的kernel上执行ioctl时会返回错误:Not
a typewriter3)ioctl交互协议request与第三个参数的定义也有关系。要注意如果用户态是32位,内核态是64位系统。那么第三个参数的变量长度需要在两个系统中保持一样的长度。否则交互协议会出错。
应用部分的用法
基本用法:
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
下面例程是ioctl的数据读取:
/* 定义魔幻数 */
#define YOUR_MAGIC 0xab
#define YOUR_CMD_READ _IOR(RDA5807M_MAGIC , 1, sizeof(your_data_opt))
...
//your_data_opt这是你的数据地址,可以是结构体,也可以是数组;但长度必须和驱动那边写的一致
your_data_opt your_opt;
memset(&devx, 0, sizeof(your_data_opt ));
//your_fd就是你要打开的驱动,调用open后得到。
//最终数据会读到your_opt数据。
int err = ioctl(your_fd,YOUR_CMD_READ,&your_opt);
if(err < 0)
{
printf("打印你错误信息...");
return -1;
}
最后
ioctl的数据写也是一样的,这边就不再复述。
如有疑问可留言交流。