package for usb-gadget and idea for dumper

This commit is contained in:
Miguel Fuertes committed 2025-09-14 23:14:09 +02:00
1 parent 7bbe036760
commit 97d6055d05
8 files changed
+126 -423

No files matched your search

@@ -1,372 +0,0 @@
#!/bin/bash
# Main script for MSM8916 USB Gadget
#SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
#CONFIG_FILE="${SCRIPT_DIR}/msm8916-usb-gadget.conf"
CONFIG_FILE="/etc/msm8916-usb-gadget.conf"
GADGET_PATH="/sys/kernel/config/usb_gadget/msm8916"
# Load configuration
[ -f "${CONFIG_FILE}" ] && . "${CONFIG_FILE}"
# Set defaults if not configured
: ${USB_VENDOR_ID:="0x1d6b"}
: ${USB_PRODUCT_ID:="0x0104"}
: ${USB_DEVICE_VERSION:="0x0100"}
: ${USB_MANUFACTURER:="MSM8916"}
: ${USB_PRODUCT:="USB Gadget"}
: ${NETWORK_BRIDGE:="br0"}
# Helper functions
log() {
logger -t msm8916-usb-gadget "$@"
echo "$(date '+%Y-%m-%d %H:%M:%S') $@"
}
error() {
log "ERROR: $@"
exit 1
}
find_udc_device() {
if [ -n "${UDC_DEVICE}" ]; then
echo "${UDC_DEVICE}"
return
fi
# MSM8916 typically uses ci_hdrc.0
if [ -e "/sys/class/udc/ci_hdrc.0" ]; then
echo "ci_hdrc.0"
return
fi
# Fallback: first available UDC
udc=$(ls /sys/class/udc/ 2>/dev/null | head -1)
if [ -n "${udc}" ]; then
echo "${udc}"
else
error "No UDC device found"
fi
}
get_serial_number() {
# Use machine-id as the source of uniqueness
if [ -f /etc/machine-id ]; then
sha256sum < /etc/machine-id | cut -d' ' -f1 | cut -c1-16
else
# Fallback to random if machine-id doesn't exist
echo "$(date +%s)-$(shuf -i 1000-9999 -n 1)"
fi
}
generate_mac_address() {
local prefix="$1"
local serial="$(get_serial_number)"
local hash="$(echo "${serial}${prefix}" | md5sum | cut -c1-12)"
# Extract bytes
local b1="${hash:0:2}"
local b2="${hash:2:2}"
local b3="${hash:4:2}"
local b4="${hash:6:2}"
local b5="${hash:8:2}"
local b6="${hash:10:2}"
# Set locally administered, unicast
b1="$(printf '%02x' $((0x${b1} & 0xfe | 0x02)))"
echo "${b1}:${b2}:${b3}:${b4}:${b5}:${b6}"
}
load_mac_addresses() {
# Generate new MAC addresses for enabled functions
[ "${ENABLE_RNDIS}" = "1" ] && {
MAC_RNDIS_HOST="$(generate_mac_address "rndis-host")"
MAC_RNDIS_DEV="$(generate_mac_address "rndis-dev")"
}
[ "${ENABLE_ECM}" = "1" ] && {
MAC_ECM_HOST="$(generate_mac_address "ecm-host")"
MAC_ECM_DEV="$(generate_mac_address "ecm-dev")"
}
[ "${ENABLE_NCM}" = "1" ] && {
MAC_NCM_HOST="$(generate_mac_address "ncm-host")"
MAC_NCM_DEV="$(generate_mac_address "ncm-dev")"
}
}
create_storage_image() {
local image_path="$1"
local size="${UMS_IMAGE_SIZE:-100M}"
log "Creating storage image: ${image_path} (${size})"
# Create the raw image file
truncate -s "${size}" "${image_path}" || \
dd if=/dev/zero of="${image_path}" bs=1M count="${size%M}"
log "Storage image created successfully (raw format)"
}
setup_gadget() {
log "Setting up USB gadget"
# Load required modules
modprobe libcomposite
# Mount configfs if not already mounted
if ! mountpoint -q /sys/kernel/config; then
log "Mounting configfs"
mount -t configfs none /sys/kernel/config
fi
# Create storage image if needed and UMS is enabled
if [ "${ENABLE_UMS}" = "1" ] && [ ! -f "${UMS_IMAGE}" ]; then
mkdir -p "$(dirname "${UMS_IMAGE}")"
create_storage_image "${UMS_IMAGE}"
fi
# Create gadget
mkdir -p "${GADGET_PATH}" || error "Failed to create gadget directory"
cd "${GADGET_PATH}" || error "Failed to change to gadget directory"
# Basic device info
echo "${USB_VENDOR_ID}" > idVendor || error "Failed to set vendor ID"
echo "${USB_PRODUCT_ID}" > idProduct || error "Failed to set product ID"
echo "${USB_DEVICE_VERSION}" > bcdDevice || error "Failed to set device version"
# Composite device descriptors
echo "0xEF" > bDeviceClass
echo "0x02" > bDeviceSubClass
echo "0x01" > bDeviceProtocol
# Strings
mkdir -p strings/0x409
echo "$(get_serial_number)" > strings/0x409/serialnumber
echo "${USB_MANUFACTURER}" > strings/0x409/manufacturer
echo "${USB_PRODUCT}" > strings/0x409/product
# Load MAC addresses
load_mac_addresses
local cfg="configs/c.1"
mkdir -p "${cfg}/strings/0x409"
local cfg_str=""
local has_wakeup=0
# RNDIS (must be first for Windows compatibility)
if [ "${ENABLE_RNDIS}" = "1" ]; then
log "Enabling RNDIS"
cfg_str="${cfg_str}+RNDIS"
mkdir -p functions/rndis.usb0
echo "${MAC_RNDIS_HOST}" > functions/rndis.usb0/host_addr
echo "${MAC_RNDIS_DEV}" > functions/rndis.usb0/dev_addr
ln -sf functions/rndis.usb0 "${cfg}"
# Windows compatibility
echo 1 > os_desc/use
echo 0xcd > os_desc/b_vendor_code
echo MSFT100 > os_desc/qw_sign
echo RNDIS > functions/rndis.usb0/os_desc/interface.rndis/compatible_id
echo 5162001 > functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id
ln -sf "${cfg}" os_desc
has_wakeup=1
fi
# ACM Serial ports
if [ "${ENABLE_ACM}" = "1" ]; then
log "Enabling ACM serial (${ACM_COUNT:-1} ports)"
# Create multiple ACM ports if requested
acm_count="${ACM_COUNT:-1}"
for i in $(seq 0 $((acm_count - 1))); do
cfg_str="${cfg_str}+ACM"
mkdir -p functions/acm.GS${i}
# Link directly to config
ln -sf functions/acm.GS${i} "${cfg}"
done
fi
# ECM
if [ "${ENABLE_ECM}" = "1" ] && [ "${ENABLE_NCM}" != "1" ]; then
log "Enabling ECM"
cfg_str="${cfg_str}+ECM"
mkdir -p functions/ecm.usb0
echo "${MAC_ECM_HOST}" > functions/ecm.usb0/host_addr
echo "${MAC_ECM_DEV}" > functions/ecm.usb0/dev_addr
ln -sf functions/ecm.usb0 "${cfg}"
has_wakeup=1
fi
# NCM (preferred over ECM)
if [ "${ENABLE_NCM}" = "1" ]; then
log "Enabling NCM"
cfg_str="${cfg_str}+NCM"
mkdir -p functions/ncm.usb0
echo "${MAC_NCM_HOST}" > functions/ncm.usb0/host_addr
echo "${MAC_NCM_DEV}" > functions/ncm.usb0/dev_addr
ln -sf functions/ncm.usb0 "${cfg}"
has_wakeup=1
fi
# Mass Storage
if [ "${ENABLE_UMS}" = "1" ]; then
if [ ! -f "${UMS_IMAGE}" ]; then
log "Warning: UMS image ${UMS_IMAGE} not found"
else
log "Enabling UMS"
cfg_str="${cfg_str}+UMS"
mkdir -p functions/mass_storage.0
echo "${UMS_READONLY:-0}" > functions/mass_storage.0/lun.0/ro
echo "${UMS_IMAGE}" > functions/mass_storage.0/lun.0/file
ln -sf functions/mass_storage.0 "${cfg}"
fi
fi
# Set configuration attributes
if [ "${has_wakeup}" = "1" ]; then
echo "0xe0" > "${cfg}/bmAttributes" # Self-powered with remote wakeup
else
echo "0xc0" > "${cfg}/bmAttributes" # Self-powered
fi
echo "${cfg_str:1}" > "${cfg}/strings/0x409/configuration"
# Enable gadget
local udc="$(find_udc_device)"
log "Using UDC: ${udc}"
echo "${udc}" > UDC || error "Failed to enable UDC"
# Configure network interfaces
# setup_network()
# Use uci instead!
}
setup_network() {
log "Configuring network interfaces"
# Wait for interfaces to appear
sleep 1
# Check if bridge exists
if ! ip link show "${NETWORK_BRIDGE}" >/dev/null 2>&1; then
log "Warning: Bridge ${NETWORK_BRIDGE} does not exist"
return
fi
# Add interfaces to bridge
if [ "${ENABLE_RNDIS}" = "1" ] && [ -f functions/rndis.usb0/ifname ]; then
rndis_if="$(cat functions/rndis.usb0/ifname)"
log "Adding ${rndis_if} to bridge ${NETWORK_BRIDGE}"
ip link set "${rndis_if}" up
ip link set "${rndis_if}" master "${NETWORK_BRIDGE}" || true
fi
if [ "${ENABLE_ECM}" = "1" ] && [ -f functions/ecm.usb0/ifname ]; then
ecm_if="$(cat functions/ecm.usb0/ifname)"
log "Adding ${ecm_if} to bridge ${NETWORK_BRIDGE}"
ip link set "${ecm_if}" up
ip link set "${ecm_if}" master "${NETWORK_BRIDGE}" || true
fi
if [ "${ENABLE_NCM}" = "1" ] && [ -f functions/ncm.usb0/ifname ]; then
ncm_if="$(cat functions/ncm.usb0/ifname)"
log "Adding ${ncm_if} to bridge ${NETWORK_BRIDGE}"
ip link set "${ncm_if}" up
ip link set "${ncm_if}" master "${NETWORK_BRIDGE}" || true
fi
}
teardown_gadget() {
log "Tearing down USB gadget"
# Check if configfs is mounted
if ! mountpoint -q /sys/kernel/config; then
log "Configfs not mounted, nothing to tear down"
return
fi
# Check if gadget directory exists
if [ ! -d "/sys/kernel/config/usb_gadget" ]; then
log "USB gadget configfs not available"
return
fi
cd /sys/kernel/config/usb_gadget
if [ ! -d msm8916 ]; then
return
fi
cd msm8916
# Disable gadget
echo "" > UDC || true
# Remove network interfaces from bridge
for func in functions/*/ifname; do
if [ -f "${func}" ]; then
iface="$(cat "${func}")"
ip link set "${iface}" nomaster || true
ip link set "${iface}" down || true
fi
done
# Remove configuration - use wildcard to catch all links
rm -f configs/c.1/* 2>/dev/null || true
rm -f os_desc/c.1 2>/dev/null || true
rmdir configs/c.1/strings/0x409 2>/dev/null || true
rmdir configs/c.1 2>/dev/null || true
# Remove functions
for func in functions/*; do
[ -d "${func}" ] && rmdir "${func}" 2>/dev/null || true
done
# Remove strings
rmdir strings/0x409 2>/dev/null || true
# Remove gadget
cd ..
rmdir msm8916 2>/dev/null || true
}
status() {
if [ -d "${GADGET_PATH}" ] && [ -s "${GADGET_PATH}/UDC" ]; then
echo "USB Gadget is active"
echo "UDC: $(cat ${GADGET_PATH}/UDC)"
echo "Functions:"
ls -1 ${GADGET_PATH}/configs/c.1/ 2>/dev/null | grep -v strings
return 0
else
echo "USB Gadget is inactive"
return 1
fi
}
case "$1" in
start)
teardown_gadget
setup_gadget
;;
stop)
teardown_gadget
;;
restart)
teardown_gadget
setup_gadget
;;
status)
status
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
+73
View File
@@ -0,0 +1,73 @@
#!/bin/sh /etc/rc.common
# SPDX-License-Identifier: GPL-2.0-or-later
# This file is based on postmarketOS initfs code.
# See: https://gitlab.com/postmarketOS/pmaports/-/blob/master/main/postmarketos-mkinitfs/
START=20
deviceinfo_manufacturer="Generic"
deviceinfo_usb_serialnumber="123456"
setup_usb_network_configfs() {
# See: https://www.kernel.org/doc/Documentation/usb/gadget_configfs.txt
CONFIGFS=/sys/kernel/config/usb_gadget
if ! [ -e "$CONFIGFS" ]; then
echo " /config/usb_gadget does not exist, skipping configfs usb gadget"
return
fi
# Default values for USB-related deviceinfo variables
usb_idVendor="${deviceinfo_usb_idVendor:-0x18D1}" # default: Google Inc.
usb_idProduct="${deviceinfo_usb_idProduct:-0xD001}" # default: Nexus 4 (fastboot)
usb_serialnumber="${deviceinfo_usb_serialnumber:-OpenWRT}"
usb_rndis_function="${deviceinfo_usb_rndis_function:-rndis.usb0}"
echo " Setting up an USB gadget through configfs"
# Create an usb gadet configuration
mkdir $CONFIGFS/g1 || echo " Couldn't create $CONFIGFS/g1"
echo "$usb_idVendor" > "$CONFIGFS/g1/idVendor"
echo "$usb_idProduct" > "$CONFIGFS/g1/idProduct"
# Create english (0x409) strings
mkdir $CONFIGFS/g1/strings/0x409 || echo " Couldn't create $CONFIGFS/g1/strings/0x409"
# shellcheck disable=SC2154
echo "$deviceinfo_manufacturer" > "$CONFIGFS/g1/strings/0x409/manufacturer"
echo "$usb_serialnumber" > "$CONFIGFS/g1/strings/0x409/serialnumber"
# shellcheck disable=SC2154
echo "$deviceinfo_name" > "$CONFIGFS/g1/strings/0x409/product"
# Create rndis function. The function can be named differently in downstream kernels.
mkdir $CONFIGFS/g1/functions/"$usb_rndis_function" \
|| echo " Couldn't create $CONFIGFS/g1/functions/$usb_rndis_function"
# Create configuration instance for the gadget
mkdir $CONFIGFS/g1/configs/c.1 \
|| echo " Couldn't create $CONFIGFS/g1/configs/c.1"
mkdir $CONFIGFS/g1/configs/c.1/strings/0x409 \
|| echo " Couldn't create $CONFIGFS/g1/configs/c.1/strings/0x409"
echo "rndis" > $CONFIGFS/g1/configs/c.1/strings/0x409/configuration \
|| echo " Couldn't write configration name"
# Link the rndis instance to the configuration
ln -s $CONFIGFS/g1/functions/"$usb_rndis_function" $CONFIGFS/g1/configs/c.1 \
|| echo " Couldn't symlink $usb_rndis_function"
# Check if there's an USB Device Controller
if [ -z "$(ls /sys/class/udc)" ]; then
echo " No USB Device Controller available"
return
fi
# Link the gadget instance to an USB Device Controller. This activates the gadget.
# See also: https://github.com/postmarketOS/pmbootstrap/issues/338
# shellcheck disable=SC2005
echo "$(ls /sys/class/udc)" > $CONFIGFS/g1/UDC || echo " Couldn't write UDC"
}
start() {
mount -t configfs none /sys/kernel/config
setup_usb_network_configfs
}
@@ -1,40 +0,0 @@
#!/bin/sh
# MSM8916 USB Gadget Configuration
### USB protocols and OS support:
# - RNDIS Ethernet: Linux/Windows supported automatically, macOS needs HoRNDIS driver
# - CDC ECM Ethernet: Linux/macOS 10.14 and earlier supported automatically.
# - CDC NCM Ethernet: Linux/macOS 10.15 and later supported automatically, Windows 11 supported automatically.
# - UMS USB Mass storage: All OS supported automatically.
# - CDC ACM Serial: All OS supported automatically. (Windows <10 needs a custom .inf)
###
# USB Functions Enable/Disable
ENABLE_RNDIS=1 # MS-Windows compatible ethernet
ENABLE_ECM=0 # CDC ECM ethernet
ENABLE_NCM=0 # CDC NCM ethernet (Best Performance)
ENABLE_UMS=0 # Mass storage
ENABLE_ACM=1 # Serial console
# Network Configuration
# Bridge to attach USB Ethernet interfaces to
NETWORK_BRIDGE="br0"
# UMS Configuration (if enabled)
UMS_IMAGE="/var/lib/msm8916-gadget/usb_mass_storage.img"
UMS_IMAGE_SIZE="100M" # Size to create if image doesn't exist (M/G suffix supported)
UMS_READONLY=0
# ACM Configuration (if enabled)
# NOTE: MSM8916 hardware supports maximum 3 ACM serial ports
ACM_COUNT=1 # Number of Serial ports
# UDC Device (auto-detect if empty)
UDC_DEVICE=""
# USB Device Identification
USB_VENDOR_ID="0x1d6b" # Linux Foundation
USB_PRODUCT_ID="0x0104" # Multifunction Composite Gadget
USB_DEVICE_VERSION="0x0100" # v1.0.0
USB_MANUFACTURER="MSM8916"
USB_PRODUCT="USB Gadget"