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

voice.c (3965B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      4 *                   Creative Labs, Inc.
      5 *                   Lee Revell <rlrevell@joe-job.com>
      6 *  Routines for control of EMU10K1 chips - voice manager
      7 *
      8 *  Rewrote voice allocator for multichannel support - rlrevell 12/2004
      9 * 
     10 *  BUGS:
     11 *    --
     12 *
     13 *  TODO:
     14 *    --
     15 */
     16
     17#include <linux/time.h>
     18#include <linux/export.h>
     19#include <sound/core.h>
     20#include <sound/emu10k1.h>
     21
     22/* Previously the voice allocator started at 0 every time.  The new voice 
     23 * allocator uses a round robin scheme.  The next free voice is tracked in 
     24 * the card record and each allocation begins where the last left off.  The 
     25 * hardware requires stereo interleaved voices be aligned to an even/odd 
     26 * boundary.  For multichannel voice allocation we ensure than the block of 
     27 * voices does not cross the 32 voice boundary.  This simplifies the 
     28 * multichannel support and ensures we can use a single write to the 
     29 * (set|clear)_loop_stop registers.  Otherwise (for example) the voices would 
     30 * get out of sync when pausing/resuming a stream.
     31 *							--rlrevell
     32 */
     33
     34static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
     35		       struct snd_emu10k1_voice **rvoice)
     36{
     37	struct snd_emu10k1_voice *voice;
     38	int i, j, k, first_voice, last_voice, skip;
     39
     40	*rvoice = NULL;
     41	first_voice = last_voice = 0;
     42	for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) {
     43		/*
     44		dev_dbg(emu->card->dev, "i %d j %d next free %d!\n",
     45		       i, j, emu->next_free_voice);
     46		*/
     47		i %= NUM_G;
     48
     49		/* stereo voices must be even/odd */
     50		if ((number == 2) && (i % 2)) {
     51			i++;
     52			continue;
     53		}
     54			
     55		skip = 0;
     56		for (k = 0; k < number; k++) {
     57			voice = &emu->voices[(i+k) % NUM_G];
     58			if (voice->use) {
     59				skip = 1;
     60				break;
     61			}
     62		}
     63		if (!skip) {
     64			/* dev_dbg(emu->card->dev, "allocated voice %d\n", i); */
     65			first_voice = i;
     66			last_voice = (i + number) % NUM_G;
     67			emu->next_free_voice = last_voice;
     68			break;
     69		}
     70	}
     71	
     72	if (first_voice == last_voice)
     73		return -ENOMEM;
     74	
     75	for (i = 0; i < number; i++) {
     76		voice = &emu->voices[(first_voice + i) % NUM_G];
     77		/*
     78		dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n",
     79		       voice->number, idx-first_voice+1, number);
     80		*/
     81		voice->use = 1;
     82		switch (type) {
     83		case EMU10K1_PCM:
     84			voice->pcm = 1;
     85			break;
     86		case EMU10K1_SYNTH:
     87			voice->synth = 1;
     88			break;
     89		case EMU10K1_MIDI:
     90			voice->midi = 1;
     91			break;
     92		case EMU10K1_EFX:
     93			voice->efx = 1;
     94			break;
     95		}
     96	}
     97	*rvoice = &emu->voices[first_voice];
     98	return 0;
     99}
    100
    101int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number,
    102			    struct snd_emu10k1_voice **rvoice)
    103{
    104	unsigned long flags;
    105	int result;
    106
    107	if (snd_BUG_ON(!rvoice))
    108		return -EINVAL;
    109	if (snd_BUG_ON(!number))
    110		return -EINVAL;
    111
    112	spin_lock_irqsave(&emu->voice_lock, flags);
    113	for (;;) {
    114		result = voice_alloc(emu, type, number, rvoice);
    115		if (result == 0 || type == EMU10K1_SYNTH || type == EMU10K1_MIDI)
    116			break;
    117
    118		/* free a voice from synth */
    119		if (emu->get_synth_voice) {
    120			result = emu->get_synth_voice(emu);
    121			if (result >= 0) {
    122				struct snd_emu10k1_voice *pvoice = &emu->voices[result];
    123				pvoice->interrupt = NULL;
    124				pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0;
    125				pvoice->epcm = NULL;
    126			}
    127		}
    128		if (result < 0)
    129			break;
    130	}
    131	spin_unlock_irqrestore(&emu->voice_lock, flags);
    132
    133	return result;
    134}
    135
    136EXPORT_SYMBOL(snd_emu10k1_voice_alloc);
    137
    138int snd_emu10k1_voice_free(struct snd_emu10k1 *emu,
    139			   struct snd_emu10k1_voice *pvoice)
    140{
    141	unsigned long flags;
    142
    143	if (snd_BUG_ON(!pvoice))
    144		return -EINVAL;
    145	spin_lock_irqsave(&emu->voice_lock, flags);
    146	pvoice->interrupt = NULL;
    147	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0;
    148	pvoice->epcm = NULL;
    149	snd_emu10k1_voice_init(emu, pvoice->number);
    150	spin_unlock_irqrestore(&emu->voice_lock, flags);
    151	return 0;
    152}
    153
    154EXPORT_SYMBOL(snd_emu10k1_voice_free);