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/firmware.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 /*__devinit*/ 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        snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
 152        snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
 153        snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
 154
 155        return 0;
 156}
 157
 158#ifdef CONFIG_SND_HDA_POWER_SAVE
 159static ssize_t power_on_acct_show(struct device *dev,
 160                                  struct device_attribute *attr,
 161                                  char *buf)
 162{
 163        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 164        struct hda_codec *codec = hwdep->private_data;
 165        snd_hda_update_power_acct(codec);
 166        return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
 167}
 168
 169static ssize_t power_off_acct_show(struct device *dev,
 170                                   struct device_attribute *attr,
 171                                   char *buf)
 172{
 173        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 174        struct hda_codec *codec = hwdep->private_data;
 175        snd_hda_update_power_acct(codec);
 176        return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
 177}
 178
 179static struct device_attribute power_attrs[] = {
 180        __ATTR_RO(power_on_acct),
 181        __ATTR_RO(power_off_acct),
 182};
 183
 184int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
 185{
 186        struct snd_hwdep *hwdep = codec->hwdep;
 187        int i;
 188
 189        for (i = 0; i < ARRAY_SIZE(power_attrs); i++)
 190                snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
 191                                          hwdep->device, &power_attrs[i]);
 192        return 0;
 193}
 194#endif /* CONFIG_SND_HDA_POWER_SAVE */
 195
 196#ifdef CONFIG_SND_HDA_RECONFIG
 197
 198/*
 199 * sysfs interface
 200 */
 201
 202static int clear_codec(struct hda_codec *codec)
 203{
 204        int err;
 205
 206        err = snd_hda_codec_reset(codec);
 207        if (err < 0) {
 208                snd_printk(KERN_ERR "The codec is being used, can't free.\n");
 209                return err;
 210        }
 211        clear_hwdep_elements(codec);
 212        return 0;
 213}
 214
 215static int reconfig_codec(struct hda_codec *codec)
 216{
 217        int err;
 218
 219        snd_hda_power_up(codec);
 220        snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
 221        err = snd_hda_codec_reset(codec);
 222        if (err < 0) {
 223                snd_printk(KERN_ERR
 224                           "The codec is being used, can't reconfigure.\n");
 225                goto error;
 226        }
 227        err = snd_hda_codec_configure(codec);
 228        if (err < 0)
 229                goto error;
 230        /* rebuild PCMs */
 231        err = snd_hda_codec_build_pcms(codec);
 232        if (err < 0)
 233                goto error;
 234        /* rebuild mixers */
 235        err = snd_hda_codec_build_controls(codec);
 236        if (err < 0)
 237                goto error;
 238        err = snd_card_register(codec->bus->card);
 239 error:
 240        snd_hda_power_down(codec);
 241        return err;
 242}
 243
 244/*
 245 * allocate a string at most len chars, and remove the trailing EOL
 246 */
 247static char *kstrndup_noeol(const char *src, size_t len)
 248{
 249        char *s = kstrndup(src, len, GFP_KERNEL);
 250        char *p;
 251        if (!s)
 252                return NULL;
 253        p = strchr(s, '\n');
 254        if (p)
 255                *p = 0;
 256        return s;
 257}
 258
 259#define CODEC_INFO_SHOW(type)                                   \
 260static ssize_t type##_show(struct device *dev,                  \
 261                           struct device_attribute *attr,       \
 262                           char *buf)                           \
 263{                                                               \
 264        struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
 265        struct hda_codec *codec = hwdep->private_data;          \
 266        return sprintf(buf, "0x%x\n", codec->type);             \
 267}
 268
 269#define CODEC_INFO_STR_SHOW(type)                               \
 270static ssize_t type##_show(struct device *dev,                  \
 271                             struct device_attribute *attr,     \
 272                                        char *buf)              \
 273{                                                               \
 274        struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
 275        struct hda_codec *codec = hwdep->private_data;          \
 276        return sprintf(buf, "%s\n",                             \
 277                       codec->type ? codec->type : "");         \
 278}
 279
 280CODEC_INFO_SHOW(vendor_id);
 281CODEC_INFO_SHOW(subsystem_id);
 282CODEC_INFO_SHOW(revision_id);
 283CODEC_INFO_SHOW(afg);
 284CODEC_INFO_SHOW(mfg);
 285CODEC_INFO_STR_SHOW(vendor_name);
 286CODEC_INFO_STR_SHOW(chip_name);
 287CODEC_INFO_STR_SHOW(modelname);
 288
 289#define CODEC_INFO_STORE(type)                                  \
 290static ssize_t type##_store(struct device *dev,                 \
 291                            struct device_attribute *attr,      \
 292                            const char *buf, size_t count)      \
 293{                                                               \
 294        struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
 295        struct hda_codec *codec = hwdep->private_data;          \
 296        unsigned long val;                                      \
 297        int err = strict_strtoul(buf, 0, &val);                 \
 298        if (err < 0)                                            \
 299                return err;                                     \
 300        codec->type = val;                                      \
 301        return count;                                           \
 302}
 303
 304#define CODEC_INFO_STR_STORE(type)                              \
 305static ssize_t type##_store(struct device *dev,                 \
 306                            struct device_attribute *attr,      \
 307                            const char *buf, size_t count)      \
 308{                                                               \
 309        struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
 310        struct hda_codec *codec = hwdep->private_data;          \
 311        char *s = kstrndup_noeol(buf, 64);                      \
 312        if (!s)                                                 \
 313                return -ENOMEM;                                 \
 314        kfree(codec->type);                                     \
 315        codec->type = s;                                        \
 316        return count;                                           \
 317}
 318
 319CODEC_INFO_STORE(vendor_id);
 320CODEC_INFO_STORE(subsystem_id);
 321CODEC_INFO_STORE(revision_id);
 322CODEC_INFO_STR_STORE(vendor_name);
 323CODEC_INFO_STR_STORE(chip_name);
 324CODEC_INFO_STR_STORE(modelname);
 325
 326#define CODEC_ACTION_STORE(type)                                \
 327static ssize_t type##_store(struct device *dev,                 \
 328                            struct device_attribute *attr,      \
 329                            const char *buf, size_t count)      \
 330{                                                               \
 331        struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
 332        struct hda_codec *codec = hwdep->private_data;          \
 333        int err = 0;                                            \
 334        if (*buf)                                               \
 335                err = type##_codec(codec);                      \
 336        return err < 0 ? err : count;                           \
 337}
 338
 339CODEC_ACTION_STORE(reconfig);
 340CODEC_ACTION_STORE(clear);
 341
 342static ssize_t init_verbs_show(struct device *dev,
 343                               struct device_attribute *attr,
 344                               char *buf)
 345{
 346        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 347        struct hda_codec *codec = hwdep->private_data;
 348        int i, len = 0;
 349        for (i = 0; i < codec->init_verbs.used; i++) {
 350                struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
 351                len += snprintf(buf + len, PAGE_SIZE - len,
 352                                "0x%02x 0x%03x 0x%04x\n",
 353                                v->nid, v->verb, v->param);
 354        }
 355        return len;
 356}
 357
 358static int parse_init_verbs(struct hda_codec *codec, const char *buf)
 359{
 360        struct hda_verb *v;
 361        int nid, verb, param;
 362
 363        if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
 364                return -EINVAL;
 365        if (!nid || !verb)
 366                return -EINVAL;
 367        v = snd_array_new(&codec->init_verbs);
 368        if (!v)
 369                return -ENOMEM;
 370        v->nid = nid;
 371        v->verb = verb;
 372        v->param = param;
 373        return 0;
 374}
 375
 376static ssize_t init_verbs_store(struct device *dev,
 377                                struct device_attribute *attr,
 378                                const char *buf, size_t count)
 379{
 380        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 381        struct hda_codec *codec = hwdep->private_data;
 382        int err = parse_init_verbs(codec, buf);
 383        if (err < 0)
 384                return err;
 385        return count;
 386}
 387
 388static ssize_t hints_show(struct device *dev,
 389                          struct device_attribute *attr,
 390                          char *buf)
 391{
 392        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 393        struct hda_codec *codec = hwdep->private_data;
 394        int i, len = 0;
 395        for (i = 0; i < codec->hints.used; i++) {
 396                struct hda_hint *hint = snd_array_elem(&codec->hints, i);
 397                len += snprintf(buf + len, PAGE_SIZE - len,
 398                                "%s = %s\n", hint->key, hint->val);
 399        }
 400        return len;
 401}
 402
 403static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
 404{
 405        int i;
 406
 407        for (i = 0; i < codec->hints.used; i++) {
 408                struct hda_hint *hint = snd_array_elem(&codec->hints, i);
 409                if (!strcmp(hint->key, key))
 410                        return hint;
 411        }
 412        return NULL;
 413}
 414
 415static void remove_trail_spaces(char *str)
 416{
 417        char *p;
 418        if (!*str)
 419                return;
 420        p = str + strlen(str) - 1;
 421        for (; isspace(*p); p--) {
 422                *p = 0;
 423                if (p == str)
 424                        return;
 425        }
 426}
 427
 428#define MAX_HINTS       1024
 429
 430static int parse_hints(struct hda_codec *codec, const char *buf)
 431{
 432        char *key, *val;
 433        struct hda_hint *hint;
 434
 435        buf = skip_spaces(buf);
 436        if (!*buf || *buf == '#' || *buf == '\n')
 437                return 0;
 438        if (*buf == '=')
 439                return -EINVAL;
 440        key = kstrndup_noeol(buf, 1024);
 441        if (!key)
 442                return -ENOMEM;
 443        /* extract key and val */
 444        val = strchr(key, '=');
 445        if (!val) {
 446                kfree(key);
 447                return -EINVAL;
 448        }
 449        *val++ = 0;
 450        val = skip_spaces(val);
 451        remove_trail_spaces(key);
 452        remove_trail_spaces(val);
 453        hint = get_hint(codec, key);
 454        if (hint) {
 455                /* replace */
 456                kfree(hint->key);
 457                hint->key = key;
 458                hint->val = val;
 459                return 0;
 460        }
 461        /* allocate a new hint entry */
 462        if (codec->hints.used >= MAX_HINTS)
 463                hint = NULL;
 464        else
 465                hint = snd_array_new(&codec->hints);
 466        if (!hint) {
 467                kfree(key);
 468                return -ENOMEM;
 469        }
 470        hint->key = key;
 471        hint->val = val;
 472        return 0;
 473}
 474
 475static ssize_t hints_store(struct device *dev,
 476                           struct device_attribute *attr,
 477                           const char *buf, size_t count)
 478{
 479        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 480        struct hda_codec *codec = hwdep->private_data;
 481        int err = parse_hints(codec, buf);
 482        if (err < 0)
 483                return err;
 484        return count;
 485}
 486
 487static ssize_t pin_configs_show(struct hda_codec *codec,
 488                                struct snd_array *list,
 489                                char *buf)
 490{
 491        int i, len = 0;
 492        for (i = 0; i < list->used; i++) {
 493                struct hda_pincfg *pin = snd_array_elem(list, i);
 494                len += sprintf(buf + len, "0x%02x 0x%08x\n",
 495                               pin->nid, pin->cfg);
 496        }
 497        return len;
 498}
 499
 500static ssize_t init_pin_configs_show(struct device *dev,
 501                                     struct device_attribute *attr,
 502                                     char *buf)
 503{
 504        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 505        struct hda_codec *codec = hwdep->private_data;
 506        return pin_configs_show(codec, &codec->init_pins, buf);
 507}
 508
 509static ssize_t user_pin_configs_show(struct device *dev,
 510                                     struct device_attribute *attr,
 511                                     char *buf)
 512{
 513        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 514        struct hda_codec *codec = hwdep->private_data;
 515        return pin_configs_show(codec, &codec->user_pins, buf);
 516}
 517
 518static ssize_t driver_pin_configs_show(struct device *dev,
 519                                       struct device_attribute *attr,
 520                                       char *buf)
 521{
 522        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 523        struct hda_codec *codec = hwdep->private_data;
 524        return pin_configs_show(codec, &codec->driver_pins, buf);
 525}
 526
 527#define MAX_PIN_CONFIGS         32
 528
 529static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
 530{
 531        int nid, cfg;
 532
 533        if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
 534                return -EINVAL;
 535        if (!nid)
 536                return -EINVAL;
 537        return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
 538}
 539
 540static ssize_t user_pin_configs_store(struct device *dev,
 541                                      struct device_attribute *attr,
 542                                      const char *buf, size_t count)
 543{
 544        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
 545        struct hda_codec *codec = hwdep->private_data;
 546        int err = parse_user_pin_configs(codec, buf);
 547        if (err < 0)
 548                return err;
 549        return count;
 550}
 551
 552#define CODEC_ATTR_RW(type) \
 553        __ATTR(type, 0644, type##_show, type##_store)
 554#define CODEC_ATTR_RO(type) \
 555        __ATTR_RO(type)
 556#define CODEC_ATTR_WO(type) \
 557        __ATTR(type, 0200, NULL, type##_store)
 558
 559static struct device_attribute codec_attrs[] = {
 560        CODEC_ATTR_RW(vendor_id),
 561        CODEC_ATTR_RW(subsystem_id),
 562        CODEC_ATTR_RW(revision_id),
 563        CODEC_ATTR_RO(afg),
 564        CODEC_ATTR_RO(mfg),
 565        CODEC_ATTR_RW(vendor_name),
 566        CODEC_ATTR_RW(chip_name),
 567        CODEC_ATTR_RW(modelname),
 568        CODEC_ATTR_RW(init_verbs),
 569        CODEC_ATTR_RW(hints),
 570        CODEC_ATTR_RO(init_pin_configs),
 571        CODEC_ATTR_RW(user_pin_configs),
 572        CODEC_ATTR_RO(driver_pin_configs),
 573        CODEC_ATTR_WO(reconfig),
 574        CODEC_ATTR_WO(clear),
 575};
 576
 577/*
 578 * create sysfs files on hwdep directory
 579 */
 580int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
 581{
 582        struct snd_hwdep *hwdep = codec->hwdep;
 583        int i;
 584
 585        for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
 586                snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
 587                                          hwdep->device, &codec_attrs[i]);
 588        return 0;
 589}
 590
 591/*
 592 * Look for hint string
 593 */
 594const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
 595{
 596        struct hda_hint *hint = get_hint(codec, key);
 597        return hint ? hint->val : NULL;
 598}
 599EXPORT_SYMBOL_HDA(snd_hda_get_hint);
 600
 601int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
 602{
 603        const char *p = snd_hda_get_hint(codec, key);
 604        if (!p || !*p)
 605                return -ENOENT;
 606        switch (toupper(*p)) {
 607        case 'T': /* true */
 608        case 'Y': /* yes */
 609        case '1':
 610                return 1;
 611        }
 612        return 0;
 613}
 614EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
 615
 616#endif /* CONFIG_SND_HDA_RECONFIG */
 617
 618#ifdef CONFIG_SND_HDA_PATCH_LOADER
 619
 620/* parser mode */
 621enum {
 622        LINE_MODE_NONE,
 623        LINE_MODE_CODEC,
 624        LINE_MODE_MODEL,
 625        LINE_MODE_PINCFG,
 626        LINE_MODE_VERB,
 627        LINE_MODE_HINT,
 628        LINE_MODE_VENDOR_ID,
 629        LINE_MODE_SUBSYSTEM_ID,
 630        LINE_MODE_REVISION_ID,
 631        LINE_MODE_CHIP_NAME,
 632        NUM_LINE_MODES,
 633};
 634
 635static inline int strmatch(const char *a, const char *b)
 636{
 637        return strnicmp(a, b, strlen(b)) == 0;
 638}
 639
 640/* parse the contents after the line "[codec]"
 641 * accept only the line with three numbers, and assign the current codec
 642 */
 643static void parse_codec_mode(char *buf, struct hda_bus *bus,
 644                             struct hda_codec **codecp)
 645{
 646        unsigned int vendorid, subid, caddr;
 647        struct hda_codec *codec;
 648
 649        *codecp = NULL;
 650        if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
 651                list_for_each_entry(codec, &bus->codec_list, list) {
 652                        if (codec->vendor_id == vendorid &&
 653                            codec->subsystem_id == subid &&
 654                            codec->addr == caddr) {
 655                                *codecp = codec;
 656                                break;
 657                        }
 658                }
 659        }
 660}
 661
 662/* parse the contents after the other command tags, [pincfg], [verb],
 663 * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
 664 * just pass to the sysfs helper (only when any codec was specified)
 665 */
 666static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
 667                              struct hda_codec **codecp)
 668{
 669        parse_user_pin_configs(*codecp, buf);
 670}
 671
 672static void parse_verb_mode(char *buf, struct hda_bus *bus,
 673                            struct hda_codec **codecp)
 674{
 675        parse_init_verbs(*codecp, buf);
 676}
 677
 678static void parse_hint_mode(char *buf, struct hda_bus *bus,
 679                            struct hda_codec **codecp)
 680{
 681        parse_hints(*codecp, buf);
 682}
 683
 684static void parse_model_mode(char *buf, struct hda_bus *bus,
 685                             struct hda_codec **codecp)
 686{
 687        kfree((*codecp)->modelname);
 688        (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
 689}
 690
 691static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
 692                                 struct hda_codec **codecp)
 693{
 694        kfree((*codecp)->chip_name);
 695        (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
 696}
 697
 698#define DEFINE_PARSE_ID_MODE(name) \
 699static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
 700                                 struct hda_codec **codecp) \
 701{ \
 702        unsigned long val; \
 703        if (!strict_strtoul(buf, 0, &val)) \
 704                (*codecp)->name = val; \
 705}
 706
 707DEFINE_PARSE_ID_MODE(vendor_id);
 708DEFINE_PARSE_ID_MODE(subsystem_id);
 709DEFINE_PARSE_ID_MODE(revision_id);
 710
 711
 712struct hda_patch_item {
 713        const char *tag;
 714        void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
 715        int need_codec;
 716};
 717
 718static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
 719        [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 },
 720        [LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 },
 721        [LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 },
 722        [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 },
 723        [LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 },
 724        [LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 },
 725        [LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 },
 726        [LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 },
 727        [LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 },
 728};
 729
 730/* check the line starting with '[' -- change the parser mode accodingly */
 731static int parse_line_mode(char *buf, struct hda_bus *bus)
 732{
 733        int i;
 734        for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
 735                if (!patch_items[i].tag)
 736                        continue;
 737                if (strmatch(buf, patch_items[i].tag))
 738                        return i;
 739        }
 740        return LINE_MODE_NONE;
 741}
 742
 743/* copy one line from the buffer in fw, and update the fields in fw
 744 * return zero if it reaches to the end of the buffer, or non-zero
 745 * if successfully copied a line
 746 *
 747 * the spaces at the beginning and the end of the line are stripped
 748 */
 749static int get_line_from_fw(char *buf, int size, struct firmware *fw)
 750{
 751        int len;
 752        const char *p = fw->data;
 753        while (isspace(*p) && fw->size) {
 754                p++;
 755                fw->size--;
 756        }
 757        if (!fw->size)
 758                return 0;
 759        if (size < fw->size)
 760                size = fw->size;
 761
 762        for (len = 0; len < fw->size; len++) {
 763                if (!*p)
 764                        break;
 765                if (*p == '\n') {
 766                        p++;
 767                        len++;
 768                        break;
 769                }
 770                if (len < size)
 771                        *buf++ = *p++;
 772        }
 773        *buf = 0;
 774        fw->size -= len;
 775        fw->data = p;
 776        remove_trail_spaces(buf);
 777        return 1;
 778}
 779
 780/*
 781 * load a "patch" firmware file and parse it
 782 */
 783int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
 784{
 785        int err;
 786        const struct firmware *fw;
 787        struct firmware tmp;
 788        char buf[128];
 789        struct hda_codec *codec;
 790        int line_mode;
 791        struct device *dev = bus->card->dev;
 792
 793        if (snd_BUG_ON(!dev))
 794                return -ENODEV;
 795        err = request_firmware(&fw, patch, dev);
 796        if (err < 0) {
 797                printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n",
 798                       patch);
 799                return err;
 800        }
 801
 802        tmp = *fw;
 803        line_mode = LINE_MODE_NONE;
 804        codec = NULL;
 805        while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) {
 806                if (!*buf || *buf == '#' || *buf == '\n')
 807                        continue;
 808                if (*buf == '[')
 809                        line_mode = parse_line_mode(buf, bus);
 810                else if (patch_items[line_mode].parser &&
 811                         (codec || !patch_items[line_mode].need_codec))
 812                        patch_items[line_mode].parser(buf, bus, &codec);
 813        }
 814        release_firmware(fw);
 815        return 0;
 816}
 817EXPORT_SYMBOL_HDA(snd_hda_load_patch);
 818#endif /* CONFIG_SND_HDA_PATCH_LOADER */
 819