From patchwork Fri Apr 25 13:45:18 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Sakamoto X-Patchwork-Id: 4063531 X-Patchwork-Delegate: tiwai@suse.de Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A96909F1F4 for ; Fri, 25 Apr 2014 14:32:15 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 99D5620398 for ; Fri, 25 Apr 2014 14:32:14 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 378BB2037D for ; Fri, 25 Apr 2014 14:32:13 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 55151265A66; Fri, 25 Apr 2014 16:32:12 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 0E9F1265740; Fri, 25 Apr 2014 16:01:41 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id E827A265522; Fri, 25 Apr 2014 16:01:39 +0200 (CEST) Received: from smtp310.phy.lolipop.jp (smtp310.phy.lolipop.jp [210.157.22.78]) by alsa0.perex.cz (Postfix) with ESMTP id 0D94D265524 for ; Fri, 25 Apr 2014 15:46:49 +0200 (CEST) Received: from smtp310.phy.lolipop.lan (HELO smtp310.phy.lolipop.jp) (172.17.1.10) (smtp-auth username m12129643-o-takashi, mechanism plain) by smtp310.phy.lolipop.jp (qpsmtpd/0.82) with ESMTPA; Fri, 25 Apr 2014 22:46:47 +0900 Received: from 127.0.0.1 (127.0.0.1) by smtp310.phy.lolipop.jp (LOLIPOP-Fsecure); Fri, 25 Apr 2014 22:45:31 +0900 (JST) X-Virus-Status: clean(LOLIPOP-Fsecure) From: Takashi Sakamoto To: clemens@ladisch.de, tiwai@suse.de, perex@perex.cz Date: Fri, 25 Apr 2014 22:45:18 +0900 Message-Id: <1398433530-13136-38-git-send-email-o-takashi@sakamocchi.jp> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1398433530-13136-1-git-send-email-o-takashi@sakamocchi.jp> References: <1398433530-13136-1-git-send-email-o-takashi@sakamocchi.jp> Cc: alsa-devel@alsa-project.org, linux1394-devel@lists.sourceforge.net, ffado-devel@lists.sf.net Subject: [alsa-devel] [PATCH 37/49] bebob: Add MIDI interface X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- sound/firewire/Kconfig | 1 + sound/firewire/bebob/Makefile | 3 +- sound/firewire/bebob/bebob.c | 7 ++ sound/firewire/bebob/bebob.h | 3 + sound/firewire/bebob/bebob_midi.c | 148 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 sound/firewire/bebob/bebob_midi.c diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 5539baa..708d3c8 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -82,6 +82,7 @@ config SND_FIREWORKS config SND_BEBOB tristate "BridgeCo DM1000/DM1100/DM1500 with BeBoB firmware" select SND_FIREWIRE_LIB + select SND_RAWMIDI help Say Y here to include support for FireWire devices based on BridgeCo DM1000/DM1100/DM1500 with BeBoB firmware: diff --git a/sound/firewire/bebob/Makefile b/sound/firewire/bebob/Makefile index 757c40e..1e39e59 100644 --- a/sound/firewire/bebob/Makefile +++ b/sound/firewire/bebob/Makefile @@ -1,2 +1,3 @@ -snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob.o +snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \ + bebob.o obj-m += snd-bebob.o diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 0c3f1f6..383df9a 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -164,6 +164,13 @@ bebob_probe(struct fw_unit *unit, snd_bebob_proc_init(bebob); + if ((bebob->midi_input_ports > 0) || + (bebob->midi_output_ports > 0)) { + err = snd_bebob_create_midi_devices(bebob); + if (err < 0) + goto error; + } + err = snd_bebob_stream_init_duplex(bebob); if (err < 0) goto error; diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 1247cca..0d53cff 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "../lib.h" #include "../fcp.h" @@ -174,6 +175,8 @@ void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob); void snd_bebob_proc_init(struct snd_bebob *bebob); +int snd_bebob_create_midi_devices(struct snd_bebob *bebob); + #define SND_BEBOB_DEV_ENTRY(vendor, model) \ { \ .match_flags = IEEE1394_MATCH_VENDOR_ID | \ diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c new file mode 100644 index 0000000..120a61b9 --- /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; +}