From patchwork Fri Aug 29 08:44:35 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jassi Brar X-Patchwork-Id: 36271 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f69.google.com (mail-pa0-f69.google.com [209.85.220.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id BE86B2054D for ; Fri, 29 Aug 2014 08:45:06 +0000 (UTC) Received: by mail-pa0-f69.google.com with SMTP id kx10sf33580878pab.8 for ; Fri, 29 Aug 2014 01:45:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:sender:precedence:list-id:x-original-sender :x-original-authentication-results:mailing-list:list-post:list-help :list-archive:list-unsubscribe; bh=cO2jV8utJw5x02AExXNCxEXDrswW9D+TEZ/1FWXal6c=; b=ZtOdNiDyDigLtpJbyXwicsu8vwjlstPE6V5RbpShKbiST5LuS88GJdzmbNJrlX2kxs /v8smallGwNd9J6NK6zPQUIfSdMLMYEWUb7wWa2JEcxsvAikwFR/06SLJ3VVlU73ZidX HRSj6aKaMz7udp5HhRZ9hfFg3yM92maiTZ4049rw5XC9ueIQbUVokm8/wHFpCw9dCE5K UaXFqDICDL6WkyPfRyCCJZzPVkjj9pm7vL7FmQoherXVQPcXy9hahCetdmePViPpXUr5 TphNfTQUSSkFgpEDcumFBUVvxFo1g8oMKuLUQp9ed4123Rmvp85/NTDOettB1/jLG4Ji w8+Q== X-Gm-Message-State: ALoCoQnJ34dvCxhZQiMUHct/1EluuHNAfc8iUntNB9kNVANTnMNRtW9j942JRpesAOcc4fgOeKha X-Received: by 10.68.222.194 with SMTP id qo2mr5195077pbc.6.1409301906095; Fri, 29 Aug 2014 01:45:06 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.89.231 with SMTP id v94ls877484qgd.14.gmail; Fri, 29 Aug 2014 01:45:06 -0700 (PDT) X-Received: by 10.220.97.5 with SMTP id j5mr9118452vcn.16.1409301905981; Fri, 29 Aug 2014 01:45:05 -0700 (PDT) Received: from mail-vc0-f172.google.com (mail-vc0-f172.google.com [209.85.220.172]) by mx.google.com with ESMTPS id qa10si5896283vcb.103.2014.08.29.01.45.05 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 29 Aug 2014 01:45:05 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.172 as permitted sender) client-ip=209.85.220.172; Received: by mail-vc0-f172.google.com with SMTP id ij19so2185096vcb.3 for ; Fri, 29 Aug 2014 01:45:05 -0700 (PDT) X-Received: by 10.52.97.233 with SMTP id ed9mr7646408vdb.16.1409301905893; Fri, 29 Aug 2014 01:45:05 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.45.67 with SMTP id uj3csp357512vcb; Fri, 29 Aug 2014 01:45:05 -0700 (PDT) X-Received: by 10.66.66.193 with SMTP id h1mr13333808pat.93.1409301904904; Fri, 29 Aug 2014 01:45:04 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id gl10si10981816pbd.139.2014.08.29.01.45.04 for ; Fri, 29 Aug 2014 01:45:04 -0700 (PDT) Received-SPF: none (google.com: linux-usb-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753270AbaH2IpA (ORCPT + 2 others); Fri, 29 Aug 2014 04:45:00 -0400 Received: from mail-pd0-f180.google.com ([209.85.192.180]:34395 "EHLO mail-pd0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753034AbaH2Io6 (ORCPT ); Fri, 29 Aug 2014 04:44:58 -0400 Received: by mail-pd0-f180.google.com with SMTP id p10so17982pdj.39 for ; Fri, 29 Aug 2014 01:44:58 -0700 (PDT) X-Received: by 10.68.225.133 with SMTP id rk5mr13274628pbc.101.1409301898012; Fri, 29 Aug 2014 01:44:58 -0700 (PDT) Received: from localhost.localdomain ([59.91.206.173]) by mx.google.com with ESMTPSA id zf5sm5839716pbc.44.2014.08.29.01.44.53 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 29 Aug 2014 01:44:57 -0700 (PDT) From: Jassi Brar To: linux-usb@vger.kernel.org Cc: daniel@zonque.org, clemens@ladisch.de, balbi@ti.com, sebastian.reimers@googlemail.com, xbing6@gmail.com, stern@rowland.harvard.edu, Jassi Brar Subject: [PATCHv2] usb: gadget: f_uac2: modulate playback data rate Date: Fri, 29 Aug 2014 14:14:35 +0530 Message-Id: <1409301875-21643-1-git-send-email-jaswinder.singh@linaro.org> X-Mailer: git-send-email 1.8.1.2 Sender: linux-usb-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: jaswinder.singh@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.172 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , The UAC2 function driver currently responds to all packets at all times with wMaxPacketSize packets. That results in way too fast audio playback as the function driver (which is in fact supposed to define the audio stream pace) delivers as fast as it can. We need data rate to match, as accurately as possible, the sampling rate expressed by the UAC2 topology to the Host. We do this by sending packets of varying length (1 sample more than usual) in a pattern so that we get the desired data rate over a period of a second or sooner. The payload pattern is calculated only once (using "Alan's Algo"), when the Host enables the interface, and saved in an array so that the 2 ping-pong usb_requests directly index into the pattern array to figure out the payload length they are supposed to transfer next. Note that the increased overhead in agdev_iso_complete() is almost zero. Signed-off-by: Jassi Brar --- Changes since v1: o Fix pattern[] to show payload size in bytes, rather than samples, by multiplying each element with frame-size. drivers/usb/gadget/function/f_uac2.c | 76 ++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 246a778..edc189e 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -59,8 +59,15 @@ const char *uac2_name = "snd_uac2"; struct uac2_req { struct uac2_rtd_params *pp; /* parent param */ struct usb_request *req; + unsigned idx; /* current element of length-pattern loop */ }; +/* + * 5512.5Hz is going to need the maximum number of elements (80), + * in the length-pattern loop, among standard ALSA supported rates. + */ +#define MAX_LOOP_LEN 80 + struct uac2_rtd_params { struct snd_uac2_chip *uac2; /* parent chip */ bool ep_enabled; /* if the ep is enabled */ @@ -80,6 +87,9 @@ struct uac2_rtd_params { unsigned max_psize; struct uac2_req ureq[USB_XFERS]; + unsigned pattern[MAX_LOOP_LEN]; + unsigned plen; /* total entries in pattern[] */ + spinlock_t lock; }; @@ -191,8 +201,12 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req) spin_lock_irqsave(&prm->lock, flags); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Update length for next payload */ + ur->idx = (ur->idx + USB_XFERS) % prm->plen; + req->length = prm->pattern[ur->idx]; req->actual = req->length; + } pending = prm->hw_ptr % prm->period_size; pending += req->actual; @@ -1066,6 +1080,31 @@ err: return -EINVAL; } +/* + * Find optimal pattern of payloads for a given number + * of samples and maximum sync period (in ms) over which + * we have to distribute them uniformly. + */ +static unsigned +get_pattern(unsigned samples, unsigned sync, unsigned *pt) +{ + unsigned n, x = 0, i = 0, p = samples % sync; + + do { + x += p; + n = samples / sync; + if (x >= sync) { + n += 1; + x -= sync; + } + if (pt) + pt[i] = n; + i++; + } while (x); + + return i; +} + static int afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) { @@ -1097,11 +1136,41 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) if (intf == agdev->as_out_intf) { ep = agdev->out_ep; prm = &uac2->c_prm; + prm->plen = 1; + prm->pattern[0] = prm->max_psize; config_ep_by_speed(gadget, fn, ep); agdev->as_out_alt = alt; } else if (intf == agdev->as_in_intf) { + struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev); + unsigned intvl, rate, fsz; + + if (gadget->speed == USB_SPEED_FULL) + intvl = (1 << (fs_epin_desc.bInterval - 1)) * 1000; + else + intvl = (1 << (hs_epin_desc.bInterval - 1)) * 125; + + rate = opts->p_srate; + if (rate == 5512) { /* which implies 5512.5 practically */ + rate = 55125; + intvl *= 10; + } + ep = agdev->in_ep; prm = &uac2->p_prm; + prm->plen = get_pattern(rate, intvl, NULL); /* dry run */ + /* We try to support arbitrary rates too */ + if (prm->plen > MAX_LOOP_LEN) { + prm->plen = 1; + prm->pattern[0] = rate / intvl; + } else { + prm->plen = get_pattern(rate, intvl, prm->pattern); + } + + fsz = opts->p_ssize * num_channels(opts->p_chmask); + /* Convert samples to bytes */ + for (i = 0; i < prm->plen; i++) + prm->pattern[i] *= fsz; + config_ep_by_speed(gadget, fn, ep); agdev->as_in_alt = alt; } else { @@ -1125,12 +1194,13 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) prm->ureq[i].req = req; prm->ureq[i].pp = prm; + prm->ureq[i].idx = i % prm->plen; req->zero = 0; req->context = &prm->ureq[i]; - req->length = prm->max_psize; + req->length = prm->pattern[prm->ureq[i].idx]; req->complete = agdev_iso_complete; - req->buf = prm->rbuf + i * req->length; + req->buf = prm->rbuf + i * prm->max_psize; } if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC))