ioctl、文件操作接口函数以及nand的升级模式的操作过程详解
概述
内核中驱动文件的操作通常是通过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的升级模式的操作过程详解的更多相关文章
- 每天一个linux命令(文件操作):【转载】find 命令的参数详解
find一些常用参数的一些常用实例和一些具体用法及注意事项. 1.使用name选项: 文件名选项是find命令最常用的选项,要么单独使用该选项,要么和其他选项一起使用.可以使用某种文件名模式来匹配文件 ...
- python 文件操作: 文件操作的函数, 模式及常用操作.
1.文件操作的函数: open("文件名(路径)", mode = '模式', encoding = "字符集") 2.模式: r , w , a , r+ , ...
- php中文件操作常用函数有哪些
php中文件操作常用函数有哪些 一.总结 一句话总结:读写文件函数 判断文件或者目录是否存在函数 创建目录函数 file_exists() mkdir() file_get_content() fil ...
- python 文件操作的函数
1. 文件操作的函数 open(文件名(路径), mode="?", encoding="字符集") 2. 模式: r, w, a, r+, w+, a+, r ...
- PHP文件操作功能函数大全
PHP文件操作功能函数大全 <?php /* 转换字节大小 */ function transByte($size){ $arr=array("B","KB&quo ...
- Linux 文件操作接口
目录 Linux 文件操作接口 C语言文件操作接口 C语言文件描述 fopen() r模式打开文件 w模式打开文件 a模式打开文件 其他模式类似 fclose() fwrite() fread() 系 ...
- C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解
前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解 ...
- (转)C# WebApi 接口返回值不困惑:返回值类型详解
原文地址:http://www.cnblogs.com/landeanfen/p/5501487.html 正文 前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi ...
- [转]C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解
本文转自:http://www.cnblogs.com/landeanfen/p/5501487.html 阅读目录 一.void无返回值 二.IHttpActionResult 1.Json(T c ...
随机推荐
- android linearlayout 把控件view置底部(放在页面最下方)
<LinearLayout android:id="@+id/recLayout" android:layout_width="fill_parent" ...
- java 利用java运行时的方法得到当前屏幕截图的方法(转)
将截屏图片保存到本地路径: package com.test; import java.awt.AWTException; import java.awt.Dimension; import java ...
- android 项目中log信息的正确处理
我们在做项目中,调试程序的时候通常是debug或者打log,特别是看一些json数据之类的,都喜欢打log看看,可是在项目上线时log信息一定不能被打印出来,大家能够平时下载一些做的烂的app,连接e ...
- Android经常使用UI组件 - TextView
TextView是Android里面用的最多的UI组件,一般使用在须要显示一些信息的时候,其不能输入,仅仅能初始设定或者在程序中改动. 实例:TextViewDemo 执行效果: 代码清单: 布局文件 ...
- java String 怎么看里面有几个指定字符
我现在有一个String 字符串,我想看一下这个字符串里有几个指定的字符,比如指定字符是div求解 public class Main { public static void main(String ...
- 数据结构C语言版 表插入排序 静态表
数据结构C语言版 表插入排序.txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了.他只是比对方更珍惜这份感情./* 数据结构C语言版 表插入排序 算法10.3 P267-P270 编译 ...
- 创建.NET Core项目
创建.NET Core项目 ? 对于.NET开发人员来说,我们已经习惯了VS这个世界上最强大的IDE,所以对他们来说,项目的创建直接利用安装到VS中相应的项目模板即可.当.NET Core跨出了Win ...
- 一个Java程序的执行过程(转)
我们手工执行java程序是这样的: 1.在记事本中或者是UE的文本编辑器中,写好源程序: 2.使用javac命令把源程序编译成.class文件: 编译后的.class(类字节码)文件中会包含 ...
- TCP和UDP的"保护消息边界" (经典)
在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有 ...
- yii框架网址解析问题
转载请注明来自souldak,微博:@evagle 首先如果你在config/main.php里面没有配置urlManager的话,那么流程如下(摘自yii官网) 用户发出了访问 URL http:/ ...