新聞中心
Linux是一個開放源代碼的操作系統(tǒng),它給開發(fā)者提供了許多強大的工具和框架,方便他們開發(fā)驅動程序、系統(tǒng)軟件、網絡應用等各種應用程序。其中,驅動程序是Linux系統(tǒng)的一個關鍵部分,因為它控制硬件設備的輸入和輸出,與內核交互,負責從設備中讀取數據和向設備中寫入數據。

創(chuàng)新互聯專注于鄂溫克網站建設服務及定制,我們擁有豐富的企業(yè)做網站經驗。 熱誠為您提供鄂溫克營銷型網站建設,鄂溫克網站制作、鄂溫克網頁設計、鄂溫克網站官網定制、小程序設計服務,打造鄂溫克網絡公司原創(chuàng)品牌,更為您提供鄂溫克網站排名全網營銷落地服務。
在Linux中,文件I/O是一種非常常見和實用的操作,因為它使應用程序可以通過文件系統(tǒng)讀取和寫入數據。而Linux驅動程序就可以通過文件I/O API和文件系統(tǒng)交互,實現對設備的讀寫操作。這篇文章將主要介紹文件讀寫操作在Linux驅動程序中的應用。
1.文件I/O API簡介
對于Linux驅動程序,文件I/O API是一個非常重要的接口,它提供了諸如open、close、read、write、ioctl等函數,這些函數是文件句柄的一部分,并且可以與用戶進程進行交互。下面簡單介紹一下這些API函數的作用:
1.1. open函數
open函數是用于打開文件的函數,其定義為int open(const char *path, int flags, mode_t mode)。在Linux中,每一個進程都有一個類似于文件句柄的數據結構,叫做文件描述符。open函數在打開文件時會返回一個文件描述符,這個文件描述符是用戶進程與內核之間聯系的唯一標識符。在驅動程序中,開發(fā)者可以通過open函數打開設備,并且跟蹤該設備的狀態(tài)。
1.2. close函數
close函數是用于關閉文件、釋放文件描述符的函數,其定義為int close(int fd)。close函數在完成驅動程序對設備的操作之后,用于關閉設備,釋放相關資源。這個函數的調用會引起驅動程序中的close函數處理,從而完成對設備的關閉操作。
1.3. read函數
read函數是用于從設備中讀取數據的函數,其定義為ssize_t read(int fd, void *buf, size_t count)。在驅動程序中,開發(fā)者可以通過read函數讀取從設備傳輸的數據,從而實現數據的接收。在調用read函數時,內核會將各個請求進行合并,以減少內核調用的次數,從而提高I/O性能。
1.4. write函數
write函數是用于向設備中寫入數據的函數,其定義為ssize_t write(int fd, const void *buf, size_t count)。在驅動程序中,開發(fā)者可以通過write函數將數據寫入設備中,以實現對設備的控制。當調用write函數時,內核會將數據緩存,并且在idle時段將數據寫入設備。
1.5. ioctl函數
ioctl函數是用于進行設備控制的函數,其定義為int ioctl(int fd, unsigned int cmd, unsigned long arg)。在開發(fā)驅動程序時,開發(fā)者可以使用ioctl函數直接進行設備控制,這樣能夠方便地實現自定義操作。ioctl函數不是標準的POSIX函數,因此它具有不同的命名空間,不同的ioctl命令需要采用不同的編號空間。
2.示例:LED驅動程序
現在,我們來看一個具體的例子:LED驅動程序。這個驅動程序中,我們可以通過文件I/O操作控制LED的開關,讓它一直處于開啟或關閉狀態(tài)。
2.1. 設備注冊和初始化
在Led驅動程序中,我們需要對設備進行注冊并且進行設備初始化。在驅動程序中,設備注冊是通過設備模型實現的,也就是說,我們需要注冊設備模型,然后再注冊設備。在驅動程序中,設備結構體包含了設備相關的所有屬性,這樣就可以讓驅動程序與應用程序進行交互。
2.2. 設備打開和關閉操作
設備打開和關閉操作是針對應用程序,提供了與驅動程序交互的接口。在打開設備時,可以使用open函數,同樣,在關閉設備時,可以使用close函數,在這些函數中,開發(fā)者可以實現一些特定的操作,例如在打開設備時,可以執(zhí)行一些初始化操作,而關閉設備時,可以進行一些善后工作。
2.3. 數據讀取和寫入操作
數據讀取和寫入操作是我們在驅動程序中經常使用的操作,通過這些操作,我們可以實現數據的傳遞。在讀取設備數據時,可以使用read函數,而在向設備中寫入數據時,可以使用write函數,這樣就能實現設備數據傳輸的功能。同時,在實現LED驅動程序的過程中,開發(fā)者還可以使用ioctl函數控制設備狀態(tài)。
3.結論
在Linux驅動程序中,文件讀寫操作是一個非常常用,實用的操作。它可以實現數據的傳遞和控制設備狀態(tài)。在Linux中,有許多基礎API可以執(zhí)行文件讀寫操作,例如open、close、read、write和ioctl函數。通過這些函數,驅動程序可以更加方便地控制設備,并且實現數據傳輸。在開發(fā)驅動程序時,我們可以利用這些API,從而更好地實現各種功能。特別是在一些Linux內核模塊和驅動程序中,文件讀寫操作是不可或缺的,因此需要對其進行深入了解。
相關問題拓展閱讀:
- 如何系統(tǒng)的學習Linux驅動開發(fā)
如何系統(tǒng)的學習Linux驅動開發(fā)
可以讀讀內核源碼,比如說minix。你看的那本書還不錯,還有一本“設備驅動程序”,好像是電力出版社的。另外你可以搞兩臺虛擬機試著做做東西,寫程序經驗和感覺都很重要。
個人感覺書還是要紙質的書,確實如此,網上下的東西,看起來總覺得力不從心。
我個人的感覺是有興趣內核源碼要研究一下,很有幫助。另外有時候寫東西對概念的理解很重要,VC其實也不錯,因為現在會VC的人越來越少了,我曾經做過一段時間,那是n年前的事情了,因為一直做Linux和JAVA,現在已經徹底丟了,我們是做設備的,LInux,windows都需要做驅動,我們一直招這種人招不到,即使招到也是做應用的。
在學習之前一直對驅動開發(fā)非常的陌生,感覺有點神秘。不知道驅動開發(fā)和普通的程序開發(fā)究竟有什么不同;它的基本框架又是什么樣的;他的開發(fā)環(huán)境有什么特殊的地方;以及怎么寫編寫一個簡單的字符設備驅動前編譯加載,下面我就對這些問題一個一個的介紹。
一、驅動的基本框架
1. 那么究竟什么是驅動程序,它有什么用呢:
l 驅動是硬件設備與應用程序之間的一個中間軟件層
l 它使得某個特定硬件能夠響應一個定義良好的內部編程接口,同時完全隱蔽了設備的工作細節(jié)
l 用戶通過一組與具體設備無關的標準化的調用來完成相應的操作
l 驅動程序的任務就是把這些標準化的系統(tǒng)調用映射到具體設備對于實際硬件的特定操作上
l 驅動程序是內核的一部分,可以使用中斷、DMA等操作
l 驅動程序在用戶態(tài)和內核態(tài)之間傳遞數據
2. Linux驅動的基本框架
3. Linux下設備驅動程序的一般可以分為以下三類
1)字符設備
a)所有能夠象字節(jié)流一樣訪問的設備都通過字符設備來實現
b)它們被映射為文件系統(tǒng)中的節(jié)點,通常在/dev/目錄下面
c)一般要包含open read write close等系統(tǒng)調用的實現
2)塊設備
d)通常是指諸如磁盤、內存、Flash等可以容納文件系統(tǒng)的存儲設備。
e)塊設備也是通過文件系統(tǒng)來訪問,與字符設備的區(qū)別是:內核管理數據的方式不同
f)它允許象字符設備一樣以字節(jié)流的方式來訪問,也可一次傳遞任意多的字節(jié)。
3)網絡接口設備
g)通常它指的是硬件設備,但有時也可能是一個軟件設備(如回環(huán)接口loopback),它們由內核中網絡子系統(tǒng)驅動,負責發(fā)送和接收數據包。
h)它們的數據傳送往往不是面向流的,因此很難將它們映射到一個文件系統(tǒng)的節(jié)點上。
二、怎么搭建一個驅動的開發(fā)環(huán)境
因為驅動是要編譯進內核,在啟動內核時就會驅動此硬件設備;或者編譯生成一個.o文件, 當應用程序需要時再動態(tài)加載進內核空間運行。因此編譯任何一個驅動程序都要鏈接到內核的源碼樹。所以搭建環(huán)境的之一步當然是建內核源碼樹
1.怎么建內核源碼樹
a) 首先看你的系統(tǒng)有沒有源碼樹,在你的/lib/ modules目錄下會有內核信息,比如我當前的系統(tǒng)里有兩個版本:
#ls /lib/ modules
2.6.15-rc7 2.6.21-1.3194.fc7
查看其源碼位置:
## ll /lib/modules/2.6.15-rc7/build
lrwxrwxrwx 1 root root 19:19 /lib/modules/2.6.15-rc7/build -> /root/xkli/linux-2.6.15-rc7
發(fā)現build是一個鏈接文件,其所對應的目錄就是源碼樹的目錄。但現在這里目標目錄已經是無效的了。所以得自己重新下載
b)下載并編譯源碼樹
有很多網站上可以下載,但官方網址是:
下載完后當然就是解壓編譯了
# tar –xzvf linux-2.6.16.54.tar.gz
#cd linux-2.6.16.54
## make menuconfig (配置內核各選項,如果沒有配置就無法下一步編譯,這里可以不要改任何東西)
#make
…
如果編譯沒有出錯。那么恭喜你。你的開發(fā)環(huán)境已經搭建好了
三、了解驅動的基本知識
1.設備號
1)什么是設備號呢?我們進系統(tǒng)根據現有的設備來講解就清楚了:
#ls -l /dev/
crwxrwxrwx 1 root root 1,1 16:36 null
crwroot root 4,1 16:35 systty
crw-rw-rw- 1 root tty,1 16:36 tty
crw-rwroot tty,1 16:35 tty0
在日期前面的兩個數(如之一列就是1,3)就是表示的設備號,之一個是主設備號,第二個是從設備號
2)設備號有什么用呢?
l 傳統(tǒng)上, 主編號標識設備相連的驅動. 例如, /dev/null 和 /dev/zero 都由驅動 1 來管理, 而虛擬控制臺和串口終端都由驅動 4 管理
l 次編號被內核用來決定引用哪個設備. 依據你的驅動是如何編寫的自己區(qū)別
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 是你請求的連續(xù)設備編號的總數. name 是應當連接到這個編號范圍的設備的名子; 它會出現在 /proc/devices 和 sysfs 中.
l第二個是動態(tài)動態(tài)分配設備編號
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 結構). 這些操作大部分負責實現系統(tǒng)調用, 因此, 命名為 open, read, 等等
2)File
定義位于include/fs.h
struct file結構與驅動相關的成員
lmode_t f_mode 標識文件的讀寫權限
lloff_t f_pos當前讀寫位置
lunsigned int_f_flag 文件標志,主要進行阻塞/非阻塞型操作時檢查
lstruct file_operation * f_op 文件操作的結構指針
lvoid * private_data 驅動程序一般將它指向已經分配的數據
lstruct 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)為從系統(tǒng)去除一個字符設備, 調用:
void cdev_del(struct cdev *dev);
4.open 和 release
無根之木不活,無基之樓不立,無論是學習哪個領域知識,基礎是重中之重。
針對學習linux驅動,我們來仔細談談:
個人認為C語言和數據結構就是重中之重!Linux系統(tǒng)更優(yōu)秀的地方就在于內核。無論是進程調度,內存管理,還是數據的組織形式,而這些算法的基礎就是一個高效而精簡的數據結構,紅黑樹也好,內核鏈表也好,看不懂C語言,搞不清數據結構,基本上談不上做驅動。基礎不扎實不要談上層建筑,資源不全面就不要談合作,很簡單的道理。
假設樓主的C語言和數據結構都是勉強過關的(分得清指針函數函數指針,能夠熟練自定義鏈表并進行增刪改查等鏈表或樹的算法重組)。我們來談下一個階段,讓我們對類Unix系統(tǒng)的基本操作有一個基本的了解,打開文件,切換路經,更改個密碼,填個用戶什么的。
接下來我們來談驅動,做驅動就得有做驅動的樣子,不知道樓主之前玩過裸板51或者AVR沒有,如果沒有,盡快搞通,資源很多,跟著人家把電平配一遍,來個矩陣鍵盤,組個跑馬燈,有成就感的同時也打下了硬件基礎,好處大大滴。
基于操作系統(tǒng)的驅動,即必須了解內核對驅動程序的管理方法,怎樣劃分一個具體的設備,是字符型?塊設備?還是別的什么,或者從總線的角度來劃分一個設備,i2c也好,USB也罷,還是數據地址控制這么一個三總線形式,都是有必要掌握的東西。
上升到應用,任何一個實踐項目中很難會有一個板子讓你從零開始寫驅動,百分之九十九是拿來改,這就是一個熟練的過程,做到一定多的東西,就會下意識地覺得,這個地方可能會有問題,我需要留意一下。
總結一下,驅動工程師其實也是一種硬件翻譯型工程師,其任務就是看懂手冊上的表格,然后體現在代碼里面??陀^地說,我們這個行業(yè)門檻較高,隊友較少,不過等到真正入門之后,那種成就感是無與倫比的。
做嵌入式應用的話一般的編程就可以了。那么嵌入式驅動開發(fā)與內核開發(fā)的話就需要學習多個方面的知識。我就把這方面的要求給你交流一下:
(一家之言啊,自己多年從事嵌入式開發(fā)的一點感悟)
嵌入式驅動開發(fā)需要了解的知識大概有以下幾類:
1 嵌入式操作系統(tǒng)驅動框架。每一個操作系統(tǒng)都有自己的構架,應該了解驅動在整個系統(tǒng)中的具置與構建驅動程序的主要事項
2 總線知識,比如PCI、USB總線。
3 芯片知識。驅動其實就是對設備上一些寄存器的配置、CPU與設備本身的通訊以及對不同命令的處理
4 要做好驅動,必須對所使用的CPU體系結構有一個比較深刻的認識
5 C++基本用不上,主要是C和匯編。
6 做驅動更好要懂內核調試(比如說linux)
先熟悉module的使用和編寫
一、什么是module
從名字上看就是模塊的意思,我個人的理解就是一個一個的小程序,可以進行動態(tài)的安裝和卸載,而在這里面就實現一些功能,其中驅動就是在module中。
二、編寫一個最簡單的module
編寫一個最簡單的module只需要兩個文件即可:Makefile和xxx.c
(1)Makefile
1 #ubuntu的內核源碼樹,如果要編譯在ubuntu中安裝的模塊就打開這2個 2 #KERN_VER = $(shell uname -r) 3 #KERN_DIR = /lib/modules/$(KERN_VER)/build
6 #開發(fā)板的linux內核的源碼樹目錄 7 KERN_DIR = /root/3288_5.1/kernel
8 9 obj-m += module_test.o10 11 all:make -C $(KERN_DIR) M=`pwd` modules
13 14 .PHONY: clean
15 clean:make -C $(KERN_DIR) M=`pwd` modules clean
在上面的Makefile中,最核心的一句就是make -C $(KERN_DIR) M=`pwd` modules
這句話的意思就是進入到kernel的源碼目錄中,使用內核源碼中的編譯規(guī)格來進行編譯這個模塊。
其目的主要是為了將module和kernel保持一致,在加載module時就不會出錯。
(2)module_test.c
1 #include// module_init module_exit 2 #include// __init __exit 3 4 // 模塊安裝函數 5 static int __init chrdev_init(void) 6 {
7 printk(KERN_INFO “chrdev_init helloworld init\n”);return 0;10 }11 12 // 模塊卸載函數13 static void __exit chrdev_exit(void)14 {printk(KERN_INFO “chrdev_exit helloworld exit\n”);16 }17 18 module_init(chrdev_init);19 module_exit(chrdev_exit);20 21 // MODULE_xxx這種宏作用是用來添加模塊描述信息22 MODULE_LICENSE(“GPL”); // 描述模塊的許可證23 MODULE_AUTHOR(“xuan”); // 描述模塊的作者24 MODULE_DESCRIPTION(“module test”); // 描述模塊的介紹信息25 MODULE_ALIAS(“alias xxx”);// 描述模塊的別名信息
(3)編譯和安裝module
進入到代碼的文件夾中,輸入:make
然后,將生成的.ko文件放到平臺中,輸入:inod xxx.ko
根據這個思路去學習
建議在看看這本書《Linux就該這么學》
關于linux 驅動讀寫文件的介紹到此就結束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關注本站。
成都創(chuàng)新互聯建站主營:成都網站建設、網站維護、網站改版的網站建設公司,提供成都網站制作、成都網站建設、成都網站推廣、成都網站優(yōu)化seo、響應式移動網站開發(fā)制作等網站服務。
當前題目:Linux驅動程序:文件讀寫操作(linux驅動讀寫文件)
文章鏈接:http://m.5511xx.com/article/ccdpoji.html


咨詢
建站咨詢
