ALSA: hda - Add pcm_playback_hook to hda_gen_spec
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>
This commit is contained in:
@ -3261,6 +3261,16 @@ EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls);
|
|||||||
* PCM definitions
|
* 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
|
* 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,
|
err = snd_hda_multi_out_analog_open(codec,
|
||||||
&spec->multiout, substream,
|
&spec->multiout, substream,
|
||||||
hinfo);
|
hinfo);
|
||||||
if (!err)
|
if (!err) {
|
||||||
spec->active_streams |= 1 << STREAM_MULTI_OUT;
|
spec->active_streams |= 1 << STREAM_MULTI_OUT;
|
||||||
|
call_pcm_playback_hook(hinfo, codec, substream,
|
||||||
|
HDA_GEN_PCM_ACT_OPEN);
|
||||||
|
}
|
||||||
mutex_unlock(&spec->pcm_mutex);
|
mutex_unlock(&spec->pcm_mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -3288,8 +3301,14 @@ static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|||||||
struct snd_pcm_substream *substream)
|
struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct hda_gen_spec *spec = codec->spec;
|
struct hda_gen_spec *spec = codec->spec;
|
||||||
return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
|
int err;
|
||||||
stream_tag, format, substream);
|
|
||||||
|
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,
|
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 snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct hda_gen_spec *spec = codec->spec;
|
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,
|
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;
|
struct hda_gen_spec *spec = codec->spec;
|
||||||
mutex_lock(&spec->pcm_mutex);
|
mutex_lock(&spec->pcm_mutex);
|
||||||
spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
|
spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
|
||||||
|
call_pcm_playback_hook(hinfo, codec, substream,
|
||||||
|
HDA_GEN_PCM_ACT_CLOSE);
|
||||||
mutex_unlock(&spec->pcm_mutex);
|
mutex_unlock(&spec->pcm_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3323,6 +3350,8 @@ static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
|||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
else
|
else
|
||||||
spec->active_streams |= 1 << STREAM_INDEP_HP;
|
spec->active_streams |= 1 << STREAM_INDEP_HP;
|
||||||
|
call_pcm_playback_hook(hinfo, codec, substream,
|
||||||
|
HDA_GEN_PCM_ACT_OPEN);
|
||||||
mutex_unlock(&spec->pcm_mutex);
|
mutex_unlock(&spec->pcm_mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -3334,10 +3363,34 @@ static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
|||||||
struct hda_gen_spec *spec = codec->spec;
|
struct hda_gen_spec *spec = codec->spec;
|
||||||
mutex_lock(&spec->pcm_mutex);
|
mutex_lock(&spec->pcm_mutex);
|
||||||
spec->active_streams &= ~(1 << STREAM_INDEP_HP);
|
spec->active_streams &= ~(1 << STREAM_INDEP_HP);
|
||||||
|
call_pcm_playback_hook(hinfo, codec, substream,
|
||||||
|
HDA_GEN_PCM_ACT_CLOSE);
|
||||||
mutex_unlock(&spec->pcm_mutex);
|
mutex_unlock(&spec->pcm_mutex);
|
||||||
return 0;
|
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
|
* Digital out
|
||||||
*/
|
*/
|
||||||
@ -3432,7 +3485,9 @@ static const struct hda_pcm_stream pcm_analog_alt_playback = {
|
|||||||
/* NID is set in build_pcms */
|
/* NID is set in build_pcms */
|
||||||
.ops = {
|
.ops = {
|
||||||
.open = alt_playback_pcm_open,
|
.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
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,6 +69,14 @@ struct automic_entry {
|
|||||||
/* active stream id */
|
/* active stream id */
|
||||||
enum { STREAM_MULTI_OUT, STREAM_INDEP_HP };
|
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 {
|
struct hda_gen_spec {
|
||||||
char stream_name_analog[32]; /* analog PCM stream */
|
char stream_name_analog[32]; /* analog PCM stream */
|
||||||
const struct hda_pcm_stream *stream_analog_playback;
|
const struct hda_pcm_stream *stream_analog_playback;
|
||||||
@ -191,6 +199,12 @@ struct hda_gen_spec {
|
|||||||
void (*automute_hook)(struct hda_codec *codec);
|
void (*automute_hook)(struct hda_codec *codec);
|
||||||
void (*cap_sync_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 */
|
/* automute / autoswitch hooks */
|
||||||
void (*hp_automute_hook)(struct hda_codec *codec,
|
void (*hp_automute_hook)(struct hda_codec *codec,
|
||||||
struct hda_jack_tbl *tbl);
|
struct hda_jack_tbl *tbl);
|
||||||
|
Reference in New Issue
Block a user