@@ -141,6 +141,7 @@ struct hda_pcm_stream {
hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */
u32 rates; /* supported rates */
u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */
+ u32 subformats; /* for S32_LE format, SNDRV_PCM_SUBFMTBIT_* */
unsigned int maxbps; /* supported max. bit per sample */
const struct snd_pcm_chmap_elem *chmap; /* chmap to override */
struct hda_pcm_ops ops;
@@ -448,8 +449,8 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
#define snd_hda_codec_cleanup_stream(codec, nid) \
__snd_hda_codec_cleanup_stream(codec, nid, 0)
-#define snd_hda_query_supported_pcm(codec, nid, ratesp, fmtsp, bpsp) \
- snd_hdac_query_supported_pcm(&(codec)->core, nid, ratesp, fmtsp, bpsp)
+#define snd_hda_query_supported_pcm(codec, nid, ratesp, fmtsp, subfmtp, bpsp) \
+ snd_hdac_query_supported_pcm(&(codec)->core, nid, ratesp, fmtsp, subfmtp, bpsp)
#define snd_hda_is_supported_format(codec, nid, fmt) \
snd_hdac_is_supported_format(&(codec)->core, nid, fmt)
@@ -146,7 +146,8 @@ unsigned int snd_hdac_calc_stream_format(unsigned int rate,
unsigned int maxbps,
unsigned short spdif_ctls);
int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
- u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
+ u32 *ratesp, u64 *formatsp, u32 *subformatsp,
+ unsigned int *bpsp);
bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid,
unsigned int format);
@@ -817,15 +817,17 @@ static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid)
* @nid: NID to query
* @ratesp: the pointer to store the detected rate bitflags
* @formatsp: the pointer to store the detected formats
+ * @subformatsp: the pointer to store the detected subformats for S32_LE format
* @bpsp: the pointer to store the detected format widths
*
- * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp
- * or @bsps argument is ignored.
+ * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp,
+ * @subformatsp or @bpsp argument is ignored.
*
* Returns 0 if successful, otherwise a negative error code.
*/
int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
- u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
+ u32 *ratesp, u64 *formatsp, u32 *subformatsp,
+ unsigned int *bpsp)
{
unsigned int i, val, wcaps;
@@ -848,9 +850,10 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
*ratesp = rates;
}
- if (formatsp || bpsp) {
- u64 formats = 0;
+ if (formatsp || subformatsp || bpsp) {
unsigned int streams, bps;
+ u32 subformats = 0;
+ u64 formats = 0;
streams = query_stream_param(codec, nid);
if (!streams)
@@ -866,24 +869,24 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
formats |= SNDRV_PCM_FMTBIT_S16_LE;
bps = 16;
}
- if (wcaps & AC_WCAP_DIGITAL) {
- if (val & AC_SUPPCM_BITS_32)
+ if (val & AC_SUPPCM_BITS_20) {
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_20;
+ bps = 20;
+ }
+ if (val & AC_SUPPCM_BITS_24) {
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_24;
+ bps = 24;
+ }
+ if (val & AC_SUPPCM_BITS_32) {
+ if (wcaps & AC_WCAP_DIGITAL) {
formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
- if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24))
+ } else {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
- if (val & AC_SUPPCM_BITS_24)
- bps = 24;
- else if (val & AC_SUPPCM_BITS_20)
- bps = 20;
- } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24|
- AC_SUPPCM_BITS_32)) {
- formats |= SNDRV_PCM_FMTBIT_S32_LE;
- if (val & AC_SUPPCM_BITS_32)
+ subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_MAX;
bps = 32;
- else if (val & AC_SUPPCM_BITS_24)
- bps = 24;
- else if (val & AC_SUPPCM_BITS_20)
- bps = 20;
+ }
}
}
#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */
@@ -911,6 +914,8 @@ int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
}
if (formatsp)
*formatsp = formats;
+ if (subformatsp)
+ *subformatsp = subformats;
if (bpsp)
*bpsp = bps;
}
@@ -3163,6 +3163,7 @@ static int set_pcm_default_values(struct hda_codec *codec,
err = snd_hda_query_supported_pcm(codec, info->nid,
info->rates ? NULL : &info->rates,
info->formats ? NULL : &info->formats,
+ info->subformats ? NULL : &info->subformats,
info->maxbps ? NULL : &info->maxbps);
if (err < 0)
return err;
@@ -3757,6 +3758,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
snd_hda_query_supported_pcm(codec, mout->dig_out_nid,
&mout->spdif_rates,
&mout->spdif_formats,
+ NULL,
&mout->spdif_maxbps);
}
mutex_lock(&codec->spdif_mutex);
@@ -1977,6 +1977,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
err = snd_hda_query_supported_pcm(codec, cvt_nid,
&per_cvt->rates,
&per_cvt->formats,
+ NULL,
&per_cvt->maxbps);
if (err < 0)
return err;
@@ -670,6 +670,7 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdev, struct hdac_hdmi_cvt *cvt)
err = snd_hdac_query_supported_pcm(hdev, cvt->nid,
&cvt->params.rates,
&cvt->params.formats,
+ NULL,
&cvt->params.maxbps);
if (err < 0)
dev_err(&hdev->dev,
@@ -1577,7 +1578,7 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev,
list_for_each_entry(cvt, &hdmi->cvt_list, head) {
ret = snd_hdac_query_supported_pcm(hdev, cvt->nid,
- &rates, &formats, &bps);
+ &rates, &formats, NULL, &bps);
if (ret)
return ret;