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)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Tue, 24 Jan 2017 09:04:21 +0000 (11:04 +0200)
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>
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 58196057488941ebc2aa23e116dbb01d1d153c8b..fb0cc4df17655b6d224341b3915afbf4acdd1a89 100644 (file)
@@ -632,6 +632,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 3f4e4785418ff62b77807473e9505e5affabd7c5..f6a0d3a1311b4adbe21cba5bf25af1f2382e3e55 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);
@@ -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);
 }
 
index 78dd37279bd4570b8c238a94c6d33c47b6db4a10..19eeb83538a5adcb951bcb63e5fc764608dd8019 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 5d7b3c6a422ba8807944639828ecc1f2097e4a23..8a39f42a4d56232bf5c1a0b8a3e1d0668f9305c2 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;