From patchwork Wed Mar 5 10:48:11 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Sakamoto X-Patchwork-Id: 3772931 X-Patchwork-Delegate: tiwai@suse.de Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id AFC4ABF13A for ; Wed, 5 Mar 2014 11:04:41 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B07B220240 for ; Wed, 5 Mar 2014 11:04:40 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 3212F20211 for ; Wed, 5 Mar 2014 11:04:39 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 2705D265A36; Wed, 5 Mar 2014 12:04:36 +0100 (CET) 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 2E864265A79; Wed, 5 Mar 2014 11:54:17 +0100 (CET) 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 86641265A6E; Wed, 5 Mar 2014 11:54:14 +0100 (CET) Received: from smtp311.phy.lolipop.jp (smtp311.phy.lolipop.jp [210.157.22.79]) by alsa0.perex.cz (Postfix) with ESMTP id CD74E2658D4 for ; Wed, 5 Mar 2014 11:49:13 +0100 (CET) Received: from smtp311.phy.lolipop.lan (HELO smtp311.phy.lolipop.jp) (172.17.1.11) (smtp-auth username m12129643-o-takashi, mechanism plain) by smtp311.phy.lolipop.jp (qpsmtpd/0.82) with ESMTPA; Wed, 05 Mar 2014 19:49:12 +0900 Received: from 127.0.0.1 (127.0.0.1) by smtp311.phy.lolipop.jp (LOLIPOP-Fsecure); Wed, 05 Mar 2014 19:48:28 +0900 (JST) X-Virus-Status: clean(LOLIPOP-Fsecure) From: Takashi Sakamoto To: clemens@ladisch.de, tiwai@suse.de, perex@perex.cz Date: Wed, 5 Mar 2014 19:48:11 +0900 Message-Id: <1394016507-15761-24-git-send-email-o-takashi@sakamocchi.jp> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1394016507-15761-1-git-send-email-o-takashi@sakamocchi.jp> References: <5316963F.1000206@sakamocchi.jp> <1394016507-15761-1-git-send-email-o-takashi@sakamocchi.jp> Cc: alsa-devel@alsa-project.org, ffado-devel@lists.sf.net Subject: [alsa-devel] [PATCH 23/39] fireworks: 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 driver starts AMDTP stream for MIDI stream at current sampling rate. --- sound/firewire/Kconfig | 1 + sound/firewire/fireworks/Makefile | 3 +- sound/firewire/fireworks/fireworks.c | 6 ++ sound/firewire/fireworks/fireworks.h | 3 + sound/firewire/fireworks/fireworks_midi.c | 158 ++++++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 sound/firewire/fireworks/fireworks_midi.c diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 0b85ebd..36a1212 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -64,6 +64,7 @@ config SND_SCS1X config SND_FIREWORKS tristate "Echo Fireworks board module support" select SND_FIREWIRE_LIB + select SND_RAWMIDI help Say Y here to include support for FireWire devices based on Echo Digital Audio Fireworks board: diff --git a/sound/firewire/fireworks/Makefile b/sound/firewire/fireworks/Makefile index 52bd15e..a2cecc6 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 52adce0..85dbad3 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -201,6 +201,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_card_register(card); if (err < 0) goto error; diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 4d69c0d..0dfed97 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "../packets-buffer.h" #include "../iso-resources.h" @@ -189,6 +190,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 0000000..a950fd1 --- /dev/null +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -0,0 +1,158 @@ +/* + * fireworks_midi.c - a part of driver for Fireworks based devices + * + * Copyright (c) 2009-2010 Clemens Ladisch + * Copyright (c) 2013 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; + + efw->capture_substreams++; + return snd_efw_stream_start_duplex(efw, &efw->tx_stream, 0); +} + +static int midi_playback_open(struct snd_rawmidi_substream *substream) +{ + struct snd_efw *efw = substream->rmidi->private_data; + + efw->playback_substreams++; + return snd_efw_stream_start_duplex(efw, &efw->rx_stream, 0); +} + +static int midi_capture_close(struct snd_rawmidi_substream *substream) +{ + struct snd_efw *efw = substream->rmidi->private_data; + + 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; + + 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; + + /* check the number of midi stream */ + if ((efw->midi_in_ports > SND_EFW_MAX_MIDI_IN_PORTS) | + (efw->midi_out_ports > SND_EFW_MAX_MIDI_OUT_PORTS)) + return -EIO; + + /* 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); + + /* + * Fireworks ignores MIDI messages in greater than first 8 data + * blocks of an AMDTP packet. + */ + efw->rx_stream.blocks_for_midi = 8; + } + + if ((efw->midi_out_ports > 0) && (efw->midi_in_ports > 0)) + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; + + return 0; +}