Chinaunix首页 | 论坛 | 博客
  • 博客访问: 504640
  • 博文数量: 77
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 689
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-12 08:40
文章分类

全部博文(77)

文章存档

2018年(1)

2016年(3)

2015年(24)

2014年(49)

我的朋友

分类: LINUX

2015-06-18 18:02:33

一、什么是ioctl 
    ioctl是设备驱动程序中对设备的I/O通道进行管理的函数所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的调用个数如下: 
int ioctl(int fd, ind cmd, …); 
    其中fd是用户程序打开设备时使用open函数返回的文件标示符,cmd是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,这个参数的有无和cmd的意义相关。 
    ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数来控制设备的I/O通道。

二、ioctl的必要性 
    用户程序所作的只是通过命令码(cmd)告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。

三、ioctl如何实现
    在驱动程序中实现的ioctl函数体内,实际上是有一个switch{case}结构,每一个case对应一个命令码,做出一些相应的操作。怎么实现这些操作,这是应用程序自己的事情。
在ioctl中命令码是唯一联系用户程序命令和驱动程序支持的途径如果有两个不同的设备,但它们的ioctlcmd(命令码)却一样的,哪天有谁不小心打开错了,并且调用ioctl,这样就完蛋了。因为这个文件里面同样有cmd对应实现,故,我们可以自己生成未使用的命令码。所以在Linux核心中是这样定义一个命令码的
http:/..../linux/include/asm-generic/ioctl.h
 #define _IOC(dir,type,nr,size) \
        (((dir)  << _IOC_DIRSHIFT) | \
        ((type) << _IOC_TYPESHIFT) | \
        ((nr)   << _IOC_NRSHIFT) | \
        ((size) << _IOC_SIZESHIFT))
____________________________________
| 设备类型 | 序列号 | 方向 |数据尺寸|
|----------|--------|------|--------|
| 8 bit | 8 bit |2 bit |8~14 bit|
|----------|--------|------|--------|

    这样一来,一个命令就变成了一个整数形式的命令码;但是命令码非常的不直观,所以Linux Kernel中提供了一些这些宏可根据便于理解的字符串生成命令码,或者是从命令码得到一些用户可以理解的字符串以标明这个命令对应的设备类型、设备序列号、数据传送方向和数据传输尺寸。

    幻数:说得再好听的名字也只不过是个0~0xff的数,占8bit(_IOC_TYPEBITS)。这个数是用来区分不同的驱动的,像设备号申请的时候一样,内核有一个文档给出一些推荐的或者已经被使用的幻数。在内核文件中定义如下
Ioctl-number.txt (f:\sourceproject\linux-kernel\linux-3.14.26-g2489c02\documentation\ioctl)

点击(此处)折叠或打开

  1. Code Seq#(hex)    Include File        Comments
  2. ========================================================
  3. 0x00    00-1F    linux/fs.h        
  4. 0x00    00-1F    scsi/scsi_ioctl.h    
  5. 0x00    00-1F    linux/fb.h        
  6. 0x00    00-1F    linux/wavefront.h    
  7. 0x02    all    linux/fd.h
  8. 0x03    all    linux/hdreg.h
  9. 0x04    D2-DC    linux/umsdos_fs.h    Dead since 2.6.11, but don't reuse these.
  10. 0x06    all    linux/lp.h
  11. 0x09    all    linux/raid/md_u.h
  12. 0x10    00-0F    drivers/char/s390/vmcp.h
  13. 0x10    10-1F    arch/s390/include/uapi/sclp_ctl.h
  14. 0x10    20-2F    arch/s390/include/uapi/asm/hypfs.h
  15. 0x12    all    linux/fs.h
  16.         linux/blkpg.h
  17. 0x1b    all    InfiniBand Subsystem    <http://infiniband.sourceforge.net/>
  18. 0x20    all    drivers/cdrom/cm206.h
  19. 0x22    all    scsi/sg.h
  20. '#'    00-3F    IEEE 1394 Subsystem    Block for the entire subsystem
  21. '$'    00-0F    linux/perf_counter.h, linux/perf_event.h
  22. .....................
  23. ....................

四、CMD参数如何得出

    cmd参数在用户程序端由一些宏根据设备类型、序列号、传送方向、数据尺寸等生成,这个整数通过系统调用传递到内核中的驱动程序,再由驱动程序使用解码宏从这个整数中得到设备的类型、序列号、传送方向、数据尺寸等信息,然后通过switch{case}结构进行相应的操作。
    Linux内核已经提供了相应的宏来自动生成ioctl命令码

_IO(type,nr)   //无数据传输
_IOR(type,nr,size)  //从设备读数据
_IOW(type,nr,size)  //向设备写数据
_IOWR(type,nr,size)  //同时有读写数据

    上面的命令已经定义了方向,我们要传的是幻数(type)序号(nr)大小(size)。在这里szie的参数只需要填参数的类型,如int,上面的命令就会帮你检测类型的正确然后赋值sizeof(int)    
    相对的,Linux内核也提供了相应的宏来从ioctl命令号种解码相应的域值:

_IOC_DIR(nr)  //从命令中提取方向
_IOC_TYPE(nr) //从命令中提取幻数
_IOC_NR(nr)  //从命令中提取序数
_IOC_SIZE(nr)  //从命令中提取数据大小

例:
/*include_cmd.hpp*/
#define LED_IOC_MAGIC 0x13  //定义幻数
#define LED_MAX_NR    3          //定义命令的最大序数
#define LED_GPRS_MAGIC _IO(LED_IOC_MAGIC,0x00)  //0x00  用”宏+幻数来自动生成ioctl命令码
#define LED_WIFI_MAGIC _IO(LED_IOC_MAGIC,0x01)  //0x00
#define LED_BT_MAGIC _IO(LED_IOC_MAGIC,0x02)  //0x00

/*test.cpp*/
fd = open();
ioctl(fd,LED_GPRS_MAGIC,0);
ioctl(fd,LED_GPRS_MAGIC,1);
ioctl(fd,LED_WIFI_MAGIC ,0);
ioctl(fd,LED_WIFI_MAGIC ,1);

/*test_ioctl.c*/
int test_ioctl (struct inode *node, struct file *filp, unsigned int cmd, unsigned long arg)
{
    if(_IOC_TYPE(cmd) !=LED_IOC_MAGIC ) return -EINVAL;   //提取出幻数做检验
    if(_IOC_NR(cmd
) > LED_MAX_NR ) return -EINVAL;          //提取命令序数

    switch(cmd){
    case LED_GPRS_MAGIC:
     if(arg==0){
    //..........
    }else if(arg ==1){
    //..........
    }
    break;
    case LED_WIFI_MAGIC:
    //..........
    break;

    }

}

阅读(2104) | 评论(0) | 转发(0) |
0

上一篇: Linux input子系统

下一篇:LCD字符显示原理

给主人留下些什么吧!~~