linux的ioctl的驱动和应用的用法

**

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
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 typewriter

3)ioctl交互协议request与第三个参数的定义也有关系。要注意如果用户态是32位,内核态是64位系统。那么第三个参数的变量长度需要在两个系统中保持一样的长度。否则交互协议会出错。

应用部分的用法

基本用法:

#include 

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的数据写也是一样的,这边就不再复述。

如有疑问可留言交流。

你可能感兴趣的:(linux,驱动开发,c语言)