Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * fireworks_midi.c - a part of driver for Fireworks based devices
  4 *
  5 * Copyright (c) 2009-2010 Clemens Ladisch
  6 * Copyright (c) 2013-2014 Takashi Sakamoto
  7 */
  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	else
 58		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	else
 75		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}