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