Linux裝置驅動程式學習(15) -Linux裝置模型(熱插拔、mdev 與 firmware)

來源:互聯網
上載者:User
熱插拔
有 2 個不同角度來看待熱插拔:
   從核心角度看,熱插拔是在硬體、核心和核心驅動之間的互動。
   從使用者角度看,熱插拔是核心和使用者空間之間,通過調用使用者空間程式(如hotplug、udev 和 mdev)的互動。 當需要通知使用者核心發生了某種熱插拔事件時,核心才調用這個使用者空間程式。
現在的電腦系統,要求 Linux 核心能夠在硬體從系統中增刪時,可靠穩定地運行。這就對裝置驅動作者增加了壓力,因為在他們必須處理一個毫無徵兆地突然出現或消失的裝置。 熱插拔工具
當使用者向系統添加或刪除裝置時,核心會產生一個熱插拔事件,並在 /proc/sys/kernel/hotplug 檔案裡尋找處理裝置串連的使用者空間程式。這個使用者空間程式主要有 hotplug:這個程式是一個典型的 bash 指令碼,只傳遞執行權給一系列位於 /etc/hot-plug.d/ 分類樹的程式。hotplug 指令碼搜尋所有的有 .hotplug 尾碼的可能對這個事件進行處理的程式並調用它們, 並傳遞給它們許多不同的已經被核心設定的環境變數。(基本已被淘汰,具體內容請參閱《LDD3》) udev :用於linux2.6.13或更高版本的核心上,為使用者空間提供使用固定裝置名稱的動態/dev目錄的解決方案。它通過在 sysfs 的 /class/ 和/block/ 分類樹中尋找一個稱為 dev 的檔案,以確定所建立的裝置節點檔案的主次裝置號。所以要使用udev,驅動必須為裝置在sysfs中建立類介面及其dev屬性檔案,方法和sculld模組中建立dev屬性相同。 udev的資料網上十分豐富,我就不在這廢話了,給出以下連結有興趣的自己研究:《UDEV Primer》(英文),地址:http://webpages.charter.net/decibelshelp/LinuxHelp_UDEVPrimer.html《udev規則編寫》(luofuchong翻譯),地址:http://www.cnitblog.com/luofuchong/archive/2007/12/18/37831.html《什麼是udev》地址:http://blog.csdn.net/steganography/archive/2006/04/10/657620.aspx《udev-FAQ 中文翻譯》地址:http://gnawux.bokee.com/3225765.html《udev輕鬆上路》地址:http://www.blog.edu.cn/user1/3313/archives/2007/1635169.shtml《Udev (簡體中文)》地址:http://wiki.archlinux.org/index.php/Udev_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)Udev官方首頁:http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html:http://www.kernel.org/pub/linux/utils/kernel/hotplug/在《LFS》中也有介紹udev的使用,很值得參考!:http://lfs.osuosl.org/lfs/downloads/stable/ mdev:一個簡化版的udev,是busybox所帶的程式,十分適合嵌入式系統。因為 hotplug現在也在被慢慢地淘汰,udev不再依賴hotplug了,所以這裡不再介紹; udev較mdev複雜,不太適合嵌入式使用。(本人也有做udev的實驗,交叉編譯是通過了,但是使用上有問題,沒有實現其功能。也許是我的檔案系統沒做好,以後有時間再研究和寫記錄。有成功高人的通知一聲,交流一下經驗。^_^謝謝!); mdev簡單易用,比較適合嵌入式系統,實驗成功。以下詳細介紹mdev的使用。 mdev在一開始建立根檔案系統時,我根據 WeiBing 的部落格上《UDEV on embeded Linux-2.6.19.2》(地址:http://weibing.blogbus.com/logs/4485453.html)這篇文章的提示,開始使用mdev,但是當時只是啟動時mdev -s 一下,並沒有深究。現在在學習了Linux裝置模型之後,對於Linux中/dev目錄的動態管理有了更深的認識,並認真的看了一下busybox中的mdev.txt文檔並翻譯了一下,做成了PDF(:http://blogimg.chinaunix.net/blog/upfile2/080111091002.pdf),在看下面的內容時請先看看這篇文檔。 先聲明一個要點:要實現裝置節點檔案的自動、動態增刪,必須在你自己的驅動源碼中實現 類 介面,並在類裝置的目錄中添加包含裝置號的名為“dev”的屬性檔案。 mdev原理及bug要使用mdev,適當知道一下原理是必不可少的(能完整地研究mdev源碼是最好的)。說實話起初我並沒有想看mdev的源碼,是在使用時發現了問題後才去研究了一下mdev的源碼。現在簡單介紹一下mdev的原理: 執行mdev -s :以‘-s’為參數調用位於 /sbin目錄寫的mdev(其實是個連結,作用是傳遞參數給/bin目錄下的busybox程式並調用它),mdev掃描 /sys/class 和 /sys/block 中所有的類裝置目錄,如果在目錄中含有名為“dev”的檔案,且檔案中包含的是裝置號,則mdev就利用這些資訊為這個裝置在/dev 下建立裝置節點檔案。一般只在啟動時才執行一次 “mdev -s”。 熱插拔事件:由於啟動時運行了命令:echo /sbin/mdev > /proc/sys/kernel/hotplug ,那麼當有熱插拔事件產生時,核心就會調用位於 /sbin目錄的mdev。這時mdev通過環境變數中的 ACTION 和 DEVPATH,來確定此次熱插拔事件的動作以及影響了/sys中的那個目錄。接著會看看這個目錄中是否有“dev”的屬性檔案,如果有就利用這些資訊為這個裝置在/dev 下建立裝置節點檔案。源碼的bug(個人意見):由於mdev是通過判斷“dev”屬性檔案的路徑字串中的第6個字元是否為‘c’,來決定裝置是字元裝置還是塊裝置【type = (path[5] == 'c' ? S_IFCHR : S_IFBLK);例如path = "/sys/class/ldd/sculld*/"為字元裝置,而/sys/devices/ldd0/sculld*/ 就會被誤判為塊裝置】,那麼如果你在非 /sys/class 和 /sys/block 目錄下建立了“dev”屬性檔案且內容是裝置號(像sculld中就這樣做了),那麼mdev也會在/dev 下建立裝置節點檔案。這樣可能所建立的裝置節點檔案是錯的。以我實驗為例,我以上一篇的文章中的sculld為基礎,加上了類介面(這樣在/sys/devices/ldd0/sculld*/和 /sys/class/ldd/sculld* 中都有內容為裝置號的“dev”屬性檔案)。在運行時發現一直會將有的sculld*建立為塊裝置節點檔案。鬱悶死了,難道我的驅動有錯???最後研究了mdev源碼之後發現,只要在 /sys中建立了“dev”屬性檔案且內容是裝置號,mdev就會以所在的目錄為名在/dev 下建立裝置節點檔案。像sculld模組,mdev會為一個裝置建立兩次裝置檔案,由於檔案名稱一樣,第二次的檔案會覆蓋第一次的。如果第二次是因為/sys/devices/ldd0/sculld*/dev 產生的裝置節點檔案,那麼裝置節點檔案就會被錯誤地建立為塊裝置。我認為這個bug的解決辦法有如下兩種:(1)在你寫驅動的時候,只在/sys/class 和 /sys/block 中的類裝置目錄中存在包含裝置號的“dev”屬性檔案。(你無法保證被人的驅動會這麼做)(2)修正mdev源碼:修改/busybox-1.9.0/util-linux/mdev.c檔案的第328行:
if (!strcmp(action, "remove"))       make_device(temp, 1);else if (!strcmp(action, "add")) {if (env_path[2]=='l') make_device(temp,0);  //tekkamanninjaif (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE)                load_firmware(getenv("FIRMWARE"), temp);}
也就是在增加裝置節點檔案之前檢查/sys/目錄下的路徑是否為/class和/block(通過檢查路徑字串的第3個字元是否為‘l’)。本人推薦第二種做法! mdev使用mdev的使用在busybox中的mdev.txt文檔已經將得很詳細了。但作為例子,我簡單講講我的使用過程:(1)在編譯時間加上對mdev的支援(我是使用的是busybox1.9.0):
    Linux System Utilities  --->               [*] mdev                  [*]   Support /etc/mdev.conf            [*]     Support command execution at device addition/removal 
(2)在啟動時加上使用mdev的命令:我在自己建立的根檔案系統(nfs)中的/linuxrc檔案中添加了如下指令: #掛載/sys為sysfs檔案系統

    echo "----------mount /sys as sysfs"

/bin/mount -t tmpfs mdev /dev

/bin/mount -t sysfs sysfs /sys

    echo "----------Starting mdev......"

/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug

    mdev -s
注意:是 /bin/echo /sbin/mdev > /proc/sys/kernel/hotplug,並非 /bin/echo /bin/mdev > /proc/sys/kernel/hotplug。busybox的文檔有錯!!(3)在你的驅動中加上對類裝置介面的支援,並在類裝置目錄下添加包含裝置號的名為“dev”的屬性檔案。(4)至於/etc/mdev.conf檔案,可有可無,不影響使用,只是添加了些功能。     為了實驗我在/etc建立了mdev.conf檔案並輸入了:     sculld[0-1] 0:0 666 * echo tekkaman > /tmp/mdev     這樣,在掛載和卸載sculld.ko時,在/tmp/下會出現mdev檔案,裡面字元為tekkaman具體的實驗源碼和現象在文章後面有。 firmware硬體市場的激烈競爭, 使得製造商連一點用於裝置控制韌體的 EEPROM 的成本都不願意花費。因此韌體一般發布在和硬體配套的驅動包中,由作業系統(其實是驅動程式)負責傳送韌體到裝置。 核心韌體介面擷取韌體的正確方法是當需要時從使用者空間擷取它。一定不要試圖從核心空間直接開啟包含韌體的檔案,那是一個易出錯的操作, 因為它把策略(以檔案名稱的形式)包含進了核心。正確的方法是使用韌體介面:
#include <linux/firmware.h>int request_firmware(const struct firmware **fw, const char *name, /* name 為韌體檔案名稱*/struct device *device);/*要求使用者空間定位並提供一個韌體映象給核心;若成功載入, 傳回值是 0(否則返回錯誤碼)*//*因為 request_firmware 需要使用者空間的操作, 所以返回前將保持休眠。若驅動必須使用韌體而不能進入休眠時,可使用以下非同步函數:*/int request_firmware_nowait(struct module *module, /* = THIS_MODULE*/int uevent,const char *name,struct device *device,void *context,/*不由韌體子系統使用的私人資料指標*/void (*cont)(const struct firmware *fw, void *context));/*如果一切正常,request_firmware_nowait 開始韌體載入過程並返回 0. 過了一段時間後(預設10秒),將用載入的結果(若載入失敗, fw 為 NULL)作為參數調用 cont。*//* fw 參數指向以下結構體:*/struct firmware {size_t size;    u8 *data;};/*那個結構包含實際的韌體, 它現在可被下載到裝置中.但是請注意:在發送它到硬體之前,必須檢查這個檔案以確保它是正確的韌體映象(裝置韌體常常包含標識字串、 校正和等等)*//*當韌體已經發送到裝置後,應當釋放 firmware 結構體, 使用:*/void release_firmware(struct firmware *fw); 

注意:要使用firmware,必須要在配置核心時選上:   Device Drivers  --->   
          Generic Driver Options  --->     
<*> Userspace firmware loading support

否則會出現: Unknown symbol release_firmware 和: Unknown symbol request_firmware 的錯誤。

韌體介面工作原理韌體子系統使用 sysfs 和熱插拔機制工作。當調用 request_firmware時, 函數將在 /sys/class/firmware 下建立一個以裝置名稱為目錄名的新目錄,其中包含 3 個屬性:loading :這個屬性應當被載入韌體的使用者空間進程設定為 1。當載入完畢, 它將被設為 0。被設為 -1 時,將中止韌體載入。

data :一個用來接收韌體資料的二進位屬性。在設定 loading 為1後, 使用者空間進程將韌體寫入這個屬性。

device :一個連結到 /sys/devices 下相關入口項的符號連結。一旦建立了 sysfs 入口項, 核心將為裝置產生一個熱插拔事件,並傳遞包括變數 FIRMWARE 的環境變數給處理熱插拔的使用者空間程式。FIRMWARE 被設定為提供給 request_firmware 的韌體檔案名稱。使用者空間程式定位韌體檔案, 並將其拷貝到核心提供的二進位屬性;若無法定位檔案, 使用者空間程式設定 loading 屬性為 -1。若韌體請求在 10 秒內沒有被服務, 核心就放棄並返回一個失敗狀態給驅動。逾時周期可通過 sysfs 屬性 /sys/class/firmware/timeout 屬性改變。 request_firmware 介面允許使用驅動發布裝置韌體。當正確地整合進熱插拔機制後, 韌體載入子系統允許裝置不受幹擾地工作。顯然這是處理問題的最好方法,但韌體受著作權保護,小心違反著作權法。

ARM9開發板實驗 實驗源碼:http://blogimg.chinaunix.net/blog/upfile2/080114113255.gz   實驗現象:
[Tekkaman2440@SBC2440V4]#ls -l /dev/sculld*ls: /dev/sculld*: No such file or directory[Tekkaman2440@SBC2440V4]#cat /tmp/mdevcat: can't open '/tmp/mdev': No such file or directory[Tekkaman2440@SBC2440V4]#insmod /lib/modules/lddbus.koMount lddbus ok !Bus device is ldd0 !You can see me in sys/module/ , sys/devices/ , sys/class/ and sys/bus/ ![Tekkaman2440@SBC2440V4]#insmod /lib/modules/sculld.ko[Tekkaman2440@SBC2440V4]#ls -l /dev/sculld*crw-rw-rw-    1 root     root     252,   0 Jan  1 00:00 /dev/sculld0crw-rw-rw-    1 root     root     252,   1 Jan  1 00:00 /dev/sculld1crw-rw----    1 root     root     252,   2 Jan  1 00:00 /dev/sculld2crw-rw----    1 root     root     252,   3 Jan  1 00:00 /dev/sculld3[Tekkaman2440@SBC2440V4]#rmmod sculldThe LDD class ldd_classdev_release : sculld0 release!The LDD class ldd_classdev_release : sculld1 release!The LDD class ldd_classdev_release : sculld2 release!The LDD class ldd_classdev_release : sculld3 release![Tekkaman2440@SBC2440V4]#ls -l /dev/sculld*ls: /dev/sculld*: No such file or directory[Tekkaman2440@SBC2440V4]#cat /tmp/mdevtekkaman
到此 Linux裝置模型 的學習暫時告一段落。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.