|
@@ -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);
|
|
}
|
|
}
|
|
|
|
|