Linux驱动之IOCTL探究(linux驱动ioctl)
Linux 驱动之 IOCTL 探究
Linux 驱动程序开发中有许多有趣的技术,其中一种技术就是让应用程序可以控制设备的状态,典型的功能就是 IOCTL。本文介绍 IOCTL,一种在 Linux 中驱动开发中常见的机制,以及如何在 Linux 驱动程序中使用它。
什么是 IOCTL ?
IOCTL(Input/Output (I/O) Control)是驱动程序编程接口(Device Driver Programming Interface, DDPI)中一种让应用程序控制设备或者驱动程序的机制。它可以让驱动程序提供给应用程序一个平台独立的接口,从而便于设备和上层用户空间应用程序间的交互。
IOCTL提供了一种让驱动程序穿越用户/内核间的界限的机制,但是,由于同一操作可能传递不同的数据,IOCTL的实现可以很复杂,甚至比实现一种新的系统调用更复杂。
如何在 Linux 驱动中使用 IOCTL ?
使用 IOCTL 实现一个跨用户和内核空间的设备接口,需要以下3步:
1、在 Linux 驱动中定义 IOCTL 命令:
首先,我们需要在驱动程序中定义 IOCTL 命令,可以使用新的命令标识符,或者可以指定一个已存在的命令标识符(在 include/uapi/asm-generic/ioctl.h 中定义)。
2、实现 IOCTL 功能:
接着,我们需要实现 IOCTL 功能,有两种方式:
(1)根据命令标识符实现多个 IOCTL 功能:
可以使用 switch 语句根据命令标识符的不同而实现不同的功能,典型的代码如下:
static long __do_ioctl(struct foo_device* dev, unsigned int cmd, unsigned long arg)
{ switch(cmd) {
case IOCTL_FOO_SET_VARIABLE: /* implement set variable logic */
break; case IOCTL_FOO_GET_VARIABLE:
/* implement get variable logic */ break;
default: /* unknown command */
return -ENOTTY; }
return 0;}
(2)实现 IOCTL 的 get/set 功能:
另外,也可以使用新式的 get/set 接口,典型的代码如下:
static long __do_ioctl(struct foo_device* dev, unsigned int cmd, unsigned long arg)
{ switch(cmd) {
case IOCTL_FOO_GET_VARIABLE: return foo_get_variable();
case IOCTL_FOO_SET_VARIABLE: foo_set_variable(arg);
break; default:
/* unknown command */ return -ENOTTY;
}
return 0;}
3、实现 IOCTL 系统调用的可为性:
最后,我们需要实现一个 ioctl 系统调用,作为上层应用程序调用内核模块的接口,该调用应该满足如下一个条件:有效地根据应用程序传入的参数传入正确的内核函数。其代码如下:
long foo_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ int ret = 0;
struct foo_device* dev = file->private_data;
mutex_lock(&dev->io_lock); ret = __do_ioctl(dev, cmd, arg);
mutex_unlock(&dev->io_lock);
return ret;}
总结
IOCTL 是一种在 Linux 驱动程序中常见的机制,它可以让应用程序控制设备的状态,从而实现跨用户和内核空间的设备接口。实现 IOCTL 需要三个步骤:在驱动程序中定义 IOCTL 命令,实现 IOCTL 功能,并实现 IOCTL 系统调用的可取性。