digi00x-midi.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family
  3. *
  4. * Copyright (c) 2014-2015 Takashi Sakamoto
  5. *
  6. * Licensed under the terms of the GNU General Public License, version 2.
  7. */
  8. #include "digi00x.h"
  9. static int midi_phys_open(struct snd_rawmidi_substream *substream)
  10. {
  11. struct snd_dg00x *dg00x = substream->rmidi->private_data;
  12. int err;
  13. err = snd_dg00x_stream_lock_try(dg00x);
  14. if (err < 0)
  15. return err;
  16. mutex_lock(&dg00x->mutex);
  17. dg00x->substreams_counter++;
  18. err = snd_dg00x_stream_start_duplex(dg00x, 0);
  19. mutex_unlock(&dg00x->mutex);
  20. if (err < 0)
  21. snd_dg00x_stream_lock_release(dg00x);
  22. return err;
  23. }
  24. static int midi_phys_close(struct snd_rawmidi_substream *substream)
  25. {
  26. struct snd_dg00x *dg00x = substream->rmidi->private_data;
  27. mutex_lock(&dg00x->mutex);
  28. dg00x->substreams_counter--;
  29. snd_dg00x_stream_stop_duplex(dg00x);
  30. mutex_unlock(&dg00x->mutex);
  31. snd_dg00x_stream_lock_release(dg00x);
  32. return 0;
  33. }
  34. static void midi_phys_capture_trigger(struct snd_rawmidi_substream *substream,
  35. int up)
  36. {
  37. struct snd_dg00x *dg00x = substream->rmidi->private_data;
  38. unsigned long flags;
  39. spin_lock_irqsave(&dg00x->lock, flags);
  40. if (up)
  41. amdtp_dot_midi_trigger(&dg00x->tx_stream, substream->number,
  42. substream);
  43. else
  44. amdtp_dot_midi_trigger(&dg00x->tx_stream, substream->number,
  45. NULL);
  46. spin_unlock_irqrestore(&dg00x->lock, flags);
  47. }
  48. static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream,
  49. int up)
  50. {
  51. struct snd_dg00x *dg00x = substream->rmidi->private_data;
  52. unsigned long flags;
  53. spin_lock_irqsave(&dg00x->lock, flags);
  54. if (up)
  55. amdtp_dot_midi_trigger(&dg00x->rx_stream, substream->number,
  56. substream);
  57. else
  58. amdtp_dot_midi_trigger(&dg00x->rx_stream, substream->number,
  59. NULL);
  60. spin_unlock_irqrestore(&dg00x->lock, flags);
  61. }
  62. static struct snd_rawmidi_ops midi_phys_capture_ops = {
  63. .open = midi_phys_open,
  64. .close = midi_phys_close,
  65. .trigger = midi_phys_capture_trigger,
  66. };
  67. static struct snd_rawmidi_ops midi_phys_playback_ops = {
  68. .open = midi_phys_open,
  69. .close = midi_phys_close,
  70. .trigger = midi_phys_playback_trigger,
  71. };
  72. static int midi_ctl_open(struct snd_rawmidi_substream *substream)
  73. {
  74. /* Do nothing. */
  75. return 0;
  76. }
  77. static int midi_ctl_capture_close(struct snd_rawmidi_substream *substream)
  78. {
  79. /* Do nothing. */
  80. return 0;
  81. }
  82. static int midi_ctl_playback_close(struct snd_rawmidi_substream *substream)
  83. {
  84. struct snd_dg00x *dg00x = substream->rmidi->private_data;
  85. snd_fw_async_midi_port_finish(&dg00x->out_control);
  86. return 0;
  87. }
  88. static void midi_ctl_capture_trigger(struct snd_rawmidi_substream *substream,
  89. int up)
  90. {
  91. struct snd_dg00x *dg00x = substream->rmidi->private_data;
  92. unsigned long flags;
  93. spin_lock_irqsave(&dg00x->lock, flags);
  94. if (up)
  95. dg00x->in_control = substream;
  96. else
  97. dg00x->in_control = NULL;
  98. spin_unlock_irqrestore(&dg00x->lock, flags);
  99. }
  100. static void midi_ctl_playback_trigger(struct snd_rawmidi_substream *substream,
  101. int up)
  102. {
  103. struct snd_dg00x *dg00x = substream->rmidi->private_data;
  104. unsigned long flags;
  105. spin_lock_irqsave(&dg00x->lock, flags);
  106. if (up)
  107. snd_fw_async_midi_port_run(&dg00x->out_control, substream);
  108. spin_unlock_irqrestore(&dg00x->lock, flags);
  109. }
  110. static struct snd_rawmidi_ops midi_ctl_capture_ops = {
  111. .open = midi_ctl_open,
  112. .close = midi_ctl_capture_close,
  113. .trigger = midi_ctl_capture_trigger,
  114. };
  115. static struct snd_rawmidi_ops midi_ctl_playback_ops = {
  116. .open = midi_ctl_open,
  117. .close = midi_ctl_playback_close,
  118. .trigger = midi_ctl_playback_trigger,
  119. };
  120. static void set_midi_substream_names(struct snd_dg00x *dg00x,
  121. struct snd_rawmidi_str *str,
  122. bool is_ctl)
  123. {
  124. struct snd_rawmidi_substream *subs;
  125. list_for_each_entry(subs, &str->substreams, list) {
  126. if (!is_ctl)
  127. snprintf(subs->name, sizeof(subs->name),
  128. "%s MIDI %d",
  129. dg00x->card->shortname, subs->number + 1);
  130. else
  131. /* This port is for asynchronous transaction. */
  132. snprintf(subs->name, sizeof(subs->name),
  133. "%s control",
  134. dg00x->card->shortname);
  135. }
  136. }
  137. int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
  138. {
  139. struct snd_rawmidi *rmidi[2];
  140. struct snd_rawmidi_str *str;
  141. unsigned int i;
  142. int err;
  143. /* Add physical midi ports. */
  144. err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 0,
  145. DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS, &rmidi[0]);
  146. if (err < 0)
  147. return err;
  148. snprintf(rmidi[0]->name, sizeof(rmidi[0]->name),
  149. "%s MIDI", dg00x->card->shortname);
  150. snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT,
  151. &midi_phys_capture_ops);
  152. snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT,
  153. &midi_phys_playback_ops);
  154. /* Add a pair of control midi ports. */
  155. err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 1,
  156. 1, 1, &rmidi[1]);
  157. if (err < 0)
  158. return err;
  159. snprintf(rmidi[1]->name, sizeof(rmidi[1]->name),
  160. "%s control", dg00x->card->shortname);
  161. snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_INPUT,
  162. &midi_ctl_capture_ops);
  163. snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_OUTPUT,
  164. &midi_ctl_playback_ops);
  165. for (i = 0; i < ARRAY_SIZE(rmidi); i++) {
  166. rmidi[i]->private_data = dg00x;
  167. rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
  168. str = &rmidi[i]->streams[SNDRV_RAWMIDI_STREAM_INPUT];
  169. set_midi_substream_names(dg00x, str, i);
  170. rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
  171. str = &rmidi[i]->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
  172. set_midi_substream_names(dg00x, str, i);
  173. rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
  174. }
  175. return 0;
  176. }