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_hda_power_up(codec); 180 snd_printk(KERN_INFO "hda-codec: reconfiguring\n"); 181 err = snd_hda_codec_reset(codec); 182 if (err < 0) { 183 snd_printk(KERN_ERR 184 "The codec is being used, can't reconfigure.\n"); 185 goto error; 186 } 187 err = snd_hda_codec_configure(codec); 188 if (err < 0) 189 goto error; 190 /* rebuild PCMs */ 191 err = snd_hda_codec_build_pcms(codec); 192 if (err < 0) 193 goto error; 194 /* rebuild mixers */ 195 err = snd_hda_codec_build_controls(codec); 196 if (err < 0) 197 goto error; 198 err = snd_card_register(codec->bus->card); 199 error: 200 snd_hda_power_down(codec); 201 return err; 202 } 203 204 /* 205 * allocate a string at most len chars, and remove the trailing EOL 206 */ 207 static char *kstrndup_noeol(const char *src, size_t len) 208 { 209 char *s = kstrndup(src, len, GFP_KERNEL); 210 char *p; 211 if (!s) 212 return NULL; 213 p = strchr(s, '\n'); 214 if (p) 215 *p = 0; 216 return s; 217 } 218 219 #define CODEC_INFO_SHOW(type) \ 220 static ssize_t type##_show(struct device *dev, \ 221 struct device_attribute *attr, \ 222 char *buf) \ 223 { \ 224 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ 225 struct hda_codec *codec = hwdep->private_data; \ 226 return sprintf(buf, "0x%x\n", codec->type); \ 227 } 228 229 #define CODEC_INFO_STR_SHOW(type) \ 230 static ssize_t type##_show(struct device *dev, \ 231 struct device_attribute *attr, \ 232 char *buf) \ 233 { \ 234 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ 235 struct hda_codec *codec = hwdep->private_data; \ 236 return sprintf(buf, "%s\n", \ 237 codec->type ? codec->type : ""); \ 238 } 239 240 CODEC_INFO_SHOW(vendor_id); 241 CODEC_INFO_SHOW(subsystem_id); 242 CODEC_INFO_SHOW(revision_id); 243 CODEC_INFO_SHOW(afg); 244 CODEC_INFO_SHOW(mfg); 245 CODEC_INFO_STR_SHOW(name); 246 CODEC_INFO_STR_SHOW(modelname); 247 248 #define CODEC_INFO_STORE(type) \ 249 static ssize_t type##_store(struct device *dev, \ 250 struct device_attribute *attr, \ 251 const char *buf, size_t count) \ 252 { \ 253 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ 254 struct hda_codec *codec = hwdep->private_data; \ 255 char *after; \ 256 codec->type = simple_strtoul(buf, &after, 0); \ 257 return count; \ 258 } 259 260 #define CODEC_INFO_STR_STORE(type) \ 261 static ssize_t type##_store(struct device *dev, \ 262 struct device_attribute *attr, \ 263 const char *buf, size_t count) \ 264 { \ 265 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ 266 struct hda_codec *codec = hwdep->private_data; \ 267 char *s = kstrndup_noeol(buf, 64); \ 268 if (!s) \ 269 return -ENOMEM; \ 270 kfree(codec->type); \ 271 codec->type = s; \ 272 return count; \ 273 } 274 275 CODEC_INFO_STORE(vendor_id); 276 CODEC_INFO_STORE(subsystem_id); 277 CODEC_INFO_STORE(revision_id); 278 CODEC_INFO_STR_STORE(name); 279 CODEC_INFO_STR_STORE(modelname); 280 281 #define CODEC_ACTION_STORE(type) \ 282 static ssize_t type##_store(struct device *dev, \ 283 struct device_attribute *attr, \ 284 const char *buf, size_t count) \ 285 { \ 286 struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ 287 struct hda_codec *codec = hwdep->private_data; \ 288 int err = 0; \ 289 if (*buf) \ 290 err = type##_codec(codec); \ 291 return err < 0 ? err : count; \ 292 } 293 294 CODEC_ACTION_STORE(reconfig); 295 CODEC_ACTION_STORE(clear); 296 297 static ssize_t init_verbs_show(struct device *dev, 298 struct device_attribute *attr, 299 char *buf) 300 { 301 struct snd_hwdep *hwdep = dev_get_drvdata(dev); 302 struct hda_codec *codec = hwdep->private_data; 303 int i, len = 0; 304 for (i = 0; i < codec->init_verbs.used; i++) { 305 struct hda_verb *v = snd_array_elem(&codec->init_verbs, i); 306 len += snprintf(buf + len, PAGE_SIZE - len, 307 "0x%02x 0x%03x 0x%04x\n", 308 v->nid, v->verb, v->param); 309 } 310 return len; 311 } 312 313 static ssize_t init_verbs_store(struct device *dev, 314 struct device_attribute *attr, 315 const char *buf, size_t count) 316 { 317 struct snd_hwdep *hwdep = dev_get_drvdata(dev); 318 struct hda_codec *codec = hwdep->private_data; 319 struct hda_verb *v; 320 int nid, verb, param; 321 322 if (sscanf(buf, "%i %i %i", &nid, &verb, ¶m) != 3) 323 return -EINVAL; 324 if (!nid || !verb) 325 return -EINVAL; 326 v = snd_array_new(&codec->init_verbs); 327 if (!v) 328 return -ENOMEM; 329 v->nid = nid; 330 v->verb = verb; 331 v->param = param; 332 return count; 333 } 334 335 static ssize_t hints_show(struct device *dev, 336 struct device_attribute *attr, 337 char *buf) 338 { 339 struct snd_hwdep *hwdep = dev_get_drvdata(dev); 340 struct hda_codec *codec = hwdep->private_data; 341 int i, len = 0; 342 for (i = 0; i < codec->hints.used; i++) { 343 struct hda_hint *hint = snd_array_elem(&codec->hints, i); 344 len += snprintf(buf + len, PAGE_SIZE - len, 345 "%s = %s\n", hint->key, hint->val); 346 } 347 return len; 348 } 349 350 static struct hda_hint *get_hint(struct hda_codec *codec, const char *key) 351 { 352 int i; 353 354 for (i = 0; i < codec->hints.used; i++) { 355 struct hda_hint *hint = snd_array_elem(&codec->hints, i); 356 if (!strcmp(hint->key, key)) 357 return hint; 358 } 359 return NULL; 360 } 361 362 static void remove_trail_spaces(char *str) 363 { 364 char *p; 365 if (!*str) 366 return; 367 p = str + strlen(str) - 1; 368 for (; isspace(*p); p--) { 369 *p = 0; 370 if (p == str) 371 return; 372 } 373 } 374 375 #define MAX_HINTS 1024 376 377 static ssize_t hints_store(struct device *dev, 378 struct device_attribute *attr, 379 const char *buf, size_t count) 380 { 381 struct snd_hwdep *hwdep = dev_get_drvdata(dev); 382 struct hda_codec *codec = hwdep->private_data; 383 char *key, *val; 384 struct hda_hint *hint; 385 386 while (isspace(*buf)) 387 buf++; 388 if (!*buf || *buf == '#' || *buf == '\n') 389 return count; 390 if (*buf == '=') 391 return -EINVAL; 392 key = kstrndup_noeol(buf, 1024); 393 if (!key) 394 return -ENOMEM; 395 /* extract key and val */ 396 val = strchr(key, '='); 397 if (!val) { 398 kfree(key); 399 return -EINVAL; 400 } 401 *val++ = 0; 402 while (isspace(*val)) 403 val++; 404 remove_trail_spaces(key); 405 remove_trail_spaces(val); 406 hint = get_hint(codec, key); 407 if (hint) { 408 /* replace */ 409 kfree(hint->key); 410 hint->key = key; 411 hint->val = val; 412 return count; 413 } 414 /* allocate a new hint entry */ 415 if (codec->hints.used >= MAX_HINTS) 416 hint = NULL; 417 else 418 hint = snd_array_new(&codec->hints); 419 if (!hint) { 420 kfree(key); 421 return -ENOMEM; 422 } 423 hint->key = key; 424 hint->val = val; 425 return count; 426 } 427 428 static ssize_t pin_configs_show(struct hda_codec *codec, 429 struct snd_array *list, 430 char *buf) 431 { 432 int i, len = 0; 433 for (i = 0; i < list->used; i++) { 434 struct hda_pincfg *pin = snd_array_elem(list, i); 435 len += sprintf(buf + len, "0x%02x 0x%08x\n", 436 pin->nid, pin->cfg); 437 } 438 return len; 439 } 440 441 static ssize_t init_pin_configs_show(struct device *dev, 442 struct device_attribute *attr, 443 char *buf) 444 { 445 struct snd_hwdep *hwdep = dev_get_drvdata(dev); 446 struct hda_codec *codec = hwdep->private_data; 447 return pin_configs_show(codec, &codec->init_pins, buf); 448 } 449 450 static ssize_t user_pin_configs_show(struct device *dev, 451 struct device_attribute *attr, 452 char *buf) 453 { 454 struct snd_hwdep *hwdep = dev_get_drvdata(dev); 455 struct hda_codec *codec = hwdep->private_data; 456 return pin_configs_show(codec, &codec->user_pins, buf); 457 } 458 459 static ssize_t driver_pin_configs_show(struct device *dev, 460 struct device_attribute *attr, 461 char *buf) 462 { 463 struct snd_hwdep *hwdep = dev_get_drvdata(dev); 464 struct hda_codec *codec = hwdep->private_data; 465 return pin_configs_show(codec, &codec->driver_pins, buf); 466 } 467 468 #define MAX_PIN_CONFIGS 32 469 470 static ssize_t user_pin_configs_store(struct device *dev, 471 struct device_attribute *attr, 472 const char *buf, size_t count) 473 { 474 struct snd_hwdep *hwdep = dev_get_drvdata(dev); 475 struct hda_codec *codec = hwdep->private_data; 476 int nid, cfg; 477 int err; 478 479 if (sscanf(buf, "%i %i", &nid, &cfg) != 2) 480 return -EINVAL; 481 if (!nid) 482 return -EINVAL; 483 err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); 484 if (err < 0) 485 return err; 486 return count; 487 } 488 489 #define CODEC_ATTR_RW(type) \ 490 __ATTR(type, 0644, type##_show, type##_store) 491 #define CODEC_ATTR_RO(type) \ 492 __ATTR_RO(type) 493 #define CODEC_ATTR_WO(type) \ 494 __ATTR(type, 0200, NULL, type##_store) 495 496 static struct device_attribute codec_attrs[] = { 497 CODEC_ATTR_RW(vendor_id), 498 CODEC_ATTR_RW(subsystem_id), 499 CODEC_ATTR_RW(revision_id), 500 CODEC_ATTR_RO(afg), 501 CODEC_ATTR_RO(mfg), 502 CODEC_ATTR_RW(name), 503 CODEC_ATTR_RW(modelname), 504 CODEC_ATTR_RW(init_verbs), 505 CODEC_ATTR_RW(hints), 506 CODEC_ATTR_RO(init_pin_configs), 507 CODEC_ATTR_RW(user_pin_configs), 508 CODEC_ATTR_RO(driver_pin_configs), 509 CODEC_ATTR_WO(reconfig), 510 CODEC_ATTR_WO(clear), 511 }; 512 513 /* 514 * create sysfs files on hwdep directory 515 */ 516 int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) 517 { 518 struct snd_hwdep *hwdep = codec->hwdep; 519 int i; 520 521 for (i = 0; i < ARRAY_SIZE(codec_attrs); i++) 522 snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, 523 hwdep->device, &codec_attrs[i]); 524 return 0; 525 } 526 527 /* 528 * Look for hint string 529 */ 530 const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) 531 { 532 struct hda_hint *hint = get_hint(codec, key); 533 return hint ? hint->val : NULL; 534 } 535 EXPORT_SYMBOL_HDA(snd_hda_get_hint); 536 537 int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) 538 { 539 const char *p = snd_hda_get_hint(codec, key); 540 if (!p || !*p) 541 return -ENOENT; 542 switch (toupper(*p)) { 543 case 'T': /* true */ 544 case 'Y': /* yes */ 545 case '1': 546 return 1; 547 } 548 return 0; 549 } 550 EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint); 551 552 #endif /* CONFIG_SND_HDA_RECONFIG */ 553