From 3541608288141d2c7763315fab6e8be44db32349 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Sun, 23 Nov 2014 13:51:28 -0800 Subject: [PATCH] usb:gadget:audio_source: Move to USB_FUNCTION API This patch adds support to use audio_source gadget function through DECLARE_USB_FUNCTION_INIT interface. Signed-off-by: Badhri Jagan Sridharan Change-Id: I1fc6c9ea07105ae4eb785eebd3bb925bfdd8bc6b --- drivers/usb/gadget/Kconfig | 10 ++ drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/f_audio_source.c | 234 +++++++++++++++++++++++++++- 3 files changed, 239 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 6977b224218c..f550989173bf 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -203,6 +203,9 @@ config USB_F_MTP tristate config USB_F_PTP + tristate + +config USB_F_AUDIO_SRC tristate choice @@ -391,6 +394,13 @@ config USB_CONFIGFS_F_PTP help USB gadget PTP support +config USB_CONFIGFS_F_AUDIO_SRC + boolean "Audio Source gadget" + depends on USB_CONFIGFS + select USB_F_AUDIO_SRC + help + USB gadget Audio Source support + config USB_CONFIGFS_UEVENT boolean "Uevent notification of Gadget state" depends on USB_CONFIGFS diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 502c379cce80..386ed6343e33 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -15,3 +15,5 @@ usb_f_mtp-y := f_mtp.o obj-$(CONFIG_USB_F_MTP) += usb_f_mtp.o usb_f_ptp-y := f_ptp.o obj-$(CONFIG_USB_F_PTP) += usb_f_ptp.o +usb_f_audio_source-y := f_audio_source.o +obj-$(CONFIG_USB_F_AUDIO_SRC) += usb_f_audio_source.o diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c index 4b9786b48950..39645be93502 100644 --- a/drivers/usb/gadget/f_audio_source.c +++ b/drivers/usb/gadget/f_audio_source.c @@ -21,6 +21,13 @@ #include #include +#include +#include +#include +#include +#include +#include +#include #define SAMPLE_RATE 44100 #define FRAMES_PER_MSEC (SAMPLE_RATE / 1000) @@ -32,6 +39,7 @@ #define AUDIO_AC_INTERFACE 0 #define AUDIO_AS_INTERFACE 1 #define AUDIO_NUM_INTERFACES 2 +#define MAX_INST_NAME_LEN 40 /* B.3.1 Standard AC Interface Descriptor */ static struct usb_interface_descriptor ac_interface_desc = { @@ -259,6 +267,7 @@ struct audio_dev { ktime_t start_time; /* number of frames sent since start_time */ s64 frames_sent; + struct audio_source_config *config; }; static inline struct audio_dev *func_to_audio(struct usb_function *f) @@ -268,6 +277,36 @@ static inline struct audio_dev *func_to_audio(struct usb_function *f) /*-------------------------------------------------------------------------*/ +struct audio_source_instance { + struct usb_function_instance func_inst; + const char *name; + struct audio_source_config *config; + struct device *audio_device; +}; + +static void audio_source_attr_release(struct config_item *item); + +static struct configfs_item_operations audio_source_item_ops = { + .release = audio_source_attr_release, +}; + +static struct config_item_type audio_source_func_type = { + .ct_item_ops = &audio_source_item_ops, + .ct_owner = THIS_MODULE, +}; + +static ssize_t audio_source_pcm_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static DEVICE_ATTR(pcm, S_IRUGO, audio_source_pcm_show, NULL); + +static struct device_attribute *audio_source_function_attributes[] = { + &dev_attr_pcm, + NULL +}; + +/*--------------------------------------------------------------------------*/ + static struct usb_request *audio_request_new(struct usb_ep *ep, int buffer_size) { struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); @@ -561,6 +600,13 @@ static void audio_build_desc(struct audio_dev *audio) memcpy(sam_freq, &rate, 3); } + +static int snd_card_setup(struct usb_configuration *c, + struct audio_source_config *config); +static struct audio_source_instance *to_fi_audio_source( + const struct usb_function_instance *fi); + + /* audio function driver setup/binding */ static int audio_bind(struct usb_configuration *c, struct usb_function *f) @@ -571,6 +617,18 @@ audio_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; struct usb_request *req; int i; + int err; + + if (IS_ENABLED(CONFIG_USB_CONFIGFS)) { + struct audio_source_instance *fi_audio = + to_fi_audio_source(f->fi); + struct audio_source_config *config = + fi_audio->config; + + err = snd_card_setup(c, config); + if (err) + return err; + } audio_build_desc(audio); @@ -636,6 +694,16 @@ audio_unbind(struct usb_configuration *c, struct usb_function *f) audio->pcm = NULL; audio->substream = NULL; audio->in_ep = NULL; + + if (IS_ENABLED(CONFIG_USB_CONFIGFS)) { + struct audio_source_instance *fi_audio = + to_fi_audio_source(f->fi); + struct audio_source_config *config = + fi_audio->config; + + config->card = -1; + config->device = -1; + } } static void audio_pcm_playback_start(struct audio_dev *audio) @@ -779,8 +847,6 @@ int audio_source_bind_config(struct usb_configuration *c, struct audio_source_config *config) { struct audio_dev *audio; - struct snd_card *card; - struct snd_pcm *pcm; int err; config->card = -1; @@ -788,6 +854,31 @@ int audio_source_bind_config(struct usb_configuration *c, audio = &_audio_dev; + err = snd_card_setup(c, config); + if (err) + return err; + + err = usb_add_function(c, &audio->func); + if (err) + goto add_fail; + + return 0; + +add_fail: + snd_card_free(audio->card); + return err; +} + +static int snd_card_setup(struct usb_configuration *c, + struct audio_source_config *config) +{ + struct audio_dev *audio; + struct snd_card *card; + struct snd_pcm *pcm; + int err; + + audio = &_audio_dev; + err = snd_card_new(&c->cdev->gadget->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, 0, &card); @@ -817,18 +908,147 @@ int audio_source_bind_config(struct usb_configuration *c, if (err) goto register_fail; - err = usb_add_function(c, &audio->func); - if (err) - goto add_fail; - config->card = pcm->card->number; config->device = pcm->device; audio->card = card; return 0; -add_fail: register_fail: pcm_fail: snd_card_free(audio->card); return err; } + +static struct audio_source_instance *to_audio_source_instance( + struct config_item *item) +{ + return container_of(to_config_group(item), struct audio_source_instance, + func_inst.group); +} + +static struct audio_source_instance *to_fi_audio_source( + const struct usb_function_instance *fi) +{ + return container_of(fi, struct audio_source_instance, func_inst); +} + +static void audio_source_attr_release(struct config_item *item) +{ + struct audio_source_instance *fi_audio = to_audio_source_instance(item); + + usb_put_function_instance(&fi_audio->func_inst); +} + +static int audio_source_set_inst_name(struct usb_function_instance *fi, + const char *name) +{ + struct audio_source_instance *fi_audio; + char *ptr; + int name_len; + + name_len = strlen(name) + 1; + if (name_len > MAX_INST_NAME_LEN) + return -ENAMETOOLONG; + + ptr = kstrndup(name, name_len, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + fi_audio = to_fi_audio_source(fi); + fi_audio->name = ptr; + + return 0; +} + +static void audio_source_free_inst(struct usb_function_instance *fi) +{ + struct audio_source_instance *fi_audio; + + fi_audio = to_fi_audio_source(fi); + device_destroy(fi_audio->audio_device->class, + fi_audio->audio_device->devt); + kfree(fi_audio->name); + kfree(fi_audio->config); +} + +static ssize_t audio_source_pcm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct audio_source_instance *fi_audio = dev_get_drvdata(dev); + struct audio_source_config *config = fi_audio->config; + + /* print PCM card and device numbers */ + return sprintf(buf, "%d %d\n", config->card, config->device); +} + +struct device *create_function_device(char *name); + +static struct usb_function_instance *audio_source_alloc_inst(void) +{ + struct audio_source_instance *fi_audio; + struct device_attribute **attrs; + struct device_attribute *attr; + struct device *dev; + void *err_ptr; + int err = 0; + + fi_audio = kzalloc(sizeof(*fi_audio), GFP_KERNEL); + if (!fi_audio) + return ERR_PTR(-ENOMEM); + + fi_audio->func_inst.set_inst_name = audio_source_set_inst_name; + fi_audio->func_inst.free_func_inst = audio_source_free_inst; + + fi_audio->config = kzalloc(sizeof(struct audio_source_config), + GFP_KERNEL); + if (!fi_audio->config) { + err_ptr = ERR_PTR(-ENOMEM); + goto fail_audio; + } + + config_group_init_type_name(&fi_audio->func_inst.group, "", + &audio_source_func_type); + dev = create_function_device("f_audio_source"); + + if (IS_ERR(dev)) { + err_ptr = dev; + goto fail_audio_config; + } + + fi_audio->config->card = -1; + fi_audio->config->device = -1; + fi_audio->audio_device = dev; + + attrs = audio_source_function_attributes; + if (attrs) { + while ((attr = *attrs++) && !err) + err = device_create_file(dev, attr); + if (err) { + err_ptr = ERR_PTR(-EINVAL); + goto fail_device; + } + } + + dev_set_drvdata(dev, fi_audio); + _audio_dev.config = fi_audio->config; + + return &fi_audio->func_inst; + +fail_device: + device_destroy(dev->class, dev->devt); +fail_audio_config: + kfree(fi_audio->config); +fail_audio: + kfree(fi_audio); + return err_ptr; + +} + +static struct usb_function *audio_source_alloc(struct usb_function_instance *fi) +{ + return &_audio_dev.func; +} + +DECLARE_USB_FUNCTION_INIT(audio_source, audio_source_alloc_inst, + audio_source_alloc); +MODULE_LICENSE("GPL"); -- 2.34.1