cmd由一个int型整数组成
方向/DIR | 大小/SIZE | 幻数/TYPE | 序数/NR |
30-31 | 30-16 | 15-8 | 7-0 |
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))
部分幻数,内核已使用Documentation/userspace-api/ioctl/ioctl-number.rst,可定义没使用的
以下面的例子来看下
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include<linux/slab.h>
/*
from include/uapi/asm-generic/ioctl.h
#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
#ifndef _IOC_NONE
# define _IOC_NONE 0U
#endif
#ifndef _IOC_WRITE
# define _IOC_WRITE 1U
#endif
#ifndef _IOC_READ
# define _IOC_READ 2U
#endif
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))
#ifndef __KERNEL__
#define _IOC_TYPECHECK(t) (sizeof(t))
#endif
#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))
#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)
#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)
*/
#define SET_TX_CARRIER _IOW(0xf5,0x80, int)
int test_open(struct inode *node, struct file *filp)
{
return 0;
}
int test_close(struct inode *node, struct file *filp)
{
return 0;
}
static long test_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int freq;
switch (cmd) {
case SET_TX_CARRIER:
if (get_user(freq, (unsigned int __user *)arg)) {
return -EFAULT;
}
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
struct file_operations test_fops = {
.open = test_open,
.unlocked_ioctl = test_ioctl,
.release = test_close,
};
static struct miscdevice test_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "test",
.fops = &test_fops,
};
static int __init test_init(void)
{
int ret;
printk("test_init\n");
ret = misc_register(&test_dev);
if (ret != 0) {
pr_err("cannot register miscdev\n");
}
printk("_IOC_NRSHIFT=%d,_IOC_NRMASK=0x%x\n", _IOC_NRSHIFT,
_IOC_NRMASK << _IOC_NRSHIFT);
printk("_IOC_TYPESHIFT=%d _IOC_TYPEMASK0x%x\n", _IOC_TYPESHIFT,
_IOC_TYPEMASK << _IOC_TYPESHIFT);
printk("_IOC_SIZESHIFT=%d _IOC_SIZEMASK=0x%x\n", _IOC_SIZESHIFT,
_IOC_SIZEMASK << _IOC_SIZESHIFT);
printk("_IOC_DIRSHIFT=%d _IOC_DIRMASK=0x%x\n", _IOC_DIRSHIFT,
_IOC_DIRMASK << _IOC_DIRSHIFT);
pr_info("SET_TX_CARRIER=0x%lx\n", SET_TX_CARRIER);
pr_info("_IOC_DIR=%ld\n", _IOC_DIR(SET_TX_CARRIER));
pr_info("_IOC_SIZE=%ld\n", _IOC_SIZE(SET_TX_CARRIER));
pr_info("_IOC_TYPE=0x%lx\n", _IOC_TYPE(SET_TX_CARRIER));
pr_info("_IOC_NR=0x%lx\n", _IOC_NR(SET_TX_CARRIER));
return 0;
}
static void __exit test_exit(void)
{
printk("test_exit\n");
misc_deregister(&test_dev);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL v2");