/*
* Audio support data for ISDN4Linux .
*
* Copyright Andreas Eversberg ( jolly @ eversberg . eu )
*
* This software may be used and distributed according to the terms
* of the GNU General Public License , incorporated herein by reference .
*
*/
#include <linux/gfp.h>
#include <linux/mISDNif.h>
#include <linux/mISDNdsp.h>
#include "core.h"
#include "dsp.h"
#define DATA_S sample_silence
#define SIZE_S (&sizeof_silence)
#define DATA_GA sample_german_all
#define SIZE_GA (&sizeof_german_all)
#define DATA_GO sample_german_old
#define SIZE_GO (&sizeof_german_old)
#define DATA_DT sample_american_dialtone
#define SIZE_DT (&sizeof_american_dialtone)
#define DATA_RI sample_american_ringing
#define SIZE_RI (&sizeof_american_ringing)
#define DATA_BU sample_american_busy
#define SIZE_BU (&sizeof_american_busy)
#define DATA_S1 sample_special1
#define SIZE_S1 (&sizeof_special1)
#define DATA_S2 sample_special2
#define SIZE_S2 (&sizeof_special2)
#define DATA_S3 sample_special3
#define SIZE_S3 (&sizeof_special3)
/***************/
/* tones loops */
/***************/
/* all tones are alaw encoded */
/* the last sample+1 is in phase with the first sample. the error is low */
static u8 sample_german_all[] = {
0 x80, 0 xab, 0 x81, 0 x6d, 0 xfd, 0 xdd, 0 x5d, 0 x9d,
0 x4d, 0 xd1, 0 x89, 0 x88, 0 xd0, 0 x4c, 0 x9c, 0 x5c,
0 xdc, 0 xfc, 0 x6c,
0 x80, 0 xab, 0 x81, 0 x6d, 0 xfd, 0 xdd, 0 x5d, 0 x9d,
0 x4d, 0 xd1, 0 x89, 0 x88, 0 xd0, 0 x4c, 0 x9c, 0 x5c,
0 xdc, 0 xfc, 0 x6c,
0 x80, 0 xab, 0 x81, 0 x6d, 0 xfd, 0 xdd, 0 x5d, 0 x9d,
0 x4d, 0 xd1, 0 x89, 0 x88, 0 xd0, 0 x4c, 0 x9c, 0 x5c,
0 xdc, 0 xfc, 0 x6c,
0 x80, 0 xab, 0 x81, 0 x6d, 0 xfd, 0 xdd, 0 x5d, 0 x9d,
0 x4d, 0 xd1, 0 x89, 0 x88, 0 xd0, 0 x4c, 0 x9c, 0 x5c,
0 xdc, 0 xfc, 0 x6c,
};
static u32 sizeof_german_all = sizeof (sample_german_all);
static u8 sample_german_old[] = {
0 xec, 0 x68, 0 xe1, 0 x6d, 0 x6d, 0 x91, 0 x51, 0 xed,
0 x6d, 0 x01, 0 x1e, 0 x10, 0 x0c, 0 x90, 0 x60, 0 x70,
0 x8c,
0 xec, 0 x68, 0 xe1, 0 x6d, 0 x6d, 0 x91, 0 x51, 0 xed,
0 x6d, 0 x01, 0 x1e, 0 x10, 0 x0c, 0 x90, 0 x60, 0 x70,
0 x8c,
0 xec, 0 x68, 0 xe1, 0 x6d, 0 x6d, 0 x91, 0 x51, 0 xed,
0 x6d, 0 x01, 0 x1e, 0 x10, 0 x0c, 0 x90, 0 x60, 0 x70,
0 x8c,
0 xec, 0 x68, 0 xe1, 0 x6d, 0 x6d, 0 x91, 0 x51, 0 xed,
0 x6d, 0 x01, 0 x1e, 0 x10, 0 x0c, 0 x90, 0 x60, 0 x70,
0 x8c,
};
static u32 sizeof_german_old = sizeof (sample_german_old);
static u8 sample_american_dialtone[] = {
0 x2a, 0 x18, 0 x90, 0 x6c, 0 x4c, 0 xbc, 0 x4c, 0 x6c,
0 x10, 0 x58, 0 x32, 0 xb9, 0 x31, 0 x2d, 0 x8d, 0 x0d,
0 x8d, 0 x2d, 0 x31, 0 x99, 0 x0f, 0 x28, 0 x60, 0 xf0,
0 xd0, 0 x50, 0 xd0, 0 x30, 0 x60, 0 x08, 0 x8e, 0 x67,
0 x09, 0 x19, 0 x21, 0 xe1, 0 xd9, 0 xb9, 0 x29, 0 x67,
0 x83, 0 x02, 0 xce, 0 xbe, 0 xee, 0 x1a, 0 x1b, 0 xef,
0 xbf, 0 xcf, 0 x03, 0 x82, 0 x66, 0 x28, 0 xb8, 0 xd8,
0 xe0, 0 x20, 0 x18, 0 x08, 0 x66, 0 x8f, 0 x09, 0 x61,
0 x31, 0 xd1, 0 x51, 0 xd1, 0 xf1, 0 x61, 0 x29, 0 x0e,
0 x98, 0 x30, 0 x2c, 0 x8c, 0 x0c, 0 x8c, 0 x2c, 0 x30,
0 xb8, 0 x33, 0 x59, 0 x11, 0 x6d, 0 x4d, 0 xbd, 0 x4d,
0 x6d, 0 x91, 0 x19,
};
static u32 sizeof_american_dialtone = sizeof (sample_american_dialtone);
static u8 sample_american_ringing[] = {
0 x2a, 0 xe0, 0 xac, 0 x0c, 0 xbc, 0 x4c, 0 x8c, 0 x90,
0 x48, 0 xc7, 0 xc1, 0 xed, 0 xcd, 0 x4d, 0 xcd, 0 xed,
0 xc1, 0 xb7, 0 x08, 0 x30, 0 xec, 0 xcc, 0 xcc, 0 x8c,
0 x10, 0 x58, 0 x1a, 0 x99, 0 x71, 0 xed, 0 x8d, 0 x8d,
0 x2d, 0 x41, 0 x89, 0 x9e, 0 x20, 0 x70, 0 x2c, 0 xec,
0 x2c, 0 x70, 0 x20, 0 x86, 0 x77, 0 xe1, 0 x31, 0 x11,
0 xd1, 0 xf1, 0 x81, 0 x09, 0 xa3, 0 x56, 0 x58, 0 x00,
0 x40, 0 xc0, 0 x60, 0 x38, 0 x46, 0 x43, 0 x57, 0 x39,
0 xd9, 0 x59, 0 x99, 0 xc9, 0 x77, 0 x2f, 0 x2e, 0 xc6,
0 xd6, 0 x28, 0 xd6, 0 x36, 0 x26, 0 x2e, 0 x8a, 0 xa3,
0 x43, 0 x63, 0 x4b, 0 x4a, 0 x62, 0 x42, 0 xa2, 0 x8b,
0 x2f, 0 x27, 0 x37, 0 xd7, 0 x29, 0 xd7, 0 xc7, 0 x2f,
0 x2e, 0 x76, 0 xc8, 0 x98, 0 x58, 0 xd8, 0 x38, 0 x56,
0 x42, 0 x47, 0 x39, 0 x61, 0 xc1, 0 x41, 0 x01, 0 x59,
0 x57, 0 xa2, 0 x08, 0 x80, 0 xf0, 0 xd0, 0 x10, 0 x30,
0 xe0, 0 x76, 0 x87, 0 x21, 0 x71, 0 x2d, 0 xed, 0 x2d,
0 x71, 0 x21, 0 x9f, 0 x88, 0 x40, 0 x2c, 0 x8c, 0 x8c,
0 xec, 0 x70, 0 x98, 0 x1b, 0 x59, 0 x11, 0 x8d, 0 xcd,
0 xcd, 0 xed, 0 x31, 0 x09, 0 xb6, 0 xc0, 0 xec, 0 xcc,
0 x4c, 0 xcc, 0 xec, 0 xc0, 0 xc6, 0 x49, 0 x91, 0 x8d,
0 x4d, 0 xbd, 0 x0d, 0 xad, 0 xe1,
};
static u32 sizeof_american_ringing = sizeof (sample_american_ringing);
static u8 sample_american_busy[] = {
0 x2a, 0 x00, 0 x6c, 0 x4c, 0 x4c, 0 x6c, 0 xb0, 0 x66,
0 x99, 0 x11, 0 x6d, 0 x8d, 0 x2d, 0 x41, 0 xd7, 0 x96,
0 x60, 0 xf0, 0 x70, 0 x40, 0 x58, 0 xf6, 0 x53, 0 x57,
0 x09, 0 x89, 0 xd7, 0 x5f, 0 xe3, 0 x2a, 0 xe3, 0 x5f,
0 xd7, 0 x89, 0 x09, 0 x57, 0 x53, 0 xf6, 0 x58, 0 x40,
0 x70, 0 xf0, 0 x60, 0 x96, 0 xd7, 0 x41, 0 x2d, 0 x8d,
0 x6d, 0 x11, 0 x99, 0 x66, 0 xb0, 0 x6c, 0 x4c, 0 x4c,
0 x6c, 0 x00, 0 x2a, 0 x01, 0 x6d, 0 x4d, 0 x4d, 0 x6d,
0 xb1, 0 x67, 0 x98, 0 x10, 0 x6c, 0 x8c, 0 x2c, 0 x40,
0 xd6, 0 x97, 0 x61, 0 xf1, 0 x71, 0 x41, 0 x59, 0 xf7,
0 x52, 0 x56, 0 x08, 0 x88, 0 xd6, 0 x5e, 0 xe2, 0 x2a,
0 xe2, 0 x5e, 0 xd6, 0 x88, 0 x08, 0 x56, 0 x52, 0 xf7,
0 x59, 0 x41, 0 x71, 0 xf1, 0 x61, 0 x97, 0 xd6, 0 x40,
0 x2c, 0 x8c, 0 x6c, 0 x10, 0 x98, 0 x67, 0 xb1, 0 x6d,
0 x4d, 0 x4d, 0 x6d, 0 x01,
};
static u32 sizeof_american_busy = sizeof (sample_american_busy);
static u8 sample_special1[] = {
0 x2a, 0 x2c, 0 xbc, 0 x6c, 0 xd6, 0 x71, 0 xbd, 0 x0d,
0 xd9, 0 x80, 0 xcc, 0 x4c, 0 x40, 0 x39, 0 x0d, 0 xbd,
0 x11, 0 x86, 0 xec, 0 xbc, 0 xec, 0 x0e, 0 x51, 0 xbd,
0 x8d, 0 x89, 0 x30, 0 x4c, 0 xcc, 0 xe0, 0 xe1, 0 xcd,
0 x4d, 0 x31, 0 x88, 0 x8c, 0 xbc, 0 x50, 0 x0f, 0 xed,
0 xbd, 0 xed, 0 x87, 0 x10, 0 xbc, 0 x0c, 0 x38, 0 x41,
0 x4d, 0 xcd, 0 x81, 0 xd8, 0 x0c, 0 xbc, 0 x70, 0 xd7,
0 x6d, 0 xbd, 0 x2d,
};
static u32 sizeof_special1 = sizeof (sample_special1);
static u8 sample_special2[] = {
0 x2a, 0 xcc, 0 x8c, 0 xd7, 0 x4d, 0 x2d, 0 x18, 0 xbc,
0 x10, 0 xc1, 0 xbd, 0 xc1, 0 x10, 0 xbc, 0 x18, 0 x2d,
0 x4d, 0 xd7, 0 x8c, 0 xcc, 0 x2a, 0 xcd, 0 x8d, 0 xd6,
0 x4c, 0 x2c, 0 x19, 0 xbd, 0 x11, 0 xc0, 0 xbc, 0 xc0,
0 x11, 0 xbd, 0 x19, 0 x2c, 0 x4c, 0 xd6, 0 x8d, 0 xcd,
0 x2a, 0 xcc, 0 x8c, 0 xd7, 0 x4d, 0 x2d, 0 x18, 0 xbc,
0 x10, 0 xc1, 0 xbd, 0 xc1, 0 x10, 0 xbc, 0 x18, 0 x2d,
0 x4d, 0 xd7, 0 x8c, 0 xcc, 0 x2a, 0 xcd, 0 x8d, 0 xd6,
0 x4c, 0 x2c, 0 x19, 0 xbd, 0 x11, 0 xc0, 0 xbc, 0 xc0,
0 x11, 0 xbd, 0 x19, 0 x2c, 0 x4c, 0 xd6, 0 x8d, 0 xcd,
};
static u32 sizeof_special2 = sizeof (sample_special2);
static u8 sample_special3[] = {
0 x2a, 0 xbc, 0 x18, 0 xcd, 0 x11, 0 x2c, 0 x8c, 0 xc1,
0 x4d, 0 xd6, 0 xbc, 0 xd6, 0 x4d, 0 xc1, 0 x8c, 0 x2c,
0 x11, 0 xcd, 0 x18, 0 xbc, 0 x2a, 0 xbd, 0 x19, 0 xcc,
0 x10, 0 x2d, 0 x8d, 0 xc0, 0 x4c, 0 xd7, 0 xbd, 0 xd7,
0 x4c, 0 xc0, 0 x8d, 0 x2d, 0 x10, 0 xcc, 0 x19, 0 xbd,
0 x2a, 0 xbc, 0 x18, 0 xcd, 0 x11, 0 x2c, 0 x8c, 0 xc1,
0 x4d, 0 xd6, 0 xbc, 0 xd6, 0 x4d, 0 xc1, 0 x8c, 0 x2c,
0 x11, 0 xcd, 0 x18, 0 xbc, 0 x2a, 0 xbd, 0 x19, 0 xcc,
0 x10, 0 x2d, 0 x8d, 0 xc0, 0 x4c, 0 xd7, 0 xbd, 0 xd7,
0 x4c, 0 xc0, 0 x8d, 0 x2d, 0 x10, 0 xcc, 0 x19, 0 xbd,
};
static u32 sizeof_special3 = sizeof (sample_special3);
static u8 sample_silence[] = {
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a, 0 x2a,
};
static u32 sizeof_silence = sizeof (sample_silence);
struct tones_samples {
u32 *len;
u8 *data;
};
static struct
tones_samples samples[] = {
{&sizeof_german_all, sample_german_all},
{&sizeof_german_old, sample_german_old},
{&sizeof_american_dialtone, sample_american_dialtone},
{&sizeof_american_ringing, sample_american_ringing},
{&sizeof_american_busy, sample_american_busy},
{&sizeof_special1, sample_special1},
{&sizeof_special2, sample_special2},
{&sizeof_special3, sample_special3},
{NULL, NULL},
};
/***********************************
* generate ulaw from alaw samples *
***********************************/
void
dsp_audio_generate_ulaw_samples(void )
{
int i, j;
i = 0 ;
while (samples[i].len) {
j = 0 ;
while (j < (*samples[i].len)) {
samples[i].data[j] =
dsp_audio_alaw_to_ulaw[samples[i].data[j]];
j++;
}
i++;
}
}
/****************************
* tone sequence definition *
****************************/
static struct pattern {
int tone;
u8 *data[10 ];
u32 *siz[10 ];
u32 seq[10 ];
} pattern[] = {
{TONE_GERMAN_DIALTONE,
{DATA_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{1900 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_OLDDIALTONE,
{DATA_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{1998 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_AMERICAN_DIALTONE,
{DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_DIALPBX,
{DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL,
NULL},
{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL,
NULL},
{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, NULL, NULL, NULL,
NULL},
{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL,
NULL},
{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, NULL, NULL, NULL,
NULL},
{SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL,
NULL},
{2000 , 2000 , 2000 , 2000 , 2000 , 12000 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_RINGING,
{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000 , 32000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_OLDRINGING,
{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000 , 40000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_AMERICAN_RINGING,
{DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000 , 32000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_RINGPBX,
{DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{4000 , 4000 , 4000 , 28000 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_OLDRINGPBX,
{DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{4000 , 4000 , 4000 , 28000 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_AMERICAN_RINGPBX,
{DATA_RI, DATA_S, DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{4000 , 4000 , 4000 , 28000 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_BUSY,
{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{4000 , 4000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_OLDBUSY,
{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{1000 , 5000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_AMERICAN_BUSY,
{DATA_BU, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_BU, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{4000 , 4000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_HANGUP,
{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{4000 , 4000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_OLDHANGUP,
{DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{1000 , 5000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_AMERICAN_HANGUP,
{DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{8000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_SPECIAL_INFO,
{DATA_S1, DATA_S2, DATA_S3, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{2666 , 2666 , 2666 , 8002 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_GASSENBESETZT,
{DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{2000 , 2000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
{TONE_GERMAN_AUFSCHALTTON,
{DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL},
{SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL},
{1000 , 5000 , 1000 , 17000 , 0 , 0 , 0 , 0 , 0 , 0 } },
{0 ,
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
{0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } },
};
/******************
* copy tone data *
******************/
/* an sk_buff is generated from the number of samples needed.
* the count will be changed and may begin from 0 each pattern period .
* the clue is to precalculate the pointers and legths to use only one
* memcpy per function call , or two memcpy if the tone sequence changes .
*
* pattern - the type of the pattern
* count - the sample from the beginning of the pattern ( phase )
* len - the number of bytes
*
* return - the sk_buff with the sample
*
* if tones has finished ( e . g . knocking tone ) , dsp - > tones is turned off
*/
void dsp_tone_copy(struct dsp *dsp, u8 *data, int len)
{
int index, count, start, num;
struct pattern *pat;
struct dsp_tone *tone = &dsp->tone;
/* if we have no tone, we copy silence */
if (!tone->tone) {
memset(data, dsp_silence, len);
return ;
}
/* process pattern */
pat = (struct pattern *)tone->pattern;
/* points to the current pattern */
index = tone->index; /* gives current sequence index */
count = tone->count; /* gives current sample */
/* copy sample */
while (len) {
/* find sample to start with */
while (42 ) {
/* wrap around */
if (!pat->seq[index]) {
count = 0 ;
index = 0 ;
}
/* check if we are currently playing this tone */
if (count < pat->seq[index])
break ;
if (dsp_debug & DEBUG_DSP_TONE)
printk(KERN_DEBUG "%s: reaching next sequence "
"(index=%d)\n" , __func__, index);
count -= pat->seq[index];
index++;
}
/* calculate start and number of samples */
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, pat->data[index] + start, num);
/* reduce length */
data += num;
count += num;
len -= num;
}
tone->index = index;
tone->count = count;
/* return sk_buff */
return ;
}
/*******************************
* send HW message to hfc card *
*******************************/
static void
dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len)
{
struct sk_buff *nskb;
/* unlocking is not required, because we don't expect a response */
nskb = _alloc_mISDN_skb(PH_CONTROL_REQ,
(len) ? HFC_SPL_LOOP_ON : HFC_SPL_LOOP_OFF, len, sample,
GFP_ATOMIC);
if (nskb) {
if (dsp->ch.peer) {
if (dsp->ch.recv(dsp->ch.peer, nskb))
dev_kfree_skb(nskb);
} else
dev_kfree_skb(nskb);
}
}
/*****************
* timer expires *
*****************/
void
dsp_tone_timeout(struct timer_list *t)
{
struct dsp *dsp = timer_container_of(dsp, t, tone.tl);
struct dsp_tone *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 */
if (pat->data[index] == DATA_S)
dsp_tone_hw_message(dsp, NULL, 0 );
else
dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index]));
/* set timer */
tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000 ;
add_timer(&tone->tl);
}
/********************
* set / release tone *
********************/
/*
* tones are relaized by streaming or by special loop commands if supported
* by hardware . when hardware is used , the patterns will be controlled by
* timers .
*/
int
dsp_tone(struct dsp *dsp, int tone)
{
struct pattern *pat;
int i;
struct dsp_tone *tonet = &dsp->tone;
tonet->software = 0 ;
tonet->hardware = 0 ;
/* we turn off the tone */
if (!tone) {
if (dsp->features.hfc_loops && timer_pending(&tonet->tl))
timer_delete(&tonet->tl);
if (dsp->features.hfc_loops)
dsp_tone_hw_message(dsp, NULL, 0 );
tonet->tone = 0 ;
return 0 ;
}
pat = NULL;
i = 0 ;
while (pattern[i].tone) {
if (pattern[i].tone == tone) {
pat = &pattern[i];
break ;
}
i++;
}
if (!pat) {
printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n" , tone);
return -EINVAL;
}
if (dsp_debug & DEBUG_DSP_TONE)
printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n" ,
__func__, tone, 0 );
tonet->tone = tone;
tonet->pattern = pat;
tonet->index = 0 ;
tonet->count = 0 ;
if (dsp->features.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))
timer_delete(&tonet->tl);
tonet->tl.expires = jiffies + (pat->seq[0 ] * HZ) / 8000 ;
add_timer(&tonet->tl);
} else {
tonet->software = 1 ;
}
return 0 ;
}
Messung V0.5 in Prozent C=95 H=90 G=92