aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/hdaudio.h3
-rw-r--r--sound/hda/hdac_device.c23
-rw-r--r--sound/hda/hdac_regmap.c8
-rw-r--r--sound/pci/hda/hda_codec.c144
-rw-r--r--sound/pci/hda/hda_codec.h7
-rw-r--r--sound/pci/hda/hda_local.h38
6 files changed, 82 insertions, 141 deletions
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 65ea6429f3a7..ce7d8d1f59c6 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -76,6 +76,7 @@ struct hdac_device {
76 /* regmap */ 76 /* regmap */
77 struct regmap *regmap; 77 struct regmap *regmap;
78 bool lazy_cache:1; /* don't wake up for writes */ 78 bool lazy_cache:1; /* don't wake up for writes */
79 bool caps_overwriting:1; /* caps overwrite being in process */
79}; 80};
80 81
81/* device/driver type used for matching */ 82/* device/driver type used for matching */
@@ -109,6 +110,8 @@ int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
109 unsigned int *res); 110 unsigned int *res);
110int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, 111int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
111 int parm); 112 int parm);
113int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
114 unsigned int parm, unsigned int val);
112int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, 115int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
113 hda_nid_t *conn_list, int max_conns); 116 hda_nid_t *conn_list, int max_conns);
114int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, 117int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index 0dac746df7da..72c584eb011b 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -273,6 +273,29 @@ int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
273EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); 273EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached);
274 274
275/** 275/**
276 * snd_hdac_override_parm - override read-only parameters
277 * @codec: the codec object
278 * @nid: NID for the parameter
279 * @parm: the parameter to change
280 * @val: the parameter value to overwrite
281 */
282int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
283 unsigned int parm, unsigned int val)
284{
285 unsigned int verb = (AC_VERB_PARAMETERS << 8) | (nid << 20) | parm;
286 int err;
287
288 if (!codec->regmap)
289 return -EINVAL;
290
291 codec->caps_overwriting = true;
292 err = snd_hdac_regmap_write_raw(codec, verb, val);
293 codec->caps_overwriting = false;
294 return err;
295}
296EXPORT_SYMBOL_GPL(snd_hdac_override_parm);
297
298/**
276 * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes 299 * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes
277 * @codec: the codec object 300 * @codec: the codec object
278 * @nid: NID to inspect 301 * @nid: NID to inspect
diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c
index db03d60d9c99..933907b16457 100644
--- a/sound/hda/hdac_regmap.c
+++ b/sound/hda/hdac_regmap.c
@@ -58,8 +58,12 @@ static bool hda_volatile_reg(struct device *dev, unsigned int reg)
58 58
59static bool hda_writeable_reg(struct device *dev, unsigned int reg) 59static bool hda_writeable_reg(struct device *dev, unsigned int reg)
60{ 60{
61 struct hdac_device *codec = dev_to_hdac_dev(dev);
61 unsigned int verb = get_verb(reg); 62 unsigned int verb = get_verb(reg);
62 63
64 if (codec->caps_overwriting)
65 return true;
66
63 switch (verb & 0xf00) { 67 switch (verb & 0xf00) {
64 case AC_VERB_GET_STREAM_FORMAT: 68 case AC_VERB_GET_STREAM_FORMAT:
65 case AC_VERB_GET_AMP_GAIN_MUTE: 69 case AC_VERB_GET_AMP_GAIN_MUTE:
@@ -97,8 +101,12 @@ static bool hda_writeable_reg(struct device *dev, unsigned int reg)
97 101
98static bool hda_readable_reg(struct device *dev, unsigned int reg) 102static bool hda_readable_reg(struct device *dev, unsigned int reg)
99{ 103{
104 struct hdac_device *codec = dev_to_hdac_dev(dev);
100 unsigned int verb = get_verb(reg); 105 unsigned int verb = get_verb(reg);
101 106
107 if (codec->caps_overwriting)
108 return true;
109
102 switch (verb) { 110 switch (verb) {
103 case AC_VERB_PARAMETERS: 111 case AC_VERB_PARAMETERS:
104 case AC_VERB_GET_CONNECT_LIST: 112 case AC_VERB_GET_CONNECT_LIST:
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 52962f697825..b27f250088c1 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -929,9 +929,7 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
929 codec->proc_widget_hook = NULL; 929 codec->proc_widget_hook = NULL;
930 codec->spec = NULL; 930 codec->spec = NULL;
931 931
932 free_hda_cache(&codec->amp_cache);
933 free_hda_cache(&codec->cmd_cache); 932 free_hda_cache(&codec->cmd_cache);
934 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
935 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); 933 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
936 934
937 /* free only driver_pins so that init_pins + user_pins are restored */ 935 /* free only driver_pins so that init_pins + user_pins are restored */
@@ -996,7 +994,6 @@ static void snd_hda_codec_dev_release(struct device *dev)
996 free_init_pincfgs(codec); 994 free_init_pincfgs(codec);
997 snd_hdac_device_exit(&codec->core); 995 snd_hdac_device_exit(&codec->core);
998 snd_hda_sysfs_clear(codec); 996 snd_hda_sysfs_clear(codec);
999 free_hda_cache(&codec->amp_cache);
1000 free_hda_cache(&codec->cmd_cache); 997 free_hda_cache(&codec->cmd_cache);
1001 kfree(codec->modelname); 998 kfree(codec->modelname);
1002 kfree(codec->wcaps); 999 kfree(codec->wcaps);
@@ -1051,7 +1048,6 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
1051 mutex_init(&codec->spdif_mutex); 1048 mutex_init(&codec->spdif_mutex);
1052 mutex_init(&codec->control_mutex); 1049 mutex_init(&codec->control_mutex);
1053 mutex_init(&codec->hash_mutex); 1050 mutex_init(&codec->hash_mutex);
1054 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
1055 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); 1051 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
1056 snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); 1052 snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
1057 snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); 1053 snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
@@ -1380,67 +1376,6 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache,
1380 return info; 1376 return info;
1381} 1377}
1382 1378
1383/* query and allocate an amp hash entry */
1384static inline struct hda_amp_info *
1385get_alloc_amp_hash(struct hda_codec *codec, u32 key)
1386{
1387 return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key);
1388}
1389
1390/* overwrite the value with the key in the caps hash */
1391static int write_caps_hash(struct hda_codec *codec, u32 key, unsigned int val)
1392{
1393 struct hda_amp_info *info;
1394
1395 mutex_lock(&codec->hash_mutex);
1396 info = get_alloc_amp_hash(codec, key);
1397 if (!info) {
1398 mutex_unlock(&codec->hash_mutex);
1399 return -EINVAL;
1400 }
1401 info->amp_caps = val;
1402 info->head.val |= INFO_AMP_CAPS;
1403 mutex_unlock(&codec->hash_mutex);
1404 return 0;
1405}
1406
1407/* query the value from the caps hash; if not found, fetch the current
1408 * value from the given function and store in the hash
1409 */
1410static unsigned int
1411query_caps_hash(struct hda_codec *codec, hda_nid_t nid, int dir, u32 key,
1412 unsigned int (*func)(struct hda_codec *, hda_nid_t, int))
1413{
1414 struct hda_amp_info *info;
1415 unsigned int val;
1416
1417 mutex_lock(&codec->hash_mutex);
1418 info = get_alloc_amp_hash(codec, key);
1419 if (!info) {
1420 mutex_unlock(&codec->hash_mutex);
1421 return 0;
1422 }
1423 if (!(info->head.val & INFO_AMP_CAPS)) {
1424 mutex_unlock(&codec->hash_mutex); /* for reentrance */
1425 val = func(codec, nid, dir);
1426 write_caps_hash(codec, key, val);
1427 } else {
1428 val = info->amp_caps;
1429 mutex_unlock(&codec->hash_mutex);
1430 }
1431 return val;
1432}
1433
1434static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid,
1435 int direction)
1436{
1437 if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
1438 nid = codec->core.afg;
1439 return snd_hda_param_read(codec, nid,
1440 direction == HDA_OUTPUT ?
1441 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
1442}
1443
1444/** 1379/**
1445 * query_amp_caps - query AMP capabilities 1380 * query_amp_caps - query AMP capabilities
1446 * @codec: the HD-auio codec 1381 * @codec: the HD-auio codec
@@ -1455,9 +1390,11 @@ static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid,
1455 */ 1390 */
1456u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) 1391u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
1457{ 1392{
1458 return query_caps_hash(codec, nid, direction, 1393 if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
1459 HDA_HASH_KEY(nid, direction, 0), 1394 nid = codec->core.afg;
1460 read_amp_cap); 1395 return snd_hda_param_read(codec, nid,
1396 direction == HDA_OUTPUT ?
1397 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
1461} 1398}
1462EXPORT_SYMBOL_GPL(query_amp_caps); 1399EXPORT_SYMBOL_GPL(query_amp_caps);
1463 1400
@@ -1498,50 +1435,14 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_caps);
1498int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, 1435int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
1499 unsigned int caps) 1436 unsigned int caps)
1500{ 1437{
1501 return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps); 1438 unsigned int parm;
1502}
1503EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
1504
1505static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid,
1506 int dir)
1507{
1508 return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
1509}
1510
1511/**
1512 * snd_hda_query_pin_caps - Query PIN capabilities
1513 * @codec: the HD-auio codec
1514 * @nid: the NID to query
1515 *
1516 * Query PIN capabilities for the given widget.
1517 * Returns the obtained capability bits.
1518 *
1519 * When cap bits have been already read, this doesn't read again but
1520 * returns the cached value.
1521 */
1522u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
1523{
1524 return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid),
1525 read_pin_cap);
1526}
1527EXPORT_SYMBOL_GPL(snd_hda_query_pin_caps);
1528 1439
1529/** 1440 snd_hda_override_wcaps(codec, nid,
1530 * snd_hda_override_pin_caps - Override the pin capabilities 1441 get_wcaps(codec, nid) | AC_WCAP_AMP_OVRD);
1531 * @codec: the CODEC 1442 parm = dir == HDA_OUTPUT ? AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP;
1532 * @nid: the NID to override 1443 return snd_hdac_override_parm(&codec->core, nid, parm, caps);
1533 * @caps: the capability bits to set
1534 *
1535 * Override the cached PIN capabilitiy bits value by the given one.
1536 *
1537 * Returns zero if successful or a negative error code.
1538 */
1539int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
1540 unsigned int caps)
1541{
1542 return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps);
1543} 1444}
1544EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps); 1445EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
1545 1446
1546/** 1447/**
1547 * snd_hda_codec_amp_stereo - update the AMP stereo values 1448 * snd_hda_codec_amp_stereo - update the AMP stereo values
@@ -3462,11 +3363,6 @@ static void hda_mark_cmd_cache_dirty(struct hda_codec *codec)
3462 cmd = snd_array_elem(&codec->cmd_cache.buf, i); 3363 cmd = snd_array_elem(&codec->cmd_cache.buf, i);
3463 cmd->dirty = 1; 3364 cmd->dirty = 1;
3464 } 3365 }
3465 for (i = 0; i < codec->amp_cache.buf.used; i++) {
3466 struct hda_amp_info *amp;
3467 amp = snd_array_elem(&codec->amp_cache.buf, i);
3468 amp->head.dirty = 1;
3469 }
3470} 3366}
3471 3367
3472/* 3368/*
@@ -3714,8 +3610,7 @@ unsigned int snd_hda_calc_stream_format(struct hda_codec *codec,
3714} 3610}
3715EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format); 3611EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format);
3716 3612
3717static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid, 3613static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
3718 int dir)
3719{ 3614{
3720 unsigned int val = 0; 3615 unsigned int val = 0;
3721 if (nid != codec->core.afg && 3616 if (nid != codec->core.afg &&
@@ -3728,14 +3623,7 @@ static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid,
3728 return val; 3623 return val;
3729} 3624}
3730 3625
3731static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) 3626static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
3732{
3733 return query_caps_hash(codec, nid, 0, HDA_HASH_PARPCM_KEY(nid),
3734 get_pcm_param);
3735}
3736
3737static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid,
3738 int dir)
3739{ 3627{
3740 unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); 3628 unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
3741 if (!streams || streams == -1) 3629 if (!streams || streams == -1)
@@ -3745,12 +3633,6 @@ static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid,
3745 return streams; 3633 return streams;
3746} 3634}
3747 3635
3748static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
3749{
3750 return query_caps_hash(codec, nid, 0, HDA_HASH_PARSTR_KEY(nid),
3751 get_stream_param);
3752}
3753
3754/** 3636/**
3755 * snd_hda_query_supported_pcm - query the supported PCM rates and formats 3637 * snd_hda_query_supported_pcm - query the supported PCM rates and formats
3756 * @codec: the HDA codec 3638 * @codec: the HDA codec
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 135b70f066f1..6af801a5bf89 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -163,12 +163,6 @@ struct hda_cache_head {
163 u16 next; 163 u16 next;
164}; 164};
165 165
166struct hda_amp_info {
167 struct hda_cache_head head;
168 u32 amp_caps; /* amp capabilities */
169 u16 vol[2]; /* current volume & mute */
170};
171
172struct hda_cache_rec { 166struct hda_cache_rec {
173 u16 hash[64]; /* hash table for index */ 167 u16 hash[64]; /* hash table for index */
174 struct snd_array buf; /* record entries */ 168 struct snd_array buf; /* record entries */
@@ -257,7 +251,6 @@ struct hda_codec {
257 struct snd_array mixers; /* list of assigned mixer elements */ 251 struct snd_array mixers; /* list of assigned mixer elements */
258 struct snd_array nids; /* list of mapped mixer elements */ 252 struct snd_array nids; /* list of mapped mixer elements */
259 253
260 struct hda_cache_rec amp_cache; /* cache for amp access */
261 struct hda_cache_rec cmd_cache; /* cache for other commands */ 254 struct hda_cache_rec cmd_cache; /* cache for other commands */
262 255
263 struct list_head conn_list; /* linked-list of connection-list */ 256 struct list_head conn_list; /* linked-list of connection-list */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 7023eeee8b9d..3b567f42296b 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -557,9 +557,41 @@ static inline void snd_hda_override_wcaps(struct hda_codec *codec,
557u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); 557u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
558int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, 558int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
559 unsigned int caps); 559 unsigned int caps);
560u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); 560/**
561int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, 561 * snd_hda_query_pin_caps - Query PIN capabilities
562 unsigned int caps); 562 * @codec: the HD-auio codec
563 * @nid: the NID to query
564 *
565 * Query PIN capabilities for the given widget.
566 * Returns the obtained capability bits.
567 *
568 * When cap bits have been already read, this doesn't read again but
569 * returns the cached value.
570 */
571static inline u32
572snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
573{
574 return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
575
576}
577
578/**
579 * snd_hda_override_pin_caps - Override the pin capabilities
580 * @codec: the CODEC
581 * @nid: the NID to override
582 * @caps: the capability bits to set
583 *
584 * Override the cached PIN capabilitiy bits value by the given one.
585 *
586 * Returns zero if successful or a negative error code.
587 */
588static inline int
589snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
590 unsigned int caps)
591{
592 return snd_hdac_override_parm(&codec->core, nid, AC_PAR_PIN_CAP, caps);
593}
594
563bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid, 595bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
564 int dir, unsigned int bits); 596 int dir, unsigned int bits);
565 597