557 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			557 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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/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[] = {
 | 
						|
	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 u32 sizeof_german_all = sizeof(sample_german_all);
 | 
						|
 | 
						|
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 u32 sizeof_german_old = sizeof(sample_german_old);
 | 
						|
 | 
						|
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 u32 sizeof_american_dialtone = sizeof(sample_american_dialtone);
 | 
						|
 | 
						|
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 u32 sizeof_american_ringing = sizeof(sample_american_ringing);
 | 
						|
 | 
						|
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 u32 sizeof_american_busy = sizeof(sample_american_busy);
 | 
						|
 | 
						|
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 u32 sizeof_special1 = sizeof(sample_special1);
 | 
						|
 | 
						|
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 u32 sizeof_special2 = sizeof(sample_special2);
 | 
						|
 | 
						|
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 u32 sizeof_special3 = sizeof(sample_special3);
 | 
						|
 | 
						|
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,
 | 
						|
	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 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) {
 | 
						|
			/* warp arround */
 | 
						|
			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(void *arg)
 | 
						|
{
 | 
						|
	struct dsp *dsp = arg;
 | 
						|
	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 */
 | 
						|
	init_timer(&tone->tl);
 | 
						|
	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))
 | 
						|
			del_timer(&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))
 | 
						|
			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;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 |