1. 程式人生 > >ioctl、檔案操作介面函式以及nand的升級模式的操作過程詳解

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_NRBITS8//序數(number)欄位的字位寬度,8bits

#define         _IOC_TYPEBITS8//幻數(type)欄位的字位寬度,8bits

#define         _IOC_SIZEBITS14//大小(

size)欄位的字位寬度,14bits

#define         _IOC_DIRBITS2//方向(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_NRSHIFT0//序數字段在整個欄位中的位移,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_NONE0U//沒有資料傳輸

#define _IOC_WRITE1U//向裝置寫入資料,驅動程式必須從使用者空間讀入資料

#define _IOC_READ2U//從裝置中讀取資料,驅動程式必須向用戶空間寫入資料

/*

*_IOC 巨集將dirtypenrsize四個引數組合成一個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的相關知識

此處主要講述使用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資訊。因此,在實際資料的寫入過程中需要特別注意將此兩部分的資料進行區分處理。