linux驱动-file_operations之ioctl
来源:互联网 发布:农村淘宝合伙人的收入 编辑:程序博客网 时间:2024/05/21 08:53
简述:
ioctl是linux应用程序用来向设备发送特殊命令。如果,设备要响应应用程序的ioctl调用,那么设备驱动必须编写响应ioctl的接口,这个接口就是file_operations的unlocked_ioctl。
应用程序ioctl接口:
声明头文件:
#include <sys/ioctl.h>
如是ubuntu系统,可以在/usr/include/sys/下面查看。
定义ioctl命令需要包含头文件:
#include <asm/ioctl.h>
命令定义规则和驱动一样的,见下。
file_operations的定义:
struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, loff_t, loff_t, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); int (*show_fdinfo)(struct seq_file *m, struct file *f);};
其中:
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
就是响应应用程序ioctl调用的接口。
主要用unlocked_ioctl,
compat_ioctl用来兼容老版本。
第一个参数:打开的文件指针
第二个参数:命令
第三个参数:可以是一个整数,也可以是数据起始地址。
ioctl命令定义(第2个参数):
定义命令需要包含头文件:
#include <asm/ioctl.h>
命令定义分4个段,如下:
type:魔数,占8位(_IOC_TYPEBITS)
number:序号,占8位(_IOC_NRBITS)
direction:方向(读写),占2位(_IOC_DIRBITS)
size:数据大小,占14位(_IOC_SIZEBITS),当第三个参数是地址的时候,就可以启用这个size来表示数据大小(单位字节),一般情况下不用就是0。(假想下,当同一type下超过256个序号的命令,其实可以启用这个,只需要驱动与应用程序配合好,当然,一般情况也没有超过256的命令)
正好32位。命令类型主要由type和number决定,先看type,然后再看number。
- 用如下的宏来编码命令:
/* 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)))#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))
_IOC_NONE:代表没有读写的命令,只执行动作。
_IOC_READ:代表读,即要返回数据给用户空间(地址是unlocked_ioctl第三个参数),数据大小为size。
_IOC_WRITE:代表写,即用户空间有送数据下来,数据起始地址是unlocked_ioctl第三个参数,大小size。
- 解码命令用下面宏:
/* used to decode ioctl numbers.. */#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)/* ...and for the drivers/sound files... */#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
如,要判断一个命令是不是读:
_IOC_DIR(nr)==IOC_OUT
定义命令例子:
#include <asm/uaccess.h>#include <asm/ioctl.h>#define YU_CMD 'A' //其实就是大写A的ascii值,也可以直接写数字#define TR_CMD 32#define YU_CMD0 _IO(YU_CMD,0)#define YU_CMD1 _IO(YU_CMD,1)#define YU_CMD2 _IOW(YU_CMD,2,sizeof(int))#define TR_CMD0 _IO(TR_CMD ,0)#define TR_CMD1 _IO(TR_CMD ,1)#define TR_CMD2 _IOR(TR_CMD ,2,20)long exioctl(struct file *f, unsigned int cmd, unsigned long data);struct file_operations fo = { ... .unlocked_ioctl = exioctl, .compat_ioctl = exioctl, //这行可要可不要,不考虑兼容老版本就不需要 ...}long exioctl(struct file *f, unsigned int cmd, unsigned long data){ int err; int ac; char ch[20] = {'t'}; switch(_IOC_TYPE(cmd)|_IOC_NR(cmd)) { case YU_CMD0: ... break; case YU_CMD1: ... break; case YU_CMD2: if(_IOC_DIR(cmd) == IOC_IN) { err = get_user(ac,data); printk("ac = %d\n",ac) } break; case TR_CMD0: ... break; case TR_CMD1: ... break; case TR_CMD2: if(_IOC_DIR(cmd) == IOC_OUT) { err = copy_to_user(data,ch,20); } break; default: err = -EINVAL; } ... return err;}
unlocked_ioctl 返回值,当没有匹配到命令时一般返回-EINVAL(”Invalid argument”),没有带读写的一般返回0,有读写的,返回读写字节数。
对于内核和用户空间数据交互,尽量用提供的api:
单个数用:
get_user:从用户空间获取一个数
put_user:推送一个数到用户空间
多个数据用:
copy_from_user:从用户空间获取数据
copy_to_user:推送数据到用户空间
如果,不用这些API,要考虑用access_ok来检查用户空间地址的有效性:
access_ok(VERIFY_READ, ptr, sizeof(*ptr))
VERIFY_READ:表示对地址有没有读权限,写用权限VERIFY_WRITE
ptr:用户空间地址
sizeof(*ptr):地址空间大小
其实,命令也可以不按照这么定义,直接用数字代替也是可以的,只要驱动和应用程序配合好,但是兼容性和可读性,就没按照规定好,不建议。
还有些特殊的预定于命令,在:
#include <uapi/asm-generic/ioctls.h>
很少看到有用的。
- linux驱动-file_operations之ioctl
- linux驱动之file_operations
- linux驱动---file_operations之llseek
- linux驱动---file_operations之poll
- linux驱动-file_operations之mmap
- Linux驱动之ioctl
- linux驱动之ioctl
- Linux简单设备驱动(2): file_operations的write、read、ioctl驱动及Android应用层开发验证
- linux字符设备驱动之file_operations结构体知识详解
- linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- linux驱动学习之ioctl接口
- Linux设备驱动之Ioctl控制
- Linux设备驱动之ioctl控制
- Linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- thinkphp核心源码注释|Build.class.php
- cocos2d js 请求网络
- Redis对于key的操作命令(附PHP代码)
- 老司机教你 “飙” EventBus 3
- UE3 性能、分析及优化
- linux驱动-file_operations之ioctl
- 2017,大屏可视化助力大数据应用落地
- 京东、宅急送的微服务实践分享(下)| 架构师小组交流会
- 感悟
- OpenGL 学习笔记3_3(绘制三角形相关)
- GStreamer播放教程08——视频解码的硬件加速
- C++ MAP的基本操作和使用
- Android适配不同的屏幕
- Tips: ubuntu下特殊默认配置坑