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内核将应用层和对应的驱动程序关联起来。
(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