summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function/f_uac2.c
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@nxp.com>2017-01-04 10:19:23 +0800
committerFelipe Balbi <felipe.balbi@linux.intel.com>2017-01-24 11:04:21 +0200
commite92b9d449d0490800160bfeb5ee1175a02979f47 (patch)
treee6a52e9d53ab3e42e90979aea3473f0ec3935015 /drivers/usb/gadget/function/f_uac2.c
parentec33efe28f9f87e51cc79ce060ae0101eedd5a19 (diff)
usb: gadget: uac2: add req_number as parameter
There are only two requests for uac2, it may not be enough at high loading system which usb interrupt handler can't be serviced on time, then the data will be lost since it is isoc transfer for audio. In this patch, we introduce a parameter for the number for usb request, and the user can override it if current number for request is not enough for his/her use case. Besides, update this parameter for legacy audio gadget and documentation. Signed-off-by: Peter Chen <peter.chen@nxp.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/gadget/function/f_uac2.c')
-rw-r--r--drivers/usb/gadget/function/f_uac2.c39
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 3f4e4785418f..f6a0d3a1311b 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -22,9 +22,6 @@
#include "u_uac2.h"
-/* Keep everyone on toes */
-#define USB_XFERS 2
-
/*
* The driver implements a simple UAC_2 topology.
* USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
@@ -78,7 +75,7 @@ struct uac2_rtd_params {
size_t period_size;
unsigned max_psize;
- struct uac2_req ureq[USB_XFERS];
+ struct uac2_req *ureq;
spinlock_t lock;
};
@@ -269,6 +266,8 @@ static int
uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+ struct audio_dev *agdev = uac2_to_agdev(uac2);
+ struct f_uac2_opts *uac2_opts = agdev_to_uac2_opts(agdev);
struct uac2_rtd_params *prm;
unsigned long flags;
int err = 0;
@@ -300,7 +299,7 @@ uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
/* Clear buffer after Play stops */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss)
- memset(prm->rbuf, 0, prm->max_psize * USB_XFERS);
+ memset(prm->rbuf, 0, prm->max_psize * uac2_opts->req_number);
return err;
}
@@ -943,6 +942,8 @@ static inline void
free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
{
struct snd_uac2_chip *uac2 = prm->uac2;
+ struct audio_dev *agdev = uac2_to_agdev(uac2);
+ struct f_uac2_opts *uac2_opts = agdev_to_uac2_opts(agdev);
int i;
if (!prm->ep_enabled)
@@ -950,7 +951,7 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
prm->ep_enabled = false;
- for (i = 0; i < USB_XFERS; i++) {
+ for (i = 0; i < uac2_opts->req_number; i++) {
if (prm->ureq[i].req) {
usb_ep_dequeue(ep, prm->ureq[i].req);
usb_ep_free_request(ep, prm->ureq[i].req);
@@ -1095,7 +1096,13 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
prm = &agdev->uac2.c_prm;
prm->max_psize = hs_epout_desc.wMaxPacketSize;
- prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+ prm->ureq = kcalloc(uac2_opts->req_number, sizeof(struct uac2_req),
+ GFP_KERNEL);
+ if (!prm->ureq) {
+ ret = -ENOMEM;
+ goto err_free_descs;
+ }
+ prm->rbuf = kcalloc(uac2_opts->req_number, prm->max_psize, GFP_KERNEL);
if (!prm->rbuf) {
prm->max_psize = 0;
ret = -ENOMEM;
@@ -1104,7 +1111,13 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
prm = &agdev->uac2.p_prm;
prm->max_psize = hs_epin_desc.wMaxPacketSize;
- prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+ prm->ureq = kcalloc(uac2_opts->req_number, sizeof(struct uac2_req),
+ GFP_KERNEL);
+ if (!prm->ureq) {
+ ret = -ENOMEM;
+ goto err_free_descs;
+ }
+ prm->rbuf = kcalloc(uac2_opts->req_number, prm->max_psize, GFP_KERNEL);
if (!prm->rbuf) {
prm->max_psize = 0;
ret = -ENOMEM;
@@ -1117,6 +1130,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
return 0;
err_no_memory:
+ kfree(agdev->uac2.p_prm.ureq);
+ kfree(agdev->uac2.c_prm.ureq);
kfree(agdev->uac2.p_prm.rbuf);
kfree(agdev->uac2.c_prm.rbuf);
err_free_descs:
@@ -1129,6 +1144,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
{
struct usb_composite_dev *cdev = fn->config->cdev;
struct audio_dev *agdev = func_to_agdev(fn);
+ struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
struct snd_uac2_chip *uac2 = &agdev->uac2;
struct usb_gadget *gadget = cdev->gadget;
struct device *dev = &uac2->pdev.dev;
@@ -1159,7 +1175,6 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
agdev->as_out_alt = alt;
req_len = prm->max_psize;
} else if (intf == agdev->as_in_intf) {
- struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
unsigned int factor, rate;
struct usb_endpoint_descriptor *ep_desc;
@@ -1205,7 +1220,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
prm->ep_enabled = true;
usb_ep_enable(ep);
- for (i = 0; i < USB_XFERS; i++) {
+ for (i = 0; i < opts->req_number; i++) {
if (!prm->ureq[i].req) {
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (req == NULL)
@@ -1489,6 +1504,7 @@ UAC2_ATTRIBUTE(p_ssize);
UAC2_ATTRIBUTE(c_chmask);
UAC2_ATTRIBUTE(c_srate);
UAC2_ATTRIBUTE(c_ssize);
+UAC2_ATTRIBUTE(req_number);
static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_attr_p_chmask,
@@ -1497,6 +1513,7 @@ static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_attr_c_chmask,
&f_uac2_opts_attr_c_srate,
&f_uac2_opts_attr_c_ssize,
+ &f_uac2_opts_attr_req_number,
NULL,
};
@@ -1534,6 +1551,7 @@ static struct usb_function_instance *afunc_alloc_inst(void)
opts->c_chmask = UAC2_DEF_CCHMASK;
opts->c_srate = UAC2_DEF_CSRATE;
opts->c_ssize = UAC2_DEF_CSSIZE;
+ opts->req_number = UAC2_DEF_REQ_NUM;
return &opts->func_inst;
}
@@ -1562,6 +1580,7 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
prm = &agdev->uac2.c_prm;
kfree(prm->rbuf);
+ kfree(prm->ureq);
usb_free_all_descriptors(f);
}