Path: blob/next/external/packages/bsp/ky/usr/bin/gadget-setup.sh
13273 views
#!/bin/bash1# In busybox ash, should use /bin/sh, but bianbu cannot use /bin/sh23name=`basename $0`4SCRIPT_VERSION="v0.5-SUPPORTROLESW"5CONFIG_FILE=$HOME/.usb_config67# USB Descriptors8VENDOR_ID="0x361c"9PRODUC_ID="0x0007"10MANUAF_STR="Ky"11PRODUC_STR="Ky Composite Device"12SERNUM_STR="20211102"13SN_PATH="/proc/device-tree/serial-number"14[ "$BOARD_SN" ] || BOARD_SN=$( [ -e $SN_PATH ] && tr -d '\000' < $SN_PATH )15[ "$BOARD_SN" ] && SERNUM_STR=$BOARD_SN1617CONFIGFS=/sys/kernel/config18GADGET_PATH=$CONFIGFS/usb_gadget/ky19GFUNC_PATH=$GADGET_PATH/functions20GCONFIG=$GADGET_PATH/configs/c.121[ "$USB_UDC" ] || USB_UDC=$(ls /sys/class/udc | awk "NR==1{print}")2223# MSC Debug Ramdisk24RAMDISK_PATH=/var/sdcard25TMPFS_FOUND=`mount | grep tmpfs | grep -v devtmpfs | awk '{print $3}' | grep '/dev/shm' | wc -l`26[ "$TMPFS_FOUND" -eq 1 ] && RAMDISK_PATH=/dev/shm/sdcard27TMPFS_FOUND=`mount | grep tmpfs | grep -v devtmpfs | awk '{print $3}' | grep '/tmp' | wc -l`28[ "$TMPFS_FOUND" -eq 1 ] && RAMDISK_PATH=/tmp/sdcard29# SCSI Target30NAA="naa.6001405c3214b06a"31CORE_DIR=$CONFIGFS/target/core32USB_GDIR=$CONFIGFS/target/usb_gadget3334# Global variables to record configured functions35MSC=disabled36UAS=disabled37UAS_ARG=""38MSC_ARG=""39ADB=disabled40UVC=disabled41RNDIS=disabled42FUNCTION_CNT=043DEBUG=4445usage()46{47echo "$name usage: "48echo ""49echo -e "Support Select functions in $CONFIG_FILE:"50echo -e "\tWrite <func>:<arg> line in $CONFIG_FILE, then run:"51echo -e "\t$name [start|stop|reload|config]"52echo -e "Or Select functions manually:"53echo -e "\t$name <function1>(,<function2>...)"54echo -e "Set USB connection:"55echo -e "\t$name [pause|resume]"56echo -e "\n$name info: show gadget info"57echo -e "\nhint: udc is automatically selected, you can"58echo -e "\toverride udc with env USB_UDC_IDX=[integer]/USB_UDC=[str]"59echo -e "Set USB role-switch:"60echo -e "\t$name role <rolesw-name> [host|device]"61echo ""62echo "Functions and arguments supported:"63echo -e "\tmsc(:dev/file) Mass Storage(Bulk-Only)."64echo -e "\tuas(:dev/file) Mass Storage(UASP)."65echo -e "\tadb Android Debug Bridge over USB."66echo -e "\tuvc Webcam."67echo -e "\trndis RNDIS NIC function."68echo -e "\nKy gadget-setup tool $SCRIPT_VERSION"69echo ""70}7172gadget_info()73{74echo "$name: $1"75}7677gadget_debug()78{79[ $DEBUG ] && echo "$name: $1"80}8182die()83{84gadget_info "$1"85exit 186}8788g_remove()89{90[ -h $1 ] && rm -f $191[ -d $1 ] && rmdir $192[ -e $1 ] && rm -f $193}9495## MSC9697msc_ramdisk_()98{99# Debug Ramdisk for MSC without any argument100gadget_info "msc: ramdisk: $RAMDISK_PATH/disk.img"101mkdir -p $RAMDISK_PATH/sda102dd if=/dev/zero of=$RAMDISK_PATH/disk.img bs=1M count=1038103mkdosfs -F 32 $RAMDISK_PATH/disk.img104}105106msc_config()107{108gadget_debug "add a msc function instance"109MSC_DIR=$GFUNC_PATH/mass_storage.usb0110mkdir -p $MSC_DIR111DEVICE=$1112[ $DEVICE ] || DEVICE=$MSC_ARG113# Create a backstore114if [ -z "$DEVICE" ]; then115echo "$name: no device specificed, select ramdisk as backstore"116msc_ramdisk_117echo "tmp files would be created in: $RAMDISK_PATH"118echo "$RAMDISK_PATH/disk.img" > $MSC_DIR/lun.0/file119elif [ -b $DEVICE ]; then120echo "$name: block device"121echo "$DEVICE" > $MSC_DIR/lun.0/file122else123echo "$name: other path, regular file"124echo "$DEVICE" > $MSC_DIR/lun.0/file125fi126127echo 1 > $MSC_DIR/lun.0/removable128echo 0 > $MSC_DIR/lun.0/nofua129}130131msc_link()132{133gadget_debug "add msc to usb config"134ln -s $MSC_DIR $GCONFIG/mass_storage.usb0135}136137msc_unlink()138{139gadget_debug "remove msc from usb config"140g_remove $GCONFIG/mass_storage.usb0141}142143msc_clean()144{145gadget_debug "clean msc"146g_remove $GFUNC_PATH/mass_storage.usb0147g_remove $RAMDISK_PATH/disk.img148g_remove $RAMDISK_PATH/sda149}150151## UAS152153uas_config()154{155gadget_debug "add a uas function instance"156# Load the target modules and mount the add a file function instance system157# Uncomment these if modules not built-in:158# lsmod | grep -q configfs || modprobe configfs159# lsmod | grep -q target_core_mod || modprobe target_core_mod160DEVICE=$1161[ $DEVICE ] || DEVICE=$UAS_ARG162mkdir -p $GADGET_PATH/functions/tcm.0163# Create a backstore164if [ -z "$DEVICE" ]; then165echo "$name: no device specificed, select rd_mcp as backstore"166BACKSTORE_DIR=$CORE_DIR/rd_mcp_0/ramdisk167mkdir -p $BACKSTORE_DIR168# ramdisk169echo rd_pages=200000 > $BACKSTORE_DIR/control170elif [ -b $DEVICE ]; then171echo "$name: block device, select iblock as backstore"172BACKSTORE_DIR=$CORE_DIR/iblock_0/iblock173mkdir -p $BACKSTORE_DIR174echo "udev_path=${DEVICE}" > $BACKSTORE_DIR/control175else176echo "$name: other path, select fileio as backstore"177BACKSTORE_DIR=$CORE_DIR/fileio_0/fileio178mkdir -p $BACKSTORE_DIR179DEVICE_SIZE=$(du -b $DEVICE | cut -f1)180echo "fd_dev_name=${DEVICE},fd_dev_size=${DEVICE_SIZE}" > $BACKSTORE_DIR/control181# echo 1 > $BACKSTORE_DIR/attrib/emulate_write_cache182fi183[ -n "$DEVICE" ] && umount $DEVICE184echo 1 > $BACKSTORE_DIR/enable185echo "$name: NAA of target: $NAA"186# Create an NAA target and a target portal group (TPG)187mkdir -p $USB_GDIR/$NAA/tpgt_1/188echo "$name tpgt_1 has lun_0"189# Create a LUN190mkdir $USB_GDIR/$NAA/tpgt_1/lun/lun_0191# Nexus initiator on target port 1 to $NAA192echo $NAA > $USB_GDIR/$NAA/tpgt_1/nexus193194# Allow write access for non authenticated initiators195# echo 0 > $USB_GDIR/$NAA/tpgt_1/attrib/demo_mode_write_protect196ln -s $BACKSTORE_DIR $USB_GDIR/$NAA/tpgt_1/lun/lun_0/data197#ln -s $BACKSTORE_DIR $USB_GDIR/$NAA/tpgt_1/lun/lun_0/virtual_scsi_port198# echo 15 > $USB_GDIR/$NAA/tpgt_1/maxburst199200# Enable the target portal group, with 1 lun201echo 1 > $USB_GDIR/$NAA/tpgt_1/enable202}203204uas_link()205{206gadget_debug "add uas to usb config"207ln -s $GADGET_PATH/functions/tcm.0 $GCONFIG/tcm.0208}209210uas_unlink()211{212gadget_debug "remove uas from usb config"213g_remove $GCONFIG/tcm.0214}215216uas_clean()217{218gadget_debug "clean uas"219[ -d "$USB_GDIR/$NAA/tpgt_1/enable" ] && echo 0 > $USB_GDIR/$NAA/tpgt_1/enable220g_remove $USB_GDIR/$NAA/tpgt_1/lun/lun_0/data221g_remove $USB_GDIR/$NAA/tpgt_1/lun/lun_0/virtual_scsi_port222g_remove $USB_GDIR/$NAA/tpgt_1/lun/lun_0223g_remove $USB_GDIR/$NAA/tpgt_1/224g_remove $USB_GDIR/$NAA/225g_remove $USB_GDIR226BACKSTORE_DIR=$CORE_DIR/iblock_0/iblock227g_remove $BACKSTORE_DIR228BACKSTORE_DIR=$CORE_DIR/fileio_0/fileio229g_remove $BACKSTORE_DIR230BACKSTORE_DIR=$CORE_DIR/rd_mcp_0/ramdisk231g_remove $BACKSTORE_DIR232g_remove $GADGET_PATH/functions/tcm.0233}234235## ADB236237adb_config()238{239gadget_debug "add a adb function instance"240mkdir $GFUNC_PATH/ffs.adb241}242243adb_link()244{245gadget_debug "add adb to usb config"246ln -s $GFUNC_PATH/ffs.adb/ $GCONFIG/ffs.adb247mkdir /dev/usb-ffs248mkdir /dev/usb-ffs/adb249mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb/250#mkdir /dev/pts251#mount -t devpts -o defaults,mode=644,ptmxmode=666 devpts /dev/pts252adbd &253sleep 1254}255256adb_unlink()257{258gadget_debug "remove adb from usb config"259killall adbd260g_remove $GCONFIG/ffs.adb261[ -e /dev/usb-ffs/adb/ ] && umount /dev/usb-ffs/adb/262#[ -e /dev/pts ] && umount /dev/pts263#g_remove /dev/pts264g_remove /dev/usb-ffs/adb265g_remove /dev/usb-ffs266}267268adb_clean()269{270gadget_debug "clean adb"271g_remove $GFUNC_PATH/ffs.adb272}273274## UVC275276### Setup streaming/ directory.277add_uvc_fmt_resolution()278{279FORMAT=$1 # $1 format "uncompressed/y" / "mjpeg/m"280UVC_DISPLAY_W=$2 # $2 Width281UVC_DISPLAY_H=$3 # $3 Height282FRAMERATE=$4 # $4 HIGH_FRAMERATE 0/1283#https://docs.kernel.org/usb/gadget_uvc.html284UVC_MJPEG_PRE_PATH=$GFUNC_PATH/$UVC_INSTANCE/streaming/$FORMAT285UVC_FRAME_WDIR=${UVC_MJPEG_PRE_PATH}/${UVC_DISPLAY_H}p286gadget_debug "UVC_FRAME_WDIR: $UVC_FRAME_WDIR"287mkdir -p $UVC_FRAME_WDIR288echo $UVC_DISPLAY_W > $UVC_FRAME_WDIR/wWidth289echo $UVC_DISPLAY_H > $UVC_FRAME_WDIR/wHeight290DW_MAX_VD_FB_SZ=$(( $UVC_DISPLAY_W * $UVC_DISPLAY_H * 2 ))291if [ "$FORMAT"=="mjpeg/m" ]; then292if [ -e "$CONFIG_FILE" ]; then293# Attempt to parse the dwMaxVideoFrameBufferSize from ~/.uvcg_config294parsed_value=$(grep "^mjpeg $UVC_DISPLAY_W $UVC_DISPLAY_H" ~/.uvcg_config | awk '{print $4}')295# Check if the value was found; if not, keep the pre-calculated value296if [ ! -z "$parsed_value" ]; then297DW_MAX_VD_FB_SZ="$parsed_value"298fi299gadget_debug "format: $FORMAT, dw_max_video_fb_size: $DW_MAX_VD_FB_SZ"300fi301fi302echo $DW_MAX_VD_FB_SZ > $UVC_FRAME_WDIR/dwMaxVideoFrameBufferSize303# Many camera host app only shows the default framerate of a format in their list304# So we set it here.305if [ "$FRAMERATE" -eq 20 ]; then306echo 500000 > $UVC_FRAME_WDIR/dwDefaultFrameInterval307elif [ "$FRAMERATE" -eq 15 ]; then308echo 666666 > $UVC_FRAME_WDIR/dwDefaultFrameInterval309elif [ "$FRAMERATE" -eq 30 ]; then310echo 333333 > $UVC_FRAME_WDIR/dwDefaultFrameInterval311elif [ "$FRAMERATE" -eq 60 ]; then312echo 166666 > $UVC_FRAME_WDIR/dwDefaultFrameInterval313elif [ "$FRAMERATE" -eq 10 ]; then314echo 1000000 > $UVC_FRAME_WDIR/dwDefaultFrameInterval315fi316# lowest framerate in this script is 10fps317DW_MIN_BITRATE=$(( 10 * $DW_MAX_VD_FB_SZ * 8 ))318DW_MAX_BITRATE=$(( $FRAMERATE * $DW_MAX_VD_FB_SZ * 8 ))319if [ "$FORMAT"=="mjpeg/m" ]; then320# MJPEG can compress the data at least 5:1,321# let's set the ratio to 4322DW_MIN_BITRATE=$(( $DW_MIN_BITRATE / 4 ))323gadget_debug "format: $FORMAT, dw_min_br: $DW_MIN_BITRATE"324fi325echo $DW_MIN_BITRATE > $UVC_FRAME_WDIR/dwMinBitRate326echo $DW_MAX_BITRATE > $UVC_FRAME_WDIR/dwMaxBitRate327echo -e "\t$UVC_INSTANCE will support ${FORMAT} ${UVC_DISPLAY_W}x${UVC_DISPLAY_H}@${FRAMERATE}p"328cat <<EOF > $UVC_FRAME_WDIR/dwFrameInterval3291666663303333333314166673325000003336666663341000000335EOF336}337338destroy_one_uvc_format_()339{340FORMAT=$1341UVC_MJPEG_PRE_PATH=$GFUNC_PATH/$UVC_INSTANCE/streaming/$FORMAT342for ppath in ${UVC_MJPEG_PRE_PATH}/*p; do343g_remove $ppath344done345}346347destroy_all_uvc_format_()348{349350destroy_one_uvc_format_ uncompressed/y351g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/uncompressed/y352destroy_one_uvc_format_ mjpeg/m353g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/mjpeg/m354}355356create_uvc_link_()357{358mkdir $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h359ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/mjpeg/m/ $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/m360ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/uncompressed/y/ $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/y361ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/ $GFUNC_PATH/$UVC_INSTANCE/streaming/class/fs362ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/ $GFUNC_PATH/$UVC_INSTANCE/streaming/class/hs363ln -s $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/ $GFUNC_PATH/$UVC_INSTANCE/streaming/class/ss364mkdir $GFUNC_PATH/$UVC_INSTANCE/control/header/h365ln -s $GFUNC_PATH/$UVC_INSTANCE/control/header/h/ $GFUNC_PATH/$UVC_INSTANCE/control/class/fs/366ln -s $GFUNC_PATH/$UVC_INSTANCE/control/header/h/ $GFUNC_PATH/$UVC_INSTANCE/control/class/ss/367}368369destroy_uvc_link_()370{371g_remove $GFUNC_PATH/$UVC_INSTANCE/control/class/fs/h372g_remove $GFUNC_PATH/$UVC_INSTANCE/control/class/ss/h373g_remove $GFUNC_PATH/$UVC_INSTANCE/control/header/h374g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/class/ss/h375g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/class/hs/h376g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/class/fs/h377g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/m378g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h/y379g_remove $GFUNC_PATH/$UVC_INSTANCE/streaming/header/h380}381382destroy_uvc_()383{384destroy_uvc_link_385destroy_all_uvc_format_386g_remove $GFUNC_PATH/$UVC_INSTANCE387}388389set_uvc_maxpacket_()390{391MAX=$1 ## $1 1024/2048/3072392BURST=$2 ## $2 1-15393FUNCTION=$GFUNC_PATH/$UVC_INSTANCE394echo -e "\t$UVC_INSTANCE set streaming_maxpacket=$MAX, streaming_maxburst=$BURST"395echo $MAX > $FUNCTION/streaming_maxpacket396echo $BURST > $FUNCTION/streaming_maxburst397}398399uvc_config()400{401UVC_INSTANCE=uvc.0402gadget_info "Adding a uvc function instance $UVC_INSTANCE..."403mkdir -p $GFUNC_PATH/$UVC_INSTANCE404# add_uvc_fmt_resolution <format> <width> <height> <framerate>405add_uvc_fmt_resolution uncompressed/y 320 240 30406add_uvc_fmt_resolution uncompressed/y 640 360 30407add_uvc_fmt_resolution uncompressed/y 640 480 30408add_uvc_fmt_resolution uncompressed/y 640 640 30409add_uvc_fmt_resolution uncompressed/y 1280 720 30410add_uvc_fmt_resolution uncompressed/y 1920 1080 30411add_uvc_fmt_resolution uncompressed/y 3840 2160 30412add_uvc_fmt_resolution mjpeg/m 640 360 30413add_uvc_fmt_resolution mjpeg/m 640 480 30414add_uvc_fmt_resolution mjpeg/m 1280 720 30415add_uvc_fmt_resolution mjpeg/m 1920 1080 30416add_uvc_fmt_resolution mjpeg/m 3840 2160 30417set_uvc_maxpacket_ 3072 15418create_uvc_link_419}420421uvc_link()422{423gadget_debug "add uvc to usb config, unlike adb, you have to run ur own uvc-gadget app"424UVC_INSTANCE=uvc.0425ln -s $GFUNC_PATH/$UVC_INSTANCE/ $GCONFIG/$UVC_INSTANCE426}427428uvc_unlink()429{430gadget_debug "remove uvc from usb config"431UVC_INSTANCE=uvc.0432g_remove $GCONFIG/$UVC_INSTANCE433}434435uvc_clean()436{437gadget_debug "clean uvc"438UVC_INSTANCE=uvc.0439destroy_uvc_440}441442## RNDIS443444rndis_config()445{446OVERRIDE_VENDOR_FOR_WINDOWS=$1447# create function instance448# functions/<f_function allowed>.<instance name>449# f_function allowed: rndis450mkdir -p $GFUNC_PATH/rndis.0451}452453rndis_link()454{455456# Add Microsoft os descriptors to ensure457# Windows recognize us as an RNDIS compatible device458# thus no need to install driver manually.459# Verified on Windows 10.460echo 0xEF > $GADGET_PATH/bDeviceClass461echo 0x02 > $GADGET_PATH/bDeviceSubClass462echo 0x01 > $GADGET_PATH/bDeviceProtocol463echo 1 > $GADGET_PATH/os_desc/use464echo 0x1 > $GADGET_PATH/os_desc/b_vendor_code465echo "MSFT100" > $GADGET_PATH/os_desc/qw_sign466mkdir -p $GFUNC_PATH/rndis.0/os_desc/interface.rndis467echo RNDIS > $GFUNC_PATH/rndis.0/os_desc/interface.rndis/compatible_id468echo 5162001 > $GFUNC_PATH/rndis.0/os_desc/interface.rndis/sub_compatible_id469ln -s $GADGET_PATH/configs/c.1 $GADGET_PATH/os_desc/c.1470471ln -s $GFUNC_PATH/rndis.0 $GCONFIG472HOST_ADDR=`cat $GFUNC_PATH/rndis.0/host_addr`473DEV_ADDR=`cat $GFUNC_PATH/rndis.0/dev_addr`474IFNAME=`cat $GFUNC_PATH/rndis.0/ifname`475gadget_info "rndis function enabled, mac(h): $HOST_ADDR, mac(g): $DEV_ADDR, ifname: $IFNAME."476gadget_info "execute ifconfig $IFNAME up to enable rndis iface."477}478479rndis_unlink()480{481[ -e $GFUNC_PATH/rndis.0/ifname ] && ifconfig `cat $GFUNC_PATH/rndis.0/ifname` down482g_remove $GCONFIG/rndis.0483}484485rndis_clean()486{487g_remove $GFUNC_PATH/rndis.0488}489490## MTP491492mtp_config()493{494die "MTP Not Supported yet."495}496497mtp_link()498{499die "MTP Not Supported yet."500}501502mtp_unlink()503{504die "MTP Not Supported yet."505}506507mtp_clean()508{509die "MTP Not Supported yet."510}511512## GADGET513no_udc()514{515gadget_info "Echo none to udc"516gadget_info "We are now trying to echo None to UDC......"517[ -e $GADGET_PATH/UDC ] || die "gadget not configured yet"518[ `cat $GADGET_PATH/UDC` ] && echo "" > $GADGET_PATH/UDC519gadget_info "echo none to UDC successfully done"520gadget_info "echo none to UDC done."521}522523give_hint_to_which_have_udc_()524{525for config_path in "/sys/kernel/config/usb_gadget/"*; do526udc_path="$config_path/UDC"527is_here=$(cat $udc_path | grep $selected_udc | wc -l)528if [ "$is_here" -gt 0 ]; then529gadget_info "ERROR: Your udc is occupied by: $udc_path"530fi531done532}533534echo_udc()535{536[ -e $GADGET_PATH/UDC ] || die "gadget not configured yet"537[ `cat $GADGET_PATH/UDC` ] && die "UDC `cat $GADGET_PATH/UDC` already been set"538if [ "$USB_UDC_IDX" ]; then539selected_udc=$(ls /sys/class/udc | awk "NR==$USB_UDC_IDX{print}")540else541selected_udc=$USB_UDC542gadget_info "Selected udc by name: $selected_udc"543gadget_info "We are now trying to echo $selected_udc to UDC......"544fi545our_udc_occupied=$(cat /sys/kernel/config/usb_gadget/*/UDC | grep $selected_udc | wc -l)546if [ "$our_udc_occupied" -gt 0 ]; then547give_hint_to_which_have_udc_548gadget_info "ERROR: configfs preserved, run $name resume after conflict resolved"549exit 127550fi551echo $selected_udc > $GADGET_PATH/UDC552gadget_info "echo $selected_udc to UDC done"553}554555gconfig()556{557gadget_info "config $VENDOR_ID/$PRODUC_ID/$SERNUM_STR/$MANUAF_STR/$PRODUC_STR."558mountpoint -q /sys/kernel/config || mount -t configfs none /sys/kernel/config559[ -e $GADGET_PATH ] && die "ERROR: gadget already configured, should run stop first"560mkdir $GADGET_PATH561echo $VENDOR_ID > $GADGET_PATH/idVendor562echo $PRODUC_ID > $GADGET_PATH/idProduct563mkdir $GADGET_PATH/strings/0x409564echo $SERNUM_STR > $GADGET_PATH/strings/0x409/serialnumber565echo $MANUAF_STR > $GADGET_PATH/strings/0x409/manufacturer566echo $PRODUC_STR > $GADGET_PATH/strings/0x409/product567mkdir $GCONFIG568echo 0xc0 > $GCONFIG/bmAttributes569echo 500 > $GCONFIG/MaxPower570mkdir $GCONFIG/strings/0x409571# Windows rndis driver requires rndis to be the first interface572[ $RNDIS = okay ] && rndis_config573[ $MSC = okay ] && msc_config574[ $UAS = okay ] && uas_config575[ $ADB = okay ] && adb_config576[ $UVC = okay ] && uvc_config577}578579gclean()580{581[ -e $GADGET_PATH/UDC ] || die "gadget not configured, no need to clean"582msc_clean583uas_clean584rndis_clean585adb_clean586uvc_clean587# Remove string in gadget588gadget_info "remove strings of $GADGET_PATH."589g_remove $GADGET_PATH/strings/0x409590# Remove gadget591gadget_info "remove $GADGET_PATH."592g_remove $GADGET_PATH593}594595glink()596{597[ $RNDIS = okay ] && rndis_link598[ $MSC = okay ] && msc_link599[ $UAS = okay ] && uas_link600[ $ADB = okay ] && adb_link601[ $UVC = okay ] && uvc_link602}603604gunlink()605{606[ -e $GADGET_PATH/UDC ] || die "gadget not configured yet"607rndis_unlink608msc_unlink609uas_unlink610adb_unlink611uvc_unlink612# Remove strings:613gadget_info "remove strings of c.1."614g_remove $GCONFIG/strings/0x409615# Remove config:616gadget_info "remove configs c.1."617g_remove $GCONFIG618}619620select_one()621{622func=$1623624if [[ "$func" == "#"* ]];then625gadget_debug "met hashtag, skip"626return627fi628629if [[ "$func" == USB_UDC=* ]]; then630USB_UDC=$(echo $func | awk -F= '{print $2}')631gadget_info "Set USB_UDC to $USB_UDC from config file"632return633fi634635case "$func" in636msc*|mass*|storage*)637MSC=okay638MSC_ARG=$(echo $func | awk -F: '{print $2}')639;;640"uvc"|"video|webcam")641UVC=okay642;;643uas*|uasp*)644UAS=okay645UAS_ARG=$(echo $func | awk -F: '{print $2}')646;;647"rndis"|"network"|"net"|"if")648RNDIS=okay649;;650"mtp")651MTP=okay652;;653"adb"|"fastboot"|"adbd")654ADB=okay655;;656*)657die "not supported function: $func"658;;659esac660gadget_info "Selected function $func"661let FUNCTION_CNT=FUNCTION_CNT+1662}663664handle_select() {665local input_str=$1666local IFS=, # split via comma667OLDIFS=$IFS # split functions668IFS=,669for token in $input_str; do670[ $DEBUG ]671select_one $token672done673IFS=$OLDIFS674}675676parse_config()677{678[ -e $CONFIG_FILE ] || die "$CONFIG_FILE not found, abort."679while read line680do681select_one $line682done < $CONFIG_FILE683}684685gstart()686{687gconfig688glink689[ $FUNCTION_CNT -lt 1 ] && die "No function selected, will not pullup."690echo_udc $1691}692693gstop()694{695no_udc696gunlink697gclean698}699700gen_role_switch_list()701{702ROLE_SWITCH_LIST=""703# Find those names with dwc3 in the dir: /sys/kernel/debug/usb704for dir in /sys/kernel/debug/usb/*; do705if [[ -d "$dir" && "$dir" == *"dwc3"* ]]; then706ROLE_SWITCH_LIST="$(basename "$dir") $ROLE_SWITCH_LIST"707fi708done709# Find role-switch location in dir: /sys/class/usb_role/xxx-role-switch/ with a role file existing710for role_switch in /sys/class/usb_role/*-role-switch/; do711if [[ -d "$role_switch" && -f "${role_switch}role" ]]; then712ROLE_SWITCH_LIST="$(basename "$role_switch") $ROLE_SWITCH_LIST"713fi714done715}716717print_role_switch_info()718{719gen_role_switch_list720echo -n "Available DRDs: "721echo "$ROLE_SWITCH_LIST"722}723724# Function to set the role for a specific role switch725set_role() {726if [ "$#" -lt 1 ]; then727echo "Usage: $name set_role <role_switch> [host|device]"728echo -e "\t$name set_role <role_switch>=[host|device]"729return 1730fi731local input="$*"732local role_switch733local role734# Use awk to parse the input735echo "$input" | awk -F'[ =]' '{736if (NF == 2) {737role_switch = $1;738role = $2;739} else if (NF == 1) {740role_switch = $1;741role = "NONE"; # Default role742} else if (NF >= 3) {743role_switch = $1;744role = $3;745sub(/=[^=]+$/, "", role_switch); # Remove the =part from role_switch746}747print role_switch, role748}' | {749read role_switch role750if [[ "$role_switch" == *"-role-switch" ]]; then751# It's a role-switch, verify its existence752local role_switch_path="/sys/class/usb_role/$role_switch/role"753if [ ! -e "$role_switch_path" ]; then754gadget_info "Error: Role switch '$role_switch' does not exist."755return 1756fi757if [[ "$role" == "NONE" ]]; then758role=$(cat $role_switch_path)759gadget_info "Role for role switch '$role_switch' is currently '$role'."760else761echo "$role" > "$role_switch_path"762gadget_info "Role for'$role_switch' set to '$role'."763fi764else765# It's a controller type, verify its existence766local usb_controller_path="/sys/kernel/debug/usb/$role_switch/mode"767if [ ! -e "$usb_controller_path" ]; then768gadget_info "Error: controller support mode switch '$role_switch' does not exist."769return 1770fi771if [[ "$role" == "NONE" ]]; then772role=$(cat $usb_controller_path)773gadget_info "Mode for '$role_switch' is currently '$role'."774else775echo "$role" > "$usb_controller_path"776sleep 1777role_after="$(cat $usb_controller_path)"778if [[ "$role" != "$role_after" ]]; then779gadget_info "Error: controller '$role_switch' doesn't support mode switch!!!"780role="$(cat $usb_controller_path)"781gadget_info "Mode for Controller '$role_switch' is currently '$role'."782else783gadget_info "Mode for controller '$role_switch' set to '$role'."784fi785fi786fi787print_role_switch_info788}789}790791print_info()792{793echo "Ky gadget-setup tool $SCRIPT_VERSION"794echo795echo "Board Model: `tr -d '\000' < /proc/device-tree/model`"796echo "Serial Number: $SERNUM_STR"797echo "General Config Info: $VENDOR_ID/$PRODUC_ID/$MANUAF_STR/$PRODUC_STR."798echo "Config File Path: $CONFIG_FILE"799echo "MSC Ramdisk Path (selected from tmpfs mounting point): $RAMDISK_PATH"800echo "UASP SCSI NAA: $NAA"801echo "UASP Target Dir: $USB_GDIR"802echo "Available UDCs: `ls -1 /sys/class/udc/ | tr '\n' ' '`"803print_role_switch_info804echo805}806807## MAIN808case "$1" in809stop|clean)810gstop811;;812restart|reload)813gstop814parse_config815gstart816;;817start)818parse_config819gstart $2820;;821pause|disconnect)822no_udc823;;824resume|connect)825USBDEV_IDX=$2826echo_udc827;;828config)829vi $CONFIG_FILE830[ -e $CONFIG_FILE ] && gadget_info ".usb_config updated"831;;832help)833usage834;;835info)836print_info837;;838set_role|role_switch|role|rolesw|mode|switch|dr_mode)839shift840set_role "$@"841;;842[a-z]*)843handle_select $1844gstart $2845;;846*)847usage848;;849esac850851exit $?852853854