基于Linux的USB主/從設(shè)備之間的三種通信方式
一旦在設(shè)備中實現(xiàn)了用戶定制的內(nèi)核模塊,就可以使該設(shè)備完成相當復雜的功能,例如仿真一個文件系統(tǒng),從而允許嵌入式應(yīng)用將其USB主機當作一個遠程存儲設(shè)備。除此以外,采用這種方法之后,設(shè)備還可以具備存儲轉(zhuǎn)發(fā)(store-and-forward)的功能,因而能夠在與USB主機的連接建立之前對來自嵌入式應(yīng)用的數(shù)據(jù)流進行緩沖。
在基于StrongARM的Linux設(shè)備中,內(nèi)核代碼用于管理芯片所攜帶的USB設(shè)備控制器外設(shè),通過調(diào)用函數(shù)sa1100_usb_open ()來初始化。在初始化之后,內(nèi)核模塊還會調(diào)用函數(shù)sa1100_usb_get_descriptor_ptr() 和sa1100_usb_set_string_descriptor()來設(shè)置在設(shè)備查詢期間傳送給USB主機的描述符,其中包含設(shè)備的數(shù)字廠商號和產(chǎn)品標識符,以及可以讓主機用來識別設(shè)備的字符串,甚至還有一個序列號域,以便主機可以唯一地識別一個連接在USB接口上的設(shè)備,或者在同種型號的多個設(shè)備中進行區(qū)分。
設(shè)備查詢過程是由USB設(shè)備控制器驅(qū)動的,并且一旦和USB主機連上之后會自動執(zhí)行,所以內(nèi)核模塊必須在USB通信開始之前設(shè)置好每個設(shè)備的描述符。當準備工作就緒之后,USB設(shè)備模塊就會調(diào)用函數(shù)sa1100_usb_start()來通知內(nèi)核接收主機發(fā)來的USB連接請求。如果設(shè)備模塊在連上USB 主機之前調(diào)用了函數(shù)sa1100_set_configured_callback(),那么接著內(nèi)核模塊就會在查詢過程結(jié)束時調(diào)用回調(diào)函數(shù)?;卣{(diào)函數(shù)很適合用來在設(shè)備上發(fā)出警告或給出一些形象的暗示,說明連接已經(jīng)建立。
如果不再需要進行USB通信,那么設(shè)備的內(nèi)核模塊就會先調(diào)用函數(shù)sa1100_usb_stop(),然后調(diào)用sa1100_usb_close(),來關(guān)閉SA1100上的USB控制器。
StrongARM 的 USB控制器支持bulk-in和bulk-out兩種數(shù)據(jù)傳送方式。當接收來自USB主機的數(shù)據(jù)包時,內(nèi)核模塊會調(diào)用sa1100_usb_recv (),將一個數(shù)據(jù)緩沖區(qū)的地址和一個回調(diào)函數(shù)送給它。然后內(nèi)核中的USB設(shè)備控制代碼會從主機取回一個bulk-out數(shù)據(jù)包,將其內(nèi)容存入制定的緩沖區(qū),接著調(diào)用回調(diào)函數(shù)。
下一步,回調(diào)函數(shù)從接收緩沖區(qū)中提取出數(shù)據(jù),將其存放到其他地方,或者將緩沖區(qū)空間添加到一個隊列中,然后分配一個新的緩沖區(qū)來接收下一個數(shù)據(jù)包。然后,如果還有數(shù)據(jù)需要接收,那么回調(diào)函數(shù)會重新調(diào)用sa1100_usb_recv(),準備接收另一個數(shù)據(jù)包。
向USB 主機發(fā)送數(shù)據(jù)的過程與此類似。內(nèi)核模塊收集了一幀數(shù)據(jù)之后,將數(shù)據(jù)的存放地址、數(shù)據(jù)長度和回調(diào)函數(shù)的地址送給sa1100_usb_send()函數(shù)。接著,在數(shù)據(jù)傳送結(jié)束之后,內(nèi)核模塊會調(diào)用回調(diào)函數(shù)。
在www.embedded.com/code.htm (arch/arm/mach-sa1100/usb-char.c)可以找到一個叫做usb-char的模塊,這是一個很好的設(shè)備端SA1110 Linux USB模塊的例子。該模塊將USB設(shè)備與USB 主機之間的連接變成一種高速串行鏈接。此外, usb-eth( arch/arm/mach-sa1100/usb-eth.c)模塊也是個不錯的例子,該模塊將USB變成了一種虛擬的以太型網(wǎng)絡(luò)。后面會深入探討這兩種模塊。
2. USB主機端通信過程
有些很好的主機端USB驅(qū)動程序的例子是隨主流Linux操作系統(tǒng)的發(fā)布而提供的,位于The Linux Kernel Archives (kernel.org)發(fā)布的原始內(nèi)核源代碼中。其中,Handspring Visor 模塊(drivers/usb/serial/visor.c)是一個編寫得更清晰,也更易理解的模塊,它同時也是USB 主機端模塊(drivers/usb/usb-skeleton.c)的模板。
利用USB實現(xiàn)高速串行通信
1. USB設(shè)備端通信過程
為了達到最實用的效果,我們可以將USB總線簡單地看作一個高速串口,然后,在一些嵌入式設(shè)備和應(yīng)用中,我們就可以用USB接口來模擬串口。 StrongARM處理器的Linux內(nèi)核就提供了一個名為usb-char的USB設(shè)備驅(qū)動程序,它所完成的恰好就是用USB模擬串口的功能。
當需要與USB 主機通信時,Linux操作系統(tǒng)中的USB設(shè)備應(yīng)用只是簡單地打開一個與其usb-char設(shè)備節(jié)點的連接(連接類型為字符型,major number 為10, minor 為240),然后就開始讀寫數(shù)據(jù)。在與USB 主機的連接建立之前,read()和write()操作均返回一個錯誤信息。一旦連接建立好,并且設(shè)備查詢完成之后,USB接口就開始象一個點對點的串口一樣與主機進行通信。
這種進行USB數(shù)據(jù)傳送的方法非常簡單有效,因而usb-char設(shè)備模塊發(fā)布之后一直很受歡迎。而且,該模塊還為通過其他方法進行USB通信提供了一個參考。
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)linux相關(guān)文章:linux教程
評論