libusb開發者指南

Wang Hsiao Ch`en發表於2020-10-10

本文件描述libusb的API,以及如何開發USB應用。
1 介紹
1.1 概覽
本文件描述libusb-0.1的API和USB相關內容。
1.2 當前OS支援
Linux 2.2或以上
FreeBSD/NetBSD/OpenBSD
Darwin/MacOSX
2 API
2.1 裝置與介面
一個裝置可能有多個介面,所以一個控制程式碼可以返回多個介面例項。不要忘記呼叫 usb_claim_interface() 。
2.2 超時
總是以毫秒為單位。
2.3 資料型別
同時使用有抽象結構和非抽象結構來保持可移植性。
2.4 同步
所有libusb v0.1的函式都是同步的,這意味著操作完成或超時前不會返回。非同步操作從libusb v1.0開始支援。
2.5 返回值
libusb v0.1有兩種返回值。一種是 usb_open() 返回的控制程式碼,另一種是整數int,返回負數表示錯誤。
3 函式
3.1 核心函式
void usb_init(void);
初始化libusb。
int usb_find_busses(void);
查詢所有匯流排,返回上次呼叫以後改變的數量(包括新增的和移除的匯流排)。
int usb_find_devices(void);
尋找每個匯流排上的所有裝置。應該在 usb_find_busses() 之後呼叫。返回上次呼叫後改變的數量(包括新增和移除的裝置)。
struct usb_bus *usb_get_busses(void);
簡單的返回全域性變數 usb_busses 。這僅對支援C呼叫規範和可以使用共享庫的語言,但是不支援C全域性變數的(例如Delphi)。
3.2 裝置操作
這組函式用於操作裝置。允許你開啟關閉裝置,設定配置、輪換設定、乾淨的關閉和重置裝置。它也提供OS級別的操作,如認領(claim)和釋放接 口。
usb_dev_handle *usb_open(struct *usb_device dev);
開啟裝置以供使用,返回裝置控制程式碼。
int usb_close(usb_dev_handle *dev);
關閉裝置,返回0成功,負數失敗。
int usb_set_configuration(usb_dev_handle *dev, int configuration);
設定活躍配置。configuration引數是描述符bConfigurationValue欄位的值。返回0成功,負數失敗。
int usb_set_altinterface(usb_dev_handle *dev, int alternate);
設定當前介面的活躍輪換設定。alternate引數是描述符bAlternateSetting欄位的值。返回0成功,負數失敗。
int usb_resetep(usb_dev_handle *dev, unsigned int ep);
重置指定端點的所有狀態。ep引數是描述符的bEndpointAddress欄位的值。返回0稱公,負數失敗。
該介面不建議使用,你可能需要的是 usb_clear_halt() 。
int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
清理端點所有停止狀態,ep是描述符bEndpointAddress欄位的值。返回0成功,負數失敗。
int usb_reset(usb_dev_handle *dev);
重置指定裝置,通過傳送RESET指令過去。返回0成功,負數失敗。
在執行該函式之後,需要重新列舉,找到裝置。當前的控制程式碼無法再工作了。
int usb_claim_interface(usb_dev_handle *dev, int interface);
通過OS認領一個介面。interface引數是描述符的bInterfaceNumber欄位。返回0成功,負數失敗。
必須在任何介面相關操作(如 usb_set_altinterface() 、 usb_bulk_write() 等)之前呼叫。
返回碼:
EBUSY :介面無效,無法被認領
ENOMEM :記憶體不足
int usb_release_interface(usb_dev_handle *dev, int interface);
釋放之前認領的介面。interface引數是描述符的bInterfaceNumber欄位。返回0成功,負數失敗。
3.3 控制傳輸
傳送訊息到預設控制管道。
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
傳送控制請求到裝置的預設控制管道。引數對應USB規範中的同名型別。返回讀寫位元組數,負數失敗。
int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, size_t buflen);
獲取裝置的字串描述,通過index和langdi索引。返回Unicode字串到buf中。返回實際寫入buf的位元組數,負數失敗。
int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen);
包裝了 usb_get_string() 函式,返回第一種語言指定index索引的字串描述,並轉換到C風格的ASCII。返回寫入buf位元組數,負數失敗。
int usb_get_descriptor(usb_dev_handle *dev, unsigned char type, unsigned char index, void *buf, int size);
獲取裝置預設控制管道的描述符,通過type和index索引。返回實際寫入buf的位元組數,負數失敗。
參考 usb_get_descriptor_by_endpoint() 瞭解允許指定控制端點的。
int usb_get_descriptor_by_endpoint(usb_dev_handle *dev, int ep, unsigned char type, unsigned char index, void *buf, int size);
從裝置獲取描述符,以type和index索引,以ep標誌的控制管道。返回讀取位元組數,負數失敗。
3.4 塊傳輸
這部分允許應用從資料塊管道傳送和接收資料。
int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
寫入一塊資料到端點ep,返回寫入成功位元組數,負數失敗。
int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
讀取一塊資料,從端點ep,返回讀取成功位元組數,負數失敗。
3.5 中斷傳輸
這組函式允許應用傳送和接收資料通過中斷管道。
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
執行對端點ep的中斷寫入,返回實際寫入位元組數,負數失敗。
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout);
執行對中斷端點ep的讀取,返回實際讀取位元組數,負數失敗。
3.6 不可移植
這些函式是不可移植的。有些是暴露了OS USB API之類的。他們都回加上函式名字尾 np 。
一個C前處理器巨集會定義實現的函式。形式是 LIBUSB_HAS
加上函式名,沒有 usb_ 字首。例如, usb_get_driver_np() 實現了,就會定義 LIBUSB_HAS_GET_DRIVER_NP 。
int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name, int namelen);
這個函式獲取介面驅動的名字。成功返回0,失敗負數。
只在Linux有實現。
int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);
這個函式從介面剝離核心驅動。使用了libusb的應用可以隨即重新認領介面。返回0成功,負數失敗。
只在Linux有實現。
4 例子
4.1 簡單例子
與裝置通訊前要先找到它。需要先找到所有匯流排(busses),然後找到所有裝置:
struct usb_bus *busses;
usb_init();
usb_find_busses();
usb_find_devices();
busses=usb_get_busses();
在這之後,應用應該手動輪詢所有匯流排和裝置,匹配其所要的:
struct usb_bus *bus;
int c,i,a;
for (bus=busses; bus; bus=bus->next) {
struct usb_device *dev;
for (dev=bus->devices; dev; dev=dev->next) {
if (dev->descriptor.bDeviceClass7) {
/開啟裝置,認領介面,然後操作/
}
/迴圈遍歷所有配置/
for (c=0; c< dev->descriptor.bNumConfigurations; c++) {
/迴圈遍歷所有介面/
for (i=0; i< dev->config[c].bNumInterfaces; i++) {
/迴圈遍歷所有輪換設定/
for (a=0; a< dev->config[c].interface[i].num_altsetting; a++) {
/檢查介面是否是印表機/
if (dev->config[c].interface[i].altsetting[a].bInterfaceClass
7) {
/開啟裝置,設定輪換配置,認領介面,然後操作/
}
}
}
}
}
}
4.2 原始碼包的例子
tests目錄有個程式叫 testlibusb.c 。它簡單的呼叫libusb尋找所有裝置,然後遍歷並列印描述符。其結果很簡單,不過用處有限。倒是可以作為很好的入門。
新增連結描述

相關文章