voice.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. #include <linux/time.h>
  11. #include <linux/export.h>
  12. #include <sound/core.h>
  13. #include <sound/emu10k1.h>
  14. /* Previously the voice allocator started at 0 every time. The new voice
  15. * allocator uses a round robin scheme. The next free voice is tracked in
  16. * the card record and each allocation begins where the last left off. The
  17. * hardware requires stereo interleaved voices be aligned to an even/odd
  18. * boundary.
  19. * --rlrevell
  20. */
  21. static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
  22. struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice)
  23. {
  24. struct snd_emu10k1_voice *voice;
  25. int i, j, k, skip;
  26. for (i = emu->next_free_voice, j = 0; j < NUM_G; i = (i + skip) % NUM_G, j += skip) {
  27. /*
  28. dev_dbg(emu->card->dev, "i %d j %d next free %d!\n",
  29. i, j, emu->next_free_voice);
  30. */
  31. /* stereo voices must be even/odd */
  32. if ((number > 1) && (i % 2)) {
  33. skip = 1;
  34. continue;
  35. }
  36. for (k = 0; k < number; k++) {
  37. voice = &emu->voices[i + k];
  38. if (voice->use) {
  39. skip = k + 1;
  40. goto next;
  41. }
  42. }
  43. for (k = 0; k < number; k++) {
  44. voice = &emu->voices[i + k];
  45. voice->use = type;
  46. voice->epcm = epcm;
  47. /* dev_dbg(emu->card->dev, "allocated voice %d\n", i + k); */
  48. }
  49. voice->last = 1;
  50. *rvoice = &emu->voices[i];
  51. emu->next_free_voice = (i + number) % NUM_G;
  52. return 0;
  53. next: ;
  54. }
  55. return -ENOMEM; // -EBUSY would have been better
  56. }
  57. static void voice_free(struct snd_emu10k1 *emu,
  58. struct snd_emu10k1_voice *pvoice)
  59. {
  60. if (pvoice->dirty)
  61. snd_emu10k1_voice_init(emu, pvoice->number);
  62. pvoice->interrupt = NULL;
  63. pvoice->use = pvoice->dirty = pvoice->last = 0;
  64. pvoice->epcm = NULL;
  65. }
  66. int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int channels,
  67. struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice)
  68. {
  69. unsigned long flags;
  70. int result;
  71. if (snd_BUG_ON(!rvoice))
  72. return -EINVAL;
  73. if (snd_BUG_ON(!count))
  74. return -EINVAL;
  75. if (snd_BUG_ON(!channels))
  76. return -EINVAL;
  77. spin_lock_irqsave(&emu->voice_lock, flags);
  78. for (int got = 0; got < channels; ) {
  79. result = voice_alloc(emu, type, count, epcm, &rvoice[got]);
  80. if (result == 0) {
  81. got++;
  82. /*
  83. dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n",
  84. rvoice[got - 1]->number, got, want);
  85. */
  86. continue;
  87. }
  88. if (type != EMU10K1_SYNTH && emu->get_synth_voice) {
  89. /* free a voice from synth */
  90. result = emu->get_synth_voice(emu);
  91. if (result >= 0) {
  92. voice_free(emu, &emu->voices[result]);
  93. continue;
  94. }
  95. }
  96. for (int i = 0; i < got; i++) {
  97. for (int j = 0; j < count; j++)
  98. voice_free(emu, rvoice[i] + j);
  99. rvoice[i] = NULL;
  100. }
  101. break;
  102. }
  103. spin_unlock_irqrestore(&emu->voice_lock, flags);
  104. return result;
  105. }
  106. EXPORT_SYMBOL(snd_emu10k1_voice_alloc);
  107. int snd_emu10k1_voice_free(struct snd_emu10k1 *emu,
  108. struct snd_emu10k1_voice *pvoice)
  109. {
  110. unsigned long flags;
  111. int last;
  112. if (snd_BUG_ON(!pvoice))
  113. return -EINVAL;
  114. spin_lock_irqsave(&emu->voice_lock, flags);
  115. do {
  116. last = pvoice->last;
  117. voice_free(emu, pvoice++);
  118. } while (!last);
  119. spin_unlock_irqrestore(&emu->voice_lock, flags);
  120. return 0;
  121. }
  122. EXPORT_SYMBOL(snd_emu10k1_voice_free);