2019-10-18 16:20:07 HeroGuo_JP 阅读数 138

libusb linux 无法打开设备

问题:

在使用Qt或者其他开发工具,开发Linux端的程序时。遇到 libusb 在linux下无法正常打开,需要 root 权限才可以打开,而普通权限能调用库,但是无法打开设备进行通讯。

解决方案

需要在 Linux的系统下的 /etc/udev/rules.d 系统文件下,创建 .rules 文件。文件内容如下:

 # Put this file in /etc/udev/rules.d/ 
 # idVendor VID ,MODE 读写权限
SUBSYSTEM=="usb", ATTRS{idVendor}=="4745", MODE="0666"
SUBSYSTEM=="usb_device", ATTRS{idVendor}=="4745", MODE="0666"

2018-10-07 20:18:44 u012247418 阅读数 11170

libusb学习笔记

ubuntu版本:ubuntu-gnome-16.04-desktop-amd64,gnome版
libusb版本 :2016-10-01: v1.0.21
作者:wang baoli
E-mail: baoliw@foxmail.com

libusb学习网站:

website:http://libusb.info/
API:http://libusb.sourceforge.net/api-1.0/
download:https://github.com/libusb/libusb
mailing list:http://mailing-list.libusb.info
libusb test demo:https://github.com/crazybaoli/libusb-test

1. 编译及安装

下载libusb源码,进入目录,shell下依次执行下列命令。

1.1 执行:./configure

提示:configure: error: “udev support requested but libudev not installed”
解决:

sudo apt-get install libudev-dev

1.2 执行:make

提示:‘aclocal-1.14’ is missing on your system.
解决:

  1. sudo apt-get install automake
  2. sudo apt-get install libtool
  3. sudo autoreconf -ivf
  4. make

1.3 安装:make install

执行:sudo make install
libusb-1.0.a 和 libusb-1.0.so 被安装到 /usr/local/lib/ 目录
libusb.h 被安装到 /usr/local/include/libusb-1.0/ 目录

注:在这以后可以直接执行:./configure && make && make install

2. 源码学习

libusb采用的linux技术:sysfs、libudev、netlink、pipe、thread、hotplug

2.1 目录分析

tests/

关于libusb的四个压力测试,不涉USB打开操作及具体的数据传输。

android/

用于生成Android版本的libusb库、test和examples。进入android/jni/,执行ndk_build即可。在android/README中有以下描述:

  1. Download the latest NDK from: http://developer.android.com/tools/sdk/ndk/index.html
  2. Extract the NDK.
  3. Open a shell and make sure there exist an NDK global variable, set to the directory where you extracted the NDK.
  4. Change directory to libusb’s “android/jni”
  5. Run “ndk-build”.
  6. The libusb library, examples and tests can then be found in:“android/libs/$ARCH”

doc/

用于生成软件接口文档。编译完工程后,打开doc/doxygen.cfg,将PROJECT_LOGO = libusb.png修改为PROJECT_LOGO = ,否则产生文档时会提示 libusb.png不存在,修改完成后在doc/目录下执行:doxygen doxygen.cfg即可生成html格式文档,或者执行make docs。
注:Ubuntu需要提前安装doxygen。

libusb/

libusb的核心代码。
1)os/目录是是平台相关的代码,支持:darwin、haiku、linux、windows、sunos、netbsd、openbsd等七种平台,即Linux, OS X, Windows, Windows CE, Android, OpenBSD/NetBSD, Haiku。
2)libusb-1.0.def DLL中导出函数的声明的一种方式:采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。
3)libusb-1.0.rc 用于windows,产生 .res文件。

msvc/

微软VC编译环境,目录下均是windows平台环境相关文件。

m4/

linux编译相关。m4 是一种宏处理器,它扫描用户输入的文本并将其输出,期间如果遇到宏就将其展开后输出。

Xcode/

apple平台相关文件。Xcode是苹果的集成开发环境(IDE),开发者可用其构建适用于苹果iPad、iPhone以及Mac设备的应用程序。在应用程序的创建、测试、优化以及提交至App Store的过程中,Xcode为开发者提供了用以管理整个开发工作流的工具。

examples/

libusb的测试demo,进入目录后执行make即可生成可执行文件进行测试。

1)getopt/

getopt现在已经是C函数库的一部分,没有编译使用,删除此目录不会有影响。

2)hotplugtest.c

热插拔测试demo

3)listdevs.c

获取系统当前的usb设备列表,并打印出VID、PID、bus和device编号

4)testlibusb.c

打印usb设备列表的详细信息:包括设备描述符、配置、接口、端点描述符

5)dpfp.c

一款指纹识别器的应用程序:URU4000B fingerprint scanner 应用程序,将采集到的指纹图像保存为文件。系统采用异步传输的方式,使用了control、interrupt、bulk三种传输方式。不仅使用了libusb_control_transfer等同步接口传输,也使用了libusb_submit_transfer的异步传输方式。

6)dpfp_threaded.c

与dpfp.c功能一致,代码也大部分相同,唯一不同在于dpfp.c将libusb_handle_events 放在 main loop中,而dpfp_threaded.c 将libusb_handle_events 放在一个线程当中。

7)sam3u_benchmark.c

Atmel SAM3U isochronous(等时传输)性能测试。程序不断接收来自SAM3U iso端点的数据,当按下CTRL-C时,计算花费时间和传输的总数据量。

8)xusb.c

一个综合的USB测试程序,包括:HID设备(xbox、PS3和Joystick)、Mass Storage,涉及中断、批量和控制传输。其中Mass Storage可以使用普通的U盘进行测试,只需修改VID和PID即可,可以实现的功能有:读取描述符、查询U盘信息、读取U盘容量、读取U盘数据(因为没有使用文件系统,读取出来的数据是原始二进制数据)。
关于Mass Storage中涉及的SCSI命令,参考: USB Mass Stroage - SCSI指令格式详解。

9)fxload.c和ezusb.c

EZ-USB的固件下载程序,可实现下载固件(image)到Cypress EZ-USB microcontrollers,ezusb系列芯片使用端点0和厂商特定命令将数据写到片上SRAM,并且也支持写数据到CPUCS register或者eeprom。
程序使用控制传输方式进行指令和数据的传输,libusb_control_transfer()的形参bmRequestType使用LIBUSB_REQUEST_TYPE_VENDOR(厂商自定义请求)。程序支持五种下载类型(Target type): an21, fx, fx2, fx2lp, fx3,支持四种固件(image)类型:“Intel HEX”, “Cypress 8051 IIC”, “Cypress 8051 BIX”, “Cypress IMG format”。

10)other

ChangeLog:代码修改日志。2008-05-25: v0.9.0 release,目前最新版2016-10-01: v1.0.21
INSTALL:编译、安装方法。编译器选项,如: ./configure CC=c99 CFLAGS=-g LIBS=-lposix
PORTING:移植libusb到其他未支持平台的方法。

注:

  1. Atmel SAM3U:基于ARM Cortex M3内核的MCU,支持usb high speed。
  2. 关于ezusb的介绍:
    http://www.linux-usb.org/ezusb/
    http://www.cypress.com/
    EZ-USB FX是CYPRESS公司出品的一种带有USB功能的8051兼容系列,封装采用PQFP。这一系列芯片的最大不同之处在于使用不同的方式存储固件,EZ-USB FX可以在一个串行EEPROM中存储固件,也可以在主机上存储固件。当设备连接主机后,这些固件通过USB总线传输到芯片中。这样做最大的好处就是固件容易升级,不需要替换芯片或使用特殊的程序,只要在主机上更新固件即可。
    CY7C61083A是一款FX2LP芯片,支持full/high speed,应用:MP3、读卡器、照相机等等

2.2 权限问题

当open USB时需要提供root权限,这同打开串口一样,对底层硬件操作都需要root权限。

2.3 函数调用图

如果能绘制出函数调用关系图会更有利于分析代码。可以采用callfraph,但有些具有特殊返回值的函数不能被识别,并且不能跨文件寻找调用关系(可能是我没有正确的使用)。可以直接采用dot语言手动绘图。

2.4 log

2.4.1 修改log输出

libusb 日志默认输出到stderr,如果我们想输出libusb 的log至syslog,有以下两种方法:
方法1:./configure --enable-system-log
修改结果会反馈在./config.h中,增加了USE_SYSTEM_LOGGING_FACILITY宏
查看syslog:cat /var/log/syslog

Nov 22 09:51:07 ubuntu libusb-test: libusb: error [_get_usbfs_fd] libusb couldn’t open USB device /dev/bus/usb/002/018: Permission denied.

方法2:./configure CFLAGS=-DUSE_SYSTEM_LOGGING_FACILITY=1
或者:CFLAGS=-DUSE_SYSTEM_LOGGING_FACILITY=1 ./configure
修改结果反馈在./Makefile文件中,使CFLAGS = -DUSE_SYSTEM_LOGGING_FACILITY=1,这会覆盖原来的cflags 。
当然,也可在执行./configure后,直接修改Makefile中的cflags选项。
推荐采用方法1.
注:可以使用 ./configur --help 来获取–enable-system-log类似的选项

2.4.2 设置debug level

using libusb_set_debug() or the LIBUSB_DEBUG environment variable

除了可以使用libusb_set_debug()函数,也可以通过环境变量LIBUSB_DEBUG 来设置debug level。

2.5 open

USB设备文件对应路径为:“/dev/bus/usb/xxx/xxx”,使用了udev文件系统。
libusb通过打开设备文件:/dev/bus/usb/bus编号/device地址 来打开USB,stm32 USB device 对应/dev/bus/usb/002/020。可以使用lsusb来查看bus和device地址。
libusb优先使用udev文件系统打开usb设备,其次选择usbfs文件系统:/proc/bus/usb/来打开usb设备。Linux2.6采用了usbfs文件系统:/proc/bus/usb,在Ubuntu16.4上没有usbfs。
分析代码可知:

static const char *find_usbfs_path(void)
{
	const char *path = "/dev/bus/usb";
	const char *ret = NULL;

	if (check_usb_vfs(path)) {
		ret = path;
	} else {
		path = "/proc/bus/usb";
		if (check_usb_vfs(path))
			ret = path;
	}

	/* look for /dev/usbdev*.* if the normal places fail */
	if (ret == NULL) {
		struct dirent *entry;
		DIR *dir;

		path = "/dev";
		dir = opendir(path);
		if (dir != NULL) {
			while ((entry = readdir(dir)) != NULL) {
				if (_is_usbdev_entry(entry, NULL, NULL)) {
					/* found one; that's enough */
					ret = path;
					usbdev_names = 1;
					break;
				}
			}
			closedir(dir);
		}
	}


#if defined(USE_UDEV)
	if (ret == NULL)
		ret = "/dev/bus/usb";
#endif

	if (ret != NULL)
		usbi_dbg("found usbfs at %s", ret);

	return ret;
}

stm32设备在linux sysfs文件系统的路径: /sys/bus/usb/devices/2-2.1,由内核向用户空间导出设备的数据结构及属性,可以修改和访问。libusb中有大量通过sysfs来获得usb设备属性的用法,如获取usb 速度:
speed = (DEVICE_CTX(dev), sysfs_dir, "speed");
我们也可以使用 cat /sys/bus/usb/devices/2-2.1/speed 来获取usb速度。
由于目录/sys/bus/usb/devices/经常被使用,在libusb源码中有以下宏定义:
#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices"

2.6 结构体乱序初始化

linux结构体可以采用乱序初始化,即用成员变量前加(.)符号,如定义linux_usbfs_backend 结构体变量时就采用了这种方法:

const struct usbi_os_backend linux_usbfs_backend = {
	.name = "Linux usbfs",
	.caps = 
	.init = op_init,
	.exit = op_exit,
	.get_device_list = NULL,
  .....
}

乱序初始化是C99标准新加的,比较直观的一种初始化方式。相比顺序初始化而言,乱序初始化就如其名,成员可以不按照顺序初始化,而且可以只初始化部分成员,扩展性较好。linux内核中采用这种方式初始化struct。

2.7 数据传输

libusb的数据传输通过向内核提交URB来实现:
ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
而非使用read、write等读写函数。

2.8 hotplug

libusb的热插拔事件有两种:arrived 、left。
hotplug事件的底层支持机制:udev或者netlink,udev的热插拔机制是基于netlink实现。
libusb对于产生的热插拔消息在handle_events()中进行处理,然后调用用户注册的回调函数。
libusb内部专门开辟了一个线程来监听是否有USB设备插拔,并通过netlink或是udev两种方式来实现监听hotplug。优先采取udev方式,当系统不支持udev时,便采用netlink方式。其实udev的热插拔机制也是基于netlink实现。
实现原理:
当libusb在热插拔监听线程(linux_udev_event_thread_main or linux_netlink_event_thread_main)中接收到内核的hotplug消息,libusb首先将消息添加到ctx->hotplug_msgs中,然后在通过管道(ctx->event_pipe)将hotplug事件发送出去。在用户创建的monitor线程里,调用libusb_handle_events()进行事件处理,具体做法是调用poll监听管道,一旦ctx->event_pipe[0]可读,便读取hotplug_msgs,经过usbi_hotplug_match_cb()函数判断VID、PID以及device class符合后再调用用户的回调函数。
注:同一个进程中也可以使用管道进行通信。

2.9 LIST

libusb实现了循环双向链表,并且只有前向和后向指针,无数据成员,实现方法上也很独特。应用时作为其它数据结构的成员,可通过list_entry宏来获得这个数据结构指针。

struct list_head {
	struct list_head *prev, *next;
};

void list_init(struct list_head *entry)
初始化一个链表

void list_add_tail(struct list_head *entry, struct list_head *head)
list_add_tail和list_add都是形成双向循环链表,只是实现上有一点不同而已。
将节点entry添加到链表head的尾部,使head->prev指向entry,(head->next固定指向了链表中的第二个节点)

void list_add(struct list_head *entry, struct list_head *head)
将节点entry添加到链表head的尾部,使head->next指向entry,(head->prev固定指向了链表中的第二个节点)

void list_del(struct list_head *entry)
删除一个链表

list_empty(entry)
判断链表是否为空

list_entry(ptr, type, member)
取得包含ptr所指结构体的对象的指针:返回type类型指针,这个type类型指针指向的对象包含这个节点。

ptr:list_head 结构体指针
type:包含member成员的数据类型
member:type数据类型里的成员,member为list_head类型

list_for_each_entry(pos, head, member, type)
遍历head链表中的每个节点(entry),pos指向每次遍历的结果。pos为type类型结构体指针,这个结构体包含list_head 结构体成员。

pos:一个包含member成员的结构体指针
head:list head
member:pos指针指向的结构体里的list_head 结构体成员
type:pos的数据类型

2.10 获取USB设备列表

用户使用ssize_t libusb_get_device_list(libusb_context *ctx, libusb_device ***list)函数即可获得系统当前所有的USB设备。
libusb将接入的usb设备都保存在ctx->usb_devs链表中,libusb_get_device_list函数便是通过它来取得设备列表。
libusb通过三种途径来维护ctx->usb_devs链表(这里主要指添加设备)。

  1. 调用libusb_init初始化时,libusb调用linux_scan_devices获取系统当前所有usb设备,并将其添加到ctx->usb_devs链表。
  2. 在hotplug监听线程中,如果有设备插入,便将其添加到ctx->usb_devs链表。
  3. 用户调用libusb_get_device_list时,再一次查看是否有新设备插入,如果有便将其添加到ctx->usb_devs链表。

2.11 控制传输

用户可以使用libusb_control_transfer() 进行控制传输。
控制传输既可以在系统枚举阶段进行,也可以在打开USB设备后进行传输,如在xusb.c中便有很多地方用到了控制传输:获取HID设备的报告描述符等。

2.12 头文件说明

(1)宏定义_MSC_VER

_MSC_VER是微软的预编译控制,由于vc++不支持stdbool.h,所以有某些头文件有以下代码以便支持bool变量。

#if !defined(_MSC_VER)
#include <stdbool.h>
#else
#define __attribute__(x)
#if !defined(bool)
#define bool int
#endif
#if !defined(true)
#define true (1 == 1)
#endif
#if !defined(false)
#define false (!true)
#endif
#if defined(_PREFAST_)
#pragma warning(disable:28193)
#endif
#endif

(2) C++支持

为了在C++代码支持libusb库,在头文件中可见以下代码:

#ifdef  __cplusplus
extern "C" {
#endif

// 代码

#ifdef  __cplusplus
}
#endif

(3)条件编译的使用

#if, #elif, #else, #endif
#if defined()和#if !defined()

2.13 其它

宏定义_WIN32

VC 有 3 个预处理常量,分别是 _WIN32、_WIN64、WIN32,WIN32和_WIN32 可以用来判断是否 Windows 系统(对于跨平台程序),而 _WIN64 用来判断编译环境是 x86 还是 x64。

3. libusb测试demo

github:https://github.com/crazybaoli/libusb-test

  • 支持bulk/interrupt endpoint 数据读写
  • 支持hotplug
  • 支持命令行参数
  • 支持快捷发送数据
  • 支持将收到的数据保存为文件
  • 支持lsusb功能,可列出系统所有usb设备
  • 支持打印显示特定usb设备(VID:PID)的描述符
2019-01-15 16:01:55 jiguangfan 阅读数 2132

Linux下libusb开发遇到如下问题

在Linux下用libusb进行usb设备打开时遇到“LIBUSB_ERROR_ACCESS  libusb_open函数返回值为-3”

此问题原因为该用户没有权限!

解决方法

第一步:执行以下命令

sudo chmod -R 777 /dev/bus/usb/

重新运行测试程序,若还报错,执行第二步

第二步:永久修改 USB 设备权限

1)使用lsusb命令找出 USB 设备的 vendorID 和 productID

2)创建一个新的udev规则

sudo vim /etc/udev/rules.d/90-myusb.rules

#在文件中添加下面的话
#用你自己的"idVendor"和"idProduct"来替换默认值。MODE="0666"表示USB设备的权限。

SUBSYSTEMS=="usb", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", GROUP="users", MODE="0666"

GROUP代表用户组,要确保此时登录的系统用户在该用户组中

可用 "usermod -a -G username groupname" 将用户添加到用户组中

3)重启电脑或重新加载 udev 规则

sudo udevadm control --reload

重新运行测试程序,若还报错,执行第三步 

第三步:su 切换到root用户下运行测试程序

 

参考链接

https://bbs.csdn.net/topics/390001023

https://blog.csdn.net/linux_shuai/article/details/51406896

https://github.com/smartdevicelink/sdl_core/issues/35

https://blog.csdn.net/chasonyang/article/details/45194135

2019-04-18 16:02:19 sinat_22338935 阅读数 232

一、准备
1、使用交叉编译器 arm-2014.05
2、下载libusb的压缩包libusb-1.0.21.tar.bz2
评论留下邮箱发给你。

二、安装(在linux终端下输入命令):
1、解压:tar -xvf libusb-1.0.21.tar.bz2
2、进入目录cd libusb-1.0.21,生成待安装的目录mkdir install(交叉编译好的库文件将放在此目录下)
3、配置安装选项: ./configure --host=arm-linux --prefix=/home/topeet/Desktop/libusb-1.0.21/install --disable-udev CC=/usr/local/arm/arm-2014.05/bin/arm-linux-gcc CXX=/usr/local/arm/arm-2014.05/bin/arm-linux-g++
其中:–host=arm-linux表示该软件编译完成后在arm平台上运行,–prefix后面为软件安装目录 --disable表示禁用功能,CC=表示指定gcc交叉编译器,CXX=表示指定g++交叉编译器。
4、编译libusb源代码:make
5、生成libusb库文件:make install
这样一个交叉编译好的库文件就生成在install目录下了。

2016-12-01 15:29:00 xfc_1939 阅读数 7939

linux交叉编译libusb的方法

  1. #### 下载libusb
    下载网址:http://sourceforge.net/projects/libusb/files/
  2. #### 交叉编译libusb ####
    • 将下载好的libusb压缩包解压后进入该文件
    • 执行下列指令
      ./configure --build=i686-linux --host=arm-linux --prefix=/home/xfc/usb/install CC=/mnt/CodeSourcery/Sourcery_CodeBench_Lite_for_Xilinx_GNU_Linux/bin/arm-xilinx-linux-gnueabi-gcc CXX=/mnt/CodeSourcery/Sourcery_CodeBench_Lite_for_Xilinx_GNU_Linux/bin/arm-xilinx-linux-gnueabi-g++
    • 执行上述指令后报如下错误
      configure:error:“udev support requested but libudev not installed”
      解决方法:在上述编译命令后面添加 --disable -udev
    • 然后执行make&&make install
    • 执行完make install后我们可以在prefix指定的目录中看到编译好的库及相应的头文件。在arm平台下使用的库文件名称是:libusb-1.0.so.0.1.0。
    • –build=i686-linux表示该软件在x86平台被编译
    • –host=arm-linux表示该软件编译完成后在arm平台上运行
    • –prefix后面为软件安装目录。
    • CC=,CXX等于指定了交叉编译使用的C,C++交叉编译器
  3. #### 交叉编译测试程序 ####
    • 交叉编译命令
      LIBUSB=/home/xfc/usb/install
      arm-xilinx-linux-gnueabi-gcc -o test -I${LIBUSB}/include/libusb-1.0 -L${LIBUSB}/lib/ -lusb-1.0 test.c
  4. #### 在ZYNQ端执行交叉编译好的程序 ####
    • 需要将之前交叉编译好的动态库拷贝到ZYNQ端linux下的/lib文件夹。注意拷贝的库文件名为:libusb-1.0.so.0.1.0。拷贝到/lib下之后需要重命名为libusb-1.0.so.0。

http://www.lai18.com/content/9413461.html
http://blog.csdn.net/wujiangguizhen/article/details/23128489

libusb移植到ARM linux

阅读数 1214

没有更多推荐了,返回首页