diff options
author | Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 2014-07-22 19:58:30 +0200 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-08-20 14:04:16 -0500 |
commit | f8f93d244afad804e09595fcb14320fe2896fef5 (patch) | |
tree | bb6e0e0aca769fa559481cc10f84c24a98cfebc7 | |
parent | 5d73abf2a77a090ca4c920ac99c8ec0e272398a9 (diff) | |
download | linux-stable-f8f93d244afad804e09595fcb14320fe2896fef5.tar.gz linux-stable-f8f93d244afad804e09595fcb14320fe2896fef5.tar.bz2 linux-stable-f8f93d244afad804e09595fcb14320fe2896fef5.zip |
usb: gadget: f_uac2: convert to new function interface with backward compatibility
Converting uac2 to the new function interface requires converting
the USB uac2's function code and its users.
This patch converts the f_uac2.c to the new function interface.
The file is now compiled into a separate usb_f_uac2.ko module.
The old function interface is provided by means of a preprocessor
conditional directives. After all users are converted, the old interface
can be removed.
Tested-by: Sebastian Reimers <sebastian.reimers@googlemail.com>
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/gadget/Kconfig | 3 | ||||
-rw-r--r-- | drivers/usb/gadget/function/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_uac2.c | 244 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_uac2.h | 32 | ||||
-rw-r--r-- | drivers/usb/gadget/legacy/audio.c | 1 |
5 files changed, 242 insertions, 40 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5c822afb6d70..ea8ebce60d8f 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -181,6 +181,9 @@ config USB_F_MASS_STORAGE config USB_F_FS tristate +config USB_F_UAC2 + tristate + choice tristate "USB Gadget Drivers" default USB_ETH diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 6d91f21b52a6..20775a87e51a 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -32,3 +32,5 @@ usb_f_mass_storage-y := f_mass_storage.o storage_common.o obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o +usb_f_uac2-y := f_uac2.o +obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 91615619c204..29b477fa2050 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -20,6 +20,10 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> +#include "u_uac2.h" + +#ifdef USB_FUAC2_INCLUDED + /* Playback(USB-IN) Default Stereo - Fl/Fr */ static int p_chmask = 0x3; module_param(p_chmask, uint, S_IRUGO); @@ -50,6 +54,8 @@ static int c_ssize = 2; module_param(c_ssize, uint, S_IRUGO); MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); +#endif + /* Keep everyone on toes */ #define USB_XFERS 2 @@ -340,6 +346,22 @@ static int uac2_pcm_open(struct snd_pcm_substream *substream) { struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; +#ifndef USB_FUAC2_INCLUDED + struct audio_dev *audio_dev; + struct f_uac2_opts *opts; + int p_ssize, c_ssize; + int p_srate, c_srate; + int p_chmask, c_chmask; + + audio_dev = uac2_to_agdev(uac2); + opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); + p_ssize = opts->p_ssize; + c_ssize = opts->c_ssize; + p_srate = opts->p_srate; + c_srate = opts->c_srate; + p_chmask = opts->p_chmask; + c_chmask = opts->c_chmask; +#endif runtime->hw = uac2_pcm_hardware; @@ -409,7 +431,19 @@ static int snd_uac2_probe(struct platform_device *pdev) struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev); struct snd_card *card; struct snd_pcm *pcm; +#ifndef USB_FUAC2_INCLUDED + struct audio_dev *audio_dev; + struct f_uac2_opts *opts; +#endif int err; +#ifndef USB_FUAC2_INCLUDED + int p_chmask, c_chmask; + + audio_dev = uac2_to_agdev(uac2); + opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); + p_chmask = opts->p_chmask; + c_chmask = opts->c_chmask; +#endif /* Choose any slot, with no id */ err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card); @@ -917,7 +951,7 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) "%s:%d Error!\n", __func__, __LINE__); } -static int __init +static int afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) { struct audio_dev *agdev = func_to_agdev(fn); @@ -925,8 +959,50 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) struct usb_composite_dev *cdev = cfg->cdev; struct usb_gadget *gadget = cdev->gadget; struct uac2_rtd_params *prm; +#ifndef USB_FUAC2_INCLUDED + struct f_uac2_opts *uac2_opts; +#endif int ret; +#ifndef USB_FUAC2_INCLUDED + uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst); +#endif + + ret = usb_string_ids_tab(cfg->cdev, strings_fn); + if (ret) + return ret; + 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; + +#ifndef USB_FUAC2_INCLUDED + /* Initialize the configurable parameters */ + usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask); + usb_out_it_desc.bmChannelConfig = cpu_to_le32(uac2_opts->c_chmask); + io_in_it_desc.bNrChannels = num_channels(uac2_opts->p_chmask); + io_in_it_desc.bmChannelConfig = cpu_to_le32(uac2_opts->p_chmask); + as_out_hdr_desc.bNrChannels = num_channels(uac2_opts->c_chmask); + as_out_hdr_desc.bmChannelConfig = cpu_to_le32(uac2_opts->c_chmask); + as_in_hdr_desc.bNrChannels = num_channels(uac2_opts->p_chmask); + as_in_hdr_desc.bmChannelConfig = cpu_to_le32(uac2_opts->p_chmask); + as_out_fmt1_desc.bSubslotSize = uac2_opts->c_ssize; + as_out_fmt1_desc.bBitResolution = uac2_opts->c_ssize * 8; + as_in_fmt1_desc.bSubslotSize = uac2_opts->p_ssize; + as_in_fmt1_desc.bBitResolution = uac2_opts->p_ssize * 8; + + snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate); + snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate); +#endif + ret = usb_interface_id(cfg, fn); if (ret < 0) { dev_err(&uac2->pdev.dev, @@ -1018,28 +1094,6 @@ err: return -EINVAL; } -static void -afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn) -{ - struct audio_dev *agdev = func_to_agdev(fn); - struct uac2_rtd_params *prm; - - alsa_uac2_exit(agdev); - - prm = &agdev->uac2.p_prm; - kfree(prm->rbuf); - - prm = &agdev->uac2.c_prm; - kfree(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; - kfree(agdev); -} - static int afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) { @@ -1163,12 +1217,22 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) struct usb_request *req = fn->config->cdev->req; struct audio_dev *agdev = func_to_agdev(fn); struct snd_uac2_chip *uac2 = &agdev->uac2; +#ifndef USB_FUAC2_INCLUDED + struct f_uac2_opts *opts; +#endif u16 w_length = le16_to_cpu(cr->wLength); u16 w_index = le16_to_cpu(cr->wIndex); u16 w_value = le16_to_cpu(cr->wValue); u8 entity_id = (w_index >> 8) & 0xff; u8 control_selector = w_value >> 8; int value = -EOPNOTSUPP; +#ifndef USB_FUAC2_INCLUDED + int p_srate, c_srate; + + opts = container_of(agdev->func.fi, struct f_uac2_opts, func_inst); + p_srate = opts->p_srate; + c_srate = opts->c_srate; +#endif if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { struct cntrl_cur_lay3 c; @@ -1198,6 +1262,9 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) struct usb_request *req = fn->config->cdev->req; struct audio_dev *agdev = func_to_agdev(fn); struct snd_uac2_chip *uac2 = &agdev->uac2; +#ifndef USB_FUAC2_INCLUDED + struct f_uac2_opts *opts; +#endif u16 w_length = le16_to_cpu(cr->wLength); u16 w_index = le16_to_cpu(cr->wIndex); u16 w_value = le16_to_cpu(cr->wValue); @@ -1205,6 +1272,13 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) u8 control_selector = w_value >> 8; struct cntrl_range_lay3 r; int value = -EOPNOTSUPP; +#ifndef USB_FUAC2_INCLUDED + int p_srate, c_srate; + + opts = container_of(agdev->func.fi, struct f_uac2_opts, func_inst); + p_srate = opts->p_srate; + c_srate = opts->c_srate; +#endif if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { if (entity_id == USB_IN_CLK_ID) @@ -1308,6 +1382,30 @@ afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr) return value; } +#ifdef USB_FUAC2_INCLUDED + +static void +old_afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn) +{ + struct audio_dev *agdev = func_to_agdev(fn); + struct uac2_rtd_params *prm; + + alsa_uac2_exit(agdev); + + prm = &agdev->uac2.p_prm; + kfree(prm->rbuf); + + prm = &agdev->uac2.c_prm; + kfree(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; + kfree(agdev); +} + static int audio_bind_config(struct usb_configuration *cfg) { struct audio_dev *agdev; @@ -1317,26 +1415,10 @@ static int audio_bind_config(struct usb_configuration *cfg) if (agdev == NULL) return -ENOMEM; - 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->func.name = "uac2_func"; agdev->func.strings = fn_strings; agdev->func.bind = afunc_bind; - agdev->func.unbind = afunc_unbind; + agdev->func.unbind = old_afunc_unbind; agdev->func.set_alt = afunc_set_alt; agdev->func.get_alt = afunc_get_alt; agdev->func.disable = afunc_disable; @@ -1365,3 +1447,85 @@ static int audio_bind_config(struct usb_configuration *cfg) return res; } + +#else + +static void afunc_free_inst(struct usb_function_instance *f) +{ + struct f_uac2_opts *opts; + + opts = container_of(f, struct f_uac2_opts, func_inst); + kfree(opts); +} + +static struct usb_function_instance *afunc_alloc_inst(void) +{ + struct f_uac2_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = afunc_free_inst; + + return &opts->func_inst; +} + +static void afunc_free(struct usb_function *f) +{ + struct audio_dev *agdev; + + agdev = func_to_agdev(f); + kfree(agdev); +} + +static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct audio_dev *agdev = func_to_agdev(f); + struct uac2_rtd_params *prm; + + alsa_uac2_exit(agdev); + + prm = &agdev->uac2.p_prm; + kfree(prm->rbuf); + + prm = &agdev->uac2.c_prm; + kfree(prm->rbuf); + usb_free_all_descriptors(f); + + if (agdev->in_ep) + agdev->in_ep->driver_data = NULL; + if (agdev->out_ep) + agdev->out_ep->driver_data = NULL; +} + +struct usb_function *afunc_alloc(struct usb_function_instance *fi) +{ + struct audio_dev *agdev; + struct f_uac2_opts *opts; + + agdev = kzalloc(sizeof(*agdev), GFP_KERNEL); + if (agdev == NULL) + return ERR_PTR(-ENOMEM); + + opts = container_of(fi, struct f_uac2_opts, func_inst); + + agdev->func.name = "uac2_func"; + agdev->func.strings = fn_strings; + agdev->func.bind = afunc_bind; + agdev->func.unbind = afunc_unbind; + agdev->func.set_alt = afunc_set_alt; + agdev->func.get_alt = afunc_get_alt; + agdev->func.disable = afunc_disable; + agdev->func.setup = afunc_setup; + agdev->func.free_func = afunc_free; + + return &agdev->func; +} + +DECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yadwinder Singh"); +MODULE_AUTHOR("Jaswinder Singh"); + +#endif diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h new file mode 100644 index 000000000000..290b83af1b69 --- /dev/null +++ b/drivers/usb/gadget/function/u_uac2.h @@ -0,0 +1,32 @@ +/* + * u_uac2.h + * + * Utility definitions for UAC2 function + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef U_UAC2_H +#define U_UAC2_H + +#include <linux/usb/composite.h> + +struct f_uac2_opts { + struct usb_function_instance func_inst; + int p_chmask; + int p_srate; + int p_ssize; + int c_chmask; + int c_srate; + int c_ssize; + bool bound; +}; + +#endif diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index 3c2328316c05..a41316bb436a 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -45,6 +45,7 @@ static struct usb_gadget_strings *audio_strings[] = { #include "u_uac1.c" #include "f_uac1.c" #else +#define USB_FUAC2_INCLUDED #include "f_uac2.c" #endif |