嵌入式Linux驅(qū)動程序和QT.ppt
《嵌入式Linux驅(qū)動程序和QT.ppt》由會員分享,可在線閱讀,更多相關(guān)《嵌入式Linux驅(qū)動程序和QT.ppt(47頁珍藏版)》請在裝配圖網(wǎng)上搜索。
嵌入式Linux驅(qū)動程序開發(fā),遼寧工程技術(shù)大學電信學院,1嵌入式Linux的設備管理,,Linux將設備分成兩大類:一類是塊設備,類似磁盤以記錄塊或扇區(qū)為單位,成塊進行輸入/輸出的設備;另一類是字符設備,類似鍵盤以字符為單位,逐個進行輸入/輸出的設備。網(wǎng)路設備是介于塊設備和字符設備之間的一種特殊設備。塊設備接口僅支持面向塊的I/O操作,所有I/O操作都通過在內(nèi)核地址空間中的I/O緩沖區(qū)進行,它可以支持隨機存取的功能。文件系統(tǒng)通常都建立在塊設備上。字符設備接口支持面向字符的I/O操作,由于它們不經(jīng)過系統(tǒng)的快速緩存,所以它們負責管理自己的緩沖區(qū)結(jié)構(gòu)。字符設備接口只支持順序存取的功能,一般不能進行任意長度的I/O請求,而是限制I/O請求的長度必須是設備要求的基本塊長的倍數(shù)。處理器與設備間數(shù)據(jù)交換方式處理器與外設之間傳輸數(shù)據(jù)的控制方式通常有3種:查詢方式、中斷方式和直接內(nèi)存存?。―MA)方式。1.查詢方式設備驅(qū)動程序通過設備的I/O端口空間,以及存儲器空間完成數(shù)據(jù)的交換。例如,網(wǎng)卡一般將自己的內(nèi)部寄存器映射為設備的I/O端口,而顯示卡則利用大量的存儲器空間作為視頻信息的存儲空間。利用這些地址空間,驅(qū)動程序可以向外設發(fā)送指定的操作指令。通常來講,由于外設的操作耗時較長,因此,當處理器實際執(zhí)行了操作指令之后,驅(qū)動程序可采用查詢方式等待外設完成操作。驅(qū)動程序在提交命令之后,開始查詢設備的狀態(tài)寄存器,當狀態(tài)寄存器表明操作完成時,驅(qū)動程序可繼續(xù)后續(xù)處理。查詢方式的優(yōu)點是硬件開銷小,使用起來比較簡單。但在此方式下,CPU要不斷地查詢外設的狀態(tài),當外設未準備好時,就只能循環(huán)等待,不能執(zhí)行其他程序,這樣就浪費了CPU的大量時間,降低了處理器的利用率。,2.中斷方式查詢方式白白浪費了大量的處理器時間,而中斷方式才是多任務操作系統(tǒng)中最有效利用處理器的方式。當CPU進行主程序操作時,外設的數(shù)據(jù)已存入端口的數(shù)據(jù)輸入寄存器,或端口的數(shù)據(jù)輸出寄存器已空,此時由外設通過接口電路向CPU發(fā)出中斷請求信號。CPU在滿足一定條件下,暫停執(zhí)行當前正在執(zhí)行的主程序,轉(zhuǎn)入執(zhí)行相應能夠進行輸入/輸出操作的子程序,待輸入/輸出操作執(zhí)行完畢之后,CPU再返回并繼續(xù)執(zhí)行原來被中斷的主程序。這樣,CPU就避免了把大量時間耗費在等待、查詢外設狀態(tài)的操作上,使其工作效率得以大大提高。中斷方式的原理示意圖如下圖所示。能夠向CPU發(fā)出中斷請求的設備或事件稱為中斷源。中斷源向CPU發(fā)出中斷請求,若優(yōu)先級別最高,則CPU在滿足一定的條件時,可中斷當前程序的運行,保護好被中斷的主程序的斷點及現(xiàn)場信息,然后根據(jù)中斷源提供的信息,找到中斷服務子程序的入口地址,轉(zhuǎn)去執(zhí)行新的程序段,這就是中斷響應。CPU響應中斷是有條件的,如內(nèi)部允許中斷、中斷未被屏蔽、當前指令執(zhí)行完等。CPU響應中斷以后,就會中止當前的程序,轉(zhuǎn)去執(zhí)行一個中斷服務子程序,以完成為相應設備的服務。系統(tǒng)引入中斷機制后,CPU與外設處于“并行”工作狀態(tài),便于實現(xiàn)信息的實時處理和系統(tǒng)的故障處理。,3.直接訪問內(nèi)存(DMA)方式利用中斷,系統(tǒng)和設備之間可以通過設備驅(qū)動程序傳送數(shù)據(jù),但是,當傳送的數(shù)據(jù)量很大時,因為中斷處理上的延遲,利用中斷方式的效率會大大降低。而直接內(nèi)存訪問(DMA)可以解決這一問題。DMA可允許設備和系統(tǒng)內(nèi)存間在沒有處理器參與的情況下傳輸大量數(shù)據(jù)。設備驅(qū)動程序在利用DMA之前,需要選擇DMA通道并定義相關(guān)寄存器,以及數(shù)據(jù)的傳輸方向,即讀取或?qū)懭?,然后將設備設定為利用該DMA通道傳輸數(shù)據(jù)。設備完成設置之后,可以立即利用該DMA通道在設備和系統(tǒng)的內(nèi)存之間傳輸數(shù)據(jù),傳輸完畢后產(chǎn)生中斷以便通知驅(qū)動程序進行后續(xù)處理。在利用DMA進行數(shù)據(jù)傳輸?shù)耐瑫r,處理器仍然可以繼續(xù)執(zhí)行指令。,設備驅(qū)動程序的概念,設備驅(qū)動程序?qū)嶋H是處理和操作硬件控制器的軟件,從本質(zhì)上講,是內(nèi)核中具有最高特權(quán)級的、駐留內(nèi)存的、可共享的底層硬件處理例程。驅(qū)動程序是內(nèi)核的一部分,是操作系統(tǒng)內(nèi)核與硬件設備的直接接口,驅(qū)動程序屏蔽了硬件的細節(jié),完成以下功能:?對設備初始化和釋放;?對設備進行管理,包括實時參數(shù)設置,以及提供對設備的操作接口;?讀取應用程序傳送給設備文件的數(shù)據(jù)或者回送應用程序請求的數(shù)據(jù);?檢測和處理設備出現(xiàn)的錯誤。Linux操作系統(tǒng)將所有的設備全部看成文件,并通過文件的操作界面進行操作。對用戶程序而言,設備驅(qū)動程序隱藏了設備的具體細節(jié),對各種不同設備提供了一致的接口,一般來說,是把設備映射為一個特殊的設備文件,用戶程序可以像對其他文件一樣對此設備文件進行操作。這意味著:?由于每一個設備至少由文件系統(tǒng)的一個文件代表,因而都有一個“文件名”。?應用程序通??梢酝ㄟ^系統(tǒng)調(diào)用open()打開設備文件,建立起與目標設備的連接。?打開了代表著目標設備的文件,即建立起與設備的連接后,可以通過read()、write()、ioctl()等常規(guī)的文件操作對目標設備進行操作。設備文件的屬性由三部分信息組成:第一部分是文件的類型,第二部分是一個主設備號,第三部分是一個次設備號。其中類型和主設備號結(jié)合在一起惟一地確定了設備文件驅(qū)動程序及其界面,而次設備號則說明目標設備是同類設備中的第幾個。由于Linux中將設備當做文件處理,所以對設備進行操作的調(diào)用格式與對文件的操作類似,主要包括open()、read()、write()、ioctl()、close()等。應用程序發(fā)出系統(tǒng)調(diào)用命令后,會從用戶態(tài)轉(zhuǎn)到核心態(tài),通過內(nèi)核將open()這樣的系統(tǒng)調(diào)用轉(zhuǎn)換成對物理設備的操作。,驅(qū)動程序結(jié)構(gòu),1.自動配置和初始化子程序,用來檢測所需驅(qū)動的硬件設備是否工作正常、對正常工作的設備及其相關(guān)驅(qū)動程序所需要的軟件狀態(tài)進行初始化。2.服務于I/O請求的子程序,該子程序稱為驅(qū)動程序的上半部。這部分程序在執(zhí)行時,系統(tǒng)仍認為與進行調(diào)用的進程屬于同一個進程,只是由用戶態(tài)變成了核心態(tài),可以在其中調(diào)用sleep()等與進程運行環(huán)境有關(guān)的函數(shù)。3.中斷服務程序,又稱為驅(qū)動程序的下半部,由Linux系統(tǒng)來接收硬件中斷,再由系統(tǒng)調(diào)用中斷服務子程序。在系統(tǒng)內(nèi)部,I/O設備的存取通過一組固定的入口點來進行,入口點也可以理解為設備的句柄,就是對設備進行操作的基本函數(shù)。字符型設備驅(qū)動程序提供如下幾個入口點:?open入口點。打開設備準備I/O操作。對字符設備文件進行打開操作,都會調(diào)用設備的open入口點。open子程序必須對將要進行的I/O操作做好必要的準備工作,如清除緩沖區(qū)等。如果設備是獨占的,即同一時刻只能有一個程序訪問此設備,則open子程序必須設置一些標志以表示設備處于忙狀態(tài)。?close入口點。關(guān)閉一個設備。當最后一次使用設備完成后,調(diào)用close子程序。獨占設備必須標記設備方可再次使用。?read入口點。從設備上讀數(shù)據(jù)。對于有緩沖區(qū)的I/O操作,一般是從緩沖區(qū)里讀數(shù)據(jù)。對字符設備文件進行讀操作將調(diào)用read子程序。?write入口點。往設備上寫數(shù)據(jù)。對于有緩沖區(qū)的I/O操作,一般是把數(shù)據(jù)寫入緩沖區(qū)里。對字符設備文件進行寫操作將調(diào)用write子程序。?ioctl入口點。執(zhí)行讀、寫之外的操作。?select入口點。檢查設備,看數(shù)據(jù)是否可讀或設備是否可用于寫數(shù)據(jù)。select系統(tǒng)調(diào)用在檢查與設備文件相關(guān)的文件描述符時使用select入口點。,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(*readdir)(structfile*,void*,filldir_t);unsignedint(*poll)(structfile*,structpoll_table_struct*);int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);int(*mmap)(structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*flush)(structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structfile*,structdentry*,intdatasync);int(*fasync)(int,structfile*,int);int(*lock)(structfile*,int,structfile_lock*);ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);};?lseek,移動文件指針的位置,只能用于可以隨機存取的設備。?read,進行讀操作,buf為存放讀取結(jié)果的緩沖區(qū),count為所要讀取的數(shù)據(jù)長度。?write,進行寫操作,與read類似。?select,進行選擇操作。?ioctl,進行讀、寫以外的其他操作。?mmap,用于把設備的內(nèi)容映射到地址空間,一般只有塊設備驅(qū)動程序使用。?open,打開設備進行I/O操作。返回0表示成功,返回負數(shù)表示失敗。?release,即close操作。,structfile主要用于與文件系統(tǒng)相關(guān)的設備驅(qū)動程序,可提供關(guān)于被打開的文件的信息,定義如下:structfile{structlist_headf_list;structdentry*f_dentry;structvfsmount*f_vfsmnt;structfile_operations*f_op;atomic_tf_count;unsignedintf_flags;mode_tf_mode;loff_tf_pos;unsignedlongf_reada,f_ramax,f_raend,f_ralen,f_rawin;structfown_structf_owner;unsignedintf_uid,f_gid;intf_error;unsignedlongf_version;/*neededforttydriver,andmaybeothers*/void*private_data;/*preallocatedhelperkiobuftospeedupO_DIRECT*/structkiobuf*f_iobuf;longf_iobuf_lock;};在用戶自己的驅(qū)動程序中,首先要根據(jù)驅(qū)動程序的功能,完成file_operations結(jié)構(gòu)中函數(shù)的實現(xiàn)。不需要的函數(shù)接口可以直接在file_operations結(jié)構(gòu)中初始化為NULL。file_operations中的變量會在驅(qū)動程序初始化時,注冊到系統(tǒng)內(nèi)部。每個進程對設備的操作,都會根據(jù)主次設備號,轉(zhuǎn)換成對file_operations結(jié)構(gòu)的訪問。,2設備驅(qū)動程序的開發(fā)過程,由于嵌入式設備由于硬件種類非常豐富,在默認的內(nèi)核發(fā)布版中不一定包括所有驅(qū)動程序。所以進行嵌入式Linux系統(tǒng)的開發(fā),很大的工作量是為各種設備編寫驅(qū)動程序。除非系統(tǒng)不使用操作系統(tǒng),程序直接操縱硬件。嵌入式Linux系統(tǒng)驅(qū)動程序開發(fā)與普通Linux開發(fā)沒有區(qū)別??梢栽谟布a(chǎn)廠家或者Internet上尋找驅(qū)動程序,也可以根據(jù)相近的硬件驅(qū)動程序來改寫,這樣可以加快開發(fā)速度。實現(xiàn)一個嵌入式Linux設備驅(qū)動的大致流程如下。(1)查看原理圖,理解設備的工作原理。一般嵌入式處理器的生產(chǎn)商提供參考電路,也可以根據(jù)需要自行設計。(2)定義設備號。設備由一個主設備號和一個次設備號來標識。主設備號惟一標識了設備類型,即設備驅(qū)動程序類型,它是塊設備表或字符設備表中設備表項的索引。次設備號僅由設備驅(qū)動程序解釋,區(qū)分被一個設備驅(qū)動控制下的某個獨立的設備。(3)實現(xiàn)初始化函數(shù)。在驅(qū)動程序中實現(xiàn)驅(qū)動的注冊和卸載。(4)設計所要實現(xiàn)的文件操作,定義file_operations結(jié)構(gòu)。(5)實現(xiàn)所需的文件操作調(diào)用,如read、write等。(6)實現(xiàn)中斷服務,并用request_irq向內(nèi)核注冊,中斷并不是每個設備驅(qū)動所必需的。(7)編譯該驅(qū)動程序到內(nèi)核中,或者用insmod命令加載模塊。(8)測試該設備,編寫應用程序,對驅(qū)動程序進行測試。,模塊化驅(qū)動程序設計,在探討模塊之前,有必要先看一看內(nèi)核模塊與應用程序之間的區(qū)別。一個應用從頭到尾完成一個任務,而模塊則是為以后處理某些請求而注冊自己,完成這個任務后,它的“主”函數(shù)就立即中止了。然而,內(nèi)核源碼僅能連接編譯到內(nèi)核模塊中,不像應用那樣有眾多的支持庫,內(nèi)核能調(diào)用的僅是由內(nèi)核開放出來的那些函數(shù)。由于沒有庫連接到模塊中,所以源碼文件不應該模塊化任何常規(guī)頭文件。與內(nèi)核有關(guān)的所有內(nèi)容都定義在目錄/usr/include/linux和/usr/include/asm下的頭文件中。1.內(nèi)核空間和用戶空間當談到軟件時,我們通常稱執(zhí)行態(tài)為“內(nèi)核空間”和“用戶空間”,在Linux系統(tǒng)中,內(nèi)核在最高級執(zhí)行,也稱為“管理員態(tài)”,在這一級任何操作都可以執(zhí)行。而應用程序則執(zhí)行在最低級,所謂的“用戶態(tài)”,在這一級處理器禁止對硬件的直接訪問和對內(nèi)存的未授權(quán)訪問。模塊是在所謂的“內(nèi)核空間”中運行的,而應用程序則是在“用戶空間”中運行的。它們分別引用不同的內(nèi)存映射,也就是程序代碼使用不同的“地址空間”。Linux通過系統(tǒng)調(diào)用和硬件中斷完成從用戶空間到內(nèi)核空間的控制轉(zhuǎn)移。執(zhí)行系統(tǒng)調(diào)用的內(nèi)核代碼在進程的上下文中執(zhí)行,它執(zhí)行調(diào)用進程的操作而且可以訪問進程地址空間的數(shù)據(jù)。但處理中斷與此不同,處理中斷的代碼相對進程而言是異步的,而且與任何一個進程都無關(guān)。模塊的作用就是擴展內(nèi)核的功能,是運行在內(nèi)核空間的模塊化的代碼。模塊的某些函數(shù)作為系統(tǒng)調(diào)用執(zhí)行,而某些函數(shù)則負責處理中斷。,各個模塊被分別編譯并鏈接成一組目標文件,這些文件能被載入正在運行的內(nèi)核,或從正在運行的內(nèi)核中卸載。必要時內(nèi)核能請求內(nèi)核守護進程Kerneld對模塊進行加載或卸載。根據(jù)需要動態(tài)載入模塊可以保證內(nèi)核達到最小,并且具有很大的靈活性。內(nèi)核模塊一部分保存在Kernel中,另一部分在Modules包中。在項目一開始,很多地方對設備安裝、使用和改動都是通過編譯進內(nèi)核來實現(xiàn)的,對驅(qū)動程序稍微做點改動,就要重新燒寫一遍內(nèi)核,而且燒寫內(nèi)核經(jīng)常容易出錯,還占用資源。模塊采用的則是另一種途徑,內(nèi)核提供一個插槽,它就像一個插件,在需要時,插入內(nèi)核中使用,不需要時從內(nèi)核中拔出。這一切都由一個稱為Kerneld的守護進程自動處理。2.模塊化的優(yōu)缺點內(nèi)核模塊的動態(tài)加載具有以下優(yōu)點:將內(nèi)核映像的尺寸保持在最小,并具有最大的靈活性。這便于檢驗新的內(nèi)核代碼,而不需要重新編譯內(nèi)核并重新引導。但是,內(nèi)核模塊的引入也對系統(tǒng)性能和內(nèi)存的利用有負面影響。裝入的內(nèi)核模塊與其他內(nèi)核部分一樣,具有相同的訪問權(quán)限,由此可見,差的內(nèi)核模塊會導致系統(tǒng)崩潰。為了使內(nèi)核模塊能訪問所有內(nèi)核資源,內(nèi)核必須維護符號表,并在加載和卸載模塊時修改這些符號表。由于有些模塊要求利用其他模塊的功能,故內(nèi)核要維護模塊之間的依賴性。內(nèi)核必須能夠在卸載模塊時通知模塊,并且要釋放分配給模塊的內(nèi)存和中斷等資源。內(nèi)核版本和模塊版本的不兼容也可能導致系統(tǒng)崩潰,因此,嚴格的版本檢查是必需的。盡管內(nèi)核模塊的引入同時帶來不少問題,但是模塊機制確實是擴充內(nèi)核功能的一種行之有效的方法,也是在內(nèi)核級進行編程的有效途徑。,設備注冊和初始化,設備的驅(qū)動程序在加載的時候首先需要調(diào)用入口函數(shù)init_module(),該函數(shù)最重要的一個工作就是向內(nèi)核注冊該設備,對于字符設備調(diào)用register_chrdev()完成注冊。register_chrdev的定義為:intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);其中,major是為設備驅(qū)動程序向系統(tǒng)申請的主設備號,如果為0,則系統(tǒng)為此驅(qū)動程序動態(tài)分配一個主設備號。name是設備名,fops是對各個調(diào)用的入口點說明。此函數(shù)返回0時表示成功;返回-EINVAL,表示申請的主設備號非法,主要原因是主設備號大于系統(tǒng)所允許的最大設備號;返回-EBUSY,表示所申請的主設備號正在被其他設備程序使用。如果動態(tài)分配主設備號成功,此函數(shù)將返回所分配的主設備號。如果register_chrdev()操作成功,設備名就會出現(xiàn)在/proc/dvices文件中。Linux在/dev目錄中為每個設備建立一個文件,用ls–l命令列出函數(shù)返回值,若小于0,則表示注冊失??;返回0或者大于0的值表示注冊成功。注冊以后,Linux將設備名與主、次設備號聯(lián)系起來。當有對此設備名的訪問時,Linux通過請求訪問的設備名得到主、次設備號,然后把此訪問分發(fā)到對應的設備驅(qū)動,設備驅(qū)動再根據(jù)次設備號調(diào)用不同的函數(shù)。當設備驅(qū)動模塊從Linux內(nèi)核中卸載,對應的主設備號必須被釋放。字符設備在cleanup_module()函數(shù)中調(diào)用unregister_chrdev()來完成設備的注銷。unregister_chrdev()的定義為:intunregister_chrdev(unsignedintmajor,constchar*name);此函數(shù)的參數(shù)為主設備號major和設備名name。Linux內(nèi)核把name和major在內(nèi)核注冊的名稱對比,如果不相等,卸載失敗,并返回?EINVAL;如果major大于最大的設備號,也返回?EINVAL。,包括設備注冊在內(nèi),設備驅(qū)動的初始化函數(shù)主要完成的功能是有以下5項。(1)對驅(qū)動程序管理的硬件進行必要的初始化。對硬件寄存器進行設置。比如,設置中斷掩碼,設置串口的工作方式、并口的數(shù)據(jù)方向等。(2)初始化設備驅(qū)動相關(guān)的參數(shù)。一般說來,每個設備都要定義一個設備變量,用以保存設備相關(guān)的參數(shù)。在這一步驟里對設備變量中的項進行初始化。(3)在內(nèi)核注冊設備。調(diào)用register_chrdev()函數(shù)來注冊設備。(4)注冊中斷。如果設備需要IRQ支持,則要使用request_irq()函數(shù)注冊中斷。(5)其他初始化工作。初始化部分一般還負責給設備驅(qū)動程序申請包括內(nèi)存、時鐘、I/O端口等在內(nèi)的系統(tǒng)資源,這些資源也可以在open子程序或者其他地方申請。這些資源不用時,應該釋放,以利于資源的共享。若驅(qū)動程序是內(nèi)核的一部分,初始化函數(shù)則要按如下方式聲明:int__initchr_driver_init(void);其中__init是必不可少的,在系統(tǒng)啟動時會由內(nèi)核調(diào)用chr_driver_init,完成驅(qū)動程序的初始化。當驅(qū)動程序是以模塊的形式編寫時,則要按照如下方式聲明:intinit_module(void)當運行后面介紹的insmod命令插入模塊時,會調(diào)用init_module函數(shù)完成初始化工作。,中斷管理,設備驅(qū)動程序通過調(diào)用request_irq函數(shù)來申請中斷,通過free_irq來釋放中斷。它們在linux/sched.h中的定義如下:intrequest_irq(unsignedintirq,void(*handler)(intirq,voiddev_id,structpt_regs*regs),unsignedlongflags,constchar*device,void*dev_id);voidfree_irq(unsignedintirq,void*dev_id);通常從request_irq函數(shù)返回的值為0時,表示申請成功;負值表示出現(xiàn)錯誤。?irq表示所要申請的硬件中斷號。?handler為向系統(tǒng)登記的中斷處理子程序,中斷產(chǎn)生時由系統(tǒng)來調(diào)用,調(diào)用時所帶參數(shù)irq為中斷號,dev_id為申請時告訴系統(tǒng)的設備標識,regs為中斷發(fā)生時寄存器內(nèi)容。?device為設備名,將會出現(xiàn)在/proc/interrupts文件里。?flag是申請時的選項,它決定中斷處理程序的一些特性,其中最重要的是決定中斷處理程序是快速處理程序(flag里設置了SA_INTERRUPT)還是慢速處理程序(不設置SA_INTERRUPT)。下面的代碼將在SBC-2410X的Linux中注冊外部中斷2。eint_irq=IRQ_EINT2;set_external_irq(eint_irq,EXT_FALLING_EDGE,GPIO_PULLUP_DIS);ret_val=request_irq(eint_irq,eint2_handler,“S3C2410Xeint2”,0);if(ret_valGPIO_MODE_SHIFT)#defineGRAB_PULLUP(x)(((x)2.入口函數(shù)模塊的入口函數(shù)leds_init(),所做的工作是點亮I/O端口對應的LED,這些二極管可以作為狀態(tài)指示之用。register_chrdev()完成字符設備在系統(tǒng)中的注冊,并建立與文件系統(tǒng)的并聯(lián)。staticint__initleds_init(void){intret;inti;/*在內(nèi)核中注冊設備*/ret=register_chrdev(LED_MAJOR,DEVICE_NAME,},3.字符設備定義staticdevfs_handle_tdevfs_handle;4.ioctlioctl入口,執(zhí)行讀、寫之外的操作,通過參數(shù)cmd設定命令參數(shù)。staticintleds_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg){switch(cmd){case0:case1:if(arg>4){return-EINVAL;}write_gpio_bit(led_table[arg],!cmd);default:return-EINVAL;}}5.文件系統(tǒng)接口定義staticstructfile_operationsleds_fops={owner:THIS_MODULE,ioctl:leds_ioctl,};6.模塊化module_init(leds_init);module_exit(leds_exit);用insmod命令加載模塊時,調(diào)用module_init();用rmmod命令來卸載模塊時,調(diào)用module_exit()函數(shù)。,加載運行LED驅(qū)動程序,1.應用程序設計#include#include#include#includeintmain(intargc,char**argv){inton;intled_no;intfd;if(argc!=3||sscanf(argv[1],"%d",}該程序首先讀取命令行的參數(shù)輸入,其中參數(shù)argv[1]賦值給led_no,表示發(fā)光二極管的序號;argv[2]賦值給on。led_no的取值范圍是1~3,on取值為0或1,0表示熄滅LED,1表示點亮LED。參數(shù)輸入后通過fd=open("/dev/leds",0)打開設備文件,在保證參數(shù)輸入正確和設備文件正確打開后,通過語句ioctl(fd,on,led_no)實現(xiàn)系統(tǒng)調(diào)用ioctl,并通過輸入的參數(shù)控制LED。在程序的最后關(guān)閉設備句柄。,嵌入式圖形用戶界面開發(fā)——Qt/Embedded,,GUI概述,目前的桌面機操作系統(tǒng)大多有著美觀、操作方便、功能齊全的GUI(圖形用戶界面),例如KDE或者GNOME。GUI(圖形用戶界面)是指計算機與其使用者之間的對話接口,可以說,GUI是當今計算機技術(shù)的重大成就。它的存在為使用者提供了友好便利的界面,并大大地方便了非專業(yè)用戶的使用,使得人們從繁瑣的命令中解脫出來,可以通過窗口、菜單方便地進行操作。UNIX環(huán)境下的圖形視窗標準為XWindowSystem,Linux是類UNIX系統(tǒng),所以頂層運行的GUI系統(tǒng)是兼容X標準的XFree86系統(tǒng)。X標準大致可以劃分XServer、GraphicLibrary(底層繪圖函數(shù)庫)、Toolkits、WindowManager等幾大部分。其好處是具有可擴展性、可移植性等優(yōu)點,但對于嵌入式系統(tǒng)而言無疑太過龐大、累贅、低效。目前流行的嵌入式GUI與X思路不同,這些GUI一般不局限于X標準,更強調(diào)系統(tǒng)的空間和效率。,嵌入式GUI的特點,在嵌入式系統(tǒng)中,GUI的地位也越來越重要,但是不同于桌面機系統(tǒng),嵌入式GUI要求簡單、直觀、可靠、占用資源小且反應快速,以適應系統(tǒng)硬件資源有限的條件。另外,由于嵌入式系統(tǒng)硬件本身的特殊性,嵌入式GUI應具備高度可移植性與可裁減性,以適應不同的硬件條件和使用需求。?體積小;?運行時耗用系統(tǒng)資源??;?上層接口與硬件無關(guān),高度可移植;?高可靠性;?在某些應用場合應具備實時性。,Qt/Embedded的特點,MiniGUI(1),提起國內(nèi)的開源軟件,就肯定會提到MiniGUI,它由魏永明先生和眾多志愿者開發(fā),是一個基于Linux的實時嵌入式系統(tǒng)的輕量級圖形用戶界面支持系統(tǒng)。MiniGUI分為最底層的GAL層和IAL層,向上為基于標準POSIX接口中pthread庫的Mini-thread架構(gòu)和基于Server/Client的Mini-Lite架構(gòu)。其中前者受限于thread模式對于整個系統(tǒng)的可靠性——進程中某個thread的意外錯誤可能導致整個進程的崩潰,該架構(gòu)應用于系統(tǒng)功能較為單一的場合。Mini-Lite應用于多進程的應用場合,采用多進程運行方式設計的Server/Client架構(gòu)能夠較好地解決各個進程之間的窗口管理、Z序剪切等問題。MiniGUI還有一種從Mini-Lite衍生出的standalone運行模式。與Lite架構(gòu)不同的是,standalone模式一次只能以窗口最大化的方式顯示一個窗口。這在顯示屏尺寸較小的應用場合具有一定的應用意義。,MiniGUI(2),MiniGUI的IAL層技術(shù)SVGAlib、LibGGI、基于framebuffer的native圖形引擎以及啞圖形引擎等,對于Trolltech公司的QVFB在XWindow下也有較好的支持。IAL層則支持Linux標準控制臺下的GPM鼠標服務、觸摸屏、標準鍵盤等。MiniGUI下豐富的控件資源也是MiniGUI的特點之一。MiniGUI免費版本是1.3.3。在該版本的控件中已經(jīng)添加了窗口皮膚、工具條等桌面GUI中的高級控件支持。對比其他系統(tǒng),“Mini”是MiniGUI的特色,輕量、高性能和高效率的MiniGUI已經(jīng)應用在電視機頂盒、實時控制系統(tǒng)、掌上電腦等諸多場合。,Microwindows,MicrowindowsOpenSourceProject成立的宗旨在于針對體積小的裝置,建立一套先進的視窗環(huán)境,在Linux桌面上通過交叉編譯可以很容易地制作出Microwindows的程序。Microwindows能夠在沒有任何操作系統(tǒng)或其他圖形系統(tǒng)的支持下運行,它能對裸顯示設備進行直接操作。這樣,Microwindows就顯得十分小巧,便于移植到各種硬件和軟件系統(tǒng)上。然而Microwindows的免費版本進展一直很慢,幾乎處于停頓狀態(tài),而且至今為止,國內(nèi)沒有任何一家對Microwindows提供全面技術(shù)支持、服務和擔保的專業(yè)公司。,常用GUI比較,Qt/Embedded架構(gòu),Qt/Embedded以原始Qt為基礎,并做了許多出色的調(diào)整以適用于嵌入式環(huán)境。Qt/Embedded通過QtAPI與LinuxI/O設施直接交互,成為嵌入式Linux端口。同Qt/X11相比,Qt/Embedded很省內(nèi)存,因為它不需要一個X服務器或是Xlib庫,它在底層拋棄了Xlib,采用framebuffer作為底層圖形接口。同時,將外部輸入設備抽象為keyboard和mouse輸入事件。,,Qt/Embedded窗口系統(tǒng),一個Qt/Embedded窗口系統(tǒng)包含了一個或多個進程,其中的一個進程可作為服務器。該服務進程會分配客戶顯示區(qū)域,以及產(chǎn)生鼠標和鍵盤事件。該服務進程還能夠提供輸入方法和一個用戶接口給運行起來的客戶應用程序。該服務進程其實就是一個有某些額外權(quán)限的客戶進程??蛻襞c服務器之間的通信使用共享內(nèi)存的方法實現(xiàn),通信量應該保持最小。這就是Qt/Embedded庫內(nèi)部層次分明的處理過程。QProcess類提供了另外一種異步的進程間通信機制。它用于啟動一個外部的程序并且通過寫一個標準的輸入和讀取外部程序的標準輸出和錯誤碼來和它們通信。,Qt/Embedded字體(1),Qt/Embedded支持四種不同的字體格式:TrueType字體(TTF),PostscriptType1字體,位圖發(fā)布字體(BDF)和Qt的預呈現(xiàn)(Pre-rendered)字體(QPF)。Qt還可以通過增加QFontFactory的子類來支持其他字體,也可以支持以插件方式出現(xiàn)的反別名字體。每個TTF或者TYPE1類型的字體首次在圖形或者文本方式的環(huán)境下被使用時,這些字體的字形都會以指定的大小被預先呈現(xiàn)出來,呈現(xiàn)的結(jié)果會被緩沖。根據(jù)給定的字體尺寸(例如10或12點陣)預先呈現(xiàn)TTF或者TYPE1類型的字體文件并把結(jié)果以QPF的格式保存起來,這樣可以節(jié)省內(nèi)存和CPU的處理時間。,Qt/Embedded字體(2),QPF文件包含了一些必要的字體,這些字體可以通過makeqpf工具取得,或者通過運行程序時加上“-savefonts”選項獲取。如果應用程序中使用到的字體都是QPF格式,那么Qt/Embedded將被重新配置,并排除對TTF和TYPE1類型的字體的編譯,這樣就可以減少Q(mào)t/Embedded的庫的大小和存儲字體的空間。例如一個10點陣大小的包含所有ASCII字符的QPF字體文件的大小為1300Byte,這個文件可以直接從物理存儲格式映射成為內(nèi)存存儲格式。Qt/Embedded的字體通常包括Unicode字體的一部分子集,ASCII和Latin-1。,Qt/Embedded輸入設備及輸入法,Qt/Embedded3.0支持幾種鼠標協(xié)議:BusMouse、IntelliMouse,Microsoft和MouseMan.Qt/Embedded還支持NECVr41XX和iPAQ的觸摸屏。通過從QWSMouseHandler或者Qcalibra-tedMouseHandler派生子類,開發(fā)人員可以讓Qt/Embedded支持更多的客戶指示設備。對于非拉丁語系字符(例如阿拉伯,中文,希伯來和日語)的輸入法,需要把它寫成過濾器的方式,并改變鍵盤的輸入。輸入法的作者應該對全部的QtAPI的使用有完整的認識。在一個無鍵盤的設備上,輸入法成了惟一的輸入字符的手段。Qtopia提供了4種輸入方法:筆跡識別器、圖形化的標準鍵盤、Unicode鍵盤和基于字典方式提取的鍵盤。,Qt/Embedded屏幕加速,通過子類化QScreen和QgfxRaster可以實現(xiàn)硬件加速,從而為屏幕操作帶來好處。Troll-tech提供了Mach64和Voodoo3視頻卡的硬件加速的驅(qū)動例子,同時可以按照協(xié)議編寫其他的驅(qū)動程序。,Qt的支撐工具,Qt包含了許多支持嵌入式系統(tǒng)開發(fā)的工具,有兩個最實用的工具是qmake和Qtdesigner(圖形設計器)。?qmake是一個為編譯Qt/Embedded庫和應用而提供的Makefile生成器。它能夠根據(jù)一個工程文件(.pro)產(chǎn)生不同平臺下的Makefile文件。qmake支持跨平臺開發(fā)和影子生成(影子生成是指當工程的源代碼共享給網(wǎng)絡上的多臺機器時,每臺機器編譯鏈接這個工程的代碼將在不同的子路徑下完成,這樣就不會覆蓋別人的編譯鏈接生成的文件。qmake還易于在不同的配置之間切換。)?Qt圖形設計器可以使開發(fā)者可視化地設計對話框而不需編寫代碼。使用Qt圖形設計器的布局管理可以生成能平滑改變尺寸的對話框。qmake和Qt圖形設計器是完全集成在一起的。,Qt/Embedded信號和插槽機制(1),信號和插槽機制是Qt的核心機制,要精通Qt編程就必須對信號和插槽有所了解。信號和插槽是一種高級接口,應用于對象之間的通信,它是Qt的核心特性,也是Qt區(qū)別于其他工具包的重要地方。信號和插槽是Qt自行定義的一種通信機制,它獨立于標準的C/C++語言,必須借助一個稱為moc(MetaObjectCompiler)的Qt工具,該工具是一個C++預處理程序,它為高層次的事件處理自動生成所需要的附加代碼。信號與插槽機制是一種強有力的對象間通信機制,完全可以取代原始的回調(diào)和消息映射機制。在Qt中信號和插槽取代了上述這些凌亂的函數(shù)指針,使得用戶編寫這些通信程序更為簡潔明了。信號和插槽能攜帶任意數(shù)量和任意類型的參數(shù),他們是類型完全安全的,因此不會像回調(diào)函數(shù)那樣產(chǎn)生coredumps。,Qt/Embedded信號和插槽機制(2),所有從QObject或其子類(例如Qwidget)派生的類都能夠包含信號和插槽。當對象改變狀態(tài)時,信號就由該對象發(fā)射(emit)出去了,這就是對象所要做的全部工作,它不知道另一端是誰在接收這個信號。這就是真正的信息封裝,它確保對象被當作一個真正的軟件組件來使用。插槽用于接收信號,但它們是普通的對象成員函數(shù)。一個插槽并不知道是否有任何信號與自己相連接。而且,對象并不了解具體的通信機制。用戶可以將很多信號與單個插槽進行連接,也可以將單個信號與很多插槽進行連接,甚至將一個信號與另外一個信號相連接也是可能的,這時無論第一個信號什么時候發(fā)射,系統(tǒng)都將立刻發(fā)射第二個信號??傊?,信號與插槽構(gòu)造了一個強大的部件編程機制。,Qt/Embedded信號和插槽機制(3),,信號,當某個信號對其客戶或所有者內(nèi)部狀態(tài)發(fā)生改變時,信號就被一個對象發(fā)射。只有定義了這個信號的類及其派生類才能夠發(fā)射這個信號。當一個信號被發(fā)射時,與其相關(guān)聯(lián)的插槽將被立刻執(zhí)行,就像一個正常的函數(shù)調(diào)用一樣。信號-插槽機制完全獨立于任何GUI事件循環(huán)。只有當所有的槽返回以后發(fā)射函數(shù)(emit)才返回。如果存在多個槽與某個信號相關(guān)聯(lián),那么,當這個信號被發(fā)射時,這些槽將會一個接一個地執(zhí)行,但是它們執(zhí)行的順序?qū)请S機的、不確定的,用戶不能人為地指定哪個先執(zhí)行、哪個后執(zhí)行。,信號示例:signals:voidmySignal();voidmySignal(intx);voidmySignalParam(intx,inty);,插槽示例:publicslots:voidmySlot();voidmySlot(intx);voidmySignalParam(intx,inty);,插槽,插槽是普通的C++成員函數(shù),可以被正常調(diào)用,它們惟一的特殊性就是很多信號可以與其相關(guān)聯(lián)。插槽可以有參數(shù),但插槽的參數(shù)不能有缺省值。插槽函數(shù)也分為3種類型,即publicslots、privateslots和protectedslots。?publicslots:在這個區(qū)內(nèi)聲明的槽意味著任何對象都可將信號與之相連接。這對于組件編程非常有用,用戶可以創(chuàng)建彼此互不了解的對象,將它們的信號與槽進行連接以便信息能夠正確地傳遞。?protectedslots:在這個區(qū)內(nèi)聲明的槽意味著當前類及其子類可以將信號與之相連接。這適用于那些槽,它們是類實現(xiàn)的一部分,但是其界面接口卻面向外部。?privateslots:在這個區(qū)內(nèi)聲明的槽意味著只有類自己可以將信號與之相連接。這適用于聯(lián)系非常緊密的類。,信號與插槽關(guān)聯(lián),通過調(diào)用QObject對象的connect()函數(shù)可以將某個對象的信號與另外一個對象的插槽函數(shù)或信號相關(guān)聯(lián),當發(fā)射者發(fā)射信號時,接收者的槽函數(shù)或信號將被調(diào)用。這個函數(shù)的作用就是將發(fā)射者sender對象中的信號signal與接收者receiver中的member插槽函數(shù)聯(lián)系起來。當指定信號signal時必須使用Qt的宏SIGNAL(),當指定插槽函數(shù)時必須使用宏SLOT()。如果發(fā)射者與接收者屬于同一個對象的話,那么在connect()調(diào)用中接收者參數(shù)可以省略。,boolQObject::connect(constQObject*sender,constchar*signal,constQObject*receiver,constchar*member)[static],解除信號與插槽關(guān)聯(lián),當信號與槽沒有必要繼續(xù)保持關(guān)聯(lián)時,用戶可以使用disconnect()函數(shù)來斷開連接。有3種情況必須使用disconnect()函數(shù)。?斷開與某個對象相關(guān)聯(lián)的任何對象?斷開與某個特定信號的任何關(guān)聯(lián)?斷開兩個對象之間的關(guān)聯(lián),boolQObject::disconnect(constQObject*sender,constchar*signal,constObject*receiver,constchar*member)[static],常見通用窗口組合(1),常見通用窗口組合(2),- 配套講稿:
如PPT文件的首頁顯示word圖標,表示該PPT已包含配套word講稿。雙擊word圖標可打開word文檔。
- 特殊限制:
部分文檔作品中含有的國旗、國徽等圖片,僅作為作品整體效果示例展示,禁止商用。設計者僅對作品中獨創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- 嵌入式 Linux 驅(qū)動程序 QT
裝配圖網(wǎng)所有資源均是用戶自行上傳分享,僅供網(wǎng)友學習交流,未經(jīng)上傳用戶書面授權(quán),請勿作他用。
鏈接地址:http://m.appdesigncorp.com/p-11531299.html