概述

内核中驱动文件的操作通常是通过write和read函数进行的,但是很多时候再用户空间进行的操作或许不是内核中公共代码部分提供的功能,此时就需要使用一种个性化的方法进行操作--ioctl系统调用。

ioctl系统调用是一种用于设备控制的公共接口,主要分为两种,一种是用户空间使用的ioctl系统调用,函数原型为:

int ioctl(int fd,unsigned long cmd,...);

另一种是在内核空间使用的ioctl调用,函数原型为:

int (*ioctl)(struct inode *inode,struct file *filp,
             unsigned int cmd,unsigned long arg);

本文中主要介绍在用户空间使用的ioctl。

知其然,知其所以然

ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。

函数原型:

int ioctl(int fd, int cmd, ...);

其中fd就是用户程序打开设备时使用的open函数返回的文件标识符,cmd就是用户程序对设备的控制命令,至于后面的省略号,是可选参数,此参数的取值情况跟第二个参数有关。

函数的返回值,在传入非法命令式,Ioctl返回-EINVAL。

选择ioctl命令

为了防止对错误设备使用正确的命令,命令号应该在系统范围内唯一。从include/asm/ioctl.h头文件中,我们可以得出cmd为一个32位的无符号整数,被划分为4个段,具体表示如下:

 cmd
 direction

(bit31--bit30)

 size

(bit29--bit16)

type 

(bit15--bit8)

 number

(bit7--bit0)

 所占位数  2  14  8  8
 作用  命令:区别读/写  数据大小  幻数:表示设备类型  命令顺序序号

#define         _IOC_NRBITS          8                               //序数(number)字段的字位宽度,8bits

#define         _IOC_TYPEBITS      8                               //幻数(type)字段的字位宽度,8bits

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

#define         _IOC_DIRBITS         2                               //方向(direction)字段的字位宽度,2bits

#define         _IOC_NRMASK        ((1 << _IOC_NRBITS)-1)    //序数字段的掩码,0x000000FF

#define         _IOC_TYPEMASK   ((1 << _IOC_TYPEBITS)-1)  //幻数字段的掩码,0x000000FF

#define         _IOC_SIZEMASK     ((1 << _IOC_SIZEBITS)-1)   //大小字段的掩码,0x00003FFF

#define         _IOC_DIRMASK      ((1 << _IOC_DIRBITS)-1)    //方向字段的掩码,0x00000003

#define        _IOC_NRSHIFT       0                                                         //序数字段在整个字段中的位移,0

#define        _IOC_TYPESHIFT   (_IOC_NRSHIFT+_IOC_NRBITS)         //幻数字段的位移,8

#define        _IOC_SIZESHIFT    (_IOC_TYPESHIFT+_IOC_TYPEBITS)  //大小字段的位移,16

#define        _IOC_DIRSHIFT      (_IOC_SIZESHIFT+_IOC_SIZEBITS)    //方向字段的位移,30

/*

* Direction bits.

*/

#define _IOC_NONE     0U     //没有数据传输

#define _IOC_WRITE   1U     //向设备写入数据,驱动程序必须从用户空间读入数据

#define _IOC_READ     2U     //从设备中读取数据,驱动程序必须向用户空间写入数据

/*

*_IOC 宏将dir,type,nr,size四个参数组合成一个cmd参数,如下图:

*

*/

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

(((dir)  << _IOC_DIRSHIFT) | \

((type) << _IOC_TYPESHIFT) | \

((nr)   << _IOC_NRSHIFT) | \

((size) << _IOC_SIZESHIFT))

/*

* used to create numbers

*/

//构造无参数的命令编号

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

//构造从驱动程序中读取数据的命令编号

#define _IOR(type,nr,size)     _IOC(_IOC_READ,(type),(nr),sizeof(size))

//用于向驱动程序写入数据命令

#define _IOW(type,nr,size)    _IOC(_IOC_WRITE,(type),(nr),sizeof(size))

//用于双向传输

#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))

/*

*used to decode ioctl numbers..

*/

//从命令参数中解析出数据方向,即写进还是读出

#define _IOC_DIR(nr)          (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)

//从命令参数中解析出幻数type

#define _IOC_TYPE(nr)              (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)

//从命令参数中解析出序数number

#define _IOC_NR(nr)           (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)

//从命令参数中解析出用户数据大小

#define _IOC_SIZE(nr)         (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)

/* ...and for the drivers/sound files... */

#define IOC_IN            (_IOC_WRITE << _IOC_DIRSHIFT)

#define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)

#define IOC_INOUT     ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)

#define IOCSIZE_MASK      (_IOC_SIZEMASK << _IOC_SIZESHIFT)

#define IOCSIZE_SHIFT      (_IOC_SIZESHIFT)

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

对于命名的规则可以参考Documentation/ioctl-number.txt.其中mtd设备的命名为:

'M'     01-16   mtd/mtd-abi.h           conflict!
                and drivers/mtd/mtdchar.c

通过上面的描述我们能够简单的了解到,ioctl命令能够为我们提供的便利。但是在实际应用中,ioctl会在某些情况下配合文件的相关操作命令完成想要的功能。

文件的操作中比较重要的一些操作主要包括open(),close(),lseek(),stat()等等的接口函数。

open函数用于打开文件,因为linux中一切皆文件的概念,所以我们可以将设备文件同普通文件一样使用正常的open函数进行打开。

close函数用于关闭之前打开的文件。

lseek函数用于确定文件的位置,包括三个参数SEEK_SET,SEEK_CUR,SEEK_END分别用于标识文件偏移值的起始位置分别在开始,当前位置或者文件末尾。

r\w函数用于文件的读写操作,

stat函数用于获取文件的相关信息,即结构体struct stat中的相关内容信息。

NAND Flash的相关知识

nand作为一种重要的存储设备被广泛的使用,作为基础知识的了解,可以通过访问URL:http://www.linux-mtd.infradead.org/

此处主要讲述使用yaffs2文件系统的情况下NAND Flash的一些特性。

YAFFS2文件系统

好马配好鞍,因此要更好的使用Nandflash这种存储介质,我们需要选择一种更加适合它物理特性的文件系统。

网上关于此方面的介绍很多,大家可以多进行翻阅集百家之言。此处只指出几点个人在实际的移植和开发过程中遇到的问题。

首先从实际的硬件结构上nand的存储分为两个部分,一个部分被称作data area;一个部分被称作spare area。这两个部分分别放置了不同的内容,一般在data area中存放实际的数据,而在spare area中存放了一些校验信息和FTL数据。在yaffs文件系统的挂载过程中会扫描这个spare area(oob)区,存放在这个区域的属于在yaffs2文件系统中称为FTL数据。这个通过读取此部分的数据和header page的数据确定数据的类型和文件的层次结构。如果这部分的数据是正确的,则系统能够正常的进行mount操作。

需要特别注意的是,要使用yaffs2文件系统,则需要将需要烧写的文件通过mkyaffs2imge工具进行操作,这个会在每一个page大小的数据之后产生FTL信息。因此,在实际数据的写入过程中需要特别注意将此两部分的数据进行区分处理。

ioctl、文件操作接口函数以及nand的升级模式的操作过程详解的更多相关文章

  1. 每天一个linux命令(文件操作):【转载】find 命令的参数详解

    find一些常用参数的一些常用实例和一些具体用法及注意事项. 1.使用name选项: 文件名选项是find命令最常用的选项,要么单独使用该选项,要么和其他选项一起使用.可以使用某种文件名模式来匹配文件 ...

  2. python 文件操作: 文件操作的函数, 模式及常用操作.

    1.文件操作的函数: open("文件名(路径)", mode = '模式', encoding = "字符集") 2.模式: r , w , a , r+ , ...

  3. php中文件操作常用函数有哪些

    php中文件操作常用函数有哪些 一.总结 一句话总结:读写文件函数 判断文件或者目录是否存在函数 创建目录函数 file_exists() mkdir() file_get_content() fil ...

  4. python 文件操作的函数

    1. 文件操作的函数 open(文件名(路径), mode="?", encoding="字符集") 2. 模式: r, w, a, r+, w+, a+, r ...

  5. PHP文件操作功能函数大全

    PHP文件操作功能函数大全 <?php /* 转换字节大小 */ function transByte($size){ $arr=array("B","KB&quo ...

  6. Linux 文件操作接口

    目录 Linux 文件操作接口 C语言文件操作接口 C语言文件描述 fopen() r模式打开文件 w模式打开文件 a模式打开文件 其他模式类似 fclose() fwrite() fread() 系 ...

  7. C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

    前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解  ...

  8. (转)C# WebApi 接口返回值不困惑:返回值类型详解

    原文地址:http://www.cnblogs.com/landeanfen/p/5501487.html 正文 前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi ...

  9. [转]C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

    本文转自:http://www.cnblogs.com/landeanfen/p/5501487.html 阅读目录 一.void无返回值 二.IHttpActionResult 1.Json(T c ...

随机推荐

  1. Hdu 2364 Escape

    Problem地址:http://acm.hdu.edu.cn/showproblem.php?pid=2364 这道题的特殊之处在于能转弯时不能直走,必须转弯,所以在行走时,要判断能否转弯,不能转弯 ...

  2. java学习之总结

    学的时候忘记写博客,现在java SE学完了一口气把写的代码发了上来没有做什么补充,其中有很多知识漏掉了,学的有点不扎实,接下来写写项目来稳好基础

  3. extjs 优化小建议

    1 原文信息 原文标题: Sencha Con 2013: Ext JS Performance tips 原文地址: [http://edspencer.net/2013/07/19/sencha- ...

  4. POJ 1947 - Rebuilding Roads 树型DP(泛化背包转移)..

    dp[x][y]表示以x为根的子树要变成有y个点..最少需要减去的边树... 最终ans=max(dp[i][P]+t)  < i=(1,n) , t = i是否为整棵树的根 > 更新的时 ...

  5. JS判断只能是数字和小数点

    JS判断只能是数字和小数点 1.文本框只能输入数字代码(小数点也不能输入) <input onkeyup="this.value=this.value.replace(/\D/g,'' ...

  6. CSDN排名第一和第二的人

    http://blog.csdn.net/phphot http://blog.csdn.net/yuanmeng001

  7. 【转】管理员必备的Linux系统监控工具

    原文连接: 管理员必备的Linux系统监控工具 #1: top - 进程活动 top提供一个当前运行系统实时动态的视图,也就是正在运行进程.在默认情况下,显示系统中CPU使用率最高的任务,并每5秒钟刷 ...

  8. 面向对象程序设计-C++ Operator Overloading & Type conversion (Static)【第十一次上课笔记】

    本次上课继续讲解了 [ ] .-> 等运算符重载的具体例子 也讲解了C++单个参数的类的类型转换的案例 最后稍微提到了 static 的第三种作用:静态数据成员 具体详解我都已注释出来了,大家可 ...

  9. select()函数详解

    Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是 习惯写诸如connect. accept.recv或recvfrom这样的阻塞程 ...

  10. Fiddler 教程(转)

    阅读目录 Fiddler的基本介绍 Fiddler的工作原理 同类的其它工具 Fiddler如何捕获Firefox的会话 Fiddler如何捕获HTTPS会话 Fiddler的基本界面 Fiddler ...