Linux主機(jī)驅(qū)動與外設(shè)驅(qū)動分離思想_第1頁
Linux主機(jī)驅(qū)動與外設(shè)驅(qū)動分離思想_第2頁
Linux主機(jī)驅(qū)動與外設(shè)驅(qū)動分離思想_第3頁
Linux主機(jī)驅(qū)動與外設(shè)驅(qū)動分離思想_第4頁
Linux主機(jī)驅(qū)動與外設(shè)驅(qū)動分離思想_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、Linux主機(jī)驅(qū)動與外設(shè)驅(qū)動分離思想1主機(jī)、外設(shè)驅(qū)動分離的意義在Linux設(shè)備驅(qū)動框架的設(shè)計中,除了有分層設(shè)計實現(xiàn)以外,還有分隔的思想。舉一個簡單的例子,假設(shè)我們要通過SPI總線訪問某外設(shè),在這個訪問過程中,要通過操作CPU XXX上的SPI控制器的寄存器來達(dá)到訪問SPI外設(shè)YYY的目的,最簡單的方法是:return_type xxx_write_spi_yyy(.)xxx_write_spi_host_ctrl_reg(ctrl);xxx_ write_spi_host_data_reg(buf);while(!(xxx_spi_host_status_reg()&SPI_DATA_TRAN

2、SFER_DONE);.如果按照這種方式來設(shè)計驅(qū)動,結(jié)果是對于任何一個SPI外設(shè)來講,它的驅(qū)動代碼都是CPU相關(guān)的。也就是說,當(dāng)然用在CPU XXX上的時候,它訪問XXX的SPI主機(jī)控制寄存器,當(dāng)用在XXX1的時候,它訪問XXX1的SPI主機(jī)控制寄存器:return_type xxx1_write_spi_yyy(.)xxx1_write_spi_host_ctrl_reg(ctrl);xxx1_ write_spi_host_data_reg(buf);while(!(xxx1_spi_host_status_reg()&SPI_DATA_TRANSFER_DONE);.這顯然是不能接受的,

3、因為這意味著外設(shè)YYY用在不同的CPU XXX和XXX1上的時候需要不同的驅(qū)動。那么,我們可以用如圖12.4的思想對主機(jī)控制器驅(qū)動和外設(shè)驅(qū)動進(jìn)行分離。這樣的結(jié)構(gòu)是,外設(shè)a、b、c的驅(qū)動與主機(jī)控制器A、B、C的驅(qū)動不相關(guān),主機(jī)控制器驅(qū)動不關(guān)心外設(shè),而外設(shè)驅(qū)動也不關(guān)心主機(jī),外設(shè)只是訪問核心層的通用的API進(jìn)行數(shù)據(jù)傳輸,主機(jī)和外設(shè)之間可以進(jìn)行任意的組合。圖12.4 Linux設(shè)備驅(qū)動的主機(jī)、外設(shè)驅(qū)動分離如果我們不進(jìn)行如圖12.4的主機(jī)和外設(shè)分離,外設(shè)a、b、c和主機(jī)A、B、C進(jìn)行組合的時候,需要9個不同的驅(qū)動。設(shè)想一共有m個主機(jī)控制器,n個外設(shè),分離的結(jié)果是需要m+n個驅(qū)動,不分離則需要m*n個驅(qū)動

4、。Linux SPI、I2C、USB、ASoC(ALSA SoC)等子系統(tǒng)都典型地利用了這種分離的設(shè)計思想,在本章我們先以簡單一些的SPI為例,而I2C、USB、ASoC等則在后續(xù)章節(jié)會進(jìn)行詳細(xì)介紹。2 Linux SPI主機(jī)和設(shè)備驅(qū)動SPI(同步外設(shè)接口)是由摩托羅拉公司開發(fā)的全雙工同步串行總線,其接口由MISO(串行數(shù)據(jù)輸入),MOSI(串行數(shù)據(jù)輸出),SCK(串行移位時鐘),SS(從使能信號)四種信號構(gòu)成,SS決定了唯一的與主設(shè)備通信的從設(shè)備,主設(shè)備通過產(chǎn)生移位時鐘來發(fā)起通訊。通訊時,數(shù)據(jù)由MOSI輸出,MISO輸入,數(shù)據(jù)在時鐘的上升或下降沿由MOSI輸出,在緊接著的下降或上升沿由MIS

5、O讀入,這樣經(jīng)過8/16次時鐘的改變,完成8/16位數(shù)據(jù)的傳輸。SPI模塊為了和外設(shè)進(jìn)行數(shù)據(jù)交換,根據(jù)外設(shè)工作要求,其輸出串行同步時鐘極性(CPOL)和相位(CPHA)可以進(jìn)行配置。如果 CPOL=0,串行同步時鐘的空閑狀態(tài)為低電平;如果CPOL=1,串行同步時鐘的空閑狀態(tài)為高電平。如果CPHA=0,在串行同步時鐘的第一個跳變沿(上升或下降)數(shù)據(jù)被采樣;如果CPHA=1,在串行同步時鐘的第二個跳變沿(上升或下降)數(shù)據(jù)被采樣。SPI接口時序如圖12.5所示。圖12.5 SPI總線時序在Linux中,用代碼清單12.12的spi_master結(jié)構(gòu)體來描述一個SPI主機(jī)控制器驅(qū)動,其主要成員是主機(jī)控

6、制器的序號(系統(tǒng)中可能存在多個SPI主機(jī)控制器)、片選數(shù)量、SPI模式和時鐘設(shè)置用到的函數(shù)、數(shù)據(jù)傳輸用到的函數(shù)等。代碼清單12.12 spi_master結(jié)構(gòu)體1 struct spi_master 2 struct device dev;3 s16 bus_num;4 u16 num_chipselect;56 /* 設(shè)置模式和時鐘 */7 int (*setup)(struct spi_device *spi);89 /* 雙向數(shù)據(jù)傳輸 */10 int (*transfer)(struct spi_device *spi,11 struct spi_message *mesg);12 1

7、3 void (*cleanup)(struct spi_device *spi);14 ;分配、注冊和注銷SPI主機(jī)的API由SPI核心提供:struct spi_master * spi_alloc_master(struct device *host, unsigned size);int spi_register_master(struct spi_master *master);void spi_unregister_master(struct spi_master *master);在Linux中,用代碼清單12.13的spi_driver結(jié)構(gòu)體來描述一個SPI外設(shè)驅(qū)動,可以認(rèn)為是

8、spi_master的client驅(qū)動。代碼清單12.13 spi_driver結(jié)構(gòu)體1 struct spi_driver 2 int (*probe)(struct spi_device *spi);3 int (*remove)(struct spi_device *spi);4 void (*shutdown)(struct spi_device *spi);5 int (*suspend)(struct spi_device *spi, pm_message_t mesg);6 int (*resume)(struct spi_device *spi);7 struct device

9、_driver driver;8 ;可以看出,spi_driver結(jié)構(gòu)體和platform_driver結(jié)構(gòu)體有極大的相似性,都有probe()、remove()、suspend()、resume()這樣的接口。是的,這幾乎是一切client驅(qū)動的習(xí)慣模板。在SPI外設(shè)驅(qū)動中,當(dāng)透過SPI總線進(jìn)行數(shù)據(jù)傳輸?shù)臅r候,使用了一套與CPU無關(guān)的統(tǒng)一的接口。這套接口的第1個關(guān)鍵數(shù)據(jù)結(jié)構(gòu)就是spi_transfer,它用于描述SPI傳輸,如代碼清單12.14。代碼清單12.14 spi_transfer結(jié)構(gòu)體1 struct spi_transfer 2 const void *tx_buf;3 void

10、 *rx_buf; 4 unsigned len;56 dma_addr_t tx_dma;7 dma_addr_t rx_dma;89 unsigned cs_change:1;10 u8 bits_per_word;11 u16 delay_usecs; 12 u32 speed_hz;1314 struct list_head transfer_list;15 ;而一次完整的SPI傳輸流程可能不只包含1次spi_transfer,它可能包含1個或多個spi_transfer,這些spi_transfer最終通過spi_message組織在一起,其定義如代碼清單12.15。代碼清單12.1

11、5 spi_message結(jié)構(gòu)體1 struct spi_message 2 struct list_head transfers;34 struct spi_device *spi;56 unsigned is_dma_mapped:1;78 /* 完成被一個callback報告 */9 void (*complete)(void *context);10 void *context;11 unsigned actual_length;12 int status;13 14 struct list_head queue;15 void *state;16 ;通過spi_message_ini

12、t()可以初始化spi_message,而將spi_transfer添加到spi_message隊列的方法則是:void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m);發(fā)起一次spi_message的傳輸有同步和異步兩種方式,使用同步API時,會阻塞等待這個消息被處理完。同步操作時使用的API是:int spi_sync(struct spi_device *spi, struct spi_message *message);使用異步API時,不會阻塞等待這個消息被處理完,但是可以在spi_message

13、的complete字段掛接一個回調(diào)函數(shù),當(dāng)消息被處理完成后,該函數(shù)會被調(diào)用。異步操作時使用的API是:int spi_async(struct spi_device *spi, struct spi_message *message);代碼清單12.16是非常典型的初始化spi_transfer、spi_message并進(jìn)行SPI數(shù)據(jù)傳輸?shù)睦?,同時它們也是SPI核心層的2個通用API,在SPI外設(shè)驅(qū)動中可以直接調(diào)用它們進(jìn)行寫和讀操作。代碼清單12.16 SPI傳輸實例spi_write()、spi_read() API1 static inline int2 spi_write(struct

14、 spi_device *spi, const u8 *buf, size_t len)3 4 struct spi_transfer t = 5 .tx_buf = buf,6 .len = len,7 ;8 struct spi_message m;910 spi_message_init(&m);11 spi_message_add_tail(&t, &m);12 return spi_sync(spi, &m);13 14 15 static inline int16 spi_read(struct spi_device *spi, u8 *buf, size_t len)17 18

15、struct spi_transfer t = 19 .rx_buf = buf,20 .len = len,21 ;22 struct spi_message m;23 24 spi_message_init(&m);25 spi_message_add_tail(&t, &m);26 return spi_sync(spi, &m);27 LDD6410開發(fā)板所使用的S3C6410的SPI主機(jī)控制器驅(qū)動位于drivers/spi/spi_s3c.h和drivers/spi/spi_s3c.c這2個文件,其主體是實現(xiàn)了spi_master的setup()、transfer()等成員函數(shù)。SP

16、I外設(shè)驅(qū)動遍布于內(nèi)核的drivers、sound的各個子目錄之下,SPI只是一種總線,spi_driver的作用只是將SPI外設(shè)掛接在該總線上,因此在spi_driver的probe()成員函數(shù)中,將注冊SPI外設(shè)本身所屬設(shè)備驅(qū)動的類型。和platform_driver對應(yīng)著一個platform_device一樣,spi_driver也對應(yīng)著一個spi_device;platform_device需要在BSP的板文件中添加板信息數(shù)據(jù),而spi_device也同樣需要。spi_device的板信息用spi_board_info結(jié)構(gòu)體描述,該結(jié)構(gòu)體記錄SPI外設(shè)使用的主機(jī)控制器序號、片選序號、數(shù)據(jù)

17、比特率、SPI傳輸模式(即CPOL、CPHA)等。如諾基亞770上2個SPI設(shè)備的板信息數(shù)據(jù)如代碼清單12.17,位于板文件arch/arm/mach-omap1/board-nokia770.c。代碼清單12.17諾基亞770板文件中的spi_board_info1 static struct spi_board_info nokia770_spi_board_info _initdata = 2 0 = 3 .modalias = lcd_mipid,4 .bus_num = 2, /* 用到的SPI主機(jī)控制器序號 */5 .chip_select = 3, /* 使用哪一號片選 */6 .max_speed_hz = , /* SPI數(shù)據(jù)傳輸比特率 */7 .platform_data = &nokia770_mipid_platform_data,8 ,9 1 = 10 .modalias = ads7846,11 .bus_num = 2,12 .chip_select = 0,13 .max_speed_hz = ,14 .irq

溫馨提示

  • 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

提交評論