blob: f9711efbcfbec3552cc6d1f513490bdd82f649f8 [file] [log] [blame]
#!/bin/bash
set -e
function 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
}
function mount_image()
{
set -x
local storage="$1"
local stormnt="$2"
mkdir -p "$stormnt" || exit 1
mount -o loop -t vfat "$storage" "$stormnt"
}
function cleanup_image()
{
set -x
local storage="$1"
local stormnt="$2"
umount -f "$stormnt"
rm -f "$storage"
rmdir "$stormnt"
}
function network()
{
set -x
local type="$1"
local name="$2"
local on="$3"
local bmc_mac="$4"
local host_mac="$5"
if [ "$on" = "on" ]; then
usb_insert "${name}" "${type}" "${bmc_mac}" "${host_mac}"
elif [ "$on" = "off" ]; then
usb_eject "${name}" "${type}"
else
echo "Unknown ${type} command"
usage
fi
}
GADGET_BASE=/sys/kernel/config/usb_gadget
function which_dev()
{
local in_use
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
}
function usb_ms_insert()
{
usb_insert "$1" mass_storage "$2" "$3"
}
function usb_ms_eject()
{
usb_eject "$1" mass_storage
}
## $1: device syspath to provide usb-gadget configure,
## e.g. functions/mass_storage.usb0/lun.0/
##
## $2: optional usb gadget interface type, e.g. usb|usb-ro|hdd|cdrom.
## if $2 not specified or illegal, then using 'usb-ro' as default
function usb_set_interface_type()
{
local usb_gadget_syspath="$1"
local interface_type="${2:-'usb-ro'}"
# defining target variables to configure interface type
local removable=
local ro=
local cdrom=
if [ ! -d "${usb_gadget_syspath}" ]; then
echo "Device syspath ${usb_gadget_syspath} does not exist" >&2
return 1
fi
case "${interface_type}" in
hdd)
removable=0
ro=0
cdrom=0
;;
usb)
removable=1
ro=0
cdrom=0
;;
cdrom)
removable=1
ro=1
cdrom=1
;;
usb-ro)
removable=1
ro=1
cdrom=0
;;
*)
echo "Unknown mass-storage interface type '${interface_type}' specified" >&2
echo "Configuring interface type as 'usb-ro'" >&2
removable=1
ro=1
cdrom=0
;;
esac
echo $removable > "${usb_gadget_syspath}/removable"
echo $ro > "${usb_gadget_syspath}/ro"
echo $cdrom > "${usb_gadget_syspath}/cdrom"
}
## $1: device name, e.g. usb0, usb1
## $2: device type defined in kernel, e.g. mass_storage, ecm, eem, rndis
## $3: Type specific
## For mass_storage, it is the backing storage, e.g. /dev/nbd1, /tmp/boot.iso
## For ecm, eem and rndis,
## it is the optional MAC address for the BMC (default a random MAC)
## $4: Type specific
## For mass_storage, it is the interface type, e.g. usb|usb-ro|hdd|cdrom.
## If interface type not specified or unknown it will default to 'usb-ro'
## For ecm, eem and rndis,
## it is the optional MAC address for the Host (default a random MAC)
function usb_insert()
{
local name="$1"
local dev_type="$2"
local storage="$3"
local intf_type="$4"
local bmc_mac="$3"
local host_mac="$4"
# By default, the gadget is not multifunctional
local is_multifunction=false
local gadget_function
local dev=
gadget_function="functions/${dev_type}.${name}"
# Checking whether the device is already attached
if [ -d "$GADGET_BASE/${name}" ]; then
# Checking whether requested function is attached
if [ -d "$GADGET_BASE/${name}/${gadget_function}" ]; then
echo "Function ${dev_type}.${name} already exists" >&2
return 1
fi
# if the requested function is not configured but the device
# is connected, it is assumed that the device is multifunctional
is_multifunction=true
fi
if [ "${is_multifunction}" = false ]; then
mkdir "$GADGET_BASE/${name}"
cd "$GADGET_BASE/${name}"
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
mkdir strings/0x409
local machineid
machineid=$(cat /etc/machine-id)
local data="OpenBMC USB gadget device serial number"
local serial
serial=$( echo -n "${machineid}${data}${machineid}" | \
sha256sum | cut -b 0-12 )
echo "$serial" > strings/0x409/serialnumber
echo "OpenBMC" > strings/0x409/manufacturer
echo "OpenBMC USB Device" > strings/0x409/product
mkdir configs/c.1
else
cd "$GADGET_BASE/${name}"
udc=$(cat "$GADGET_BASE/${name}/UDC")
fi
mkdir "${gadget_function}"
case "${dev_type}" in
mass_storage)
# usb_set_interface_type handles default and unknown type
usb_set_interface_type "${gadget_function}/lun.0" "${intf_type}"
echo "${storage}" > "${gadget_function}/lun.0/file"
;;
ecm|eem|rndis)
if [[ -n ${bmc_mac} && "${bmc_mac}" != "." ]]; then
echo "${bmc_mac}" > "${gadget_function}/dev_addr"
fi
if [[ -n "${host_mac}" ]]; then
echo "${host_mac}" > "${gadget_function}/host_addr"
fi
;;
esac
if [ "${is_multifunction}" = false ]; then
mkdir configs/c.1/strings/0x409
echo "Conf 1" > configs/c.1/strings/0x409/configuration
echo 120 > configs/c.1/MaxPower
dev=$(which_dev)
else
dev=$(cat "$GADGET_BASE/${name}/UDC")
# reattach UDC to reconfigure interface descriptors.
echo '' > UDC
fi
ln -s "${gadget_function}" configs/c.1
echo "$dev" > UDC
}
## $1: device name, e.g. usb0, usb1
## $2: device type defined in kernel, e.g. mass_storage, ecm, eem, rndis
function usb_eject()
{
local name="$1"
local dev_type="$2"
local func_cnt
local udc
func_cnt=$(find "$GADGET_BASE/${name}/functions/" -maxdepth 1 -mindepth 1 | wc -l)
udc=$(cat "$GADGET_BASE/${name}/UDC")
echo '' > "$GADGET_BASE/${name}/UDC"
# remove function
rm -f "$GADGET_BASE/${name}/configs/c.1/${dev_type}.${name}"
rmdir "$GADGET_BASE/${name}/functions/${dev_type}.${name}"
# check wether composite device is used
if [ "${func_cnt}" -gt 1 ]; then
# bring the device back online
echo "${udc}" > "$GADGET_BASE/${name}/UDC"
return 0;
fi
rmdir "$GADGET_BASE/${name}/configs/c.1/strings/0x409"
rmdir "$GADGET_BASE/${name}/configs/c.1"
rmdir "$GADGET_BASE/${name}/strings/0x409"
rmdir "$GADGET_BASE/${name}"
}
function usage()
{
echo "Usage: $0 <action> ..."
echo " $0 setup <file> <sizeMB>"
echo " $0 insert <name> <file> [<type=usb|usb-ro|hdd|cdrom>]"
echo " $0 eject <name>"
echo " $0 mount <file> <mnt>"
echo " $0 cleanup <file> <mnt>"
echo " $0 ecm <name> <on|off> [<bmc-mac-address|.> [<host-mac-address>]]"
echo " $0 eem <name> <on|off> [<bmc-mac-address|.> [<host-mac-address>]]"
echo " $0 rndis <name> <on|off> [<bmc-mac-address|.> [<host-mac-address>]]"
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 "$@"
;;
ecm|eem|rndis)
network "$@"
;;
*)
usage
;;
esac
exit $?