LCOV - code coverage report
Current view: top level - sound/pci/hda - hda_sysfs.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 36 0.0 %
Date: 2022-04-01 14:35:51 Functions: 0 15 0.0 %
Branches: 0 8 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * sysfs interface for HD-audio codec
       4                 :            :  *
       5                 :            :  * Copyright (c) 2014 Takashi Iwai <tiwai@suse.de>
       6                 :            :  *
       7                 :            :  * split from hda_hwdep.c
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/init.h>
      11                 :            : #include <linux/slab.h>
      12                 :            : #include <linux/compat.h>
      13                 :            : #include <linux/mutex.h>
      14                 :            : #include <linux/ctype.h>
      15                 :            : #include <linux/string.h>
      16                 :            : #include <linux/export.h>
      17                 :            : #include <sound/core.h>
      18                 :            : #include <sound/hda_codec.h>
      19                 :            : #include "hda_local.h"
      20                 :            : #include <sound/hda_hwdep.h>
      21                 :            : #include <sound/minors.h>
      22                 :            : 
      23                 :            : /* hint string pair */
      24                 :            : struct hda_hint {
      25                 :            :         const char *key;
      26                 :            :         const char *val;        /* contained in the same alloc as key */
      27                 :            : };
      28                 :            : 
      29                 :            : #ifdef CONFIG_PM
      30                 :          0 : static ssize_t power_on_acct_show(struct device *dev,
      31                 :            :                                   struct device_attribute *attr,
      32                 :            :                                   char *buf)
      33                 :            : {
      34                 :          0 :         struct hda_codec *codec = dev_get_drvdata(dev);
      35                 :          0 :         snd_hda_update_power_acct(codec);
      36                 :          0 :         return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
      37                 :            : }
      38                 :            : 
      39                 :          0 : static ssize_t power_off_acct_show(struct device *dev,
      40                 :            :                                    struct device_attribute *attr,
      41                 :            :                                    char *buf)
      42                 :            : {
      43                 :          0 :         struct hda_codec *codec = dev_get_drvdata(dev);
      44                 :          0 :         snd_hda_update_power_acct(codec);
      45                 :          0 :         return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
      46                 :            : }
      47                 :            : 
      48                 :            : static DEVICE_ATTR_RO(power_on_acct);
      49                 :            : static DEVICE_ATTR_RO(power_off_acct);
      50                 :            : #endif /* CONFIG_PM */
      51                 :            : 
      52                 :            : #define CODEC_INFO_SHOW(type, field)                            \
      53                 :            : static ssize_t type##_show(struct device *dev,                  \
      54                 :            :                            struct device_attribute *attr,       \
      55                 :            :                            char *buf)                           \
      56                 :            : {                                                               \
      57                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);         \
      58                 :            :         return sprintf(buf, "0x%x\n", codec->field);               \
      59                 :            : }
      60                 :            : 
      61                 :            : #define CODEC_INFO_STR_SHOW(type, field)                        \
      62                 :            : static ssize_t type##_show(struct device *dev,                  \
      63                 :            :                              struct device_attribute *attr,     \
      64                 :            :                                         char *buf)              \
      65                 :            : {                                                               \
      66                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);         \
      67                 :            :         return sprintf(buf, "%s\n",                           \
      68                 :            :                        codec->field ? codec->field : "");       \
      69                 :            : }
      70                 :            : 
      71                 :          0 : CODEC_INFO_SHOW(vendor_id, core.vendor_id);
      72                 :          0 : CODEC_INFO_SHOW(subsystem_id, core.subsystem_id);
      73                 :          0 : CODEC_INFO_SHOW(revision_id, core.revision_id);
      74                 :          0 : CODEC_INFO_SHOW(afg, core.afg);
      75                 :          0 : CODEC_INFO_SHOW(mfg, core.mfg);
      76         [ #  # ]:          0 : CODEC_INFO_STR_SHOW(vendor_name, core.vendor_name);
      77         [ #  # ]:          0 : CODEC_INFO_STR_SHOW(chip_name, core.chip_name);
      78         [ #  # ]:          0 : CODEC_INFO_STR_SHOW(modelname, modelname);
      79                 :            : 
      80                 :          0 : static ssize_t pin_configs_show(struct hda_codec *codec,
      81                 :            :                                 struct snd_array *list,
      82                 :            :                                 char *buf)
      83                 :            : {
      84                 :          0 :         const struct hda_pincfg *pin;
      85                 :          0 :         int i, len = 0;
      86                 :          0 :         mutex_lock(&codec->user_mutex);
      87         [ #  # ]:          0 :         snd_array_for_each(list, i, pin) {
      88                 :          0 :                 len += sprintf(buf + len, "0x%02x 0x%08x\n",
      89                 :          0 :                                pin->nid, pin->cfg);
      90                 :            :         }
      91                 :          0 :         mutex_unlock(&codec->user_mutex);
      92                 :          0 :         return len;
      93                 :            : }
      94                 :            : 
      95                 :          0 : static ssize_t init_pin_configs_show(struct device *dev,
      96                 :            :                                      struct device_attribute *attr,
      97                 :            :                                      char *buf)
      98                 :            : {
      99                 :          0 :         struct hda_codec *codec = dev_get_drvdata(dev);
     100                 :          0 :         return pin_configs_show(codec, &codec->init_pins, buf);
     101                 :            : }
     102                 :            : 
     103                 :          0 : static ssize_t driver_pin_configs_show(struct device *dev,
     104                 :            :                                        struct device_attribute *attr,
     105                 :            :                                        char *buf)
     106                 :            : {
     107                 :          0 :         struct hda_codec *codec = dev_get_drvdata(dev);
     108                 :          0 :         return pin_configs_show(codec, &codec->driver_pins, buf);
     109                 :            : }
     110                 :            : 
     111                 :            : #ifdef CONFIG_SND_HDA_RECONFIG
     112                 :            : 
     113                 :            : /*
     114                 :            :  * sysfs interface
     115                 :            :  */
     116                 :            : 
     117                 :            : static int clear_codec(struct hda_codec *codec)
     118                 :            : {
     119                 :            :         int err;
     120                 :            : 
     121                 :            :         err = snd_hda_codec_reset(codec);
     122                 :            :         if (err < 0) {
     123                 :            :                 codec_err(codec, "The codec is being used, can't free.\n");
     124                 :            :                 return err;
     125                 :            :         }
     126                 :            :         snd_hda_sysfs_clear(codec);
     127                 :            :         return 0;
     128                 :            : }
     129                 :            : 
     130                 :            : static int reconfig_codec(struct hda_codec *codec)
     131                 :            : {
     132                 :            :         int err;
     133                 :            : 
     134                 :            :         snd_hda_power_up(codec);
     135                 :            :         codec_info(codec, "hda-codec: reconfiguring\n");
     136                 :            :         err = snd_hda_codec_reset(codec);
     137                 :            :         if (err < 0) {
     138                 :            :                 codec_err(codec,
     139                 :            :                            "The codec is being used, can't reconfigure.\n");
     140                 :            :                 goto error;
     141                 :            :         }
     142                 :            :         err = snd_hda_codec_configure(codec);
     143                 :            :         if (err < 0)
     144                 :            :                 goto error;
     145                 :            :         err = snd_card_register(codec->card);
     146                 :            :  error:
     147                 :            :         snd_hda_power_down(codec);
     148                 :            :         return err;
     149                 :            : }
     150                 :            : 
     151                 :            : /*
     152                 :            :  * allocate a string at most len chars, and remove the trailing EOL
     153                 :            :  */
     154                 :            : static char *kstrndup_noeol(const char *src, size_t len)
     155                 :            : {
     156                 :            :         char *s = kstrndup(src, len, GFP_KERNEL);
     157                 :            :         char *p;
     158                 :            :         if (!s)
     159                 :            :                 return NULL;
     160                 :            :         p = strchr(s, '\n');
     161                 :            :         if (p)
     162                 :            :                 *p = 0;
     163                 :            :         return s;
     164                 :            : }
     165                 :            : 
     166                 :            : #define CODEC_INFO_STORE(type, field)                           \
     167                 :            : static ssize_t type##_store(struct device *dev,                 \
     168                 :            :                             struct device_attribute *attr,      \
     169                 :            :                             const char *buf, size_t count)      \
     170                 :            : {                                                               \
     171                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);         \
     172                 :            :         unsigned long val;                                      \
     173                 :            :         int err = kstrtoul(buf, 0, &val);                   \
     174                 :            :         if (err < 0)                                         \
     175                 :            :                 return err;                                     \
     176                 :            :         codec->field = val;                                  \
     177                 :            :         return count;                                           \
     178                 :            : }
     179                 :            : 
     180                 :            : #define CODEC_INFO_STR_STORE(type, field)                       \
     181                 :            : static ssize_t type##_store(struct device *dev,                 \
     182                 :            :                             struct device_attribute *attr,      \
     183                 :            :                             const char *buf, size_t count)      \
     184                 :            : {                                                               \
     185                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);         \
     186                 :            :         char *s = kstrndup_noeol(buf, 64);                      \
     187                 :            :         if (!s)                                                 \
     188                 :            :                 return -ENOMEM;                                 \
     189                 :            :         kfree(codec->field);                                 \
     190                 :            :         codec->field = s;                                    \
     191                 :            :         return count;                                           \
     192                 :            : }
     193                 :            : 
     194                 :            : CODEC_INFO_STORE(vendor_id, core.vendor_id);
     195                 :            : CODEC_INFO_STORE(subsystem_id, core.subsystem_id);
     196                 :            : CODEC_INFO_STORE(revision_id, core.revision_id);
     197                 :            : CODEC_INFO_STR_STORE(vendor_name, core.vendor_name);
     198                 :            : CODEC_INFO_STR_STORE(chip_name, core.chip_name);
     199                 :            : CODEC_INFO_STR_STORE(modelname, modelname);
     200                 :            : 
     201                 :            : #define CODEC_ACTION_STORE(type)                                \
     202                 :            : static ssize_t type##_store(struct device *dev,                 \
     203                 :            :                             struct device_attribute *attr,      \
     204                 :            :                             const char *buf, size_t count)      \
     205                 :            : {                                                               \
     206                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);         \
     207                 :            :         int err = 0;                                            \
     208                 :            :         if (*buf)                                               \
     209                 :            :                 err = type##_codec(codec);                      \
     210                 :            :         return err < 0 ? err : count;                                \
     211                 :            : }
     212                 :            : 
     213                 :            : CODEC_ACTION_STORE(reconfig);
     214                 :            : CODEC_ACTION_STORE(clear);
     215                 :            : 
     216                 :            : static ssize_t init_verbs_show(struct device *dev,
     217                 :            :                                struct device_attribute *attr,
     218                 :            :                                char *buf)
     219                 :            : {
     220                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);
     221                 :            :         const struct hda_verb *v;
     222                 :            :         int i, len = 0;
     223                 :            :         mutex_lock(&codec->user_mutex);
     224                 :            :         snd_array_for_each(&codec->init_verbs, i, v) {
     225                 :            :                 len += scnprintf(buf + len, PAGE_SIZE - len,
     226                 :            :                                 "0x%02x 0x%03x 0x%04x\n",
     227                 :            :                                 v->nid, v->verb, v->param);
     228                 :            :         }
     229                 :            :         mutex_unlock(&codec->user_mutex);
     230                 :            :         return len;
     231                 :            : }
     232                 :            : 
     233                 :            : static int parse_init_verbs(struct hda_codec *codec, const char *buf)
     234                 :            : {
     235                 :            :         struct hda_verb *v;
     236                 :            :         int nid, verb, param;
     237                 :            : 
     238                 :            :         if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
     239                 :            :                 return -EINVAL;
     240                 :            :         if (!nid || !verb)
     241                 :            :                 return -EINVAL;
     242                 :            :         mutex_lock(&codec->user_mutex);
     243                 :            :         v = snd_array_new(&codec->init_verbs);
     244                 :            :         if (!v) {
     245                 :            :                 mutex_unlock(&codec->user_mutex);
     246                 :            :                 return -ENOMEM;
     247                 :            :         }
     248                 :            :         v->nid = nid;
     249                 :            :         v->verb = verb;
     250                 :            :         v->param = param;
     251                 :            :         mutex_unlock(&codec->user_mutex);
     252                 :            :         return 0;
     253                 :            : }
     254                 :            : 
     255                 :            : static ssize_t init_verbs_store(struct device *dev,
     256                 :            :                                 struct device_attribute *attr,
     257                 :            :                                 const char *buf, size_t count)
     258                 :            : {
     259                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);
     260                 :            :         int err = parse_init_verbs(codec, buf);
     261                 :            :         if (err < 0)
     262                 :            :                 return err;
     263                 :            :         return count;
     264                 :            : }
     265                 :            : 
     266                 :            : static ssize_t hints_show(struct device *dev,
     267                 :            :                           struct device_attribute *attr,
     268                 :            :                           char *buf)
     269                 :            : {
     270                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);
     271                 :            :         const struct hda_hint *hint;
     272                 :            :         int i, len = 0;
     273                 :            :         mutex_lock(&codec->user_mutex);
     274                 :            :         snd_array_for_each(&codec->hints, i, hint) {
     275                 :            :                 len += scnprintf(buf + len, PAGE_SIZE - len,
     276                 :            :                                 "%s = %s\n", hint->key, hint->val);
     277                 :            :         }
     278                 :            :         mutex_unlock(&codec->user_mutex);
     279                 :            :         return len;
     280                 :            : }
     281                 :            : 
     282                 :            : static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
     283                 :            : {
     284                 :            :         struct hda_hint *hint;
     285                 :            :         int i;
     286                 :            : 
     287                 :            :         snd_array_for_each(&codec->hints, i, hint) {
     288                 :            :                 if (!strcmp(hint->key, key))
     289                 :            :                         return hint;
     290                 :            :         }
     291                 :            :         return NULL;
     292                 :            : }
     293                 :            : 
     294                 :            : static void remove_trail_spaces(char *str)
     295                 :            : {
     296                 :            :         char *p;
     297                 :            :         if (!*str)
     298                 :            :                 return;
     299                 :            :         p = str + strlen(str) - 1;
     300                 :            :         for (; isspace(*p); p--) {
     301                 :            :                 *p = 0;
     302                 :            :                 if (p == str)
     303                 :            :                         return;
     304                 :            :         }
     305                 :            : }
     306                 :            : 
     307                 :            : #define MAX_HINTS       1024
     308                 :            : 
     309                 :            : static int parse_hints(struct hda_codec *codec, const char *buf)
     310                 :            : {
     311                 :            :         char *key, *val;
     312                 :            :         struct hda_hint *hint;
     313                 :            :         int err = 0;
     314                 :            : 
     315                 :            :         buf = skip_spaces(buf);
     316                 :            :         if (!*buf || *buf == '#' || *buf == '\n')
     317                 :            :                 return 0;
     318                 :            :         if (*buf == '=')
     319                 :            :                 return -EINVAL;
     320                 :            :         key = kstrndup_noeol(buf, 1024);
     321                 :            :         if (!key)
     322                 :            :                 return -ENOMEM;
     323                 :            :         /* extract key and val */
     324                 :            :         val = strchr(key, '=');
     325                 :            :         if (!val) {
     326                 :            :                 kfree(key);
     327                 :            :                 return -EINVAL;
     328                 :            :         }
     329                 :            :         *val++ = 0;
     330                 :            :         val = skip_spaces(val);
     331                 :            :         remove_trail_spaces(key);
     332                 :            :         remove_trail_spaces(val);
     333                 :            :         mutex_lock(&codec->user_mutex);
     334                 :            :         hint = get_hint(codec, key);
     335                 :            :         if (hint) {
     336                 :            :                 /* replace */
     337                 :            :                 kfree(hint->key);
     338                 :            :                 hint->key = key;
     339                 :            :                 hint->val = val;
     340                 :            :                 goto unlock;
     341                 :            :         }
     342                 :            :         /* allocate a new hint entry */
     343                 :            :         if (codec->hints.used >= MAX_HINTS)
     344                 :            :                 hint = NULL;
     345                 :            :         else
     346                 :            :                 hint = snd_array_new(&codec->hints);
     347                 :            :         if (hint) {
     348                 :            :                 hint->key = key;
     349                 :            :                 hint->val = val;
     350                 :            :         } else {
     351                 :            :                 err = -ENOMEM;
     352                 :            :         }
     353                 :            :  unlock:
     354                 :            :         mutex_unlock(&codec->user_mutex);
     355                 :            :         if (err)
     356                 :            :                 kfree(key);
     357                 :            :         return err;
     358                 :            : }
     359                 :            : 
     360                 :            : static ssize_t hints_store(struct device *dev,
     361                 :            :                            struct device_attribute *attr,
     362                 :            :                            const char *buf, size_t count)
     363                 :            : {
     364                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);
     365                 :            :         int err = parse_hints(codec, buf);
     366                 :            :         if (err < 0)
     367                 :            :                 return err;
     368                 :            :         return count;
     369                 :            : }
     370                 :            : 
     371                 :            : static ssize_t user_pin_configs_show(struct device *dev,
     372                 :            :                                      struct device_attribute *attr,
     373                 :            :                                      char *buf)
     374                 :            : {
     375                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);
     376                 :            :         return pin_configs_show(codec, &codec->user_pins, buf);
     377                 :            : }
     378                 :            : 
     379                 :            : #define MAX_PIN_CONFIGS         32
     380                 :            : 
     381                 :            : static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
     382                 :            : {
     383                 :            :         int nid, cfg, err;
     384                 :            : 
     385                 :            :         if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
     386                 :            :                 return -EINVAL;
     387                 :            :         if (!nid)
     388                 :            :                 return -EINVAL;
     389                 :            :         mutex_lock(&codec->user_mutex);
     390                 :            :         err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
     391                 :            :         mutex_unlock(&codec->user_mutex);
     392                 :            :         return err;
     393                 :            : }
     394                 :            : 
     395                 :            : static ssize_t user_pin_configs_store(struct device *dev,
     396                 :            :                                       struct device_attribute *attr,
     397                 :            :                                       const char *buf, size_t count)
     398                 :            : {
     399                 :            :         struct hda_codec *codec = dev_get_drvdata(dev);
     400                 :            :         int err = parse_user_pin_configs(codec, buf);
     401                 :            :         if (err < 0)
     402                 :            :                 return err;
     403                 :            :         return count;
     404                 :            : }
     405                 :            : 
     406                 :            : /* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */
     407                 :            : static DEVICE_ATTR_RW(init_verbs);
     408                 :            : static DEVICE_ATTR_RW(hints);
     409                 :            : static DEVICE_ATTR_RW(user_pin_configs);
     410                 :            : static DEVICE_ATTR_WO(reconfig);
     411                 :            : static DEVICE_ATTR_WO(clear);
     412                 :            : 
     413                 :            : /**
     414                 :            :  * snd_hda_get_hint - Look for hint string
     415                 :            :  * @codec: the HDA codec
     416                 :            :  * @key: the hint key string
     417                 :            :  *
     418                 :            :  * Look for a hint key/value pair matching with the given key string
     419                 :            :  * and returns the value string.  If nothing found, returns NULL.
     420                 :            :  */
     421                 :            : const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
     422                 :            : {
     423                 :            :         struct hda_hint *hint = get_hint(codec, key);
     424                 :            :         return hint ? hint->val : NULL;
     425                 :            : }
     426                 :            : EXPORT_SYMBOL_GPL(snd_hda_get_hint);
     427                 :            : 
     428                 :            : /**
     429                 :            :  * snd_hda_get_bool_hint - Get a boolean hint value
     430                 :            :  * @codec: the HDA codec
     431                 :            :  * @key: the hint key string
     432                 :            :  *
     433                 :            :  * Look for a hint key/value pair matching with the given key string
     434                 :            :  * and returns a boolean value parsed from the value.  If no matching
     435                 :            :  * key is found, return a negative value.
     436                 :            :  */
     437                 :            : int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
     438                 :            : {
     439                 :            :         const char *p;
     440                 :            :         int ret;
     441                 :            : 
     442                 :            :         mutex_lock(&codec->user_mutex);
     443                 :            :         p = snd_hda_get_hint(codec, key);
     444                 :            :         if (!p || !*p)
     445                 :            :                 ret = -ENOENT;
     446                 :            :         else {
     447                 :            :                 switch (toupper(*p)) {
     448                 :            :                 case 'T': /* true */
     449                 :            :                 case 'Y': /* yes */
     450                 :            :                 case '1':
     451                 :            :                         ret = 1;
     452                 :            :                         break;
     453                 :            :                 default:
     454                 :            :                         ret = 0;
     455                 :            :                         break;
     456                 :            :                 }
     457                 :            :         }
     458                 :            :         mutex_unlock(&codec->user_mutex);
     459                 :            :         return ret;
     460                 :            : }
     461                 :            : EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
     462                 :            : 
     463                 :            : /**
     464                 :            :  * snd_hda_get_int_hint - Get an integer hint value
     465                 :            :  * @codec: the HDA codec
     466                 :            :  * @key: the hint key string
     467                 :            :  * @valp: pointer to store a value
     468                 :            :  *
     469                 :            :  * Look for a hint key/value pair matching with the given key string
     470                 :            :  * and stores the integer value to @valp.  If no matching key is found,
     471                 :            :  * return a negative error code.  Otherwise it returns zero.
     472                 :            :  */
     473                 :            : int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
     474                 :            : {
     475                 :            :         const char *p;
     476                 :            :         unsigned long val;
     477                 :            :         int ret;
     478                 :            : 
     479                 :            :         mutex_lock(&codec->user_mutex);
     480                 :            :         p = snd_hda_get_hint(codec, key);
     481                 :            :         if (!p)
     482                 :            :                 ret = -ENOENT;
     483                 :            :         else if (kstrtoul(p, 0, &val))
     484                 :            :                 ret = -EINVAL;
     485                 :            :         else {
     486                 :            :                 *valp = val;
     487                 :            :                 ret = 0;
     488                 :            :         }
     489                 :            :         mutex_unlock(&codec->user_mutex);
     490                 :            :         return ret;
     491                 :            : }
     492                 :            : EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
     493                 :            : #endif /* CONFIG_SND_HDA_RECONFIG */
     494                 :            : 
     495                 :            : /*
     496                 :            :  * common sysfs attributes
     497                 :            :  */
     498                 :            : #ifdef CONFIG_SND_HDA_RECONFIG
     499                 :            : #define RECONFIG_DEVICE_ATTR(name)      DEVICE_ATTR_RW(name)
     500                 :            : #else
     501                 :            : #define RECONFIG_DEVICE_ATTR(name)      DEVICE_ATTR_RO(name)
     502                 :            : #endif
     503                 :            : static RECONFIG_DEVICE_ATTR(vendor_id);
     504                 :            : static RECONFIG_DEVICE_ATTR(subsystem_id);
     505                 :            : static RECONFIG_DEVICE_ATTR(revision_id);
     506                 :            : static DEVICE_ATTR_RO(afg);
     507                 :            : static DEVICE_ATTR_RO(mfg);
     508                 :            : static RECONFIG_DEVICE_ATTR(vendor_name);
     509                 :            : static RECONFIG_DEVICE_ATTR(chip_name);
     510                 :            : static RECONFIG_DEVICE_ATTR(modelname);
     511                 :            : static DEVICE_ATTR_RO(init_pin_configs);
     512                 :            : static DEVICE_ATTR_RO(driver_pin_configs);
     513                 :            : 
     514                 :            : 
     515                 :            : #ifdef CONFIG_SND_HDA_PATCH_LOADER
     516                 :            : 
     517                 :            : /* parser mode */
     518                 :            : enum {
     519                 :            :         LINE_MODE_NONE,
     520                 :            :         LINE_MODE_CODEC,
     521                 :            :         LINE_MODE_MODEL,
     522                 :            :         LINE_MODE_PINCFG,
     523                 :            :         LINE_MODE_VERB,
     524                 :            :         LINE_MODE_HINT,
     525                 :            :         LINE_MODE_VENDOR_ID,
     526                 :            :         LINE_MODE_SUBSYSTEM_ID,
     527                 :            :         LINE_MODE_REVISION_ID,
     528                 :            :         LINE_MODE_CHIP_NAME,
     529                 :            :         NUM_LINE_MODES,
     530                 :            : };
     531                 :            : 
     532                 :            : static inline int strmatch(const char *a, const char *b)
     533                 :            : {
     534                 :            :         return strncasecmp(a, b, strlen(b)) == 0;
     535                 :            : }
     536                 :            : 
     537                 :            : /* parse the contents after the line "[codec]"
     538                 :            :  * accept only the line with three numbers, and assign the current codec
     539                 :            :  */
     540                 :            : static void parse_codec_mode(char *buf, struct hda_bus *bus,
     541                 :            :                              struct hda_codec **codecp)
     542                 :            : {
     543                 :            :         int vendorid, subid, caddr;
     544                 :            :         struct hda_codec *codec;
     545                 :            : 
     546                 :            :         *codecp = NULL;
     547                 :            :         if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
     548                 :            :                 list_for_each_codec(codec, bus) {
     549                 :            :                         if ((vendorid <= 0 || codec->core.vendor_id == vendorid) &&
     550                 :            :                             (subid <= 0 || codec->core.subsystem_id == subid) &&
     551                 :            :                             codec->core.addr == caddr) {
     552                 :            :                                 *codecp = codec;
     553                 :            :                                 break;
     554                 :            :                         }
     555                 :            :                 }
     556                 :            :         }
     557                 :            : }
     558                 :            : 
     559                 :            : /* parse the contents after the other command tags, [pincfg], [verb],
     560                 :            :  * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
     561                 :            :  * just pass to the sysfs helper (only when any codec was specified)
     562                 :            :  */
     563                 :            : static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
     564                 :            :                               struct hda_codec **codecp)
     565                 :            : {
     566                 :            :         parse_user_pin_configs(*codecp, buf);
     567                 :            : }
     568                 :            : 
     569                 :            : static void parse_verb_mode(char *buf, struct hda_bus *bus,
     570                 :            :                             struct hda_codec **codecp)
     571                 :            : {
     572                 :            :         parse_init_verbs(*codecp, buf);
     573                 :            : }
     574                 :            : 
     575                 :            : static void parse_hint_mode(char *buf, struct hda_bus *bus,
     576                 :            :                             struct hda_codec **codecp)
     577                 :            : {
     578                 :            :         parse_hints(*codecp, buf);
     579                 :            : }
     580                 :            : 
     581                 :            : static void parse_model_mode(char *buf, struct hda_bus *bus,
     582                 :            :                              struct hda_codec **codecp)
     583                 :            : {
     584                 :            :         kfree((*codecp)->modelname);
     585                 :            :         (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
     586                 :            : }
     587                 :            : 
     588                 :            : static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
     589                 :            :                                  struct hda_codec **codecp)
     590                 :            : {
     591                 :            :         snd_hda_codec_set_name(*codecp, buf);
     592                 :            : }
     593                 :            : 
     594                 :            : #define DEFINE_PARSE_ID_MODE(name) \
     595                 :            : static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
     596                 :            :                                  struct hda_codec **codecp) \
     597                 :            : { \
     598                 :            :         unsigned long val; \
     599                 :            :         if (!kstrtoul(buf, 0, &val)) \
     600                 :            :                 (*codecp)->core.name = val; \
     601                 :            : }
     602                 :            : 
     603                 :            : DEFINE_PARSE_ID_MODE(vendor_id);
     604                 :            : DEFINE_PARSE_ID_MODE(subsystem_id);
     605                 :            : DEFINE_PARSE_ID_MODE(revision_id);
     606                 :            : 
     607                 :            : 
     608                 :            : struct hda_patch_item {
     609                 :            :         const char *tag;
     610                 :            :         const char *alias;
     611                 :            :         void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
     612                 :            : };
     613                 :            : 
     614                 :            : static const struct hda_patch_item patch_items[NUM_LINE_MODES] = {
     615                 :            :         [LINE_MODE_CODEC] = {
     616                 :            :                 .tag = "[codec]",
     617                 :            :                 .parser = parse_codec_mode,
     618                 :            :         },
     619                 :            :         [LINE_MODE_MODEL] = {
     620                 :            :                 .tag = "[model]",
     621                 :            :                 .parser = parse_model_mode,
     622                 :            :         },
     623                 :            :         [LINE_MODE_VERB] = {
     624                 :            :                 .tag = "[verb]",
     625                 :            :                 .alias = "[init_verbs]",
     626                 :            :                 .parser = parse_verb_mode,
     627                 :            :         },
     628                 :            :         [LINE_MODE_PINCFG] = {
     629                 :            :                 .tag = "[pincfg]",
     630                 :            :                 .alias = "[user_pin_configs]",
     631                 :            :                 .parser = parse_pincfg_mode,
     632                 :            :         },
     633                 :            :         [LINE_MODE_HINT] = {
     634                 :            :                 .tag = "[hint]",
     635                 :            :                 .alias = "[hints]",
     636                 :            :                 .parser = parse_hint_mode
     637                 :            :         },
     638                 :            :         [LINE_MODE_VENDOR_ID] = {
     639                 :            :                 .tag = "[vendor_id]",
     640                 :            :                 .parser = parse_vendor_id_mode,
     641                 :            :         },
     642                 :            :         [LINE_MODE_SUBSYSTEM_ID] = {
     643                 :            :                 .tag = "[subsystem_id]",
     644                 :            :                 .parser = parse_subsystem_id_mode,
     645                 :            :         },
     646                 :            :         [LINE_MODE_REVISION_ID] = {
     647                 :            :                 .tag = "[revision_id]",
     648                 :            :                 .parser = parse_revision_id_mode,
     649                 :            :         },
     650                 :            :         [LINE_MODE_CHIP_NAME] = {
     651                 :            :                 .tag = "[chip_name]",
     652                 :            :                 .parser = parse_chip_name_mode,
     653                 :            :         },
     654                 :            : };
     655                 :            : 
     656                 :            : /* check the line starting with '[' -- change the parser mode accodingly */
     657                 :            : static int parse_line_mode(char *buf, struct hda_bus *bus)
     658                 :            : {
     659                 :            :         int i;
     660                 :            :         for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
     661                 :            :                 if (!patch_items[i].tag)
     662                 :            :                         continue;
     663                 :            :                 if (strmatch(buf, patch_items[i].tag))
     664                 :            :                         return i;
     665                 :            :                 if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
     666                 :            :                         return i;
     667                 :            :         }
     668                 :            :         return LINE_MODE_NONE;
     669                 :            : }
     670                 :            : 
     671                 :            : /* copy one line from the buffer in fw, and update the fields in fw
     672                 :            :  * return zero if it reaches to the end of the buffer, or non-zero
     673                 :            :  * if successfully copied a line
     674                 :            :  *
     675                 :            :  * the spaces at the beginning and the end of the line are stripped
     676                 :            :  */
     677                 :            : static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
     678                 :            :                             const void **fw_data_p)
     679                 :            : {
     680                 :            :         int len;
     681                 :            :         size_t fw_size = *fw_size_p;
     682                 :            :         const char *p = *fw_data_p;
     683                 :            : 
     684                 :            :         while (isspace(*p) && fw_size) {
     685                 :            :                 p++;
     686                 :            :                 fw_size--;
     687                 :            :         }
     688                 :            :         if (!fw_size)
     689                 :            :                 return 0;
     690                 :            : 
     691                 :            :         for (len = 0; len < fw_size; len++) {
     692                 :            :                 if (!*p)
     693                 :            :                         break;
     694                 :            :                 if (*p == '\n') {
     695                 :            :                         p++;
     696                 :            :                         len++;
     697                 :            :                         break;
     698                 :            :                 }
     699                 :            :                 if (len < size)
     700                 :            :                         *buf++ = *p++;
     701                 :            :         }
     702                 :            :         *buf = 0;
     703                 :            :         *fw_size_p = fw_size - len;
     704                 :            :         *fw_data_p = p;
     705                 :            :         remove_trail_spaces(buf);
     706                 :            :         return 1;
     707                 :            : }
     708                 :            : 
     709                 :            : /**
     710                 :            :  * snd_hda_load_patch - load a "patch" firmware file and parse it
     711                 :            :  * @bus: HD-audio bus
     712                 :            :  * @fw_size: the firmware byte size
     713                 :            :  * @fw_buf: the firmware data
     714                 :            :  */
     715                 :            : int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
     716                 :            : {
     717                 :            :         char buf[128];
     718                 :            :         struct hda_codec *codec;
     719                 :            :         int line_mode;
     720                 :            : 
     721                 :            :         line_mode = LINE_MODE_NONE;
     722                 :            :         codec = NULL;
     723                 :            :         while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
     724                 :            :                 if (!*buf || *buf == '#' || *buf == '\n')
     725                 :            :                         continue;
     726                 :            :                 if (*buf == '[')
     727                 :            :                         line_mode = parse_line_mode(buf, bus);
     728                 :            :                 else if (patch_items[line_mode].parser &&
     729                 :            :                          (codec || line_mode <= LINE_MODE_CODEC))
     730                 :            :                         patch_items[line_mode].parser(buf, bus, &codec);
     731                 :            :         }
     732                 :            :         return 0;
     733                 :            : }
     734                 :            : EXPORT_SYMBOL_GPL(snd_hda_load_patch);
     735                 :            : #endif /* CONFIG_SND_HDA_PATCH_LOADER */
     736                 :            : 
     737                 :            : /*
     738                 :            :  * sysfs entries
     739                 :            :  */
     740                 :            : static struct attribute *hda_dev_attrs[] = {
     741                 :            :         &dev_attr_vendor_id.attr,
     742                 :            :         &dev_attr_subsystem_id.attr,
     743                 :            :         &dev_attr_revision_id.attr,
     744                 :            :         &dev_attr_afg.attr,
     745                 :            :         &dev_attr_mfg.attr,
     746                 :            :         &dev_attr_vendor_name.attr,
     747                 :            :         &dev_attr_chip_name.attr,
     748                 :            :         &dev_attr_modelname.attr,
     749                 :            :         &dev_attr_init_pin_configs.attr,
     750                 :            :         &dev_attr_driver_pin_configs.attr,
     751                 :            : #ifdef CONFIG_PM
     752                 :            :         &dev_attr_power_on_acct.attr,
     753                 :            :         &dev_attr_power_off_acct.attr,
     754                 :            : #endif
     755                 :            : #ifdef CONFIG_SND_HDA_RECONFIG
     756                 :            :         &dev_attr_init_verbs.attr,
     757                 :            :         &dev_attr_hints.attr,
     758                 :            :         &dev_attr_user_pin_configs.attr,
     759                 :            :         &dev_attr_reconfig.attr,
     760                 :            :         &dev_attr_clear.attr,
     761                 :            : #endif
     762                 :            :         NULL
     763                 :            : };
     764                 :            : 
     765                 :            : static const struct attribute_group hda_dev_attr_group = {
     766                 :            :         .attrs  = hda_dev_attrs,
     767                 :            : };
     768                 :            : 
     769                 :            : const struct attribute_group *snd_hda_dev_attr_groups[] = {
     770                 :            :         &hda_dev_attr_group,
     771                 :            :         NULL
     772                 :            : };
     773                 :            : 
     774                 :          0 : void snd_hda_sysfs_init(struct hda_codec *codec)
     775                 :            : {
     776                 :          0 :         mutex_init(&codec->user_mutex);
     777                 :            : #ifdef CONFIG_SND_HDA_RECONFIG
     778                 :            :         snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
     779                 :            :         snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
     780                 :            :         snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
     781                 :            : #endif
     782                 :          0 : }
     783                 :            : 
     784                 :          0 : void snd_hda_sysfs_clear(struct hda_codec *codec)
     785                 :            : {
     786                 :            : #ifdef CONFIG_SND_HDA_RECONFIG
     787                 :            :         struct hda_hint *hint;
     788                 :            :         int i;
     789                 :            : 
     790                 :            :         /* clear init verbs */
     791                 :            :         snd_array_free(&codec->init_verbs);
     792                 :            :         /* clear hints */
     793                 :            :         snd_array_for_each(&codec->hints, i, hint) {
     794                 :            :                 kfree(hint->key); /* we don't need to free hint->val */
     795                 :            :         }
     796                 :            :         snd_array_free(&codec->hints);
     797                 :            :         snd_array_free(&codec->user_pins);
     798                 :            : #endif
     799                 :          0 : }

Generated by: LCOV version 1.14