【Linux系列】Linux设备驱动之Ioctl控制

DATE: 2019.9.14


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设备驱动之Ioctl控制_第1张图片
通过上图我们可以知道,如果想访问底层设备,就必须打开对应的设备文件。也就是在这个打开的过程中,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 

#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!

你可能感兴趣的:(【Linux系列】Linux设备驱动之Ioctl控制)