diff options
-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_uac1.c | 169 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_uac1.c | 31 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_uac1.h | 20 | ||||
-rw-r--r-- | drivers/usb/gadget/legacy/audio.c | 1 |
6 files changed, 195 insertions, 31 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index ea8ebce..68302aa 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_UAC1 + tristate + config USB_F_UAC2 tristate diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 20775a8..edb6dfa 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -32,5 +32,7 @@ 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_uac1-y := f_uac1.o u_uac1.o +obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.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_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 9cfaf1d..787ed2b 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -11,13 +11,17 @@ #include <linux/slab.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/device.h> #include <linux/atomic.h> #include "u_uac1.h" +#ifdef USBF_UAC1_INCLUDED #include "u_uac1.c" +#endif #define OUT_EP_MAX_PACKET_SIZE 200 +#ifdef USBF_UAC1_INCLUDED static int req_buf_size = OUT_EP_MAX_PACKET_SIZE; module_param(req_buf_size, int, S_IRUGO); MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size"); @@ -29,6 +33,7 @@ MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count"); static int audio_buf_size = 48000; module_param(audio_buf_size, int, S_IRUGO); MODULE_PARM_DESC(audio_buf_size, "Audio buffer size"); +#endif static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value); static int generic_get_cmd(struct usb_audio_control *con, u8 cmd); @@ -47,7 +52,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd); #define F_AUDIO_NUM_INTERFACES 2 /* B.3.1 Standard AC Interface Descriptor */ -static struct usb_interface_descriptor ac_interface_desc __initdata = { +static struct usb_interface_descriptor ac_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bNumEndpoints = 0, @@ -189,7 +194,7 @@ static struct usb_endpoint_descriptor as_out_ep_desc = { }; /* Class-specific AS ISO OUT Endpoint Descriptor */ -static struct uac_iso_endpoint_descriptor as_iso_out_desc __initdata = { +static struct uac_iso_endpoint_descriptor as_iso_out_desc = { .bLength = UAC_ISO_ENDPOINT_DESC_SIZE, .bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorSubtype = UAC_EP_GENERAL, @@ -198,7 +203,7 @@ static struct uac_iso_endpoint_descriptor as_iso_out_desc __initdata = { .wLockDelay = __constant_cpu_to_le16(1), }; -static struct usb_descriptor_header *f_audio_desc[] __initdata = { +static struct usb_descriptor_header *f_audio_desc[] = { (struct usb_descriptor_header *)&ac_interface_desc, (struct usb_descriptor_header *)&ac_header_desc, @@ -332,8 +337,17 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req) struct f_audio *audio = req->context; struct usb_composite_dev *cdev = audio->card.func.config->cdev; struct f_audio_buf *copy_buf = audio->copy_buf; +#ifndef USBF_UAC1_INCLUDED + struct f_uac1_opts *opts; + int audio_buf_size; +#endif int err; +#ifndef USBF_UAC1_INCLUDED + opts = container_of(audio->card.func.fi, struct f_uac1_opts, + func_inst); + audio_buf_size = opts->audio_buf_size; +#endif if (!copy_buf) return -EINVAL; @@ -578,10 +592,21 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) struct usb_composite_dev *cdev = f->config->cdev; struct usb_ep *out_ep = audio->out_ep; struct usb_request *req; +#ifndef USBF_UAC1_INCLUDED + struct f_uac1_opts *opts; + int req_buf_size, req_count, audio_buf_size; +#endif int i = 0, err = 0; DBG(cdev, "intf %d, alt %d\n", intf, alt); +#ifndef USBF_UAC1_INCLUDED + opts = container_of(f->fi, struct f_uac1_opts, func_inst); + req_buf_size = opts->req_buf_size; + req_count = opts->req_count; + audio_buf_size = opts->audio_buf_size; + +#endif if (intf == 1) { if (alt == 1) { usb_ep_enable(out_ep); @@ -657,13 +682,50 @@ static void f_audio_build_desc(struct f_audio *audio) } /* audio function driver setup/binding */ -static int __init +static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_audio *audio = func_to_audio(f); int status; struct usb_ep *ep = NULL; +#ifndef USBF_UAC1_INCLUDED + struct f_uac1_opts *audio_opts; + + audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst); + audio->card.gadget = c->cdev->gadget; + audio_opts->card = &audio->card; + /* set up ASLA audio devices */ + if (!audio_opts->bound) { + status = gaudio_setup(&audio->card); + if (status < 0) + return status; + audio_opts->bound = true; + } +#else + audio->card.gadget = c->cdev->gadget; +#endif + if (strings_uac1[0].id == 0) { + status = usb_string_ids_tab(c->cdev, strings_uac1); + if (status < 0) +#ifdef USBF_UAC1_INCLUDED + return status; +#else + goto fail; +#endif + ac_interface_desc.iInterface = strings_uac1[STR_AC_IF].id; + input_terminal_desc.iTerminal = + strings_uac1[STR_INPUT_TERMINAL].id; + input_terminal_desc.iChannelNames = + strings_uac1[STR_INPUT_TERMINAL_CH_NAMES].id; + feature_unit_desc.iFeature = strings_uac1[STR_FEAT_DESC_0].id; + output_terminal_desc.iTerminal = + strings_uac1[STR_OUTPUT_TERMINAL].id; + as_interface_alt_0_desc.iInterface = + strings_uac1[STR_AS_IF_ALT0].id; + as_interface_alt_1_desc.iInterface = + strings_uac1[STR_AS_IF_ALT1].id; + } f_audio_build_desc(audio); @@ -698,19 +760,24 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: +#ifndef USBF_UAC1_INCLUDED + gaudio_cleanup(&audio->card); +#endif if (ep) ep->driver_data = NULL; return status; } +#ifdef USBF_UAC1_INCLUDED static void -f_audio_unbind(struct usb_configuration *c, struct usb_function *f) +old_f_audio_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_audio *audio = func_to_audio(f); usb_free_all_descriptors(f); kfree(audio); } +#endif /*-------------------------------------------------------------------------*/ @@ -727,7 +794,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd) } /* Todo: add more control selecotor dynamically */ -static int __init control_selector_init(struct f_audio *audio) +static int control_selector_init(struct f_audio *audio) { INIT_LIST_HEAD(&audio->cs); list_add(&feature_unit.list, &audio->cs); @@ -744,6 +811,7 @@ static int __init control_selector_init(struct f_audio *audio) return 0; } +#ifdef USBF_UAC1_INCLUDED /** * audio_bind_config - add USB audio function to a configuration * @c: the configuration to supcard the USB audio function @@ -756,24 +824,6 @@ static int __init audio_bind_config(struct usb_configuration *c) struct f_audio *audio; int status; - if (strings_uac1[0].id == 0) { - status = usb_string_ids_tab(c->cdev, strings_uac1); - if (status < 0) - return status; - ac_interface_desc.iInterface = strings_uac1[STR_AC_IF].id; - input_terminal_desc.iTerminal = - strings_uac1[STR_INPUT_TERMINAL].id; - input_terminal_desc.iChannelNames = - strings_uac1[STR_INPUT_TERMINAL_CH_NAMES].id; - feature_unit_desc.iFeature = strings_uac1[STR_FEAT_DESC_0].id; - output_terminal_desc.iTerminal = - strings_uac1[STR_OUTPUT_TERMINAL].id; - as_interface_alt_0_desc.iInterface = - strings_uac1[STR_AS_IF_ALT0].id; - as_interface_alt_1_desc.iInterface = - strings_uac1[STR_AS_IF_ALT1].id; - } - /* allocate and initialize one new instance */ audio = kzalloc(sizeof *audio, GFP_KERNEL); if (!audio) @@ -789,10 +839,9 @@ static int __init audio_bind_config(struct usb_configuration *c) status = gaudio_setup(&audio->card); if (status < 0) goto setup_fail; - audio->card.func.strings = uac1_strings; audio->card.func.bind = f_audio_bind; - audio->card.func.unbind = f_audio_unbind; + audio->card.func.unbind = old_f_audio_unbind; audio->card.func.set_alt = f_audio_set_alt; audio->card.func.setup = f_audio_setup; audio->card.func.disable = f_audio_disable; @@ -816,3 +865,71 @@ setup_fail: kfree(audio); return status; } +#else +static void f_audio_free_inst(struct usb_function_instance *f) +{ + struct f_uac1_opts *opts; + + opts = container_of(f, struct f_uac1_opts, func_inst); + gaudio_cleanup(opts->card); + kfree(opts); +} + +static struct usb_function_instance *f_audio_alloc_inst(void) +{ + struct f_uac1_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = f_audio_free_inst; + + return &opts->func_inst; +} + +static void f_audio_free(struct usb_function *f) +{ + struct f_audio *audio = func_to_audio(f); + + kfree(audio); +} + +static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f) +{ + usb_free_all_descriptors(f); +} + +static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) +{ + struct f_audio *audio; + + /* allocate and initialize one new instance */ + audio = kzalloc(sizeof(*audio), GFP_KERNEL); + if (!audio) + return ERR_PTR(-ENOMEM); + + audio->card.func.name = "g_audio"; + + INIT_LIST_HEAD(&audio->play_queue); + spin_lock_init(&audio->lock); + + audio->card.func.strings = uac1_strings; + audio->card.func.bind = f_audio_bind; + audio->card.func.unbind = f_audio_unbind; + audio->card.func.set_alt = f_audio_set_alt; + audio->card.func.setup = f_audio_setup; + audio->card.func.disable = f_audio_disable; + audio->card.func.free_func = f_audio_free; + + control_selector_init(audio); + + INIT_WORK(&audio->playback_work, f_audio_playback_work); + + return &audio->card.func; +} + +DECLARE_USB_FUNCTION_INIT(uac1, f_audio_alloc_inst, f_audio_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bryan Wu"); +#endif diff --git a/drivers/usb/gadget/function/u_uac1.c b/drivers/usb/gadget/function/u_uac1.c index 7a55fea..9a55e5c 100644 --- a/drivers/usb/gadget/function/u_uac1.c +++ b/drivers/usb/gadget/function/u_uac1.c @@ -10,6 +10,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/device.h> #include <linux/delay.h> @@ -23,6 +24,7 @@ * This component encapsulates the ALSA devices for USB audio gadget */ +#ifdef USBF_UAC1_INCLUDED #define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D0p" #define FILE_PCM_CAPTURE "/dev/snd/pcmC0D0c" #define FILE_CONTROL "/dev/snd/controlC0" @@ -38,7 +40,7 @@ MODULE_PARM_DESC(fn_cap, "Capture PCM device file name"); static char *fn_cntl = FILE_CONTROL; module_param(fn_cntl, charp, S_IRUGO); MODULE_PARM_DESC(fn_cntl, "Control device file name"); - +#endif /*-------------------------------------------------------------------------*/ /** @@ -167,7 +169,7 @@ static int playback_default_hw_params(struct gaudio_snd_dev *snd) /** * Playback audio buffer data by ALSA PCM device */ -static size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) +size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) { struct gaudio_snd_dev *snd = &card->playback; struct snd_pcm_substream *substream = snd->substream; @@ -202,12 +204,12 @@ try_again: return 0; } -static int u_audio_get_playback_channels(struct gaudio *card) +int u_audio_get_playback_channels(struct gaudio *card) { return card->playback.channels; } -static int u_audio_get_playback_rate(struct gaudio *card) +int u_audio_get_playback_rate(struct gaudio *card) { return card->playback.rate; } @@ -220,6 +222,15 @@ static int gaudio_open_snd_dev(struct gaudio *card) { struct snd_pcm_file *pcm_file; struct gaudio_snd_dev *snd; +#ifndef USBF_UAC1_INCLUDED + struct f_uac1_opts *opts; + char *fn_play, *fn_cap, *fn_cntl; + + opts = container_of(card->func.fi, struct f_uac1_opts, func_inst); + fn_play = opts->fn_play; + fn_cap = opts->fn_cap; + fn_cntl = opts->fn_cntl; +#endif if (!card) return -ENODEV; @@ -293,7 +304,9 @@ static int gaudio_close_snd_dev(struct gaudio *gau) return 0; } +#ifdef USBF_UAC1_INCLUDED static struct gaudio *the_card; +#endif /** * gaudio_setup - setup ALSA interface and preparing for USB transfer * @@ -301,15 +314,17 @@ static struct gaudio *the_card; * * Returns negative errno, or zero on success */ -int __init gaudio_setup(struct gaudio *card) +int gaudio_setup(struct gaudio *card) { int ret; ret = gaudio_open_snd_dev(card); if (ret) ERROR(card, "we need at least one control device\n"); +#ifdef USBF_UAC1_INCLUDED else if (!the_card) the_card = card; +#endif return ret; @@ -320,11 +335,17 @@ int __init gaudio_setup(struct gaudio *card) * * This is called to free all resources allocated by @gaudio_setup(). */ +#ifdef USBF_UAC1_INCLUDED void gaudio_cleanup(void) +#else +void gaudio_cleanup(struct gaudio *the_card) +#endif { if (the_card) { gaudio_close_snd_dev(the_card); +#ifdef USBF_UAC1_INCLUDED the_card = NULL; +#endif } } diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h index 18c2e72..5b4fe9e 100644 --- a/drivers/usb/gadget/function/u_uac1.h +++ b/drivers/usb/gadget/function/u_uac1.h @@ -50,7 +50,27 @@ struct gaudio { /* TODO */ }; +struct f_uac1_opts { + struct usb_function_instance func_inst; + int req_buf_size; + int req_count; + int audio_buf_size; + char *fn_play; + char *fn_cap; + char *fn_cntl; + bool bound; + struct gaudio *card; +}; + int gaudio_setup(struct gaudio *card); +#ifdef USBF_UAC1_INCLUDED void gaudio_cleanup(void); +#else +void gaudio_cleanup(struct gaudio *the_card); +#endif + +size_t u_audio_playback(struct gaudio *card, void *buf, size_t count); +int u_audio_get_playback_channels(struct gaudio *card); +int u_audio_get_playback_rate(struct gaudio *card); #endif /* __U_AUDIO_H */ diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index 47a7de7..cf1a543 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -80,6 +80,7 @@ static struct usb_function *f_uac2; #endif #ifdef CONFIG_GADGET_UAC1 +#define USBF_UAC1_INCLUDED #include "u_uac1.h" #include "f_uac1.c" #endif |