Linux系统调用——ioctl()

  • ioctl 是设备驱动程序中设备控制接口函数,通过指定的命令来实现对应的操作。

    用户空间
    int ioctl(int fd, int cmd, ...) ;
    • cmd: 交互协议,设备驱动将根据 cmd 执行对应操作

    • ...: 可变参数 arg

    驱动程序
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

    在linux内核2.6.36以后版本中使用上面两个函数取代了ioctl()。

    • unlocked_ioctl: 在无大内核锁的情况下调用,一般使用这个。

    • compat_ioctl:为 64 位系统提供 32 位 ioctl 的兼容方法,也是在无大内核锁的情况下调用。

    协议cmd

    第二个参数 cmd 为用户与驱动的 “协议”,可以是任意 int 型数据,但是为了确保该 “协议” 的唯一性,ioctl 命令应该使用更科学严谨的方法赋值,在linux中,提供了一种 ioctl 命令的统一格式,将 32 位 int 型数据划分为四个位段。

    内核提供了宏来生成ioctl命令:

    #define _IOC(dir,type,nr,size) \
        (((dir)  << _IOC_DIRSHIFT) |      ((type) << _IOC_TYPESHIFT) |      ((nr)   << _IOC_NRSHIFT) |      ((size) << _IOC_SIZESHIFT))
    1. dir(direction,ioctl 命令访问模式(数据传输方向),占据 2 bit,可以为 _IOC_NONE_IOC_READ_IOC_WRITE_IOC_READ | _IOC_WRITE,分别指示了四种访问模式:无数据、读数据、写数据、读写数据;

    2. type(device type),设备类型,占据 8 bit,又称为 “幻数” 或者 “魔数”,可以为任意 char 型字符,例如‘a’、’b’、’c’ 等等,其主要作用是使 ioctl 命令有唯一的设备标识;

    3. nr(number),命令编号/序数,占据 8 bit,可以为任意 unsigned char 型数据,取值范围 0~255,如果定义了多个 ioctl 命令,通常从 0 开始编号递增;

    4. size,涉及到 ioctl 函数 第三个参数 arg ,占据 13bit 或者 14bit(体系相关,arm 架构一般为 14 位),指定了 arg 的数据类型及长度;

    通常,为了方便会使用宏 _IOC() 衍生的接口来直接定义 ioctl 命令:

    #define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)   //定义不带参数的 ioctl 命令
    #define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))  //定义带写参数的 ioctl 命令(copy_from_user)
    #define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) //定义带读参数的ioctl命令(copy_to_user)
    #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))       //定义带读写参数的 ioctl 命令

    同时,内核还提供了反向解析ioctl命令的宏接口:

    #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)

Linux系统调用——ioctl()

上一篇:Linux环境下利用 Socket 接口实现 FTP 客户端和服务器程序所需的函数


下一篇:Linux基础:dirname命令总结