关于魔数的分析

在嵌入式中经常碰到魔数,比如:

#define PLATDRV_MAGIC 0X60

#define LED_OFF    _IO(PLATDRV_MAGIC,0X18)

#define LED_ON      _IO(PLATDRV_MAGIC,0X19)

然后我们会调用ioctl(fd[i],LED_OFF)或者ioctl(fd[i],LED_ON)

网上资料:_IO(魔数,基数)

                  _IOR(魔数,基数,变量型)

                  _IOW(魔数,基数,变量型)

                  _IOWR(魔数,基数,变量型)

#define _IO(type,nr)    _IOC(_IOC_NONE,(type),(nr),0)

再看 _IOC() 的定义://include/asm/ioctl.h

#define _IOC(dir,type,nr,size)   

(((dir)<< _IOC_DIRSHIFT)|((type)<<_IOC_TYPESHIFT)|((nr)<<_IOC_NRSHIFT)|((size) << _IOC_SIZESHIFT))

#define _IOC_DIRSHIFT    (_IOC_SIZESHIFT+_IOC_SIZEBITS)    //16+14=30

#define _IOC_TYPESHIFT    (_IOC_NRSHIFT+_IOC_NRBITS)      //0+8=8

#define _IOC_NRSHIFT    0

#define _IOC_SIZESHIFT    (_IOC_TYPESHIFT+_IOC_TYPEBITS)//8+8=16

#define _IOC_NRBITS    8

#define _IOC_TYPEBITS    8  //

#define _IOC_SIZEBITS     14 //大小(size)字段的字位宽度,14bits

由上面的定义,往上推得到:

_IOC_TYPESHIFT = 8

_IOC_SIZESHIFT = 16

_IOC_DIRSHIFT = 30

所以#define _IOC(dir,type,nr,size)   (((dir)<<30)|((type)<<8)|((nr)<<0)((size)<<16))

cmd的大小为 32位,共分 4 个域:

bit31~bit30 2位为 “区别读写” 区,作用是区分是读取命令还是写入命令。//dir
bit29~bit16 14位为 "数据大小" 区,表示 ioctl() 中的 arg 变量传送的内存大小。//size
bit15~bit08  8位为 “魔数"(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。//type
bit07~bit00   8位为 "区别序号" 区,是区分命令的命令顺序序号。//nr

所以#define LED_OFF    _IO(PLATDRV_MAGIC,0X18)就是_IOC(_IOC_NONE,PLATDRV_MAGIC,0X18,0)

其中_IOC_NONE为0 ,也即是:

((0<<30)|(0x60<<8)|(0x18<<0)|(0<<16))

现在我们来看ioctl(fd[i],LED_OFF)

ioctl的原型:int ioctl(int fd, int cmd, …)

其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是

一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。

在驱动程序中实现的ioctl函数体内,实际上是有一个switch{case}结构,每一个case对应一个命令码,做出一些相应的操作。

怎么实现这些操作,这是每一个程序员自己的事情,因为设备都是特定的,这里也没法说。关键在于怎么样组织命令码,因为在ioctl

中命令码是唯一联系用户程序命令和驱动程序支持的途径。

在Linux核心中是这样定义一个命令码的:

https://img-blog.csdn.net/20130715085808218?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuZ3dlbjEyMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

| 设备类型 | 数据尺寸 | 魔数   |  序列号 |

|      2 bit    |    14 bit   | 8 bit    |     8bit   |

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






  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值