Linux驱动之 字符设备 ioctl接口使用

本文详细介绍了Linux驱动开发中字符设备的ioctl接口使用,包括应用层和驱动层的ioctl函数,以及如何传递命令参数。示例展示了如何通过ioctl命令进行设备的读写操作,同时解释了各种错误情况及其含义。此外,还提到了访问用户空间内存的安全检查函数access_ok(),以及ioctl命令格式的定义和解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符设备ioctl接口使用:

Linux驱动编写除了对设备进行读写数据之外,通常还希望可以对设备进行控制。
从应用层传递一些命令参数,并在驱动层实现相应设备操作,这时候就用到了 ioctl函数:
应用层:

#include <sys/ioctl.h> 
/*
 * @description		:  应用层 ioctl
 * @param - fd		: 打开设备文件的时候获得文件描述符 
 * @param - request : 给驱动层传递的命令,需要注意的时候,驱动层的命令和应用层的命令一定要统一
 * @param - "..."	: 可变参数
 * @return 			: 0 成功; -1 失败,同时设置errno
 */	
int ioctl(int fd, unsigned long request, ...);

驱动层:

#include <linux/ioctl.h>   
/*
 * @description		: 驱动层 ioctl
 * @param - file *	: 为打开字符设备文件的进程创建的结构体,用于存放文件的动态信息 
 * @param - cmd		: 用户层传入的命令,根据不同的命令执行不一样的操作
 * @param - arg		: 用户层传入的可变参数
 * @return 			: 0 成功; 失败,返回带错误码的负值
 */
long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg)
long (*compat_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg)
//unlocked_ioctl,顾名思义,应该在无大内核锁(BKL)的情况下调用;
//compat_ioctl,compatible(兼容的),主要目的是为 64 位系统提供 32 位 ioctl 的兼容方法,同样也是在无大内核锁的情况下调用。

access_ok 函数:

/*
 * @description		: 检查用户空间中的内存地址是否可用
 * @param - type	: 检查的访问类型,可为 VERIFY_READ(可读) 或者 VERIFY_WRITE(可写),可写必可读。
 * @param - addr	: 用户空间的指针变量,其指向一个要检查的内存块开始处。
 * @param - size	: 检查的内存块大小
 * @return 			: 该内存地址可用,则返回真(非0值),否则返回 0
 */
access_ok (type, addr, size); 

ERRORS:

EBADF  fd is not a valid descriptor. //该fd文件描述符无效
EFAULT argp references an inaccessible memory area. //参数argp引用了一个不可访问的内存区域
EINVAL request or argp is not valid. //命令request或参数argp无效。
ENOTTY fd is not associated with a character special device. //描述符fd与字符特殊设备没有关联,设备类型不匹配
ENOTTY The specified request does not apply to the kind of object that the descriptor fd references.//指定的请求不适用于描述符fd引用的对象的类型。

传递的命令参数(request ) :
在linux中,提供了一种 ioctl 命令的统一格式,将 32 位 int 型数据划分为四个位段:
在这里插入图片描述
设备类型,type(device type),占据 8 bit,也叫做 “幻数” 或者 “魔数”,可以为任意 char 型字符,
例如’a’、‘b’、‘c’、‘k’ 等等,其作用是使 ioctl 命令有唯一的设备标识;
序列号,nr(number),占据 8 bit,可以为任意 unsigned char 型数据,取值范围 0~255,如果定义了多个 ioctl 命令,通常从 0 开始编号递增,代表这个设备的第几个命令;
方向,ioctl 命令访问模式(数据传输方向),dir(direction),占据 2 bit,可以为 _IOC_NONE、_IOC_READ、_IOC_WRITE、_IOC_READ | _IOC_WRITE,分别指示了四种访问模式:无数据、读数据、写数据、读写数据;
数据尺寸,size,涉及到 ioctl 函数 第三个参数 arg ,占据 8~14bit,指定 arg 的数据类型及长度,表示了需要读写的参数大小,如果在驱动的 ioctl 实现中不检查,通常可以忽略该参数;

ioctl_cmd.h

#ifndef __IOCTL_CMD_H__
#define __IOCTL_CMD_H__

/*  定义设备类型,任意 char 型字符 */
#define DEV_FIFO_TYPE 'k'
/*
*   访问模式:
*   _IOC_NONE   不带参数操作,值为 0
*   _IOC_READ   带读参数,读数据操作,值为 1
*   _IOC_WRITE  带写参数,写数据操作,值为 2
*   _IOC_READ|_IOC_WRITE 带读写参数,读写数据操作
*/
/*
*   宏
*   _IO:       定义 不带参数的 ioctl 命令 
*   _IOR:      定义带 读参数的ioctl命令    (copy_to_user)
*   _IOW:      定义带 写参数的 ioctl 命令  (copy_from_user)
*   _IOWR:     定义带 读写参数的 ioctl 命令
*/
/* 不带参数操作,常用于初始化 */
#define DEV_FIFO_CLEAN _IO(DEV_FIFO_TYPE,0)
/* 读操作 */
#define DEV_FIFO_GETVALUE _IOR(DEV_FIFO_TYPE,1,int)
/* 写操作 */
#define DEV_FIFO_SETVALUE _IOW(DEV_FIFO_TYPE,2,int)
/* 命令数 */
#define DEV_FIFO_MAXNR  3

#endif

app_cdev.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#include <sys/ioctl.h>
#include "ioctl_cmd.h"

int main()
{
   
	int fd;
	int ret;
	int num = 0;
	char *filename = "/dev/hello";

	/* 打开驱动文件 */
	fd = open(filename,O_RDWR);
	if(fd<0)
	{
   
		printf("Can't open file %s
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程一时爽Cxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值