|  | /* | 
|  | * 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) | 
|  | if (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; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  |