listdevs 用于获取并显示系统当前的 USB 设备信息,包含:VID、PID、bus 编号、设备地址、端口号。
$ ./listdevs 1d6b:0002 (bus 1, device 1) 0e0f:0002 (bus 2, device 3) path: 2 0e0f:0003 (bus 2, device 2) path: 1 1d6b:0001 (bus 2, device 1)
int main(void) { libusb_device **devs; int r; ssize_t cnt; r = libusb_init(NULL); if (r < 0) return r; cnt = libusb_get_device_list(NULL, &devs); if (cnt < 0){ libusb_exit(NULL); return (int) cnt; } print_devs(devs); libusb_free_device_list(devs, 1); libusb_exit(NULL); return 0; }
main 函数很清晰简洁,这也说明 libusb 库的封装非常好。
骨架函数就三个:libusb_init() -> libusb_get_device_list() -> print_devs(),分别对应 libusb 初始化,获取 USB 设备列表,打印 USB 设备列表(信息)。
libusb 规定,在调用任何 libusb 功能函数之前都需要 libusb_init(),在分析 libusb_init() 之前先来看下 libusb_device{} 结构体:
struct libusb_device { /* lock protects refcnt, everything else is finalized at initialization * time */ usbi_mutex_t lock; int refcnt; struct libusb_context *ctx; struct libusb_device *parent_dev; uint8_t bus_number; uint8_t port_number; uint8_t device_address; enum libusb_speed speed; struct list_head list; unsigned long session_data; struct libusb_device_descriptor device_descriptor; int attached; }
libusb_device{} 描述一个 USB 设备的信息:
lock/refcnt:引用计数,一旦有其他地方引用到该设备,refcnt 值加一;避免设备在其他模块内部使用的情况下被销毁。自动指针、动态内存管理里面广泛使用引用计数。
libusb_context:该设备所属的上下文,官方术语叫“libusb session”。通过在 libusb_init() 时指定互相独立的“libusb session”,进而允许你的程序独立的使用 libusb,而不会因为其他地方调用 libusb_exit() 而销毁自己正在使用的资源。“libusb session”使用 session_id 唯一标识。
parent_dev:当前设备所属的父设备(通常指控制器/Hub)。
bus_number/port_number/device_address/speed:这些是 USB 规范及内核驱动里的概念,speed 标识设备速率(低速,全速,高速,超高速),device_address 标识内核驱动枚举时为设备分配的地址,port_number 标识设备占用的 Hub 端口号,bus_number 标识设备所属的总线编号。
list:每一个“libusb session”有个 usb_devs 链表,usb_devs 链表上保存属于该 session 的 USB 设备。在构件完成一个设备之后,就把它加入到自己所属的 usb_devs 链表上。
session_data:保存 session_id。
device_descriptor:顾名思义,该设备的设备描述符。
attached:标识设备状态是 attached(已连接上主机)还是 detached(未连接主机)。
接下来就看下 libusb_init() 做了哪些事情。
原文:https://www.cnblogs.com/rockyching2009/p/14174818.html