xref: /openbmc/linux/sound/firewire/oxfw/oxfw-midi.c (revision ea77850e)
1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
205588d34STakashi Sakamoto /*
305588d34STakashi Sakamoto  * oxfw_midi.c - a part of driver for OXFW970/971 based devices
405588d34STakashi Sakamoto  *
505588d34STakashi Sakamoto  * Copyright (c) 2014 Takashi Sakamoto
605588d34STakashi Sakamoto  */
705588d34STakashi Sakamoto 
805588d34STakashi Sakamoto #include "oxfw.h"
905588d34STakashi Sakamoto 
midi_capture_open(struct snd_rawmidi_substream * substream)1005588d34STakashi Sakamoto static int midi_capture_open(struct snd_rawmidi_substream *substream)
1105588d34STakashi Sakamoto {
1205588d34STakashi Sakamoto 	struct snd_oxfw *oxfw = substream->rmidi->private_data;
1305588d34STakashi Sakamoto 	int err;
1405588d34STakashi Sakamoto 
158985f4acSTakashi Sakamoto 	err = snd_oxfw_stream_lock_try(oxfw);
168985f4acSTakashi Sakamoto 	if (err < 0)
178985f4acSTakashi Sakamoto 		return err;
188985f4acSTakashi Sakamoto 
1905588d34STakashi Sakamoto 	mutex_lock(&oxfw->mutex);
2005588d34STakashi Sakamoto 
213299d2a0STakashi Sakamoto 	err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0);
224f380d00STakashi Sakamoto 	if (err >= 0) {
234a0a0472STakashi Sakamoto 		++oxfw->substreams_count;
244f380d00STakashi Sakamoto 		err = snd_oxfw_stream_start_duplex(oxfw);
2503a954aeSTakashi Sakamoto 		if (err < 0)
2603a954aeSTakashi Sakamoto 			--oxfw->substreams_count;
274f380d00STakashi Sakamoto 	}
2805588d34STakashi Sakamoto 
2905588d34STakashi Sakamoto 	mutex_unlock(&oxfw->mutex);
3005588d34STakashi Sakamoto 
318985f4acSTakashi Sakamoto 	if (err < 0)
328985f4acSTakashi Sakamoto 		snd_oxfw_stream_lock_release(oxfw);
338985f4acSTakashi Sakamoto 
3405588d34STakashi Sakamoto 	return err;
3505588d34STakashi Sakamoto }
3605588d34STakashi Sakamoto 
midi_playback_open(struct snd_rawmidi_substream * substream)3705588d34STakashi Sakamoto static int midi_playback_open(struct snd_rawmidi_substream *substream)
3805588d34STakashi Sakamoto {
3905588d34STakashi Sakamoto 	struct snd_oxfw *oxfw = substream->rmidi->private_data;
4005588d34STakashi Sakamoto 	int err;
4105588d34STakashi Sakamoto 
428985f4acSTakashi Sakamoto 	err = snd_oxfw_stream_lock_try(oxfw);
438985f4acSTakashi Sakamoto 	if (err < 0)
448985f4acSTakashi Sakamoto 		return err;
458985f4acSTakashi Sakamoto 
4605588d34STakashi Sakamoto 	mutex_lock(&oxfw->mutex);
4705588d34STakashi Sakamoto 
483299d2a0STakashi Sakamoto 	err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0);
494f380d00STakashi Sakamoto 	if (err >= 0) {
504a0a0472STakashi Sakamoto 		++oxfw->substreams_count;
514f380d00STakashi Sakamoto 		err = snd_oxfw_stream_start_duplex(oxfw);
524f380d00STakashi Sakamoto 	}
5305588d34STakashi Sakamoto 
5405588d34STakashi Sakamoto 	mutex_unlock(&oxfw->mutex);
5505588d34STakashi Sakamoto 
568985f4acSTakashi Sakamoto 	if (err < 0)
578985f4acSTakashi Sakamoto 		snd_oxfw_stream_lock_release(oxfw);
588985f4acSTakashi Sakamoto 
5905588d34STakashi Sakamoto 	return err;
6005588d34STakashi Sakamoto }
6105588d34STakashi Sakamoto 
midi_capture_close(struct snd_rawmidi_substream * substream)6205588d34STakashi Sakamoto static int midi_capture_close(struct snd_rawmidi_substream *substream)
6305588d34STakashi Sakamoto {
6405588d34STakashi Sakamoto 	struct snd_oxfw *oxfw = substream->rmidi->private_data;
6505588d34STakashi Sakamoto 
6605588d34STakashi Sakamoto 	mutex_lock(&oxfw->mutex);
6705588d34STakashi Sakamoto 
684a0a0472STakashi Sakamoto 	--oxfw->substreams_count;
69779f0dbaSTakashi Sakamoto 	snd_oxfw_stream_stop_duplex(oxfw);
7005588d34STakashi Sakamoto 
7105588d34STakashi Sakamoto 	mutex_unlock(&oxfw->mutex);
7205588d34STakashi Sakamoto 
738985f4acSTakashi Sakamoto 	snd_oxfw_stream_lock_release(oxfw);
7405588d34STakashi Sakamoto 	return 0;
7505588d34STakashi Sakamoto }
7605588d34STakashi Sakamoto 
midi_playback_close(struct snd_rawmidi_substream * substream)7705588d34STakashi Sakamoto static int midi_playback_close(struct snd_rawmidi_substream *substream)
7805588d34STakashi Sakamoto {
7905588d34STakashi Sakamoto 	struct snd_oxfw *oxfw = substream->rmidi->private_data;
8005588d34STakashi Sakamoto 
8105588d34STakashi Sakamoto 	mutex_lock(&oxfw->mutex);
8205588d34STakashi Sakamoto 
834a0a0472STakashi Sakamoto 	--oxfw->substreams_count;
84779f0dbaSTakashi Sakamoto 	snd_oxfw_stream_stop_duplex(oxfw);
8505588d34STakashi Sakamoto 
8605588d34STakashi Sakamoto 	mutex_unlock(&oxfw->mutex);
8705588d34STakashi Sakamoto 
888985f4acSTakashi Sakamoto 	snd_oxfw_stream_lock_release(oxfw);
8905588d34STakashi Sakamoto 	return 0;
9005588d34STakashi Sakamoto }
9105588d34STakashi Sakamoto 
midi_capture_trigger(struct snd_rawmidi_substream * substrm,int up)9205588d34STakashi Sakamoto static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
9305588d34STakashi Sakamoto {
9405588d34STakashi Sakamoto 	struct snd_oxfw *oxfw = substrm->rmidi->private_data;
9505588d34STakashi Sakamoto 	unsigned long flags;
9605588d34STakashi Sakamoto 
9705588d34STakashi Sakamoto 	spin_lock_irqsave(&oxfw->lock, flags);
9805588d34STakashi Sakamoto 
9905588d34STakashi Sakamoto 	if (up)
10003e2a67eSTakashi Sakamoto 		amdtp_am824_midi_trigger(&oxfw->tx_stream,
10105588d34STakashi Sakamoto 					 substrm->number, substrm);
10205588d34STakashi Sakamoto 	else
10303e2a67eSTakashi Sakamoto 		amdtp_am824_midi_trigger(&oxfw->tx_stream,
10405588d34STakashi Sakamoto 					 substrm->number, NULL);
10505588d34STakashi Sakamoto 
10605588d34STakashi Sakamoto 	spin_unlock_irqrestore(&oxfw->lock, flags);
10705588d34STakashi Sakamoto }
10805588d34STakashi Sakamoto 
midi_playback_trigger(struct snd_rawmidi_substream * substrm,int up)10905588d34STakashi Sakamoto static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
11005588d34STakashi Sakamoto {
11105588d34STakashi Sakamoto 	struct snd_oxfw *oxfw = substrm->rmidi->private_data;
11205588d34STakashi Sakamoto 	unsigned long flags;
11305588d34STakashi Sakamoto 
11405588d34STakashi Sakamoto 	spin_lock_irqsave(&oxfw->lock, flags);
11505588d34STakashi Sakamoto 
11605588d34STakashi Sakamoto 	if (up)
11703e2a67eSTakashi Sakamoto 		amdtp_am824_midi_trigger(&oxfw->rx_stream,
11805588d34STakashi Sakamoto 					 substrm->number, substrm);
11905588d34STakashi Sakamoto 	else
12003e2a67eSTakashi Sakamoto 		amdtp_am824_midi_trigger(&oxfw->rx_stream,
12105588d34STakashi Sakamoto 					 substrm->number, NULL);
12205588d34STakashi Sakamoto 
12305588d34STakashi Sakamoto 	spin_unlock_irqrestore(&oxfw->lock, flags);
12405588d34STakashi Sakamoto }
12505588d34STakashi Sakamoto 
set_midi_substream_names(struct snd_oxfw * oxfw,struct snd_rawmidi_str * str)12605588d34STakashi Sakamoto static void set_midi_substream_names(struct snd_oxfw *oxfw,
12705588d34STakashi Sakamoto 				     struct snd_rawmidi_str *str)
12805588d34STakashi Sakamoto {
12905588d34STakashi Sakamoto 	struct snd_rawmidi_substream *subs;
13005588d34STakashi Sakamoto 
13105588d34STakashi Sakamoto 	list_for_each_entry(subs, &str->substreams, list) {
132*ea77850eSTakashi Iwai 		scnprintf(subs->name, sizeof(subs->name),
13305588d34STakashi Sakamoto 			  "%s MIDI %d",
13405588d34STakashi Sakamoto 			  oxfw->card->shortname, subs->number + 1);
13505588d34STakashi Sakamoto 	}
13605588d34STakashi Sakamoto }
13705588d34STakashi Sakamoto 
snd_oxfw_create_midi(struct snd_oxfw * oxfw)13805588d34STakashi Sakamoto int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
13905588d34STakashi Sakamoto {
14057eb6799STakashi Iwai 	static const struct snd_rawmidi_ops capture_ops = {
14139feaf2dSTakashi Sakamoto 		.open		= midi_capture_open,
14239feaf2dSTakashi Sakamoto 		.close		= midi_capture_close,
14339feaf2dSTakashi Sakamoto 		.trigger	= midi_capture_trigger,
14439feaf2dSTakashi Sakamoto 	};
14557eb6799STakashi Iwai 	static const struct snd_rawmidi_ops playback_ops = {
14639feaf2dSTakashi Sakamoto 		.open		= midi_playback_open,
14739feaf2dSTakashi Sakamoto 		.close		= midi_playback_close,
14839feaf2dSTakashi Sakamoto 		.trigger	= midi_playback_trigger,
14939feaf2dSTakashi Sakamoto 	};
15005588d34STakashi Sakamoto 	struct snd_rawmidi *rmidi;
15105588d34STakashi Sakamoto 	struct snd_rawmidi_str *str;
15232056041STakashi Sakamoto 	int err;
15305588d34STakashi Sakamoto 
15432056041STakashi Sakamoto 	if (oxfw->midi_input_ports == 0 && oxfw->midi_output_ports == 0)
15505588d34STakashi Sakamoto 		return 0;
15605588d34STakashi Sakamoto 
15705588d34STakashi Sakamoto 	/* create midi ports */
15805588d34STakashi Sakamoto 	err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0,
15905588d34STakashi Sakamoto 			      oxfw->midi_output_ports, oxfw->midi_input_ports,
16005588d34STakashi Sakamoto 			      &rmidi);
16105588d34STakashi Sakamoto 	if (err < 0)
16205588d34STakashi Sakamoto 		return err;
16305588d34STakashi Sakamoto 
16405588d34STakashi Sakamoto 	snprintf(rmidi->name, sizeof(rmidi->name),
16505588d34STakashi Sakamoto 		 "%s MIDI", oxfw->card->shortname);
16605588d34STakashi Sakamoto 	rmidi->private_data = oxfw;
16705588d34STakashi Sakamoto 
16805588d34STakashi Sakamoto 	if (oxfw->midi_input_ports > 0) {
16905588d34STakashi Sakamoto 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
17005588d34STakashi Sakamoto 
17105588d34STakashi Sakamoto 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
17239feaf2dSTakashi Sakamoto 				    &capture_ops);
17305588d34STakashi Sakamoto 
17405588d34STakashi Sakamoto 		str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
17505588d34STakashi Sakamoto 
17605588d34STakashi Sakamoto 		set_midi_substream_names(oxfw, str);
17705588d34STakashi Sakamoto 	}
17805588d34STakashi Sakamoto 
17905588d34STakashi Sakamoto 	if (oxfw->midi_output_ports > 0) {
18005588d34STakashi Sakamoto 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
18105588d34STakashi Sakamoto 
18205588d34STakashi Sakamoto 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
18339feaf2dSTakashi Sakamoto 				    &playback_ops);
18405588d34STakashi Sakamoto 
18505588d34STakashi Sakamoto 		str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
18605588d34STakashi Sakamoto 
18705588d34STakashi Sakamoto 		set_midi_substream_names(oxfw, str);
18805588d34STakashi Sakamoto 	}
18905588d34STakashi Sakamoto 
19005588d34STakashi Sakamoto 	if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0))
19105588d34STakashi Sakamoto 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
19205588d34STakashi Sakamoto 
19305588d34STakashi Sakamoto 	return 0;
19405588d34STakashi Sakamoto }
195