Răsfoiți Sursa

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 <[email protected]>
Chuanhong Guo 1 an în urmă
părinte
comite
b196a9f6ce

+ 54 - 0
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 <[email protected]>
+
+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))

+ 13 - 0
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'

+ 13 - 0
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'

+ 12 - 0
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'

+ 144 - 0
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
+}