dice-midi.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * dice_midi.c - a part of driver for Dice based devices
  4. *
  5. * Copyright (c) 2014 Takashi Sakamoto
  6. */
  7. #include "dice.h"
  8. static int midi_open(struct snd_rawmidi_substream *substream)
  9. {
  10. struct snd_dice *dice = substream->rmidi->private_data;
  11. int err;
  12. err = snd_dice_stream_lock_try(dice);
  13. if (err < 0)
  14. return err;
  15. mutex_lock(&dice->mutex);
  16. err = snd_dice_stream_reserve_duplex(dice, 0, 0, 0);
  17. if (err >= 0) {
  18. ++dice->substreams_counter;
  19. err = snd_dice_stream_start_duplex(dice);
  20. if (err < 0)
  21. --dice->substreams_counter;
  22. }
  23. mutex_unlock(&dice->mutex);
  24. if (err < 0)
  25. snd_dice_stream_lock_release(dice);
  26. return err;
  27. }
  28. static int midi_close(struct snd_rawmidi_substream *substream)
  29. {
  30. struct snd_dice *dice = substream->rmidi->private_data;
  31. mutex_lock(&dice->mutex);
  32. --dice->substreams_counter;
  33. snd_dice_stream_stop_duplex(dice);
  34. mutex_unlock(&dice->mutex);
  35. snd_dice_stream_lock_release(dice);
  36. return 0;
  37. }
  38. static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
  39. {
  40. struct snd_dice *dice = substrm->rmidi->private_data;
  41. unsigned long flags;
  42. spin_lock_irqsave(&dice->lock, flags);
  43. if (up)
  44. amdtp_am824_midi_trigger(&dice->tx_stream[0],
  45. substrm->number, substrm);
  46. else
  47. amdtp_am824_midi_trigger(&dice->tx_stream[0],
  48. substrm->number, NULL);
  49. spin_unlock_irqrestore(&dice->lock, flags);
  50. }
  51. static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
  52. {
  53. struct snd_dice *dice = substrm->rmidi->private_data;
  54. unsigned long flags;
  55. spin_lock_irqsave(&dice->lock, flags);
  56. if (up)
  57. amdtp_am824_midi_trigger(&dice->rx_stream[0],
  58. substrm->number, substrm);
  59. else
  60. amdtp_am824_midi_trigger(&dice->rx_stream[0],
  61. substrm->number, NULL);
  62. spin_unlock_irqrestore(&dice->lock, flags);
  63. }
  64. static void set_midi_substream_names(struct snd_dice *dice,
  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", dice->card->shortname, subs->number + 1);
  71. }
  72. }
  73. int snd_dice_create_midi(struct snd_dice *dice)
  74. {
  75. static const struct snd_rawmidi_ops capture_ops = {
  76. .open = midi_open,
  77. .close = midi_close,
  78. .trigger = midi_capture_trigger,
  79. };
  80. static const struct snd_rawmidi_ops playback_ops = {
  81. .open = midi_open,
  82. .close = midi_close,
  83. .trigger = midi_playback_trigger,
  84. };
  85. struct snd_rawmidi *rmidi;
  86. struct snd_rawmidi_str *str;
  87. unsigned int midi_in_ports, midi_out_ports;
  88. int i;
  89. int err;
  90. midi_in_ports = 0;
  91. midi_out_ports = 0;
  92. for (i = 0; i < MAX_STREAMS; ++i) {
  93. midi_in_ports = max(midi_in_ports, dice->tx_midi_ports[i]);
  94. midi_out_ports = max(midi_out_ports, dice->rx_midi_ports[i]);
  95. }
  96. if (midi_in_ports + midi_out_ports == 0)
  97. return 0;
  98. /* create midi ports */
  99. err = snd_rawmidi_new(dice->card, dice->card->driver, 0,
  100. midi_out_ports, midi_in_ports,
  101. &rmidi);
  102. if (err < 0)
  103. return err;
  104. snprintf(rmidi->name, sizeof(rmidi->name),
  105. "%s MIDI", dice->card->shortname);
  106. rmidi->private_data = dice;
  107. if (midi_in_ports > 0) {
  108. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
  109. snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
  110. &capture_ops);
  111. str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
  112. set_midi_substream_names(dice, str);
  113. }
  114. if (midi_out_ports > 0) {
  115. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
  116. snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
  117. &playback_ops);
  118. str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
  119. set_midi_substream_names(dice, str);
  120. }
  121. if ((midi_out_ports > 0) && (midi_in_ports > 0))
  122. rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
  123. return 0;
  124. }