【Linux驱动层】iTOP-RK3568学习之路(七):IOCTAL

记住API,不要管API内部实现。以前我一直疑惑怎么关于cmd,怎么网上说的不一样,应该是随着Linux内核版本更新,实现不一样了,但接口还一样。

一、应用层

c 复制代码
int ioctl(int fd, unsigned int cmd, unsigned long args);

参数含义:

fd :是用户程序打开设备时返回的文件描述符

cmd :是用户程序对设备的控制命令,

args:应用程序向驱动程序下发的参数,如果传递的参数为指针类型,则可以接收驱动向用户空间传递的数据

定义一个命令,但是不需要参数:

c 复制代码
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)

定义一个命令,应用程序从驱动程序读参数:

c 复制代码
#define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))

定义一个命令,应用程序向驱动程序写参数:

c 复制代码
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

定义一个命令,参数是双向传递的:

c 复制代码
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

type:命令的类型,一般为一个 ASCII 码值,一个驱动程序一般使用一个 type

nr:该命令下序号。一个驱动有多个命令,一般他们的 type,序号不同

size:args 的类型

c 复制代码
#define CMD_TEST0 _IO('L',0)

#define CMD_TEST1 _IOW('L',1,int)

#define CMD_TEST2 _IOR('L',2,int)

实例代码:

c 复制代码
#define CMD_TEST0 _IO('L', 0)
#define CMD_TEST1 _IOW('L', 1, int)
#define CMD_TEST2 _IOR('L', 2, int)

int main(int argc, char *argv[])
{
    int fd;                         // 定义 int 类型的文件描述符 fd
    int val;                        // 定义 int 类型的传递参数 val
    fd = open("/dev/test", O_RDWR); // 打开 test 设备节点
    if (fd < 0)
    {
        printf("file open fail\n");
    }
    if (!strcmp(argv[1], "write"))
    {
        ioctl(fd, CMD_TEST1, 1); // 如果第二个参数为 write,向内核空间写入 1
    }
    else if (!strcmp(argv[1], "read"))
    {
        ioctl(fd, CMD_TEST2, &val); // 如果第二个参数为 read,则读取内核空间传递向用户空间传递的值
        printf("val is %d\n", val);
    }
    close(fd);
}

二、驱动层

c 复制代码
long (*unlocked_ioctl) (struct file *file , unsigned int cmd, unsigned long arg);

file:文件描述符。

cmd:与应用程序的 cmd 参数对应,在驱动程序中对传递来的 cmd 参数进行判断从而做出不同的动作。

arg:与应用程序的 arg 参数对应,从而实现内核空间和用户空间参数的传递。

实例代码:

c 复制代码
static long cdev_test_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int val; // 定义 int 类型向应用空间传递的变量 val
    switch (cmd)
    {
    case CMD_TEST0:
        printk("this is CMD_TEST0\n");
        break;
    case CMD_TEST1:
        printk("this is CMD_TEST1\n");
        printk("arg is %ld\n", arg); // 打印应用空间传递来的 arg 参数
        break;
    case CMD_TEST2:
        val = 1; // 将要传递的变量 val 赋值为 1
        printk("this is CMD_TEST2\n");
        if (copy_to_user((int *)arg, &val, sizeof(val)) != 0)
        { // 通过 copy_to_user 向用户空间传递数据
            printk("copy_to_user error \n");
        }
        break;
    default:
        break;
    }
    return 0;
}
相关推荐
CoovallyAIHub20 小时前
中科大DSAI Lab团队多篇论文入选ICCV 2025,推动三维视觉与泛化感知技术突破
深度学习·算法·计算机视觉
NAGNIP21 小时前
Serverless 架构下的大模型框架落地实践
算法·架构
moonlifesudo21 小时前
半开区间和开区间的两个二分模版
算法
moonlifesudo21 小时前
300:最长递增子序列
算法
CoovallyAIHub1 天前
港大&字节重磅发布DanceGRPO:突破视觉生成RLHF瓶颈,多项任务性能提升超180%!
深度学习·算法·计算机视觉
用户31187945592181 天前
Kylin Linux 10 安装 glib2-devel-2.62.5-7.ky10.x86_64.rpm 方法(附安装包)
linux
CoovallyAIHub1 天前
英伟达ViPE重磅发布!解决3D感知难题,SLAM+深度学习完美融合(附带数据集下载地址)
深度学习·算法·计算机视觉
涛啊涛1 天前
Centos7非LVM根分区容量不足后扩容,对调硬盘挂载/
linux·磁盘管理
聚客AI2 天前
🙋‍♀️Transformer训练与推理全流程:从输入处理到输出生成
人工智能·算法·llm
大怪v2 天前
前端:人工智能?我也会啊!来个花活,😎😎😎“自动驾驶”整起!
前端·javascript·算法