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

Commit 85673860 authored by Manu Gautam's avatar Manu Gautam
Browse files

usb: gadget: audio: open/close Audio files on USB connect/disconnect



Driver opens audio files on bind_config, but doesn't close them.
It prevents system to enter suspend state as AFE keeps pushing
data to apps. Change this design to open Audio streams on USB connect
(after set_alt) and close on disconnect i.e. function_disable. Also,
free usb_req and req->buff on disconnect after calling ep_disable as
buffers are currently not freed at all.

Change-Id: Ia6960c399aec2e082d04ad4409fa36880e87a5b7
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
parent 926233dc
Loading
Loading
Loading
Loading
+73 −1
Original line number Original line Diff line number Diff line
@@ -479,6 +479,9 @@ static void f_audio_buffer_free(struct f_audio_buf *audio_buf)


struct f_audio {
struct f_audio {
	struct gaudio			card;
	struct gaudio			card;
	atomic_t			online;
	struct mutex                    mutex;
	struct work_struct		close_work;


	/* endpoints handle full and/or high speeds */
	/* endpoints handle full and/or high speeds */
	struct usb_ep			*out_ep;
	struct usb_ep			*out_ep;
@@ -520,6 +523,19 @@ static void f_audio_playback_work(struct work_struct *data)
	int res = 0;
	int res = 0;


	pr_debug("%s: started\n", __func__);
	pr_debug("%s: started\n", __func__);
	if (!atomic_read(&audio->online)) {
		pr_debug("%s offline\n", __func__);
		return;
	}
	/* set up ASLA audio devices if not already done */
	mutex_lock(&audio->mutex);
	res = gaudio_setup(&audio->card);
	if (res < 0) {
		mutex_unlock(&audio->mutex);
		return;
	}
	mutex_unlock(&audio->mutex);

	spin_lock_irqsave(&audio->playback_lock, flags);
	spin_lock_irqsave(&audio->playback_lock, flags);
	if (list_empty(&audio->play_queue)) {
	if (list_empty(&audio->play_queue)) {
		pr_err("playback_buf is empty");
		pr_err("playback_buf is empty");
@@ -605,6 +621,19 @@ static void f_audio_capture_work(struct work_struct *data)
	int res = 0;
	int res = 0;


	pr_debug("%s Started\n", __func__);
	pr_debug("%s Started\n", __func__);
	if (!atomic_read(&audio->online)) {
		pr_debug("%s offline\n", __func__);
		return;
	}
	/* set up ASLA audio devices if not already done */
	mutex_lock(&audio->mutex);
	res = gaudio_setup(&audio->card);
	if (res < 0) {
		mutex_unlock(&audio->mutex);
		return;
	}
	mutex_unlock(&audio->mutex);

	spin_lock_irqsave(&audio->capture_lock, flags);
	spin_lock_irqsave(&audio->capture_lock, flags);
	if (!list_empty(&audio->capture_queue)) {
	if (!list_empty(&audio->capture_queue)) {
		spin_unlock_irqrestore(&audio->capture_lock, flags);
		spin_unlock_irqrestore(&audio->capture_lock, flags);
@@ -701,6 +730,11 @@ static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
		break;
		break;
	default:
	default:
		pr_err("Failed completion: status %d", status);
		pr_err("Failed completion: status %d", status);
		/* fall through to to free buffer and req */
	case -ECONNRESET:
	case -ESHUTDOWN:
		kfree(req->buf);
		usb_ep_free_request(ep, req);
		break;
		break;
	}
	}
}
}
@@ -987,6 +1021,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
	req_playback_count = opts->req_playback_count;
	req_playback_count = opts->req_playback_count;
	audio_playback_buf_size = opts->audio_playback_buf_size;
	audio_playback_buf_size = opts->audio_playback_buf_size;


	atomic_set(&audio->online, 1);
	if (intf == uac1_header_desc.baInterfaceNr[0]) {
	if (intf == uac1_header_desc.baInterfaceNr[0]) {
		if (audio->alt_intf[0] == alt) {
		if (audio->alt_intf[0] == alt) {
			pr_debug("Alt interface is already set to %d. Do nothing.\n",
			pr_debug("Alt interface is already set to %d. Do nothing.\n",
@@ -996,6 +1031,10 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
		}
		}


		if (alt == 1) {
		if (alt == 1) {
			err = config_ep_by_speed(cdev->gadget, f, in_ep);
			if (err)
				return err;

			err = usb_ep_enable(in_ep);
			err = usb_ep_enable(in_ep);
			if (err) {
			if (err) {
				pr_err("Failed to enable capture ep");
				pr_err("Failed to enable capture ep");
@@ -1029,6 +1068,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			schedule_work(&audio->capture_work);
			schedule_work(&audio->capture_work);
		} else {
		} else {
			struct f_audio_buf *capture_buf;
			struct f_audio_buf *capture_buf;
			usb_ep_disable(in_ep);
			spin_lock_irqsave(&audio->capture_lock, flags);
			spin_lock_irqsave(&audio->capture_lock, flags);
			while (!list_empty(&audio->capture_queue)) {
			while (!list_empty(&audio->capture_queue)) {
				capture_buf =
				capture_buf =
@@ -1051,6 +1091,10 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
		}
		}


		if (alt == 1) {
		if (alt == 1) {
			err = config_ep_by_speed(cdev->gadget, f, out_ep);
			if (err)
				return err;

			err = usb_ep_enable(out_ep);
			err = usb_ep_enable(out_ep);
			if (err) {
			if (err) {
				pr_err("Failed to enable playback ep");
				pr_err("Failed to enable playback ep");
@@ -1092,6 +1136,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
		} else {
		} else {
			struct f_audio_buf *playback_copy_buf =
			struct f_audio_buf *playback_copy_buf =
				audio->playback_copy_buf;
				audio->playback_copy_buf;
			usb_ep_disable(out_ep);
			if (playback_copy_buf) {
			if (playback_copy_buf) {
				pr_err("Schedule playback_work");
				pr_err("Schedule playback_work");
				list_add_tail(&playback_copy_buf->list,
				list_add_tail(&playback_copy_buf->list,
@@ -1110,10 +1155,32 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
	return err;
	return err;
}
}


static void f_audio_close_work(struct work_struct *data)
{
	struct f_audio *audio =
			container_of(data, struct f_audio, close_work);

	pr_debug("close audio files\n");
	mutex_lock(&audio->mutex);
	gaudio_cleanup(&audio->card);
	mutex_unlock(&audio->mutex);
}

static void f_audio_disable(struct usb_function *f)
static void f_audio_disable(struct usb_function *f)
{
{
	struct f_audio	*audio = func_to_audio(f);
	struct f_audio	*audio = func_to_audio(f);
	struct usb_ep	*out_ep = audio->out_ep;
	struct usb_ep	*in_ep = audio->in_ep;

	pr_debug("Disable audio");
	atomic_set(&audio->online, 0);
	usb_ep_disable(in_ep);
	usb_ep_disable(out_ep);

	u_audio_clear(&audio->card);
	u_audio_clear(&audio->card);
	schedule_work(&audio->close_work);

	return;
}
}


/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
@@ -1523,6 +1590,9 @@ static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
{
{
	struct f_audio *audio = func_to_audio(f);
	struct f_audio *audio = func_to_audio(f);


	flush_work(&audio->playback_work);
	flush_work(&audio->capture_work);
	flush_work(&audio->close_work);
	gaudio_cleanup(&audio->card);
	gaudio_cleanup(&audio->card);
	usb_free_all_descriptors(f);
	usb_free_all_descriptors(f);
}
}
@@ -1561,6 +1631,8 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi)


	INIT_WORK(&audio->playback_work, f_audio_playback_work);
	INIT_WORK(&audio->playback_work, f_audio_playback_work);
	INIT_WORK(&audio->capture_work, f_audio_capture_work);
	INIT_WORK(&audio->capture_work, f_audio_capture_work);
	INIT_WORK(&audio->close_work, f_audio_close_work);
	mutex_init(&audio->mutex);


	return &audio->card.func;
	return &audio->card.func;
}
}
+8 −0
Original line number Original line Diff line number Diff line
@@ -708,8 +708,16 @@ static int gaudio_close_snd_dev(struct gaudio *gau)
 */
 */
int gaudio_setup(struct gaudio *card)
int gaudio_setup(struct gaudio *card)
{
{
	struct gaudio_snd_dev *snd;
	int	ret;
	int	ret;


	snd = &card->control;
	if (snd->card) {
		pr_debug("snd devices already opened\n");
		return 0;
	}

	pr_debug("trying to open snd devices\n");
	ret = gaudio_open_snd_dev(card);
	ret = gaudio_open_snd_dev(card);
	if (ret)
	if (ret)
		ERROR(card, "we need at least one control device\n");
		ERROR(card, "we need at least one control device\n");