greybus: audio: Reorder gb_deactivate sequence to avoid protocol error
authorVaibhav Agarwal <vaibhav.agarwal@linaro.org>
Sat, 23 Apr 2016 14:34:05 +0000 (20:04 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 26 Apr 2016 00:37:10 +0000 (17:37 -0700)
gb_activate_tx/rx is triggered from _prepare() & gb_deactivate
from shutdown(). This may cause protocol error in case shutdown
executes without _prepare due to some hw_params failure.

Also, reorganise _prepare & _shutdown calls to make it more
readable & cleaner.

Signed-off-by: Vaibhav Agarwal <vaibhav.agarwal@linaro.org>
Reviewed-by: Mark Greer <mgreer@animalcreek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/audio_codec.c

index a2b81ba78196f7b21855130831f97771f1c7ff84..7a9abbf0ed5a82e6a7cd69d44d636e7945398fbe 100644 (file)
@@ -395,12 +395,88 @@ static int gbcodec_startup(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static int gbmodule_shutdown_tx(struct gbaudio_module_info *module,
+                               struct gbaudio_data_connection *data,
+                               int codec_state, struct device *dev)
+{
+       int ret, module_state;
+       __u16 i2s_port, cportid;
+
+       module_state = module->ctrlstate[0];
+       if (module_state == GBAUDIO_CODEC_SHUTDOWN) {
+               dev_dbg(dev, "%s: module already configured\n",
+                       module->name);
+               return 0;
+       }
+
+       if (codec_state == GBAUDIO_CODEC_STOP) {
+               ret = gb_audio_apbridgea_shutdown_tx(data->connection, 0);
+               if (ret)
+                       return ret;
+       }
+
+       /* deactivate */
+       cportid = data->connection->intf_cport_id;
+       if (module_state >= GBAUDIO_CODEC_PREPARE) {
+               ret = gb_audio_gb_deactivate_tx(module->mgmt_connection,
+                                               cportid);
+               if (ret)
+                       return ret;
+       }
+
+       /* unregister cport */
+       i2s_port = 0;   /* fixed for now */
+       cportid = data->connection->hd_cport_id;
+       ret = gb_audio_apbridgea_unregister_cport(data->connection, i2s_port,
+                                                 cportid,
+                                                 AUDIO_APBRIDGEA_DIRECTION_TX);
+
+       return ret;
+}
+
+static int gbmodule_shutdown_rx(struct gbaudio_module_info *module,
+                               struct gbaudio_data_connection *data,
+                               int codec_state, struct device *dev)
+{
+       int ret, module_state;
+       __u16 i2s_port, cportid;
+
+       module_state = module->ctrlstate[1];
+       if (module_state == GBAUDIO_CODEC_SHUTDOWN) {
+               dev_dbg(dev, "%s: module already configured\n",
+                       module->name);
+               return 0;
+       }
+
+       if (codec_state == GBAUDIO_CODEC_STOP) {
+               ret = gb_audio_apbridgea_shutdown_rx(data->connection, 0);
+               if (ret)
+                       return ret;
+       }
+
+       /* deactivate */
+       cportid = data->connection->intf_cport_id;
+       if (module_state >= GBAUDIO_CODEC_PREPARE) {
+               ret = gb_audio_gb_deactivate_rx(module->mgmt_connection,
+                                               cportid);
+               if (ret)
+                       return ret;
+       }
+
+       /* unregister cport */
+       i2s_port = 0;   /* fixed for now */
+       cportid = data->connection->hd_cport_id;
+       ret = gb_audio_apbridgea_unregister_cport(data->connection, i2s_port,
+                                                 cportid,
+                                                 AUDIO_APBRIDGEA_DIRECTION_RX);
+
+       return ret;
+}
+
 static void gbcodec_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       int ret;
-       __u16 i2s_port, cportid;
-       int state, module_state;
+       int ret, state;
        struct gbaudio_module_info *module;
        struct gbaudio_data_connection *data;
        struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
@@ -423,14 +499,6 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream,
                        mutex_unlock(&module->lock);
                        continue;
                }
-               module_state = module->ctrlstate[substream->stream];
-               if (module_state == GBAUDIO_CODEC_SHUTDOWN) {
-                       dev_dbg(codec->dev, "%s: module already configured\n",
-                               module->name);
-                       mutex_unlock(&module->lock);
-                       continue;
-               }
-
                /* find the dai */
                data = find_data(module, dai->name);
                if (!data) {
@@ -440,32 +508,18 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream,
                        continue;
                }
 
-               /* deactivate */
-               cportid = data->connection->intf_cport_id;
                switch (substream->stream) {
-               case SNDRV_PCM_STREAM_CAPTURE:
-                       ret = gb_audio_gb_deactivate_rx(module->mgmt_connection,
-                                                       cportid);
-                       /* unregister cport */
-                       i2s_port = 0;   /* fixed for now */
-                       cportid = data->connection->hd_cport_id;
-                       ret = gb_audio_apbridgea_unregister_cport(
-                                       data->connection, i2s_port, cportid,
-                                       AUDIO_APBRIDGEA_DIRECTION_RX);
-                       break;
                case SNDRV_PCM_STREAM_PLAYBACK:
-                       ret = gb_audio_gb_deactivate_tx(module->mgmt_connection,
-                                                       cportid);
-                       /* unregister cport */
-                       i2s_port = 0;   /* fixed for now */
-                       cportid = data->connection->hd_cport_id;
-                       ret = gb_audio_apbridgea_unregister_cport(
-                                       data->connection, i2s_port, cportid,
-                                       AUDIO_APBRIDGEA_DIRECTION_TX);
+                       ret = gbmodule_shutdown_tx(module, data, state,
+                                                  dai->dev);
+                       break;
+               case SNDRV_PCM_STREAM_CAPTURE:
+                       ret = gbmodule_shutdown_rx(module, data, state,
+                                                  dai->dev);
                        break;
                }
-               dev_dbg(dai->dev, "Unregister %s:%d DAI, ret:%d\n", dai->name,
-                       cportid, ret);
+               dev_dbg(dai->dev, "Unregister %s DAI, ret:%d\n", dai->name,
+                       ret);
                state = GBAUDIO_CODEC_SHUTDOWN;
                module->ctrlstate[substream->stream] = state;
                dev_dbg(dai->dev, "%s: state:%d\n", module->name, state);
@@ -589,14 +643,82 @@ func_exit:
        return ret;
 }
 
+static int gbmodule_prepare_tx(struct gbaudio_module_info *module,
+                              struct gbaudio_data_connection *data,
+                              int codec_state, struct device *dev)
+{
+       int ret;
+       uint16_t data_cport;
+
+       data_cport = data->connection->intf_cport_id;
+       ret = gb_audio_gb_set_tx_data_size(module->mgmt_connection, data_cport,
+                                          192);
+       if (ret) {
+               dev_err(dev, "%d:Error during set_tx_data_size, cport:%d\n",
+                       ret, data_cport);
+               return ret;
+       }
+       if (codec_state < GBAUDIO_CODEC_PREPARE) {
+               ret = gb_audio_apbridgea_set_tx_data_size(data->connection, 0,
+                                                         192);
+               if (ret) {
+                       dev_err(dev,
+                               "%d:Error during apbridgea set_tx_data_size, cport\n",
+                               ret);
+                       return ret;
+               }
+       }
+       ret = gb_audio_gb_activate_tx(module->mgmt_connection,
+                                     data_cport);
+       if (ret)
+               dev_err(dev, "%s:Error during activate stream,%d\n",
+                       module->name, ret);
+
+       return ret;
+}
+
+static int gbmodule_prepare_rx(struct gbaudio_module_info *module,
+                              struct gbaudio_data_connection *data,
+                              int codec_state, struct device *dev)
+{
+       int ret;
+       uint16_t data_cport;
+
+       data_cport = data->connection->intf_cport_id;
+
+       ret = gb_audio_gb_set_rx_data_size(module->mgmt_connection, data_cport,
+                                          192);
+       if (ret) {
+               dev_err(dev, "%d:Error during set_rx_data_size, cport:%d\n",
+                       ret, data_cport);
+               return ret;
+       }
+       if (codec_state < GBAUDIO_CODEC_PREPARE) {
+               ret = gb_audio_apbridgea_set_rx_data_size(data->connection, 0,
+                                                         192);
+               if (ret) {
+                       dev_err(dev,
+                               "%d:Error during apbridgea_set_rx_data_size\n",
+                               ret);
+                       return ret;
+               }
+       }
+       ret = gb_audio_gb_activate_rx(module->mgmt_connection,
+                                     data_cport);
+       if (ret)
+               dev_err(dev, "%s:Error during activate stream,%d\n",
+                       module->name, ret);
+
+       return ret;
+}
+
 static int gbcodec_prepare(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        int ret;
-       uint16_t data_cport;
-       struct gbaudio_data_connection *data;
        struct gbaudio_module_info *module;
        int state;
+       struct gbaudio_data_connection *data;
        struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
 
        mutex_lock(&codec->lock);
@@ -623,71 +745,24 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream,
                        mutex_unlock(&module->lock);
                        continue;
                }
-               /* deactivate rx/tx */
-               data_cport = data->connection->intf_cport_id;
 
                switch (substream->stream) {
-               case SNDRV_PCM_STREAM_CAPTURE:
-                       ret = gb_audio_gb_set_rx_data_size(
-                                               module->mgmt_connection,
-                                               data_cport, 192);
-                       if (ret) {
-                               dev_err(dai->dev,
-                                       "%d:Error during set_rx_data_size, cport:%d\n",
-                                       ret, data_cport);
-                               mutex_unlock(&module->lock);
-                               goto func_exit;
-                       }
-                       if (state < GBAUDIO_CODEC_PREPARE) {
-                               ret = gb_audio_apbridgea_set_rx_data_size(
-                                                       data->connection, 0,
-                                                       192);
-                               if (ret) {
-                                       dev_err(dai->dev,
-                               "%d:Error during apbridgea_set_rx_data_size\n",
-                               ret);
-                                       mutex_unlock(&module->lock);
-                                       goto func_exit;
-                               }
-                       }
-                       ret = gb_audio_gb_activate_rx(module->mgmt_connection,
-                                                     data_cport);
-                       if (ret)
-                               dev_err(dai->dev,
-                                       "%s:Error during activate stream,%d\n",
-                                       module->name, ret);
-                       break;
                case SNDRV_PCM_STREAM_PLAYBACK:
-                       ret = gb_audio_gb_set_tx_data_size(
-                                               module->mgmt_connection,
-                                               data_cport, 192);
-                       if (ret) {
-                               dev_err(dai->dev,
-                                       "%d:Error during module set_tx_data_size, cport:%d\n",
-                                       ret, data_cport);
-                               mutex_unlock(&module->lock);
-                               goto func_exit;
-                       }
-                       if (state < GBAUDIO_CODEC_PREPARE) {
-                               ret = gb_audio_apbridgea_set_tx_data_size(
-                                                       data->connection, 0,
-                                                       192);
-                               if (ret) {
-                                       dev_err(dai->dev,
-                                               "%d:Error during apbridgea set_tx_data_size, cport\n",
-                                               ret);
-                                       mutex_unlock(&module->lock);
-                                       goto func_exit;
-                               }
-                       }
-                       ret = gb_audio_gb_activate_tx(module->mgmt_connection,
-                                                     data_cport);
-                       if (ret)
-                               dev_err(dai->dev,
-                                       "%s:Error during activate stream,%d\n",
-                                       module->name, ret);
+                       ret = gbmodule_prepare_tx(module, data, state,
+                                                 dai->dev);
+                       break;
+               case SNDRV_PCM_STREAM_CAPTURE:
+                       ret = gbmodule_prepare_rx(module, data, state,
+                                                 dai->dev);
                        break;
                }
+               if (ret == -ENODEV)
+                       continue;
+               if (ret) {
+                       mutex_unlock(&module->lock);
+                       goto func_exit;
+               }
+
                state = GBAUDIO_CODEC_PREPARE;
                module->ctrlstate[substream->stream] = state;
                dev_dbg(dai->dev, "%s: state:%d\n", module->name, state);
@@ -697,7 +772,7 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream,
 
 func_exit:
        mutex_unlock(&codec->lock);
-       return 0;
+       return ret;
 }
 
 static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd,