OTG配置为USB盘之二
在前面一节中,描述了otg配置U盘时涉及到的知识点,本篇用统一的脚本完成。
目标
将3588开发板子配置为一个U盘。
配置文件和脚本
配置文件
说明:
1)USB_FUNCS是将开发板配置为什么类型的设备,例如u盘,配置ums等等。
2)UMS_FILE 即对应的具体存储设备,本文就着重讲解此处的应用。
存储设备可以是
a. 一个文件,里面在内存或者磁盘上创建一个img文件。
b. 一个分区
#!/bin/sh# The env variables below can be overridden# option: adb acm hid mtp ntb rndis uac1 uac2 ums uvc
#export USB_FUNCS="adb"
export USB_FUNCS="ums"#export UMS_FILE=/userdata/ums_shared.img
#export UMS_FILE=/dev/mmcblk0p7
export UMS_FILE=/dev/sda5
#export UMS_SIZE=1024M
export UMS_SIZE=7G
export UMS_FSTYPE=ntfs
export UMS_MOUNT=0
export UMS_MOUNTPOINT=/mnt/ums
export UMS_RO=0
设置u盘脚本
脚本运行 usbdevice start等参数
#!/bin/sh # Uncomment below to see more logs
# set -x# Load default env variables from profiles
. /etc/profileLOG_FILE=/tmp/usbdevice.log
USB_FUNCS_FILE=/tmp/.usbdevicealias usb_enable='touch $USB_FUNCS_FILE'
alias usb_disable='rm -f $USB_FUNCS_FILE'
alias usb_is_enabled='[ -f $USB_FUNCS_FILE ]'
alias usb_set_started='echo $USB_FUNCS > $USB_FUNCS_FILE'
usb_get_started()
{usb_is_enabled || return 0cat $USB_FUNCS_FILE
}CONFIGFS_DIR=/sys/kernel/config
USB_GROUP=rockchip
USB_STRINGS_ATTR=strings/0x409
USB_GADGET_DIR=$CONFIGFS_DIR/usb_gadget/$USB_GROUP
USB_GADGET_STRINGS_DIR=$USB_GADGET_DIR/$USB_STRINGS_ATTR
USB_FUNCTIONS_DIR=$USB_GADGET_DIR/functions
USB_CONFIGS_DIR=$USB_GADGET_DIR/configs/b.1
USB_CONFIGS_STRINGS_DIR=$USB_CONFIGS_DIR/$USB_STRINGS_ATTR# Make sure that we own this session (pid equals sid)
if ! ps x -o cmd,pid,sid | grep -wq "$$$"; thensetsid $0 $@exit $?
fi# ---- helper functions
usb_msg()
{logger -t $(basename $0) "[$$]: $@"echo "[$(date +"%F %T")] $@"
}usb_pid()
{case $1 inums) echo 0x0000;;mtp) echo 0x0001;;uvc) echo 0x0005;;adb) echo 0x0006;;adb_mtp) echo 0x0011;;adb_ums) echo 0x0018;;adb_uvc) echo 0x0015;;ntb_uvc) echo 0x0017;;acm) echo 0x1005;;*) echo 0x0019;;esac
}usb_instances()
{for func in $@; doVAR=$(echo $func | tr 'a-z' 'A-Z')_INSTANCESeval echo "\${$VAR:-$func.gs0}"done
}usb_run_stage()
{for f in $1_pre_$2_hook $1_$2 $1_post_$2_hook; dotype $f >/dev/null 2>/dev/null || continueusb_msg "Run stage: $f"eval $f || breakdone
}usb_wait_files()
{for i in `seq 200`;dofuser -s $@ 2>/dev/null && breaksleep .01done
}usb_release_files()
{for i in `seq 200`;dofuser -s -k $@ 2>/dev/null || breaksleep .01done
}# usage: usb_mount <src> <mountpoint> <options>
usb_mount()
{mkdir -p $2mountpoint -q $2 || mount $@
}usb_umount()
{mountpoint -q $1 || return 0usb_release_files -m $1umount $1
}usb_symlink()
{mkdir -p $1[ -e $2 ] || ln -s $1 $2
}usb_try_symlink()
{usb_symlink $@ &>/dev/null || true
}usb_write()
{if echo "x$1" | grep -q "^x-"; thenOPTS=$1shiftfiFILE=$1shiftif [ -r $FILE ] && [ "$(cat $FILE)" = "$@" ]; thenreturn 0fiecho $OPTS "$@" > $FILE
}usb_try_write()
{usb_write $@ &>/dev/null || true
}usb_start_daemon()
{NAME=$(echo $1 | sed "s#^[^ ]*/\([^ ]*\).*#\1#")TAG_FILE=/tmp/.usb_$NAME# Enable spawntouch $TAG_FILE# Already started[ -z "$(usb_get_started)" ] || return 0# Start and spawn background daemon{exec 3<&-cd /while usb_is_enabled; do# Don't spawn after stopped[ ! -f $TAG_FILE ] ||start-stop-daemon -Sqx $@ || truesleep .5done}&
}usb_stop_daemon()
{NAME=$(echo $1 | sed "s#^[^ ]*/\([^ ]*\).*#\1#")TAG_FILE=/tmp/.usb_$NAME# Stop and disable spawnrm -f $TAG_FILEstart-stop-daemon -Kqox $@
}usb_load_config()
{USB_CONFIG_FILE=$(find /etc/ -name .usb_config | head -n 1)[ -n "$USB_CONFIG_FILE" -a -r $USB_CONFIG_FILE ] || return 0ums_parse(){grep "\<$1=" $USB_CONFIG_FILE | cut -d'=' -f2}UMS_FILE=$(ums_parse ums_block)UMS_SIZE=$(ums_parse ums_block_size || echo 0)MUMS_FSTYPE=$(ums_parse ums_block_type)UMS_MOUNT=$([ "$(ums_parse ums_block_auto_mount)" != on ]; echo $?)UMS_RO=$([ "$(ums_parse ums_block_ro)" != on ]; echo $?)USB_FUNCS=$(grep "usb_.*_en" $USB_CONFIG_FILE | cut -d'_' -f2 | xargs)
}# ---- adb
ADB_INSTANCES=${ADB_INSTANCES:-ffs.adb}adb_prepare()
{usb_mount adb /dev/usb-ffs/adb -o uid=2000,gid=2000 -t functionfsusb_start_daemon /usr/bin/adbdusb_wait_files -m /dev/usb-ffs/adb
}adb_stop()
{usb_stop_daemon /usr/bin/adbd
}# ---- ntb
NTB_INSTANCES=${NTB_INSTANCES:-ffs.ntb}ntb_prepare()
{usb_mount ntb /dev/usb-ffs/ntb -o uid=2000,gid=2000 -t functionfs
}# ---- uac1
uac1_prepare()
{for f in $(find . -name "*_feature_unit"); doecho 1 >$fdone
}# ---- uac2
uac2_prepare()
{uac1_prepare
}# ---- mtp
mtp_prepare()
{echo "MTP" > os_desc/interface.MTP/compatible_idecho 1 > $USB_GADGET_DIR/os_desc/use
}mtp_start()
{usb_start_daemon /usr/bin/mtp-serverusb_wait_files /dev/mtp_usb
}mtp_stop()
{usb_stop_daemon /usr/bin/mtp-serverusb_release_files /dev/mtp_usbecho 0 > $USB_GADGET_DIR/os_desc/use
}# ---- acm
ACM_INSTANCES=${ACM_INSTANCES:-acm.gs6}# ---- rndis
# Nothing special# ---- uvc
UVC_INSTANCES=${UVC_INSTANCES:-uvc.gs6}uvc_add_yuyv()
{WIDTH=$(echo $1 | cut -d'x' -f1)HEIGHT=$(echo $1 | cut -d'x' -f2)DIR=${HEIGHT}p[ ! -d $DIR ] || return 0mkdir -p $DIRecho $WIDTH > $DIR/wWidthecho $HEIGHT > $DIR/wHeightecho 333333 > $DIR/dwDefaultFrameIntervalecho $((WIDTH * HEIGHT * 20)) > $DIR/dwMinBitRateecho $((WIDTH * HEIGHT * 20)) > $DIR/dwMaxBitRateecho $((WIDTH * HEIGHT * 2)) > $DIR/dwMaxVideoFrameBufferSizeecho -e "333333\n666666\n1000000\n2000000" > $DIR/dwFrameInterval
}uvc_add_mjpeg()
{WIDTH=$(echo $1 | cut -d'x' -f1)HEIGHT=$(echo $1 | cut -d'x' -f2)DIR=${HEIGHT}p[ ! -d $DIR ] || return 0mkdir -p $DIRecho $WIDTH > $DIR/wWidthecho $HEIGHT > $DIR/wHeightecho 333333 > $DIR/dwDefaultFrameIntervalecho $((WIDTH * HEIGHT * 20)) > $DIR/dwMinBitRateecho $((WIDTH * HEIGHT * 20)) > $DIR/dwMaxBitRateecho $((WIDTH * HEIGHT * 2)) > $DIR/dwMaxVideoFrameBufferSizeecho -e "333333\n666666\n1000000\n2000000" > $DIR/dwFrameInterval
}uvc_add_h264()
{WIDTH=$(echo $1 | cut -d'x' -f1)HEIGHT=$(echo $1 | cut -d'x' -f2)DIR=${HEIGHT}p[ ! -d $DIR ] || return 0mkdir -p $DIRecho $WIDTH > $DIR/wWidthecho $HEIGHT > $DIR/wHeightecho 333333 > $DIR/dwDefaultFrameIntervalecho $((WIDTH * HEIGHT * 10)) > $DIR/dwMinBitRateecho $((WIDTH * HEIGHT * 10)) > $DIR/dwMaxBitRateecho -e "333333\n666666\n1000000\n2000000" > $DIR/dwFrameInterval
}uvc_support_resolutions()
{case ${1:-yuyv} inyuyv) echo "640x480 1280x720";;mjpeg) echo "640x480 1280x720 1920x1080 2560x1440 2592x1944";;h264) echo "640x480 1280x720 1920x1080";;esac
}uvc_prepare()
{UVC_DIR=$(pwd)usb_symlink $UVC_DIR/control/header/h $UVC_DIR/control/class/fs/husb_symlink $UVC_DIR/control/header/h $UVC_DIR/control/class/ss/husb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/fs/husb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/hs/husb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/ss/hUVC_YUYV_RES=$(uvc_support_resolutions yuyv)if [ -n "$UVC_YUYV_RES" ]; thenusb_try_symlink $UVC_DIR/streaming/uncompressed/u \$UVC_DIR/streaming/header/h/ucd $UVC_DIR/streaming/uncompressed/ufor res in $UVC_YUYV_RES; douvc_add_yuyv $resdonefiUVC_MJPEG_RES=$(uvc_support_resolutions mjpeg)if [ -n "$UVC_MJPEG_RES" ]; thenusb_try_symlink $UVC_DIR/streaming/mjpeg/m \$UVC_DIR/streaming/header/h/mcd $UVC_DIR/streaming/mjpeg/mfor res in $UVC_MJPEG_RES; douvc_add_mjpeg $resdonefiUVC_H264_RES=$(uvc_support_resolutions h264)if [ -n "$UVC_H264_RES" ]; thenusb_try_symlink $UVC_DIR/streaming/framebased/f \$UVC_DIR/streaming/header/h/fcd $UVC_DIR/streaming/framebased/ffor res in $UVC_H264_RES; douvc_add_h264 $resdoneusb_try_write -ne guidFormat "\\x48\\x32\\x36\\x34\\x00\\x00\\x10\\x00\\x80\\x00\\x00\\xaa\\x00\\x38\\x9b\\x71"fi
}# TODO: Start UVC daemon in uvc_start
# TODO: Stop UVC daemon in uvc_stop# ---- hid
HID_INSTANCES=${HID_INSTANCES:-hid.usb0}hid_prepare()
{echo 1 > protocolecho 1 > subclassecho 8 > report_lengthecho -ne "\\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0" \> report_desc
}# ---- ums
UMS_INSTANCES=${UMS_INSTANCES:-mass_storage.0}ums_prepare()
{if [ ! -f $UMS_FILE ]; thenusb_msg "Formating $UMS_FILE($UMS_SIZE) to $UMS_FSTYPE"#truncate -s $UMS_SIZE $UMS_FILE#mkfs.$UMS_FSTYPE -s 4096 -L "mbca19" $UMS_FILE || \# usb_msg "Failed to format $UMS_FILE to $UMS_FSTYPE"fi
}ums_stop()
{echo > lun.0/fileusb_umount $UMS_MOUNTPOINT[ "$UMS_MOUNT" -eq 1 ] || return 0# Try auto fstype firstlyusb_mount $UMS_FILE $UMS_MOUNTPOINT -o async 2>/dev/null || \usb_mount $UMS_FILE $UMS_MOUNTPOINT -o async -t $UMS_FSTYPE
}ums_start()
{echo "current : $(pwd)"case "$USB_STATE" inCONFIGURED)if [ "$(cat lun.0/ro)" != "$UMS_RO" ]; thenecho > lun.0/fileecho $UMS_RO > lun.0/rofiif ! grep -wq $UMS_FILE lun.0/file; thenusb_umount $UMS_MOUNTPOINTecho $UMS_FILE > lun.0/filefi;;DISCONNECTED)ums_stop;;esac
}# ---- global
usb_init()
{usb_msg "Initializing"echo 0x2207 > idVendorecho 0x0310 > bcdDeviceecho 0x0200 > bcdUSBmkdir -p $USB_GADGET_STRINGS_DIRSERIAL=$(grep Serial /proc/cpuinfo | cut -d':' -f2)echo ${SERIAL:-0123456789ABCDEF} > $USB_GADGET_STRINGS_DIR/serialnumberecho $USB_GROUP > $USB_GADGET_STRINGS_DIR/manufacturerecho "rk3xxhjx" > $USB_GADGET_STRINGS_DIR/productmkdir -p $USB_CONFIGS_DIRecho 500 > $USB_CONFIGS_DIR/MaxPowerecho 0x1 > os_desc/b_vendor_codeecho MSFT100 > os_desc/qw_signln -s $USB_CONFIGS_DIR os_desc/mkdir -p $USB_CONFIGS_STRINGS_DIR
}usb_funcs_grep()
{echo $USB_FUNCS | xargs -n 1 | sort | uniq | grep $@ || true
}usb_funcs_sort()
{{for func in $@; dousb_funcs_grep -E $funcdoneusb_funcs_grep -vE $(echo $@ | tr ' ' '|')} | uniq | xargs
}usb_prepare()
{usb_load_config# Allow function/variable overriding[ -d /etc/usbdevice.d ] && . /etc/usbdevice.d/*UMS_FILE=${UMS_FILE:-/userdata/ums_shared.img}UMS_SIZE=${UMS_SIZE:-256M}UMS_FSTYPE=${UMS_FSTYPE:-vfat}UMS_MOUNT=${UMS_MOUNT:-0}UMS_MOUNTPOINT=${UMS_MOUNTPOINT:-/mnt/ums}UMS_RO=${UMS_RO:-0}# Put RNDIS & UAC & UVC at first (required by kernel)USB_FUNCS=$(usb_funcs_sort rndis uac uvc)if [ ! -d $USB_GADGET_DIR ]; thenmountpoint -q $CONFIGFS_DIR || \mount -t configfs none $CONFIGFS_DIRmkdir -p $USB_GADGET_DIRcd $USB_GADGET_DIR# Global initializeusb_run_stage usb initfiUSB_STATE=$(cat /sys/class/android_usb/android0/state)USB_UDC=$(ls /sys/class/udc/ | head -n 1)# Parse started USB functionsOLD_FUNCS=$(usb_get_started)# Stop old USB functions when USB functions changedif [ -n "$OLD_FUNCS" ] && [ "$OLD_FUNCS" != "$USB_FUNCS" ]; thenusb_msg "Functions changed $OLD_FUNCS -> $USB_FUNCS"usb_stopfi
}usb_start()
{usb_msg "Starting functions: $USB_FUNCS"echo $USB_FUNCS | tr ' ' '_' > $USB_CONFIGS_STRINGS_DIR/configurationfor func in $USB_FUNCS; dofor instance in $(usb_instances $func); dousb_msg "Preparing instance: $instance"if ! mkdir -p $USB_FUNCTIONS_DIR/$instance 2>/dev/null; thenusb_msg "Failed to create instance: $instance"continuefiecho "except dir: $USB_FUNCTIONS_DIR/$instance"cd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continuecd $USB_FUNCTIONS_DIR/$instanceecho "start dir : $(pwd)"usb_run_stage $func prepare# Make symlink after prepared (required by UVC)usb_symlink $USB_FUNCTIONS_DIR/$instance \$USB_CONFIGS_DIR/f-$instancedonedoneusb_write $USB_GADGET_DIR/UDC $USB_UDCfor func in $USB_FUNCS; dofor instance in $(usb_instances $func); docd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continueusb_msg "Starting instance: $instance"usb_run_stage $func startdonedone# Store started functionsusb_set_started
}usb_stop()
{if [ -n "$OLD_FUNCS" ]; thenusb_msg "Stopping functions: $OLD_FUNCS"fiusb_write $USB_GADGET_DIR/UDC ""for func in $USB_FUNCS; dofor instance in $(usb_instances $func); docd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continueusb_msg "Stopping instance: $instance"usb_run_stage $func stopdonedonerm -f $USB_CONFIGS_DIR/f-*# Clear functions to avoid stopping them againunset OLD_FUNCS
}usb_restart()
{usb_run_stage usb stopusb_run_stage usb start
}ACTION=${1:-update}
if [ "$ACTION" = update ]; thenusb_is_enabled || exit 0
fi# Lock it
exec 3<$0
flock -x 3echo "Starting $0 ${ACTION}, log saved to $LOG_FILE"# Redirect outputs to log file
exec >>$LOG_FILE 2>&1usb_msg "Handling ${ACTION} request"usb_run_stage usb preparecase "$ACTION" instart|update)usb_enableusb_run_stage usb start;;stop)usb_disableusb_run_stage usb stop;;restart)usb_enableusb_run_stage usb restart;;*)echo "Usage: usbdevice [start|stop|restart|update]" >&2;;
esacusb_msg "Done $ACTION request"
echo# Unlock it
flock -u 3
步骤
以内存为存储介质
创建文件
mount -t tmpfs -o size=4G tmpfs /mnt/mem
并在/mnt/mem 目录下创建 test.img 文件作为 U 盘存储
dd if=/dev/zero of=test.img bs=1M count=2048
这里注意一点:img文件并不能被格式化,则上述U盘脚本中的 如下格式化的部分,需要注释掉,否则有问题。
ums_prepare()
{if [ ! -f $UMS_FILE ]; thenusb_msg "Formating $UMS_FILE($UMS_SIZE) to $UMS_FSTYPE"#truncate -s $UMS_SIZE $UMS_FILE#mkfs.$UMS_FSTYPE -s 4096 -L "mbca19" $UMS_FILE || \# usb_msg "Failed to format $UMS_FILE to $UMS_FSTYPE"fi
}
创建后,在windows下访问时先要将其格式为NTFS等。
以U盘SATA盘等为存储介质
首先格式化为NTFS,然后运行上述脚本进行usb 设备创建。
将开发板插入到windows下可以直接作为U盘使用,不需要格式化等额外操作。
可以实现linux 下面写,而windows读的,满足类似移动硬盘的应用场景。
性能测试
在windows下用 CD 工具压测,环境采用USB3.0的接口(特别要注意线缆的选择,用2.0的线缆是)。