ANDROID: usb: gadget: f_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

[AmitP: Folded following android-4.9 commit changes into this patch
        95106e3d2071 ("ANDROID: usb: gadget: build audio_source function only if SND is enabled")
        4de9e33e5046 ("ANDROID: usb: gadget: audio_source: fix comparison of distinct pointer types")
        Parts of 051584e76d12 ("ANDROID: usb: gadget: function: cleanup: Add blank line after declaration")]
Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
This commit is contained in:
Badhri Jagan Sridharan 2014-11-23 13:51:28 -08:00 committed by Amit Pundir
parent 4503b048c5
commit 4f5452d938
3 changed files with 245 additions and 11 deletions

View file

@ -215,6 +215,9 @@ config USB_F_PRINTER
config USB_F_TCM
tristate
config USB_F_AUDIO_SRC
tristate
# this first set of drivers all depend on bulk-capable hardware.
config USB_CONFIGFS
@ -368,6 +371,15 @@ config USB_CONFIGFS_F_FS
implemented in kernel space (for instance Ethernet, serial or
mass storage) and other are implemented in user space.
config USB_CONFIGFS_F_AUDIO_SRC
bool "Audio Source gadget"
depends on USB_CONFIGFS
depends on SND
select SND_PCM
select USB_F_AUDIO_SRC
help
USB gadget Audio Source support
config USB_CONFIGFS_UEVENT
bool "Uevent notification of Gadget state"
depends on USB_CONFIGFS

View file

@ -11,3 +11,5 @@ libcomposite-y := usbstring.o config.o epautoconf.o
libcomposite-y += composite.o functions.o configfs.o u_f.o
obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/
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,9 +277,40 @@ 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);
if (!req)
return NULL;
@ -338,10 +378,9 @@ static void audio_send(struct audio_dev *audio)
/* compute number of frames to send */
now = ktime_get();
msecs = ktime_to_ns(now) - ktime_to_ns(audio->start_time);
do_div(msecs, 1000000);
frames = msecs * SAMPLE_RATE;
do_div(frames, 1000);
msecs = div_s64((ktime_to_ns(now) - ktime_to_ns(audio->start_time)),
1000000);
frames = div_s64((msecs * SAMPLE_RATE), 1000);
/* Readjust our frames_sent if we fall too far behind.
* If we get too far behind it is better to drop some frames than
@ -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");