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