bebob_midi.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * bebob_midi.c - a part of driver for BeBoB based devices
  4. *
  5. * Copyright (c) 2013-2014 Takashi Sakamoto
  6. */
  7. #include "bebob.h"
  8. static int midi_open(struct snd_rawmidi_substream *substream)
  9. {
  10. struct snd_bebob *bebob = substream->rmidi->private_data;
  11. int err;
  12. err = snd_bebob_stream_lock_try(bebob);
  13. if (err < 0)
  14. return err;
  15. mutex_lock(&bebob->mutex);
  16. err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0);
  17. if (err >= 0) {
  18. ++bebob->substreams_counter;
  19. err = snd_bebob_stream_start_duplex(bebob);
  20. if (err < 0)
  21. --bebob->substreams_counter;
  22. }
  23. mutex_unlock(&bebob->mutex);
  24. if (err < 0)
  25. snd_bebob_stream_lock_release(bebob);
  26. return err;
  27. }
  28. static int midi_close(struct snd_rawmidi_substream *substream)
  29. {
  30. struct snd_bebob *bebob = substream->rmidi->private_data;
  31. mutex_lock(&bebob->mutex);
  32. bebob->substreams_counter--;
  33. snd_bebob_stream_stop_duplex(bebob);
  34. mutex_unlock(&bebob->mutex);
  35. snd_bebob_stream_lock_release(bebob);
  36. return 0;
  37. }
  38. static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
  39. {
  40. struct snd_bebob *bebob = substrm->rmidi->private_data;
  41. unsigned long flags;
  42. spin_lock_irqsave(&bebob->lock, flags);
  43. if (up)
  44. amdtp_am824_midi_trigger(&bebob->tx_stream,
  45. substrm->number, substrm);
  46. else
  47. amdtp_am824_midi_trigger(&bebob->tx_stream,
  48. substrm->number, NULL);
  49. spin_unlock_irqrestore(&bebob->lock, flags);
  50. }
  51. static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
  52. {
  53. struct snd_bebob *bebob = substrm->rmidi->private_data;
  54. unsigned long flags;
  55. spin_lock_irqsave(&bebob->lock, flags);
  56. if (up)
  57. amdtp_am824_midi_trigger(&bebob->rx_stream,
  58. substrm->number, substrm);
  59. else
  60. amdtp_am824_midi_trigger(&bebob->rx_stream,
  61. substrm->number, NULL);
  62. spin_unlock_irqrestore(&bebob->lock, flags);
  63. }
  64. static void set_midi_substream_names(struct snd_bebob *bebob,
  65. struct snd_rawmidi_str *str)
  66. {
  67. struct snd_rawmidi_substream *subs;
  68. list_for_each_entry(subs, &str->substreams, list) {
  69. scnprintf(subs->name, sizeof(subs->name),
  70. "%s MIDI %d",
  71. bebob->card->shortname, subs->number + 1);
  72. }
  73. }
  74. int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
  75. {
  76. static const struct snd_rawmidi_ops capture_ops = {
  77. .open = midi_open,
  78. .close = midi_close,
  79. .trigger = midi_capture_trigger,
  80. };
  81. static const struct snd_rawmidi_ops playback_ops = {
  82. .open = midi_open,
  83. .close = midi_close,
  84. .trigger = midi_playback_trigger,
  85. };
  86. struct snd_rawmidi *rmidi;
  87. struct snd_rawmidi_str *str;
  88. int err;
  89. /* create midi ports */
  90. err = snd_rawmidi_new(bebob->card, bebob->card->driver, 0,
  91. bebob->midi_output_ports, bebob->midi_input_ports,
  92. &rmidi);
  93. if (err < 0)
  94. return err;
  95. snprintf(rmidi->name, sizeof(rmidi->name),
  96. "%s MIDI", bebob->card->shortname);
  97. rmidi->private_data = bebob;
  98. if (bebob->midi_input_ports > 0) {
  99. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
  100. snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
  101. &capture_ops);
  102. str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
  103. set_midi_substream_names(bebob, str);
  104. }
  105. if (bebob->midi_output_ports > 0) {
  106. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
  107. snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
  108. &playback_ops);
  109. str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
  110. set_midi_substream_names(bebob, str);
  111. }
  112. if ((bebob->midi_output_ports > 0) && (bebob->midi_input_ports > 0))
  113. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
  114. return 0;
  115. }