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