From patchwork Tue May 23 07:53:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251774 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A4930C77B75 for ; Tue, 23 May 2023 07:56:01 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 02BAF3E7; Tue, 23 May 2023 09:55:09 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 02BAF3E7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828559; bh=I/p60eavfID9D562lIw2hF811oSYAbXSFq7eo2sUKts=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=UKVB8zuzURCV+rnBrkgz381NSJy5iwWXflj3mUWgjz/TbB2/jlUI7UASLrWpU8brv ixGFJ8Y/gD89Ty58AwnugD8C8qKxCkeNy6SJXZrgPwH030ay69ZuemS2mQ0721m1lJ hkeS/2QioA4Uo8QV2h0lMCZehDZWOnnWT0zzWblo= Received: by alsa1.perex.cz (Postfix, from userid 50401) id A3E68F805AC; Tue, 23 May 2023 09:54:18 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id F1E5EF805AC; Tue, 23 May 2023 09:54:17 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id B6D6CF80587; Tue, 23 May 2023 09:54:13 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 10985F80086 for ; Tue, 23 May 2023 09:54:02 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 10985F80086 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=lLQAIxBb; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=sy5A0T9Y Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 6C3EF2279B; Tue, 23 May 2023 07:54:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828442; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VQF15d6OKz+sEjxW2B3qwnSbFxVOjFt/haCiYrsAH14=; b=lLQAIxBbwvchGZbm8jjK1tsC2EQoM1oVtvtYVSn05orlmuJZx2su/GV5gqsiT8wzB/5Mp5 ancYO95uDVXk7LmqLeCZblx6GS5ovTZWXb0kw8RuhaDdwHDp8NkHR4czCLz3DaNa730smY /pCNN64iHYQ5bOH1jICqJmo4i+wzRZg= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828442; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VQF15d6OKz+sEjxW2B3qwnSbFxVOjFt/haCiYrsAH14=; b=sy5A0T9YWWblAaN51i78ulcFKO9KzIPAH/Ok73YtWMfcDRo5VzXs4GUxgp8RM5Tv1DcBU3 rxdvVSGDHav8qJAA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 1CA8B13A1A; Tue, 23 May 2023 07:54:02 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id mFd7AxpxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:02 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 01/37] ALSA: rawmidi: Pass rawmidi directly to snd_rawmidi_kernel_open() Date: Tue, 23 May 2023 09:53:22 +0200 Message-Id: <20230523075358.9672-2-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: VLJKNEKGLOLY27KUZBAZ2LRYC2KGHR5Q X-Message-ID-Hash: VLJKNEKGLOLY27KUZBAZ2LRYC2KGHR5Q X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: snd_rawmidi_kernel_open() is used only internally from ALSA sequencer, so far, and parsing the card / device matching table at each open is redundant, as each sequencer client already gets the rawmidi object beforehand. This patch optimizes the path by passing the rawmidi object directly at snd_rawmidi_kernel_open(). This is also a preparation for the upcoming UMP rawmidi I/O support. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 2 +- sound/core/rawmidi.c | 17 ++++------------- sound/core/seq/seq_midi.c | 8 ++++---- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index e1f59b2940af..52b1cbfb2526 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -161,7 +161,7 @@ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream); /* main midi functions */ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info); -int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, +int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice, int mode, struct snd_rawmidi_file *rfile); int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile); int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7147fda66d93..589b75087d27 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -406,24 +406,15 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, } /* called from sound/core/seq/seq_midi.c */ -int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, +int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice, int mode, struct snd_rawmidi_file *rfile) { - struct snd_rawmidi *rmidi; - int err = 0; + int err; if (snd_BUG_ON(!rfile)) return -EINVAL; - - mutex_lock(®ister_mutex); - rmidi = snd_rawmidi_search(card, device); - if (!rmidi) - err = -ENODEV; - else if (!try_module_get(rmidi->card->module)) - err = -ENXIO; - mutex_unlock(®ister_mutex); - if (err < 0) - return err; + if (!try_module_get(rmidi->card->module)) + return -ENXIO; mutex_lock(&rmidi->open_mutex); err = rawmidi_open_priv(rmidi, subdevice, mode, rfile); diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 4589aac09154..2b5fff80de58 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -38,6 +38,7 @@ MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes."); /* data for this midi synth driver */ struct seq_midisynth { struct snd_card *card; + struct snd_rawmidi *rmidi; int device; int subdevice; struct snd_rawmidi_file input_rfile; @@ -168,8 +169,7 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe struct snd_rawmidi_params params; /* open midi port */ - err = snd_rawmidi_kernel_open(msynth->card, msynth->device, - msynth->subdevice, + err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice, SNDRV_RAWMIDI_LFLG_INPUT, &msynth->input_rfile); if (err < 0) { @@ -212,8 +212,7 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info struct snd_rawmidi_params params; /* open midi port */ - err = snd_rawmidi_kernel_open(msynth->card, msynth->device, - msynth->subdevice, + err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice, SNDRV_RAWMIDI_LFLG_OUTPUT, &msynth->output_rfile); if (err < 0) { @@ -328,6 +327,7 @@ snd_seq_midisynth_probe(struct device *_dev) for (p = 0; p < ports; p++) { ms = &msynth[p]; + ms->rmidi = rmidi; if (snd_seq_midisynth_new(ms, card, device, p) < 0) goto __nomem; From patchwork Tue May 23 07:53:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251815 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4D1D8C7EE23 for ; Tue, 23 May 2023 08:05:02 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 43C5DEA9; Tue, 23 May 2023 10:04:10 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 43C5DEA9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829100; bh=ZdlTPH9tx9kHqQ9wgVUvTHqhV3bd9Irh3kp04UL0Xhw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=mBIzKhHjO796/1egNs7WCbqOrscAv4SKobeLm1SLMSoIdNnmT8JQqJ4Y9n88YjcX8 qZmiJUnXhkA5u5Yu1lJE73dJ1hkxq5H0XJ3MEhJe2p+teXWFWGmv4Lxurhn9gMT8aM fy58mp8Eq1ejgBP9+eE9oiW8N4NAhUOuvJRFJacM= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 3F692F80551; Tue, 23 May 2023 09:56:52 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 476CFF805C9; Tue, 23 May 2023 09:56:52 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 505A3F805C9; Tue, 23 May 2023 09:56:49 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 27F60F80249 for ; Tue, 23 May 2023 09:54:02 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 27F60F80249 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=PKJPHpLd; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=kz87lPoH Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 9A06A227A4; Tue, 23 May 2023 07:54:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828442; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=b27Ref8ImoJXjyPyFCsfRMw/pwLg1dpXQ6Knv5YaWzU=; b=PKJPHpLdfovv6Ped0GtzgzELQxM8mRsu3WqXvCdt8I/E58Qazm1Pm91iqalS7QJIcBIjA4 I8mBnrm5/Vap0GtQFpj/lPlHM7X7qapDnWXhaKPFsA1kkxI0UuUn7KEf2q/9OmmYEsbSLE pktb1FHx9n7uhQysQbSOLiqAzuTgXdQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828442; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=b27Ref8ImoJXjyPyFCsfRMw/pwLg1dpXQ6Knv5YaWzU=; b=kz87lPoH4W2qwxgW5jaiQZ2noEOiUjbPXXNkot90FuBslb4W5kc6Q44UUk9yUm7j40oHE0 HcOTRm88wckEGRBA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 4E34413588; Tue, 23 May 2023 07:54:02 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id sL4kEhpxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:02 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 02/37] ALSA: rawmidi: Add ioctl callback to snd_rawmidi_global_ops Date: Tue, 23 May 2023 09:53:23 +0200 Message-Id: <20230523075358.9672-3-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: NVXBGVI5362BAZE3LWR47KXG2H2NF4E5 X-Message-ID-Hash: NVXBGVI5362BAZE3LWR47KXG2H2NF4E5 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: A new callback, ioctl, is added to snd_rawmidi_global_ops for allowing the driver to deal with the own ioctls. This is another preparation patch for the upcoming UMP support. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 2 ++ sound/core/rawmidi.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 52b1cbfb2526..84413cfcdcb5 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -47,6 +47,8 @@ struct snd_rawmidi_global_ops { int (*dev_unregister) (struct snd_rawmidi * rmidi); void (*get_port_info)(struct snd_rawmidi *rmidi, int number, struct snd_seq_port_info *info); + long (*ioctl)(struct snd_rawmidi *rmidi, unsigned int cmd, + void __user *argp); }; struct snd_rawmidi_runtime { diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 589b75087d27..ab28cfc1fac8 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -893,6 +893,7 @@ static int snd_rawmidi_ioctl_status64(struct snd_rawmidi_file *rfile, static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_rawmidi_file *rfile; + struct snd_rawmidi *rmidi; void __user *argp = (void __user *)arg; rfile = file->private_data; @@ -984,8 +985,10 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long } } default: - rmidi_dbg(rfile->rmidi, - "rawmidi: unknown command = 0x%x\n", cmd); + rmidi = rfile->rmidi; + if (rmidi->ops && rmidi->ops->ioctl) + return rmidi->ops->ioctl(rmidi, cmd, argp); + rmidi_dbg(rmidi, "rawmidi: unknown command = 0x%x\n", cmd); } return -ENOTTY; } From patchwork Tue May 23 07:53:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251777 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C8F65C7EE26 for ; Tue, 23 May 2023 07:56:37 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id D6180204; Tue, 23 May 2023 09:55:45 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz D6180204 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828596; bh=dc9KgbZVIGI7W4HMjn2FBUc9VORIO1ZnCZT8OEZmm0Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=Am/GoKU4te2LtAVbAQgt8602696zMttWM6oAo5sjYd4iF1qjrgaR1DzMecUBpOBCg 5tgUL8eCCueG/39uCdu7dl6+CI/yzGMuXfDyakZrH/kBZ8RA4zNSme1NkKPBllgjLP ERXHlNMNmfz3ILAcPvnIPbNEq0dskWvUvK6uJGug= Received: by alsa1.perex.cz (Postfix, from userid 50401) id E748BF805D7; Tue, 23 May 2023 09:54:34 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id EE7C5F805CA; Tue, 23 May 2023 09:54:33 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 19054F805C9; Tue, 23 May 2023 09:54:29 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id C4D0AF8024E for ; Tue, 23 May 2023 09:54:03 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz C4D0AF8024E Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=Fpx0zemT; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=jqyYqBHf Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 232BA211E1; Tue, 23 May 2023 07:54:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828443; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=P77TInkq3OcKK0+Ua/sV5m/uS4++7tsVHOOokqewZ+Y=; b=Fpx0zemTsLc4TftKXz/wecZ9SCIe+o0OVexMqZbCr90QzFLx3cc/g6v7izVh8v8/s+QSb+ AHvtjwpDtLkWglah59AUhqhaoRE62EGy1HVSpi0NqrCu2QxXM0NhaVqJVBGNjULB+eSy6G /46qYOaVj5QuI+U2yb4QCkd3mKvBesY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828443; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=P77TInkq3OcKK0+Ua/sV5m/uS4++7tsVHOOokqewZ+Y=; b=jqyYqBHf6jYrzEjwQdUI0VFhjVxrdryRn9UaAjrlerbPjkA9Oy2r+HHKS4v2nihArLyD5w xRDcP432yCR1M4Aw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id A34BE13A1A; Tue, 23 May 2023 07:54:02 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id aBT6JBpxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:02 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 03/37] ALSA: rawmidi: UMP support Date: Tue, 23 May 2023 09:53:24 +0200 Message-Id: <20230523075358.9672-4-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: P6WRXGQRPR2YFPD3X5A2RHBPFJ7CFX4E X-Message-ID-Hash: P6WRXGQRPR2YFPD3X5A2RHBPFJ7CFX4E X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This patch adds the support helpers for UMP (Universal MIDI Packet) in ALSA core. The basic design is that a rawmidi instance is assigned to each UMP Endpoint. A UMP Endpoint provides a UMP stream, typically bidirectional (but can be also uni-directional, too), which may hold up to 16 UMP Groups, where each UMP (input/output) Group corresponds to the traditional MIDI I/O Endpoint. Additionally, the ALSA UMP abstraction provides the multiple UMP Blocks that can be assigned to each UMP Endpoint. A UMP Block is a metadata to hold the UMP Group clusters, and can represent the functions assigned to each UMP Group. A typical implementation of UMP Block is the Group Terminal Blocks of USB MIDI 2.0 specification. For distinguishing from the legacy byte-stream MIDI device, a new device "umpC*D*" will be created, instead of the standard (MIDI 1.0) devices "midiC*D*". The UMP instance can be identified by the new rawmidi info bit SNDRV_RAWMIDI_INFO_UMP, too. A UMP rawmidi device reads/writes only in 4-bytes words alignment, stored in CPU native endianness. The transmit and receive functions take care of the input/out data alignment, and may return zero or aligned size, and the params ioctl may return -EINVAL when the given input/output buffer size isn't aligned. A few new UMP-specific ioctls are added for obtaining the new UMP endpoint and block information. As of this commit, no ALSA sequencer instance is attached to UMP devices yet. They will be supported by later patches. Along with those changes, the protocol version for rawmidi is bumped to 2.0.3. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 8 ++ include/sound/ump.h | 118 ++++++++++++++++++ include/uapi/sound/asound.h | 57 ++++++++- sound/core/Kconfig | 4 + sound/core/Makefile | 2 + sound/core/rawmidi.c | 155 ++++++++++++++++-------- sound/core/rawmidi_compat.c | 4 + sound/core/ump.c | 230 ++++++++++++++++++++++++++++++++++++ 8 files changed, 529 insertions(+), 49 deletions(-) create mode 100644 include/sound/ump.h create mode 100644 sound/core/ump.c diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 84413cfcdcb5..b8a230a7583b 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -63,6 +63,7 @@ struct snd_rawmidi_runtime { size_t avail_min; /* min avail for wakeup */ size_t avail; /* max used buffer for wakeup */ size_t xruns; /* over/underruns counter */ + size_t align; /* alignment (0 = byte stream, 3 = UMP) */ int buffer_ref; /* buffer reference count */ /* misc */ wait_queue_head_t sleep; @@ -148,6 +149,13 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, const struct snd_rawmidi_ops *ops); +/* internal */ +int snd_rawmidi_init(struct snd_rawmidi *rmidi, + struct snd_card *card, char *id, int device, + int output_count, int input_count, + unsigned int info_flags); +int snd_rawmidi_free(struct snd_rawmidi *rmidi); + /* callbacks */ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, diff --git a/include/sound/ump.h b/include/sound/ump.h new file mode 100644 index 000000000000..8a3ac97cd1d3 --- /dev/null +++ b/include/sound/ump.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Universal MIDI Packet (UMP) Support + */ +#ifndef __SOUND_UMP_H +#define __SOUND_UMP_H + +#include + +struct snd_ump_endpoint; +struct snd_ump_block; + +struct snd_ump_endpoint { + struct snd_rawmidi core; /* raw UMP access */ + + struct snd_ump_endpoint_info info; + + void *private_data; + void (*private_free)(struct snd_ump_endpoint *ump); + + struct list_head block_list; /* list of snd_ump_block objects */ +}; + +struct snd_ump_block { + struct snd_ump_block_info info; + struct snd_ump_endpoint *ump; + + void *private_data; + void (*private_free)(struct snd_ump_block *blk); + + struct list_head list; +}; + +#define rawmidi_to_ump(rmidi) container_of(rmidi, struct snd_ump_endpoint, core) + +int snd_ump_endpoint_new(struct snd_card *card, char *id, int device, + int output, int input, + struct snd_ump_endpoint **ump_ret); +int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, + unsigned int direction, unsigned int first_group, + unsigned int num_groups, struct snd_ump_block **blk_ret); + +/* + * Some definitions for UMP + */ + +/* MIDI 2.0 Message Type */ +enum { + UMP_MSG_TYPE_UTILITY = 0x00, + UMP_MSG_TYPE_SYSTEM = 0x01, + UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE = 0x02, + UMP_MSG_TYPE_DATA = 0x03, + UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE = 0x04, + UMP_MSG_TYPE_EXTENDED_DATA = 0x05, +}; + +/* MIDI 2.0 SysEx / Data Status; same values for both 7-bit and 8-bit SysEx */ +enum { + UMP_SYSEX_STATUS_SINGLE = 0, + UMP_SYSEX_STATUS_START = 1, + UMP_SYSEX_STATUS_CONTINUE = 2, + UMP_SYSEX_STATUS_END = 3, +}; + +/* + * Helpers for retrieving / filling bits from UMP + */ +/* get the message type (4bit) from a UMP packet (header) */ +static inline unsigned char ump_message_type(u32 data) +{ + return data >> 28; +} + +/* get the group number (0-based, 4bit) from a UMP packet (header) */ +static inline unsigned char ump_message_group(u32 data) +{ + return (data >> 24) & 0x0f; +} + +/* get the MIDI status code (4bit) from a UMP packet (header) */ +static inline unsigned char ump_message_status_code(u32 data) +{ + return (data >> 20) & 0x0f; +} + +/* get the MIDI channel number (0-based, 4bit) from a UMP packet (header) */ +static inline unsigned char ump_message_channel(u32 data) +{ + return (data >> 16) & 0x0f; +} + +/* get the MIDI status + channel combo byte (8bit) from a UMP packet (header) */ +static inline unsigned char ump_message_status_channel(u32 data) +{ + return (data >> 16) & 0xff; +} + +/* compose a UMP packet (header) from type, group and status values */ +static inline u32 ump_compose(unsigned char type, unsigned char group, + unsigned char status, unsigned char channel) +{ + return ((u32)type << 28) | ((u32)group << 24) | ((u32)status << 20) | + ((u32)channel << 16); +} + +/* get SysEx message status (for both 7 and 8bits) from a UMP packet (header) */ +static inline unsigned char ump_sysex_message_status(u32 data) +{ + return (data >> 20) & 0xf; +} + +/* get SysEx message length (for both 7 and 8bits) from a UMP packet (header) */ +static inline unsigned char ump_sysex_message_length(u32 data) +{ + return (data >> 16) & 0xf; +} + +#endif /* __SOUND_UMP_H */ diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 0aa955aa8246..b001df4b335e 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -708,7 +708,7 @@ enum { * Raw MIDI section - /dev/snd/midi?? */ -#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2) +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3) enum { SNDRV_RAWMIDI_STREAM_OUTPUT = 0, @@ -719,6 +719,7 @@ enum { #define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 #define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 #define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 +#define SNDRV_RAWMIDI_INFO_UMP 0x00000008 struct snd_rawmidi_info { unsigned int device; /* RO/WR (control): device number */ @@ -779,6 +780,57 @@ struct snd_rawmidi_status { }; #endif +/* UMP EP Protocol / JRTS capability bits */ +#define SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK 0x0300 +#define SNDRV_UMP_EP_INFO_PROTO_MIDI1 0x0100 /* MIDI 1.0 */ +#define SNDRV_UMP_EP_INFO_PROTO_MIDI2 0x0200 /* MIDI 2.0 */ +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_MASK 0x0003 +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_TX 0x0001 /* JRTS Transmit */ +#define SNDRV_UMP_EP_INFO_PROTO_JRTS_RX 0x0002 /* JRTS Receive */ + +/* UMP Endpoint information */ +struct snd_ump_endpoint_info { + int card; /* card number */ + int device; /* device number */ + unsigned int flags; /* additional info */ + unsigned int protocol_caps; /* protocol capabilities */ + unsigned int protocol; /* current protocol */ + unsigned int num_blocks; /* # of function blocks */ + unsigned short version; /* UMP major/minor version */ + unsigned short padding[7]; + unsigned char name[128]; /* endpoint name string */ + unsigned char product_id[128]; /* unique product id string */ + unsigned char reserved[32]; +} __packed; + +/* UMP direction */ +#define SNDRV_UMP_DIR_INPUT 0x01 +#define SNDRV_UMP_DIR_OUTPUT 0x02 +#define SNDRV_UMP_DIR_BIDIRECTION 0x03 + +/* UMP block info flags */ +#define SNDRV_UMP_BLOCK_IS_MIDI1 (1U << 0) /* MIDI 1.0 port w/o restrict */ +#define SNDRV_UMP_BLOCK_IS_LOWSPEED (1U << 1) /* 31.25Kbps B/W MIDI1 port */ + +/* UMP groups and blocks */ +#define SNDRV_UMP_MAX_GROUPS 16 +#define SNDRV_UMP_MAX_BLOCKS 32 + +/* UMP Block information */ +struct snd_ump_block_info { + int card; /* card number */ + int device; /* device number */ + unsigned char block_id; /* block ID (R/W) */ + unsigned char direction; /* UMP direction */ + unsigned char active; /* Activeness */ + unsigned char first_group; /* first group ID */ + unsigned char num_groups; /* number of groups */ + unsigned char padding[3]; + unsigned int flags; /* various info flags */ + unsigned char name[128]; /* block name string */ + unsigned char reserved[32]; +} __packed; + #define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) #define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) #define SNDRV_RAWMIDI_IOCTL_USER_PVERSION _IOW('W', 0x02, int) @@ -786,6 +838,9 @@ struct snd_rawmidi_status { #define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status) #define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) #define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) +/* Additional ioctls for UMP rawmidi devices */ +#define SNDRV_UMP_IOCTL_ENDPOINT_INFO _IOR('W', 0x40, struct snd_ump_endpoint_info) +#define SNDRV_UMP_IOCTL_BLOCK_INFO _IOR('W', 0x41, struct snd_ump_block_info) /* * Timer section - /dev/snd/timer diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 12990d9a4dff..eb1c6c930de9 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -26,6 +26,10 @@ config SND_RAWMIDI tristate select SND_SEQ_DEVICE if SND_SEQUENCER != n +config SND_UMP + tristate + select SND_RAWMIDI + config SND_COMPRESS_OFFLOAD tristate diff --git a/sound/core/Makefile b/sound/core/Makefile index 2762f03d9b7b..562a05edbc50 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -28,6 +28,7 @@ snd-pcm-dmaengine-objs := pcm_dmaengine.o snd-ctl-led-objs := control_led.o snd-rawmidi-objs := rawmidi.o +snd-ump-objs := ump.o snd-timer-objs := timer.o snd-hrtimer-objs := hrtimer.o snd-rtctimer-objs := rtctimer.o @@ -45,6 +46,7 @@ obj-$(CONFIG_SND_PCM) += snd-pcm.o obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o +obj-$(CONFIG_SND_UMP) += snd-ump.o obj-$(CONFIG_SND_OSSEMUL) += oss/ obj-$(CONFIG_SND_SEQUENCER) += seq/ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index ab28cfc1fac8..6360e2239a63 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -21,6 +21,7 @@ #include #include #include +#include MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA."); @@ -35,7 +36,6 @@ module_param_array(amidi_map, int, NULL, 0444); MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device."); #endif /* CONFIG_SND_OSSEMUL */ -static int snd_rawmidi_free(struct snd_rawmidi *rmidi); static int snd_rawmidi_dev_free(struct snd_device *device); static int snd_rawmidi_dev_register(struct snd_device *device); static int snd_rawmidi_dev_disconnect(struct snd_device *device); @@ -73,6 +73,9 @@ struct snd_rawmidi_status64 { #define SNDRV_RAWMIDI_IOCTL_STATUS64 _IOWR('W', 0x20, struct snd_rawmidi_status64) +#define rawmidi_is_ump(rmidi) \ + (IS_ENABLED(CONFIG_SND_UMP) && ((rmidi)->info_flags & SNDRV_RAWMIDI_INFO_UMP)) + static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) { struct snd_rawmidi *rawmidi; @@ -181,9 +184,23 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) } runtime->appl_ptr = runtime->hw_ptr = 0; substream->runtime = runtime; + if (rawmidi_is_ump(substream->rmidi)) + runtime->align = 3; return 0; } +/* get the current alignment (either 0 or 3) */ +static inline int get_align(struct snd_rawmidi_runtime *runtime) +{ + if (IS_ENABLED(CONFIG_SND_UMP)) + return runtime->align; + else + return 0; +} + +/* get the trimmed size with the current alignment */ +#define get_aligned_size(runtime, size) ((size) & ~get_align(runtime)) + static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -721,6 +738,8 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream, return -EINVAL; if (params->avail_min < 1 || params->avail_min > params->buffer_size) return -EINVAL; + if (params->buffer_size & get_align(runtime)) + return -EINVAL; if (params->buffer_size != runtime->buffer_size) { newbuf = kvzalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) @@ -1046,12 +1065,13 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream, struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec }; int orig_count = src_count; int frame_size = sizeof(struct snd_rawmidi_framing_tstamp); + int align = get_align(runtime); BUILD_BUG_ON(frame_size != 0x20); if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0)) return -EINVAL; - while (src_count > 0) { + while (src_count > align) { if ((int)(runtime->buffer_size - runtime->avail) < frame_size) { runtime->xruns += src_count; break; @@ -1059,7 +1079,9 @@ static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream, if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH) frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH; else { - frame.length = src_count; + frame.length = get_aligned_size(runtime, src_count); + if (!frame.length) + break; memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH); } memcpy(frame.data, buffer, frame.length); @@ -1123,6 +1145,10 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, goto unlock; } + count = get_aligned_size(runtime, count); + if (!count) + goto unlock; + if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { result = receive_with_tstamp_framing(substream, buffer, count, &ts64); } else if (count == 1) { /* special case, faster code */ @@ -1142,6 +1168,9 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) count1 = runtime->buffer_size - runtime->avail; + count1 = get_aligned_size(runtime, count1); + if (!count1) + goto unlock; memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1); runtime->hw_ptr += count1; runtime->hw_ptr %= runtime->buffer_size; @@ -1342,12 +1371,18 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (int)(runtime->buffer_size - runtime->avail)) count1 = runtime->buffer_size - runtime->avail; + count1 = get_aligned_size(runtime, count1); + if (!count1) + goto __skip; memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1); count -= count1; result += count1; if (count > 0) { if (count > (int)(runtime->buffer_size - runtime->avail - count1)) count = runtime->buffer_size - runtime->avail - count1; + count = get_aligned_size(runtime, count); + if (!count) + goto __skip; memcpy(buffer + count1, runtime->buffer, count); result += count; } @@ -1404,6 +1439,7 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, return -EINVAL; } snd_BUG_ON(runtime->avail + count > runtime->buffer_size); + count = get_aligned_size(runtime, count); runtime->hw_ptr += count; runtime->hw_ptr %= runtime->buffer_size; runtime->avail += count; @@ -1690,6 +1726,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); + if (IS_ENABLED(CONFIG_SND_UMP)) + snd_iprintf(buffer, "Type: %s\n", + rawmidi_is_ump(rmidi) ? "UMP" : "Legacy"); mutex_lock(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { list_for_each_entry(substream, @@ -1800,6 +1839,56 @@ static void release_rawmidi_device(struct device *dev) kfree(container_of(dev, struct snd_rawmidi, dev)); } +/* used for both rawmidi and ump */ +int snd_rawmidi_init(struct snd_rawmidi *rmidi, + struct snd_card *card, char *id, int device, + int output_count, int input_count, + unsigned int info_flags) +{ + int err; + static const struct snd_device_ops ops = { + .dev_free = snd_rawmidi_dev_free, + .dev_register = snd_rawmidi_dev_register, + .dev_disconnect = snd_rawmidi_dev_disconnect, + }; + + rmidi->card = card; + rmidi->device = device; + mutex_init(&rmidi->open_mutex); + init_waitqueue_head(&rmidi->open_wait); + INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams); + INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams); + rmidi->info_flags = info_flags; + + if (id != NULL) + strscpy(rmidi->id, id, sizeof(rmidi->id)); + + snd_device_initialize(&rmidi->dev, card); + rmidi->dev.release = release_rawmidi_device; + if (rawmidi_is_ump(rmidi)) + dev_set_name(&rmidi->dev, "umpC%iD%i", card->number, device); + else + dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device); + + err = snd_rawmidi_alloc_substreams(rmidi, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], + SNDRV_RAWMIDI_STREAM_INPUT, + input_count); + if (err < 0) + return err; + err = snd_rawmidi_alloc_substreams(rmidi, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], + SNDRV_RAWMIDI_STREAM_OUTPUT, + output_count); + if (err < 0) + return err; + err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops); + if (err < 0) + return err; + return 0; +} +EXPORT_SYMBOL_GPL(snd_rawmidi_init); + /** * snd_rawmidi_new - create a rawmidi instance * @card: the card instance @@ -1820,56 +1909,21 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, { struct snd_rawmidi *rmidi; int err; - static const struct snd_device_ops ops = { - .dev_free = snd_rawmidi_dev_free, - .dev_register = snd_rawmidi_dev_register, - .dev_disconnect = snd_rawmidi_dev_disconnect, - }; - if (snd_BUG_ON(!card)) - return -ENXIO; if (rrawmidi) *rrawmidi = NULL; rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); if (!rmidi) return -ENOMEM; - rmidi->card = card; - rmidi->device = device; - mutex_init(&rmidi->open_mutex); - init_waitqueue_head(&rmidi->open_wait); - INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams); - INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams); - - if (id != NULL) - strscpy(rmidi->id, id, sizeof(rmidi->id)); - - snd_device_initialize(&rmidi->dev, card); - rmidi->dev.release = release_rawmidi_device; - dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device); - - err = snd_rawmidi_alloc_substreams(rmidi, - &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], - SNDRV_RAWMIDI_STREAM_INPUT, - input_count); - if (err < 0) - goto error; - err = snd_rawmidi_alloc_substreams(rmidi, - &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], - SNDRV_RAWMIDI_STREAM_OUTPUT, - output_count); - if (err < 0) - goto error; - err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops); - if (err < 0) - goto error; - + err = snd_rawmidi_init(rmidi, card, id, device, + output_count, input_count, 0); + if (err < 0) { + snd_rawmidi_free(rmidi); + return err; + } if (rrawmidi) *rrawmidi = rmidi; return 0; - - error: - snd_rawmidi_free(rmidi); - return err; } EXPORT_SYMBOL(snd_rawmidi_new); @@ -1884,7 +1938,8 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) } } -static int snd_rawmidi_free(struct snd_rawmidi *rmidi) +/* called from ump.c, too */ +int snd_rawmidi_free(struct snd_rawmidi *rmidi) { if (!rmidi) return 0; @@ -1901,6 +1956,7 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi) put_device(&rmidi->dev); return 0; } +EXPORT_SYMBOL_GPL(snd_rawmidi_free); static int snd_rawmidi_dev_free(struct snd_device *device) { @@ -1951,7 +2007,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } #ifdef CONFIG_SND_OSSEMUL rmidi->ossreg = 0; - if ((int)rmidi->device == midi_map[rmidi->card->number]) { + if (!rawmidi_is_ump(rmidi) && + (int)rmidi->device == midi_map[rmidi->card->number]) { if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0, &snd_rawmidi_f_ops, rmidi) < 0) { @@ -1965,7 +2022,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device) #endif } } - if ((int)rmidi->device == amidi_map[rmidi->card->number]) { + if (!rawmidi_is_ump(rmidi) && + (int)rmidi->device == amidi_map[rmidi->card->number]) { if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1, &snd_rawmidi_f_ops, rmidi) < 0) { @@ -1989,7 +2047,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } rmidi->proc_entry = entry; #if IS_ENABLED(CONFIG_SND_SEQUENCER) - if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ + /* no own registration mechanism? */ + if (!rmidi->ops || !rmidi->ops->dev_register) { if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { rmidi->seq_dev->private_data = rmidi; rmidi->seq_dev->private_free = snd_rawmidi_dev_seq_free; diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c index 68a93443583c..b81b30d82f88 100644 --- a/sound/core/rawmidi_compat.c +++ b/sound/core/rawmidi_compat.c @@ -111,6 +111,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign case SNDRV_RAWMIDI_IOCTL_INFO: case SNDRV_RAWMIDI_IOCTL_DROP: case SNDRV_RAWMIDI_IOCTL_DRAIN: +#if IS_ENABLED(CONFIG_SND_UMP) + case SNDRV_UMP_IOCTL_ENDPOINT_INFO: + case SNDRV_UMP_IOCTL_BLOCK_INFO: +#endif return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); case SNDRV_RAWMIDI_IOCTL_PARAMS32: return snd_rawmidi_ioctl_params_compat(rfile, argp); diff --git a/sound/core/ump.c b/sound/core/ump.c new file mode 100644 index 000000000000..ee57ba1ee989 --- /dev/null +++ b/sound/core/ump.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Universal MIDI Packet (UMP) support + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ump_err(ump, fmt, args...) dev_err(&(ump)->core.dev, fmt, ##args) +#define ump_warn(ump, fmt, args...) dev_warn(&(ump)->core.dev, fmt, ##args) +#define ump_info(ump, fmt, args...) dev_info(&(ump)->core.dev, fmt, ##args) +#define ump_dbg(ump, fmt, args...) dev_dbg(&(ump)->core.dev, fmt, ##args) + +static int snd_ump_dev_register(struct snd_rawmidi *rmidi); +static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi); +static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd, + void __user *argp); + +static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = { + .dev_register = snd_ump_dev_register, + .dev_unregister = snd_ump_dev_unregister, + .ioctl = snd_ump_ioctl, +}; + +static void snd_ump_endpoint_free(struct snd_rawmidi *rmidi) +{ + struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); + struct snd_ump_block *fb; + + while (!list_empty(&ump->block_list)) { + fb = list_first_entry(&ump->block_list, struct snd_ump_block, + list); + list_del(&fb->list); + if (fb->private_free) + fb->private_free(fb); + kfree(fb); + } + + if (ump->private_free) + ump->private_free(ump); +} + +/** + * snd_ump_endpoint_new - create a UMP Endpoint object + * @card: the card instance + * @id: the id string for rawmidi + * @device: the device index for rawmidi + * @output: 1 for enabling output + * @input: 1 for enabling input + * @ump_ret: the pointer to store the new UMP instance + * + * Creates a new UMP Endpoint object. A UMP Endpoint is tied with one rawmidi + * instance with one input and/or one output rawmidi stream (either uni- + * or bi-directional). A UMP Endpoint may contain one or multiple UMP Blocks + * that consist of one or multiple UMP Groups. + * + * Use snd_rawmidi_set_ops() to set the operators to the new instance. + * Unlike snd_rawmidi_new(), this function sets up the info_flags by itself + * depending on the given @output and @input. + * + * The device has SNDRV_RAWMIDI_INFO_UMP flag set and a different device + * file ("umpCxDx") than a standard MIDI 1.x device ("midiCxDx") is + * created. + * + * Return: Zero if successful, or a negative error code on failure. + */ +int snd_ump_endpoint_new(struct snd_card *card, char *id, int device, + int output, int input, + struct snd_ump_endpoint **ump_ret) +{ + unsigned int info_flags = SNDRV_RAWMIDI_INFO_UMP; + struct snd_ump_endpoint *ump; + int err; + + if (input) + info_flags |= SNDRV_RAWMIDI_INFO_INPUT; + if (output) + info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; + if (input && output) + info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; + + ump = kzalloc(sizeof(*ump), GFP_KERNEL); + if (!ump) + return -ENOMEM; + INIT_LIST_HEAD(&ump->block_list); + err = snd_rawmidi_init(&ump->core, card, id, device, + output, input, info_flags); + if (err < 0) { + snd_rawmidi_free(&ump->core); + return err; + } + + ump->info.card = card->number; + ump->info.device = device; + + ump->core.private_free = snd_ump_endpoint_free; + ump->core.ops = &snd_ump_rawmidi_ops; + + ump_dbg(ump, "Created a UMP EP #%d (%s)\n", device, id); + *ump_ret = ump; + return 0; +} +EXPORT_SYMBOL_GPL(snd_ump_endpoint_new); + +/* + * Device register / unregister hooks; + * do nothing, placeholders for avoiding the default rawmidi handling + */ +static int snd_ump_dev_register(struct snd_rawmidi *rmidi) +{ + return 0; +} + +static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi) +{ + return 0; +} + +static struct snd_ump_block * +snd_ump_get_block(struct snd_ump_endpoint *ump, unsigned char id) +{ + struct snd_ump_block *fb; + + list_for_each_entry(fb, &ump->block_list, list) { + if (fb->info.block_id == id) + return fb; + } + return NULL; +} + +/** + * snd_ump_block_new - Create a UMP block + * @ump: UMP object + * @blk: block ID number to create + * @direction: direction (in/out/bidirection) + * @first_group: the first group ID (0-based) + * @num_groups: the number of groups in this block + * @blk_ret: the pointer to store the resultant block object + */ +int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, + unsigned int direction, unsigned int first_group, + unsigned int num_groups, struct snd_ump_block **blk_ret) +{ + struct snd_ump_block *fb, *p; + + if (blk < 0 || blk >= SNDRV_UMP_MAX_BLOCKS) + return -EINVAL; + + if (snd_ump_get_block(ump, blk)) + return -EBUSY; + + fb = kzalloc(sizeof(*fb), GFP_KERNEL); + if (!fb) + return -ENOMEM; + + fb->ump = ump; + fb->info.card = ump->info.card; + fb->info.device = ump->info.device; + fb->info.block_id = blk; + if (blk >= ump->info.num_blocks) + ump->info.num_blocks = blk + 1; + fb->info.direction = direction; + fb->info.active = 1; + fb->info.first_group = first_group; + fb->info.num_groups = num_groups; + /* fill the default name, may be overwritten to a better name */ + snprintf(fb->info.name, sizeof(fb->info.name), "Group %d-%d", + first_group + 1, first_group + num_groups); + + /* put the entry in the ordered list */ + list_for_each_entry(p, &ump->block_list, list) { + if (p->info.block_id > blk) { + list_add_tail(&fb->list, &p->list); + goto added; + } + } + list_add_tail(&fb->list, &ump->block_list); + + added: + ump_dbg(ump, "Created a UMP Block #%d (%s)\n", blk, fb->info.name); + *blk_ret = fb; + return 0; +} +EXPORT_SYMBOL_GPL(snd_ump_block_new); + +static int snd_ump_ioctl_block(struct snd_ump_endpoint *ump, + struct snd_ump_block_info __user *argp) +{ + struct snd_ump_block *fb; + unsigned char id; + + if (get_user(id, &argp->block_id)) + return -EFAULT; + fb = snd_ump_get_block(ump, id); + if (!fb) + return -ENOENT; + if (copy_to_user(argp, &fb->info, sizeof(fb->info))) + return -EFAULT; + return 0; +} + +/* + * Handle UMP-specific ioctls; called from snd_rawmidi_ioctl() + */ +static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd, + void __user *argp) +{ + struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); + + switch (cmd) { + case SNDRV_UMP_IOCTL_ENDPOINT_INFO: + if (copy_to_user(argp, &ump->info, sizeof(ump->info))) + return -EFAULT; + return 0; + case SNDRV_UMP_IOCTL_BLOCK_INFO: + return snd_ump_ioctl_block(ump, argp); + default: + ump_dbg(ump, "rawmidi: unknown command = 0x%x\n", cmd); + return -ENOTTY; + } +} + +MODULE_DESCRIPTION("Universal MIDI Packet (UMP) Core Driver"); +MODULE_LICENSE("GPL"); From patchwork Tue May 23 07:53:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251775 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1CC43C7EE23 for ; Tue, 23 May 2023 07:56:08 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A6038820; Tue, 23 May 2023 09:55:15 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A6038820 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828565; bh=onLq1qk2kPtDpXRaVu1W02449ygtOesh5K96yHluOhE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=am73hWhe7+e8U4pTU8rOO5hKRCDKb0UmsHcUs4uKnmvgzr8od9AkV8LFXhJ/9JD4m uDtQw3LkgAT0HgLcSBBzlr7P2thd7W4g0jyeC5l+wXxP+Tlmw+AyDJFeBCEwaJu0xX LtFAel0kWiCyQp5Yfl+evkQ2qtB55lKHXJpmp3DI= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 2E56FF805C0; Tue, 23 May 2023 09:54:21 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id A4104F805B6; Tue, 23 May 2023 09:54:20 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id A5784F8058C; Tue, 23 May 2023 09:54:15 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 35BF9F80425 for ; Tue, 23 May 2023 09:54:03 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 35BF9F80425 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=s6ZDFeGW; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=abwDvXzy Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 99344218F1; Tue, 23 May 2023 07:54:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828443; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=es7gmVhOF2AYk9dNSNKDgpSwT7KFsv33WXRr9YFKqFs=; b=s6ZDFeGWrLVWOqLrnNGqOEJluot39f0E+9I5uajQZOnL7LMRF8gozQSdzJAwCIPAM+MNrR bnJ2WVTglj9W00WFQKvev66AhuxhBceZaeSelhgCvnvTTS2HneNo6mxwb9PU2ALc3z/TvM 7ParXxNC/ij5fgHZsm9WzF+5zTa+xSI= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828443; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=es7gmVhOF2AYk9dNSNKDgpSwT7KFsv33WXRr9YFKqFs=; b=abwDvXzyjmj71uPNJwhHvjSQGyyv2zYuxwcrfkGsnA5yZRUdf56OHi+UvsmrnCM8zHtvy/ xeCv4IUmte19TDDg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 2082113588; Tue, 23 May 2023 07:54:03 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id uKKuBRtxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:03 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 04/37] ALSA: rawmidi: Skip UMP devices at SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE Date: Tue, 23 May 2023 09:53:25 +0200 Message-Id: <20230523075358.9672-5-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: PT4I6Q3H5ZJ7C4YNAHNONHIRXRU2BXAH X-Message-ID-Hash: PT4I6Q3H5ZJ7C4YNAHNONHIRXRU2BXAH X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Applications may look for rawmidi devices with the ioctl SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE. Returning a UMP device from this ioctl may confuse the existing applications that support only the legacy rawmidi. This patch changes the code to skip the UMP devices from the lookup for avoiding the confusion, and introduces a new ioctl to look for the UMP devices instead. Along with this change, bump the CTL protocol version to 2.0.9. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 3 +- sound/core/rawmidi.c | 57 +++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index b001df4b335e..1e4a21036109 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -1016,7 +1016,7 @@ struct snd_timer_tread { * * ****************************************************************************/ -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8) +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9) struct snd_ctl_card_info { int card; /* card number */ @@ -1177,6 +1177,7 @@ struct snd_ctl_tlv { #define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) #define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) #define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) +#define SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE _IOWR('U', 0x43, int) #define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) #define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 6360e2239a63..9936ed282b85 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1012,6 +1012,37 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long return -ENOTTY; } +/* ioctl to find the next device; either legacy or UMP depending on @find_ump */ +static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp, + bool find_ump) + +{ + struct snd_rawmidi *rmidi; + int device; + bool is_ump; + + if (get_user(device, argp)) + return -EFAULT; + if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */ + device = SNDRV_RAWMIDI_DEVICES - 1; + mutex_lock(®ister_mutex); + device = device < 0 ? 0 : device + 1; + for (; device < SNDRV_RAWMIDI_DEVICES; device++) { + rmidi = snd_rawmidi_search(card, device); + if (!rmidi) + continue; + is_ump = rawmidi_is_ump(rmidi); + if (find_ump == is_ump) + break; + } + if (device == SNDRV_RAWMIDI_DEVICES) + device = -1; + mutex_unlock(®ister_mutex); + if (put_user(device, argp)) + return -EFAULT; + return 0; +} + static int snd_rawmidi_control_ioctl(struct snd_card *card, struct snd_ctl_file *control, unsigned int cmd, @@ -1021,27 +1052,11 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, switch (cmd) { case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE: - { - int device; - - if (get_user(device, (int __user *)argp)) - return -EFAULT; - if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */ - device = SNDRV_RAWMIDI_DEVICES - 1; - mutex_lock(®ister_mutex); - device = device < 0 ? 0 : device + 1; - while (device < SNDRV_RAWMIDI_DEVICES) { - if (snd_rawmidi_search(card, device)) - break; - device++; - } - if (device == SNDRV_RAWMIDI_DEVICES) - device = -1; - mutex_unlock(®ister_mutex); - if (put_user(device, (int __user *)argp)) - return -EFAULT; - return 0; - } + return snd_rawmidi_next_device(card, argp, false); +#if IS_ENABLED(CONFIG_SND_UMP) + case SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE: + return snd_rawmidi_next_device(card, argp, true); +#endif case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: { int val; From patchwork Tue May 23 07:53:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251776 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 08097C7EE23 for ; Tue, 23 May 2023 07:56:24 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 4F21383B; Tue, 23 May 2023 09:55:32 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 4F21383B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828582; bh=DbpU+rbdJkAT5qKgMi4+HaKaHkwa8ODYiocpf69dxtY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=Qdk663/ou5/j53295kC+TbF/zXP3qvZAWWrXLp5F9nwSfKmAxu/Sj9AdNX4U88im7 tRQ76ge6KqJOZCVQkoUzyfWbGCkXKwTr29fImfBflQe7E5YLVqlVIFtp4Usqr2A0yP A9oIhIlJsQJZ/4y1osmf1xJ+DimF7ZacBX8HjhIA= Received: by alsa1.perex.cz (Postfix, from userid 50401) id E7C23F805C3; Tue, 23 May 2023 09:54:28 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id EAA63F805B6; Tue, 23 May 2023 09:54:27 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 54944F805C1; Tue, 23 May 2023 09:54:24 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 4E49EF8053D for ; Tue, 23 May 2023 09:54:04 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 4E49EF8053D Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=aPH7OmYK; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=c6k2oPCv Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id E323A218F6; Tue, 23 May 2023 07:54:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828443; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mpcAAE3E4+YS/NXc11uNo67NAO9/YDf8hhSiZWIao78=; b=aPH7OmYKZu8BQQkdToCuu48NDoKzcKQjlgkw3HNaUK7AIxeKSliXjH9ehE1zUkm/o5pRek PlJQTagEc4URt3nlPdwV59STvRB4xeQ/tzIMQohGU1ZpM6SdbEHOo737PZAGFAm2Aq7Hfq wJB1s6cuOJ8m9CvFE0lJXTBGi3oI8Zk= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828443; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mpcAAE3E4+YS/NXc11uNo67NAO9/YDf8hhSiZWIao78=; b=c6k2oPCvgn3Eye7b7y7Caz/kTQVqr43clil4WgHn17wzsGG5Q0mqV/Ae3fFVHYi6MpWdxr occ8/bQsThCrkQCw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 8285113A24; Tue, 23 May 2023 07:54:03 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id mLFHHhtxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:03 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 05/37] ALSA: ump: Add ioctls to inquiry UMP EP and Block info via control API Date: Tue, 23 May 2023 09:53:26 +0200 Message-Id: <20230523075358.9672-6-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: XTHDPZ63UNBQAIEYSNCSTD2CAWCS5IVK X-Message-ID-Hash: XTHDPZ63UNBQAIEYSNCSTD2CAWCS5IVK X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: It'd be convenient to have ioctls to inquiry the UMP Endpoint and UMP Block information directly via the control API without opening the rawmidi interface, just like SNDRV_CTL_IOCTL_RAWMIDI_INFO. This patch extends the rawmidi ioctl handler to support those; new ioctls, SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO and SNDRV_CTL_IOCTL_UMP_BLOCK_INFO, return the snd_ump_endpoint and snd_ump_block data that is specified by the device field, respectively. Suggested-by: Jaroslav Kysela Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 2 ++ sound/core/rawmidi.c | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 1e4a21036109..5c5f41dd4001 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -1178,6 +1178,8 @@ struct snd_ctl_tlv { #define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) #define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) #define SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE _IOWR('U', 0x43, int) +#define SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO _IOWR('U', 0x44, struct snd_ump_endpoint_info) +#define SNDRV_CTL_IOCTL_UMP_BLOCK_INFO _IOWR('U', 0x45, struct snd_ump_block_info) #define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) #define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 9936ed282b85..ffb5b58105f4 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1043,6 +1043,28 @@ static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp, return 0; } +#if IS_ENABLED(CONFIG_SND_UMP) +/* inquiry of UMP endpoint and block info via control API */ +static int snd_rawmidi_call_ump_ioctl(struct snd_card *card, int cmd, + void __user *argp) +{ + struct snd_ump_endpoint_info __user *info = argp; + struct snd_rawmidi *rmidi; + int device, ret; + + if (get_user(device, &info->device)) + return -EFAULT; + mutex_lock(®ister_mutex); + rmidi = snd_rawmidi_search(card, device); + if (rmidi && rmidi->ops && rmidi->ops->ioctl) + ret = rmidi->ops->ioctl(rmidi, cmd, argp); + else + ret = -ENXIO; + mutex_unlock(®ister_mutex); + return ret; +} +#endif + static int snd_rawmidi_control_ioctl(struct snd_card *card, struct snd_ctl_file *control, unsigned int cmd, @@ -1056,6 +1078,10 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, #if IS_ENABLED(CONFIG_SND_UMP) case SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE: return snd_rawmidi_next_device(card, argp, true); + case SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO: + return snd_rawmidi_call_ump_ioctl(card, SNDRV_UMP_IOCTL_ENDPOINT_INFO, argp); + case SNDRV_CTL_IOCTL_UMP_BLOCK_INFO: + return snd_rawmidi_call_ump_ioctl(card, SNDRV_UMP_IOCTL_BLOCK_INFO, argp); #endif case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: { From patchwork Tue May 23 07:53:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251816 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 60442C7EE26 for ; Tue, 23 May 2023 08:05:26 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 8CB82E74; Tue, 23 May 2023 10:04:33 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 8CB82E74 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829123; bh=PU2p/pCj76SMlZcRoMs8YQGaLl6OBGHN7hkAOWp5tq4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=mGafwz5qaNT/Udhfdc6ba9gB3Z8DqsFT7Rp7ihda4wjA3po6VjuKrycmnzqICDYfK EGrvPRZOZKNN3Sj1U26G+ckLRcFYvE1XapuSWFZdq0Mri8JXeh0Zix0X72gGe4iRyq sToR+b9Wn3WbbeBHWHTegaDDOJO2NCcjph6Fn6N0= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 7E6AEF805E3; Tue, 23 May 2023 09:56:56 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id A5B45F805E2; Tue, 23 May 2023 09:56:55 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 987A5F805C8; Tue, 23 May 2023 09:56:49 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E037EF80542 for ; Tue, 23 May 2023 09:54:04 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E037EF80542 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=wG/pLiU0; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=DjW414mY Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 54D5E21899; Tue, 23 May 2023 07:54:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828444; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6ktXHEJwRtSCCBPJ4QDB5v/NoMHF3eNfNjpM8JZRdSA=; b=wG/pLiU0OcYlgFzM6QRLr+INpJvf0m4Hz2GMDUZ23jkPN2DGYViq3c7pfiuDiTTWf4C5jp PKIuq/GvgVXqPKSbsXtMXMtz0k6eo/NtpNm3m+cMMRm6ewLEZbP6Hep6WL3Tw0dBN8y6kc pWQMefdPxRLLA6Gf0Skw9fiHSxNqiRQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828444; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6ktXHEJwRtSCCBPJ4QDB5v/NoMHF3eNfNjpM8JZRdSA=; b=DjW414mYwn4rBb2KkFpafnCmgs9VHPabazpjcceVa0rlAjGheDlavBsNoHm6ApXEUo6OB7 uS0v3nxo3u116cAQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id F159613588; Tue, 23 May 2023 07:54:03 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 6P4GOhtxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:03 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 06/37] ALSA: ump: Additional proc output Date: Tue, 23 May 2023 09:53:27 +0200 Message-Id: <20230523075358.9672-7-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: CUSN63D3T72CS3AL6TCUJXG2V2TLI7PA X-Message-ID-Hash: CUSN63D3T72CS3AL6TCUJXG2V2TLI7PA X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: UMP devices may have more interesting information than the traditional rawmidi. Extend the rawmidi_global_ops to allow the optional proc info output and show some more bits in the proc file for UMP. Note that the "Groups" field shows the first and the last UMP Groups, and both numbers are 1-based (i.e. the first group is 1). Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 3 +++ sound/core/rawmidi.c | 2 ++ sound/core/ump.c | 49 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index b8a230a7583b..b0197b1d1fe4 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -18,6 +18,7 @@ #if IS_ENABLED(CONFIG_SND_SEQUENCER) #include #endif +#include /* * Raw MIDI interface @@ -49,6 +50,8 @@ struct snd_rawmidi_global_ops { struct snd_seq_port_info *info); long (*ioctl)(struct snd_rawmidi *rmidi, unsigned int cmd, void __user *argp); + void (*proc_read)(struct snd_info_entry *entry, + struct snd_info_buffer *buf); }; struct snd_rawmidi_runtime { diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index ffb5b58105f4..2d3cec908154 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1770,6 +1770,8 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, if (IS_ENABLED(CONFIG_SND_UMP)) snd_iprintf(buffer, "Type: %s\n", rawmidi_is_ump(rmidi) ? "UMP" : "Legacy"); + if (rmidi->ops->proc_read) + rmidi->ops->proc_read(entry, buffer); mutex_lock(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { list_for_each_entry(substream, diff --git a/sound/core/ump.c b/sound/core/ump.c index ee57ba1ee989..651cd3752719 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -21,11 +21,14 @@ static int snd_ump_dev_register(struct snd_rawmidi *rmidi); static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi); static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd, void __user *argp); +static void snd_ump_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer); static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = { .dev_register = snd_ump_dev_register, .dev_unregister = snd_ump_dev_unregister, .ioctl = snd_ump_ioctl, + .proc_read = snd_ump_proc_read, }; static void snd_ump_endpoint_free(struct snd_rawmidi *rmidi) @@ -226,5 +229,51 @@ static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd, } } +static const char *ump_direction_string(int dir) +{ + switch (dir) { + case SNDRV_UMP_DIR_INPUT: + return "input"; + case SNDRV_UMP_DIR_OUTPUT: + return "output"; + case SNDRV_UMP_DIR_BIDIRECTION: + return "bidirection"; + default: + return "unknown"; + } +} + +/* Additional proc file output */ +static void snd_ump_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_rawmidi *rmidi = entry->private_data; + struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); + struct snd_ump_block *fb; + + snd_iprintf(buffer, "EP Name: %s\n", ump->info.name); + snd_iprintf(buffer, "EP Product ID: %s\n", ump->info.product_id); + snd_iprintf(buffer, "UMP Version: 0x%04x\n", ump->info.version); + snd_iprintf(buffer, "Protocol Caps: 0x%08x\n", ump->info.protocol_caps); + snd_iprintf(buffer, "Protocol: 0x%08x\n", ump->info.protocol); + snd_iprintf(buffer, "Num Blocks: %d\n\n", ump->info.num_blocks); + + list_for_each_entry(fb, &ump->block_list, list) { + snd_iprintf(buffer, "Block %d (%s)\n", fb->info.block_id, + fb->info.name); + snd_iprintf(buffer, " Direction: %s\n", + ump_direction_string(fb->info.direction)); + snd_iprintf(buffer, " Active: %s\n", + fb->info.active ? "Yes" : "No"); + snd_iprintf(buffer, " Groups: %d-%d\n", + fb->info.first_group + 1, + fb->info.first_group + fb->info.num_groups); + snd_iprintf(buffer, " Is MIDI1: %s%s\n", + (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1) ? "Yes" : "No", + (fb->info.flags & SNDRV_UMP_BLOCK_IS_LOWSPEED) ? " (Low Speed)" : ""); + snd_iprintf(buffer, "\n"); + } +} + MODULE_DESCRIPTION("Universal MIDI Packet (UMP) Core Driver"); MODULE_LICENSE("GPL"); From patchwork Tue May 23 07:53:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251817 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 31B0EC7EE23 for ; Tue, 23 May 2023 08:05:42 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id D24F5EA1; Tue, 23 May 2023 10:04:49 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz D24F5EA1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829139; bh=iS9i6Hzq85kIzJDuoiEmybGLMwgAMZEDGV8gIARdnp0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=olcfXog5OAC5lFdr7MC/qRxngcD+m+CYEjLxWUOaCsNSkPx8bd54YJZuMX2YUN/O0 eUDxLjn46lUqzt74msRFYx6m7RXr7xtYrhFhmPkLubtbUA+pk/fTxhC3hKAgjFSsT4 a6r49l8S25S6MZNRb/P6ABRmIU1zDYvXforHjBDQ= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 9A404F80709; Tue, 23 May 2023 09:56:58 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 43AADF8071C; Tue, 23 May 2023 09:56:58 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 64B56F80544; Tue, 23 May 2023 09:56:51 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 80452F80544 for ; Tue, 23 May 2023 09:54:05 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 80452F80544 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=y3bhBJas; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=myq9CoN4 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id C495C20409; Tue, 23 May 2023 07:54:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828444; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DsZiH7AE6CokpKw2dE4gaR8qL2hUFyIdDhBwv7w0K4s=; b=y3bhBJashklzYYiMWEd7PtXwL1khNccdDUPp3ZAus6lOVF6iwCpNI2KfRXHTz1baCYl4HY u490oHqi3Wd0xTDxKo55KpjcVMiAKmxahlhRAEQntTHD0Q1z7gZsqyNfV/iwC1fPR/yVYH DnOMPbTeCjV7PNEpyYCZl9J5G2LvaHM= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828444; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DsZiH7AE6CokpKw2dE4gaR8qL2hUFyIdDhBwv7w0K4s=; b=myq9CoN4kIrOtkN/IHg5IWuKRzFSYPRayDoMRA4YZX5J+6XQr0ayzE1v72jCADQVc4mHGf TTNOLmh5/f5OlpCA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 4028A13A1A; Tue, 23 May 2023 07:54:04 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id QCELDBxxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:04 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 07/37] ALSA: usb-audio: Manage number of rawmidis globally Date: Tue, 23 May 2023 09:53:28 +0200 Message-Id: <20230523075358.9672-8-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: QTG4ATKS56YHGCVCNALDRHYIOW6VMAV4 X-Message-ID-Hash: QTG4ATKS56YHGCVCNALDRHYIOW6VMAV4 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: We're going to create rawmidi objects for MIDI 2.0 in a different code from the current code for USB-MIDI 1.0. As a preliminary work, this patch adds the number of rawmidi objects to keep globally in a USB-audio card instance, so that it can be referred from both MIDI 1.0 and 2.0 code. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/card.c | 5 +++-- sound/usb/midi.c | 7 ++++++- sound/usb/midi.h | 5 +++-- sound/usb/quirks.c | 5 +++-- sound/usb/usbaudio.h | 1 + 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index f6e99ced8068..bd051e634516 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -179,8 +179,9 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) { int err = __snd_usbmidi_create(chip->card, iface, - &chip->midi_list, NULL, - chip->usb_id); + &chip->midi_list, NULL, + chip->usb_id, + &chip->num_rawmidis); if (err < 0) { dev_err(&dev->dev, "%u:%d: cannot create sequencer device\n", diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 2839f6b6f09b..6b0993258e03 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2461,7 +2461,8 @@ int __snd_usbmidi_create(struct snd_card *card, struct usb_interface *iface, struct list_head *midi_list, const struct snd_usb_audio_quirk *quirk, - unsigned int usb_id) + unsigned int usb_id, + unsigned int *num_rawmidis) { struct snd_usb_midi *umidi; struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS]; @@ -2476,6 +2477,8 @@ int __snd_usbmidi_create(struct snd_card *card, umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; + if (num_rawmidis) + umidi->next_midi_device = *num_rawmidis; spin_lock_init(&umidi->disc_lock); init_rwsem(&umidi->disc_rwsem); mutex_init(&umidi->mutex); @@ -2595,6 +2598,8 @@ int __snd_usbmidi_create(struct snd_card *card, usb_autopm_get_interface_no_resume(umidi->iface); list_add_tail(&umidi->list, midi_list); + if (num_rawmidis) + *num_rawmidis = umidi->next_midi_device; return 0; free_midi: diff --git a/sound/usb/midi.h b/sound/usb/midi.h index 3f153195c841..2100f1486b03 100644 --- a/sound/usb/midi.h +++ b/sound/usb/midi.h @@ -46,14 +46,15 @@ int __snd_usbmidi_create(struct snd_card *card, struct usb_interface *iface, struct list_head *midi_list, const struct snd_usb_audio_quirk *quirk, - unsigned int usb_id); + unsigned int usb_id, + unsigned int *num_rawmidis); static inline int snd_usbmidi_create(struct snd_card *card, struct usb_interface *iface, struct list_head *midi_list, const struct snd_usb_audio_quirk *quirk) { - return __snd_usbmidi_create(card, iface, midi_list, quirk, 0); + return __snd_usbmidi_create(card, iface, midi_list, quirk, 0, NULL); } void snd_usbmidi_input_stop(struct list_head *p); diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 3ecd1ba7fd4b..1cabe4cc019f 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -436,8 +436,9 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, chip->usb_id == USB_ID(0x0582, 0x002b) ? &ua700_quirk : &uaxx_quirk; return __snd_usbmidi_create(chip->card, iface, - &chip->midi_list, quirk, - chip->usb_id); + &chip->midi_list, quirk, + chip->usb_id, + &chip->num_rawmidis); } if (altsd->bNumEndpoints != 1) diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 38a85b2c9a73..b1fa0a377866 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -49,6 +49,7 @@ struct snd_usb_audio { struct list_head clock_ref_list; /* list of clock refcounts */ int pcm_devs; + unsigned int num_rawmidis; /* number of created rawmidi devices */ struct list_head midi_list; /* list of midi interfaces */ struct list_head mixer_list; /* list of mixer interfaces */ From patchwork Tue May 23 07:53:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251778 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9C273C77B75 for ; Tue, 23 May 2023 07:57:00 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A98C3868; Tue, 23 May 2023 09:56:08 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A98C3868 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828618; bh=wmP8bDCQKLWJezr9s2vqXPA73otrb6UlEETUzDpekWw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=VUqNCuFptfctEYS8FVCPMwUeUfOpul27FHs5wom9pJPuEM9AcZDSaAww5F9ML6xtz fFFzv5z0U4jciV/mInNqIBexGxSbeylneuoauDTTjigHpflxqZvjLo+BM3ZlysIiLe egqSE5Ps4ZtE1YghcfXPY6GcF0Lwg/reIVi60/MI= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 79DA9F805D2; Tue, 23 May 2023 09:54:38 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 79B61F805CA; Tue, 23 May 2023 09:54:37 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 076F5F805CA; Tue, 23 May 2023 09:54:32 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id A7229F80548 for ; Tue, 23 May 2023 09:54:05 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz A7229F80548 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=uLRLsHdX; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=jiHGGJt6 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 2B28A20403; Tue, 23 May 2023 07:54:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828445; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BMiSIlSSN6kDoW8mqxsPxhE+FfS9q6ZCEyPe0Whc9mI=; b=uLRLsHdX3CG/lnTB3W7LhRY8Q4hDPsAxa4yUMX3XoUkU563CufPWk1XUQzKBMGPYubprsn kCjzzHsUu7+1mBbyjfxdmJg3FHMm2nbKn983PCotA/N4PQTuN9FygGo5ekWeLScdBYlXd/ jMTURRtPj7Dukrd0U9KIFKUGluln6VQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828445; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BMiSIlSSN6kDoW8mqxsPxhE+FfS9q6ZCEyPe0Whc9mI=; b=jiHGGJt6/40fYKU8gnPWA+LS9FQQtPvNVoHPt4iVJJ7cXrZQNDvbAp6QAdx6kbFJyF01wS PUvQcjHlM3DMncDQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id BFCB913588; Tue, 23 May 2023 07:54:04 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id sF0qLBxxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:04 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 08/37] ALSA: usb-audio: Define USB MIDI 2.0 specs Date: Tue, 23 May 2023 09:53:29 +0200 Message-Id: <20230523075358.9672-9-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: A7OJXRAOFQCNMIXEJ2ZWEDX7YWULMNPF X-Message-ID-Hash: A7OJXRAOFQCNMIXEJ2ZWEDX7YWULMNPF X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Define new structs and constants from USB MIDI 2.0 specification, to be used in the upcoming MIDI 2.0 support in USB-audio driver. A new class-specific endpoint descriptor and group terminal block descriptors are defined. Acked-by: Greg Kroah-Hartman Acked-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/linux/usb/midi-v2.h | 94 +++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 include/linux/usb/midi-v2.h diff --git a/include/linux/usb/midi-v2.h b/include/linux/usb/midi-v2.h new file mode 100644 index 000000000000..ebbffcae0417 --- /dev/null +++ b/include/linux/usb/midi-v2.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * -- USB MIDI 2.0 definitions. + */ + +#ifndef __LINUX_USB_MIDI_V2_H +#define __LINUX_USB_MIDI_V2_H + +#include +#include + +/* A.1 MS Class-Specific Interface Descriptor Types */ +#define USB_DT_CS_GR_TRM_BLOCK 0x26 + +/* A.1 MS Class-Specific Interface Descriptor Subtypes */ +/* same as MIDI 1.0 */ + +/* A.2 MS Class-Specific Endpoint Descriptor Subtypes */ +#define USB_MS_GENERAL_2_0 0x02 + +/* A.3 MS Class-Specific Group Terminal Block Descriptor Subtypes */ +#define USB_MS_GR_TRM_BLOCK_UNDEFINED 0x00 +#define USB_MS_GR_TRM_BLOCK_HEADER 0x01 +#define USB_MS_GR_TRM_BLOCK 0x02 + +/* A.4 MS Interface Header MIDIStreaming Class Revision */ +#define USB_MS_REV_MIDI_1_0 0x0100 +#define USB_MS_REV_MIDI_2_0 0x0200 + +/* A.5 MS MIDI IN and OUT Jack Types */ +/* same as MIDI 1.0 */ + +/* A.6 Group Terminal Block Types */ +#define USB_MS_GR_TRM_BLOCK_TYPE_BIDIRECTIONAL 0x00 +#define USB_MS_GR_TRM_BLOCK_TYPE_INPUT_ONLY 0x01 +#define USB_MS_GR_TRM_BLOCK_TYPE_OUTPUT_ONLY 0x02 + +/* A.7 Group Terminal Default MIDI Protocol */ +#define USB_MS_MIDI_PROTO_UNKNOWN 0x00 /* Unknown (Use MIDI-CI) */ +#define USB_MS_MIDI_PROTO_1_0_64 0x01 /* MIDI 1.0, UMP up to 64bits */ +#define USB_MS_MIDI_PROTO_1_0_64_JRTS 0x02 /* MIDI 1.0, UMP up to 64bits, Jitter Reduction Timestamps */ +#define USB_MS_MIDI_PROTO_1_0_128 0x03 /* MIDI 1.0, UMP up to 128bits */ +#define USB_MS_MIDI_PROTO_1_0_128_JRTS 0x04 /* MIDI 1.0, UMP up to 128bits, Jitter Reduction Timestamps */ +#define USB_MS_MIDI_PROTO_2_0 0x11 /* MIDI 2.0 */ +#define USB_MS_MIDI_PROTO_2_0_JRTS 0x12 /* MIDI 2.0, Jitter Reduction Timestamps */ + +/* 5.2.2.1 Class-Specific MS Interface Header Descriptor */ +/* Same as MIDI 1.0, use struct usb_ms_header_descriptor */ + +/* 5.3.2 Class-Specific MIDI Streaming Data Endpoint Descriptor */ +struct usb_ms20_endpoint_descriptor { + __u8 bLength; /* 4+n */ + __u8 bDescriptorType; /* USB_DT_CS_ENDPOINT */ + __u8 bDescriptorSubtype; /* USB_MS_GENERAL_2_0 */ + __u8 bNumGrpTrmBlock; /* Number of Group Terminal Blocks: n */ + __u8 baAssoGrpTrmBlkID[]; /* ID of the Group Terminal Blocks [n] */ +} __packed; + +#define USB_DT_MS20_ENDPOINT_SIZE(n) (4 + (n)) + +/* As above, but more useful for defining your own descriptors: */ +#define DECLARE_USB_MS20_ENDPOINT_DESCRIPTOR(n) \ +struct usb_ms20_endpoint_descriptor_##n { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubtype; \ + __u8 bNumGrpTrmBlock; \ + __u8 baAssoGrpTrmBlkID[n]; \ +} __packed + +/* 5.4.1 Class-Specific Group Terminal Block Header Descriptor */ +struct usb_ms20_gr_trm_block_header_descriptor { + __u8 bLength; /* 5 */ + __u8 bDescriptorType; /* USB_DT_CS_GR_TRM_BLOCK */ + __u8 bDescriptorSubtype; /* USB_MS_GR_TRM_BLOCK_HEADER */ + __u16 wTotalLength; /* Total number of bytes */ +} __packed; + +/* 5.4.2.1 Group Terminal Block Descriptor */ +struct usb_ms20_gr_trm_block_descriptor { + __u8 bLength; /* 13 */ + __u8 bDescriptorType; /* USB_DT_CS_GR_TRM_BLOCK */ + __u8 bDescriptorSubtype; /* USB_MS_GR_TRM_BLOCK */ + __u8 bGrpTrmBlkID; /* ID of this Group Terminal Block */ + __u8 bGrpTrmBlkType; /* Group Terminal Block Type */ + __u8 nGroupTrm; /* The first member Group Terminal in this block */ + __u8 nNumGroupTrm; /* Number of member Group Terminals spanned */ + __u8 iBlockItem; /* String ID of Block item */ + __u8 bMIDIProtocol; /* Default MIDI protocol */ + __u16 wMaxInputBandwidth; /* Max input bandwidth capability in 4kB/s */ + __u16 wMaxOutputBandwidth; /* Max output bandwidth capability in 4kB/s */ +} __packed; + +#endif /* __LINUX_USB_MIDI_V2_H */ From patchwork Tue May 23 07:53:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251780 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 93101C7EE26 for ; Tue, 23 May 2023 07:57:37 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 42FAE825; Tue, 23 May 2023 09:56:45 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 42FAE825 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828655; bh=2VKJFa20jtDZJN0HbibhS4gJmtmBUFYBe8WRGctGWmc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=Cw9K6/SACYCTzfIK9cu8uEhx5Cbc0OSYI/65ULJKU4+mjR2nlEji3W7fXABIJDZdx VoXn+Uw0A1DDZnbwhBjPkVSJGtE4NfedTf07q6cNIWHfnqAMW13N3NZGO4VgA8J+1h aHlw4i3qgJMp0OZCu7cVo7SDGGmt9siUEgB4/D/Q= Received: by alsa1.perex.cz (Postfix, from userid 50401) id B43C4F80552; Tue, 23 May 2023 09:54:48 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 4B02AF80589; Tue, 23 May 2023 09:54:47 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 22FBBF805F3; Tue, 23 May 2023 09:54:43 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 41118F80551 for ; Tue, 23 May 2023 09:54:05 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 41118F80551 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=avjsbwvG; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=anEfvilk Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id A026C2040B; Tue, 23 May 2023 07:54:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828445; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Of5xGGlD4xF8TsO44mPG3XPWcfTzLaZhzoUkVwSvDFE=; b=avjsbwvGY6DnSSl3gFyPcqWlERKCtrgmMbPAwsn93w3dRMtyb9RukWs5FSlrmE6RqdFOX+ 8Iq3wQN4hu2zPHvvF++Hi8gWcodklnT9ECLHx7RK7GRoK+/Z4PKsFmTwRiqdpMtEpPtxIg k1OCC5z6x6Uf55PcBk2zhvBsAnQFrCA= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828445; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Of5xGGlD4xF8TsO44mPG3XPWcfTzLaZhzoUkVwSvDFE=; b=anEfvilktMJ98zSCan9ngUG7fHmNauM8g2BJCd47VnFJwoV+aRvLNcGAByzFCOAve+CCvy vYAdUgNVhgD5W4Aw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 2C89F13A1A; Tue, 23 May 2023 07:54:05 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id UAZABR1xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:05 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 09/37] ALSA: usb-audio: USB MIDI 2.0 UMP support Date: Tue, 23 May 2023 09:53:30 +0200 Message-Id: <20230523075358.9672-10-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: OBHXLYOUO3QY25JCKIUPRIUIGOUCBLUA X-Message-ID-Hash: OBHXLYOUO3QY25JCKIUPRIUIGOUCBLUA X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This patch provides a basic support for USB MIDI 2.0. As of this patch, the driver creates a UMP device per MIDI I/O endpoints, which serves as a dumb terminal to read/write UMP streams. A new Kconfig CONFIG_SND_USB_AUDIO_MIDI_V2 manages whether to enable or disable the MIDI 2.0 support. Also, the driver provides a new module option, midi2_enable, to allow disabling the MIDI 2.0 at runtime, too. When MIDI 2.0 support is disabled, the driver tries to fall back to the already existing MIDI 1.0 device (each MIDI 2.0 device is supposed to provide the MIDI 1.0 interface at the altset 0). For now, the driver doesn't manage any MIDI-CI or other protocol setups by itself, but relies on the default protocol given via the group terminal block descriptors. The MIDI 1.0 messages on MIDI 2.0 device will be automatically converted in ALSA sequencer in a later patch. As of this commit, the driver accepts merely the rawmidi UMP accesses. The driver builds up the topology in the following way: - Create an object for each MIDI endpoint belonging to the USB interface - Find MIDI EP "pairs" that share the same GTB; note that MIDI EP is unidirectional, while UMP is (normally) bidirectional, so two MIDI EPs can form a single UMP EP - A UMP endpoint object is created for each I/O pair - For remaining "solo" MIDI EPs, create unidirectional UMP EPs - Finally, parse GTBs and fill the protocol bits on each UMP So the driver may support multiple UMP Endpoints in theory, although most devices are supposed to have a single UMP EP that can contain up to 16 groups -- which should be large enough. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/Kconfig | 11 + sound/usb/Makefile | 1 + sound/usb/card.c | 13 +- sound/usb/midi2.c | 1052 ++++++++++++++++++++++++++++++++++++++++++ sound/usb/midi2.h | 33 ++ sound/usb/quirks.c | 3 +- sound/usb/usbaudio.h | 1 + 7 files changed, 1109 insertions(+), 5 deletions(-) create mode 100644 sound/usb/midi2.c create mode 100644 sound/usb/midi2.h diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 059242f15d75..4a9569a3a39a 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -15,6 +15,7 @@ config SND_USB_AUDIO select SND_HWDEP select SND_RAWMIDI select SND_PCM + select SND_UMP if SND_USB_AUDIO_MIDI_V2 select BITREVERSE select SND_USB_AUDIO_USE_MEDIA_CONTROLLER if MEDIA_CONTROLLER && (MEDIA_SUPPORT=y || MEDIA_SUPPORT=SND_USB_AUDIO) help @@ -24,6 +25,16 @@ config SND_USB_AUDIO To compile this driver as a module, choose M here: the module will be called snd-usb-audio. +config SND_USB_AUDIO_MIDI_V2 + bool "MIDI 2.0 support by USB Audio driver" + depends on SND_USB_AUDIO + help + Say Y here to include the support for MIDI 2.0 by USB Audio driver. + When the config is set, the driver tries to probe MIDI 2.0 interface + at first, then falls back to MIDI 1.0 interface as default. + The MIDI 2.0 support can be disabled dynamically via midi2_enable + module option, too. + config SND_USB_AUDIO_USE_MEDIA_CONTROLLER bool diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 9ccb21a4ff8a..db5ff76d0e61 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -22,6 +22,7 @@ snd-usb-audio-objs := card.o \ stream.o \ validate.o +snd-usb-audio-$(CONFIG_SND_USB_AUDIO_MIDI_V2) += midi2.o snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o snd-usbmidi-lib-objs := midi.o diff --git a/sound/usb/card.c b/sound/usb/card.c index bd051e634516..1b2edc0fd2e9 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -44,6 +44,7 @@ #include "usbaudio.h" #include "card.h" #include "midi.h" +#include "midi2.h" #include "mixer.h" #include "proc.h" #include "quirks.h" @@ -178,10 +179,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) { - int err = __snd_usbmidi_create(chip->card, iface, - &chip->midi_list, NULL, - chip->usb_id, - &chip->num_rawmidis); + int err = snd_usb_midi_v2_create(chip, iface, NULL, + chip->usb_id); if (err < 0) { dev_err(&dev->dev, "%u:%d: cannot create sequencer device\n", @@ -486,6 +485,7 @@ static void snd_usb_audio_free(struct snd_card *card) struct snd_usb_audio *chip = card->private_data; snd_usb_endpoint_free_all(chip); + snd_usb_midi_v2_free_all(chip); mutex_destroy(&chip->mutex); if (!atomic_read(&chip->shutdown)) @@ -645,6 +645,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, INIT_LIST_HEAD(&chip->iface_ref_list); INIT_LIST_HEAD(&chip->clock_ref_list); INIT_LIST_HEAD(&chip->midi_list); + INIT_LIST_HEAD(&chip->midi_v2_list); INIT_LIST_HEAD(&chip->mixer_list); if (quirk_flags[idx]) @@ -969,6 +970,7 @@ static void usb_audio_disconnect(struct usb_interface *intf) list_for_each(p, &chip->midi_list) { snd_usbmidi_disconnect(p); } + snd_usb_midi_v2_disconnect_all(chip); /* * Nice to check quirk && quirk->shares_media_device and * then call the snd_media_device_delete(). Don't have @@ -1080,6 +1082,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) snd_usbmidi_suspend(p); list_for_each_entry(mixer, &chip->mixer_list, list) snd_usb_mixer_suspend(mixer); + snd_usb_midi_v2_suspend_all(chip); } if (!PMSG_IS_AUTO(message) && !chip->system_suspend) { @@ -1125,6 +1128,8 @@ static int usb_audio_resume(struct usb_interface *intf) snd_usbmidi_resume(p); } + snd_usb_midi_v2_resume_all(chip); + out: if (chip->num_suspended_intf == chip->system_suspend) { snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c new file mode 100644 index 000000000000..7b4cfbaf2ec0 --- /dev/null +++ b/sound/usb/midi2.c @@ -0,0 +1,1052 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MIDI 2.0 support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "usbaudio.h" +#include "midi.h" +#include "midi2.h" +#include "helper.h" + +static bool midi2_enable = true; +module_param(midi2_enable, bool, 0444); +MODULE_PARM_DESC(midi2_enable, "Enable MIDI 2.0 support."); + +/* stream direction; just shorter names */ +enum { + STR_OUT = SNDRV_RAWMIDI_STREAM_OUTPUT, + STR_IN = SNDRV_RAWMIDI_STREAM_INPUT +}; + +#define NUM_URBS 8 + +struct snd_usb_midi2_urb; +struct snd_usb_midi2_endpoint; +struct snd_usb_midi2_ump; +struct snd_usb_midi2_interface; + +/* URB context */ +struct snd_usb_midi2_urb { + struct urb *urb; + struct snd_usb_midi2_endpoint *ep; + unsigned int index; /* array index */ +}; + +/* A USB MIDI input/output endpoint */ +struct snd_usb_midi2_endpoint { + struct usb_device *dev; + const struct usb_ms20_endpoint_descriptor *ms_ep; /* reference to EP descriptor */ + struct snd_usb_midi2_endpoint *pair; /* bidirectional pair EP */ + struct snd_usb_midi2_ump *rmidi; /* assigned UMP EP */ + int direction; /* direction (STR_IN/OUT) */ + unsigned int endpoint; /* EP number */ + unsigned int pipe; /* URB pipe */ + unsigned int packets; /* packet buffer size in bytes */ + unsigned int interval; /* interval for INT EP */ + wait_queue_head_t wait; /* URB waiter */ + spinlock_t lock; /* URB locking */ + struct snd_rawmidi_substream *substream; /* NULL when closed */ + unsigned int num_urbs; /* number of allocated URBs */ + unsigned long urb_free; /* bitmap for free URBs */ + unsigned long urb_free_mask; /* bitmask for free URBs */ + atomic_t running; /* running status */ + atomic_t suspended; /* saved running status for suspend */ + bool disconnected; /* shadow of umidi->disconnected */ + struct list_head list; /* list to umidi->ep_list */ + struct snd_usb_midi2_urb urbs[NUM_URBS]; +}; + +/* A UMP endpoint - one or two USB MIDI endpoints are assigned */ +struct snd_usb_midi2_ump { + struct usb_device *dev; + struct snd_usb_midi2_interface *umidi; /* reference to MIDI iface */ + struct snd_ump_endpoint *ump; /* assigned UMP EP object */ + struct snd_usb_midi2_endpoint *eps[2]; /* USB MIDI endpoints */ + int index; /* rawmidi device index */ + unsigned char usb_block_id; /* USB GTB id used for finding a pair */ + struct list_head list; /* list to umidi->rawmidi_list */ +}; + +/* top-level instance per USB MIDI interface */ +struct snd_usb_midi2_interface { + struct snd_usb_audio *chip; /* assigned USB-audio card */ + struct usb_interface *iface; /* assigned USB interface */ + struct usb_host_interface *hostif; + const char *blk_descs; /* group terminal block descriptors */ + unsigned int blk_desc_size; /* size of GTB descriptors */ + bool disconnected; + struct list_head ep_list; /* list of endpoints */ + struct list_head rawmidi_list; /* list of UMP rawmidis */ + struct list_head list; /* list to chip->midi_v2_list */ +}; + +/* submit URBs as much as possible; used for both input and output */ +static void do_submit_urbs_locked(struct snd_usb_midi2_endpoint *ep, + int (*prepare)(struct snd_usb_midi2_endpoint *, + struct urb *)) +{ + struct snd_usb_midi2_urb *ctx; + int index, err = 0; + + if (ep->disconnected) + return; + + while (ep->urb_free) { + index = find_first_bit(&ep->urb_free, ep->num_urbs); + if (index >= ep->num_urbs) + return; + ctx = &ep->urbs[index]; + err = prepare(ep, ctx->urb); + if (err < 0) + return; + if (!ctx->urb->transfer_buffer_length) + return; + ctx->urb->dev = ep->dev; + err = usb_submit_urb(ctx->urb, GFP_ATOMIC); + if (err < 0) { + dev_dbg(&ep->dev->dev, + "usb_submit_urb error %d\n", err); + return; + } + clear_bit(index, &ep->urb_free); + } +} + +/* prepare for output submission: copy from rawmidi buffer to urb packet */ +static int prepare_output_urb(struct snd_usb_midi2_endpoint *ep, + struct urb *urb) +{ + int count; + + if (ep->substream) + count = snd_rawmidi_transmit(ep->substream, + urb->transfer_buffer, + ep->packets); + else + count = -ENODEV; + if (count < 0) { + dev_dbg(&ep->dev->dev, "rawmidi transmit error %d\n", count); + return count; + } + cpu_to_le32_array((u32 *)urb->transfer_buffer, count >> 2); + urb->transfer_buffer_length = count; + return 0; +} + +static void submit_output_urbs_locked(struct snd_usb_midi2_endpoint *ep) +{ + do_submit_urbs_locked(ep, prepare_output_urb); +} + +/* URB completion for output; re-filling and re-submit */ +static void output_urb_complete(struct urb *urb) +{ + struct snd_usb_midi2_urb *ctx = urb->context; + struct snd_usb_midi2_endpoint *ep = ctx->ep; + unsigned long flags; + + spin_lock_irqsave(&ep->lock, flags); + set_bit(ctx->index, &ep->urb_free); + if (urb->status >= 0 && atomic_read(&ep->running)) + submit_output_urbs_locked(ep); + if (ep->urb_free == ep->urb_free_mask) + wake_up(&ep->wait); + spin_unlock_irqrestore(&ep->lock, flags); +} + +/* prepare for input submission: just set the buffer length */ +static int prepare_input_urb(struct snd_usb_midi2_endpoint *ep, + struct urb *urb) +{ + urb->transfer_buffer_length = ep->packets; + return 0; +} + +static void submit_input_urbs_locked(struct snd_usb_midi2_endpoint *ep) +{ + do_submit_urbs_locked(ep, prepare_input_urb); +} + +/* URB completion for input; copy into rawmidi buffer and resubmit */ +static void input_urb_complete(struct urb *urb) +{ + struct snd_usb_midi2_urb *ctx = urb->context; + struct snd_usb_midi2_endpoint *ep = ctx->ep; + unsigned long flags; + int len; + + spin_lock_irqsave(&ep->lock, flags); + if (ep->disconnected || urb->status < 0) + goto dequeue; + len = urb->actual_length; + len &= ~3; /* align UMP */ + if (len > ep->packets) + len = ep->packets; + if (len > 0 && ep->substream) { + le32_to_cpu_array((u32 *)urb->transfer_buffer, len >> 2); + snd_rawmidi_receive(ep->substream, urb->transfer_buffer, len); + } + dequeue: + set_bit(ctx->index, &ep->urb_free); + submit_input_urbs_locked(ep); + if (ep->urb_free == ep->urb_free_mask) + wake_up(&ep->wait); + spin_unlock_irqrestore(&ep->lock, flags); +} + +/* URB submission helper; for both direction */ +static void submit_io_urbs(struct snd_usb_midi2_endpoint *ep) +{ + unsigned long flags; + + if (!ep) + return; + spin_lock_irqsave(&ep->lock, flags); + if (ep->direction == STR_IN) + submit_input_urbs_locked(ep); + else + submit_output_urbs_locked(ep); + spin_unlock_irqrestore(&ep->lock, flags); +} + +/* kill URBs for close, suspend and disconnect */ +static void kill_midi_urbs(struct snd_usb_midi2_endpoint *ep, bool suspending) +{ + int i; + + if (!ep) + return; + if (suspending) + ep->suspended = ep->running; + atomic_set(&ep->running, 0); + for (i = 0; i < ep->num_urbs; i++) { + if (!ep->urbs[i].urb) + break; + usb_kill_urb(ep->urbs[i].urb); + } +} + +/* wait until all URBs get freed */ +static void drain_urb_queue(struct snd_usb_midi2_endpoint *ep) +{ + if (!ep) + return; + spin_lock_irq(&ep->lock); + atomic_set(&ep->running, 0); + wait_event_lock_irq_timeout(ep->wait, + ep->disconnected || + ep->urb_free == ep->urb_free_mask, + ep->lock, msecs_to_jiffies(500)); + spin_unlock_irq(&ep->lock); +} + +/* release URBs for an EP */ +static void free_midi_urbs(struct snd_usb_midi2_endpoint *ep) +{ + struct snd_usb_midi2_urb *ctx; + int i; + + if (!ep) + return; + for (i = 0; i < ep->num_urbs; ++i) { + ctx = &ep->urbs[i]; + if (!ctx->urb) + break; + usb_free_coherent(ep->dev, ep->packets, + ctx->urb->transfer_buffer, + ctx->urb->transfer_dma); + usb_free_urb(ctx->urb); + ctx->urb = NULL; + } + ep->num_urbs = 0; +} + +/* allocate URBs for an EP */ +static int alloc_midi_urbs(struct snd_usb_midi2_endpoint *ep) +{ + struct snd_usb_midi2_urb *ctx; + void (*comp)(struct urb *urb); + void *buffer; + int i, err; + int endpoint, len; + + endpoint = ep->endpoint; + len = ep->packets; + if (ep->direction == STR_IN) + comp = input_urb_complete; + else + comp = output_urb_complete; + + ep->num_urbs = 0; + ep->urb_free = ep->urb_free_mask = 0; + for (i = 0; i < NUM_URBS; i++) { + ctx = &ep->urbs[i]; + ctx->index = i; + ctx->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ctx->urb) { + dev_err(&ep->dev->dev, "URB alloc failed\n"); + return -ENOMEM; + } + ctx->ep = ep; + buffer = usb_alloc_coherent(ep->dev, len, GFP_KERNEL, + &ctx->urb->transfer_dma); + if (!buffer) { + dev_err(&ep->dev->dev, + "URB buffer alloc failed (size %d)\n", len); + return -ENOMEM; + } + if (ep->interval) + usb_fill_int_urb(ctx->urb, ep->dev, ep->pipe, + buffer, len, comp, ctx, ep->interval); + else + usb_fill_bulk_urb(ctx->urb, ep->dev, ep->pipe, + buffer, len, comp, ctx); + err = usb_urb_ep_type_check(ctx->urb); + if (err < 0) { + dev_err(&ep->dev->dev, "invalid MIDI EP %x\n", + endpoint); + return err; + } + ctx->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + ep->num_urbs++; + } + ep->urb_free = ep->urb_free_mask = GENMASK(ep->num_urbs - 1, 0); + return 0; +} + +static struct snd_usb_midi2_endpoint * +substream_to_endpoint(struct snd_rawmidi_substream *substream) +{ + struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); + struct snd_usb_midi2_ump *rmidi = ump->private_data; + + return rmidi->eps[substream->stream]; +} + +/* rawmidi open callback */ +static int snd_usb_midi_v2_open(struct snd_rawmidi_substream *substream) +{ + struct snd_usb_midi2_endpoint *ep = substream_to_endpoint(substream); + int err = 0; + + if (!ep || !ep->endpoint) + return -ENODEV; + if (ep->disconnected) + return -EIO; + if (ep->substream) + return -EBUSY; + if (ep->direction == STR_OUT) { + err = alloc_midi_urbs(ep); + if (err) + return err; + } + spin_lock_irq(&ep->lock); + ep->substream = substream; + spin_unlock_irq(&ep->lock); + return 0; +} + +/* rawmidi close callback */ +static int snd_usb_midi_v2_close(struct snd_rawmidi_substream *substream) +{ + struct snd_usb_midi2_endpoint *ep = substream_to_endpoint(substream); + + spin_lock_irq(&ep->lock); + ep->substream = NULL; + spin_unlock_irq(&ep->lock); + if (ep->direction == STR_OUT) { + kill_midi_urbs(ep, false); + drain_urb_queue(ep); + free_midi_urbs(ep); + } + return 0; +} + +/* rawmidi trigger callback */ +static void snd_usb_midi_v2_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct snd_usb_midi2_endpoint *ep = substream_to_endpoint(substream); + + atomic_set(&ep->running, up); + if (up && ep->direction == STR_OUT && !ep->disconnected) + submit_io_urbs(ep); +} + +/* rawmidi drain callback */ +static void snd_usb_midi_v2_drain(struct snd_rawmidi_substream *substream) +{ + struct snd_usb_midi2_endpoint *ep = substream_to_endpoint(substream); + + drain_urb_queue(ep); +} + +/* allocate and start all input streams */ +static int start_input_streams(struct snd_usb_midi2_interface *umidi) +{ + struct snd_usb_midi2_endpoint *ep; + int err; + + list_for_each_entry(ep, &umidi->ep_list, list) { + if (ep->direction == STR_IN) { + err = alloc_midi_urbs(ep); + if (err < 0) + goto error; + } + } + + list_for_each_entry(ep, &umidi->ep_list, list) { + if (ep->direction == STR_IN) + submit_io_urbs(ep); + } + + return 0; + + error: + list_for_each_entry(ep, &umidi->ep_list, list) { + if (ep->direction == STR_IN) + free_midi_urbs(ep); + } + + return err; +} + +static const struct snd_rawmidi_ops output_ops = { + .open = snd_usb_midi_v2_open, + .close = snd_usb_midi_v2_close, + .trigger = snd_usb_midi_v2_trigger, + .drain = snd_usb_midi_v2_drain, +}; + +static const struct snd_rawmidi_ops input_ops = { + .open = snd_usb_midi_v2_open, + .close = snd_usb_midi_v2_close, + .trigger = snd_usb_midi_v2_trigger, +}; + +/* create a USB MIDI 2.0 endpoint object */ +static int create_midi2_endpoint(struct snd_usb_midi2_interface *umidi, + struct usb_host_endpoint *hostep, + const struct usb_ms20_endpoint_descriptor *ms_ep) +{ + struct snd_usb_midi2_endpoint *ep; + int endpoint, dir; + + usb_audio_dbg(umidi->chip, "Creating an EP 0x%02x, #GTB=%d\n", + hostep->desc.bEndpointAddress, + ms_ep->bNumGrpTrmBlock); + + ep = kzalloc(sizeof(*ep), GFP_KERNEL); + if (!ep) + return -ENOMEM; + + spin_lock_init(&ep->lock); + init_waitqueue_head(&ep->wait); + ep->dev = umidi->chip->dev; + endpoint = hostep->desc.bEndpointAddress; + dir = (endpoint & USB_DIR_IN) ? STR_IN : STR_OUT; + + ep->endpoint = endpoint; + ep->direction = dir; + ep->ms_ep = ms_ep; + if (usb_endpoint_xfer_int(&hostep->desc)) + ep->interval = hostep->desc.bInterval; + else + ep->interval = 0; + if (dir == STR_IN) { + if (ep->interval) + ep->pipe = usb_rcvintpipe(ep->dev, endpoint); + else + ep->pipe = usb_rcvbulkpipe(ep->dev, endpoint); + } else { + if (ep->interval) + ep->pipe = usb_sndintpipe(ep->dev, endpoint); + else + ep->pipe = usb_sndbulkpipe(ep->dev, endpoint); + } + ep->packets = usb_maxpacket(ep->dev, ep->pipe); + list_add_tail(&ep->list, &umidi->ep_list); + + return 0; +} + +/* destructor for endpoint; from snd_usb_midi_v2_free() */ +static void free_midi2_endpoint(struct snd_usb_midi2_endpoint *ep) +{ + list_del(&ep->list); + free_midi_urbs(ep); + kfree(ep); +} + +/* call all endpoint destructors */ +static void free_all_midi2_endpoints(struct snd_usb_midi2_interface *umidi) +{ + struct snd_usb_midi2_endpoint *ep; + + while (!list_empty(&umidi->ep_list)) { + ep = list_first_entry(&umidi->ep_list, + struct snd_usb_midi2_endpoint, list); + free_midi2_endpoint(ep); + } +} + +/* find a MIDI STREAMING descriptor with a given subtype */ +static void *find_usb_ms_endpoint_descriptor(struct usb_host_endpoint *hostep, + unsigned char subtype) +{ + unsigned char *extra = hostep->extra; + int extralen = hostep->extralen; + + while (extralen > 3) { + struct usb_ms_endpoint_descriptor *ms_ep = + (struct usb_ms_endpoint_descriptor *)extra; + + if (ms_ep->bLength > 3 && + ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT && + ms_ep->bDescriptorSubtype == subtype) + return ms_ep; + if (!extra[0]) + break; + extralen -= extra[0]; + extra += extra[0]; + } + return NULL; +} + +/* get the full group terminal block descriptors and return the size */ +static int get_group_terminal_block_descs(struct snd_usb_midi2_interface *umidi) +{ + struct usb_host_interface *hostif = umidi->hostif; + struct usb_device *dev = umidi->chip->dev; + struct usb_ms20_gr_trm_block_header_descriptor header = { 0 }; + unsigned char *data; + int err, size; + + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_STANDARD | USB_DIR_IN, + USB_DT_CS_GR_TRM_BLOCK << 8 | hostif->desc.bAlternateSetting, + hostif->desc.bInterfaceNumber, + &header, sizeof(header)); + if (err < 0) + return err; + size = __le16_to_cpu(header.wTotalLength); + if (!size) { + dev_err(&dev->dev, "Failed to get GTB descriptors for %d:%d\n", + hostif->desc.bInterfaceNumber, hostif->desc.bAlternateSetting); + return -EINVAL; + } + + data = kzalloc(size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_STANDARD | USB_DIR_IN, + USB_DT_CS_GR_TRM_BLOCK << 8 | hostif->desc.bAlternateSetting, + hostif->desc.bInterfaceNumber, data, size); + if (err < 0) { + kfree(data); + return err; + } + + umidi->blk_descs = data; + umidi->blk_desc_size = size; + return 0; +} + +/* find the corresponding group terminal block descriptor */ +static const struct usb_ms20_gr_trm_block_descriptor * +find_group_terminal_block(struct snd_usb_midi2_interface *umidi, int id) +{ + const unsigned char *data = umidi->blk_descs; + int size = umidi->blk_desc_size; + const struct usb_ms20_gr_trm_block_descriptor *desc; + + size -= sizeof(struct usb_ms20_gr_trm_block_header_descriptor); + data += sizeof(struct usb_ms20_gr_trm_block_header_descriptor); + while (size > 0 && *data && *data <= size) { + desc = (const struct usb_ms20_gr_trm_block_descriptor *)data; + if (desc->bLength >= sizeof(*desc) && + desc->bDescriptorType == USB_DT_CS_GR_TRM_BLOCK && + desc->bDescriptorSubtype == USB_MS_GR_TRM_BLOCK && + desc->bGrpTrmBlkID == id) + return desc; + size -= *data; + data += *data; + } + + return NULL; +} + +/* fill up the information from GTB */ +static int parse_group_terminal_block(struct snd_usb_midi2_ump *rmidi, + const struct usb_ms20_gr_trm_block_descriptor *desc) +{ + struct snd_usb_audio *chip = rmidi->umidi->chip; + struct snd_ump_endpoint *ump = rmidi->ump; + + usb_audio_dbg(chip, + "GTB id %d: groups = %d / %d, type = %d\n", + desc->bGrpTrmBlkID, desc->nGroupTrm, desc->nNumGroupTrm, + desc->bGrpTrmBlkType); + + /* set default protocol */ + switch (desc->bMIDIProtocol) { + case USB_MS_MIDI_PROTO_1_0_64: + case USB_MS_MIDI_PROTO_1_0_64_JRTS: + case USB_MS_MIDI_PROTO_1_0_128: + case USB_MS_MIDI_PROTO_1_0_128_JRTS: + ump->info.protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1; + break; + case USB_MS_MIDI_PROTO_2_0: + case USB_MS_MIDI_PROTO_2_0_JRTS: + ump->info.protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI2; + break; + } + + ump->info.protocol_caps = ump->info.protocol; + switch (desc->bMIDIProtocol) { + case USB_MS_MIDI_PROTO_1_0_64_JRTS: + case USB_MS_MIDI_PROTO_1_0_128_JRTS: + case USB_MS_MIDI_PROTO_2_0_JRTS: + ump->info.protocol_caps |= SNDRV_UMP_EP_INFO_PROTO_JRTS_TX | + SNDRV_UMP_EP_INFO_PROTO_JRTS_RX; + break; + } + + return 0; +} + +/* allocate and parse for each assigned group terminal block */ +static int parse_group_terminal_blocks(struct snd_usb_midi2_interface *umidi) +{ + struct snd_usb_midi2_ump *rmidi; + const struct usb_ms20_gr_trm_block_descriptor *desc; + int err; + + err = get_group_terminal_block_descs(umidi); + if (err < 0) + return err; + if (!umidi->blk_descs) + return 0; + + list_for_each_entry(rmidi, &umidi->rawmidi_list, list) { + desc = find_group_terminal_block(umidi, rmidi->usb_block_id); + if (!desc) + continue; + err = parse_group_terminal_block(rmidi, desc); + if (err < 0) + return err; + } + + return 0; +} + +/* parse endpoints included in the given interface and create objects */ +static int parse_midi_2_0_endpoints(struct snd_usb_midi2_interface *umidi) +{ + struct usb_host_interface *hostif = umidi->hostif; + struct usb_host_endpoint *hostep; + struct usb_ms20_endpoint_descriptor *ms_ep; + int i, err; + + for (i = 0; i < hostif->desc.bNumEndpoints; i++) { + hostep = &hostif->endpoint[i]; + if (!usb_endpoint_xfer_bulk(&hostep->desc) && + !usb_endpoint_xfer_int(&hostep->desc)) + continue; + ms_ep = find_usb_ms_endpoint_descriptor(hostep, USB_MS_GENERAL_2_0); + if (!ms_ep) + continue; + if (ms_ep->bLength <= sizeof(*ms_ep)) + continue; + if (!ms_ep->bNumGrpTrmBlock) + continue; + if (ms_ep->bLength < sizeof(*ms_ep) + ms_ep->bNumGrpTrmBlock) + continue; + err = create_midi2_endpoint(umidi, hostep, ms_ep); + if (err < 0) + return err; + } + return 0; +} + +static void free_all_midi2_umps(struct snd_usb_midi2_interface *umidi) +{ + struct snd_usb_midi2_ump *rmidi; + + while (!list_empty(&umidi->rawmidi_list)) { + rmidi = list_first_entry(&umidi->rawmidi_list, + struct snd_usb_midi2_ump, list); + list_del(&rmidi->list); + kfree(rmidi); + } +} + +static int create_midi2_ump(struct snd_usb_midi2_interface *umidi, + struct snd_usb_midi2_endpoint *ep_in, + struct snd_usb_midi2_endpoint *ep_out, + int blk_id) +{ + struct snd_usb_midi2_ump *rmidi; + struct snd_ump_endpoint *ump; + int input, output; + char idstr[16]; + int err; + + rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); + if (!rmidi) + return -ENOMEM; + INIT_LIST_HEAD(&rmidi->list); + rmidi->dev = umidi->chip->dev; + rmidi->umidi = umidi; + rmidi->usb_block_id = blk_id; + + rmidi->index = umidi->chip->num_rawmidis; + snprintf(idstr, sizeof(idstr), "UMP %d", rmidi->index); + input = ep_in ? 1 : 0; + output = ep_out ? 1 : 0; + err = snd_ump_endpoint_new(umidi->chip->card, idstr, rmidi->index, + output, input, &ump); + if (err < 0) { + usb_audio_dbg(umidi->chip, "Failed to create a UMP object\n"); + kfree(rmidi); + return err; + } + + rmidi->ump = ump; + umidi->chip->num_rawmidis++; + + ump->private_data = rmidi; + + if (input) + snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_INPUT, + &input_ops); + if (output) + snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_OUTPUT, + &output_ops); + + rmidi->eps[STR_IN] = ep_in; + rmidi->eps[STR_OUT] = ep_out; + if (ep_in) { + ep_in->pair = ep_out; + ep_in->rmidi = rmidi; + } + if (ep_out) { + ep_out->pair = ep_in; + ep_out->rmidi = rmidi; + } + + list_add_tail(&rmidi->list, &umidi->rawmidi_list); + return 0; +} + +/* find the UMP EP with the given USB block id */ +static struct snd_usb_midi2_ump * +find_midi2_ump(struct snd_usb_midi2_interface *umidi, int blk_id) +{ + struct snd_usb_midi2_ump *rmidi; + + list_for_each_entry(rmidi, &umidi->rawmidi_list, list) { + if (rmidi->usb_block_id == blk_id) + return rmidi; + } + return NULL; +} + +/* look for the matching output endpoint and create UMP object if found */ +static int find_matching_ep_partner(struct snd_usb_midi2_interface *umidi, + struct snd_usb_midi2_endpoint *ep, + int blk_id) +{ + struct snd_usb_midi2_endpoint *pair_ep; + int blk; + + usb_audio_dbg(umidi->chip, "Looking for a pair for EP-in 0x%02x\n", + ep->endpoint); + list_for_each_entry(pair_ep, &umidi->ep_list, list) { + if (pair_ep->direction != STR_OUT) + continue; + if (pair_ep->pair) + continue; /* already paired */ + for (blk = 0; blk < pair_ep->ms_ep->bNumGrpTrmBlock; blk++) { + if (pair_ep->ms_ep->baAssoGrpTrmBlkID[blk] == blk_id) { + usb_audio_dbg(umidi->chip, + "Found a match with EP-out 0x%02x blk %d\n", + pair_ep->endpoint, blk); + return create_midi2_ump(umidi, ep, pair_ep, blk_id); + } + } + } + return 0; +} + +static void snd_usb_midi_v2_free(struct snd_usb_midi2_interface *umidi) +{ + free_all_midi2_endpoints(umidi); + free_all_midi2_umps(umidi); + list_del(&umidi->list); + kfree(umidi->blk_descs); + kfree(umidi); +} + +/* parse the interface for MIDI 2.0 */ +static int parse_midi_2_0(struct snd_usb_midi2_interface *umidi) +{ + struct snd_usb_midi2_endpoint *ep; + int blk, id, err; + + /* First, create an object for each USB MIDI Endpoint */ + err = parse_midi_2_0_endpoints(umidi); + if (err < 0) + return err; + if (list_empty(&umidi->ep_list)) { + usb_audio_warn(umidi->chip, "No MIDI endpoints found\n"); + return -ENODEV; + } + + /* + * Next, look for EP I/O pairs that are found in group terminal blocks + * A UMP object is created for each EP I/O pair as bidirecitonal + * UMP EP + */ + list_for_each_entry(ep, &umidi->ep_list, list) { + /* only input in this loop; output is matched in find_midi_ump() */ + if (ep->direction != STR_IN) + continue; + for (blk = 0; blk < ep->ms_ep->bNumGrpTrmBlock; blk++) { + id = ep->ms_ep->baAssoGrpTrmBlkID[blk]; + err = find_matching_ep_partner(umidi, ep, id); + if (err < 0) + return err; + } + } + + /* + * For the remaining EPs, treat as singles, create a UMP object with + * unidirectional EP + */ + list_for_each_entry(ep, &umidi->ep_list, list) { + if (ep->rmidi) + continue; /* already paired */ + for (blk = 0; blk < ep->ms_ep->bNumGrpTrmBlock; blk++) { + id = ep->ms_ep->baAssoGrpTrmBlkID[blk]; + if (find_midi2_ump(umidi, id)) + continue; + usb_audio_dbg(umidi->chip, + "Creating a unidirection UMP for EP=0x%02x, blk=%d\n", + ep->endpoint, id); + if (ep->direction == STR_IN) + err = create_midi2_ump(umidi, ep, NULL, id); + else + err = create_midi2_ump(umidi, NULL, ep, id); + if (err < 0) + return err; + break; + } + } + + return 0; +} + +/* is the given interface for MIDI 2.0? */ +static bool is_midi2_altset(struct usb_host_interface *hostif) +{ + struct usb_ms_header_descriptor *ms_header = + (struct usb_ms_header_descriptor *)hostif->extra; + + if (hostif->extralen < 7 || + ms_header->bLength < 7 || + ms_header->bDescriptorType != USB_DT_CS_INTERFACE || + ms_header->bDescriptorSubtype != UAC_HEADER) + return false; + + return le16_to_cpu(ms_header->bcdMSC) == USB_MS_REV_MIDI_2_0; +} + +/* change the altsetting */ +static int set_altset(struct snd_usb_midi2_interface *umidi) +{ + usb_audio_dbg(umidi->chip, "Setting host iface %d:%d\n", + umidi->hostif->desc.bInterfaceNumber, + umidi->hostif->desc.bAlternateSetting); + return usb_set_interface(umidi->chip->dev, + umidi->hostif->desc.bInterfaceNumber, + umidi->hostif->desc.bAlternateSetting); +} + +/* fill the fallback name string for each rawmidi instance */ +static void set_fallback_rawmidi_names(struct snd_usb_midi2_interface *umidi) +{ + struct snd_usb_midi2_ump *rmidi; + + list_for_each_entry(rmidi, &umidi->rawmidi_list, list) { + if (!*rmidi->ump->core.name) + sprintf(rmidi->ump->core.name, "USB MIDI %d", + rmidi->index); + } +} + +/* create MIDI interface; fallback to MIDI 1.0 if needed */ +int snd_usb_midi_v2_create(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk, + unsigned int usb_id) +{ + struct snd_usb_midi2_interface *umidi; + struct usb_host_interface *hostif; + int err; + + usb_audio_dbg(chip, "Parsing interface %d...\n", + iface->altsetting[0].desc.bInterfaceNumber); + + /* fallback to MIDI 1.0? */ + if (!midi2_enable) { + usb_audio_info(chip, "Falling back to MIDI 1.0 by module option\n"); + goto fallback_to_midi1; + } + if ((quirk && quirk->type != QUIRK_MIDI_STANDARD_INTERFACE) || + iface->num_altsetting < 2) { + usb_audio_info(chip, "Quirk or no altest; falling back to MIDI 1.0\n"); + goto fallback_to_midi1; + } + hostif = &iface->altsetting[1]; + if (!is_midi2_altset(hostif)) { + usb_audio_info(chip, "No MIDI 2.0 at altset 1, falling back to MIDI 1.0\n"); + goto fallback_to_midi1; + } + if (!hostif->desc.bNumEndpoints) { + usb_audio_info(chip, "No endpoint at altset 1, falling back to MIDI 1.0\n"); + goto fallback_to_midi1; + } + + usb_audio_dbg(chip, "Creating a MIDI 2.0 instance for %d:%d\n", + hostif->desc.bInterfaceNumber, + hostif->desc.bAlternateSetting); + + umidi = kzalloc(sizeof(*umidi), GFP_KERNEL); + if (!umidi) + return -ENOMEM; + umidi->chip = chip; + umidi->iface = iface; + umidi->hostif = hostif; + INIT_LIST_HEAD(&umidi->rawmidi_list); + INIT_LIST_HEAD(&umidi->ep_list); + + list_add_tail(&umidi->list, &chip->midi_v2_list); + + err = set_altset(umidi); + if (err < 0) { + usb_audio_err(chip, "Failed to set altset\n"); + goto error; + } + + /* assume only altset 1 corresponding to MIDI 2.0 interface */ + err = parse_midi_2_0(umidi); + if (err < 0) { + usb_audio_err(chip, "Failed to parse MIDI 2.0 interface\n"); + goto error; + } + + /* parse USB group terminal blocks */ + err = parse_group_terminal_blocks(umidi); + if (err < 0) { + usb_audio_err(chip, "Failed to parse GTB\n"); + goto error; + } + + err = start_input_streams(umidi); + if (err < 0) { + usb_audio_err(chip, "Failed to start input streams\n"); + goto error; + } + + set_fallback_rawmidi_names(umidi); + return 0; + + error: + snd_usb_midi_v2_free(umidi); + return err; + + fallback_to_midi1: + return __snd_usbmidi_create(chip->card, iface, &chip->midi_list, + quirk, usb_id, &chip->num_rawmidis); +} + +static void suspend_midi2_endpoint(struct snd_usb_midi2_endpoint *ep) +{ + kill_midi_urbs(ep, true); + drain_urb_queue(ep); +} + +void snd_usb_midi_v2_suspend_all(struct snd_usb_audio *chip) +{ + struct snd_usb_midi2_interface *umidi; + struct snd_usb_midi2_endpoint *ep; + + list_for_each_entry(umidi, &chip->midi_v2_list, list) { + list_for_each_entry(ep, &umidi->ep_list, list) + suspend_midi2_endpoint(ep); + } +} + +static void resume_midi2_endpoint(struct snd_usb_midi2_endpoint *ep) +{ + ep->running = ep->suspended; + if (ep->direction == STR_IN) + submit_io_urbs(ep); + /* FIXME: does it all? */ +} + +void snd_usb_midi_v2_resume_all(struct snd_usb_audio *chip) +{ + struct snd_usb_midi2_interface *umidi; + struct snd_usb_midi2_endpoint *ep; + + list_for_each_entry(umidi, &chip->midi_v2_list, list) { + set_altset(umidi); + list_for_each_entry(ep, &umidi->ep_list, list) + resume_midi2_endpoint(ep); + } +} + +void snd_usb_midi_v2_disconnect_all(struct snd_usb_audio *chip) +{ + struct snd_usb_midi2_interface *umidi; + struct snd_usb_midi2_endpoint *ep; + + list_for_each_entry(umidi, &chip->midi_v2_list, list) { + umidi->disconnected = 1; + list_for_each_entry(ep, &umidi->ep_list, list) { + ep->disconnected = 1; + kill_midi_urbs(ep, false); + drain_urb_queue(ep); + } + } +} + +/* release the MIDI instance */ +void snd_usb_midi_v2_free_all(struct snd_usb_audio *chip) +{ + struct snd_usb_midi2_interface *umidi, *next; + + list_for_each_entry_safe(umidi, next, &chip->midi_v2_list, list) + snd_usb_midi_v2_free(umidi); +} diff --git a/sound/usb/midi2.h b/sound/usb/midi2.h new file mode 100644 index 000000000000..94a65fcbd58b --- /dev/null +++ b/sound/usb/midi2.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef __USB_AUDIO_MIDI2_H +#define __USB_AUDIO_MIDI2_H + +#include "midi.h" + +#if IS_ENABLED(CONFIG_SND_USB_AUDIO_MIDI_V2) +int snd_usb_midi_v2_create(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk, + unsigned int usb_id); +void snd_usb_midi_v2_suspend_all(struct snd_usb_audio *chip); +void snd_usb_midi_v2_resume_all(struct snd_usb_audio *chip); +void snd_usb_midi_v2_disconnect_all(struct snd_usb_audio *chip); +void snd_usb_midi_v2_free_all(struct snd_usb_audio *chip); +#else /* CONFIG_SND_USB_AUDIO_MIDI_V2 */ +/* fallback to MIDI 1.0 creation */ +static inline int snd_usb_midi_v2_create(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk, + unsigned int usb_id) +{ + return __snd_usbmidi_create(chip->card, iface, &chip->midi_list, + quirk, usb_id, &chip->num_rawmidis); +} + +static inline void snd_usb_midi_v2_suspend_all(struct snd_usb_audio *chip) {} +static inline void snd_usb_midi_v2_resume_all(struct snd_usb_audio *chip) {} +static inline void snd_usb_midi_v2_disconnect_all(struct snd_usb_audio *chip) {} +static inline void snd_usb_midi_v2_free_all(struct snd_usb_audio *chip) {} +#endif /* CONFIG_SND_USB_AUDIO_MIDI_V2 */ + +#endif /* __USB_AUDIO_MIDI2_H */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 1cabe4cc019f..53e079e91580 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -19,6 +19,7 @@ #include "mixer.h" #include "mixer_quirks.h" #include "midi.h" +#include "midi2.h" #include "quirks.h" #include "helper.h" #include "endpoint.h" @@ -80,7 +81,7 @@ static int create_any_midi_quirk(struct snd_usb_audio *chip, struct usb_driver *driver, const struct snd_usb_audio_quirk *quirk) { - return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk); + return snd_usb_midi_v2_create(chip, intf, quirk, 0); } /* diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b1fa0a377866..43d4029edab4 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -51,6 +51,7 @@ struct snd_usb_audio { unsigned int num_rawmidis; /* number of created rawmidi devices */ struct list_head midi_list; /* list of midi interfaces */ + struct list_head midi_v2_list; /* list of MIDI 2 interfaces */ struct list_head mixer_list; /* list of mixer interfaces */ From patchwork Tue May 23 07:53:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251779 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3A716C7EE26 for ; Tue, 23 May 2023 07:57:24 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 0AAEC3E8; Tue, 23 May 2023 09:56:32 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 0AAEC3E8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828642; bh=37kXzkuCSeYTjflL2hgT83ZiSCMTuw5tib26JW7iJDo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=Y9v2cWaqkngag6riy5w9FAOXQmQZEclaeSnS/5ShYb/4a3/QuxCGSH4tH+wjc8WFh yhnb33nxYWF8py+igtPj+j9MH+RHJcZACX1oIQoDoxY/V1HZlECz87ynPNp0deTQ6T u46vSoU1p7HWB1uTN/ZarbnlEE+FrIJYN+fMny+U= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 383DAF805F1; Tue, 23 May 2023 09:54:39 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 75771F805EF; Tue, 23 May 2023 09:54:39 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 56D27F805D2; Tue, 23 May 2023 09:54:35 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 1DBC6F80549 for ; Tue, 23 May 2023 09:54:05 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 1DBC6F80549 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=xJlS6E9i; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=tA9lxT/A Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id C53762191A; Tue, 23 May 2023 07:54:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828445; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DHrx6V+uewqzX9UqFfIqqGA6/p4XBbhXfx4OFs0RTCU=; b=xJlS6E9iJ2EFF+DymKFeMpQ084cBqDmConz1kdV5Oas2qUnII0Td6kqFhGtxhT3q/nIEiA 7WEBLg1sbVGSTQGaA8kChbcSa5XUk+R6g/q6ALltoeQC8lh4GuKbFgXiPsyk9DmeEJPZJw E5mmWBD9QxU+IV3Pa1DWkEhYNLKkVlY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828445; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DHrx6V+uewqzX9UqFfIqqGA6/p4XBbhXfx4OFs0RTCU=; b=tA9lxT/AZ2PkzccDo0UI9LUOktfO0xARmOgHdxDdUqhMB7w+OR7HwmCgcric2OLX4uy7fE e72T7+Pt15xOh7Bw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 8D04313588; Tue, 23 May 2023 07:54:05 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id KAROIR1xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:05 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 10/37] ALSA: usb-audio: Get UMP EP name string from USB interface Date: Tue, 23 May 2023 09:53:31 +0200 Message-Id: <20230523075358.9672-11-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: Q22BNHMAFPG357VF3F7CY2JAQKI6I5RI X-Message-ID-Hash: Q22BNHMAFPG357VF3F7CY2JAQKI6I5RI X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: USB descriptor may provide a nicer name for USB interface, and we may take it as the UMP Endpoint name. The UMP EP name is copied as the rawmidi name, too. Also, fill the UMP block product_id field from the iSerialNumber string of the USB device descriptor as a recommended unique id, too. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/midi2.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 7b4cfbaf2ec0..2ac3f96216bc 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -892,15 +892,39 @@ static int set_altset(struct snd_usb_midi2_interface *umidi) umidi->hostif->desc.bAlternateSetting); } +/* fill UMP Endpoint name string from USB descriptor */ +static void fill_ump_ep_name(struct snd_ump_endpoint *ump, + struct usb_device *dev, int id) +{ + usb_string(dev, id, ump->info.name, sizeof(ump->info.name)); +} + /* fill the fallback name string for each rawmidi instance */ static void set_fallback_rawmidi_names(struct snd_usb_midi2_interface *umidi) { + struct usb_device *dev = umidi->chip->dev; struct snd_usb_midi2_ump *rmidi; + struct snd_ump_endpoint *ump; list_for_each_entry(rmidi, &umidi->rawmidi_list, list) { - if (!*rmidi->ump->core.name) - sprintf(rmidi->ump->core.name, "USB MIDI %d", - rmidi->index); + ump = rmidi->ump; + /* fill UMP EP name from USB descriptors */ + if (!*ump->info.name && umidi->hostif->desc.iInterface) + fill_ump_ep_name(ump, dev, umidi->hostif->desc.iInterface); + else if (!*ump->info.name && dev->descriptor.iProduct) + fill_ump_ep_name(ump, dev, dev->descriptor.iProduct); + /* fill fallback name */ + if (!*ump->info.name) + sprintf(ump->info.name, "USB MIDI %d", rmidi->index); + /* copy as rawmidi name if not set */ + if (!*ump->core.name) + strscpy(ump->core.name, ump->info.name, + sizeof(ump->core.name)); + /* use serial number string as unique UMP product id */ + if (!*ump->info.product_id && dev->descriptor.iSerialNumber) + usb_string(dev, dev->descriptor.iSerialNumber, + ump->info.product_id, + sizeof(ump->info.product_id)); } } From patchwork Tue May 23 07:53:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251783 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id CFAAAC77B75 for ; Tue, 23 May 2023 07:58:18 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id CABBC84B; Tue, 23 May 2023 09:57:26 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz CABBC84B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828696; bh=SvVLV/PcyjorYA/EtWsvVnaELs25shWi5j68ffpPNgQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=PThXOzWlOPGFpkiXQ2HqsRAHbR5gP0YR8OwNh8QVh4RAk6gNfLWt2JxcGdOqYV+uf a8KSSKoY3kx/1RKaYyg3Nb9Ay4TVbW2mm/GkxYLsfI3+Ar7IvFUATC7rGzuqln6ie+ Scpl5ijyUBq70cxU4qRXhn3VQxfys9qdxVnqe/zw= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 9A5D6F80610; Tue, 23 May 2023 09:54:56 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id A6F25F80612; Tue, 23 May 2023 09:54:55 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5A6BDF805FB; Tue, 23 May 2023 09:54:48 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 9E178F80552 for ; Tue, 23 May 2023 09:54:06 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 9E178F80552 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=c+GvQ5bh; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=iq20Bz5j Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 3FFBD2040A; Tue, 23 May 2023 07:54:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828446; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bVKMfmKZD+HwascEjydzIHk2mo8oo1vs9MeGSXjDJ5A=; b=c+GvQ5bhnqvqd1Rmub7KpN893zt17bAwZReyt2r3o78J0tHEAh/JQtAHFna7M9p7DmLH0w UtQw8x4aKR9eCqvQEmtO4Q9YWymswUzwXurWSn78/k5IGf424rS2Zi0vcjnHvpteGxSZsi vf6tiEeEYKQQ/i0Ce7J5vH8wAYVgyzY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828446; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bVKMfmKZD+HwascEjydzIHk2mo8oo1vs9MeGSXjDJ5A=; b=iq20Bz5jE44WbLBxUdE3iXKccn+VduVi1q1srrt8z65FH3j0mZhdlZP2E+S7TFyxteznrx u8hXBtLi0CpjdJDQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id CC60E13A1A; Tue, 23 May 2023 07:54:05 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 4AGvLR1xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:05 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 11/37] ALSA: usb-audio: Trim superfluous "MIDI" suffix from UMP EP name Date: Tue, 23 May 2023 09:53:32 +0200 Message-Id: <20230523075358.9672-12-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: KOMOGOK52FRGXOTGCUZJVAJPJOL5QOO5 X-Message-ID-Hash: KOMOGOK52FRGXOTGCUZJVAJPJOL5QOO5 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: A single USB audio device may have multiple interfaces for different purposes (e.g. audio, MIDI and HID), where the iInterface descriptor of each interface may contain an own suffix, e.g. "MIDI" for a MIDI interface. as such a suffix is superfluous as a rawmidi and UMP Endpoint name, this patch trims the superfluous "MIDI" suffix from the name string. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/midi2.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 2ac3f96216bc..790e4cd5d35c 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -896,7 +896,14 @@ static int set_altset(struct snd_usb_midi2_interface *umidi) static void fill_ump_ep_name(struct snd_ump_endpoint *ump, struct usb_device *dev, int id) { + int len; + usb_string(dev, id, ump->info.name, sizeof(ump->info.name)); + + /* trim superfluous "MIDI" suffix */ + len = strlen(ump->info.name); + if (len > 5 && !strcmp(ump->info.name + len - 5, " MIDI")) + ump->info.name[len - 5] = 0; } /* fill the fallback name string for each rawmidi instance */ From patchwork Tue May 23 07:53:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251781 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 37709C7EE2A for ; Tue, 23 May 2023 07:57:52 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id EA145A4B; Tue, 23 May 2023 09:56:59 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz EA145A4B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828670; bh=svMCdHDmVDNqttHfJUkPcv7ueEoH0oFuZeT63QkwRgw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=qwINv2MkTDSM1RYcdq724CP4sknIswJL8tkeWCc4S47aRcwLEFJCoOcVFT/HT/e6n U3hrQNtQNz9FQmMqKM2XAmzAmttY06ms8wngqaOsx4J+3GPVulpHz9Bqog08Te+nKk DGsHqiKB6EBNIKsZQUMk1lPEeh805PL1CT4iOEm4= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 413EDF80606; Tue, 23 May 2023 09:54:51 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 116E3F805FB; Tue, 23 May 2023 09:54:51 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 0612CF805AA; Tue, 23 May 2023 09:54:44 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E14EDF8026A for ; Tue, 23 May 2023 09:54:06 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E14EDF8026A Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=VwK8ends; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=hrqlcv+Z Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 6A25F2040C; Tue, 23 May 2023 07:54:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828446; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cxnmOhq+hNE1bnrwoap3xaZVrhnrAGTCoSHtcTlVz/U=; b=VwK8endsKeeUiW3ovXy9mmmdXp0nQDmndTyzdj7Q8VBlBJVE4kWMqxLkCAv9TLj6OQSjuj sKeRV639IxN2VG7actZPdyG+WxppmpjKa3+LqvRMFdLSOgLzNNJXZa2pzXUP5ICXbGfn4D Iab7K/diKlTqTtiZOBWIOzWPFfNXdcQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828446; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cxnmOhq+hNE1bnrwoap3xaZVrhnrAGTCoSHtcTlVz/U=; b=hrqlcv+ZUVDteACAVDImOuE1NZQqe5ky+mTIEyteLt3XU3tgRUCVeAntJrycvPIKNLhdVZ 0ajCWtIUsw9V0zCw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 23CF813588; Tue, 23 May 2023 07:54:06 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id sHokBh5xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:06 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 12/37] ALSA: usb-audio: Create UMP blocks from USB MIDI GTBs Date: Tue, 23 May 2023 09:53:33 +0200 Message-Id: <20230523075358.9672-13-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: FQ65URMLWP7I7NG3YCHMEPSG6BHEWKU6 X-Message-ID-Hash: FQ65URMLWP7I7NG3YCHMEPSG6BHEWKU6 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: <> List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: USB MIDI spec defines the Group Terminal Blocks (GTB) that associate multiple UMP Groups. Those correspond to snd_ump_block entities in ALSA UMP abstraction, and now we create those UMP Block objects for each UMP Endpoint from the parsed GTB information. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/midi2.c | 100 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 6 deletions(-) diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 790e4cd5d35c..5ffee06ac746 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -599,14 +599,8 @@ find_group_terminal_block(struct snd_usb_midi2_interface *umidi, int id) static int parse_group_terminal_block(struct snd_usb_midi2_ump *rmidi, const struct usb_ms20_gr_trm_block_descriptor *desc) { - struct snd_usb_audio *chip = rmidi->umidi->chip; struct snd_ump_endpoint *ump = rmidi->ump; - usb_audio_dbg(chip, - "GTB id %d: groups = %d / %d, type = %d\n", - desc->bGrpTrmBlkID, desc->nGroupTrm, desc->nNumGroupTrm, - desc->bGrpTrmBlkType); - /* set default protocol */ switch (desc->bMIDIProtocol) { case USB_MS_MIDI_PROTO_1_0_64: @@ -798,6 +792,94 @@ static int find_matching_ep_partner(struct snd_usb_midi2_interface *umidi, return 0; } +/* create a UMP block from a GTB entry */ +static int create_gtb_block(struct snd_usb_midi2_ump *rmidi, int dir, int blk) +{ + struct snd_usb_midi2_interface *umidi = rmidi->umidi; + const struct usb_ms20_gr_trm_block_descriptor *desc; + struct snd_ump_block *fb; + int type, err; + + desc = find_group_terminal_block(umidi, blk); + if (!desc) + return 0; + + usb_audio_dbg(umidi->chip, + "GTB %d: type=%d, group=%d/%d, protocol=%d, in bw=%d, out bw=%d\n", + blk, desc->bGrpTrmBlkType, desc->nGroupTrm, + desc->nNumGroupTrm, desc->bMIDIProtocol, + __le16_to_cpu(desc->wMaxInputBandwidth), + __le16_to_cpu(desc->wMaxOutputBandwidth)); + + /* assign the direction */ + switch (desc->bGrpTrmBlkType) { + case USB_MS_GR_TRM_BLOCK_TYPE_BIDIRECTIONAL: + type = SNDRV_UMP_DIR_BIDIRECTION; + break; + case USB_MS_GR_TRM_BLOCK_TYPE_INPUT_ONLY: + type = SNDRV_UMP_DIR_INPUT; + break; + case USB_MS_GR_TRM_BLOCK_TYPE_OUTPUT_ONLY: + type = SNDRV_UMP_DIR_OUTPUT; + break; + default: + usb_audio_dbg(umidi->chip, "Unsupported GTB type %d\n", + desc->bGrpTrmBlkType); + return 0; /* unsupported */ + } + + /* guess work: set blk-1 as the (0-based) block ID */ + err = snd_ump_block_new(rmidi->ump, blk - 1, type, + desc->nGroupTrm, desc->nNumGroupTrm, + &fb); + if (err == -EBUSY) + return 0; /* already present */ + else if (err) + return err; + + if (desc->iBlockItem) + usb_string(rmidi->dev, desc->iBlockItem, + fb->info.name, sizeof(fb->info.name)); + + if (__le16_to_cpu(desc->wMaxInputBandwidth) == 1 || + __le16_to_cpu(desc->wMaxOutputBandwidth) == 1) + fb->info.flags |= SNDRV_UMP_BLOCK_IS_MIDI1 | + SNDRV_UMP_BLOCK_IS_LOWSPEED; + + usb_audio_dbg(umidi->chip, + "Created a UMP block %d from GTB, name=%s\n", + blk, fb->info.name); + return 0; +} + +/* Create UMP blocks for each UMP EP */ +static int create_blocks_from_gtb(struct snd_usb_midi2_interface *umidi) +{ + struct snd_usb_midi2_ump *rmidi; + int i, blk, err, dir; + + list_for_each_entry(rmidi, &umidi->rawmidi_list, list) { + if (!rmidi->ump) + continue; + /* Blocks have been already created? */ + if (rmidi->ump->info.num_blocks) + continue; + /* loop over GTBs */ + for (dir = 0; dir < 2; dir++) { + if (!rmidi->eps[dir]) + continue; + for (i = 0; i < rmidi->eps[dir]->ms_ep->bNumGrpTrmBlock; i++) { + blk = rmidi->eps[dir]->ms_ep->baAssoGrpTrmBlkID[i]; + err = create_gtb_block(rmidi, dir, blk); + if (err < 0) + return err; + } + } + } + + return 0; +} + static void snd_usb_midi_v2_free(struct snd_usb_midi2_interface *umidi) { free_all_midi2_endpoints(umidi); @@ -1009,6 +1091,12 @@ int snd_usb_midi_v2_create(struct snd_usb_audio *chip, goto error; } + err = create_blocks_from_gtb(umidi); + if (err < 0) { + usb_audio_err(chip, "Failed to create GTB blocks\n"); + goto error; + } + set_fallback_rawmidi_names(umidi); return 0; From patchwork Tue May 23 07:53:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251782 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 58235C7EE23 for ; Tue, 23 May 2023 07:58:04 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 68CF11E7; Tue, 23 May 2023 09:57:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 68CF11E7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828682; bh=pXh479cb/9fdWoRO6bYc75PhGVbNwDkR3ILDMJTUu0U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=SjhsNsKA+QuoHGKsdDWYGkxMh7ZxPKejmbeJXBIQU+eBLUZeg1uUNTIB3gVJrbfxP EONSyJJolSZd81L1SjfhKMDVNyGNkTca8s/U8a3jp1pksdLSIyUEWDkK5mFB3fXYOu hxa0OcWuEaK6dcXk7D5IoZNHY59nWzZcCPntC3rc= Received: by alsa1.perex.cz (Postfix, from userid 50401) id BF9CDF80604; Tue, 23 May 2023 09:54:53 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 0B0A0F80609; Tue, 23 May 2023 09:54:53 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 6D5EDF80589; Tue, 23 May 2023 09:54:46 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 1EC77F80557 for ; Tue, 23 May 2023 09:54:07 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 1EC77F80557 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=yT+GCP17; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=SRE2J/ph Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id C6DE5219D2; Tue, 23 May 2023 07:54:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828446; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rBljb7tTyeyRFOU5zBjiuTcOaaBXGLatx/YtsSA+dkA=; b=yT+GCP17WIK+5B3mcEPjOjIo6S30779rgp3Hz2mTkK5S3dm5P/GEt6Zf6+zIxZenIh23rh SQCcxmlKLb5HPXcDYLj7pAQNrLPCvsshF/J6wIllXRwjNaCr5LOVHPg9c5uefTI8GvPMVD 9Lb06JLhP7glrBXr0Ynhbfvv0AePRXU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828446; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rBljb7tTyeyRFOU5zBjiuTcOaaBXGLatx/YtsSA+dkA=; b=SRE2J/phZtrG7vXQqXoeNfl02sav/XroeaKt2syQ6/mpGDkKJSAx4KNdNJsEY1oQchgM++ MYtRDYiJYxtBkiAA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 6141213A1A; Tue, 23 May 2023 07:54:06 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id cOLmFh5xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:06 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 13/37] ALSA: ump: Redirect rawmidi substream access via own helpers Date: Tue, 23 May 2023 09:53:34 +0200 Message-Id: <20230523075358.9672-14-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: GLCFCJYM63VNT5VZZWZR3AXGGQ33XJ5N X-Message-ID-Hash: GLCFCJYM63VNT5VZZWZR3AXGGQ33XJ5N X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This is a code refactoring for abstracting the rawmidi access to the UMP's own helpers. It's a preliminary work for the later code refactoring of the UMP layer. Until now, we access to the rawmidi substream directly from the driver via rawmidi access helpers, but after this change, the driver is supposed to access via the newly introduced snd_ump_ops and receive/transmit via snd_ump_receive() and snd_ump_transmit() helpers. As of this commit, those are merely wrappers for the rawmidi substream, and no much function change is seen here. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/ump.h | 14 ++++++ sound/core/ump.c | 111 ++++++++++++++++++++++++++++++++++++++++++++ sound/usb/midi2.c | 71 ++++++++++------------------ 3 files changed, 149 insertions(+), 47 deletions(-) diff --git a/include/sound/ump.h b/include/sound/ump.h index 8a3ac97cd1d3..6f786b462f16 100644 --- a/include/sound/ump.h +++ b/include/sound/ump.h @@ -9,18 +9,30 @@ struct snd_ump_endpoint; struct snd_ump_block; +struct snd_ump_ops; struct snd_ump_endpoint { struct snd_rawmidi core; /* raw UMP access */ struct snd_ump_endpoint_info info; + const struct snd_ump_ops *ops; /* UMP ops set by the driver */ + struct snd_rawmidi_substream *substreams[2]; /* opened substreams */ + void *private_data; void (*private_free)(struct snd_ump_endpoint *ump); struct list_head block_list; /* list of snd_ump_block objects */ }; +/* ops filled by UMP drivers */ +struct snd_ump_ops { + int (*open)(struct snd_ump_endpoint *ump, int dir); + void (*close)(struct snd_ump_endpoint *ump, int dir); + void (*trigger)(struct snd_ump_endpoint *ump, int dir, int up); + void (*drain)(struct snd_ump_endpoint *ump, int dir); +}; + struct snd_ump_block { struct snd_ump_block_info info; struct snd_ump_endpoint *ump; @@ -39,6 +51,8 @@ int snd_ump_endpoint_new(struct snd_card *card, char *id, int device, int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, unsigned int direction, unsigned int first_group, unsigned int num_groups, struct snd_ump_block **blk_ret); +int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count); +int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count); /* * Some definitions for UMP diff --git a/sound/core/ump.c b/sound/core/ump.c index 651cd3752719..46ec297a786c 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -23,6 +23,11 @@ static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd, void __user *argp); static void snd_ump_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer); +static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream); +static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream); +static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream, + int up); +static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream); static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = { .dev_register = snd_ump_dev_register, @@ -31,6 +36,19 @@ static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = { .proc_read = snd_ump_proc_read, }; +static const struct snd_rawmidi_ops snd_ump_rawmidi_input_ops = { + .open = snd_ump_rawmidi_open, + .close = snd_ump_rawmidi_close, + .trigger = snd_ump_rawmidi_trigger, +}; + +static const struct snd_rawmidi_ops snd_ump_rawmidi_output_ops = { + .open = snd_ump_rawmidi_open, + .close = snd_ump_rawmidi_close, + .trigger = snd_ump_rawmidi_trigger, + .drain = snd_ump_rawmidi_drain, +}; + static void snd_ump_endpoint_free(struct snd_rawmidi *rmidi) { struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); @@ -104,6 +122,12 @@ int snd_ump_endpoint_new(struct snd_card *card, char *id, int device, ump->core.private_free = snd_ump_endpoint_free; ump->core.ops = &snd_ump_rawmidi_ops; + if (input) + snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_ump_rawmidi_input_ops); + if (output) + snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_ump_rawmidi_output_ops); ump_dbg(ump, "Created a UMP EP #%d (%s)\n", device, id); *ump_ret = ump; @@ -137,6 +161,93 @@ snd_ump_get_block(struct snd_ump_endpoint *ump, unsigned char id) return NULL; } +/* + * rawmidi ops for UMP endpoint + */ +static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream) +{ + struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); + int dir = substream->stream; + int err; + + if (ump->substreams[dir]) + return -EBUSY; + err = ump->ops->open(ump, dir); + if (err < 0) + return err; + ump->substreams[dir] = substream; + return 0; +} + +static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream) +{ + struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); + int dir = substream->stream; + + ump->substreams[dir] = NULL; + ump->ops->close(ump, dir); + return 0; +} + +static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); + int dir = substream->stream; + + ump->ops->trigger(ump, dir, up); +} + +static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream) +{ + struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); + + if (ump->ops->drain) + ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT); +} + +/** + * snd_ump_receive - transfer UMP packets from the device + * @ump: the UMP endpoint + * @buffer: the buffer pointer to transfer + * @count: byte size to transfer + * + * Called from the driver to submit the received UMP packets from the device + * to user-space. It's essentially a wrapper of rawmidi_receive(). + * The data to receive is in CPU-native endianness. + */ +int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count) +{ + struct snd_rawmidi_substream *substream = + ump->substreams[SNDRV_RAWMIDI_STREAM_INPUT]; + + if (!substream) + return 0; + return snd_rawmidi_receive(substream, (const char *)buffer, count); +} +EXPORT_SYMBOL_GPL(snd_ump_receive); + +/** + * snd_ump_transmit - transmit UMP packets + * @ump: the UMP endpoint + * @buffer: the buffer pointer to transfer + * @count: byte size to transfer + * + * Called from the driver to obtain the UMP packets from user-space to the + * device. It's essentially a wrapper of rawmidi_transmit(). + * The data to transmit is in CPU-native endianness. + */ +int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count) +{ + struct snd_rawmidi_substream *substream = + ump->substreams[SNDRV_RAWMIDI_STREAM_OUTPUT]; + + if (!substream) + return -ENODEV; + return snd_rawmidi_transmit(substream, (char *)buffer, count); +} +EXPORT_SYMBOL_GPL(snd_ump_transmit); + /** * snd_ump_block_new - Create a UMP block * @ump: UMP object diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 5ffee06ac746..7e849b2384ee 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -52,7 +52,8 @@ struct snd_usb_midi2_endpoint { struct usb_device *dev; const struct usb_ms20_endpoint_descriptor *ms_ep; /* reference to EP descriptor */ struct snd_usb_midi2_endpoint *pair; /* bidirectional pair EP */ - struct snd_usb_midi2_ump *rmidi; /* assigned UMP EP */ + struct snd_usb_midi2_ump *rmidi; /* assigned UMP EP pair */ + struct snd_ump_endpoint *ump; /* assigned UMP EP */ int direction; /* direction (STR_IN/OUT) */ unsigned int endpoint; /* EP number */ unsigned int pipe; /* URB pipe */ @@ -133,12 +134,8 @@ static int prepare_output_urb(struct snd_usb_midi2_endpoint *ep, { int count; - if (ep->substream) - count = snd_rawmidi_transmit(ep->substream, - urb->transfer_buffer, - ep->packets); - else - count = -ENODEV; + count = snd_ump_transmit(ep->ump, urb->transfer_buffer, + ep->packets); if (count < 0) { dev_dbg(&ep->dev->dev, "rawmidi transmit error %d\n", count); return count; @@ -197,9 +194,9 @@ static void input_urb_complete(struct urb *urb) len &= ~3; /* align UMP */ if (len > ep->packets) len = ep->packets; - if (len > 0 && ep->substream) { + if (len > 0) { le32_to_cpu_array((u32 *)urb->transfer_buffer, len >> 2); - snd_rawmidi_receive(ep->substream, urb->transfer_buffer, len); + snd_ump_receive(ep->ump, (u32 *)urb->transfer_buffer, len); } dequeue: set_bit(ctx->index, &ep->urb_free); @@ -330,68 +327,58 @@ static int alloc_midi_urbs(struct snd_usb_midi2_endpoint *ep) } static struct snd_usb_midi2_endpoint * -substream_to_endpoint(struct snd_rawmidi_substream *substream) +ump_to_endpoint(struct snd_ump_endpoint *ump, int dir) { - struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); struct snd_usb_midi2_ump *rmidi = ump->private_data; - return rmidi->eps[substream->stream]; + return rmidi->eps[dir]; } -/* rawmidi open callback */ -static int snd_usb_midi_v2_open(struct snd_rawmidi_substream *substream) +/* ump open callback */ +static int snd_usb_midi_v2_open(struct snd_ump_endpoint *ump, int dir) { - struct snd_usb_midi2_endpoint *ep = substream_to_endpoint(substream); + struct snd_usb_midi2_endpoint *ep = ump_to_endpoint(ump, dir); int err = 0; if (!ep || !ep->endpoint) return -ENODEV; if (ep->disconnected) return -EIO; - if (ep->substream) - return -EBUSY; if (ep->direction == STR_OUT) { err = alloc_midi_urbs(ep); if (err) return err; } - spin_lock_irq(&ep->lock); - ep->substream = substream; - spin_unlock_irq(&ep->lock); return 0; } -/* rawmidi close callback */ -static int snd_usb_midi_v2_close(struct snd_rawmidi_substream *substream) +/* ump close callback */ +static void snd_usb_midi_v2_close(struct snd_ump_endpoint *ump, int dir) { - struct snd_usb_midi2_endpoint *ep = substream_to_endpoint(substream); + struct snd_usb_midi2_endpoint *ep = ump_to_endpoint(ump, dir); - spin_lock_irq(&ep->lock); - ep->substream = NULL; - spin_unlock_irq(&ep->lock); if (ep->direction == STR_OUT) { kill_midi_urbs(ep, false); drain_urb_queue(ep); free_midi_urbs(ep); } - return 0; } -/* rawmidi trigger callback */ -static void snd_usb_midi_v2_trigger(struct snd_rawmidi_substream *substream, +/* ump trigger callback */ +static void snd_usb_midi_v2_trigger(struct snd_ump_endpoint *ump, int dir, int up) { - struct snd_usb_midi2_endpoint *ep = substream_to_endpoint(substream); + struct snd_usb_midi2_endpoint *ep = ump_to_endpoint(ump, dir); atomic_set(&ep->running, up); if (up && ep->direction == STR_OUT && !ep->disconnected) submit_io_urbs(ep); } -/* rawmidi drain callback */ -static void snd_usb_midi_v2_drain(struct snd_rawmidi_substream *substream) +/* ump drain callback */ +static void snd_usb_midi_v2_drain(struct snd_ump_endpoint *ump, int dir) { - struct snd_usb_midi2_endpoint *ep = substream_to_endpoint(substream); + struct snd_usb_midi2_endpoint *ep = ump_to_endpoint(ump, dir); drain_urb_queue(ep); } @@ -426,19 +413,13 @@ static int start_input_streams(struct snd_usb_midi2_interface *umidi) return err; } -static const struct snd_rawmidi_ops output_ops = { +static const struct snd_ump_ops snd_usb_midi_v2_ump_ops = { .open = snd_usb_midi_v2_open, .close = snd_usb_midi_v2_close, .trigger = snd_usb_midi_v2_trigger, .drain = snd_usb_midi_v2_drain, }; -static const struct snd_rawmidi_ops input_ops = { - .open = snd_usb_midi_v2_open, - .close = snd_usb_midi_v2_close, - .trigger = snd_usb_midi_v2_trigger, -}; - /* create a USB MIDI 2.0 endpoint object */ static int create_midi2_endpoint(struct snd_usb_midi2_interface *umidi, struct usb_host_endpoint *hostep, @@ -729,23 +710,19 @@ static int create_midi2_ump(struct snd_usb_midi2_interface *umidi, umidi->chip->num_rawmidis++; ump->private_data = rmidi; - - if (input) - snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_INPUT, - &input_ops); - if (output) - snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_OUTPUT, - &output_ops); + ump->ops = &snd_usb_midi_v2_ump_ops; rmidi->eps[STR_IN] = ep_in; rmidi->eps[STR_OUT] = ep_out; if (ep_in) { ep_in->pair = ep_out; ep_in->rmidi = rmidi; + ep_in->ump = ump; } if (ep_out) { ep_out->pair = ep_in; ep_out->rmidi = rmidi; + ep_out->ump = ump; } list_add_tail(&rmidi->list, &umidi->rawmidi_list); From patchwork Tue May 23 07:53:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251785 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 51DC9C7EE23 for ; Tue, 23 May 2023 07:58:50 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 0C53B846; Tue, 23 May 2023 09:57:58 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 0C53B846 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828728; bh=WXLNedAKeoZSC3jlV0KdDu8rJa1kyXerWq1OPiXcuzM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=kQ/Ticw/K00Ix2iCrhLfKueqZ4407DGKgp7eHe5Cm35LJJFCoNiH5/Lw08mqKljTD HBND1LhQtKRjX3ZRh/Ufrg9eSXuJfM/hOMqDzhvtjR2QvHNei3M89RMtatYLa+UNJf iahRDPEM2CR1S1MV9Re6Uoyosqv6p8DBc/Kous2c= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 55121F80637; Tue, 23 May 2023 09:55:06 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id F40CEF8061A; Tue, 23 May 2023 09:55:04 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 2A11CF80619; Tue, 23 May 2023 09:54:57 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 80663F80553 for ; Tue, 23 May 2023 09:54:07 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 80663F80553 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=FbmTm6RF; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=kSCNoBvH Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 26DC721910; Tue, 23 May 2023 07:54:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828447; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ydncxWn0EV81E3/dRgQHhCNZG1te/frMoK6XJTkG0LI=; b=FbmTm6RFpyP9ruCbUT2lKrnDee6HlT4RMLfnFmWv1BTR3SVeErgXxeYJb8FPkZuBE+n3bv 92RyAQsFvBCxEZIOhM+UPrEFneKXScXfvfH0uQdkRS1DiTC6mZGFZzCfdaSPZEqwpLZdLu pSj4aeQCWBiNZv/kNdSJZ0iTaCIqNCg= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828447; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ydncxWn0EV81E3/dRgQHhCNZG1te/frMoK6XJTkG0LI=; b=kSCNoBvHSd0K8GyM0TA2b+mREYPrcJoE57oibA4iCGjSdFYRj3K38iQMfOdDmKec6tOiP6 C8TefoRynJra5qAw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id C79AB13588; Tue, 23 May 2023 07:54:06 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id OIzPLx5xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:06 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 14/37] ALSA: ump: Add legacy raw MIDI support Date: Tue, 23 May 2023 09:53:35 +0200 Message-Id: <20230523075358.9672-15-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: GPU4DLRJHNDNR3ESGXGNTO6XG4HUFGQY X-Message-ID-Hash: GPU4DLRJHNDNR3ESGXGNTO6XG4HUFGQY X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This patch extends the UMP core code to support the legacy MIDI 1.0 rawmidi devices. When the new kconfig CONFIG_SND_UMP_LEGACY_RAWMIDI is set, the UMP core allows to attach an additional rawmidi device for each UMP Endpoint. The rawmidi device contains 16 substreams where each substream corresponds to a UMP Group belonging to the EP. The device reads/writes the legacy MIDI 1.0 byte streams and translates from/to UMP packets. The legacy rawmidi devices are exclusive with the UMP rawmidi devices, hence both of them can't be opened at the same time unless the UMP rawmidi is opened in APPEND mode. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/ump.h | 30 +++ include/sound/ump_msg.h | 540 +++++++++++++++++++++++++++++++++++++++ sound/core/Kconfig | 9 + sound/core/Makefile | 1 + sound/core/ump.c | 258 ++++++++++++++++++- sound/core/ump_convert.c | 520 +++++++++++++++++++++++++++++++++++++ sound/core/ump_convert.h | 43 ++++ 7 files changed, 1398 insertions(+), 3 deletions(-) create mode 100644 include/sound/ump_msg.h create mode 100644 sound/core/ump_convert.c create mode 100644 sound/core/ump_convert.h diff --git a/include/sound/ump.h b/include/sound/ump.h index 6f786b462f16..45f4c9b673b5 100644 --- a/include/sound/ump.h +++ b/include/sound/ump.h @@ -10,6 +10,7 @@ struct snd_ump_endpoint; struct snd_ump_block; struct snd_ump_ops; +struct ump_cvt_to_ump; struct snd_ump_endpoint { struct snd_rawmidi core; /* raw UMP access */ @@ -23,6 +24,24 @@ struct snd_ump_endpoint { void (*private_free)(struct snd_ump_endpoint *ump); struct list_head block_list; /* list of snd_ump_block objects */ + + /* intermediate buffer for UMP input */ + u32 input_buf[4]; + int input_buf_head; + int input_pending; + +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) + struct mutex open_mutex; + + spinlock_t legacy_locks[2]; + struct snd_rawmidi *legacy_rmidi; + struct snd_rawmidi_substream *legacy_substreams[2][SNDRV_UMP_MAX_GROUPS]; + + /* for legacy output; need to open the actual substream unlike input */ + int legacy_out_opens; + struct snd_rawmidi_file legacy_out_rfile; + struct ump_cvt_to_ump *out_cvts; +#endif }; /* ops filled by UMP drivers */ @@ -54,6 +73,17 @@ int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count); int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count); +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) +int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, + char *id, int device); +#else +static inline int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, + char *id, int device) +{ + return 0; +} +#endif + /* * Some definitions for UMP */ diff --git a/include/sound/ump_msg.h b/include/sound/ump_msg.h new file mode 100644 index 000000000000..c76c39944a5f --- /dev/null +++ b/include/sound/ump_msg.h @@ -0,0 +1,540 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Universal MIDI Packet (UMP): Message Definitions + */ +#ifndef __SOUND_UMP_MSG_H +#define __SOUND_UMP_MSG_H + +/* MIDI 1.0 / 2.0 Status Code (4bit) */ +enum { + UMP_MSG_STATUS_PER_NOTE_RCC = 0x0, + UMP_MSG_STATUS_PER_NOTE_ACC = 0x1, + UMP_MSG_STATUS_RPN = 0x2, + UMP_MSG_STATUS_NRPN = 0x3, + UMP_MSG_STATUS_RELATIVE_RPN = 0x4, + UMP_MSG_STATUS_RELATIVE_NRPN = 0x5, + UMP_MSG_STATUS_PER_NOTE_PITCH_BEND = 0x6, + UMP_MSG_STATUS_NOTE_OFF = 0x8, + UMP_MSG_STATUS_NOTE_ON = 0x9, + UMP_MSG_STATUS_POLY_PRESSURE = 0xa, + UMP_MSG_STATUS_CC = 0xb, + UMP_MSG_STATUS_PROGRAM = 0xc, + UMP_MSG_STATUS_CHANNEL_PRESSURE = 0xd, + UMP_MSG_STATUS_PITCH_BEND = 0xe, + UMP_MSG_STATUS_PER_NOTE_MGMT = 0xf, +}; + +/* MIDI 1.0 Channel Control (7bit) */ +enum { + UMP_CC_BANK_SELECT = 0, + UMP_CC_MODULATION = 1, + UMP_CC_BREATH = 2, + UMP_CC_FOOT = 4, + UMP_CC_PORTAMENTO_TIME = 5, + UMP_CC_DATA = 6, + UMP_CC_VOLUME = 7, + UMP_CC_BALANCE = 8, + UMP_CC_PAN = 10, + UMP_CC_EXPRESSION = 11, + UMP_CC_EFFECT_CONTROL_1 = 12, + UMP_CC_EFFECT_CONTROL_2 = 13, + UMP_CC_GP_1 = 16, + UMP_CC_GP_2 = 17, + UMP_CC_GP_3 = 18, + UMP_CC_GP_4 = 19, + UMP_CC_BANK_SELECT_LSB = 32, + UMP_CC_MODULATION_LSB = 33, + UMP_CC_BREATH_LSB = 34, + UMP_CC_FOOT_LSB = 36, + UMP_CC_PORTAMENTO_TIME_LSB = 37, + UMP_CC_DATA_LSB = 38, + UMP_CC_VOLUME_LSB = 39, + UMP_CC_BALANCE_LSB = 40, + UMP_CC_PAN_LSB = 42, + UMP_CC_EXPRESSION_LSB = 43, + UMP_CC_EFFECT1_LSB = 44, + UMP_CC_EFFECT2_LSB = 45, + UMP_CC_GP_1_LSB = 48, + UMP_CC_GP_2_LSB = 49, + UMP_CC_GP_3_LSB = 50, + UMP_CC_GP_4_LSB = 51, + UMP_CC_SUSTAIN = 64, + UMP_CC_PORTAMENTO_SWITCH = 65, + UMP_CC_SOSTENUTO = 66, + UMP_CC_SOFT_PEDAL = 67, + UMP_CC_LEGATO = 68, + UMP_CC_HOLD_2 = 69, + UMP_CC_SOUND_CONTROLLER_1 = 70, + UMP_CC_SOUND_CONTROLLER_2 = 71, + UMP_CC_SOUND_CONTROLLER_3 = 72, + UMP_CC_SOUND_CONTROLLER_4 = 73, + UMP_CC_SOUND_CONTROLLER_5 = 74, + UMP_CC_SOUND_CONTROLLER_6 = 75, + UMP_CC_SOUND_CONTROLLER_7 = 76, + UMP_CC_SOUND_CONTROLLER_8 = 77, + UMP_CC_SOUND_CONTROLLER_9 = 78, + UMP_CC_SOUND_CONTROLLER_10 = 79, + UMP_CC_GP_5 = 80, + UMP_CC_GP_6 = 81, + UMP_CC_GP_7 = 82, + UMP_CC_GP_8 = 83, + UMP_CC_PORTAMENTO_CONTROL = 84, + UMP_CC_EFFECT_1 = 91, + UMP_CC_EFFECT_2 = 92, + UMP_CC_EFFECT_3 = 93, + UMP_CC_EFFECT_4 = 94, + UMP_CC_EFFECT_5 = 95, + UMP_CC_DATA_INC = 96, + UMP_CC_DATA_DEC = 97, + UMP_CC_NRPN_LSB = 98, + UMP_CC_NRPN_MSB = 99, + UMP_CC_RPN_LSB = 100, + UMP_CC_RPN_MSB = 101, + UMP_CC_ALL_SOUND_OFF = 120, + UMP_CC_RESET_ALL = 121, + UMP_CC_LOCAL_CONTROL = 122, + UMP_CC_ALL_NOTES_OFF = 123, + UMP_CC_OMNI_OFF = 124, + UMP_CC_OMNI_ON = 125, + UMP_CC_POLY_OFF = 126, + UMP_CC_POLY_ON = 127, +}; + +/* MIDI 1.0 / 2.0 System Messages (0xfx) */ +enum { + UMP_SYSTEM_STATUS_MIDI_TIME_CODE = 0xf1, + UMP_SYSTEM_STATUS_SONG_POSITION = 0xf2, + UMP_SYSTEM_STATUS_SONG_SELECT = 0xf3, + UMP_SYSTEM_STATUS_TUNE_REQUEST = 0xf6, + UMP_SYSTEM_STATUS_TIMING_CLOCK = 0xf8, + UMP_SYSTEM_STATUS_START = 0xfa, + UMP_SYSTEM_STATUS_CONTINUE = 0xfb, + UMP_SYSTEM_STATUS_STOP = 0xfc, + UMP_SYSTEM_STATUS_ACTIVE_SENSING = 0xfe, + UMP_SYSTEM_STATUS_RESET = 0xff, +}; + +/* MIDI 1.0 Realtime and SysEx status messages (0xfx) */ +enum { + UMP_MIDI1_MSG_REALTIME = 0xf0, /* mask */ + UMP_MIDI1_MSG_SYSEX_START = 0xf0, + UMP_MIDI1_MSG_SYSEX_END = 0xf7, +}; + +/* + * UMP Message Definitions + */ + +/* MIDI 1.0 Note Off / Note On (32bit) */ +struct snd_ump_midi1_msg_note { +#ifdef __BIG_ENDIAN_BITFIELD + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 note:8; + u32 velocity:8; +#else + u32 velocity:8; + u32 note:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; +#endif +} __packed; + +/* MIDI 1.0 Poly Pressure (32bit) */ +struct snd_ump_midi1_msg_paf { +#ifdef __BIG_ENDIAN_BITFIELD + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 note:8; + u32 data:8; +#else + u32 data:8; + u32 note:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; +#endif +} __packed; + +/* MIDI 1.0 Control Change (32bit) */ +struct snd_ump_midi1_msg_cc { +#ifdef __BIG_ENDIAN_BITFIELD + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 index:8; + u32 data:8; +#else + u32 data:8; + u32 index:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; +#endif +} __packed; + +/* MIDI 1.0 Program Change (32bit) */ +struct snd_ump_midi1_msg_program { +#ifdef __BIG_ENDIAN_BITFIELD + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 program:8; + u32 reserved:8; +#else +#endif + u32 reserved:8; + u32 program:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; +} __packed; + +/* MIDI 1.0 Channel Pressure (32bit) */ +struct snd_ump_midi1_msg_caf { +#ifdef __BIG_ENDIAN_BITFIELD + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 data:8; + u32 reserved:8; +#else + u32 reserved:8; + u32 data:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; +#endif +} __packed; + +/* MIDI 1.0 Pitch Bend (32bit) */ +struct snd_ump_midi1_msg_pitchbend { +#ifdef __BIG_ENDIAN_BITFIELD + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 data_lsb:8; + u32 data_msb:8; +#else + u32 data_msb:8; + u32 data_lsb:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; +#endif +} __packed; + +/* System Common and Real Time messages (32bit); no channel field */ +struct snd_ump_system_msg { +#ifdef __BIG_ENDIAN_BITFIELD + u32 type:4; + u32 group:4; + u32 status:8; + u32 parm1:8; + u32 parm2:8; +#else + u32 parm2:8; + u32 parm1:8; + u32 status:8; + u32 group:4; + u32 type:4; +#endif +} __packed; + +/* MIDI 1.0 UMP CVM (32bit) */ +union snd_ump_midi1_msg { + struct snd_ump_midi1_msg_note note; + struct snd_ump_midi1_msg_paf paf; + struct snd_ump_midi1_msg_cc cc; + struct snd_ump_midi1_msg_program pg; + struct snd_ump_midi1_msg_caf caf; + struct snd_ump_midi1_msg_pitchbend pb; + struct snd_ump_system_msg system; + u32 raw; +}; + +/* MIDI 2.0 Note Off / Note On (64bit) */ +struct snd_ump_midi2_msg_note { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 note:8; + u32 attribute_type:8; + /* 1 */ + u32 velocity:16; + u32 attribute_data:16; +#else + /* 0 */ + u32 attribute_type:8; + u32 note:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 attribute_data:16; + u32 velocity:16; +#endif +} __packed; + +/* MIDI 2.0 Poly Pressure (64bit) */ +struct snd_ump_midi2_msg_paf { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 note:8; + u32 reserved:8; + /* 1 */ + u32 data; +#else + /* 0 */ + u32 reserved:8; + u32 note:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 data; +#endif +} __packed; + +/* MIDI 2.0 Per-Note Controller (64bit) */ +struct snd_ump_midi2_msg_pernote_cc { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 note:8; + u32 index:8; + /* 1 */ + u32 data; +#else + /* 0 */ + u32 index:8; + u32 note:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 data; +#endif +} __packed; + +/* MIDI 2.0 Per-Note Management (64bit) */ +struct snd_ump_midi2_msg_pernote_mgmt { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 note:8; + u32 flags:8; + /* 1 */ + u32 reserved; +#else + /* 0 */ + u32 flags:8; + u32 note:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 reserved; +#endif +} __packed; + +/* MIDI 2.0 Control Change (64bit) */ +struct snd_ump_midi2_msg_cc { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 index:8; + u32 reserved:8; + /* 1 */ + u32 data; +#else + /* 0 */ + u32 reserved:8; + u32 index:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 data; +#endif +} __packed; + +/* MIDI 2.0 Registered Controller (RPN) / Assignable Controller (NRPN) (64bit) */ +struct snd_ump_midi2_msg_rpn { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 bank:8; + u32 index:8; + /* 1 */ + u32 data; +#else + /* 0 */ + u32 index:8; + u32 bank:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 data; +#endif +} __packed; + +/* MIDI 2.0 Program Change (64bit) */ +struct snd_ump_midi2_msg_program { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 reserved:15; + u32 bank_valid:1; + /* 1 */ + u32 program:8; + u32 reserved2:8; + u32 bank_msb:8; + u32 bank_lsb:8; +#else + /* 0 */ + u32 bank_valid:1; + u32 reserved:15; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 bank_lsb:8; + u32 bank_msb:8; + u32 reserved2:8; + u32 program:8; +#endif +} __packed; + +/* MIDI 2.0 Channel Pressure (64bit) */ +struct snd_ump_midi2_msg_caf { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 reserved:16; + /* 1 */ + u32 data; +#else + /* 0 */ + u32 reserved:16; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 data; +#endif +} __packed; + +/* MIDI 2.0 Pitch Bend (64bit) */ +struct snd_ump_midi2_msg_pitchbend { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 reserved:16; + /* 1 */ + u32 data; +#else + /* 0 */ + u32 reserved:16; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 data; +#endif +} __packed; + +/* MIDI 2.0 Per-Note Pitch Bend (64bit) */ +struct snd_ump_midi2_msg_pernote_pitchbend { +#ifdef __BIG_ENDIAN_BITFIELD + /* 0 */ + u32 type:4; + u32 group:4; + u32 status:4; + u32 channel:4; + u32 note:8; + u32 reserved:8; + /* 1 */ + u32 data; +#else + /* 0 */ + u32 reserved:8; + u32 note:8; + u32 channel:4; + u32 status:4; + u32 group:4; + u32 type:4; + /* 1 */ + u32 data; +#endif +} __packed; + +/* MIDI 2.0 UMP CVM (64bit) */ +union snd_ump_midi2_msg { + struct snd_ump_midi2_msg_note note; + struct snd_ump_midi2_msg_paf paf; + struct snd_ump_midi2_msg_pernote_cc pernote_cc; + struct snd_ump_midi2_msg_pernote_mgmt pernote_mgmt; + struct snd_ump_midi2_msg_cc cc; + struct snd_ump_midi2_msg_rpn rpn; + struct snd_ump_midi2_msg_program pg; + struct snd_ump_midi2_msg_caf caf; + struct snd_ump_midi2_msg_pitchbend pb; + struct snd_ump_midi2_msg_pernote_pitchbend pernote_pb; + u32 raw[2]; +}; + +#endif /* __SOUND_UMP_MSG_H */ diff --git a/sound/core/Kconfig b/sound/core/Kconfig index eb1c6c930de9..e41818e59a15 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -30,6 +30,15 @@ config SND_UMP tristate select SND_RAWMIDI +config SND_UMP_LEGACY_RAWMIDI + bool "Legacy raw MIDI support for UMP streams" + depends on SND_UMP + help + This option enables the legacy raw MIDI support for UMP streams. + When this option is set, an additional rawmidi device for the + legacy MIDI 1.0 byte streams is created for each UMP Endpoint. + The device contains 16 substreams corresponding to UMP groups. + config SND_COMPRESS_OFFLOAD tristate diff --git a/sound/core/Makefile b/sound/core/Makefile index 562a05edbc50..a6b444ee2832 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -29,6 +29,7 @@ snd-pcm-dmaengine-objs := pcm_dmaengine.o snd-ctl-led-objs := control_led.o snd-rawmidi-objs := rawmidi.o snd-ump-objs := ump.o +snd-ump-$(CONFIG_SND_UMP_LEGACY_RAWMIDI) += ump_convert.o snd-timer-objs := timer.o snd-hrtimer-objs := hrtimer.o snd-rtctimer-objs := rtctimer.o diff --git a/sound/core/ump.c b/sound/core/ump.c index 46ec297a786c..cbe704b5d90d 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -11,6 +11,7 @@ #include #include #include +#include "ump_convert.h" #define ump_err(ump, fmt, args...) dev_err(&(ump)->core.dev, fmt, ##args) #define ump_warn(ump, fmt, args...) dev_warn(&(ump)->core.dev, fmt, ##args) @@ -29,6 +30,23 @@ static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream, int up); static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream); +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) +static int process_legacy_output(struct snd_ump_endpoint *ump, + u32 *buffer, int count); +static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, + int words); +#else +static inline int process_legacy_output(struct snd_ump_endpoint *ump, + u32 *buffer, int count) +{ + return 0; +} +static inline void process_legacy_input(struct snd_ump_endpoint *ump, + const u32 *src, int words) +{ +} +#endif + static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = { .dev_register = snd_ump_dev_register, .dev_unregister = snd_ump_dev_unregister, @@ -65,6 +83,10 @@ static void snd_ump_endpoint_free(struct snd_rawmidi *rmidi) if (ump->private_free) ump->private_free(ump); + +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) + snd_ump_convert_free(ump); +#endif } /** @@ -110,6 +132,11 @@ int snd_ump_endpoint_new(struct snd_card *card, char *id, int device, if (!ump) return -ENOMEM; INIT_LIST_HEAD(&ump->block_list); +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) + mutex_init(&ump->open_mutex); + spin_lock_init(&ump->legacy_locks[0]); + spin_lock_init(&ump->legacy_locks[1]); +#endif err = snd_rawmidi_init(&ump->core, card, id, device, output, input, info_flags); if (err < 0) { @@ -206,6 +233,33 @@ static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream) ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT); } +/* number of 32bit words per message type */ +static unsigned char ump_packet_words[0x10] = { + 1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4 +}; + +/* parse the UMP packet data; + * the data is copied onto ump->input_buf[]. + * When a full packet is completed, returns the number of words (from 1 to 4). + * OTOH, if the packet is incomplete, returns 0. + */ +static int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val) +{ + int words; + + if (!ump->input_pending) + ump->input_pending = ump_packet_words[ump_message_type(val)]; + + ump->input_buf[ump->input_buf_head++] = val; + ump->input_pending--; + if (!ump->input_pending) { + words = ump->input_buf_head; + ump->input_buf_head = 0; + return words; + } + return 0; +} + /** * snd_ump_receive - transfer UMP packets from the device * @ump: the UMP endpoint @@ -218,9 +272,18 @@ static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream) */ int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count) { - struct snd_rawmidi_substream *substream = - ump->substreams[SNDRV_RAWMIDI_STREAM_INPUT]; + struct snd_rawmidi_substream *substream; + const u32 *p = buffer; + int n, words = count >> 2; + while (words--) { + n = snd_ump_receive_ump_val(ump, *p++); + if (!n) + continue; + process_legacy_input(ump, ump->input_buf, n); + } + + substream = ump->substreams[SNDRV_RAWMIDI_STREAM_INPUT]; if (!substream) return 0; return snd_rawmidi_receive(substream, (const char *)buffer, count); @@ -241,10 +304,15 @@ int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count) { struct snd_rawmidi_substream *substream = ump->substreams[SNDRV_RAWMIDI_STREAM_OUTPUT]; + int err; if (!substream) return -ENODEV; - return snd_rawmidi_transmit(substream, (char *)buffer, count); + err = snd_rawmidi_transmit(substream, (char *)buffer, count); + /* received either data or an error? */ + if (err) + return err; + return process_legacy_output(ump, buffer, count); } EXPORT_SYMBOL_GPL(snd_ump_transmit); @@ -386,5 +454,189 @@ static void snd_ump_proc_read(struct snd_info_entry *entry, } } +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) +/* + * Legacy rawmidi support + */ +static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream) +{ + struct snd_ump_endpoint *ump = substream->rmidi->private_data; + int dir = substream->stream; + int group = substream->number; + int err; + + mutex_lock(&ump->open_mutex); + if (ump->legacy_substreams[dir][group]) { + err = -EBUSY; + goto unlock; + } + if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { + if (!ump->legacy_out_opens) { + err = snd_rawmidi_kernel_open(&ump->core, 0, + SNDRV_RAWMIDI_LFLG_OUTPUT | + SNDRV_RAWMIDI_LFLG_APPEND, + &ump->legacy_out_rfile); + if (err < 0) + goto unlock; + } + ump->legacy_out_opens++; + snd_ump_reset_convert_to_ump(ump, group); + } + spin_lock_irq(&ump->legacy_locks[dir]); + ump->legacy_substreams[dir][group] = substream; + spin_unlock_irq(&ump->legacy_locks[dir]); + unlock: + mutex_unlock(&ump->open_mutex); + return 0; +} + +static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream) +{ + struct snd_ump_endpoint *ump = substream->rmidi->private_data; + int dir = substream->stream; + int group = substream->number; + + mutex_lock(&ump->open_mutex); + spin_lock_irq(&ump->legacy_locks[dir]); + ump->legacy_substreams[dir][group] = NULL; + spin_unlock_irq(&ump->legacy_locks[dir]); + if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { + if (!--ump->legacy_out_opens) + snd_rawmidi_kernel_release(&ump->legacy_out_rfile); + } + mutex_unlock(&ump->open_mutex); + return 0; +} + +static void snd_ump_legacy_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct snd_ump_endpoint *ump = substream->rmidi->private_data; + int dir = substream->stream; + + ump->ops->trigger(ump, dir, up); +} + +static void snd_ump_legacy_drain(struct snd_rawmidi_substream *substream) +{ + struct snd_ump_endpoint *ump = substream->rmidi->private_data; + + if (ump->ops->drain) + ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT); +} + +static int snd_ump_legacy_dev_register(struct snd_rawmidi *rmidi) +{ + /* dummy, just for avoiding create superfluous seq clients */ + return 0; +} + +static const struct snd_rawmidi_ops snd_ump_legacy_input_ops = { + .open = snd_ump_legacy_open, + .close = snd_ump_legacy_close, + .trigger = snd_ump_legacy_trigger, +}; + +static const struct snd_rawmidi_ops snd_ump_legacy_output_ops = { + .open = snd_ump_legacy_open, + .close = snd_ump_legacy_close, + .trigger = snd_ump_legacy_trigger, + .drain = snd_ump_legacy_drain, +}; + +static const struct snd_rawmidi_global_ops snd_ump_legacy_ops = { + .dev_register = snd_ump_legacy_dev_register, +}; + +static int process_legacy_output(struct snd_ump_endpoint *ump, + u32 *buffer, int count) +{ + struct snd_rawmidi_substream *substream; + struct ump_cvt_to_ump *ctx; + const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT; + unsigned char c; + int group, size = 0; + unsigned long flags; + + if (!ump->out_cvts || !ump->legacy_out_opens) + return 0; + + spin_lock_irqsave(&ump->legacy_locks[dir], flags); + for (group = 0; group < SNDRV_UMP_MAX_GROUPS; group++) { + substream = ump->legacy_substreams[dir][group]; + if (!substream) + continue; + ctx = &ump->out_cvts[group]; + while (!ctx->ump_bytes && + snd_rawmidi_transmit(substream, &c, 1) > 0) + snd_ump_convert_to_ump(ump, group, c); + if (ctx->ump_bytes && ctx->ump_bytes <= count) { + size = ctx->ump_bytes; + memcpy(buffer, ctx->ump, size); + ctx->ump_bytes = 0; + break; + } + } + spin_unlock_irqrestore(&ump->legacy_locks[dir], flags); + return size; +} + +static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, + int words) +{ + struct snd_rawmidi_substream *substream; + unsigned char buf[16]; + unsigned char group; + unsigned long flags; + const int dir = SNDRV_RAWMIDI_STREAM_INPUT; + int size; + + size = snd_ump_convert_from_ump(ump, src, buf, &group); + if (size <= 0) + return; + spin_lock_irqsave(&ump->legacy_locks[dir], flags); + substream = ump->legacy_substreams[dir][group]; + if (substream) + snd_rawmidi_receive(substream, buf, size); + spin_unlock_irqrestore(&ump->legacy_locks[dir], flags); +} + +int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, + char *id, int device) +{ + struct snd_rawmidi *rmidi; + bool input, output; + int err; + + err = snd_ump_convert_init(ump); + if (err < 0) + return err; + + input = ump->core.info_flags & SNDRV_RAWMIDI_INFO_INPUT; + output = ump->core.info_flags & SNDRV_RAWMIDI_INFO_OUTPUT; + err = snd_rawmidi_new(ump->core.card, id, device, + output ? 16 : 0, input ? 16 : 0, + &rmidi); + if (err < 0) { + snd_ump_convert_free(ump); + return err; + } + + if (input) + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_ump_legacy_input_ops); + if (output) + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_ump_legacy_output_ops); + rmidi->info_flags = ump->core.info_flags & ~SNDRV_RAWMIDI_INFO_UMP; + rmidi->ops = &snd_ump_legacy_ops; + rmidi->private_data = ump; + ump->legacy_rmidi = rmidi; + ump_dbg(ump, "Created a legacy rawmidi #%d (%s)\n", device, id); + return 0; +} +EXPORT_SYMBOL_GPL(snd_ump_attach_legacy_rawmidi); +#endif /* CONFIG_SND_UMP_LEGACY_RAWMIDI */ + MODULE_DESCRIPTION("Universal MIDI Packet (UMP) Core Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/core/ump_convert.c b/sound/core/ump_convert.c new file mode 100644 index 000000000000..cb7c2f959a27 --- /dev/null +++ b/sound/core/ump_convert.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Helpers for UMP <-> MIDI 1.0 byte stream conversion + */ + +#include +#include +#include +#include +#include +#include "ump_convert.h" + +/* + * Upgrade / downgrade value bits + */ +static u8 downscale_32_to_7bit(u32 src) +{ + return src >> 25; +} + +static u16 downscale_32_to_14bit(u32 src) +{ + return src >> 18; +} + +static u8 downscale_16_to_7bit(u16 src) +{ + return src >> 9; +} + +static u16 upscale_7_to_16bit(u8 src) +{ + u16 val, repeat; + + val = (u16)src << 9; + if (src <= 0x40) + return val; + repeat = src & 0x3f; + return val | (repeat << 3) | (repeat >> 3); +} + +static u32 upscale_7_to_32bit(u8 src) +{ + u32 val, repeat; + + val = src << 25; + if (src <= 0x40) + return val; + repeat = src & 0x3f; + return val | (repeat << 19) | (repeat << 13) | + (repeat << 7) | (repeat << 1) | (repeat >> 5); +} + +static u32 upscale_14_to_32bit(u16 src) +{ + u32 val, repeat; + + val = src << 18; + if (src <= 0x2000) + return val; + repeat = src & 0x1fff; + return val | (repeat << 5) | (repeat >> 8); +} + +/* + * UMP -> MIDI 1 byte stream conversion + */ +/* convert a UMP System message to MIDI 1.0 byte stream */ +static int cvt_ump_system_to_legacy(u32 data, unsigned char *buf) +{ + buf[0] = ump_message_status_channel(data); + switch (ump_message_status_code(data)) { + case UMP_SYSTEM_STATUS_MIDI_TIME_CODE: + case UMP_SYSTEM_STATUS_SONG_SELECT: + buf[1] = (data >> 8) & 0x7f; + return 1; + case UMP_SYSTEM_STATUS_SONG_POSITION: + buf[1] = (data >> 8) & 0x7f; + buf[2] = data & 0x7f; + return 3; + default: + return 1; + } +} + +/* convert a UMP MIDI 1.0 Channel Voice message to MIDI 1.0 byte stream */ +static int cvt_ump_midi1_to_legacy(u32 data, unsigned char *buf) +{ + buf[0] = ump_message_status_channel(data); + buf[1] = (data >> 8) & 0xff; + switch (ump_message_status_code(data)) { + case UMP_MSG_STATUS_PROGRAM: + case UMP_MSG_STATUS_CHANNEL_PRESSURE: + return 2; + default: + buf[2] = data & 0xff; + return 3; + } +} + +/* convert a UMP MIDI 2.0 Channel Voice message to MIDI 1.0 byte stream */ +static int cvt_ump_midi2_to_legacy(const union snd_ump_midi2_msg *midi2, + unsigned char *buf) +{ + unsigned char status = midi2->note.status; + unsigned char channel = midi2->note.channel; + u16 v; + + buf[0] = (status << 4) | channel; + switch (status) { + case UMP_MSG_STATUS_NOTE_OFF: + case UMP_MSG_STATUS_NOTE_ON: + buf[1] = midi2->note.note; + buf[2] = downscale_16_to_7bit(midi2->note.velocity); + if (status == UMP_MSG_STATUS_NOTE_ON && !buf[2]) + buf[2] = 1; + return 3; + case UMP_MSG_STATUS_POLY_PRESSURE: + buf[1] = midi2->paf.note; + buf[2] = downscale_32_to_7bit(midi2->paf.data); + return 3; + case UMP_MSG_STATUS_CC: + buf[1] = midi2->cc.index; + buf[2] = downscale_32_to_7bit(midi2->cc.data); + return 3; + case UMP_MSG_STATUS_CHANNEL_PRESSURE: + buf[1] = downscale_32_to_7bit(midi2->caf.data); + return 2; + case UMP_MSG_STATUS_PROGRAM: + if (midi2->pg.bank_valid) { + buf[0] = channel | (UMP_MSG_STATUS_CC << 4); + buf[1] = UMP_CC_BANK_SELECT; + buf[2] = midi2->pg.bank_msb; + buf[3] = channel | (UMP_MSG_STATUS_CC << 4); + buf[4] = UMP_CC_BANK_SELECT_LSB; + buf[5] = midi2->pg.bank_lsb; + buf[6] = channel | (UMP_MSG_STATUS_PROGRAM << 4); + buf[7] = midi2->pg.program; + return 8; + } + buf[1] = midi2->pg.program; + return 2; + case UMP_MSG_STATUS_PITCH_BEND: + v = downscale_32_to_14bit(midi2->pb.data); + buf[1] = v & 0x7f; + buf[2] = v >> 7; + return 3; + case UMP_MSG_STATUS_RPN: + case UMP_MSG_STATUS_NRPN: + buf[0] = channel | (UMP_MSG_STATUS_CC << 4); + buf[1] = status == UMP_MSG_STATUS_RPN ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB; + buf[2] = midi2->rpn.bank; + buf[3] = buf[0]; + buf[4] = status == UMP_MSG_STATUS_RPN ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB; + buf[5] = midi2->rpn.index; + buf[6] = buf[0]; + buf[7] = UMP_CC_DATA; + v = downscale_32_to_14bit(midi2->rpn.data); + buf[8] = v >> 7; + buf[9] = buf[0]; + buf[10] = UMP_CC_DATA_LSB; + buf[11] = v & 0x7f; + return 12; + default: + return 0; + } +} + +/* convert a UMP 7-bit SysEx message to MIDI 1.0 byte stream */ +static int cvt_ump_sysex7_to_legacy(const u32 *data, unsigned char *buf) +{ + unsigned char status; + unsigned char bytes; + int size, offset; + + status = ump_sysex_message_status(*data); + if (status > UMP_SYSEX_STATUS_END) + return 0; // unsupported, skip + bytes = ump_sysex_message_length(*data); + if (bytes > 6) + return 0; // skip + + size = 0; + if (status == UMP_SYSEX_STATUS_SINGLE || + status == UMP_SYSEX_STATUS_START) { + buf[0] = UMP_MIDI1_MSG_SYSEX_START; + size = 1; + } + + offset = 8; + for (; bytes; bytes--, size++) { + buf[size] = (*data >> offset) & 0x7f; + if (!offset) { + offset = 24; + data++; + } else { + offset -= 8; + } + } + + if (status == UMP_SYSEX_STATUS_SINGLE || + status == UMP_SYSEX_STATUS_END) + buf[size++] = UMP_MIDI1_MSG_SYSEX_END; + + return size; +} + +/* convert from a UMP packet @data to MIDI 1.0 bytes at @buf; + * the target group is stored at @group_ret, + * returns the number of bytes of MIDI 1.0 stream + */ +int snd_ump_convert_from_ump(struct snd_ump_endpoint *ump, + const u32 *data, + unsigned char *buf, + unsigned char *group_ret) +{ + *group_ret = ump_message_group(*data); + + switch (ump_message_type(*data)) { + case UMP_MSG_TYPE_SYSTEM: + return cvt_ump_system_to_legacy(*data, buf); + case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE: + return cvt_ump_midi1_to_legacy(*data, buf); + case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE: + return cvt_ump_midi2_to_legacy((const union snd_ump_midi2_msg *)data, + buf); + case UMP_MSG_TYPE_DATA: + return cvt_ump_sysex7_to_legacy(data, buf); + } + + return 0; +} + +/* + * MIDI 1 byte stream -> UMP conversion + */ +/* convert MIDI 1.0 SysEx to a UMP packet */ +static int cvt_legacy_sysex_to_ump(struct ump_cvt_to_ump *cvt, + unsigned char group, u32 *data, bool finish) +{ + unsigned char status; + bool start = cvt->in_sysex == 1; + int i, offset; + + if (start && finish) + status = UMP_SYSEX_STATUS_SINGLE; + else if (start) + status = UMP_SYSEX_STATUS_START; + else if (finish) + status = UMP_SYSEX_STATUS_END; + else + status = UMP_SYSEX_STATUS_CONTINUE; + *data = ump_compose(UMP_MSG_TYPE_DATA, group, status, cvt->len); + offset = 8; + for (i = 0; i < cvt->len; i++) { + *data |= cvt->buf[i] << offset; + if (!offset) { + offset = 24; + data++; + } else + offset -= 8; + } + cvt->len = 0; + if (finish) + cvt->in_sysex = 0; + else + cvt->in_sysex++; + return 8; +} + +/* convert to a UMP System message */ +static int cvt_legacy_system_to_ump(struct ump_cvt_to_ump *cvt, + unsigned char group, u32 *data) +{ + data[0] = ump_compose(UMP_MSG_TYPE_SYSTEM, group, 0, cvt->buf[0]); + if (cvt->cmd_bytes > 1) + data[0] |= cvt->buf[1] << 8; + if (cvt->cmd_bytes > 2) + data[0] |= cvt->buf[2]; + return 4; +} + +static void fill_rpn(struct ump_cvt_to_ump_bank *cc, + union snd_ump_midi2_msg *midi2) +{ + if (cc->rpn_set) { + midi2->rpn.status = UMP_MSG_STATUS_RPN; + midi2->rpn.bank = cc->cc_rpn_msb; + midi2->rpn.index = cc->cc_rpn_lsb; + cc->rpn_set = 0; + cc->cc_rpn_msb = cc->cc_rpn_lsb = 0; + } else { + midi2->rpn.status = UMP_MSG_STATUS_NRPN; + midi2->rpn.bank = cc->cc_nrpn_msb; + midi2->rpn.index = cc->cc_nrpn_lsb; + cc->nrpn_set = 0; + cc->cc_nrpn_msb = cc->cc_nrpn_lsb = 0; + } + midi2->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) | + cc->cc_data_lsb); + cc->cc_data_msb = cc->cc_data_lsb = 0; +} + +/* convert to a MIDI 1.0 Channel Voice message */ +static int cvt_legacy_cmd_to_ump(struct snd_ump_endpoint *ump, + struct ump_cvt_to_ump *cvt, + unsigned char group, u32 *data, + unsigned char bytes) +{ + const unsigned char *buf = cvt->buf; + struct ump_cvt_to_ump_bank *cc; + union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)data; + unsigned char status, channel; + + BUILD_BUG_ON(sizeof(union snd_ump_midi1_msg) != 4); + BUILD_BUG_ON(sizeof(union snd_ump_midi2_msg) != 8); + + /* for MIDI 1.0 UMP, it's easy, just pack it into UMP */ + if (ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI1) { + data[0] = ump_compose(UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE, + group, 0, buf[0]); + data[0] |= buf[1] << 8; + if (bytes > 2) + data[0] |= buf[2]; + return 4; + } + + status = *buf >> 4; + channel = *buf & 0x0f; + cc = &cvt->bank[channel]; + + /* special handling: treat note-on with 0 velocity as note-off */ + if (status == UMP_MSG_STATUS_NOTE_ON && !buf[2]) + status = UMP_MSG_STATUS_NOTE_OFF; + + /* initialize the packet */ + data[0] = ump_compose(UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE, + group, status, channel); + data[1] = 0; + + switch (status) { + case UMP_MSG_STATUS_NOTE_ON: + if (!buf[2]) + status = UMP_MSG_STATUS_NOTE_OFF; + fallthrough; + case UMP_MSG_STATUS_NOTE_OFF: + midi2->note.note = buf[1]; + midi2->note.velocity = upscale_7_to_16bit(buf[2]); + break; + case UMP_MSG_STATUS_POLY_PRESSURE: + midi2->paf.note = buf[1]; + midi2->paf.data = upscale_7_to_32bit(buf[2]); + break; + case UMP_MSG_STATUS_CC: + switch (buf[1]) { + case UMP_CC_RPN_MSB: + cc->rpn_set = 1; + cc->cc_rpn_msb = buf[2]; + return 0; // skip + case UMP_CC_RPN_LSB: + cc->rpn_set = 1; + cc->cc_rpn_lsb = buf[2]; + return 0; // skip + case UMP_CC_NRPN_MSB: + cc->nrpn_set = 1; + cc->cc_nrpn_msb = buf[2]; + return 0; // skip + case UMP_CC_NRPN_LSB: + cc->nrpn_set = 1; + cc->cc_nrpn_lsb = buf[2]; + return 0; // skip + case UMP_CC_DATA: + cc->cc_data_msb = buf[2]; + return 0; // skip + case UMP_CC_BANK_SELECT: + cc->bank_set = 1; + cc->cc_bank_msb = buf[2]; + return 0; // skip + case UMP_CC_BANK_SELECT_LSB: + cc->bank_set = 1; + cc->cc_bank_lsb = buf[2]; + return 0; // skip + case UMP_CC_DATA_LSB: + cc->cc_data_lsb = buf[2]; + if (cc->rpn_set || cc->nrpn_set) + fill_rpn(cc, midi2); + else + return 0; // skip + break; + default: + midi2->cc.index = buf[1]; + midi2->cc.data = upscale_7_to_32bit(buf[2]); + break; + } + break; + case UMP_MSG_STATUS_PROGRAM: + midi2->pg.program = buf[1]; + if (cc->bank_set) { + midi2->pg.bank_valid = 1; + midi2->pg.bank_msb = cc->cc_bank_msb; + midi2->pg.bank_lsb = cc->cc_bank_lsb; + cc->bank_set = 0; + cc->cc_bank_msb = cc->cc_bank_lsb = 0; + } + break; + case UMP_MSG_STATUS_CHANNEL_PRESSURE: + midi2->caf.data = upscale_7_to_32bit(buf[1]); + break; + case UMP_MSG_STATUS_PITCH_BEND: + midi2->pb.data = upscale_14_to_32bit(buf[1] | (buf[2] << 7)); + break; + default: + return 0; + } + + return 8; +} + +static int do_convert_to_ump(struct snd_ump_endpoint *ump, + unsigned char group, unsigned char c, u32 *data) +{ + /* bytes for 0x80-0xf0 */ + static unsigned char cmd_bytes[8] = { + 3, 3, 3, 3, 2, 2, 3, 0 + }; + /* bytes for 0xf0-0xff */ + static unsigned char system_bytes[16] = { + 0, 2, 3, 2, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1 + }; + struct ump_cvt_to_ump *cvt = &ump->out_cvts[group]; + unsigned char bytes; + + if (c == UMP_MIDI1_MSG_SYSEX_START) { + cvt->in_sysex = 1; + cvt->len = 0; + return 0; + } + if (c == UMP_MIDI1_MSG_SYSEX_END) { + if (!cvt->in_sysex) + return 0; /* skip */ + return cvt_legacy_sysex_to_ump(cvt, group, data, true); + } + + if ((c & 0xf0) == UMP_MIDI1_MSG_REALTIME) { + bytes = system_bytes[c & 0x0f]; + if (!bytes) + return 0; /* skip */ + if (bytes == 1) { + data[0] = ump_compose(UMP_MSG_TYPE_SYSTEM, group, 0, c); + return 4; + } + cvt->buf[0] = c; + cvt->len = 1; + cvt->cmd_bytes = bytes; + cvt->in_sysex = 0; /* abort SysEx */ + return 0; + } + + if (c & 0x80) { + bytes = cmd_bytes[(c >> 8) & 7]; + cvt->buf[0] = c; + cvt->len = 1; + cvt->cmd_bytes = bytes; + cvt->in_sysex = 0; /* abort SysEx */ + return 0; + } + + if (cvt->in_sysex) { + cvt->buf[cvt->len++] = c; + if (cvt->len == 6) + return cvt_legacy_sysex_to_ump(cvt, group, data, false); + return 0; + } + + if (!cvt->len) + return 0; + + cvt->buf[cvt->len++] = c; + if (cvt->len < cvt->cmd_bytes) + return 0; + cvt->len = 1; + if ((cvt->buf[0] & 0xf0) == UMP_MIDI1_MSG_REALTIME) + return cvt_legacy_system_to_ump(cvt, group, data); + return cvt_legacy_cmd_to_ump(ump, cvt, group, data, cvt->cmd_bytes); +} + +/* feed a MIDI 1.0 byte @c and convert to a UMP packet; + * the target group is @group, + * the result is stored in out_cvts[group].ump[] and out_cvts[group].ump_bytes + */ +void snd_ump_convert_to_ump(struct snd_ump_endpoint *ump, + unsigned char group, unsigned char c) +{ + struct ump_cvt_to_ump *cvt = &ump->out_cvts[group]; + + cvt->ump_bytes = do_convert_to_ump(ump, group, c, cvt->ump); +} + +/* reset the converter context, called at each open */ +void snd_ump_reset_convert_to_ump(struct snd_ump_endpoint *ump, + unsigned char group) +{ + memset(&ump->out_cvts[group], 0, sizeof(*ump->out_cvts)); +} + +/* initialize converters */ +int snd_ump_convert_init(struct snd_ump_endpoint *ump) +{ + ump->out_cvts = kcalloc(16, sizeof(*ump->out_cvts), GFP_KERNEL); + if (!ump->out_cvts) + return -ENOMEM; + return 0; +} + +/* release resources */ +void snd_ump_convert_free(struct snd_ump_endpoint *ump) +{ + kfree(ump->out_cvts); + ump->out_cvts = NULL; +} diff --git a/sound/core/ump_convert.h b/sound/core/ump_convert.h new file mode 100644 index 000000000000..bbfe96084779 --- /dev/null +++ b/sound/core/ump_convert.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef __UMP_CONVERT_H +#define __UMP_CONVERT_H + +#include + +/* context for converting from legacy control messages to UMP packet */ +struct ump_cvt_to_ump_bank { + bool rpn_set; + bool nrpn_set; + bool bank_set; + unsigned char cc_rpn_msb, cc_rpn_lsb; + unsigned char cc_nrpn_msb, cc_nrpn_lsb; + unsigned char cc_data_msb, cc_data_lsb; + unsigned char cc_bank_msb, cc_bank_lsb; +}; + +/* context for converting from MIDI1 byte stream to UMP packet */ +struct ump_cvt_to_ump { + /* MIDI1 intermediate buffer */ + unsigned char buf[4]; + int len; + int cmd_bytes; + + /* UMP output packet */ + u32 ump[4]; + int ump_bytes; + + /* various status */ + unsigned int in_sysex; + struct ump_cvt_to_ump_bank bank[16]; /* per channel */ +}; + +int snd_ump_convert_init(struct snd_ump_endpoint *ump); +void snd_ump_convert_free(struct snd_ump_endpoint *ump); +int snd_ump_convert_from_ump(struct snd_ump_endpoint *ump, + const u32 *data, unsigned char *dst, + unsigned char *group_ret); +void snd_ump_convert_to_ump(struct snd_ump_endpoint *ump, + unsigned char group, unsigned char c); +void snd_ump_reset_convert_to_ump(struct snd_ump_endpoint *ump, + unsigned char group); +#endif /* __UMP_CONVERT_H */ From patchwork Tue May 23 07:53:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251784 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 74F1FC7EE2A for ; Tue, 23 May 2023 07:58:37 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 6B7C984A; Tue, 23 May 2023 09:57:45 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 6B7C984A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828715; bh=qX4dAtCEBrxHAyjjAuyQHzKaAJY9+vmAXF2peejKq54=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=PLDHEG+KHAR1FdDW6I38ZAAYODK5lN+QWjrKryFuNzNA5ADndpJQRbG6n8dmzmFbm OxRlX8dlz2O2n4wbj2i443MkL9hRKcHz39wIZUQ/vnvglBiFQ0l5zGVcNJzmA6kRsX h1YIZivexBoE4eBqMIIHiFW9C5l1uLYzfgdY/YI8= Received: by alsa1.perex.cz (Postfix, from userid 50401) id CD856F80619; Tue, 23 May 2023 09:54:58 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 12CDDF80619; Tue, 23 May 2023 09:54:58 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 9B1D0F805FA; Tue, 23 May 2023 09:54:49 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id AF931F80558 for ; Tue, 23 May 2023 09:54:07 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz AF931F80558 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=spLCdVUS; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=cvLknQse Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 68B942040D; Tue, 23 May 2023 07:54:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828447; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TygGfmhyxHyXtO48ucZvDwYqdaCkFLRB2qITd7bHM2E=; b=spLCdVUSBOL1ydTQEo23AMV6VgxobeyHa2dCzCjAVgnS8XxN9lVMXGkNGIc7hxQvE8XguZ eseQ4BEd/mqqoyyem53sqj3iyE+eIuBl5flVzN75+V09d8BR8Tl1lGXiuFYBSxvvR9moBA UIKXMpCDPnrPd4AC/ZC5ke5j4yF8/8A= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828447; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TygGfmhyxHyXtO48ucZvDwYqdaCkFLRB2qITd7bHM2E=; b=cvLknQse9tQL16PGNajENYNTBkDL3gHpSCpwsYdEDQsOyn/nArxG+eEgWiwpbWjsO/vHhq HJXZ5lBOfsIWERBw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 2944B13A1A; Tue, 23 May 2023 07:54:07 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id SCYhBx9xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:07 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 15/37] ALSA: usb-audio: Enable the legacy raw MIDI support Date: Tue, 23 May 2023 09:53:36 +0200 Message-Id: <20230523075358.9672-16-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: 42BZLDNDND3DBZ3OHZNV6OP5DJYCVGCX X-Message-ID-Hash: 42BZLDNDND3DBZ3OHZNV6OP5DJYCVGCX X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Attach the legacy rawmidi devices when enabled in Kconfig accordingly. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/midi2.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 7e849b2384ee..f3fba8b07cb3 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -857,6 +857,25 @@ static int create_blocks_from_gtb(struct snd_usb_midi2_interface *umidi) return 0; } +/* attach legacy rawmidis */ +static int attach_legacy_rawmidi(struct snd_usb_midi2_interface *umidi) +{ +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) + struct snd_usb_midi2_ump *rmidi; + int err; + + list_for_each_entry(rmidi, &umidi->rawmidi_list, list) { + err = snd_ump_attach_legacy_rawmidi(rmidi->ump, + "Legacy MIDI", + umidi->chip->num_rawmidis); + if (err < 0) + return err; + umidi->chip->num_rawmidis++; + } +#endif + return 0; +} + static void snd_usb_midi_v2_free(struct snd_usb_midi2_interface *umidi) { free_all_midi2_endpoints(umidi); @@ -922,7 +941,7 @@ static int parse_midi_2_0(struct snd_usb_midi2_interface *umidi) } } - return 0; + return attach_legacy_rawmidi(umidi); } /* is the given interface for MIDI 2.0? */ @@ -991,6 +1010,12 @@ static void set_fallback_rawmidi_names(struct snd_usb_midi2_interface *umidi) usb_string(dev, dev->descriptor.iSerialNumber, ump->info.product_id, sizeof(ump->info.product_id)); +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) + if (ump->legacy_rmidi && !*ump->legacy_rmidi->name) + snprintf(ump->legacy_rmidi->name, + sizeof(ump->legacy_rmidi->name), + "%s (MIDI 1.0)", ump->info.name); +#endif } } From patchwork Tue May 23 07:53:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251786 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BDFD5C7EE23 for ; Tue, 23 May 2023 07:59:09 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 83AAEA4D; Tue, 23 May 2023 09:58:17 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 83AAEA4D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828747; bh=HycIzlhBmKg2OrIiBtsrD93dBY3/VKEMnjylPoxL0DQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=WBlekubUPXovYCZkMAhhIVdjRY849TpeAkJWgsRF43whYAgr77FtsEzdOc6m727Nd EviGANQwpYxWXRTZDtkIZgKPT/5zZUrI3XWrDJdth2DROdmlW5jHlzplB4x6WnBPo8 o2Bmv/QhS78LH+mttNYs/DLQp0pjk5kR88g7E2QI= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 17064F8063A; Tue, 23 May 2023 09:55:08 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id E6A8DF80636; Tue, 23 May 2023 09:55:07 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 4A886F80624; Tue, 23 May 2023 09:54:59 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E1C16F8055B for ; Tue, 23 May 2023 09:54:07 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E1C16F8055B Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=XH6OPh1/; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=hqpuVHha Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id BD4132040E; Tue, 23 May 2023 07:54:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828447; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3QYHzLsbn2lpr2akas3+UD3Ro0HbP/pTE0k8rJDQSZY=; b=XH6OPh1/8l601VL4QEe9KcM0UukyxU8GDgO8ThQPl9l/VilscRZCNqZtCl5sZVSV9yvpev lFGBxz9QlfOLqCGN2SEYRSWSI/w5Bry1lyJQBm7TAoZDC0queV2v7mna8MzEOk/SB04Vw5 idfb09diPpFISDmZNjhoD6w1EMv+QgE= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828447; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3QYHzLsbn2lpr2akas3+UD3Ro0HbP/pTE0k8rJDQSZY=; b=hqpuVHhamcbJEVopAg9z6Ffv5KticZFXHt8jsEawbZd9xTx2G4BPAAH33fQONl3T/1fBzI krjrybFsK5rWe2AQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 66D0013588; Tue, 23 May 2023 07:54:07 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id aAlBFh9xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:07 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 16/37] ALSA: usb-audio: Inform inconsistent protocols in GTBs Date: Tue, 23 May 2023 09:53:37 +0200 Message-Id: <20230523075358.9672-17-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: HMOSEXJD626OOCMPT5EIHGORRG4AHFV2 X-Message-ID-Hash: HMOSEXJD626OOCMPT5EIHGORRG4AHFV2 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: When parsing Group Terminal Blocks, we overwrote the preferred protocol and the protocol capabilities silently from the last parsed GTB. This patch adds the information print indicating the unexpected overrides instead of silent action. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/midi2.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index f3fba8b07cb3..341783418a6a 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -581,6 +581,7 @@ static int parse_group_terminal_block(struct snd_usb_midi2_ump *rmidi, const struct usb_ms20_gr_trm_block_descriptor *desc) { struct snd_ump_endpoint *ump = rmidi->ump; + unsigned int protocol, protocol_caps; /* set default protocol */ switch (desc->bMIDIProtocol) { @@ -588,24 +589,40 @@ static int parse_group_terminal_block(struct snd_usb_midi2_ump *rmidi, case USB_MS_MIDI_PROTO_1_0_64_JRTS: case USB_MS_MIDI_PROTO_1_0_128: case USB_MS_MIDI_PROTO_1_0_128_JRTS: - ump->info.protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1; + protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1; break; case USB_MS_MIDI_PROTO_2_0: case USB_MS_MIDI_PROTO_2_0_JRTS: - ump->info.protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI2; + protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI2; break; + default: + return 0; } - ump->info.protocol_caps = ump->info.protocol; + if (ump->info.protocol && ump->info.protocol != protocol) + usb_audio_info(rmidi->umidi->chip, + "Overriding preferred MIDI protocol in GTB %d: %x -> %x\n", + rmidi->usb_block_id, ump->info.protocol, + protocol); + ump->info.protocol = protocol; + + protocol_caps = protocol; switch (desc->bMIDIProtocol) { case USB_MS_MIDI_PROTO_1_0_64_JRTS: case USB_MS_MIDI_PROTO_1_0_128_JRTS: case USB_MS_MIDI_PROTO_2_0_JRTS: - ump->info.protocol_caps |= SNDRV_UMP_EP_INFO_PROTO_JRTS_TX | + protocol_caps |= SNDRV_UMP_EP_INFO_PROTO_JRTS_TX | SNDRV_UMP_EP_INFO_PROTO_JRTS_RX; break; } + if (ump->info.protocol_caps && ump->info.protocol_caps != protocol_caps) + usb_audio_info(rmidi->umidi->chip, + "Overriding MIDI protocol caps in GTB %d: %x -> %x\n", + rmidi->usb_block_id, ump->info.protocol_caps, + protocol_caps); + ump->info.protocol_caps = protocol_caps; + return 0; } From patchwork Tue May 23 07:53:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251793 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0C309C7EE26 for ; Tue, 23 May 2023 08:00:08 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 784241FA; Tue, 23 May 2023 09:59:15 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 784241FA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828805; bh=/isZxYJgiOzeSf+rd79ZDm8TuIe8OqP83lENtH6WgWo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=sLvGIG2/rrr/Zbdxg2DkOqK6ETbGNtCwpENW4CxwzE08l6822WAqYo4jUV2MBtGDv amUyWsbY2FWm1wV301YpuiILyEa/AwV452PBLnT8hnhQw5MPXxICeiB9KMmf4p61wd DVxMmh1CwDUA8E52F6M85GmKKlqASQHPNM0HGJZg= Received: by alsa1.perex.cz (Postfix, from userid 50401) id D4E55F80425; Tue, 23 May 2023 09:55:17 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 02ED6F80673; Tue, 23 May 2023 09:55:17 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5B7EDF8061A; Tue, 23 May 2023 09:55:03 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id A4945F80563 for ; Tue, 23 May 2023 09:54:08 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz A4945F80563 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=MxFbxoWd; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=QLtWeTZE Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id F30D021976; Tue, 23 May 2023 07:54:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uMzBP59J7x7TxGFaxuEDckjn0BZosp/WXU2Nz5BQgbk=; b=MxFbxoWdt43CnWdWmOn3iq6Bc3CSpCRFqENLliyU0THhGtYaOK8XYj+J5LjqHUUe/ChdSl KUUH2pIBQYaMRwo26/j3MBL7ODQIZnSqVCzteVe6vaXTE0tlFPcNzPIWuqgojhgPPgB2jY TDyP8ld4FFcxud1cV1BpznNXMZODPsw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uMzBP59J7x7TxGFaxuEDckjn0BZosp/WXU2Nz5BQgbk=; b=QLtWeTZE8e4awLgLDbzJ8+2XjVLrtRiXEdyEnSMUpcDqXTUTMjCS7X73C1oRFh51qPstpZ ttNfnL/Y//C0hZDg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id B2F2613A1A; Tue, 23 May 2023 07:54:07 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 8AyuJx9xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:07 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 17/37] ALSA: seq: Clear padded bytes at expanding events Date: Tue, 23 May 2023 09:53:38 +0200 Message-Id: <20230523075358.9672-18-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: XKMDTEP5VEV3QMX3QMP2SYLEIRSFAQQK X-Message-ID-Hash: XKMDTEP5VEV3QMX3QMP2SYLEIRSFAQQK X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: <> List-Archive: <> List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: There can be a small memory hole that may not be cleared at expanding an event with the variable length type. Make sure to clear it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/seq_memory.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 47ef6bc30c0e..c8d26bce69ff 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -152,12 +152,16 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char return -EINVAL; if (copy_from_user(buf, (void __force __user *)event->data.ext.ptr, len)) return -EFAULT; - return newlen; + } else { + err = snd_seq_dump_var_event(event, + in_kernel ? seq_copy_in_kernel : seq_copy_in_user, + &buf); + if (err < 0) + return err; } - err = snd_seq_dump_var_event(event, - in_kernel ? seq_copy_in_kernel : seq_copy_in_user, - &buf); - return err < 0 ? err : newlen; + if (len != newlen) + memset(buf + len, 0, newlen - len); + return newlen; } EXPORT_SYMBOL(snd_seq_expand_var_event); From patchwork Tue May 23 07:53:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251787 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E3873C7EE26 for ; Tue, 23 May 2023 07:59:38 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 0EF95825; Tue, 23 May 2023 09:58:47 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 0EF95825 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828777; bh=Q7XChJ81USTG6I1MONPEPJD6E97CLOOIs2e4XH0YjnA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=aZ4+CDwvhsFjxJ20h9WhVEh33Avv9Chd53WA0aLw3Tz2zj7ntGG7EROIp8pvtonj8 0NONyCc8Agc1MpFQ8PsEyu/xA4F+20tyilVdjxEmCbj3xoVMZ0CUOgSr9JVWQytIbZ 8++iNF0in6KacFgWFtYvTGnCUPmPOQdxhBbw+ut8= Received: by alsa1.perex.cz (Postfix, from userid 50401) id C8908F80642; Tue, 23 May 2023 09:55:10 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 0B75FF8063D; Tue, 23 May 2023 09:55:10 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 1FD72F80624; Tue, 23 May 2023 09:55:00 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 8B699F8055C for ; Tue, 23 May 2023 09:54:08 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 8B699F8055C Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=z3Y44aRl; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=21+OBiQx Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 39B9D2040F; Tue, 23 May 2023 07:54:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=y2o6vAzyvCPRZAh3qVpJkQiDsJRDhW9KZ1VjQNePS50=; b=z3Y44aRlV4mYA4B7ea1B/gUOtaUvgKz7qtVU4lAp3KohD1iA1jBhm9xsrWolAX2xjX/pTc kDvn69jdbchOjqEFrHAXvBTYWU+Q+UOtbHiPWAr+2tjxs6x0tKgeQkAXu1RjkK73MFCKJO TZjpcZoW5L+oILANixNkv6IdnJ3MIYQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=y2o6vAzyvCPRZAh3qVpJkQiDsJRDhW9KZ1VjQNePS50=; b=21+OBiQxTDs5Qa3HfTXcDDS8/Il/54WP7Gav2H8dItEnAv4/bMOJlSe/te9NxwOYz70ZMZ JlFuQtVvXRj3aLDQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 03AD913588; Tue, 23 May 2023 07:54:07 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id AJQmOx9xbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:07 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 18/37] ALSA: seq: Add snd_seq_expand_var_event_at() helper Date: Tue, 23 May 2023 09:53:39 +0200 Message-Id: <20230523075358.9672-19-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: K4OWB37FNPKRUWG6BJO5DWSB3BPT5N4Y X-Message-ID-Hash: K4OWB37FNPKRUWG6BJO5DWSB3BPT5N4Y X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Create a new variant of snd_seq_expand_var_event() for expanding the data starting from the given byte offset. It'll be used by the new UMP sequencer code later. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/seq_kernel.h | 2 + sound/core/seq/seq_memory.c | 86 +++++++++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 19 deletions(-) diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h index 658911926f3a..527e7f8ad661 100644 --- a/include/sound/seq_kernel.h +++ b/include/sound/seq_kernel.h @@ -70,6 +70,8 @@ int snd_seq_kernel_client_ctl(int client, unsigned int cmd, void *arg); typedef int (*snd_seq_dump_func_t)(void *ptr, void *buf, int count); int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char *buf, int in_kernel, int size_aligned); +int snd_seq_expand_var_event_at(const struct snd_seq_event *event, int count, + char *buf, int offset); int snd_seq_dump_var_event(const struct snd_seq_event *event, snd_seq_dump_func_t func, void *private_data); diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index c8d26bce69ff..a8d2db439f86 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -63,8 +63,9 @@ static int get_var_len(const struct snd_seq_event *event) return event->data.ext.len & ~SNDRV_SEQ_EXT_MASK; } -int snd_seq_dump_var_event(const struct snd_seq_event *event, - snd_seq_dump_func_t func, void *private_data) +static int dump_var_event(const struct snd_seq_event *event, + snd_seq_dump_func_t func, void *private_data, + int offset, int maxlen) { int len, err; struct snd_seq_event_cell *cell; @@ -72,10 +73,16 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, len = get_var_len(event); if (len <= 0) return len; + if (len <= offset) + return 0; + if (maxlen && len > offset + maxlen) + len = offset + maxlen; if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { char buf[32]; char __user *curptr = (char __force __user *)event->data.ext.ptr; + curptr += offset; + len -= offset; while (len > 0) { int size = sizeof(buf); if (len < size) @@ -91,20 +98,35 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, return 0; } if (!(event->data.ext.len & SNDRV_SEQ_EXT_CHAINED)) - return func(private_data, event->data.ext.ptr, len); + return func(private_data, event->data.ext.ptr + offset, + len - offset); cell = (struct snd_seq_event_cell *)event->data.ext.ptr; for (; len > 0 && cell; cell = cell->next) { int size = sizeof(struct snd_seq_event); + char *curptr = (char *)&cell->event; + + if (offset >= size) { + offset -= size; + len -= size; + continue; + } if (len < size) size = len; - err = func(private_data, &cell->event, size); + err = func(private_data, curptr + offset, size - offset); if (err < 0) return err; + offset = 0; len -= size; } return 0; } + +int snd_seq_dump_var_event(const struct snd_seq_event *event, + snd_seq_dump_func_t func, void *private_data) +{ + return dump_var_event(event, func, private_data, 0, 0); +} EXPORT_SYMBOL(snd_seq_dump_var_event); @@ -132,11 +154,27 @@ static int seq_copy_in_user(void *ptr, void *src, int size) return 0; } +static int expand_var_event(const struct snd_seq_event *event, + int offset, int size, char *buf, bool in_kernel) +{ + if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { + if (! in_kernel) + return -EINVAL; + if (copy_from_user(buf, + (char __force __user *)event->data.ext.ptr + offset, + size)) + return -EFAULT; + return 0; + } + return dump_var_event(event, + in_kernel ? seq_copy_in_kernel : seq_copy_in_user, + &buf, offset, size); +} + int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char *buf, int in_kernel, int size_aligned) { - int len, newlen; - int err; + int len, newlen, err; len = get_var_len(event); if (len < 0) @@ -146,25 +184,35 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char newlen = roundup(len, size_aligned); if (count < newlen) return -EAGAIN; - - if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { - if (! in_kernel) - return -EINVAL; - if (copy_from_user(buf, (void __force __user *)event->data.ext.ptr, len)) - return -EFAULT; - } else { - err = snd_seq_dump_var_event(event, - in_kernel ? seq_copy_in_kernel : seq_copy_in_user, - &buf); - if (err < 0) - return err; - } + err = expand_var_event(event, 0, len, buf, in_kernel); + if (err < 0) + return err; if (len != newlen) memset(buf + len, 0, newlen - len); return newlen; } EXPORT_SYMBOL(snd_seq_expand_var_event); +int snd_seq_expand_var_event_at(const struct snd_seq_event *event, int count, + char *buf, int offset) +{ + int len, err; + + len = get_var_len(event); + if (len < 0) + return len; + if (len <= offset) + return 0; + len -= offset; + if (len > count) + len = count; + err = expand_var_event(event, offset, count, buf, true); + if (err < 0) + return err; + return len; +} +EXPORT_SYMBOL_GPL(snd_seq_expand_var_event_at); + /* * release this cell, free extended data if available */ From patchwork Tue May 23 07:53:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251814 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F41FFC7EE26 for ; Tue, 23 May 2023 08:04:49 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 100F4E81; Tue, 23 May 2023 10:03:58 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 100F4E81 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829088; bh=V0sTbQ+jSq37f7KzbXAB+1HEEJMn6bDuwzQ038JWlgs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=C8TnpEO0UIoaYTtaV/IwJ0eG5AoEjSAZ7Ep9EnfrbATaMHVr8OrRbVrOFiPUckyuj JrBhd/9ft4syHFAmAUq8P8Il5AU0cLoLyzRJZnBISuBxxKS1cEoRE9AJJbONR8kni0 oropS/ZrkgXHYjgmGnLuQ4zjo4fKuD+vXFpuQOEQ= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 84680F8070C; Tue, 23 May 2023 09:56:24 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 194B4F80707; Tue, 23 May 2023 09:56:24 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 22E8CF805AC; Tue, 23 May 2023 09:56:00 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id A49A5F80564 for ; Tue, 23 May 2023 09:54:08 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz A49A5F80564 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=HkjeYC0Q; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=XpHHji8S Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 7CD8720410; Tue, 23 May 2023 07:54:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l4DZ5woY6gmacraFwH4PrBR7nOGakjNJMIBScTlvDFE=; b=HkjeYC0QuYOlGB79i3zWQ/9nWZoV0V00HmPoZjX8OD3mqJf/3zUTw9Eb//H552FIYpcm9x R9FfayH9I+Xn4sSfIE6He1cX/yhBeKa/6S8syoOB8VSzThoY1S86tUrGg7Yfora7TmCj6O K08n5j33ogHA3gs0vajGR/5etm9bJEQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l4DZ5woY6gmacraFwH4PrBR7nOGakjNJMIBScTlvDFE=; b=XpHHji8S3+L9y7x/IwkdgDVaipr1QtJ8kmLMfx6sxcg2inXZ1uZQA0V1yFFRsC+ChRksAm v6YIzmrwfWxOM0DQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 4291D13A1A; Tue, 23 May 2023 07:54:08 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id wN89DiBxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:08 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 19/37] ALSA: seq: Treat snd_seq_client object directly in client drivers Date: Tue, 23 May 2023 09:53:40 +0200 Message-Id: <20230523075358.9672-20-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: DN5ENKMBCT6AE63MHBDE37VSNIXK2ZF3 X-Message-ID-Hash: DN5ENKMBCT6AE63MHBDE37VSNIXK2ZF3 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Introduce the new helpers, snd_seq_kernel_client_get() and _put() for kernel client drivers to treat the snd_seq_client more directly. This allows us to reduce the exported symbols and APIs at each time we need to access some field in future. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 15 +++++++++++++++ sound/core/seq/seq_clientmgr.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 2d707afa1ef1..98e8032a32e2 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2390,6 +2390,21 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table } EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); +/* get a sequencer client object; for internal use from a kernel client */ +struct snd_seq_client *snd_seq_kernel_client_get(int id) +{ + return snd_seq_client_use_ptr(id); +} +EXPORT_SYMBOL_GPL(snd_seq_kernel_client_get); + +/* put a sequencer client object; for internal use from a kernel client */ +void snd_seq_kernel_client_put(struct snd_seq_client *cptr) +{ + if (cptr) + snd_seq_client_unlock(cptr); +} +EXPORT_SYMBOL_GPL(snd_seq_kernel_client_put); + /*---------------------------------------------------------------------------*/ #ifdef CONFIG_SND_PROC_FS diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index 8cdd0ee53fb1..f05704e45ab4 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -88,4 +88,8 @@ void snd_seq_client_ioctl_unlock(int clientid); extern int seq_client_load[15]; +/* for internal use between kernel sequencer clients */ +struct snd_seq_client *snd_seq_kernel_client_get(int client); +void snd_seq_kernel_client_put(struct snd_seq_client *cptr); + #endif From patchwork Tue May 23 07:53:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251794 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8D9ABC7EE23 for ; Tue, 23 May 2023 08:00:19 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 50F8B206; Tue, 23 May 2023 09:59:27 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 50F8B206 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828817; bh=yBsVux825mRojnBmf7SlCALNmsxCmgJfQPi1hDtPuSM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=qC/IMbfdOn5Il+JpBcULk3zmiHY9J1qdLumRxTm4qLJcnvTrN9XTGWCx8GUN3Rr1z UTiWeFTLjJxtmo+QLIWyTI2rvTEyxMNXA/24zGWexxw8X9cOlqD8ExyqjBOVC/jLSO fM79VETY8Y57wGSzZpFGqTJXXSu+Ccje81eswGSI= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 41573F80679; Tue, 23 May 2023 09:55:21 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id E681CF80674; Tue, 23 May 2023 09:55:19 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id E7238F80638; Tue, 23 May 2023 09:55:07 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id EC610F8055A for ; Tue, 23 May 2023 09:54:08 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz EC610F8055A Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=EUqXzLC0; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=aUmxVBbe Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id BB467219EE; Tue, 23 May 2023 07:54:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=duuZwN1C9IUQLQQEAFsw/JZ4JxAL3kzU5sIEEpm2/Z8=; b=EUqXzLC0QgGY2mNYInw54Hs0O9Ti2wyrYx1zPwp5ZJnHqF7bq+RQGr7r0NWYKth1JsXRlD Wmtn2Z/18DlKT50ZVuq0ujLJUSnIhKh/49QV6wy0BDW3yFy9hM6ny2TUPXp9H5VszRR15o jDSAAdpo2ZeNse13KJMYTKQLbcpIVnM= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=duuZwN1C9IUQLQQEAFsw/JZ4JxAL3kzU5sIEEpm2/Z8=; b=aUmxVBbexQ+QEfvys+3GiVCD2BcAxLFBuvh/IvWCESBt9h97lPmuHSZGjM9gPOTWbmhYsD Pyh6xWc+EdLd5QAA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 7FF0913588; Tue, 23 May 2023 07:54:08 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 6AueHSBxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:08 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 20/37] ALSA: seq: Drop dead code for the old broadcast support Date: Tue, 23 May 2023 09:53:41 +0200 Message-Id: <20230523075358.9672-21-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: OUYQEZ5IR7L6EWADBTTJFO6X2ID66E57 X-Message-ID-Hash: OUYQEZ5IR7L6EWADBTTJFO6X2ID66E57 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The broadcast and multicast supports have been never enabled. Let's drop the dead code. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 105 +-------------------------------- 1 file changed, 1 insertion(+), 104 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 98e8032a32e2..019af1343325 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -711,93 +711,6 @@ static int deliver_to_subscribers(struct snd_seq_client *client, return (result < 0) ? result : num_ev; } - -#ifdef SUPPORT_BROADCAST -/* - * broadcast to all ports: - */ -static int port_broadcast_event(struct snd_seq_client *client, - struct snd_seq_event *event, - int atomic, int hop) -{ - int num_ev = 0, err, result = 0; - struct snd_seq_client *dest_client; - struct snd_seq_client_port *port; - - dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST); - if (dest_client == NULL) - return 0; /* no matching destination */ - - read_lock(&dest_client->ports_lock); - list_for_each_entry(port, &dest_client->ports_list_head, list) { - event->dest.port = port->addr.port; - /* pass NULL as source client to avoid error bounce */ - err = snd_seq_deliver_single_event(NULL, event, - SNDRV_SEQ_FILTER_BROADCAST, - atomic, hop); - if (err < 0) { - /* save first error that occurs and continue */ - if (!result) - result = err; - continue; - } - num_ev++; - } - read_unlock(&dest_client->ports_lock); - snd_seq_client_unlock(dest_client); - event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */ - return (result < 0) ? result : num_ev; -} - -/* - * send the event to all clients: - * if destination port is also ADDRESS_BROADCAST, deliver to all ports. - */ -static int broadcast_event(struct snd_seq_client *client, - struct snd_seq_event *event, int atomic, int hop) -{ - int err, result = 0, num_ev = 0; - int dest; - struct snd_seq_addr addr; - - addr = event->dest; /* save */ - - for (dest = 0; dest < SNDRV_SEQ_MAX_CLIENTS; dest++) { - /* don't send to itself */ - if (dest == client->number) - continue; - event->dest.client = dest; - event->dest.port = addr.port; - if (addr.port == SNDRV_SEQ_ADDRESS_BROADCAST) - err = port_broadcast_event(client, event, atomic, hop); - else - /* pass NULL as source client to avoid error bounce */ - err = snd_seq_deliver_single_event(NULL, event, - SNDRV_SEQ_FILTER_BROADCAST, - atomic, hop); - if (err < 0) { - /* save first error that occurs and continue */ - if (!result) - result = err; - continue; - } - num_ev += err; - } - event->dest = addr; /* restore */ - return (result < 0) ? result : num_ev; -} - - -/* multicast - not supported yet */ -static int multicast_event(struct snd_seq_client *client, struct snd_seq_event *event, - int atomic, int hop) -{ - pr_debug("ALSA: seq: multicast not supported yet.\n"); - return 0; /* ignored */ -} -#endif /* SUPPORT_BROADCAST */ - - /* deliver an event to the destination port(s). * if the event is to subscribers or broadcast, the event is dispatched * to multiple targets. @@ -826,15 +739,6 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS || event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) result = deliver_to_subscribers(client, event, atomic, hop); -#ifdef SUPPORT_BROADCAST - else if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST || - event->dest.client == SNDRV_SEQ_ADDRESS_BROADCAST) - result = broadcast_event(client, event, atomic, hop); - else if (event->dest.client >= SNDRV_SEQ_MAX_CLIENTS) - result = multicast_event(client, event, atomic, hop); - else if (event->dest.port == SNDRV_SEQ_ADDRESS_BROADCAST) - result = port_broadcast_event(client, event, atomic, hop); -#endif else result = snd_seq_deliver_single_event(client, event, 0, atomic, hop); @@ -936,14 +840,7 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) { event->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; event->queue = SNDRV_SEQ_QUEUE_DIRECT; - } else -#ifdef SUPPORT_BROADCAST - if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST) { - event->dest.client = SNDRV_SEQ_ADDRESS_BROADCAST; - event->queue = SNDRV_SEQ_QUEUE_DIRECT; - } -#endif - if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) { + } else if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) { /* check presence of source port */ struct snd_seq_client_port *src_port = snd_seq_port_use_ptr(client, event->source.port); if (src_port == NULL) From patchwork Tue May 23 07:53:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251788 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id ACED3C7EE23 for ; Tue, 23 May 2023 07:59:40 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id B82D4DF1; Tue, 23 May 2023 09:58:48 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz B82D4DF1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828778; bh=Vccg4FlsvwiYMPUY9WGb897bHE4fbIFzcKzHSZr7So4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=Xe25Zi1Ox0XiOZgE28kyB6sONilANsNfMkrbA+dSlfW5gfJXVvskPC3Hbenv65Bxp iIsXQ4pJG7n0fih4XYhLEsEmztDULgceZ0ZWTExPswrkey+Hi0GqSVREZIFl9e4EkK KkTFPfBlKdrdDkhqg6Iy8FY4bBbT2j320XNb9aUQ= Received: by alsa1.perex.cz (Postfix, from userid 50401) id A29CCF805B2; Tue, 23 May 2023 09:55:14 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 50D87F80655; Tue, 23 May 2023 09:55:13 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id EF642F80621; Tue, 23 May 2023 09:55:02 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 31674F80568 for ; Tue, 23 May 2023 09:54:09 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 31674F80568 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=f3PzBo9j; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=CSSV1xs8 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id EF66420411; Tue, 23 May 2023 07:54:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pabiQ7OVJjJ/NOtnH4HgaI79pZvmZ7fW1qyAiIkjeV8=; b=f3PzBo9jbSqWA1p0sPMUOW0kAJmylGdpTbM800c+Cz14ois3OKX8hQiUPhjLLweMt11+jc mgGVeElw0dNkjRRYIr7ZJyP8SnBe1lTEe+ZdaBZssdRbrFMpjJwQDqEGKaEOSZVQSOqLBx 6b2HD87ZDjS/H/YeX19M0lRAWDRK8to= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828448; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pabiQ7OVJjJ/NOtnH4HgaI79pZvmZ7fW1qyAiIkjeV8=; b=CSSV1xs87aOdr6CNPqMpG5JvgKsjAItKVeNPn+f1v1sRYlewkG4YmunhnVgb7W67ep9ibd T3gOmRqJd8+jblDA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id B8B6413A1A; Tue, 23 May 2023 07:54:08 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id KEYNKiBxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:08 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 21/37] ALSA: seq: Check the conflicting port at port creation Date: Tue, 23 May 2023 09:53:42 +0200 Message-Id: <20230523075358.9672-22-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: 2RSIPXY7QLKTPGT67XQESGPES24P3AFU X-Message-ID-Hash: 2RSIPXY7QLKTPGT67XQESGPES24P3AFU X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: We didn't check if a port with the given port number has been already present at creating a new port. Check it and return -EBUSY properly if the port number conflicts. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 12 ++++++++---- sound/core/seq/seq_ports.c | 25 ++++++++++++++++--------- sound/core/seq/seq_ports.h | 5 +++-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 019af1343325..06743114cabf 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1194,15 +1194,19 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) struct snd_seq_port_info *info = arg; struct snd_seq_client_port *port; struct snd_seq_port_callback *callback; - int port_idx; + int port_idx, err; /* it is not allowed to create the port for an another client */ if (info->addr.client != client->number) return -EPERM; - port = snd_seq_create_port(client, (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info->addr.port : -1); - if (port == NULL) - return -ENOMEM; + if (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) + port_idx = info->addr.port; + else + port_idx = -1; + err = snd_seq_create_port(client, port_idx, &port); + if (err < 0) + return err; if (client->type == USER_CLIENT && info->kernel) { port_idx = port->addr.port; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 25fcf5a2c71c..500b1a5a9679 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -107,33 +107,34 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp) } -/* create a port, port number is returned (-1 on failure); +/* create a port, port number or a negative error code is returned * the caller needs to unref the port via snd_seq_port_unlock() appropriately */ -struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, - int port) +int snd_seq_create_port(struct snd_seq_client *client, int port, + struct snd_seq_client_port **port_ret) { struct snd_seq_client_port *new_port, *p; - int num = -1; + int num; + *port_ret = NULL; + /* sanity check */ if (snd_BUG_ON(!client)) - return NULL; + return -EINVAL; if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) { pr_warn("ALSA: seq: too many ports for client %d\n", client->number); - return NULL; + return -EINVAL; } /* create a new port */ new_port = kzalloc(sizeof(*new_port), GFP_KERNEL); if (!new_port) - return NULL; /* failure, out of memory */ + return -ENOMEM; /* failure, out of memory */ /* init port data */ new_port->addr.client = client->number; new_port->addr.port = -1; new_port->owner = THIS_MODULE; - sprintf(new_port->name, "port-%d", num); snd_use_lock_init(&new_port->use_lock); port_subs_info_init(&new_port->c_src); port_subs_info_init(&new_port->c_dest); @@ -143,6 +144,10 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, mutex_lock(&client->ports_mutex); write_lock_irq(&client->ports_lock); list_for_each_entry(p, &client->ports_list_head, list) { + if (p->addr.port == port) { + num = -EBUSY; + goto unlock; + } if (p->addr.port > num) break; if (port < 0) /* auto-probe mode */ @@ -153,10 +158,12 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, client->num_ports++; new_port->addr.port = num; /* store the port number in the port */ sprintf(new_port->name, "port-%d", num); + *port_ret = new_port; + unlock: write_unlock_irq(&client->ports_lock); mutex_unlock(&client->ports_mutex); - return new_port; + return num; } /* */ diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h index b1f2c4943174..44f0e9e96bbf 100644 --- a/sound/core/seq/seq_ports.h +++ b/sound/core/seq/seq_ports.h @@ -86,8 +86,9 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl /* unlock the port */ #define snd_seq_port_unlock(port) snd_use_lock_free(&(port)->use_lock) -/* create a port, port number is returned (-1 on failure) */ -struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port_index); +/* create a port, port number or a negative error code is returned */ +int snd_seq_create_port(struct snd_seq_client *client, int port_index, + struct snd_seq_client_port **port_ret); /* delete a port */ int snd_seq_delete_port(struct snd_seq_client *client, int port); From patchwork Tue May 23 07:53:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251796 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5C34FC7EE23 for ; Tue, 23 May 2023 08:00:59 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id B44F7E7A; Tue, 23 May 2023 10:00:06 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz B44F7E7A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828856; bh=JaUED+G155puuptz0gwi+7lH9b4tOqmNtl/tWfoSQ7A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=r91h53fR8180JFUAl9ndoyu7g5P4JbzKpSjLzm3dbV02YMrGfXS5hVIqsEhepoJqb QOtaHqYlND0DIqmDJjiEqqZ80AFC39qPkVi0Ss1n3zkd4fvVrT8USBCd95R32K97Px JiYhii0AzHwjs+sPgXZXAoLSjAsXwIQOzg3xmWBs= Received: by alsa1.perex.cz (Postfix, from userid 50401) id E374CF80687; Tue, 23 May 2023 09:55:27 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id D5DE1F80687; Tue, 23 May 2023 09:55:26 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5803FF80567; Tue, 23 May 2023 09:55:11 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 81070F80567 for ; Tue, 23 May 2023 09:54:09 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 81070F80567 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=mXRFpVPR; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=fbSDasF5 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 2F89E20412; Tue, 23 May 2023 07:54:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828449; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wjHzsw6r5GBiZYln6HcaZ/+TH4q9OK+QhfwKeMGSpWE=; b=mXRFpVPRbXHozl7d1VkD3iVHJmQDfzORkMV/xuSFRbCEGbENe7osSTvazlzCP1ZtAnwZoB 8tShtavyMOM5UdrZvJMTphi40/hkFq40UBXWw2Tj/t0zWRjBwX+AS8+23r7k2Y9D3KSMzM awQOg5RO/I966kYcNPck0faRTzG1fKo= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828449; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wjHzsw6r5GBiZYln6HcaZ/+TH4q9OK+QhfwKeMGSpWE=; b=fbSDasF5r7cHUc9ts/b0FjjsJCe/Typ/AGsvhMkrWS1mppHCQjO+NO6LRgZtDfbUgMwHXR xvebhLiQIytW8PDw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id EF11E13588; Tue, 23 May 2023 07:54:08 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id KG1oOSBxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:08 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 22/37] ALSA: seq: Check validity before creating a port object Date: Tue, 23 May 2023 09:53:43 +0200 Message-Id: <20230523075358.9672-23-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: BIGFCRPRID2PUIQGFTSYAROX2YBJJKXY X-Message-ID-Hash: BIGFCRPRID2PUIQGFTSYAROX2YBJJKXY X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The client type and the port info validity check should be done before actually creating a port, instead of unnecessary create-and-scratch. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 06743114cabf..2dac8c3355fd 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1199,6 +1199,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) /* it is not allowed to create the port for an another client */ if (info->addr.client != client->number) return -EPERM; + if (client->type == USER_CLIENT && info->kernel) + return -EINVAL; if (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) port_idx = info->addr.port; @@ -1208,12 +1210,6 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) if (err < 0) return err; - if (client->type == USER_CLIENT && info->kernel) { - port_idx = port->addr.port; - snd_seq_port_unlock(port); - snd_seq_delete_port(client, port_idx); - return -EINVAL; - } if (client->type == KERNEL_CLIENT) { callback = info->kernel; if (callback) { From patchwork Tue May 23 07:53:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251795 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5C554C7EE23 for ; Tue, 23 May 2023 08:00:40 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 55EE683A; Tue, 23 May 2023 09:59:48 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 55EE683A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828838; bh=cbsQtu9Tvyr05xCdatBybi/dBSSfkibUyGXPL+P4V3Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=PspcZYrJG44v2B2VWdUD1wpk20/FHep89vubRjHzOUP0VsfAmF3eIEAv+5E/WZUwQ WSVIwaKQexRx5eHkKmLjihaKEH9cLxsvwBHKhYKgZzrYVs8r3mcHS/sdfI/uLkuaUh FjvyHbHMJ1BTqq5IZ0SlubIiTyUrx6PlI0xHsqvM= Received: by alsa1.perex.cz (Postfix, from userid 50401) id B50C8F80678; Tue, 23 May 2023 09:55:24 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id F1471F80682; Tue, 23 May 2023 09:55:23 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id CC1D4F8063E; Tue, 23 May 2023 09:55:09 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 979FCF8056F for ; Tue, 23 May 2023 09:54:09 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 979FCF8056F Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=AA5gc7cz; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=163DO29d Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 71D79219FA; Tue, 23 May 2023 07:54:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828449; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=oMJMbFQgcCvHbmJa9OEy6qWd09vQvN9bjPxXemze1cA=; b=AA5gc7cz0DvWTCGBMgX9haf4b2gLcvLjK4uWNrBGUIM1NXDEcLl01m5PZLHVebQ2rpYMX9 ZFhzMFq4N/ZNMf0IIzQH1X4VEkFsIY65xh/nTspoK8/cuLJpNJ9vXZcg+tbHbaMQL6cU8v AmlghIcYjTq0nZ0Ak4Vt6L5z25npRmw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828449; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=oMJMbFQgcCvHbmJa9OEy6qWd09vQvN9bjPxXemze1cA=; b=163DO29dg01bIQwP/HiNTgA9Z4aTnAageXRIpoW8BX4Goze2FFZRLP7y8q/FzDbKSKPqoQ ECaKfmzQLGctV8CQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 2EC2A13A1A; Tue, 23 May 2023 07:54:09 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id oMt1CiFxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:09 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 23/37] ALSA: seq: Prohibit creating ports with special numbers Date: Tue, 23 May 2023 09:53:44 +0200 Message-Id: <20230523075358.9672-24-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: LY2VTIGPG7GD57AVMCZED4RN5QLV46XO X-Message-ID-Hash: LY2VTIGPG7GD57AVMCZED4RN5QLV46XO X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Some port numbers are special, such as 254 for subscribers and 255 for broadcast. Return error if application tries to create such a port. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 2dac8c3355fd..0f26f20596d7 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1206,6 +1206,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) port_idx = info->addr.port; else port_idx = -1; + if (port_idx >= SNDRV_SEQ_ADDRESS_UNKNOWN) + return -EINVAL; err = snd_seq_create_port(client, port_idx, &port); if (err < 0) return err; From patchwork Tue May 23 07:53:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251797 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2B5FAC7EE2D for ; Tue, 23 May 2023 08:01:12 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id B5BC2DEF; Tue, 23 May 2023 10:00:19 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz B5BC2DEF DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828869; bh=VutwHKkNUcgBrityYjS/Ev1MG5G+jCAv00K9rVoaHH8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=ILR5f2kNrqt6as91K+Sa2sdf/JdFm1Sf87RTwkeey55NAXvb3Oop356hzBMmj+v9K zQOPk/VWgbWAd2hMlZDTxSpUxKnNBMQ0+c0+YRxaG4z04lvt6Cek7l3gcvlnO9PneJ 3hvJjjUgvh0Rj+0QVp0f9sez1w2o0gmqjho92fek= Received: by alsa1.perex.cz (Postfix, from userid 50401) id DCF99F80690; Tue, 23 May 2023 09:55:32 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 7B4C9F80674; Tue, 23 May 2023 09:55:31 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 4F55BF80654; Tue, 23 May 2023 09:55:13 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id C9273F80571 for ; Tue, 23 May 2023 09:54:09 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz C9273F80571 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=sGnXeIWD; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=4Ut8mft+ Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id A1B3D20413; Tue, 23 May 2023 07:54:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828449; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OK0/8+s6e4TrHDufqC0z71Ik1XqkA7S/T2+8+IjWHaE=; b=sGnXeIWDoZR2Ox+RlzsYXib3Mi6YnhEf+BsZExQqtiT9CQIGLmD6ynu+yfqyUumKdg7x/8 ltuxZv2tilYwSJDDgk3ckfs0LDVNahpahSNc1mmZNFU7ZZ1LvRzq8XFFRDTMAK232NlzwZ sbBtNxBUGNynY+TGo29p7LZhyS40yKs= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828449; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OK0/8+s6e4TrHDufqC0z71Ik1XqkA7S/T2+8+IjWHaE=; b=4Ut8mft+HnygagJk3mCWYaUb0Zq5Eoz8w1S0Vs5IxXEvA2FjQvf0oR3tAYkdxDPdnVfUFo EjEsgge7LCb8t0BA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 6FB7213588; Tue, 23 May 2023 07:54:09 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id qOY5GSFxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:09 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 24/37] ALSA: seq: Introduce SNDRV_SEQ_IOCTL_USER_PVERSION ioctl Date: Tue, 23 May 2023 09:53:45 +0200 Message-Id: <20230523075358.9672-25-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: I7ZPM3WHIFOZELYIDJFSV6XY2DTVQH2H X-Message-ID-Hash: I7ZPM3WHIFOZELYIDJFSV6XY2DTVQH2H X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: <> List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: For the future extension of ALSA sequencer ABI, introduce a new ioctl SNDRV_SEQ_IOCTL_USER_PVERSION. This is similar like the ioctls used in PCM and other interfaces, for an application to specify its supporting ABI version. The use of this ioctl will be mandatory for the upcoming UMP support. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 1 + sound/core/seq/seq_clientmgr.c | 8 ++++++++ sound/core/seq/seq_clientmgr.h | 1 + sound/core/seq/seq_compat.c | 1 + 4 files changed, 11 insertions(+) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index 00d2703e8fca..4a3c5a718bae 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -561,6 +561,7 @@ struct snd_seq_query_subs { #define SNDRV_SEQ_IOCTL_CLIENT_ID _IOR ('S', 0x01, int) #define SNDRV_SEQ_IOCTL_SYSTEM_INFO _IOWR('S', 0x02, struct snd_seq_system_info) #define SNDRV_SEQ_IOCTL_RUNNING_MODE _IOWR('S', 0x03, struct snd_seq_running_info) +#define SNDRV_SEQ_IOCTL_USER_PVERSION _IOW('S', 0x04, int) #define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO _IOWR('S', 0x10, struct snd_seq_client_info) #define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO _IOW ('S', 0x11, struct snd_seq_client_info) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 0f26f20596d7..89a8d14df83b 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1056,6 +1056,12 @@ static int snd_seq_ioctl_pversion(struct snd_seq_client *client, void *arg) return 0; } +static int snd_seq_ioctl_user_pversion(struct snd_seq_client *client, void *arg) +{ + client->user_pversion = *(unsigned int *)arg; + return 0; +} + static int snd_seq_ioctl_client_id(struct snd_seq_client *client, void *arg) { int *client_id = arg; @@ -1985,6 +1991,7 @@ static const struct ioctl_handler { int (*func)(struct snd_seq_client *client, void *arg); } ioctl_handlers[] = { { SNDRV_SEQ_IOCTL_PVERSION, snd_seq_ioctl_pversion }, + { SNDRV_SEQ_IOCTL_USER_PVERSION, snd_seq_ioctl_user_pversion }, { SNDRV_SEQ_IOCTL_CLIENT_ID, snd_seq_ioctl_client_id }, { SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info }, { SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode }, @@ -2125,6 +2132,7 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index, client->accept_input = 1; client->accept_output = 1; client->data.kernel.card = card; + client->user_pversion = SNDRV_SEQ_VERSION; va_start(args, name_fmt); vsnprintf(client->name, sizeof(client->name), name_fmt, args); diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index f05704e45ab4..abe0ceadf3da 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -35,6 +35,7 @@ struct snd_seq_client { snd_seq_client_type_t type; unsigned int accept_input: 1, accept_output: 1; + unsigned int user_pversion; char name[64]; /* client name */ int number; /* client number */ unsigned int filter; /* filter flags */ diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c index 54723566ce24..c0ce6236dc7f 100644 --- a/sound/core/seq/seq_compat.c +++ b/sound/core/seq/seq_compat.c @@ -81,6 +81,7 @@ static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned l switch (cmd) { case SNDRV_SEQ_IOCTL_PVERSION: + case SNDRV_SEQ_IOCTL_USER_PVERSION: case SNDRV_SEQ_IOCTL_CLIENT_ID: case SNDRV_SEQ_IOCTL_SYSTEM_INFO: case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO: From patchwork Tue May 23 07:53:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251798 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C3F91C7EE23 for ; Tue, 23 May 2023 08:01:23 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A59C4E80; Tue, 23 May 2023 10:00:31 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A59C4E80 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828881; bh=ViG6QVI3xfrh+rlJAH0UOX3cpxAFMIippFJQWZe8Kzc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=OaRee3YdCCa7DPWS7frRN0sRgDEpsINFkiC+5l3UfurlkyF4fKD0H7cpfTmU1916l RJB5m+tIKwD7WGf4GOmkUELZjlMJ9Nr+avSENkeyKS08TCo6CB3kizsMVo9YxQnOl5 /ci2fIxVjVfj4y/vlY74syPF6Ip84HYkNqbUMXf8= Received: by alsa1.perex.cz (Postfix, from userid 50401) id A52E5F80698; Tue, 23 May 2023 09:55:35 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 78EC0F805AF; Tue, 23 May 2023 09:55:34 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 3C6AAF80679; Tue, 23 May 2023 09:55:20 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 49DB2F80578 for ; Tue, 23 May 2023 09:54:10 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 49DB2F80578 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=SV4NvtV9; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=E0UKAXzf Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 1EF7620414; Tue, 23 May 2023 07:54:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828450; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HRbJPal0LCt/4u6l8raqIvzJUXbVwRiniSakd0JY1/E=; b=SV4NvtV9IsG0ai1VNPjHflmmwG2pyywy+QGCyq12VipdDYnKyR62W/w9Jy3ulz1GDtvdJg 5xaNjBhLvh8ANem7uCYqB7PbQOn3SvjJ5P1vN8E9vNdoBAjijRQTPx6H6Egl6hHsFrwnJd mxvOYufJQQWsmwvAPBh77Et9WgsTwnc= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828450; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HRbJPal0LCt/4u6l8raqIvzJUXbVwRiniSakd0JY1/E=; b=E0UKAXzfYaJRgx5VXIkieBwNzI2CWx8xXzfPHKciuODNcI2P9xSJ6nGKHFrCYAicfDNZfV zRr3NHyFkC/A6LBA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id AE12713588; Tue, 23 May 2023 07:54:09 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id sECvKCFxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:09 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 25/37] ALSA: seq: Add UMP support Date: Tue, 23 May 2023 09:53:46 +0200 Message-Id: <20230523075358.9672-26-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: W5SLDZYSAZXF4INRJXOQHZ4VCJR67GPO X-Message-ID-Hash: W5SLDZYSAZXF4INRJXOQHZ4VCJR67GPO X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Starting from this commit, we add the basic support of UMP (Universal MIDI Packet) events on ALSA sequencer infrastructure. The biggest change here is that, for transferring UMP packets that are up to 128 bits, we extend the data payload of ALSA sequencer event record when the client is declared to support for the new UMP events. A new event flag bit, SNDRV_SEQ_EVENT_UMP, is defined and it shall be set for the UMP packet events that have the larger payload of 128 bits, defined as struct snd_seq_ump_event. For controlling the UMP feature enablement in kernel, a new Kconfig, CONFIG_SND_SEQ_UMP is introduced. The extended event for UMP is available only when this Kconfig item is set. Similarly, the size of the internal snd_seq_event_cell also increases (in 4 bytes) when the Kconfig item is set. (But the size increase is effective only for 32bit architectures; 64bit archs already have padding there.) Overall, when CONFIG_SND_SEQ_UMP isn't set, there is no change in the event and cell, keeping the old sizes. For applications that want to access the UMP packets, first of all, a sequencer client has to declare the user-protocol to match with the latest one via the new SNDRV_SEQ_IOCTL_USER_PVERSION; otherwise it's treated as if a legacy client without UMP support. Then the client can switch to the new UMP mode (MIDI 1.0 or MIDI 2.0) with a new field, midi_version, in snd_seq_client_info. When switched to UMP mode (midi_version = 1 or 2), the client can write the UMP events with SNDRV_SEQ_EVENT_UMP flag. For reads, the alignment size is changed from snd_seq_event (28 bytes) to snd_seq_ump_event (32 bytes). When a UMP sequencer event is delivered to a legacy sequencer client, it's ignored or handled as an error. Conceptually, ALSA sequencer client and port correspond to the UMP Endpoint and Group, respectively; each client may have multiple ports and each port has the fixed number (16) of channels, total up to 256 channels. As of this commit, ALSA sequencer core just sends and receives the UMP events as-is from/to clients. The automatic conversions between the legacy events and the new UMP events will be implemented in a later patch. Along with this commit, bump the sequencer protocol version to 1.0.3. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/asequencer.h | 4 + include/sound/seq_kernel.h | 8 ++ include/uapi/sound/asequencer.h | 53 +++++++---- sound/core/seq/Kconfig | 7 ++ sound/core/seq/seq_clientmgr.c | 156 +++++++++++++++++++++++--------- sound/core/seq/seq_clientmgr.h | 1 + sound/core/seq/seq_memory.c | 10 +- sound/core/seq/seq_memory.h | 19 +++- 8 files changed, 194 insertions(+), 64 deletions(-) diff --git a/include/sound/asequencer.h b/include/sound/asequencer.h index 18d4bc3ee0b7..ddbb6bf801bb 100644 --- a/include/sound/asequencer.h +++ b/include/sound/asequencer.h @@ -65,6 +65,10 @@ #define snd_seq_ev_is_abstime(ev) (snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_ABS) #define snd_seq_ev_is_reltime(ev) (snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_REL) +/* check whether the given event is a UMP event */ +#define snd_seq_ev_is_ump(ev) \ + (IS_ENABLED(CONFIG_SND_SEQ_UMP) && ((ev)->flags & SNDRV_SEQ_EVENT_UMP)) + /* queue sync port */ #define snd_seq_queue_sync_port(q) ((q) + 16) diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h index 527e7f8ad661..c8621671fa70 100644 --- a/include/sound/seq_kernel.h +++ b/include/sound/seq_kernel.h @@ -75,6 +75,14 @@ int snd_seq_expand_var_event_at(const struct snd_seq_event *event, int count, int snd_seq_dump_var_event(const struct snd_seq_event *event, snd_seq_dump_func_t func, void *private_data); +/* size of the event packet; it can be greater than snd_seq_event size */ +static inline size_t snd_seq_event_packet_size(struct snd_seq_event *ev) +{ + if (snd_seq_ev_is_ump(ev)) + return sizeof(struct snd_seq_ump_event); + return sizeof(struct snd_seq_event); +} + /* interface for OSS emulation */ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo); diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index 4a3c5a718bae..b87950cbfb79 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -10,7 +10,7 @@ #include /** version of the sequencer */ -#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 2) +#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3) /** * definition of sequencer event types @@ -174,6 +174,7 @@ struct snd_seq_connect { #define SNDRV_SEQ_PRIORITY_HIGH (1<<4) /* event should be processed before others */ #define SNDRV_SEQ_PRIORITY_MASK (1<<4) +#define SNDRV_SEQ_EVENT_UMP (1<<5) /* event holds a UMP packet */ /* note event */ struct snd_seq_ev_note { @@ -252,6 +253,19 @@ struct snd_seq_ev_quote { struct snd_seq_event *event; /* quoted event */ } __attribute__((packed)); +union snd_seq_event_data { /* event data... */ + struct snd_seq_ev_note note; + struct snd_seq_ev_ctrl control; + struct snd_seq_ev_raw8 raw8; + struct snd_seq_ev_raw32 raw32; + struct snd_seq_ev_ext ext; + struct snd_seq_ev_queue_control queue; + union snd_seq_timestamp time; + struct snd_seq_addr addr; + struct snd_seq_connect connect; + struct snd_seq_result result; + struct snd_seq_ev_quote quote; +}; /* sequencer event */ struct snd_seq_event { @@ -262,25 +276,27 @@ struct snd_seq_event { unsigned char queue; /* schedule queue */ union snd_seq_timestamp time; /* schedule time */ - struct snd_seq_addr source; /* source address */ struct snd_seq_addr dest; /* destination address */ - union { /* event data... */ - struct snd_seq_ev_note note; - struct snd_seq_ev_ctrl control; - struct snd_seq_ev_raw8 raw8; - struct snd_seq_ev_raw32 raw32; - struct snd_seq_ev_ext ext; - struct snd_seq_ev_queue_control queue; - union snd_seq_timestamp time; - struct snd_seq_addr addr; - struct snd_seq_connect connect; - struct snd_seq_result result; - struct snd_seq_ev_quote quote; - } data; + union snd_seq_event_data data; }; + /* (compatible) event for UMP-capable clients */ +struct snd_seq_ump_event { + snd_seq_event_type_t type; /* event type */ + unsigned char flags; /* event flags */ + char tag; + unsigned char queue; /* schedule queue */ + union snd_seq_timestamp time; /* schedule time */ + struct snd_seq_addr source; /* source address */ + struct snd_seq_addr dest; /* destination address */ + + union { + union snd_seq_event_data data; + unsigned int ump[4]; + }; +}; /* * bounce event - stored as variable size data @@ -344,9 +360,14 @@ struct snd_seq_client_info { int event_lost; /* number of lost events */ int card; /* RO: card number[kernel] */ int pid; /* RO: pid[user] */ - char reserved[56]; /* for future use */ + unsigned int midi_version; /* MIDI version */ + char reserved[52]; /* for future use */ }; +/* MIDI version numbers in client info */ +#define SNDRV_SEQ_CLIENT_LEGACY_MIDI 0 /* Legacy client */ +#define SNDRV_SEQ_CLIENT_UMP_MIDI_1_0 1 /* UMP MIDI 1.0 */ +#define SNDRV_SEQ_CLIENT_UMP_MIDI_2_0 2 /* UMP MIDI 2.0 */ /* client pool size */ struct snd_seq_client_pool { diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index f84718a44980..c69d8beb09fa 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig @@ -60,4 +60,11 @@ config SND_SEQ_MIDI_EMUL config SND_SEQ_VIRMIDI tristate +config SND_SEQ_UMP + bool "Support for UMP events" + help + Say Y here to enable the support for handling UMP (Universal MIDI + Packet) events via ALSA sequencer infrastructure, which is an + essential feature for enabling MIDI 2.0 support. + endif # SND_SEQUENCER diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 89a8d14df83b..801d5eee21eb 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -387,6 +387,15 @@ static int snd_seq_release(struct inode *inode, struct file *file) return 0; } +static bool event_is_compatible(const struct snd_seq_client *client, + const struct snd_seq_event *ev) +{ + if (snd_seq_ev_is_ump(ev) && !client->midi_version) + return false; + if (snd_seq_ev_is_ump(ev) && snd_seq_ev_is_variable(ev)) + return false; + return true; +} /* handle client read() */ /* possible error values: @@ -400,6 +409,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, { struct snd_seq_client *client = file->private_data; struct snd_seq_fifo *fifo; + size_t aligned_size; int err; long result = 0; struct snd_seq_event_cell *cell; @@ -431,43 +441,54 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, err = 0; snd_seq_fifo_lock(fifo); + if (client->midi_version > 0) + aligned_size = sizeof(struct snd_seq_ump_event); + else + aligned_size = sizeof(struct snd_seq_event); + /* while data available in queue */ - while (count >= sizeof(struct snd_seq_event)) { + while (count >= aligned_size) { int nonblock; nonblock = (file->f_flags & O_NONBLOCK) || result > 0; err = snd_seq_fifo_cell_out(fifo, &cell, nonblock); if (err < 0) break; + if (!event_is_compatible(client, &cell->event)) { + snd_seq_cell_free(cell); + cell = NULL; + continue; + } if (snd_seq_ev_is_variable(&cell->event)) { - struct snd_seq_event tmpev; - tmpev = cell->event; + struct snd_seq_ump_event tmpev; + + memcpy(&tmpev, &cell->event, aligned_size); tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK; - if (copy_to_user(buf, &tmpev, sizeof(struct snd_seq_event))) { + if (copy_to_user(buf, &tmpev, aligned_size)) { err = -EFAULT; break; } - count -= sizeof(struct snd_seq_event); - buf += sizeof(struct snd_seq_event); + count -= aligned_size; + buf += aligned_size; err = snd_seq_expand_var_event(&cell->event, count, (char __force *)buf, 0, - sizeof(struct snd_seq_event)); + aligned_size); if (err < 0) break; result += err; count -= err; buf += err; } else { - if (copy_to_user(buf, &cell->event, sizeof(struct snd_seq_event))) { + if (copy_to_user(buf, &cell->event, aligned_size)) { err = -EFAULT; break; } - count -= sizeof(struct snd_seq_event); - buf += sizeof(struct snd_seq_event); + count -= aligned_size; + buf += aligned_size; } snd_seq_cell_free(cell); cell = NULL; /* to be sure */ - result += sizeof(struct snd_seq_event); + result += aligned_size; } if (err < 0) { @@ -665,15 +686,17 @@ static int deliver_to_subscribers(struct snd_seq_client *client, { struct snd_seq_subscribers *subs; int err, result = 0, num_ev = 0; - struct snd_seq_event event_saved; struct snd_seq_client_port *src_port; + union __snd_seq_event event_saved; + size_t saved_size; struct snd_seq_port_subs_info *grp; src_port = snd_seq_port_use_ptr(client, event->source.port); if (src_port == NULL) return -EINVAL; /* invalid source port */ /* save original event record */ - event_saved = *event; + saved_size = snd_seq_event_packet_size(event); + memcpy(&event_saved, event, saved_size); grp = &src_port->c_src; /* lock list */ @@ -700,14 +723,13 @@ static int deliver_to_subscribers(struct snd_seq_client *client, } num_ev++; /* restore original event record */ - *event = event_saved; + memcpy(event, &event_saved, saved_size); } if (atomic) read_unlock(&grp->list_lock); else up_read(&grp->list_mutex); - *event = event_saved; /* restore */ - snd_seq_port_unlock(src_port); + memcpy(event, &event_saved, saved_size); return (result < 0) ? result : num_ev; } @@ -769,7 +791,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) return -EINVAL; } - if (cell->event.type == SNDRV_SEQ_EVENT_NOTE) { + if (!snd_seq_ev_is_ump(&cell->event) && + cell->event.type == SNDRV_SEQ_EVENT_NOTE) { /* NOTE event: * the event cell is re-used as a NOTE-OFF event and * enqueued again. @@ -793,7 +816,7 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) /* add the duration time */ switch (ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) { case SNDRV_SEQ_TIME_STAMP_TICK: - ev->time.tick += ev->data.note.duration; + cell->event.time.tick += ev->data.note.duration; break; case SNDRV_SEQ_TIME_STAMP_REAL: /* unit for duration is ms */ @@ -850,7 +873,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, /* direct event processing without enqueued */ if (snd_seq_ev_is_direct(event)) { - if (event->type == SNDRV_SEQ_EVENT_NOTE) + if (!snd_seq_ev_is_ump(event) && + event->type == SNDRV_SEQ_EVENT_NOTE) return -EINVAL; /* this event must be enqueued! */ return snd_seq_deliver_event(client, event, atomic, hop); } @@ -920,7 +944,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, struct snd_seq_client *client = file->private_data; int written = 0, len; int err, handled; - struct snd_seq_event event; + union __snd_seq_event __event; + struct snd_seq_event *ev = &__event.legacy; if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT)) return -ENXIO; @@ -946,49 +971,66 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, err = -EINVAL; while (count >= sizeof(struct snd_seq_event)) { /* Read in the event header from the user */ - len = sizeof(event); - if (copy_from_user(&event, buf, len)) { + len = sizeof(struct snd_seq_event); + if (copy_from_user(ev, buf, len)) { err = -EFAULT; break; } - event.source.client = client->number; /* fill in client number */ + /* read in the rest bytes for UMP events */ + if (snd_seq_ev_is_ump(ev)) { + if (count < sizeof(struct snd_seq_ump_event)) + break; + if (copy_from_user((char *)ev + len, buf + len, + sizeof(struct snd_seq_ump_event) - len)) { + err = -EFAULT; + break; + } + len = sizeof(struct snd_seq_ump_event); + } + + ev->source.client = client->number; /* fill in client number */ /* Check for extension data length */ - if (check_event_type_and_length(&event)) { + if (check_event_type_and_length(ev)) { + err = -EINVAL; + break; + } + + if (!event_is_compatible(client, ev)) { err = -EINVAL; break; } /* check for special events */ - if (event.type == SNDRV_SEQ_EVENT_NONE) - goto __skip_event; - else if (snd_seq_ev_is_reserved(&event)) { - err = -EINVAL; - break; + if (!snd_seq_ev_is_ump(ev)) { + if (ev->type == SNDRV_SEQ_EVENT_NONE) + goto __skip_event; + else if (snd_seq_ev_is_reserved(ev)) { + err = -EINVAL; + break; + } } - if (snd_seq_ev_is_variable(&event)) { - int extlen = event.data.ext.len & ~SNDRV_SEQ_EXT_MASK; + if (snd_seq_ev_is_variable(ev)) { + int extlen = ev->data.ext.len & ~SNDRV_SEQ_EXT_MASK; if ((size_t)(extlen + len) > count) { /* back out, will get an error this time or next */ err = -EINVAL; break; } /* set user space pointer */ - event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR; - event.data.ext.ptr = (char __force *)buf - + sizeof(struct snd_seq_event); + ev->data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR; + ev->data.ext.ptr = (char __force *)buf + len; len += extlen; /* increment data length */ } else { #ifdef CONFIG_COMPAT - if (client->convert32 && snd_seq_ev_is_varusr(&event)) { - void *ptr = (void __force *)compat_ptr(event.data.raw32.d[1]); - event.data.ext.ptr = ptr; - } + if (client->convert32 && snd_seq_ev_is_varusr(ev)) + ev->data.ext.ptr = + (void __force *)compat_ptr(ev->data.raw32.d[1]); #endif } /* ok, enqueue it */ - err = snd_seq_client_enqueue_event(client, &event, file, + err = snd_seq_client_enqueue_event(client, ev, file, !(file->f_flags & O_NONBLOCK), 0, 0, &client->ioctl_mutex); if (err < 0) @@ -1146,6 +1188,7 @@ static void get_client_info(struct snd_seq_client *cptr, else info->card = -1; + info->midi_version = cptr->midi_version; memset(info->reserved, 0, sizeof(info->reserved)); } @@ -1180,12 +1223,19 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client, if (client->type != client_info->type) return -EINVAL; + /* check validity of midi_version field */ + if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3) && + client_info->midi_version > SNDRV_SEQ_CLIENT_UMP_MIDI_2_0) + return -EINVAL; + /* fill the info fields */ if (client_info->name[0]) strscpy(client->name, client_info->name, sizeof(client->name)); client->filter = client_info->filter; client->event_lost = client_info->event_lost; + if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3)) + client->midi_version = client_info->midi_version; memcpy(client->event_filter, client_info->event_filter, 32); return 0; @@ -2181,10 +2231,12 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, if (snd_BUG_ON(!ev)) return -EINVAL; - if (ev->type == SNDRV_SEQ_EVENT_NONE) - return 0; /* ignore this */ - if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR) - return -EINVAL; /* quoted events can't be enqueued */ + if (!snd_seq_ev_is_ump(ev)) { + if (ev->type == SNDRV_SEQ_EVENT_NONE) + return 0; /* ignore this */ + if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR) + return -EINVAL; /* quoted events can't be enqueued */ + } /* fill in client number */ ev->source.client = client; @@ -2376,6 +2428,19 @@ static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, mutex_unlock(&client->ports_mutex); } +static const char *midi_version_string(unsigned int version) +{ + switch (version) { + case SNDRV_SEQ_CLIENT_LEGACY_MIDI: + return "Legacy"; + case SNDRV_SEQ_CLIENT_UMP_MIDI_1_0: + return "UMP MIDI1"; + case SNDRV_SEQ_CLIENT_UMP_MIDI_2_0: + return "UMP MIDI2"; + default: + return "Unknown"; + } +} /* exported to seq_info.c */ void snd_seq_info_clients_read(struct snd_info_entry *entry, @@ -2400,9 +2465,10 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, continue; } - snd_iprintf(buffer, "Client %3d : \"%s\" [%s]\n", + snd_iprintf(buffer, "Client %3d : \"%s\" [%s %s]\n", c, client->name, - client->type == USER_CLIENT ? "User" : "Kernel"); + client->type == USER_CLIENT ? "User" : "Kernel", + midi_version_string(client->midi_version)); snd_seq_info_dump_ports(buffer, client); if (snd_seq_write_pool_allocated(client)) { snd_iprintf(buffer, " Output pool :\n"); diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index abe0ceadf3da..5657f8091835 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -35,6 +35,7 @@ struct snd_seq_client { snd_seq_client_type_t type; unsigned int accept_input: 1, accept_output: 1; + unsigned int midi_version; unsigned int user_pversion; char name[64]; /* client name */ int number; /* client number */ diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index a8d2db439f86..174585bf59d2 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -340,6 +340,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, int ncells, err; unsigned int extlen; struct snd_seq_event_cell *cell; + int size; *cellp = NULL; @@ -357,7 +358,12 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, return err; /* copy the event */ - cell->event = *event; + size = snd_seq_event_packet_size(event); + memcpy(&cell->ump, event, size); +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) + if (size < sizeof(cell->event)) + cell->ump.raw.extra = 0; +#endif /* decompose */ if (snd_seq_ev_is_variable(event)) { @@ -375,7 +381,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, tail = NULL; while (ncells-- > 0) { - int size = sizeof(struct snd_seq_event); + size = sizeof(struct snd_seq_event); if (len < size) size = len; err = snd_seq_cell_alloc(pool, &tmp, nonblock, file, diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h index 7d7ff80f915e..7f7a2c0b187d 100644 --- a/sound/core/seq/seq_memory.h +++ b/sound/core/seq/seq_memory.h @@ -11,9 +11,26 @@ struct snd_info_buffer; +/* aliasing for legacy and UMP event packet handling */ +union __snd_seq_event { + struct snd_seq_event legacy; +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) + struct snd_seq_ump_event ump; +#endif + struct { + struct snd_seq_event event; +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) + u32 extra; +#endif + } __packed raw; +}; + /* container for sequencer event (internal use) */ struct snd_seq_event_cell { - struct snd_seq_event event; + union { + struct snd_seq_event event; + union __snd_seq_event ump; + }; struct snd_seq_pool *pool; /* used pool */ struct snd_seq_event_cell *next; /* next cell */ }; From patchwork Tue May 23 07:53:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251801 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A20E4C7EE23 for ; Tue, 23 May 2023 08:02:14 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A0B3DE87; Tue, 23 May 2023 10:01:22 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A0B3DE87 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828932; bh=XUpYdy0hHn+ixKI+HpJ9fsG0NqStjpcCrjZtW/jRZNA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=CaNtj23ES6OoqyI7kxJA91muz0pGfI1+gV6JCpMPjsdU6qJgRpBslmyiPi8tc4zAn ixQMwvwxHXTBZ+JurIH99oqtpj2suM/944uEWC+eSUf9lDz2DXXQ3VSYiM2AsDGgF1 bvY5xzb/HIutksf7KfFeHAvNAG2C9QrAn1WNNzs0= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 076B8F806B6; Tue, 23 May 2023 09:55:45 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 14A1DF806B2; Tue, 23 May 2023 09:55:45 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 17D08F80674; Tue, 23 May 2023 09:55:27 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 884B6F800DF for ; Tue, 23 May 2023 09:54:10 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 884B6F800DF Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=RUCnozLD; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=w9Z3PBz7 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 6540420415; Tue, 23 May 2023 07:54:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828450; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Za1t99tL4S6YC12LH4d/NDSvAlOTykT+bpOd7rGANIA=; b=RUCnozLDzs9aFM3/ILWQ7oQaWVqs1TqOT/UoX3KpreEBQOFIrcs0mc7KZ6sUK+X7VmxWtb 222G3lMexXz5nfoqBBRFCdjbNwOGhP948JleujhTJhFOwj1sl5SNk0cTq2JPZCXJXh52Pu VVjWHiMrt+zGY8lZ6RUHqRhI4BFijlE= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828450; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Za1t99tL4S6YC12LH4d/NDSvAlOTykT+bpOd7rGANIA=; b=w9Z3PBz7pSilQub8pqx8tNLeeuXVwQSJ/igFapMSt70tz3VsFw5y8AHJ39E4S09mB1uKAI moY/G2RJT7U80YAg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 0812513A1A; Tue, 23 May 2023 07:54:10 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 4DMUACJxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:09 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 26/37] ALSA: seq: Add port inactive flag Date: Tue, 23 May 2023 09:53:47 +0200 Message-Id: <20230523075358.9672-27-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: 7LPG3XA2U22R3LWNZPKVCBFT5ZGQBCDD X-Message-ID-Hash: 7LPG3XA2U22R3LWNZPKVCBFT5ZGQBCDD X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This extends the ALSA sequencer port capability bit to indicate the "inactive" flag. When this flag is set, the port is essentially invisible, and doesn't appear in the port query ioctls, while the direct access and the connection to this port are still allowed. The active/inactive state can be flipped dynamically, so that it can be visible at any time later. This feature is introduced basically for UMP; some UMP Groups in a UMP Block may be unassigned, hence those are practically invisible. On ALSA sequencer, the corresponding sequencer ports will get this new "inactive" flag to indicate the invisible state. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 1 + sound/core/seq/seq_clientmgr.c | 2 ++ sound/core/seq/seq_ports.c | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index b87950cbfb79..c6ca6609790b 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -427,6 +427,7 @@ struct snd_seq_remove_events { #define SNDRV_SEQ_PORT_CAP_SUBS_READ (1<<5) /* allow read subscription */ #define SNDRV_SEQ_PORT_CAP_SUBS_WRITE (1<<6) /* allow write subscription */ #define SNDRV_SEQ_PORT_CAP_NO_EXPORT (1<<7) /* routing not allowed */ +#define SNDRV_SEQ_PORT_CAP_INACTIVE (1<<8) /* inactive port */ /* port type */ #define SNDRV_SEQ_PORT_TYPE_SPECIFIC (1<<0) /* hardware specific */ diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 801d5eee21eb..6508ce63f761 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2416,6 +2416,8 @@ static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, mutex_lock(&client->ports_mutex); list_for_each_entry(p, &client->ports_list_head, list) { + if (p->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) + continue; snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n", p->addr.port, p->name, FLAG_PERM_RD(p->capability), diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 500b1a5a9679..42f4172d4766 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -69,11 +69,15 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl { int num; struct snd_seq_client_port *port, *found; + bool check_inactive = (pinfo->capability & SNDRV_SEQ_PORT_CAP_INACTIVE); num = pinfo->addr.port; found = NULL; read_lock(&client->ports_lock); list_for_each_entry(port, &client->ports_list_head, list) { + if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) && + !check_inactive) + continue; /* skip inactive ports */ if (port->addr.port < num) continue; if (port->addr.port == num) { From patchwork Tue May 23 07:53:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251799 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7C800C77B75 for ; Tue, 23 May 2023 08:01:44 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 84E9AE82; Tue, 23 May 2023 10:00:52 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 84E9AE82 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828902; bh=JJv3Jcpsarm6/UJpugK9/QJGtsFSNDCCYmVguybRDgI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=Ejzcj7JDPYajgIGFvuCgwRy8n/egzN5GMfWIl8IWymj5JmwAjqDVN+zsY+xRcCBIh dzRYR1Z4i9vThFvTYzlgCwDvkyUhq0fw/C7r7EI6bUIx6bfId9m223Fv+TU9pnJj2F 0ZR4VoJhg2km29YiTSkr5NMd1WZcY95CpnOeONjA= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 2CF44F806AB; Tue, 23 May 2023 09:55:39 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 9074FF806A0; Tue, 23 May 2023 09:55:38 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 99979F80682; Tue, 23 May 2023 09:55:22 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id D0F12F80579 for ; Tue, 23 May 2023 09:54:10 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz D0F12F80579 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=nZQ1c9za; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=ylM3LZYZ Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 7CDBE20416; Tue, 23 May 2023 07:54:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828450; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5NG2CvvqkfyXT6KfR2ATsi6VihNF6lLcBKYgL/VMEh8=; b=nZQ1c9za7bZvHM3ojokmBGGkAx79Wlsn4hvIc4CL61945nKhjL4sw5enlW3hJUh2AbyAt/ IK9grQyg+CDqTWmP7gv12+fPCJwdnvxk5ljNhsZvXuKEteVSHVqhgG3S7ygh6xzFGokoD5 DW+equGc4bkdDpdlnFbFu2wo6VoEL38= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828450; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5NG2CvvqkfyXT6KfR2ATsi6VihNF6lLcBKYgL/VMEh8=; b=ylM3LZYZ4pgUG57abvlCVyDVD11frO9a6tpJLQF6kanJDUug/kGIuZqJed0KxnvXGUqhBJ Ob6yWgeFJD9QsYDg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 420BF13588; Tue, 23 May 2023 07:54:10 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id WFVDDyJxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:10 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 27/37] ALSA: seq: Support MIDI 2.0 UMP Endpoint port Date: Tue, 23 May 2023 09:53:48 +0200 Message-Id: <20230523075358.9672-28-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: BAWL7DMZU2YON5R476TZCAAZ5LTDULO5 X-Message-ID-Hash: BAWL7DMZU2YON5R476TZCAAZ5LTDULO5 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This is an extension to ALSA sequencer infrastructure to support the MIDI 2.0 UMP Endpoint port. It's a "catch-all" port that is supposed to be present for each UMP Endpoint. When this port is read via subscription, it sends any events from all ports (UMP Groups) found in the same client. A UMP Endpoint port can be created with the new capability bit SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT. Although the port assignment isn't strictly defined, it should be the port number 0. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 1 + sound/core/seq/seq_clientmgr.c | 47 +++++++++++++++++++++++++++------ sound/core/seq/seq_clientmgr.h | 1 + 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index c6ca6609790b..67532c46b115 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -428,6 +428,7 @@ struct snd_seq_remove_events { #define SNDRV_SEQ_PORT_CAP_SUBS_WRITE (1<<6) /* allow write subscription */ #define SNDRV_SEQ_PORT_CAP_NO_EXPORT (1<<7) /* routing not allowed */ #define SNDRV_SEQ_PORT_CAP_INACTIVE (1<<8) /* inactive port */ +#define SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT (1<<9) /* MIDI 2.0 UMP Endpoint port */ /* port type */ #define SNDRV_SEQ_PORT_TYPE_SPECIFIC (1<<0) /* hardware specific */ diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 6508ce63f761..061b3e2bece1 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -239,6 +239,7 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize) mutex_init(&client->ports_mutex); INIT_LIST_HEAD(&client->ports_list_head); mutex_init(&client->ioctl_mutex); + client->ump_endpoint_port = -1; /* find free slot in the client table */ spin_lock_irq(&clients_lock); @@ -680,20 +681,17 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, /* * send the event to all subscribers: */ -static int deliver_to_subscribers(struct snd_seq_client *client, - struct snd_seq_event *event, - int atomic, int hop) +static int __deliver_to_subscribers(struct snd_seq_client *client, + struct snd_seq_event *event, + struct snd_seq_client_port *src_port, + int atomic, int hop) { struct snd_seq_subscribers *subs; int err, result = 0, num_ev = 0; - struct snd_seq_client_port *src_port; union __snd_seq_event event_saved; size_t saved_size; struct snd_seq_port_subs_info *grp; - src_port = snd_seq_port_use_ptr(client, event->source.port); - if (src_port == NULL) - return -EINVAL; /* invalid source port */ /* save original event record */ saved_size = snd_seq_event_packet_size(event); memcpy(&event_saved, event, saved_size); @@ -733,6 +731,31 @@ static int deliver_to_subscribers(struct snd_seq_client *client, return (result < 0) ? result : num_ev; } +static int deliver_to_subscribers(struct snd_seq_client *client, + struct snd_seq_event *event, + int atomic, int hop) +{ + struct snd_seq_client_port *src_port; + int ret = 0, ret2; + + src_port = snd_seq_port_use_ptr(client, event->source.port); + if (src_port) { + ret = __deliver_to_subscribers(client, event, src_port, atomic, hop); + snd_seq_port_unlock(src_port); + } + + if (client->ump_endpoint_port < 0 || + event->source.port == client->ump_endpoint_port) + return ret; + + src_port = snd_seq_port_use_ptr(client, client->ump_endpoint_port); + if (!src_port) + return ret; + ret2 = __deliver_to_subscribers(client, event, src_port, atomic, hop); + snd_seq_port_unlock(src_port); + return ret2 < 0 ? ret2 : ret; +} + /* deliver an event to the destination port(s). * if the event is to subscribers or broadcast, the event is dispatched * to multiple targets. @@ -1257,6 +1280,9 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) return -EPERM; if (client->type == USER_CLIENT && info->kernel) return -EINVAL; + if ((info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT) && + client->ump_endpoint_port >= 0) + return -EBUSY; if (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) port_idx = info->addr.port; @@ -1286,6 +1312,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg) info->addr = port->addr; snd_seq_set_port_info(port, info); + if (info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT) + client->ump_endpoint_port = port->addr.port; snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port); snd_seq_port_unlock(port); @@ -1305,8 +1333,11 @@ static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, void *arg) return -EPERM; err = snd_seq_delete_port(client, info->addr.port); - if (err >= 0) + if (err >= 0) { + if (client->ump_endpoint_port == info->addr.port) + client->ump_endpoint_port = -1; snd_seq_system_client_ev_port_exit(client->number, info->addr.port); + } return err; } diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index 5657f8091835..bb973d36ce78 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -50,6 +50,7 @@ struct snd_seq_client { struct mutex ports_mutex; struct mutex ioctl_mutex; int convert32; /* convert 32->64bit */ + int ump_endpoint_port; /* output pool */ struct snd_seq_pool *pool; /* memory pool for this client */ From patchwork Tue May 23 07:53:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251818 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 67A42C77B75 for ; Tue, 23 May 2023 08:09:32 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 1F8CC204; Tue, 23 May 2023 10:08:40 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 1F8CC204 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829370; bh=dAvj3mFssctctNHqX/ReLQlmm5AVZvNM55TRW4UGLXA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=C7m9Gq59vp94M46xm+s6AnbqV5jad/qyI3Y8LD6FQNe+zSgFnnFCtlElYwGrQW01y Fi9mw1DRhPLaRL+5TE3fCyiIs9u2tlXANyn/5eTyrIPPrigAY93mBvidvw0v31bEEk yIX4BrcPMecYMU/jc+OgfIAVazf4u108krkyoVLc= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 4E341F80549; Tue, 23 May 2023 10:08:11 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id D9254F800DF; Tue, 23 May 2023 10:08:10 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 93D7BF80674; Tue, 23 May 2023 09:55:25 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 349E2F80570 for ; Tue, 23 May 2023 09:54:11 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 349E2F80570 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=0LmK8Q4U; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=gz4Z+ioD Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id EFCE220417; Tue, 23 May 2023 07:54:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828450; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uA/KjUgcKuQxtHZTF3e6fCvm4X7bDeBEar63HAq3Wsc=; b=0LmK8Q4Uc/4K5xXvH6ARxg+LNLB4oQ4miCSzVS0JSIfRHLDFmZbBpoWwRi7emDf7UW0Vyh Bl4+un7AFnRLsR6b+3BbKcu5F0vOe1MXqDs/CNow80CBjQwI5c66OQpT3kADM8QIEsBlte /R4iOl2qDQn4V4l6Fs8rtdJjT5wVAzo= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828450; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uA/KjUgcKuQxtHZTF3e6fCvm4X7bDeBEar63HAq3Wsc=; b=gz4Z+ioDjfb4E3UfAvko5dFPqCEljOGRJTrRlsDsdiwJdKnIoJK/NHdb9LQ+ZX7RZrnHxE Lduv12PS0ZBCgQBQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 7595F13A1A; Tue, 23 May 2023 07:54:10 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id uBmpGyJxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:10 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 28/37] ALSA: seq: Add port direction to snd_seq_port_info Date: Tue, 23 May 2023 09:53:49 +0200 Message-Id: <20230523075358.9672-29-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Hits: administrivia X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header Message-ID-Hash: 5GPED6UBB7OLN6PL7BX5TCR6QY7BLZOS X-Message-ID-Hash: 5GPED6UBB7OLN6PL7BX5TCR6QY7BLZOS X-Mailman-Approved-At: Tue, 23 May 2023 08:08:05 +0000 X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add a new field "direction" to snd_seq_port_info for allowing a client to tell the expected direction of the port access. A port might still allow subscriptions for read/write (e.g. for MIDI-CI) even if the primary usage of the port is a single direction (either input or output only). This new "direction" field can help to indicate such cases. When the direction is unspecified at creating a port and the port has either read or write capability, the corresponding direction bits are set automatically as default. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 9 ++++++++- sound/core/seq/seq_clientmgr.c | 16 ++++++++++++++-- sound/core/seq/seq_dummy.c | 1 + sound/core/seq/seq_midi.c | 4 ++++ sound/core/seq/seq_ports.c | 13 +++++++++++++ sound/core/seq/seq_ports.h | 2 ++ sound/core/seq/seq_virmidi.c | 1 + 7 files changed, 43 insertions(+), 3 deletions(-) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index 67532c46b115..eae1e0b0bf37 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -455,6 +455,12 @@ struct snd_seq_remove_events { #define SNDRV_SEQ_PORT_FLG_TIMESTAMP (1<<1) #define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<2) +/* port direction */ +#define SNDRV_SEQ_PORT_DIR_UNKNOWN 0 +#define SNDRV_SEQ_PORT_DIR_INPUT 1 +#define SNDRV_SEQ_PORT_DIR_OUTPUT 2 +#define SNDRV_SEQ_PORT_DIR_BIDIRECTION 3 + struct snd_seq_port_info { struct snd_seq_addr addr; /* client/port numbers */ char name[64]; /* port name */ @@ -471,7 +477,8 @@ struct snd_seq_port_info { void *kernel; /* reserved for kernel use (must be NULL) */ unsigned int flags; /* misc. conditioning */ unsigned char time_queue; /* queue # for timestamping */ - char reserved[59]; /* for future use */ + unsigned char direction; /* port usage direction (r/w/bidir) */ + char reserved[58]; /* for future use */ }; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 061b3e2bece1..33aa6c5c5c9e 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2440,6 +2440,17 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer, #define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-') +static const char *port_direction_name(unsigned char dir) +{ + static const char *names[4] = { + "-", "In", "Out", "In/Out" + }; + + if (dir > SNDRV_SEQ_PORT_DIR_BIDIRECTION) + return "Invalid"; + return names[dir]; +} + static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, struct snd_seq_client *client) { @@ -2449,12 +2460,13 @@ static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer, list_for_each_entry(p, &client->ports_list_head, list) { if (p->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) continue; - snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n", + snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c) [%s]\n", p->addr.port, p->name, FLAG_PERM_RD(p->capability), FLAG_PERM_WR(p->capability), FLAG_PERM_EX(p->capability), - FLAG_PERM_DUPLEX(p->capability)); + FLAG_PERM_DUPLEX(p->capability), + port_direction_name(p->direction)); snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: "); snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: "); } diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index 8c18d8c4177e..2e8844ee32ed 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -127,6 +127,7 @@ create_port(int idx, int type) pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; if (duplex) pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; + pinfo.direction = SNDRV_SEQ_PORT_DIR_BIDIRECTION; pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | SNDRV_SEQ_PORT_TYPE_SOFTWARE | SNDRV_SEQ_PORT_TYPE_PORT; diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 2b5fff80de58..44302d98950e 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -367,6 +367,10 @@ snd_seq_midisynth_probe(struct device *_dev) if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) && info->flags & SNDRV_RAWMIDI_INFO_DUPLEX) port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; + if (port->capability & SNDRV_SEQ_PORT_CAP_READ) + port->direction |= SNDRV_SEQ_PORT_DIR_INPUT; + if (port->capability & SNDRV_SEQ_PORT_CAP_WRITE) + port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT; port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | SNDRV_SEQ_PORT_TYPE_HARDWARE | SNDRV_SEQ_PORT_TYPE_PORT; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 42f4172d4766..5574341f49eb 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -356,6 +356,16 @@ int snd_seq_set_port_info(struct snd_seq_client_port * port, port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0; port->time_queue = info->time_queue; + /* direction */ + port->direction = info->direction; + /* fill default port direction */ + if (!port->direction) { + if (info->capability & SNDRV_SEQ_PORT_CAP_READ) + port->direction |= SNDRV_SEQ_PORT_DIR_INPUT; + if (info->capability & SNDRV_SEQ_PORT_CAP_WRITE) + port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT; + } + return 0; } @@ -393,6 +403,9 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port, info->time_queue = port->time_queue; } + /* direction */ + info->direction = port->direction; + return 0; } diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h index 44f0e9e96bbf..dce733ab2398 100644 --- a/sound/core/seq/seq_ports.h +++ b/sound/core/seq/seq_ports.h @@ -72,6 +72,8 @@ struct snd_seq_client_port { int midi_voices; int synth_voices; + /* direction */ + unsigned char direction; }; struct snd_seq_client; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index f5cae49500c8..1b9260108e48 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -385,6 +385,7 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev) pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; + pinfo->direction = SNDRV_SEQ_PORT_DIR_BIDIRECTION; pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | SNDRV_SEQ_PORT_TYPE_SOFTWARE | SNDRV_SEQ_PORT_TYPE_PORT; From patchwork Tue May 23 07:53:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251800 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0A2D1C77B75 for ; Tue, 23 May 2023 08:02:04 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 52567DF9; Tue, 23 May 2023 10:01:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 52567DF9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828922; bh=Gwl3sIBLAt6uCqoBH4A0o4d0pA6eBiCydG8g3NtQGqA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=qVFt+m2cTMeCoFA7cx+4w9rt/p5nGcOmGkKQ9wQEXWevC5e0xqG/fUo4LQTRpY7Kt zngiIeqqY9YpGhK7YxwZV30GBLaXpIxJM4H5nnzyzjVLxaNYetkByIhRQYUdZ8jwfY VnjqMsIptfYuT2ydkMrgeSUEM1HzOXQiz+WnNvjY= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 23245F805AB; Tue, 23 May 2023 09:55:42 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 46BAAF806A3; Tue, 23 May 2023 09:55:42 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 7DE9FF80570; Tue, 23 May 2023 09:55:26 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 5D36BF8057B for ; Tue, 23 May 2023 09:54:11 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 5D36BF8057B Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=y1cY/y9B; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=f4gFMx00 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 30F8921A67; Tue, 23 May 2023 07:54:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828451; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Sa3pwc1C5HhGxbLR03Hm6eyUQzwJ+yyOfNOAHUZ83fg=; b=y1cY/y9BBnkXdpqA9huOH9Pk87lfjP2H1VdxMtHiahqPP3DdE2zkn43/JVpxy4UIRZgFxJ G4HgsF9r9jHl6oSeTvNWd6BTeyPwFowKWPrgM2v59cCdylobh6mtWJgK1UoJBG9zdCmRz3 jMtoVOsGNZjsPQROogmcLfS6+FlbHLU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828451; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Sa3pwc1C5HhGxbLR03Hm6eyUQzwJ+yyOfNOAHUZ83fg=; b=f4gFMx00Sm+Md8jzCk7Ggm5hQtj3eNjq6UkQcF5hJ2hy7VNTa5zXernYeQ9HfssNmiJUGl hYc7kWT8RYOOQkDw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id E3F3C13588; Tue, 23 May 2023 07:54:10 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id SFO7NSJxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:10 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 29/37] ALSA: seq: Add UMP group number to snd_seq_port_info Date: Tue, 23 May 2023 09:53:50 +0200 Message-Id: <20230523075358.9672-30-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: 75GKAHSTW4RJPM6EIZ2PAQYWTZTCNDTI X-Message-ID-Hash: 75GKAHSTW4RJPM6EIZ2PAQYWTZTCNDTI X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add yet more new filed "ump_group" to snd_seq_port_info for specifying the associated UMP Group number for each sequencer port. This will be referred in the upcoming automatic UMP conversion in sequencer core. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 3 ++- sound/core/seq/seq_ports.c | 9 +++++++-- sound/core/seq/seq_ports.h | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index eae1e0b0bf37..2470eaa5edc5 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -478,7 +478,8 @@ struct snd_seq_port_info { unsigned int flags; /* misc. conditioning */ unsigned char time_queue; /* queue # for timestamping */ unsigned char direction; /* port usage direction (r/w/bidir) */ - char reserved[58]; /* for future use */ + unsigned char ump_group; /* 0 = UMP EP (no conversion), 1-16 = UMP group number */ + char reserved[57]; /* for future use */ }; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 5574341f49eb..9b80f8275026 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -356,8 +356,12 @@ int snd_seq_set_port_info(struct snd_seq_client_port * port, port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0; port->time_queue = info->time_queue; - /* direction */ + /* UMP direction and group */ port->direction = info->direction; + port->ump_group = info->ump_group; + if (port->ump_group > SNDRV_UMP_MAX_GROUPS) + port->ump_group = 0; + /* fill default port direction */ if (!port->direction) { if (info->capability & SNDRV_SEQ_PORT_CAP_READ) @@ -403,8 +407,9 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port, info->time_queue = port->time_queue; } - /* direction */ + /* UMP direction and group */ info->direction = port->direction; + info->ump_group = port->ump_group; return 0; } diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h index dce733ab2398..c6c138edceab 100644 --- a/sound/core/seq/seq_ports.h +++ b/sound/core/seq/seq_ports.h @@ -72,8 +72,9 @@ struct snd_seq_client_port { int midi_voices; int synth_voices; - /* direction */ + /* UMP direction and group */ unsigned char direction; + unsigned char ump_group; }; struct snd_seq_client; From patchwork Tue May 23 07:53:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251803 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D50FAC7EE23 for ; Tue, 23 May 2023 08:02:52 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id D1F7EE8B; Tue, 23 May 2023 10:01:59 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz D1F7EE8B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828970; bh=3LBIN3zcB6VwvRAluB9TkgdZXXsJzIaOzy75wWtw+w0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=GZe01VgeC8RsJlec3E7dfU7CO/4xbooDP7saTTWhHybpOawK2Rnme+nmURxVup5K6 nXNbcAvUtjPJ4KD7WVf1QwJFUKoUVxBu4SukfQiCvPD1equyKoJhEfJ2Dl/HkvwtvN iiwCxhownSuPYIBi7TSH/A6/Vmbtr6E1lc625qUM= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5BEABF806CC; Tue, 23 May 2023 09:55:55 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 2DF6CF806C3; Tue, 23 May 2023 09:55:54 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id BF117F805D5; Tue, 23 May 2023 09:55:44 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E9D17F8057C for ; Tue, 23 May 2023 09:54:11 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E9D17F8057C Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=OJbhg0gr; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=GgQ9Qw03 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 9901420418; Tue, 23 May 2023 07:54:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828451; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lRp9BJ0To4Td1JK6hwMrmaWH6yhNyvMGR6X7ycsOazY=; b=OJbhg0grmXsJLPef5Tz0XNUgaquOYoomIOjweABtDNAij0jVmk8x1GgrAp80XuhyKmLNNj RQMErTYmWKLMA/RdH2H1Yxknt45YzJ4P6y5daj1kcHxXD4S8tDjxU2fZ06R2CxhYhzZy+F Vxka26w+fFIsbXo0X/BL1aiA2AGVFUY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828451; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lRp9BJ0To4Td1JK6hwMrmaWH6yhNyvMGR6X7ycsOazY=; b=GgQ9Qw03zUj+xubfT9yTHejUrB03fdkxpIuF8mrIuUqsY+yZcqM1pnXsNMdOmjryh5HchO 5YoLdaSVz7f5fVAQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 2822713A1A; Tue, 23 May 2023 07:54:11 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id AId7ByNxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:11 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 30/37] ALSA: seq: Automatic conversion of UMP events Date: Tue, 23 May 2023 09:53:51 +0200 Message-Id: <20230523075358.9672-31-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: 5P4WXVJKZTW74XRZIMPWEOFQTVIAV5WD X-Message-ID-Hash: 5P4WXVJKZTW74XRZIMPWEOFQTVIAV5WD X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This patch enables the automatic conversion of UMP events from/to the legacy ALSA sequencer MIDI events. Also, as UMP itself has two different modes (MIDI 1.0 and MIDI 2.0), yet another converters between them are needed, too. Namely, we have conversions between the legacy and UMP like: - seq legacy event -> seq UMP MIDI 1.0 event - seq legacy event -> seq UMP MIDI 2.0 event - seq UMP MIDI 1.0 event -> seq legacy event - seq UMP MIDI 2.0 event -> seq legacy event and the conversions between UMP MIDI 1.0 and 2.0 clients like: - seq UMP MIDI 1.0 event -> seq UMP MIDI 2.0 event - seq UMP MIDI 2.0 event -> seq UMP MIDI 1.0 event The translation is per best-effort; some MIDI 2.0 specific events are ignored when translated to MIDI 1.0. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/Kconfig | 2 + sound/core/seq/Makefile | 1 + sound/core/seq/seq_clientmgr.c | 50 +- sound/core/seq/seq_clientmgr.h | 15 + sound/core/seq/seq_ports.h | 15 + sound/core/seq/seq_ump_convert.c | 1190 ++++++++++++++++++++++++++++++ sound/core/seq/seq_ump_convert.h | 22 + 7 files changed, 1280 insertions(+), 15 deletions(-) create mode 100644 sound/core/seq/seq_ump_convert.c create mode 100644 sound/core/seq/seq_ump_convert.h diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index c69d8beb09fa..f8336134153e 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig @@ -66,5 +66,7 @@ config SND_SEQ_UMP Say Y here to enable the support for handling UMP (Universal MIDI Packet) events via ALSA sequencer infrastructure, which is an essential feature for enabling MIDI 2.0 support. + It includes the automatic conversion of ALSA sequencer events + among legacy and UMP clients. endif # SND_SEQUENCER diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index 3a2177a7e50c..ba264a695643 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -8,6 +8,7 @@ snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \ seq_fifo.o seq_prioq.o seq_timer.o \ seq_system.o seq_ports.o snd-seq-$(CONFIG_SND_PROC_FS) += seq_info.o +snd-seq-$(CONFIG_SND_SEQ_UMP) += seq_ump_convert.o snd-seq-midi-objs := seq_midi.o snd-seq-midi-emul-objs := seq_midi_emul.o snd-seq-midi-event-objs := seq_midi_event.o diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 33aa6c5c5c9e..07b090f76b5f 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -20,6 +20,7 @@ #include "seq_timer.h" #include "seq_info.h" #include "seq_system.h" +#include "seq_ump_convert.h" #include #ifdef CONFIG_COMPAT #include @@ -612,6 +613,27 @@ static int update_timestamp_of_queue(struct snd_seq_event *event, return 1; } +/* deliver a single event; called from below and UMP converter */ +int __snd_seq_deliver_single_event(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop) +{ + switch (dest->type) { + case USER_CLIENT: + if (!dest->data.user.fifo) + return 0; + return snd_seq_fifo_event_in(dest->data.user.fifo, event); + case KERNEL_CLIENT: + if (!dest_port->event_input) + return 0; + return dest_port->event_input(event, + snd_seq_ev_is_direct(event), + dest_port->private_data, + atomic, hop); + } + return 0; +} /* * deliver an event to the specified destination. @@ -648,22 +670,20 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, update_timestamp_of_queue(event, dest_port->time_queue, dest_port->time_real); - switch (dest->type) { - case USER_CLIENT: - if (dest->data.user.fifo) - result = snd_seq_fifo_event_in(dest->data.user.fifo, event); - break; - - case KERNEL_CLIENT: - if (dest_port->event_input == NULL) - break; - result = dest_port->event_input(event, direct, - dest_port->private_data, - atomic, hop); - break; - default: - break; +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) + if (snd_seq_ev_is_ump(event)) { + result = snd_seq_deliver_from_ump(client, dest, dest_port, + event, atomic, hop); + goto __skip; + } else if (snd_seq_client_is_ump(dest)) { + result = snd_seq_deliver_to_ump(client, dest, dest_port, + event, atomic, hop); + goto __skip; } +#endif /* CONFIG_SND_SEQ_UMP */ + + result = __snd_seq_deliver_single_event(dest, dest_port, event, + atomic, hop); __skip: if (dest_port) diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index bb973d36ce78..97762892ffab 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -85,6 +85,11 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table int snd_seq_client_notify_subscription(int client, int port, struct snd_seq_port_subscribe *info, int evtype); +int __snd_seq_deliver_single_event(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop); + /* only for OSS sequencer */ bool snd_seq_client_ioctl_lock(int clientid); void snd_seq_client_ioctl_unlock(int clientid); @@ -95,4 +100,14 @@ extern int seq_client_load[15]; struct snd_seq_client *snd_seq_kernel_client_get(int client); void snd_seq_kernel_client_put(struct snd_seq_client *cptr); +static inline bool snd_seq_client_is_ump(struct snd_seq_client *c) +{ + return c->midi_version != SNDRV_SEQ_CLIENT_LEGACY_MIDI; +} + +static inline bool snd_seq_client_is_midi2(struct snd_seq_client *c) +{ + return c->midi_version == SNDRV_SEQ_CLIENT_UMP_MIDI_2_0; +} + #endif diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h index c6c138edceab..b111382f697a 100644 --- a/sound/core/seq/seq_ports.h +++ b/sound/core/seq/seq_ports.h @@ -42,6 +42,17 @@ struct snd_seq_port_subs_info { int (*close)(void *private_data, struct snd_seq_port_subscribe *info); }; +/* context for converting from legacy control event to UMP packet */ +struct snd_seq_ump_midi2_bank { + bool rpn_set; + bool nrpn_set; + bool bank_set; + unsigned char cc_rpn_msb, cc_rpn_lsb; + unsigned char cc_nrpn_msb, cc_nrpn_lsb; + unsigned char cc_data_msb, cc_data_lsb; + unsigned char cc_bank_msb, cc_bank_lsb; +}; + struct snd_seq_client_port { struct snd_seq_addr addr; /* client/port number */ @@ -75,6 +86,10 @@ struct snd_seq_client_port { /* UMP direction and group */ unsigned char direction; unsigned char ump_group; + +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) + struct snd_seq_ump_midi2_bank midi2_bank[16]; /* per channel */ +#endif }; struct snd_seq_client; diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c new file mode 100644 index 000000000000..433fe842947e --- /dev/null +++ b/sound/core/seq/seq_ump_convert.c @@ -0,0 +1,1190 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ALSA sequencer event conversion between UMP and legacy clients + */ + +#include +#include +#include +#include +#include +#include +#include "seq_ump_convert.h" + +/* + * Upgrade / downgrade value bits + */ +static u8 downscale_32_to_7bit(u32 src) +{ + return src >> 25; +} + +static u16 downscale_32_to_14bit(u32 src) +{ + return src >> 18; +} + +static u8 downscale_16_to_7bit(u16 src) +{ + return src >> 9; +} + +static u16 upscale_7_to_16bit(u8 src) +{ + u16 val, repeat; + + val = (u16)src << 9; + if (src <= 0x40) + return val; + repeat = src & 0x3f; + return val | (repeat << 3) | (repeat >> 3); +} + +static u32 upscale_7_to_32bit(u8 src) +{ + u32 val, repeat; + + val = src << 25; + if (src <= 0x40) + return val; + repeat = src & 0x3f; + return val | (repeat << 19) | (repeat << 13) | + (repeat << 7) | (repeat << 1) | (repeat >> 5); +} + +static u32 upscale_14_to_32bit(u16 src) +{ + u32 val, repeat; + + val = src << 18; + if (src <= 0x2000) + return val; + repeat = src & 0x1fff; + return val | (repeat << 5) | (repeat >> 8); +} + +static unsigned char get_ump_group(struct snd_seq_client_port *port) +{ + return port->ump_group ? (port->ump_group - 1) : 0; +} + +/* create a UMP header */ +#define make_raw_ump(port, type) \ + ump_compose(type, get_ump_group(port), 0, 0) + +/* + * UMP -> MIDI1 sequencer event + */ + +/* MIDI 1.0 CVM */ + +/* encode note event */ +static void ump_midi1_to_note_ev(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) +{ + ev->data.note.channel = val->note.channel; + ev->data.note.note = val->note.note; + ev->data.note.velocity = val->note.velocity; +} + +/* encode one parameter controls */ +static void ump_midi1_to_ctrl_ev(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.channel = val->caf.channel; + ev->data.control.value = val->caf.data; +} + +/* encode pitch wheel change */ +static void ump_midi1_to_pitchbend_ev(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.channel = val->pb.channel; + ev->data.control.value = (val->pb.data_msb << 7) | val->pb.data_lsb; + ev->data.control.value -= 8192; +} + +/* encode midi control change */ +static void ump_midi1_to_cc_ev(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.channel = val->cc.channel; + ev->data.control.param = val->cc.index; + ev->data.control.value = val->cc.data; +} + +/* Encoding MIDI 1.0 UMP packet */ +struct seq_ump_midi1_to_ev { + int seq_type; + void (*encode)(const union snd_ump_midi1_msg *val, struct snd_seq_event *ev); +}; + +/* Encoders for MIDI1 status 0x80-0xe0 */ +static struct seq_ump_midi1_to_ev midi1_msg_encoders[] = { + {SNDRV_SEQ_EVENT_NOTEOFF, ump_midi1_to_note_ev}, /* 0x80 */ + {SNDRV_SEQ_EVENT_NOTEON, ump_midi1_to_note_ev}, /* 0x90 */ + {SNDRV_SEQ_EVENT_KEYPRESS, ump_midi1_to_note_ev}, /* 0xa0 */ + {SNDRV_SEQ_EVENT_CONTROLLER, ump_midi1_to_cc_ev}, /* 0xb0 */ + {SNDRV_SEQ_EVENT_PGMCHANGE, ump_midi1_to_ctrl_ev}, /* 0xc0 */ + {SNDRV_SEQ_EVENT_CHANPRESS, ump_midi1_to_ctrl_ev}, /* 0xd0 */ + {SNDRV_SEQ_EVENT_PITCHBEND, ump_midi1_to_pitchbend_ev}, /* 0xe0 */ +}; + +static int cvt_ump_midi1_to_event(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) +{ + unsigned char status = val->note.status; + + if (status < 0x8 || status > 0xe) + return 0; /* invalid - skip */ + status -= 8; + ev->type = midi1_msg_encoders[status].seq_type; + ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED; + midi1_msg_encoders[status].encode(val, ev); + return 1; +} + +/* MIDI System message */ + +/* encode one parameter value*/ +static void ump_system_to_one_param_ev(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.value = val->system.parm1; +} + +/* encode song position */ +static void ump_system_to_songpos_ev(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.value = (val->system.parm1 << 7) | val->system.parm2; +} + +/* Encoders for 0xf0 - 0xff */ +static struct seq_ump_midi1_to_ev system_msg_encoders[] = { + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf0 */ + {SNDRV_SEQ_EVENT_QFRAME, ump_system_to_one_param_ev}, /* 0xf1 */ + {SNDRV_SEQ_EVENT_SONGPOS, ump_system_to_songpos_ev}, /* 0xf2 */ + {SNDRV_SEQ_EVENT_SONGSEL, ump_system_to_one_param_ev}, /* 0xf3 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf4 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf5 */ + {SNDRV_SEQ_EVENT_TUNE_REQUEST, NULL}, /* 0xf6 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf7 */ + {SNDRV_SEQ_EVENT_CLOCK, NULL}, /* 0xf8 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf9 */ + {SNDRV_SEQ_EVENT_START, NULL}, /* 0xfa */ + {SNDRV_SEQ_EVENT_CONTINUE, NULL}, /* 0xfb */ + {SNDRV_SEQ_EVENT_STOP, NULL}, /* 0xfc */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xfd */ + {SNDRV_SEQ_EVENT_SENSING, NULL}, /* 0xfe */ + {SNDRV_SEQ_EVENT_RESET, NULL}, /* 0xff */ +}; + +static int cvt_ump_system_to_event(const union snd_ump_midi1_msg *val, + struct snd_seq_event *ev) +{ + unsigned char status = val->system.status; + + if ((status & 0xf0) != UMP_MIDI1_MSG_REALTIME) + return 0; /* invalid status - skip */ + status &= 0x0f; + ev->type = system_msg_encoders[status].seq_type; + ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED; + if (ev->type == SNDRV_SEQ_EVENT_NONE) + return 0; + if (system_msg_encoders[status].encode) + system_msg_encoders[status].encode(val, ev); + return 1; +} + +/* MIDI 2.0 CVM */ + +/* encode note event */ +static int ump_midi2_to_note_ev(const union snd_ump_midi2_msg *val, + struct snd_seq_event *ev) +{ + ev->data.note.channel = val->note.channel; + ev->data.note.note = val->note.note; + ev->data.note.velocity = downscale_16_to_7bit(val->note.velocity); + /* correct note-on velocity 0 to 1; + * it's no longer equivalent as not-off for MIDI 2.0 + */ + if (ev->type == SNDRV_SEQ_EVENT_NOTEON && + !ev->data.note.velocity) + ev->data.note.velocity = 1; + return 1; +} + +/* encode pitch wheel change */ +static int ump_midi2_to_pitchbend_ev(const union snd_ump_midi2_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.channel = val->pb.channel; + ev->data.control.value = downscale_32_to_14bit(val->pb.data); + ev->data.control.value -= 8192; + return 1; +} + +/* encode midi control change */ +static int ump_midi2_to_cc_ev(const union snd_ump_midi2_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.channel = val->cc.channel; + ev->data.control.param = val->cc.index; + ev->data.control.value = downscale_32_to_7bit(val->cc.data); + return 1; +} + +/* encode midi program change */ +static int ump_midi2_to_pgm_ev(const union snd_ump_midi2_msg *val, + struct snd_seq_event *ev) +{ + int size = 1; + + ev->data.control.channel = val->pg.channel; + if (val->pg.bank_valid) { + ev->type = SNDRV_SEQ_EVENT_CONTROL14; + ev->data.control.param = UMP_CC_BANK_SELECT; + ev->data.control.value = (val->pg.bank_msb << 7) | val->pg.bank_lsb; + ev[1] = ev[0]; + ev++; + ev->type = SNDRV_SEQ_EVENT_PGMCHANGE; + size = 2; + } + ev->data.control.value = val->pg.program; + return size; +} + +/* encode one parameter controls */ +static int ump_midi2_to_ctrl_ev(const union snd_ump_midi2_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.channel = val->caf.channel; + ev->data.control.value = downscale_32_to_7bit(val->caf.data); + return 1; +} + +/* encode RPN/NRPN */ +static int ump_midi2_to_rpn_ev(const union snd_ump_midi2_msg *val, + struct snd_seq_event *ev) +{ + ev->data.control.channel = val->rpn.channel; + ev->data.control.param = (val->rpn.bank << 7) | val->rpn.index; + ev->data.control.value = downscale_32_to_14bit(val->rpn.data); + return 1; +} + +/* Encoding MIDI 2.0 UMP Packet */ +struct seq_ump_midi2_to_ev { + int seq_type; + int (*encode)(const union snd_ump_midi2_msg *val, struct snd_seq_event *ev); +}; + +/* Encoders for MIDI2 status 0x00-0xf0 */ +static struct seq_ump_midi2_to_ev midi2_msg_encoders[] = { + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x00 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x10 */ + {SNDRV_SEQ_EVENT_REGPARAM, ump_midi2_to_rpn_ev}, /* 0x20 */ + {SNDRV_SEQ_EVENT_NONREGPARAM, ump_midi2_to_rpn_ev}, /* 0x30 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x40 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x50 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x60 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x70 */ + {SNDRV_SEQ_EVENT_NOTEOFF, ump_midi2_to_note_ev}, /* 0x80 */ + {SNDRV_SEQ_EVENT_NOTEON, ump_midi2_to_note_ev}, /* 0x90 */ + {SNDRV_SEQ_EVENT_KEYPRESS, ump_midi2_to_note_ev}, /* 0xa0 */ + {SNDRV_SEQ_EVENT_CONTROLLER, ump_midi2_to_cc_ev}, /* 0xb0 */ + {SNDRV_SEQ_EVENT_PGMCHANGE, ump_midi2_to_pgm_ev}, /* 0xc0 */ + {SNDRV_SEQ_EVENT_CHANPRESS, ump_midi2_to_ctrl_ev}, /* 0xd0 */ + {SNDRV_SEQ_EVENT_PITCHBEND, ump_midi2_to_pitchbend_ev}, /* 0xe0 */ + {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf0 */ +}; + +static int cvt_ump_midi2_to_event(const union snd_ump_midi2_msg *val, + struct snd_seq_event *ev) +{ + unsigned char status = val->note.status; + + ev->type = midi2_msg_encoders[status].seq_type; + if (ev->type == SNDRV_SEQ_EVENT_NONE) + return 0; /* skip */ + ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED; + return midi2_msg_encoders[status].encode(val, ev); +} + +/* parse and compose for a sysex var-length event */ +static int cvt_ump_sysex7_to_event(const u32 *data, unsigned char *buf, + struct snd_seq_event *ev) +{ + unsigned char status; + unsigned char bytes; + u32 val; + int size = 0; + + val = data[0]; + status = ump_sysex_message_status(val); + bytes = ump_sysex_message_length(val); + if (bytes > 6) + return 0; // skip + + if (status == UMP_SYSEX_STATUS_SINGLE || + status == UMP_SYSEX_STATUS_START) { + buf[0] = UMP_MIDI1_MSG_SYSEX_START; + size = 1; + } + + if (bytes > 0) + buf[size++] = (val >> 8) & 0x7f; + if (bytes > 1) + buf[size++] = val & 0x7f; + val = data[1]; + if (bytes > 2) + buf[size++] = (val >> 24) & 0x7f; + if (bytes > 3) + buf[size++] = (val >> 16) & 0x7f; + if (bytes > 4) + buf[size++] = (val >> 8) & 0x7f; + if (bytes > 5) + buf[size++] = val & 0x7f; + + if (status == UMP_SYSEX_STATUS_SINGLE || + status == UMP_SYSEX_STATUS_END) + buf[size++] = UMP_MIDI1_MSG_SYSEX_END; + + ev->type = SNDRV_SEQ_EVENT_SYSEX; + ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE; + ev->data.ext.len = size; + ev->data.ext.ptr = buf; + return 1; +} + +/* convert UMP packet from MIDI 1.0 to MIDI 2.0 and deliver it */ +static int cvt_ump_midi1_to_midi2(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *__event, + int atomic, int hop) +{ + struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event; + struct snd_seq_ump_event ev_cvt; + const union snd_ump_midi1_msg *midi1 = (const union snd_ump_midi1_msg *)event->ump; + union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)ev_cvt.ump; + + ev_cvt = *event; + memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump)); + + midi2->note.type = UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE; + midi2->note.group = midi1->note.group; + midi2->note.status = midi1->note.status; + midi2->note.channel = midi1->note.channel; + switch (midi1->note.status) { + case UMP_MSG_STATUS_NOTE_ON: + case UMP_MSG_STATUS_NOTE_OFF: + midi2->note.note = midi1->note.note; + midi2->note.velocity = upscale_7_to_16bit(midi1->note.velocity); + break; + case UMP_MSG_STATUS_POLY_PRESSURE: + midi2->paf.note = midi1->paf.note; + midi2->paf.data = upscale_7_to_32bit(midi1->paf.data); + break; + case UMP_MSG_STATUS_CC: + midi2->cc.index = midi1->cc.index; + midi2->cc.data = upscale_7_to_32bit(midi1->cc.data); + break; + case UMP_MSG_STATUS_PROGRAM: + midi2->pg.program = midi1->pg.program; + break; + case UMP_MSG_STATUS_CHANNEL_PRESSURE: + midi2->caf.data = upscale_7_to_32bit(midi1->caf.data); + break; + case UMP_MSG_STATUS_PITCH_BEND: + midi2->pb.data = upscale_14_to_32bit((midi1->pb.data_msb << 7) | + midi1->pb.data_lsb); + break; + default: + return 0; + } + + return __snd_seq_deliver_single_event(dest, dest_port, + (struct snd_seq_event *)&ev_cvt, + atomic, hop); +} + +/* convert UMP packet from MIDI 2.0 to MIDI 1.0 and deliver it */ +static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *__event, + int atomic, int hop) +{ + struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event; + struct snd_seq_ump_event ev_cvt; + union snd_ump_midi1_msg *midi1 = (union snd_ump_midi1_msg *)ev_cvt.ump; + const union snd_ump_midi2_msg *midi2 = (const union snd_ump_midi2_msg *)event->ump; + u16 v; + + ev_cvt = *event; + memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump)); + + midi1->note.type = UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE; + midi1->note.group = midi2->note.group; + midi1->note.status = midi2->note.status; + midi1->note.channel = midi2->note.channel; + switch (midi2->note.status << 4) { + case UMP_MSG_STATUS_NOTE_ON: + case UMP_MSG_STATUS_NOTE_OFF: + midi1->note.note = midi2->note.note; + midi1->note.velocity = downscale_16_to_7bit(midi2->note.velocity); + break; + case UMP_MSG_STATUS_POLY_PRESSURE: + midi1->paf.note = midi2->paf.note; + midi1->paf.data = downscale_32_to_7bit(midi2->paf.data); + break; + case UMP_MSG_STATUS_CC: + midi1->cc.index = midi2->cc.index; + midi1->cc.data = downscale_32_to_7bit(midi2->cc.data); + break; + case UMP_MSG_STATUS_PROGRAM: + midi1->pg.program = midi2->pg.program; + break; + case UMP_MSG_STATUS_CHANNEL_PRESSURE: + midi1->caf.data = downscale_32_to_7bit(midi2->caf.data); + break; + case UMP_MSG_STATUS_PITCH_BEND: + v = downscale_32_to_14bit(midi2->pb.data); + midi1->pb.data_msb = v >> 7; + midi1->pb.data_lsb = v & 0x7f; + break; + default: + return 0; + } + + return __snd_seq_deliver_single_event(dest, dest_port, + (struct snd_seq_event *)&ev_cvt, + atomic, hop); +} + +/* convert UMP to a legacy ALSA seq event and deliver it */ +static int cvt_ump_to_any(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + unsigned char type, + int atomic, int hop) +{ + struct snd_seq_event ev_cvt[2]; /* up to two events */ + struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event; + /* use the second event as a temp buffer for saving stack usage */ + unsigned char *sysex_buf = (unsigned char *)(ev_cvt + 1); + unsigned char flags = event->flags & ~SNDRV_SEQ_EVENT_UMP; + int i, len, err; + + ev_cvt[0] = ev_cvt[1] = *event; + ev_cvt[0].flags = flags; + ev_cvt[1].flags = flags; + switch (type) { + case UMP_MSG_TYPE_SYSTEM: + len = cvt_ump_system_to_event((union snd_ump_midi1_msg *)ump_ev->ump, + ev_cvt); + break; + case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE: + len = cvt_ump_midi1_to_event((union snd_ump_midi1_msg *)ump_ev->ump, + ev_cvt); + break; + case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE: + len = cvt_ump_midi2_to_event((union snd_ump_midi2_msg *)ump_ev->ump, + ev_cvt); + break; + case UMP_MSG_TYPE_DATA: + len = cvt_ump_sysex7_to_event(ump_ev->ump, sysex_buf, ev_cvt); + break; + default: + return 0; + } + + for (i = 0; i < len; i++) { + err = __snd_seq_deliver_single_event(dest, dest_port, + &ev_cvt[i], atomic, hop); + if (err < 0) + return err; + } + + return 0; +} + +/* Replace UMP group field with the destination and deliver */ +static int deliver_with_group_convert(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_ump_event *ump_ev, + int atomic, int hop) +{ + struct snd_seq_ump_event ev = *ump_ev; + + /* rewrite the group to the destination port */ + ev.ump[0] &= ~(0xfU << 24); + /* fill with the new group; the dest_port->ump_group field is 1-based */ + ev.ump[0] |= ((dest_port->ump_group - 1) << 24); + + return __snd_seq_deliver_single_event(dest, dest_port, + (struct snd_seq_event *)&ev, + atomic, hop); +} + +/* Convert from UMP packet and deliver */ +int snd_seq_deliver_from_ump(struct snd_seq_client *source, + struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop) +{ + struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event; + unsigned char type; + + if (snd_seq_ev_is_variable(event)) + return 0; // skip, no variable event for UMP, so far + type = ump_message_type(ump_ev->ump[0]); + + if (snd_seq_client_is_ump(dest)) { + if (snd_seq_client_is_midi2(dest) && + type == UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE) + return cvt_ump_midi1_to_midi2(dest, dest_port, + event, atomic, hop); + else if (!snd_seq_client_is_midi2(dest) && + type == UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE) + return cvt_ump_midi2_to_midi1(dest, dest_port, + event, atomic, hop); + /* non-EP port and different group is set? */ + if (dest_port->ump_group && + ump_message_group(*ump_ev->ump) + 1 != dest_port->ump_group) + return deliver_with_group_convert(dest, dest_port, + ump_ev, atomic, hop); + /* copy as-is */ + return __snd_seq_deliver_single_event(dest, dest_port, + event, atomic, hop); + } + + return cvt_ump_to_any(dest, dest_port, event, type, atomic, hop); +} + +/* + * MIDI1 sequencer event -> UMP conversion + */ + +/* Conversion to UMP MIDI 1.0 */ + +/* convert note on/off event to MIDI 1.0 UMP */ +static int note_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + if (!event->data.note.velocity) + status = UMP_MSG_STATUS_NOTE_OFF; + data->note.status = status; + data->note.channel = event->data.note.channel & 0x0f; + data->note.velocity = event->data.note.velocity & 0x7f; + data->note.note = event->data.note.note & 0x7f; + return 1; +} + +/* convert CC event to MIDI 1.0 UMP */ +static int cc_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + data->cc.status = status; + data->cc.channel = event->data.control.channel & 0x0f; + data->cc.index = event->data.control.param; + data->cc.data = event->data.control.value; + return 1; +} + +/* convert one-parameter control event to MIDI 1.0 UMP */ +static int ctrl_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + data->caf.status = status; + data->caf.channel = event->data.control.channel & 0x0f; + data->caf.data = event->data.control.value & 0x7f; + return 1; +} + +/* convert pitchbend event to MIDI 1.0 UMP */ +static int pitchbend_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + int val = event->data.control.value + 8192; + + val = clamp(val, 0, 0x3fff); + data->pb.status = status; + data->pb.channel = event->data.control.channel & 0x0f; + data->pb.data_msb = (val >> 7) & 0x7f; + data->pb.data_lsb = val & 0x7f; + return 1; +} + +/* convert 14bit control event to MIDI 1.0 UMP; split to two events */ +static int ctrl14_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + data->cc.status = UMP_MSG_STATUS_CC; + data->cc.channel = event->data.control.channel & 0x0f; + data->cc.index = event->data.control.param & 0x7f; + if (event->data.control.param < 0x20) { + data->cc.data = (event->data.control.value >> 7) & 0x7f; + data[1] = data[0]; + data[1].cc.index = event->data.control.param | 0x20; + data[1].cc.data = event->data.control.value & 0x7f; + return 2; + } + + data->cc.data = event->data.control.value & 0x7f; + return 1; +} + +/* convert RPN/NRPN event to MIDI 1.0 UMP; split to four events */ +static int rpn_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + bool is_rpn = (status == UMP_MSG_STATUS_RPN); + + data->cc.status = UMP_MSG_STATUS_CC; + data->cc.channel = event->data.control.channel & 0x0f; + data[1] = data[2] = data[3] = data[0]; + + data[0].cc.index = is_rpn ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB; + data[0].cc.data = (event->data.control.param >> 7) & 0x7f; + data[1].cc.index = is_rpn ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB; + data[1].cc.data = event->data.control.param & 0x7f; + data[2].cc.index = UMP_CC_DATA; + data[2].cc.data = (event->data.control.value >> 7) & 0x7f; + data[3].cc.index = UMP_CC_DATA_LSB; + data[3].cc.data = event->data.control.value & 0x7f; + return 4; +} + +/* convert system / RT message to UMP */ +static int system_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + data->system.status = status; + return 1; +} + +/* convert system / RT message with 1 parameter to UMP */ +static int system_1p_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + data->system.status = status; + data->system.parm1 = event->data.control.value & 0x7f; + return 1; +} + +/* convert system / RT message with two parameters to UMP */ +static int system_2p_ev_to_ump_midi1(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status) +{ + data->system.status = status; + data->system.parm1 = (event->data.control.value >> 7) & 0x7f; + data->system.parm1 = event->data.control.value & 0x7f; + return 1; +} + +/* Conversion to UMP MIDI 2.0 */ + +/* convert note on/off event to MIDI 2.0 UMP */ +static int note_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + if (!event->data.note.velocity) + status = UMP_MSG_STATUS_NOTE_OFF; + data->note.status = status; + data->note.channel = event->data.note.channel & 0x0f; + data->note.note = event->data.note.note & 0x7f; + data->note.velocity = upscale_7_to_16bit(event->data.note.velocity & 0x7f); + return 1; +} + +/* convert PAF event to MIDI 2.0 UMP */ +static int paf_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + data->paf.status = status; + data->paf.channel = event->data.note.channel & 0x0f; + data->paf.note = event->data.note.note & 0x7f; + data->paf.data = upscale_7_to_32bit(event->data.note.velocity & 0x7f); + return 1; +} + +/* set up the MIDI2 RPN/NRPN packet data from the parsed info */ +static void fill_rpn(struct snd_seq_ump_midi2_bank *cc, + union snd_ump_midi2_msg *data) +{ + if (cc->rpn_set) { + data->rpn.status = UMP_MSG_STATUS_RPN; + data->rpn.bank = cc->cc_rpn_msb; + data->rpn.index = cc->cc_rpn_lsb; + cc->rpn_set = 0; + cc->cc_rpn_msb = cc->cc_rpn_lsb = 0; + } else { + data->rpn.status = UMP_MSG_STATUS_NRPN; + data->rpn.bank = cc->cc_nrpn_msb; + data->rpn.index = cc->cc_nrpn_lsb; + cc->nrpn_set = 0; + cc->cc_nrpn_msb = cc->cc_nrpn_lsb = 0; + } + data->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) | + cc->cc_data_lsb); + cc->cc_data_msb = cc->cc_data_lsb = 0; +} + +/* convert CC event to MIDI 2.0 UMP */ +static int cc_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + unsigned char channel = event->data.control.channel & 0x0f; + unsigned char index = event->data.control.param & 0x7f; + unsigned char val = event->data.control.value & 0x7f; + struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel]; + + /* process special CC's (bank/rpn/nrpn) */ + switch (index) { + case UMP_CC_RPN_MSB: + cc->rpn_set = 1; + cc->cc_rpn_msb = val; + return 0; // skip + case UMP_CC_RPN_LSB: + cc->rpn_set = 1; + cc->cc_rpn_lsb = val; + return 0; // skip + case UMP_CC_NRPN_MSB: + cc->nrpn_set = 1; + cc->cc_nrpn_msb = val; + return 0; // skip + case UMP_CC_NRPN_LSB: + cc->nrpn_set = 1; + cc->cc_nrpn_lsb = val; + return 0; // skip + case UMP_CC_DATA: + cc->cc_data_msb = val; + return 0; // skip + case UMP_CC_BANK_SELECT: + cc->bank_set = 1; + cc->cc_bank_msb = val; + return 0; // skip + case UMP_CC_BANK_SELECT_LSB: + cc->bank_set = 1; + cc->cc_bank_lsb = val; + return 0; // skip + case UMP_CC_DATA_LSB: + cc->cc_data_lsb = val; + if (!(cc->rpn_set || cc->nrpn_set)) + return 0; // skip + fill_rpn(cc, data); + return 1; + } + + data->cc.status = status; + data->cc.channel = channel; + data->cc.index = index; + data->cc.data = upscale_7_to_32bit(event->data.control.value & 0x7f); + return 1; +} + +/* convert one-parameter control event to MIDI 2.0 UMP */ +static int ctrl_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + data->caf.status = status; + data->caf.channel = event->data.control.channel & 0x0f; + data->caf.data = upscale_7_to_32bit(event->data.control.value & 0x7f); + return 1; +} + +/* convert program change event to MIDI 2.0 UMP */ +static int pgm_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + unsigned char channel = event->data.control.channel & 0x0f; + struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel]; + + data->pg.status = status; + data->pg.channel = channel; + data->pg.program = event->data.control.value & 0x7f; + if (cc->bank_set) { + data->pg.bank_valid = 1; + data->pg.bank_msb = cc->cc_bank_msb; + data->pg.bank_lsb = cc->cc_bank_lsb; + cc->bank_set = 0; + cc->cc_bank_msb = cc->cc_bank_lsb = 0; + } + return 1; +} + +/* convert pitchbend event to MIDI 2.0 UMP */ +static int pitchbend_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + int val = event->data.control.value + 8192; + + val = clamp(val, 0, 0x3fff); + data->pb.status = status; + data->pb.channel = event->data.control.channel & 0x0f; + data->pb.data = upscale_14_to_32bit(val); + return 1; +} + +/* convert 14bit control event to MIDI 2.0 UMP; split to two events */ +static int ctrl14_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + unsigned char channel = event->data.control.channel & 0x0f; + unsigned char index = event->data.control.param & 0x7f; + struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel]; + unsigned char msb, lsb; + + msb = (event->data.control.value >> 7) & 0x7f; + lsb = event->data.control.value & 0x7f; + /* process special CC's (bank/rpn/nrpn) */ + switch (index) { + case UMP_CC_BANK_SELECT: + cc->cc_bank_msb = msb; + fallthrough; + case UMP_CC_BANK_SELECT_LSB: + cc->bank_set = 1; + cc->cc_bank_lsb = lsb; + return 0; // skip + case UMP_CC_RPN_MSB: + cc->cc_rpn_msb = msb; + fallthrough; + case UMP_CC_RPN_LSB: + cc->rpn_set = 1; + cc->cc_rpn_lsb = lsb; + return 0; // skip + case UMP_CC_NRPN_MSB: + cc->cc_nrpn_msb = msb; + fallthrough; + case UMP_CC_NRPN_LSB: + cc->nrpn_set = 1; + cc->cc_nrpn_lsb = lsb; + return 0; // skip + case UMP_CC_DATA: + cc->cc_data_msb = msb; + fallthrough; + case UMP_CC_DATA_LSB: + cc->cc_data_lsb = lsb; + if (!(cc->rpn_set || cc->nrpn_set)) + return 0; // skip + fill_rpn(cc, data); + return 1; + } + + data->cc.status = UMP_MSG_STATUS_CC; + data->cc.channel = channel; + data->cc.index = index; + if (event->data.control.param < 0x20) { + data->cc.data = upscale_7_to_32bit(msb); + data[1] = data[0]; + data[1].cc.index = event->data.control.param | 0x20; + data[1].cc.data = upscale_7_to_32bit(lsb); + return 2; + } + + data->cc.data = upscale_7_to_32bit(lsb); + return 1; +} + +/* convert RPN/NRPN event to MIDI 2.0 UMP */ +static int rpn_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + data->rpn.status = status; + data->rpn.channel = event->data.control.channel; + data->rpn.bank = (event->data.control.param >> 7) & 0x7f; + data->rpn.index = event->data.control.param & 0x7f; + data->rpn.data = upscale_14_to_32bit(event->data.control.value & 0x3fff); + return 1; +} + +/* convert system / RT message to UMP */ +static int system_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + return system_ev_to_ump_midi1(event, dest_port, + (union snd_ump_midi1_msg *)data, + status); +} + +/* convert system / RT message with 1 parameter to UMP */ +static int system_1p_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + return system_1p_ev_to_ump_midi1(event, dest_port, + (union snd_ump_midi1_msg *)data, + status); +} + +/* convert system / RT message with two parameters to UMP */ +static int system_2p_ev_to_ump_midi2(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status) +{ + return system_1p_ev_to_ump_midi1(event, dest_port, + (union snd_ump_midi1_msg *)data, + status); +} + +struct seq_ev_to_ump { + int seq_type; + unsigned char status; + int (*midi1_encode)(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi1_msg *data, + unsigned char status); + int (*midi2_encode)(const struct snd_seq_event *event, + struct snd_seq_client_port *dest_port, + union snd_ump_midi2_msg *data, + unsigned char status); +}; + +static const struct seq_ev_to_ump seq_ev_ump_encoders[] = { + { SNDRV_SEQ_EVENT_NOTEON, UMP_MSG_STATUS_NOTE_ON, + note_ev_to_ump_midi1, note_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_NOTEOFF, UMP_MSG_STATUS_NOTE_OFF, + note_ev_to_ump_midi1, note_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_KEYPRESS, UMP_MSG_STATUS_POLY_PRESSURE, + note_ev_to_ump_midi1, paf_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_CONTROLLER, UMP_MSG_STATUS_CC, + cc_ev_to_ump_midi1, cc_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_PGMCHANGE, UMP_MSG_STATUS_PROGRAM, + ctrl_ev_to_ump_midi1, pgm_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_CHANPRESS, UMP_MSG_STATUS_CHANNEL_PRESSURE, + ctrl_ev_to_ump_midi1, ctrl_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_PITCHBEND, UMP_MSG_STATUS_PITCH_BEND, + pitchbend_ev_to_ump_midi1, pitchbend_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_CONTROL14, 0, + ctrl14_ev_to_ump_midi1, ctrl14_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_NONREGPARAM, UMP_MSG_STATUS_NRPN, + rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_REGPARAM, UMP_MSG_STATUS_RPN, + rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_QFRAME, UMP_SYSTEM_STATUS_MIDI_TIME_CODE, + system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_SONGPOS, UMP_SYSTEM_STATUS_SONG_POSITION, + system_2p_ev_to_ump_midi1, system_2p_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_SONGSEL, UMP_SYSTEM_STATUS_SONG_SELECT, + system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_TUNE_REQUEST, UMP_SYSTEM_STATUS_TUNE_REQUEST, + system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_CLOCK, UMP_SYSTEM_STATUS_TIMING_CLOCK, + system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_START, UMP_SYSTEM_STATUS_START, + system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_CONTINUE, UMP_SYSTEM_STATUS_CONTINUE, + system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_STOP, UMP_SYSTEM_STATUS_STOP, + system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, + { SNDRV_SEQ_EVENT_SENSING, UMP_SYSTEM_STATUS_ACTIVE_SENSING, + system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, +}; + +static const struct seq_ev_to_ump *find_ump_encoder(int type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(seq_ev_ump_encoders); i++) + if (seq_ev_ump_encoders[i].seq_type == type) + return &seq_ev_ump_encoders[i]; + + return NULL; +} + +static void setup_ump_event(struct snd_seq_ump_event *dest, + const struct snd_seq_event *src) +{ + memcpy(dest, src, sizeof(*src)); + dest->type = 0; + dest->flags |= SNDRV_SEQ_EVENT_UMP; + dest->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; + memset(dest->ump, 0, sizeof(dest->ump)); +} + +/* Convert ALSA seq event to UMP MIDI 1.0 and deliver it */ +static int cvt_to_ump_midi1(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop) +{ + const struct seq_ev_to_ump *encoder; + struct snd_seq_ump_event ev_cvt; + union snd_ump_midi1_msg data[4]; + int i, n, err; + + encoder = find_ump_encoder(event->type); + if (!encoder) + return __snd_seq_deliver_single_event(dest, dest_port, + event, atomic, hop); + + data->raw = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE); + n = encoder->midi1_encode(event, dest_port, data, encoder->status); + if (!n) + return 0; + + setup_ump_event(&ev_cvt, event); + for (i = 0; i < n; i++) { + ev_cvt.ump[0] = data[i].raw; + err = __snd_seq_deliver_single_event(dest, dest_port, + (struct snd_seq_event *)&ev_cvt, + atomic, hop); + if (err < 0) + return err; + } + + return 0; +} + +/* Convert ALSA seq event to UMP MIDI 2.0 and deliver it */ +static int cvt_to_ump_midi2(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop) +{ + const struct seq_ev_to_ump *encoder; + struct snd_seq_ump_event ev_cvt; + union snd_ump_midi2_msg data[2]; + int i, n, err; + + encoder = find_ump_encoder(event->type); + if (!encoder) + return __snd_seq_deliver_single_event(dest, dest_port, + event, atomic, hop); + + data->raw[0] = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE); + data->raw[1] = 0; + n = encoder->midi2_encode(event, dest_port, data, encoder->status); + if (!n) + return 0; + + setup_ump_event(&ev_cvt, event); + for (i = 0; i < n; i++) { + memcpy(ev_cvt.ump, &data[i], sizeof(data[i])); + err = __snd_seq_deliver_single_event(dest, dest_port, + (struct snd_seq_event *)&ev_cvt, + atomic, hop); + if (err < 0) + return err; + } + + return 0; +} + +/* Fill up a sysex7 UMP from the byte stream */ +static void fill_sysex7_ump(struct snd_seq_client_port *dest_port, + u32 *val, u8 status, u8 *buf, int len) +{ + memset(val, 0, 8); + memcpy((u8 *)val + 2, buf, len); +#ifdef __LITTLE_ENDIAN + swab32_array(val, 2); +#endif + val[0] |= ump_compose(UMP_MSG_TYPE_DATA, get_ump_group(dest_port), + status, len); +} + +/* Convert sysex var event to UMP sysex7 packets and deliver them */ +static int cvt_sysex_to_ump(struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop) +{ + struct snd_seq_ump_event ev_cvt; + unsigned char status; + u8 buf[6], *xbuf; + int offset = 0; + int len, err; + + if (!snd_seq_ev_is_variable(event)) + return 0; + + setup_ump_event(&ev_cvt, event); + for (;;) { + len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset); + if (len <= 0) + break; + if (WARN_ON(len > 6)) + break; + offset += len; + xbuf = buf; + if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) { + status = UMP_SYSEX_STATUS_START; + xbuf++; + len--; + if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { + status = UMP_SYSEX_STATUS_SINGLE; + len--; + } + } else { + if (xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { + status = UMP_SYSEX_STATUS_END; + len--; + } else { + status = UMP_SYSEX_STATUS_CONTINUE; + } + } + fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len); + err = __snd_seq_deliver_single_event(dest, dest_port, + (struct snd_seq_event *)&ev_cvt, + atomic, hop); + if (err < 0) + return err; + } + return 0; +} + +/* Convert to UMP packet and deliver */ +int snd_seq_deliver_to_ump(struct snd_seq_client *source, + struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop) +{ + if (event->type == SNDRV_SEQ_EVENT_SYSEX) + return cvt_sysex_to_ump(dest, dest_port, event, atomic, hop); + else if (snd_seq_client_is_midi2(dest)) + return cvt_to_ump_midi2(dest, dest_port, event, atomic, hop); + else + return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop); +} diff --git a/sound/core/seq/seq_ump_convert.h b/sound/core/seq/seq_ump_convert.h new file mode 100644 index 000000000000..6c146d803280 --- /dev/null +++ b/sound/core/seq/seq_ump_convert.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ALSA sequencer event conversion between UMP and legacy clients + */ +#ifndef __SEQ_UMP_CONVERT_H +#define __SEQ_UMP_CONVERT_H + +#include "seq_clientmgr.h" +#include "seq_ports.h" + +int snd_seq_deliver_from_ump(struct snd_seq_client *source, + struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop); +int snd_seq_deliver_to_ump(struct snd_seq_client *source, + struct snd_seq_client *dest, + struct snd_seq_client_port *dest_port, + struct snd_seq_event *event, + int atomic, int hop); + +#endif /* __SEQ_UMP_CONVERT_H */ From patchwork Tue May 23 07:53:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251802 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9264AC77B75 for ; Tue, 23 May 2023 08:02:35 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 3A8AAE11; Tue, 23 May 2023 10:01:43 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 3A8AAE11 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828953; bh=crSK8jdKGzpSJM1QPrgUffR0upGXdksheS9CrVZaMZg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=MIgqG7h/p11wuiyAnWfIjFBeTQicjzcxOtO4OItFAEmWQXm/b02QN/7CHBTbGd8LS zH6+D+MY0AGzFA0pQeZOT1LeRczglWJfgj27RNzY1XpTZj1yLHMsHs8O7vIKQFmj6y 48ezKDTfWjfs+bLksnK5+YeNcGxydsAnhaC0h82Y= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 76869F806BB; Tue, 23 May 2023 09:55:49 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id E70B4F806C0; Tue, 23 May 2023 09:55:48 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 104D2F80692; Tue, 23 May 2023 09:55:30 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 1763BF8057A for ; Tue, 23 May 2023 09:54:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 1763BF8057A Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=ARpDM/TB; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=VZSR6WqS Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id DC19320419; Tue, 23 May 2023 07:54:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828451; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ykdvugQv+oZ0dN/zBeueH0+m1vWwSeY55CmWxWBpKkQ=; b=ARpDM/TBwSXQiycNQBz8hKHuHb92rcfPQ4LmW+XtGPLMju2hHKZuerq0ArzUEu/wkH0On6 kg0adST4gJ+1PzNanwaofF2Y2HPNlWZDT4O2hWS551F62QNIKdqqqi0xKq/r81t/XuWjeW xiN//PdNRobBDYCxiOKLPA69fV8KMmI= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828451; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ykdvugQv+oZ0dN/zBeueH0+m1vWwSeY55CmWxWBpKkQ=; b=VZSR6WqSRhuVMani4T+Nwr2jKD1+MrUL4TfAdpfEk7EwgZvcgCg7DVFnuXh1FIhoTYh1y4 KGBqetoVcO670CDg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 7F85213588; Tue, 23 May 2023 07:54:11 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 8LniHSNxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:11 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 31/37] ALSA: seq: Allow suppressing UMP conversions Date: Tue, 23 May 2023 09:53:52 +0200 Message-Id: <20230523075358.9672-32-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: L7U7NEUWK5KYYM2KD4VL5SV3JEXHWNBW X-Message-ID-Hash: L7U7NEUWK5KYYM2KD4VL5SV3JEXHWNBW X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: A sequencer client like seq_dummy rather doesn't want to convert UMP events but receives / sends as is. Add a new event filter flag to suppress the automatic UMP conversion and applies accordingly. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 1 + sound/core/seq/seq_clientmgr.c | 18 ++++++++++-------- sound/core/seq/seq_dummy.c | 8 ++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index 2470eaa5edc5..c4632bd9d3a0 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -347,6 +347,7 @@ typedef int __bitwise snd_seq_client_type_t; #define SNDRV_SEQ_FILTER_BROADCAST (1U<<0) /* accept broadcast messages */ #define SNDRV_SEQ_FILTER_MULTICAST (1U<<1) /* accept multicast messages */ #define SNDRV_SEQ_FILTER_BOUNCE (1U<<2) /* accept bounce event in error */ +#define SNDRV_SEQ_FILTER_NO_CONVERT (1U<<30) /* don't convert UMP events */ #define SNDRV_SEQ_FILTER_USE_EVENT (1U<<31) /* use event filter */ struct snd_seq_client_info { diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 07b090f76b5f..3b1adcb1ccdd 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -671,14 +671,16 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, dest_port->time_real); #if IS_ENABLED(CONFIG_SND_SEQ_UMP) - if (snd_seq_ev_is_ump(event)) { - result = snd_seq_deliver_from_ump(client, dest, dest_port, - event, atomic, hop); - goto __skip; - } else if (snd_seq_client_is_ump(dest)) { - result = snd_seq_deliver_to_ump(client, dest, dest_port, - event, atomic, hop); - goto __skip; + if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) { + if (snd_seq_ev_is_ump(event)) { + result = snd_seq_deliver_from_ump(client, dest, dest_port, + event, atomic, hop); + goto __skip; + } else if (snd_seq_client_is_ump(dest)) { + result = snd_seq_deliver_to_ump(client, dest, dest_port, + event, atomic, hop); + goto __skip; + } } #endif /* CONFIG_SND_SEQ_UMP */ diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index 2e8844ee32ed..9308194b2d9a 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -152,6 +152,7 @@ static int __init register_client(void) { struct snd_seq_dummy_port *rec1, *rec2; + struct snd_seq_client *client; int i; if (ports < 1) { @@ -165,6 +166,13 @@ register_client(void) if (my_client < 0) return my_client; + /* don't convert events but just pass-through */ + client = snd_seq_kernel_client_get(my_client); + if (!client) + return -EINVAL; + client->filter = SNDRV_SEQ_FILTER_NO_CONVERT; + snd_seq_kernel_client_put(client); + /* create ports */ for (i = 0; i < ports; i++) { rec1 = create_port(i, 0); From patchwork Tue May 23 07:53:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251804 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 36C62C77B75 for ; Tue, 23 May 2023 08:03:04 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 4F640E93; Tue, 23 May 2023 10:02:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 4F640E93 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684828982; bh=Ki4uXyYFEdPwZ+pO6NImaRzFRg85z5WjAUMNnO541L4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=GjDdSs55UMqoJdiKTRCCFPy+cEe2mJccScd8ywgAzt9gapqVUW8lbsHURlItN660q jHMua4HxOxj1FEYqF71TOmJbPiESonelegpQ0r9NP8vxDIyNqGBxa1CeGGlFn+6z3v Xc1DTtkM7Xiq4O94S3N1qCT1qcHobkqdd793ttl8= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 4445AF806C3; Tue, 23 May 2023 09:56:00 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 2C5C7F806CD; Tue, 23 May 2023 09:56:00 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 3CA0FF806BD; Tue, 23 May 2023 09:55:48 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 5D2EDF8057E for ; Tue, 23 May 2023 09:54:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 5D2EDF8057E Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=mRxkbmG/; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=czbkBmd6 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 26BF921AC4; Tue, 23 May 2023 07:54:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828452; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HaXvJ3FZXx/ZZA9swPFXqNVogZH19QDVyoLkE+uk0Ns=; b=mRxkbmG/Z0dZ732M8et4jZfMolajmPk2Ii++Uem+2RXV4a1+m3JqJzNG1Gbe6eUJjTR5Yj g7mEXTxZBO5UGTcbEL2fYeNMqhZLpIgd/ZDq6TnjXGdvpxSrJVVSCXMmEeUUEZlUg2lP4a mBacI1fPn2/9GTWeAuePRcXMZxbpbGo= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828452; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HaXvJ3FZXx/ZZA9swPFXqNVogZH19QDVyoLkE+uk0Ns=; b=czbkBmd6ZjenlUqYv3CkbPTklYdOsG3+bT7bsd8lp/FjLY0Me9Dfo5iQagVEtMtNivxlSk QKRM6w4b/cbg3TAQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id C599F13A1A; Tue, 23 May 2023 07:54:11 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id YO6MLiNxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:11 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 32/37] ALSA: seq: Bind UMP device Date: Tue, 23 May 2023 09:53:53 +0200 Message-Id: <20230523075358.9672-33-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: WHHAW6DG7GATOB3KXDXEDCIDSNMZWNV6 X-Message-ID-Hash: WHHAW6DG7GATOB3KXDXEDCIDSNMZWNV6 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This patch introduces a new ALSA sequencer client for the kernel UMP object, snd-seq-ump-client. It's a UMP version of snd-seq-midi driver, while this driver creates a sequencer client per UMP endpoint which contains (fixed) 16 ports. The UMP rawmidi device is opened in APPEND mode for output, so that multiple sequencer clients can share the same UMP endpoint, as well as the legacy UMP rawmidi devices that are opened in APPEND mode, too. For input, on the other hand, the incoming data is processed on the fly in the dedicated hook, hence it doesn't open a rawmidi device. The UMP packet group is updated upon delivery depending on the target sequencer port (which corresponds to the actual UMP group). Each sequencer port sets a new port type bit, SNDRV_SEQ_PORT_TYPE_MIDI_UMP, in addition to the other standard types for MIDI. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/seq_device.h | 1 + include/sound/ump.h | 15 +- include/uapi/sound/asequencer.h | 1 + sound/core/seq/Kconfig | 5 + sound/core/seq/Makefile | 2 + sound/core/seq/seq_ump_client.c | 389 ++++++++++++++++++++++++++++++++ sound/core/ump.c | 28 ++- 7 files changed, 439 insertions(+), 2 deletions(-) create mode 100644 sound/core/seq/seq_ump_client.c diff --git a/include/sound/seq_device.h b/include/sound/seq_device.h index 8899affe9155..dead74b022f4 100644 --- a/include/sound/seq_device.h +++ b/include/sound/seq_device.h @@ -78,5 +78,6 @@ void snd_seq_driver_unregister(struct snd_seq_driver *drv); */ #define SNDRV_SEQ_DEV_ID_MIDISYNTH "seq-midi" #define SNDRV_SEQ_DEV_ID_OPL3 "opl3-synth" +#define SNDRV_SEQ_DEV_ID_UMP "seq-ump-client" #endif /* __SOUND_SEQ_DEVICE_H */ diff --git a/include/sound/ump.h b/include/sound/ump.h index 45f4c9b673b5..e4fdf7cccf12 100644 --- a/include/sound/ump.h +++ b/include/sound/ump.h @@ -11,6 +11,7 @@ struct snd_ump_endpoint; struct snd_ump_block; struct snd_ump_ops; struct ump_cvt_to_ump; +struct snd_seq_ump_ops; struct snd_ump_endpoint { struct snd_rawmidi core; /* raw UMP access */ @@ -30,9 +31,9 @@ struct snd_ump_endpoint { int input_buf_head; int input_pending; -#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) struct mutex open_mutex; +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) spinlock_t legacy_locks[2]; struct snd_rawmidi *legacy_rmidi; struct snd_rawmidi_substream *legacy_substreams[2][SNDRV_UMP_MAX_GROUPS]; @@ -42,6 +43,12 @@ struct snd_ump_endpoint { struct snd_rawmidi_file legacy_out_rfile; struct ump_cvt_to_ump *out_cvts; #endif + +#if IS_ENABLED(CONFIG_SND_SEQUENCER) + struct snd_seq_device *seq_dev; + const struct snd_seq_ump_ops *seq_ops; + void *seq_client; +#endif }; /* ops filled by UMP drivers */ @@ -52,6 +59,12 @@ struct snd_ump_ops { void (*drain)(struct snd_ump_endpoint *ump, int dir); }; +/* ops filled by sequencer binding */ +struct snd_seq_ump_ops { + void (*input_receive)(struct snd_ump_endpoint *ump, + const u32 *data, int words); +}; + struct snd_ump_block { struct snd_ump_block_info info; struct snd_ump_endpoint *ump; diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index c4632bd9d3a0..3fa6b17aa7a2 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -439,6 +439,7 @@ struct snd_seq_remove_events { #define SNDRV_SEQ_PORT_TYPE_MIDI_XG (1<<4) /* XG compatible device */ #define SNDRV_SEQ_PORT_TYPE_MIDI_MT32 (1<<5) /* MT-32 compatible device */ #define SNDRV_SEQ_PORT_TYPE_MIDI_GM2 (1<<6) /* General MIDI 2 compatible device */ +#define SNDRV_SEQ_PORT_TYPE_MIDI_UMP (1<<7) /* UMP */ /* other standards...*/ #define SNDRV_SEQ_PORT_TYPE_SYNTH (1<<10) /* Synth device (no MIDI compatible - direct wavetable) */ diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index f8336134153e..c14981daf943 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig @@ -62,6 +62,7 @@ config SND_SEQ_VIRMIDI config SND_SEQ_UMP bool "Support for UMP events" + default y if SND_SEQ_UMP_CLIENT help Say Y here to enable the support for handling UMP (Universal MIDI Packet) events via ALSA sequencer infrastructure, which is an @@ -69,4 +70,8 @@ config SND_SEQ_UMP It includes the automatic conversion of ALSA sequencer events among legacy and UMP clients. +config SND_SEQ_UMP_CLIENT + tristate + def_tristate SND_UMP + endif # SND_SEQUENCER diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index ba264a695643..990eec7c83ad 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -14,12 +14,14 @@ snd-seq-midi-emul-objs := seq_midi_emul.o snd-seq-midi-event-objs := seq_midi_event.o snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o +snd-seq-ump-client-objs := seq_ump_client.o obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o obj-$(CONFIG_SND_SEQ_MIDI) += snd-seq-midi.o +obj-$(CONFIG_SND_SEQ_UMP_CLIENT) += snd-seq-ump-client.o obj-$(CONFIG_SND_SEQ_MIDI_EMUL) += snd-seq-midi-emul.o obj-$(CONFIG_SND_SEQ_MIDI_EVENT) += snd-seq-midi-event.o obj-$(CONFIG_SND_SEQ_VIRMIDI) += snd-seq-virmidi.o diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c new file mode 100644 index 000000000000..8d360655ff5d --- /dev/null +++ b/sound/core/seq/seq_ump_client.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* ALSA sequencer binding for UMP device */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "seq_clientmgr.h" + +struct seq_ump_client; +struct seq_ump_group; + +enum { + STR_IN = SNDRV_RAWMIDI_STREAM_INPUT, + STR_OUT = SNDRV_RAWMIDI_STREAM_OUTPUT +}; + +/* object per UMP group; corresponding to a sequencer port */ +struct seq_ump_group { + int group; /* group index (0-based) */ + unsigned int dir_bits; /* directions */ + bool active; /* activeness */ + char name[64]; /* seq port name */ +}; + +/* context for UMP input parsing, per EP */ +struct seq_ump_input_buffer { + unsigned char len; /* total length in words */ + unsigned char pending; /* pending words */ + unsigned char type; /* parsed UMP packet type */ + unsigned char group; /* parsed UMP packet group */ + u32 buf[4]; /* incoming UMP packet */ +}; + +/* sequencer client, per UMP EP (rawmidi) */ +struct seq_ump_client { + struct snd_ump_endpoint *ump; /* assigned endpoint */ + int seq_client; /* sequencer client id */ + int opened[2]; /* current opens for each direction */ + struct snd_rawmidi_file out_rfile; /* rawmidi for output */ + struct seq_ump_input_buffer input; /* input parser context */ + struct seq_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */ +}; + +/* number of 32bit words for each UMP message type */ +static unsigned char ump_packet_words[0x10] = { + 1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4 +}; + +/* conversion between UMP group and seq port; + * assume the port number is equal with UMP group number (1-based) + */ +static unsigned char ump_group_to_seq_port(unsigned char group) +{ + return group + 1; +} + +/* process the incoming rawmidi stream */ +static void seq_ump_input_receive(struct snd_ump_endpoint *ump, + const u32 *val, int words) +{ + struct seq_ump_client *client = ump->seq_client; + struct snd_seq_ump_event ev = {}; + + if (!client->opened[STR_IN]) + return; + + ev.source.port = ump_group_to_seq_port(ump_message_group(*val)); + ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; + ev.flags = SNDRV_SEQ_EVENT_UMP; + memcpy(ev.ump, val, words << 2); + snd_seq_kernel_client_dispatch(client->seq_client, + (struct snd_seq_event *)&ev, + true, 0); +} + +/* process an input sequencer event; only deal with UMP types */ +static int seq_ump_process_event(struct snd_seq_event *ev, int direct, + void *private_data, int atomic, int hop) +{ + struct seq_ump_client *client = private_data; + struct snd_rawmidi_substream *substream; + struct snd_seq_ump_event *ump_ev; + unsigned char type; + int len; + + substream = client->out_rfile.output; + if (!substream) + return -ENODEV; + if (!snd_seq_ev_is_ump(ev)) + return 0; /* invalid event, skip */ + ump_ev = (struct snd_seq_ump_event *)ev; + type = ump_message_type(ump_ev->ump[0]); + len = ump_packet_words[type]; + if (len > 4) + return 0; // invalid - skip + snd_rawmidi_kernel_write(substream, ev->data.raw8.d, len << 2); + return 0; +} + +/* open the rawmidi */ +static int seq_ump_client_open(struct seq_ump_client *client, int dir) +{ + struct snd_ump_endpoint *ump = client->ump; + int err = 0; + + mutex_lock(&ump->open_mutex); + if (dir == STR_OUT && !client->opened[dir]) { + err = snd_rawmidi_kernel_open(&ump->core, 0, + SNDRV_RAWMIDI_LFLG_OUTPUT | + SNDRV_RAWMIDI_LFLG_APPEND, + &client->out_rfile); + if (err < 0) + goto unlock; + } + client->opened[dir]++; + unlock: + mutex_unlock(&ump->open_mutex); + return err; +} + +/* close the rawmidi */ +static int seq_ump_client_close(struct seq_ump_client *client, int dir) +{ + struct snd_ump_endpoint *ump = client->ump; + + mutex_lock(&ump->open_mutex); + if (!--client->opened[dir]) + if (dir == STR_OUT) + snd_rawmidi_kernel_release(&client->out_rfile); + mutex_unlock(&ump->open_mutex); + return 0; +} + +/* sequencer subscription ops for each client */ +static int seq_ump_subscribe(void *pdata, struct snd_seq_port_subscribe *info) +{ + struct seq_ump_client *client = pdata; + + return seq_ump_client_open(client, STR_IN); +} + +static int seq_ump_unsubscribe(void *pdata, struct snd_seq_port_subscribe *info) +{ + struct seq_ump_client *client = pdata; + + return seq_ump_client_close(client, STR_IN); +} + +static int seq_ump_use(void *pdata, struct snd_seq_port_subscribe *info) +{ + struct seq_ump_client *client = pdata; + + return seq_ump_client_open(client, STR_OUT); +} + +static int seq_ump_unuse(void *pdata, struct snd_seq_port_subscribe *info) +{ + struct seq_ump_client *client = pdata; + + return seq_ump_client_close(client, STR_OUT); +} + +/* fill port_info from the given UMP EP and group info */ +static void fill_port_info(struct snd_seq_port_info *port, + struct seq_ump_client *client, + struct seq_ump_group *group) +{ + unsigned int rawmidi_info = client->ump->core.info_flags; + + port->addr.client = client->seq_client; + port->addr.port = ump_group_to_seq_port(group->group); + port->capability = 0; + if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) + port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | + SNDRV_SEQ_PORT_CAP_SYNC_WRITE | + SNDRV_SEQ_PORT_CAP_SUBS_WRITE; + if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) + port->capability |= SNDRV_SEQ_PORT_CAP_READ | + SNDRV_SEQ_PORT_CAP_SYNC_READ | + SNDRV_SEQ_PORT_CAP_SUBS_READ; + if (rawmidi_info & SNDRV_RAWMIDI_INFO_DUPLEX) + port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; + if (group->dir_bits & (1 << STR_IN)) + port->direction |= SNDRV_SEQ_PORT_DIR_INPUT; + if (group->dir_bits & (1 << STR_OUT)) + port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT; + port->ump_group = group->group + 1; + if (!group->active) + port->capability |= SNDRV_SEQ_PORT_CAP_INACTIVE; + port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | + SNDRV_SEQ_PORT_TYPE_MIDI_UMP | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_PORT; + port->midi_channels = 16; + if (*group->name) + snprintf(port->name, sizeof(port->name), "Group %d (%s)", + group->group + 1, group->name); + else + sprintf(port->name, "Group %d", group->group + 1); +} + +/* create a new sequencer port per UMP group */ +static int seq_ump_group_init(struct seq_ump_client *client, int group_index) +{ + struct seq_ump_group *group = &client->groups[group_index]; + struct snd_seq_port_info *port; + struct snd_seq_port_callback pcallbacks; + int err; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) { + err = -ENOMEM; + goto error; + } + + fill_port_info(port, client, group); + port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; + memset(&pcallbacks, 0, sizeof(pcallbacks)); + pcallbacks.owner = THIS_MODULE; + pcallbacks.private_data = client; + pcallbacks.subscribe = seq_ump_subscribe; + pcallbacks.unsubscribe = seq_ump_unsubscribe; + pcallbacks.use = seq_ump_use; + pcallbacks.unuse = seq_ump_unuse; + pcallbacks.event_input = seq_ump_process_event; + port->kernel = &pcallbacks; + err = snd_seq_kernel_client_ctl(client->seq_client, + SNDRV_SEQ_IOCTL_CREATE_PORT, + port); + error: + kfree(port); + return err; +} + +/* update dir_bits and active flag for all groups in the client */ +static void update_group_attrs(struct seq_ump_client *client) +{ + struct snd_ump_block *fb; + struct seq_ump_group *group; + int i; + + for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) { + group = &client->groups[i]; + *group->name = 0; + group->dir_bits = 0; + group->active = 0; + group->group = i; + } + + list_for_each_entry(fb, &client->ump->block_list, list) { + if (fb->info.first_group < 0 || + fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS) + break; + group = &client->groups[fb->info.first_group]; + for (i = 0; i < fb->info.num_groups; i++, group++) { + if (fb->info.active) + group->active = 1; + switch (fb->info.direction) { + case SNDRV_UMP_DIR_INPUT: + group->dir_bits |= (1 << STR_IN); + break; + case SNDRV_UMP_DIR_OUTPUT: + group->dir_bits |= (1 << STR_OUT); + break; + case SNDRV_UMP_DIR_BIDIRECTION: + group->dir_bits |= (1 << STR_OUT) | (1 << STR_IN); + break; + } + if (!*fb->info.name) + continue; + if (!*group->name) { + /* store the first matching name */ + strscpy(group->name, fb->info.name, + sizeof(group->name)); + } else { + /* when overlapping, concat names */ + strlcat(group->name, ", ", sizeof(group->name)); + strlcat(group->name, fb->info.name, + sizeof(group->name)); + } + } + } +} + +/* release the client resources */ +static void seq_ump_client_free(struct seq_ump_client *client) +{ + if (client->seq_client >= 0) + snd_seq_delete_kernel_client(client->seq_client); + + client->ump->seq_ops = NULL; + client->ump->seq_client = NULL; + + kfree(client); +} + +/* update the MIDI version for the given client */ +static void setup_client_midi_version(struct seq_ump_client *client) +{ + struct snd_seq_client *cptr; + + cptr = snd_seq_kernel_client_get(client->seq_client); + if (!cptr) + return; + if (client->ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2) + cptr->midi_version = SNDRV_SEQ_CLIENT_UMP_MIDI_2_0; + else + cptr->midi_version = SNDRV_SEQ_CLIENT_UMP_MIDI_1_0; + snd_seq_kernel_client_put(cptr); +} + +static const struct snd_seq_ump_ops seq_ump_ops = { + .input_receive = seq_ump_input_receive, +}; + +/* create a sequencer client and ports for the given UMP endpoint */ +static int snd_seq_ump_probe(struct device *_dev) +{ + struct snd_seq_device *dev = to_seq_dev(_dev); + struct snd_ump_endpoint *ump = dev->private_data; + struct snd_card *card = dev->card; + struct seq_ump_client *client; + int p, err; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->ump = ump; + + client->seq_client = + snd_seq_create_kernel_client(card, ump->core.device, + ump->core.name); + if (client->seq_client < 0) { + err = client->seq_client; + goto error; + } + + setup_client_midi_version(client); + update_group_attrs(client); + + for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) { + err = seq_ump_group_init(client, p); + if (err < 0) + goto error; + } + + ump->seq_client = client; + ump->seq_ops = &seq_ump_ops; + return 0; + + error: + seq_ump_client_free(client); + return err; +} + +/* remove a sequencer client */ +static int snd_seq_ump_remove(struct device *_dev) +{ + struct snd_seq_device *dev = to_seq_dev(_dev); + struct snd_ump_endpoint *ump = dev->private_data; + + if (ump->seq_client) + seq_ump_client_free(ump->seq_client); + return 0; +} + +static struct snd_seq_driver seq_ump_driver = { + .driver = { + .name = KBUILD_MODNAME, + .probe = snd_seq_ump_probe, + .remove = snd_seq_ump_remove, + }, + .id = SNDRV_SEQ_DEV_ID_UMP, + .argsize = 0, +}; + +module_snd_seq_driver(seq_ump_driver); + +MODULE_DESCRIPTION("ALSA sequencer client for UMP rawmidi"); +MODULE_LICENSE("GPL"); diff --git a/sound/core/ump.c b/sound/core/ump.c index cbe704b5d90d..69993cad6772 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -132,8 +132,8 @@ int snd_ump_endpoint_new(struct snd_card *card, char *id, int device, if (!ump) return -ENOMEM; INIT_LIST_HEAD(&ump->block_list); -#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) mutex_init(&ump->open_mutex); +#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) spin_lock_init(&ump->legacy_locks[0]); spin_lock_init(&ump->legacy_locks[1]); #endif @@ -166,8 +166,30 @@ EXPORT_SYMBOL_GPL(snd_ump_endpoint_new); * Device register / unregister hooks; * do nothing, placeholders for avoiding the default rawmidi handling */ + +#if IS_ENABLED(CONFIG_SND_SEQUENCER) +static void snd_ump_dev_seq_free(struct snd_seq_device *device) +{ + struct snd_ump_endpoint *ump = device->private_data; + + ump->seq_dev = NULL; +} +#endif + static int snd_ump_dev_register(struct snd_rawmidi *rmidi) { +#if IS_ENABLED(CONFIG_SND_SEQUENCER) + struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); + int err; + + err = snd_seq_device_new(ump->core.card, ump->core.device, + SNDRV_SEQ_DEV_ID_UMP, 0, &ump->seq_dev); + if (err < 0) + return err; + ump->seq_dev->private_data = ump; + ump->seq_dev->private_free = snd_ump_dev_seq_free; + snd_device_register(ump->core.card, ump->seq_dev); +#endif return 0; } @@ -280,6 +302,10 @@ int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count) n = snd_ump_receive_ump_val(ump, *p++); if (!n) continue; +#if IS_ENABLED(CONFIG_SND_SEQUENCER) + if (ump->seq_ops) + ump->seq_ops->input_receive(ump, ump->input_buf, n); +#endif process_legacy_input(ump, ump->input_buf, n); } From patchwork Tue May 23 07:53:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251805 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1DC48C7EE23 for ; Tue, 23 May 2023 08:03:26 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 3952082A; Tue, 23 May 2023 10:02:34 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 3952082A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829004; bh=bPRhjAk5GH+D2toyh6ZBzOssO9HUZjgQtZnxnzbjG+I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=NfDvrUQwI4fHhOiC5Ibc5jW00ATgUHLonn6WMFUlwFzQ7vrPjeJsVl5FPtLMElj6D 4Z/cn2ZQOlrj6q9swnKhO9JiznjiNc/jI+rfMEOWidLz225KSuSXBiyE0T6CTuH03C at+24b7MK4QX9KQblCSZgUtMO4VT7aKuZUYyD7wc= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 70336F806DC; Tue, 23 May 2023 09:56:05 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 77FBFF806D1; Tue, 23 May 2023 09:56:04 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 4FD83F806C2; Tue, 23 May 2023 09:55:49 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 7BDDBF8057F for ; Tue, 23 May 2023 09:54:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 7BDDBF8057F Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=pGb4yt/1; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=HyphhFOp Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 59C2E2041A; Tue, 23 May 2023 07:54:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828452; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lOTcZ9DIk5No118bn2nnkWGzCS2/GY1r2cgjHjJmqlU=; b=pGb4yt/1Unx5AMGYBOE6YXbBkoRHdWIXYyGy5gTMsXXt6p+0pt3f7LcGD1tUzhFV2lwTKJ Ir4tsTFsrNKR5TEHpbGBlf6YGnV7X7wVWzo5QP3wOTZfljys5H3wpRd3LGKRfslm46yqBg lTFiyfasqQE21Hr/uwkTHh6EoOJ+PTA= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828452; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lOTcZ9DIk5No118bn2nnkWGzCS2/GY1r2cgjHjJmqlU=; b=HyphhFOpNX++GJhHbWTtU77kQFyGUMgeYvmXoMBxx/rfGH255jbRnJPtdc9jki/G0z3//Y +gIWqgtcW7QvS7CA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 1A12813588; Tue, 23 May 2023 07:54:12 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id gHgCBSRxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:12 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 33/37] ALSA: seq: ump: Create UMP Endpoint port for broadcast Date: Tue, 23 May 2023 09:53:54 +0200 Message-Id: <20230523075358.9672-34-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: JX2CLJZS2VJJHVH5QKAZIJ22R6SZRFQI X-Message-ID-Hash: JX2CLJZS2VJJHVH5QKAZIJ22R6SZRFQI X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: <> List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Create a sequencer port for broadcasting the all group inputs at the port number 0. This corresponds to a UMP Endpoint connection; application can read all UMP events from this port no matter which group the UMP packet belongs to. Unlike seq ports for other UMP groups, a UMP Endpoint port has no SND_SEQ_PORT_TYPE_MIDI_GENERIC bit, so that it won't be treated as a normal MIDI 1.0 device from legacy applications. The port is named as "MIDI 2.0" to align with representations on other operation systems. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/seq_ump_client.c | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c index 8d360655ff5d..600b061ac8c3 100644 --- a/sound/core/seq/seq_ump_client.c +++ b/sound/core/seq/seq_ump_client.c @@ -290,6 +290,62 @@ static void update_group_attrs(struct seq_ump_client *client) } } +/* create a UMP Endpoint port */ +static int create_ump_endpoint_port(struct seq_ump_client *client) +{ + struct snd_seq_port_info *port; + struct snd_seq_port_callback pcallbacks; + unsigned int rawmidi_info = client->ump->core.info_flags; + int err; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->addr.client = client->seq_client; + port->addr.port = 0; /* fixed */ + port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; + port->capability = SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT; + if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) { + port->capability |= SNDRV_SEQ_PORT_CAP_READ | + SNDRV_SEQ_PORT_CAP_SYNC_READ | + SNDRV_SEQ_PORT_CAP_SUBS_READ; + port->direction |= SNDRV_SEQ_PORT_DIR_INPUT; + } + if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) { + port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | + SNDRV_SEQ_PORT_CAP_SYNC_WRITE | + SNDRV_SEQ_PORT_CAP_SUBS_WRITE; + port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT; + } + if (rawmidi_info & SNDRV_RAWMIDI_INFO_DUPLEX) + port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; + port->ump_group = 0; /* no associated group, no conversion */ + port->type = SNDRV_SEQ_PORT_TYPE_MIDI_UMP | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_PORT; + port->midi_channels = 16; + strcpy(port->name, "MIDI 2.0"); + memset(&pcallbacks, 0, sizeof(pcallbacks)); + pcallbacks.owner = THIS_MODULE; + pcallbacks.private_data = client; + if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) { + pcallbacks.subscribe = seq_ump_subscribe; + pcallbacks.unsubscribe = seq_ump_unsubscribe; + } + if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) { + pcallbacks.use = seq_ump_use; + pcallbacks.unuse = seq_ump_unuse; + pcallbacks.event_input = seq_ump_process_event; + } + port->kernel = &pcallbacks; + err = snd_seq_kernel_client_ctl(client->seq_client, + SNDRV_SEQ_IOCTL_CREATE_PORT, + port); + kfree(port); + return err; +} + /* release the client resources */ static void seq_ump_client_free(struct seq_ump_client *client) { @@ -353,6 +409,10 @@ static int snd_seq_ump_probe(struct device *_dev) goto error; } + err = create_ump_endpoint_port(client); + if (err < 0) + goto error; + ump->seq_client = client; ump->seq_ops = &seq_ump_ops; return 0; From patchwork Tue May 23 07:53:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251807 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5EEB6C77B75 for ; Tue, 23 May 2023 08:04:03 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 511EFE88; Tue, 23 May 2023 10:03:11 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 511EFE88 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829041; bh=v/VMMCGDFx31LhFtLZJM/13EXSC2ClBrNLvyuyDA9iY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=JfoYJabQb+XPTSFcEkwUveaiLyqR0EI1VxIRZNDqkv7S6TaZKPQ2906ZBwogFf2Xk lW3UW0pBiwT45GxpDYu7Y+Qir5oTFtUDGqZTxFbC+QNoK4DcMgSPILR4DEOFRFlQZW ROJ8eM/f0nNMZ4jV8EL6VB0WTB8nNETF8ypYPlS4= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 2DDB6F806E8; Tue, 23 May 2023 09:56:11 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 3FBC8F805E5; Tue, 23 May 2023 09:56:11 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 85CD6F806C0; Tue, 23 May 2023 09:55:53 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id DB49DF80086 for ; Tue, 23 May 2023 09:54:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz DB49DF80086 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=aaJRyh4s; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=/8mwtXmx Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 92F8521B10; Tue, 23 May 2023 07:54:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828452; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+VA/WrJJegm1Ay7NPirvOeFMKFPeb95a1/jKrr24UbE=; b=aaJRyh4sFpjNqCrTCopyym9NXknyjC08PF5EjYtxHnesTwZcCS51rLL2pioTu5Vy2MPahv 5/wEScvskbA5d2Si95V0yTUDtrLzXc5LAm+rM9QedPtbr9bwHro06dDxEHSSAPV19cM5ie NGNpfN9R5cvAUzMF4fBhLOKcOGI+lcs= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828452; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+VA/WrJJegm1Ay7NPirvOeFMKFPeb95a1/jKrr24UbE=; b=/8mwtXmxiCRVG20SxuXvU41UBX0f6cqlo8lOTVJK8vqQ+AkhPcbjPnPKHumgzbiLQQFK7s NjN+/9ULv0HoCRAQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 4FA4713A1A; Tue, 23 May 2023 07:54:12 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id sFtzEiRxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:12 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 34/37] ALSA: seq: Add ioctls for client UMP info query and setup Date: Tue, 23 May 2023 09:53:55 +0200 Message-Id: <20230523075358.9672-35-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: QYRSHP46Z4QN6LYZH5FLVD7T62FBA7PV X-Message-ID-Hash: QYRSHP46Z4QN6LYZH5FLVD7T62FBA7PV X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add new ioctls for sequencer clients to query and set the UMP endpoint and block information. As a sequencer client corresponds to a UMP Endpoint, one UMP Endpoint information can be assigned at most to a single sequencer client while multiple UMP block infos can be assigned by passing the type with the offset of block id (i.e. type = block_id + 1). For the kernel client, only SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO is allowed. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 14 ++++ sound/core/seq/seq_clientmgr.c | 120 +++++++++++++++++++++++++++++++- sound/core/seq/seq_clientmgr.h | 4 +- sound/core/seq/seq_compat.c | 2 + sound/core/seq/seq_ump_client.c | 15 ++++ 5 files changed, 153 insertions(+), 2 deletions(-) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index 3fa6b17aa7a2..c75f594f21e3 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -585,6 +585,18 @@ struct snd_seq_query_subs { char reserved[64]; /* for future use */ }; +/* + * UMP-specific information + */ +/* type of UMP info query */ +#define SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT 0 +#define SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK 1 + +struct snd_seq_client_ump_info { + int client; /* client number to inquire/set */ + int type; /* type to inquire/set */ + unsigned char info[512]; /* info (either UMP ep or block info) */ +} __packed; /* * IOCTL commands @@ -598,6 +610,8 @@ struct snd_seq_query_subs { #define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO _IOWR('S', 0x10, struct snd_seq_client_info) #define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO _IOW ('S', 0x11, struct snd_seq_client_info) +#define SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO _IOWR('S', 0x12, struct snd_seq_client_ump_info) +#define SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO _IOWR('S', 0x13, struct snd_seq_client_ump_info) #define SNDRV_SEQ_IOCTL_CREATE_PORT _IOWR('S', 0x20, struct snd_seq_port_info) #define SNDRV_SEQ_IOCTL_DELETE_PORT _IOW ('S', 0x21, struct snd_seq_port_info) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 3b1adcb1ccdd..03ca78ea2cce 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -14,6 +14,7 @@ #include #include +#include #include "seq_clientmgr.h" #include "seq_memory.h" #include "seq_queue.h" @@ -71,6 +72,10 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, struct snd_seq_event *event, int filter, int atomic, int hop); +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) +static void free_ump_info(struct snd_seq_client *client); +#endif + /* */ static inline unsigned short snd_seq_file_flags(struct file *file) @@ -382,6 +387,9 @@ static int snd_seq_release(struct inode *inode, struct file *file) seq_free_client(client); if (client->data.user.fifo) snd_seq_fifo_delete(&client->data.user.fifo); +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) + free_ump_info(client); +#endif put_pid(client->data.user.owner); kfree(client); } @@ -1282,7 +1290,6 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client, if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3)) client->midi_version = client_info->midi_version; memcpy(client->event_filter, client_info->event_filter, 32); - return 0; } @@ -2087,6 +2094,108 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client, return 0; } +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) +#define NUM_UMP_INFOS (SNDRV_UMP_MAX_BLOCKS + 1) + +static void free_ump_info(struct snd_seq_client *client) +{ + int i; + + if (!client->ump_info) + return; + for (i = 0; i < NUM_UMP_INFOS; i++) + kfree(client->ump_info[i]); + kfree(client->ump_info); + client->ump_info = NULL; +} + +static void terminate_ump_info_strings(void *p, int type) +{ + if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) { + struct snd_ump_endpoint_info *ep = p; + ep->name[sizeof(ep->name) - 1] = 0; + } else { + struct snd_ump_block_info *bp = p; + bp->name[sizeof(bp->name) - 1] = 0; + } +} + +/* UMP-specific ioctls -- called directly without data copy */ +static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, + unsigned int cmd, + unsigned long arg) +{ + struct snd_seq_client_ump_info __user *argp = + (struct snd_seq_client_ump_info __user *)arg; + struct snd_seq_client *cptr; + int client, type, err = 0; + size_t size; + void *p; + + if (get_user(client, &argp->client) || get_user(type, &argp->type)) + return -EFAULT; + if (cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO && + caller->number != client) + return -EPERM; + if (type < 0 || type >= NUM_UMP_INFOS) + return -EINVAL; + if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) + size = sizeof(struct snd_ump_endpoint_info); + else + size = sizeof(struct snd_ump_block_info); + cptr = snd_seq_client_use_ptr(client); + if (!cptr) + return -ENOENT; + + mutex_lock(&cptr->ioctl_mutex); + if (!cptr->midi_version) { + err = -EBADFD; + goto error; + } + + if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) { + if (!cptr->ump_info) + p = NULL; + else + p = cptr->ump_info[type]; + if (!p) { + err = -ENODEV; + goto error; + } + if (copy_to_user(argp->info, p, size)) { + err = -EFAULT; + goto error; + } + } else { + if (cptr->type != USER_CLIENT) { + err = -EBADFD; + goto error; + } + if (!cptr->ump_info) { + cptr->ump_info = kcalloc(NUM_UMP_INFOS, + sizeof(void *), GFP_KERNEL); + if (!cptr->ump_info) { + err = -ENOMEM; + goto error; + } + } + p = memdup_user(argp->info, size); + if (IS_ERR(p)) { + err = PTR_ERR(p); + goto error; + } + kfree(cptr->ump_info[type]); + terminate_ump_info_strings(p, type); + cptr->ump_info[type] = p; + } + + error: + mutex_unlock(&cptr->ioctl_mutex); + snd_seq_client_unlock(cptr); + return err; +} +#endif + /* -------------------------------------------------------- */ static const struct ioctl_handler { @@ -2157,6 +2266,15 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd, if (snd_BUG_ON(!client)) return -ENXIO; +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) + /* exception - handling large data */ + switch (cmd) { + case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO: + case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO: + return snd_seq_ioctl_client_ump_info(client, cmd, arg); + } +#endif + for (handler = ioctl_handlers; handler->cmd > 0; ++handler) { if (handler->cmd == cmd) break; diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index 97762892ffab..be3fe555f233 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -12,7 +12,6 @@ #include "seq_ports.h" #include "seq_lock.h" - /* client manager */ struct snd_seq_user_client { @@ -59,6 +58,9 @@ struct snd_seq_client { struct snd_seq_user_client user; struct snd_seq_kernel_client kernel; } data; + + /* for UMP */ + void **ump_info; }; /* usage statistics */ diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c index c0ce6236dc7f..1e35bf086a51 100644 --- a/sound/core/seq/seq_compat.c +++ b/sound/core/seq/seq_compat.c @@ -86,6 +86,8 @@ static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned l case SNDRV_SEQ_IOCTL_SYSTEM_INFO: case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO: case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO: + case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO: + case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO: case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT: case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT: case SNDRV_SEQ_IOCTL_CREATE_QUEUE: diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c index 600b061ac8c3..e24833804094 100644 --- a/sound/core/seq/seq_ump_client.c +++ b/sound/core/seq/seq_ump_client.c @@ -47,6 +47,7 @@ struct seq_ump_client { struct snd_rawmidi_file out_rfile; /* rawmidi for output */ struct seq_ump_input_buffer input; /* input parser context */ struct seq_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */ + void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */ }; /* number of 32bit words for each UMP message type */ @@ -384,6 +385,8 @@ static int snd_seq_ump_probe(struct device *_dev) struct snd_ump_endpoint *ump = dev->private_data; struct snd_card *card = dev->card; struct seq_ump_client *client; + struct snd_ump_block *fb; + struct snd_seq_client *cptr; int p, err; client = kzalloc(sizeof(*client), GFP_KERNEL); @@ -400,6 +403,10 @@ static int snd_seq_ump_probe(struct device *_dev) goto error; } + client->ump_info[0] = &ump->info; + list_for_each_entry(fb, &ump->block_list, list) + client->ump_info[fb->info.block_id + 1] = &fb->info; + setup_client_midi_version(client); update_group_attrs(client); @@ -413,6 +420,14 @@ static int snd_seq_ump_probe(struct device *_dev) if (err < 0) goto error; + cptr = snd_seq_kernel_client_get(client->seq_client); + if (!cptr) { + err = -EINVAL; + goto error; + } + cptr->ump_info = client->ump_info; + snd_seq_kernel_client_put(cptr); + ump->seq_client = client; ump->seq_ops = &seq_ump_ops; return 0; From patchwork Tue May 23 07:53:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251808 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9CF7CC77B75 for ; Tue, 23 May 2023 08:04:16 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id B5A4F86E; Tue, 23 May 2023 10:03:24 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz B5A4F86E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829054; bh=2S5bfPVDlHq2XWH5E9lmadAP9vsgL5Zpzg3k5L+MxQY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=I9U2YTOlSyt1mi1HkMjQY+1SOjIMplSY9C0Fb063KJRlWXUIyuMxeovNR38a9fhB2 2XSM4o7sIwFAYxB09FTVlTWNcaz6FgwgmP1+J6n8rd0hE6ie5fw8XiQvn5+rQa/jmw DwgR4pb2iiVJzL6ag5MNa7ivnynIl1VUYhJoyTM4= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 7BD5FF805E6; Tue, 23 May 2023 09:56:17 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 7EE7DF805E4; Tue, 23 May 2023 09:56:16 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 3C068F806C3; Tue, 23 May 2023 09:55:57 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id D230FF80588 for ; Tue, 23 May 2023 09:54:13 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz D230FF80588 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=oNNRfBQT; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=J2iFqDWu Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id E51532041B; Tue, 23 May 2023 07:54:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828452; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fHQrHilsIqjDo5H9WbGUCwqE2MfITTbQXGoxi+ShiBk=; b=oNNRfBQT3taA3ZwcuPQW/0mjshFULGlgmhc6kUnxcP8nnH5tPXrF/DB4aNRMlcOifEu9S1 7G3q00cEOGbbQHw9nLRq5ojJZG+q3Ye31sSq/++yc1uJ5ZuBO+T6tw2qQy3i4aCeYF15Xu //7rUUx0bJyePpwtbxVdUE5X7CltAWw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828452; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fHQrHilsIqjDo5H9WbGUCwqE2MfITTbQXGoxi+ShiBk=; b=J2iFqDWuHzBL+wLK3QYiN/SFbj/S1l1zrT7vBaa0QmuU+J8kKwPwdBGsqrixTAy+cv+AyK 5fzyDyRPTjodJEAA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 965A513588; Tue, 23 May 2023 07:54:12 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id WCEtIiRxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:12 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 35/37] ALSA: seq: Print UMP Endpoint and Block information in proc outputs Date: Tue, 23 May 2023 09:53:56 +0200 Message-Id: <20230523075358.9672-36-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: OQOFKEFUL7MMGJAZH2QQHPT32PKNTUFO X-Message-ID-Hash: OQOFKEFUL7MMGJAZH2QQHPT32PKNTUFO X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: <> List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This patch enhances the /proc/asound/seq/clients output to show a few more information about the assigned UMP Endpoint and Blocks. The "Groups" are shown in 1-based group number to align with the sequencer client name and port number. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/seq/seq_clientmgr.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 03ca78ea2cce..8cce8061ca55 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2120,6 +2120,33 @@ static void terminate_ump_info_strings(void *p, int type) } } +#ifdef CONFIG_SND_PROC_FS +static void dump_ump_info(struct snd_info_buffer *buffer, + struct snd_seq_client *client) +{ + struct snd_ump_endpoint_info *ep; + struct snd_ump_block_info *bp; + int i; + + if (!client->ump_info) + return; + ep = client->ump_info[SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT]; + if (ep && *ep->name) + snd_iprintf(buffer, " UMP Endpoint: \"%s\"\n", ep->name); + for (i = 0; i < SNDRV_UMP_MAX_BLOCKS; i++) { + bp = client->ump_info[i + 1]; + if (bp && *bp->name) { + snd_iprintf(buffer, " UMP Block %d: \"%s\" [%s]\n", + i, bp->name, + bp->active ? "Active" : "Inactive"); + snd_iprintf(buffer, " Groups: %d-%d\n", + bp->first_group + 1, + bp->first_group + bp->num_groups); + } + } +} +#endif + /* UMP-specific ioctls -- called directly without data copy */ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, unsigned int cmd, @@ -2654,6 +2681,9 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, c, client->name, client->type == USER_CLIENT ? "User" : "Kernel", midi_version_string(client->midi_version)); +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) + dump_ump_info(buffer, client); +#endif snd_seq_info_dump_ports(buffer, client); if (snd_seq_write_pool_allocated(client)) { snd_iprintf(buffer, " Output pool :\n"); From patchwork Tue May 23 07:53:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251806 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D4881C7EE23 for ; Tue, 23 May 2023 08:03:44 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 96C8FE98; Tue, 23 May 2023 10:02:52 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 96C8FE98 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829022; bh=CihVDD5ia4eTDpONNmXvj1EEjF8qsKFeK2Jv4NLk7qg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=UNs60HdxrvC5Hpjzn6rPQDJTdzLadNA8nRa3AZLuD/1tFhFtHTBF11pV50fq/Alhj Vpw9ka59VFctI8wZqAIjiTYt0VlJkZil5GR5u8sGhYxGc+k7FXQDgecfAGmJjClj+n VkKNusyvzPuRCsxR2ohbuxrx8pS0hn2Xtd+TQWgo= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 6A34EF806BA; Tue, 23 May 2023 09:56:09 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id E1DC3F806E1; Tue, 23 May 2023 09:56:08 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 9B3FAF8057F; Tue, 23 May 2023 09:55:51 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 445AAF80580 for ; Tue, 23 May 2023 09:54:13 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 445AAF80580 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=ANv1bQjX; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=G9/3BtnH Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 1A9282041C; Tue, 23 May 2023 07:54:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828453; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XrdrP+yuN0II5OmsQTVnDce1vkjWRPxSiCWtpTAImdg=; b=ANv1bQjXnsPP6hkBDMqHs/qa0Lc37QZWFnBG0dqiMXOK/J9QG8Zvfa27CrVg7EqpNspp0w GWQ35Q09+7Lhzmio82j731JBxOGdYfY4CTuPlAzWG7UPXvYd9Ow+uv/WJiBUWBfXOnkRxF YqBm+f2Kpj4fzEt9sNylDVxWQ4Gi8XY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828453; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XrdrP+yuN0II5OmsQTVnDce1vkjWRPxSiCWtpTAImdg=; b=G9/3BtnHol/dTW/u7vmcUZmt7iU38fZJ2MS5qBjlLRkBwvmA9KBVGk7T7TCPe8Y7+a1usb yxBqUGtAi89dBoBA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id CE3C413A1A; Tue, 23 May 2023 07:54:12 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id CP32MCRxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:12 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 36/37] ALSA: seq: Add UMP group filter Date: Tue, 23 May 2023 09:53:57 +0200 Message-Id: <20230523075358.9672-37-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: 7ZKAVUR4NZ2BNXD4JTVCZBSOHBRMEYJA X-Message-ID-Hash: 7ZKAVUR4NZ2BNXD4JTVCZBSOHBRMEYJA X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add a new filter bitmap for UMP groups for reducing the unnecessary read/write when the client is connected to UMP EP seq port. The new group_filter field contains the bitmap for the groups, i.e. when the bit is set, the corresponding group is filtered out and the messages to that group won't be delivered. The filter bitmap consists of each bit of 1-based UMP Group number. The bit 0 is reserved for the future use. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/uapi/sound/asequencer.h | 3 ++- sound/core/seq/seq_clientmgr.c | 2 ++ sound/core/seq/seq_clientmgr.h | 1 + sound/core/seq/seq_ump_convert.c | 13 +++++++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h index c75f594f21e3..5e91243665d8 100644 --- a/include/uapi/sound/asequencer.h +++ b/include/uapi/sound/asequencer.h @@ -362,7 +362,8 @@ struct snd_seq_client_info { int card; /* RO: card number[kernel] */ int pid; /* RO: pid[user] */ unsigned int midi_version; /* MIDI version */ - char reserved[52]; /* for future use */ + unsigned int group_filter; /* UMP group filter bitmap (for 1-based Group indices) */ + char reserved[48]; /* for future use */ }; /* MIDI version numbers in client info */ diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 8cce8061ca55..948ae45e0cc3 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1229,6 +1229,7 @@ static void get_client_info(struct snd_seq_client *cptr, info->filter = cptr->filter; info->event_lost = cptr->event_lost; memcpy(info->event_filter, cptr->event_filter, 32); + info->group_filter = cptr->group_filter; info->num_ports = cptr->num_ports; if (cptr->type == USER_CLIENT) @@ -1290,6 +1291,7 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client, if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3)) client->midi_version = client_info->midi_version; memcpy(client->event_filter, client_info->event_filter, 32); + client->group_filter = client_info->group_filter; return 0; } diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index be3fe555f233..915b1017286e 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h @@ -40,6 +40,7 @@ struct snd_seq_client { int number; /* client number */ unsigned int filter; /* filter flags */ DECLARE_BITMAP(event_filter, 256); + unsigned short group_filter; snd_use_lock_t use_lock; int event_lost; /* ports */ diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c index 433fe842947e..14ba6fed9dd1 100644 --- a/sound/core/seq/seq_ump_convert.c +++ b/sound/core/seq/seq_ump_convert.c @@ -527,6 +527,17 @@ static int deliver_with_group_convert(struct snd_seq_client *dest, atomic, hop); } +/* apply the UMP event filter; return true to skip the event */ +static bool ump_event_filtered(struct snd_seq_client *dest, + const struct snd_seq_ump_event *ev) +{ + unsigned char group; + + group = ump_message_group(ev->ump[0]); + /* check the bitmap for 1-based group number */ + return dest->group_filter & (1U << (group + 1)); +} + /* Convert from UMP packet and deliver */ int snd_seq_deliver_from_ump(struct snd_seq_client *source, struct snd_seq_client *dest, @@ -539,6 +550,8 @@ int snd_seq_deliver_from_ump(struct snd_seq_client *source, if (snd_seq_ev_is_variable(event)) return 0; // skip, no variable event for UMP, so far + if (ump_event_filtered(dest, ump_ev)) + return 0; // skip if group filter is set and matching type = ump_message_type(ump_ev->ump[0]); if (snd_seq_client_is_ump(dest)) { From patchwork Tue May 23 07:53:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13251809 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2CE59C7EE23 for ; Tue, 23 May 2023 08:04:34 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 34A25AE9; Tue, 23 May 2023 10:03:41 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 34A25AE9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684829071; bh=M52WtGxPz090GfvqS7pb3cJFU2GarqyrYb6177LvXUo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=HHJ1F5zDk1fth/In/qIIdNpk5KExny/v87Zgrn2vOOINMRxV6LHAl6Ru+pTRORupr RuS6I8Sf6UvIkwEwZKEQ+q0lkLDUfFY+mpXLAaOi1uDBSikpHWTplkIDYG1xUU4a3v FTIdRN6GVS5Mjs7EZreKXwZjp0+912+/2/V2rjCU= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 74B2AF806F1; Tue, 23 May 2023 09:56:20 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 145BFF806F1; Tue, 23 May 2023 09:56:20 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id E698BF80588; Tue, 23 May 2023 09:55:59 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id CC5A7F8057D for ; Tue, 23 May 2023 09:54:13 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz CC5A7F8057D Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=iwbrCBK4; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=65L+LsDr Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 978542041D; Tue, 23 May 2023 07:54:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684828453; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OH6U4rT8EGIg2wRGbAhHHHcKP8gZmbdiQQCnZVG0uog=; b=iwbrCBK4TaTcMJec35k4YWNVxYEWIkMVLrB05aWJYhr5g60WRbRRtJJalxXfKjIzRRCU9q rm0i+MxHJr838XqqJKb0tuev9JTMEUMy818aFPAyHdUxIeAFrybZmFwPsiXr8z3GQbBLF0 +dokmoX5TKwfkc6kzhzq8qCmsikaj7E= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684828453; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OH6U4rT8EGIg2wRGbAhHHHcKP8gZmbdiQQCnZVG0uog=; b=65L+LsDrEIWPztWB7uL7QaFmKtrAc80jlelPvm/YvIyDYyp5YhQioEQma3jr5doJWcdf7x /xGSohlxmwn0cJAw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 2521A13588; Tue, 23 May 2023 07:54:13 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id qOP2BCVxbGT4KgAAMHmgww (envelope-from ); Tue, 23 May 2023 07:54:13 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH v2 37/37] ALSA: docs: Add MIDI 2.0 documentation Date: Tue, 23 May 2023 09:53:58 +0200 Message-Id: <20230523075358.9672-38-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230523075358.9672-1-tiwai@suse.de> References: <20230523075358.9672-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: G3LFL2J7HG26G72LT23ZASAREO4GGT54 X-Message-ID-Hash: G3LFL2J7HG26G72LT23ZASAREO4GGT54 X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add the brief document for describing the MIDI 2.0 implementation on Linux kernel. Both rawmidi and sequencer API extensions are described. Acked-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- Documentation/sound/designs/index.rst | 1 + Documentation/sound/designs/midi-2.0.rst | 351 +++++++++++++++++++++++ 2 files changed, 352 insertions(+) create mode 100644 Documentation/sound/designs/midi-2.0.rst diff --git a/Documentation/sound/designs/index.rst b/Documentation/sound/designs/index.rst index 1eb08e7bae52..b79db9ad8732 100644 --- a/Documentation/sound/designs/index.rst +++ b/Documentation/sound/designs/index.rst @@ -15,3 +15,4 @@ Designs and Implementations oss-emulation seq-oss jack-injection + midi-2.0 diff --git a/Documentation/sound/designs/midi-2.0.rst b/Documentation/sound/designs/midi-2.0.rst new file mode 100644 index 000000000000..d55b0a4c6acb --- /dev/null +++ b/Documentation/sound/designs/midi-2.0.rst @@ -0,0 +1,351 @@ +================= +MIDI 2.0 on Linux +================= + +General +======= + +MIDI 2.0 is an extended protocol for providing higher resolutions and +more fine controls over the legacy MIDI 1.0. The fundamental changes +introduced for supporting MIDI 2.0 are: + +- Support of Universal MIDI Packet (UMP) +- Support of MIDI 2.0 protocol messages +- Transparent conversions between UMP and legacy MIDI 1.0 byte stream +- MIDI-CI for property and profile configurations + +UMP is a new container format to hold all MIDI protocol 1.0 and MIDI +2.0 protocol messages. Unlike the former byte stream, it's 32bit +aligned, and each message can be put in a single packet. UMP can send +the events up to 16 "UMP Groups", where each UMP Group contain up to +16 MIDI channels. + +MIDI 2.0 protocol is an extended protocol to achieve the higher +resolution and more controls over the old MIDI 1.0 protocol. + +MIDI-CI is a high-level protocol that can talk with the MIDI device +for the flexible profiles and configurations. It's represented in the +form of special SysEx. + +For Linux implementations, the kernel supports the UMP transport and +the encoding/decoding of MIDI protocols on UMP, while MIDI-CI is +supported in user-space over the standard SysEx. + +As of this writing, only USB MIDI device supports the UMP and Linux +2.0 natively. The UMP support itself is pretty generic, hence it +could be used by other transport layers, although it could be +implemented differently (e.g. as a ALSA sequencer client), too. + +The access to UMP devices are provided in two ways: the access via +rawmidi device and the access via ALSA sequencer API. + +ALSA sequencer API was extended to allow the payload of UMP packets. +It's allowed to connect freely between MIDI 1.0 and MIDI 2.0 sequencer +clients, and the events are converted transparently. + + +Kernel Configuration +==================== + +The following new configs are added for supporting MIDI 2.0: +`CONFIG_SND_UMP`, `CONFIG_SND_UMP_LEGACY_RAWMIDI`, +`CONFIG_SND_SEQ_UMP`, `CONFIG_SND_SEQ_UMP_CLIENT`, and +`CONFIG_SND_USB_AUDIO_MIDI_V2`. The first visible one is +`CONFIG_SND_USB_AUDIO_MIDI_V2`, and when you choose it (to set `=y`), +the core support for UMP (`CONFIG_SND_UMP`) and the sequencer binding +(`CONFIG_SND_SEQ_UMP_CLIENT`) will be automatically selected. + +Additionally, `CONFIG_SND_UMP_LEGACY_RAWMIDI=y` will enable the +support for the legacy raw MIDI device for UMP Endpoints. + + +Rawmidi Device with USB MIDI 2.0 +================================ + +When a device supports MIDI 2.0, the USB-audio driver probes and uses +the MIDI 2.0 interface (that is found always at the altset 1) as +default instead of the MIDI 1.0 interface (at altset 0). You can +switch back to the binding with the old MIDI 1.0 interface by passing +`midi2_enable=0` option to snd-usb-audio driver module, too. + +When the MIDI 2.0 device is probed, the kernel creates a rawmidi +device for each UMP Endpoint of the device. Its device name is +`/dev/snd/umpC*D*` and different from the standard rawmidi device name +`/dev/snd/midiC*D*` for MIDI 1.0, in order to avoid confusing the +legacy applications accessing mistakenly to UMP devices. + +You can read and write UMP packet data directly from/to this UMP +rawmidi device. For example, reading via `hexdump` like below will +show the incoming UMP packets of the card 0 device 0 in the hex +format:: + + % hexdump -C /dev/snd/umpC0D0 + 00000000 01 07 b0 20 00 07 b0 20 64 3c 90 20 64 3c 80 20 |... ... d<. d<. | + +Unlike the MIDI 1.0 byte stream, UMP is a 32bit packet, and the size +for reading or writing the device is also aligned to 32bit (which is 4 +bytes). + +The 32-bit words in the UMP packet payload are always in CPU native +endianness. Transport drivers are responsible to convert UMP words +from / to system endianness to required transport endianness / byte +order. + +When `CONFIG_SND_UMP_LEGACY_RAWMIDI` is set, the driver creates +another standard raw MIDI device additionally as `/dev/snd/midiC*D*`. +This contains 16 substreams, and each substream corresponds to a +(0-based) UMP Group. Legacy applications can access to the specified +group via each substream in MIDI 1.0 byte stream format. With the +ALSA rawmidi API, you can open the arbitrary substream, while just +opening `/dev/snd/midiC*D*` will end up with opening the first +substream. + +Each UMP Endpoint can provide the additional information, constructed +from USB MIDI 2.0 descriptors. And a UMP Endpoint may contain one or +more UMP Blocks, where UMP Block is an abstraction introduced in the +ALSA UMP implementations to represent the associations among UMP +Groups. UMP Block corresponds to Group Terminal Block (GTB) in USB +MIDI 2.0 specifications but provide a few more generic information. +The information of UMP Endpoints and UMP Blocks are found in the proc +file `/proc/asound/card*/midi*`. For example:: + + % cat /proc/asound/card1/midi0 + ProtoZOA MIDI + + Type: UMP + EP Name: ProtoZOA + EP Product ID: ABCD12345678 + UMP Version: 0x0000 + Protocol Caps: 0x00000100 + Protocol: 0x00000100 + Num Blocks: 3 + + Block 0 (ProtoZOA Main) + Direction: bidirection + Active: Yes + Groups: 1-1 + Is MIDI1: No + + Block 1 (ProtoZOA Ext IN) + Direction: output + Active: Yes + Groups: 2-2 + Is MIDI1: Yes (Low Speed) + .... + +Note that `Groups` field shown in the proc file above indicates the +1-based UMP Group numbers (from-to). + +Those additional UMP Endpoint and UMP Block information can be +obtained via the new ioctls `SNDRV_UMP_IOCTL_ENDPOINT_INFO` and +`SNDRV_UMP_IOCTL_BLOCK_INFO`, respectively. + +The rawmidi name and the UMP Endpoint name are usually identical, and +in the case of USB MIDI, it's taken from `iInterface` of the +corresponding USB MIDI interface descriptor. If it's not provided, +it's copied from `iProduct` of the USB device descriptor as a +fallback. + +The Endpoint Product ID is a string field and supposed to be unique. +It's copied from `iSerialNumber` of the device for USB MIDI. + +The protocol capabilities and the actual protocol bits are defined in +`asound.h`. + + +ALSA Sequencer with USB MIDI 2.0 +================================ + +In addition to the rawmidi interfaces, ALSA sequencer interface +supports the new UMP MIDI 2.0 device, too. Now, each ALSA sequencer +client may set its MIDI version (0, 1 or 2) to declare itself being +either the legacy, UMP MIDI 1.0 or UMP MIDI 2.0 device, respectively. +The first, legacy client is the one that sends/receives the old +sequencer event as was. Meanwhile, UMP MIDI 1.0 and 2.0 clients send +and receive in the extended event record for UMP. The MIDI version is +seen in the new `midi_version` field of `snd_seq_client_info`. + +A UMP packet can be sent/received in a sequencer event embedded by +specifying the new event flag bit `SNDRV_SEQ_EVENT_UMP`. When this +flag is set, the event has 16 byte (128 bit) data payload for holding +the UMP packet. Without the `SNDRV_SEQ_EVENT_UMP` bit flag, the event +is treated as a legacy event as it was (with max 12 byte data +payload). + +With `SNDRV_SEQ_EVENT_UMP` flag set, the type field of a UMP sequencer +event is ignored (but it should be set to 0 as default). + +The type of each client can be seen in `/proc/asound/seq/clients`. +For example:: + + % cat /proc/asound/seq/clients + Client info + cur clients : 3 + .... + Client 14 : "Midi Through" [Kernel Legacy] + Port 0 : "Midi Through Port-0" (RWe-) + Client 20 : "ProtoZOA" [Kernel UMP MIDI1] + UMP Endpoint: ProtoZOA + UMP Block 0: ProtoZOA Main [Active] + Groups: 1-1 + UMP Block 1: ProtoZOA Ext IN [Active] + Groups: 2-2 + UMP Block 2: ProtoZOA Ext OUT [Active] + Groups: 3-3 + Port 0 : "MIDI 2.0" (RWeX) [In/Out] + Port 1 : "ProtoZOA Main" (RWeX) [In/Out] + Port 2 : "ProtoZOA Ext IN" (-We-) [Out] + Port 3 : "ProtoZOA Ext OUT" (R-e-) [In] + +Here you can find two types of kernel clients, "Legacy" for client 14, +and "UMP MIDI1" for client 20, which is a USB MIDI 2.0 device. +A USB MIDI 2.0 client gives always the port 0 as "MIDI 2.0" and the +rest ports from 1 for each UMP Group (e.g. port 1 for Group 1). +In this example, the device has three active groups (Main, Ext IN and +Ext OUT), and those are exposed as sequencer ports from 1 to 3. +The "MIDI 2.0" port is for a UMP Endpoint, and its difference from +other UMP Group ports is that UMP Endpoint port sends the events from +the all ports on the device ("catch-all"), while each UMP Group port +sends only the events from the given UMP Group. + +Note that, although each UMP sequencer client usually creates 16 +ports, those ports that don't belong to any UMP Blocks (or belonging +to inactive UMP Blocks) are marked as inactive, and they don't appear +in the proc outputs. In the example above, the sequencer ports from 4 +to 16 are present but not shown there. + +The proc file above shows the UMP Block information, too. The same +entry (but with more detailed information) is found in the rawmidi +proc output. + +When clients are connected between different MIDI versions, the events +are translated automatically depending on the client's version, not +only between the legacy and the UMP MIDI 1.0/2.0 types, but also +between UMP MIDI 1.0 and 2.0 types, too. For example, running +`aseqdump` program on the ProtoZOA Main port in the legacy mode will +give you the output like:: + + % aseqdump -p 20:1 + Waiting for data. Press Ctrl+C to end. + Source Event Ch Data + 20:1 Note on 0, note 60, velocity 100 + 20:1 Note off 0, note 60, velocity 100 + 20:1 Control change 0, controller 11, value 4 + +When you run `aseqdump` in MIDI 2.0 mode, it'll receive the high +precision data like:: + + % aseqdump -u 2 -p 20:1 + Waiting for data. Press Ctrl+C to end. + Source Event Ch Data + 20:1 Note on 0, note 60, velocity 0xc924, attr type = 0, data = 0x0 + 20:1 Note off 0, note 60, velocity 0xc924, attr type = 0, data = 0x0 + 20:1 Control change 0, controller 11, value 0x2000000 + +while the data is automatically converted by ALSA sequencer core. + + +Rawmidi API Extensions +====================== + +* The additional UMP Endpoint information can be obtained via the new + ioctl `SNDRV_UMP_IOCTL_ENDPOINT_INFO`. It contains the associated + card and device numbers, the bit flags, the protocols, the number of + UMP Blocks, the name string of the endpoint, etc. + + The protocols are specified in two field, the protocol capabilities + and the current protocol. Both contain the bit flags specifying the + MIDI protocol version (`SNDRV_UMP_EP_INFO_PROTO_MIDI1` or + `SNDRV_UMP_EP_INFO_PROTO_MIDI2`) in the upper byte and the jitter + reduction timestamp (`SNDRV_UMP_EP_INFO_PROTO_JRTS_TX` and + `SNDRV_UMP_EP_INFO_PROTO_JRTS_RX`) in the lower byte. + + A UMP Endpoint may contain up to 32 UMP Blocks, and the number of + the currently assigned blocks are shown in the Endpoint information. + +* Each UMP Block information can be obtained via another new ioctl + `SNDRV_UMP_IOCTL_BLOCK_INFO`. The block ID number (0-based) has to + be passed for the block to query. The received data contains the + associated the direction of the block, the first associated group ID + (0-based) and the number of groups, the name string of the block, + etc. + + The direction is either `SNDRV_UMP_DIR_INPUT`, + `SNDRV_UMP_DIR_OUTPUT` or `SNDRV_UMP_DIR_BIDIRECTION`. + + +Control API Extensions +====================== + +* The new ioctl `SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE` is introduced for + querying the next UMP rawmidi device, while the existing ioctl + `SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE` queries only the legacy + rawmidi devices. + + For setting the subdevice (substream number) to be opened, use the + ioctl `SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE` like the normal + rawmidi. + +* Two new ioctls `SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO` and + `SNDRV_CTL_IOCTL_UMP_BLOCK_INFO` provide the UMP Endpoint and UMP + Block information of the specified UMP device via ALSA control API + without opening the actual (UMP) rawmidi device. + The `card` field is ignored upon inquiry, always tied with the card + of the control interface. + + +Sequencer API Extensions +======================== + +* `midi_version` field is added to `snd_seq_client_info` to indicate + the current MIDI version (either 0, 1 or 2) of each client. + When `midi_version` is 1 or 2, the alignment of read from a UMP + sequencer client is also changed from the former 28 bytes to 32 + bytes for the extended payload. The alignment size for the write + isn't changed, but each event size may differ depending on the new + bit flag below. + +* `SNDRV_SEQ_EVENT_UMP` flag bit is added for each sequencer event + flags. When this bit flag is set, the sequencer event is extended + to have a larger payload of 16 bytes instead of the legacy 12 + bytes, and the event contains the UMP packet in the payload. + +* The new sequencer port type bit (`SNDRV_SEQ_PORT_TYPE_MIDI_UMP`) + indicates the port being UMP-capable. + +* The sequencer ports have new capability bits to indicate the + inactive ports (`SNDRV_SEQ_PORT_CAP_INACTIVE`) and the UMP Endpoint + port (`SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT`). + +* The event conversion of ALSA sequencer clients can be suppressed the + new filter bit `SNDRV_SEQ_FILTER_NO_CONVERT` set to the client info. + For example, the kernel pass-through client (`snd-seq-dummy`) sets + this flag internally. + +* The port information gained the new field `direction` to indicate + the direction of the port (either `SNDRV_SEQ_PORT_DIR_INPUT`, + `SNDRV_SEQ_PORT_DIR_OUTPUT` or `SNDRV_SEQ_PORT_DIR_BIDIRECTION`). + +* Another additional field for the port information is `ump_group` + which specifies the associated UMP Group Number (1-based). + When it's non-zero, the UMP group field in the UMP packet updated + upon delivery to the specified group (corrected to be 0-based). + Each sequencer port is supposed to set this field if it's a port to + specific to a certain UMP group. + +* Each client may set the additional event filter for UMP Groups in + `group_filter` bitmap. The filter consists of bitmap from 1-based + Group numbers. For example, when the bit 1 is set, messages from + Group 1 (i.e. the very first group) are filtered and not delivered. + The bit 0 is reserved for future use. + +* Two new ioctls are added for UMP-capable clients: + `SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO` and + `SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO`. They are used to get and set + either `snd_ump_endpoint_info` or `snd_ump_block_info` data + associated with the sequencer client. The USB MIDI driver provides + those information from the underlying UMP rawmidi, while a + user-space client may provide its own data via `*_SET` ioctl. + For an Endpoint data, pass 0 to the `type` field, while for a Block + data, pass the block number + 1 to the `type` field. + Setting the data for a kernel client shall result in an error.