IO IOC IOR IOW等一些宏定义的解析
// 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:
scull_quantum = SCULL_QUANTUM;
scull_qset = SCULL_QSET;
break;case SCULL_IOCSQUANTUM: /* Set: arg points to the value */
if (! capable (CAP_SYS_ADMIN))
return -EPERM;
retval = __get_user(scull_quantum, (int __user *)arg);
break; case SCULL_IOCTQUANTUM: /* Tell: arg is the value */
if (! capable (CAP_SYS_ADMIN))
return -EPERM;
scull_quantum = arg;
break; case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */
retval = __put_user(scull_quantum, (int __user *)arg);
break; case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */
return scull_quantum; case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */
if (! capable (CAP_SYS_ADMIN))
return -EPERM;
tmp = scull_quantum;
retval = __get_user(scull_quantum, (int __user *)arg);
if (retval == 0)
retval = __put_user(tmp, (int __user *)arg);
break; case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */
if (! capable (CAP_SYS_ADMIN))
return -EPERM;
tmp = scull_quantum;
scull_quantum = arg;
return tmp; case SCULL_IOCSQSET:
if (! capable (CAP_SYS_ADMIN))
return -EPERM;
retval = __get_user(scull_qset, (int __user *)arg);
break; case SCULL_IOCTQSET:
if (! capable (CAP_SYS_ADMIN))
return -EPERM;
scull_qset = arg;
break; case SCULL_IOCGQSET:
retval = __put_user(scull_qset, (int __user *)arg);
break; case SCULL_IOCQQSET:
return scull_qset; case SCULL_IOCXQSET:
if (! capable (CAP_SYS_ADMIN))
return -EPERM;
tmp = scull_qset;
retval = __get_user(scull_qset, (int __user *)arg);
if (retval == 0)
retval = put_user(tmp, (int __user *)arg);
break; case SCULL_IOCHQSET:
if (! capable (CAP_SYS_ADMIN))
return -EPERM;
tmp = scull_qset;
scull_qset = arg;
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?*/ case SCULL_P_IOCTSIZE:
scull_p_buffer = arg;
break; case SCULL_P_IOCQSIZE:
return scull_p_buffer; default: /* redundant, as cmd was checked against MAXNR */
return -ENOTTY;
}
return retval;}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
