OSDN Git Service

usb: gadget: uac2: add req_number as parameter
authorPeter Chen <peter.chen@nxp.com>
Wed, 4 Jan 2017 02:19:23 +0000 (10:19 +0800)
committerAjay Agarwal <ajaya@codeaurora.org>
Wed, 9 Jan 2019 04:46:55 +0000 (10:16 +0530)
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.

Change-Id: I6d85f82eb3d93bb9e547855780d266bb095ca6b2
Signed-off-by: Peter Chen <peter.chen@nxp.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Git-commit: e92b9d449d0490800160bfeb5ee1175a02979f47
Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
Documentation/usb/gadget-testing.txt
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/u_uac2.h
drivers/usb/gadget/legacy/audio.c

index b24d3ef..2d73451 100644 (file)
@@ -630,6 +630,8 @@ The uac2 function provides these attributes in its function directory:
        p_chmask - playback channel mask
        p_srate - playback sampling rate
        p_ssize - playback sample size (bytes)
+       req_number - the number of pre-allocated request for both capture
+                    and playback
 
 The attributes have sane default values.
 
index 380092f..2e30f6a 100644 (file)
@@ -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);
@@ -1096,7 +1097,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;
@@ -1105,7 +1112,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;
@@ -1118,6 +1131,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:
@@ -1130,6 +1145,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;
@@ -1160,7 +1176,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;
 
@@ -1206,7 +1221,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)
@@ -1490,6 +1505,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,
@@ -1498,6 +1514,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,
 };
 
@@ -1535,6 +1552,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;
 }
 
@@ -1563,6 +1581,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);
 }
 
index 78dd372..19eeb83 100644 (file)
@@ -24,6 +24,7 @@
 #define UAC2_DEF_CCHMASK 0x3
 #define UAC2_DEF_CSRATE 64000
 #define UAC2_DEF_CSSIZE 2
+#define UAC2_DEF_REQ_NUM 2
 
 struct f_uac2_opts {
        struct usb_function_instance    func_inst;
@@ -33,6 +34,7 @@ struct f_uac2_opts {
        int                             c_chmask;
        int                             c_srate;
        int                             c_ssize;
+       int                             req_number;
        bool                            bound;
 
        struct mutex                    lock;
index 685cf3b..9f732d7 100644 (file)
@@ -229,6 +229,7 @@ static int audio_bind(struct usb_composite_dev *cdev)
        uac2_opts->c_chmask = c_chmask;
        uac2_opts->c_srate = c_srate;
        uac2_opts->c_ssize = c_ssize;
+       uac2_opts->req_number = UAC2_DEF_REQ_NUM;
 #else
        uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst);
        uac1_opts->fn_play = fn_play;