-
本函數(shù)影響由fd參數(shù)引用的一個打開的文件。
-
#include<unistd.h>
-
#include<sys/ioctl.h>
-
int ioctl( int fd, int request, .../* void *arg */ );
-
返回0:成功 -1:出錯
-
第三個參數(shù)總是一個指針,但指針的類型依賴于request參數(shù)。
-
我們可以把和網(wǎng)絡(luò)相關(guān)的請求劃分為6類:
-
套接口操作
-
文件操作
-
接口操作
-
ARP高速緩存操作
-
路由表操作
-
流系統(tǒng)
-
下表列出了網(wǎng)絡(luò)相關(guān)ioctl請求的request參數(shù)以及arg地址必須指向的數(shù)據(jù)類型:
-
類別
|
Request
|
說明
|
數(shù)據(jù)類型
|
套
接
口
|
SIOCATMARK
SIOCSPGRP
SIOCGPGRP
|
是否位于帶外標(biāo)記
設(shè)置套接口的進(jìn)程ID或進(jìn)程組ID
獲取套接口的進(jìn)程ID或進(jìn)程組ID
|
int
int
int
|
文
件
|
FIONBIN
FIOASYNC
FIONREAD
FIOSETOWN
FIOGETOWN
|
設(shè)置/清除非阻塞I/O標(biāo)志
設(shè)置/清除信號驅(qū)動異步I/O標(biāo)志
獲取接收緩存區(qū)中的字節(jié)數(shù)
設(shè)置文件的進(jìn)程ID或進(jìn)程組ID
獲取文件的進(jìn)程ID或進(jìn)程組ID
|
int
int
int
int
int
|
接
口
|
SIOCGIFCONF
SIOCSIFADDR
SIOCGIFADDR
SIOCSIFFLAGS
SIOCGIFFLAGS
SIOCSIFDSTADDR
SIOCGIFDSTADDR
SIOCGIFBRDADDR
SIOCSIFBRDADDR
SIOCGIFNETMASK
SIOCSIFNETMASK
SIOCGIFMETRIC
SIOCSIFMETRIC
SIOCGIFMTU
SIOCxxx
|
獲取所有接口的清單
設(shè)置接口地址
獲取接口地址
設(shè)置接口標(biāo)志
獲取接口標(biāo)志
設(shè)置點(diǎn)到點(diǎn)地址
獲取點(diǎn)到點(diǎn)地址
獲取廣播地址
設(shè)置廣播地址
獲取子網(wǎng)掩碼
設(shè)置子網(wǎng)掩碼
獲取接口的測度
設(shè)置接口的測度
獲取接口MTU
(還有很多取決于系統(tǒng)的實(shí)現(xiàn))
|
struct ifconf
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
struct ifreq
|
ARP
|
SIOCSARP
SIOCGARP
SIOCDARP
|
創(chuàng)建/修改ARP表項(xiàng)
獲取ARP表項(xiàng)
刪除ARP表項(xiàng)
|
struct arpreq
struct arpreq
struct arpreq
|
路
由
|
SIOCADDRT
SIOCDELRT
|
增加路徑
刪除路徑
|
struct rtentry
struct rtentry
|
流
|
I_xxx
|
|
|
-
套接口操作:
-
明確用于套接口操作的ioctl請求有三個,它們都要求ioctl的第三個參數(shù)是指向某個整數(shù)的一個指針。
-
SIOCATMARK: 如果本套接口的的度指針當(dāng)前位于帶外標(biāo)記,那就通過由第三個參數(shù)指向的整數(shù)返回一個非0值;否則返回一個0值。POSIX以函數(shù)sockatmark替換本請求。
-
SIOCGPGRP: 通過第三個參數(shù)指向的整數(shù)返回本套接口的進(jìn)程ID或進(jìn)程組ID,該ID指定針對本套接口的SIGIO或SIGURG信號的接收進(jìn)程。本請求和fcntl的F_GETOWN命令等效,POSIX標(biāo)準(zhǔn)化的是fcntl函數(shù)。
-
SIOCSPGRP: 把本套接口的進(jìn)程ID或者進(jìn)程組ID設(shè)置成第三個參數(shù)指向的整數(shù),該ID指定針對本套接口的SIGIO或SIGURG信號的接收進(jìn)程,本請求和fcntl的F_SETOWN命令等效,POSIX標(biāo)準(zhǔn)化的是fcntl操作。
-
文件操作:
-
以下5個請求都要求ioctl的第三個參數(shù)指向一個整數(shù)。
-
FIONBIO: 根據(jù)ioctl的第三個參數(shù)指向一個0或非0值分別清除或設(shè)置本套接口的非阻塞標(biāo)志。本請求和O_NONBLOCK文件狀態(tài)標(biāo)志等效,而該標(biāo)志通過fcntl的F_SETFL命令清除或設(shè)置。
-
FIOASYNC: 根據(jù)iocl的第三個參數(shù)指向一個0值或非0值分別清除或設(shè)置針對本套接口的信號驅(qū)動異步I/O標(biāo)志,它決定是否收取針對本套接口的異步I/O信號(SIGIO)。本請求和O_ASYNC文件狀態(tài)標(biāo)志等效,而該標(biāo)志可以通過fcntl的F_SETFL命令清除或設(shè)置。
-
FIONREAD: 通過由ioctl的第三個參數(shù)指向的整數(shù)返回當(dāng)前在本套接口接收緩沖區(qū)中的字節(jié)數(shù)。本特性同樣適用于文件,管道和終端。
-
FIOSETOWN: 對于套接口和SIOCSPGRP等效。
-
FIOGETOWN: 對于套接口和SIOCGPGRP等效。
-
接口配置:
-
得到系統(tǒng)中所有接口由SIOCGIFCONF請求完成,該請求使用ifconf結(jié)構(gòu),ifconf又使用ifreq結(jié)構(gòu),如下所示:
-
Struct ifconf{
-
int ifc_len; // 緩沖區(qū)的大小
-
union{
-
caddr_t ifcu_buf; // input from user->kernel
-
struct ifreq *ifcu_req; // return of structures returned
-
}ifc_ifcu;
-
};
-
#define ifc_buf ifc_ifcu.ifcu_buf //buffer address
-
#define ifc_req ifc_ifcu.ifcu_req //array of structures returned
-
#define IFNAMSIZ 16
-
struct ifreq{
-
char ifr_name[IFNAMSIZ]; // interface name, e.g., “le0”
-
union{
-
struct sockaddr ifru_addr;
-
struct sockaddr ifru_dstaddr;
-
struct sockaddr ifru_broadaddr;
-
short ifru_flags;
-
int ifru_metric;
-
caddr_t ifru_data;
-
}ifr_ifru;
-
};
-
#define ifr_addr ifr_ifru.ifru_addr // address
-
#define ifr_dstaddr ifr_ifru.ifru_dstaddr // otner end of p-to-p link
-
#define ifr_broadaddr ifr_ifru.ifru_broadaddr // broadcast address
-
#define ifr_flags ifr_ifru.ifru_flags // flags
-
#define ifr_metric ifr_ifru.ifru_metric // metric
-
#define ifr_data ifr_ifru.ifru_data // for use by interface
-
再調(diào)用ioctl前我們必須先分撇一個緩沖區(qū)和一個ifconf結(jié)構(gòu),然后才初始化后者。如下圖展示了一個ifconf結(jié)構(gòu)的初始化結(jié)構(gòu),其中緩沖區(qū)的大小為1024,ioctl的第三個參數(shù)指向這樣一個ifconf結(jié)構(gòu)。
-
ifc_len 1024
|
Ifc_buf ---------->緩存
|
-
假設(shè)內(nèi)核返回2個ifreq結(jié)構(gòu),ioctl返回時通過同一個ifconf結(jié)構(gòu)緩沖區(qū)填入了那2個ifreq結(jié)構(gòu),ifconf結(jié)構(gòu)的ifc_len成員也被更新,以反映存放在緩沖區(qū)中的信息量
-
一般來講ioctl在用戶程序中的調(diào)用是:ioctl(int fd,int command, (char*)argstruct)
-
ioctl調(diào)用與網(wǎng)絡(luò)編程有關(guān)(本文只討論這一點(diǎn)),文件描述符fd實(shí)際上是由socket()系統(tǒng)調(diào)用返回的。參數(shù)command的取值由/usr/include/linux/sockios.h所規(guī)定。這些command的由于功能的不同,可分為以下幾個小類:
-
• 改變路由表 (例如 SIOCADDRT, SIOCDELRT),
-
• 讀/更新 ARP/RARP 緩存(如:SIOCDARP, SIOCSRARP),
-
• 一般的與網(wǎng)絡(luò)接口有關(guān)的(例如 SIOCGIFNAME, SIOCSIFADDR 等等)
-
在Gooodies 目錄下有很多樣例程序展示了如何使用ioctl。當(dāng)你看這些程序時,注意參數(shù)argstruct是與參數(shù)command相關(guān)的。例如,與路由表相關(guān)的 ioctl使用rtentry這種結(jié)構(gòu),rtentry定義在/usr/include/linux/route.h(參見例子 adddefault.c)。與ARP有關(guān)的ioctl調(diào)用使用arpreq結(jié)構(gòu),arpreq定義在 /usr/include/linux/if_arp.h(參見例子arpread.c)
-
與網(wǎng)絡(luò)接口有關(guān)的ioctl調(diào)用使用的command參數(shù)通??雌饋硐馭IOCxIFyyyy的形式,這里x要 么是S(設(shè)定set,寫write),要么是G(得到get,讀read)。在getifinfo.c程序中就使用了這種形式的command參數(shù)來讀 IP地址,硬件地址,廣播地址和得到與網(wǎng)絡(luò)接口有關(guān)的一些標(biāo)志(flag)。在這些ioctl調(diào)用中,第三個參數(shù)是ifreq結(jié)構(gòu),它在 /usr/include/linux/if.h中定義。在某些情況下, ioctrl調(diào)用可能會使用到在sockios.h之外的新的定義,例如,WaveLAN無線網(wǎng)絡(luò)卡會保存有關(guān)無線網(wǎng)絡(luò)信號強(qiáng)度的信息,這對用戶的程序可 能有用。但用戶怎么得到這種信息呢?我們的第一個本能是在sockios.h中定義新的ioctl命令,例如SIOCGIFWVLNSS(它的英文縮寫表 示W(wǎng)aveLAN的信號強(qiáng)度)。但不幸的是,這種命令不是對所有其他的網(wǎng)絡(luò)接口(例如:loopback環(huán)回接口)有意義,而且不應(yīng)當(dāng)允許對于 WAVLAN卡以外的網(wǎng)絡(luò)接口使用ioctl命令。那么,我們需要的是這樣一種機(jī)制:它能夠定義一種與網(wǎng)絡(luò)接口相關(guān)的ioctl命令。幸運(yùn)的是,在 Linux操作系統(tǒng)中已經(jīng)為實(shí)現(xiàn)這個目的內(nèi)建了一種掛鉤(hook)機(jī)制。當(dāng)你再次看sockios.h文件時,你將發(fā)現(xiàn)每一種設(shè)備已經(jīng)預(yù)先定義了 SIOCDEVPRIVATE的ioctl命令。而它的實(shí)現(xiàn)將留給開發(fā)相應(yīng)驅(qū)動程序的人去完成。
-
通常,一個用戶程序使用ioctl (sockid,SIOCDEVPRIVATE,(char*)&ifr)來調(diào)用與某種設(shè)備(指像WaveLAN那樣的特殊設(shè)備)相關(guān)的 ioctl命令,這里ifr是struct ifreq ifr形式的變量。用戶程序應(yīng)當(dāng)在ifr.ifr_name中填充與這個設(shè)備相關(guān)的名字,例如,假設(shè)WaveLAN使用的接口號為eth1。一般的,一個 用戶程序還需要與內(nèi)核互相交換ioctl的command參數(shù)和結(jié)果,這可以通過ifr.ifr_data這個變量來實(shí)現(xiàn),例如,想得到WaveLAN中 表示信號強(qiáng)度的信息時,可以通過返回這個變量來實(shí)現(xiàn)。Linux的源代碼已經(jīng)包括了兩種設(shè)備de4x5和ewrk3,它們定義并且實(shí)現(xiàn)了特定的ioctl 調(diào)用。這兩個設(shè)備的源代碼在de4x5.h,de4x5.c,ewrk3.h,ewrk3.c中(在 /usr/src/linux/drivers/net/目錄中)。這兩種設(shè)備都定義了它們特有的結(jié)構(gòu)(struct ewrk3_ioctl 和 struct de4x5_ioctl)來方便用戶程序和設(shè)備驅(qū)動之間交換信息。每次調(diào)用ioctl前,用戶程序應(yīng)當(dāng)在相應(yīng)的結(jié)構(gòu)變量中設(shè)定合適的初值,并且將 ifr.ifr_data指向該值。
-
在我們進(jìn)一步討論ewrk3和de4x5的代碼前,讓我們仔細(xì)看看ioctl調(diào)用是如何一步步地實(shí)現(xiàn)的。所有的和接口相關(guān)的ioctl請求 (SIOCxIFyyyy 和 SIOCDEVPRIVATE)將會調(diào)用dev_ioctl()(在/usr/src/linux/net/core/dev.c中)。但這只是一個包裝 器(wrapper),實(shí)際的動作將由dev_ifsioc()(也在dev.c中)來實(shí)現(xiàn)。差不多dev_ioctl()這個函數(shù)所做的所有工作只是檢 查這個調(diào)用是否已經(jīng)有了正當(dāng)?shù)臋?quán)限(例如,改變路由表需要有root的權(quán)限)。而dev_ifsioc()這個函數(shù)首先要做的一些事情包括得到與 ifr.ifr_name相匹配的設(shè)備的結(jié)構(gòu)(在/usr/include/linux/netdevice.h中定義)。但這是在實(shí)現(xiàn)特定的接口命令 (例如:SIOCGIFADDR)之后。這些特定的接口命令被放置到一個巨大的switch語句之中。其中SIOCDEVPRIVATE命令和其他的在 0x89F0到0x89FF之間的代碼將出現(xiàn)在switch語句中的一個分支——default語句中。內(nèi)核會檢查表示設(shè)備的結(jié)構(gòu)變量中,是否已經(jīng)定義了 一個與設(shè)備相關(guān)的ioctl句柄(handler)。這里的句柄是一個函數(shù)指針,它在表示設(shè)備的結(jié)構(gòu)變量中do_ioctl部分。如果已經(jīng)設(shè)置了這個句 柄,那么內(nèi)核將會執(zhí)行它。
-
所以,如果要實(shí)現(xiàn)一個與設(shè)備相關(guān)的ioctl命令,所要做的只是編寫一個與這個設(shè)備相關(guān)的ioctl句柄,并且將表示這 個設(shè)備的結(jié)構(gòu)變量中do_ioctl部分指向這個句柄。對于ewrk3這個設(shè)備,它的句柄是ewrk3_ioctl()(在ewrk3.c里面)并且相應(yīng) 的表示該設(shè)備的結(jié)構(gòu)變量由ewrk3_init()來初始化。在ewrk3_ioctl()的代碼中清晰的指出ifr.ifr_data是用作設(shè)備驅(qū)動程 序和用戶程序之間交換信息的。注意,這部分的內(nèi)存可以雙向的交流信息。例如,在ewrk3的驅(qū)動程序代碼中,if.ifr_data的頭兩個字節(jié)是用來表 示特殊的動作(例如,EWRK3_SET_PROM,EWRK3_CLR_PROM),而這個動作是符合使用者(驅(qū)動程序?qū)崿F(xiàn)了多個與設(shè)備相關(guān)的、由 SIOCDEVPRIVATE調(diào)用的命令)的要求的。另外,ifr.ifr_data中第5個字節(jié)指向的緩沖區(qū)(buffer)被用來交換其他的信息 (如:當(dāng)使用EWRK3_SET_HWADDR和EWRK3_GET_HWADDR時為硬件地址)
-
在你深入ewrk3_ioctl()時,請注意一般情況下一個用戶進(jìn)程不能直接訪問內(nèi)核所在的內(nèi)存。為此,驅(qū)動開發(fā)者可以使用兩個特殊的函數(shù) memcpy_tofs()和memcpy_fromfs()。內(nèi)核函數(shù)memcpy_tofs(arg1, arg2, arg3) 從地址arg2(用戶空間)向地址arg1(內(nèi)核空間)拷貝arg3個字節(jié)。類似的,memcpy_fromfs(arg1,arg2,arg3)從地址 arg2(用戶空間)向地址arg1(內(nèi)核空間)拷貝arg3個字節(jié)。在這些調(diào)用之前,verify_area()將會檢查這個進(jìn)程是否擁有合適的訪問權(quán) 限。另外,注意使用printk()函數(shù)可以輸出debug信息。這個函數(shù)與printf()函數(shù)類似,但不能處理浮點(diǎn)類型的數(shù)。內(nèi)核代碼不能夠使用 printf()函數(shù)。printk()函數(shù)產(chǎn)生的結(jié)果將記錄在/usr/adm/messages里。如果想知道更多的關(guān)于這些函數(shù)的或者與它們相關(guān)的 信息,可以參考《Linux Kernel Hacker’s Guide》(在Linux文檔網(wǎng)站的首頁) 這本書中Supporting Functions部分。
-
-
使用ioctl與內(nèi)核交換數(shù)據(jù)
-
1. 前言
-
使用ioctl系統(tǒng)調(diào)用是用戶空間向內(nèi)核交換數(shù)據(jù)的常用方法之一,從ioctl這個名稱上看,本意是針對I/O設(shè)備進(jìn)行的控制操作,但實(shí)際并不限制是真正的I/O設(shè)備,可以是任何一個內(nèi)核設(shè)備即可。
-
2. 基本過程
-
在內(nèi)核空間中ioctl是很多內(nèi)核操作結(jié)構(gòu)的一個成員函數(shù),如文件操作結(jié)構(gòu)struct file_operations(include/linux/fs.h)、協(xié)議操作結(jié)構(gòu)struct proto_ops(include/linux/net.h)等、tty操作結(jié)構(gòu)struct tty_driver(include/linux/tty_driver.h)等,而這些操作結(jié)構(gòu)分別對應(yīng)各種內(nèi)核設(shè)備,只要在用戶空間打開這些設(shè)備, 如I/O設(shè)備可用open(2)打開,網(wǎng)絡(luò)協(xié)議可用socket(2)打開等,獲取一個文件描述符后,就可以在這個描述符上調(diào)用ioctl(2)來向內(nèi)核 交換數(shù)據(jù)。
-
3. ioctl(2)
-
ioctl(2)函數(shù)的基本使用格式為:int ioctl(int fd, int cmd, void *data)
-
第一個參數(shù)是文件描述符;cmd是操作命令,一般分為GET、SET以及其他類型命令,GET是用戶空間進(jìn)程從內(nèi)核讀數(shù)據(jù),SET是用戶空間進(jìn)程向內(nèi)核寫數(shù)據(jù),cmd雖然是一個整數(shù),但是有一定的參數(shù)格式的,下面再詳細(xì)說明;第三個參數(shù)是數(shù)據(jù)起始位置指針,
-
cmd命令參數(shù)是個32位整數(shù),分為四部分:dir(2b) size(14b) type(8b) nr(8b)
-
詳細(xì)定義cmd要包括這4個部分時可使用宏_IOC(dir,type,nr,size)來定義,而最簡單情況下使用_IO(type, nr)來定義就可以了,這些宏都在include/asm/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操作,可以有兩個方式,一種是在現(xiàn)有的內(nèi)核代碼中直接添加相關(guān)代碼進(jìn)行支持,比如想通過socket描述符進(jìn)行 ioctl操作,可在net/ipv4/af_inet.c中的inet_ioctl()函數(shù)中添加自己定義的命令和相關(guān)的處理函數(shù),重新編譯內(nèi)核即可, 不過這種方法一般不推薦;第二種方法是定義自己的內(nèi)核設(shè)備,通過設(shè)備的ioctl()來操作,可以編成模塊,這樣不影響原有的內(nèi)核,這是最通常的做法。
-
4. 內(nèi)核設(shè)備
-
為進(jìn)行ioctl操作最通常是使用字符設(shè)備來進(jìn)行,當(dāng)然定義其他類型的設(shè)備也可以。在用戶空間,可使用mknod命令建立一個字符類型設(shè)備文件,假設(shè)該設(shè)備的主設(shè)備號為123,次設(shè)備號為0:
-
mknode /dev/newchar c 123 0
-
如果是編程的話,可以用mknode(2)函數(shù)來建立設(shè)備文件。
-
建立設(shè)備文件后再將該設(shè)備的內(nèi)核模塊文件插入內(nèi)核,就可以使用open(2)打開/dev/newchar文件,然后調(diào)用ioctl(2)來傳遞數(shù)據(jù),最后用close(2)關(guān)閉設(shè)備。而如果內(nèi)核中還沒有插入該設(shè)備的模塊,open(2)時就會失敗。
-
由于內(nèi)核內(nèi)存空間和用戶內(nèi)存空間不同,要將內(nèi)核數(shù)據(jù)拷貝到用戶空間,要使用專用拷貝函數(shù)copy_to_user();要將用戶空間數(shù)據(jù)拷貝到內(nèi)核,要使用copy_from_user()。
-
要最簡單實(shí)現(xiàn)以上功能,內(nèi)核模塊只需要實(shí)現(xiàn)設(shè)備的open, ioctl和release三個函數(shù)即可,下面介紹程序片斷:
-
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);
-
// 定義文件操作結(jié)構(gòu),結(jié)構(gòu)中其他元素為空
-
struct file_operations newchar_fops =
-
{
-
owner: THIS_MODULE,
-
ioctl: newchar_ioctl,
-
open: newchar_open,
-
release: newchar_release,
-
};
-
// 定義要傳輸?shù)臄?shù)據(jù)塊結(jié)構(gòu)
-
struct newchar{
-
int a;
-
int b;
-
};
-
#define MAJOR_DEV_NUM 123
-
#define DEVICE_NAME "newchar"
-
打開設(shè)備,非常簡單,就是增加模塊計數(shù)器,防止在打開設(shè)備的情況下刪除模塊,當(dāng)然想搞得復(fù)雜的話可進(jìn)行各種限制檢查,如只允許指定的用戶打開等:
-
static int newchar_open(struct inode *inode, struct file *filep)
-
{
-
MOD_INC_USE_COUNT;
-
return 0;
-
}
-
關(guān)閉設(shè)備,也很簡單,減模塊計數(shù)器:
-
static int newchar_release(struct inode *inode, struct file *filep)
-
{
-
MOD_DEC_USE_COUNT;
-
return 0;
-
}
-
進(jìn)行ioctl調(diào)用的基本處理函數(shù)
-
static int newchar_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
-
{
-
int ret;
-
// 首先檢查cmd是否合法
-
if (_IOC_TYPE(cmd) != NEWCHAR_IOC_MAGIC) return -EINVAL;
-
if (_IOC_NR(cmd) > NEWCHAR_IOC_MAXNR) return -EINVAL;
-
// 錯誤情況下的缺省返回值
-
ret = EINVAL;
-
switch(cmd)
-
{
-
case KNEWCHAR_SET:
-
// 設(shè)置操作,將數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間
-
{
-
struct newchar nc;
-
if(copy_from_user(&nc, (const char*)arg, sizeof(nc)) != 0)
-
return -EFAULT;
-
ret = do_set_newchar(&nc);
-
}
-
break;
-
case KNEWCHAR_GET:
-
// GET操作通常會在數(shù)據(jù)緩沖區(qū)中先傳遞部分初始值作為數(shù)據(jù)查找條件,獲取全部
-
// 數(shù)據(jù)后重新寫回緩沖區(qū)
-
// 當(dāng)然也可以根據(jù)具體情況什么也不傳入直接向內(nèi)核獲取數(shù)據(jù)
-
{
-
struct newchar nc;
-
if(copy_from_user(&nc, (const char*)arg, sizeof(nc)) != 0)
-
return -EFAULT;
-
ret = do_get_newchar(&nc);
-
if(ret == 0){
-
if(copy_to_user((unsigned char *)arg, &nc, sizeof(nc))!=0)
-
return -EFAULT;
-
}
-
}
-
break;
-
}
-
return ret;
-
}
-
模塊初始化函數(shù),登記字符設(shè)備
-
static int __init _init(void)
-
{
-
int result;
-
// 登記該字符設(shè)備,這是2.4以前的基本方法,到2.6后有了些變化,
-
// 是使用MKDEV和cdev_init()來進(jìn)行,本文還是按老方法
-
result = register_chrdev(MAJOR_DEV_NUM, DEVICE_NAME, &newchar_fops);
-
if (result < 0) {
-
printk(KERN_WARNING __FUNCTION__ ": failed register character device for /dev/newchar\n");
-
return result;
-
}
-
return 0;
-
}
-
模塊退出函數(shù),登出字符設(shè)備
-
static void __exit _cleanup(void)
-
{
-
int result;
-
result = unregister_chrdev(MAJOR_DEV_NUM, DEVICE_NAME);
-
if (result < 0)
-
printk(__FUNCTION__ ": failed unregister character device for /dev/newchar\n");
-
return;
-
}
-
module_init(_init);
-
module_exit(_cleanup);
-
5. 結(jié)論
-
用ioctl()在用戶空間和內(nèi)核空間傳遞數(shù)據(jù)是最常用方法之一,比較簡單方便,而且可以在同一個ioctl中對不同的命令傳送不同的數(shù)據(jù)結(jié)構(gòu),本文只是為描述方便而在不同命令中使用了相同的數(shù)據(jù)結(jié)構(gòu)。
-
轉(zhuǎn)載:http://yfydz.
-
-