要明白虛擬文件系統之前必須先搞清楚什麼是文件。
狹義地說,「文件」是指「磁碟文件」,進而可以是有組織有次序地存儲於任何介質(包括內存)中的一組信息。廣義地說,凡是可以產生或消耗信息的都是文件。比方說設備文件、管道、套接字以及/proc目錄下的特殊文件(實際上只存在於內存中),這些都是「文件」。磁碟文件只不過是個特例而已,你可以認為他是在磁碟設備上存儲的、按照一定次序組織在一起的一組相關的信息。
上面這些是我從書上抄的,但我自己的看法是,計算機系統中所有內核向應用程序提供的信息輸入輸出介面都是文件。所以應用層看到的「文件」已經是被操作系統抽象過的一個輸入輸出介面。拿磁碟文件來說,對應用而言它看到的是一個個文件按照目錄結構組織起來的一棵樹,但實際上磁碟設備並不知道這么回事兒,它只認識磁頭、柱面和扇區。從這個角度上來說,應用程序看到的文件本身就是虛擬的。所謂的對文件操作最終都要落實到磁碟設備對某些扇區的讀寫上,但這些都是內核處理的,應用程序是看不見這一切的。
知道了廣義的文件系統定義之後就不難理解,作為一個通用操作系統,linux需要為用戶程序提供一個統一的系統操作界面來完成對各種文件的訪問。虛擬文件系VFS就是這么一個統一的、抽象的、虛擬的文件操作界面。你可以認為它是應用層與驅動層之間的一個中間層,對上提供一組標準的介面open/close/read/write/lseek,對下則又根據不同的文件類型調用不同的驅動程序提供的介面完成對具體設備的操作。這些操作通常是通過讀寫外設上(磁碟也是外設)的控制寄存器和存儲區間來完成的。
不知道我這樣解釋你明白了沒,要是還不明白可以看看我共享在網路知道上的《Linux內核源代碼情景分析》,那裡面有更詳細的說明。
B. 什麼是linux 平台驅動開發
在學習之前一直對驅動開發非常的陌生,感覺有點神秘。不知道驅動開發和普通的程序開發究竟有什麼不同;它的基本框架又是什麼樣的;他的開發環境有什麼特殊的地方;以及怎麼寫編寫一個簡單的字元設備驅動前編譯載入,下面我就對這些問題一個一個的介紹。
一、驅動的基本框架
1. 那麼究竟什麼是驅動程序,它有什麼用呢:
l 驅動是硬體設備與應用程序之間的一個中間軟體層
l 它使得某個特定硬體能夠響應一個定義良好的內部編程介面,同時完全隱蔽了設備的工作細節
l 用戶通過一組與具體設備無關的標准化的調用來完成相應的操作
l 驅動程序的任務就是把這些標准化的系統調用映射到具體設備對於實際硬體的特定操作上
l 驅動程序是內核的一部分,可以使用中斷、DMA等操作
l 驅動程序在用戶態和內核態之間傳遞數據
2. Linux驅動的基本框架
3. Linux下設備驅動程序的一般可以分為以下三類
1) 字元設備
a) 所有能夠象位元組流一樣訪問的設備都通過字元設備來實現
b) 它們被映射為文件系統中的節點,通常在/dev/目錄下面
c) 一般要包含open read write close等系統調用的實現
2) 塊設備
d) 通常是指諸如磁碟、內存、Flash等可以容納文件系統的存儲設備。
e) 塊設備也是通過文件系統來訪問,與字元設備的區別是:內核管理數據的方式不同
f) 它允許象字元設備一樣以位元組流的方式來訪問,也可一次傳遞任意多的位元組。
3) 網路介面設備
g) 通常它指的是硬體設備,但有時也可能是一個軟體設備(如回環介面loopback),它們由內核中網路子系統驅動,負責發送和接收數據包。
h) 它們的數據傳送往往不是面向流的,因此很難將它們映射到一個文件系統的節點上。
二、怎麼搭建一個驅動的開發環境
因為驅動是要編譯進內核,在啟動內核時就會驅動此硬體設備;或者編譯生成一個.o文件, 當應用程序需要時再動態載入進內核空間運行。因此編譯任何一個驅動程序都要鏈接到內核的源碼樹。所以搭建環境的第一步當然是建內核源碼樹
1. 怎麼建內核源碼樹
a) 首先看你的系統有沒有源碼樹,在你的/lib/ moles目錄下會有內核信息,比如我當前的系統里有兩個版本:
#ls /lib/ moles
2.6.15-rc7 2.6.21-1.3194.fc7
查看其源碼位置:
## ll /lib/moles/2.6.15-rc7/build
lrwxrwxrwx 1 root root 27 2008-04-28 19:19 /lib/moles/2.6.15-rc7/build -> /root/xkli/linux-2.6.15-rc7
發現build是一個鏈接文件,其所對應的目錄就是源碼樹的目錄。但現在這里目標目錄已經是無效的了。所以得自己重新下載
b)下載並編譯源碼樹
有很多網站上可以下載,但官方網址是:
http://www.kernel.org/pub/linux/kernel/v2.6/
下載完後當然就是解壓編譯了
# tar –xzvf linux-2.6.16.54.tar.gz
#cd linux-2.6.16.54
## make menuconfig (配置內核各選項,如果沒有配置就無法下一步編譯,這里可以不要改任何東西)
#make
…
如果編譯沒有出錯。那麼恭喜你。你的開發環境已經搭建好了
三、了解驅動的基本知識
1. 設備號
1) 什麼是設備號呢?我們進系統根據現有的設備來講解就清楚了:
#ls -l /dev/
crwxrwxrwx 1 root root 1, 3 2009-05-11 16:36 null
crw------- 1 root root 4, 0 2009-05-11 16:35 systty
crw-rw-rw- 1 root tty 5, 0 2009-05-11 16:36 tty
crw-rw---- 1 root tty 4, 0 2009-05-11 16:35 tty0
在日期前面的兩個數(如第一列就是1,3)就是表示的設備號,第一個是主設備號,第二個是從設備號
2) 設備號有什麼用呢?
l 傳統上, 主編號標識設備相連的驅動. 例如, /dev/null 和 /dev/zero 都由驅動 1 來管理, 而虛擬控制台和串口終端都由驅動 4 管理
l 次編號被內核用來決定引用哪個設備. 依據你的驅動是如何編寫的自己區別
3) 設備號結構類型以及申請方式
l 在內核中, dev_t 類型(在 中定義)用來持有設備編號, 對於 2.6.0 內核, dev_t 是 32 位的量, 12 位用作主編號, 20 位用作次編號.
l 能獲得一個 dev_t 的主或者次編號方式:
MAJOR(dev_t dev); //主要
MINOR(dev_t dev);//次要
l 但是如果你有主次編號, 需要將其轉換為一個 dev_t, 使用: MKDEV(int major, int minor);
4) 怎麼在程序中分配和釋放設備號
在建立一個字元驅動時需要做的第一件事是獲取一個或多個設備編號來使用. 可以達到此功能的函數有兩個:
l 一個是你自己事先知道設備號的
register_chrdev_region, 在 中聲明:
int register_chrdev_region(dev_t first, unsigned int count, char *name);
first 是你要分配的起始設備編號. first 的次編號部分常常是 0,count 是你請求的連續設備編號的總數. name 是應當連接到這個編號范圍的設備的名子; 它會出現在 /proc/devices 和 sysfs 中.
l 第二個是動態動態分配設備編號
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
使用這個函數, dev 是一個只輸出的參數, 它在函數成功完成時持有你的分配范圍的第一個數. fisetminor 應當是請求的第一個要用的次編號; 它常常是 0. count 和 name 參數如同給 request_chrdev_region 的一樣.
5) 設備編號的釋放使用
不管你是採用哪些方式分配的設備號。使用之後肯定是要釋放的,其方式如下:
void unregister_chrdev_region(dev_t first, unsigned int count);
6)
2. 驅動程序的二個最重要數據結構
1) file_operation
倒如字元設備scull的一般定義如下:
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
file_operation也稱為設備驅動程序介面
定義在 , 是一個函數指針的集合. 每個打開文件(內部用一個 file 結構來代表)與它自身的函數集合相關連( 通過包含一個稱為 f_op 的成員, 它指向一個 file_operations 結構). 這些操作大部分負責實現系統調用, 因此, 命名為 open, read, 等等
2) File
定義位於include/fs.h
struct file結構與驅動相關的成員
l mode_t f_mode 標識文件的讀寫許可權
l loff_t f_pos 當前讀寫位置
l unsigned int_f_flag 文件標志,主要進行阻塞/非阻塞型操作時檢查
l struct file_operation * f_op 文件操作的結構指針
l void * private_data 驅動程序一般將它指向已經分配的數據
l struct dentry* f_dentry 文件對應的目錄項結構
3. 字元設備注冊
1) 內核在內部使用類型 struct cdev 的結構來代表字元設備. 在內核調用你的設備操作前, 必須編寫分配並注冊一個或幾個這些結構. 有 2 種方法來分配和初始化一個這些結構.
l 如果你想在運行時獲得一個獨立的 cdev 結構,可以這樣使用:
struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
l 如果想將 cdev 結構嵌入一個你自己的設備特定的結構; 你應當初始化你已經分配的結構, 使用:
void cdev_init(struct cdev *cdev, struct file_operations *fops);
2) 一旦 cdev 結構建立, 最後的步驟是把它告訴內核, 調用:
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
說明:dev 是 cdev 結構, num 是這個設備響應的第一個設備號, count 是應當關聯到設備的設備號的數目. 常常 count 是 1, 但是有多個設備號對應於一個特定的設備的情形.
3) 為從系統去除一個字元設備, 調用:
void cdev_del(struct cdev *dev);
4. open 和 release
C. linux 內核 頭文件 (.h)中很多類似 struct file_operations; struct inode; struct mole;什麼意思
這個應該是內核中已經定義好了的結構名稱了:
struct file_operations是一個字元設備把驅動的操作和設備號聯系在一起的紐帶,是一系列指針的集合,每個被打開的文件都對應於一系列的操作,這就是file_operations,用來執行一系列的系統調用。
struct file代表一個打開的文件,在執行file_operation中的open操作時被創建,這里需要注意的是與用戶空間inode指針的區別,一個在內核,而file指針在用戶空間,由c庫來定義。
struct inode被內核用來代表一個文件,注意和struct file的區別,struct inode一個是代表文件,struct file一個是代表打開的文件。
樓主如果對Linux系統感興趣,想學習更多Linux系統知識,可以網路《Linux就該這么學》,不錯的一本Linux系統入門教程。
D. linux驅動 file_operations 中int (*open) (struct inode *, struct file *);這句話open是函數指針,
這是在定義函數指針,只需要形式參數個數,類型以及返回值類型就可以決定函數指針的類型,至於形參的名字,無論叫什麼都是沒有影響的,因此不必要寫出形參的名字。
你可以寫xx,不過也會被忽略。
E. linux的很多platform_driver 里沒有 file_operations,該如何使用
一般你去找,都會有的,只是你沒有深入去看代碼可以。file的操作不一定在init裡面
F. Linux中修改文件許可權是說Operation not permitted
原因:帶有i屬性的文件是不能修改的。
1、首先執行chmod 777 /etc/sysctl.conf時會報出錯誤:chmod: changing permissions of '/etc/sysctl.conf': Operation not permitted。