blob: 53eef6a01589738086c884d55f3e9e87663fb5be [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 Iwai28073142007-07-27 18:58:06 +0200158 return 0;
159}
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200160
Takashi Iwai83012a72012-08-24 18:38:08 +0200161#ifdef CONFIG_PM
Takashi Iwaia2f63092009-11-11 09:34:25 +0100162static ssize_t power_on_acct_show(struct device *dev,
163 struct device_attribute *attr,
164 char *buf)
165{
166 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
167 struct hda_codec *codec = hwdep->private_data;
168 snd_hda_update_power_acct(codec);
169 return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
170}
171
172static ssize_t power_off_acct_show(struct device *dev,
173 struct device_attribute *attr,
174 char *buf)
175{
176 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
177 struct hda_codec *codec = hwdep->private_data;
178 snd_hda_update_power_acct(codec);
179 return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
180}
181
Takashi Iwaicaa751b2014-02-25 08:30:50 +0100182static DEVICE_ATTR_RO(power_on_acct);
183static DEVICE_ATTR_RO(power_off_acct);
Takashi Iwai83012a72012-08-24 18:38:08 +0200184#endif /* CONFIG_PM */
Takashi Iwaia2f63092009-11-11 09:34:25 +0100185
Takashi Iwaie7ee0582008-11-21 09:26:20 +0100186#ifdef CONFIG_SND_HDA_RECONFIG
187
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200188/*
189 * sysfs interface
190 */
191
192static int clear_codec(struct hda_codec *codec)
193{
Takashi Iwaia65d6292009-02-23 16:57:04 +0100194 int err;
195
196 err = snd_hda_codec_reset(codec);
197 if (err < 0) {
198 snd_printk(KERN_ERR "The codec is being used, can't free.\n");
199 return err;
200 }
Takashi Iwai11aeff02008-07-30 15:01:46 +0200201 clear_hwdep_elements(codec);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200202 return 0;
203}
204
205static int reconfig_codec(struct hda_codec *codec)
206{
207 int err;
208
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100209 snd_hda_power_up(codec);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200210 snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
Takashi Iwaia65d6292009-02-23 16:57:04 +0100211 err = snd_hda_codec_reset(codec);
212 if (err < 0) {
213 snd_printk(KERN_ERR
214 "The codec is being used, can't reconfigure.\n");
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100215 goto error;
Takashi Iwaia65d6292009-02-23 16:57:04 +0100216 }
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200217 err = snd_hda_codec_configure(codec);
218 if (err < 0)
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100219 goto error;
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200220 /* rebuild PCMs */
Takashi Iwai529bd6c2008-11-27 14:17:01 +0100221 err = snd_hda_codec_build_pcms(codec);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200222 if (err < 0)
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100223 goto error;
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200224 /* rebuild mixers */
225 err = snd_hda_codec_build_controls(codec);
226 if (err < 0)
Takashi Iwaibb6ac722009-03-13 09:02:42 +0100227 goto error;
228 err = snd_card_register(codec->bus->card);
229 error:
230 snd_hda_power_down(codec);
231 return err;
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200232}
233
234/*
235 * allocate a string at most len chars, and remove the trailing EOL
236 */
237static char *kstrndup_noeol(const char *src, size_t len)
238{
239 char *s = kstrndup(src, len, GFP_KERNEL);
240 char *p;
241 if (!s)
242 return NULL;
243 p = strchr(s, '\n');
244 if (p)
245 *p = 0;
246 return s;
247}
248
249#define CODEC_INFO_SHOW(type) \
250static ssize_t type##_show(struct device *dev, \
251 struct device_attribute *attr, \
252 char *buf) \
253{ \
254 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
255 struct hda_codec *codec = hwdep->private_data; \
256 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{ \
264 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
265 struct hda_codec *codec = hwdep->private_data; \
266 return sprintf(buf, "%s\n", \
267 codec->type ? codec->type : ""); \
268}
269
270CODEC_INFO_SHOW(vendor_id);
271CODEC_INFO_SHOW(subsystem_id);
272CODEC_INFO_SHOW(revision_id);
273CODEC_INFO_SHOW(afg);
274CODEC_INFO_SHOW(mfg);
Takashi Iwai812a2cc2009-05-16 10:00:49 +0200275CODEC_INFO_STR_SHOW(vendor_name);
276CODEC_INFO_STR_SHOW(chip_name);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200277CODEC_INFO_STR_SHOW(modelname);
278
279#define CODEC_INFO_STORE(type) \
280static ssize_t type##_store(struct device *dev, \
281 struct device_attribute *attr, \
282 const char *buf, size_t count) \
283{ \
284 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
285 struct hda_codec *codec = hwdep->private_data; \
Takashi Iwai014c41f2009-12-27 13:53:24 +0100286 unsigned long val; \
Jingoo Hanb785a492013-07-19 16:24:59 +0900287 int err = kstrtoul(buf, 0, &val); \
Takashi Iwai014c41f2009-12-27 13:53:24 +0100288 if (err < 0) \
289 return err; \
290 codec->type = val; \
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200291 return count; \
292}
293
294#define CODEC_INFO_STR_STORE(type) \
295static ssize_t type##_store(struct device *dev, \
296 struct device_attribute *attr, \
297 const char *buf, size_t count) \
298{ \
299 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
300 struct hda_codec *codec = hwdep->private_data; \
301 char *s = kstrndup_noeol(buf, 64); \
302 if (!s) \
303 return -ENOMEM; \
304 kfree(codec->type); \
305 codec->type = s; \
306 return count; \
307}
308
309CODEC_INFO_STORE(vendor_id);
310CODEC_INFO_STORE(subsystem_id);
311CODEC_INFO_STORE(revision_id);
Takashi Iwai812a2cc2009-05-16 10:00:49 +0200312CODEC_INFO_STR_STORE(vendor_name);
313CODEC_INFO_STR_STORE(chip_name);
Takashi Iwaid7ffba12008-07-30 15:01:46 +0200314CODEC_INFO_STR_STORE(modelname);
315
316#define CODEC_ACTION_STORE(type) \
317static ssize_t type##_store(struct device *dev, \
318 struct device_attribute *attr, \
319 const char *buf, size_t count) \
320{ \
321 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
322 struct hda_codec *codec = hwdep->private_data; \
323 int err = 0; \
324 if (*buf) \
325 err = type##_codec(codec); \
326 return err < 0 ? err : count; \
327}
328
329CODEC_ACTION_STORE(reconfig);
330CODEC_ACTION_STORE(clear);
331
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100332static ssize_t init_verbs_show(struct device *dev,
333 struct device_attribute *attr,
334 char *buf)
335{
336 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
337 struct hda_codec *codec = hwdep->private_data;
338 int i, len = 0;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100339 mutex_lock(&codec->user_mutex);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100340 for (i = 0; i < codec->init_verbs.used; i++) {
341 struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
342 len += snprintf(buf + len, PAGE_SIZE - len,
343 "0x%02x 0x%03x 0x%04x\n",
344 v->nid, v->verb, v->param);
345 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100346 mutex_unlock(&codec->user_mutex);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100347 return len;
348}
349
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200350static int parse_init_verbs(struct hda_codec *codec, const char *buf)
Takashi Iwai11aeff02008-07-30 15:01:46 +0200351{
Takashi Iwai55290e12009-02-20 15:59:01 +0100352 struct hda_verb *v;
353 int nid, verb, param;
Takashi Iwai11aeff02008-07-30 15:01:46 +0200354
Takashi Iwai55290e12009-02-20 15:59:01 +0100355 if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
356 return -EINVAL;
357 if (!nid || !verb)
Takashi Iwai11aeff02008-07-30 15:01:46 +0200358 return -EINVAL;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100359 mutex_lock(&codec->user_mutex);
Takashi Iwai11aeff02008-07-30 15:01:46 +0200360 v = snd_array_new(&codec->init_verbs);
Takashi Iwai09b70e82013-01-10 18:21:56 +0100361 if (!v) {
362 mutex_unlock(&codec->user_mutex);
Takashi Iwai11aeff02008-07-30 15:01:46 +0200363 return -ENOMEM;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100364 }
Takashi Iwai55290e12009-02-20 15:59:01 +0100365 v->nid = nid;
366 v->verb = verb;
367 v->param = param;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100368 mutex_unlock(&codec->user_mutex);
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200369 return 0;
370}
371
372static ssize_t init_verbs_store(struct device *dev,
373 struct device_attribute *attr,
374 const char *buf, size_t count)
375{
376 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
377 struct hda_codec *codec = hwdep->private_data;
378 int err = parse_init_verbs(codec, buf);
379 if (err < 0)
380 return err;
Takashi Iwai11aeff02008-07-30 15:01:46 +0200381 return count;
382}
383
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100384static ssize_t hints_show(struct device *dev,
385 struct device_attribute *attr,
386 char *buf)
387{
388 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
389 struct hda_codec *codec = hwdep->private_data;
390 int i, len = 0;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100391 mutex_lock(&codec->user_mutex);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100392 for (i = 0; i < codec->hints.used; i++) {
393 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
394 len += snprintf(buf + len, PAGE_SIZE - len,
395 "%s = %s\n", hint->key, hint->val);
396 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100397 mutex_unlock(&codec->user_mutex);
Takashi Iwaiab1726f2009-03-02 17:09:25 +0100398 return len;
399}
400
Takashi Iwai43b62712009-03-02 14:25:17 +0100401static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
402{
403 int i;
404
405 for (i = 0; i < codec->hints.used; i++) {
406 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
407 if (!strcmp(hint->key, key))
408 return hint;
409 }
410 return NULL;
411}
412
413static void remove_trail_spaces(char *str)
414{
415 char *p;
416 if (!*str)
417 return;
418 p = str + strlen(str) - 1;
419 for (; isspace(*p); p--) {
420 *p = 0;
421 if (p == str)
422 return;
423 }
424}
425
426#define MAX_HINTS 1024
427
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200428static int parse_hints(struct hda_codec *codec, const char *buf)
Takashi Iwai1e1be432008-07-30 15:01:46 +0200429{
Takashi Iwai43b62712009-03-02 14:25:17 +0100430 char *key, *val;
431 struct hda_hint *hint;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100432 int err = 0;
Takashi Iwai1e1be432008-07-30 15:01:46 +0200433
André Goddard Rosae7d28602009-12-14 18:01:06 -0800434 buf = skip_spaces(buf);
Takashi Iwai43b62712009-03-02 14:25:17 +0100435 if (!*buf || *buf == '#' || *buf == '\n')
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200436 return 0;
Takashi Iwai43b62712009-03-02 14:25:17 +0100437 if (*buf == '=')
438 return -EINVAL;
439 key = kstrndup_noeol(buf, 1024);
440 if (!key)
Takashi Iwai1e1be432008-07-30 15:01:46 +0200441 return -ENOMEM;
Takashi Iwai43b62712009-03-02 14:25:17 +0100442 /* extract key and val */
443 val = strchr(key, '=');
444 if (!val) {
445 kfree(key);
446 return -EINVAL;
447 }
448 *val++ = 0;
André Goddard Rosae7d28602009-12-14 18:01:06 -0800449 val = skip_spaces(val);
Takashi Iwai43b62712009-03-02 14:25:17 +0100450 remove_trail_spaces(key);
451 remove_trail_spaces(val);
Takashi Iwai09b70e82013-01-10 18:21:56 +0100452 mutex_lock(&codec->user_mutex);
Takashi Iwai43b62712009-03-02 14:25:17 +0100453 hint = get_hint(codec, key);
454 if (hint) {
455 /* replace */
456 kfree(hint->key);
457 hint->key = key;
458 hint->val = val;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100459 goto unlock;
Takashi Iwai43b62712009-03-02 14:25:17 +0100460 }
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);
Takashi Iwai09b70e82013-01-10 18:21:56 +0100466 if (hint) {
467 hint->key = key;
468 hint->val = val;
469 } else {
470 err = -ENOMEM;
Takashi Iwai1e1be432008-07-30 15:01:46 +0200471 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100472 unlock:
473 mutex_unlock(&codec->user_mutex);
474 if (err)
475 kfree(key);
476 return err;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200477}
478
479static ssize_t hints_store(struct device *dev,
480 struct device_attribute *attr,
481 const char *buf, size_t count)
482{
483 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
484 struct hda_codec *codec = hwdep->private_data;
485 int err = parse_hints(codec, buf);
486 if (err < 0)
487 return err;
Takashi Iwai1e1be432008-07-30 15:01:46 +0200488 return count;
489}
490
Takashi Iwai3be14142009-02-20 14:11:16 +0100491static ssize_t pin_configs_show(struct hda_codec *codec,
492 struct snd_array *list,
493 char *buf)
494{
495 int i, len = 0;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100496 mutex_lock(&codec->user_mutex);
Takashi Iwai3be14142009-02-20 14:11:16 +0100497 for (i = 0; i < list->used; i++) {
498 struct hda_pincfg *pin = snd_array_elem(list, i);
499 len += sprintf(buf + len, "0x%02x 0x%08x\n",
500 pin->nid, pin->cfg);
501 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100502 mutex_unlock(&codec->user_mutex);
Takashi Iwai3be14142009-02-20 14:11:16 +0100503 return len;
504}
505
506static ssize_t init_pin_configs_show(struct device *dev,
507 struct device_attribute *attr,
508 char *buf)
509{
510 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
511 struct hda_codec *codec = hwdep->private_data;
512 return pin_configs_show(codec, &codec->init_pins, buf);
513}
514
Takashi Iwai346ff702009-02-23 09:42:57 +0100515static ssize_t user_pin_configs_show(struct device *dev,
516 struct device_attribute *attr,
517 char *buf)
Takashi Iwai3be14142009-02-20 14:11:16 +0100518{
519 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
520 struct hda_codec *codec = hwdep->private_data;
Takashi Iwai346ff702009-02-23 09:42:57 +0100521 return pin_configs_show(codec, &codec->user_pins, buf);
Takashi Iwai3be14142009-02-20 14:11:16 +0100522}
523
Takashi Iwai346ff702009-02-23 09:42:57 +0100524static ssize_t driver_pin_configs_show(struct device *dev,
525 struct device_attribute *attr,
526 char *buf)
Takashi Iwai3be14142009-02-20 14:11:16 +0100527{
528 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
529 struct hda_codec *codec = hwdep->private_data;
Takashi Iwai346ff702009-02-23 09:42:57 +0100530 return pin_configs_show(codec, &codec->driver_pins, buf);
Takashi Iwai3be14142009-02-20 14:11:16 +0100531}
532
533#define MAX_PIN_CONFIGS 32
534
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200535static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
536{
Takashi Iwai09b70e82013-01-10 18:21:56 +0100537 int nid, cfg, err;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200538
539 if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
540 return -EINVAL;
541 if (!nid)
542 return -EINVAL;
Takashi Iwai09b70e82013-01-10 18:21:56 +0100543 mutex_lock(&codec->user_mutex);
544 err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
545 mutex_unlock(&codec->user_mutex);
546 return err;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200547}
548
Takashi Iwai346ff702009-02-23 09:42:57 +0100549static ssize_t user_pin_configs_store(struct device *dev,
550 struct device_attribute *attr,
551 const char *buf, size_t count)
Takashi Iwai3be14142009-02-20 14:11:16 +0100552{
553 struct snd_hwdep *hwdep = dev_get_drvdata(dev);
554 struct hda_codec *codec = hwdep->private_data;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200555 int err = parse_user_pin_configs(codec, buf);
Takashi Iwai3be14142009-02-20 14:11:16 +0100556 if (err < 0)
557 return err;
558 return count;
559}
560
Takashi Iwaicaa751b2014-02-25 08:30:50 +0100561static DEVICE_ATTR_RW(vendor_id);
562static DEVICE_ATTR_RW(subsystem_id);
563static DEVICE_ATTR_RW(revision_id);
564static DEVICE_ATTR_RO(afg);
565static DEVICE_ATTR_RO(mfg);
566static DEVICE_ATTR_RW(vendor_name);
567static DEVICE_ATTR_RW(chip_name);
568static DEVICE_ATTR_RW(modelname);
569static DEVICE_ATTR_RW(init_verbs);
570static DEVICE_ATTR_RW(hints);
571static DEVICE_ATTR_RO(init_pin_configs);
572static DEVICE_ATTR_RW(user_pin_configs);
573static DEVICE_ATTR_RO(driver_pin_configs);
574static DEVICE_ATTR_WO(reconfig);
575static DEVICE_ATTR_WO(clear);
Takashi Iwaie7ee0582008-11-21 09:26:20 +0100576
Takashi Iwai43b62712009-03-02 14:25:17 +0100577/*
578 * Look for hint string
579 */
580const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
581{
582 struct hda_hint *hint = get_hint(codec, key);
583 return hint ? hint->val : NULL;
584}
Takashi Iwai2698ea92013-12-18 07:45:52 +0100585EXPORT_SYMBOL_GPL(snd_hda_get_hint);
Takashi Iwai43b62712009-03-02 14:25:17 +0100586
587int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
588{
Takashi Iwai09b70e82013-01-10 18:21:56 +0100589 const char *p;
590 int ret;
591
592 mutex_lock(&codec->user_mutex);
593 p = snd_hda_get_hint(codec, key);
Takashi Iwai43b62712009-03-02 14:25:17 +0100594 if (!p || !*p)
Takashi Iwai09b70e82013-01-10 18:21:56 +0100595 ret = -ENOENT;
596 else {
597 switch (toupper(*p)) {
598 case 'T': /* true */
599 case 'Y': /* yes */
600 case '1':
601 ret = 1;
602 break;
603 default:
604 ret = 0;
605 break;
606 }
Takashi Iwai43b62712009-03-02 14:25:17 +0100607 }
Takashi Iwai09b70e82013-01-10 18:21:56 +0100608 mutex_unlock(&codec->user_mutex);
609 return ret;
Takashi Iwai43b62712009-03-02 14:25:17 +0100610}
Takashi Iwai2698ea92013-12-18 07:45:52 +0100611EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
Takashi Iwai43b62712009-03-02 14:25:17 +0100612
Takashi Iwaibc759722013-01-11 17:40:31 +0100613int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
614{
615 const char *p;
616 unsigned long val;
617 int ret;
618
619 mutex_lock(&codec->user_mutex);
620 p = snd_hda_get_hint(codec, key);
621 if (!p)
622 ret = -ENOENT;
Jingoo Hanb785a492013-07-19 16:24:59 +0900623 else if (kstrtoul(p, 0, &val))
Takashi Iwaibc759722013-01-11 17:40:31 +0100624 ret = -EINVAL;
625 else {
626 *valp = val;
627 ret = 0;
628 }
629 mutex_unlock(&codec->user_mutex);
630 return ret;
631}
Takashi Iwai2698ea92013-12-18 07:45:52 +0100632EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
Takashi Iwaie7ee0582008-11-21 09:26:20 +0100633#endif /* CONFIG_SND_HDA_RECONFIG */
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200634
635#ifdef CONFIG_SND_HDA_PATCH_LOADER
636
637/* parser mode */
638enum {
639 LINE_MODE_NONE,
640 LINE_MODE_CODEC,
641 LINE_MODE_MODEL,
642 LINE_MODE_PINCFG,
643 LINE_MODE_VERB,
644 LINE_MODE_HINT,
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100645 LINE_MODE_VENDOR_ID,
646 LINE_MODE_SUBSYSTEM_ID,
647 LINE_MODE_REVISION_ID,
648 LINE_MODE_CHIP_NAME,
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200649 NUM_LINE_MODES,
650};
651
652static inline int strmatch(const char *a, const char *b)
653{
654 return strnicmp(a, b, strlen(b)) == 0;
655}
656
657/* parse the contents after the line "[codec]"
658 * accept only the line with three numbers, and assign the current codec
659 */
660static void parse_codec_mode(char *buf, struct hda_bus *bus,
661 struct hda_codec **codecp)
662{
Takashi Iwaief940b02011-09-28 20:12:08 +0200663 int vendorid, subid, caddr;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200664 struct hda_codec *codec;
665
666 *codecp = NULL;
667 if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
668 list_for_each_entry(codec, &bus->codec_list, list) {
Takashi Iwaief940b02011-09-28 20:12:08 +0200669 if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
670 (subid <= 0 || codec->subsystem_id == subid) &&
David Henningsson2385b782010-06-02 16:56:41 +0200671 codec->addr == caddr) {
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200672 *codecp = codec;
673 break;
674 }
675 }
676 }
677}
678
679/* parse the contents after the other command tags, [pincfg], [verb],
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100680 * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200681 * just pass to the sysfs helper (only when any codec was specified)
682 */
683static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
684 struct hda_codec **codecp)
685{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200686 parse_user_pin_configs(*codecp, buf);
687}
688
689static void parse_verb_mode(char *buf, struct hda_bus *bus,
690 struct hda_codec **codecp)
691{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200692 parse_init_verbs(*codecp, buf);
693}
694
695static void parse_hint_mode(char *buf, struct hda_bus *bus,
696 struct hda_codec **codecp)
697{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200698 parse_hints(*codecp, buf);
699}
700
701static void parse_model_mode(char *buf, struct hda_bus *bus,
702 struct hda_codec **codecp)
703{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200704 kfree((*codecp)->modelname);
705 (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
706}
707
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100708static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
709 struct hda_codec **codecp)
710{
711 kfree((*codecp)->chip_name);
712 (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
713}
714
715#define DEFINE_PARSE_ID_MODE(name) \
716static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
717 struct hda_codec **codecp) \
718{ \
719 unsigned long val; \
Jingoo Hanb785a492013-07-19 16:24:59 +0900720 if (!kstrtoul(buf, 0, &val)) \
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100721 (*codecp)->name = val; \
722}
723
724DEFINE_PARSE_ID_MODE(vendor_id);
725DEFINE_PARSE_ID_MODE(subsystem_id);
726DEFINE_PARSE_ID_MODE(revision_id);
727
728
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200729struct hda_patch_item {
730 const char *tag;
Takashi Iwai8e3ae6f2014-01-07 15:28:51 +0100731 const char *alias;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200732 void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
733};
734
735static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
Takashi Iwai8e3ae6f2014-01-07 15:28:51 +0100736 [LINE_MODE_CODEC] = {
737 .tag = "[codec]",
738 .parser = parse_codec_mode,
739 },
740 [LINE_MODE_MODEL] = {
741 .tag = "[model]",
742 .parser = parse_model_mode,
743 },
744 [LINE_MODE_VERB] = {
745 .tag = "[verb]",
746 .alias = "[init_verbs]",
747 .parser = parse_verb_mode,
748 },
749 [LINE_MODE_PINCFG] = {
750 .tag = "[pincfg]",
751 .alias = "[user_pin_configs]",
752 .parser = parse_pincfg_mode,
753 },
754 [LINE_MODE_HINT] = {
755 .tag = "[hint]",
756 .alias = "[hints]",
757 .parser = parse_hint_mode
758 },
759 [LINE_MODE_VENDOR_ID] = {
760 .tag = "[vendor_id]",
761 .parser = parse_vendor_id_mode,
762 },
763 [LINE_MODE_SUBSYSTEM_ID] = {
764 .tag = "[subsystem_id]",
765 .parser = parse_subsystem_id_mode,
766 },
767 [LINE_MODE_REVISION_ID] = {
768 .tag = "[revision_id]",
769 .parser = parse_revision_id_mode,
770 },
771 [LINE_MODE_CHIP_NAME] = {
772 .tag = "[chip_name]",
773 .parser = parse_chip_name_mode,
774 },
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200775};
776
777/* check the line starting with '[' -- change the parser mode accodingly */
778static int parse_line_mode(char *buf, struct hda_bus *bus)
779{
780 int i;
781 for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
782 if (!patch_items[i].tag)
783 continue;
784 if (strmatch(buf, patch_items[i].tag))
785 return i;
Takashi Iwai8e3ae6f2014-01-07 15:28:51 +0100786 if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
787 return i;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200788 }
789 return LINE_MODE_NONE;
790}
791
792/* copy one line from the buffer in fw, and update the fields in fw
793 * return zero if it reaches to the end of the buffer, or non-zero
794 * if successfully copied a line
795 *
796 * the spaces at the beginning and the end of the line are stripped
797 */
Takashi Iwai4918cda2012-08-09 12:33:28 +0200798static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
799 const void **fw_data_p)
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200800{
801 int len;
Takashi Iwai4918cda2012-08-09 12:33:28 +0200802 size_t fw_size = *fw_size_p;
803 const char *p = *fw_data_p;
804
805 while (isspace(*p) && fw_size) {
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200806 p++;
Takashi Iwai4918cda2012-08-09 12:33:28 +0200807 fw_size--;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200808 }
Takashi Iwai4918cda2012-08-09 12:33:28 +0200809 if (!fw_size)
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200810 return 0;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200811
Takashi Iwai4918cda2012-08-09 12:33:28 +0200812 for (len = 0; len < fw_size; len++) {
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200813 if (!*p)
814 break;
815 if (*p == '\n') {
816 p++;
817 len++;
818 break;
819 }
820 if (len < size)
821 *buf++ = *p++;
822 }
823 *buf = 0;
Takashi Iwai4918cda2012-08-09 12:33:28 +0200824 *fw_size_p = fw_size - len;
825 *fw_data_p = p;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200826 remove_trail_spaces(buf);
827 return 1;
828}
829
830/*
831 * load a "patch" firmware file and parse it
832 */
Takashi Iwai4918cda2012-08-09 12:33:28 +0200833int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200834{
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200835 char buf[128];
836 struct hda_codec *codec;
837 int line_mode;
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200838
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200839 line_mode = LINE_MODE_NONE;
840 codec = NULL;
Takashi Iwai4918cda2012-08-09 12:33:28 +0200841 while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200842 if (!*buf || *buf == '#' || *buf == '\n')
843 continue;
844 if (*buf == '[')
845 line_mode = parse_line_mode(buf, bus);
Takashi Iwaib09f3e72010-01-28 00:01:53 +0100846 else if (patch_items[line_mode].parser &&
Takashi Iwaid81e3972014-01-07 15:23:44 +0100847 (codec || line_mode <= LINE_MODE_CODEC))
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200848 patch_items[line_mode].parser(buf, bus, &codec);
849 }
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200850 return 0;
851}
Takashi Iwai2698ea92013-12-18 07:45:52 +0100852EXPORT_SYMBOL_GPL(snd_hda_load_patch);
Takashi Iwai4ea6fbc2009-06-17 09:52:54 +0200853#endif /* CONFIG_SND_HDA_PATCH_LOADER */
Takashi Iwaicaa751b2014-02-25 08:30:50 +0100854
855/*
856 * sysfs entries
857 */
858static struct attribute *hda_dev_attrs[] = {
859#ifdef CONFIG_PM
860 &dev_attr_power_on_acct.attr,
861 &dev_attr_power_off_acct.attr,
862#endif
863#ifdef CONFIG_SND_HDA_RECONFIG
864 &dev_attr_vendor_id.attr,
865 &dev_attr_subsystem_id.attr,
866 &dev_attr_revision_id.attr,
867 &dev_attr_afg.attr,
868 &dev_attr_mfg.attr,
869 &dev_attr_vendor_name.attr,
870 &dev_attr_chip_name.attr,
871 &dev_attr_modelname.attr,
872 &dev_attr_init_verbs.attr,
873 &dev_attr_hints.attr,
874 &dev_attr_init_pin_configs.attr,
875 &dev_attr_user_pin_configs.attr,
876 &dev_attr_driver_pin_configs.attr,
877 &dev_attr_reconfig.attr,
878 &dev_attr_clear.attr,
879#endif
880 NULL
881};
882
883static struct attribute_group hda_dev_attr_group = {
884 .attrs = hda_dev_attrs,
885};
886
887static const struct attribute_group *snd_hda_dev_attr_groups[] = {
888 &hda_dev_attr_group,
889 NULL
890};