xref: /linux/sound/firewire/tascam/tascam-midi.c (revision e5c86679d5e864947a52fb31e45a425dea3e7fa9)
1 /*
2  * tascam-midi.c - a part of driver for TASCAM FireWire series
3  *
4  * Copyright (c) 2015 Takashi Sakamoto
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8 
9 #include "tascam.h"
10 
11 static int midi_capture_open(struct snd_rawmidi_substream *substream)
12 {
13 	/* Do nothing. */
14 	return 0;
15 }
16 
17 static int midi_playback_open(struct snd_rawmidi_substream *substream)
18 {
19 	struct snd_tscm *tscm = substream->rmidi->private_data;
20 
21 	/* Initialize internal status. */
22 	tscm->running_status[substream->number] = 0;
23 	tscm->on_sysex[substream->number] = 0;
24 	return 0;
25 }
26 
27 static int midi_capture_close(struct snd_rawmidi_substream *substream)
28 {
29 	/* Do nothing. */
30 	return 0;
31 }
32 
33 static int midi_playback_close(struct snd_rawmidi_substream *substream)
34 {
35 	struct snd_tscm *tscm = substream->rmidi->private_data;
36 
37 	snd_fw_async_midi_port_finish(&tscm->out_ports[substream->number]);
38 
39 	return 0;
40 }
41 
42 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
43 {
44 	struct snd_tscm *tscm = substrm->rmidi->private_data;
45 	unsigned long flags;
46 
47 	spin_lock_irqsave(&tscm->lock, flags);
48 
49 	if (up)
50 		tscm->tx_midi_substreams[substrm->number] = substrm;
51 	else
52 		tscm->tx_midi_substreams[substrm->number] = NULL;
53 
54 	spin_unlock_irqrestore(&tscm->lock, flags);
55 }
56 
57 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
58 {
59 	struct snd_tscm *tscm = substrm->rmidi->private_data;
60 	unsigned long flags;
61 
62 	spin_lock_irqsave(&tscm->lock, flags);
63 
64 	if (up)
65 		snd_fw_async_midi_port_run(&tscm->out_ports[substrm->number],
66 					   substrm);
67 
68 	spin_unlock_irqrestore(&tscm->lock, flags);
69 }
70 
71 int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
72 {
73 	static const struct snd_rawmidi_ops capture_ops = {
74 		.open		= midi_capture_open,
75 		.close		= midi_capture_close,
76 		.trigger	= midi_capture_trigger,
77 	};
78 	static const struct snd_rawmidi_ops playback_ops = {
79 		.open		= midi_playback_open,
80 		.close		= midi_playback_close,
81 		.trigger	= midi_playback_trigger,
82 	};
83 	struct snd_rawmidi *rmidi;
84 	struct snd_rawmidi_str *stream;
85 	struct snd_rawmidi_substream *subs;
86 	int err;
87 
88 	err = snd_rawmidi_new(tscm->card, tscm->card->driver, 0,
89 			      tscm->spec->midi_playback_ports,
90 			      tscm->spec->midi_capture_ports,
91 			      &rmidi);
92 	if (err < 0)
93 		return err;
94 
95 	snprintf(rmidi->name, sizeof(rmidi->name),
96 		 "%s MIDI", tscm->card->shortname);
97 	rmidi->private_data = tscm;
98 
99 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
100 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
101 			    &capture_ops);
102 	stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
103 
104 	/* Set port names for MIDI input. */
105 	list_for_each_entry(subs, &stream->substreams, list) {
106 		/* TODO: support virtual MIDI ports. */
107 		if (subs->number < tscm->spec->midi_capture_ports) {
108 			/* Hardware MIDI ports. */
109 			snprintf(subs->name, sizeof(subs->name),
110 				 "%s MIDI %d",
111 				 tscm->card->shortname, subs->number + 1);
112 		}
113 	}
114 
115 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
116 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
117 			    &playback_ops);
118 	stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
119 
120 	/* Set port names for MIDI ourput. */
121 	list_for_each_entry(subs, &stream->substreams, list) {
122 		if (subs->number < tscm->spec->midi_playback_ports) {
123 			/* Hardware MIDI ports only. */
124 			snprintf(subs->name, sizeof(subs->name),
125 				 "%s MIDI %d",
126 				 tscm->card->shortname, subs->number + 1);
127 		}
128 	}
129 
130 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
131 
132 	return 0;
133 }
134