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