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