亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 2022 | 回復(fù): 1
打印 上一主題 下一主題

Linux設(shè)備驅(qū)動(dòng)入門(一) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2009-09-16 15:57 |只看該作者 |倒序?yàn)g覽
用來防止用戶程序直接訪問內(nèi)核中關(guān)鍵性數(shù)據(jù)結(jié)構(gòu)和硬件設(shè)備是驅(qū)動(dòng)程序的主要目的之一,所以,一個(gè)設(shè)計(jì)精良的驅(qū)動(dòng)通常應(yīng)該隱藏了硬件的復(fù)雜性和多變性。例如,一個(gè)程序?qū)憯?shù)據(jù)到磁盤時(shí),只需要打開一個(gè)文件并執(zhí)行寫命令即可,而不必了解磁盤中的每個(gè)扇區(qū)的大小是512字節(jié)或者是1024字節(jié),細(xì)節(jié)性的問題則交由驅(qū)動(dòng)程序處理。此外,驅(qū)動(dòng)程序還可以隱藏硬件的多變性(可能來自于不同廠家,甚至同一廠家不同型號(hào))并給用戶提供一個(gè)統(tǒng)一的訪問接口。這也是Unix/Linux信條之一“一切皆文件”的賴以存在的基礎(chǔ)。

1、可加載模塊(loadable module)

Linux采取了“宏內(nèi)核”的結(jié)構(gòu),并附帶一個(gè)設(shè)計(jì)精良的接口以實(shí)現(xiàn)在系統(tǒng)運(yùn)行時(shí)動(dòng)態(tài)的加載或移除驅(qū)動(dòng)模塊。這種富有彈性的設(shè)計(jì),為最終用戶,甚至也為程序的開發(fā)過程帶來了極大的便利;诖斯δ埽陂_發(fā)驅(qū)動(dòng)的過程中,開發(fā)人員不用在每一次驅(qū)動(dòng)程序的修改后重啟系統(tǒng)就能對(duì)其進(jìn)行測試。

當(dāng)然,驅(qū)動(dòng)程序也可以以靜態(tài)方式編譯進(jìn)內(nèi)核,而且,許多關(guān)鍵性的驅(qū)動(dòng)也需要這樣編譯。比如,對(duì)于無盤工作站而言,由于系統(tǒng)啟動(dòng)最初就需要通過網(wǎng)卡從其它共享文件系統(tǒng)中加載所需的資源,此時(shí)必須將網(wǎng)卡驅(qū)動(dòng)靜態(tài)編譯進(jìn)內(nèi)核,因?yàn)榭杉虞d模塊都是系統(tǒng)啟動(dòng)后才進(jìn)行動(dòng)態(tài)加載。

通常使用啟動(dòng)腳本裝載動(dòng)態(tài)驅(qū)動(dòng)模塊,當(dāng)然,也可以使用相關(guān)命令在需要時(shí)再進(jìn)行加載。此外,內(nèi)核也可以在某個(gè)服務(wù)需要某個(gè)特殊模塊時(shí)自動(dòng)請(qǐng)求加載所需的模塊。

雖然前文中一直稱驅(qū)動(dòng)程序?yàn)榭杉虞d模塊,但內(nèi)核模塊并沒有確定的術(shù)語,硬件驅(qū)動(dòng)(device drivers)、可加載內(nèi)核模塊(LKM,loadable kernel modules)、內(nèi)核模塊(kernel modules)、可加載模塊(loadable modules)、驅(qū)動(dòng)模塊(driver modules)和模塊(modules)等都常用來表示可動(dòng)態(tài)加載進(jìn)內(nèi)核的硬件驅(qū)動(dòng),后文中則不加區(qū)別的使用它們。

2、硬件驅(qū)動(dòng)結(jié)構(gòu)

盡管Linux/Unix驅(qū)動(dòng)程序模塊的開發(fā)一直處于不斷地演進(jìn)中,但其基本結(jié)構(gòu)并沒有太大改變。硬件設(shè)備大體上可分為兩大類:字符設(shè)備和塊設(shè)備。


  • 字符設(shè)備是以串行流式數(shù)據(jù)序列進(jìn)行數(shù)據(jù)存取的設(shè)備,字符設(shè)備驅(qū)動(dòng)負(fù)責(zé)實(shí)現(xiàn)這種行為;通常字符設(shè)備驅(qū)動(dòng)至少需要實(shí)現(xiàn) open、 close、read和 write等系統(tǒng)調(diào)用。常見的字符設(shè)備如控制臺(tái)( /dev/console )和串口( /dev/ttyS0 )。
  • 塊設(shè)備通常是可編址的,其數(shù)據(jù)存取也通常以固定大小的數(shù)據(jù)塊進(jìn)行,但數(shù)據(jù)塊的存入位置則可能是隨機(jī)的。在大部分Unix系統(tǒng)中, 一個(gè)塊設(shè)備傳送一個(gè)或多個(gè)長度經(jīng)常是512字節(jié)(或者其2次冪倍)的整塊數(shù)據(jù),但Linux允許一次傳遞任意字節(jié)的數(shù)據(jù),其跟字符設(shè)備的區(qū)別僅在于內(nèi)核內(nèi)部對(duì)數(shù)據(jù)的管理方式上和驅(qū)動(dòng)程序的接口實(shí)現(xiàn)上有所不同。磁盤是常見的塊設(shè)備。


3、一個(gè)驅(qū)動(dòng)程序的例子

因?yàn)長inux支持可加載式硬件驅(qū)動(dòng),所以很容易構(gòu)建出一個(gè)關(guān)于簡易驅(qū)動(dòng)框架來說明驅(qū)動(dòng)程序的結(jié)構(gòu)。下面就是這樣一個(gè)關(guān)于字符型設(shè)備驅(qū)動(dòng)程序的例子:

/* Example Minimal Character Device Driver */
#include linux/module.h>
static int __init hello_init(void)
{
  printk("Hello Device Driver World!\n");
  return 0;
}
static void __exit hello_exit(void)
{
  printk("Goodbye, Cruel World!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("Marion");
MODULE_DESCRIPTION("An example of device driver!");
MODULE_LICENSE("GPL");
/* End the hello*/

上面這個(gè)例子雖然短小,但卻充分具備了讓內(nèi)核加載或卸載以及初始化或退出的程序結(jié)構(gòu)。

不同于標(biāo)準(zhǔn)的二進(jìn)制可執(zhí)行程序,設(shè)備驅(qū)動(dòng)是一種特殊的二進(jìn)制模塊,它不能簡單的通過shell執(zhí)行。2.6系列內(nèi)核的模塊通常是內(nèi)核對(duì)象(kernel object)格式,這些模塊在完成編譯后通常以.ko為后綴。創(chuàng)建內(nèi)核對(duì)象步驟和編譯選項(xiàng)非常復(fù)雜,本文僅描述其大體過程,以幫助讀者簡單了解內(nèi)核對(duì)象的構(gòu)建步驟。

4、模塊構(gòu)建基礎(chǔ)

驅(qū)動(dòng)程序的編譯必須針對(duì)于特定的內(nèi)核進(jìn)行。盡管在另一個(gè)不同的內(nèi)核上編譯的驅(qū)動(dòng)模塊也可以運(yùn)行,但如果不確定此模塊是否依賴于編譯時(shí)的內(nèi)核的某些特性時(shí),將會(huì)給后來運(yùn)行過程來帶來很大風(fēng)險(xiǎn)。因此,最穩(wěn)妥的辦法還是基于某內(nèi)核自身的代碼樹(Source tree)構(gòu)建內(nèi)核對(duì)象,這也可以保證在開發(fā)人員改變了內(nèi)核的配置后,驅(qū)動(dòng)也會(huì)在新配置的內(nèi)核的基礎(chǔ)上進(jìn)行重建。如果需要在不同的內(nèi)核上構(gòu)建內(nèi)核對(duì)象,則必須確保驅(qū)動(dòng)程序構(gòu)建時(shí)的配置所使用的編譯選項(xiàng)、引用內(nèi)核頭文件的位置和內(nèi)核配置選項(xiàng)在驅(qū)動(dòng)實(shí)際運(yùn)行的內(nèi)核上做了同樣的配置。

為了基于前文中的例子構(gòu)建驅(qū)動(dòng)程序,大致要經(jīng)過以下幾個(gè)步驟:
(1)在內(nèi)核源碼目錄中的.../driver/char目錄中創(chuàng)建一個(gè)名為examples的子目錄;
(2)在內(nèi)核配置文件中添加一個(gè)菜單項(xiàng),以允許在編譯內(nèi)核時(shí)可以選擇編譯examples(編譯進(jìn)內(nèi)核或編譯成模塊);
(3)在.../driver/char/Makefile文件中添加一個(gè)子目錄項(xiàng)examples以對(duì)應(yīng)于前述第二步驟的菜單項(xiàng);
(4)為.../driver/char/examples目錄創(chuàng)建一個(gè)makefile文件,在其中為前述第二個(gè)步驟中創(chuàng)建的菜單項(xiàng)添加hello.o模塊對(duì)象以進(jìn)行編譯;
(5)添加驅(qū)動(dòng)程序源碼;

下面詳細(xì)描述前面的幾個(gè)步驟:

首先,在內(nèi)核源碼目錄的.../driver/char目錄中創(chuàng)建examples子目錄,而后再創(chuàng)建兩個(gè)文件:一個(gè)是前面例子中的驅(qū)動(dòng)源碼,一個(gè)是為其創(chuàng)建的makefile文件。makefile文件非常簡單,其內(nèi)容只有如下一行即可:
obj-$(CONFIG_EXAMPLES) += hello.o

添加菜單項(xiàng)至內(nèi)核配置工具的過程可能稍有些繞。首先需要在.../driver/char/Kconfig文件中添加一個(gè)"config"項(xiàng)以啟用前文中的examples配置項(xiàng)。添加位置是menu "Character devices"一行的后面,添加內(nèi)容如下:

config EXAMPLES
tristate "Enable Examples"
default m
---help---
   Enable compilation option for driver examples

而后回到內(nèi)核目錄中,運(yùn)行內(nèi)核編譯命令make gconfig(需要xwindow的支持)后,可以Device Drivers->Character drivers找到我們添加的“Enable Examples”項(xiàng),默認(rèn)為“-”(通過default項(xiàng)指定),即編譯為內(nèi)核模塊。如果指定為“對(duì)號(hào)”則表示以靜態(tài)方式編譯進(jìn)內(nèi)核;如果為空,則表示不編譯此項(xiàng)。如下圖所示:



接下來還需要在.../drivers/char/Makefile文件中添加一個(gè)選項(xiàng),以指示內(nèi)核編譯程序在我們選擇了CONFIG_EXAMPLES時(shí)會(huì)到examples子目錄中編譯hello1模塊。這需要在“obj-$(CONFIG_IPMI_HANDLER)      += ipmi/”一行附近添加如下行:

obj-$(CONFIG_EXAMPLES)          += examples/

至此,此示例驅(qū)動(dòng)構(gòu)建基礎(chǔ)結(jié)構(gòu)已經(jīng)完成,而且會(huì)在內(nèi)核編譯過程中自動(dòng)選擇此項(xiàng)進(jìn)行編譯了。在執(zhí)行完前面的"make gconfig"命令后,此時(shí)再執(zhí)行如下命令即可完成驅(qū)動(dòng)模塊的編譯。

# make modules
  
  CHK     include/linux/version.h
  CHK     include/linux/utsrelease.h
  CC [M]  drivers/char/examples/hello.o
  Building modules, stage 2.
  MODPOST
  CC      drivers/char/examples/hello.mod.o
  LD [M]  drivers/char/examples/hello.ko

如果您的編譯過程顯示有如上信息,則表示內(nèi)核模塊編譯完成。接下來就可以使用如下命令安裝剛剛編譯完成的內(nèi)核模塊:
# make modules_install

使用此種方式安裝時(shí),安裝過程會(huì)重新安裝所有已編譯的內(nèi)核模塊,包括此前編譯的其它模塊,而這并非是必須的。

在一個(gè)通過標(biāo)準(zhǔn)方式安裝的Linux系統(tǒng)上,內(nèi)核模塊通常位于/lib/modules//…之中,其中的即當(dāng)前系統(tǒng)運(yùn)行中的內(nèi)核版本號(hào),并且此目錄的結(jié)構(gòu)組織方式跟內(nèi)核源代碼樹的結(jié)構(gòu)是類似的。通常使用“make modules_install”命令安裝的模塊就位于此目錄中。因此,在單獨(dú)安裝某個(gè)或某些內(nèi)核模塊時(shí),可以通過在此目錄中創(chuàng)建跟編譯時(shí)內(nèi)核源碼樹中一樣的內(nèi)核模塊驅(qū)動(dòng)相關(guān)的目錄,并把編譯完成的*.ko文件復(fù)制到新建的對(duì)應(yīng)目錄中來實(shí)現(xiàn)。

5、加載/卸載內(nèi)核模塊

安裝完成后,便可以手動(dòng)加載或卸載這些模塊了,這可以使用modprobe實(shí)現(xiàn)。我們首先去加載hello模塊。
# modprobe hello
# tail -1 /var/log/messages
  Sep 14 22:06:23 localhost kernel: Hello Device Driver World!

此模塊在加載時(shí)會(huì)調(diào)用模塊初始化函數(shù),程序中使用module_init()宏(macro)來指定的模塊初始化函數(shù),如module_init(hello_init)。在此模塊中,初始化函數(shù)僅用來打印一行信息至系統(tǒng)日志,信息內(nèi)容是在hello_init()中定義好的。在實(shí)際驅(qū)動(dòng)程序編寫中,初始化函數(shù)常用來執(zhí)行資源分配及硬件設(shè)備初始化。
接下來可以使用lsmod命令以格式化列表的形式顯示系統(tǒng)中加載的所有模塊。如果其中有hello模塊出現(xiàn)則表示前面的加載是成功的。例如:
# lsmod
Module                  Size  Used by
hello                   5632  0
ipv6                  274208  18
autofs4                25092  2
i2c_core               25344  1 i2c_piix4
…………

其中Used by一列表示當(dāng)前模塊正在被使用的信息,以及依賴于當(dāng)前模塊的其它模塊。如最后一行表示i2c_piix4模塊依賴于i2c_core模塊。

內(nèi)核模塊的卸載可以通過使用modprobe的-r選項(xiàng)來實(shí)現(xiàn)。
# modprobe -r hello
# tail -1 /var/log/messages
  Sep 14 22:14:33 localhost kernel: Goodbye, Cruel World!

hello模塊退出時(shí)會(huì)調(diào)用exit例行函數(shù),這使用module_exit()宏來實(shí)現(xiàn)。其工作方式類似前面的加載過程。

下篇預(yù)告:接下來將介紹Linux系統(tǒng)上模塊管理的常用工具的使用方法,敬請(qǐng)期待。

參考書籍:
The Embedded Linux Primier
Linux Device Driver


本文來自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u/24866/showart_2053841.html

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2014-04-14 17:05 |只看該作者
頂。。。。!
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP