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