diff options
Diffstat (limited to 'drivers/staging/echo')
-rw-r--r-- | drivers/staging/echo/TODO | 5 | ||||
-rw-r--r-- | drivers/staging/echo/bit_operations.h | 226 | ||||
-rw-r--r-- | drivers/staging/echo/echo.c | 190 | ||||
-rw-r--r-- | drivers/staging/echo/echo.h | 15 | ||||
-rw-r--r-- | drivers/staging/echo/fir.h | 109 | ||||
-rw-r--r-- | drivers/staging/echo/mmx.h | 281 | ||||
-rw-r--r-- | drivers/staging/echo/oslec.h | 70 |
7 files changed, 178 insertions, 718 deletions
diff --git a/drivers/staging/echo/TODO b/drivers/staging/echo/TODO index f6d8580..72a311a 100644 --- a/drivers/staging/echo/TODO +++ b/drivers/staging/echo/TODO @@ -1,8 +1,5 @@ TODO: - - checkpatch.pl cleanups - - handle bit_operations.h (merge in or make part of common code?) - - remove proc interface, only use echo.h interface (proc interface is - racy and not correct.) + - send to lkml for review Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc: Steve Underwood <steveu@coppice.org> and David Rowe <david@rowetel.com> diff --git a/drivers/staging/echo/bit_operations.h b/drivers/staging/echo/bit_operations.h deleted file mode 100644 index 4c4ccbc..0000000 --- a/drivers/staging/echo/bit_operations.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * bit_operations.h - Various bit level operations, such as bit reversal - * - * Written by Steve Underwood <steveu@coppice.org> - * - * Copyright (C) 2006 Steve Underwood - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*! \file */ - -#if !defined(_BIT_OPERATIONS_H_) -#define _BIT_OPERATIONS_H_ - -#if defined(__i386__) || defined(__x86_64__) -/*! \brief Find the bit position of the highest set bit in a word - \param bits The word to be searched - \return The bit number of the highest set bit, or -1 if the word is zero. */ -static inline int top_bit(unsigned int bits) -{ - int res; - - __asm__(" xorl %[res],%[res];\n" - " decl %[res];\n" - " bsrl %[bits],%[res]\n" - :[res] "=&r" (res) - :[bits] "rm"(bits) - ); - return res; -} - -/*! \brief Find the bit position of the lowest set bit in a word - \param bits The word to be searched - \return The bit number of the lowest set bit, or -1 if the word is zero. */ -static inline int bottom_bit(unsigned int bits) -{ - int res; - - __asm__(" xorl %[res],%[res];\n" - " decl %[res];\n" - " bsfl %[bits],%[res]\n" - :[res] "=&r" (res) - :[bits] "rm"(bits) - ); - return res; -} -#else -static inline int top_bit(unsigned int bits) -{ - int i; - - if (bits == 0) - return -1; - i = 0; - if (bits & 0xFFFF0000) { - bits &= 0xFFFF0000; - i += 16; - } - if (bits & 0xFF00FF00) { - bits &= 0xFF00FF00; - i += 8; - } - if (bits & 0xF0F0F0F0) { - bits &= 0xF0F0F0F0; - i += 4; - } - if (bits & 0xCCCCCCCC) { - bits &= 0xCCCCCCCC; - i += 2; - } - if (bits & 0xAAAAAAAA) { - bits &= 0xAAAAAAAA; - i += 1; - } - return i; -} - -static inline int bottom_bit(unsigned int bits) -{ - int i; - - if (bits == 0) - return -1; - i = 32; - if (bits & 0x0000FFFF) { - bits &= 0x0000FFFF; - i -= 16; - } - if (bits & 0x00FF00FF) { - bits &= 0x00FF00FF; - i -= 8; - } - if (bits & 0x0F0F0F0F) { - bits &= 0x0F0F0F0F; - i -= 4; - } - if (bits & 0x33333333) { - bits &= 0x33333333; - i -= 2; - } - if (bits & 0x55555555) { - bits &= 0x55555555; - i -= 1; - } - return i; -} -#endif - -/*! \brief Bit reverse a byte. - \param data The byte to be reversed. - \return The bit reversed version of data. */ -static inline uint8_t bit_reverse8(uint8_t x) -{ -#if defined(__i386__) || defined(__x86_64__) - /* If multiply is fast */ - return ((x * 0x0802U & 0x22110U) | (x * 0x8020U & 0x88440U)) * - 0x10101U >> 16; -#else - /* If multiply is slow, but we have a barrel shifter */ - x = (x >> 4) | (x << 4); - x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2); - return ((x & 0xAA) >> 1) | ((x & 0x55) << 1); -#endif -} - -/*! \brief Bit reverse a 16 bit word. - \param data The word to be reversed. - \return The bit reversed version of data. */ -uint16_t bit_reverse16(uint16_t data); - -/*! \brief Bit reverse a 32 bit word. - \param data The word to be reversed. - \return The bit reversed version of data. */ -uint32_t bit_reverse32(uint32_t data); - -/*! \brief Bit reverse each of the four bytes in a 32 bit word. - \param data The word to be reversed. - \return The bit reversed version of data. */ -uint32_t bit_reverse_4bytes(uint32_t data); - -/*! \brief Find the number of set bits in a 32 bit word. - \param x The word to be searched. - \return The number of set bits. */ -int one_bits32(uint32_t x); - -/*! \brief Create a mask as wide as the number in a 32 bit word. - \param x The word to be searched. - \return The mask. */ -uint32_t make_mask32(uint32_t x); - -/*! \brief Create a mask as wide as the number in a 16 bit word. - \param x The word to be searched. - \return The mask. */ -uint16_t make_mask16(uint16_t x); - -/*! \brief Find the least significant one in a word, and return a word - with just that bit set. - \param x The word to be searched. - \return The word with the single set bit. */ -static inline uint32_t least_significant_one32(uint32_t x) -{ - return x & (-(int32_t) x); -} - -/*! \brief Find the most significant one in a word, and return a word - with just that bit set. - \param x The word to be searched. - \return The word with the single set bit. */ -static inline uint32_t most_significant_one32(uint32_t x) -{ -#if defined(__i386__) || defined(__x86_64__) - return 1 << top_bit(x); -#else - x = make_mask32(x); - return x ^ (x >> 1); -#endif -} - -/*! \brief Find the parity of a byte. - \param x The byte to be checked. - \return 1 for odd, or 0 for even. */ -static inline int parity8(uint8_t x) -{ - x = (x ^ (x >> 4)) & 0x0F; - return (0x6996 >> x) & 1; -} - -/*! \brief Find the parity of a 16 bit word. - \param x The word to be checked. - \return 1 for odd, or 0 for even. */ -static inline int parity16(uint16_t x) -{ - x ^= (x >> 8); - x = (x ^ (x >> 4)) & 0x0F; - return (0x6996 >> x) & 1; -} - -/*! \brief Find the parity of a 32 bit word. - \param x The word to be checked. - \return 1 for odd, or 0 for even. */ -static inline int parity32(uint32_t x) -{ - x ^= (x >> 16); - x ^= (x >> 8); - x = (x ^ (x >> 4)) & 0x0F; - return (0x6996 >> x) & 1; -} - -#endif -/*- End of file ------------------------------------------------------------*/ diff --git a/drivers/staging/echo/echo.c b/drivers/staging/echo/echo.c index 79d15c6..4cc4f2e 100644 --- a/drivers/staging/echo/echo.c +++ b/drivers/staging/echo/echo.c @@ -82,9 +82,9 @@ [2] The classic, very useful paper that tells you how to actually build a real world echo canceller: - Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice - Echo Canceller with a TMS320020, - http://www.rowetel.com/images/echo/spra129.pdf + Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice + Echo Canceller with a TMS320020, + http://www.rowetel.com/images/echo/spra129.pdf [3] I have written a series of blog posts on this work, here is Part 1: http://www.rowetel.com/blog/?p=18 @@ -92,7 +92,7 @@ [4] The source code http://svn.rowetel.com/software/oslec/ [5] A nice reference on LMS filters: - http://en.wikipedia.org/wiki/Least_mean_squares_filter + http://en.wikipedia.org/wiki/Least_mean_squares_filter Credits: @@ -102,21 +102,17 @@ Mark, Pawel, and Pavel. */ -#include <linux/kernel.h> /* We're doing kernel work */ +#include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> -#include "bit_operations.h" #include "echo.h" -#define MIN_TX_POWER_FOR_ADAPTION 64 -#define MIN_RX_POWER_FOR_ADAPTION 64 -#define DTD_HANGOVER 600 /* 600 samples, or 75ms */ -#define DC_LOG2BETA 3 /* log2() of DC filter Beta */ +#define MIN_TX_POWER_FOR_ADAPTION 64 +#define MIN_RX_POWER_FOR_ADAPTION 64 +#define DTD_HANGOVER 600 /* 600 samples, or 75ms */ +#define DC_LOG2BETA 3 /* log2() of DC filter Beta */ -/*-----------------------------------------------------------------------*\ - FUNCTIONS -\*-----------------------------------------------------------------------*/ /* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */ @@ -224,6 +220,14 @@ static inline void lms_adapt_bg(struct oslec_state *ec, int clean, } #endif +static inline int top_bit(unsigned int bits) +{ + if (bits == 0) + return -1; + else + return (int)fls((int32_t)bits)-1; +} + struct oslec_state *oslec_create(int len, int adaption_mode) { struct oslec_state *ec; @@ -328,7 +332,7 @@ void oslec_snapshot(struct oslec_state *ec) } EXPORT_SYMBOL_GPL(oslec_snapshot); -/* Dual Path Echo Canceller ------------------------------------------------*/ +/* Dual Path Echo Canceller */ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) { @@ -336,9 +340,11 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) int clean_bg; int tmp, tmp1; - /* Input scaling was found be required to prevent problems when tx - starts clipping. Another possible way to handle this would be the - filter coefficent scaling. */ + /* + * Input scaling was found be required to prevent problems when tx + * starts clipping. Another possible way to handle this would be the + * filter coefficent scaling. + */ ec->tx = tx; ec->rx = rx; @@ -346,33 +352,40 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) rx >>= 1; /* - Filter DC, 3dB point is 160Hz (I think), note 32 bit precision required - otherwise values do not track down to 0. Zero at DC, Pole at (1-Beta) - only real axis. Some chip sets (like Si labs) don't need - this, but something like a $10 X100P card does. Any DC really slows - down convergence. - - Note: removes some low frequency from the signal, this reduces - the speech quality when listening to samples through headphones - but may not be obvious through a telephone handset. - - Note that the 3dB frequency in radians is approx Beta, e.g. for - Beta = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz. + * Filter DC, 3dB point is 160Hz (I think), note 32 bit precision + * required otherwise values do not track down to 0. Zero at DC, Pole + * at (1-Beta) on real axis. Some chip sets (like Si labs) don't + * need this, but something like a $10 X100P card does. Any DC really + * slows down convergence. + * + * Note: removes some low frequency from the signal, this reduces the + * speech quality when listening to samples through headphones but may + * not be obvious through a telephone handset. + * + * Note that the 3dB frequency in radians is approx Beta, e.g. for Beta + * = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz. */ if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) { tmp = rx << 15; -#if 1 - /* Make sure the gain of the HPF is 1.0. This can still saturate a little under - impulse conditions, and it might roll to 32768 and need clipping on sustained peak - level signals. However, the scale of such clipping is small, and the error due to - any saturation should not markedly affect the downstream processing. */ + + /* + * Make sure the gain of the HPF is 1.0. This can still + * saturate a little under impulse conditions, and it might + * roll to 32768 and need clipping on sustained peak level + * signals. However, the scale of such clipping is small, and + * the error due to any saturation should not markedly affect + * the downstream processing. + */ tmp -= (tmp >> 4); -#endif + ec->rx_1 += -(ec->rx_1 >> DC_LOG2BETA) + tmp - ec->rx_2; - /* hard limit filter to prevent clipping. Note that at this stage - rx should be limited to +/- 16383 due to right shift above */ + /* + * hard limit filter to prevent clipping. Note that at this + * stage rx should be limited to +/- 16383 due to right shift + * above + */ tmp1 = ec->rx_1 >> 15; if (tmp1 > 16383) tmp1 = 16383; @@ -407,7 +420,7 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) ec->Lrxacc += abs(rx) - ec->Lrx; ec->Lrx = (ec->Lrxacc + (1 << 4)) >> 5; - /* Foreground filter --------------------------------------------------- */ + /* Foreground filter */ ec->fir_state.coeffs = ec->fir_taps16[0]; echo_value = fir16(&ec->fir_state, tx); @@ -415,14 +428,14 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) ec->Lcleanacc += abs(ec->clean) - ec->Lclean; ec->Lclean = (ec->Lcleanacc + (1 << 4)) >> 5; - /* Background filter --------------------------------------------------- */ + /* Background filter */ echo_value = fir16(&ec->fir_state_bg, tx); clean_bg = rx - echo_value; ec->Lclean_bgacc += abs(clean_bg) - ec->Lclean_bg; ec->Lclean_bg = (ec->Lclean_bgacc + (1 << 4)) >> 5; - /* Background Filter adaption ----------------------------------------- */ + /* Background Filter adaption */ /* Almost always adap bg filter, just simple DT and energy detection to minimise adaption in cases of strong double talk. @@ -447,14 +460,14 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) therefore the scaled version of (1) is: (2^30) * f = (2^30) * Beta * clean_bg_rx/P - factor = (2^30) * Beta * clean_bg_rx/P ----- (2) + factor = (2^30) * Beta * clean_bg_rx/P ----- (2) We have chosen Beta = 0.25 by experiment, so: - factor = (2^30) * (2^-2) * clean_bg_rx/P + factor = (2^30) * (2^-2) * clean_bg_rx/P - (30 - 2 - log2(P)) - factor = clean_bg_rx 2 ----- (3) + (30 - 2 - log2(P)) + factor = clean_bg_rx 2 ----- (3) To avoid a divide we approximate log2(P) as top_bit(P), which returns the position of the highest non-zero bit in @@ -483,7 +496,7 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) if (ec->nonupdate_dwell) ec->nonupdate_dwell--; - /* Transfer logic ------------------------------------------------------ */ + /* Transfer logic */ /* These conditions are from the dual path paper [1], I messed with them a bit to improve performance. */ @@ -495,7 +508,10 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) /* (ec->Lclean_bg < 0.125*ec->Ltx) */ (8 * ec->Lclean_bg < ec->Ltx)) { if (ec->cond_met == 6) { - /* BG filter has had better results for 6 consecutive samples */ + /* + * BG filter has had better results for 6 consecutive + * samples + */ ec->adapt = 1; memcpy(ec->fir_taps16[0], ec->fir_taps16[1], ec->taps * sizeof(int16_t)); @@ -504,25 +520,34 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) } else ec->cond_met = 0; - /* Non-Linear Processing --------------------------------------------------- */ + /* Non-Linear Processing */ ec->clean_nlp = ec->clean; if (ec->adaption_mode & ECHO_CAN_USE_NLP) { - /* Non-linear processor - a fancy way to say "zap small signals, to avoid - residual echo due to (uLaw/ALaw) non-linearity in the channel.". */ + /* + * Non-linear processor - a fancy way to say "zap small + * signals, to avoid residual echo due to (uLaw/ALaw) + * non-linearity in the channel.". + */ if ((16 * ec->Lclean < ec->Ltx)) { - /* Our e/c has improved echo by at least 24 dB (each factor of 2 is 6dB, - so 2*2*2*2=16 is the same as 6+6+6+6=24dB) */ + /* + * Our e/c has improved echo by at least 24 dB (each + * factor of 2 is 6dB, so 2*2*2*2=16 is the same as + * 6+6+6+6=24dB) + */ if (ec->adaption_mode & ECHO_CAN_USE_CNG) { ec->cng_level = ec->Lbgn; - /* Very elementary comfort noise generation. Just random - numbers rolled off very vaguely Hoth-like. DR: This - noise doesn't sound quite right to me - I suspect there - are some overlfow issues in the filtering as it's too - "crackly". TODO: debug this, maybe just play noise at - high level or look at spectrum. + /* + * Very elementary comfort noise generation. + * Just random numbers rolled off very vaguely + * Hoth-like. DR: This noise doesn't sound + * quite right to me - I suspect there are some + * overlfow issues in the filtering as it's too + * "crackly". + * TODO: debug this, maybe just play noise at + * high level or look at spectrum. */ ec->cng_rndnum = @@ -540,18 +565,22 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) if (ec->clean_nlp < -ec->Lbgn) ec->clean_nlp = -ec->Lbgn; } else { - /* just mute the residual, doesn't sound very good, used mainly - in G168 tests */ + /* + * just mute the residual, doesn't sound very + * good, used mainly in G168 tests + */ ec->clean_nlp = 0; } } else { - /* Background noise estimator. I tried a few algorithms - here without much luck. This very simple one seems to - work best, we just average the level using a slow (1 sec - time const) filter if the current level is less than a - (experimentally derived) constant. This means we dont - include high level signals like near end speech. When - combined with CNG or especially CLIP seems to work OK. + /* + * Background noise estimator. I tried a few + * algorithms here without much luck. This very simple + * one seems to work best, we just average the level + * using a slow (1 sec time const) filter if the + * current level is less than a (experimentally + * derived) constant. This means we dont include high + * level signals like near end speech. When combined + * with CNG or especially CLIP seems to work OK. */ if (ec->Lclean < 40) { ec->Lbgn_acc += abs(ec->clean) - ec->Lbgn; @@ -587,12 +616,13 @@ EXPORT_SYMBOL_GPL(oslec_update); It can also help by removing and DC in the tx signal. DC is bad for LMS algorithms. - This is one of the classic DC removal filters, adjusted to provide sufficient - bass rolloff to meet the above requirement to protect hybrids from things that - upset them. The difference between successive samples produces a lousy HPF, and - then a suitably placed pole flattens things out. The final result is a nicely - rolled off bass end. The filtering is implemented with extended fractional - precision, which noise shapes things, giving very clean DC removal. + This is one of the classic DC removal filters, adjusted to provide + sufficient bass rolloff to meet the above requirement to protect hybrids + from things that upset them. The difference between successive samples + produces a lousy HPF, and then a suitably placed pole flattens things out. + The final result is a nicely rolled off bass end. The filtering is + implemented with extended fractional precision, which noise shapes things, + giving very clean DC removal. */ int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx) @@ -601,13 +631,17 @@ int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx) if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) { tmp = tx << 15; -#if 1 - /* Make sure the gain of the HPF is 1.0. The first can still saturate a little under - impulse conditions, and it might roll to 32768 and need clipping on sustained peak - level signals. However, the scale of such clipping is small, and the error due to - any saturation should not markedly affect the downstream processing. */ + + /* + * Make sure the gain of the HPF is 1.0. The first can still + * saturate a little under impulse conditions, and it might + * roll to 32768 and need clipping on sustained peak level + * signals. However, the scale of such clipping is small, and + * the error due to any saturation should not markedly affect + * the downstream processing. + */ tmp -= (tmp >> 4); -#endif + ec->tx_1 += -(ec->tx_1 >> DC_LOG2BETA) + tmp - ec->tx_2; tmp1 = ec->tx_1 >> 15; if (tmp1 > 32767) diff --git a/drivers/staging/echo/echo.h b/drivers/staging/echo/echo.h index c835e5c..754e66d 100644 --- a/drivers/staging/echo/echo.h +++ b/drivers/staging/echo/echo.h @@ -28,13 +28,17 @@ #ifndef __ECHO_H #define __ECHO_H -/*! \page echo_can_page Line echo cancellation for voice +/* +Line echo cancellation for voice + +What does it do? -\section echo_can_page_sec_1 What does it do? This module aims to provide G.168-2002 compliant echo cancellation, to remove electrical echoes (e.g. from 2-4 wire hybrids) from voice calls. -\section echo_can_page_sec_2 How does it work? + +How does it work? + The heart of the echo cancellor is FIR filter. This is adapted to match the echo impulse response of the telephone line. It must be long enough to adequately cover the duration of that impulse response. The signal transmitted @@ -108,7 +112,8 @@ major mis-convergence in the adaption process. An assessment algorithm is needed which produces a fairly accurate result from a very short burst of far end energy. -\section echo_can_page_sec_3 How do I use it? +How do I use it? + The echo cancellor processes both the transmit and receive streams sample by sample. The processing function is not declared inline. Unfortunately, cancellation requires many operations per sample, so the call overhead is only @@ -118,7 +123,7 @@ a minor burden. #include "fir.h" #include "oslec.h" -/*! +/* G.168 echo canceller descriptor. This defines the working state for a line echo canceller. */ diff --git a/drivers/staging/echo/fir.h b/drivers/staging/echo/fir.h index ac6c553..7b9fabf 100644 --- a/drivers/staging/echo/fir.h +++ b/drivers/staging/echo/fir.h @@ -23,14 +23,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/*! \page fir_page FIR filtering -\section fir_page_sec_1 What does it do? -???. - -\section fir_page_sec_2 How does it work? -???. -*/ - #if !defined(_FIR_H_) #define _FIR_H_ @@ -62,14 +54,10 @@ can. */ -#if defined(USE_MMX) || defined(USE_SSE2) -#include "mmx.h" -#endif - -/*! - 16 bit integer FIR descriptor. This defines the working state for a single - instance of an FIR filter using 16 bit integer coefficients. -*/ +/* + * 16 bit integer FIR descriptor. This defines the working state for a single + * instance of an FIR filter using 16 bit integer coefficients. + */ struct fir16_state_t { int taps; int curr_pos; @@ -77,11 +65,11 @@ struct fir16_state_t { int16_t *history; }; -/*! - 32 bit integer FIR descriptor. This defines the working state for a single - instance of an FIR filter using 32 bit integer coefficients, and filtering - 16 bit integer data. -*/ +/* + * 32 bit integer FIR descriptor. This defines the working state for a single + * instance of an FIR filter using 32 bit integer coefficients, and filtering + * 16 bit integer data. + */ struct fir32_state_t { int taps; int curr_pos; @@ -89,10 +77,10 @@ struct fir32_state_t { int16_t *history; }; -/*! - Floating point FIR descriptor. This defines the working state for a single - instance of an FIR filter using floating point coefficients and data. -*/ +/* + * Floating point FIR descriptor. This defines the working state for a single + * instance of an FIR filter using floating point coefficients and data. + */ struct fir_float_state_t { int taps; int curr_pos; @@ -106,7 +94,7 @@ static inline const int16_t *fir16_create(struct fir16_state_t *fir, fir->taps = taps; fir->curr_pos = taps - 1; fir->coeffs = coeffs; -#if defined(USE_MMX) || defined(USE_SSE2) || defined(__bfin__) +#if defined(__bfin__) fir->history = kcalloc(2 * taps, sizeof(int16_t), GFP_KERNEL); #else fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL); @@ -116,7 +104,7 @@ static inline const int16_t *fir16_create(struct fir16_state_t *fir, static inline void fir16_flush(struct fir16_state_t *fir) { -#if defined(USE_MMX) || defined(USE_SSE2) || defined(__bfin__) +#if defined(__bfin__) memset(fir->history, 0, 2 * fir->taps * sizeof(int16_t)); #else memset(fir->history, 0, fir->taps * sizeof(int16_t)); @@ -158,71 +146,7 @@ static inline int32_t dot_asm(short *x, short *y, int len) static inline int16_t fir16(struct fir16_state_t *fir, int16_t sample) { int32_t y; -#if defined(USE_MMX) - int i; - union mmx_t *mmx_coeffs; - union mmx_t *mmx_hist; - - fir->history[fir->curr_pos] = sample; - fir->history[fir->curr_pos + fir->taps] = sample; - - mmx_coeffs = (union mmx_t *)fir->coeffs; - mmx_hist = (union mmx_t *)&fir->history[fir->curr_pos]; - i = fir->taps; - pxor_r2r(mm4, mm4); - /* 8 samples per iteration, so the filter must be a multiple of 8 long. */ - while (i > 0) { - movq_m2r(mmx_coeffs[0], mm0); - movq_m2r(mmx_coeffs[1], mm2); - movq_m2r(mmx_hist[0], mm1); - movq_m2r(mmx_hist[1], mm3); - mmx_coeffs += 2; - mmx_hist += 2; - pmaddwd_r2r(mm1, mm0); - pmaddwd_r2r(mm3, mm2); - paddd_r2r(mm0, mm4); - paddd_r2r(mm2, mm4); - i -= 8; - } - movq_r2r(mm4, mm0); - psrlq_i2r(32, mm0); - paddd_r2r(mm0, mm4); - movd_r2m(mm4, y); - emms(); -#elif defined(USE_SSE2) - int i; - union xmm_t *xmm_coeffs; - union xmm_t *xmm_hist; - - fir->history[fir->curr_pos] = sample; - fir->history[fir->curr_pos + fir->taps] = sample; - - xmm_coeffs = (union xmm_t *)fir->coeffs; - xmm_hist = (union xmm_t *)&fir->history[fir->curr_pos]; - i = fir->taps; - pxor_r2r(xmm4, xmm4); - /* 16 samples per iteration, so the filter must be a multiple of 16 long. */ - while (i > 0) { - movdqu_m2r(xmm_coeffs[0], xmm0); - movdqu_m2r(xmm_coeffs[1], xmm2); - movdqu_m2r(xmm_hist[0], xmm1); - movdqu_m2r(xmm_hist[1], xmm3); - xmm_coeffs += 2; - xmm_hist += 2; - pmaddwd_r2r(xmm1, xmm0); - pmaddwd_r2r(xmm3, xmm2); - paddd_r2r(xmm0, xmm4); - paddd_r2r(xmm2, xmm4); - i -= 16; - } - movdqa_r2r(xmm4, xmm0); - psrldq_i2r(8, xmm0); - paddd_r2r(xmm0, xmm4); - movdqa_r2r(xmm4, xmm0); - psrldq_i2r(4, xmm0); - paddd_r2r(xmm0, xmm4); - movd_r2m(xmm4, y); -#elif defined(__bfin__) +#if defined(__bfin__) fir->history[fir->curr_pos] = sample; fir->history[fir->curr_pos + fir->taps] = sample; y = dot_asm((int16_t *) fir->coeffs, &fir->history[fir->curr_pos], @@ -290,4 +214,3 @@ static inline int16_t fir32(struct fir32_state_t *fir, int16_t sample) } #endif -/*- End of file ------------------------------------------------------------*/ diff --git a/drivers/staging/echo/mmx.h b/drivers/staging/echo/mmx.h deleted file mode 100644 index c1dcd72..0000000 --- a/drivers/staging/echo/mmx.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * mmx.h - * Copyright (C) 1997-2001 H. Dietz and R. Fisher - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef AVCODEC_I386MMX_H -#define AVCODEC_I386MMX_H - -/* - * The type of an value that fits in an MMX register (note that long - * long constant values MUST be suffixed by LL and unsigned long long - * values by ULL, lest they be truncated by the compiler) - */ - -union mmx_t { - long long q; /* Quadword (64-bit) value */ - unsigned long long uq; /* Unsigned Quadword */ - int d[2]; /* 2 Doubleword (32-bit) values */ - unsigned int ud[2]; /* 2 Unsigned Doubleword */ - short w[4]; /* 4 Word (16-bit) values */ - unsigned short uw[4]; /* 4 Unsigned Word */ - char b[8]; /* 8 Byte (8-bit) values */ - unsigned char ub[8]; /* 8 Unsigned Byte */ - float s[2]; /* Single-precision (32-bit) value */ -}; /* On an 8-byte (64-bit) boundary */ - -/* SSE registers */ -union xmm_t { - char b[16]; -}; - -#define mmx_i2r(op, imm, reg) \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "i" (imm)) - -#define mmx_m2r(op, mem, reg) \ - __asm__ __volatile__ (#op " %0, %%" #reg \ - : /* nothing */ \ - : "m" (mem)) - -#define mmx_r2m(op, reg, mem) \ - __asm__ __volatile__ (#op " %%" #reg ", %0" \ - : "=m" (mem) \ - : /* nothing */) - -#define mmx_r2r(op, regs, regd) \ - __asm__ __volatile__ (#op " %" #regs ", %" #regd) - -#define emms() __asm__ __volatile__ ("emms") - -#define movd_m2r(var, reg) mmx_m2r(movd, var, reg) -#define movd_r2m(reg, var) mmx_r2m(movd, reg, var) -#define movd_r2r(regs, regd) mmx_r2r(movd, regs, regd) - -#define movq_m2r(var, reg) mmx_m2r(movq, var, reg) -#define movq_r2m(reg, var) mmx_r2m(movq, reg, var) -#define movq_r2r(regs, regd) mmx_r2r(movq, regs, regd) - -#define packssdw_m2r(var, reg) mmx_m2r(packssdw, var, reg) -#define packssdw_r2r(regs, regd) mmx_r2r(packssdw, regs, regd) -#define packsswb_m2r(var, reg) mmx_m2r(packsswb, var, reg) -#define packsswb_r2r(regs, regd) mmx_r2r(packsswb, regs, regd) - -#define packuswb_m2r(var, reg) mmx_m2r(packuswb, var, reg) -#define packuswb_r2r(regs, regd) mmx_r2r(packuswb, regs, regd) - -#define paddb_m2r(var, reg) mmx_m2r(paddb, var, reg) -#define paddb_r2r(regs, regd) mmx_r2r(paddb, regs, regd) -#define paddd_m2r(var, reg) mmx_m2r(paddd, var, reg) -#define paddd_r2r(regs, regd) mmx_r2r(paddd, regs, regd) -#define paddw_m2r(var, reg) mmx_m2r(paddw, var, reg) -#define paddw_r2r(regs, regd) mmx_r2r(paddw, regs, regd) - -#define paddsb_m2r(var, reg) mmx_m2r(paddsb, var, reg) -#define paddsb_r2r(regs, regd) mmx_r2r(paddsb, regs, regd) -#define paddsw_m2r(var, reg) mmx_m2r(paddsw, var, reg) -#define paddsw_r2r(regs, regd) mmx_r2r(paddsw, regs, regd) - -#define paddusb_m2r(var, reg) mmx_m2r(paddusb, var, reg) -#define paddusb_r2r(regs, regd) mmx_r2r(paddusb, regs, regd) -#define paddusw_m2r(var, reg) mmx_m2r(paddusw, var, reg) -#define paddusw_r2r(regs, regd) mmx_r2r(paddusw, regs, regd) - -#define pand_m2r(var, reg) mmx_m2r(pand, var, reg) -#define pand_r2r(regs, regd) mmx_r2r(pand, regs, regd) - -#define pandn_m2r(var, reg) mmx_m2r(pandn, var, reg) -#define pandn_r2r(regs, regd) mmx_r2r(pandn, regs, regd) - -#define pcmpeqb_m2r(var, reg) mmx_m2r(pcmpeqb, var, reg) -#define pcmpeqb_r2r(regs, regd) mmx_r2r(pcmpeqb, regs, regd) -#define pcmpeqd_m2r(var, reg) mmx_m2r(pcmpeqd, var, reg) -#define pcmpeqd_r2r(regs, regd) mmx_r2r(pcmpeqd, regs, regd) -#define pcmpeqw_m2r(var, reg) mmx_m2r(pcmpeqw, var, reg) -#define pcmpeqw_r2r(regs, regd) mmx_r2r(pcmpeqw, regs, regd) - -#define pcmpgtb_m2r(var, reg) mmx_m2r(pcmpgtb, var, reg) -#define pcmpgtb_r2r(regs, regd) mmx_r2r(pcmpgtb, regs, regd) -#define pcmpgtd_m2r(var, reg) mmx_m2r(pcmpgtd, var, reg) -#define pcmpgtd_r2r(regs, regd) mmx_r2r(pcmpgtd, regs, regd) -#define pcmpgtw_m2r(var, reg) mmx_m2r(pcmpgtw, var, reg) -#define pcmpgtw_r2r(regs, regd) mmx_r2r(pcmpgtw, regs, regd) - -#define pmaddwd_m2r(var, reg) mmx_m2r(pmaddwd, var, reg) -#define pmaddwd_r2r(regs, regd) mmx_r2r(pmaddwd, regs, regd) - -#define pmulhw_m2r(var, reg) mmx_m2r(pmulhw, var, reg) -#define pmulhw_r2r(regs, regd) mmx_r2r(pmulhw, regs, regd) - -#define pmullw_m2r(var, reg) mmx_m2r(pmullw, var, reg) -#define pmullw_r2r(regs, regd) mmx_r2r(pmullw, regs, regd) - -#define por_m2r(var, reg) mmx_m2r(por, var, reg) -#define por_r2r(regs, regd) mmx_r2r(por, regs, regd) - -#define pslld_i2r(imm, reg) mmx_i2r(pslld, imm, reg) -#define pslld_m2r(var, reg) mmx_m2r(pslld, var, reg) -#define pslld_r2r(regs, regd) mmx_r2r(pslld, regs, regd) -#define psllq_i2r(imm, reg) mmx_i2r(psllq, imm, reg) -#define psllq_m2r(var, reg) mmx_m2r(psllq, var, reg) -#define psllq_r2r(regs, regd) mmx_r2r(psllq, regs, regd) -#define psllw_i2r(imm, reg) mmx_i2r(psllw, imm, reg) -#define psllw_m2r(var, reg) mmx_m2r(psllw, var, reg) -#define psllw_r2r(regs, regd) mmx_r2r(psllw, regs, regd) - -#define psrad_i2r(imm, reg) mmx_i2r(psrad, imm, reg) -#define psrad_m2r(var, reg) mmx_m2r(psrad, var, reg) -#define psrad_r2r(regs, regd) mmx_r2r(psrad, regs, regd) -#define psraw_i2r(imm, reg) mmx_i2r(psraw, imm, reg) -#define psraw_m2r(var, reg) mmx_m2r(psraw, var, reg) -#define psraw_r2r(regs, regd) mmx_r2r(psraw, regs, regd) - -#define psrld_i2r(imm, reg) mmx_i2r(psrld, imm, reg) -#define psrld_m2r(var, reg) mmx_m2r(psrld, var, reg) -#define psrld_r2r(regs, regd) mmx_r2r(psrld, regs, regd) -#define psrlq_i2r(imm, reg) mmx_i2r(psrlq, imm, reg) -#define psrlq_m2r(var, reg) mmx_m2r(psrlq, var, reg) -#define psrlq_r2r(regs, regd) mmx_r2r(psrlq, regs, regd) -#define psrlw_i2r(imm, reg) mmx_i2r(psrlw, imm, reg) -#define psrlw_m2r(var, reg) mmx_m2r(psrlw, var, reg) -#define psrlw_r2r(regs, regd) mmx_r2r(psrlw, regs, regd) - -#define psubb_m2r(var, reg) mmx_m2r(psubb, var, reg) -#define psubb_r2r(regs, regd) mmx_r2r(psubb, regs, regd) -#define psubd_m2r(var, reg) mmx_m2r(psubd, var, reg) -#define psubd_r2r(regs, regd) mmx_r2r(psubd, regs, regd) -#define psubw_m2r(var, reg) mmx_m2r(psubw, var, reg) -#define psubw_r2r(regs, regd) mmx_r2r(psubw, regs, regd) - -#define psubsb_m2r(var, reg) mmx_m2r(psubsb, var, reg) -#define psubsb_r2r(regs, regd) mmx_r2r(psubsb, regs, regd) -#define psubsw_m2r(var, reg) mmx_m2r(psubsw, var, reg) -#define psubsw_r2r(regs, regd) mmx_r2r(psubsw, regs, regd) - -#define psubusb_m2r(var, reg) mmx_m2r(psubusb, var, reg) -#define psubusb_r2r(regs, regd) mmx_r2r(psubusb, regs, regd) -#define psubusw_m2r(var, reg) mmx_m2r(psubusw, var, reg) -#define psubusw_r2r(regs, regd) mmx_r2r(psubusw, regs, regd) - -#define punpckhbw_m2r(var, reg) mmx_m2r(punpckhbw, var, reg) -#define punpckhbw_r2r(regs, regd) mmx_r2r(punpckhbw, regs, regd) -#define punpckhdq_m2r(var, reg) mmx_m2r(punpckhdq, var, reg) -#define punpckhdq_r2r(regs, regd) mmx_r2r(punpckhdq, regs, regd) -#define punpckhwd_m2r(var, reg) mmx_m2r(punpckhwd, var, reg) -#define punpckhwd_r2r(regs, regd) mmx_r2r(punpckhwd, regs, regd) - -#define punpcklbw_m2r(var, reg) mmx_m2r(punpcklbw, var, reg) -#define punpcklbw_r2r(regs, regd) mmx_r2r(punpcklbw, regs, regd) -#define punpckldq_m2r(var, reg) mmx_m2r(punpckldq, var, reg) -#define punpckldq_r2r(regs, regd) mmx_r2r(punpckldq, regs, regd) -#define punpcklwd_m2r(var, reg) mmx_m2r(punpcklwd, var, reg) -#define punpcklwd_r2r(regs, regd) mmx_r2r(punpcklwd, regs, regd) - -#define pxor_m2r(var, reg) mmx_m2r(pxor, var, reg) -#define pxor_r2r(regs, regd) mmx_r2r(pxor, regs, regd) - -/* 3DNOW extensions */ - -#define pavgusb_m2r(var, reg) mmx_m2r(pavgusb, var, reg) -#define pavgusb_r2r(regs, regd) mmx_r2r(pavgusb, regs, regd) - -/* AMD MMX extensions - also available in intel SSE */ - -#define mmx_m2ri(op, mem, reg, imm) \ - __asm__ __volatile__ (#op " %1, %0, %%" #reg \ - : /* nothing */ \ - : "m" (mem), "i" (imm)) -#define mmx_r2ri(op, regs, regd, imm) \ - __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ - : /* nothing */ \ - : "i" (imm)) - -#define mmx_fetch(mem, hint) \ - __asm__ __volatile__ ("prefetch" #hint " %0" \ - : /* nothing */ \ - : "m" (mem)) - -#define maskmovq(regs, maskreg) mmx_r2ri(maskmovq, regs, maskreg) - -#define movntq_r2m(mmreg, var) mmx_r2m(movntq, mmreg, var) - -#define pavgb_m2r(var, reg) mmx_m2r(pavgb, var, reg) -#define pavgb_r2r(regs, regd) mmx_r2r(pavgb, regs, regd) -#define pavgw_m2r(var, reg) mmx_m2r(pavgw, var, reg) -#define pavgw_r2r(regs, regd) mmx_r2r(pavgw, regs, regd) - -#define pextrw_r2r(mmreg, reg, imm) mmx_r2ri(pextrw, mmreg, reg, imm) - -#define pinsrw_r2r(reg, mmreg, imm) mmx_r2ri(pinsrw, reg, mmreg, imm) - -#define pmaxsw_m2r(var, reg) mmx_m2r(pmaxsw, var, reg) -#define pmaxsw_r2r(regs, regd) mmx_r2r(pmaxsw, regs, regd) - -#define pmaxub_m2r(var, reg) mmx_m2r(pmaxub, var, reg) -#define pmaxub_r2r(regs, regd) mmx_r2r(pmaxub, regs, regd) - -#define pminsw_m2r(var, reg) mmx_m2r(pminsw, var, reg) -#define pminsw_r2r(regs, regd) mmx_r2r(pminsw, regs, regd) - -#define pminub_m2r(var, reg) mmx_m2r(pminub, var, reg) -#define pminub_r2r(regs, regd) mmx_r2r(pminub, regs, regd) - -#define pmovmskb(mmreg, reg) \ - __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) - -#define pmulhuw_m2r(var, reg) mmx_m2r(pmulhuw, var, reg) -#define pmulhuw_r2r(regs, regd) mmx_r2r(pmulhuw, regs, regd) - -#define prefetcht0(mem) mmx_fetch(mem, t0) -#define prefetcht1(mem) mmx_fetch(mem, t1) -#define prefetcht2(mem) mmx_fetch(mem, t2) -#define prefetchnta(mem) mmx_fetch(mem, nta) - -#define psadbw_m2r(var, reg) mmx_m2r(psadbw, var, reg) -#define psadbw_r2r(regs, regd) mmx_r2r(psadbw, regs, regd) - -#define pshufw_m2r(var, reg, imm) mmx_m2ri(pshufw, var, reg, imm) -#define pshufw_r2r(regs, regd, imm) mmx_r2ri(pshufw, regs, regd, imm) - -#define sfence() __asm__ __volatile__ ("sfence\n\t") - -/* SSE2 */ -#define pshufhw_m2r(var, reg, imm) mmx_m2ri(pshufhw, var, reg, imm) -#define pshufhw_r2r(regs, regd, imm) mmx_r2ri(pshufhw, regs, regd, imm) -#define pshuflw_m2r(var, reg, imm) mmx_m2ri(pshuflw, var, reg, imm) -#define pshuflw_r2r(regs, regd, imm) mmx_r2ri(pshuflw, regs, regd, imm) - -#define pshufd_r2r(regs, regd, imm) mmx_r2ri(pshufd, regs, regd, imm) - -#define movdqa_m2r(var, reg) mmx_m2r(movdqa, var, reg) -#define movdqa_r2m(reg, var) mmx_r2m(movdqa, reg, var) -#define movdqa_r2r(regs, regd) mmx_r2r(movdqa, regs, regd) -#define movdqu_m2r(var, reg) mmx_m2r(movdqu, var, reg) -#define movdqu_r2m(reg, var) mmx_r2m(movdqu, reg, var) -#define movdqu_r2r(regs, regd) mmx_r2r(movdqu, regs, regd) - -#define pmullw_r2m(reg, var) mmx_r2m(pmullw, reg, var) - -#define pslldq_i2r(imm, reg) mmx_i2r(pslldq, imm, reg) -#define psrldq_i2r(imm, reg) mmx_i2r(psrldq, imm, reg) - -#define punpcklqdq_r2r(regs, regd) mmx_r2r(punpcklqdq, regs, regd) -#define punpckhqdq_r2r(regs, regd) mmx_r2r(punpckhqdq, regs, regd) - -#endif /* AVCODEC_I386MMX_H */ diff --git a/drivers/staging/echo/oslec.h b/drivers/staging/echo/oslec.h index bad8523..f417536 100644 --- a/drivers/staging/echo/oslec.h +++ b/drivers/staging/echo/oslec.h @@ -27,8 +27,6 @@ #ifndef __OSLEC_H #define __OSLEC_H -/* TODO: document interface */ - /* Mask bits for the adaption mode */ #define ECHO_CAN_USE_ADAPTION 0x01 #define ECHO_CAN_USE_NLP 0x02 @@ -38,49 +36,59 @@ #define ECHO_CAN_USE_RX_HPF 0x20 #define ECHO_CAN_DISABLE 0x40 -/*! - G.168 echo canceller descriptor. This defines the working state for a line - echo canceller. -*/ +/** + * oslec_state: G.168 echo canceller descriptor. + * + * This defines the working state for a line echo canceller. + */ struct oslec_state; -/*! Create a voice echo canceller context. - \param len The length of the canceller, in samples. - \return The new canceller context, or NULL if the canceller could not be created. -*/ +/** + * oslec_create - Create a voice echo canceller context. + * @len: The length of the canceller, in samples. + * @return: The new canceller context, or NULL if the canceller could not be + * created. + */ struct oslec_state *oslec_create(int len, int adaption_mode); -/*! Free a voice echo canceller context. - \param ec The echo canceller context. -*/ +/** + * oslec_free - Free a voice echo canceller context. + * @ec: The echo canceller context. + */ void oslec_free(struct oslec_state *ec); -/*! Flush (reinitialise) a voice echo canceller context. - \param ec The echo canceller context. -*/ +/** + * oslec_flush - Flush (reinitialise) a voice echo canceller context. + * @ec: The echo canceller context. + */ void oslec_flush(struct oslec_state *ec); -/*! Set the adaption mode of a voice echo canceller context. - \param ec The echo canceller context. - \param adapt The mode. -*/ +/** + * oslec_adaption_mode - set the adaption mode of a voice echo canceller context. + * @ec The echo canceller context. + * @adaption_mode: The mode. + */ void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode); void oslec_snapshot(struct oslec_state *ec); -/*! Process a sample through a voice echo canceller. - \param ec The echo canceller context. - \param tx The transmitted audio sample. - \param rx The received audio sample. - \return The clean (echo cancelled) received sample. -*/ +/** + * oslec_update: Process a sample through a voice echo canceller. + * @ec: The echo canceller context. + * @tx: The transmitted audio sample. + * @rx: The received audio sample. + * + * The return value is the clean (echo cancelled) received sample. + */ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx); -/*! Process to high pass filter the tx signal. - \param ec The echo canceller context. - \param tx The transmitted auio sample. - \return The HP filtered transmit sample, send this to your D/A. -*/ +/** + * oslec_hpf_tx: Process to high pass filter the tx signal. + * @ec: The echo canceller context. + * @tx: The transmitted auio sample. + * + * The return value is the HP filtered transmit sample, send this to your D/A. + */ int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx); #endif /* __OSLEC_H */ |