Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 743a13cb authored by Badhri Jagan Sridharan's avatar Badhri Jagan Sridharan Committed by Dmitry Shmidt
Browse files

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: default avatarBadhri Jagan Sridharan <badhri@google.com>
Change-Id: I1fc6c9ea07105ae4eb785eebd3bb925bfdd8bc6b
parent d6b2d77c
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -215,6 +215,9 @@ config USB_F_MTP
config USB_F_PTP
        tristate

config USB_F_AUDIO_SRC
	tristate

# this first set of drivers all depend on bulk-capable hardware.

config USB_CONFIGFS
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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
+227 −7
Original line number Diff line number Diff line
@@ -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");