W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
到此我們已經(jīng)快速瀏覽了這些成員, 我們開(kāi)始在真實(shí)的 scull 函數(shù)中使用它們.
open 方法提供給驅(qū)動(dòng)來(lái)做任何的初始化來(lái)準(zhǔn)備后續(xù)的操作. 在大部分驅(qū)動(dòng)中, open 應(yīng)當(dāng)進(jìn)行下面的工作:
檢查設(shè)備特定的錯(cuò)誤(例如設(shè)備沒(méi)準(zhǔn)備好, 或者類(lèi)似的硬件錯(cuò)誤
如果它第一次打開(kāi), 初始化設(shè)備
如果需要, 更新 f_op 指針.
分配并填充要放進(jìn) filp->private_data 的任何數(shù)據(jù)結(jié)構(gòu)
但是, 事情的第一步常常是確定打開(kāi)哪個(gè)設(shè)備. 記住 open 方法的原型是:
int (*open)(struct inode *inode, struct file *filp);
inode 參數(shù)有我們需要的信息,以它的 i_cdev 成員的形式, 里面包含我們之前建立的 cdev 結(jié)構(gòu). 唯一的問(wèn)題是通常我們不想要 cdev 結(jié)構(gòu)本身, 我們需要的是包含 cdev 結(jié)構(gòu)的 scull_dev 結(jié)構(gòu). C 語(yǔ)言使程序員玩弄各種技巧來(lái)做這種轉(zhuǎn)換; 但是, 這種技巧編程是易出錯(cuò)的, 并且導(dǎo)致別人難于閱讀和理解代碼. 幸運(yùn)的是, 在這種情況下, 內(nèi)核 hacker 已經(jīng)為我們實(shí)現(xiàn)了這個(gè)技巧, 以 container_of 宏的形式, 在 <linux/kernel.h> 中定義:
container_of(pointer, container_type, container_field);
這個(gè)宏使用一個(gè)指向 container_field 類(lèi)型的成員的指針, 它在一個(gè) container_type 類(lèi)型的結(jié)構(gòu)中, 并且返回一個(gè)指針指向包含結(jié)構(gòu). 在 scull_open, 這個(gè)宏用來(lái)找到適當(dāng)?shù)脑O(shè)備結(jié)構(gòu):
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
一旦它找到 scull_dev 結(jié)構(gòu), scull 在文件結(jié)構(gòu)的 private_data 成員中存儲(chǔ)一個(gè)它的指針, 為以后更易存取.
識(shí)別打開(kāi)的設(shè)備的另外的方法是查看存儲(chǔ)在 inode 結(jié)構(gòu)的次編號(hào). 如果你使用 register_chrdev 注冊(cè)你的設(shè)備, 你必須使用這個(gè)技術(shù). 確認(rèn)使用 iminor 從 inode 結(jié)構(gòu)中獲取次編號(hào), 并且確定它對(duì)應(yīng)一個(gè)你的驅(qū)動(dòng)真正準(zhǔn)備好處理的設(shè)備.
scull_open 的代碼(稍微簡(jiǎn)化過(guò))是:
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
{
scull_trim(dev); /* ignore errors */
}
return 0; /* success */
}
代碼看來(lái)相當(dāng)稀疏, 因?yàn)樵谡{(diào)用 open 時(shí)它沒(méi)有做任何特別的設(shè)備處理. 它不需要, 因?yàn)?scull 設(shè)備設(shè)計(jì)為全局的和永久的. 特別地, 沒(méi)有如"在第一次打開(kāi)時(shí)初始化設(shè)備"等動(dòng)作, 因?yàn)槲覀儾粸?scull 保持打開(kāi)計(jì)數(shù).
唯一在設(shè)備上的真實(shí)操作是當(dāng)設(shè)備為寫(xiě)而打開(kāi)時(shí)將它截取為長(zhǎng)度為 0. 這樣做是因?yàn)? 在設(shè)計(jì)上, 用一個(gè)短的文件覆蓋一個(gè) scull 設(shè)備導(dǎo)致一個(gè)短的設(shè)備數(shù)據(jù)區(qū). 這類(lèi)似于為寫(xiě)而打開(kāi)一個(gè)常規(guī)文件, 將其截短為 0. 如果設(shè)備為讀而打開(kāi), 這個(gè)操作什么都不做.
在我們查看其他 scull 特性的代碼時(shí)將看到一個(gè)真實(shí)的初始化如何起作用的.
release 方法的角色是 open 的反面. 有時(shí)你會(huì)發(fā)現(xiàn)方法的實(shí)現(xiàn)稱(chēng)為 device_close, 而不是 device_release. 任一方式, 設(shè)備方法應(yīng)當(dāng)進(jìn)行下面的任務(wù):
釋放 open 分配在 filp->private_data 中的任何東西
在最后的 close 關(guān)閉設(shè)備
scull 的基本形式?jīng)]有硬件去關(guān)閉, 因此需要的代碼是最少的:[12]
int scull_release(struct inode *inode, struct file *filp)
{
return 0;
}
你可能想知道當(dāng)一個(gè)設(shè)備文件關(guān)閉次數(shù)超過(guò)它被打開(kāi)的次數(shù)會(huì)發(fā)生什么. 畢竟, dup 和 fork 系統(tǒng)調(diào)用不調(diào)用 open 來(lái)創(chuàng)建打開(kāi)文件的拷貝; 每個(gè)拷貝接著在程序終止時(shí)被關(guān)閉. 例如, 大部分程序不打開(kāi)它們的 stdin 文件(或設(shè)備), 但是它們都以關(guān)閉它結(jié)束. 當(dāng)一個(gè)打開(kāi)的設(shè)備文件已經(jīng)真正被關(guān)閉時(shí)驅(qū)動(dòng)如何知道?
答案簡(jiǎn)單: 不是每個(gè) close 系統(tǒng)調(diào)用引起調(diào)用 release 方法. 只有真正釋放設(shè)備數(shù)據(jù)結(jié)構(gòu)的調(diào)用會(huì)調(diào)用這個(gè)方法 -- 因此得名. 內(nèi)核維持一個(gè)文件結(jié)構(gòu)被使用多少次的計(jì)數(shù). fork 和 dup 都不創(chuàng)建新文件(只有 open 這樣); 它們只遞增正存在的結(jié)構(gòu)中的計(jì)數(shù). close 系統(tǒng)調(diào)用僅在文件結(jié)構(gòu)計(jì)數(shù)掉到 0 時(shí)執(zhí)行 release 方法, 這在結(jié)構(gòu)被銷(xiāo)毀時(shí)發(fā)生. release 方法和 close 系統(tǒng)調(diào)用之間的這種關(guān)系保證了你的驅(qū)動(dòng)一次 open 只看到一次 release.
注意, flush 方法在每次應(yīng)用程序調(diào)用 close 時(shí)都被調(diào)用. 但是, 很少驅(qū)動(dòng)實(shí)現(xiàn) flush, 因?yàn)槌3T?close 時(shí)沒(méi)有什么要做, 除非調(diào)用 release.
如你會(huì)想到的, 前面的討論即便是應(yīng)用程序沒(méi)有明顯地關(guān)閉它打開(kāi)的文件也適用: 內(nèi)核在進(jìn)程 exit 時(shí)自動(dòng)關(guān)閉了任何文件, 通過(guò)在內(nèi)部使用 close 系統(tǒng)調(diào)用.
[12] 其他風(fēng)味的設(shè)備由不同的函數(shù)關(guān)閉, 因?yàn)?scull_open 為每個(gè)設(shè)備替換了不同的 filp->f_op. 我們?cè)诮榻B每種風(fēng)味時(shí)再討論它們.
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: