aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/f_uac2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/f_uac2.c')
-rw-r--r--drivers/usb/gadget/f_uac2.c267
1 files changed, 86 insertions, 181 deletions
diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c
index d3c6cffccb7..6261db4a991 100644
--- a/drivers/usb/gadget/f_uac2.c
+++ b/drivers/usb/gadget/f_uac2.c
@@ -50,13 +50,6 @@ static int c_ssize = 2;
module_param(c_ssize, uint, S_IRUGO);
MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-#define ALT_SET(x, a) do {(x) &= ~0xff; (x) |= (a); } while (0)
-#define ALT_GET(x) ((x) & 0xff)
-#define INTF_SET(x, i) do {(x) &= 0xff; (x) |= ((i) << 8); } while (0)
-#define INTF_GET(x) ((x >> 8) & 0xff)
-
/* Keep everyone on toes */
#define USB_XFERS 2
@@ -97,6 +90,7 @@ struct uac2_req {
};
struct uac2_rtd_params {
+ struct snd_uac2_chip *uac2; /* parent chip */
bool ep_enabled; /* if the ep is enabled */
/* Size of the ring buffer */
size_t dma_bytes;
@@ -144,8 +138,9 @@ static struct snd_pcm_hardware uac2_pcm_hardware = {
};
struct audio_dev {
- /* Currently active {Interface[15:8] | AltSettings[7:0]} */
- __u16 ac_alt, as_out_alt, as_in_alt;
+ u8 ac_intf, ac_alt;
+ u8 as_out_intf, as_out_alt;
+ u8 as_in_intf, as_in_alt;
struct usb_ep *in_ep, *out_ep;
struct usb_function func;
@@ -175,18 +170,6 @@ struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p)
}
static inline
-struct snd_uac2_chip *prm_to_uac2(struct uac2_rtd_params *r)
-{
- struct snd_uac2_chip *uac2 = container_of(r,
- struct snd_uac2_chip, c_prm);
-
- if (&uac2->c_prm != r)
- uac2 = container_of(r, struct snd_uac2_chip, p_prm);
-
- return uac2;
-}
-
-static inline
uint num_channels(uint chanmask)
{
uint num = 0;
@@ -210,10 +193,10 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
struct uac2_req *ur = req->context;
struct snd_pcm_substream *substream;
struct uac2_rtd_params *prm = ur->pp;
- struct snd_uac2_chip *uac2 = prm_to_uac2(prm);
+ struct snd_uac2_chip *uac2 = prm->uac2;
/* i/f shutting down */
- if (!prm->ep_enabled)
+ if (!prm->ep_enabled || req->status == -ESHUTDOWN)
return;
/*
@@ -266,19 +249,14 @@ 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 uac2_rtd_params *prm;
unsigned long flags;
- struct usb_ep *ep;
int err = 0;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ep = agdev->in_ep;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
prm = &uac2->p_prm;
- } else {
- ep = agdev->out_ep;
+ else
prm = &uac2->c_prm;
- }
spin_lock_irqsave(&prm->lock, flags);
@@ -408,7 +386,7 @@ static struct snd_pcm_ops uac2_pcm_ops = {
.prepare = uac2_pcm_null,
};
-static int __devinit snd_uac2_probe(struct platform_device *pdev)
+static int snd_uac2_probe(struct platform_device *pdev)
{
struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev);
struct snd_card *card;
@@ -416,7 +394,7 @@ static int __devinit snd_uac2_probe(struct platform_device *pdev)
int err;
/* Choose any slot, with no id */
- err = snd_card_create(-1, NULL, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -443,8 +421,6 @@ static int __devinit snd_uac2_probe(struct platform_device *pdev)
strcpy(card->shortname, "UAC2_Gadget");
sprintf(card->longname, "UAC2_Gadget %i", pdev->id);
- snd_card_set_dev(card, &pdev->dev);
-
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX);
@@ -467,8 +443,6 @@ static int snd_uac2_remove(struct platform_device *pdev)
{
struct snd_card *card = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
if (card)
return snd_card_free(card);
@@ -526,32 +500,22 @@ enum {
STR_AS_IN_ALT1,
};
-static const char ifassoc[] = "Source/Sink";
-static const char ifctrl[] = "Topology Control";
static char clksrc_in[8];
static char clksrc_out[8];
-static const char usb_it[] = "USBH Out";
-static const char io_it[] = "USBD Out";
-static const char usb_ot[] = "USBH In";
-static const char io_ot[] = "USBD In";
-static const char out_alt0[] = "Playback Inactive";
-static const char out_alt1[] = "Playback Active";
-static const char in_alt0[] = "Capture Inactive";
-static const char in_alt1[] = "Capture Active";
static struct usb_string strings_fn[] = {
- [STR_ASSOC].s = ifassoc,
- [STR_IF_CTRL].s = ifctrl,
+ [STR_ASSOC].s = "Source/Sink",
+ [STR_IF_CTRL].s = "Topology Control",
[STR_CLKSRC_IN].s = clksrc_in,
[STR_CLKSRC_OUT].s = clksrc_out,
- [STR_USB_IT].s = usb_it,
- [STR_IO_IT].s = io_it,
- [STR_USB_OT].s = usb_ot,
- [STR_IO_OT].s = io_ot,
- [STR_AS_OUT_ALT0].s = out_alt0,
- [STR_AS_OUT_ALT1].s = out_alt1,
- [STR_AS_IN_ALT0].s = in_alt0,
- [STR_AS_IN_ALT1].s = in_alt1,
+ [STR_USB_IT].s = "USBH Out",
+ [STR_IO_IT].s = "USBD Out",
+ [STR_USB_OT].s = "USBH In",
+ [STR_IO_OT].s = "USBD In",
+ [STR_AS_OUT_ALT0].s = "Playback Inactive",
+ [STR_AS_OUT_ALT1].s = "Playback Active",
+ [STR_AS_IN_ALT0].s = "Capture Inactive",
+ [STR_AS_IN_ALT1].s = "Capture Active",
{ },
};
@@ -917,7 +881,7 @@ struct cntrl_range_lay3 {
static inline void
free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
{
- struct snd_uac2_chip *uac2 = prm_to_uac2(prm);
+ struct snd_uac2_chip *uac2 = prm->uac2;
int i;
prm->ep_enabled = false;
@@ -952,8 +916,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
return ret;
}
std_ac_if_desc.bInterfaceNumber = ret;
- ALT_SET(agdev->ac_alt, 0);
- INTF_SET(agdev->ac_alt, ret);
+ agdev->ac_intf = ret;
+ agdev->ac_alt = 0;
ret = usb_interface_id(cfg, fn);
if (ret < 0) {
@@ -963,8 +927,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
}
std_as_out_if0_desc.bInterfaceNumber = ret;
std_as_out_if1_desc.bInterfaceNumber = ret;
- ALT_SET(agdev->as_out_alt, 0);
- INTF_SET(agdev->as_out_alt, ret);
+ agdev->as_out_intf = ret;
+ agdev->as_out_alt = 0;
ret = usb_interface_id(cfg, fn);
if (ret < 0) {
@@ -974,37 +938,43 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
}
std_as_in_if0_desc.bInterfaceNumber = ret;
std_as_in_if1_desc.bInterfaceNumber = ret;
- ALT_SET(agdev->as_in_alt, 0);
- INTF_SET(agdev->as_in_alt, ret);
+ agdev->as_in_intf = ret;
+ agdev->as_in_alt = 0;
agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
- if (!agdev->out_ep)
+ if (!agdev->out_ep) {
dev_err(&uac2->pdev.dev,
"%s:%d Error!\n", __func__, __LINE__);
+ goto err;
+ }
agdev->out_ep->driver_data = agdev;
agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
- if (!agdev->in_ep)
+ if (!agdev->in_ep) {
dev_err(&uac2->pdev.dev,
"%s:%d Error!\n", __func__, __LINE__);
+ goto err;
+ }
agdev->in_ep->driver_data = agdev;
+ uac2->p_prm.uac2 = uac2;
+ uac2->c_prm.uac2 = uac2;
+
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize;
- fn->descriptors = usb_copy_descriptors(fs_audio_desc);
- if (gadget_is_dualspeed(gadget))
- fn->hs_descriptors = usb_copy_descriptors(hs_audio_desc);
+ ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
+ if (ret)
+ goto err;
prm = &agdev->uac2.c_prm;
prm->max_psize = hs_epout_desc.wMaxPacketSize;
prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
if (!prm->rbuf) {
prm->max_psize = 0;
- dev_err(&uac2->pdev.dev,
- "%s:%d Error!\n", __func__, __LINE__);
+ goto err;
}
prm = &agdev->uac2.p_prm;
@@ -1012,19 +982,28 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
if (!prm->rbuf) {
prm->max_psize = 0;
- dev_err(&uac2->pdev.dev,
- "%s:%d Error!\n", __func__, __LINE__);
+ goto err;
}
- return alsa_uac2_init(agdev);
+ ret = alsa_uac2_init(agdev);
+ if (ret)
+ goto err;
+ return 0;
+err:
+ kfree(agdev->uac2.p_prm.rbuf);
+ kfree(agdev->uac2.c_prm.rbuf);
+ usb_free_all_descriptors(fn);
+ if (agdev->in_ep)
+ agdev->in_ep->driver_data = NULL;
+ if (agdev->out_ep)
+ agdev->out_ep->driver_data = NULL;
+ return -EINVAL;
}
static void
afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
{
struct audio_dev *agdev = func_to_agdev(fn);
- struct usb_composite_dev *cdev = cfg->cdev;
- struct usb_gadget *gadget = cdev->gadget;
struct uac2_rtd_params *prm;
alsa_uac2_exit(agdev);
@@ -1034,10 +1013,7 @@ afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
prm = &agdev->uac2.c_prm;
kfree(prm->rbuf);
-
- if (gadget_is_dualspeed(gadget))
- usb_free_descriptors(fn->hs_descriptors);
- usb_free_descriptors(fn->descriptors);
+ usb_free_all_descriptors(fn);
if (agdev->in_ep)
agdev->in_ep->driver_data = NULL;
@@ -1064,7 +1040,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
return -EINVAL;
}
- if (intf == INTF_GET(agdev->ac_alt)) {
+ if (intf == agdev->ac_intf) {
/* Control I/f has only 1 AltSetting - 0 */
if (alt) {
dev_err(&uac2->pdev.dev,
@@ -1074,16 +1050,16 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
return 0;
}
- if (intf == INTF_GET(agdev->as_out_alt)) {
+ if (intf == agdev->as_out_intf) {
ep = agdev->out_ep;
prm = &uac2->c_prm;
config_ep_by_speed(gadget, fn, ep);
- ALT_SET(agdev->as_out_alt, alt);
- } else if (intf == INTF_GET(agdev->as_in_alt)) {
+ agdev->as_out_alt = alt;
+ } else if (intf == agdev->as_in_intf) {
ep = agdev->in_ep;
prm = &uac2->p_prm;
config_ep_by_speed(gadget, fn, ep);
- ALT_SET(agdev->as_in_alt, alt);
+ agdev->as_in_alt = alt;
} else {
dev_err(&uac2->pdev.dev,
"%s:%d Error!\n", __func__, __LINE__);
@@ -1117,7 +1093,6 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
prm->ureq[i].pp = prm;
req->zero = 0;
- req->dma = DMA_ADDR_INVALID;
req->context = &prm->ureq[i];
req->length = prm->max_psize;
req->complete = agdev_iso_complete;
@@ -1136,12 +1111,12 @@ afunc_get_alt(struct usb_function *fn, unsigned intf)
struct audio_dev *agdev = func_to_agdev(fn);
struct snd_uac2_chip *uac2 = &agdev->uac2;
- if (intf == INTF_GET(agdev->ac_alt))
- return ALT_GET(agdev->ac_alt);
- else if (intf == INTF_GET(agdev->as_out_alt))
- return ALT_GET(agdev->as_out_alt);
- else if (intf == INTF_GET(agdev->as_in_alt))
- return ALT_GET(agdev->as_in_alt);
+ if (intf == agdev->ac_intf)
+ return agdev->ac_alt;
+ else if (intf == agdev->as_out_intf)
+ return agdev->as_out_alt;
+ else if (intf == agdev->as_in_intf)
+ return agdev->as_in_alt;
else
dev_err(&uac2->pdev.dev,
"%s:%d Invalid Interface %d!\n",
@@ -1157,10 +1132,10 @@ afunc_disable(struct usb_function *fn)
struct snd_uac2_chip *uac2 = &agdev->uac2;
free_ep(&uac2->p_prm, agdev->in_ep);
- ALT_SET(agdev->as_in_alt, 0);
+ agdev->as_in_alt = 0;
free_ep(&uac2->c_prm, agdev->out_ep);
- ALT_SET(agdev->as_out_alt, 0);
+ agdev->as_out_alt = 0;
}
static int
@@ -1267,7 +1242,7 @@ setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr)
u16 w_index = le16_to_cpu(cr->wIndex);
u8 intf = w_index & 0xff;
- if (intf != INTF_GET(agdev->ac_alt)) {
+ if (intf != agdev->ac_intf) {
dev_err(&uac2->pdev.dev,
"%s:%d Error!\n", __func__, __LINE__);
return -EOPNOTSUPP;
@@ -1316,97 +1291,27 @@ afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr)
static int audio_bind_config(struct usb_configuration *cfg)
{
- int id, res;
+ int res;
agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL);
- if (agdev_g == NULL) {
- printk(KERN_ERR "Unable to allocate audio gadget\n");
+ if (agdev_g == NULL)
return -ENOMEM;
- }
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_ASSOC].id = id;
- iad_desc.iFunction = id,
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_IF_CTRL].id = id;
- std_ac_if_desc.iInterface = id,
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_CLKSRC_IN].id = id;
- in_clk_src_desc.iClockSource = id,
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_CLKSRC_OUT].id = id;
- out_clk_src_desc.iClockSource = id,
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_USB_IT].id = id;
- usb_out_it_desc.iTerminal = id,
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_IO_IT].id = id;
- io_in_it_desc.iTerminal = id;
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_USB_OT].id = id;
- usb_in_ot_desc.iTerminal = id;
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_IO_OT].id = id;
- io_out_ot_desc.iTerminal = id;
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_AS_OUT_ALT0].id = id;
- std_as_out_if0_desc.iInterface = id;
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_AS_OUT_ALT1].id = id;
- std_as_out_if1_desc.iInterface = id;
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
-
- strings_fn[STR_AS_IN_ALT0].id = id;
- std_as_in_if0_desc.iInterface = id;
-
- id = usb_string_id(cfg->cdev);
- if (id < 0)
- return id;
- strings_fn[STR_AS_IN_ALT1].id = id;
- std_as_in_if1_desc.iInterface = id;
+ res = usb_string_ids_tab(cfg->cdev, strings_fn);
+ if (res)
+ return res;
+ iad_desc.iFunction = strings_fn[STR_ASSOC].id;
+ std_ac_if_desc.iInterface = strings_fn[STR_IF_CTRL].id;
+ in_clk_src_desc.iClockSource = strings_fn[STR_CLKSRC_IN].id;
+ out_clk_src_desc.iClockSource = strings_fn[STR_CLKSRC_OUT].id;
+ usb_out_it_desc.iTerminal = strings_fn[STR_USB_IT].id;
+ io_in_it_desc.iTerminal = strings_fn[STR_IO_IT].id;
+ usb_in_ot_desc.iTerminal = strings_fn[STR_USB_OT].id;
+ io_out_ot_desc.iTerminal = strings_fn[STR_IO_OT].id;
+ std_as_out_if0_desc.iInterface = strings_fn[STR_AS_OUT_ALT0].id;
+ std_as_out_if1_desc.iInterface = strings_fn[STR_AS_OUT_ALT1].id;
+ std_as_in_if0_desc.iInterface = strings_fn[STR_AS_IN_ALT0].id;
+ std_as_in_if1_desc.iInterface = strings_fn[STR_AS_IN_ALT1].id;
agdev_g->func.name = "uac2_func";
agdev_g->func.strings = fn_strings;