libusb移植與v4l2使用--Applecai的學(xué)習(xí)筆記

前言

之前把家里的庫存小模塊都玩了一遍,這些主要是配在單片機玩的,但是我放到linux上,目的就是學(xué)習(xí)linux自己寫驅(qū)動。至于usb等驅(qū)動包括v4l2內(nèi)核配置下就有了。然后網(wǎng)上找的簡單的框架API調(diào)用下,家里的usb camera就用起來了。2年前我就已經(jīng)玩過v4l2了,arm-VS2017 opencv遠程人臉識別--APPLE的學(xué)習(xí)筆記,至于libusb我去移植它還是第一次,我想后面做些usb相關(guān)的應(yīng)用,所以看了下libusb是常用庫,所以就交叉編譯移植下。代碼已上傳我的gitee,15_usbdev工程。

問題

包括交叉編譯問題的臨時解決,及測試代碼編譯后segment fault的調(diào)試解決
(如下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++
結(jié)果報錯

  1. 打開config.log查看是-V的問題,改成-v。
  2. 又報錯4447,就是如下2句,我就刪除了。
    /LT_INIT/
    /LT_LANG(Windows Resource)/
  3. 又報錯error: cannot find input file: `Makefile.in',按網(wǎng)上搜索的結(jié)果
    就在configure 之前執(zhí)行如下命令
    aclocal
    libtoolize --force
    automake --add-missing
    autoconf
    autoheader
    make clean
  4. 重新再運行步驟2的配置命令,成功生成makefile
  5. make
  6. make install
    然后拿libusb中的example code來使用,功能就是遍歷usb設(shè)備。
    靜態(tài)編譯由于缺少udev庫報錯。于是動態(tài)編譯,如下命令是錯誤的,-fPIC -shared是編譯so動態(tài)庫的。但是我一開始沒反應(yīng)過來
    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

通過開發(fā)板上gdb調(diào)試,由于當前是buildroot uclib編譯的,我之前的gdb是用的自己通過busybox glib編譯的,所以換了掛載的文件系統(tǒng),然后里面有我之前準備的gdb bin文件。gdb運行后提示缺少python。查看報錯是有個路徑也要copy gdb文件夾。copy完成后gdb正常運行。發(fā)現(xiàn)原因是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) 

這時候反應(yīng)到我添加了-fPIC -shared,重新改成動態(tài)編譯,依然報錯,缺少udev。網(wǎng)上搜索了下libusb默認找設(shè)備是從udev,可以通過配置--disable udev來禁止調(diào)用udev相關(guān)函數(shù)。所以我重新編譯libusb,結(jié)果同樣的命令再運行一次,configure無法通過。于是重新unzip libusb,本次編譯就非常順利。之前可能是一開始編譯不正確,后來沒有用make clean。所以如下才是正確的

正確的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++ --disable-udev --enable-system-log
  3. make
  4. make install
    然后對c文件進行編譯,鏈接動態(tài)庫的方式。
    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調(diào)用及功能測試通過

一開始插入usb camera后,libusb掃描到2個設(shè)備,拔走camera后,libusb掃描到一個usb設(shè)備。至于camg里面是調(diào)用了v4l2的API顯示camera基本信息的。至于camg就是用-static靜態(tài)編譯的,這是很順利的。

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)

小插曲

我把掛載文件系統(tǒng)環(huán)境又換成在buildroot用uclib編譯的,結(jié)果

./usbtest
-sh: ./usbtest: not found
我猜測是缺少庫文件。因為之前我自己編譯的busybox文件系統(tǒng)環(huán)境中很多庫我我從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是獨立的,為了應(yīng)用于嵌入式系統(tǒng)中,完全重新實現(xiàn)出來的。和glibc在源碼結(jié)構(gòu)和二進制上,都不兼容。我直接copy了libpthread和libc,依然無法解決。由于buildroot之前用uclib編譯的,若改用glibc非?;ㄙM時間,而當前文件系統(tǒng)已經(jīng)不是我的重點,所以我準備將文件系統(tǒng)環(huán)境切換到之前用glibc編譯的busybox最下文件系統(tǒng)下,而且,庫文件可以用ti制作的庫直接替換了。或者之后再嘗試用uclib來編譯libusb,就怕編譯不過。
今天繼續(xù)嘗試用buildroot自帶的編譯器uclib進行交叉編譯,結(jié)果還是很順利的。并且添加了支持打印debug信息。APP代碼動態(tài)編譯不行,缺少glibc庫支持,改成靜態(tài)編譯通過,驗證通過。
我的原始解壓路徑在/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應(yīng)該要添加--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. 編譯應(yīng)用代碼--靜態(tài)
/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

帶調(diào)試信息輸出如下
驗證成功,中間出入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還是閱讀,發(fā)現(xiàn)了好多debug信息都很有用,只要答應(yīng)出來就可以看到路徑了,當然代碼比較少分析起來比較簡單,我就直接分析源碼了,并且復(fù)習(xí)了下里面用到的函數(shù)sscanf,opendir和readlink函數(shù)及close-on-exec機制,多讀讀優(yōu)秀的設(shè)計還是很有幫助的。結(jié)果發(fā)現(xiàn)它是用的udev相關(guān)函數(shù)find_usbfs_path對于設(shè)備文件操作獲取usb配置描述信息的。然后它要進行控制傳輸,usb是通過ioctrl函數(shù)處理的。
所以我理解這都是APP使用的函數(shù),那么我不用libusb其實也可以自己操控底層的,比如通過ioctrl函數(shù),而檢測usb也可以通過udev單獨的庫進行設(shè)備文件監(jiān)控,然后udev在2013年就停止更新了。網(wǎng)上介紹用eudev庫來處理熱拔插設(shè)備。至于底層host的源碼明天看,而且先要看help文檔,這樣我快速可以理解下哪些接口是開放給APP用的。
libusb源碼閱讀參考網(wǎng)址:https://blog.csdn.net/weixin_30466039/article/details/98294990
libusb官網(wǎng)我記得也有API描述的,我忘記看官網(wǎng)了,不過源碼容易理解,暫時就不看官網(wǎng)了。今天的目標已達成,已經(jīng)識別出了哪些是和usb host驅(qū)動交互的函數(shù),有了思路。

小驚喜

之前在看linux內(nèi)核的雙鏈表,結(jié)果發(fā)現(xiàn)libusb中也是一樣的,只是它封裝的層次少。突然發(fā)現(xiàn)好用的代碼設(shè)計,被使用的概率真大,我將來從空白開始設(shè)計代碼看來也可以用這樣的雙鏈表使用思路了。畫了一個add頭插函數(shù)。因為它和我常用的從中間p插入s圖解上直觀看上去有點不同,因為它鏈成了一個圓圈。但是從方法論上是一樣的。


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容