驅動程序最重要的部分就是驅動程序源代碼文件,源文件描述了設備如何和VxBus、VxWorks OS交互。但是,VxWorks 設備驅動程序還需要另外一些文件,這些附加文件能夠幫助你將自己編寫的驅動集成到VxWorks編譯環境中去,這也是發布驅動程序最重要的一步。本節主要討論如何在源碼樹中找到相關的驅動程序文件和其他附加文件。最後還說明驅動程序的各個部分是如何安裝在VxWorks OS中的。
3.1 文件位置
在開發驅動程序之前,了解驅動程序文件在VxWorks源碼樹中的位置是非常重要的,驅動程序文件主要分佈在源碼樹中的3個不同位置。
- installDir/vxworks-6.x/target/3rdparty 第三方提供的基於VxBus驅動模型的驅動,它們一般都做為插件安裝到現有的VxWorks開發環境中
- installDir/vxworks-6.x/target/src/hwif 風河官方提供的基於VxBus驅動模型的驅動程序,它們一般都作為標準產品的一部分,或者作為補丁來升級。
- installDir/vxworks-6.x/target/src/drv 風河官方提供的基於傳統模型的驅動程序,和VxBus不兼容
3.3.1 風河官方的驅動程序
根據驅動程序的類型,installDir/vxworks-6.x/target/src/hwif目錄下的驅動被組織成不同的子目錄,例如,定時器的驅動程序在目錄installDir/vxworks-6.x/target/src/hwif/timer
3.3.2 第三方的驅動程序
第三方驅動程序的組織方式允許驅動程序開發廠商和開發者創建第三方驅動程序,不需要擔心不同廠商的文件之間的命名空間衝突。每一個想提供VxWorks驅動程序的廠商必須在3rdparty目錄創建自己的子目錄,比如說,Acme公司計劃為vxworks開發第三方設備驅動程序,那麼就必須在3rdparty目錄創建自己的目錄installDir/vxworks-6.x/target/3rdparty/acme,在這個目錄下,不同類型的驅動程序又組織成不同目錄,跟hwif目錄一樣。
3.2 驅動程序文件例子:wrsample
風河公司提供的VxBus的驅動程序例子位於目錄:installDir/vxworks-6.x/target/3rdparty/windriver/wrsample,這些文件可以被當做模板來幫助你開發第三方驅動程序,具體信息請參考wrsample目錄下的README文件。
3.3 其他必須的文件
儘管一個驅動程序可以包括很多文件,比如多個源文件和多個頭文件,但是一個標準的VxWorks驅動程序有一個最小的文件集,對於大多數vxworks驅動程序最少要求6個文件:
- 驅動程序源文件 實現驅動程序控制邏輯
- 組件描述文件(CDF) 主要用於將驅動程序集成到VxWorks編譯環境中,以便於配置
- 一個driverName.dc文件 提供驅動註冊常式的原型
- 一個driverName.dr文件 提供一小段調用驅動註冊常式的代碼
- README文件 提供版本信息
- Makefile文件 提供編譯規則
一般情況下,CDF文件,dc文件,dr文件都被認為是驅動程序的配置文件,下面詳細介紹這些文件。
3.3.1 驅動程序源文件
驅動程序源文件包含了驅動程序功能的實現邏輯,它們被放在目錄installDir/vxworks-6.x/target/src/hwif, 第三方的被放在目錄installDir/vxworks-6.x/target/3rdparty。很多VxWorks設備驅動程序只包含一個源文件,一個驅動程序可以包含一個或者幾個可選的頭文件;但是驅動程序可以包含多個源文件,但是此時必須在Makefile裡面提供各個模塊的依賴規則。下面以文件vxbCn3xxxTimer.c來說明VxWorks驅動程序的結構。
設備驅動程序的第一部分是一個描述VxBus初始化階段要調用的常式的結構:
/* data structures used by the driver to register itself * with Vxworks */ /* drvBusFuncs provides a set of entry points into the * driver that are called during various phases of the * boot process. Drivers can choose to implement 1 or * more of these entry point, according to the needs of * the driver during its initialization phases. */ LOCAL struct drvBusFuncs cn3xxxTimerDrvFuncs = { cn3xxxTimerInstInit, /* devInstanceInit */ cn3xxxTimerInstInit2, /* devInstanceInit2 */ cn3xxxTimerInstConnect /* devConnect */ };
接著就是描述驅動程序所支持的驅動方法的數據結構(每一種類別的驅動程序都必須實現該類的驅動方法):
/* cn3xxxTimerDrv_methods provides the list of driver * methods that this driver supports. For each driver * class supported by Wind River, one or more methods * are expected to be defined for the driver. For * timer driver class, the 'vxbTimerFuncGet' method * is required to be supported. */ LOCAL struct vxbDeviceMethod cn3xxxTimerDrv_methods[] = { DEVMETHOD(vxbTimerFuncGet, cn3xxxTimerFuncGet), {0,NULL} };
跟著就是描述該驅動程序需要的註冊信息的結構:
/* The cnxxxTimerDrvRegistration structure provides a * description of the driver to VxWorks, so that VxWorks * can connect this driver to appropriate hardware during * the boot process. */ LOCAL struct vxbDevRegInfo cn3xxxTimerDrvRegistration = { NULL, /* reserved for VxBus use */ VXB_DEVID_DEVICE, /* devID */ VXB_BUSID_PLB, /* busID = PLB */ VXB_VER_4_0_0, /* vxbVersion */ "cn3xxxTimerDev", /* drvName */ &cn3xxxTimerDrvFuncs, /* pDrvBusFuncs */ NULL /* pMethods */ NULL /* devProbe */ };
在註冊信息後面,驅動程序必須提供一個常式來向VxBus註冊,表明該驅動程序的存在:
/* The vxbCn3xxxTimerDrvRegister function contains the * first instructions of the device driver that are * ever executed within a VxWorks system. This function * registers the driver with VxBus by providing pointers * to the data structures listed previously. Once this * step is complete, VxWorks is able to associate this * driver with appropriate hardware within the system * to form an instance. */ void vxbCn3xxxTimerDrvRegister (void) { vxbDevRegister (&cn3xxxTimerDrvRegistration); }
由於驅動程序註冊方法被當做是驅動程序的第一個入口點,VxWorks必須被配置成:當該驅動程序向VxBus註冊時,VxWorks知道調用該入口點。為了做到這點,VxWorks使用了之前提到了那幾個驅動配置文件:CDF文件,dc文件,dr文件。
注意:VxBus和VxWorks要求驅動程序的註冊方法必須是全局的。大多數驅動程序並不需要其他的全局符號,因此都可以聲明成LOCAL。
3.3.2 CDF文件
該文件的全稱是:component description File,組件描述文件。根據VxBus標準開發的VxWorks設備驅動程序都被編譯成一個單獨的模塊,可以使用VxWorks配置工具非常輕鬆地將驅動程序配置進BSP中。但是,你必須為你的設備驅動程序創建一個VxWorks組件。
一個組件是一個基本的功能單元,它可以單獨配置進入VxWorks內核鏡像中。為了能夠單獨添加和刪除設備驅動程序到VxWorks中,驅動程序必須能夠被VxWorks配置工具識別成individual 組件。為了讓驅動程序能夠在Workbench或者vxprj中是可以配置的,你必須創建CDF文件,CDF文件提供VxWorks配置工具所需要的信息。針對風河公司發布的設備驅動程序,其對應的CDF文件位於以下目錄:
installDir/vxworks-6.x/target/config/comps/vxWorks
在風河提供的驅動程序中,一個CDF文件可能包含著描述多個設備驅動程序的信息,對於第三方驅動,其CDF文件路徑是在驅動程序目錄下。
注意:內核配置工具並不自動搜索installDir/vxworks-6.x/target/3rdparty/ directories下的文件,為了讓內核配置工具能夠讀取第三方驅動的CDF文件,必須手工將CDF文件拷貝到以下目錄:installDir/vxworks-6.x/target/config/comps/vxWorks
為新驅動編寫CDF文件之前,首先拷貝一個標準的CDF文件到你的驅動程序目錄,然後根據你的驅動程序來修改CDF文件。CDF文件主要放在以下目錄:
installDir/vxworks-6.x/target/config/comps/vxWorks
以下以一個PCI匯流排控制器的CDF文件為例,這個文件的路徑是:installDir/vxworks-6.x/target/config/comps/vxWorks/40m85xxPci.cdf:
/* 40m85xxPci.cdf - Component configuration file */ Component DRV_PCIBUS_M85XX { NAME M85xx PCI bus SYNOPSIS M85xx PCI bus controller Driver MODULES m85xxPci.o SOURCE $(WIND_BASE)/target/src/hwif/busCtlr _CHILDREN FOLDER_DRIVERS _INIT_ORDER hardWareInterFaceBusInit INIT_RTN m85xxPciRegister(); PROTOTYPE void m85xxPciRegister (void); REQUIRES DRV_RESOURCE_M85XXCCSR \ INCLUDE_PARAM_SYS \ INCLUDE_PCI_BUS \ INCLUDE_PLB_BUS \ INCLUDE_VXBUS INIT_AFTER INCLUDE_PCI_BUS }
Component DRV_PCIBUS_M85XX {
CDF文件使用上述語句來定義一個組件ID。VxWorks中的每個組件必須用Component關鍵字來描述,驅動程序的ID一般以DRV_開始,並在ID中包含該驅動程序的描述性信息,每一類的驅動程序對組件ID都有著相同的命名習慣,比如DRV_PCIBUS_M85XX意味著它是一個PCI 匯流排控制器的組件。設備驅動程序組件標準的命名習慣應該是:DRV_CLASS_NAME,組件名字必須是唯一的,因此DRV_CLASS_NAME中的DRV和CLASS都有可能相同,這就要求NAME必須唯一才行。如果為第三方驅動寫CDF文件,可以考慮把VENDOR和驅動程序名作為NAME的一部分。總之,保證DRV_CLASS_NAME唯一就可以。
注意:以前老的驅動程序一般以INCLUDE_開頭,不過新驅動都更改了這一用法,使用DRV_開頭。
NAME M85xx PCI bus
這是名字域,可讀性較強,會在內核配置工具的名字欄顯示該域定義的信息
SYNOPSIS M85xx PCI bus controller Driver
摘要域,主要是對該組件的簡短介紹
MODULES m85xxPci.o
模塊域,它列舉了編譯驅動程序生成的目標文件的名字。當一個驅動程序被包含在工程中時,VxWorks配置服務會分析模塊域定義的目標文件中的內容,以決定是否會包含其他組件來把該驅動程序編譯進VxWorks鏡像。MODULES和REQUIES域一起,提供了把驅動程序編譯進VxWorks內核所有需要的信息。
_CHILDREN FOLDER_DRIVERS
這個域用來幫助Workbench對相似的組件的顯示進行管理,如下圖:
_INIT_ORDER hardWareInterFaceBusInit
這個初始化順序域描述的是:在VxWorks啟動的過程中,應該在什麼時候初始化本驅動程序,所有的匯流排驅動程序都必須在hardWareInterFaceBusInit中初始化,PCI匯流排也不例外。
INIT_RTN m85xxPciRegister();
定義設備驅動程序的初始化方法,因此,我們必須在這個域提供驅動程序註冊方法。這個只是一個初級或者說最小的初始化,後續的初始化會等到VxWorks找到相關的硬體后就會將驅動程序和硬體綁定,形成了一個實例。
PROTOTYPE void m85xxPciRegister (void);
驅動註冊方法的原型定義
REQUIRES …
該域描述了驅動程序能夠在VxWorks中正常工作所必須有的組件。這個域是必須存在的,因為不是所有設備驅動程序的依賴性都能夠通過檢查驅動中的unresolved externals來決定的。為了支持該驅動程序,它和MODULES域一起決定哪些組件還需要被包含進來。
INIT_AFTER INCLUDE_PCI_BUS
這個INIT_AFTER和INIT_BEFORE被用於指明INIT_ORDER的依賴性,INIT_AFTER說明必須先初始化PCI匯流排,才能夠初始化本驅動。INIT_BEFORE是在這之前必須要初始化本驅動。
HDR_FILES $(WIND_BASE)/target/src/hwif/h/end/fei8255xVxbEnd.h
上面的這行代碼並沒有在例子中出現,HDR_FILES主要提供驅動註冊函數的原型
CFG_PARAMS參數配置
在初始化期間,有時候設備驅動程序需要一些配置信息,如果這些信息是和設備而不是實例相關的,則可以再編譯階段通過傳遞參數來實現。CFG_PARAMS和Parameter關鍵字將幫你實現這些任務。CFG_PARAMS用來指明組件要用的參數,而Parameter用來定義參數。如:
Component DRV_NET_SAMPLE { NAME network device supporting jumbo frames ... CFG_PARAMS SAMPLE_JUMBO_MTU_VALUE } Parameter SAMPLE_JUMBO_MTU_VALUE { NAME Jumbo frame MTU size SYNOPSIS max num of bytes in a jumbo MTU TYPE int DEFAULT 9000 }
每個參數都必須有NAME,SYNOPSIS,TYPE,DEFAULT四個域。TYPE描述了參數的數據類型,包括任何C類型,BOOL,string(NULL-terminated);DEFAULT定義的值是參數的默認值。
3.3.3 驅動程序配置文件
對於某些BSP,VxWorks支持兩種不同的方式來構建VxWorks鏡像,一是使用Workbench或者vxprj命令行工具,二是直接在BSP目錄中調用make命令。所有的BSP都支持第一種方法,儘管大多數都支持make方式,但是並不是所有的VxWorks開發環境和SMP都支持。
當從makefile文件編譯BSP時,CDF裡面的信息並不用來配置BSP,程序員反而可以在BSP源文件config.h裡面直接通過INCLUDE和EXCLUDE添加、刪除某些組件,例如,如果你把Cn3xxx定時器驅動程序包含進你的VxWorks鏡像中,可以在BSP中定義:#define DRV_TIMER_CN3XXX,為了簡單起見,這裡假設DRV_TIMER_CN3XXX不依賴於其他組件。修改完config.h文件后,你可以在BSP目錄中直接調用make工具來編譯BSP,編譯BSP后,剛剛添加的定時器驅動程序已經可以被包含進VxWorks鏡像了。
為了支持驅動程序在BSP中直接編譯,你必須創建兩個附加文件,前面提過的DC和DR文件,這兩個文件的作用就是把驅動程序和BSP命令行工具關聯起來。dc文件的名字必須和驅動程序源文件的名字一樣(後綴不一樣嘛),以CN3XXX定時器驅動程序為例,vxbCn3xxxTimer.dc文件如下:
IMPORT void vxbCn3xxxTimerDrvRegister();
DC文件主要是提供驅動程序註冊方法的原型聲明,或者以#ifdef../#endif來包含住:
#ifdef DRV_TIMER_CN3XXX
IMPORT void vxbCn3xxxTimerDrvRegister();
#endif
DR文件就更加簡潔了,描述了如何調用驅動程序註冊方法,vxbCn3xxxTimer.dr文件如下:
#ifdef DRV_TIMER_CN3XXX
vxbCn3xxxTimerDrvRegister();
#endif
註冊方法必須使用#ifdef/#endif結構來包含,作用是當系統不包含此組件時,就不需要註冊。在#ifdef後面使用的宏必須和CDF中使用的宏一致。對於風河公司提供的設備驅動程序,DC和DR文件的位置在以下目錄:
installDir/vxworks-6.x/target/config/comps/src/hwif
對於第三方驅動,DR和DC文件在驅動程序的目錄下。為了使這些文件起作用,它們必須被合併到VxWorks鏡像的初始化文件中,當新的驅動被增加到VxWorks源碼樹時,可以使用以下命令來重新創建初始化文件:
cd installDir/vxworks-6.x/target/config/comps/src/hwif
make vxbUsrCmdLine.c
當執行MAKE命令時,它會搜索所有的驅動程序配置文件,並一起合併到vxbUsrCmdLine.c文件中,該文件的目錄在:
installDir/vxworks-6.x/target/config/all/vxbUsrCmdLine.c
注意:vxbUsrCmdLine.c文件在以下幾種情況下是不會被更新的:vxbUsrCmdLine.c的修改時間比dc、dr文件和installDir/vxworks-6.x/target/config/comps/src/hwif目錄中的文件的修改時間要更新,在這種情況下,把以前的vxbUsrCmdLine.c文件重命名,並重新執行MAKE命令即可。
3.3.4 README 文件
雖然MAKE環境並不要求有README文件,但是每個設備驅動程序都應該提供README文件給最終用戶。第三方廠商可能會在README文件裡面描述驅動版本信息、驅動程序的文件列表、已知的缺陷等信息。README文件包括三個數據段和三個行分隔符:
- 使用一行文字來表明這是某某驅動程序的README文件,可能會包括支持的設備信息,如:
README: VxWorks/VxBus driver for device device
- 第一個數據段和第二個數據段的分隔符
- 該數據段描述本驅動程序支持的設備列表、已經測試過的設備,也描述了驅動程序的VxWorks和VxBus版本信息,最後還包括組成本驅動的所有文件列表等。
- 第二個數據段和第三個數據段的分隔符
- 驅動程序版本信息列表,以及各個版本的變更信息
注意:驅動程序版本信息包括兩個部分(例如2.3),不能使用3部分的版本信息格式,README文件的一個例子目錄在:
installDir/vxworks-6.x/target/3rdparty/windriver/wrsample
3.3.5 設備驅動程序Makefiles
為了在VxWorks環境中正確編譯設備驅動程序,你必須提供合適的Makefiles。有兩種makefile來幫助你解決問題,第一種是廠商的makefile,目錄位於:installDir/vxworks-6.x/target/3rdparty/vendor/Makefile,第二種是驅動程序的makefile,目錄位於:installDir/vxworks-6.x/target/3rdparty/vendor/driver/Makefile。這些makefiles裡面的內容有點複雜,因此可以在以下目錄拷貝一個makefile模板,然後修改即可:
installDir/vxworks-6.x/target/3rdparty/windriver
installDir/vxworks-6.x/target/3rdparty/windriver/wrsample
(1)廠商makeflie
廠商的makefile是被同一個廠商目錄下的所有驅動程序共享的,它使用通配符來確定哪些驅動程序被安裝到了廠商目錄下,並為每一個設備驅動程序調用make命令。從目錄installDir/vxworks-6.x/target/3rdparty/windriver拷貝makefile模板,並添加到對應廠商目錄下installDir/vxworks-6.x/target/3rdparty/vendor,你可以根據makefile模板做相應的修改。
(2)驅動程序makefile
在以下目錄創建驅動程序makefile
installDir/vxworks-6.x/target/3rdparty/vendor/driver
這個makefile文件用於編譯驅動程序子目錄中的源文件,這個makefile也可以從以下目錄拷貝並加以修改:installDir/vxworks-6.x/target/3rdparty/windriver/wrsample。但是,跟廠商makefile不一樣的是,驅動程序makefile不使用通配符來尋找驅動程序源文件,相反,它包含一個要生產的目標文件列表,並說明如何從源文件中編譯生成這些目標文件。wrsample中的makefile的comment能夠幫助你根據驅動程序來修改makefile,不過通常情況下,主要是修改LIB_BASE_NAME(公司名字),和OBJ_COMMON(要生產的目標文件列表)。另外如果你只想為某一CPU平台編譯驅動程序,可以使用該CPU平台的定義來代替OBJ_COMMON,如POWERPC平台(OBJ_PPC32)。