diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 22:45:09 +0900 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 14:28:01 +0200 |
commit | a63d3ff1059a4d2236521e4fdbafabfc62b4f81a (patch) | |
tree | 4598ead1e5c0f3e3b09881d361cd892475be1b88 /sound/firewire/fireworks | |
parent | 6a22683e89e2c851f754ebbec0f2a53f2967bc07 (diff) |
ALSA: fireworks: Add MIDI interface
This commit adds a functionality to capture/playback MIDI messages.
When no AMDTP streams are running, this driver starts AMDTP stream for MIDI
stream at current sampling rate.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/fireworks')
-rw-r--r-- | sound/firewire/fireworks/Makefile | 3 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.c | 6 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.h | 3 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_midi.c | 147 |
4 files changed, 158 insertions, 1 deletions
diff --git a/sound/firewire/fireworks/Makefile b/sound/firewire/fireworks/Makefile index 52bd15e285b0..a2cecc6d8a4a 100644 --- a/sound/firewire/fireworks/Makefile +++ b/sound/firewire/fireworks/Makefile @@ -1,3 +1,4 @@ snd-fireworks-objs := fireworks_transaction.o fireworks_command.o \ - fireworks_stream.o fireworks_proc.o fireworks.o + fireworks_stream.o fireworks_proc.o fireworks_midi.o \ + fireworks.o obj-m += snd-fireworks.o diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 311e4a6ef0a6..9204c7c56513 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -226,6 +226,12 @@ efw_probe(struct fw_unit *unit, snd_efw_proc_init(efw); + if (efw->midi_out_ports || efw->midi_in_ports) { + err = snd_efw_create_midi_devices(efw); + if (err < 0) + goto error; + } + err = snd_efw_stream_init_duplex(efw); if (err < 0) goto error; diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index eef7ad89fd4e..d1819696754d 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -22,6 +22,7 @@ #include <sound/initval.h> #include <sound/pcm.h> #include <sound/info.h> +#include <sound/rawmidi.h> #include "../packets-buffer.h" #include "../iso-resources.h" @@ -198,6 +199,8 @@ void snd_efw_stream_destroy_duplex(struct snd_efw *efw); void snd_efw_proc_init(struct snd_efw *efw); +int snd_efw_create_midi_devices(struct snd_efw *efw); + #define SND_EFW_DEV_ENTRY(vendor, model) \ { \ .match_flags = IEEE1394_MATCH_VENDOR_ID | \ diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c new file mode 100644 index 000000000000..cbf34e99237f --- /dev/null +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -0,0 +1,147 @@ +/* + * fireworks_midi.c - a part of driver for Fireworks based devices + * + * Copyright (c) 2009-2010 Clemens Ladisch + * Copyright (c) 2013-2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ +#include "fireworks.h" + +static int midi_capture_open(struct snd_rawmidi_substream *substream) +{ + struct snd_efw *efw = substream->rmidi->private_data; + + atomic_inc(&efw->capture_substreams); + return snd_efw_stream_start_duplex(efw, 0); +} + +static int midi_playback_open(struct snd_rawmidi_substream *substream) +{ + struct snd_efw *efw = substream->rmidi->private_data; + + atomic_inc(&efw->playback_substreams); + return snd_efw_stream_start_duplex(efw, 0); +} + +static int midi_capture_close(struct snd_rawmidi_substream *substream) +{ + struct snd_efw *efw = substream->rmidi->private_data; + + atomic_dec(&efw->capture_substreams); + snd_efw_stream_stop_duplex(efw); + + return 0; +} + +static int midi_playback_close(struct snd_rawmidi_substream *substream) +{ + struct snd_efw *efw = substream->rmidi->private_data; + + atomic_dec(&efw->playback_substreams); + snd_efw_stream_stop_duplex(efw); + + return 0; +} + +static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) +{ + struct snd_efw *efw = substrm->rmidi->private_data; + unsigned long flags; + + spin_lock_irqsave(&efw->lock, flags); + + if (up) + amdtp_stream_midi_trigger(&efw->tx_stream, + substrm->number, substrm); + else + amdtp_stream_midi_trigger(&efw->tx_stream, + substrm->number, NULL); + + spin_unlock_irqrestore(&efw->lock, flags); +} + +static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) +{ + struct snd_efw *efw = substrm->rmidi->private_data; + unsigned long flags; + + spin_lock_irqsave(&efw->lock, flags); + + if (up) + amdtp_stream_midi_trigger(&efw->rx_stream, + substrm->number, substrm); + else + amdtp_stream_midi_trigger(&efw->rx_stream, + substrm->number, NULL); + + spin_unlock_irqrestore(&efw->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_efw *efw, + 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", efw->card->shortname, subs->number + 1); + } +} + +int snd_efw_create_midi_devices(struct snd_efw *efw) +{ + struct snd_rawmidi *rmidi; + struct snd_rawmidi_str *str; + int err; + + /* create midi ports */ + err = snd_rawmidi_new(efw->card, efw->card->driver, 0, + efw->midi_out_ports, efw->midi_in_ports, + &rmidi); + if (err < 0) + return err; + + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", efw->card->shortname); + rmidi->private_data = efw; + + if (efw->midi_in_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(efw, str); + } + + if (efw->midi_out_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(efw, str); + } + + if ((efw->midi_out_ports > 0) && (efw->midi_in_ports > 0)) + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; + + return 0; +} |