天天看點

ioctl---操作裝置的接口

ioctl接口存在的意義:

**********因為對于大部分的驅動來說,除了需要有讀寫裝置的能力,而且還要有通過裝置驅動來對硬體進行各種控制的能力.

1.    對于使用者空間,ioctl函數的原型是

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

參數說明:

**********fd--------->檔案描述符

**********cmd------>控制指令

**********...---------->這三個點不是表示一個變數目的參數,而是單個可選的參數(這是因為有的指令需要參數,ioctl就有三個參數,有的指令不需要參數ioctl就有兩個參數).

2.    對于核心空間,ioctl函數的原型------------------>(包含在<linux/fs.h>頭檔案中)

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

參數說明:

**********inode對應于使用者空間應用程式傳遞到核心空間的檔案描述符fd

**********filp描述檔案的結構體

**********cmd對應于使用者空間應用程式傳遞到核心空間的控制指令

**********arg對應于傳遞到核心控件的指令參數(即三個點)

##############################################################################################################################

對于在核心層的ioctl,為ioctl建立唯一的指令代碼

**********指令由四個位段組成,分别是 資料傳輸方向(dir),設定某一特定驅動指令類型的标志(type),指令序号(nr),參數的大小(size)

**********首先在确定type之前要先檢視Documentation/ioctl/ioctl-number.txt檔案,不要使用已經使用過的type

**********用于建立指令的宏函數-------->(在頭檔案<linux/ioctl.h>中)

/* used to create numbers */
#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)					//建立沒有參數的指令
#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))		//建立讀取裝置的指令(get)
#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))		//建立寫裝置的指令(set)
#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))	//建立讀寫裝置的指令
#define _IOR_BAD(type,nr,size)	_IOC(_IOC_READ,(type),(nr),sizeof(size))			//
#define _IOW_BAD(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))			//
#define _IOWR_BAD(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))		//
           

********** _IOC(dir, type, nr, size)宏函數的定義

#define _IOC(dir,type,nr,size) \
	(((dir)  << _IOC_DIRSHIFT) | \		//左移29/30位
	 ((type) << _IOC_TYPESHIFT) | \ 	//左移8位
	 ((nr)   << _IOC_NRSHIFT) | \		//左移0
	 ((size) << _IOC_SIZESHIFT))		//左移16
           

********** 其他宏的定義

# define _IOC_NONE	0U

# define _IOC_WRITE	1U

# define _IOC_READ	2U
           
#ifdef __KERNEL__
/* provoke compile error for invalid uses of size argument */
extern unsigned int __invalid_size_argument_for_IOC;
#define _IOC_TYPECHECK(t) \
	((sizeof(t) == sizeof(t[1]) && \
	  sizeof(t) < (1 << _IOC_SIZEBITS)) ? \
	  sizeof(t) : __invalid_size_argument_for_IOC)
#else
#define _IOC_TYPECHECK(t) (sizeof(t))
#endif
           

********** 用于在自己實作的驅動裡,解析使用者空間請求指令的宏函數

/* used to decode ioctl numbers.. */
#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)		//解析資料的傳輸方向
#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)		//解析某一特定驅動類型的指令标志
#define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)			//解析具體的指令号
#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)		//解析參數的大小
           

**********下面是建立ioctl指令的例子

/*使用字元'k'作為驅動指令的類型*/
#define MY_IOC_DRVTYPE  'k'
/*建立一個沒有參數,指令号為0的指令*/
#define MY_IOCRESET  _IO(MY_IOC_DRVTYPE, 0)
/*建立一個帶有整型參數,指令号為1的指令*/
#define MY_IOCREAD _IOR(MY_IOC_DRVTYPE, 1)
           

##############################################################################################################################

對于ioctl參數的使用說明

**********當使用一個指針引用使用者空間,必須要確定使用者空間位址是有效的

**********調用access_ok函數來對位址進行校驗.----------------------->(在頭檔案<asm/uaccess.h>中)

int access_ok(int type, const void *addr, unsigned long size);
           

參數說明:

**********type是VERIFY_READ或者VERIFY_WRITE,判斷是讀使用者空間還是寫使用者空間(如是讀寫給定的位址,使用VERIFY_WRITE,因為VERIFY_WRITE是VERIFY_READ的超級)

#define VERIFY_READ 0
#define VERIFY_WRITE 1
           

**********addr一個使用者空間的位址

**********szie傳輸資料的大小

**********成功傳回1,失敗傳回0

繼續閱讀