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

linear.c (5864B)


      1/*
      2 *  Linear conversion Plug-In
      3 *  Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>,
      4 *			  Abramo Bagnara <abramo@alsa-project.org>
      5 *
      6 *
      7 *   This library is free software; you can redistribute it and/or modify
      8 *   it under the terms of the GNU Library General Public License as
      9 *   published by the Free Software Foundation; either version 2 of
     10 *   the License, or (at your option) any later version.
     11 *
     12 *   This program is distributed in the hope that it will be useful,
     13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 *   GNU Library General Public License for more details.
     16 *
     17 *   You should have received a copy of the GNU Library General Public
     18 *   License along with this library; if not, write to the Free Software
     19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     20 *
     21 */
     22
     23#include <linux/time.h>
     24#include <sound/core.h>
     25#include <sound/pcm.h>
     26#include "pcm_plugin.h"
     27
     28/*
     29 *  Basic linear conversion plugin
     30 */
     31 
     32struct linear_priv {
     33	int cvt_endian;		/* need endian conversion? */
     34	unsigned int src_ofs;	/* byte offset in source format */
     35	unsigned int dst_ofs;	/* byte soffset in destination format */
     36	unsigned int copy_ofs;	/* byte offset in temporary u32 data */
     37	unsigned int dst_bytes;		/* byte size of destination format */
     38	unsigned int copy_bytes;	/* bytes to copy per conversion */
     39	unsigned int flip; /* MSB flip for signeness, done after endian conv */
     40};
     41
     42static inline void do_convert(struct linear_priv *data,
     43			      unsigned char *dst, unsigned char *src)
     44{
     45	unsigned int tmp = 0;
     46	unsigned char *p = (unsigned char *)&tmp;
     47
     48	memcpy(p + data->copy_ofs, src + data->src_ofs, data->copy_bytes);
     49	if (data->cvt_endian)
     50		tmp = swab32(tmp);
     51	tmp ^= data->flip;
     52	memcpy(dst, p + data->dst_ofs, data->dst_bytes);
     53}
     54
     55static void convert(struct snd_pcm_plugin *plugin,
     56		    const struct snd_pcm_plugin_channel *src_channels,
     57		    struct snd_pcm_plugin_channel *dst_channels,
     58		    snd_pcm_uframes_t frames)
     59{
     60	struct linear_priv *data = (struct linear_priv *)plugin->extra_data;
     61	int channel;
     62	int nchannels = plugin->src_format.channels;
     63	for (channel = 0; channel < nchannels; ++channel) {
     64		char *src;
     65		char *dst;
     66		int src_step, dst_step;
     67		snd_pcm_uframes_t frames1;
     68		if (!src_channels[channel].enabled) {
     69			if (dst_channels[channel].wanted)
     70				snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
     71			dst_channels[channel].enabled = 0;
     72			continue;
     73		}
     74		dst_channels[channel].enabled = 1;
     75		src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
     76		dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
     77		src_step = src_channels[channel].area.step / 8;
     78		dst_step = dst_channels[channel].area.step / 8;
     79		frames1 = frames;
     80		while (frames1-- > 0) {
     81			do_convert(data, dst, src);
     82			src += src_step;
     83			dst += dst_step;
     84		}
     85	}
     86}
     87
     88static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
     89			       const struct snd_pcm_plugin_channel *src_channels,
     90			       struct snd_pcm_plugin_channel *dst_channels,
     91			       snd_pcm_uframes_t frames)
     92{
     93	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
     94		return -ENXIO;
     95	if (frames == 0)
     96		return 0;
     97#ifdef CONFIG_SND_DEBUG
     98	{
     99		unsigned int channel;
    100		for (channel = 0; channel < plugin->src_format.channels; channel++) {
    101			if (snd_BUG_ON(src_channels[channel].area.first % 8 ||
    102				       src_channels[channel].area.step % 8))
    103				return -ENXIO;
    104			if (snd_BUG_ON(dst_channels[channel].area.first % 8 ||
    105				       dst_channels[channel].area.step % 8))
    106				return -ENXIO;
    107		}
    108	}
    109#endif
    110	if (frames > dst_channels[0].frames)
    111		frames = dst_channels[0].frames;
    112	convert(plugin, src_channels, dst_channels, frames);
    113	return frames;
    114}
    115
    116static void init_data(struct linear_priv *data,
    117		      snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
    118{
    119	int src_le, dst_le, src_bytes, dst_bytes;
    120
    121	src_bytes = snd_pcm_format_width(src_format) / 8;
    122	dst_bytes = snd_pcm_format_width(dst_format) / 8;
    123	src_le = snd_pcm_format_little_endian(src_format) > 0;
    124	dst_le = snd_pcm_format_little_endian(dst_format) > 0;
    125
    126	data->dst_bytes = dst_bytes;
    127	data->cvt_endian = src_le != dst_le;
    128	data->copy_bytes = src_bytes < dst_bytes ? src_bytes : dst_bytes;
    129	if (src_le) {
    130		data->copy_ofs = 4 - data->copy_bytes;
    131		data->src_ofs = src_bytes - data->copy_bytes;
    132	} else
    133		data->src_ofs = snd_pcm_format_physical_width(src_format) / 8 -
    134			src_bytes;
    135	if (dst_le)
    136		data->dst_ofs = 4 - data->dst_bytes;
    137	else
    138		data->dst_ofs = snd_pcm_format_physical_width(dst_format) / 8 -
    139			dst_bytes;
    140	if (snd_pcm_format_signed(src_format) !=
    141	    snd_pcm_format_signed(dst_format)) {
    142		if (dst_le)
    143			data->flip = (__force u32)cpu_to_le32(0x80000000);
    144		else
    145			data->flip = (__force u32)cpu_to_be32(0x80000000);
    146	}
    147}
    148
    149int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug,
    150				struct snd_pcm_plugin_format *src_format,
    151				struct snd_pcm_plugin_format *dst_format,
    152				struct snd_pcm_plugin **r_plugin)
    153{
    154	int err;
    155	struct linear_priv *data;
    156	struct snd_pcm_plugin *plugin;
    157
    158	if (snd_BUG_ON(!r_plugin))
    159		return -ENXIO;
    160	*r_plugin = NULL;
    161
    162	if (snd_BUG_ON(src_format->rate != dst_format->rate))
    163		return -ENXIO;
    164	if (snd_BUG_ON(src_format->channels != dst_format->channels))
    165		return -ENXIO;
    166	if (snd_BUG_ON(!snd_pcm_format_linear(src_format->format) ||
    167		       !snd_pcm_format_linear(dst_format->format)))
    168		return -ENXIO;
    169
    170	err = snd_pcm_plugin_build(plug, "linear format conversion",
    171				   src_format, dst_format,
    172				   sizeof(struct linear_priv), &plugin);
    173	if (err < 0)
    174		return err;
    175	data = (struct linear_priv *)plugin->extra_data;
    176	init_data(data, src_format->format, dst_format->format);
    177	plugin->transfer = linear_transfer;
    178	*r_plugin = plugin;
    179	return 0;
    180}