public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: crwulff@gmail.com
To: linux-usb@vger.kernel.org
Cc: Pavel Hofman <pavel.hofman@ivitera.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	James Gruber <jimmyjgruber@gmail.com>,
	Jeff Johnson <quic_jjohnson@quicinc.com>,
	John Keeping <jkeeping@inmusicbrands.com>,
	Jonathan Corbet <corbet@lwn.net>, Lee Jones <lee@kernel.org>,
	Perr Zhang <perr@usb7.net>,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	Chris Wulff <crwulff@gmail.com>
Subject: [PATCH RFC 10/14] usb: gadget: f_uac2: Make string table dynamic with strings from all alt modes
Date: Sat, 28 Sep 2024 11:09:01 -0400	[thread overview]
Message-ID: <20240928150905.2616313-11-crwulff@gmail.com> (raw)
In-Reply-To: <20240928150905.2616313-1-crwulff@gmail.com>

From: Chris Wulff <crwulff@gmail.com>

The number of strings is now dependent on how many alt modes exist and
what their strings are set to. This allows the strings to be dynamically
consolidated where alt modes use the same strings, or separate when
different strings are configured in some alt modes.

Signed-off-by: Chris Wulff <crwulff@gmail.com>
---
 drivers/usb/gadget/function/f_uac2.c | 181 +++++++++++++++++----------
 1 file changed, 113 insertions(+), 68 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index e9f951215c26..54702888855d 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -93,38 +93,6 @@ static int afunc_notify(struct g_audio *agdev, int unit_id, int cs);
 
 /* --------- USB Function Interface ------------- */
 
-enum {
-	STR_ASSOC,
-	STR_IF_CTRL,
-	STR_CLKSRC_IN,
-	STR_CLKSRC_OUT,
-	STR_USB_IT,
-	STR_USB_IT_CH,
-	STR_IO_IT,
-	STR_IO_IT_CH,
-	STR_USB_OT,
-	STR_IO_OT,
-	STR_FU_IN,
-	STR_FU_OUT,
-	STR_AS_OUT_ALT0,
-	STR_AS_OUT_ALT1,
-	STR_AS_IN_ALT0,
-	STR_AS_IN_ALT1,
-	NUM_STR_DESCRIPTORS,
-};
-
-static struct usb_string strings_fn[NUM_STR_DESCRIPTORS + 1] = {};
-
-static struct usb_gadget_strings str_fn = {
-	.language = 0x0409,	/* en-us */
-	.strings = strings_fn,
-};
-
-static struct usb_gadget_strings *fn_strings[] = {
-	&str_fn,
-	NULL,
-};
-
 static struct usb_interface_assoc_descriptor iad_desc = {
 	.bLength = sizeof iad_desc,
 	.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
@@ -649,6 +617,98 @@ struct cntrl_subrange_lay3 {
 
 DECLARE_UAC2_CNTRL_RANGES_LAY3(srates, UAC_MAX_RATES);
 
+/*-------------------------------------------------------------------------*/
+
+/*
+ * String handling
+ */
+
+#define MAX_STRINGS 256
+
+static int add_string(struct usb_string *strings, const char *s)
+{
+	int i;
+
+	if (!s || s[0] == '\0')
+		return 0;
+
+	for (i = 0; i < MAX_STRINGS; i++) {
+		if (!strings[i].s) {
+			strings[i].s = s;
+			return 0; /* IDs aren't allocated yet */
+		}
+
+		if (!strcmp(s, strings[i].s))
+			return strings[i].id;
+	}
+
+	return -1;
+}
+
+static void add_alt_strings(struct usb_string *strings, struct f_uac2_alt_opts *alt_opts, bool fu)
+{
+	add_string(strings, alt_opts->name);
+	add_string(strings, alt_opts->it_name);
+	add_string(strings, alt_opts->it_ch_name);
+	add_string(strings, alt_opts->ot_name);
+	if (fu)
+		add_string(strings, alt_opts->fu_vol_name);
+}
+
+static struct usb_string *attach_strings(struct usb_composite_dev *cdev,
+					 struct f_uac2_opts *audio_opts)
+{
+	struct usb_string	*strings = kzalloc(sizeof(struct usb_string) * MAX_STRINGS,
+						   GFP_KERNEL);
+	struct f_uac2_alt_opts	*alt_opts;
+	struct usb_string	*us;
+	int			strings_fn_length;
+
+	struct usb_gadget_strings strings_fn = {
+		.language = 0x0409,	/* en-us */
+		.strings = strings
+	};
+
+	struct usb_gadget_strings *fn_strings[] = {
+		&strings_fn,
+		NULL,
+	};
+
+	if (!strings)
+		return ERR_PTR(-ENOMEM);
+
+	/* Add all the strings from all the alt mode options */
+	add_string(strings, audio_opts->function_name);
+	add_string(strings, audio_opts->if_ctrl_name);
+	add_string(strings, audio_opts->clksrc_in_name);
+	add_string(strings, audio_opts->clksrc_out_name);
+	add_string(strings, audio_opts->c_alt_0_opts.name);
+	add_string(strings, audio_opts->p_alt_0_opts.name);
+	add_alt_strings(strings, &audio_opts->c_alt_1_opts, FUOUT_EN(audio_opts));
+	add_alt_strings(strings, &audio_opts->p_alt_1_opts, FUIN_EN(audio_opts));
+	list_for_each_entry(alt_opts, &audio_opts->c_alt_opts, list) {
+		add_alt_strings(strings, alt_opts, FUOUT_EN(audio_opts));
+	}
+	list_for_each_entry(alt_opts, &audio_opts->p_alt_opts, list) {
+		add_alt_strings(strings, alt_opts, FUIN_EN(audio_opts));
+	}
+
+	for (strings_fn_length = 0; strings[strings_fn_length].s; strings_fn_length++)
+		;
+
+	/* Attach strings to the composite device and get string IDs assigned */
+	us = usb_gstrings_attach(cdev, fn_strings, strings_fn_length);
+
+	/* Strings are now copied to the composite device and we use the
+	 * copy in "us" going forward, that has all the string IDs.
+	 */
+	kfree(strings);
+
+	return us;
+}
+
+/*-------------------------------------------------------------------------*/
+
 static int set_ep_max_packet_size_bint(struct device *dev, const struct f_uac2_alt_opts *alt_opts,
 	struct usb_endpoint_descriptor *ep_desc,
 	enum usb_device_speed speed, bool is_playback)
@@ -994,26 +1054,11 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 	if (ret)
 		return ret;
 
-	strings_fn[STR_ASSOC].s = uac2_opts->function_name;
-	strings_fn[STR_IF_CTRL].s = uac2_opts->if_ctrl_name;
-	strings_fn[STR_CLKSRC_IN].s = uac2_opts->clksrc_in_name;
-	strings_fn[STR_CLKSRC_OUT].s = uac2_opts->clksrc_out_name;
-
-	strings_fn[STR_USB_IT].s = uac2_opts->c_it_name;
-	strings_fn[STR_USB_IT_CH].s = uac2_opts->c_it_ch_name;
-	strings_fn[STR_IO_OT].s = uac2_opts->c_ot_name;
-	strings_fn[STR_FU_OUT].s = uac2_opts->c_fu_vol_name;
-	strings_fn[STR_AS_OUT_ALT0].s = "Playback Inactive";
-	strings_fn[STR_AS_OUT_ALT1].s = "Playback Active";
-
-	strings_fn[STR_IO_IT].s = uac2_opts->p_it_name;
-	strings_fn[STR_IO_IT_CH].s = uac2_opts->p_it_ch_name;
-	strings_fn[STR_USB_OT].s = uac2_opts->p_ot_name;
-	strings_fn[STR_FU_IN].s = uac2_opts->p_fu_vol_name;
-	strings_fn[STR_AS_IN_ALT0].s = "Capture Inactive";
-	strings_fn[STR_AS_IN_ALT1].s = "Capture Active";
-
-	us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn));
+	/* Past this point, all settings that apply to an alt mode should
+	 * be used from their alt mode opts.
+	 */
+
+	us = attach_strings(cdev, uac2_opts);
 	if (IS_ERR(us))
 		return PTR_ERR(us);
 
@@ -1030,30 +1075,30 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 		}
 	}
 
-	iad_desc.iFunction = us[STR_ASSOC].id;
-	std_ac_if_desc.iInterface = us[STR_IF_CTRL].id;
-	in_clk_src_desc.iClockSource = us[STR_CLKSRC_IN].id;
-	out_clk_src_desc.iClockSource = us[STR_CLKSRC_OUT].id;
-	usb_out_it_desc.iTerminal = us[STR_USB_IT].id;
-	usb_out_it_desc.iChannelNames = us[STR_USB_IT_CH].id;
-	io_in_it_desc.iTerminal = us[STR_IO_IT].id;
-	io_in_it_desc.iChannelNames = us[STR_IO_IT_CH].id;
-	usb_in_ot_desc.iTerminal = us[STR_USB_OT].id;
-	io_out_ot_desc.iTerminal = us[STR_IO_OT].id;
-	std_as_out_if0_desc.iInterface = us[STR_AS_OUT_ALT0].id;
-	std_as_out_if1_desc.iInterface = us[STR_AS_OUT_ALT1].id;
-	std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id;
-	std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id;
+	iad_desc.iFunction = add_string(us, uac2_opts->function_name);
+	std_ac_if_desc.iInterface = add_string(us, uac2_opts->if_ctrl_name);
+	in_clk_src_desc.iClockSource = add_string(us, uac2_opts->clksrc_in_name);
+	out_clk_src_desc.iClockSource = add_string(us, uac2_opts->clksrc_out_name);
+	usb_out_it_desc.iTerminal = add_string(us, uac2_opts->c_alt_1_opts.it_name);
+	usb_out_it_desc.iChannelNames = add_string(us, uac2_opts->c_alt_1_opts.it_ch_name);
+	io_in_it_desc.iTerminal = add_string(us, uac2_opts->p_alt_1_opts.it_name);
+	io_in_it_desc.iChannelNames = add_string(us, uac2_opts->p_alt_1_opts.it_ch_name);
+	usb_in_ot_desc.iTerminal = add_string(us, uac2_opts->p_alt_1_opts.ot_name);
+	io_out_ot_desc.iTerminal = add_string(us, uac2_opts->c_alt_1_opts.ot_name);
+	std_as_out_if0_desc.iInterface = add_string(us, uac2_opts->c_alt_0_opts.name);
+	std_as_out_if1_desc.iInterface = add_string(us, uac2_opts->c_alt_1_opts.name);
+	std_as_in_if0_desc.iInterface = add_string(us, uac2_opts->p_alt_0_opts.name);
+	std_as_in_if1_desc.iInterface = add_string(us, uac2_opts->p_alt_0_opts.name);
 
 	if (FUOUT_EN(uac2_opts)) {
 		u8 *i_feature = (u8 *)out_feature_unit_desc +
 				out_feature_unit_desc->bLength - 1;
-		*i_feature = us[STR_FU_OUT].id;
+		*i_feature = add_string(us, uac2_opts->c_alt_1_opts.fu_vol_name);
 	}
 	if (FUIN_EN(uac2_opts)) {
 		u8 *i_feature = (u8 *)in_feature_unit_desc +
 				in_feature_unit_desc->bLength - 1;
-		*i_feature = us[STR_FU_IN].id;
+		*i_feature = add_string(us, uac2_opts->p_alt_1_opts.fu_vol_name);
 	}
 
 
-- 
2.43.0


  parent reply	other threads:[~2024-09-28 15:09 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-28 15:08 [PATCH RFC 00/14] usb: gadget: f_uac: Add support for alt mode settings crwulff
2024-09-28 15:08 ` [PATCH RFC 01/14] usb: gadget: f_uac: Refactor common configfs attribute defines used in UAC1/2 crwulff
2024-09-28 15:08 ` [PATCH RFC 02/14] usb: gadget: f_uac1: Fix fs/hs/ss descriptors to have correct values crwulff
2024-09-28 15:08 ` [PATCH RFC 03/14] usb: gadget: f_uac1: Add adaptive sync support for capture crwulff
2024-09-28 15:08 ` [PATCH RFC 04/14] usb: gadget: f_uac2: Move max packet size code to a common header crwulff
2024-09-28 15:08 ` [PATCH RFC 05/14] usb: gadget: f_uac1: Add hs_bint to configfs crwulff
2024-09-28 15:08 ` [PATCH RFC 06/14] usb: gadget: f_uac1: Add terminal type attributes crwulff
2024-09-28 15:08 ` [PATCH RFC 07/14] usb: gadget: f_uac1: Add alt mode settings interface crwulff
2024-09-28 15:08 ` [PATCH RFC 08/14] usb: gadget: f_uac2: " crwulff
2024-09-28 15:09 ` [PATCH RFC 09/14] usb: gadget: f_uac1: Make string table dynamic with strings from all alt modes crwulff
2024-09-28 15:09 ` crwulff [this message]
2024-09-28 15:09 ` [PATCH RFC 11/14] usb: gadget: f_uac1: Generate dynamic descriptors based on alt opts crwulff
2024-09-28 15:09 ` [PATCH RFC 12/14] usb: gadget: f_uac2: " crwulff
2024-09-28 15:09 ` [PATCH RFC 13/14] usb: gadget: f_uac1: support ganged volume/mute controls crwulff
2024-09-28 15:09 ` [PATCH RFC 14/14] usb: gadget: f_uac2: " crwulff

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240928150905.2616313-11-crwulff@gmail.com \
    --to=crwulff@gmail.com \
    --cc=corbet@lwn.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=jimmyjgruber@gmail.com \
    --cc=jkeeping@inmusicbrands.com \
    --cc=lee@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=pavel.hofman@ivitera.com \
    --cc=perr@usb7.net \
    --cc=quic_jjohnson@quicinc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox