oxfw-midi.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * oxfw_midi.c - a part of driver for OXFW970/971 based devices
  4. *
  5. * Copyright (c) 2014 Takashi Sakamoto
  6. */
  7. #include "oxfw.h"
  8. static int midi_capture_open(struct snd_rawmidi_substream *substream)
  9. {
  10. struct snd_oxfw *oxfw = substream->rmidi->private_data;
  11. int err;
  12. err = snd_oxfw_stream_lock_try(oxfw);
  13. if (err < 0)
  14. return err;
  15. mutex_lock(&oxfw->mutex);
  16. err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0);
  17. if (err >= 0) {
  18. ++oxfw->substreams_count;
  19. err = snd_oxfw_stream_start_duplex(oxfw);
  20. if (err < 0)
  21. --oxfw->substreams_count;
  22. }
  23. mutex_unlock(&oxfw->mutex);
  24. if (err < 0)
  25. snd_oxfw_stream_lock_release(oxfw);
  26. return err;
  27. }
  28. static int midi_playback_open(struct snd_rawmidi_substream *substream)
  29. {
  30. struct snd_oxfw *oxfw = substream->rmidi->private_data;
  31. int err;
  32. err = snd_oxfw_stream_lock_try(oxfw);
  33. if (err < 0)
  34. return err;
  35. mutex_lock(&oxfw->mutex);
  36. err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0);
  37. if (err >= 0) {
  38. ++oxfw->substreams_count;
  39. err = snd_oxfw_stream_start_duplex(oxfw);
  40. }
  41. mutex_unlock(&oxfw->mutex);
  42. if (err < 0)
  43. snd_oxfw_stream_lock_release(oxfw);
  44. return err;
  45. }
  46. static int midi_capture_close(struct snd_rawmidi_substream *substream)
  47. {
  48. struct snd_oxfw *oxfw = substream->rmidi->private_data;
  49. mutex_lock(&oxfw->mutex);
  50. --oxfw->substreams_count;
  51. snd_oxfw_stream_stop_duplex(oxfw);
  52. mutex_unlock(&oxfw->mutex);
  53. snd_oxfw_stream_lock_release(oxfw);
  54. return 0;
  55. }
  56. static int midi_playback_close(struct snd_rawmidi_substream *substream)
  57. {
  58. struct snd_oxfw *oxfw = substream->rmidi->private_data;
  59. mutex_lock(&oxfw->mutex);
  60. --oxfw->substreams_count;
  61. snd_oxfw_stream_stop_duplex(oxfw);
  62. mutex_unlock(&oxfw->mutex);
  63. snd_oxfw_stream_lock_release(oxfw);
  64. return 0;
  65. }
  66. static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
  67. {
  68. struct snd_oxfw *oxfw = substrm->rmidi->private_data;
  69. unsigned long flags;
  70. spin_lock_irqsave(&oxfw->lock, flags);
  71. if (up)
  72. amdtp_am824_midi_trigger(&oxfw->tx_stream,
  73. substrm->number, substrm);
  74. else
  75. amdtp_am824_midi_trigger(&oxfw->tx_stream,
  76. substrm->number, NULL);
  77. spin_unlock_irqrestore(&oxfw->lock, flags);
  78. }
  79. static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
  80. {
  81. struct snd_oxfw *oxfw = substrm->rmidi->private_data;
  82. unsigned long flags;
  83. spin_lock_irqsave(&oxfw->lock, flags);
  84. if (up)
  85. amdtp_am824_midi_trigger(&oxfw->rx_stream,
  86. substrm->number, substrm);
  87. else
  88. amdtp_am824_midi_trigger(&oxfw->rx_stream,
  89. substrm->number, NULL);
  90. spin_unlock_irqrestore(&oxfw->lock, flags);
  91. }
  92. static void set_midi_substream_names(struct snd_oxfw *oxfw,
  93. struct snd_rawmidi_str *str)
  94. {
  95. struct snd_rawmidi_substream *subs;
  96. list_for_each_entry(subs, &str->substreams, list) {
  97. scnprintf(subs->name, sizeof(subs->name),
  98. "%s MIDI %d",
  99. oxfw->card->shortname, subs->number + 1);
  100. }
  101. }
  102. int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
  103. {
  104. static const struct snd_rawmidi_ops capture_ops = {
  105. .open = midi_capture_open,
  106. .close = midi_capture_close,
  107. .trigger = midi_capture_trigger,
  108. };
  109. static const struct snd_rawmidi_ops playback_ops = {
  110. .open = midi_playback_open,
  111. .close = midi_playback_close,
  112. .trigger = midi_playback_trigger,
  113. };
  114. struct snd_rawmidi *rmidi;
  115. struct snd_rawmidi_str *str;
  116. int err;
  117. if (oxfw->midi_input_ports == 0 && oxfw->midi_output_ports == 0)
  118. return 0;
  119. /* create midi ports */
  120. err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0,
  121. oxfw->midi_output_ports, oxfw->midi_input_ports,
  122. &rmidi);
  123. if (err < 0)
  124. return err;
  125. snprintf(rmidi->name, sizeof(rmidi->name),
  126. "%s MIDI", oxfw->card->shortname);
  127. rmidi->private_data = oxfw;
  128. if (oxfw->midi_input_ports > 0) {
  129. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
  130. snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
  131. &capture_ops);
  132. str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
  133. set_midi_substream_names(oxfw, str);
  134. }
  135. if (oxfw->midi_output_ports > 0) {
  136. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
  137. snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
  138. &playback_ops);
  139. str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
  140. set_midi_substream_names(oxfw, str);
  141. }
  142. if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0))
  143. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
  144. return 0;
  145. }