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