姓名:薛紹宏? ? ?學(xué)號(hào):19020100016? ? 學(xué)院:電子工程學(xué)院
【嵌牛導(dǎo)讀】本文介紹了嵌入式Linux基于libusb的USB驅(qū)動(dòng)開(kāi)發(fā)
【嵌牛鼻子】嵌入式Linux驅(qū)動(dòng)程序開(kāi)發(fā)
【嵌牛提問(wèn)】嵌入式Linux的USB驅(qū)動(dòng)如何基于libusb進(jìn)行開(kāi)發(fā)示惊?
【嵌牛正文】
由于usb設(shè)備的普遍性及其多樣性究西,大量的usb設(shè)備的驅(qū)動(dòng)開(kāi)發(fā)也就成為開(kāi)發(fā)者做的最多的事情。Linux平臺(tái)上蘸炸,內(nèi)核驅(qū)動(dòng)的開(kāi)發(fā)由于內(nèi)核的復(fù)雜和版本問(wèn)題慕购,初學(xué)者難以入手聊疲,驅(qū)動(dòng)程序也不易升級(jí)和維護(hù)。本文主要介紹Linux平臺(tái)下使用libusb庫(kù)基于usb文件系統(tǒng)的驅(qū)動(dòng)開(kāi)發(fā)脓钾,并將其應(yīng)用到嵌入式系統(tǒng)中售睹,可顯著降低開(kāi)發(fā)難度,提高工作效率
1.前言
Linux內(nèi)核經(jīng)過(guò)開(kāi)發(fā)人員的不斷努力可训,已經(jīng)變得十分地完善和強(qiáng)大昌妹。其中,設(shè)備驅(qū)動(dòng)占據(jù)了內(nèi)核的很大一部分握截,內(nèi)核都能夠高效飞崖、穩(wěn)定地驅(qū)動(dòng)大部分設(shè)備。而另外一些設(shè)備谨胞,注入自己設(shè)計(jì)的硬件產(chǎn)品固歪。這些驅(qū)動(dòng)就需要驅(qū)動(dòng)工程師開(kāi)發(fā)出相關(guān)的內(nèi)核設(shè)備驅(qū)動(dòng)了。內(nèi)核驅(qū)動(dòng)有他的優(yōu)點(diǎn),然而在內(nèi)核驅(qū)動(dòng)開(kāi)發(fā)過(guò)程中會(huì)遇到如下的一些問(wèn)題:
對(duì)于不用的Linux內(nèi)核版本牢裳,驅(qū)動(dòng)程序也會(huì)有不同的版本逢防。不利于升級(jí)和維護(hù)。
Linux自帶的驅(qū)動(dòng)程序開(kāi)發(fā)蒲讯,需要對(duì)內(nèi)核的重新編譯忘朝,而且開(kāi)發(fā)出來(lái)的驅(qū)動(dòng)模塊比較大。
所以判帮,如果我們能夠找到一個(gè)為用戶(hù)空間提供與內(nèi)核版本無(wú)關(guān)的通用接口的方法局嘁,就能夠不必重新改變編譯好的內(nèi)核,也不必為內(nèi)核版本兼容性問(wèn)題而頭痛晦墙,只需在用戶(hù)空間開(kāi)發(fā)程序悦昵。這樣就極大地提高了開(kāi)發(fā)效率,縮短了開(kāi)發(fā)周期晌畅。
USB協(xié)議是目前使用最廣泛的外部總線(xiàn)協(xié)議但指,Linux對(duì)usb控制器、usb核心和常用的usb設(shè)備驅(qū)動(dòng)有了比較完善的支持抗楔。但由于usb所支持的設(shè)備的多樣性枚赡,一些特殊的usb設(shè)備的驅(qū)動(dòng)還需要開(kāi)發(fā)人員自行編寫(xiě)。而libusb為開(kāi)發(fā)人員提供了在用戶(hù)空間操作usb設(shè)備的API函數(shù)庫(kù)谓谦,使usb驅(qū)動(dòng)開(kāi)發(fā)變得極為方便贫橙。
2.實(shí)現(xiàn)原理
2.1USB簡(jiǎn)介
usb(Universal Serial Bus)是用于將適用usb的外圍設(shè)備連接到主機(jī)的外部總線(xiàn)結(jié)構(gòu)。目前usb接口規(guī)范主要有:USB1.1(低速1.5Mb/s反粥,全速12Mb/s)和USB2.0(高速480Mb/s)卢肃,能夠滿(mǎn)足大部分外圍設(shè)備的傳輸速度要求。usb同時(shí)又是一種通信協(xié)議才顿,他支持主系統(tǒng)(host)和usb的外圍設(shè)備(device)之間的數(shù)據(jù)傳輸莫湘。當(dāng)前流行的USB Host規(guī)范有:OHCI、UHCI和EHCI郑气。嵌入式系統(tǒng)主要是使用OHCI規(guī)范幅垮。
usb驅(qū)動(dòng)分為usb主機(jī)端驅(qū)動(dòng)程序和usb設(shè)備端驅(qū)動(dòng)程序,本文重點(diǎn)分析usb主機(jī)端驅(qū)動(dòng)程序的開(kāi)發(fā)過(guò)程尾组。USB主機(jī)(host)驅(qū)動(dòng)結(jié)構(gòu)如圖:
開(kāi)發(fā)人員主要關(guān)注usb設(shè)備驅(qū)動(dòng)部分忙芒。usb設(shè)備的邏輯組織中,包含設(shè)備(device)讳侨、配置(config)呵萨、接口(interface)和端口(endpoint)四個(gè)層次:
每個(gè)usb設(shè)備可以有一個(gè)或多個(gè)配置,但一次只能選中其中一個(gè)跨跨。接口經(jīng)捆綁為配置潮峦。接口代表了一個(gè)基本功能。
每個(gè)usb驅(qū)動(dòng)程序控制一個(gè)接口,而一個(gè)接口有不同的設(shè)置(setting)忱嘹,但同一時(shí)間只能有一種活躍配置(cur_altsetting)嘱腥。設(shè)備接口是端點(diǎn)的集合(collection),端點(diǎn)是usb通信的最基本形式拘悦。usb主機(jī)(host)通過(guò)端點(diǎn)與usb設(shè)備進(jìn)行通信爹橱。
usb端點(diǎn)有以下四種傳輸方式:控制(Control),等待(iso)窄做、中斷(interrupt)、批量(bulk)慰技⊥终担控制和批量端點(diǎn)用于異步的少量數(shù)據(jù)傳輸,而批量和等時(shí)端點(diǎn)是周期性的吻商√图眨控制和中斷端點(diǎn)是用于少量數(shù)據(jù)傳輸,而批量和等時(shí)端點(diǎn)用于大量數(shù)據(jù)傳輸艾帐。
控制端點(diǎn)同城用于配置設(shè)備乌叶、獲取設(shè)備信息、發(fā)送命令到設(shè)備柒爸、或者獲取設(shè)備的狀態(tài)報(bào)告准浴,“端點(diǎn)0”為默認(rèn)的控制端點(diǎn),usb核心使用該端點(diǎn)在設(shè)備插入時(shí)進(jìn)行設(shè)備的配置捎稚。批量端點(diǎn)它要求數(shù)據(jù)傳輸?shù)臏?zhǔn)確性乐横,但不保證固定時(shí)間內(nèi)的完成。中斷端點(diǎn)是例如usb鍵盤(pán)和鼠標(biāo)所使用的的主要傳輸方式今野。libusb主要提供控制葡公、批量和中斷的傳輸方式的API函數(shù)。
2.2usb文件系統(tǒng)(usbfs)
Linux內(nèi)核提供了usb文件系統(tǒng)条霜,他需要編寫(xiě)內(nèi)核時(shí)選中相關(guān)編譯選項(xiàng)催什。并在系統(tǒng)啟動(dòng)運(yùn)行時(shí)動(dòng)態(tài)掛載≡姿可在/etc/fstab文件中添加如下一行:
nonc /proc/bus/usb usbfs defaults 0 0
或者輸入命令:
mount -t usbfs none /proc/bus/usb
usbfs動(dòng)態(tài)跟蹤總線(xiàn)上插入和移除的設(shè)備蒲凶,通過(guò)它可以查看系統(tǒng)中usb的設(shè)備信息,包括拓?fù)洳鹉凇挶⒃O(shè)備描述符、產(chǎn)品ID矛纹、配置描述符臂聋、接口描述符、端點(diǎn)描述符等。usbfs還允許用戶(hù)空間的程序直接訪(fǎng)問(wèn)usb設(shè)備孩等,這使得容易維護(hù)和調(diào)試艾君。
usbfs也至此各種ioctl的調(diào)用。有了這些ioctl我們就可以編寫(xiě)用戶(hù)空間的usb驅(qū)動(dòng)程序肄方,而libusb做的工作就是把這些ioctl開(kāi)發(fā)成一個(gè)庫(kù)冰垄。
3.libusb實(shí)現(xiàn)驅(qū)動(dòng)開(kāi)發(fā)
3.1libusb簡(jiǎn)介
libusb是一種高級(jí)別的API,它封裝了低級(jí)別的內(nèi)核與USB模塊的交互权她,并提供了一系列適合在用戶(hù)空間進(jìn)行usb驅(qū)動(dòng)開(kāi)發(fā)的函數(shù)虹茶。libusb基于usb文件系統(tǒng)提供的usb接口,端點(diǎn)等信息隅要,與usb設(shè)備進(jìn)行通信蝴罪。顯然,只要開(kāi)發(fā)平臺(tái)上的內(nèi)核支持usb文件系統(tǒng)步清,我們就可以利用libusb進(jìn)行usb驅(qū)動(dòng)開(kāi)發(fā)要门。
libusb可以跨平臺(tái)實(shí)現(xiàn),開(kāi)發(fā)的程序很容易在不同操作系統(tǒng)上一直廓啊。對(duì)于Linux操作系統(tǒng)欢搜,也很容易在不同的CPU架構(gòu)間進(jìn)行移植,而且不低擔(dān)心內(nèi)核版本造成的種種問(wèn)題谴轮。相對(duì)于Linux內(nèi)核驅(qū)動(dòng)開(kāi)發(fā)炒瘟,libusb無(wú)疑是一種省時(shí)省力而又行之有效的開(kāi)發(fā)工具。
libusb定義了struct usb_bus第步,struct usb_device 和usb_xxx_descriptor來(lái)對(duì)usb總線(xiàn)唧领、設(shè)備、配置和端點(diǎn)等進(jìn)行描述雌续。
一般可通過(guò)libusb提供的一些初始化函數(shù)斩个,在usb文件系統(tǒng)中查找先關(guān)的總線(xiàn)和設(shè)備,并保存在幾個(gè)對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)中:
usb_init()函數(shù)檢查環(huán)境變量USB_DEVFS_PATH驯杜,目錄/dev/bus/usb或目錄/proc/bus/usb,若指定路徑下含有usb文件系統(tǒng)信息受啥,則將路徑保存在全局變量usb_path[PATH_MAX+1]中。
usb_find_busses()函數(shù)會(huì)根據(jù)usb_path[]找到系統(tǒng)中所有的usb bus,并組成鏈表鸽心,由全局結(jié)構(gòu)指針usb_busses指向滚局。
usb_find_devices()函數(shù)則遍歷usb_busses指向的鏈表,尋找所有bus上的所有usb設(shè)備顽频。每個(gè)bus上的所有devices列表由usb_bus結(jié)構(gòu)成員struct usb_device *devices指向藤肢。
我們可用兩層的for循環(huán),遍歷usb_busses指向的鏈表糯景,找到與指定描述符相符的usb_device嘁圈。如通常是通過(guò)IDVender和IDProduct查找省骂。
usb_dev_handle是一個(gè)十分重要的句柄結(jié)構(gòu),如果要對(duì)usb設(shè)備最住、接口钞澳、端點(diǎn)等操作,都離不開(kāi)它涨缚,結(jié)構(gòu)如下:
struct usb_dev_handle{
int fd;
struct usb_bus *bus;
struct usb_device *device;
int config;
int interface;
int altsetting;
void *impl_info;
1
2
3
4
5
6
7
8
域fd為文件描述符轧粟,與文件系統(tǒng)關(guān)聯(lián):域bus和device則指向要處理的usb設(shè)備。
開(kāi)發(fā)人員可以使用usb_open()脓魏,打開(kāi)指定的usb設(shè)備Dev兰吟,并返回相應(yīng)的句柄結(jié)構(gòu):
usb_dev_handle *dev_handle = usb_open(dev);
之后,dev_handle便貫穿于對(duì)應(yīng)usb設(shè)備的操作過(guò)程中茂翔,直至最后調(diào)用usb_close()關(guān)閉指定的usb設(shè)備混蔼,釋放該句柄。
開(kāi)放人員可使用usb_set_configuration()檩电,usb_setaltinterface()等函數(shù)對(duì)usb設(shè)備的配置,接口和端點(diǎn)等進(jìn)行設(shè)定府树。然后調(diào)用usb_control_msg()進(jìn)行控制傳輸俐末,或usb_bulk_write(),usb_bulk_read()進(jìn)行大批量的端點(diǎn)讀寫(xiě)奄侠。
3.2開(kāi)發(fā)實(shí)例
libusb要應(yīng)用到嵌入式系統(tǒng)中卓箫,需要交叉編譯;開(kāi)發(fā)代碼中要包含libusb的頭文件usb.h垄潮,并在編譯時(shí)烹卒,要是用-I和-L選項(xiàng)指定libusb的頭文件和庫(kù)文件的路徑,和-lusb指定libusb.a靜態(tài)庫(kù)文件弯洗。
下面的偽代碼在系統(tǒng)中按廠(chǎng)商號(hào)和產(chǎn)品號(hào)找到usb圖像采集設(shè)備并讀bulk端點(diǎn)到緩沖中旅急,
int main(void)
{
? ? //...一些初始化工作
? ? dev_usbdev_probe();//找到usb設(shè)備
? ? dev_hanle = usb_open(dev); //打開(kāi)設(shè)備
? ? //發(fā)送控制信息,請(qǐng)求傳輸
? ? usb_control_msg(dev_handle,0x40,0xb5,2,0,buffer,sizeof(buffer),1000);
? ? if(dev_handle){
? ? //若請(qǐng)求成功牡整,從端點(diǎn)6傳輸數(shù)據(jù)到image_buffer中
? ? ? ? usb_bulk_read(dev_handle,6,&image_buffer[64],64,1000);
? ? }
}
1
2
3
4
5
6
7
8
9
10
11
12
4.總結(jié)
本文實(shí)現(xiàn)基礎(chǔ)是usbfs允許用戶(hù)空間的程序直接訪(fǎng)問(wèn)usb設(shè)備藐吮,這使得許多內(nèi)核驅(qū)動(dòng)程序可以遷移到用戶(hù)空間,通過(guò)libusb庫(kù)提供的API函數(shù)實(shí)現(xiàn)嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)的方法逃贝,使得開(kāi)發(fā)人員無(wú)需被底層的usb協(xié)議所困谣辞,無(wú)需區(qū)分不同版本內(nèi)核驅(qū)動(dòng)開(kāi)發(fā),從而使得usb的驅(qū)動(dòng)開(kāi)發(fā)更容易維護(hù)和調(diào)試沐扳,從而可以提高開(kāi)發(fā)效率并縮短開(kāi)發(fā)周期泥从。