• 【linux驱动分析】ioctl函数的使用


    一、用户空间的ioctl
        int  ioctl(int fd, unsigned long cmd, void *data);
    第一个參数是文件描写叙述符,第二个參数代表传递的命令,它会原样传递给驱动,第三个參数是可选类型的,主要依据第二个參数选择,第三个參数不管是整数还是指针,都会以unsigned long的形式传递给驱动程序。

    二、内核空间的ioctl
    1、參数的定义
        long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
    这是linux-2.6.38中的定义,与曾经的不太一样,它是三个參数。它定义在file_operations结构体中,vfs.txt这样说:
    unlocked_ioctl: called by the ioctl(2) system call.
    第二个參数cmd是一个32位的整数,关于cmd各个位的含义可在Documentationioctlioctl-decoding.txt中找到:
    *********************************************************************************************************
    To decode a hex IOCTL code:

    Most architectures use this generic format, but check
    include/ARCH/ioctl.h for specifics, e.g. powerpc
    uses 3 bits to encode read/write and 13 bits for size.

     bits meaning
     31-30 00 - no parameters: uses _IO macro
           10 - read: _IOR
           01 - write: _IOW
           11 - read/write: _IOWR

     29-16    size of arguments

     15-8      ascii character supposedly
           unique to each driver

     7-0 function #


    So for example 0x82187201 is a read with arg length of 0x218,
    character 'r' function 1. Grepping the source reveals this is:

    #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])

    *********************************************************************************************************
    0~7位为type(幻数),8~15位为number(序数,顺序编号),16~29位为size(用户数据的大小,13或者14位),30~31位为direction(传输数据的方向,这里的读取是从用户角度来说的)。

    2、cmd參数的构造

    可用宏来构造幻数(它们定义在<linux/ioctl.h>):
    #ifndef  _IOC_NONE
    # define  _IOC_NONE 0U
    #endif
    #ifndef  _IOC_WRITE
    # define  _IOC_WRITE 1U
    #endif
    #ifndef  _IOC_READ
    # define  _IOC_READ 2U
    #endif
    #define  _IO(type, nr)  _IOC(_IOC_NONE, (type), (nr), 0)
    #define  _IOR(type, nr, size)  _IOC(_IOC_READ, (type), (nr), (_IOC_TYPECHECK(size)))
    #define  _IOW(type, nr, size)  _IOC(_IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))
    #define  _IOWR(type, nr, size)  _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size)))

    注意:第三个參数为要进行传递的參数的类型,比方int或者struct foo,不要使用sizeof(arg)作为第三个參数,由于ioctl可能会觉得你传递给他的是size_t的类型。
    幻数能够选择一个字母,可是要注意不能反复,能够查看Documentationioctlioctl-number.txt
    比方'k',在ioctl-number.txt文件中有说明(只是这个是x86平台的):
    'k' 00-0F linux/spi/spidev.h conflict!
    'k' 00-05 video/kyro.h conflict!
    说以上面出现的序号我们就不能再用了。

    3、使用实例

    以下的代码演示样例是用来检測cmd的正确性和用户空间相应的地址是否可读写:
    access_ok定义在<arch/arm/include/asm/uaccess.h>中,使用时要包括<asm/uaccess.h>这个头文件。
    if(_IOC_TYPE(cmd) != POWMAN_MAGIC){
      return -EINVAL;
     }
     if(_IOC_NR(cmd) > POWMAN_MAGIC_MAXNR){
      return -EINVAL;
     }
     
     if (_IOC_DIR(cmd) & _IOC_WRITE)
      if (!access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd))){
       return -EFAULT;
      }
     if (_IOC_DIR(cmd) & _IOC_READ)
      if (!access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd))){
       return -EFAULT;
      }

    除了用copy_to_user和copy_from_user外,假设传递经常使用的数据大小(1、2、4、8字节)的单个数据可用以下的一组函数,它们速度相对较快。
    它们定义在<arch/arm/include/asm/uaccess.h>中,使用时要包括<asm/uaccess.h>这个头文件。
    put_user(datum, ptr)
    把datum传递到用户空间,ptr指向用户空间地址,假设ptr是字符指针,就传递1个字节,2、4、8字节类似。
    成功返回0,出错返回-EFAULT。
    get_user(local, ptr)
    从用户空间接收一个数据,放在local变量里。
    实例:
    if (get_user(val, (int __user *)arg))
       return -EFAULT;

  • 相关阅读:
    20189222 《网络攻防技术》第十周作业
    20189222 《网络攻防技术》第九周作业
    20189222 《网络攻防技术》第八周作业
    20189222 《网络攻防技术》第七周作业
    20189209 《网络攻防技术》第六周作业
    20189209 《网络攻防技术》第五周作业
    20189209 《网络攻防技术》第四周作业
    20189209 《网络攻防技术》第三周作业
    20189209 《网络攻防技术》第二周作业
    快速排序+折半查找 c++
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4019544.html
Copyright © 2020-2023  润新知