linux 设备驱动之IOCTRL
1,where come from?
ioctrl(或者说unlocked_ioctl/compat_ioctl)是file_operations结构体的函数指针
struct file_operations {
...
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
...
};
2,who am i
在用户空间,ioctl是一个系统调用, 作用于一个文件描述符; 它接收一个确定要进行的
命令的数字和(可选地)另一个参数, 常常是一个指针.这些
命令可以内核空间和用户空间之间进行数据交互。这些命令可以从驱动拷贝相关的数据结构到用户空间。
3,所谓的命令(CMD)是什么?
在Kernel层,对于一个32bit的系统,分成了4个域,分段如下@include/uapi/asm-generic/ioctl.h
2bits(读写区)_IOC_DIRBITS |
14bits(数据大小区)_IOC_SIZEBITS |
8bits(Magic)_IOC_TYPEBITS |
8bits(命令序号)_IOC_NRBITS |
31 30/
29 28 ... 17 16/
15 14 ... 9 8/
7 6 ... 1 0
所谓的Magic区,无非就是不同驱动使用一个字母来标识。比如LDD3,
#define SCULL_IOC_MAGIC '
k'
#define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int)
4,为什么不使用“粗暴”的,一个unsigned int值来代替一个cmd?
我认为,使用一个32bit的不同位来表示一个cmd,能包含更多的信息,节省了内存
5,如何使用?
5.1,在应用层和Kernel使用同一个CMD定义的h文件,来使用cmd
在应用层:#define REMOTE_IOC_SET_REPEAT_KEY_MAPPING _IOW_BAD(
'I',20,sizeof(short))
在Kernel层:#define REMOTE_IOC_SET_REPEAT_KEY_MAPPING _IOW_BAD(
'I',20,sizeof(short))
5.2,
在应用层调用这个命令,device_fd为对应的设备文件
val = (i<<16) | repeat_key_map[i];
ioctl(device_fd, REMOTE_IOC_SET_REPEAT_KEY_MAPPING, &
val);
在Kernel层,将会做相应的处理
先把&val传进来的值copy_from_user,然后使用这个val值
static long remote_config_ioctl(struct file *filp, unsigned int
cmd, unsigned long
args)
{
void __user *
argp = (void __user *)
args;
ret = copy_from_user(&
val,
argp, sizeof(unsigned long));
case REMOTE_IOC_SET_REPEAT_KEY_MAPPING:
remote->key_repeat_map[remote->map_num][val >> 16] =
val & 0xffff;
break;
...
}
6,另外:IOCTL相关的宏,读ioctl.h就知道了。
#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)))
#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))