xref: /linux/sound/firewire/dice/dice-midi.c (revision b7019ac550eb3916f34d79db583e9b7ea2524afa)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * dice_midi.c - a part of driver for Dice based devices
4  *
5  * Copyright (c) 2014 Takashi Sakamoto
6  */
7 #include "dice.h"
8 
9 static int midi_open(struct snd_rawmidi_substream *substream)
10 {
11 	struct snd_dice *dice = substream->rmidi->private_data;
12 	int err;
13 
14 	err = snd_dice_stream_lock_try(dice);
15 	if (err < 0)
16 		return err;
17 
18 	mutex_lock(&dice->mutex);
19 
20 	dice->substreams_counter++;
21 	err = snd_dice_stream_start_duplex(dice, 0);
22 
23 	mutex_unlock(&dice->mutex);
24 
25 	if (err < 0)
26 		snd_dice_stream_lock_release(dice);
27 
28 	return err;
29 }
30 
31 static int midi_close(struct snd_rawmidi_substream *substream)
32 {
33 	struct snd_dice *dice = substream->rmidi->private_data;
34 
35 	mutex_lock(&dice->mutex);
36 
37 	dice->substreams_counter--;
38 	snd_dice_stream_stop_duplex(dice);
39 
40 	mutex_unlock(&dice->mutex);
41 
42 	snd_dice_stream_lock_release(dice);
43 	return 0;
44 }
45 
46 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
47 {
48 	struct snd_dice *dice = substrm->rmidi->private_data;
49 	unsigned long flags;
50 
51 	spin_lock_irqsave(&dice->lock, flags);
52 
53 	if (up)
54 		amdtp_am824_midi_trigger(&dice->tx_stream[0],
55 					  substrm->number, substrm);
56 	else
57 		amdtp_am824_midi_trigger(&dice->tx_stream[0],
58 					  substrm->number, NULL);
59 
60 	spin_unlock_irqrestore(&dice->lock, flags);
61 }
62 
63 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
64 {
65 	struct snd_dice *dice = substrm->rmidi->private_data;
66 	unsigned long flags;
67 
68 	spin_lock_irqsave(&dice->lock, flags);
69 
70 	if (up)
71 		amdtp_am824_midi_trigger(&dice->rx_stream[0],
72 					 substrm->number, substrm);
73 	else
74 		amdtp_am824_midi_trigger(&dice->rx_stream[0],
75 					 substrm->number, NULL);
76 
77 	spin_unlock_irqrestore(&dice->lock, flags);
78 }
79 
80 static void set_midi_substream_names(struct snd_dice *dice,
81 				     struct snd_rawmidi_str *str)
82 {
83 	struct snd_rawmidi_substream *subs;
84 
85 	list_for_each_entry(subs, &str->substreams, list) {
86 		snprintf(subs->name, sizeof(subs->name),
87 			 "%s MIDI %d", dice->card->shortname, subs->number + 1);
88 	}
89 }
90 
91 int snd_dice_create_midi(struct snd_dice *dice)
92 {
93 	static const struct snd_rawmidi_ops capture_ops = {
94 		.open		= midi_open,
95 		.close		= midi_close,
96 		.trigger	= midi_capture_trigger,
97 	};
98 	static const struct snd_rawmidi_ops playback_ops = {
99 		.open		= midi_open,
100 		.close		= midi_close,
101 		.trigger	= midi_playback_trigger,
102 	};
103 	struct snd_rawmidi *rmidi;
104 	struct snd_rawmidi_str *str;
105 	unsigned int midi_in_ports, midi_out_ports;
106 	int i;
107 	int err;
108 
109 	midi_in_ports = 0;
110 	midi_out_ports = 0;
111 	for (i = 0; i < MAX_STREAMS; ++i) {
112 		midi_in_ports = max(midi_in_ports, dice->tx_midi_ports[i]);
113 		midi_out_ports = max(midi_out_ports, dice->rx_midi_ports[i]);
114 	}
115 
116 	if (midi_in_ports + midi_out_ports == 0)
117 		return 0;
118 
119 	/* create midi ports */
120 	err = snd_rawmidi_new(dice->card, dice->card->driver, 0,
121 			      midi_out_ports, midi_in_ports,
122 			      &rmidi);
123 	if (err < 0)
124 		return err;
125 
126 	snprintf(rmidi->name, sizeof(rmidi->name),
127 		 "%s MIDI", dice->card->shortname);
128 	rmidi->private_data = dice;
129 
130 	if (midi_in_ports > 0) {
131 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
132 
133 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
134 				    &capture_ops);
135 
136 		str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
137 
138 		set_midi_substream_names(dice, str);
139 	}
140 
141 	if (midi_out_ports > 0) {
142 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
143 
144 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
145 				    &playback_ops);
146 
147 		str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
148 
149 		set_midi_substream_names(dice, str);
150 	}
151 
152 	if ((midi_out_ports > 0) && (midi_in_ports > 0))
153 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
154 
155 	return 0;
156 }
157