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)
    
posted @ 2020-06-18 19:17  elon_wang  阅读(2208)  评论(0编辑  收藏  举报