voice.c 3.9 KB

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