字符设备驱动的ioctl函数

字符设备驱动的ioctl函数

用户空间的ioctl

#include <sys/ioctl.h>

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

//使用例子,framerbuffer技术获取屏幕属性
	ioctl(fd, FBIOGET_VSCREENINFO, &varInfo);
	

内核空间的ioctl

#include <asm/ioctl.c>

	int (*ioctl) (struct inode *, struct file *, unsigned int cmd, unsigned long argv);
	long (*unlocked_ioctl) (struct file *, unsigned int cmd, unsigned long argv);
	long (*compat_ioctl) (struct file *, unsigned int cmd, unsigned long argv);
/*
	inode file:文件描述符
	cmd:由用户空间直接不经修改的传递给驱动程序
	argv:可选参数:具体内容依赖于cmd
*/

用户空间的ioctl会调用内核空间的ioctl,内核空间中cmd有具体的含义。
img
图片转自知乎,侵删。
分为4个字段:数据方向,数据大小,设备类型,命令编号

  1. dir(direction),ioctl 命令访问模式(数据传输方向),占据 2 bit,可以为 _IOC_NONE、_IOC_READ、_IOC_WRITE、_IOC_READ | _IOC_WRITE,分别指示了四种访问模式:无数据、读数据、写数据、读写数据;
  2. size,涉及到 ioctl 函数 第三个参数 arg ,占据 13bit 或者 14bit(体系相关,arm 架构一般为 14 位),指定了 arg 的数据类型及长度,如果在驱动的 ioctl 实现中不检查,通常可以忽略该参数;
  3. type(device type),设备类型,占据 8 bit,在一些文献中翻译为 “幻数” 或者 “魔数”,可以为任意 char 型字符,例如‘a’、’b’、’c’ 等等,其主要作用是使 ioctl 命令有唯一的设备标识;
  4. nr(number),命令编号/序数,占据 8 bit,可以为任意 unsigned char 型数据,取值范围 0~255,如果定义了多个 ioctl 命令,通常从 0 开始编号递增;

在驱动编程中通常使用宏定义制造出这个32位的cmd或者反向解析

#include <asm/ioctl.h>

/* used to create numbers */
#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

/* used to decode them.. */    
#define _IOC_DIR(nr)            (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)    
#define _IOC_TYPE(nr)           (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)    
#define _IOC_NR(nr)             (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)                      
#define _IOC_SIZE(nr)           (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) 

内核空间示例代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/ioctl.h>

struct led_info {
	int age;
	char stat;
};

#define LED_ON _IOWR('l', 0, struct led_info)
#define LED_OFF _IOWR('l', 1, struct led_info)
#define GET_INFO _IOWR('l', 2, struct led_info)
#define PUT_INFO _IOWR('l', 3, struct led_info)
struct led_info info = {
	.age = 0,
	.stat = 0,
};

static long led_ioctl(struct file *file, unsigned int cmd, unsigned long argv)
{
	int ret = -1;
	switch (cmd) 
	{
		case LED_ON:
			led_on();
			break;
		case LED_OFF:
			led_off();
			break;
		case GET_INFO:
			ret = copy_to_user((struct led_info*)argv, &info, sizeof(info));
			break;
		case PUT_INFO:
			ret = copy_from_user(&info, (struct led_info*)argv, sizeof(info));
			printk("info.age = %d\n", info.age);
			break;

	}

	return 0;
}

用户空间示例代码:

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

struct led_info {
	int age;
	char stat;
};

#define LED_ON _IOWR('l', 0, struct led_info)
#define LED_OFF _IOWR('l', 1, struct led_info)
#define GET_INFO _IOWR('l', 2, struct led_info)
#define PUT_INFO _IOWR('l', 3, struct led_info)

int main(int argc, const char *argv[])
{
	char stat[4];
	struct led_info info;
	memset(&info, 0, sizeof(info));
	int fd = open("/dev/myled", O_RDWR);
	if (fd < 0)
	{
		perror("open led fail:");
		exit(-1);
	}
	ioctl(fd, GET_INFO, &info);
	printf("user info.age = %d\n", info.age);
	info.age = 100;
	ioctl(fd, PUT_INFO, &info);

	close(fd);
	return 0;
}

只是对ioctl内核态到用户态的数据传输的测试,实际工程中会对cmd的各个域进行判断。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值