1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2248b7802STakashi Sakamoto /*
3248b7802STakashi Sakamoto  * bebob_midi.c - a part of driver for BeBoB based devices
4248b7802STakashi Sakamoto  *
5248b7802STakashi Sakamoto  * Copyright (c) 2013-2014 Takashi Sakamoto
6248b7802STakashi Sakamoto  */
7248b7802STakashi Sakamoto 
8248b7802STakashi Sakamoto #include "bebob.h"
9248b7802STakashi Sakamoto 
midi_open(struct snd_rawmidi_substream * substream)1073f7864eSTakashi Sakamoto static int midi_open(struct snd_rawmidi_substream *substream)
11248b7802STakashi Sakamoto {
12248b7802STakashi Sakamoto 	struct snd_bebob *bebob = substream->rmidi->private_data;
13618eabeaSTakashi Sakamoto 	int err;
14618eabeaSTakashi Sakamoto 
15618eabeaSTakashi Sakamoto 	err = snd_bebob_stream_lock_try(bebob);
16618eabeaSTakashi Sakamoto 	if (err < 0)
17ac2888b9STakashi Sakamoto 		return err;
18248b7802STakashi Sakamoto 
192a71e701STakashi Sakamoto 	mutex_lock(&bebob->mutex);
201fde7a44STakashi Sakamoto 	err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0);
21ac2888b9STakashi Sakamoto 	if (err >= 0) {
22ac2888b9STakashi Sakamoto 		++bebob->substreams_counter;
23ac2888b9STakashi Sakamoto 		err = snd_bebob_stream_start_duplex(bebob);
24097f8ba3STakashi Sakamoto 		if (err < 0)
25097f8ba3STakashi Sakamoto 			--bebob->substreams_counter;
26ac2888b9STakashi Sakamoto 	}
272a71e701STakashi Sakamoto 	mutex_unlock(&bebob->mutex);
28618eabeaSTakashi Sakamoto 	if (err < 0)
29618eabeaSTakashi Sakamoto 		snd_bebob_stream_lock_release(bebob);
30ac2888b9STakashi Sakamoto 
31618eabeaSTakashi Sakamoto 	return err;
32248b7802STakashi Sakamoto }
33248b7802STakashi Sakamoto 
midi_close(struct snd_rawmidi_substream * substream)3473f7864eSTakashi Sakamoto static int midi_close(struct snd_rawmidi_substream *substream)
35248b7802STakashi Sakamoto {
36248b7802STakashi Sakamoto 	struct snd_bebob *bebob = substream->rmidi->private_data;
37248b7802STakashi Sakamoto 
382a71e701STakashi Sakamoto 	mutex_lock(&bebob->mutex);
394fd6c6c7STakashi Sakamoto 	bebob->substreams_counter--;
40248b7802STakashi Sakamoto 	snd_bebob_stream_stop_duplex(bebob);
412a71e701STakashi Sakamoto 	mutex_unlock(&bebob->mutex);
42248b7802STakashi Sakamoto 
43618eabeaSTakashi Sakamoto 	snd_bebob_stream_lock_release(bebob);
44248b7802STakashi Sakamoto 	return 0;
45248b7802STakashi Sakamoto }
46248b7802STakashi Sakamoto 
midi_capture_trigger(struct snd_rawmidi_substream * substrm,int up)47248b7802STakashi Sakamoto static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
48248b7802STakashi Sakamoto {
49248b7802STakashi Sakamoto 	struct snd_bebob *bebob = substrm->rmidi->private_data;
50248b7802STakashi Sakamoto 	unsigned long flags;
51248b7802STakashi Sakamoto 
52248b7802STakashi Sakamoto 	spin_lock_irqsave(&bebob->lock, flags);
53248b7802STakashi Sakamoto 
54248b7802STakashi Sakamoto 	if (up)
5503e2a67eSTakashi Sakamoto 		amdtp_am824_midi_trigger(&bebob->tx_stream,
56248b7802STakashi Sakamoto 					 substrm->number, substrm);
57248b7802STakashi Sakamoto 	else
5803e2a67eSTakashi Sakamoto 		amdtp_am824_midi_trigger(&bebob->tx_stream,
59248b7802STakashi Sakamoto 					 substrm->number, NULL);
60248b7802STakashi Sakamoto 
61248b7802STakashi Sakamoto 	spin_unlock_irqrestore(&bebob->lock, flags);
62248b7802STakashi Sakamoto }
63248b7802STakashi Sakamoto 
midi_playback_trigger(struct snd_rawmidi_substream * substrm,int up)64248b7802STakashi Sakamoto static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
65248b7802STakashi Sakamoto {
66248b7802STakashi Sakamoto 	struct snd_bebob *bebob = substrm->rmidi->private_data;
67248b7802STakashi Sakamoto 	unsigned long flags;
68248b7802STakashi Sakamoto 
69248b7802STakashi Sakamoto 	spin_lock_irqsave(&bebob->lock, flags);
70248b7802STakashi Sakamoto 
71248b7802STakashi Sakamoto 	if (up)
7203e2a67eSTakashi Sakamoto 		amdtp_am824_midi_trigger(&bebob->rx_stream,
73248b7802STakashi Sakamoto 					 substrm->number, substrm);
74248b7802STakashi Sakamoto 	else
7503e2a67eSTakashi Sakamoto 		amdtp_am824_midi_trigger(&bebob->rx_stream,
76248b7802STakashi Sakamoto 					 substrm->number, NULL);
77248b7802STakashi Sakamoto 
78248b7802STakashi Sakamoto 	spin_unlock_irqrestore(&bebob->lock, flags);
79248b7802STakashi Sakamoto }
80248b7802STakashi Sakamoto 
set_midi_substream_names(struct snd_bebob * bebob,struct snd_rawmidi_str * str)81248b7802STakashi Sakamoto static void set_midi_substream_names(struct snd_bebob *bebob,
82248b7802STakashi Sakamoto 				     struct snd_rawmidi_str *str)
83248b7802STakashi Sakamoto {
84248b7802STakashi Sakamoto 	struct snd_rawmidi_substream *subs;
85248b7802STakashi Sakamoto 
86248b7802STakashi Sakamoto 	list_for_each_entry(subs, &str->substreams, list) {
87*ea77850eSTakashi Iwai 		scnprintf(subs->name, sizeof(subs->name),
88248b7802STakashi Sakamoto 			  "%s MIDI %d",
89248b7802STakashi Sakamoto 			  bebob->card->shortname, subs->number + 1);
90248b7802STakashi Sakamoto 	}
91248b7802STakashi Sakamoto }
92248b7802STakashi Sakamoto 
snd_bebob_create_midi_devices(struct snd_bebob * bebob)93248b7802STakashi Sakamoto int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
94248b7802STakashi Sakamoto {
9557eb6799STakashi Iwai 	static const struct snd_rawmidi_ops capture_ops = {
9673f7864eSTakashi Sakamoto 		.open		= midi_open,
9773f7864eSTakashi Sakamoto 		.close		= midi_close,
984780f774STakashi Sakamoto 		.trigger	= midi_capture_trigger,
994780f774STakashi Sakamoto 	};
10057eb6799STakashi Iwai 	static const struct snd_rawmidi_ops playback_ops = {
10173f7864eSTakashi Sakamoto 		.open		= midi_open,
10273f7864eSTakashi Sakamoto 		.close		= midi_close,
1034780f774STakashi Sakamoto 		.trigger	= midi_playback_trigger,
1044780f774STakashi Sakamoto 	};
105248b7802STakashi Sakamoto 	struct snd_rawmidi *rmidi;
106248b7802STakashi Sakamoto 	struct snd_rawmidi_str *str;
107248b7802STakashi Sakamoto 	int err;
108248b7802STakashi Sakamoto 
109248b7802STakashi Sakamoto 	/* create midi ports */
110248b7802STakashi Sakamoto 	err = snd_rawmidi_new(bebob->card, bebob->card->driver, 0,
111248b7802STakashi Sakamoto 			      bebob->midi_output_ports, bebob->midi_input_ports,
112248b7802STakashi Sakamoto 			      &rmidi);
113248b7802STakashi Sakamoto 	if (err < 0)
114248b7802STakashi Sakamoto 		return err;
115248b7802STakashi Sakamoto 
116248b7802STakashi Sakamoto 	snprintf(rmidi->name, sizeof(rmidi->name),
117248b7802STakashi Sakamoto 		 "%s MIDI", bebob->card->shortname);
118248b7802STakashi Sakamoto 	rmidi->private_data = bebob;
119248b7802STakashi Sakamoto 
120248b7802STakashi Sakamoto 	if (bebob->midi_input_ports > 0) {
121248b7802STakashi Sakamoto 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
122248b7802STakashi Sakamoto 
123248b7802STakashi Sakamoto 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
1244780f774STakashi Sakamoto 				    &capture_ops);
125248b7802STakashi Sakamoto 
126248b7802STakashi Sakamoto 		str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
127248b7802STakashi Sakamoto 
128248b7802STakashi Sakamoto 		set_midi_substream_names(bebob, str);
129248b7802STakashi Sakamoto 	}
130248b7802STakashi Sakamoto 
131248b7802STakashi Sakamoto 	if (bebob->midi_output_ports > 0) {
132248b7802STakashi Sakamoto 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
133248b7802STakashi Sakamoto 
134248b7802STakashi Sakamoto 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
1354780f774STakashi Sakamoto 				    &playback_ops);
136248b7802STakashi Sakamoto 
137248b7802STakashi Sakamoto 		str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
138248b7802STakashi Sakamoto 
139248b7802STakashi Sakamoto 		set_midi_substream_names(bebob, str);
140248b7802STakashi Sakamoto 	}
141248b7802STakashi Sakamoto 
142248b7802STakashi Sakamoto 	if ((bebob->midi_output_ports > 0) && (bebob->midi_input_ports > 0))
143248b7802STakashi Sakamoto 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
144248b7802STakashi Sakamoto 
145248b7802STakashi Sakamoto 	return 0;
146248b7802STakashi Sakamoto }
147