diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 22:45:18 +0900 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 14:30:16 +0200 |
commit | 248b78027d26735eb22f5ee91a400e5eabfea77d (patch) | |
tree | c0059652bb1b659b6d76f37b061e65e642e849b7 /sound/firewire/bebob/bebob_midi.c | |
parent | ad9697bad78fab4665d93e61c702892e289e1764 (diff) |
ALSA: bebob: Add MIDI interface
This commit adds a functionality to capture/playback MIDI messages.
When no AMDTP streams are running, this module starts AMDTP stream at current
sampling rate for MIDI substream.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/bebob/bebob_midi.c')
-rw-r--r-- | sound/firewire/bebob/bebob_midi.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c new file mode 100644 index 000000000000..120a61b90c59 --- /dev/null +++ b/sound/firewire/bebob/bebob_midi.c @@ -0,0 +1,148 @@ +/* + * bebob_midi.c - a part of driver for BeBoB based devices + * + * Copyright (c) 2013-2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "bebob.h" + +static int midi_capture_open(struct snd_rawmidi_substream *substream) +{ + struct snd_bebob *bebob = substream->rmidi->private_data; + + atomic_inc(&bebob->capture_substreams); + return snd_bebob_stream_start_duplex(bebob, 0); +} + +static int midi_playback_open(struct snd_rawmidi_substream *substream) +{ + struct snd_bebob *bebob = substream->rmidi->private_data; + + atomic_inc(&bebob->playback_substreams); + return snd_bebob_stream_start_duplex(bebob, 0); +} + +static int midi_capture_close(struct snd_rawmidi_substream *substream) +{ + struct snd_bebob *bebob = substream->rmidi->private_data; + + atomic_dec(&bebob->capture_substreams); + snd_bebob_stream_stop_duplex(bebob); + + return 0; +} + +static int midi_playback_close(struct snd_rawmidi_substream *substream) +{ + struct snd_bebob *bebob = substream->rmidi->private_data; + + atomic_dec(&bebob->playback_substreams); + snd_bebob_stream_stop_duplex(bebob); + + return 0; +} + +static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) +{ + struct snd_bebob *bebob = substrm->rmidi->private_data; + unsigned long flags; + + spin_lock_irqsave(&bebob->lock, flags); + + if (up) + amdtp_stream_midi_trigger(&bebob->tx_stream, + substrm->number, substrm); + else + amdtp_stream_midi_trigger(&bebob->tx_stream, + substrm->number, NULL); + + spin_unlock_irqrestore(&bebob->lock, flags); +} + +static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) +{ + struct snd_bebob *bebob = substrm->rmidi->private_data; + unsigned long flags; + + spin_lock_irqsave(&bebob->lock, flags); + + if (up) + amdtp_stream_midi_trigger(&bebob->rx_stream, + substrm->number, substrm); + else + amdtp_stream_midi_trigger(&bebob->rx_stream, + substrm->number, NULL); + + spin_unlock_irqrestore(&bebob->lock, flags); +} + +static struct snd_rawmidi_ops midi_capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, +}; + +static struct snd_rawmidi_ops midi_playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, +}; + +static void set_midi_substream_names(struct snd_bebob *bebob, + struct snd_rawmidi_str *str) +{ + struct snd_rawmidi_substream *subs; + + list_for_each_entry(subs, &str->substreams, list) { + snprintf(subs->name, sizeof(subs->name), + "%s MIDI %d", + bebob->card->shortname, subs->number + 1); + } +} + +int snd_bebob_create_midi_devices(struct snd_bebob *bebob) +{ + struct snd_rawmidi *rmidi; + struct snd_rawmidi_str *str; + int err; + + /* create midi ports */ + err = snd_rawmidi_new(bebob->card, bebob->card->driver, 0, + bebob->midi_output_ports, bebob->midi_input_ports, + &rmidi); + if (err < 0) + return err; + + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", bebob->card->shortname); + rmidi->private_data = bebob; + + if (bebob->midi_input_ports > 0) { + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; + + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &midi_capture_ops); + + str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; + + set_midi_substream_names(bebob, str); + } + + if (bebob->midi_output_ports > 0) { + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; + + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &midi_playback_ops); + + str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; + + set_midi_substream_names(bebob, str); + } + + if ((bebob->midi_output_ports > 0) && (bebob->midi_input_ports > 0)) + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; + + return 0; +} |