aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--channels/Makefile8
-rw-r--r--channels/chan_misdn.c168
-rw-r--r--channels/chan_misdn_config.c12
-rw-r--r--channels/misdn/Makefile69
-rw-r--r--channels/misdn/chan_misdn_config.h1
-rw-r--r--channels/misdn/ie.c8
-rw-r--r--channels/misdn/isdn_lib.c20
-rw-r--r--channels/misdn/isdn_lib.h1
-rw-r--r--channels/misdn/isdn_lib_intern.h8
-rw-r--r--channels/misdn/isdn_msg_parser.c27
-rw-r--r--channels/misdn/mISDN.patch2500
-rw-r--r--channels/misdn/mISDNuser.patch271
-rw-r--r--doc/README.misdn104
13 files changed, 3025 insertions, 172 deletions
diff --git a/channels/Makefile b/channels/Makefile
index c736dfa26..704ed505c 100644
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -83,6 +83,7 @@ endif
ifneq ($(wildcard misdn/chan_misdn_lib.a),)
CHANNEL_LIBS+=chan_misdn.so
+ CFLAGS+=-Imisdn
endif
CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations
@@ -234,11 +235,10 @@ chan_h323.so: chan_h323.o h323/libchanh323.a
endif
chan_misdn.so: chan_misdn.o chan_misdn_config.o misdn/chan_misdn_lib.a
- $(CC) -shared -Xlinker -x -o $@ $^ $(MISDNUSER)/i4lnet/libisdnnet.a $(MISDNUSER)/lib/libmISDN.a
-
-chan_misdn_config.o: chan_misdn_config.c
- $(CC) $(CFLAGS) -c chan_misdn_config.c
+ $(CC) -shared -Xlinker -x -L/usr/lib -o $@ $^ -lmISDN -lisdnnet
+chan_misdn.o: chan_misdn.c
+ $(CC) $(CFLAGS) -DCHAN_MISDN_VERSION=\"0.2.1\" -c $< -o $@
#chan_modem.so : chan_modem.o
# $(CC) -rdynamic -shared -Xlinker -x -o $@ $<
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 1abe0436e..46296c18f 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -1092,13 +1092,12 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
ast_setstate(ast, AST_STATE_DOWN);
return -1;
}
-
+
port=newbc->port;
-
+
ast_copy_string(newbc->dad, ext, sizeof(newbc->dad));
ast_copy_string(ast->exten, ext, sizeof(ast->exten));
-
chan_misdn_log(1, 0, "* CALL: %s\n",dest);
chan_misdn_log(1, port, " --> * dad:%s tech:%s ctx:%s\n",ast->exten,ast->name, ast->context);
@@ -1131,22 +1130,63 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
strncpy(newbc->oad,callerid, l);
newbc->oad[l-1] = 0;
}
-
- misdn_cfg_get( port, MISDN_CFG_DIALPLAN, &newbc->dnumplan, sizeof(int));
- switch (newbc->dnumplan) {
- case NUMPLAN_INTERNATIONAL:
- case NUMPLAN_NATIONAL:
- case NUMPLAN_SUBSCRIBER:
- case NUMPLAN_UNKNOWN:
- /* Maybe we should cut off the prefix if present ? */
+ }
+
+
+ misdn_cfg_get( port, MISDN_CFG_DIALPLAN, &newbc->dnumplan, sizeof(int));
+ switch (newbc->dnumplan) {
+ case NUMPLAN_INTERNATIONAL:
+ chan_misdn_log(2, port, " --> TON: International\n");
+ break;
+ case NUMPLAN_NATIONAL:
+ chan_misdn_log(2, port, " --> TON: National\n");
+ break;
+ case NUMPLAN_SUBSCRIBER:
+ chan_misdn_log(2, port, " --> TON: Subscriber\n");
+ break;
+ case NUMPLAN_UNKNOWN:
+ chan_misdn_log(2, port, " --> TON: Unknown\n");
+ break;
+ /* Maybe we should cut off the prefix if present ? */
+ default:
+ chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n ");
break;
- default:
+ }
+
+
+ misdn_cfg_get( port, MISDN_CFG_LOCALDIALPLAN, &newbc->onumplan, sizeof(int));
+ switch (newbc->onumplan) {
+ case NUMPLAN_INTERNATIONAL:
+ chan_misdn_log(2, port, " --> TON: International\n");
+ break;
+ case NUMPLAN_NATIONAL:
+ chan_misdn_log(2, port, " --> TON: National\n");
+ break;
+ case NUMPLAN_SUBSCRIBER:
+ chan_misdn_log(2, port, " --> TON: Subscriber\n");
+ break;
+ case NUMPLAN_UNKNOWN:
+ chan_misdn_log(2, port, " --> TON: Unknown\n");
+ break;
+ /* Maybe we should cut off the prefix if present ? */
+ default:
chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n ");
break;
- }
-
}
}
+
+
+
+
+ {
+ int eb3;
+
+ misdn_cfg_get( port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int));
+ newbc->early_bconnect=eb3;
+
+ }
+
+
/* Will be overridden by asterisk in head! */
{
@@ -1160,38 +1200,48 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
int def_callingpres;
misdn_cfg_get( port, MISDN_CFG_USE_CALLINGPRES, &def_callingpres, sizeof(int));
if ( def_callingpres) {
+
switch (ast->cid.cid_pres & 0x60){
case AST_PRES_RESTRICTED:
+ chan_misdn_log(2, port, " --> PRES: Restricted (0x1)\n");
newbc->pres=1;
break;
+
case AST_PRES_UNAVAILABLE:
+ chan_misdn_log(2, port, " --> PRES: Unavailable (0x2)\n");
newbc->pres=2;
break;
-
+
default:
+ chan_misdn_log(2, port, " --> PRES: Allowed (0x0)\n");
newbc->pres=0;
}
switch (ast->cid.cid_pres & 0x3){
case AST_PRES_USER_NUMBER_UNSCREENED:
+ chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n");
newbc->screen=0;
break;
case AST_PRES_USER_NUMBER_PASSED_SCREEN:
+ chan_misdn_log(2, port, " --> SCREEN: Passed Screen (0x1)\n");
newbc->screen=1;
break;
case AST_PRES_USER_NUMBER_FAILED_SCREEN:
+ chan_misdn_log(2, port, " --> SCREEN: Failed Screen (0x2)\n");
newbc->screen=2;
break;
case AST_PRES_NETWORK_NUMBER:
+ chan_misdn_log(2, port, " --> SCREEN: Network Nr. (0x3)\n");
newbc->screen=3;
break;
default:
+ chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n");
newbc->screen=0;
}
}
@@ -1210,9 +1260,11 @@ static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
newbc->ec_deftaps=ec;
}
- if ( !ectr ) {
- newbc->ec_training=0;
+
+ if (ectr>=0) {
+ newbc->ec_training=ectr;
}
+
}
}
@@ -1533,9 +1585,8 @@ int misdn_hangup(struct ast_channel *ast)
struct chan_list *p;
struct misdn_bchannel *bc=NULL;
- if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1;
- p = MISDN_ASTERISK_TECH_PVT(ast) ;
-
+ if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) ) ) return -1;
+
release_lock;
chan_misdn_trace_call(ast,1,"*->I: EVENT_HANGUP cause=%d\n",ast->hangupcause);
@@ -1666,8 +1717,7 @@ struct ast_frame *misdn_read(struct ast_channel *ast)
int len =0 ;
if (!ast) return NULL;
- tmp = MISDN_ASTERISK_TECH_PVT(ast);
- if (!tmp) return NULL;
+ if (! (tmp=MISDN_ASTERISK_TECH_PVT(ast)) ) return NULL;
if (!tmp->bc) return NULL;
@@ -1699,8 +1749,7 @@ int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
struct chan_list *p;
int i = 0;
- if (!ast || ! MISDN_ASTERISK_PVT(ast)) return -1;
- p = MISDN_ASTERISK_TECH_PVT(ast) ;
+ if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast)) ) return -1;
if (!p->bc ) {
ast_log(LOG_WARNING, "private but no bc\n");
@@ -2099,15 +2148,18 @@ struct ast_channel *misdn_new(struct chan_list *chlist, int state, char * name,
tmp->priority=1;
- if (context)
+ if (context) {
ast_copy_string(tmp->context, context, sizeof(tmp->context));
- else
+ } else {
chan_misdn_log(1,0,"misdn_new: no context given.\n");
- if (exten)
- ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
- else
+ }
+
+ if (exten) {
+ ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
+ } else {
chan_misdn_log(1,0,"misdn_new: no exten given.\n");
-
+ }
+
if (callerid) {
char *cid_name, *cid_num;
@@ -2863,32 +2915,25 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
/** queue new chan **/
cl_queue_chan(&cl_te, ch) ;
-
+
/*
added support for s extension hope it will help those poor cretains
which haven't overlap dial.
*/
{
- misdn_cfg_get( bc->port, MISDN_CFG_LANGUAGE, chan->language, sizeof(chan->language));
- int ai;
- misdn_cfg_get( bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
- if ( ai ) {
- do_immediate_setup(bc, ch , chan);
- break;
- }
+ misdn_cfg_get( bc->port, MISDN_CFG_LANGUAGE, chan->language, sizeof(chan->language));
+
+ }
- int immediate;
- misdn_cfg_get( bc->port, MISDN_CFG_IMMEDIATE, &immediate, sizeof(int));
+ {
+ int eb3;
- if (ast_strlen_zero(bc->orig_dad) && immediate ) {
- do_immediate_setup(bc, ch , chan);
- break;
- }
+ misdn_cfg_get( bc->port, MISDN_CFG_EARLY_BCONNECT, &eb3, sizeof(int));
+ bc->early_bconnect=eb3;
}
-
{
int ec, ectr;
@@ -2902,8 +2947,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
bc->ec_deftaps=ec;
}
- if ( !ectr ) {
- bc->ec_training=0;
+ if ( ectr>=0 ) {
+ bc->ec_training=ectr;
}
}
@@ -2913,6 +2958,29 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
snprintf(buf,16,"%d",bc->urate);
pbx_builtin_setvar_helper(chan,"MISDN_URATE",buf);
}
+
+
+
+ /**
+ from here on we start the PBX, so no configuration should
+ be considered anymore
+ **/
+
+ int ai;
+ misdn_cfg_get( bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
+ if ( ai ) {
+ do_immediate_setup(bc, ch , chan);
+ break;
+ }
+
+
+ int immediate;
+ misdn_cfg_get( bc->port, MISDN_CFG_IMMEDIATE, &immediate, sizeof(int));
+
+ if (ast_strlen_zero(bc->orig_dad) && immediate ) {
+ do_immediate_setup(bc, ch , chan);
+ break;
+ }
/* Check for Pickup Request first */
if (!strcmp(chan->exten, ast_pickup_ext())) {
@@ -3210,8 +3278,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
struct ast_channel *hold_ast=AST_BRIDGED_P(ch->ast);
ch->state = MISDN_CONNECTED;
- //ast_moh_stop(ch->ast);
- //start_bc_tones(ch);
if (hold_ast) {
ast_moh_stop(hold_ast);
}
@@ -3384,8 +3450,8 @@ int load_module(void)
int unload_module(void)
{
/* First, take us out of the channel loop */
- chan_misdn_log(0, 0, "-- Unregistering mISDN Channel Driver --\n");
-
+ ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
+
if (!g_config_initialized) return 0;
ast_cli_unregister(&cli_send_display);
diff --git a/channels/chan_misdn_config.c b/channels/chan_misdn_config.c
index f8e494127..26598717c 100644
--- a/channels/chan_misdn_config.c
+++ b/channels/chan_misdn_config.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include "chan_misdn_config.h"
@@ -59,7 +60,8 @@ struct port_config {
char *language;
char *callerid;
char *method;
- int *dialplan;
+ int *dialplan;
+ int *localdialplan;
char *nationalprefix;
char *internationalprefix;
int *pres;
@@ -151,6 +153,7 @@ static void free_port_cfg (void) {
FREE_ELEM(callerid);
FREE_ELEM(method);
FREE_ELEM(dialplan);
+ FREE_ELEM(localdialplan);
FREE_ELEM(nationalprefix);
FREE_ELEM(internationalprefix);
FREE_ELEM(pres);
@@ -277,6 +280,8 @@ void misdn_cfg_get(int port, enum misdn_cfg_elements elem, void *buf, int bufsiz
break;
case MISDN_CFG_DIALPLAN: GET_PORTCFG_MEMCPY(dialplan);
break;
+ case MISDN_CFG_LOCALDIALPLAN: GET_PORTCFG_MEMCPY(localdialplan);
+ break;
case MISDN_CFG_NATPREFIX: GET_PORTCFG_STRCPY(nationalprefix);
break;
case MISDN_CFG_INTERNATPREFIX:
@@ -534,6 +539,8 @@ void misdn_cfg_get_config_string(int port, enum misdn_cfg_elements elem, char* b
break;
case MISDN_CFG_DIALPLAN: GET_CFG_INT(DIALPLAN, dialplan);
break;
+ case MISDN_CFG_LOCALDIALPLAN: GET_CFG_INT(LOCALDIALPLAN, localdialplan);
+ break;
case MISDN_CFG_NATPREFIX: GET_CFG_STRING(NATIONALPREFIX, nationalprefix);
break;
case MISDN_CFG_INTERNATPREFIX:
@@ -812,6 +819,7 @@ static void build_port_config(struct ast_variable *v, char *cat) {
}
PARSE_CFG_STR(context);
PARSE_CFG_INT(dialplan);
+ PARSE_CFG_INT(localdialplan);
PARSE_CFG_STR(nationalprefix);
PARSE_CFG_STR(internationalprefix);
PARSE_CFG_STR(language);
@@ -963,6 +971,8 @@ static void fill_defaults (void) {
}
if (!port_cfg[0]->dialplan)
port_cfg[0]->dialplan = (int *)calloc(1, sizeof(int));
+ if (!port_cfg[0]->localdialplan)
+ port_cfg[0]->localdialplan = (int *)calloc(1, sizeof(int));
if (!port_cfg[0]->nationalprefix) {
port_cfg[0]->nationalprefix = (char *)malloc(2 * sizeof(char));
sprintf(port_cfg[0]->nationalprefix, "0");
diff --git a/channels/misdn/Makefile b/channels/misdn/Makefile
index 2288bc7d2..e0e18cf85 100644
--- a/channels/misdn/Makefile
+++ b/channels/misdn/Makefile
@@ -5,41 +5,68 @@
#
# Verify those options with main Makefile
-ifndef LINUX
-LINUX=/lib/modules/$(shell uname -r)/build
-endif
-
-CFLAGS += -pipe -c
+CFLAGS += -pipe -c -DMISDNUSER_JOLLY
SOURCES = isdn_lib.c isdn_msg_parser.c
OBJDIR = .
OBJS = isdn_lib.o isdn_msg_parser.o
-ifndef MISDNUSER
-MISDNUSER=/usr/src/install-misdn/mISDNuser
-endif
-
-MISDNCFLAGS += -I$(MISDNUSER)/include -I$(MISDNUSER)/i4lnet -I$(MISDNUSER)/lib
-MISDNCFLAGS += -DMISDNUSER_JOLLY -I$(LINUX)/include
-
-all: chan_misdn_lib.a Makefile.ast
+all: chan_misdn_lib.a
%.o: %.c
- $(CC) $(MISDNCFLAGS) $(CFLAGS) -o $@ $<
-
+ $(CC) $(CFLAGS) -o $@ $<
+
chan_misdn_lib.a: $(OBJS)
ar crv $@ $(OBJS)
-Makefile.ast: FORCE
- @echo CFLAGS+=$(MISDNCFLAGS) -Imisdn/ -DCHAN_MISDN_VERSION=\\\"0.2.0\\\" >$@.tmp
- @echo MISDNUSER = $(MISDNUSER) >>$@.tmp
- @if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else mv -f $@.tmp $@; fi
+misdn: test_preempt
+ if [ ! -d lib ] ; then \
+ mkdir lib; \
+ cd lib ; \
+ wget http://isdn.jolly.de/download/v3.1/mISDN_for_PBX4Linux-3.0.tar.gz ;\
+ tar xzf mISDN_for_PBX4Linux-3.0.tar.gz; \
+ wget http://isdn.jolly.de/download/v3.1/mISDNuser_for_PBX4Linux-3.0.tar.gz ;\
+ tar xzf mISDNuser_for_PBX4Linux-3.0.tar.gz ;\
+ cd mISDN; patch -p1 <../../mISDN.patch; \
+ cd ../mISDNuser ; patch -p1 <../../mISDNuser.patch; \
+ fi
+ cd lib/mISDN ; make install
+ cd lib/mISDNuser ; make install
+LINUX=/lib/modules/$(uname -r)/build
+GCCVERSION=$(shell $(CC) --version | grep GCC | cut -d " " -f 3 | cut -d "." -f 1)
-FORCE:
+test_preempt:
+ @if grep 'CONFIG_DEBUG_SPINLOCK=y' $(LINUX)/.config ; then \
+ echo -e "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!\nDisable the DEBUG_SPINLOCK Setting in your Kernel Config.\n with this option set, mISDN will not work! \n\n" ;\
+ read ; \
+ exit 1 ; \
+ fi
+ @if grep 'CONFIG_DEBUG_SPINLOCK_SLEEP=y' $(LINUX)/.config ; then \
+ echo -e "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!\nDisable the DEBUG_SPINLOCK_SLEEP Setting in your Kernel Config.\n with this option set, mISDN will not work! \n\n" ;\
+ read ; \
+ exit 1 ; \
+ fi
+ @if grep 'CONFIG_SMP=y' $(LINUX)/.config ; then \
+ echo -e "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!\nDisable the SMP Setting in your Kernel Config.\n\n" ; \
+ read ; \
+ exit 1 ; \
+ fi
+ @if test "$(GCCVERSION)" -gt 3 ; then \
+ echo -e "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!\nYou're using GCC 4! Please downgrade to gcc-3.x and type:\nexport CC=gcc-3.x\nbefore issuing make again.\nyou won't have success with gcc-4!\n\n" ; \
+ read ; \
+ exit 1 ; \
+ fi
+
+FORCE:
+
clean:
- rm *.a *.o Makefile.ast
+ rm -rf *.a *.o *.so
+
+misdn_clean:
+ rm -rf lib
+
diff --git a/channels/misdn/chan_misdn_config.h b/channels/misdn/chan_misdn_config.h
index 328d888ca..250a74e54 100644
--- a/channels/misdn/chan_misdn_config.h
+++ b/channels/misdn/chan_misdn_config.h
@@ -32,6 +32,7 @@ enum misdn_cfg_elements {
MISDN_CFG_CALLERID, /* char[] */
MISDN_CFG_METHOD, /* char[] */
MISDN_CFG_DIALPLAN, /* int */
+ MISDN_CFG_LOCALDIALPLAN, /* int */
MISDN_CFG_NATPREFIX, /* char[] */
MISDN_CFG_INTERNATPREFIX, /* char[] */
MISDN_CFG_PRES, /* int (bool) */
diff --git a/channels/misdn/ie.c b/channels/misdn/ie.c
index 911ebaff2..4d1815f65 100644
--- a/channels/misdn/ie.c
+++ b/channels/misdn/ie.c
@@ -26,10 +26,10 @@
#include "isdn_lib_intern.h"
-#include <mISDNlib.h>
-#include <isdn_net.h>
-#include <l3dss1.h>
-#include <net_l3.h>
+#include <mISDNuser/mISDNlib.h>
+#include <mISDNuser/isdn_net.h>
+#include <mISDNuser/l3dss1.h>
+#include <mISDNuser/net_l3.h>
#define CENTREX_FAC 0x88
diff --git a/channels/misdn/isdn_lib.c b/channels/misdn/isdn_lib.c
index d912795ac..aa1d51cea 100644
--- a/channels/misdn/isdn_lib.c
+++ b/channels/misdn/isdn_lib.c
@@ -91,8 +91,8 @@ enum global_states {
static enum global_states global_state=MISDN_INITIALIZING;
-#include <../i4lnet/net_l2.h>
-#include <tone.h>
+#include <mISDNuser/net_l2.h>
+#include <mISDNuser/tone.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
@@ -341,6 +341,10 @@ int misdn_cap_is_speech(int cap)
int misdn_inband_avail(struct misdn_bchannel *bc)
{
+
+ /*if ! early_bconnect we have never inband available*/
+ if ( ! bc->early_bconnect ) return 0;
+
switch (bc->progress_indicator) {
case INFO_PI_INBAND_AVAILABLE:
case INFO_PI_CALL_NOT_E2E_ISDN:
@@ -421,7 +425,7 @@ void empty_bc(struct misdn_bchannel *bc)
bc->curptx=0; bc->curprx=0;
bc->crypt_key[0] = 0;
-
+
bc->tone=TONE_NONE;
bc->tone_cnt2 = bc->tone_cnt=0;
@@ -429,12 +433,15 @@ void empty_bc(struct misdn_bchannel *bc)
bc->onumplan=NUMPLAN_UNKNOWN;
bc->rnumplan=NUMPLAN_UNKNOWN;
+
bc->active = 0;
-
+
+ bc->early_bconnect = 1;
+
bc->ec_enable = 0;
bc->ec_deftaps = 128;
bc->ec_whenbridged = 0;
- bc->ec_training = 400;
+ bc->ec_training = 1;
bc->orig=0;
@@ -3240,7 +3247,7 @@ void manager_ec_enable(struct misdn_bchannel *bc)
struct misdn_stack *stack=get_stack_by_bc(bc);
- cb_log(1, stack?stack->port:0,"Sending Control ECHOCAN_ON enblock\n");
+ cb_log(1, stack?stack->port:0,"Sending Control ECHOCAN_ON taps:%d training:%d\n",bc->ec_deftaps, bc->ec_training);
switch (bc->ec_deftaps) {
case 4:
@@ -3266,6 +3273,7 @@ void manager_ec_enable(struct misdn_bchannel *bc)
}
+
void manager_ec_disable(struct misdn_bchannel *bc)
{
struct misdn_stack *stack=get_stack_by_bc(bc);
diff --git a/channels/misdn/isdn_lib.h b/channels/misdn/isdn_lib.h
index 92ebdf4db..28a4fe7b6 100644
--- a/channels/misdn/isdn_lib.h
+++ b/channels/misdn/isdn_lib.h
@@ -184,6 +184,7 @@ struct misdn_bchannel {
int te_choose_channel;
+ int early_bconnect;
/* dtmf digit */
int dtmf;
diff --git a/channels/misdn/isdn_lib_intern.h b/channels/misdn/isdn_lib_intern.h
index 471648a68..0305a2dad 100644
--- a/channels/misdn/isdn_lib_intern.h
+++ b/channels/misdn/isdn_lib_intern.h
@@ -2,10 +2,10 @@
#define ISDN_LIB_INTER
-#include <mISDNlib.h>
-#include <isdn_net.h>
-#include <l3dss1.h>
-#include <net_l3.h>
+#include <mISDNuser/mISDNlib.h>
+#include <mISDNuser/isdn_net.h>
+#include <mISDNuser/l3dss1.h>
+#include <mISDNuser/net_l3.h>
#include <pthread.h>
diff --git a/channels/misdn/isdn_msg_parser.c b/channels/misdn/isdn_msg_parser.c
index 751d36f72..9b59f8685 100644
--- a/channels/misdn/isdn_msg_parser.c
+++ b/channels/misdn/isdn_msg_parser.c
@@ -284,31 +284,30 @@ msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
{
int coding=0, capability, mode=0 /* 2 for packet ! */
,user, rate=0x10;
+
+ switch (bc->law) {
+ case INFO_CODEC_ULAW: user=2;
+ break;
+ case INFO_CODEC_ALAW: user=3;
+ break;
+ default:
+ user=3;
+ }
+
switch (bc->capability) {
case INFO_CAPABILITY_SPEECH: capability = 0;
-// cb_log(2, bc->stack->port, " --> Speech\n");
break;
case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: capability = 8;
-// cb_log(2, bc->stack->port, " --> cap unres Digital\n");
+ user=-1;
break;
case INFO_CAPABILITY_DIGITAL_RESTRICTED: capability = 9;
-// cb_log(2, bc->stack->port, " --> cap res Digital\n");
+ user=-1;
break;
default:
-// cb_log(2, bc->stack->port, " --> cap Speech\n");
capability=bc->capability;
}
- switch (bc->law) {
- case INFO_CODEC_ULAW: user=2;
-// cb_log(2, bc->stack->port, " --> Codec Ulaw\n");
- break;
- case INFO_CODEC_ALAW: user=3;
-// cb_log(2, bc->stack->port, " --> Codec Alaw\n");
- break;
- default:
- user=3;
- }
+
enc_ie_bearer(&setup->BEARER, msg, coding, capability, mode, rate, -1, user, nt,bc);
}
diff --git a/channels/misdn/mISDN.patch b/channels/misdn/mISDN.patch
new file mode 100644
index 000000000..681c5fa79
--- /dev/null
+++ b/channels/misdn/mISDN.patch
@@ -0,0 +1,2500 @@
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/arith.h mISDN/drivers/isdn/hardware/mISDN/arith.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/arith.h 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/arith.h 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,347 @@
++#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<ZT_CHUNKSIZE;x+=8)
++ __ACSS(dst + x, src + x);
++}
++static inline void SCSS(volatile short *dst, const short *src)
++{
++ int x;
++ for (x=0;x<ZT_CHUNKSIZE;x+=8)
++ __SCSS(dst + x, src + x);
++}
++#else
++#error No MMX for ZT_CHUNKSIZE < 8
++#endif
++#endif
++static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
++{
++ int sum;
++ /* Divide length by 16 */
++ len >>= 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<ntaps;i++) {
++ correction = history[i] * nsuppr;
++ taps[i] += correction;
++ }
++}
++
++static inline void UPDATE2(volatile int *taps, volatile short *taps_short, const short *history, const int nsuppr, const int ntaps)
++{
++ int i;
++ int correction;
++#if 0
++ ntaps >>= 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<ntaps;i++) {
++ correction = history[i] * nsuppr;
++ taps[i] += correction;
++ taps_short[i] = taps[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<len;k++) {
++ if (max < y[k]) {
++ bestpos = k;
++ max = y[k];
++ }
++ }
++ *pos = (len - 1 - bestpos);
++ return max;
++}
++
++
++
++#else
++
++#ifdef ZT_CHUNKSIZE
++static inline void ACSS(short *dst, short *src)
++{
++ int x,sum;
++ /* Add src to dst with saturation, storing in dst */
++ for (x=0;x<ZT_CHUNKSIZE;x++) {
++ sum = dst[x]+src[x];
++ if (sum > 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<ZT_CHUNKSIZE;x++) {
++ sum = dst[x]-src[x];
++ if (sum > 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<len;x++)
++ sum += (coeffs[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<len;x++)
++ sum += coeffs[x] * hist[x];
++ return sum;
++}
++
++static inline void UPDATE(int *taps, const short *history, const int nsuppr, const int ntaps)
++{
++ int i;
++ int correction;
++ for (i=0;i<ntaps;i++) {
++ correction = history[i] * nsuppr;
++ taps[i] += correction;
++ }
++}
++
++static inline void UPDATE2(int *taps, short *taps_short, const short *history, const int nsuppr, const int ntaps)
++{
++ int i;
++ int correction;
++ for (i=0;i<ntaps;i++) {
++ correction = history[i] * nsuppr;
++ taps[i] += correction;
++ taps_short[i] = taps[i] >> 16;
++ }
++}
++
++static inline short MAX16(const short *y, int len, int *pos)
++{
++ int k;
++ short max = 0;
++ int bestpos = 0;
++ for (k=0;k<len;k++) {
++ if (max < y[k]) {
++ bestpos = k;
++ max = y[k];
++ }
++ }
++ *pos = (len - 1 - bestpos);
++ return max;
++}
++
++#endif /* MMX */
++#endif /* _ZAPTEL_ARITH_H */
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/biquad.h mISDN/drivers/isdn/hardware/mISDN/biquad.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/biquad.h 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/biquad.h 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,73 @@
++/*
++ * SpanDSP - a series of DSP components for telephony
++ *
++ * biquad.h - General telephony bi-quad section routines (currently this just
++ * handles canonic/type 2 form)
++ *
++ * Written by Steve Underwood <steveu@coppice.org>
++ *
++ * Copyright (C) 2001 Steve Underwood
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++typedef struct
++{
++ int32_t gain;
++ int32_t a1;
++ int32_t a2;
++ int32_t b1;
++ int32_t b2;
++
++ int32_t z1;
++ int32_t z2;
++} biquad2_state_t;
++
++static inline void biquad2_init (biquad2_state_t *bq,
++ int32_t gain,
++ int32_t a1,
++ int32_t a2,
++ int32_t b1,
++ int32_t b2)
++{
++ bq->gain = gain;
++ bq->a1 = a1;
++ bq->a2 = a2;
++ bq->b1 = b1;
++ bq->b2 = b2;
++
++ bq->z1 = 0;
++ bq->z2 = 0;
++}
++/*- End of function --------------------------------------------------------*/
++
++static inline int16_t biquad2 (biquad2_state_t *bq, int16_t sample)
++{
++ int32_t y;
++ int32_t z0;
++
++ z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2;
++ y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2;
++
++ bq->z2 = bq->z1;
++ bq->z1 = z0 >> 15;
++ y >>= 15;
++ return y;
++}
++/*- End of function --------------------------------------------------------*/
++/*- End of file ------------------------------------------------------------*/
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp_cancel.c mISDN/drivers/isdn/hardware/mISDN/dsp_cancel.c
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp_cancel.c 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/dsp_cancel.c 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,390 @@
++/* $Id: mISDN_echo_cancel.patch,v 1.1 2005/11/07 16:01:31 nadi Exp $
++ *
++ * Simple but fast Echo cancellation for mISDN_dsp.
++ *
++ * Copyright Andreas Eversberg (jolly@jolly.de)
++ *
++ * This software may be used and distributed according to the terms
++ * of the GNU General Public License, incorporated herein by reference.
++ *
++ */
++
++#include "layer1.h"
++#include "helper.h"
++#include "debug.h"
++#include "dsp.h"
++
++
++/*
++ * how this works:
++ *
++ *
++ *
++ */
++void bchdev_echocancel_chunk(dsp_t* dev, uint8_t *rxchunk, uint8_t *txchunk, uint16_t size);
++int bchdev_echocancel_activate(dsp_t* dev, int deftaps, int train);
++void bchdev_echocancel_deactivate(dsp_t* dev);
++
++
++
++
++
++
++static char flip_table[256];
++
++void dsp_cancel_init_flip_bits()
++{
++ int i,k;
++
++ for (i = 0 ; i < 256 ; i++) {
++ unsigned char sample = 0 ;
++ for (k = 0; k<8; k++) {
++ if ( i & 1 << k ) sample |= 0x80 >> k;
++ }
++ flip_table[i] = sample;
++ }
++}
++
++static unsigned char * flip_buf_bits ( unsigned char * buf , int len)
++{
++ int i;
++ char * start = buf;
++
++ for (i = 0 ; i < len; i++) {
++ buf[i] = flip_table[buf[i]];
++ }
++
++ return start;
++}
++
++
++
++void
++dsp_cancel_tx(dsp_t *dsp, u8 *data, int len)
++{
++ if (!dsp ) return ;
++ if (!data) return;
++
++ if (dsp->txbuflen + len < ECHOCAN_BUFLEN) {
++ memcpy(&dsp->txbuf[dsp->txbuflen],data,len);
++ dsp->txbuflen+=len;
++ } else {
++ printk("ECHOCAN: TXBUF Overflow len:%d newlen:%d\n",dsp->txbuflen,len);
++ dsp->txbuflen=0;
++ }
++
++}
++
++void
++dsp_cancel_rx(dsp_t *dsp, u8 *data, int len)
++{
++ if (!dsp ) return ;
++ if (!data) return;
++
++ if (len <= dsp->txbuflen) {
++ char tmp[ECHOCAN_BUFLEN];
++
++ int delta=dsp->txbuflen-len;
++
++ memcpy(tmp,&dsp->txbuf[len],delta);
++
++ flip_buf_bits(data,len);
++ flip_buf_bits(dsp->txbuf,len);
++ bchdev_echocancel_chunk(dsp, data, dsp->txbuf, len);
++ flip_buf_bits(data,len);
++
++ memcpy(dsp->txbuf,tmp,delta);
++ dsp->txbuflen=delta;
++ //dsp->txbuflen=0;
++
++ //bchdev_echocancel_chunk(dsp, dsp->txbuf, data, len);
++ } else {
++ printk("ECHOCAN: TXBUF Underrun len:%d newlen:%d\n",dsp->txbuflen,len);
++ }
++
++}
++
++int
++dsp_cancel_init(dsp_t *dsp, int deftaps, int training, int delay)
++{
++
++ if (!dsp) return -1;
++
++ printk("DSP_CANCEL_INIT called\n");
++
++ if (delay < 0)
++ {
++ printk("Disabling EC\n");
++ dsp->cancel_enable = 0;
++
++ dsp->txbuflen=0;
++
++ bchdev_echocancel_deactivate(dsp);
++
++ return(0);
++ }
++
++ dsp->txbuflen=0;
++ dsp->rxbuflen=0;
++
++
++ bchdev_echocancel_activate(dsp,deftaps, training);
++
++ printk("Enabling EC\n");
++ dsp->cancel_enable = 1;
++ return(0);
++}
++
++
++
++
++
++/*****************************************************/
++#define __ECHO_STATE_MUTE (1 << 8)
++#define ECHO_STATE_IDLE (0)
++#define ECHO_STATE_PRETRAINING (1 | (__ECHO_STATE_MUTE))
++#define ECHO_STATE_STARTTRAINING (2 | (__ECHO_STATE_MUTE))
++#define ECHO_STATE_AWAITINGECHO (3 | (__ECHO_STATE_MUTE))
++#define ECHO_STATE_TRAINING (4 | (__ECHO_STATE_MUTE))
++#define ECHO_STATE_ACTIVE (5)
++
++#define AMI_MASK 0x55
++
++
++static unsigned char linear2alaw (short linear)
++{
++ int mask;
++ int seg;
++ int pcm_val;
++ static int seg_end[8] =
++ {
++ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
++ };
++
++ pcm_val = linear;
++ if (pcm_val >= 0)
++ {
++ /* Sign (7th) bit = 1 */
++ mask = AMI_MASK | 0x80;
++ }
++ else
++ {
++ /* Sign bit = 0 */
++ mask = AMI_MASK;
++ pcm_val = -pcm_val;
++ }
++
++ /* Convert the scaled magnitude to segment number. */
++ for (seg = 0; seg < 8; seg++)
++ {
++ if (pcm_val <= seg_end[seg])
++ break;
++ }
++ /* Combine the sign, segment, and quantization bits. */
++ return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask;
++}
++
++/*- End of function --------------------------------------------------------*/
++
++static short int alaw2linear (uint8_t alaw)
++{
++ int i;
++ int seg;
++
++ alaw ^= AMI_MASK;
++ i = ((alaw & 0x0F) << 4);
++ seg = (((int) alaw & 0x70) >> 4);
++ if (seg)
++ i = (i + 0x100) << (seg - 1);
++ return (short int) ((alaw & 0x80) ? i : -i);
++}
++
++
++/** @return string of given echo cancellation state */
++char* bchdev_echocancel_statestr(uint16_t state)
++{
++ switch(state) {
++ case ECHO_STATE_IDLE:
++ return "idle";
++ break;
++ case ECHO_STATE_PRETRAINING:
++ return "pre-training";
++ break;
++ case ECHO_STATE_STARTTRAINING:
++ return "transmit impulse";
++ break;
++ case ECHO_STATE_AWAITINGECHO:
++ return "awaiting echo";
++ break;
++ case ECHO_STATE_TRAINING:
++ return "training start";
++ break;
++ case ECHO_STATE_ACTIVE:
++ return "training finished";
++ break;
++ default:
++ return "unknown";
++ }
++}
++
++/** Changes state of echo cancellation to given state */
++void bchdev_echocancel_setstate(dsp_t* dev, uint16_t state)
++{
++ char* statestr = bchdev_echocancel_statestr(state);
++
++ printk("bchdev: echo cancel state %d (%s)\n", state & 0xff, statestr);
++ if (state == ECHO_STATE_ACTIVE)
++ printk("bchdev: %d taps trained\n", dev->echolastupdate);
++ dev->echostate = state;
++}
++
++static int buf_size=0;
++static int ec_timer=2000;
++//static int ec_timer=1000;
++
++
++/** Activates echo cancellation for the given bch_dev, device must have been locked before! */
++int bchdev_echocancel_activate(dsp_t* dev, int deftaps, int training)
++{
++ int taps;
++
++ if (! dev) return -EINVAL;
++
++ if (dev->ec && dev->ecdis_rd && dev->ecdis_wr) {
++ // already active
++ return 0;
++ }
++
++ if (deftaps>0) {
++ taps=deftaps;
++ } else {
++ taps=128;
++ }
++
++
++ switch (buf_size) {
++ case 0: taps += 0; break;
++ case 1: taps += 256-128; break;
++ case 2: taps += 512-128; break;
++ default: taps += 1024-128;
++ }
++
++ if (!dev->ec) dev->ec = echo_can_create(taps, 0);
++ if (!dev->ec) {
++ return -ENOMEM;
++ }
++
++ dev->echolastupdate = 0;
++
++ if (!training) {
++ dev->echotimer=0;
++ bchdev_echocancel_setstate(dev, ECHO_STATE_IDLE);
++ } else {
++ if (training<10)
++ training= ec_timer;
++
++ dev->echotimer = training;
++ bchdev_echocancel_setstate(dev, ECHO_STATE_PRETRAINING);
++
++ }
++
++ if (!dev->ecdis_rd) dev->ecdis_rd = kmalloc(sizeof(echo_can_disable_detector_state_t), GFP_KERNEL);
++ if (!dev->ecdis_rd) {
++ kfree(dev->ec); dev->ec = NULL;
++ return -ENOMEM;
++ }
++ echo_can_disable_detector_init(dev->ecdis_rd);
++
++ if (!dev->ecdis_wr) dev->ecdis_wr = kmalloc(sizeof(echo_can_disable_detector_state_t), GFP_KERNEL);
++ if (!dev->ecdis_wr) {
++ kfree(dev->ec); dev->ec = NULL;
++ kfree(dev->ecdis_rd); dev->ecdis_rd = NULL;
++ return -ENOMEM;
++ }
++ echo_can_disable_detector_init(dev->ecdis_wr);
++
++ return 0;
++}
++
++/** Deactivates echo cancellation for the given bch_dev, device must have been locked before! */
++void bchdev_echocancel_deactivate(dsp_t* dev)
++{
++ if (! dev) return;
++
++ //chan_misdn_log("bchdev: deactivating echo cancellation on port=%04x, chan=%02x\n", dev->stack->port, dev->channel);
++
++ if (dev->ec) echo_can_free(dev->ec);
++ dev->ec = NULL;
++
++ dev->echolastupdate = 0;
++ dev->echotimer = 0;
++ bchdev_echocancel_setstate(dev, ECHO_STATE_IDLE);
++
++ if (dev->ecdis_rd) kfree(dev->ecdis_rd);
++ dev->ecdis_rd = NULL;
++
++ if (dev->ecdis_wr) kfree(dev->ecdis_wr);
++ dev->ecdis_wr = NULL;
++}
++
++/** Processes one TX- and one RX-packet with echocancellation */
++void bchdev_echocancel_chunk(dsp_t* dev, uint8_t *rxchunk, uint8_t *txchunk, uint16_t size)
++{
++ int16_t rxlin, txlin;
++ uint16_t pos;
++
++ /* Perform echo cancellation on a chunk if requested */
++ if (dev->ec) {
++ if (dev->echostate & __ECHO_STATE_MUTE) {
++ if (dev->echostate == ECHO_STATE_STARTTRAINING) {
++ // Transmit impulse now
++ txchunk[0] = linear2alaw(16384);
++ memset(txchunk+1, 0, size-1);
++ bchdev_echocancel_setstate(dev, ECHO_STATE_TRAINING); //AWAITINGECHO);
++ } else {
++ // train the echo cancellation
++ for (pos = 0; pos < size; pos++) {
++ rxlin = alaw2linear(rxchunk[pos]);
++ txlin = alaw2linear(txchunk[pos]);
++ if (dev->echostate == ECHO_STATE_PRETRAINING) {
++ if (dev->echotimer <= 0) {
++ dev->echotimer = 0;
++ bchdev_echocancel_setstate(dev, ECHO_STATE_STARTTRAINING);
++ } else {
++ dev->echotimer--;
++ }
++ }
++ if ((dev->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) {
++ dev->echolastupdate = 0;
++ bchdev_echocancel_setstate(dev, ECHO_STATE_TRAINING);
++ }
++ if (dev->echostate == ECHO_STATE_TRAINING) {
++ if (echo_can_traintap(dev->ec, dev->echolastupdate++, rxlin)) {
++ bchdev_echocancel_setstate(dev, ECHO_STATE_ACTIVE);
++ }
++ }
++
++ rxchunk[pos] = linear2alaw(0);
++ txchunk[pos] = linear2alaw(0);
++ }
++ }
++ } else {
++ for (pos = 0; pos < size; pos++) {
++ rxlin = alaw2linear(rxchunk[pos]);
++ txlin = alaw2linear(txchunk[pos]);
++
++ if (echo_can_disable_detector_update(dev->ecdis_rd, rxlin) ||
++ echo_can_disable_detector_update(dev->ecdis_wr, txlin)) {
++ bchdev_echocancel_deactivate(dev);
++ printk("EC: Fax detected, EC disabled\n");
++ return ;
++ } else {
++ rxlin = echo_can_update(dev->ec, txlin, rxlin);
++ rxchunk[pos] = linear2alaw(rxlin);
++ }
++ }
++ }
++ }
++}
++
++/******************************************************/
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp_core.c mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp_core.c 2005-01-29 17:15:21.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/dsp_core.c 2005-12-02 09:57:08.000000000 +0100
+@@ -42,17 +42,11 @@
+ * v |
+ * +-----+-------------+-----+
+ * |(3)(4) |
+- * | |
+- * | |
+ * | CMX |
+ * | |
+- * | |
+- * | |
+- * | |
+ * | +-------------+
+ * | | ^
+ * | | |
+- * | | |
+ * |+---------+| +----+----+
+ * ||(1) || |(5) |
+ * || || | |
+@@ -62,7 +56,6 @@
+ * |+----+----+| +----+----+
+ * +-----+-----+ ^
+ * | |
+- * | |
+ * v |
+ * +----+----+ +----+----+
+ * |(5) | |(2) |
+@@ -74,8 +67,18 @@
+ * | ^
+ * | |
+ * v |
++ * +----+-------------+----+
++ * |(7) |
++ * | |
++ * | Echo Cancellation |
++ * | |
++ * | |
++ * +----+-------------+----+
++ * | ^
++ * | |
++ * v |
+ * +----+----+ +----+----+
+- * |(7) | |(7) |
++ * |(8) | |(8) |
+ * | | | |
+ * | Encrypt | | Decrypt |
+ * | | | |
+@@ -115,6 +118,13 @@
+ * data to/form upper layer may be swithed on/off individually without loosing
+ * features of CMX, Tones and DTMF.
+ *
++ * Echo Cancellation: Sometimes we like to cancel echo from the interface.
++ * Note that a VoIP call may not have echo caused by the IP phone. The echo
++ * is generated by the telephone line connected to it. Because the delay
++ * is high, it becomes an echo. RESULT: Echo Cachelation is required if
++ * both echo AND delay is applied to an interface.
++ * Remember that software CMX always generates a more or less delay.
++ *
+ * If all used features can be realized in hardware, and if transmit and/or
+ * receive data ist disabled, the card may not send/receive any data at all.
+ * Not receiving is usefull if only announcements are played. Not sending is
+@@ -215,6 +225,9 @@
+ printk(KERN_ERR "%s: failed to create tx packet\n", __FUNCTION__);
+ return;
+ }
++ /* if echo cancellation is enabled */
++ if (dsp->cancel_enable)
++ dsp_cancel_tx(dsp, nskb->data, nskb->len);
+ /* crypt if enabled */
+ if (dsp->bf_enable)
+ dsp_bf_encrypt(dsp, nskb->data, nskb->len);
+@@ -380,6 +393,34 @@
+ if (dsp_debug & DEBUG_DSP_CMX)
+ dsp_cmx_debug(dsp);
+ break;
++ case ECHOCAN_ON: /* turn echo calcellation on */
++
++ if (len<4) {
++ ret = -EINVAL;
++ break;
++ }
++ int ec_arr[2];
++
++ memcpy(&ec_arr,data,sizeof(ec_arr));
++
++
++ printk("data[0]: %d data[1]: %d, len :%d\n",ec_arr[0],
++ ec_arr[1] ,len);
++
++ if (dsp_debug & DEBUG_DSP_CORE)
++ printk(KERN_DEBUG "%s: turn echo cancelation on (delay=%d attenuation-shift=%d\n", __FUNCTION__, ec_arr[0], ec_arr[1]);
++
++ ret = dsp_cancel_init(dsp, ec_arr[0], ec_arr[1] ,1);
++
++ dsp_cmx_hardware(dsp->conf, dsp);
++ break;
++ case ECHOCAN_OFF: /* turn echo calcellation off */
++ if (dsp_debug & DEBUG_DSP_CORE)
++ printk(KERN_DEBUG "%s: turn echo cancelation off\n", __FUNCTION__);
++
++ ret = dsp_cancel_init(dsp, 0,0,-1);
++ dsp_cmx_hardware(dsp->conf, dsp);
++ break;
+ case BF_ENABLE_KEY: /* turn blowfish on */
+ if (len<4 || len>56) {
+ ret = -EINVAL;
+@@ -522,6 +563,9 @@
+ /* decrypt if enabled */
+ if (dsp->bf_enable)
+ dsp_bf_decrypt(dsp, skb->data, skb->len);
++ /* if echo cancellation is enabled */
++ if (dsp->cancel_enable)
++ dsp_cancel_rx(dsp, skb->data, skb->len);
+ /* check if dtmf soft decoding is turned on */
+ if (dsp->dtmf.software) {
+ digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, (dsp_options&DSP_OPT_ULAW)?1:0);
+@@ -919,6 +963,9 @@
+ dsp_audio_generate_ulaw_samples();
+ dsp_audio_generate_volume_changes();
+
++
++ dsp_cancel_init_flip_bits();
++
+ /* init global lock */
+ lock_HW_init(&dsp_lock);
+
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp.h mISDN/drivers/isdn/hardware/mISDN/dsp.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/dsp.h 2005-01-29 17:15:31.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/dsp.h 2005-12-02 09:57:08.000000000 +0100
+@@ -40,6 +40,13 @@
+ #include "memdbg.h"
+ #endif
+
++#include "ecdis.h"
++#include "mec2.h"
++
++//#include "mec.h"
++//#include "mec3.h"
++
++
+ extern int dsp_options;
+ extern int dsp_debug;
+
+@@ -109,6 +116,8 @@
+
+ #define DSP_DTMF_NPOINTS 102
+
++#define ECHOCAN_BUFLEN 4*128
++
+ typedef struct _dtmf_t {
+ int software; /* dtmf uses software decoding */
+ int hardware; /* dtmf uses hardware decoding */
+@@ -120,6 +129,13 @@
+ } dtmf_t;
+
+
++/**************
++ *Cancel Stuff*
++ ***************/
++
++void dsp_cancel_init_flip_bits(void);
++
++
+ /***************
+ * tones stuff *
+ ***************/
+@@ -200,6 +216,25 @@
+ u8 bf_crypt_inring[16];
+ u8 bf_data_out[9];
+ int bf_sync;
++
++ /* echo cancellation stuff */
++ int cancel_enable;
++ echo_can_state_t* 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 */
+@@ -228,4 +263,8 @@
+ 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);
++
+
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/ec.c mISDN/drivers/isdn/hardware/mISDN/ec.c
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/ec.c 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/ec.c 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,105 @@
++#include "mec2.h"
++#include "ec.h"
++
++
++
++#define __ECHO_STATE_MUTE (1 << 8)
++#define ECHO_STATE_IDLE (0)
++#define ECHO_STATE_PRETRAINING (1 | (__ECHO_STATE_MUTE))
++#define ECHO_STATE_STARTTRAINING (2 | (__ECHO_STATE_MUTE))
++#define ECHO_STATE_AWAITINGECHO (3 | (__ECHO_STATE_MUTE))
++#define ECHO_STATE_TRAINING (4 | (__ECHO_STATE_MUTE))
++#define ECHO_STATE_ACTIVE (5)
++
++#define AMI_MASK 0x55
++
++static unsigned char linear2alaw (short linear)
++{
++ int mask;
++ int seg;
++ int pcm_val;
++ static int seg_end[8] =
++ {
++ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
++ };
++
++ pcm_val = linear;
++ if (pcm_val >= 0)
++ {
++ /* Sign (7th) bit = 1 */
++ mask = AMI_MASK | 0x80;
++ }
++ else
++ {
++ /* Sign bit = 0 */
++ mask = AMI_MASK;
++ pcm_val = -pcm_val;
++ }
++
++ /* Convert the scaled magnitude to segment number. */
++ for (seg = 0; seg < 8; seg++)
++ {
++ if (pcm_val <= seg_end[seg])
++ break;
++ }
++ /* Combine the sign, segment, and quantization bits. */
++ return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask;
++}
++/*- End of function --------------------------------------------------------*/
++
++static short int alaw2linear (uint8_t alaw)
++{
++ int i;
++ int seg;
++
++ alaw ^= AMI_MASK;
++ i = ((alaw & 0x0F) << 4);
++ seg = (((int) alaw & 0x70) >> 4);
++ if (seg)
++ i = (i + 0x100) << (seg - 1);
++ return (short int) ((alaw & 0x80) ? i : -i);
++}
++
++
++void ec_chunk(struct echo_can_s *echo_can, unsigned char *rxchunk, const unsigned char *txchunk, int chunk_size)
++{
++ short rxlin, txlin;
++ int x;
++ //unsigned long flags;
++ /* Perform echo cancellation on a chunk if necessary */
++ if (echo_can->ec) {
++ if (echo_can->echostate & __ECHO_STATE_MUTE) {
++ /* Special stuff for training the echo can */
++ for (x=0;x< chunk_size;x++) {
++ rxlin = alaw2linear(rxchunk[x]);
++ txlin = alaw2linear(txchunk[x]);
++ if (echo_can->echostate == ECHO_STATE_PRETRAINING) {
++ if (--echo_can->echotimer <= 0) {
++ echo_can->echotimer = 0;
++ echo_can->echostate = ECHO_STATE_STARTTRAINING;
++ }
++ }
++ if ((echo_can->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) {
++ echo_can->echolastupdate = 0;
++ echo_can->echostate = ECHO_STATE_TRAINING;
++ }
++ if (echo_can->echostate == ECHO_STATE_TRAINING) {
++ if (echo_can_traintap(echo_can->ec, echo_can->echolastupdate++, rxlin)) {
++#if 0
++ printf("Finished training (%d taps trained)!\n", echo_can->echolastupdate);
++#endif
++ echo_can->echostate = ECHO_STATE_ACTIVE;
++ }
++ }
++ rxlin = 0;
++ rxchunk[x] = linear2alaw((int)rxlin);
++ }
++ } else {
++ for (x=0;x<chunk_size;x++) {
++ rxlin = alaw2linear(rxchunk[x]);
++ rxlin = echo_can_update(echo_can->ec, alaw2linear(txchunk[x]), rxlin);
++ rxchunk[x] = linear2alaw((int)rxlin);
++ }
++ }
++ }
++}
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/ecdis.h mISDN/drivers/isdn/hardware/mISDN/ecdis.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/ecdis.h 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/ecdis.h 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,118 @@
++/*
++ * SpanDSP - a series of DSP components for telephony
++ *
++ * ec_disable_detector.h - A detector which should eventually meet the
++ * G.164/G.165 requirements for detecting the
++ * 2100Hz echo cancellor disable tone.
++ *
++ * Written by Steve Underwood <steveu@coppice.org>
++ *
++ * Copyright (C) 2001 Steve Underwood
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include "biquad.h"
++
++typedef struct
++{
++ biquad2_state_t notch;
++ int notch_level;
++ int channel_level;
++ int tone_present;
++ int tone_cycle_duration;
++ int good_cycles;
++ int hit;
++} echo_can_disable_detector_state_t;
++
++
++#define FALSE 0
++#define TRUE (!FALSE)
++
++static inline void echo_can_disable_detector_init (echo_can_disable_detector_state_t *det)
++{
++ /* Elliptic notch */
++ /* This is actually centred at 2095Hz, but gets the balance we want, due
++ to the asymmetric walls of the notch */
++ biquad2_init (&det->notch,
++ (int32_t) (-0.7600000*32768.0),
++ (int32_t) (-0.1183852*32768.0),
++ (int32_t) (-0.5104039*32768.0),
++ (int32_t) ( 0.1567596*32768.0),
++ (int32_t) ( 1.0000000*32768.0));
++
++ det->channel_level = 0;
++ det->notch_level = 0;
++ det->tone_present = FALSE;
++ det->tone_cycle_duration = 0;
++ det->good_cycles = 0;
++ det->hit = 0;
++}
++/*- End of function --------------------------------------------------------*/
++
++static inline int echo_can_disable_detector_update (echo_can_disable_detector_state_t *det,
++ int16_t amp)
++{
++ int16_t notched;
++
++ notched = biquad2 (&det->notch, amp);
++ /* Estimate the overall energy in the channel, and the energy in
++ the notch (i.e. overall channel energy - tone energy => noise).
++ Use abs instead of multiply for speed (is it really faster?).
++ Damp the overall energy a little more for a stable result.
++ Damp the notch energy a little less, so we don't damp out the
++ blip every time the phase reverses */
++ det->channel_level += ((abs(amp) - det->channel_level) >> 5);
++ det->notch_level += ((abs(notched) - det->notch_level) >> 4);
++ if (det->channel_level > 280)
++ {
++ /* There is adequate energy in the channel. Is it mostly at 2100Hz? */
++ if (det->notch_level*6 < det->channel_level)
++ {
++ /* The notch says yes, so we have the tone. */
++ if (!det->tone_present)
++ {
++ /* Do we get a kick every 450+-25ms? */
++ if (det->tone_cycle_duration >= 425*8
++ &&
++ det->tone_cycle_duration <= 475*8)
++ {
++ det->good_cycles++;
++ if (det->good_cycles > 2)
++ det->hit = TRUE;
++ }
++ det->tone_cycle_duration = 0;
++ }
++ det->tone_present = TRUE;
++ }
++ else
++ {
++ det->tone_present = FALSE;
++ }
++ det->tone_cycle_duration++;
++ }
++ else
++ {
++ det->tone_present = FALSE;
++ det->tone_cycle_duration = 0;
++ det->good_cycles = 0;
++ }
++ return det->hit;
++}
++/*- End of function --------------------------------------------------------*/
++/*- End of file ------------------------------------------------------------*/
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/ec.h mISDN/drivers/isdn/hardware/mISDN/ec.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/ec.h 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/ec.h 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,12 @@
++
++
++
++struct echo_can_s {
++ int echostate;
++ int echotimer;
++ int echolastupdate;
++ echo_can_state_t *ec;
++};
++
++
++
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c 2005-01-31 18:24:03.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c 2005-12-02 09:57:08.000000000 +0100
+@@ -136,7 +136,7 @@
+ static int nt_t1_count[] = { 480, 240, 120, 60, 30, 15, 8, 4 };
+ #define CLKDEL_TE 0x0f /* CLKDEL in TE mode */
+ #define CLKDEL_NT 0x0c /* CLKDEL in NT mode (0x60 MUST not be included!) */
+-static u_char silence = 0xff; /* silence by LAW */
++static u_char mysilence = 0xff; /* silence by LAW */
+
+ /* enable 32 bit fifo access (PC usage) */
+ #define FIFO_32BIT_ACCESS
+@@ -903,11 +903,11 @@
+ bch->tx_idx = bch->tx_len = 0;
+ }
+ /* now we have no more data, so in case of transparent,
+- * we set the last byte in fifo to 'silence' in case we will get
++ * we set the last byte in fifo to 'mysilence' in case we will get
+ * no more data at all. this prevents sending an undefined value.
+ */
+ if (!hdlc)
+- HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence);
++ HFC_outb_(hc, A_FIFO_DATA0_NOINC, mysilence);
+ }
+
+
+@@ -1551,7 +1551,7 @@
+ HFC_outb(hc, A_IRQ_MSK, 0);
+ HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
+ HFC_wait(hc);
+- HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); /* tx silence */
++ HFC_outb_(hc, A_FIFO_DATA0_NOINC, mysilence); /* tx silence */
+ /* enable RX fifo */
+ HFC_outb(hc, R_FIFO, (ch<<1)|1);
+ HFC_wait(hc);
+@@ -1692,7 +1692,7 @@
+
+ /* if off */
+ if (len <= 0) {
+- HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence);
++ HFC_outb_(hc, A_FIFO_DATA0_NOINC, mysilence);
+ if (hc->chan[ch].slot_tx>=0) {
+ if (debug & DEBUG_HFCMULTI_MODE)
+ printk(KERN_DEBUG "%s: connecting PCM due to no more TONE: channel %d slot_tx %d\n", __FUNCTION__, ch, hc->chan[ch].slot_tx);
+@@ -2183,7 +2183,7 @@
+ ret = 0;
+ break;
+
+- /* set silence */
++ /* set mysilence */
+ case HW_SPL_LOOP_OFF:
+ if (debug & DEBUG_HFCMULTI_MSG)
+ printk(KERN_DEBUG "%s: HW_SPL_LOOP_OFF\n", __FUNCTION__);
+@@ -2799,7 +2799,13 @@
+ if (debug & DEBUG_HFCMULTI_INIT)
+ printk(KERN_DEBUG "setup_pci(): investigating card entry %d (looking for type %d)\n", i, hc->type);
+ inuse:
++
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
++ tmp_dev = pci_get_subsys(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_sub, id_list[i].device_sub, tmp_dev);
++#else
+ tmp_dev = pci_find_subsys(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_sub, id_list[i].device_sub, tmp_dev);
++#endif
++
+ if (tmp_dev) {
+ /* skip if already in use */
+ list_for_each_entry_safe(hc_tmp, next, &HFCM_obj.ilist, list) {
+@@ -3318,9 +3324,9 @@
+ hc->type = type[HFC_cnt] & 0xff;
+ if (type[HFC_cnt] & 0x100) {
+ test_and_set_bit(HFC_CHIP_ULAW, &hc->chip);
+- silence = 0xff; /* ulaw silence */
++ mysilence = 0xff; /* ulaw silence */
+ } else
+- silence = 0x2a; /* alaw silence */
++ mysilence = 0x2a; /* alaw silence */
+ if (type[HFC_cnt] & 0x200)
+ test_and_set_bit(HFC_CHIP_DTMF, &hc->chip);
+ // if ((type[HFC_cnt]&0x400) && hc->type==4)
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c 2005-03-26 11:21:39.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/l3_udss1.c 2005-12-02 09:57:08.000000000 +0100
+@@ -1202,6 +1202,14 @@
+ err = check_infoelements(pc, skb, ie_PROGRESS);
+ if (err)
+ l3dss1_std_ie_err(pc, err);
++ /* START: patch by steinwej - http://www.beronet.com/bugs/bug_view_page.php?bug_id=0000095 */
++ /* clear T310 if running */
++ L3DelTimer(&pc->timer);
++ if (pc->t303skb) {
++ dev_kfree_skb(pc->t303skb);
++ pc->t303skb = NULL;
++ }
++ /* END */
+ if (ERR_IE_COMPREHENSION != err) {
+ if (mISDN_l3up(pc, CC_PROGRESS | INDICATION, skb))
+ dev_kfree_skb(skb);
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/Makefile mISDN/drivers/isdn/hardware/mISDN/Makefile
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/Makefile 2005-06-05 14:44:10.000000000 +0200
++++ mISDN/drivers/isdn/hardware/mISDN/Makefile 2005-12-05 19:03:11.000000000 +0100
+@@ -30,6 +30,7 @@
+
+ ifdef CONFIG_MISDN_SPEEDFAX
+ obj-$(CONFIG_MISDN_DRV) += sedlfax.o
++obj-$(CONFIG_MISDN_DRV) += faxl3.o
+ endif
+
+ ifdef CONFIG_MISDN_W6692
+@@ -70,8 +71,6 @@
+ 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_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
+ mISDN_x25dte-objs := x25_dte.o x25_l3.o
+ I4LmISDN-objs := i4l_mISDN.o
+-
+-include Rules.mISDN
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6 mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6 2005-06-05 14:44:10.000000000 +0200
++++ mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6 2005-12-02 09:57:08.000000000 +0100
+@@ -71,6 +71,6 @@
+ 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_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
+ mISDN_x25dte-objs := x25_dte.o x25_l3.o
+ I4LmISDN-objs := i4l_mISDN.o
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/mec2_const.h mISDN/drivers/isdn/hardware/mISDN/mec2_const.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/mec2_const.h 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/mec2_const.h 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,25 @@
++/*
++ Important constants for tuning mec2 echo can
++ */
++#ifndef _MEC2_CONST_H
++#define _MEC2_CONST_H
++
++
++/* Convergence speed -- higher means slower */
++#define DEFAULT_BETA1_I 2048
++#define DEFAULT_SIGMA_LY_I 7
++#define DEFAULT_SIGMA_LU_I 7
++#define DEFAULT_ALPHA_ST_I 5
++#define DEFAULT_ALPHA_YT_I 5
++#define DEFAULT_CUTOFF_I 128
++#define DEFAULT_HANGT 600
++#define DEFAULT_SUPPR_I 16
++#define MIN_UPDATE_THRESH_I 4096
++#define DEFAULT_M 16
++#define SUPPR_FLOOR -64
++#define SUPPR_CEIL -24
++#define RES_SUPR_FACTOR -20
++#define AGGRESSIVE_HCNTR 160 /* 20ms */
++
++#endif /* _MEC2_CONST_H */
++
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/mec2.h mISDN/drivers/isdn/hardware/mISDN/mec2.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/mec2.h 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/mec2.h 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,409 @@
++/*
++ * Mark's Second Echo Canceller
++ *
++ * Copyright (C) 2002, Digium, Inc.
++ *
++ * This program is free software and may be used and
++ * distributed according to the terms of the GNU
++ * General Public License, incorporated herein by
++ * reference.
++ *
++ */
++#ifndef _MARK2_ECHO_H
++#define _MARK2_ECHO_H
++
++#ifdef __KERNEL__
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#define MALLOC(a) kmalloc((a), GFP_KERNEL)
++#define FREE(a) kfree(a)
++#else
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <string.h>
++#include <math.h>
++#define MALLOC(a) malloc(a)
++#define FREE(a) free(a)
++#endif
++
++/* Get optimized routines for math */
++#include "arith.h"
++
++#ifndef NULL
++#define NULL 0
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE (!FALSE)
++#endif
++
++#include "mec2_const.h"
++
++/* Circular buffer definition */
++typedef struct {
++ int idx_d;
++ int size_d;
++ short *buf_d; /* Twice as large as we need */
++} echo_can_cb_s;
++
++// class definition
++//
++typedef struct {
++ /* Echo canceller definition */
++
++ /* absolute time */
++ int i_d;
++
++ /* pre-computed constants */
++
++ int N_d;
++ int beta2_i;
++
++ // declare accumulators for power computations
++ //
++ int Ly_i;
++ int Lu_i;
++
++ // declare an accumulator for the near-end signal detector
++ //
++ int s_tilde_i;
++ int HCNTR_d;
++
++ // circular buffers and coefficients
++ //
++ int *a_i;
++ short *a_s;
++ echo_can_cb_s y_s;
++ echo_can_cb_s s_s;
++ echo_can_cb_s u_s;
++ echo_can_cb_s y_tilde_s;
++ int y_tilde_i;
++
++ /* Max memory */
++ short max_y_tilde;
++ int max_y_tilde_pos;
++
++} echo_can_state_t;
++
++static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
++{
++ cb->buf_d = (short *)where;
++ cb->idx_d = 0;
++ cb->size_d = len;
++}
++
++static inline void add_cc_s(echo_can_cb_s *cb, short newval)
++{
++ /* Can't use modulus because N+M isn't a power of two (generally) */
++ cb->idx_d--;
++ if (cb->idx_d < (int)0)
++ {cb->idx_d += cb->size_d;}
++ /* Load two copies into memory */
++ cb->buf_d[cb->idx_d] = newval;
++ cb->buf_d[cb->idx_d + cb->size_d] = newval;
++}
++
++static inline short get_cc_s(echo_can_cb_s *cb, int pos)
++{
++ /* Load two copies into memory */
++ return cb->buf_d[cb->idx_d + pos];
++}
++
++static inline void init_cc(echo_can_state_t *ec, int N, int maxy, int maxu) {
++
++ void *ptr = ec;
++ unsigned long tmp;
++ /* double-word align past end of state */
++ ptr += sizeof(echo_can_state_t);
++ tmp = (unsigned long)ptr;
++ tmp += 3;
++ tmp &= ~3L;
++ ptr = (void *)tmp;
++
++ // reset parameters
++ //
++ ec->N_d = N;
++ ec->beta2_i = DEFAULT_BETA1_I;
++
++ // allocate coefficient memory
++ //
++ ec->a_i = ptr;
++ ptr += (sizeof(int) * ec->N_d);
++ ec->a_s = ptr;
++ ptr += (sizeof(short) * ec->N_d);
++
++ /* Reset Y circular buffer (short version) */
++ init_cb_s(&ec->y_s, maxy, ptr);
++ ptr += (sizeof(short) * (maxy) * 2);
++
++ /* Reset Sig circular buffer (short version for FIR filter) */
++ init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
++ ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
++
++ init_cb_s(&ec->u_s, maxu, ptr);
++ ptr += (sizeof(short) * maxu * 2);
++
++ // allocate a buffer for the reference signal power computation
++ //
++ init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
++
++
++ // reset absolute time
++ //
++ ec->i_d = (int)0;
++
++ // reset the power computations (for y and u)
++ //
++ ec->Ly_i = DEFAULT_CUTOFF_I;
++ ec->Lu_i = DEFAULT_CUTOFF_I;
++
++ // reset the near-end speech detector
++ //
++ ec->s_tilde_i = 0;
++ ec->HCNTR_d = (int)0;
++
++ // exit gracefully
++ //
++}
++
++static inline void echo_can_free(echo_can_state_t *ec)
++{
++ FREE(ec);
++}
++
++static inline short echo_can_update(echo_can_state_t *ec, short iref, short isig) {
++
++ /* declare local variables that are used more than once
++ */
++ int k;
++ int rs;
++ short u;
++ int Py_i;
++ int two_beta_i;
++
++ /***************************************************************************
++ //
++ // flow A on pg. 428
++ //
++ ***************************************************************************/
++
++ /* eq. (16): high-pass filter the input to generate the next value;
++ // push the current value into the circular buffer
++ //
++ // sdc_im1_d = sdc_d;
++ // sdc_d = sig;
++ // s_i_d = sdc_d;
++ // s_d = s_i_d;
++ // s_i_d = (float)(1.0 - gamma_d) * s_i_d
++ + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d); */
++
++
++ /* Delete last sample from power estimate */
++ ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
++ /* push the reference data onto the circular buffer */
++ add_cc_s(&ec->y_s, iref);
++
++ /* eq. (2): compute r in fixed-point */
++ rs = CONVOLVE2(ec->a_s, ec->y_s.buf_d + ec->y_s.idx_d, ec->N_d);
++ rs >>= 15;
++
++ /* eq. (3): compute the output value (see figure 3) and the error
++ // note: the error is the same as the output signal when near-end
++ // speech is not present
++ */
++ u = isig - rs;
++
++ add_cc_s(&ec->u_s, u);
++
++
++
++ /* Delete oldest part of received s_tilde */
++ ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
++
++ /* push the signal on the circular buffer, too */
++ add_cc_s(&ec->s_s, isig);
++ ec->s_tilde_i += abs(isig);
++ ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_YT_I;
++
++ /* Add to our list of recent y_tilde's */
++ add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);
++
++ /****************************************************************************
++ //
++ // flow B on pg. 428
++ //
++ ****************************************************************************/
++
++ /* compute the new convergence factor
++ */
++ Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
++ Py_i >>= 15;
++ if (ec->HCNTR_d > 0) {
++ Py_i = (1 << 15);
++ }
++
++#if 0
++ printf("Py: %e, Py_i: %e\n", Py, Py_i * AMPL_SCALE_1);
++#endif
++
++ /* Vary rate of adaptation depending on position in the file
++ // Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
++ // has begun of the file to allow the echo cancellor to estimate the
++ // channel accurately
++ */
++#if 0
++ if (ec->start_speech_d != 0 ){
++ if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
++ ec->beta2_d = max_cc_float(MIN_BETA,
++ DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) -
++ DEFAULT_T0 -
++ ec->start_speech_d)));
++ }
++ }
++ else {ec->beta2_d = DEFAULT_BETA1;}
++#endif
++
++ ec->beta2_i = DEFAULT_BETA1_I; /* Fixed point, inverted */
++
++ two_beta_i = (ec->beta2_i * Py_i) >> 15; /* Fixed point version, inverted */
++ if (!two_beta_i)
++ two_beta_i++;
++
++ /* Update Lu_i (Suppressed power estimate) */
++ ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
++ ec->Lu_i += abs(u);
++
++ /* eq. (10): update power estimate of the reference
++ */
++ ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
++ ec->Ly_i += abs(iref);
++
++ if (ec->Ly_i < DEFAULT_CUTOFF_I)
++ ec->Ly_i = DEFAULT_CUTOFF_I;
++
++#if 0
++ printf("Float: %e, Int: %e\n", ec->Ly_d, (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * AMPL_SCALE_1);
++#endif
++
++ if (ec->y_tilde_i > ec->max_y_tilde) {
++ /* New highest y_tilde with full life */
++ ec->max_y_tilde = ec->y_tilde_i;
++ ec->max_y_tilde_pos = ec->N_d - 1;
++ } else if (--ec->max_y_tilde_pos < 0) {
++ /* Time to find new max y tilde... */
++ ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
++ }
++
++ if ((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
++ {
++ ec->HCNTR_d = DEFAULT_HANGT;
++ }
++ else if (ec->HCNTR_d > (int)0)
++ {
++ ec->HCNTR_d--;
++ }
++
++ /* update coefficients if no near-end speech and we have enough signal
++ * to bother trying to update.
++ */
++ if (!ec->HCNTR_d && !(ec->i_d % DEFAULT_M) &&
++ (ec->Lu_i > MIN_UPDATE_THRESH_I)) {
++ // loop over all filter coefficients
++ //
++ for (k=0; k<ec->N_d; k++) {
++
++ // eq. (7): compute an expectation over M_d samples
++ //
++ int grad2;
++ grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
++ ec->y_s.buf_d + ec->y_s.idx_d + k, DEFAULT_M);
++ // eq. (7): update the coefficient
++ //
++ ec->a_i[k] += grad2 / two_beta_i;
++ ec->a_s[k] = ec->a_i[k] >> 16;
++ }
++ }
++
++ /* paragraph below eq. (15): if no near-end speech,
++ // check for residual error suppression
++ */
++#ifndef NO_ECHO_SUPPRESSOR
++#ifdef AGGRESSIVE_SUPPRESSOR
++ if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
++ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
++ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
++ }
++#else
++ if ((ec->HCNTR_d == 0) && ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I)) {
++ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
++ }
++#endif
++#endif
++
++#if 0
++ if ((ec->HCNTR_d == 0) && ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
++ (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) {
++ suppr_factor = (10/(float)(SUPPR_FLOOR-SUPPR_CEIL))*log(ec->Lu_d/ec->Ly_d)
++ - SUPPR_CEIL/(float)(SUPPR_FLOOR - SUPPR_CEIL);
++
++ u_suppr = pow(10.0,(suppr_factor)*RES_SUPR_FACTOR/10.0)*u_suppr;
++
++ }
++#endif
++ ec->i_d++;
++ return u;
++}
++
++static inline echo_can_state_t *echo_can_create(int len, int adaption_mode)
++{
++ echo_can_state_t *ec;
++ int maxy;
++ int maxu;
++ maxy = len + DEFAULT_M;
++ maxu = DEFAULT_M;
++ if (maxy < (1 << DEFAULT_ALPHA_YT_I))
++ maxy = (1 << DEFAULT_ALPHA_YT_I);
++ if (maxy < (1 << DEFAULT_SIGMA_LY_I))
++ maxy = (1 << DEFAULT_SIGMA_LY_I);
++ if (maxu < (1 << DEFAULT_SIGMA_LU_I))
++ maxu = (1 << DEFAULT_SIGMA_LU_I);
++ ec = (echo_can_state_t *)MALLOC(sizeof(echo_can_state_t) +
++ 4 + /* align */
++ sizeof(int) * len + /* a_i */
++ sizeof(short) * len + /* a_s */
++ 2 * sizeof(short) * (maxy) + /* y_s */
++ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
++ 2 * sizeof(short) * (maxu) + /* u_s */
++ 2 * sizeof(short) * len); /* y_tilde_s */
++ if (ec) {
++ memset(ec, 0, sizeof(echo_can_state_t) +
++ 4 + /* align */
++ sizeof(int) * len + /* a_i */
++ sizeof(short) * len + /* a_s */
++ 2 * sizeof(short) * (maxy) + /* y_s */
++ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
++ 2 * sizeof(short) * (maxu) + /* u_s */
++ 2 * sizeof(short) * len); /* y_tilde_s */
++ init_cc(ec, len, maxy, maxu);
++ }
++ return ec;
++}
++
++static inline int echo_can_traintap(echo_can_state_t *ec, int pos, short val)
++{
++ /* Reset hang counter to avoid adjustments after
++ initial forced training */
++ ec->HCNTR_d = ec->N_d << 1;
++ if (pos >= ec->N_d)
++ return 1;
++ ec->a_i[pos] = val << 17;
++ ec->a_s[pos] = val << 1;
++ if (++pos >= ec->N_d)
++ return 1;
++ return 0;
++}
++
++#endif
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/mec3.h mISDN/drivers/isdn/hardware/mISDN/mec3.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/mec3.h 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/mec3.h 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,243 @@
++/*
++ * Mark's Third Echo Canceller
++ *
++ * Copyright (C) 2003, Digium, Inc.
++ *
++ * This program is free software and may be used
++ * and distributed under the terms of the GNU General Public
++ * License, incorporated herein by reference.
++ *
++ * Dedicated to the crew of the Columbia, STS-107 for their
++ * bravery and courageous sacrifice for science.
++ *
++ */
++
++#ifndef _MARK3_ECHO_H
++#define _MARK3_ECHO_H
++
++
++
++#ifdef __KERNEL__
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#define MALLOC(a) kmalloc((a), GFP_KERNEL)
++#define FREE(a) kfree(a)
++#else
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <string.h>
++#include <math.h>
++#define MALLOC(a) malloc(a)
++#define FREE(a) free(a)
++#endif
++
++/* Features */
++
++/*
++ * DO_BACKUP -- Backup coefficients, and revert in the presense of double talk to try to prevent
++ * them from diverging during the ramp-up before the DTD kicks in
++ */
++/* #define DO_BACKUP */
++
++#define STEP_SHIFT 2 /* Convergence rate higher = slower / better (as a shift) */
++
++#define SIGMA_REF_PWR 655 /* Keep denominator from being 0 */
++
++#define MIN_TX_ENERGY 256 /* Must have at least this much reference */
++#define MIN_RX_ENERGY 32 /* Must have at least this much receive energy */
++
++#define MAX_ATTENUATION_SHIFT 6 /* Maximum amount of loss we care about */
++#define MAX_BETA 1024
++
++#define SUPPR_SHIFT 4 /* Amount of loss at which we suppress audio */
++
++#define HANG_TIME 600 /* Hangover time */
++
++#define NTAPS 2048 /* Maximum number of echo can taps */
++
++#define BACKUP 256 /* Backup every this number of samples */
++
++#define POWER_OFFSET 5 /* Shift power by this amount to be sure we don't overflow the
++ reference power. Higher = less likely to overflow, lower = more accurage */
++
++#include "arith.h"
++
++typedef struct {
++ short buf[NTAPS * 2];
++ short max;
++ int maxexp;
++} cbuf_s;
++
++typedef struct {
++ short a_s[NTAPS]; /* Coefficients in shorts */
++ int a_i[NTAPS]; /* Coefficients in ints*/
++#ifdef DO_BACKUP
++ int b_i[NTAPS]; /* Coefficients (backup1) */
++ int c_i[NTAPS]; /* Coefficients (backup2) */
++#endif
++ cbuf_s ref; /* Reference excitation */
++ cbuf_s sig; /* Signal (echo + near end + noise) */
++ cbuf_s e; /* Error */
++ int refpwr; /* Reference power */
++ int taps; /* Number of taps */
++ int tappwr; /* Power of taps */
++ int hcntr; /* Hangtime counter */
++ int pos; /* Position in curcular buffers */
++ int backup; /* Backup timer */
++} echo_can_state_t;
++
++static inline void echo_can_free(echo_can_state_t *ec)
++{
++ FREE(ec);
++}
++
++static inline void buf_add(cbuf_s *b, short sample, int pos, int taps)
++{
++ /* Store and keep track of maxima */
++ int x;
++ b->buf[pos] = sample;
++ b->buf[pos + taps] = sample;
++ if (sample > b->max) {
++ b->max = sample;
++ b->maxexp = taps;
++ } else {
++ b->maxexp--;
++ if (!b->maxexp) {
++ b->max = 0;
++ for (x=0;x<taps;x++)
++ if (b->max < abs(b->buf[pos + x])) {
++ b->max = abs(b->buf[pos + x]);
++ b->maxexp = x + 1;
++ }
++ }
++ }
++}
++
++static inline short echo_can_update(echo_can_state_t *ec, short ref, short sig)
++{
++ int x;
++ short u;
++ int refpwr;
++ int beta; /* Factor */
++ int se; /* Simulated echo */
++#ifdef DO_BACKUP
++ if (!ec->backup) {
++ /* Backup coefficients periodically */
++ ec->backup = BACKUP;
++ memcpy(ec->c_i,ec->b_i,sizeof(ec->c_i));
++ memcpy(ec->b_i,ec->a_i,sizeof(ec->b_i));
++ } else
++ ec->backup--;
++#endif
++ /* Remove old samples from reference power calculation */
++ ec->refpwr -= ((ec->ref.buf[ec->pos] * ec->ref.buf[ec->pos]) >> POWER_OFFSET);
++
++ /* Store signal and reference */
++ buf_add(&ec->ref, ref, ec->pos, ec->taps);
++ buf_add(&ec->sig, sig, ec->pos, ec->taps);
++
++ /* Add new reference power */
++ ec->refpwr += ((ec->ref.buf[ec->pos] * ec->ref.buf[ec->pos]) >> POWER_OFFSET);
++
++
++ /* Calculate simulated echo */
++ se = CONVOLVE2(ec->a_s, ec->ref.buf + ec->pos, ec->taps);
++ se >>= 15;
++
++ u = sig - se;
++ if (ec->hcntr)
++ ec->hcntr--;
++
++ /* Store error */
++ buf_add(&ec->e, sig, ec->pos, ec->taps);
++ if ((ec->ref.max > MIN_TX_ENERGY) &&
++ (ec->sig.max > MIN_RX_ENERGY) &&
++ (ec->e.max > (ec->ref.max >> MAX_ATTENUATION_SHIFT))) {
++ /* We have sufficient energy */
++ if (ec->sig.max < (ec->ref.max >> 1)) {
++ /* No double talk */
++ if (!ec->hcntr) {
++ refpwr = ec->refpwr >> (16 - POWER_OFFSET);
++ if (refpwr < SIGMA_REF_PWR)
++ refpwr = SIGMA_REF_PWR;
++ beta = (u << 16) / refpwr;
++ beta >>= STEP_SHIFT;
++ if (beta > MAX_BETA)
++ beta = 0;
++ if (beta < -MAX_BETA)
++ beta = 0;
++ /* Update coefficients */
++ for (x=0;x<ec->taps;x++) {
++ ec->a_i[x] += beta * ec->ref.buf[ec->pos + x];
++ ec->a_s[x] = ec->a_i[x] >> 16;
++ }
++ }
++ } else {
++#ifdef DO_BACKUP
++ if (!ec->hcntr) {
++ /* Our double talk detector is turning on for the first time. Revert
++ our coefficients, since we're probably well into the double talk by now */
++ memcpy(ec->a_i, ec->c_i, sizeof(ec->a_i));
++ for (x=0;x<ec->taps;x++) {
++ ec->a_s[x] = ec->a_i[x] >> 16;
++ }
++ }
++#endif
++ /* Reset hang-time counter, and prevent backups */
++ ec->hcntr = HANG_TIME;
++#ifdef DO_BACKUP
++ ec->backup = BACKUP;
++#endif
++ }
++ }
++#ifndef NO_ECHO__SUPPRESSOR
++ if (ec->e.max < (ec->ref.max >> SUPPR_SHIFT)) {
++ /* Suppress residual echo */
++ u *= u;
++ u >>= 16;
++ }
++#endif
++ ec->pos--;
++ if (ec->pos < 0)
++ ec->pos = ec->taps-1;
++ return u;
++}
++
++static inline echo_can_state_t *echo_can_create(int taps, int adaption_mode)
++{
++ echo_can_state_t *ec;
++ int x;
++
++ //taps = NTAPS;
++ ec = MALLOC(sizeof(echo_can_state_t));
++ if (ec) {
++ memset(ec, 0, sizeof(echo_can_state_t));
++ ec->taps = taps;
++ ec->pos = ec->taps-1;
++ for (x=0;x<31;x++) {
++ if ((1 << x) >= ec->taps) {
++ ec->tappwr = x;
++ break;
++ }
++ }
++ }
++ return ec;
++}
++
++static inline int echo_can_traintap(echo_can_state_t *ec, int pos, short val)
++{
++ /* Reset hang counter to avoid adjustments after
++ initial forced training */
++ ec->hcntr = ec->taps << 1;
++ if (pos >= ec->taps)
++ return 1;
++ ec->a_i[pos] = val << 17;
++ ec->a_s[pos] = val << 1;
++ if (++pos >= ec->taps)
++ return 1;
++ return 0;
++}
++
++
++#endif
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/mec.h mISDN/drivers/isdn/hardware/mISDN/mec.h
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/mec.h 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/drivers/isdn/hardware/mISDN/mec.h 2005-12-02 09:57:08.000000000 +0100
+@@ -0,0 +1,308 @@
++/*
++ * Mark's Echo Canceller
++ *
++ * Mark Spencer <markster@linux-support.net>
++ *
++ * Simple, LMS Echo Canceller with double talk detection.
++ * Partly based on the TI App note:
++ * "Digital Voice Echo Canceller with a TMS 32020"
++ *
++ * Special additional thanks to:
++ * Jim Dixon (Lambda Telecommunications)
++ * Iman Ghobrial (Adtran, Inc.)
++ *
++ * Copyright (C) 2001, Linux Support Services, Inc.
++ *
++ * This program is free software and may be used and
++ * distributed according to the terms of the GNU
++ * General Public License, incorporated herein by
++ * reference.
++ *
++ */
++
++#ifndef _MEC_H
++#define _MEC_H
++
++/* You have to express the size of the echo canceller in taps as
++ a power of 2 (6 = 64 taps, 7 = 128 taps, 8 = 256 taps) */
++#define NUM_TAPS_POW2 6 /* Size of echo canceller in power of 2 (taps) */
++#define NUM_TAPS (1 << NUM_TAPS_POW2) /* Actual number of taps */
++#define TAP_MASK (NUM_TAPS-1)
++
++
++#define SIGMA_LU_POW NUM_TAPS_POW2
++#define SIGMA_LY_POW NUM_TAPS_POW2
++#define SIGMA_YT_POW (NUM_TAPS_POW2 - 1)
++#define SIGMA_ST_POW (NUM_TAPS_POW2 - 1)
++
++#define BETA_POW 8
++
++#define CUTOFF_S 4
++
++/* The higher you make this, the better the quality, but the more CPU time required */
++#define MIN_QUALITY 100
++
++/* This optimization saves a lot of processor but may degrade quality */
++#define OPTIMIZEDIV
++
++#if 0
++/* This converges much more slowly but saves processor */
++#define MIN_UPDATE 256
++#define MIN_SKIP 8
++#endif
++
++#define HANG_T 600 /* 600 samples, or 75ms */
++
++typedef struct mark_ec {
++ /* Circular position */
++ int cpos;
++ short y[NUM_TAPS]; /* Last N samples (relative to cpos) transmitted */
++ short y_abs[NUM_TAPS]; /* Last N samples (relative to cpos) transmitted (abs value) */
++ short s[NUM_TAPS]; /* Last N samples (relative to cpos) received */
++ short s_abs[NUM_TAPS]; /* Last N samples (relative to cpos) received (abs value) */
++ short u[NUM_TAPS]; /* Last N samples (relative to cpos) with echo removed */
++ short u_abs[NUM_TAPS]; /* Last N samples (relative to cpos) with echo removed */
++
++ int Ly; /* tx power */
++ int Lu; /* Power of echo-cancelled output */
++
++ int Ty[NUM_TAPS]; /* Short term power estimate of transmit */
++ int Ts; /* Short term power estimate of received signal */
++
++ int a[NUM_TAPS]; /* Tap weight coefficients (not relative) */
++
++ short sdc[NUM_TAPS]; /* Near end signal before High Pass Filter */
++
++ int samples; /* Sample count */
++ int pass; /* Number of passes we've made */
++
++ int hangt;
++
++ int lastmax; /* Optimize maximum search */
++ int maxTy; /* Maximum Ty */
++} echo_can_state_t;
++
++#define INLINE inline
++
++#ifdef __KERNEL__
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#define MALLOC(a) kmalloc((a), GFP_KERNEL)
++#define FREE(a) kfree((a))
++#else
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <string.h>
++#define MALLOC(a) malloc(a)
++#define FREE(a) free(a)
++#endif
++
++static INLINE echo_can_state_t *echo_can_create(int len, int adaption_mode)
++{
++ echo_can_state_t *ec;
++ /* Uhm, we're only one length, sorry. */
++ ec = MALLOC(sizeof(echo_can_state_t));
++ if (ec)
++ memset(ec, 0, sizeof(*ec));
++ return ec;
++}
++
++#define PASSPOS 32000
++#undef PASSPOS
++
++static INLINE void echo_can_free(echo_can_state_t *ec)
++{
++ FREE(ec);
++}
++
++static INLINE int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx)
++{
++ /* Process a sample, where tx is the near end and rx is the far end + echo */
++
++ int suppr;
++ int nsuppr;
++ short rxabs, txabs;
++ register int Lu;
++ register int x;
++ register int pos;
++ register int r_hat; /* Estimated echo */
++ int oldrxabs;
++ int oldtxabs;
++ int oldsupprabs;
++ int supprabs;
++#ifdef MIN_UPDATE
++ int totalupd;
++#endif
++
++ txabs = abs(tx);
++ rxabs = abs(rx);
++
++ ec->pass++;
++
++ r_hat = 0;
++
++ /* Load next value */
++ ec->y[ec->cpos] = tx;
++
++ /* Load next abs value */
++ oldtxabs = ec->y_abs[ec->cpos];
++ ec->y_abs[ec->cpos] = txabs;
++
++ /* Bring in receive value (near-end signal) */
++ ec->sdc[ec->cpos] = rx;
++
++ /* Bring in receive value absolute value */
++ oldrxabs = ec->s_abs[ec->cpos];
++ ec->s_abs[ec->cpos] = rxabs;
++
++ Lu = ec->Lu | 1;
++
++#if 0
++ /* Apply first order high pass filter (3 dB @ 160 Hz) */
++ tx = ec->s[ec->cpos] = (1.0-DEFGAMMA) * ec->s[(ec->cpos - 1) & TAP_MASK] +
++ 0.5 * (1.0-DEFGAMMA) * ( ec->sdc[(ec->cpos - 1) & TAP_MASK] - ec->sdc[(ec->cpos - 2) & TAP_MASK]);
++#endif
++
++ /* Estimate echo */
++ pos = ec->cpos;
++ for (x=0;x<NUM_TAPS;x++) {
++ r_hat += ec->a[x] * ec->y[pos];
++ /* Go backwards in time and loop around circular buffer */
++ pos = (pos - 1) & TAP_MASK;
++ }
++
++ r_hat >>= 16;
++
++ if (ec->hangt > 0)
++ ec->hangt--;
++
++ /* printf("rx: %F, rhat: %F\n", rx, r_hat); */
++ /* Calculate suppressed amount */
++ suppr = rx - r_hat;
++
++ if (ec->pass > NUM_TAPS) {
++ /* Have to have enough taps to start with */
++ if (ec->maxTy > ec->Ts) {
++ /* There is no near-end speech detected */
++ if (!ec->hangt) {
++ /* We're not in the hang-time from the end of near-end speech */
++ if ((ec->Ly > 1024) && ((ec->Ly / Lu) < MIN_QUALITY)) {
++#ifdef OPTIMIZEDIV
++ /* We both have enough signal on the transmit */
++ nsuppr = (suppr << 18) / ec->Ly;
++
++ if (nsuppr > 32767)
++ nsuppr = 32767;
++ if (nsuppr < -32768)
++ nsuppr = -32768;
++
++ nsuppr /= ec->Ly;
++#else
++ /* We both have enough signal on the transmit */
++ nsuppr = (suppr << 16) / ec->Ly;
++
++ if (nsuppr > 32767)
++ nsuppr = 32767;
++ if (nsuppr < -32768)
++ nsuppr = -32768;
++
++#endif
++
++ /* Update coefficients */
++ pos = ec->cpos;
++#ifdef MIN_UPDATE
++ totalupd =0;
++#endif
++ for (x=0;x<NUM_TAPS;x++) {
++ register int adj;
++ adj = ec->y[pos] * nsuppr;
++#ifndef OPTIMIZEDIV
++ adj /= ec->Ly;
++ adj >>= BETA_POW;
++#else
++ adj >>= BETA_POW + 2;
++#endif
++#ifdef PASSPOS
++ if (ec->pass > PASSPOS)
++ printf("tx: %d, old %d: %d, adj %d, nsuppr: %d, power: %d\n", tx, x, ec->a[x], adj, nsuppr, ec->Ly);
++#endif
++ ec->a[x] += adj;
++#ifdef MIN_UPDATE
++ totalupd += abs(adj);
++#endif
++ /* Go backwards in time and loop around circular buffer */
++ pos = (pos - 1) & TAP_MASK;
++ }
++#ifdef MIN_UPDATE
++ /* If we didn't update at least this much, delay for many more taps */
++ if (totalupd < MIN_UPDATE) {
++ ec->hangt += MIN_SKIP;
++ }
++#endif
++ }
++
++ }
++ } else
++ /* Near end speech detected */
++ ec->hangt = HANG_T;
++ }
++
++ /* Save supression and absolute values */
++ supprabs = abs(suppr);
++ oldsupprabs = ec->u_abs[ec->cpos];
++ ec->u[ec->cpos] = suppr;
++ ec->u_abs[ec->cpos] = supprabs;
++
++ /* Update tx power */
++ ec->Ly += (txabs >> SIGMA_LY_POW) - (oldtxabs >> SIGMA_LY_POW);
++
++ /* Update rx power */
++ ec->Lu += (supprabs >> SIGMA_LU_POW) - (oldsupprabs >> SIGMA_LU_POW);
++
++ /* Short term power of tx */
++ ec->Ty[ec->cpos] = ec->Ty[(ec->cpos - 1) & TAP_MASK] +
++ ((txabs >> SIGMA_YT_POW ) - (oldtxabs >> SIGMA_YT_POW));
++
++ /* Keep track of highest */
++ if (ec->lastmax == ec->cpos) {
++ register int maxTy = 0;
++ /* Have to loop through and find the new highest since our old highest expired */
++ /* Estimate echo */
++ pos = ec->cpos;
++ for (x=0;x<NUM_TAPS;x++) {
++ if (ec->Ty[pos] > maxTy)
++ maxTy = ec->Ty[pos];
++ /* Go backwards in time and loop around circular buffer */
++ pos = (pos - 1) & TAP_MASK;
++ }
++ ec->maxTy = maxTy;
++ } else {
++ /* Just keep the highest */
++ if (ec->Ty[ec->cpos] > ec->maxTy) {
++ ec->maxTy = ec->Ty[ec->cpos];
++ ec->lastmax = ec->cpos;
++ }
++ }
++ ec->Ts += (rxabs >> SIGMA_ST_POW) - (oldrxabs >> SIGMA_ST_POW) ;
++
++ /* Increment position memory */
++ ec->cpos = (ec->cpos + 1 ) & TAP_MASK;
++
++ return suppr;
++}
++
++static inline int echo_can_traintap(echo_can_state_t *ec, int pos, short val)
++{
++ /* Reset hang counter to avoid adjustments after
++ initial forced training */
++ ec->hangt = NUM_TAPS << 1;
++ if (pos >= NUM_TAPS)
++ return 1;
++ ec->a[pos] = val << 17;
++ if (++pos >= NUM_TAPS)
++ return 1;
++ return 0;
++}
++
++#endif
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c 2004-08-27 21:27:40.000000000 +0200
++++ mISDN/drivers/isdn/hardware/mISDN/sedl_fax.c 2005-12-02 09:57:08.000000000 +0100
+@@ -811,8 +811,8 @@
+ return(err);
+ }
+
+- printk(KERN_INFO "mISDN: sedlpci found adapter %s at %s\n",
+- (char *) ent->driver_data, pdev->slot_name);
++/* printk(KERN_INFO "mISDN: sedlpci found adapter %s at %s\n",
++ (char *) ent->driver_data, pdev->slot_name); */
+
+ card->cfg = pci_resource_start(pdev, 0);
+ card->irq = pdev->irq;
+diff -u -r -P /tmp/mISDN/drivers/isdn/hardware/mISDN/w6692.c mISDN/drivers/isdn/hardware/mISDN/w6692.c
+--- /tmp/mISDN/drivers/isdn/hardware/mISDN/w6692.c 2004-08-27 21:27:40.000000000 +0200
++++ mISDN/drivers/isdn/hardware/mISDN/w6692.c 2005-12-02 09:57:08.000000000 +0100
+@@ -1502,8 +1502,8 @@
+ return(err);
+ }
+
+- printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n",
+- (char *) ent->driver_data, pdev->slot_name);
++/* printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n",
++ (char *) ent->driver_data, pdev->slot_name); */
+
+ card->addr = pci_resource_start(pdev, 1);
+ card->irq = pdev->irq;
+diff -u -r -P /tmp/mISDN/include/linux/mISDNif.h mISDN/include/linux/mISDNif.h
+--- /tmp/mISDN/include/linux/mISDNif.h 2005-02-05 11:18:17.000000000 +0100
++++ mISDN/include/linux/mISDNif.h 2005-12-02 09:57:08.000000000 +0100
+@@ -173,6 +173,8 @@
+ #define BF_DISABLE 0x2315
+ #define BF_ACCEPT 0x2316
+ #define BF_REJECT 0x2317
++#define ECHOCAN_ON 0x2318
++#define ECHOCAN_OFF 0x2319
+ #define HW_POTS_ON 0x1001
+ #define HW_POTS_OFF 0x1002
+ #define HW_POTS_SETMICVOL 0x1100
+diff -u -r -P /tmp/mISDN/Makefile mISDN/Makefile
+--- /tmp/mISDN/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ mISDN/Makefile 2005-12-05 19:08:57.000000000 +0100
+@@ -0,0 +1,54 @@
++BASEDIR=$(shell pwd)
++
++
++INSTALL_PREFIX := /
++export INSTALL_PREFIX
++
++#PATH to linux source/headers
++#LINUX=/usr/src/linux
++LINUX=/lib/modules/$(shell uname -r)/build
++
++MISDNDIR=$(BASEDIR)
++MISDN_SRC=$(MISDNDIR)/drivers/isdn/hardware/mISDN
++
++########################################
++# USER CONFIGS END
++########################################
++
++CONFIGS+=CONFIG_MISDN_DRV=m CONFIG_MISDN_DSP=m
++CONFIGS+=CONFIG_MISDN_HFCMULTI=m
++CONFIGS+=CONFIG_MISDN_HFCPCI=m
++CONFIGS+=CONFIG_MISDN_HFCUSB=m
++#CONFIGS+=CONFIG_MISDN_AVM_FRITZ=m
++
++
++MINCLUDES+=-I$(MISDNDIR)/include
++
++all:
++ @echo
++ @echo "Makeing mISDN"
++ @echo "============="
++ @echo
++ cp $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile.v2.6 $(MISDNDIR)/drivers/isdn/hardware/mISDN/Makefile
++
++ cd $(LINUX) ; make SUBDIRS=$(MISDN_SRC) modules $(CONFIGS) LINUXINCLUDE="$(MINCLUDES) -I$(LINUX)/include"
++
++
++
++install: all
++ cd $(LINUX) ; make SUBDIRS=$(MISDN_SRC) modules_install
++ cp $(MISDNDIR)/include/linux/*.h $(INSTALL_PREFIX)/usr/include/linux/
++ depmod
++
++.PHONY: install all clean
++
++clean:
++ rm -rf drivers/isdn/hardware/mISDN/*.o
++ rm -rf drivers/isdn/hardware/mISDN/*.ko
++ rm -rf *~
++ find . -iname ".*.cmd" -exec rm -rf {} \;
++ find . -iname ".*.d" -exec rm -rf {} \;
++ find . -iname "*.mod.c" -exec rm -rf {} \;
++ find . -iname "*.mod" -exec rm -rf {} \;
++
++
diff --git a/channels/misdn/mISDNuser.patch b/channels/misdn/mISDNuser.patch
new file mode 100644
index 000000000..a5a70acc8
--- /dev/null
+++ b/channels/misdn/mISDNuser.patch
@@ -0,0 +1,271 @@
+diff -u -r -P /tmp/mISDNuser/example/Makefile mISDNuser/example/Makefile
+--- /tmp/mISDNuser/example/Makefile 2004-08-28 14:31:02.000000000 +0200
++++ mISDNuser/example/Makefile 2005-12-05 18:57:10.000000000 +0100
+@@ -3,6 +3,11 @@
+
+ all: $(PROGS)
+
++install:
++ for i in $(PROGS) ; do \
++ install -m 755 $$i $(INSTALL_PREFIX)/usr/bin ;\
++ done
++
+ testcon: testcon.o $(mISDNLIB)
+
+ testnet: testnet.o $(mISDNLIB)
+@@ -26,7 +31,7 @@
+
+
+ clean:
+- rm -f *.o *~ DEADJOE
++ rm -f *.o *.so *~ DEADJOE
+ rm -f loadfirm logger testcon testcon_l2 testnet
+
+ distclean: clean
+diff -u -r -P /tmp/mISDNuser/i4lnet/Makefile mISDNuser/i4lnet/Makefile
+--- /tmp/mISDNuser/i4lnet/Makefile 2004-08-28 14:27:53.000000000 +0200
++++ mISDNuser/i4lnet/Makefile 2005-12-05 18:57:40.000000000 +0100
+@@ -1,9 +1,18 @@
+
+-all: libisdnnet.a
++all: libisdnnet.a libisdnnet.so
++
++install:
++ install -m 644 libisdnnet.so $(INSTALL_PREFIX)/usr/lib/
++ cp *.h $(INSTALL_PREFIX)/usr/include/mISDNuser/
++
+
+ ISDNNETOBJ = net_if.o isdn_debug.o isdn_msg.o fsm.o net_l2.o tei.o net_l3.o \
+ manager.o tone.o bchannel.o g711.o
+
++libisdnnet.so: $(ISDNNETOBJ)
++ rm -f $@
++ $(CC) -shared -Xlinker -x -o $@ $(ISDNNETOBJ)
++
+ libisdnnet.a: $(ISDNNETOBJ)
+ rm -f $@
+ ar cr $@ $(ISDNNETOBJ)
+@@ -33,7 +42,7 @@
+ g711.o: g711.c $(INCLUDEDIR)/g711.h
+
+ clean:
+- rm -f *.o *~ DEADJOE
++ rm -f *.o *.so *~ DEADJOE
+ rm -f libisdnnet.a
+
+ distclean: clean
+diff -u -r -P /tmp/mISDNuser/i4lnet/net_if.c mISDNuser/i4lnet/net_if.c
+--- /tmp/mISDNuser/i4lnet/net_if.c 2004-12-05 18:23:40.000000000 +0100
++++ mISDNuser/i4lnet/net_if.c 2005-11-14 09:27:58.000000000 +0100
+@@ -1,7 +1,7 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <string.h>
+-#include <asm/bitops.h>
++#include "net_l2.h"
+ #include "isdn_net.h"
+ #include "bchannel.h"
+ #include "helper.h"
+diff -u -r -P /tmp/mISDNuser/i4lnet/net_l2.c mISDNuser/i4lnet/net_l2.c
+--- /tmp/mISDNuser/i4lnet/net_l2.c 2004-12-05 23:22:15.000000000 +0100
++++ mISDNuser/i4lnet/net_l2.c 2005-11-14 09:27:58.000000000 +0100
+@@ -32,18 +32,6 @@
+
+ #define L2_STATE_COUNT (ST_L2_8+1)
+
+-static char *strL2State[] =
+-{
+- "ST_L2_1",
+- "ST_L2_2",
+- "ST_L2_3",
+- "ST_L2_4",
+- "ST_L2_5",
+- "ST_L2_6",
+- "ST_L2_7",
+- "ST_L2_8",
+-};
+-
+ enum {
+ EV_L2_UI,
+ EV_L2_SABME,
+diff -u -r -P /tmp/mISDNuser/i4lnet/net_l2.h mISDNuser/i4lnet/net_l2.h
+--- /tmp/mISDNuser/i4lnet/net_l2.h 2004-12-05 00:47:10.000000000 +0100
++++ mISDNuser/i4lnet/net_l2.h 2005-11-14 09:27:58.000000000 +0100
+@@ -9,7 +9,6 @@
+ #ifndef NET_L2_H
+ #define NET_L2_H
+
+-#include <asm/bitops.h>
+ #include "mISDNlib.h"
+ #include "isdn_net.h"
+ #include "fsm.h"
+@@ -118,4 +117,31 @@
+ #define FLG_LAPD_NET 18
+ #define FLG_TEI_T201_1 19
+
++
++/* Simple replacement for the NON-ATOMIC routines which asm/bitops.h
++ was providing. */
++static inline int test_bit(int bit, unsigned long *word)
++{
++ return !!((*word) & (1<<bit));
++}
++static inline int test_and_clear_bit(int bit, unsigned long *word)
++{
++ int ret = !!((*word) & (1<<bit));
++ *word &= ~(1<<bit);
++ return ret;
++}
++static inline int test_and_set_bit(int bit, unsigned long *word)
++{
++ int ret = !!((*word) & (1<<bit));
++ *word |= 1<<bit;
++ return ret;
++}
++static inline void clear_bit(int bit, unsigned long *word)
++{
++ *word &= ~(1<<bit);
++}
++static inline void set_bit(int bit, unsigned long *word)
++{
++ *word |= 1<<bit;
++}
+ #endif
+diff -u -r -P /tmp/mISDNuser/i4lnet/net_l3.c mISDNuser/i4lnet/net_l3.c
+--- /tmp/mISDNuser/i4lnet/net_l3.c 2005-04-30 17:32:06.000000000 +0200
++++ mISDNuser/i4lnet/net_l3.c 2005-11-14 09:27:58.000000000 +0100
+@@ -9,7 +9,6 @@
+ */
+
+ #include <stdlib.h>
+-#include <asm/bitops.h>
+ #include "mISDNlib.h"
+ #include "net_l2.h"
+ #include "net_l3.h"
+diff -u -r -P /tmp/mISDNuser/lib/Makefile mISDNuser/lib/Makefile
+--- /tmp/mISDNuser/lib/Makefile 2004-08-28 14:28:38.000000000 +0200
++++ mISDNuser/lib/Makefile 2005-12-05 18:57:27.000000000 +0100
+@@ -1,7 +1,18 @@
+
+-all: libmISDN.a
++all: libmISDN.a libmISDN.so
+
+-libmISDN.a: device.o layer.o stack.o status.o
++install:
++ install -m 644 libmISDN.so $(INSTALL_PREFIX)/usr/lib/
++
++LIBMISDN_OBJS=device.o layer.o stack.o status.o
++
++libmISDN.so: $(LIBMISDN_OBJS)
++ rm -f $@
++ $(CC) -shared -Xlinker -x -o $@ $(LIBMISDN_OBJS)
++
++
++
++libmISDN.a: $(LIBMISDN_OBJS)
+ rm -f $@
+ ar -r $@ $^
+ ar -s $@
+@@ -12,9 +23,8 @@
+ status.o : status.c ../include/mISDNlib.h
+
+ clean:
+- rm -f *.o *~ DEADJOE
++ rm -f *.o *.so *~ DEADJOE
+ rm -f libmISDN.a
+
+ distclean: clean
+ rm -f *.a
+-
+diff -u -r -P /tmp/mISDNuser/Makefile mISDNuser/Makefile
+--- /tmp/mISDNuser/Makefile 2004-08-28 14:30:55.000000000 +0200
++++ mISDNuser/Makefile 2005-12-05 19:16:52.000000000 +0100
+@@ -1,10 +1,26 @@
++#
++# Set this to your local copy of mISDN
++#
++MISDNDIR := /usr/src/mISDN
++
++#
++# Change this to create an install prefix for the shared libs, programms and
++# includes
++#
++INSTALL_PREFIX := /
++export INSTALL_PREFIX
++
++MISDNINCLUDEDIR := $(MISDNDIR)/include
++export MISDNINCLUDEDIR
++
+ mISDN_DIR := $(PWD)
+ export mISDN_DIR
+
+ INCLUDEDIR := $(mISDN_DIR)/include
+ export INCLUDEDIR
+
+-CFLAGS:= -g -Wall -O2 -I $(INCLUDEDIR)
++CFLAGS:= -g -Wall -O2 -I $(INCLUDEDIR) -I $(MISDNINCLUDEDIR)
++CFLAGS+= -D CLOSE_REPORT=1
+ export CFLAGS
+
+ mISDNLIB := $(PWD)/lib/libmISDN.a
+@@ -20,9 +36,20 @@
+
+ LIBS := lib/libmISDN.a
+
+-all:
++all: test_misdn_includes
+ make TARGET=$@ subdirs
+
++
++install_path:
++ mkdir -p $(INSTALL_PREFIX)/usr/bin/
++ mkdir -p $(INSTALL_PREFIX)/usr/lib/mISDNuser/
++ mkdir -p $(INSTALL_PREFIX)/usr/include/mISDNuser/
++
++install: install_path all
++ make TARGET=install subdirs
++ cp include/*.h $(INSTALL_PREFIX)/usr/include/mISDNuser/
++
++
+ subdirs:
+ set -e; for i in $(SUBDIRS) ; do $(MAKE) -C $$i $(TARGET); done
+
+@@ -61,3 +88,8 @@
+ voiparchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_voip-$(VERSION).tar.bz2
+ voiparchiv: archiv
+
++
++test_misdn_includes:
++ @if ! echo "#include <linux/mISDNif.h>" | gcc -I$(MISDNINCLUDEDIR) -C -E - >/tmp/muh ; then echo -e "\n\nYou either don't seem to have installed mISDN properly\nor you haven't set the MISDNDIR variable in this very Makefile.\n\nPlease either install mISDN or set the MISDNDIR properly\n"; exit 1; fi
++
++
+diff -u -r -P /tmp/mISDNuser/tenovis/Makefile mISDNuser/tenovis/Makefile
+--- /tmp/mISDNuser/tenovis/Makefile 2004-08-28 14:29:27.000000000 +0200
++++ mISDNuser/tenovis/Makefile 2005-12-05 18:51:05.000000000 +0100
+@@ -10,6 +10,11 @@
+
+ all: sublib $(PROGS)
+
++install:
++ for i in $(PROGS) ; do \
++ install -m 755 $$i $(INSTALL_PREFIX)/usr/bin ;\
++ done
++
+ testlib: testlib.o $(TENOVISLIB) $(mISDNLIB)
+
+ tstlib: tstlib.o $(TENOVISLIB) $(mISDNLIB)
+diff -u -r -P /tmp/mISDNuser/voip/Makefile mISDNuser/voip/Makefile
+--- /tmp/mISDNuser/voip/Makefile 2004-08-28 14:29:53.000000000 +0200
++++ mISDNuser/voip/Makefile 2005-12-05 18:50:39.000000000 +0100
+@@ -24,6 +24,11 @@
+
+ all: $(PROGRAMMS)
+
++install:
++ for i in $(PROGRAMMS) ; do \
++ install -m 755 $$i $(INSTALL_PREFIX)/usr/bin ;\
++ done
++
+ INTERNET_PORT = 2074
+
+ CARGS = -DInternet_Port=$(INTERNET_PORT)
diff --git a/doc/README.misdn b/doc/README.misdn
index 2ff0b9bfe..652ba70cd 100644
--- a/doc/README.misdn
+++ b/doc/README.misdn
@@ -26,8 +26,7 @@ Features:
Supported Hardware:
-------------------
-chan_misdn supports any mISDN compatible Hardware. Especially the 1-8 Port
-BRI Cards available from http://shop.beronet.com
+chan_misdn supports any mISDN compatible Hardware.
Overview
--------
@@ -49,48 +48,29 @@ Overview
Fast Installation Guide
-----------------------
-You have two options on how to install chan_misdn.
-
-(1) Requirements:
- - mISDN and mISDNuser from jolly (see Pre-Requisites below)
- Installation:
- - cd <asterisk-src-dir>/channels/misdn
- - edit Makefile so that MISDNUSER points to your mISDNuser directory
- - run 'make'
- - cd <asterisk-src-dir>
- - compile and install asterisk via 'make install'
-
-(2) Requirements:
- - Asterisk headers and Kernel headers
- Description:
- The Makefile gets the newest mISDN and mISDNuser Sources from
- jollys webpage and the newest release of chan_misdn from beronets
- Servers. After that it compiles and installs everything (hopefully).
- Installation:
- - cd /usr/src
- - wget http://www.beronet.com/downloads/install-misdn.tar.gz
- - tar zxf install-misdn.tar.gz
- - cd install-misdn
- - make install
+It is easy to install mISDN and mISDNuser. Using the Makefile from
+channels/misdn. You just need to type:
+
+cd channels/misdn
+make misdn
+
+Then all the necessary files are fetched from jollys homepage and are patched
+with the Echocanellor.
Pre-Requisites
--------------
-To compile and install this driver, you'll need at least one mISDN Driver, the
-mISDNuser package and the Asterisk includes (which will be inside of the
-sources). Chan_misdn works with both, the current release version and the
-development (svn trunk) version of Asterisk.
+To compile and install this driver, you'll need at least one mISDN Driver and
+the mISDNuser package. Chan_misdn works with both, the current release version
+and the development (svn trunk) version of Asterisk. mISDNuser and mISDN must
+be fetched from jollys homepage and must be patched with the Echocancellor.
-To get the mISDN stuff please follow the instructions at
-http://www.isdn4linux.de. Please Note that mISDN works good for the
-linux-2.6.x kernels. Some of the mISDN drivers do not compile against the
-2.4.x or older kernels, you can patch them, but than you'll get mysterious
-errors.
+Please Note that mISDN works good for the linux-2.6.x kernels. Some of the
+mISDN drivers do not compile against the 2.4.x or older kernels, you can patch
+them, but than you'll get mysterious errors.
-I use Kernels > 2.6.9 and it works perfect. with kernels >= 2.6.10 there is a
-very litle bug in hfc_multi.c which causes the module not to compile, it can
-be easily fixed by changing pci_findsubsys to pci_getsubsys in code.
+Using Kernels > 2.6.9 works perfect.
Ok so far so good, now follow the compilation instructions.
@@ -99,46 +79,26 @@ Ok so far so good, now follow the compilation instructions.
Compilation
-----------
-!! Be aware, in the actual mISDNuser package theres a bug in the Makefile
-!! the compilation stops near iapplication.h, this isn't very important
-!! at this step you are ready.
-
-After you've successfully installed mISDN, mISDNuser and Asterisk, you should
-modify the Makefile in the chan_misdn source path. There you can tell the
-Makefile where to install the driver, sample-conf, and most important where it
-can find the linux kernel includes, the mISDNuser package and the Asterisk
-includes. If you use the development version of Asterisk (or at least a newer
-version than release) uncomment the CCFLAGS+=-DASTERISK_STABLE, the release
-version of Asterisk is at the moment v1-2 as subversion branch.
+The compilation of chan_misdn requires a library which will be generated under
+channels/misdn/.
-Now you can type in:
+To compile this library you just need to go into this directory and type
+make. Now you can go back to the asterisk source root and type make install
+again, which now should compile and install chan_misdn.
-make
-
-This should compile chan_misdn.so, if there's an error check the paths in the
-Makefile again.
Installation
------------
-After successful compilation of chan_misdn, you should simply type in:
-
-make install
-
-as privileged user to put chan_misdn.so in the Asterisk modules
-directory.
+Chan_misdn is automatically installed by the asterisk installation process.
-You should see a message like: "Successfully installed chan_misdn".
-Congratulations.
-
-Theres a sample init.d script for loading the mISDN modules (mISDN.sample),
-simply copy it to /etc/init.d/ and modify it, there you can enter your cards.
+There is a sample init.d script for loading the mISDN modules (mISDN.sample),
+5Asimply copy it to /etc/init.d/ and modify it, there you can enter your cards.
!! Forget to use capi together with chan_misdn.
-
Configuration
-------------
@@ -162,6 +122,11 @@ configuration file, bigger numbers will lead to more debug output. There's also
tracefile option, which takes a path+filename where debug output is written
to.
+- misdn.conf: [default] section
+The default section is another special section which can contain all the
+options available int the usr/port sections. the user/port section inherit
+their parameters from the default section.
+
- misdn.conf: user/port sections
The user sections have names which are unequal to "general". Those sections
contain the ports variable which mean the mISDN Ports. Here you can add
@@ -205,8 +170,8 @@ The available Optchars are:
vt - txgain control
-chan_misdn registers a new dial plan application "misdn_set_opt" when loaded. This
-application takes the Optionsstring as argument. The Syntax is:
+chan_misdn registers a new dial plan application "misdn_set_opt" when
+loaded. This application takes the Optionsstring as argument. The Syntax is:
misdn_set_opt(<OPTIONSSTRING>)
@@ -343,6 +308,11 @@ it, you can just change pci_find_subsys to pci_get_subsys, this works.
* asterisk >= v1-0.2 , also CVS Head
* mISDN/mISDNuser (3.0-beta) from isdn.jolly.de
+- chan_misdn-0.2.1
+ * linux-kernel >= 2.6.8 (but at least 2.6)
+ * asterisk >= v1.2 , also CVS Head
+ * mISDN/mISDNuser (3.0) from isdn.jolly.de
+
Known Problems
--------------