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