1. 前言
使用ioctl
系統呼叫是使用者空間向核心交換資料的常用方法之一,從
ioctl
這個名稱上看,本意是針對
i/o裝置進行的控制操作,但實際並不限制是真正的
i/o裝置,可以是任何乙個核心裝置即可。
2. 基本過程
在核心空間中
ioctl
是很多核心操作結構的乙個成員函式,如檔案操作結構
struct file_operations(include/linux/fs.h)
、協議操作結構
struct proto_ops(include/linux/net.h)
等、tty
操作結構
struct tty_driver(include/linux/tty_driver.h)
等,而這些操作結構分別對應各種核心裝置,只要在使用者空間開啟這些裝置,如
i/o裝置可用
open(2)
開啟,網路協議可用
socket(2)
開啟等,獲取乙個檔案描述符後,就可以在這個描述符上呼叫
ioctl(2)
來向核心交換資料。
3. ioctl(2)
ioctl(2)
函式的基本使用格式為:
int ioctl(int fd, int cmd, void *data)
第乙個引數是檔案描述符;
cmd是操作命令,一般分為
get、
set以及其他型別命令,
get是使用者空間程序從核心讀資料,
set是使用者空間程序向核心寫資料,
cmd雖然是乙個整數,但是有一定的引數格式的,下面再詳細說明;第三個引數是資料起始位置指標,
cmd命令引數是個
32位整數,分為四部分:
dir(2b) size(14b) type(8b) nr(8b)
詳細定義
cmd要包括這
4個部分時可使用巨集
_ioc(dir,type,nr,size)
來定義,而最簡單情況下使用
_io(type, nr)
來定義就可以了,這些巨集都在
include/a**/ioctl.h
中定義
本文cmd
定義為:
#define newchar_ioc_magic 'm'
#define newchar_set _io(newchar_ioc_magic, 0)
#define newchar_get _io(newchar_ioc_magic, 1)
#define newchar_ioc_maxnr 1
要定義自己的
ioctl
操作,可以有兩個方式,一種是在現有的核心**中直接新增相關**進行支援,比如想通過
socket
描述符進行
ioctl
操作,可在
net/ipv4/af_inet.c
中的inet_ioctl()
ioctl()
來操作,可以編成模組,這樣不影響原有的核心,這是最通常的做法。
4. 核心裝置
為進行ioctl
操作最通常是使用字元裝置來進行,當然定義其他型別的裝置也可以。在使用者空間,可使用
mknod
命令建立乙個字元型別裝置檔案,假設該裝置的主裝置號為
123,次裝置號為0:
mknode /dev/newchar c 123 0
如果是程式設計的話,可以用
mknode(2)
函式來建立裝置檔案。
建立裝置檔案後再將該裝置的核心模組檔案插入核心,就可以使用
open(2)
開啟/dev/newchar
檔案,然後呼叫
ioctl(2)
來傳遞資料,最後用
close(2)
關閉裝置。而如果核心中還沒有插入該裝置的模組,
open(2)
時就會失敗。
由於核心記憶體空間和使用者記憶體空間不同,要將核心資料拷貝到使用者空間,要使用專用拷貝函式
copy_to_user()
;要將使用者空間資料拷貝到核心,要使用
copy_from_user()。
要最簡單實現以上功能,核心模組只需要實現裝置的
open, ioctl
和release
三個函式即可,
下面介紹程式片斷:
static int newchar_ioctl(struct inode *inode, struct file *filep,
unsigned int cmd, unsigned long arg);
static int newchar_open(struct inode *inode, struct file *filep);
static int newchar_release(struct inode *inode, struct file *filep);
// 定義檔案操作結構,結構中其他元素為空
struct file_operations newchar_fops = ;
// 定義要傳輸的資料塊結構
struct newchar;
#define major_dev_num 123
#define device_name "newchar"
開啟裝置,非常簡單,就是增加模組計數器,防止在開啟裝置的情況下刪除模組,
當然想搞得複雜的話可進行各種限制檢查,如只允許指定的使用者開啟等:
static int newchar_open(struct inode *inode, struct file *filep)
關閉裝置,也很簡單,減模組計數器:
static int newchar_release(struct inode *inode, struct file *filep)
進行ioctl
呼叫的基本處理函式
static int newchar_ioctl(struct inode *inode, struct file *filep,
unsigned int cmd, unsigned long arg)
break;
case knewchar_get:
// get
操作通常會在資料緩衝區中先傳遞部分初始值作為資料查詢條件,獲取全部
// 資料後重新寫回緩衝區
// 當然也可以根據具體情況什麼也不傳入直接向核心獲取資料
} break; }
return ret; }
模組初始化函式,登記字元裝置
static int __init _init(void)
return 0; }
模組退出函式,登出字元裝置
static void __exit _cleanup(void)
module_init(_init);
module_exit(_cleanup);
5. 結論
用ioctl()
在使用者空間和核心空間傳遞資料是最常用方法之一,比較簡單方便,而且可以在同乙個
ioctl
中對不同的命令傳送不同的資料結構,本文只是為描述方便而在不同命令中使用了相同的資料結構。
使用ioctl與核心交換資料
1.前言 使用ioctl系統呼叫是使用者空間向核心交換資料的常用方法之一,從ioctl這個名稱上看,本意是針對i o裝置進行的控制操作,但實際並不限制是真正的i o裝置,可以是任何乙個核心裝置即可。2.基本過程 在核心空間中ioctl是很多核心操作結構的乙個成員函式,如檔案操作結構struct fi...
使用ioctl和核心交換資料
1.前言 使用ioctl系統呼叫是使用者空間向核心交換資料的常用方法之一,從ioctl這個名稱上看,本意是針對i o裝置進行的控制操作,但實際並不限制是真正的i o裝置,能是所有乙個核心裝置即可。2.基本過程 在核心空間中ioctl是非常多核心操作結構的乙個成員函式,如檔案操作結構struct fi...
linux ioctl與核心交換資料
1.前言 使用ioctl系統呼叫是使用者空間向核心交換資料的常用方法之一,從ioctl這個名稱上看,本意是針對i o裝置進行的控制操作,但實際並不限制是真正的i o裝置,可以是任何乙個核心裝置即可。2.基本過程 在核心空間中ioctl是很多核心操作結構的乙個成員函式,如檔案操作結構struct fi...