Linux 字符设备驱动开发基础(三)—— read()、write() 相关函数解析
我們在前面講到了file_operations,其是一個函數(shù)指針的集合,用于存放我們定義的用于操作設(shè)備的函數(shù)的指針,如果我們不定義,它默認保留為NULL。其中有最重要的幾個函數(shù),分別是open()、read()、write()、ioctl(),下面分別對其進行解析
? ? ?
一、 打開和關(guān)閉設(shè)備函數(shù)
a -- 打開設(shè)備
? ????int (*open) (struct inode *, struct file *);
在操作設(shè)備前必須先調(diào)用open函數(shù)打開文件,可以干一些需要的初始化操作。當(dāng)然,如果不實現(xiàn)這個函數(shù)的話,驅(qū)動會默認設(shè)備的打開永遠成功。打開成功時open返回0。
b -- 關(guān)閉設(shè)備 ?????
? ? ??int (*release) (struct inode *, struct file *);
當(dāng)設(shè)備文件被關(guān)閉時內(nèi)核會調(diào)用這個操作,當(dāng)然這也可以不實現(xiàn),函數(shù)默認為NULL。關(guān)閉設(shè)備永遠成功。
這兩個函數(shù)已經(jīng)講過,這里不再贅述,主要看下面幾個函數(shù)
二、read()、write() 函數(shù)
? ? ? ? 現(xiàn)在把 read()、write() 兩個函數(shù)放一起講,因為兩個函數(shù)非密不可分的,先看一下兩個函數(shù)的定義?
a -- read() 函數(shù)
| ? ?函數(shù)原型 | ? ? ? ???ssize_t (*read) (struct file * filp, char __user * buffer, size_t ? ?size , loff_t * p);? |
| ? ?參數(shù)含義 | ?filp ? ? ? :為進行讀取信息的目標(biāo)文件, ?buffer ?:為對應(yīng)放置信息的緩沖區(qū)(即用戶空間內(nèi)存地址); ?size ? ? :為要讀取的信息長度; ?p ? ? ? ? ?:為讀的位置相對于文件開頭的偏移,在讀取信息后,這個指針一般都會移動, ? ? ? ? ? ? ? ? ?移動的值為要讀取信息的長度值 |
b -- write() 函數(shù)
| ? ?函數(shù)原型 | ? ? ? ???ssize_t (*write) (struct file * filp, const char __user * ? buffer, size_t count, loff_t * ppos);? |
| ? ?參數(shù)含義 | filp ? ? ?:為目標(biāo)文件結(jié)構(gòu)體指針; buffer :為要寫入文件的信息緩沖區(qū); count ?:為要寫入信息的長度; ppos ? :為當(dāng)前的偏移位置,這個值通常是用來判斷寫文件是否越界 |
? ? ? ? ?
? ? ? ?兩個函數(shù)的作用分別是?從設(shè)備中獲取數(shù)據(jù)及發(fā)送數(shù)據(jù)給設(shè)備,應(yīng)用程序中與之對應(yīng)的也有 write() 函數(shù)及 read() 函數(shù):
| ? ? len = read(fd,buf,len) ? ? len = write(fd,buf,size) | static?ssize_t?hello_read(struct?file?*filep,?char?__user?*buf,?size_t?len,?loff_t?*pos) static?ssize_t?hello_write(struct?file?*filep,?const?char?__user?*buf,?size_t?len,?loff_t?*pos) |
? ? ? ?我們知道,應(yīng)用程序工作在用戶空間,而驅(qū)動工作在內(nèi)核空間,二者不能直接通信的,那我們用何種方法進行通信呢?下面介紹一下內(nèi)核中的memcpy---copy_from_user和copy_to_user,雖然說內(nèi)核中不能使用C庫提供的函數(shù),但是內(nèi)核也有一個memcpy的函數(shù),用法跟C庫中的一樣。
? ? ? ? 下面看一下copy_from_user() 及 copy_to_user() 函數(shù)的定義:
[cpp]?view plaincopy
[cpp]?view plaincopy
? ? ? ?其實在這里,我們可以思考,既然拷貝的功能上面的_memcpy() 函數(shù)就可以實現(xiàn),為什么還要封裝成 copy_to_user()和copy_from_user()呢?答案是_memcpy() 函數(shù)是有缺陷的,譬如我們在用戶層調(diào)用函數(shù)時傳入的不是字符串,而是一個不能訪問或修改的地址,那樣就會造成系統(tǒng)崩潰。
? ? ? 出于上面的原因, 內(nèi)核和用戶態(tài)之間交互的數(shù)據(jù)時必須要先對數(shù)據(jù)進行檢測 ,如果數(shù)據(jù)是安全的,才可以進行數(shù)據(jù)交互。上面的函數(shù)就是memcpy的改進版,在memcpy功能的基礎(chǔ)上加上的檢查傳入?yún)?shù)的功能,防止有些人有意或者無意的傳入無效的參數(shù)。? ? ?
? ? ? 現(xiàn)在我們可以審視一下這兩個函數(shù)了:
[cpp]?view plaincopy
和memcpy的參數(shù)一樣,但它根據(jù)傳參方向的不同分開了兩個函數(shù)。
"to"是相對于內(nèi)核態(tài)來說的。所以,to函數(shù)的意思是從from指針指向的數(shù)據(jù)將n個字節(jié)的數(shù)據(jù)傳到to指針指向的數(shù)據(jù)。
"from"也是相對于內(nèi)核來說的。所以,from函數(shù)的意思是從from指針指向的數(shù)據(jù)將n個字節(jié)的數(shù)據(jù)傳到to指針指向的數(shù)據(jù)。
返回值:函數(shù)的返回值是指定要讀取的n個字節(jié)中還剩下多少字節(jié)還沒有被拷貝。
注意:
一般的,如果返回值不為0時,調(diào)用copy_to_user的函數(shù)會返回錯誤號-EFAULT表示操作出錯。當(dāng)然也可以自己決定。
又到了擺實例的時候了,這里只列出部分代碼,看看這兩個函數(shù)的用法:
[cpp]?view plaincopy
[cpp]?view plaincopy
? ? ? 到這里open、close、read、write四個函數(shù)已經(jīng)學(xué)完,下面我們來看一下四個函數(shù)使用時,到底經(jīng)歷了一個怎樣的過程:
注:箭頭方向是從調(diào)用的一方指向受作用的一方
?? ?
? ??
? ?
總結(jié)
以上是生活随笔為你收集整理的Linux 字符设备驱动开发基础(三)—— read()、write() 相关函数解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python pysnmp使用
- 下一篇: 专业视频压制神器下载——解决会声会影、P