擊左上方藍色“一口Linux”,選擇“設(shè)為星標”
第一時間看干貨文章 ?【干貨】嵌入式驅(qū)動工程師學(xué)習(xí)路線 ?【干貨】Linux嵌入式知識點-思維導(dǎo)圖-免費獲取 ?【就業(yè)】一個可以寫到簡歷的基于Linux物聯(lián)網(wǎng)綜合項目 ?【就業(yè)】簡歷模版

ADB 全稱為"Android Debug Bridge",Android 調(diào)試橋。在純 Linux 系統(tǒng)中也可以使用。它是 client-server 架構(gòu),由三部分組成:
adb push d:\1.txt /root時,它就是一個 adbclient,它通過 adbserver 把windows 下的文件 "d:\1.txt" 推送到開發(fā)板的 /root 目錄實際上,adbclient 和 adbserver 都是同一個應(yīng)用程序:比如 Windows 下的 adb.exe,使用不同的參數(shù)來啟動時就可以作為 adbclient 或者 adbserver。我們第 1 次執(zhí)行 adb 命令時,它會幫我們啟動一個 adb 程序作為 adbserver。
解壓 GIT 倉庫如下文件:

確認里面的 adb.exe 所在目錄,把這個目錄添加進 Windows 的 Path 環(huán)境變量里。
STM32MP157 的出廠系統(tǒng)已經(jīng)安裝好了 adbd,可以直接連接 USB 線進行測試。
比如在 Windows 上執(zhí)行命令:
adb devices # 列出adb設(shè)備
adb push d:\1.txt /root # 上傳文件到開發(fā)板/root目錄
adb shell # 啟動adb命令行
IMX6ULL 的出廠系統(tǒng)還沒安裝 adbd,等移植 ADB 時再進行實驗。
我們關(guān)注的是 Gadget 部分:
使用 legacy 的方法時,我們需要在驅(qū)動程序里指定設(shè)備信息(比如設(shè)備描述符、配置描述符等等),還需要在驅(qū)動程序里實現(xiàn)數(shù)據(jù)的傳輸功能,這都在驅(qū)動程序里限定死了。
使用 configfs 時,我們可以靈活地指定設(shè)備信息、靈活地選擇各種 function。但是,還不夠靈活:你必須選擇某個 function,這個 function 里已經(jīng)實現(xiàn)實現(xiàn)了數(shù)據(jù)的傳輸功能,你無法更改。
我們能否把 Gadget 設(shè)備的端點暴露給用戶程序?讓用戶程序自己操作端點來傳輸數(shù)據(jù)?可以!這就是 functionfs。
functionfs 是一種文件系統(tǒng),它的使用分為兩步:
抓住這兩點來分析代碼。
以 legacy 的方式來分析,只要安裝 g_ffs.ko 驅(qū)動程序:
insmod g_ffs.ko
就會觸發(fā)以下調(diào)用過程:
# drivers\usb\gadget\legacy\g_ffs.c
gfs_init
usb_get_function_instance("ffs");
try_get_usb_function_instance
fi = fd->alloc_inst();
# drivers\usb\gadget\function\f_fs.c
ffs_alloc_inst
dev = _ffs_alloc_dev();
ret = functionfs_init();
ret = register_filesystem(&ffs_fs_type);
使用 configfs 方式的話,需要執(zhí)行以下命令:
modprobe libcomposite
mount -t configfs none /sys/kernel/config
mkdir -p /sys/kernel/config/usb_gadget/g1
mkdir -p /sys/kernel/config/usb_gadget/g1/functions/ffs.adb
可以看到提示信息:

執(zhí)行命令cat /proc/filesystems可以看到 functionfs。
這時就可以掛載 functionfs 了,執(zhí)行如下命令:
# mkdir -p /dev/usb-ffs/adb
# mount -t functionfs adb /dev/usb-ffs/adb # 上面創(chuàng)建了 functions/ffs.adb, 掛載時 dev 就要指定為 adb
# ls /dev/usb-ffs/adb/
ep0
有了 ep0 端點后,用戶態(tài)程序就可以通過它跟主機通信了。
ep0 對應(yīng)的驅(qū)動程序,分析如下:


源碼:https://www.github.com/hadess/adbd
本文關(guān)注的不是 adb 本身的實現(xiàn),而是數(shù)據(jù)如何傳輸。
分析文件:adbd-master\adb\usb_linux_client.cpp

在接口描述符里,定義了多個接口描述符,這是 APP 提出的請求。如果 Gadget 設(shè)備有足夠的端點,那么就會在在 functionfs 跟目錄下創(chuàng)建出這些端點,比如 ep1、ep2。
ADB 程序的調(diào)用關(guān)系如下:
init_functionfs
// 設(shè)置功能描述符(接口描述符)
v2_descriptor.fs_count = 3;
v2_descriptor.hs_count = 3;
v2_descriptor.ss_count = 5;
v2_descriptor.os_count = 1;
v2_descriptor.fs_descs = fs_descriptors;
v2_descriptor.hs_descs = hs_descriptors;
v2_descriptor.ss_descs = ss_descriptors;
v2_descriptor.os_header = os_desc_header;
v2_descriptor.os_desc = os_desc_compat;
h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR); // 打開端點 0
// 把接口描述符發(fā)給驅(qū)動程序
ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor));
// 發(fā)送字符串描述符, 這會觸發(fā)驅(qū)動程序根據(jù)接口描述符創(chuàng)建更多的 endpoint
ret = adb_write(h->control, &strings, sizeof(strings));
上面的函數(shù)操作的都是 ep0,對應(yīng)的驅(qū)動程序如下:

函數(shù) ffs_epfiles_create 會根據(jù)接口描述符申請更多的 endpoint,并且在 functionfs 里創(chuàng)建對應(yīng)的節(jié)點:

如果不想自己編譯,可以使用 GIT 倉庫里的可執(zhí)行程序:

以 IMX6ULL 為例,打開《嵌入式 Linux 應(yīng)用開發(fā)完全手冊 V5_IMX6ULL_Pro開發(fā)板.pdf》,找到《6.5 構(gòu)建 IMX6ULL Pro 版的根文件系統(tǒng)》章節(jié),執(zhí)行以下命令:
make clean
make 100ask_imx6ull_pro_ddr512m_systemV_qt5_defconfig
make menuconfig
配置 ADB:-> Target packages -> System tools

然后執(zhí)行:
make android-tools-rebuild
期間會自動下載源碼、編譯。
成功后,可在如下目錄查看到可執(zhí)行程序 adb、adbd:
/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/target/usr/bin
把可執(zhí)行程序放到開發(fā)板的 /usr/bin 目錄。
IMX6ULL 上使用的簡化腳本:
modprobe libcomposite
mount -t configfs none /sys/kernel/config
mkdir -p /dev/usb-ffs/adb
mkdir -p /sys/kernel/config/usb_gadget/g1
mkdir -p /sys/kernel/config/usb_gadget/g1/functions/ffs.adb
mkdir -p /sys/kernel/config/usb_gadget/g1/configs/b.1
ln -s /sys/kernel/config/usb_gadget/g1/functions/ffs.adb /sys/kernel/config/usb_gadget/g1/configs/b.1
mount -t functionfs adb /dev/usb-ffs/adb
start-stop-daemon --start --oknodo --pidfile /var/run/adbd.pid --startas /usr/bin/adbd --background
sleep 1
echo ci_hdrc.0 > /sys/kernel/config/usb_gadget/g1/UDC
可以在 /etc/init.d/ 目錄下創(chuàng)建一個 S99adbd 文件,就可以自動使能 ADB 功能。這個文件在 GIT 倉庫里:

來自 STM32MP157 的供參考的腳本:
#!/bin/bash -e
### BEGIN INIT INFO
# Provides: adbd
# Required-Start:
# Required-Stop:
# Default-Start:
# Default-Stop:
# Short-Description:
# Description: Linux ADB
### END INIT INFO
VENDOR_ID="0x1d6b"
PRODUCT_ID="0x0104"
UDC=`ls /sys/class/udc/ | awk '{print $1}'`
start() {
mkdir -p /dev/usb-ffs/adb -m 0770
mkdir -p /sys/kernel/config/usb_gadget/g1 -m 0770
echo ${VENDOR_ID} > /sys/kernel/config/usb_gadget/g1//idVendor
echo ${PRODUCT_ID} > /sys/kernel/config/usb_gadget/g1//idProduct
mkdir -p /sys/kernel/config/usb_gadget/g1/strings/0x409 -m 0770
echo "0123456789ABCDEF" > /sys/kernel/config/usb_gadget/g1/strings/0x409/serialnumber
echo "STMicroelectronics" > /sys/kernel/config/usb_gadget/g1/strings/0x409/manufacturer
echo "STM32MP1" > /sys/kernel/config/usb_gadget/g1/strings/0x409/product
mkdir -p /sys/kernel/config/usb_gadget/g1/functions/ffs.adb
mkdir -p /sys/kernel/config/usb_gadget/g1/configs/b.1 -m 0770
mkdir -p /sys/kernel/config/usb_gadget/g1/configs/b.1/strings/0x409 -m 0770
ln -s /sys/kernel/config/usb_gadget/g1/functions/ffs.adb /sys/kernel/config/usb_gadget/g1/configs/b.1
echo "adb" > /sys/kernel/config/usb_gadget/g1/configs/b.1/strings/0x409/configuration
mount -t functionfs adb /dev/usb-ffs/adb
start-stop-daemon --start --oknodo --pidfile /var/run/adbd.pid --startas /bin/adbd --background
sleep 1
echo $UDC > /sys/kernel/config/usb_gadget/g1/UDC
}
stop() {
start-stop-daemon --stop --oknodo --pidfile /var/run/adbd.pid --retry 5
umount /dev/usb-ffs/adb
}
restart() {
echo $UDC > /sys/kernel/config/usb_gadget/g1/UDC
}
if [ "$UDC" != "" ]; then
case $1 in
start|stop|restart) "$1" ;;
esac
fi
exit $?一口君原創(chuàng)得所有c語言基礎(chǔ)知識、c語言實例代碼,均整理成pdf文檔【定期更新】

end
一口Linux
關(guān)注,回復(fù)【1024】海量Linux資料贈送
精彩文章合集
文章推薦