forked from Minki/linux
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>
This commit is contained in:
parent
ec33efe28f
commit
e92b9d449d
@ -632,6 +632,8 @@ The uac2 function provides these attributes in its function directory:
|
|||||||
p_chmask - playback channel mask
|
p_chmask - playback channel mask
|
||||||
p_srate - playback sampling rate
|
p_srate - playback sampling rate
|
||||||
p_ssize - playback sample size (bytes)
|
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.
|
The attributes have sane default values.
|
||||||
|
|
||||||
|
@ -22,9 +22,6 @@
|
|||||||
|
|
||||||
#include "u_uac2.h"
|
#include "u_uac2.h"
|
||||||
|
|
||||||
/* Keep everyone on toes */
|
|
||||||
#define USB_XFERS 2
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The driver implements a simple UAC_2 topology.
|
* The driver implements a simple UAC_2 topology.
|
||||||
* USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
|
* USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
|
||||||
@ -78,7 +75,7 @@ struct uac2_rtd_params {
|
|||||||
size_t period_size;
|
size_t period_size;
|
||||||
|
|
||||||
unsigned max_psize;
|
unsigned max_psize;
|
||||||
struct uac2_req ureq[USB_XFERS];
|
struct uac2_req *ureq;
|
||||||
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
@ -269,6 +266,8 @@ static int
|
|||||||
uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
{
|
{
|
||||||
struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
|
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;
|
struct uac2_rtd_params *prm;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
@ -300,7 +299,7 @@ uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||||||
|
|
||||||
/* Clear buffer after Play stops */
|
/* Clear buffer after Play stops */
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss)
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
@ -943,6 +942,8 @@ static inline void
|
|||||||
free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
|
free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
|
||||||
{
|
{
|
||||||
struct snd_uac2_chip *uac2 = prm->uac2;
|
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;
|
int i;
|
||||||
|
|
||||||
if (!prm->ep_enabled)
|
if (!prm->ep_enabled)
|
||||||
@ -950,7 +951,7 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
|
|||||||
|
|
||||||
prm->ep_enabled = false;
|
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) {
|
if (prm->ureq[i].req) {
|
||||||
usb_ep_dequeue(ep, prm->ureq[i].req);
|
usb_ep_dequeue(ep, prm->ureq[i].req);
|
||||||
usb_ep_free_request(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 = &agdev->uac2.c_prm;
|
||||||
prm->max_psize = hs_epout_desc.wMaxPacketSize;
|
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) {
|
if (!prm->rbuf) {
|
||||||
prm->max_psize = 0;
|
prm->max_psize = 0;
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
@ -1104,7 +1111,13 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||||||
|
|
||||||
prm = &agdev->uac2.p_prm;
|
prm = &agdev->uac2.p_prm;
|
||||||
prm->max_psize = hs_epin_desc.wMaxPacketSize;
|
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) {
|
if (!prm->rbuf) {
|
||||||
prm->max_psize = 0;
|
prm->max_psize = 0;
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
@ -1117,6 +1130,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_no_memory:
|
err_no_memory:
|
||||||
|
kfree(agdev->uac2.p_prm.ureq);
|
||||||
|
kfree(agdev->uac2.c_prm.ureq);
|
||||||
kfree(agdev->uac2.p_prm.rbuf);
|
kfree(agdev->uac2.p_prm.rbuf);
|
||||||
kfree(agdev->uac2.c_prm.rbuf);
|
kfree(agdev->uac2.c_prm.rbuf);
|
||||||
err_free_descs:
|
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 usb_composite_dev *cdev = fn->config->cdev;
|
||||||
struct audio_dev *agdev = func_to_agdev(fn);
|
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 snd_uac2_chip *uac2 = &agdev->uac2;
|
||||||
struct usb_gadget *gadget = cdev->gadget;
|
struct usb_gadget *gadget = cdev->gadget;
|
||||||
struct device *dev = &uac2->pdev.dev;
|
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;
|
agdev->as_out_alt = alt;
|
||||||
req_len = prm->max_psize;
|
req_len = prm->max_psize;
|
||||||
} else if (intf == agdev->as_in_intf) {
|
} else if (intf == agdev->as_in_intf) {
|
||||||
struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
|
|
||||||
unsigned int factor, rate;
|
unsigned int factor, rate;
|
||||||
struct usb_endpoint_descriptor *ep_desc;
|
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;
|
prm->ep_enabled = true;
|
||||||
usb_ep_enable(ep);
|
usb_ep_enable(ep);
|
||||||
|
|
||||||
for (i = 0; i < USB_XFERS; i++) {
|
for (i = 0; i < opts->req_number; i++) {
|
||||||
if (!prm->ureq[i].req) {
|
if (!prm->ureq[i].req) {
|
||||||
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||||
if (req == NULL)
|
if (req == NULL)
|
||||||
@ -1489,6 +1504,7 @@ UAC2_ATTRIBUTE(p_ssize);
|
|||||||
UAC2_ATTRIBUTE(c_chmask);
|
UAC2_ATTRIBUTE(c_chmask);
|
||||||
UAC2_ATTRIBUTE(c_srate);
|
UAC2_ATTRIBUTE(c_srate);
|
||||||
UAC2_ATTRIBUTE(c_ssize);
|
UAC2_ATTRIBUTE(c_ssize);
|
||||||
|
UAC2_ATTRIBUTE(req_number);
|
||||||
|
|
||||||
static struct configfs_attribute *f_uac2_attrs[] = {
|
static struct configfs_attribute *f_uac2_attrs[] = {
|
||||||
&f_uac2_opts_attr_p_chmask,
|
&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_chmask,
|
||||||
&f_uac2_opts_attr_c_srate,
|
&f_uac2_opts_attr_c_srate,
|
||||||
&f_uac2_opts_attr_c_ssize,
|
&f_uac2_opts_attr_c_ssize,
|
||||||
|
&f_uac2_opts_attr_req_number,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1534,6 +1551,7 @@ static struct usb_function_instance *afunc_alloc_inst(void)
|
|||||||
opts->c_chmask = UAC2_DEF_CCHMASK;
|
opts->c_chmask = UAC2_DEF_CCHMASK;
|
||||||
opts->c_srate = UAC2_DEF_CSRATE;
|
opts->c_srate = UAC2_DEF_CSRATE;
|
||||||
opts->c_ssize = UAC2_DEF_CSSIZE;
|
opts->c_ssize = UAC2_DEF_CSSIZE;
|
||||||
|
opts->req_number = UAC2_DEF_REQ_NUM;
|
||||||
return &opts->func_inst;
|
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;
|
prm = &agdev->uac2.c_prm;
|
||||||
kfree(prm->rbuf);
|
kfree(prm->rbuf);
|
||||||
|
kfree(prm->ureq);
|
||||||
usb_free_all_descriptors(f);
|
usb_free_all_descriptors(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#define UAC2_DEF_CCHMASK 0x3
|
#define UAC2_DEF_CCHMASK 0x3
|
||||||
#define UAC2_DEF_CSRATE 64000
|
#define UAC2_DEF_CSRATE 64000
|
||||||
#define UAC2_DEF_CSSIZE 2
|
#define UAC2_DEF_CSSIZE 2
|
||||||
|
#define UAC2_DEF_REQ_NUM 2
|
||||||
|
|
||||||
struct f_uac2_opts {
|
struct f_uac2_opts {
|
||||||
struct usb_function_instance func_inst;
|
struct usb_function_instance func_inst;
|
||||||
@ -33,6 +34,7 @@ struct f_uac2_opts {
|
|||||||
int c_chmask;
|
int c_chmask;
|
||||||
int c_srate;
|
int c_srate;
|
||||||
int c_ssize;
|
int c_ssize;
|
||||||
|
int req_number;
|
||||||
bool bound;
|
bool bound;
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
@ -229,6 +229,7 @@ static int audio_bind(struct usb_composite_dev *cdev)
|
|||||||
uac2_opts->c_chmask = c_chmask;
|
uac2_opts->c_chmask = c_chmask;
|
||||||
uac2_opts->c_srate = c_srate;
|
uac2_opts->c_srate = c_srate;
|
||||||
uac2_opts->c_ssize = c_ssize;
|
uac2_opts->c_ssize = c_ssize;
|
||||||
|
uac2_opts->req_number = UAC2_DEF_REQ_NUM;
|
||||||
#else
|
#else
|
||||||
uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst);
|
uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst);
|
||||||
uac1_opts->fn_play = fn_play;
|
uac1_opts->fn_play = fn_play;
|
||||||
|
Loading…
Reference in New Issue
Block a user