Linux设备驱动之Ioctl控制

  1. 1、参考
  2. 2、Linux设备驱动模型
  3. 3、Linux设备驱动之Ioctl控制
    1. 3.1 用户空间调用ioctl控制设备
    2. 3.2 驱动ioctl方法
    3. 3.3 用户态调用ioctl实例分析

1、参考

linux设备驱动框架
ioctl系统调用流程
Linux设备驱动之Ioctl控制
使用ioctl“实现”自定义的系统调用
ioctl()分析——从用户空间到设备驱动

2、Linux设备驱动模型

(1) 在Linux文件系统中,每个文件都用一个struct inode结构体来描述,这个结构体记录了这个文件的所有信息,例如文件类型,访问权限等。

(2) 在linux操作系统中,每个驱动程序在应用层的/dev目录或者其他如/sys目录下都会有一个文件与之对应。

(3) 在linux操作系统中, 每个驱动程序都有一个设备号。

(4) 在linux操作系统中,每打开一次文件,Linux操作系统会在VFS层分配一个struct file结构体来描述打开的文件。
Linux设备驱动模型

通过上图我们可以知道,如果想访问底层设备,就必须打开对应的设备文件。也就是在这个打开的过程中,Linux内核将应用层和对应的驱动程序关联起来。

(1) 当open函数打开设备文件时,可以根据设备文件对应的struct inode结构体描述的信息,可以知道接下来要操作的设备类型(字符设备还是块设备),还会分配一个struct file结构体。

(2) 根据struct inode结构体里面记录的设备号,可以找到对应的驱动程序。这里以字符设备为例。在Linux操作系统中每个字符设备都有一个struct cdev结构体。此结构体描述了字符设备所有信息,其中最重要的一项就是字符设备的操作函数接口。

(3) 找到struct cdev结构体后,linux内核就会将struct cdev结构体所在的内存空间首地址记录在struct inode结构体i_cdev成员中,将struct cdev结构体中的记录的函数操作接口地址记录在struct file结构体的f_ops成员中。

(4) 任务完成,VFS层会给应用返回一个文件描述符(fd)。这个fd是和struct file结构体对应的。接下来上层应用程序就可以通过fd找到struct file,然后在有struct file找到操作字符设备的函数接口了。

3、Linux设备驱动之Ioctl控制

 大部分驱动除了需要具备读写设备的能力之外,还需要具备对硬件控制的能力。

3.1 用户空间调用ioctl控制设备

int ioctl(int fd,unsigned long cmd,...);
/*fd:文件描述符
cmd:控制命令.
..:可选参数:*argp,具体内容依赖于cmd*/

ioctl函数是用户态控制设备的接口。

这里只是将command下发给驱动程序去完成相应的动作或操作。

3.2 驱动ioctl方法

int (*ioctl) (struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg);

/*inode与filp两个指针对应于应用程序传递的文件描述符fd,这和传递open方法的参数一样。cmd: 由用户空间直接不经修改的传递给驱动程序
arg: 可选。*/

3.3 用户态调用ioctl实例分析

#include <sys/ioctl.h>

#define IAVENCIOC_MAGIC                'V'
#define IAVENC_IOW(nr, size)        _IOW(IAVENCIOC_MAGIC, nr, size)
IOC_START_ENCODE        = 0x12, /*!< 0x12 */
#define IAV_IOC_START_ENCODE                IAVENC_IOW(IOC_START_ENCODE, u32)

#ifndef AM_IOCTL
#define AM_IOCTL(_filp, _cmd, _arg)    \
        do {                         \
            if (ioctl(_filp, _cmd, _arg) < 0) {    \
                perror(#_cmd);        \
                return -1;            \
            }                        \
        } while (0)
#endif

static int start_encode(u32 stream_map)
{
    struct iav_queryinfo query_info;
    struct iav_stream_info *stream_info;
    int i;

    for (i = 0; i < MAX_ENCODE_STREAM_NUM; i++) {
        if (stream_map & (1 << i)) {
            memset(&query_info, 0, sizeof(query_info));
            query_info.qid = IAV_INFO_STREAM;
            stream_info = &query_info.arg.stream;
            stream_info->id = i;
            AM_IOCTL(fd_iav, IAV_IOC_QUERY_INFO, &query_info);
            if (stream_info->state == IAV_STREAM_STATE_ENCODING) {
                stream_map &= ~(1 << i);
            }
        }
    }
    if (stream_map == 0) {
        printf("already in encoding, nothing to do \n");
        return 0;
    }

    AM_IOCTL(fd_iav, IAV_IOC_START_ENCODE, stream_map);

    printf("Start encoding for stream 0x%x successfully\n", stream_map);
    return 0;
}

THE END!


本博文只能阅读,谢绝转载,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2963033731@qq.com

文章标题:Linux设备驱动之Ioctl控制

字数:982

本文作者:Soaring Lee

发布时间:2019-09-14, 15:13:47

最后更新:2021-08-13, 23:02:32

原始链接:https://soaringleefighting.github.io/2019/09/14/【Linux系列】Linux设备驱动之Ioctl控制/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

×

喜欢就点赞,疼爱就打赏

相册