简介
IOCTL被称为输入和输出控制,用于与设备驱动程序进行通信。该系统调用在大多数驱动程序类别中可用。此功能的主要用途是处理默认情况下内核没有系统调用的设备的某些特定操作。这个函数在设备驱动里面用的很多。
IOCTL的一些实时应用程序是从“ cd”驱动器中弹出媒体,以更改串行端口的波特率,调整音量,读取或写入设备寄存器等。我们已经在设备中具有写入和读取功能驱动。但这还不足以适用于所有情况。
IOCTL涉及到的一步骤
- 在驱动程序创建IOCTL命令
- 在驱动程序编写IOCTL函数
- 应用程序创建IOCTL命令
- 应用程序使用IOCTL调用
在驱动程序创建IOCTL命令
```cdefine “ioctl name” __IOX(“magic number”,”command number”,”argument type”)
- IOX 可以是下面几种值 “IO“: an ioctl with no parameters “IOW“: an ioctl with write parameters (copy_from_user) “IOR“: an ioctl with read parameters (copy_to_user) “IOWR“: an ioctl with both write and read parameters
“Magic Number” 是唯一的数字或字符,将区分我们从其他ioctl调用ioctl()调用的集合。有时在这里使用设备的主要号码。 “command number” 是分配给ioctl的编号。这用于区分命令 “argument type” 是数据类型
- 下面是使用例子
```c
#include <linux/ioctl.h>
#define WR_VALUE _IOW('a','a',int32_t*)
#define RD_VALUE _IOR('a','b',int32_t*)
Write IOCTL function in the driver
上面我们创建了IOCTL命令。下面我们来实现ioctl驱动函数
inioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
<inode> : is the inode number of the file being worked on.
<file> : is the file pointer to the file that was passed by the application.
<cmd> : is the ioctl command that was called from the userspace.
<arg> : are the arguments passed from the userspace.
在函数“ ioctl”中,我们需要实现上面(WR_VALUE
,RD_VALUE
)定义的所有命令。
然后,我们需要通知内核ioctl调用是在函数“ etx_ioctl
” 中实现的。
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case WR_VALUE:
copy_from_user(&value ,(int32_t*) arg, sizeof(value));
printk(KERN_INFO "Value = %d\n", value);
break;
case RD_VALUE:
copy_to_user((int32_t*) arg, &value, sizeof(value));
break;
}
return 0;
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = etx_read,
.write = etx_write,
.open = etx_open,
.unlocked_ioctl = etx_ioctl,
.release = etx_release,
};
代码
驱动
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h> //kmalloc()
#include <linux/uaccess.h> //copy_to/from_user()
#include <linux/ioctl.h>
#define WR_VALUE _IOW('a', 'a', int32_t *)
#define RD_VALUE _IOR('a', 'b', int32_t *)
#define NONE_Op _IO('a', 'c')
#define READWRIE_VALUE _IOWR('a', 'd', int32_t *)
int32_t value = 0;
dev_t dev = 0;
static struct class *dev_class;
static struct cdev etx_cdev;
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
static int etx_open(struct inode *inode, struct file *file);
static int etx_release(struct inode *inode, struct file *file);
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off);
static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t *off);
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = etx_read,
.write = etx_write,
.open = etx_open,
.unlocked_ioctl = etx_ioctl,
.release = etx_release,
};
static int etx_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Opened...!!!\n");
return 0;
}
static int etx_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Closed...!!!\n");
return 0;
}
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Read Function\n");
return 0;
}
static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Write function\n");
return 0;
}
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = 0x00;
switch (cmd)
{
case WR_VALUE:
ret = copy_from_user(&value, (int32_t *)arg, sizeof(value));
printk(KERN_INFO "Value = %d\n", value);
break;
case RD_VALUE:
ret = copy_to_user((int32_t *)arg, &value, sizeof(value));
break;
case NONE_Op:
printk("Nonr Argc\n");
break;
case READWRIE_VALUE:
ret = copy_from_user(&value, (int32_t *)arg, sizeof(value));
value = value + 1;
ret = copy_to_user((int32_t *)arg, &value, sizeof(value));
break;
}
(void)ret;
return 0;
}
static int __init etx_driver_init(void)
{
/*Allocating Major number*/
if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0)
{
printk(KERN_INFO "Cannot allocate major number\n");
return -1;
}
printk(KERN_INFO "Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&etx_cdev, &fops);
/*Adding character device to the system*/
if ((cdev_add(&etx_cdev, dev, 1)) < 0)
{
printk(KERN_INFO "Cannot add the device to the system\n");
goto r_class;
}
/*Creating struct class*/
if ((dev_class = class_create(THIS_MODULE, "etx_class")) == NULL)
{
printk(KERN_INFO "Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if ((device_create(dev_class, NULL, dev, NULL, "etx_device")) == NULL)
{
printk(KERN_INFO "Cannot create the Device 1\n");
goto r_device;
}
printk(KERN_INFO "Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev, 1);
return -1;
}
void __exit etx_driver_exit(void)
{
device_destroy(dev_class, dev);
class_destroy(dev_class);
cdev_del(&etx_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Device Driver Remove...Done!!!\n");
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
MODULE_DESCRIPTION("A Sample ioctl module demo");
MODULE_VERSION("2:1.0");
应用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define WR_VALUE _IOW('a', 'a', int32_t *)
#define RD_VALUE _IOR('a', 'b', int32_t *)
#define NONE_Op _IO('a', 'c')
#define READWRIE_VALUE _IOWR('a', 'd', int32_t *)
int main()
{
int fd;
int32_t value, number;
printf("*********************************\n");
printf("*******WWW.EmbeTronicX.com*******\n");
printf("\nOpening Driver\n");
fd = open("/dev/etx_device", O_RDWR);
if (fd < 0)
{
printf("Cannot open device file...\n");
return 0;
}
printf("Enter the Value to send\n");
scanf("%d", &number);
printf("Writing Value to Driver\n");
ioctl(fd, WR_VALUE, (int32_t *)&number);
printf("Reading Value from Driver\n");
ioctl(fd, RD_VALUE, (int32_t *)&value);
printf("Value is %d\n", value);
printf("None Value from Driver\n");
ioctl(fd, NONE_Op);
scanf("%d", &number);
printf("Write Value is 0x%x\n", number);
ioctl(fd, READWRIE_VALUE, (int32_t *)&number);
printf("Write Bakc Value is 0x%x\n", number);
printf("Closing Driver\n");
close(fd);
}