From patchwork Sat Feb 3 02:36:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wesley Cheng X-Patchwork-Id: 196184 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:9bc1:b0:106:209c:c626 with SMTP id op1csp821899dyc; Fri, 2 Feb 2024 19:00:45 -0800 (PST) X-Google-Smtp-Source: AGHT+IGVW9/5djWVJPfopVvwa+W4QkdiT9j3RwpKb45v2FqGsmnbPAV+UfUisbhveDJMGeKKxp5C X-Received: by 2002:a17:90a:3481:b0:296:58cc:c172 with SMTP id p1-20020a17090a348100b0029658ccc172mr1737855pjb.22.1706929245000; Fri, 02 Feb 2024 19:00:45 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706929244; cv=pass; d=google.com; s=arc-20160816; b=ReH2dDWyjdKpSijE9btUaOd6jlGd3RsOu3nb8vnQ8QA+t631wkstLoQnOvzyngmc2Y ft+P/eSV5lJAOxW6KKUfivzML4Ro9T6EwnDKCQaEgZ3PLx6mkA3iQKPls8Ta4EYpqBdo 485luQOyWaMmQNldfTVYLF9zhGcyEO2J/C5iTKVB/jnXmxOCzTJhrU/I8HHVOTsXv8IC TuzD/3J6K8cUK1Jsa5UGYqkdjUAlBouibAkn8T8xmumGfOPTmF0R7E7Y9eCbcE64maoG X8fh7J5jWodzjYqeuWh1zdPlQ4lbzkItcIyfg6InRp0Qd86I/RK5RxD2nI3uWxuS/9QY Ei8w== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=mime-version:list-unsubscribe:list-subscribe:list-id:precedence :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=60ObKyG9TuHBxrZeqJMrxbRUfxtLp+1tF0A4Dzl6/6A=; fh=0cYTs6ABVO3GUdK2Z3+8gs1RX7lVeFrli1X3hyLh0xg=; b=jnQ54RUH4lfvJnPjCD1348txhwm8WCQEYCWJ+Xf9+IAmjnSMCroXAkdZjoQ2dEX7FB ZuSWLnosnRhBHHX12PZ+KYIwSbxVoBSJqwhMG8eIIdcoX1EosVZSgDGBF5LPg5vd3f2h nKD86ubDusON/cPPSa7axCIkj4EtMXHPFRonKXxdUp8yXJV6Cfw4bbUKpMJayu4ITn2t /R2ECAHcdocxs/dn2Qw9BvaD0JIUYBGjV6SJ6wykEljqIVU03s4UziFH0MEgwpmMNTWn MNu83VGuk6237tWidQS9dnJvWE0n5HEmIz39Ukot3lVvwKW/jOiTrT4yuKQTOBEUQ6Cp ieIw==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@quicinc.com header.s=qcppdkim1 header.b=J4OK3gk7; arc=pass (i=1 spf=pass spfdomain=quicinc.com dkim=pass dkdomain=quicinc.com dmarc=pass fromdomain=quicinc.com); spf=pass (google.com: domain of linux-kernel+bounces-50844-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-50844-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=quicinc.com X-Forwarded-Encrypted: i=1; AJvYcCUpoo0YMq4BcMSP7jwKYl+MfUleLKrh2+RMpXZsa3F/8grzybBfMPDwMBueV7yQoFRb+ge7PKNtGa/QXSt+WqGVNLM+SA== Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [2604:1380:40f1:3f00::1]) by mx.google.com with ESMTPS id ft2-20020a17090b0f8200b002963a1d9e9bsi855190pjb.164.2024.02.02.19.00.44 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Feb 2024 19:00:44 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-50844-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) client-ip=2604:1380:40f1:3f00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@quicinc.com header.s=qcppdkim1 header.b=J4OK3gk7; arc=pass (i=1 spf=pass spfdomain=quicinc.com dkim=pass dkdomain=quicinc.com dmarc=pass fromdomain=quicinc.com); spf=pass (google.com: domain of linux-kernel+bounces-50844-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:40f1:3f00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-50844-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=quicinc.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id D291DB295DB for ; Sat, 3 Feb 2024 02:51:55 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E337C51C23; Sat, 3 Feb 2024 02:38:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="J4OK3gk7" Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE301171AE; Sat, 3 Feb 2024 02:37:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706927874; cv=none; b=fBNtxAEAc5Y07jZwKf+QKmhNEE1L6eThN8qV3FQOxBIwsr2btJiB+r0beZ2hCEY8X8xVQ8moBdKH2/npsxszLXCk6aZ7BWI3vTa6WMQTSX/i2ZaenyfCyDfA0gDjsBozCSGQuSfWrV5XRvvZyQlNu35hJxCT1oXdsvdKFf0WdIs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706927874; c=relaxed/simple; bh=XHbx/v/TuXqw8WQvMgvyY6h+6CwDlT1EQepdFQ4hDLM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=icm9Vbz2eq1w4hGqGtP4+yLibmZynt+WHgvNOvKAO0PcFfqfsSGjeRDvkDK2JB0rhlYQu9XeCE5L20ngms7oqDnMKoNNYf13kvJ6qqSybm9P1z60eOMUhZTen43Oc2J2XvSOQy5JiFfzDnCU/XpjhtkMyA4KPte89ERPrUP0YaY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=J4OK3gk7; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.24/8.17.1.24) with ESMTP id 4132QjKs029159; Sat, 3 Feb 2024 02:37:32 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type; s=qcppdkim1; bh=60ObKyG9TuHBxrZeqJMr xbRUfxtLp+1tF0A4Dzl6/6A=; b=J4OK3gk7DNZV8jI5zFkNIicxTbyVkt/Ge+B0 pRllEeKpawUokwnY2IRPevo29sgSC6c7+OnKdQ+FQgMQNmbICTHQMtrtdIDN4J2F r6wSr9ud1OxNoWqttOgo21NzJjiY3/hD+h9PmZv+z/g+rR+/ntpTxfJZqMcneAK6 wYgDJJ5goMw+v5Llrg7kevfRuPZswTpO3en0bpYFElbyThEeo8PNSCmoeAbnbmHJ vXA6y4wauA3BqW6Od/pz9l6jp0SyiECTXNY0LCfpiWS6DSXa56AziHLo6N2Z30E6 f7XkfduP8jieLNQ3y8Kn8zXtFkrA+FmH7Xb9Ba2lkIxUQnFh8g== Received: from nalasppmta03.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3w1ax4849m-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 03 Feb 2024 02:37:31 +0000 (GMT) Received: from nalasex01b.na.qualcomm.com (nalasex01b.na.qualcomm.com [10.47.209.197]) by NALASPPMTA03.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 4132bUCr012287 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 3 Feb 2024 02:37:30 GMT Received: from hu-wcheng-lv.qualcomm.com (10.49.16.6) by nalasex01b.na.qualcomm.com (10.47.209.197) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.40; Fri, 2 Feb 2024 18:37:30 -0800 From: Wesley Cheng To: , , , , , , , , , , , , , , CC: , , , , , , , Wesley Cheng Subject: [PATCH v13 43/53] ASoC: Add SND kcontrol for fetching USB offload status Date: Fri, 2 Feb 2024 18:36:35 -0800 Message-ID: <20240203023645.31105-44-quic_wcheng@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240203023645.31105-1-quic_wcheng@quicinc.com> References: <20240203023645.31105-1-quic_wcheng@quicinc.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: nalasex01b.na.qualcomm.com (10.47.209.197) To nalasex01b.na.qualcomm.com (10.47.209.197) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: a9njwXRwMqosq7zR3H2dLEK_LdAJw9_2 X-Proofpoint-GUID: a9njwXRwMqosq7zR3H2dLEK_LdAJw9_2 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.272,Aquarius:18.0.1011,Hydra:6.0.619,FMLib:17.11.176.26 definitions=2024-02-02_16,2024-01-31_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 clxscore=1015 bulkscore=0 phishscore=0 mlxlogscore=999 priorityscore=1501 impostorscore=0 malwarescore=0 spamscore=0 adultscore=0 suspectscore=0 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2401310000 definitions=main-2402030015 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1789845039779811513 X-GMAIL-MSGID: 1789845039779811513 Add a kcontrol to the platform sound card to fetch the current offload status. This can allow for userspace to ensure/check which USB SND resources are actually busy versus having to attempt opening the USB SND devices, which will result in an error if offloading is active. Signed-off-by: Wesley Cheng --- include/sound/soc-usb.h | 27 ++++++++ sound/soc/soc-usb.c | 150 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 175 insertions(+), 2 deletions(-) diff --git a/include/sound/soc-usb.h b/include/sound/soc-usb.h index 20d7b32bba07..c05d9b2f5c90 100644 --- a/include/sound/soc-usb.h +++ b/include/sound/soc-usb.h @@ -6,6 +6,24 @@ #ifndef __LINUX_SND_SOC_USB_H #define __LINUX_SND_SOC_USB_H +enum snd_soc_usb_dai_state { + SND_SOC_USB_IDLE, + SND_SOC_USB_PREPARED, + SND_SOC_USB_RUNNING, +}; + +/** + * struct snd_soc_usb_session + * @active_card_idx - active offloaded sound card + * @active_pcm_idx - active offloaded PCM device + * @state - USB BE DAI link PCM state + */ +struct snd_soc_usb_session { + int active_card_idx; + int active_pcm_idx; + enum snd_soc_usb_dai_state state; +}; + /** * struct snd_soc_usb_device * @card_idx - sound card index associated with USB device @@ -25,6 +43,8 @@ struct snd_soc_usb_device { * @list - list head for SND SOC struct list * @dev - USB backend device reference * @component - reference to ASoC component + * @active_list - active sessions + * @num_supported_streams - number of supported concurrent sessions * @connection_status_cb - callback to notify connection events * @put_offload_dev - callback to select USB sound card/PCM device * @get_offload_dev - callback to fetch selected USB sound card/PCM device @@ -33,6 +53,8 @@ struct snd_soc_usb_device { struct snd_soc_usb { struct list_head list; struct snd_soc_component *component; + struct snd_soc_usb_session *active_list; + unsigned int num_supported_streams; int (*connection_status_cb)(struct snd_soc_usb *usb, struct snd_soc_usb_device *sdev, bool connected); int (*put_offload_dev)(struct snd_kcontrol *kcontrol, @@ -50,6 +72,11 @@ int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev); int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev); void *snd_soc_usb_find_priv_data(struct device *dev); +int snd_soc_usb_prepare_session(struct snd_soc_usb *usb, int card_idx, int pcm_idx); +int snd_soc_usb_shutdown_session(struct snd_soc_usb *usb, int session_id); +int snd_soc_usb_set_session_state(struct snd_soc_usb *usb, int session_id, + enum snd_soc_usb_dai_state state); + struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component, int num_supported_streams, void *data); void snd_soc_usb_free_port(struct snd_soc_usb *usb); diff --git a/sound/soc/soc-usb.c b/sound/soc/soc-usb.c index c568c67e3e4a..9c082129cb9f 100644 --- a/sound/soc/soc-usb.c +++ b/sound/soc/soc-usb.c @@ -42,11 +42,62 @@ static struct snd_soc_usb *snd_soc_find_usb_ctx(struct device_node *node) } /* SOC USB sound kcontrols */ +static int snd_soc_usb_get_offload_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct snd_soc_usb *ctx = snd_soc_find_usb_ctx(component->dev->of_node); + int control_idx = 0; + int pcm_idx; + int card_idx; + int i; + + for (i = 0; i < ctx->num_supported_streams; i++) { + card_idx = -1; + pcm_idx = -1; + + if (ctx->active_list[i].state == SND_SOC_USB_RUNNING) { + card_idx = ctx->active_list[i].active_card_idx; + pcm_idx = ctx->active_list[i].active_pcm_idx; + } + + ucontrol->value.integer.value[control_idx] = card_idx; + control_idx++; + ucontrol->value.integer.value[control_idx] = pcm_idx; + control_idx++; + } + + return 0; +} + +static int snd_soc_usb_offload_status_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct snd_soc_usb *ctx = snd_soc_find_usb_ctx(component->dev->of_node); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2*ctx->num_supported_streams; + uinfo->value.integer.min = -1; + uinfo->value.integer.max = SNDRV_CARDS; + + return 0; +} + +static const struct snd_kcontrol_new soc_usb_status_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .name = "SNDUSB OFFLD playback status", + .info = snd_soc_usb_offload_status_info, + .get = snd_soc_usb_get_offload_status, + .put = NULL, +}; + static int soc_usb_put_offload_dev(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct snd_soc_usb *ctx = snd_soc_usb_find_priv_data(component->dev); + struct snd_soc_usb *ctx = snd_soc_find_usb_ctx(component->dev->of_node); int ret = 0; mutex_lock(&ctx_mutex); @@ -61,7 +112,7 @@ static int soc_usb_get_offload_dev(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct snd_soc_usb *ctx = snd_soc_usb_find_priv_data(component->dev); + struct snd_soc_usb *ctx = snd_soc_find_usb_ctx(component->dev->of_node); int ret = 0; mutex_lock(&ctx_mutex); @@ -95,10 +146,96 @@ static const struct snd_kcontrol_new soc_usb_dev_ctrl = { static int snd_soc_usb_control_init(struct snd_soc_component *component) { + int ret; + + ret = snd_ctl_add(component->card->snd_card, + snd_ctl_new1(&soc_usb_status_ctrl, component)); + if (ret < 0) + return ret; + return snd_ctl_add(component->card->snd_card, snd_ctl_new1(&soc_usb_dev_ctrl, component)); } +/** + * snd_soc_usb_set_session_state() - Set the session state for a session + * @usb: SOC USB device + * @session_id: index to active_list + * @state: USB PCM device index + * + * Set the session state for an entry in active_list. This should be only + * called after snd_soc_usb_prepare_session. + * + * Returns 0 on success, negative on error. + * + */ +int snd_soc_usb_set_session_state(struct snd_soc_usb *usb, int session_id, + enum snd_soc_usb_dai_state state) +{ + if (session_id < 0 || session_id >= usb->num_supported_streams) + return -EINVAL; + + mutex_lock(&ctx_mutex); + if (usb->active_list[session_id].state == state) { + mutex_unlock(&ctx_mutex); + return 0; + } + + usb->active_list[session_id].state = state; + mutex_unlock(&ctx_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_set_session_state); + +/** + * snd_soc_usb_prepare_session() - Find and prepare a session + * @usb: SOC USB device + * @card_idx: USB card index + * @pcm_idx: USB PCM device index + * + * Find an open active session slot on the SOC USB device. If all slots + * are busy, return an error. If not, claim the slot and place it into + * the SND_SOC_USB_PREPARED state. This should be called first before + * calling snd_soc_usb_set_session_state or snd_soc_usb_shutdown_session. + * + * Returns the session id (index) to active_list, negative on error. + * + */ +int snd_soc_usb_prepare_session(struct snd_soc_usb *usb, int card_idx, int pcm_idx) +{ + int i; + + mutex_lock(&ctx_mutex); + for (i = 0; i < usb->num_supported_streams; i++) { + if (usb->active_list[i].state == SND_SOC_USB_IDLE) { + usb->active_list[i].active_card_idx = card_idx; + usb->active_list[i].active_pcm_idx = pcm_idx; + usb->active_list[i].state = SND_SOC_USB_PREPARED; + mutex_unlock(&ctx_mutex); + return i; + } + } + mutex_unlock(&ctx_mutex); + + return -EBUSY; +} +EXPORT_SYMBOL_GPL(snd_soc_usb_prepare_session); + +/** + * snd_soc_usb_shutdown_session() - Set USB SOC to idle state + * @usb: SOC USB device + * @session_id: index to active_list + * + * Place the session specified by session_id into the idle/shutdown state. + * + */ +int snd_soc_usb_shutdown_session(struct snd_soc_usb *usb, int session_id) +{ + return snd_soc_usb_set_session_state(usb, session_id, SND_SOC_USB_IDLE); +} +EXPORT_SYMBOL_GPL(snd_soc_usb_shutdown_session); + /** * snd_soc_usb_get_components_tag() - Retrieve SOC USB component tag * @playback: direction of audio stream @@ -185,8 +322,16 @@ struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *componen if (!usb) return ERR_PTR(-ENOMEM); + usb->active_list = kcalloc(num_streams, sizeof(struct snd_soc_usb_session), + GFP_KERNEL); + if (!usb->active_list) { + kfree(usb); + return ERR_PTR(-ENOMEM); + } + usb->component = component; usb->priv_data = data; + usb->num_supported_streams = num_streams; return usb; } @@ -202,6 +347,7 @@ EXPORT_SYMBOL_GPL(snd_soc_usb_allocate_port); void snd_soc_usb_free_port(struct snd_soc_usb *usb) { snd_soc_usb_remove_port(usb); + kfree(usb->active_list); kfree(usb); } EXPORT_SYMBOL_GPL(snd_soc_usb_free_port);