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

ctpcm.c (11843B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
      4 *
      5 * @File	ctpcm.c
      6 *
      7 * @Brief
      8 * This file contains the definition of the pcm device functions.
      9 *
     10 * @Author	Liu Chun
     11 * @Date 	Apr 2 2008
     12 */
     13
     14#include "ctpcm.h"
     15#include "cttimer.h"
     16#include <linux/slab.h>
     17#include <sound/pcm.h>
     18
     19/* Hardware descriptions for playback */
     20static const struct snd_pcm_hardware ct_pcm_playback_hw = {
     21	.info			= (SNDRV_PCM_INFO_MMAP |
     22				   SNDRV_PCM_INFO_INTERLEAVED |
     23				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
     24				   SNDRV_PCM_INFO_MMAP_VALID |
     25				   SNDRV_PCM_INFO_PAUSE),
     26	.formats		= (SNDRV_PCM_FMTBIT_U8 |
     27				   SNDRV_PCM_FMTBIT_S16_LE |
     28				   SNDRV_PCM_FMTBIT_S24_3LE |
     29				   SNDRV_PCM_FMTBIT_S32_LE |
     30				   SNDRV_PCM_FMTBIT_FLOAT_LE),
     31	.rates			= (SNDRV_PCM_RATE_CONTINUOUS |
     32				   SNDRV_PCM_RATE_8000_192000),
     33	.rate_min		= 8000,
     34	.rate_max		= 192000,
     35	.channels_min		= 1,
     36	.channels_max		= 2,
     37	.buffer_bytes_max	= (128*1024),
     38	.period_bytes_min	= (64),
     39	.period_bytes_max	= (128*1024),
     40	.periods_min		= 2,
     41	.periods_max		= 1024,
     42	.fifo_size		= 0,
     43};
     44
     45static const struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
     46	.info			= (SNDRV_PCM_INFO_MMAP |
     47				   SNDRV_PCM_INFO_INTERLEAVED |
     48				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
     49				   SNDRV_PCM_INFO_MMAP_VALID |
     50				   SNDRV_PCM_INFO_PAUSE),
     51	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
     52	.rates			= (SNDRV_PCM_RATE_48000 |
     53				   SNDRV_PCM_RATE_44100 |
     54				   SNDRV_PCM_RATE_32000),
     55	.rate_min		= 32000,
     56	.rate_max		= 48000,
     57	.channels_min		= 2,
     58	.channels_max		= 2,
     59	.buffer_bytes_max	= (128*1024),
     60	.period_bytes_min	= (64),
     61	.period_bytes_max	= (128*1024),
     62	.periods_min		= 2,
     63	.periods_max		= 1024,
     64	.fifo_size		= 0,
     65};
     66
     67/* Hardware descriptions for capture */
     68static const struct snd_pcm_hardware ct_pcm_capture_hw = {
     69	.info			= (SNDRV_PCM_INFO_MMAP |
     70				   SNDRV_PCM_INFO_INTERLEAVED |
     71				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
     72				   SNDRV_PCM_INFO_PAUSE |
     73				   SNDRV_PCM_INFO_MMAP_VALID),
     74	.formats		= (SNDRV_PCM_FMTBIT_U8 |
     75				   SNDRV_PCM_FMTBIT_S16_LE |
     76				   SNDRV_PCM_FMTBIT_S24_3LE |
     77				   SNDRV_PCM_FMTBIT_S32_LE |
     78				   SNDRV_PCM_FMTBIT_FLOAT_LE),
     79	.rates			= (SNDRV_PCM_RATE_CONTINUOUS |
     80				   SNDRV_PCM_RATE_8000_96000),
     81	.rate_min		= 8000,
     82	.rate_max		= 96000,
     83	.channels_min		= 1,
     84	.channels_max		= 2,
     85	.buffer_bytes_max	= (128*1024),
     86	.period_bytes_min	= (384),
     87	.period_bytes_max	= (64*1024),
     88	.periods_min		= 2,
     89	.periods_max		= 1024,
     90	.fifo_size		= 0,
     91};
     92
     93static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
     94{
     95	struct ct_atc_pcm *apcm = atc_pcm;
     96
     97	if (!apcm->substream)
     98		return;
     99
    100	snd_pcm_period_elapsed(apcm->substream);
    101}
    102
    103static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
    104{
    105	struct ct_atc_pcm *apcm = runtime->private_data;
    106	struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
    107
    108	atc->pcm_release_resources(atc, apcm);
    109	ct_timer_instance_free(apcm->timer);
    110	kfree(apcm);
    111	runtime->private_data = NULL;
    112}
    113
    114/* pcm playback operations */
    115static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
    116{
    117	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    118	struct snd_pcm_runtime *runtime = substream->runtime;
    119	struct ct_atc_pcm *apcm;
    120	int err;
    121
    122	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
    123	if (!apcm)
    124		return -ENOMEM;
    125
    126	apcm->substream = substream;
    127	apcm->interrupt = ct_atc_pcm_interrupt;
    128	if (IEC958 == substream->pcm->device) {
    129		runtime->hw = ct_spdif_passthru_playback_hw;
    130		atc->spdif_out_passthru(atc, 1);
    131	} else {
    132		runtime->hw = ct_pcm_playback_hw;
    133		if (FRONT == substream->pcm->device)
    134			runtime->hw.channels_max = 8;
    135	}
    136
    137	err = snd_pcm_hw_constraint_integer(runtime,
    138					    SNDRV_PCM_HW_PARAM_PERIODS);
    139	if (err < 0)
    140		goto free_pcm;
    141
    142	err = snd_pcm_hw_constraint_minmax(runtime,
    143					   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
    144					   1024, UINT_MAX);
    145	if (err < 0)
    146		goto free_pcm;
    147
    148	apcm->timer = ct_timer_instance_new(atc->timer, apcm);
    149	if (!apcm->timer) {
    150		err = -ENOMEM;
    151		goto free_pcm;
    152	}
    153	runtime->private_data = apcm;
    154	runtime->private_free = ct_atc_pcm_free_substream;
    155
    156	return 0;
    157
    158free_pcm:
    159	kfree(apcm);
    160	return err;
    161}
    162
    163static int ct_pcm_playback_close(struct snd_pcm_substream *substream)
    164{
    165	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    166
    167	/* TODO: Notify mixer inactive. */
    168	if (IEC958 == substream->pcm->device)
    169		atc->spdif_out_passthru(atc, 0);
    170
    171	/* The ct_atc_pcm object will be freed by runtime->private_free */
    172
    173	return 0;
    174}
    175
    176static int ct_pcm_hw_params(struct snd_pcm_substream *substream,
    177				     struct snd_pcm_hw_params *hw_params)
    178{
    179	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    180	struct ct_atc_pcm *apcm = substream->runtime->private_data;
    181
    182	/* clear previous resources */
    183	atc->pcm_release_resources(atc, apcm);
    184	return 0;
    185}
    186
    187static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
    188{
    189	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    190	struct ct_atc_pcm *apcm = substream->runtime->private_data;
    191
    192	/* clear previous resources */
    193	atc->pcm_release_resources(atc, apcm);
    194	return 0;
    195}
    196
    197
    198static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
    199{
    200	int err;
    201	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    202	struct snd_pcm_runtime *runtime = substream->runtime;
    203	struct ct_atc_pcm *apcm = runtime->private_data;
    204
    205	if (IEC958 == substream->pcm->device)
    206		err = atc->spdif_passthru_playback_prepare(atc, apcm);
    207	else
    208		err = atc->pcm_playback_prepare(atc, apcm);
    209
    210	if (err < 0) {
    211		dev_err(atc->card->dev,
    212			"Preparing pcm playback failed!!!\n");
    213		return err;
    214	}
    215
    216	return 0;
    217}
    218
    219static int
    220ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
    221{
    222	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    223	struct snd_pcm_runtime *runtime = substream->runtime;
    224	struct ct_atc_pcm *apcm = runtime->private_data;
    225
    226	switch (cmd) {
    227	case SNDRV_PCM_TRIGGER_START:
    228	case SNDRV_PCM_TRIGGER_RESUME:
    229	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    230		atc->pcm_playback_start(atc, apcm);
    231		break;
    232	case SNDRV_PCM_TRIGGER_STOP:
    233	case SNDRV_PCM_TRIGGER_SUSPEND:
    234	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    235		atc->pcm_playback_stop(atc, apcm);
    236		break;
    237	default:
    238		break;
    239	}
    240
    241	return 0;
    242}
    243
    244static snd_pcm_uframes_t
    245ct_pcm_playback_pointer(struct snd_pcm_substream *substream)
    246{
    247	unsigned long position;
    248	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    249	struct snd_pcm_runtime *runtime = substream->runtime;
    250	struct ct_atc_pcm *apcm = runtime->private_data;
    251
    252	/* Read out playback position */
    253	position = atc->pcm_playback_position(atc, apcm);
    254	position = bytes_to_frames(runtime, position);
    255	if (position >= runtime->buffer_size)
    256		position = 0;
    257	return position;
    258}
    259
    260/* pcm capture operations */
    261static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
    262{
    263	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    264	struct snd_pcm_runtime *runtime = substream->runtime;
    265	struct ct_atc_pcm *apcm;
    266	int err;
    267
    268	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
    269	if (!apcm)
    270		return -ENOMEM;
    271
    272	apcm->started = 0;
    273	apcm->substream = substream;
    274	apcm->interrupt = ct_atc_pcm_interrupt;
    275	runtime->hw = ct_pcm_capture_hw;
    276	runtime->hw.rate_max = atc->rsr * atc->msr;
    277
    278	err = snd_pcm_hw_constraint_integer(runtime,
    279					    SNDRV_PCM_HW_PARAM_PERIODS);
    280	if (err < 0)
    281		goto free_pcm;
    282
    283	err = snd_pcm_hw_constraint_minmax(runtime,
    284					   SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
    285					   1024, UINT_MAX);
    286	if (err < 0)
    287		goto free_pcm;
    288
    289	apcm->timer = ct_timer_instance_new(atc->timer, apcm);
    290	if (!apcm->timer) {
    291		err = -ENOMEM;
    292		goto free_pcm;
    293	}
    294	runtime->private_data = apcm;
    295	runtime->private_free = ct_atc_pcm_free_substream;
    296
    297	return 0;
    298
    299free_pcm:
    300	kfree(apcm);
    301	return err;
    302}
    303
    304static int ct_pcm_capture_close(struct snd_pcm_substream *substream)
    305{
    306	/* The ct_atc_pcm object will be freed by runtime->private_free */
    307	/* TODO: Notify mixer inactive. */
    308	return 0;
    309}
    310
    311static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
    312{
    313	int err;
    314	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    315	struct snd_pcm_runtime *runtime = substream->runtime;
    316	struct ct_atc_pcm *apcm = runtime->private_data;
    317
    318	err = atc->pcm_capture_prepare(atc, apcm);
    319	if (err < 0) {
    320		dev_err(atc->card->dev,
    321			"Preparing pcm capture failed!!!\n");
    322		return err;
    323	}
    324
    325	return 0;
    326}
    327
    328static int
    329ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
    330{
    331	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    332	struct snd_pcm_runtime *runtime = substream->runtime;
    333	struct ct_atc_pcm *apcm = runtime->private_data;
    334
    335	switch (cmd) {
    336	case SNDRV_PCM_TRIGGER_START:
    337		atc->pcm_capture_start(atc, apcm);
    338		break;
    339	case SNDRV_PCM_TRIGGER_STOP:
    340		atc->pcm_capture_stop(atc, apcm);
    341		break;
    342	default:
    343		atc->pcm_capture_stop(atc, apcm);
    344		break;
    345	}
    346
    347	return 0;
    348}
    349
    350static snd_pcm_uframes_t
    351ct_pcm_capture_pointer(struct snd_pcm_substream *substream)
    352{
    353	unsigned long position;
    354	struct ct_atc *atc = snd_pcm_substream_chip(substream);
    355	struct snd_pcm_runtime *runtime = substream->runtime;
    356	struct ct_atc_pcm *apcm = runtime->private_data;
    357
    358	/* Read out playback position */
    359	position = atc->pcm_capture_position(atc, apcm);
    360	position = bytes_to_frames(runtime, position);
    361	if (position >= runtime->buffer_size)
    362		position = 0;
    363	return position;
    364}
    365
    366/* PCM operators for playback */
    367static const struct snd_pcm_ops ct_pcm_playback_ops = {
    368	.open	 	= ct_pcm_playback_open,
    369	.close		= ct_pcm_playback_close,
    370	.hw_params	= ct_pcm_hw_params,
    371	.hw_free	= ct_pcm_hw_free,
    372	.prepare	= ct_pcm_playback_prepare,
    373	.trigger	= ct_pcm_playback_trigger,
    374	.pointer	= ct_pcm_playback_pointer,
    375};
    376
    377/* PCM operators for capture */
    378static const struct snd_pcm_ops ct_pcm_capture_ops = {
    379	.open	 	= ct_pcm_capture_open,
    380	.close		= ct_pcm_capture_close,
    381	.hw_params	= ct_pcm_hw_params,
    382	.hw_free	= ct_pcm_hw_free,
    383	.prepare	= ct_pcm_capture_prepare,
    384	.trigger	= ct_pcm_capture_trigger,
    385	.pointer	= ct_pcm_capture_pointer,
    386};
    387
    388static const struct snd_pcm_chmap_elem surround_map[] = {
    389	{ .channels = 1,
    390	  .map = { SNDRV_CHMAP_MONO } },
    391	{ .channels = 2,
    392	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
    393	{ }
    394};
    395
    396static const struct snd_pcm_chmap_elem clfe_map[] = {
    397	{ .channels = 1,
    398	  .map = { SNDRV_CHMAP_MONO } },
    399	{ .channels = 2,
    400	  .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
    401	{ }
    402};
    403
    404static const struct snd_pcm_chmap_elem side_map[] = {
    405	{ .channels = 1,
    406	  .map = { SNDRV_CHMAP_MONO } },
    407	{ .channels = 2,
    408	  .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
    409	{ }
    410};
    411
    412/* Create ALSA pcm device */
    413int ct_alsa_pcm_create(struct ct_atc *atc,
    414		       enum CTALSADEVS device,
    415		       const char *device_name)
    416{
    417	struct snd_pcm *pcm;
    418	const struct snd_pcm_chmap_elem *map;
    419	int chs;
    420	int err;
    421	int playback_count, capture_count;
    422
    423	playback_count = (IEC958 == device) ? 1 : 256;
    424	capture_count = (FRONT == device) ? 1 : 0;
    425	err = snd_pcm_new(atc->card, "ctxfi", device,
    426			  playback_count, capture_count, &pcm);
    427	if (err < 0) {
    428		dev_err(atc->card->dev, "snd_pcm_new failed!! Err=%d\n",
    429			err);
    430		return err;
    431	}
    432
    433	pcm->private_data = atc;
    434	pcm->info_flags = 0;
    435	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
    436	strscpy(pcm->name, device_name, sizeof(pcm->name));
    437
    438	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
    439
    440	if (FRONT == device)
    441		snd_pcm_set_ops(pcm,
    442				SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
    443
    444	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
    445				       &atc->pci->dev, 128*1024, 128*1024);
    446
    447	chs = 2;
    448	switch (device) {
    449	case FRONT:
    450		chs = 8;
    451		map = snd_pcm_std_chmaps;
    452		break;
    453	case SURROUND:
    454		map = surround_map;
    455		break;
    456	case CLFE:
    457		map = clfe_map;
    458		break;
    459	case SIDE:
    460		map = side_map;
    461		break;
    462	default:
    463		map = snd_pcm_std_chmaps;
    464		break;
    465	}
    466	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, chs,
    467				     0, NULL);
    468	if (err < 0)
    469		return err;
    470
    471#ifdef CONFIG_PM_SLEEP
    472	atc->pcms[device] = pcm;
    473#endif
    474
    475	return 0;
    476}