| #!/bin/bash |
| # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # TODO(thutt): Convert to /bin/sh from bash |
| # TODO(thutt): Lookup board configs by config file installed |
| # by private overlay. |
| # TODO(thutt): This scripts makes an assumption that all Arm-based boards use |
| # WM8903 and that the board will always have the same codec. |
| # |
| NAME=$(basename "${0}"); |
| AMIXER=${AMIXER:-"/usr/bin/amixer"}; |
| SLEEP_TIME=${SLEEP_TIME:-"0.5"}; # Seconds to sleep between GPIO checking. |
| HP_GPIO="185"; # Headphone GPIO. |
| HP_GPIO_DIR="/sys/class/gpio/gpio${HP_GPIO}"; |
| # This represents the board this image is targeted for. |
| BOARD="$(cat /etc/lsb-release | grep CHROMEOS_RELEASE_BOARD | cut -d'=' -f2)" |
| # This is the codec chip we are currently using. |
| CODEC="$(cat /proc/asound/pcm | head -n1 | cut -d':' -f2 | awk '{print $1}')" |
| |
| declare active_low; # inv: '0' or '1'. |
| declare machine_kind; # inv: An element of 'machine_to_codec'. |
| declare codec; # inv: ${machine_to_codec[${machine_kind}]} |
| |
| function log () |
| { |
| msg=${1}; |
| logger "${NAME}: ${msg}."; |
| } |
| |
| function failure () |
| { |
| msg=${1}; |
| log "Headphone jack cannot be monitored: ${msg}"; |
| false || exit; |
| } |
| |
| function get_gpio_attribute () |
| { |
| attribute=${1}; # Pathname of GPIO attribute to read. |
| shift; |
| if [ -f "${attribute}" ] ; then |
| cat "${attribute}"; |
| true && return; |
| else |
| echo ""; |
| false || return; |
| fi; |
| } |
| |
| function wm8903_set_output_headphones () |
| { |
| ${AMIXER} set 'Speaker' off &>/dev/null |
| ${AMIXER} set 'Int Spk' off &>/dev/null |
| ${AMIXER} set 'Headphone' on &>/dev/null |
| } |
| |
| function wm8903_set_output_internal_speaker () |
| { |
| ${AMIXER} set 'Speaker' on &>/dev/null |
| ${AMIXER} set 'Int Spk' on &>/dev/null |
| ${AMIXER} set 'Headphone' off &>/dev/null |
| } |
| |
| function wm8903_initialize () |
| { |
| # Without enabling DACL, Kaen has no speaker output. |
| ${AMIXER} set 'Speaker' 100% &>/dev/null |
| ${AMIXER} set 'Headphone' 100% &>/dev/null |
| ${AMIXER} set 'Digital' 100% &>/dev/null |
| ${AMIXER} set "Left Speaker Mixer DACL" on &>/dev/null |
| ${AMIXER} set "Right Speaker Mixer DACL" on &>/dev/null |
| ${AMIXER} set 'ADC Input' 'DMIC' &>/dev/null |
| } |
| |
| function initialize_codec () |
| { |
| # Board type is found in /etc/lsb-release: |
| # tegra2_seaboard |
| # We need to support the audio config per board. |
| local machine_kind=$BOARD |
| # Codec type is found in /proc/asound/pcm |
| # TODO(thutt): We should support more than one codec, and |
| # support more than one codec per board. Current implementation |
| # is a stopgap. |
| codec="" |
| if [ "$CODEC" = "WM8903" ]; then |
| codec="wm8903" |
| fi |
| |
| if [ -n "${codec}" ] ; then |
| init_fn="${codec}_initialize"; |
| if declare -f ${init_fn} >/dev/null; then |
| ${init_fn}; |
| else |
| false; |
| fi; |
| else |
| false; |
| fi; |
| } |
| |
| function multiplex () |
| { |
| local hp_gpio_dir=${1}; |
| local value_pathname="${hp_gpio_dir}/value"; |
| local -a value; |
| |
| value[1]="-"; # Force mismatch on first loop. |
| while true ; do |
| value[0]=${value[1]}; |
| value[1]="$(get_gpio_attribute "${value_pathname}")"; |
| if [ "${value[0]}" != "${value[1]}" ] ; then |
| # Headphone Jack has changed state. |
| case "${active_low}${value[1]}" in |
| "00" ) ${codec}_set_output_headphones; ;; |
| "01" ) ${codec}_set_output_internal_speaker; ;; |
| "10" ) ${codec}_set_output_internal_speaker; ;; |
| "11" ) ${codec}_set_output_headphones; ;; |
| * ) # Ignore invalid combos. |
| ;; |
| esac; |
| fi; |
| sleep ${SLEEP_TIME}; |
| done; |
| } |
| |
| function main () |
| { |
| local hp_gpio_dir=$(readlink --canonicalize "${HP_GPIO_DIR}"); |
| if [ ! -d "${hp_gpio_dir}" ] ; then |
| failure "'${HP_GPIO_DIR}' does not exist"; |
| fi; |
| |
| active_low=$(get_gpio_attribute "${hp_gpio_dir}/active_low"); |
| if [ -z "${active_low}" ] ; then |
| failure "Unable to determine active low or active high"; |
| fi; |
| multiplex ${hp_gpio_dir} |
| } |
| |
| if initialize_codec ; then |
| main; |
| else |
| log "Unknown machine / sound codec combo; headphone jack not managed." |
| fi; |
| true && exit; |