ALSA: hda - Add show for init_verbs and hints sysfs entries
[safe/jmp/linux-2.6] / sound / pci / hda / hda_hwdep.c
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 <sound/core.h>
28 #include "hda_codec.h"
29 #include "hda_local.h"
30 #include <sound/hda_hwdep.h>
31 #include <sound/minors.h>
32
33 /* hint string pair */
34 struct hda_hint {
35         const char *key;
36         const char *val;        /* contained in the same alloc as key */
37 };
38
39 /*
40  * write/read an out-of-bound verb
41  */
42 static int verb_write_ioctl(struct hda_codec *codec,
43                             struct hda_verb_ioctl __user *arg)
44 {
45         u32 verb, res;
46
47         if (get_user(verb, &arg->verb))
48                 return -EFAULT;
49         res = snd_hda_codec_read(codec, verb >> 24, 0,
50                                  (verb >> 8) & 0xffff, verb & 0xff);
51         if (put_user(res, &arg->res))
52                 return -EFAULT;
53         return 0;
54 }
55
56 static int get_wcap_ioctl(struct hda_codec *codec,
57                           struct hda_verb_ioctl __user *arg)
58 {
59         u32 verb, res;
60         
61         if (get_user(verb, &arg->verb))
62                 return -EFAULT;
63         res = get_wcaps(codec, verb >> 24);
64         if (put_user(res, &arg->res))
65                 return -EFAULT;
66         return 0;
67 }
68
69
70 /*
71  */
72 static int hda_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
73                            unsigned int cmd, unsigned long arg)
74 {
75         struct hda_codec *codec = hw->private_data;
76         void __user *argp = (void __user *)arg;
77
78         switch (cmd) {
79         case HDA_IOCTL_PVERSION:
80                 return put_user(HDA_HWDEP_VERSION, (int __user *)argp);
81         case HDA_IOCTL_VERB_WRITE:
82                 return verb_write_ioctl(codec, argp);
83         case HDA_IOCTL_GET_WCAP:
84                 return get_wcap_ioctl(codec, argp);
85         }
86         return -ENOIOCTLCMD;
87 }
88
89 #ifdef CONFIG_COMPAT
90 static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
91                                   unsigned int cmd, unsigned long arg)
92 {
93         return hda_hwdep_ioctl(hw, file, cmd, (unsigned long)compat_ptr(arg));
94 }
95 #endif
96
97 static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
98 {
99 #ifndef CONFIG_SND_DEBUG_VERBOSE
100         if (!capable(CAP_SYS_RAWIO))
101                 return -EACCES;
102 #endif
103         return 0;
104 }
105
106 static void clear_hwdep_elements(struct hda_codec *codec)
107 {
108         int i;
109
110         /* clear init verbs */
111         snd_array_free(&codec->init_verbs);
112         /* clear hints */
113         for (i = 0; i < codec->hints.used; i++) {
114                 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
115                 kfree(hint->key); /* we don't need to free hint->val */
116         }
117         snd_array_free(&codec->hints);
118         snd_array_free(&codec->user_pins);
119 }
120
121 static void hwdep_free(struct snd_hwdep *hwdep)
122 {
123         clear_hwdep_elements(hwdep->private_data);
124 }
125
126 int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
127 {
128         char hwname[16];
129         struct snd_hwdep *hwdep;
130         int err;
131
132         sprintf(hwname, "HDA Codec %d", codec->addr);
133         err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep);
134         if (err < 0)
135                 return err;
136         codec->hwdep = hwdep;
137         sprintf(hwdep->name, "HDA Codec %d", codec->addr);
138         hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
139         hwdep->private_data = codec;
140         hwdep->private_free = hwdep_free;
141         hwdep->exclusive = 1;
142
143         hwdep->ops.open = hda_hwdep_open;
144         hwdep->ops.ioctl = hda_hwdep_ioctl;
145 #ifdef CONFIG_COMPAT
146         hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
147 #endif
148
149         snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
150         snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
151         snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
152
153         return 0;
154 }
155
156 #ifdef CONFIG_SND_HDA_RECONFIG
157
158 /*
159  * sysfs interface
160  */
161
162 static int clear_codec(struct hda_codec *codec)
163 {
164         int err;
165
166         err = snd_hda_codec_reset(codec);
167         if (err < 0) {
168                 snd_printk(KERN_ERR "The codec is being used, can't free.\n");
169                 return err;
170         }
171         clear_hwdep_elements(codec);
172         return 0;
173 }
174
175 static int reconfig_codec(struct hda_codec *codec)
176 {
177         int err;
178
179         snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
180         err = snd_hda_codec_reset(codec);
181         if (err < 0) {
182                 snd_printk(KERN_ERR
183                            "The codec is being used, can't reconfigure.\n");
184                 return err;
185         }
186         err = snd_hda_codec_configure(codec);
187         if (err < 0)
188                 return err;
189         /* rebuild PCMs */
190         err = snd_hda_codec_build_pcms(codec);
191         if (err < 0)
192                 return err;
193         /* rebuild mixers */
194         err = snd_hda_codec_build_controls(codec);
195         if (err < 0)
196                 return err;
197         return snd_card_register(codec->bus->card);
198 }
199
200 /*
201  * allocate a string at most len chars, and remove the trailing EOL
202  */
203 static char *kstrndup_noeol(const char *src, size_t len)
204 {
205         char *s = kstrndup(src, len, GFP_KERNEL);
206         char *p;
207         if (!s)
208                 return NULL;
209         p = strchr(s, '\n');
210         if (p)
211                 *p = 0;
212         return s;
213 }
214
215 #define CODEC_INFO_SHOW(type)                                   \
216 static ssize_t type##_show(struct device *dev,                  \
217                            struct device_attribute *attr,       \
218                            char *buf)                           \
219 {                                                               \
220         struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
221         struct hda_codec *codec = hwdep->private_data;          \
222         return sprintf(buf, "0x%x\n", codec->type);             \
223 }
224
225 #define CODEC_INFO_STR_SHOW(type)                               \
226 static ssize_t type##_show(struct device *dev,                  \
227                              struct device_attribute *attr,     \
228                                         char *buf)              \
229 {                                                               \
230         struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
231         struct hda_codec *codec = hwdep->private_data;          \
232         return sprintf(buf, "%s\n",                             \
233                        codec->type ? codec->type : "");         \
234 }
235
236 CODEC_INFO_SHOW(vendor_id);
237 CODEC_INFO_SHOW(subsystem_id);
238 CODEC_INFO_SHOW(revision_id);
239 CODEC_INFO_SHOW(afg);
240 CODEC_INFO_SHOW(mfg);
241 CODEC_INFO_STR_SHOW(name);
242 CODEC_INFO_STR_SHOW(modelname);
243
244 #define CODEC_INFO_STORE(type)                                  \
245 static ssize_t type##_store(struct device *dev,                 \
246                             struct device_attribute *attr,      \
247                             const char *buf, size_t count)      \
248 {                                                               \
249         struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
250         struct hda_codec *codec = hwdep->private_data;          \
251         char *after;                                            \
252         codec->type = simple_strtoul(buf, &after, 0);           \
253         return count;                                           \
254 }
255
256 #define CODEC_INFO_STR_STORE(type)                              \
257 static ssize_t type##_store(struct device *dev,                 \
258                             struct device_attribute *attr,      \
259                             const char *buf, size_t count)      \
260 {                                                               \
261         struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
262         struct hda_codec *codec = hwdep->private_data;          \
263         char *s = kstrndup_noeol(buf, 64);                      \
264         if (!s)                                                 \
265                 return -ENOMEM;                                 \
266         kfree(codec->type);                                     \
267         codec->type = s;                                        \
268         return count;                                           \
269 }
270
271 CODEC_INFO_STORE(vendor_id);
272 CODEC_INFO_STORE(subsystem_id);
273 CODEC_INFO_STORE(revision_id);
274 CODEC_INFO_STR_STORE(name);
275 CODEC_INFO_STR_STORE(modelname);
276
277 #define CODEC_ACTION_STORE(type)                                \
278 static ssize_t type##_store(struct device *dev,                 \
279                             struct device_attribute *attr,      \
280                             const char *buf, size_t count)      \
281 {                                                               \
282         struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
283         struct hda_codec *codec = hwdep->private_data;          \
284         int err = 0;                                            \
285         if (*buf)                                               \
286                 err = type##_codec(codec);                      \
287         return err < 0 ? err : count;                           \
288 }
289
290 CODEC_ACTION_STORE(reconfig);
291 CODEC_ACTION_STORE(clear);
292
293 static ssize_t init_verbs_show(struct device *dev,
294                                struct device_attribute *attr,
295                                char *buf)
296 {
297         struct snd_hwdep *hwdep = dev_get_drvdata(dev);
298         struct hda_codec *codec = hwdep->private_data;
299         int i, len = 0;
300         for (i = 0; i < codec->init_verbs.used; i++) {
301                 struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
302                 len += snprintf(buf + len, PAGE_SIZE - len,
303                                 "0x%02x 0x%03x 0x%04x\n",
304                                 v->nid, v->verb, v->param);
305         }
306         return len;
307 }
308
309 static ssize_t init_verbs_store(struct device *dev,
310                                 struct device_attribute *attr,
311                                 const char *buf, size_t count)
312 {
313         struct snd_hwdep *hwdep = dev_get_drvdata(dev);
314         struct hda_codec *codec = hwdep->private_data;
315         struct hda_verb *v;
316         int nid, verb, param;
317
318         if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
319                 return -EINVAL;
320         if (!nid || !verb)
321                 return -EINVAL;
322         v = snd_array_new(&codec->init_verbs);
323         if (!v)
324                 return -ENOMEM;
325         v->nid = nid;
326         v->verb = verb;
327         v->param = param;
328         return count;
329 }
330
331 static ssize_t hints_show(struct device *dev,
332                           struct device_attribute *attr,
333                           char *buf)
334 {
335         struct snd_hwdep *hwdep = dev_get_drvdata(dev);
336         struct hda_codec *codec = hwdep->private_data;
337         int i, len = 0;
338         for (i = 0; i < codec->hints.used; i++) {
339                 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
340                 len += snprintf(buf + len, PAGE_SIZE - len,
341                                 "%s = %s\n", hint->key, hint->val);
342         }
343         return len;
344 }
345
346 static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
347 {
348         int i;
349
350         for (i = 0; i < codec->hints.used; i++) {
351                 struct hda_hint *hint = snd_array_elem(&codec->hints, i);
352                 if (!strcmp(hint->key, key))
353                         return hint;
354         }
355         return NULL;
356 }
357
358 static void remove_trail_spaces(char *str)
359 {
360         char *p;
361         if (!*str)
362                 return;
363         p = str + strlen(str) - 1;
364         for (; isspace(*p); p--) {
365                 *p = 0;
366                 if (p == str)
367                         return;
368         }
369 }
370
371 #define MAX_HINTS       1024
372
373 static ssize_t hints_store(struct device *dev,
374                            struct device_attribute *attr,
375                            const char *buf, size_t count)
376 {
377         struct snd_hwdep *hwdep = dev_get_drvdata(dev);
378         struct hda_codec *codec = hwdep->private_data;
379         char *key, *val;
380         struct hda_hint *hint;
381
382         while (isspace(*buf))
383                 buf++;
384         if (!*buf || *buf == '#' || *buf == '\n')
385                 return count;
386         if (*buf == '=')
387                 return -EINVAL;
388         key = kstrndup_noeol(buf, 1024);
389         if (!key)
390                 return -ENOMEM;
391         /* extract key and val */
392         val = strchr(key, '=');
393         if (!val) {
394                 kfree(key);
395                 return -EINVAL;
396         }
397         *val++ = 0;
398         while (isspace(*val))
399                 val++;
400         remove_trail_spaces(key);
401         remove_trail_spaces(val);
402         hint = get_hint(codec, key);
403         if (hint) {
404                 /* replace */
405                 kfree(hint->key);
406                 hint->key = key;
407                 hint->val = val;
408                 return count;
409         }
410         /* allocate a new hint entry */
411         if (codec->hints.used >= MAX_HINTS)
412                 hint = NULL;
413         else
414                 hint = snd_array_new(&codec->hints);
415         if (!hint) {
416                 kfree(key);
417                 return -ENOMEM;
418         }
419         hint->key = key;
420         hint->val = val;
421         return count;
422 }
423
424 static ssize_t pin_configs_show(struct hda_codec *codec,
425                                 struct snd_array *list,
426                                 char *buf)
427 {
428         int i, len = 0;
429         for (i = 0; i < list->used; i++) {
430                 struct hda_pincfg *pin = snd_array_elem(list, i);
431                 len += sprintf(buf + len, "0x%02x 0x%08x\n",
432                                pin->nid, pin->cfg);
433         }
434         return len;
435 }
436
437 static ssize_t init_pin_configs_show(struct device *dev,
438                                      struct device_attribute *attr,
439                                      char *buf)
440 {
441         struct snd_hwdep *hwdep = dev_get_drvdata(dev);
442         struct hda_codec *codec = hwdep->private_data;
443         return pin_configs_show(codec, &codec->init_pins, buf);
444 }
445
446 static ssize_t user_pin_configs_show(struct device *dev,
447                                      struct device_attribute *attr,
448                                      char *buf)
449 {
450         struct snd_hwdep *hwdep = dev_get_drvdata(dev);
451         struct hda_codec *codec = hwdep->private_data;
452         return pin_configs_show(codec, &codec->user_pins, buf);
453 }
454
455 static ssize_t driver_pin_configs_show(struct device *dev,
456                                        struct device_attribute *attr,
457                                        char *buf)
458 {
459         struct snd_hwdep *hwdep = dev_get_drvdata(dev);
460         struct hda_codec *codec = hwdep->private_data;
461         return pin_configs_show(codec, &codec->driver_pins, buf);
462 }
463
464 #define MAX_PIN_CONFIGS         32
465
466 static ssize_t user_pin_configs_store(struct device *dev,
467                                       struct device_attribute *attr,
468                                       const char *buf, size_t count)
469 {
470         struct snd_hwdep *hwdep = dev_get_drvdata(dev);
471         struct hda_codec *codec = hwdep->private_data;
472         int nid, cfg;
473         int err;
474
475         if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
476                 return -EINVAL;
477         if (!nid)
478                 return -EINVAL;
479         err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
480         if (err < 0)
481                 return err;
482         return count;
483 }
484
485 #define CODEC_ATTR_RW(type) \
486         __ATTR(type, 0644, type##_show, type##_store)
487 #define CODEC_ATTR_RO(type) \
488         __ATTR_RO(type)
489 #define CODEC_ATTR_WO(type) \
490         __ATTR(type, 0200, NULL, type##_store)
491
492 static struct device_attribute codec_attrs[] = {
493         CODEC_ATTR_RW(vendor_id),
494         CODEC_ATTR_RW(subsystem_id),
495         CODEC_ATTR_RW(revision_id),
496         CODEC_ATTR_RO(afg),
497         CODEC_ATTR_RO(mfg),
498         CODEC_ATTR_RW(name),
499         CODEC_ATTR_RW(modelname),
500         CODEC_ATTR_RW(init_verbs),
501         CODEC_ATTR_RW(hints),
502         CODEC_ATTR_RO(init_pin_configs),
503         CODEC_ATTR_RW(user_pin_configs),
504         CODEC_ATTR_RO(driver_pin_configs),
505         CODEC_ATTR_WO(reconfig),
506         CODEC_ATTR_WO(clear),
507 };
508
509 /*
510  * create sysfs files on hwdep directory
511  */
512 int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
513 {
514         struct snd_hwdep *hwdep = codec->hwdep;
515         int i;
516
517         for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
518                 snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
519                                           hwdep->device, &codec_attrs[i]);
520         return 0;
521 }
522
523 /*
524  * Look for hint string
525  */
526 const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
527 {
528         struct hda_hint *hint = get_hint(codec, key);
529         return hint ? hint->val : NULL;
530 }
531 EXPORT_SYMBOL_HDA(snd_hda_get_hint);
532
533 int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
534 {
535         const char *p = snd_hda_get_hint(codec, key);
536         if (!p || !*p)
537                 return -ENOENT;
538         switch (toupper(*p)) {
539         case 'T': /* true */
540         case 'Y': /* yes */
541         case '1':
542                 return 1;
543         }
544         return 0;
545 }
546 EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
547
548 #endif /* CONFIG_SND_HDA_RECONFIG */