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/profile

LOG_FILE=/tmp/usbdevice.log
USB_FUNCS_FILE=/tmp/.usbdevice

alias 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 0
	cat $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 "$$$"; then
	setsid $0 $@
	exit $?
fi

# ---- helper functions
usb_msg()
{
	logger -t $(basename $0) "[$$]: $@"
	echo "[$(date +"%F %T")] $@"
}

usb_pid()
{
	case $1 in
		ums)		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 $@; do
		VAR=$(echo $func | tr 'a-z' 'A-Z')_INSTANCES
		eval echo "\${$VAR:-$func.gs0}"
	done
}

usb_run_stage()
{
	for f in $1_pre_$2_hook $1_$2 $1_post_$2_hook; do
		type $f >/dev/null 2>/dev/null || continue

		usb_msg "Run stage: $f"
		eval $f || break
	done
}

usb_wait_files()
{
	for i in `seq 200`;do
		fuser -s $@ 2>/dev/null && break
		sleep .01
	done
}

usb_release_files()
{
	for i in `seq 200`;do
		fuser -s -k $@ 2>/dev/null || break
		sleep .01
	done
}

# usage: usb_mount <src> <mountpoint> <options>
usb_mount()
{
	mkdir -p $2
	mountpoint -q $2 || mount $@
}

usb_umount()
{
	mountpoint -q $1 || return 0
	usb_release_files -m $1
	umount $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-"; then
		OPTS=$1
		shift
	fi

	FILE=$1
	shift

	if [ -r $FILE ] && [ "$(cat $FILE)" = "$@" ]; then
		return 0
	fi

	echo $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 spawn
	touch $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 $@ || true
			sleep .5
		done
	}&
}

usb_stop_daemon()
{
	NAME=$(echo $1 | sed "s#^[^ ]*/\([^ ]*\).*#\1#")
	TAG_FILE=/tmp/.usb_$NAME

	# Stop and disable spawn
	rm -f $TAG_FILE
	start-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 0

	ums_parse()
	{
		grep "\<$1=" $USB_CONFIG_FILE | cut -d'=' -f2
	}
	UMS_FILE=$(ums_parse ums_block)
	UMS_SIZE=$(ums_parse ums_block_size || echo 0)M
	UMS_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 functionfs
	usb_start_daemon /usr/bin/adbd
	usb_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"); do
		echo 1 >$f
	done
}

# ---- uac2
uac2_prepare()
{
	uac1_prepare
}

# ---- mtp
mtp_prepare()
{
	echo "MTP" > os_desc/interface.MTP/compatible_id
	echo 1 > $USB_GADGET_DIR/os_desc/use
}

mtp_start()
{
	usb_start_daemon /usr/bin/mtp-server
	usb_wait_files /dev/mtp_usb
}

mtp_stop()
{
	usb_stop_daemon /usr/bin/mtp-server
	usb_release_files /dev/mtp_usb

	echo 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 0

	mkdir -p $DIR
	echo $WIDTH > $DIR/wWidth
	echo $HEIGHT > $DIR/wHeight
	echo 333333 > $DIR/dwDefaultFrameInterval
	echo $((WIDTH * HEIGHT * 20)) > $DIR/dwMinBitRate
	echo $((WIDTH * HEIGHT * 20)) > $DIR/dwMaxBitRate
	echo $((WIDTH * HEIGHT * 2)) > $DIR/dwMaxVideoFrameBufferSize
	echo -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 0

	mkdir -p $DIR
	echo $WIDTH > $DIR/wWidth
	echo $HEIGHT > $DIR/wHeight
	echo 333333 > $DIR/dwDefaultFrameInterval
	echo $((WIDTH * HEIGHT * 20)) > $DIR/dwMinBitRate
	echo $((WIDTH * HEIGHT * 20)) > $DIR/dwMaxBitRate
	echo $((WIDTH * HEIGHT * 2)) > $DIR/dwMaxVideoFrameBufferSize
	echo -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 0

	mkdir -p $DIR
	echo $WIDTH > $DIR/wWidth
	echo $HEIGHT > $DIR/wHeight
	echo 333333 > $DIR/dwDefaultFrameInterval
	echo $((WIDTH * HEIGHT * 10)) > $DIR/dwMinBitRate
	echo $((WIDTH * HEIGHT * 10)) > $DIR/dwMaxBitRate
	echo -e "333333\n666666\n1000000\n2000000" > $DIR/dwFrameInterval
}

uvc_support_resolutions()
{
	case ${1:-yuyv} in
		yuyv)	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/h
	usb_symlink $UVC_DIR/control/header/h $UVC_DIR/control/class/ss/h

	usb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/fs/h
	usb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/hs/h
	usb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/ss/h

	UVC_YUYV_RES=$(uvc_support_resolutions yuyv)
	if [ -n "$UVC_YUYV_RES" ]; then
		usb_try_symlink $UVC_DIR/streaming/uncompressed/u \
			$UVC_DIR/streaming/header/h/u
		cd $UVC_DIR/streaming/uncompressed/u

		for res in $UVC_YUYV_RES; do
			uvc_add_yuyv $res
		done
	fi

	UVC_MJPEG_RES=$(uvc_support_resolutions mjpeg)
	if [ -n "$UVC_MJPEG_RES" ]; then
		usb_try_symlink $UVC_DIR/streaming/mjpeg/m \
			$UVC_DIR/streaming/header/h/m
		cd $UVC_DIR/streaming/mjpeg/m

		for res in $UVC_MJPEG_RES; do
			uvc_add_mjpeg $res
		done
	fi

	UVC_H264_RES=$(uvc_support_resolutions h264)
	if [ -n "$UVC_H264_RES" ]; then
		usb_try_symlink $UVC_DIR/streaming/framebased/f \
			$UVC_DIR/streaming/header/h/f
		cd $UVC_DIR/streaming/framebased/f

		for res in $UVC_H264_RES; do
			uvc_add_h264 $res
		done

		usb_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 > protocol
	echo 1 > subclass
	echo 8 > report_length
	echo -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 ]; then
		usb_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/file
	usb_umount $UMS_MOUNTPOINT

	[ "$UMS_MOUNT" -eq 1 ] || return 0

	# Try auto fstype firstly
	usb_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" in
		CONFIGURED)
			if [ "$(cat lun.0/ro)" != "$UMS_RO" ]; then
				echo > lun.0/file
				echo $UMS_RO > lun.0/ro
			fi

			if ! grep -wq $UMS_FILE lun.0/file; then
				usb_umount $UMS_MOUNTPOINT
				echo $UMS_FILE > lun.0/file
			fi
			;;
		DISCONNECTED)
			ums_stop
			;;
	esac
}

# ---- global
usb_init()
{
	usb_msg "Initializing"

	echo 0x2207 > idVendor
	echo 0x0310 > bcdDevice
	echo 0x0200 > bcdUSB

	mkdir -p $USB_GADGET_STRINGS_DIR
	SERIAL=$(grep Serial /proc/cpuinfo | cut -d':' -f2)
	echo ${SERIAL:-0123456789ABCDEF} > $USB_GADGET_STRINGS_DIR/serialnumber
	echo $USB_GROUP  > $USB_GADGET_STRINGS_DIR/manufacturer
	echo "rk3xxhjx"  > $USB_GADGET_STRINGS_DIR/product

	mkdir -p $USB_CONFIGS_DIR
	echo 500 > $USB_CONFIGS_DIR/MaxPower

	echo 0x1 > os_desc/b_vendor_code
	echo MSFT100 > os_desc/qw_sign
	ln -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 $@; do
			usb_funcs_grep -E $func
		done
		usb_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 ]; then
		mountpoint -q $CONFIGFS_DIR || \
			mount -t configfs none $CONFIGFS_DIR

		mkdir -p $USB_GADGET_DIR
		cd $USB_GADGET_DIR

		# Global initialize
		usb_run_stage usb init
	fi

	USB_STATE=$(cat /sys/class/android_usb/android0/state)
	USB_UDC=$(ls /sys/class/udc/ | head -n 1)

	# Parse started USB functions
	OLD_FUNCS=$(usb_get_started)

	# Stop old USB functions when USB functions changed
	if [ -n "$OLD_FUNCS" ] && [ "$OLD_FUNCS" != "$USB_FUNCS" ]; then
		usb_msg "Functions changed $OLD_FUNCS -> $USB_FUNCS"
		usb_stop
	fi
}

usb_start()
{
	usb_msg "Starting functions: $USB_FUNCS"

	echo $USB_FUNCS | tr ' ' '_' > $USB_CONFIGS_STRINGS_DIR/configuration

	for func in $USB_FUNCS; do
		for instance in $(usb_instances $func); do
			usb_msg "Preparing instance: $instance"

			if ! mkdir -p $USB_FUNCTIONS_DIR/$instance 2>/dev/null; then
				usb_msg "Failed to create instance: $instance"
				continue
			fi
      echo "except dir: $USB_FUNCTIONS_DIR/$instance"
			cd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continue
			
			cd $USB_FUNCTIONS_DIR/$instance
      echo "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-$instance
		done
	done

	usb_write $USB_GADGET_DIR/UDC $USB_UDC

	for func in $USB_FUNCS; do
		for instance in $(usb_instances $func); do
			cd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continue

			usb_msg "Starting instance: $instance"
			usb_run_stage $func start
		done
	done

	# Store started functions
	usb_set_started
}

usb_stop()
{
	if [ -n "$OLD_FUNCS" ]; then
		usb_msg "Stopping functions: $OLD_FUNCS"
	fi

	usb_write $USB_GADGET_DIR/UDC ""

	for func in $USB_FUNCS; do
		for instance in $(usb_instances $func); do
			cd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continue

			usb_msg "Stopping instance: $instance"
			usb_run_stage $func stop
		done
	done

	rm -f $USB_CONFIGS_DIR/f-*

	# Clear functions to avoid stopping them again
	unset OLD_FUNCS
}

usb_restart()
{
	usb_run_stage usb stop
	usb_run_stage usb start
}

ACTION=${1:-update}
if [ "$ACTION" = update ]; then
	usb_is_enabled || exit 0
fi

# Lock it
exec 3<$0
flock -x 3

echo "Starting $0 ${ACTION}, log saved to $LOG_FILE"

# Redirect outputs to log file
exec >>$LOG_FILE 2>&1

usb_msg "Handling ${ACTION} request"

usb_run_stage usb prepare

case "$ACTION" in
	start|update)
		usb_enable
		usb_run_stage usb start
		;;
	stop)
		usb_disable
		usb_run_stage usb stop
		;;
	restart)
		usb_enable
		usb_run_stage usb restart
		;;
	*)
		echo "Usage: usbdevice [start|stop|restart|update]" >&2
		;;
esac

usb_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 ]; then
		usb_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的线缆是)。

     

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

proware

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值