diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c index cabe289b932458444484d6643059d63f663ae832..25b1042d3c776ed308b0fada7f6c14708f508210 100644 --- a/drivers/staging/greybus/audio_codec.c +++ b/drivers/staging/greybus/audio_codec.c @@ -80,11 +80,7 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream, struct gbaudio_dai *gb_dai; struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev); - if (!atomic_read(&gb->is_connected)) - return; - /* find the dai */ - mutex_lock(&gb->lock); gb_dai = gbaudio_find_dai(gb, -1, dai->name); if (!gb_dai) { dev_err(dai->dev, "%s: DAI not registered\n", dai->name); @@ -93,6 +89,13 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream, atomic_dec(&gb_dai->users); + if (!atomic_read(&gb->is_connected)) { + if (!atomic_read(&gb_dai->users)) + wake_up_interruptible(&gb_dai->wait_queue); + return; + } + + mutex_lock(&gb->lock); /* deactivate rx/tx */ cportid = gb_dai->connection->intf_cport_id; @@ -121,6 +124,11 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream, func_exit: mutex_unlock(&gb->lock); + /* + if (!atomic_read(&gb_dai->users)) + wake_up_interruptible(&gb_dai->wait_queue); + */ + return; } @@ -290,8 +298,11 @@ static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd, struct gbaudio_dai *gb_dai; struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev); - if (!atomic_read(&gb->is_connected)) + if (!atomic_read(&gb->is_connected)) { + if (cmd == SNDRV_PCM_TRIGGER_STOP) + return 0; return -ENODEV; + } /* find the dai */ mutex_lock(&gb->lock); @@ -443,9 +454,10 @@ static unsigned int gbcodec_read(struct snd_soc_codec *codec, */ static void gb_audio_cleanup(struct gbaudio_codec_info *gb) { - int cportid, ret; + int cportid, ret, timeout_result; struct gbaudio_dai *gb_dai; struct gb_connection *connection; + long timeout = msecs_to_jiffies(50); /* 50ms */ struct device *dev = gb->dev; list_for_each_entry(gb_dai, &gb->dai_list, list) { @@ -454,6 +466,16 @@ static void gb_audio_cleanup(struct gbaudio_codec_info *gb) * manually */ if (atomic_read(&gb_dai->users)) { + /* schedule a wait event */ + timeout_result = + wait_event_interruptible_timeout( + gb_dai->wait_queue, + !atomic_read(&gb_dai->users), + timeout); + if (!timeout_result) + dev_warn(dev, "%s:DAI still in use.\n", + gb_dai->name); + connection = gb_dai->connection; /* PB active */ ret = gb_audio_apbridgea_stop_tx(connection, 0); @@ -473,7 +495,6 @@ static void gb_audio_cleanup(struct gbaudio_codec_info *gb) if (ret) dev_info(dev, "%d:Failed during unregister cport\n", ret); - atomic_dec(&gb_dai->users); } } } @@ -655,6 +676,7 @@ static int gb_audio_add_data_connection(struct gbaudio_codec_info *gbcodec, connection->private = gbcodec; atomic_set(&dai->users, 0); + init_waitqueue_head(&dai->wait_queue); dai->data_cport = connection->intf_cport_id; dai->connection = connection; list_add(&dai->list, &gbcodec->dai_list); diff --git a/drivers/staging/greybus/audio_codec.h b/drivers/staging/greybus/audio_codec.h index 4c19bd8844881fadafe513ad17c623f4cbdcdefa..fc60c36aa040f2e558d076b0826a7e193c3ce707 100644 --- a/drivers/staging/greybus/audio_codec.h +++ b/drivers/staging/greybus/audio_codec.h @@ -88,6 +88,7 @@ struct gbaudio_dai { atomic_t users; struct gb_connection *connection; struct list_head list; + wait_queue_head_t wait_queue; }; struct gbaudio_codec_info {