#!/bin/sh # # Copyright 2023,2024 Emil Renner Berthing # # This is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set -e fs='/sys/kernel/config' top="$fs/usb_gadget" service='mkgadget' ctrl='10100000.usb' gadget=g1 vid=0x1b67 pid=0x400c model="$(tr '\000' '\n' < /proc/device-tree/model)" manufacturer="${model%% *}" product="${model#* }" serial=0001 c1_name='Ethernet Emulation' dev_addr='56:7f:82:61:f4:0a' host_addr='92:94:d9:a4:92:9a' readonly usage=" Usage: $0 [] [add|del|enable|disable] Options: -C Use this UDC controller. Default: $ctrl -s Set systemd service name. Default: $service -g Set gadget name. Default: $gadget -V Set vendor ID. Default: $vid -P Set product ID. Default: $pid -m Set manufacturer string. Default: $manufacturer -p Set product string. Default: $product -c Set configuration name. Default: $c1_name -D Set device MAC address. Default: $dev_addr -H Set host MAC address. Default: $host_addr -h Show this help. " while getopts 'C:s:g:V:P:m:p:c:D:H:h' opt; do case "$opt" in C) ctrl="$OPTARG";; s) service="$OPTARG";; g) gadget="$OPTARG";; V) vid="$OPTARG";; P) pid="$OPTARG";; m) manufacturer="$OPTARG";; p) product="$OPTARG";; c) c1_name="$OPTARG";; D) dev_addr="$OPTARG";; H) host_addr="$OPTARG";; h) echo "Create USB gadget on $ctrl" echo "$usage" exit 0;; *) echo "$usage" >&2 exit 1;; esac done shift $((OPTIND - 1)) error() { echo "$@" >&2 exit 1 } case "$1" in on|add|create) modprobe libcomposite || error "Error loading libcomposite: $?" for i in /sys/class/udc/$ctrl; do if [ -d "$i" ]; then udc="${i#/sys/class/udc/}" break fi done [ -n "$udc" ] || error "Could not find UDC controller $ctrl" [ -d "$top" ] || error "Could not find $top" [ ! -d "$top/$gadget" ] || error "Gadget $gadget already exists" # Create gadget mkdir "$top/$gadget" cd "$top/$gadget" # Set VID/PID echo "$vid" > idVendor echo "$pid" > idProduct # English language strings mkdir strings/0x409 echo "$manufacturer" > strings/0x409/manufacturer echo "$product" > strings/0x409/product echo "$serial" > strings/0x409/serialnumber # Create EEM configuration mkdir configs/c.1 mkdir configs/c.1/strings/0x409 echo "$c1_name" > configs/c.1/strings/0x409/configuration mkdir functions/eem.0 echo "$host_addr" > functions/eem.0/host_addr echo "$dev_addr" > functions/eem.0/dev_addr ln -s functions/eem.0 configs/c.1/ # Enable new configuration for the USB controller echo "$udc" > UDC # Make sure device is in peripheral mode if [[ -f "/sys/class/udc/$udc/device/mode" ]]; then read -r mode < "/sys/class/udc/$udc/device/mode" case "$mode" in *_peripheral) ;; *) echo peripheral > "/sys/class/udc/$udc/device/mode";; esac fi ;; off|del|delete|rm|remove) [ -d "$top/$gadget" ] || error "Gadget $gadget does not exist" cd "$top" # Disable gadget echo > "$gadget/UDC" # Remove function links for i in "$gadget"/configs/*/*; do [ ! -h "$i" ] || rm "$i" done # Remove functions for i in "$gadget"/functions/*; do [ ! -d "$i" ] || rmdir "$i" done # Remove configs for i in "$gadget"/configs/*; do [ ! -d "$i/strings/0x409" ] || rmdir "$i/strings/0x409" [ ! -d "$i" ] || rmdir "$i" done # Remove gadget rmdir "$gadget/strings/0x409" rmdir "$gadget" ;; enable) if [ ! -f "/etc/systemd/system/${service}.service" ]; then { echo '[Unit]' echo 'Description=Create USB EEM gadget' echo 'DefaultDependencies=no' echo echo '[Service]' echo 'Type=oneshot' echo 'RemainAfterExit=yes' echo 'StandardInput=null' echo 'ProtectSystem=full' echo 'ProtectHome=yes' echo "ExecStart=$0 add" echo "ExecStop=$0 del" echo echo '[Install]' echo 'WantedBy=usb-gadget.target' } | install -m644 -o root -g root /dev/stdin "/etc/systemd/system/${service}.service" echo "Created \"/etc/systemd/system/${service}.service\"" fi systemctl enable "${service}.service" ;; disable) systemctl disable "${service}.service" rm "/etc/systemd/system/${service}.service" echo "Removed \"/etc/systemd/system/${service}.service\"" ;; *) echo "Unknown action \"$1\"." >&2 echo "$usage" >&2 exit 1;; esac