通libusb我们可以在应用层对USB设备进行读写操作。本文以读取USB鼠标数据为例讲述libusb的使用流程。
通过源码安装libusb:
最新的版本为:libusb-1.0.24,GitHub上免费下载地址:
https://github.com/libusb/libusb/releases/tag/v1.0.24
ps: CSDN上很多人用这个公共的开源资源来赚积分,而且下载分还贼高,真不怎么地道。
解压源码:tar xjvf libusb-1.0.24.tar.bz2
在解压跟目录下输入命令:
./configure
注意:如果报以下错误
configure: error: udev support requested but libudev header not installed
不要慌,这是由于没安装libudev库,可以通过以下方式解决:
1、输入命令apt-get install libudev-dev安装libudev
2、运行configure脚本时输入:./configure --disable-udev(这种方法本人还没验证)
编译:make
安装:make install
默认安装在/usr/local/lib目录下
以上是源码编译安装流程,在线通过以下命令安装也很简单:
a、apt-get install libudev-dev
b、apt-get install libusb-dev
c、apt-get install libusb-1.0-0-dev
安装完libusb库后就可以开发应用层程序对USB设备进行读写操作了,下面是参考libusb例子中的testlibusb.c文件编写的鼠标数据读取程序test_rw.c:
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <getopt.h>
#include <ctype.h>
#include <signal.h>
#include "libusb.h"
int verbose = 1;
static volatile sig_atomic_t rcv_exit;
static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor *ep_comp)
{
printf(" USB 3.0 Endpoint Companion:\n");
printf(" bMaxBurst: %u\n", ep_comp->bMaxBurst);
printf(" bmAttributes: %02xh\n", ep_comp->bmAttributes);
printf(" wBytesPerInterval: %u\n", ep_comp->wBytesPerInterval);
}
static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
{
int i, ret;
printf(" Endpoint:\n");
printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
printf(" bmAttributes: %02xh\n", endpoint->bmAttributes);
printf(" wMaxPacketSize: %u\n", endpoint->wMaxPacketSize);
printf(" bInterval: %u\n", endpoint->bInterval);
printf(" bRefresh: %u\n", endpoint->bRefresh);
printf(" bSynchAddress: %u\n", endpoint->bSynchAddress);
for (i = 0; i < endpoint->extra_length;) {
if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i + 1]) {
struct libusb_ss_endpoint_companion_descriptor *ep_comp;
ret = libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp);
if (LIBUSB_SUCCESS != ret)
continue;
print_endpoint_comp(ep_comp);
libusb_free_ss_endpoint_companion_descriptor(ep_comp);
}
i += endpoint->extra[i];
}
}
static void print_altsetting(const struct libusb_interface_descriptor *interface)
{
uint8_t i;
printf(" Interface:\n");
printf(" bInterfaceNumber: %u\n", interface->bInterfaceNumber);
printf(" bAlternateSetting: %u\n", interface->bAlternateSetting);
printf(" bNumEndpoints: %u\n", interface->bNumEndpoints);
printf(" bInterfaceClass: %u\n", interface->bInterfaceClass);
printf(" bInterfaceSubClass: %u\n", interface->bInterfaceSubClass);
printf(" bInterfaceProtocol: %u\n", interface->bInterfaceProtocol);
printf(" iInterface: %u\n", interface->iInterface);
for (i = 0; i < interface->bNumEndpoints; i++)
print_endpoint(&interface->endpoint[i]);
}
static void print_2_0_ext_cap(struct libusb_usb_2_0_extension_descriptor *usb_2_0_ext_cap)
{
printf(" USB 2.0 Extension Capabilities:\n");
printf(" bDevCapabilityType: %u\n", usb_2_0_ext_cap->bDevCapabilityType);
printf(" bmAttributes: %08xh\n", usb_2_0_ext_cap->bmAttributes);
}
static void print_ss_usb_cap(struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap)
{
printf(" USB 3.0 Capabilities:\n");
printf(" bDevCapabilityType: %u\n", ss_usb_cap->bDevCapabilityType);
printf(" bmAttributes: %02xh\n", ss_usb_cap->bmAttributes);
printf(" wSpeedSupported: %u\n", ss_usb_cap->wSpeedSupported);
printf(" bFunctionalitySupport: %u\n", ss_usb_cap->bFunctionalitySupport);
printf(" bU1devExitLat: %u\n", ss_usb_cap->bU1DevExitLat);
printf(" bU2devExitLat: %u\n", ss_usb_cap->bU2DevExitLat);
}
static void print_bos(libusb_device_handle *handle)
{
struct libusb_bos_descriptor *bos;
uint8_t i;
int ret;
ret = libusb_get_bos_descriptor(handle, &bos);
if (ret < 0)
return;
printf(" Binary Object Store (BOS):\n");
printf(" wTotalLength: %u\n", bos->wTotalLength);
printf(" bNumDeviceCaps: %u\n", bos->bNumDeviceCaps);
for (i = 0; i < bos->bNumDeviceCaps; i++) {
struct libusb_bos_dev_capability_descriptor *dev_cap = bos->dev_capability[i];
if (dev_cap->bDevCapabilityType == LIBUSB_BT_USB_2_0_EXTENSION) {
struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension;
ret = libusb_get_usb_2_0_extension_descriptor(NULL, dev_cap, &usb_2_0_extension);
if (ret < 0)
return;
print_2_0_ext_cap(usb_2_0_extension);
libusb_free_usb_2_0_extension_descriptor(usb_2_0_extension);
} else if (dev_cap->bDevCapabilityType == LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) {
struct libusb_ss_usb_device_capability_descriptor *ss_dev_cap;
ret = libusb_get_ss_usb_device_capability_descriptor(NULL, dev_cap, &ss_dev_cap);
if (ret < 0)
return;
print_ss_usb_cap(ss_dev_cap);
libusb_free_ss_usb_device_capability_descriptor(ss_dev_cap);
}
}
libusb_free_bos_descriptor(bos);
}
static void print_interface(const struct libusb_interface *interface)
{
int i;
for (i = 0; i < interface->num_altsetting; i++)
print_altsetting(&interface->altsetting[i]);
}
static void print_configuration(struct libusb_config_descriptor *config)
{
uint8_t i;
printf(" Configuration:\n");
printf(" wTotalLength: %u\n", config->wTotalLength);
printf(" bNumInterfaces: %u\n", config->bNumInterfaces);
printf(" bConfigurationValue: %u\n", config->bConfigurationValue);
printf(" iConfiguration: %u\n", config->iConfiguration);
printf(" bmAttributes: %02xh\n", config->bmAttributes);
printf(" MaxPower: %u\n", config->MaxPower);
for (i = 0; i < config->bNumInterfaces; i++)
print_interface(&config->interface[i]);
}
static void print_device(libusb_device *dev, libusb_device_handle *handle, uint16_t vid, uint16_t pid)
{
struct libusb_device_descriptor desc;
unsigned char string[256];
const char *speed;
int ret;
uint8_t i;
switch (libusb_get_device_speed(dev)) {
case LIBUSB_SPEED_LOW: speed = "1.5M"; break;
case LIBUSB_SPEED_FULL: speed = "12M"; break;
case LIBUSB_SPEED_HIGH: speed = "480M"; break;
case LIBUSB_SPEED_SUPER: speed = "5G"; break;
case LIBUSB_SPEED_SUPER_PLUS: speed = "10G"; break;
default: speed = "Unknown";
}
ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0) {
fprintf(stderr, "failed to get device descriptor");
return;
}
if (!handle)
libusb_open(dev, &handle);
if((desc.idVendor == vid) && (desc.idProduct == pid))
{
printf("Dev (bus %u, device %u): %04X - %04X speed: %s\n",
libusb_get_bus_number(dev), libusb_get_device_address(dev),
desc.idVendor, desc.idProduct, speed);
if (handle)
{
if (desc.iManufacturer) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
if (ret > 0)
printf(" Manufacturer: %s\n", (char *)string);
}
if (desc.iProduct) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
if (ret > 0)
printf(" Product: %s\n", (char *)string);
}
if (desc.iSerialNumber && verbose) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
if (ret > 0)
printf(" Serial Number: %s\n", (char *)string);
}
}
if (verbose) {
for (i = 0; i < desc.bNumConfigurations; i++) {
struct libusb_config_descriptor *config;
ret = libusb_get_config_descriptor(dev, i, &config);
if (LIBUSB_SUCCESS != ret) {
printf(" Couldn't retrieve descriptors\n");
continue;
}
print_configuration(config);
libusb_free_config_descriptor(config);
}
if (handle && desc.bcdUSB >= 0x0201)
print_bos(handle);
}
}
if(handle)
{
libusb_close(handle);
}
}
static int test_wrapped_device(const char *device_name, uint16_t vendor_id, uint16_t product_id)
{
libusb_device_handle *handle;
int r, fd;
fd = open(device_name, O_RDWR);
if (fd < 0) {
printf("Error could not open %s: %s\n", device_name, strerror(errno));
return 1;
}
r = libusb_wrap_sys_device(NULL, fd, &handle);
if (r) {
printf("Error wrapping device: %s: %s\n", device_name, libusb_strerror(r));
close(fd);
return 1;
}
print_device(libusb_get_device(handle), handle, vendor_id, product_id);
close(fd);
return 0;
}
static void sig_handler(int signum)
{
switch (signum) {
case SIGTERM:
rcv_exit = 1;
break;
case SIGINT:
rcv_exit = 1;
break;
case SIGUSR1:
break;
}
}
static void usage(char *program)
{
printf("%s - test usb data transfers to/from usb device\n",
program);
printf("Usage:\n");
printf(" %s [options]\n", program);
printf("options are:\n");
printf("Common:\n");
printf(" --help (or -h)\n");
printf(" -v vendor_id\n");
printf(" -p product_id\n");
printf(" -d device name\n");
}
static int interrupt_data_rw(uint16_t vendor_id, uint16_t product_id)
{
int kernelDriverDetached = 0;
unsigned char data_in[64]={0};
int length = 0;
int r,j;
libusb_device_handle *handle;
handle = libusb_open_device_with_vid_pid(NULL, vendor_id, product_id);
if (handle == NULL)
{
printf("libusb_open() failed\n");
return -1;;
}
/*驱动必须解绑定,否则数据由驱动程序处理*/ if(libusb_kernel_driver_active(handle, 0))
{
printf("Kernel Driver Active\n");
r = libusb_detach_kernel_driver(handle, 0);
if (r == 0)
{
printf("Detach Kernel Driver\n");
kernelDriverDetached = 1;
}
else
{
fprintf(stderr, "Error detaching kernel driver.\n");
return -1;;
}
}
/* 指定当前接口 */
r = libusb_claim_interface(handle, 0);
if (r != 0)
{
fprintf(stderr, "Error claiming interface.\n");
goto exit;
}
while(!rcv_exit)
{
memset(data_in, 0, sizeof(data_in));
/*中断方式读取断点数据,
由端点描述符可知端点地址 0x81 为鼠标输入端点
读取长度为5字节,超时时间为1000ms*/
r = libusb_interrupt_transfer(handle, 0x81, data_in, 5, &length, 1000);
if ((r < 0) || (length == 0))
{
printf("bulk recive error,r:%d length:%d\n",r,length);
}
else
{
printf("receive data:\n");
for(j=0; j<length; j++)
{
printf("0x%x ",data_in[j]);
}
printf("\n");
}
usleep(500000);
}
/* 释放指定的接口 */
r = libusb_release_interface(handle, 0);
if (0 != r)
{
fprintf(stderr, "Error releasing interface.\n");
}
exit:
if(kernelDriverDetached)
{
//恢复驱动绑定,否则鼠标不可用
libusb_attach_kernel_driver(handle, 0);
}
libusb_close(handle);
return r;
}
int main(int argc, char *argv[])
{
char *program = argv[0];
int option;
const char *device_name = NULL; //"/dev/bus/usb/001/005"
libusb_device **devs;
ssize_t cnt;
int r, i;
uint16_t vid=0, pid=0;
libusb_device_handle *handle = NULL;
static const struct option options[] = {
{ "vendid", required_argument, NULL, 'v' },
{ "productid", required_argument, NULL, 'p' },
{ "devicename", required_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
};
/* Parse command line options, if any */
while ((option = getopt_long_only(argc, argv,
"hv:p:d:",options, NULL)))
{
if (option == -1)
break;
switch (option) {
case 'v':
vid = strtoul(optarg, NULL, 0);
break;
case 'p':
pid = strtoul(optarg, NULL, 0);
break;
case 'd':
device_name = optarg;
break;
case 'h':
usage(program);
exit(EXIT_SUCCESS);
break;
default:
printf("ERROR: Invalid command line option\n");
usage(program);
exit(EXIT_FAILURE);
}
}
printf("vid:0x%x pid:0x%x devicename:%s\n",vid,pid,device_name);
r = libusb_init(NULL);
if (r < 0)
return r;
if (device_name) {
printf("test_wrapped_device\n");
r = test_wrapped_device(device_name,vid,pid);
} else {
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0) {
libusb_exit(NULL);
return 1;
}
for (i = 0; devs[i]; i++)
print_device(devs[i], handle,vid,pid);
libusb_free_device_list(devs, 1);
}
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
//read mouse data
interrupt_data_rw(vid,pid);
libusb_exit(NULL);
return r;
}
编译命令:
gcc -o test_rw test_rw.c -I/usr/local/include/libusb-1.0/ -I../ -lusb-1.0
lsusb查看鼠标设备信息如下:
根权限运行程序,读取鼠标信息:./testrw -v 0x046d -p 0xc045,读取过程需要移动鼠标,否则会提示读取失败。
版权归原作者 缥缈孤鸿_jason 所有, 如有侵权,请联系我们删除。