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