嵌入式Linux設(shè)備驅(qū)動開發(fā)之:字符設(shè)備驅(qū)動編程
(5)釋放設(shè)備。
釋放設(shè)備的函數(shù)接口是release()。要注意釋放設(shè)備和關(guān)閉設(shè)備是完全不同的。當(dāng)一個進(jìn)程釋放設(shè)備時,其他進(jìn)程還能繼續(xù)使用該設(shè)備,只是該進(jìn)程暫時停止對該設(shè)備的使用;而當(dāng)一個進(jìn)程關(guān)閉設(shè)備時,其他進(jìn)程必須重新打開此設(shè)備才能使用它。
釋放設(shè)備時要完成的工作如下。
n 遞減計(jì)數(shù)器MOD_DEC_USE_COUNT(最新版本已經(jīng)不再使用)。
n 釋放打開設(shè)備時系統(tǒng)所分配的內(nèi)存空間(包括filp->private_data指向的內(nèi)存空間)。
n 在最后一次釋放設(shè)備操作時關(guān)閉設(shè)備。
(6)讀寫設(shè)備。
讀寫設(shè)備的主要任務(wù)就是把內(nèi)核空間的數(shù)據(jù)復(fù)制到用戶空間,或者從用戶空間復(fù)制到內(nèi)核空間,也就是將內(nèi)核空間緩沖區(qū)里的數(shù)據(jù)復(fù)制到用戶空間的緩沖區(qū)中或者相反。這里首先解釋一個read()和write()函數(shù)的入口函數(shù),如表11.5所示。
表11.5 read、write函數(shù)接口語法要點(diǎn)
所需頭文件 | #includelinux/fs.h> |
函數(shù)原型 | ssize_t(*read)(structfile*filp,char*buff,size_tcount,loff_t*offp) |
函數(shù)傳入值 | filp:文件指針 |
buff:指向用戶緩沖區(qū) | |
count:傳入的數(shù)據(jù)長度 | |
offp:用戶在文件中的位置 | |
函數(shù)返回值 | 成功:寫入的數(shù)據(jù)長度 |
雖然這個過程看起來很簡單,但是內(nèi)核空間地址和應(yīng)用空間地址是有很大區(qū)別的,其中一個區(qū)別是用戶空間的內(nèi)存是可以被換出的,因此可能會出現(xiàn)頁面失效等情況。所以不能使用諸如memcpy()之類的函數(shù)來完成這樣的操作。在這里要使用copy_to_user()或copy_from_user()等函數(shù),它們是用來實(shí)現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)交換的。
copy_to_user()和copy_from_user()的格式如表11.6所示。
表11.6 copy_to_user()/copy_from_user()函數(shù)語法要點(diǎn)
所需頭文件 | #includeasm/uaccess.h> |
函數(shù)原型 | unsignedlongcopy_to_user(void*to,constvoid*from,unsignedlongcount) |
函數(shù)傳入值 | to:數(shù)據(jù)目的緩沖區(qū) |
from:數(shù)據(jù)源緩沖區(qū) | |
count:數(shù)據(jù)長度 | |
函數(shù)返回值 | 成功:寫入的數(shù)據(jù)長度 |
要注意,這兩個函數(shù)不僅實(shí)現(xiàn)了用戶空間和內(nèi)核空間的數(shù)據(jù)轉(zhuǎn)換,而且還會檢查用戶空間指針的有效性。如果指針無效,那么就不進(jìn)行復(fù)制。
(7)ioctl。
大部分設(shè)備除了讀寫操作,還需要硬件配置和控制(例如,設(shè)置串口設(shè)備的波特率)等很多其他操作。在字符設(shè)備驅(qū)動中ioctl函數(shù)接口給用戶提供對設(shè)備的非讀寫操作機(jī)制。
ioctl函數(shù)接口的具體格式如表11.7所示。
表11.7 ioctl函數(shù)接口語法要點(diǎn)
所需頭文件 | #includelinux/fs.h> |
函數(shù)原型 | int(*ioctl)(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg) |
函數(shù)傳入值 | inode:文件的內(nèi)核內(nèi)部結(jié)構(gòu)指針 |
filp:被打開的文件描述符 | |
cmd:命令類型 | |
arg:命令相關(guān)參數(shù) |
下面列出其他在驅(qū)動程序中常用的內(nèi)核函數(shù)。
(8)獲取內(nèi)存。
在應(yīng)用程序中獲取內(nèi)存通常使用函數(shù)malloc(),但在設(shè)備驅(qū)動程序中動態(tài)開辟內(nèi)存可以以字節(jié)或頁面為單位。其中,以字節(jié)為單位分配內(nèi)存的函數(shù)有kmalloc(),注意的是,kmalloc()函數(shù)返回的是物理地址,而malloc()等返回的是線性虛擬地址,因此在驅(qū)動程序中不能使用malloc()函數(shù)。與malloc()不同,kmalloc()申請空間有大小限制。長度是2的整次方,并且不會對所獲取的內(nèi)存空間清零。
以頁為單位分配內(nèi)存的函數(shù)如下所示。
n get_zeroed_page():獲得一個已清零頁面。
n get_free_page():獲得一個或幾個連續(xù)頁面。
n get_dma_pages():獲得用于DMA傳輸?shù)捻撁妗?/p>
與之相對應(yīng)的釋放內(nèi)存用也有kfree()或free_page函數(shù)族。
表11.8給出了kmalloc()函數(shù)的語法格式。
表11.8 kmalloc()函數(shù)語法要點(diǎn)
所需頭文件 | #includelinux/malloc.h> | |
函數(shù)原型 | void*kmalloc(unsignedintlen,intflags) | |
函數(shù)傳入值 | len:希望申請的字節(jié)數(shù) | |
flags | GFP_KERNEL:內(nèi)核內(nèi)存的通常分配方法,可能引起睡眠 | |
GFP_BUFFER:用于管理緩沖區(qū)高速緩存 | ||
GFP_ATOMIC:為中斷處理程序或其他運(yùn)行于進(jìn)程上下文之外的代碼分配內(nèi)存,且不會引起睡眠 | ||
GFP_USER:用戶分配內(nèi)存,可能引起睡眠 | ||
GFP_HIGHUSER:優(yōu)先高端內(nèi)存分配 | ||
__GFP_DMA:DMA數(shù)據(jù)傳輸請求內(nèi)存 | ||
__GFP_HIGHMEN:請求高端內(nèi)存 | ||
函數(shù)返回值 | 成功:寫入的數(shù)據(jù)長度 |
linux相關(guān)文章:linux教程
評論