linux 驱动程序___高级字符驱动程序___ioctl 方法解读

 

~ ioctl方法

  • 概述
    • 目的: 通过设备驱动程序执行各种类型的硬件控制
    • 用户空间的调用原型:int ioctl(int fd, unsigned long cmd, ...);
      • fd 指的是 文件描述符
      • ”…“ 代表可选参数,使用 ”…“ 可以关闭编译时的逻辑检查
      • 习惯上使用 char *argp;
      • 可选参数可以为空,可为整型,可以是指针;当使用指针时可以交换任意数量的数据。
    • 驱动程序的原型实现:int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
      • inode 和 filp两个指针对应于用户空间的 文件描述符 fd
      • cmd 参数直接传输,不经任何修改
      • arg 接收的是可选参数,接收类型永远是 unsigned long,参数类型检查被关闭,如果有错误也不进行报告
      • 多数 ioctl 都是通过 switch 语句来完成的
  • ioctl 命令选择
    • ioctl 命令结构
      • 参考文件
        • include/asm/ioctl.h
        • Documentation/ioctl-number.txt
      • 位段结构
        • type
          • 幻数(类型),主要在Documentation/ioctl-number.txt 中定义
          • 位宽:8位 ( _IOC_TYPEBITS )
        • number
          • 序数(顺序编号)
          • 位宽:8位 ( _IOC_NRBITS )
        • direction
          • 数据传送的标志,定义数据传送的方向,该字段是一个位掩码,可以通过逻辑运算分离
          • 可使用值
            • 没有数据传输 (_IOC_NONE)
              • #ifndef _IOC_NONE

                # define _IOC_NONE 0U

                #endif

            • _IOC_READ
              • #ifndef _IOC_READ

                # define _IOC_READ 2U

                #endif

            • _IOC_WRITE
              • #ifndef _IOC_WRITE

                # define _IOC_WRITE 1U

                #endif

            • 双向数据传输(_IOC_READ|_IOC_WRITE)
        • size
          • 指示用户数据大小,与体系结构有关,通常是13位或者14位
          • 宏定义:_IOC_SIZEBITS
          • 系统不对字段进行检查,用户数据大时可以乎略
    • 构造命令编号的宏
      • 定义位置: <asm/ioctl.h>;type和number位字段通过参数传入,size位字段通过对 datatype 参数取 sizeof 获得。
      • _IO(type, nr)
        • 用于构造无参数的命令编号
      • _IOR(type, nr, datatype)
        • 用于构造从驱动程序中读取数据的命令编号
      • _IOW(type, nr, datatype)
        • 用于写入数据的命令
      • _IOWR(type, nr, datatype)
        • 用于双向传输
    • 解开位段结构的宏
      • 定义位置 <asm/ioctl.h>
      • _IOC_DIR(nr)
      • _IOC_TYPE(nr)
      • _IOC_NR(nr)
      • _IOC_SIZE(nr)
  • ioctl 命令号不能匹配的默认的返回值
    • 非法参数:-ENVAL
    • POSIX标准规定返回: -ENOTTY
  • ioctl 的预定义命令
    • 部分预定义命令可由内核识别,这些命令在使用时无法到达设备,由内核运行,并且因为编号冲突,结果不可预期
    • 预定义命令分类
      • 可用于任何文件(普通、设备、FIFO和套接字)的命令
        • 幻数是 ”T“
      • 只适用于普通文件的命令
      • 特定于文件系统类型的命令
        • 只能在宿主文件系统上执行
    • 实际预定义命令
      • FIOCLEX
        • 设置执行时关闭标志(File IOctl Close on EXec),设置后当调用进程执行一个新程序时,文件描述符将被关闭
      • FIOUNCLEX
        • 清除执行时关闭标志(File IOctl Not Close on EXec),恢复通常的文件行为,撤销 FIOCLEX 操作。
      • FIOASYNC
        • 设置或复位异步通知
        • 修改 O_SYNC 标志,同样的工作可通过 fcntl 完成,因此 FIOASYNC 很少使用
      • FIOQSIZE
        • 返回文件或目录的大小。
        • 不可用于设备文件,否则导致 ENOTTY 错误
      • FIONBIO
        • File IOctl Non-Blocking I/O, 即文件 ioctl 非阻塞型 I/O
        • 该调用修改 filp->f_flags 中的 O_NONBLOCK 标志, 系统调用的第三个参数说明了是复位还是设置
        • filp->f_flags 中的 O_NONBLOCK 通常由 fcntl 系统调用使用命令 F_SETFL 命令完成
    • 使用 ioctl 参数
      • 当 ioctl 第三个参数是个指针时,会出现一些问题
      • 当指针指向用户空间时,必须保证用户空间合法,否则应返回错误
      • 地址验证函数 access_ok
        • 函数声明及原型
          • <asm/uaccess.h>
          • int access_ok(int type, const void *addr, unsigned long size);
        • 参数说明
          • type
            • VERIFY_READ
              • 从用户空间读出数据
            • VERIFY_WRITE
              • 往用户空间写入数据
              • 如果既要读取又要写入,则应该使用 VERIFY_WRITE,为超集
          • addr
            • 用户空间地址
          • size
            • 数据的字节数,如果为int,则是 sizeof(int)
        • 返回值是 bool 量
          • 访问成功返回 1
          • 访问失败返回 0,此时驱动程序应该返回 -EFAULT 给调用者
        • 使用注意事项
          • 没有完成验证内存的全部工作,只对进程对空间的访问权限进行验证,尤其确保指针没有指向内核空间
          • 大多数程序不需要直接调用该函数,大多数内存管理函数会处理它
      • 写入/读取数据函数(限于 1,2,4和8个字节)
        • 写入用户空间

          • put_user(datum, ptr);
            • 进行地址检查,成功时返回 0, 失败时返回 -EFAULT
          • __put_user(datum, ptr);
            • 不进行地址检查,使用时需要自行调用 access_ok

          读取用户空间

          • get_user(local, ptr)
          • __get_user(local, ptr)

          当指针类型与指定类型不相符时,编译器返回 “conversion to non-scalar type requested"

          此时必须使用 copy_to_user 或者 copy_from_user

    • 权能与受限操作
      • 对权能检查的说明
        • 对设备的访问一般由设备文件的权限控制,驱动程序不进行检查
        • 对于一些附加操作,驱动程序需要进行附加检查以确认用户是否有权进行
      • 权能(capability)
        • 权能把特权操作划分为独立的组,这样某些特定用户或程序可被授权执行指定操作,同时又没有执行其它操作的权限

          相关系统调用函数:capget 和 capset,因此可以在用户空间管理权能

      • 定义文件
        • <linux/capability.h>
      • 驱动程序关心的权能
        • CAP_DAC_OVERRIDE
          • 超越文件或目录的访问权限,数据访问控制或DAC)的能力
        • CAP_NET_ADMIN
          • 执行网络管理任务的能力,包括那些影响网络接口的任务
        • CAP_SYS_MODULE
          • 载入或删除内核模块的能力
        • CAP_SYS_RAMIO
          • 执行”裸“ I/O操作的能力,例如访问设备端口或直接与 USB 通信
        • CAP_SYS_ADMIN
          • 截获的能力,它提供了访问许多系统管理操作的途径
        • CAP_SYS_TTY_CONFIG
          • 执行 tty 配置任务的能力
      • 权能检查
        • 在执行一项特殊操作时,驱动程序应该检查调用进程是否有相关权能
        • 函数实现
          • <sys/sched.h>
          • int capable(int capability);
  • ioctl 命令的实现
    • 利用 switch 语句实现命令控制,参考 scull 源代码
    • 参数传递的一般途径(六种)
      • int quantum;

         

        ioctl(fd,SCULL_IOCSQUANTUM, &quantum); /* Set by pointer */

        ioctl(fd,SCULL_IOCTQUANTUM, quantum); /* Set by value */

         

        ioctl(fd,SCULL_IOCGQUANTUM, &quantum); /* Get by pointer */

        quantum = ioctl(fd,SCULL_IOCQQUANTUM); /* Get by return value */

         

        ioctl(fd,SCULL_IOCXQUANTUM, &quantum); /* Exchange by pointer */

        quantum = ioctl(fd,SCULL_IOCHQUANTUM, quantum); /* Exchange by value *

         

  • 非 ioctl 的设备控制——转议序列
    • 适用于只执行命令,不需要数据传输的设备
    • 如果写入数据种出现控制符时会产生误会
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值