ff-midi.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * ff-midi.c - a part of driver for RME Fireface series
  4. *
  5. * Copyright (c) 2015-2017 Takashi Sakamoto
  6. */
  7. #include "ff.h"
  8. static int midi_capture_open(struct snd_rawmidi_substream *substream)
  9. {
  10. /* Do nothing. */
  11. return 0;
  12. }
  13. static int midi_playback_open(struct snd_rawmidi_substream *substream)
  14. {
  15. struct snd_ff *ff = substream->rmidi->private_data;
  16. /* Initialize internal status. */
  17. ff->on_sysex[substream->number] = 0;
  18. ff->rx_midi_error[substream->number] = false;
  19. WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream);
  20. return 0;
  21. }
  22. static int midi_capture_close(struct snd_rawmidi_substream *substream)
  23. {
  24. /* Do nothing. */
  25. return 0;
  26. }
  27. static int midi_playback_close(struct snd_rawmidi_substream *substream)
  28. {
  29. struct snd_ff *ff = substream->rmidi->private_data;
  30. cancel_work_sync(&ff->rx_midi_work[substream->number]);
  31. WRITE_ONCE(ff->rx_midi_substreams[substream->number], NULL);
  32. return 0;
  33. }
  34. static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
  35. int up)
  36. {
  37. struct snd_ff *ff = substream->rmidi->private_data;
  38. unsigned long flags;
  39. spin_lock_irqsave(&ff->lock, flags);
  40. if (up)
  41. WRITE_ONCE(ff->tx_midi_substreams[substream->number],
  42. substream);
  43. else
  44. WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL);
  45. spin_unlock_irqrestore(&ff->lock, flags);
  46. }
  47. static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
  48. int up)
  49. {
  50. struct snd_ff *ff = substream->rmidi->private_data;
  51. unsigned long flags;
  52. spin_lock_irqsave(&ff->lock, flags);
  53. if (up || !ff->rx_midi_error[substream->number])
  54. schedule_work(&ff->rx_midi_work[substream->number]);
  55. spin_unlock_irqrestore(&ff->lock, flags);
  56. }
  57. static void set_midi_substream_names(struct snd_rawmidi_str *stream,
  58. const char *const name)
  59. {
  60. struct snd_rawmidi_substream *substream;
  61. list_for_each_entry(substream, &stream->substreams, list) {
  62. scnprintf(substream->name, sizeof(substream->name),
  63. "%s MIDI %d", name, substream->number + 1);
  64. }
  65. }
  66. int snd_ff_create_midi_devices(struct snd_ff *ff)
  67. {
  68. static const struct snd_rawmidi_ops midi_capture_ops = {
  69. .open = midi_capture_open,
  70. .close = midi_capture_close,
  71. .trigger = midi_capture_trigger,
  72. };
  73. static const struct snd_rawmidi_ops midi_playback_ops = {
  74. .open = midi_playback_open,
  75. .close = midi_playback_close,
  76. .trigger = midi_playback_trigger,
  77. };
  78. struct snd_rawmidi *rmidi;
  79. struct snd_rawmidi_str *stream;
  80. int err;
  81. err = snd_rawmidi_new(ff->card, ff->card->driver, 0,
  82. ff->spec->midi_out_ports, ff->spec->midi_in_ports,
  83. &rmidi);
  84. if (err < 0)
  85. return err;
  86. snprintf(rmidi->name, sizeof(rmidi->name),
  87. "%s MIDI", ff->card->shortname);
  88. rmidi->private_data = ff;
  89. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
  90. snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
  91. &midi_capture_ops);
  92. stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
  93. set_midi_substream_names(stream, ff->card->shortname);
  94. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
  95. snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
  96. &midi_playback_ops);
  97. stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
  98. set_midi_substream_names(stream, ff->card->shortname);
  99. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
  100. return 0;
  101. }