1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2248b7802STakashi Sakamoto /*
3248b7802STakashi Sakamoto * bebob_midi.c - a part of driver for BeBoB based devices
4248b7802STakashi Sakamoto *
5248b7802STakashi Sakamoto * Copyright (c) 2013-2014 Takashi Sakamoto
6248b7802STakashi Sakamoto */
7248b7802STakashi Sakamoto
8248b7802STakashi Sakamoto #include "bebob.h"
9248b7802STakashi Sakamoto
midi_open(struct snd_rawmidi_substream * substream)1073f7864eSTakashi Sakamoto static int midi_open(struct snd_rawmidi_substream *substream)
11248b7802STakashi Sakamoto {
12248b7802STakashi Sakamoto struct snd_bebob *bebob = substream->rmidi->private_data;
13618eabeaSTakashi Sakamoto int err;
14618eabeaSTakashi Sakamoto
15618eabeaSTakashi Sakamoto err = snd_bebob_stream_lock_try(bebob);
16618eabeaSTakashi Sakamoto if (err < 0)
17ac2888b9STakashi Sakamoto return err;
18248b7802STakashi Sakamoto
192a71e701STakashi Sakamoto mutex_lock(&bebob->mutex);
201fde7a44STakashi Sakamoto err = snd_bebob_stream_reserve_duplex(bebob, 0, 0, 0);
21ac2888b9STakashi Sakamoto if (err >= 0) {
22ac2888b9STakashi Sakamoto ++bebob->substreams_counter;
23ac2888b9STakashi Sakamoto err = snd_bebob_stream_start_duplex(bebob);
24097f8ba3STakashi Sakamoto if (err < 0)
25097f8ba3STakashi Sakamoto --bebob->substreams_counter;
26ac2888b9STakashi Sakamoto }
272a71e701STakashi Sakamoto mutex_unlock(&bebob->mutex);
28618eabeaSTakashi Sakamoto if (err < 0)
29618eabeaSTakashi Sakamoto snd_bebob_stream_lock_release(bebob);
30ac2888b9STakashi Sakamoto
31618eabeaSTakashi Sakamoto return err;
32248b7802STakashi Sakamoto }
33248b7802STakashi Sakamoto
midi_close(struct snd_rawmidi_substream * substream)3473f7864eSTakashi Sakamoto static int midi_close(struct snd_rawmidi_substream *substream)
35248b7802STakashi Sakamoto {
36248b7802STakashi Sakamoto struct snd_bebob *bebob = substream->rmidi->private_data;
37248b7802STakashi Sakamoto
382a71e701STakashi Sakamoto mutex_lock(&bebob->mutex);
394fd6c6c7STakashi Sakamoto bebob->substreams_counter--;
40248b7802STakashi Sakamoto snd_bebob_stream_stop_duplex(bebob);
412a71e701STakashi Sakamoto mutex_unlock(&bebob->mutex);
42248b7802STakashi Sakamoto
43618eabeaSTakashi Sakamoto snd_bebob_stream_lock_release(bebob);
44248b7802STakashi Sakamoto return 0;
45248b7802STakashi Sakamoto }
46248b7802STakashi Sakamoto
midi_capture_trigger(struct snd_rawmidi_substream * substrm,int up)47248b7802STakashi Sakamoto static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
48248b7802STakashi Sakamoto {
49248b7802STakashi Sakamoto struct snd_bebob *bebob = substrm->rmidi->private_data;
50248b7802STakashi Sakamoto unsigned long flags;
51248b7802STakashi Sakamoto
52248b7802STakashi Sakamoto spin_lock_irqsave(&bebob->lock, flags);
53248b7802STakashi Sakamoto
54248b7802STakashi Sakamoto if (up)
5503e2a67eSTakashi Sakamoto amdtp_am824_midi_trigger(&bebob->tx_stream,
56248b7802STakashi Sakamoto substrm->number, substrm);
57248b7802STakashi Sakamoto else
5803e2a67eSTakashi Sakamoto amdtp_am824_midi_trigger(&bebob->tx_stream,
59248b7802STakashi Sakamoto substrm->number, NULL);
60248b7802STakashi Sakamoto
61248b7802STakashi Sakamoto spin_unlock_irqrestore(&bebob->lock, flags);
62248b7802STakashi Sakamoto }
63248b7802STakashi Sakamoto
midi_playback_trigger(struct snd_rawmidi_substream * substrm,int up)64248b7802STakashi Sakamoto static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
65248b7802STakashi Sakamoto {
66248b7802STakashi Sakamoto struct snd_bebob *bebob = substrm->rmidi->private_data;
67248b7802STakashi Sakamoto unsigned long flags;
68248b7802STakashi Sakamoto
69248b7802STakashi Sakamoto spin_lock_irqsave(&bebob->lock, flags);
70248b7802STakashi Sakamoto
71248b7802STakashi Sakamoto if (up)
7203e2a67eSTakashi Sakamoto amdtp_am824_midi_trigger(&bebob->rx_stream,
73248b7802STakashi Sakamoto substrm->number, substrm);
74248b7802STakashi Sakamoto else
7503e2a67eSTakashi Sakamoto amdtp_am824_midi_trigger(&bebob->rx_stream,
76248b7802STakashi Sakamoto substrm->number, NULL);
77248b7802STakashi Sakamoto
78248b7802STakashi Sakamoto spin_unlock_irqrestore(&bebob->lock, flags);
79248b7802STakashi Sakamoto }
80248b7802STakashi Sakamoto
set_midi_substream_names(struct snd_bebob * bebob,struct snd_rawmidi_str * str)81248b7802STakashi Sakamoto static void set_midi_substream_names(struct snd_bebob *bebob,
82248b7802STakashi Sakamoto struct snd_rawmidi_str *str)
83248b7802STakashi Sakamoto {
84248b7802STakashi Sakamoto struct snd_rawmidi_substream *subs;
85248b7802STakashi Sakamoto
86248b7802STakashi Sakamoto list_for_each_entry(subs, &str->substreams, list) {
87*ea77850eSTakashi Iwai scnprintf(subs->name, sizeof(subs->name),
88248b7802STakashi Sakamoto "%s MIDI %d",
89248b7802STakashi Sakamoto bebob->card->shortname, subs->number + 1);
90248b7802STakashi Sakamoto }
91248b7802STakashi Sakamoto }
92248b7802STakashi Sakamoto
snd_bebob_create_midi_devices(struct snd_bebob * bebob)93248b7802STakashi Sakamoto int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
94248b7802STakashi Sakamoto {
9557eb6799STakashi Iwai static const struct snd_rawmidi_ops capture_ops = {
9673f7864eSTakashi Sakamoto .open = midi_open,
9773f7864eSTakashi Sakamoto .close = midi_close,
984780f774STakashi Sakamoto .trigger = midi_capture_trigger,
994780f774STakashi Sakamoto };
10057eb6799STakashi Iwai static const struct snd_rawmidi_ops playback_ops = {
10173f7864eSTakashi Sakamoto .open = midi_open,
10273f7864eSTakashi Sakamoto .close = midi_close,
1034780f774STakashi Sakamoto .trigger = midi_playback_trigger,
1044780f774STakashi Sakamoto };
105248b7802STakashi Sakamoto struct snd_rawmidi *rmidi;
106248b7802STakashi Sakamoto struct snd_rawmidi_str *str;
107248b7802STakashi Sakamoto int err;
108248b7802STakashi Sakamoto
109248b7802STakashi Sakamoto /* create midi ports */
110248b7802STakashi Sakamoto err = snd_rawmidi_new(bebob->card, bebob->card->driver, 0,
111248b7802STakashi Sakamoto bebob->midi_output_ports, bebob->midi_input_ports,
112248b7802STakashi Sakamoto &rmidi);
113248b7802STakashi Sakamoto if (err < 0)
114248b7802STakashi Sakamoto return err;
115248b7802STakashi Sakamoto
116248b7802STakashi Sakamoto snprintf(rmidi->name, sizeof(rmidi->name),
117248b7802STakashi Sakamoto "%s MIDI", bebob->card->shortname);
118248b7802STakashi Sakamoto rmidi->private_data = bebob;
119248b7802STakashi Sakamoto
120248b7802STakashi Sakamoto if (bebob->midi_input_ports > 0) {
121248b7802STakashi Sakamoto rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
122248b7802STakashi Sakamoto
123248b7802STakashi Sakamoto snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
1244780f774STakashi Sakamoto &capture_ops);
125248b7802STakashi Sakamoto
126248b7802STakashi Sakamoto str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
127248b7802STakashi Sakamoto
128248b7802STakashi Sakamoto set_midi_substream_names(bebob, str);
129248b7802STakashi Sakamoto }
130248b7802STakashi Sakamoto
131248b7802STakashi Sakamoto if (bebob->midi_output_ports > 0) {
132248b7802STakashi Sakamoto rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
133248b7802STakashi Sakamoto
134248b7802STakashi Sakamoto snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
1354780f774STakashi Sakamoto &playback_ops);
136248b7802STakashi Sakamoto
137248b7802STakashi Sakamoto str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
138248b7802STakashi Sakamoto
139248b7802STakashi Sakamoto set_midi_substream_names(bebob, str);
140248b7802STakashi Sakamoto }
141248b7802STakashi Sakamoto
142248b7802STakashi Sakamoto if ((bebob->midi_output_ports > 0) && (bebob->midi_input_ports > 0))
143248b7802STakashi Sakamoto rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
144248b7802STakashi Sakamoto
145248b7802STakashi Sakamoto return 0;
146248b7802STakashi Sakamoto }
147