summaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/function/f_uac2.c
diff options
context:
space:
mode:
authorRuslan Bilovol <ruslan.bilovol@gmail.com>2021-06-04 00:01:04 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-06-09 11:26:49 +0200
commite89bb4288378b85c82212b60dc98ecda6b3d3a70 (patch)
tree902329a9974240b3a8fe129d0e890e2dcd680cf1 /drivers/usb/gadget/function/f_uac2.c
parentusb: gadget: f_uac2: add adaptive sync support for capture (diff)
downloadlinux-e89bb4288378b85c82212b60dc98ecda6b3d3a70.tar.xz
linux-e89bb4288378b85c82212b60dc98ecda6b3d3a70.zip
usb: gadget: u_audio: add real feedback implementation
This adds interface between userspace and feedback endpoint to report real feedback frequency to the Host. Current implementation adds new userspace interface ALSA mixer control "Capture Pitch 1000000" (similar to aloop driver's "PCM Rate Shift 100000" mixer control) Value in PPM is chosen to have correction value agnostic of the actual HW rate, which the application is not necessarily dealing with, while still retaining a good enough precision to allow smooth clock correction on the playback side, if necessary. Similar to sound/usb/endpoint.c, a slow down is allowed up to 25%. This has no impact on the required bandwidth. Speedup correction has an impact on the bandwidth reserved for the isochronous endpoint. The default allowed speedup is 500ppm. This seems to be more than enough but, if necessary, this is configurable through a module parameter. The reserved bandwidth is rounded up to the next packet size. Usage of this new control is easy to implement in existing userspace tools like alsaloop from alsa-utils. Signed-off-by: Ruslan Bilovol <ruslan.bilovol@gmail.com> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> Link: https://lore.kernel.org/r/20210603220104.1216001-4-jbrunet@baylibre.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/gadget/function/f_uac2.c')
-rw-r--r--drivers/usb/gadget/function/f_uac2.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 321e6c05ba93..ae29ff2b2b68 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
ssize = uac2_opts->c_ssize;
}
+ if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC))
+ srate = srate * (1000 + uac2_opts->fb_max) / 1000;
+
max_size_bw = num_channels(chmask) * ssize *
- ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1);
+ DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
max_size_ep));
@@ -957,6 +960,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
agdev->params.c_srate = uac2_opts->c_srate;
agdev->params.c_ssize = uac2_opts->c_ssize;
agdev->params.req_number = uac2_opts->req_number;
+ agdev->params.fb_max = uac2_opts->fb_max;
ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget");
if (ret)
goto err_free_descs;
@@ -1329,6 +1333,7 @@ UAC2_ATTRIBUTE(c_srate);
UAC2_ATTRIBUTE_SYNC(c_sync);
UAC2_ATTRIBUTE(c_ssize);
UAC2_ATTRIBUTE(req_number);
+UAC2_ATTRIBUTE(fb_max);
static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_attr_p_chmask,
@@ -1339,6 +1344,7 @@ static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_attr_c_ssize,
&f_uac2_opts_attr_c_sync,
&f_uac2_opts_attr_req_number,
+ &f_uac2_opts_attr_fb_max,
NULL,
};
@@ -1378,6 +1384,7 @@ static struct usb_function_instance *afunc_alloc_inst(void)
opts->c_ssize = UAC2_DEF_CSSIZE;
opts->c_sync = UAC2_DEF_CSYNC;
opts->req_number = UAC2_DEF_REQ_NUM;
+ opts->fb_max = UAC2_DEF_FB_MAX;
return &opts->func_inst;
}