概述

内核中驱动文件的操作通常是通过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. 学习笔记,发QQ邮件

    首先设置自己的邮箱  设置   账号 吧这些全部选中就可以了 POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 public static void Sender() ...

  2. Apache 2.2 到 2.4的不同

    1.权限设定方式变更 2.2使用Order Deny / Allow的方式,2.4改用Require apache2.2: Order deny,allowDeny from allapache2.4 ...

  3. android Graphics(一):概述及基本几何图形绘制

    前言:我最近想抽空研究研究android的各种特效,android的特效真是其它平台无法比拟的,而且一个漂亮的UI交互,会给APP增色不少,而学习特效之前,有关graphics绘图的基础知识是必不可少 ...

  4. Android图像篇

    Android的渲染分为2D渲染和3D渲染两种,当中2D渲染的引擎为Skia.3D渲染的引擎是OpenGL ES.眼下.Android支持OpenGL ES1.0和OpenGL ES 2.0两种标准. ...

  5. B站开源播放框架ijkplayer(iOS版)使用教程

    最近在关注直播这块儿,开始时直接用ffmpeg写了一个,写得比较烂,卡顿很严重,后来听说了B站开源播放框架ijkplayer,于是就去试试看这是链接 ,一用之下果然不错,逢人便向人安利,可总是有部分同 ...

  6. JSONToObejct 问题 part 1

    直接截图,就明白了 前端的处理 这里用到 JSON2.stringify()  这个方法是将对象(object) 转换成 [{},{},+...+,{}] 这种键值对形式的数据,不然rows只是一个选 ...

  7. CentOS用yum安装搭建LAMP

    #1.安装Apache yum install httpd httpd-devel #启动apache /etc/init.d/httpd start #设为开机启动: chkconfig httpd ...

  8. Ural 1149 - Sinus Dances

    Let An = sin(1–sin(2+sin(3–sin(4+…sin(n))…)Let Sn = (…(A1+n)A2+n–1)A3+…+2)An+1For given N print SN I ...

  9. Net::OpenSSH 模块使用

    use Net::OpenSSH; my $host = "$ip"; my $user = 'root'; my $passphrase = 'uxxxxxD'; my $key ...

  10. quartz群调查调度机制和源代码分析

    pageId=85056282#quartz集群调度机制调研及源代码分析-quartz2.2.1集群调度机制调研及源代码分析" style="color:rgb(59,115,17 ...