Commit | Line | Data |
---|---|---|
248b7802 TS |
1 | /* |
2 | * bebob_midi.c - a part of driver for BeBoB based devices | |
3 | * | |
4 | * Copyright (c) 2013-2014 Takashi Sakamoto | |
5 | * | |
6 | * Licensed under the terms of the GNU General Public License, version 2. | |
7 | */ | |
8 | ||
9 | #include "bebob.h" | |
10 | ||
73f7864e | 11 | static int midi_open(struct snd_rawmidi_substream *substream) |
248b7802 TS |
12 | { |
13 | struct snd_bebob *bebob = substream->rmidi->private_data; | |
618eabea TS |
14 | int err; |
15 | ||
16 | err = snd_bebob_stream_lock_try(bebob); | |
17 | if (err < 0) | |
ac2888b9 | 18 | return err; |
248b7802 | 19 | |
2a71e701 | 20 | mutex_lock(&bebob->mutex); |
ac2888b9 TS |
21 | err = snd_bebob_stream_reserve_duplex(bebob, 0); |
22 | if (err >= 0) { | |
23 | ++bebob->substreams_counter; | |
24 | err = snd_bebob_stream_start_duplex(bebob); | |
25 | } | |
2a71e701 | 26 | mutex_unlock(&bebob->mutex); |
618eabea TS |
27 | if (err < 0) |
28 | snd_bebob_stream_lock_release(bebob); | |
ac2888b9 | 29 | |
618eabea | 30 | return err; |
248b7802 TS |
31 | } |
32 | ||
73f7864e | 33 | static int midi_close(struct snd_rawmidi_substream *substream) |
248b7802 TS |
34 | { |
35 | struct snd_bebob *bebob = substream->rmidi->private_data; | |
36 | ||
2a71e701 | 37 | mutex_lock(&bebob->mutex); |
4fd6c6c7 | 38 | bebob->substreams_counter--; |
248b7802 | 39 | snd_bebob_stream_stop_duplex(bebob); |
2a71e701 | 40 | mutex_unlock(&bebob->mutex); |
248b7802 | 41 | |
618eabea | 42 | snd_bebob_stream_lock_release(bebob); |
248b7802 TS |
43 | return 0; |
44 | } | |
45 | ||
46 | static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) | |
47 | { | |
48 | struct snd_bebob *bebob = substrm->rmidi->private_data; | |
49 | unsigned long flags; | |
50 | ||
51 | spin_lock_irqsave(&bebob->lock, flags); | |
52 | ||
53 | if (up) | |
03e2a67e TS |
54 | amdtp_am824_midi_trigger(&bebob->tx_stream, |
55 | substrm->number, substrm); | |
248b7802 | 56 | else |
03e2a67e TS |
57 | amdtp_am824_midi_trigger(&bebob->tx_stream, |
58 | substrm->number, NULL); | |
248b7802 TS |
59 | |
60 | spin_unlock_irqrestore(&bebob->lock, flags); | |
61 | } | |
62 | ||
63 | static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) | |
64 | { | |
65 | struct snd_bebob *bebob = substrm->rmidi->private_data; | |
66 | unsigned long flags; | |
67 | ||
68 | spin_lock_irqsave(&bebob->lock, flags); | |
69 | ||
70 | if (up) | |
03e2a67e TS |
71 | amdtp_am824_midi_trigger(&bebob->rx_stream, |
72 | substrm->number, substrm); | |
248b7802 | 73 | else |
03e2a67e TS |
74 | amdtp_am824_midi_trigger(&bebob->rx_stream, |
75 | substrm->number, NULL); | |
248b7802 TS |
76 | |
77 | spin_unlock_irqrestore(&bebob->lock, flags); | |
78 | } | |
79 | ||
248b7802 TS |
80 | static void set_midi_substream_names(struct snd_bebob *bebob, |
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", | |
88 | bebob->card->shortname, subs->number + 1); | |
89 | } | |
90 | } | |
91 | ||
92 | int snd_bebob_create_midi_devices(struct snd_bebob *bebob) | |
93 | { | |
57eb6799 | 94 | static const struct snd_rawmidi_ops capture_ops = { |
73f7864e TS |
95 | .open = midi_open, |
96 | .close = midi_close, | |
4780f774 TS |
97 | .trigger = midi_capture_trigger, |
98 | }; | |
57eb6799 | 99 | static const struct snd_rawmidi_ops playback_ops = { |
73f7864e TS |
100 | .open = midi_open, |
101 | .close = midi_close, | |
4780f774 TS |
102 | .trigger = midi_playback_trigger, |
103 | }; | |
248b7802 TS |
104 | struct snd_rawmidi *rmidi; |
105 | struct snd_rawmidi_str *str; | |
106 | int err; | |
107 | ||
108 | /* create midi ports */ | |
109 | err = snd_rawmidi_new(bebob->card, bebob->card->driver, 0, | |
110 | bebob->midi_output_ports, bebob->midi_input_ports, | |
111 | &rmidi); | |
112 | if (err < 0) | |
113 | return err; | |
114 | ||
115 | snprintf(rmidi->name, sizeof(rmidi->name), | |
116 | "%s MIDI", bebob->card->shortname); | |
117 | rmidi->private_data = bebob; | |
118 | ||
119 | if (bebob->midi_input_ports > 0) { | |
120 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | |
121 | ||
122 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | |
4780f774 | 123 | &capture_ops); |
248b7802 TS |
124 | |
125 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | |
126 | ||
127 | set_midi_substream_names(bebob, str); | |
128 | } | |
129 | ||
130 | if (bebob->midi_output_ports > 0) { | |
131 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; | |
132 | ||
133 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | |
4780f774 | 134 | &playback_ops); |
248b7802 TS |
135 | |
136 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | |
137 | ||
138 | set_midi_substream_names(bebob, str); | |
139 | } | |
140 | ||
141 | if ((bebob->midi_output_ports > 0) && (bebob->midi_input_ports > 0)) | |
142 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | |
143 | ||
144 | return 0; | |
145 | } |