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