ioctl#
The ioctl() function manipulates the underlying device parameters of special files. Most devices can perform operations beyond simple data transfers; user space must often be able to request, for example, that the device lock its door, eject its media, report error information, change a baud rate, or self destruct. These operations are usually supported via the ioctl method.
lwn.nethave wonderful explaination on ioctl, i suggest you read it, here to know the internals.
#define IOCTL_IOC_MAGIC 'd'
#define IOCTL_MAXNR 2
struct ioctl_dev {
struct cdev cdev;
};
int ioctl_open(struct inode *inode, struct file *filp)
{
filp->private_data =
container_of(inode->i_cdev, struct ioctl_dev, cdev);
return 0;
}
long ioctl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct ioctl_dev *ioctl_dev = filp->private_data;
if (_IOC_TYPE(cmd) != IOCTL_IOC_MAGIC) {
pr_warn("magic mismatch IOCTL failed\n");
return -ENOTTY;
}
if (_IOC_NR(cmd) > IOCTL_MAXNR) {
pr_warn("invalid ioctl call\n");
return -ENOTTY;
}
ret = access_ok((void __user *)arg, _IOC_SIZE(cmd));
if (!ret)
return -EFAULT;
switch (cmd) {
case IOCTL_RESET:
ret = ioctl_reset(ioctl_dev);
break;
case IOCTL_HOWMANY:
ret = ioctl_howmany(ioctl_dev, (unsigned long)arg);
break;
case IOCTL_MESSAGE:
ret = ioctl_message(ioctl_dev, (void *__user)arg);
break;
default:
return -ENOTTY;
}
return ret;
}
static struct file_operations fops = {
.open = ioctl_open,
.unlocked_ioctl = ioctl_ioctl,
};
static int __init m_init(void)
{
int ret;
ioctl_dev = kzalloc(sizeof(*ioctl_dev), GFP_KERNEL);
ret = alloc_chrdev_region(&dev__t, 0, IOCTL_DEV_NR, MODULE_NAME);
cdev_init(&ioctl_dev->cdev, &fops);
ioctl_dev->cdev.owner = THIS_MODULE;
ret = cdev_add(&ioctl_dev->cdev, dev__t, IOCTL_DEV_NR);
[...]
}