ANDROID: 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 <badhri@google.com>
Change-Id: I1fc6c9ea07105ae4eb785eebd3bb925bfdd8bc6b
This commit is contained in:
Badhri Jagan Sridharan
2014-11-23 13:51:28 -08:00
committed by Dmitry Shmidt
parent d6b2d77cd6
commit 743a13cbca
3 changed files with 239 additions and 7 deletions

View File

@@ -213,6 +213,9 @@ config USB_F_MTP
tristate
config USB_F_PTP
tristate
config USB_F_AUDIO_SRC
tristate
# this first set of drivers all depend on bulk-capable hardware.
@@ -382,6 +385,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

View File

@@ -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

View File

@@ -21,6 +21,13 @@
#include <sound/initval.h>
#include <sound/pcm.h>
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/usb/ch9.h>
#include <linux/configfs.h>
#include <linux/usb/composite.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#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");