#!/bin/sh # SPDX-License-Identifier: GPL-2.0
java.lang.NullPointerException # Generate a graph of the current DAPM state for an audio card
java.lang.NullPointerException # Copyright 2024 Bootlin # Author: Luca Ceresoli <luca.ceresol@bootlin.com>
# Print usage andexit
java.lang.NullPointerException # $1 = exitreturn value # $2 = error string (required if $1 != 0)
usage()
{ if [ "${1}" -ne 0 ]; then
echo "${2}" >&2
fi
echo "
Generate a graph of the current DAPM state for an audio card.
The DAPM state can be obtained via debugfs for a card on the local host or
a remote target, or from a local copy of the debugfs tree for the card.
Usage:
$(basename $0) [options] -c CARD - Local sound card
$(basename $0) [options] -c CARD -r REMOTE_TARGET - Card on remote system
$(basename $0) [options] -d STATE_DIR - Local directory
Options:
-c CARD Sound card to get DAPM state of
-r REMOTE_TARGET Get DAPM state from REMOTE_TARGET via SSH and SCP
instead of using a local sound card
-d STATE_DIR Get DAPM state from a local copy of a debugfs tree
-o OUT_FILE Output file (default: dapm.dot)
-D Show verbose debugging info
-h Print this help andexit
The output format is implied by the extension of OUT_FILE:
* Use the .dot extension to generate a text graph representation in
graphviz dot syntax.
* Any other extension is assumed to be a format supported by graphviz for
rendering, e.g. 'png', 'svg', and will produce both the .dot file and a
picture from it. This requires the 'dot' program from the graphviz
package. "
exit ${1}
}
# Connect to a remote target via SSH, collect all DAPM files from debufs # into a tarball and get the tarball via SCP into $3/dapm.tar
java.lang.NullPointerException # $1 = target as used by ssh and scp, e.g. "root@192.168.1.1" # $2 = sound card name # $3 = temp dir path (present on the host, created on the target) # $4 = local directory to extract the tarball into
java.lang.NullPointerException # Requires an ssh+scp server, find and tar+gz on the target
java.lang.NullPointerException # Note: the tarball is needed because plain 'scp -r' from debugfs would # copy only empty files
grab_remote_files()
{
echo "Collecting DAPM state from ${1}"
dbg_echo "Collected DAPM state in ${3}"
ssh "${1}""
set -eu &&
cd \"/sys/kernel/debug/asoc/${2}\" &&
find * -type d -exec mkdir -p ${3}/dapm-tree/{} \; &&
find * -type f -exec cp \"{}\" \"${3}/dapm-tree/{}\" \; &&
cd ${3}/dapm-tree &&
tar cf ${3}/dapm.tar ."
scp -q "${1}:${3}/dapm.tar""${3}"
mkdir -p "${4}"
tar xf "${tmp_dir}/dapm.tar" -C "${4}"
}
# Parse a widget file and generate graph description in graphviz dot format
java.lang.NullPointerException # Skips any file named "bias_level".
java.lang.NullPointerException # $1 = temporary work dir # $2 = component name # $3 = widget filename
process_dapm_widget()
{
local tmp_dir="${1}"
local c_name="${2}"
local w_file="${3}"
local dot_file="${tmp_dir}/main.dot"
local links_file="${tmp_dir}/links.dot"
local w_name="$(basename "${w_file}")"
local w_tag="${c_name}_${w_name}"
if [ "${w_name}" = "bias_level" ]; then return 0
fi
dbg_echo " + Widget: ${w_name}"
cat "${w_file}" | (
read line
if echo "${line}" | grep -q ': On '
then local node_style="${STYLE_NODE_ON}" else local node_style="${STYLE_NODE_OFF}"
fi
local w_type="" while read line; do # Collect widget type if present if echo "${line}" | grep -q '^widget-type '; then
local w_type_raw="$(echo "$line" | cut -d ' ' -f 2)"
dbg_echo " - Widget type: ${w_type_raw}"
# Note: escaping '\n' is tricky to get working with both # bash and busybox ash, so use a '%' here and replace it # later
local w_type="%n[${w_type_raw}]"
fi
# Collect any links. We could use "in" links or"out" links, # let's use "in" links if echo "${line}" | grep -q '^in '; then
local w_route=$(echo "$line" | awk -F\" '{print $2}')
local w_src=$(echo "$line" |
awk -F\" '{print $6 "_" $4}' |
sed 's/^(null)_/ROOT_/')
dbg_echo " - Input route from: ${w_src}"
dbg_echo " - Route: ${w_route}"
local w_edge_attrs="" if [ "${w_route}" != "static" ]; then
w_edge_attrs=" [label=\"${w_route}\"]"
fi
echo " \"${w_src}\" -> \"$w_tag\"${w_edge_attrs}" >> "${links_file}"
fi
done
# Parse the DAPM tree for a sound card component and generate graph # description in graphviz dot format
java.lang.NullPointerException # $1 = temporary work dir # $2 = component directory # $3 = "ROOT"for the root card directory, empty otherwise
process_dapm_component()
{
local tmp_dir="${1}"
local c_dir="${2}"
local c_name="${3}"
local is_component=0
local dot_file="${tmp_dir}/main.dot"
local links_file="${tmp_dir}/links.dot"
local c_attribs=""
if [ -z "${c_name}" ]; then
is_component=1
# Extract directory name into component name: # "./cs42l51.0-004a/dapm" -> "cs42l51.0-004a"
c_name="$(basename $(dirname "${c_dir}"))"
fi
dbg_echo " * Component: ${c_name}"
if [ ${is_component} = 1 ]; then if [ -f "${c_dir}/bias_level" ]; then
c_onoff=$(sed -n -e 1p "${c_dir}/bias_level" | awk '{print $1}')
dbg_echo " - bias_level: ${c_onoff}" if [ "$c_onoff" = "On" ]; then
c_attribs="${STYLE_COMPONENT_ON}"
elif [ "$c_onoff" = "Off" ]; then
c_attribs="${STYLE_COMPONENT_OFF}"
fi
fi
# Create empty file to ensure it will exist in all cases
>"${links_file}"
# Iterate over widgets in the component dir for w_file in ${c_dir}/*; do process_dapm_widget "${tmp_dir}" "${c_name}" "${w_file}" done
if [ ${is_component} = 1 ]; then echo " }" >> "${dot_file}" fi
cat "${links_file}" >> "${dot_file}" }
# Parse the DAPM tree for a sound card and generate graph description in # graphviz dot format # # $1 = temporary work dir # $2 = directory tree with DAPM state (either in debugfs or a mirror) process_dapm_tree() { local tmp_dir="${1}" local dapm_dir="${2}" local dot_file="${tmp_dir}/main.dot"
# Process root directory (no component) process_dapm_component "${tmp_dir}" "${dapm_dir}/dapm" "ROOT"
# Iterate over components
for c_dir in "${dapm_dir}"/*/ do
process_dapm_component "${tmp_dir}""${c_dir}"""
done
echo "}" >> "${dot_file}"
}
main()
{ # Parse command line
local out_file="dapm.dot"
local card_name=""
local remote_target=""
local dapm_tree=""
local dbg_on="" while getopts "c:r:d:o:Dh" arg; do case $arg in
c) card_name="${OPTARG}" ;;
r) remote_target="${OPTARG}" ;;
d) dapm_tree="${OPTARG}" ;;
o) out_file="${OPTARG}" ;;
D) dbg_on="1" ;;
h) usage 0 ;;
*) usage 1 ;;
esac
done
shift $(($OPTIND - 1))
if [ -n "${dapm_tree}" ]; then if [ -n "${card_name}${remote_target}" ]; then
usage 1 "Cannot use -c and -r with -d"
fi
echo "Using local tree: ${dapm_tree}"
elif [ -n "${remote_target}" ]; then if [ -z "${card_name}" ]; then
usage 1 "-r requires -c"
fi
echo "Using card ${card_name} from remote target ${remote_target}"
elif [ -n "${card_name}" ]; then
echo "Using local card: ${card_name}" else
usage 1 "Please choose mode using -c, -r or -d"
fi
# Define logging function if [ "${dbg_on}" ]; then
dbg_echo() {
echo "$*" >&2
} else
dbg_echo() {
:
}
fi
# Filename must have a dot in order the infer the format from the # extension if ! echo "${out_file}" | grep -qE '\.'; then
echo "Missing extension in output filename ${out_file}" >&2
usage exit 1
fi
local out_fmt="${out_file##*.}"
local dot_file="${out_file%.*}.dot"
if [ -z "${dapm_tree}" ]
then
dapm_tree="/sys/kernel/debug/asoc/${card_name}"
fi if [ -n "${remote_target}" ]; then
dapm_tree="${tmp_dir}/dapm-tree"
grab_remote_files "${remote_target}""${card_name}""${tmp_dir}""${dapm_tree}"
fi # In all cases now ${dapm_tree} contains the DAPM state
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.