From patchwork Fri Aug 29 06:13:39 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jassi Brar X-Patchwork-Id: 36270 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-yk0-f198.google.com (mail-yk0-f198.google.com [209.85.160.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 6152D2054F for ; Fri, 29 Aug 2014 06:14:23 +0000 (UTC) Received: by mail-yk0-f198.google.com with SMTP id q200sf7899039ykb.9 for ; Thu, 28 Aug 2014 23:14:23 -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=V8YtntOSmf+X8lpyBeWY8TFdNmp3QQZTDqyblGqtXsU=; b=XI9JDjWhLl83YfmrSpaw2NbMrLijI5KqCf4s3taYsqUCDmpHzyDvB0yqXWVvpBH9vw kFumd1FsMGGx5Te1xlwgVgsSAPJZbOoPr/jqoAUTkDPTGpdk9ykocBwg743KeSzFzd6H 2P+ZcUrTd6Z4+pcWjwKv/MQTwcNh3zLIXpIrqSieXpYm/Fzrrqufy26HDsmwrfosev8n /v6bg2Fb7ncDDHvXtzgg69LOaG/czohVD2UFvh8YvoFV88Sd/gLbgTFDVp1+P1r8pjSz MC/tVgkyLpurQr3YyvfELDWUnGo7HvWwlc8kSlPQrmh6cY0meGoUoMCdugCMMNE0ewzz wcWw== X-Gm-Message-State: ALoCoQmg2lNME1+jD628GyhkTJsI/pcIOLAtB5XXAoSKzIsViNFxaZhkaPQm3oJ1ePC9PMCRxmbm X-Received: by 10.236.28.228 with SMTP id g64mr4675155yha.40.1409292863220; Thu, 28 Aug 2014 23:14:23 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.33.246 with SMTP id j109ls888463qgj.83.gmail; Thu, 28 Aug 2014 23:14:23 -0700 (PDT) X-Received: by 10.220.79.68 with SMTP id o4mr6222114vck.38.1409292863143; Thu, 28 Aug 2014 23:14:23 -0700 (PDT) Received: from mail-vc0-f170.google.com (mail-vc0-f170.google.com [209.85.220.170]) by mx.google.com with ESMTPS id q3si5870735vct.6.2014.08.28.23.14.22 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 28 Aug 2014 23:14:22 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.170 as permitted sender) client-ip=209.85.220.170; Received: by mail-vc0-f170.google.com with SMTP id la4so2017892vcb.15 for ; Thu, 28 Aug 2014 23:14:22 -0700 (PDT) X-Received: by 10.52.138.210 with SMTP id qs18mr7127696vdb.18.1409292862772; Thu, 28 Aug 2014 23:14:22 -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 uj3csp343819vcb; Thu, 28 Aug 2014 23:14:22 -0700 (PDT) X-Received: by 10.70.102.5 with SMTP id fk5mr12767426pdb.114.1409292861709; Thu, 28 Aug 2014 23:14:21 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id sa2si10797526pbc.8.2014.08.28.23.14.21 for ; Thu, 28 Aug 2014 23:14:21 -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 S1752150AbaH2GOT (ORCPT + 2 others); Fri, 29 Aug 2014 02:14:19 -0400 Received: from mail-pa0-f42.google.com ([209.85.220.42]:48365 "EHLO mail-pa0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751794AbaH2GOS (ORCPT ); Fri, 29 Aug 2014 02:14:18 -0400 Received: by mail-pa0-f42.google.com with SMTP id lf10so5719394pab.29 for ; Thu, 28 Aug 2014 23:14:18 -0700 (PDT) X-Received: by 10.70.38.4 with SMTP id c4mr12870997pdk.108.1409292858053; Thu, 28 Aug 2014 23:14:18 -0700 (PDT) Received: from localhost.localdomain ([59.89.160.2]) by mx.google.com with ESMTPSA id x1sm8513818pdm.13.2014.08.28.23.14.13 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 28 Aug 2014 23:14:17 -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: [PATCH] usb: gadget: f_uac2: modulate playback data rate Date: Fri, 29 Aug 2014 11:43:39 +0530 Message-Id: <1409292819-2714-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.170 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 --- drivers/usb/gadget/function/f_uac2.c | 70 ++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 246a778..84fd3b0 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; /* valid 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,35 @@ 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; + + 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); + } config_ep_by_speed(gadget, fn, ep); agdev->as_in_alt = alt; } else { @@ -1125,12 +1188,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))