root/sound/pci/emu10k1/voice.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. voice_alloc
  2. snd_emu10k1_voice_alloc
  3. snd_emu10k1_voice_free

   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 
  34 static 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 
 101 int 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 
 136 EXPORT_SYMBOL(snd_emu10k1_voice_alloc);
 137 
 138 int 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 
 154 EXPORT_SYMBOL(snd_emu10k1_voice_free);

/* [<][>][^][v][top][bottom][index][help] */