Add usb-ctrl for USB gadget control
The usb-ctrl is copied from [intel-bmc][1] that creates/destroy USB
mass-storage devices via USB gadget driver.
It supports multiple devices and could be extended with future features.
[1]: https://github.com/Intel-BMC/openbmc/blob/intel/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl
Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: Ie875e7e385ddacef82b7e4d20795c97c001384b3
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/meson.build b/meson.build
index 5419464..76caf0e 100644
--- a/meson.build
+++ b/meson.build
@@ -6,3 +6,4 @@
subdir('firstboot')
subdir('http-redirect')
+subdir('usb-ctrl')
diff --git a/meson_options.txt b/meson_options.txt
index b9aade8..75405d9 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -7,3 +7,6 @@
option(
'http-redirect', type: 'feature', description: 'Redirect http traffic to https.',
)
+option(
+ 'usb-ctrl', type: 'feature', description: 'Control USB gadget devices',
+)
diff --git a/usb-ctrl/meson.build b/usb-ctrl/meson.build
new file mode 100644
index 0000000..af207f4
--- /dev/null
+++ b/usb-ctrl/meson.build
@@ -0,0 +1,7 @@
+if get_option('usb-ctrl').enabled()
+ install_data(
+ 'usb-ctrl',
+ install_mode: 'rwxr-xr-x',
+ install_dir: get_option('bindir'),
+ )
+endif
diff --git a/usb-ctrl/usb-ctrl b/usb-ctrl/usb-ctrl
new file mode 100644
index 0000000..ae9f542
--- /dev/null
+++ b/usb-ctrl/usb-ctrl
@@ -0,0 +1,136 @@
+#!/bin/sh
+
+setup_image()
+{
+ set -x
+ local storage="$1"
+ local sz_mb="$2"
+ # create the backing store
+ dd if=/dev/zero of=$storage bs=1M seek=$sz_mb count=0 2>/dev/null
+ # this shows up as 23FC-F676 in /dev/disk/by-uuid
+ local diskid=0x23FCF676
+ mkdosfs -n 'OPENBMC-FW' -i $diskid -I $storage >/dev/null 2>&1
+}
+
+mount_image()
+{
+ set -x
+ local storage="$1"
+ local stormnt="$2"
+ mkdir -p $stormnt || exit 1
+ mount -o loop -t vfat $storage $stormnt
+}
+
+cleanup_image()
+{
+ set -x
+ local storage="$1"
+ local stormnt="$2"
+ umount -f "$stormnt"
+ rm -f "$storage"
+ rmdir "$stormnt"
+}
+
+GADGET_BASE=/sys/kernel/config/usb_gadget
+
+which_dev()
+{
+ local in_use=$(cat $GADGET_BASE/*/UDC)
+ cd /sys/class/udc
+ for D in *; do
+ case "$in_use" in
+ *"$D"*) ;;
+ *) echo "$D"; return 0;;
+ esac
+ done
+ return 1
+}
+
+usb_ms_insert()
+{
+ local name="$1"
+ local storage="$2"
+
+ if [ -d $GADGET_BASE/$name ]; then
+ echo "device $name already exists" >&2
+ return 1
+ fi
+ mkdir $GADGET_BASE/$name
+ cd $GADGET_BASE/$name
+
+ echo 0x1d6b > idVendor # Linux Foundation
+ echo 0x0105 > idProduct # FunctionFS Gadget
+ mkdir strings/0x409
+ local machineid=$(cat /etc/machine-id)
+ local data="OpenBMC USB mass storage gadget device serial number"
+ local serial=$( echo -n "${machineid}${data}${machineid}" | \
+ sha256sum | cut -b 0-12 )
+ echo $serial > strings/0x409/serialnumber
+ echo OpenBMC > strings/0x409/manufacturer
+ echo "OpenBMC Mass Storage" > strings/0x409/product
+
+ mkdir configs/c.1
+ mkdir functions/mass_storage.$name
+ echo $storage > functions/mass_storage.$name/lun.0/file
+ echo 0 > functions/mass_storage.$name/lun.0/removable
+ mkdir configs/c.1/strings/0x409
+
+ echo "Conf 1" > configs/c.1/strings/0x409/configuration
+ echo 120 > configs/c.1/MaxPower
+ ln -s functions/mass_storage.$name configs/c.1
+ local dev=$(which_dev)
+ echo $dev > UDC
+}
+
+usb_ms_eject()
+{
+ local name="$1"
+
+ echo '' > $GADGET_BASE/$name/UDC
+
+ rm -f $GADGET_BASE/$name/configs/c.1/mass_storage.$name
+ rmdir $GADGET_BASE/$name/configs/c.1/strings/0x409
+ rmdir $GADGET_BASE/$name/configs/c.1
+ rmdir $GADGET_BASE/$name/functions/mass_storage.$name
+ rmdir $GADGET_BASE/$name/strings/0x409
+ rmdir $GADGET_BASE/$name
+}
+
+usage()
+{
+ echo "Usage: $0 <action> ..."
+ echo " $0 setup <file> <sizeMB>"
+ echo " $0 insert <name> <file>"
+ echo " $0 eject <name>"
+ echo " $0 mount <file> <mnt>"
+ echo " $0 cleanup <file> <mnt>"
+ exit 1
+}
+
+echo "$#: $0 $@"
+case "$1" in
+ insert)
+ shift
+ usb_ms_insert "$@"
+ ;;
+ eject)
+ shift
+ usb_ms_eject "$@"
+ ;;
+ setup)
+ shift
+ setup_image "$@"
+ ;;
+ mount)
+ shift
+ mount_image "$@"
+ ;;
+ cleanup)
+ shift
+ cleanup_image "$@"
+ ;;
+ *)
+ usage
+ ;;
+esac
+exit $?