Chinaunix首页 | 论坛 | 博客

分类: LINUX

2012-11-07 16:56:02

    大部分驱动除了需要具有读写设备的能力外,还需要具备对硬件控制的能力。例如,要求设备报告错误信息,改变波特率,这些操作常常通过 ioctl 方法来实现。
    在用户空间,使用 ioctl 系统调用来控制设备,原型如下:
    int ioctl(int fd, unsigned long cmd, ...)
    原型中的点表示这是一个可选的参数,存在与否依赖于控制命令(第2个参数)是否涉及到与设备的数据交互。
    ioctl 驱动方法原型:
    int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
    cmd 参数从用户空间传下来,可选的参数 arg 以一个 unsigned long 的形式传递,不管它是一个整数或一个指针。如果 cmd 命令不涉及数据传输,则第 3 个参数 arg 的值无任何意义。

实现 ioctl 步骤(规范做法):
1.定义命令 ==> 应用层
2.实现命令 ==> 驱动层
    在编写 ioctl 代码之前,首先需要定义命令。为了防止对错误的设备使用正确的命令,命令号应该在系统范围内是唯一的。ioctl 命令编码被划分为几个位段,include/asm/ioctl.h 中定义了这些位字段:类型(幻数)、序号、传输方向、用户数据大小。
    Type 类型(幻数):表明哪个设备的命令,8 位宽;
    Number 序号:表明设备命令中的第几个,8 位宽;
    Direction 传输方向:可能的值是 _IOC_NONE(没有数据传输)、_IOC_READ、_IOC_WRITE。数据传送是从应用程序的角度来看的,_IOC_WRITE 是写数据到设备;
    Size 用户数据大小:13/14 位宽,视处理器而定。
内核提供了下列宏来帮助定义命令:
_IO(Type, Number)  没有参数的命令

_IOR(Type, Number, Size)  从设备中读数据
_IOW(Type, Number, Size)  写数据到设备中
_IOWR(Type, Number, Size)  双向传送
    注意:Size 不能直接写有几个字节,应该写参数的类型,例如:int、struct xxx 等,内核会自动用 sizeof 计算所占的字节数。
定义命令范例:
#define MEM_IOCTL_MAGIC 'm'  //定义类型
_IOW(MEM_IOCTL_MAGIC, 0, int)
_IOR(MEM_IOCTL_MAGIC, 1, int)

    ioctl 函数的实现通常是使用 switch 语句。ioctl 中用户传下来的参数如果是一个整数,可以直接使用。如果是指针,必须确保用户地址是有效的。使用 copy_from_user copy_to_user 函数会自行进行地址有效性检查。驱动中可以使用 _IOC_DIR(cmd) & _IOC_READ 来判断数据的传输方向。

                       ——忠于梦想 勇于实践    linux_xpj@opencores.org

阅读(1140) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~