Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp1577883imm; Thu, 19 Jul 2018 04:23:41 -0700 (PDT) X-Google-Smtp-Source: AAOMgpfZHkeV0LcJBVxSm/xXlG2aXc9u6p8zDtAhJCOTxqcUGMDnzEdzyqmRjdlwBbzCEzzKjM2V X-Received: by 2002:a62:c0a:: with SMTP id u10-v6mr9119223pfi.43.1531999421275; Thu, 19 Jul 2018 04:23:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531999421; cv=none; d=google.com; s=arc-20160816; b=GhYbNYQ9+nbfj54hEBe0U+q3ymkBkTE2KoadETzmW8eFD6u19XhoIfs8rH9czOC0ov MgN5nC36rErJLTw4NM0mRBsOEHKvU3AGsAo1n2u/QgfThV7IQywyf4keuy9iff1rfUoo t4EYq3u5ebi1+Fs5M8Z28yvBTJPiRw2VMQyieR0WbfnKJd6TkydltxjCnCBShXN34Gjh FELhCwUojdbTbljunMtk2+hn4VplCN24RkB8e72/FoG4mim+pQypcbDFDZJjlh2aKtTT X95bIoNvaDkzvTsLpRkBggHTU1VbEDKPuFa6ry6+36hE2F9CIkiPDuxSoViNor0bKJbW 534w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=f3iRAeG/jR+sEB1tHYIcSXHBOvpHy0mUczU5qsXxck0=; b=m0AlBBWps6oeFlKpvcuN7XuWirV5Sw53mS0VwmOCQouvO33aT7RHln/wuc1Tab6EQD vpLfe21j+KheXE/b+ErW3z7spzbo6Gi6WR7q0j6BkE/vBn236U5i5i21BJlmj4786Pp7 zveK5PCgeVw5W5gqGj5uDSWP6NBnVU5wZ1MMuea69AXjW2tYiZ4jtYGLKEhVWCFZ01V8 PdhhF/YtA68vm/xVzkyDx516ymC1B2RXJRzTRpBLhLnAhwAIXLMHu35g/tZK05pWfTjv FZwS1lD4opewMsM98LHgkBe8Rgd6H3xyFLlLLAK820lAma7TiD7gfdc8eiBPiCkFhkTo jAgA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=codethink.co.uk Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h185-v6si5655713pfc.172.2018.07.19.04.23.04; Thu, 19 Jul 2018 04:23:41 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=codethink.co.uk Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731313AbeGSMFF (ORCPT + 99 others); Thu, 19 Jul 2018 08:05:05 -0400 Received: from imap1.codethink.co.uk ([176.9.8.82]:59733 "EHLO imap1.codethink.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727489AbeGSMFF (ORCPT ); Thu, 19 Jul 2018 08:05:05 -0400 Received: from [148.252.241.226] (helo=ct-lt-1121.office.codethink.co.uk) by imap1.codethink.co.uk with esmtpsa (Exim 4.84_2 #1 (Debian)) id 1fg70l-0004fU-2j; Thu, 19 Jul 2018 12:22:19 +0100 From: Jorge Sanjuan To: tiwai@suse.de Cc: alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/4] ALSA: usb-audio: AudioStreaming Power Domain parsing Date: Thu, 19 Jul 2018 12:22:13 +0100 Message-Id: <20180719112215.4219-3-jorge.sanjuan@codethink.co.uk> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180719112215.4219-1-jorge.sanjuan@codethink.co.uk> References: <20180719112215.4219-1-jorge.sanjuan@codethink.co.uk> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Power Domains in the UAC3 spec are mainly intended to be associated to an Input or Output Terminal so the host changes the power state of the entire capture or playback path within the topology. This patch adds support for finding Power Domains associated to an Audio Streaming Interface (bTerminalLink) and adds a reference to them in the usb audio substreams (snd_usb_substream). Signed-off-by: Jorge Sanjuan --- sound/usb/card.h | 2 ++ sound/usb/stream.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/sound/usb/card.h b/sound/usb/card.h index 9b41b7dda84f..ac785d15ced4 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -37,6 +37,7 @@ struct audioformat { struct snd_usb_substream; struct snd_usb_endpoint; +struct snd_usb_power_domain; struct snd_urb_ctx { struct urb *urb; @@ -115,6 +116,7 @@ struct snd_usb_substream { int interface; /* current interface */ int endpoint; /* assigned endpoint */ struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ + struct snd_usb_power_domain *str_pd; /* UAC3 Power Domain for streaming path */ snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ unsigned int channels; /* current number of channels (for hw_params callback) */ unsigned int channels_max; /* max channels in the all audiofmts */ diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 729afd808cc4..031878a2a481 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -37,6 +37,7 @@ #include "format.h" #include "clock.h" #include "stream.h" +#include "power.h" /* * free a substream @@ -53,6 +54,7 @@ static void free_substream(struct snd_usb_substream *subs) kfree(fp); } kfree(subs->rate_list.list); + kfree(subs->str_pd); } @@ -82,7 +84,8 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) static void snd_usb_init_substream(struct snd_usb_stream *as, int stream, - struct audioformat *fp) + struct audioformat *fp, + struct snd_usb_power_domain *pd) { struct snd_usb_substream *subs = &as->substream[stream]; @@ -107,6 +110,9 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, if (fp->channels > subs->channels_max) subs->channels_max = fp->channels; + if (pd) + subs->str_pd = pd; + snd_usb_preallocate_buffer(subs); } @@ -468,9 +474,11 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor * fmt_list and will be freed on the chip instance release. do not free * fp or do remove it from the substream fmt_list to avoid double-free. */ -int snd_usb_add_audio_stream(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp) +static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, + struct audioformat *fp, + struct snd_usb_power_domain *pd) + { struct snd_usb_stream *as; struct snd_usb_substream *subs; @@ -498,7 +506,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, err = snd_pcm_new_stream(as->pcm, stream, 1); if (err < 0) return err; - snd_usb_init_substream(as, stream, fp); + snd_usb_init_substream(as, stream, fp, pd); return add_chmap(as->pcm, stream, subs); } @@ -526,7 +534,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, else strcpy(pcm->name, "USB Audio"); - snd_usb_init_substream(as, stream, fp); + snd_usb_init_substream(as, stream, fp, pd); /* * Keep using head insertion for M-Audio Audiophile USB (tm) which has a @@ -544,6 +552,21 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, return add_chmap(pcm, stream, &as->substream[stream]); } +int snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, + struct audioformat *fp) +{ + return __snd_usb_add_audio_stream(chip, stream, fp, NULL); +} + +int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, + int stream, + struct audioformat *fp, + struct snd_usb_power_domain *pd) +{ + return __snd_usb_add_audio_stream(chip, stream, fp, pd); +} + static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, struct usb_host_interface *alts, int protocol, int iface_no) @@ -819,6 +842,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, static struct audioformat * snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, struct usb_host_interface *alts, + struct snd_usb_power_domain **pd_out, int iface_no, int altset_idx, int altno, int stream) { @@ -829,6 +853,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, struct uac3_as_header_descriptor *as = NULL; struct uac3_hc_descriptor_header hc_header; struct snd_pcm_chmap_elem *chmap; + struct snd_usb_power_domain *pd; unsigned char badd_profile; u64 badd_formats = 0; unsigned int num_channels; @@ -1008,12 +1033,28 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, fp->rate_max = UAC3_BADD_SAMPLING_RATE; fp->rates = SNDRV_PCM_RATE_CONTINUOUS; + pd = kzalloc(sizeof(pd), GFP_KERNEL); + if (!pd) { + kfree(fp->rate_table); + kfree(fp); + return NULL; + } + pd->pd_id = (stream == SNDRV_PCM_STREAM_PLAYBACK) ? + UAC3_BADD_PD_ID10 : UAC3_BADD_PD_ID11; + pd->pd_d1d0_rec = UAC3_BADD_PD_RECOVER_D1D0; + pd->pd_d2d0_rec = UAC3_BADD_PD_RECOVER_D2D0; + } else { fp->attributes = parse_uac_endpoint_attributes(chip, alts, UAC_VERSION_3, iface_no); + + pd = snd_usb_find_power_domain(chip->ctrl_intf, + as->bTerminalLink); + /* ok, let's parse further... */ if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { + kfree(pd); kfree(fp->chmap); kfree(fp->rate_table); kfree(fp); @@ -1021,6 +1062,9 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, } } + if (pd) + *pd_out = pd; + return fp; } @@ -1032,6 +1076,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) struct usb_interface_descriptor *altsd; int i, altno, err, stream; struct audioformat *fp = NULL; + struct snd_usb_power_domain *pd = NULL; int num, protocol; dev = chip->dev; @@ -1114,7 +1159,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) break; } case UAC_VERSION_3: - fp = snd_usb_get_audioformat_uac3(chip, alts, + fp = snd_usb_get_audioformat_uac3(chip, alts, &pd, iface_no, i, altno, stream); break; } @@ -1125,9 +1170,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) return PTR_ERR(fp); dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); - err = snd_usb_add_audio_stream(chip, stream, fp); + if (protocol == UAC_VERSION_3) + err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); + else + err = snd_usb_add_audio_stream(chip, stream, fp); + if (err < 0) { list_del(&fp->list); /* unlink for avoiding double-free */ + kfree(pd); kfree(fp->rate_table); kfree(fp->chmap); kfree(fp); -- 2.11.0