ALSA: hda - Use regmap for parameter caches, too
authorTakashi Iwai <tiwai@suse.de>
Thu, 26 Feb 2015 07:54:56 +0000 (08:54 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 23 Mar 2015 12:19:40 +0000 (13:19 +0100)
The amp hash table was used for recording the cached reads of some
capability values like pin caps or amp caps.  Now all these are moved
to regmap as well.

One addition to the regmap helper is codec->caps_overwriting flag.
This is set in snd_hdac_override_parm(), and the regmap helper accepts
any register while this flag is set, so that it can overwrite even the
read-only verb like AC_VERB_PARAMETERS.  The flag is cleared
immediately in snd_hdac_override_parm(), as it's a once-off flag.

Along with these changes, the no longer needed amp hash and relevant
fields are removed from hda_codec struct now.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/sound/hdaudio.h
sound/hda/hdac_device.c
sound/hda/hdac_regmap.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_local.h

index 65ea6429f3a7fe5f47190847a522749466574c68..ce7d8d1f59c63cab4597f49d65b7cde6ca22d032 100644 (file)
@@ -76,6 +76,7 @@ struct hdac_device {
        /* regmap */
        struct regmap *regmap;
        bool lazy_cache:1;      /* don't wake up for writes */
+       bool caps_overwriting:1; /* caps overwrite being in process */
 };
 
 /* 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,
                        unsigned int *res);
 int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
                                int parm);
+int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
+                          unsigned int parm, unsigned int val);
 int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
                             hda_nid_t *conn_list, int max_conns);
 int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
index 0dac746df7da9c8415d394641c441aa3ed0f145b..72c584eb011b97539c49db1b67aaecd19119074d 100644 (file)
@@ -272,6 +272,29 @@ int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached);
 
+/**
+ * snd_hdac_override_parm - override read-only parameters
+ * @codec: the codec object
+ * @nid: NID for the parameter
+ * @parm: the parameter to change
+ * @val: the parameter value to overwrite
+ */
+int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
+                          unsigned int parm, unsigned int val)
+{
+       unsigned int verb = (AC_VERB_PARAMETERS << 8) | (nid << 20) | parm;
+       int err;
+
+       if (!codec->regmap)
+               return -EINVAL;
+
+       codec->caps_overwriting = true;
+       err = snd_hdac_regmap_write_raw(codec, verb, val);
+       codec->caps_overwriting = false;
+       return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_override_parm);
+
 /**
  * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes
  * @codec: the codec object
index db03d60d9c9917d67993962c4f2a33d1ba5c677f..933907b164574c59a85179f2c1e635522b806838 100644 (file)
@@ -58,8 +58,12 @@ static bool hda_volatile_reg(struct device *dev, unsigned int reg)
 
 static bool hda_writeable_reg(struct device *dev, unsigned int reg)
 {
+       struct hdac_device *codec = dev_to_hdac_dev(dev);
        unsigned int verb = get_verb(reg);
 
+       if (codec->caps_overwriting)
+               return true;
+
        switch (verb & 0xf00) {
        case AC_VERB_GET_STREAM_FORMAT:
        case AC_VERB_GET_AMP_GAIN_MUTE:
@@ -97,8 +101,12 @@ static bool hda_writeable_reg(struct device *dev, unsigned int reg)
 
 static bool hda_readable_reg(struct device *dev, unsigned int reg)
 {
+       struct hdac_device *codec = dev_to_hdac_dev(dev);
        unsigned int verb = get_verb(reg);
 
+       if (codec->caps_overwriting)
+               return true;
+
        switch (verb) {
        case AC_VERB_PARAMETERS:
        case AC_VERB_GET_CONNECT_LIST:
index 52962f697825b4297a87447c9e39305b37b7a667..b27f250088c15dc65df763f3407914add6e64f1f 100644 (file)
@@ -929,9 +929,7 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
        codec->proc_widget_hook = NULL;
        codec->spec = NULL;
 
-       free_hda_cache(&codec->amp_cache);
        free_hda_cache(&codec->cmd_cache);
-       init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
 
        /* 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)
        free_init_pincfgs(codec);
        snd_hdac_device_exit(&codec->core);
        snd_hda_sysfs_clear(codec);
-       free_hda_cache(&codec->amp_cache);
        free_hda_cache(&codec->cmd_cache);
        kfree(codec->modelname);
        kfree(codec->wcaps);
@@ -1051,7 +1048,6 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
        mutex_init(&codec->spdif_mutex);
        mutex_init(&codec->control_mutex);
        mutex_init(&codec->hash_mutex);
-       init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
        init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
        snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
        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,
        return info;
 }
 
-/* query and allocate an amp hash entry */
-static inline struct hda_amp_info *
-get_alloc_amp_hash(struct hda_codec *codec, u32 key)
-{
-       return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key);
-}
-
-/* overwrite the value with the key in the caps hash */
-static int write_caps_hash(struct hda_codec *codec, u32 key, unsigned int val)
-{
-       struct hda_amp_info *info;
-
-       mutex_lock(&codec->hash_mutex);
-       info = get_alloc_amp_hash(codec, key);
-       if (!info) {
-               mutex_unlock(&codec->hash_mutex);
-               return -EINVAL;
-       }
-       info->amp_caps = val;
-       info->head.val |= INFO_AMP_CAPS;
-       mutex_unlock(&codec->hash_mutex);
-       return 0;
-}
-
-/* query the value from the caps hash; if not found, fetch the current
- * value from the given function and store in the hash
- */
-static unsigned int
-query_caps_hash(struct hda_codec *codec, hda_nid_t nid, int dir, u32 key,
-               unsigned int (*func)(struct hda_codec *, hda_nid_t, int))
-{
-       struct hda_amp_info *info;
-       unsigned int val;
-
-       mutex_lock(&codec->hash_mutex);
-       info = get_alloc_amp_hash(codec, key);
-       if (!info) {
-               mutex_unlock(&codec->hash_mutex);
-               return 0;
-       }
-       if (!(info->head.val & INFO_AMP_CAPS)) {
-               mutex_unlock(&codec->hash_mutex); /* for reentrance */
-               val = func(codec, nid, dir);
-               write_caps_hash(codec, key, val);
-       } else {
-               val = info->amp_caps;
-               mutex_unlock(&codec->hash_mutex);
-       }
-       return val;
-}
-
-static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid,
-                                int direction)
-{
-       if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
-               nid = codec->core.afg;
-       return snd_hda_param_read(codec, nid,
-                                 direction == HDA_OUTPUT ?
-                                 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
-}
-
 /**
  * query_amp_caps - query AMP capabilities
  * @codec: the HD-auio codec
@@ -1455,9 +1390,11 @@ static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid,
  */
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 {
-       return query_caps_hash(codec, nid, direction,
-                              HDA_HASH_KEY(nid, direction, 0),
-                              read_amp_cap);
+       if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
+               nid = codec->core.afg;
+       return snd_hda_param_read(codec, nid,
+                                 direction == HDA_OUTPUT ?
+                                 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
 }
 EXPORT_SYMBOL_GPL(query_amp_caps);
 
@@ -1498,50 +1435,14 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_caps);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps)
 {
-       return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps);
-}
-EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
-
-static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid,
-                                int dir)
-{
-       return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-}
-
-/**
- * snd_hda_query_pin_caps - Query PIN capabilities
- * @codec: the HD-auio codec
- * @nid: the NID to query
- *
- * Query PIN capabilities for the given widget.
- * Returns the obtained capability bits.
- *
- * When cap bits have been already read, this doesn't read again but
- * returns the cached value.
- */
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
-{
-       return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid),
-                              read_pin_cap);
-}
-EXPORT_SYMBOL_GPL(snd_hda_query_pin_caps);
+       unsigned int parm;
 
-/**
- * snd_hda_override_pin_caps - Override the pin capabilities
- * @codec: the CODEC
- * @nid: the NID to override
- * @caps: the capability bits to set
- *
- * Override the cached PIN capabilitiy bits value by the given one.
- *
- * Returns zero if successful or a negative error code.
- */
-int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
-                             unsigned int caps)
-{
-       return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps);
+       snd_hda_override_wcaps(codec, nid,
+                              get_wcaps(codec, nid) | AC_WCAP_AMP_OVRD);
+       parm = dir == HDA_OUTPUT ? AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP;
+       return snd_hdac_override_parm(&codec->core, nid, parm, caps);
 }
-EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps);
+EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
 
 /**
  * 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)
                cmd = snd_array_elem(&codec->cmd_cache.buf, i);
                cmd->dirty = 1;
        }
-       for (i = 0; i < codec->amp_cache.buf.used; i++) {
-               struct hda_amp_info *amp;
-               amp = snd_array_elem(&codec->amp_cache.buf, i);
-               amp->head.dirty = 1;
-       }
 }
 
 /*
@@ -3714,8 +3610,7 @@ unsigned int snd_hda_calc_stream_format(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format);
 
-static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid,
-                                 int dir)
+static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
 {
        unsigned int val = 0;
        if (nid != codec->core.afg &&
@@ -3728,14 +3623,7 @@ static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid,
        return val;
 }
 
-static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
-{
-       return query_caps_hash(codec, nid, 0, HDA_HASH_PARPCM_KEY(nid),
-                              get_pcm_param);
-}
-
-static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid,
-                                    int dir)
+static unsigned int query_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)
@@ -3745,12 +3633,6 @@ static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid,
        return streams;
 }
 
-static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
-{
-       return query_caps_hash(codec, nid, 0, HDA_HASH_PARSTR_KEY(nid),
-                              get_stream_param);
-}
-
 /**
  * snd_hda_query_supported_pcm - query the supported PCM rates and formats
  * @codec: the HDA codec
index 135b70f066f1ad17bd177449a9a16632ec8971a8..6af801a5bf89f28a0bc5a60a01b8f34d0195eb5a 100644 (file)
@@ -163,12 +163,6 @@ struct hda_cache_head {
        u16 next;
 };
 
-struct hda_amp_info {
-       struct hda_cache_head head;
-       u32 amp_caps;           /* amp capabilities */
-       u16 vol[2];             /* current volume & mute */
-};
-
 struct hda_cache_rec {
        u16 hash[64];                   /* hash table for index */
        struct snd_array buf;           /* record entries */
@@ -257,7 +251,6 @@ struct hda_codec {
        struct snd_array mixers;        /* list of assigned mixer elements */
        struct snd_array nids;          /* list of mapped mixer elements */
 
-       struct hda_cache_rec amp_cache; /* cache for amp access */
        struct hda_cache_rec cmd_cache; /* cache for other commands */
 
        struct list_head conn_list;     /* linked-list of connection-list */
index 7023eeee8b9d2d356c60942d634266c312285426..3b567f42296b9d6b2ca148c66c59c12b5628cb9e 100644 (file)
@@ -557,9 +557,41 @@ static inline void snd_hda_override_wcaps(struct hda_codec *codec,
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps);
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
-int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
-                             unsigned int caps);
+/**
+ * snd_hda_query_pin_caps - Query PIN capabilities
+ * @codec: the HD-auio codec
+ * @nid: the NID to query
+ *
+ * Query PIN capabilities for the given widget.
+ * Returns the obtained capability bits.
+ *
+ * When cap bits have been already read, this doesn't read again but
+ * returns the cached value.
+ */
+static inline u32
+snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+{
+       return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+
+}
+
+/**
+ * snd_hda_override_pin_caps - Override the pin capabilities
+ * @codec: the CODEC
+ * @nid: the NID to override
+ * @caps: the capability bits to set
+ *
+ * Override the cached PIN capabilitiy bits value by the given one.
+ *
+ * Returns zero if successful or a negative error code.
+ */
+static inline int
+snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
+                         unsigned int caps)
+{
+       return snd_hdac_override_parm(&codec->core, nid, AC_PAR_PIN_CAP, caps);
+}
+
 bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
                           int dir, unsigned int bits);