Commit | Line | Data |
---|---|---|
a63d3ff1 TS |
1 | /* |
2 | * fireworks_midi.c - a part of driver for Fireworks based devices | |
3 | * | |
4 | * Copyright (c) 2009-2010 Clemens Ladisch | |
5 | * Copyright (c) 2013-2014 Takashi Sakamoto | |
6 | * | |
7 | * Licensed under the terms of the GNU General Public License, version 2. | |
8 | */ | |
9 | #include "fireworks.h" | |
10 | ||
11 | static int midi_capture_open(struct snd_rawmidi_substream *substream) | |
12 | { | |
13 | struct snd_efw *efw = substream->rmidi->private_data; | |
594ddced TS |
14 | int err; |
15 | ||
16 | err = snd_efw_stream_lock_try(efw); | |
17 | if (err < 0) | |
18 | goto end; | |
a63d3ff1 TS |
19 | |
20 | atomic_inc(&efw->capture_substreams); | |
594ddced TS |
21 | err = snd_efw_stream_start_duplex(efw, 0); |
22 | if (err < 0) | |
23 | snd_efw_stream_lock_release(efw); | |
24 | ||
25 | end: | |
26 | return err; | |
a63d3ff1 TS |
27 | } |
28 | ||
29 | static int midi_playback_open(struct snd_rawmidi_substream *substream) | |
30 | { | |
31 | struct snd_efw *efw = substream->rmidi->private_data; | |
594ddced TS |
32 | int err; |
33 | ||
34 | err = snd_efw_stream_lock_try(efw); | |
35 | if (err < 0) | |
36 | goto end; | |
a63d3ff1 TS |
37 | |
38 | atomic_inc(&efw->playback_substreams); | |
594ddced TS |
39 | err = snd_efw_stream_start_duplex(efw, 0); |
40 | if (err < 0) | |
41 | snd_efw_stream_lock_release(efw); | |
42 | end: | |
43 | return err; | |
a63d3ff1 TS |
44 | } |
45 | ||
46 | static int midi_capture_close(struct snd_rawmidi_substream *substream) | |
47 | { | |
48 | struct snd_efw *efw = substream->rmidi->private_data; | |
49 | ||
50 | atomic_dec(&efw->capture_substreams); | |
51 | snd_efw_stream_stop_duplex(efw); | |
52 | ||
594ddced | 53 | snd_efw_stream_lock_release(efw); |
a63d3ff1 TS |
54 | return 0; |
55 | } | |
56 | ||
57 | static int midi_playback_close(struct snd_rawmidi_substream *substream) | |
58 | { | |
59 | struct snd_efw *efw = substream->rmidi->private_data; | |
60 | ||
61 | atomic_dec(&efw->playback_substreams); | |
62 | snd_efw_stream_stop_duplex(efw); | |
63 | ||
594ddced | 64 | snd_efw_stream_lock_release(efw); |
a63d3ff1 TS |
65 | return 0; |
66 | } | |
67 | ||
68 | static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) | |
69 | { | |
70 | struct snd_efw *efw = substrm->rmidi->private_data; | |
71 | unsigned long flags; | |
72 | ||
73 | spin_lock_irqsave(&efw->lock, flags); | |
74 | ||
75 | if (up) | |
03e2a67e | 76 | amdtp_am824_midi_trigger(&efw->tx_stream, |
a63d3ff1 TS |
77 | substrm->number, substrm); |
78 | else | |
03e2a67e | 79 | amdtp_am824_midi_trigger(&efw->tx_stream, |
a63d3ff1 TS |
80 | substrm->number, NULL); |
81 | ||
82 | spin_unlock_irqrestore(&efw->lock, flags); | |
83 | } | |
84 | ||
85 | static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) | |
86 | { | |
87 | struct snd_efw *efw = substrm->rmidi->private_data; | |
88 | unsigned long flags; | |
89 | ||
90 | spin_lock_irqsave(&efw->lock, flags); | |
91 | ||
92 | if (up) | |
03e2a67e TS |
93 | amdtp_am824_midi_trigger(&efw->rx_stream, |
94 | substrm->number, substrm); | |
a63d3ff1 | 95 | else |
03e2a67e TS |
96 | amdtp_am824_midi_trigger(&efw->rx_stream, |
97 | substrm->number, NULL); | |
a63d3ff1 TS |
98 | |
99 | spin_unlock_irqrestore(&efw->lock, flags); | |
100 | } | |
101 | ||
102 | static struct snd_rawmidi_ops midi_capture_ops = { | |
103 | .open = midi_capture_open, | |
104 | .close = midi_capture_close, | |
105 | .trigger = midi_capture_trigger, | |
106 | }; | |
107 | ||
108 | static struct snd_rawmidi_ops midi_playback_ops = { | |
109 | .open = midi_playback_open, | |
110 | .close = midi_playback_close, | |
111 | .trigger = midi_playback_trigger, | |
112 | }; | |
113 | ||
114 | static void set_midi_substream_names(struct snd_efw *efw, | |
115 | struct snd_rawmidi_str *str) | |
116 | { | |
117 | struct snd_rawmidi_substream *subs; | |
118 | ||
119 | list_for_each_entry(subs, &str->substreams, list) { | |
120 | snprintf(subs->name, sizeof(subs->name), | |
121 | "%s MIDI %d", efw->card->shortname, subs->number + 1); | |
122 | } | |
123 | } | |
124 | ||
125 | int snd_efw_create_midi_devices(struct snd_efw *efw) | |
126 | { | |
127 | struct snd_rawmidi *rmidi; | |
128 | struct snd_rawmidi_str *str; | |
129 | int err; | |
130 | ||
131 | /* create midi ports */ | |
132 | err = snd_rawmidi_new(efw->card, efw->card->driver, 0, | |
133 | efw->midi_out_ports, efw->midi_in_ports, | |
134 | &rmidi); | |
135 | if (err < 0) | |
136 | return err; | |
137 | ||
138 | snprintf(rmidi->name, sizeof(rmidi->name), | |
139 | "%s MIDI", efw->card->shortname); | |
140 | rmidi->private_data = efw; | |
141 | ||
142 | if (efw->midi_in_ports > 0) { | |
143 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | |
144 | ||
145 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | |
73616c4e | 146 | &midi_capture_ops); |
a63d3ff1 TS |
147 | |
148 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | |
149 | ||
150 | set_midi_substream_names(efw, str); | |
151 | } | |
152 | ||
153 | if (efw->midi_out_ports > 0) { | |
154 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; | |
155 | ||
156 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | |
73616c4e | 157 | &midi_playback_ops); |
a63d3ff1 TS |
158 | |
159 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | |
160 | ||
161 | set_midi_substream_names(efw, str); | |
162 | } | |
163 | ||
164 | if ((efw->midi_out_ports > 0) && (efw->midi_in_ports > 0)) | |
165 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | |
166 | ||
167 | return 0; | |
168 | } |