ioctl接口存在的意义:
**********因为对于大部分的驱动来说,除了需要有读写设备的能力,而且还要有通过设备驱动来对硬件进行各种控制的能力.
1. 对于用户空间,ioctl函数的原型是
int ioctl(int fd, unsigned long cmd, ...);参数说明:
**********fd--------->文件描述符
**********cmd------>控制命令
**********...---------->这三个点不是表示一个变数目的参数,而是单个可选的参数(这是因为有的命令需要参数,ioctl就有三个参数,有的命令不需要参数ioctl就有两个参数).
2. 对于内核空间,ioctl函数的原型------------------>(包含在<linux/fs.h>头文件中)
int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);参数说明:
**********inode对应于用户空间应用程序传递到内核空间的文件描述符fd
**********filp描述文件的结构体
**********cmd对应于用户空间应用程序传递到内核空间的控制命令
**********arg对应于传递到内核控件的命令参数(即三个点)
##############################################################################################################################
对于在内核层的ioctl,为ioctl创建唯一的命令代码
**********命令由四个位段组成,分别是 数据传输方向(dir),设定某一特定驱动命令类型的标志(type),命令序号(nr),参数的大小(size)
**********首先在确定type之前要先查看Documentation/ioctl/ioctl-number.txt文件,不要使用已经使用过的type
**********用于创建命令的宏函数-------->(在头文件<linux/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))) //创建读取设备的命令(get) #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) //创建写设备的命令(set) #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(dir, type, nr, size)宏函数的定义
#define _IOC(dir,type,nr,size) (((dir) << _IOC_DIRSHIFT) | \ //左移29/30位 ((type) << _IOC_TYPESHIFT) | \ //左移8位 ((nr) << _IOC_NRSHIFT) | \ //左移0 ((size) << _IOC_SIZESHIFT)) //左移16**********其他宏的定义
# define _IOC_NONE 0U # define _IOC_WRITE 1U # define _IOC_READ 2U
#ifdef __KERNEL__ /* provoke compile error for invalid uses of size argument */ extern unsigned int __invalid_size_argument_for_IOC; #define _IOC_TYPECHECK(t) ((sizeof(t) == sizeof(t[1]) && sizeof(t) < (1 << _IOC_SIZEBITS)) ? sizeof(t) : __invalid_size_argument_for_IOC) #else #define _IOC_TYPECHECK(t) (sizeof(t)) #endif
**********用于在自己实现的驱动里,解析用户空间请求命令的宏函数
/* 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) //解析参数的大小
**********下面是创建ioctl命令的例子
/*使用字符‘k‘作为驱动命令的类型*/ #define MY_IOC_DRVTYPE ‘k‘ /*创建一个没有参数,命令号为0的命令*/ #define MY_IOCRESET _IO(MY_IOC_DRVTYPE, 0) /*创建一个带有整型参数,命令号为1的命令*/ #define MY_IOCREAD _IOR(MY_IOC_DRVTYPE, 1)##############################################################################################################################
对于ioctl参数的使用说明
**********当使用一个指针引用用户空间,必须要确保用户空间地址是有效的
**********调用access_ok函数来对地址进行校验.----------------------->(在头文件<asm/uaccess.h>中)
int access_ok(int type, const void *addr, unsigned long size);参数说明:
**********type是VERIFY_READ或者VERIFY_WRITE,判断是读用户空间还是写用户空间(如是读写给定的地址,使用VERIFY_WRITE,因为VERIFY_WRITE是VERIFY_READ的超级)
#define VERIFY_READ 0 #define VERIFY_WRITE 1**********addr一个用户空间的地址
**********szie传输数据的大小
**********成功返回1,失败返回0