ALSA: hda - Add pcm_playback_hook to hda_gen_spec
authorTakashi Iwai <tiwai@suse.de>
Mon, 7 Jan 2013 10:54:34 +0000 (11:54 +0100)
committerTakashi Iwai <tiwai@suse.de>
Sat, 12 Jan 2013 07:43:52 +0000 (08:43 +0100)
The new hook which is called at each PCM playback ops.
It can be used to control the codec-specific power-saving feature in
each codec driver.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h

index 296628b..28ad5e9 100644 (file)
@@ -3261,6 +3261,16 @@ EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls);
  * PCM definitions
  */
 
+static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream,
+                                  int action)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->pcm_playback_hook)
+               spec->pcm_playback_hook(hinfo, codec, substream, action);
+}
+
 /*
  * Analog playback callbacks
  */
@@ -3275,8 +3285,11 @@ static int playback_pcm_open(struct hda_pcm_stream *hinfo,
        err = snd_hda_multi_out_analog_open(codec,
                                            &spec->multiout, substream,
                                             hinfo);
-       if (!err)
+       if (!err) {
                spec->active_streams |= 1 << STREAM_MULTI_OUT;
+               call_pcm_playback_hook(hinfo, codec, substream,
+                                      HDA_GEN_PCM_ACT_OPEN);
+       }
        mutex_unlock(&spec->pcm_mutex);
        return err;
 }
@@ -3288,8 +3301,14 @@ static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                struct snd_pcm_substream *substream)
 {
        struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
-                                               stream_tag, format, substream);
+       int err;
+
+       err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+                                              stream_tag, format, substream);
+       if (!err)
+               call_pcm_playback_hook(hinfo, codec, substream,
+                                      HDA_GEN_PCM_ACT_PREPARE);
+       return err;
 }
 
 static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
@@ -3297,7 +3316,13 @@ static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
                                struct snd_pcm_substream *substream)
 {
        struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+       int err;
+
+       err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+       if (!err)
+               call_pcm_playback_hook(hinfo, codec, substream,
+                                      HDA_GEN_PCM_ACT_CLEANUP);
+       return err;
 }
 
 static int playback_pcm_close(struct hda_pcm_stream *hinfo,
@@ -3307,6 +3332,8 @@ static int playback_pcm_close(struct hda_pcm_stream *hinfo,
        struct hda_gen_spec *spec = codec->spec;
        mutex_lock(&spec->pcm_mutex);
        spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_CLOSE);
        mutex_unlock(&spec->pcm_mutex);
        return 0;
 }
@@ -3323,6 +3350,8 @@ static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
                err = -EBUSY;
        else
                spec->active_streams |= 1 << STREAM_INDEP_HP;
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_OPEN);
        mutex_unlock(&spec->pcm_mutex);
        return err;
 }
@@ -3334,10 +3363,34 @@ static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
        struct hda_gen_spec *spec = codec->spec;
        mutex_lock(&spec->pcm_mutex);
        spec->active_streams &= ~(1 << STREAM_INDEP_HP);
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_CLOSE);
        mutex_unlock(&spec->pcm_mutex);
        return 0;
 }
 
+static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   unsigned int stream_tag,
+                                   unsigned int format,
+                                   struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_PREPARE);
+       return 0;
+}
+
+static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_CLEANUP);
+       return 0;
+}
+
 /*
  * Digital out
  */
@@ -3432,7 +3485,9 @@ static const struct hda_pcm_stream pcm_analog_alt_playback = {
        /* NID is set in build_pcms */
        .ops = {
                .open = alt_playback_pcm_open,
-               .close = alt_playback_pcm_close
+               .close = alt_playback_pcm_close,
+               .prepare = alt_playback_pcm_prepare,
+               .cleanup = alt_playback_pcm_cleanup
        },
 };
 
index 4c0d9ad..7e84c22 100644 (file)
@@ -69,6 +69,14 @@ struct automic_entry {
 /* active stream id */
 enum { STREAM_MULTI_OUT, STREAM_INDEP_HP };
 
+/* PCM hook action */
+enum {
+       HDA_GEN_PCM_ACT_OPEN,
+       HDA_GEN_PCM_ACT_PREPARE,
+       HDA_GEN_PCM_ACT_CLEANUP,
+       HDA_GEN_PCM_ACT_CLOSE,
+};
+
 struct hda_gen_spec {
        char stream_name_analog[32];    /* analog PCM stream */
        const struct hda_pcm_stream *stream_analog_playback;
@@ -191,6 +199,12 @@ struct hda_gen_spec {
        void (*automute_hook)(struct hda_codec *codec);
        void (*cap_sync_hook)(struct hda_codec *codec);
 
+       /* PCM playback hook */
+       void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream,
+                                 int action);
+
        /* automute / autoswitch hooks */
        void (*hp_automute_hook)(struct hda_codec *codec,
                                 struct hda_jack_tbl *tbl);