int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
這是驅動程式裝置控制介面函式(ioctl函式)的核心原型定義,
struct inode * 和
struct file* 描述了操作的檔案,unsigned int 描述了ioctl命令號,這是乙個重要的引數,我們稍後會對它做詳細介紹。最後乙個引數是unsigned long資料型別,描述了ioctl命令可能帶有的引數,它可能是乙個整數或指標資料。
ioctl命令號是這個函式中最重要的引數,它描述的ioctl要處理的命令。linux中使用乙個32位的資料來編碼ioctl命令,它包含四個部分:dir:type:nr:size。
代表資料傳輸的方向,佔2位,可以是_ioc_none(無資料傳輸,0u),_ioc_write(向裝置寫資料,1u)或_ioc_read(從裝置讀資料,2u)或他們的邏輯或組合,當然只有_ioc_write和_ioc_read的邏輯或才有意義。
描述了ioctl命令的型別,8位。每種裝置或系統都可以指定自己的乙個型別號,ioctl用這個型別來表示ioctl命令所屬的裝置或驅動。一般用ascii碼字元來表示,如 'a'。
ioctl命令序號,一般8位。對於乙個指定的裝置驅動,可以對它的ioctl命令做乙個順序編碼,一般從零開始,這個編碼就是ioctl命令的序號。
ioctl命令的引數大小,一般14位。ioctl命令號的這個資料成員不是強制使用的,你可以不使用它,但是我們建議你指定這個資料成員,通過它我們可以檢查使用者空間資料的大小以避免錯誤的資料操作,也可以實現相容舊版本的ioctl命令。
我們可以自己來直接指定乙個ioctl命令號,它可能僅僅是乙個整數集,但linux中的ioctl命令號都是有特定含義的,因此通常我們不推薦這麼做。其實linux核心已經提供了相應的巨集來自動生成ioctl命令號:
_io(type,nr)
_ior(type,nr,size)
_iow(type,nr,size)
_iowr(type,nr,size)
巨集_io用於無資料傳輸,巨集_ior用於從裝置讀資料,巨集 _iow用於向裝置寫資料,巨集_iowr用於同時有讀寫資料的ioctl命令。相對的,linux核心也提供了相應的巨集來從ioctl命令號種解碼相應的域值:
_ioc_dir(nr)
_ioc_type(nr)
_ioc_nr(nr)
_ioc_size(nr)
這些巨集都定義在標頭檔案中(一般在標頭檔案中)。一般在使用中,先指定各個ioctl命令的順序編號(一般從0開始),然後根據使用的環境用這些巨集來自動生成ioctl命令號,在後面的例子中你可以了解實際的使用場景。
ioctl函式的返回值是乙個整數型別的值,如果命令執行成功,ioctl返回零,如果出現錯誤,ioctl函式應該返回乙個負值。這個負值會作為errno值反饋給呼叫此ioctl的使用者空間程式。關於返回值的具體含義,請參考和標頭檔案。
這裡有必要說明一下ioctl命令的引數,因為它很容易犯錯誤。如果ioctl命令引數僅僅是乙個整數,那麼事情很簡單了,我們可以在ioctl函式中直接使用它。但如果它是乙個指標資料,那麼使用上就要小心了。首先要說明這個引數是有使用者空間的程式傳遞過來的,因此這個指標指向的位址是使用者空間位址,在linux中,使用者空間位址是乙個虛擬位址,在核心空間是無法直接使用它的。為了解決在核心空間使用使用者空間位址的資料,linux核心提供了以下函式,它們用於在核心空間訪問使用者空間的資料,定義在標頭檔案中:
unsigned long __must_check copy_to_user(void __user *to,
const void *from, unsigned long n);
unsigned long __must_check copy_from_user(void *to,
const void __user *from, unsigned long n);
copy_from_user和copy_to_user一般用於複雜的或大資料交換,對於簡單的資料型別,如int或char,核心提供了簡單的巨集來實現這個功能:
#define get_user(x,ptr)
#define put_user(x,ptr)
其中,x是核心空間的簡單資料型別位址,ptr是使用者空間位址指標。
這裡有必要再一次強調的是,在核心模組或驅動程式的編寫中,我們強烈建議你使用核心提供的介面來生成並操作ioctl命令號,這樣可以對命令號賦予特定的含義,使我們的程式更加的健壯;另一方面也可以提高程式的可移植性。 舉例
好了,是時候舉個例子了。我們將擴充套件我們的helloworld驅動新增ioctl函式。
首先,我們新增乙個標頭檔案來定義ioctl介面需要用到的資料(hello.h):
#ifndef _hello_h
#define _hello_h
#include
#define maxbuf 20
typedef struct _buf_databuf_data;
#define hello_ioctl_nr_base 0
#define hello_ioctl_nr_set_data (hello_ioctl_nr_base + 1)
#define hello_ioctl_nr_max (hello_ioctl_nr_get_buff + 1)
#define hello_ioctl_set_data _ior('h', hello_ioctl_nr_set_data, buf_data*)
#endif
然後為我們的驅動程式新增ioctl介面hello_ioctl,並實現這個函式:
static int hello_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
memset(hello_buf, 0, sizeof(hello_buf));
memcpy(hello_buf, buff.data, buff.size);
break;
default:
printk("hello_ioctl: unknown ioctl command (%d)\n", cmd);
break;
}error:
return err;
}static struct file_operations hello_fops = ;
後記到這裡我們已經向您展示了linux核心驅動程式的裝置控制介面(ioctl介面),詳細的介紹了它的使用,並給出了乙個實際的例子,儘管它很簡單,但已經足夠了。到這裡你可以寫出乙個標準的linux驅動程式了。不過這裡還有個問題,那就是我們不得不從/proc/devices檔案裡讀取裝置號然後手動建立裝置節點。我們是否可以讓系統自動的建立這個裝置節點檔案呢?當然可以。不過在那之前,我們必須深入了解linux的裝置驅動模型。
ioctl引數詳解
本函式影響由fd引數引用的乙個開啟的檔案。include int ioctl int fd,int request,返回0 成功 1 出錯 第三個引數總是乙個指標,但指標的型別依賴於request引數。套介面操作 檔案操作 介面操作 arp快取記憶體操作 路由表操作 流系統類別request 說明資...
ioctl方法詳解
int ioctl struct inode struct file unsigned int,unsigned long 這是驅動程式裝置控制介面函式 ioctl函式 的核心原型定義,struct inode 和 struct file 描述了操作的檔案,unsigned int 描述了ioctl...
ioctl函式介紹
我這裡說的ioctl函式是在驅動程式裡的,因為我不知道還有沒有別的場合用到了ioctl,所以就規定了我們討論的範圍。為什麼要寫篇文章呢,是因為我前一陣子被ioctl給搞混 了,這幾天才弄明白它,於是在這裡清理一下頭腦。一 什麼是ioctl。ioctl是裝置驅動程式中對裝置的i o通道進行管理的函式。...