概述

内核中驱动文件的操作通常是通过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. 编程的毛病——C++之父访谈

    原文见:http://www.technologyreview.com/InfoTech/17831/  翻译:xeon 11/29/2006 在20世纪的80年代和90年代,Bjarne Strou ...

  2. java大作业 KShinglingAlgorithm

    wiki上关于KShingling Algorithm(w-shingling)的说明: http://en.wikipedia.org/wiki/W-shingling 摘要: In natural ...

  3. 11427 - Expect the Expected(概率期望)

    11427 - Expect the Expected Some mathematical background. This problem asks you to compute the expec ...

  4. Matrix Factorization, Algorithms, Applications, and Avaliable packages

    矩阵分解 来源:http://www.cvchina.info/2011/09/05/matrix-factorization-jungle/ 美帝的有心人士收集了市面上的矩阵分解的差点儿全部算法和应 ...

  5. [Swust OJ 666]--初来乍到(题号都这么溜~~,递归,找规律)

    题目链接:http://acm.swust.edu.cn/problem/0666/ Time limit(ms): 1000 Memory limit(kb): 65535   Descriptio ...

  6. USACO Milk2 区间合并

    这题WA了四次,后来发现不能用所谓的桶排来写 虽然空间上是可以的,但是存在这样一个问题 比如两组数据[15,20]和[21,30] 在20 和 21这两个时刻之间没有milking,但是用桶排的方法写 ...

  7. 基于visual Studio2013解决算法导论之044最短路径

     题目 最短路径 解决代码及点评 // 26最短路径dijstra.cpp : 定义控制台应用程序的入口点. // #include <iostream> using namespa ...

  8. Vedis - An Embeddable Datastore Engine

    Vedis - An Embeddable Datastore Engine     An Embeddable Datastore Engine         Tweet        Follo ...

  9. MySQL中关于日期、时间的数据类型和函数

    一.日期相关的数据类型 1.datetime 占用8字节,既显示了日期,又显示了时间.其表示的日期范围为“1000-01-01 00:00:00”到“9999-12-31 23:59:59” 2.da ...

  10. Python 第五篇(上):算法、自定义模块、系统标准模块(time 、datetime 、random 、OS 、sys 、hashlib 、json和pickle)

    一:算法回顾: 冒泡算法,也叫冒泡排序,其特点如下: 1.比较相邻的元素.如果第一个比第二个大,就交换他们两个. 2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应 ...