VxWorks驅動開發筆記.docx_第1頁
VxWorks驅動開發筆記.docx_第2頁
VxWorks驅動開發筆記.docx_第3頁
VxWorks驅動開發筆記.docx_第4頁
VxWorks驅動開發筆記.docx_第5頁
已閱讀5頁,還剩290頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

VxWorks驅動開發筆記普通應用軟件的開發,客戶都會提出很明確的需求如功能、用戶界面、外部接口以及開發周期經費等等要求,這些要求一般都相對直觀且容易理解。但是對于驅動程序的開發開說,開發周期以及經費這些需求往往都比較容易理解,可是對于功能、用戶界面以及外部接口等需求就很難描述了,因為這需要對底層操作系統的理解,否則就無法提出適宜的需求來,而對底層操作系統的理解才是驅動程序開發之所以困難的主要原因。1.1驅動程序的結構驅動程序有兩大基本特征:一是它實現了對硬件設備的訪問(最根本目的),二是它實現了一系列與硬件設備無關的的訪問接口。通過這些接口,上層軟件在控制此類硬件設備時無需對硬件進行詳細的了解就可以進行訪問,此外,當硬件設備更換時,只需要修改設備驅動的硬件相關的部分,而上層軟件無需做任何更改。這兩個基本特征也正好決定了驅動程序的主體結構。如圖1.1所示,圖中的陰影部分為設備驅動程序。圖1.1驅動程序的結構1.2驅動程序的工作流程不同設備在操作系統中完成的工作是不同的,但是就是工作流程來說,大致可以分為兩個階段。第一個階段是初始化階段,在初始化階段,驅動程序主要完成硬件以及設備驅動相關數據結構的初始化。第二個階段是硬件的訪問階段,根據設備工作模式的不同,可以分為中斷模式和輪詢模式,無論何種模式都可以通過與硬件設備無關的通用接口進行硬件設備的訪問。2.1串口驅動原理串口因為調試簡單在許多數據量不大的場合依然較為流行,可以借助串口對目標機中操作系統的運行情況進行監控等等。下圖為Tornado開發軟件通過串口對目標機上運行的VxWorks操作系統進行監控的結構原理圖。圖2.1Tornado通過串口對vxWorks操作系統進行監控設備的驅動程序分為與硬件相關部分和硬件無關部分,而硬件相關部分則負責具體的硬件實現,硬件無關部分實現了一系列通用的數據接口,其中硬件無關部分實現是create、remove、open、close、read、write、ioctl等7個通用的函數接口。使用這7個基本的函數,不但能夠訪問串口,而且還能夠對網絡、磁盤文件等多類設備進行訪問。這7個函數的原型在文件ioLib.c中進行定義。分別為:intcreat(constchar*name,intflag):該函數創建了一個文件描述符fd。其中name為一個抽象文件的文件路徑,這個抽象可以指硬盤上保存的一個文件,也可以是一個以字符串表示的一個設備,當文件描述符創建完畢后自動以參數flag打開該文件。STATUSremove(constchar*name):移除文件,name表明文件路徑。intopen(constchar*name,intflags,intmode);打開文件,準備訪問。name為文件路徑,flags為打開方式如只讀、只寫、讀寫以及不存在可創建等,mode為打開模式只有在NFS文件系統下才有效。打開成功后返回文件描述符。STATUSclose(intfd);關閉文件。fd為文件描述符。intread(intfd,char*buffer,size_tmaxbytes);從文件描述符fd指定的文件中讀取最多maxbytes個字節,保存在buffer指定的位置??赡軙捎谖募L度的原因,實際讀取的字節數小于maxbytes,函數返回實際讀出的字節數。intwrite(intfd,char*buffer,size_tnbytes);向文件描述符fd指定的文件中寫入nbytes個字節的數據,原數據保存在buffer只能的內存中??赡軙捎赽uffer空間等原因,實際寫入的字節數小于nbytes,函數返回實際寫入的字節數。intioctl(intfd,intfunction,intarg);控制函數,主要用于設置或讀取設備的工作方式等特性。上述這7個通用接口,也就是串口驅動的一個最根本的需求,即通過這幾個函數就可以實現對串口控制芯片i8250的操作。而函數庫iosLib中則是上述各個接口的較為底層的實現。它首先根據訪問設備類型的不同(普通磁盤文件和硬件設備)而將其分為兩類,并用不同的數據結構描述,這里主要對結構DRV_ENTRY進行分析。如圖2.3。圖2.3iosLib庫提供的數據結構結構數組drvTable的每個元素drvTablei對應一類設備,因此其下表i將是不同類型設備之間區分的一個重要的參考。由于0通常表示無效,因此drvTable0為空,不代表任何設備。圖2.4給出了ioLib提供的通用函數和結構DRV_ENTRY的基本關系。圖中的箭頭表示調用關系,有調用者指向被調用者。圖2.4ioLib庫與iosLib庫的內部關系由于數組drvTable的每個元素drvTablei對應一類設備,如果要使用某一類設備中的一個,如系統中兩個串口的一個,就必須指明是哪個串口。在函數庫ioLib中的7個通用函數中都有一個重要的參數name,表明文件的路徑或者設備的名稱,該名稱具有唯一性,也就是一個name指向唯一一個文件或者唯一一個設備。下面要引入的數據結構是設備描述符,如圖2.5所示,它在函數庫iosLib中定義。圖2.5設備描述符基本的設備描述符的數據結構為DEV_HDR,它描述了一些最為基本的信息,數組decTable的下標devnum和設備名稱name,該設備序號即是ioLib庫中使用的文件描述符fd。綜合起來設備描述符DRV_HDR、結構DRV_ENTRY以及7個通用函數庫的關系可以用圖2.6來描述。圖2.6DRV_HDR、DRV_ENTRY及通用接口之間的關系上述通用接口可以滿足網卡、串口等外圍設備的需要,對于具體的外部設備,則需要對圖2.6所說的通用接口進行擴展,如圖2.7所示,這個擴展主要采用了兩種手段,一是繼承,即通過對結構DEV_HDR進行繼承得到如串口、終端以及網卡等特殊類型的設備;而是多態,也就是對一個通用的接口,根據具體設備的不同而采取不同的函數。C不是面向對象語言,沒有明確的類、繼承和多態的概念,但是可以靈活地使用C達到同樣的目的。圖2.7通用接口通過多態和繼承得到擴展圖2.8則更為詳細地描述了VxWorks操作系統對多個設備的管理。對每類設備的操作函數,系統創建了一個DRV_ENTRY結構數組來描述,每個DRV_ENTRY結構變量對應一類設備的操作函數,對某類設備的具體操作方式的設置則是通過設定DRV_ENTRY結構變量中個函數指針來實現的;對于同一類的設備,系統為其從DEV_HDR派生了一個數據結構,而每個結構變量則是對應該類設備中的每一個具體的設備,不同的設備通過雙向鏈表鏈接在一起。圖2.8VxWorks對系統中多個設備的管理結構2.3串口驅動程序函數庫分析為了進一步加深對IO設備管理數據結構的理解,本節將分別對函數庫ioLib、iosLib進行分析。2.3.1函數庫ioLibioLib庫為上層提供了7個基本的函數接口:creat(),remove(),open(),close(),read(),write()以及ioctl()。上層用戶只需要對這7個函數進行操作就能夠完成對硬件的訪問。下面一次分析ioLib庫中各個函數庫的功能。1.intcreat(constchar*name,intflag)該函數提供了一個與設備無關的通用接口,用于創建一個文件(可以是普通的磁盤文件也可以是抽象的設備文件),該文件的路徑為name,創建完畢后自動打開,打開的參數為flag。該函數的正常返回值為文件描述符,否則將會返回ERROR。對照圖2.8,該函數根據設備的名稱,從鏈表中找到該設備對應的設備號drmNum(該數值即為函數返回的文件描述符),然后以此為下標就可以找到該類設備的de_create函數指針,從而找到該設備的create函數。2.intopen(constchar*name,intflags,intmode)該函數打開一個文件以方便進行讀、寫或者更新,打開后返回該文件的文件描述符。open()函數的參數為文件名以及訪問方式:lO_RDONLY(0)以只讀方式打開lO_WRONLY(1)以只寫方式打開lO_RDWR(2)以讀寫方式打開lO_CREAT(0x0200)如果文件不存在,就創建一個文件并打開。3.LOCALintioCreateOrOpen(constchar*name,intflags,intmode,BOOLcreate)這個函數其實是函數create()和open()函數的實現主體。create()和open()函數只是根據參數create簡單調用函數ioCreateOrOpen()而已,真正的實現在函數ioCreateOrOpen()中。4.STATUSunlink(char*name)該函數主要是和posix兼容,它的功能與remove完全相同。5.STATUSremove(constchar*name)調用函數iosDelete來刪除文件。如果有符號鏈接,則需要沿著符號鏈接直接找到文件并刪除。6.STATUSclose(intfd)調用函數ioClose函數關閉文件。7.intrename(constchar*oldname,constchar*newname)修改文件名。并不是所有的設備都支持重命名操作,比如通常的dosFS和rt11FS都是支持重命名操作的,而netDrv和nfsDrv則不支持,因此在使用這個函數前需要明確設備是否支持重命名操作。重命名操作主要通過調用函數ioctl(fd,FIORENAME,(int)newname)完成。注意:調用函數ioctl(fd,FIORENAME,(int)newname)重命名前需要先打開文件open()。8.intread(intfd,char*buffer,size_tmaxbytes)調用函數iosRead實現讀操作,maxbytes為讀取的最大字節數,讀取之后存放在buffer指定的地址空間,不過可能由于文件中字節數的限制等因素,實際讀取的字節數可能會小于maxbytes,因此需要在最終的返回值中返回實際讀取的字節數。9.intwrite(intfd,char*buffer,size_tnbytes)調用函數iosWrite向指定的文件中寫入數據,nbytes為期望寫入的字節數,但是實際上可能會由于文件本身的限制導致實際寫入的字節數小于nbytes,因此需要在返回值中記錄實際寫入的字節數。10.intioctl(intfd,intfunction,intarg)直接調用函數iosIoctl實現對文件的控制操作。11.intlseek(intfd,longoffset,intwhence)設定一個文件的讀寫指針,下次讀寫操作將從設定的位置開始。參數whence有三個數值:lSEEK_SET(0)設定到相對于文件起始位置偏移offset位置。lSEEK_CUR(1)設定到當前位置偏移offset的位置。lSEEK_END(2)相對于文件結束位置偏移offset的位置。注意:如果指定的地址是無效的地址(超出了文件的范圍),那么將返回錯誤指示。12.intreadv(intfd,structiovec*iov,intiovcnt)從設備fd中讀取數據,保存在iov起始地址為iov的數組中。iovcnt為結構iovec數組iov的元素的個數。iov是一個數組指針,它指向一個iovec結構數組,iovec結構中的元素iov_base指定了數據保存起始位置地址,而iovcnt則指定了iov數組的元素個數,因此總的讀出的字節數為各個數組元素中保存數據的字節數之和。如圖2.9所示。圖2.9iovec結構示意圖13.intwritev(intfd,registerstructiovec*iov,intiovcnt)該函數調用iosWrite函數將幾段分散的數據寫入到fd設備中。14.STATUSioFullFileNameGet(char* pathName,DEV_HDR* ppDevHdr,char* fullFileName)通常來說,一個完整的文件的路徑包括兩部分,該文件所在的設備路徑,以及該文件在該設備上的相對路徑,這兩部分組合得到了一個完整的路徑。這個函數的作用就是根據參數pathName制定的路徑名,這個路徑名可以是相對(相對麼默認的路徑ioDefPath)路徑名或者絕對路徑名。函數ioFullFileNameGet的作用個就是根據提供的路徑名找到該文件坐在的設備及其相對于該設備的路徑。其中設備名結構變量指針的指針保存在DEV_HDR*ppDevHdr參數中返回,相對于設備的文件名則存放在參數char* fullFileName中保存。舉例來說當前默認路徑為“/dev/sd1/x/”,相對路徑名為“y.txt”,該函數將會找到設備“/dev/sd1/”對應的DEV_HDR*ppDevHdr指針返回,并將fullFileName設置為x/y.txt返回。15.STATUSioDefPathSet(char*name)設定默認路徑,并將其復制到全局變量ioDefPath中,注意name必須是一個絕對路徑,也就是說name指定的路徑必須包含一個有效的設備(即從iosDevList中能夠搜索到的設備)。16.voidioDefPathGet(char*pathname)將ioDefPath復制到pathname中返回。17.STATUSchdir(char*pathname)這個函數等價于函數ioDefPathSet(),可以認為是ioDefPathSet()函數的一個別名。18.char*getcwd(char*buffer,intsize)ioDefPathGet()函數的別名。只是如果參數size指定的空間太小的話將返回ERROR。19.char*getwd(char*pathname)ioDefPathGet()函數的別名。20.STATUSioDefPathCat(char*name)修改默認的路徑。如果name是一個包含設備路徑的一個絕對路徑名,那么它就成為了一個新的默認路徑。否則name將會被連接到當前默認路徑從而更新了新的默認路徑。例如:如果默認路徑為sda/x,name=sda/y,則默認路徑修改為sda/y;如果name=/y,則默認路徑修改為sda/x/y.21.voidioDefDevGet(char*devName)獲取默認路徑所屬的設備的名稱。22.voidioDefDirGet(char*dirName)這個函數在新的版本中將會刪除。它的主要作用就是獲取默認路徑相對于所屬設備的相對路徑。如設備名為sda,默認路徑為sda/x,則ioDefDevGet()函數獲取了sda設備,而函數ioDefDirGet()則獲取了相對路徑。23.voidioGlobalStdSet(intstdFd,intnewFd)文件ioLib中定義了一個數組LOCALintioStdFd3,該數組表明標準文件描述符。這三個標準的文件描述符主要是:標準輸入0、標準輸出1、錯誤輸出2。這個函數的作用,就是設置這個數組中某個元素的文件描述符。stdFd:指的是ioStdFd數組中元素的下標,02有效。newFd:數組中元素的數值。24.intioGlobalStdGet(intstdFd)獲取數組ioStdFd中某個元素的數值,即文件描述符的數值。25.voidioTaskStdSet(inttaskId,intstdFd,intnewFd)對VxWorks系統來說,并不是每個任務的標準輸入、標準輸出、錯誤輸出都是相同的,多數任務的標準輸入是鍵盤,標準輸出是顯示器等,但是對某些串口監控的任務來說,可以把它的標準輸入設置為串口等等。每個任務描述符中都有一個數組taskStd,表明這個任務的標準輸入、標準輸出以及錯誤輸出,這個函數的功能,就是設置一個任務的標準輸入、標準輸出、錯誤輸出。26.intioTaskStdGet(inttaskId,intstdFd)獲取一個任務的標準輸入、標準輸出、錯誤輸出27.BOOLisatty(intfd/*filedescriptortocheck*/)判斷一個文件描述符是否是一個tty。最初的計算機沒有鍵盤和顯示器,輸入輸出都比較麻煩,后來有Teletype公司生產了一種字符型終端設備,因此有很多計算機操作系統都把字符型終端設備叫做tty設備。關于文件路徑的進一步詳細操作可以參考函數庫pathLib。2.3.2函數庫iosLib函數庫iosLib是庫ioLib的底層實現,它負責將各個硬件設備及其驅動組織起來,從而使得用戶只需要調用ioLib庫就可以通過類似于文件IO的訪問方式來訪問各個硬件設備。在對iosLib庫函數進行分析的過程中我們將主要分析系統是如何將這些設備以及驅動組織起來,以及如何為ioLib庫提供接口的。在函數庫iosLib中定義了一個通用的接口結構DRV_ENTRY,它為ioLib庫提供了一個通用過的接口,使得ioLib無需了解具體的設備類型就可以對硬件設備進行訪問;另一方面它又通過繼承的方法,將不同類型的設備保存在鏈表中進行統一管理(參見圖2.8)。下面對設備的管理函數進行詳細分析。1.staticSTATUSnullWrite(intdummy,char*pBuf,intnBytes)空函數。2.STATUSiosInit(intmax_drivers,intmax_files,char*nullDevName)iosLib函數庫初始化,該函數的主要作用是動態創建了一個FD_ENTRY結構數組和一個DRV_ENTRY結構數組,并進行了初始化。3.intiosDrvInstall(FUNCPTRpCreate,FUNCPTRpDelete,FUNCPTRpOpen,FUNCPTRpClose,FUNCPTRpRead,FUNCPTRpWrite,FUNCPTRpIoctl)從DRV_ENTRY結構數組中找到一個空閑的DRV_ENTRY結構變量,將參數指定函數指針填充到該。注意由于最開始的一個元素即drvTable0中填充的是一個空設備,因此查找空閑的元素是從下表1開始查找的。如圖2.10。該函數返回下標i。圖2.10函數iosDrvInstall的操作正是這個步驟才使得一類設備的特殊訪問方法與通用的接口連接起來。4.STATUSiosDrvRemove(intdrvnum,BOOLforceClose)函數iosDrvInstall的逆過程,將DRV_ENTRY結構數組中的下表為drvnum的元素清空。如果forceClose參數為TRUE則需要強制關閉該設備已經打開的文件。如果forceClose為FALSE但是該設備有打開的文件,則返回錯誤。注意:一個設備可能對應多個打開的文件。5.STATUSiosDevAdd(DEV_HDR*pDevHdr,char*name,intdrvnum)增加一個設備,該設備名稱(路徑)名為name,該設備的7個訪問函數在對應的DRV_ENTRY結構數組中的下表為drvnum。如圖2.11所示。注意,在添加設備之前需要調用函數iosDevMatch檢查已經添加的設備中是否包含相同的路徑名(文件名)如果有則說明該設備已經加入了。返回錯誤。此外就是該函數只修改了iosDvList鏈,并不觸及DRV_ENTRY結構數組的操作。如果已經加入的設備中有“ab”這個名字,那么還可以增加名字為“abc”、“a”這樣的設備,但是名字為“ab”的再不能添加了。圖2.11在設備管理庫中加入新設備6.voidiosDevDelete(DEV_HDR*pDevHdr/*pointertodevicesstructure*/)從iosDvList鏈中刪除一個設備。注意添加的時候DEV_HDR結構中的name是動態分配的,因此這里需要釋放相應的空間。這里可以參考iosDevAdd函數,在iosDevAdd函數中參數pDevHdr也不是動態分配的。7.DEV_HDR*iosDevFind(char*name,/*nameofthedevice*/char*pNameTail/*wheretoputptrtotailofname*/)根據名字查找一個設備的DEV_HDR結構。查找遵照一下原則:l調用函數iosDevMatch在devTable數組中查找與name最為匹配的,也就是說查找的設備名字與name的前面n(n為設備名稱的字符個數)個字符完全相同;l如果查到了匹配的,則返回值*pNameTail返回的則是name字符串中不包含設備名稱的字符串;l如果沒有找到匹配的設備,則返回默認的設備(如果有的話),此時*pNameTail返回的則是原name字符串。8.LOCALDEV_HDR*iosDevMatch(char*name)該函數的作用是查找已經添加的設備名中與參數name匹配度最大設備名。所謂匹配度最大就是說設備名正好是name字符串的前n(n為設備名稱字符串長度)個字符完全相同中的所有設備中n最大的那一個設備。例如已經添加的設備中有“ab”、“abc”“bcde”,那么與name=“abcde”匹配最大的為“abc”。9.DEV_HDR*iosNextDevGet(DEV_HDR*pDev)從node鏈中查找下一個node的DEV_HDR結構變量,參照前面的鏈表結構圖。10.intiosCreate(DEV_HDR*pDevHdr,char*fileName,intmode)該函數根據DEV_HDR結構指針pDevHdr中的drvNum數值作為下標,找到drvTable數組中的DEV_ENTRY結構變量中的de_create函數指針,調用de_create函數。11.intiosDelete(DEV_HDR*pDevHdr,char*fileName)類似于函數iosCreate()。12.intiosOpen(DEV_HDR*pDevHdr,char*fileName,intflags,intmode)類似于函數iosCreate()。13.STATUSiosClose(intfd)類似于函數iosCreate()。14.intiosRead(intfd,char*buffer,intmaxbytes)類似于函數iosCreate()。15.intiosWrite(intfd,char*buffer,intnbytes)類似于函數iosCreate()。16.intiosIoctl(intfd,intfunction,intarg)基本的控制函數,主要完成幾個功能。function=FIOGETNAME,將文件描述符的名字復制到arg中;其他情況則執行drvTablepFdEntry-pDevHdr-drvNum.de_ioctl,這個類似于函數iosCreate()。17.LOCALvoidiosLock(void)這個函數和iosUnlock共同管理一個二進制信號量,主要負責對fdTable、iosDevList的訪問保護。主要進行互斥操作。2.3.3函數庫ttyDrv.c前面主要分析了vxWorks系統IO設備管理的通用數據結構及其操作,這個通用接口既適用于串口類設備、又適用于網絡設備等等。對于串口這類設備來說,其驅動又有其獨有的要求,如收發緩存的管理,波特率的設置等等。同樣,作為串口驅動的部分,也可以分為與硬件相關部分和與硬件無關部分。VxWorks操作系統的串口驅動與硬件無關部分主要有兩個函數庫來實現,一是ttyDrv函數庫,主要用于7個通用函數中的5個函數的具體實現,另一個是tyLib函數庫,主要用于處理收發緩沖區的處理。另一方面,從結構TYCO_DEV來看,tyLib的主要數據結構TY_DEV變量包含在結構TYCO_DEV,因此其層次關系可以用圖2.12所示。圖2.12函數庫ttyDrv與tyLib的層次關系函數庫ttyDrv主要通過結構SIO_CHAN訪問底層函數,在結構TYCO_DEV中有一個SIO_CHAN結構變量指針,該變量指針指向底層的操作函數。如圖13所示。圖2.13ttyDrv庫與底層庫的函數接口首先分析ttyDrv函數庫,這個函數庫比較簡單,直接分析各個函數。1.STATUSttyDrv(void)函數ttyDrv主要調用了函數iosDrvInstall完成了7個函數的安裝,對串口來說,系統并不要完全安裝這7個函數,比如delete函數,如果操作系統不要求delete串口驅動,那么這個函數也就不需要了。實際上ttyDrv函數主要安裝了基本操作函數,如圖2.14。圖2.14函數ttyDrv主要安裝的函數這些函數中有ttyOpen、ttyClose、ttyIoctl是由函數庫ttyDrv.C提供的,其他函數如tyRead、tyWrite則是由函數庫tyLib提供的。2.STATUSttyDevCreate(char*name,SIO_CHAN* pSioChan,intrdBufSize,intwrtBufSize)這個函數為一個tty設備創建了一個TYCO_DEV數據結構并進行初始化(包括硬件的初始化)。其中pSioChain是底層串行通道描述符(SIO_CHAN結構變量)的地址。rdBufSize和wrtBufSize為讀寫緩沖區的大小。ttyDevCreate函數在執行過程中調用了函數tyDevInit對tyLib庫進行了初始化。注意調用函數tyDevInit的最后一個參數ttyStartup,這個函數對底層操作函數(pSioChan)-pDrvFuncs-txStartup進行了封裝,也就是說只有函數ttyDrv直接與底層硬件操作函數向關聯,而tyLib庫則完全被保護在了硬件無關層(參見圖2.12)。ttyDevCreate()函數操作的數據結構如圖2.15所示。同時它指定了串口的處理模式為中斷模式(另一種為輪詢模式)。圖2.15ttyDevCreate()函數操作的數據結構注意這個函數和ioLib庫中的create函數是完全不同的概念,該函數的調用應該在create之前。3.LOCALintttyOpen(TYCO_DEV* pTyCoDev,char* name,int flags,int mode)打開一個ttyDrv串行設備。所謂打開設備就是使其處于準備收發數據的狀態,對i8250串口控制芯片來說就是設定計算機準備接收(DTR)和請求發送數據(RTS)的狀態。注意:每調用一次函數ttyOpen,該pTyCoDev-tyDev.numOpen就會自動加1,表明該設備打開的次數。4.LOCALintttyClose(TYCO_DEV* pTyCoDev)關閉一個ttyDrv設備。所謂關閉設備就是就是關閉其收發數據就緒的狀態。注意:每調用一次函數ttyClose,pTyCoDev-tyDev.numOpen就會自動減1,表明該設備打開的次數。5.LOCALintttyIoctl(TYCO_DEV* pTyCoDev,int request,void* arg)對硬件設備的控制操作。request是一個比較廣義的操作,包含的種類繁多,而且對同樣的操作,對不同的函數庫來說,參數也可能會有所不同,如波特率設置,在ttyDrv庫request為FIOBAUDRATE,這個參數在iosLib.h中定義,而在sioLib庫中該參數為SIO_BAUD_SET,因此需要進行參數的轉換;另一方面sioIoCtl函數和tyIoCtl函數處理的職責是不同的,因此需要首先嘗試調用sioIoCtl函數,如果無此操作則嘗試tyIoCtl函數。6.LOCALvoidttyStartup(TYCO_DEV*pTyCoDev)發送數據函數。直接調用底層的發送函數。在函數ttyDrv中調用iosDrvInstall函數安裝了兩個函數tyRead和tyWrite,這兩個函數并在函數庫ttyDev中,而是在tyLib庫中。主要完成收發緩沖區的處理,下面要進行tyLib庫的分析。2.3.4函數庫tyLibtyLib函數在ttyDrv庫與底層硬件操作之間建立了一個收發緩沖區,當上層函數需要接收數據時并不是直接讀取硬件的接收寄存器,而是調用函數tyRead讀取tyLib的緩沖區,同樣在發送數據時也是通過調用tyWrite函數將數據發送給tyLib的緩沖區中。tyLib負責對緩沖區進行管理,包括在輪詢和中斷模式下自動從串口控制器中讀寫數據,當接收緩沖區占用了一定的空間之后,調用上層回調函數將接收緩沖區的數據取走等等,另外在不同的模式下,還要完成對接收緩沖區的數據進行重新組織等任務。當前tyLib庫的接收緩沖區管理主要實現了line模式和raw模式的緩沖區管理。所謂line模式就想當我們的中斷輸入,只有在按下回車鍵以后,計算機才進行相應的動作,否則只是在屏幕上進行顯示,如果在動作前按下了退格、CTRL-X、CTRL-C等等按鍵,那么還要重新對新輸入的line進行修改等等。這在利用串口連接終端的情況下是十分有用的。在raw模式下,計算機每次指示讀取相應的字符,并不對其中的含義進行解釋,讀取完畢后就根據緩沖區的情況決定是否調用回調函數將接收緩沖區的數據取走。1.STATUStyDevInit下面分析tyLib庫中的各個函數。(FASTTY_DEV_IDpTyDev,intrdBufSize,intwrtBufSize,FUNCPTRtxStartup)用指定的參數初始化tty設備描述符。tty設備描述符是一個數據結構TY_DEV的變量而不是硬件設備,該結構變量在函數調用前已經創建,因此這里只需要進行初始化就行了,而不用重新創建。注意區分互斥變量和二進制信號量的區別?;コ庾兞康哪康氖菫榱吮WC在一定的時間段內一個任務對某個資源獨占,即只有當前任務可以訪問某一資源,在這期間其他任務無法獲取到該資源,互斥變量的獲取和釋放都是由同一任務完成,它主要強調資源的獨占性;而二進制信號量則是某一任務為了獲取某一資源,但是該資源卻是由其他任務來提供的,它的主要目的是為了確保不同任務的同步,即只有在資源有效的情況下,才能有任務實用該資源,二進制信號量的獲取和提供往往是由不同的任務來完成的,通常是任務A提供了某一資源,任務B等待到任務A提供了資源后才能有效獲取。二者的區別主要在于二進制信號量的資源是消耗性的,它分別由不同的任務生產和消耗;而互斥變量保護的資源則是獨占性,不存在生產和消耗之說,而僅僅是確保只有一個任務可以訪問該資源。這里的二進制信號量rdSyncSem,這個信號量確保底層串口驅動tyIRd在輸入環狀緩沖區保存了一定的數據之后,tyRead上層函數才能有效獲取該信號量并開始讀取這些數據。二進制信號量wrtSyncSem則是確保在輸出環狀緩沖區中有足夠的空間資源,當有了足夠的空間資源則函數tyITx釋放掉一定的空間時候信號量有效,而tyWrite只有在獲取了該信號量后才可以向輸出環狀緩沖區中寫入數據。互斥變量mutexSem的作用是為了確保對TY_DEV結構變量的訪問保護。2.STATUStyDevRemove(TY_DEV_IDpTyDev)tyDevInit函數的逆過程。注意這里flushingRdBuf和flushingWrtBuf要在rdBuf和wrtBuf內存被釋放之前置為True是為了確保中斷處理程序tyITx和tyIRd不會在釋放了之后訪問這段內存。3.LOCALvoidtyFlush(FASTTY_DEV_IDpTyDev)這個函數比較簡單,直接調用函數tyFlushRd和函數tyFlushWrt對各自的buffer進行flush。4.LOCALvoidtyFlushRd(FASTTY_DEV_IDpTyDev)該函數的作用是對輸入環狀緩沖區進行flush。注意flush前需要將flushingRdBuf置位是為了確保不被中斷處理程序tyIRd搞亂。注意flush結束之后要發送一個XON信號提示對方串口設備接收準備好,并將變量flushingRdBuf復位為False。5.LOCALvoidtyFlushWrt(FASTTY_DEV_IDpTyDev)該函數的作用是對輸出環狀緩沖區進行flush。注意flush前需要將flushingWrtBuf置位是為了確保不被中斷處理程序tyITx搞亂。注意flush結束之后free空間很大,因此要給出一個wrtSyncSem信號量,并將變量flushingWrtBuf復位為False。最后還要利用_func_selWakeupAll通知各個函數輸出環狀緩沖區已經空出來了。6.voidtyAbortFuncSet(FUNCPTRfunc)設置abort函數,當收到abort字符時執行func函數。默認為null。7.voidtyAbortSet(charch)設置abort字符,默認該字符為CTRL-C。8.voidtyBackspaceSet(charch)設定backspace字符,默認字符為CTRL-H。9.voidtyDeleteLineSet(charch)設置行刪除命令字符,默認為CTRL-U。10.voidtyEOFSet(charch)設置end-of-file字符,默認該字符為CTRL-D。11.voidtyMonitorTrapSet(charch)設置TRAP-TO-MONITOR字符,默認該字符為CTRL-X。當OPT_MON_TRAP選項有效時,輸入TRAP-TO-MONITOR字符,將會終止通常的多任務系統并進入TRAP-TO-MONITOR程序。12.STATUStyIoctl(FASTTY_DEV_IDpTyDev,intrequest,intarg)處理tty設備的ioctl請求。現有的bug:在line模式下,以參數FIONREAD調用返回的是輸入緩沖區中的字符數,如果在buffer中有5個空行,每個空行字符占用一字節,此外還有一個行字符數占用一字節,那么其返回值為10。FIONREAD:返回接收環形緩沖區中的有效字符數(不包含正在輸入的未完成的行)。FIONWRITE:返回發送環形緩沖區中的有效字符數。FIOFLUSH:flush輸入發送環形緩沖區。FIOWFLUSH:flush接收環形緩沖區。FIORFLUSH:flush發送環形緩沖區。FIOGETOPTIONS:讀取設備選項。FIOSETOPTIONS:設置設備選項。FIOCANCEL:取消設備的讀寫。FIOISATTY:返回TRUE。FIOPROTOHOOK:設定函數pTyDev-protoHook。FIOPROTOARG:設定函數pTyDev-protoHook的參數pTyDev-protoArg。FIORBUFSET:重新設定發送環形緩沖區。FIOWBUFSET:重新設定發送環形緩沖區。FIOSELECT:增加selWakeupList。FIOUNSELECT:刪掉selWakeupList中指定的tyWrite(FASTTY_DEV_IDpTyDev,char*buffer,FASTintnbytes)向TY_DEV的發送環形緩沖區中寫入數據。并啟動tyTxStartup開始向device發送。注意在寫入前take二進制信號量wrtSyncSem確保有足夠的空間,寫完后檢查是否有空間,如果有空間則需要give二進制信號量wrtSyncSem,方便其他任務寫入。14.inttyRead(FASTTY_DEV_IDpTyDev,char*buffer,intmaxbytes)從接收環形緩沖區中讀取數據。pTyDev-lnBytesLeft變量記錄了上次讀取數據時,讀取行中剩余的字節數,如果為0說明已經完整地讀取了一整行。否則說明上次讀取的行中還有一定的字節沒有讀取,這時候可以直接讀取。讀取完畢之后要檢查接收環形緩沖區中空閑的空間否足夠,如果足夠的話且OPT_TANDEM選項有效且當前為XOFF,這時候需要向device發送一個XON信號表明接收準備好。15.STATUStyITx(FASTTY_DEV_IDpTyDev,char*pChar)中斷級處理程序,取出下一個要發送的字符(注意并不是所有要發送的字符都是要先從發送環形緩沖區中取出來的,如XON/XOFF字符),準備將該字符發送到串口控制芯片(并未發送)。根據設定的規則,取出該字符需要根據如下準則:l首先檢查接收端口是否需要發送XON/XOFF信號(需要發送的話rdState.pending為True),如果需要發送,則下一個發送的字符為XON/XOFF;l如果wrtState.xoff為true,說明發送處于關閉狀態,此時是不能夠發送數據的,因此直接退出并置pTyDev-wrtState.busy為FALSE;否則如果wrtState.flushingWrtBuf為true,則說明正在清空

溫馨提示

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

評論

0/150

提交評論