嵌入式Linux驅動程序開發(五)-基于libusb的USB驅動開發

姓名:薛紹宏? ? ?學號:19020100016? ? 學院:電子工程學院

轉自:https://blog.csdn.net/su1041168096/article/details/78989835?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162722361816780265466801%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162722361816780265466801&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-18-78989835.pc_search_result_control_group&utm_term=%E5%B5%8C%E5%85%A5%E5%BC%8Flinux%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91&spm=1018.2226.3001.4449

【嵌牛導讀】本文介紹了嵌入式Linux基于libusb的USB驅動開發

【嵌牛鼻子】嵌入式Linux驅動程序開發

【嵌牛提問】嵌入式Linux的USB驅動如何基于libusb進行開發?

【嵌牛正文】

由于usb設備的普遍性及其多樣性,大量的usb設備的驅動開發也就成為開發者做的最多的事情。Linux平臺上,內核驅動的開發由于內核的復雜和版本問題,初學者難以入手,驅動程序也不易升級和維護。本文主要介紹Linux平臺下使用libusb庫基于usb文件系統的驅動開發,并將其應用到嵌入式系統中,可顯著降低開發難度,提高工作效率

1.前言

Linux內核經過開發人員的不斷努力,已經變得十分地完善和強大。其中,設備驅動占據了內核的很大一部分,內核都能夠高效、穩定地驅動大部分設備。而另外一些設備,注入自己設計的硬件產品。這些驅動就需要驅動工程師開發出相關的內核設備驅動了。內核驅動有他的優點,然而在內核驅動開發過程中會遇到如下的一些問題:

對于不用的Linux內核版本,驅動程序也會有不同的版本。不利于升級和維護。

Linux自帶的驅動程序開發,需要對內核的重新編譯,而且開發出來的驅動模塊比較大。

所以,如果我們能夠找到一個為用戶空間提供與內核版本無關的通用接口的方法,就能夠不必重新改變編譯好的內核,也不必為內核版本兼容性問題而頭痛,只需在用戶空間開發程序。這樣就極大地提高了開發效率,縮短了開發周期。

USB協議是目前使用最廣泛的外部總線協議,Linux對usb控制器、usb核心和常用的usb設備驅動有了比較完善的支持。但由于usb所支持的設備的多樣性,一些特殊的usb設備的驅動還需要開發人員自行編寫。而libusb為開發人員提供了在用戶空間操作usb設備的API函數庫,使usb驅動開發變得極為方便。

2.實現原理

2.1USB簡介

usb(Universal Serial Bus)是用于將適用usb的外圍設備連接到主機的外部總線結構。目前usb接口規范主要有:USB1.1(低速1.5Mb/s,全速12Mb/s)和USB2.0(高速480Mb/s),能夠滿足大部分外圍設備的傳輸速度要求。usb同時又是一種通信協議,他支持主系統(host)和usb的外圍設備(device)之間的數據傳輸。當前流行的USB Host規范有:OHCI、UHCI和EHCI。嵌入式系統主要是使用OHCI規范。

usb驅動分為usb主機端驅動程序和usb設備端驅動程序,本文重點分析usb主機端驅動程序的開發過程。USB主機(host)驅動結構如圖:

開發人員主要關注usb設備驅動部分。usb設備的邏輯組織中,包含設備(device)、配置(config)、接口(interface)和端口(endpoint)四個層次:

每個usb設備可以有一個或多個配置,但一次只能選中其中一個。接口經捆綁為配置。接口代表了一個基本功能。

每個usb驅動程序控制一個接口,而一個接口有不同的設置(setting),但同一時間只能有一種活躍配置(cur_altsetting)。設備接口是端點的集合(collection),端點是usb通信的最基本形式。usb主機(host)通過端點與usb設備進行通信。

usb端點有以下四種傳輸方式:控制(Control),等待(iso)、中斷(interrupt)、批量(bulk)。控制和批量端點用于異步的少量數據傳輸,而批量和等時端點是周期性的。控制和中斷端點是用于少量數據傳輸,而批量和等時端點用于大量數據傳輸。

控制端點同城用于配置設備、獲取設備信息、發送命令到設備、或者獲取設備的狀態報告,“端點0”為默認的控制端點,usb核心使用該端點在設備插入時進行設備的配置。批量端點它要求數據傳輸的準確性,但不保證固定時間內的完成。中斷端點是例如usb鍵盤和鼠標所使用的的主要傳輸方式。libusb主要提供控制、批量和中斷的傳輸方式的API函數。

2.2usb文件系統(usbfs)

Linux內核提供了usb文件系統,他需要編寫內核時選中相關編譯選項。并在系統啟動運行時動態掛載。可在/etc/fstab文件中添加如下一行:

nonc /proc/bus/usb usbfs defaults 0 0

或者輸入命令:

mount -t usbfs none /proc/bus/usb

usbfs動態跟蹤總線上插入和移除的設備,通過它可以查看系統中usb的設備信息,包括拓撲、帶寬、設備描述符、產品ID、配置描述符、接口描述符、端點描述符等。usbfs還允許用戶空間的程序直接訪問usb設備,這使得容易維護和調試。

usbfs也至此各種ioctl的調用。有了這些ioctl我們就可以編寫用戶空間的usb驅動程序,而libusb做的工作就是把這些ioctl開發成一個庫。

3.libusb實現驅動開發

3.1libusb簡介

libusb是一種高級別的API,它封裝了低級別的內核與USB模塊的交互,并提供了一系列適合在用戶空間進行usb驅動開發的函數。libusb基于usb文件系統提供的usb接口,端點等信息,與usb設備進行通信。顯然,只要開發平臺上的內核支持usb文件系統,我們就可以利用libusb進行usb驅動開發。

libusb可以跨平臺實現,開發的程序很容易在不同操作系統上一直。對于Linux操作系統,也很容易在不同的CPU架構間進行移植,而且不低擔心內核版本造成的種種問題。相對于Linux內核驅動開發,libusb無疑是一種省時省力而又行之有效的開發工具。

libusb定義了struct usb_bus,struct usb_device 和usb_xxx_descriptor來對usb總線、設備、配置和端點等進行描述。

一般可通過libusb提供的一些初始化函數,在usb文件系統中查找先關的總線和設備,并保存在幾個對應的數據結構中:

usb_init()函數檢查環境變量USB_DEVFS_PATH,目錄/dev/bus/usb或目錄/proc/bus/usb,若指定路徑下含有usb文件系統信息,則將路徑保存在全局變量usb_path[PATH_MAX+1]中。

usb_find_busses()函數會根據usb_path[]找到系統中所有的usb bus,并組成鏈表,由全局結構指針usb_busses指向。

usb_find_devices()函數則遍歷usb_busses指向的鏈表,尋找所有bus上的所有usb設備。每個bus上的所有devices列表由usb_bus結構成員struct usb_device *devices指向。

我們可用兩層的for循環,遍歷usb_busses指向的鏈表,找到與指定描述符相符的usb_device。如通常是通過IDVender和IDProduct查找。

usb_dev_handle是一個十分重要的句柄結構,如果要對usb設備、接口、端點等操作,都離不開它,結構如下:

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為文件描述符,與文件系統關聯:域bus和device則指向要處理的usb設備。

開發人員可以使用usb_open(),打開指定的usb設備Dev,并返回相應的句柄結構:

usb_dev_handle *dev_handle = usb_open(dev);

之后,dev_handle便貫穿于對應usb設備的操作過程中,直至最后調用usb_close()關閉指定的usb設備,釋放該句柄。

開放人員可使用usb_set_configuration(),usb_setaltinterface()等函數對usb設備的配置,接口和端點等進行設定。然后調用usb_control_msg()進行控制傳輸,或usb_bulk_write(),usb_bulk_read()進行大批量的端點讀寫。

3.2開發實例

libusb要應用到嵌入式系統中,需要交叉編譯;開發代碼中要包含libusb的頭文件usb.h,并在編譯時,要是用-I和-L選項指定libusb的頭文件和庫文件的路徑,和-lusb指定libusb.a靜態庫文件。

下面的偽代碼在系統中按廠商號和產品號找到usb圖像采集設備并讀bulk端點到緩沖中,

int main(void)

{

? ? //...一些初始化工作

? ? dev_usbdev_probe();//找到usb設備

? ? dev_hanle = usb_open(dev); //打開設備

? ? //發送控制信息,請求傳輸

? ? usb_control_msg(dev_handle,0x40,0xb5,2,0,buffer,sizeof(buffer),1000);

? ? if(dev_handle){

? ? //若請求成功,從端點6傳輸數據到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.總結

本文實現基礎是usbfs允許用戶空間的程序直接訪問usb設備,這使得許多內核驅動程序可以遷移到用戶空間,通過libusb庫提供的API函數實現嵌入式Linux驅動開發的方法,使得開發人員無需被底層的usb協議所困,無需區分不同版本內核驅動開發,從而使得usb的驅動開發更容易維護和調試,從而可以提高開發效率并縮短開發周期。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容