Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
orangepi-xunlong
GitHub Repository: orangepi-xunlong/orangepi-build
Path: blob/next/external/packages/bsp/ky/usr/bin/gadget-setup.sh
13273 views
1
#!/bin/bash
2
# In busybox ash, should use /bin/sh, but bianbu cannot use /bin/sh
3
4
name=`basename $0`
5
SCRIPT_VERSION="v0.5-SUPPORTROLESW"
6
CONFIG_FILE=$HOME/.usb_config
7
8
# USB Descriptors
9
VENDOR_ID="0x361c"
10
PRODUC_ID="0x0007"
11
MANUAF_STR="Ky"
12
PRODUC_STR="Ky Composite Device"
13
SERNUM_STR="20211102"
14
SN_PATH="/proc/device-tree/serial-number"
15
[ "$BOARD_SN" ] || BOARD_SN=$( [ -e $SN_PATH ] && tr -d '\000' < $SN_PATH )
16
[ "$BOARD_SN" ] && SERNUM_STR=$BOARD_SN
17
18
CONFIGFS=/sys/kernel/config
19
GADGET_PATH=$CONFIGFS/usb_gadget/ky
20
GFUNC_PATH=$GADGET_PATH/functions
21
GCONFIG=$GADGET_PATH/configs/c.1
22
[ "$USB_UDC" ] || USB_UDC=$(ls /sys/class/udc | awk "NR==1{print}")
23
24
# MSC Debug Ramdisk
25
RAMDISK_PATH=/var/sdcard
26
TMPFS_FOUND=`mount | grep tmpfs | grep -v devtmpfs | awk '{print $3}' | grep '/dev/shm' | wc -l`
27
[ "$TMPFS_FOUND" -eq 1 ] && RAMDISK_PATH=/dev/shm/sdcard
28
TMPFS_FOUND=`mount | grep tmpfs | grep -v devtmpfs | awk '{print $3}' | grep '/tmp' | wc -l`
29
[ "$TMPFS_FOUND" -eq 1 ] && RAMDISK_PATH=/tmp/sdcard
30
# SCSI Target
31
NAA="naa.6001405c3214b06a"
32
CORE_DIR=$CONFIGFS/target/core
33
USB_GDIR=$CONFIGFS/target/usb_gadget
34
35
# Global variables to record configured functions
36
MSC=disabled
37
UAS=disabled
38
UAS_ARG=""
39
MSC_ARG=""
40
ADB=disabled
41
UVC=disabled
42
RNDIS=disabled
43
FUNCTION_CNT=0
44
DEBUG=
45
46
usage()
47
{
48
echo "$name usage: "
49
echo ""
50
echo -e "Support Select functions in $CONFIG_FILE:"
51
echo -e "\tWrite <func>:<arg> line in $CONFIG_FILE, then run:"
52
echo -e "\t$name [start|stop|reload|config]"
53
echo -e "Or Select functions manually:"
54
echo -e "\t$name <function1>(,<function2>...)"
55
echo -e "Set USB connection:"
56
echo -e "\t$name [pause|resume]"
57
echo -e "\n$name info: show gadget info"
58
echo -e "\nhint: udc is automatically selected, you can"
59
echo -e "\toverride udc with env USB_UDC_IDX=[integer]/USB_UDC=[str]"
60
echo -e "Set USB role-switch:"
61
echo -e "\t$name role <rolesw-name> [host|device]"
62
echo ""
63
echo "Functions and arguments supported:"
64
echo -e "\tmsc(:dev/file) Mass Storage(Bulk-Only)."
65
echo -e "\tuas(:dev/file) Mass Storage(UASP)."
66
echo -e "\tadb Android Debug Bridge over USB."
67
echo -e "\tuvc Webcam."
68
echo -e "\trndis RNDIS NIC function."
69
echo -e "\nKy gadget-setup tool $SCRIPT_VERSION"
70
echo ""
71
}
72
73
gadget_info()
74
{
75
echo "$name: $1"
76
}
77
78
gadget_debug()
79
{
80
[ $DEBUG ] && echo "$name: $1"
81
}
82
83
die()
84
{
85
gadget_info "$1"
86
exit 1
87
}
88
89
g_remove()
90
{
91
[ -h $1 ] && rm -f $1
92
[ -d $1 ] && rmdir $1
93
[ -e $1 ] && rm -f $1
94
}
95
96
## MSC
97
98
msc_ramdisk_()
99
{
100
# Debug Ramdisk for MSC without any argument
101
gadget_info "msc: ramdisk: $RAMDISK_PATH/disk.img"
102
mkdir -p $RAMDISK_PATH/sda
103
dd if=/dev/zero of=$RAMDISK_PATH/disk.img bs=1M count=1038
104
mkdosfs -F 32 $RAMDISK_PATH/disk.img
105
}
106
107
msc_config()
108
{
109
gadget_debug "add a msc function instance"
110
MSC_DIR=$GFUNC_PATH/mass_storage.usb0
111
mkdir -p $MSC_DIR
112
DEVICE=$1
113
[ $DEVICE ] || DEVICE=$MSC_ARG
114
# Create a backstore
115
if [ -z "$DEVICE" ]; then
116
echo "$name: no device specificed, select ramdisk as backstore"
117
msc_ramdisk_
118
echo "tmp files would be created in: $RAMDISK_PATH"
119
echo "$RAMDISK_PATH/disk.img" > $MSC_DIR/lun.0/file
120
elif [ -b $DEVICE ]; then
121
echo "$name: block device"
122
echo "$DEVICE" > $MSC_DIR/lun.0/file
123
else
124
echo "$name: other path, regular file"
125
echo "$DEVICE" > $MSC_DIR/lun.0/file
126
fi
127
128
echo 1 > $MSC_DIR/lun.0/removable
129
echo 0 > $MSC_DIR/lun.0/nofua
130
}
131
132
msc_link()
133
{
134
gadget_debug "add msc to usb config"
135
ln -s $MSC_DIR $GCONFIG/mass_storage.usb0
136
}
137
138
msc_unlink()
139
{
140
gadget_debug "remove msc from usb config"
141
g_remove $GCONFIG/mass_storage.usb0
142
}
143
144
msc_clean()
145
{
146
gadget_debug "clean msc"
147
g_remove $GFUNC_PATH/mass_storage.usb0
148
g_remove $RAMDISK_PATH/disk.img
149
g_remove $RAMDISK_PATH/sda
150
}
151
152
## UAS
153
154
uas_config()
155
{
156
gadget_debug "add a uas function instance"
157
# Load the target modules and mount the add a file function instance system
158
# Uncomment these if modules not built-in:
159
# lsmod | grep -q configfs || modprobe configfs
160
# lsmod | grep -q target_core_mod || modprobe target_core_mod
161
DEVICE=$1
162
[ $DEVICE ] || DEVICE=$UAS_ARG
163
mkdir -p $GADGET_PATH/functions/tcm.0
164
# Create a backstore
165
if [ -z "$DEVICE" ]; then
166
echo "$name: no device specificed, select rd_mcp as backstore"
167
BACKSTORE_DIR=$CORE_DIR/rd_mcp_0/ramdisk
168
mkdir -p $BACKSTORE_DIR
169
# ramdisk
170
echo rd_pages=200000 > $BACKSTORE_DIR/control
171
elif [ -b $DEVICE ]; then
172
echo "$name: block device, select iblock as backstore"
173
BACKSTORE_DIR=$CORE_DIR/iblock_0/iblock
174
mkdir -p $BACKSTORE_DIR
175
echo "udev_path=${DEVICE}" > $BACKSTORE_DIR/control
176
else
177
echo "$name: other path, select fileio as backstore"
178
BACKSTORE_DIR=$CORE_DIR/fileio_0/fileio
179
mkdir -p $BACKSTORE_DIR
180
DEVICE_SIZE=$(du -b $DEVICE | cut -f1)
181
echo "fd_dev_name=${DEVICE},fd_dev_size=${DEVICE_SIZE}" > $BACKSTORE_DIR/control
182
# echo 1 > $BACKSTORE_DIR/attrib/emulate_write_cache
183
fi
184
[ -n "$DEVICE" ] && umount $DEVICE
185
echo 1 > $BACKSTORE_DIR/enable
186
echo "$name: NAA of target: $NAA"
187
# Create an NAA target and a target portal group (TPG)
188
mkdir -p $USB_GDIR/$NAA/tpgt_1/
189
echo "$name tpgt_1 has lun_0"
190
# Create a LUN
191
mkdir $USB_GDIR/$NAA/tpgt_1/lun/lun_0
192
# Nexus initiator on target port 1 to $NAA
193
echo $NAA > $USB_GDIR/$NAA/tpgt_1/nexus
194
195
# Allow write access for non authenticated initiators
196
# echo 0 > $USB_GDIR/$NAA/tpgt_1/attrib/demo_mode_write_protect
197
ln -s $BACKSTORE_DIR $USB_GDIR/$NAA/tpgt_1/lun/lun_0/data
198
#ln -s $BACKSTORE_DIR $USB_GDIR/$NAA/tpgt_1/lun/lun_0/virtual_scsi_port
199
# echo 15 > $USB_GDIR/$NAA/tpgt_1/maxburst
200
201
# Enable the target portal group, with 1 lun
202
echo 1 > $USB_GDIR/$NAA/tpgt_1/enable
203
}
204
205
uas_link()
206
{
207
gadget_debug "add uas to usb config"
208
ln -s $GADGET_PATH/functions/tcm.0 $GCONFIG/tcm.0
209
}
210
211
uas_unlink()
212
{
213
gadget_debug "remove uas from usb config"
214
g_remove $GCONFIG/tcm.0
215
}
216
217
uas_clean()
218
{
219
gadget_debug "clean uas"
220
[ -d "$USB_GDIR/$NAA/tpgt_1/enable" ] && echo 0 > $USB_GDIR/$NAA/tpgt_1/enable
221
g_remove $USB_GDIR/$NAA/tpgt_1/lun/lun_0/data
222
g_remove $USB_GDIR/$NAA/tpgt_1/lun/lun_0/virtual_scsi_port
223
g_remove $USB_GDIR/$NAA/tpgt_1/lun/lun_0
224
g_remove $USB_GDIR/$NAA/tpgt_1/
225
g_remove $USB_GDIR/$NAA/
226
g_remove $USB_GDIR
227
BACKSTORE_DIR=$CORE_DIR/iblock_0/iblock
228
g_remove $BACKSTORE_DIR
229
BACKSTORE_DIR=$CORE_DIR/fileio_0/fileio
230
g_remove $BACKSTORE_DIR
231
BACKSTORE_DIR=$CORE_DIR/rd_mcp_0/ramdisk
232
g_remove $BACKSTORE_DIR
233
g_remove $GADGET_PATH/functions/tcm.0
234
}
235
236
## ADB
237
238
adb_config()
239
{
240
gadget_debug "add a adb function instance"
241
mkdir $GFUNC_PATH/ffs.adb
242
}
243
244
adb_link()
245
{
246
gadget_debug "add adb to usb config"
247
ln -s $GFUNC_PATH/ffs.adb/ $GCONFIG/ffs.adb
248
mkdir /dev/usb-ffs
249
mkdir /dev/usb-ffs/adb
250
mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb/
251
#mkdir /dev/pts
252
#mount -t devpts -o defaults,mode=644,ptmxmode=666 devpts /dev/pts
253
adbd &
254
sleep 1
255
}
256
257
adb_unlink()
258
{
259
gadget_debug "remove adb from usb config"
260
killall adbd
261
g_remove $GCONFIG/ffs.adb
262
[ -e /dev/usb-ffs/adb/ ] && umount /dev/usb-ffs/adb/
263
#[ -e /dev/pts ] && umount /dev/pts
264
#g_remove /dev/pts
265
g_remove /dev/usb-ffs/adb
266
g_remove /dev/usb-ffs
267
}
268
269
adb_clean()
270
{
271
gadget_debug "clean adb"
272
g_remove $GFUNC_PATH/ffs.adb
273
}
274
275
## UVC
276
277
### Setup streaming/ directory.
278
add_uvc_fmt_resolution()
279
{
280
FORMAT=$1 # $1 format "uncompressed/y" / "mjpeg/m"
281
UVC_DISPLAY_W=$2 # $2 Width
282
UVC_DISPLAY_H=$3 # $3 Height
283
FRAMERATE=$4 # $4 HIGH_FRAMERATE 0/1
284
#https://docs.kernel.org/usb/gadget_uvc.html
285
UVC_MJPEG_PRE_PATH=$GFUNC_PATH/$UVC_INSTANCE/streaming/$FORMAT
286
UVC_FRAME_WDIR=${UVC_MJPEG_PRE_PATH}/${UVC_DISPLAY_H}p
287
gadget_debug "UVC_FRAME_WDIR: $UVC_FRAME_WDIR"
288
mkdir -p $UVC_FRAME_WDIR
289
echo $UVC_DISPLAY_W > $UVC_FRAME_WDIR/wWidth
290
echo $UVC_DISPLAY_H > $UVC_FRAME_WDIR/wHeight
291
DW_MAX_VD_FB_SZ=$(( $UVC_DISPLAY_W * $UVC_DISPLAY_H * 2 ))
292
if [ "$FORMAT"=="mjpeg/m" ]; then
293
if [ -e "$CONFIG_FILE" ]; then
294
# Attempt to parse the dwMaxVideoFrameBufferSize from ~/.uvcg_config
295
parsed_value=$(grep "^mjpeg $UVC_DISPLAY_W $UVC_DISPLAY_H" ~/.uvcg_config | awk '{print $4}')
296
# Check if the value was found; if not, keep the pre-calculated value
297
if [ ! -z "$parsed_value" ]; then
298
DW_MAX_VD_FB_SZ="$parsed_value"
299
fi
300
gadget_debug "format: $FORMAT, dw_max_video_fb_size: $DW_MAX_VD_FB_SZ"
301
fi
302
fi
303
echo $DW_MAX_VD_FB_SZ > $UVC_FRAME_WDIR/dwMaxVideoFrameBufferSize
304
# Many camera host app only shows the default framerate of a format in their list
305
# So we set it here.
306
if [ "$FRAMERATE" -eq 20 ]; then
307
echo 500000 > $UVC_FRAME_WDIR/dwDefaultFrameInterval
308
elif [ "$FRAMERATE" -eq 15 ]; then
309
echo 666666 > $UVC_FRAME_WDIR/dwDefaultFrameInterval
310
elif [ "$FRAMERATE" -eq 30 ]; then
311
echo 333333 > $UVC_FRAME_WDIR/dwDefaultFrameInterval
312
elif [ "$FRAMERATE" -eq 60 ]; then
313
echo 166666 > $UVC_FRAME_WDIR/dwDefaultFrameInterval
314
elif [ "$FRAMERATE" -eq 10 ]; then
315
echo 1000000 > $UVC_FRAME_WDIR/dwDefaultFrameInterval
316
fi
317
# lowest framerate in this script is 10fps
318
DW_MIN_BITRATE=$(( 10 * $DW_MAX_VD_FB_SZ * 8 ))
319
DW_MAX_BITRATE=$(( $FRAMERATE * $DW_MAX_VD_FB_SZ * 8 ))
320
if [ "$FORMAT"=="mjpeg/m" ]; then
321
# MJPEG can compress the data at least 5:1,
322
# let's set the ratio to 4
323
DW_MIN_BITRATE=$(( $DW_MIN_BITRATE / 4 ))
324
gadget_debug "format: $FORMAT, dw_min_br: $DW_MIN_BITRATE"
325
fi
326
echo $DW_MIN_BITRATE > $UVC_FRAME_WDIR/dwMinBitRate
327
echo $DW_MAX_BITRATE > $UVC_FRAME_WDIR/dwMaxBitRate
328
echo -e "\t$UVC_INSTANCE will support ${FORMAT} ${UVC_DISPLAY_W}x${UVC_DISPLAY_H}@${FRAMERATE}p"
329
cat <<EOF > $UVC_FRAME_WDIR/dwFrameInterval
330
166666
331
333333
332
416667
333
500000
334
666666
335
1000000
336
EOF
337
}
338
339
destroy_one_uvc_format_()
340
{
341
FORMAT=$1
342
UVC_MJPEG_PRE_PATH=$GFUNC_PATH/$UVC_INSTANCE/streaming/$FORMAT
343
for ppath in ${UVC_MJPEG_PRE_PATH}/*p; do
344
g_remove $ppath
345
done
346
}
347
348
destroy_all_uvc_format_()
349
{
350
351
destroy_one_uvc_format_ uncompressed/y
352
g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/uncompressed/y
353
destroy_one_uvc_format_ mjpeg/m
354
g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/mjpeg/m
355
}
356
357
create_uvc_link_()
358
{
359
mkdir $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h
360
ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/mjpeg/m/ $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/m
361
ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/uncompressed/y/ $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/y
362
ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/ $GFUNC_PATH/$UVC_INSTANCE/streaming/class/fs
363
ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/ $GFUNC_PATH/$UVC_INSTANCE/streaming/class/hs
364
ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/ $GFUNC_PATH/$UVC_INSTANCE/streaming/class/ss
365
mkdir $GFUNC_PATH/$UVC_INSTANCE/control/header/h
366
ln -s $GFUNC_PATH/$UVC_INSTANCE/control/header/h/ $GFUNC_PATH/$UVC_INSTANCE/control/class/fs/
367
ln -s $GFUNC_PATH/$UVC_INSTANCE/control/header/h/ $GFUNC_PATH/$UVC_INSTANCE/control/class/ss/
368
}
369
370
destroy_uvc_link_()
371
{
372
g_remove $GFUNC_PATH/$UVC_INSTANCE/control/class/fs/h
373
g_remove $GFUNC_PATH/$UVC_INSTANCE/control/class/ss/h
374
g_remove $GFUNC_PATH/$UVC_INSTANCE/control/header/h
375
g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/class/ss/h
376
g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/class/hs/h
377
g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/class/fs/h
378
g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/m
379
g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/y
380
g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h
381
}
382
383
destroy_uvc_()
384
{
385
destroy_uvc_link_
386
destroy_all_uvc_format_
387
g_remove $GFUNC_PATH/$UVC_INSTANCE
388
}
389
390
set_uvc_maxpacket_()
391
{
392
MAX=$1 ## $1 1024/2048/3072
393
BURST=$2 ## $2 1-15
394
FUNCTION=$GFUNC_PATH/$UVC_INSTANCE
395
echo -e "\t$UVC_INSTANCE set streaming_maxpacket=$MAX, streaming_maxburst=$BURST"
396
echo $MAX > $FUNCTION/streaming_maxpacket
397
echo $BURST > $FUNCTION/streaming_maxburst
398
}
399
400
uvc_config()
401
{
402
UVC_INSTANCE=uvc.0
403
gadget_info "Adding a uvc function instance $UVC_INSTANCE..."
404
mkdir -p $GFUNC_PATH/$UVC_INSTANCE
405
# add_uvc_fmt_resolution <format> <width> <height> <framerate>
406
add_uvc_fmt_resolution uncompressed/y 320 240 30
407
add_uvc_fmt_resolution uncompressed/y 640 360 30
408
add_uvc_fmt_resolution uncompressed/y 640 480 30
409
add_uvc_fmt_resolution uncompressed/y 640 640 30
410
add_uvc_fmt_resolution uncompressed/y 1280 720 30
411
add_uvc_fmt_resolution uncompressed/y 1920 1080 30
412
add_uvc_fmt_resolution uncompressed/y 3840 2160 30
413
add_uvc_fmt_resolution mjpeg/m 640 360 30
414
add_uvc_fmt_resolution mjpeg/m 640 480 30
415
add_uvc_fmt_resolution mjpeg/m 1280 720 30
416
add_uvc_fmt_resolution mjpeg/m 1920 1080 30
417
add_uvc_fmt_resolution mjpeg/m 3840 2160 30
418
set_uvc_maxpacket_ 3072 15
419
create_uvc_link_
420
}
421
422
uvc_link()
423
{
424
gadget_debug "add uvc to usb config, unlike adb, you have to run ur own uvc-gadget app"
425
UVC_INSTANCE=uvc.0
426
ln -s $GFUNC_PATH/$UVC_INSTANCE/ $GCONFIG/$UVC_INSTANCE
427
}
428
429
uvc_unlink()
430
{
431
gadget_debug "remove uvc from usb config"
432
UVC_INSTANCE=uvc.0
433
g_remove $GCONFIG/$UVC_INSTANCE
434
}
435
436
uvc_clean()
437
{
438
gadget_debug "clean uvc"
439
UVC_INSTANCE=uvc.0
440
destroy_uvc_
441
}
442
443
## RNDIS
444
445
rndis_config()
446
{
447
OVERRIDE_VENDOR_FOR_WINDOWS=$1
448
# create function instance
449
# functions/<f_function allowed>.<instance name>
450
# f_function allowed: rndis
451
mkdir -p $GFUNC_PATH/rndis.0
452
}
453
454
rndis_link()
455
{
456
457
# Add Microsoft os descriptors to ensure
458
# Windows recognize us as an RNDIS compatible device
459
# thus no need to install driver manually.
460
# Verified on Windows 10.
461
echo 0xEF > $GADGET_PATH/bDeviceClass
462
echo 0x02 > $GADGET_PATH/bDeviceSubClass
463
echo 0x01 > $GADGET_PATH/bDeviceProtocol
464
echo 1 > $GADGET_PATH/os_desc/use
465
echo 0x1 > $GADGET_PATH/os_desc/b_vendor_code
466
echo "MSFT100" > $GADGET_PATH/os_desc/qw_sign
467
mkdir -p $GFUNC_PATH/rndis.0/os_desc/interface.rndis
468
echo RNDIS > $GFUNC_PATH/rndis.0/os_desc/interface.rndis/compatible_id
469
echo 5162001 > $GFUNC_PATH/rndis.0/os_desc/interface.rndis/sub_compatible_id
470
ln -s $GADGET_PATH/configs/c.1 $GADGET_PATH/os_desc/c.1
471
472
ln -s $GFUNC_PATH/rndis.0 $GCONFIG
473
HOST_ADDR=`cat $GFUNC_PATH/rndis.0/host_addr`
474
DEV_ADDR=`cat $GFUNC_PATH/rndis.0/dev_addr`
475
IFNAME=`cat $GFUNC_PATH/rndis.0/ifname`
476
gadget_info "rndis function enabled, mac(h): $HOST_ADDR, mac(g): $DEV_ADDR, ifname: $IFNAME."
477
gadget_info "execute ifconfig $IFNAME up to enable rndis iface."
478
}
479
480
rndis_unlink()
481
{
482
[ -e $GFUNC_PATH/rndis.0/ifname ] && ifconfig `cat $GFUNC_PATH/rndis.0/ifname` down
483
g_remove $GCONFIG/rndis.0
484
}
485
486
rndis_clean()
487
{
488
g_remove $GFUNC_PATH/rndis.0
489
}
490
491
## MTP
492
493
mtp_config()
494
{
495
die "MTP Not Supported yet."
496
}
497
498
mtp_link()
499
{
500
die "MTP Not Supported yet."
501
}
502
503
mtp_unlink()
504
{
505
die "MTP Not Supported yet."
506
}
507
508
mtp_clean()
509
{
510
die "MTP Not Supported yet."
511
}
512
513
## GADGET
514
no_udc()
515
{
516
gadget_info "Echo none to udc"
517
gadget_info "We are now trying to echo None to UDC......"
518
[ -e $GADGET_PATH/UDC ] || die "gadget not configured yet"
519
[ `cat $GADGET_PATH/UDC` ] && echo "" > $GADGET_PATH/UDC
520
gadget_info "echo none to UDC successfully done"
521
gadget_info "echo none to UDC done."
522
}
523
524
give_hint_to_which_have_udc_()
525
{
526
for config_path in "/sys/kernel/config/usb_gadget/"*; do
527
udc_path="$config_path/UDC"
528
is_here=$(cat $udc_path | grep $selected_udc | wc -l)
529
if [ "$is_here" -gt 0 ]; then
530
gadget_info "ERROR: Your udc is occupied by: $udc_path"
531
fi
532
done
533
}
534
535
echo_udc()
536
{
537
[ -e $GADGET_PATH/UDC ] || die "gadget not configured yet"
538
[ `cat $GADGET_PATH/UDC` ] && die "UDC `cat $GADGET_PATH/UDC` already been set"
539
if [ "$USB_UDC_IDX" ]; then
540
selected_udc=$(ls /sys/class/udc | awk "NR==$USB_UDC_IDX{print}")
541
else
542
selected_udc=$USB_UDC
543
gadget_info "Selected udc by name: $selected_udc"
544
gadget_info "We are now trying to echo $selected_udc to UDC......"
545
fi
546
our_udc_occupied=$(cat /sys/kernel/config/usb_gadget/*/UDC | grep $selected_udc | wc -l)
547
if [ "$our_udc_occupied" -gt 0 ]; then
548
give_hint_to_which_have_udc_
549
gadget_info "ERROR: configfs preserved, run $name resume after conflict resolved"
550
exit 127
551
fi
552
echo $selected_udc > $GADGET_PATH/UDC
553
gadget_info "echo $selected_udc to UDC done"
554
}
555
556
gconfig()
557
{
558
gadget_info "config $VENDOR_ID/$PRODUC_ID/$SERNUM_STR/$MANUAF_STR/$PRODUC_STR."
559
mountpoint -q /sys/kernel/config || mount -t configfs none /sys/kernel/config
560
[ -e $GADGET_PATH ] && die "ERROR: gadget already configured, should run stop first"
561
mkdir $GADGET_PATH
562
echo $VENDOR_ID > $GADGET_PATH/idVendor
563
echo $PRODUC_ID > $GADGET_PATH/idProduct
564
mkdir $GADGET_PATH/strings/0x409
565
echo $SERNUM_STR > $GADGET_PATH/strings/0x409/serialnumber
566
echo $MANUAF_STR > $GADGET_PATH/strings/0x409/manufacturer
567
echo $PRODUC_STR > $GADGET_PATH/strings/0x409/product
568
mkdir $GCONFIG
569
echo 0xc0 > $GCONFIG/bmAttributes
570
echo 500 > $GCONFIG/MaxPower
571
mkdir $GCONFIG/strings/0x409
572
# Windows rndis driver requires rndis to be the first interface
573
[ $RNDIS = okay ] && rndis_config
574
[ $MSC = okay ] && msc_config
575
[ $UAS = okay ] && uas_config
576
[ $ADB = okay ] && adb_config
577
[ $UVC = okay ] && uvc_config
578
}
579
580
gclean()
581
{
582
[ -e $GADGET_PATH/UDC ] || die "gadget not configured, no need to clean"
583
msc_clean
584
uas_clean
585
rndis_clean
586
adb_clean
587
uvc_clean
588
# Remove string in gadget
589
gadget_info "remove strings of $GADGET_PATH."
590
g_remove $GADGET_PATH/strings/0x409
591
# Remove gadget
592
gadget_info "remove $GADGET_PATH."
593
g_remove $GADGET_PATH
594
}
595
596
glink()
597
{
598
[ $RNDIS = okay ] && rndis_link
599
[ $MSC = okay ] && msc_link
600
[ $UAS = okay ] && uas_link
601
[ $ADB = okay ] && adb_link
602
[ $UVC = okay ] && uvc_link
603
}
604
605
gunlink()
606
{
607
[ -e $GADGET_PATH/UDC ] || die "gadget not configured yet"
608
rndis_unlink
609
msc_unlink
610
uas_unlink
611
adb_unlink
612
uvc_unlink
613
# Remove strings:
614
gadget_info "remove strings of c.1."
615
g_remove $GCONFIG/strings/0x409
616
# Remove config:
617
gadget_info "remove configs c.1."
618
g_remove $GCONFIG
619
}
620
621
select_one()
622
{
623
func=$1
624
625
if [[ "$func" == "#"* ]];then
626
gadget_debug "met hashtag, skip"
627
return
628
fi
629
630
if [[ "$func" == USB_UDC=* ]]; then
631
USB_UDC=$(echo $func | awk -F= '{print $2}')
632
gadget_info "Set USB_UDC to $USB_UDC from config file"
633
return
634
fi
635
636
case "$func" in
637
msc*|mass*|storage*)
638
MSC=okay
639
MSC_ARG=$(echo $func | awk -F: '{print $2}')
640
;;
641
"uvc"|"video|webcam")
642
UVC=okay
643
;;
644
uas*|uasp*)
645
UAS=okay
646
UAS_ARG=$(echo $func | awk -F: '{print $2}')
647
;;
648
"rndis"|"network"|"net"|"if")
649
RNDIS=okay
650
;;
651
"mtp")
652
MTP=okay
653
;;
654
"adb"|"fastboot"|"adbd")
655
ADB=okay
656
;;
657
*)
658
die "not supported function: $func"
659
;;
660
esac
661
gadget_info "Selected function $func"
662
let FUNCTION_CNT=FUNCTION_CNT+1
663
}
664
665
handle_select() {
666
local input_str=$1
667
local IFS=, # split via comma
668
OLDIFS=$IFS # split functions
669
IFS=,
670
for token in $input_str; do
671
[ $DEBUG ]
672
select_one $token
673
done
674
IFS=$OLDIFS
675
}
676
677
parse_config()
678
{
679
[ -e $CONFIG_FILE ] || die "$CONFIG_FILE not found, abort."
680
while read line
681
do
682
select_one $line
683
done < $CONFIG_FILE
684
}
685
686
gstart()
687
{
688
gconfig
689
glink
690
[ $FUNCTION_CNT -lt 1 ] && die "No function selected, will not pullup."
691
echo_udc $1
692
}
693
694
gstop()
695
{
696
no_udc
697
gunlink
698
gclean
699
}
700
701
gen_role_switch_list()
702
{
703
ROLE_SWITCH_LIST=""
704
# Find those names with dwc3 in the dir: /sys/kernel/debug/usb
705
for dir in /sys/kernel/debug/usb/*; do
706
if [[ -d "$dir" && "$dir" == *"dwc3"* ]]; then
707
ROLE_SWITCH_LIST="$(basename "$dir") $ROLE_SWITCH_LIST"
708
fi
709
done
710
# Find role-switch location in dir: /sys/class/usb_role/xxx-role-switch/ with a role file existing
711
for role_switch in /sys/class/usb_role/*-role-switch/; do
712
if [[ -d "$role_switch" && -f "${role_switch}role" ]]; then
713
ROLE_SWITCH_LIST="$(basename "$role_switch") $ROLE_SWITCH_LIST"
714
fi
715
done
716
}
717
718
print_role_switch_info()
719
{
720
gen_role_switch_list
721
echo -n "Available DRDs: "
722
echo "$ROLE_SWITCH_LIST"
723
}
724
725
# Function to set the role for a specific role switch
726
set_role() {
727
if [ "$#" -lt 1 ]; then
728
echo "Usage: $name set_role <role_switch> [host|device]"
729
echo -e "\t$name set_role <role_switch>=[host|device]"
730
return 1
731
fi
732
local input="$*"
733
local role_switch
734
local role
735
# Use awk to parse the input
736
echo "$input" | awk -F'[ =]' '{
737
if (NF == 2) {
738
role_switch = $1;
739
role = $2;
740
} else if (NF == 1) {
741
role_switch = $1;
742
role = "NONE"; # Default role
743
} else if (NF >= 3) {
744
role_switch = $1;
745
role = $3;
746
sub(/=[^=]+$/, "", role_switch); # Remove the =part from role_switch
747
}
748
print role_switch, role
749
}' | {
750
read role_switch role
751
if [[ "$role_switch" == *"-role-switch" ]]; then
752
# It's a role-switch, verify its existence
753
local role_switch_path="/sys/class/usb_role/$role_switch/role"
754
if [ ! -e "$role_switch_path" ]; then
755
gadget_info "Error: Role switch '$role_switch' does not exist."
756
return 1
757
fi
758
if [[ "$role" == "NONE" ]]; then
759
role=$(cat $role_switch_path)
760
gadget_info "Role for role switch '$role_switch' is currently '$role'."
761
else
762
echo "$role" > "$role_switch_path"
763
gadget_info "Role for'$role_switch' set to '$role'."
764
fi
765
else
766
# It's a controller type, verify its existence
767
local usb_controller_path="/sys/kernel/debug/usb/$role_switch/mode"
768
if [ ! -e "$usb_controller_path" ]; then
769
gadget_info "Error: controller support mode switch '$role_switch' does not exist."
770
return 1
771
fi
772
if [[ "$role" == "NONE" ]]; then
773
role=$(cat $usb_controller_path)
774
gadget_info "Mode for '$role_switch' is currently '$role'."
775
else
776
echo "$role" > "$usb_controller_path"
777
sleep 1
778
role_after="$(cat $usb_controller_path)"
779
if [[ "$role" != "$role_after" ]]; then
780
gadget_info "Error: controller '$role_switch' doesn't support mode switch!!!"
781
role="$(cat $usb_controller_path)"
782
gadget_info "Mode for Controller '$role_switch' is currently '$role'."
783
else
784
gadget_info "Mode for controller '$role_switch' set to '$role'."
785
fi
786
fi
787
fi
788
print_role_switch_info
789
}
790
}
791
792
print_info()
793
{
794
echo "Ky gadget-setup tool $SCRIPT_VERSION"
795
echo
796
echo "Board Model: `tr -d '\000' < /proc/device-tree/model`"
797
echo "Serial Number: $SERNUM_STR"
798
echo "General Config Info: $VENDOR_ID/$PRODUC_ID/$MANUAF_STR/$PRODUC_STR."
799
echo "Config File Path: $CONFIG_FILE"
800
echo "MSC Ramdisk Path (selected from tmpfs mounting point): $RAMDISK_PATH"
801
echo "UASP SCSI NAA: $NAA"
802
echo "UASP Target Dir: $USB_GDIR"
803
echo "Available UDCs: `ls -1 /sys/class/udc/ | tr '\n' ' '`"
804
print_role_switch_info
805
echo
806
}
807
808
## MAIN
809
case "$1" in
810
stop|clean)
811
gstop
812
;;
813
restart|reload)
814
gstop
815
parse_config
816
gstart
817
;;
818
start)
819
parse_config
820
gstart $2
821
;;
822
pause|disconnect)
823
no_udc
824
;;
825
resume|connect)
826
USBDEV_IDX=$2
827
echo_udc
828
;;
829
config)
830
vi $CONFIG_FILE
831
[ -e $CONFIG_FILE ] && gadget_info ".usb_config updated"
832
;;
833
help)
834
usage
835
;;
836
info)
837
print_info
838
;;
839
set_role|role_switch|role|rolesw|mode|switch|dr_mode)
840
shift
841
set_role "$@"
842
;;
843
[a-z]*)
844
handle_select $1
845
gstart $2
846
;;
847
*)
848
usage
849
;;
850
esac
851
852
exit $?
853
854