Linux Audio

Check our new training course

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