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 --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;
--
2.43.0