libusb移植与v4l2使用--Applecai的学习笔记
前言
之前把家里的库存小模块都玩了一遍,这些主要是配在单片机玩的,但是我放到linux上,目的就是学习linux自己写驱动。至于usb等驱动包括v4l2内核配置下就有了。然后网上找的简单的框架API调用下,家里的usb camera就用起来了。2年前我就已经玩过v4l2了,arm-VS2017 opencv远程人脸识别--APPLE的学习笔记,至于libusb我去移植它还是第一次,我想后面做些usb相关的应用,所以看了下libusb是常用库,所以就交叉编译移植下。代码已上传我的gitee,15_usbdev工程。
问题
包括交叉编译问题的临时解决,及测试代码编译后segment fault的调试解决
(如下6个步骤不要参考,参考正确的libusb交叉编译步骤)
一,libusb交叉编译
1.交叉编译先./autogen.sh。
2.配置
./configure --build=i686-linux --host=arm-linux --prefix=/home/applecai/tools/install CC=/home/applecai/bbb/ti-processor-sdk-linux-am335x-evm-06.01.00.08/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-gcc CXX=/home/applecai/bbb/ti-processor-sdk-linux-am335x-evm-06.01.00.08/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-g++
结果报错
- 打开config.log查看是-V的问题,改成-v。
- 又报错4447,就是如下2句,我就删除了。
/LT_INIT/
/LT_LANG(Windows Resource)/ - 又报错error: cannot find input file: `Makefile.in',按网上搜索的结果
就在configure 之前执行如下命令
aclocal
libtoolize --force
automake --add-missing
autoconf
autoheader
make clean - 重新再运行步骤2的配置命令,成功生成makefile
- make
- make install
然后拿libusb中的example code来使用,功能就是遍历usb设备。
静态编译由于缺少udev库报错。于是动态编译,如下命令是错误的,-fPIC -shared是编译so动态库的。但是我一开始没反应过来
arm-linux-gnueabihf-gcc -g -fPIC -shared usbtest.c -o usbtest -I/home/applecai/tools/install/include/libusb-1.0/ -L/home/applecai/tools/install/lib/ -lusb-1.0
直接运行编译后的代码则segment fault
通过开发板上gdb调试,由于当前是buildroot uclib编译的,我之前的gdb是用的自己通过busybox glib编译的,所以换了挂载的文件系统,然后里面有我之前准备的gdb bin文件。gdb运行后提示缺少python。查看报错是有个路径也要copy gdb文件夹。copy完成后gdb正常运行。发现原因是0x00000000 in ?? ()
[ 15.766487] random: gdb: uninitialized urandom read (24 bytes read)
GNU gdb (GDB) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./usbtest...done.
(gdb) b main
Breakpoint 1 at 0x8dc: file usbtest.c, line 39.
(gdb) r
Starting program: /usr/study/usbtest
Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
(gdb)
这时候反应到我添加了-fPIC -shared,重新改成动态编译,依然报错,缺少udev。网上搜索了下libusb默认找设备是从udev,可以通过配置--disable udev来禁止调用udev相关函数。所以我重新编译libusb,结果同样的命令再运行一次,configure无法通过。于是重新unzip libusb,本次编译就非常顺利。之前可能是一开始编译不正确,后来没有用make clean。所以如下才是正确的
正确的libusb交叉编译步骤
- ./autogen.sh
- ./configure --build=i686-linux --host=arm-linux --prefix=/home/applecai/tools/install CC=/home/applecai/bbb/ti-processor-sdk-linux-am335x-evm-06.01.00.08/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-gcc CXX=/home/applecai/bbb/ti-processor-sdk-linux-am335x-evm-06.01.00.08/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-g++ --disable-udev --enable-system-log
- make
- make install
然后对c文件进行编译,链接动态库的方式。
arm-linux-gnueabihf-gcc usbtest.c -o usbtest -I/home/applecai/tools/install/include/libusb-1.0/ -L/home/applecai/tools/install/lib/ -lusb-1.0 -lpthread
API调用及功能测试通过
一开始插入usb camera后,libusb扫描到2个设备,拔走camera后,libusb扫描到一个usb设备。至于camg里面是调用了v4l2的API显示camera基本信息的。至于camg就是用-static静态编译的,这是很顺利的。
Please press Enter to activate this console.
[root@apple335 ]# cd /usr/study/
[root@apple335 study]# [ 20.194856] usb 1-1: new high-speed USB device number 2 using musb-hdrc
[ 20.387122] usb 1-1: New USB device found, idVendor=1871, idProduct=0142, bcdDevice= 0.0c
[ 20.395387] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 20.402561] usb 1-1: Product: USB2.0 Camera
[ 20.406793] usb 1-1: Manufacturer: AVEO Technology Corp.
[ 20.414666] uvcvideo: Found UVC 1.00 device USB2.0 Camera (1871:0142)
[ 20.423928] uvcvideo 1-1:1.0: Entity type for entity Extension 4 was not initialized!
[ 20.431894] uvcvideo 1-1:1.0: Entity type for entity Processing 3 was not initialized!
[ 20.439886] uvcvideo 1-1:1.0: Entity type for entity Camera 1 was not initialized!
[ 20.448030] input: USB2.0 Camera: USB2.0 Camera as /devices/platform/ocp/47400000.usb/47401c00.usb/musb-hdrc.1/usb1/1-1/1-1:1.0/input/input0
[root@apple335 study]# cd /usr/study/
[root@apple335 study]# ls
camg core t usbtest
[root@apple335 study]# ./usbtest
Hello, world!1
121871:0142 (bus 1, device 2) path: 1
1d6b:0002 (bus 1, device 1)
[root@apple335 study]# ./camg
init camera
driver: uvcvideo
card: USB2.0 Camera: USB2.0 Camera
bus_info: usb-musb-hdrc.1-1
version: 328765
capabilities: 84a00001
Device supports capture.
Device supports streaming.
Support format:
1.YUYV 4:2:2
support format RGB32
set fmt...
fmt.type: 1
pix.pixelformat: RGB4
pix.height: 480
pix.width: 640
pix.field: 4
get fmt...
fmt.type: 1
pix.pixelformat: YUYV
pix.height: 480
pix.width: 640
pix.field: 1
numerator:1
denominator:30
[root@apple335 study]# [ 59.204985] usb 1-1: USB disconnect, device number 2
[root@apple335 study]# ./usbtest
Hello, world!1
121d6b:0002 (bus 1, device 1)
小插曲
我把挂载文件系统环境又换成在buildroot用uclib编译的,结果
./usbtest
-sh: ./usbtest: not found
我猜测是缺少库文件。因为之前我自己编译的busybox文件系统环境中很多库我我从ti包中copy的。查看需要的库。
root@applecaiHP:/home/applecai/mydriver/usbdev# arm-linux-gnueabihf-objdump -x usbtest |grep NEEDED
NEEDED libusb-1.0.so.0
NEEDED libpthread.so.0
NEEDED libc.so.6
root@applecaiHP:/home/applecai/mydriver/usbdev#
uClibc是独立的,为了应用于嵌入式系统中,完全重新实现出来的。和glibc在源码结构和二进制上,都不兼容。我直接copy了libpthread和libc,依然无法解决。由于buildroot之前用uclib编译的,若改用glibc非常花费时间,而当前文件系统已经不是我的重点,所以我准备将文件系统环境切换到之前用glibc编译的busybox最下文件系统下,而且,库文件可以用ti制作的库直接替换了。或者之后再尝试用uclib来编译libusb,就怕编译不过。
今天继续尝试用buildroot自带的编译器uclib进行交叉编译,结果还是很顺利的。并且添加了支持打印debug信息。APP代码动态编译不行,缺少glibc库支持,改成静态编译通过,验证通过。
我的原始解压路径在/home/applecai/sftp/libusb-1.0.23里面是用uclib编译的。libusb-1.0.23_gclib文件夹是昨天用arm-linux-gnueabihf工具链编译的。
uclib交叉编译步骤
1. ./autogen.sh
2. ./configure -help
查看到需要输出debug log应该要添加--enable-debug-log
3. ./configure --build=i686-linux --host=arm-linux --prefix=/home/applecai/tools/install2 CC=/home/applecai/studybr/buildroot-2020.05.2/output/host/bin/arm-linux-gcc CXX=/home/applecai/studybr/buildroot-2020.05.2/output/host/bin/arm-linux-cc --disable-udev --enable-debug-log
4. make
5. make install
6. 编译应用代码--静态
/home/applecai/mydriver/usbdev# /home/applecai/studybr/buildroot-2020.05.2/output/host/bin/arm-linux-gcc usbtest.c -static -o usbtest2 -I/home/applecai/tools/install/include/libusb-1.0/ -L. libusb-1.0.a
**备注:由于我没有交叉编译过udev,所以--disable-udev必须添加,否则./configure就有如下错误**
checking for libudev.h... no
configure: error: udev support requested but libudev header not installed
带调试信息输出如下
验证成功,中间出入usb camera后又运行一次程序。
Welcome to Buildroot
buildroot login: root
# cd /usr/study/
# ./usbtest2
Hello, world!1
[timestamp] [threadID] facility level [function call] <message>
--------------------------------------------------------------------------------
[ 0.000615] [0000006f] libusb: debug [libusb_init] created default context
[ 0.001613] [0000006f] libusb: debug [libusb_init] libusb v1.0.23.11397
[ 0.001914] [0000006f] libusb: debug [find_usbfs_path] found usbfs at /dev/bus/usb
[ 0.002001] [0000006f] libusb: debug [get_kernel_version] reported kernel version is 5.4.61
[ 0.002042] [0000006f] libusb: debug [op_init] bulk continuation flag supported
[ 0.002076] [0000006f] libusb: debug [op_init] zero length packet flag supported
[ 0.002111] [0000006f] libusb: debug [op_init] max iso packet length is (likely) 49152 bytes
[ 0.002275] [0000006f] libusb: debug [op_init] sysfs can relate devices
[ 0.002317] [0000006f] libusb: debug [op_init] sysfs has complete descriptors
[ 0.002950] [0000006f] libusb: debug [linux_get_device_address] getting address for device: usb1 detached: 0
[ 0.003025] [0000006f] libusb: debug [linux_get_device_address] scan usb1
[ 0.003669] [0000006f] libusb: debug [linux_get_device_address] bus=1 dev=1
[ 0.003729] [0000006f] libusb: debug [linux_enumerate_device] busnum 1 devaddr 1 session_id 257
[ 0.003773] [0000006f] libusb: debug [linux_enumerate_device] allocating new device for 1/1 (session 257)
[ 0.004219] [0000006f] libusb: debug [usbi_add_pollfd] add fd 6 events 1
[ 0.004321] [0000006f] libusb: debug [usbi_io_init] using timerfd for timeouts
[ 0.004362] [0000006f] libusb: debug [usbi_add_pollfd] add fd 8 events 1
[ 0.004405] [0000006f] libusb: debug [libusb_get_device_list]
[ 0.004471] [0000006f] libusb: debug [libusb_get_device_descriptor]
121d6b:0002 (bus 1, device 1)
[ 0.004544] [0000006f] libusb: debug [libusb_exit]
[ 0.004578] [0000006f] libusb: debug [libusb_exit] destroying default context
[ 0.004618] [0000006f] libusb: debug [libusb_handle_events_timeout_completed] doing our own event handling
[ 0.004656] [0000006f] libusb: debug [handle_events] poll fds modified, reallocating
[ 0.004710] [0000006f] libusb: debug [handle_events] poll() 2 fds with timeout in 0ms
[ 0.004764] [0000006f] libusb: debug [handle_events] poll() returned 0
[ 0.004805] [0000006f] libusb: debug [libusb_unref_device] destroy device 1.1
[ 0.004848] [0000006f] libusb: debug [usbi_remove_pollfd] remove fd 6
[ 0.004962] [0000006f] libusb: debug [usbi_remove_pollfd] remove fd 8
[ 0.005142] [00000070] libusb: debug [linux_netlink_event_thread_main] netlink event thread entering
[ 0.005221] [00000070] libusb: debug [linux_netlink_event_thread_main] netlink event thread exiting
# [ 105.435041] usb 1-1: new high-speed USB device number 2 using musb-hdrc
[ 105.627306] usb 1-1: New USB device found, idVendor=1871, idProduct=0142, bcdDevice= 0.0c
[ 105.635593] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 105.642767] usb 1-1: Product: USB2.0 Camera
[ 105.647022] usb 1-1: Manufacturer: AVEO Technology Corp.
[ 105.655825] uvcvideo: Found UVC 1.00 device USB2.0 Camera (1871:0142)
[ 105.665118] uvcvideo 1-1:1.0: Entity type for entity Extension 4 was not initialized!
[ 105.673009] uvcvideo 1-1:1.0: Entity type for entity Processing 3 was not initialized!
[ 105.681016] uvcvideo 1-1:1.0: Entity type for entity Camera 1 was not initialized!
[ 105.690063] input: USB2.0 Camera: USB2.0 Camera as /devices/platform/ocp/47400000.usb/47401c00.usb/musb-hdrc.1/usb1/1-1/1-1:1.0/input/input0
# ./usbtest2
Hello, world!1
[timestamp] [threadID] facility level [function call] <message>
--------------------------------------------------------------------------------
[ 0.000027] [00000071] libusb: debug [libusb_init] created default context
[ 0.000120] [00000071] libusb: debug [libusb_init] libusb v1.0.23.11397
[ 0.000361] [00000071] libusb: debug [find_usbfs_path] found usbfs at /dev/bus/usb
[ 0.000445] [00000071] libusb: debug [get_kernel_version] reported kernel version is 5.4.61
[ 0.000486] [00000071] libusb: debug [op_init] bulk continuation flag supported
[ 0.000519] [00000071] libusb: debug [op_init] zero length packet flag supported
[ 0.000552] [00000071] libusb: debug [op_init] max iso packet length is (likely) 49152 bytes
[ 0.000645] [00000071] libusb: debug [op_init] sysfs can relate devices
[ 0.000685] [00000071] libusb: debug [op_init] sysfs has complete descriptors
[ 0.001355] [00000071] libusb: debug [linux_get_device_address] getting address for device: usb1 detached: 0
[ 0.001430] [00000071] libusb: debug [linux_get_device_address] scan usb1
[ 0.001907] [00000071] libusb: debug [linux_get_device_address] bus=1 dev=1
[ 0.001960] [00000071] libusb: debug [linux_enumerate_device] busnum 1 devaddr 1 session_id 257
[ 0.002004] [00000071] libusb: debug [linux_enumerate_device] allocating new device for 1/1 (session 257)
[ 0.002330] [00000071] libusb: debug [linux_get_device_address] getting address for device: 1-1 detached: 0
[ 0.002380] [00000071] libusb: debug [linux_get_device_address] scan 1-1
[ 0.002825] [00000071] libusb: debug [linux_get_device_address] bus=1 dev=2
[ 0.002876] [00000071] libusb: debug [linux_enumerate_device] busnum 1 devaddr 2 session_id 258
[ 0.002919] [00000071] libusb: debug [linux_enumerate_device] allocating new device for 1/2 (session 258)
[ 0.003256] [00000071] libusb: debug [linux_get_parent_info] Dev 0x4f3a8 (1-1) has parent 0x4ef28 (usb1) port 1
[ 0.003382] [00000071] libusb: debug [usbi_add_pollfd] add fd 6 events 1
[ 0.003476] [00000071] libusb: debug [usbi_io_init] using timerfd for timeouts
[ 0.003517] [00000071] libusb: debug [usbi_add_pollfd] add fd 8 events 1
[ 0.003560] [00000071] libusb: debug [libusb_get_device_list]
[ 0.003625] [00000071] libusb: debug [libusb_get_device_descriptor]
121871:0142 (bus 1, device 2) path: 1
[ 0.003952] [00000071] libusb: debug [libusb_get_device_descriptor]
1d6b:0002 (bus 1, device 1)
[ 0.004023] [00000071] libusb: debug [libusb_exit]
[ 0.004057] [00000071] libusb: debug [libusb_exit] destroying default context
[ 0.004097] [00000071] libusb: debug [libusb_handle_events_timeout_completed] doing our own event handling
[ 0.004136] [00000071] libusb: debug [handle_events] poll fds modified, reallocating
[ 0.004199] [00000071] libusb: debug [handle_events] poll() 2 fds with timeout in 0ms
[ 0.004254] [00000071] libusb: debug [handle_events] poll() returned 0
[ 0.004296] [00000071] libusb: debug [libusb_unref_device] destroy device 1.2
[ 0.004338] [00000071] libusb: debug [libusb_unref_device] destroy device 1.1
[ 0.004376] [00000071] libusb: debug [usbi_remove_pollfd] remove fd 6
[ 0.004502] [00000071] libusb: debug [usbi_remove_pollfd] remove fd 8
[ 0.004662] [00000072] libusb: debug [linux_netlink_event_thread_main] netlink event thread entering
[ 0.004747] [00000072] libusb: debug [linux_netlink_event_thread_main] netlink event thread exiting
libusb源码阅读
昨天等于是试用,今天阅读了下源码,我的目的主要想通过源码阅读了解它和底层交互的API。
然后我从libusb_init还是阅读,发现了好多debug信息都很有用,只要答应出来就可以看到路径了,当然代码比较少分析起来比较简单,我就直接分析源码了,并且复习了下里面用到的函数sscanf,opendir和readlink函数及close-on-exec机制,多读读优秀的设计还是很有帮助的。结果发现它是用的udev相关函数find_usbfs_path对于设备文件操作获取usb配置描述信息的。然后它要进行控制传输,usb是通过ioctrl函数处理的。
所以我理解这都是APP使用的函数,那么我不用libusb其实也可以自己操控底层的,比如通过ioctrl函数,而检测usb也可以通过udev单独的库进行设备文件监控,然后udev在2013年就停止更新了。网上介绍用eudev库来处理热拔插设备。至于底层host的源码明天看,而且先要看help文档,这样我快速可以理解下哪些接口是开放给APP用的。
libusb源码阅读参考网址:https://blog.csdn.net/weixin_30466039/article/details/98294990
libusb官网我记得也有API描述的,我忘记看官网了,不过源码容易理解,暂时就不看官网了。今天的目标已达成,已经识别出了哪些是和usb host驱动交互的函数,有了思路。
小惊喜
之前在看linux内核的双链表,结果发现libusb中也是一样的,只是它封装的层次少。突然发现好用的代码设计,被使用的概率真大,我将来从空白开始设计代码看来也可以用这样的双链表使用思路了。画了一个add头插函数。因为它和我常用的从中间p插入s图解上直观看上去有点不同,因为它链成了一个圆圈。但是从方法论上是一样的。
image.png