usb: gadget: f_uac2: fix packet size calculation
authorJohn Keeping <john@metanate.com>
Fri, 10 Jan 2020 11:28:14 +0000 (11:28 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 15 Jan 2020 09:39:23 +0000 (10:39 +0100)
The packet size for USB audio must always be a multiple of the frame
size, otherwise we are transmitting a partial frame which omits some
channels (and these end up at the wrong offset in the next packet).
Furthermore, it breaks the residue handling such that we end up trying
to send a packet exceeding the maximum packet size for the endpoint.

Signed-off-by: John Keeping <john@metanate.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/function/u_audio.c

index cf4f2358889b54ea32317c74408c0ae36964baff..6d956f190f5ac7322cbcf8a26d444aa13e1117b5 100644 (file)
@@ -407,7 +407,7 @@ int u_audio_start_playback(struct g_audio *audio_dev)
        struct usb_ep *ep;
        struct uac_rtd_params *prm;
        struct uac_params *params = &audio_dev->params;
-       unsigned int factor, rate;
+       unsigned int factor;
        const struct usb_endpoint_descriptor *ep_desc;
        int req_len, i;
 
@@ -426,13 +426,15 @@ int u_audio_start_playback(struct g_audio *audio_dev)
        /* pre-compute some values for iso_complete() */
        uac->p_framesize = params->p_ssize *
                            num_channels(params->p_chmask);
-       rate = params->p_srate * uac->p_framesize;
        uac->p_interval = factor / (1 << (ep_desc->bInterval - 1));
-       uac->p_pktsize = min_t(unsigned int, rate / uac->p_interval,
+       uac->p_pktsize = min_t(unsigned int,
+                               uac->p_framesize *
+                                       (params->p_srate / uac->p_interval),
                                prm->max_psize);
 
        if (uac->p_pktsize < prm->max_psize)
-               uac->p_pktsize_residue = rate % uac->p_interval;
+               uac->p_pktsize_residue = uac->p_framesize *
+                       (params->p_srate % uac->p_interval);
        else
                uac->p_pktsize_residue = 0;