| #!/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 $? |