From: Chris Wulff <crwulff@xxxxxxxxx> 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@xxxxxxxxx> --- .../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