diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-06-18 10:40:14 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-06-20 10:24:05 -0400 |
commit | 7eb56e84e6c4deaa552db96834ea0b233ba92f50 (patch) | |
tree | e9904734cc9d14f23b2cd05568d3a7292fcd3023 /sound/pci/hda/patch_via.c | |
parent | 9af7421091fd37a2f8c35ca8b3a5f78a6f20fa89 (diff) |
ALSA: hda - Assign HP-independent PCM to individual stream
Instead of using the secondary substream, create an individual PCM
stream for HP-independent PCM. Otherwise it's difficult to handle
different channel numbers with multi-channel stream in the sam PCM
stream structure.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r-- | sound/pci/hda/patch_via.c | 144 |
1 files changed, 91 insertions, 53 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 18f2a135c026..264889c9c177 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -122,6 +122,7 @@ struct via_spec { | |||
122 | unsigned int num_iverbs; | 122 | unsigned int num_iverbs; |
123 | 123 | ||
124 | char stream_name_analog[32]; | 124 | char stream_name_analog[32]; |
125 | char stream_name_hp[32]; | ||
125 | const struct hda_pcm_stream *stream_analog_playback; | 126 | const struct hda_pcm_stream *stream_analog_playback; |
126 | const struct hda_pcm_stream *stream_analog_capture; | 127 | const struct hda_pcm_stream *stream_analog_capture; |
127 | 128 | ||
@@ -1210,14 +1211,20 @@ static const struct hda_verb vt1708_volume_init_verbs[] = { | |||
1210 | { } | 1211 | { } |
1211 | }; | 1212 | }; |
1212 | 1213 | ||
1214 | static void substream_set_idle(struct hda_codec *codec, | ||
1215 | struct snd_pcm_substream *substream) | ||
1216 | { | ||
1217 | int idle = substream->pstr->substream_opened == 1 | ||
1218 | && substream->ref_count == 0; | ||
1219 | analog_low_current_mode(codec, idle); | ||
1220 | } | ||
1221 | |||
1213 | static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, | 1222 | static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, |
1214 | struct hda_codec *codec, | 1223 | struct hda_codec *codec, |
1215 | struct snd_pcm_substream *substream) | 1224 | struct snd_pcm_substream *substream) |
1216 | { | 1225 | { |
1217 | struct via_spec *spec = codec->spec; | 1226 | struct via_spec *spec = codec->spec; |
1218 | int idle = substream->pstr->substream_opened == 1 | 1227 | substream_set_idle(codec, substream); |
1219 | && substream->ref_count == 0; | ||
1220 | analog_low_current_mode(codec, idle); | ||
1221 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, | 1228 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, |
1222 | hinfo); | 1229 | hinfo); |
1223 | } | 1230 | } |
@@ -1226,17 +1233,29 @@ static int via_playback_pcm_close(struct hda_pcm_stream *hinfo, | |||
1226 | struct hda_codec *codec, | 1233 | struct hda_codec *codec, |
1227 | struct snd_pcm_substream *substream) | 1234 | struct snd_pcm_substream *substream) |
1228 | { | 1235 | { |
1229 | int idle = substream->pstr->substream_opened == 1 | 1236 | substream_set_idle(codec, substream); |
1230 | && substream->ref_count == 0; | 1237 | return 0; |
1238 | } | ||
1231 | 1239 | ||
1232 | analog_low_current_mode(codec, idle); | 1240 | static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, |
1241 | struct hda_codec *codec, | ||
1242 | struct snd_pcm_substream *substream) | ||
1243 | { | ||
1244 | struct via_spec *spec = codec->spec; | ||
1245 | struct hda_multi_out *mout = &spec->multiout; | ||
1246 | |||
1247 | if (!mout->hp_nid || mout->hp_nid == mout->dac_nids[HDA_FRONT] || | ||
1248 | !spec->hp_independent_mode) | ||
1249 | return -EINVAL; | ||
1250 | substream_set_idle(codec, substream); | ||
1233 | return 0; | 1251 | return 0; |
1234 | } | 1252 | } |
1235 | 1253 | ||
1236 | static void playback_multi_pcm_prep_0(struct hda_codec *codec, | 1254 | static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, |
1237 | unsigned int stream_tag, | 1255 | struct hda_codec *codec, |
1238 | unsigned int format, | 1256 | unsigned int stream_tag, |
1239 | struct snd_pcm_substream *substream) | 1257 | unsigned int format, |
1258 | struct snd_pcm_substream *substream) | ||
1240 | { | 1259 | { |
1241 | struct via_spec *spec = codec->spec; | 1260 | struct via_spec *spec = codec->spec; |
1242 | struct hda_multi_out *mout = &spec->multiout; | 1261 | struct hda_multi_out *mout = &spec->multiout; |
@@ -1301,27 +1320,20 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec, | |||
1301 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, | 1320 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, |
1302 | 0, format); | 1321 | 0, format); |
1303 | } | 1322 | } |
1323 | vt1708_start_hp_work(spec); | ||
1324 | return 0; | ||
1304 | } | 1325 | } |
1305 | 1326 | ||
1306 | static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, | 1327 | static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo, |
1307 | struct hda_codec *codec, | 1328 | struct hda_codec *codec, |
1308 | unsigned int stream_tag, | 1329 | unsigned int stream_tag, |
1309 | unsigned int format, | 1330 | unsigned int format, |
1310 | struct snd_pcm_substream *substream) | 1331 | struct snd_pcm_substream *substream) |
1311 | { | 1332 | { |
1312 | struct via_spec *spec = codec->spec; | 1333 | struct via_spec *spec = codec->spec; |
1313 | struct hda_multi_out *mout = &spec->multiout; | 1334 | struct hda_multi_out *mout = &spec->multiout; |
1314 | const hda_nid_t *nids = mout->dac_nids; | ||
1315 | 1335 | ||
1316 | if (substream->number == 0) | 1336 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); |
1317 | playback_multi_pcm_prep_0(codec, stream_tag, format, | ||
1318 | substream); | ||
1319 | else { | ||
1320 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && | ||
1321 | spec->hp_independent_mode) | ||
1322 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | ||
1323 | stream_tag, 0, format); | ||
1324 | } | ||
1325 | vt1708_start_hp_work(spec); | 1337 | vt1708_start_hp_work(spec); |
1326 | return 0; | 1338 | return 0; |
1327 | } | 1339 | } |
@@ -1335,33 +1347,38 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
1335 | const hda_nid_t *nids = mout->dac_nids; | 1347 | const hda_nid_t *nids = mout->dac_nids; |
1336 | int i; | 1348 | int i; |
1337 | 1349 | ||
1338 | if (substream->number == 0) { | 1350 | for (i = 0; i < mout->num_dacs; i++) |
1339 | for (i = 0; i < mout->num_dacs; i++) | 1351 | snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); |
1340 | snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); | ||
1341 | 1352 | ||
1342 | if (mout->hp_nid && !spec->hp_independent_mode) | 1353 | if (mout->hp_nid && !spec->hp_independent_mode) |
1343 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | 1354 | snd_hda_codec_setup_stream(codec, mout->hp_nid, |
1344 | 0, 0, 0); | 1355 | 0, 0, 0); |
1345 | 1356 | ||
1346 | for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) | 1357 | for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) |
1347 | if (mout->extra_out_nid[i]) | 1358 | if (mout->extra_out_nid[i]) |
1348 | snd_hda_codec_setup_stream(codec, | 1359 | snd_hda_codec_setup_stream(codec, |
1349 | mout->extra_out_nid[i], | 1360 | mout->extra_out_nid[i], |
1350 | 0, 0, 0); | ||
1351 | mutex_lock(&codec->spdif_mutex); | ||
1352 | if (mout->dig_out_nid && | ||
1353 | mout->dig_out_used == HDA_DIG_ANALOG_DUP) { | ||
1354 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
1355 | 0, 0, 0); | ||
1356 | mout->dig_out_used = 0; | ||
1357 | } | ||
1358 | mutex_unlock(&codec->spdif_mutex); | ||
1359 | } else { | ||
1360 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && | ||
1361 | spec->hp_independent_mode) | ||
1362 | snd_hda_codec_setup_stream(codec, mout->hp_nid, | ||
1363 | 0, 0, 0); | 1361 | 0, 0, 0); |
1362 | mutex_lock(&codec->spdif_mutex); | ||
1363 | if (mout->dig_out_nid && | ||
1364 | mout->dig_out_used == HDA_DIG_ANALOG_DUP) { | ||
1365 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
1366 | 0, 0, 0); | ||
1367 | mout->dig_out_used = 0; | ||
1364 | } | 1368 | } |
1369 | mutex_unlock(&codec->spdif_mutex); | ||
1370 | vt1708_stop_hp_work(spec); | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
1375 | struct hda_codec *codec, | ||
1376 | struct snd_pcm_substream *substream) | ||
1377 | { | ||
1378 | struct via_spec *spec = codec->spec; | ||
1379 | struct hda_multi_out *mout = &spec->multiout; | ||
1380 | |||
1381 | snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0); | ||
1365 | vt1708_stop_hp_work(spec); | 1382 | vt1708_stop_hp_work(spec); |
1366 | return 0; | 1383 | return 0; |
1367 | } | 1384 | } |
@@ -1431,7 +1448,7 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
1431 | } | 1448 | } |
1432 | 1449 | ||
1433 | static const struct hda_pcm_stream via_pcm_analog_playback = { | 1450 | static const struct hda_pcm_stream via_pcm_analog_playback = { |
1434 | .substreams = 2, /* will be changed in via_build_pcms() */ | 1451 | .substreams = 1, |
1435 | .channels_min = 2, | 1452 | .channels_min = 2, |
1436 | .channels_max = 8, | 1453 | .channels_max = 8, |
1437 | /* NID is set in via_build_pcms */ | 1454 | /* NID is set in via_build_pcms */ |
@@ -1443,8 +1460,21 @@ static const struct hda_pcm_stream via_pcm_analog_playback = { | |||
1443 | }, | 1460 | }, |
1444 | }; | 1461 | }; |
1445 | 1462 | ||
1463 | static const struct hda_pcm_stream via_pcm_hp_playback = { | ||
1464 | .substreams = 1, | ||
1465 | .channels_min = 2, | ||
1466 | .channels_max = 2, | ||
1467 | /* NID is set in via_build_pcms */ | ||
1468 | .ops = { | ||
1469 | .open = via_playback_hp_pcm_open, | ||
1470 | .close = via_playback_pcm_close, | ||
1471 | .prepare = via_playback_hp_pcm_prepare, | ||
1472 | .cleanup = via_playback_hp_pcm_cleanup | ||
1473 | }, | ||
1474 | }; | ||
1475 | |||
1446 | static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { | 1476 | static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { |
1447 | .substreams = 2, /* will be changed in via_build_pcms() */ | 1477 | .substreams = 1, |
1448 | .channels_min = 2, | 1478 | .channels_min = 2, |
1449 | .channels_max = 8, | 1479 | .channels_max = 8, |
1450 | /* NID is set in via_build_pcms */ | 1480 | /* NID is set in via_build_pcms */ |
@@ -1462,7 +1492,7 @@ static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { | |||
1462 | }; | 1492 | }; |
1463 | 1493 | ||
1464 | static const struct hda_pcm_stream via_pcm_analog_capture = { | 1494 | static const struct hda_pcm_stream via_pcm_analog_capture = { |
1465 | .substreams = 2, /* will be changed in via_build_pcms() */ | 1495 | .substreams = 1, /* will be changed in via_build_pcms() */ |
1466 | .channels_min = 2, | 1496 | .channels_min = 2, |
1467 | .channels_max = 2, | 1497 | .channels_max = 2, |
1468 | /* NID is set in via_build_pcms */ | 1498 | /* NID is set in via_build_pcms */ |
@@ -1577,8 +1607,6 @@ static int via_build_pcms(struct hda_codec *codec) | |||
1577 | spec->multiout.dac_nids[0]; | 1607 | spec->multiout.dac_nids[0]; |
1578 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = | 1608 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = |
1579 | spec->multiout.max_channels; | 1609 | spec->multiout.max_channels; |
1580 | if (!spec->multiout.hp_nid) | ||
1581 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams = 1; | ||
1582 | 1610 | ||
1583 | if (!spec->stream_analog_capture) | 1611 | if (!spec->stream_analog_capture) |
1584 | spec->stream_analog_capture = &via_pcm_analog_capture; | 1612 | spec->stream_analog_capture = &via_pcm_analog_capture; |
@@ -1616,6 +1644,16 @@ static int via_build_pcms(struct hda_codec *codec) | |||
1616 | } | 1644 | } |
1617 | } | 1645 | } |
1618 | 1646 | ||
1647 | if (spec->multiout.hp_nid) { | ||
1648 | codec->num_pcms++; | ||
1649 | info++; | ||
1650 | snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp), | ||
1651 | "%s HP", codec->chip_name); | ||
1652 | info->name = spec->stream_name_hp; | ||
1653 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback; | ||
1654 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | ||
1655 | spec->multiout.hp_nid; | ||
1656 | } | ||
1619 | return 0; | 1657 | return 0; |
1620 | } | 1658 | } |
1621 | 1659 | ||