diff mbox series

[RFC,05/14] usb: gadget: f_uac1: Add hs_bint to configfs.

Message ID 20240928150905.2616313-6-crwulff@gmail.com
State New
Headers show
Series usb: gadget: f_uac: Add support for alt mode settings | expand

Commit Message

Chris Wulff Sept. 28, 2024, 3:08 p.m. UTC
From: Chris Wulff <crwulff@gmail.com>

This matches options from f_uac2. This only adds the options but using
it requires additional descriptors added later.

Signed-off-by: Chris Wulff <crwulff@gmail.com>
---
 .../ABI/testing/configfs-usb-gadget-uac1      |  2 +
 Documentation/usb/gadget-testing.rst          |  2 +
 drivers/usb/gadget/function/f_uac1.c          | 89 +++++++++++++++++++
 drivers/usb/gadget/function/u_uac1.h          |  4 +
 4 files changed, 97 insertions(+)
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1 b/Documentation/ABI/testing/configfs-usb-gadget-uac1
index 758b8c9a988a..fed8567b10ec 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-uac1
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1
@@ -8,6 +8,7 @@  Description:
 		c_chmask		capture channel mask
 		c_srate			list of capture sampling rates (comma-separated)
 		c_ssize			capture sample size (bytes)
+		c_hs_bint		capture bInterval for HS/SS (1-4: fixed, 0: auto)
 		c_sync			capture synchronization type
 					(async/adaptive)
 		c_mute_present		capture mute control enable
@@ -22,6 +23,7 @@  Description:
 		p_chmask		playback channel mask
 		p_srate			list of playback sampling rates (comma-separated)
 		p_ssize			playback sample size (bytes)
+		p_hs_bint		playback bInterval for HS/SS (1-4: fixed, 0: auto)
 		p_mute_present		playback mute control enable
 		p_volume_present	playback volume control enable
 		p_volume_min		playback volume control min value
diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst
index 68fc0011b388..bdb82b58b260 100644
--- a/Documentation/usb/gadget-testing.rst
+++ b/Documentation/usb/gadget-testing.rst
@@ -958,6 +958,7 @@  The uac1 function provides these attributes in its function directory:
 	c_volume_min     capture volume control min value (in 1/256 dB)
 	c_volume_max     capture volume control max value (in 1/256 dB)
 	c_volume_res     capture volume control resolution (in 1/256 dB)
+	c_hs_bint        capture bInterval for HS/SS (1-4: fixed, 0: auto)
 	fb_max           maximum extra bandwidth in async mode
 	p_chmask         playback channel mask
 	p_srate          list of playback sampling rates (comma-separated)
@@ -967,6 +968,7 @@  The uac1 function provides these attributes in its function directory:
 	p_volume_min     playback volume control min value (in 1/256 dB)
 	p_volume_max     playback volume control max value (in 1/256 dB)
 	p_volume_res     playback volume control resolution (in 1/256 dB)
+	p_hs_bint        playback bInterval for HS/SS (1-4: fixed, 0: auto)
 	req_number       the number of pre-allocated requests for both capture
 	                 and playback
 	function_name    name of the interface
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 84423d9a8bd7..861e6219552e 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -1159,6 +1159,32 @@  f_audio_suspend(struct usb_function *f)
 }
 
 /*-------------------------------------------------------------------------*/
+
+static int set_ep_max_packet_size_bint(struct device *dev, const struct f_uac1_opts *opts,
+	struct usb_endpoint_descriptor *ep_desc,
+	enum usb_device_speed speed, bool is_playback)
+{
+	int chmask, srate, ssize, hs_bint, sync;
+
+	if (is_playback) {
+		chmask = opts->p_chmask;
+		srate = get_max_srate(opts->p_srates);
+		ssize = opts->p_ssize;
+		hs_bint = opts->p_hs_bint;
+		sync = USB_ENDPOINT_SYNC_ASYNC;
+	} else {
+		chmask = opts->c_chmask;
+		srate = get_max_srate(opts->c_srates);
+		ssize = opts->c_ssize;
+		hs_bint = opts->c_hs_bint;
+		sync = opts->c_sync;
+	}
+
+	return uac_set_ep_max_packet_size_bint(
+		dev, ep_desc, speed, is_playback, hs_bint, chmask,
+		srate, ssize, sync, opts->fb_max);
+}
+
 static struct uac_feature_unit_descriptor *build_fu_desc(int chmask)
 {
 	struct uac_feature_unit_descriptor *fu_desc;
@@ -1419,6 +1445,15 @@  static int f_audio_validate_opts(struct g_audio *audio, struct device *dev)
 		return -EINVAL;
 	}
 
+	if ((opts->p_hs_bint < 0) || (opts->p_hs_bint > 4)) {
+		dev_err(dev, "Error: incorrect playback HS/SS bInterval (1-4: fixed, 0: auto)\n");
+		return -EINVAL;
+	}
+	if ((opts->c_hs_bint < 0) || (opts->c_hs_bint > 4)) {
+		dev_err(dev, "Error: incorrect capture HS/SS bInterval (1-4: fixed, 0: auto)\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -1613,6 +1648,54 @@  static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 		uac1->as_in_alt = 0;
 	}
 
+	hs_as_in_ep_desc.bInterval = audio_opts->p_hs_bint;
+	ss_as_in_ep_desc.bInterval = audio_opts->p_hs_bint;
+	hs_as_out_ep_desc.bInterval = audio_opts->c_hs_bint;
+	ss_as_out_ep_desc.bInterval = audio_opts->c_hs_bint;
+
+	/* Calculate wMaxPacketSize according to audio bandwidth */
+	status = set_ep_max_packet_size_bint(dev, audio_opts, &fs_as_in_ep_desc,
+					     USB_SPEED_FULL, true);
+	if (status < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		goto err_free_fu;
+	}
+
+	status = set_ep_max_packet_size_bint(dev, audio_opts, &fs_as_out_ep_desc,
+					     USB_SPEED_FULL, false);
+	if (status < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		goto err_free_fu;
+	}
+
+	status = set_ep_max_packet_size_bint(dev, audio_opts, &hs_as_in_ep_desc,
+					     USB_SPEED_HIGH, true);
+	if (status < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		goto err_free_fu;
+	}
+
+	status = set_ep_max_packet_size_bint(dev, audio_opts, &hs_as_out_ep_desc,
+					     USB_SPEED_HIGH, false);
+	if (status < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		goto err_free_fu;
+	}
+
+	status = set_ep_max_packet_size_bint(dev, audio_opts, &ss_as_in_ep_desc,
+					     USB_SPEED_SUPER, true);
+	if (status < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		goto err_free_fu;
+	}
+
+	status = set_ep_max_packet_size_bint(dev, audio_opts, &hs_as_out_ep_desc,
+					     USB_SPEED_SUPER, false);
+	if (status < 0) {
+		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+		goto err_free_fu;
+	}
+
 	audio->gadget = gadget;
 
 	status = -ENODEV;
@@ -1782,9 +1865,11 @@  UAC1_ATTRIBUTE(u32, c_chmask);
 UAC1_RATE_ATTRIBUTE(c_srate);
 UAC1_ATTRIBUTE_SYNC(c_sync);
 UAC1_ATTRIBUTE(u32, c_ssize);
+UAC1_ATTRIBUTE(u8, c_hs_bint);
 UAC1_ATTRIBUTE(u32, p_chmask);
 UAC1_RATE_ATTRIBUTE(p_srate);
 UAC1_ATTRIBUTE(u32, p_ssize);
+UAC1_ATTRIBUTE(u8, p_hs_bint);
 UAC1_ATTRIBUTE(u32, req_number);
 
 UAC1_ATTRIBUTE(bool, p_mute_present);
@@ -1818,9 +1903,11 @@  static struct configfs_attribute *f_uac1_attrs[] = {
 	&f_uac1_opts_attr_c_srate,
 	&f_uac1_opts_attr_c_sync,
 	&f_uac1_opts_attr_c_ssize,
+	&f_uac1_opts_attr_c_hs_bint,
 	&f_uac1_opts_attr_p_chmask,
 	&f_uac1_opts_attr_p_srate,
 	&f_uac1_opts_attr_p_ssize,
+	&f_uac1_opts_attr_p_hs_bint,
 	&f_uac1_opts_attr_req_number,
 	&f_uac1_opts_attr_fb_max,
 
@@ -1883,9 +1970,11 @@  static struct usb_function_instance *f_audio_alloc_inst(void)
 	opts->c_srates[0] = UAC1_DEF_CSRATE;
 	opts->c_sync = UAC1_DEF_CSYNC;
 	opts->c_ssize = UAC1_DEF_CSSIZE;
+	opts->c_hs_bint = UAC1_DEF_CHSBINT;
 	opts->p_chmask = UAC1_DEF_PCHMASK;
 	opts->p_srates[0] = UAC1_DEF_PSRATE;
 	opts->p_ssize = UAC1_DEF_PSSIZE;
+	opts->p_hs_bint = UAC1_DEF_PHSBINT;
 
 	opts->p_mute_present = UAC1_DEF_MUTE_PRESENT;
 	opts->p_volume_present = UAC1_DEF_VOLUME_PRESENT;
diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h
index 59eac5ca8114..c7e7480bf71f 100644
--- a/drivers/usb/gadget/function/u_uac1.h
+++ b/drivers/usb/gadget/function/u_uac1.h
@@ -16,9 +16,11 @@ 
 #define UAC1_DEF_CSRATE		48000
 #define UAC1_DEF_CSYNC		USB_ENDPOINT_SYNC_ADAPTIVE
 #define UAC1_DEF_CSSIZE		2
+#define UAC1_DEF_CHSBINT	0
 #define UAC1_DEF_PCHMASK	0x3
 #define UAC1_DEF_PSRATE		48000
 #define UAC1_DEF_PSSIZE		2
+#define UAC1_DEF_PHSBINT	0
 #define UAC1_DEF_REQ_NUM	2
 #define UAC1_DEF_INT_REQ_NUM	10
 
@@ -35,9 +37,11 @@  struct f_uac1_opts {
 	int				c_srates[UAC_MAX_RATES];
 	int				c_sync;
 	int				c_ssize;
+	u8				c_hs_bint;
 	int				p_chmask;
 	int				p_srates[UAC_MAX_RATES];
 	int				p_ssize;
+	u8				p_hs_bint;
 
 	bool			p_mute_present;
 	bool			p_volume_present;