summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuanhong Guo <gch981213@gmail.com>2023-11-19 20:56:52 +0800
committerChuanhong Guo <gch981213@gmail.com>2023-12-28 13:10:32 +0800
commitb196a9f6ce8ef7d6b09d20ef79ffcf464d1a15ab (patch)
tree5a45cc2697c475192821324fbfcad1e44b0706ac
parentb799dd3c705dfd95745cdd94b13d1cd2ad2367a6 (diff)
downloadopenwrt-b196a9f6ce8ef7d6b09d20ef79ffcf464d1a15ab.tar.gz
openwrt-b196a9f6ce8ef7d6b09d20ef79ffcf464d1a15ab.tar.bz2
openwrt-b196a9f6ce8ef7d6b09d20ef79ffcf464d1a15ab.zip
package: new package for usb gadget setup
Setting up usb gadgets using g_* kernel modules are considered a legacy approach, but the usb_gadget configfs is a bit annoying to use directly. The usb_gadget configfs works by creating magic directories and writing to magic files under /sys/kernel/config/usbgadget. This new package is an init script to setup usb_gadget configfs using uci. In the config file, gadget/configuration/function sections create corresponding directories. UCI options are magic files available in the configfs and strings/0x409 directories, grabbed with a 'find' command. UDC option in gadget writes the UDC file under the 'gadget' directory to attach the generated gadget config. It's also possible to apply pre-made config templates under /usr/share/usbgadget. The templates use the same UCI config format, with the 'gadget' entry named 'g1'. Currently, there are templates for CDC-ACM and CDC-NCM gadgets written based on existing g_*.ko module code. Certain SBCs come with only a USB device port (e.g. Raspberry Pi Zero). With this script, it's now possible to perform initial setup on them by adding a default NCM gadget. Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
-rw-r--r--package/utils/usbgadget/Makefile54
-rw-r--r--package/utils/usbgadget/files/presets/acm13
-rw-r--r--package/utils/usbgadget/files/presets/ncm13
-rw-r--r--package/utils/usbgadget/files/usbgadget.conf12
-rw-r--r--package/utils/usbgadget/files/usbgadget.init144
5 files changed, 236 insertions, 0 deletions
diff --git a/package/utils/usbgadget/Makefile b/package/utils/usbgadget/Makefile
new file mode 100644
index 0000000000..d3a68ea9df
--- /dev/null
+++ b/package/utils/usbgadget/Makefile
@@ -0,0 +1,54 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=usbgadget
+PKG_RELEASE:=1
+
+PKG_LICENSE:=BSD-2-Clause
+
+PKG_MAINTAINER:=Chuanhong Guo <gch981213@gmail.com>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/$(PKG_NAME)
+ SECTION:=utils
+ CATEGORY:=Utilities
+ DEPENDS:=@USB_GADGET_SUPPORT +kmod-usb-gadget +kmod-usb-lib-composite
+ TITLE:=init script to create USB gadgets
+endef
+
+define Build/Compile
+endef
+
+define Package/$(PKG_NAME)/install
+ $(INSTALL_DIR) $(1)/etc/config $(1)/etc/init.d
+ $(INSTALL_CONF) ./files/usbgadget.conf $(1)/etc/config/usbgadget
+ $(INSTALL_BIN) ./files/usbgadget.init $(1)/etc/init.d/usbgadget
+endef
+
+$(eval $(call BuildPackage,$(PKG_NAME)))
+
+# 1: short name
+# 2: description
+# 3: dependencies on other packages
+define GadgetPreset
+ define Package/$(PKG_NAME)-$(1)
+ SECTION:=utils
+ CATEGORY:=Utilities
+ TITLE+= $(2) gadget preset
+ DEPENDS+= $(3)
+ endef
+
+ define Package/$(PKG_NAME)-$(1)/description
+ This package contains the USB gadget preset for $(3).
+ endef
+
+ define Package/$(PKG_NAME)-$(1)/install
+ $(INSTALL_DIR) $$(1)/usr/share/usbgadget
+ $(INSTALL_CONF) ./files/presets/$(1) $$(1)/usr/share/usbgadget
+ endef
+
+ $$(eval $$(call BuildPackage,$(PKG_NAME)-$(1)))
+endef
+
+$(eval $(call GadgetPreset,ncm,CDC-NCM,+kmod-usb-gadget-ncm))
+$(eval $(call GadgetPreset,acm,CDC-ACM,+kmod-usb-gadget-serial)) \ No newline at end of file
diff --git a/package/utils/usbgadget/files/presets/acm b/package/utils/usbgadget/files/presets/acm
new file mode 100644
index 0000000000..f8ce9c4a4a
--- /dev/null
+++ b/package/utils/usbgadget/files/presets/acm
@@ -0,0 +1,13 @@
+config gadget 'g1'
+ option idVendor '0x0525'
+ option idProduct '0xa4a7'
+ option bDeviceClass '2'
+ option product 'Gadget Serial v2.4'
+
+config configuration 'cfg1'
+ option configuration 'ACM'
+ option gadget 'g1'
+
+config function 'acm1'
+ option function 'acm'
+ option configuration 'cfg1'
diff --git a/package/utils/usbgadget/files/presets/ncm b/package/utils/usbgadget/files/presets/ncm
new file mode 100644
index 0000000000..cb3a19329e
--- /dev/null
+++ b/package/utils/usbgadget/files/presets/ncm
@@ -0,0 +1,13 @@
+config gadget 'g1'
+ option idVendor '0x0525'
+ option idProduct '0xa4a1'
+ option bDeviceClass '2'
+ option product 'NCM Gadget'
+
+config configuration 'cfg1'
+ option configuration 'NCM'
+ option gadget 'g1'
+
+config function 'ncm1'
+ option function 'ncm'
+ option configuration 'cfg1'
diff --git a/package/utils/usbgadget/files/usbgadget.conf b/package/utils/usbgadget/files/usbgadget.conf
new file mode 100644
index 0000000000..0d80fc97df
--- /dev/null
+++ b/package/utils/usbgadget/files/usbgadget.conf
@@ -0,0 +1,12 @@
+# apply a preset under /usr/share/usbgadget
+config preset
+ option name 'ncm'
+ # specify a UDC to enable this gadget:
+ # option UDC 'musb-hdrc.2.auto'
+
+# or create a custom gadget here following the content of presets:
+#config gadget 'g1'
+# option idVendor ...
+# ...
+# and add an UDC under the gadget section to enable it:
+# option UDC 'musb-hdrc.2.auto'
diff --git a/package/utils/usbgadget/files/usbgadget.init b/package/utils/usbgadget/files/usbgadget.init
new file mode 100644
index 0000000000..f2e105caae
--- /dev/null
+++ b/package/utils/usbgadget/files/usbgadget.init
@@ -0,0 +1,144 @@
+#!/bin/sh /etc/rc.common
+
+START=19
+
+GADGET_FS=/sys/kernel/config/usb_gadget
+GADGET_PRESETS_DIR=/usr/share/usbgadget
+GADGET_PREFIX=owrt_
+
+log() {
+ logger -t usbgadget "$@"
+}
+
+apply_configs() {
+ local fs_path="$1"
+ local cfg="$2"
+ for param in $(find "$fs_path" -maxdepth 1 -type f -exec basename '{}' ';'); do
+ [ "$param" = "UDC" ] && continue
+
+ config_get val "$cfg" "$param"
+ [ -n "$val" ] && echo "$val" > "${fs_path}/${param}"
+ done
+}
+
+setup_gadget() {
+ local cfg="$1"
+ local gadget_path="${GADGET_FS}/${GADGET_PREFIX}${cfg}"
+ local param udc
+
+ config_get udc "$cfg" UDC
+ [ -z "$udc" ] && return
+
+ mkdir "$gadget_path" || return
+ apply_configs "$gadget_path" "$cfg"
+
+ local strings_path="${gadget_path}/strings/0x409"
+ mkdir "$strings_path"
+ apply_configs "$strings_path" "$cfg"
+}
+
+setup_configuration() {
+ local cfg="$1"
+ local gadget
+ config_get gadget "$cfg" gadget
+ local cfgs_path="${GADGET_FS}/${GADGET_PREFIX}${gadget}/configs"
+ [ -d "${cfgs_path}" ] || return
+ local cfg_path="${cfgs_path}/${cfg}.1"
+ mkdir "$cfg_path" || {
+ log "failed to create configuration ${cfg}"
+ return
+ }
+
+ apply_configs "$cfg_path" "$cfg"
+
+ local strings_path="${cfg_path}/strings/0x409"
+ mkdir "$strings_path"
+ apply_configs "$strings_path" "$cfg"
+}
+
+setup_function() {
+ local cfg="$1"
+ local usbcfg gadget usbfun
+
+ config_get usbcfg "$cfg" configuration
+ [ -z "$usbcfg" ] && return
+ config_get usbfun "$cfg" function
+ [ -z "$usbfun" ] && return
+
+ config_get gadget "$usbcfg" gadget
+ local gadget_path="${GADGET_FS}/${GADGET_PREFIX}${gadget}"
+ local cfg_path="${gadget_path}/configs/${usbcfg}.1"
+ [ -d "${cfg_path}" ] || return
+
+ local fun_path="${gadget_path}/functions/${usbfun}.${cfg}"
+ mkdir "$fun_path" || {
+ log "failed to create function ${usbfun}.${cfg}"
+ return
+ }
+
+ apply_configs "$fun_path" "$cfg"
+
+ ln -s "$fun_path" "$cfg_path"
+}
+
+attach_gadget() {
+ local cfg="$1"
+ local gadget_path="${GADGET_FS}/${GADGET_PREFIX}${cfg}"
+ local param udc
+
+ config_get udc "$cfg" UDC
+ [ -z "$udc" ] && return
+
+ echo "$udc" > "$gadget_path/UDC"
+}
+
+load_gadget() {
+ config_foreach setup_gadget gadget
+ config_foreach setup_configuration configuration
+ config_foreach setup_function function
+ config_foreach attach_gadget gadget
+}
+
+# use subshell for isolated env
+apply_preset() (
+ local preset="$1"
+ local gadget="$2"
+ UCI_CONFIG_DIR=$GADGET_PRESETS_DIR config_load "$1"
+ config_set g1 UDC "$2"
+ load_gadget
+)
+
+load_preset() {
+ local cfg="$1"
+ config_get name "$cfg" name
+ config_get udc "$cfg" UDC
+ [ -z "$udc" ] && return
+ apply_preset $name $udc
+}
+
+start() {
+ grep -q /sys/kernel/config /proc/mounts || \
+ mount -t configfs configfs /sys/kernel/config
+
+ [ -d /sys/kernel/config/usb_gadget ] || {
+ log "usb_gadget support not found."
+ return 1
+ }
+
+ config_load usbgadget
+ config_foreach load_preset preset
+ load_gadget
+}
+
+stop() {
+ for gadget_path in ${GADGET_FS}/${GADGET_PREFIX}* ; do
+ [ -d "$gadget_path" ] || continue
+ echo "" > ${gadget_path}/UDC
+ find ${gadget_path}/configs -maxdepth 2 -type l -exec rm '{}' ';'
+ rmdir ${gadget_path}/configs/*/strings/*
+ rmdir ${gadget_path}/configs/*
+ rmdir ${gadget_path}/functions/*
+ rmdir ${gadget_path}/strings/*
+ rmdir $gadget_path
+ done
+}