版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1
7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)7.2字符設(shè)備驅(qū)動(dòng)編程7.3GPIO驅(qū)動(dòng)程序?qū)嵗?.4按鍵驅(qū)動(dòng)編程實(shí)例第7章嵌入式Linux設(shè)備驅(qū)動(dòng)編程2
7.1.1Linux設(shè)備驅(qū)動(dòng)概述設(shè)備驅(qū)動(dòng)概念操作系統(tǒng)是通過各種驅(qū)動(dòng)程序來駕馭硬件設(shè)備的,它為用戶屏蔽了各種各樣的設(shè)備,驅(qū)動(dòng)硬件是操作系統(tǒng)最基本的功能,并且提供統(tǒng)一的操作方式。設(shè)備驅(qū)動(dòng)程序是操作系統(tǒng)最基本的組成部分之一,在Linux內(nèi)核源程序中也占有60%以上。因此,熟悉驅(qū)動(dòng)的編寫是很重要的。Linux的一個(gè)重要特點(diǎn)就是將所有的設(shè)備都當(dāng)做文件進(jìn)行處理,這一類特殊文件就是設(shè)備文件(通常在/dev目錄下),這樣在應(yīng)用程序看來,硬件設(shè)備只是一個(gè)設(shè)備文件,應(yīng)用程序可以象操作普通文件一樣對(duì)硬件設(shè)備進(jìn)行操作,這樣就大大方便了對(duì)設(shè)備的處理。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)
在ARM系統(tǒng)中,每個(gè)物理設(shè)備都有自己的控制器,每個(gè)硬件控制器都有各自的控制狀態(tài)寄存器,這些寄存器用來啟動(dòng)、停止、初始化設(shè)備,以及對(duì)設(shè)備進(jìn)行診斷,對(duì)硬件的控制主要是針對(duì)這些寄存器進(jìn)行操作——設(shè)備驅(qū)動(dòng)程序的主要功能就是完成對(duì)硬件寄存器的操作。
沒有操作系統(tǒng)時(shí)用戶程序?qū)拇嫫鞯牟僮鳎?/p>
#definerGPFCON(*(volatileunsigned*)0x56000050) rGPFCON=0x55aa;7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)4
7.1.1Linux設(shè)備驅(qū)動(dòng)概述Linux系統(tǒng)的設(shè)備分為三類:字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)設(shè)備.字符設(shè)備通常指像普通文件或字節(jié)流一樣,以字節(jié)為單位順序讀寫的設(shè)備,如并口設(shè)備、虛擬控制臺(tái)等。塊設(shè)備通常指一些需要以塊為單位隨機(jī)讀寫的設(shè)備,如IDE硬盤、SCSI硬盤、光驅(qū)等。
字符設(shè)備和塊設(shè)備可以像文件一樣被訪問,例如,驅(qū)動(dòng)程序都會(huì)實(shí)現(xiàn)open(打開)、close(關(guān)閉,或叫release)、read(讀?。?、write(寫入)或seek(定位)等操作。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)5
7.1.1Linux設(shè)備驅(qū)動(dòng)概述網(wǎng)絡(luò)設(shè)備通常是指通過網(wǎng)絡(luò)能夠與其他主機(jī)進(jìn)行數(shù)據(jù)通信的設(shè)備,如網(wǎng)卡等。Linux網(wǎng)絡(luò)設(shè)備不是面向流的設(shè)備,因此不會(huì)將網(wǎng)絡(luò)設(shè)備的名字(如eth0)映射到文件系統(tǒng)中。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)6
7.1.1Linux設(shè)備驅(qū)動(dòng)概述設(shè)備驅(qū)動(dòng)程序的特點(diǎn)內(nèi)核代碼:驅(qū)動(dòng)程序是內(nèi)核的一部分內(nèi)核接口:為內(nèi)核提供標(biāo)準(zhǔn)接口內(nèi)核機(jī)制和服務(wù):設(shè)備驅(qū)動(dòng)程序使用標(biāo)準(zhǔn)的內(nèi)核服務(wù)可裝載:可加載/卸載可設(shè)置:可配置為內(nèi)核的一部分動(dòng)態(tài)性7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)7
7.1.1Linux設(shè)備驅(qū)動(dòng)概述設(shè)備驅(qū)動(dòng)程序與整個(gè)軟硬件系統(tǒng)的關(guān)系7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)設(shè)備文件
Linux把所有設(shè)備都看作是特殊的文件,都納入文件系統(tǒng)的范疇,例如,系統(tǒng)中第一個(gè)IDE硬盤使用/dev/hda來表示。系統(tǒng)通過處理文件的接口—虛擬文件系統(tǒng)VFS來管理和控制各種設(shè)備,Linux的設(shè)備又稱為設(shè)備文件。Linux抽象了對(duì)硬件的處理,所有的硬件設(shè)備都可以作為普通文件來看待,對(duì)它們的使用和操作文件相同,使用標(biāo)準(zhǔn)的系統(tǒng)調(diào)用接口來完成打開、關(guān)閉、讀寫和I/O控制等操作,驅(qū)動(dòng)程序的主要任務(wù)也就是要實(shí)現(xiàn)這些系統(tǒng)調(diào)用函數(shù)。由于引入了設(shè)備文件這一概念,Linux為文件和設(shè)備提供了一致的用戶接口,對(duì)用戶來說,設(shè)備文件與普通文件并無區(qū)別。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)主設(shè)備號(hào)與次設(shè)備號(hào)
Linux下每個(gè)設(shè)備都對(duì)應(yīng)兩個(gè)設(shè)備號(hào),一個(gè)是主設(shè)備號(hào),標(biāo)識(shí)該設(shè)備的類別,也標(biāo)識(shí)該設(shè)備的驅(qū)動(dòng)程序;另一個(gè)是從設(shè)備號(hào),標(biāo)識(shí)使用同一個(gè)設(shè)備驅(qū)動(dòng)程序的、不同的硬件設(shè)備。設(shè)備文件的主設(shè)備號(hào)必須與設(shè)備驅(qū)動(dòng)程序在登記時(shí)申請(qǐng)的主設(shè)備號(hào)一致,否則用戶進(jìn)程將無法訪問驅(qū)動(dòng)程序。習(xí)慣上,設(shè)備文件都存在于系統(tǒng)的/dev目錄下。使用命令#ls–l/dev,可以列出系統(tǒng)的設(shè)備文件,下面是該命令顯示的部分內(nèi)容:crw-------1rootroot10,10Jan302003adbmousecrw-------1rootroot14,3Jan302003dspbrw-rw----1rootfloppy2,0Jan302003fd0brw-rw----1rootfloppy2,4Jan302003fd0CompaQ7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)主設(shè)備號(hào)與次設(shè)備號(hào)使用命令mknod可以創(chuàng)建指定類型的設(shè)備文件,同時(shí)為其分配主設(shè)備號(hào)和次設(shè)備號(hào):
#mknod/dev/dspc143命令中c表示字符設(shè)備,14是主設(shè)備號(hào),3是次設(shè)備號(hào)。主設(shè)備號(hào)的范圍是1~255,次設(shè)備號(hào)可以使0~255間的值。系統(tǒng)依靠主設(shè)備號(hào)標(biāo)識(shí)不同的驅(qū)動(dòng)程序,因此在同一個(gè)系統(tǒng)中,一類設(shè)備的主設(shè)備號(hào)是唯一的。所有已經(jīng)注冊(cè)(即已經(jīng)加載了驅(qū)動(dòng)程序)的硬件設(shè)備的主設(shè)備號(hào)都可以在文件/proc/devices中得到。#cat/proc/devices7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)11
7.1.2Linux內(nèi)核模塊編程設(shè)備驅(qū)動(dòng)和內(nèi)核模塊Linux設(shè)備驅(qū)動(dòng)屬于內(nèi)核的一部分,Linux內(nèi)核的一個(gè)模塊可以以兩種方式被編譯和加載。直接編譯進(jìn)Linux內(nèi)核,隨同Linux啟動(dòng)時(shí)加載;編譯成一個(gè)可加載和刪除的模塊。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)12
7.1.2Linux內(nèi)核模塊編程模塊相關(guān)命令lsmod列出當(dāng)前系統(tǒng)中加載的模塊
7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)13
7.1.2Linux內(nèi)核模塊編程模塊相關(guān)命令rmmod——用于模塊卸載。insmod和modprobe——用于加載模塊modprobe可以根據(jù)模塊間依存關(guān)系以及/etc/modules.conf文件中的內(nèi)容自動(dòng)加載其他有依賴關(guān)系的模塊,而insmod不會(huì)自動(dòng)解決依存關(guān)系,即如果要加載的模塊引用了當(dāng)前內(nèi)核符號(hào)表中不存在的符號(hào),則無法加載。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)14
小結(jié)操作系統(tǒng)通過各種驅(qū)動(dòng)程序來駕馭硬件設(shè)備,為用戶屏蔽了各種各樣的設(shè)備的差異性,提供統(tǒng)一的操作方式。Linux系統(tǒng)的設(shè)備分為三類:字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)設(shè)備。Linux下每個(gè)設(shè)備都對(duì)應(yīng)兩個(gè)設(shè)備號(hào),一個(gè)是主設(shè)備號(hào),另一個(gè)是從設(shè)備號(hào)。
#mknod/dev/dspc143Linux內(nèi)核的一個(gè)模塊可以以兩種方式被編譯和加載。模塊命令:lsmod insmod rmmod7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)15
7.1.2Linux內(nèi)核模塊編程一個(gè)Linux內(nèi)核模塊主要由以下幾個(gè)部分組成。模塊加載函數(shù)(必須)模塊卸載函數(shù)(必須)模塊許可證聲明(必須)模塊參數(shù)(可選):接收加載模塊時(shí)傳入的數(shù)據(jù),對(duì)應(yīng)模塊的全局變量;模塊導(dǎo)出符號(hào)(可選):對(duì)應(yīng)于模塊的函數(shù)或變量,導(dǎo)出后可供其它模塊使用。模塊作者等信息聲明(可選)7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)16
7.1.2Linux內(nèi)核模塊編程模塊加載函數(shù)staticint__initinitialization_function(void){ /*初始化代碼*/}module_init(initialization_function);模塊加載函數(shù)以“module_init(funcName)”的形式指定,當(dāng)通過insmod或modprobe命令加載內(nèi)核模塊時(shí),模塊的加載函數(shù)會(huì)自動(dòng)被內(nèi)核執(zhí)行,完成本模塊的相關(guān)初始化工作。包括向內(nèi)核注冊(cè)設(shè)備、申請(qǐng)內(nèi)存等。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)初始化完成后釋放該函數(shù)占用的內(nèi)存17
7.1.2Linux內(nèi)核模塊編程模塊卸載函數(shù)staticvoid__exitcleanup_function(void){ /*釋放代碼*/}module_exit(cleanup_function);模塊卸載函數(shù)以“module_exit(funcName)”的形式指定,通常來說,模塊卸載函數(shù)要完成與模塊加載函數(shù)相反的功能(釋放內(nèi)存、釋放硬件資源)。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)函數(shù)在運(yùn)行完成后自動(dòng)回收內(nèi)存18
7.1.2Linux內(nèi)核模塊編程——模塊參數(shù)定義方式:module_param(參數(shù)名,參數(shù)類型,讀寫權(quán)限):
staticchar*str_param=“LinuxModule”; staticintnum_param=4000; module_param(num_param,int,S_IRUGO); module_param(str_param,charp,S_IRUGO);傳值方式
insmode模塊名參數(shù)名=參數(shù)值7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)19
7.1.2Linux內(nèi)核模塊編程——模塊參數(shù)參數(shù)類型:
byte,short,ushort,int,uint,long,ulong,charp讀寫權(quán)限
模塊加載后,在/sys/module/目錄下將出現(xiàn)以此模塊命名的目錄,如果此模塊存在讀寫權(quán)限不用0的參數(shù),在此模塊的目錄下還將出現(xiàn)parameters目錄,包含一系列以參數(shù)名命名的文件節(jié)點(diǎn),這些文件的權(quán)限值就是對(duì)應(yīng)參數(shù)的權(quán)限值。通常使用<linux/stat.h>中定義的值來表示權(quán)限值。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)20
7.1.2Linux內(nèi)核模塊編程導(dǎo)出符號(hào):
Linux2.6的/proc/kallsyms文件對(duì)應(yīng)著內(nèi)核符號(hào)表,記錄了符號(hào)及符號(hào)所在的內(nèi)存地址。
模塊中可使用如下宏導(dǎo)出符號(hào)到內(nèi)核符號(hào)表:
EXPORT_SYMBOL(符號(hào)名); EXPORT_SYMBOL_GPL(符號(hào)名);
導(dǎo)出的符號(hào)可以被其它模塊使用,使用前需要進(jìn)行聲明。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)21
7.1.2Linux內(nèi)核模塊編程——模塊參數(shù)模塊聲明與描述:
MODULE_AUTHOR(author); MODULE_DESCRIPTION(description); MODULE_VERSION(version); MODULE_DEVICE_TABLE(table_info); MODULE_ALIAS(alternate_name);7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)22
7.1.2Linux內(nèi)核模塊編程模塊的使用計(jì)數(shù)Linux2.4內(nèi)核中,模塊自身通過MOD_INC_USE_COUNT、MOD_DEC_USE_COUNT宏來管理自己被使用的計(jì)數(shù)。Linux2.6內(nèi)核提供了模塊計(jì)數(shù)管理接口try_module_get(&module)和module_put(&module),從而取代Linux2.4內(nèi)核中的模塊使用計(jì)數(shù)管理宏。
7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)23
7.1.2Linux內(nèi)核模塊編程模塊許可證聲明:MODULE_LICENSE("DualBSD/GPL");聲明內(nèi)核模塊的許可權(quán)限,linux2.6內(nèi)核中,可接受的LICENSE包括GPL、GPLv2、GPLandadditioanlrights、DualBSD/GPL等,如果不聲明LICENSE,模塊被加載時(shí)將收到內(nèi)核被污染的警告(KernelTainted)。7.1設(shè)備驅(qū)動(dòng)編程基礎(chǔ)Linux下的設(shè)備驅(qū)動(dòng)程序可以按照兩種方式進(jìn)行編譯,一種是直接靜態(tài)編譯成內(nèi)核的一部分,另一種是編譯成可以動(dòng)態(tài)加載的模塊,在系統(tǒng)調(diào)試階段,多使用模塊方式。1、模塊的入口函數(shù)用戶程序通常從main()函數(shù)開始,執(zhí)行一系列指令直到程序結(jié)束,內(nèi)核模塊與此不同,內(nèi)核模塊從函數(shù)init_module或是用宏module_init指定的函數(shù)調(diào)用開始,這就是內(nèi)核模塊的入口函數(shù)。它通常向內(nèi)核注冊(cè)模塊提供哪些功能并且讓內(nèi)核準(zhǔn)備好在需要時(shí)調(diào)用它。當(dāng)它完成這些后,該函數(shù)就結(jié)束執(zhí)行了。模塊在被內(nèi)核調(diào)用前什么都不做。模塊編程實(shí)例(2.4內(nèi)核下)
2、模塊的退出函數(shù)所有的模塊或是調(diào)用cleanup_module或是用宏module_exit指定函數(shù)。這是模塊的退出函數(shù),它撤銷入口函數(shù)所做的一切。例如注銷入口函數(shù)所注冊(cè)的功能。所有模塊都必須有入口函數(shù)和退出函數(shù)。模塊編程實(shí)例
3、模塊可調(diào)用的函數(shù)每一個(gè)module都可以提供一些函數(shù)或變量讓別人使用,同時(shí)也可以使用已經(jīng)載入kernel里的module提供的function。除此之外,kernel本身也會(huì)提供一些funciton或variable供module使用。也就是說:module所使用的function或variable,要么是寫在module中,要么就是別的module提供的,再不就是kernel所提供的。不能使用libc或glibc所提供的function,像printf之類的東西。模塊編程實(shí)例
4、最簡(jiǎn)單的模塊程序?qū)嵗猦elloworld#include<linux/init.h>#include<linux/module.h>MODULE_LICENSE("DualBSD/GPL");inthello_init(void){ printk("<1>Hello,world\n"); return0;}voidhello_exit(void){ printk("\n<1>Goodbyecruelworld\n");}module_init(hello_init);module_exit(hello_exit);模塊編程實(shí)例
4、最簡(jiǎn)單的模塊程序?qū)嵗猦elloworld運(yùn)行如下的編譯命令,就可以得到相應(yīng)的.o文件:#gcc-chello_module.c-D__KERNEL__-DMODULE-I/usr/src/linux-2.4.20-8/include/-O-Wall之后運(yùn)行insmod命令,就可以加載該模塊,通過lsmod命令可以看相應(yīng)的模塊已經(jīng)加載。例子中的printk()函數(shù)用來向用戶顯示一些信息,但它并不是設(shè)計(jì)用來同用戶交互的,它實(shí)際上是為內(nèi)核提供日志功能,記錄內(nèi)核信息或用來給出警告。函數(shù)調(diào)用中的<1>為信息的優(yōu)先級(jí),內(nèi)核共定義了8個(gè)優(yōu)先級(jí),并在linux/kernel.h中定義了8個(gè)優(yōu)先級(jí)的宏,如實(shí)際中,推薦使用KERN_ALERT來代替<1>。調(diào)試時(shí)在真正的控制臺(tái)下加載模塊才能看到顯示的信息,否則只記錄在文件/var/log/messages中。模塊編程
4、最簡(jiǎn)單的模塊程序?qū)嵗猦elloworld注意事項(xiàng):內(nèi)核模塊和內(nèi)核的版本問題:為某個(gè)版本編譯的模塊不能被另一個(gè)版本的內(nèi)核加載。使用圖形界面的問題:建議在控制臺(tái)下輸入源代碼、編譯和加載,而不是在X下。gcc傾向于在默認(rèn)的內(nèi)核源文件路徑(通常是/usr/src/)下尋找包含文件(頭文件),可以通過gcc的-I選項(xiàng)來切換。模塊編程
30
7.2.1字符設(shè)備驅(qū)動(dòng)編寫(運(yùn)行)流程7.2字符設(shè)備驅(qū)動(dòng)編程根據(jù)具體功能劃分,設(shè)備驅(qū)動(dòng)程序的代碼則可以劃分為以下幾個(gè)部分:驅(qū)動(dòng)程序的注冊(cè)和注銷、設(shè)備的打開、釋放、讀寫、控制等操作操作、設(shè)備的中斷和輪詢處理。用戶程序通常利用這幾個(gè)部分對(duì)設(shè)備進(jìn)行訪問,由于用戶程序不能直接訪問內(nèi)核驅(qū)動(dòng)程序,所以Linux系統(tǒng)中用戶對(duì)設(shè)備的操作需要Linux系統(tǒng)中虛擬文件系統(tǒng)的支持。用戶采用標(biāo)準(zhǔn)的文件操作訪問設(shè)備,虛擬文件系統(tǒng)將用戶的這種文件訪問轉(zhuǎn)化成驅(qū)動(dòng)程序的調(diào)用,從而產(chǎn)生對(duì)硬件的訪問和操作。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
32
7.2字符設(shè)備驅(qū)動(dòng)編程字符設(shè)備驅(qū)動(dòng)相關(guān)結(jié)構(gòu)體(定義在linux/fs.h中):file_operations,對(duì)設(shè)備驅(qū)動(dòng)相關(guān)的接口函數(shù)進(jìn)行了統(tǒng)一的抽象。用來存儲(chǔ)驅(qū)動(dòng)內(nèi)核模塊提供的對(duì)設(shè)備進(jìn)行各種操作的函數(shù)的指針,把系統(tǒng)調(diào)用和驅(qū)動(dòng)程序關(guān)聯(lián)起來。file,代表一個(gè)打開的文件描述符,系統(tǒng)中每一個(gè)打開的文件在內(nèi)核中都有一個(gè)關(guān)聯(lián)的structfile。它由內(nèi)核在open時(shí)創(chuàng)建,并傳遞給在文件上操作的任何函數(shù)。inode,(i結(jié)點(diǎn)),內(nèi)核中用inode結(jié)構(gòu)表示具體的文件。對(duì)于單個(gè)文件,可能會(huì)有多個(gè)表示打開的文件描述符file結(jié)構(gòu),但是它們都指向了單個(gè)的inode結(jié)構(gòu)。33
7.2字符設(shè)備驅(qū)動(dòng)編程字符設(shè)備驅(qū)動(dòng)相關(guān)結(jié)構(gòu)體(定義在linux/fs.h中):structfile_operations{structmodule*owner;loff_t(*llseek)(structfile*,loff_t,int);ssize_t(*read)(structfile*,char*,size_t,loff_t*);ssize_t(*write)(structfile*,constchar*,size_t,loff_t*); int(*open)(structinode*,structfile*);int(*release)(structinode*,structfile*); ……};為實(shí)現(xiàn)這種用戶文件操作到設(shè)備操作的轉(zhuǎn)換,虛擬文件系統(tǒng)向下為設(shè)備驅(qū)動(dòng)提供了一個(gè)標(biāo)準(zhǔn)化的文件操作實(shí)現(xiàn)接口,這個(gè)接口由/include/linus/fs.h文件中的file_operations結(jié)構(gòu)定義,其成員幾乎全部是函數(shù)指針。開發(fā)設(shè)備驅(qū)動(dòng)程序的主要任務(wù)就是實(shí)現(xiàn)這個(gè)文件操作實(shí)現(xiàn)接口結(jié)構(gòu)中的函數(shù)指針。應(yīng)用程序利用系統(tǒng)調(diào)用對(duì)設(shè)備進(jìn)行讀寫操作時(shí),Linux通過設(shè)備的主設(shè)備號(hào)找到相應(yīng)的驅(qū)動(dòng)程序,然后通過虛擬文件系統(tǒng)調(diào)用這個(gè)文件操作實(shí)現(xiàn)接口,文件操作實(shí)現(xiàn)接口調(diào)用設(shè)備驅(qū)動(dòng)程序完成對(duì)硬件的操作。在file_operations結(jié)構(gòu)中,一般只有主要的部分必須實(shí)現(xiàn):open(),release(),read(),write(),ioctl(),llseek()等。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
1.驅(qū)動(dòng)程序的注冊(cè)和注銷
設(shè)備驅(qū)動(dòng)程序可以在系統(tǒng)啟動(dòng)的時(shí)候初始化,也可以在需要的時(shí)候動(dòng)態(tài)加載。每個(gè)字符設(shè)備或是塊設(shè)備的初始化都是通過register_chrdev()或是register_blkdev()向內(nèi)核注冊(cè)。在關(guān)閉字符設(shè)備或是塊設(shè)備時(shí),還需要通過unregister_chrdev()或是unregister_blkdev()從內(nèi)核中注銷設(shè)備。
設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
1.驅(qū)動(dòng)程序的注冊(cè)和注銷intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);major:主設(shè)備號(hào),為0則系統(tǒng)自動(dòng)分配返回值:如果是動(dòng)態(tài)分配主設(shè)備號(hào),則返回分配的主設(shè)備號(hào),且設(shè)備名會(huì)出現(xiàn)在/proc/devices中intunregister_chrdev(unsignedintmajor,constchar*name);設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
2.設(shè)備的打開和釋放
打開設(shè)備的函數(shù)接口為open()。 int(*open)(structinode*,structfile*);在大部分設(shè)備驅(qū)動(dòng)程序中,open完成如下工作:(1)增加設(shè)備的使用計(jì)數(shù)。(2)檢查設(shè)備的相關(guān)錯(cuò)誤,如設(shè)備尚未準(zhǔn)備好或是類似硬件的問題。(3)檢查是首次打開,則初始化設(shè)備。(4)識(shí)別次設(shè)備號(hào),如有必要?jiǎng)t更新f_op指針。(5)如果需要,分配且設(shè)置要放在filp->private_data里的數(shù)據(jù)結(jié)構(gòu)。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
2.設(shè)備的打開和釋放
釋放設(shè)備由release()來完成
int(*release)(structinode*,structfile*);
注意釋放和關(guān)閉設(shè)備的區(qū)別。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
3.設(shè)備的讀寫操作ssize_t(*read)(structfile*,char*,size_t,loff_t*);ssize_t(*write)(structfile*,constchar*,size_t,loff_t*);字符設(shè)備使用各自的read()和write()來進(jìn)行數(shù)據(jù)讀寫。用戶程序不能直接讀寫內(nèi)核空間的數(shù)據(jù),所以需要在驅(qū)動(dòng)程序使用copy_to_user()和copy_from_user()函數(shù)來實(shí)現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)交換。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
4.設(shè)備的控制操作除了讀寫操作,有時(shí)還要控制設(shè)備。這可以通過設(shè)備驅(qū)動(dòng)程序中的ioctl()來完成。例如IDE硬盤的控制可以通過hd_ioctl(),對(duì)光驅(qū)的控制可以通過cdrom_ioctl()。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
5.設(shè)備的輪詢和中斷處理對(duì)于不支持中斷的設(shè)備,讀寫時(shí)需要輪詢?cè)O(shè)備狀態(tài),以及是否需要繼續(xù)進(jìn)行數(shù)據(jù)傳輸。輪詢方式(pollingmode)也就是查詢等待方式。對(duì)于不支持中斷方式的硬件設(shè)備只能采用這種方式來控制I/O過程,所以Linux中也配備了查詢等待方式。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
5.設(shè)備的輪詢和中斷處理在硬件支持中斷的情況下,驅(qū)動(dòng)程序可以使用中斷方式控制I/O過程。Linux設(shè)置了名字為irq_action的中斷例程描述符表:
staticstructirqaction*irq_action[NR_IRQS+1]; NR_IRQS表示中斷源的數(shù)目。irq_action[]是一個(gè)指向irqaction結(jié)構(gòu)的指針數(shù)組,它指向的irqaction結(jié)構(gòu)是各個(gè)設(shè)備中斷服務(wù)例程的描述符。
structirqaction{ void(*handler)(int,void*,structpt_regs*);
/*指向中斷服務(wù)例程*/ unsignedlongflags;/*中斷標(biāo)志*/ unsignedlongmask;/*中斷掩碼*/ void*dev_id; structirqaction*next;/*指向下一個(gè)描述符*/};
在驅(qū)動(dòng)程序初始化時(shí),調(diào)用函數(shù)request_irq()建立該驅(qū)動(dòng)程序的irqaction結(jié)構(gòu)體,并把它登記到irq_action[]數(shù)組中設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
5.設(shè)備的輪詢和中斷處理
request_irq()函數(shù)的原型如下:intrequest_irq( usignedintirq, void(*handle)(int,void*,structpt_regs*), unsignedlongirqflags, constchar*devname, void*dev_id);參數(shù)irq是設(shè)備中斷請(qǐng)求號(hào),在向irq_action[]數(shù)組登記時(shí),它作為數(shù)組的下標(biāo)。把中斷號(hào)為irq的irqaction結(jié)構(gòu)體的首地址寫入irq_action[irq]。這樣,就把設(shè)備的中斷請(qǐng)求號(hào)與該設(shè)備的服務(wù)例程聯(lián)系在一起了。當(dāng)CPU接收到中斷請(qǐng)求后,根據(jù)中斷號(hào)就可以通過irq_action[]找到該設(shè)備的中斷服務(wù)程序。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
※字符設(shè)備驅(qū)動(dòng)案例
#defineDEVICE_NAME"demo"staticssize_tdemo_write(structfile*filp,constchar*buffer,size_tcount){ chardrv_buf[]; copy_from_user(drv_buf,buffer,count);…}staticssize_tdemo_read(structfile*filp,char*buffer,size_tcount,loff_t*ppos){ chardrv_buf[]; copy_to_user(buffer,drv_buf,count);….}程序代碼框架※字符設(shè)備驅(qū)動(dòng)案例
staticintdemo_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg){}staticintdemo_open(structinode*inode,structfile*file){ MOD_INC_USE_COUNT; ……}staticintdemo_release(structinode*inode,structfile*filp){ MOD_DEC_USE_COUNT; ……}程序代碼框架※字符設(shè)備驅(qū)動(dòng)案例
staticstructfile_operationsdemo_fops={owner:THIS_MODULE,write:demo_write,read:demo_read,ioctl:demo_ioctl,open:demo_open,release:demo_release,};程序代碼框架※字符設(shè)備驅(qū)動(dòng)案例
staticint__initdemo_init(void){intresult;result=register_chrdev(demo_Major,“demo",&demo_fops);if(result<0)returnresult;if(demo_Major==0)demo_Major=result;/*dynamic*/printk(DEVICE_NAME"initialized\n");return0;}程序代碼框架※字符設(shè)備驅(qū)動(dòng)案例
staticvoid__exitdemo_exit(void){unregister_chrdev(demo_major,"demo");printk(DEVICE_NAME"unloaded\n");}module_init(demo_init);module_exit(demo_exit);程序代碼框架※字符設(shè)備驅(qū)動(dòng)案例
代碼功能分析:#include<linux/config.h>#include<linux/module.h>#include<linux/devfs_fs_kernel.h>#include<linux/init.h>#include<linux/kernel.h>/*printk()*/#include<linux/slab.h>/*kmalloc()*/#include<linux/fs.h>/*everything...*/#include<linux/errno.h>/*errorcodes*/#include<linux/types.h>/*size_t*/#include<linux/proc_fs.h>#include<linux/fcntl.h>/*O_ACCMODE*/#include<linux/poll.h>/*COPY_TO_USER*/#include<asm/system.h>/*cli(),*_flags*※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:#defineDEVICE_NAME "demo"#definedemo_MAJOR254#definedemo_MINOR0staticintMAX_BUF_LEN=1024;staticchardrv_buf[1024];staticintWRI_LENGTH=0;※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:/*逆序排列緩沖區(qū)數(shù)據(jù)*/staticvoiddo_write(){ inti; intlen=WRI_LENGTH; chartmp; for(i=0;i<(len>>1);i++,len--){ tmp=drv_buf[len-1]; drv_buf[len-1]=drv_buf[i]; drv_buf[i]=tmp; }}※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:staticssize_tdemo_write(structfile*filp,constchar*buffer,size_tcount){ if(count>MAX_BUF_LEN)count=MAX_BUF_LEN;
copy_from_user(drv_buf,buffer,count); WRI_LENGTH=count; printk("userwritedatatodriver\n"); do_write(); returncount;}※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:staticssize_tdemo_read(structfile*filp,char*buffer,size_tcount,loff_t*ppos){ if(count>MAX_BUF_LEN) count=MAX_BUF_LEN;
copy_to_user(buffer,drv_buf,count); printk("userreaddatafromdriver\n"); returncount;}※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:staticintdemo_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg){ printk("ioctlruning\n"); switch(cmd){ case1:printk("runingcommand1\n");break; case2:printk("runingcommand2\n");break; default: printk("errorcmdnumber\n");break; } return0;}※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:staticintdemo_open(structinode*inode,structfile*file){ MOD_INC_USE_COUNT; sprintf(drv_buf,"deviceopensucess!\n"); printk("deviceopensucess!\n"); return0;}※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:staticintdemo_release(structinode*inode,structfile*filp){ MOD_DEC_USE_COUNT; printk("devicerelease\n"); return0;}※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:staticstructfile_operationsdemo_fops={ owner: THIS_MODULE, write: demo_write, read: demo_read, ioctl: demo_ioctl, open: demo_open, release: demo_release,};※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:staticint__initdemo_init(void){ intresult;SET_MODULE_OWNER(&demo_fops);result=register_chrdev(demo_MAJOR,"demo",&demo_fops);if(result<0)returnresult;//if(demo_MAJOR==0)demo_MAJOR=result;/*dynamic*/ printk(DEVICE_NAME"initialized\n"); return0;}※字符設(shè)備驅(qū)動(dòng)案例
代碼分析功能分析:staticvoid__exitdemo_exit(void){unregister_chrdev(demo_MAJOR,"demo"); printk(DEVICE_NAME"unloaded\n");}/*************************************************************************************/module_init(demo_init);module_exit(demo_exit);※字符設(shè)備驅(qū)動(dòng)案例
模塊化驅(qū)動(dòng)程序的編譯、加載和卸載:1、編譯
#gcc-cdemo.c-D__KERNEL__-DMODULE-I/usr/src/linux-2.4.20-8/include/-O-Wall2、創(chuàng)建設(shè)備節(jié)點(diǎn)
#mknod/dev/democ25402、加載
#insmoddemo.o3、卸載
#rmmoddemo※字符設(shè)備驅(qū)動(dòng)案例
新建設(shè)備的測(cè)試程序:#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<unistd.h>#include<sys/ioctl.h>intMAX_LEN=32;※字符設(shè)備驅(qū)動(dòng)案例
新建設(shè)備的測(cè)試程序:voidshowbuf(char*buf){ inti,j=0; for(i=0;i<MAX_LEN;i++){ if(i%4==0) printf("\n%4d:",j++); printf("%4d",buf[i]); } printf("\n*****************************************************\n");}※字符設(shè)備驅(qū)動(dòng)案例
新建設(shè)備的測(cè)試程序:intmain(){ intfd; inti; charbuf[255];
for(i=0;i<MAX_LEN;i++){ buf[i]=i;
} fd=open("/dev/demo",O_RDWR); if(fd<0){ printf("####DEMOdeviceopenfail####\n"); return(-1);
}※字符設(shè)備驅(qū)動(dòng)案例
新建設(shè)備的測(cè)試程序: printf("write%dbytesdatato/dev/demo\n",MAX_LEN); showbuf(buf); write(fd,buf,MAX_LEN); printf("Read%dbytesdatafrom/dev/demo\n",MAX_LEN); read(fd,buf,MAX_LEN); showbuf(buf); ioctl(fd,1,NULL); ioctl(fd,4,NULL); close(fd); return0;}※字符設(shè)備驅(qū)動(dòng)案例
demo.c回顧:根據(jù)具體功能劃分,設(shè)備驅(qū)動(dòng)程序的代碼則可以劃分為以下幾個(gè)部分:驅(qū)動(dòng)程序的注冊(cè)和注銷、設(shè)備的打開和釋放、設(shè)備的讀寫操作、設(shè)備的控制操作、設(shè)備的中斷和輪詢處理。問題:1、從demo.c中找出上述代碼各部分的代碼。
2、找出test_demo.c對(duì)驅(qū)動(dòng)程序中相關(guān)功能調(diào)用的代碼,觀察功能調(diào)用的語法與demo.c中定義的相關(guān)函數(shù)原型之時(shí)的關(guān)系,有什么發(fā)現(xiàn)?66
設(shè)備驅(qū)動(dòng)程序與整個(gè)軟硬件系統(tǒng)的關(guān)系※字符設(shè)備驅(qū)動(dòng)案例
總結(jié):驅(qū)動(dòng)模塊的注冊(cè):推薦使用宏module_init()來指定驅(qū)動(dòng)程序的初始化函數(shù);用宏__init修飾初始化函數(shù),使被修飾的函數(shù)代碼只在啟動(dòng)時(shí)執(zhí)行一次,啟動(dòng)之后可以釋放相應(yīng)的內(nèi)存空間。向內(nèi)核注冊(cè)驅(qū)動(dòng)程序:register_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops)※字符設(shè)備驅(qū)動(dòng)案例
總結(jié):打開設(shè)備時(shí)需要做的工作:
(1)增加設(shè)備的使用計(jì)數(shù)(MOD_INC_USE_COUNT)。(2)檢查設(shè)備的相關(guān)錯(cuò)誤,如設(shè)備尚未準(zhǔn)備好或是類似硬件的問題。(3)如果是首次打開,則初始化設(shè)備。(4)識(shí)別次設(shè)備號(hào),如有必要?jiǎng)t更新f_op指針?!址O(shè)備驅(qū)動(dòng)案例
總結(jié):讀、寫操作:
使用copy_to_user(buffer,drv_buf,count)和copy_from_user(drv_buf,buffer,count)
在內(nèi)核空間和用戶空間之間傳遞數(shù)據(jù)?!址O(shè)備驅(qū)動(dòng)案例
總結(jié):structfile_operations結(jié)構(gòu)初始化(2.4內(nèi)核中):
staticstructfile_operationsdemo_fops={ owner: THIS_MODULE, write: demo_write, read: demo_read, ioctl: demo_ioctl, open: demo_open, release: demo_release,};※字符設(shè)備驅(qū)動(dòng)案例
總結(jié):structfile_operations結(jié)構(gòu)初始化(2.6內(nèi)核中):
staticstructfile_operationsdemo_fops={ .owner= THIS_MODULE, .write= demo_write, .read= demo_read, .ioctl= demo_ioctl, .open= demo_open, .release= demo_release,};※字符設(shè)備驅(qū)動(dòng)案例
總結(jié):release/close:使用宏MOD_DEC_USE_COUNT遞減計(jì)數(shù)器卸載:使用unregister_chrdev(demo_MAJOR,“demo”)向內(nèi)核注銷驅(qū)動(dòng)模塊。5.設(shè)備的中斷處理在硬件支持中斷的情況下,驅(qū)動(dòng)程序可以使用中斷方式控制I/O過程。Linux設(shè)置了名字為irq_action的中斷例程描述符表:
staticstructirqaction*irq_action[NR_IRQS+1]; NR_IRQS表示中斷源的數(shù)目。irq_action[]是一個(gè)指向irqaction結(jié)構(gòu)的指針數(shù)組,它指向的irqaction結(jié)構(gòu)是各個(gè)設(shè)備中斷服務(wù)例程的描述符。
structirqaction{ void(*handler)(int,void*,structpt_regs*);
/*指向中斷服務(wù)例程*/ unsignedlongflags;/*中斷標(biāo)志*/ unsignedlongmask;/*中斷掩碼*/ void*dev_id; structirqaction*next;/*指向下一個(gè)描述符*/};
在驅(qū)動(dòng)程序初始化時(shí),調(diào)用函數(shù)request_irq()建立該驅(qū)動(dòng)程序的irqaction結(jié)構(gòu)體,并把它登記到irq_action[]數(shù)組中設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
5.設(shè)備的中斷處理
request_irq()函數(shù)的原型如下:intrequest_irq( usignedintirq, void(*handle)(int,void*,structpt_regs*), unsignedlongirqflags, constchar*devname, void*dev_id);參數(shù)irq是設(shè)備中斷請(qǐng)求號(hào),在向irq_action[]數(shù)組登記時(shí),它作為數(shù)組的下標(biāo)。把中斷號(hào)為irq的irqaction結(jié)構(gòu)體的首地址寫入irq_action[irq]。這樣,就把設(shè)備的中斷請(qǐng)求號(hào)與該設(shè)備的服務(wù)例程聯(lián)系在一起了。當(dāng)CPU接收到中斷請(qǐng)求后,根據(jù)中斷號(hào)就可以通過irq_action[]找到該設(shè)備的中斷服務(wù)程序。設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)
※字符設(shè)備驅(qū)動(dòng)案例
總結(jié):字符設(shè)備驅(qū)動(dòng)程序基本結(jié)構(gòu)編寫所需要的功能函數(shù):read,write,ioctl,open,release以及中斷服務(wù)程序等;定義structfile_operations結(jié)構(gòu)變量,并將步驟1中定義的功能函數(shù)賦值該變量中相應(yīng)的函數(shù)指針;編寫初始化函數(shù),實(shí)現(xiàn)驅(qū)動(dòng)模塊的注冊(cè)加載、中斷服務(wù)程序的登記;編寫驅(qū)動(dòng)程序注銷函數(shù);使用宏module_init,module_exit聲明初始化(注冊(cè))和注銷函數(shù)。767.3.1GPIO工作原理FS2410開發(fā)板的S3C2410處理器具有117個(gè)多功能通用I/O(GPIO)端口管腳,包括GPIO8個(gè)端口組,分別為GPA(23個(gè)輸出端口)、GPB(11個(gè)輸入/輸出端口)、GPC(16個(gè)輸入/輸出端口)、GPD(16個(gè)輸入/輸出端口)、GPE(16個(gè)輸入/輸出端口)、GPF(8個(gè)輸入/輸出端口)、GPH(11個(gè)輸入/輸出端口)。根據(jù)各種系統(tǒng)設(shè)計(jì)的需求,通過軟件方法可以將這些端口配置成具有相應(yīng)功能(例如:外部中斷或數(shù)據(jù)總線)的端口。7.3GPIO驅(qū)動(dòng)程序?qū)嵗?7
7.3.1GPIO工作原理LED和蜂鳴器原理圖7.3GPIO驅(qū)動(dòng)程序?qū)嵗?8
7.3.1GPIO工作原理相關(guān)寄存器7.3GPIO驅(qū)動(dòng)程序?qū)嵗?9Linux2.6新增的相關(guān)函數(shù)1、設(shè)備號(hào)相關(guān)函數(shù)在Linux2.6中,用dev_t類型來描述設(shè)備號(hào),dev_t是32位數(shù)值類型,其中高12位表示主設(shè)備號(hào),低20位表示次設(shè)備號(hào)。linux/kdev.h中定義了三個(gè)宏進(jìn)行設(shè)備號(hào)的處理。獲得主設(shè)備號(hào):MAJOR(dev_tdev)獲得次設(shè)備號(hào):MINOR(dev_tdev)構(gòu)造dev_t實(shí)例:MKDEV(intmajor,intminor)靜態(tài)分配設(shè)備號(hào):register_chrdev_region()動(dòng)態(tài)分配設(shè)備號(hào):alloc_chrdev_region()7.3GPIO驅(qū)動(dòng)程序?qū)嵗?0Linux2.6新增的相關(guān)函數(shù)2、字符設(shè)備注冊(cè)在Linux2.6中,用structcdev結(jié)構(gòu)來描述字符設(shè)備。在驅(qū)動(dòng)程序中必須將設(shè)備號(hào)及設(shè)備操作接口(file_operations結(jié)構(gòu)來描述)賦予cdev結(jié)構(gòu)變量:申請(qǐng)cdev結(jié)構(gòu): structcdev*cdev_alloc(void)與file_operations結(jié)構(gòu)關(guān)聯(lián):
voidcdev_init(structcdev*,structfile_operations*)與設(shè)備號(hào)關(guān)聯(lián)并向內(nèi)核注冊(cè):
voidcdev_add(structcdev*,dev_t,unsignedint)7.3GPIO驅(qū)動(dòng)程序?qū)嵗?1
7.3.1GPIO工作原理GPIO驅(qū)動(dòng)程序第1部分:宏定義code\ch8\GPIO\gpio_drv.h第2部分:驅(qū)動(dòng)模塊加載部分:code\ch8\GPIO\gpio_drv_init.c第3部分:打開設(shè)備(open操作)code\ch8\GPIO\gpio_drv_open.c第4部分:控制設(shè)備(ioctl操作)code\ch8\GPIO\gpio_drv_ioctl.c7.3GPIO驅(qū)動(dòng)程序?qū)嵗?2
7.3.1GPIO工作原理GPIO驅(qū)動(dòng)程序第5部分設(shè)備釋放操作code\ch8\GPIO\gpio_drv_release.c第6部分模塊注銷操作code\ch8\GPIO\gpio_drv_unregister.c測(cè)試程序:code\ch8\GPIO\gpio_test.c7.3GPIO驅(qū)動(dòng)程序?qū)嵗?3
8.4.1中斷編程實(shí)例注冊(cè)中斷intrequest_irq(unsignedintirq, void(*handler)(intirq,void*dev_id,structpt_regs*regs), unsignedlongirqflags,constchar*devname,oid*dev_id);釋放中斷voidfree_irq(unsignedintirq,void*dev_id);8.4按鍵驅(qū)動(dòng)程序?qū)嵗?4
8.4.2按鍵工作原理8.4按鍵驅(qū)動(dòng)程序?qū)嵗?5
8.4.2按鍵工作原理按鍵電路主要端口8.4按鍵驅(qū)動(dòng)程序?qū)嵗?6
8.4.3按鍵驅(qū)動(dòng)程序8.4按鍵驅(qū)動(dòng)程序?qū)嵗?7
8.4.4按鍵測(cè)試程序8.4按鍵驅(qū)動(dòng)程序?qū)嵗?8
驅(qū)動(dòng)程序的結(jié)構(gòu)驅(qū)動(dòng)程序主要數(shù)據(jù)結(jié)構(gòu)GPIO驅(qū)動(dòng)程序按鍵驅(qū)動(dòng)8.5小結(jié)89
根據(jù)書上的提示,將本章中所述的按鍵驅(qū)動(dòng)程序進(jìn)行進(jìn)一步的改進(jìn),并在目標(biāo)板上進(jìn)行測(cè)試。實(shí)現(xiàn)各種外設(shè)(包括ADC、SPI、I2C等)的字符設(shè)備驅(qū)動(dòng)程序。8.6
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 鐵嶺師范高等??茖W(xué)?!队?jì)算化學(xué)初步》2023-2024學(xué)年第一學(xué)期期末試卷
- 天水師范學(xué)院《應(yīng)用數(shù)理統(tǒng)計(jì)》2023-2024學(xué)年第一學(xué)期期末試卷
- 液壓?jiǎn)㈤]機(jī)課程設(shè)計(jì)
- 污水處理流程課程設(shè)計(jì)
- 消費(fèi)心理分析課程設(shè)計(jì)
- 數(shù)字出版行業(yè)相關(guān)投資計(jì)劃提議范本
- 核輻照改性產(chǎn)品行業(yè)相關(guān)投資計(jì)劃提議
- 不飽和聚酯樹脂相關(guān)行業(yè)投資規(guī)劃報(bào)告
- 農(nóng)用化學(xué)品相關(guān)行業(yè)投資方案
- 汽車營(yíng)銷專業(yè)課程設(shè)計(jì)
- 醫(yī)院物業(yè)服務(wù)機(jī)構(gòu)運(yùn)行管理機(jī)制
- PPE安全防護(hù)知識(shí)培訓(xùn)
- 中醫(yī)學(xué):常用穴位課件
- 山東省濟(jì)南市各縣區(qū)鄉(xiāng)鎮(zhèn)行政村村莊村名居民村民委員會(huì)明細(xì)
- 煤炭物流園區(qū)總體規(guī)劃(2016-2030)參考范本
- 數(shù)字電子技術(shù)ppt課件完整版
- 趣味語文知識(shí)競(jìng)賽題集錦
- 一級(jí)部門職責(zé)及組織架構(gòu)-總裁辦教學(xué)
- 尺橈骨骨折護(hù)理
- 精品新技術(shù)、新產(chǎn)品、新工藝、新材料的應(yīng)用
- 機(jī)械設(shè)計(jì)課程設(shè)計(jì)-壓床的設(shè)計(jì)與分析
評(píng)論
0/150
提交評(píng)論