mISDN-1_1_9.1/ 0000755 0000000 0000000 00000000000 11137306107 011432 5 ustar root root mISDN-1_1_9.1/add.config 0000644 0000000 0000050 00000000264 11110524073 013157 0 ustar root src #
# Modular ISDN driver
#
CONFIG_MISDN_DRV=m
CONFIG_MISDN_AVM_FRITZ=y
CONFIG_MISDN_HFCPCI=y
CONFIG_MISDN_SPEEDFAX=y
CONFIG_MISDN_W6692=y
CONFIG_MISDN_DSP=y
CONFIG_MISDN_MEMDEBUG=y
mISDN-1_1_9.1/CHANGES 0000644 0000000 0000050 00000000437 11135651701 012243 0 ustar root src mISDN-1-1-2:
- added a workaround that fixes a kernel panic when bridging is done after already a few
voice frames where transceived on both legs (like when you transfer a call from SIP 2 ISDN)
- jollys mail has changed
- minor tweaks to misdn-init and to the Kernel-Patch script
mISDN-1_1_9.1/config/ 0002755 0000000 0000050 00000000000 11135651701 012513 5 ustar root src mISDN-1_1_9.1/config/Makefile 0000644 0000000 0000050 00000000704 11110524073 014144 0 ustar root src
all:
@echo "Please run 'make install'."
install:
install -D -m755 mISDN $(INSTALL_PREFIX)/usr/sbin/mISDN
for file in $(shell echo *.xsl); do install -D -m644 $${file} $(INSTALL_PREFIX)/usr/lib/mISDN/$${file}; done
if [ -d $(INSTALL_PREFIX)/etc/init.d ]; then \
if [ -e $(INSTALL_PREFIX)/etc/init.d/mISDN ]; then rm -rf $(INSTALL_PREFIX)/etc/init.d/mISDN; fi; \
ln -s $(INSTALL_PREFIX)/usr/sbin/mISDN $(INSTALL_PREFIX)/etc/init.d/mISDN; \
fi
mISDN-1_1_9.1/config/README.mISDN 0000644 0000000 0000050 00000005052 11135651701 014304 0 ustar root src 'mISDN': init-script to auto-configure and load the mISDN kernel drivers
===========================================================================
This script makes it easy to configure and activate mISDN compatible
adapter cards. It scans an eyecandy config file named mISDN.conf
for your card and port settings, then it loads the driver modules properly.
The misdn-init.conf can also be autogenerated by the mISDN script.
---------------------------------------------------------------------------
Requirements:
The 'mISDN' script requires you to install the tool 'xsltproc'. To install
xsltproc on debian, just type:
$ apt-get install xsltproc (as root)
On other distros the package name might be libxmtools or likewise.
---------------------------------------------------------------------------
Usage: /usr/sbin/misdn-init start|stop|restart|config|scan|help
--start scan /etc/misdn-init.conf and load the mISDN drivers
--stop unload the mISDN drivers
--restart see stop, then start
--config scan your PCI bus for mISDN compatible hardware and generate
a /etc/mISDN.conf
--scan scan your PCI bus for mISDN compatible hardware and print
the results to the console
--help print the usage info
---------------------------------------------------------------------------
* Here is a quick overview on how to use mISDN:
1) Get and install mISDN:
$ wget http://www.misdn.org/downloads/mISDN.tar.gz
$ tar xzf mISDN.tar.gz
$ cd mISDN*
$ make install
2) Let mISDN scan your PCI bus for mISDN compatible hardware and write
the results into /etc/mISDN.conf:
$ (as root) mISDN config
3) (optional) Edit /etc/mISDN.conf and set everything the way you want it.
This file is heavily commented, hence it should be self-explaining.
4) (optional, but recommended) Add 'mISDN' to your run level.
This is distribution dependend. Here an example for a debian system:
ATTENTION: If you have services in your runlevels that depend
on mISDN, make sure that 'mISDN' starts before, and
stops after them (this is done by changing the values
that are set to 60 in this example, more info: read the
manpage for update-rc.d).
$ (as root) update-rc.d mISDN start 60 2 3 4 5 . stop 60 0 1 6 .
5) Run the following to start mISDN:
$ (as root) mISDN start
---------------------------------------------------------------------------
* Report Bugs:
If you experience any bugs or have a feature request, please visit:
www.isdn4linux.de/mantis
mISDN-1_1_9.1/config/mISDN 0000755 0000000 0000050 00000037752 11135651701 013367 0 ustar root src #!/bin/bash
#----------------------------------------------
#
# CONFIGURATION:
#
MISDN_CONF="/etc/mISDN.conf"
MISDN_CONF_XSL="/usr/lib/mISDN/mISDN.conf.xsl"
#
#----------------------------------------------
SELF="${0}"
USAGE="Usage: ${SELF} start|stop|restart|config|scan|help"
function die {
echo "[!!] ${1}"
exit 1
}
function check_cmd
{
if ! which "${1}" > /dev/null; then
if [ "${2}" = "opt" ]; then
return
fi
if [ "$(id -u)" != "0" ]; then
die "$1 not in path, please install and/or be root."
else
die "$1 not in path, please install."
fi
exit 1
else
local var=$(echo ${1} | tr a-z A-Z)
eval "$var=`which ${1}`"
fi
}
function check_misdn_conf
{
if [ ! -f ${MISDN_CONF} ]; then
die "${MISDN_CONF} not found. Please run: ${SELF} config"
fi
}
check_cmd sed
check_cmd cut
check_cmd cp
check_cmd wc
check_cmd grep
check_cmd xsltproc
check_cmd modprobe
check_cmd sleep
check_cmd lspci
check_cmd lsusb opt
check_cmd mknod
check_cmd chown
check_cmd chmod
declare -a START_COMMANDS
declare -a STOP_COMMANDS
declare -a HFCMULTI_card
declare -a HFCMULTI_type
declare -a HFCMULTI_protocol
declare -a HFCMULTI_layermask
HFCMULTI_options=''
MISDNDSP_options=''
L1OIP_options=''
AVMFRITZ_protocol=''
AVMFRITZ_layermask=''
HFCPCI_protocol=''
HFCPCI_layermask=''
HFCSUSB_protocol=''
HFCSUSB_layermask=''
HFCSUSB_options=''
XHFC_protocol=''
XHFC_layermask=''
XHFC_options=''
L1OIP_type=''
L1OIP_protocol=''
L1OIP_layermask=''
L1OIP_codec=''
L1OIP_ip=''
L1OIP_port=''
L1OIP_localport=''
L1OIP_ondemand=''
L1OIP_id=''
DEVNODE_user='root'
DEVNODE_group='root'
DEVNODE_mode='0644'
declare -a SCAN_card
declare -a SCAN_opts
declare -a SCAN_num_ports
declare -a SCAN_port_opts
function parse_config
{
local CONFIG=$(${XSLTPROC} ${MISDN_CONF_XSL} ${MISDN_CONF})
local t p l line i tmpcmd curr tmpstr extra_modules val
local IFS=$'\n'
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install capi"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_core debug=0"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_l1 debug=0"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_l2 debug=0"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install l3udss1 debug=0"
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_capi"
for line in ${CONFIG}; do
case "${line}" in
DEVNODE:mISDN*)
tmpstr=$(echo ${line} | ${SED} -n 's/.*user:\([^ ]*\).*/\1/p')
if [ ! -z "${tmpstr}" ]; then
DEVNODE_user="${tmpstr}"
fi
tmpstr=$(echo ${line} | ${SED} -n 's/.*group:\([^ ]*\).*/\1/p')
if [ ! -z "${tmpstr}" ]; then
DEVNODE_group="${tmpstr}"
fi
tmpstr=$(echo ${line} | ${SED} -n 's/.*mode:\([^ ]*\).*/\1/p')
if [ ! -z "${tmpstr}" ]; then
DEVNODE_mode="${tmpstr}"
fi
;;
MODULE:hfcmulti*)
HFCMULTI_options=${line:16}
;;
MODULE:hfcsusb*)
HFCSUSB_options=${line:15}
;;
MODULE:xhfc*)
XHFC_options=${line:12}
;;
MODULE:mISDN_debugtool*)
extra_modules[${#extra_modules[@]}]=${line:7}
;;
MODULE:mISDN_dsp*)
MISDNDSP_options=${line:17}
;;
MODULE:l1oip*)
L1OIP_options=${line:13}
;;
CARD:BN*)
curr='hfcmulti'
i=${#HFCMULTI_type[@]}
let "t = $(echo ${line} | ${SED} -n 's/.*type:\([^,]*\).*/\1/p')"
HFCMULTI_type[${i}]=$(printf "0x%x" ${t})
# this is for the BN2E1 card that needs two type numbers
t=$(echo ${line} | ${SED} -n 's/.*type:[^,]*,\([^ ]*\).*/\1/p')
if [ ! -z "${t}" ]; then
let "t = ${t}"
HFCMULTI_type[${i}]="${HFCMULTI_type[${i}]},$(printf "0x%x" ${t})"
fi
HFCMULTI_card[${i}]=$(echo ${line:5} | ${CUT} -d" " -f1)
;;
CARD:hfcpci*)
curr='hfcpci'
;;
CARD:hfcsusb*)
curr='hfcsusb'
;;
CARD:xhfc*)
curr='xhfc'
;;
CARD:avmfritz*)
curr='avmfritz'
;;
CARD:l1oip*)
curr='l1oip'
;;
PORT*)
case "${curr}" in
hfcmulti)
let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
HFCMULTI_protocol[${i}]="${HFCMULTI_protocol[${i}]:+"${HFCMULTI_protocol[${i}]},"}$(printf "0x%x" ${p})"
let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
HFCMULTI_layermask[${i}]="${HFCMULTI_layermask[${i}]:+"${HFCMULTI_layermask[${i}]},"}$(printf "0x%x" ${l})"
;;
hfcpci)
let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
HFCPCI_protocol="${HFCPCI_protocol:+"${HFCPCI_protocol},"}$(printf "0x%x" ${p})"
let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
HFCPCI_layermask="${HFCPCI_layermask:+"${HFCPCI_layermask},"}$(printf "0x%x" ${l})"
;;
hfcsusb)
let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
HFCSUSB_protocol="${HFCSUSB_protocol:+"${HFCSUSB_protocol},"}$(printf "0x%x" ${p})"
let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
HFCSUSB_layermask="${HFCSUSB_layermask:+"${HFCSUSB_layermask},"}$(printf "0x%x" ${l})"
;;
xhfc)
let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
XHFC_protocol="${XHFC_protocol:+"${XHFC_protocol},"}$(printf "0x%x" ${p})"
let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
XHFC_layermask="${XHFC_layermask:+"${XHFC_layermask},"}$(printf "0x%x" ${l})"
;;
avmfritz)
let "p = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
AVMFRITZ_protocol="${AVMFRITZ_protocol:+"${AVMFRITZ_protocol},"}$(printf "0x%x" ${p})"
let "l = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
AVMFRITZ_layermask="${AVMFRITZ_layermask:+"${AVMFRITZ_layermask},"}$(printf "0x%x" ${l})"
;;
l1oip)
let "val = $(echo ${line} | ${SED} -n 's/.*type:\([^ ]*\).*/\1/p')"
L1OIP_type="${L1OIP_type:+"${L1OIP_type},"}$(printf "0x%x" ${val})"
let "val = $(echo ${line} | ${SED} -n 's/.*protocol:\([^ ]*\).*/\1/p')"
L1OIP_protocol="${L1OIP_protocol:+"${L1OIP_protocol},"}$(printf "0x%x" ${val})"
let "val = $(echo ${line} | ${SED} -n 's/.*layermask:\([^ ]*\).*/\1/p')"
L1OIP_layermask="${L1OIP_layermask:+"${L1OIP_layermask},"}$(printf "0x%x" ${val})"
val="$(echo ${line} | ${SED} -n 's/.*codec:\([^ ]*\).*/\1/p')"
L1OIP_codec="${L1OIP_codec:+"${L1OIP_codec},"}${val}"
val="$(echo ${line} | ${SED} -n 's/.*ip:\([^ ]*\).*/\1/p')"
L1OIP_ip="${L1OIP_ip:+"${L1OIP_ip},"}${val}"
val="$(echo ${line} | ${SED} -n 's/.*port:\([^ ]*\).*/\1/p')"
L1OIP_port="${L1OIP_port:+"${L1OIP_port},"}${val}"
val="$(echo ${line} | ${SED} -n 's/.*localport:\([^ ]*\).*/\1/p')"
L1OIP_localport="${L1OIP_localport:+"${L1OIP_localport},"}${val}"
val="$(echo ${line} | ${SED} -n 's/.*ondemand:\([^ ]*\).*/\1/p')"
L1OIP_ondemand="${L1OIP_ondemand:+"${L1OIP_ondemand},"}${val}"
val="$(echo ${line} | ${SED} -n 's/.*id:\([^ ]*\).*/\1/p')"
L1OIP_id="${L1OIP_id:+"${L1OIP_id},"}${val}"
;;
esac
;;
esac
done
if [ ! -z "${HFCMULTI_protocol[0]}" ]; then
tmpcmd="${MODPROBE} --ignore-install hfcmulti type=${HFCMULTI_type[0]}"
i=1
while [ ! -z "${HFCMULTI_type[${i}]}" ]; do
tmpcmd="${tmpcmd},${HFCMULTI_type[${i}]}"
let "i = ${i} + 1"
done
tmpcmd="${tmpcmd} protocol=${HFCMULTI_protocol[0]}"
i=1
while [ ! -z "${HFCMULTI_protocol[${i}]}" ]; do
tmpcmd="${tmpcmd},${HFCMULTI_protocol[${i}]}"
let "i = ${i} + 1"
done
tmpcmd="${tmpcmd} layermask=${HFCMULTI_layermask[0]}"
i=1
while [ ! -z "${HFCMULTI_layermask[${i}]}" ]; do
tmpcmd="${tmpcmd},${HFCMULTI_layermask[${i}]}"
let "i = ${i} + 1"
done
START_COMMANDS[${#START_COMMANDS[@]}]="${tmpcmd} ${HFCMULTI_options}"
fi
if [ ! -z "${HFCPCI_protocol}" ]; then
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install hfcpci protocol=${HFCPCI_protocol} layermask=${HFCPCI_layermask}"
fi
if [ ! -z "${HFCSUSB_protocol}" ]; then
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install hfcsusb protocol=${HFCSUSB_protocol} layermask=${HFCSUSB_layermask} ${HFCSUSB_options}"
fi
if [ ! -z "${XHFC_protocol}" ]; then
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install xhfc protocol=${XHFC_protocol} layermask=${XHFC_layermask} ${XHFC_options}"
fi
if [ ! -z "${AVMFRITZ_protocol}" ]; then
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install avmfritz protocol=${AVMFRITZ_protocol} layermask=${AVMFRITZ_layermask}"
fi
if [ ! -z "${L1OIP_type}" ]; then
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install l1oip type=${L1OIP_type} protocol=${L1OIP_protocol} layermask=${L1OIP_layermask} codec=${L1OIP_codec} ip=${L1OIP_ip} port=${L1OIP_port} localport=${L1OIP_localport} ondemand=${L1OIP_ondemand} id=${L1OIP_id} ${L1OIP_options}"
fi
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install mISDN_dsp ${MISDNDSP_options}"
i=1
while [ ! -z "${extra_modules[${i}]}" ]; do
START_COMMANDS[${#START_COMMANDS[@]}]="${MODPROBE} --ignore-install ${extra_modules[${i}]}"
let "i = ${i} + 1"
done
}
function run_start_commands
{
local i=0
echo "-- Loading mISDN modules --"
while [ ! -z "${START_COMMANDS[${i}]}" ]; do
echo ">> ${START_COMMANDS[${i}]}"
eval "${START_COMMANDS[${i}]}"
let "i = ${i} + 1"
done
}
function run_stop_commands
{
local mod i=0
for mod in $(lsmod | ${SED} -ne '/Module/!{s/\([^ ]*\).*/\1/;p}'); do
case "${mod}" in
mISDN_capi | mISDN_dsp | l3udss1 | mISDN_l2 | mISDN_l1 | mISDN_isac | hfcmulti | hfcpci | hfcsusb | xhfc | avmfritz | l1oip)
STOP_COMMANDS[0]="${STOP_COMMANDS[0]:-"${MODPROBE} -r --ignore-remove"} ${mod}"
;;
mISDN_debugtool)
STOP_COMMANDS[1]="${MODPROBE} -r --ignore-remove mISDN_debugtool"
;;
mISDN_core)
STOP_COMMANDS[2]="${MODPROBE} -r --ignore-remove mISDN_core"
;;
esac
done
echo "-- Unloading mISDN modules --"
for i in `seq 0 1 2`; do
if [ ! -z "${STOP_COMMANDS[${i}]}" ]; then
echo ">> ${STOP_COMMANDS[${i}]}"
eval "${STOP_COMMANDS[${i}]}"
fi
done
}
function scan_devices
{
local skipnext=0 IFS=$'\n'
local NL="
"
function addcard {
SCAN_card[${#SCAN_card[@]}]="${1}"
SCAN_opts[${#SCAN_opts[@]}]="${2}"
SCAN_num_ports[${#SCAN_num_ports[@]}]="${3}"
SCAN_port_opts[${#SCAN_port_opts[@]}]="${4}"
}
for line in $(${LSPCI} -n -d 0xd161:b410); do
addcard "BN4S0" "" 4 'mode="te" link="ptmp"'
done
for line in $(${LSPCI} -n | ${SED} -n 's/^\(0000:\|\)\([0-9a-f]\{2\}:[0-9a-f]\{2\}.[0-9a-f]\{1\}\)\( Class \| \)[0-9a-f]\{4\}: 1397:\([0-9a-f]\{4\}\).*$/\4 \2/p'); do
if [ ${skipnext} -eq 1 ]; then
skipnext=0
continue
fi
case "${line}" in
30b1*)
case "${line:5}" in
00*)
addcard "BN1E1" "" 1 'mode="nt" link="ptp"'
;;
*)
if [ $(${LSPCI} -n -s "${line:5:3}" -d 0x1397:30b1 | ${WC} -l) -eq 2 ]; then
addcard "BN2E1" "" 2 'mode="nt" link="ptp"'
skipnext=1
else
addcard "BN1E1" "" 1 'mode="nt" link="ptp"'
fi
;;
esac
;;
16b8*)
addcard "BN8S0" "" 8 'mode="te" link="ptmp"'
;;
08b4*)
if ${LSPCI} -n -v -s "${line:5}" | ${GREP} "Subsystem" | ${GREP} "1397:b567" > /dev/null ; then
addcard "BN1S0" "" 1 'mode="te" link="ptmp"'
elif ${LSPCI} -n -v -s "${line:5}" | ${GREP} "Subsystem" | ${GREP} "1397:b566\|1397:b569" > /dev/null ; then
addcard "BN2S0" "" 2 'mode="te" link="ptmp"'
else
addcard "BN4S0" "" 4 'mode="te" link="ptmp"'
fi
;;
esac
done
for line in $(${LSPCI} -n | ${GREP} "1397:\(2bd\(0\|6\|7\|8\|9\|a\|b\|c\)\|b100\)\|1043:0675\|0871:ffa\(1\|2\)\|1051:0100\|15b0:2bd0\|114f:007\(0\|1\|2\|3\)\|13d1:2bd1\|182d:3069"); do
addcard "hfcpci" "" 1 'mode="te" link="ptmp"'
done
for line in $(${LSPCI} -n -d 0x1397:a003); do
addcard "xhfc" "" 4 'mode="te" link="ptmp"'
done
for line in $(${LSPCI} -n | ${GREP} "1244:\(0a00\|0e00\)"); do
addcard "avmfritz" "" 1 'mode="te" link="ptmp"'
done
for line in $(${LSPCI} -n -d 1050:6692); do
addcard "w6692pci" "" 1 'mode="te" link="ptmp"'
done
if [ -e ${LSUSB} ]; then
for line in $(${LSUSB} | ${GREP} "0959:2bd0\|0675:1688\|07b0:0007\|0742:200\(7\|8\|9\|A\)\|08e3:0301\|07fa:084\(7\|8\)\|07ba:0006\|0586:0102"); do
addcard "hfcsusb" "" 1 'mode="te" link="ptmp"'
done
fi
}
function write_mISDN_conf
{
local NL="
"
local TAB=" "
local HEADER="
${TAB}hfcmulti
${TAB}mISDN_dsp
${TAB}mISDN"
local FOOTER=""
local i=0 j=0 MAIN=""
echo "Writing ${MISDN_CONF} for ${#SCAN_card[@]} mISDN compatible device(s):"
while [ ! -z "${SCAN_card[${i}]}" ]; do
echo ">> ${SCAN_card[${i}]}"
MAIN="${MAIN}${NL}${TAB}"
j=1
while [ ${j} -le ${SCAN_num_ports[${i}]} ]; do
MAIN="${MAIN}${NL}${TAB}${TAB}${j}"
let "j = ${j} + 1"
done
MAIN="${MAIN}${NL}${TAB}"
let "i = ${i} + 1"
done
if [ -f ${MISDN_CONF} ]; then
echo "${MISDN_CONF} already present, saving a backup: ${MISDN_CONF}.bak"
${CP} "${MISDN_CONF}" "${MISDN_CONF}.bak" || die "Could not backup your existing ${MISDN_CONF}!"
fi
echo "${HEADER}${MAIN}${NL}${FOOTER}" > ${MISDN_CONF}
}
function print_scan_results
{
local i=0
echo "${#SCAN_card[@]} mISDN compatible device(s) found:"
while [ ! -z "${SCAN_card[${i}]}" ]; do
echo ">> ${SCAN_card[${i}]}"
let "i = ${i} + 1"
done
}
function mk_misdn_dev
{
if [ ! -e /dev/mISDN ]; then
echo "creating device node: /dev/mISDN"
${MKNOD} /dev/mISDN c 46 0
fi
${CHOWN} ${DEVNODE_user}:${DEVNODE_group} /dev/mISDN
${CHMOD} ${DEVNODE_mode} /dev/mISDN
}
#
# MAIN
#
case "${1}" in
start|--start)
check_misdn_conf
parse_config
run_start_commands
mk_misdn_dev
;;
stop|--stop)
run_stop_commands
;;
restart|--restart)
check_misdn_conf
parse_config
run_stop_commands
${SLEEP} 2
run_start_commands
mk_misdn_dev
;;
config|--config)
scan_devices
write_mISDN_conf
;;
scan|--scan)
scan_devices
print_scan_results
;;
help|--help)
echo "${USAGE}"
exit 0
;;
*)
echo "${USAGE}"
exit 2
;;
esac
mISDN-1_1_9.1/config/mISDN.conf 0000644 0000000 0000050 00000000605 11110524073 014265 0 ustar root src
1
2
3
4
5
6
7
8
mISDN-1_1_9.1/config/mISDN.conf.bnx.xsl 0000644 0000000 0000050 00000016544 11135651701 015677 0 ustar root src
no
(2**8)
+
(2**9)
+
(2**11)
(2**11)
+
(2**12)
+
(2**13)
+
(2**18)
+
(2**19)
4
layermask:
3
0
15
protocol:
te
nt
34
18
34
+
ptp
ptmp
0
(-32)
(-32)
+
(2**16)
capi:
yes
no
no
4
8
type:1+
,1+
yes
layermask:
3
0
15
protocol:
te
nt
34
18
34
+
ptp
ptmp
0
(-32)
(-32)
+
(2**16)
+
(2**18)
+
(2**19)
+
(2**21)
+
(2**23)
capi:
yes
no
no
mISDN-1_1_9.1/config/mISDN.conf.hfcmulti.xsl 0000644 0000000 0000050 00000002331 11110524073 016702 0 ustar root src
poll=
128
pcm=
debug=
0
timer=
0
1
mISDN-1_1_9.1/config/mISDN.conf.hfcsusb.xsl 0000644 0000000 0000050 00000001413 11110524073 016524 0 ustar root src
debug=
0
poll=
0
mISDN-1_1_9.1/config/mISDN.conf.inc.xsl 0000644 0000000 0000050 00000003670 11110524073 015647 0 ustar root src
0
0
yes
no
no
0
0
0
yes
no
mISDN-1_1_9.1/config/mISDN.conf.l1oip.xsl 0000644 0000000 0000050 00000007143 11135651701 016127 0 ustar root src
debug=
0
type:
1
2
3
4
1
layermask:
3
15
protocol:
te
nt
34
18
34
+
ptp
ptmp
0
(-32)
(-32)
codec:
0
ip:
0,0,0,0
port:
0
localport:
0
ondemand:
0
id:
0
mISDN-1_1_9.1/config/mISDN.conf.mISDN_debugtool.xsl 0000644 0000000 0000050 00000000776 11110524073 020060 0 ustar root src
PORT=
mISDN-1_1_9.1/config/mISDN.conf.mISDN_dsp.xsl 0000644 0000000 0000050 00000002213 11110524073 016646 0 ustar root src
debug=
0
options=
0
poll=
dtmfthreshold=
mISDN-1_1_9.1/config/mISDN.conf.singlepci.xsl 0000644 0000000 0000050 00000003550 11110524073 017050 0 ustar root src
layermask:
3
0
15
protocol:
te
nt
34
18
34
+
ptp
ptmp
0
(-32)
(-32)
capi:
yes
no
no
mISDN-1_1_9.1/config/mISDN.conf.xhfc.xsl 0000644 0000000 0000050 00000010261 11135651701 016026 0 ustar root src
debug=
0
layermask:
3
0
15
protocol:
te
nt
2
18
34
+
ptp
ptmp
1024
0
0
+
up
s0
32
0
0
+
yes
no
128
0
0
+
yes
no
256
0
0
+
yes
no
512
0
0
+
yes
no
64
0
0
capi:
yes
no
no
mISDN-1_1_9.1/config/mISDN.conf.xsl 0000644 0000000 0000050 00000012236 11135651701 015103 0 ustar root src
user:
root
group:
root
mode:
644
PORT:
PORT:
PORT:
PORT:
PORT:
PORT:
PORT:
PORT:
mISDN-1_1_9.1/drivers/ 0002755 0000000 0000050 00000000000 11110524073 012716 5 ustar root src mISDN-1_1_9.1/drivers/isdn/ 0002755 0000000 0000050 00000000000 11110524073 013653 5 ustar root src mISDN-1_1_9.1/drivers/isdn/Config.in.v2.4 0000644 0000000 0000050 00000020347 11110524073 016104 0 ustar root src #
# ISDN device configuration
#
# only included if CONFIG_ISDN != n
define_bool CONFIG_ISDN_BOOL y
if [ "$CONFIG_INET" != "n" ]; then
bool ' Support synchronous PPP' CONFIG_ISDN_PPP
if [ "$CONFIG_ISDN_PPP" != "n" ]; then
bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
dep_tristate ' Support BSD compression' CONFIG_ISDN_PPP_BSDCOMP $CONFIG_ISDN
fi
fi
bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO
if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
bool ' Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX
fi
if [ "$CONFIG_X25" != "n" ]; then
bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25
fi
mainmenu_option next_comment
comment 'ISDN feature submodules'
dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN
endmenu
comment 'low-level hardware drivers'
mainmenu_option next_comment
comment 'Passive ISDN cards'
dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
define_bool CONFIG_ISDN_HISAX y
comment ' D-channel protocol features'
bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
if [ "$CONFIG_HISAX_EURO" != "n" ]; then
bool ' Support for german chargeinfo' CONFIG_DE_AOC
bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
fi
bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1
int ' Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
comment ' HiSax supported cards'
if [ "$CONFIG_ISA" != "n" ]; then
bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
bool ' AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
bool ' ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
bool ' ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
bool ' TELEINT cards' CONFIG_HISAX_TELEINT
bool ' HFC-S based cards' CONFIG_HISAX_HFCS
bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
bool ' MIC card' CONFIG_HISAX_MIC
bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF
bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR
fi
bool ' Teles PCI' CONFIG_HISAX_TELESPCI
bool ' Teles S0Box' CONFIG_HISAX_S0BOX
bool ' AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
bool ' AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
bool ' Elsa cards' CONFIG_HISAX_ELSA
bool ' Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
bool ' Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
bool ' NETjet card' CONFIG_HISAX_NETJET
bool ' NETspider U card' CONFIG_HISAX_NETJET_U
bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY
bool ' Telekom A4T card' CONFIG_HISAX_BKM_A4T
bool ' Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
bool ' Gazel cards' CONFIG_HISAX_GAZEL
bool ' HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
bool ' Winbond W6692 based cards' CONFIG_HISAX_W6692
bool ' HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
bool ' Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
bool ' Am7930' CONFIG_HISAX_AMD7930
fi
fi
bool ' HiSax debugging' CONFIG_HISAX_DEBUG
dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
dep_tristate 'AVM A1 PCMCIA cards' CONFIG_HISAX_AVM_A1_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA $CONFIG_HISAX_AVM_A1_PCMCIA
dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_ISDN_DRV_HISAX $CONFIG_EXPERIMENTAL
dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_ISDN_DRV_HISAX $CONFIG_EXPERIMENTAL
dep_tristate 'Auerswald devices ISDN support' CONFIG_USB_AUERISDN $CONFIG_ISDN_DRV_HISAX
fi
endmenu
### Active ISDN cards
mainmenu_option next_comment
comment 'Active ISDN cards'
dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
dep_tristate 'Spellcaster support' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
dep_tristate 'IBM Active 2000 support' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
bool 'Eicon active card support' CONFIG_ISDN_DRV_EICON
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then
dep_tristate ' Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN $CONFIG_PCI
fi
if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then
dep_tristate ' Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then
dep_bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI
bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
fi
fi
fi
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
dep_tristate 'Auvertech TurboPAM support' CONFIG_ISDN_DRV_TPAM $CONFIG_ISDN $CONFIG_PCI
fi
# CAPI subsystem
tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI
if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
dep_bool ' CAPI2.0 Middleware support (EXPERIMENTAL)' CONFIG_ISDN_CAPI_MIDDLEWARE $CONFIG_EXPERIMENTAL
dep_tristate ' CAPI2.0 /dev/capi support' CONFIG_ISDN_CAPI_CAPI20 $CONFIG_ISDN_CAPI
if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" = "y" ]; then
dep_mbool ' CAPI2.0 filesystem support' CONFIG_ISDN_CAPI_CAPIFS_BOOL $CONFIG_ISDN_CAPI_CAPI20
if [ "$CONFIG_ISDN_CAPI_CAPIFS_BOOL" = "y" ]; then
define_tristate CONFIG_ISDN_CAPI_CAPIFS $CONFIG_ISDN_CAPI_CAPI20
else
define_tristate CONFIG_ISDN_CAPI_CAPIFS n
fi
fi
dep_tristate ' CAPI2.0 capidrv interface support' CONFIG_ISDN_CAPI_CAPIDRV $CONFIG_ISDN_CAPI $CONFIG_ISDN
fi
# CAPI drivers
if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
dep_tristate ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA $CONFIG_ISDN_CAPI
dep_tristate ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
dep_mbool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 $CONFIG_ISDN_DRV_AVMB1_B1PCI
dep_tristate ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA $CONFIG_ISDN_CAPI
dep_tristate ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI
dep_tristate ' AVM B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_PCMCIA
dep_tristate ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
dep_tristate ' AVM C4/C2 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI
fi
# HYSDN
dep_tristate ' Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)' CONFIG_HYSDN m $CONFIG_PROC_FS
dep_mbool ' HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI $CONFIG_HYSDN $CONFIG_ISDN_CAPI
endmenu
mainmenu_option next_comment
comment 'modular ISDN driver'
dep_tristate ' mISDN support' CONFIG_MISDN_DRV $CONFIG_ISDN_CAPI
if [ "$CONFIG_MISDN_DRV" != "n" ]; then
comment ' mISDN supported cards'
bool ' AVM Fritz PCI and ISA PnP cards' CONFIG_MISDN_AVM_FRITZ
bool ' Cologne Chip Design HFC PCI cards' CONFIG_MISDN_HFCPCI
bool ' Cologne Chip Design HFC multiport cards' CONFIG_MISDN_HFCMULTI
bool ' Sedlbauer Speedfax + cards' CONFIG_MISDN_SPEEDFAX
bool ' Winbond W6692 cards' CONFIG_MISDN_W6692
comment ' mISDN supported features'
bool ' mISDN audio DSP module' CONFIG_MISDN_DSP
bool ' mISDN memory leak debug' CONFIG_MISDN_MEMDEBUG
fi
endmenu
mISDN-1_1_9.1/drivers/isdn/Makefile.v2.4 0000644 0000000 0000050 00000003045 11110524073 016003 0 ustar root src # Makefile for the kernel ISDN subsystem and device drivers.
# The target object and module list name.
O_TARGET := vmlinux-obj.o
# Objects that export symbols.
export-objs := isdn_common.o
# Multipart objects.
list-multi := isdn.o
isdn-objs := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
# Optional parts of multipart objects.
isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o
isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
isdn-objs-$(CONFIG_ISDN_WITH_ABC) += isdn_dwabc.o
isdn-objs += $(isdn-objs-y)
# Ordering constraints: isdn.o first, rest doesn't matter
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
# Object files in subdirectories
mod-subdirs := avmb1 eicon hisax
subdir-$(CONFIG_ISDN_DIVERSION) += divert
subdir-$(CONFIG_ISDN_HISAX) += hisax
subdir-$(CONFIG_ISDN_DRV_ICN) += icn
subdir-$(CONFIG_ISDN_DRV_PCBIT) += pcbit
subdir-$(CONFIG_ISDN_DRV_SC) += sc
subdir-$(CONFIG_ISDN_CAPI) += avmb1
subdir-$(CONFIG_ISDN_DRV_LOOP) += isdnloop
subdir-$(CONFIG_ISDN_DRV_ACT2000) += act2000
subdir-$(CONFIG_ISDN_DRV_EICON) += eicon
subdir-$(CONFIG_HYSDN) += hysdn
subdir-$(CONFIG_ISDN_DRV_TPAM) += tpam
subdir-$(CONFIG_MISDN_DRV) += hardware/mISDN
obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y))
# The global Rules.make.
include $(TOPDIR)/Rules.make
# Link rules for multi-part drivers.
isdn.o: $(isdn-objs)
$(LD) -r -o $@ $(isdn-objs)
mISDN-1_1_9.1/drivers/isdn/hardware/ 0002755 0000000 0000050 00000000000 11110524073 015450 5 ustar root src mISDN-1_1_9.1/drivers/isdn/hardware/Kconfig.v2.6 0000644 0000000 0000050 00000000352 11110524073 017443 0 ustar root src #
# ISDN hardware drivers
#
comment "CAPI hardware drivers"
depends on NET && ISDN && ISDN_CAPI
source "drivers/isdn/hardware/avm/Kconfig"
source "drivers/isdn/hardware/eicon/Kconfig"
source "drivers/isdn/hardware/mISDN/Kconfig"
mISDN-1_1_9.1/drivers/isdn/hardware/Makefile.v2.6 0000644 0000000 0000050 00000000262 11110524073 017600 0 ustar root src # Makefile for the CAPI hardware drivers
# Object files in subdirectories
obj-$(CONFIG_CAPI_AVM) += avm/
obj-$(CONFIG_CAPI_EICON) += eicon/
obj-$(CONFIG_MISDN_DRV) += mISDN/
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/ 0002755 0000000 0000050 00000000000 11137306013 016363 5 ustar root src mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/Kconfig.v2.6 0000644 0000000 0000050 00000007723 11135651701 020374 0 ustar root src #
# modularer ISDN driver
#
menu "Modular ISDN driver"
depends on NET && ISDN && ISDN_CAPI!=n
config MISDN_DRV
tristate "Support modular ISDN driver"
help
Enable support for the modular ISDN driver.
This driver is the successor of the famous HiSax driver.
if MISDN_DRV!=n
config MISDN_MEMDEBUG
bool "Enable memory leak debug for mISDN"
help
This option is for watching the use of several resources in mISDN.
It includes extra code to maintain list of allocated memory and
sk_buffs. On module unload you can see not freed resources an
their allocation orging and some object specific informations.
If unsure, say 'N'.
config MISDN_AVM_FRITZ
bool "Support for AVM Fritz!Cards"
depends on PCI || ISA
help
Enable support for AVM Fritz!Card PCI and PnP.
config MISDN_NETJET
bool "Support for NETJet cards"
depends on PCI
help
Enable support for Traverse Technologies' NETJet PCI cards.
config MISDN_HFCPCI
bool "Support for HFC PCI cards"
depends on PCI
help
Enable support for card with Cologne Chips Design HFC PCI based
cards.
config MISDN_HFCMULTI
bool "Support for HFC multiport cards (HFC-4S/8S/E1)"
depends on PCI
help
Enable support for card with Cologne Chip AG's HFC multiport
chip. There are three types of chips that are quite similar,
but the interface is different:
* HFC-4S (4 S/T interfaces on one chip)
* HFC-8S (8 S/T interfaces on one chip)
* HFC-E1 (E1 interface for 2Mbit ISDN)
if MISDN_HFCMULTI!=n
config HFCMULTI_PCIMEM
bool "HFC multiport driver with memory mapped IO"
depends on PCI
help
Use memory mapped PCI access rather than IO access.
This feature MIGHT be slightly faster, especially when
using hardware DTMF detection. Also it may cause trouble with some
PCI bridges.
If unsure, say 'N'.
endif
config MISDN_HFCUSB
bool "Support for HFC-S USB based TAs"
depends on USB && EXPERIMENTAL
help
Enable support for USB ISDN TAs with Cologne Chip AG's
HFC-S USB ISDN Controller
config MISDN_HFCMINI
bool "Support for 'HFC-S mini' based TAs"
depends on PCI
help
Enable support for Cologne Chip AG's 'HFC-S mini' Evaluation Card
config MISDN_XHFC
bool "Support for XHFC based cards"
depends on PCI
help
Enable support for Cologne Chips AG's XHFC Evaluation Card
config MISDN_SPEEDFAX
bool "Support for Sedlbauer Speedfax+"
depends on PCI || ISA
help
Enable support for Sedlbauer Speedfax+.
config MISDN_W6692
bool "Support for Winbond 6692 based cards"
depends on PCI
help
Enable support for Winbond 6692 PCI chip based cards.
config MISDN_DSP
bool "Digital Audio Processing of transparent data"
help
Enable support for digital audio processing capability.
This module may be used for special applications that require
cross connecting of bchannels, conferencing, dtmf decoding
echo cancelation, tone generation, and Blowfish encryption and
decryption.
It may use hardware features if available.
E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
and get more informations about this module and it's usage.
If unsure, say 'N'.
config MISDN_LOOP
bool "Loop device"
help
Enable support for loop device.
This module may be used for special applications that provide
bchannel data from user space. Applications can directly
access bchannels, so applications can be integrated into DSP
audio processing.
E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
and get more informations about this module and it's usage.
If unsure, say 'N'.
config MISDN_L1OIP
bool "ISDN over IP tunnel"
help
Enable support for ISDN over IP tunnel.
It features:
- layer 1 control via network keepalive frames
- dynamic IP exchange, if one or both peers have dynamic IPs
- channel bundeling for reduced IP overhead
- BRI (S0) and PRI (S2M) interface
NOTE: This protocol is called 'Layer 1 over IP' and is not
compatible with ISDNoIP (Agfeo) or TDMoIP.
endif
endmenu
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/Makefile 0000644 0000000 0000050 00000005370 11135651701 020033 0 ustar root src # Makefile for the modular ISDN driver
#
EXTRA_CFLAGS += -ggdb
#
ifdef MINCLUDES
EXTRA_CFLAGS += -I$(MINCLUDES) -g
endif
ifdef CONFIG_MISDN_MEMDEBUG
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
endif
ifdef CONFIG_MISDN_NETDEV
EXTRA_CFLAGS += -DCONFIG_MISDN_NETDEV
endif
EXTRA_CFLAGS += -DMISDNVERSION=\"$(MISDNVERSION)\"
obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
obj-$(CONFIG_MISDN_DRV) += l3udss1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
ifdef CONFIG_MISDN_AVM_FRITZ
obj-$(CONFIG_MISDN_DRV) += avmfritz.o
endif
ifdef CONFIG_MISDN_NETJET
obj-$(CONFIG_MISDN_DRV) += netjetpci.o
endif
ifdef CONFIG_MISDN_HFCPCI
obj-$(CONFIG_MISDN_DRV) += hfcpci.o
endif
ifdef CONFIG_MISDN_HFCUSB
obj-$(CONFIG_MISDN_DRV) += hfcsusb.o
endif
ifdef CONFIG_MISDN_HFCMINI
obj-$(CONFIG_MISDN_DRV) += hfcsmini.o
endif
ifdef CONFIG_MISDN_SPEEDFAX
obj-$(CONFIG_MISDN_DRV) += sedlfax.o
# obj-$(CONFIG_MISDN_DRV) += faxl3.o
endif
ifdef CONFIG_MISDN_W6692
obj-$(CONFIG_MISDN_DRV) += w6692pci.o
endif
ifdef CONFIG_MISDN_HFCMULTI
obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
endif
ifdef CONFIG_MISDN_XHFC
obj-$(CONFIG_MISDN_DRV) += xhfc.o
endif
ifdef CONFIG_MISDN_DSP
obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
endif
ifdef CONFIG_MISDN_LOOP
obj-$(CONFIG_MISDN_DRV) += mISDN_loop.o
endif
ifdef CONFIG_I4L_CAPI_LAYER
obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
endif
# multi objects
sedlfax-objs := sedl_fax.o isar.o
avmfritz-objs := avm_fritz.o
netjetpci-objs := netjet.o
hfcpci-objs := hfc_pci.o
hfcsusb-objs := hfcs_usb.o
hfcsmini-objs := hfcs_mini.o
w6692pci-objs := w6692.o
hfcmulti-objs := hfc_multi.o
xhfc-objs := xhfc_su.o xhfc_pci2pi.o
mISDN_isac-objs := isac.o arcofi.o
mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
channel.o l3helper.o \
sysfs_obj.o sysfs_inst.o sysfs_st.o
ifdef CONFIG_MISDN_NETDEV
mISDN_core-objs += netdev.o
endif
ifdef CONFIG_MISDN_MEMDEBUG
mISDN_core-objs += memdbg.o
endif
ifdef CONFIG_MISDN_DEBUGTOOL
obj-$(CONFIG_MISDN_DEBUGTOOL) += mISDN_debugtool.o
endif
mISDN_l1-objs := layer1.o
mISDN_l2-objs := layer2.o tei.o
l3udss1-objs := layer3.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
supp_serv.o
mISDN_dtmf-objs := dtmf.o
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
mISDN_loop-objs := loop.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o
mISDN_debugtool-objs := debugtool.o
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/Makefile.v2.4 0000644 0000000 0000050 00000003573 11135651701 020526 0 ustar root src # Makefile for the modular ISDN driver
#
# EXTRA_CFLAGS += -S -g
#
ifdef CONFIG_MISDN_MEMDEBUG
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
endif
EXTRA_CFLAGS += -I ../../avmb1
obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
obj-$(CONFIG_MISDN_DRV) += l3udss1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
ifdef CONFIG_MISDN_AVM_FRITZ
obj-$(CONFIG_MISDN_DRV) += avmfritz.o
endif
ifdef CONFIG_MISDN_HFCPCI
obj-$(CONFIG_MISDN_DRV) += hfcpci.o
endif
ifdef CONFIG_MISDN_SPEEDFAX
obj-$(CONFIG_MISDN_DRV) += sedlfax.o
endif
ifdef CONFIG_MISDN_W6692
obj-$(CONFIG_MISDN_DRV) += w6692pci.o
endif
ifdef CONFIG_MISDN_HFCMULTI
obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
endif
ifdef CONFIG_MISDN_DSP
obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
endif
ifdef CONFIG_I4L_CAPI_LAYER
obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
endif
# multi objects
sedlfax-objs := sedl_fax.o isar.o
avmfritz-objs := avm_fritz.o
hfcpci-objs := hfc_pci.o
w6692pci-objs := w6692.o
hfcmulti-objs := hfc_multi.o
mISDN_isac-objs := isac.o arcofi.o
mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
dchannel.o bchannel.o l3helper.o
ifdef CONFIG_MISDN_MEMDEBUG
mISDN_core-objs += memdbg.o
endif
mISDN_l1-objs := layer1.o
mISDN_l2-objs := layer2.o tei.o
l3udss1-objs := layer3.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
supp_serv.o
mISDN_dtmf-objs := dtmf.o
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o
include Rules.mISDN
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/Makefile.v2.6 0000644 0000000 0000050 00000005370 11135651701 020525 0 ustar root src # Makefile for the modular ISDN driver
#
EXTRA_CFLAGS += -ggdb
#
ifdef MINCLUDES
EXTRA_CFLAGS += -I$(MINCLUDES) -g
endif
ifdef CONFIG_MISDN_MEMDEBUG
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
endif
ifdef CONFIG_MISDN_NETDEV
EXTRA_CFLAGS += -DCONFIG_MISDN_NETDEV
endif
EXTRA_CFLAGS += -DMISDNVERSION=\"$(MISDNVERSION)\"
obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l2.o
obj-$(CONFIG_MISDN_DRV) += mISDN_x25dte.o
obj-$(CONFIG_MISDN_DRV) += l3udss1.o
obj-$(CONFIG_MISDN_DRV) += mISDN_capi.o
obj-$(CONFIG_MISDN_DRV) += mISDN_dtmf.o
ifdef CONFIG_MISDN_AVM_FRITZ
obj-$(CONFIG_MISDN_DRV) += avmfritz.o
endif
ifdef CONFIG_MISDN_NETJET
obj-$(CONFIG_MISDN_DRV) += netjetpci.o
endif
ifdef CONFIG_MISDN_HFCPCI
obj-$(CONFIG_MISDN_DRV) += hfcpci.o
endif
ifdef CONFIG_MISDN_HFCUSB
obj-$(CONFIG_MISDN_DRV) += hfcsusb.o
endif
ifdef CONFIG_MISDN_HFCMINI
obj-$(CONFIG_MISDN_DRV) += hfcsmini.o
endif
ifdef CONFIG_MISDN_SPEEDFAX
obj-$(CONFIG_MISDN_DRV) += sedlfax.o
# obj-$(CONFIG_MISDN_DRV) += faxl3.o
endif
ifdef CONFIG_MISDN_W6692
obj-$(CONFIG_MISDN_DRV) += w6692pci.o
endif
ifdef CONFIG_MISDN_HFCMULTI
obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
endif
ifdef CONFIG_MISDN_XHFC
obj-$(CONFIG_MISDN_DRV) += xhfc.o
endif
ifdef CONFIG_MISDN_DSP
obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
endif
ifdef CONFIG_MISDN_LOOP
obj-$(CONFIG_MISDN_DRV) += mISDN_loop.o
endif
ifdef CONFIG_I4L_CAPI_LAYER
obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
endif
# multi objects
sedlfax-objs := sedl_fax.o isar.o
avmfritz-objs := avm_fritz.o
netjetpci-objs := netjet.o
hfcpci-objs := hfc_pci.o
hfcsusb-objs := hfcs_usb.o
hfcsmini-objs := hfcs_mini.o
w6692pci-objs := w6692.o
hfcmulti-objs := hfc_multi.o
xhfc-objs := xhfc_su.o xhfc_pci2pi.o
mISDN_isac-objs := isac.o arcofi.o
mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
channel.o l3helper.o \
sysfs_obj.o sysfs_inst.o sysfs_st.o
ifdef CONFIG_MISDN_NETDEV
mISDN_core-objs += netdev.o
endif
ifdef CONFIG_MISDN_MEMDEBUG
mISDN_core-objs += memdbg.o
endif
ifdef CONFIG_MISDN_DEBUGTOOL
obj-$(CONFIG_MISDN_DEBUGTOOL) += mISDN_debugtool.o
endif
mISDN_l1-objs := layer1.o
mISDN_l2-objs := layer2.o tei.o
l3udss1-objs := layer3.o l3_udss1.o
mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.o \
asn1_aoc.o asn1_comp.o asn1_generic.o asn1_diversion.o \
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
supp_serv.o
mISDN_dtmf-objs := dtmf.o
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
mISDN_loop-objs := loop.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o
mISDN_debugtool-objs := debugtool.o
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4 0000755 0000000 0000050 00000003265 11110524073 021007 0 ustar root src #
# local Rules for 2.4
#
O_TARGET := vmlinux-obj.o
export-objs := core.o isac.o helper.o debug.o fsm.o dchannel.o bchannel.o \
l3helper.o
ifdef CONFIG_MISDN_MEMDEBUG
export-objs += memdbg.o
endif
M_OBJS := $(obj-m)
include $(TOPDIR)/Rules.make
mISDN_core.o: $(mISDN_core-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_isac.o: $(mISDN_isac-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
avmfritz.o: $(avmfritz-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
sedlfax.o: $(sedlfax-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
w6692pci.o: $(w6692pci-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
hfcpci.o: $(hfcpci-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
hfcmulti.o: $(hfcmulti-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_l1.o: $(mISDN_l1-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_l2.o: $(mISDN_l2-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_x25dte.o: $(mISDN_x25dte-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
l3udss1.o: $(l3udss1-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_capi.o: $(mISDN_capi-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_dtmf.o: $(mISDN_dtmf-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
ifdef CONFIG_I4L_CAPI_LAYER
I4LmISDN.o: $(I4LmISDN-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
endif
mISDN_dsp.o: $(mISDN_dsp-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/app_plci.c 0000644 0000000 0000050 00000171410 11135651701 020325 0 ustar root src /* $Id: app_plci.c,v 1.19 2006/12/06 15:18:07 gkelleter Exp $
*
*/
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
#include "dss1.h"
#define AppPlciDebug(aplci, lev, fmt, args...) \
capidebug(lev, fmt, ## args)
#ifndef CAPIUTIL_VERSION
#define CAPIUTIL_VERSION 1
#endif
static void AppPlciClearOtherApps(AppPlci_t *);
static void AppPlciInfoIndMsg(AppPlci_t *, __u32, unsigned char);
static void AppPlciInfoIndIE(AppPlci_t *, unsigned char, __u32, Q931_info_t *);
static int AppPlciLinkUp(AppPlci_t *);
static int AppPlciLinkDown(AppPlci_t *);
static u_char BEARER_SPEECH_64K_ALAW[] = {4, 3, 0x80, 0x90, 0xA3};
static u_char BEARER_SPEECH_64K_ULAW[] = {4, 3, 0x80, 0x90, 0xA2};
static u_char BEARER_UNRES_DIGITAL_64K[] = {4, 2, 0x88, 0x90};
static u_char BEARER_RES_DIGITAL_64K[] = {4, 2, 0x89, 0x90};
static u_char BEARER_31AUDIO_64K_ALAW[] = {4, 3, 0x90, 0x90, 0xA3};
static u_char BEARER_31AUDIO_64K_ULAW[] = {4, 3, 0x90, 0x90, 0xA2};
static u_char HLC_TELEPHONY[] = {0x7d, 2, 0x91, 0x81};
static u_char HLC_FACSIMILE[] = {0x7d, 2, 0x91, 0x84};
__u16 q931CIPValue(Q931_info_t *qi)
{
__u16 CIPValue = 0;
u_char *p;
if (!qi)
return 0;
if (!qi->bearer_capability.off)
return 0;
p = (u_char *)qi;
p += L3_EXTRA_SIZE + qi->bearer_capability.off;
if (memcmp(p, BEARER_SPEECH_64K_ALAW, 5) == 0
|| memcmp(p, BEARER_SPEECH_64K_ULAW, 5) == 0) {
CIPValue = 1;
} else if (memcmp(p, BEARER_UNRES_DIGITAL_64K, 4) == 0) {
CIPValue = 2;
} else if (memcmp(p, BEARER_RES_DIGITAL_64K, 4) == 0) {
CIPValue = 3;
} else if (memcmp(p, BEARER_31AUDIO_64K_ALAW, 5) == 0
|| memcmp(p, BEARER_31AUDIO_64K_ULAW, 5) == 0) {
CIPValue = 4;
} else {
CIPValue = 0;
}
// FIXME: handle duplicated IE's
if (!qi->hlc.off)
return CIPValue;
p = (u_char *)qi;
p += L3_EXTRA_SIZE + qi->hlc.off;
if ((CIPValue == 1) || (CIPValue == 4)) {
if (memcmp(p, HLC_TELEPHONY, 4) == 0) {
CIPValue = 16;
} else if (memcmp(p, HLC_FACSIMILE, 4) == 0) {
CIPValue = 17;
}
}
return CIPValue;
}
u_int plci_parse_channel_id(u_char *p)
{
u_int cid = -1;
int l;
if (p) {
p++;
capidebug(CAPI_DBG_PLCI_INFO, "%s: l(%d) %x", __FUNCTION__, p[0], p[1]);
l = *p++;
if (l == 1) {
cid = *p;
} else if (l == 3) {
cid = *p++ << 16;
cid |= *p++ << 8;
cid |= *p;
}
}
return(cid);
}
__u16 CIPValue2setup(__u16 CIPValue, struct sk_buff *skb)
{
switch (CIPValue) {
case 16:
mISDN_AddvarIE(skb, BEARER_31AUDIO_64K_ALAW);
mISDN_AddvarIE(skb, HLC_TELEPHONY);
break;
case 17:
mISDN_AddvarIE(skb, BEARER_31AUDIO_64K_ALAW);
mISDN_AddvarIE(skb, HLC_FACSIMILE);
break;
case 1:
mISDN_AddvarIE(skb, BEARER_SPEECH_64K_ALAW);
break;
case 2:
mISDN_AddvarIE(skb, BEARER_UNRES_DIGITAL_64K);
break;
case 3:
mISDN_AddvarIE(skb, BEARER_RES_DIGITAL_64K);
break;
case 4:
mISDN_AddvarIE(skb, BEARER_31AUDIO_64K_ALAW);
break;
default:
return CapiIllMessageParmCoding;
}
return 0;
}
__u16 cmsg2setup_req(_cmsg *cmsg, struct sk_buff *skb)
{
if (CIPValue2setup(cmsg->CIPValue, skb))
goto err;
mISDN_AddIE(skb, IE_CALLING_PN, cmsg->CallingPartyNumber);
mISDN_AddIE(skb, IE_CALLING_SUB, cmsg->CallingPartySubaddress);
mISDN_AddIE(skb, IE_CALLED_PN, cmsg->CalledPartyNumber);
mISDN_AddIE(skb, IE_CALLED_SUB, cmsg->CalledPartySubaddress);
mISDN_AddIE(skb, IE_BEARER, cmsg->BC);
mISDN_AddIE(skb, IE_LLC, cmsg->LLC);
mISDN_AddIE(skb, IE_HLC, cmsg->HLC);
return 0;
err:
return CapiIllMessageParmCoding;
}
__u16 cmsg2info_req(_cmsg *cmsg, struct sk_buff *skb)
{
mISDN_AddIE(skb, IE_KEYPAD, cmsg->Keypadfacility);
mISDN_AddIE(skb, IE_CALLED_PN, cmsg->CalledPartyNumber);
return 0;
}
__u16 cmsg2alerting_req(_cmsg *cmsg, struct sk_buff *skb)
{
mISDN_AddIE(skb, IE_USER_USER, cmsg->Useruserdata);
return 0;
}
__u16 AppPlciCheckBprotocol(AppPlci_t *aplci, _cmsg *cmsg)
{
struct capi_ctr *ctrl = aplci->contr->ctrl;
u_long sprot;
sprot = le32_to_cpu(ctrl->profile.support1);
if (!test_bit(cmsg->B1protocol, &sprot))
return CapiB1ProtocolNotSupported;
sprot = le32_to_cpu(ctrl->profile.support2);
if (!test_bit(cmsg->B2protocol, &sprot))
return CapiB2ProtocolNotSupported;
sprot = le32_to_cpu(ctrl->profile.support3);
if (!test_bit(cmsg->B3protocol, &sprot))
return CapiB3ProtocolNotSupported;
aplci->Bprotocol.B1 = cmsg->B1protocol;
aplci->Bprotocol.B2 = cmsg->B2protocol;
aplci->Bprotocol.B3 = cmsg->B3protocol;
if (cmsg->B1configuration && cmsg->B1configuration[0]) {
if (cmsg->B1configuration[0] > 15) {
int_errtxt("B1cfg too large(%d)", cmsg->B1configuration[0]);
return CapiB1ProtocolParameterNotSupported;
}
memcpy(&aplci->Bprotocol.B1cfg[0], cmsg->B1configuration, cmsg->B1configuration[0] + 1);
} else
aplci->Bprotocol.B1cfg[0] = 0;
if (cmsg->B2configuration && cmsg->B2configuration[0]) {
if (cmsg->B2configuration[0] > 15) {
int_errtxt("B2cfg too large(%d)", cmsg->B2configuration[0]);
return CapiB2ProtocolParameterNotSupported;
}
memcpy(&aplci->Bprotocol.B2cfg[0], cmsg->B2configuration, cmsg->B2configuration[0] + 1);
} else
aplci->Bprotocol.B2cfg[0] = 0;
if (cmsg->B3configuration && cmsg->B3configuration[0]) {
if (cmsg->B3configuration[0] > 79) {
int_errtxt("B3cfg too large(%d)", cmsg->B3configuration[0]);
return CapiB3ProtocolParameterNotSupported;
}
memcpy(&aplci->Bprotocol.B3cfg[0], cmsg->B3configuration, cmsg->B3configuration[0] + 1);
} else
aplci->Bprotocol.B3cfg[0] = 0;
return 0;
}
// --------------------------------------------------------------------
// PLCI state machine
//
// Some rules:
// * EV_AP_* events come from CAPI Application
// * EV_L3_* events come from the ISDN stack
// * EV_PI_* events generated in PLCI handling
// * messages are send in the routine that handle the event
//
// --------------------------------------------------------------------
enum {
ST_PLCI_P_0,
ST_PLCI_P_0_1,
ST_PLCI_P_1,
ST_PLCI_P_2,
ST_PLCI_P_3,
ST_PLCI_P_4,
ST_PLCI_P_ACT,
ST_PLCI_P_HELD,
ST_PLCI_P_5,
ST_PLCI_P_6,
ST_PLCI_P_RES,
}
const ST_PLCI_COUNT = ST_PLCI_P_RES + 1;
static char *str_st_plci[] = {
"ST_PLCI_P_0",
"ST_PLCI_P_0_1",
"ST_PLCI_P_1",
"ST_PLCI_P_2",
"ST_PLCI_P_3",
"ST_PLCI_P_4",
"ST_PLCI_P_ACT",
"ST_PLCI_P_HELD",
"ST_PLCI_P_5",
"ST_PLCI_P_6",
"ST_PLCI_P_RES",
};
enum {
EV_AP_CONNECT_REQ,
EV_PI_CONNECT_CONF,
EV_PI_CONNECT_IND,
EV_AP_CONNECT_RESP,
EV_PI_CONNECT_ACTIVE_IND,
EV_AP_CONNECT_ACTIVE_RESP,
EV_AP_ALERT_REQ,
EV_AP_INFO_REQ,
EV_PI_INFO_IND,
EV_PI_FACILITY_IND,
EV_AP_SELECT_B_PROTOCOL_REQ,
EV_AP_DISCONNECT_REQ,
EV_PI_DISCONNECT_IND,
EV_AP_DISCONNECT_RESP,
EV_AP_HOLD_REQ,
EV_AP_RETRIEVE_REQ,
EV_PI_HOLD_CONF,
EV_PI_RETRIEVE_CONF,
EV_AP_SUSPEND_REQ,
EV_PI_SUSPEND_CONF,
EV_AP_RESUME_REQ,
EV_PI_RESUME_CONF,
EV_PI_CHANNEL_ERR,
EV_L3_SETUP_IND,
EV_L3_SETUP_CONF_ERR,
EV_L3_SETUP_CONF,
EV_L3_SETUP_COMPL_IND,
EV_L3_DISCONNECT_IND,
EV_L3_RELEASE_IND,
EV_L3_RELEASE_PROC_IND,
EV_L3_NOTIFY_IND,
EV_L3_HOLD_IND,
EV_L3_HOLD_ACKNOWLEDGE,
EV_L3_HOLD_REJECT,
EV_L3_RETRIEVE_IND,
EV_L3_RETRIEVE_ACKNOWLEDGE,
EV_L3_RETRIEVE_REJECT,
EV_L3_SUSPEND_ERR,
EV_L3_SUSPEND_CONF,
EV_L3_RESUME_ERR,
EV_L3_RESUME_CONF,
EV_L3_REJECT_IND,
EV_PH_CONTROL_IND,
EV_AP_RELEASE,
}
const EV_PLCI_COUNT = EV_AP_RELEASE + 1;
static char* str_ev_plci[] = {
"EV_AP_CONNECT_REQ",
"EV_PI_CONNECT_CONF",
"EV_PI_CONNECT_IND",
"EV_AP_CONNECT_RESP",
"EV_PI_CONNECT_ACTIVE_IND",
"EV_AP_CONNECT_ACTIVE_RESP",
"EV_AP_ALERT_REQ",
"EV_AP_INFO_REQ",
"EV_PI_INFO_IND",
"EV_PI_FACILITY_IND",
"EV_AP_SELECT_B_PROTOCOL_REQ",
"EV_AP_DISCONNECT_REQ",
"EV_PI_DISCONNECT_IND",
"EV_AP_DISCONNECT_RESP",
"EV_AP_HOLD_REQ",
"EV_AP_RETRIEVE_REQ",
"EV_PI_HOLD_CONF",
"EV_PI_RETRIEVE_CONF",
"EV_AP_SUSPEND_REQ",
"EV_PI_SUSPEND_CONF",
"EV_AP_RESUME_REQ",
"EV_PI_RESUME_CONF",
"EV_PI_CHANNEL_ERR",
"EV_L3_SETUP_IND",
"EV_L3_SETUP_CONF_ERR",
"EV_L3_SETUP_CONF",
"EV_L3_SETUP_COMPL_IND",
"EV_L3_DISCONNECT_IND",
"EV_L3_RELEASE_IND",
"EV_L3_RELEASE_PROC_IND",
"EV_L3_NOTIFY_IND",
"EV_L3_HOLD_IND",
"EV_L3_HOLD_ACKNOWLEDGE",
"EV_L3_HOLD_REJECT",
"EV_L3_RETRIEVE_IND",
"EV_L3_RETRIEVE_ACKNOWLEDGE",
"EV_L3_RETRIEVE_REJECT",
"EV_L3_SUSPEND_ERR",
"EV_L3_SUSPEND_CONF",
"EV_L3_RESUME_ERR",
"EV_L3_RESUME_CONF",
"EV_L3_REJECT_IND",
"EV_PH_CONTROL_IND",
"EV_AP_RELEASE",
};
static struct Fsm plci_fsm =
{ 0, 0, 0, 0, 0 };
static void
AppPlci_debug(struct FsmInst *fi, char *fmt, ...)
{
char tmp[128];
char *p = tmp;
va_list args;
AppPlci_t *aplci = fi->userdata;
va_start(args, fmt);
p += sprintf(p, "APLCI 0x%x: ", aplci->addr);
p += vsprintf(p, fmt, args);
*p = 0;
AppPlciDebug(aplci, CAPI_DBG_PLCI_STATE, tmp);
va_end(args);
}
static inline void
Send2Application(AppPlci_t *aplci, _cmsg *cmsg)
{
SendCmsg2Application(aplci->appl, cmsg);
}
static void
SendingDelayedMsg(AppPlci_t *aplci)
{
struct sk_buff *skb;
while((skb = skb_dequeue(&aplci->delayedq))) {
if (test_bit(APPL_STATE_RELEASE, &aplci->appl->state)) {
printk(KERN_WARNING "%s: Application allready released\n", __FUNCTION__);
dev_kfree_skb(skb);
} else {
#ifdef OLDCAPI_DRIVER_INTERFACE
aplci->appl->contr->ctrl->handle_capimsg(aplci->appl->contr->ctrl, aplci->appl->ApplId, skb);
#else
capi_ctr_handle_message(aplci->appl->contr->ctrl, aplci->appl->ApplId, skb);
#endif
}
}
test_and_clear_bit(PLCI_STATE_SENDDELAYED, &aplci->plci->state);
}
static void
Send2ApplicationDelayed(AppPlci_t *aplci, _cmsg *cmsg)
{
struct sk_buff *skb;
if (test_bit(APPL_STATE_RELEASE, &aplci->appl->state)) {
printk(KERN_WARNING "%s: Application allready released\n", __FUNCTION__);
cmsg_free(cmsg);
return;
}
if (!(skb = alloc_skb(CAPI_MSG_DEFAULT_LEN, GFP_ATOMIC))) {
printk(KERN_WARNING "%s: no mem for %d bytes\n", __FUNCTION__, CAPI_MSG_DEFAULT_LEN);
int_error();
cmsg_free(cmsg);
return;
}
capi_cmsg2message(cmsg, skb->data);
AppPlciDebug(aplci, CAPI_DBG_APPL_MSG, "%s: len(%d) applid(%x) %s msgnr(%d) addr(%08x)",
__FUNCTION__, CAPIMSG_LEN(skb->data), cmsg->ApplId, capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->Messagenumber, cmsg->adr.adrController);
cmsg_free(cmsg);
if (CAPI_MSG_DEFAULT_LEN < CAPIMSG_LEN(skb->data)) {
printk(KERN_ERR "%s: CAPI_MSG_DEFAULT_LEN overrun (%d/%d)\n", __FUNCTION__,
CAPIMSG_LEN(skb->data), CAPI_MSG_DEFAULT_LEN);
int_error();
dev_kfree_skb(skb);
return;
}
skb_put(skb, CAPIMSG_LEN(skb->data));
skb_queue_tail(&aplci->delayedq, skb);
if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state) &&
!test_and_set_bit(PLCI_STATE_SENDDELAYED, &aplci->plci->state))
SendingDelayedMsg(aplci);
}
static inline void
AppPlciCmsgHeader(AppPlci_t *aplci, _cmsg *cmsg, __u8 cmd, __u8 subcmd)
{
capi_cmsg_header(cmsg, aplci->appl->ApplId, cmd, subcmd,
aplci->appl->MsgId++, aplci->addr);
}
static void
plci_connect_req(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
struct sk_buff *skb;
_cmsg *cmsg = arg;
__u16 Info = 0;
mISDN_FsmChangeState(fi, ST_PLCI_P_0_1);
test_and_set_bit(PLCI_STATE_OUTGOING, &plci->state);
skb = mISDN_alloc_l3msg(260, MT_SETUP);
if (!skb) {
Info = CapiNoPlciAvailable;
goto answer;
}
if ((Info = cmsg2setup_req(cmsg, skb))) {
goto answer;
}
if ((Info = AppPlciCheckBprotocol(aplci, cmsg))) {
goto answer;
}
plciNewCrReq(plci);
plciL4L3(plci, CC_SETUP | REQUEST, skb);
answer:
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
if (cmsg->Info == 0)
cmsg->adr.adrPLCI = aplci->addr;
mISDN_FsmEvent(fi, EV_PI_CONNECT_CONF, cmsg);
}
static void
plci_connect_conf(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
_cmsg *cmsg = arg;
if (cmsg->Info == 0) {
Send2Application(aplci, cmsg);
mISDN_FsmChangeState(fi, ST_PLCI_P_1);
} else {
Send2Application(aplci, cmsg);
mISDN_FsmChangeState(fi, ST_PLCI_P_0);
AppPlciDestr(aplci);
}
}
static void
plci_connect_ind(struct FsmInst *fi, int event, void *arg)
{
mISDN_FsmChangeState(fi, ST_PLCI_P_2);
Send2Application(fi->userdata, arg);
}
static void plci_hold_req(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
plciL4L3(plci, CC_HOLD | REQUEST, arg);
}
static void plci_retrieve_req(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
plciL4L3(plci, CC_RETRIEVE | REQUEST, arg);
}
static void plci_suspend_req(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
plciL4L3(plci, CC_SUSPEND | REQUEST, arg);
}
static void plci_resume_req(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
// we already sent CONF with Info = SuppInfo = 0
mISDN_FsmChangeState(fi, ST_PLCI_P_RES);
plciNewCrReq(plci);
plciL4L3(plci, CC_RESUME | REQUEST, arg);
}
static void
plci_alert_req(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
_cmsg *cmsg = arg;
__u16 Info = 0;
if (test_and_set_bit(PLCI_STATE_ALERTING, &plci->state)) {
Info = 0x0003; // other app is already alerting
} else {
struct sk_buff *skb = mISDN_alloc_l3msg(260, MT_ALERTING);
if (!skb) {
int_error();
goto answer;
}
Info = cmsg2alerting_req(cmsg, skb);
if (Info == 0) {
plciL4L3(plci, CC_ALERTING | REQUEST, skb);
}
}
answer:
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
Send2Application(aplci, cmsg);
}
static void
plci_connect_resp(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
unsigned char cause[4];
_cmsg *cmsg = arg;
struct sk_buff *skb;
if (cmsg->Reject == 0) { // accept
if (AppPlciCheckBprotocol(aplci, cmsg)) {
int_error();
}
AppPlciClearOtherApps(aplci);
plciL4L3(plci, CC_CONNECT | REQUEST, NULL);
mISDN_FsmChangeState(fi, ST_PLCI_P_4);
cmsg_free(cmsg);
return;
}
// ignore, reject
memcpy(cause, "\x02\x80", 2); // IE CAUSE, location = local
switch (cmsg->Reject) {
case 2: cause[2] = 0x90; break; // normal call clearing
case 3: cause[2] = 0x91; break; // user busy
case 4: cause[2] = 0xac; break; // req circuit/channel not avail
case 5: cause[2] = 0x9d; break; // fac rejected
case 6: cause[2] = 0x86; break; // channel unacceptable
case 7: cause[2] = 0xd8; break; // incompatible dest
case 8: cause[2] = 0x9b; break; // dest out of order
default:
if ((cmsg->Reject & 0xff00) == 0x3400) {
cause[2] = cmsg->Reject & 0xff;
} else {
cause[2] = 0x90; break; // normal call clearing
}
}
// FIXME
// WHY ???
// if (cmsg->Reject != 1) {
// ignore
// AppPlciClearOtherApps(aplci);
// }
// plciDetachAppPlci(plci, aplci);
if (plci->nAppl == 1) {
int prim;
if (test_bit(PLCI_STATE_ALERTING, &plci->state)) {
prim = CC_DISCONNECT | REQUEST;
skb = mISDN_alloc_l3msg(10, MT_DISCONNECT);
} else {
// if we already answered, we can't just ignore but must clear actively
prim = CC_RELEASE_COMPLETE | REQUEST;
skb = mISDN_alloc_l3msg(10, MT_RELEASE_COMPLETE);
}
if (!skb) {
plciL4L3(plci, prim, NULL);
} else {
mISDN_AddIE(skb, IE_CAUSE, cause);
plciL4L3(plci, prim, skb);
}
}
cmsg->Command = CAPI_DISCONNECT;
cmsg->Subcommand = CAPI_IND;
cmsg->Messagenumber = aplci->appl->MsgId++;
cmsg->Reject = 0x3400 | cause[2];
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_connect_active_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
mISDN_FsmChangeState(fi, ST_PLCI_P_ACT);
AppPlciLinkUp(aplci);
if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state))
Send2Application(aplci, arg);
else
Send2ApplicationDelayed(aplci, arg);
}
static void plci_connect_active_resp(struct FsmInst *fi, int event, void *arg)
{
cmsg_free(arg);
}
static void plci_disconnect_req(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
u_char cause[4];
_cmsg *cmsg = arg;
mISDN_FsmChangeState(fi, ST_PLCI_P_5);
if (!plci) {
int_error();
return;
}
// FIXME handle additional Inf
capi_cmsg_answer(cmsg);
cmsg->Reason = 0; // disconnect initiated
Send2Application(aplci, cmsg);
AppPlciLinkDown(aplci);
if (!aplci->cause[0]) { // FIXME handle additional Info
struct sk_buff *skb;
skb = mISDN_alloc_l3msg(10, MT_DISCONNECT);
if (!skb) {
plciL4L3(plci, CC_DISCONNECT | REQUEST, NULL);
} else {
memcpy(cause, "\x02\x80\x90", 3); // normal call clearing
mISDN_AddIE(skb, IE_CAUSE, cause);
plciL4L3(plci, CC_DISCONNECT | REQUEST, skb);
}
} else {
/* release physical link */
// FIXME
plciL4L3(plci, CC_RELEASE | REQUEST, NULL);
}
}
static void plci_suspend_conf(struct FsmInst *fi, int event, void *arg)
{
mISDN_FsmChangeState(fi, ST_PLCI_P_5);
}
static void plci_resume_conf(struct FsmInst *fi, int event, void *arg)
{
// facility_ind Resume: Reason = 0
AppPlci_t *aplci = fi->userdata;
mISDN_FsmChangeState(fi, ST_PLCI_P_ACT);
AppPlciLinkUp(aplci);
if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state))
Send2Application(aplci, arg);
else
Send2ApplicationDelayed(aplci, arg);
}
static void
plci_disconnect_ind(struct FsmInst *fi, int event, void *arg)
{
mISDN_FsmChangeState(fi, ST_PLCI_P_6);
Send2Application(fi->userdata, arg);
}
static void
plci_disconnect_resp(struct FsmInst *fi, int event, void *arg)
{
if (arg)
cmsg_free(arg);
mISDN_FsmChangeState(fi, ST_PLCI_P_0);
AppPlciDestr(fi->userdata);
}
static void
plci_appl_release(struct FsmInst *fi, int event, void *arg)
{
AppPlciDestr(fi->userdata);
}
static void
plci_appl_release_disc(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
mISDN_FsmChangeState(fi, ST_PLCI_P_5);
if (!plci) {
int_error();
return;
}
AppPlciLinkDown(aplci);
if (!aplci->cause[0]) {
struct sk_buff *skb;
skb = mISDN_alloc_l3msg(10, MT_DISCONNECT);
if (!skb) {
plciL4L3(plci, CC_DISCONNECT | REQUEST, NULL);
} else {
u_char *cause = "\x02\x80\x9f";
mISDN_AddIE(skb, IE_CAUSE, cause);
plciL4L3(plci, CC_DISCONNECT | REQUEST, skb);
}
} else {
/* release physical link */
// FIXME
plciL4L3(plci, CC_RELEASE | REQUEST, NULL);
}
}
static void
plci_cc_setup_conf(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
_cmsg *cmsg;
Q931_info_t *qi = arg;
u_char *p;
if (aplci->channel == -1) {/* no valid channel set */
mISDN_FsmEvent(fi, EV_PI_CHANNEL_ERR, NULL);
return;
}
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND);
if (qi) {
p = (u_char *)qi;
p += L3_EXTRA_SIZE;
if (qi->connected_nr.off)
cmsg->ConnectedNumber = &p[qi->connected_nr.off + 1];
if (qi->connected_sub.off)
cmsg->ConnectedSubaddress = &p[qi->connected_sub.off + 1];
if (qi->llc.off)
cmsg->LLC = &p[qi->llc.off + 1];
}
if (mISDN_FsmEvent(fi, EV_PI_CONNECT_ACTIVE_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_cc_setup_conf_err(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
_cmsg *cmsg;
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
cmsg->Reason = CapiProtocolErrorLayer3;
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_channel_err(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
_cmsg *cmsg;
u_char cause[4];
struct sk_buff *skb;
skb = mISDN_alloc_l3msg(10, MT_RELEASE_COMPLETE);
if (skb) {
cause[0] = 2;
cause[1] = 0x80;
cause[2] = 0x86; /* channel unacceptable */
mISDN_AddIE(skb, IE_CAUSE, cause);
plciL4L3(aplci->plci, CC_RELEASE_COMPLETE | REQUEST, skb);
} else
int_error();
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
cmsg->Reason = CapiProtocolErrorLayer3;
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_cc_setup_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
_cmsg *cmsg;
u_char *p;
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT, CAPI_IND);
// FIXME: CW
if (qi) {
p = (u_char *)qi;
p += L3_EXTRA_SIZE;
cmsg->CIPValue = q931CIPValue(qi);
if (qi->called_nr.off)
cmsg->CalledPartyNumber = &p[qi->called_nr.off + 1];
if (qi->called_sub.off)
cmsg->CalledPartySubaddress = &p[qi->called_sub.off + 1];
if (qi->calling_nr.off)
cmsg->CallingPartyNumber = &p[qi->calling_nr.off + 1];
if (qi->calling_sub.off)
cmsg->CallingPartySubaddress = &p[qi->calling_sub.off + 1];
if (qi->bearer_capability.off)
cmsg->BC = &p[qi->bearer_capability.off + 1];
if (qi->llc.off)
cmsg->LLC = &p[qi->llc.off + 1];
if (qi->hlc.off)
cmsg->HLC = &p[qi->hlc.off + 1];
#if CAPIUTIL_VERSION > 1
/* ETS 300 092 Annex B */
if (qi->calling_nr.repeated) {
if (qi->ext[qi->calling_nr.ridx].ie.off)
cmsg->CallingPartyNumber2 = &p[qi->ext[qi->calling_nr.ridx].ie.off + 1];
else
int_error();
}
#endif
// all else set to default
}
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_CONNECT_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_cc_setup_compl_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
_cmsg *cmsg;
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND);
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_CONNECT_ACTIVE_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_cc_disconnect_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
u_char *p;
if (qi) {
p = (u_char *)qi;
p += L3_EXTRA_SIZE;
if (qi->cause.off)
memcpy(aplci->cause, &p[qi->cause.off + 1], 3);
}
if (aplci->appl->InfoMask & CAPI_INFOMASK_EARLYB3)
return;
// AppPlciLinkDown(aplci);
plciL4L3(aplci->plci, CC_RELEASE | REQUEST, NULL);
}
static void
plci_cc_release_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
u_char *p;
_cmsg *cmsg;
AppPlciLinkDown(aplci);
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
if (qi) {
p = (u_char *)qi;
p += L3_EXTRA_SIZE;
if (qi->cause.off)
cmsg->Reason = 0x3400 | p[qi->cause.off + 3];
else if (aplci->cause[0]) // cause from CC_DISCONNECT IND
cmsg->Reason = 0x3400 | aplci->cause[2];
else
cmsg->Reason = 0;
} else {
cmsg->Reason = CapiProtocolErrorLayer1;
}
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_cc_notify_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
__u8 *nf;
if (!qi || !qi->notify.off)
return;
nf = (u_char *)qi;
nf += L3_EXTRA_SIZE + qi->notify.off + 1;
if (nf[0] != 1) // len != 1
return;
switch (nf[1]) {
case 0xF9: // user hold
SendSSNotificationEvent(aplci, 0x8000);
break;
case 0xFA: // user retrieve
SendSSNotificationEvent(aplci, 0x8001);
break;
case 0x80: // user suspended
SendSSNotificationEvent(aplci, 0x8002);
break;
case 0x81: // user resumed
SendSSNotificationEvent(aplci, 0x8003);
break;
case 0xFB: // call is diverting
SendSSNotificationEvent(aplci, 0x8004);
break;
case 0xE8: // diversion activated
SendSSNotificationEvent(aplci, 0x8005);
break;
default:
int_errtxt("unhandled notification %x", nf[1]);
}
}
static void plci_hold_conf(struct FsmInst *fi, int event, void *arg)
{
mISDN_FsmChangeState(fi, ST_PLCI_P_HELD);
}
static void
AppPlci_hold_reply(AppPlci_t *aplci, __u16 SuppServiceReason)
{
_cmsg *cmsg;
__u8 tmp[10], *p;
if (aplci->appl) {
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
p = &tmp[1];
p += capiEncodeWord(p, 0x0002); // Hold
p += capiEncodeFacIndSuspend(p, SuppServiceReason);
tmp[0] = p - &tmp[1];
cmsg->FacilitySelector = 0x0003;
cmsg->FacilityIndicationParameter = tmp;
Send2Application(aplci, cmsg);
}
if (SuppServiceReason == CapiSuccess)
mISDN_FsmEvent(&aplci->plci_m, EV_PI_HOLD_CONF, NULL);
}
static void
plci_cc_hold_rej(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
u_char *p;
__u16 SuppServiceReason;
if (qi) { // reject from network
if (qi->cause.off) {
p = (u_char *)qi;
p += L3_EXTRA_SIZE + qi->cause.off;
SuppServiceReason = 0x3400 | p[3];
} else
SuppServiceReason = CapiProtocolErrorLayer3;
} else { // timeout
SuppServiceReason = CapiTimeOut;
}
AppPlci_hold_reply(aplci, SuppServiceReason);
}
static void
plci_cc_hold_ack(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
AppPlci_hold_reply(aplci, CapiSuccess);
AppPlciLinkDown(aplci);
}
static void
plci_cc_hold_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
AppPlci_hold_reply(aplci, CapiSuccess);
AppPlciLinkDown(aplci);
plciL4L3(aplci->plci, CC_HOLD_ACKNOWLEDGE| REQUEST, NULL);
}
static void plci_retrieve_conf(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
mISDN_FsmChangeState(fi, ST_PLCI_P_ACT);
AppPlciLinkUp(aplci);
if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state))
Send2Application(aplci, arg);
else
Send2ApplicationDelayed(aplci, arg);
}
static void
AppPlci_retrieve_reply(AppPlci_t *aplci, __u16 SuppServiceReason)
{
_cmsg *cmsg;
__u8 tmp[10], *p;
if (aplci->appl) {
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
p = &tmp[1];
p += capiEncodeWord(p, 0x0003); // Retrieve
p += capiEncodeFacIndSuspend(p, SuppServiceReason);
tmp[0] = p - &tmp[1];
cmsg->FacilitySelector = 0x0003;
cmsg->FacilityIndicationParameter = tmp;
if (SuppServiceReason != CapiSuccess)
Send2Application(aplci, cmsg);
else
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_RETRIEVE_CONF, cmsg))
cmsg_free(cmsg);
}
}
static void
plci_cc_retrieve_rej(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
u_char *p;
__u16 SuppServiceReason;
if (qi) { // reject from network
if (qi->cause.off) {
p = (u_char *)qi;
p += L3_EXTRA_SIZE + qi->cause.off;
SuppServiceReason = 0x3400 | p[3];
} else
SuppServiceReason = CapiProtocolErrorLayer3;
} else { // timeout
SuppServiceReason = CapiTimeOut;
}
AppPlci_retrieve_reply(aplci, SuppServiceReason);
}
static void
plci_cc_retrieve_ack(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
u_char *ie;
if (qi->channel_id.off) {
ie = (u_char *)qi;
ie += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(ie);
AppPlci_retrieve_reply(aplci, CapiSuccess);
} else
AppPlci_retrieve_reply(aplci, 0x3711); /* resource Error */
}
static void
plci_cc_retrieve_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
u_char *ie;
if (qi->channel_id.off) {
ie = (u_char *)qi;
ie += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(ie);
AppPlci_retrieve_reply(aplci, CapiSuccess);
plciL4L3(aplci->plci, CC_RETRIEVE_ACKNOWLEDGE | REQUEST, NULL);
} else {
AppPlci_retrieve_reply(aplci, 0x3711); /* resource Error */
plciL4L3(aplci->plci, CC_RETRIEVE_REJECT | REQUEST, NULL);
}
}
static void
AppPlci_suspend_reply(AppPlci_t *aplci, __u16 SuppServiceReason)
{
_cmsg *cmsg;
__u8 tmp[10], *p;
if (aplci->appl) {
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
p = &tmp[1];
p += capiEncodeWord(p, 0x0004); // Suspend
p += capiEncodeFacIndSuspend(p, SuppServiceReason);
tmp[0] = p - &tmp[1];
cmsg->FacilitySelector = 0x0003;
cmsg->FacilityIndicationParameter = tmp;
Send2Application(aplci, cmsg);
}
if (SuppServiceReason == CapiSuccess)
mISDN_FsmEvent(&aplci->plci_m, EV_PI_SUSPEND_CONF, NULL);
}
static void
plci_cc_suspend_err(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
u_char *p;
__u16 SuppServiceReason;
if (qi) { // reject from network
if (qi->cause.off) {
p = (u_char *)qi;
p += L3_EXTRA_SIZE + qi->cause.off;
SuppServiceReason = 0x3400 | p[3];
} else
SuppServiceReason = CapiProtocolErrorLayer3;
} else { // timeout
SuppServiceReason = CapiTimeOut;
}
AppPlci_suspend_reply(aplci, SuppServiceReason);
}
static void
plci_cc_suspend_conf(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
_cmsg *cmsg;
AppPlciLinkDown(aplci);
AppPlci_suspend_reply(aplci, CapiSuccess);
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_cc_resume_err(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
u_char *p;
_cmsg *cmsg;
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND);
if (qi) { // reject from network
if (qi->cause.off) {
p = (u_char *)qi;
p += L3_EXTRA_SIZE + qi->cause.off;
cmsg->Reason = 0x3400 | p[3];
} else
cmsg->Reason = 0;
} else { // timeout
cmsg->Reason = CapiProtocolErrorLayer1;
}
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_DISCONNECT_IND, cmsg))
cmsg_free(cmsg);
}
static void
plci_cc_resume_conf(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Q931_info_t *qi = arg;
_cmsg *cmsg;
__u8 tmp[10], *p;
if (!qi || !qi->channel_id.off) {
int_error();
return;
}
p = (u_char *)qi;
p += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(p);
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
p = &tmp[1];
p += capiEncodeWord(p, 0x0005); // Suspend
p += capiEncodeFacIndSuspend(p, CapiSuccess);
tmp[0] = p - &tmp[1];
cmsg->FacilitySelector = 0x0003;
cmsg->FacilityIndicationParameter = tmp;
if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_RESUME_CONF, cmsg))
cmsg_free(cmsg);
}
static void
plci_select_b_protocol_req(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
_cmsg *cmsg = arg;
__u16 Info;
int ret;
Info = AppPlciCheckBprotocol(aplci, cmsg);
if (Info)
goto answer;
ret = AppPlciLinkDown(aplci);
if (ret) {
Info = CapiMessageNotSupportedInCurrentState;
goto answer;
}
ret = AppPlciLinkUp(aplci);
if (ret < 0)
Info = CapiMessageNotSupportedInCurrentState;
else
Info = ret;
answer:
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state))
Send2Application(aplci, arg);
else
Send2ApplicationDelayed(aplci, arg);
}
static void
plci_info_req_overlap(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
Plci_t *plci = aplci->plci;
_cmsg *cmsg = arg;
__u16 Info = 0;
struct sk_buff *skb;
skb = mISDN_alloc_l3msg(100, MT_INFORMATION);
if (skb) {
Info = cmsg2info_req(cmsg, skb);
if (Info == CapiSuccess)
plciL4L3(plci, CC_INFORMATION | REQUEST, skb);
else
kfree_skb(skb);
}
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
Send2Application(aplci, cmsg);
}
static void
plci_cc_ph_control_ind(struct FsmInst *fi, int event, void *arg)
{
AppPlci_t *aplci = fi->userdata;
int *tt = arg;
_cmsg *cmsg;
__u8 tmp[2];
if (!arg)
return;
AppPlciDebug(aplci, CAPI_DBG_PLCI_INFO, "%s: tt(%x)", __FUNCTION__, *tt);
if ((*tt & ~DTMF_TONE_MASK) != DTMF_TONE_VAL)
return;
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND);
tmp[0] = 1;
tmp[1] = *tt & DTMF_TONE_MASK;
cmsg->FacilitySelector = 0x0001;
cmsg->FacilityIndicationParameter = tmp;
Send2Application(aplci, cmsg);
}
static void
plci_info_req(struct FsmInst *fi, int event, void *arg)
{
// FIXME handle INFO CONF
if (arg)
cmsg_free(arg);
}
static struct FsmNode fn_plci_list[] =
{
{ST_PLCI_P_0, EV_AP_CONNECT_REQ, plci_connect_req},
{ST_PLCI_P_0, EV_PI_CONNECT_IND, plci_connect_ind},
{ST_PLCI_P_0, EV_AP_RESUME_REQ, plci_resume_req},
{ST_PLCI_P_0, EV_L3_SETUP_IND, plci_cc_setup_ind},
{ST_PLCI_P_0, EV_AP_RELEASE, plci_appl_release},
{ST_PLCI_P_0_1, EV_PI_CONNECT_CONF, plci_connect_conf},
{ST_PLCI_P_0_1, EV_AP_RELEASE, plci_appl_release},
{ST_PLCI_P_1, EV_PI_CONNECT_ACTIVE_IND, plci_connect_active_ind},
{ST_PLCI_P_1, EV_AP_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_1, EV_PI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_1, EV_AP_INFO_REQ, plci_info_req_overlap},
{ST_PLCI_P_1, EV_L3_SETUP_CONF, plci_cc_setup_conf},
{ST_PLCI_P_1, EV_L3_SETUP_CONF_ERR, plci_cc_setup_conf_err},
{ST_PLCI_P_1, EV_L3_DISCONNECT_IND, plci_cc_disconnect_ind},
{ST_PLCI_P_1, EV_L3_RELEASE_PROC_IND, plci_cc_setup_conf_err},
{ST_PLCI_P_1, EV_L3_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_1, EV_L3_REJECT_IND, plci_cc_release_ind},
{ST_PLCI_P_1, EV_PI_CHANNEL_ERR, plci_channel_err},
{ST_PLCI_P_1, EV_AP_RELEASE, plci_appl_release_disc},
{ST_PLCI_P_2, EV_AP_ALERT_REQ, plci_alert_req},
{ST_PLCI_P_2, EV_AP_CONNECT_RESP, plci_connect_resp},
{ST_PLCI_P_2, EV_AP_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_2, EV_PI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_2, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind},
{ST_PLCI_P_2, EV_AP_INFO_REQ, plci_info_req},
{ST_PLCI_P_2, EV_L3_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_2, EV_AP_RELEASE, plci_appl_release_disc},
{ST_PLCI_P_4, EV_PI_CONNECT_ACTIVE_IND, plci_connect_active_ind},
{ST_PLCI_P_4, EV_AP_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_4, EV_PI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_4, EV_AP_INFO_REQ, plci_info_req},
{ST_PLCI_P_4, EV_L3_SETUP_COMPL_IND, plci_cc_setup_compl_ind},
{ST_PLCI_P_4, EV_L3_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_4, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind},
{ST_PLCI_P_4, EV_PI_CHANNEL_ERR, plci_channel_err},
{ST_PLCI_P_4, EV_AP_RELEASE, plci_appl_release_disc},
{ST_PLCI_P_ACT, EV_AP_CONNECT_ACTIVE_RESP, plci_connect_active_resp},
{ST_PLCI_P_ACT, EV_AP_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_ACT, EV_PI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_ACT, EV_AP_INFO_REQ, plci_info_req},
{ST_PLCI_P_ACT, EV_AP_SELECT_B_PROTOCOL_REQ, plci_select_b_protocol_req},
{ST_PLCI_P_ACT, EV_AP_HOLD_REQ, plci_hold_req},
{ST_PLCI_P_ACT, EV_AP_SUSPEND_REQ, plci_suspend_req},
{ST_PLCI_P_ACT, EV_PI_SUSPEND_CONF, plci_suspend_conf},
{ST_PLCI_P_ACT, EV_L3_DISCONNECT_IND, plci_cc_disconnect_ind},
{ST_PLCI_P_ACT, EV_L3_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_ACT, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind},
{ST_PLCI_P_ACT, EV_L3_NOTIFY_IND, plci_cc_notify_ind},
{ST_PLCI_P_ACT, EV_L3_HOLD_IND, plci_cc_hold_ind},
{ST_PLCI_P_ACT, EV_L3_HOLD_ACKNOWLEDGE, plci_cc_hold_ack},
{ST_PLCI_P_ACT, EV_L3_HOLD_REJECT, plci_cc_hold_rej},
{ST_PLCI_P_ACT, EV_PI_HOLD_CONF, plci_hold_conf},
{ST_PLCI_P_ACT, EV_L3_SUSPEND_ERR, plci_cc_suspend_err},
{ST_PLCI_P_ACT, EV_L3_SUSPEND_CONF, plci_cc_suspend_conf},
{ST_PLCI_P_ACT, EV_PH_CONTROL_IND, plci_cc_ph_control_ind},
{ST_PLCI_P_ACT, EV_AP_RELEASE, plci_appl_release_disc},
{ST_PLCI_P_HELD, EV_AP_RETRIEVE_REQ, plci_retrieve_req},
{ST_PLCI_P_HELD, EV_L3_RETRIEVE_ACKNOWLEDGE, plci_cc_retrieve_ack},
{ST_PLCI_P_HELD, EV_L3_RETRIEVE_REJECT, plci_cc_retrieve_rej},
{ST_PLCI_P_HELD, EV_PI_RETRIEVE_CONF, plci_retrieve_conf},
{ST_PLCI_P_HELD, EV_AP_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_HELD, EV_AP_INFO_REQ, plci_info_req},
{ST_PLCI_P_HELD, EV_L3_RETRIEVE_IND, plci_cc_retrieve_ind},
{ST_PLCI_P_HELD, EV_L3_DISCONNECT_IND, plci_cc_disconnect_ind},
{ST_PLCI_P_HELD, EV_L3_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_HELD, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind},
{ST_PLCI_P_HELD, EV_L3_NOTIFY_IND, plci_cc_notify_ind},
{ST_PLCI_P_HELD, EV_PI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_HELD, EV_AP_RELEASE, plci_appl_release_disc},
{ST_PLCI_P_5, EV_PI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_5, EV_L3_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_5, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind},
{ST_PLCI_P_5, EV_AP_RELEASE, plci_appl_release},
{ST_PLCI_P_6, EV_AP_DISCONNECT_RESP, plci_disconnect_resp},
{ST_PLCI_P_6, EV_AP_RELEASE, plci_disconnect_resp},
{ST_PLCI_P_RES, EV_PI_RESUME_CONF, plci_resume_conf},
{ST_PLCI_P_RES, EV_PI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_RES, EV_L3_RESUME_ERR, plci_cc_resume_err},
{ST_PLCI_P_RES, EV_L3_RESUME_CONF, plci_cc_resume_conf},
{ST_PLCI_P_RES, EV_AP_RELEASE, plci_appl_release_disc},
};
const int FN_PLCI_COUNT = sizeof(fn_plci_list)/sizeof(struct FsmNode);
int
AppPlciConstr(AppPlci_t **aplci, Application_t *appl, Plci_t *plci)
{
AppPlci_t *apl = AppPlci_alloc();
if (!apl)
return(-ENOMEM);
memset(apl, 0, sizeof(AppPlci_t));
INIT_LIST_HEAD(&apl->head);
INIT_LIST_HEAD(&apl->Nccis);
apl->addr = plci->addr;
apl->appl = appl;
apl->plci = plci;
apl->contr = plci->contr;
apl->plci_m.fsm = &plci_fsm;
apl->plci_m.state = ST_PLCI_P_0;
apl->plci_m.debug = plci->contr->debug & CAPI_DBG_PLCI_STATE;
apl->plci_m.userdata = apl;
apl->plci_m.printdebug = AppPlci_debug;
apl->channel = -1;
skb_queue_head_init(&apl->delayedq);
*aplci = apl;
return(0);
}
void AppPlciDestr(AppPlci_t *aplci)
{
struct list_head *item, *next;
if (aplci->plci) {
AppPlciDebug(aplci, CAPI_DBG_PLCI, "%s plci state %s", __FUNCTION__,
str_st_plci[aplci->plci_m.state]);
if (aplci->plci_m.state != ST_PLCI_P_0) {
struct sk_buff *skb = mISDN_alloc_l3msg(10, MT_RELEASE_COMPLETE);
unsigned char cause[] = {2,0x80,0x80| CAUSE_RESOURCES_UNAVAIL};
if (skb) {
mISDN_AddIE(skb, IE_CAUSE, cause);
plciL4L3(aplci->plci, CC_RELEASE_COMPLETE | REQUEST, skb);
}
}
plciDetachAppPlci(aplci->plci, aplci);
}
list_for_each_safe(item, next, &aplci->Nccis) {
ncciDelAppPlci((Ncci_t *)item);
}
if (aplci->appl)
ApplicationDelAppPlci(aplci->appl, aplci);
skb_queue_purge(&aplci->delayedq);
AppPlci_free(aplci);
}
void
AppPlciRelease(AppPlci_t *aplci)
{
struct list_head *item, *next;
list_for_each_safe(item, next, &aplci->Nccis) {
ncciApplRelease((Ncci_t *)item);
}
mISDN_FsmEvent(&aplci->plci_m, EV_AP_RELEASE, NULL);
}
static __inline__ Ncci_t *
get_single_NCCI(AppPlci_t *aplci)
{
struct list_head *item = aplci->Nccis.next;
if (item == &aplci->Nccis)
return(NULL);
if (item->next != &aplci->Nccis)
return(NULL); // more as one NCCI
return((Ncci_t *)item);
}
static int
PL_l3l4(mISDNinstance_t *inst, struct sk_buff *skb)
{
AppPlci_t *aplci;
Ncci_t *ncci;
mISDN_head_t *hh;
hh = mISDN_HEAD_P(skb);
aplci = inst->privat;
if (!aplci)
return(-EINVAL);
ncci = get_single_NCCI(aplci);
capidebug(CAPI_DBG_NCCI_L3, "%s: prim(%x) dinfo (%x) skb(%p) APLCI(%x) ncci(%p)",
__FUNCTION__, hh->prim, hh->dinfo, skb, aplci->addr, ncci);
if (hh->prim == CAPI_MESSAGE_REQUEST) {
if (!ncci) {
int_error();
return(-EINVAL);
}
ncciSendMessage(ncci, skb);
return(0);
}
if (!ncci) {
if ((hh->prim != (DL_ESTABLISH | INDICATION)) && (hh->prim != (DL_ESTABLISH | CONFIRM))) {
int_error();
return(-ENODEV);
}
ncci = ncciConstr(aplci);
if (!ncci) {
int_error();
return(-ENOMEM);
}
}
return(ncci_l3l4(ncci, hh, skb));
}
static int
PL_l3l4mux(mISDNinstance_t *inst, struct sk_buff *skb)
{
AppPlci_t *aplci;
Ncci_t *ncci;
mISDN_head_t *hh;
__u32 addr;
hh = mISDN_HEAD_P(skb);
aplci = inst->privat;
if (!aplci)
return(-EINVAL);
capidebug(CAPI_DBG_NCCI_L3, "%s: prim(%x) dinfo (%x) skb->len(%d)",
__FUNCTION__, hh->prim, hh->dinfo, skb->len);
if (skb->len < 4) {
int_error();
return(-EINVAL);
}
if (hh->prim == CAPI_MESSAGE_REQUEST) {
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT);
if (!ncci) {
int_error();
return(-EINVAL);
}
ncciSendMessage(ncci, skb);
return(0);
}
addr = CAPIMSG_U32(skb->data, 0);
ncci = getNCCI4addr(aplci, addr, GET_NCCI_ONLY_PLCI);
if (hh->prim == CAPI_CONNECT_B3_IND) {
if (ncci) {
int_error();
return(-EBUSY);
}
ncci = ncciConstr(aplci);
if (!ncci) {
int_error();
return(-ENOMEM);
}
addr &= 0xffff0000;
addr |= aplci->addr;
ncci->addr = addr;
capimsg_setu32(skb->data, 0, addr);
#ifdef OLDCAPI_DRIVER_INTERFACE
ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, addr, ncci->window);
#endif
} else if (hh->prim == CAPI_CONNECT_B3_CONF) {
if (ncci && ((addr & 0xffff0000) != 0)) {
if (ncci->addr != addr) {
ncci->addr = addr;
#ifdef OLDCAPI_DRIVER_INTERFACE
ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, addr, ncci->window);
#endif
} else
int_error();
}
}
if (!ncci) {
int_error();
return(-ENODEV);
}
return(ncci_l3l4_direct(ncci, hh, skb));
}
static int
AppPlciLinkUp(AppPlci_t *aplci)
{
mISDN_pid_t pid;
mISDN_stPara_t stpara;
int retval;
if (aplci->channel == -1) {/* no valid channel set */
int_error();
return -EINVAL;
}
memset(&pid, 0, sizeof(mISDN_pid_t));
pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2) | ISDN_LAYER(3) |
ISDN_LAYER(4);
if (test_bit(PLCI_STATE_OUTGOING, &aplci->plci->state))
pid.global = 1; // DTE, orginate
else
pid.global = 2; // DCE, answer
if (aplci->Bprotocol.B1 > 23) {
int_errtxt("wrong B1 prot %x", aplci->Bprotocol.B1);
return 0x3001;
}
pid.protocol[1] = (1 << aplci->Bprotocol.B1) |
ISDN_PID_LAYER(1) | ISDN_PID_BCHANNEL_BIT;
retval = mISDN_add_pid_parameter(&pid, 1, &aplci->Bprotocol.B1cfg[0]);
if (retval) {/* ressource error */
kfree(pid.pbuf);
return 0x1008;
}
if (aplci->Bprotocol.B2 > 23) {
int_errtxt("wrong B2 prot %x", aplci->Bprotocol.B2);
kfree(pid.pbuf);
return 0x3002;
}
pid.protocol[2] = (1 << aplci->Bprotocol.B2) |
ISDN_PID_LAYER(2) | ISDN_PID_BCHANNEL_BIT;
retval = mISDN_add_pid_parameter(&pid, 2, &aplci->Bprotocol.B2cfg[0]);
if (retval) {/* ressource error */
kfree(pid.pbuf);
return 0x1008;
}
/* handle DTMF TODO */
if ((pid.protocol[2] == ISDN_PID_L2_B_TRANS) &&
(pid.protocol[1] == ISDN_PID_L1_B_64TRANS))
pid.protocol[2] = ISDN_PID_L2_B_TRANSDTMF;
if (aplci->Bprotocol.B3 > 23) {
int_errtxt("wrong B3 prot %x", aplci->Bprotocol.B3);
kfree(pid.pbuf);
return 0x3003;
}
pid.protocol[3] = (1 << aplci->Bprotocol.B3) |
ISDN_PID_LAYER(3) | ISDN_PID_BCHANNEL_BIT;
retval = mISDN_add_pid_parameter(&pid, 3, &aplci->Bprotocol.B3cfg[0]);
if (retval) {/* ressource error */
kfree(pid.pbuf);
return 0x1008;
}
capidebug(CAPI_DBG_PLCI, "AppPlciLinkUp B1(%x) B2(%x) B3(%x) global(%d) ch(%x)",
pid.protocol[1], pid.protocol[2], pid.protocol[3], pid.global,
aplci->channel);
capidebug(CAPI_DBG_PLCI, "AppPlciLinkUp B1cfg(%d) B2cfg(%d) B3cfg(%d) maxplen(%d)",
aplci->Bprotocol.B1cfg[0], aplci->Bprotocol.B2cfg[0],
aplci->Bprotocol.B3cfg[0], pid.maxplen);
capidebug(CAPI_DBG_PLCI, "AppPlciLinkUp ch(%d) aplci->contr->linklist(%p)",
aplci->channel & 3, aplci->contr->linklist);
pid.protocol[4] = ISDN_PID_L4_B_CAPI20;
aplci->link = ControllerSelChannel(aplci->contr, aplci->channel);
if (!aplci->link) {
int_error();
kfree(pid.pbuf);
return(-EBUSY);
}
capidebug(CAPI_DBG_NCCI, "AppPlciLinkUp aplci->link(%p)", aplci->link);
memset(&aplci->link->inst.pid, 0, sizeof(mISDN_pid_t));
aplci->link->inst.privat = aplci;
aplci->link->inst.pid.layermask = ISDN_LAYER(4);
aplci->link->inst.pid.protocol[4] = ISDN_PID_L4_B_CAPI20;
if (pid.protocol[3] == ISDN_PID_L3_B_TRANS) {
aplci->link->inst.pid.protocol[3] = ISDN_PID_L3_B_TRANS;
aplci->link->inst.pid.layermask |= ISDN_LAYER(3);
}
if (aplci->link->inst.function)
int_errtxt("id(%08x) overwrite function (%p)", aplci->link->inst.id, aplci->link->inst.function);
if (aplci->Bprotocol.B3 == 0) // transparent
aplci->link->inst.function = PL_l3l4;
else
aplci->link->inst.function = PL_l3l4mux;
retval = mISDN_ctrl(aplci->link->st, MGR_ADDLAYER | REQUEST, &aplci->link->inst);
if (retval) {
printk(KERN_WARNING "%s MGR_ADDLAYER | REQUEST ret(%d)\n",
__FUNCTION__, retval);
return(retval);
}
stpara.maxdatalen = aplci->appl->reg_params.datablklen;
stpara.up_headerlen = CAPI_B3_DATA_IND_HEADER_SIZE;
stpara.down_headerlen = 0;
retval = mISDN_ctrl(aplci->link->st, MGR_ADDSTPARA | REQUEST, &stpara);
if (retval) {
printk(KERN_WARNING "%s MGR_SETSTACK | REQUEST ret(%d)\n",
__FUNCTION__, retval);
}
retval = mISDN_ctrl(aplci->link->st, MGR_SETSTACK | REQUEST, &pid);
kfree(pid.pbuf);
if (retval) {
printk(KERN_WARNING "%s MGR_SETSTACK | REQUEST ret(%d)\n",
__FUNCTION__, retval);
return(retval);
}
return(0);
}
static int
ReleaseLink(AppPlci_t *aplci)
{
int retval = 0;
if (aplci->link) {
#if 0
if (ncci->ncci_m.state != ST_NCCI_N_0)
ncciL4L3(ncci, DL_RELEASE | REQUEST, 0, 0, NULL, NULL);
#endif
retval = mISDN_ctrl(aplci->link->inst.st, MGR_CLEARSTACK | REQUEST, NULL);
if (retval)
int_error();
aplci->link = NULL;
skb_queue_purge(&aplci->delayedq);
test_and_clear_bit(PLCI_STATE_STACKREADY, &aplci->plci->state);
}
return(retval);
}
Ncci_t *
getNCCI4addr(AppPlci_t *aplci, __u32 addr, int mode)
{
Ncci_t *ncci = NULL;
struct list_head *item;
int cnt = 0;
list_for_each(item, &aplci->Nccis) {
cnt++;
ncci = (Ncci_t *)item;
if (ncci->addr == addr)
return(ncci);
if (mode == GET_NCCI_ONLY_PLCI) {
if (ncci->addr == (addr & 0xffff))
return(ncci);
}
}
if (!cnt)
return(NULL);
if (mode != GET_NCCI_PLCI)
return(NULL);
if (1 == cnt) {
if (!(addr & 0xffff0000))
return(ncci);
}
return(NULL);
}
void
AppPlciDelNCCI(Ncci_t *ncci) {
list_del_init(&ncci->head);
}
int
AppPlcimISDN_Active(AppPlci_t *aplci)
{
if (!aplci) {
int_error();
return(-EINVAL);
}
if (!test_and_set_bit(PLCI_STATE_SENDDELAYED, &aplci->plci->state)) {
test_and_set_bit(PLCI_STATE_STACKREADY, &aplci->plci->state);
SendingDelayedMsg(aplci);
} else
test_and_set_bit(PLCI_STATE_STACKREADY, &aplci->plci->state);
return(0);
}
void
AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg)
{
Q931_info_t *qi = arg;
u_char *ie;
AppPlciDebug(aplci, CAPI_DBG_PLCI_L3, "%s: aplci(%x) pr(%x) arg(%p)",
__FUNCTION__, aplci->addr, pr, arg);
switch (pr) {
case CC_SETUP | INDICATION:
if (!qi)
return;
if (qi->channel_id.off) {
ie = (u_char *)qi;
ie += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(ie);
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_IND, arg);
if (qi) {
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi);
AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
AppPlciInfoIndIE(aplci, IE_CALLED_PN, CAPI_INFOMASK_CALLEDPN, qi);
AppPlciInfoIndIE(aplci, IE_COMPLETE, CAPI_INFOMASK_COMPLETE, qi);
}
break;
case CC_TIMEOUT | INDICATION:
mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_CONF_ERR, arg);
break;
case CC_CONNECT | INDICATION:
if (qi) {
AppPlciInfoIndIE(aplci, IE_DATE, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi);
AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
if (qi->channel_id.off) {
ie = (u_char *)qi;
ie += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(ie);
}
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_CONF, arg);
break;
case CC_CONNECT_ACKNOWLEDGE | INDICATION:
if (qi) {
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
if (qi->channel_id.off) {
ie = (u_char *)qi;
ie += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(ie);
}
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_COMPL_IND, arg);
break;
case CC_DISCONNECT | INDICATION:
if (qi) {
AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_EARLYB3, MT_DISCONNECT);
AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi);
AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_DISCONNECT_IND, arg);
break;
case CC_RELEASE | INDICATION:
if (qi) {
AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_RELEASE_IND, arg);
break;
case CC_RELEASE_COMPLETE | INDICATION:
if (qi) {
AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_RELEASE_IND, arg);
break;
case CC_RELEASE_CR | INDICATION:
mISDN_FsmEvent(&aplci->plci_m, EV_L3_RELEASE_PROC_IND, arg);
break;
case CC_SETUP_ACKNOWLEDGE | INDICATION:
if (qi) {
AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_SETUP_ACKNOWLEDGE);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_PROGRESS,
CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi);
AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
if (qi->channel_id.off) {
ie = (u_char *)qi;
ie += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(ie);
}
}
break;
case CC_PROCEEDING | INDICATION:
if (qi) {
AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_CALL_PROCEEDING);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_PROGRESS,
CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi);
AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
if (qi->channel_id.off) {
ie = (u_char *)qi;
ie += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(ie);
}
}
break;
case CC_ALERTING | INDICATION:
if (qi) {
AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_ALERTING);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
AppPlciInfoIndIE(aplci, IE_PROGRESS,
CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi);
AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi);
AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
if (qi->channel_id.off) {
ie = (u_char *)qi;
ie += L3_EXTRA_SIZE + qi->channel_id.off;
aplci->channel = plci_parse_channel_id(ie);
}
}
break;
case CC_PROGRESS | INDICATION:
if (qi) {
AppPlciInfoIndMsg(aplci, CAPI_INFOMASK_PROGRESS, MT_PROGRESS);
AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi);
AppPlciInfoIndIE(aplci, IE_PROGRESS,
CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi);
}
break;
case CC_HOLD | INDICATION:
if (qi)
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
if (mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_IND, arg)) {
/* no routine reject L3 */
plciL4L3(aplci->plci, CC_HOLD_REJECT | REQUEST, NULL);
}
break;
case CC_HOLD_ACKNOWLEDGE | INDICATION:
if (qi)
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_ACKNOWLEDGE, arg);
break;
case CC_HOLD_REJECT | INDICATION:
if (qi) {
AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_REJECT, arg);
break;
case CC_RETRIEVE | INDICATION:
if (qi) {
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
}
if (mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_IND, arg)) {
/* no routine reject L3 */
plciL4L3(aplci->plci, CC_RETRIEVE_REJECT | REQUEST, NULL);
}
break;
case CC_RETRIEVE_ACKNOWLEDGE | INDICATION:
if (qi) {
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi);
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_ACKNOWLEDGE, arg);
break;
case CC_RETRIEVE_REJECT | INDICATION:
if (qi) {
AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi);
AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi);
}
mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_REJECT, arg);
break;
case CC_SUSPEND_ACKNOWLEDGE | INDICATION:
mISDN_FsmEvent(&aplci->plci_m, EV_L3_SUSPEND_CONF, arg);
break;
case CC_SUSPEND_REJECT | INDICATION:
mISDN_FsmEvent(&aplci->plci_m, EV_L3_SUSPEND_ERR, arg);
break;
case CC_RESUME_ACKNOWLEDGE | INDICATION:
mISDN_FsmEvent(&aplci->plci_m, EV_L3_RESUME_CONF, arg);
break;
case CC_RESUME_REJECT | INDICATION:
mISDN_FsmEvent(&aplci->plci_m, EV_L3_RESUME_ERR, arg);
break;
case CC_NOTIFY | INDICATION:
mISDN_FsmEvent(&aplci->plci_m, EV_L3_NOTIFY_IND, arg);
break;
case PH_CONTROL | INDICATION:
/* TOUCH TONE */
mISDN_FsmEvent(&aplci->plci_m, EV_PH_CONTROL_IND, arg);
break;
default:
AppPlciDebug(aplci, CAPI_DBG_WARN,
"%s: pr 0x%x not handled", __FUNCTION__, pr);
break;
}
}
void
AppPlciGetCmsg(AppPlci_t *aplci, _cmsg *cmsg)
{
int retval = 0;
switch (CMSGCMD(cmsg)) {
case CAPI_INFO_REQ:
retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_INFO_REQ, cmsg);
break;
case CAPI_ALERT_REQ:
retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_ALERT_REQ, cmsg);
break;
case CAPI_CONNECT_REQ:
retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_CONNECT_REQ, cmsg);
break;
case CAPI_CONNECT_RESP:
retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_CONNECT_RESP, cmsg);
break;
case CAPI_DISCONNECT_REQ:
retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_DISCONNECT_REQ, cmsg);
break;
case CAPI_DISCONNECT_RESP:
retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_DISCONNECT_RESP, cmsg);
break;
case CAPI_CONNECT_ACTIVE_RESP:
retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_CONNECT_ACTIVE_RESP, cmsg);
break;
case CAPI_SELECT_B_PROTOCOL_REQ:
retval = mISDN_FsmEvent(&aplci->plci_m, EV_AP_SELECT_B_PROTOCOL_REQ, cmsg);
break;
default:
int_error();
retval = -1;
}
if (retval) {
if (cmsg->Command == CAPI_REQ) {
capi_cmsg_answer(cmsg);
cmsg->Info = CapiMessageNotSupportedInCurrentState;
Send2Application(aplci, cmsg);
} else
cmsg_free(cmsg);
}
}
__u16
AppPlciSendMessage(AppPlci_t *aplci, struct sk_buff *skb)
{
_cmsg *cmsg;
__u16 ret;
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
ret = CAPI_REGOSRESOURCEERR;
} else {
capi_message2cmsg(cmsg, skb->data);
AppPlciGetCmsg(aplci, cmsg);
dev_kfree_skb(skb);
ret = CAPI_NOERROR;
}
return(ret);
}
void
ConnectB3Request(AppPlci_t *aplci, struct sk_buff *skb)
{
Ncci_t *ncci = ncciConstr(aplci);
int err;
if (!ncci) {
int_error();
dev_kfree_skb(skb);
return;
}
if (!ncci->link) {
int_error();
dev_kfree_skb(skb);
return;
}
err = mISDN_queue_message(&ncci->link->inst, 0, skb);
if (err) {
int_errtxt("mISDN_queue_message return(%d)", err);
dev_kfree_skb(skb);
}
}
void
DisconnectB3Request(AppPlci_t *aplci, struct sk_buff *skb)
{
Ncci_t *ncci;
int err;
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT);
if ((!ncci) || (!ncci->link)) {
int_error();
if (aplci->appl)
AnswerMessage2Application(aplci->appl, skb, CapiIllContrPlciNcci);
dev_kfree_skb(skb);
return;
}
if (ncci->link->inst.id == 0) {
/* stack is already cleared and so we cannot handle this via the stack */
ncciSendMessage(ncci, skb);
return;
}
err = mISDN_queue_message(&ncci->link->inst, 0, skb);
if (err) {
int_errtxt("mISDN_queue_message return(%d)", err);
dev_kfree_skb(skb);
}
}
static int
AppPlciLinkDown(AppPlci_t *aplci)
{
struct list_head *item, *next;
list_for_each_safe(item, next, &aplci->Nccis) {
ncciReleaseLink((Ncci_t *)item);
}
ReleaseLink(aplci);
return(0);
}
int
AppPlciFacHoldReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
struct sk_buff *skb;
skb = mISDN_alloc_l3msg(20, MT_HOLD);
if (!skb) {
int_error();
return CapiIllMessageParmCoding;
}
if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_HOLD_REQ, skb)) {
// no routine
facConfParm->u.Info.SupplementaryServiceInfo =
CapiRequestNotAllowedInThisState;
dev_kfree_skb(skb);
return CapiMessageNotSupportedInCurrentState;
} else {
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
}
return CapiSuccess;
}
int
AppPlciFacRetrieveReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
struct sk_buff *skb;
skb = mISDN_alloc_l3msg(20, MT_RETRIEVE);
if (!skb) {
int_error();
return CapiIllMessageParmCoding;
}
if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_RETRIEVE_REQ, skb)) {
// no routine
facConfParm->u.Info.SupplementaryServiceInfo =
CapiRequestNotAllowedInThisState;
dev_kfree_skb(skb);
return CapiMessageNotSupportedInCurrentState;
} else {
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
}
return CapiSuccess;
}
int
AppPlciFacSuspendReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
__u8 *CallIdentity;
struct sk_buff *skb;
CallIdentity = facReqParm->u.Suspend.CallIdentity;
if (CallIdentity && CallIdentity[0] > 8)
return CapiIllMessageParmCoding;
skb = mISDN_alloc_l3msg(20, MT_SUSPEND);
if (!skb) {
int_error();
return CapiIllMessageParmCoding;
}
if (CallIdentity && CallIdentity[0])
mISDN_AddIE(skb, IE_CALL_ID, CallIdentity);
if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_SUSPEND_REQ, skb)) {
// no routine
facConfParm->u.Info.SupplementaryServiceInfo =
CapiRequestNotAllowedInThisState;
dev_kfree_skb(skb);
return CapiMessageNotSupportedInCurrentState;
} else {
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
}
return CapiSuccess;
}
int
AppPlciFacResumeReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
{
__u8 *CallIdentity;
struct sk_buff *skb;
CallIdentity = facReqParm->u.Resume.CallIdentity;
if (CallIdentity && CallIdentity[0] > 8) {
AppPlciDestr(aplci);
return CapiIllMessageParmCoding;
}
skb = mISDN_alloc_l3msg(20, MT_RESUME);
if (!skb) {
int_error();
AppPlciDestr(aplci);
return CapiIllMessageParmCoding;
}
if (CallIdentity && CallIdentity[0])
mISDN_AddIE(skb, IE_CALL_ID, CallIdentity);
if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_RESUME_REQ, skb))
dev_kfree_skb(skb);
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
return CapiSuccess;
}
static void
AppPlciClearOtherApps(AppPlci_t *aplci)
{
AppPlci_t *o_aplci;
_cmsg *cm;
struct list_head *item, *next;
if (!aplci->plci)
return;
if (aplci->plci->nAppl <= 1)
return;
list_for_each_safe(item, next, &aplci->plci->AppPlcis) {
o_aplci = (AppPlci_t *)item;
if (o_aplci != aplci) {
CMSG_ALLOC(cm);
AppPlciCmsgHeader(o_aplci, cm, CAPI_DISCONNECT, CAPI_IND);
cm->Reason = 0x3304; // other application got the call
mISDN_FsmEvent(&o_aplci->plci_m, EV_PI_DISCONNECT_IND, cm);
}
}
}
static void
AppPlciInfoIndMsg(AppPlci_t *aplci, __u32 mask, unsigned char mt)
{
_cmsg *cmsg;
if ((!aplci->appl) || (!(aplci->appl->InfoMask & mask)))
return;
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_INFO, CAPI_IND);
cmsg->InfoNumber = 0x8000 | mt;
cmsg->InfoElement = 0;
Send2Application(aplci, cmsg);
}
static void
AppPlciInfoIndIE(AppPlci_t *aplci, unsigned char ie, __u32 mask, Q931_info_t *qi)
{
_cmsg *cmsg;
u_char *iep = NULL;
ie_info_t *ies;
if ((!aplci->appl) || (!(aplci->appl->InfoMask & mask)))
return;
if (!qi)
return;
ies = &qi->bearer_capability;
if (ie & 0x80) { /* single octett */
if (ie == IE_COMPLETE) {
if (!qi->sending_complete.off)
return;
} else {
int_error();
return;
}
} else {
if (mISDN_l3_ie2pos(ie) < 0)
return;
ies += mISDN_l3_ie2pos(ie);
if (!ies->off)
return;
iep = (u_char *)qi;
iep += L3_EXTRA_SIZE + ies->off +1;
}
CMSG_ALLOC(cmsg);
AppPlciCmsgHeader(aplci, cmsg, CAPI_INFO, CAPI_IND);
cmsg->InfoNumber = ie;
cmsg->InfoElement = iep;
if (ie == IE_PROGRESS && aplci->appl->InfoMask & CAPI_INFOMASK_EARLYB3) {
if (iep[0] == 0x02 && iep[2] == 0x88) { // in-band information available
AppPlciLinkUp(aplci);
if (!test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state)) {
Send2ApplicationDelayed(aplci,cmsg);
return;
}
}
}
Send2Application(aplci, cmsg);
}
void init_AppPlci(void)
{
plci_fsm.state_count = ST_PLCI_COUNT;
plci_fsm.event_count = EV_PLCI_COUNT;
plci_fsm.strEvent = str_ev_plci;
plci_fsm.strState = str_st_plci;
mISDN_FsmNew(&plci_fsm, fn_plci_list, FN_PLCI_COUNT);
}
void free_AppPlci(void)
{
mISDN_FsmFree(&plci_fsm);
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/appl.c 0000644 0000000 0000050 00000031346 11135651701 017475 0 ustar root src /* $Id: appl.c,v 1.14 2006/03/06 12:52:07 keil Exp $
*
* Applications are owned by the controller and only
* handle this controller, multiplexing multiple
* controller with one application is done in the higher
* driver independ CAPI driver. The application contain
* the Listen state machine.
*
*/
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
#include "mISDNManufacturer.h"
#define applDebug(appl, lev, fmt, args...) \
capidebug(lev, fmt, ## args)
static struct list_head garbage_applications = LIST_HEAD_INIT(garbage_applications);
int
ApplicationConstr(Controller_t *contr, __u16 ApplId, capi_register_params *rp)
{
Application_t *appl = kmalloc(sizeof(Application_t), GFP_ATOMIC);
if (!appl) {
return(-ENOMEM);
}
memset(appl, 0, sizeof(Application_t));
INIT_LIST_HEAD(&appl->head);
appl->contr = contr;
appl->maxplci = contr->maxplci;
appl->AppPlcis = kmalloc(appl->maxplci * sizeof(AppPlci_t *), GFP_ATOMIC);
if (!appl->AppPlcis) {
kfree(appl);
return(-ENOMEM);
}
memset(appl->AppPlcis, 0, appl->maxplci * sizeof(AppPlci_t *));
appl->ApplId = ApplId;
appl->MsgId = 1;
appl->NotificationMask = 0;
memcpy(&appl->reg_params, rp, sizeof(capi_register_params));
listenConstr(appl);
list_add(&appl->head, &contr->Applications);
test_and_set_bit(APPL_STATE_ACTIV, &appl->state);
return(0);
}
/*
* Destroy the Application
*
* depending who initiate this we cannot release imediatly, if
* any AppPlci is still in use.
*
* @who: 0 - a AppPlci is released in state APPL_STATE_RELEASE
* 1 - Application is released from CAPI application
* 2 - the controller is resetted
* 3 - the controller is removed
* 4 - the CAPI module will be unload
*/
int
ApplicationDestr(Application_t *appl, int who)
{
int i, used = 0;
AppPlci_t **aplci_p = appl->AppPlcis;
if (test_and_set_bit(APPL_STATE_DESTRUCTOR, &appl->state)) {
// we are allready in this function
return(-EBUSY);
}
test_and_set_bit(APPL_STATE_RELEASE, &appl->state);
test_and_clear_bit(APPL_STATE_ACTIV, &appl->state);
listenDestr(appl);
if (who > 2) {
appl->contr = NULL;
}
if (aplci_p) {
for (i = 0; i < appl->maxplci; i++) {
if (*aplci_p) {
switch (who) {
case 4:
AppPlciDestr(*aplci_p);
*aplci_p = NULL;
break;
case 1:
case 2:
case 3:
AppPlciRelease(*aplci_p);
case 0:
if ((volatile AppPlci_t *)(*aplci_p))
used++;
break;
}
}
aplci_p++;
}
}
if (used) {
if (who == 3) {
list_del_init(&appl->head);
list_add(&appl->head, &garbage_applications);
}
test_and_clear_bit(APPL_STATE_DESTRUCTOR, &appl->state);
return(-EBUSY);
}
list_del_init(&appl->head);
appl->maxplci = 0;
kfree(appl->AppPlcis);
appl->AppPlcis = NULL;
kfree(appl);
return(0);
}
AppPlci_t *
getAppPlci4addr(Application_t *appl, __u32 addr)
{
int plci_idx = (addr >> 8) & 0xff;
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return NULL;
}
return(appl->AppPlcis[plci_idx - 1]);
}
static void
FacilityReq(Application_t *appl, struct sk_buff *skb)
{
_cmsg *cmsg;
AppPlci_t *aplci;
Ncci_t *ncci;
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
dev_kfree_skb(skb);
return;
}
capi_message2cmsg(cmsg, skb->data);
switch (cmsg->FacilitySelector) {
case 0x0000: // Handset
case 0x0001: // DTMF
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (aplci) {
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_PLCI);
if (ncci) {
ncciGetCmsg(ncci, cmsg);
break;
}
}
SendCmsgAnswer2Application(appl, cmsg, CapiIllContrPlciNcci);
break;
case 0x0003: // SupplementaryServices
SupplementaryFacilityReq(appl, cmsg);
break;
default:
int_error();
SendCmsgAnswer2Application(appl, cmsg, CapiFacilityNotSupported);
break;
}
dev_kfree_skb(skb);
}
void
ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
{
Plci_t *plci;
AppPlci_t *aplci;
__u16 ret;
switch (CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data))) {
// new NCCI
case CAPI_CONNECT_B3_REQ:
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
ConnectB3Request(aplci, skb);
break;
// maybe already down NCCI
case CAPI_DISCONNECT_B3_RESP:
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
DisconnectB3Request(aplci, skb);
break;
// for PLCI state machine
case CAPI_INFO_REQ:
case CAPI_ALERT_REQ:
case CAPI_CONNECT_RESP:
case CAPI_CONNECT_ACTIVE_RESP:
case CAPI_DISCONNECT_REQ:
case CAPI_DISCONNECT_RESP:
case CAPI_SELECT_B_PROTOCOL_REQ:
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
goto free;
}
ret = AppPlciSendMessage(aplci, skb);
if (ret) {
int_error();
}
break;
case CAPI_CONNECT_REQ:
if (ControllerNewPlci(appl->contr, &plci, MISDN_ID_ANY)) {
AnswerMessage2Application(appl, skb, CapiNoPlciAvailable);
goto free;
}
aplci = ApplicationNewAppPlci(appl, plci);
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiNoPlciAvailable);
goto free;
}
ret = AppPlciSendMessage(aplci, skb);
if (ret) {
int_error();
}
break;
// for LISTEN state machine
case CAPI_LISTEN_REQ:
ret = listenSendMessage(appl, skb);
if (ret) {
int_error();
}
break;
// other
case CAPI_FACILITY_REQ:
FacilityReq(appl, skb);
break;
case CAPI_FACILITY_RESP:
goto free;
case CAPI_MANUFACTURER_REQ:
applManufacturerReq(appl, skb);
break;
case CAPI_INFO_RESP:
goto free;
default:
applDebug(appl, CAPI_DBG_WARN, "applSendMessage: %#x %#x not handled!",
CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
break;
}
return;
free:
dev_kfree_skb(skb);
return;
}
AppPlci_t *
ApplicationNewAppPlci(Application_t *appl, Plci_t *plci)
{
AppPlci_t *aplci;
int plci_idx = (plci->addr >> 8) & 0xff;
if (test_bit(APPL_STATE_RELEASE, &appl->state))
return(NULL);
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return(NULL);
}
if (appl->AppPlcis[plci_idx - 1]) {
int_error();
return(NULL);
}
if (AppPlciConstr(&aplci, appl, plci)) {
int_error();
return(NULL);
}
applDebug(appl, CAPI_DBG_APPL_INFO, "ApplicationNewAppPlci: idx(%d) aplci(%p) appl(%p) plci(%p)",
plci_idx, aplci, appl, plci);
appl->AppPlcis[plci_idx - 1] = aplci;
plciAttachAppPlci(plci, aplci);
return(aplci);
}
void
ApplicationDelAppPlci(Application_t *appl, AppPlci_t *aplci)
{
int plci_idx = (aplci->addr >> 8) & 0xff;
if ((plci_idx < 1) || (plci_idx >= appl->maxplci)) {
int_error();
return;
}
if (appl->AppPlcis[plci_idx - 1] != aplci) {
int_error();
return;
}
appl->AppPlcis[plci_idx - 1] = NULL;
if (test_bit(APPL_STATE_RELEASE, &appl->state) &&
!test_bit(APPL_STATE_DESTRUCTOR, &appl->state))
ApplicationDestr(appl, 0);
}
void
SendCmsg2Application(Application_t *appl, _cmsg *cmsg)
{
struct sk_buff *skb;
if (test_bit(APPL_STATE_RELEASE, &appl->state)) {
/* Application is released and cannot receive messages
* anymore. To avoid stalls in the state machines we
* must answer INDICATIONS.
*/
AppPlci_t *aplci;
Ncci_t *ncci;
if (CAPI_IND != cmsg->Subcommand)
goto free;
switch(cmsg->Command) {
// for NCCI state machine
case CAPI_CONNECT_B3:
cmsg->Reject = 2;
case CAPI_CONNECT_B3_ACTIVE:
case CAPI_DISCONNECT_B3:
aplci = getAppPlci4addr(appl, (cmsg->adr.adrNCCI & 0xffff));
if (!aplci)
goto free;
ncci = getNCCI4addr(aplci, cmsg->adr.adrNCCI, GET_NCCI_EXACT);
if (!ncci) {
int_error();
goto free;
}
capi_cmsg_answer(cmsg);
ncciGetCmsg(ncci, cmsg);
break;
// for PLCI state machine
case CAPI_CONNECT:
cmsg->Reject = 2;
case CAPI_CONNECT_ACTIVE:
case CAPI_DISCONNECT:
aplci = getAppPlci4addr(appl, (cmsg->adr.adrPLCI & 0xffff));
if (!aplci)
goto free;
capi_cmsg_answer(cmsg);
AppPlciGetCmsg(aplci, cmsg);
break;
case CAPI_FACILITY:
case CAPI_MANUFACTURER:
case CAPI_INFO:
goto free;
default:
int_error();
goto free;
}
return;
}
if (!(skb = alloc_skb(CAPI_MSG_DEFAULT_LEN, GFP_ATOMIC))) {
printk(KERN_WARNING "%s: no mem for %d bytes\n", __FUNCTION__, CAPI_MSG_DEFAULT_LEN);
int_error();
goto free;
}
capi_cmsg2message(cmsg, skb->data);
applDebug(appl, CAPI_DBG_APPL_MSG, "%s: len(%d) applid(%x) %s msgnr(%d) addr(%08x)",
__FUNCTION__, CAPIMSG_LEN(skb->data), cmsg->ApplId, capi_cmd2str(cmsg->Command, cmsg->Subcommand),
cmsg->Messagenumber, cmsg->adr.adrController);
if (CAPI_MSG_DEFAULT_LEN < CAPIMSG_LEN(skb->data)) {
printk(KERN_ERR "%s: CAPI_MSG_DEFAULT_LEN overrun (%d/%d)\n", __FUNCTION__,
CAPIMSG_LEN(skb->data), CAPI_MSG_DEFAULT_LEN);
int_error();
dev_kfree_skb(skb);
goto free;
}
skb_put(skb, CAPIMSG_LEN(skb->data));
#ifdef OLDCAPI_DRIVER_INTERFACE
appl->contr->ctrl->handle_capimsg(appl->contr->ctrl, cmsg->ApplId, skb);
#else
capi_ctr_handle_message(appl->contr->ctrl, cmsg->ApplId, skb);
#endif
free:
cmsg_free(cmsg);
}
void
SendCmsgAnswer2Application(Application_t *appl, _cmsg *cmsg, __u16 Info)
{
capi_cmsg_answer(cmsg);
cmsg->Info = Info;
SendCmsg2Application(appl, cmsg);
}
void
AnswerMessage2Application(Application_t *appl, struct sk_buff *skb, __u16 Info)
{
_cmsg *cmsg;
CMSG_ALLOC(cmsg);
capi_message2cmsg(cmsg, skb->data);
SendCmsgAnswer2Application(appl, cmsg, Info);
}
#define AVM_MANUFACTURER_ID 0x214D5641 /* "AVM!" */
#define CLASS_AVM 0x00
#define FUNCTION_AVM_D2_TRACE 0x01
struct AVMD2Trace {
__u8 Length;
__u8 data[4];
};
void applManufacturerReqAVM(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
{
struct AVMD2Trace *at;
if (cmsg->Class != CLASS_AVM) {
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown class %#x\n", cmsg->Class);
cmsg_free(cmsg);
dev_kfree_skb(skb);
return;
}
switch (cmsg->Function) {
case FUNCTION_AVM_D2_TRACE:
at = (struct AVMD2Trace *)cmsg->ManuData;
if (!at || at->Length != 4) {
int_error();
break;
}
if (memcmp(at->data, "\200\014\000\000", 4) == 0) {
test_and_set_bit(APPL_STATE_D2TRACE, &appl->state);
} else if (memcmp(at->data, "\000\000\000\000", 4) == 0) {
test_and_clear_bit(APPL_STATE_D2TRACE, &appl->state);
} else {
int_error();
}
break;
default:
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown function %#x\n", cmsg->Function);
}
cmsg_free(cmsg);
dev_kfree_skb(skb);
}
void applManufacturerReqmISDN(Application_t *appl, _cmsg *cmsg, struct sk_buff *skb)
{
AppPlci_t *aplci;
Ncci_t *ncci;
switch (cmsg->Class) {
case mISDN_MF_CLASS_HANDSET:
/* Note normally MANUFATURER messages are only defined for
* controller address we extent it here to PLCI/NCCI
*/
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (aplci) {
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_PLCI);
if (ncci) {
cmsg_free(cmsg);
ncciSendMessage(ncci, skb);
return;
}
}
SendCmsgAnswer2Application(appl, cmsg, CapiIllContrPlciNcci);
break;
default:
cmsg_free(cmsg);
break;
}
dev_kfree_skb(skb);
}
void
applManufacturerReq(Application_t *appl, struct sk_buff *skb)
{
_cmsg *cmsg;
if (skb->len < 16 + 8) {
dev_kfree_skb(skb);
return;
}
cmsg = cmsg_alloc();
if (!cmsg) {
int_error();
dev_kfree_skb(skb);
return;
}
capi_message2cmsg(cmsg, skb->data);
switch (cmsg->ManuID) {
case mISDN_MANUFACTURER_ID:
applManufacturerReqmISDN(appl, cmsg, skb);
break;
case AVM_MANUFACTURER_ID:
applManufacturerReqAVM(appl, cmsg, skb);
break;
default:
applDebug(appl, CAPI_DBG_APPL_INFO, "CAPI: unknown ManuID %#x\n", cmsg->ManuID);
cmsg_free(cmsg);
dev_kfree_skb(skb);
break;
}
}
void applD2Trace(Application_t *appl, u_char *buf, int len)
{
_cmsg *cmsg;
__u8 manuData[255];
if (!test_bit(APPL_STATE_D2TRACE, &appl->state))
return;
CMSG_ALLOC(cmsg);
capi_cmsg_header(cmsg, appl->ApplId, CAPI_MANUFACTURER, CAPI_IND,
appl->MsgId++, appl->contr->addr);
cmsg->ManuID = AVM_MANUFACTURER_ID;
cmsg->Class = CLASS_AVM;
cmsg->Function = FUNCTION_AVM_D2_TRACE;
cmsg->ManuData = (_cstruct) &manuData;
manuData[0] = 2 + len; // length
manuData[1] = 0x80;
manuData[2] = 0x0f;
memcpy(&manuData[3], buf, len);
SendCmsg2Application(appl, cmsg);
}
void
free_Application(void)
{
struct list_head *item, *next;
int n = 0;
if (list_empty(&garbage_applications)) {
printk(KERN_DEBUG "%s: no garbage\n", __FUNCTION__);
return;
}
list_for_each_safe(item, next, &garbage_applications) {
ApplicationDestr((Application_t *)item, 4);
n++;
}
printk(KERN_WARNING"%s: %d garbage items\n", __FUNCTION__, n);
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/arcofi.c 0000644 0000000 0000050 00000006747 11135651701 020013 0 ustar root src /* $Id: arcofi.c,v 1.7 2006/03/06 12:52:07 keil Exp $
*
* arcofi.c Ansteuerung ARCOFI 2165
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include "channel.h"
#include "layer1.h"
#include "isac.h"
#include "arcofi.h"
#include "debug.h"
#include "helper.h"
#define ARCOFI_TIMER_VALUE 20
static void
add_arcofi_timer(channel_t *dch) {
isac_chip_t *isac = dch->hw;
if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
init_timer(&isac->arcofitimer);
isac->arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ)/1000);
add_timer(&isac->arcofitimer);
}
static void
send_arcofi(channel_t *dch) {
u_char val;
isac_chip_t *isac = dch->hw;
add_arcofi_timer(dch);
isac->mon_txp = 0;
isac->mon_txc = isac->arcofi_list->len;
memcpy(isac->mon_tx, isac->arcofi_list->msg, isac->mon_txc);
switch(isac->arcofi_bc) {
case 0: break;
case 1: isac->mon_tx[1] |= 0x40;
break;
default: break;
}
isac->mocr &= 0x0f;
isac->mocr |= 0xa0;
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
val = dch->read_reg(dch->inst.privat, ISAC_MOSR);
dch->write_reg(dch->inst.privat, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
isac->mocr |= 0x10;
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
}
int
arcofi_fsm(channel_t *dch, int event, void *data) {
isac_chip_t *isac = dch->hw;
if (dch->debug & L1_DEB_MONITOR) {
mISDN_debugprint(&dch->inst, "arcofi state %d event %d", isac->arcofi_state, event);
}
if (event == ARCOFI_TIMEOUT) {
isac->arcofi_state = ARCOFI_NOP;
test_and_set_bit(FLG_ARCOFI_ERROR, &dch->Flags);
wake_up(&isac->arcofi_wait);
return(1);
}
switch (isac->arcofi_state) {
case ARCOFI_NOP:
if (event == ARCOFI_START) {
isac->arcofi_list = data;
isac->arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(dch);
}
break;
case ARCOFI_TRANSMIT:
if (event == ARCOFI_TX_END) {
if (isac->arcofi_list->receive) {
add_arcofi_timer(dch);
isac->arcofi_state = ARCOFI_RECEIVE;
} else {
if (isac->arcofi_list->next) {
isac->arcofi_list =
isac->arcofi_list->next;
send_arcofi(dch);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
isac->arcofi_state = ARCOFI_NOP;
wake_up(&isac->arcofi_wait);
}
}
}
break;
case ARCOFI_RECEIVE:
if (event == ARCOFI_RX_END) {
struct sk_buff *skb = data;
// FIXME handle message
if (skb)
kfree_skb(skb);
else
int_error();
if (isac->arcofi_list->next) {
isac->arcofi_list =
isac->arcofi_list->next;
isac->arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(dch);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
isac->arcofi_state = ARCOFI_NOP;
wake_up(&isac->arcofi_wait);
}
}
break;
default:
mISDN_debugprint(&dch->inst, "Arcofi unknown state %x", isac->arcofi_state);
return(2);
}
return(0);
}
static void
arcofi_timer(channel_t *dch) {
arcofi_fsm(dch, ARCOFI_TIMEOUT, NULL);
}
void
clear_arcofi(channel_t *dch) {
isac_chip_t *isac = dch->hw;
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
}
void
init_arcofi(channel_t *dch) {
isac_chip_t *isac = dch->hw;
isac->arcofitimer.function = (void *) arcofi_timer;
isac->arcofitimer.data = (long) dch;
init_timer(&isac->arcofitimer);
dch->type |= ISAC_TYPE_ARCOFI;
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/arcofi.h 0000644 0000000 0000050 00000001211 11110524073 017767 0 ustar root src /* $Id: arcofi.h,v 1.2 2006/03/06 12:52:07 keil Exp $
*
* arcofi.h Ansteuerung ARCOFI 2165
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#define ARCOFI_USE 1
/* states */
#define ARCOFI_NOP 0
#define ARCOFI_TRANSMIT 1
#define ARCOFI_RECEIVE 2
/* events */
#define ARCOFI_START 1
#define ARCOFI_TX_END 2
#define ARCOFI_RX_END 3
#define ARCOFI_TIMEOUT 4
struct arcofi_msg {
struct arcofi_msg *next;
u_char receive;
u_char len;
u_char msg[10];
};
extern int arcofi_fsm(channel_t *, int, void *);
extern void init_arcofi(channel_t *);
extern void clear_arcofi(channel_t *);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1.c 0000644 0000000 0000050 00000005712 11135651701 017401 0 ustar root src /* $Id: asn1.c,v 1.1 2003/11/09 09:12:28 keil Exp $
*
*/
#include "asn1.h"
int ParseTag(u_char *p, u_char *end, int *tag)
{
*tag = *p;
return 1;
}
int ParseLen(u_char *p, u_char *end, int *len)
{
int l, i;
if (*p == 0x80) { // indefinite
*len = -1;
return 1;
}
if (!(*p & 0x80)) { // one byte
*len = *p;
return 1;
}
*len = 0;
l = *p & ~0x80;
p++;
for (i = 0; i < l; i++) {
*len = (*len << 8) + *p;
p++;
}
return l+1;
}
int
ParseASN1(u_char *p, u_char *end, int level)
{
int tag, len;
int ret;
int j;
u_char *tag_end, *beg;
beg = p;
CallASN1(ret, p, end, ParseTag(p, end, &tag));
CallASN1(ret, p, end, ParseLen(p, end, &len));
#ifdef ASN1_DEBUG
for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
print_asn1msg(PRT_DEBUG_DECODE, "TAG 0x%02x LEN %3d\n", tag, len);
#endif
if (tag & ASN1_TAG_CONSTRUCTED) {
if (len == -1) { // indefinite
while (*p) {
CallASN1(ret, p, end, ParseASN1(p, end, level + 1));
}
p++;
if (*p)
return -1;
p++;
} else {
tag_end = p + len;
while (p < tag_end) {
CallASN1(ret, p, end, ParseASN1(p, end, level +1));
}
}
} else {
for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
while (len--) {
print_asn1msg(PRT_DEBUG_DECODE, "%02x ", *p);
p++;
}
print_asn1msg(PRT_DEBUG_DECODE, "\n");
}
for (j = 0; j < level*5; j++) print_asn1msg(PRT_DEBUG_DECODE, " ");
print_asn1msg(PRT_DEBUG_DECODE, "END (%d)\n", p - beg - 2);
return p - beg;
}
#if 0
#if 0
u_char data[] = {"\xA2\x03\x02\x01\xA3"};
#endif
#if 0 // ActNotDiv
u_char data[] = {"\xA1\x2C\x02\x01\x7E\x02\x01\x09\x30\x24\x0A"
"\x01\x02\x0A\x01\x03\x30\x0C\x80\x0A\x30\x31"
"\x33\x30\x31\x34\x34\x37\x37\x30\xA1\x0E\x0A"
"\x01\x02\x12\x09\x32\x31\x31\x33\x34\x31\x38\x33\x30"};
#endif
#if 0 // ActDiv
u_char data[] = {"\xA1\x24\x02\x01\xA1\x02\x01\x07\x30\x1C\x0A"
"\x01\x02\x0A\x01\x01\x30\x0C\x80\x0A\x30"
"\x31\x33\x30\x31\x34\x34\x37\x37\x30\x80"
"\x06\x33\x34\x31\x38\x33\x30"};
#endif
#if 0 // DeactNotDiv
u_char data[] = {"\xA1\x1E\x02\x01\x08\x02\x01\x0A\x30\x16\x0A"
"\x01\x02\x0A\x01\x03\xA1\x0E\x0A\x01\x02\x12"
"\x09\x32\x31\x31\x33\x34\x31\x38\x33\x30"};
#endif
#if 1 // DeactDiv
u_char data[] = {"\xA1\x16\x02\x01\xB1\x02\x01\x08\x30\x0E\x0A"
"\x01\x02\x0A\x01\x01\x80\x06\x33\x34\x31\x38\x33\x30"};
#endif
#if 0 // AOCE, 0 Einheiten
u_char data[] = {"\xA1\x15\x02\x02\x00\xDC\x02\x01\x24\x30\x0C"
"\x30\x0A\xA1\x05\x30\x03\x02\x01\x00\x82\x01\x00"};
#endif
#if 0 // AOCE, 1 Einheit
u_char data[] = {"\xA1\x15\x02\x02\x00\xBC\x02\x01\x24\x30\x0C\x30"
"\x0A\xA1\x05\x30\x03\x02\x01\x01\x82\x01\x00"};
#endif
#if 0 // AOCD currency
u_char data[] = {"\xA1\x1A\x02\x02\x1C\x65\x02\x01\x21\x30\x11\xA1\x0C\x81\x02\x44\x4D\xA2\x06\x81\x01\x18\x82\x01\x01\x82\x01\x00"};
#endif
u_char *end = data + 47;
#include "asn1_component.h"
void
main()
{
struct Aoc chan;
#ifdef ASN1_DEBUG
ParseASN1(data, end, 0);
#endif
ParseComponent(&chan, data, end);
}
#endif
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1.h 0000644 0000000 0000050 00000015533 11135651701 017410 0 ustar root src /* $Id: asn1.h,v 1.3 2006/03/06 12:52:07 keil Exp $
*
*/
#include
#include "helper.h"
#ifndef __ASN1_H__
#define __ASN1_H__
typedef enum {
invoke = 1,
returnResult = 2,
returnError = 3,
reject = 4,
} asn1Component;
typedef enum {
GeneralP = 0,
InvokeP = 1,
ReturnResultP= 2,
ReturnErrorP = 3,
} asn1Problem;
struct PublicPartyNumber {
int publicTypeOfNumber;
char numberDigits[30];
};
struct PartyNumber {
int type;
union {
char unknown[30];
struct PublicPartyNumber publicPartyNumber;
} p;
};
struct Address {
struct PartyNumber partyNumber;
char partySubaddress[30];
};
struct ServedUserNr {
int all;
struct PartyNumber partyNumber;
};
struct ActDivNotification {
int procedure;
int basicService;
struct ServedUserNr servedUserNr;
struct Address address;
};
struct DeactDivNotification {
int procedure;
int basicService;
struct ServedUserNr servedUserNr;
};
struct ServedUserNumberList {
struct PartyNumber partyNumber[10];
};
struct IntResult {
struct ServedUserNr servedUserNr;
int procedure;
int basicService;
struct Address address;
};
struct IntResultList {
struct IntResult intResult[10];
};
struct asn1Invoke {
__u16 invokeId;
__u16 operationValue;
union {
struct ActDivNotification actNot;
struct DeactDivNotification deactNot;
} o;
};
struct asn1ReturnResult {
__u16 invokeId;
union {
struct ServedUserNumberList list;
struct IntResultList resultList;
} o;
};
struct asn1ReturnError {
__u16 invokeId;
__u16 errorValue;
};
struct asn1Reject {
int invokeId;
asn1Problem problem;
__u16 problemValue;
};
struct asn1_parm {
asn1Component comp;
union {
struct asn1Invoke inv;
struct asn1ReturnResult retResult;
struct asn1ReturnError retError;
struct asn1Reject reject;
} u;
};
#undef ASN1_DEBUG
// #define ASN1_DEBUG
#ifdef ASN1_DEBUG
#define print_asn1msg(dummy, fmt, args...) printk(KERN_DEBUG fmt, ## args)
#else
#define print_asn1msg(dummy, fmt, args...)
#endif
int ParseASN1(u_char *p, u_char *end, int level);
int ParseTag(u_char *p, u_char *end, int *tag);
int ParseLen(u_char *p, u_char *end, int *len);
#define ASN1_TAG_BOOLEAN (0x01) // is that true?
#define ASN1_TAG_INTEGER (0x02)
#define ASN1_TAG_BIT_STRING (0x03)
#define ASN1_TAG_OCTET_STRING (0x04)
#define ASN1_TAG_NULL (0x05)
#define ASN1_TAG_OBJECT_IDENTIFIER (0x06)
#define ASN1_TAG_ENUM (0x0a)
#define ASN1_TAG_SEQUENCE (0x30)
#define ASN1_TAG_SET (0x31)
#define ASN1_TAG_NUMERIC_STRING (0x12)
#define ASN1_TAG_PRINTABLE_STRING (0x13)
#define ASN1_TAG_IA5_STRING (0x16)
#define ASN1_TAG_UTC_TIME (0x17)
#define ASN1_TAG_CONSTRUCTED (0x20)
#define ASN1_TAG_CONTEXT_SPECIFIC (0x80)
#define ASN1_TAG_EXPLICIT (0x100)
#define ASN1_TAG_OPT (0x200)
#define ASN1_NOT_TAGGED (0x400)
#define CallASN1(ret, p, end, todo) do { \
ret = todo; \
if (ret < 0) { \
int_error(); \
return -1; \
} \
p += ret; \
} while (0)
#define INIT \
int tag, len; \
int ret; \
u_char *beg; \
\
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", __FUNCTION__); \
beg = p; \
CallASN1(ret, p, end, ParseTag(p, end, &tag)); \
CallASN1(ret, p, end, ParseLen(p, end, &len)); \
if (len >= 0) { \
if (p + len > end) \
return -1; \
end = p + len; \
}
#define XSEQUENCE_1(todo, act_tag, the_tag, arg1) do { \
if (p < end) { \
if (((the_tag) &~ ASN1_TAG_OPT) == ASN1_NOT_TAGGED) { \
if (((u_char)act_tag == *p) || ((act_tag) == ASN1_NOT_TAGGED)) { \
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
} else { \
if (!((the_tag) & ASN1_TAG_OPT)) { \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 1 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} \
} \
} else { \
if ((the_tag) & ASN1_TAG_EXPLICIT) { \
if ((u_char)(((the_tag) & 0xff) | (ASN1_TAG_CONTEXT_SPECIFIC | ASN1_TAG_CONSTRUCTED)) == *p) { \
int xtag, xlen; \
CallASN1(ret, p, end, ParseTag(p, end, &xtag)); \
CallASN1(ret, p, end, ParseLen(p, end, &xlen)); \
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
} else { \
if (!(the_tag) & ASN1_TAG_OPT) { \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 2 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} \
} \
} else { \
if ((u_char)(((the_tag) & 0xff) | (ASN1_TAG_CONTEXT_SPECIFIC | (act_tag & ASN1_TAG_CONSTRUCTED))) == *p) { \
CallASN1(ret, p, end, todo(pc, p, end, arg1)); \
} else { \
if (!(the_tag) & ASN1_TAG_OPT) { \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 3 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} \
} \
} \
} \
} else { \
if (!(the_tag) & ASN1_TAG_OPT) { \
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 4 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} \
} \
} while (0)
#define XSEQUENCE_OPT_1(todo, act_tag, the_tag, arg1) \
XSEQUENCE_1(todo, act_tag, (the_tag | ASN1_TAG_OPT), arg1)
#define XSEQUENCE(todo, act_tag, the_tag) XSEQUENCE_1(todo, act_tag, the_tag, -1)
#define XSEQUENCE_OPT(todo, act_tag, the_tag) XSEQUENCE_OPT_1(todo, act_tag, the_tag, -1)
#define XCHOICE_1(todo, act_tag, the_tag, arg1) \
if (act_tag == ASN1_NOT_TAGGED) { \
return todo(pc, beg, end, arg1); \
} \
if (the_tag == ASN1_NOT_TAGGED) { \
if (act_tag == tag) { \
return todo(pc, beg, end, arg1); \
} \
} else { \
if ((the_tag | (0x80 | (act_tag & 0x20))) == tag) { \
return todo(pc, beg, end, arg1); \
} \
}
#define XCHOICE(todo, act_tag, the_tag) XCHOICE_1(todo, act_tag, the_tag, -1)
#define XCHOICE_DEFAULT do {\
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 5 %s:%d\n", __FUNCTION__, __LINE__); \
return -1; \
} while (0)
#define CHECK_P do { \
if (p >= end) \
return -1; \
} while (0)
#endif
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_address.c 0000644 0000000 0000050 00000015543 11135651701 021111 0 ustar root src /* $Id: asn1_address.c,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
#include "asn1.h"
#include "asn1_generic.h"
#include "asn1_address.h"
void buildnumber(char *num, int oc3, int oc3a, char *result, int version,
int *provider, int *sondernummer, int *intern, int *local,
int dir, int who);
// ======================================================================
// Address Types EN 300 196-1 D.3
int ParsePresentationRestricted(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
int ret;
ret = ParseNull(pc, p, end, -1);
if (ret < 0)
return ret;
strcpy(str, "(presentation restricted)");
return ret;
}
int ParseNotAvailInterworking(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
int ret;
ret = ParseNull(pc, p, end, -1);
if (ret < 0)
return ret;
strcpy(str, "(not available)");
return ret;
}
int ParsePresentedAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
XCHOICE_1(ParseAddressScreened, ASN1_TAG_SEQUENCE, 0, str);
XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
XCHOICE_1(ParseAddressScreened, ASN1_TAG_NULL, 3, str);
XCHOICE_DEFAULT;
}
int ParsePresentedNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
XCHOICE_1(ParseNumberScreened, ASN1_TAG_SEQUENCE, 0, str);
XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
XCHOICE_1(ParseNumberScreened, ASN1_TAG_NULL, 3, str);
XCHOICE_DEFAULT;
}
int ParsePresentedNumberUnscreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
struct PartyNumber partyNumber;
INIT;
XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 0, &partyNumber); // FIXME EXP
XCHOICE_1(ParsePresentationRestricted, ASN1_TAG_NULL, 1, str);
XCHOICE_1(ParseNotAvailInterworking, ASN1_TAG_NULL, 2, str);
XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 3, &partyNumber); // FIXME EXP
XCHOICE_DEFAULT;
}
int ParseNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
struct PartyNumber partyNumber;
char screeningIndicator[30];
INIT;
XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &partyNumber);
XSEQUENCE_1(ParseScreeningIndicator, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, screeningIndicator);
// str += sprintf(str, "%s", partyNumber);
return p - beg;
}
int ParseAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
struct PartyNumber partyNumber;
char partySubaddress[30] = { 0, };
char screeningIndicator[30];
INIT;
XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &partyNumber);
XSEQUENCE_1(ParseScreeningIndicator, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, screeningIndicator);
XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, partySubaddress);
// str += sprintf(str, "%s", partyNumber);
if (strlen(partySubaddress))
str += sprintf(str, ".%s", partySubaddress);
return p - beg;
}
int ParseAddress(struct asn1_parm *pc, u_char *p, u_char *end, struct Address *address)
{
INIT;
address->partySubaddress[0] = 0;
XSEQUENCE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &address->partyNumber);
XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, address->partySubaddress);
return p - beg;
}
int ParsePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PartyNumber *partyNumber)
{
INIT;
partyNumber->type = 0;
XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 0, partyNumber->p.unknown); // unknownPartyNumber
partyNumber->type = 1;
XCHOICE_1(ParsePublicPartyNumber, ASN1_TAG_SEQUENCE, 1, &partyNumber->p.publicPartyNumber);
#if 0
XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 3, str); // dataPartyNumber
XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 4, str); // telexPartyNumber
XCHOICE_1(ParsePrivatePartyNumber, ASN1_TAG_SEQUENCE, 5, str);
XCHOICE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, 8, str); // nationalStandardPartyNumber
#endif
XCHOICE_DEFAULT;
}
int ParsePublicPartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PublicPartyNumber *publicPartyNumber)
{
INIT;
XSEQUENCE_1(ParsePublicTypeOfNumber, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &publicPartyNumber->publicTypeOfNumber);
XSEQUENCE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, ASN1_NOT_TAGGED, publicPartyNumber->numberDigits);
return p - beg;
}
#if 0
int ParsePrivatePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
int privateTypeOfNumber;
char numberDigits[20];
INIT;
XSEQUENCE_1(ParsePrivateTypeOfNumber, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &privateTypeOfNumber);
XSEQUENCE_1(ParseNumberDigits, ASN1_TAG_NUMERIC_STRING, ASN1_NOT_TAGGED, numberDigits);
switch (privateTypeOfNumber) {
case 0: str += sprintf(str, "(unknown)"); break;
case 1: str += sprintf(str, "(regional2)"); break;
case 2: str += sprintf(str, "(regional1)"); break;
case 3: str += sprintf(str, "(ptn)"); break;
case 4: str += sprintf(str, "(local)"); break;
case 6: str += sprintf(str, "(abbrev)"); break;
}
str += sprintf(str, numberDigits);
return p - beg;
}
#endif
int ParsePublicTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *publicTypeOfNumber)
{
return ParseEnum(pc, p, end, publicTypeOfNumber);
}
#if 0
int ParsePrivateTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *privateTypeOfNumber)
{
return ParseEnum(pc, p, end, privateTypeOfNumber);
}
#endif
int ParsePartySubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
XCHOICE_1(ParseUserSpecifiedSubaddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, str);
XCHOICE_1(ParseNSAPSubaddress, ASN1_TAG_OCTET_STRING, ASN1_NOT_TAGGED, str);
XCHOICE_DEFAULT;
}
int ParseUserSpecifiedSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
int oddCountIndicator;
INIT;
XSEQUENCE_1(ParseSubaddressInformation, ASN1_TAG_OCTET_STRING, ASN1_NOT_TAGGED, str);
XSEQUENCE_OPT_1(ParseBoolean, ASN1_TAG_BOOLEAN, ASN1_NOT_TAGGED, &oddCountIndicator);
return p - beg;
}
int ParseNSAPSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
return ParseOctetString(pc, p, end, str);
}
int ParseSubaddressInformation(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
return ParseOctetString(pc, p, end, str);
}
int ParseScreeningIndicator(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
int ret;
int screeningIndicator;
ret = ParseEnum(pc, p, end, &screeningIndicator);
if (ret < 0)
return ret;
switch (screeningIndicator) {
case 0: sprintf(str, "user provided, not screened"); break;
case 1: sprintf(str, "user provided, passed"); break;
case 2: sprintf(str, "user provided, failed"); break;
case 3: sprintf(str, "network provided"); break;
default: sprintf(str, "(%d)", screeningIndicator); break;
}
return ret;
}
int ParseNumberDigits(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
return ParseNumericString(pc, p, end, str);
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_address.h 0000644 0000000 0000050 00000003300 11135651701 021102 0 ustar root src /* $Id: asn1_address.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
// ======================================================================
// Address Types EN 300 196-1 D.3
int ParsePresentedAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParsePresentedNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParsePresentedNumberUnscreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseAddressScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseNumberScreened(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseAddress(struct asn1_parm *pc, u_char *p, u_char *end, struct Address *address);
int ParsePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PartyNumber *partyNumber);
int ParsePublicPartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, struct PublicPartyNumber *publicPartyNumber);
int ParsePrivatePartyNumber(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParsePublicTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *publicTypeOfNumber);
int ParsePrivateTypeOfNumber(struct asn1_parm *pc, u_char *p, u_char *end, int *privateTypeOfNumber);
int ParsePartySubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseUserSpecifiedSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseNSAPSubaddress(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseSubaddressInformation(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseScreeningIndicator(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseNumberDigits(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_aoc.c 0000644 0000000 0000050 00000017112 11135651701 020220 0 ustar root src /* $Id: asn1_aoc.c,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
#include "asn1.h"
#include "asn1_generic.h"
#if 0
#include "asn1_address.h"
#endif
#include "asn1_aoc.h"
// ======================================================================
// AOC EN 300 182-1 V1.3.3
#if 0
// AOCDCurrency
int
ParseAOCDCurrency(struct Channel *chanp, u_char *p, u_char *end, int dummy)
{
INIT;
XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
XCHOICE(ParseAOCDCurrencyInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
XCHOICE_DEFAULT;
}
#endif
// AOCDChargingUnit
int
ParseAOCDChargingUnit(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
XCHOICE(ParseAOCDChargingUnitInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
XCHOICE_DEFAULT;
}
#if 0
// AOCECurrency
int
ParseAOCECurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
XCHOICE(ParseAOCECurrencyInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
XCHOICE_DEFAULT;
}
#endif
// AOCEChargingUnit
int
ParseAOCEChargingUnit(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // chargeNotAvail
XCHOICE(ParseAOCEChargingUnitInfo, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
XCHOICE_DEFAULT;
}
#if 0
// AOCDCurrencyInfo
int
ParseAOCDSpecificCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int typeOfChargingInfo;
int billingId;
INIT;
XSEQUENCE(ParseRecordedCurrency, ASN1_TAG_SEQUENCE, 1);
XSEQUENCE_1(ParseTypeOfChargingInfo, ASN1_TAG_ENUM, 2, &typeOfChargingInfo);
XSEQUENCE_OPT_1(ParseAOCDBillingId, ASN1_TAG_ENUM, 3, &billingId);
return p - beg;
}
int
ParseAOCDCurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XCHOICE(ParseAOCDSpecificCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
XCHOICE_DEFAULT;
}
#endif
// AOCDChargingUnitInfo
int
ParseAOCDSpecificChargingUnits(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int recordedUnits;
int typeOfChargingInfo;
int billingId;
INIT;
XSEQUENCE_1(ParseRecordedUnitsList, ASN1_TAG_SEQUENCE, 1, &recordedUnits);
XSEQUENCE_1(ParseTypeOfChargingInfo, ASN1_TAG_ENUM, 2, &typeOfChargingInfo);
XSEQUENCE_OPT_1(ParseAOCDBillingId, ASN1_TAG_ENUM, 3, &billingId);
// p_L3L4(pc, CC_CHARGE | INDICATION, &recordedUnits);
return p - beg;
}
int
ParseAOCDChargingUnitInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XCHOICE(ParseAOCDSpecificChargingUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
XCHOICE_DEFAULT;
}
#if 0
// RecordedCurrency
int
ParseRecordedCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
char currency[11];
INIT;
XSEQUENCE_1(ParseCurrency, ASN1_TAG_IA5_STRING, 1, currency);
XSEQUENCE(ParseAmount, ASN1_TAG_SEQUENCE, 2);
return p - beg;
}
#endif
// RecordedUnitsList
int
ParseRecordedUnitsList(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
{
int i;
INIT;
XSEQUENCE_1(ParseRecordedUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, recordedUnits);
for (i = 0; i < 31; i++)
XSEQUENCE_OPT_1(ParseRecordedUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, recordedUnits);
return p - beg;
}
// TypeOfChargingInfo
int
ParseTypeOfChargingInfo(struct asn1_parm *pc, u_char *p, u_char *end, int *typeOfChargingInfo)
{
return ParseEnum(pc, p, end, typeOfChargingInfo);
}
// RecordedUnits
int
ParseRecordedUnitsChoice(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
{
INIT;
XCHOICE_1(ParseNumberOfUnits, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, recordedUnits);
XCHOICE(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED); // not available
XCHOICE_DEFAULT;
}
int
ParseRecordedUnits(struct asn1_parm *pc, u_char *p, u_char *end, int *recordedUnits)
{
int typeOfUnit;
INIT;
XSEQUENCE_1(ParseRecordedUnitsChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, recordedUnits);
XSEQUENCE_OPT_1(ParseTypeOfUnit, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &typeOfUnit);
return p - beg;
}
// AOCDBillingId
int
ParseAOCDBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId)
{
return ParseEnum(pc, p, end, billingId);
}
#if 0
// AOCECurrencyInfo
int
ParseAOCESpecificCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int billingId;
INIT;
XSEQUENCE(ParseRecordedCurrency, ASN1_TAG_SEQUENCE, 1);
XSEQUENCE_OPT_1(ParseAOCEBillingId, ASN1_TAG_ENUM, 2, &billingId);
return p - beg;
}
int
ParseAOCECurrencyInfoChoice(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XCHOICE(ParseAOCESpecificCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
XCHOICE_DEFAULT;
}
int
ParseAOCECurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XSEQUENCE(ParseAOCECurrencyInfoChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
XSEQUENCE_OPT(ParseChargingAssociation, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
XCHOICE_DEFAULT;
}
#endif
// AOCEChargingUnitInfo
int
ParseAOCESpecificChargingUnits(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int recordedUnits;
int billingId;
INIT;
XSEQUENCE_1(ParseRecordedUnitsList, ASN1_TAG_SEQUENCE, 1, &recordedUnits);
XSEQUENCE_OPT_1(ParseAOCEBillingId, ASN1_TAG_ENUM, 2, &billingId);
// p_L3L4(pc, CC_CHARGE | INDICATION, &recordedUnits);
return p - beg;
}
int
ParseAOCEChargingUnitInfoChoice(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XCHOICE(ParseAOCESpecificChargingUnits, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
XCHOICE(ParseNull, ASN1_TAG_NULL, 1); // freeOfCharge
XCHOICE_DEFAULT;
}
int
ParseAOCEChargingUnitInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
XSEQUENCE(ParseAOCEChargingUnitInfoChoice, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
XSEQUENCE_OPT(ParseChargingAssociation, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED);
return p - beg;
}
// AOCEBillingId
int
ParseAOCEBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId)
{
return ParseEnum(pc, p, end, billingId);
}
#if 0
// Currency
int
ParseCurrency(struct asn1_parm *pc, u_char *p, u_char *end, char *currency)
{
return ParseIA5String(chanp, p, end, currency);
}
// Amount
int
ParseAmount(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int amount;
int multiplier;
INIT;
XSEQUENCE_1(ParseCurrencyAmount, ASN1_TAG_INTEGER, 1, &amount);
XSEQUENCE_1(ParseMultiplier, ASN1_TAG_INTEGER, 2, &multiplier);
return p - beg;
}
// CurrencyAmount
int
ParseCurrencyAmount(struct asn1_parm *pc, u_char *p, u_char *end, int *currencyAmount)
{
return ParseInteger(chanp, p, end, currencyAmount);
}
// Multiplier
int
ParseMultiplier(struct asn1_parm *pc, u_char *p, u_char *end, int *multiplier)
{
return ParseEnum(chanp, p, end, multiplier);
}
#endif
// TypeOfUnit
int
ParseTypeOfUnit(struct asn1_parm *pc, u_char *p, u_char *end, int *typeOfUnit)
{
return ParseInteger(pc, p, end, typeOfUnit);
}
// NumberOfUnits
int
ParseNumberOfUnits(struct asn1_parm *pc, u_char *p, u_char *end, int *numberOfUnits)
{
return ParseInteger(pc, p, end, numberOfUnits);
}
// Charging Association
int
ParseChargingAssociation(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
// char partyNumber[30];
INIT;
// XCHOICE_1(ParsePartyNumber, ASN1_TAG_SEQUENCE, 0, partyNumber);
XCHOICE(ParseChargeIdentifier, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED);
XCHOICE_DEFAULT;
}
// ChargeIdentifier
int
ParseChargeIdentifier(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int chargeIdentifier;
return ParseInteger(pc, p, end, &chargeIdentifier);
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_aoc.h 0000644 0000000 0000050 00000003766 11135651701 020237 0 ustar root src /* $Id: asn1_aoc.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
// ======================================================================
// AOC EN 300 182-1 V1.3.3
int ParseAOCDCurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
int ParseAOCDChargingUnit(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
int ParseAOCECurrency(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
int ParseAOCEChargingUnit(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
int ParseAOCDCurrencyInfo(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
int ParseAOCDChargingUnitInfo(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
int ParseRecordedCurrency(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
int ParseRecordedUnitsList(struct asn1_parm *pc,u_char *p, u_char *end, int *recordedUnits);
int ParseTypeOfChargingInfo(struct asn1_parm *pc,u_char *p, u_char *end, int *typeOfChargingInfo);
int ParseRecordedUnits(struct asn1_parm *pc,u_char *p, u_char *end, int *recordedUnits);
int ParseAOCDBillingId(struct asn1_parm *pc, u_char *p, u_char *end, int *billingId);
int ParseAOCECurrencyInfo(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
int ParseAOCEChargingUnitInfo(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
int ParseAOCEBillingId(struct asn1_parm *pc,u_char *p, u_char *end, int *billingId);
int ParseCurrency(struct asn1_parm *pc,u_char *p, u_char *end, char *currency);
int ParseAmount(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
int ParseCurrencyAmount(struct asn1_parm *pc,u_char *p, u_char *end, int *currencyAmount);
int ParseMultiplier(struct asn1_parm *pc,u_char *p, u_char *end, int *multiplier);
int ParseTypeOfUnit(struct asn1_parm *pc,u_char *p, u_char *end, int *typeOfUnit);
int ParseNumberOfUnits(struct asn1_parm *pc,u_char *p, u_char *end, int *numberOfUnits);
int ParseChargingAssociation(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
int ParseChargeIdentifier(struct asn1_parm *pc,u_char *p, u_char *end, int dummy);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_basic_service.c 0000644 0000000 0000050 00000000627 11135651701 022262 0 ustar root src /* $Id: asn1_basic_service.c,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
#include "asn1.h"
#include "asn1_generic.h"
#include "asn1_basic_service.h"
// ======================================================================
// Basic Service Elements EN 300 196-1 D.6
int ParseBasicService(struct asn1_parm *pc, u_char *p, u_char *end, int *basicService)
{
return ParseEnum(pc, p, end, basicService);
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_basic_service.h 0000644 0000000 0000050 00000000432 11135651701 022261 0 ustar root src /* $Id: asn1_basic_service.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
// ======================================================================
// Basic Service Elements EN 300 196-1 D.6
int ParseBasicService(struct asn1_parm *pc, u_char *p, u_char *end, int *basicService);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_comp.c 0000644 0000000 0000050 00000016137 11135651701 020422 0 ustar root src /* $Id: asn1_comp.c,v 1.3 2006/11/14 12:17:02 crich Exp $
*
*/
#include "asn1.h"
#include "asn1_comp.h"
#include "asn1_generic.h"
#include "asn1_aoc.h"
#include "asn1_diversion.h"
// ======================================================================
// Component EN 300 196-1 D.1
int
ParseInvokeId(struct asn1_parm *pc, u_char *p, u_char *end, int *invokeId)
{
return ParseInteger(pc, p, end, invokeId);
}
int
ParseErrorValue(struct asn1_parm *pc, u_char *p, u_char *end, int *errorValue)
{
return ParseInteger(pc, p, end, errorValue);
}
int
ParseOperationValue(struct asn1_parm *pc, u_char *p, u_char *end, int *operationValue)
{
return ParseInteger(pc, p, end, operationValue);
}
int
ParseInvokeComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int invokeId, operationValue;
INIT;
pc->comp = invoke;
XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
// XSEQUENCE_OPT(ParseLinkedId, ASN1_TAG_INTEGER, 0);
XSEQUENCE_1(ParseOperationValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &operationValue);
pc->u.inv.invokeId = invokeId;
pc->u.inv.operationValue = operationValue;
switch (operationValue) {
#if 0
case 7: XSEQUENCE(ParseARGActivationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
case 8: XSEQUENCE(ParseARGDeactivationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
#endif
case 9: XSEQUENCE_1(ParseARGActivationStatusNotificationDiv, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &pc->u.inv.o.actNot); break;
case 10: XSEQUENCE_1(ParseARGDeactivationStatusNotificationDiv, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &pc->u.inv.o.deactNot); break;
#if 0
case 11: XSEQUENCE(ParseARGInterrogationDiversion, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
case 12: XSEQUENCE(ParseARGDiversionInformation, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
case 17: XSEQUENCE(ParseARGInterrogateServedUserNumbers, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
// case 30: XSEQUENCE(ParseChargingRequest, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
// case 31: XSEQUENCE(ParseAOCSCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
// case 32: XSEQUENCE(ParseAOCSSpecialArr, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
case 33: XSEQUENCE(ParseAOCDCurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
case 34: XSEQUENCE(ParseAOCDChargingUnit, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
case 35: XSEQUENCE(ParseAOCECurrency, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
case 36: XSEQUENCE(ParseAOCEChargingUnit, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED); break;
#endif
default:
return -1;
}
return p - beg;
}
int
ParseReturnResultComponentSequence(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int operationValue;
INIT;
XSEQUENCE_1(ParseOperationValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &operationValue);
switch (operationValue) {
case 11: XSEQUENCE(ParseRESInterrogationDiversion, ASN1_TAG_SET, ASN1_NOT_TAGGED); break;
case 17: XSEQUENCE(ParseRESInterrogateServedUserNumbers, ASN1_TAG_SET, ASN1_NOT_TAGGED); break;
default: return -1;
}
return p - beg;
}
int
ParseReturnResultComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int invokeId;
INIT;
pc->comp = returnResult;
XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
XSEQUENCE_OPT(ParseReturnResultComponentSequence, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED);
pc->u.retResult.invokeId = invokeId;
return p - beg;
}
int
ParseReturnErrorComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int invokeId;
int errorValue;
char error[80];
INIT;
pc->comp = returnError;
XSEQUENCE_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
XSEQUENCE_1(ParseErrorValue, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &errorValue);
pc->u.retError.invokeId = invokeId;
pc->u.retError.errorValue = errorValue;
switch (errorValue) {
case 0: sprintf(error, "not subscribed"); break;
case 3: sprintf(error, "not available"); break;
case 4: sprintf(error, "not implemented"); break;
case 6: sprintf(error, "invalid served user nr"); break;
case 7: sprintf(error, "invalid call state"); break;
case 8: sprintf(error, "basic service not provided"); break;
case 9: sprintf(error, "not incoming call"); break;
case 10: sprintf(error, "supplementary service interaction not allowed"); break;
case 11: sprintf(error, "resource unavailable"); break;
case 12: sprintf(error, "invalid diverted-to nr"); break;
case 14: sprintf(error, "special service nr"); break;
case 15: sprintf(error, "diversion to served user nr"); break;
case 23: sprintf(error, "incoming call accepted"); break;
case 24: sprintf(error, "number of diversions exceeded"); break;
case 46: sprintf(error, "not activated"); break;
case 48: sprintf(error, "request already accepted"); break;
default: sprintf(error, "(%d)", errorValue); break;
}
print_asn1msg(PRT_DEBUG_DECODE, "ReturnError: %s\n", error);
return p - beg;
}
int
ParseProblemValue(struct asn1_parm *pc, u_char *p, u_char *end, asn1Problem prob)
{
INIT;
pc->u.reject.problem = prob;
print_asn1msg(PRT_DEBUG_DECODE, "ParseProblemValue: %d %d\n", prob, *p);
pc->u.reject.problemValue = *p++;
return p - beg;
}
int
ParseRejectProblem(struct asn1_parm *pc, u_char *p, u_char *end)
{
INIT;
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 0, GeneralP);
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 1, InvokeP);
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 2, ReturnResultP);
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 3, ReturnErrorP);
XCHOICE_DEFAULT;
}
int
ParseRejectComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int invokeId = -1;
int rval;
INIT;
pc->comp = reject;
XSEQUENCE_OPT_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
XSEQUENCE_OPT(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED);
print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: invokeId %d\n", invokeId);
pc->u.reject.invokeId = invokeId;
rval = ParseRejectProblem(pc, p, end);
print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: rval %d\n", rval);
if (rval > 0)
p += rval;
else
return(-1);
return p - beg;
}
int
ParseUnknownComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
//int invokeId;
INIT;
pc->comp = tag;
return end - beg;
}
int
ParseComponent(struct asn1_parm *pc, u_char *p, u_char *end)
{
INIT;
XCHOICE(ParseInvokeComponent, ASN1_TAG_SEQUENCE, 1);
XCHOICE(ParseReturnResultComponent, ASN1_TAG_SEQUENCE, 2);
XCHOICE(ParseReturnErrorComponent, ASN1_TAG_SEQUENCE, 3);
XCHOICE(ParseRejectComponent, ASN1_TAG_SEQUENCE, 4);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 5);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 6);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 7);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 8);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 9);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 10);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 11);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 12);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 13);
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 14);
XCHOICE_DEFAULT;
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_comp.h 0000644 0000000 0000050 00000001077 11135651701 020424 0 ustar root src /* $Id: asn1_comp.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
#include "asn1.h"
int ParseInvokeId(struct asn1_parm *parm, u_char *p, u_char *end, int *invokeId);
int ParseOperationValue(struct asn1_parm *parm, u_char *p, u_char *end, int *operationValue);
int ParseInvokeComponent(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
int ParseReturnResultComponent(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
int ParseComponent(struct asn1_parm *parm, u_char *p, u_char *end);
int XParseComponent(struct asn1_parm *parm, u_char *p, u_char *end);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_diversion.c 0000644 0000000 0000050 00000016452 11135651701 021466 0 ustar root src /* $Id: asn1_diversion.c,v 1.1 2003/11/09 09:12:28 keil Exp $
*
*/
#include "asn1.h"
#include "asn1_generic.h"
#include "asn1_address.h"
#include "asn1_basic_service.h"
#include "asn1_diversion.h"
// ======================================================================
// Diversion Supplementary Services ETS 300 207-1 Table 3
#if 0
int
ParseARGActivationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int procedure, basicService;
struct ServedUserNr servedUserNr;
struct Address address;
INIT;
XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &address);
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
return p - beg;
}
int
ParseARGDeactivationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int procedure, basicService;
struct ServedUserNr servedUserNr;
INIT;
XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
print_asn1msg(PRT_SHOWNUMBERS, "Deactivation Diversion %d (%d), \n",
procedure, basicService);
return p - beg;
}
#endif
int
ParseARGActivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct ActDivNotification *actNot)
{
INIT;
XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &actNot->procedure);
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &actNot->basicService);
XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &actNot->address);
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &actNot->servedUserNr);
return p - beg;
}
int
ParseARGDeactivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct DeactDivNotification *deactNot)
{
INIT;
XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &deactNot->procedure);
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &deactNot->basicService);
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &deactNot->servedUserNr);
return p - beg;
}
#if 0
int
ParseARGInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int procedure, basicService;
struct ServedUserNr servedUserNr;
INIT;
XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &procedure);
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr);
print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion %d (%d), \n",
procedure, basicService);
return p - beg;
}
#endif
int
ParseRESInterrogationDiversion(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
print_asn1msg(PRT_SHOWNUMBERS, "Interrogation Diversion Result\n");
return ParseIntResultList(pc, p, end, &pc->u.retResult.o.resultList);
}
#if 0
int
ParseARGInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers\n");
return 0;
}
#endif
int
ParseRESInterrogateServedUserNumbers(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
int ret;
ret = ParseServedUserNumberList(pc, p, end, &pc->u.retResult.o.list);
if (ret < 0)
return ret;
print_asn1msg(PRT_SHOWNUMBERS, "Interrogate Served User Numbers:\n");
return ret;
}
int
ParseARGDiversionInformation(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
char diversionReason[20];
int basicService;
char servedUserSubaddress[30];
char callingAddress[80];
char originalCalledNr[80];
char lastDivertingNr[80];
char lastDivertingReason[20];
INIT;
servedUserSubaddress[0] = 0;
callingAddress[0] = 0;
originalCalledNr[0] = 0;
lastDivertingNr[0] = 0;
lastDivertingReason[0] = 0;
XSEQUENCE_1(ParseDiversionReason, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, diversionReason);
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &basicService);
XSEQUENCE_OPT_1(ParsePartySubaddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, servedUserSubaddress);
XSEQUENCE_OPT_1(ParsePresentedAddressScreened, ASN1_NOT_TAGGED, 0 | ASN1_TAG_EXPLICIT, callingAddress);
XSEQUENCE_OPT_1(ParsePresentedNumberUnscreened, ASN1_NOT_TAGGED, 1 | ASN1_TAG_EXPLICIT, originalCalledNr);
XSEQUENCE_OPT_1(ParsePresentedNumberUnscreened, ASN1_NOT_TAGGED, 2 | ASN1_TAG_EXPLICIT, lastDivertingNr);
XSEQUENCE_OPT_1(ParseDiversionReason, ASN1_TAG_ENUM, 3 | ASN1_TAG_EXPLICIT, lastDivertingReason);
// XSEQUENCE_OPT_1(ParseQ931InformationElement, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, userInfo);
print_asn1msg(PRT_SHOWNUMBERS, "Diversion Information %s(%d) %s\n"
" callingAddress %s originalCalled Nr %s\n"
" lastDivertingNr %s lastDiverting Reason %s\n",
diversionReason, basicService, servedUserSubaddress, callingAddress,
originalCalledNr, lastDivertingNr, lastDivertingReason);
return p - beg;
}
int
ParseIntResultList(struct asn1_parm *pc, u_char *p, u_char *end, struct IntResultList *intResultList)
{
int i;
INIT;
for (i = 0; i < 10; i++) {
intResultList->intResult[i].basicService = -1;
XSEQUENCE_OPT_1(ParseIntResult, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED,
&intResultList->intResult[i] );
}
return p - beg;
}
int
ParseIntResult(struct asn1_parm *pc, u_char *p, u_char *end, struct IntResult *intResult)
{
INIT;
XSEQUENCE_1(ParseServedUserNr, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &intResult->servedUserNr);
XSEQUENCE_1(ParseBasicService, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &intResult->basicService);
XSEQUENCE_1(ParseProcedure, ASN1_TAG_ENUM, ASN1_NOT_TAGGED, &intResult->procedure);
XSEQUENCE_1(ParseAddress, ASN1_TAG_SEQUENCE, ASN1_NOT_TAGGED, &intResult->address);
return p - beg;
}
int
ParseServedUserNrAll(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNr *servedUserNr)
{
int ret;
ret = ParseNull(pc, p, end, 0);
if (ret < 0)
return ret;
servedUserNr->all = 1;
return ret;
}
int
ParseServedUserNr(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNr *servedUserNr)
{
INIT;
servedUserNr->all = 0;
XCHOICE_1(ParseServedUserNrAll, ASN1_TAG_NULL, ASN1_NOT_TAGGED, servedUserNr);
XCHOICE_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &servedUserNr->partyNumber);
XCHOICE_DEFAULT;
}
int
ParseProcedure(struct asn1_parm *pc, u_char *p, u_char *end, int *procedure)
{
return ParseEnum(pc, p, end, procedure);
}
int ParseServedUserNumberList(struct asn1_parm *pc, u_char *p, u_char *end, struct ServedUserNumberList *list)
{
int i;
INIT;
for (i = 0; i < 10; i++) {
list->partyNumber[i].type = -1;
XSEQUENCE_OPT_1(ParsePartyNumber, ASN1_NOT_TAGGED, ASN1_NOT_TAGGED, &list->partyNumber[i]);
}
return p - beg;
}
int
ParseDiversionReason(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
int ret;
int diversionReason;
ret = ParseEnum(pc, p, end, &diversionReason);
if (ret < 0)
return ret;
switch (diversionReason) {
case 0: sprintf(str, "unknown"); break;
case 1: sprintf(str, "CFU"); break;
case 2: sprintf(str, "CFB"); break;
case 3: sprintf(str, "CFNR"); break;
case 4: sprintf(str, "CD (Alerting)"); break;
case 5: sprintf(str, "CD (Immediate)"); break;
default: sprintf(str, "(%d)", diversionReason); break;
}
return ret;
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_diversion.h 0000644 0000000 0000050 00000003107 11135651701 021464 0 ustar root src /* $Id: asn1_diversion.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
#if 0
int ParseARGActivationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
int ParseARGDeactivationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
#endif
int ParseARGActivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct ActDivNotification *actNot);
int ParseARGDeactivationStatusNotificationDiv(struct asn1_parm *pc, u_char *p, u_char *end, struct DeactDivNotification *deactNot);
int ParseARGInterrogationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
int ParseRESInterrogationDiversion(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
int ParseARGInterrogateServedUserNumbers(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
int ParseRESInterrogateServedUserNumbers(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
int ParseARGDiversionInformation(struct asn1_parm *parm, u_char *p, u_char *end, int dummy);
int ParseIntResult(struct asn1_parm *parm, u_char *p, u_char *end, struct IntResult *intResult);
int ParseIntResultList(struct asn1_parm *parm, u_char *p, u_char *end, struct IntResultList *intResultList);
int ParseServedUserNr(struct asn1_parm *parm, u_char *p, u_char *end, struct ServedUserNr *servedUserNr);
int ParseProcedure(struct asn1_parm *pc, u_char *p, u_char *end, int *procedure);
int ParseServedUserNumberList(struct asn1_parm *parm, u_char *p, u_char *end, struct ServedUserNumberList *list);
int ParseDiversionReason(struct asn1_parm *parm, u_char *p, u_char *end, char *str);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_enc.c 0000644 0000000 0000050 00000007675 11135651701 020240 0 ustar root src /* $Id: asn1_enc.c,v 1.4 2006/03/06 12:52:07 keil Exp $
*
*/
#include "m_capi.h"
#include "helper.h"
#include "asn1_enc.h"
int encodeNull(__u8 *dest)
{
dest[0] = 0x05; // null
dest[1] = 0; // length
return 2;
}
int encodeBoolean(__u8 *dest, __u32 i)
{
dest[0] = 0x01; // BOOLEAN
dest[1] = 1; // length 1
dest[3] = i ? 1:0; // Value
return 3;
}
int encodeInt(__u8 *dest, __u32 i)
{
__u8 *p;
dest[0] = 0x02; // integer
dest[1] = 0; // length
p = &dest[2];
do {
*p++ = i;
i >>= 8;
} while (i);
dest[1] = p - &dest[2];
return p - dest;
}
int encodeEnum(__u8 *dest, __u32 i)
{
__u8 *p;
dest[0] = 0x0a; // integer
dest[1] = 0; // length
p = &dest[2];
do {
*p++ = i;
i >>= 8;
} while (i);
dest[1] = p - &dest[2];
return p - dest;
}
int encodeNumberDigits(__u8 *dest, __u8 *nd, __u8 len)
{
__u8 *p;
int i;
dest[0] = 0x12; // numeric string
dest[1] = 0x0; // length
p = &dest[2];
for (i = 0; i < len; i++)
*p++ = *nd++;
dest[1] = p - &dest[2];
return p - dest;
}
int encodePublicPartyNumber(__u8 *dest, __u8 *facilityPartyNumber)
{
__u8 *p;
dest[0] = 0x20; // sequence
dest[1] = 0; // length
p = &dest[2];
p += encodeEnum(p, (facilityPartyNumber[2] & 0x70) >> 4);
p += encodeNumberDigits(p, &facilityPartyNumber[4], facilityPartyNumber[0] - 3);
dest[1] = p - &dest[2];
return p - dest;
}
int encodePartyNumber(__u8 *dest, __u8 *facilityPartyNumber)
{
__u8 *p = dest;
p = dest;
switch (facilityPartyNumber[1]) {
case 0: // unknown
p += encodeNumberDigits(p, &facilityPartyNumber[4], facilityPartyNumber[0] - 3);
dest[0] &= 0x20;
dest[0] |= 0x81;
break;
case 1: // publicPartyNumber
p += encodePublicPartyNumber(p, facilityPartyNumber);
dest[0] &= 0x20;
dest[0] |= 0x81;
break;
default:
int_error();
return -1;
}
return p - dest;
}
int encodeServedUserNumber(__u8 *dest, __u8 *servedUserNumber)
{
if (servedUserNumber[0])
return encodePartyNumber(dest, servedUserNumber);
else
return encodeNull(dest);
}
int encodeAddress(__u8 *dest, __u8 *facilityPartyNumber, __u8 *calledPartySubaddress)
{
__u8 *p = dest;
dest[0] = 0x30; // invoke id tag, integer
dest[1] = 0; // length
p = &dest[2];
p += encodePartyNumber(p, facilityPartyNumber);
#if 0 // FIXME
if (calledPartySubaddress[0])
p += encodePartySubaddress(p, calledPartySubaddress);
#endif
dest[1] = p - &dest[2];
return p - dest;
}
int encodeActivationDiversion(__u8 *dest, struct FacReqCFActivate *CFActivate)
{
__u8 *p;
dest[0] = 0x30; // sequence
dest[1] = 0; // length
p = &dest[2];
p += encodeEnum(p, CFActivate->Procedure);
p += encodeEnum(p, CFActivate->BasicService);
p += encodeAddress(p, CFActivate->ForwardedToNumber, CFActivate->ForwardedToSubaddress);
p += encodeServedUserNumber(p, CFActivate->ServedUserNumber);
dest[1] = p - &dest[2];
return p - dest;
}
int encodeDeactivationDiversion(__u8 *dest, struct FacReqCFDeactivate *CFDeactivate)
{
__u8 *p;
dest[0] = 0x30; // sequence
dest[1] = 0; // length
p = &dest[2];
p += encodeEnum(p, CFDeactivate->Procedure);
p += encodeEnum(p, CFDeactivate->BasicService);
p += encodeServedUserNumber(p, CFDeactivate->ServedUserNumber);
dest[1] = p - &dest[2];
return p - dest;
}
int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameters *params)
{
__u8 *p;
dest[0] = 0x30; // sequence
dest[1] = 0; // length
p = &dest[2];
p += encodeEnum(p, params->Procedure);
#if 0
if (basicService == 0)
p += encodeNull(p);
else
#endif
p += encodeEnum(p, params->BasicService);
p += encodeServedUserNumber(p, params->ServedUserNumber);
dest[1] = p - &dest[2];
return p - dest;
}
int encodeInvokeDeflection(__u8 *dest, struct FacReqCDeflection *CD)
{
__u8 *p;
dest[0] = 0x30; // sequence
dest[1] = 0; // length
p = &dest[2];
p += encodeAddress(p, CD->DeflectedToNumber, CD->DeflectedToSubaddress);
p += encodeBoolean(p, CD->PresentationAllowed);
dest[1] = p - &dest[2];
return p - dest;
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_enc.h 0000644 0000000 0000050 00000001570 11135651701 020231 0 ustar root src /* $Id: asn1_enc.h,v 1.1 2006/03/06 12:52:07 keil Exp $
*
*/
#include "asn1.h"
int encodeNull(__u8 *dest);
int encodeBoolean(__u8 *dest, __u32 i);
int encodeInt(__u8 *dest, __u32 i);
int encodeEnum(__u8 *dest, __u32 i);
int encodeNumberDigits(__u8 *dest, __u8 *nd, __u8 len);
int encodePublicPartyNumber(__u8 *dest, __u8 *facilityPartyNumber);
int encodePartyNumber(__u8 *dest, __u8 *facilityPartyNumber);
int encodeServedUserNumber(__u8 *dest, __u8 *servedUserNumber);
int encodeAddress(__u8 *dest, __u8 *facilityPartyNumber, __u8 *calledPartySubaddress);
int encodeActivationDiversion(__u8 *dest, struct FacReqCFActivate *CFActivate);
int encodeDeactivationDiversion(__u8 *dest,struct FacReqCFDeactivate *CFDeactivate);
int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameters *params);
int encodeInvokeDeflection(__u8 *dest, struct FacReqCDeflection *CD);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_generic.c 0000644 0000000 0000050 00000003662 11135651701 021077 0 ustar root src /* $Id: asn1_generic.c,v 1.1 2003/11/09 09:12:28 keil Exp $
*
*/
#include "asn1.h"
#include "asn1_generic.h"
// ======================================================================
// general ASN.1
int
ParseBoolean(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
{
INIT;
*i = 0;
while (len--) {
CHECK_P;
*i = (*i >> 8) + *p;
p++;
}
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> BOOL = %d %#x\n", *i, *i);
return p - beg;
}
int
ParseNull(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
{
INIT;
return p - beg;
}
int
ParseInteger(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
{
INIT;
*i = 0;
while (len--) {
CHECK_P;
*i = (*i << 8) + *p;
p++;
}
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> INT = %d %#x\n", *i, *i);
return p - beg;
}
int
ParseEnum(struct asn1_parm *pc, u_char *p, u_char *end, int *i)
{
INIT;
*i = 0;
while (len--) {
CHECK_P;
*i = (*i << 8) + *p;
p++;
}
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> ENUM = %d %#x\n", *i, *i);
return p - beg;
}
#if 0
int
ParseIA5String(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> IA5 = ");
while (len--) {
CHECK_P;
print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
*str++ = *p;
p++;
}
print_asn1msg(PRT_DEBUG_DECODE, "\n");
*str = 0;
return p - beg;
}
#endif
int
ParseNumericString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> NumStr = ");
while (len--) {
CHECK_P;
print_asn1msg(PRT_DEBUG_DECODE, "%c", *p);
*str++ = *p;
p++;
}
print_asn1msg(PRT_DEBUG_DECODE, "\n");
*str = 0;
return p - beg;
}
int
ParseOctetString(struct asn1_parm *pc, u_char *p, u_char *end, char *str)
{
INIT;
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> Octets = ");
while (len--) {
CHECK_P;
print_asn1msg(PRT_DEBUG_DECODE, " %02x", *p);
*str++ = *p;
p++;
}
print_asn1msg(PRT_DEBUG_DECODE, "\n");
*str = 0;
return p - beg;
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/asn1_generic.h 0000644 0000000 0000050 00000001277 11110524073 021076 0 ustar root src /* $Id: asn1_generic.h,v 1.0 2001/11/02 23:42:26 kkeil Exp $
*
*/
#include "asn1.h"
// ======================================================================
// general ASN.1
int ParseBoolean(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
int ParseNull(struct asn1_parm *pc, u_char *p, u_char *end, int dummy);
int ParseInteger(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
int ParseEnum(struct asn1_parm *pc, u_char *p, u_char *end, int *i);
int ParseIA5String(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseNumericString(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
int ParseOctetString(struct asn1_parm *pc, u_char *p, u_char *end, char *str);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/avm_fritz.c 0000644 0000000 0000050 00000114134 11135651701 020537 0 ustar root src /* $Id: avm_fritz.c,v 1.43 2007/02/13 10:43:45 crich Exp $
*
* fritz_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
* Thanks to AVM, Berlin for informations
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include
#include
#ifdef NEW_ISAPNP
#include
#else
#include
#endif
#include
#include
#include "core.h"
#include "channel.h"
#include "isac.h"
#include "layer1.h"
#include "debug.h"
static const char *avm_fritz_rev = "$Revision: 1.43 $";
enum {
AVM_FRITZ_PCI,
AVM_FRITZ_PNP,
AVM_FRITZ_PCIV2,
};
#ifndef PCI_VENDOR_ID_AVM
#define PCI_VENDOR_ID_AVM 0x1244
#endif
#ifndef PCI_DEVICE_ID_AVM_FRITZ
#define PCI_DEVICE_ID_AVM_FRITZ 0xa00
#endif
#ifndef PCI_DEVICE_ID_AVM_A1_V2
#define PCI_DEVICE_ID_AVM_A1_V2 0xe00
#endif
#define HDLC_FIFO 0x0
#define HDLC_STATUS 0x4
#define CHIP_WINDOW 0x10
#define CHIP_INDEX 0x4
#define AVM_HDLC_1 0x00
#define AVM_HDLC_2 0x01
#define AVM_ISAC_FIFO 0x02
#define AVM_ISAC_REG_LOW 0x04
#define AVM_ISAC_REG_HIGH 0x06
#define AVM_STATUS0_IRQ_ISAC 0x01
#define AVM_STATUS0_IRQ_HDLC 0x02
#define AVM_STATUS0_IRQ_TIMER 0x04
#define AVM_STATUS0_IRQ_MASK 0x07
#define AVM_STATUS0_RESET 0x01
#define AVM_STATUS0_DIS_TIMER 0x02
#define AVM_STATUS0_RES_TIMER 0x04
#define AVM_STATUS0_ENA_IRQ 0x08
#define AVM_STATUS0_TESTBIT 0x10
#define AVM_STATUS1_INT_SEL 0x0f
#define AVM_STATUS1_ENA_IOM 0x80
#define HDLC_MODE_ITF_FLG 0x01
#define HDLC_MODE_TRANS 0x02
#define HDLC_MODE_CCR_7 0x04
#define HDLC_MODE_CCR_16 0x08
#define HDLC_MODE_TESTLOOP 0x80
#define HDLC_INT_XPR 0x80
#define HDLC_INT_XDU 0x40
#define HDLC_INT_RPR 0x20
#define HDLC_INT_MASK 0xE0
#define HDLC_STAT_RME 0x01
#define HDLC_STAT_RDO 0x10
#define HDLC_STAT_CRCVFRRAB 0x0E
#define HDLC_STAT_CRCVFR 0x06
#define HDLC_STAT_RML_MASK 0x3f00
#define HDLC_CMD_XRS 0x80
#define HDLC_CMD_XME 0x01
#define HDLC_CMD_RRS 0x20
#define HDLC_CMD_XML_MASK 0x3f00
/* Fritz PCI v2.0 */
#define AVM_HDLC_FIFO_1 0x10
#define AVM_HDLC_FIFO_2 0x18
#define AVM_HDLC_STATUS_1 0x14
#define AVM_HDLC_STATUS_2 0x1c
#define AVM_ISACSX_INDEX 0x04
#define AVM_ISACSX_DATA 0x08
/* data struct */
struct hdlc_stat_reg {
#ifdef __BIG_ENDIAN
u_char fill;
u_char mode;
u_char xml;
u_char cmd;
#else
u_char cmd;
u_char xml;
u_char mode;
u_char fill;
#endif
} __attribute__((packed));
typedef struct hdlc_hw {
union {
u_int ctrl;
struct hdlc_stat_reg sr;
} ctrl;
u_int stat;
} hdlc_hw_t;
typedef struct _fritzpnppci {
struct list_head list;
union {
#if defined(CONFIG_PNP)
#ifdef NEW_ISAPNP
struct pnp_dev *pnp;
#else
struct pci_dev *pnp;
#endif
#endif
struct pci_dev *pci;
} dev;
u_int type;
u_int irq;
u_int irqcnt;
u_int addr;
spinlock_t lock;
isac_chip_t isac;
hdlc_hw_t hdlc[2];
channel_t dch;
channel_t bch[2];
u_char ctrlreg;
} fritzpnppci;
/* Interface functions */
static u_char
ReadISAC(void *fc, u_char offset)
{
register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
register long addr = ((fritzpnppci *)fc)->addr;
register u_char val;
outb(idx, addr + CHIP_INDEX);
val = inb(addr + CHIP_WINDOW + (offset & 0xf));
return (val);
}
static void
WriteISAC(void *fc, u_char offset, u_char value)
{
register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
register long addr = ((fritzpnppci *)fc)->addr;
outb(idx, addr + CHIP_INDEX);
outb(value, addr + CHIP_WINDOW + (offset & 0xf));
}
static void
ReadISACfifo(void *fc, u_char * data, int size)
{
register long addr = ((fritzpnppci *)fc)->addr;
outb(AVM_ISAC_FIFO, addr + CHIP_INDEX);
insb(addr + CHIP_WINDOW, data, size);
}
static void
WriteISACfifo(void *fc, u_char * data, int size)
{
register long addr = ((fritzpnppci *)fc)->addr;
outb(AVM_ISAC_FIFO, addr + CHIP_INDEX);
outsb(addr + CHIP_WINDOW, data, size);
}
static unsigned char
fcpci2_read_isac(void *fc, unsigned char offset)
{
register long addr = ((fritzpnppci *)fc)->addr;
unsigned char val;
outl(offset, addr + AVM_ISACSX_INDEX);
val = inl(addr + AVM_ISACSX_DATA);
return val;
}
static void
fcpci2_write_isac(void *fc, unsigned char offset, unsigned char value)
{
register long addr = ((fritzpnppci *)fc)->addr;
outl(offset, addr + AVM_ISACSX_INDEX);
outl(value, addr + AVM_ISACSX_DATA);
}
static void
fcpci2_read_isac_fifo(void *fc, unsigned char * data, int size)
{
register long addr = ((fritzpnppci *)fc)->addr;
int i;
outl(0, addr + AVM_ISACSX_INDEX);
for (i = 0; i < size; i++)
data[i] = inl(addr + AVM_ISACSX_DATA);
}
static void
fcpci2_write_isac_fifo(void *fc, unsigned char * data, int size)
{
register long addr = ((fritzpnppci *)fc)->addr;
int i;
outl(0, addr + AVM_ISACSX_INDEX);
for (i = 0; i < size; i++)
outl(data[i], addr + AVM_ISACSX_DATA);
}
static inline
channel_t *Sel_BCS(fritzpnppci *fc, int channel)
{
if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && (fc->bch[0].channel == channel))
return(&fc->bch[0]);
else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && (fc->bch[1].channel == channel))
return(&fc->bch[1]);
else
return(NULL);
}
static inline void
__write_ctrl_pnp(fritzpnppci *fc, hdlc_hw_t *hdlc, int channel, int which) {
register u_char idx = channel ? AVM_HDLC_2 : AVM_HDLC_1;
outb(idx, fc->addr + CHIP_INDEX);
if (which & 4)
outb(hdlc->ctrl.sr.mode, fc->addr + CHIP_WINDOW + HDLC_STATUS + 2);
if (which & 2)
outb(hdlc->ctrl.sr.xml, fc->addr + CHIP_WINDOW + HDLC_STATUS + 1);
if (which & 1)
outb(hdlc->ctrl.sr.cmd, fc->addr + CHIP_WINDOW + HDLC_STATUS);
}
static inline void
__write_ctrl_pci(fritzpnppci *fc, hdlc_hw_t *hdlc, int channel) {
register u_int idx = channel ? AVM_HDLC_2 : AVM_HDLC_1;
outl(idx, fc->addr + CHIP_INDEX);
outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS);
}
static inline void
__write_ctrl_pciv2(fritzpnppci *fc, hdlc_hw_t *hdlc, int channel) {
outl(hdlc->ctrl.ctrl, fc->addr + (channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1));
}
void
write_ctrl(channel_t *bch, int which) {
fritzpnppci *fc = bch->inst.privat;
hdlc_hw_t *hdlc = bch->hw;
if (fc->dch.debug & L1_DEB_HSCX)
mISDN_debugprint(&bch->inst, "hdlc %c wr%x ctrl %x",
'A' + bch->channel, which, hdlc->ctrl.ctrl);
switch(fc->type) {
case AVM_FRITZ_PCIV2:
__write_ctrl_pciv2(fc, hdlc, bch->channel);
break;
case AVM_FRITZ_PCI:
__write_ctrl_pci(fc, hdlc, bch->channel);
break;
case AVM_FRITZ_PNP:
__write_ctrl_pnp(fc, hdlc, bch->channel, which);
break;
}
}
static inline u_int
__read_status_pnp(u_long addr, u_int channel)
{
register u_int stat;
outb(channel ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX);
stat = inb(addr + CHIP_WINDOW + HDLC_STATUS);
if (stat & HDLC_INT_RPR)
stat |= (inb(addr + CHIP_WINDOW + HDLC_STATUS + 1)) << 8;
return (stat);
}
static inline u_int
__read_status_pci(u_long addr, u_int channel)
{
outl(channel ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX);
return inl(addr + CHIP_WINDOW + HDLC_STATUS);
}
static inline u_int
__read_status_pciv2(u_long addr, u_int channel)
{
return inl(addr + (channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1));
}
static u_int
read_status(fritzpnppci *fc, int channel)
{
switch(fc->type) {
case AVM_FRITZ_PCIV2:
return(__read_status_pciv2(fc->addr, channel));
case AVM_FRITZ_PCI:
return(__read_status_pci(fc->addr, channel));
case AVM_FRITZ_PNP:
return(__read_status_pnp(fc->addr, channel));
}
/* dummy */
return(0);
}
static void
enable_hwirq(fritzpnppci *fc)
{
fc->ctrlreg |= AVM_STATUS0_ENA_IRQ;
outb(fc->ctrlreg, fc->addr + 2);
}
static void
disable_hwirq(fritzpnppci *fc)
{
fc->ctrlreg &= ~((u_char)AVM_STATUS0_ENA_IRQ);
outb(fc->ctrlreg, fc->addr + 2);
}
static int
modehdlc(channel_t *bch, int bc, int protocol)
{
hdlc_hw_t *hdlc = bch->hw;
if (bch->debug & L1_DEB_HSCX)
mISDN_debugprint(&bch->inst, "hdlc %c protocol %x-->%x ch %d-->%d",
'A' + bch->channel, bch->state, protocol, bch->channel, bc);
if ((protocol != -1) && (bc != bch->channel))
printk(KERN_WARNING "%s: fritzcard mismatch channel(%d/%d)\n", __FUNCTION__, bch->channel, bc);
hdlc->ctrl.ctrl = 0;
switch (protocol) {
case (-1): /* used for init */
bch->state = -1;
bch->channel = bc;
case (ISDN_PID_NONE):
if (bch->state == ISDN_PID_NONE)
break;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bch, 5);
bch->state = ISDN_PID_NONE;
test_and_clear_bit(FLG_HDLC, &bch->Flags);
test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
break;
case (ISDN_PID_L1_B_64TRANS):
bch->state = protocol;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bch, 5);
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bch, 1);
hdlc->ctrl.sr.cmd = 0;
test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
break;
case (ISDN_PID_L1_B_64HDLC):
bch->state = protocol;
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
write_ctrl(bch, 5);
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bch, 1);
hdlc->ctrl.sr.cmd = 0;
test_and_set_bit(FLG_HDLC, &bch->Flags);
break;
default:
mISDN_debugprint(&bch->inst, "prot not known %x", protocol);
return(-ENOPROTOOPT);
}
return(0);
}
static void
hdlc_empty_fifo(channel_t *bch, int count)
{
register u_int *ptr;
u_char *p;
u_char idx = bch->channel ? AVM_HDLC_2 : AVM_HDLC_1;
int cnt=0;
fritzpnppci *fc = bch->inst.privat;
if ((fc->dch.debug & L1_DEB_HSCX) && !(fc->dch.debug & L1_DEB_HSCX_FIFO))
mISDN_debugprint(&bch->inst, "hdlc_empty_fifo %d", count);
if (!bch->rx_skb) {
if (!(bch->rx_skb = alloc_stack_skb(bch->maxlen, bch->up_headerlen))) {
printk(KERN_WARNING "mISDN: B receive out of memory\n");
return;
}
}
if ((bch->rx_skb->len + count) > bch->maxlen) {
if (bch->debug & L1_DEB_WARN)
mISDN_debugprint(&bch->inst, "hdlc_empty_fifo overrun %d",
bch->rx_skb->len + count);
return;
}
p = skb_put(bch->rx_skb, count);
ptr = (u_int *)p;
if (fc->type == AVM_FRITZ_PCIV2) {
while (cnt < count) {
#ifdef __powerpc__
#ifdef CONFIG_APUS
*ptr++ = in_le32((unsigned *)(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1) +_IO_BASE));
#else
*ptr++ = in_be32((unsigned *)(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1) +_IO_BASE));
#endif /* CONFIG_APUS */
#else
*ptr++ = inl(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1));
#endif /* __powerpc__ */
cnt += 4;
}
} else if (fc->type == AVM_FRITZ_PCI) {
outl(idx, fc->addr + CHIP_INDEX);
while (cnt < count) {
#ifdef __powerpc__
#ifdef CONFIG_APUS
*ptr++ = in_le32((unsigned *)(fc->addr + CHIP_WINDOW +_IO_BASE));
#else
*ptr++ = in_be32((unsigned *)(fc->addr + CHIP_WINDOW +_IO_BASE));
#endif /* CONFIG_APUS */
#else
*ptr++ = inl(fc->addr + CHIP_WINDOW);
#endif /* __powerpc__ */
cnt += 4;
}
} else {
outb(idx, fc->addr + CHIP_INDEX);
while (cnt < count) {
*p++ = inb(fc->addr + CHIP_WINDOW);
cnt++;
}
}
if (fc->dch.debug & L1_DEB_HSCX_FIFO) {
char *t = bch->log;
if (fc->type == AVM_FRITZ_PNP)
p = (u_char *) ptr;
t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
bch->channel ? 'B' : 'A', count);
mISDN_QuickHex(t, p, count);
mISDN_debugprint(&bch->inst, bch->log);
}
}
#define HDLC_FIFO_SIZE 32
static void
hdlc_fill_fifo(channel_t *bch)
{
fritzpnppci *fc = bch->inst.privat;
hdlc_hw_t *hdlc = bch->hw;
int count, cnt =0;
u_char *p;
u_int *ptr;
if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
mISDN_debugprint(&bch->inst, "%s", __FUNCTION__);
if (!bch->tx_skb)
return;
count = bch->tx_skb->len - bch->tx_idx;
if (count <= 0)
return;
p = bch->tx_skb->data + bch->tx_idx;
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
if (count > HDLC_FIFO_SIZE) {
count = HDLC_FIFO_SIZE;
} else {
if (test_bit(FLG_HDLC, &bch->Flags))
hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
}
if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
mISDN_debugprint(&bch->inst, "%s: %d/%d", __FUNCTION__,
count, bch->tx_idx);
ptr = (u_int *) p;
bch->tx_idx += count;
hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
if (fc->type == AVM_FRITZ_PCIV2) {
__write_ctrl_pciv2(fc, hdlc, bch->channel);
while (cntaddr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1) +_IO_BASE), *ptr++);
#else
out_be32((unsigned *)(fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1) +_IO_BASE), *ptr++);
#endif /* CONFIG_APUS */
#else
outl(*ptr++, fc->addr + (bch->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1));
#endif /* __powerpc__ */
cnt += 4;
}
} else if (fc->type == AVM_FRITZ_PCI) {
__write_ctrl_pci(fc, hdlc, bch->channel);
while (cntaddr + CHIP_WINDOW +_IO_BASE), *ptr++);
#else
out_be32((unsigned *)(fc->addr + CHIP_WINDOW +_IO_BASE), *ptr++);
#endif /* CONFIG_APUS */
#else
outl(*ptr++, fc->addr + CHIP_WINDOW);
#endif /* __powerpc__ */
cnt += 4;
}
} else {
__write_ctrl_pnp(fc, hdlc, bch->channel, 3);
while (cntaddr + CHIP_WINDOW);
cnt++;
}
}
if (bch->debug & L1_DEB_HSCX_FIFO) {
char *t = bch->log;
if (fc->type == AVM_FRITZ_PNP)
p = (u_char *) ptr;
t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
bch->channel ? 'B' : 'A', count);
mISDN_QuickHex(t, p, count);
mISDN_debugprint(&bch->inst, bch->log);
}
}
static void
HDLC_irq_xpr(channel_t *bch)
{
if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
hdlc_fill_fifo(bch);
else {
if (bch->tx_skb)
dev_kfree_skb(bch->tx_skb);
bch->tx_idx = 0;
if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
bch->tx_skb = bch->next_skb;
if (bch->tx_skb) {
mISDN_head_t *hh = mISDN_HEAD_P(bch->tx_skb);
bch->next_skb = NULL;
test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
hdlc_fill_fifo(bch);
} else {
printk(KERN_WARNING "hdlc tx irq TX_NEXT without skb\n");
test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
}
} else {
bch->tx_skb = NULL;
test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
}
}
}
static void
HDLC_irq(channel_t *bch, u_int stat)
{
int len;
struct sk_buff *skb;
hdlc_hw_t *hdlc = bch->hw;
if (bch->debug & L1_DEB_HSCX)
mISDN_debugprint(&bch->inst, "ch%d stat %#x", bch->channel, stat);
if (stat & HDLC_INT_RPR) {
if (stat & HDLC_STAT_RDO) {
if (bch->debug & L1_DEB_HSCX)
mISDN_debugprint(&bch->inst, "RDO");
else
mISDN_debugprint(&bch->inst, "ch%d stat %#x", bch->channel, stat);
hdlc->ctrl.sr.xml = 0;
hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
write_ctrl(bch, 1);
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
write_ctrl(bch, 1);
if (bch->rx_skb)
skb_trim(bch->rx_skb, 0);
} else {
if (!(len = (stat & HDLC_STAT_RML_MASK)>>8))
len = 32;
hdlc_empty_fifo(bch, len);
if (!bch->rx_skb)
goto handle_tx;
if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, &bch->Flags)) {
if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) ||
test_bit(FLG_TRANSPARENT, &bch->Flags)) {
if (bch->rx_skb->len < MISDN_COPY_SIZE) {
skb = alloc_stack_skb(bch->rx_skb->len, bch->up_headerlen);
if (skb) {
memcpy(skb_put(skb, bch->rx_skb->len),
bch->rx_skb->data, bch->rx_skb->len);
skb_trim(bch->rx_skb, 0);
} else {
skb = bch->rx_skb;
bch->rx_skb = NULL;
}
} else {
skb = bch->rx_skb;
bch->rx_skb = NULL;
}
queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb);
} else {
if (bch->debug & L1_DEB_HSCX)
mISDN_debugprint(&bch->inst, "invalid frame");
else
mISDN_debugprint(&bch->inst, "ch%d invalid frame %#x", bch->channel, stat);
skb_trim(bch->rx_skb, 0);
}
}
}
}
handle_tx:
if (stat & HDLC_INT_XDU) {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame on HDLC
* in transparent mode we send the next data
*/
if (bch->debug & L1_DEB_WARN) {
if (bch->tx_skb)
mISDN_debugprint(&bch->inst, "ch%d XDU tx_len(%d) tx_idx(%d) Flags(%lx)",
bch->channel, bch->tx_skb->len, bch->tx_idx, bch->Flags);
else
mISDN_debugprint(&bch->inst, "ch%d XDU no tx_skb Flags(%lx)",
bch->channel, bch->Flags);
}
if (bch->tx_skb && bch->tx_skb->len) {
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
bch->tx_idx = 0;
}
hdlc->ctrl.sr.xml = 0;
hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS;
write_ctrl(bch, 1);
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
HDLC_irq_xpr(bch);
return;
} else if (stat & HDLC_INT_XPR)
HDLC_irq_xpr(bch);
}
static inline void
HDLC_irq_main(fritzpnppci *fc)
{
u_int stat;
channel_t *bch;
stat = read_status(fc, 0);
if (stat & HDLC_INT_MASK) {
if (!(bch = Sel_BCS(fc, 0))) {
if (fc->bch[0].debug)
mISDN_debugprint(&fc->bch[0].inst, "hdlc spurious channel 0 IRQ");
} else
HDLC_irq(bch, stat);
}
stat = read_status(fc, 1);
if (stat & HDLC_INT_MASK) {
if (!(bch = Sel_BCS(fc, 1))) {
if (fc->bch[1].debug)
mISDN_debugprint(&fc->bch[1].inst, "hdlc spurious channel 1 IRQ");
} else
HDLC_irq(bch, stat);
}
}
static irqreturn_t
avm_fritz_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
fritzpnppci *fc = dev_id;
u_char val;
u_char sval;
spin_lock(&fc->lock);
sval = inb(fc->addr + 2);
if (fc->dch.debug & L1_DEB_INTSTAT)
mISDN_debugprint(&fc->dch.inst, "irq stat0 %x", sval);
if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
/* possible a shared IRQ reqest */
spin_unlock(&fc->lock);
return IRQ_NONE;
}
fc->irqcnt++;
if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
val = ReadISAC(fc, ISAC_ISTA);
mISDN_isac_interrupt(&fc->dch, val);
}
if (!(sval & AVM_STATUS0_IRQ_HDLC)) {
HDLC_irq_main(fc);
}
if (fc->type == AVM_FRITZ_PNP) {
WriteISAC(fc, ISAC_MASK, 0xFF);
WriteISAC(fc, ISAC_MASK, 0x0);
}
spin_unlock(&fc->lock);
return IRQ_HANDLED;
}
static irqreturn_t
avm_fritzv2_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
fritzpnppci *fc = dev_id;
u_char val;
u_char sval;
spin_lock(&fc->lock);
sval = inb(fc->addr + 2);
if (fc->dch.debug & L1_DEB_INTSTAT)
mISDN_debugprint(&fc->dch.inst, "irq stat0 %x", sval);
if (!(sval & AVM_STATUS0_IRQ_MASK)) {
/* possible a shared IRQ reqest */
spin_unlock(&fc->lock);
return IRQ_NONE;
}
fc->irqcnt++;
if (sval & AVM_STATUS0_IRQ_HDLC) {
HDLC_irq_main(fc);
}
if (sval & AVM_STATUS0_IRQ_ISAC) {
val = fcpci2_read_isac(fc, ISACSX_ISTA);
mISDN_isac_interrupt(&fc->dch, val);
}
if (sval & AVM_STATUS0_IRQ_TIMER) {
if (fc->dch.debug & L1_DEB_INTSTAT)
mISDN_debugprint(&fc->dch.inst, "Fc2 timer irq");
outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2);
udelay(1);
outb(fc->ctrlreg, fc->addr + 2);
}
spin_unlock(&fc->lock);
return IRQ_HANDLED;
}
static int
hdlc_down(mISDNinstance_t *inst, struct sk_buff *skb)
{
channel_t *bch;
int ret = 0;
mISDN_head_t *hh = mISDN_HEAD_P(skb);
u_long flags;
bch = container_of(inst, channel_t, inst);
if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
spin_lock_irqsave(inst->hwlock, flags);
ret = channel_senddata(bch, hh->dinfo, skb);
if (ret > 0) { /* direct TX */
hdlc_fill_fifo(bch);
ret = 0;
}
spin_unlock_irqrestore(inst->hwlock, flags);
return(ret);
}
if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
(hh->prim == (DL_ESTABLISH | REQUEST))) {
if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
spin_lock_irqsave(inst->hwlock, flags);
ret = modehdlc(bch, bch->channel,
bch->inst.pid.protocol[1]);
spin_unlock_irqrestore(inst->hwlock, flags);
}
skb_trim(skb, 0);
return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
(hh->prim == (DL_RELEASE | REQUEST)) ||
((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
spin_lock_irqsave(inst->hwlock, flags);
if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
dev_kfree_skb(bch->next_skb);
bch->next_skb = NULL;
}
if (bch->tx_skb) {
dev_kfree_skb(bch->tx_skb);
bch->tx_skb = NULL;
bch->tx_idx = 0;
}
test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
modehdlc(bch, bch->channel, 0);
if (bch->rx_skb) {
dev_kfree_skb(bch->rx_skb);
bch->rx_skb = NULL;
}
test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
spin_unlock_irqrestore(inst->hwlock, flags);
skb_trim(skb, 0);
if (hh->prim != (PH_CONTROL | REQUEST))
if (!mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, 0, skb))
return(0);
} else {
printk(KERN_WARNING "hdlc_down unknown prim(%x)\n", hh->prim);
ret = -EINVAL;
}
if (!ret)
dev_kfree_skb(skb);
return(ret);
}
static void
inithdlc(fritzpnppci *fc)
{
modehdlc(&fc->bch[0], 0, -1);
modehdlc(&fc->bch[1], 1, -1);
}
void
clear_pending_hdlc_ints(fritzpnppci *fc)
{
u_int val;
val = read_status(fc, 0);
mISDN_debugprint(&fc->dch.inst, "HDLC 1 STA %x", val);
val = read_status(fc, 1);
mISDN_debugprint(&fc->dch.inst, "HDLC 2 STA %x", val);
}
static void
reset_avmpcipnp(fritzpnppci *fc)
{
switch (fc->type) {
case AVM_FRITZ_PNP:
case AVM_FRITZ_PCI:
fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER;
break;
case AVM_FRITZ_PCIV2:
fc->ctrlreg = AVM_STATUS0_RESET;
break;
}
printk(KERN_INFO "AVM PCI/PnP: reset\n");
disable_hwirq(fc);
mdelay(5);
switch (fc->type) {
case AVM_FRITZ_PNP:
fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
disable_hwirq(fc);
outb(AVM_STATUS1_ENA_IOM | fc->irq, fc->addr + 3);
break;
case AVM_FRITZ_PCI:
fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
disable_hwirq(fc);
outb(AVM_STATUS1_ENA_IOM, fc->addr + 3);
break;
case AVM_FRITZ_PCIV2:
fc->ctrlreg = 0;
disable_hwirq(fc);
break;
}
mdelay(1);
printk(KERN_INFO "AVM PCI/PnP: S0/S1 %x/%x\n", inb(fc->addr + 2), inb(fc->addr + 3));
}
static int init_card(fritzpnppci *fc)
{
int cnt = 3;
u_int shared = SA_SHIRQ;
u_long flags;
u_char *id = "AVM Fritz!PCI";
if (fc->type == AVM_FRITZ_PNP) {
shared = 0;
id = "AVM Fritz!PnP";
}
reset_avmpcipnp(fc); /* disable IRQ */
if (fc->type == AVM_FRITZ_PCIV2) {
if (request_irq(fc->irq, (void *)avm_fritzv2_interrupt, shared, id, fc)) {
printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
fc->irq);
return(-EIO);
}
} else {
if (request_irq(fc->irq, (void *)avm_fritz_interrupt, shared, id, fc)) {
printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
fc->irq);
return(-EIO);
}
}
while (cnt) {
int ret;
spin_lock_irqsave(&fc->lock, flags);
mISDN_clear_isac(&fc->dch);
if ((ret=mISDN_isac_init(&fc->dch))) {
printk(KERN_WARNING "mISDN: mISDN_isac_init failed with %d\n", ret);
spin_unlock_irqrestore(&fc->lock, flags);
break;
}
clear_pending_hdlc_ints(fc);
inithdlc(fc);
WriteISAC(fc, ISAC_MASK, 0);
enable_hwirq(fc);
/* RESET Receiver and Transmitter */
WriteISAC(fc, ISAC_CMDR, 0x41);
spin_unlock_irqrestore(&fc->lock, flags);
/* Timeout 10ms */
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((10*HZ)/1000);
printk(KERN_INFO "AVM Fritz!PCI: IRQ %d count %d\n",
fc->irq, fc->irqcnt);
if (!fc->irqcnt) {
printk(KERN_WARNING
"AVM Fritz!PCI: IRQ(%d) getting no interrupts during init %d\n",
fc->irq, 4 - cnt);
if (cnt == 1) {
return (-EIO);
} else {
reset_avmpcipnp(fc);
cnt--;
}
} else {
return(0);
}
}
return(-EIO);
}
#define MAX_CARDS 4
static int fritz_cnt;
static u_int protocol[MAX_CARDS];
static int layermask[MAX_CARDS];
static mISDNobject_t fritz;
static int debug;
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
#ifdef OLD_MODULE_PARAM
MODULE_PARM(debug, "1i");
#define MODULE_PARM_T "1-4i"
MODULE_PARM(protocol, MODULE_PARM_T);
MODULE_PARM(layermask, MODULE_PARM_T);
#else
module_param(debug, uint, S_IRUGO | S_IWUSR);
#ifdef OLD_MODULE_PARAM_ARRAY
static int num_protocol=0,num_layermask=0;
module_param_array(protocol, uint, num_protocol, S_IRUGO | S_IWUSR);
module_param_array(layermask, uint, num_layermask, S_IRUGO | S_IWUSR);
#else
module_param_array(protocol, uint, NULL, S_IRUGO | S_IWUSR);
module_param_array(layermask, uint, NULL, S_IRUGO | S_IWUSR);
#endif
#endif
#endif
int
setup_fritz(fritzpnppci *fc)
{
u_int val, ver;
if (!request_region(fc->addr, 32, (fc->type == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
printk(KERN_WARNING
"mISDN: %s config port %x-%x already in use\n",
"AVM Fritz!PCI",
fc->addr,
fc->addr + 31);
return(-EIO);
}
switch (fc->type) {
case AVM_FRITZ_PCI:
val = inl(fc->addr);
printk(KERN_INFO "AVM PCI: stat %#x\n", val);
printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
val & 0xff, (val>>8) & 0xff);
outl(AVM_HDLC_1, fc->addr + CHIP_INDEX);
ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24;
printk(KERN_INFO "AVM PnP: HDLC version %x\n", ver & 0xf);
fc->dch.read_reg = &ReadISAC;
fc->dch.write_reg = &WriteISAC;
fc->dch.read_fifo = &ReadISACfifo;
fc->dch.write_fifo = &WriteISACfifo;
fc->dch.type = ISAC_TYPE_ISAC;
break;
case AVM_FRITZ_PCIV2:
val = inl(fc->addr);
printk(KERN_INFO "AVM PCI V2: stat %#x\n", val);
printk(KERN_INFO "AVM PCI V2: Class %X Rev %d\n",
val & 0xff, (val>>8) & 0xff);
ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24;
printk(KERN_INFO "AVM PnP: HDLC version %x\n", ver & 0xf);
fc->dch.read_reg = &fcpci2_read_isac;
fc->dch.write_reg = &fcpci2_write_isac;
fc->dch.read_fifo = &fcpci2_read_isac_fifo;
fc->dch.write_fifo = &fcpci2_write_isac_fifo;
fc->dch.type = ISAC_TYPE_ISACSX;
break;
case AVM_FRITZ_PNP:
val = inb(fc->addr);
ver = inb(fc->addr + 1);
printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
outb(AVM_HDLC_1, fc->addr + CHIP_INDEX);
ver = inb(fc->addr + CHIP_WINDOW + 7);
printk(KERN_INFO "AVM PnP: HDLC version %x\n", ver & 0xf);
fc->dch.read_reg = &ReadISAC;
fc->dch.write_reg = &WriteISAC;
fc->dch.read_fifo = &ReadISACfifo;
fc->dch.write_fifo = &WriteISACfifo;
fc->dch.type = ISAC_TYPE_ISAC;
break;
default:
release_region(fc->addr, 32);
printk(KERN_WARNING "AVM unknown type %d\n", fc->type);
return(-ENODEV);
}
printk(KERN_INFO "mISDN: %s config irq:%d base:0x%X\n",
(fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" :
(fc->type == AVM_FRITZ_PCIV2) ? "AVM Fritz!PCIv2" : "AVM Fritz!PnP",
fc->irq, fc->addr);
fc->dch.hw = &fc->isac;
return(0);
}
static void
release_card(fritzpnppci *card)
{
u_long flags;
disable_hwirq(card);
spin_lock_irqsave(&card->lock, flags);
modehdlc(&card->bch[0], 0, ISDN_PID_NONE);
modehdlc(&card->bch[1], 1, ISDN_PID_NONE);
mISDN_isac_free(&card->dch);
spin_unlock_irqrestore(&card->lock, flags);
free_irq(card->irq, card);
spin_lock_irqsave(&card->lock, flags);
release_region(card->addr, 32);
mISDN_freechannel(&card->bch[1]);
mISDN_freechannel(&card->bch[0]);
mISDN_freechannel(&card->dch);
spin_unlock_irqrestore(&card->lock, flags);
mISDN_ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
spin_lock_irqsave(&fritz.lock, flags);
list_del(&card->list);
spin_unlock_irqrestore(&fritz.lock, flags);
if (card->type == AVM_FRITZ_PNP) {
#if defined(CONFIG_PNP)
pnp_disable_dev(card->dev.pnp);
pnp_set_drvdata(card->dev.pnp, NULL);
#endif
} else {
pci_disable_device(card->dev.pci);
pci_set_drvdata(card->dev.pci, NULL);
}
kfree(card);
}
static int
fritz_manager(void *data, u_int prim, void *arg) {
fritzpnppci *card;
mISDNinstance_t *inst = data;
struct sk_buff *skb;
u_long flags;
int channel = -1;
if (debug & 0x10000)
printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n",
__FUNCTION__, data, prim, arg);
if (!data) {
MGR_HASPROTOCOL_HANDLER(prim,arg,&fritz)
printk(KERN_ERR "%s: no data prim %x arg %p\n",
__FUNCTION__, prim, arg);
return(-EINVAL);
}
spin_lock_irqsave(&fritz.lock, flags);
list_for_each_entry(card, &fritz.ilist, list) {
if (&card->dch.inst == inst) {
channel = 2;
break;
}
if (&card->bch[0].inst == inst) {
channel = 0;
break;
}
if (&card->bch[1].inst == inst) {
channel = 1;
break;
}
}
spin_unlock_irqrestore(&fritz.lock, flags);
if (channel<0) {
printk(KERN_WARNING "%s: no channel data %p prim %x arg %p\n",
__FUNCTION__, data, prim, arg);
return(-EINVAL);
}
switch(prim) {
case MGR_REGLAYER | CONFIRM:
if (channel == 2)
mISDN_setpara(&card->dch, &inst->st->para);
else
mISDN_setpara(&card->bch[channel], &inst->st->para);
break;
case MGR_UNREGLAYER | REQUEST:
if ((skb = create_link_skb(PH_CONTROL | REQUEST,
HW_DEACTIVATE, 0, NULL, 0))) {
if (channel == 2) {
if (mISDN_ISAC_l1hw(inst, skb))
dev_kfree_skb(skb);
} else {
if (hdlc_down(inst, skb))
dev_kfree_skb(skb);
}
} else
printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
break;
case MGR_CLRSTPARA | INDICATION:
arg = NULL;
case MGR_ADDSTPARA | INDICATION:
if (channel == 2)
mISDN_setpara(&card->dch, arg);
else
mISDN_setpara(&card->bch[channel], arg);
break;
case MGR_RELEASE | INDICATION:
if (channel == 2) {
release_card(card);
} else {
fritz.refcnt--;
}
break;
case MGR_SETSTACK | INDICATION:
if ((channel!=2) && (inst->pid.global == 2)) {
if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
0, 0, NULL, 0))) {
if (hdlc_down(inst, skb))
dev_kfree_skb(skb);
}
if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
0, 0, NULL, 0);
else
mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
0, 0, NULL, 0);
}
break;
PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION);
PRIM_NOT_HANDLED(MGR_GLOBALOPT | REQUEST);
default:
printk(KERN_WARNING "%s: prim %x not handled\n",
__FUNCTION__, prim);
return(-EINVAL);
}
return(0);
}
static int __devinit setup_instance(fritzpnppci *card)
{
int i, err;
mISDN_pid_t pid;
u_long flags;
struct device *dev;
if (card->type == AVM_FRITZ_PNP) {
#if defined(CONFIG_PNP)
dev = &card->dev.pnp->dev;
#else
dev = NULL;
#endif
} else {
dev = &card->dev.pci->dev;
}
spin_lock_irqsave(&fritz.lock, flags);
list_add_tail(&card->list, &fritz.ilist);
spin_unlock_irqrestore(&fritz.lock, flags);
card->dch.debug = debug;
spin_lock_init(&card->lock);
card->dch.inst.hwlock = &card->lock;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
card->dch.inst.class_dev.parent = dev;
#else
card->dch.inst.class_dev.dev = dev;
#endif
card->dch.inst.pid.layermask = ISDN_LAYER(0);
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
mISDN_init_instance(&card->dch.inst, &fritz, card, mISDN_ISAC_l1hw);
sprintf(card->dch.inst.name, "Fritz%d", fritz_cnt+1);
mISDN_set_dchannel_pid(&pid, protocol[fritz_cnt], layermask[fritz_cnt]);
mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
for (i=0; i<2; i++) {
card->bch[i].channel = i;
mISDN_init_instance(&card->bch[i].inst, &fritz, card, hdlc_down);
card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
card->bch[i].inst.hwlock = &card->lock;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
card->bch[i].inst.class_dev.parent = dev;
#else
card->bch[i].inst.class_dev.dev = dev;
#endif
card->bch[i].debug = debug;
sprintf(card->bch[i].inst.name, "%s B%d", card->dch.inst.name, i+1);
mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
card->bch[i].hw = &card->hdlc[i];
}
printk(KERN_DEBUG "fritz card %p dch %p bch1 %p bch2 %p\n",
card, &card->dch, &card->bch[0], &card->bch[1]);
err = setup_fritz(card);
if (err) {
mISDN_freechannel(&card->dch);
mISDN_freechannel(&card->bch[1]);
mISDN_freechannel(&card->bch[0]);
spin_lock_irqsave(&fritz.lock, flags);
list_del(&card->list);
spin_unlock_irqrestore(&fritz.lock, flags);
kfree(card);
return(err);
}
fritz_cnt++;
err = mISDN_ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->dch.inst);
if (err) {
release_card(card);
return(err);
}
for (i=0; i<2; i++) {
err = mISDN_ctrl(card->dch.inst.st, MGR_NEWSTACK | REQUEST, &card->bch[i].inst);
if (err) {
printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
return(err);
}
}
err = mISDN_ctrl(card->dch.inst.st, MGR_SETSTACK | REQUEST, &pid);
if (err) {
printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", err);
mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
return(err);
}
err = init_card(card);
if (err) {
mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
return(err);
}
mISDN_ctrl(card->dch.inst.st, MGR_CTRLREADY | INDICATION, NULL);
printk(KERN_INFO "fritz %d cards installed\n", fritz_cnt);
return(0);
}
static int __devinit fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int err = -ENOMEM;
fritzpnppci *card;
if (!(card = kmalloc(sizeof(fritzpnppci), GFP_ATOMIC))) {
printk(KERN_ERR "No kmem for fritzcard\n");
return(err);
}
memset(card, 0, sizeof(fritzpnppci));
if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
card->type = AVM_FRITZ_PCIV2;
else
card->type = AVM_FRITZ_PCI;
card->dev.pci = pdev;
err = pci_enable_device(pdev);
if (err) {
kfree(card);
return(err);
}
printk(KERN_INFO "mISDN_fcpcipnp: found adapter %s at %s\n",
(char *) ent->driver_data, pci_name(pdev));
card->addr = pci_resource_start(pdev, 1);
card->irq = pdev->irq;
pci_set_drvdata(pdev, card);
err = setup_instance(card);
if (err)
pci_set_drvdata(pdev, NULL);
return(err);
}
#if defined(CONFIG_PNP)
#ifdef NEW_ISAPNP
static int __devinit fritzpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
#else
static int __devinit fritzpnp_probe(struct pci_dev *pdev, const struct isapnp_device_id *dev_id)
#endif
{
int err;
fritzpnppci *card;
if (!pdev)
return(-ENODEV);
if (!(card = kmalloc(sizeof(fritzpnppci), GFP_ATOMIC))) {
printk(KERN_ERR "No kmem for fritzcard\n");
return(-ENOMEM);
}
memset(card, 0, sizeof(fritzpnppci));
card->type = AVM_FRITZ_PNP;
card->dev.pnp = pdev;
pnp_disable_dev(pdev);
err = pnp_activate_dev(pdev);
if (err<0) {
printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__,
(char *)dev_id->driver_data, err);
kfree(card);
return(err);
}
card->addr = pnp_port_start(pdev, 0);
card->irq = pnp_irq(pdev, 0);
printk(KERN_INFO "mISDN_fcpcipnp: found adapter %s at IO %#x irq %d\n",
(char *)dev_id->driver_data, card->addr, card->irq);
pnp_set_drvdata(pdev, card);
err = setup_instance(card);
if (err)
pnp_set_drvdata(pdev, NULL);
return(err);
}
#endif /* CONFIG_PNP */
static void __devexit fritz_remove_pci(struct pci_dev *pdev)
{
fritzpnppci *card = pci_get_drvdata(pdev);
if (card)
mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
else
printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
}
#if defined(CONFIG_PNP)
#ifdef NEW_ISAPNP
static void __devexit fritz_remove_pnp(struct pnp_dev *pdev)
#else
static void __devexit fritz_remove_pnp(struct pci_dev *pdev)
#endif
{
fritzpnppci *card = pnp_get_drvdata(pdev);
if (card)
mISDN_ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
else
printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__);
}
#endif /* CONFIG_PNP */
static struct pci_device_id fcpci_ids[] __devinitdata = {
{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1 , PCI_ANY_ID, PCI_ANY_ID,
0, 0, (unsigned long) "Fritz!Card PCI" },
{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
0, 0, (unsigned long) "Fritz!Card PCI v2" },
{ }
};
MODULE_DEVICE_TABLE(pci, fcpci_ids);
static struct pci_driver fcpci_driver = {
name: "fcpci",
probe: fritzpci_probe,
remove: __devexit_p(fritz_remove_pci),
id_table: fcpci_ids,
};
#if defined(CONFIG_PNP)
#ifdef NEW_ISAPNP
static struct pnp_device_id fcpnp_ids[] __devinitdata = {
{
.id = "AVM0900",
.driver_data = (unsigned long) "Fritz!Card PnP",
},
};
static struct pnp_driver fcpnp_driver = {
#else
static struct isapnp_device_id fcpnp_ids[] __devinitdata = {
{ ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900),
ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900),
(unsigned long) "Fritz!Card PnP" },
{ }
};
MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
static struct isapnp_driver fcpnp_driver = {
#endif
name: "fcpnp",
probe: fritzpnp_probe,
remove: __devexit_p(fritz_remove_pnp),
id_table: fcpnp_ids,
};
#endif /* CONFIG_PNP */
static char FritzName[] = "AVM Fritz";
static int __init Fritz_init(void)
{
int err;
#ifdef OLD_PCI_REGISTER_DRIVER
int pci_nr_found;
#endif
printk(KERN_INFO "AVM Fritz PCI/PnP driver Rev. %s\n", mISDN_getrev(avm_fritz_rev));
#ifdef MODULE
fritz.owner = THIS_MODULE;
#endif
spin_lock_init(&fritz.lock);
INIT_LIST_HEAD(&fritz.ilist);
fritz.name = FritzName;
fritz.own_ctrl = fritz_manager;
fritz.DPROTO.protocol[0] = ISDN_PID_L0_TE_S0;
fritz.BPROTO.protocol[1] = ISDN_PID_L1_B_64TRANS |
ISDN_PID_L1_B_64HDLC;
fritz.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANS;
if ((err = mISDN_register(&fritz))) {
printk(KERN_ERR "Can't register Fritz PCI error(%d)\n", err);
return(err);
}
err = pci_register_driver(&fcpci_driver);
if (err < 0)
goto out;
#ifdef OLD_PCI_REGISTER_DRIVER
pci_nr_found = err;
#endif
#if defined(CONFIG_PNP)
err = pnp_register_driver(&fcpnp_driver);
if (err < 0)
goto out_unregister_pci;
#endif
#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
#ifdef OLD_PCI_REGISTER_DRIVER
if (pci_nr_found + err == 0) {
err = -ENODEV;
goto out_unregister_isapnp;
}
#endif
#endif
mISDN_module_register(THIS_MODULE);
return 0;
#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
#ifdef OLD_PCI_REGISTER_DRIVER
out_unregister_isapnp:
#if defined(CONFIG_PNP)
pnp_unregister_driver(&fcpnp_driver);
#endif
#endif
#endif
#if defined(CONFIG_PNP)
out_unregister_pci:
#endif
pci_unregister_driver(&fcpci_driver);
out:
return err;
}
static void __exit Fritz_cleanup(void)
{
fritzpnppci *card, *next;
int err;
mISDN_module_unregister(THIS_MODULE);
if ((err = mISDN_unregister(&fritz))) {
printk(KERN_ERR "Can't unregister Fritz PCI error(%d)\n", err);
}
list_for_each_entry_safe(card, next, &fritz.ilist, list) {
printk(KERN_ERR "Fritz PCI card struct not empty refs %d\n",
fritz.refcnt);
release_card(card);
}
#if defined(CONFIG_PNP)
pnp_unregister_driver(&fcpnp_driver);
#endif
pci_unregister_driver(&fcpci_driver);
}
module_init(Fritz_init);
module_exit(Fritz_cleanup);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/capi.c 0000644 0000000 0000050 00000024412 11135651701 017451 0 ustar root src /* $Id: capi.c,v 1.21 2006/12/21 15:25:06 nadi Exp $
*
*/
#include
#include "core.h"
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
static char *capi_revision = "$Revision: 1.21 $";
static int debug = 0;
static mISDNobject_t capi_obj;
static char MName[] = "mISDN Capi 2.0";
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
#ifdef OLD_MODULE_PARAM
MODULE_PARM(debug, "1i");
#else
module_param(debug, uint, S_IRUGO | S_IWUSR);
#endif
#endif
static char deb_buf[256];
void capidebug(int level, char *fmt, ...)
{
va_list args;
if (debug & level) {
va_start(args, fmt);
vsprintf(deb_buf, fmt, args);
printk(KERN_DEBUG "%s\n", deb_buf);
va_end(args);
}
}
#ifdef OLDCAPI_DRIVER_INTERFACE
struct capi_driver_interface *cdrv_if;
#endif
struct kmem_cache *mISDN_cmsg_cp;
struct kmem_cache *mISDN_AppPlci_cp;
struct kmem_cache *mISDN_ncci_cp;
struct kmem_cache *mISDN_sspc_cp;
#ifdef MISDN_KMEM_DEBUG
static struct list_head mISDN_kmem_garbage = LIST_HEAD_INIT(mISDN_kmem_garbage);
_cmsg *
_kd_cmsg_alloc(char *fn, int line)
{
_kd_cmsg_t *ki = kmem_cache_alloc(mISDN_cmsg_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_CM;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->cm);
}
void
cmsg_free(_cmsg *cm)
{
km_dbg_item_t *kdi;
if (!cm) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(cm);
list_del(&kdi->head);
kmem_cache_free(mISDN_cmsg_cp, kdi);
}
AppPlci_t *
_kd_AppPlci_alloc(char *fn, int line)
{
_kd_AppPlci_t *ki = kmem_cache_alloc(mISDN_AppPlci_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_AP;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->ap);
}
void
AppPlci_free(AppPlci_t *ap)
{
km_dbg_item_t *kdi;
if (!ap) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(ap);
list_del(&kdi->head);
kmem_cache_free(mISDN_AppPlci_cp, kdi);
}
Ncci_t *
_kd_ncci_alloc(char *fn, int line)
{
_kd_Ncci_t *ki = kmem_cache_alloc(mISDN_ncci_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_NI;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->ni);
}
void
ncci_free(Ncci_t *ni)
{
km_dbg_item_t *kdi;
if (!ni) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(ni);
list_del(&kdi->head);
kmem_cache_free(mISDN_ncci_cp, kdi);
}
SSProcess_t *
_kd_SSProcess_alloc(char *fn, int line)
{
_kd_SSProcess_t *ki = kmem_cache_alloc(mISDN_sspc_cp, GFP_ATOMIC);
if (!ki)
return(NULL);
ki->kdi.typ = KM_DBG_TYP_SP;
INIT_LIST_HEAD(&ki->kdi.head);
ki->kdi.line = line;
ki->kdi.file = fn;
list_add_tail(&ki->kdi.head, &mISDN_kmem_garbage);
return(&ki->sp);
}
void
SSProcess_free(SSProcess_t *sp)
{
km_dbg_item_t *kdi;
if (!sp) {
int_errtxt("zero pointer free at %p", __builtin_return_address(0));
return;
}
kdi = KDB_GET_KDI(sp);
list_del(&kdi->head);
kmem_cache_free(mISDN_sspc_cp, kdi);
}
static void
free_garbage(void)
{
struct list_head *item, *next;
_kd_all_t *kda;
list_for_each_safe(item, next, &mISDN_kmem_garbage) {
kda = (_kd_all_t *)item;
printk(KERN_DEBUG "garbage item found (%p <- %p -> %p) type%ld allocated at %s:%d\n",
kda->kdi.head.prev, item, kda->kdi.head.next, kda->kdi.typ, kda->kdi.file, kda->kdi.line);
list_del(item);
switch(kda->kdi.typ) {
case KM_DBG_TYP_CM:
printk(KERN_DEBUG "cmsg cmd(%x,%x) appl(%x) addr(%x) nr(%d)\n",
kda->a.cm.Command,
kda->a.cm.Subcommand,
kda->a.cm.ApplId,
kda->a.cm.adr.adrController,
kda->a.cm.Messagenumber);
kmem_cache_free(mISDN_cmsg_cp, item);
break;
case KM_DBG_TYP_AP:
printk(KERN_DEBUG "AppPlci: PLCI(%x) m.state(%x) appl(%p)\n",
kda->a.ap.addr,
kda->a.ap.plci_m.state,
kda->a.ap.appl);
kmem_cache_free(mISDN_AppPlci_cp, item);
break;
case KM_DBG_TYP_NI:
printk(KERN_DEBUG "Ncci: NCCI(%x) state(%lx) m.state(%x) aplci(%p)\n",
kda->a.ni.addr,
kda->a.ni.state,
kda->a.ni.ncci_m.state,
kda->a.ni.AppPlci);
kmem_cache_free(mISDN_ncci_cp, item);
break;
case KM_DBG_TYP_SP:
printk(KERN_DEBUG "SSPc: addr(%x) id(%x) apid(%x) func(%x)\n",
kda->a.sp.addr,
kda->a.sp.invokeId,
kda->a.sp.ApplId,
kda->a.sp.Function);
kmem_cache_free(mISDN_sspc_cp, item);
break;
default:
printk(KERN_DEBUG "unknown garbage item(%p) type %ld\n",
item, kda->kdi.typ);
break;
}
}
}
#endif
static void CapiCachesFree(void)
{
#ifdef MISDN_KMEM_DEBUG
free_garbage();
#endif
if (mISDN_cmsg_cp) {
kmem_cache_destroy(mISDN_cmsg_cp);
mISDN_cmsg_cp = NULL;
}
if (mISDN_AppPlci_cp) {
kmem_cache_destroy(mISDN_AppPlci_cp);
mISDN_AppPlci_cp = NULL;
}
if (mISDN_ncci_cp) {
kmem_cache_destroy(mISDN_ncci_cp);
mISDN_ncci_cp = NULL;
}
if (mISDN_sspc_cp) {
kmem_cache_destroy(mISDN_sspc_cp);
mISDN_sspc_cp = NULL;
}
}
static int CapiNew(void)
{
mISDN_cmsg_cp = NULL;
mISDN_AppPlci_cp = NULL;
mISDN_ncci_cp = NULL;
mISDN_sspc_cp = NULL;
mISDN_cmsg_cp = kmem_cache_create("mISDN_cmesg",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_cmsg_t),
#else
sizeof(_cmsg),
#endif
0, 0, NULL
#ifdef MISDN_COMPAT_KMEMCACHE
, NULL
#endif
);
if (!mISDN_cmsg_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_AppPlci_cp = kmem_cache_create("mISDN_AppPlci",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_AppPlci_t),
#else
sizeof(AppPlci_t),
#endif
0, 0, NULL
#ifdef MISDN_COMPAT_KMEMCACHE
, NULL
#endif
);
if (!mISDN_AppPlci_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_ncci_cp = kmem_cache_create("mISDN_Ncci",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_Ncci_t),
#else
sizeof(Ncci_t),
#endif
0, 0, NULL
#ifdef MISDN_COMPAT_KMEMCACHE
, NULL
#endif
);
if (!mISDN_ncci_cp) {
CapiCachesFree();
return(-ENOMEM);
}
mISDN_sspc_cp = kmem_cache_create("mISDN_SSProc",
#ifdef MISDN_KMEM_DEBUG
sizeof(_kd_SSProcess_t),
#else
sizeof(SSProcess_t),
#endif
0, 0, NULL
#ifdef MISDN_COMPAT_KMEMCACHE
, NULL
#endif
);
if (!mISDN_sspc_cp) {
CapiCachesFree();
return(-ENOMEM);
}
#ifdef OLDCAPI_DRIVER_INTERFACE
cdrv_if = attach_capi_driver(&mISDN_driver);
if (!cdrv_if) {
CapiCachesFree();
printk(KERN_ERR "mISDN: failed to attach capi_driver\n");
return -EIO;
}
#endif
init_listen();
init_AppPlci();
init_ncci();
return 0;
}
static int
capi20_manager(void *data, u_int prim, void *arg) {
mISDNinstance_t *inst = data;
int found=0;
PLInst_t *plink = NULL;
Controller_t *ctrl;
u_long flags;
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "capi20_manager data:%p prim:%x arg:%p\n", data, prim, arg);
if (!data)
return(-EINVAL);
spin_lock_irqsave(&capi_obj.lock, flags);
list_for_each_entry(ctrl, &capi_obj.ilist, list) {
if (&ctrl->inst == inst) {
found++;
break;
}
list_for_each_entry(plink, &ctrl->linklist, list) {
if (&plink->inst == inst) {
found++;
break;
}
}
if (found)
break;
plink = NULL;
}
if (&ctrl->list == &capi_obj.ilist)
ctrl = NULL;
spin_unlock_irqrestore(&capi_obj.lock, flags);
if (prim == (MGR_NEWLAYER | REQUEST)) {
int ret = ControllerConstr(&ctrl, data, arg, &capi_obj);
if (!ret)
ctrl->debug = debug;
return(ret);
}
if (!ctrl) {
if (CAPI_DBG_WARN & debug)
printk(KERN_WARNING "capi20_manager setif no instance\n");
return(-EINVAL);
}
switch(prim) {
case MGR_NEWENTITY | CONFIRM:
ctrl->entity = (u_long)arg & 0xffffffff;
break;
#ifdef FIXME
case MGR_CONNECT | REQUEST:
return(mISDN_ConnectIF(inst, arg));
case MGR_SETIF | INDICATION:
case MGR_SETIF | REQUEST:
if (&ctrl->inst == inst)
return(mISDN_SetIF(inst, arg, prim, NULL, ControllerL3L4, ctrl));
else
return(AppPlcimISDN_SetIF(inst->data, prim, arg));
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
return(mISDN_DisConnectIF(inst, arg));
#endif
case MGR_SETSTACK | INDICATION:
if (!(&ctrl->inst == inst))
return(AppPlcimISDN_Active(inst->privat));
return(0);
case MGR_RELEASE | INDICATION:
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "release_capi20 id %x\n", ctrl->inst.st->id);
ControllerDestr(ctrl);
break;
case MGR_UNREGLAYER | REQUEST:
if (plink) {
plink->inst.function = NULL;
mISDN_ctrl(&plink->inst, MGR_UNREGLAYER | REQUEST, NULL);
}
break;
case MGR_CTRLREADY | INDICATION:
if (CAPI_DBG_INFO & debug)
printk(KERN_DEBUG "ctrl %x ready\n", ctrl->inst.st->id);
ControllerRun(ctrl);
break;
default:
if (CAPI_DBG_WARN & debug)
printk(KERN_WARNING "capi20_manager prim %x not handled\n", prim);
return(-EINVAL);
}
return(0);
}
int Capi20Init(void)
{
int err;
printk(KERN_INFO "%s driver file version %s\n", MName, mISDN_getrev(capi_revision));
#ifdef MODULE
capi_obj.owner = THIS_MODULE;
#endif
capi_obj.name = MName;
capi_obj.DPROTO.protocol[4] = ISDN_PID_L4_CAPI20;
capi_obj.BPROTO.protocol[4] = ISDN_PID_L4_B_CAPI20;
capi_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_TRANS;
capi_obj.own_ctrl = capi20_manager;
spin_lock_init(&capi_obj.lock);
INIT_LIST_HEAD(&capi_obj.ilist);
if ((err = CapiNew()))
return(err);
if ((err = mISDN_register(&capi_obj))) {
printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
#ifdef OLDCAPI_DRIVER_INTERFACE
detach_capi_driver(&mISDN_driver);
#endif
CapiCachesFree();
free_listen();
free_AppPlci();
free_ncci();
free_Application();
} else
mISDN_module_register(THIS_MODULE);
return(err);
}
#ifdef MODULE
static void Capi20cleanup(void)
{
int err;
Controller_t *contr, *next;
mISDN_module_unregister(THIS_MODULE);
if ((err = mISDN_unregister(&capi_obj))) {
printk(KERN_ERR "Can't unregister CAPI20 error(%d)\n", err);
}
if (!list_empty(&capi_obj.ilist)) {
printk(KERN_WARNING "mISDN controller list not empty\n");
list_for_each_entry_safe(contr, next, &capi_obj.ilist, list)
ControllerDestr(contr);
}
#ifdef OLDCAPI_DRIVER_INTERFACE
detach_capi_driver(&mISDN_driver);
#endif
free_Application();
CapiCachesFree();
free_listen();
free_AppPlci();
free_ncci();
}
module_init(Capi20Init);
module_exit(Capi20cleanup);
#endif
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/capi_enc.c 0000644 0000000 0000050 00000011527 11110524073 020273 0 ustar root src /* $Id: capi_enc.c,v 1.3 2003/11/21 22:29:41 keil Exp $
*
*/
#include "m_capi.h"
#include "asn1.h"
int capiEncodeWord(__u8 *p, __u16 i)
{
*p++ = i;
*p++ = i >> 8;
return 2;
}
int capiEncodeDWord(__u8 *p, __u32 i)
{
*p++ = i;
*p++ = i >> 8;
*p++ = i >> 16;
*p++ = i >> 24;
return 4;
}
int capiEncodeFacilityPartyNumber(__u8 *dest, struct PartyNumber *partyNumber)
{
__u8 *p;
p = &dest[1];
switch (partyNumber->type) {
case 0: // unknown
*p++ = 0;
*p++ = 0;
*p++ = 0;
strcpy(p, partyNumber->p.unknown); p += strlen(partyNumber->p.unknown);
break;
case 1: // publicPartyNumber
*p++ = 1;
*p++ = partyNumber->p.publicPartyNumber.publicTypeOfNumber << 4;
*p++ = 0;
strcpy(p, partyNumber->p.publicPartyNumber.numberDigits);
p += strlen(partyNumber->p.publicPartyNumber.numberDigits);
break;
default:
int_error();
}
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacilityPartyNumber2(__u8 *dest, struct ServedUserNr *servedUserNr)
{
if (servedUserNr->all) {
*dest++ = 0; // empty struct;
return 1;
}
return capiEncodeFacilityPartyNumber(dest, &servedUserNr->partyNumber);
}
int capiEncodeServedUserNumbers(__u8 *dest, struct ServedUserNumberList *list)
{
__u8 *p;
int i;
p = &dest[1];
for (i = 0; i < 10; i++) {
if (list->partyNumber[i].type >= 0)
p += capiEncodeFacilityPartyNumber(p, &list->partyNumber[i]);
}
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeInterrogateResponse(__u8 *dest, struct IntResult *intResult)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, intResult->procedure);
p += capiEncodeWord(p, intResult->basicService);
p += capiEncodeFacilityPartyNumber2(p, &intResult->servedUserNr);
p += capiEncodeFacilityPartyNumber(p, &intResult->address.partyNumber);
*p++ = 0; // subaddress
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeInterrogateResponseList(__u8 *dest, struct IntResultList *list)
{
__u8 *p;
int i;
p = &dest[1];
for (i = 0; i < 10; i++) {
if (list->intResult[i].basicService >= 0)
p += capiEncodeInterrogateResponse(p, &list->intResult[i]);
}
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacIndCFact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, SupplementaryServiceReason);
p += capiEncodeDWord(p, Handle);
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacIndCFdeact(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, SupplementaryServiceReason);
p += capiEncodeDWord(p, Handle);
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacIndCFinterParameters(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle,
struct IntResultList *list)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, SupplementaryServiceReason);
p += capiEncodeDWord(p, Handle);
p += capiEncodeInterrogateResponseList(p, list);
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacIndCFinterNumbers(__u8 *dest, __u16 SupplementaryServiceReason, __u32 Handle,
struct ServedUserNumberList *list)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, SupplementaryServiceReason);
p += capiEncodeDWord(p, Handle);
p += capiEncodeServedUserNumbers(p, list);
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacIndCFNotAct(__u8 *dest, struct ActDivNotification *actNot)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, actNot->procedure);
p += capiEncodeWord(p, actNot->basicService);
p += capiEncodeFacilityPartyNumber2(p, &actNot->servedUserNr);
p += capiEncodeFacilityPartyNumber(p, &actNot->address.partyNumber);
*p++ = 0; // sub
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacIndCFNotDeact(__u8 *dest, struct DeactDivNotification *deactNot)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, deactNot->procedure);
p += capiEncodeWord(p, deactNot->basicService);
p += capiEncodeFacilityPartyNumber2(p, &deactNot->servedUserNr);
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacConfStruct(__u8 *dest, struct FacConfParm *facConfParm)
{
__u8 *p;
p = &dest[1];
switch (facConfParm->Function) {
case 0x0000:
p += capiEncodeWord(p, facConfParm->u.GetSupportedServices.SupplementaryServiceInfo);
p += capiEncodeDWord(p, facConfParm->u.GetSupportedServices.SupportedServices);
break;
default:
p += capiEncodeWord(p, facConfParm->u.Info.SupplementaryServiceInfo);
}
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacConfParm(__u8 *dest, struct FacConfParm *facConfParm)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, facConfParm->Function);
p += capiEncodeFacConfStruct(p, facConfParm);
dest[0] = p - &dest[1];
return p - dest;
}
int capiEncodeFacIndSuspend(__u8 *dest, __u16 SupplementaryServiceReason)
{
__u8 *p;
p = &dest[1];
p += capiEncodeWord(p, SupplementaryServiceReason);
dest[0] = p - &dest[1];
return p - dest;
}
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/channel.c 0000644 0000000 0000050 00000003360 11135651701 020144 0 ustar root src /* $Id: channel.c,v 1.2 2006/03/06 12:58:31 keil Exp $
*
* Author (c) Karsten Keil
*
* This file is released under the GPLv2
*
*/
#include
#include "channel.h"
#include "layer1.h"
int
mISDN_initchannel(channel_t *ch, ulong prop, int maxlen)
{
ch->log = kmalloc(MAX_LOG_SPACE, GFP_ATOMIC);
if (!ch->log) {
printk(KERN_WARNING
"mISDN: No memory for channel log\n");
return(-ENOMEM);
}
ch->Flags = prop;
ch->maxlen = maxlen;
ch->hw = NULL;
ch->rx_skb = NULL;
ch->tx_skb = NULL;
ch->tx_idx = 0;
ch->next_skb = NULL;
return(0);
}
int
mISDN_freechannel(channel_t *ch)
{
if (ch->tx_skb) {
dev_kfree_skb(ch->tx_skb);
ch->tx_skb = NULL;
}
if (ch->rx_skb) {
dev_kfree_skb(ch->rx_skb);
ch->rx_skb = NULL;
}
if (ch->next_skb) {
dev_kfree_skb(ch->next_skb);
ch->next_skb = NULL;
}
kfree(ch->log);
ch->log = NULL;
return(0);
}
/* need called with HW lock */
int
mISDN_setpara(channel_t *ch, mISDN_stPara_t *stp)
{
if (!stp) { // clear parameters
ch->maxlen = 0;
ch->up_headerlen = 0;
return(0);
}
if (stp->up_headerlen)
ch->up_headerlen = stp->up_headerlen;
if (stp->maxdatalen) {
if (ch->maxlen < stp->maxdatalen) {
if (ch->rx_skb) {
struct sk_buff *skb;
skb = alloc_skb(stp->maxdatalen +
ch->up_headerlen, GFP_ATOMIC);
if (!skb) {
int_errtxt("no skb for %d+%d", stp->maxdatalen, ch->up_headerlen);
return(-ENOMEM);
}
skb_reserve(skb, ch->up_headerlen);
memcpy(skb_put(skb, ch->rx_skb->len),
ch->rx_skb->data, ch->rx_skb->len);
dev_kfree_skb(ch->rx_skb);
ch->rx_skb = skb;
}
}
ch->maxlen = stp->maxdatalen;
}
return(0);
}
EXPORT_SYMBOL(mISDN_initchannel);
EXPORT_SYMBOL(mISDN_freechannel);
EXPORT_SYMBOL(mISDN_setpara);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/channel.h 0000644 0000000 0000050 00000010551 11135651701 020151 0 ustar root src /* $Id: channel.h,v 1.4 2006/09/07 13:02:34 crich Exp $
*
* Basic declarations for a mISDN HW channel
*
* Author (c) Karsten Keil
*
* This file is released under the GPLv2
*
*/
#ifndef MISDN_CHANNEL_H
#define MISDN_CHANNEL_H
#include
#include
#include
#include
#include "helper.h"
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
#include "core.h"
#define MAX_DFRAME_LEN_L1 300
#define MAX_MON_FRAME 32
#define MAX_LOG_SPACE 2048
#define MISDN_COPY_SIZE 32
/* channel->Flags bit field */
#define FLG_TX_BUSY 0 // tx_buf in use
#define FLG_TX_NEXT 1 // next_skb in use
#define FLG_L1_BUSY 2 // L1 is permanent busy
#define FLG_USED 5 // channel is in use
#define FLG_ACTIVE 6 // channel is activated
#define FLG_BUSY_TIMER 7
/* channel type */
#define FLG_DCHANNEL 8 // channel is D-channel
#define FLG_BCHANNEL 9 // channel is B-channel
#define FLG_ECHANNEL 10 // channel is E-channel
#define FLG_TRANSPARENT 12 // channel use transparent data
#define FLG_HDLC 13 // channel use hdlc data
#define FLG_L2DATA 14 // channel use L2 DATA primitivs
#define FLG_ORIGIN 15 // channel is on origin site
/* channel specific stuff */
/* arcofi specific */
#define FLG_ARCOFI_TIMER 16
#define FLG_ARCOFI_ERROR 17
/* isar specific */
#define FLG_INITIALIZED 16
#define FLG_DLEETX 17
#define FLG_LASTDLE 18
#define FLG_FIRST 19
#define FLG_LASTDATA 20
#define FLG_NMD_DATA 21
#define FLG_FTI_RUN 22
#define FLG_LL_OK 23
#define FLG_LL_CONN 24
#define FLG_DTMFSEND 25
#define MSK_INIT_DCHANNEL ((1<Flags) ? DL_DATA : PH_DATA;
if (!skb) {
err = mISDN_queue_data(&ch->inst, FLG_MSG_UP, pr, dinfo, 0, NULL, ch->up_headerlen);
} else {
#ifdef CONFIG_MISDN_NETDEV
misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_UP);
#endif
if (ch->Flags & MSK_INIT_DCHANNEL)
mISDN_dt_new_frame(ch->inst.st, D_RX, skb, 1);
err = mISDN_queueup_newhead(&ch->inst, 0, pr, dinfo, skb);
}
if (unlikely(err)) {
int_errtxt("err=%d", err);
if (skb)
dev_kfree_skb(skb);
}
}
static inline int
channel_senddata(channel_t *ch, int di, struct sk_buff *skb)
{
/* HW lock must be obtained */
/* check oversize */
if (skb->len <= 0) {
printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__);
return(-EINVAL);
}
if (skb->len > ch->maxlen) {
printk(KERN_WARNING "%s: skb too large(%d/%d)\n",
__FUNCTION__, skb->len, ch->maxlen);
return(-EINVAL);
}
/* check for pending next_skb */
if (ch->next_skb) {
#ifdef DEBUG_NEXT_SKB_EXISTS
printk(KERN_WARNING "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n",
__FUNCTION__, skb->len, ch->next_skb->len);
#endif
return(-EBUSY);
}
if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) {
test_and_set_bit(FLG_TX_NEXT, &ch->Flags);
#ifdef CONFIG_MISDN_NETDEV
misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_DOWN);
#endif
if (ch->Flags & MSK_INIT_DCHANNEL)
mISDN_dt_new_frame(ch->inst.st, D_TX, skb, 1);
ch->next_skb = skb;
return(0);
} else {
/* write to fifo */
ch->tx_skb = skb;
ch->tx_idx = 0;
#ifdef CONFIG_MISDN_NETDEV
misdn_log_frame(ch->inst.st, skb->data, skb->len, FLG_MSG_DOWN);
#endif
if (ch->Flags & MSK_INIT_DCHANNEL)
mISDN_dt_new_frame(ch->inst.st, D_TX, skb, 1);
queue_ch_frame(ch, CONFIRM, di, NULL);
return(skb->len);
}
}
#endif
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/contr.c 0000644 0000000 0000050 00000047722 11135651701 017673 0 ustar root src /* $Id: contr.c,v 1.30 2006/09/14 15:51:46 gkelleter Exp $
*
*/
#include
#include
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
#define contrDebug(contr, lev, fmt, args...) \
if (contr->debug & lev) capidebug(lev, fmt, ## args)
void
ControllerDestr(Controller_t *contr)
{
mISDNinstance_t *inst = &contr->inst;
struct list_head *item, *next;
u_long flags;
spin_lock_irqsave(&contr->list_lock, flags);
list_for_each_safe(item, next, &contr->Applications) {
ApplicationDestr(list_entry(item, Application_t, head), 3);
}
if (contr->plcis) {
Plci_t *plci = contr->plcis;
int i;
for (i = 0; i < contr->maxplci; i++) {
AppPlci_t *aplci;
if (test_bit(PLCI_STATE_ACTIV, &plci->state)) {
if (plci->nAppl) {
printk(KERN_ERR "%s: PLCI(%x) still busy (%d)\n",
__FUNCTION__, plci->addr, plci->nAppl);
list_for_each_safe(item, next, &plci->AppPlcis) {
aplci = (AppPlci_t *)item;
aplci->contr = NULL;
plciDetachAppPlci(plci, aplci);
AppPlciDestr(aplci);
}
}
}
plci++;
}
kfree(contr->plcis);
contr->plcis = NULL;
}
list_for_each_safe(item, next, &contr->SSProcesse) {
SSProcessDestr(list_entry(item, SSProcess_t, head));
}
#ifdef OLDCAPI_DRIVER_INTERFACE
if (contr->ctrl)
cdrv_if->detach_ctr(contr->ctrl);
#else
if (contr->ctrl) {
detach_capi_ctr(contr->ctrl);
kfree(contr->ctrl);
}
#endif
contr->ctrl = NULL;
#ifdef FIXME
if (inst->up.peer) {
mISDN_ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
}
if (inst->down.peer) {
mISDN_ctrl(inst->down.peer, MGR_DISCONNECT | REQUEST, &inst->down);
}
#endif
list_for_each_safe(item, next, &contr->linklist) {
PLInst_t *plink = list_entry(item, PLInst_t, list);
list_del(&plink->list);
kfree(plink);
}
if (contr->entity != MISDN_ENTITY_NONE)
mISDN_ctrl(inst, MGR_DELENTITY | REQUEST, (void *)((u_long)contr->entity));
mISDN_ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
list_del(&contr->list);
spin_unlock_irqrestore(&contr->list_lock, flags);
kfree(contr);
}
void
ControllerRun(Controller_t *contr)
{
PLInst_t *plink;
int ret;
if (contr->inst.st && contr->inst.st->mgr)
sprintf(contr->ctrl->manu, "mISDN CAPI controller %s", contr->inst.st->mgr->name);
else
sprintf(contr->ctrl->manu, "mISDN CAPI");
strncpy(contr->ctrl->serial, "0002", CAPI_SERIAL_LEN);
contr->ctrl->version.majorversion = 2;
contr->ctrl->version.minorversion = 0;
contr->ctrl->version.majormanuversion = 1;
contr->ctrl->version.minormanuversion = 0;
memset(&contr->ctrl->profile, 0, sizeof(struct capi_profile));
contr->ctrl->profile.ncontroller = cpu_to_le16(1);
contr->ctrl->profile.nbchannel = cpu_to_le16(contr->nr_bc);
contrDebug(contr, CAPI_DBG_INFO, "%s: %s version(%s)",
__FUNCTION__, contr->ctrl->manu, contr->ctrl->serial);
// FIXME
ret = mISDN_ctrl(contr->inst.st, MGR_GLOBALOPT | REQUEST, &contr->ctrl->profile.goptions);
if (ret) {
/* Fallback on error, minimum set */
contr->ctrl->profile.goptions = GLOBALOPT_INTERNAL_CTRL;
}
/* add options we allways know about FIXME: DTMF */
contr->ctrl->profile.goptions |= GLOBALOPT_DTMF |
GLOBALOPT_SUPPLEMENTARY_SERVICE;
if (contr->nr_bc) {
mISDN_pid_t pidmask;
memset(&pidmask, 0, sizeof(mISDN_pid_t));
pidmask.protocol[1] = 0x03ff;
pidmask.protocol[2] = 0x1fff;
pidmask.protocol[3] = 0x00ff;
if (list_empty(&contr->linklist)) {
int_error();
ret = -EINVAL;
} else {
plink = list_entry(contr->linklist.next, PLInst_t, list);
ret = mISDN_ctrl(plink->st, MGR_EVALSTACK | REQUEST, &pidmask);
}
if (ret) {
/* Fallback on error, minimum set */
int_error();
contr->ctrl->profile.support1 = 3; // HDLC, TRANS
contr->ctrl->profile.support2 = 3; // X75SLP, TRANS
contr->ctrl->profile.support3 = 1; // TRANS
} else {
contr->ctrl->profile.support1 = pidmask.protocol[1];
contr->ctrl->profile.support2 = pidmask.protocol[2];
contr->ctrl->profile.support3 = pidmask.protocol[3];
}
}
contrDebug(contr, CAPI_DBG_INFO, "%s: GLOBAL(%08X) B1(%08X) B2(%08X) B3(%08X)",
__FUNCTION__, contr->ctrl->profile.goptions, contr->ctrl->profile.support1,
contr->ctrl->profile.support2, contr->ctrl->profile.support3);
cpu_to_le32s(&contr->ctrl->profile.goptions);
cpu_to_le32s(&contr->ctrl->profile.support1);
cpu_to_le32s(&contr->ctrl->profile.support2);
cpu_to_le32s(&contr->ctrl->profile.support3);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->ready(contr->ctrl);
#else
capi_ctr_ready(contr->ctrl);
#endif
}
Application_t
*getApplication4Id(Controller_t *contr, __u16 ApplId)
{
struct list_head *item;
Application_t *ap = NULL;
list_for_each(item, &contr->Applications) {
ap = (Application_t *)item;
if (ap->ApplId == ApplId)
break;
ap = NULL;
}
return(ap);
}
Plci_t
*getPlci4Addr(Controller_t *contr, __u32 addr)
{
int i = (addr >> 8) & 0xff;
if ((i < 1) || (i > contr->maxplci)) {
int_error();
return(NULL);
}
return(&contr->plcis[i - 1]);
}
static void
RegisterApplication(struct capi_ctr *ctrl, __u16 ApplId, capi_register_params *rp)
{
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
u_long flags;
int ret;
contrDebug(contr, CAPI_DBG_APPL, "%s: ApplId(%x)", __FUNCTION__, ApplId);
appl = getApplication4Id(contr, ApplId);
if (appl) {
int_error();
return;
}
spin_lock_irqsave(&contr->list_lock, flags);
ret = ApplicationConstr(contr, ApplId, rp);
spin_unlock_irqrestore(&contr->list_lock, flags);
if (ret) {
int_error();
return;
}
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->appl_registered(contr->ctrl, ApplId);
#endif
}
static void
ReleaseApplication(struct capi_ctr *ctrl, __u16 ApplId)
{
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
u_long flags;
contrDebug(contr, CAPI_DBG_APPL, "%s: ApplId(%x) caller:%lx", __FUNCTION__, ApplId, __builtin_return_address(0));
spin_lock_irqsave(&contr->list_lock, flags);
appl = getApplication4Id(contr, ApplId);
if (!appl) {
spin_unlock_irqrestore(&contr->list_lock, flags);
int_error();
return;
}
ApplicationDestr(appl, 1);
spin_unlock_irqrestore(&contr->list_lock, flags);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->appl_released(contr->ctrl, ApplId);
#endif
}
#ifdef OLDCAPI_DRIVER_INTERFACE
static void
#else
static u16
#endif
SendMessage(struct capi_ctr *ctrl, struct sk_buff *skb)
{
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
int ApplId;
int err = CAPI_NOERROR;
u16 cmd;
AppPlci_t *aplci;
Ncci_t *ncci;
mISDN_head_t *hh = mISDN_HEAD_P(skb);
ApplId = CAPIMSG_APPID(skb->data);
appl = getApplication4Id(contr, ApplId);
if (!appl) {
int_error();
err = CAPI_ILLAPPNR;
goto end;
}
hh->prim = CAPI_MESSAGE_REQUEST;
hh->dinfo = ApplId;
cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
contrDebug(contr, CAPI_DBG_CONTR_MSG, "SendMessage: %s caddr(%x)",
capi_cmd2str(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data)),
CAPIMSG_CONTROL(skb->data));
switch (cmd) {
// for NCCI state machine
case CAPI_DATA_B3_REQ:
case CAPI_DATA_B3_RESP:
case CAPI_CONNECT_B3_RESP:
case CAPI_CONNECT_B3_ACTIVE_RESP:
case CAPI_DISCONNECT_B3_REQ:
case CAPI_RESET_B3_REQ:
case CAPI_RESET_B3_RESP:
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
dev_kfree_skb(skb);
break;
}
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT);
if ((!ncci) || (!ncci->link)) {
int_error();
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
dev_kfree_skb(skb);
break;
}
err = mISDN_queue_message(&ncci->link->inst, 0, skb);
if (err) {
int_errtxt("mISDN_queue_message return(%d)", err);
err = CAPI_MSGBUSY;
}
break;
// new NCCI
case CAPI_CONNECT_B3_REQ:
// maybe already down NCCI
case CAPI_DISCONNECT_B3_RESP:
// for PLCI state machine
case CAPI_INFO_REQ:
case CAPI_ALERT_REQ:
case CAPI_CONNECT_REQ:
case CAPI_CONNECT_RESP:
case CAPI_CONNECT_ACTIVE_RESP:
case CAPI_DISCONNECT_REQ:
case CAPI_DISCONNECT_RESP:
case CAPI_SELECT_B_PROTOCOL_REQ:
// for LISTEN state machine
case CAPI_LISTEN_REQ:
// other
case CAPI_FACILITY_REQ:
case CAPI_MANUFACTURER_REQ:
case CAPI_INFO_RESP:
err = mISDN_queue_message(&contr->inst, 0, skb);
if (err) {
int_errtxt("mISDN_queue_message return(%d)", err);
err = CAPI_MSGBUSY;
}
break;
/* need not further action currently, so it can be released here too avoid
* overlap with a release application
*/
case CAPI_FACILITY_RESP:
dev_kfree_skb(skb);
break;
default:
contrDebug(contr, CAPI_DBG_WARN, "SendMessage: %#x %#x not handled!",
CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
err = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
break;
}
end:
#ifndef OLDCAPI_DRIVER_INTERFACE
return(err);
#endif
}
static int
LoadFirmware(struct capi_ctr *ctrl, capiloaddata *data)
{
Controller_t *contr = ctrl->driverdata;
struct firm {
int len;
void *data;
} firm;
int retval;
firm.len = data->firmware.len;
if (data->firmware.user) {
firm.data = vmalloc(data->firmware.len);
if (!firm.data)
return(-ENOMEM);
retval = copy_from_user(firm.data, data->firmware.data, data->firmware.len);
if (retval) {
vfree(firm.data);
return(retval);
}
} else
firm.data = data;
mISDN_ctrl(contr->inst.st, MGR_LOADFIRM | REQUEST, &firm);
if (data->firmware.user)
vfree(firm.data);
return(0);
}
static char *
procinfo(struct capi_ctr *ctrl)
{
Controller_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & contr->debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
if (!contr)
return "";
sprintf(contr->infobuf, "-");
return contr->infobuf;
}
static int
read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
{
int len = 0;
len += sprintf(page+len, "mISDN_read_proc\n");
if (off+count >= len)
*eof = 1;
if (len < off)
return 0;
*start = page + off;
return ((count < len-off) ? count : len-off);
};
static void
ResetController(struct capi_ctr *ctrl)
{
Controller_t *contr = ctrl->driverdata;
struct list_head *item, *next;
u_long flags;
spin_lock_irqsave(&contr->list_lock, flags);
list_for_each_safe(item, next, &contr->Applications) {
ApplicationDestr((Application_t *)item, 2);
}
list_for_each_safe(item, next, &contr->SSProcesse) {
SSProcessDestr((SSProcess_t *)item);
}
spin_unlock_irqrestore(&contr->list_lock, flags);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->reseted(contr->ctrl);
#else
capi_ctr_reseted(contr->ctrl);
#endif
}
#ifdef OLDCAPI_DRIVER_INTERFACE
static void
Remove_Controller(struct capi_ctr *ctrl)
{
Controller_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & contr->debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
}
struct capi_driver mISDN_driver = {
"mISDN",
"0.01",
LoadFirmware,
ResetController,
Remove_Controller,
RegisterApplication,
ReleaseApplication,
SendMessage,
procinfo,
read_proc,
0,
0,
};
#endif
void
ControllerD2Trace(Controller_t *contr, u_char *buf, int len)
{
struct list_head *item;
list_for_each(item, &contr->Applications) {
applD2Trace((Application_t *)item, buf, len);
}
}
static __inline__ Plci_t *
getPlci4L3id(Controller_t *contr, u_int l3id)
{
Plci_t *plci = contr->plcis;
int i;
for (i = 0; i < contr->maxplci; i++) {
if (test_bit(PLCI_STATE_ACTIV, &plci->state) &&
(plci->l3id == l3id))
return(plci);
plci++;
}
return(NULL);
}
int
ControllerNewPlci(Controller_t *contr, Plci_t **plci_p, u_int l3id)
{
int i;
Plci_t *plci = contr->plcis;
for (i = 0; i < contr->maxplci; i++) {
if (!test_and_set_bit(PLCI_STATE_ACTIV, &plci->state))
break;
plci++;
}
if (i == contr->maxplci) {
contrDebug(contr, CAPI_DBG_PLCI, "%s: no free PLCI",
__FUNCTION__);
return(-EBUSY); //FIXME
}
*plci_p = plci;
if (l3id == MISDN_ID_ANY) {
if (contr->entity == MISDN_ENTITY_NONE) {
printk(KERN_ERR "mISDN %s: no ENTITY id\n",
__FUNCTION__);
test_and_clear_bit(PLCI_STATE_ACTIV, &plci->state);
return(-EINVAL); //FIXME
}
plci->l3id = (contr->entity << 16) | plci->addr;
} else {
plci = getPlci4L3id(contr, l3id);
if (plci) {
printk(KERN_WARNING "mISDN %s: PLCI(%x) allready has l3id(%x)\n",
__FUNCTION__, plci->addr, l3id);
test_and_clear_bit(PLCI_STATE_ACTIV, &(*plci_p)->state);
return(-EBUSY);
}
plci = *plci_p;
plci->l3id = l3id;
}
contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p,%d) id(%x)",
__FUNCTION__, plci->addr, plci, sizeof(*plci), plci->l3id);
return(0);
}
int
ControllerReleasePlci(Plci_t *plci)
{
if (!plci->contr) {
int_error();
return(-EINVAL);
}
if (plci->nAppl) {
contrDebug(plci->contr, CAPI_DBG_PLCI, "%s: PLCI(%x) still has %d Applications",
__FUNCTION__, plci->addr, plci->nAppl);
return(-EBUSY);
}
if (!list_empty(&plci->AppPlcis)) {
int_errtxt("PLCI(%x) AppPlcis list not empty", plci->addr);
return(-EBUSY);
}
test_and_clear_bit(PLCI_STATE_ALERTING, &plci->state);
test_and_clear_bit(PLCI_STATE_OUTGOING, &plci->state);
plci->l3id = MISDN_ID_NONE;
if (!test_and_clear_bit(PLCI_STATE_ACTIV, &plci->state))
int_errtxt("PLCI(%x) was not activ", plci->addr);
return(0);
}
void
ControllerAddSSProcess(Controller_t *contr, SSProcess_t *sp)
{
u_long flags;
INIT_LIST_HEAD(&sp->head);
sp->contr = contr;
sp->addr = contr->addr;
spin_lock_irqsave(&contr->list_lock, flags);
contr->LastInvokeId++;
sp->invokeId = contr->LastInvokeId;
list_add(&sp->head, &contr->SSProcesse);
spin_unlock_irqrestore(&contr->list_lock, flags);
}
SSProcess_t
*getSSProcess4Id(Controller_t *contr, __u16 id)
{
struct list_head *item;
SSProcess_t *sp = NULL;
list_for_each(item, &contr->SSProcesse) {
sp = (SSProcess_t *)item;
if (sp->invokeId == id)
break;
sp = NULL;
}
return(sp);
}
static int
Controller_function(mISDNinstance_t *inst, struct sk_buff *skb)
{
Controller_t *contr;
Plci_t *plci;
int ret = -EINVAL;
mISDN_head_t *hh;
hh = mISDN_HEAD_P(skb);
contr = inst->privat;
contrDebug(contr, CAPI_DBG_CONTR_INFO, "%s: prim(%x) id(%x)",
__FUNCTION__, hh->prim, hh->dinfo);
if (hh->prim == CAPI_MESSAGE_REQUEST) {
Application_t *appl = getApplication4Id(contr, hh->dinfo);
if (!appl) {
int_error();
return(ret);
}
ApplicationSendMessage(appl, skb);
return(0);
} else if (hh->prim == (CC_NEW_CR | INDICATION)) {
ret = ControllerNewPlci(contr, &plci, hh->dinfo);
if(!ret)
dev_kfree_skb(skb);
} else if (hh->dinfo == MISDN_ID_DUMMY) {
contrDebug(contr, CAPI_DBG_CONTR_INFO, "%s: call Supplementary_l3l4 len %d",
__FUNCTION__, skb->len);
ret = Supplementary_l3l4(contr, hh->prim, skb);
} else {
if (!(plci = getPlci4L3id(contr, hh->dinfo))) {
contrDebug(contr, CAPI_DBG_WARN, "%s: unknown plci prim(%x) id(%x)",
__FUNCTION__, hh->prim, hh->dinfo);
return(-ENODEV);
}
contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p)", __FUNCTION__, plci->addr, plci);
ret = plci_l3l4(plci, hh->prim, skb);
}
return(ret);
}
int
ControllerL4L3(Controller_t *contr, u_int prim, int dinfo, struct sk_buff *skb)
{
return(mISDN_queuedown_newhead(&contr->inst, 0, prim, dinfo, skb));
}
void
ControllerPutStatus(Controller_t *contr, char *msg)
{
contrDebug(contr, CAPI_DBG_CONTR, "%s: %s", __FUNCTION__, msg);
}
int
ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *ocapi)
{
struct list_head *head;
Controller_t *contr;
int retval;
mISDNstack_t *cst;
PLInst_t *plink;
u_long flags;
if (!st)
return(-EINVAL);
if (list_empty(&st->childlist)) {
if ((st->id & FLG_CLONE_STACK) &&
(st->childlist.prev != &st->childlist)) {
head = st->childlist.prev;
} else {
printk(KERN_ERR "%s: invalid empty childlist (no clone) stid(%x) childlist(%p<-%p->%p)\n",
__FUNCTION__, st->id, st->childlist.prev, &st->childlist, st->childlist.next);
return(-EINVAL);
}
} else
head = &st->childlist;
if (!pid)
return(-EINVAL);
contr = kmalloc(sizeof(Controller_t), GFP_KERNEL);
if (!contr)
return(-ENOMEM);
memset(contr, 0, sizeof(Controller_t));
INIT_LIST_HEAD(&contr->Applications);
INIT_LIST_HEAD(&contr->SSProcesse);
INIT_LIST_HEAD(&contr->linklist);
spin_lock_init(&contr->list_lock);
contr->next_id = 1;
memcpy(&contr->inst.pid, pid, sizeof(mISDN_pid_t));
#ifndef OLDCAPI_DRIVER_INTERFACE
if (!(contr->ctrl = kmalloc(sizeof(struct capi_ctr), GFP_KERNEL))) {
printk(KERN_ERR "no mem for contr->ctrl\n");
int_error();
ControllerDestr(contr);
return -ENOMEM;
}
memset(contr->ctrl, 0, sizeof(struct capi_ctr));
#endif
list_for_each_entry(cst, head, list)
contr->nr_bc++;
if (!contr->nr_bc) {
printk(KERN_ERR "no bchannels\n");
ControllerDestr(contr);
return(-EINVAL); // FIXME
}
if (contr->nr_bc <= 2)
contr->maxplci = CAPI_MAXPLCI_BRI;
else if (contr->nr_bc <= 8)
contr->maxplci = contr->nr_bc * 2 + 4;
else
contr->maxplci = CAPI_MAXPLCI_PRI;
contr->plcis = kmalloc(contr->maxplci*sizeof(Plci_t), GFP_KERNEL);
if (!contr->plcis) {
printk(KERN_ERR "no mem for contr->plcis\n");
int_error();
contr->maxplci = 0;
ControllerDestr(contr);
return -ENOMEM;
}
contr->addr = (st->id >> 8) & 0xff;
sprintf(contr->inst.name, "CAPI %d", contr->addr);
mISDN_init_instance(&contr->inst, ocapi, contr, Controller_function);
if (!mISDN_SetHandledPID(ocapi, &contr->inst.pid)) {
int_error();
ControllerDestr(contr);
return(-ENOPROTOOPT);
}
list_for_each_entry(cst, head, list) {
if (!(plink = kmalloc(sizeof(PLInst_t), GFP_KERNEL))) {
printk(KERN_ERR "no mem for PLinst\n");
int_error();
ControllerDestr(contr);
return -ENOMEM;
}
memset(plink, 0, sizeof(PLInst_t));
plink->st = cst;
plink->inst.st = cst;
mISDN_init_instance(&plink->inst, ocapi, plink, NULL);
plink->inst.pid.layermask |= ISDN_LAYER(4);
// plink->inst.down.stat = IF_NOACTIV;
list_add_tail(&plink->list, &contr->linklist);
}
spin_lock_irqsave(&ocapi->lock, flags);
list_add_tail(&contr->list, &ocapi->ilist);
spin_unlock_irqrestore(&ocapi->lock, flags);
contr->entity = MISDN_ENTITY_NONE;
retval = mISDN_ctrl(&contr->inst, MGR_NEWENTITY | REQUEST, NULL);
if (retval) {
printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
__FUNCTION__, retval);
}
retval = 0;
#ifdef OLDCAPI_DRIVER_INTERFACE
{
char tmp[10];
sprintf(tmp, "mISDN%d", (st->id >> 8) & 0xff);
contr->ctrl = cdrv_if->attach_ctr(&mISDN_driver, tmp, contr);
if (!contr->ctrl)
retval = -ENODEV;
}
#else
contr->ctrl->owner = THIS_MODULE;
sprintf(contr->ctrl->name, "mISDN%d", contr->addr);
contr->ctrl->driver_name = "mISDN";
contr->ctrl->driverdata = contr;
contr->ctrl->register_appl = RegisterApplication;
contr->ctrl->release_appl = ReleaseApplication;
contr->ctrl->send_message = SendMessage;
contr->ctrl->load_firmware = LoadFirmware;
contr->ctrl->reset_ctr = ResetController;
contr->ctrl->procinfo = procinfo;
contr->ctrl->ctr_read_proc = read_proc;
retval = attach_capi_ctr(contr->ctrl);
#endif
if (!retval) {
printk(KERN_DEBUG "contr->addr(%02x) cnr(%02x) st(%08x)\n",
contr->addr, contr->ctrl->cnr, st->id);
contr->addr = contr->ctrl->cnr;
plciInit(contr);
mISDN_ctrl(st, MGR_REGLAYER | INDICATION, &contr->inst);
// contr->inst.up.stat = IF_DOWN;
*contr_p = contr;
} else {
ControllerDestr(contr);
}
return retval;
}
PLInst_t *
ControllerSelChannel(Controller_t *contr, u_int channel)
{
mISDNstack_t *cst;
PLInst_t *plink;
channel_info_t ci;
int ret;
if (list_empty(&contr->linklist)) {
int_errtxt("no linklist for controller(%x)", contr->addr);
return(NULL);
}
ci.channel = channel;
ci.st.p = NULL;
ret = mISDN_ctrl(contr->inst.st, MGR_SELCHANNEL | REQUEST, &ci);
if (ret) {
int_errtxt("MGR_SELCHANNEL ret(%d)", ret);
return(NULL);
}
cst = ci.st.p;
list_for_each_entry(plink, &contr->linklist, list) {
if (cst == plink->st)
return(plink);
}
return(NULL);
}
int
ControllerNextId(Controller_t *contr)
{
int id;
id = contr->next_id++;
if (id == 0x7fff)
contr->next_id = 1;
id |= (contr->entity << 16);
return(id);
}
#if 0
static void
d2_listener(struct IsdnCardState *cs, u_char *buf, int len)
{
Controller_t *contr = cs->contr;
if (!contr) {
int_error();
return;
}
ControllerD2Trace(contr, buf, len);
}
#endif
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/core.c 0000644 0000000 0000050 00000047431 11135651701 017473 0 ustar root src /* $Id: core.c,v 1.40 2007/02/13 10:43:45 crich Exp $
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include
#include
#include
#include
#include "core.h"
#ifdef CONFIG_KMOD
#include
#endif
#ifdef CONFIG_SMP
#include
#endif
static char *mISDN_core_revision = "$Revision: 1.40 $";
static char *mISDN_core_version = MISDNVERSION ;
static void (*dt_new_frame) (mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb) = NULL;
LIST_HEAD(mISDN_objectlist);
static rwlock_t mISDN_objects_lock = RW_LOCK_UNLOCKED;
LIST_HEAD(mISDN_modulelist);
static rwlock_t mISDN_modules_lock = RW_LOCK_UNLOCKED;
struct modulelist {
struct list_head list;
struct module *module;
};
int core_debug;
static u_char entityarray[MISDN_MAX_ENTITY/8];
static spinlock_t entity_lock = SPIN_LOCK_UNLOCKED;
static uint debug;
static int obj_id;
static int dt_enabled = 0;
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
#ifdef OLD_MODULE_PARAM
MODULE_PARM(debug, "1i");
#else
module_param (debug, uint, S_IRUGO | S_IWUSR);
#endif
MODULE_PARM_DESC (debug, "mISDN core debug mask");
#endif
typedef struct _mISDN_thread {
/* thread */
struct task_struct *thread;
wait_queue_head_t waitq;
struct semaphore *notify;
u_long Flags;
struct sk_buff_head workq;
} mISDN_thread_t;
#define mISDN_TFLAGS_STARTED 0
#define mISDN_TFLAGS_RMMOD 1
#define mISDN_TFLAGS_ACTIV 2
#define mISDN_TFLAGS_TEST 3
static mISDN_thread_t mISDN_thread;
static moditem_t modlist[] = {
{"mISDN_l1", ISDN_PID_L1_TE_S0},
{"mISDN_l2", ISDN_PID_L2_LAPD},
{"mISDN_l2", ISDN_PID_L2_B_X75SLP},
{"l3udss1", ISDN_PID_L3_DSS1USER},
{"mISDN_dtmf", ISDN_PID_L2_B_TRANSDTMF},
{NULL, ISDN_PID_NONE}
};
/*
* kernel thread to do work which cannot be done
*in interrupt context
*/
static int
mISDNd(void *data)
{
mISDN_thread_t *hkt = data;
#ifdef CONFIG_SMP
lock_kernel();
#endif
MAKEDAEMON("mISDNd");
sigfillset(¤t->blocked);
hkt->thread = current;
#ifdef CONFIG_SMP
unlock_kernel();
#endif
printk(KERN_DEBUG "mISDNd: kernel daemon started (current:%p)\n", current);
test_and_set_bit(mISDN_TFLAGS_STARTED, &hkt->Flags);
for (;;) {
int err;
struct sk_buff *skb;
mISDN_headext_t *hhe;
if (test_and_clear_bit(mISDN_TFLAGS_RMMOD, &hkt->Flags))
break;
if (hkt->notify != NULL)
up(hkt->notify);
wait_event_interruptible(hkt->waitq, ((!skb_queue_empty(&hkt->workq)) || (hkt->Flags & 0xfffffffe)));
if (test_and_clear_bit(mISDN_TFLAGS_RMMOD, &hkt->Flags))
break;
while ((skb = skb_dequeue(&hkt->workq))) {
test_and_set_bit(mISDN_TFLAGS_ACTIV, &hkt->Flags);
err = -EINVAL;
hhe=mISDN_HEADEXT_P(skb);
switch (hhe->addr) {
case MGR_FUNCTION:
err = hhe->func.ctrl(hhe->data[0], hhe->prim,
skb->len ? skb->data : NULL);
if (err) {
printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) failed err(%d)\n",
hhe->addr, hhe->prim, err);
} else {
if (debug)
printk(KERN_DEBUG "mISDNd: addr(%x) prim(%x) success\n",
hhe->addr, hhe->prim);
err--; /* to free skb */
}
break;
#ifdef FIXME
case MGR_QUEUEIF:
err = hhe->func.iff(hhe->data[0], skb);
if (err) {
printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) failed err(%d)\n",
hhe->addr, hhe->prim, err);
}
break;
#endif
default:
int_error();
printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) unknown\n",
hhe->addr, hhe->prim);
err = -EINVAL;
break;
}
if (err)
kfree_skb(skb);
test_and_clear_bit(mISDN_TFLAGS_ACTIV, &hkt->Flags);
}
if (test_and_clear_bit(mISDN_TFLAGS_TEST, &hkt->Flags))
printk(KERN_DEBUG "mISDNd: test event done\n");
}
printk(KERN_DEBUG "mISDNd: daemon exit now (current:%p)\n", current);
test_and_clear_bit(mISDN_TFLAGS_STARTED, &hkt->Flags);
test_and_clear_bit(mISDN_TFLAGS_ACTIV, &hkt->Flags);
discard_queue(&hkt->workq);
hkt->thread = NULL;
if (hkt->notify != NULL)
up(hkt->notify);
return(0);
}
mISDNobject_t *
get_object(int id) {
mISDNobject_t *obj;
read_lock(&mISDN_objects_lock);
list_for_each_entry(obj, &mISDN_objectlist, list)
if (obj->id == id) {
read_unlock(&mISDN_objects_lock);
return(obj);
}
read_unlock(&mISDN_objects_lock);
return(NULL);
}
static mISDNobject_t *
find_object(int protocol) {
mISDNobject_t *obj;
int err;
read_lock(&mISDN_objects_lock);
list_for_each_entry(obj, &mISDN_objectlist, list) {
err = obj->own_ctrl(NULL, MGR_HASPROTOCOL | REQUEST, &protocol);
if (!err)
goto unlock;
if (err != -ENOPROTOOPT) {
if (0 == mISDN_HasProtocol(obj, protocol))
goto unlock;
}
}
obj = NULL;
unlock:
read_unlock(&mISDN_objects_lock);
return(obj);
}
static mISDNobject_t *
find_object_module(int protocol) {
#ifdef CONFIG_KMOD
int err;
#endif
moditem_t *m = modlist;
mISDNobject_t *obj;
while (m->name != NULL) {
if (m->protocol == protocol) {
#ifdef CONFIG_KMOD
if (debug)
printk(KERN_DEBUG
"find_object_module %s - trying to load\n",
m->name);
err=request_module(m->name);
if (debug)
printk(KERN_DEBUG "find_object_module: request_module(%s) returns(%d)\n",
m->name, err);
#else
printk(KERN_WARNING "not possible to autoload %s please try to load manually\n",
m->name);
#endif
if ((obj = find_object(protocol)))
return(obj);
}
m++;
}
if (debug)
printk(KERN_DEBUG "%s: no module for protocol %x found\n",
__FUNCTION__, protocol);
return(NULL);
}
#ifdef FIXME
static int
dummy_if(mISDNif_t *hif, struct sk_buff *skb)
{
if (!skb) {
printk(KERN_WARNING "%s: hif(%p) without skb\n",
__FUNCTION__, hif);
return(-EINVAL);
}
if (debug & DEBUG_DUMMY_FUNC) {
mISDN_head_t *hh = mISDN_HEAD_P(skb);
printk(KERN_DEBUG "%s: hif(%p) skb(%p) len(%d) prim(%x)\n",
__FUNCTION__, hif, skb, skb->len, hh->prim);
}
dev_kfree_skb_any(skb);
return(0);
}
#endif
mISDNinstance_t *
get_next_instance(mISDNstack_t *st, mISDN_pid_t *pid)
{
int err;
mISDNinstance_t *next;
int layer, proto;
mISDNobject_t *obj;
layer = mISDN_get_lowlayer(pid->layermask);
proto = pid->protocol[layer];
next = get_instance(st, layer, proto);
if (!next) {
obj = find_object(proto);
if (!obj)
obj = find_object_module(proto);
if (!obj) {
if (debug)
printk(KERN_WARNING "%s: no object found\n",
__FUNCTION__);
return(NULL);
}
err = obj->own_ctrl(st, MGR_NEWLAYER | REQUEST, pid);
if (err) {
printk(KERN_WARNING "%s: newlayer err(%d)\n",
__FUNCTION__, err);
return(NULL);
}
next = get_instance(st, layer, proto);
}
return(next);
}
static int
sel_channel(mISDNstack_t *st, channel_info_t *ci)
{
int err = -EINVAL;
if (!ci)
return(err);
if (debug)
printk(KERN_DEBUG "%s: st(%p) st->mgr(%p)\n",
__FUNCTION__, st, st->mgr);
if (st->mgr) {
if (st->mgr->obj && st->mgr->obj->own_ctrl) {
err = st->mgr->obj->own_ctrl(st->mgr, MGR_SELCHANNEL | REQUEST, ci);
if (debug)
printk(KERN_DEBUG "%s: MGR_SELCHANNEL(%d)\n", __FUNCTION__, err);
} else
int_error();
} else {
printk(KERN_WARNING "%s: no mgr st(%p)\n", __FUNCTION__, st);
}
if (err) {
mISDNstack_t *cst;
u_int nr = 0;
ci->st.p = NULL;
if (!(ci->channel & (~CHANNEL_NUMBER))) {
/* only number is set */
struct list_head *head;
if (list_empty(&st->childlist)) {
if ((st->id & FLG_CLONE_STACK) &&
(st->childlist.prev != &st->childlist)) {
head = st->childlist.prev;
} else {
printk(KERN_WARNING "%s: invalid empty childlist (no clone) stid(%x) childlist(%p<-%p->%p)\n",
__FUNCTION__, st->id, st->childlist.prev, &st->childlist, st->childlist.next);
return(err);
}
} else
head = &st->childlist;
list_for_each_entry(cst, head, list) {
nr++;
if (nr == (ci->channel & 3)) {
ci->st.p = cst;
return(0);
}
}
}
}
return(err);
}
#ifdef FIXME
static int
disconnect_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
int err = 0;
if (hif) {
hif->stat = IF_NOACTIV;
hif->func = dummy_if;
hif->peer = NULL;
hif->fdata = NULL;
}
if (inst)
err = inst->obj->own_ctrl(inst, prim, hif);
return(err);
}
static int
add_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
mISDNif_t *myif;
if (!inst)
return(-EINVAL);
if (!hif)
return(-EINVAL);
if (hif->stat & IF_UP) {
myif = &inst->down;
} else if (hif->stat & IF_DOWN) {
myif = &inst->up;
} else
return(-EINVAL);
while(myif->clone)
myif = myif->clone;
myif->clone = hif;
hif->predecessor = myif;
inst->obj->own_ctrl(inst, prim, hif);
return(0);
}
#endif
static char tmpbuf[4096];
static int
debugout(mISDNinstance_t *inst, logdata_t *log)
{
char *p = tmpbuf;
if (log->head && *log->head)
p += sprintf(p,"%s ", log->head);
else
p += sprintf(p,"%s ", inst->obj->name);
p += vsprintf(p, log->fmt, log->args);
printk(KERN_DEBUG "%s\n", tmpbuf);
return(0);
}
static int
get_hdevice(mISDNdevice_t **dev, int *typ)
{
if (!dev)
return(-EINVAL);
if (!typ)
return(-EINVAL);
#ifdef FIXME
if (*typ == mISDN_RAW_DEVICE) {
*dev = get_free_rawdevice();
if (!(*dev))
return(-ENODEV);
return(0);
}
#endif
return(-EINVAL);
}
#ifdef FIXME
static int
mgr_queue(void *data, u_int prim, struct sk_buff *skb)
{
mISDN_headext_t *hhe = mISDN_HEADEXT_P(skb);
hhe->addr = prim;
skb_queue_tail(&mISDN_thread.workq, skb);
wake_up_interruptible(&mISDN_thread.waitq);
return(0);
}
#endif
static int
set_stack_req(mISDNstack_t *st, mISDN_pid_t *pid)
{
struct sk_buff *skb;
mISDN_headext_t *hhe;
mISDN_pid_t *npid;
u_char *pbuf = NULL;
int err;
if (!(skb = alloc_skb(sizeof(mISDN_pid_t) + pid->maxplen, GFP_ATOMIC)))
return(-ENOMEM);
hhe = mISDN_HEADEXT_P(skb);
hhe->prim = MGR_SETSTACK_NW | REQUEST;
hhe->addr = MGR_FUNCTION;
hhe->data[0] = st;
npid = (mISDN_pid_t *)skb_put(skb, sizeof(mISDN_pid_t));
if (pid->maxplen)
pbuf = skb_put(skb, pid->maxplen);
err = copy_pid(npid, pid, pbuf);
if (err) // FIXME error handling
int_errtxt("copy_pid error %d", err);
hhe->func.ctrl = mISDN_ctrl;
skb_queue_tail(&mISDN_thread.workq, skb);
wake_up_interruptible(&mISDN_thread.waitq);
return(0);
}
static int
queue_ctrl_ready(mISDNstack_t *st, void *arg)
{
struct sk_buff *skb;
mISDN_headext_t *hhe;
if (!(skb = alloc_skb(4, GFP_ATOMIC)))
return(-ENOMEM);
if (arg) /* maybe changed for future enhancements */
return(-EINVAL);
hhe = mISDN_HEADEXT_P(skb);
hhe->prim = MGR_CTRLREADY | INDICATION;
hhe->addr = MGR_FUNCTION;
hhe->data[0] = st;
hhe->func.ctrl = do_for_all_layers;
skb_queue_tail(&mISDN_thread.workq, skb);
wake_up_interruptible(&mISDN_thread.waitq);
return(0);
}
int
mISDN_alloc_entity(int *entity)
{
u_long flags;
spin_lock_irqsave(&entity_lock, flags);
*entity = 1;
while(*entity < MISDN_MAX_ENTITY) {
if (!test_and_set_bit(*entity, (u_long *)&entityarray[0]))
break;
(*entity)++;
}
spin_unlock_irqrestore(&entity_lock, flags);
if (*entity == MISDN_MAX_ENTITY)
return(-EBUSY);
return(0);
}
int
mISDN_delete_entity(int entity)
{
u_long flags;
int ret = 0;
spin_lock_irqsave(&entity_lock, flags);
if (!test_and_clear_bit(entity, (u_long *)&entityarray[0])) {
printk(KERN_WARNING "mISDN: del_entity(%d) but entity not allocated\n", entity);
ret = -ENODEV;
}
spin_unlock_irqrestore(&entity_lock, flags);
return(ret);
}
static int
new_entity(mISDNinstance_t *inst)
{
int entity;
int ret;
if (!inst)
return(-EINVAL);
ret = mISDN_alloc_entity(&entity);
if (ret) {
printk(KERN_WARNING "mISDN: no more entity available(max %d)\n", MISDN_MAX_ENTITY);
return(ret);
}
ret = inst->obj->own_ctrl(inst, MGR_NEWENTITY | CONFIRM, (void *)((u_long)entity));
if (ret)
mISDN_delete_entity(entity);
return(ret);
}
int
mISDN_ctrl(void *data, u_int prim, void *arg) {
mISDNstack_t *st = data;
switch(prim) {
case MGR_NEWSTACK | REQUEST:
if (!(st = new_stack(data, arg)))
return(-EINVAL);
return(0);
case MGR_NEWENTITY | REQUEST:
return(new_entity(data));
case MGR_DELENTITY | REQUEST:
case MGR_DELENTITY | INDICATION:
return(mISDN_delete_entity((u_long)arg & 0xffffffff));
case MGR_REGLAYER | INDICATION:
return(register_layer(st, arg));
case MGR_REGLAYER | REQUEST:
if (!register_layer(st, arg)) {
mISDNinstance_t *inst = arg;
return(inst->obj->own_ctrl(arg, MGR_REGLAYER | CONFIRM, NULL));
}
return(-EINVAL);
case MGR_UNREGLAYER | REQUEST:
return(unregister_instance(data));
#ifdef FIXME
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
return(disconnect_if(data, prim, arg));
#endif
case MGR_GETDEVICE | REQUEST:
return(get_hdevice(data, arg));
case MGR_DELDEVICE | REQUEST:
return(free_device(data));
#ifdef FIXME
case MGR_QUEUEIF | REQUEST:
return(mgr_queue(data, MGR_QUEUEIF, arg));
#endif
}
if (!data)
return(-EINVAL);
switch(prim) {
case MGR_ADDLAYER | REQUEST:
return(preregister_layer(st, arg));
case MGR_SETSTACK | REQUEST:
/* can sleep in case of module reload */
#ifdef CONFIG_MISDN_NETDEV
misdn_netdev_addstack(st);
#endif
return(set_stack_req(st, arg));
case MGR_SETSTACK_NW | REQUEST:
return(set_stack(st, arg));
case MGR_CLEARSTACK | REQUEST:
return(clear_stack(st, arg ? 1 : 0));
case MGR_DELSTACK | REQUEST:
return(release_stack(st));
case MGR_SELCHANNEL | REQUEST:
return(sel_channel(st, arg));
case MGR_STOPSTACK | REQUEST:
return(mISDN_start_stop(st, 0));
case MGR_STARTSTACK | REQUEST:
return(mISDN_start_stop(st, 1));
#ifdef FIXME
case MGR_ADDIF | REQUEST:
return(add_if(data, prim, arg));
#endif
case MGR_CTRLREADY | INDICATION:
return(queue_ctrl_ready(st, arg));
case MGR_ADDSTPARA | REQUEST:
case MGR_CLRSTPARA | REQUEST:
return(change_stack_para(st, prim, arg));
#ifdef FIXME
case MGR_CONNECT | REQUEST:
return(mISDN_ConnectIF(data, arg));
#endif
case MGR_EVALSTACK | REQUEST:
return(evaluate_stack_pids(data, arg));
case MGR_GLOBALOPT | REQUEST:
case MGR_LOADFIRM | REQUEST:
if (st->mgr && st->mgr->obj && st->mgr->obj->own_ctrl)
return(st->mgr->obj->own_ctrl(st->mgr, prim, arg));
break;
case MGR_DEBUGDATA | REQUEST:
return(debugout(data, arg));
default:
if (debug)
printk(KERN_WARNING "manager prim %x not handled\n", prim);
break;
}
return(-EINVAL);
}
void
mISDN_dt_set_callback(void (*new_frame) (mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb))
{
dt_new_frame = new_frame;
}
void
mISDN_dt_unset_callback(void)
{
dt_new_frame = NULL;
}
void
mISDN_dt_enable(void)
{
dt_enabled = dt_new_frame ? 1 : 0;
}
void
mISDN_dt_disable(void)
{
dt_enabled = 0;
}
void
mISDN_dt_new_frame(mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb)
{
if (dt_enabled)
dt_new_frame(stack, type, skb, duplicate_skb);
else if (!duplicate_skb && skb)
kfree_skb(skb);
}
void
mISDN_module_register(struct module *module)
{
struct modulelist *ml = kmalloc(sizeof(struct modulelist), GFP_KERNEL);
if (!ml) {
printk(KERN_DEBUG "mISDN_register_module: kmalloc failed!\n");
return;
}
ml->module = module;
write_lock(&mISDN_modules_lock);
list_add(&ml->list, &mISDN_modulelist);
write_unlock(&mISDN_modules_lock);
if (debug)
printk(KERN_DEBUG "mISDN_register_module(%s)\n", module->name);
}
void
mISDN_module_unregister(struct module *module)
{
struct modulelist *ml, *mi;
write_lock(&mISDN_modules_lock);
list_for_each_entry_safe(ml, mi, &mISDN_modulelist, list)
if (ml->module == module) {
list_del(&ml->list);
kfree(ml);
write_unlock(&mISDN_modules_lock);
if (debug)
printk(KERN_DEBUG "mISDN_unregister_module(%s)\n",
module->name);
return;
}
write_unlock(&mISDN_modules_lock);
}
void
mISDN_inc_usage(void)
{
struct modulelist *ml;
read_lock(&mISDN_modules_lock);
list_for_each_entry(ml, &mISDN_modulelist, list)
try_module_get(ml->module);
read_unlock(&mISDN_modules_lock);
}
void
mISDN_dec_usage(void)
{
struct modulelist *ml;
read_lock(&mISDN_modules_lock);
list_for_each_entry(ml, &mISDN_modulelist, list) {
if (module_refcount(ml->module) > 0)
module_put(ml->module);
}
read_unlock(&mISDN_modules_lock);
}
int mISDN_register(mISDNobject_t *obj) {
u_long flags;
int retval=0;
if (!obj)
return(-EINVAL);
write_lock_irqsave(&mISDN_objects_lock, flags);
obj->id = obj_id++;
list_add_tail(&obj->list, &mISDN_objectlist);
write_unlock_irqrestore(&mISDN_objects_lock, flags);
// register_prop
if (debug)
printk(KERN_DEBUG "mISDN_register %s id %x\n", obj->name,
obj->id);
if (core_debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "mISDN_register: obj(%p)\n", obj);
#ifndef SYSFS_SUPPORT_2_6_24
retval = mISDN_register_sysfs_obj(obj);
if (retval) {
printk(KERN_ERR "mISDN_register class_device_register return(%d)\n", retval);
write_lock_irqsave(&mISDN_objects_lock, flags);
list_del(&obj->list);
write_unlock_irqrestore(&mISDN_objects_lock, flags);
}
#endif
return(retval);
}
int mISDN_unregister(mISDNobject_t *obj) {
u_long flags;
if (!obj)
return(-EINVAL);
if (debug)
printk(KERN_DEBUG "mISDN_unregister %s %d refs\n",
obj->name, obj->refcnt);
if (obj->DPROTO.protocol[0]) {
if (debug)
printk(KERN_DEBUG "mISDN_unregister stacks(%s)\n",
obj->name);
release_stacks(obj);
} else
cleanup_object(obj);
write_lock_irqsave(&mISDN_objects_lock, flags);
list_del(&obj->list);
write_unlock_irqrestore(&mISDN_objects_lock, flags);
if (core_debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "mISDN_unregister: mISDN_objectlist(%p<-%p->%p)\n",
mISDN_objectlist.prev, &mISDN_objectlist, mISDN_objectlist.next);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
device_unregister(&obj->class_dev);
#else
class_device_unregister(&obj->class_dev);
#endif
return(0);
}
int
mISDNInit(void)
{
struct semaphore sem;
int err;
init_MUTEX_LOCKED(&sem);
printk(KERN_INFO "Modular ISDN Stack core version (%s) revision (%s)\n", mISDN_core_version, mISDN_core_revision);
core_debug = debug;
#ifdef MISDN_MEMDEBUG
err = __mid_init();
if (err)
return(err);
#endif
err = mISDN_sysfs_init();
if (err)
goto sysfs_fail;
err = init_mISDNdev(debug);
if (err)
goto dev_fail;
#ifdef CONFIG_MISDN_NETDEV
misdn_netdev_init();
#endif
init_waitqueue_head(&mISDN_thread.waitq);
skb_queue_head_init(&mISDN_thread.workq);
mISDN_thread.notify = &sem;
kernel_thread(mISDNd, (void *)&mISDN_thread, 0);
down(&sem);
mISDN_thread.notify = NULL;
test_and_set_bit(mISDN_TFLAGS_TEST, &mISDN_thread.Flags);
wake_up_interruptible(&mISDN_thread.waitq);
return(err);
dev_fail:
mISDN_sysfs_cleanup();
sysfs_fail:
#ifdef MISDN_MEMDEBUG
__mid_cleanup();
#endif
return(err);
}
void mISDN_cleanup(void) {
struct semaphore sem;
init_MUTEX_LOCKED(&sem);
free_mISDNdev();
if (!list_empty(&mISDN_objectlist)) {
printk(KERN_WARNING "mISDNcore mISDN_objects not empty\n");
}
check_stacklist();
if (!list_empty(&mISDN_modulelist))
printk(KERN_WARNING "mISDNcore mISDN_modulelist not empty\n");
if (mISDN_thread.thread) {
/* abort mISDNd kernel thread */
mISDN_thread.notify = &sem;
test_and_set_bit(mISDN_TFLAGS_RMMOD, &mISDN_thread.Flags);
wake_up_interruptible(&mISDN_thread.waitq);
down(&sem);
mISDN_thread.notify = NULL;
}
#ifdef MISDN_MEMDEBUG
__mid_cleanup();
#endif
#ifdef CONFIG_MISDN_NETDEV
misdn_netdev_exit();
#endif
mISDN_sysfs_cleanup();
printk(KERN_DEBUG "mISDNcore unloaded\n");
}
module_init(mISDNInit);
module_exit(mISDN_cleanup);
EXPORT_SYMBOL(mISDN_module_register);
EXPORT_SYMBOL(mISDN_module_unregister);
EXPORT_SYMBOL(mISDN_inc_usage);
EXPORT_SYMBOL(mISDN_dec_usage);
EXPORT_SYMBOL(mISDN_ctrl);
EXPORT_SYMBOL(mISDN_register);
EXPORT_SYMBOL(mISDN_unregister);
EXPORT_SYMBOL(mISDN_dt_set_callback);
EXPORT_SYMBOL(mISDN_dt_unset_callback);
EXPORT_SYMBOL(mISDN_dt_enable);
EXPORT_SYMBOL(mISDN_dt_disable);
EXPORT_SYMBOL(mISDN_dt_new_frame);
#ifdef CONFIG_MISDN_NETDEV
EXPORT_SYMBOL(misdn_log_frame);
#endif
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/core.h 0000644 0000000 0000050 00000007757 11135651701 017507 0 ustar root src /* $Id: core.h,v 1.19 2006/12/21 15:25:06 nadi Exp $
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include
#include
#include
#include
#include "helper.h"
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
#define mISDN_MAJOR 46
#define mISDN_MINOR_CORE 0
#define mISDN_MINOR_RAW_MIN 128
#define mISDN_MINOR_RAW_MAX 255
/* debugging */
#define DEBUG_CORE_FUNC 0x0001
//#define DEBUG_DUMMY_FUNC 0x0002
#define DEBUG_MSG_THREAD_ERR 0x0010
#define DEBUG_MSG_THREAD_INFO 0x0020
#define DEBUG_QUEUE_FUNC 0x0040
#define DEBUG_DEV_OP 0x0100
#define DEBUG_MGR_FUNC 0x0200
#define DEBUG_DEV_TIMER 0x0400
#define DEBUG_RDATA 0x1000
#define DEBUG_WDATA 0x2000
#define DEBUG_SYSFS 0x4000
#define DEBUG_THREADS 0x8000
/* from udevice.c */
extern int init_mISDNdev(int);
extern int free_mISDNdev(void);
extern mISDNdevice_t *get_free_rawdevice(void);
extern int free_device(mISDNdevice_t *dev);
/* from stack.c */
extern void get_stack_info(struct sk_buff *);
extern int get_stack_cnt(void);
extern void check_stacklist(void);
extern void cleanup_object(mISDNobject_t *);
extern mISDNstack_t *get_stack4id(u_int);
extern int mISDN_start_stack_thread(mISDNstack_t *);
extern mISDNstack_t *new_stack(mISDNstack_t *, mISDNinstance_t *);
extern int mISDN_start_stop(mISDNstack_t *, int);
extern int release_stack(mISDNstack_t *);
extern int do_for_all_layers(void *, u_int, void *);
extern int change_stack_para(mISDNstack_t *, u_int, mISDN_stPara_t *);
extern void release_stacks(mISDNobject_t *);
extern int copy_pid(mISDN_pid_t *, mISDN_pid_t *, u_char *);
extern int set_stack(mISDNstack_t *, mISDN_pid_t *);
extern int clear_stack(mISDNstack_t *, int);
extern int evaluate_stack_pids(mISDNstack_t *, mISDN_pid_t *);
extern mISDNinstance_t *getlayer4lay(mISDNstack_t *, int);
extern mISDNinstance_t *get_instance(mISDNstack_t *, int, int);
/* from sysfs_obj.c */
extern int mISDN_register_sysfs_obj(mISDNobject_t *);
extern int mISDN_sysfs_init(void);
extern void mISDN_sysfs_cleanup(void);
/* from sysfs_inst.c */
extern int mISDN_register_sysfs_inst(mISDNinstance_t *);
extern void mISDN_unregister_sysfs_inst(mISDNinstance_t *);
extern int mISDN_sysfs_inst_init(void);
extern void mISDN_sysfs_inst_cleanup(void);
/* from sysfs_stack.c */
extern int mISDN_register_sysfs_stack(mISDNstack_t *);
extern void mISDN_unregister_sysfs_st(mISDNstack_t *);
extern int mISDN_sysfs_st_init(void);
extern void mISDN_sysfs_st_cleanup(void);
/* from core.c */
extern int core_debug;
extern int register_layer(mISDNstack_t *, mISDNinstance_t *);
extern int preregister_layer(mISDNstack_t *, mISDNinstance_t *);
extern int unregister_instance(mISDNinstance_t *);
extern mISDNinstance_t *get_next_instance(mISDNstack_t *, mISDN_pid_t *);
extern mISDNobject_t *get_object(int);
extern mISDNinstance_t *get_instance4id(u_int);
extern int mISDN_alloc_entity(int *);
extern int mISDN_delete_entity(int);
extern void mISDN_module_register(struct module *);
extern void mISDN_module_unregister(struct module *);
extern void mISDN_inc_usage(void);
extern void mISDN_dec_usage(void);
/* debugtool helpers from core.c */
extern void mISDN_dt_set_callback(void (*new_frame) (mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb));
extern void mISDN_dt_unset_callback(void);
extern void mISDN_dt_enable(void);
extern void mISDN_dt_disable(void);
extern void mISDN_dt_new_frame(mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb);
#ifdef CONFIG_MISDN_NETDEV
/* from netdev_main.c */
void misdn_log_frame(mISDNstack_t *, /* Stack for which to log */
unsigned char *, /* frame to log */
int, /* frame len */
int ); /* direction (0=rx,1=tx) */
int misdn_netdev_addstack(mISDNstack_t *); /* create new netdevice by
stack */
int misdn_netdev_init(void); /* initialize netdevices */
void misdn_netdev_exit(void); /* exit netdeivces */
#endif
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/debug.c 0000644 0000000 0000050 00000003302 11135651701 017616 0 ustar root src /* $Id: debug.c,v 1.7 2006/03/23 13:11:43 keil Exp $
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include
#include
#include
#include
#include "debug.h"
#define mISDN_STATUS_BUFSIZE 4096
static char tmpbuf[mISDN_STATUS_BUFSIZE];
void
vmISDN_debug(int id, char *head, char *fmt, va_list args)
{
/* if head == NULL the fmt contains the full info */
char *p = tmpbuf;
p += sprintf(p,"%d ", id);
if (head)
p += sprintf(p, "%s ", head);
p += vsprintf(p, fmt, args);
printk(KERN_DEBUG "%s\n", tmpbuf);
}
void
mISDN_debug(int id, char *head, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vmISDN_debug(id, head, fmt, args);
va_end(args);
}
void
mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...)
{
logdata_t log;
va_start(log.args, fmt);
log.head = inst->name;
log.fmt = fmt;
mISDN_ctrl(inst, MGR_DEBUGDATA | REQUEST, &log);
va_end(log.args);
}
char *
mISDN_getrev(const char *revision)
{
char *rev;
char *p;
if ((p = strchr(revision, ':'))) {
rev = p + 2;
p = strchr(rev, '$');
if (p)
*--p = 0;
} else
rev = "???";
return rev;
}
int
mISDN_QuickHex(char *txt, u_char * p, int cnt)
{
register int i;
register char *t = txt;
register u_char w;
for (i = 0; i < cnt; i++) {
*t++ = ' ';
w = (p[i] >> 4) & 0x0f;
if (w < 10)
*t++ = '0' + w;
else
*t++ = 'A' - 10 + w;
w = p[i] & 0x0f;
if (w < 10)
*t++ = '0' + w;
else
*t++ = 'A' - 10 + w;
}
*t++ = 0;
return (t - txt);
}
EXPORT_SYMBOL(vmISDN_debug);
EXPORT_SYMBOL(mISDN_debug);
EXPORT_SYMBOL(mISDN_getrev);
EXPORT_SYMBOL(mISDN_debugprint);
EXPORT_SYMBOL(mISDN_QuickHex);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/debug.h 0000644 0000000 0000050 00000001021 11110524073 017611 0 ustar root src /* $Id: debug.h,v 1.3 2006/03/06 12:52:07 keil Exp $
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#ifndef MISDN_DEBUG_H
#define MISDN_DEBUG_MANAGER 0x10000
extern void vmISDN_debug(int id, char *head, char *fmt, va_list args);
extern void mISDN_debug(int id, char *head, char *fmt, ...);
extern char * mISDN_getrev(const char *revision);
extern void mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...);
extern int mISDN_QuickHex(char *, u_char *, int);
#endif
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/debugtool.c 0000644 0000000 0000050 00000015136 11135651701 020524 0 ustar root src /*
* debugtool.c: Debug-Tool for mISDN
*
* Copyright (C) 2007, Nadi Sarrar
*
* Nadi Sarrar
*
* 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., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "core.h"
#include
#define DT_VERSION 1
#define MODULE_NAME "mISDN_debugtool"
#define ADDR INADDR_LOOPBACK
static int PORT = 50501;
static int dt_enabled = 0;
static struct task_struct *thread;
static struct sk_buff_head skb_q;
static DECLARE_WAIT_QUEUE_HEAD(skb_q_wait);
static void dt_new_frame (mISDNstack_t *stack, enum mISDN_dt_type type, struct sk_buff *skb, int duplicate_skb)
{
struct sk_buff *dup;
mISDN_dt_header_t *hdr;
dup = skb ? (duplicate_skb ? skb_copy(skb, GFP_ATOMIC) : skb) : alloc_skb(0, GFP_ATOMIC);
if (!dup)
return;
hdr = (mISDN_dt_header_t *)dup->cb;
memset(hdr, 0, sizeof(mISDN_dt_header_t));
hdr->version = DT_VERSION;
hdr->type = type;
hdr->stack_id = stack->id;
hdr->stack_protocol = stack->pid.modparm_protocol;
hdr->time = current_kernel_time();
hdr->plength = skb ? skb->len : 0;
skb_queue_tail(&skb_q, dup);
wake_up_interruptible(&skb_q_wait);
}
static inline int dt_send_buf (struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len)
{
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
int size = 0;
if (!sock->sk)
return 0;
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_flags = 0;
msg.msg_name = addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
oldfs = get_fs();
set_fs(KERNEL_DS);
size = sock_sendmsg(sock, &msg, len);
set_fs(oldfs);
return size;
}
static inline void dt_send_skb (struct socket *sock, struct sockaddr_in *addr, const struct sk_buff *skb)
{
if (skb->len) {
unsigned char buf[sizeof(mISDN_dt_header_t) + skb->len];
memcpy(buf, skb->cb, sizeof(mISDN_dt_header_t));
memcpy(buf + sizeof(mISDN_dt_header_t), skb->data, skb->len);
dt_send_buf(sock, addr, buf, sizeof(buf));
} else
dt_send_buf(sock, addr, (unsigned char *)skb->cb, sizeof(mISDN_dt_header_t));
}
static void dt_run (void)
{
int ret;
struct sk_buff *skb;
struct socket *sock;
struct sockaddr_in addr;
lock_kernel();
current->flags |= PF_NOFREEZE;
daemonize(MODULE_NAME);
allow_signal(SIGKILL);
unlock_kernel();
/* init socket */
ret = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
if (ret < 0) {
printk(KERN_INFO "%s: sock_create failed! (%d)\n", __FUNCTION__, -ret);
sock = NULL;
return;
}
memset(&addr, 0, sizeof(struct sockaddr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(ADDR);
addr.sin_port = htons(PORT);
ret = sock->ops->connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr), 0);
if (ret < 0) {
printk(KERN_INFO "%s: Could not connect to socket (%d)\n", __FUNCTION__, -ret);
sock_release(sock);
sock = NULL;
return;
}
printk(KERN_INFO MODULE_NAME ": Using destination port %d.\n", PORT);
for (;;) {
wait_event_interruptible(skb_q_wait, signal_pending(current) || !skb_queue_empty(&skb_q));
if (signal_pending(current))
break;
skb = skb_dequeue(&skb_q);
dt_send_skb(sock, &addr, skb);
kfree_skb(skb);
}
printk(KERN_INFO MODULE_NAME ": Leaving thread successfully.\n");
sock_release(sock);
}
/* sysfs */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
static void dt_class_release (struct device *dev) {}
#else
static void dt_class_release (struct class_device *dev) {}
#endif
static struct class dt_class = {
.name = "mISDN-debugtool",
#ifndef CLASS_WITHOUT_OWNER
.owner = THIS_MODULE,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
.dev_release = &dt_class_release,
#else
.release = &dt_class_release,
#endif
};
static ssize_t attr_show_enabled (struct class *class, char *buf)
{
return sprintf(buf, "%d\n", dt_enabled);
}
static ssize_t attr_store_enabled (struct class *class, const char *buf, size_t count)
{
if (count > 0 && *buf == '1') {
mISDN_dt_enable();
dt_enabled = 1;
} else {
mISDN_dt_disable();
dt_enabled = 0;
}
return count;
}
static CLASS_ATTR(enabled, 0644, attr_show_enabled, attr_store_enabled);
module_param(PORT, int, S_IRUGO);
int __init dt_init(void)
{
/* init queue */
skb_queue_head_init(&skb_q);
/* init sysfs */
if (class_register(&dt_class) ||
class_create_file(&dt_class, &class_attr_enabled)) {
printk(KERN_INFO MODULE_NAME "%s: Failed to initialize sysfs!\n", __FUNCTION__);
return -EPERM;
}
/* start thread */
thread = kthread_run((void *)dt_run, NULL, MODULE_NAME);
if (IS_ERR(thread)) {
printk(KERN_INFO MODULE_NAME "%s: Could not start kernel thread!\n", __FUNCTION__);
class_unregister(&dt_class);
return -ENOMEM;
}
/* register with mISDN */
mISDN_module_register(THIS_MODULE);
mISDN_dt_set_callback(dt_new_frame);
printk(KERN_INFO MODULE_NAME ": module loaded\n");
return 0;
}
void __exit dt_exit(void)
{
int ret;
mISDN_dt_disable();
mISDN_dt_unset_callback();
mISDN_module_unregister(THIS_MODULE);
if (thread) {
lock_kernel();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
ret = kill_pid(find_pid_ns(thread->pid, &init_pid_ns), SIGKILL, 1);
#else
ret = kill_proc(thread->pid, SIGKILL, 1);
#endif
unlock_kernel();
if (ret < 0)
printk(KERN_INFO MODULE_NAME ": Unknown error (%d) while trying to terminate kernel thread!\n", -ret);
wake_up_interruptible(&skb_q_wait);
}
class_unregister(&dt_class);
skb_queue_purge(&skb_q);
printk(KERN_INFO MODULE_NAME ": module unloaded\n");
}
module_init(dt_init);
module_exit(dt_exit);
MODULE_DESCRIPTION("Debug-Tool for mISDN");
MODULE_AUTHOR("Nadi Sarrar ");
MODULE_LICENSE("GPL");
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/dsp.h 0000644 0000000 0000050 00000017242 11135651701 017333 0 ustar root src /* $Id: dsp.h,v 1.13 2007/03/27 15:06:29 jolly Exp $
*
* Audio support data for ISDN4Linux.
*
* Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define DEBUG_DSP_MGR 0x0001
#define DEBUG_DSP_CORE 0x0002
#define DEBUG_DSP_DTMF 0x0004
#define DEBUG_DSP_DTMFCOEFF 0x0008
#define DEBUG_DSP_CMX 0x0010
#define DEBUG_DSP_TONE 0x0020
#define DEBUG_DSP_BLOWFISH 0x0040
#define DEBUG_DSP_DELAY 0x0080
/* options may be:
*
* bit 0 = use ulaw instead of alaw
* bit 1 = enable hfc hardware accelleration for all channels
*
*/
#define DSP_OPT_ULAW (1<<0)
#define DSP_OPT_NOHARDWARE (1<<1)
#define FEAT_STATE_INIT 1
#define FEAT_STATE_WAIT 2
#define FEAT_STATE_RECEIVED 3
#include
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
#include "dsp_ecdis.h"
/*
* You are now able to choose between the Mark2 and the
* kb1 Echo cancellor. Just comment the one and comment
* out the other.
*/
//#define AGGRESSIVE_SUPPRESSOR
//#include "dsp_mec2.h"
//#include "dsp_kb1ec.h"
#include "dsp_mg2ec.h"
/*
* uncomment this one to cancel echo more aggressive
*/
//#define AGGRESSIVE_SUPPRESSOR
extern int dsp_options;
extern int dsp_debug;
extern int dsp_poll;
extern int dsp_tics;
/***************
* audio stuff *
***************/
extern s32 dsp_audio_alaw_to_s32[256];
extern s32 dsp_audio_ulaw_to_s32[256];
extern s32 *dsp_audio_law_to_s32;
extern u8 dsp_audio_s16_to_law[65536];
extern u8 dsp_audio_alaw_to_ulaw[256];
extern u8 dsp_audio_mix_law[65536];
extern u8 dsp_audio_seven2law[128];
extern u8 dsp_audio_law2seven[256];
extern void dsp_audio_generate_law_tables(void);
extern void dsp_audio_generate_s2law_table(void);
extern void dsp_audio_generate_seven(void);
extern void dsp_audio_generate_mix_table(void);
extern void dsp_audio_generate_ulaw_samples(void);
extern void dsp_audio_generate_volume_changes(void);
extern u8 dsp_silence;
/*************
* cmx stuff *
*************/
#define MAX_POLL 256 /* maximum number of send-chunks */
#define CMX_BUFF_SIZE 0x8000 /* must be 2**n (0x1000 about 1/2 second) */
#define CMX_BUFF_HALF 0x4000 /* CMX_BUFF_SIZE / 2 */
#define CMX_BUFF_MASK 0x7fff /* CMX_BUFF_SIZE - 1 */
/* how many seconds will we check the lowest delay until the jitter buffer
is reduced by that delay */
#define MAX_SECONDS_JITTER_CHECK 5
extern struct timer_list dsp_spl_tl;
extern u64 dsp_spl_jiffies;
/* the structure of conferences:
*
* each conference has a unique number, given by user space.
* the conferences are linked in a chain.
* each conference has members linked in a chain.
* each dsplayer points to a member, each member points to a dsplayer.
*/
/* all members within a conference (this is linked 1:1 with the dsp) */
struct _dsp;
typedef struct _conf_member {
struct list_head list;
struct _dsp *dsp;
} conf_member_t;
/* the list of all conferences */
typedef struct _conference {
struct list_head list;
u32 id; /* all cmx stacks with the same ID are connected */
struct list_head mlist;
int software; /* conf is processed by software */
int hardware; /* conf is processed by hardware */
} conference_t;
extern mISDNobject_t dsp_obj;
/**************
* DTMF stuff *
**************/
#define DSP_DTMF_NPOINTS 102
#define ECHOCAN_BUFLEN 4*128
typedef struct _dtmf_t {
int treshold; /* above this is dtmf (square of) */
int software; /* dtmf uses software decoding */
int hardware; /* dtmf uses hardware decoding */
int size; /* number of bytes in buffer */
signed short buffer[DSP_DTMF_NPOINTS]; /* buffers one full dtmf frame */
u8 lastwhat, lastdigit;
int count;
u8 digits[16]; /* just the dtmf result */
} dtmf_t;
/****************
* cancel stuff *
****************/
/***************
* tones stuff *
***************/
typedef struct _tone_t {
int software; /* tones are generated by software */
int hardware; /* tones are generated by hardware */
int tone;
void *pattern;
int count;
int index;
struct timer_list tl;
} tone_t;
/*****************
* general stuff *
*****************/
#define DELAY_CHECK 8000
struct dsp_features {
int hfc_id; /* unique id to identify the chip (or -1) */
int hfc_dtmf; /* set if HFCmulti card supports dtmf */
int hfc_loops; /* set if card supports tone loops */
int hfc_echocanhw; /* set if card supports echocancelation*/
int pcm_id; /* unique id to identify the pcm bus (or -1) */
int pcm_slots; /* number of slots on the pcm bus */
int pcm_banks; /* number of IO banks of pcm bus */
int has_jitter; /* data is jittered and unsorted */
};
typedef struct _dsp {
struct list_head list;
mISDNinstance_t inst;
int b_active;
int echo; /* echo is done by software */
int rx_disabled;
int tx_mix;
tone_t tone;
dtmf_t dtmf;
int tx_volume, rx_volume;
/* conference stuff */
u32 conf_id;
conference_t *conf;
conf_member_t *member;
/* while we're waiting for the hw */
u32 queue_conf_id;
/* buffer stuff */
int rx_W; /* current write pos for data without timestamp */
int rx_R; /* current read pos for transmit clock */
int tx_W; /* current write pos for transmit data */
int tx_R; /* current read pos for transmit clock */
int delay[MAX_SECONDS_JITTER_CHECK];
u8 tx_buff[CMX_BUFF_SIZE];
u8 rx_buff[CMX_BUFF_SIZE];
/* hardware stuff */
struct dsp_features features; /* features */
struct timer_list feature_tl;
spinlock_t feature_lock;
int feature_state;
int pcm_slot_rx; /* current PCM slot (or -1) */
int pcm_bank_rx;
int pcm_slot_tx;
int pcm_bank_tx;
int hfc_conf; /* unique id of current conference (or -1) */
/* encryption stuff */
int bf_enable;
u32 bf_p[18];
u32 bf_s[1024];
int bf_crypt_pos;
u8 bf_data_in[9];
u8 bf_crypt_out[9];
int bf_decrypt_in_pos;
int bf_decrypt_out_pos;
u8 bf_crypt_inring[16];
u8 bf_data_out[9];
int bf_sync;
/* echo cancellation stuff */
int queue_cancel[3];
int cancel_enable;
int cancel_hardware; /*we are using hw echo canc*/
struct echo_can_state * ec; /**< == NULL: echo cancellation disabled;
!= NULL: echo cancellation enabled */
echo_can_disable_detector_state_t* ecdis_rd;
echo_can_disable_detector_state_t* ecdis_wr;
uint16_t echotimer;
uint16_t echostate;
uint16_t echolastupdate;
char txbuf[ECHOCAN_BUFLEN];
int txbuflen;
char rxbuf[ECHOCAN_BUFLEN];
int rxbuflen;
} dsp_t;
/* functions */
extern void dsp_change_volume(struct sk_buff *skb, int volume);
extern struct list_head Conf_list;
extern void dsp_cmx_debug(dsp_t *dsp);
extern void dsp_cmx_hardware(conference_t *conf, dsp_t *dsp);
extern int dsp_cmx_conf(dsp_t *dsp, u32 conf_id);
extern void dsp_cmx_receive(dsp_t *dsp, struct sk_buff *skb);
#ifdef OLDCMX
extern struct sk_buff *dsp_cmx_send(dsp_t *dsp, int len, int dinfo);
#else
extern void dsp_cmx_send(void *data);
#endif
extern void dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb);
extern int dsp_cmx_del_conf_member(dsp_t *dsp);
extern int dsp_cmx_del_conf(conference_t *conf);
extern void dsp_dtmf_goertzel_init(dsp_t *dsp);
extern u8 *dsp_dtmf_goertzel_decode(dsp_t *dsp, u8 *data, int len, int fmt);
extern int dsp_tone(dsp_t *dsp, int tone);
extern void dsp_tone_copy(dsp_t *dsp, u8 *data, int len);
extern void dsp_tone_timeout(void *arg);
extern void dsp_bf_encrypt(dsp_t *dsp, u8 *data, int len);
extern void dsp_bf_decrypt(dsp_t *dsp, u8 *data, int len);
extern int dsp_bf_init(dsp_t *dsp, const u8 *key, unsigned int keylen);
extern void dsp_bf_cleanup(dsp_t *dsp);
extern void dsp_cancel_tx(dsp_t *dsp, u8 *data, int len);
extern void dsp_cancel_rx(dsp_t *dsp, u8 *data, int len);
extern int dsp_cancel_init(dsp_t *dsp, int taps, int training, int delay);
mISDN-1_1_9.1/drivers/isdn/hardware/mISDN/dsp_arith.h 0000644 0000000 0000050 00000017033 11135651701 020520 0 ustar root src #ifndef _ZAPTEL_ARITH_H
#define _ZAPTEL_ARITH_H
/*
* Handy add/subtract functions to operate on chunks of shorts.
* Feel free to add customizations for additional architectures
*
*/
#ifdef CONFIG_ZAPTEL_MMX
#ifdef ZT_CHUNKSIZE
static inline void __ACSS(volatile short *dst, const short *src)
{
__asm__ __volatile__ (
"movq 0(%0), %%mm0;\n"
"movq 0(%1), %%mm1;\n"
"movq 8(%0), %%mm2;\n"
"movq 8(%1), %%mm3;\n"
"paddsw %%mm1, %%mm0;\n"
"paddsw %%mm3, %%mm2;\n"
"movq %%mm0, 0(%0);\n"
"movq %%mm2, 8(%0);\n"
: "=r" (dst)
: "r" (src), "0" (dst)
: "memory"
#if CLOBBERMMX
, "%mm0", "%mm1", "%mm2", "%mm3"
#endif
);
}
static inline void __SCSS(volatile short *dst, const short *src)
{
__asm__ __volatile__ (
"movq 0(%0), %%mm0;\n"
"movq 0(%1), %%mm1;\n"
"movq 8(%0), %%mm2;\n"
"movq 8(%1), %%mm3;\n"
"psubsw %%mm1, %%mm0;\n"
"psubsw %%mm3, %%mm2;\n"
"movq %%mm0, 0(%0);\n"
"movq %%mm2, 8(%0);\n"
: "=r" (dst)
: "r" (src), "0" (dst)
: "memory"
#if CLOBBERMMX
, "%mm0", "%mm1", "%mm2", "%mm3"
#endif
);
}
#if (ZT_CHUNKSIZE == 8)
#define ACSS(a,b) __ACSS(a,b)
#define SCSS(a,b) __SCSS(a,b)
#elif (ZT_CHUNKSIZE > 8)
static inline void ACSS(volatile short *dst, const short *src)
{
int x;
for (x=0;x>= 4;
/* Clear our accumulator, mm4 */
/*
For every set of eight...
Load 16 coefficients into four registers...
Shift each word right 16 to make them shorts...
Pack the resulting shorts into two registers...
With the coefficients now in mm0 and mm2, load the
history into mm1 and mm3...
Multiply/add mm1 into mm0, and mm3 into mm2...
Add mm2 into mm0 (without saturation, alas). Now we have two half-results.
Accumulate in mm4 (again, without saturation, alas)
*/
__asm__ (
"pxor %%mm4, %%mm4;\n"
"mov %1, %%edi;\n"
"mov %2, %%esi;\n"
"mov %3, %%ecx;\n"
"1:"
"movq 0(%%edi), %%mm0;\n"
"movq 8(%%edi), %%mm1;\n"
"movq 16(%%edi), %%mm2;\n"
"movq 24(%%edi), %%mm3;\n"
/* can't use 4/5 since 4 is the accumulator for us */
"movq 32(%%edi), %%mm6;\n"
"movq 40(%%edi), %%mm7;\n"
"psrad $16, %%mm0;\n"
"psrad $16, %%mm1;\n"
"psrad $16, %%mm2;\n"
"psrad $16, %%mm3;\n"
"psrad $16, %%mm6;\n"
"psrad $16, %%mm7;\n"
"packssdw %%mm1, %%mm0;\n"
"packssdw %%mm3, %%mm2;\n"
"packssdw %%mm7, %%mm6;\n"
"movq 0(%%esi), %%mm1;\n"
"movq 8(%%esi), %%mm3;\n"
"movq 16(%%esi), %%mm7;\n"
"pmaddwd %%mm1, %%mm0;\n"
"pmaddwd %%mm3, %%mm2;\n"
"pmaddwd %%mm7, %%mm6;\n"
"paddd %%mm6, %%mm4;\n"
"paddd %%mm2, %%mm4;\n"
"paddd %%mm0, %%mm4;\n"
/* Come back and do for the last few bytes */
"movq 48(%%edi), %%mm6;\n"
"movq 56(%%edi), %%mm7;\n"
"psrad $16, %%mm6;\n"
"psrad $16, %%mm7;\n"
"packssdw %%mm7, %%mm6;\n"
"movq 24(%%esi), %%mm7;\n"
"pmaddwd %%mm7, %%mm6;\n"
"paddd %%mm6, %%mm4;\n"
"add $64, %%edi;\n"
"add $32, %%esi;\n"
"dec %%ecx;\n"
"jnz 1b;\n"
"movq %%mm4, %%mm0;\n"
"psrlq $32, %%mm0;\n"
"paddd %%mm0, %%mm4;\n"
"movd %%mm4, %0;\n"
: "=r" (sum)
: "r" (coeffs), "r" (hist), "r" (len)
: "%ecx", "%edi", "%esi"
);
return sum;
}
static inline void UPDATE(volatile int *taps, const short *history, const int nsuppr, const int ntaps)
{
int i;
int correction;
for (i=0;i>= 4;
/* First, load up taps, */
__asm__ (
"pxor %%mm4, %%mm4;\n"
"mov %0, %%edi;\n"
"mov %1, %%esi;\n"
"mov %3, %%ecx;\n"
"1:"
"jnz 1b;\n"
"movq %%mm4, %%mm0;\n"
"psrlq $32, %%mm0;\n"
"paddd %%mm0, %%mm4;\n"
"movd %%mm4, %0;\n"
: "=r" (taps), "=r" (taps_short)
: "r" (history), "r" (nsuppr), "r" (ntaps), "0" (taps)
: "%ecx", "%edi", "%esi"
);
#endif
#if 1
for (i=0;i> 16;
}
#endif
}
static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
{
int sum;
/* Divide length by 16 */
len >>= 4;
/* Clear our accumulator, mm4 */
/*
For every set of eight...
Load in eight coefficients and eight historic samples, multliply add and
accumulate the result
*/
__asm__ (
"pxor %%mm4, %%mm4;\n"
"mov %1, %%edi;\n"
"mov %2, %%esi;\n"
"mov %3, %%ecx;\n"
"1:"
"movq 0(%%edi), %%mm0;\n"
"movq 8(%%edi), %%mm2;\n"
"movq 0(%%esi), %%mm1;\n"
"movq 8(%%esi), %%mm3;\n"
"pmaddwd %%mm1, %%mm0;\n"
"pmaddwd %%mm3, %%mm2;\n"
"paddd %%mm2, %%mm4;\n"
"paddd %%mm0, %%mm4;\n"
"movq 16(%%edi), %%mm0;\n"
"movq 24(%%edi), %%mm2;\n"
"movq 16(%%esi), %%mm1;\n"
"movq 24(%%esi), %%mm3;\n"
"pmaddwd %%mm1, %%mm0;\n"
"pmaddwd %%mm3, %%mm2;\n"
"paddd %%mm2, %%mm4;\n"
"paddd %%mm0, %%mm4;\n"
"add $32, %%edi;\n"
"add $32, %%esi;\n"
"dec %%ecx;\n"
"jnz 1b;\n"
"movq %%mm4, %%mm0;\n"
"psrlq $32, %%mm0;\n"
"paddd %%mm0, %%mm4;\n"
"movd %%mm4, %0;\n"
: "=r" (sum)
: "r" (coeffs), "r" (hist), "r" (len)
: "%ecx", "%edi", "%esi"
);
return sum;
}
static inline short MAX16(const short *y, int len, int *pos)
{
int k;
short max = 0;
int bestpos = 0;
for (k=0;k 32767)
sum = 32767;
else if (sum < -32768)
sum = -32768;
dst[x] = sum;
}
}
static inline void SCSS(short *dst, short *src)
{
int x,sum;
/* Add src to dst with saturation, storing in dst */
for (x=0;x 32767)
sum = 32767;
else if (sum < -32768)
sum = -32768;
dst[x] = sum;
}
}
#endif /* ZT_CHUNKSIZE */
static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
{
int x;
int sum = 0;
for (x=0;x> 16) * hist[x];
return sum;
}
static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
{
int x;
int sum = 0;
for (x=0;x> 16;
}
}
static inline short MAX16(const short *y, int len, int *pos)
{
int k;
short max = 0;
int bestpos = 0;
for (k=0;k