通信原理大綜合課件高頻全_第1頁
通信原理大綜合課件高頻全_第2頁
通信原理大綜合課件高頻全_第3頁
通信原理大綜合課件高頻全_第4頁
通信原理大綜合課件高頻全_第5頁
已閱讀5頁,還剩39頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第8章設(shè)備驅(qū)動程序開發(fā)基礎(chǔ)一、Linux驅(qū)動程序概念

設(shè)備驅(qū)動程序是操作系統(tǒng)內(nèi)核與機(jī)器硬件之間的接口。驅(qū)動程序?yàn)閼?yīng)用程序屏蔽了硬件的細(xì)節(jié),在應(yīng)用程序看來,硬件設(shè)備只是一個設(shè)備文件,應(yīng)用程序可以像操作普通文件一樣對硬件設(shè)備進(jìn)行操作。8.1設(shè)備驅(qū)動概述每個設(shè)備都對應(yīng)一個設(shè)備文件,設(shè)備文件放在/dev目錄下。Linux對設(shè)備文件的訪問就是對硬件設(shè)備的操作。設(shè)備文件會調(diào)用驅(qū)動程序?qū)τ布M(jìn)行操作。設(shè)備文件在用戶層看來就和普通文件沒有區(qū)別,也擁有讀、寫和執(zhí)行權(quán)限,擁有和它對應(yīng)的索引節(jié)點(diǎn)等。文件系統(tǒng)層處理請求的權(quán)限,通過設(shè)備驅(qū)動層的接口將任務(wù)傳到驅(qū)動程序。設(shè)備驅(qū)動程序一般應(yīng)具有以下功能:對硬件設(shè)備的初始化和釋放;對設(shè)備進(jìn)行管理,提供對設(shè)備操作的統(tǒng)一接口;在設(shè)備和應(yīng)用程序之間傳送數(shù)據(jù);檢測或處理設(shè)備出現(xiàn)的錯誤。

嵌入式系統(tǒng)有許多設(shè)備用于與用戶交互。觸摸屏、小鍵盤、滾動輪、傳感器、RS232接口、LCD等還有閃存、USB、GSM等專用設(shè)備。二、應(yīng)用程序?qū)υO(shè)備的操作過程如下:通過系統(tǒng)調(diào)用open()打開具體的設(shè)備,建立以設(shè)備的連接。通過對文件的系統(tǒng)調(diào)用read()、write()、ioctl()等對設(shè)備進(jìn)行操作。但是用戶進(jìn)程一般位于內(nèi)核之外,工作在用戶態(tài),驅(qū)動程序作為系統(tǒng)內(nèi)核的一部分,工作在內(nèi)核態(tài),不能通過指針把用戶空間的數(shù)據(jù)地址傳遞給內(nèi)核,要經(jīng)過Linux提供的函數(shù)進(jìn)行轉(zhuǎn)換。

三、設(shè)備的分類字符設(shè)備以字節(jié)為單位逐個進(jìn)行I/O操作字符設(shè)備中的緩存是可有可無不支持隨機(jī)訪問如串口設(shè)備/dev/cua0和/dev/cua1塊設(shè)備塊設(shè)備的存取是通過buffer、cache來進(jìn)行可以進(jìn)行隨機(jī)訪問例如IDE硬盤設(shè)備/dev/hda網(wǎng)絡(luò)設(shè)備是通過BSDsocket接口訪問的設(shè)備如網(wǎng)卡等.對這三種設(shè)備文件編寫驅(qū)動程序時會有一定的區(qū)別。四、設(shè)備號設(shè)備號是一個數(shù)字,它是設(shè)備的標(biāo)志。主設(shè)備號表明某一類設(shè)備,一般對應(yīng)著確定的驅(qū)動程序;次設(shè)備號一般是用于區(qū)分標(biāo)明不同屬性,例如不同的使用方法,不同的位置,不同的操作等,它標(biāo)志著某個具體的物理設(shè)備。高字節(jié)為主設(shè)備號和低字節(jié)為次設(shè)備號。例如,在系統(tǒng)中的塊設(shè)備IDE硬盤的主設(shè)備號是3,而多個IDE硬盤及其各個分區(qū)分別賦予次設(shè)備號1、2、3……crw-rw-rw-1rootroot1,3Apr112002nullcrw-------1rootroot10,1Apr112002psauxcrw-------1rootroot4,1Oct2803:04tty1crw-rw-rw-1roottty4,64Apr112002ttys0crw-rw----1rootuucp4,65Apr112002ttyS1crw--w----1vcsatty7,1Apr112002vcs1crw--w----1vcsatty7,129Apr112002vcsa1crw-rw-rw-1rootroot1,5Apr112002zero五、通過mknod命令來創(chuàng)建設(shè)備文件mknod設(shè)備名設(shè)備類型主設(shè)備好此設(shè)備號如mknodttys0 c641串口設(shè)備,設(shè)備類型為字符型,主設(shè)備號64,此設(shè)備號1。六、設(shè)備驅(qū)動程序開發(fā)步驟熟悉硬件設(shè)備,重點(diǎn)是設(shè)備中的各種寄存器。定義設(shè)備號,應(yīng)用程序利用設(shè)備號訪問驅(qū)動程序。熟悉設(shè)備初始化函數(shù),在驅(qū)動程序中實(shí)現(xiàn)設(shè)備的注冊和中斷注冊等。設(shè)計所需要的文件操作調(diào)用,定義file_operations結(jié)構(gòu)。實(shí)現(xiàn)所需的文件操作調(diào)用,如read、write、llseek等函數(shù)。實(shí)現(xiàn)中斷服務(wù)程序。測試程序。發(fā)布驅(qū)動程序。8.2設(shè)備驅(qū)動程序框架一、虛擬文件系統(tǒng)與驅(qū)動程序間的接口structfile_operations結(jié)構(gòu)在/include/linux/fs.h中定義。

這個結(jié)構(gòu)的每一個成員的名字都對應(yīng)著一個系統(tǒng)調(diào)用。用戶進(jìn)程利用系統(tǒng)調(diào)用在對設(shè)備文件進(jìn)行諸如read/write操作時,系統(tǒng)調(diào)用通過設(shè)備文件的主設(shè)備號找到相應(yīng)的設(shè)備驅(qū)動程序,然后讀取這個數(shù)據(jù)結(jié)構(gòu)相應(yīng)的函數(shù)指針,接著把控制權(quán)交給該函數(shù)。這是linux的設(shè)備驅(qū)動程序工作的基本原理。既然是這樣,則編寫設(shè)備驅(qū)動程序的主要工作就是編寫子函數(shù),并填充file_operations的各個域。我們在向內(nèi)核注冊設(shè)備的函數(shù)中,一個參數(shù)就是指向strcutfile_operations的指針。structfile_operations{

int(*seek)(structinode*,structfile*,off_t,int);

int(*read)(structinode*,structfile*,char,int);

int(*write)(structinode*,structfile*,off_t,int);

int(*readdir)(structinode*,structfile*,structdirent*,int);

int(*select)(structinode*,structfile*,int,select_table*);

int(*ioctl)(structinode*,structfile*,unsinedint,unsignedlong);

int(*mmap)(structinode*,structfile*,structvm_area_struct*);

int(*open)(structinode*,structfile*);

int(*release)(structinode*,structfile*);

int(*fsync)(structinode*,structfile*);

int(*fasync)(structinode*,structfile*,int);

int(*check_media_change)(structinode*,structfile*);

int(*revalidate)(dev_tdev);

}

1、打開設(shè)備函數(shù)open函數(shù)完成以下工作檢查設(shè)備特定的錯誤(例如設(shè)備沒準(zhǔn)備好,或者類似的硬件錯誤)如果它第一次打開,初始化設(shè)備,包括設(shè)備注冊、對設(shè)備模式、設(shè)備參數(shù)進(jìn)行設(shè)置,即配置各種寄存器。為設(shè)備實(shí)現(xiàn)申請中斷、設(shè)置DMA方式、申請對設(shè)備的控制權(quán)。識別次設(shè)備號,填充file->private_data結(jié)構(gòu)。使用計數(shù)增1。另外,當(dāng)有多個物理設(shè)備時,就需要識別次設(shè)備號來對各個不同的設(shè)備進(jìn)行不同的操作,在有些驅(qū)動程序中并不需要用到。int(*open)(structinode*,structfile*);

這里,實(shí)現(xiàn)計數(shù)器操作的是用在<linux/module.h>中定義的3個宏如下?!OD_INC_USE_COUNT:計數(shù)器加一?!OD_DEC_USE_COUNT:計數(shù)器減一?!OD_IN_USE:計數(shù)器非零時返回真。2、關(guān)閉設(shè)備函數(shù)函數(shù)原型int(*release)(structinode*,structfile*);

關(guān)閉設(shè)備函數(shù)完成以下任務(wù):釋放打開設(shè)備時分配的資源如中斷等;釋放open在filp->private_data中分配的內(nèi)存;計數(shù)器減1;在最后的關(guān)閉設(shè)備3、讀設(shè)備數(shù)據(jù)函數(shù)#include<linux/fs.h>ssize_t(*read)(structfile*filp,char*buff,size_tcount,loff_t*f_pos)filp:文件指針buff:指向用戶緩沖區(qū)count:傳入的數(shù)據(jù)長度*f_pos:指向file->f_pos,給出當(dāng)前讀寫的位置。返回值為實(shí)際所讀字節(jié)數(shù),返回-1表示出錯。返回0表示文件結(jié)束4、寫設(shè)備數(shù)據(jù)函數(shù)#include<linux/fs.h>ssize_t(*write)(structfile*filp,constchar*buff,size_tcount,loff_t*offp)write()函數(shù)把count個字節(jié)從buf指向的緩沖區(qū)寫入與handle相連的文件中,返回值為實(shí)際寫入的字節(jié)數(shù)。雖然這個過程看起來很簡單,但是內(nèi)核空間地址和應(yīng)用空間地址是有很大區(qū)別的,其中之一就是用戶空間的內(nèi)存是可以被換出的,因此可能會出現(xiàn)頁面失效等情況。所以就不能使用諸如memcpy之類的函數(shù)來完成這樣的操作。在這里就要使用copy_to_user或copy_from_user函數(shù),它們就是用來實(shí)現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)交換的。copy_to_user和copy_from_user的格式如表#include<asm/uaccess.h>Unsignedlongcopy_to_user(void*to,constvoid*from,unsignedlongcount)Unsignedlongcopy_from_user(void*to,constvoid*from,unsignedlongcount)To:數(shù)據(jù)目的緩沖區(qū)函數(shù)傳入值From:數(shù)據(jù)源緩沖區(qū)count:數(shù)據(jù)長度函數(shù)返回值成功:寫入的數(shù)據(jù)長度失?。?EFAULT5、設(shè)備控制函數(shù)ioctl入口點(diǎn)執(zhí)行讀、寫之外的操作。函數(shù)原型為:intioctl(intfd,intcmd,…)參數(shù)cmd不經(jīng)修改的傳遞給驅(qū)動程序,可選的arg參數(shù)無論是指針還是整數(shù)值,都以unsignedlong的形式傳遞給驅(qū)動程序。在實(shí)現(xiàn)ioctl的時候,大多數(shù)都包含switch語句,用來根據(jù)不同的cmd值來執(zhí)行不同的硬件操作。二、設(shè)備驅(qū)動程序的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)1、file結(jié)構(gòu)Structfile提供關(guān)于被打開的文件信息,主要用于與文件系統(tǒng)對應(yīng)的設(shè)備驅(qū)動程序使用。系統(tǒng)中每個打開的文件有一個關(guān)聯(lián)的structfile在內(nèi)核空間).它由內(nèi)核在open時創(chuàng)建,并傳遞給在文件上操作的任何函數(shù),直到最后的關(guān)閉.在文件的所有實(shí)例都關(guān)閉后,內(nèi)核釋放這個數(shù)據(jù)結(jié)構(gòu).mode_tf_mode;文件模式確定文件是可讀的或者是可寫的(或者都是),通過位FMODE_READ和FMODE_WRITE.你可能想在你的open或者ioctl函數(shù)中檢查這個成員的讀寫許可,但是你不需要檢查讀寫許可,因?yàn)閮?nèi)核在調(diào)用你的方法之前檢查.loff_tf_pos;當(dāng)前讀寫位置.loff_t在所有平臺都是64位,如果驅(qū)動設(shè)備需要知道文件當(dāng)前的位置,可以讀取這個字段得值。unsignedintf_flags;f_flags表示文件標(biāo)志,如O_RDONLY、O_WDONLY、等,為了支持非阻塞型操作,驅(qū)動程序需要檢查這個標(biāo)志。structfile_operations*f_op;f_op表示文件的對應(yīng)操作,指向驅(qū)動中的file_operations,內(nèi)核在執(zhí)行open時為這個指針賦值,可以調(diào)用這個指針指向file_operations中的相應(yīng)成員。void*private_data;系統(tǒng)調(diào)用的open設(shè)置這個指針為空,驅(qū)動可以江這個字段用于任何目的或者忽略它;驅(qū)動程序可以使用這個成員來指向分配的數(shù)據(jù),但是必須記住在內(nèi)核銷毀文件結(jié)構(gòu)之前,在release方法中釋放那個內(nèi)存.2、inode結(jié)構(gòu)

文件系統(tǒng)處理的文件所需信息在inode數(shù)據(jù)結(jié)構(gòu)中。但這個結(jié)構(gòu)只有3個成員對于編寫驅(qū)動代碼有用:dev_ti_rdev;這個字段包含了實(shí)際設(shè)備的編號,如果需要可用一下函數(shù)獲得。unsignedintiminor(structinode*inode)//獲得從設(shè)備號unsignedintimajor(structinode*inode)//獲得主設(shè)備號2、stuctcdev*i_nodestuctcdev是表示字符設(shè)備的內(nèi)部結(jié)構(gòu),當(dāng)inode指向一個字符文件時,該字段包含指向stuctcdev結(jié)構(gòu)的指針。3、stuctblok_devce*i_nodestuctblok_devce是表示塊設(shè)備的內(nèi)部結(jié)構(gòu),當(dāng)inode指向一個字符文件時,該字段包含指向stuctblok_devce結(jié)構(gòu)的指針。3、設(shè)備數(shù)據(jù)結(jié)構(gòu)分為字符設(shè)備、塊設(shè)備、網(wǎng)絡(luò)設(shè)備三種設(shè)備數(shù)據(jù)結(jié)構(gòu)一字符設(shè)備數(shù)據(jù)結(jié)構(gòu)為例:Sturctcdev結(jié)構(gòu)在/include/linux/cdev.h中定義在設(shè)備初始化時,設(shè)備驅(qū)動程序會構(gòu)造一個sturctcdev結(jié)構(gòu)作為字符設(shè)備向內(nèi)核注冊。8.3設(shè)備驅(qū)動程序結(jié)構(gòu)Linux的設(shè)備驅(qū)動程序可以分成三個主要部分:自動配置和初始化子程序。(檢測硬件設(shè)備是否正常;初始化,僅初始化時調(diào)用一次。)服務(wù)于I/O請求的子程序。(調(diào)用這部分程序是由于系統(tǒng)調(diào)用的結(jié)果)中斷服務(wù)子程序。(由Linux系統(tǒng)接收中斷,再由系統(tǒng)調(diào)用中斷服務(wù)子程序。)Linux對中斷的處理

從應(yīng)用編程角度來看,編寫一個中斷處理程序只要根據(jù)具體應(yīng)用實(shí)現(xiàn)中斷服務(wù)子程序,并利用一系列LinuxAPI函數(shù)向內(nèi)核注冊該服務(wù)子程序就行了,具體的調(diào)度處理在linux內(nèi)部實(shí)現(xiàn)。1、注冊中斷處理程序

向內(nèi)核注冊中斷處理程序主要實(shí)現(xiàn)兩個功能,一是注冊中斷號,二是注冊中斷處理函數(shù)。在linux中對應(yīng)的中斷處理注冊函數(shù)為:intrequest_irq(unsignedintirq,void(*handler)(int,void*,structpt_regs*),unsignedlongflags,constchar*device,void*dev_id);返回值:request_irq返回0表示成功,返回-INVAL表示irq>15或handler==NULL,返回-EBUSY,表示中斷已經(jīng)被占用且不能共享。函數(shù)注冊中斷服務(wù)函數(shù),其中:irq:中斷號handler:中斷響應(yīng)處理函數(shù)irq_flags:中斷管理選項(xiàng)掩碼devname:設(shè)備名稱dev_id:中斷共享時使用

在一個設(shè)備驅(qū)動程序向內(nèi)核注冊了中斷服務(wù)程序后,中斷到來時的調(diào)度就由內(nèi)核的中斷處理子系統(tǒng)來完成了。中斷處理子系統(tǒng)的一個主要任務(wù)是根據(jù)中斷號找到正確的中斷處理代碼段。

設(shè)備驅(qū)動的初始化

設(shè)備驅(qū)動的初始化函數(shù)主要完成的功能是:a對驅(qū)動程序管理的硬件進(jìn)行必要的初始化。如對硬件寄存器進(jìn)行設(shè)置,設(shè)置串口的工作方式等。b初始化設(shè)備驅(qū)動相關(guān)的參數(shù)。一般情況下,定義一個設(shè)備變量,用以保存設(shè)備的相關(guān)參數(shù)。這里對設(shè)備變量的各項(xiàng)進(jìn)行初始化。c在內(nèi)核中注冊設(shè)備。Intregister_chrdev(unsignedint,constchar*,structfile_operation*)3個參數(shù)為主設(shè)備號、設(shè)備名稱、file_operation結(jié)構(gòu)地址。d如果設(shè)備需要IRQ支持,則要注冊中斷。初始化程序聲明。當(dāng)驅(qū)動程序是內(nèi)核的一部分,則要按如下方式聲明,注意不能缺少__initint__initchr_driver_init(void);則在系統(tǒng)啟動的時候會由內(nèi)核調(diào)用chr_driver_init,完成的驅(qū)動程序的初始化。當(dāng)驅(qū)動程序是以模塊的形式編寫分,則要按如下方式聲明,當(dāng)運(yùn)行insmod命令插入模塊時會調(diào)用init_module函數(shù)完成初始化工作。

intinit_module(void)e其他初始化工作8.4設(shè)備驅(qū)動程序開發(fā)過程定義主設(shè)備號、次設(shè)備號,也可以動態(tài)獲取。實(shí)現(xiàn)驅(qū)動初始化和清除函數(shù)。如果驅(qū)動程序采用模塊方式,則要實(shí)現(xiàn)模塊初始化和清除函數(shù)。設(shè)計要實(shí)現(xiàn)的文件操作,定義file_operations結(jié)構(gòu)。實(shí)現(xiàn)所需的文件操作調(diào)用,如read、write等。實(shí)現(xiàn)中斷服務(wù)函數(shù),并用request_irq向內(nèi)核注冊。將驅(qū)動編譯到內(nèi)核或編譯成模塊,用ismod命令加載。生成設(shè)備節(jié)點(diǎn)文件。一、設(shè)備驅(qū)動程序開發(fā)流程二、模塊化驅(qū)動程序設(shè)計

在linux系統(tǒng)中提供了一種全新的模塊化機(jī)制,可以在不重新編譯內(nèi)核的情況下,將編譯好的模塊動態(tài)的插入運(yùn)行中的內(nèi)核,或者將內(nèi)核中已經(jīng)存在的一個模塊移走??梢钥闯鲞@種機(jī)制為驅(qū)動程序開發(fā)調(diào)試提供了很大的方便。

對應(yīng)的模塊化編程,源程序中必須至少提供

init_module()和cleanup_module()兩個函數(shù)。下面就開始寫子程序。

#include<linux/types.h>基本的類型定義

#include<linux/fs.h>文件系統(tǒng)使用相關(guān)的頭文件

#include<linux/mm.h>

#include<linux/errno.h>

#include<asm/segment.h>

unsignedinttest_major=0;

staticintread_test(structinode*inode,structfile*file,char*buf,intcount)

{

intleft;用戶空間和內(nèi)核空間

if(verify_area(VERIFY_WRITE,buf,count)==-EFAULT)

return-EFAULT;

for(left=count;left>0;left--)

{

__put_user(1,buf,1);

buf++;

}

returncount;

}這個函數(shù)是為read調(diào)用準(zhǔn)備的。當(dāng)調(diào)用read時,read_test()被調(diào)用,它把用戶的緩沖區(qū)全部寫1。buf是read調(diào)用的一個參數(shù)。它是用戶進(jìn)程空間的一個地址。但是在read_test被調(diào)用時,系統(tǒng)進(jìn)入核心態(tài)。所以不能使用buf這個地址,必須用__put_user(),這是kernel提供的一個函數(shù),用于向用戶傳送數(shù)據(jù)。另外還有很多類似功能的函數(shù)。請參考,在向用戶空間拷貝數(shù)據(jù)之前,必須驗(yàn)證buf是否可用。這就用到函數(shù)verify_area。為了驗(yàn)證BUF是否可以用。staticintwrite_test(structinode*inode,structfile*file,constchar*buf,intcount)

{

returncount;

}

staticintopen_test(structinode*inode,structfile*file)

{

MOD_INC_USE_COUNT;模塊計數(shù)加以,表示當(dāng)前內(nèi)核有個設(shè)備加載內(nèi)核當(dāng)中去

return0;

}

staticvoidrelease_test(structinode*inode,structfile*file)

{

MOD_DEC_USE_COUNT;

}這幾個函數(shù)都是空操作。實(shí)際調(diào)用發(fā)生時什么也不做,他們僅僅為下面的結(jié)構(gòu)提供函數(shù)指針。

structfile_operationstest_fops={?

read_test,

write_test,

open_test,

release_test,

};

設(shè)備驅(qū)動程序的主體可以說是寫好了。現(xiàn)在要把驅(qū)動程序嵌入內(nèi)核。驅(qū)動程序可以按照兩種方式編譯。一種是編譯進(jìn)kernel,另一種是編譯成模塊(modules),如果編譯進(jìn)內(nèi)核的話,會增加內(nèi)核的大小,還要改動內(nèi)核的源文件,而且不能動態(tài)的卸載,不利于調(diào)試,所以推薦使用模塊方式。intinit_module(void)

{

intresult;

result=register_chrdev(0,"test",&test_fops);對設(shè)備操作的整個接口

if(result<0){

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論