#!/bin/sh # zaptel-helper: helper script/functions for Zaptel # Wrriten by Tzafrir Cohen # Copyright (C) 2006-2007, Xorcom # # All rights reserved. # # 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. # Should be possible to run with -e set. This is also recommended. # Constants: # maximal time (in seconds) to wait for /dev/zap/dtl to appear after # loading zaptel DEVZAP_TIMEOUT=${DEVZAP_TIMEOUT:-20} # Zaptel modules we'll try when detecting zaptel hardware: ALL_MODULES="${ALL_MODULES:-zaphfc qozap ztgsm wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wanpipe wcusb xpp_usb}" # Where do we write the list of modules we detected (if at all): MODLIST_FILE_DEBIAN=${MODLIST_FILE_DEBIAN:-/etc/modules} MODLIST_FILE_REDHAT=${MODLIST_FILE_REDHAT:-/etc/sysconfig/zaptel} # The location of of the fxotune binary FXOTUNE="${FXOTUNE:-/usr/sbin/fxotune}" FXOTUNE_CONF="${FXOTUNE_CONF:-/etc/fxotune.conf}" # this is the context FXO zaptel channels are in. # See run_fxotune. FXO_CONTEXT=${FXO_CONTEXT:-from-pstn} ZTCFG="${ZTCFG:-/sbin/ztcfg}" # TODO: this may not be appropriate for a general-purpose script. # However you should not use a direct 'echo' to write output to the user #, to make it simple to override. say() { echo "$@" } error() { echo >&2 "$@" } die() { error "$@" exit 1 } ############################################################################# ##### ##### Init helper functions ##### # Wait for udev to generate /dev/zap/ctl, if needed: wait_for_zapctl() { # if device file already exists, or if zaptel has failed to load: # no point waiting. if [ -c /dev/zap/ctl ] || ! grep -q zaptel /proc/modules ; then return fi say "Waiting for /dev/zap/ctl to be generated" devzap_found=0 for i in `seq $DEVZAP_TIMEOUT`; do sleep 1 if [ -c /dev/zap/ctl ]; then devzap_found=1 break fi done if [ "$devzap_found" != 1 ]; then say "Still no /dev/zap/ctl after $devzap_timeout seconds." error "No /dev/zap/ctl: cannot run ztcfg. Aborting." fi } # load the fxotune parameters # FIXME: /etc/fxotune.conf is a bad location for that file . # /etc/zaptel/fxotune.conf? fxotune_load() { if [ -x "$FXOTUNE" ] && [ -r "FXOTUNE_CONF" ]; then $FROTUNE -s fi } # If there is no zaptel timing source, load # ztdummy. Other modules should have been loaded by # now. guarantee_timing_source() { if ! head -c 0 /dev/zap/pseudo 2>/dev/null then modprobe ztdummy || true # will fail if there is no module package fi } kill_zaptel_users() { fuser -k /dev/zap/* } # recursively unload a module and its dependencies, if possible. # where's modprobe -r when you need it? # inputs: module to unload. # returns: the result from unload_module() { module="$1" line=`lsmod 2>/dev/null | grep "^$1 "` if [ "$line" = '' ]; then return; fi # module was not loaded set -- $line # $1: the original module, $2: size, $3: refcount, $4: deps list mods=`echo $4 | tr , ' '` for mod in $mods; do # run in a subshell, so it won't step over our vars: (unload_module $mod) # TODO: the following is probably the error handling we want: # if [ $? != 0 ]; then return 1; fi done rmmod $module } # sleep a while until the xpp modules fully register wait_for_xpp() { if [ -d /proc/xpp ] then # wait for the XPDs to register: # TODO: improve error reporting and produce a messagee here cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true fi } zap_reg_xpp() { if [ ! -d /proc/xpp ]; then return; fi # Get a list of connected Astribank devices, sorted by the name of # the USB connector. That order is rather arbitrary, but will not # change without changes to the cabling. xbusses=`sort -k 2 /proc/xpp/xbuses | awk -F: '/STATUS=connected/ {print $1}'` # get a list of XPDs that were not yet registered as zaptel spans. # this will be the case if you set the parameter zap_autoreg=0 to # the module xpp # Append /dev/null to provide a valid file name in case of an empty pattern. xbusses_pattern=`echo $xbusses| sed -e 's|XBUS-[0-9]*|/proc/xpp/&/XPD-*/zt_registration|g'`' /dev/null' xpds_to_register=`grep -l 0 $xbusses_pattern 2>/dev/null` || true for file in $xpds_to_register; do echo 1 >$file done } # Set the sync source of the Astribank to the right value fix_asterisbank_sync() { # do nothing if module not present if [ ! -d /proc/xpp ]; then return; fi #if ! grep -q '^HOST' /proc/xpp/sync 2>/dev/null; then return; fi case "$XPP_SYNC" in n*|N*) return;; host|HOST) sync_value="HOST";; [0-9]*)sync_value="$XPP_SYNC";; *) # find the number of the first bus, and sync from it: fxo_pat=`awk -F: '/STATUS=connected/{print $1}' /proc/xpp/xbuses | sed -e 's|.*|/proc/xpp/&/*/fxo_info|'` # find the first FXO unit, and set it as the sync master bus=`ls -1 $fxo_pat 2> /dev/null | head -n1 | cut -d- -f2 | cut -d/ -f1` # do nothing if there is no bus: case "$bus" in [0-9]*):;; *) return;; esac sync_value="$bus 0" ;; esac # the built-in echo of bash fails to print a proper error on failure if ! /bin/echo "$sync_value" >/proc/xpp/sync then error "Updating XPP sync source failed (used XPP_SYNC='$XPP_SYNC')" fi } run_adj_clock() { if [ "$XPP_RUN_ADJ_CLOCK" = '' ]; then return; fi # daemonize adj_clock: (adj_clock /dev/null 2>&1 &)& } init_astribank() { wait_for_xpp zap_reg_xpp fix_asterisbank_sync run_adj_clock } xpp_do_blink() { val="$1" shift for xbus in $* do for xpd in /proc/xpp/XBUS-"$xbus"/XPD-* do echo "$val" > "$xpd/blink" done done } xpp_blink() { xbuses=`grep STATUS=connected /proc/xpp/xbuses | sed -e 's/^XBUS-//' -e 's/:.*$//'` num=`echo $1 | tr -c -d 0-9` case "$num" in [0-9]*) shift xpp_do_blink 1 $xbuses sleep 2 xpp_do_blink 0 $xbuses ;; *) shift echo 1>&2 Enumerating $xbuses xpp_do_blink 0 $xbuses for i in $xbuses do echo "BLINKING: $i" xpp_do_blink 1 "$i" sleep 2 xpp_do_blink 0 "$i" done ;; esac } # The current Debian start function. # The function is not responsible for loading the zaptel modules: # they will be loaded beforehand. debian_start() { wait_for_xpp zap_reg_xpp fix_asterisbank_sync wait_for_zapctl if [ -r /etc/fxotune.conf ] && [ -x $FXOTUNE ]; then $FXOTUNE -s fi # configure existing modules: $ZTCFG } # run_fxotune: destroy all FXO channels and run fxotune. # This allows running fxotune without completly shutting down Asterisk. # # A simplistic assumption: every zaptel channel in the context from-pstn # is a FXO ones. # or rather: all tunable FXO channels are in the context from-pstn are # not defined by zaptel. run_fxotune() { zap_fxo_chans=`asterisk -rx "zap show channels" | awk "/$FXO_CONTEXT/{print \$1}"` xpp_fxo_chans=`cat /proc/zaptel/* | awk '/XPP_FXO/{print $1}'` for chan in $xpp_fxo_chans $zap_fxo_chans; do asterisk -rx "zap destroy channel $chan" done $FXOTUNE -i asterisk -rx "zap restart" } # recursively unload a module and its dependencies, if possible. # where's modprobe -r when you need it? # inputs: module to unload. unload_module() { set +e module="$1" line=`lsmod 2>/dev/null | grep "^$module "` if [ "$line" = '' ]; then return; fi # module was not loaded set -- $line # $1: the original module, $2: size, $3: refcount, $4: deps list mods=`echo $4 | tr , ' '` # xpd_fxs actually sort of depends on xpp: case "$module" in xpd_*) mods="xpp_usb $mods";; esac for mod in $mods; do # run in a subshell, so it won't step over our vars: (unload_module $mod) done rmmod $module || true set -e } unload() { unload_module zaptel } # sleep a while until the xpp modules fully register wait_for_xpp() { if [ -d /proc/xpp ] && \ [ "`cat /sys/module/xpp/parameters/zap_autoreg`" = 'Y' ] then # wait for the XPDs to register: # TODO: improve error reporting and produce a messagee here cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true fi } ############################################################################# ##### ##### Hardware detection functions ##### load_modules() { say "Test Loading modules:" for i in $ALL_MODULES do lines_before=`count_proc_zap_lines` args="${i}_args" eval "args=\$$args" # a module is worth listing if it: # a. loaded successfully, and # b. added channels lines under /proc/zaptel/* if /sbin/modprobe $i $args 2> /dev/null then check=0 case "$i" in xpp_usb) check=`grep 'STATUS=connected' 2>/dev/null /proc/xpp/xbuses | wc -l` ;; # FIXME: zttranscode will always load, and will never # add a span. Maybe try to read from /dev/zap/transcode . zttranscode) : ;; *) if [ $lines_before -lt `count_proc_zap_lines` ]; then check=1; fi ;; esac if [ "$check" != 0 ] then probed_modules="$probed_modules $i" say " ok $i $args" else say " - $i $args" rmmod $i fi else say " - $i $args" fi done } update_module_list_debian() { say "Updating Debian modules list $MODLIST_FILE_DEBIAN." del_args=`for i in $ALL_MODULES ztdummy do echo "$i" | sed s:.\*:-e\ '/^&/d': done` add_args=`for i in $* do echo "$i" | sed s:.\*:-e\ '\$a&': done` sed -i.bak $del_args "$MODLIST_FILE_DEBIAN" for i in $* do echo "$i" done >> "$MODLIST_FILE_DEBIAN" } update_module_list_redhat() { say "Updating modules list in zaptel init config $MODLIST_FILE_REDHAT." sed -i.bak -e '/^MODULES=/d' "$MODLIST_FILE_REDHAT" echo "MODULES=\"$*\"" >> "$MODLIST_FILE_REDHAT" } update_module_list() { if [ -f "$MODLIST_FILE_DEBIAN" ]; then update_module_list_debian "$@" elif [ -f "$MODLIST_FILE_REDHAT" ]; then update_module_list_redhat "$@" else die "Can't find a modules list to update. Tried: $MODLIST_FILE_DEBIAN, $MODLIST_FILE_REDHAT. Aborting" fi } # unless we wanted to use this as a set of functions, run # the given function with its parameters: if [ "$ZAPHELPER_ONLY_INCLUDE" = '' ]; then "$@" fi