cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dsp_dtmf.c (7905B)


      1/*
      2 * DTMF decoder.
      3 *
      4 * Copyright            by Andreas Eversberg (jolly@eversberg.eu)
      5 *			based on different decoders such as ISDN4Linux
      6 *
      7 * This software may be used and distributed according to the terms
      8 * of the GNU General Public License, incorporated herein by reference.
      9 *
     10 */
     11
     12#include <linux/mISDNif.h>
     13#include <linux/mISDNdsp.h>
     14#include "core.h"
     15#include "dsp.h"
     16
     17#define NCOEFF            8     /* number of frequencies to be analyzed */
     18
     19/* For DTMF recognition:
     20 * 2 * cos(2 * PI * k / N) precalculated for all k
     21 */
     22static u64 cos2pik[NCOEFF] =
     23{
     24	/* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */
     25	55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630
     26};
     27
     28/* digit matrix */
     29static char dtmf_matrix[4][4] =
     30{
     31	{'1', '2', '3', 'A'},
     32	{'4', '5', '6', 'B'},
     33	{'7', '8', '9', 'C'},
     34	{'*', '0', '#', 'D'}
     35};
     36
     37/* dtmf detection using goertzel algorithm
     38 * init function
     39 */
     40void dsp_dtmf_goertzel_init(struct dsp *dsp)
     41{
     42	dsp->dtmf.size = 0;
     43	dsp->dtmf.lastwhat = '\0';
     44	dsp->dtmf.lastdigit = '\0';
     45	dsp->dtmf.count = 0;
     46}
     47
     48/* check for hardware or software features
     49 */
     50void dsp_dtmf_hardware(struct dsp *dsp)
     51{
     52	int hardware = 1;
     53
     54	if (!dsp->dtmf.enable)
     55		return;
     56
     57	if (!dsp->features.hfc_dtmf)
     58		hardware = 0;
     59
     60	/* check for volume change */
     61	if (dsp->tx_volume) {
     62		if (dsp_debug & DEBUG_DSP_DTMF)
     63			printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
     64			       "because tx_volume is changed\n",
     65			       __func__, dsp->name);
     66		hardware = 0;
     67	}
     68	if (dsp->rx_volume) {
     69		if (dsp_debug & DEBUG_DSP_DTMF)
     70			printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
     71			       "because rx_volume is changed\n",
     72			       __func__, dsp->name);
     73		hardware = 0;
     74	}
     75	/* check if encryption is enabled */
     76	if (dsp->bf_enable) {
     77		if (dsp_debug & DEBUG_DSP_DTMF)
     78			printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
     79			       "because encryption is enabled\n",
     80			       __func__, dsp->name);
     81		hardware = 0;
     82	}
     83	/* check if pipeline exists */
     84	if (dsp->pipeline.inuse) {
     85		if (dsp_debug & DEBUG_DSP_DTMF)
     86			printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, "
     87			       "because pipeline exists.\n",
     88			       __func__, dsp->name);
     89		hardware = 0;
     90	}
     91
     92	dsp->dtmf.hardware = hardware;
     93	dsp->dtmf.software = !hardware;
     94}
     95
     96
     97/*************************************************************
     98 * calculate the coefficients of the given sample and decode *
     99 *************************************************************/
    100
    101/* the given sample is decoded. if the sample is not long enough for a
    102 * complete frame, the decoding is finished and continued with the next
    103 * call of this function.
    104 *
    105 * the algorithm is very good for detection with a minimum of errors. i
    106 * tested it allot. it even works with very short tones (40ms). the only
    107 * disadvantage is, that it doesn't work good with different volumes of both
    108 * tones. this will happen, if accoustically coupled dialers are used.
    109 * it sometimes detects tones during speech, which is normal for decoders.
    110 * use sequences to given commands during calls.
    111 *
    112 * dtmf - points to a structure of the current dtmf state
    113 * spl and len - the sample
    114 * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder
    115 */
    116
    117u8
    118*dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt)
    119{
    120	u8 what;
    121	int size;
    122	signed short *buf;
    123	s32 sk, sk1, sk2;
    124	int k, n, i;
    125	s32 *hfccoeff;
    126	s32 result[NCOEFF], tresh, treshl;
    127	int lowgroup, highgroup;
    128	s64 cos2pik_;
    129
    130	dsp->dtmf.digits[0] = '\0';
    131
    132	/* Note: The function will loop until the buffer has not enough samples
    133	 * left to decode a full frame.
    134	 */
    135again:
    136	/* convert samples */
    137	size = dsp->dtmf.size;
    138	buf = dsp->dtmf.buffer;
    139	switch (fmt) {
    140	case 0: /* alaw */
    141	case 1: /* ulaw */
    142		while (size < DSP_DTMF_NPOINTS && len) {
    143			buf[size++] = dsp_audio_law_to_s32[*data++];
    144			len--;
    145		}
    146		break;
    147
    148	case 2: /* HFC coefficients */
    149	default:
    150		if (len < 64) {
    151			if (len > 0)
    152				printk(KERN_ERR "%s: coefficients have invalid "
    153				       "size. (is=%d < must=%d)\n",
    154				       __func__, len, 64);
    155			return dsp->dtmf.digits;
    156		}
    157		hfccoeff = (s32 *)data;
    158		for (k = 0; k < NCOEFF; k++) {
    159			sk2 = (*hfccoeff++) >> 4;
    160			sk = (*hfccoeff++) >> 4;
    161			if (sk > 32767 || sk < -32767 || sk2 > 32767
    162			    || sk2 < -32767)
    163				printk(KERN_WARNING
    164				       "DTMF-Detection overflow\n");
    165			/* compute |X(k)|**2 */
    166			result[k] =
    167				(sk * sk) -
    168				(((cos2pik[k] * sk) >> 15) * sk2) +
    169				(sk2 * sk2);
    170		}
    171		data += 64;
    172		len -= 64;
    173		goto coefficients;
    174		break;
    175	}
    176	dsp->dtmf.size = size;
    177
    178	if (size < DSP_DTMF_NPOINTS)
    179		return dsp->dtmf.digits;
    180
    181	dsp->dtmf.size = 0;
    182
    183	/* now we have a full buffer of signed long samples - we do goertzel */
    184	for (k = 0; k < NCOEFF; k++) {
    185		sk = 0;
    186		sk1 = 0;
    187		sk2 = 0;
    188		buf = dsp->dtmf.buffer;
    189		cos2pik_ = cos2pik[k];
    190		for (n = 0; n < DSP_DTMF_NPOINTS; n++) {
    191			sk = ((cos2pik_ * sk1) >> 15) - sk2 + (*buf++);
    192			sk2 = sk1;
    193			sk1 = sk;
    194		}
    195		sk >>= 8;
    196		sk2 >>= 8;
    197		if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767)
    198			printk(KERN_WARNING "DTMF-Detection overflow\n");
    199		/* compute |X(k)|**2 */
    200		result[k] =
    201			(sk * sk) -
    202			(((cos2pik[k] * sk) >> 15) * sk2) +
    203			(sk2 * sk2);
    204	}
    205
    206	/* our (squared) coefficients have been calculated, we need to process
    207	 * them.
    208	 */
    209coefficients:
    210	tresh = 0;
    211	for (i = 0; i < NCOEFF; i++) {
    212		if (result[i] < 0)
    213			result[i] = 0;
    214		if (result[i] > dsp->dtmf.treshold) {
    215			if (result[i] > tresh)
    216				tresh = result[i];
    217		}
    218	}
    219
    220	if (tresh == 0) {
    221		what = 0;
    222		goto storedigit;
    223	}
    224
    225	if (dsp_debug & DEBUG_DSP_DTMFCOEFF) {
    226		s32 tresh_100 = tresh/100;
    227
    228		if (tresh_100 == 0) {
    229			tresh_100 = 1;
    230			printk(KERN_DEBUG
    231				"tresh(%d) too small set tresh/100 to 1\n",
    232				tresh);
    233		}
    234		printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d"
    235		       " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n",
    236		       result[0] / 10000, result[1] / 10000, result[2] / 10000,
    237		       result[3] / 10000, result[4] / 10000, result[5] / 10000,
    238		       result[6] / 10000, result[7] / 10000, tresh / 10000,
    239		       result[0] / (tresh_100), result[1] / (tresh_100),
    240		       result[2] / (tresh_100), result[3] / (tresh_100),
    241		       result[4] / (tresh_100), result[5] / (tresh_100),
    242		       result[6] / (tresh_100), result[7] / (tresh_100));
    243	}
    244
    245	/* calc digit (lowgroup/highgroup) */
    246	lowgroup = -1;
    247	highgroup = -1;
    248	treshl = tresh >> 3;  /* tones which are not on, must be below 9 dB */
    249	tresh = tresh >> 2;  /* touchtones must match within 6 dB */
    250	for (i = 0; i < NCOEFF; i++) {
    251		if (result[i] < treshl)
    252			continue;  /* ignore */
    253		if (result[i] < tresh) {
    254			lowgroup = -1;
    255			highgroup = -1;
    256			break;  /* noise in between */
    257		}
    258		/* good level found. This is allowed only one time per group */
    259		if (i < NCOEFF / 2) {
    260			/* lowgroup */
    261			if (lowgroup >= 0) {
    262				/* Bad. Another tone found. */
    263				lowgroup = -1;
    264				break;
    265			} else
    266				lowgroup = i;
    267		} else {
    268			/* higroup */
    269			if (highgroup >= 0) {
    270				/* Bad. Another tone found. */
    271				highgroup = -1;
    272				break;
    273			} else
    274				highgroup = i - (NCOEFF / 2);
    275		}
    276	}
    277
    278	/* get digit or null */
    279	what = 0;
    280	if (lowgroup >= 0 && highgroup >= 0)
    281		what = dtmf_matrix[lowgroup][highgroup];
    282
    283storedigit:
    284	if (what && (dsp_debug & DEBUG_DSP_DTMF))
    285		printk(KERN_DEBUG "DTMF what: %c\n", what);
    286
    287	if (dsp->dtmf.lastwhat != what)
    288		dsp->dtmf.count = 0;
    289
    290	/* the tone (or no tone) must remain 3 times without change */
    291	if (dsp->dtmf.count == 2) {
    292		if (dsp->dtmf.lastdigit != what) {
    293			dsp->dtmf.lastdigit = what;
    294			if (what) {
    295				if (dsp_debug & DEBUG_DSP_DTMF)
    296					printk(KERN_DEBUG "DTMF digit: %c\n",
    297					       what);
    298				if ((strlen(dsp->dtmf.digits) + 1)
    299				    < sizeof(dsp->dtmf.digits)) {
    300					dsp->dtmf.digits[strlen(
    301							dsp->dtmf.digits) + 1] = '\0';
    302					dsp->dtmf.digits[strlen(
    303							dsp->dtmf.digits)] = what;
    304				}
    305			}
    306		}
    307	} else
    308		dsp->dtmf.count++;
    309
    310	dsp->dtmf.lastwhat = what;
    311
    312	goto again;
    313}