趙 波,高 真 香 子,項(xiàng) 伯 陽,于 忠 得
(1.大連工業(yè)大學(xué) 信息科學(xué)與工程學(xué)院,遼寧 大連 116034;2.大連交通大學(xué) 電氣信息學(xué)院,遼寧 大連 116028)
為統(tǒng)一管理Linux中的所有設(shè)備,Linux開發(fā)了設(shè)備模型。Linux設(shè)備模型可描述為:總線—設(shè)備—驅(qū)動(dòng)程序編程接口,內(nèi)核設(shè)備支持被清晰地結(jié)構(gòu)化為總線、設(shè)備和驅(qū)動(dòng)程序[1]。platform驅(qū)動(dòng)架構(gòu)是Linux設(shè)備模型中的重要組成部分,用于片上系統(tǒng)的外圍設(shè)備控制器驅(qū)動(dòng)的實(shí)現(xiàn)。隨著片上系統(tǒng)(SOC)的集成度越來越高,越來越多的外圍設(shè)備控制器被集成進(jìn)SOC,現(xiàn)有的驅(qū)動(dòng)程序已無法滿足使用需求,研究platform驅(qū)動(dòng)架構(gòu)有利于這些設(shè)備驅(qū)動(dòng)的改寫、維護(hù)與擴(kuò)展,本文實(shí)現(xiàn)了基于platform驅(qū)動(dòng)架構(gòu)的LCD驅(qū)動(dòng)。
Linux設(shè)備模型,實(shí)質(zhì)上就是系統(tǒng)地管理Linux中所有設(shè)備,將設(shè)備間的層次關(guān)系抽象出來。內(nèi)核設(shè)備驅(qū)動(dòng)模型按層次可劃分為總線、設(shè)備、驅(qū)動(dòng)三層架構(gòu),其基本關(guān)系可簡要概括為[2]:
(1)驅(qū)動(dòng)核心可以注冊多種類型的總線;
(2)每種總線下面可以掛載許多設(shè)備(通過kset devices);
(3)每種總線下可以使用多種設(shè)備驅(qū)動(dòng)(通過包含一個(gè)kset drivers);
(4)每個(gè)驅(qū)動(dòng)可以處理一組設(shè)備。
平臺(tái)設(shè)備(platform)驅(qū)動(dòng)架構(gòu)的實(shí)現(xiàn),是在Linux設(shè)備模型的基礎(chǔ)上,通過對總線、設(shè)備、驅(qū)動(dòng)3個(gè)概念的再定義而實(shí)現(xiàn)的[3],在Linux內(nèi)核中,這3個(gè)概念通過platform總線、platform_device(platform設(shè)備)、platform_driver(platform驅(qū)動(dòng))3個(gè)部分實(shí)現(xiàn)。
Linux操作系統(tǒng)中,platform總線負(fù)責(zé)將platform驅(qū)動(dòng)架構(gòu)注冊進(jìn)系統(tǒng)內(nèi)核,在內(nèi)核識(shí)別platform總線之后,才能進(jìn)行platform設(shè)備、platform驅(qū)動(dòng)的識(shí)別與自動(dòng)匹配,所以,platform總線應(yīng)該在系統(tǒng)上電后自動(dòng)啟動(dòng)。platform總線的生成與注冊過程如圖1所示。
圖1 platform總線的生成與注冊過程Fig.1 Platform bus formation and registration process
在系統(tǒng)上電后,Linux內(nèi)核會(huì)自動(dòng)運(yùn)行/init/main.c程序,完成一些基本啟動(dòng)配置,然后調(diào)用/drivers/base/init.c文件中的driver_init()函數(shù),進(jìn)行內(nèi)核驅(qū)動(dòng)機(jī)制初始化,其中就會(huì)通過調(diào)用/drivers/base/platform.c文件的 device_register()函數(shù),將platform總線與platform驅(qū)動(dòng)架構(gòu)注冊進(jìn)Linux內(nèi)核。其中,platform總線作為設(shè)備的一種,通過platform_bus結(jié)構(gòu)體表示;platform驅(qū)動(dòng)架構(gòu)通過platform_bus_type結(jié)構(gòu)體來實(shí)現(xiàn),這兩個(gè)結(jié)構(gòu)體均在platform.c中被定義為全局對象。
platform設(shè)備主要包括LCD、串口等可以被CPU總線直接尋址的集成于片上系統(tǒng)(SOC)的外圍設(shè)備控制器等[4]。Linux內(nèi)核中,platform設(shè)備通過platform_device結(jié)構(gòu)體實(shí)現(xiàn),代碼路徑:/include/linux/platform_device.h,具體定義如下:
其中,設(shè)備名稱name是platform設(shè)備與platform驅(qū)動(dòng)自動(dòng)匹配的關(guān)鍵,只有name值相同時(shí),platform設(shè)備與platform驅(qū)動(dòng)才能匹配上。
Linux系統(tǒng)中,通過結(jié)構(gòu)體的互相包含方式,實(shí)現(xiàn)了面向?qū)ο笏枷氲睦^承。在platform設(shè)備結(jié)構(gòu)體中,就包含了struct device結(jié)構(gòu)體,實(shí)現(xiàn)了對Linux中設(shè)備概念(struct device)的繼承。在struct device dev中dev->platform_data與dev->driver_data是兩個(gè)void型變量,可用于存儲(chǔ)具體設(shè)備的硬件信息、驅(qū)動(dòng)信息等,如LCD的分辨率、刷新率等,可定義一個(gè)FS2410_fb_mach_info結(jié)構(gòu),記錄LCD的硬件信息(屏幕尺寸、屏幕信息、LCD配置寄存器)等,并將該結(jié)構(gòu)體賦值給platform_device中的dev->platform_data。
*resource是具體設(shè)備的資源,如中斷號(hào)IRQ、地址資源等。通過platform_device_register()可以自動(dòng)將platform_device結(jié)構(gòu)體(硬件配置信息)注冊進(jìn)內(nèi)核空間。
platform設(shè)備必須在platform驅(qū)動(dòng)之前注冊入內(nèi)核空間,否則無法自動(dòng)匹配。
platform驅(qū)動(dòng)完全遵照設(shè)備驅(qū)動(dòng)模型的約定[3],通過platform_driver_register()函數(shù)完成platform_driver的注冊,platform驅(qū)動(dòng)的封裝結(jié)構(gòu)體為 platform_driver,代碼路徑為:/include/linux/platform_device.h,具體定義如下:struct device_driver driver,實(shí)現(xiàn)了對 device_driver的繼承,為具體的platform驅(qū)動(dòng)提供了統(tǒng)一內(nèi)核接口;同時(shí),提供了(*suspend)、(*resume)等函數(shù)指針,可用于休眠、喚醒等智能電源管理功能。在具體應(yīng)用中,只需驅(qū)動(dòng)開發(fā)人員實(shí)現(xiàn)設(shè)備底層功能函數(shù),同時(shí)將功能函數(shù)填充platform_driver結(jié)構(gòu)體的接口中,就可以由Linux內(nèi)核自動(dòng)進(jìn)行platform驅(qū)動(dòng)的管理,大大減輕了工作難度與強(qiáng)度。
對于platform_driver的注冊,可以通過調(diào)用platform_driver_register(&platform_driver)來實(shí)現(xiàn),其主要涉及的數(shù)據(jù)流程參見圖2。
圖2 注冊platform驅(qū)動(dòng)的內(nèi)核數(shù)據(jù)流程Fig.2 Kernel data flow of Platform driver register
在platform驅(qū)動(dòng)的注冊過程中,會(huì)在_driver_attach()中通過調(diào)用driver_match_device(drv,dev)來匹配platform設(shè)備中name與platform驅(qū)動(dòng)中的name值,如果相同,platform設(shè)備與platform驅(qū)動(dòng)就綁定成功,底層的設(shè)備就可以正常地運(yùn)行。
本研究以優(yōu)龍F(tuán)S2410開發(fā)板為硬件平臺(tái),Linux 2.6.31為內(nèi)核版本,外接8寸夏普LCD顯示屏,采用Platform驅(qū)動(dòng)架構(gòu)的LCD驅(qū)動(dòng)實(shí)現(xiàn)。在FS2410中,LCDC(LCD控制器)是集成于SOC的外圍設(shè)備控制器,被CPU總線直接尋址,按照platform驅(qū)動(dòng)架構(gòu)的一般步驟,有四個(gè)環(huán)節(jié):定義platform 設(shè)備(platform_device)、注冊platform設(shè)備、定義platform驅(qū)動(dòng)(platform_driver)、注冊platform驅(qū)動(dòng),同時(shí)必須保證platform設(shè)備在platform驅(qū)動(dòng)之前注冊進(jìn)內(nèi)核空間。
代碼路徑:/arch/arm/plat-s3c24xx/Devs.c。
在Devs.c統(tǒng)一定義了S3C24xx架構(gòu)的platform_device,在這個(gè)文件里,可定義
在同文件的如下程序中定義了Lcdc所持有的資源(CPU尋址地址、IRQ中斷號(hào))。
同時(shí),定義一個(gè)FS2410fb_mach_info結(jié)構(gòu)體,記錄LCD的屏幕信息、分辨率、LCD配置寄存器等信息,并填充到platform_device的dev->platform_data中,供內(nèi)核空間調(diào)用。
代碼路徑:/arch/arm/mach-s3c2410/mach_smdk2410.c。
在 mach-smdk2410.c中,通過platform_add_devices(smdk2410_devices,…)將 smdk2410_devices注冊進(jìn)內(nèi)核空間,其中smdk2410_devices[]={&s3c_device_usb,&s3c_device_lcd,…},即所有2410平臺(tái)的platform設(shè)備,都被裝填入smdk2410_devics[]這個(gè)數(shù)組,在platform_add_devices()中統(tǒng)一注冊進(jìn)內(nèi)核空間。
代碼路徑:/drivers/video/s3c2410fb.c。
在s3c2410fb.c對platform_driver進(jìn)行了定義:
在此結(jié)構(gòu)體中,具體填充了probe驅(qū)動(dòng)探測函數(shù),suspend、resume電源管理函數(shù),對于驅(qū)動(dòng)開發(fā)人員,不需關(guān)心內(nèi)核對它的調(diào)用,只需關(guān)心具體功能函數(shù)的實(shí)現(xiàn),并填充到標(biāo)準(zhǔn)接口即可。在.driver中.name=”FS2410-lcd”,這個(gè)值需要與platform_device中的name完全一致。在suspend、resume部分,實(shí)行了Linux電源管理,在具體驅(qū)動(dòng)開發(fā)中,可以在此處實(shí)現(xiàn)智能節(jié)電措施,可以采用如安卓操作系統(tǒng)(Android)中的喚醒鎖(wakelock)等機(jī)制。
S3c2410fb_probe()的調(diào)用實(shí)現(xiàn),是在將platform驅(qū)動(dòng)注冊進(jìn)內(nèi)核空間,并和內(nèi)核已維護(hù)的platform_device鏈表中的name相匹配后。其具體實(shí)現(xiàn)流程:
在/drivers/video/s3c2410fb.c中通過調(diào)用platform_driver_register()實(shí)現(xiàn)了platform_driver的注冊,具體實(shí)現(xiàn)如下:platform_driver_register(&s3c2410fb_driver)。
采用platform驅(qū)動(dòng)架構(gòu),移植LCD驅(qū)動(dòng),修改相應(yīng) Makefile、Kconfig[5],編譯內(nèi)核,并通過USB下載到FS2410開發(fā)板后,串口打印顯示LCD驅(qū)動(dòng)加載成功。圖3為在移植后的8寸夏普LCD屏上運(yùn)行QT/E應(yīng)用程序,顯示結(jié)果清晰、穩(wěn)定,無撕裂現(xiàn)象。
圖3 移植實(shí)驗(yàn)結(jié)果Fig.3 Porting experiment results
采用platform驅(qū)動(dòng)架構(gòu),具有框架代碼復(fù)用、設(shè)備資源與驅(qū)動(dòng)獨(dú)立性強(qiáng)、代碼精簡、具有統(tǒng)一內(nèi)核接口、易于維護(hù)與擴(kuò)展等特點(diǎn)。在開發(fā)具體驅(qū)動(dòng)時(shí),只需專注完成底層設(shè)備操作函數(shù)集,并與platform_driver結(jié)構(gòu)體提供的內(nèi)核接口一一對應(yīng),保證device.name與driver.name相一致,platform設(shè)備在platform驅(qū)動(dòng)之前注冊進(jìn)內(nèi)核空間,就可以使驅(qū)動(dòng)良好、穩(wěn)定地運(yùn)行,大大減輕了工作強(qiáng)度,壓縮新產(chǎn)品的研發(fā)時(shí)間。移植試驗(yàn)證明,采用該架構(gòu)的驅(qū)動(dòng)具有很好的移植性、可維護(hù)性、擴(kuò)展性。
[1]VENKATESWARAN S.Essential Linux Device Drivers[M].Boston:Prentice Hall,2008:71-77.
[2]CORBET J,RUBINI A,HARTMAN G K.Linux設(shè)備驅(qū)動(dòng)程序[M].3版.魏永明,譯.北京:中國電力出版社,2006:359-388.
[3]韋東山.嵌入式Linux應(yīng)用開發(fā)完全手冊[M].北京:人民郵電出版社,2008:476-490.
[4]宮莉莉,趙勇.基于嵌入式Linux系統(tǒng)的LCD驅(qū)動(dòng)實(shí)現(xiàn)[J].微計(jì)算機(jī)信息,2008,24(35):1-3.
[5]蘇哲欣,劉鴻飛,薛曉.基于嵌入式Linux的LCD驅(qū)動(dòng)分析與實(shí)現(xiàn)[J].工業(yè)控制計(jì)算機(jī),2009,22(2):29-30.