// include/asm-generic/ioctl.h 头文件
#define _IOC_NRBITS8
#define _IOC_TYPEBITS 8
#define _IOC_SIZEBITS 14
#define _IOC_DIRBITS 2
#define _IOC_NRSHIFT0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
/*
* Direction bits.
*/
#define _IOC_NONE 0U
#define _IOC_WRITE 1U
#define _IOC_READ 2U
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \ //dir <<30
((type) << _IOC_TYPESHIFT) | \ //type << 8
((nr) << _IOC_NRSHIFT) | \ //nr << 0
((size) << _IOC_SIZESHIFT)) //size << 16
可以看出IOC返回的是一个32bit的数据,具体type dir nr size的方向位置如下:
总结:
我们只需要设置type这个数字然后定义nr这个值的大小,并设定每个值的作用即可,模仿scull的定义
#define TEST_IOC_MAGIC 0x54 //type =0x54
#define TEST_IOCSQUANTUM _IOW(TEST_IOC_MAGIC, 1, int)//0x40045401
//dir size type nr 组合成32bit的数据,一个CMD
#define TEST_IOCSQSET _IOW(TEST_IOC_MAGIC, 2, int) //0x40045402
#define TEST_IOCTQUANTUM _IO(TEST_IOC_MAGIC, 3) //0x00005403
#define TEST_IOCTQSET _IO(TEST_IOC_MAGIC, 4) //0x00005404
#define TEST_IOCGQUANTUM _IOR(TEST_IOC_MAGIC, 5, int)//0x80045405
#define TEST_IOCGQSET _IOR(TEST_IOC_MAGIC, 6, int)//0x80045406
#define TEST_IOCQQUANTUM _IO(TEST_IOC_MAGIC, 7) //0x00005407
#define TEST_IOCQQSET _IO(TEST_IOC_MAGIC, 8) //0x00005408
#define TEST_IOCXQUANTUM _IOWR(TEST_IOC_MAGIC, 9, int)//0xC0045409
#define TEST_IOCXQSET _IOWR(TEST_IOC_MAGIC,10, int)//0xC004540A
#define TEST_IOCHQUANTUM _IO(TEST_IOC_MAGIC, 11) //0x0000540B
#define TEST_IOCHQSET _IO(TEST_IOC_MAGIC, 12) //0x0000540C
//附录:scull ioctl函数的源码:
int scull_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int err = 0, tmp;
int retval = 0;
/*
* extract the type and number bitfields, and don't decode
* wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
*/
if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY;
/*
* the direction is a bitmask, and VERIFY_WRITE catches R/W
* transfers. `Type' is user-oriented, while
* access_ok is kernel-oriented, so the concept of "read" and
* "write" is reversed
*/
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if (err) return -EFAULT;
switch(cmd) {
case SCULL_IOCRESET:
<span style="white-space:pre"> </span>scull_quantum = SCULL_QUANTUM;
<span style="white-space:pre"> </span>scull_qset = SCULL_QSET;
<span style="white-space:pre"> </span>break;
case SCULL_IOCSQUANTUM: /* Set: arg points to the value */
<span style="white-space:pre"> </span>if (! capable (CAP_SYS_ADMIN))
<span style="white-space:pre"> </span>return -EPERM;
<span style="white-space:pre"> </span>retval = __get_user(scull_quantum, (int __user *)arg);
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_IOCTQUANTUM: /* Tell: arg is the value */
<span style="white-space:pre"> </span>if (! capable (CAP_SYS_ADMIN))
<span style="white-space:pre"> </span>return -EPERM;
<span style="white-space:pre"> </span>scull_quantum = arg;
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */
<span style="white-space:pre"> </span>retval = __put_user(scull_quantum, (int __user *)arg);
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */
<span style="white-space:pre"> </span>return scull_quantum;
<span style="white-space:pre"> </span>case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */
<span style="white-space:pre"> </span>if (! capable (CAP_SYS_ADMIN))
<span style="white-space:pre"> </span>return -EPERM;
<span style="white-space:pre"> </span>tmp = scull_quantum;
<span style="white-space:pre"> </span>retval = __get_user(scull_quantum, (int __user *)arg);
<span style="white-space:pre"> </span>if (retval == 0)
<span style="white-space:pre"> </span>retval = __put_user(tmp, (int __user *)arg);
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */
<span style="white-space:pre"> </span>if (! capable (CAP_SYS_ADMIN))
<span style="white-space:pre"> </span>return -EPERM;
<span style="white-space:pre"> </span>tmp = scull_quantum;
<span style="white-space:pre"> </span>scull_quantum = arg;
<span style="white-space:pre"> </span>return tmp;
<span style="white-space:pre"> </span>case SCULL_IOCSQSET:
<span style="white-space:pre"> </span>if (! capable (CAP_SYS_ADMIN))
<span style="white-space:pre"> </span>return -EPERM;
<span style="white-space:pre"> </span>retval = __get_user(scull_qset, (int __user *)arg);
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_IOCTQSET:
<span style="white-space:pre"> </span>if (! capable (CAP_SYS_ADMIN))
<span style="white-space:pre"> </span>return -EPERM;
<span style="white-space:pre"> </span>scull_qset = arg;
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_IOCGQSET:
<span style="white-space:pre"> </span>retval = __put_user(scull_qset, (int __user *)arg);
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_IOCQQSET:
<span style="white-space:pre"> </span>return scull_qset;
<span style="white-space:pre"> </span>case SCULL_IOCXQSET:
<span style="white-space:pre"> </span>if (! capable (CAP_SYS_ADMIN))
<span style="white-space:pre"> </span>return -EPERM;
<span style="white-space:pre"> </span>tmp = scull_qset;
<span style="white-space:pre"> </span>retval = __get_user(scull_qset, (int __user *)arg);
<span style="white-space:pre"> </span>if (retval == 0)
<span style="white-space:pre"> </span>retval = put_user(tmp, (int __user *)arg);
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_IOCHQSET:
<span style="white-space:pre"> </span>if (! capable (CAP_SYS_ADMIN))
<span style="white-space:pre"> </span>return -EPERM;
<span style="white-space:pre"> </span>tmp = scull_qset;
<span style="white-space:pre"> </span>scull_qset = arg;
<span style="white-space:pre"> </span>return tmp;
/*
* The following two change the buffer size for scullpipe.
* The scullpipe device uses this same ioctl method, just to
* write less code. Actually, it's the same driver, isn't it?
*/
<span style="white-space:pre"> </span>case SCULL_P_IOCTSIZE:
<span style="white-space:pre"> </span>scull_p_buffer = arg;
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case SCULL_P_IOCQSIZE:
<span style="white-space:pre"> </span>return scull_p_buffer;
<span style="white-space:pre"> </span>default: /* redundant, as cmd was checked against MAXNR */
<span style="white-space:pre"> </span>return -ENOTTY;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return retval;
}