#!/bin/bash # # sound - sound configuration plugin for postplug # Copyright (c) 2005-2007 by Davide Madrisan # Copyright (c) 2005-2009 by Silvan Calarco # Note: Some code has been stolen from /usr/sbin/alsaconf version 1.0.13 if [ $UID != 0 ]; then echo "$0: must be superuser." >&2 exit 1 fi me="sound" [ -r /etc/sysconfig/machine ] && . /etc/sysconfig/machine . /etc/postplug/postplug.defs [ -r /etc/sysconfig/postplug ] && . /etc/sysconfig/postplug # remove obsolete realtime module configuration if [ -e /etc/modprobe.conf -a "`grep ' realtime ' /etc/modprobe.conf 2>/dev/null`" ]; then sed -i "/options realtime */d" /etc/modprobe.conf sed -i "/alias on-boot-realtime realtime/d" /etc/modprobe.conf fi LSPCI=/usr/sbin/lspci SYSCONFIG_SOUNDCARDS=/etc/sysconfig/soundcards CARDID_DB=/var/lib/postplug/alsaconf.cards function build_card_db() { # convert ISA PnP id number to string 'ABC' function convert_isapnp_id() { [ "$1" ] || return local a b c strs let a='('$1'>>2) & 0x3f' let b='(('$1' & 0x03) << 3) | (('$1' >> 13) & 0x07)' let c='('$1'>> 8) & 0x1f' strs='@ABCDEFGHIJKLMNOPQRSTUVWXYZ' echo ${strs:$a:1}${strs:$b:1}${strs:$c:1} } # swap high & low bytes function swap_number() { local v if [ -z "$1" ]; then echo "0000" return fi let v='(('$1'>>8)&0xff)|(('$1'&0xff)<<8)' printf "%04x" $v } local MODDIR=/lib/modules/`uname -r` local last_driver driver vendor device dummy id1 id2 echo -n > $1 # list pci cards while read driver vendor device dummy; do if expr $driver : 'snd-.*' >/dev/null ; then if [ "$last_driver" != "$driver" ]; then echo $driver.o last_driver=$driver fi id1=`printf '0x%04x' $vendor` id2=`printf '0x%04x' $device` echo "PCI: $id1=$id2" fi done < $MODDIR/modules.pcimap >> $1 # list isapnp cards local cardvendor carddevice data func dev1 dev2 while read driver cardvendor carddevice data vendor func; do if expr $driver : 'snd-.*' >/dev/null ; then if [ "$last_driver" != "$driver" ]; then echo $driver.o last_driver=$driver fi id1=`convert_isapnp_id $cardvendor` dev1=`swap_number $carddevice` id2=`convert_isapnp_id $vendor` dev2=`swap_number $func` echo "ISAPNP: $id1$dev1=$id2$dev2" fi done < $MODDIR/modules.isapnpmap >> $1 } function probe_cards() { local use_modinfo_db=0 local index bindex d1 d2 ncards [ -r /proc/isapnp ] || /sbin/modprobe isapnp >/dev/null 2>&1 [ -r /proc/isapnp ] || /sbin/modprobe isa-pnp >/dev/null 2>&1 if [ -r /proc/isapnp ]; then cat /proc/isapnp > "$DUMP" found="1" elif [ -d /sys/bus/pnp/devices ]; then # use 2.6 kernel's sysfs output # fake the isapnp dump index=0 bindex=0 for d1 in /sys/devices/pnp* ; do for d2 in $d1/*:* ; do if [ -r $d2/card_id ]; then id=`cat $d2/card_id` name=`cat $d2/name` echo "Card $index '$id:$name' " >> "$DUMP" index=$[$index+1] found="1" elif [ -r $d2/id ]; then # FIXME: multiple id might be present (separated with new-line) id=`head -n 1 $d2/id` echo "BIOS $bindex '$id' " >> "$DUMP" bindex=$[$bindex+1] found="1" fi done done fi if [ "$found" = "0" ]; then echo -n >"$DUMP" fi [ -r $CARDID_DB ] || use_modinfo_db=1 if [ $use_modinfo_db != 1 ]; then [ $CARDID_DB -ot /lib/modules/`uname -r`/modules.dep ] && use_modinfo_db=1 fi if [ $use_modinfo_db = 1 ]; then logmsg "$me" "building soundcard database \`$CARDID_DB'" build_card_db $CARDID_DB fi if [ ! -r $CARDID_DB ]; then logmsg "$me" "error: "$"cannot create soundcard database" exit 1 fi ncards=`grep '^snd-.*\.o$' $CARDID_DB | wc -w` awk ' BEGIN { format="%-40s %s\n"; ncards='"$ncards"'; idx=0; } /^snd-.*\.o$/{ sub(/.o$/, ""); driver=$0; perc=(idx * 100) / (ncards + 1); print int(perc); idx++; } /^[]*PCI: /{ gsub(/0x/, ""); gsub(/=/, ":"); x = sprintf ("'$LSPCI' -n 2>/dev/null| grep '"' 04..: '"' | grep %s", $2); if (system (x) == 0) printf "%s %s\n", $2, driver >>"'"$FOUND"'" } /^[]*ISAPNP: /{ id2 = substr($0, index($0, "=")+1); gsub(/=.*/, ""); x = sprintf ("grep '\''^Card [0-9] .%s:'\'' '"$DUMP"'", $2); if (system (x) == 0) printf "%s %s\n", $2, driver >>"'"$FOUND"'" else if (index($2, "ffff") > 0) { x = sprintf ("grep '\''^BIOS [0-9]* .%s.'\'' '"$DUMP"'", id2); if (system (x) == 0) printf "%s %s\n", id2, driver >>"'"$FOUND"'" } }' < $CARDID_DB # # PowerMac # if grep -q MacRISC /proc/cpuinfo; then find /lib/modules/`uname -r` -name 'snd-powermac' -print | \ while read i; do i=${i##*/} i=${i%%.o} i=${i%%.ko} echo "PowerMac $i" >> $FOUND done fi } # set default mixer volumes function set_mixers() { [ -x /usr/bin/amixer ] || return /usr/bin/amixer -s -q <<_EOF set Master 90% unmute set 'Master Mono' 75% unmute set Front 90% unmute set Speaker 90% unmute set PCM 90% unmute mixer Synth 90% unmute mixer CD 90% unmute # mute mic set Mic 0% mute # ESS 1969 chipset has 2 PCM channels set PCM,1 90% unmute # Trident/YMFPCI/emu10k1 set Wave 100% unmute set Music 100% unmute set AC97 100% unmute # CS4237B chipset: set 'Master Digital' 75% unmute # Envy24 chips with analog outs set DAC 90% unmute set DAC,0 90% unmute set DAC,1 90% unmute # some notebooks use headphone instead of master set Headphone 75% unmute set Playback 100% unmute # turn off digital switches set "SB Live Analog/Digital Output Jack" off set "Audigy Analog/Digital Output Jack" off _EOF } function ac_config_card() { CARD_DRIVER=snd-$1 CARD_OPTS="${*:2}" # soundcard already configured grep -q "alias snd-card-0 $CARD_DRIVER" ${cfgout:-$cfgfile} 2>/dev/null && { logmsg "$me" $"soundcard \"$CARD_DRIVER\" already configured" return; } logmsg "$me" $"configuring soundcard \"$1\"" addcfg=`mktemp -q /tmp/alsaconf.XXXXXX` || { logmsg "$me" $"error: "$"cannot create temporary files" exit 1; } if ! grep -q char-major-116 /lib/modules/`uname -r`/modules.alias; then [ "$cfgout" ] && echo "# --- Generated by POSTPLUG, do not edit. ---" >> $addcfg || echo "$ACB" >> $addcfg echo "\ alias char-major-116 snd alias char-major-14 $SOUND_CORE alias sound-service-0-0 snd-mixer-oss alias sound-service-0-1 snd-seq-oss alias sound-service-0-3 snd-pcm-oss alias sound-service-0-8 snd-seq-oss alias sound-service-0-12 snd-pcm-oss" >> $addcfg fi # echo "options snd device_mode=0666" >> $addcfg echo "\ alias snd-card-0 $CARD_DRIVER alias sound-slot-0 $CARD_DRIVER" >> $addcfg # apply workarounds for specific machines case "${SYSTEM_MANUFACTURER}_${SYSTEM_PRODUCT_NAME}" in "Hewlett-Packard_HP Compaq 6735s") CARD_OPTS="$CARD_OPTS model=laptop" ;; esac [ "$CARD_OPTS" ] && echo "\ options $CARD_DRIVER $CARD_OPTS" >> $addcfg # # load modem after soundcard in case of snd-intel8x0 card # if [ "$CARD_DRIVER" = "snd-intel8x0" ]; then # echo "\ #options snd_intel8x0 index=0 #options snd_intel8x0m index=1" >> $addcfg # CONFIGURE_INTEL8x0=1 # fi [ "$cfgout" ] || echo "$ACE" >> $addcfg cat $addcfg >> ${cfgout:-$cfgfile} /sbin/depmod -a 2>/dev/null echo "SOUNDCARD0=\"$CARD_DRIVER\"" > $SYSCONFIG_SOUNDCARDS # if [ "$CONFIGURE_INTEL8x0" ]; then # # reload modules in correct order # cat /proc/modules | grep "snd_intel8x0 " >/dev/null && rmmod snd_intel8x0 # cat /proc/modules | grep "snd_intel8x0m " >/dev/null && rmmod snd_intel8x0m # modprobe snd_intel8x0 2>/dev/null # modprobe snd_intel8x0m 2>/dev/null # fi # (re)load driver rmmod -f $CARD_DRIVER >/dev/null 2>&1 modprobe $CARD_DRIVER >/dev/null 2>&1 udevadm settle set_mixers if [ -x /usr/sbin/alsactl ]; then logmsg "$me" $"saving the mixer setup (/etc/asound.state)" /usr/sbin/alsactl store >/dev/null 2>&1 fi rm -f $addcfg } if [ "$SOUND_BUILD_CARDID_DB_ONLY" ]; then build_card_db $CARDID_DB exit 0 fi if [ "$SOUND_FORCE_RESCAN" != on ]; then # audio device change detection SOUND_DEV="`lspci -n | grep " 04[0-9][0-9]: "`" [ "$SOUND_DEV" ] || exit 0 if [ -e $SYSCONFIG_SOUNDCARDS ]; then if [ -e $postpluglibdir/sound.cache ]; then SOUND_DEV_CACHED="`cat $postpluglibdir/sound.cache`" [ "$SOUND_DEV" = "$SOUND_DEV_CACHED" ] && exit 0 logmsg "$me" "warning: audio device appears to have changed; re-probing" mv $SYSCONFIG_SOUNDCARDS $SYSCONFIG_SOUNDCARDS.postplug.save else [ -r $SYSCONFIG_SOUNDCARDS ] && . $SYSCONFIG_SOUNDCARDS # soundcards already detected and configured [ "$SOUNDCARD0" ] && { [ -e $postpluglibdir/sound.cache ] || echo "$SOUND_DEV" > $postpluglibdir/sound.cache exit 0 } fi fi fi FOUND=`mktemp -q /tmp/alsaconf.XXXXXX` || { logmsg "$me" $"error: "$"cannot create temporary files"; exit 1; } DUMP=`mktemp -q /tmp/alsaconf.XXXXXX` || { logmsg "$me" $"error: "$"cannot create temporary files"; exit 1; } TMP=`mktemp -q /tmp/alsaconf.XXXXXX` || { logmsg "$me" $"error: "$"cannot create temporary files"; exit 1; } trap "rm -f $TMP $FOUND $DUMP" 0 1 2 5 15 # populate the `$FOUND' file with the list of available PCI soundcards probe_cards >/dev/null devs_found=() if [ -s "$FOUND" ]; then while read dev card ; do /sbin/modprobe -a -l | grep -E $card'\.(o|ko)' >/dev/null 2>&1 || continue devs_found=("${devs_found[@]}" "${card##snd-}") done < "$FOUND" fi case "$(uname -r)" in 2.6.*) cfgfile="/etc/modprobe.conf" [ -d /etc/modprobe.conf.d ] && cfgout="/etc/modprobe.conf.d/sound" [ -d /etc/modprobe.d ] && cfgout="/etc/modprobe.d/sound.conf" ;; *) cfgfile="/etc/modules.conf" ;; esac ACB="# --- BEGIN: Generated by ALSACONF, do not edit. ---" ACE="# --- END: Generated by ALSACONF, do not edit. ---" # remove ac block if [ -e $cfgfile ]; then awk '/^'"$ACB"'$/,/^'"$ACE"'$/ { next } { print }' < $cfgfile > $TMP cat $TMP > $cfgfile fi [ -e "$cfgout" ] && rm -f $cfgout if [ "$devs_found" ]; then # FIXME : eventually check for TP600E soundcard if [ "$devs_found" = "legacy" ]; then # FIXME : no ISA cards supported for now : # ac_config_legacy (alsaconf script) else logmsg "$me" $"detected PCI sound card(s) \"$devs_found\"" ac_config_card "$devs_found" fi else [ -d /usr/share/config/ ] && KCMARTSRC=/usr/share/config/kcmartsrc [ -d /opt/kde3/share/ ] && KCMARTSRC=/opt/kde3/share/config/kcmartsrc [ "$KCMARTSRC" ] || KCMARTSRC="$(kde-config --prefix 2>/dev/null)/share/config/kcmartsrc" [ -e "$KCMARTSRC" ] || { logmsg "$me" $"creating $KCMARTSRC" echo "\ [Arts] StartServer=false" > $KCMARTSRC; } fi /sbin/modprobe -r isapnp >/dev/null 2>&1 /sbin/modprobe -r isa-pnp >/dev/null 2>&1 echo "$SOUND_DEV" > $postpluglibdir/sound.cache exit 0