一、libusb简介
libusb库提供的api接口供应用层调用,可以对系统中的usb设备操作,如reset一个usb设备,或者获取其具体信息,如configuration、interface及settings等。libusb遵循posix协议,可以跨平台使用,Linux下默认预装libusb1.0版本,开发者可以直接使用,只是在编译时需要链接lib库。
二、libusb的api介绍
1. libusb_init和libusb_exit及struct libusb_context
代码中调用libusb接口函数需要先建立上下文环境,其中结构体struct libusb_context代表一段libusb的会话,官方文档中有对这个结构的说明[libusb]。libusb_init()表示开启会话,libusb_exit()表示结束会话。通俗的理解就是struct libusb_context* ctx中的ctx代表一把钥匙,libusb_init(&ctx)表示开启,libusb_exit(null)表示锁上。
2. libusb中几个重要的数据结构体和接口函数
libusb_device **list;这个结构体用来列举当前系统中的usb设备。
libusb_device_handle * handle;这个结构体是用来处理具体list中的usb设备的。
上面两个结构体的使用方式:
ssize_t num_devs = libusb_get_device_list(ctx, &list);根据ctx获取系统中的usb设备,返回设备个数,list指向链表头。
libusb_device *dev = list[i];
libusb_open(dev,&handle);
获取第i个设备并使用handle进行处理。
struct libusb_device_descriptor desc; usb设备描述结构体。
struct libusb_config_descriptor conf; usb设备配置描述结构体。
libusb_get_device_descriptor(dev, &desc);获取usb设备描述。
libusb_get_config_descriptor(dev, j, &conf); 获取usb设备配置描述。
uint8_t bnum = libusb_get_bus_number(dev); 获取usb设备总线号。
uint8_t dnum = libusb_get_device_address(dev); 获取usb设备端口号。比方3-1.1。
除上述一些接口外还有其它一些接口函数,具体用法可以到官网上查询。
三、 使用libusb获取当前usb设备的具体信息。
#include<stdio.h>
#include<libusb.h>
//#include <libusb-1.0/libusb.h>
#include<sys/types.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int get_configuration(libusb_device* dev, struct libusb_config_descriptor *config)
{
int ret = 0;
ret = libusb_get_config_descriptor(dev, 0, &config);
return ret;
}
static void dump_altsetting(libusb_device_handle *dev, const struct libusb_interface_descriptor *interface)
{
// char cls[128], subcls[128], proto[128];
// char *ifstr;
// get_class_string(cls, sizeof(cls), interface->bInterfaceClass);
// get_subclass_string(subcls, sizeof(subcls), interface->bInterfaceClass, interface->bInterfaceSubClass);
// get_protocol_string(proto, sizeof(proto), interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bInterfaceProtocol);
// ifstr = get_dev_string(dev, interface->iInterface);
printf(" Interface Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bInterfaceNumber %5u\n"
" bAlternateSetting %5u\n"
" bNumEndpoints %5u\n"
" bInterfaceClass %5u\n"
" bInterfaceSubClass %5u\n"
" bInterfaceProtocol %5u\n",
interface->bLength, interface->bDescriptorType, interface->bInterfaceNumber,
interface->bAlternateSetting, interface->bNumEndpoints, interface->bInterfaceClass,
interface->bInterfaceSubClass,interface->bInterfaceProtocol);
// free(ifstr);
}
static void dump_interface(libusb_device_handle *dev, const struct libusb_interface *interface)
{
int i;
for (i = 0; i < interface->num_altsetting; i++)
dump_altsetting(dev, &interface->altsetting[i]);
}
static int list_devices(libusb_context *ctx)
{
libusb_device **list;
struct libusb_device_descriptor desc;
struct libusb_config_descriptor* conf;
libusb_device_handle * handle = NULL;
int config= 0;
int ret;
int status;
ssize_t num_devs, i, j, k;
status = 1; /* 1 device not found, 0 device found */
num_devs = libusb_get_device_list(ctx, &list);
if (num_devs < 0)
goto error;
for (i = 0; i < num_devs; ++i) {
libusb_device *dev = list[i];
libusb_open(dev,&handle);
libusb_get_configuration(handle,&config);
uint8_t bnum = libusb_get_bus_number(dev);
uint8_t dnum = libusb_get_device_address(dev);
libusb_get_device_descriptor(dev, &desc);
status = 0;
printf("device:%04x:%04x\n",desc.idVendor,desc.idProduct);
printf("bDeviceSubClass = %5u\n",desc.bDeviceSubClass);
printf("bDeviceClass = %5u\n",desc.bDeviceClass);
printf("bDeviceProtocol = %5u\n",desc.bDeviceProtocol);
for( j = 0; j < desc.bNumConfigurations; ++j) {
ret = libusb_get_config_descriptor(dev, j, &conf);
if (ret) {
fprintf(stderr, "Couldn't get configuration "
"descriptor %lu, some information will "
"be missing\n", j);
} else {
printf("bNumberInterfaces = %5u\n",conf->bNumInterfaces);
printf("bConfigurationValue = %5u\n",conf->bConfigurationValue);
for (k = 0 ; k < conf->bNumInterfaces ; k++)
dump_interface(handle, &conf->interface[k]);
libusb_free_config_descriptor(conf);
}
}
}
libusb_free_device_list(list, 0);
error:
return status;
}
int main(int argc, char* args[])
{
int err = 0;
libusb_context *ctx;
err = libusb_init(&ctx);
if (err) {
fprintf(stderr, "unable to initialize libusb: %i\n", err);
return EXIT_FAILURE;
}
list_devices(ctx);
return 0;
}
Makefile
header_src=/usr/include/libusb-1.0
lsusb : lsusb.c
gcc lsusb.c -o lsusb -lusb-1.0 -I$(header_src)
clean:
rm ./lsusb
四、使用libusb重置usb设备
#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
struct libusb_device_handle *devh;
struct libusb_device *dev;
struct libusb_device **devs;
struct libusb_context *ctx;
void resetUSB() {
int success;
int bpoint = 0;
do {
success = libusb_reset_device(devh);
++bpoint;
if (bpoint > 3) {
success = 1;
}
} while (success < 0);
if (success) {
printf("\nreset usb device failed:%d\n", success);
} else {
printf("\nreset usb device ok\n");
}
}
struct libusb_device* search_device(int _busNum, int _devNum) {
libusb_device *l_dev;
int i = 0;
int l_busNum, l_devNum;
while ((l_dev = devs[i++]) != NULL) {
printf("check against %d device\n", i);
l_busNum =(int) libusb_get_bus_number(l_dev);
l_devNum =(int) libusb_get_device_address(l_dev);
printf("bus number: %d; device number: %d\n", l_busNum, l_devNum);
if ((l_busNum == _busNum) && (l_devNum == _devNum)) {
printf("found device\n");
return l_dev;
}
}
return NULL;
}
int main(int argc, char **argv) {
//parse the input parameters to get the bus number and device number
int l_busNum, l_devNum;
int l_ret;
if (argc < 3) {
printf("not enough arguments!\n");
printf("usage: ./usbreset <bus number> <dev number>\n");
return 0;
}
printf("bus number: %s\n", argv[1]);
printf("dev number: %s\n", argv[2]);
l_busNum = atoi(argv[1]);
l_devNum = atoi(argv[2]);
printf("bus number: %d; dev number: %d\n", l_busNum, l_devNum);
l_ret = libusb_init(&ctx);
if (l_ret ) {
fprintf(stderr, "unable to initialize libusb: %i\n", err);
return EXIT_FAILURE;
l_ret = libusb_get_device_list(NULL, &devs);
if (l_ret < 0) {
return (int) l_ret;
}
dev = search_device(l_busNum, l_devNum);
if (dev == NULL) {
printf("device not found\n");
return 0;
}
l_ret = libusb_open(dev, &devh);
if (l_ret == 0) {
printf("got the usb handle successfully.\n");
} else {
printf("error getting usb handle.\n");
}
//reset the usb device
resetUSB();
//free the device list
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return 0;
}
五、总结。
libusb是一个应用层处理usb设备的很好的借口代码,相对于udev来说,libusb更加接近usb驱动,能够从系统级别操作或取得usb的信息。