Update of HFC multiport driver and dsp module. Ported to current api names.

Many fixes, hardware support for dtmf, conferences, crossconnects.
Blowfish crypt support for audio data (dsp).
Changes to Kconfig, Makefile and Rules.mISDN. Minor changes to mISDNif.h.

Modified Files:
	mISDN/drivers/isdn/hardware/mISDN/Kconfig.v2.6
	mISDN/drivers/isdn/hardware/mISDN/Makefile
	mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.4
	mISDN/drivers/isdn/hardware/mISDN/Makefile.v2.6
	mISDN/drivers/isdn/hardware/mISDN/Rules.mISDN.v2.4
	mISDN/drivers/isdn/hardware/mISDN/dsp.h
	mISDN/drivers/isdn/hardware/mISDN/dsp_audio.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_dtmf.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_tones.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.h
	mISDN/include/linux/mISDNif.h
This commit is contained in:
Andreas Eversberg 2004-02-14 17:43:15 +00:00
parent c86cad1c3c
commit e8fae00343
14 changed files with 1759 additions and 1164 deletions

View File

@ -39,7 +39,7 @@ config MISDN_HFCMULTI
bool "Support for HFC multiport cards (HFC-4S/8S/E1)"
depends on PCI
help
Enable support for card with Cologne Chips Design HFC multiport
Enable support for card with Cologne Chip AG's HFC multiport
chip. There are three types of chips that are quite similar,
but the interface is different:
* HFC-4S (4 S/T interfaces on one chip)
@ -63,12 +63,27 @@ config MISDN_DSP
help
Enable support for digital audio processing capability.
This module may be used for special applications that require
cross connecting of bchannels, conferencing, dtmf decoding and
tone generation. It may use hardware features if available.
cross connecting of bchannels, conferencing, dtmf decoding
tone generation, and Blowfish encryption and decryption.
It may use hardware features if available.
E.g. it is required for PBX4Linux. Go to http://isdn.jolly.de
and get more informations about this module and it's usage.
If unsure, say 'N'.
if MISDN_DSP!=n
config MISDN_DSP_HARDWARETEST
bool "Hardware test for one HFC-4S/8S only"
depends on PCI
help
This is a test option if ONLY ONE HFC-4S/8S card is installed
and NO OTHER CARD is used by mISDN. In this case the DSP module
uses the hardware crossconnect/dtmf/conference/tone features.
Later this flag will be removed when mISDN supports stack
feature lists.
endif
endif
endmenu

View File

@ -65,7 +65,7 @@ mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.
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
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o

View File

@ -67,7 +67,7 @@ mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.
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
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o

View File

@ -66,6 +66,6 @@ mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.
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
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o
mISDN_x25dte-objs := x25_dte.o x25_l3.o
I4LmISDN-objs := i4l_mISDN.o

View File

@ -39,6 +39,10 @@ hfcpci.o: $(hfcpci-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
hfcmulti.o: $(hfcmulti-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)
mISDN_l1.o: $(mISDN_l1-objs)
$(RM) $@
$(LD) -r -o $@ $(filter-out $(MODVERFILE) dummy ,$^)

View File

@ -9,8 +9,7 @@
*
*/
/* compile using hardware features (if supported by hardware) */
//#define WITH_HARDWARE
//#define AUTOJITTER
#define DEBUG_DSP_MGR 0x0001
#define DEBUG_DSP_CORE 0x0002
@ -18,40 +17,46 @@
#define DEBUG_DSP_DTMFCOEFF 0x0008
#define DEBUG_DSP_CMX 0x0010
#define DEBUG_DSP_TONE 0x0020
#define DEBUG_DSP_BLOWFISH 0x0040
#define DEBUG_DSP_DELAY 0x0080
/* options may be:
*
* bit 0 = use ulaw instead of alaw
* bit 1 = disable hfc hardware accelleration
* bit 1 = enable hfc hardware accelleration for all channels
*
*/
#define DSP_OPT_ULAW (1<<0)
#define DSP_OPT_NOHARDWARE (1<<1)
//#define DSP_OPT_NOFLIP (1<<2)
#ifdef HAS_WORKQUEUE
#include <linux/workqueue.h>
#else
#include <linux/tqueue.h>
#endif
#include <linux/timer.h>
extern int options;
extern int dsp_options;
extern int dsp_debug;
/***************
* audio stuff *
***************/
extern signed long dsp_audio_alaw_to_s32[256];
extern signed long dsp_audio_ulaw_to_s32[256];
extern signed long *dsp_audio_law_to_s32;
extern unsigned char dsp_audio_s16_to_law[65536];
extern unsigned char dsp_audio_alaw_to_ulaw[256];
extern unsigned char dsp_audio_mix_law[65536];
extern s32 dsp_audio_alaw_to_s32[256];
extern s32 dsp_audio_ulaw_to_s32[256];
extern s32 *dsp_audio_law_to_s32;
extern u8 dsp_audio_s16_to_law[65536];
extern u8 dsp_audio_alaw_to_ulaw[256];
extern u8 dsp_audio_mix_law[65536];
extern u8 dsp_audio_seven2law[128];
extern u8 dsp_audio_law2seven[256];
extern void dsp_audio_generate_s2law_table(void);
extern void dsp_audio_generate_seven(void);
extern void dsp_audio_generate_mix_table(void);
extern void dsp_audio_generate_ulaw_samples(void);
extern void dsp_audio_generate_volume_changes(void);
extern unsigned char silence;
extern u8 silence;
/*************
@ -62,10 +67,6 @@ extern unsigned char silence;
#define CMX_BUFF_HALF 0x2000 /* CMX_BUFF_SIZE / 2 */
#define CMX_BUFF_MASK 0x3fff /* CMX_BUFF_SIZE - 1 */
// jolly patch start
#define SEND_LEN 64 /* initial chunk length for mixed data to card */
// jolly patch stop
/* the structure of conferences:
*
* each conference has a unique number, given by user space.
@ -86,13 +87,15 @@ typedef struct _conf_member {
typedef struct _conference {
struct _conference *prev;
struct _conference *next;
u_int id; /* all cmx stacks with the same ID are connected */
u32 id; /* all cmx stacks with the same ID are connected */
conf_member_t *mlist;
int solution; /* currently connected via -1=software 0=hardware 1-8=conference unit (hardware is only possible on the same chip) */
u_int hfc_id; /* unique id to identify the chip */
int software; /* conf is processed by software */
int hardware; /* conf is processed by hardware */
//#ifndef AUTOJITTER
int largest; /* largest frame received in conf's life. */
//#endif
int W_min, W_max; /* min/maximum rx-write pointer of members */
signed long conf_buff[CMX_BUFF_SIZE];
s32 conf_buff[CMX_BUFF_SIZE];
} conference_t;
extern mISDNobject_t dsp_obj;
@ -104,14 +107,14 @@ extern mISDNobject_t dsp_obj;
#define DSP_DTMF_NPOINTS 102
typedef struct _dmtf_t {
typedef struct _dtmf_t {
int software; /* dtmf uses software decoding */
int hardware; /* dtmf uses hardware decoding */
int size; /* number of bytes in buffer */
signed short buffer[DSP_DTMF_NPOINTS]; /* buffers one full dtmf frame */
unsigned char lastwhat, lastdigit;
u8 lastwhat, lastdigit;
int count;
unsigned char digits[16]; /* just the dtmf result */
u8 digits[16]; /* just the dtmf result */
} dtmf_t;
@ -120,49 +123,89 @@ typedef struct _dmtf_t {
***************/
typedef struct _tone_t {
int tone;
void *pattern;
int count;
int index;
int software; /* tones are generated by software */
int hardware; /* tones are generated by hardware */
int tone;
void *pattern;
int count;
int index;
struct timer_list tl;
} tone_t;
/*****************
* general stuff *
*****************/
#define DELAY_CHECK 8000
typedef struct _dsp {
struct _dsp *prev;
struct _dsp *next;
int debug;
u_int hfc_id; /* unique id to identify the chip (or 0) */
mISDNinstance_t inst;
int largest; /* largest frame received in dsp's life. */
int b_active;
int tx_pending;
int conf_id;
int echo;
int echo; /* echo is done by software */
int rx_disabled;
int tx_mix;
conference_t *conf;
conf_member_t *member;
tone_t tone;
dtmf_t dtmf;
int tx_volume, rx_volume;
struct work_struct sendwork; /* event for sending data */
int tx_pending;
/* conference stuff */
u32 conf_id;
conference_t *conf;
conf_member_t *member;
/* buffer stuff */
int largest; /* largest frame received in dsp's life. */
int R_tx, W_tx; /* pointers of transmit buffer */
int R_rx, W_rx; /* pointers of receive buffer and conference buffer */
unsigned char tx_buff[CMX_BUFF_SIZE];
unsigned char rx_buff[CMX_BUFF_SIZE];
u8 tx_buff[CMX_BUFF_SIZE];
u8 rx_buff[CMX_BUFF_SIZE];
#ifdef AUTOJITTER
int tx_delay; /* used to find the delay of tx buffer */
int tx_delay_count;
int rx_delay; /* used to find the delay of rx buffer */
int rx_delay_count;
#endif
/* hardware stuff */
int hfc_id; /* unique id to identify the chip (or -1) */
int hfc_dtmf; /* set if HFCmulti card supports dtmf */
int hfc_loops; /* set if card supports tone loops */
int pcm_id; /* unique id to identify the pcm bus (or -1) */
int pcm_slots; /* number of slots on the pcm bus */
int pcm_banks; /* number of IO banks of pcm bus */
int pcm_slot_rx; /* current PCM slot (or -1) */
int pcm_bank_rx;
int pcm_slot_tx;
int pcm_bank_tx;
int hfc_conf; /* unique id of current conference (or -1) */
/* encryption stuff */
int bf_enable;
u32 bf_p[18];
u32 bf_s[1024];
int bf_crypt_pos;
u8 bf_data_in[9];
u8 bf_crypt_out[9];
int bf_decrypt_in_pos;
int bf_decrypt_out_pos;
u8 bf_crypt_inring[16];
u8 bf_data_out[9];
int bf_sync;
} dsp_t;
/* functions */
extern void dsp_change_volume(struct sk_buff *skb, int volume);
extern conference_t *Conf_list;
extern void dsp_cmx_debug(dsp_t *dsp);
extern int dsp_cmx(dsp_t *dsp);
extern void dsp_cmx_hardware(conference_t *conf, dsp_t *dsp);
extern int dsp_cmx_conf(dsp_t *dsp, u32 conf_id);
extern void dsp_cmx_receive(dsp_t *dsp, struct sk_buff *skb);
extern struct sk_buff *dsp_cmx_send(dsp_t *dsp, int len, int dinfo);
extern void dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb);
@ -170,8 +213,15 @@ extern int dsp_cmx_del_conf_member(dsp_t *dsp);
extern int dsp_cmx_del_conf(conference_t *conf);
extern void dsp_dtmf_goertzel_init(dsp_t *dsp);
extern unsigned char *dsp_dtmf_goertzel_decode(dsp_t *dsp, unsigned char *data, int len, int fmt);
extern u8 *dsp_dtmf_goertzel_decode(dsp_t *dsp, u8 *data, int len, int fmt);
extern int dsp_tone(dsp_t *dsp, int tone);
extern void dsp_tone_copy(dsp_t *dsp, unsigned char *data, int len);
extern void dsp_tone_copy(dsp_t *dsp, u8 *data, int len);
extern void dsp_tone_timeout(void *arg);
extern void dsp_bf_encrypt(dsp_t *dsp, u8 *data, int len);
extern void dsp_bf_decrypt(dsp_t *dsp, u8 *data, int len);
extern int dsp_bf_init(dsp_t *dsp, const u8 *key, unsigned int keylen);
extern void dsp_bf_cleanup(dsp_t *dsp);

View File

@ -1,6 +1,6 @@
/* $Id$
*
* Audio support data for ISDN4Linux.
* Audio support data for mISDN_dsp.
*
* Copyright 2002/2003 by Andreas Eversberg (jolly@jolly.de)
*
@ -15,7 +15,7 @@
#include "dsp.h"
/* ulaw[unsigned char] -> signed 16-bit */
signed long dsp_audio_ulaw_to_s32[256] =
s32 dsp_audio_ulaw_to_s32[256] =
{
0xffff8284, 0xffff8684, 0xffff8a84, 0xffff8e84,
0xffff9284, 0xffff9684, 0xffff9a84, 0xffff9e84,
@ -84,7 +84,7 @@ signed long dsp_audio_ulaw_to_s32[256] =
};
/* alaw[unsigned char] -> signed 16-bit */
signed long dsp_audio_alaw_to_s32[256] =
s32 dsp_audio_alaw_to_s32[256] =
{
0x000013fc, 0xffffec04, 0x00000144, 0xfffffebc,
0x0000517c, 0xffffae84, 0x0000051c, 0xfffffae4,
@ -152,10 +152,10 @@ signed long dsp_audio_alaw_to_s32[256] =
0x0000327c, 0xffffcd84, 0x0000032c, 0xfffffcd4
};
signed long *dsp_audio_law_to_s32;
s32 *dsp_audio_law_to_s32;
/* signed 16-bit -> law */
unsigned char dsp_audio_s16_to_law[65536];
u8 dsp_audio_s16_to_law[65536];
/* table is used to generate s16_to_alaw */
static short dsp_audio_alaw_relations[512] =
@ -228,7 +228,7 @@ static short dsp_audio_alaw_relations[512] =
/* alaw -> ulaw */
unsigned char dsp_audio_alaw_to_ulaw[256] =
u8 dsp_audio_alaw_to_ulaw[256] =
{
0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
@ -264,7 +264,44 @@ unsigned char dsp_audio_alaw_to_ulaw[256] =
0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
};
unsigned char silence;
/* ulaw -> alaw */
u8 dsp_audio_ulaw_to_alaw[256] =
{
0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
};
u8 silence;
/*****************************************************
@ -276,7 +313,7 @@ dsp_audio_generate_s2law_table(void)
{
int i, j;
if (options & DSP_OPT_ULAW) {
if (dsp_options & DSP_OPT_ULAW) {
/* generating ulaw-table */
i = j = 0;
while(i < 32768) {
@ -308,8 +345,62 @@ dsp_audio_generate_s2law_table(void)
}
/*
* the seven bit sample is the number of every second alaw-sample ordered by
* aplitude. 0x00 is negative, 0x7f is positive amplitude.
*/
u8 dsp_audio_seven2law[128];
u8 dsp_audio_law2seven[256];
/********************************************************************
* generate table for conversion law from/to 7-bit alaw-like sample *
********************************************************************/
void
dsp_audio_generate_seven(void)
{
int i, j;
u8 spl;
/* conversion from law to seven bit audio */
i = 0;
while(i < 256) {
/* spl is the source: the law-sample (converted to alaw) */
spl = i;
if (dsp_options & DSP_OPT_ULAW)
spl = dsp_audio_ulaw_to_alaw[i];
/* find the 7-bit-sample */
j = 0;
while(j < 256) {
if (dsp_audio_alaw_relations[(j<<1)|1] == spl)
break;
j++;
}
if (j == 256) {
printk(KERN_WARNING "fatal error in %s: alaw-sample '0x%2x' not found in relations-table.\n", __FUNCTION__, spl);
}
/* write 7-bit audio value */
dsp_audio_law2seven[i] = j >> 1;
i++;
}
/* conversion from seven bit audio to law */
i = 0;
while(i < 128) {
/* find alaw-spl */
spl = dsp_audio_alaw_relations[(i<<2)|1];
/* convert to ulaw, if required */
if (dsp_options & DSP_OPT_ULAW)
spl = dsp_audio_alaw_to_ulaw[spl];
/* write 8-bit law sample */
dsp_audio_seven2law[i] = spl;
i++;
}
}
/* mix 2*law -> law */
unsigned char dsp_audio_mix_law[65536];
u8 dsp_audio_mix_law[65536];
/******************************************************
* generate mix table to mix two law samples into one *
@ -319,7 +410,7 @@ void
dsp_audio_generate_mix_table(void)
{
int i, j;
signed long sample;
s32 sample;
i = 0;
while(i < 256) {
@ -343,24 +434,24 @@ dsp_audio_generate_mix_table(void)
* generate different volume changes *
*************************************/
static unsigned char dsp_audio_reduce8[256];
static unsigned char dsp_audio_reduce7[256];
static unsigned char dsp_audio_reduce6[256];
static unsigned char dsp_audio_reduce5[256];
static unsigned char dsp_audio_reduce4[256];
static unsigned char dsp_audio_reduce3[256];
static unsigned char dsp_audio_reduce2[256];
static unsigned char dsp_audio_reduce1[256];
static unsigned char dsp_audio_increase1[256];
static unsigned char dsp_audio_increase2[256];
static unsigned char dsp_audio_increase3[256];
static unsigned char dsp_audio_increase4[256];
static unsigned char dsp_audio_increase5[256];
static unsigned char dsp_audio_increase6[256];
static unsigned char dsp_audio_increase7[256];
static unsigned char dsp_audio_increase8[256];
static u8 dsp_audio_reduce8[256];
static u8 dsp_audio_reduce7[256];
static u8 dsp_audio_reduce6[256];
static u8 dsp_audio_reduce5[256];
static u8 dsp_audio_reduce4[256];
static u8 dsp_audio_reduce3[256];
static u8 dsp_audio_reduce2[256];
static u8 dsp_audio_reduce1[256];
static u8 dsp_audio_increase1[256];
static u8 dsp_audio_increase2[256];
static u8 dsp_audio_increase3[256];
static u8 dsp_audio_increase4[256];
static u8 dsp_audio_increase5[256];
static u8 dsp_audio_increase6[256];
static u8 dsp_audio_increase7[256];
static u8 dsp_audio_increase8[256];
static unsigned char *dsp_audio_volume_change[16] = {
static u8 *dsp_audio_volume_change[16] = {
dsp_audio_reduce8,
dsp_audio_reduce7,
dsp_audio_reduce6,
@ -382,7 +473,7 @@ static unsigned char *dsp_audio_volume_change[16] = {
void
dsp_audio_generate_volume_changes(void)
{
register signed long sample;
register s32 sample;
int i;
i = 0;
@ -459,9 +550,9 @@ dsp_audio_generate_volume_changes(void)
void
dsp_change_volume(struct sk_buff *skb, int volume)
{
unsigned char *volume_change;
u8 *volume_change;
int i, ii;
unsigned char *p;
u8 *p;
int shift;
if (volume == 0)

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@
* Compensate jitter due to system load and hardware fault.
* All features are done in kernel space and will be realized
* using hardware, if available and supported by chip set.
* Blowfish encryption/decryption
*/
/* STRUCTURE:
@ -31,6 +32,7 @@
* - (4) echo generation for delay test
* - (5) volume control
* - (6) disable receive data
* - (7) encryption/decryption
*
* Look:
* TX RX
@ -72,6 +74,16 @@
* | ^
* | |
* v |
* +----+----+ +----+----+
* |(7) | |(7) |
* | | | |
* | Encrypt | | Decrypt |
* | | | |
* | | | |
* +----+----+ +----+----+
* | ^
* | |
* v |
* ------card layer------
* TX RX
*
@ -149,25 +161,6 @@ or if cmx is currently using software.
*/
#ifdef WITH_HARDWARE
alle einstellungen der hardware sollten in einer struktur hinterlegt werden.
sobald der channel aktiviert wird, wird diese struktur an den hfc-chip gesendet.
wenn sich die daten der hardware ändern, gibt es eben ein update der struktur,
die an den hfc-chip gesendet wird (wenn aktiv).
beim PH_DEACTIVATE sollten daten zur deaktivierung der hardware gesendet werden.
die daten der struktur
- conference number
- other crossconnect member
- loop
- rx_data
- dtmf
- law-codec
- tone-loop
- volume
- loop
#endif
const char *dsp_revision = "$Revision$";
#include <linux/delay.h>
@ -182,22 +175,30 @@ const char *dsp_revision = "$Revision$";
static char DSPName[] = "DSP";
mISDNobject_t dsp_obj;
static mISDN_HWlock_t dsp_lock;
mISDN_HWlock_t dsp_lock;
static int debug = 0;
int options = 0;
int dsp_debug;
static int options = 0;
int dsp_options;
#ifndef AUTOJITTER
int poll = 0;
#endif
#ifdef MODULE
MODULE_AUTHOR("Andreas Eversberg");
MODULE_PARM(debug, "1i");
MODULE_PARM(options, "1i");
#ifndef AUTOJITTER
MODULE_PARM(poll, "1i");
#endif
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif
#endif
/*
* sending next frame to card (triggered by PH_ACTIVAT and PH_DATA_CONF)
* sending next frame to card (triggered by PH_DATA_IND)
*/
static void
sendevent(dsp_t *dsp)
@ -205,26 +206,31 @@ sendevent(dsp_t *dsp)
struct sk_buff *nskb;
lock_HW(&dsp_lock, 0);
dsp->tx_pending = 0;
if (dsp->b_active) {
if (dsp->b_active && dsp->tx_pending) {
/* get data from cmx */
nskb = dsp_cmx_send(dsp, SEND_LEN, 0);
nskb = dsp_cmx_send(dsp, dsp->tx_pending, 0);
dsp->tx_pending = 0;
if (!nskb) {
printk(KERN_ERR "%s: failed to create subsequent packet\n", __FUNCTION__);
unlock_HW(&dsp_lock);
printk(KERN_ERR "%s: failed to create tx packet\n", __FUNCTION__);
return;
}
/* crypt if enabled */
if (dsp->bf_enable)
dsp_bf_encrypt(dsp, nskb->data, nskb->len);
/* change volume if requested */
if (dsp->tx_volume)
dsp_change_volume(nskb, dsp->tx_volume);
/* send subsequent requests to card */
unlock_HW(&dsp_lock);
if (dsp->inst.down.func(&dsp->inst.down, nskb)) {
printk(KERN_ERR "%s: failed to send subsequent packet\n", __FUNCTION__);
dev_kfree_skb(nskb);
printk(KERN_ERR "%s: failed to send tx packet\n", __FUNCTION__);
}
} else
} else {
dsp->tx_pending = 0;
unlock_HW(&dsp_lock);
}
}
@ -234,9 +240,10 @@ sendevent(dsp_t *dsp)
static int
dsp_control_req(dsp_t *dsp, mISDN_head_t *hh, struct sk_buff *skb)
{
struct sk_buff *nskb;
int ret = 0;
int cont;
unsigned char *data;
u8 *data;
int len;
if (skb->len < sizeof(int)) {
@ -248,27 +255,20 @@ dsp_control_req(dsp_t *dsp, mISDN_head_t *hh, struct sk_buff *skb)
switch (cont) {
case DTMF_TONE_START: /* turn on DTMF */
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: start dtmf\n", __FUNCTION__);
dsp_dtmf_goertzel_init(dsp);
/* checking for hardware capability */
#ifdef WITH_HARDWARE
if (...............) {
dsp->dtmf.hardware = 2;
if (dsp->hfc_dtmf) {
dsp->dtmf.hardware = 1;
dsp->dtmf.software = 0;
} else {
#endif
dsp->dtmf.hardware = 0;
dsp->dtmf.software = 1;
#ifdef WITH_HARDWARE
}
auch hier muss der chip davon erfahren
auch beim TONE_STOP muss der chip was erfahren.
bedenke activate un deactivate.
#endif
break;
case DTMF_TONE_STOP: /* turn off DTMF */
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: stop dtmf\n", __FUNCTION__);
dsp->dtmf.hardware = 0;
dsp->dtmf.software = 0;
@ -278,19 +278,20 @@ bedenke activate un deactivate.
ret = -EINVAL;
break;
}
dsp->conf_id = *((int *)data);
if (dsp->debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: join conference %d\n", __FUNCTION__, dsp->conf_id);
ret = dsp_cmx(dsp);
if (debug & DEBUG_DSP_CMX)
if (*((u32 *)data) == 0)
goto conf_split;
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: join conference %d\n", __FUNCTION__, *((u32 *)data));
ret = dsp_cmx_conf(dsp, *((u32 *)data));
if (dsp_debug & DEBUG_DSP_CMX)
dsp_cmx_debug(dsp);
break;
case CMX_CONF_SPLIT: /* remove from conference */
if (dsp->debug & DEBUG_DSP_CORE)
conf_split:
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: release conference\n", __FUNCTION__);
dsp->conf_id = 0;
ret = dsp_cmx(dsp);
if (debug & DEBUG_DSP_CMX)
ret = dsp_cmx_conf(dsp, 0);
if (dsp_debug & DEBUG_DSP_CMX)
dsp_cmx_debug(dsp);
break;
case TONE_PATT_ON: /* play tone */
@ -298,22 +299,19 @@ bedenke activate un deactivate.
ret = -EINVAL;
break;
}
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: turn tone 0x%x on\n", __FUNCTION__, *((int *)skb->data));
ret = dsp_tone(dsp, *((int *)data));
if (!ret && dsp->conf_id)
ret = dsp_cmx(dsp);
if (ret)
dsp_tone(dsp, 0);
if (!ret)
dsp_cmx_hardware(dsp->conf, dsp);
if (!dsp->tone.tone)
goto tone_off;
break;
case TONE_PATT_OFF: /* stop tone */
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: turn tone off\n", __FUNCTION__);
dsp_tone(dsp, 0);
if (dsp->conf_id)
ret = dsp_cmx(dsp);
dsp_cmx_hardware(dsp->conf, dsp);
/* reset tx buffers (user space data) */
tone_off:
dsp->R_tx = dsp->W_tx = 0;
@ -324,10 +322,9 @@ bedenke activate un deactivate.
break;
}
dsp->tx_volume = *((int *)data);
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: change tx volume to %d\n", __FUNCTION__, dsp->tx_volume);
if (dsp->conf_id)
ret = dsp_cmx(dsp);
dsp_cmx_hardware(dsp->conf, dsp);
break;
case VOL_CHANGE_RX: /* change volume */
if (len != sizeof(int)) {
@ -335,63 +332,87 @@ bedenke activate un deactivate.
break;
}
dsp->rx_volume = *((int *)data);
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: change rx volume to %d\n", __FUNCTION__, dsp->tx_volume);
if (dsp->conf_id)
ret = dsp_cmx(dsp);
dsp_cmx_hardware(dsp->conf, dsp);
break;
case CMX_ECHO_ON: /* enable echo */
dsp->echo = 1;
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: enable cmx-echo\n", __FUNCTION__);
if (dsp->conf_id)
ret = dsp_cmx(dsp);
if (debug & DEBUG_DSP_CMX)
dsp_cmx_hardware(dsp->conf, dsp);
if (dsp_debug & DEBUG_DSP_CMX)
dsp_cmx_debug(dsp);
break;
case CMX_ECHO_OFF: /* disable echo */
dsp->echo = 0;
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: disable cmx-echo\n", __FUNCTION__);
if (dsp->conf_id)
ret = dsp_cmx(dsp);
if (debug & DEBUG_DSP_CMX)
dsp_cmx_hardware(dsp->conf, dsp);
if (dsp_debug & DEBUG_DSP_CMX)
dsp_cmx_debug(dsp);
break;
case CMX_RECEIVE_ON: /* enable receive to user space */
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: enable receive to user space\n", __FUNCTION__);
dsp->rx_disabled = 0;
if (dsp->conf_id)
ret = dsp_cmx(dsp);
dsp_cmx_hardware(dsp->conf, dsp);
break;
case CMX_RECEIVE_OFF: /* disable receive to user space */
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: disable receive to user space\n", __FUNCTION__);
dsp->rx_disabled = 1;
if (dsp->conf_id)
ret = dsp_cmx(dsp);
dsp_cmx_hardware(dsp->conf, dsp);
break;
case CMX_MIX_ON: /* enable mixing of transmit data with conference members */
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: enable mixing of tx-data with conf mebers\n", __FUNCTION__);
dsp->tx_mix = 1;
if (dsp->conf_id)
ret = dsp_cmx(dsp);
if (debug & DEBUG_DSP_CMX)
dsp_cmx_hardware(dsp->conf, dsp);
if (dsp_debug & DEBUG_DSP_CMX)
dsp_cmx_debug(dsp);
break;
case CMX_MIX_OFF: /* disable mixing of transmit data with conference members */
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: disable mixing of tx-data with conf mebers\n", __FUNCTION__);
dsp->tx_mix = 0;
if (dsp->conf_id)
ret = dsp_cmx(dsp);
if (debug & DEBUG_DSP_CMX)
dsp_cmx_hardware(dsp->conf, dsp);
if (dsp_debug & DEBUG_DSP_CMX)
dsp_cmx_debug(dsp);
break;
case BF_ENABLE_KEY: /* turn blowfish on */
if (len<4 || len>56) {
ret = -EINVAL;
break;
}
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: turn blowfish on (key not shown)\n", __FUNCTION__);
ret = dsp_bf_init(dsp, (u8*)data, len);
/* set new cont */
if (!ret)
cont = BF_ACCEPT;
else
cont = BF_REJECT;
/* send indication if it worked to set it */
nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &cont, 0);
unlock_HW(&dsp_lock);
if (nskb)
{
if (dsp->inst.up.func(&dsp->inst.up, nskb))
dev_kfree_skb(nskb);
}
lock_HW(&dsp_lock, 0);
if (!ret)
dsp_cmx_hardware(dsp->conf, dsp);
break;
case BF_DISABLE: /* turn blowfish off */
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: turn blowfish off\n", __FUNCTION__);
dsp_bf_cleanup(dsp);
dsp_cmx_hardware(dsp->conf, dsp);
break;
default:
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: ctrl req %x unhandled\n", __FUNCTION__, cont);
ret = -EINVAL;
}
@ -436,7 +457,7 @@ dsp_from_up(mISDNif_t *hif, struct sk_buff *skb)
break;
case DL_ESTABLISH | REQUEST:
case PH_ACTIVATE | REQUEST:
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: activating b_channel %s\n", __FUNCTION__, dsp->inst.name);
lock_HW(&dsp_lock, 0);
dsp->tx_pending = 0;
@ -447,15 +468,18 @@ dsp_from_up(mISDNif_t *hif, struct sk_buff *skb)
return(dsp->inst.down.func(&dsp->inst.down, skb));
case DL_RELEASE | REQUEST:
case PH_DEACTIVATE | REQUEST:
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: releasing b_channel %s\n", __FUNCTION__, dsp->inst.name);
lock_HW(&dsp_lock, 0);
dsp->tx_pending = 0;
dsp->tone.tone = dsp->tone.hardware = dsp->tone.software = 0;
if (timer_pending(&dsp->tone.tl))
del_timer(&dsp->tone.tl);
unlock_HW(&dsp_lock);
hh->prim = PH_DEACTIVATE | REQUEST;
return(dsp->inst.down.func(&dsp->inst.down, skb));
default:
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: msg %x unhandled %s\n", __FUNCTION__, hh->prim, dsp->inst.name);
ret = -EINVAL;
break;
@ -475,7 +499,7 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
dsp_t *dsp;
mISDN_head_t *hh;
int ret = 0;
unsigned char *digits;
u8 *digits;
int cont;
struct sk_buff *nskb;
@ -490,25 +514,29 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
{
case PH_DATA | CONFIRM:
case DL_DATA | CONFIRM:
lock_HW(&dsp_lock, 0);
dsp->tx_pending = 1;
schedule_work(&dsp->sendwork);
unlock_HW(&dsp_lock);
break;
case PH_DATA | INDICATION:
case DL_DATA | INDICATION:
if (skb->len < 1)
break;
lock_HW(&dsp_lock, 0);
/* decrypt if enabled */
if (dsp->bf_enable)
dsp_bf_decrypt(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, (options&DSP_OPT_ULAW)?1:0);
digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, (dsp_options&DSP_OPT_ULAW)?1:0);
if (digits) while(*digits) {
if (dsp->debug & DEBUG_DSP_DTMF)
if (dsp_debug & DEBUG_DSP_DTMF)
printk(KERN_DEBUG "%s: sending software decoded digit(%c) to upper layer %s\n", __FUNCTION__, *digits, dsp->inst.name);
cont = DTMF_TONE_VAL | *digits;
nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &cont, 0);
unlock_HW(&dsp_lock);
if (!nskb)
{
lock_HW(&dsp_lock, 0);
break;
}
if (dsp->inst.up.func(&dsp->inst.up, nskb))
dev_kfree_skb(nskb);
lock_HW(&dsp_lock, 0);
@ -518,10 +546,24 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
/* change volume if requested */
if (dsp->rx_volume)
dsp_change_volume(skb, dsp->rx_volume);
/* process data from card at cmx */
dsp_cmx_receive(dsp, skb);
/* we need to process receive data if software */
if (dsp->pcm_slot_tx<0 && dsp->pcm_slot_rx<0) {
/* process data from card at cmx */
dsp_cmx_receive(dsp, skb);
}
/* we send data only if software or if we have some
* or if we cannot do tones with hardware
*/
if ((dsp->pcm_slot_tx<0 && !dsp->hfc_loops)
|| dsp->R_tx!=dsp->W_tx
|| (dsp->tone.tone && dsp->tone.software)) {
/* schedule sending skb->len bytes */
dsp->tx_pending = skb->len;
schedule_work(&dsp->sendwork);
}
if (dsp->rx_disabled) {
/* if receive is not allowed */
dev_kfree_skb(skb);
unlock_HW(&dsp_lock);
break;
}
@ -530,23 +572,30 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
return(dsp->inst.up.func(&dsp->inst.up, skb));
case PH_CONTROL | INDICATION:
lock_HW(&dsp_lock, 0);
if (dsp->debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: PH_CONTROL received: %x %s\n", __FUNCTION__, hh->dinfo, dsp->inst.name);
if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
printk(KERN_DEBUG "%s: PH_CONTROL received: %x (len %d) %s\n", __FUNCTION__, hh->dinfo, skb->len, dsp->inst.name);
switch (hh->dinfo) {
case HW_HFC_COEFF: /* getting coefficients */
if (dsp->dtmf.hardware == 2)
if (!dsp->dtmf.hardware) {
if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
printk(KERN_DEBUG "%s: ignoring DTMF coefficients from HFC\n", __FUNCTION__);
break;
}
if (dsp->inst.up.func) {
digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, 2);
if (digits) while(*digits) {
int k;
struct sk_buff *nskb;
if (dsp->debug & DEBUG_DSP_DTMF)
if (dsp_debug & DEBUG_DSP_DTMF)
printk(KERN_DEBUG "%s: now sending software decoded digit(%c) to upper layer %s\n", __FUNCTION__, *digits, dsp->inst.name);
k = *digits | DTMF_TONE_VAL;
nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &k, 0);
unlock_HW(&dsp_lock);
if (!nskb)
{
lock_HW(&dsp_lock, 0);
break;
}
if (dsp->inst.up.func(&dsp->inst.up, nskb))
dev_kfree_skb(nskb);
lock_HW(&dsp_lock, 0);
@ -556,7 +605,7 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
break;
default:
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: ctrl ind %x unhandled %s\n", __FUNCTION__, hh->dinfo, dsp->inst.name);
ret = -EINVAL;
}
@ -564,7 +613,7 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
break;
case PH_ACTIVATE | CONFIRM:
lock_HW(&dsp_lock, 0);
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: b_channel is now active %s\n", __FUNCTION__, dsp->inst.name);
/* bchannel now active */
dsp->b_active = 1;
@ -573,30 +622,30 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
if (dsp->conf)
dsp->W_rx = dsp->R_rx = dsp->conf->W_max;
memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff));
if (dsp->conf_id)
ret = dsp_cmx(dsp);
/* now trigger transmission */
dsp->tx_pending = 1;
schedule_work(&dsp->sendwork);
unlock_HW(&dsp_lock);
if (dsp->debug & DEBUG_DSP_CORE)
dsp_cmx_hardware(dsp->conf, dsp);
// /* now trigger transmission */
//#ifndef AUTOJITTER
// dsp->tx_pending = 1;
// schedule_work(&dsp->sendwork);
//#endif
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: done with activation, sending confirm to user space. %s\n", __FUNCTION__, dsp->inst.name);
/* send activation to upper layer */
hh->prim = DL_ESTABLISH | CONFIRM;
unlock_HW(&dsp_lock);
return(dsp->inst.up.func(&dsp->inst.up, skb));
case PH_DEACTIVATE | CONFIRM:
lock_HW(&dsp_lock, 0);
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: b_channel is now inactive %s\n", __FUNCTION__, dsp->inst.name);
/* bchannel now inactive */
dsp->b_active = 0;
if (dsp->conf_id)
dsp_cmx(dsp);
unlock_HW(&dsp_lock);
dsp_cmx_hardware(dsp->conf, dsp);
hh->prim = DL_RELEASE | CONFIRM;
unlock_HW(&dsp_lock);
return(dsp->inst.up.func(&dsp->inst.up, skb));
default:
if (dsp->debug & DEBUG_DSP_CORE)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: msg %x unhandled %s\n", __FUNCTION__, hh->prim, dsp->inst.name);
ret = -EINVAL;
}
@ -615,6 +664,9 @@ release_dsp(dsp_t *dsp)
mISDNinstance_t *inst = &dsp->inst;
conference_t *conf;
lock_HW(&dsp_lock, 0);
if (timer_pending(&dsp->tone.tl))
del_timer(&dsp->tone.tl);
#ifdef HAS_WORKQUEUE
if (dsp->sendwork.pending)
printk(KERN_ERR "%s: pending sendwork: %lx %s\n", __FUNCTION__, dsp->sendwork.pending, dsp->inst.name);
@ -622,7 +674,7 @@ release_dsp(dsp_t *dsp)
if (dsp->sendwork.sync)
printk(KERN_ERR "%s: pending sendwork: %lx %s\n", __FUNCTION__, dsp->sendwork.sync, dsp->inst.name);
#endif
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: removing conferences %s\n", __FUNCTION__, dsp->inst.name);
conf = dsp->conf;
if (conf) {
@ -632,7 +684,7 @@ release_dsp(dsp_t *dsp)
}
}
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: disconnecting instances %s\n", __FUNCTION__, dsp->inst.name);
if (inst->up.peer) {
inst->up.peer->obj->ctrl(inst->up.peer,
@ -643,13 +695,14 @@ release_dsp(dsp_t *dsp)
MGR_DISCONNECT | REQUEST, &inst->down);
}
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: remove & destroy object %s\n", __FUNCTION__, dsp->inst.name);
REMOVE_FROM_LISTBASE(dsp, ((dsp_t *)dsp_obj.ilist));
dsp_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
unlock_HW(&dsp_lock);
vfree(dsp);
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: dsp instance released\n", __FUNCTION__);
}
@ -663,7 +716,7 @@ new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
dsp_t *ndsp;
int err = 0;
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: creating new dsp instance\n", __FUNCTION__);
if (!st || !pid)
@ -685,31 +738,52 @@ new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
}
sprintf(ndsp->inst.name, "DSP_S%x/C%x",
(st->id&0xff), (st->id&0xff00)>>8);
ndsp->debug = debug;
ndsp->inst.up.owner = &ndsp->inst;
ndsp->inst.down.owner = &ndsp->inst;
// jolly patch start
//#ifndef AUTOJITTER
/* set frame size to start */
ndsp->largest = SEND_LEN << 1;
// jolly patch stop
#ifdef WITH_HARDWARE
if (!(options & DSP_OPT_NOHARDWARE)) {
/* check if b-channel is on hfc_chip (0 = no chip) */
hier muss noch herausgefunden werden, wie ich erfrage, ob und
welcher hfc-chip verwendet wird (0 = kein chip)
ndsp->hfc_id = ;
ndsp->largest = 64 << 1;
//#endif
ndsp->hfc_id = -1; /* current PCM id */
ndsp->pcm_id = -1; /* current PCM id */
ndsp->pcm_slot_rx = -1; /* current CPM slot */
ndsp->pcm_slot_tx = -1;
ndsp->pcm_bank_rx = -1;
ndsp->pcm_bank_tx = -1;
ndsp->hfc_conf = -1; /* current conference number */
#ifdef CONFIG_MISDN_DSP_HARDWARETEST
if (!(dsp_options & DSP_OPT_NOHARDWARE)) {
/* check if b-channel is on HFCmulti */
ndsp->hfc_id = 1;
/* check if b-channel is capable of HFCmulti DTMF */
ndsp->hfc_dtmf = 1;
/* check if b-channel is capable of HFCmulti tone loops */
ndsp->hfc_loops = 0;
/* check if b-channel is on PCM */
ndsp->pcm_id = 1;
ndsp->pcm_slots = 32;
ndsp->pcm_banks = 2;
}
#endif
/* set timer */
ndsp->tone.tl.function = (void *)dsp_tone_timeout;
ndsp->tone.tl.data = (long) ndsp;
init_timer(&ndsp->tone.tl);
/* init send que */
INIT_WORK(&ndsp->sendwork, (void *)(void *)sendevent, ndsp);
lock_HW(&dsp_lock, 0);
/* append and register */
APPEND_TO_LIST(ndsp, ((dsp_t *)dsp_obj.ilist));
err = dsp_obj.ctrl(st, MGR_REGLAYER | INDICATION, &ndsp->inst);
if (err) {
printk(KERN_ERR "%s: failed to register layer %s\n", __FUNCTION__, ndsp->inst.name);
REMOVE_FROM_LISTBASE(ndsp, ((dsp_t *)dsp_obj.ilist));
unlock_HW(&dsp_lock);
goto free_mem;
} else {
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: dsp instance created %s\n", __FUNCTION__, ndsp->inst.name);
unlock_HW(&dsp_lock);
}
return(err);
}
@ -724,7 +798,7 @@ dsp_manager(void *data, u_int prim, void *arg) {
dsp_t *dspl = (dsp_t *)dsp_obj.ilist;
int ret = 0;
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n", __FUNCTION__, data, prim, arg);
if (!data)
return(-EINVAL);
@ -736,9 +810,7 @@ dsp_manager(void *data, u_int prim, void *arg) {
switch(prim) {
case MGR_NEWLAYER | REQUEST:
lock_HW(&dsp_lock, 0);
ret = new_dsp(data, arg);
unlock_HW(&dsp_lock);
break;
case MGR_CONNECT | REQUEST:
if (!dspl) {
@ -773,12 +845,10 @@ dsp_manager(void *data, u_int prim, void *arg) {
ret = -EINVAL;
break;
}
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: release_dsp id %x\n", __FUNCTION__, dspl->inst.st->id);
lock_HW(&dsp_lock, 0);
release_dsp(dspl);
unlock_HW(&dsp_lock);
break;
default:
printk(KERN_WARNING "%s: prim %x not handled\n", __FUNCTION__, prim);
@ -796,13 +866,41 @@ static int dsp_init(void)
{
int err;
/* copy variables */
dsp_options = options;
dsp_debug = debug;
/* display revision */
printk(KERN_INFO "mISDN_dsp: Audio DSP Rev. %s (debug=0x%x)\n", mISDN_getrev(dsp_revision), debug);
#ifndef AUTOJITTER
/* set packet size */
switch(poll) {
case 8:
break;
case 16:
break;
case 32:
break;
case 64: case 0:
poll = 64;
break;
case 128:
break;
case 256:
break;
default:
printk(KERN_ERR "%s: Wrong poll value (%d).\n", __FUNCTION__, poll);
err = -EINVAL;
return(err);
}
#endif
/* fill mISDN object (dsp_obj) */
memset(&dsp_obj, 0, sizeof(dsp_obj));
#ifdef MODULE
dsp_obj.owner = THIS_MODULE;
SET_MODULE_OWNER(&dsp_obj);
#endif
dsp_obj.name = DSPName;
dsp_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_DSP;
@ -812,11 +910,12 @@ static int dsp_init(void)
dsp_obj.ilist = NULL;
/* initialize audio tables */
silence = (options&DSP_OPT_ULAW)?0xff:0x2a;
dsp_audio_law_to_s32 = (options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32:dsp_audio_alaw_to_s32;
silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a;
dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32:dsp_audio_alaw_to_s32;
dsp_audio_generate_s2law_table();
dsp_audio_generate_seven();
dsp_audio_generate_mix_table();
if (options & DSP_OPT_ULAW)
if (dsp_options & DSP_OPT_ULAW)
dsp_audio_generate_ulaw_samples();
dsp_audio_generate_volume_changes();
@ -840,7 +939,7 @@ static void dsp_cleanup(void)
{
int err;
if (debug & DEBUG_DSP_MGR)
if (dsp_debug & DEBUG_DSP_MGR)
printk(KERN_DEBUG "%s: removing module\n", __FUNCTION__);
if ((err = mISDN_unregister(&dsp_obj))) {

View File

@ -21,9 +21,9 @@
/* For DTMF recognition:
* 2 * cos(2 * PI * k / N) precalculated for all k
*/
static signed long long cos2pik[NCOEFF] =
static u64 cos2pik[NCOEFF] =
{
/* k << 15 (source: hfc-4s document (www.colognechip.de)) */
/* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */
55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630
};
@ -68,17 +68,18 @@ void dsp_dtmf_goertzel_init(dsp_t *dsp)
* fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder
*/
unsigned char
*dsp_dtmf_goertzel_decode(dsp_t *dsp, unsigned char *data, int len, int fmt)
u8
*dsp_dtmf_goertzel_decode(dsp_t *dsp, u8 *data, int len, int fmt)
{
unsigned char what;
u8 what;
int size;
signed short *buf;
signed long sk, sk1, sk2;
s32 sk, sk1, sk2;
int k, n, i;
signed long result[NCOEFF], tresh, treshl;
s32 *hfccoeff;
s32 result[NCOEFF], tresh, treshl;
int lowgroup, highgroup;
signed long long cos2pik_;
s64 cos2pik_;
dsp->dtmf.digits[0] = '\0';
@ -100,16 +101,26 @@ again:
case 2: /* HFC coefficients */
default:
if (len == 0)
return(dsp->dtmf.digits);
if (len < sizeof(result)) {
printk(KERN_ERR "%s: coefficients have invalid size.\n",
__FUNCTION__);
if (len < 64) {
if (len > 0)
printk(KERN_ERR "%s: coefficients have invalid size. (is=%d < must=%d)\n",
__FUNCTION__, len, 64);
return(dsp->dtmf.digits);
}
memcpy(result, data, sizeof(result));
data += sizeof(result);
len -= sizeof(result);
hfccoeff = (s32 *)data;
for (k = 0; k < NCOEFF; k++) {
sk2 = (*hfccoeff++)>>4;
sk = (*hfccoeff++)>>4;
if (sk>32767 || sk<-32767 || sk2>32767 || sk2<-32767)
printk(KERN_WARNING "DTMF-Detection overflow\n");
/* compute |X(k)|**2 */
result[k] =
(sk * sk) -
(((cos2pik[k] * sk) >> 15) * sk2) +
(sk2 * sk2);
}
data += 64;
len -= 64;
goto coefficients;
break;
}
@ -160,9 +171,9 @@ again:
goto storedigit;
}
if (dsp->debug & DEBUG_DSP_DTMFCOEFF)
printk(KERN_DEBUG "a %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld"
" tr:%3ld r %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld\n",
if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
" tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
result[0]/10000, result[1]/10000, result[2]/10000,
result[3]/10000, result[4]/10000, result[5]/10000,
result[6]/10000, result[7]/10000, tresh/10000,
@ -208,7 +219,7 @@ again:
what = dtmf_matrix[lowgroup][highgroup];
storedigit:
if (what && (dsp->debug & DEBUG_DSP_DTMF))
if (what && (dsp_debug & DEBUG_DSP_DTMF))
printk(KERN_DEBUG "DTMF what: %c\n", what);
if (dsp->dtmf.lastwhat!=what)
@ -219,7 +230,7 @@ storedigit:
if (dsp->dtmf.lastdigit!=what) {
dsp->dtmf.lastdigit = what;
if (what) {
if (dsp->debug & DEBUG_DSP_DTMF)
if (dsp_debug & DEBUG_DSP_DTMF)
printk(KERN_DEBUG "DTMF digit: %c\n",
what);
if ((strlen(dsp->dtmf.digits)+1) <sizeof(dsp->dtmf.digits)) {

View File

@ -38,32 +38,9 @@
/***************/
/* all tones are alaw encoded */
/* the last sample+1 is in phase with the first sample. the error is low */
static unsigned char sample_german_all[]= {
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
static u8 sample_german_all[]= {
0x80,0xab,0x81,0x6d,0xfd,0xdd,0x5d,0x9d,
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
@ -77,339 +54,125 @@ static unsigned char sample_german_all[]= {
0x4d,0xd1,0x89,0x88,0xd0,0x4c,0x9c,0x5c,
0xdc,0xfc,0x6c,
};
static unsigned long sizeof_german_all = sizeof(sample_german_all);
static u32 sizeof_german_all = sizeof(sample_german_all);
static unsigned char sample_german_old[]= {
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
0x2d,0x59,0x3d,0x0d,0xdd,0x9d,0x89,0xbd,
0x6c,0xe0,0x7c,0xbc,0x5c,0x1c,0x08,0x0c,
static u8 sample_german_old[]= {
0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
0x8c,
0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
0x8c,
0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
0x8c,
0xec,0x68,0xe1,0x6d,0x6d,0x91,0x51,0xed,
0x6d,0x01,0x1e,0x10,0x0c,0x90,0x60,0x70,
0x8c,
};
static unsigned long sizeof_german_old = sizeof(sample_german_old);
static u32 sizeof_german_old = sizeof(sample_german_old);
static unsigned char sample_american_dialtone[]= {
0x2a,0xd0,0x9c,0x64,0x44,0xb4,0x44,0x64,0x9c,0xac,
0x9e,0xb1,0xbd,0x25,0x85,0x05,0x85,0x25,0x3d,0x11,
0x47,0x20,0xec,0x3c,0x1c,0xdc,0x1c,0xbc,0xec,0x00,
0xc6,0x29,0x81,0x91,0xad,0x51,0x91,0x41,0xd9,0x29,
0x6f,0x12,0x1e,0x7e,0xc2,0x13,0x07,0x57,0xe9,0xd7,
0x1f,0x8e,0x08,0x80,0x90,0x2c,0x6c,0x6c,0x2c,0x30,
0x48,0x5f,0x01,0x6d,0xfd,0x5d,0x25,0xa5,0x9d,0x0d,
0x01,0xce,0x70,0x3c,0x24,0x84,0xc4,0x04,0xe4,0x7c,
0x10,0xca,0x91,0x7d,0x65,0x45,0xb5,0x45,0x85,0xdd,
0x2d,0x27,0xf0,0xfc,0x64,0xc4,0x44,0xc4,0x64,0x1c,
0x2c,0x16,0x81,0xcd,0x5d,0x65,0x85,0x65,0xa5,0x3d,
0xd1,0x29,0x38,0x50,0xcc,0xfc,0x7c,0xfc,0xcc,0x2c,
0x80,0xf6,0xc7,0xd9,0xc1,0x31,0x31,0xc1,0x21,0x09,
0xc7,0x33,0xba,0xba,0xb3,0x87,0xe9,0x39,0x19,0x19,
0x49,0xb7,0x2e,0xb8,0x40,0xac,0x8c,0x4c,0xcc,0x8c,
0xd0,0x58,0x13,0x01,0x8d,0x7d,0x25,0xe5,0xe5,0x5d,
0x4d,0x31,0x7b,0x30,0x3c,0x24,0x04,0xc4,0xc4,0x64,
0x1c,0x2c,0xe6,0x31,0xfd,0x65,0xc5,0xb5,0x45,0x05,
0x5d,0x6d,0x29,0x00,0xbc,0xe4,0x04,0x44,0xc4,0x64,
0xdc,0xec,0x08,0xd9,0x6d,0x9d,0x25,0x65,0xe5,0x5d,
0xbd,0xd1,0x09,0xe8,0xf0,0x6c,0x4c,0xbc,0x4c,0x8c,
0xd0,0x60,0x76,0xff,0xc9,0x21,0x61,0xe1,0x99,0x89,
0x47,0xef,0x6b,0x6b,0xef,0xb7,0x09,0x59,0x81,0xc1,
0x01,0x21,0xe9,0xa2,0xf8,0xf0,0x6c,0x4c,0xfc,0xfc,
0x4c,0xec,0x80,0x1a,0x81,0x8d,0x1d,0xe5,0x65,0x65,
0x25,0xfd,0xd1,0x27,0x40,0xbc,0x24,0x04,0x44,0x44,
0x84,0x5c,0x6c,0x28,0x01,0xbd,0xe5,0xc5,0xb5,0xb5,
0x05,0xa5,0x8d,0xb9,0x20,0xcc,0xa4,0x84,0xc4,0xc4,
0x64,0xdc,0x6c,0x78,0xc9,0x2d,0xfd,0xa5,0x25,0x25,
0xdd,0x4d,0xd1,0xb9,0xc6,0x00,0xac,0x8c,0x0c,0x8c,
0x2c,0xf0,0x20,0x76,0xb3,0xd7,0xc9,0x49,0x89,0x97,
0x9f,0x0b,0x72,0x12,0x8b,0x27,0x89,0x21,0x41,0x71,
0x11,0x71,0xc1,0x39,0x7b,0xf8,0x90,0x0c,0xfc,0x9c,
0x1c,0xfc,0x8c,0xb0,0x1e,0x61,0x8d,0x1d,0xe5,0x85,
0x85,0xe5,0x9d,0x2d,0x29,0x80,0x4c,0x24,0x04,0x44,
0x44,0x04,0xa4,0x0c,0x38,0x21,0x4d,0x25,0xc5,0xb5,
0x45,0x05,0x25,0xcd,0x59,0x38,0x8c,0xdc,0x64,0x04,
0x04,0x64,0xdc,0x8c,0x20,0x17,0x11,0x4d,0x1d,0xa5,
0x5d,0x9d,0xcd,0x11,0xf9,0x4e,0x20,0x70,0x2c,0xec,
0x2c,0x10,0xc0,0xf8,0x46,0xcb,0xe7,0xb7,0xc7,0xff,
0x2a,0xfe,0xc6,0xb6,0xe6,0xca,0x47,0xf9,0xc1,0x11,
0x2d,0xed,0x2d,0x71,0x21,0x4f,0xf8,0x10,0xcc,0x9c,
0x5c,0xa4,0x1c,0x4c,0x10,0x16,0x21,0x8d,0xdd,0x65,
0x05,0x05,0x65,0xdd,0x8d,0x39,0x58,0xcc,0x24,0x04,
0x44,0xb4,0xc4,0x24,0x4c,0x20,0x39,0x0d,0xa5,0x05,
0x45,0x45,0x05,0x25,0x4d,0x81,0x28,0x2c,0x9c,0xe4,
0x84,0x84,0xe4,0x1c,0x8c,0x60,0x1f,0xb1,0x8d,0xfd,
0x1d,0x9d,0xfd,0x0d,0x91,0xf9,0x7a,0x38,0xc0,0x70,
0x10,0x70,0x40,0x20,0x88,0x26,0x8a,0x13,0x73,0x0a,
0x9e,0x96,0x88,0x48,0xc8,0xd6,0xb2,0x77,0x21,0xf1,
0x2d,0x8d,0x0d,0x8d,0xad,0x01,0xc7,0xb8,0xd0,0x4c,
0xdc,0x24,0x24,0xa4,0xfc,0x2c,0xc8,0x79,0x6d,0xdd,
0x65,0xc5,0xc5,0x85,0xa5,0xcd,0x21,0xb8,0x8c,0xa4,
0x04,0xb4,0xb4,0xc4,0xe4,0xbc,0x00,0x29,0x6d,0x5d,
0x85,0x45,0x45,0x05,0x25,0xbd,0x41,0x26,0xd0,0xfc,
0x24,0x64,0x64,0xe4,0x1c,0x8c,0x80,0x1b,0x81,0xed,
0x4d,0xfd,0xfd,0x4d,0x6d,0xf1,0xf9,0xa3,0xe8,0x20,
0x00,0xc0,0x80,0x58,0x08,0xb6,0xee,0x6a,0x6a,0xee,
0x46,0x88,0x98,0xe0,0x60,0x20,0xc8,0xfe,0x77,0x61,
0xd1,0x8d,0x4d,0xbd,0x4d,0x6d,0xf1,0xe9,0x08,0xd0,
0xbc,0x5c,0xe4,0x64,0x24,0x9c,0x6c,0xd8,0x09,0xed,
0xdd,0x65,0xc5,0x45,0x05,0xe5,0xbd,0x01,0x28,0x6c,
0x5c,0x04,0x44,0xb4,0xc4,0x64,0xfc,0x30,0xe7,0x2d,
0x1d,0x65,0xc5,0xc5,0x05,0x25,0x3d,0x31,0x7a,0x30,
0x4c,0x5c,0xe4,0xe4,0x24,0x7c,0x8c,0x00,0x12,0x59,
0xd1,0x8d,0xcd,0x4d,0x8d,0xad,0x41,0xb9,0x2f,0xb6,
0x48,0x18,0x18,0x38,0xe8,0x86,0xb2,0xbb,0xbb,0x32,
0xc6,0x08,0x20,0xc0,0x30,0x30,0xc0,0xd8,0xc6,0xf7,
0x81,0x2d,0xcd,0xfd,0x7d,0xfd,0xcd,0x51,0x39,0x28,
0xd0,0x3c,0xa4,0x64,0x84,0x64,0x5c,0xcc,0x80,0x17,
0x2d,0x1d,0x65,0xc5,0x45,0xc5,0x65,0xfd,0xf1,0x26,
0x2c,0xdc,0x84,0x44,0xb4,0x44,0x64,0x7c,0x90,0xcb,
0x11,0x7d,0xe5,0x05,0xc5,0x85,0x25,0x3d,0x71,0xcf,
0x00,0x0c,0x9c,0xa4,0x24,0x5c,0xfc,0x6c,0x00,0x5e,
0x49,0x31,0x2d,0x6d,0x6d,0x2d,0x91,0x81,0x09,0x8f,
0x1e,0xd6,0xe8,0x56,0x06,0x12,0xc3,0x7f,0x1f,0x13,
0x6e,0x28,0xd8,0x40,0x90,0x50,0xac,0x90,0x80,0x28,
0xc7,0x01,0xed,0xbd,0x1d,0xdd,0x1d,0x3d,0xed,0x21,
0x46,0x10,0x3c,0x24,0x84,0x04,0x84,0x24,0xbc,0xb0,
0x9f,0xad,0x9d,0x65,0x45,0xb5,0x45,0x65,0x9d,0xd1,
static u8 sample_american_dialtone[]= {
0x2a,0x18,0x90,0x6c,0x4c,0xbc,0x4c,0x6c,
0x10,0x58,0x32,0xb9,0x31,0x2d,0x8d,0x0d,
0x8d,0x2d,0x31,0x99,0x0f,0x28,0x60,0xf0,
0xd0,0x50,0xd0,0x30,0x60,0x08,0x8e,0x67,
0x09,0x19,0x21,0xe1,0xd9,0xb9,0x29,0x67,
0x83,0x02,0xce,0xbe,0xee,0x1a,0x1b,0xef,
0xbf,0xcf,0x03,0x82,0x66,0x28,0xb8,0xd8,
0xe0,0x20,0x18,0x08,0x66,0x8f,0x09,0x61,
0x31,0xd1,0x51,0xd1,0xf1,0x61,0x29,0x0e,
0x98,0x30,0x2c,0x8c,0x0c,0x8c,0x2c,0x30,
0xb8,0x33,0x59,0x11,0x6d,0x4d,0xbd,0x4d,
0x6d,0x91,0x19,
};
static unsigned long sizeof_american_dialtone = sizeof(sample_american_dialtone);
static u32 sizeof_american_dialtone = sizeof(sample_american_dialtone);
static unsigned char sample_american_ringing[]= {
0x2a,0x42,0xee,0x2e,0x1a,0x73,0x87,0x29,0x49,0x79,
0x79,0xc9,0xf7,0x0b,0x96,0x18,0x00,0xf0,0x70,0xb0,
0xe0,0x28,0x3f,0xd9,0xf1,0x2d,0x6d,0x6d,0xad,0x01,
0x77,0xe8,0x30,0x6c,0xbc,0x3c,0x4c,0x6c,0xc0,0x0e,
0xe1,0xed,0x3d,0xdd,0xdd,0x7d,0x8d,0x81,0x26,0x90,
0xbc,0x5c,0xe4,0x24,0x1c,0x6c,0x98,0xf9,0x8d,0xdd,
0x65,0x85,0xe5,0x1d,0xed,0xf7,0xb0,0x3c,0xe4,0x04,
0x04,0x64,0x9c,0x10,0xcf,0x2d,0x5d,0x85,0x45,0xc5,
0x65,0x3d,0x01,0xf8,0x4c,0xe4,0xc4,0xb4,0xc4,0xe4,
0xcc,0x08,0xb1,0x9d,0x85,0x45,0xb5,0x05,0xa5,0x2d,
0x2a,0x2c,0xa4,0x04,0xb4,0x44,0x84,0x9c,0xb0,0x09,
0xcd,0xe5,0xc5,0xb5,0xc5,0xe5,0x4d,0xf9,0x00,0x3c,
0x64,0xc4,0x44,0x84,0x5c,0x2c,0xce,0x11,0x9d,0x65,
0x05,0x05,0xe5,0x3d,0xb1,0xf6,0xec,0x1c,0xe4,0x84,
0x64,0xdc,0x8c,0xf8,0x99,0x6d,0x1d,0x25,0xe5,0x5d,
0xbd,0x91,0x27,0x80,0x8c,0x7c,0xdc,0xdc,0x3c,0xec,
0xe0,0x0f,0xc1,0x6d,0x4d,0x3d,0xbd,0x6d,0x31,0xe9,
0x76,0x00,0xac,0x6c,0x6c,0x2c,0xf0,0xd8,0x3e,0x29,
0xe1,0xb1,0x71,0xf1,0x01,0x19,0x97,0x0a,0xf6,0xc8,
0x78,0x78,0x48,0x28,0x86,0x72,0x1b,0x2f,0xef,0x43,
static u8 sample_american_ringing[]= {
0x2a,0xe0,0xac,0x0c,0xbc,0x4c,0x8c,0x90,
0x48,0xc7,0xc1,0xed,0xcd,0x4d,0xcd,0xed,
0xc1,0xb7,0x08,0x30,0xec,0xcc,0xcc,0x8c,
0x10,0x58,0x1a,0x99,0x71,0xed,0x8d,0x8d,
0x2d,0x41,0x89,0x9e,0x20,0x70,0x2c,0xec,
0x2c,0x70,0x20,0x86,0x77,0xe1,0x31,0x11,
0xd1,0xf1,0x81,0x09,0xa3,0x56,0x58,0x00,
0x40,0xc0,0x60,0x38,0x46,0x43,0x57,0x39,
0xd9,0x59,0x99,0xc9,0x77,0x2f,0x2e,0xc6,
0xd6,0x28,0xd6,0x36,0x26,0x2e,0x8a,0xa3,
0x43,0x63,0x4b,0x4a,0x62,0x42,0xa2,0x8b,
0x2f,0x27,0x37,0xd7,0x29,0xd7,0xc7,0x2f,
0x2e,0x76,0xc8,0x98,0x58,0xd8,0x38,0x56,
0x42,0x47,0x39,0x61,0xc1,0x41,0x01,0x59,
0x57,0xa2,0x08,0x80,0xf0,0xd0,0x10,0x30,
0xe0,0x76,0x87,0x21,0x71,0x2d,0xed,0x2d,
0x71,0x21,0x9f,0x88,0x40,0x2c,0x8c,0x8c,
0xec,0x70,0x98,0x1b,0x59,0x11,0x8d,0xcd,
0xcd,0xed,0x31,0x09,0xb6,0xc0,0xec,0xcc,
0x4c,0xcc,0xec,0xc0,0xc6,0x49,0x91,0x8d,
0x4d,0xbd,0x0d,0xad,0xe1,
};
static unsigned long sizeof_american_ringing = sizeof(sample_american_ringing);
static u32 sizeof_american_ringing = sizeof(sample_american_ringing);
static unsigned char sample_american_busy[]= {
0x2a,0x67,0x77,0x27,0xfe,0x18,0x70,0xec,0x8c,0x2c,
0x80,0x2f,0x71,0x3d,0xa5,0xe5,0xdd,0x6d,0x37,0x10,
0xdc,0x04,0xc4,0x84,0x7c,0x60,0x41,0xdd,0xc5,0xb5,
0xc5,0xa5,0x11,0xc8,0xbc,0x64,0xc4,0x04,0xa4,0x2c,
0x2a,0x51,0x7d,0xa5,0x5d,0x3d,0x11,0xb7,0x98,0x10,
0x2c,0xac,0xb0,0x78,0x5e,0xef,0x9f,0x7b,0xe6,0xe8,
0x08,0x96,0x53,0xd9,0x11,0x8d,0xcd,0x8d,0x31,0xef,
0xb0,0x3c,0x24,0xe4,0xa4,0xcc,0xf8,0xb1,0x1d,0x85,
0x45,0x05,0x5d,0xf1,0xd8,0x7c,0x04,0xb4,0x44,0xe4,
0xec,0x1f,0x0d,0xe5,0x05,0x05,0x25,0x6d,0xb7,0x30,
0xbc,0xdc,0xdc,0x3c,0x50,0xe8,0x89,0xb1,0x11,0x91,
0x01,0x49,0x1f,0x1a,0x1a,0x3f,0xe9,0x79,0x19,0x09,
0x2a,0x18,0xd0,0xcc,0xbc,0xcc,0xd0,0x16,0x01,0xbd,
0x25,0x65,0xe5,0xfd,0x81,0xe0,0xfc,0x84,0x44,0xc4,
0x24,0x2c,0xd7,0xbd,0x85,0x45,0x45,0x65,0x0d,0x9f,
0x2c,0xa4,0x84,0x84,0x24,0x0c,0x48,0x61,0x0d,0x9d,
0x9d,0xbd,0x51,0x49,0xb6,0x60,0x30,0x40,0xe0,0x68,
0x4e,0xeb,0xc2,0xf6,0xf8,0x60,0x80,0x98,0x0e,0x79,
0x51,0x4d,0xfd,0x3d,0xed,0x39,0x20,0x4c,0x24,0x84,
0x64,0x1c,0x70,0x09,0xbd,0x65,0x45,0x45,0xe5,0x8d,
0x2a,0x8c,0xe4,0x44,0x44,0x64,0xbc,0x08,0x71,0x1d,
0x65,0x85,0x25,0x4d,0x21,0x38,0xec,0x3c,0xfc,0x4c,
0x50,0x78,0x0f,0x99,0x81,0x61,0xf9,0xf7,0xc3,0xea,
0x4f,0x69,0xe1,0x41,0x31,0x61,0xb7,0x48,0x50,0xbc,
0x9c,0x9c,0x0c,0x60,0x49,0x0d,0x25,0x85,0x85,0xa5,
0x2d,0x9e,0x0c,0x64,0x44,0x44,0x84,0xbc,0xd6,0x2d,
0x25,0xc5,0x45,0x85,0xfd,0xe1,0x80,0xfc,0xe4,0x64,
0x24,0xbc,0x00,0x17,0xd1,0xcd,0xbd,0xcd,0xd1,0x19,
0x2a,0x08,0x18,0x78,0xe8,0x3e,0x1b,0x1b,0x1e,0x48,
0x00,0x90,0x10,0xb0,0x88,0xe9,0x51,0x3d,0xdd,0xdd,
0xbd,0x31,0xb6,0x6c,0x24,0x04,0x04,0xe4,0x0c,0x1e,
0xed,0xe5,0x45,0xb5,0x05,0x7d,0xd9,0xf0,0x5c,0x04,
0x44,0x84,0x1c,0xb0,0xf9,0xcd,0xa5,0xe5,0x25,0x3d,
0xb1,0xee,0x30,0x8c,0xcc,0x8c,0x10,0xd8,0x52,0x97,
0x09,0xe9,0xe7,0x7a,0x9e,0xee,0x5f,0x79,0xb1,0xad,
0x2d,0x11,0x99,0xb6,0x10,0x3c,0x5c,0xa4,0x7c,0x50,
0x2a,0x2d,0xa5,0x05,0xc5,0x65,0xbd,0xc9,0x10,0xa4,
0xc4,0xb4,0xc4,0xdc,0x40,0x61,0x7d,0x85,0xc5,0x05,
0xdd,0x11,0x36,0x6c,0xdc,0xe4,0xa4,0x3c,0x70,0x2e,
0x81,0x2d,0x8d,0xed,0x71,0x19,0xff,0x26,0x76,0x66,
static u8 sample_american_busy[]= {
0x2a,0x00,0x6c,0x4c,0x4c,0x6c,0xb0,0x66,
0x99,0x11,0x6d,0x8d,0x2d,0x41,0xd7,0x96,
0x60,0xf0,0x70,0x40,0x58,0xf6,0x53,0x57,
0x09,0x89,0xd7,0x5f,0xe3,0x2a,0xe3,0x5f,
0xd7,0x89,0x09,0x57,0x53,0xf6,0x58,0x40,
0x70,0xf0,0x60,0x96,0xd7,0x41,0x2d,0x8d,
0x6d,0x11,0x99,0x66,0xb0,0x6c,0x4c,0x4c,
0x6c,0x00,0x2a,0x01,0x6d,0x4d,0x4d,0x6d,
0xb1,0x67,0x98,0x10,0x6c,0x8c,0x2c,0x40,
0xd6,0x97,0x61,0xf1,0x71,0x41,0x59,0xf7,
0x52,0x56,0x08,0x88,0xd6,0x5e,0xe2,0x2a,
0xe2,0x5e,0xd6,0x88,0x08,0x56,0x52,0xf7,
0x59,0x41,0x71,0xf1,0x61,0x97,0xd6,0x40,
0x2c,0x8c,0x6c,0x10,0x98,0x67,0xb1,0x6d,
0x4d,0x4d,0x6d,0x01,
};
static unsigned long sizeof_american_busy = sizeof(sample_american_busy);
static u32 sizeof_american_busy = sizeof(sample_american_busy);
static unsigned char sample_special1[]= {
0xa4,0x2a,0x64,0xb4,0x7d,0xd8,0x05,0x45,
0x8c,0xd1,0x44,0xc4,0xf1,0xcc,0xb5,0x05,
0x48,0x9d,0xb4,0xe4,0x1e,0x24,0xb5,0x5d,
0x61,0x85,0x44,0x3c,0x2c,0xc4,0xc5,0x6d,
0xbd,0x45,0x84,0x40,0xdc,0xb4,0xe5,0xd7,
0xe5,0xb5,0xdc,0xd7,0x84,0xb4,0xbd,0x40,
0xc5,0x45,0x2c,0x6d,0x44,0xc4,0x61,0x3c,
0xb5,0x85,0x1e,0x5d,0xb4,0x24,0x48,0xe4,
0xb5,0x9d,0xf1,0x05,0x44,0xcc,0x8c,0xc4,
0x05,0xd1,0x7d,0x45,0x64,0xd8,0xa4,0xb4,
0xa5,0x2a,0x65,0xb5,0x7c,0xd9,0x04,0x44,
0x8d,0xd0,0x45,0xc5,0xf0,0xcd,0xb4,0x04,
0x49,0x9c,0xb5,0xe5,0x1f,0x25,0xb4,0x5c,
0x60,0x84,0x45,0x3d,0x2d,0xc5,0xc4,0x6c,
0xbc,0x44,0x85,0x41,0xdd,0xb5,0xe4,0xd6,
0xe4,0xb4,0xdd,0xd6,0x85,0xb5,0xbc,0x41,
0xc4,0x44,0x2d,0x6c,0x45,0xc5,0x60,0x3d,
0xb4,0x84,0x1f,0x5c,0xb5,0x25,0x49,0xe5,
0xb4,0x9c,0xf0,0x04,0x45,0xcd,0x8d,0xc5,
0x04,0xd0,0x7c,0x44,0x65,0xd9,0xa5,0xb5,
0xa4,0x2a,0x64,0xb4,0x7d,0xd8,0x05,0x45,
0x8c,0xd1,0x44,0xc4,0xf1,0xcc,0xb5,0x05,
0x48,0x9d,0xb4,0xe4,0x1e,0x24,0xb5,0x5d,
0x61,0x85,0x44,0x3c,0x2c,0xc4,0xc5,0x6d,
0xbd,0x45,0x84,0x40,0xdc,0xb4,0xe5,0xd7,
0xe5,0xb5,0xdc,0xd7,0x84,0xb4,0xbd,0x40,
0xc5,0x45,0x2c,0x6d,0x44,0xc4,0x61,0x3c,
0xb5,0x85,0x1e,0x5d,0xb4,0x24,0x48,0xe4,
0xb5,0x9d,0xf1,0x05,0x44,0xcc,0x8c,0xc4,
0x05,0xd1,0x7d,0x45,0x64,0xd8,0xa4,0xb4,
0xa5,0x2a,0x65,0xb5,0x7c,0xd9,0x04,0x44,
0x8d,0xd0,0x45,0xc5,0xf0,0xcd,0xb4,0x04,
0x49,0x9c,0xb5,0xe5,0x1f,0x25,0xb4,0x5c,
0x60,0x84,0x45,0x3d,0x2d,0xc5,0xc4,0x6c,
0xbc,0x44,0x85,0x41,0xdd,0xb5,0xe4,0xd6,
0xe4,0xb4,0xdd,0xd6,0x85,0xb5,0xbc,0x41,
0xc4,0x44,0x2d,0x6c,0x45,0xc5,0x60,0x3d,
0xb4,0x84,0x1f,0x5c,0xb5,0x25,0x49,0xe5,
0xb4,0x9c,0xf0,0x04,0x45,0xcd,0x8d,0xc5,
0x04,0xd0,0x7c,0x44,0x65,0xd9,0xa5,0xb5,
static u8 sample_special1[]= {
0x2a,0x2c,0xbc,0x6c,0xd6,0x71,0xbd,0x0d,
0xd9,0x80,0xcc,0x4c,0x40,0x39,0x0d,0xbd,
0x11,0x86,0xec,0xbc,0xec,0x0e,0x51,0xbd,
0x8d,0x89,0x30,0x4c,0xcc,0xe0,0xe1,0xcd,
0x4d,0x31,0x88,0x8c,0xbc,0x50,0x0f,0xed,
0xbd,0xed,0x87,0x10,0xbc,0x0c,0x38,0x41,
0x4d,0xcd,0x81,0xd8,0x0c,0xbc,0x70,0xd7,
0x6d,0xbd,0x2d,
};
static unsigned long sizeof_special1 = sizeof(sample_special1);
static u32 sizeof_special1 = sizeof(sample_special1);
static unsigned char sample_special2[]= {
0x25,0xd0,0xd9,0x45,0xc4,0x84,0xc5,0x2a,
0xd8,0x85,0x24,0x44,0xb5,0xd1,0xcc,0x9d,
0xcc,0xb4,0xb5,0x9d,0x24,0xd1,0xd8,0x44,
0xc5,0x85,0xc4,0x2a,0xd9,0x84,0x25,0x45,
0xb4,0xd0,0xcd,0x9c,0xcd,0xb5,0xb4,0x9c,
0x25,0xd0,0xd9,0x45,0xc4,0x84,0xc5,0x2a,
0xd8,0x85,0x24,0x44,0xb5,0xd1,0xcc,0x9d,
0xcc,0xb4,0xb5,0x9d,0x24,0xd1,0xd8,0x44,
0xc5,0x85,0xc4,0x2a,0xd9,0x84,0x25,0x45,
0xb4,0xd0,0xcd,0x9c,0xcd,0xb5,0xb4,0x9c,
0x25,0xd0,0xd9,0x45,0xc4,0x84,0xc5,0x2a,
0xd8,0x85,0x24,0x44,0xb5,0xd1,0xcc,0x9d,
0xcc,0xb4,0xb5,0x9d,0x24,0xd1,0xd8,0x44,
0xc5,0x85,0xc4,0x2a,0xd9,0x84,0x25,0x45,
0xb4,0xd0,0xcd,0x9c,0xcd,0xb5,0xb4,0x9c,
0x25,0xd0,0xd9,0x45,0xc4,0x84,0xc5,0x2a,
0xd8,0x85,0x24,0x44,0xb5,0xd1,0xcc,0x9d,
0xcc,0xb4,0xb5,0x9d,0x24,0xd1,0xd8,0x44,
0xc5,0x85,0xc4,0x2a,0xd9,0x84,0x25,0x45,
0xb4,0xd0,0xcd,0x9c,0xcd,0xb5,0xb4,0x9c,
0x25,0xd0,0xd9,0x45,0xc4,0x84,0xc5,0x2a,
0xd8,0x85,0x24,0x44,0xb5,0xd1,0xcc,0x9d,
0xcc,0xb4,0xb5,0x9d,0x24,0xd1,0xd8,0x44,
0xc5,0x85,0xc4,0x2a,0xd9,0x84,0x25,0x45,
0xb4,0xd0,0xcd,0x9c,0xcd,0xb5,0xb4,0x9c,
0x25,0xd0,0xd9,0x45,0xc4,0x84,0xc5,0x2a,
0xd8,0x85,0x24,0x44,0xb5,0xd1,0xcc,0x9d,
0xcc,0xb4,0xb5,0x9d,0x24,0xd1,0xd8,0x44,
0xc5,0x85,0xc4,0x2a,0xd9,0x84,0x25,0x45,
0xb4,0xd0,0xcd,0x9c,0xcd,0xb5,0xb4,0x9c,
0x25,0xd0,0xd9,0x45,0xc4,0x84,0xc5,0x2a,
0xd8,0x85,0x24,0x44,0xb5,0xd1,0xcc,0x9d,
0xcc,0xb4,0xb5,0x9d,0x24,0xd1,0xd8,0x44,
0xc5,0x85,0xc4,0x2a,0xd9,0x84,0x25,0x45,
0xb4,0xd0,0xcd,0x9c,0xcd,0xb5,0xb4,0x9c,
static u8 sample_special2[]= {
0x2a,0xcc,0x8c,0xd7,0x4d,0x2d,0x18,0xbc,
0x10,0xc1,0xbd,0xc1,0x10,0xbc,0x18,0x2d,
0x4d,0xd7,0x8c,0xcc,0x2a,0xcd,0x8d,0xd6,
0x4c,0x2c,0x19,0xbd,0x11,0xc0,0xbc,0xc0,
0x11,0xbd,0x19,0x2c,0x4c,0xd6,0x8d,0xcd,
0x2a,0xcc,0x8c,0xd7,0x4d,0x2d,0x18,0xbc,
0x10,0xc1,0xbd,0xc1,0x10,0xbc,0x18,0x2d,
0x4d,0xd7,0x8c,0xcc,0x2a,0xcd,0x8d,0xd6,
0x4c,0x2c,0x19,0xbd,0x11,0xc0,0xbc,0xc0,
0x11,0xbd,0x19,0x2c,0x4c,0xd6,0x8d,0xcd,
};
static unsigned long sizeof_special2 = sizeof(sample_special2);
static u32 sizeof_special2 = sizeof(sample_special2);
static unsigned char sample_special3[]= {
0xd9,0x44,0xd9,0xb5,0xcc,0x44,0x25,0x85,
0xc4,0x9c,0xb5,0xd1,0xb4,0x2a,0xc5,0xd0,
0x24,0x9d,0xcd,0x84,0xd8,0x45,0xd8,0xb4,
0xcd,0x45,0x24,0x84,0xc5,0x9d,0xb4,0xd0,
0xb5,0x2b,0xc4,0xd1,0x25,0x9c,0xcc,0x85,
0xd9,0x44,0xd9,0xb5,0xcc,0x44,0x25,0x85,
0xc4,0x9c,0xb5,0xd1,0xb4,0x2a,0xc5,0xd0,
0x24,0x9d,0xcd,0x84,0xd8,0x45,0xd8,0xb4,
0xcd,0x45,0x24,0x84,0xc5,0x9d,0xb4,0xd0,
0xb5,0x2b,0xc4,0xd1,0x25,0x9c,0xcc,0x85,
0xd9,0x44,0xd9,0xb5,0xcc,0x44,0x25,0x85,
0xc4,0x9c,0xb5,0xd1,0xb4,0x2a,0xc5,0xd0,
0x24,0x9d,0xcd,0x84,0xd8,0x45,0xd8,0xb4,
0xcd,0x45,0x24,0x84,0xc5,0x9d,0xb4,0xd0,
0xb5,0x2b,0xc4,0xd1,0x25,0x9c,0xcc,0x85,
0xd9,0x44,0xd9,0xb5,0xcc,0x44,0x25,0x85,
0xc4,0x9c,0xb5,0xd1,0xb4,0x2a,0xc5,0xd0,
0x24,0x9d,0xcd,0x84,0xd8,0x45,0xd8,0xb4,
0xcd,0x45,0x24,0x84,0xc5,0x9d,0xb4,0xd0,
0xb5,0x2b,0xc4,0xd1,0x25,0x9c,0xcc,0x85,
0xd9,0x44,0xd9,0xb5,0xcc,0x44,0x25,0x85,
0xc4,0x9c,0xb5,0xd1,0xb4,0x2a,0xc5,0xd0,
0x24,0x9d,0xcd,0x84,0xd8,0x45,0xd8,0xb4,
0xcd,0x45,0x24,0x84,0xc5,0x9d,0xb4,0xd0,
0xb5,0x2b,0xc4,0xd1,0x25,0x9c,0xcc,0x85,
0xd9,0x44,0xd9,0xb5,0xcc,0x44,0x25,0x85,
0xc4,0x9c,0xb5,0xd1,0xb4,0x2a,0xc5,0xd0,
0x24,0x9d,0xcd,0x84,0xd8,0x45,0xd8,0xb4,
0xcd,0x45,0x24,0x84,0xc5,0x9d,0xb4,0xd0,
0xb5,0x2b,0xc4,0xd1,0x25,0x9c,0xcc,0x85,
0xd9,0x44,0xd9,0xb5,0xcc,0x44,0x25,0x85,
0xc4,0x9c,0xb5,0xd1,0xb4,0x2a,0xc5,0xd0,
0x24,0x9d,0xcd,0x84,0xd8,0x45,0xd8,0xb4,
0xcd,0x45,0x24,0x84,0xc5,0x9d,0xb4,0xd0,
0xb5,0x2b,0xc4,0xd1,0x25,0x9c,0xcc,0x85,
static u8 sample_special3[]= {
0x2a,0xbc,0x18,0xcd,0x11,0x2c,0x8c,0xc1,
0x4d,0xd6,0xbc,0xd6,0x4d,0xc1,0x8c,0x2c,
0x11,0xcd,0x18,0xbc,0x2a,0xbd,0x19,0xcc,
0x10,0x2d,0x8d,0xc0,0x4c,0xd7,0xbd,0xd7,
0x4c,0xc0,0x8d,0x2d,0x10,0xcc,0x19,0xbd,
0x2a,0xbc,0x18,0xcd,0x11,0x2c,0x8c,0xc1,
0x4d,0xd6,0xbc,0xd6,0x4d,0xc1,0x8c,0x2c,
0x11,0xcd,0x18,0xbc,0x2a,0xbd,0x19,0xcc,
0x10,0x2d,0x8d,0xc0,0x4c,0xd7,0xbd,0xd7,
0x4c,0xc0,0x8d,0x2d,0x10,0xcc,0x19,0xbd,
};
static unsigned long sizeof_special3 = sizeof(sample_special3);
static u32 sizeof_special3 = sizeof(sample_special3);
static unsigned char sample_silence[]= {
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
static u8 sample_silence[]= {
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
@ -423,11 +186,11 @@ static unsigned char sample_silence[]= {
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
};
static unsigned long sizeof_silence = sizeof(sample_silence);
static u32 sizeof_silence = sizeof(sample_silence);
struct tones_samples {
unsigned long *len;
unsigned char *data;
u32 *len;
u8 *data;
};
static struct
tones_samples samples[] = {
@ -470,9 +233,9 @@ dsp_audio_generate_ulaw_samples(void)
struct pattern {
int tone;
unsigned char *data[10];
unsigned long *siz[10];
unsigned long seq[10];
u8 *data[10];
u32 *siz[10];
u32 seq[10];
} pattern[] = {
{TONE_GERMAN_DIALTONE,
{DATA_GA,0,0,0,0,0,0,0,0,0},
@ -492,12 +255,12 @@ struct pattern {
{TONE_GERMAN_DIALPBX,
{DATA_GA,DATA_S,DATA_GA,DATA_S,DATA_GA,DATA_S,0,0,0,0},
{SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,0,0,0,0},
{1995,2005,1995,2005,1995,12005,0,0,0,0}},
{2000,2000,2000,2000,2000,12000,0,0,0,0}},
{TONE_GERMAN_OLDDIALPBX,
{DATA_GO,DATA_S,DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0},
{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0},
{1998,2002,1998,2002,1998,12002,0,0,0,0}},
{2000,2000,2000,2000,2000,12000,0,0,0,0}},
{TONE_AMERICAN_DIALPBX,
{DATA_DT,DATA_S,DATA_DT,DATA_S,DATA_DT,DATA_S,0,0,0,0},
@ -507,12 +270,12 @@ struct pattern {
{TONE_GERMAN_RINGING,
{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
{7999,32001,0,0,0,0,0,0,0,0}},
{8000,32000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_OLDRINGING,
{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
{7992,40008,0,0,0,0,0,0,0,0}},
{8000,40000,0,0,0,0,0,0,0,0}},
{TONE_AMERICAN_RINGING,
{DATA_RI,DATA_S,0,0,0,0,0,0,0,0},
@ -522,12 +285,12 @@ struct pattern {
{TONE_GERMAN_RINGPBX,
{DATA_GA,DATA_S,DATA_GA,DATA_S,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,SIZE_GA,SIZE_S,0,0,0,0,0,0},
{3990,4010,3990,28010,0,0,0,0,0,0}},
{4000,4000,4000,28000,0,0,0,0,0,0}},
{TONE_GERMAN_OLDRINGPBX,
{DATA_GO,DATA_S,DATA_GA,DATA_S,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,SIZE_GA,SIZE_S,0,0,0,0,0,0},
{3996,4040,3996,28004,0,0,0,0,0,0}},
{DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0,0,0},
{4000,4000,4000,28000,0,0,0,0,0,0}},
{TONE_AMERICAN_RINGPBX,
{DATA_RI,DATA_S,DATA_RI,DATA_S,0,0,0,0,0,0},
@ -537,12 +300,12 @@ struct pattern {
{TONE_GERMAN_BUSY,
{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
{3990,4010,0,0,0,0,0,0,0,0}},
{4000,4000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_OLDBUSY,
{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
{999,5001,0,0,0,0,0,0,0,0}},
{1000,5000,0,0,0,0,0,0,0,0}},
{TONE_AMERICAN_BUSY,
{DATA_BU,DATA_S,0,0,0,0,0,0,0,0},
@ -552,12 +315,12 @@ struct pattern {
{TONE_GERMAN_HANGUP,
{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
{3990,4010,0,0,0,0,0,0,0,0}},
{4000,4000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_OLDHANGUP,
{DATA_GO,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,0,0,0,0,0,0,0,0},
{999,3001,0,0,0,0,0,0,0,0}},
{1000,5000,0,0,0,0,0,0,0,0}},
{TONE_AMERICAN_HANGUP,
{DATA_DT,0,0,0,0,0,0,0,0,0},
@ -572,12 +335,12 @@ struct pattern {
{TONE_GERMAN_GASSENBESETZT,
{DATA_GA,DATA_S,0,0,0,0,0,0,0,0},
{SIZE_GA,SIZE_S,0,0,0,0,0,0,0,0},
{1995,2005,0,0,0,0,0,0,0,0}},
{2000,2000,0,0,0,0,0,0,0,0}},
{TONE_GERMAN_AUFSCHALTTON,
{DATA_GO,DATA_S,DATA_GO,DATA_S,0,0,0,0,0,0},
{SIZE_GO,SIZE_S,SIZE_GO,SIZE_S,0,0,0,0,0,0},
{999,3001,999,11001,0,0,0,0,0,0}},
{1000,5000,1000,17000,0,0,0,0,0,0}},
{0,
{0,0,0,0,0,0,0,0,0,0},
@ -602,10 +365,9 @@ struct pattern {
*
* if tones has finished (e.g. knocking tone), dsp->tones is turned off
*/
void dsp_tone_copy(dsp_t *dsp, unsigned char *data, int len)
void dsp_tone_copy(dsp_t *dsp, u8 *data, int len)
{
unsigned char *s;
int index, count, rest, start, num;
int index, count, start, num;
struct pattern *pat;
tone_t *tone = &dsp->tone;
@ -633,19 +395,22 @@ void dsp_tone_copy(dsp_t *dsp, unsigned char *data, int len)
if (count < pat->seq[index]) {
break;
}
if (dsp->debug & DEBUG_DSP_TONE)
if (dsp_debug & DEBUG_DSP_TONE)
printk(KERN_DEBUG "%s: reaching next sequence (index=%d)\n", __FUNCTION__, index);
count -= pat->seq[index];
index++;
}
/* calculate start and number of samples */
start = count % (*pat->siz[index]);
s = pat->data[index] + start;
rest = pat->seq[index] - start;
num = (rest>len)?len:rest;
start = count % (*(pat->siz[index]));
num = len;
if (num+count > pat->seq[index])
num = pat->seq[index] - count;
if (num+start > (*(pat->siz[index])))
num = (*(pat->siz[index])) - start;
/* copy memory */
memcpy(data, s, num);
memcpy(data, pat->data[index]+start, num);
/* reduce length */
data += num;
count += num;
len -= num;
}
@ -657,6 +422,54 @@ void dsp_tone_copy(dsp_t *dsp, unsigned char *data, int len)
}
/*******************************
* send HW message to hfc card *
*******************************/
static void
dsp_tone_hw_message(dsp_t *dsp, u8 *sample, int len)
{
struct sk_buff *nskb;
nskb = create_link_skb(PH_CONTROL | REQUEST, (len)?HW_SPL_LOOP_ON:HW_SPL_LOOP_OFF, len, sample, 0);
if (!nskb) {
printk(KERN_ERR "%s: No mem for skb.\n", __FUNCTION__);
return;
}
/* unlocking is not required, because we don't expect a response */
if (dsp->inst.down.func(&dsp->inst.down, nskb))
dev_kfree_skb(nskb);
}
/*****************
* timer expires *
*****************/
void
dsp_tone_timeout(void *arg)
{
dsp_t *dsp = arg;
tone_t *tone = &dsp->tone;
struct pattern *pat = (struct pattern *)tone->pattern;
int index = tone->index;
if (!tone->tone)
return;
index++;
if (!pat->seq[index])
index = 0;
tone->index = index;
/* set next tone */
dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index]));
/* set timer */
init_timer(&tone->tl);
tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000;
add_timer(&tone->tl);
}
/********************
* set/release tone *
********************/
@ -673,12 +486,16 @@ dsp_tone(dsp_t *dsp, int tone)
int i;
tone_t *tonet = &dsp->tone;
tonet->software = 0;
tonet->hardware = 0;
/* we turn off the tone */
if (!tone) {
#ifdef WITH_HARDWARE
muessen wir noch die hardwareloop rausnehmen?: oder macht das der cmx ?:
wenn ja, dann muessen wir auch beim tone an/aus den cmx aufrufen (PH_CONTROL)
#endif
if (dsp->hfc_loops)
if (timer_pending(&tonet->tl))
del_timer(&tonet->tl);
if (dsp->hfc_loops)
dsp_tone_hw_message(dsp, NULL, 0);
tonet->tone = 0;
return(0);
}
@ -696,22 +513,27 @@ muessen wir noch die hardwareloop rausnehmen?: oder macht das der cmx ?:
printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n", tone);
return(-EINVAL);
}
if (dsp->debug & DEBUG_DSP_TONE)
if (dsp_debug & DEBUG_DSP_TONE)
printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n", __FUNCTION__, tone, 0);
tonet->tone = tone;
tonet->pattern = pat;
tonet->index = 0;
tonet->count = 0;
#ifdef WITH_HARDWARE
/* first check if we can do it with hardware */
if (.............) {
/* we have hardware support, so we set our pattern */
return(0);
if (dsp->hfc_loops) {
tonet->hardware = 1;
/* set first tone */
dsp_tone_hw_message(dsp, pat->data[0], *(pat->siz[0]));
/* set timer */
if (timer_pending(&tonet->tl))
del_timer(&tonet->tl);
init_timer(&tonet->tl);
tonet->tl.expires = jiffies + (pat->seq[0] * HZ) / 8000;
add_timer(&tonet->tl);
} else {
tonet->software = 1;
}
#endif
return(0);
}

File diff suppressed because it is too large Load Diff

View File

@ -38,9 +38,12 @@ struct hfc_chan {
int sync; /* sync state (used by E1) */
struct sk_buff *dtmf_skb;
unsigned long protocol; /* current protocol */
int slot; /* current pcm slot */
int dir; /* current pcm direction */
int slot_tx; /* current pcm slot */
int bank_tx; /* current pcm bank */
int slot_rx;
int bank_rx;
int conf; /* conference setting of TX slot */
int txpending; /* if there is currently data in the FIFO 0=no, 1=yes, 2=splloop */
};
typedef struct hfc_chan hfc_chan_t;
@ -1074,6 +1077,14 @@ struct hfc_register_names {
#define HFC_outl(a,b,c) (*((volatile u_long *)((a->pci_io)+b)) = c)
#define HFC_inl(a,b) (*((volatile u_long *)((a->pci_io)+b)))
/* no debug */
#define HFC_outl_(a,b,c) (*((volatile u_long *)((a->pci_io)+b)) = c)
#define HFC_inl_(a,b) (*((volatile u_long *)((a->pci_io)+b)))
#define HFC_inw_(a,b) (*((volatile u_short *)((a->pci_io)+b)))
#define HFC_outb_(a,b,c) (*((volatile u_char *)((a->pci_io)+b)) = c)
#define HFC_inb_(a,b) (*((volatile u_char *)((a->pci_io)+b)))
#define HFC_wait_(a) while((*((volatile u_char *)((a->pci_io)+R_STATUS))) & V_BUSY)
/* macros */
#ifndef HFC_REGISTER_MAP
@ -1140,7 +1151,7 @@ static unsigned char _HFC_inb(hfc_multi_t *a, unsigned char b, char *function, i
printk(KERN_DEBUG "HFC_inb(\"%s\", %02x=%s) = 0x%02x=%s; in %s() line %d\n", a->name, b, regname, c, bits, function, line);
return(c);
}
#define HFC_inb(a,b) _HFC_inw(a, b, __FUNCTION__, __LINE__)
#define HFC_inw(a,b) _HFC_inw(a, b, __FUNCTION__, __LINE__)
static unsigned short _HFC_inw(hfc_multi_t *a, unsigned char b, char *function, int line)
{
char regname[256]="";
@ -1169,3 +1180,5 @@ static void _HFC_wait(hfc_multi_t *a, char *function, int line)
#endif /* HFC_REGISTER_MAP */

View File

@ -120,10 +120,10 @@
#define HW_PCM_DISC 0x0581
#define HW_CONF_JOIN 0x0582
#define HW_CONF_SPLIT 0x0583
#define HW_ECHO_ON 0x0584
#define HW_ECHO_OFF 0x0585
#define HW_RECEIVE_OFF 0x0586
#define HW_RECEIVE_ON 0x0587
#define HW_RECEIVE_OFF 0x0584
#define HW_RECEIVE_ON 0x0585
#define HW_SPL_LOOP_ON 0x0586
#define HW_SPL_LOOP_OFF 0x0587
#define HW_TESTLOOP 0xFF00
#define HW_FIRM_START 0xFF10
#define HW_FIRM_DATA 0xFF11