diff options
-rw-r--r-- | channels/Makefile | 8 | ||||
-rw-r--r-- | channels/chan_misdn.c | 168 | ||||
-rw-r--r-- | channels/chan_misdn_config.c | 12 | ||||
-rw-r--r-- | channels/misdn/Makefile | 69 | ||||
-rw-r--r-- | channels/misdn/chan_misdn_config.h | 1 | ||||
-rw-r--r-- | channels/misdn/ie.c | 8 | ||||
-rw-r--r-- | channels/misdn/isdn_lib.c | 20 | ||||
-rw-r--r-- | channels/misdn/isdn_lib.h | 1 | ||||
-rw-r--r-- | channels/misdn/isdn_lib_intern.h | 8 | ||||
-rw-r--r-- | channels/misdn/isdn_msg_parser.c | 27 | ||||
-rw-r--r-- | channels/misdn/mISDN.patch | 2500 | ||||
-rw-r--r-- | channels/misdn/mISDNuser.patch | 271 | ||||
-rw-r--r-- | doc/README.misdn | 104 |
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 -------------- |