#!/bin/bash
#
# alsasound     This shell script takes care of starting and stopping
#               the ALSA sound driver.
#
# This script requires /usr/sbin/alsactl program from alsa-utils package.
#
# Copyright (c) by Jaroslav Kysela <perex@suse.cz> 
#
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#
# For RedHat 5.0+:
# chkconfig: 2345 87 14
# description: ALSA driver
#
# modified to visually fit into SuSE 6.0+ by Philipp Thomas <pthomas@suse.de>
# further improvements by Bernd Kaindl, Olaf Hering and Takashi Iwai.
# 
### BEGIN INIT INFO
# Provides:       alsasound
# Required-Start: $remote_fs
# Required-Stop:  $remote_fs
# Default-Start:  2 3 5
# Default-Stop:
# Description:    Loading ALSA drivers and store/restore the current setting
### END INIT INFO

. /etc/rc.status
. /etc/sysconfig/sound

test -z $LOAD_SEQUENCER && LOAD_SEQUENCER=yes

# Shell functions sourced from /etc/rc.status:
#      rc_check         check and set local and overall rc status
#      rc_status        check and set local and overall rc status
#      rc_status -v     ditto but be verbose in local rc status
#      rc_status -v -r  ditto and clear the local rc status
#      rc_failed        set local and overall rc status to failed
#      rc_reset         clear local rc status (overall remains)
#      rc_exit          exit appropriate to overall rc status

# First reset status of this service
rc_reset

alsactl=/usr/sbin/alsactl
asoundcfg=/etc/asound.state
aconnect=/usr/bin/aconnect
alsascrdir=/etc/alsa.d
if [ -x /sbin/lsmod ]; then
  lsmod=/sbin/lsmod
else
  lsmod=lsmod
fi

# modprobe returns 255 when failed..
function probe_module () {
   /sbin/modprobe $*
   test $? = 0 && return 0
   return 1
}

function load_sequencer() {
  #
  # insert sequencer modules
  #
  if [ x"$LOAD_SEQUENCER" = xyes -a -r /proc/asound/seq/drivers ]; then
    cut -d , -f 1 /proc/asound/seq/drivers | \
    while read t ; do
      test -z $t || /sbin/modprobe $t
    done
  fi
}

function load_carddeps() {
  #
  # run card-dependent scripts
  for i in $*; do
    i=${i##snd-}
    i=${i##snd_}
    if [ -x $alsascrdir/$i ]; then
      $alsascrdir/$i
    fi
  done
}

function restore_mixer() {
  #
  # restore driver settings
  #
  if [ -d /proc/asound ]; then
    if [ ! -r $asoundcfg ]; then
      if [ -x /usr/bin/set_default_volume ]; then
        echo "No mixer config is found - adjusting default volumes"
	grep '^[0-9]' /proc/asound/cards | while read card; do
	    /usr/bin/set_default_volume $card
	done
      else
        echo "No mixer config in $asoundcfg, you have to unmute your card!"
      fi
    else
      echo -n "Restoring the previous sound setting"
      $alsactl -F -f $asoundcfg restore >/dev/null 2>&1
      rc_status -v
    fi
  fi
}

function get_drivers() {
  /sbin/modprobe -c | \
    grep -E "^[[:space:]]*alias[[:space:]]+snd-card-[[:digit:]]" | sort |\
	awk '{print $3}'
}

function start() {
  #
  # insert all sound modules
  #
  module_loaded=0
  c=""
  drivers=`get_drivers`
  for i in $drivers; do
    if [ $i != off ]; then
      if [ x$c = x ]; then
        echo -n ": "
	c=1
      fi
      j=${i##snd-}
      j=${i##snd_}
      echo -n " $j"
      probe_module $i && module_loaded=1
    fi
  done
  rc_status -v -r
  test $module_loaded -eq 0 && return
  #
  # insert 32bit ioctl wrapper if exists
  #
  /sbin/modprobe snd-ioctl32 >/dev/null 2>&1
  #
  # rest of start action...
  #
  load_sequencer
  if [ x"$LOAD_OSS_EMUL_MODULES" = xyes ]; then
    /sbin/modprobe snd-pcm-oss
    # /sbin/modprobe snd-mixer-oss
    test x"$LOAD_SEQUENCER" = xyes && /sbin/modprobe snd-seq-oss
  fi
  restore_mixer
  load_carddeps $drivers
}

function terminate() {
  #
  # Kill processes holding open sound devices
  #
  # DEVS=`find /dev/ -follow -type c -maxdepth 1 -print 2>/dev/null | xargs ls -dils | grep "1*1[46]," | cut -d: -f2 | cut -d" " -f2; echo /proc/asound/dev/*`
  fuser -k /dev/admmidi? /dev/adsp? /dev/amidi? /dev/audio* /dev/dmfm* \
     /dev/dmmidi? /dev/dsp* /dev/dspW* /dev/midi0? /dev/mixer? /dev/music \
     /dev/patmgr? /dev/sequencer* /dev/sndstat >/dev/null 2>&1
  if [ -d /proc/asound/dev ]; then
    fuser -k /proc/asound/dev/* >/dev/null 2>&1
  fi
  if [ -d /dev/snd ]; then
    fuser -k /dev/snd/* >/dev/null 2>&1
  fi
  #
  # remove all sequencer connections if any
  #
  if [ -f /proc/asound/seq/clients -a -x $aconnect ]; then
    $aconnect --removeall
  fi
}

function stop() {
  #
  # store driver settings
  #
  if [ -x $alsactl ]; then
    $alsactl -f $asoundcfg store
  else
    echo -n -e "${rc_warning}!!!alsactl not found!!!${rc_reset} "
  fi
  #
  # mute master to avoid clicks at unload
  #
  /usr/bin/amixer set Master mute >/dev/null 2>&1
  #
  # remove all sound modules
  #
  $lsmod | grep -E "^snd" | grep -Ev "(snd-page-alloc|snd_page_alloc)" | while read line; do \
     /sbin/rmmod `echo $line | cut -d ' ' -f 1`; \
  done
}

# See how we were called.
case "$1" in
  start)
        # Start driver if it isn't already up.
	echo -n "Starting sound driver"
	if [ ! -d /proc/asound ]; then
	  start
          rc_status
	else
	  echo -n ":  already running"
          rc_status -v
	fi
        ;;
  stop)
        # Stop daemons.
        echo -n "Shutting down sound driver"
	if [ -d /proc/asound ]; then
	  terminate
	  stop
	fi
	rc_status -v
        ;;
  try-restart)
        $0 status >/dev/null && $0 restart
	rc_status
	;;
  restart)
	$0 stop
	$0 start
        rc_status
	;;
  force-reload)
	$0 stop && $0 start
	rc_status
	;;
  reload)
	load_sequencer
	load_carddeps `get_drivers`
	rc_status
	;;
  status)
        if [ -d /proc/asound ]; then
          echo -n "ALSA sound driver loaded."
          rc_status -v
        else
          echo -n "ALSA sound driver not loaded."
	  rc_status -u
        fi
        ;;
  *)
	echo "Usage: $0 {start|stop|try-restart|restart|force-reload|reload|status}"
        exit 1
esac

rc_exit
