summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/configfs-usb-gadget-uac24
-rw-r--r--Documentation/usb/gadget-testing.rst4
-rw-r--r--drivers/usb/gadget/function/f_uac2.c126
-rw-r--r--drivers/usb/gadget/function/u_uac2.h4
4 files changed, 91 insertions, 47 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac2 b/Documentation/ABI/testing/configfs-usb-gadget-uac2
index 33fb237b3ca5..3371c39f651d 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-uac2
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uac2
@@ -8,7 +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)
+ 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
@@ -23,7 +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)
+ 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 bd91191683be..c6d034abce3a 100644
--- a/Documentation/usb/gadget-testing.rst
+++ b/Documentation/usb/gadget-testing.rst
@@ -734,7 +734,7 @@ The uac2 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)
+ 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)
@@ -744,7 +744,7 @@ The uac2 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)
+ p_hs_bint playback bInterval for HS/SS (1-4: fixed, 0: auto)
req_number the number of pre-allocated request for both capture
and playback
function_name name of the interface
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 34bb6c9a9023..48d6fb26bb19 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -664,29 +664,11 @@ static int get_max_srate(const int *srates)
return max_srate;
}
-static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
- struct usb_endpoint_descriptor *ep_desc,
- enum usb_device_speed speed, bool is_playback)
+static int get_max_bw_for_bint(const struct f_uac2_opts *uac2_opts,
+ u8 bint, unsigned int factor, bool is_playback)
{
int chmask, srate, ssize;
- u16 max_size_bw, max_size_ep;
- unsigned int factor;
-
- switch (speed) {
- case USB_SPEED_FULL:
- max_size_ep = 1023;
- factor = 1000;
- break;
-
- case USB_SPEED_HIGH:
- case USB_SPEED_SUPER:
- max_size_ep = 1024;
- factor = 8000;
- break;
-
- default:
- return -EINVAL;
- }
+ u16 max_size_bw;
if (is_playback) {
chmask = uac2_opts->p_chmask;
@@ -704,14 +686,76 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
srate = srate * (1000 + uac2_opts->fb_max) / 1000;
// updated srate is always bigger, therefore DIV_ROUND_UP always yields +1
max_size_bw = num_channels(chmask) * ssize *
- (DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))));
+ (DIV_ROUND_UP(srate, factor / (1 << (bint - 1))));
} else {
// adding 1 frame provision for Win10
max_size_bw = num_channels(chmask) * ssize *
- (DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))) + 1);
+ (DIV_ROUND_UP(srate, factor / (1 << (bint - 1))) + 1);
}
- ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
- max_size_ep));
+ return max_size_bw;
+}
+
+static int set_ep_max_packet_size_bint(struct device *dev, const struct f_uac2_opts *uac2_opts,
+ struct usb_endpoint_descriptor *ep_desc,
+ enum usb_device_speed speed, bool is_playback)
+{
+ u16 max_size_bw, max_size_ep;
+ u8 bint, opts_bint;
+ char *dir;
+
+ switch (speed) {
+ case USB_SPEED_FULL:
+ max_size_ep = 1023;
+ // fixed
+ bint = ep_desc->bInterval;
+ max_size_bw = get_max_bw_for_bint(uac2_opts, bint, 1000, is_playback);
+ break;
+
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ max_size_ep = 1024;
+ if (is_playback)
+ opts_bint = uac2_opts->p_hs_bint;
+ else
+ opts_bint = uac2_opts->c_hs_bint;
+
+ if (opts_bint > 0) {
+ /* fixed bint */
+ bint = opts_bint;
+ max_size_bw = get_max_bw_for_bint(uac2_opts, bint, 8000, is_playback);
+ } else {
+ /* checking bInterval from 4 to 1 whether the required bandwidth fits */
+ for (bint = 4; bint > 0; --bint) {
+ max_size_bw = get_max_bw_for_bint(
+ uac2_opts, bint, 8000, is_playback);
+ if (max_size_bw <= max_size_ep)
+ break;
+ }
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (is_playback)
+ dir = "Playback";
+ else
+ dir = "Capture";
+
+ if (max_size_bw <= max_size_ep)
+ dev_dbg(dev,
+ "%s: Will use maxpctksize %d and bInterval %d\n",
+ dir, max_size_bw, bint);
+ else {
+ dev_warn(dev,
+ "%s: Req. maxpcktsize %d at bInterval %d > max ISOC %d, may drop data!\n",
+ dir, max_size_bw, bint, max_size_ep);
+ max_size_bw = max_size_ep;
+ }
+
+ ep_desc->wMaxPacketSize = cpu_to_le16(max_size_bw);
+ ep_desc->bInterval = bint;
return 0;
}
@@ -965,13 +1009,13 @@ static int afunc_validate_opts(struct g_audio *agdev, struct device *dev)
return -EINVAL;
}
- if ((opts->p_hs_bint < 1) || (opts->p_hs_bint > 4)) {
- dev_err(dev, "Error: incorrect playback HS/SS bInterval (1-4)\n");
+ 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 < 1) || (opts->c_hs_bint > 4)) {
- dev_err(dev, "Error: incorrect capture HS/SS bInterval (1-4)\n");
+ 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;
}
@@ -1141,43 +1185,43 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
ss_epout_desc.bInterval = uac2_opts->c_hs_bint;
/* Calculate wMaxPacketSize according to audio bandwidth */
- ret = set_ep_max_packet_size(uac2_opts, &fs_epin_desc, USB_SPEED_FULL,
- true);
+ ret = set_ep_max_packet_size_bint(dev, uac2_opts, &fs_epin_desc,
+ USB_SPEED_FULL, true);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
- ret = set_ep_max_packet_size(uac2_opts, &fs_epout_desc, USB_SPEED_FULL,
- false);
+ ret = set_ep_max_packet_size_bint(dev, uac2_opts, &fs_epout_desc,
+ USB_SPEED_FULL, false);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
- ret = set_ep_max_packet_size(uac2_opts, &hs_epin_desc, USB_SPEED_HIGH,
- true);
+ ret = set_ep_max_packet_size_bint(dev, uac2_opts, &hs_epin_desc,
+ USB_SPEED_HIGH, true);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
- ret = set_ep_max_packet_size(uac2_opts, &hs_epout_desc, USB_SPEED_HIGH,
- false);
+ ret = set_ep_max_packet_size_bint(dev, uac2_opts, &hs_epout_desc,
+ USB_SPEED_HIGH, false);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
- ret = set_ep_max_packet_size(uac2_opts, &ss_epin_desc, USB_SPEED_SUPER,
- true);
+ ret = set_ep_max_packet_size_bint(dev, uac2_opts, &ss_epin_desc,
+ USB_SPEED_SUPER, true);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
}
- ret = set_ep_max_packet_size(uac2_opts, &ss_epout_desc, USB_SPEED_SUPER,
- false);
+ ret = set_ep_max_packet_size_bint(dev, uac2_opts, &ss_epout_desc,
+ USB_SPEED_SUPER, false);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return ret;
diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h
index 733a0e0945fb..0510c9bad58d 100644
--- a/drivers/usb/gadget/function/u_uac2.h
+++ b/drivers/usb/gadget/function/u_uac2.h
@@ -19,11 +19,11 @@
#define UAC2_DEF_PCHMASK 0x3
#define UAC2_DEF_PSRATE 48000
#define UAC2_DEF_PSSIZE 2
-#define UAC2_DEF_PHSBINT 4
+#define UAC2_DEF_PHSBINT 0
#define UAC2_DEF_CCHMASK 0x3
#define UAC2_DEF_CSRATE 64000
#define UAC2_DEF_CSSIZE 2
-#define UAC2_DEF_CHSBINT 4
+#define UAC2_DEF_CHSBINT 0
#define UAC2_DEF_CSYNC USB_ENDPOINT_SYNC_ASYNC
#define UAC2_DEF_MUTE_PRESENT 1