From fd61a2db4c4f6890aeb524cc536a6142da08cc89 Mon Sep 17 00:00:00 2001 From: Meng Dongyang Date: Wed, 16 May 2018 18:46:31 +0800 Subject: [PATCH] usb: gadget: uac: add uevent of setting interface Add uevent of setting interface to notify the application. In some cases that the application want to get the change event and state of alt immediately when to select the next operation, but current code doesn't have the interface for it. So this patch sent a uevent when setting interface and report the state of alt throw attribute of uevent. Change-Id: I47084f99bc046dede86d6b5777677f3799056c03 Signed-off-by: Meng Dongyang --- drivers/usb/gadget/function/f_audio_source.c | 109 +++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index 8124af33b738..ebdcdc4e1040 100644 --- a/drivers/usb/gadget/function/f_audio_source.c +++ b/drivers/usb/gadget/function/f_audio_source.c @@ -244,7 +244,10 @@ struct audio_source_config { int device; }; +static struct class *audio_source_class; + struct audio_dev { + struct device *dev; struct usb_function func; struct snd_card *card; struct snd_pcm *pcm; @@ -253,6 +256,8 @@ struct audio_dev { struct list_head idle_reqs; struct usb_ep *in_ep; + struct work_struct work; + spinlock_t lock; /* beginning, end and current position in our buffer */ @@ -260,6 +265,8 @@ struct audio_dev { void *buffer_end; void *buffer_pos; + unsigned int alt; + /* byte size of a "period" */ unsigned int period; /* bytes sent since last call to snd_pcm_period_elapsed */ @@ -278,6 +285,84 @@ static inline struct audio_dev *func_to_audio(struct usb_function *f) return container_of(f, struct audio_dev, func); } +static void audio_source_work(struct work_struct *data) +{ + struct audio_dev *audio = container_of(data, struct audio_dev, work); + char *set_interface[3] = { "USB_STATE=SET_INTERFACE", NULL, NULL}; + char **uevent_envp = NULL; + + if (audio->alt) + set_interface[1] = "1"; + else + set_interface[1] = "0"; + uevent_envp = set_interface; + + if (uevent_envp) { + kobject_uevent_env(&audio->dev->kobj, KOBJ_CHANGE, + uevent_envp); + pr_info("%s: sent uevent %s\n", __func__, + uevent_envp[0]); + } else { + pr_info("%s: did not send uevent set interface\n", + __func__); + } +} + +static ssize_t +alt_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct audio_dev *audio = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", audio->alt); +} + +static ssize_t +alt_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned int value; + struct audio_dev *audio = dev_get_drvdata(dev); + + if (sscanf(buf, "%d\n", &value) != 1) + return -1; + + if (audio->alt != value) { + audio->alt = value; + schedule_work(&audio->work); + } + return size; +} +static DEVICE_ATTR_RW(alt); + +static struct device_attribute *audio_source_attributes[] = { + &dev_attr_alt, + NULL +}; + +static int audio_source_create_device(struct audio_dev *audio) +{ + struct device_attribute **attrs = audio_source_attributes; + struct device_attribute *attr; + int err; + + audio->dev = device_create(audio_source_class, NULL, + MKDEV(0, 0), NULL, "audio_source0"); + if (IS_ERR(audio->dev)) + return PTR_ERR(audio->dev); + + dev_set_drvdata(audio->dev, audio); + + while ((attr = *attrs++)) { + err = device_create_file(audio->dev, attr); + if (err) { + device_destroy(audio_source_class, audio->dev->devt); + return err; + } + } + return 0; +} + /*-------------------------------------------------------------------------*/ struct audio_source_instance { @@ -574,6 +659,11 @@ static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (ret) return ret; + if (audio->alt != alt) { + audio->alt = alt; + schedule_work(&audio->work); + } + usb_ep_enable(audio->in_ep); return 0; } @@ -636,6 +726,13 @@ audio_bind(struct usb_configuration *c, struct usb_function *f) err = snd_card_setup(c, config); if (err) return err; + + audio_source_class = class_create(THIS_MODULE, "audio_source"); + if (IS_ERR(audio_source_class)) + return PTR_ERR(audio_source_class); + + INIT_WORK(&audio->work, audio_source_work); + audio_source_create_device(audio); } audio_build_desc(audio); @@ -697,11 +794,16 @@ audio_unbind(struct usb_configuration *c, struct usb_function *f) while ((req = audio_req_get(audio))) audio_request_free(req, audio->in_ep); + cancel_work_sync(&audio->work); + device_destroy(audio_source_class, audio->dev->devt); + class_destroy(audio_source_class); + snd_card_free_when_closed(audio->card); audio->card = NULL; audio->pcm = NULL; audio->substream = NULL; audio->in_ep = NULL; + audio->dev = NULL; if (IS_ENABLED(CONFIG_USB_CONFIGFS)) { struct audio_source_instance *fi_audio = @@ -879,6 +981,13 @@ int audio_source_bind_config(struct usb_configuration *c, if (err) goto add_fail; + audio_source_class = class_create(THIS_MODULE, "audio_source"); + if (IS_ERR(audio_source_class)) + return PTR_ERR(audio_source_class); + + INIT_WORK(&audio->work, audio_source_work); + audio_source_create_device(audio); + return 0; add_fail: