|
@@ -1053,6 +1053,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
|
|
|
/* FIXME: more better hash key? */
|
|
|
#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
|
|
|
#define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
|
|
|
+#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
|
|
|
+#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
|
|
|
#define INFO_AMP_CAPS (1<<0)
|
|
|
#define INFO_AMP_VOL(ch) (1 << (1 + (ch)))
|
|
|
|
|
@@ -1143,19 +1145,32 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
|
|
|
}
|
|
|
EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
|
|
|
|
|
|
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+static unsigned int
|
|
|
+query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
|
|
|
+ unsigned int (*func)(struct hda_codec *, hda_nid_t))
|
|
|
{
|
|
|
struct hda_amp_info *info;
|
|
|
|
|
|
- info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
|
|
|
+ info = get_alloc_amp_hash(codec, key);
|
|
|
if (!info)
|
|
|
return 0;
|
|
|
if (!info->head.val) {
|
|
|
- info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
|
|
|
info->head.val |= INFO_AMP_CAPS;
|
|
|
+ info->amp_caps = func(codec, nid);
|
|
|
}
|
|
|
return info->amp_caps;
|
|
|
}
|
|
|
+
|
|
|
+static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+{
|
|
|
+ return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
|
|
|
+}
|
|
|
+
|
|
|
+u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+{
|
|
|
+ return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
|
|
|
+ read_pin_cap);
|
|
|
+}
|
|
|
EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
|
|
|
|
|
|
/*
|
|
@@ -2538,6 +2553,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
|
|
|
}
|
|
|
EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
|
|
|
|
|
|
+static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+{
|
|
|
+ unsigned int val = 0;
|
|
|
+ if (nid != codec->afg &&
|
|
|
+ (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
|
|
|
+ val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
|
|
|
+ if (!val || val == -1)
|
|
|
+ val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
|
|
|
+ if (!val || val == -1)
|
|
|
+ return 0;
|
|
|
+ return val;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+{
|
|
|
+ return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
|
|
|
+ get_pcm_param);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+{
|
|
|
+ unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
|
|
|
+ if (!streams || streams == -1)
|
|
|
+ streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
|
|
|
+ if (!streams || streams == -1)
|
|
|
+ return 0;
|
|
|
+ return streams;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+{
|
|
|
+ return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
|
|
|
+ get_stream_param);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* snd_hda_query_supported_pcm - query the supported PCM rates and formats
|
|
|
* @codec: the HDA codec
|
|
@@ -2556,15 +2606,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
|
|
{
|
|
|
unsigned int i, val, wcaps;
|
|
|
|
|
|
- val = 0;
|
|
|
wcaps = get_wcaps(codec, nid);
|
|
|
- if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) {
|
|
|
- val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
|
|
|
- if (val == -1)
|
|
|
- return -EIO;
|
|
|
- }
|
|
|
- if (!val)
|
|
|
- val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
|
|
|
+ val = query_pcm_param(codec, nid);
|
|
|
|
|
|
if (ratesp) {
|
|
|
u32 rates = 0;
|
|
@@ -2586,15 +2629,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
|
|
u64 formats = 0;
|
|
|
unsigned int streams, bps;
|
|
|
|
|
|
- streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
|
|
|
- if (streams == -1)
|
|
|
+ streams = query_stream_param(codec, nid);
|
|
|
+ if (!streams)
|
|
|
return -EIO;
|
|
|
- if (!streams) {
|
|
|
- streams = snd_hda_param_read(codec, codec->afg,
|
|
|
- AC_PAR_STREAM);
|
|
|
- if (streams == -1)
|
|
|
- return -EIO;
|
|
|
- }
|
|
|
|
|
|
bps = 0;
|
|
|
if (streams & AC_SUPFMT_PCM) {
|
|
@@ -2668,17 +2705,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
|
|
|
int i;
|
|
|
unsigned int val = 0, rate, stream;
|
|
|
|
|
|
- if (nid != codec->afg &&
|
|
|
- (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
|
|
|
- val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
|
|
|
- if (val == -1)
|
|
|
- return 0;
|
|
|
- }
|
|
|
- if (!val) {
|
|
|
- val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
|
|
|
- if (val == -1)
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ val = query_pcm_param(codec, nid);
|
|
|
+ if (!val)
|
|
|
+ return 0;
|
|
|
|
|
|
rate = format & 0xff00;
|
|
|
for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++)
|
|
@@ -2690,12 +2719,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
|
|
|
if (i >= AC_PAR_PCM_RATE_BITS)
|
|
|
return 0;
|
|
|
|
|
|
- stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
|
|
|
- if (stream == -1)
|
|
|
- return 0;
|
|
|
- if (!stream && nid != codec->afg)
|
|
|
- stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
|
|
|
- if (!stream || stream == -1)
|
|
|
+ stream = query_stream_param(codec, nid);
|
|
|
+ if (!stream)
|
|
|
return 0;
|
|
|
|
|
|
if (stream & AC_SUPFMT_PCM) {
|