blob: 896d116ca9514f9de996f98619fd03b2e81cf484 [file] [log] [blame]
Takashi Iwai28073142007-07-27 18:58:06 +02001/*
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
Takashi Iwai28073142007-07-27 18:58:06 +020021#include <linux/init.h>
22#include <linux/slab.h>
Takashi Iwai28073142007-07-27 18:58:06 +020023#include <linux/compat.h>
24#include <linux/mutex.h>
Takashi Iwai1e1be432008-07-30 15:01:46 +020025#include <linux/ctype.h>
André Goddard Rosae7d28602009-12-14 18:01:06 -080026#include <linux/string.h>
Paul Gortmakerd81a6d72011-09-22 09:34:58 -040027#include <linux/export.h>
Takashi Iwai28073142007-07-27 18:58:06 +020028#include <sound/core.h>
29#include "hda_codec.h"
30#include "hda_local.h"
31#include <sound/hda_hwdep.h>
Takashi Iwaid7ffba12008-07-30 15:01:46 +020032#include <sound/minors.h>
Takashi Iwai28073142007-07-27 18:58:06 +020033
Takashi Iwai43b62712009-03-02 14:25:17 +010034/* hint string pair */
35struct hda_hint {
36 const char *key;
37 const char *val; /* contained in the same alloc as key */
38};
39
Takashi Iwai28073142007-07-27 18:58:06 +020040/*
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{
Takashi Iwai312d0452007-07-31 11:08:10 +020094 return hda_hwdep_ioctl(hw, file, cmd, (unsigned long)compat_ptr(arg));
Takashi Iwai28073142007-07-27 18:58:06 +020095}
96#endif
97
98static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
99{
Takashi Iwai62cf8722008-05-20 12:15:15 +0200100#ifndef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwai28073142007-07-27 18:58:06 +0200101 if (!capable(CAP_SYS_RAWIO))
102 return -EACCES;
103#endif
104 return 0;
105}
106
Takashi Iwai11aeff02008-07-30 15:01:46 +0200107static void clear_hwdep_elements(struct hda_codec *codec)
108{
Takashi Iwai1e1be432008-07-30 15:01:46 +0200109 int i;
110
Takashi Iwai11aeff02008-07-30 15:01:46 +0200111 /* clear init verbs */
112 snd_array_free(&codec->init_verbs);
Takashi Iwai1e1be432008-07-30 15:01:46 +0200113 /* clear hints */
Takashi Iwai43b62712009-03-02 14:25:17 +0100114 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 }
Takashi Iwai1e1be432008-07-30 15:01:46 +0200118 snd_array_free(&codec->hints);
Takashi Iwai346ff702009-02-23 09:42:57 +0100119 snd_array_free(&codec->user_pins);
Takashi Iwai11aeff02008-07-30 15:01:46 +0200120}
121
122static void hwdep_free(struct snd_hwdep *hwdep)
123{
124 clear_hwdep_elements(hwdep->private_data);
125}
126
Takashi Iwaicaa751b2014-02-25 08:30:50 +0100127static const struct attribute_group *snd_hda_dev_attr_groups[];
128
Takashi Iwai6a0f56a2012-12-07 07:41:56 +0100129int snd_hda_create_hwdep(struct hda_codec *codec)
Takashi Iwai28073142007-07-27 18:58:06 +0200130{
131 char hwname[16];
132 struct snd_hwdep *hwdep;
133 int err;
134
135 sprintf(hwname, "HDA Codec %d", codec->addr);
136 err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep);
137 if (err < 0)
138 return err;
139 codec->hwdep = hwdep;
140 sprintf(hwdep->name, "HDA Codec %d", codec->addr);
141 hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
142 hwdep->private_data = codec;
Takashi Iwai11aeff02008-07-30 15:01:46 +0200143 hwdep->private_free = hwdep_free;
Takashi Iwai28073142007-07-27 18:58:06 +0200144 hwdep->exclusive = 1;
Takashi Iwaicaa751b2014-02-25 08:30:50 +0100145 hwdep->groups = snd_hda_dev_attr_groups;
Takashi Iwai28073142007-07-27 18:58:06 +0200146
147 hwdep->ops.open = hda_hwdep_open;
148 hwdep->ops.ioctl = hda_hwdep_ioctl;
149#ifdef CONFIG_COMPAT
150 hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
151#endif
152
Takashi Iwai09b70e82013-01-10 18:21:56 +0100153 mutex_init(&codec->user_mutex);
Takashi Iwai11aeff02008-07-30 15:01:46 +0200154 snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
Takashi Iwai43b62712009-03-02 14:25:17 +0100155 snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
Takashi Iwai346ff702009-02-23 09:42:57 +0100156 snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
Takashi Iwai11aeff02008-07-30 15:01:46 +0200157
Takashi Iwai13aeaf62014-02-25 07:53:47 +0100158 /* link to codec */
159 hwdep->dev = &codec->dev;
160
Takashi Iwai28073142007-07-27 18:58:06 +0200161 return 0;
162}
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200163
Takashi Iwai83012a72012-08-24 18:38:08 +0200164#ifdef CONFIG_PM
Takashi Iwaia2f63092009-11-11 09:34:25 +0100165static ssize_t power_on_acct_show(struct device *dev,
166 struct device_attribute *attr,
167 char *buf)
168{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100169 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwaia2f63092009-11-11 09:34:25 +0100170 snd_hda_update_power_acct(codec);
171 return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
172}
173
174static ssize_t power_off_acct_show(struct device *dev,
175 struct device_attribute *attr,
176 char *buf)
177{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100178 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwaia2f63092009-11-11 09:34:25 +0100179 snd_hda_update_power_acct(codec);
180 return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
181}
182
Takashi Iwaicaa751b2014-02-25 08:30:50 +0100183static DEVICE_ATTR_RO(power_on_acct);
184static DEVICE_ATTR_RO(power_off_acct);
Takashi Iwai83012a72012-08-24 18:38:08 +0200185#endif /* CONFIG_PM */
Takashi Iwaia2f63092009-11-11 09:34:25 +0100186
Takashi Iwaie7ee0582008-11-21 09:26:20 +0100187#ifdef CONFIG_SND_HDA_RECONFIG
188
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200189/*
190 * sysfs interface
191 */
192
193static int clear_codec(struct hda_codec *codec)
194{
Takashi Iwaia65d6292009-02-23 16:57:04 +0100195 int err;
196
197 err = snd_hda_codec_reset(codec);
198 if (err < 0) {
199 snd_printk(KERN_ERR "The codec is being used, can't free.\n");
200 return err;
201 }
Takashi Iwai11aeff02008-07-30 15:01:46 +0200202 clear_hwdep_elements(codec);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200203 return 0;
204}
205
206static int reconfig_codec(struct hda_codec *codec)
207{
208 int err;
209
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100210 snd_hda_power_up(codec);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200211 snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
Takashi Iwaia65d6292009-02-23 16:57:04 +0100212 err = snd_hda_codec_reset(codec);
213 if (err < 0) {
214 snd_printk(KERN_ERR
215 "The codec is being used, can't reconfigure.\n");
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100216 goto error;
Takashi Iwaia65d6292009-02-23 16:57:04 +0100217 }
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200218 err = snd_hda_codec_configure(codec);
219 if (err < 0)
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100220 goto error;
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200221 /* rebuild PCMs */
Takashi Iwai529bd6c2008-11-27 14:17:01 +0100222 err = snd_hda_codec_build_pcms(codec);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200223 if (err < 0)
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100224 goto error;
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200225 /* rebuild mixers */
226 err = snd_hda_codec_build_controls(codec);
227 if (err < 0)
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100228 goto error;
229 err = snd_card_register(codec->bus->card);
230 error:
231 snd_hda_power_down(codec);
232 return err;
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200233}
234
235/*
236 * allocate a string at most len chars, and remove the trailing EOL
237 */
238static char *kstrndup_noeol(const char *src, size_t len)
239{
240 char *s = kstrndup(src, len, GFP_KERNEL);
241 char *p;
242 if (!s)
243 return NULL;
244 p = strchr(s, '\n');
245 if (p)
246 *p = 0;
247 return s;
248}
249
250#define CODEC_INFO_SHOW(type) \
251static ssize_t type##_show(struct device *dev, \
252 struct device_attribute *attr, \
253 char *buf) \
254{ \
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100255 struct hda_codec *codec = dev_get_drvdata(dev); \
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200256 return sprintf(buf, "0x%x\n", codec->type); \
257}
258
259#define CODEC_INFO_STR_SHOW(type) \
260static ssize_t type##_show(struct device *dev, \
261 struct device_attribute *attr, \
262 char *buf) \
263{ \
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100264 struct hda_codec *codec = dev_get_drvdata(dev); \
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200265 return sprintf(buf, "%s\n", \
266 codec->type ? codec->type : ""); \
267}
268
269CODEC_INFO_SHOW(vendor_id);
270CODEC_INFO_SHOW(subsystem_id);
271CODEC_INFO_SHOW(revision_id);
272CODEC_INFO_SHOW(afg);
273CODEC_INFO_SHOW(mfg);
Takashi Iwai812a2cc2009-05-16 10:00:49 +0200274CODEC_INFO_STR_SHOW(vendor_name);
275CODEC_INFO_STR_SHOW(chip_name);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200276CODEC_INFO_STR_SHOW(modelname);
277
278#define CODEC_INFO_STORE(type) \
279static ssize_t type##_store(struct device *dev, \
280 struct device_attribute *attr, \
281 const char *buf, size_t count) \
282{ \
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100283 struct hda_codec *codec = dev_get_drvdata(dev); \
Takashi Iwai014c41f2009-12-27 13:53:24 +0100284 unsigned long val; \
Jingoo Hanb785a492013-07-19 16:24:59 +0900285 int err = kstrtoul(buf, 0, &val); \
Takashi Iwai014c41f2009-12-27 13:53:24 +0100286 if (err < 0) \
287 return err; \
288 codec->type = val; \
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200289 return count; \
290}
291
292#define CODEC_INFO_STR_STORE(type) \
293static ssize_t type##_store(struct device *dev, \
294 struct device_attribute *attr, \
295 const char *buf, size_t count) \
296{ \
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100297 struct hda_codec *codec = dev_get_drvdata(dev); \
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200298 char *s = kstrndup_noeol(buf, 64); \
299 if (!s) \
300 return -ENOMEM; \
301 kfree(codec->type); \
302 codec->type = s; \
303 return count; \
304}
305
306CODEC_INFO_STORE(vendor_id);
307CODEC_INFO_STORE(subsystem_id);
308CODEC_INFO_STORE(revision_id);
Takashi Iwai812a2cc2009-05-16 10:00:49 +0200309CODEC_INFO_STR_STORE(vendor_name);
310CODEC_INFO_STR_STORE(chip_name);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200311CODEC_INFO_STR_STORE(modelname);
312
313#define CODEC_ACTION_STORE(type) \
314static ssize_t type##_store(struct device *dev, \
315 struct device_attribute *attr, \
316 const char *buf, size_t count) \
317{ \
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100318 struct hda_codec *codec = dev_get_drvdata(dev); \
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200319 int err = 0; \
320 if (*buf) \
321 err = type##_codec(codec); \
322 return err < 0 ? err : count; \
323}
324
325CODEC_ACTION_STORE(reconfig);
326CODEC_ACTION_STORE(clear);
327
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100328static ssize_t init_verbs_show(struct device *dev,
329 struct device_attribute *attr,
330 char *buf)
331{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100332 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100333 int i, len = 0;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100334 mutex_lock(&codec->user_mutex);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100335 for (i = 0; i < codec->init_verbs.used; i++) {
336 struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
337 len += snprintf(buf + len, PAGE_SIZE - len,
338 "0x%02x 0x%03x 0x%04x\n",
339 v->nid, v->verb, v->param);
340 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100341 mutex_unlock(&codec->user_mutex);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100342 return len;
343}
344
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200345static int parse_init_verbs(struct hda_codec *codec, const char *buf)
Takashi Iwai11aeff02008-07-30 15:01:46 +0200346{
Takashi Iwai55290e12009-02-20 15:59:01 +0100347 struct hda_verb *v;
348 int nid, verb, param;
Takashi Iwai11aeff02008-07-30 15:01:46 +0200349
Takashi Iwai55290e12009-02-20 15:59:01 +0100350 if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
351 return -EINVAL;
352 if (!nid || !verb)
Takashi Iwai11aeff02008-07-30 15:01:46 +0200353 return -EINVAL;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100354 mutex_lock(&codec->user_mutex);
Takashi Iwai11aeff02008-07-30 15:01:46 +0200355 v = snd_array_new(&codec->init_verbs);
Takashi Iwai09b70e82013-01-10 18:21:56 +0100356 if (!v) {
357 mutex_unlock(&codec->user_mutex);
Takashi Iwai11aeff02008-07-30 15:01:46 +0200358 return -ENOMEM;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100359 }
Takashi Iwai55290e12009-02-20 15:59:01 +0100360 v->nid = nid;
361 v->verb = verb;
362 v->param = param;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100363 mutex_unlock(&codec->user_mutex);
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200364 return 0;
365}
366
367static ssize_t init_verbs_store(struct device *dev,
368 struct device_attribute *attr,
369 const char *buf, size_t count)
370{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100371 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200372 int err = parse_init_verbs(codec, buf);
373 if (err < 0)
374 return err;
Takashi Iwai11aeff02008-07-30 15:01:46 +0200375 return count;
376}
377
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100378static ssize_t hints_show(struct device *dev,
379 struct device_attribute *attr,
380 char *buf)
381{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100382 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100383 int i, len = 0;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100384 mutex_lock(&codec->user_mutex);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100385 for (i = 0; i < codec->hints.used; i++) {
386 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
387 len += snprintf(buf + len, PAGE_SIZE - len,
388 "%s = %s\n", hint->key, hint->val);
389 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100390 mutex_unlock(&codec->user_mutex);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100391 return len;
392}
393
Takashi Iwai43b62712009-03-02 14:25:17 +0100394static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
395{
396 int i;
397
398 for (i = 0; i < codec->hints.used; i++) {
399 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
400 if (!strcmp(hint->key, key))
401 return hint;
402 }
403 return NULL;
404}
405
406static void remove_trail_spaces(char *str)
407{
408 char *p;
409 if (!*str)
410 return;
411 p = str + strlen(str) - 1;
412 for (; isspace(*p); p--) {
413 *p = 0;
414 if (p == str)
415 return;
416 }
417}
418
419#define MAX_HINTS 1024
420
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200421static int parse_hints(struct hda_codec *codec, const char *buf)
Takashi Iwai1e1be432008-07-30 15:01:46 +0200422{
Takashi Iwai43b62712009-03-02 14:25:17 +0100423 char *key, *val;
424 struct hda_hint *hint;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100425 int err = 0;
Takashi Iwai1e1be432008-07-30 15:01:46 +0200426
André Goddard Rosae7d28602009-12-14 18:01:06 -0800427 buf = skip_spaces(buf);
Takashi Iwai43b62712009-03-02 14:25:17 +0100428 if (!*buf || *buf == '#' || *buf == '\n')
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200429 return 0;
Takashi Iwai43b62712009-03-02 14:25:17 +0100430 if (*buf == '=')
431 return -EINVAL;
432 key = kstrndup_noeol(buf, 1024);
433 if (!key)
Takashi Iwai1e1be432008-07-30 15:01:46 +0200434 return -ENOMEM;
Takashi Iwai43b62712009-03-02 14:25:17 +0100435 /* extract key and val */
436 val = strchr(key, '=');
437 if (!val) {
438 kfree(key);
439 return -EINVAL;
440 }
441 *val++ = 0;
André Goddard Rosae7d28602009-12-14 18:01:06 -0800442 val = skip_spaces(val);
Takashi Iwai43b62712009-03-02 14:25:17 +0100443 remove_trail_spaces(key);
444 remove_trail_spaces(val);
Takashi Iwai09b70e82013-01-10 18:21:56 +0100445 mutex_lock(&codec->user_mutex);
Takashi Iwai43b62712009-03-02 14:25:17 +0100446 hint = get_hint(codec, key);
447 if (hint) {
448 /* replace */
449 kfree(hint->key);
450 hint->key = key;
451 hint->val = val;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100452 goto unlock;
Takashi Iwai43b62712009-03-02 14:25:17 +0100453 }
454 /* allocate a new hint entry */
455 if (codec->hints.used >= MAX_HINTS)
456 hint = NULL;
457 else
458 hint = snd_array_new(&codec->hints);
Takashi Iwai09b70e82013-01-10 18:21:56 +0100459 if (hint) {
460 hint->key = key;
461 hint->val = val;
462 } else {
463 err = -ENOMEM;
Takashi Iwai1e1be432008-07-30 15:01:46 +0200464 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100465 unlock:
466 mutex_unlock(&codec->user_mutex);
467 if (err)
468 kfree(key);
469 return err;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200470}
471
472static ssize_t hints_store(struct device *dev,
473 struct device_attribute *attr,
474 const char *buf, size_t count)
475{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100476 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200477 int err = parse_hints(codec, buf);
478 if (err < 0)
479 return err;
Takashi Iwai1e1be432008-07-30 15:01:46 +0200480 return count;
481}
482
Takashi Iwai3be14142009-02-20 14:11:16 +0100483static ssize_t pin_configs_show(struct hda_codec *codec,
484 struct snd_array *list,
485 char *buf)
486{
487 int i, len = 0;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100488 mutex_lock(&codec->user_mutex);
Takashi Iwai3be14142009-02-20 14:11:16 +0100489 for (i = 0; i < list->used; i++) {
490 struct hda_pincfg *pin = snd_array_elem(list, i);
491 len += sprintf(buf + len, "0x%02x 0x%08x\n",
492 pin->nid, pin->cfg);
493 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100494 mutex_unlock(&codec->user_mutex);
Takashi Iwai3be14142009-02-20 14:11:16 +0100495 return len;
496}
497
498static ssize_t init_pin_configs_show(struct device *dev,
499 struct device_attribute *attr,
500 char *buf)
501{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100502 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwai3be14142009-02-20 14:11:16 +0100503 return pin_configs_show(codec, &codec->init_pins, buf);
504}
505
Takashi Iwai346ff702009-02-23 09:42:57 +0100506static ssize_t user_pin_configs_show(struct device *dev,
507 struct device_attribute *attr,
508 char *buf)
Takashi Iwai3be14142009-02-20 14:11:16 +0100509{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100510 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwai346ff702009-02-23 09:42:57 +0100511 return pin_configs_show(codec, &codec->user_pins, buf);
Takashi Iwai3be14142009-02-20 14:11:16 +0100512}
513
Takashi Iwai346ff702009-02-23 09:42:57 +0100514static ssize_t driver_pin_configs_show(struct device *dev,
515 struct device_attribute *attr,
516 char *buf)
Takashi Iwai3be14142009-02-20 14:11:16 +0100517{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100518 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwai346ff702009-02-23 09:42:57 +0100519 return pin_configs_show(codec, &codec->driver_pins, buf);
Takashi Iwai3be14142009-02-20 14:11:16 +0100520}
521
522#define MAX_PIN_CONFIGS 32
523
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200524static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
525{
Takashi Iwai09b70e82013-01-10 18:21:56 +0100526 int nid, cfg, err;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200527
528 if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
529 return -EINVAL;
530 if (!nid)
531 return -EINVAL;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100532 mutex_lock(&codec->user_mutex);
533 err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
534 mutex_unlock(&codec->user_mutex);
535 return err;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200536}
537
Takashi Iwai346ff702009-02-23 09:42:57 +0100538static ssize_t user_pin_configs_store(struct device *dev,
539 struct device_attribute *attr,
540 const char *buf, size_t count)
Takashi Iwai3be14142009-02-20 14:11:16 +0100541{
Takashi Iwaif806bdb2014-02-25 10:00:58 +0100542 struct hda_codec *codec = dev_get_drvdata(dev);
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200543 int err = parse_user_pin_configs(codec, buf);
Takashi Iwai3be14142009-02-20 14:11:16 +0100544 if (err < 0)
545 return err;
546 return count;
547}
548
Takashi Iwaicaa751b2014-02-25 08:30:50 +0100549static DEVICE_ATTR_RW(vendor_id);
550static DEVICE_ATTR_RW(subsystem_id);
551static DEVICE_ATTR_RW(revision_id);
552static DEVICE_ATTR_RO(afg);
553static DEVICE_ATTR_RO(mfg);
554static DEVICE_ATTR_RW(vendor_name);
555static DEVICE_ATTR_RW(chip_name);
556static DEVICE_ATTR_RW(modelname);
557static DEVICE_ATTR_RW(init_verbs);
558static DEVICE_ATTR_RW(hints);
559static DEVICE_ATTR_RO(init_pin_configs);
560static DEVICE_ATTR_RW(user_pin_configs);
561static DEVICE_ATTR_RO(driver_pin_configs);
562static DEVICE_ATTR_WO(reconfig);
563static DEVICE_ATTR_WO(clear);
Takashi Iwaie7ee0582008-11-21 09:26:20 +0100564
Takashi Iwai43b62712009-03-02 14:25:17 +0100565/*
566 * Look for hint string
567 */
568const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
569{
570 struct hda_hint *hint = get_hint(codec, key);
571 return hint ? hint->val : NULL;
572}
Takashi Iwai2698ea92013-12-18 07:45:52 +0100573EXPORT_SYMBOL_GPL(snd_hda_get_hint);
Takashi Iwai43b62712009-03-02 14:25:17 +0100574
575int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
576{
Takashi Iwai09b70e82013-01-10 18:21:56 +0100577 const char *p;
578 int ret;
579
580 mutex_lock(&codec->user_mutex);
581 p = snd_hda_get_hint(codec, key);
Takashi Iwai43b62712009-03-02 14:25:17 +0100582 if (!p || !*p)
Takashi Iwai09b70e82013-01-10 18:21:56 +0100583 ret = -ENOENT;
584 else {
585 switch (toupper(*p)) {
586 case 'T': /* true */
587 case 'Y': /* yes */
588 case '1':
589 ret = 1;
590 break;
591 default:
592 ret = 0;
593 break;
594 }
Takashi Iwai43b62712009-03-02 14:25:17 +0100595 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100596 mutex_unlock(&codec->user_mutex);
597 return ret;
Takashi Iwai43b62712009-03-02 14:25:17 +0100598}
Takashi Iwai2698ea92013-12-18 07:45:52 +0100599EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
Takashi Iwai43b62712009-03-02 14:25:17 +0100600
Takashi Iwaibc759722013-01-11 17:40:31 +0100601int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
602{
603 const char *p;
604 unsigned long val;
605 int ret;
606
607 mutex_lock(&codec->user_mutex);
608 p = snd_hda_get_hint(codec, key);
609 if (!p)
610 ret = -ENOENT;
Jingoo Hanb785a492013-07-19 16:24:59 +0900611 else if (kstrtoul(p, 0, &val))
Takashi Iwaibc759722013-01-11 17:40:31 +0100612 ret = -EINVAL;
613 else {
614 *valp = val;
615 ret = 0;
616 }
617 mutex_unlock(&codec->user_mutex);
618 return ret;
619}
Takashi Iwai2698ea92013-12-18 07:45:52 +0100620EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
Takashi Iwaie7ee0582008-11-21 09:26:20 +0100621#endif /* CONFIG_SND_HDA_RECONFIG */
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200622
623#ifdef CONFIG_SND_HDA_PATCH_LOADER
624
625/* parser mode */
626enum {
627 LINE_MODE_NONE,
628 LINE_MODE_CODEC,
629 LINE_MODE_MODEL,
630 LINE_MODE_PINCFG,
631 LINE_MODE_VERB,
632 LINE_MODE_HINT,
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100633 LINE_MODE_VENDOR_ID,
634 LINE_MODE_SUBSYSTEM_ID,
635 LINE_MODE_REVISION_ID,
636 LINE_MODE_CHIP_NAME,
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200637 NUM_LINE_MODES,
638};
639
640static inline int strmatch(const char *a, const char *b)
641{
642 return strnicmp(a, b, strlen(b)) == 0;
643}
644
645/* parse the contents after the line "[codec]"
646 * accept only the line with three numbers, and assign the current codec
647 */
648static void parse_codec_mode(char *buf, struct hda_bus *bus,
649 struct hda_codec **codecp)
650{
Takashi Iwaief940b02011-09-28 20:12:08 +0200651 int vendorid, subid, caddr;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200652 struct hda_codec *codec;
653
654 *codecp = NULL;
655 if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
656 list_for_each_entry(codec, &bus->codec_list, list) {
Takashi Iwaief940b02011-09-28 20:12:08 +0200657 if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
658 (subid <= 0 || codec->subsystem_id == subid) &&
David Henningsson2385b782010-06-02 16:56:41 +0200659 codec->addr == caddr) {
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200660 *codecp = codec;
661 break;
662 }
663 }
664 }
665}
666
667/* parse the contents after the other command tags, [pincfg], [verb],
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100668 * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200669 * just pass to the sysfs helper (only when any codec was specified)
670 */
671static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
672 struct hda_codec **codecp)
673{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200674 parse_user_pin_configs(*codecp, buf);
675}
676
677static void parse_verb_mode(char *buf, struct hda_bus *bus,
678 struct hda_codec **codecp)
679{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200680 parse_init_verbs(*codecp, buf);
681}
682
683static void parse_hint_mode(char *buf, struct hda_bus *bus,
684 struct hda_codec **codecp)
685{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200686 parse_hints(*codecp, buf);
687}
688
689static void parse_model_mode(char *buf, struct hda_bus *bus,
690 struct hda_codec **codecp)
691{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200692 kfree((*codecp)->modelname);
693 (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
694}
695
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100696static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
697 struct hda_codec **codecp)
698{
699 kfree((*codecp)->chip_name);
700 (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
701}
702
703#define DEFINE_PARSE_ID_MODE(name) \
704static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
705 struct hda_codec **codecp) \
706{ \
707 unsigned long val; \
Jingoo Hanb785a492013-07-19 16:24:59 +0900708 if (!kstrtoul(buf, 0, &val)) \
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100709 (*codecp)->name = val; \
710}
711
712DEFINE_PARSE_ID_MODE(vendor_id);
713DEFINE_PARSE_ID_MODE(subsystem_id);
714DEFINE_PARSE_ID_MODE(revision_id);
715
716
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200717struct hda_patch_item {
718 const char *tag;
Takashi Iwai8e3ae6f2014-01-07 15:28:51 +0100719 const char *alias;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200720 void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
721};
722
723static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
Takashi Iwai8e3ae6f2014-01-07 15:28:51 +0100724 [LINE_MODE_CODEC] = {
725 .tag = "[codec]",
726 .parser = parse_codec_mode,
727 },
728 [LINE_MODE_MODEL] = {
729 .tag = "[model]",
730 .parser = parse_model_mode,
731 },
732 [LINE_MODE_VERB] = {
733 .tag = "[verb]",
734 .alias = "[init_verbs]",
735 .parser = parse_verb_mode,
736 },
737 [LINE_MODE_PINCFG] = {
738 .tag = "[pincfg]",
739 .alias = "[user_pin_configs]",
740 .parser = parse_pincfg_mode,
741 },
742 [LINE_MODE_HINT] = {
743 .tag = "[hint]",
744 .alias = "[hints]",
745 .parser = parse_hint_mode
746 },
747 [LINE_MODE_VENDOR_ID] = {
748 .tag = "[vendor_id]",
749 .parser = parse_vendor_id_mode,
750 },
751 [LINE_MODE_SUBSYSTEM_ID] = {
752 .tag = "[subsystem_id]",
753 .parser = parse_subsystem_id_mode,
754 },
755 [LINE_MODE_REVISION_ID] = {
756 .tag = "[revision_id]",
757 .parser = parse_revision_id_mode,
758 },
759 [LINE_MODE_CHIP_NAME] = {
760 .tag = "[chip_name]",
761 .parser = parse_chip_name_mode,
762 },
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200763};
764
765/* check the line starting with '[' -- change the parser mode accodingly */
766static int parse_line_mode(char *buf, struct hda_bus *bus)
767{
768 int i;
769 for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
770 if (!patch_items[i].tag)
771 continue;
772 if (strmatch(buf, patch_items[i].tag))
773 return i;
Takashi Iwai8e3ae6f2014-01-07 15:28:51 +0100774 if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
775 return i;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200776 }
777 return LINE_MODE_NONE;
778}
779
780/* copy one line from the buffer in fw, and update the fields in fw
781 * return zero if it reaches to the end of the buffer, or non-zero
782 * if successfully copied a line
783 *
784 * the spaces at the beginning and the end of the line are stripped
785 */
Takashi Iwai4918cda2012-08-09 12:33:28 +0200786static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
787 const void **fw_data_p)
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200788{
789 int len;
Takashi Iwai4918cda2012-08-09 12:33:28 +0200790 size_t fw_size = *fw_size_p;
791 const char *p = *fw_data_p;
792
793 while (isspace(*p) && fw_size) {
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200794 p++;
Takashi Iwai4918cda2012-08-09 12:33:28 +0200795 fw_size--;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200796 }
Takashi Iwai4918cda2012-08-09 12:33:28 +0200797 if (!fw_size)
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200798 return 0;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200799
Takashi Iwai4918cda2012-08-09 12:33:28 +0200800 for (len = 0; len < fw_size; len++) {
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200801 if (!*p)
802 break;
803 if (*p == '\n') {
804 p++;
805 len++;
806 break;
807 }
808 if (len < size)
809 *buf++ = *p++;
810 }
811 *buf = 0;
Takashi Iwai4918cda2012-08-09 12:33:28 +0200812 *fw_size_p = fw_size - len;
813 *fw_data_p = p;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200814 remove_trail_spaces(buf);
815 return 1;
816}
817
818/*
819 * load a "patch" firmware file and parse it
820 */
Takashi Iwai4918cda2012-08-09 12:33:28 +0200821int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200822{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200823 char buf[128];
824 struct hda_codec *codec;
825 int line_mode;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200826
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200827 line_mode = LINE_MODE_NONE;
828 codec = NULL;
Takashi Iwai4918cda2012-08-09 12:33:28 +0200829 while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200830 if (!*buf || *buf == '#' || *buf == '\n')
831 continue;
832 if (*buf == '[')
833 line_mode = parse_line_mode(buf, bus);
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100834 else if (patch_items[line_mode].parser &&
Takashi Iwaid81e3972014-01-07 15:23:44 +0100835 (codec || line_mode <= LINE_MODE_CODEC))
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200836 patch_items[line_mode].parser(buf, bus, &codec);
837 }
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200838 return 0;
839}
Takashi Iwai2698ea92013-12-18 07:45:52 +0100840EXPORT_SYMBOL_GPL(snd_hda_load_patch);
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200841#endif /* CONFIG_SND_HDA_PATCH_LOADER */
Takashi Iwaicaa751b2014-02-25 08:30:50 +0100842
843/*
844 * sysfs entries
845 */
846static struct attribute *hda_dev_attrs[] = {
847#ifdef CONFIG_PM
848 &dev_attr_power_on_acct.attr,
849 &dev_attr_power_off_acct.attr,
850#endif
851#ifdef CONFIG_SND_HDA_RECONFIG
852 &dev_attr_vendor_id.attr,
853 &dev_attr_subsystem_id.attr,
854 &dev_attr_revision_id.attr,
855 &dev_attr_afg.attr,
856 &dev_attr_mfg.attr,
857 &dev_attr_vendor_name.attr,
858 &dev_attr_chip_name.attr,
859 &dev_attr_modelname.attr,
860 &dev_attr_init_verbs.attr,
861 &dev_attr_hints.attr,
862 &dev_attr_init_pin_configs.attr,
863 &dev_attr_user_pin_configs.attr,
864 &dev_attr_driver_pin_configs.attr,
865 &dev_attr_reconfig.attr,
866 &dev_attr_clear.attr,
867#endif
868 NULL
869};
870
871static struct attribute_group hda_dev_attr_group = {
872 .attrs = hda_dev_attrs,
873};
874
875static const struct attribute_group *snd_hda_dev_attr_groups[] = {
876 &hda_dev_attr_group,
877 NULL
878};