1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * Lee Revell <rlrevell@joe-job.com> 5 * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> 6 * Creative Labs, Inc. 7 * 8 * Routines for control of EMU10K1 chips - voice manager 9 */ 10 11 #include <linux/time.h> 12 #include <linux/export.h> 13 #include <sound/core.h> 14 #include <sound/emu10k1.h> 15 16 /* Previously the voice allocator started at 0 every time. The new voice 17 * allocator uses a round robin scheme. The next free voice is tracked in 18 * the card record and each allocation begins where the last left off. The 19 * hardware requires stereo interleaved voices be aligned to an even/odd 20 * boundary. 21 * --rlrevell 22 */ 23 24 static int voice_alloc(struct snd_emu10k1 *emu, int type, int number, 25 struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice) 26 { 27 struct snd_emu10k1_voice *voice; 28 int i, j, k, skip; 29 30 for (i = emu->next_free_voice, j = 0; j < NUM_G; i = (i + skip) % NUM_G, j += skip) { 31 /* 32 dev_dbg(emu->card->dev, "i %d j %d next free %d!\n", 33 i, j, emu->next_free_voice); 34 */ 35 36 /* stereo voices must be even/odd */ 37 if ((number > 1) && (i % 2)) { 38 skip = 1; 39 continue; 40 } 41 42 for (k = 0; k < number; k++) { 43 voice = &emu->voices[i + k]; 44 if (voice->use) { 45 skip = k + 1; 46 goto next; 47 } 48 } 49 50 for (k = 0; k < number; k++) { 51 voice = &emu->voices[i + k]; 52 voice->use = type; 53 voice->epcm = epcm; 54 /* dev_dbg(emu->card->dev, "allocated voice %d\n", i + k); */ 55 } 56 voice->last = 1; 57 58 *rvoice = &emu->voices[i]; 59 emu->next_free_voice = (i + number) % NUM_G; 60 return 0; 61 62 next: ; 63 } 64 return -ENOMEM; // -EBUSY would have been better 65 } 66 67 static void voice_free(struct snd_emu10k1 *emu, 68 struct snd_emu10k1_voice *pvoice) 69 { 70 if (pvoice->dirty) 71 snd_emu10k1_voice_init(emu, pvoice->number); 72 pvoice->interrupt = NULL; 73 pvoice->use = pvoice->dirty = pvoice->last = 0; 74 pvoice->epcm = NULL; 75 } 76 77 int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int channels, 78 struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice) 79 { 80 unsigned long flags; 81 int result; 82 83 if (snd_BUG_ON(!rvoice)) 84 return -EINVAL; 85 if (snd_BUG_ON(!count)) 86 return -EINVAL; 87 if (snd_BUG_ON(!channels)) 88 return -EINVAL; 89 90 spin_lock_irqsave(&emu->voice_lock, flags); 91 for (int got = 0; got < channels; ) { 92 result = voice_alloc(emu, type, count, epcm, &rvoice[got]); 93 if (result == 0) { 94 got++; 95 /* 96 dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n", 97 rvoice[got - 1]->number, got, want); 98 */ 99 continue; 100 } 101 if (type != EMU10K1_SYNTH && emu->get_synth_voice) { 102 /* free a voice from synth */ 103 result = emu->get_synth_voice(emu); 104 if (result >= 0) { 105 voice_free(emu, &emu->voices[result]); 106 continue; 107 } 108 } 109 for (int i = 0; i < got; i++) { 110 for (int j = 0; j < count; j++) 111 voice_free(emu, rvoice[i] + j); 112 rvoice[i] = NULL; 113 } 114 break; 115 } 116 spin_unlock_irqrestore(&emu->voice_lock, flags); 117 118 return result; 119 } 120 121 EXPORT_SYMBOL(snd_emu10k1_voice_alloc); 122 123 int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, 124 struct snd_emu10k1_voice *pvoice) 125 { 126 unsigned long flags; 127 int last; 128 129 if (snd_BUG_ON(!pvoice)) 130 return -EINVAL; 131 spin_lock_irqsave(&emu->voice_lock, flags); 132 do { 133 last = pvoice->last; 134 voice_free(emu, pvoice++); 135 } while (!last); 136 spin_unlock_irqrestore(&emu->voice_lock, flags); 137 return 0; 138 } 139 140 EXPORT_SYMBOL(snd_emu10k1_voice_free); 141