Changeset 772 for GPL/trunk/alsa-kernel/pci/emu10k1/voice.c
- Timestamp:
- Apr 19, 2025, 8:08:37 PM (4 months ago)
- Location:
- GPL/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GPL/trunk
- Property svn:mergeinfo changed
/GPL/branches/uniaud32-6.6-LTS (added) merged: 765,768-769 /GPL/branches/uniaud32-exp (added) merged: 735-741,743-744,748-751,753-760,762-764 /GPL/branches/uniaud32-next merged: 718-734
- Property svn:mergeinfo changed
-
GPL/trunk/alsa-kernel/pci/emu10k1/voice.c
r679 r772 2 2 /* 3 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * Lee Revell <rlrevell@joe-job.com> 5 * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> 4 6 * Creative Labs, Inc. 5 * Lee Revell <rlrevell@joe-job.com>7 * 6 8 * Routines for control of EMU10K1 chips - voice manager 7 *8 * Rewrote voice allocator for multichannel support - rlrevell 12/20049 *10 * BUGS:11 * --12 *13 * TODO:14 * --15 9 */ 16 10 … … 24 18 * the card record and each allocation begins where the last left off. The 25 19 * 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. 20 * boundary. 31 21 * --rlrevell 32 22 */ 33 23 34 24 static int voice_alloc(struct snd_emu10k1 *emu, int type, int number, 35 struct snd_emu10k1_ voice **rvoice)25 struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice) 36 26 { 37 27 struct snd_emu10k1_voice *voice; 38 int i, j, k, first_voice, last_voice,skip;28 int i, j, k, skip; 39 29 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) { 30 for (i = emu->next_free_voice, j = 0; j < NUM_G; i = (i + skip) % NUM_G, j += skip) { 43 31 /* 44 32 dev_dbg(emu->card->dev, "i %d j %d next free %d!\n", 45 33 i, j, emu->next_free_voice); 46 34 */ 47 i %= NUM_G;48 35 49 36 /* stereo voices must be even/odd */ 50 if ((number == 2) && (i % 2)) {51 i++;37 if ((number > 1) && (i % 2)) { 38 skip = 1; 52 39 continue; 53 40 } 54 55 skip = 0; 41 56 42 for (k = 0; k < number; k++) { 57 voice = &emu->voices[ (i+k) % NUM_G];43 voice = &emu->voices[i + k]; 58 44 if (voice->use) { 59 skip = 1;60 break;45 skip = k + 1; 46 goto next; 61 47 } 62 48 } 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;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); */ 69 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: ; 70 63 } 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; 64 return -ENOMEM; // -EBUSY would have been better 99 65 } 100 66 101 int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number, 102 struct snd_emu10k1_voice **rvoice) 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) 103 79 { 104 80 unsigned long flags; … … 107 83 if (snd_BUG_ON(!rvoice)) 108 84 return -EINVAL; 109 if (snd_BUG_ON(!number)) 85 if (snd_BUG_ON(!count)) 86 return -EINVAL; 87 if (snd_BUG_ON(!channels)) 110 88 return -EINVAL; 111 89 112 90 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) { 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 */ 120 103 result = emu->get_synth_voice(emu); 121 104 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; 105 voice_free(emu, &emu->voices[result]); 106 continue; 126 107 } 127 108 } 128 if (result < 0) 129 break; 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; 130 115 } 131 116 spin_unlock_irqrestore(&emu->voice_lock, flags); … … 140 125 { 141 126 unsigned long flags; 127 int last; 142 128 143 129 if (snd_BUG_ON(!pvoice)) 144 130 return -EINVAL; 145 131 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);132 do { 133 last = pvoice->last; 134 voice_free(emu, pvoice++); 135 } while (!last); 150 136 spin_unlock_irqrestore(&emu->voice_lock, flags); 151 137 return 0;
Note:
See TracChangeset
for help on using the changeset viewer.