Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9152799
  • 博文数量: 1727
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 19860
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1727)

文章存档

2024年(3)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: LINUX

2010-11-23 08:55:55

    * 用户空间的系统调用  int ioctl(int fd, ulong cmd, ...)
      内核空间 int (*ioctl)(struct inode *inode, struct file *filp, ulong cmd, ulong arg)
    * IOCTL的命令号
      命令号分为几个位段(Documentation/ioctl-number.txt)(linux/ioctl.h)
      type: 魔数 (_IOC_TYPEBITS)   type
      number: 序号 _IOC_NRBITS   nr
      direction: 数据传输方向(从应用的角度看待) _IOC_NONE/READ/WRITE/(READ | WRITE)
      size: 用户数据大小。 _IOC_SIZEBITS, 一般通过由体系决定的数据类型来决定
    * 命令号的定义
      #define type魔数   'k"  //定义魔数
      _IO(type,nr)               //定义无参数传递之命令
      _IOR(type, nr, datatype)   //定义从驱动中读数据的命令号
      _IOW(type, nr, datatype)   //定义写数据的命令号
      _IOWR(type, nr, datatype)  //定义双向传输的命令号

      解码命令号 _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd)
    * 命令号定义范例。
      /*we use 'k' as magic number*/
      #define SCULL_IOC_MAGIC    'k'
      /*
      * S means "Set" through a ptr,
      * G means "get" reply by setting through a ptr,
      * T means "Tell" 值参
      * Q means "Query" 返回为值参
      * X means "eXchange" 自动切换 S & G
      * H means "sHift" 自动切换 T & Q
      */
      /*reset 没有数据往来*/
      #define SCULL_IOCRESET     _IO(SCULL_IOC_MAGIC, 0)
      /*通过传递给驱动 指针变量 来设置QUANTNUM */
      #define SCULL_IOCSQUANTNUM _IOW(SCULL_IOC_MAGIC, 1, int) //通过指针变量传递
      /*通过传递给驱动 指针变量 来设置QSET */
      #define SCULL_IOCSQSET     _IOW(SCULL_IOC_MAGIC, 2, int) //通过指针变量传递
      /*通过传递给驱动 值变量 来设置QUANTNUM */
      #define SCULL_IOCTQUANTUM  _IO(SCULL_IOC_MAGIC, 3) //通过值传递
      /*通过传递给驱动 值变量 来设置QSET */
      #define SCULL_IOCTQSET     _IO(SCULL_IOC_MAGIC, 4) //通过值传递
      /*驱动通过 指针变量int 来返回QUANTNUM 值*/
      #define SCULL_IOCGQUANTUM  _IOR(SCULL_IOC_MAGIC, 5, int)//通过指针变量传递
      /*驱动通过 指针变量int 来返回QSET 值*/
      #define SCULL_IOCGQSET     _IOR(SCULL_IOC_MAGIC, 6, int)//通过指针变量传递
      /*驱动通过 ioctl函数返回值 来返回QUANTNUM 值*/
      #define SCULL_IOCQQUANTUM  _IO(SCULL_IOC_MAGIC, 7) //通过值传递
      /*驱动通过 ioctl函数 来返回QSET 值*/
      #define SCULL_IOCQQSET     _IO(SCULL_IOC_MAGIC, 8) //通过值传递

      #define SCULL_IOCXQUANTUM  _IOWR(SCULL_IOC_MAGIC, 9, int)
      #define SCULL_IOCXQSET     _IOWR(SCULL_IOC_MAGIC, 10, int)
      #define SCULL_IOCHQUANTUM  _IO(SCULL_IOC_MAGIC, 11)
      #define SCULL_IOCHQSET     _IO(SCULL_IOC_MAGIC, 12)

      #define SCULL_IOC_MAXNR    14
      当前列出了通过指针和值参来传递整数参数, 根据惯例在ioctl中应当使用指针方式,即S/G方式。
      可以看出上面定义命令号时,通过指针进行参数传递的都是通过 _IOR/W/WR参数进行方向控制。
    * ioctl 参数使用
          o copy_from_user / copy_to_user 安全的在内核空间和用户空间之间移动数据
          o 地址有效性校验
            int access_ok(int type, const void *addr, ulong size)
            type: VERIFY_READ / VERIFY_WRITE
            addr: 用户空间地址
            size: 用户空间地址上有效数据的长度
            返回值: 1:地址可以正常存取, 0:失败
          o 简单数据的存取, 对 ioctl 参数 是地址参数的情况
                + put_user(dataum, ptr)     __put_user(datum, ptr)
                  把datum 写到用户空间 ptr, 这个速度比较快。 传递数据大小依赖ptr参数的类型。 成功时返回0,错误时返回-EFAULT.
                  一般用来在实现read方法, 可以节省时钟周期。
                + get_user(local, ptr)  __get_user(local, ptr)
                  从用户空间ptr接受数据到local变量。
                + 当编译器出现“converion to non-scalar type requested"错误时,应当是使用copy_to_user 或者 copy_from_user.
             

    * ioctl的返回值
      不合适的命令号时应当返回 -ENOTTY 或者 -EINVAL
      返回负值则将被在用户空间设置 errno

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