xref: /OK3568_Linux_fs/debian/overlay/usr/bin/usbdevice (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/bin/sh -e
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# Usage:
4*4882a593Smuzhiyun# usbdevice [start|update|stop]
5*4882a593Smuzhiyun#
6*4882a593Smuzhiyun# Hookable stages:
7*4882a593Smuzhiyun# usb_<pre|post>_<init|prepare|start|stop|restart>_hook
8*4882a593Smuzhiyun# <usb function>_<pre|post>_<prepare|start|stop>_hook
9*4882a593Smuzhiyun#
10*4882a593Smuzhiyun# Example hook:
11*4882a593Smuzhiyun# root@RK3588:/# more /etc/usbdevice.d/usb_init.sh
12*4882a593Smuzhiyun# #!/bin/sh
13*4882a593Smuzhiyun# usb_pre_init_hook()
14*4882a593Smuzhiyun# {
15*4882a593Smuzhiyun#	echo "usb pre-init hook"
16*4882a593Smuzhiyun# }
17*4882a593Smuzhiyun#
18*4882a593Smuzhiyun# root@RK3588:/# more /etc/usbdevice.d/uvc.sh
19*4882a593Smuzhiyun# #!/bin/sh
20*4882a593Smuzhiyun# UVC_INSTANCES="uvc.gs1 uvc.gs2"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun# Uncomment below to see more logs
23*4882a593Smuzhiyun# set -x
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun# Load default env variables from profiles
26*4882a593Smuzhiyun. /etc/profile
27*4882a593Smuzhiyun
28*4882a593SmuzhiyunLOG_FILE=/tmp/usbdevice.log
29*4882a593SmuzhiyunUSB_FUNCS_FILE=/tmp/.usbdevice
30*4882a593Smuzhiyun
31*4882a593Smuzhiyunalias usb_enable='touch $USB_FUNCS_FILE'
32*4882a593Smuzhiyunalias usb_disable='rm -f $USB_FUNCS_FILE'
33*4882a593Smuzhiyunalias usb_is_enabled='[ -f $USB_FUNCS_FILE ]'
34*4882a593Smuzhiyunalias usb_set_started='echo $USB_FUNCS > $USB_FUNCS_FILE'
35*4882a593Smuzhiyunusb_get_started()
36*4882a593Smuzhiyun{
37*4882a593Smuzhiyun	usb_is_enabled || return 0
38*4882a593Smuzhiyun	cat $USB_FUNCS_FILE
39*4882a593Smuzhiyun}
40*4882a593Smuzhiyun
41*4882a593SmuzhiyunCONFIGFS_DIR=/sys/kernel/config
42*4882a593SmuzhiyunUSB_GROUP=rockchip
43*4882a593SmuzhiyunUSB_STRINGS_ATTR=strings/0x409
44*4882a593SmuzhiyunUSB_GADGET_DIR=$CONFIGFS_DIR/usb_gadget/$USB_GROUP
45*4882a593SmuzhiyunUSB_GADGET_STRINGS_DIR=$USB_GADGET_DIR/$USB_STRINGS_ATTR
46*4882a593SmuzhiyunUSB_FUNCTIONS_DIR=$USB_GADGET_DIR/functions
47*4882a593SmuzhiyunUSB_CONFIGS_DIR=$USB_GADGET_DIR/configs/b.1
48*4882a593SmuzhiyunUSB_CONFIGS_STRINGS_DIR=$USB_CONFIGS_DIR/$USB_STRINGS_ATTR
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun# Make sure that we own this session (pid equals sid)
51*4882a593Smuzhiyunif ! ps x -o pid,sid | grep -wq "$$$"; then
52*4882a593Smuzhiyun	setsid $0 $@
53*4882a593Smuzhiyun	exit $?
54*4882a593Smuzhiyunfi
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun# ---- helper functions
57*4882a593Smuzhiyunusb_msg()
58*4882a593Smuzhiyun{
59*4882a593Smuzhiyun	logger -t "$(basename "$0")" "[$$]: $@"
60*4882a593Smuzhiyun	echo "[$(date +"%F %T")] $@"
61*4882a593Smuzhiyun}
62*4882a593Smuzhiyun
63*4882a593Smuzhiyunusb_pid()
64*4882a593Smuzhiyun{
65*4882a593Smuzhiyun	case "$(echo $USB_FUNCS | xargs -n 1 | sort | paste -sd'-')" in
66*4882a593Smuzhiyun		ums)		echo 0x0000;;
67*4882a593Smuzhiyun		mtp)		echo 0x0001;;
68*4882a593Smuzhiyun		uvc)		echo 0x0005;;
69*4882a593Smuzhiyun		adb)		echo 0x0006;;
70*4882a593Smuzhiyun		adb-mtp)	echo 0x0011;;
71*4882a593Smuzhiyun		adb-ums)	echo 0x0018;;
72*4882a593Smuzhiyun		adb-uvc)	echo 0x0015;;
73*4882a593Smuzhiyun		ntb-uvc)	echo 0x0017;;
74*4882a593Smuzhiyun		acm)		echo 0x1005;;
75*4882a593Smuzhiyun		*)		echo 0x0019;;
76*4882a593Smuzhiyun	esac
77*4882a593Smuzhiyun}
78*4882a593Smuzhiyun
79*4882a593Smuzhiyunusb_instances()
80*4882a593Smuzhiyun{
81*4882a593Smuzhiyun	for func in $@; do
82*4882a593Smuzhiyun		VAR=$(echo $func | tr 'a-z' 'A-Z')_INSTANCES
83*4882a593Smuzhiyun		eval echo "\${$VAR:-$func.gs0}"
84*4882a593Smuzhiyun	done
85*4882a593Smuzhiyun}
86*4882a593Smuzhiyun
87*4882a593Smuzhiyunusb_run_stage()
88*4882a593Smuzhiyun{
89*4882a593Smuzhiyun	for f in $1_pre_$2_hook $1_$2 $1_post_$2_hook; do
90*4882a593Smuzhiyun		type $f >/dev/null 2>/dev/null || continue
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun		usb_msg "Run stage: $f"
93*4882a593Smuzhiyun		eval $f || break
94*4882a593Smuzhiyun	done
95*4882a593Smuzhiyun}
96*4882a593Smuzhiyun
97*4882a593Smuzhiyunusb_wait_files()
98*4882a593Smuzhiyun{
99*4882a593Smuzhiyun	for i in `seq 200`;do
100*4882a593Smuzhiyun		fuser -s $@ 2>/dev/null && break
101*4882a593Smuzhiyun		sleep .01
102*4882a593Smuzhiyun	done
103*4882a593Smuzhiyun}
104*4882a593Smuzhiyun
105*4882a593Smuzhiyunusb_release_files()
106*4882a593Smuzhiyun{
107*4882a593Smuzhiyun	for i in `seq 200`;do
108*4882a593Smuzhiyun		fuser -s -k $@ 2>/dev/null || break
109*4882a593Smuzhiyun		sleep .01
110*4882a593Smuzhiyun	done
111*4882a593Smuzhiyun}
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun# usage: usb_mount <src> <mountpoint> <options>
114*4882a593Smuzhiyunusb_mount()
115*4882a593Smuzhiyun{
116*4882a593Smuzhiyun	mkdir -p $2
117*4882a593Smuzhiyun	mountpoint -q $2 || mount $@
118*4882a593Smuzhiyun}
119*4882a593Smuzhiyun
120*4882a593Smuzhiyunusb_umount()
121*4882a593Smuzhiyun{
122*4882a593Smuzhiyun	mountpoint -q $1 || return 0
123*4882a593Smuzhiyun	usb_release_files -m $1
124*4882a593Smuzhiyun	umount $1
125*4882a593Smuzhiyun}
126*4882a593Smuzhiyun
127*4882a593Smuzhiyunusb_symlink()
128*4882a593Smuzhiyun{
129*4882a593Smuzhiyun	mkdir -p $1
130*4882a593Smuzhiyun	[ -e $2 ] || ln -s $1 $2
131*4882a593Smuzhiyun}
132*4882a593Smuzhiyun
133*4882a593Smuzhiyunusb_try_symlink()
134*4882a593Smuzhiyun{
135*4882a593Smuzhiyun	usb_symlink $@ &>/dev/null || true
136*4882a593Smuzhiyun}
137*4882a593Smuzhiyun
138*4882a593Smuzhiyunusb_write()
139*4882a593Smuzhiyun{
140*4882a593Smuzhiyun	if echo "x$1" | grep -q "^x-"; then
141*4882a593Smuzhiyun		OPTS=$1
142*4882a593Smuzhiyun		shift
143*4882a593Smuzhiyun	fi
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun	FILE=$1
146*4882a593Smuzhiyun	shift
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun	if [ -r $FILE ] && [ "$(cat $FILE)" = "$@" ]; then
149*4882a593Smuzhiyun		return 0
150*4882a593Smuzhiyun	fi
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun	echo $OPTS "$@" > $FILE
153*4882a593Smuzhiyun}
154*4882a593Smuzhiyun
155*4882a593Smuzhiyunusb_try_write()
156*4882a593Smuzhiyun{
157*4882a593Smuzhiyun	usb_write $@ &>/dev/null || true
158*4882a593Smuzhiyun}
159*4882a593Smuzhiyun
160*4882a593Smuzhiyunusb_start_daemon()
161*4882a593Smuzhiyun{
162*4882a593Smuzhiyun	NAME=$(echo $1 | sed "s#^[^ ]*/\([^ ]*\).*#\1#")
163*4882a593Smuzhiyun	TAG_FILE=/tmp/.usb_$NAME
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun	# Enable spawn
166*4882a593Smuzhiyun	touch $TAG_FILE
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun	# Already started
169*4882a593Smuzhiyun	[ -z "$(usb_get_started)" ] || return 0
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun	# Start and spawn background daemon
172*4882a593Smuzhiyun	{
173*4882a593Smuzhiyun		exec 3<&-
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun		cd /
176*4882a593Smuzhiyun		while usb_is_enabled; do
177*4882a593Smuzhiyun			# Don't spawn after stopped
178*4882a593Smuzhiyun			[ ! -f $TAG_FILE ] ||
179*4882a593Smuzhiyun				start-stop-daemon -Sqx $@ || true
180*4882a593Smuzhiyun			sleep .5
181*4882a593Smuzhiyun		done
182*4882a593Smuzhiyun	}&
183*4882a593Smuzhiyun}
184*4882a593Smuzhiyun
185*4882a593Smuzhiyunusb_stop_daemon()
186*4882a593Smuzhiyun{
187*4882a593Smuzhiyun	NAME=$(echo $1 | sed "s#^[^ ]*/\([^ ]*\).*#\1#")
188*4882a593Smuzhiyun	TAG_FILE=/tmp/.usb_$NAME
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun	# Stop and disable spawn
191*4882a593Smuzhiyun	rm -f $TAG_FILE
192*4882a593Smuzhiyun	start-stop-daemon -Kqox $@
193*4882a593Smuzhiyun}
194*4882a593Smuzhiyun
195*4882a593Smuzhiyunusb_load_config()
196*4882a593Smuzhiyun{
197*4882a593Smuzhiyun	USB_CONFIG_FILE=$(find /etc/ -name .usb_config | head -n 1)
198*4882a593Smuzhiyun	[ -n "$USB_CONFIG_FILE" -a -r "$USB_CONFIG_FILE" ] || return 0
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun	ums_parse()
201*4882a593Smuzhiyun	{
202*4882a593Smuzhiyun		grep "\<$1=" "$USB_CONFIG_FILE" | cut -d'=' -f2
203*4882a593Smuzhiyun	}
204*4882a593Smuzhiyun	UMS_FILE="$(ums_parse ums_block)"
205*4882a593Smuzhiyun	UMS_SIZE=$(ums_parse ums_block_size || echo 0)M
206*4882a593Smuzhiyun	UMS_FSTYPE=$(ums_parse ums_block_type)
207*4882a593Smuzhiyun	UMS_MOUNT=$([ "$(ums_parse ums_block_auto_mount)" != on ]; echo $?)
208*4882a593Smuzhiyun	UMS_RO=$([ "$(ums_parse ums_block_ro)" != on ]; echo $?)
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun	USB_FUNCS="$(sed -n "s/usb_\(.*\)_en/\1/p" "$USB_CONFIG_FILE" | xargs)"
211*4882a593Smuzhiyun}
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun# ---- adb
214*4882a593SmuzhiyunADB_INSTANCES=${ADB_INSTANCES:-ffs.adb}
215*4882a593Smuzhiyun
216*4882a593Smuzhiyunadb_prepare()
217*4882a593Smuzhiyun{
218*4882a593Smuzhiyun	usb_mount adb /dev/usb-ffs/adb -o uid=2000,gid=2000 -t functionfs
219*4882a593Smuzhiyun	usb_start_daemon /usr/bin/adbd
220*4882a593Smuzhiyun	usb_wait_files -m /dev/usb-ffs/adb
221*4882a593Smuzhiyun}
222*4882a593Smuzhiyun
223*4882a593Smuzhiyunadb_stop()
224*4882a593Smuzhiyun{
225*4882a593Smuzhiyun	usb_stop_daemon /usr/bin/adbd
226*4882a593Smuzhiyun}
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun# ---- ntb
229*4882a593SmuzhiyunNTB_INSTANCES=${NTB_INSTANCES:-ffs.ntb}
230*4882a593Smuzhiyun
231*4882a593Smuzhiyunntb_prepare()
232*4882a593Smuzhiyun{
233*4882a593Smuzhiyun	usb_mount ntb /dev/usb-ffs/ntb -o uid=2000,gid=2000 -t functionfs
234*4882a593Smuzhiyun}
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun# ---- uac1
237*4882a593Smuzhiyunuac1_prepare()
238*4882a593Smuzhiyun{
239*4882a593Smuzhiyun	for f in $(find . -name "*_feature_unit"); do
240*4882a593Smuzhiyun		echo 1 >$f
241*4882a593Smuzhiyun	done
242*4882a593Smuzhiyun}
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun# ---- uac2
245*4882a593Smuzhiyunuac2_prepare()
246*4882a593Smuzhiyun{
247*4882a593Smuzhiyun	uac1_prepare
248*4882a593Smuzhiyun}
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun# ---- mtp
251*4882a593Smuzhiyunmtp_prepare()
252*4882a593Smuzhiyun{
253*4882a593Smuzhiyun	echo "MTP" > os_desc/interface.MTP/compatible_id
254*4882a593Smuzhiyun	echo 1 > $USB_GADGET_DIR/os_desc/use
255*4882a593Smuzhiyun}
256*4882a593Smuzhiyun
257*4882a593Smuzhiyunmtp_start()
258*4882a593Smuzhiyun{
259*4882a593Smuzhiyun	usb_start_daemon /usr/bin/mtp-server
260*4882a593Smuzhiyun	usb_wait_files /dev/mtp_usb
261*4882a593Smuzhiyun}
262*4882a593Smuzhiyun
263*4882a593Smuzhiyunmtp_stop()
264*4882a593Smuzhiyun{
265*4882a593Smuzhiyun	usb_stop_daemon /usr/bin/mtp-server
266*4882a593Smuzhiyun	usb_release_files /dev/mtp_usb
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun	echo 0 > $USB_GADGET_DIR/os_desc/use
269*4882a593Smuzhiyun}
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun# ---- acm
272*4882a593SmuzhiyunACM_INSTANCES=${ACM_INSTANCES:-acm.gs6}
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun# ---- rndis
275*4882a593Smuzhiyun# Nothing special
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun# ---- uvc
278*4882a593SmuzhiyunUVC_INSTANCES=${UVC_INSTANCES:-uvc.gs6}
279*4882a593Smuzhiyun
280*4882a593Smuzhiyunuvc_add_yuyv()
281*4882a593Smuzhiyun{
282*4882a593Smuzhiyun	WIDTH=$(echo $1 | cut -d'x' -f1)
283*4882a593Smuzhiyun	HEIGHT=$(echo $1 | cut -d'x' -f2)
284*4882a593Smuzhiyun	DIR=${HEIGHT}p
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun	[ ! -d $DIR ] || return 0
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun	mkdir -p $DIR
289*4882a593Smuzhiyun	echo $WIDTH > $DIR/wWidth
290*4882a593Smuzhiyun	echo $HEIGHT > $DIR/wHeight
291*4882a593Smuzhiyun	echo 333333 > $DIR/dwDefaultFrameInterval
292*4882a593Smuzhiyun	echo $((WIDTH * HEIGHT * 20)) > $DIR/dwMinBitRate
293*4882a593Smuzhiyun	echo $((WIDTH * HEIGHT * 20)) > $DIR/dwMaxBitRate
294*4882a593Smuzhiyun	echo $((WIDTH * HEIGHT * 2)) > $DIR/dwMaxVideoFrameBufferSize
295*4882a593Smuzhiyun	echo -e "333333\n666666\n1000000\n2000000" > $DIR/dwFrameInterval
296*4882a593Smuzhiyun}
297*4882a593Smuzhiyun
298*4882a593Smuzhiyunuvc_add_mjpeg()
299*4882a593Smuzhiyun{
300*4882a593Smuzhiyun	WIDTH=$(echo $1 | cut -d'x' -f1)
301*4882a593Smuzhiyun	HEIGHT=$(echo $1 | cut -d'x' -f2)
302*4882a593Smuzhiyun	DIR=${HEIGHT}p
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun	[ ! -d $DIR ] || return 0
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun	mkdir -p $DIR
307*4882a593Smuzhiyun	echo $WIDTH > $DIR/wWidth
308*4882a593Smuzhiyun	echo $HEIGHT > $DIR/wHeight
309*4882a593Smuzhiyun	echo 333333 > $DIR/dwDefaultFrameInterval
310*4882a593Smuzhiyun	echo $((WIDTH * HEIGHT * 20)) > $DIR/dwMinBitRate
311*4882a593Smuzhiyun	echo $((WIDTH * HEIGHT * 20)) > $DIR/dwMaxBitRate
312*4882a593Smuzhiyun	echo $((WIDTH * HEIGHT * 2)) > $DIR/dwMaxVideoFrameBufferSize
313*4882a593Smuzhiyun	echo -e "333333\n666666\n1000000\n2000000" > $DIR/dwFrameInterval
314*4882a593Smuzhiyun}
315*4882a593Smuzhiyun
316*4882a593Smuzhiyunuvc_add_h264()
317*4882a593Smuzhiyun{
318*4882a593Smuzhiyun	WIDTH=$(echo $1 | cut -d'x' -f1)
319*4882a593Smuzhiyun	HEIGHT=$(echo $1 | cut -d'x' -f2)
320*4882a593Smuzhiyun	DIR=${HEIGHT}p
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun	[ ! -d $DIR ] || return 0
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun	mkdir -p $DIR
325*4882a593Smuzhiyun	echo $WIDTH > $DIR/wWidth
326*4882a593Smuzhiyun	echo $HEIGHT > $DIR/wHeight
327*4882a593Smuzhiyun	echo 333333 > $DIR/dwDefaultFrameInterval
328*4882a593Smuzhiyun	echo $((WIDTH * HEIGHT * 10)) > $DIR/dwMinBitRate
329*4882a593Smuzhiyun	echo $((WIDTH * HEIGHT * 10)) > $DIR/dwMaxBitRate
330*4882a593Smuzhiyun	echo -e "333333\n666666\n1000000\n2000000" > $DIR/dwFrameInterval
331*4882a593Smuzhiyun}
332*4882a593Smuzhiyun
333*4882a593Smuzhiyunuvc_support_resolutions()
334*4882a593Smuzhiyun{
335*4882a593Smuzhiyun	case ${1:-yuyv} in
336*4882a593Smuzhiyun		yuyv)	echo "640x480 1280x720";;
337*4882a593Smuzhiyun		mjpeg)	echo "640x480 1280x720 1920x1080 2560x1440 2592x1944";;
338*4882a593Smuzhiyun		h264)	echo "640x480 1280x720 1920x1080";;
339*4882a593Smuzhiyun	esac
340*4882a593Smuzhiyun}
341*4882a593Smuzhiyun
342*4882a593Smuzhiyunuvc_prepare()
343*4882a593Smuzhiyun{
344*4882a593Smuzhiyun	UVC_DIR=$(pwd)
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun	usb_symlink $UVC_DIR/control/header/h $UVC_DIR/control/class/fs/h
347*4882a593Smuzhiyun	usb_symlink $UVC_DIR/control/header/h $UVC_DIR/control/class/ss/h
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun	usb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/fs/h
350*4882a593Smuzhiyun	usb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/hs/h
351*4882a593Smuzhiyun	usb_symlink $UVC_DIR/streaming/header/h $UVC_DIR/streaming/class/ss/h
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun	UVC_YUYV_RES=$(uvc_support_resolutions yuyv)
354*4882a593Smuzhiyun	if [ -n "$UVC_YUYV_RES" ]; then
355*4882a593Smuzhiyun		usb_try_symlink $UVC_DIR/streaming/uncompressed/u \
356*4882a593Smuzhiyun			$UVC_DIR/streaming/header/h/u
357*4882a593Smuzhiyun		cd $UVC_DIR/streaming/uncompressed/u
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun		for res in $UVC_YUYV_RES; do
360*4882a593Smuzhiyun			uvc_add_yuyv $res
361*4882a593Smuzhiyun		done
362*4882a593Smuzhiyun	fi
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun	UVC_MJPEG_RES=$(uvc_support_resolutions mjpeg)
365*4882a593Smuzhiyun	if [ -n "$UVC_MJPEG_RES" ]; then
366*4882a593Smuzhiyun		usb_try_symlink $UVC_DIR/streaming/mjpeg/m \
367*4882a593Smuzhiyun			$UVC_DIR/streaming/header/h/m
368*4882a593Smuzhiyun		cd $UVC_DIR/streaming/mjpeg/m
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun		for res in $UVC_MJPEG_RES; do
371*4882a593Smuzhiyun			uvc_add_mjpeg $res
372*4882a593Smuzhiyun		done
373*4882a593Smuzhiyun	fi
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun	UVC_H264_RES=$(uvc_support_resolutions h264)
376*4882a593Smuzhiyun	if [ -n "$UVC_H264_RES" ]; then
377*4882a593Smuzhiyun		usb_try_symlink $UVC_DIR/streaming/framebased/f \
378*4882a593Smuzhiyun			$UVC_DIR/streaming/header/h/f
379*4882a593Smuzhiyun		cd $UVC_DIR/streaming/framebased/f
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun		for res in $UVC_H264_RES; do
382*4882a593Smuzhiyun			uvc_add_h264 $res
383*4882a593Smuzhiyun		done
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun		usb_try_write -ne guidFormat "\\x48\\x32\\x36\\x34\\x00\\x00\\x10\\x00\\x80\\x00\\x00\\xaa\\x00\\x38\\x9b\\x71"
386*4882a593Smuzhiyun	fi
387*4882a593Smuzhiyun}
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun# TODO: Start UVC daemon in uvc_start
390*4882a593Smuzhiyun# TODO: Stop UVC daemon in uvc_stop
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun# ---- hid
393*4882a593SmuzhiyunHID_INSTANCES=${HID_INSTANCES:-hid.usb0}
394*4882a593Smuzhiyun
395*4882a593Smuzhiyunhid_prepare()
396*4882a593Smuzhiyun{
397*4882a593Smuzhiyun	echo 1 > protocol
398*4882a593Smuzhiyun	echo 1 > subclass
399*4882a593Smuzhiyun	echo 8 > report_length
400*4882a593Smuzhiyun	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" \
401*4882a593Smuzhiyun		> report_desc
402*4882a593Smuzhiyun}
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun# ---- ums
405*4882a593SmuzhiyunUMS_INSTANCES=${UMS_INSTANCES:-mass_storage.0}
406*4882a593Smuzhiyun
407*4882a593Smuzhiyunums_prepare()
408*4882a593Smuzhiyun{
409*4882a593Smuzhiyun	if [ ! -f "$UMS_FILE" ]; then
410*4882a593Smuzhiyun		usb_msg "Formating $UMS_FILE($UMS_SIZE) to $UMS_FSTYPE"
411*4882a593Smuzhiyun		truncate -s $UMS_SIZE "$UMS_FILE"
412*4882a593Smuzhiyun		mkfs.$UMS_FSTYPE "$UMS_FILE" || \
413*4882a593Smuzhiyun			usb_msg "Failed to format $UMS_FILE to $UMS_FSTYPE"
414*4882a593Smuzhiyun	fi
415*4882a593Smuzhiyun}
416*4882a593Smuzhiyun
417*4882a593Smuzhiyunums_stop()
418*4882a593Smuzhiyun{
419*4882a593Smuzhiyun	echo > lun.0/file
420*4882a593Smuzhiyun	usb_umount "$UMS_MOUNTPOINT"
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun	[ "$UMS_MOUNT" -eq 1 ] || return 0
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun	# Try auto fstype firstly
425*4882a593Smuzhiyun	usb_mount "$UMS_FILE" "$UMS_MOUNTPOINT" -o sync 2>/dev/null || \
426*4882a593Smuzhiyun		usb_mount "$UMS_FILE" "$UMS_MOUNTPOINT" -o sync -t $UMS_FSTYPE
427*4882a593Smuzhiyun}
428*4882a593Smuzhiyun
429*4882a593Smuzhiyunums_start()
430*4882a593Smuzhiyun{
431*4882a593Smuzhiyun	case "$USB_STATE" in
432*4882a593Smuzhiyun		CONFIGURED)
433*4882a593Smuzhiyun			if [ "$(cat lun.0/ro)" != "$UMS_RO" ]; then
434*4882a593Smuzhiyun				echo > lun.0/file
435*4882a593Smuzhiyun				echo $UMS_RO > lun.0/ro
436*4882a593Smuzhiyun			fi
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun			if ! grep -wq "$UMS_FILE" lun.0/file; then
439*4882a593Smuzhiyun				usb_umount "$UMS_MOUNTPOINT"
440*4882a593Smuzhiyun				echo "$UMS_FILE" > lun.0/file
441*4882a593Smuzhiyun			fi
442*4882a593Smuzhiyun			;;
443*4882a593Smuzhiyun		DISCONNECTED)
444*4882a593Smuzhiyun			ums_stop
445*4882a593Smuzhiyun			;;
446*4882a593Smuzhiyun	esac
447*4882a593Smuzhiyun}
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun# ---- global
450*4882a593Smuzhiyunusb_init()
451*4882a593Smuzhiyun{
452*4882a593Smuzhiyun	usb_msg "Initializing"
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun	echo 0x2207 > idVendor
455*4882a593Smuzhiyun	echo 0x0310 > bcdDevice
456*4882a593Smuzhiyun	echo 0x0200 > bcdUSB
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun	mkdir -p $USB_GADGET_STRINGS_DIR
459*4882a593Smuzhiyun	SERIAL=$(grep Serial /proc/cpuinfo | cut -d':' -f2)
460*4882a593Smuzhiyun	echo ${SERIAL:-0123456789ABCDEF} > $USB_GADGET_STRINGS_DIR/serialnumber
461*4882a593Smuzhiyun	echo $USB_GROUP  > $USB_GADGET_STRINGS_DIR/manufacturer
462*4882a593Smuzhiyun	echo "rk3xxx"  > $USB_GADGET_STRINGS_DIR/product
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun	mkdir -p $USB_CONFIGS_DIR
465*4882a593Smuzhiyun	echo 500 > $USB_CONFIGS_DIR/MaxPower
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun	echo 0x1 > os_desc/b_vendor_code
468*4882a593Smuzhiyun	echo MSFT100 > os_desc/qw_sign
469*4882a593Smuzhiyun	ln -s $USB_CONFIGS_DIR os_desc/
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun	mkdir -p $USB_CONFIGS_STRINGS_DIR
472*4882a593Smuzhiyun}
473*4882a593Smuzhiyun
474*4882a593Smuzhiyunusb_funcs_grep()
475*4882a593Smuzhiyun{
476*4882a593Smuzhiyun	echo $USB_FUNCS | xargs -n 1 | sort | uniq | grep $@ || true
477*4882a593Smuzhiyun}
478*4882a593Smuzhiyun
479*4882a593Smuzhiyunusb_funcs_sort()
480*4882a593Smuzhiyun{
481*4882a593Smuzhiyun	{
482*4882a593Smuzhiyun		for func in $@; do
483*4882a593Smuzhiyun			usb_funcs_grep -E $func
484*4882a593Smuzhiyun		done
485*4882a593Smuzhiyun		usb_funcs_grep -vE $(echo $@ | tr ' ' '|')
486*4882a593Smuzhiyun	} | uniq | xargs
487*4882a593Smuzhiyun}
488*4882a593Smuzhiyun
489*4882a593Smuzhiyunusb_prepare()
490*4882a593Smuzhiyun{
491*4882a593Smuzhiyun	usb_load_config
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun	# Allow function/variable overriding
494*4882a593Smuzhiyun	[ -d /etc/usbdevice.d ] && . /etc/usbdevice.d/*
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun	UMS_FILE=${UMS_FILE:-/userdata/ums_shared.img}
497*4882a593Smuzhiyun	UMS_SIZE=${UMS_SIZE:-256M}
498*4882a593Smuzhiyun	UMS_FSTYPE=${UMS_FSTYPE:-vfat}
499*4882a593Smuzhiyun	UMS_MOUNT=${UMS_MOUNT:-0}
500*4882a593Smuzhiyun	UMS_MOUNTPOINT="${UMS_MOUNTPOINT:-/mnt/ums}"
501*4882a593Smuzhiyun	UMS_RO=${UMS_RO:-0}
502*4882a593Smuzhiyun	USB_FUNCS=${USB_FUNCS:-adb}
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun	# Orders required by kernel
505*4882a593Smuzhiyun	USB_FUNCS="$(usb_funcs_sort rndis uac uvc adb ntb ums mtp acm)"
506*4882a593Smuzhiyun	USB_CONFIG="$(echo "$USB_FUNCS" | tr ' ' '_')"
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun	if [ ! -d $USB_GADGET_DIR ]; then
509*4882a593Smuzhiyun		mountpoint -q $CONFIGFS_DIR || \
510*4882a593Smuzhiyun			mount -t configfs none $CONFIGFS_DIR
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun		mkdir -p $USB_GADGET_DIR
513*4882a593Smuzhiyun		cd $USB_GADGET_DIR
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun		# Global initialize
516*4882a593Smuzhiyun		usb_run_stage usb init
517*4882a593Smuzhiyun	fi
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun	USB_STATE=$(cat /sys/class/android_usb/android0/state)
520*4882a593Smuzhiyun	USB_UDC=$(ls /sys/class/udc/ | head -n 1)
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun	# Parse started USB functions
523*4882a593Smuzhiyun	OLD_FUNCS=$(usb_get_started)
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun	# Stop old USB functions when USB functions changed
526*4882a593Smuzhiyun	if [ -n "$OLD_FUNCS" ] && [ "$OLD_FUNCS" != "$USB_FUNCS" ]; then
527*4882a593Smuzhiyun		usb_msg "Functions changed $OLD_FUNCS -> $USB_FUNCS"
528*4882a593Smuzhiyun		usb_stop
529*4882a593Smuzhiyun	fi
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun	# Update USB PID
532*4882a593Smuzhiyun	usb_pid > $USB_GADGET_DIR/idProduct
533*4882a593Smuzhiyun}
534*4882a593Smuzhiyun
535*4882a593Smuzhiyunusb_start()
536*4882a593Smuzhiyun{
537*4882a593Smuzhiyun	usb_msg "Starting functions: $USB_FUNCS"
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun	echo "$USB_CONFIG" > $USB_CONFIGS_STRINGS_DIR/configuration
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun	for func in $USB_FUNCS; do
542*4882a593Smuzhiyun		for instance in $(usb_instances $func); do
543*4882a593Smuzhiyun			usb_msg "Preparing instance: $instance"
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun			if ! mkdir -p $USB_FUNCTIONS_DIR/$instance 2>/dev/null; then
546*4882a593Smuzhiyun				usb_msg "Failed to create instance: $instance"
547*4882a593Smuzhiyun				continue
548*4882a593Smuzhiyun			fi
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun			cd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continue
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun			usb_run_stage $func prepare
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun			# Make symlink after prepared (required by UVC)
555*4882a593Smuzhiyun			usb_symlink $USB_FUNCTIONS_DIR/$instance \
556*4882a593Smuzhiyun				$USB_CONFIGS_DIR/f-$instance
557*4882a593Smuzhiyun		done
558*4882a593Smuzhiyun	done
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun	usb_write $USB_GADGET_DIR/UDC $USB_UDC
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun	for func in $USB_FUNCS; do
563*4882a593Smuzhiyun		for instance in $(usb_instances $func); do
564*4882a593Smuzhiyun			cd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continue
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun			usb_msg "Starting instance: $instance"
567*4882a593Smuzhiyun			usb_run_stage $func start
568*4882a593Smuzhiyun		done
569*4882a593Smuzhiyun	done
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun	# Store started functions
572*4882a593Smuzhiyun	usb_set_started
573*4882a593Smuzhiyun}
574*4882a593Smuzhiyun
575*4882a593Smuzhiyunusb_stop()
576*4882a593Smuzhiyun{
577*4882a593Smuzhiyun	if [ -n "$OLD_FUNCS" ]; then
578*4882a593Smuzhiyun		usb_msg "Stopping functions: $OLD_FUNCS"
579*4882a593Smuzhiyun	fi
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun	usb_write $USB_GADGET_DIR/UDC ""
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun	for func in $USB_FUNCS; do
584*4882a593Smuzhiyun		for instance in $(usb_instances $func); do
585*4882a593Smuzhiyun			cd $USB_FUNCTIONS_DIR/$instance &>/dev/null || continue
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun			usb_msg "Stopping instance: $instance"
588*4882a593Smuzhiyun			usb_run_stage $func stop
589*4882a593Smuzhiyun		done
590*4882a593Smuzhiyun	done
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun	rm -f $USB_CONFIGS_DIR/f-*
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun	# Clear functions to avoid stopping them again
595*4882a593Smuzhiyun	unset OLD_FUNCS
596*4882a593Smuzhiyun}
597*4882a593Smuzhiyun
598*4882a593Smuzhiyunusb_restart()
599*4882a593Smuzhiyun{
600*4882a593Smuzhiyun	usb_run_stage usb stop
601*4882a593Smuzhiyun	usb_run_stage usb start
602*4882a593Smuzhiyun}
603*4882a593Smuzhiyun
604*4882a593SmuzhiyunACTION=${1:-update}
605*4882a593Smuzhiyunif [ "$ACTION" = update ]; then
606*4882a593Smuzhiyun	usb_is_enabled || exit 0
607*4882a593Smuzhiyunfi
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun# Lock it
610*4882a593Smuzhiyunexec 3<$0
611*4882a593Smuzhiyunflock -x 3
612*4882a593Smuzhiyun
613*4882a593Smuzhiyunecho "Starting $0 ${ACTION}, log saved to $LOG_FILE"
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun# Redirect outputs to log file
616*4882a593Smuzhiyunexec >>$LOG_FILE 2>&1
617*4882a593Smuzhiyun
618*4882a593Smuzhiyunusb_msg "Handling ${ACTION} request"
619*4882a593Smuzhiyun
620*4882a593Smuzhiyunusb_run_stage usb prepare
621*4882a593Smuzhiyun
622*4882a593Smuzhiyuncase "$ACTION" in
623*4882a593Smuzhiyun	start|update)
624*4882a593Smuzhiyun		usb_enable
625*4882a593Smuzhiyun		usb_run_stage usb start
626*4882a593Smuzhiyun		;;
627*4882a593Smuzhiyun	stop)
628*4882a593Smuzhiyun		usb_disable
629*4882a593Smuzhiyun		usb_run_stage usb stop
630*4882a593Smuzhiyun		;;
631*4882a593Smuzhiyun	restart)
632*4882a593Smuzhiyun		usb_enable
633*4882a593Smuzhiyun		usb_run_stage usb restart
634*4882a593Smuzhiyun		;;
635*4882a593Smuzhiyun	*)
636*4882a593Smuzhiyun		echo "Usage: usbdevice [start|stop|restart|update]" >&2
637*4882a593Smuzhiyun		;;
638*4882a593Smuzhiyunesac
639*4882a593Smuzhiyun
640*4882a593Smuzhiyunusb_msg "Done $ACTION request"
641*4882a593Smuzhiyunecho
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun# Unlock it
644*4882a593Smuzhiyunflock -u 3
645