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

u_uac1_legacy.c (7230B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * u_uac1.c -- ALSA audio utilities for Gadget stack
      4 *
      5 * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
      6 * Copyright (C) 2008 Analog Devices, Inc
      7 */
      8
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/slab.h>
     12#include <linux/device.h>
     13#include <linux/delay.h>
     14#include <linux/ctype.h>
     15#include <linux/random.h>
     16#include <linux/syscalls.h>
     17
     18#include "u_uac1_legacy.h"
     19
     20/*
     21 * This component encapsulates the ALSA devices for USB audio gadget
     22 */
     23
     24/*-------------------------------------------------------------------------*/
     25
     26/*
     27 * Some ALSA internal helper functions
     28 */
     29static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
     30{
     31	struct snd_interval t;
     32	t.empty = 0;
     33	t.min = t.max = val;
     34	t.openmin = t.openmax = 0;
     35	t.integer = 1;
     36	return snd_interval_refine(i, &t);
     37}
     38
     39static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
     40				 snd_pcm_hw_param_t var, unsigned int val,
     41				 int dir)
     42{
     43	int changed;
     44	if (hw_is_mask(var)) {
     45		struct snd_mask *m = hw_param_mask(params, var);
     46		if (val == 0 && dir < 0) {
     47			changed = -EINVAL;
     48			snd_mask_none(m);
     49		} else {
     50			if (dir > 0)
     51				val++;
     52			else if (dir < 0)
     53				val--;
     54			changed = snd_mask_refine_set(
     55					hw_param_mask(params, var), val);
     56		}
     57	} else if (hw_is_interval(var)) {
     58		struct snd_interval *i = hw_param_interval(params, var);
     59		if (val == 0 && dir < 0) {
     60			changed = -EINVAL;
     61			snd_interval_none(i);
     62		} else if (dir == 0)
     63			changed = snd_interval_refine_set(i, val);
     64		else {
     65			struct snd_interval t;
     66			t.openmin = 1;
     67			t.openmax = 1;
     68			t.empty = 0;
     69			t.integer = 0;
     70			if (dir < 0) {
     71				t.min = val - 1;
     72				t.max = val;
     73			} else {
     74				t.min = val;
     75				t.max = val+1;
     76			}
     77			changed = snd_interval_refine(i, &t);
     78		}
     79	} else
     80		return -EINVAL;
     81	if (changed) {
     82		params->cmask |= 1 << var;
     83		params->rmask |= 1 << var;
     84	}
     85	return changed;
     86}
     87/*-------------------------------------------------------------------------*/
     88
     89/*
     90 * Set default hardware params
     91 */
     92static int playback_default_hw_params(struct gaudio_snd_dev *snd)
     93{
     94	struct snd_pcm_substream *substream = snd->substream;
     95	struct snd_pcm_hw_params *params;
     96	snd_pcm_sframes_t result;
     97
     98       /*
     99	* SNDRV_PCM_ACCESS_RW_INTERLEAVED,
    100	* SNDRV_PCM_FORMAT_S16_LE
    101	* CHANNELS: 2
    102	* RATE: 48000
    103	*/
    104	snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
    105	snd->format = SNDRV_PCM_FORMAT_S16_LE;
    106	snd->channels = 2;
    107	snd->rate = 48000;
    108
    109	params = kzalloc(sizeof(*params), GFP_KERNEL);
    110	if (!params)
    111		return -ENOMEM;
    112
    113	_snd_pcm_hw_params_any(params);
    114	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
    115			snd->access, 0);
    116	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
    117			snd->format, 0);
    118	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
    119			snd->channels, 0);
    120	_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
    121			snd->rate, 0);
    122
    123	snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
    124	snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params);
    125
    126	result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
    127	if (result < 0) {
    128		ERROR(snd->card,
    129			"Preparing sound card failed: %d\n", (int)result);
    130		kfree(params);
    131		return result;
    132	}
    133
    134	/* Store the hardware parameters */
    135	snd->access = params_access(params);
    136	snd->format = params_format(params);
    137	snd->channels = params_channels(params);
    138	snd->rate = params_rate(params);
    139
    140	kfree(params);
    141
    142	INFO(snd->card,
    143		"Hardware params: access %x, format %x, channels %d, rate %d\n",
    144		snd->access, snd->format, snd->channels, snd->rate);
    145
    146	return 0;
    147}
    148
    149/*
    150 * Playback audio buffer data by ALSA PCM device
    151 */
    152size_t u_audio_playback(struct gaudio *card, void *buf, size_t count)
    153{
    154	struct gaudio_snd_dev	*snd = &card->playback;
    155	struct snd_pcm_substream *substream = snd->substream;
    156	struct snd_pcm_runtime *runtime = substream->runtime;
    157	ssize_t result;
    158	snd_pcm_sframes_t frames;
    159
    160try_again:
    161	if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
    162		runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
    163		result = snd_pcm_kernel_ioctl(substream,
    164				SNDRV_PCM_IOCTL_PREPARE, NULL);
    165		if (result < 0) {
    166			ERROR(card, "Preparing sound card failed: %d\n",
    167					(int)result);
    168			return result;
    169		}
    170	}
    171
    172	frames = bytes_to_frames(runtime, count);
    173	result = snd_pcm_kernel_write(snd->substream, buf, frames);
    174	if (result != frames) {
    175		ERROR(card, "Playback error: %d\n", (int)result);
    176		goto try_again;
    177	}
    178
    179	return 0;
    180}
    181
    182int u_audio_get_playback_channels(struct gaudio *card)
    183{
    184	return card->playback.channels;
    185}
    186
    187int u_audio_get_playback_rate(struct gaudio *card)
    188{
    189	return card->playback.rate;
    190}
    191
    192/*
    193 * Open ALSA PCM and control device files
    194 * Initial the PCM or control device
    195 */
    196static int gaudio_open_snd_dev(struct gaudio *card)
    197{
    198	struct snd_pcm_file *pcm_file;
    199	struct gaudio_snd_dev *snd;
    200	struct f_uac1_legacy_opts *opts;
    201	char *fn_play, *fn_cap, *fn_cntl;
    202
    203	opts = container_of(card->func.fi, struct f_uac1_legacy_opts,
    204			    func_inst);
    205	fn_play = opts->fn_play;
    206	fn_cap = opts->fn_cap;
    207	fn_cntl = opts->fn_cntl;
    208
    209	/* Open control device */
    210	snd = &card->control;
    211	snd->filp = filp_open(fn_cntl, O_RDWR, 0);
    212	if (IS_ERR(snd->filp)) {
    213		int ret = PTR_ERR(snd->filp);
    214		ERROR(card, "unable to open sound control device file: %s\n",
    215				fn_cntl);
    216		snd->filp = NULL;
    217		return ret;
    218	}
    219	snd->card = card;
    220
    221	/* Open PCM playback device and setup substream */
    222	snd = &card->playback;
    223	snd->filp = filp_open(fn_play, O_WRONLY, 0);
    224	if (IS_ERR(snd->filp)) {
    225		int ret = PTR_ERR(snd->filp);
    226
    227		ERROR(card, "No such PCM playback device: %s\n", fn_play);
    228		snd->filp = NULL;
    229		return ret;
    230	}
    231	pcm_file = snd->filp->private_data;
    232	snd->substream = pcm_file->substream;
    233	snd->card = card;
    234	playback_default_hw_params(snd);
    235
    236	/* Open PCM capture device and setup substream */
    237	snd = &card->capture;
    238	snd->filp = filp_open(fn_cap, O_RDONLY, 0);
    239	if (IS_ERR(snd->filp)) {
    240		ERROR(card, "No such PCM capture device: %s\n", fn_cap);
    241		snd->substream = NULL;
    242		snd->card = NULL;
    243		snd->filp = NULL;
    244	} else {
    245		pcm_file = snd->filp->private_data;
    246		snd->substream = pcm_file->substream;
    247		snd->card = card;
    248	}
    249
    250	return 0;
    251}
    252
    253/*
    254 * Close ALSA PCM and control device files
    255 */
    256static int gaudio_close_snd_dev(struct gaudio *gau)
    257{
    258	struct gaudio_snd_dev	*snd;
    259
    260	/* Close control device */
    261	snd = &gau->control;
    262	if (snd->filp)
    263		filp_close(snd->filp, NULL);
    264
    265	/* Close PCM playback device and setup substream */
    266	snd = &gau->playback;
    267	if (snd->filp)
    268		filp_close(snd->filp, NULL);
    269
    270	/* Close PCM capture device and setup substream */
    271	snd = &gau->capture;
    272	if (snd->filp)
    273		filp_close(snd->filp, NULL);
    274
    275	return 0;
    276}
    277
    278/*
    279 * gaudio_setup - setup ALSA interface and preparing for USB transfer
    280 *
    281 * This sets up PCM, mixer or MIDI ALSA devices fore USB gadget using.
    282 *
    283 * Returns negative errno, or zero on success
    284 */
    285int gaudio_setup(struct gaudio *card)
    286{
    287	int	ret;
    288
    289	ret = gaudio_open_snd_dev(card);
    290	if (ret)
    291		ERROR(card, "we need at least one control device\n");
    292
    293	return ret;
    294
    295}
    296
    297/*
    298 * gaudio_cleanup - remove ALSA device interface
    299 *
    300 * This is called to free all resources allocated by @gaudio_setup().
    301 */
    302void gaudio_cleanup(struct gaudio *the_card)
    303{
    304	if (the_card)
    305		gaudio_close_snd_dev(the_card);
    306}
    307