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