Commit 825315bc authored by Ian Minett's avatar Ian Minett Committed by Takashi Iwai

ALSA: hda/ca0132: Add PCM enhancements

Remove the playback PCM open callback.
PCM stream setup and cleanup functions are added for use by PCM callbacks.
Delay stream cleanup if effects are on, to allow time for any effects tail to
finish.
Add the analog capture PCM callbacks.
Change the max channels of analog playback to 6.
Add two new PCMs: AMic2 and What-U-Hear.
Signed-off-by: default avatarIan Minett <ian_minett@creativelabs.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent a7e76271
...@@ -2630,17 +2630,62 @@ static bool dspload_wait_loaded(struct hda_codec *codec) ...@@ -2630,17 +2630,62 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir) CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir)
/* /*
* PCM callbacks * PCM stuffs
*/ */
static int ca0132_playback_pcm_open(struct hda_pcm_stream *hinfo, static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid,
struct hda_codec *codec, u32 stream_tag,
struct snd_pcm_substream *substream) int channel_id, int format)
{ {
struct ca0132_spec *spec = codec->spec; unsigned int oldval, newval;
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
hinfo); if (!nid)
return;
snd_printdd(
"ca0132_setup_stream: NID=0x%x, stream=0x%x, "
"channel=%d, format=0x%x\n",
nid, stream_tag, channel_id, format);
/* update the format-id if changed */
oldval = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_STREAM_FORMAT,
0);
if (oldval != format) {
msleep(20);
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_STREAM_FORMAT,
format);
}
oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
newval = (stream_tag << 4) | channel_id;
if (oldval != newval) {
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_CHANNEL_STREAMID,
newval);
}
}
static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
{
unsigned int val;
if (!nid)
return;
snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid);
val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
if (!val)
return;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
} }
/*
* PCM callbacks
*/
static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec, struct hda_codec *codec,
unsigned int stream_tag, unsigned int stream_tag,
...@@ -2648,8 +2693,10 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -2648,8 +2693,10 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct ca0132_spec *spec = codec->spec; struct ca0132_spec *spec = codec->spec;
return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
stream_tag, format, substream); ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
return 0;
} }
static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
...@@ -2657,7 +2704,18 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, ...@@ -2657,7 +2704,18 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct ca0132_spec *spec = codec->spec; struct ca0132_spec *spec = codec->spec;
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
if (spec->dsp_state == DSP_DOWNLOADING)
return 0;
/*If Playback effects are on, allow stream some time to flush
*effects tail*/
if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
msleep(50);
ca0132_cleanup_stream(codec, spec->dacs[0]);
return 0;
} }
/* /*
...@@ -2698,6 +2756,36 @@ static int ca0132_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, ...@@ -2698,6 +2756,36 @@ static int ca0132_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_dig_close(codec, &spec->multiout); return snd_hda_multi_out_dig_close(codec, &spec->multiout);
} }
/*
* Analog capture
*/
static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct ca0132_spec *spec = codec->spec;
ca0132_setup_stream(codec, spec->adcs[substream->number],
stream_tag, 0, format);
return 0;
}
static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0132_spec *spec = codec->spec;
if (spec->dsp_state == DSP_DOWNLOADING)
return 0;
ca0132_cleanup_stream(codec, hinfo->nid);
return 0;
}
/* /*
* Select the active output. * Select the active output.
* If autodetect is enabled, output will be selected based on jack detection. * If autodetect is enabled, output will be selected based on jack detection.
...@@ -3509,9 +3597,8 @@ static struct snd_kcontrol_new ca0132_mixer[] = { ...@@ -3509,9 +3597,8 @@ static struct snd_kcontrol_new ca0132_mixer[] = {
static struct hda_pcm_stream ca0132_pcm_analog_playback = { static struct hda_pcm_stream ca0132_pcm_analog_playback = {
.substreams = 1, .substreams = 1,
.channels_min = 2, .channels_min = 2,
.channels_max = 2, .channels_max = 6,
.ops = { .ops = {
.open = ca0132_playback_pcm_open,
.prepare = ca0132_playback_pcm_prepare, .prepare = ca0132_playback_pcm_prepare,
.cleanup = ca0132_playback_pcm_cleanup .cleanup = ca0132_playback_pcm_cleanup
}, },
...@@ -3521,6 +3608,10 @@ static struct hda_pcm_stream ca0132_pcm_analog_capture = { ...@@ -3521,6 +3608,10 @@ static struct hda_pcm_stream ca0132_pcm_analog_capture = {
.substreams = 1, .substreams = 1,
.channels_min = 2, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
.ops = {
.prepare = ca0132_capture_pcm_prepare,
.cleanup = ca0132_capture_pcm_cleanup
},
}; };
static struct hda_pcm_stream ca0132_pcm_digital_playback = { static struct hda_pcm_stream ca0132_pcm_digital_playback = {
...@@ -3555,10 +3646,24 @@ static int ca0132_build_pcms(struct hda_codec *codec) ...@@ -3555,10 +3646,24 @@ static int ca0132_build_pcms(struct hda_codec *codec)
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
spec->multiout.max_channels; spec->multiout.max_channels;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
codec->num_pcms++; codec->num_pcms++;
info++;
info->name = "CA0132 Analog Mic-In2";
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1];
codec->num_pcms++;
info++;
info->name = "CA0132 What U Hear";
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2];
codec->num_pcms++;
if (!spec->dig_out && !spec->dig_in) if (!spec->dig_out && !spec->dig_in)
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment