diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-09-24 01:52:47 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-24 01:52:47 -0400 |
commit | 23930fa1cebfea6f79881c588ccd1b0781e49e3f (patch) | |
tree | 36d29e3f83661c4f5f45b6f74ac0d5f9886867a8 /sound | |
parent | 36b35a5be0e4b406acd816e2122d153e875105be (diff) | |
parent | 4f5537de7c1531398e84e18a24f667e49cc94208 (diff) |
Merge branch 'master' into upstream
Diffstat (limited to 'sound')
100 files changed, 5128 insertions, 1788 deletions
diff --git a/sound/aoa/Kconfig b/sound/aoa/Kconfig index 2f4334d19ccd..5d5813cec4c8 100644 --- a/sound/aoa/Kconfig +++ b/sound/aoa/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | menu "Apple Onboard Audio driver" | 1 | menu "Apple Onboard Audio driver" |
2 | depends on SND!=n && PPC | 2 | depends on SND!=n && PPC_PMAC |
3 | 3 | ||
4 | config SND_AOA | 4 | config SND_AOA |
5 | tristate "Apple Onboard Audio driver" | 5 | tristate "Apple Onboard Audio driver" |
diff --git a/sound/aoa/codecs/Kconfig b/sound/aoa/codecs/Kconfig index 90cf58f68630..d5fbd6016e93 100644 --- a/sound/aoa/codecs/Kconfig +++ b/sound/aoa/codecs/Kconfig | |||
@@ -1,6 +1,8 @@ | |||
1 | config SND_AOA_ONYX | 1 | config SND_AOA_ONYX |
2 | tristate "support Onyx chip" | 2 | tristate "support Onyx chip" |
3 | depends on SND_AOA | 3 | depends on SND_AOA |
4 | select I2C | ||
5 | select I2C_POWERMAC | ||
4 | ---help--- | 6 | ---help--- |
5 | This option enables support for the Onyx (pcm3052) | 7 | This option enables support for the Onyx (pcm3052) |
6 | codec chip found in the latest Apple machines | 8 | codec chip found in the latest Apple machines |
@@ -18,6 +20,8 @@ config SND_AOA_ONYX | |||
18 | config SND_AOA_TAS | 20 | config SND_AOA_TAS |
19 | tristate "support TAS chips" | 21 | tristate "support TAS chips" |
20 | depends on SND_AOA | 22 | depends on SND_AOA |
23 | select I2C | ||
24 | select I2C_POWERMAC | ||
21 | ---help--- | 25 | ---help--- |
22 | This option enables support for the tas chips | 26 | This option enables support for the tas chips |
23 | found in a lot of Apple Machines, especially | 27 | found in a lot of Apple Machines, especially |
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 16c0b6b0a805..2ef55a17917c 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c | |||
@@ -66,6 +66,8 @@ | |||
66 | #include <asm/prom.h> | 66 | #include <asm/prom.h> |
67 | #include <linux/delay.h> | 67 | #include <linux/delay.h> |
68 | #include <linux/module.h> | 68 | #include <linux/module.h> |
69 | #include <linux/mutex.h> | ||
70 | |||
69 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | 71 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); |
70 | MODULE_LICENSE("GPL"); | 72 | MODULE_LICENSE("GPL"); |
71 | MODULE_DESCRIPTION("tas codec driver for snd-aoa"); | 73 | MODULE_DESCRIPTION("tas codec driver for snd-aoa"); |
@@ -91,6 +93,10 @@ struct tas { | |||
91 | u8 bass, treble; | 93 | u8 bass, treble; |
92 | u8 acr; | 94 | u8 acr; |
93 | int drc_range; | 95 | int drc_range; |
96 | /* protects hardware access against concurrency from | ||
97 | * userspace when hitting controls and during | ||
98 | * codec init/suspend/resume */ | ||
99 | struct mutex mtx; | ||
94 | }; | 100 | }; |
95 | 101 | ||
96 | static int tas_reset_init(struct tas *tas); | 102 | static int tas_reset_init(struct tas *tas); |
@@ -231,8 +237,10 @@ static int tas_snd_vol_get(struct snd_kcontrol *kcontrol, | |||
231 | { | 237 | { |
232 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 238 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
233 | 239 | ||
240 | mutex_lock(&tas->mtx); | ||
234 | ucontrol->value.integer.value[0] = tas->cached_volume_l; | 241 | ucontrol->value.integer.value[0] = tas->cached_volume_l; |
235 | ucontrol->value.integer.value[1] = tas->cached_volume_r; | 242 | ucontrol->value.integer.value[1] = tas->cached_volume_r; |
243 | mutex_unlock(&tas->mtx); | ||
236 | return 0; | 244 | return 0; |
237 | } | 245 | } |
238 | 246 | ||
@@ -241,14 +249,18 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, | |||
241 | { | 249 | { |
242 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 250 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
243 | 251 | ||
252 | mutex_lock(&tas->mtx); | ||
244 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] | 253 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] |
245 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) | 254 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) { |
255 | mutex_unlock(&tas->mtx); | ||
246 | return 0; | 256 | return 0; |
257 | } | ||
247 | 258 | ||
248 | tas->cached_volume_l = ucontrol->value.integer.value[0]; | 259 | tas->cached_volume_l = ucontrol->value.integer.value[0]; |
249 | tas->cached_volume_r = ucontrol->value.integer.value[1]; | 260 | tas->cached_volume_r = ucontrol->value.integer.value[1]; |
250 | if (tas->hw_enabled) | 261 | if (tas->hw_enabled) |
251 | tas_set_volume(tas); | 262 | tas_set_volume(tas); |
263 | mutex_unlock(&tas->mtx); | ||
252 | return 1; | 264 | return 1; |
253 | } | 265 | } |
254 | 266 | ||
@@ -276,8 +288,10 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, | |||
276 | { | 288 | { |
277 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 289 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
278 | 290 | ||
291 | mutex_lock(&tas->mtx); | ||
279 | ucontrol->value.integer.value[0] = !tas->mute_l; | 292 | ucontrol->value.integer.value[0] = !tas->mute_l; |
280 | ucontrol->value.integer.value[1] = !tas->mute_r; | 293 | ucontrol->value.integer.value[1] = !tas->mute_r; |
294 | mutex_unlock(&tas->mtx); | ||
281 | return 0; | 295 | return 0; |
282 | } | 296 | } |
283 | 297 | ||
@@ -286,14 +300,18 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, | |||
286 | { | 300 | { |
287 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 301 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
288 | 302 | ||
303 | mutex_lock(&tas->mtx); | ||
289 | if (tas->mute_l == !ucontrol->value.integer.value[0] | 304 | if (tas->mute_l == !ucontrol->value.integer.value[0] |
290 | && tas->mute_r == !ucontrol->value.integer.value[1]) | 305 | && tas->mute_r == !ucontrol->value.integer.value[1]) { |
306 | mutex_unlock(&tas->mtx); | ||
291 | return 0; | 307 | return 0; |
308 | } | ||
292 | 309 | ||
293 | tas->mute_l = !ucontrol->value.integer.value[0]; | 310 | tas->mute_l = !ucontrol->value.integer.value[0]; |
294 | tas->mute_r = !ucontrol->value.integer.value[1]; | 311 | tas->mute_r = !ucontrol->value.integer.value[1]; |
295 | if (tas->hw_enabled) | 312 | if (tas->hw_enabled) |
296 | tas_set_volume(tas); | 313 | tas_set_volume(tas); |
314 | mutex_unlock(&tas->mtx); | ||
297 | return 1; | 315 | return 1; |
298 | } | 316 | } |
299 | 317 | ||
@@ -322,8 +340,10 @@ static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol, | |||
322 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 340 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
323 | int idx = kcontrol->private_value; | 341 | int idx = kcontrol->private_value; |
324 | 342 | ||
343 | mutex_lock(&tas->mtx); | ||
325 | ucontrol->value.integer.value[0] = tas->mixer_l[idx]; | 344 | ucontrol->value.integer.value[0] = tas->mixer_l[idx]; |
326 | ucontrol->value.integer.value[1] = tas->mixer_r[idx]; | 345 | ucontrol->value.integer.value[1] = tas->mixer_r[idx]; |
346 | mutex_unlock(&tas->mtx); | ||
327 | 347 | ||
328 | return 0; | 348 | return 0; |
329 | } | 349 | } |
@@ -334,15 +354,19 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol, | |||
334 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 354 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
335 | int idx = kcontrol->private_value; | 355 | int idx = kcontrol->private_value; |
336 | 356 | ||
357 | mutex_lock(&tas->mtx); | ||
337 | if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] | 358 | if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] |
338 | && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) | 359 | && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) { |
360 | mutex_unlock(&tas->mtx); | ||
339 | return 0; | 361 | return 0; |
362 | } | ||
340 | 363 | ||
341 | tas->mixer_l[idx] = ucontrol->value.integer.value[0]; | 364 | tas->mixer_l[idx] = ucontrol->value.integer.value[0]; |
342 | tas->mixer_r[idx] = ucontrol->value.integer.value[1]; | 365 | tas->mixer_r[idx] = ucontrol->value.integer.value[1]; |
343 | 366 | ||
344 | if (tas->hw_enabled) | 367 | if (tas->hw_enabled) |
345 | tas_set_mixer(tas); | 368 | tas_set_mixer(tas); |
369 | mutex_unlock(&tas->mtx); | ||
346 | return 1; | 370 | return 1; |
347 | } | 371 | } |
348 | 372 | ||
@@ -375,7 +399,9 @@ static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol, | |||
375 | { | 399 | { |
376 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 400 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
377 | 401 | ||
402 | mutex_lock(&tas->mtx); | ||
378 | ucontrol->value.integer.value[0] = tas->drc_range; | 403 | ucontrol->value.integer.value[0] = tas->drc_range; |
404 | mutex_unlock(&tas->mtx); | ||
379 | return 0; | 405 | return 0; |
380 | } | 406 | } |
381 | 407 | ||
@@ -384,12 +410,16 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, | |||
384 | { | 410 | { |
385 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 411 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
386 | 412 | ||
387 | if (tas->drc_range == ucontrol->value.integer.value[0]) | 413 | mutex_lock(&tas->mtx); |
414 | if (tas->drc_range == ucontrol->value.integer.value[0]) { | ||
415 | mutex_unlock(&tas->mtx); | ||
388 | return 0; | 416 | return 0; |
417 | } | ||
389 | 418 | ||
390 | tas->drc_range = ucontrol->value.integer.value[0]; | 419 | tas->drc_range = ucontrol->value.integer.value[0]; |
391 | if (tas->hw_enabled) | 420 | if (tas->hw_enabled) |
392 | tas3004_set_drc(tas); | 421 | tas3004_set_drc(tas); |
422 | mutex_unlock(&tas->mtx); | ||
393 | return 1; | 423 | return 1; |
394 | } | 424 | } |
395 | 425 | ||
@@ -417,7 +447,9 @@ static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol, | |||
417 | { | 447 | { |
418 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 448 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
419 | 449 | ||
450 | mutex_lock(&tas->mtx); | ||
420 | ucontrol->value.integer.value[0] = tas->drc_enabled; | 451 | ucontrol->value.integer.value[0] = tas->drc_enabled; |
452 | mutex_unlock(&tas->mtx); | ||
421 | return 0; | 453 | return 0; |
422 | } | 454 | } |
423 | 455 | ||
@@ -426,12 +458,16 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, | |||
426 | { | 458 | { |
427 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 459 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
428 | 460 | ||
429 | if (tas->drc_enabled == ucontrol->value.integer.value[0]) | 461 | mutex_lock(&tas->mtx); |
462 | if (tas->drc_enabled == ucontrol->value.integer.value[0]) { | ||
463 | mutex_unlock(&tas->mtx); | ||
430 | return 0; | 464 | return 0; |
465 | } | ||
431 | 466 | ||
432 | tas->drc_enabled = ucontrol->value.integer.value[0]; | 467 | tas->drc_enabled = ucontrol->value.integer.value[0]; |
433 | if (tas->hw_enabled) | 468 | if (tas->hw_enabled) |
434 | tas3004_set_drc(tas); | 469 | tas3004_set_drc(tas); |
470 | mutex_unlock(&tas->mtx); | ||
435 | return 1; | 471 | return 1; |
436 | } | 472 | } |
437 | 473 | ||
@@ -463,7 +499,9 @@ static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol, | |||
463 | { | 499 | { |
464 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 500 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
465 | 501 | ||
502 | mutex_lock(&tas->mtx); | ||
466 | ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); | 503 | ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); |
504 | mutex_unlock(&tas->mtx); | ||
467 | return 0; | 505 | return 0; |
468 | } | 506 | } |
469 | 507 | ||
@@ -471,15 +509,21 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, | |||
471 | struct snd_ctl_elem_value *ucontrol) | 509 | struct snd_ctl_elem_value *ucontrol) |
472 | { | 510 | { |
473 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 511 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
474 | int oldacr = tas->acr; | 512 | int oldacr; |
513 | |||
514 | mutex_lock(&tas->mtx); | ||
515 | oldacr = tas->acr; | ||
475 | 516 | ||
476 | tas->acr &= ~TAS_ACR_INPUT_B; | 517 | tas->acr &= ~TAS_ACR_INPUT_B; |
477 | if (ucontrol->value.enumerated.item[0]) | 518 | if (ucontrol->value.enumerated.item[0]) |
478 | tas->acr |= TAS_ACR_INPUT_B; | 519 | tas->acr |= TAS_ACR_INPUT_B; |
479 | if (oldacr == tas->acr) | 520 | if (oldacr == tas->acr) { |
521 | mutex_unlock(&tas->mtx); | ||
480 | return 0; | 522 | return 0; |
523 | } | ||
481 | if (tas->hw_enabled) | 524 | if (tas->hw_enabled) |
482 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); | 525 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); |
526 | mutex_unlock(&tas->mtx); | ||
483 | return 1; | 527 | return 1; |
484 | } | 528 | } |
485 | 529 | ||
@@ -518,7 +562,9 @@ static int tas_snd_treble_get(struct snd_kcontrol *kcontrol, | |||
518 | { | 562 | { |
519 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 563 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
520 | 564 | ||
565 | mutex_lock(&tas->mtx); | ||
521 | ucontrol->value.integer.value[0] = tas->treble; | 566 | ucontrol->value.integer.value[0] = tas->treble; |
567 | mutex_unlock(&tas->mtx); | ||
522 | return 0; | 568 | return 0; |
523 | } | 569 | } |
524 | 570 | ||
@@ -527,12 +573,16 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, | |||
527 | { | 573 | { |
528 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 574 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
529 | 575 | ||
530 | if (tas->treble == ucontrol->value.integer.value[0]) | 576 | mutex_lock(&tas->mtx); |
577 | if (tas->treble == ucontrol->value.integer.value[0]) { | ||
578 | mutex_unlock(&tas->mtx); | ||
531 | return 0; | 579 | return 0; |
580 | } | ||
532 | 581 | ||
533 | tas->treble = ucontrol->value.integer.value[0]; | 582 | tas->treble = ucontrol->value.integer.value[0]; |
534 | if (tas->hw_enabled) | 583 | if (tas->hw_enabled) |
535 | tas_set_treble(tas); | 584 | tas_set_treble(tas); |
585 | mutex_unlock(&tas->mtx); | ||
536 | return 1; | 586 | return 1; |
537 | } | 587 | } |
538 | 588 | ||
@@ -560,7 +610,9 @@ static int tas_snd_bass_get(struct snd_kcontrol *kcontrol, | |||
560 | { | 610 | { |
561 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 611 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
562 | 612 | ||
613 | mutex_lock(&tas->mtx); | ||
563 | ucontrol->value.integer.value[0] = tas->bass; | 614 | ucontrol->value.integer.value[0] = tas->bass; |
615 | mutex_unlock(&tas->mtx); | ||
564 | return 0; | 616 | return 0; |
565 | } | 617 | } |
566 | 618 | ||
@@ -569,12 +621,16 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, | |||
569 | { | 621 | { |
570 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 622 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
571 | 623 | ||
572 | if (tas->bass == ucontrol->value.integer.value[0]) | 624 | mutex_lock(&tas->mtx); |
625 | if (tas->bass == ucontrol->value.integer.value[0]) { | ||
626 | mutex_unlock(&tas->mtx); | ||
573 | return 0; | 627 | return 0; |
628 | } | ||
574 | 629 | ||
575 | tas->bass = ucontrol->value.integer.value[0]; | 630 | tas->bass = ucontrol->value.integer.value[0]; |
576 | if (tas->hw_enabled) | 631 | if (tas->hw_enabled) |
577 | tas_set_bass(tas); | 632 | tas_set_bass(tas); |
633 | mutex_unlock(&tas->mtx); | ||
578 | return 1; | 634 | return 1; |
579 | } | 635 | } |
580 | 636 | ||
@@ -628,16 +684,16 @@ static int tas_reset_init(struct tas *tas) | |||
628 | 684 | ||
629 | tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; | 685 | tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; |
630 | if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) | 686 | if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) |
631 | return -ENODEV; | 687 | goto outerr; |
632 | 688 | ||
633 | tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL | | 689 | tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL | |
634 | TAS_ACR_B_MON_SEL_RIGHT; | 690 | TAS_ACR_B_MON_SEL_RIGHT; |
635 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) | 691 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) |
636 | return -ENODEV; | 692 | goto outerr; |
637 | 693 | ||
638 | tmp = 0; | 694 | tmp = 0; |
639 | if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) | 695 | if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) |
640 | return -ENODEV; | 696 | goto outerr; |
641 | 697 | ||
642 | tas3004_set_drc(tas); | 698 | tas3004_set_drc(tas); |
643 | 699 | ||
@@ -649,9 +705,11 @@ static int tas_reset_init(struct tas *tas) | |||
649 | 705 | ||
650 | tas->acr &= ~TAS_ACR_ANALOG_PDOWN; | 706 | tas->acr &= ~TAS_ACR_ANALOG_PDOWN; |
651 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) | 707 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) |
652 | return -ENODEV; | 708 | goto outerr; |
653 | 709 | ||
654 | return 0; | 710 | return 0; |
711 | outerr: | ||
712 | return -ENODEV; | ||
655 | } | 713 | } |
656 | 714 | ||
657 | static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock) | 715 | static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock) |
@@ -666,11 +724,13 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock | |||
666 | break; | 724 | break; |
667 | case CLOCK_SWITCH_SLAVE: | 725 | case CLOCK_SWITCH_SLAVE: |
668 | /* Clocks are back, re-init the codec */ | 726 | /* Clocks are back, re-init the codec */ |
727 | mutex_lock(&tas->mtx); | ||
669 | tas_reset_init(tas); | 728 | tas_reset_init(tas); |
670 | tas_set_volume(tas); | 729 | tas_set_volume(tas); |
671 | tas_set_mixer(tas); | 730 | tas_set_mixer(tas); |
672 | tas->hw_enabled = 1; | 731 | tas->hw_enabled = 1; |
673 | tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); | 732 | tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); |
733 | mutex_unlock(&tas->mtx); | ||
674 | break; | 734 | break; |
675 | default: | 735 | default: |
676 | /* doesn't happen as of now */ | 736 | /* doesn't happen as of now */ |
@@ -684,19 +744,23 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock | |||
684 | * our i2c device is suspended, and then take note of that! */ | 744 | * our i2c device is suspended, and then take note of that! */ |
685 | static int tas_suspend(struct tas *tas) | 745 | static int tas_suspend(struct tas *tas) |
686 | { | 746 | { |
747 | mutex_lock(&tas->mtx); | ||
687 | tas->hw_enabled = 0; | 748 | tas->hw_enabled = 0; |
688 | tas->acr |= TAS_ACR_ANALOG_PDOWN; | 749 | tas->acr |= TAS_ACR_ANALOG_PDOWN; |
689 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); | 750 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); |
751 | mutex_unlock(&tas->mtx); | ||
690 | return 0; | 752 | return 0; |
691 | } | 753 | } |
692 | 754 | ||
693 | static int tas_resume(struct tas *tas) | 755 | static int tas_resume(struct tas *tas) |
694 | { | 756 | { |
695 | /* reset codec */ | 757 | /* reset codec */ |
758 | mutex_lock(&tas->mtx); | ||
696 | tas_reset_init(tas); | 759 | tas_reset_init(tas); |
697 | tas_set_volume(tas); | 760 | tas_set_volume(tas); |
698 | tas_set_mixer(tas); | 761 | tas_set_mixer(tas); |
699 | tas->hw_enabled = 1; | 762 | tas->hw_enabled = 1; |
763 | mutex_unlock(&tas->mtx); | ||
700 | return 0; | 764 | return 0; |
701 | } | 765 | } |
702 | 766 | ||
@@ -739,11 +803,14 @@ static int tas_init_codec(struct aoa_codec *codec) | |||
739 | return -EINVAL; | 803 | return -EINVAL; |
740 | } | 804 | } |
741 | 805 | ||
806 | mutex_lock(&tas->mtx); | ||
742 | if (tas_reset_init(tas)) { | 807 | if (tas_reset_init(tas)) { |
743 | printk(KERN_ERR PFX "tas failed to initialise\n"); | 808 | printk(KERN_ERR PFX "tas failed to initialise\n"); |
809 | mutex_unlock(&tas->mtx); | ||
744 | return -ENXIO; | 810 | return -ENXIO; |
745 | } | 811 | } |
746 | tas->hw_enabled = 1; | 812 | tas->hw_enabled = 1; |
813 | mutex_unlock(&tas->mtx); | ||
747 | 814 | ||
748 | if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, | 815 | if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, |
749 | aoa_get_card(), | 816 | aoa_get_card(), |
@@ -822,6 +889,7 @@ static int tas_create(struct i2c_adapter *adapter, | |||
822 | if (!tas) | 889 | if (!tas) |
823 | return -ENOMEM; | 890 | return -ENOMEM; |
824 | 891 | ||
892 | mutex_init(&tas->mtx); | ||
825 | tas->i2c.driver = &tas_driver; | 893 | tas->i2c.driver = &tas_driver; |
826 | tas->i2c.adapter = adapter; | 894 | tas->i2c.adapter = adapter; |
827 | tas->i2c.addr = addr; | 895 | tas->i2c.addr = addr; |
@@ -850,6 +918,7 @@ static int tas_create(struct i2c_adapter *adapter, | |||
850 | detach: | 918 | detach: |
851 | i2c_detach_client(&tas->i2c); | 919 | i2c_detach_client(&tas->i2c); |
852 | fail: | 920 | fail: |
921 | mutex_destroy(&tas->mtx); | ||
853 | kfree(tas); | 922 | kfree(tas); |
854 | return -EINVAL; | 923 | return -EINVAL; |
855 | } | 924 | } |
@@ -908,6 +977,7 @@ static int tas_i2c_detach(struct i2c_client *client) | |||
908 | /* power down codec chip */ | 977 | /* power down codec chip */ |
909 | tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); | 978 | tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); |
910 | 979 | ||
980 | mutex_destroy(&tas->mtx); | ||
911 | kfree(tas); | 981 | kfree(tas); |
912 | return 0; | 982 | return 0; |
913 | } | 983 | } |
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c index f69d33357a28..7c26089527f6 100644 --- a/sound/aoa/core/snd-aoa-gpio-feature.c +++ b/sound/aoa/core/snd-aoa-gpio-feature.c | |||
@@ -56,7 +56,7 @@ static struct device_node *get_gpio(char *name, | |||
56 | { | 56 | { |
57 | struct device_node *np, *gpio; | 57 | struct device_node *np, *gpio; |
58 | u32 *reg; | 58 | u32 *reg; |
59 | char *audio_gpio; | 59 | const char *audio_gpio; |
60 | 60 | ||
61 | *gpioptr = -1; | 61 | *gpioptr = -1; |
62 | 62 | ||
diff --git a/sound/core/control.c b/sound/core/control.c index bb397eaa7187..6973a9686b67 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -75,6 +75,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file) | |||
75 | init_waitqueue_head(&ctl->change_sleep); | 75 | init_waitqueue_head(&ctl->change_sleep); |
76 | spin_lock_init(&ctl->read_lock); | 76 | spin_lock_init(&ctl->read_lock); |
77 | ctl->card = card; | 77 | ctl->card = card; |
78 | ctl->prefer_pcm_subdevice = -1; | ||
79 | ctl->prefer_rawmidi_subdevice = -1; | ||
78 | ctl->pid = current->pid; | 80 | ctl->pid = current->pid; |
79 | file->private_data = ctl; | 81 | file->private_data = ctl; |
80 | write_lock_irqsave(&card->ctl_files_rwlock, flags); | 82 | write_lock_irqsave(&card->ctl_files_rwlock, flags); |
@@ -236,11 +238,16 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, | |||
236 | kctl.id.index = ncontrol->index; | 238 | kctl.id.index = ncontrol->index; |
237 | kctl.count = ncontrol->count ? ncontrol->count : 1; | 239 | kctl.count = ncontrol->count ? ncontrol->count : 1; |
238 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 240 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
239 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE| | 241 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| |
240 | SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT)); | 242 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| |
243 | SNDRV_CTL_ELEM_ACCESS_DINDIRECT| | ||
244 | SNDRV_CTL_ELEM_ACCESS_INDIRECT| | ||
245 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| | ||
246 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); | ||
241 | kctl.info = ncontrol->info; | 247 | kctl.info = ncontrol->info; |
242 | kctl.get = ncontrol->get; | 248 | kctl.get = ncontrol->get; |
243 | kctl.put = ncontrol->put; | 249 | kctl.put = ncontrol->put; |
250 | kctl.tlv.p = ncontrol->tlv.p; | ||
244 | kctl.private_value = ncontrol->private_value; | 251 | kctl.private_value = ncontrol->private_value; |
245 | kctl.private_data = private_data; | 252 | kctl.private_data = private_data; |
246 | return snd_ctl_new(&kctl, access); | 253 | return snd_ctl_new(&kctl, access); |
@@ -882,6 +889,8 @@ struct user_element { | |||
882 | struct snd_ctl_elem_info info; | 889 | struct snd_ctl_elem_info info; |
883 | void *elem_data; /* element data */ | 890 | void *elem_data; /* element data */ |
884 | unsigned long elem_data_size; /* size of element data in bytes */ | 891 | unsigned long elem_data_size; /* size of element data in bytes */ |
892 | void *tlv_data; /* TLV data */ | ||
893 | unsigned long tlv_data_size; /* TLV data size */ | ||
885 | void *priv_data; /* private data (like strings for enumerated type) */ | 894 | void *priv_data; /* private data (like strings for enumerated type) */ |
886 | unsigned long priv_data_size; /* size of private data in bytes */ | 895 | unsigned long priv_data_size; /* size of private data in bytes */ |
887 | }; | 896 | }; |
@@ -916,9 +925,48 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, | |||
916 | return change; | 925 | return change; |
917 | } | 926 | } |
918 | 927 | ||
928 | static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, | ||
929 | int op_flag, | ||
930 | unsigned int size, | ||
931 | unsigned int __user *tlv) | ||
932 | { | ||
933 | struct user_element *ue = kcontrol->private_data; | ||
934 | int change = 0; | ||
935 | void *new_data; | ||
936 | |||
937 | if (op_flag > 0) { | ||
938 | if (size > 1024 * 128) /* sane value */ | ||
939 | return -EINVAL; | ||
940 | new_data = kmalloc(size, GFP_KERNEL); | ||
941 | if (new_data == NULL) | ||
942 | return -ENOMEM; | ||
943 | if (copy_from_user(new_data, tlv, size)) { | ||
944 | kfree(new_data); | ||
945 | return -EFAULT; | ||
946 | } | ||
947 | change = ue->tlv_data_size != size; | ||
948 | if (!change) | ||
949 | change = memcmp(ue->tlv_data, new_data, size); | ||
950 | kfree(ue->tlv_data); | ||
951 | ue->tlv_data = new_data; | ||
952 | ue->tlv_data_size = size; | ||
953 | } else { | ||
954 | if (! ue->tlv_data_size || ! ue->tlv_data) | ||
955 | return -ENXIO; | ||
956 | if (size < ue->tlv_data_size) | ||
957 | return -ENOSPC; | ||
958 | if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) | ||
959 | return -EFAULT; | ||
960 | } | ||
961 | return change; | ||
962 | } | ||
963 | |||
919 | static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) | 964 | static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) |
920 | { | 965 | { |
921 | kfree(kcontrol->private_data); | 966 | struct user_element *ue = kcontrol->private_data; |
967 | if (ue->tlv_data) | ||
968 | kfree(ue->tlv_data); | ||
969 | kfree(ue); | ||
922 | } | 970 | } |
923 | 971 | ||
924 | static int snd_ctl_elem_add(struct snd_ctl_file *file, | 972 | static int snd_ctl_elem_add(struct snd_ctl_file *file, |
@@ -937,7 +985,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
937 | return -EINVAL; | 985 | return -EINVAL; |
938 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 986 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
939 | (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| | 987 | (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| |
940 | SNDRV_CTL_ELEM_ACCESS_INACTIVE)); | 988 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| |
989 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); | ||
941 | info->id.numid = 0; | 990 | info->id.numid = 0; |
942 | memset(&kctl, 0, sizeof(kctl)); | 991 | memset(&kctl, 0, sizeof(kctl)); |
943 | down_write(&card->controls_rwsem); | 992 | down_write(&card->controls_rwsem); |
@@ -963,6 +1012,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
963 | kctl.get = snd_ctl_elem_user_get; | 1012 | kctl.get = snd_ctl_elem_user_get; |
964 | if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) | 1013 | if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) |
965 | kctl.put = snd_ctl_elem_user_put; | 1014 | kctl.put = snd_ctl_elem_user_put; |
1015 | if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { | ||
1016 | kctl.tlv.c = snd_ctl_elem_user_tlv; | ||
1017 | access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | ||
1018 | } | ||
966 | switch (info->type) { | 1019 | switch (info->type) { |
967 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | 1020 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: |
968 | private_size = sizeof(char); | 1021 | private_size = sizeof(char); |
@@ -997,6 +1050,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
997 | if (ue == NULL) | 1050 | if (ue == NULL) |
998 | return -ENOMEM; | 1051 | return -ENOMEM; |
999 | ue->info = *info; | 1052 | ue->info = *info; |
1053 | ue->info.access = 0; | ||
1000 | ue->elem_data = (char *)ue + sizeof(*ue); | 1054 | ue->elem_data = (char *)ue + sizeof(*ue); |
1001 | ue->elem_data_size = private_size; | 1055 | ue->elem_data_size = private_size; |
1002 | kctl.private_free = snd_ctl_elem_user_free; | 1056 | kctl.private_free = snd_ctl_elem_user_free; |
@@ -1067,6 +1121,67 @@ static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr) | |||
1067 | return 0; | 1121 | return 0; |
1068 | } | 1122 | } |
1069 | 1123 | ||
1124 | static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, | ||
1125 | struct snd_ctl_tlv __user *_tlv, | ||
1126 | int op_flag) | ||
1127 | { | ||
1128 | struct snd_card *card = file->card; | ||
1129 | struct snd_ctl_tlv tlv; | ||
1130 | struct snd_kcontrol *kctl; | ||
1131 | struct snd_kcontrol_volatile *vd; | ||
1132 | unsigned int len; | ||
1133 | int err = 0; | ||
1134 | |||
1135 | if (copy_from_user(&tlv, _tlv, sizeof(tlv))) | ||
1136 | return -EFAULT; | ||
1137 | if (tlv.length < sizeof(unsigned int) * 3) | ||
1138 | return -EINVAL; | ||
1139 | down_read(&card->controls_rwsem); | ||
1140 | kctl = snd_ctl_find_numid(card, tlv.numid); | ||
1141 | if (kctl == NULL) { | ||
1142 | err = -ENOENT; | ||
1143 | goto __kctl_end; | ||
1144 | } | ||
1145 | if (kctl->tlv.p == NULL) { | ||
1146 | err = -ENXIO; | ||
1147 | goto __kctl_end; | ||
1148 | } | ||
1149 | vd = &kctl->vd[tlv.numid - kctl->id.numid]; | ||
1150 | if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || | ||
1151 | (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || | ||
1152 | (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { | ||
1153 | err = -ENXIO; | ||
1154 | goto __kctl_end; | ||
1155 | } | ||
1156 | if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { | ||
1157 | if (file && vd->owner != NULL && vd->owner != file) { | ||
1158 | err = -EPERM; | ||
1159 | goto __kctl_end; | ||
1160 | } | ||
1161 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); | ||
1162 | if (err > 0) { | ||
1163 | up_read(&card->controls_rwsem); | ||
1164 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); | ||
1165 | return 0; | ||
1166 | } | ||
1167 | } else { | ||
1168 | if (op_flag) { | ||
1169 | err = -ENXIO; | ||
1170 | goto __kctl_end; | ||
1171 | } | ||
1172 | len = kctl->tlv.p[1] + 2 * sizeof(unsigned int); | ||
1173 | if (tlv.length < len) { | ||
1174 | err = -ENOMEM; | ||
1175 | goto __kctl_end; | ||
1176 | } | ||
1177 | if (copy_to_user(_tlv->tlv, kctl->tlv.p, len)) | ||
1178 | err = -EFAULT; | ||
1179 | } | ||
1180 | __kctl_end: | ||
1181 | up_read(&card->controls_rwsem); | ||
1182 | return err; | ||
1183 | } | ||
1184 | |||
1070 | static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1185 | static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1071 | { | 1186 | { |
1072 | struct snd_ctl_file *ctl; | 1187 | struct snd_ctl_file *ctl; |
@@ -1086,11 +1201,11 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
1086 | case SNDRV_CTL_IOCTL_CARD_INFO: | 1201 | case SNDRV_CTL_IOCTL_CARD_INFO: |
1087 | return snd_ctl_card_info(card, ctl, cmd, argp); | 1202 | return snd_ctl_card_info(card, ctl, cmd, argp); |
1088 | case SNDRV_CTL_IOCTL_ELEM_LIST: | 1203 | case SNDRV_CTL_IOCTL_ELEM_LIST: |
1089 | return snd_ctl_elem_list(ctl->card, argp); | 1204 | return snd_ctl_elem_list(card, argp); |
1090 | case SNDRV_CTL_IOCTL_ELEM_INFO: | 1205 | case SNDRV_CTL_IOCTL_ELEM_INFO: |
1091 | return snd_ctl_elem_info_user(ctl, argp); | 1206 | return snd_ctl_elem_info_user(ctl, argp); |
1092 | case SNDRV_CTL_IOCTL_ELEM_READ: | 1207 | case SNDRV_CTL_IOCTL_ELEM_READ: |
1093 | return snd_ctl_elem_read_user(ctl->card, argp); | 1208 | return snd_ctl_elem_read_user(card, argp); |
1094 | case SNDRV_CTL_IOCTL_ELEM_WRITE: | 1209 | case SNDRV_CTL_IOCTL_ELEM_WRITE: |
1095 | return snd_ctl_elem_write_user(ctl, argp); | 1210 | return snd_ctl_elem_write_user(ctl, argp); |
1096 | case SNDRV_CTL_IOCTL_ELEM_LOCK: | 1211 | case SNDRV_CTL_IOCTL_ELEM_LOCK: |
@@ -1105,6 +1220,12 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
1105 | return snd_ctl_elem_remove(ctl, argp); | 1220 | return snd_ctl_elem_remove(ctl, argp); |
1106 | case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: | 1221 | case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: |
1107 | return snd_ctl_subscribe_events(ctl, ip); | 1222 | return snd_ctl_subscribe_events(ctl, ip); |
1223 | case SNDRV_CTL_IOCTL_TLV_READ: | ||
1224 | return snd_ctl_tlv_ioctl(ctl, argp, 0); | ||
1225 | case SNDRV_CTL_IOCTL_TLV_WRITE: | ||
1226 | return snd_ctl_tlv_ioctl(ctl, argp, 1); | ||
1227 | case SNDRV_CTL_IOCTL_TLV_COMMAND: | ||
1228 | return snd_ctl_tlv_ioctl(ctl, argp, -1); | ||
1108 | case SNDRV_CTL_IOCTL_POWER: | 1229 | case SNDRV_CTL_IOCTL_POWER: |
1109 | return -ENOPROTOOPT; | 1230 | return -ENOPROTOOPT; |
1110 | case SNDRV_CTL_IOCTL_POWER_STATE: | 1231 | case SNDRV_CTL_IOCTL_POWER_STATE: |
@@ -1338,6 +1459,11 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) | |||
1338 | struct snd_card *card = device->device_data; | 1459 | struct snd_card *card = device->device_data; |
1339 | struct list_head *flist; | 1460 | struct list_head *flist; |
1340 | struct snd_ctl_file *ctl; | 1461 | struct snd_ctl_file *ctl; |
1462 | int err, cardnum; | ||
1463 | |||
1464 | snd_assert(card != NULL, return -ENXIO); | ||
1465 | cardnum = card->number; | ||
1466 | snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); | ||
1341 | 1467 | ||
1342 | down_read(&card->controls_rwsem); | 1468 | down_read(&card->controls_rwsem); |
1343 | list_for_each(flist, &card->ctl_files) { | 1469 | list_for_each(flist, &card->ctl_files) { |
@@ -1346,6 +1472,10 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) | |||
1346 | kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); | 1472 | kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); |
1347 | } | 1473 | } |
1348 | up_read(&card->controls_rwsem); | 1474 | up_read(&card->controls_rwsem); |
1475 | |||
1476 | if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, | ||
1477 | card, -1)) < 0) | ||
1478 | return err; | ||
1349 | return 0; | 1479 | return 0; |
1350 | } | 1480 | } |
1351 | 1481 | ||
@@ -1367,23 +1497,6 @@ static int snd_ctl_dev_free(struct snd_device *device) | |||
1367 | } | 1497 | } |
1368 | 1498 | ||
1369 | /* | 1499 | /* |
1370 | * de-registration of the control device | ||
1371 | */ | ||
1372 | static int snd_ctl_dev_unregister(struct snd_device *device) | ||
1373 | { | ||
1374 | struct snd_card *card = device->device_data; | ||
1375 | int err, cardnum; | ||
1376 | |||
1377 | snd_assert(card != NULL, return -ENXIO); | ||
1378 | cardnum = card->number; | ||
1379 | snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); | ||
1380 | if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, | ||
1381 | card, -1)) < 0) | ||
1382 | return err; | ||
1383 | return snd_ctl_dev_free(device); | ||
1384 | } | ||
1385 | |||
1386 | /* | ||
1387 | * create control core: | 1500 | * create control core: |
1388 | * called from init.c | 1501 | * called from init.c |
1389 | */ | 1502 | */ |
@@ -1393,7 +1506,6 @@ int snd_ctl_create(struct snd_card *card) | |||
1393 | .dev_free = snd_ctl_dev_free, | 1506 | .dev_free = snd_ctl_dev_free, |
1394 | .dev_register = snd_ctl_dev_register, | 1507 | .dev_register = snd_ctl_dev_register, |
1395 | .dev_disconnect = snd_ctl_dev_disconnect, | 1508 | .dev_disconnect = snd_ctl_dev_disconnect, |
1396 | .dev_unregister = snd_ctl_dev_unregister | ||
1397 | }; | 1509 | }; |
1398 | 1510 | ||
1399 | snd_assert(card != NULL, return -ENXIO); | 1511 | snd_assert(card != NULL, return -ENXIO); |
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 3c0161bb5ba4..ab48962c48ce 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c | |||
@@ -407,6 +407,10 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns | |||
407 | case SNDRV_CTL_IOCTL_POWER_STATE: | 407 | case SNDRV_CTL_IOCTL_POWER_STATE: |
408 | case SNDRV_CTL_IOCTL_ELEM_LOCK: | 408 | case SNDRV_CTL_IOCTL_ELEM_LOCK: |
409 | case SNDRV_CTL_IOCTL_ELEM_UNLOCK: | 409 | case SNDRV_CTL_IOCTL_ELEM_UNLOCK: |
410 | case SNDRV_CTL_IOCTL_ELEM_REMOVE: | ||
411 | case SNDRV_CTL_IOCTL_TLV_READ: | ||
412 | case SNDRV_CTL_IOCTL_TLV_WRITE: | ||
413 | case SNDRV_CTL_IOCTL_TLV_COMMAND: | ||
410 | return snd_ctl_ioctl(file, cmd, (unsigned long)argp); | 414 | return snd_ctl_ioctl(file, cmd, (unsigned long)argp); |
411 | case SNDRV_CTL_IOCTL_ELEM_LIST32: | 415 | case SNDRV_CTL_IOCTL_ELEM_LIST32: |
412 | return snd_ctl_elem_list_compat(ctl->card, argp); | 416 | return snd_ctl_elem_list_compat(ctl->card, argp); |
diff --git a/sound/core/device.c b/sound/core/device.c index 6ce4da4a1081..ccb25816ac9e 100644 --- a/sound/core/device.c +++ b/sound/core/device.c | |||
@@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new); | |||
71 | * @device_data: the data pointer to release | 71 | * @device_data: the data pointer to release |
72 | * | 72 | * |
73 | * Removes the device from the list on the card and invokes the | 73 | * Removes the device from the list on the card and invokes the |
74 | * callback, dev_unregister or dev_free, corresponding to the state. | 74 | * callbacks, dev_disconnect and dev_free, corresponding to the state. |
75 | * Then release the device. | 75 | * Then release the device. |
76 | * | 76 | * |
77 | * Returns zero if successful, or a negative error code on failure or if the | 77 | * Returns zero if successful, or a negative error code on failure or if the |
@@ -90,16 +90,14 @@ int snd_device_free(struct snd_card *card, void *device_data) | |||
90 | continue; | 90 | continue; |
91 | /* unlink */ | 91 | /* unlink */ |
92 | list_del(&dev->list); | 92 | list_del(&dev->list); |
93 | if ((dev->state == SNDRV_DEV_REGISTERED || | 93 | if (dev->state == SNDRV_DEV_REGISTERED && |
94 | dev->state == SNDRV_DEV_DISCONNECTED) && | 94 | dev->ops->dev_disconnect) |
95 | dev->ops->dev_unregister) { | 95 | if (dev->ops->dev_disconnect(dev)) |
96 | if (dev->ops->dev_unregister(dev)) | 96 | snd_printk(KERN_ERR |
97 | snd_printk(KERN_ERR "device unregister failure\n"); | 97 | "device disconnect failure\n"); |
98 | } else { | 98 | if (dev->ops->dev_free) { |
99 | if (dev->ops->dev_free) { | 99 | if (dev->ops->dev_free(dev)) |
100 | if (dev->ops->dev_free(dev)) | 100 | snd_printk(KERN_ERR "device free failure\n"); |
101 | snd_printk(KERN_ERR "device free failure\n"); | ||
102 | } | ||
103 | } | 101 | } |
104 | kfree(dev); | 102 | kfree(dev); |
105 | return 0; | 103 | return 0; |
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 8bd0dcc93eba..9aa9d94891f0 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
@@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex); | |||
42 | static int snd_hwdep_free(struct snd_hwdep *hwdep); | 42 | static int snd_hwdep_free(struct snd_hwdep *hwdep); |
43 | static int snd_hwdep_dev_free(struct snd_device *device); | 43 | static int snd_hwdep_dev_free(struct snd_device *device); |
44 | static int snd_hwdep_dev_register(struct snd_device *device); | 44 | static int snd_hwdep_dev_register(struct snd_device *device); |
45 | static int snd_hwdep_dev_unregister(struct snd_device *device); | 45 | static int snd_hwdep_dev_disconnect(struct snd_device *device); |
46 | 46 | ||
47 | 47 | ||
48 | static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) | 48 | static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) |
@@ -353,7 +353,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device, | |||
353 | static struct snd_device_ops ops = { | 353 | static struct snd_device_ops ops = { |
354 | .dev_free = snd_hwdep_dev_free, | 354 | .dev_free = snd_hwdep_dev_free, |
355 | .dev_register = snd_hwdep_dev_register, | 355 | .dev_register = snd_hwdep_dev_register, |
356 | .dev_unregister = snd_hwdep_dev_unregister | 356 | .dev_disconnect = snd_hwdep_dev_disconnect, |
357 | }; | 357 | }; |
358 | 358 | ||
359 | snd_assert(rhwdep != NULL, return -EINVAL); | 359 | snd_assert(rhwdep != NULL, return -EINVAL); |
@@ -439,7 +439,7 @@ static int snd_hwdep_dev_register(struct snd_device *device) | |||
439 | return 0; | 439 | return 0; |
440 | } | 440 | } |
441 | 441 | ||
442 | static int snd_hwdep_dev_unregister(struct snd_device *device) | 442 | static int snd_hwdep_dev_disconnect(struct snd_device *device) |
443 | { | 443 | { |
444 | struct snd_hwdep *hwdep = device->device_data; | 444 | struct snd_hwdep *hwdep = device->device_data; |
445 | 445 | ||
@@ -454,9 +454,9 @@ static int snd_hwdep_dev_unregister(struct snd_device *device) | |||
454 | snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); | 454 | snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); |
455 | #endif | 455 | #endif |
456 | snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); | 456 | snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); |
457 | list_del(&hwdep->list); | 457 | list_del_init(&hwdep->list); |
458 | mutex_unlock(®ister_mutex); | 458 | mutex_unlock(®ister_mutex); |
459 | return snd_hwdep_free(hwdep); | 459 | return 0; |
460 | } | 460 | } |
461 | 461 | ||
462 | #ifdef CONFIG_PROC_FS | 462 | #ifdef CONFIG_PROC_FS |
@@ -497,7 +497,7 @@ static void __init snd_hwdep_proc_init(void) | |||
497 | 497 | ||
498 | static void __exit snd_hwdep_proc_done(void) | 498 | static void __exit snd_hwdep_proc_done(void) |
499 | { | 499 | { |
500 | snd_info_unregister(snd_hwdep_proc_entry); | 500 | snd_info_free_entry(snd_hwdep_proc_entry); |
501 | } | 501 | } |
502 | #else /* !CONFIG_PROC_FS */ | 502 | #else /* !CONFIG_PROC_FS */ |
503 | #define snd_hwdep_proc_init() | 503 | #define snd_hwdep_proc_init() |
diff --git a/sound/core/info.c b/sound/core/info.c index 340332c6d973..e43662b33f16 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -78,6 +78,7 @@ struct snd_info_private_data { | |||
78 | 78 | ||
79 | static int snd_info_version_init(void); | 79 | static int snd_info_version_init(void); |
80 | static int snd_info_version_done(void); | 80 | static int snd_info_version_done(void); |
81 | static void snd_info_disconnect(struct snd_info_entry *entry); | ||
81 | 82 | ||
82 | 83 | ||
83 | /* resize the proc r/w buffer */ | 84 | /* resize the proc r/w buffer */ |
@@ -174,15 +175,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) | |||
174 | switch (entry->content) { | 175 | switch (entry->content) { |
175 | case SNDRV_INFO_CONTENT_TEXT: | 176 | case SNDRV_INFO_CONTENT_TEXT: |
176 | switch (orig) { | 177 | switch (orig) { |
177 | case 0: /* SEEK_SET */ | 178 | case SEEK_SET: |
178 | file->f_pos = offset; | 179 | file->f_pos = offset; |
179 | ret = file->f_pos; | 180 | ret = file->f_pos; |
180 | goto out; | 181 | goto out; |
181 | case 1: /* SEEK_CUR */ | 182 | case SEEK_CUR: |
182 | file->f_pos += offset; | 183 | file->f_pos += offset; |
183 | ret = file->f_pos; | 184 | ret = file->f_pos; |
184 | goto out; | 185 | goto out; |
185 | case 2: /* SEEK_END */ | 186 | case SEEK_END: |
186 | default: | 187 | default: |
187 | ret = -EINVAL; | 188 | ret = -EINVAL; |
188 | goto out; | 189 | goto out; |
@@ -304,7 +305,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) | |||
304 | mutex_lock(&info_mutex); | 305 | mutex_lock(&info_mutex); |
305 | p = PDE(inode); | 306 | p = PDE(inode); |
306 | entry = p == NULL ? NULL : (struct snd_info_entry *)p->data; | 307 | entry = p == NULL ? NULL : (struct snd_info_entry *)p->data; |
307 | if (entry == NULL || entry->disconnected) { | 308 | if (entry == NULL || ! entry->p) { |
308 | mutex_unlock(&info_mutex); | 309 | mutex_unlock(&info_mutex); |
309 | return -ENODEV; | 310 | return -ENODEV; |
310 | } | 311 | } |
@@ -586,10 +587,10 @@ int __exit snd_info_done(void) | |||
586 | snd_info_version_done(); | 587 | snd_info_version_done(); |
587 | if (snd_proc_root) { | 588 | if (snd_proc_root) { |
588 | #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) | 589 | #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) |
589 | snd_info_unregister(snd_seq_root); | 590 | snd_info_free_entry(snd_seq_root); |
590 | #endif | 591 | #endif |
591 | #ifdef CONFIG_SND_OSSEMUL | 592 | #ifdef CONFIG_SND_OSSEMUL |
592 | snd_info_unregister(snd_oss_root); | 593 | snd_info_free_entry(snd_oss_root); |
593 | #endif | 594 | #endif |
594 | snd_remove_proc_entry(&proc_root, snd_proc_root); | 595 | snd_remove_proc_entry(&proc_root, snd_proc_root); |
595 | } | 596 | } |
@@ -648,17 +649,28 @@ int snd_info_card_register(struct snd_card *card) | |||
648 | * de-register the card proc file | 649 | * de-register the card proc file |
649 | * called from init.c | 650 | * called from init.c |
650 | */ | 651 | */ |
651 | int snd_info_card_free(struct snd_card *card) | 652 | void snd_info_card_disconnect(struct snd_card *card) |
652 | { | 653 | { |
653 | snd_assert(card != NULL, return -ENXIO); | 654 | snd_assert(card != NULL, return); |
655 | mutex_lock(&info_mutex); | ||
654 | if (card->proc_root_link) { | 656 | if (card->proc_root_link) { |
655 | snd_remove_proc_entry(snd_proc_root, card->proc_root_link); | 657 | snd_remove_proc_entry(snd_proc_root, card->proc_root_link); |
656 | card->proc_root_link = NULL; | 658 | card->proc_root_link = NULL; |
657 | } | 659 | } |
658 | if (card->proc_root) { | 660 | if (card->proc_root) |
659 | snd_info_unregister(card->proc_root); | 661 | snd_info_disconnect(card->proc_root); |
660 | card->proc_root = NULL; | 662 | mutex_unlock(&info_mutex); |
661 | } | 663 | } |
664 | |||
665 | /* | ||
666 | * release the card proc file resources | ||
667 | * called from init.c | ||
668 | */ | ||
669 | int snd_info_card_free(struct snd_card *card) | ||
670 | { | ||
671 | snd_assert(card != NULL, return -ENXIO); | ||
672 | snd_info_free_entry(card->proc_root); | ||
673 | card->proc_root = NULL; | ||
662 | return 0; | 674 | return 0; |
663 | } | 675 | } |
664 | 676 | ||
@@ -767,6 +779,8 @@ static struct snd_info_entry *snd_info_create_entry(const char *name) | |||
767 | entry->mode = S_IFREG | S_IRUGO; | 779 | entry->mode = S_IFREG | S_IRUGO; |
768 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 780 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
769 | mutex_init(&entry->access); | 781 | mutex_init(&entry->access); |
782 | INIT_LIST_HEAD(&entry->children); | ||
783 | INIT_LIST_HEAD(&entry->list); | ||
770 | return entry; | 784 | return entry; |
771 | } | 785 | } |
772 | 786 | ||
@@ -819,30 +833,35 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, | |||
819 | 833 | ||
820 | EXPORT_SYMBOL(snd_info_create_card_entry); | 834 | EXPORT_SYMBOL(snd_info_create_card_entry); |
821 | 835 | ||
822 | static int snd_info_dev_free_entry(struct snd_device *device) | 836 | static void snd_info_disconnect(struct snd_info_entry *entry) |
823 | { | 837 | { |
824 | struct snd_info_entry *entry = device->device_data; | 838 | struct list_head *p, *n; |
825 | snd_info_free_entry(entry); | 839 | struct proc_dir_entry *root; |
826 | return 0; | ||
827 | } | ||
828 | 840 | ||
829 | static int snd_info_dev_register_entry(struct snd_device *device) | 841 | list_for_each_safe(p, n, &entry->children) { |
830 | { | 842 | snd_info_disconnect(list_entry(p, struct snd_info_entry, list)); |
831 | struct snd_info_entry *entry = device->device_data; | 843 | } |
832 | return snd_info_register(entry); | 844 | |
845 | if (! entry->p) | ||
846 | return; | ||
847 | list_del_init(&entry->list); | ||
848 | root = entry->parent == NULL ? snd_proc_root : entry->parent->p; | ||
849 | snd_assert(root, return); | ||
850 | snd_remove_proc_entry(root, entry->p); | ||
851 | entry->p = NULL; | ||
833 | } | 852 | } |
834 | 853 | ||
835 | static int snd_info_dev_disconnect_entry(struct snd_device *device) | 854 | static int snd_info_dev_free_entry(struct snd_device *device) |
836 | { | 855 | { |
837 | struct snd_info_entry *entry = device->device_data; | 856 | struct snd_info_entry *entry = device->device_data; |
838 | entry->disconnected = 1; | 857 | snd_info_free_entry(entry); |
839 | return 0; | 858 | return 0; |
840 | } | 859 | } |
841 | 860 | ||
842 | static int snd_info_dev_unregister_entry(struct snd_device *device) | 861 | static int snd_info_dev_register_entry(struct snd_device *device) |
843 | { | 862 | { |
844 | struct snd_info_entry *entry = device->device_data; | 863 | struct snd_info_entry *entry = device->device_data; |
845 | return snd_info_unregister(entry); | 864 | return snd_info_register(entry); |
846 | } | 865 | } |
847 | 866 | ||
848 | /** | 867 | /** |
@@ -871,8 +890,7 @@ int snd_card_proc_new(struct snd_card *card, const char *name, | |||
871 | static struct snd_device_ops ops = { | 890 | static struct snd_device_ops ops = { |
872 | .dev_free = snd_info_dev_free_entry, | 891 | .dev_free = snd_info_dev_free_entry, |
873 | .dev_register = snd_info_dev_register_entry, | 892 | .dev_register = snd_info_dev_register_entry, |
874 | .dev_disconnect = snd_info_dev_disconnect_entry, | 893 | /* disconnect is done via snd_info_card_disconnect() */ |
875 | .dev_unregister = snd_info_dev_unregister_entry | ||
876 | }; | 894 | }; |
877 | struct snd_info_entry *entry; | 895 | struct snd_info_entry *entry; |
878 | int err; | 896 | int err; |
@@ -901,6 +919,11 @@ void snd_info_free_entry(struct snd_info_entry * entry) | |||
901 | { | 919 | { |
902 | if (entry == NULL) | 920 | if (entry == NULL) |
903 | return; | 921 | return; |
922 | if (entry->p) { | ||
923 | mutex_lock(&info_mutex); | ||
924 | snd_info_disconnect(entry); | ||
925 | mutex_unlock(&info_mutex); | ||
926 | } | ||
904 | kfree(entry->name); | 927 | kfree(entry->name); |
905 | if (entry->private_free) | 928 | if (entry->private_free) |
906 | entry->private_free(entry); | 929 | entry->private_free(entry); |
@@ -935,38 +958,14 @@ int snd_info_register(struct snd_info_entry * entry) | |||
935 | p->size = entry->size; | 958 | p->size = entry->size; |
936 | p->data = entry; | 959 | p->data = entry; |
937 | entry->p = p; | 960 | entry->p = p; |
961 | if (entry->parent) | ||
962 | list_add_tail(&entry->list, &entry->parent->children); | ||
938 | mutex_unlock(&info_mutex); | 963 | mutex_unlock(&info_mutex); |
939 | return 0; | 964 | return 0; |
940 | } | 965 | } |
941 | 966 | ||
942 | EXPORT_SYMBOL(snd_info_register); | 967 | EXPORT_SYMBOL(snd_info_register); |
943 | 968 | ||
944 | /** | ||
945 | * snd_info_unregister - de-register the info entry | ||
946 | * @entry: the info entry | ||
947 | * | ||
948 | * De-registers the info entry and releases the instance. | ||
949 | * | ||
950 | * Returns zero if successful, or a negative error code on failure. | ||
951 | */ | ||
952 | int snd_info_unregister(struct snd_info_entry * entry) | ||
953 | { | ||
954 | struct proc_dir_entry *root; | ||
955 | |||
956 | if (! entry) | ||
957 | return 0; | ||
958 | snd_assert(entry->p != NULL, return -ENXIO); | ||
959 | root = entry->parent == NULL ? snd_proc_root : entry->parent->p; | ||
960 | snd_assert(root, return -ENXIO); | ||
961 | mutex_lock(&info_mutex); | ||
962 | snd_remove_proc_entry(root, entry->p); | ||
963 | mutex_unlock(&info_mutex); | ||
964 | snd_info_free_entry(entry); | ||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | EXPORT_SYMBOL(snd_info_unregister); | ||
969 | |||
970 | /* | 969 | /* |
971 | 970 | ||
972 | */ | 971 | */ |
@@ -999,8 +998,7 @@ static int __init snd_info_version_init(void) | |||
999 | 998 | ||
1000 | static int __exit snd_info_version_done(void) | 999 | static int __exit snd_info_version_done(void) |
1001 | { | 1000 | { |
1002 | if (snd_info_version_entry) | 1001 | snd_info_free_entry(snd_info_version_entry); |
1003 | snd_info_unregister(snd_info_version_entry); | ||
1004 | return 0; | 1002 | return 0; |
1005 | } | 1003 | } |
1006 | 1004 | ||
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index bb2c40d0ab66..3ebc34919c76 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c | |||
@@ -131,10 +131,8 @@ int snd_info_minor_register(void) | |||
131 | 131 | ||
132 | int snd_info_minor_unregister(void) | 132 | int snd_info_minor_unregister(void) |
133 | { | 133 | { |
134 | if (snd_sndstat_proc_entry) { | 134 | snd_info_free_entry(snd_sndstat_proc_entry); |
135 | snd_info_unregister(snd_sndstat_proc_entry); | 135 | snd_sndstat_proc_entry = NULL; |
136 | snd_sndstat_proc_entry = NULL; | ||
137 | } | ||
138 | return 0; | 136 | return 0; |
139 | } | 137 | } |
140 | 138 | ||
diff --git a/sound/core/init.c b/sound/core/init.c index 4d9258884e44..d7607a25acdf 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -81,8 +81,6 @@ static inline int init_info_for_card(struct snd_card *card) | |||
81 | #define init_info_for_card(card) | 81 | #define init_info_for_card(card) |
82 | #endif | 82 | #endif |
83 | 83 | ||
84 | static void snd_card_free_thread(void * __card); | ||
85 | |||
86 | /** | 84 | /** |
87 | * snd_card_new - create and initialize a soundcard structure | 85 | * snd_card_new - create and initialize a soundcard structure |
88 | * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] | 86 | * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] |
@@ -145,7 +143,6 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
145 | INIT_LIST_HEAD(&card->ctl_files); | 143 | INIT_LIST_HEAD(&card->ctl_files); |
146 | spin_lock_init(&card->files_lock); | 144 | spin_lock_init(&card->files_lock); |
147 | init_waitqueue_head(&card->shutdown_sleep); | 145 | init_waitqueue_head(&card->shutdown_sleep); |
148 | INIT_WORK(&card->free_workq, snd_card_free_thread, card); | ||
149 | #ifdef CONFIG_PM | 146 | #ifdef CONFIG_PM |
150 | mutex_init(&card->power_lock); | 147 | mutex_init(&card->power_lock); |
151 | init_waitqueue_head(&card->power_sleep); | 148 | init_waitqueue_head(&card->power_sleep); |
@@ -310,6 +307,7 @@ int snd_card_disconnect(struct snd_card *card) | |||
310 | if (err < 0) | 307 | if (err < 0) |
311 | snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number); | 308 | snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number); |
312 | 309 | ||
310 | snd_info_card_disconnect(card); | ||
313 | return 0; | 311 | return 0; |
314 | } | 312 | } |
315 | 313 | ||
@@ -326,22 +324,10 @@ EXPORT_SYMBOL(snd_card_disconnect); | |||
326 | * Returns zero. Frees all associated devices and frees the control | 324 | * Returns zero. Frees all associated devices and frees the control |
327 | * interface associated to given soundcard. | 325 | * interface associated to given soundcard. |
328 | */ | 326 | */ |
329 | int snd_card_free(struct snd_card *card) | 327 | static int snd_card_do_free(struct snd_card *card) |
330 | { | 328 | { |
331 | struct snd_shutdown_f_ops *s_f_ops; | 329 | struct snd_shutdown_f_ops *s_f_ops; |
332 | 330 | ||
333 | if (card == NULL) | ||
334 | return -EINVAL; | ||
335 | mutex_lock(&snd_card_mutex); | ||
336 | snd_cards[card->number] = NULL; | ||
337 | mutex_unlock(&snd_card_mutex); | ||
338 | |||
339 | #ifdef CONFIG_PM | ||
340 | wake_up(&card->power_sleep); | ||
341 | #endif | ||
342 | /* wait, until all devices are ready for the free operation */ | ||
343 | wait_event(card->shutdown_sleep, card->files == NULL); | ||
344 | |||
345 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 331 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
346 | if (snd_mixer_oss_notify_callback) | 332 | if (snd_mixer_oss_notify_callback) |
347 | snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); | 333 | snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); |
@@ -360,7 +346,7 @@ int snd_card_free(struct snd_card *card) | |||
360 | } | 346 | } |
361 | if (card->private_free) | 347 | if (card->private_free) |
362 | card->private_free(card); | 348 | card->private_free(card); |
363 | snd_info_unregister(card->proc_id); | 349 | snd_info_free_entry(card->proc_id); |
364 | if (snd_info_card_free(card) < 0) { | 350 | if (snd_info_card_free(card) < 0) { |
365 | snd_printk(KERN_WARNING "unable to free card info\n"); | 351 | snd_printk(KERN_WARNING "unable to free card info\n"); |
366 | /* Not fatal error */ | 352 | /* Not fatal error */ |
@@ -370,61 +356,59 @@ int snd_card_free(struct snd_card *card) | |||
370 | card->s_f_ops = s_f_ops->next; | 356 | card->s_f_ops = s_f_ops->next; |
371 | kfree(s_f_ops); | 357 | kfree(s_f_ops); |
372 | } | 358 | } |
359 | kfree(card); | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int snd_card_free_prepare(struct snd_card *card) | ||
364 | { | ||
365 | if (card == NULL) | ||
366 | return -EINVAL; | ||
367 | (void) snd_card_disconnect(card); | ||
373 | mutex_lock(&snd_card_mutex); | 368 | mutex_lock(&snd_card_mutex); |
369 | snd_cards[card->number] = NULL; | ||
374 | snd_cards_lock &= ~(1 << card->number); | 370 | snd_cards_lock &= ~(1 << card->number); |
375 | mutex_unlock(&snd_card_mutex); | 371 | mutex_unlock(&snd_card_mutex); |
376 | kfree(card); | 372 | #ifdef CONFIG_PM |
373 | wake_up(&card->power_sleep); | ||
374 | #endif | ||
377 | return 0; | 375 | return 0; |
378 | } | 376 | } |
379 | 377 | ||
380 | EXPORT_SYMBOL(snd_card_free); | 378 | int snd_card_free_when_closed(struct snd_card *card) |
381 | |||
382 | static void snd_card_free_thread(void * __card) | ||
383 | { | 379 | { |
384 | struct snd_card *card = __card; | 380 | int free_now = 0; |
385 | struct module * module = card->module; | 381 | int ret = snd_card_free_prepare(card); |
386 | 382 | if (ret) | |
387 | if (!try_module_get(module)) { | 383 | return ret; |
388 | snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number); | ||
389 | module = NULL; | ||
390 | } | ||
391 | 384 | ||
392 | snd_card_free(card); | 385 | spin_lock(&card->files_lock); |
386 | if (card->files == NULL) | ||
387 | free_now = 1; | ||
388 | else | ||
389 | card->free_on_last_close = 1; | ||
390 | spin_unlock(&card->files_lock); | ||
393 | 391 | ||
394 | module_put(module); | 392 | if (free_now) |
393 | snd_card_do_free(card); | ||
394 | return 0; | ||
395 | } | 395 | } |
396 | 396 | ||
397 | /** | 397 | EXPORT_SYMBOL(snd_card_free_when_closed); |
398 | * snd_card_free_in_thread - call snd_card_free() in thread | ||
399 | * @card: soundcard structure | ||
400 | * | ||
401 | * This function schedules the call of snd_card_free() function in a | ||
402 | * work queue. When all devices are released (non-busy), the work | ||
403 | * is woken up and calls snd_card_free(). | ||
404 | * | ||
405 | * When a card can be disconnected at any time by hotplug service, | ||
406 | * this function should be used in disconnect (or detach) callback | ||
407 | * instead of calling snd_card_free() directly. | ||
408 | * | ||
409 | * Returns - zero otherwise a negative error code if the start of thread failed. | ||
410 | */ | ||
411 | int snd_card_free_in_thread(struct snd_card *card) | ||
412 | { | ||
413 | if (card->files == NULL) { | ||
414 | snd_card_free(card); | ||
415 | return 0; | ||
416 | } | ||
417 | 398 | ||
418 | if (schedule_work(&card->free_workq)) | 399 | int snd_card_free(struct snd_card *card) |
419 | return 0; | 400 | { |
401 | int ret = snd_card_free_prepare(card); | ||
402 | if (ret) | ||
403 | return ret; | ||
420 | 404 | ||
421 | snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number); | 405 | /* wait, until all devices are ready for the free operation */ |
422 | /* try to free the structure immediately */ | 406 | wait_event(card->shutdown_sleep, card->files == NULL); |
423 | snd_card_free(card); | 407 | snd_card_do_free(card); |
424 | return -EFAULT; | 408 | return 0; |
425 | } | 409 | } |
426 | 410 | ||
427 | EXPORT_SYMBOL(snd_card_free_in_thread); | 411 | EXPORT_SYMBOL(snd_card_free); |
428 | 412 | ||
429 | static void choose_default_id(struct snd_card *card) | 413 | static void choose_default_id(struct snd_card *card) |
430 | { | 414 | { |
@@ -625,9 +609,9 @@ int __init snd_card_info_init(void) | |||
625 | 609 | ||
626 | int __exit snd_card_info_done(void) | 610 | int __exit snd_card_info_done(void) |
627 | { | 611 | { |
628 | snd_info_unregister(snd_card_info_entry); | 612 | snd_info_free_entry(snd_card_info_entry); |
629 | #ifdef MODULE | 613 | #ifdef MODULE |
630 | snd_info_unregister(snd_card_module_info_entry); | 614 | snd_info_free_entry(snd_card_module_info_entry); |
631 | #endif | 615 | #endif |
632 | return 0; | 616 | return 0; |
633 | } | 617 | } |
@@ -708,15 +692,16 @@ EXPORT_SYMBOL(snd_card_file_add); | |||
708 | * | 692 | * |
709 | * This function removes the file formerly added to the card via | 693 | * This function removes the file formerly added to the card via |
710 | * snd_card_file_add() function. | 694 | * snd_card_file_add() function. |
711 | * If all files are removed and the release of the card is | 695 | * If all files are removed and snd_card_free_when_closed() was |
712 | * scheduled, it will wake up the the thread to call snd_card_free() | 696 | * called beforehand, it processes the pending release of |
713 | * (see snd_card_free_in_thread() function). | 697 | * resources. |
714 | * | 698 | * |
715 | * Returns zero or a negative error code. | 699 | * Returns zero or a negative error code. |
716 | */ | 700 | */ |
717 | int snd_card_file_remove(struct snd_card *card, struct file *file) | 701 | int snd_card_file_remove(struct snd_card *card, struct file *file) |
718 | { | 702 | { |
719 | struct snd_monitor_file *mfile, *pfile = NULL; | 703 | struct snd_monitor_file *mfile, *pfile = NULL; |
704 | int last_close = 0; | ||
720 | 705 | ||
721 | spin_lock(&card->files_lock); | 706 | spin_lock(&card->files_lock); |
722 | mfile = card->files; | 707 | mfile = card->files; |
@@ -731,9 +716,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) | |||
731 | pfile = mfile; | 716 | pfile = mfile; |
732 | mfile = mfile->next; | 717 | mfile = mfile->next; |
733 | } | 718 | } |
734 | spin_unlock(&card->files_lock); | ||
735 | if (card->files == NULL) | 719 | if (card->files == NULL) |
720 | last_close = 1; | ||
721 | spin_unlock(&card->files_lock); | ||
722 | if (last_close) { | ||
736 | wake_up(&card->shutdown_sleep); | 723 | wake_up(&card->shutdown_sleep); |
724 | if (card->free_on_last_close) | ||
725 | snd_card_do_free(card); | ||
726 | } | ||
737 | if (!mfile) { | 727 | if (!mfile) { |
738 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); | 728 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); |
739 | return -ENOENT; | 729 | return -ENOENT; |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 75a9505c7445..f4c67042e3ac 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
@@ -1193,10 +1193,8 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer) | |||
1193 | 1193 | ||
1194 | static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer) | 1194 | static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer) |
1195 | { | 1195 | { |
1196 | if (mixer->proc_entry) { | 1196 | snd_info_free_entry(mixer->proc_entry); |
1197 | snd_info_unregister(mixer->proc_entry); | 1197 | mixer->proc_entry = NULL; |
1198 | mixer->proc_entry = NULL; | ||
1199 | } | ||
1200 | } | 1198 | } |
1201 | #else /* !CONFIG_PROC_FS */ | 1199 | #else /* !CONFIG_PROC_FS */ |
1202 | #define snd_mixer_oss_proc_init(mix) | 1200 | #define snd_mixer_oss_proc_init(mix) |
@@ -1312,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd) | |||
1312 | card->mixer_oss = mixer; | 1310 | card->mixer_oss = mixer; |
1313 | snd_mixer_oss_build(mixer); | 1311 | snd_mixer_oss_build(mixer); |
1314 | snd_mixer_oss_proc_init(mixer); | 1312 | snd_mixer_oss_proc_init(mixer); |
1315 | } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) { | 1313 | } else { |
1316 | mixer = card->mixer_oss; | ||
1317 | if (mixer == NULL || !mixer->oss_dev_alloc) | ||
1318 | return 0; | ||
1319 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); | ||
1320 | mixer->oss_dev_alloc = 0; | ||
1321 | } else { /* free */ | ||
1322 | mixer = card->mixer_oss; | 1314 | mixer = card->mixer_oss; |
1323 | if (mixer == NULL) | 1315 | if (mixer == NULL) |
1324 | return 0; | 1316 | return 0; |
1317 | if (mixer->oss_dev_alloc) { | ||
1325 | #ifdef SNDRV_OSS_INFO_DEV_MIXERS | 1318 | #ifdef SNDRV_OSS_INFO_DEV_MIXERS |
1326 | snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); | 1319 | snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); |
1327 | #endif | 1320 | #endif |
1328 | if (mixer->oss_dev_alloc) | ||
1329 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); | 1321 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); |
1322 | mixer->oss_dev_alloc = 0; | ||
1323 | } | ||
1324 | if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) | ||
1325 | return 0; | ||
1330 | snd_mixer_oss_proc_done(mixer); | 1326 | snd_mixer_oss_proc_done(mixer); |
1331 | return snd_mixer_oss_free1(mixer); | 1327 | return snd_mixer_oss_free1(mixer); |
1332 | } | 1328 | } |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 472fce0ee0e8..505b23ec4058 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -2846,11 +2846,9 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm) | |||
2846 | int stream; | 2846 | int stream; |
2847 | for (stream = 0; stream < 2; ++stream) { | 2847 | for (stream = 0; stream < 2; ++stream) { |
2848 | struct snd_pcm_str *pstr = &pcm->streams[stream]; | 2848 | struct snd_pcm_str *pstr = &pcm->streams[stream]; |
2849 | if (pstr->oss.proc_entry) { | 2849 | snd_info_free_entry(pstr->oss.proc_entry); |
2850 | snd_info_unregister(pstr->oss.proc_entry); | 2850 | pstr->oss.proc_entry = NULL; |
2851 | pstr->oss.proc_entry = NULL; | 2851 | snd_pcm_oss_proc_free_setup_list(pstr); |
2852 | snd_pcm_oss_proc_free_setup_list(pstr); | ||
2853 | } | ||
2854 | } | 2852 | } |
2855 | } | 2853 | } |
2856 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ | 2854 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ |
@@ -2931,25 +2929,23 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm) | |||
2931 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, | 2929 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, |
2932 | pcm->card, 1); | 2930 | pcm->card, 1); |
2933 | } | 2931 | } |
2934 | } | ||
2935 | return 0; | ||
2936 | } | ||
2937 | |||
2938 | static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm) | ||
2939 | { | ||
2940 | snd_pcm_oss_disconnect_minor(pcm); | ||
2941 | if (pcm->oss.reg) { | ||
2942 | if (dsp_map[pcm->card->number] == (int)pcm->device) { | 2932 | if (dsp_map[pcm->card->number] == (int)pcm->device) { |
2943 | #ifdef SNDRV_OSS_INFO_DEV_AUDIO | 2933 | #ifdef SNDRV_OSS_INFO_DEV_AUDIO |
2944 | snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); | 2934 | snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); |
2945 | #endif | 2935 | #endif |
2946 | } | 2936 | } |
2947 | pcm->oss.reg = 0; | 2937 | pcm->oss.reg = 0; |
2948 | snd_pcm_oss_proc_done(pcm); | ||
2949 | } | 2938 | } |
2950 | return 0; | 2939 | return 0; |
2951 | } | 2940 | } |
2952 | 2941 | ||
2942 | static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm) | ||
2943 | { | ||
2944 | snd_pcm_oss_disconnect_minor(pcm); | ||
2945 | snd_pcm_oss_proc_done(pcm); | ||
2946 | return 0; | ||
2947 | } | ||
2948 | |||
2953 | static struct snd_pcm_notify snd_pcm_oss_notify = | 2949 | static struct snd_pcm_notify snd_pcm_oss_notify = |
2954 | { | 2950 | { |
2955 | .n_register = snd_pcm_oss_register_minor, | 2951 | .n_register = snd_pcm_oss_register_minor, |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 7581edd7b9ff..bf8f412988b8 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm); | |||
42 | static int snd_pcm_dev_free(struct snd_device *device); | 42 | static int snd_pcm_dev_free(struct snd_device *device); |
43 | static int snd_pcm_dev_register(struct snd_device *device); | 43 | static int snd_pcm_dev_register(struct snd_device *device); |
44 | static int snd_pcm_dev_disconnect(struct snd_device *device); | 44 | static int snd_pcm_dev_disconnect(struct snd_device *device); |
45 | static int snd_pcm_dev_unregister(struct snd_device *device); | ||
46 | 45 | ||
47 | static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) | 46 | static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) |
48 | { | 47 | { |
@@ -494,19 +493,13 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) | |||
494 | static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) | 493 | static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) |
495 | { | 494 | { |
496 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 495 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
497 | if (pstr->proc_xrun_debug_entry) { | 496 | snd_info_free_entry(pstr->proc_xrun_debug_entry); |
498 | snd_info_unregister(pstr->proc_xrun_debug_entry); | 497 | pstr->proc_xrun_debug_entry = NULL; |
499 | pstr->proc_xrun_debug_entry = NULL; | ||
500 | } | ||
501 | #endif | 498 | #endif |
502 | if (pstr->proc_info_entry) { | 499 | snd_info_free_entry(pstr->proc_info_entry); |
503 | snd_info_unregister(pstr->proc_info_entry); | 500 | pstr->proc_info_entry = NULL; |
504 | pstr->proc_info_entry = NULL; | 501 | snd_info_free_entry(pstr->proc_root); |
505 | } | 502 | pstr->proc_root = NULL; |
506 | if (pstr->proc_root) { | ||
507 | snd_info_unregister(pstr->proc_root); | ||
508 | pstr->proc_root = NULL; | ||
509 | } | ||
510 | return 0; | 503 | return 0; |
511 | } | 504 | } |
512 | 505 | ||
@@ -570,29 +563,19 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
570 | 563 | ||
571 | return 0; | 564 | return 0; |
572 | } | 565 | } |
573 | 566 | ||
574 | static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) | 567 | static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) |
575 | { | 568 | { |
576 | if (substream->proc_info_entry) { | 569 | snd_info_free_entry(substream->proc_info_entry); |
577 | snd_info_unregister(substream->proc_info_entry); | 570 | substream->proc_info_entry = NULL; |
578 | substream->proc_info_entry = NULL; | 571 | snd_info_free_entry(substream->proc_hw_params_entry); |
579 | } | 572 | substream->proc_hw_params_entry = NULL; |
580 | if (substream->proc_hw_params_entry) { | 573 | snd_info_free_entry(substream->proc_sw_params_entry); |
581 | snd_info_unregister(substream->proc_hw_params_entry); | 574 | substream->proc_sw_params_entry = NULL; |
582 | substream->proc_hw_params_entry = NULL; | 575 | snd_info_free_entry(substream->proc_status_entry); |
583 | } | 576 | substream->proc_status_entry = NULL; |
584 | if (substream->proc_sw_params_entry) { | 577 | snd_info_free_entry(substream->proc_root); |
585 | snd_info_unregister(substream->proc_sw_params_entry); | 578 | substream->proc_root = NULL; |
586 | substream->proc_sw_params_entry = NULL; | ||
587 | } | ||
588 | if (substream->proc_status_entry) { | ||
589 | snd_info_unregister(substream->proc_status_entry); | ||
590 | substream->proc_status_entry = NULL; | ||
591 | } | ||
592 | if (substream->proc_root) { | ||
593 | snd_info_unregister(substream->proc_root); | ||
594 | substream->proc_root = NULL; | ||
595 | } | ||
596 | return 0; | 579 | return 0; |
597 | } | 580 | } |
598 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ | 581 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ |
@@ -696,7 +679,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device, | |||
696 | .dev_free = snd_pcm_dev_free, | 679 | .dev_free = snd_pcm_dev_free, |
697 | .dev_register = snd_pcm_dev_register, | 680 | .dev_register = snd_pcm_dev_register, |
698 | .dev_disconnect = snd_pcm_dev_disconnect, | 681 | .dev_disconnect = snd_pcm_dev_disconnect, |
699 | .dev_unregister = snd_pcm_dev_unregister | ||
700 | }; | 682 | }; |
701 | 683 | ||
702 | snd_assert(rpcm != NULL, return -EINVAL); | 684 | snd_assert(rpcm != NULL, return -EINVAL); |
@@ -740,6 +722,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | |||
740 | substream = pstr->substream; | 722 | substream = pstr->substream; |
741 | while (substream) { | 723 | while (substream) { |
742 | substream_next = substream->next; | 724 | substream_next = substream->next; |
725 | snd_pcm_timer_done(substream); | ||
743 | snd_pcm_substream_proc_done(substream); | 726 | snd_pcm_substream_proc_done(substream); |
744 | kfree(substream); | 727 | kfree(substream); |
745 | substream = substream_next; | 728 | substream = substream_next; |
@@ -756,7 +739,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | |||
756 | 739 | ||
757 | static int snd_pcm_free(struct snd_pcm *pcm) | 740 | static int snd_pcm_free(struct snd_pcm *pcm) |
758 | { | 741 | { |
742 | struct snd_pcm_notify *notify; | ||
743 | |||
759 | snd_assert(pcm != NULL, return -ENXIO); | 744 | snd_assert(pcm != NULL, return -ENXIO); |
745 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { | ||
746 | notify->n_unregister(pcm); | ||
747 | } | ||
760 | if (pcm->private_free) | 748 | if (pcm->private_free) |
761 | pcm->private_free(pcm); | 749 | pcm->private_free(pcm); |
762 | snd_pcm_lib_preallocate_free_for_all(pcm); | 750 | snd_pcm_lib_preallocate_free_for_all(pcm); |
@@ -804,7 +792,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
804 | kctl = snd_ctl_file(list); | 792 | kctl = snd_ctl_file(list); |
805 | if (kctl->pid == current->pid) { | 793 | if (kctl->pid == current->pid) { |
806 | prefer_subdevice = kctl->prefer_pcm_subdevice; | 794 | prefer_subdevice = kctl->prefer_pcm_subdevice; |
807 | break; | 795 | if (prefer_subdevice != -1) |
796 | break; | ||
808 | } | 797 | } |
809 | } | 798 | } |
810 | up_read(&card->controls_rwsem); | 799 | up_read(&card->controls_rwsem); |
@@ -918,6 +907,28 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) | |||
918 | substream->pstr->substream_opened--; | 907 | substream->pstr->substream_opened--; |
919 | } | 908 | } |
920 | 909 | ||
910 | static ssize_t show_pcm_class(struct class_device *class_device, char *buf) | ||
911 | { | ||
912 | struct snd_pcm *pcm; | ||
913 | const char *str; | ||
914 | static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = { | ||
915 | [SNDRV_PCM_CLASS_GENERIC] = "generic", | ||
916 | [SNDRV_PCM_CLASS_MULTI] = "multi", | ||
917 | [SNDRV_PCM_CLASS_MODEM] = "modem", | ||
918 | [SNDRV_PCM_CLASS_DIGITIZER] = "digitizer", | ||
919 | }; | ||
920 | |||
921 | if (! (pcm = class_get_devdata(class_device)) || | ||
922 | pcm->dev_class > SNDRV_PCM_CLASS_LAST) | ||
923 | str = "none"; | ||
924 | else | ||
925 | str = strs[pcm->dev_class]; | ||
926 | return snprintf(buf, PAGE_SIZE, "%s\n", str); | ||
927 | } | ||
928 | |||
929 | static struct class_device_attribute pcm_attrs = | ||
930 | __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL); | ||
931 | |||
921 | static int snd_pcm_dev_register(struct snd_device *device) | 932 | static int snd_pcm_dev_register(struct snd_device *device) |
922 | { | 933 | { |
923 | int cidx, err; | 934 | int cidx, err; |
@@ -956,6 +967,8 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
956 | mutex_unlock(®ister_mutex); | 967 | mutex_unlock(®ister_mutex); |
957 | return err; | 968 | return err; |
958 | } | 969 | } |
970 | snd_add_device_sysfs_file(devtype, pcm->card, pcm->device, | ||
971 | &pcm_attrs); | ||
959 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 972 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
960 | snd_pcm_timer_init(substream); | 973 | snd_pcm_timer_init(substream); |
961 | } | 974 | } |
@@ -971,35 +984,22 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
971 | static int snd_pcm_dev_disconnect(struct snd_device *device) | 984 | static int snd_pcm_dev_disconnect(struct snd_device *device) |
972 | { | 985 | { |
973 | struct snd_pcm *pcm = device->device_data; | 986 | struct snd_pcm *pcm = device->device_data; |
974 | struct list_head *list; | 987 | struct snd_pcm_notify *notify; |
975 | struct snd_pcm_substream *substream; | 988 | struct snd_pcm_substream *substream; |
976 | int cidx; | 989 | int cidx, devtype; |
977 | 990 | ||
978 | mutex_lock(®ister_mutex); | 991 | mutex_lock(®ister_mutex); |
992 | if (list_empty(&pcm->list)) | ||
993 | goto unlock; | ||
994 | |||
979 | list_del_init(&pcm->list); | 995 | list_del_init(&pcm->list); |
980 | for (cidx = 0; cidx < 2; cidx++) | 996 | for (cidx = 0; cidx < 2; cidx++) |
981 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 997 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
982 | if (substream->runtime) | 998 | if (substream->runtime) |
983 | substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; | 999 | substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; |
984 | list_for_each(list, &snd_pcm_notify_list) { | 1000 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { |
985 | struct snd_pcm_notify *notify; | ||
986 | notify = list_entry(list, struct snd_pcm_notify, list); | ||
987 | notify->n_disconnect(pcm); | 1001 | notify->n_disconnect(pcm); |
988 | } | 1002 | } |
989 | mutex_unlock(®ister_mutex); | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static int snd_pcm_dev_unregister(struct snd_device *device) | ||
994 | { | ||
995 | int cidx, devtype; | ||
996 | struct snd_pcm_substream *substream; | ||
997 | struct list_head *list; | ||
998 | struct snd_pcm *pcm = device->device_data; | ||
999 | |||
1000 | snd_assert(pcm != NULL, return -ENXIO); | ||
1001 | mutex_lock(®ister_mutex); | ||
1002 | list_del(&pcm->list); | ||
1003 | for (cidx = 0; cidx < 2; cidx++) { | 1003 | for (cidx = 0; cidx < 2; cidx++) { |
1004 | devtype = -1; | 1004 | devtype = -1; |
1005 | switch (cidx) { | 1005 | switch (cidx) { |
@@ -1011,23 +1011,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device) | |||
1011 | break; | 1011 | break; |
1012 | } | 1012 | } |
1013 | snd_unregister_device(devtype, pcm->card, pcm->device); | 1013 | snd_unregister_device(devtype, pcm->card, pcm->device); |
1014 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | ||
1015 | snd_pcm_timer_done(substream); | ||
1016 | } | ||
1017 | list_for_each(list, &snd_pcm_notify_list) { | ||
1018 | struct snd_pcm_notify *notify; | ||
1019 | notify = list_entry(list, struct snd_pcm_notify, list); | ||
1020 | notify->n_unregister(pcm); | ||
1021 | } | 1014 | } |
1015 | unlock: | ||
1022 | mutex_unlock(®ister_mutex); | 1016 | mutex_unlock(®ister_mutex); |
1023 | return snd_pcm_free(pcm); | 1017 | return 0; |
1024 | } | 1018 | } |
1025 | 1019 | ||
1026 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) | 1020 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) |
1027 | { | 1021 | { |
1028 | struct list_head *p; | 1022 | struct list_head *p; |
1029 | 1023 | ||
1030 | snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL); | 1024 | snd_assert(notify != NULL && |
1025 | notify->n_register != NULL && | ||
1026 | notify->n_unregister != NULL && | ||
1027 | notify->n_disconnect, return -EINVAL); | ||
1031 | mutex_lock(®ister_mutex); | 1028 | mutex_lock(®ister_mutex); |
1032 | if (nfree) { | 1029 | if (nfree) { |
1033 | list_del(¬ify->list); | 1030 | list_del(¬ify->list); |
@@ -1090,8 +1087,7 @@ static void snd_pcm_proc_init(void) | |||
1090 | 1087 | ||
1091 | static void snd_pcm_proc_done(void) | 1088 | static void snd_pcm_proc_done(void) |
1092 | { | 1089 | { |
1093 | if (snd_pcm_proc_entry) | 1090 | snd_info_free_entry(snd_pcm_proc_entry); |
1094 | snd_info_unregister(snd_pcm_proc_entry); | ||
1095 | } | 1091 | } |
1096 | 1092 | ||
1097 | #else /* !CONFIG_PROC_FS */ | 1093 | #else /* !CONFIG_PROC_FS */ |
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 2b8aab6fd6cd..2b539799d23b 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
@@ -478,7 +478,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l | |||
478 | * mmap of PCM status/control records because of the size | 478 | * mmap of PCM status/control records because of the size |
479 | * incompatibility. | 479 | * incompatibility. |
480 | */ | 480 | */ |
481 | substream->no_mmap_ctrl = 1; | 481 | pcm_file->no_compat_mmap = 1; |
482 | 482 | ||
483 | switch (cmd) { | 483 | switch (cmd) { |
484 | case SNDRV_PCM_IOCTL_PVERSION: | 484 | case SNDRV_PCM_IOCTL_PVERSION: |
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 067d2056db9a..be030cb4d373 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
@@ -101,7 +101,7 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) | |||
101 | { | 101 | { |
102 | snd_pcm_lib_preallocate_dma_free(substream); | 102 | snd_pcm_lib_preallocate_dma_free(substream); |
103 | #ifdef CONFIG_SND_VERBOSE_PROCFS | 103 | #ifdef CONFIG_SND_VERBOSE_PROCFS |
104 | snd_info_unregister(substream->proc_prealloc_entry); | 104 | snd_info_free_entry(substream->proc_prealloc_entry); |
105 | substream->proc_prealloc_entry = NULL; | 105 | substream->proc_prealloc_entry = NULL; |
106 | #endif | 106 | #endif |
107 | return 0; | 107 | return 0; |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 439f047929e1..0224c70414f5 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -1992,35 +1992,9 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) | |||
1992 | return 0; | 1992 | return 0; |
1993 | } | 1993 | } |
1994 | 1994 | ||
1995 | static void snd_pcm_add_file(struct snd_pcm_str *str, | ||
1996 | struct snd_pcm_file *pcm_file) | ||
1997 | { | ||
1998 | pcm_file->next = str->files; | ||
1999 | str->files = pcm_file; | ||
2000 | } | ||
2001 | |||
2002 | static void snd_pcm_remove_file(struct snd_pcm_str *str, | ||
2003 | struct snd_pcm_file *pcm_file) | ||
2004 | { | ||
2005 | struct snd_pcm_file * pcm_file1; | ||
2006 | if (str->files == pcm_file) { | ||
2007 | str->files = pcm_file->next; | ||
2008 | } else { | ||
2009 | pcm_file1 = str->files; | ||
2010 | while (pcm_file1 && pcm_file1->next != pcm_file) | ||
2011 | pcm_file1 = pcm_file1->next; | ||
2012 | if (pcm_file1 != NULL) | ||
2013 | pcm_file1->next = pcm_file->next; | ||
2014 | } | ||
2015 | } | ||
2016 | |||
2017 | static void pcm_release_private(struct snd_pcm_substream *substream) | 1995 | static void pcm_release_private(struct snd_pcm_substream *substream) |
2018 | { | 1996 | { |
2019 | struct snd_pcm_file *pcm_file = substream->file; | ||
2020 | |||
2021 | snd_pcm_unlink(substream); | 1997 | snd_pcm_unlink(substream); |
2022 | snd_pcm_remove_file(substream->pstr, pcm_file); | ||
2023 | kfree(pcm_file); | ||
2024 | } | 1998 | } |
2025 | 1999 | ||
2026 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) | 2000 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) |
@@ -2060,7 +2034,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | |||
2060 | return 0; | 2034 | return 0; |
2061 | } | 2035 | } |
2062 | 2036 | ||
2063 | substream->no_mmap_ctrl = 0; | ||
2064 | err = snd_pcm_hw_constraints_init(substream); | 2037 | err = snd_pcm_hw_constraints_init(substream); |
2065 | if (err < 0) { | 2038 | if (err < 0) { |
2066 | snd_printd("snd_pcm_hw_constraints_init failed\n"); | 2039 | snd_printd("snd_pcm_hw_constraints_init failed\n"); |
@@ -2105,19 +2078,16 @@ static int snd_pcm_open_file(struct file *file, | |||
2105 | if (err < 0) | 2078 | if (err < 0) |
2106 | return err; | 2079 | return err; |
2107 | 2080 | ||
2108 | if (substream->ref_count > 1) | 2081 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); |
2109 | pcm_file = substream->file; | 2082 | if (pcm_file == NULL) { |
2110 | else { | 2083 | snd_pcm_release_substream(substream); |
2111 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); | 2084 | return -ENOMEM; |
2112 | if (pcm_file == NULL) { | 2085 | } |
2113 | snd_pcm_release_substream(substream); | 2086 | pcm_file->substream = substream; |
2114 | return -ENOMEM; | 2087 | if (substream->ref_count == 1) { |
2115 | } | ||
2116 | str = substream->pstr; | 2088 | str = substream->pstr; |
2117 | substream->file = pcm_file; | 2089 | substream->file = pcm_file; |
2118 | substream->pcm_release = pcm_release_private; | 2090 | substream->pcm_release = pcm_release_private; |
2119 | pcm_file->substream = substream; | ||
2120 | snd_pcm_add_file(str, pcm_file); | ||
2121 | } | 2091 | } |
2122 | file->private_data = pcm_file; | 2092 | file->private_data = pcm_file; |
2123 | *rpcm_file = pcm_file; | 2093 | *rpcm_file = pcm_file; |
@@ -2209,6 +2179,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file) | |||
2209 | fasync_helper(-1, file, 0, &substream->runtime->fasync); | 2179 | fasync_helper(-1, file, 0, &substream->runtime->fasync); |
2210 | mutex_lock(&pcm->open_mutex); | 2180 | mutex_lock(&pcm->open_mutex); |
2211 | snd_pcm_release_substream(substream); | 2181 | snd_pcm_release_substream(substream); |
2182 | kfree(pcm_file); | ||
2212 | mutex_unlock(&pcm->open_mutex); | 2183 | mutex_unlock(&pcm->open_mutex); |
2213 | wake_up(&pcm->open_wait); | 2184 | wake_up(&pcm->open_wait); |
2214 | module_put(pcm->card->module); | 2185 | module_put(pcm->card->module); |
@@ -3270,11 +3241,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) | |||
3270 | offset = area->vm_pgoff << PAGE_SHIFT; | 3241 | offset = area->vm_pgoff << PAGE_SHIFT; |
3271 | switch (offset) { | 3242 | switch (offset) { |
3272 | case SNDRV_PCM_MMAP_OFFSET_STATUS: | 3243 | case SNDRV_PCM_MMAP_OFFSET_STATUS: |
3273 | if (substream->no_mmap_ctrl) | 3244 | if (pcm_file->no_compat_mmap) |
3274 | return -ENXIO; | 3245 | return -ENXIO; |
3275 | return snd_pcm_mmap_status(substream, file, area); | 3246 | return snd_pcm_mmap_status(substream, file, area); |
3276 | case SNDRV_PCM_MMAP_OFFSET_CONTROL: | 3247 | case SNDRV_PCM_MMAP_OFFSET_CONTROL: |
3277 | if (substream->no_mmap_ctrl) | 3248 | if (pcm_file->no_compat_mmap) |
3278 | return -ENXIO; | 3249 | return -ENXIO; |
3279 | return snd_pcm_mmap_control(substream, file, area); | 3250 | return snd_pcm_mmap_control(substream, file, area); |
3280 | default: | 3251 | default: |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 8c15c66eb4aa..269c467ca9bb 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -55,7 +55,6 @@ static int snd_rawmidi_free(struct snd_rawmidi *rawmidi); | |||
55 | static int snd_rawmidi_dev_free(struct snd_device *device); | 55 | static int snd_rawmidi_dev_free(struct snd_device *device); |
56 | static int snd_rawmidi_dev_register(struct snd_device *device); | 56 | static int snd_rawmidi_dev_register(struct snd_device *device); |
57 | static int snd_rawmidi_dev_disconnect(struct snd_device *device); | 57 | static int snd_rawmidi_dev_disconnect(struct snd_device *device); |
58 | static int snd_rawmidi_dev_unregister(struct snd_device *device); | ||
59 | 58 | ||
60 | static LIST_HEAD(snd_rawmidi_devices); | 59 | static LIST_HEAD(snd_rawmidi_devices); |
61 | static DEFINE_MUTEX(register_mutex); | 60 | static DEFINE_MUTEX(register_mutex); |
@@ -431,7 +430,8 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
431 | kctl = snd_ctl_file(list); | 430 | kctl = snd_ctl_file(list); |
432 | if (kctl->pid == current->pid) { | 431 | if (kctl->pid == current->pid) { |
433 | subdevice = kctl->prefer_rawmidi_subdevice; | 432 | subdevice = kctl->prefer_rawmidi_subdevice; |
434 | break; | 433 | if (subdevice != -1) |
434 | break; | ||
435 | } | 435 | } |
436 | } | 436 | } |
437 | up_read(&card->controls_rwsem); | 437 | up_read(&card->controls_rwsem); |
@@ -1426,7 +1426,6 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, | |||
1426 | .dev_free = snd_rawmidi_dev_free, | 1426 | .dev_free = snd_rawmidi_dev_free, |
1427 | .dev_register = snd_rawmidi_dev_register, | 1427 | .dev_register = snd_rawmidi_dev_register, |
1428 | .dev_disconnect = snd_rawmidi_dev_disconnect, | 1428 | .dev_disconnect = snd_rawmidi_dev_disconnect, |
1429 | .dev_unregister = snd_rawmidi_dev_unregister | ||
1430 | }; | 1429 | }; |
1431 | 1430 | ||
1432 | snd_assert(rrawmidi != NULL, return -EINVAL); | 1431 | snd_assert(rrawmidi != NULL, return -EINVAL); |
@@ -1479,6 +1478,14 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) | |||
1479 | static int snd_rawmidi_free(struct snd_rawmidi *rmidi) | 1478 | static int snd_rawmidi_free(struct snd_rawmidi *rmidi) |
1480 | { | 1479 | { |
1481 | snd_assert(rmidi != NULL, return -ENXIO); | 1480 | snd_assert(rmidi != NULL, return -ENXIO); |
1481 | |||
1482 | snd_info_free_entry(rmidi->proc_entry); | ||
1483 | rmidi->proc_entry = NULL; | ||
1484 | mutex_lock(®ister_mutex); | ||
1485 | if (rmidi->ops && rmidi->ops->dev_unregister) | ||
1486 | rmidi->ops->dev_unregister(rmidi); | ||
1487 | mutex_unlock(®ister_mutex); | ||
1488 | |||
1482 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); | 1489 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); |
1483 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); | 1490 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); |
1484 | if (rmidi->private_free) | 1491 | if (rmidi->private_free) |
@@ -1587,21 +1594,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) | |||
1587 | 1594 | ||
1588 | mutex_lock(®ister_mutex); | 1595 | mutex_lock(®ister_mutex); |
1589 | list_del_init(&rmidi->list); | 1596 | list_del_init(&rmidi->list); |
1590 | mutex_unlock(®ister_mutex); | ||
1591 | return 0; | ||
1592 | } | ||
1593 | |||
1594 | static int snd_rawmidi_dev_unregister(struct snd_device *device) | ||
1595 | { | ||
1596 | struct snd_rawmidi *rmidi = device->device_data; | ||
1597 | |||
1598 | snd_assert(rmidi != NULL, return -ENXIO); | ||
1599 | mutex_lock(®ister_mutex); | ||
1600 | list_del(&rmidi->list); | ||
1601 | if (rmidi->proc_entry) { | ||
1602 | snd_info_unregister(rmidi->proc_entry); | ||
1603 | rmidi->proc_entry = NULL; | ||
1604 | } | ||
1605 | #ifdef CONFIG_SND_OSSEMUL | 1597 | #ifdef CONFIG_SND_OSSEMUL |
1606 | if (rmidi->ossreg) { | 1598 | if (rmidi->ossreg) { |
1607 | if ((int)rmidi->device == midi_map[rmidi->card->number]) { | 1599 | if ((int)rmidi->device == midi_map[rmidi->card->number]) { |
@@ -1615,17 +1607,9 @@ static int snd_rawmidi_dev_unregister(struct snd_device *device) | |||
1615 | rmidi->ossreg = 0; | 1607 | rmidi->ossreg = 0; |
1616 | } | 1608 | } |
1617 | #endif /* CONFIG_SND_OSSEMUL */ | 1609 | #endif /* CONFIG_SND_OSSEMUL */ |
1618 | if (rmidi->ops && rmidi->ops->dev_unregister) | ||
1619 | rmidi->ops->dev_unregister(rmidi); | ||
1620 | snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); | 1610 | snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); |
1621 | mutex_unlock(®ister_mutex); | 1611 | mutex_unlock(®ister_mutex); |
1622 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | 1612 | return 0; |
1623 | if (rmidi->seq_dev) { | ||
1624 | snd_device_free(rmidi->card, rmidi->seq_dev); | ||
1625 | rmidi->seq_dev = NULL; | ||
1626 | } | ||
1627 | #endif | ||
1628 | return snd_rawmidi_free(rmidi); | ||
1629 | } | 1613 | } |
1630 | 1614 | ||
1631 | /** | 1615 | /** |
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c index 84704ccb1829..412dd62b654e 100644 --- a/sound/core/rtctimer.c +++ b/sound/core/rtctimer.c | |||
@@ -156,7 +156,7 @@ static int __init rtctimer_init(void) | |||
156 | static void __exit rtctimer_exit(void) | 156 | static void __exit rtctimer_exit(void) |
157 | { | 157 | { |
158 | if (rtctimer) { | 158 | if (rtctimer) { |
159 | snd_timer_global_unregister(rtctimer); | 159 | snd_timer_global_free(rtctimer); |
160 | rtctimer = NULL; | 160 | rtctimer = NULL; |
161 | } | 161 | } |
162 | } | 162 | } |
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index e7234135641c..92858cf8b6eb 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c | |||
@@ -303,8 +303,7 @@ register_proc(void) | |||
303 | static void | 303 | static void |
304 | unregister_proc(void) | 304 | unregister_proc(void) |
305 | { | 305 | { |
306 | if (info_entry) | 306 | snd_info_free_entry(info_entry); |
307 | snd_info_unregister(info_entry); | ||
308 | info_entry = NULL; | 307 | info_entry = NULL; |
309 | } | 308 | } |
310 | #endif /* CONFIG_PROC_FS */ | 309 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 102ff548ce69..b79d011813c0 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c | |||
@@ -90,7 +90,6 @@ static int snd_seq_device_free(struct snd_seq_device *dev); | |||
90 | static int snd_seq_device_dev_free(struct snd_device *device); | 90 | static int snd_seq_device_dev_free(struct snd_device *device); |
91 | static int snd_seq_device_dev_register(struct snd_device *device); | 91 | static int snd_seq_device_dev_register(struct snd_device *device); |
92 | static int snd_seq_device_dev_disconnect(struct snd_device *device); | 92 | static int snd_seq_device_dev_disconnect(struct snd_device *device); |
93 | static int snd_seq_device_dev_unregister(struct snd_device *device); | ||
94 | 93 | ||
95 | static int init_device(struct snd_seq_device *dev, struct ops_list *ops); | 94 | static int init_device(struct snd_seq_device *dev, struct ops_list *ops); |
96 | static int free_device(struct snd_seq_device *dev, struct ops_list *ops); | 95 | static int free_device(struct snd_seq_device *dev, struct ops_list *ops); |
@@ -189,7 +188,6 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, | |||
189 | .dev_free = snd_seq_device_dev_free, | 188 | .dev_free = snd_seq_device_dev_free, |
190 | .dev_register = snd_seq_device_dev_register, | 189 | .dev_register = snd_seq_device_dev_register, |
191 | .dev_disconnect = snd_seq_device_dev_disconnect, | 190 | .dev_disconnect = snd_seq_device_dev_disconnect, |
192 | .dev_unregister = snd_seq_device_dev_unregister | ||
193 | }; | 191 | }; |
194 | 192 | ||
195 | if (result) | 193 | if (result) |
@@ -309,15 +307,6 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device) | |||
309 | } | 307 | } |
310 | 308 | ||
311 | /* | 309 | /* |
312 | * unregister the existing device | ||
313 | */ | ||
314 | static int snd_seq_device_dev_unregister(struct snd_device *device) | ||
315 | { | ||
316 | struct snd_seq_device *dev = device->device_data; | ||
317 | return snd_seq_device_free(dev); | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * register device driver | 310 | * register device driver |
322 | * id = driver id | 311 | * id = driver id |
323 | * entry = driver operators - duplicated to each instance | 312 | * entry = driver operators - duplicated to each instance |
@@ -573,7 +562,7 @@ static void __exit alsa_seq_device_exit(void) | |||
573 | { | 562 | { |
574 | remove_drivers(); | 563 | remove_drivers(); |
575 | #ifdef CONFIG_PROC_FS | 564 | #ifdef CONFIG_PROC_FS |
576 | snd_info_unregister(info_entry); | 565 | snd_info_free_entry(info_entry); |
577 | #endif | 566 | #endif |
578 | if (num_ops) | 567 | if (num_ops) |
579 | snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops); | 568 | snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops); |
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c index 142e9e6882c9..8a7fe5cca1c9 100644 --- a/sound/core/seq/seq_info.c +++ b/sound/core/seq/seq_info.c | |||
@@ -64,9 +64,9 @@ int __init snd_seq_info_init(void) | |||
64 | 64 | ||
65 | int __exit snd_seq_info_done(void) | 65 | int __exit snd_seq_info_done(void) |
66 | { | 66 | { |
67 | snd_info_unregister(queues_entry); | 67 | snd_info_free_entry(queues_entry); |
68 | snd_info_unregister(clients_entry); | 68 | snd_info_free_entry(clients_entry); |
69 | snd_info_unregister(timer_entry); | 69 | snd_info_free_entry(timer_entry); |
70 | return 0; | 70 | return 0; |
71 | } | 71 | } |
72 | #endif | 72 | #endif |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 7edd1fc58b17..efa476c5210a 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -268,7 +268,11 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
268 | snd_minors[minor] = preg; | 268 | snd_minors[minor] = preg; |
269 | if (card) | 269 | if (card) |
270 | device = card->dev; | 270 | device = card->dev; |
271 | class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name); | 271 | preg->class_dev = class_device_create(sound_class, NULL, |
272 | MKDEV(major, minor), | ||
273 | device, "%s", name); | ||
274 | if (preg->class_dev) | ||
275 | class_set_devdata(preg->class_dev, private_data); | ||
272 | 276 | ||
273 | mutex_unlock(&sound_mutex); | 277 | mutex_unlock(&sound_mutex); |
274 | return 0; | 278 | return 0; |
@@ -276,6 +280,24 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
276 | 280 | ||
277 | EXPORT_SYMBOL(snd_register_device); | 281 | EXPORT_SYMBOL(snd_register_device); |
278 | 282 | ||
283 | /* find the matching minor record | ||
284 | * return the index of snd_minor, or -1 if not found | ||
285 | */ | ||
286 | static int find_snd_minor(int type, struct snd_card *card, int dev) | ||
287 | { | ||
288 | int cardnum, minor; | ||
289 | struct snd_minor *mptr; | ||
290 | |||
291 | cardnum = card ? card->number : -1; | ||
292 | for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) | ||
293 | if ((mptr = snd_minors[minor]) != NULL && | ||
294 | mptr->type == type && | ||
295 | mptr->card == cardnum && | ||
296 | mptr->device == dev) | ||
297 | return minor; | ||
298 | return -1; | ||
299 | } | ||
300 | |||
279 | /** | 301 | /** |
280 | * snd_unregister_device - unregister the device on the given card | 302 | * snd_unregister_device - unregister the device on the given card |
281 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX | 303 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX |
@@ -289,32 +311,42 @@ EXPORT_SYMBOL(snd_register_device); | |||
289 | */ | 311 | */ |
290 | int snd_unregister_device(int type, struct snd_card *card, int dev) | 312 | int snd_unregister_device(int type, struct snd_card *card, int dev) |
291 | { | 313 | { |
292 | int cardnum, minor; | 314 | int minor; |
293 | struct snd_minor *mptr; | ||
294 | 315 | ||
295 | cardnum = card ? card->number : -1; | ||
296 | mutex_lock(&sound_mutex); | 316 | mutex_lock(&sound_mutex); |
297 | for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) | 317 | minor = find_snd_minor(type, card, dev); |
298 | if ((mptr = snd_minors[minor]) != NULL && | 318 | if (minor < 0) { |
299 | mptr->type == type && | ||
300 | mptr->card == cardnum && | ||
301 | mptr->device == dev) | ||
302 | break; | ||
303 | if (minor == ARRAY_SIZE(snd_minors)) { | ||
304 | mutex_unlock(&sound_mutex); | 319 | mutex_unlock(&sound_mutex); |
305 | return -EINVAL; | 320 | return -EINVAL; |
306 | } | 321 | } |
307 | 322 | ||
308 | class_device_destroy(sound_class, MKDEV(major, minor)); | 323 | class_device_destroy(sound_class, MKDEV(major, minor)); |
309 | 324 | ||
325 | kfree(snd_minors[minor]); | ||
310 | snd_minors[minor] = NULL; | 326 | snd_minors[minor] = NULL; |
311 | mutex_unlock(&sound_mutex); | 327 | mutex_unlock(&sound_mutex); |
312 | kfree(mptr); | ||
313 | return 0; | 328 | return 0; |
314 | } | 329 | } |
315 | 330 | ||
316 | EXPORT_SYMBOL(snd_unregister_device); | 331 | EXPORT_SYMBOL(snd_unregister_device); |
317 | 332 | ||
333 | int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev, | ||
334 | const struct class_device_attribute *attr) | ||
335 | { | ||
336 | int minor, ret = -EINVAL; | ||
337 | struct class_device *cdev; | ||
338 | |||
339 | mutex_lock(&sound_mutex); | ||
340 | minor = find_snd_minor(type, card, dev); | ||
341 | if (minor >= 0 && (cdev = snd_minors[minor]->class_dev) != NULL) | ||
342 | ret = class_device_create_file(cdev, attr); | ||
343 | mutex_unlock(&sound_mutex); | ||
344 | return ret; | ||
345 | |||
346 | } | ||
347 | |||
348 | EXPORT_SYMBOL(snd_add_device_sysfs_file); | ||
349 | |||
318 | #ifdef CONFIG_PROC_FS | 350 | #ifdef CONFIG_PROC_FS |
319 | /* | 351 | /* |
320 | * INFO PART | 352 | * INFO PART |
@@ -387,8 +419,7 @@ int __init snd_minor_info_init(void) | |||
387 | 419 | ||
388 | int __exit snd_minor_info_done(void) | 420 | int __exit snd_minor_info_done(void) |
389 | { | 421 | { |
390 | if (snd_minor_info_entry) | 422 | snd_info_free_entry(snd_minor_info_entry); |
391 | snd_info_unregister(snd_minor_info_entry); | ||
392 | return 0; | 423 | return 0; |
393 | } | 424 | } |
394 | #endif /* CONFIG_PROC_FS */ | 425 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 74f0fe5a1ba0..b2fc40aa520b 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c | |||
@@ -270,8 +270,7 @@ int __init snd_minor_info_oss_init(void) | |||
270 | 270 | ||
271 | int __exit snd_minor_info_oss_done(void) | 271 | int __exit snd_minor_info_oss_done(void) |
272 | { | 272 | { |
273 | if (snd_minor_info_oss_entry) | 273 | snd_info_free_entry(snd_minor_info_oss_entry); |
274 | snd_info_unregister(snd_minor_info_oss_entry); | ||
275 | return 0; | 274 | return 0; |
276 | } | 275 | } |
277 | #endif /* CONFIG_PROC_FS */ | 276 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 0a984e881c10..10a79aed33f8 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -88,7 +88,7 @@ static DEFINE_MUTEX(register_mutex); | |||
88 | static int snd_timer_free(struct snd_timer *timer); | 88 | static int snd_timer_free(struct snd_timer *timer); |
89 | static int snd_timer_dev_free(struct snd_device *device); | 89 | static int snd_timer_dev_free(struct snd_device *device); |
90 | static int snd_timer_dev_register(struct snd_device *device); | 90 | static int snd_timer_dev_register(struct snd_device *device); |
91 | static int snd_timer_dev_unregister(struct snd_device *device); | 91 | static int snd_timer_dev_disconnect(struct snd_device *device); |
92 | 92 | ||
93 | static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left); | 93 | static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left); |
94 | 94 | ||
@@ -718,7 +718,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
718 | } | 718 | } |
719 | } | 719 | } |
720 | if (timer->flags & SNDRV_TIMER_FLG_RESCHED) | 720 | if (timer->flags & SNDRV_TIMER_FLG_RESCHED) |
721 | snd_timer_reschedule(timer, ticks_left); | 721 | snd_timer_reschedule(timer, timer->sticks); |
722 | if (timer->running) { | 722 | if (timer->running) { |
723 | if (timer->hw.flags & SNDRV_TIMER_HW_STOP) { | 723 | if (timer->hw.flags & SNDRV_TIMER_HW_STOP) { |
724 | timer->hw.stop(timer); | 724 | timer->hw.stop(timer); |
@@ -773,7 +773,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, | |||
773 | static struct snd_device_ops ops = { | 773 | static struct snd_device_ops ops = { |
774 | .dev_free = snd_timer_dev_free, | 774 | .dev_free = snd_timer_dev_free, |
775 | .dev_register = snd_timer_dev_register, | 775 | .dev_register = snd_timer_dev_register, |
776 | .dev_unregister = snd_timer_dev_unregister | 776 | .dev_disconnect = snd_timer_dev_disconnect, |
777 | }; | 777 | }; |
778 | 778 | ||
779 | snd_assert(tid != NULL, return -EINVAL); | 779 | snd_assert(tid != NULL, return -EINVAL); |
@@ -813,6 +813,21 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, | |||
813 | static int snd_timer_free(struct snd_timer *timer) | 813 | static int snd_timer_free(struct snd_timer *timer) |
814 | { | 814 | { |
815 | snd_assert(timer != NULL, return -ENXIO); | 815 | snd_assert(timer != NULL, return -ENXIO); |
816 | |||
817 | mutex_lock(®ister_mutex); | ||
818 | if (! list_empty(&timer->open_list_head)) { | ||
819 | struct list_head *p, *n; | ||
820 | struct snd_timer_instance *ti; | ||
821 | snd_printk(KERN_WARNING "timer %p is busy?\n", timer); | ||
822 | list_for_each_safe(p, n, &timer->open_list_head) { | ||
823 | list_del_init(p); | ||
824 | ti = list_entry(p, struct snd_timer_instance, open_list); | ||
825 | ti->timer = NULL; | ||
826 | } | ||
827 | } | ||
828 | list_del(&timer->device_list); | ||
829 | mutex_unlock(®ister_mutex); | ||
830 | |||
816 | if (timer->private_free) | 831 | if (timer->private_free) |
817 | timer->private_free(timer); | 832 | timer->private_free(timer); |
818 | kfree(timer); | 833 | kfree(timer); |
@@ -867,30 +882,13 @@ static int snd_timer_dev_register(struct snd_device *dev) | |||
867 | return 0; | 882 | return 0; |
868 | } | 883 | } |
869 | 884 | ||
870 | static int snd_timer_unregister(struct snd_timer *timer) | 885 | static int snd_timer_dev_disconnect(struct snd_device *device) |
871 | { | 886 | { |
872 | struct list_head *p, *n; | 887 | struct snd_timer *timer = device->device_data; |
873 | struct snd_timer_instance *ti; | ||
874 | |||
875 | snd_assert(timer != NULL, return -ENXIO); | ||
876 | mutex_lock(®ister_mutex); | 888 | mutex_lock(®ister_mutex); |
877 | if (! list_empty(&timer->open_list_head)) { | 889 | list_del_init(&timer->device_list); |
878 | snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer); | ||
879 | list_for_each_safe(p, n, &timer->open_list_head) { | ||
880 | list_del_init(p); | ||
881 | ti = list_entry(p, struct snd_timer_instance, open_list); | ||
882 | ti->timer = NULL; | ||
883 | } | ||
884 | } | ||
885 | list_del(&timer->device_list); | ||
886 | mutex_unlock(®ister_mutex); | 890 | mutex_unlock(®ister_mutex); |
887 | return snd_timer_free(timer); | 891 | return 0; |
888 | } | ||
889 | |||
890 | static int snd_timer_dev_unregister(struct snd_device *device) | ||
891 | { | ||
892 | struct snd_timer *timer = device->device_data; | ||
893 | return snd_timer_unregister(timer); | ||
894 | } | 892 | } |
895 | 893 | ||
896 | void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) | 894 | void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) |
@@ -955,18 +953,12 @@ int snd_timer_global_register(struct snd_timer *timer) | |||
955 | return snd_timer_dev_register(&dev); | 953 | return snd_timer_dev_register(&dev); |
956 | } | 954 | } |
957 | 955 | ||
958 | int snd_timer_global_unregister(struct snd_timer *timer) | ||
959 | { | ||
960 | return snd_timer_unregister(timer); | ||
961 | } | ||
962 | |||
963 | /* | 956 | /* |
964 | * System timer | 957 | * System timer |
965 | */ | 958 | */ |
966 | 959 | ||
967 | struct snd_timer_system_private { | 960 | struct snd_timer_system_private { |
968 | struct timer_list tlist; | 961 | struct timer_list tlist; |
969 | struct timer * timer; | ||
970 | unsigned long last_expires; | 962 | unsigned long last_expires; |
971 | unsigned long last_jiffies; | 963 | unsigned long last_jiffies; |
972 | unsigned long correction; | 964 | unsigned long correction; |
@@ -978,7 +970,7 @@ static void snd_timer_s_function(unsigned long data) | |||
978 | struct snd_timer_system_private *priv = timer->private_data; | 970 | struct snd_timer_system_private *priv = timer->private_data; |
979 | unsigned long jiff = jiffies; | 971 | unsigned long jiff = jiffies; |
980 | if (time_after(jiff, priv->last_expires)) | 972 | if (time_after(jiff, priv->last_expires)) |
981 | priv->correction = (long)jiff - (long)priv->last_expires; | 973 | priv->correction += (long)jiff - (long)priv->last_expires; |
982 | snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies); | 974 | snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies); |
983 | } | 975 | } |
984 | 976 | ||
@@ -994,7 +986,7 @@ static int snd_timer_s_start(struct snd_timer * timer) | |||
994 | njiff++; | 986 | njiff++; |
995 | } else { | 987 | } else { |
996 | njiff += timer->sticks - priv->correction; | 988 | njiff += timer->sticks - priv->correction; |
997 | priv->correction -= timer->sticks; | 989 | priv->correction = 0; |
998 | } | 990 | } |
999 | priv->last_expires = priv->tlist.expires = njiff; | 991 | priv->last_expires = priv->tlist.expires = njiff; |
1000 | add_timer(&priv->tlist); | 992 | add_timer(&priv->tlist); |
@@ -1013,6 +1005,7 @@ static int snd_timer_s_stop(struct snd_timer * timer) | |||
1013 | timer->sticks = priv->last_expires - jiff; | 1005 | timer->sticks = priv->last_expires - jiff; |
1014 | else | 1006 | else |
1015 | timer->sticks = 1; | 1007 | timer->sticks = 1; |
1008 | priv->correction = 0; | ||
1016 | return 0; | 1009 | return 0; |
1017 | } | 1010 | } |
1018 | 1011 | ||
@@ -1126,7 +1119,7 @@ static void __init snd_timer_proc_init(void) | |||
1126 | 1119 | ||
1127 | static void __exit snd_timer_proc_done(void) | 1120 | static void __exit snd_timer_proc_done(void) |
1128 | { | 1121 | { |
1129 | snd_info_unregister(snd_timer_proc_entry); | 1122 | snd_info_free_entry(snd_timer_proc_entry); |
1130 | } | 1123 | } |
1131 | #else /* !CONFIG_PROC_FS */ | 1124 | #else /* !CONFIG_PROC_FS */ |
1132 | #define snd_timer_proc_init() | 1125 | #define snd_timer_proc_init() |
@@ -1982,7 +1975,7 @@ static void __exit alsa_timer_exit(void) | |||
1982 | /* unregister the system timer */ | 1975 | /* unregister the system timer */ |
1983 | list_for_each_safe(p, n, &snd_timer_list) { | 1976 | list_for_each_safe(p, n, &snd_timer_list) { |
1984 | struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); | 1977 | struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); |
1985 | snd_timer_unregister(timer); | 1978 | snd_timer_free(timer); |
1986 | } | 1979 | } |
1987 | snd_timer_proc_done(); | 1980 | snd_timer_proc_done(); |
1988 | #ifdef SNDRV_OSS_INFO_DEV_TIMERS | 1981 | #ifdef SNDRV_OSS_INFO_DEV_TIMERS |
@@ -2005,5 +1998,4 @@ EXPORT_SYMBOL(snd_timer_notify); | |||
2005 | EXPORT_SYMBOL(snd_timer_global_new); | 1998 | EXPORT_SYMBOL(snd_timer_global_new); |
2006 | EXPORT_SYMBOL(snd_timer_global_free); | 1999 | EXPORT_SYMBOL(snd_timer_global_free); |
2007 | EXPORT_SYMBOL(snd_timer_global_register); | 2000 | EXPORT_SYMBOL(snd_timer_global_register); |
2008 | EXPORT_SYMBOL(snd_timer_global_unregister); | ||
2009 | EXPORT_SYMBOL(snd_timer_interrupt); | 2001 | EXPORT_SYMBOL(snd_timer_interrupt); |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 395c4ef52ac9..7971285dfd5b 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -73,6 +73,19 @@ config SND_MTPAV | |||
73 | To compile this driver as a module, choose M here: the module | 73 | To compile this driver as a module, choose M here: the module |
74 | will be called snd-mtpav. | 74 | will be called snd-mtpav. |
75 | 75 | ||
76 | config SND_MTS64 | ||
77 | tristate "ESI Miditerminal 4140 driver" | ||
78 | depends on SND && PARPORT | ||
79 | select SND_RAWMIDI | ||
80 | help | ||
81 | The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with | ||
82 | additional SMPTE Timecode capabilities for the parallel port. | ||
83 | |||
84 | Say 'Y' to include support for this device. | ||
85 | |||
86 | To compile this driver as a module, chose 'M' here: the module | ||
87 | will be called snd-mts64. | ||
88 | |||
76 | config SND_SERIAL_U16550 | 89 | config SND_SERIAL_U16550 |
77 | tristate "UART16550 serial MIDI driver" | 90 | tristate "UART16550 serial MIDI driver" |
78 | depends on SND | 91 | depends on SND |
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index cb98c3d662be..c9bad6d67e73 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | snd-dummy-objs := dummy.o | 6 | snd-dummy-objs := dummy.o |
7 | snd-mtpav-objs := mtpav.o | 7 | snd-mtpav-objs := mtpav.o |
8 | snd-mts64-objs := mts64.o | ||
8 | snd-serial-u16550-objs := serial-u16550.o | 9 | snd-serial-u16550-objs := serial-u16550.o |
9 | snd-virmidi-objs := virmidi.o | 10 | snd-virmidi-objs := virmidi.o |
10 | 11 | ||
@@ -13,5 +14,6 @@ obj-$(CONFIG_SND_DUMMY) += snd-dummy.o | |||
13 | obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o | 14 | obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o |
14 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o | 15 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o |
15 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o | 16 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o |
17 | obj-$(CONFIG_SND_MTS64) += snd-mts64.o | ||
16 | 18 | ||
17 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ | 19 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index ffeafaf2ecca..42001efa9f3e 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
30 | #include <sound/core.h> | 30 | #include <sound/core.h> |
31 | #include <sound/control.h> | 31 | #include <sound/control.h> |
32 | #include <sound/tlv.h> | ||
32 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
33 | #include <sound/rawmidi.h> | 34 | #include <sound/rawmidi.h> |
34 | #include <sound/initval.h> | 35 | #include <sound/initval.h> |
@@ -285,7 +286,7 @@ static struct snd_pcm_hardware snd_card_dummy_playback = | |||
285 | .channels_max = USE_CHANNELS_MAX, | 286 | .channels_max = USE_CHANNELS_MAX, |
286 | .buffer_bytes_max = MAX_BUFFER_SIZE, | 287 | .buffer_bytes_max = MAX_BUFFER_SIZE, |
287 | .period_bytes_min = 64, | 288 | .period_bytes_min = 64, |
288 | .period_bytes_max = MAX_BUFFER_SIZE, | 289 | .period_bytes_max = MAX_PERIOD_SIZE, |
289 | .periods_min = USE_PERIODS_MIN, | 290 | .periods_min = USE_PERIODS_MIN, |
290 | .periods_max = USE_PERIODS_MAX, | 291 | .periods_max = USE_PERIODS_MAX, |
291 | .fifo_size = 0, | 292 | .fifo_size = 0, |
@@ -443,10 +444,13 @@ static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int su | |||
443 | } | 444 | } |
444 | 445 | ||
445 | #define DUMMY_VOLUME(xname, xindex, addr) \ | 446 | #define DUMMY_VOLUME(xname, xindex, addr) \ |
446 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 447 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
448 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
449 | .name = xname, .index = xindex, \ | ||
447 | .info = snd_dummy_volume_info, \ | 450 | .info = snd_dummy_volume_info, \ |
448 | .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \ | 451 | .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \ |
449 | .private_value = addr } | 452 | .private_value = addr, \ |
453 | .tlv = { .p = db_scale_dummy } } | ||
450 | 454 | ||
451 | static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol, | 455 | static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol, |
452 | struct snd_ctl_elem_info *uinfo) | 456 | struct snd_ctl_elem_info *uinfo) |
@@ -497,6 +501,8 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, | |||
497 | return change; | 501 | return change; |
498 | } | 502 | } |
499 | 503 | ||
504 | static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); | ||
505 | |||
500 | #define DUMMY_CAPSRC(xname, xindex, addr) \ | 506 | #define DUMMY_CAPSRC(xname, xindex, addr) \ |
501 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 507 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
502 | .info = snd_dummy_capsrc_info, \ | 508 | .info = snd_dummy_capsrc_info, \ |
@@ -547,13 +553,13 @@ static struct snd_kcontrol_new snd_dummy_controls[] = { | |||
547 | DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), | 553 | DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), |
548 | DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), | 554 | DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), |
549 | DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), | 555 | DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), |
550 | DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_MASTER), | 556 | DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH), |
551 | DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE), | 557 | DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE), |
552 | DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_MASTER), | 558 | DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE), |
553 | DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), | 559 | DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), |
554 | DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MASTER), | 560 | DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC), |
555 | DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), | 561 | DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), |
556 | DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER) | 562 | DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD) |
557 | }; | 563 | }; |
558 | 564 | ||
559 | static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) | 565 | static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) |
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 17cc105b26fc..2de181ad0b05 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c | |||
@@ -211,7 +211,7 @@ static void __devexit snd_mpu401_pnp_remove(struct pnp_dev *dev) | |||
211 | struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev); | 211 | struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev); |
212 | 212 | ||
213 | snd_card_disconnect(card); | 213 | snd_card_disconnect(card); |
214 | snd_card_free_in_thread(card); | 214 | snd_card_free_when_closed(card); |
215 | } | 215 | } |
216 | 216 | ||
217 | static struct pnp_driver snd_mpu401_pnp_driver = { | 217 | static struct pnp_driver snd_mpu401_pnp_driver = { |
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c new file mode 100644 index 000000000000..169987302ae4 --- /dev/null +++ b/sound/drivers/mts64.c | |||
@@ -0,0 +1,1091 @@ | |||
1 | /* | ||
2 | * ALSA Driver for Ego Systems Inc. (ESI) Miditerminal 4140 | ||
3 | * Copyright (c) 2006 by Matthias König <mk@phasorlab.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/parport.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/initval.h> | ||
29 | #include <sound/rawmidi.h> | ||
30 | #include <sound/control.h> | ||
31 | |||
32 | #define CARD_NAME "Miditerminal 4140" | ||
33 | #define DRIVER_NAME "MTS64" | ||
34 | #define PLATFORM_DRIVER "snd_mts64" | ||
35 | |||
36 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
37 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
38 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
39 | |||
40 | static struct platform_device *platform_devices[SNDRV_CARDS]; | ||
41 | static int device_count; | ||
42 | |||
43 | module_param_array(index, int, NULL, S_IRUGO); | ||
44 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); | ||
45 | module_param_array(id, charp, NULL, S_IRUGO); | ||
46 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | ||
47 | module_param_array(enable, bool, NULL, S_IRUGO); | ||
48 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | ||
49 | |||
50 | MODULE_AUTHOR("Matthias Koenig <mk@phasorlab.de>"); | ||
51 | MODULE_DESCRIPTION("ESI Miditerminal 4140"); | ||
52 | MODULE_LICENSE("GPL"); | ||
53 | MODULE_SUPPORTED_DEVICE("{{ESI,Miditerminal 4140}}"); | ||
54 | |||
55 | /********************************************************************* | ||
56 | * Chip specific | ||
57 | *********************************************************************/ | ||
58 | #define MTS64_NUM_INPUT_PORTS 5 | ||
59 | #define MTS64_NUM_OUTPUT_PORTS 4 | ||
60 | #define MTS64_SMPTE_SUBSTREAM 4 | ||
61 | |||
62 | struct mts64 { | ||
63 | spinlock_t lock; | ||
64 | struct snd_card *card; | ||
65 | struct snd_rawmidi *rmidi; | ||
66 | struct pardevice *pardev; | ||
67 | int pardev_claimed; | ||
68 | |||
69 | int open_count; | ||
70 | int current_midi_output_port; | ||
71 | int current_midi_input_port; | ||
72 | u8 mode[MTS64_NUM_INPUT_PORTS]; | ||
73 | struct snd_rawmidi_substream *midi_input_substream[MTS64_NUM_INPUT_PORTS]; | ||
74 | int smpte_switch; | ||
75 | u8 time[4]; /* [0]=hh, [1]=mm, [2]=ss, [3]=ff */ | ||
76 | u8 fps; | ||
77 | }; | ||
78 | |||
79 | static int snd_mts64_free(struct mts64 *mts) | ||
80 | { | ||
81 | kfree(mts); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int __devinit snd_mts64_create(struct snd_card *card, | ||
86 | struct pardevice *pardev, | ||
87 | struct mts64 **rchip) | ||
88 | { | ||
89 | struct mts64 *mts; | ||
90 | |||
91 | *rchip = NULL; | ||
92 | |||
93 | mts = kzalloc(sizeof(struct mts64), GFP_KERNEL); | ||
94 | if (mts == NULL) | ||
95 | return -ENOMEM; | ||
96 | |||
97 | /* Init chip specific data */ | ||
98 | spin_lock_init(&mts->lock); | ||
99 | mts->card = card; | ||
100 | mts->pardev = pardev; | ||
101 | mts->current_midi_output_port = -1; | ||
102 | mts->current_midi_input_port = -1; | ||
103 | |||
104 | *rchip = mts; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /********************************************************************* | ||
110 | * HW register related constants | ||
111 | *********************************************************************/ | ||
112 | |||
113 | /* Status Bits */ | ||
114 | #define MTS64_STAT_BSY 0x80 | ||
115 | #define MTS64_STAT_BIT_SET 0x20 /* readout process, bit is set */ | ||
116 | #define MTS64_STAT_PORT 0x10 /* read byte is a port number */ | ||
117 | |||
118 | /* Control Bits */ | ||
119 | #define MTS64_CTL_READOUT 0x08 /* enable readout */ | ||
120 | #define MTS64_CTL_WRITE_CMD 0x06 | ||
121 | #define MTS64_CTL_WRITE_DATA 0x02 | ||
122 | #define MTS64_CTL_STROBE 0x01 | ||
123 | |||
124 | /* Command */ | ||
125 | #define MTS64_CMD_RESET 0xfe | ||
126 | #define MTS64_CMD_PROBE 0x8f /* Used in probing procedure */ | ||
127 | #define MTS64_CMD_SMPTE_SET_TIME 0xe8 | ||
128 | #define MTS64_CMD_SMPTE_SET_FPS 0xee | ||
129 | #define MTS64_CMD_SMPTE_STOP 0xef | ||
130 | #define MTS64_CMD_SMPTE_FPS_24 0xe3 | ||
131 | #define MTS64_CMD_SMPTE_FPS_25 0xe2 | ||
132 | #define MTS64_CMD_SMPTE_FPS_2997 0xe4 | ||
133 | #define MTS64_CMD_SMPTE_FPS_30D 0xe1 | ||
134 | #define MTS64_CMD_SMPTE_FPS_30 0xe0 | ||
135 | #define MTS64_CMD_COM_OPEN 0xf8 /* setting the communication mode */ | ||
136 | #define MTS64_CMD_COM_CLOSE1 0xff /* clearing communication mode */ | ||
137 | #define MTS64_CMD_COM_CLOSE2 0xf5 | ||
138 | |||
139 | /********************************************************************* | ||
140 | * Hardware specific functions | ||
141 | *********************************************************************/ | ||
142 | static void mts64_enable_readout(struct parport *p); | ||
143 | static void mts64_disable_readout(struct parport *p); | ||
144 | static int mts64_device_ready(struct parport *p); | ||
145 | static int mts64_device_init(struct parport *p); | ||
146 | static int mts64_device_open(struct mts64 *mts); | ||
147 | static int mts64_device_close(struct mts64 *mts); | ||
148 | static u8 mts64_map_midi_input(u8 c); | ||
149 | static int mts64_probe(struct parport *p); | ||
150 | static u16 mts64_read(struct parport *p); | ||
151 | static u8 mts64_read_char(struct parport *p); | ||
152 | static void mts64_smpte_start(struct parport *p, | ||
153 | u8 hours, u8 minutes, | ||
154 | u8 seconds, u8 frames, | ||
155 | u8 idx); | ||
156 | static void mts64_smpte_stop(struct parport *p); | ||
157 | static void mts64_write_command(struct parport *p, u8 c); | ||
158 | static void mts64_write_data(struct parport *p, u8 c); | ||
159 | static void mts64_write_midi(struct mts64 *mts, u8 c, int midiport); | ||
160 | |||
161 | |||
162 | /* Enables the readout procedure | ||
163 | * | ||
164 | * Before we can read a midi byte from the device, we have to set | ||
165 | * bit 3 of control port. | ||
166 | */ | ||
167 | static void mts64_enable_readout(struct parport *p) | ||
168 | { | ||
169 | u8 c; | ||
170 | |||
171 | c = parport_read_control(p); | ||
172 | c |= MTS64_CTL_READOUT; | ||
173 | parport_write_control(p, c); | ||
174 | } | ||
175 | |||
176 | /* Disables readout | ||
177 | * | ||
178 | * Readout is disabled by clearing bit 3 of control | ||
179 | */ | ||
180 | static void mts64_disable_readout(struct parport *p) | ||
181 | { | ||
182 | u8 c; | ||
183 | |||
184 | c = parport_read_control(p); | ||
185 | c &= ~MTS64_CTL_READOUT; | ||
186 | parport_write_control(p, c); | ||
187 | } | ||
188 | |||
189 | /* waits for device ready | ||
190 | * | ||
191 | * Checks if BUSY (Bit 7 of status) is clear | ||
192 | * 1 device ready | ||
193 | * 0 failure | ||
194 | */ | ||
195 | static int mts64_device_ready(struct parport *p) | ||
196 | { | ||
197 | int i; | ||
198 | u8 c; | ||
199 | |||
200 | for (i = 0; i < 0xffff; ++i) { | ||
201 | c = parport_read_status(p); | ||
202 | c &= MTS64_STAT_BSY; | ||
203 | if (c != 0) | ||
204 | return 1; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* Init device (LED blinking startup magic) | ||
211 | * | ||
212 | * Returns: | ||
213 | * 0 init ok | ||
214 | * -EIO failure | ||
215 | */ | ||
216 | static int __devinit mts64_device_init(struct parport *p) | ||
217 | { | ||
218 | int i; | ||
219 | |||
220 | mts64_write_command(p, MTS64_CMD_RESET); | ||
221 | |||
222 | for (i = 0; i < 64; ++i) { | ||
223 | msleep(100); | ||
224 | |||
225 | if (mts64_probe(p) == 0) { | ||
226 | /* success */ | ||
227 | mts64_disable_readout(p); | ||
228 | return 0; | ||
229 | } | ||
230 | } | ||
231 | mts64_disable_readout(p); | ||
232 | |||
233 | return -EIO; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Opens the device (set communication mode) | ||
238 | */ | ||
239 | static int mts64_device_open(struct mts64 *mts) | ||
240 | { | ||
241 | int i; | ||
242 | struct parport *p = mts->pardev->port; | ||
243 | |||
244 | for (i = 0; i < 5; ++i) | ||
245 | mts64_write_command(p, MTS64_CMD_COM_OPEN); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * Close device (clear communication mode) | ||
252 | */ | ||
253 | static int mts64_device_close(struct mts64 *mts) | ||
254 | { | ||
255 | int i; | ||
256 | struct parport *p = mts->pardev->port; | ||
257 | |||
258 | for (i = 0; i < 5; ++i) { | ||
259 | mts64_write_command(p, MTS64_CMD_COM_CLOSE1); | ||
260 | mts64_write_command(p, MTS64_CMD_COM_CLOSE2); | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | /* map hardware port to substream number | ||
267 | * | ||
268 | * When reading a byte from the device, the device tells us | ||
269 | * on what port the byte is. This HW port has to be mapped to | ||
270 | * the midiport (substream number). | ||
271 | * substream 0-3 are Midiports 1-4 | ||
272 | * substream 4 is SMPTE Timecode | ||
273 | * The mapping is done by the table: | ||
274 | * HW | 0 | 1 | 2 | 3 | 4 | ||
275 | * SW | 0 | 1 | 4 | 2 | 3 | ||
276 | */ | ||
277 | static u8 mts64_map_midi_input(u8 c) | ||
278 | { | ||
279 | static u8 map[] = { 0, 1, 4, 2, 3 }; | ||
280 | |||
281 | return map[c]; | ||
282 | } | ||
283 | |||
284 | |||
285 | /* Probe parport for device | ||
286 | * | ||
287 | * Do we have a Miditerminal 4140 on parport? | ||
288 | * Returns: | ||
289 | * 0 device found | ||
290 | * -ENODEV no device | ||
291 | */ | ||
292 | static int __devinit mts64_probe(struct parport *p) | ||
293 | { | ||
294 | u8 c; | ||
295 | |||
296 | mts64_smpte_stop(p); | ||
297 | mts64_write_command(p, MTS64_CMD_PROBE); | ||
298 | |||
299 | msleep(50); | ||
300 | |||
301 | c = mts64_read(p); | ||
302 | |||
303 | c &= 0x00ff; | ||
304 | if (c != MTS64_CMD_PROBE) | ||
305 | return -ENODEV; | ||
306 | else | ||
307 | return 0; | ||
308 | |||
309 | } | ||
310 | |||
311 | /* Read byte incl. status from device | ||
312 | * | ||
313 | * Returns: | ||
314 | * data in lower 8 bits and status in upper 8 bits | ||
315 | */ | ||
316 | static u16 mts64_read(struct parport *p) | ||
317 | { | ||
318 | u8 data, status; | ||
319 | |||
320 | mts64_device_ready(p); | ||
321 | mts64_enable_readout(p); | ||
322 | status = parport_read_status(p); | ||
323 | data = mts64_read_char(p); | ||
324 | mts64_disable_readout(p); | ||
325 | |||
326 | return (status << 8) | data; | ||
327 | } | ||
328 | |||
329 | /* Read a byte from device | ||
330 | * | ||
331 | * Note, that readout mode has to be enabled. | ||
332 | * readout procedure is as follows: | ||
333 | * - Write number of the Bit to read to DATA | ||
334 | * - Read STATUS | ||
335 | * - Bit 5 of STATUS indicates if Bit is set | ||
336 | * | ||
337 | * Returns: | ||
338 | * Byte read from device | ||
339 | */ | ||
340 | static u8 mts64_read_char(struct parport *p) | ||
341 | { | ||
342 | u8 c = 0; | ||
343 | u8 status; | ||
344 | u8 i; | ||
345 | |||
346 | for (i = 0; i < 8; ++i) { | ||
347 | parport_write_data(p, i); | ||
348 | c >>= 1; | ||
349 | status = parport_read_status(p); | ||
350 | if (status & MTS64_STAT_BIT_SET) | ||
351 | c |= 0x80; | ||
352 | } | ||
353 | |||
354 | return c; | ||
355 | } | ||
356 | |||
357 | /* Starts SMPTE Timecode generation | ||
358 | * | ||
359 | * The device creates SMPTE Timecode by hardware. | ||
360 | * 0 24 fps | ||
361 | * 1 25 fps | ||
362 | * 2 29.97 fps | ||
363 | * 3 30 fps (Drop-frame) | ||
364 | * 4 30 fps | ||
365 | */ | ||
366 | static void mts64_smpte_start(struct parport *p, | ||
367 | u8 hours, u8 minutes, | ||
368 | u8 seconds, u8 frames, | ||
369 | u8 idx) | ||
370 | { | ||
371 | static u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24, | ||
372 | MTS64_CMD_SMPTE_FPS_25, | ||
373 | MTS64_CMD_SMPTE_FPS_2997, | ||
374 | MTS64_CMD_SMPTE_FPS_30D, | ||
375 | MTS64_CMD_SMPTE_FPS_30 }; | ||
376 | |||
377 | mts64_write_command(p, MTS64_CMD_SMPTE_SET_TIME); | ||
378 | mts64_write_command(p, frames); | ||
379 | mts64_write_command(p, seconds); | ||
380 | mts64_write_command(p, minutes); | ||
381 | mts64_write_command(p, hours); | ||
382 | |||
383 | mts64_write_command(p, MTS64_CMD_SMPTE_SET_FPS); | ||
384 | mts64_write_command(p, fps[idx]); | ||
385 | } | ||
386 | |||
387 | /* Stops SMPTE Timecode generation | ||
388 | */ | ||
389 | static void mts64_smpte_stop(struct parport *p) | ||
390 | { | ||
391 | mts64_write_command(p, MTS64_CMD_SMPTE_STOP); | ||
392 | } | ||
393 | |||
394 | /* Write a command byte to device | ||
395 | */ | ||
396 | static void mts64_write_command(struct parport *p, u8 c) | ||
397 | { | ||
398 | mts64_device_ready(p); | ||
399 | |||
400 | parport_write_data(p, c); | ||
401 | |||
402 | parport_write_control(p, MTS64_CTL_WRITE_CMD); | ||
403 | parport_write_control(p, MTS64_CTL_WRITE_CMD | MTS64_CTL_STROBE); | ||
404 | parport_write_control(p, MTS64_CTL_WRITE_CMD); | ||
405 | } | ||
406 | |||
407 | /* Write a data byte to device | ||
408 | */ | ||
409 | static void mts64_write_data(struct parport *p, u8 c) | ||
410 | { | ||
411 | mts64_device_ready(p); | ||
412 | |||
413 | parport_write_data(p, c); | ||
414 | |||
415 | parport_write_control(p, MTS64_CTL_WRITE_DATA); | ||
416 | parport_write_control(p, MTS64_CTL_WRITE_DATA | MTS64_CTL_STROBE); | ||
417 | parport_write_control(p, MTS64_CTL_WRITE_DATA); | ||
418 | } | ||
419 | |||
420 | /* Write a MIDI byte to midiport | ||
421 | * | ||
422 | * midiport ranges from 0-3 and maps to Ports 1-4 | ||
423 | * assumptions: communication mode is on | ||
424 | */ | ||
425 | static void mts64_write_midi(struct mts64 *mts, u8 c, | ||
426 | int midiport) | ||
427 | { | ||
428 | struct parport *p = mts->pardev->port; | ||
429 | |||
430 | /* check current midiport */ | ||
431 | if (mts->current_midi_output_port != midiport) | ||
432 | mts64_write_command(p, midiport); | ||
433 | |||
434 | /* write midi byte */ | ||
435 | mts64_write_data(p, c); | ||
436 | } | ||
437 | |||
438 | /********************************************************************* | ||
439 | * Control elements | ||
440 | *********************************************************************/ | ||
441 | |||
442 | /* SMPTE Switch */ | ||
443 | static int snd_mts64_ctl_smpte_switch_info(struct snd_kcontrol *kctl, | ||
444 | struct snd_ctl_elem_info *uinfo) | ||
445 | { | ||
446 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
447 | uinfo->count = 1; | ||
448 | uinfo->value.integer.min = 0; | ||
449 | uinfo->value.integer.max = 1; | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl, | ||
454 | struct snd_ctl_elem_value *uctl) | ||
455 | { | ||
456 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
457 | |||
458 | spin_lock_irq(&mts->lock); | ||
459 | uctl->value.integer.value[0] = mts->smpte_switch; | ||
460 | spin_unlock_irq(&mts->lock); | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | /* smpte_switch is not accessed from IRQ handler, so we just need | ||
466 | to protect the HW access */ | ||
467 | static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl, | ||
468 | struct snd_ctl_elem_value *uctl) | ||
469 | { | ||
470 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
471 | int changed = 0; | ||
472 | |||
473 | spin_lock_irq(&mts->lock); | ||
474 | if (mts->smpte_switch == uctl->value.integer.value[0]) | ||
475 | goto __out; | ||
476 | |||
477 | changed = 1; | ||
478 | mts->smpte_switch = uctl->value.integer.value[0]; | ||
479 | if (mts->smpte_switch) { | ||
480 | mts64_smpte_start(mts->pardev->port, | ||
481 | mts->time[0], mts->time[1], | ||
482 | mts->time[2], mts->time[3], | ||
483 | mts->fps); | ||
484 | } else { | ||
485 | mts64_smpte_stop(mts->pardev->port); | ||
486 | } | ||
487 | __out: | ||
488 | spin_unlock_irq(&mts->lock); | ||
489 | return changed; | ||
490 | } | ||
491 | |||
492 | static struct snd_kcontrol_new mts64_ctl_smpte_switch __devinitdata = { | ||
493 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
494 | .name = "SMPTE Playback Switch", | ||
495 | .index = 0, | ||
496 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
497 | .private_value = 0, | ||
498 | .info = snd_mts64_ctl_smpte_switch_info, | ||
499 | .get = snd_mts64_ctl_smpte_switch_get, | ||
500 | .put = snd_mts64_ctl_smpte_switch_put | ||
501 | }; | ||
502 | |||
503 | /* Time */ | ||
504 | static int snd_mts64_ctl_smpte_time_h_info(struct snd_kcontrol *kctl, | ||
505 | struct snd_ctl_elem_info *uinfo) | ||
506 | { | ||
507 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
508 | uinfo->count = 1; | ||
509 | uinfo->value.integer.min = 0; | ||
510 | uinfo->value.integer.max = 23; | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static int snd_mts64_ctl_smpte_time_f_info(struct snd_kcontrol *kctl, | ||
515 | struct snd_ctl_elem_info *uinfo) | ||
516 | { | ||
517 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
518 | uinfo->count = 1; | ||
519 | uinfo->value.integer.min = 0; | ||
520 | uinfo->value.integer.max = 99; | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int snd_mts64_ctl_smpte_time_info(struct snd_kcontrol *kctl, | ||
525 | struct snd_ctl_elem_info *uinfo) | ||
526 | { | ||
527 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
528 | uinfo->count = 1; | ||
529 | uinfo->value.integer.min = 0; | ||
530 | uinfo->value.integer.max = 59; | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static int snd_mts64_ctl_smpte_time_get(struct snd_kcontrol *kctl, | ||
535 | struct snd_ctl_elem_value *uctl) | ||
536 | { | ||
537 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
538 | int idx = kctl->private_value; | ||
539 | |||
540 | spin_lock_irq(&mts->lock); | ||
541 | uctl->value.integer.value[0] = mts->time[idx]; | ||
542 | spin_unlock_irq(&mts->lock); | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl, | ||
548 | struct snd_ctl_elem_value *uctl) | ||
549 | { | ||
550 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
551 | int idx = kctl->private_value; | ||
552 | int changed = 0; | ||
553 | |||
554 | spin_lock_irq(&mts->lock); | ||
555 | if (mts->time[idx] != uctl->value.integer.value[0]) { | ||
556 | changed = 1; | ||
557 | mts->time[idx] = uctl->value.integer.value[0]; | ||
558 | } | ||
559 | spin_unlock_irq(&mts->lock); | ||
560 | |||
561 | return changed; | ||
562 | } | ||
563 | |||
564 | static struct snd_kcontrol_new mts64_ctl_smpte_time_hours __devinitdata = { | ||
565 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
566 | .name = "SMPTE Time Hours", | ||
567 | .index = 0, | ||
568 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
569 | .private_value = 0, | ||
570 | .info = snd_mts64_ctl_smpte_time_h_info, | ||
571 | .get = snd_mts64_ctl_smpte_time_get, | ||
572 | .put = snd_mts64_ctl_smpte_time_put | ||
573 | }; | ||
574 | |||
575 | static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes __devinitdata = { | ||
576 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
577 | .name = "SMPTE Time Minutes", | ||
578 | .index = 0, | ||
579 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
580 | .private_value = 1, | ||
581 | .info = snd_mts64_ctl_smpte_time_info, | ||
582 | .get = snd_mts64_ctl_smpte_time_get, | ||
583 | .put = snd_mts64_ctl_smpte_time_put | ||
584 | }; | ||
585 | |||
586 | static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds __devinitdata = { | ||
587 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
588 | .name = "SMPTE Time Seconds", | ||
589 | .index = 0, | ||
590 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
591 | .private_value = 2, | ||
592 | .info = snd_mts64_ctl_smpte_time_info, | ||
593 | .get = snd_mts64_ctl_smpte_time_get, | ||
594 | .put = snd_mts64_ctl_smpte_time_put | ||
595 | }; | ||
596 | |||
597 | static struct snd_kcontrol_new mts64_ctl_smpte_time_frames __devinitdata = { | ||
598 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
599 | .name = "SMPTE Time Frames", | ||
600 | .index = 0, | ||
601 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
602 | .private_value = 3, | ||
603 | .info = snd_mts64_ctl_smpte_time_f_info, | ||
604 | .get = snd_mts64_ctl_smpte_time_get, | ||
605 | .put = snd_mts64_ctl_smpte_time_put | ||
606 | }; | ||
607 | |||
608 | /* FPS */ | ||
609 | static int snd_mts64_ctl_smpte_fps_info(struct snd_kcontrol *kctl, | ||
610 | struct snd_ctl_elem_info *uinfo) | ||
611 | { | ||
612 | static char *texts[5] = { "24", | ||
613 | "25", | ||
614 | "29.97", | ||
615 | "30D", | ||
616 | "30" }; | ||
617 | |||
618 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
619 | uinfo->count = 1; | ||
620 | uinfo->value.enumerated.items = 5; | ||
621 | if (uinfo->value.enumerated.item > 4) | ||
622 | uinfo->value.enumerated.item = 4; | ||
623 | strcpy(uinfo->value.enumerated.name, | ||
624 | texts[uinfo->value.enumerated.item]); | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl, | ||
630 | struct snd_ctl_elem_value *uctl) | ||
631 | { | ||
632 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
633 | |||
634 | spin_lock_irq(&mts->lock); | ||
635 | uctl->value.enumerated.item[0] = mts->fps; | ||
636 | spin_unlock_irq(&mts->lock); | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl, | ||
642 | struct snd_ctl_elem_value *uctl) | ||
643 | { | ||
644 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
645 | int changed = 0; | ||
646 | |||
647 | spin_lock_irq(&mts->lock); | ||
648 | if (mts->fps != uctl->value.enumerated.item[0]) { | ||
649 | changed = 1; | ||
650 | mts->fps = uctl->value.enumerated.item[0]; | ||
651 | } | ||
652 | spin_unlock_irq(&mts->lock); | ||
653 | |||
654 | return changed; | ||
655 | } | ||
656 | |||
657 | static struct snd_kcontrol_new mts64_ctl_smpte_fps __devinitdata = { | ||
658 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
659 | .name = "SMPTE Fps", | ||
660 | .index = 0, | ||
661 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
662 | .private_value = 0, | ||
663 | .info = snd_mts64_ctl_smpte_fps_info, | ||
664 | .get = snd_mts64_ctl_smpte_fps_get, | ||
665 | .put = snd_mts64_ctl_smpte_fps_put | ||
666 | }; | ||
667 | |||
668 | |||
669 | static int __devinit snd_mts64_ctl_create(struct snd_card *card, | ||
670 | struct mts64 *mts) | ||
671 | { | ||
672 | int err, i; | ||
673 | static struct snd_kcontrol_new *control[] = { | ||
674 | &mts64_ctl_smpte_switch, | ||
675 | &mts64_ctl_smpte_time_hours, | ||
676 | &mts64_ctl_smpte_time_minutes, | ||
677 | &mts64_ctl_smpte_time_seconds, | ||
678 | &mts64_ctl_smpte_time_frames, | ||
679 | &mts64_ctl_smpte_fps, | ||
680 | 0 }; | ||
681 | |||
682 | for (i = 0; control[i]; ++i) { | ||
683 | err = snd_ctl_add(card, snd_ctl_new1(control[i], mts)); | ||
684 | if (err < 0) { | ||
685 | snd_printd("Cannot create control: %s\n", | ||
686 | control[i]->name); | ||
687 | return err; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | /********************************************************************* | ||
695 | * Rawmidi | ||
696 | *********************************************************************/ | ||
697 | #define MTS64_MODE_INPUT_TRIGGERED 0x01 | ||
698 | |||
699 | static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream) | ||
700 | { | ||
701 | struct mts64 *mts = substream->rmidi->private_data; | ||
702 | |||
703 | if (mts->open_count == 0) { | ||
704 | /* We don't need a spinlock here, because this is just called | ||
705 | if the device has not been opened before. | ||
706 | So there aren't any IRQs from the device */ | ||
707 | mts64_device_open(mts); | ||
708 | |||
709 | msleep(50); | ||
710 | } | ||
711 | ++(mts->open_count); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream) | ||
717 | { | ||
718 | struct mts64 *mts = substream->rmidi->private_data; | ||
719 | unsigned long flags; | ||
720 | |||
721 | --(mts->open_count); | ||
722 | if (mts->open_count == 0) { | ||
723 | /* We need the spinlock_irqsave here because we can still | ||
724 | have IRQs at this point */ | ||
725 | spin_lock_irqsave(&mts->lock, flags); | ||
726 | mts64_device_close(mts); | ||
727 | spin_unlock_irqrestore(&mts->lock, flags); | ||
728 | |||
729 | msleep(500); | ||
730 | |||
731 | } else if (mts->open_count < 0) | ||
732 | mts->open_count = 0; | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static void snd_mts64_rawmidi_output_trigger(struct snd_rawmidi_substream *substream, | ||
738 | int up) | ||
739 | { | ||
740 | struct mts64 *mts = substream->rmidi->private_data; | ||
741 | u8 data; | ||
742 | unsigned long flags; | ||
743 | |||
744 | spin_lock_irqsave(&mts->lock, flags); | ||
745 | while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) { | ||
746 | mts64_write_midi(mts, data, substream->number+1); | ||
747 | snd_rawmidi_transmit_ack(substream, 1); | ||
748 | } | ||
749 | spin_unlock_irqrestore(&mts->lock, flags); | ||
750 | } | ||
751 | |||
752 | static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, | ||
753 | int up) | ||
754 | { | ||
755 | struct mts64 *mts = substream->rmidi->private_data; | ||
756 | unsigned long flags; | ||
757 | |||
758 | spin_lock_irqsave(&mts->lock, flags); | ||
759 | if (up) | ||
760 | mts->mode[substream->number] |= MTS64_MODE_INPUT_TRIGGERED; | ||
761 | else | ||
762 | mts->mode[substream->number] &= ~MTS64_MODE_INPUT_TRIGGERED; | ||
763 | |||
764 | spin_unlock_irqrestore(&mts->lock, flags); | ||
765 | } | ||
766 | |||
767 | static struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = { | ||
768 | .open = snd_mts64_rawmidi_open, | ||
769 | .close = snd_mts64_rawmidi_close, | ||
770 | .trigger = snd_mts64_rawmidi_output_trigger | ||
771 | }; | ||
772 | |||
773 | static struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = { | ||
774 | .open = snd_mts64_rawmidi_open, | ||
775 | .close = snd_mts64_rawmidi_close, | ||
776 | .trigger = snd_mts64_rawmidi_input_trigger | ||
777 | }; | ||
778 | |||
779 | /* Create and initialize the rawmidi component */ | ||
780 | static int __devinit snd_mts64_rawmidi_create(struct snd_card *card) | ||
781 | { | ||
782 | struct mts64 *mts = card->private_data; | ||
783 | struct snd_rawmidi *rmidi; | ||
784 | struct snd_rawmidi_substream *substream; | ||
785 | struct list_head *list; | ||
786 | int err; | ||
787 | |||
788 | err = snd_rawmidi_new(card, CARD_NAME, 0, | ||
789 | MTS64_NUM_OUTPUT_PORTS, | ||
790 | MTS64_NUM_INPUT_PORTS, | ||
791 | &rmidi); | ||
792 | if (err < 0) | ||
793 | return err; | ||
794 | |||
795 | rmidi->private_data = mts; | ||
796 | strcpy(rmidi->name, CARD_NAME); | ||
797 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | | ||
798 | SNDRV_RAWMIDI_INFO_INPUT | | ||
799 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
800 | |||
801 | mts->rmidi = rmidi; | ||
802 | |||
803 | /* register rawmidi ops */ | ||
804 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
805 | &snd_mts64_rawmidi_output_ops); | ||
806 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
807 | &snd_mts64_rawmidi_input_ops); | ||
808 | |||
809 | /* name substreams */ | ||
810 | /* output */ | ||
811 | list_for_each(list, | ||
812 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { | ||
813 | substream = list_entry(list, struct snd_rawmidi_substream, list); | ||
814 | sprintf(substream->name, | ||
815 | "Miditerminal %d", substream->number+1); | ||
816 | } | ||
817 | /* input */ | ||
818 | list_for_each(list, | ||
819 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { | ||
820 | substream = list_entry(list, struct snd_rawmidi_substream, list); | ||
821 | mts->midi_input_substream[substream->number] = substream; | ||
822 | switch(substream->number) { | ||
823 | case MTS64_SMPTE_SUBSTREAM: | ||
824 | strcpy(substream->name, "Miditerminal SMPTE"); | ||
825 | break; | ||
826 | default: | ||
827 | sprintf(substream->name, | ||
828 | "Miditerminal %d", substream->number+1); | ||
829 | } | ||
830 | } | ||
831 | |||
832 | /* controls */ | ||
833 | err = snd_mts64_ctl_create(card, mts); | ||
834 | |||
835 | return err; | ||
836 | } | ||
837 | |||
838 | /********************************************************************* | ||
839 | * parport stuff | ||
840 | *********************************************************************/ | ||
841 | static void snd_mts64_interrupt(int irq, void *private, struct pt_regs *r) | ||
842 | { | ||
843 | struct mts64 *mts = ((struct snd_card*)private)->private_data; | ||
844 | u16 ret; | ||
845 | u8 status, data; | ||
846 | struct snd_rawmidi_substream *substream; | ||
847 | |||
848 | spin_lock(&mts->lock); | ||
849 | ret = mts64_read(mts->pardev->port); | ||
850 | data = ret & 0x00ff; | ||
851 | status = ret >> 8; | ||
852 | |||
853 | if (status & MTS64_STAT_PORT) { | ||
854 | mts->current_midi_input_port = mts64_map_midi_input(data); | ||
855 | } else { | ||
856 | if (mts->current_midi_input_port == -1) | ||
857 | goto __out; | ||
858 | substream = mts->midi_input_substream[mts->current_midi_input_port]; | ||
859 | if (mts->mode[substream->number] & MTS64_MODE_INPUT_TRIGGERED) | ||
860 | snd_rawmidi_receive(substream, &data, 1); | ||
861 | } | ||
862 | __out: | ||
863 | spin_unlock(&mts->lock); | ||
864 | } | ||
865 | |||
866 | static int __devinit snd_mts64_probe_port(struct parport *p) | ||
867 | { | ||
868 | struct pardevice *pardev; | ||
869 | int res; | ||
870 | |||
871 | pardev = parport_register_device(p, DRIVER_NAME, | ||
872 | NULL, NULL, NULL, | ||
873 | 0, NULL); | ||
874 | if (!pardev) | ||
875 | return -EIO; | ||
876 | |||
877 | if (parport_claim(pardev)) { | ||
878 | parport_unregister_device(pardev); | ||
879 | return -EIO; | ||
880 | } | ||
881 | |||
882 | res = mts64_probe(p); | ||
883 | |||
884 | parport_release(pardev); | ||
885 | parport_unregister_device(pardev); | ||
886 | |||
887 | return res; | ||
888 | } | ||
889 | |||
890 | static void __devinit snd_mts64_attach(struct parport *p) | ||
891 | { | ||
892 | struct platform_device *device; | ||
893 | |||
894 | device = platform_device_alloc(PLATFORM_DRIVER, device_count); | ||
895 | if (!device) | ||
896 | return; | ||
897 | |||
898 | /* Temporary assignment to forward the parport */ | ||
899 | platform_set_drvdata(device, p); | ||
900 | |||
901 | if (platform_device_register(device) < 0) { | ||
902 | platform_device_put(device); | ||
903 | return; | ||
904 | } | ||
905 | |||
906 | /* Since we dont get the return value of probe | ||
907 | * We need to check if device probing succeeded or not */ | ||
908 | if (!platform_get_drvdata(device)) { | ||
909 | platform_device_unregister(device); | ||
910 | return; | ||
911 | } | ||
912 | |||
913 | /* register device in global table */ | ||
914 | platform_devices[device_count] = device; | ||
915 | device_count++; | ||
916 | } | ||
917 | |||
918 | static void snd_mts64_detach(struct parport *p) | ||
919 | { | ||
920 | /* nothing to do here */ | ||
921 | } | ||
922 | |||
923 | static struct parport_driver mts64_parport_driver = { | ||
924 | .name = "mts64", | ||
925 | .attach = snd_mts64_attach, | ||
926 | .detach = snd_mts64_detach | ||
927 | }; | ||
928 | |||
929 | /********************************************************************* | ||
930 | * platform stuff | ||
931 | *********************************************************************/ | ||
932 | static void snd_mts64_card_private_free(struct snd_card *card) | ||
933 | { | ||
934 | struct mts64 *mts = card->private_data; | ||
935 | struct pardevice *pardev = mts->pardev; | ||
936 | |||
937 | if (pardev) { | ||
938 | if (mts->pardev_claimed) | ||
939 | parport_release(pardev); | ||
940 | parport_unregister_device(pardev); | ||
941 | } | ||
942 | |||
943 | snd_mts64_free(mts); | ||
944 | } | ||
945 | |||
946 | static int __devinit snd_mts64_probe(struct platform_device *pdev) | ||
947 | { | ||
948 | struct pardevice *pardev; | ||
949 | struct parport *p; | ||
950 | int dev = pdev->id; | ||
951 | struct snd_card *card = NULL; | ||
952 | struct mts64 *mts = NULL; | ||
953 | int err; | ||
954 | |||
955 | p = platform_get_drvdata(pdev); | ||
956 | platform_set_drvdata(pdev, NULL); | ||
957 | |||
958 | if (dev >= SNDRV_CARDS) | ||
959 | return -ENODEV; | ||
960 | if (!enable[dev]) | ||
961 | return -ENOENT; | ||
962 | if ((err = snd_mts64_probe_port(p)) < 0) | ||
963 | return err; | ||
964 | |||
965 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
966 | if (card == NULL) { | ||
967 | snd_printd("Cannot create card\n"); | ||
968 | return -ENOMEM; | ||
969 | } | ||
970 | strcpy(card->driver, DRIVER_NAME); | ||
971 | strcpy(card->shortname, "ESI " CARD_NAME); | ||
972 | sprintf(card->longname, "%s at 0x%lx, irq %i", | ||
973 | card->shortname, p->base, p->irq); | ||
974 | |||
975 | pardev = parport_register_device(p, /* port */ | ||
976 | DRIVER_NAME, /* name */ | ||
977 | NULL, /* preempt */ | ||
978 | NULL, /* wakeup */ | ||
979 | snd_mts64_interrupt, /* ISR */ | ||
980 | PARPORT_DEV_EXCL, /* flags */ | ||
981 | (void *)card); /* private */ | ||
982 | if (pardev == NULL) { | ||
983 | snd_printd("Cannot register pardevice\n"); | ||
984 | err = -EIO; | ||
985 | goto __err; | ||
986 | } | ||
987 | |||
988 | if ((err = snd_mts64_create(card, pardev, &mts)) < 0) { | ||
989 | snd_printd("Cannot create main component\n"); | ||
990 | parport_unregister_device(pardev); | ||
991 | goto __err; | ||
992 | } | ||
993 | card->private_data = mts; | ||
994 | card->private_free = snd_mts64_card_private_free; | ||
995 | |||
996 | if ((err = snd_mts64_rawmidi_create(card)) < 0) { | ||
997 | snd_printd("Creating Rawmidi component failed\n"); | ||
998 | goto __err; | ||
999 | } | ||
1000 | |||
1001 | /* claim parport */ | ||
1002 | if (parport_claim(pardev)) { | ||
1003 | snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base); | ||
1004 | err = -EIO; | ||
1005 | goto __err; | ||
1006 | } | ||
1007 | mts->pardev_claimed = 1; | ||
1008 | |||
1009 | /* init device */ | ||
1010 | if ((err = mts64_device_init(p)) < 0) | ||
1011 | goto __err; | ||
1012 | |||
1013 | platform_set_drvdata(pdev, card); | ||
1014 | |||
1015 | /* At this point card will be usable */ | ||
1016 | if ((err = snd_card_register(card)) < 0) { | ||
1017 | snd_printd("Cannot register card\n"); | ||
1018 | goto __err; | ||
1019 | } | ||
1020 | |||
1021 | snd_printk("ESI Miditerminal 4140 on 0x%lx\n", p->base); | ||
1022 | return 0; | ||
1023 | |||
1024 | __err: | ||
1025 | snd_card_free(card); | ||
1026 | return err; | ||
1027 | } | ||
1028 | |||
1029 | static int snd_mts64_remove(struct platform_device *pdev) | ||
1030 | { | ||
1031 | struct snd_card *card = platform_get_drvdata(pdev); | ||
1032 | |||
1033 | if (card) | ||
1034 | snd_card_free(card); | ||
1035 | |||
1036 | return 0; | ||
1037 | } | ||
1038 | |||
1039 | |||
1040 | static struct platform_driver snd_mts64_driver = { | ||
1041 | .probe = snd_mts64_probe, | ||
1042 | .remove = snd_mts64_remove, | ||
1043 | .driver = { | ||
1044 | .name = PLATFORM_DRIVER | ||
1045 | } | ||
1046 | }; | ||
1047 | |||
1048 | /********************************************************************* | ||
1049 | * module init stuff | ||
1050 | *********************************************************************/ | ||
1051 | static void snd_mts64_unregister_all(void) | ||
1052 | { | ||
1053 | int i; | ||
1054 | |||
1055 | for (i = 0; i < SNDRV_CARDS; ++i) { | ||
1056 | if (platform_devices[i]) { | ||
1057 | platform_device_unregister(platform_devices[i]); | ||
1058 | platform_devices[i] = NULL; | ||
1059 | } | ||
1060 | } | ||
1061 | platform_driver_unregister(&snd_mts64_driver); | ||
1062 | parport_unregister_driver(&mts64_parport_driver); | ||
1063 | } | ||
1064 | |||
1065 | static int __init snd_mts64_module_init(void) | ||
1066 | { | ||
1067 | int err; | ||
1068 | |||
1069 | if ((err = platform_driver_register(&snd_mts64_driver)) < 0) | ||
1070 | return err; | ||
1071 | |||
1072 | if (parport_register_driver(&mts64_parport_driver) != 0) { | ||
1073 | platform_driver_unregister(&snd_mts64_driver); | ||
1074 | return -EIO; | ||
1075 | } | ||
1076 | |||
1077 | if (device_count == 0) { | ||
1078 | snd_mts64_unregister_all(); | ||
1079 | return -ENODEV; | ||
1080 | } | ||
1081 | |||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | static void __exit snd_mts64_module_exit(void) | ||
1086 | { | ||
1087 | snd_mts64_unregister_all(); | ||
1088 | } | ||
1089 | |||
1090 | module_init(snd_mts64_module_init); | ||
1091 | module_exit(snd_mts64_module_exit); | ||
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index e552ec34166f..1679300b7583 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c | |||
@@ -105,13 +105,13 @@ static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *fi | |||
105 | struct file *file, long long offset, int orig) | 105 | struct file *file, long long offset, int orig) |
106 | { | 106 | { |
107 | switch (orig) { | 107 | switch (orig) { |
108 | case 0: /* SEEK_SET */ | 108 | case SEEK_SET: |
109 | file->f_pos = offset; | 109 | file->f_pos = offset; |
110 | break; | 110 | break; |
111 | case 1: /* SEEK_CUR */ | 111 | case SEEK_CUR: |
112 | file->f_pos += offset; | 112 | file->f_pos += offset; |
113 | break; | 113 | break; |
114 | case 2: /* SEEK_END, offset is negative */ | 114 | case SEEK_END: /* offset is negative */ |
115 | file->f_pos = entry->size + offset; | 115 | file->f_pos = entry->size + offset; |
116 | break; | 116 | break; |
117 | default: | 117 | default: |
@@ -159,8 +159,7 @@ int snd_opl4_create_proc(struct snd_opl4 *opl4) | |||
159 | 159 | ||
160 | void snd_opl4_free_proc(struct snd_opl4 *opl4) | 160 | void snd_opl4_free_proc(struct snd_opl4 *opl4) |
161 | { | 161 | { |
162 | if (opl4->proc_entry) | 162 | snd_info_free_entry(opl4->proc_entry); |
163 | snd_info_unregister(opl4->proc_entry); | ||
164 | } | 163 | } |
165 | 164 | ||
166 | #endif /* CONFIG_PROC_FS */ | 165 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index c1d7fcdd1973..1613ed844ac6 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <sound/driver.h> | 23 | #include <sound/driver.h> |
24 | #include <sound/core.h> | 24 | #include <sound/core.h> |
25 | #include <sound/control.h> | 25 | #include <sound/control.h> |
26 | #include <sound/tlv.h> | ||
26 | #include <sound/vx_core.h> | 27 | #include <sound/vx_core.h> |
27 | #include "vx_cmd.h" | 28 | #include "vx_cmd.h" |
28 | 29 | ||
@@ -455,10 +456,13 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
455 | 456 | ||
456 | static struct snd_kcontrol_new vx_control_output_level = { | 457 | static struct snd_kcontrol_new vx_control_output_level = { |
457 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 458 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
459 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
460 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
458 | .name = "Master Playback Volume", | 461 | .name = "Master Playback Volume", |
459 | .info = vx_output_level_info, | 462 | .info = vx_output_level_info, |
460 | .get = vx_output_level_get, | 463 | .get = vx_output_level_get, |
461 | .put = vx_output_level_put, | 464 | .put = vx_output_level_put, |
465 | /* tlv will be filled later */ | ||
462 | }; | 466 | }; |
463 | 467 | ||
464 | /* | 468 | /* |
@@ -712,12 +716,17 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
712 | return 0; | 716 | return 0; |
713 | } | 717 | } |
714 | 718 | ||
719 | static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); | ||
720 | |||
715 | static struct snd_kcontrol_new vx_control_audio_gain = { | 721 | static struct snd_kcontrol_new vx_control_audio_gain = { |
716 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 722 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
723 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
724 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
717 | /* name will be filled later */ | 725 | /* name will be filled later */ |
718 | .info = vx_audio_gain_info, | 726 | .info = vx_audio_gain_info, |
719 | .get = vx_audio_gain_get, | 727 | .get = vx_audio_gain_get, |
720 | .put = vx_audio_gain_put | 728 | .put = vx_audio_gain_put, |
729 | .tlv = { .p = db_scale_audio_gain }, | ||
721 | }; | 730 | }; |
722 | static struct snd_kcontrol_new vx_control_output_switch = { | 731 | static struct snd_kcontrol_new vx_control_output_switch = { |
723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 732 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -729,9 +738,12 @@ static struct snd_kcontrol_new vx_control_output_switch = { | |||
729 | static struct snd_kcontrol_new vx_control_monitor_gain = { | 738 | static struct snd_kcontrol_new vx_control_monitor_gain = { |
730 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 739 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
731 | .name = "Monitoring Volume", | 740 | .name = "Monitoring Volume", |
741 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
742 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
732 | .info = vx_audio_gain_info, /* shared */ | 743 | .info = vx_audio_gain_info, /* shared */ |
733 | .get = vx_audio_monitor_get, | 744 | .get = vx_audio_monitor_get, |
734 | .put = vx_audio_monitor_put | 745 | .put = vx_audio_monitor_put, |
746 | .tlv = { .p = db_scale_audio_gain }, | ||
735 | }; | 747 | }; |
736 | static struct snd_kcontrol_new vx_control_monitor_switch = { | 748 | static struct snd_kcontrol_new vx_control_monitor_switch = { |
737 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 749 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -918,6 +930,7 @@ int snd_vx_mixer_new(struct vx_core *chip) | |||
918 | for (i = 0; i < chip->hw->num_outs; i++) { | 930 | for (i = 0; i < chip->hw->num_outs; i++) { |
919 | temp = vx_control_output_level; | 931 | temp = vx_control_output_level; |
920 | temp.index = i; | 932 | temp.index = i; |
933 | temp.tlv.p = chip->hw->output_level_db_scale; | ||
921 | if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) | 934 | if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) |
922 | return err; | 935 | return err; |
923 | } | 936 | } |
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index dc7cc2001b74..5da49e2eb350 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -28,12 +28,14 @@ | |||
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include <sound/control.h> | 30 | #include <sound/control.h> |
31 | #include <sound/tlv.h> | ||
31 | #include <sound/ak4xxx-adda.h> | 32 | #include <sound/ak4xxx-adda.h> |
32 | 33 | ||
33 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); | 34 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); |
34 | MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); | 35 | MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); |
35 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
36 | 37 | ||
38 | /* write the given register and save the data to the cache */ | ||
37 | void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, | 39 | void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, |
38 | unsigned char val) | 40 | unsigned char val) |
39 | { | 41 | { |
@@ -41,15 +43,7 @@ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, | |||
41 | ak->ops.write(ak, chip, reg, val); | 43 | ak->ops.write(ak, chip, reg, val); |
42 | 44 | ||
43 | /* save the data */ | 45 | /* save the data */ |
44 | if (ak->type == SND_AK4524 || ak->type == SND_AK4528) { | 46 | snd_akm4xxx_set(ak, chip, reg, val); |
45 | if ((reg != 0x04 && reg != 0x05) || (val & 0x80) == 0) | ||
46 | snd_akm4xxx_set(ak, chip, reg, val); | ||
47 | else | ||
48 | snd_akm4xxx_set_ipga(ak, chip, reg, val); | ||
49 | } else { | ||
50 | /* AK4529, or else */ | ||
51 | snd_akm4xxx_set(ak, chip, reg, val); | ||
52 | } | ||
53 | ak->ops.unlock(ak, chip); | 47 | ak->ops.unlock(ak, chip); |
54 | } | 48 | } |
55 | 49 | ||
@@ -73,12 +67,6 @@ static void ak4524_reset(struct snd_akm4xxx *ak, int state) | |||
73 | for (reg = 0x04; reg < maxreg; reg++) | 67 | for (reg = 0x04; reg < maxreg; reg++) |
74 | snd_akm4xxx_write(ak, chip, reg, | 68 | snd_akm4xxx_write(ak, chip, reg, |
75 | snd_akm4xxx_get(ak, chip, reg)); | 69 | snd_akm4xxx_get(ak, chip, reg)); |
76 | if (ak->type == SND_AK4528) | ||
77 | continue; | ||
78 | /* IPGA */ | ||
79 | for (reg = 0x04; reg < 0x06; reg++) | ||
80 | snd_akm4xxx_write(ak, chip, reg, | ||
81 | snd_akm4xxx_get_ipga(ak, chip, reg)); | ||
82 | } | 70 | } |
83 | } | 71 | } |
84 | 72 | ||
@@ -137,11 +125,48 @@ void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state) | |||
137 | case SND_AK4381: | 125 | case SND_AK4381: |
138 | ak4381_reset(ak, state); | 126 | ak4381_reset(ak, state); |
139 | break; | 127 | break; |
128 | default: | ||
129 | break; | ||
140 | } | 130 | } |
141 | } | 131 | } |
142 | 132 | ||
143 | EXPORT_SYMBOL(snd_akm4xxx_reset); | 133 | EXPORT_SYMBOL(snd_akm4xxx_reset); |
144 | 134 | ||
135 | |||
136 | /* | ||
137 | * Volume conversion table for non-linear volumes | ||
138 | * from -63.5dB (mute) to 0dB step 0.5dB | ||
139 | * | ||
140 | * Used for AK4524 input/ouput attenuation, AK4528, and | ||
141 | * AK5365 input attenuation | ||
142 | */ | ||
143 | static unsigned char vol_cvt_datt[128] = { | ||
144 | 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, | ||
145 | 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, | ||
146 | 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a, | ||
147 | 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, | ||
148 | 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, | ||
149 | 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c, | ||
150 | 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23, | ||
151 | 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d, | ||
152 | 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, | ||
153 | 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40, | ||
154 | 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a, | ||
155 | 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54, | ||
156 | 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f, | ||
157 | 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69, | ||
158 | 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73, | ||
159 | 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f, | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * dB tables | ||
164 | */ | ||
165 | static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); | ||
166 | static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); | ||
167 | static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); | ||
168 | static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); | ||
169 | |||
145 | /* | 170 | /* |
146 | * initialize all the ak4xxx chips | 171 | * initialize all the ak4xxx chips |
147 | */ | 172 | */ |
@@ -155,8 +180,6 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
155 | 0x01, 0x03, /* 1: ADC/DAC enable */ | 180 | 0x01, 0x03, /* 1: ADC/DAC enable */ |
156 | 0x04, 0x00, /* 4: ADC left muted */ | 181 | 0x04, 0x00, /* 4: ADC left muted */ |
157 | 0x05, 0x00, /* 5: ADC right muted */ | 182 | 0x05, 0x00, /* 5: ADC right muted */ |
158 | 0x04, 0x80, /* 4: ADC IPGA gain 0dB */ | ||
159 | 0x05, 0x80, /* 5: ADC IPGA gain 0dB */ | ||
160 | 0x06, 0x00, /* 6: DAC left muted */ | 183 | 0x06, 0x00, /* 6: DAC left muted */ |
161 | 0x07, 0x00, /* 7: DAC right muted */ | 184 | 0x07, 0x00, /* 7: DAC right muted */ |
162 | 0xff, 0xff | 185 | 0xff, 0xff |
@@ -238,6 +261,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
238 | int chip, num_chips; | 261 | int chip, num_chips; |
239 | unsigned char *ptr, reg, data, *inits; | 262 | unsigned char *ptr, reg, data, *inits; |
240 | 263 | ||
264 | memset(ak->images, 0, sizeof(ak->images)); | ||
265 | memset(ak->volumes, 0, sizeof(ak->volumes)); | ||
266 | |||
241 | switch (ak->type) { | 267 | switch (ak->type) { |
242 | case SND_AK4524: | 268 | case SND_AK4524: |
243 | inits = inits_ak4524; | 269 | inits = inits_ak4524; |
@@ -263,6 +289,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
263 | inits = inits_ak4381; | 289 | inits = inits_ak4381; |
264 | num_chips = ak->num_dacs / 2; | 290 | num_chips = ak->num_dacs / 2; |
265 | break; | 291 | break; |
292 | case SND_AK5365: | ||
293 | /* FIXME: any init sequence? */ | ||
294 | return; | ||
266 | default: | 295 | default: |
267 | snd_BUG(); | 296 | snd_BUG(); |
268 | return; | 297 | return; |
@@ -280,14 +309,23 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
280 | 309 | ||
281 | EXPORT_SYMBOL(snd_akm4xxx_init); | 310 | EXPORT_SYMBOL(snd_akm4xxx_init); |
282 | 311 | ||
312 | /* | ||
313 | * Mixer callbacks | ||
314 | */ | ||
315 | #define AK_IPGA (1<<20) /* including IPGA */ | ||
316 | #define AK_VOL_CVT (1<<21) /* need dB conversion */ | ||
317 | #define AK_NEEDSMSB (1<<22) /* need MSB update bit */ | ||
318 | #define AK_INVERT (1<<23) /* data is inverted */ | ||
283 | #define AK_GET_CHIP(val) (((val) >> 8) & 0xff) | 319 | #define AK_GET_CHIP(val) (((val) >> 8) & 0xff) |
284 | #define AK_GET_ADDR(val) ((val) & 0xff) | 320 | #define AK_GET_ADDR(val) ((val) & 0xff) |
285 | #define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f) | 321 | #define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f) |
322 | #define AK_GET_VOL_CVT(val) (((val) >> 21) & 1) | ||
323 | #define AK_GET_IPGA(val) (((val) >> 20) & 1) | ||
324 | #define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1) | ||
286 | #define AK_GET_INVERT(val) (((val) >> 23) & 1) | 325 | #define AK_GET_INVERT(val) (((val) >> 23) & 1) |
287 | #define AK_GET_MASK(val) (((val) >> 24) & 0xff) | 326 | #define AK_GET_MASK(val) (((val) >> 24) & 0xff) |
288 | #define AK_COMPOSE(chip,addr,shift,mask) \ | 327 | #define AK_COMPOSE(chip,addr,shift,mask) \ |
289 | (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) | 328 | (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) |
290 | #define AK_INVERT (1<<23) | ||
291 | 329 | ||
292 | static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol, | 330 | static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol, |
293 | struct snd_ctl_elem_info *uinfo) | 331 | struct snd_ctl_elem_info *uinfo) |
@@ -307,31 +345,39 @@ static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol, | |||
307 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | 345 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
308 | int chip = AK_GET_CHIP(kcontrol->private_value); | 346 | int chip = AK_GET_CHIP(kcontrol->private_value); |
309 | int addr = AK_GET_ADDR(kcontrol->private_value); | 347 | int addr = AK_GET_ADDR(kcontrol->private_value); |
310 | int invert = AK_GET_INVERT(kcontrol->private_value); | 348 | |
311 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | 349 | ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr); |
312 | unsigned char val = snd_akm4xxx_get(ak, chip, addr); | ||
313 | |||
314 | ucontrol->value.integer.value[0] = invert ? mask - val : val; | ||
315 | return 0; | 350 | return 0; |
316 | } | 351 | } |
317 | 352 | ||
318 | static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, | 353 | static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr, |
319 | struct snd_ctl_elem_value *ucontrol) | 354 | unsigned char nval) |
320 | { | 355 | { |
321 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | 356 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
322 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
323 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
324 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
325 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | 357 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); |
326 | unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); | 358 | int chip = AK_GET_CHIP(kcontrol->private_value); |
327 | int change; | ||
328 | 359 | ||
329 | if (invert) | 360 | if (snd_akm4xxx_get_vol(ak, chip, addr) == nval) |
361 | return 0; | ||
362 | |||
363 | snd_akm4xxx_set_vol(ak, chip, addr, nval); | ||
364 | if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128) | ||
365 | nval = vol_cvt_datt[nval]; | ||
366 | if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128) | ||
367 | nval++; /* need to correct + 1 since both 127 and 128 are 0dB */ | ||
368 | if (AK_GET_INVERT(kcontrol->private_value)) | ||
330 | nval = mask - nval; | 369 | nval = mask - nval; |
331 | change = snd_akm4xxx_get(ak, chip, addr) != nval; | 370 | if (AK_GET_NEEDSMSB(kcontrol->private_value)) |
332 | if (change) | 371 | nval |= 0x80; |
333 | snd_akm4xxx_write(ak, chip, addr, nval); | 372 | snd_akm4xxx_write(ak, chip, addr, nval); |
334 | return change; | 373 | return 1; |
374 | } | ||
375 | |||
376 | static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, | ||
377 | struct snd_ctl_elem_value *ucontrol) | ||
378 | { | ||
379 | return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), | ||
380 | ucontrol->value.integer.value[0]); | ||
335 | } | 381 | } |
336 | 382 | ||
337 | static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, | 383 | static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, |
@@ -352,77 +398,21 @@ static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol, | |||
352 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | 398 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
353 | int chip = AK_GET_CHIP(kcontrol->private_value); | 399 | int chip = AK_GET_CHIP(kcontrol->private_value); |
354 | int addr = AK_GET_ADDR(kcontrol->private_value); | 400 | int addr = AK_GET_ADDR(kcontrol->private_value); |
355 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
356 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
357 | unsigned char val = snd_akm4xxx_get(ak, chip, addr); | ||
358 | |||
359 | ucontrol->value.integer.value[0] = invert ? mask - val : val; | ||
360 | |||
361 | val = snd_akm4xxx_get(ak, chip, addr+1); | ||
362 | ucontrol->value.integer.value[1] = invert ? mask - val : val; | ||
363 | 401 | ||
402 | ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr); | ||
403 | ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1); | ||
364 | return 0; | 404 | return 0; |
365 | } | 405 | } |
366 | 406 | ||
367 | static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, | 407 | static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, |
368 | struct snd_ctl_elem_value *ucontrol) | 408 | struct snd_ctl_elem_value *ucontrol) |
369 | { | 409 | { |
370 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
371 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
372 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
373 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
374 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
375 | unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); | ||
376 | int change0, change1; | ||
377 | |||
378 | if (invert) | ||
379 | nval = mask - nval; | ||
380 | change0 = snd_akm4xxx_get(ak, chip, addr) != nval; | ||
381 | if (change0) | ||
382 | snd_akm4xxx_write(ak, chip, addr, nval); | ||
383 | |||
384 | nval = ucontrol->value.integer.value[1] % (mask+1); | ||
385 | if (invert) | ||
386 | nval = mask - nval; | ||
387 | change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval; | ||
388 | if (change1) | ||
389 | snd_akm4xxx_write(ak, chip, addr+1, nval); | ||
390 | |||
391 | |||
392 | return change0 || change1; | ||
393 | } | ||
394 | |||
395 | static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol, | ||
396 | struct snd_ctl_elem_info *uinfo) | ||
397 | { | ||
398 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
399 | uinfo->count = 1; | ||
400 | uinfo->value.integer.min = 0; | ||
401 | uinfo->value.integer.max = 36; | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol, | ||
406 | struct snd_ctl_elem_value *ucontrol) | ||
407 | { | ||
408 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
409 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
410 | int addr = AK_GET_ADDR(kcontrol->private_value); | 410 | int addr = AK_GET_ADDR(kcontrol->private_value); |
411 | ucontrol->value.integer.value[0] = | 411 | int change; |
412 | snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f; | ||
413 | return 0; | ||
414 | } | ||
415 | 412 | ||
416 | static int snd_akm4xxx_ipga_gain_put(struct snd_kcontrol *kcontrol, | 413 | change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]); |
417 | struct snd_ctl_elem_value *ucontrol) | 414 | change |= put_ak_reg(kcontrol, addr + 1, |
418 | { | 415 | ucontrol->value.integer.value[1]); |
419 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
420 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
421 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
422 | unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80; | ||
423 | int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval; | ||
424 | if (change) | ||
425 | snd_akm4xxx_write(ak, chip, addr, nval); | ||
426 | return change; | 416 | return change; |
427 | } | 417 | } |
428 | 418 | ||
@@ -472,179 +462,280 @@ static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol, | |||
472 | return change; | 462 | return change; |
473 | } | 463 | } |
474 | 464 | ||
465 | static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol, | ||
466 | struct snd_ctl_elem_info *uinfo) | ||
467 | { | ||
468 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
469 | uinfo->count = 1; | ||
470 | uinfo->value.integer.min = 0; | ||
471 | uinfo->value.integer.max = 1; | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol, | ||
476 | struct snd_ctl_elem_value *ucontrol) | ||
477 | { | ||
478 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
479 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
480 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
481 | int shift = AK_GET_SHIFT(kcontrol->private_value); | ||
482 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
483 | unsigned char val = snd_akm4xxx_get(ak, chip, addr); | ||
484 | |||
485 | if (invert) | ||
486 | val = ! val; | ||
487 | ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0; | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol, | ||
492 | struct snd_ctl_elem_value *ucontrol) | ||
493 | { | ||
494 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
495 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
496 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
497 | int shift = AK_GET_SHIFT(kcontrol->private_value); | ||
498 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
499 | long flag = ucontrol->value.integer.value[0]; | ||
500 | unsigned char val, oval; | ||
501 | int change; | ||
502 | |||
503 | if (invert) | ||
504 | flag = ! flag; | ||
505 | oval = snd_akm4xxx_get(ak, chip, addr); | ||
506 | if (flag) | ||
507 | val = oval | (1<<shift); | ||
508 | else | ||
509 | val = oval & ~(1<<shift); | ||
510 | change = (oval != val); | ||
511 | if (change) | ||
512 | snd_akm4xxx_write(ak, chip, addr, val); | ||
513 | return change; | ||
514 | } | ||
515 | |||
475 | /* | 516 | /* |
476 | * build AK4xxx controls | 517 | * build AK4xxx controls |
477 | */ | 518 | */ |
478 | 519 | ||
479 | int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) | 520 | static int build_dac_controls(struct snd_akm4xxx *ak) |
480 | { | 521 | { |
481 | unsigned int idx, num_emphs; | 522 | int idx, err, mixer_ch, num_stereo; |
482 | struct snd_kcontrol *ctl; | 523 | struct snd_kcontrol_new knew; |
483 | int err; | ||
484 | int mixer_ch = 0; | ||
485 | int num_stereo; | ||
486 | |||
487 | ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); | ||
488 | if (! ctl) | ||
489 | return -ENOMEM; | ||
490 | 524 | ||
525 | mixer_ch = 0; | ||
491 | for (idx = 0; idx < ak->num_dacs; ) { | 526 | for (idx = 0; idx < ak->num_dacs; ) { |
492 | memset(ctl, 0, sizeof(*ctl)); | 527 | memset(&knew, 0, sizeof(knew)); |
493 | if (ak->channel_names == NULL) { | 528 | if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) { |
494 | strcpy(ctl->id.name, "DAC Volume"); | 529 | knew.name = "DAC Volume"; |
530 | knew.index = mixer_ch + ak->idx_offset * 2; | ||
495 | num_stereo = 1; | 531 | num_stereo = 1; |
496 | ctl->id.index = mixer_ch + ak->idx_offset * 2; | ||
497 | } else { | 532 | } else { |
498 | strcpy(ctl->id.name, ak->channel_names[mixer_ch]); | 533 | knew.name = ak->dac_info[mixer_ch].name; |
499 | num_stereo = ak->num_stereo[mixer_ch]; | 534 | num_stereo = ak->dac_info[mixer_ch].num_channels; |
500 | ctl->id.index = 0; | ||
501 | } | 535 | } |
502 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 536 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
503 | ctl->count = 1; | 537 | knew.count = 1; |
538 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
539 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
504 | if (num_stereo == 2) { | 540 | if (num_stereo == 2) { |
505 | ctl->info = snd_akm4xxx_stereo_volume_info; | 541 | knew.info = snd_akm4xxx_stereo_volume_info; |
506 | ctl->get = snd_akm4xxx_stereo_volume_get; | 542 | knew.get = snd_akm4xxx_stereo_volume_get; |
507 | ctl->put = snd_akm4xxx_stereo_volume_put; | 543 | knew.put = snd_akm4xxx_stereo_volume_put; |
508 | } else { | 544 | } else { |
509 | ctl->info = snd_akm4xxx_volume_info; | 545 | knew.info = snd_akm4xxx_volume_info; |
510 | ctl->get = snd_akm4xxx_volume_get; | 546 | knew.get = snd_akm4xxx_volume_get; |
511 | ctl->put = snd_akm4xxx_volume_put; | 547 | knew.put = snd_akm4xxx_volume_put; |
512 | } | 548 | } |
513 | switch (ak->type) { | 549 | switch (ak->type) { |
514 | case SND_AK4524: | 550 | case SND_AK4524: |
515 | /* register 6 & 7 */ | 551 | /* register 6 & 7 */ |
516 | ctl->private_value = | 552 | knew.private_value = |
517 | AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); | 553 | AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) | |
554 | AK_VOL_CVT; | ||
555 | knew.tlv.p = db_scale_vol_datt; | ||
518 | break; | 556 | break; |
519 | case SND_AK4528: | 557 | case SND_AK4528: |
520 | /* register 4 & 5 */ | 558 | /* register 4 & 5 */ |
521 | ctl->private_value = | 559 | knew.private_value = |
522 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); | 560 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) | |
561 | AK_VOL_CVT; | ||
562 | knew.tlv.p = db_scale_vol_datt; | ||
523 | break; | 563 | break; |
524 | case SND_AK4529: { | 564 | case SND_AK4529: { |
525 | /* registers 2-7 and b,c */ | 565 | /* registers 2-7 and b,c */ |
526 | int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; | 566 | int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; |
527 | ctl->private_value = | 567 | knew.private_value = |
528 | AK_COMPOSE(0, val, 0, 255) | AK_INVERT; | 568 | AK_COMPOSE(0, val, 0, 255) | AK_INVERT; |
569 | knew.tlv.p = db_scale_8bit; | ||
529 | break; | 570 | break; |
530 | } | 571 | } |
531 | case SND_AK4355: | 572 | case SND_AK4355: |
532 | /* register 4-9, chip #0 only */ | 573 | /* register 4-9, chip #0 only */ |
533 | ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); | 574 | knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255); |
575 | knew.tlv.p = db_scale_8bit; | ||
534 | break; | 576 | break; |
535 | case SND_AK4358: | 577 | case SND_AK4358: { |
536 | if (idx >= 6) | 578 | /* register 4-9 and 11-12, chip #0 only */ |
537 | /* register 4-9, chip #0 only */ | 579 | int addr = idx < 6 ? idx + 4 : idx + 5; |
538 | ctl->private_value = | 580 | knew.private_value = |
539 | AK_COMPOSE(0, idx + 5, 0, 255); | 581 | AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB; |
540 | else | 582 | knew.tlv.p = db_scale_7bit; |
541 | /* register 4-9, chip #0 only */ | ||
542 | ctl->private_value = | ||
543 | AK_COMPOSE(0, idx + 4, 0, 255); | ||
544 | break; | 583 | break; |
584 | } | ||
545 | case SND_AK4381: | 585 | case SND_AK4381: |
546 | /* register 3 & 4 */ | 586 | /* register 3 & 4 */ |
547 | ctl->private_value = | 587 | knew.private_value = |
548 | AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); | 588 | AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); |
589 | knew.tlv.p = db_scale_linear; | ||
549 | break; | 590 | break; |
550 | default: | 591 | default: |
551 | err = -EINVAL; | 592 | return -EINVAL; |
552 | goto __error; | ||
553 | } | 593 | } |
554 | 594 | ||
555 | ctl->private_data = ak; | 595 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
556 | err = snd_ctl_add(ak->card, | ||
557 | snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ| | ||
558 | SNDRV_CTL_ELEM_ACCESS_WRITE)); | ||
559 | if (err < 0) | 596 | if (err < 0) |
560 | goto __error; | 597 | return err; |
561 | 598 | ||
562 | idx += num_stereo; | 599 | idx += num_stereo; |
563 | mixer_ch++; | 600 | mixer_ch++; |
564 | } | 601 | } |
565 | for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { | 602 | return 0; |
566 | memset(ctl, 0, sizeof(*ctl)); | 603 | } |
567 | strcpy(ctl->id.name, "ADC Volume"); | 604 | |
568 | ctl->id.index = idx + ak->idx_offset * 2; | 605 | static int build_adc_controls(struct snd_akm4xxx *ak) |
569 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 606 | { |
570 | ctl->count = 1; | 607 | int idx, err, mixer_ch, num_stereo; |
571 | ctl->info = snd_akm4xxx_volume_info; | 608 | struct snd_kcontrol_new knew; |
572 | ctl->get = snd_akm4xxx_volume_get; | 609 | |
573 | ctl->put = snd_akm4xxx_volume_put; | 610 | mixer_ch = 0; |
574 | /* register 4 & 5 */ | 611 | for (idx = 0; idx < ak->num_adcs;) { |
575 | ctl->private_value = | 612 | memset(&knew, 0, sizeof(knew)); |
576 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); | 613 | if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) { |
577 | ctl->private_data = ak; | 614 | knew.name = "ADC Volume"; |
578 | err = snd_ctl_add(ak->card, | 615 | knew.index = mixer_ch + ak->idx_offset * 2; |
579 | snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ| | 616 | num_stereo = 1; |
580 | SNDRV_CTL_ELEM_ACCESS_WRITE)); | 617 | } else { |
581 | if (err < 0) | 618 | knew.name = ak->adc_info[mixer_ch].name; |
582 | goto __error; | 619 | num_stereo = ak->adc_info[mixer_ch].num_channels; |
583 | 620 | } | |
584 | memset(ctl, 0, sizeof(*ctl)); | 621 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
585 | strcpy(ctl->id.name, "IPGA Analog Capture Volume"); | 622 | knew.count = 1; |
586 | ctl->id.index = idx + ak->idx_offset * 2; | 623 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
587 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 624 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; |
588 | ctl->count = 1; | 625 | if (num_stereo == 2) { |
589 | ctl->info = snd_akm4xxx_ipga_gain_info; | 626 | knew.info = snd_akm4xxx_stereo_volume_info; |
590 | ctl->get = snd_akm4xxx_ipga_gain_get; | 627 | knew.get = snd_akm4xxx_stereo_volume_get; |
591 | ctl->put = snd_akm4xxx_ipga_gain_put; | 628 | knew.put = snd_akm4xxx_stereo_volume_put; |
629 | } else { | ||
630 | knew.info = snd_akm4xxx_volume_info; | ||
631 | knew.get = snd_akm4xxx_volume_get; | ||
632 | knew.put = snd_akm4xxx_volume_put; | ||
633 | } | ||
592 | /* register 4 & 5 */ | 634 | /* register 4 & 5 */ |
593 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); | 635 | if (ak->type == SND_AK5365) |
594 | ctl->private_data = ak; | 636 | knew.private_value = |
595 | err = snd_ctl_add(ak->card, | 637 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) | |
596 | snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ| | 638 | AK_VOL_CVT | AK_IPGA; |
597 | SNDRV_CTL_ELEM_ACCESS_WRITE)); | 639 | else |
640 | knew.private_value = | ||
641 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) | | ||
642 | AK_VOL_CVT | AK_IPGA; | ||
643 | knew.tlv.p = db_scale_vol_datt; | ||
644 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | ||
598 | if (err < 0) | 645 | if (err < 0) |
599 | goto __error; | 646 | return err; |
647 | |||
648 | if (ak->type == SND_AK5365 && (idx % 2) == 0) { | ||
649 | if (! ak->adc_info || | ||
650 | ! ak->adc_info[mixer_ch].switch_name) | ||
651 | knew.name = "Capture Switch"; | ||
652 | else | ||
653 | knew.name = ak->adc_info[mixer_ch].switch_name; | ||
654 | knew.info = ak4xxx_switch_info; | ||
655 | knew.get = ak4xxx_switch_get; | ||
656 | knew.put = ak4xxx_switch_put; | ||
657 | knew.access = 0; | ||
658 | /* register 2, bit 0 (SMUTE): 0 = normal operation, | ||
659 | 1 = mute */ | ||
660 | knew.private_value = | ||
661 | AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT; | ||
662 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | ||
663 | if (err < 0) | ||
664 | return err; | ||
665 | } | ||
666 | |||
667 | idx += num_stereo; | ||
668 | mixer_ch++; | ||
600 | } | 669 | } |
601 | if (ak->type == SND_AK4355 || ak->type == SND_AK4358) | 670 | return 0; |
602 | num_emphs = 1; | 671 | } |
603 | else | 672 | |
604 | num_emphs = ak->num_dacs / 2; | 673 | static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) |
674 | { | ||
675 | int idx, err; | ||
676 | struct snd_kcontrol_new knew; | ||
677 | |||
605 | for (idx = 0; idx < num_emphs; idx++) { | 678 | for (idx = 0; idx < num_emphs; idx++) { |
606 | memset(ctl, 0, sizeof(*ctl)); | 679 | memset(&knew, 0, sizeof(knew)); |
607 | strcpy(ctl->id.name, "Deemphasis"); | 680 | knew.name = "Deemphasis"; |
608 | ctl->id.index = idx + ak->idx_offset; | 681 | knew.index = idx + ak->idx_offset; |
609 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 682 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
610 | ctl->count = 1; | 683 | knew.count = 1; |
611 | ctl->info = snd_akm4xxx_deemphasis_info; | 684 | knew.info = snd_akm4xxx_deemphasis_info; |
612 | ctl->get = snd_akm4xxx_deemphasis_get; | 685 | knew.get = snd_akm4xxx_deemphasis_get; |
613 | ctl->put = snd_akm4xxx_deemphasis_put; | 686 | knew.put = snd_akm4xxx_deemphasis_put; |
614 | switch (ak->type) { | 687 | switch (ak->type) { |
615 | case SND_AK4524: | 688 | case SND_AK4524: |
616 | case SND_AK4528: | 689 | case SND_AK4528: |
617 | /* register 3 */ | 690 | /* register 3 */ |
618 | ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); | 691 | knew.private_value = AK_COMPOSE(idx, 3, 0, 0); |
619 | break; | 692 | break; |
620 | case SND_AK4529: { | 693 | case SND_AK4529: { |
621 | int shift = idx == 3 ? 6 : (2 - idx) * 2; | 694 | int shift = idx == 3 ? 6 : (2 - idx) * 2; |
622 | /* register 8 with shift */ | 695 | /* register 8 with shift */ |
623 | ctl->private_value = AK_COMPOSE(0, 8, shift, 0); | 696 | knew.private_value = AK_COMPOSE(0, 8, shift, 0); |
624 | break; | 697 | break; |
625 | } | 698 | } |
626 | case SND_AK4355: | 699 | case SND_AK4355: |
627 | case SND_AK4358: | 700 | case SND_AK4358: |
628 | ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); | 701 | knew.private_value = AK_COMPOSE(idx, 3, 0, 0); |
629 | break; | 702 | break; |
630 | case SND_AK4381: | 703 | case SND_AK4381: |
631 | ctl->private_value = AK_COMPOSE(idx, 1, 1, 0); | 704 | knew.private_value = AK_COMPOSE(idx, 1, 1, 0); |
632 | break; | 705 | break; |
706 | default: | ||
707 | return -EINVAL; | ||
633 | } | 708 | } |
634 | ctl->private_data = ak; | 709 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
635 | err = snd_ctl_add(ak->card, | ||
636 | snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ| | ||
637 | SNDRV_CTL_ELEM_ACCESS_WRITE)); | ||
638 | if (err < 0) | 710 | if (err < 0) |
639 | goto __error; | 711 | return err; |
640 | } | 712 | } |
641 | err = 0; | 713 | return 0; |
642 | |||
643 | __error: | ||
644 | kfree(ctl); | ||
645 | return err; | ||
646 | } | 714 | } |
647 | 715 | ||
716 | int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) | ||
717 | { | ||
718 | int err, num_emphs; | ||
719 | |||
720 | err = build_dac_controls(ak); | ||
721 | if (err < 0) | ||
722 | return err; | ||
723 | |||
724 | err = build_adc_controls(ak); | ||
725 | if (err < 0) | ||
726 | return err; | ||
727 | |||
728 | if (ak->type == SND_AK4355 || ak->type == SND_AK4358) | ||
729 | num_emphs = 1; | ||
730 | else | ||
731 | num_emphs = ak->num_dacs / 2; | ||
732 | err = build_deemphasis(ak, num_emphs); | ||
733 | if (err < 0) | ||
734 | return err; | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
648 | EXPORT_SYMBOL(snd_akm4xxx_build_controls); | 739 | EXPORT_SYMBOL(snd_akm4xxx_build_controls); |
649 | 740 | ||
650 | static int __init alsa_akm4xxx_module_init(void) | 741 | static int __init alsa_akm4xxx_module_init(void) |
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 8fcf2c151823..fd9b61eda0f3 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <sound/core.h> | 26 | #include <sound/core.h> |
27 | #include <sound/tlv.h> | ||
27 | #include <sound/ad1816a.h> | 28 | #include <sound/ad1816a.h> |
28 | 29 | ||
29 | #include <asm/io.h> | 30 | #include <asm/io.h> |
@@ -765,6 +766,13 @@ static int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
765 | return change; | 766 | return change; |
766 | } | 767 | } |
767 | 768 | ||
769 | #define AD1816A_SINGLE_TLV(xname, reg, shift, mask, invert, xtlv) \ | ||
770 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
771 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
772 | .name = xname, .info = snd_ad1816a_info_single, \ | ||
773 | .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \ | ||
774 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ | ||
775 | .tlv = { .p = (xtlv) } } | ||
768 | #define AD1816A_SINGLE(xname, reg, shift, mask, invert) \ | 776 | #define AD1816A_SINGLE(xname, reg, shift, mask, invert) \ |
769 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \ | 777 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \ |
770 | .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \ | 778 | .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \ |
@@ -822,6 +830,14 @@ static int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
822 | return change; | 830 | return change; |
823 | } | 831 | } |
824 | 832 | ||
833 | #define AD1816A_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \ | ||
834 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
835 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
836 | .name = xname, .info = snd_ad1816a_info_double, \ | ||
837 | .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \ | ||
838 | .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \ | ||
839 | .tlv = { .p = (xtlv) } } | ||
840 | |||
825 | #define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ | 841 | #define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ |
826 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \ | 842 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \ |
827 | .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \ | 843 | .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \ |
@@ -890,28 +906,44 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
890 | return change; | 906 | return change; |
891 | } | 907 | } |
892 | 908 | ||
909 | static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); | ||
910 | static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | ||
911 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | ||
912 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
913 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | ||
914 | |||
893 | static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { | 915 | static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { |
894 | AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), | 916 | AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), |
895 | AD1816A_DOUBLE("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1), | 917 | AD1816A_DOUBLE_TLV("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1, |
918 | db_scale_5bit), | ||
896 | AD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1), | 919 | AD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1), |
897 | AD1816A_DOUBLE("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1), | 920 | AD1816A_DOUBLE_TLV("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1, |
921 | db_scale_6bit), | ||
898 | AD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1), | 922 | AD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1), |
899 | AD1816A_DOUBLE("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1), | 923 | AD1816A_DOUBLE_TLV("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1, |
924 | db_scale_5bit_12db_max), | ||
900 | AD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1), | 925 | AD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1), |
901 | AD1816A_DOUBLE("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1), | 926 | AD1816A_DOUBLE_TLV("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1, |
927 | db_scale_5bit_12db_max), | ||
902 | AD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1), | 928 | AD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1), |
903 | AD1816A_DOUBLE("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1), | 929 | AD1816A_DOUBLE_TLV("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1, |
930 | db_scale_5bit_12db_max), | ||
904 | AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1), | 931 | AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1), |
905 | AD1816A_DOUBLE("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1), | 932 | AD1816A_DOUBLE_TLV("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1, |
933 | db_scale_6bit), | ||
906 | AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1), | 934 | AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1), |
907 | AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1), | 935 | AD1816A_SINGLE_TLV("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1, |
936 | db_scale_5bit_12db_max), | ||
908 | AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0), | 937 | AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0), |
909 | AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1), | 938 | AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1), |
910 | AD1816A_DOUBLE("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1), | 939 | AD1816A_DOUBLE_TLV("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1, |
940 | db_scale_5bit_12db_max), | ||
911 | AD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1), | 941 | AD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1), |
912 | AD1816A_SINGLE("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1), | 942 | AD1816A_SINGLE_TLV("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1, |
943 | db_scale_4bit), | ||
913 | AD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1), | 944 | AD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1), |
914 | AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1), | 945 | AD1816A_SINGLE_TLV("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1, |
946 | db_scale_5bit), | ||
915 | { | 947 | { |
916 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 948 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
917 | .name = "Capture Source", | 949 | .name = "Capture Source", |
@@ -920,7 +952,8 @@ AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1), | |||
920 | .put = snd_ad1816a_put_mux, | 952 | .put = snd_ad1816a_put_mux, |
921 | }, | 953 | }, |
922 | AD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1), | 954 | AD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1), |
923 | AD1816A_DOUBLE("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0), | 955 | AD1816A_DOUBLE_TLV("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0, |
956 | db_scale_rec_gain), | ||
924 | AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1), | 957 | AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1), |
925 | AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0), | 958 | AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0), |
926 | }; | 959 | }; |
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index e711f87d5fd1..a6fbd5d1d62f 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include <sound/ad1848.h> | 30 | #include <sound/ad1848.h> |
31 | #include <sound/control.h> | 31 | #include <sound/control.h> |
32 | #include <sound/tlv.h> | ||
32 | #include <sound/pcm_params.h> | 33 | #include <sound/pcm_params.h> |
33 | 34 | ||
34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
@@ -118,6 +119,8 @@ void snd_ad1848_out(struct snd_ad1848 *chip, | |||
118 | #endif | 119 | #endif |
119 | } | 120 | } |
120 | 121 | ||
122 | EXPORT_SYMBOL(snd_ad1848_out); | ||
123 | |||
121 | static void snd_ad1848_dout(struct snd_ad1848 *chip, | 124 | static void snd_ad1848_dout(struct snd_ad1848 *chip, |
122 | unsigned char reg, unsigned char value) | 125 | unsigned char reg, unsigned char value) |
123 | { | 126 | { |
@@ -941,6 +944,8 @@ int snd_ad1848_create(struct snd_card *card, | |||
941 | return 0; | 944 | return 0; |
942 | } | 945 | } |
943 | 946 | ||
947 | EXPORT_SYMBOL(snd_ad1848_create); | ||
948 | |||
944 | static struct snd_pcm_ops snd_ad1848_playback_ops = { | 949 | static struct snd_pcm_ops snd_ad1848_playback_ops = { |
945 | .open = snd_ad1848_playback_open, | 950 | .open = snd_ad1848_playback_open, |
946 | .close = snd_ad1848_playback_close, | 951 | .close = snd_ad1848_playback_close, |
@@ -988,12 +993,16 @@ int snd_ad1848_pcm(struct snd_ad1848 *chip, int device, struct snd_pcm **rpcm) | |||
988 | return 0; | 993 | return 0; |
989 | } | 994 | } |
990 | 995 | ||
996 | EXPORT_SYMBOL(snd_ad1848_pcm); | ||
997 | |||
991 | const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction) | 998 | const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction) |
992 | { | 999 | { |
993 | return direction == SNDRV_PCM_STREAM_PLAYBACK ? | 1000 | return direction == SNDRV_PCM_STREAM_PLAYBACK ? |
994 | &snd_ad1848_playback_ops : &snd_ad1848_capture_ops; | 1001 | &snd_ad1848_playback_ops : &snd_ad1848_capture_ops; |
995 | } | 1002 | } |
996 | 1003 | ||
1004 | EXPORT_SYMBOL(snd_ad1848_get_pcm_ops); | ||
1005 | |||
997 | /* | 1006 | /* |
998 | * MIXER part | 1007 | * MIXER part |
999 | */ | 1008 | */ |
@@ -1171,7 +1180,8 @@ static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
1171 | 1180 | ||
1172 | /* | 1181 | /* |
1173 | */ | 1182 | */ |
1174 | int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int type, unsigned long value) | 1183 | int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, |
1184 | const struct ad1848_mix_elem *c) | ||
1175 | { | 1185 | { |
1176 | static struct snd_kcontrol_new newctls[] = { | 1186 | static struct snd_kcontrol_new newctls[] = { |
1177 | [AD1848_MIX_SINGLE] = { | 1187 | [AD1848_MIX_SINGLE] = { |
@@ -1196,32 +1206,46 @@ int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int | |||
1196 | struct snd_kcontrol *ctl; | 1206 | struct snd_kcontrol *ctl; |
1197 | int err; | 1207 | int err; |
1198 | 1208 | ||
1199 | ctl = snd_ctl_new1(&newctls[type], chip); | 1209 | ctl = snd_ctl_new1(&newctls[c->type], chip); |
1200 | if (! ctl) | 1210 | if (! ctl) |
1201 | return -ENOMEM; | 1211 | return -ENOMEM; |
1202 | strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); | 1212 | strlcpy(ctl->id.name, c->name, sizeof(ctl->id.name)); |
1203 | ctl->id.index = index; | 1213 | ctl->id.index = c->index; |
1204 | ctl->private_value = value; | 1214 | ctl->private_value = c->private_value; |
1215 | if (c->tlv) { | ||
1216 | ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
1217 | ctl->tlv.p = c->tlv; | ||
1218 | } | ||
1205 | if ((err = snd_ctl_add(chip->card, ctl)) < 0) | 1219 | if ((err = snd_ctl_add(chip->card, ctl)) < 0) |
1206 | return err; | 1220 | return err; |
1207 | return 0; | 1221 | return 0; |
1208 | } | 1222 | } |
1209 | 1223 | ||
1224 | EXPORT_SYMBOL(snd_ad1848_add_ctl_elem); | ||
1225 | |||
1226 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | ||
1227 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
1228 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | ||
1210 | 1229 | ||
1211 | static struct ad1848_mix_elem snd_ad1848_controls[] = { | 1230 | static struct ad1848_mix_elem snd_ad1848_controls[] = { |
1212 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), | 1231 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), |
1213 | AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1), | 1232 | AD1848_DOUBLE_TLV("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1, |
1233 | db_scale_6bit), | ||
1214 | AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1), | 1234 | AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1), |
1215 | AD1848_DOUBLE("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1), | 1235 | AD1848_DOUBLE_TLV("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1, |
1236 | db_scale_5bit_12db_max), | ||
1216 | AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1), | 1237 | AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1), |
1217 | AD1848_DOUBLE("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1), | 1238 | AD1848_DOUBLE_TLV("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1, |
1218 | AD1848_DOUBLE("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0), | 1239 | db_scale_5bit_12db_max), |
1240 | AD1848_DOUBLE_TLV("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0, | ||
1241 | db_scale_rec_gain), | ||
1219 | { | 1242 | { |
1220 | .name = "Capture Source", | 1243 | .name = "Capture Source", |
1221 | .type = AD1848_MIX_CAPTURE, | 1244 | .type = AD1848_MIX_CAPTURE, |
1222 | }, | 1245 | }, |
1223 | AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0), | 1246 | AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0), |
1224 | AD1848_SINGLE("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0) | 1247 | AD1848_SINGLE_TLV("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0, |
1248 | db_scale_6bit), | ||
1225 | }; | 1249 | }; |
1226 | 1250 | ||
1227 | int snd_ad1848_mixer(struct snd_ad1848 *chip) | 1251 | int snd_ad1848_mixer(struct snd_ad1848 *chip) |
@@ -1245,12 +1269,7 @@ int snd_ad1848_mixer(struct snd_ad1848 *chip) | |||
1245 | return 0; | 1269 | return 0; |
1246 | } | 1270 | } |
1247 | 1271 | ||
1248 | EXPORT_SYMBOL(snd_ad1848_out); | ||
1249 | EXPORT_SYMBOL(snd_ad1848_create); | ||
1250 | EXPORT_SYMBOL(snd_ad1848_pcm); | ||
1251 | EXPORT_SYMBOL(snd_ad1848_get_pcm_ops); | ||
1252 | EXPORT_SYMBOL(snd_ad1848_mixer); | 1272 | EXPORT_SYMBOL(snd_ad1848_mixer); |
1253 | EXPORT_SYMBOL(snd_ad1848_add_ctl); | ||
1254 | 1273 | ||
1255 | /* | 1274 | /* |
1256 | * INIT part | 1275 | * INIT part |
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 34998de9968c..85818200333f 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c | |||
@@ -2038,7 +2038,80 @@ MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver."); | |||
2038 | static struct platform_device *platform_devices[SNDRV_CARDS]; | 2038 | static struct platform_device *platform_devices[SNDRV_CARDS]; |
2039 | 2039 | ||
2040 | #ifdef CONFIG_PNP | 2040 | #ifdef CONFIG_PNP |
2041 | static int pnp_registered; | 2041 | static int pnp_registered, pnpc_registered; |
2042 | |||
2043 | static struct pnp_device_id snd_audiodrive_pnpbiosids[] = { | ||
2044 | { .id = "ESS1869" }, | ||
2045 | { .id = "" } /* end */ | ||
2046 | }; | ||
2047 | |||
2048 | MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids); | ||
2049 | |||
2050 | /* PnP main device initialization */ | ||
2051 | static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev, | ||
2052 | struct pnp_resource_table *cfg) | ||
2053 | { | ||
2054 | int err; | ||
2055 | |||
2056 | pnp_init_resource_table(cfg); | ||
2057 | if (port[dev] != SNDRV_AUTO_PORT) | ||
2058 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
2059 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
2060 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
2061 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2062 | pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2); | ||
2063 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
2064 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
2065 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
2066 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
2067 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
2068 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
2069 | if (pnp_device_is_isapnp(pdev)) { | ||
2070 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
2071 | if (err < 0) | ||
2072 | snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n"); | ||
2073 | } | ||
2074 | err = pnp_activate_dev(pdev); | ||
2075 | if (err < 0) { | ||
2076 | snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); | ||
2077 | return -EBUSY; | ||
2078 | } | ||
2079 | /* ok. hack using Vendor-Defined Card-Level registers */ | ||
2080 | /* skip csn and logdev initialization - already done in isapnp_configure */ | ||
2081 | if (pnp_device_is_isapnp(pdev)) { | ||
2082 | isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev)); | ||
2083 | isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */ | ||
2084 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2085 | isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */ | ||
2086 | isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */ | ||
2087 | isapnp_cfg_end(); | ||
2088 | } | ||
2089 | port[dev] = pnp_port_start(pdev, 0); | ||
2090 | fm_port[dev] = pnp_port_start(pdev, 1); | ||
2091 | mpu_port[dev] = pnp_port_start(pdev, 2); | ||
2092 | dma1[dev] = pnp_dma(pdev, 0); | ||
2093 | dma2[dev] = pnp_dma(pdev, 1); | ||
2094 | irq[dev] = pnp_irq(pdev, 0); | ||
2095 | snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]); | ||
2096 | snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]); | ||
2097 | return 0; | ||
2098 | } | ||
2099 | |||
2100 | static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | ||
2101 | struct pnp_dev *pdev) | ||
2102 | { | ||
2103 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
2104 | |||
2105 | if (!cfg) | ||
2106 | return -ENOMEM; | ||
2107 | acard->dev = pdev; | ||
2108 | if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { | ||
2109 | kfree(cfg); | ||
2110 | return -EBUSY; | ||
2111 | } | ||
2112 | kfree(cfg); | ||
2113 | return 0; | ||
2114 | } | ||
2042 | 2115 | ||
2043 | static struct pnp_card_device_id snd_audiodrive_pnpids[] = { | 2116 | static struct pnp_card_device_id snd_audiodrive_pnpids[] = { |
2044 | /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */ | 2117 | /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */ |
@@ -2061,13 +2134,11 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = { | |||
2061 | 2134 | ||
2062 | MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); | 2135 | MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); |
2063 | 2136 | ||
2064 | static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | 2137 | static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, |
2065 | struct pnp_card_link *card, | 2138 | struct pnp_card_link *card, |
2066 | const struct pnp_card_device_id *id) | 2139 | const struct pnp_card_device_id *id) |
2067 | { | 2140 | { |
2068 | struct pnp_dev *pdev; | ||
2069 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | 2141 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); |
2070 | int err; | ||
2071 | 2142 | ||
2072 | if (!cfg) | 2143 | if (!cfg) |
2073 | return -ENOMEM; | 2144 | return -ENOMEM; |
@@ -2082,58 +2153,16 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | |||
2082 | return -EBUSY; | 2153 | return -EBUSY; |
2083 | } | 2154 | } |
2084 | /* Control port initialization */ | 2155 | /* Control port initialization */ |
2085 | err = pnp_activate_dev(acard->devc); | 2156 | if (pnp_activate_dev(acard->devc) < 0) { |
2086 | if (err < 0) { | ||
2087 | snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); | 2157 | snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); |
2088 | kfree(cfg); | ||
2089 | return -EAGAIN; | 2158 | return -EAGAIN; |
2090 | } | 2159 | } |
2091 | snd_printdd("pnp: port=0x%llx\n", | 2160 | snd_printdd("pnp: port=0x%llx\n", |
2092 | (unsigned long long)pnp_port_start(acard->devc, 0)); | 2161 | (unsigned long long)pnp_port_start(acard->devc, 0)); |
2093 | /* PnP initialization */ | 2162 | if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { |
2094 | pdev = acard->dev; | ||
2095 | pnp_init_resource_table(cfg); | ||
2096 | if (port[dev] != SNDRV_AUTO_PORT) | ||
2097 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
2098 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
2099 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
2100 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2101 | pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2); | ||
2102 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
2103 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
2104 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
2105 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
2106 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
2107 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
2108 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
2109 | if (err < 0) | ||
2110 | snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n"); | ||
2111 | err = pnp_activate_dev(pdev); | ||
2112 | if (err < 0) { | ||
2113 | snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); | ||
2114 | kfree(cfg); | 2163 | kfree(cfg); |
2115 | return -EBUSY; | 2164 | return -EBUSY; |
2116 | } | 2165 | } |
2117 | /* ok. hack using Vendor-Defined Card-Level registers */ | ||
2118 | /* skip csn and logdev initialization - already done in isapnp_configure */ | ||
2119 | if (pnp_device_is_isapnp(pdev)) { | ||
2120 | isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev)); | ||
2121 | isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */ | ||
2122 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2123 | isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */ | ||
2124 | isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */ | ||
2125 | isapnp_cfg_end(); | ||
2126 | } else { | ||
2127 | snd_printk(KERN_ERR PFX "unable to install ISA PnP hack, expect malfunction\n"); | ||
2128 | } | ||
2129 | port[dev] = pnp_port_start(pdev, 0); | ||
2130 | fm_port[dev] = pnp_port_start(pdev, 1); | ||
2131 | mpu_port[dev] = pnp_port_start(pdev, 2); | ||
2132 | dma1[dev] = pnp_dma(pdev, 0); | ||
2133 | dma2[dev] = pnp_dma(pdev, 1); | ||
2134 | irq[dev] = pnp_irq(pdev, 0); | ||
2135 | snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]); | ||
2136 | snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]); | ||
2137 | kfree(cfg); | 2166 | kfree(cfg); |
2138 | return 0; | 2167 | return 0; |
2139 | } | 2168 | } |
@@ -2302,7 +2331,69 @@ static struct platform_driver snd_es18xx_nonpnp_driver = { | |||
2302 | #ifdef CONFIG_PNP | 2331 | #ifdef CONFIG_PNP |
2303 | static unsigned int __devinitdata es18xx_pnp_devices; | 2332 | static unsigned int __devinitdata es18xx_pnp_devices; |
2304 | 2333 | ||
2305 | static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | 2334 | static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev, |
2335 | const struct pnp_device_id *id) | ||
2336 | { | ||
2337 | static int dev; | ||
2338 | int err; | ||
2339 | struct snd_card *card; | ||
2340 | |||
2341 | if (pnp_device_is_isapnp(pdev)) | ||
2342 | return -ENOENT; /* we have another procedure - card */ | ||
2343 | for (; dev < SNDRV_CARDS; dev++) { | ||
2344 | if (enable[dev] && isapnp[dev]) | ||
2345 | break; | ||
2346 | } | ||
2347 | if (dev >= SNDRV_CARDS) | ||
2348 | return -ENODEV; | ||
2349 | |||
2350 | card = snd_es18xx_card_new(dev); | ||
2351 | if (! card) | ||
2352 | return -ENOMEM; | ||
2353 | if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) { | ||
2354 | snd_card_free(card); | ||
2355 | return err; | ||
2356 | } | ||
2357 | snd_card_set_dev(card, &pdev->dev); | ||
2358 | if ((err = snd_audiodrive_probe(card, dev)) < 0) { | ||
2359 | snd_card_free(card); | ||
2360 | return err; | ||
2361 | } | ||
2362 | pnp_set_drvdata(pdev, card); | ||
2363 | dev++; | ||
2364 | es18xx_pnp_devices++; | ||
2365 | return 0; | ||
2366 | } | ||
2367 | |||
2368 | static void __devexit snd_audiodrive_pnp_remove(struct pnp_dev * pdev) | ||
2369 | { | ||
2370 | snd_card_free(pnp_get_drvdata(pdev)); | ||
2371 | pnp_set_drvdata(pdev, NULL); | ||
2372 | } | ||
2373 | |||
2374 | #ifdef CONFIG_PM | ||
2375 | static int snd_audiodrive_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) | ||
2376 | { | ||
2377 | return snd_es18xx_suspend(pnp_get_drvdata(pdev), state); | ||
2378 | } | ||
2379 | static int snd_audiodrive_pnp_resume(struct pnp_dev *pdev) | ||
2380 | { | ||
2381 | return snd_es18xx_resume(pnp_get_drvdata(pdev)); | ||
2382 | } | ||
2383 | #endif | ||
2384 | |||
2385 | static struct pnp_driver es18xx_pnp_driver = { | ||
2386 | .name = "es18xx-pnpbios", | ||
2387 | .id_table = snd_audiodrive_pnpbiosids, | ||
2388 | .probe = snd_audiodrive_pnp_detect, | ||
2389 | .remove = __devexit_p(snd_audiodrive_pnp_remove), | ||
2390 | #ifdef CONFIG_PM | ||
2391 | .suspend = snd_audiodrive_pnp_suspend, | ||
2392 | .resume = snd_audiodrive_pnp_resume, | ||
2393 | #endif | ||
2394 | }; | ||
2395 | |||
2396 | static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard, | ||
2306 | const struct pnp_card_device_id *pid) | 2397 | const struct pnp_card_device_id *pid) |
2307 | { | 2398 | { |
2308 | static int dev; | 2399 | static int dev; |
@@ -2320,7 +2411,7 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | |||
2320 | if (! card) | 2411 | if (! card) |
2321 | return -ENOMEM; | 2412 | return -ENOMEM; |
2322 | 2413 | ||
2323 | if ((res = snd_audiodrive_pnp(dev, card->private_data, pcard, pid)) < 0) { | 2414 | if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) { |
2324 | snd_card_free(card); | 2415 | snd_card_free(card); |
2325 | return res; | 2416 | return res; |
2326 | } | 2417 | } |
@@ -2336,19 +2427,19 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | |||
2336 | return 0; | 2427 | return 0; |
2337 | } | 2428 | } |
2338 | 2429 | ||
2339 | static void __devexit snd_audiodrive_pnp_remove(struct pnp_card_link * pcard) | 2430 | static void __devexit snd_audiodrive_pnpc_remove(struct pnp_card_link * pcard) |
2340 | { | 2431 | { |
2341 | snd_card_free(pnp_get_card_drvdata(pcard)); | 2432 | snd_card_free(pnp_get_card_drvdata(pcard)); |
2342 | pnp_set_card_drvdata(pcard, NULL); | 2433 | pnp_set_card_drvdata(pcard, NULL); |
2343 | } | 2434 | } |
2344 | 2435 | ||
2345 | #ifdef CONFIG_PM | 2436 | #ifdef CONFIG_PM |
2346 | static int snd_audiodrive_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) | 2437 | static int snd_audiodrive_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state) |
2347 | { | 2438 | { |
2348 | return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state); | 2439 | return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state); |
2349 | } | 2440 | } |
2350 | 2441 | ||
2351 | static int snd_audiodrive_pnp_resume(struct pnp_card_link *pcard) | 2442 | static int snd_audiodrive_pnpc_resume(struct pnp_card_link *pcard) |
2352 | { | 2443 | { |
2353 | return snd_es18xx_resume(pnp_get_card_drvdata(pcard)); | 2444 | return snd_es18xx_resume(pnp_get_card_drvdata(pcard)); |
2354 | } | 2445 | } |
@@ -2359,11 +2450,11 @@ static struct pnp_card_driver es18xx_pnpc_driver = { | |||
2359 | .flags = PNP_DRIVER_RES_DISABLE, | 2450 | .flags = PNP_DRIVER_RES_DISABLE, |
2360 | .name = "es18xx", | 2451 | .name = "es18xx", |
2361 | .id_table = snd_audiodrive_pnpids, | 2452 | .id_table = snd_audiodrive_pnpids, |
2362 | .probe = snd_audiodrive_pnp_detect, | 2453 | .probe = snd_audiodrive_pnpc_detect, |
2363 | .remove = __devexit_p(snd_audiodrive_pnp_remove), | 2454 | .remove = __devexit_p(snd_audiodrive_pnpc_remove), |
2364 | #ifdef CONFIG_PM | 2455 | #ifdef CONFIG_PM |
2365 | .suspend = snd_audiodrive_pnp_suspend, | 2456 | .suspend = snd_audiodrive_pnpc_suspend, |
2366 | .resume = snd_audiodrive_pnp_resume, | 2457 | .resume = snd_audiodrive_pnpc_resume, |
2367 | #endif | 2458 | #endif |
2368 | }; | 2459 | }; |
2369 | #endif /* CONFIG_PNP */ | 2460 | #endif /* CONFIG_PNP */ |
@@ -2373,8 +2464,10 @@ static void __init_or_module snd_es18xx_unregister_all(void) | |||
2373 | int i; | 2464 | int i; |
2374 | 2465 | ||
2375 | #ifdef CONFIG_PNP | 2466 | #ifdef CONFIG_PNP |
2376 | if (pnp_registered) | 2467 | if (pnpc_registered) |
2377 | pnp_unregister_card_driver(&es18xx_pnpc_driver); | 2468 | pnp_unregister_card_driver(&es18xx_pnpc_driver); |
2469 | if (pnp_registered) | ||
2470 | pnp_unregister_driver(&es18xx_pnp_driver); | ||
2378 | #endif | 2471 | #endif |
2379 | for (i = 0; i < ARRAY_SIZE(platform_devices); ++i) | 2472 | for (i = 0; i < ARRAY_SIZE(platform_devices); ++i) |
2380 | platform_device_unregister(platform_devices[i]); | 2473 | platform_device_unregister(platform_devices[i]); |
@@ -2405,11 +2498,13 @@ static int __init alsa_card_es18xx_init(void) | |||
2405 | } | 2498 | } |
2406 | 2499 | ||
2407 | #ifdef CONFIG_PNP | 2500 | #ifdef CONFIG_PNP |
2408 | err = pnp_register_card_driver(&es18xx_pnpc_driver); | 2501 | err = pnp_register_driver(&es18xx_pnp_driver); |
2409 | if (!err) { | 2502 | if (!err) |
2410 | pnp_registered = 1; | 2503 | pnp_registered = 1; |
2411 | cards += es18xx_pnp_devices; | 2504 | err = pnp_register_card_driver(&es18xx_pnpc_driver); |
2412 | } | 2505 | if (!err) |
2506 | pnpc_registered = 1; | ||
2507 | cards += es18xx_pnp_devices; | ||
2413 | #endif | 2508 | #endif |
2414 | 2509 | ||
2415 | if(!cards) { | 2510 | if(!cards) { |
diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index 4080255007d5..80f0a83818b2 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c | |||
@@ -61,13 +61,13 @@ static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, | |||
61 | struct gus_proc_private *priv = entry->private_data; | 61 | struct gus_proc_private *priv = entry->private_data; |
62 | 62 | ||
63 | switch (orig) { | 63 | switch (orig) { |
64 | case 0: /* SEEK_SET */ | 64 | case SEEK_SET: |
65 | file->f_pos = offset; | 65 | file->f_pos = offset; |
66 | break; | 66 | break; |
67 | case 1: /* SEEK_CUR */ | 67 | case SEEK_CUR: |
68 | file->f_pos += offset; | 68 | file->f_pos += offset; |
69 | break; | 69 | break; |
70 | case 2: /* SEEK_END, offset is negative */ | 70 | case SEEK_END: /* offset is negative */ |
71 | file->f_pos = priv->size + offset; | 71 | file->f_pos = priv->size + offset; |
72 | break; | 72 | break; |
73 | default: | 73 | default: |
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 4031b61b797f..da92bf6c392b 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <sound/mpu401.h> | 33 | #include <sound/mpu401.h> |
34 | #include <sound/opl3.h> | 34 | #include <sound/opl3.h> |
35 | #include <sound/initval.h> | 35 | #include <sound/initval.h> |
36 | #include <sound/tlv.h> | ||
36 | 37 | ||
37 | #include <asm/io.h> | 38 | #include <asm/io.h> |
38 | 39 | ||
@@ -337,6 +338,14 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs * | |||
337 | .info = snd_opl3sa2_info_single, \ | 338 | .info = snd_opl3sa2_info_single, \ |
338 | .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ | 339 | .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ |
339 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } | 340 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } |
341 | #define OPL3SA2_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ | ||
342 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
343 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
344 | .name = xname, .index = xindex, \ | ||
345 | .info = snd_opl3sa2_info_single, \ | ||
346 | .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ | ||
347 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ | ||
348 | .tlv = { .p = (xtlv) } } | ||
340 | 349 | ||
341 | static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 350 | static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
342 | { | 351 | { |
@@ -395,6 +404,14 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
395 | .info = snd_opl3sa2_info_double, \ | 404 | .info = snd_opl3sa2_info_double, \ |
396 | .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ | 405 | .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ |
397 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } | 406 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } |
407 | #define OPL3SA2_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \ | ||
408 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
409 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
410 | .name = xname, .index = xindex, \ | ||
411 | .info = snd_opl3sa2_info_double, \ | ||
412 | .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ | ||
413 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \ | ||
414 | .tlv = { .p = (xtlv) } } | ||
398 | 415 | ||
399 | static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 416 | static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
400 | { | 417 | { |
@@ -469,11 +486,16 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
469 | return change; | 486 | return change; |
470 | } | 487 | } |
471 | 488 | ||
489 | static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0); | ||
490 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
491 | |||
472 | static struct snd_kcontrol_new snd_opl3sa2_controls[] = { | 492 | static struct snd_kcontrol_new snd_opl3sa2_controls[] = { |
473 | OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), | 493 | OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), |
474 | OPL3SA2_DOUBLE("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1), | 494 | OPL3SA2_DOUBLE_TLV("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1, |
495 | db_scale_master), | ||
475 | OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1), | 496 | OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1), |
476 | OPL3SA2_SINGLE("Mic Playback Volume", 0, 0x09, 0, 31, 1) | 497 | OPL3SA2_SINGLE_TLV("Mic Playback Volume", 0, 0x09, 0, 31, 1, |
498 | db_scale_5bit_12db_max), | ||
477 | }; | 499 | }; |
478 | 500 | ||
479 | static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = { | 501 | static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = { |
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 4359903f4376..9ae659f82430 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c | |||
@@ -347,8 +347,8 @@ int | |||
347 | setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol) | 347 | setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol) |
348 | { | 348 | { |
349 | struct device_node *np; | 349 | struct device_node *np; |
350 | u32* pp; | 350 | const u32* pp; |
351 | 351 | ||
352 | np = find_devices("gpio"); | 352 | np = find_devices("gpio"); |
353 | if (!np) | 353 | if (!np) |
354 | return -ENODEV; | 354 | return -ENODEV; |
@@ -356,7 +356,8 @@ setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* | |||
356 | np = np->child; | 356 | np = np->child; |
357 | while(np != 0) { | 357 | while(np != 0) { |
358 | if (name) { | 358 | if (name) { |
359 | char *property = get_property(np,"audio-gpio",NULL); | 359 | const char *property = |
360 | get_property(np,"audio-gpio",NULL); | ||
360 | if (property != 0 && strcmp(property,name) == 0) | 361 | if (property != 0 && strcmp(property,name) == 0) |
361 | break; | 362 | break; |
362 | } else if (compatible && device_is_compatible(np, compatible)) | 363 | } else if (compatible && device_is_compatible(np, compatible)) |
@@ -365,11 +366,11 @@ setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* | |||
365 | } | 366 | } |
366 | if (!np) | 367 | if (!np) |
367 | return -ENODEV; | 368 | return -ENODEV; |
368 | pp = (u32 *)get_property(np, "AAPL,address", NULL); | 369 | pp = get_property(np, "AAPL,address", NULL); |
369 | if (!pp) | 370 | if (!pp) |
370 | return -ENODEV; | 371 | return -ENODEV; |
371 | *gpio_addr = (*pp) & 0x0000ffff; | 372 | *gpio_addr = (*pp) & 0x0000ffff; |
372 | pp = (u32 *)get_property(np, "audio-gpio-active-state", NULL); | 373 | pp = get_property(np, "audio-gpio-active-state", NULL); |
373 | if (pp) | 374 | if (pp) |
374 | *gpio_pol = *pp; | 375 | *gpio_pol = *pp; |
375 | else | 376 | else |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e49c0fe21b0d..8a6b1803c763 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -475,6 +475,7 @@ config SND_FM801_TEA575X | |||
475 | depends on SND_FM801_TEA575X_BOOL | 475 | depends on SND_FM801_TEA575X_BOOL |
476 | default SND_FM801 | 476 | default SND_FM801 |
477 | select VIDEO_V4L1 | 477 | select VIDEO_V4L1 |
478 | select VIDEO_DEV | ||
478 | 479 | ||
479 | config SND_HDA_INTEL | 480 | config SND_HDA_INTEL |
480 | tristate "Intel HD Audio" | 481 | tristate "Intel HD Audio" |
@@ -743,4 +744,17 @@ config SND_YMFPCI | |||
743 | To compile this driver as a module, choose M here: the module | 744 | To compile this driver as a module, choose M here: the module |
744 | will be called snd-ymfpci. | 745 | will be called snd-ymfpci. |
745 | 746 | ||
747 | config SND_AC97_POWER_SAVE | ||
748 | bool "AC97 Power-Saving Mode" | ||
749 | depends on SND_AC97_CODEC && EXPERIMENTAL | ||
750 | default n | ||
751 | help | ||
752 | Say Y here to enable the aggressive power-saving support of | ||
753 | AC97 codecs. In this mode, the power-mode is dynamically | ||
754 | controlled at each open/close. | ||
755 | |||
756 | The mode is activated by passing power_save=1 option to | ||
757 | snd-ac97-codec driver. You can toggle it dynamically over | ||
758 | sysfs, too. | ||
759 | |||
746 | endmenu | 760 | endmenu |
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 51e83d7a839a..a79e91850ba3 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/tlv.h> | ||
34 | #include <sound/ac97_codec.h> | 35 | #include <sound/ac97_codec.h> |
35 | #include <sound/asoundef.h> | 36 | #include <sound/asoundef.h> |
36 | #include <sound/initval.h> | 37 | #include <sound/initval.h> |
@@ -47,6 +48,11 @@ static int enable_loopback; | |||
47 | module_param(enable_loopback, bool, 0444); | 48 | module_param(enable_loopback, bool, 0444); |
48 | MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); | 49 | MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); |
49 | 50 | ||
51 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
52 | static int power_save; | ||
53 | module_param(power_save, bool, 0644); | ||
54 | MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control"); | ||
55 | #endif | ||
50 | /* | 56 | /* |
51 | 57 | ||
52 | */ | 58 | */ |
@@ -151,7 +157,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { | |||
151 | { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk | 157 | { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk |
152 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, | 158 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, |
153 | { 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix | 159 | { 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix |
154 | { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, | 160 | { 0x50534304, 0xffffffff, "UCB1400", patch_ucb1400, NULL }, |
155 | { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, | 161 | { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, |
156 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, | 162 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, |
157 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, | 163 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, |
@@ -187,6 +193,8 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { | |||
187 | }; | 193 | }; |
188 | 194 | ||
189 | 195 | ||
196 | static void update_power_regs(struct snd_ac97 *ac97); | ||
197 | |||
190 | /* | 198 | /* |
191 | * I/O routines | 199 | * I/O routines |
192 | */ | 200 | */ |
@@ -554,6 +562,18 @@ int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
554 | } | 562 | } |
555 | err = snd_ac97_update_bits(ac97, reg, val_mask, val); | 563 | err = snd_ac97_update_bits(ac97, reg, val_mask, val); |
556 | snd_ac97_page_restore(ac97, page_save); | 564 | snd_ac97_page_restore(ac97, page_save); |
565 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
566 | /* check analog mixer power-down */ | ||
567 | if ((val_mask & 0x8000) && | ||
568 | (kcontrol->private_value & (1<<30))) { | ||
569 | if (val & 0x8000) | ||
570 | ac97->power_up &= ~(1 << (reg>>1)); | ||
571 | else | ||
572 | ac97->power_up |= 1 << (reg>>1); | ||
573 | if (power_save) | ||
574 | update_power_regs(ac97); | ||
575 | } | ||
576 | #endif | ||
557 | return err; | 577 | return err; |
558 | } | 578 | } |
559 | 579 | ||
@@ -962,6 +982,10 @@ static int snd_ac97_bus_dev_free(struct snd_device *device) | |||
962 | static int snd_ac97_free(struct snd_ac97 *ac97) | 982 | static int snd_ac97_free(struct snd_ac97 *ac97) |
963 | { | 983 | { |
964 | if (ac97) { | 984 | if (ac97) { |
985 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
986 | if (ac97->power_workq) | ||
987 | destroy_workqueue(ac97->power_workq); | ||
988 | #endif | ||
965 | snd_ac97_proc_done(ac97); | 989 | snd_ac97_proc_done(ac97); |
966 | if (ac97->bus) | 990 | if (ac97->bus) |
967 | ac97->bus->codec[ac97->num] = NULL; | 991 | ac97->bus->codec[ac97->num] = NULL; |
@@ -1117,7 +1141,9 @@ struct snd_kcontrol *snd_ac97_cnew(const struct snd_kcontrol_new *_template, str | |||
1117 | /* | 1141 | /* |
1118 | * create mute switch(es) for normal stereo controls | 1142 | * create mute switch(es) for normal stereo controls |
1119 | */ | 1143 | */ |
1120 | static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, int check_stereo, struct snd_ac97 *ac97) | 1144 | static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, |
1145 | int check_stereo, int check_amix, | ||
1146 | struct snd_ac97 *ac97) | ||
1121 | { | 1147 | { |
1122 | struct snd_kcontrol *kctl; | 1148 | struct snd_kcontrol *kctl; |
1123 | int err; | 1149 | int err; |
@@ -1137,10 +1163,14 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, | |||
1137 | } | 1163 | } |
1138 | if (mute_mask == 0x8080) { | 1164 | if (mute_mask == 0x8080) { |
1139 | struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); | 1165 | struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); |
1166 | if (check_amix) | ||
1167 | tmp.private_value |= (1 << 30); | ||
1140 | tmp.index = ac97->num; | 1168 | tmp.index = ac97->num; |
1141 | kctl = snd_ctl_new1(&tmp, ac97); | 1169 | kctl = snd_ctl_new1(&tmp, ac97); |
1142 | } else { | 1170 | } else { |
1143 | struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1); | 1171 | struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1); |
1172 | if (check_amix) | ||
1173 | tmp.private_value |= (1 << 30); | ||
1144 | tmp.index = ac97->num; | 1174 | tmp.index = ac97->num; |
1145 | kctl = snd_ctl_new1(&tmp, ac97); | 1175 | kctl = snd_ctl_new1(&tmp, ac97); |
1146 | } | 1176 | } |
@@ -1153,6 +1183,32 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, | |||
1153 | } | 1183 | } |
1154 | 1184 | ||
1155 | /* | 1185 | /* |
1186 | * set dB information | ||
1187 | */ | ||
1188 | static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); | ||
1189 | static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | ||
1190 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | ||
1191 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
1192 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | ||
1193 | |||
1194 | static unsigned int *find_db_scale(unsigned int maxval) | ||
1195 | { | ||
1196 | switch (maxval) { | ||
1197 | case 0x0f: return db_scale_4bit; | ||
1198 | case 0x1f: return db_scale_5bit; | ||
1199 | case 0x3f: return db_scale_6bit; | ||
1200 | } | ||
1201 | return NULL; | ||
1202 | } | ||
1203 | |||
1204 | static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv) | ||
1205 | { | ||
1206 | kctl->tlv.p = tlv; | ||
1207 | if (tlv) | ||
1208 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
1209 | } | ||
1210 | |||
1211 | /* | ||
1156 | * create a volume for normal stereo/mono controls | 1212 | * create a volume for normal stereo/mono controls |
1157 | */ | 1213 | */ |
1158 | static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigned int lo_max, | 1214 | static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigned int lo_max, |
@@ -1174,6 +1230,10 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne | |||
1174 | tmp.index = ac97->num; | 1230 | tmp.index = ac97->num; |
1175 | kctl = snd_ctl_new1(&tmp, ac97); | 1231 | kctl = snd_ctl_new1(&tmp, ac97); |
1176 | } | 1232 | } |
1233 | if (reg >= AC97_PHONE && reg <= AC97_PCM) | ||
1234 | set_tlv_db_scale(kctl, db_scale_5bit_12db_max); | ||
1235 | else | ||
1236 | set_tlv_db_scale(kctl, find_db_scale(lo_max)); | ||
1177 | err = snd_ctl_add(card, kctl); | 1237 | err = snd_ctl_add(card, kctl); |
1178 | if (err < 0) | 1238 | if (err < 0) |
1179 | return err; | 1239 | return err; |
@@ -1186,7 +1246,9 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne | |||
1186 | /* | 1246 | /* |
1187 | * create a mute-switch and a volume for normal stereo/mono controls | 1247 | * create a mute-switch and a volume for normal stereo/mono controls |
1188 | */ | 1248 | */ |
1189 | static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int reg, int check_stereo, struct snd_ac97 *ac97) | 1249 | static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, |
1250 | int reg, int check_stereo, int check_amix, | ||
1251 | struct snd_ac97 *ac97) | ||
1190 | { | 1252 | { |
1191 | int err; | 1253 | int err; |
1192 | char name[44]; | 1254 | char name[44]; |
@@ -1197,7 +1259,9 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int | |||
1197 | 1259 | ||
1198 | if (snd_ac97_try_bit(ac97, reg, 15)) { | 1260 | if (snd_ac97_try_bit(ac97, reg, 15)) { |
1199 | sprintf(name, "%s Switch", pfx); | 1261 | sprintf(name, "%s Switch", pfx); |
1200 | if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0) | 1262 | if ((err = snd_ac97_cmute_new_stereo(card, name, reg, |
1263 | check_stereo, check_amix, | ||
1264 | ac97)) < 0) | ||
1201 | return err; | 1265 | return err; |
1202 | } | 1266 | } |
1203 | check_volume_resolution(ac97, reg, &lo_max, &hi_max); | 1267 | check_volume_resolution(ac97, reg, &lo_max, &hi_max); |
@@ -1209,8 +1273,10 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int | |||
1209 | return 0; | 1273 | return 0; |
1210 | } | 1274 | } |
1211 | 1275 | ||
1212 | #define snd_ac97_cmix_new(card, pfx, reg, ac97) snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97) | 1276 | #define snd_ac97_cmix_new(card, pfx, reg, acheck, ac97) \ |
1213 | #define snd_ac97_cmute_new(card, name, reg, ac97) snd_ac97_cmute_new_stereo(card, name, reg, 0, ac97) | 1277 | snd_ac97_cmix_new_stereo(card, pfx, reg, 0, acheck, ac97) |
1278 | #define snd_ac97_cmute_new(card, name, reg, acheck, ac97) \ | ||
1279 | snd_ac97_cmute_new_stereo(card, name, reg, 0, acheck, ac97) | ||
1214 | 1280 | ||
1215 | static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97); | 1281 | static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97); |
1216 | 1282 | ||
@@ -1226,9 +1292,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1226 | /* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */ | 1292 | /* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */ |
1227 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) { | 1293 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) { |
1228 | if (ac97->flags & AC97_HAS_NO_MASTER_VOL) | 1294 | if (ac97->flags & AC97_HAS_NO_MASTER_VOL) |
1229 | err = snd_ac97_cmute_new(card, "Master Playback Switch", AC97_MASTER, ac97); | 1295 | err = snd_ac97_cmute_new(card, "Master Playback Switch", |
1296 | AC97_MASTER, 0, ac97); | ||
1230 | else | 1297 | else |
1231 | err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, ac97); | 1298 | err = snd_ac97_cmix_new(card, "Master Playback", |
1299 | AC97_MASTER, 0, ac97); | ||
1232 | if (err < 0) | 1300 | if (err < 0) |
1233 | return err; | 1301 | return err; |
1234 | } | 1302 | } |
@@ -1245,6 +1313,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1245 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max); | 1313 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max); |
1246 | kctl->private_value &= ~(0xff << 16); | 1314 | kctl->private_value &= ~(0xff << 16); |
1247 | kctl->private_value |= (int)max << 16; | 1315 | kctl->private_value |= (int)max << 16; |
1316 | set_tlv_db_scale(kctl, find_db_scale(max)); | ||
1248 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max); | 1317 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max); |
1249 | } | 1318 | } |
1250 | 1319 | ||
@@ -1258,6 +1327,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1258 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max); | 1327 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max); |
1259 | kctl->private_value &= ~(0xff << 16); | 1328 | kctl->private_value &= ~(0xff << 16); |
1260 | kctl->private_value |= (int)max << 16; | 1329 | kctl->private_value |= (int)max << 16; |
1330 | set_tlv_db_scale(kctl, find_db_scale(max)); | ||
1261 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8); | 1331 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8); |
1262 | } | 1332 | } |
1263 | 1333 | ||
@@ -1265,19 +1335,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1265 | if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) | 1335 | if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) |
1266 | && !(ac97->flags & AC97_AD_MULTI)) { | 1336 | && !(ac97->flags & AC97_AD_MULTI)) { |
1267 | /* Surround Master (0x38) is with stereo mutes */ | 1337 | /* Surround Master (0x38) is with stereo mutes */ |
1268 | if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0) | 1338 | if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", |
1339 | AC97_SURROUND_MASTER, 1, 0, | ||
1340 | ac97)) < 0) | ||
1269 | return err; | 1341 | return err; |
1270 | } | 1342 | } |
1271 | 1343 | ||
1272 | /* build headphone controls */ | 1344 | /* build headphone controls */ |
1273 | if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { | 1345 | if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { |
1274 | if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, ac97)) < 0) | 1346 | if ((err = snd_ac97_cmix_new(card, "Headphone Playback", |
1347 | AC97_HEADPHONE, 0, ac97)) < 0) | ||
1275 | return err; | 1348 | return err; |
1276 | } | 1349 | } |
1277 | 1350 | ||
1278 | /* build master mono controls */ | 1351 | /* build master mono controls */ |
1279 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { | 1352 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { |
1280 | if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", AC97_MASTER_MONO, ac97)) < 0) | 1353 | if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", |
1354 | AC97_MASTER_MONO, 0, ac97)) < 0) | ||
1281 | return err; | 1355 | return err; |
1282 | } | 1356 | } |
1283 | 1357 | ||
@@ -1301,8 +1375,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1301 | ((ac97->flags & AC97_HAS_PC_BEEP) || | 1375 | ((ac97->flags & AC97_HAS_PC_BEEP) || |
1302 | snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { | 1376 | snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { |
1303 | for (idx = 0; idx < 2; idx++) | 1377 | for (idx = 0; idx < 2; idx++) |
1304 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) | 1378 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) |
1305 | return err; | 1379 | return err; |
1380 | set_tlv_db_scale(kctl, db_scale_4bit); | ||
1306 | snd_ac97_write_cache(ac97, AC97_PC_BEEP, | 1381 | snd_ac97_write_cache(ac97, AC97_PC_BEEP, |
1307 | snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); | 1382 | snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); |
1308 | } | 1383 | } |
@@ -1310,7 +1385,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1310 | /* build Phone controls */ | 1385 | /* build Phone controls */ |
1311 | if (!(ac97->flags & AC97_HAS_NO_PHONE)) { | 1386 | if (!(ac97->flags & AC97_HAS_NO_PHONE)) { |
1312 | if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { | 1387 | if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { |
1313 | if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0) | 1388 | if ((err = snd_ac97_cmix_new(card, "Phone Playback", |
1389 | AC97_PHONE, 1, ac97)) < 0) | ||
1314 | return err; | 1390 | return err; |
1315 | } | 1391 | } |
1316 | } | 1392 | } |
@@ -1318,7 +1394,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1318 | /* build MIC controls */ | 1394 | /* build MIC controls */ |
1319 | if (!(ac97->flags & AC97_HAS_NO_MIC)) { | 1395 | if (!(ac97->flags & AC97_HAS_NO_MIC)) { |
1320 | if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { | 1396 | if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { |
1321 | if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0) | 1397 | if ((err = snd_ac97_cmix_new(card, "Mic Playback", |
1398 | AC97_MIC, 1, ac97)) < 0) | ||
1322 | return err; | 1399 | return err; |
1323 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) | 1400 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) |
1324 | return err; | 1401 | return err; |
@@ -1327,14 +1404,16 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1327 | 1404 | ||
1328 | /* build Line controls */ | 1405 | /* build Line controls */ |
1329 | if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { | 1406 | if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { |
1330 | if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, ac97)) < 0) | 1407 | if ((err = snd_ac97_cmix_new(card, "Line Playback", |
1408 | AC97_LINE, 1, ac97)) < 0) | ||
1331 | return err; | 1409 | return err; |
1332 | } | 1410 | } |
1333 | 1411 | ||
1334 | /* build CD controls */ | 1412 | /* build CD controls */ |
1335 | if (!(ac97->flags & AC97_HAS_NO_CD)) { | 1413 | if (!(ac97->flags & AC97_HAS_NO_CD)) { |
1336 | if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { | 1414 | if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { |
1337 | if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0) | 1415 | if ((err = snd_ac97_cmix_new(card, "CD Playback", |
1416 | AC97_CD, 1, ac97)) < 0) | ||
1338 | return err; | 1417 | return err; |
1339 | } | 1418 | } |
1340 | } | 1419 | } |
@@ -1342,7 +1421,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1342 | /* build Video controls */ | 1421 | /* build Video controls */ |
1343 | if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { | 1422 | if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { |
1344 | if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { | 1423 | if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { |
1345 | if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0) | 1424 | if ((err = snd_ac97_cmix_new(card, "Video Playback", |
1425 | AC97_VIDEO, 1, ac97)) < 0) | ||
1346 | return err; | 1426 | return err; |
1347 | } | 1427 | } |
1348 | } | 1428 | } |
@@ -1350,7 +1430,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1350 | /* build Aux controls */ | 1430 | /* build Aux controls */ |
1351 | if (!(ac97->flags & AC97_HAS_NO_AUX)) { | 1431 | if (!(ac97->flags & AC97_HAS_NO_AUX)) { |
1352 | if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { | 1432 | if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { |
1353 | if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0) | 1433 | if ((err = snd_ac97_cmix_new(card, "Aux Playback", |
1434 | AC97_AUX, 1, ac97)) < 0) | ||
1354 | return err; | 1435 | return err; |
1355 | } | 1436 | } |
1356 | } | 1437 | } |
@@ -1363,31 +1444,38 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1363 | else | 1444 | else |
1364 | init_val = 0x9f1f; | 1445 | init_val = 0x9f1f; |
1365 | for (idx = 0; idx < 2; idx++) | 1446 | for (idx = 0; idx < 2; idx++) |
1366 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) | 1447 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) |
1367 | return err; | 1448 | return err; |
1449 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1368 | ac97->spec.ad18xx.pcmreg[0] = init_val; | 1450 | ac97->spec.ad18xx.pcmreg[0] = init_val; |
1369 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { | 1451 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { |
1370 | for (idx = 0; idx < 2; idx++) | 1452 | for (idx = 0; idx < 2; idx++) |
1371 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) | 1453 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) |
1372 | return err; | 1454 | return err; |
1455 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1373 | ac97->spec.ad18xx.pcmreg[1] = init_val; | 1456 | ac97->spec.ad18xx.pcmreg[1] = init_val; |
1374 | } | 1457 | } |
1375 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { | 1458 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { |
1376 | for (idx = 0; idx < 2; idx++) | 1459 | for (idx = 0; idx < 2; idx++) |
1377 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) | 1460 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) |
1378 | return err; | 1461 | return err; |
1462 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1379 | for (idx = 0; idx < 2; idx++) | 1463 | for (idx = 0; idx < 2; idx++) |
1380 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0) | 1464 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0) |
1381 | return err; | 1465 | return err; |
1466 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1382 | ac97->spec.ad18xx.pcmreg[2] = init_val; | 1467 | ac97->spec.ad18xx.pcmreg[2] = init_val; |
1383 | } | 1468 | } |
1384 | snd_ac97_write_cache(ac97, AC97_PCM, init_val); | 1469 | snd_ac97_write_cache(ac97, AC97_PCM, init_val); |
1385 | } else { | 1470 | } else { |
1386 | if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) { | 1471 | if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) { |
1387 | if (ac97->flags & AC97_HAS_NO_PCM_VOL) | 1472 | if (ac97->flags & AC97_HAS_NO_PCM_VOL) |
1388 | err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97); | 1473 | err = snd_ac97_cmute_new(card, |
1474 | "PCM Playback Switch", | ||
1475 | AC97_PCM, 0, ac97); | ||
1389 | else | 1476 | else |
1390 | err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97); | 1477 | err = snd_ac97_cmix_new(card, "PCM Playback", |
1478 | AC97_PCM, 0, ac97); | ||
1391 | if (err < 0) | 1479 | if (err < 0) |
1392 | return err; | 1480 | return err; |
1393 | } | 1481 | } |
@@ -1398,19 +1486,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1398 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) | 1486 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) |
1399 | return err; | 1487 | return err; |
1400 | if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { | 1488 | if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { |
1401 | if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0) | 1489 | err = snd_ac97_cmute_new(card, "Capture Switch", |
1490 | AC97_REC_GAIN, 0, ac97); | ||
1491 | if (err < 0) | ||
1402 | return err; | 1492 | return err; |
1403 | } | 1493 | } |
1404 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) | 1494 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) |
1405 | return err; | 1495 | return err; |
1496 | set_tlv_db_scale(kctl, db_scale_rec_gain); | ||
1406 | snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); | 1497 | snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); |
1407 | snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); | 1498 | snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); |
1408 | } | 1499 | } |
1409 | /* build MIC Capture controls */ | 1500 | /* build MIC Capture controls */ |
1410 | if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { | 1501 | if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { |
1411 | for (idx = 0; idx < 2; idx++) | 1502 | for (idx = 0; idx < 2; idx++) |
1412 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0) | 1503 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0) |
1413 | return err; | 1504 | return err; |
1505 | set_tlv_db_scale(kctl, db_scale_rec_gain); | ||
1414 | snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000); | 1506 | snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000); |
1415 | } | 1507 | } |
1416 | 1508 | ||
@@ -1481,6 +1573,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1481 | } | 1573 | } |
1482 | 1574 | ||
1483 | /* build S/PDIF controls */ | 1575 | /* build S/PDIF controls */ |
1576 | |||
1577 | /* Hack for ASUS P5P800-VM, which does not indicate S/PDIF capability */ | ||
1578 | if (ac97->subsystem_vendor == 0x1043 && | ||
1579 | ac97->subsystem_device == 0x810f) | ||
1580 | ac97->ext_id |= AC97_EI_SPDIF; | ||
1581 | |||
1484 | if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) { | 1582 | if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) { |
1485 | if (ac97->build_ops->build_spdif) { | 1583 | if (ac97->build_ops->build_spdif) { |
1486 | if ((err = ac97->build_ops->build_spdif(ac97)) < 0) | 1584 | if ((err = ac97->build_ops->build_spdif(ac97)) < 0) |
@@ -1817,18 +1915,25 @@ static int snd_ac97_dev_register(struct snd_device *device) | |||
1817 | return 0; | 1915 | return 0; |
1818 | } | 1916 | } |
1819 | 1917 | ||
1820 | /* unregister ac97 codec */ | 1918 | /* disconnect ac97 codec */ |
1821 | static int snd_ac97_dev_unregister(struct snd_device *device) | 1919 | static int snd_ac97_dev_disconnect(struct snd_device *device) |
1822 | { | 1920 | { |
1823 | struct snd_ac97 *ac97 = device->device_data; | 1921 | struct snd_ac97 *ac97 = device->device_data; |
1824 | if (ac97->dev.bus) | 1922 | if (ac97->dev.bus) |
1825 | device_unregister(&ac97->dev); | 1923 | device_unregister(&ac97->dev); |
1826 | return snd_ac97_free(ac97); | 1924 | return 0; |
1827 | } | 1925 | } |
1828 | 1926 | ||
1829 | /* build_ops to do nothing */ | 1927 | /* build_ops to do nothing */ |
1830 | static struct snd_ac97_build_ops null_build_ops; | 1928 | static struct snd_ac97_build_ops null_build_ops; |
1831 | 1929 | ||
1930 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
1931 | static void do_update_power(void *data) | ||
1932 | { | ||
1933 | update_power_regs(data); | ||
1934 | } | ||
1935 | #endif | ||
1936 | |||
1832 | /** | 1937 | /** |
1833 | * snd_ac97_mixer - create an Codec97 component | 1938 | * snd_ac97_mixer - create an Codec97 component |
1834 | * @bus: the AC97 bus which codec is attached to | 1939 | * @bus: the AC97 bus which codec is attached to |
@@ -1860,7 +1965,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
1860 | static struct snd_device_ops ops = { | 1965 | static struct snd_device_ops ops = { |
1861 | .dev_free = snd_ac97_dev_free, | 1966 | .dev_free = snd_ac97_dev_free, |
1862 | .dev_register = snd_ac97_dev_register, | 1967 | .dev_register = snd_ac97_dev_register, |
1863 | .dev_unregister = snd_ac97_dev_unregister, | 1968 | .dev_disconnect = snd_ac97_dev_disconnect, |
1864 | }; | 1969 | }; |
1865 | 1970 | ||
1866 | snd_assert(rac97 != NULL, return -EINVAL); | 1971 | snd_assert(rac97 != NULL, return -EINVAL); |
@@ -1883,6 +1988,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
1883 | bus->codec[ac97->num] = ac97; | 1988 | bus->codec[ac97->num] = ac97; |
1884 | mutex_init(&ac97->reg_mutex); | 1989 | mutex_init(&ac97->reg_mutex); |
1885 | mutex_init(&ac97->page_mutex); | 1990 | mutex_init(&ac97->page_mutex); |
1991 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
1992 | ac97->power_workq = create_workqueue("ac97"); | ||
1993 | INIT_WORK(&ac97->power_work, do_update_power, ac97); | ||
1994 | #endif | ||
1886 | 1995 | ||
1887 | #ifdef CONFIG_PCI | 1996 | #ifdef CONFIG_PCI |
1888 | if (ac97->pci) { | 1997 | if (ac97->pci) { |
@@ -2117,15 +2226,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
2117 | return -ENOMEM; | 2226 | return -ENOMEM; |
2118 | } | 2227 | } |
2119 | } | 2228 | } |
2120 | /* make sure the proper powerdown bits are cleared */ | 2229 | if (ac97_is_audio(ac97)) |
2121 | if (ac97->scaps && ac97_is_audio(ac97)) { | 2230 | update_power_regs(ac97); |
2122 | reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); | ||
2123 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) | ||
2124 | reg &= ~AC97_EA_PRJ; | ||
2125 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) | ||
2126 | reg &= ~(AC97_EA_PRI | AC97_EA_PRK); | ||
2127 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg); | ||
2128 | } | ||
2129 | snd_ac97_proc_init(ac97); | 2231 | snd_ac97_proc_init(ac97); |
2130 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) { | 2232 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) { |
2131 | snd_ac97_free(ac97); | 2233 | snd_ac97_free(ac97); |
@@ -2153,19 +2255,152 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) | |||
2153 | snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f); | 2255 | snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f); |
2154 | } | 2256 | } |
2155 | 2257 | ||
2156 | power = ac97->regs[AC97_POWERDOWN] | 0x8000; /* EAPD */ | 2258 | /* surround, CLFE, mic powerdown */ |
2157 | power |= 0x4000; /* Headphone amplifier powerdown */ | 2259 | power = ac97->regs[AC97_EXTENDED_STATUS]; |
2158 | power |= 0x0300; /* ADC & DAC powerdown */ | 2260 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) |
2159 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2261 | power |= AC97_EA_PRJ; |
2160 | udelay(100); | 2262 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) |
2161 | power |= 0x0400; /* Analog Mixer powerdown (Vref on) */ | 2263 | power |= AC97_EA_PRI | AC97_EA_PRK; |
2264 | power |= AC97_EA_PRL; | ||
2265 | snd_ac97_write(ac97, AC97_EXTENDED_STATUS, power); | ||
2266 | |||
2267 | /* powerdown external amplifier */ | ||
2268 | if (ac97->scaps & AC97_SCAP_INV_EAPD) | ||
2269 | power = ac97->regs[AC97_POWERDOWN] & ~AC97_PD_EAPD; | ||
2270 | else if (! (ac97->scaps & AC97_SCAP_EAPD_LED)) | ||
2271 | power = ac97->regs[AC97_POWERDOWN] | AC97_PD_EAPD; | ||
2272 | power |= AC97_PD_PR6; /* Headphone amplifier powerdown */ | ||
2273 | power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */ | ||
2162 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2274 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2163 | udelay(100); | 2275 | udelay(100); |
2164 | #if 0 | 2276 | power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ |
2165 | /* FIXME: this causes click noises on some boards at resume */ | ||
2166 | power |= 0x3800; /* AC-link powerdown, internal Clk disable */ | ||
2167 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2277 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2278 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2279 | if (power_save) { | ||
2280 | udelay(100); | ||
2281 | /* AC-link powerdown, internal Clk disable */ | ||
2282 | /* FIXME: this may cause click noises on some boards */ | ||
2283 | power |= AC97_PD_PR4 | AC97_PD_PR5; | ||
2284 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | ||
2285 | } | ||
2286 | #endif | ||
2287 | } | ||
2288 | |||
2289 | |||
2290 | struct ac97_power_reg { | ||
2291 | unsigned short reg; | ||
2292 | unsigned short power_reg; | ||
2293 | unsigned short mask; | ||
2294 | }; | ||
2295 | |||
2296 | enum { PWIDX_ADC, PWIDX_FRONT, PWIDX_CLFE, PWIDX_SURR, PWIDX_MIC, PWIDX_SIZE }; | ||
2297 | |||
2298 | static struct ac97_power_reg power_regs[PWIDX_SIZE] = { | ||
2299 | [PWIDX_ADC] = { AC97_PCM_LR_ADC_RATE, AC97_POWERDOWN, AC97_PD_PR0}, | ||
2300 | [PWIDX_FRONT] = { AC97_PCM_FRONT_DAC_RATE, AC97_POWERDOWN, AC97_PD_PR1}, | ||
2301 | [PWIDX_CLFE] = { AC97_PCM_LFE_DAC_RATE, AC97_EXTENDED_STATUS, | ||
2302 | AC97_EA_PRI | AC97_EA_PRK}, | ||
2303 | [PWIDX_SURR] = { AC97_PCM_SURR_DAC_RATE, AC97_EXTENDED_STATUS, | ||
2304 | AC97_EA_PRJ}, | ||
2305 | [PWIDX_MIC] = { AC97_PCM_MIC_ADC_RATE, AC97_EXTENDED_STATUS, | ||
2306 | AC97_EA_PRL}, | ||
2307 | }; | ||
2308 | |||
2309 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2310 | /** | ||
2311 | * snd_ac97_update_power - update the powerdown register | ||
2312 | * @ac97: the codec instance | ||
2313 | * @reg: the rate register, e.g. AC97_PCM_FRONT_DAC_RATE | ||
2314 | * @powerup: non-zero when power up the part | ||
2315 | * | ||
2316 | * Update the AC97 powerdown register bits of the given part. | ||
2317 | */ | ||
2318 | int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) | ||
2319 | { | ||
2320 | int i; | ||
2321 | |||
2322 | if (! ac97) | ||
2323 | return 0; | ||
2324 | |||
2325 | if (reg) { | ||
2326 | /* SPDIF requires DAC power, too */ | ||
2327 | if (reg == AC97_SPDIF) | ||
2328 | reg = AC97_PCM_FRONT_DAC_RATE; | ||
2329 | for (i = 0; i < PWIDX_SIZE; i++) { | ||
2330 | if (power_regs[i].reg == reg) { | ||
2331 | if (powerup) | ||
2332 | ac97->power_up |= (1 << i); | ||
2333 | else | ||
2334 | ac97->power_up &= ~(1 << i); | ||
2335 | break; | ||
2336 | } | ||
2337 | } | ||
2338 | } | ||
2339 | |||
2340 | if (! power_save) | ||
2341 | return 0; | ||
2342 | |||
2343 | if (! powerup && ac97->power_workq) | ||
2344 | /* adjust power-down bits after two seconds delay | ||
2345 | * (for avoiding loud click noises for many (OSS) apps | ||
2346 | * that open/close frequently) | ||
2347 | */ | ||
2348 | queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2); | ||
2349 | else | ||
2350 | update_power_regs(ac97); | ||
2351 | |||
2352 | return 0; | ||
2353 | } | ||
2354 | |||
2355 | EXPORT_SYMBOL(snd_ac97_update_power); | ||
2356 | #endif /* CONFIG_SND_AC97_POWER_SAVE */ | ||
2357 | |||
2358 | static void update_power_regs(struct snd_ac97 *ac97) | ||
2359 | { | ||
2360 | unsigned int power_up, bits; | ||
2361 | int i; | ||
2362 | |||
2363 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2364 | if (power_save) | ||
2365 | power_up = ac97->power_up; | ||
2366 | else { | ||
2168 | #endif | 2367 | #endif |
2368 | power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); | ||
2369 | power_up |= (1 << PWIDX_MIC); | ||
2370 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) | ||
2371 | power_up |= (1 << PWIDX_SURR); | ||
2372 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) | ||
2373 | power_up |= (1 << PWIDX_CLFE); | ||
2374 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2375 | } | ||
2376 | #endif | ||
2377 | if (power_up) { | ||
2378 | if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) { | ||
2379 | /* needs power-up analog mix and vref */ | ||
2380 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2381 | AC97_PD_PR3, 0); | ||
2382 | msleep(1); | ||
2383 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2384 | AC97_PD_PR2, 0); | ||
2385 | } | ||
2386 | } | ||
2387 | for (i = 0; i < PWIDX_SIZE; i++) { | ||
2388 | if (power_up & (1 << i)) | ||
2389 | bits = 0; | ||
2390 | else | ||
2391 | bits = power_regs[i].mask; | ||
2392 | snd_ac97_update_bits(ac97, power_regs[i].power_reg, | ||
2393 | power_regs[i].mask, bits); | ||
2394 | } | ||
2395 | if (! power_up) { | ||
2396 | if (! (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2)) { | ||
2397 | /* power down analog mix and vref */ | ||
2398 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2399 | AC97_PD_PR2, AC97_PD_PR2); | ||
2400 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2401 | AC97_PD_PR3, AC97_PD_PR3); | ||
2402 | } | ||
2403 | } | ||
2169 | } | 2404 | } |
2170 | 2405 | ||
2171 | 2406 | ||
@@ -2484,6 +2719,7 @@ static int tune_mute_led(struct snd_ac97 *ac97) | |||
2484 | msw->put = master_mute_sw_put; | 2719 | msw->put = master_mute_sw_put; |
2485 | snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); | 2720 | snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); |
2486 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ | 2721 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ |
2722 | ac97->scaps |= AC97_SCAP_EAPD_LED; | ||
2487 | return 0; | 2723 | return 0; |
2488 | } | 2724 | } |
2489 | 2725 | ||
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 094cfc1f3a19..dc28b111a06d 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/control.h> | 34 | #include <sound/control.h> |
35 | #include <sound/tlv.h> | ||
35 | #include <sound/ac97_codec.h> | 36 | #include <sound/ac97_codec.h> |
36 | #include "ac97_patch.h" | 37 | #include "ac97_patch.h" |
37 | #include "ac97_id.h" | 38 | #include "ac97_id.h" |
@@ -51,6 +52,20 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro | |||
51 | return 0; | 52 | return 0; |
52 | } | 53 | } |
53 | 54 | ||
55 | /* replace with a new TLV */ | ||
56 | static void reset_tlv(struct snd_ac97 *ac97, const char *name, | ||
57 | unsigned int *tlv) | ||
58 | { | ||
59 | struct snd_ctl_elem_id sid; | ||
60 | struct snd_kcontrol *kctl; | ||
61 | memset(&sid, 0, sizeof(sid)); | ||
62 | strcpy(sid.name, name); | ||
63 | sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
64 | kctl = snd_ctl_find_id(ac97->bus->card, &sid); | ||
65 | if (kctl && kctl->tlv.p) | ||
66 | kctl->tlv.p = tlv; | ||
67 | } | ||
68 | |||
54 | /* set to the page, update bits and restore the page */ | 69 | /* set to the page, update bits and restore the page */ |
55 | static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page) | 70 | static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page) |
56 | { | 71 | { |
@@ -466,7 +481,7 @@ int patch_wolfson05(struct snd_ac97 * ac97) | |||
466 | ac97->build_ops = &patch_wolfson_wm9705_ops; | 481 | ac97->build_ops = &patch_wolfson_wm9705_ops; |
467 | #ifdef CONFIG_TOUCHSCREEN_WM9705 | 482 | #ifdef CONFIG_TOUCHSCREEN_WM9705 |
468 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ | 483 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ |
469 | ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; | 484 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; |
470 | #endif | 485 | #endif |
471 | return 0; | 486 | return 0; |
472 | } | 487 | } |
@@ -1380,6 +1395,17 @@ static void ad1888_resume(struct snd_ac97 *ac97) | |||
1380 | 1395 | ||
1381 | #endif | 1396 | #endif |
1382 | 1397 | ||
1398 | static const struct snd_ac97_res_table ad1819_restbl[] = { | ||
1399 | { AC97_PHONE, 0x9f1f }, | ||
1400 | { AC97_MIC, 0x9f1f }, | ||
1401 | { AC97_LINE, 0x9f1f }, | ||
1402 | { AC97_CD, 0x9f1f }, | ||
1403 | { AC97_VIDEO, 0x9f1f }, | ||
1404 | { AC97_AUX, 0x9f1f }, | ||
1405 | { AC97_PCM, 0x9f1f }, | ||
1406 | { } /* terminator */ | ||
1407 | }; | ||
1408 | |||
1383 | int patch_ad1819(struct snd_ac97 * ac97) | 1409 | int patch_ad1819(struct snd_ac97 * ac97) |
1384 | { | 1410 | { |
1385 | unsigned short scfg; | 1411 | unsigned short scfg; |
@@ -1387,6 +1413,7 @@ int patch_ad1819(struct snd_ac97 * ac97) | |||
1387 | // patch for Analog Devices | 1413 | // patch for Analog Devices |
1388 | scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); | 1414 | scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); |
1389 | snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */ | 1415 | snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */ |
1416 | ac97->res_table = ad1819_restbl; | ||
1390 | return 0; | 1417 | return 0; |
1391 | } | 1418 | } |
1392 | 1419 | ||
@@ -1522,12 +1549,16 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = { | |||
1522 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ | 1549 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ |
1523 | }; | 1550 | }; |
1524 | 1551 | ||
1552 | static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); | ||
1553 | |||
1525 | static int patch_ad1885_specific(struct snd_ac97 * ac97) | 1554 | static int patch_ad1885_specific(struct snd_ac97 * ac97) |
1526 | { | 1555 | { |
1527 | int err; | 1556 | int err; |
1528 | 1557 | ||
1529 | if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) | 1558 | if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) |
1530 | return err; | 1559 | return err; |
1560 | reset_tlv(ac97, "Headphone Playback Volume", | ||
1561 | db_scale_6bit_6db_max); | ||
1531 | return 0; | 1562 | return 0; |
1532 | } | 1563 | } |
1533 | 1564 | ||
@@ -1551,12 +1582,27 @@ int patch_ad1885(struct snd_ac97 * ac97) | |||
1551 | return 0; | 1582 | return 0; |
1552 | } | 1583 | } |
1553 | 1584 | ||
1585 | static int patch_ad1886_specific(struct snd_ac97 * ac97) | ||
1586 | { | ||
1587 | reset_tlv(ac97, "Headphone Playback Volume", | ||
1588 | db_scale_6bit_6db_max); | ||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | static struct snd_ac97_build_ops patch_ad1886_build_ops = { | ||
1593 | .build_specific = &patch_ad1886_specific, | ||
1594 | #ifdef CONFIG_PM | ||
1595 | .resume = ad18xx_resume | ||
1596 | #endif | ||
1597 | }; | ||
1598 | |||
1554 | int patch_ad1886(struct snd_ac97 * ac97) | 1599 | int patch_ad1886(struct snd_ac97 * ac97) |
1555 | { | 1600 | { |
1556 | patch_ad1881(ac97); | 1601 | patch_ad1881(ac97); |
1557 | /* Presario700 workaround */ | 1602 | /* Presario700 workaround */ |
1558 | /* for Jack Sense/SPDIF Register misetting causing */ | 1603 | /* for Jack Sense/SPDIF Register misetting causing */ |
1559 | snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010); | 1604 | snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010); |
1605 | ac97->build_ops = &patch_ad1886_build_ops; | ||
1560 | return 0; | 1606 | return 0; |
1561 | } | 1607 | } |
1562 | 1608 | ||
@@ -2015,6 +2061,8 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = { | |||
2015 | /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ | 2061 | /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ |
2016 | }; | 2062 | }; |
2017 | 2063 | ||
2064 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); | ||
2065 | |||
2018 | static int patch_alc650_specific(struct snd_ac97 * ac97) | 2066 | static int patch_alc650_specific(struct snd_ac97 * ac97) |
2019 | { | 2067 | { |
2020 | int err; | 2068 | int err; |
@@ -2025,6 +2073,9 @@ static int patch_alc650_specific(struct snd_ac97 * ac97) | |||
2025 | if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) | 2073 | if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) |
2026 | return err; | 2074 | return err; |
2027 | } | 2075 | } |
2076 | if (ac97->id != AC97_ID_ALC650F) | ||
2077 | reset_tlv(ac97, "Master Playback Volume", | ||
2078 | db_scale_5bit_3db_max); | ||
2028 | return 0; | 2079 | return 0; |
2029 | } | 2080 | } |
2030 | 2081 | ||
@@ -2208,7 +2259,8 @@ int patch_alc655(struct snd_ac97 * ac97) | |||
2208 | val &= ~(1 << 1); /* Pin 47 is spdif input pin */ | 2259 | val &= ~(1 << 1); /* Pin 47 is spdif input pin */ |
2209 | else { /* ALC655 */ | 2260 | else { /* ALC655 */ |
2210 | if (ac97->subsystem_vendor == 0x1462 && | 2261 | if (ac97->subsystem_vendor == 0x1462 && |
2211 | ac97->subsystem_device == 0x0131) /* MSI S270 laptop */ | 2262 | (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */ |
2263 | ac97->subsystem_device == 0x0161)) /* LG K1 Express */ | ||
2212 | val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ | 2264 | val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ |
2213 | else | 2265 | else |
2214 | val |= (1 << 1); /* Pin 47 is spdif input pin */ | 2266 | val |= (1 << 1); /* Pin 47 is spdif input pin */ |
@@ -2759,6 +2811,10 @@ int patch_vt1616(struct snd_ac97 * ac97) | |||
2759 | */ | 2811 | */ |
2760 | int patch_vt1617a(struct snd_ac97 * ac97) | 2812 | int patch_vt1617a(struct snd_ac97 * ac97) |
2761 | { | 2813 | { |
2814 | /* bring analog power consumption to normal, like WinXP driver | ||
2815 | * for EPIA SP | ||
2816 | */ | ||
2817 | snd_ac97_write_cache(ac97, 0x5c, 0x20); | ||
2762 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ | 2818 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ |
2763 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; | 2819 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; |
2764 | return 0; | 2820 | return 0; |
@@ -2872,3 +2928,41 @@ int patch_lm4550(struct snd_ac97 *ac97) | |||
2872 | ac97->res_table = lm4550_restbl; | 2928 | ac97->res_table = lm4550_restbl; |
2873 | return 0; | 2929 | return 0; |
2874 | } | 2930 | } |
2931 | |||
2932 | /* | ||
2933 | * UCB1400 codec (http://www.semiconductors.philips.com/acrobat_download/datasheets/UCB1400-02.pdf) | ||
2934 | */ | ||
2935 | static const struct snd_kcontrol_new snd_ac97_controls_ucb1400[] = { | ||
2936 | /* enable/disable headphone driver which allows direct connection to | ||
2937 | stereo headphone without the use of external DC blocking | ||
2938 | capacitors */ | ||
2939 | AC97_SINGLE("Headphone Driver", 0x6a, 6, 1, 0), | ||
2940 | /* Filter used to compensate the DC offset is added in the ADC to remove idle | ||
2941 | tones from the audio band. */ | ||
2942 | AC97_SINGLE("DC Filter", 0x6a, 4, 1, 0), | ||
2943 | /* Control smart-low-power mode feature. Allows automatic power down | ||
2944 | of unused blocks in the ADC analog front end and the PLL. */ | ||
2945 | AC97_SINGLE("Smart Low Power Mode", 0x6c, 4, 3, 0), | ||
2946 | }; | ||
2947 | |||
2948 | static int patch_ucb1400_specific(struct snd_ac97 * ac97) | ||
2949 | { | ||
2950 | int idx, err; | ||
2951 | for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++) | ||
2952 | if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97))) < 0) | ||
2953 | return err; | ||
2954 | return 0; | ||
2955 | } | ||
2956 | |||
2957 | static struct snd_ac97_build_ops patch_ucb1400_ops = { | ||
2958 | .build_specific = patch_ucb1400_specific, | ||
2959 | }; | ||
2960 | |||
2961 | int patch_ucb1400(struct snd_ac97 * ac97) | ||
2962 | { | ||
2963 | ac97->build_ops = &patch_ucb1400_ops; | ||
2964 | /* enable headphone driver and smart low power mode by default */ | ||
2965 | snd_ac97_write(ac97, 0x6a, 0x0050); | ||
2966 | snd_ac97_write(ac97, 0x6c, 0x0030); | ||
2967 | return 0; | ||
2968 | } | ||
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index adcaa04586cb..741979217207 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h | |||
@@ -58,5 +58,6 @@ int patch_cm9780(struct snd_ac97 * ac97); | |||
58 | int patch_vt1616(struct snd_ac97 * ac97); | 58 | int patch_vt1616(struct snd_ac97 * ac97); |
59 | int patch_vt1617a(struct snd_ac97 * ac97); | 59 | int patch_vt1617a(struct snd_ac97 * ac97); |
60 | int patch_it2646(struct snd_ac97 * ac97); | 60 | int patch_it2646(struct snd_ac97 * ac97); |
61 | int patch_ucb1400(struct snd_ac97 * ac97); | ||
61 | int mpatch_si3036(struct snd_ac97 * ac97); | 62 | int mpatch_si3036(struct snd_ac97 * ac97); |
62 | int patch_lm4550(struct snd_ac97 * ac97); | 63 | int patch_lm4550(struct snd_ac97 * ac97); |
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index f684aa2c0067..3758d07182f8 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c | |||
@@ -269,6 +269,7 @@ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate) | |||
269 | return -EINVAL; | 269 | return -EINVAL; |
270 | } | 270 | } |
271 | 271 | ||
272 | snd_ac97_update_power(ac97, reg, 1); | ||
272 | switch (reg) { | 273 | switch (reg) { |
273 | case AC97_PCM_MIC_ADC_RATE: | 274 | case AC97_PCM_MIC_ADC_RATE: |
274 | if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ | 275 | if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ |
@@ -606,6 +607,7 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, | |||
606 | goto error; | 607 | goto error; |
607 | } | 608 | } |
608 | } | 609 | } |
610 | pcm->cur_dbl = r; | ||
609 | spin_unlock_irq(&pcm->bus->bus_lock); | 611 | spin_unlock_irq(&pcm->bus->bus_lock); |
610 | for (i = 3; i < 12; i++) { | 612 | for (i = 3; i < 12; i++) { |
611 | if (!(slots & (1 << i))) | 613 | if (!(slots & (1 << i))) |
@@ -651,6 +653,21 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) | |||
651 | unsigned short slots = pcm->aslots; | 653 | unsigned short slots = pcm->aslots; |
652 | int i, cidx; | 654 | int i, cidx; |
653 | 655 | ||
656 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
657 | int r = pcm->cur_dbl; | ||
658 | for (i = 3; i < 12; i++) { | ||
659 | if (!(slots & (1 << i))) | ||
660 | continue; | ||
661 | for (cidx = 0; cidx < 4; cidx++) { | ||
662 | if (pcm->r[r].rslots[cidx] & (1 << i)) { | ||
663 | int reg = get_slot_reg(pcm, cidx, i, r); | ||
664 | snd_ac97_update_power(pcm->r[r].codec[cidx], | ||
665 | reg, 0); | ||
666 | } | ||
667 | } | ||
668 | } | ||
669 | #endif | ||
670 | |||
654 | bus = pcm->bus; | 671 | bus = pcm->bus; |
655 | spin_lock_irq(&pcm->bus->bus_lock); | 672 | spin_lock_irq(&pcm->bus->bus_lock); |
656 | for (i = 3; i < 12; i++) { | 673 | for (i = 3; i < 12; i++) { |
@@ -660,6 +677,7 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) | |||
660 | bus->used_slots[pcm->stream][cidx] &= ~(1 << i); | 677 | bus->used_slots[pcm->stream][cidx] &= ~(1 << i); |
661 | } | 678 | } |
662 | pcm->aslots = 0; | 679 | pcm->aslots = 0; |
680 | pcm->cur_dbl = 0; | ||
663 | spin_unlock_irq(&pcm->bus->bus_lock); | 681 | spin_unlock_irq(&pcm->bus->bus_lock); |
664 | return 0; | 682 | return 0; |
665 | } | 683 | } |
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 2118df50b9d6..a3fdd7da911c 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c | |||
@@ -457,14 +457,10 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) | |||
457 | 457 | ||
458 | void snd_ac97_proc_done(struct snd_ac97 * ac97) | 458 | void snd_ac97_proc_done(struct snd_ac97 * ac97) |
459 | { | 459 | { |
460 | if (ac97->proc_regs) { | 460 | snd_info_free_entry(ac97->proc_regs); |
461 | snd_info_unregister(ac97->proc_regs); | 461 | ac97->proc_regs = NULL; |
462 | ac97->proc_regs = NULL; | 462 | snd_info_free_entry(ac97->proc); |
463 | } | 463 | ac97->proc = NULL; |
464 | if (ac97->proc) { | ||
465 | snd_info_unregister(ac97->proc); | ||
466 | ac97->proc = NULL; | ||
467 | } | ||
468 | } | 464 | } |
469 | 465 | ||
470 | void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) | 466 | void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) |
@@ -485,8 +481,6 @@ void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) | |||
485 | 481 | ||
486 | void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus) | 482 | void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus) |
487 | { | 483 | { |
488 | if (bus->proc) { | 484 | snd_info_free_entry(bus->proc); |
489 | snd_info_unregister(bus->proc); | 485 | bus->proc = NULL; |
490 | bus->proc = NULL; | ||
491 | } | ||
492 | } | 486 | } |
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index 94c26ec05882..c153cb79c518 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <sound/core.h> | 28 | #include <sound/core.h> |
29 | #include <sound/ak4531_codec.h> | 29 | #include <sound/ak4531_codec.h> |
30 | #include <sound/tlv.h> | ||
30 | 31 | ||
31 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | 32 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); |
32 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); | 33 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); |
@@ -63,6 +64,14 @@ static void snd_ak4531_dump(struct snd_ak4531 *ak4531) | |||
63 | .info = snd_ak4531_info_single, \ | 64 | .info = snd_ak4531_info_single, \ |
64 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ | 65 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ |
65 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) } | 66 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) } |
67 | #define AK4531_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ | ||
68 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
69 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
70 | .name = xname, .index = xindex, \ | ||
71 | .info = snd_ak4531_info_single, \ | ||
72 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ | ||
73 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22), \ | ||
74 | .tlv = { .p = (xtlv) } } | ||
66 | 75 | ||
67 | static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 76 | static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
68 | { | 77 | { |
@@ -122,6 +131,14 @@ static int snd_ak4531_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
122 | .info = snd_ak4531_info_double, \ | 131 | .info = snd_ak4531_info_double, \ |
123 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ | 132 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ |
124 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) } | 133 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) } |
134 | #define AK4531_DOUBLE_TLV(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert, xtlv) \ | ||
135 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
136 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
137 | .name = xname, .index = xindex, \ | ||
138 | .info = snd_ak4531_info_double, \ | ||
139 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ | ||
140 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22), \ | ||
141 | .tlv = { .p = (xtlv) } } | ||
125 | 142 | ||
126 | static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 143 | static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
127 | { | 144 | { |
@@ -250,50 +267,62 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
250 | return change; | 267 | return change; |
251 | } | 268 | } |
252 | 269 | ||
270 | static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); | ||
271 | static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); | ||
272 | static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); | ||
273 | |||
253 | static struct snd_kcontrol_new snd_ak4531_controls[] = { | 274 | static struct snd_kcontrol_new snd_ak4531_controls[] = { |
254 | 275 | ||
255 | AK4531_DOUBLE("Master Playback Switch", 0, AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1), | 276 | AK4531_DOUBLE_TLV("Master Playback Switch", 0, |
277 | AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, | ||
278 | db_scale_master), | ||
256 | AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1), | 279 | AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1), |
257 | 280 | ||
258 | AK4531_SINGLE("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1), | 281 | AK4531_SINGLE_TLV("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1, |
282 | db_scale_mono), | ||
259 | AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1), | 283 | AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1), |
260 | 284 | ||
261 | AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1), | 285 | AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1), |
262 | AK4531_DOUBLE("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1), | 286 | AK4531_DOUBLE_TLV("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1, |
287 | db_scale_input), | ||
263 | AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0), | 288 | AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0), |
264 | AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0), | 289 | AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0), |
265 | 290 | ||
266 | AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1), | 291 | AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1), |
267 | AK4531_DOUBLE("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1), | 292 | AK4531_DOUBLE_TLV("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1, |
293 | db_scale_input), | ||
268 | AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0), | 294 | AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0), |
269 | AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5), | 295 | AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5), |
270 | 296 | ||
271 | AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1), | 297 | AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1), |
272 | AK4531_DOUBLE("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1), | 298 | AK4531_DOUBLE_TLV("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1, |
299 | db_scale_input), | ||
273 | AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0), | 300 | AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0), |
274 | AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1), | 301 | AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1), |
275 | 302 | ||
276 | AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1), | 303 | AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1), |
277 | AK4531_DOUBLE("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1), | 304 | AK4531_DOUBLE_TLV("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1, |
305 | db_scale_input), | ||
278 | AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0), | 306 | AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0), |
279 | AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3), | 307 | AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3), |
280 | 308 | ||
281 | AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), | 309 | AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), |
282 | AK4531_DOUBLE("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1), | 310 | AK4531_DOUBLE_TLV("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1, |
311 | db_scale_input), | ||
283 | AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), | 312 | AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), |
284 | AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), | 313 | AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), |
285 | 314 | ||
286 | AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), | 315 | AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), |
287 | AK4531_SINGLE("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1), | 316 | AK4531_SINGLE_TLV("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1, db_scale_input), |
288 | AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0), | 317 | AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0), |
289 | AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0), | 318 | AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0), |
290 | 319 | ||
291 | AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1), | 320 | AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1), |
292 | AK4531_SINGLE("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1), | 321 | AK4531_SINGLE_TLV("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1, db_scale_input), |
293 | AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0), | 322 | AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0), |
294 | AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0), | 323 | AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0), |
295 | 324 | ||
296 | AK4531_SINGLE("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1), | 325 | AK4531_SINGLE_TLV("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1, db_scale_input), |
297 | AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1), | 326 | AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1), |
298 | AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0), | 327 | AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0), |
299 | AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0), | 328 | AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0), |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 146eed70dce6..9855f528ea78 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -70,9 +70,13 @@ | |||
70 | #include <sound/pcm.h> | 70 | #include <sound/pcm.h> |
71 | #include <sound/ac97_codec.h> | 71 | #include <sound/ac97_codec.h> |
72 | #include <sound/info.h> | 72 | #include <sound/info.h> |
73 | #include <sound/tlv.h> | ||
73 | 74 | ||
74 | #include "ca0106.h" | 75 | #include "ca0106.h" |
75 | 76 | ||
77 | static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); | ||
78 | static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); | ||
79 | |||
76 | static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, | 80 | static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, |
77 | struct snd_ctl_elem_info *uinfo) | 81 | struct snd_ctl_elem_info *uinfo) |
78 | { | 82 | { |
@@ -469,18 +473,24 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, | |||
469 | #define CA_VOLUME(xname,chid,reg) \ | 473 | #define CA_VOLUME(xname,chid,reg) \ |
470 | { \ | 474 | { \ |
471 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 475 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
476 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
477 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
472 | .info = snd_ca0106_volume_info, \ | 478 | .info = snd_ca0106_volume_info, \ |
473 | .get = snd_ca0106_volume_get, \ | 479 | .get = snd_ca0106_volume_get, \ |
474 | .put = snd_ca0106_volume_put, \ | 480 | .put = snd_ca0106_volume_put, \ |
481 | .tlv = { .p = snd_ca0106_db_scale1 }, \ | ||
475 | .private_value = ((chid) << 8) | (reg) \ | 482 | .private_value = ((chid) << 8) | (reg) \ |
476 | } | 483 | } |
477 | 484 | ||
478 | #define I2C_VOLUME(xname,chid) \ | 485 | #define I2C_VOLUME(xname,chid) \ |
479 | { \ | 486 | { \ |
480 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 487 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
488 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
489 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
481 | .info = snd_ca0106_i2c_volume_info, \ | 490 | .info = snd_ca0106_i2c_volume_info, \ |
482 | .get = snd_ca0106_i2c_volume_get, \ | 491 | .get = snd_ca0106_i2c_volume_get, \ |
483 | .put = snd_ca0106_i2c_volume_put, \ | 492 | .put = snd_ca0106_i2c_volume_put, \ |
493 | .tlv = { .p = snd_ca0106_db_scale2 }, \ | ||
484 | .private_value = chid \ | 494 | .private_value = chid \ |
485 | } | 495 | } |
486 | 496 | ||
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 9631456ec3de..1990430a21c1 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/rawmidi.h> | 34 | #include <sound/rawmidi.h> |
35 | #include <sound/ac97_codec.h> | 35 | #include <sound/ac97_codec.h> |
36 | #include <sound/tlv.h> | ||
36 | #include <sound/opl3.h> | 37 | #include <sound/opl3.h> |
37 | #include <sound/initval.h> | 38 | #include <sound/initval.h> |
38 | 39 | ||
@@ -1054,6 +1055,8 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol, | |||
1054 | return change; | 1055 | return change; |
1055 | } | 1056 | } |
1056 | 1057 | ||
1058 | static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); | ||
1059 | |||
1057 | static struct snd_kcontrol_new snd_cs4281_fm_vol = | 1060 | static struct snd_kcontrol_new snd_cs4281_fm_vol = |
1058 | { | 1061 | { |
1059 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1062 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1062,6 +1065,7 @@ static struct snd_kcontrol_new snd_cs4281_fm_vol = | |||
1062 | .get = snd_cs4281_get_volume, | 1065 | .get = snd_cs4281_get_volume, |
1063 | .put = snd_cs4281_put_volume, | 1066 | .put = snd_cs4281_put_volume, |
1064 | .private_value = ((BA0_FMLVC << 16) | BA0_FMRVC), | 1067 | .private_value = ((BA0_FMLVC << 16) | BA0_FMRVC), |
1068 | .tlv = { .p = db_scale_dsp }, | ||
1065 | }; | 1069 | }; |
1066 | 1070 | ||
1067 | static struct snd_kcontrol_new snd_cs4281_pcm_vol = | 1071 | static struct snd_kcontrol_new snd_cs4281_pcm_vol = |
@@ -1072,6 +1076,7 @@ static struct snd_kcontrol_new snd_cs4281_pcm_vol = | |||
1072 | .get = snd_cs4281_get_volume, | 1076 | .get = snd_cs4281_get_volume, |
1073 | .put = snd_cs4281_put_volume, | 1077 | .put = snd_cs4281_put_volume, |
1074 | .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC), | 1078 | .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC), |
1079 | .tlv = { .p = db_scale_dsp }, | ||
1075 | }; | 1080 | }; |
1076 | 1081 | ||
1077 | static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus) | 1082 | static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus) |
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 5c9711c0265c..89c402770a1d 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
@@ -868,35 +868,23 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) | |||
868 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; | 868 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; |
869 | int i; | 869 | int i; |
870 | 870 | ||
871 | if (ins->proc_sym_info_entry) { | 871 | snd_info_free_entry(ins->proc_sym_info_entry); |
872 | snd_info_unregister(ins->proc_sym_info_entry); | 872 | ins->proc_sym_info_entry = NULL; |
873 | ins->proc_sym_info_entry = NULL; | 873 | |
874 | } | 874 | snd_info_free_entry(ins->proc_modules_info_entry); |
875 | 875 | ins->proc_modules_info_entry = NULL; | |
876 | if (ins->proc_modules_info_entry) { | 876 | |
877 | snd_info_unregister(ins->proc_modules_info_entry); | 877 | snd_info_free_entry(ins->proc_parameter_dump_info_entry); |
878 | ins->proc_modules_info_entry = NULL; | 878 | ins->proc_parameter_dump_info_entry = NULL; |
879 | } | 879 | |
880 | 880 | snd_info_free_entry(ins->proc_sample_dump_info_entry); | |
881 | if (ins->proc_parameter_dump_info_entry) { | 881 | ins->proc_sample_dump_info_entry = NULL; |
882 | snd_info_unregister(ins->proc_parameter_dump_info_entry); | 882 | |
883 | ins->proc_parameter_dump_info_entry = NULL; | 883 | snd_info_free_entry(ins->proc_scb_info_entry); |
884 | } | 884 | ins->proc_scb_info_entry = NULL; |
885 | 885 | ||
886 | if (ins->proc_sample_dump_info_entry) { | 886 | snd_info_free_entry(ins->proc_task_info_entry); |
887 | snd_info_unregister(ins->proc_sample_dump_info_entry); | 887 | ins->proc_task_info_entry = NULL; |
888 | ins->proc_sample_dump_info_entry = NULL; | ||
889 | } | ||
890 | |||
891 | if (ins->proc_scb_info_entry) { | ||
892 | snd_info_unregister(ins->proc_scb_info_entry); | ||
893 | ins->proc_scb_info_entry = NULL; | ||
894 | } | ||
895 | |||
896 | if (ins->proc_task_info_entry) { | ||
897 | snd_info_unregister(ins->proc_task_info_entry); | ||
898 | ins->proc_task_info_entry = NULL; | ||
899 | } | ||
900 | 888 | ||
901 | mutex_lock(&chip->spos_mutex); | 889 | mutex_lock(&chip->spos_mutex); |
902 | for (i = 0; i < ins->nscb; ++i) { | 890 | for (i = 0; i < ins->nscb; ++i) { |
@@ -905,10 +893,8 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) | |||
905 | } | 893 | } |
906 | mutex_unlock(&chip->spos_mutex); | 894 | mutex_unlock(&chip->spos_mutex); |
907 | 895 | ||
908 | if (ins->proc_dsp_dir) { | 896 | snd_info_free_entry(ins->proc_dsp_dir); |
909 | snd_info_unregister (ins->proc_dsp_dir); | 897 | ins->proc_dsp_dir = NULL; |
910 | ins->proc_dsp_dir = NULL; | ||
911 | } | ||
912 | 898 | ||
913 | return 0; | 899 | return 0; |
914 | } | 900 | } |
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 232b337852ff..343f51d5311b 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c | |||
@@ -233,7 +233,7 @@ void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb) | |||
233 | 233 | ||
234 | snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name); | 234 | snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name); |
235 | 235 | ||
236 | snd_info_unregister(scb->proc_info); | 236 | snd_info_free_entry(scb->proc_info); |
237 | scb->proc_info = NULL; | 237 | scb->proc_info = NULL; |
238 | 238 | ||
239 | snd_assert (scb_info != NULL, return); | 239 | snd_assert (scb_info != NULL, return); |
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index 2911a8adc1f2..ad947b4c04cc 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o | 5 | snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o |
6 | 6 | ||
7 | ifdef CONFIG_PM | 7 | ifeq ($(CONFIG_PM),y) |
8 | snd-cs5535audio-objs += cs5535audio_pm.o | 8 | snd-cs5535audio-objs += cs5535audio_pm.o |
9 | endif | 9 | endif |
10 | 10 | ||
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 289bcd99c19c..493ec0816bb3 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -232,7 +232,7 @@ static int snd_emu10k1_suspend(struct pci_dev *pci, pm_message_t state) | |||
232 | return 0; | 232 | return 0; |
233 | } | 233 | } |
234 | 234 | ||
235 | int snd_emu10k1_resume(struct pci_dev *pci) | 235 | static int snd_emu10k1_resume(struct pci_dev *pci) |
236 | { | 236 | { |
237 | struct snd_card *card = pci_get_drvdata(pci); | 237 | struct snd_card *card = pci_get_drvdata(pci); |
238 | struct snd_emu10k1 *emu = card->private_data; | 238 | struct snd_emu10k1 *emu = card->private_data; |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 79f24cdf5fbf..be65d4db8e27 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -927,6 +927,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
927 | .ca0151_chip = 1, | 927 | .ca0151_chip = 1, |
928 | .spk71 = 1, | 928 | .spk71 = 1, |
929 | .spdif_bug = 1, | 929 | .spdif_bug = 1, |
930 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ | ||
930 | .ac97_chip = 1} , | 931 | .ac97_chip = 1} , |
931 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, | 932 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, |
932 | .driver = "Audigy2", .name = "Audigy 2 EX [1005]", | 933 | .driver = "Audigy2", .name = "Audigy 2 EX [1005]", |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index bda8bdf59935..da1610a571b8 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -1626,12 +1626,7 @@ static struct pci_driver driver = { | |||
1626 | // initialization of the module | 1626 | // initialization of the module |
1627 | static int __init alsa_card_emu10k1x_init(void) | 1627 | static int __init alsa_card_emu10k1x_init(void) |
1628 | { | 1628 | { |
1629 | int err; | 1629 | return pci_register_driver(&driver); |
1630 | |||
1631 | if ((err = pci_register_driver(&driver)) > 0) | ||
1632 | return err; | ||
1633 | |||
1634 | return 0; | ||
1635 | } | 1630 | } |
1636 | 1631 | ||
1637 | // clean up the module | 1632 | // clean up the module |
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index dfba00230d4d..13cd6ce89811 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/mutex.h> | 35 | #include <linux/mutex.h> |
36 | 36 | ||
37 | #include <sound/core.h> | 37 | #include <sound/core.h> |
38 | #include <sound/tlv.h> | ||
38 | #include <sound/emu10k1.h> | 39 | #include <sound/emu10k1.h> |
39 | 40 | ||
40 | #if 0 /* for testing purposes - digital out -> capture */ | 41 | #if 0 /* for testing purposes - digital out -> capture */ |
@@ -266,6 +267,7 @@ static const u32 treble_table[41][5] = { | |||
266 | { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 } | 267 | { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 } |
267 | }; | 268 | }; |
268 | 269 | ||
270 | /* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */ | ||
269 | static const u32 db_table[101] = { | 271 | static const u32 db_table[101] = { |
270 | 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, | 272 | 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, |
271 | 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, | 273 | 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, |
@@ -290,6 +292,9 @@ static const u32 db_table[101] = { | |||
290 | 0x7fffffff, | 292 | 0x7fffffff, |
291 | }; | 293 | }; |
292 | 294 | ||
295 | /* EMU10k1/EMU10k2 DSP control db gain */ | ||
296 | static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); | ||
297 | |||
293 | static const u32 onoff_table[2] = { | 298 | static const u32 onoff_table[2] = { |
294 | 0x00000000, 0x00000001 | 299 | 0x00000000, 0x00000001 |
295 | }; | 300 | }; |
@@ -755,6 +760,11 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, | |||
755 | knew.device = gctl->id.device; | 760 | knew.device = gctl->id.device; |
756 | knew.subdevice = gctl->id.subdevice; | 761 | knew.subdevice = gctl->id.subdevice; |
757 | knew.info = snd_emu10k1_gpr_ctl_info; | 762 | knew.info = snd_emu10k1_gpr_ctl_info; |
763 | if (gctl->tlv.p) { | ||
764 | knew.tlv.p = gctl->tlv.p; | ||
765 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
766 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
767 | } | ||
758 | knew.get = snd_emu10k1_gpr_ctl_get; | 768 | knew.get = snd_emu10k1_gpr_ctl_get; |
759 | knew.put = snd_emu10k1_gpr_ctl_put; | 769 | knew.put = snd_emu10k1_gpr_ctl_put; |
760 | memset(nctl, 0, sizeof(*nctl)); | 770 | memset(nctl, 0, sizeof(*nctl)); |
@@ -1013,6 +1023,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, | |||
1013 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; | 1023 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; |
1014 | ctl->min = 0; | 1024 | ctl->min = 0; |
1015 | ctl->max = 100; | 1025 | ctl->max = 100; |
1026 | ctl->tlv.p = snd_emu10k1_db_scale1; | ||
1016 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; | 1027 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; |
1017 | } | 1028 | } |
1018 | 1029 | ||
@@ -1027,6 +1038,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, | |||
1027 | ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; | 1038 | ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; |
1028 | ctl->min = 0; | 1039 | ctl->min = 0; |
1029 | ctl->max = 100; | 1040 | ctl->max = 100; |
1041 | ctl->tlv.p = snd_emu10k1_db_scale1; | ||
1030 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; | 1042 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; |
1031 | } | 1043 | } |
1032 | 1044 | ||
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 9905651935fb..4e0f95438f47 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -100,6 +100,7 @@ | |||
100 | #include <sound/pcm.h> | 100 | #include <sound/pcm.h> |
101 | #include <sound/ac97_codec.h> | 101 | #include <sound/ac97_codec.h> |
102 | #include <sound/info.h> | 102 | #include <sound/info.h> |
103 | #include <sound/tlv.h> | ||
103 | #include <sound/emu10k1.h> | 104 | #include <sound/emu10k1.h> |
104 | #include "p16v.h" | 105 | #include "p16v.h" |
105 | 106 | ||
@@ -784,12 +785,16 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol, | |||
784 | } | 785 | } |
785 | return change; | 786 | return change; |
786 | } | 787 | } |
788 | static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); | ||
787 | 789 | ||
788 | #define P16V_VOL(xname,xreg,xhl) { \ | 790 | #define P16V_VOL(xname,xreg,xhl) { \ |
789 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 791 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
792 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
793 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
790 | .info = snd_p16v_volume_info, \ | 794 | .info = snd_p16v_volume_info, \ |
791 | .get = snd_p16v_volume_get, \ | 795 | .get = snd_p16v_volume_get, \ |
792 | .put = snd_p16v_volume_put, \ | 796 | .put = snd_p16v_volume_put, \ |
797 | .tlv = { .p = snd_p16v_db_scale1 }, \ | ||
793 | .private_value = ((xreg) | ((xhl) << 8)) \ | 798 | .private_value = ((xreg) | ((xhl) << 8)) \ |
794 | } | 799 | } |
795 | 800 | ||
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index cc0f34f68185..3ce5a4e7e31f 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <sound/opl3.h> | 62 | #include <sound/opl3.h> |
63 | #include <sound/mpu401.h> | 63 | #include <sound/mpu401.h> |
64 | #include <sound/initval.h> | 64 | #include <sound/initval.h> |
65 | #include <sound/tlv.h> | ||
65 | 66 | ||
66 | #include <asm/io.h> | 67 | #include <asm/io.h> |
67 | 68 | ||
@@ -1164,6 +1165,14 @@ static int snd_es1938_reg_read(struct es1938 *chip, unsigned char reg) | |||
1164 | return snd_es1938_read(chip, reg); | 1165 | return snd_es1938_read(chip, reg); |
1165 | } | 1166 | } |
1166 | 1167 | ||
1168 | #define ES1938_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ | ||
1169 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1170 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\ | ||
1171 | .name = xname, .index = xindex, \ | ||
1172 | .info = snd_es1938_info_single, \ | ||
1173 | .get = snd_es1938_get_single, .put = snd_es1938_put_single, \ | ||
1174 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ | ||
1175 | .tlv = { .p = xtlv } } | ||
1167 | #define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \ | 1176 | #define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \ |
1168 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 1177 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
1169 | .info = snd_es1938_info_single, \ | 1178 | .info = snd_es1938_info_single, \ |
@@ -1217,6 +1226,14 @@ static int snd_es1938_put_single(struct snd_kcontrol *kcontrol, | |||
1217 | return snd_es1938_reg_bits(chip, reg, mask, val) != val; | 1226 | return snd_es1938_reg_bits(chip, reg, mask, val) != val; |
1218 | } | 1227 | } |
1219 | 1228 | ||
1229 | #define ES1938_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \ | ||
1230 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1231 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\ | ||
1232 | .name = xname, .index = xindex, \ | ||
1233 | .info = snd_es1938_info_double, \ | ||
1234 | .get = snd_es1938_get_double, .put = snd_es1938_put_double, \ | ||
1235 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \ | ||
1236 | .tlv = { .p = xtlv } } | ||
1220 | #define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ | 1237 | #define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ |
1221 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 1238 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
1222 | .info = snd_es1938_info_double, \ | 1239 | .info = snd_es1938_info_double, \ |
@@ -1297,8 +1314,41 @@ static int snd_es1938_put_double(struct snd_kcontrol *kcontrol, | |||
1297 | return change; | 1314 | return change; |
1298 | } | 1315 | } |
1299 | 1316 | ||
1317 | static unsigned int db_scale_master[] = { | ||
1318 | TLV_DB_RANGE_HEAD(2), | ||
1319 | 0, 54, TLV_DB_SCALE_ITEM(-3600, 50, 1), | ||
1320 | 54, 63, TLV_DB_SCALE_ITEM(-900, 100, 0), | ||
1321 | }; | ||
1322 | |||
1323 | static unsigned int db_scale_audio1[] = { | ||
1324 | TLV_DB_RANGE_HEAD(2), | ||
1325 | 0, 8, TLV_DB_SCALE_ITEM(-3300, 300, 1), | ||
1326 | 8, 15, TLV_DB_SCALE_ITEM(-900, 150, 0), | ||
1327 | }; | ||
1328 | |||
1329 | static unsigned int db_scale_audio2[] = { | ||
1330 | TLV_DB_RANGE_HEAD(2), | ||
1331 | 0, 8, TLV_DB_SCALE_ITEM(-3450, 300, 1), | ||
1332 | 8, 15, TLV_DB_SCALE_ITEM(-1050, 150, 0), | ||
1333 | }; | ||
1334 | |||
1335 | static unsigned int db_scale_mic[] = { | ||
1336 | TLV_DB_RANGE_HEAD(2), | ||
1337 | 0, 8, TLV_DB_SCALE_ITEM(-2400, 300, 1), | ||
1338 | 8, 15, TLV_DB_SCALE_ITEM(0, 150, 0), | ||
1339 | }; | ||
1340 | |||
1341 | static unsigned int db_scale_line[] = { | ||
1342 | TLV_DB_RANGE_HEAD(2), | ||
1343 | 0, 8, TLV_DB_SCALE_ITEM(-3150, 300, 1), | ||
1344 | 8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0), | ||
1345 | }; | ||
1346 | |||
1347 | static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0); | ||
1348 | |||
1300 | static struct snd_kcontrol_new snd_es1938_controls[] = { | 1349 | static struct snd_kcontrol_new snd_es1938_controls[] = { |
1301 | ES1938_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0), | 1350 | ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0, |
1351 | db_scale_master), | ||
1302 | ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), | 1352 | ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), |
1303 | { | 1353 | { |
1304 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1354 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1309,19 +1359,27 @@ ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), | |||
1309 | }, | 1359 | }, |
1310 | { | 1360 | { |
1311 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1361 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1362 | .access = (SNDRV_CTL_ELEM_ACCESS_READ | | ||
1363 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1312 | .name = "Hardware Master Playback Switch", | 1364 | .name = "Hardware Master Playback Switch", |
1313 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
1314 | .info = snd_es1938_info_hw_switch, | 1365 | .info = snd_es1938_info_hw_switch, |
1315 | .get = snd_es1938_get_hw_switch, | 1366 | .get = snd_es1938_get_hw_switch, |
1367 | .tlv = { .p = db_scale_master }, | ||
1316 | }, | 1368 | }, |
1317 | ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0), | 1369 | ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0), |
1318 | ES1938_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0), | 1370 | ES1938_DOUBLE_TLV("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0, |
1371 | db_scale_line), | ||
1319 | ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0), | 1372 | ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0), |
1320 | ES1938_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0), | 1373 | ES1938_DOUBLE_TLV("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0, |
1321 | ES1938_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0), | 1374 | db_scale_mic), |
1322 | ES1938_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0), | 1375 | ES1938_DOUBLE_TLV("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0, |
1323 | ES1938_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0), | 1376 | db_scale_line), |
1324 | ES1938_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0), | 1377 | ES1938_DOUBLE_TLV("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0, |
1378 | db_scale_mic), | ||
1379 | ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0, | ||
1380 | db_scale_line), | ||
1381 | ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0, | ||
1382 | db_scale_capture), | ||
1325 | ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0), | 1383 | ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0), |
1326 | ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0), | 1384 | ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0), |
1327 | ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), | 1385 | ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), |
@@ -1332,16 +1390,26 @@ ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), | |||
1332 | .get = snd_es1938_get_mux, | 1390 | .get = snd_es1938_get_mux, |
1333 | .put = snd_es1938_put_mux, | 1391 | .put = snd_es1938_put_mux, |
1334 | }, | 1392 | }, |
1335 | ES1938_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0), | 1393 | ES1938_DOUBLE_TLV("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0, |
1336 | ES1938_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0), | 1394 | db_scale_line), |
1337 | ES1938_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0), | 1395 | ES1938_DOUBLE_TLV("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0, |
1338 | ES1938_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0), | 1396 | db_scale_audio2), |
1339 | ES1938_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0), | 1397 | ES1938_DOUBLE_TLV("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0, |
1340 | ES1938_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0), | 1398 | db_scale_mic), |
1341 | ES1938_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0), | 1399 | ES1938_DOUBLE_TLV("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0, |
1342 | ES1938_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0), | 1400 | db_scale_line), |
1343 | ES1938_DOUBLE("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0), | 1401 | ES1938_DOUBLE_TLV("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0, |
1344 | ES1938_DOUBLE("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0), | 1402 | db_scale_mic), |
1403 | ES1938_DOUBLE_TLV("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0, | ||
1404 | db_scale_line), | ||
1405 | ES1938_DOUBLE_TLV("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0, | ||
1406 | db_scale_line), | ||
1407 | ES1938_DOUBLE_TLV("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0, | ||
1408 | db_scale_line), | ||
1409 | ES1938_DOUBLE_TLV("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0, | ||
1410 | db_scale_audio2), | ||
1411 | ES1938_DOUBLE_TLV("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0, | ||
1412 | db_scale_audio1), | ||
1345 | ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0), | 1413 | ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0), |
1346 | { | 1414 | { |
1347 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1415 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 3c5ab7c2e72d..f3c40385c87d 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
@@ -1905,7 +1905,7 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1905 | /* Figure out which volume control button was pushed, | 1905 | /* Figure out which volume control button was pushed, |
1906 | based on differences from the default register | 1906 | based on differences from the default register |
1907 | values. */ | 1907 | values. */ |
1908 | x = inb(chip->io_port + 0x1c); | 1908 | x = inb(chip->io_port + 0x1c) & 0xee; |
1909 | /* Reset the volume control registers. */ | 1909 | /* Reset the volume control registers. */ |
1910 | outb(0x88, chip->io_port + 0x1c); | 1910 | outb(0x88, chip->io_port + 0x1c); |
1911 | outb(0x88, chip->io_port + 0x1d); | 1911 | outb(0x88, chip->io_port + 0x1d); |
@@ -1921,7 +1921,8 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1921 | /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ | 1921 | /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ |
1922 | spin_lock_irqsave(&chip->ac97_lock, flags); | 1922 | spin_lock_irqsave(&chip->ac97_lock, flags); |
1923 | val = chip->ac97->regs[AC97_MASTER]; | 1923 | val = chip->ac97->regs[AC97_MASTER]; |
1924 | if (x & 1) { | 1924 | switch (x) { |
1925 | case 0x88: | ||
1925 | /* mute */ | 1926 | /* mute */ |
1926 | val ^= 0x8000; | 1927 | val ^= 0x8000; |
1927 | chip->ac97->regs[AC97_MASTER] = val; | 1928 | chip->ac97->regs[AC97_MASTER] = val; |
@@ -1929,26 +1930,31 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1929 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); | 1930 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); |
1930 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | 1931 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
1931 | &chip->master_switch->id); | 1932 | &chip->master_switch->id); |
1932 | } else { | 1933 | break; |
1933 | val &= 0x7fff; | 1934 | case 0xaa: |
1934 | if (((x>>1) & 7) > 4) { | 1935 | /* volume up */ |
1935 | /* volume up */ | 1936 | if ((val & 0x7f) > 0) |
1936 | if ((val & 0xff) > 0) | 1937 | val--; |
1937 | val--; | 1938 | if ((val & 0x7f00) > 0) |
1938 | if ((val & 0xff00) > 0) | 1939 | val -= 0x0100; |
1939 | val -= 0x0100; | 1940 | chip->ac97->regs[AC97_MASTER] = val; |
1940 | } else { | 1941 | outw(val, chip->io_port + ESM_AC97_DATA); |
1941 | /* volume down */ | 1942 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); |
1942 | if ((val & 0xff) < 0x1f) | 1943 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
1943 | val++; | 1944 | &chip->master_volume->id); |
1944 | if ((val & 0xff00) < 0x1f00) | 1945 | break; |
1945 | val += 0x0100; | 1946 | case 0x66: |
1946 | } | 1947 | /* volume down */ |
1948 | if ((val & 0x7f) < 0x1f) | ||
1949 | val++; | ||
1950 | if ((val & 0x7f00) < 0x1f00) | ||
1951 | val += 0x0100; | ||
1947 | chip->ac97->regs[AC97_MASTER] = val; | 1952 | chip->ac97->regs[AC97_MASTER] = val; |
1948 | outw(val, chip->io_port + ESM_AC97_DATA); | 1953 | outw(val, chip->io_port + ESM_AC97_DATA); |
1949 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); | 1954 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); |
1950 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | 1955 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
1951 | &chip->master_volume->id); | 1956 | &chip->master_volume->id); |
1957 | break; | ||
1952 | } | 1958 | } |
1953 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 1959 | spin_unlock_irqrestore(&chip->ac97_lock, flags); |
1954 | } | 1960 | } |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 13868c985126..bdfda1997d5b 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * The driver for the ForteMedia FM801 based soundcards | 2 | * The driver for the ForteMedia FM801 based soundcards |
3 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | 3 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> |
4 | * | 4 | * |
5 | * Support FM only card by Andy Shevchenko <andy@smile.org.ua> | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program 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 | * it under the terms of the GNU General Public License as published by |
@@ -28,6 +29,7 @@ | |||
28 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
32 | #include <sound/tlv.h> | ||
31 | #include <sound/ac97_codec.h> | 33 | #include <sound/ac97_codec.h> |
32 | #include <sound/mpu401.h> | 34 | #include <sound/mpu401.h> |
33 | #include <sound/opl3.h> | 35 | #include <sound/opl3.h> |
@@ -54,6 +56,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * | |||
54 | * 1 = MediaForte 256-PCS | 56 | * 1 = MediaForte 256-PCS |
55 | * 2 = MediaForte 256-PCPR | 57 | * 2 = MediaForte 256-PCPR |
56 | * 3 = MediaForte 64-PCR | 58 | * 3 = MediaForte 64-PCR |
59 | * 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card | ||
57 | * High 16-bits are video (radio) device number + 1 | 60 | * High 16-bits are video (radio) device number + 1 |
58 | */ | 61 | */ |
59 | static int tea575x_tuner[SNDRV_CARDS]; | 62 | static int tea575x_tuner[SNDRV_CARDS]; |
@@ -158,6 +161,7 @@ struct fm801 { | |||
158 | unsigned int multichannel: 1, /* multichannel support */ | 161 | unsigned int multichannel: 1, /* multichannel support */ |
159 | secondary: 1; /* secondary codec */ | 162 | secondary: 1; /* secondary codec */ |
160 | unsigned char secondary_addr; /* address of the secondary codec */ | 163 | unsigned char secondary_addr; /* address of the secondary codec */ |
164 | unsigned int tea575x_tuner; /* tuner flags */ | ||
161 | 165 | ||
162 | unsigned short ply_ctrl; /* playback control */ | 166 | unsigned short ply_ctrl; /* playback control */ |
163 | unsigned short cap_ctrl; /* capture control */ | 167 | unsigned short cap_ctrl; /* capture control */ |
@@ -318,10 +322,8 @@ static unsigned int channels[] = { | |||
318 | 2, 4, 6 | 322 | 2, 4, 6 |
319 | }; | 323 | }; |
320 | 324 | ||
321 | #define CHANNELS sizeof(channels) / sizeof(channels[0]) | ||
322 | |||
323 | static struct snd_pcm_hw_constraint_list hw_constraints_channels = { | 325 | static struct snd_pcm_hw_constraint_list hw_constraints_channels = { |
324 | .count = CHANNELS, | 326 | .count = ARRAY_SIZE(channels), |
325 | .list = channels, | 327 | .list = channels, |
326 | .mask = 0, | 328 | .mask = 0, |
327 | }; | 329 | }; |
@@ -1052,6 +1054,13 @@ static int snd_fm801_put_single(struct snd_kcontrol *kcontrol, | |||
1052 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \ | 1054 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \ |
1053 | .get = snd_fm801_get_double, .put = snd_fm801_put_double, \ | 1055 | .get = snd_fm801_get_double, .put = snd_fm801_put_double, \ |
1054 | .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) } | 1056 | .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) } |
1057 | #define FM801_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \ | ||
1058 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1059 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
1060 | .name = xname, .info = snd_fm801_info_double, \ | ||
1061 | .get = snd_fm801_get_double, .put = snd_fm801_put_double, \ | ||
1062 | .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \ | ||
1063 | .tlv = { .p = (xtlv) } } | ||
1055 | 1064 | ||
1056 | static int snd_fm801_info_double(struct snd_kcontrol *kcontrol, | 1065 | static int snd_fm801_info_double(struct snd_kcontrol *kcontrol, |
1057 | struct snd_ctl_elem_info *uinfo) | 1066 | struct snd_ctl_elem_info *uinfo) |
@@ -1148,14 +1157,19 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol, | |||
1148 | return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); | 1157 | return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); |
1149 | } | 1158 | } |
1150 | 1159 | ||
1160 | static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); | ||
1161 | |||
1151 | #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) | 1162 | #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) |
1152 | 1163 | ||
1153 | static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = { | 1164 | static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = { |
1154 | FM801_DOUBLE("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1), | 1165 | FM801_DOUBLE_TLV("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1, |
1166 | db_scale_dsp), | ||
1155 | FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1), | 1167 | FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1), |
1156 | FM801_DOUBLE("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1), | 1168 | FM801_DOUBLE_TLV("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1, |
1169 | db_scale_dsp), | ||
1157 | FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1), | 1170 | FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1), |
1158 | FM801_DOUBLE("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1), | 1171 | FM801_DOUBLE_TLV("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1, |
1172 | db_scale_dsp), | ||
1159 | FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1), | 1173 | FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1), |
1160 | { | 1174 | { |
1161 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1175 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1253,6 +1267,9 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) | |||
1253 | int id; | 1267 | int id; |
1254 | unsigned short cmdw; | 1268 | unsigned short cmdw; |
1255 | 1269 | ||
1270 | if (chip->tea575x_tuner & 0x0010) | ||
1271 | goto __ac97_ok; | ||
1272 | |||
1256 | /* codec cold reset + AC'97 warm reset */ | 1273 | /* codec cold reset + AC'97 warm reset */ |
1257 | outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL)); | 1274 | outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL)); |
1258 | inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ | 1275 | inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ |
@@ -1290,6 +1307,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) | |||
1290 | wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); | 1307 | wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); |
1291 | } | 1308 | } |
1292 | 1309 | ||
1310 | __ac97_ok: | ||
1311 | |||
1293 | /* init volume */ | 1312 | /* init volume */ |
1294 | outw(0x0808, FM801_REG(chip, PCM_VOL)); | 1313 | outw(0x0808, FM801_REG(chip, PCM_VOL)); |
1295 | outw(0x9f1f, FM801_REG(chip, FM_VOL)); | 1314 | outw(0x9f1f, FM801_REG(chip, FM_VOL)); |
@@ -1298,9 +1317,12 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) | |||
1298 | /* I2S control - I2S mode */ | 1317 | /* I2S control - I2S mode */ |
1299 | outw(0x0003, FM801_REG(chip, I2S_MODE)); | 1318 | outw(0x0003, FM801_REG(chip, I2S_MODE)); |
1300 | 1319 | ||
1301 | /* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */ | 1320 | /* interrupt setup */ |
1302 | cmdw = inw(FM801_REG(chip, IRQ_MASK)); | 1321 | cmdw = inw(FM801_REG(chip, IRQ_MASK)); |
1303 | cmdw &= ~0x0083; | 1322 | if (chip->irq < 0) |
1323 | cmdw |= 0x00c3; /* mask everything, no PCM nor MPU */ | ||
1324 | else | ||
1325 | cmdw &= ~0x0083; /* unmask MPU, PLAYBACK & CAPTURE */ | ||
1304 | outw(cmdw, FM801_REG(chip, IRQ_MASK)); | 1326 | outw(cmdw, FM801_REG(chip, IRQ_MASK)); |
1305 | 1327 | ||
1306 | /* interrupt clear */ | 1328 | /* interrupt clear */ |
@@ -1365,20 +1387,23 @@ static int __devinit snd_fm801_create(struct snd_card *card, | |||
1365 | chip->card = card; | 1387 | chip->card = card; |
1366 | chip->pci = pci; | 1388 | chip->pci = pci; |
1367 | chip->irq = -1; | 1389 | chip->irq = -1; |
1390 | chip->tea575x_tuner = tea575x_tuner; | ||
1368 | if ((err = pci_request_regions(pci, "FM801")) < 0) { | 1391 | if ((err = pci_request_regions(pci, "FM801")) < 0) { |
1369 | kfree(chip); | 1392 | kfree(chip); |
1370 | pci_disable_device(pci); | 1393 | pci_disable_device(pci); |
1371 | return err; | 1394 | return err; |
1372 | } | 1395 | } |
1373 | chip->port = pci_resource_start(pci, 0); | 1396 | chip->port = pci_resource_start(pci, 0); |
1374 | if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED, | 1397 | if ((tea575x_tuner & 0x0010) == 0) { |
1375 | "FM801", chip)) { | 1398 | if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED, |
1376 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); | 1399 | "FM801", chip)) { |
1377 | snd_fm801_free(chip); | 1400 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); |
1378 | return -EBUSY; | 1401 | snd_fm801_free(chip); |
1402 | return -EBUSY; | ||
1403 | } | ||
1404 | chip->irq = pci->irq; | ||
1405 | pci_set_master(pci); | ||
1379 | } | 1406 | } |
1380 | chip->irq = pci->irq; | ||
1381 | pci_set_master(pci); | ||
1382 | 1407 | ||
1383 | pci_read_config_byte(pci, PCI_REVISION_ID, &rev); | 1408 | pci_read_config_byte(pci, PCI_REVISION_ID, &rev); |
1384 | if (rev >= 0xb1) /* FM801-AU */ | 1409 | if (rev >= 0xb1) /* FM801-AU */ |
@@ -1394,12 +1419,12 @@ static int __devinit snd_fm801_create(struct snd_card *card, | |||
1394 | snd_card_set_dev(card, &pci->dev); | 1419 | snd_card_set_dev(card, &pci->dev); |
1395 | 1420 | ||
1396 | #ifdef TEA575X_RADIO | 1421 | #ifdef TEA575X_RADIO |
1397 | if (tea575x_tuner > 0 && (tea575x_tuner & 0xffff) < 4) { | 1422 | if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) { |
1398 | chip->tea.dev_nr = tea575x_tuner >> 16; | 1423 | chip->tea.dev_nr = tea575x_tuner >> 16; |
1399 | chip->tea.card = card; | 1424 | chip->tea.card = card; |
1400 | chip->tea.freq_fixup = 10700; | 1425 | chip->tea.freq_fixup = 10700; |
1401 | chip->tea.private_data = chip; | 1426 | chip->tea.private_data = chip; |
1402 | chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0xffff) - 1]; | 1427 | chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; |
1403 | snd_tea575x_init(&chip->tea); | 1428 | snd_tea575x_init(&chip->tea); |
1404 | } | 1429 | } |
1405 | #endif | 1430 | #endif |
@@ -1439,6 +1464,9 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, | |||
1439 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 1464 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
1440 | card->shortname, chip->port, chip->irq); | 1465 | card->shortname, chip->port, chip->irq); |
1441 | 1466 | ||
1467 | if (tea575x_tuner[dev] & 0x0010) | ||
1468 | goto __fm801_tuner_only; | ||
1469 | |||
1442 | if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { | 1470 | if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { |
1443 | snd_card_free(card); | 1471 | snd_card_free(card); |
1444 | return err; | 1472 | return err; |
@@ -1465,6 +1493,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, | |||
1465 | return err; | 1493 | return err; |
1466 | } | 1494 | } |
1467 | 1495 | ||
1496 | __fm801_tuner_only: | ||
1468 | if ((err = snd_card_register(card)) < 0) { | 1497 | if ((err = snd_card_register(card)) < 0) { |
1469 | snd_card_free(card); | 1498 | snd_card_free(card); |
1470 | return err; | 1499 | return err; |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 23201f3eeb12..9c3d7ac08068 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include "hda_codec.h" | 30 | #include "hda_codec.h" |
31 | #include <sound/asoundef.h> | 31 | #include <sound/asoundef.h> |
32 | #include <sound/tlv.h> | ||
32 | #include <sound/initval.h> | 33 | #include <sound/initval.h> |
33 | #include "hda_local.h" | 34 | #include "hda_local.h" |
34 | 35 | ||
@@ -50,8 +51,10 @@ struct hda_vendor_id { | |||
50 | /* codec vendor labels */ | 51 | /* codec vendor labels */ |
51 | static struct hda_vendor_id hda_vendor_ids[] = { | 52 | static struct hda_vendor_id hda_vendor_ids[] = { |
52 | { 0x10ec, "Realtek" }, | 53 | { 0x10ec, "Realtek" }, |
54 | { 0x1057, "Motorola" }, | ||
53 | { 0x11d4, "Analog Devices" }, | 55 | { 0x11d4, "Analog Devices" }, |
54 | { 0x13f6, "C-Media" }, | 56 | { 0x13f6, "C-Media" }, |
57 | { 0x14f1, "Conexant" }, | ||
55 | { 0x434d, "C-Media" }, | 58 | { 0x434d, "C-Media" }, |
56 | { 0x8384, "SigmaTel" }, | 59 | { 0x8384, "SigmaTel" }, |
57 | {} /* terminator */ | 60 | {} /* terminator */ |
@@ -841,6 +844,31 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
841 | return change; | 844 | return change; |
842 | } | 845 | } |
843 | 846 | ||
847 | int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||
848 | unsigned int size, unsigned int __user *_tlv) | ||
849 | { | ||
850 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
851 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
852 | int dir = get_amp_direction(kcontrol); | ||
853 | u32 caps, val1, val2; | ||
854 | |||
855 | if (size < 4 * sizeof(unsigned int)) | ||
856 | return -ENOMEM; | ||
857 | caps = query_amp_caps(codec, nid, dir); | ||
858 | val2 = (((caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT) + 1) * 25; | ||
859 | val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); | ||
860 | val1 = ((int)val1) * ((int)val2); | ||
861 | if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) | ||
862 | return -EFAULT; | ||
863 | if (put_user(2 * sizeof(unsigned int), _tlv + 1)) | ||
864 | return -EFAULT; | ||
865 | if (put_user(val1, _tlv + 2)) | ||
866 | return -EFAULT; | ||
867 | if (put_user(val2, _tlv + 3)) | ||
868 | return -EFAULT; | ||
869 | return 0; | ||
870 | } | ||
871 | |||
844 | /* switch */ | 872 | /* switch */ |
845 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 873 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
846 | { | 874 | { |
@@ -1477,10 +1505,10 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
1477 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | 1505 | formats |= SNDRV_PCM_FMTBIT_S32_LE; |
1478 | if (val & AC_SUPPCM_BITS_32) | 1506 | if (val & AC_SUPPCM_BITS_32) |
1479 | bps = 32; | 1507 | bps = 32; |
1480 | else if (val & AC_SUPPCM_BITS_20) | ||
1481 | bps = 20; | ||
1482 | else if (val & AC_SUPPCM_BITS_24) | 1508 | else if (val & AC_SUPPCM_BITS_24) |
1483 | bps = 24; | 1509 | bps = 24; |
1510 | else if (val & AC_SUPPCM_BITS_20) | ||
1511 | bps = 20; | ||
1484 | } | 1512 | } |
1485 | } | 1513 | } |
1486 | else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */ | 1514 | else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */ |
@@ -1916,7 +1944,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o | |||
1916 | 1944 | ||
1917 | /* front */ | 1945 | /* front */ |
1918 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); | 1946 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); |
1919 | if (mout->hp_nid) | 1947 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]) |
1920 | /* headphone out will just decode front left/right (stereo) */ | 1948 | /* headphone out will just decode front left/right (stereo) */ |
1921 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); | 1949 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); |
1922 | /* extra outputs copied from front */ | 1950 | /* extra outputs copied from front */ |
@@ -1984,7 +2012,7 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) | |||
1984 | * in the order of front, rear, CLFE, side, ... | 2012 | * in the order of front, rear, CLFE, side, ... |
1985 | * | 2013 | * |
1986 | * If more extra outputs (speaker and headphone) are found, the pins are | 2014 | * If more extra outputs (speaker and headphone) are found, the pins are |
1987 | * assisnged to hp_pin and speaker_pins[], respectively. If no line-out jack | 2015 | * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack |
1988 | * is detected, one of speaker of HP pins is assigned as the primary | 2016 | * is detected, one of speaker of HP pins is assigned as the primary |
1989 | * output, i.e. to line_out_pins[0]. So, line_outs is always positive | 2017 | * output, i.e. to line_out_pins[0]. So, line_outs is always positive |
1990 | * if any analog output exists. | 2018 | * if any analog output exists. |
@@ -2046,14 +2074,26 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c | |||
2046 | cfg->speaker_outs++; | 2074 | cfg->speaker_outs++; |
2047 | break; | 2075 | break; |
2048 | case AC_JACK_HP_OUT: | 2076 | case AC_JACK_HP_OUT: |
2049 | cfg->hp_pin = nid; | 2077 | if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) |
2078 | continue; | ||
2079 | cfg->hp_pins[cfg->hp_outs] = nid; | ||
2080 | cfg->hp_outs++; | ||
2050 | break; | 2081 | break; |
2051 | case AC_JACK_MIC_IN: | 2082 | case AC_JACK_MIC_IN: { |
2052 | if (loc == AC_JACK_LOC_FRONT) | 2083 | int preferred, alt; |
2053 | cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid; | 2084 | if (loc == AC_JACK_LOC_FRONT) { |
2054 | else | 2085 | preferred = AUTO_PIN_FRONT_MIC; |
2055 | cfg->input_pins[AUTO_PIN_MIC] = nid; | 2086 | alt = AUTO_PIN_MIC; |
2087 | } else { | ||
2088 | preferred = AUTO_PIN_MIC; | ||
2089 | alt = AUTO_PIN_FRONT_MIC; | ||
2090 | } | ||
2091 | if (!cfg->input_pins[preferred]) | ||
2092 | cfg->input_pins[preferred] = nid; | ||
2093 | else if (!cfg->input_pins[alt]) | ||
2094 | cfg->input_pins[alt] = nid; | ||
2056 | break; | 2095 | break; |
2096 | } | ||
2057 | case AC_JACK_LINE_IN: | 2097 | case AC_JACK_LINE_IN: |
2058 | if (loc == AC_JACK_LOC_FRONT) | 2098 | if (loc == AC_JACK_LOC_FRONT) |
2059 | cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; | 2099 | cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; |
@@ -2119,8 +2159,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c | |||
2119 | cfg->speaker_outs, cfg->speaker_pins[0], | 2159 | cfg->speaker_outs, cfg->speaker_pins[0], |
2120 | cfg->speaker_pins[1], cfg->speaker_pins[2], | 2160 | cfg->speaker_pins[1], cfg->speaker_pins[2], |
2121 | cfg->speaker_pins[3], cfg->speaker_pins[4]); | 2161 | cfg->speaker_pins[3], cfg->speaker_pins[4]); |
2122 | snd_printd(" hp=0x%x, dig_out=0x%x, din_in=0x%x\n", | 2162 | snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", |
2123 | cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin); | 2163 | cfg->hp_outs, cfg->hp_pins[0], |
2164 | cfg->hp_pins[1], cfg->hp_pins[2], | ||
2165 | cfg->hp_pins[3], cfg->hp_pins[4]); | ||
2124 | snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," | 2166 | snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," |
2125 | " cd=0x%x, aux=0x%x\n", | 2167 | " cd=0x%x, aux=0x%x\n", |
2126 | cfg->input_pins[AUTO_PIN_MIC], | 2168 | cfg->input_pins[AUTO_PIN_MIC], |
@@ -2141,10 +2183,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c | |||
2141 | sizeof(cfg->speaker_pins)); | 2183 | sizeof(cfg->speaker_pins)); |
2142 | cfg->speaker_outs = 0; | 2184 | cfg->speaker_outs = 0; |
2143 | memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); | 2185 | memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); |
2144 | } else if (cfg->hp_pin) { | 2186 | } else if (cfg->hp_outs) { |
2145 | cfg->line_outs = 1; | 2187 | cfg->line_outs = cfg->hp_outs; |
2146 | cfg->line_out_pins[0] = cfg->hp_pin; | 2188 | memcpy(cfg->line_out_pins, cfg->hp_pins, |
2147 | cfg->hp_pin = 0; | 2189 | sizeof(cfg->hp_pins)); |
2190 | cfg->hp_outs = 0; | ||
2191 | memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); | ||
2148 | } | 2192 | } |
2149 | } | 2193 | } |
2150 | 2194 | ||
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 40520e9d5a4b..c12bc4e8840f 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -479,7 +479,7 @@ struct hda_codec_ops { | |||
479 | struct hda_amp_info { | 479 | struct hda_amp_info { |
480 | u32 key; /* hash key */ | 480 | u32 key; /* hash key */ |
481 | u32 amp_caps; /* amp capabilities */ | 481 | u32 amp_caps; /* amp capabilities */ |
482 | u16 vol[2]; /* current volume & mute*/ | 482 | u16 vol[2]; /* current volume & mute */ |
483 | u16 status; /* update flag */ | 483 | u16 status; /* update flag */ |
484 | u16 next; /* next link */ | 484 | u16 next; /* next link */ |
485 | }; | 485 | }; |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 85ad164ada59..97e9af130b71 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -46,11 +46,18 @@ struct hda_gnode { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | /* patch-specific record */ | 48 | /* patch-specific record */ |
49 | |||
50 | #define MAX_PCM_VOLS 2 | ||
51 | struct pcm_vol { | ||
52 | struct hda_gnode *node; /* Node for PCM volume */ | ||
53 | unsigned int index; /* connection of PCM volume */ | ||
54 | }; | ||
55 | |||
49 | struct hda_gspec { | 56 | struct hda_gspec { |
50 | struct hda_gnode *dac_node[2]; /* DAC node */ | 57 | struct hda_gnode *dac_node[2]; /* DAC node */ |
51 | struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ | 58 | struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ |
52 | struct hda_gnode *pcm_vol_node[2]; /* Node for PCM volume */ | 59 | struct pcm_vol pcm_vol[MAX_PCM_VOLS]; /* PCM volumes */ |
53 | unsigned int pcm_vol_index[2]; /* connection of PCM volume */ | 60 | unsigned int pcm_vol_nodes; /* number of PCM volumes */ |
54 | 61 | ||
55 | struct hda_gnode *adc_node; /* ADC node */ | 62 | struct hda_gnode *adc_node; /* ADC node */ |
56 | struct hda_gnode *cap_vol_node; /* Node for capture volume */ | 63 | struct hda_gnode *cap_vol_node; /* Node for capture volume */ |
@@ -285,9 +292,11 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, | |||
285 | return node == spec->dac_node[dac_idx]; | 292 | return node == spec->dac_node[dac_idx]; |
286 | } | 293 | } |
287 | spec->dac_node[dac_idx] = node; | 294 | spec->dac_node[dac_idx] = node; |
288 | if (node->wid_caps & AC_WCAP_OUT_AMP) { | 295 | if ((node->wid_caps & AC_WCAP_OUT_AMP) && |
289 | spec->pcm_vol_node[dac_idx] = node; | 296 | spec->pcm_vol_nodes < MAX_PCM_VOLS) { |
290 | spec->pcm_vol_index[dac_idx] = 0; | 297 | spec->pcm_vol[spec->pcm_vol_nodes].node = node; |
298 | spec->pcm_vol[spec->pcm_vol_nodes].index = 0; | ||
299 | spec->pcm_vol_nodes++; | ||
291 | } | 300 | } |
292 | return 1; /* found */ | 301 | return 1; /* found */ |
293 | } | 302 | } |
@@ -307,13 +316,16 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, | |||
307 | select_input_connection(codec, node, i); | 316 | select_input_connection(codec, node, i); |
308 | unmute_input(codec, node, i); | 317 | unmute_input(codec, node, i); |
309 | unmute_output(codec, node); | 318 | unmute_output(codec, node); |
310 | if (! spec->pcm_vol_node[dac_idx]) { | 319 | if (spec->dac_node[dac_idx] && |
311 | if (node->wid_caps & AC_WCAP_IN_AMP) { | 320 | spec->pcm_vol_nodes < MAX_PCM_VOLS && |
312 | spec->pcm_vol_node[dac_idx] = node; | 321 | !(spec->dac_node[dac_idx]->wid_caps & |
313 | spec->pcm_vol_index[dac_idx] = i; | 322 | AC_WCAP_OUT_AMP)) { |
314 | } else if (node->wid_caps & AC_WCAP_OUT_AMP) { | 323 | if ((node->wid_caps & AC_WCAP_IN_AMP) || |
315 | spec->pcm_vol_node[dac_idx] = node; | 324 | (node->wid_caps & AC_WCAP_OUT_AMP)) { |
316 | spec->pcm_vol_index[dac_idx] = 0; | 325 | int n = spec->pcm_vol_nodes; |
326 | spec->pcm_vol[n].node = node; | ||
327 | spec->pcm_vol[n].index = i; | ||
328 | spec->pcm_vol_nodes++; | ||
317 | } | 329 | } |
318 | } | 330 | } |
319 | return 1; | 331 | return 1; |
@@ -370,7 +382,9 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, | |||
370 | /* set PIN-Out enable */ | 382 | /* set PIN-Out enable */ |
371 | snd_hda_codec_write(codec, node->nid, 0, | 383 | snd_hda_codec_write(codec, node->nid, 0, |
372 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 384 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
373 | AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | 385 | AC_PINCTL_OUT_EN | |
386 | ((node->pin_caps & AC_PINCAP_HP_DRV) ? | ||
387 | AC_PINCTL_HP_EN : 0)); | ||
374 | return node; | 388 | return node; |
375 | } | 389 | } |
376 | } | 390 | } |
@@ -461,14 +475,19 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) | |||
461 | return "Front Line"; | 475 | return "Front Line"; |
462 | return "Line"; | 476 | return "Line"; |
463 | case AC_JACK_CD: | 477 | case AC_JACK_CD: |
478 | #if 0 | ||
464 | if (pinctl) | 479 | if (pinctl) |
465 | *pinctl |= AC_PINCTL_VREF_GRD; | 480 | *pinctl |= AC_PINCTL_VREF_GRD; |
481 | #endif | ||
466 | return "CD"; | 482 | return "CD"; |
467 | case AC_JACK_AUX: | 483 | case AC_JACK_AUX: |
468 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | 484 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
469 | return "Front Aux"; | 485 | return "Front Aux"; |
470 | return "Aux"; | 486 | return "Aux"; |
471 | case AC_JACK_MIC_IN: | 487 | case AC_JACK_MIC_IN: |
488 | if (node->pin_caps & | ||
489 | (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT)) | ||
490 | *pinctl |= AC_PINCTL_VREF_80; | ||
472 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | 491 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
473 | return "Front Mic"; | 492 | return "Front Mic"; |
474 | return "Mic"; | 493 | return "Mic"; |
@@ -556,6 +575,29 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, | |||
556 | return 1; /* found */ | 575 | return 1; /* found */ |
557 | } | 576 | } |
558 | 577 | ||
578 | /* add a capture source element */ | ||
579 | static void add_cap_src(struct hda_gspec *spec, int idx) | ||
580 | { | ||
581 | struct hda_input_mux_item *csrc; | ||
582 | char *buf; | ||
583 | int num, ocap; | ||
584 | |||
585 | num = spec->input_mux.num_items; | ||
586 | csrc = &spec->input_mux.items[num]; | ||
587 | buf = spec->cap_labels[num]; | ||
588 | for (ocap = 0; ocap < num; ocap++) { | ||
589 | if (! strcmp(buf, spec->cap_labels[ocap])) { | ||
590 | /* same label already exists, | ||
591 | * put the index number to be unique | ||
592 | */ | ||
593 | sprintf(buf, "%s %d", spec->cap_labels[ocap], num); | ||
594 | break; | ||
595 | } | ||
596 | } | ||
597 | csrc->index = idx; | ||
598 | spec->input_mux.num_items++; | ||
599 | } | ||
600 | |||
559 | /* | 601 | /* |
560 | * parse input | 602 | * parse input |
561 | */ | 603 | */ |
@@ -576,28 +618,26 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) | |||
576 | * if it reaches to a proper input PIN, add the path as the | 618 | * if it reaches to a proper input PIN, add the path as the |
577 | * input path. | 619 | * input path. |
578 | */ | 620 | */ |
621 | /* first, check the direct connections to PIN widgets */ | ||
579 | for (i = 0; i < adc_node->nconns; i++) { | 622 | for (i = 0; i < adc_node->nconns; i++) { |
580 | node = hda_get_node(spec, adc_node->conn_list[i]); | 623 | node = hda_get_node(spec, adc_node->conn_list[i]); |
581 | if (! node) | 624 | if (node && node->type == AC_WID_PIN) { |
582 | continue; | 625 | err = parse_adc_sub_nodes(codec, spec, node); |
583 | err = parse_adc_sub_nodes(codec, spec, node); | 626 | if (err < 0) |
584 | if (err < 0) | 627 | return err; |
585 | return err; | 628 | else if (err > 0) |
586 | else if (err > 0) { | 629 | add_cap_src(spec, i); |
587 | struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items]; | 630 | } |
588 | char *buf = spec->cap_labels[spec->input_mux.num_items]; | 631 | } |
589 | int ocap; | 632 | /* ... then check the rests, more complicated connections */ |
590 | for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) { | 633 | for (i = 0; i < adc_node->nconns; i++) { |
591 | if (! strcmp(buf, spec->cap_labels[ocap])) { | 634 | node = hda_get_node(spec, adc_node->conn_list[i]); |
592 | /* same label already exists, | 635 | if (node && node->type != AC_WID_PIN) { |
593 | * put the index number to be unique | 636 | err = parse_adc_sub_nodes(codec, spec, node); |
594 | */ | 637 | if (err < 0) |
595 | sprintf(buf, "%s %d", spec->cap_labels[ocap], | 638 | return err; |
596 | spec->input_mux.num_items); | 639 | else if (err > 0) |
597 | } | 640 | add_cap_src(spec, i); |
598 | } | ||
599 | csrc->index = i; | ||
600 | spec->input_mux.num_items++; | ||
601 | } | 641 | } |
602 | } | 642 | } |
603 | 643 | ||
@@ -647,9 +687,6 @@ static int parse_input(struct hda_codec *codec) | |||
647 | /* | 687 | /* |
648 | * create mixer controls if possible | 688 | * create mixer controls if possible |
649 | */ | 689 | */ |
650 | #define DIR_OUT 0x1 | ||
651 | #define DIR_IN 0x2 | ||
652 | |||
653 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, | 690 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, |
654 | unsigned int index, const char *type, const char *dir_sfx) | 691 | unsigned int index, const char *type, const char *dir_sfx) |
655 | { | 692 | { |
@@ -722,49 +759,97 @@ static int check_existing_control(struct hda_codec *codec, const char *type, con | |||
722 | /* | 759 | /* |
723 | * build output mixer controls | 760 | * build output mixer controls |
724 | */ | 761 | */ |
725 | static int build_output_controls(struct hda_codec *codec) | 762 | static int create_output_mixers(struct hda_codec *codec, const char **names) |
726 | { | 763 | { |
727 | struct hda_gspec *spec = codec->spec; | 764 | struct hda_gspec *spec = codec->spec; |
728 | static const char *types[2] = { "Master", "Headphone" }; | ||
729 | int i, err; | 765 | int i, err; |
730 | 766 | ||
731 | for (i = 0; i < 2 && spec->pcm_vol_node[i]; i++) { | 767 | for (i = 0; i < spec->pcm_vol_nodes; i++) { |
732 | err = create_mixer(codec, spec->pcm_vol_node[i], | 768 | err = create_mixer(codec, spec->pcm_vol[i].node, |
733 | spec->pcm_vol_index[i], | 769 | spec->pcm_vol[i].index, |
734 | types[i], "Playback"); | 770 | names[i], "Playback"); |
735 | if (err < 0) | 771 | if (err < 0) |
736 | return err; | 772 | return err; |
737 | } | 773 | } |
738 | return 0; | 774 | return 0; |
739 | } | 775 | } |
740 | 776 | ||
777 | static int build_output_controls(struct hda_codec *codec) | ||
778 | { | ||
779 | struct hda_gspec *spec = codec->spec; | ||
780 | static const char *types_speaker[] = { "Speaker", "Headphone" }; | ||
781 | static const char *types_line[] = { "Front", "Headphone" }; | ||
782 | |||
783 | switch (spec->pcm_vol_nodes) { | ||
784 | case 1: | ||
785 | return create_mixer(codec, spec->pcm_vol[0].node, | ||
786 | spec->pcm_vol[0].index, | ||
787 | "Master", "Playback"); | ||
788 | case 2: | ||
789 | if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) | ||
790 | return create_output_mixers(codec, types_speaker); | ||
791 | else | ||
792 | return create_output_mixers(codec, types_line); | ||
793 | } | ||
794 | return 0; | ||
795 | } | ||
796 | |||
741 | /* create capture volume/switch */ | 797 | /* create capture volume/switch */ |
742 | static int build_input_controls(struct hda_codec *codec) | 798 | static int build_input_controls(struct hda_codec *codec) |
743 | { | 799 | { |
744 | struct hda_gspec *spec = codec->spec; | 800 | struct hda_gspec *spec = codec->spec; |
745 | struct hda_gnode *adc_node = spec->adc_node; | 801 | struct hda_gnode *adc_node = spec->adc_node; |
746 | int err; | 802 | int i, err; |
747 | 803 | static struct snd_kcontrol_new cap_sel = { | |
748 | if (! adc_node) | 804 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
805 | .name = "Capture Source", | ||
806 | .info = capture_source_info, | ||
807 | .get = capture_source_get, | ||
808 | .put = capture_source_put, | ||
809 | }; | ||
810 | |||
811 | if (! adc_node || ! spec->input_mux.num_items) | ||
749 | return 0; /* not found */ | 812 | return 0; /* not found */ |
750 | 813 | ||
814 | spec->cur_cap_src = 0; | ||
815 | select_input_connection(codec, adc_node, | ||
816 | spec->input_mux.items[0].index); | ||
817 | |||
751 | /* create capture volume and switch controls if the ADC has an amp */ | 818 | /* create capture volume and switch controls if the ADC has an amp */ |
752 | err = create_mixer(codec, adc_node, 0, NULL, "Capture"); | 819 | /* do we have only a single item? */ |
820 | if (spec->input_mux.num_items == 1) { | ||
821 | err = create_mixer(codec, adc_node, | ||
822 | spec->input_mux.items[0].index, | ||
823 | NULL, "Capture"); | ||
824 | if (err < 0) | ||
825 | return err; | ||
826 | return 0; | ||
827 | } | ||
753 | 828 | ||
754 | /* create input MUX if multiple sources are available */ | 829 | /* create input MUX if multiple sources are available */ |
755 | if (spec->input_mux.num_items > 1) { | 830 | if ((err = snd_ctl_add(codec->bus->card, |
756 | static struct snd_kcontrol_new cap_sel = { | 831 | snd_ctl_new1(&cap_sel, codec))) < 0) |
757 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 832 | return err; |
758 | .name = "Capture Source", | 833 | |
759 | .info = capture_source_info, | 834 | /* no volume control? */ |
760 | .get = capture_source_get, | 835 | if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) || |
761 | .put = capture_source_put, | 836 | ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) |
762 | }; | 837 | return 0; |
763 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0) | 838 | |
839 | for (i = 0; i < spec->input_mux.num_items; i++) { | ||
840 | struct snd_kcontrol_new knew; | ||
841 | char name[32]; | ||
842 | sprintf(name, "%s Capture Volume", | ||
843 | spec->input_mux.items[i].label); | ||
844 | knew = (struct snd_kcontrol_new) | ||
845 | HDA_CODEC_VOLUME(name, adc_node->nid, | ||
846 | spec->input_mux.items[i].index, | ||
847 | HDA_INPUT); | ||
848 | if ((err = snd_ctl_add(codec->bus->card, | ||
849 | snd_ctl_new1(&knew, codec))) < 0) | ||
764 | return err; | 850 | return err; |
765 | spec->cur_cap_src = 0; | ||
766 | select_input_connection(codec, adc_node, spec->input_mux.items[0].index); | ||
767 | } | 851 | } |
852 | |||
768 | return 0; | 853 | return 0; |
769 | } | 854 | } |
770 | 855 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 79d63c99f092..e9d4cb4d07e1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -55,6 +55,7 @@ static char *model; | |||
55 | static int position_fix; | 55 | static int position_fix; |
56 | static int probe_mask = -1; | 56 | static int probe_mask = -1; |
57 | static int single_cmd; | 57 | static int single_cmd; |
58 | static int disable_msi; | ||
58 | 59 | ||
59 | module_param(index, int, 0444); | 60 | module_param(index, int, 0444); |
60 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); | 61 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); |
@@ -68,6 +69,8 @@ module_param(probe_mask, int, 0444); | |||
68 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); | 69 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); |
69 | module_param(single_cmd, bool, 0444); | 70 | module_param(single_cmd, bool, 0444); |
70 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); | 71 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); |
72 | module_param(disable_msi, int, 0); | ||
73 | MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); | ||
71 | 74 | ||
72 | 75 | ||
73 | /* just for backward compatibility */ | 76 | /* just for backward compatibility */ |
@@ -252,7 +255,7 @@ enum { | |||
252 | struct azx_dev { | 255 | struct azx_dev { |
253 | u32 *bdl; /* virtual address of the BDL */ | 256 | u32 *bdl; /* virtual address of the BDL */ |
254 | dma_addr_t bdl_addr; /* physical address of the BDL */ | 257 | dma_addr_t bdl_addr; /* physical address of the BDL */ |
255 | volatile u32 *posbuf; /* position buffer pointer */ | 258 | u32 *posbuf; /* position buffer pointer */ |
256 | 259 | ||
257 | unsigned int bufsize; /* size of the play buffer in bytes */ | 260 | unsigned int bufsize; /* size of the play buffer in bytes */ |
258 | unsigned int fragsize; /* size of each period in bytes */ | 261 | unsigned int fragsize; /* size of each period in bytes */ |
@@ -271,8 +274,8 @@ struct azx_dev { | |||
271 | /* for sanity check of position buffer */ | 274 | /* for sanity check of position buffer */ |
272 | unsigned int period_intr; | 275 | unsigned int period_intr; |
273 | 276 | ||
274 | unsigned int opened: 1; | 277 | unsigned int opened :1; |
275 | unsigned int running: 1; | 278 | unsigned int running :1; |
276 | }; | 279 | }; |
277 | 280 | ||
278 | /* CORB/RIRB */ | 281 | /* CORB/RIRB */ |
@@ -330,8 +333,9 @@ struct azx { | |||
330 | 333 | ||
331 | /* flags */ | 334 | /* flags */ |
332 | int position_fix; | 335 | int position_fix; |
333 | unsigned int initialized: 1; | 336 | unsigned int initialized :1; |
334 | unsigned int single_cmd: 1; | 337 | unsigned int single_cmd :1; |
338 | unsigned int polling_mode :1; | ||
335 | }; | 339 | }; |
336 | 340 | ||
337 | /* driver types */ | 341 | /* driver types */ |
@@ -516,23 +520,36 @@ static void azx_update_rirb(struct azx *chip) | |||
516 | static unsigned int azx_rirb_get_response(struct hda_codec *codec) | 520 | static unsigned int azx_rirb_get_response(struct hda_codec *codec) |
517 | { | 521 | { |
518 | struct azx *chip = codec->bus->private_data; | 522 | struct azx *chip = codec->bus->private_data; |
519 | int timeout = 50; | 523 | unsigned long timeout; |
520 | 524 | ||
521 | while (chip->rirb.cmds) { | 525 | again: |
522 | if (! --timeout) { | 526 | timeout = jiffies + msecs_to_jiffies(1000); |
523 | snd_printk(KERN_ERR | 527 | do { |
524 | "hda_intel: azx_get_response timeout, " | 528 | if (chip->polling_mode) { |
525 | "switching to single_cmd mode...\n"); | 529 | spin_lock_irq(&chip->reg_lock); |
526 | chip->rirb.rp = azx_readb(chip, RIRBWP); | 530 | azx_update_rirb(chip); |
527 | chip->rirb.cmds = 0; | 531 | spin_unlock_irq(&chip->reg_lock); |
528 | /* switch to single_cmd mode */ | ||
529 | chip->single_cmd = 1; | ||
530 | azx_free_cmd_io(chip); | ||
531 | return -1; | ||
532 | } | 532 | } |
533 | msleep(1); | 533 | if (! chip->rirb.cmds) |
534 | return chip->rirb.res; /* the last value */ | ||
535 | schedule_timeout_interruptible(1); | ||
536 | } while (time_after_eq(timeout, jiffies)); | ||
537 | |||
538 | if (!chip->polling_mode) { | ||
539 | snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, " | ||
540 | "switching to polling mode...\n"); | ||
541 | chip->polling_mode = 1; | ||
542 | goto again; | ||
534 | } | 543 | } |
535 | return chip->rirb.res; /* the last value */ | 544 | |
545 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " | ||
546 | "switching to single_cmd mode...\n"); | ||
547 | chip->rirb.rp = azx_readb(chip, RIRBWP); | ||
548 | chip->rirb.cmds = 0; | ||
549 | /* switch to single_cmd mode */ | ||
550 | chip->single_cmd = 1; | ||
551 | azx_free_cmd_io(chip); | ||
552 | return -1; | ||
536 | } | 553 | } |
537 | 554 | ||
538 | /* | 555 | /* |
@@ -642,14 +659,14 @@ static int azx_reset(struct azx *chip) | |||
642 | azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); | 659 | azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); |
643 | 660 | ||
644 | count = 50; | 661 | count = 50; |
645 | while (! azx_readb(chip, GCTL) && --count) | 662 | while (!azx_readb(chip, GCTL) && --count) |
646 | msleep(1); | 663 | msleep(1); |
647 | 664 | ||
648 | /* Brent Chartrand said to wait >= 540us for codecs to intialize */ | 665 | /* Brent Chartrand said to wait >= 540us for codecs to initialize */ |
649 | msleep(1); | 666 | msleep(1); |
650 | 667 | ||
651 | /* check to see if controller is ready */ | 668 | /* check to see if controller is ready */ |
652 | if (! azx_readb(chip, GCTL)) { | 669 | if (!azx_readb(chip, GCTL)) { |
653 | snd_printd("azx_reset: controller not ready!\n"); | 670 | snd_printd("azx_reset: controller not ready!\n"); |
654 | return -EBUSY; | 671 | return -EBUSY; |
655 | } | 672 | } |
@@ -658,7 +675,7 @@ static int azx_reset(struct azx *chip) | |||
658 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN); | 675 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN); |
659 | 676 | ||
660 | /* detect codecs */ | 677 | /* detect codecs */ |
661 | if (! chip->codec_mask) { | 678 | if (!chip->codec_mask) { |
662 | chip->codec_mask = azx_readw(chip, STATESTS); | 679 | chip->codec_mask = azx_readw(chip, STATESTS); |
663 | snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); | 680 | snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); |
664 | } | 681 | } |
@@ -766,7 +783,7 @@ static void azx_init_chip(struct azx *chip) | |||
766 | azx_int_enable(chip); | 783 | azx_int_enable(chip); |
767 | 784 | ||
768 | /* initialize the codec command I/O */ | 785 | /* initialize the codec command I/O */ |
769 | if (! chip->single_cmd) | 786 | if (!chip->single_cmd) |
770 | azx_init_cmd_io(chip); | 787 | azx_init_cmd_io(chip); |
771 | 788 | ||
772 | /* program the position buffer */ | 789 | /* program the position buffer */ |
@@ -794,7 +811,7 @@ static void azx_init_chip(struct azx *chip) | |||
794 | /* | 811 | /* |
795 | * interrupt handler | 812 | * interrupt handler |
796 | */ | 813 | */ |
797 | static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs) | 814 | static irqreturn_t azx_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
798 | { | 815 | { |
799 | struct azx *chip = dev_id; | 816 | struct azx *chip = dev_id; |
800 | struct azx_dev *azx_dev; | 817 | struct azx_dev *azx_dev; |
@@ -999,8 +1016,9 @@ static struct snd_pcm_hardware azx_pcm_hw = { | |||
999 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1016 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1000 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 1017 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
1001 | SNDRV_PCM_INFO_MMAP_VALID | | 1018 | SNDRV_PCM_INFO_MMAP_VALID | |
1002 | SNDRV_PCM_INFO_PAUSE /*|*/ | 1019 | /* No full-resume yet implemented */ |
1003 | /*SNDRV_PCM_INFO_RESUME*/), | 1020 | /* SNDRV_PCM_INFO_RESUME |*/ |
1021 | SNDRV_PCM_INFO_PAUSE), | ||
1004 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1022 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
1005 | .rates = SNDRV_PCM_RATE_48000, | 1023 | .rates = SNDRV_PCM_RATE_48000, |
1006 | .rate_min = 48000, | 1024 | .rate_min = 48000, |
@@ -1178,7 +1196,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | |||
1178 | if (chip->position_fix == POS_FIX_POSBUF || | 1196 | if (chip->position_fix == POS_FIX_POSBUF || |
1179 | chip->position_fix == POS_FIX_AUTO) { | 1197 | chip->position_fix == POS_FIX_AUTO) { |
1180 | /* use the position buffer */ | 1198 | /* use the position buffer */ |
1181 | pos = *azx_dev->posbuf; | 1199 | pos = le32_to_cpu(*azx_dev->posbuf); |
1182 | if (chip->position_fix == POS_FIX_AUTO && | 1200 | if (chip->position_fix == POS_FIX_AUTO && |
1183 | azx_dev->period_intr == 1 && ! pos) { | 1201 | azx_dev->period_intr == 1 && ! pos) { |
1184 | printk(KERN_WARNING | 1202 | printk(KERN_WARNING |
@@ -1222,7 +1240,12 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, | |||
1222 | struct snd_pcm *pcm; | 1240 | struct snd_pcm *pcm; |
1223 | struct azx_pcm *apcm; | 1241 | struct azx_pcm *apcm; |
1224 | 1242 | ||
1225 | snd_assert(cpcm->stream[0].substreams || cpcm->stream[1].substreams, return -EINVAL); | 1243 | /* if no substreams are defined for both playback and capture, |
1244 | * it's just a placeholder. ignore it. | ||
1245 | */ | ||
1246 | if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) | ||
1247 | return 0; | ||
1248 | |||
1226 | snd_assert(cpcm->name, return -EINVAL); | 1249 | snd_assert(cpcm->name, return -EINVAL); |
1227 | 1250 | ||
1228 | err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, | 1251 | err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, |
@@ -1248,7 +1271,8 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, | |||
1248 | snd_dma_pci_data(chip->pci), | 1271 | snd_dma_pci_data(chip->pci), |
1249 | 1024 * 64, 1024 * 128); | 1272 | 1024 * 64, 1024 * 128); |
1250 | chip->pcm[pcm_dev] = pcm; | 1273 | chip->pcm[pcm_dev] = pcm; |
1251 | chip->pcm_devs = pcm_dev + 1; | 1274 | if (chip->pcm_devs < pcm_dev + 1) |
1275 | chip->pcm_devs = pcm_dev + 1; | ||
1252 | 1276 | ||
1253 | return 0; | 1277 | return 0; |
1254 | } | 1278 | } |
@@ -1326,7 +1350,7 @@ static int __devinit azx_init_stream(struct azx *chip) | |||
1326 | struct azx_dev *azx_dev = &chip->azx_dev[i]; | 1350 | struct azx_dev *azx_dev = &chip->azx_dev[i]; |
1327 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); | 1351 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); |
1328 | azx_dev->bdl_addr = chip->bdl.addr + off; | 1352 | azx_dev->bdl_addr = chip->bdl.addr + off; |
1329 | azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); | 1353 | azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); |
1330 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ | 1354 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ |
1331 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); | 1355 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); |
1332 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ | 1356 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ |
@@ -1355,6 +1379,10 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
1355 | snd_pcm_suspend_all(chip->pcm[i]); | 1379 | snd_pcm_suspend_all(chip->pcm[i]); |
1356 | snd_hda_suspend(chip->bus, state); | 1380 | snd_hda_suspend(chip->bus, state); |
1357 | azx_free_cmd_io(chip); | 1381 | azx_free_cmd_io(chip); |
1382 | if (chip->irq >= 0) | ||
1383 | free_irq(chip->irq, chip); | ||
1384 | if (!disable_msi) | ||
1385 | pci_disable_msi(chip->pci); | ||
1358 | pci_disable_device(pci); | 1386 | pci_disable_device(pci); |
1359 | pci_save_state(pci); | 1387 | pci_save_state(pci); |
1360 | return 0; | 1388 | return 0; |
@@ -1367,6 +1395,12 @@ static int azx_resume(struct pci_dev *pci) | |||
1367 | 1395 | ||
1368 | pci_restore_state(pci); | 1396 | pci_restore_state(pci); |
1369 | pci_enable_device(pci); | 1397 | pci_enable_device(pci); |
1398 | if (!disable_msi) | ||
1399 | pci_enable_msi(pci); | ||
1400 | /* FIXME: need proper error handling */ | ||
1401 | request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED, | ||
1402 | "HDA Intel", chip); | ||
1403 | chip->irq = pci->irq; | ||
1370 | pci_set_master(pci); | 1404 | pci_set_master(pci); |
1371 | azx_init_chip(chip); | 1405 | azx_init_chip(chip); |
1372 | snd_hda_resume(chip->bus); | 1406 | snd_hda_resume(chip->bus); |
@@ -1398,12 +1432,14 @@ static int azx_free(struct azx *chip) | |||
1398 | azx_writel(chip, DPLBASE, 0); | 1432 | azx_writel(chip, DPLBASE, 0); |
1399 | azx_writel(chip, DPUBASE, 0); | 1433 | azx_writel(chip, DPUBASE, 0); |
1400 | 1434 | ||
1401 | /* wait a little for interrupts to finish */ | 1435 | synchronize_irq(chip->irq); |
1402 | msleep(1); | ||
1403 | } | 1436 | } |
1404 | 1437 | ||
1405 | if (chip->irq >= 0) | 1438 | if (chip->irq >= 0) { |
1406 | free_irq(chip->irq, (void*)chip); | 1439 | free_irq(chip->irq, (void*)chip); |
1440 | if (!disable_msi) | ||
1441 | pci_disable_msi(chip->pci); | ||
1442 | } | ||
1407 | if (chip->remap_addr) | 1443 | if (chip->remap_addr) |
1408 | iounmap(chip->remap_addr); | 1444 | iounmap(chip->remap_addr); |
1409 | 1445 | ||
@@ -1434,19 +1470,19 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1434 | struct azx **rchip) | 1470 | struct azx **rchip) |
1435 | { | 1471 | { |
1436 | struct azx *chip; | 1472 | struct azx *chip; |
1437 | int err = 0; | 1473 | int err; |
1438 | static struct snd_device_ops ops = { | 1474 | static struct snd_device_ops ops = { |
1439 | .dev_free = azx_dev_free, | 1475 | .dev_free = azx_dev_free, |
1440 | }; | 1476 | }; |
1441 | 1477 | ||
1442 | *rchip = NULL; | 1478 | *rchip = NULL; |
1443 | 1479 | ||
1444 | if ((err = pci_enable_device(pci)) < 0) | 1480 | err = pci_enable_device(pci); |
1481 | if (err < 0) | ||
1445 | return err; | 1482 | return err; |
1446 | 1483 | ||
1447 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 1484 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
1448 | 1485 | if (!chip) { | |
1449 | if (NULL == chip) { | ||
1450 | snd_printk(KERN_ERR SFX "cannot allocate chip\n"); | 1486 | snd_printk(KERN_ERR SFX "cannot allocate chip\n"); |
1451 | pci_disable_device(pci); | 1487 | pci_disable_device(pci); |
1452 | return -ENOMEM; | 1488 | return -ENOMEM; |
@@ -1472,13 +1508,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1472 | } | 1508 | } |
1473 | #endif | 1509 | #endif |
1474 | 1510 | ||
1475 | if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) { | 1511 | err = pci_request_regions(pci, "ICH HD audio"); |
1512 | if (err < 0) { | ||
1476 | kfree(chip); | 1513 | kfree(chip); |
1477 | pci_disable_device(pci); | 1514 | pci_disable_device(pci); |
1478 | return err; | 1515 | return err; |
1479 | } | 1516 | } |
1480 | 1517 | ||
1481 | chip->addr = pci_resource_start(pci,0); | 1518 | chip->addr = pci_resource_start(pci, 0); |
1482 | chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0)); | 1519 | chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0)); |
1483 | if (chip->remap_addr == NULL) { | 1520 | if (chip->remap_addr == NULL) { |
1484 | snd_printk(KERN_ERR SFX "ioremap error\n"); | 1521 | snd_printk(KERN_ERR SFX "ioremap error\n"); |
@@ -1486,6 +1523,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1486 | goto errout; | 1523 | goto errout; |
1487 | } | 1524 | } |
1488 | 1525 | ||
1526 | if (!disable_msi) | ||
1527 | pci_enable_msi(pci); | ||
1528 | |||
1489 | if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED, | 1529 | if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED, |
1490 | "HDA Intel", (void*)chip)) { | 1530 | "HDA Intel", (void*)chip)) { |
1491 | snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); | 1531 | snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); |
@@ -1519,7 +1559,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1519 | } | 1559 | } |
1520 | chip->num_streams = chip->playback_streams + chip->capture_streams; | 1560 | chip->num_streams = chip->playback_streams + chip->capture_streams; |
1521 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); | 1561 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); |
1522 | if (! chip->azx_dev) { | 1562 | if (!chip->azx_dev) { |
1523 | snd_printk(KERN_ERR "cannot malloc azx_dev\n"); | 1563 | snd_printk(KERN_ERR "cannot malloc azx_dev\n"); |
1524 | goto errout; | 1564 | goto errout; |
1525 | } | 1565 | } |
@@ -1550,7 +1590,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1550 | chip->initialized = 1; | 1590 | chip->initialized = 1; |
1551 | 1591 | ||
1552 | /* codec detection */ | 1592 | /* codec detection */ |
1553 | if (! chip->codec_mask) { | 1593 | if (!chip->codec_mask) { |
1554 | snd_printk(KERN_ERR SFX "no codecs found!\n"); | 1594 | snd_printk(KERN_ERR SFX "no codecs found!\n"); |
1555 | err = -ENODEV; | 1595 | err = -ENODEV; |
1556 | goto errout; | 1596 | goto errout; |
@@ -1577,16 +1617,16 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * | |||
1577 | { | 1617 | { |
1578 | struct snd_card *card; | 1618 | struct snd_card *card; |
1579 | struct azx *chip; | 1619 | struct azx *chip; |
1580 | int err = 0; | 1620 | int err; |
1581 | 1621 | ||
1582 | card = snd_card_new(index, id, THIS_MODULE, 0); | 1622 | card = snd_card_new(index, id, THIS_MODULE, 0); |
1583 | if (NULL == card) { | 1623 | if (!card) { |
1584 | snd_printk(KERN_ERR SFX "Error creating card!\n"); | 1624 | snd_printk(KERN_ERR SFX "Error creating card!\n"); |
1585 | return -ENOMEM; | 1625 | return -ENOMEM; |
1586 | } | 1626 | } |
1587 | 1627 | ||
1588 | if ((err = azx_create(card, pci, pci_id->driver_data, | 1628 | err = azx_create(card, pci, pci_id->driver_data, &chip); |
1589 | &chip)) < 0) { | 1629 | if (err < 0) { |
1590 | snd_card_free(card); | 1630 | snd_card_free(card); |
1591 | return err; | 1631 | return err; |
1592 | } | 1632 | } |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 14e8aa2806ed..f9416c36396e 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -30,9 +30,13 @@ | |||
30 | /* mono volume with index (index=0,1,...) (channel=1,2) */ | 30 | /* mono volume with index (index=0,1,...) (channel=1,2) */ |
31 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 31 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
32 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 32 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
33 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
34 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
35 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | ||
33 | .info = snd_hda_mixer_amp_volume_info, \ | 36 | .info = snd_hda_mixer_amp_volume_info, \ |
34 | .get = snd_hda_mixer_amp_volume_get, \ | 37 | .get = snd_hda_mixer_amp_volume_get, \ |
35 | .put = snd_hda_mixer_amp_volume_put, \ | 38 | .put = snd_hda_mixer_amp_volume_put, \ |
39 | .tlv = { .c = snd_hda_mixer_amp_tlv }, \ | ||
36 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } | 40 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } |
37 | /* stereo volume with index */ | 41 | /* stereo volume with index */ |
38 | #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ | 42 | #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ |
@@ -63,6 +67,7 @@ | |||
63 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); | 67 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); |
64 | int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 68 | int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); |
65 | int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 69 | int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); |
70 | int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv); | ||
66 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); | 71 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); |
67 | int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 72 | int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); |
68 | int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 73 | int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); |
@@ -224,7 +229,8 @@ struct auto_pin_cfg { | |||
224 | hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ | 229 | hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ |
225 | int speaker_outs; | 230 | int speaker_outs; |
226 | hda_nid_t speaker_pins[5]; | 231 | hda_nid_t speaker_pins[5]; |
227 | hda_nid_t hp_pin; | 232 | int hp_outs; |
233 | hda_nid_t hp_pins[5]; | ||
228 | hda_nid_t input_pins[AUTO_PIN_LAST]; | 234 | hda_nid_t input_pins[AUTO_PIN_LAST]; |
229 | hda_nid_t dig_out_pin; | 235 | hda_nid_t dig_out_pin; |
230 | hda_nid_t dig_in_pin; | 236 | hda_nid_t dig_in_pin; |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c2f0fe85bf35..d737f17695a3 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -52,10 +52,9 @@ static void print_amp_caps(struct snd_info_buffer *buffer, | |||
52 | struct hda_codec *codec, hda_nid_t nid, int dir) | 52 | struct hda_codec *codec, hda_nid_t nid, int dir) |
53 | { | 53 | { |
54 | unsigned int caps; | 54 | unsigned int caps; |
55 | if (dir == HDA_OUTPUT) | 55 | caps = snd_hda_param_read(codec, nid, |
56 | caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP); | 56 | dir == HDA_OUTPUT ? |
57 | else | 57 | AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); |
58 | caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_IN_CAP); | ||
59 | if (caps == -1 || caps == 0) { | 58 | if (caps == -1 || caps == 0) { |
60 | snd_iprintf(buffer, "N/A\n"); | 59 | snd_iprintf(buffer, "N/A\n"); |
61 | return; | 60 | return; |
@@ -74,10 +73,7 @@ static void print_amp_vals(struct snd_info_buffer *buffer, | |||
74 | unsigned int val; | 73 | unsigned int val; |
75 | int i; | 74 | int i; |
76 | 75 | ||
77 | if (dir == HDA_OUTPUT) | 76 | dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; |
78 | dir = AC_AMP_GET_OUTPUT; | ||
79 | else | ||
80 | dir = AC_AMP_GET_INPUT; | ||
81 | for (i = 0; i < indices; i++) { | 77 | for (i = 0; i < indices; i++) { |
82 | snd_iprintf(buffer, " ["); | 78 | snd_iprintf(buffer, " ["); |
83 | if (stereo) { | 79 | if (stereo) { |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 6823f2bc10b3..511df07fa2a3 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -488,9 +488,13 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { | |||
488 | { | 488 | { |
489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
490 | .name = "PCM Playback Volume", | 490 | .name = "PCM Playback Volume", |
491 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
492 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | ||
493 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | ||
491 | .info = ad1986a_pcm_amp_vol_info, | 494 | .info = ad1986a_pcm_amp_vol_info, |
492 | .get = ad1986a_pcm_amp_vol_get, | 495 | .get = ad1986a_pcm_amp_vol_get, |
493 | .put = ad1986a_pcm_amp_vol_put, | 496 | .put = ad1986a_pcm_amp_vol_put, |
497 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
494 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | 498 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) |
495 | }, | 499 | }, |
496 | { | 500 | { |
@@ -637,6 +641,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
637 | .info = snd_hda_mixer_amp_volume_info, | 641 | .info = snd_hda_mixer_amp_volume_info, |
638 | .get = snd_hda_mixer_amp_volume_get, | 642 | .get = snd_hda_mixer_amp_volume_get, |
639 | .put = ad1986a_laptop_master_vol_put, | 643 | .put = ad1986a_laptop_master_vol_put, |
644 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
640 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | 645 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), |
641 | }, | 646 | }, |
642 | { | 647 | { |
@@ -791,6 +796,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { | |||
791 | .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ | 796 | .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ |
792 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, | 797 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, |
793 | .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ | 798 | .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ |
799 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb, | ||
800 | .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */ | ||
794 | { .modelname = "laptop", .config = AD1986A_LAPTOP }, | 801 | { .modelname = "laptop", .config = AD1986A_LAPTOP }, |
795 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, | 802 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, |
796 | .config = AD1986A_LAPTOP }, /* FSC V2060 */ | 803 | .config = AD1986A_LAPTOP }, /* FSC V2060 */ |
@@ -803,6 +810,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { | |||
803 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */ | 810 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */ |
804 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, | 811 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, |
805 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ | 812 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ |
813 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026, | ||
814 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung X10-T2300 Culesa */ | ||
806 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153, | 815 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153, |
807 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */ | 816 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */ |
808 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, | 817 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, |
@@ -1626,10 +1635,12 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
1626 | { | 1635 | { |
1627 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1636 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1628 | struct ad198x_spec *spec = codec->spec; | 1637 | struct ad198x_spec *spec = codec->spec; |
1629 | if (spec->need_dac_fix) | 1638 | int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, |
1639 | spec->num_channel_mode, | ||
1640 | &spec->multiout.max_channels); | ||
1641 | if (! err && spec->need_dac_fix) | ||
1630 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | 1642 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; |
1631 | return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, | 1643 | return err; |
1632 | spec->num_channel_mode, &spec->multiout.max_channels); | ||
1633 | } | 1644 | } |
1634 | 1645 | ||
1635 | /* 6-stack mode */ | 1646 | /* 6-stack mode */ |
@@ -2460,7 +2471,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec) | |||
2460 | pin = spec->autocfg.speaker_pins[0]; | 2471 | pin = spec->autocfg.speaker_pins[0]; |
2461 | if (pin) /* connect to front */ | 2472 | if (pin) /* connect to front */ |
2462 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); | 2473 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); |
2463 | pin = spec->autocfg.hp_pin; | 2474 | pin = spec->autocfg.hp_pins[0]; |
2464 | if (pin) /* connect to front */ | 2475 | if (pin) /* connect to front */ |
2465 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 2476 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); |
2466 | } | 2477 | } |
@@ -2512,7 +2523,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
2512 | (err = ad1988_auto_create_extra_out(codec, | 2523 | (err = ad1988_auto_create_extra_out(codec, |
2513 | spec->autocfg.speaker_pins[0], | 2524 | spec->autocfg.speaker_pins[0], |
2514 | "Speaker")) < 0 || | 2525 | "Speaker")) < 0 || |
2515 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin, | 2526 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], |
2516 | "Headphone")) < 0 || | 2527 | "Headphone")) < 0 || |
2517 | (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | 2528 | (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) |
2518 | return err; | 2529 | return err; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 18d105263fea..d08d2e399c8f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -79,6 +79,7 @@ enum { | |||
79 | ALC262_BASIC, | 79 | ALC262_BASIC, |
80 | ALC262_FUJITSU, | 80 | ALC262_FUJITSU, |
81 | ALC262_HP_BPC, | 81 | ALC262_HP_BPC, |
82 | ALC262_BENQ_ED8, | ||
82 | ALC262_AUTO, | 83 | ALC262_AUTO, |
83 | ALC262_MODEL_LAST /* last tag */ | 84 | ALC262_MODEL_LAST /* last tag */ |
84 | }; | 85 | }; |
@@ -89,6 +90,7 @@ enum { | |||
89 | ALC660_3ST, | 90 | ALC660_3ST, |
90 | ALC861_3ST_DIG, | 91 | ALC861_3ST_DIG, |
91 | ALC861_6ST_DIG, | 92 | ALC861_6ST_DIG, |
93 | ALC861_UNIWILL_M31, | ||
92 | ALC861_AUTO, | 94 | ALC861_AUTO, |
93 | ALC861_MODEL_LAST, | 95 | ALC861_MODEL_LAST, |
94 | }; | 96 | }; |
@@ -97,6 +99,7 @@ enum { | |||
97 | enum { | 99 | enum { |
98 | ALC882_3ST_DIG, | 100 | ALC882_3ST_DIG, |
99 | ALC882_6ST_DIG, | 101 | ALC882_6ST_DIG, |
102 | ALC882_ARIMA, | ||
100 | ALC882_AUTO, | 103 | ALC882_AUTO, |
101 | ALC882_MODEL_LAST, | 104 | ALC882_MODEL_LAST, |
102 | }; | 105 | }; |
@@ -108,6 +111,7 @@ enum { | |||
108 | ALC883_3ST_6ch, | 111 | ALC883_3ST_6ch, |
109 | ALC883_6ST_DIG, | 112 | ALC883_6ST_DIG, |
110 | ALC888_DEMO_BOARD, | 113 | ALC888_DEMO_BOARD, |
114 | ALC883_ACER, | ||
111 | ALC883_AUTO, | 115 | ALC883_AUTO, |
112 | ALC883_MODEL_LAST, | 116 | ALC883_MODEL_LAST, |
113 | }; | 117 | }; |
@@ -153,6 +157,7 @@ struct alc_spec { | |||
153 | /* channel model */ | 157 | /* channel model */ |
154 | const struct hda_channel_mode *channel_mode; | 158 | const struct hda_channel_mode *channel_mode; |
155 | int num_channel_mode; | 159 | int num_channel_mode; |
160 | int need_dac_fix; | ||
156 | 161 | ||
157 | /* PCM information */ | 162 | /* PCM information */ |
158 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ | 163 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ |
@@ -190,6 +195,7 @@ struct alc_config_preset { | |||
190 | hda_nid_t dig_in_nid; | 195 | hda_nid_t dig_in_nid; |
191 | unsigned int num_channel_mode; | 196 | unsigned int num_channel_mode; |
192 | const struct hda_channel_mode *channel_mode; | 197 | const struct hda_channel_mode *channel_mode; |
198 | int need_dac_fix; | ||
193 | unsigned int num_mux_defs; | 199 | unsigned int num_mux_defs; |
194 | const struct hda_input_mux *input_mux; | 200 | const struct hda_input_mux *input_mux; |
195 | void (*unsol_event)(struct hda_codec *, unsigned int); | 201 | void (*unsol_event)(struct hda_codec *, unsigned int); |
@@ -262,9 +268,12 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
262 | { | 268 | { |
263 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 269 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
264 | struct alc_spec *spec = codec->spec; | 270 | struct alc_spec *spec = codec->spec; |
265 | return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, | 271 | int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, |
266 | spec->num_channel_mode, | 272 | spec->num_channel_mode, |
267 | &spec->multiout.max_channels); | 273 | &spec->multiout.max_channels); |
274 | if (! err && spec->need_dac_fix) | ||
275 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | ||
276 | return err; | ||
268 | } | 277 | } |
269 | 278 | ||
270 | /* | 279 | /* |
@@ -544,6 +553,7 @@ static void setup_preset(struct alc_spec *spec, | |||
544 | 553 | ||
545 | spec->channel_mode = preset->channel_mode; | 554 | spec->channel_mode = preset->channel_mode; |
546 | spec->num_channel_mode = preset->num_channel_mode; | 555 | spec->num_channel_mode = preset->num_channel_mode; |
556 | spec->need_dac_fix = preset->need_dac_fix; | ||
547 | 557 | ||
548 | spec->multiout.max_channels = spec->channel_mode[0].channels; | 558 | spec->multiout.max_channels = spec->channel_mode[0].channels; |
549 | 559 | ||
@@ -1348,6 +1358,10 @@ static struct hda_verb alc880_pin_clevo_init_verbs[] = { | |||
1348 | }; | 1358 | }; |
1349 | 1359 | ||
1350 | static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { | 1360 | static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { |
1361 | /* change to EAPD mode */ | ||
1362 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
1363 | {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, | ||
1364 | |||
1351 | /* Headphone output */ | 1365 | /* Headphone output */ |
1352 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | 1366 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
1353 | /* Front output*/ | 1367 | /* Front output*/ |
@@ -1782,25 +1796,9 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
1782 | } | 1796 | } |
1783 | } | 1797 | } |
1784 | 1798 | ||
1785 | /* If the use of more than one ADC is requested for the current | 1799 | /* SPDIF for stream index #1 */ |
1786 | * model, configure a second analog capture-only PCM. | ||
1787 | */ | ||
1788 | if (spec->num_adc_nids > 1) { | ||
1789 | codec->num_pcms++; | ||
1790 | info++; | ||
1791 | info->name = spec->stream_name_analog; | ||
1792 | /* No playback stream for second PCM */ | ||
1793 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; | ||
1794 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | ||
1795 | if (spec->stream_analog_capture) { | ||
1796 | snd_assert(spec->adc_nids, return -EINVAL); | ||
1797 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | ||
1798 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; | ||
1799 | } | ||
1800 | } | ||
1801 | |||
1802 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | 1800 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { |
1803 | codec->num_pcms++; | 1801 | codec->num_pcms = 2; |
1804 | info++; | 1802 | info++; |
1805 | info->name = spec->stream_name_digital; | 1803 | info->name = spec->stream_name_digital; |
1806 | if (spec->multiout.dig_out_nid && | 1804 | if (spec->multiout.dig_out_nid && |
@@ -1815,6 +1813,24 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
1815 | } | 1813 | } |
1816 | } | 1814 | } |
1817 | 1815 | ||
1816 | /* If the use of more than one ADC is requested for the current | ||
1817 | * model, configure a second analog capture-only PCM. | ||
1818 | */ | ||
1819 | /* Additional Analaog capture for index #2 */ | ||
1820 | if (spec->num_adc_nids > 1 && spec->stream_analog_capture && | ||
1821 | spec->adc_nids) { | ||
1822 | codec->num_pcms = 3; | ||
1823 | info++; | ||
1824 | info->name = spec->stream_name_analog; | ||
1825 | /* No playback stream for second PCM */ | ||
1826 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; | ||
1827 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | ||
1828 | if (spec->stream_analog_capture) { | ||
1829 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | ||
1830 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; | ||
1831 | } | ||
1832 | } | ||
1833 | |||
1818 | return 0; | 1834 | return 0; |
1819 | } | 1835 | } |
1820 | 1836 | ||
@@ -2130,7 +2146,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2130 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, | 2146 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, |
2131 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, | 2147 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, |
2132 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, | 2148 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, |
2149 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST }, | ||
2150 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST }, | ||
2133 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, | 2151 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, |
2152 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST }, | ||
2134 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, | 2153 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, |
2135 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, | 2154 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, |
2136 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, | 2155 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, |
@@ -2145,6 +2164,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2145 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, | 2164 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, |
2146 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, | 2165 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, |
2147 | /* TCL S700 */ | 2166 | /* TCL S700 */ |
2167 | { .modelname = "tcl", .config = ALC880_TCL_S700 }, | ||
2148 | { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 }, | 2168 | { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 }, |
2149 | 2169 | ||
2150 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ | 2170 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ |
@@ -2156,8 +2176,13 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2156 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, | 2176 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, |
2157 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, | 2177 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, |
2158 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, | 2178 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, |
2159 | /* Clevo m520G NB */ | 2179 | |
2160 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, .config = ALC880_CLEVO }, | 2180 | /* Clevo laptops */ |
2181 | { .modelname = "clevo", .config = ALC880_CLEVO }, | ||
2182 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, | ||
2183 | .config = ALC880_CLEVO }, /* Clevo m520G NB */ | ||
2184 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0660, | ||
2185 | .config = ALC880_CLEVO }, /* Clevo m665n */ | ||
2161 | 2186 | ||
2162 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ | 2187 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ |
2163 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, | 2188 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, |
@@ -2222,12 +2247,16 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2222 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, | 2247 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, |
2223 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, | 2248 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, |
2224 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, | 2249 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, |
2250 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */ | ||
2225 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, | 2251 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, |
2226 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, | 2252 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, |
2227 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, | 2253 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, |
2228 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, | 2254 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, |
2255 | { .modelname = "asus-w1v", .config = ALC880_ASUS_W1V }, | ||
2229 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, | 2256 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, |
2257 | { .modelname = "asus-dig", .config = ALC880_ASUS_DIG }, | ||
2230 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */ | 2258 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */ |
2259 | { .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 }, | ||
2231 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, | 2260 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, |
2232 | 2261 | ||
2233 | { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, | 2262 | { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, |
@@ -2243,6 +2272,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2243 | 2272 | ||
2244 | { .modelname = "lg-lw", .config = ALC880_LG_LW }, | 2273 | { .modelname = "lg-lw", .config = ALC880_LG_LW }, |
2245 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, | 2274 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, |
2275 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW }, | ||
2246 | 2276 | ||
2247 | #ifdef CONFIG_SND_DEBUG | 2277 | #ifdef CONFIG_SND_DEBUG |
2248 | { .modelname = "test", .config = ALC880_TEST }, | 2278 | { .modelname = "test", .config = ALC880_TEST }, |
@@ -2263,6 +2293,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2263 | .dac_nids = alc880_dac_nids, | 2293 | .dac_nids = alc880_dac_nids, |
2264 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | 2294 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), |
2265 | .channel_mode = alc880_threestack_modes, | 2295 | .channel_mode = alc880_threestack_modes, |
2296 | .need_dac_fix = 1, | ||
2266 | .input_mux = &alc880_capture_source, | 2297 | .input_mux = &alc880_capture_source, |
2267 | }, | 2298 | }, |
2268 | [ALC880_3ST_DIG] = { | 2299 | [ALC880_3ST_DIG] = { |
@@ -2273,6 +2304,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2273 | .dig_out_nid = ALC880_DIGOUT_NID, | 2304 | .dig_out_nid = ALC880_DIGOUT_NID, |
2274 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | 2305 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), |
2275 | .channel_mode = alc880_threestack_modes, | 2306 | .channel_mode = alc880_threestack_modes, |
2307 | .need_dac_fix = 1, | ||
2276 | .input_mux = &alc880_capture_source, | 2308 | .input_mux = &alc880_capture_source, |
2277 | }, | 2309 | }, |
2278 | [ALC880_TCL_S700] = { | 2310 | [ALC880_TCL_S700] = { |
@@ -2365,6 +2397,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2365 | .dac_nids = alc880_asus_dac_nids, | 2397 | .dac_nids = alc880_asus_dac_nids, |
2366 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2398 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2367 | .channel_mode = alc880_asus_modes, | 2399 | .channel_mode = alc880_asus_modes, |
2400 | .need_dac_fix = 1, | ||
2368 | .input_mux = &alc880_capture_source, | 2401 | .input_mux = &alc880_capture_source, |
2369 | }, | 2402 | }, |
2370 | [ALC880_ASUS_DIG] = { | 2403 | [ALC880_ASUS_DIG] = { |
@@ -2376,6 +2409,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2376 | .dig_out_nid = ALC880_DIGOUT_NID, | 2409 | .dig_out_nid = ALC880_DIGOUT_NID, |
2377 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2410 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2378 | .channel_mode = alc880_asus_modes, | 2411 | .channel_mode = alc880_asus_modes, |
2412 | .need_dac_fix = 1, | ||
2379 | .input_mux = &alc880_capture_source, | 2413 | .input_mux = &alc880_capture_source, |
2380 | }, | 2414 | }, |
2381 | [ALC880_ASUS_DIG2] = { | 2415 | [ALC880_ASUS_DIG2] = { |
@@ -2387,6 +2421,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2387 | .dig_out_nid = ALC880_DIGOUT_NID, | 2421 | .dig_out_nid = ALC880_DIGOUT_NID, |
2388 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2422 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2389 | .channel_mode = alc880_asus_modes, | 2423 | .channel_mode = alc880_asus_modes, |
2424 | .need_dac_fix = 1, | ||
2390 | .input_mux = &alc880_capture_source, | 2425 | .input_mux = &alc880_capture_source, |
2391 | }, | 2426 | }, |
2392 | [ALC880_ASUS_W1V] = { | 2427 | [ALC880_ASUS_W1V] = { |
@@ -2398,6 +2433,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2398 | .dig_out_nid = ALC880_DIGOUT_NID, | 2433 | .dig_out_nid = ALC880_DIGOUT_NID, |
2399 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2434 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2400 | .channel_mode = alc880_asus_modes, | 2435 | .channel_mode = alc880_asus_modes, |
2436 | .need_dac_fix = 1, | ||
2401 | .input_mux = &alc880_capture_source, | 2437 | .input_mux = &alc880_capture_source, |
2402 | }, | 2438 | }, |
2403 | [ALC880_UNIWILL_DIG] = { | 2439 | [ALC880_UNIWILL_DIG] = { |
@@ -2408,6 +2444,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2408 | .dig_out_nid = ALC880_DIGOUT_NID, | 2444 | .dig_out_nid = ALC880_DIGOUT_NID, |
2409 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2445 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2410 | .channel_mode = alc880_asus_modes, | 2446 | .channel_mode = alc880_asus_modes, |
2447 | .need_dac_fix = 1, | ||
2411 | .input_mux = &alc880_capture_source, | 2448 | .input_mux = &alc880_capture_source, |
2412 | }, | 2449 | }, |
2413 | [ALC880_CLEVO] = { | 2450 | [ALC880_CLEVO] = { |
@@ -2419,6 +2456,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2419 | .hp_nid = 0x03, | 2456 | .hp_nid = 0x03, |
2420 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | 2457 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), |
2421 | .channel_mode = alc880_threestack_modes, | 2458 | .channel_mode = alc880_threestack_modes, |
2459 | .need_dac_fix = 1, | ||
2422 | .input_mux = &alc880_capture_source, | 2460 | .input_mux = &alc880_capture_source, |
2423 | }, | 2461 | }, |
2424 | [ALC880_LG] = { | 2462 | [ALC880_LG] = { |
@@ -2430,6 +2468,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2430 | .dig_out_nid = ALC880_DIGOUT_NID, | 2468 | .dig_out_nid = ALC880_DIGOUT_NID, |
2431 | .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), | 2469 | .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), |
2432 | .channel_mode = alc880_lg_ch_modes, | 2470 | .channel_mode = alc880_lg_ch_modes, |
2471 | .need_dac_fix = 1, | ||
2433 | .input_mux = &alc880_lg_capture_source, | 2472 | .input_mux = &alc880_lg_capture_source, |
2434 | .unsol_event = alc880_lg_unsol_event, | 2473 | .unsol_event = alc880_lg_unsol_event, |
2435 | .init_hook = alc880_lg_automute, | 2474 | .init_hook = alc880_lg_automute, |
@@ -2714,7 +2753,7 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec) | |||
2714 | pin = spec->autocfg.speaker_pins[0]; | 2753 | pin = spec->autocfg.speaker_pins[0]; |
2715 | if (pin) /* connect to front */ | 2754 | if (pin) /* connect to front */ |
2716 | alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); | 2755 | alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); |
2717 | pin = spec->autocfg.hp_pin; | 2756 | pin = spec->autocfg.hp_pins[0]; |
2718 | if (pin) /* connect to front */ | 2757 | if (pin) /* connect to front */ |
2719 | alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 2758 | alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); |
2720 | } | 2759 | } |
@@ -2755,7 +2794,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) | |||
2755 | (err = alc880_auto_create_extra_out(spec, | 2794 | (err = alc880_auto_create_extra_out(spec, |
2756 | spec->autocfg.speaker_pins[0], | 2795 | spec->autocfg.speaker_pins[0], |
2757 | "Speaker")) < 0 || | 2796 | "Speaker")) < 0 || |
2758 | (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin, | 2797 | (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], |
2759 | "Headphone")) < 0 || | 2798 | "Headphone")) < 0 || |
2760 | (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | 2799 | (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) |
2761 | return err; | 2800 | return err; |
@@ -3697,7 +3736,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
3697 | return err; | 3736 | return err; |
3698 | } | 3737 | } |
3699 | 3738 | ||
3700 | nid = cfg->hp_pin; | 3739 | nid = cfg->hp_pins[0]; |
3701 | if (nid) { | 3740 | if (nid) { |
3702 | err = alc260_add_playback_controls(spec, nid, "Headphone"); | 3741 | err = alc260_add_playback_controls(spec, nid, "Headphone"); |
3703 | if (err < 0) | 3742 | if (err < 0) |
@@ -3767,7 +3806,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) | |||
3767 | if (nid) | 3806 | if (nid) |
3768 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); | 3807 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); |
3769 | 3808 | ||
3770 | nid = spec->autocfg.hp_pin; | 3809 | nid = spec->autocfg.hp_pins[0]; |
3771 | if (nid) | 3810 | if (nid) |
3772 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); | 3811 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); |
3773 | } | 3812 | } |
@@ -3900,7 +3939,8 @@ static struct hda_board_config alc260_cfg_tbl[] = { | |||
3900 | { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, | 3939 | { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, |
3901 | .config = ALC260_BASIC }, /* CTL Travel Master U553W */ | 3940 | .config = ALC260_BASIC }, /* CTL Travel Master U553W */ |
3902 | { .modelname = "hp", .config = ALC260_HP }, | 3941 | { .modelname = "hp", .config = ALC260_HP }, |
3903 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, | 3942 | { .modelname = "hp-3013", .config = ALC260_HP_3013 }, |
3943 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 }, | ||
3904 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, | 3944 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, |
3905 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 }, | 3945 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 }, |
3906 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, | 3946 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, |
@@ -4266,6 +4306,13 @@ static struct hda_verb alc882_init_verbs[] = { | |||
4266 | { } | 4306 | { } |
4267 | }; | 4307 | }; |
4268 | 4308 | ||
4309 | static struct hda_verb alc882_eapd_verbs[] = { | ||
4310 | /* change to EAPD mode */ | ||
4311 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
4312 | {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, | ||
4313 | { } | ||
4314 | }; | ||
4315 | |||
4269 | /* | 4316 | /* |
4270 | * generic initialization of ADC, input mixers and output mixers | 4317 | * generic initialization of ADC, input mixers and output mixers |
4271 | */ | 4318 | */ |
@@ -4397,6 +4444,9 @@ static struct hda_board_config alc882_cfg_tbl[] = { | |||
4397 | .config = ALC882_6ST_DIG }, /* Foxconn */ | 4444 | .config = ALC882_6ST_DIG }, /* Foxconn */ |
4398 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, | 4445 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, |
4399 | .config = ALC882_6ST_DIG }, /* ECS to Intel*/ | 4446 | .config = ALC882_6ST_DIG }, /* ECS to Intel*/ |
4447 | { .modelname = "arima", .config = ALC882_ARIMA }, | ||
4448 | { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, | ||
4449 | .config = ALC882_ARIMA }, /* Arima W820Di1 */ | ||
4400 | { .modelname = "auto", .config = ALC882_AUTO }, | 4450 | { .modelname = "auto", .config = ALC882_AUTO }, |
4401 | {} | 4451 | {} |
4402 | }; | 4452 | }; |
@@ -4411,6 +4461,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
4411 | .dig_in_nid = ALC882_DIGIN_NID, | 4461 | .dig_in_nid = ALC882_DIGIN_NID, |
4412 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), | 4462 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), |
4413 | .channel_mode = alc882_ch_modes, | 4463 | .channel_mode = alc882_ch_modes, |
4464 | .need_dac_fix = 1, | ||
4414 | .input_mux = &alc882_capture_source, | 4465 | .input_mux = &alc882_capture_source, |
4415 | }, | 4466 | }, |
4416 | [ALC882_6ST_DIG] = { | 4467 | [ALC882_6ST_DIG] = { |
@@ -4424,6 +4475,15 @@ static struct alc_config_preset alc882_presets[] = { | |||
4424 | .channel_mode = alc882_sixstack_modes, | 4475 | .channel_mode = alc882_sixstack_modes, |
4425 | .input_mux = &alc882_capture_source, | 4476 | .input_mux = &alc882_capture_source, |
4426 | }, | 4477 | }, |
4478 | [ALC882_ARIMA] = { | ||
4479 | .mixers = { alc882_base_mixer, alc882_chmode_mixer }, | ||
4480 | .init_verbs = { alc882_init_verbs, alc882_eapd_verbs }, | ||
4481 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
4482 | .dac_nids = alc882_dac_nids, | ||
4483 | .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), | ||
4484 | .channel_mode = alc882_sixstack_modes, | ||
4485 | .input_mux = &alc882_capture_source, | ||
4486 | }, | ||
4427 | }; | 4487 | }; |
4428 | 4488 | ||
4429 | 4489 | ||
@@ -4466,7 +4526,7 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) | |||
4466 | struct alc_spec *spec = codec->spec; | 4526 | struct alc_spec *spec = codec->spec; |
4467 | hda_nid_t pin; | 4527 | hda_nid_t pin; |
4468 | 4528 | ||
4469 | pin = spec->autocfg.hp_pin; | 4529 | pin = spec->autocfg.hp_pins[0]; |
4470 | if (pin) /* connect to front */ | 4530 | if (pin) /* connect to front */ |
4471 | alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ | 4531 | alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ |
4472 | } | 4532 | } |
@@ -4999,16 +5059,23 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
4999 | */ | 5059 | */ |
5000 | static struct hda_board_config alc883_cfg_tbl[] = { | 5060 | static struct hda_board_config alc883_cfg_tbl[] = { |
5001 | { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG }, | 5061 | { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG }, |
5062 | { .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG }, | ||
5063 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, | ||
5064 | .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/ | ||
5065 | { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch }, | ||
5066 | { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d, | ||
5067 | .config = ALC883_3ST_6ch }, | ||
5068 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601, | ||
5069 | .config = ALC883_3ST_6ch }, /* D102GGC */ | ||
5002 | { .modelname = "6stack-dig", .config = ALC883_6ST_DIG }, | 5070 | { .modelname = "6stack-dig", .config = ALC883_6ST_DIG }, |
5003 | { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD }, | ||
5004 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, | 5071 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, |
5005 | .config = ALC883_6ST_DIG }, /* MSI */ | 5072 | .config = ALC883_6ST_DIG }, /* MSI */ |
5006 | { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, | 5073 | { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, |
5007 | .config = ALC883_6ST_DIG }, /* Foxconn */ | 5074 | .config = ALC883_6ST_DIG }, /* Foxconn */ |
5008 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, | 5075 | { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD }, |
5009 | .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/ | 5076 | { .modelname = "acer", .config = ALC883_ACER }, |
5010 | { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d, | 5077 | { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/, |
5011 | .config = ALC883_3ST_6ch }, | 5078 | .config = ALC883_ACER }, |
5012 | { .modelname = "auto", .config = ALC883_AUTO }, | 5079 | { .modelname = "auto", .config = ALC883_AUTO }, |
5013 | {} | 5080 | {} |
5014 | }; | 5081 | }; |
@@ -5038,6 +5105,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
5038 | .dig_in_nid = ALC883_DIGIN_NID, | 5105 | .dig_in_nid = ALC883_DIGIN_NID, |
5039 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), | 5106 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), |
5040 | .channel_mode = alc883_3ST_6ch_modes, | 5107 | .channel_mode = alc883_3ST_6ch_modes, |
5108 | .need_dac_fix = 1, | ||
5041 | .input_mux = &alc883_capture_source, | 5109 | .input_mux = &alc883_capture_source, |
5042 | }, | 5110 | }, |
5043 | [ALC883_3ST_6ch] = { | 5111 | [ALC883_3ST_6ch] = { |
@@ -5049,6 +5117,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
5049 | .adc_nids = alc883_adc_nids, | 5117 | .adc_nids = alc883_adc_nids, |
5050 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), | 5118 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), |
5051 | .channel_mode = alc883_3ST_6ch_modes, | 5119 | .channel_mode = alc883_3ST_6ch_modes, |
5120 | .need_dac_fix = 1, | ||
5052 | .input_mux = &alc883_capture_source, | 5121 | .input_mux = &alc883_capture_source, |
5053 | }, | 5122 | }, |
5054 | [ALC883_6ST_DIG] = { | 5123 | [ALC883_6ST_DIG] = { |
@@ -5077,6 +5146,23 @@ static struct alc_config_preset alc883_presets[] = { | |||
5077 | .channel_mode = alc883_sixstack_modes, | 5146 | .channel_mode = alc883_sixstack_modes, |
5078 | .input_mux = &alc883_capture_source, | 5147 | .input_mux = &alc883_capture_source, |
5079 | }, | 5148 | }, |
5149 | [ALC883_ACER] = { | ||
5150 | .mixers = { alc883_base_mixer, | ||
5151 | alc883_chmode_mixer }, | ||
5152 | /* On TravelMate laptops, GPIO 0 enables the internal speaker | ||
5153 | * and the headphone jack. Turn this on and rely on the | ||
5154 | * standard mute methods whenever the user wants to turn | ||
5155 | * these outputs off. | ||
5156 | */ | ||
5157 | .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs }, | ||
5158 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
5159 | .dac_nids = alc883_dac_nids, | ||
5160 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
5161 | .adc_nids = alc883_adc_nids, | ||
5162 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
5163 | .channel_mode = alc883_3ST_2ch_modes, | ||
5164 | .input_mux = &alc883_capture_source, | ||
5165 | }, | ||
5080 | }; | 5166 | }; |
5081 | 5167 | ||
5082 | 5168 | ||
@@ -5121,7 +5207,7 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec) | |||
5121 | struct alc_spec *spec = codec->spec; | 5207 | struct alc_spec *spec = codec->spec; |
5122 | hda_nid_t pin; | 5208 | hda_nid_t pin; |
5123 | 5209 | ||
5124 | pin = spec->autocfg.hp_pin; | 5210 | pin = spec->autocfg.hp_pins[0]; |
5125 | if (pin) /* connect to front */ | 5211 | if (pin) /* connect to front */ |
5126 | /* use dac 0 */ | 5212 | /* use dac 0 */ |
5127 | alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 5213 | alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); |
@@ -5217,8 +5303,10 @@ static int patch_alc883(struct hda_codec *codec) | |||
5217 | spec->stream_digital_playback = &alc883_pcm_digital_playback; | 5303 | spec->stream_digital_playback = &alc883_pcm_digital_playback; |
5218 | spec->stream_digital_capture = &alc883_pcm_digital_capture; | 5304 | spec->stream_digital_capture = &alc883_pcm_digital_capture; |
5219 | 5305 | ||
5220 | spec->adc_nids = alc883_adc_nids; | 5306 | if (! spec->adc_nids && spec->input_mux) { |
5221 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | 5307 | spec->adc_nids = alc883_adc_nids; |
5308 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | ||
5309 | } | ||
5222 | 5310 | ||
5223 | codec->patch_ops = alc_patch_ops; | 5311 | codec->patch_ops = alc_patch_ops; |
5224 | if (board_config == ALC883_AUTO) | 5312 | if (board_config == ALC883_AUTO) |
@@ -5481,6 +5569,7 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | |||
5481 | .info = snd_hda_mixer_amp_volume_info, | 5569 | .info = snd_hda_mixer_amp_volume_info, |
5482 | .get = snd_hda_mixer_amp_volume_get, | 5570 | .get = snd_hda_mixer_amp_volume_get, |
5483 | .put = alc262_fujitsu_master_vol_put, | 5571 | .put = alc262_fujitsu_master_vol_put, |
5572 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
5484 | .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), | 5573 | .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), |
5485 | }, | 5574 | }, |
5486 | { | 5575 | { |
@@ -5499,6 +5588,13 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | |||
5499 | { } /* end */ | 5588 | { } /* end */ |
5500 | }; | 5589 | }; |
5501 | 5590 | ||
5591 | /* additional init verbs for Benq laptops */ | ||
5592 | static struct hda_verb alc262_EAPD_verbs[] = { | ||
5593 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
5594 | {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, | ||
5595 | {} | ||
5596 | }; | ||
5597 | |||
5502 | /* add playback controls from the parsed DAC table */ | 5598 | /* add playback controls from the parsed DAC table */ |
5503 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | 5599 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) |
5504 | { | 5600 | { |
@@ -5534,7 +5630,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct | |||
5534 | return err; | 5630 | return err; |
5535 | } | 5631 | } |
5536 | } | 5632 | } |
5537 | nid = cfg->hp_pin; | 5633 | nid = cfg->hp_pins[0]; |
5538 | if (nid) { | 5634 | if (nid) { |
5539 | /* spec->multiout.hp_nid = 2; */ | 5635 | /* spec->multiout.hp_nid = 2; */ |
5540 | if (nid == 0x16) { | 5636 | if (nid == 0x16) { |
@@ -5769,6 +5865,7 @@ static struct hda_board_config alc262_cfg_tbl[] = { | |||
5769 | { .modelname = "fujitsu", .config = ALC262_FUJITSU }, | 5865 | { .modelname = "fujitsu", .config = ALC262_FUJITSU }, |
5770 | { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, | 5866 | { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, |
5771 | .config = ALC262_FUJITSU }, | 5867 | .config = ALC262_FUJITSU }, |
5868 | { .modelname = "hp-bpc", .config = ALC262_HP_BPC }, | ||
5772 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x208c, | 5869 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x208c, |
5773 | .config = ALC262_HP_BPC }, /* xw4400 */ | 5870 | .config = ALC262_HP_BPC }, /* xw4400 */ |
5774 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, | 5871 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, |
@@ -5777,6 +5874,9 @@ static struct hda_board_config alc262_cfg_tbl[] = { | |||
5777 | .config = ALC262_HP_BPC }, /* xw8400 */ | 5874 | .config = ALC262_HP_BPC }, /* xw8400 */ |
5778 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe, | 5875 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe, |
5779 | .config = ALC262_HP_BPC }, /* xw9400 */ | 5876 | .config = ALC262_HP_BPC }, /* xw9400 */ |
5877 | { .modelname = "benq", .config = ALC262_BENQ_ED8 }, | ||
5878 | { .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560, | ||
5879 | .config = ALC262_BENQ_ED8 }, | ||
5780 | { .modelname = "auto", .config = ALC262_AUTO }, | 5880 | { .modelname = "auto", .config = ALC262_AUTO }, |
5781 | {} | 5881 | {} |
5782 | }; | 5882 | }; |
@@ -5814,6 +5914,16 @@ static struct alc_config_preset alc262_presets[] = { | |||
5814 | .channel_mode = alc262_modes, | 5914 | .channel_mode = alc262_modes, |
5815 | .input_mux = &alc262_HP_capture_source, | 5915 | .input_mux = &alc262_HP_capture_source, |
5816 | }, | 5916 | }, |
5917 | [ALC262_BENQ_ED8] = { | ||
5918 | .mixers = { alc262_base_mixer }, | ||
5919 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, | ||
5920 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
5921 | .dac_nids = alc262_dac_nids, | ||
5922 | .hp_nid = 0x03, | ||
5923 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
5924 | .channel_mode = alc262_modes, | ||
5925 | .input_mux = &alc262_capture_source, | ||
5926 | }, | ||
5817 | }; | 5927 | }; |
5818 | 5928 | ||
5819 | static int patch_alc262(struct hda_codec *codec) | 5929 | static int patch_alc262(struct hda_codec *codec) |
@@ -5942,6 +6052,23 @@ static struct hda_channel_mode alc861_threestack_modes[2] = { | |||
5942 | { 2, alc861_threestack_ch2_init }, | 6052 | { 2, alc861_threestack_ch2_init }, |
5943 | { 6, alc861_threestack_ch6_init }, | 6053 | { 6, alc861_threestack_ch6_init }, |
5944 | }; | 6054 | }; |
6055 | /* Set mic1 as input and unmute the mixer */ | ||
6056 | static struct hda_verb alc861_uniwill_m31_ch2_init[] = { | ||
6057 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
6058 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ | ||
6059 | { } /* end */ | ||
6060 | }; | ||
6061 | /* Set mic1 as output and mute mixer */ | ||
6062 | static struct hda_verb alc861_uniwill_m31_ch4_init[] = { | ||
6063 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
6064 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ | ||
6065 | { } /* end */ | ||
6066 | }; | ||
6067 | |||
6068 | static struct hda_channel_mode alc861_uniwill_m31_modes[2] = { | ||
6069 | { 2, alc861_uniwill_m31_ch2_init }, | ||
6070 | { 4, alc861_uniwill_m31_ch4_init }, | ||
6071 | }; | ||
5945 | 6072 | ||
5946 | /* patch-ALC861 */ | 6073 | /* patch-ALC861 */ |
5947 | 6074 | ||
@@ -6020,6 +6147,47 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { | |||
6020 | }, | 6147 | }, |
6021 | { } /* end */ | 6148 | { } /* end */ |
6022 | }; | 6149 | }; |
6150 | static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { | ||
6151 | /* output mixer control */ | ||
6152 | HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
6153 | HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
6154 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), | ||
6155 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), | ||
6156 | /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ | ||
6157 | |||
6158 | /* Input mixer control */ | ||
6159 | /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
6160 | HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ | ||
6161 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), | ||
6162 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), | ||
6163 | HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), | ||
6164 | HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), | ||
6165 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), | ||
6166 | HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), | ||
6167 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), | ||
6168 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), | ||
6169 | |||
6170 | /* Capture mixer control */ | ||
6171 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
6172 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
6173 | { | ||
6174 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6175 | .name = "Capture Source", | ||
6176 | .count = 1, | ||
6177 | .info = alc_mux_enum_info, | ||
6178 | .get = alc_mux_enum_get, | ||
6179 | .put = alc_mux_enum_put, | ||
6180 | }, | ||
6181 | { | ||
6182 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6183 | .name = "Channel Mode", | ||
6184 | .info = alc_ch_mode_info, | ||
6185 | .get = alc_ch_mode_get, | ||
6186 | .put = alc_ch_mode_put, | ||
6187 | .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), | ||
6188 | }, | ||
6189 | { } /* end */ | ||
6190 | }; | ||
6023 | 6191 | ||
6024 | /* | 6192 | /* |
6025 | * generic initialization of ADC, input mixers and output mixers | 6193 | * generic initialization of ADC, input mixers and output mixers |
@@ -6148,6 +6316,67 @@ static struct hda_verb alc861_threestack_init_verbs[] = { | |||
6148 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 6316 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
6149 | { } | 6317 | { } |
6150 | }; | 6318 | }; |
6319 | |||
6320 | static struct hda_verb alc861_uniwill_m31_init_verbs[] = { | ||
6321 | /* | ||
6322 | * Unmute ADC0 and set the default input to mic-in | ||
6323 | */ | ||
6324 | /* port-A for surround (rear panel) */ | ||
6325 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
6326 | /* port-B for mic-in (rear panel) with vref */ | ||
6327 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
6328 | /* port-C for line-in (rear panel) */ | ||
6329 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
6330 | /* port-D for Front */ | ||
6331 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
6332 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
6333 | /* port-E for HP out (front panel) */ | ||
6334 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80 | ||
6335 | /* route front PCM to HP */ | ||
6336 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
6337 | /* port-F for mic-in (front panel) with vref */ | ||
6338 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
6339 | /* port-G for CLFE (rear panel) */ | ||
6340 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
6341 | /* port-H for side (rear panel) */ | ||
6342 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
6343 | /* CD-in */ | ||
6344 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
6345 | /* route front mic to ADC1*/ | ||
6346 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6347 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6348 | /* Unmute DAC0~3 & spdif out*/ | ||
6349 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6350 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6351 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6352 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6353 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6354 | |||
6355 | /* Unmute Mixer 14 (mic) 1c (Line in)*/ | ||
6356 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6357 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6358 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6359 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6360 | |||
6361 | /* Unmute Stereo Mixer 15 */ | ||
6362 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6363 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6364 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
6365 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step | ||
6366 | |||
6367 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6368 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6369 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6370 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6371 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6372 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6373 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6374 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6375 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front) | ||
6376 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
6377 | { } | ||
6378 | }; | ||
6379 | |||
6151 | /* | 6380 | /* |
6152 | * generic initialization of ADC, input mixers and output mixers | 6381 | * generic initialization of ADC, input mixers and output mixers |
6153 | */ | 6382 | */ |
@@ -6401,7 +6630,7 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec) | |||
6401 | struct alc_spec *spec = codec->spec; | 6630 | struct alc_spec *spec = codec->spec; |
6402 | hda_nid_t pin; | 6631 | hda_nid_t pin; |
6403 | 6632 | ||
6404 | pin = spec->autocfg.hp_pin; | 6633 | pin = spec->autocfg.hp_pins[0]; |
6405 | if (pin) /* connect to front */ | 6634 | if (pin) /* connect to front */ |
6406 | alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); | 6635 | alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); |
6407 | } | 6636 | } |
@@ -6436,7 +6665,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) | |||
6436 | 6665 | ||
6437 | if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || | 6666 | if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || |
6438 | (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | 6667 | (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || |
6439 | (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || | 6668 | (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0])) < 0 || |
6440 | (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | 6669 | (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) |
6441 | return err; | 6670 | return err; |
6442 | 6671 | ||
@@ -6477,10 +6706,14 @@ static struct hda_board_config alc861_cfg_tbl[] = { | |||
6477 | { .modelname = "3stack", .config = ALC861_3ST }, | 6706 | { .modelname = "3stack", .config = ALC861_3ST }, |
6478 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, | 6707 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, |
6479 | .config = ALC861_3ST }, | 6708 | .config = ALC861_3ST }, |
6709 | { .modelname = "3stack-660", .config = ALC660_3ST }, | ||
6480 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7, | 6710 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7, |
6481 | .config = ALC660_3ST }, | 6711 | .config = ALC660_3ST }, |
6482 | { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, | 6712 | { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, |
6483 | { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, | 6713 | { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, |
6714 | { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31}, | ||
6715 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072, | ||
6716 | .config = ALC861_UNIWILL_M31 }, | ||
6484 | { .modelname = "auto", .config = ALC861_AUTO }, | 6717 | { .modelname = "auto", .config = ALC861_AUTO }, |
6485 | {} | 6718 | {} |
6486 | }; | 6719 | }; |
@@ -6493,6 +6726,7 @@ static struct alc_config_preset alc861_presets[] = { | |||
6493 | .dac_nids = alc861_dac_nids, | 6726 | .dac_nids = alc861_dac_nids, |
6494 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), | 6727 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), |
6495 | .channel_mode = alc861_threestack_modes, | 6728 | .channel_mode = alc861_threestack_modes, |
6729 | .need_dac_fix = 1, | ||
6496 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | 6730 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), |
6497 | .adc_nids = alc861_adc_nids, | 6731 | .adc_nids = alc861_adc_nids, |
6498 | .input_mux = &alc861_capture_source, | 6732 | .input_mux = &alc861_capture_source, |
@@ -6505,6 +6739,7 @@ static struct alc_config_preset alc861_presets[] = { | |||
6505 | .dig_out_nid = ALC861_DIGOUT_NID, | 6739 | .dig_out_nid = ALC861_DIGOUT_NID, |
6506 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), | 6740 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), |
6507 | .channel_mode = alc861_threestack_modes, | 6741 | .channel_mode = alc861_threestack_modes, |
6742 | .need_dac_fix = 1, | ||
6508 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | 6743 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), |
6509 | .adc_nids = alc861_adc_nids, | 6744 | .adc_nids = alc861_adc_nids, |
6510 | .input_mux = &alc861_capture_source, | 6745 | .input_mux = &alc861_capture_source, |
@@ -6528,10 +6763,25 @@ static struct alc_config_preset alc861_presets[] = { | |||
6528 | .dac_nids = alc660_dac_nids, | 6763 | .dac_nids = alc660_dac_nids, |
6529 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), | 6764 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), |
6530 | .channel_mode = alc861_threestack_modes, | 6765 | .channel_mode = alc861_threestack_modes, |
6766 | .need_dac_fix = 1, | ||
6767 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | ||
6768 | .adc_nids = alc861_adc_nids, | ||
6769 | .input_mux = &alc861_capture_source, | ||
6770 | }, | ||
6771 | [ALC861_UNIWILL_M31] = { | ||
6772 | .mixers = { alc861_uniwill_m31_mixer }, | ||
6773 | .init_verbs = { alc861_uniwill_m31_init_verbs }, | ||
6774 | .num_dacs = ARRAY_SIZE(alc861_dac_nids), | ||
6775 | .dac_nids = alc861_dac_nids, | ||
6776 | .dig_out_nid = ALC861_DIGOUT_NID, | ||
6777 | .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), | ||
6778 | .channel_mode = alc861_uniwill_m31_modes, | ||
6779 | .need_dac_fix = 1, | ||
6531 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | 6780 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), |
6532 | .adc_nids = alc861_adc_nids, | 6781 | .adc_nids = alc861_adc_nids, |
6533 | .input_mux = &alc861_capture_source, | 6782 | .input_mux = &alc861_capture_source, |
6534 | }, | 6783 | }, |
6784 | |||
6535 | }; | 6785 | }; |
6536 | 6786 | ||
6537 | 6787 | ||
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 250242cd6c70..76ec3d75fa9e 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c | |||
@@ -298,6 +298,7 @@ struct hda_codec_preset snd_hda_preset_si3054[] = { | |||
298 | { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, | 298 | { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, |
299 | { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, | 299 | { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, |
300 | { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, | 300 | { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, |
301 | { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 }, | ||
301 | {} | 302 | {} |
302 | }; | 303 | }; |
303 | 304 | ||
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ea99083a1024..731b7b97ee71 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -36,15 +36,15 @@ | |||
36 | 36 | ||
37 | #define NUM_CONTROL_ALLOC 32 | 37 | #define NUM_CONTROL_ALLOC 32 |
38 | #define STAC_HP_EVENT 0x37 | 38 | #define STAC_HP_EVENT 0x37 |
39 | #define STAC_UNSOL_ENABLE (AC_USRSP_EN | STAC_HP_EVENT) | ||
40 | 39 | ||
41 | #define STAC_REF 0 | 40 | #define STAC_REF 0 |
42 | #define STAC_D945GTP3 1 | 41 | #define STAC_D945GTP3 1 |
43 | #define STAC_D945GTP5 2 | 42 | #define STAC_D945GTP5 2 |
44 | #define STAC_MACMINI 3 | 43 | #define STAC_MACMINI 3 |
45 | #define STAC_D965_2112 4 | 44 | #define STAC_922X_MODELS 4 /* number of 922x models */ |
46 | #define STAC_D965_284B 5 | 45 | #define STAC_D965_3ST 4 |
47 | #define STAC_922X_MODELS 6 /* number of 922x models */ | 46 | #define STAC_D965_5ST 5 |
47 | #define STAC_927X_MODELS 6 /* number of 922x models */ | ||
48 | 48 | ||
49 | struct sigmatel_spec { | 49 | struct sigmatel_spec { |
50 | struct snd_kcontrol_new *mixers[4]; | 50 | struct snd_kcontrol_new *mixers[4]; |
@@ -73,6 +73,7 @@ struct sigmatel_spec { | |||
73 | hda_nid_t *pin_nids; | 73 | hda_nid_t *pin_nids; |
74 | unsigned int num_pins; | 74 | unsigned int num_pins; |
75 | unsigned int *pin_configs; | 75 | unsigned int *pin_configs; |
76 | unsigned int *bios_pin_configs; | ||
76 | 77 | ||
77 | /* codec specific stuff */ | 78 | /* codec specific stuff */ |
78 | struct hda_verb *init; | 79 | struct hda_verb *init; |
@@ -110,24 +111,10 @@ static hda_nid_t stac922x_adc_nids[2] = { | |||
110 | 0x06, 0x07, | 111 | 0x06, 0x07, |
111 | }; | 112 | }; |
112 | 113 | ||
113 | static hda_nid_t stac9227_adc_nids[2] = { | ||
114 | 0x07, 0x08, | ||
115 | }; | ||
116 | |||
117 | #if 0 | ||
118 | static hda_nid_t d965_2112_dac_nids[3] = { | ||
119 | 0x02, 0x03, 0x05, | ||
120 | }; | ||
121 | #endif | ||
122 | |||
123 | static hda_nid_t stac922x_mux_nids[2] = { | 114 | static hda_nid_t stac922x_mux_nids[2] = { |
124 | 0x12, 0x13, | 115 | 0x12, 0x13, |
125 | }; | 116 | }; |
126 | 117 | ||
127 | static hda_nid_t stac9227_mux_nids[2] = { | ||
128 | 0x15, 0x16, | ||
129 | }; | ||
130 | |||
131 | static hda_nid_t stac927x_adc_nids[3] = { | 118 | static hda_nid_t stac927x_adc_nids[3] = { |
132 | 0x07, 0x08, 0x09 | 119 | 0x07, 0x08, 0x09 |
133 | }; | 120 | }; |
@@ -136,8 +123,17 @@ static hda_nid_t stac927x_mux_nids[3] = { | |||
136 | 0x15, 0x16, 0x17 | 123 | 0x15, 0x16, 0x17 |
137 | }; | 124 | }; |
138 | 125 | ||
126 | static hda_nid_t stac9205_adc_nids[2] = { | ||
127 | 0x12, 0x13 | ||
128 | }; | ||
129 | |||
130 | static hda_nid_t stac9205_mux_nids[2] = { | ||
131 | 0x19, 0x1a | ||
132 | }; | ||
133 | |||
139 | static hda_nid_t stac9200_pin_nids[8] = { | 134 | static hda_nid_t stac9200_pin_nids[8] = { |
140 | 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, | 135 | 0x08, 0x09, 0x0d, 0x0e, |
136 | 0x0f, 0x10, 0x11, 0x12, | ||
141 | }; | 137 | }; |
142 | 138 | ||
143 | static hda_nid_t stac922x_pin_nids[10] = { | 139 | static hda_nid_t stac922x_pin_nids[10] = { |
@@ -151,6 +147,13 @@ static hda_nid_t stac927x_pin_nids[14] = { | |||
151 | 0x14, 0x21, 0x22, 0x23, | 147 | 0x14, 0x21, 0x22, 0x23, |
152 | }; | 148 | }; |
153 | 149 | ||
150 | static hda_nid_t stac9205_pin_nids[12] = { | ||
151 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
152 | 0x0f, 0x14, 0x16, 0x17, 0x18, | ||
153 | 0x21, 0x22, | ||
154 | |||
155 | }; | ||
156 | |||
154 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 157 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
155 | { | 158 | { |
156 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 159 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
@@ -190,25 +193,23 @@ static struct hda_verb stac922x_core_init[] = { | |||
190 | {} | 193 | {} |
191 | }; | 194 | }; |
192 | 195 | ||
193 | static struct hda_verb stac9227_core_init[] = { | 196 | static struct hda_verb d965_core_init[] = { |
194 | /* set master volume and direct control */ | 197 | /* set master volume and direct control */ |
195 | { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 198 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
196 | /* unmute node 0x1b */ | 199 | /* unmute node 0x1b */ |
197 | { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 200 | { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, |
201 | /* select node 0x03 as DAC */ | ||
202 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
198 | {} | 203 | {} |
199 | }; | 204 | }; |
200 | 205 | ||
201 | static struct hda_verb d965_2112_core_init[] = { | 206 | static struct hda_verb stac927x_core_init[] = { |
202 | /* set master volume and direct control */ | 207 | /* set master volume and direct control */ |
203 | { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 208 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
204 | /* unmute node 0x1b */ | ||
205 | { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
206 | /* select node 0x03 as DAC */ | ||
207 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
208 | {} | 209 | {} |
209 | }; | 210 | }; |
210 | 211 | ||
211 | static struct hda_verb stac927x_core_init[] = { | 212 | static struct hda_verb stac9205_core_init[] = { |
212 | /* set master volume and direct control */ | 213 | /* set master volume and direct control */ |
213 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 214 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
214 | {} | 215 | {} |
@@ -277,6 +278,21 @@ static snd_kcontrol_new_t stac927x_mixer[] = { | |||
277 | { } /* end */ | 278 | { } /* end */ |
278 | }; | 279 | }; |
279 | 280 | ||
281 | static snd_kcontrol_new_t stac9205_mixer[] = { | ||
282 | { | ||
283 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
284 | .name = "Input Source", | ||
285 | .count = 1, | ||
286 | .info = stac92xx_mux_enum_info, | ||
287 | .get = stac92xx_mux_enum_get, | ||
288 | .put = stac92xx_mux_enum_put, | ||
289 | }, | ||
290 | HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), | ||
291 | HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), | ||
292 | HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
293 | { } /* end */ | ||
294 | }; | ||
295 | |||
280 | static int stac92xx_build_controls(struct hda_codec *codec) | 296 | static int stac92xx_build_controls(struct hda_codec *codec) |
281 | { | 297 | { |
282 | struct sigmatel_spec *spec = codec->spec; | 298 | struct sigmatel_spec *spec = codec->spec; |
@@ -341,38 +357,67 @@ static unsigned int d945gtp5_pin_configs[10] = { | |||
341 | 0x02a19320, 0x40000100, | 357 | 0x02a19320, 0x40000100, |
342 | }; | 358 | }; |
343 | 359 | ||
344 | static unsigned int d965_2112_pin_configs[10] = { | ||
345 | 0x0221401f, 0x40000100, 0x40000100, 0x01014011, | ||
346 | 0x01a19021, 0x01813024, 0x01452130, 0x40000100, | ||
347 | 0x02a19320, 0x40000100, | ||
348 | }; | ||
349 | |||
350 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { | 360 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { |
351 | [STAC_REF] = ref922x_pin_configs, | 361 | [STAC_REF] = ref922x_pin_configs, |
352 | [STAC_D945GTP3] = d945gtp3_pin_configs, | 362 | [STAC_D945GTP3] = d945gtp3_pin_configs, |
353 | [STAC_D945GTP5] = d945gtp5_pin_configs, | 363 | [STAC_D945GTP5] = d945gtp5_pin_configs, |
354 | [STAC_MACMINI] = d945gtp5_pin_configs, | 364 | [STAC_MACMINI] = d945gtp5_pin_configs, |
355 | [STAC_D965_2112] = d965_2112_pin_configs, | ||
356 | }; | 365 | }; |
357 | 366 | ||
358 | static struct hda_board_config stac922x_cfg_tbl[] = { | 367 | static struct hda_board_config stac922x_cfg_tbl[] = { |
368 | { .modelname = "5stack", .config = STAC_D945GTP5 }, | ||
369 | { .modelname = "3stack", .config = STAC_D945GTP3 }, | ||
359 | { .modelname = "ref", | 370 | { .modelname = "ref", |
360 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | 371 | .pci_subvendor = PCI_VENDOR_ID_INTEL, |
361 | .pci_subdevice = 0x2668, /* DFI LanParty */ | 372 | .pci_subdevice = 0x2668, /* DFI LanParty */ |
362 | .config = STAC_REF }, /* SigmaTel reference board */ | 373 | .config = STAC_REF }, /* SigmaTel reference board */ |
374 | /* Intel 945G based systems */ | ||
363 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 375 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
364 | .pci_subdevice = 0x0101, | 376 | .pci_subdevice = 0x0101, |
365 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ | 377 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ |
366 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 378 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
367 | .pci_subdevice = 0x0202, | 379 | .pci_subdevice = 0x0202, |
368 | .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack, 9221 A1 */ | 380 | .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack */ |
369 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 381 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
370 | .pci_subdevice = 0x0b0b, | 382 | .pci_subdevice = 0x0606, |
371 | .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack, 9221 A1 */ | 383 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ |
384 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
385 | .pci_subdevice = 0x0601, | ||
386 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ | ||
387 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
388 | .pci_subdevice = 0x0111, | ||
389 | .config = STAC_D945GTP3 }, /* Intel D945GZP - 3 Stack */ | ||
390 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
391 | .pci_subdevice = 0x1115, | ||
392 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
393 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
394 | .pci_subdevice = 0x1116, | ||
395 | .config = STAC_D945GTP3 }, /* Intel D945GBO - 3 Stack */ | ||
396 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
397 | .pci_subdevice = 0x1117, | ||
398 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
399 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
400 | .pci_subdevice = 0x1118, | ||
401 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
402 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
403 | .pci_subdevice = 0x1119, | ||
404 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
405 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
406 | .pci_subdevice = 0x8826, | ||
407 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
408 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
409 | .pci_subdevice = 0x5049, | ||
410 | .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ | ||
411 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
412 | .pci_subdevice = 0x5055, | ||
413 | .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ | ||
414 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
415 | .pci_subdevice = 0x5048, | ||
416 | .config = STAC_D945GTP3 }, /* Intel D945GPB - 3 Stack */ | ||
417 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
418 | .pci_subdevice = 0x0110, | ||
419 | .config = STAC_D945GTP3 }, /* Intel D945GLR - 3 Stack */ | ||
372 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 420 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
373 | .pci_subdevice = 0x0707, | ||
374 | .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */ | ||
375 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
376 | .pci_subdevice = 0x0404, | 421 | .pci_subdevice = 0x0404, |
377 | .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ | 422 | .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ |
378 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 423 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
@@ -384,44 +429,214 @@ static struct hda_board_config stac922x_cfg_tbl[] = { | |||
384 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 429 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
385 | .pci_subdevice = 0x0417, | 430 | .pci_subdevice = 0x0417, |
386 | .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ | 431 | .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ |
432 | /* Intel 945P based systems */ | ||
433 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
434 | .pci_subdevice = 0x0b0b, | ||
435 | .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack */ | ||
436 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
437 | .pci_subdevice = 0x0112, | ||
438 | .config = STAC_D945GTP3 }, /* Intel D945PLN - 3 Stack */ | ||
439 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
440 | .pci_subdevice = 0x0d0d, | ||
441 | .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */ | ||
442 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
443 | .pci_subdevice = 0x0909, | ||
444 | .config = STAC_D945GTP3 }, /* Intel D945PAW - 3 Stack */ | ||
445 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
446 | .pci_subdevice = 0x0505, | ||
447 | .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */ | ||
448 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
449 | .pci_subdevice = 0x0707, | ||
450 | .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */ | ||
451 | /* other systems */ | ||
387 | { .pci_subvendor = 0x8384, | 452 | { .pci_subvendor = 0x8384, |
388 | .pci_subdevice = 0x7680, | 453 | .pci_subdevice = 0x7680, |
389 | .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */ | 454 | .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */ |
455 | {} /* terminator */ | ||
456 | }; | ||
457 | |||
458 | static unsigned int ref927x_pin_configs[14] = { | ||
459 | 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, | ||
460 | 0x01a19040, 0x01011012, 0x01016011, 0x0101201f, | ||
461 | 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070, | ||
462 | 0x01c42190, 0x40000100, | ||
463 | }; | ||
464 | |||
465 | static unsigned int d965_3st_pin_configs[14] = { | ||
466 | 0x0221401f, 0x02a19120, 0x40000100, 0x01014011, | ||
467 | 0x01a19021, 0x01813024, 0x40000100, 0x40000100, | ||
468 | 0x40000100, 0x40000100, 0x40000100, 0x40000100, | ||
469 | 0x40000100, 0x40000100 | ||
470 | }; | ||
471 | |||
472 | static unsigned int d965_5st_pin_configs[14] = { | ||
473 | 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, | ||
474 | 0x01a19040, 0x01011012, 0x01016011, 0x40000100, | ||
475 | 0x40000100, 0x40000100, 0x40000100, 0x01442070, | ||
476 | 0x40000100, 0x40000100 | ||
477 | }; | ||
478 | |||
479 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | ||
480 | [STAC_REF] = ref927x_pin_configs, | ||
481 | [STAC_D965_3ST] = d965_3st_pin_configs, | ||
482 | [STAC_D965_5ST] = d965_5st_pin_configs, | ||
483 | }; | ||
484 | |||
485 | static struct hda_board_config stac927x_cfg_tbl[] = { | ||
486 | { .modelname = "5stack", .config = STAC_D965_5ST }, | ||
487 | { .modelname = "3stack", .config = STAC_D965_3ST }, | ||
488 | { .modelname = "ref", | ||
489 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
490 | .pci_subdevice = 0x2668, /* DFI LanParty */ | ||
491 | .config = STAC_REF }, /* SigmaTel reference board */ | ||
492 | /* Intel 946 based systems */ | ||
493 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
494 | .pci_subdevice = 0x3d01, | ||
495 | .config = STAC_D965_3ST }, /* D946 configuration */ | ||
496 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
497 | .pci_subdevice = 0xa301, | ||
498 | .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack */ | ||
499 | /* 965 based 3 stack systems */ | ||
500 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
501 | .pci_subdevice = 0x2116, | ||
502 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
503 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
504 | .pci_subdevice = 0x2115, | ||
505 | .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack */ | ||
506 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
507 | .pci_subdevice = 0x2114, | ||
508 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
509 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
510 | .pci_subdevice = 0x2113, | ||
511 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
390 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 512 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
391 | .pci_subdevice = 0x2112, | 513 | .pci_subdevice = 0x2112, |
392 | .config = STAC_D965_2112 }, | 514 | .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack */ |
515 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
516 | .pci_subdevice = 0x2111, | ||
517 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
518 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
519 | .pci_subdevice = 0x2110, | ||
520 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
521 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
522 | .pci_subdevice = 0x2009, | ||
523 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
524 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
525 | .pci_subdevice = 0x2008, | ||
526 | .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */ | ||
527 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
528 | .pci_subdevice = 0x2007, | ||
529 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
530 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
531 | .pci_subdevice = 0x2006, | ||
532 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
533 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
534 | .pci_subdevice = 0x2005, | ||
535 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
536 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
537 | .pci_subdevice = 0x2004, | ||
538 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
539 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
540 | .pci_subdevice = 0x2003, | ||
541 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
542 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
543 | .pci_subdevice = 0x2002, | ||
544 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
545 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
546 | .pci_subdevice = 0x2001, | ||
547 | .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */ | ||
548 | /* 965 based 5 stack systems */ | ||
549 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
550 | .pci_subdevice = 0x2301, | ||
551 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
552 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
553 | .pci_subdevice = 0x2302, | ||
554 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
555 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
556 | .pci_subdevice = 0x2303, | ||
557 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
393 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 558 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
394 | .pci_subdevice = 0x284b, | 559 | .pci_subdevice = 0x2304, |
395 | .config = STAC_D965_284B }, | 560 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ |
561 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
562 | .pci_subdevice = 0x2305, | ||
563 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
564 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
565 | .pci_subdevice = 0x2501, | ||
566 | .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */ | ||
567 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
568 | .pci_subdevice = 0x2502, | ||
569 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
570 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
571 | .pci_subdevice = 0x2503, | ||
572 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
573 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
574 | .pci_subdevice = 0x2504, | ||
575 | .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */ | ||
396 | {} /* terminator */ | 576 | {} /* terminator */ |
397 | }; | 577 | }; |
398 | 578 | ||
399 | static unsigned int ref927x_pin_configs[14] = { | 579 | static unsigned int ref9205_pin_configs[12] = { |
400 | 0x01813122, 0x01a19021, 0x01014010, 0x01016011, | 580 | 0x40000100, 0x40000100, 0x01016011, 0x01014010, |
401 | 0x01012012, 0x01011014, 0x40000100, 0x40000100, | 581 | 0x01813122, 0x01a19021, 0x40000100, 0x40000100, |
402 | 0x40000100, 0x40000100, 0x40000100, 0x01441030, | 582 | 0x40000100, 0x40000100, 0x01441030, 0x01c41030 |
403 | 0x01c41030, 0x40000100, | ||
404 | }; | 583 | }; |
405 | 584 | ||
406 | static unsigned int *stac927x_brd_tbl[] = { | 585 | static unsigned int *stac9205_brd_tbl[] = { |
407 | ref927x_pin_configs, | 586 | ref9205_pin_configs, |
408 | }; | 587 | }; |
409 | 588 | ||
410 | static struct hda_board_config stac927x_cfg_tbl[] = { | 589 | static struct hda_board_config stac9205_cfg_tbl[] = { |
411 | { .modelname = "ref", | 590 | { .modelname = "ref", |
412 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | 591 | .pci_subvendor = PCI_VENDOR_ID_INTEL, |
413 | .pci_subdevice = 0x2668, /* DFI LanParty */ | 592 | .pci_subdevice = 0x2668, /* DFI LanParty */ |
414 | .config = STAC_REF }, /* SigmaTel reference board */ | 593 | .config = STAC_REF }, /* SigmaTel reference board */ |
594 | /* Dell laptops have BIOS problem */ | ||
595 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5, | ||
596 | .config = STAC_REF }, /* Dell Inspiron 630m */ | ||
597 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2, | ||
598 | .config = STAC_REF }, /* Dell Latitude D620 */ | ||
599 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb, | ||
600 | .config = STAC_REF }, /* Dell Latitude 120L */ | ||
415 | {} /* terminator */ | 601 | {} /* terminator */ |
416 | }; | 602 | }; |
417 | 603 | ||
604 | static int stac92xx_save_bios_config_regs(struct hda_codec *codec) | ||
605 | { | ||
606 | int i; | ||
607 | struct sigmatel_spec *spec = codec->spec; | ||
608 | |||
609 | if (! spec->bios_pin_configs) { | ||
610 | spec->bios_pin_configs = kcalloc(spec->num_pins, | ||
611 | sizeof(*spec->bios_pin_configs), GFP_KERNEL); | ||
612 | if (! spec->bios_pin_configs) | ||
613 | return -ENOMEM; | ||
614 | } | ||
615 | |||
616 | for (i = 0; i < spec->num_pins; i++) { | ||
617 | hda_nid_t nid = spec->pin_nids[i]; | ||
618 | unsigned int pin_cfg; | ||
619 | |||
620 | pin_cfg = snd_hda_codec_read(codec, nid, 0, | ||
621 | AC_VERB_GET_CONFIG_DEFAULT, 0x00); | ||
622 | snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n", | ||
623 | nid, pin_cfg); | ||
624 | spec->bios_pin_configs[i] = pin_cfg; | ||
625 | } | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
418 | static void stac92xx_set_config_regs(struct hda_codec *codec) | 630 | static void stac92xx_set_config_regs(struct hda_codec *codec) |
419 | { | 631 | { |
420 | int i; | 632 | int i; |
421 | struct sigmatel_spec *spec = codec->spec; | 633 | struct sigmatel_spec *spec = codec->spec; |
422 | unsigned int pin_cfg; | 634 | unsigned int pin_cfg; |
423 | 635 | ||
424 | for (i=0; i < spec->num_pins; i++) { | 636 | if (! spec->pin_nids || ! spec->pin_configs) |
637 | return; | ||
638 | |||
639 | for (i = 0; i < spec->num_pins; i++) { | ||
425 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, | 640 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, |
426 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, | 641 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, |
427 | spec->pin_configs[i] & 0x000000ff); | 642 | spec->pin_configs[i] & 0x000000ff); |
@@ -795,11 +1010,29 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, | |||
795 | return 0; | 1010 | return 0; |
796 | } | 1011 | } |
797 | 1012 | ||
1013 | /* create volume control/switch for the given prefx type */ | ||
1014 | static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) | ||
1015 | { | ||
1016 | char name[32]; | ||
1017 | int err; | ||
1018 | |||
1019 | sprintf(name, "%s Playback Volume", pfx); | ||
1020 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, | ||
1021 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | ||
1022 | if (err < 0) | ||
1023 | return err; | ||
1024 | sprintf(name, "%s Playback Switch", pfx); | ||
1025 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, | ||
1026 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | ||
1027 | if (err < 0) | ||
1028 | return err; | ||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
798 | /* add playback controls from the parsed DAC table */ | 1032 | /* add playback controls from the parsed DAC table */ |
799 | static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | 1033 | static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, |
800 | const struct auto_pin_cfg *cfg) | 1034 | const struct auto_pin_cfg *cfg) |
801 | { | 1035 | { |
802 | char name[32]; | ||
803 | static const char *chname[4] = { | 1036 | static const char *chname[4] = { |
804 | "Front", "Surround", NULL /*CLFE*/, "Side" | 1037 | "Front", "Surround", NULL /*CLFE*/, "Side" |
805 | }; | 1038 | }; |
@@ -814,26 +1047,15 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | |||
814 | 1047 | ||
815 | if (i == 2) { | 1048 | if (i == 2) { |
816 | /* Center/LFE */ | 1049 | /* Center/LFE */ |
817 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume", | 1050 | err = create_controls(spec, "Center", nid, 1); |
818 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) | 1051 | if (err < 0) |
819 | return err; | ||
820 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume", | ||
821 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | ||
822 | return err; | ||
823 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch", | ||
824 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) | ||
825 | return err; | 1052 | return err; |
826 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch", | 1053 | err = create_controls(spec, "LFE", nid, 2); |
827 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | 1054 | if (err < 0) |
828 | return err; | 1055 | return err; |
829 | } else { | 1056 | } else { |
830 | sprintf(name, "%s Playback Volume", chname[i]); | 1057 | err = create_controls(spec, chname[i], nid, 3); |
831 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, | 1058 | if (err < 0) |
832 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
833 | return err; | ||
834 | sprintf(name, "%s Playback Switch", chname[i]); | ||
835 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, | ||
836 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
837 | return err; | 1059 | return err; |
838 | } | 1060 | } |
839 | } | 1061 | } |
@@ -849,39 +1071,85 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | |||
849 | return 0; | 1071 | return 0; |
850 | } | 1072 | } |
851 | 1073 | ||
852 | /* add playback controls for HP output */ | 1074 | static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) |
853 | static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg) | ||
854 | { | 1075 | { |
855 | struct sigmatel_spec *spec = codec->spec; | 1076 | int i; |
856 | hda_nid_t pin = cfg->hp_pin; | ||
857 | hda_nid_t nid; | ||
858 | int i, err; | ||
859 | unsigned int wid_caps; | ||
860 | 1077 | ||
861 | if (! pin) | 1078 | for (i = 0; i < spec->multiout.num_dacs; i++) { |
862 | return 0; | 1079 | if (spec->multiout.dac_nids[i] == nid) |
1080 | return 1; | ||
1081 | } | ||
1082 | if (spec->multiout.hp_nid == nid) | ||
1083 | return 1; | ||
1084 | return 0; | ||
1085 | } | ||
863 | 1086 | ||
864 | wid_caps = get_wcaps(codec, pin); | 1087 | static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) |
865 | if (wid_caps & AC_WCAP_UNSOL_CAP) | 1088 | { |
866 | spec->hp_detect = 1; | 1089 | if (!spec->multiout.hp_nid) |
1090 | spec->multiout.hp_nid = nid; | ||
1091 | else if (spec->multiout.num_dacs > 4) { | ||
1092 | printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); | ||
1093 | return 1; | ||
1094 | } else { | ||
1095 | spec->multiout.dac_nids[spec->multiout.num_dacs] = nid; | ||
1096 | spec->multiout.num_dacs++; | ||
1097 | } | ||
1098 | return 0; | ||
1099 | } | ||
867 | 1100 | ||
868 | nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | 1101 | /* add playback controls for Speaker and HP outputs */ |
869 | for (i = 0; i < cfg->line_outs; i++) { | 1102 | static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, |
870 | if (! spec->multiout.dac_nids[i]) | 1103 | struct auto_pin_cfg *cfg) |
1104 | { | ||
1105 | struct sigmatel_spec *spec = codec->spec; | ||
1106 | hda_nid_t nid; | ||
1107 | int i, old_num_dacs, err; | ||
1108 | |||
1109 | old_num_dacs = spec->multiout.num_dacs; | ||
1110 | for (i = 0; i < cfg->hp_outs; i++) { | ||
1111 | unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); | ||
1112 | if (wid_caps & AC_WCAP_UNSOL_CAP) | ||
1113 | spec->hp_detect = 1; | ||
1114 | nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, | ||
1115 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | ||
1116 | if (check_in_dac_nids(spec, nid)) | ||
1117 | nid = 0; | ||
1118 | if (! nid) | ||
871 | continue; | 1119 | continue; |
872 | if (spec->multiout.dac_nids[i] == nid) | 1120 | add_spec_dacs(spec, nid); |
873 | return 0; | 1121 | } |
1122 | for (i = 0; i < cfg->speaker_outs; i++) { | ||
1123 | nid = snd_hda_codec_read(codec, cfg->speaker_pins[0], 0, | ||
1124 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | ||
1125 | if (check_in_dac_nids(spec, nid)) | ||
1126 | nid = 0; | ||
1127 | if (check_in_dac_nids(spec, nid)) | ||
1128 | nid = 0; | ||
1129 | if (! nid) | ||
1130 | continue; | ||
1131 | add_spec_dacs(spec, nid); | ||
874 | } | 1132 | } |
875 | 1133 | ||
876 | spec->multiout.hp_nid = nid; | 1134 | for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { |
877 | 1135 | static const char *pfxs[] = { | |
878 | /* control HP volume/switch on the output mixer amp */ | 1136 | "Speaker", "External Speaker", "Speaker2", |
879 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Headphone Playback Volume", | 1137 | }; |
880 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | 1138 | err = create_controls(spec, pfxs[i - old_num_dacs], |
881 | return err; | 1139 | spec->multiout.dac_nids[i], 3); |
882 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Headphone Playback Switch", | 1140 | if (err < 0) |
883 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | 1141 | return err; |
884 | return err; | 1142 | } |
1143 | if (spec->multiout.hp_nid) { | ||
1144 | const char *pfx; | ||
1145 | if (old_num_dacs == spec->multiout.num_dacs) | ||
1146 | pfx = "Master"; | ||
1147 | else | ||
1148 | pfx = "Headphone"; | ||
1149 | err = create_controls(spec, pfx, spec->multiout.hp_nid, 3); | ||
1150 | if (err < 0) | ||
1151 | return err; | ||
1152 | } | ||
885 | 1153 | ||
886 | return 0; | 1154 | return 0; |
887 | } | 1155 | } |
@@ -895,23 +1163,28 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const | |||
895 | int i, j, k; | 1163 | int i, j, k; |
896 | 1164 | ||
897 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 1165 | for (i = 0; i < AUTO_PIN_LAST; i++) { |
898 | int index = -1; | 1166 | int index; |
899 | if (cfg->input_pins[i]) { | 1167 | |
900 | imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; | 1168 | if (!cfg->input_pins[i]) |
901 | 1169 | continue; | |
902 | for (j=0; j<spec->num_muxes; j++) { | 1170 | index = -1; |
903 | int num_cons = snd_hda_get_connections(codec, spec->mux_nids[j], con_lst, HDA_MAX_NUM_INPUTS); | 1171 | for (j = 0; j < spec->num_muxes; j++) { |
904 | for (k=0; k<num_cons; k++) | 1172 | int num_cons; |
905 | if (con_lst[k] == cfg->input_pins[i]) { | 1173 | num_cons = snd_hda_get_connections(codec, |
906 | index = k; | 1174 | spec->mux_nids[j], |
907 | break; | 1175 | con_lst, |
908 | } | 1176 | HDA_MAX_NUM_INPUTS); |
909 | if (index >= 0) | 1177 | for (k = 0; k < num_cons; k++) |
910 | break; | 1178 | if (con_lst[k] == cfg->input_pins[i]) { |
911 | } | 1179 | index = k; |
912 | imux->items[imux->num_items].index = index; | 1180 | goto found; |
913 | imux->num_items++; | 1181 | } |
914 | } | 1182 | } |
1183 | continue; | ||
1184 | found: | ||
1185 | imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; | ||
1186 | imux->items[imux->num_items].index = index; | ||
1187 | imux->num_items++; | ||
915 | } | 1188 | } |
916 | 1189 | ||
917 | if (imux->num_items == 1) { | 1190 | if (imux->num_items == 1) { |
@@ -944,11 +1217,20 @@ static void stac92xx_auto_init_multi_out(struct hda_codec *codec) | |||
944 | static void stac92xx_auto_init_hp_out(struct hda_codec *codec) | 1217 | static void stac92xx_auto_init_hp_out(struct hda_codec *codec) |
945 | { | 1218 | { |
946 | struct sigmatel_spec *spec = codec->spec; | 1219 | struct sigmatel_spec *spec = codec->spec; |
947 | hda_nid_t pin; | 1220 | int i; |
948 | 1221 | ||
949 | pin = spec->autocfg.hp_pin; | 1222 | for (i = 0; i < spec->autocfg.hp_outs; i++) { |
950 | if (pin) /* connect to front */ | 1223 | hda_nid_t pin; |
951 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | 1224 | pin = spec->autocfg.hp_pins[i]; |
1225 | if (pin) /* connect to front */ | ||
1226 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | ||
1227 | } | ||
1228 | for (i = 0; i < spec->autocfg.speaker_outs; i++) { | ||
1229 | hda_nid_t pin; | ||
1230 | pin = spec->autocfg.speaker_pins[i]; | ||
1231 | if (pin) /* connect to front */ | ||
1232 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN); | ||
1233 | } | ||
952 | } | 1234 | } |
953 | 1235 | ||
954 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) | 1236 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) |
@@ -994,7 +1276,7 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, | |||
994 | struct auto_pin_cfg *cfg) | 1276 | struct auto_pin_cfg *cfg) |
995 | { | 1277 | { |
996 | struct sigmatel_spec *spec = codec->spec; | 1278 | struct sigmatel_spec *spec = codec->spec; |
997 | hda_nid_t pin = cfg->hp_pin; | 1279 | hda_nid_t pin = cfg->hp_pins[0]; |
998 | unsigned int wid_caps; | 1280 | unsigned int wid_caps; |
999 | 1281 | ||
1000 | if (! pin) | 1282 | if (! pin) |
@@ -1007,6 +1289,57 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, | |||
1007 | return 0; | 1289 | return 0; |
1008 | } | 1290 | } |
1009 | 1291 | ||
1292 | /* add playback controls for LFE output */ | ||
1293 | static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, | ||
1294 | struct auto_pin_cfg *cfg) | ||
1295 | { | ||
1296 | struct sigmatel_spec *spec = codec->spec; | ||
1297 | int err; | ||
1298 | hda_nid_t lfe_pin = 0x0; | ||
1299 | int i; | ||
1300 | |||
1301 | /* | ||
1302 | * search speaker outs and line outs for a mono speaker pin | ||
1303 | * with an amp. If one is found, add LFE controls | ||
1304 | * for it. | ||
1305 | */ | ||
1306 | for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) { | ||
1307 | hda_nid_t pin = spec->autocfg.speaker_pins[i]; | ||
1308 | unsigned long wcaps = get_wcaps(codec, pin); | ||
1309 | wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); | ||
1310 | if (wcaps == AC_WCAP_OUT_AMP) | ||
1311 | /* found a mono speaker with an amp, must be lfe */ | ||
1312 | lfe_pin = pin; | ||
1313 | } | ||
1314 | |||
1315 | /* if speaker_outs is 0, then speakers may be in line_outs */ | ||
1316 | if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) { | ||
1317 | for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) { | ||
1318 | hda_nid_t pin = spec->autocfg.line_out_pins[i]; | ||
1319 | unsigned long cfg; | ||
1320 | cfg = snd_hda_codec_read(codec, pin, 0, | ||
1321 | AC_VERB_GET_CONFIG_DEFAULT, | ||
1322 | 0x00); | ||
1323 | if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) { | ||
1324 | unsigned long wcaps = get_wcaps(codec, pin); | ||
1325 | wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); | ||
1326 | if (wcaps == AC_WCAP_OUT_AMP) | ||
1327 | /* found a mono speaker with an amp, | ||
1328 | must be lfe */ | ||
1329 | lfe_pin = pin; | ||
1330 | } | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | if (lfe_pin) { | ||
1335 | err = create_controls(spec, "LFE", lfe_pin, 1); | ||
1336 | if (err < 0) | ||
1337 | return err; | ||
1338 | } | ||
1339 | |||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1010 | static int stac9200_parse_auto_config(struct hda_codec *codec) | 1343 | static int stac9200_parse_auto_config(struct hda_codec *codec) |
1011 | { | 1344 | { |
1012 | struct sigmatel_spec *spec = codec->spec; | 1345 | struct sigmatel_spec *spec = codec->spec; |
@@ -1021,6 +1354,9 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
1021 | if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) | 1354 | if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) |
1022 | return err; | 1355 | return err; |
1023 | 1356 | ||
1357 | if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) | ||
1358 | return err; | ||
1359 | |||
1024 | if (spec->autocfg.dig_out_pin) | 1360 | if (spec->autocfg.dig_out_pin) |
1025 | spec->multiout.dig_out_nid = 0x05; | 1361 | spec->multiout.dig_out_nid = 0x05; |
1026 | if (spec->autocfg.dig_in_pin) | 1362 | if (spec->autocfg.dig_in_pin) |
@@ -1073,6 +1409,15 @@ static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted) | |||
1073 | AC_VERB_SET_GPIO_DATA, gpiostate); | 1409 | AC_VERB_SET_GPIO_DATA, gpiostate); |
1074 | } | 1410 | } |
1075 | 1411 | ||
1412 | static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | ||
1413 | unsigned int event) | ||
1414 | { | ||
1415 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) | ||
1416 | snd_hda_codec_write(codec, nid, 0, | ||
1417 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1418 | (AC_USRSP_EN | event)); | ||
1419 | } | ||
1420 | |||
1076 | static int stac92xx_init(struct hda_codec *codec) | 1421 | static int stac92xx_init(struct hda_codec *codec) |
1077 | { | 1422 | { |
1078 | struct sigmatel_spec *spec = codec->spec; | 1423 | struct sigmatel_spec *spec = codec->spec; |
@@ -1084,9 +1429,10 @@ static int stac92xx_init(struct hda_codec *codec) | |||
1084 | /* set up pins */ | 1429 | /* set up pins */ |
1085 | if (spec->hp_detect) { | 1430 | if (spec->hp_detect) { |
1086 | /* Enable unsolicited responses on the HP widget */ | 1431 | /* Enable unsolicited responses on the HP widget */ |
1087 | snd_hda_codec_write(codec, cfg->hp_pin, 0, | 1432 | for (i = 0; i < cfg->hp_outs; i++) |
1088 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1433 | enable_pin_detect(codec, cfg->hp_pins[i], |
1089 | STAC_UNSOL_ENABLE); | 1434 | STAC_HP_EVENT); |
1435 | stac92xx_auto_init_hp_out(codec); | ||
1090 | /* fake event to set up pins */ | 1436 | /* fake event to set up pins */ |
1091 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); | 1437 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); |
1092 | } else { | 1438 | } else { |
@@ -1131,6 +1477,9 @@ static void stac92xx_free(struct hda_codec *codec) | |||
1131 | kfree(spec->kctl_alloc); | 1477 | kfree(spec->kctl_alloc); |
1132 | } | 1478 | } |
1133 | 1479 | ||
1480 | if (spec->bios_pin_configs) | ||
1481 | kfree(spec->bios_pin_configs); | ||
1482 | |||
1134 | kfree(spec); | 1483 | kfree(spec); |
1135 | } | 1484 | } |
1136 | 1485 | ||
@@ -1139,6 +1488,8 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
1139 | { | 1488 | { |
1140 | unsigned int pin_ctl = snd_hda_codec_read(codec, nid, | 1489 | unsigned int pin_ctl = snd_hda_codec_read(codec, nid, |
1141 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); | 1490 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); |
1491 | if (flag == AC_PINCTL_OUT_EN && (pin_ctl & AC_PINCTL_IN_EN)) | ||
1492 | return; | ||
1142 | snd_hda_codec_write(codec, nid, 0, | 1493 | snd_hda_codec_write(codec, nid, 0, |
1143 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 1494 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
1144 | pin_ctl | flag); | 1495 | pin_ctl | flag); |
@@ -1154,33 +1505,57 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
1154 | pin_ctl & ~flag); | 1505 | pin_ctl & ~flag); |
1155 | } | 1506 | } |
1156 | 1507 | ||
1157 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | 1508 | static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) |
1509 | { | ||
1510 | if (!nid) | ||
1511 | return 0; | ||
1512 | if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) | ||
1513 | & (1 << 31)) | ||
1514 | return 1; | ||
1515 | return 0; | ||
1516 | } | ||
1517 | |||
1518 | static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | ||
1158 | { | 1519 | { |
1159 | struct sigmatel_spec *spec = codec->spec; | 1520 | struct sigmatel_spec *spec = codec->spec; |
1160 | struct auto_pin_cfg *cfg = &spec->autocfg; | 1521 | struct auto_pin_cfg *cfg = &spec->autocfg; |
1161 | int i, presence; | 1522 | int i, presence; |
1162 | 1523 | ||
1163 | if ((res >> 26) != STAC_HP_EVENT) | 1524 | presence = 0; |
1164 | return; | 1525 | for (i = 0; i < cfg->hp_outs; i++) { |
1165 | 1526 | presence = get_pin_presence(codec, cfg->hp_pins[i]); | |
1166 | presence = snd_hda_codec_read(codec, cfg->hp_pin, 0, | 1527 | if (presence) |
1167 | AC_VERB_GET_PIN_SENSE, 0x00) >> 31; | 1528 | break; |
1529 | } | ||
1168 | 1530 | ||
1169 | if (presence) { | 1531 | if (presence) { |
1170 | /* disable lineouts, enable hp */ | 1532 | /* disable lineouts, enable hp */ |
1171 | for (i = 0; i < cfg->line_outs; i++) | 1533 | for (i = 0; i < cfg->line_outs; i++) |
1172 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], | 1534 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], |
1173 | AC_PINCTL_OUT_EN); | 1535 | AC_PINCTL_OUT_EN); |
1174 | stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); | 1536 | for (i = 0; i < cfg->speaker_outs; i++) |
1537 | stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], | ||
1538 | AC_PINCTL_OUT_EN); | ||
1175 | } else { | 1539 | } else { |
1176 | /* enable lineouts, disable hp */ | 1540 | /* enable lineouts, disable hp */ |
1177 | for (i = 0; i < cfg->line_outs; i++) | 1541 | for (i = 0; i < cfg->line_outs; i++) |
1178 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], | 1542 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], |
1179 | AC_PINCTL_OUT_EN); | 1543 | AC_PINCTL_OUT_EN); |
1180 | stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); | 1544 | for (i = 0; i < cfg->speaker_outs; i++) |
1545 | stac92xx_set_pinctl(codec, cfg->speaker_pins[i], | ||
1546 | AC_PINCTL_OUT_EN); | ||
1181 | } | 1547 | } |
1182 | } | 1548 | } |
1183 | 1549 | ||
1550 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | ||
1551 | { | ||
1552 | switch (res >> 26) { | ||
1553 | case STAC_HP_EVENT: | ||
1554 | stac92xx_hp_detect(codec, res); | ||
1555 | break; | ||
1556 | } | ||
1557 | } | ||
1558 | |||
1184 | #ifdef CONFIG_PM | 1559 | #ifdef CONFIG_PM |
1185 | static int stac92xx_resume(struct hda_codec *codec) | 1560 | static int stac92xx_resume(struct hda_codec *codec) |
1186 | { | 1561 | { |
@@ -1188,6 +1563,7 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
1188 | int i; | 1563 | int i; |
1189 | 1564 | ||
1190 | stac92xx_init(codec); | 1565 | stac92xx_init(codec); |
1566 | stac92xx_set_config_regs(codec); | ||
1191 | for (i = 0; i < spec->num_mixers; i++) | 1567 | for (i = 0; i < spec->num_mixers; i++) |
1192 | snd_hda_resume_ctls(codec, spec->mixers[i]); | 1568 | snd_hda_resume_ctls(codec, spec->mixers[i]); |
1193 | if (spec->multiout.dig_out_nid) | 1569 | if (spec->multiout.dig_out_nid) |
@@ -1220,12 +1596,18 @@ static int patch_stac9200(struct hda_codec *codec) | |||
1220 | return -ENOMEM; | 1596 | return -ENOMEM; |
1221 | 1597 | ||
1222 | codec->spec = spec; | 1598 | codec->spec = spec; |
1599 | spec->num_pins = 8; | ||
1600 | spec->pin_nids = stac9200_pin_nids; | ||
1223 | spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl); | 1601 | spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl); |
1224 | if (spec->board_config < 0) | 1602 | if (spec->board_config < 0) { |
1225 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); | 1603 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); |
1226 | else { | 1604 | err = stac92xx_save_bios_config_regs(codec); |
1227 | spec->num_pins = 8; | 1605 | if (err < 0) { |
1228 | spec->pin_nids = stac9200_pin_nids; | 1606 | stac92xx_free(codec); |
1607 | return err; | ||
1608 | } | ||
1609 | spec->pin_configs = spec->bios_pin_configs; | ||
1610 | } else { | ||
1229 | spec->pin_configs = stac9200_brd_tbl[spec->board_config]; | 1611 | spec->pin_configs = stac9200_brd_tbl[spec->board_config]; |
1230 | stac92xx_set_config_regs(codec); | 1612 | stac92xx_set_config_regs(codec); |
1231 | } | 1613 | } |
@@ -1261,13 +1643,19 @@ static int patch_stac922x(struct hda_codec *codec) | |||
1261 | return -ENOMEM; | 1643 | return -ENOMEM; |
1262 | 1644 | ||
1263 | codec->spec = spec; | 1645 | codec->spec = spec; |
1646 | spec->num_pins = 10; | ||
1647 | spec->pin_nids = stac922x_pin_nids; | ||
1264 | spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); | 1648 | spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); |
1265 | if (spec->board_config < 0) | 1649 | if (spec->board_config < 0) { |
1266 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " | 1650 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " |
1267 | "using BIOS defaults\n"); | 1651 | "using BIOS defaults\n"); |
1268 | else if (stac922x_brd_tbl[spec->board_config] != NULL) { | 1652 | err = stac92xx_save_bios_config_regs(codec); |
1269 | spec->num_pins = 10; | 1653 | if (err < 0) { |
1270 | spec->pin_nids = stac922x_pin_nids; | 1654 | stac92xx_free(codec); |
1655 | return err; | ||
1656 | } | ||
1657 | spec->pin_configs = spec->bios_pin_configs; | ||
1658 | } else if (stac922x_brd_tbl[spec->board_config] != NULL) { | ||
1271 | spec->pin_configs = stac922x_brd_tbl[spec->board_config]; | 1659 | spec->pin_configs = stac922x_brd_tbl[spec->board_config]; |
1272 | stac92xx_set_config_regs(codec); | 1660 | stac92xx_set_config_regs(codec); |
1273 | } | 1661 | } |
@@ -1281,25 +1669,6 @@ static int patch_stac922x(struct hda_codec *codec) | |||
1281 | 1669 | ||
1282 | spec->multiout.dac_nids = spec->dac_nids; | 1670 | spec->multiout.dac_nids = spec->dac_nids; |
1283 | 1671 | ||
1284 | switch (spec->board_config) { | ||
1285 | case STAC_D965_2112: | ||
1286 | spec->adc_nids = stac9227_adc_nids; | ||
1287 | spec->mux_nids = stac9227_mux_nids; | ||
1288 | #if 0 | ||
1289 | spec->multiout.dac_nids = d965_2112_dac_nids; | ||
1290 | spec->multiout.num_dacs = ARRAY_SIZE(d965_2112_dac_nids); | ||
1291 | #endif | ||
1292 | spec->init = d965_2112_core_init; | ||
1293 | spec->mixer = stac9227_mixer; | ||
1294 | break; | ||
1295 | case STAC_D965_284B: | ||
1296 | spec->adc_nids = stac9227_adc_nids; | ||
1297 | spec->mux_nids = stac9227_mux_nids; | ||
1298 | spec->init = stac9227_core_init; | ||
1299 | spec->mixer = stac9227_mixer; | ||
1300 | break; | ||
1301 | } | ||
1302 | |||
1303 | err = stac92xx_parse_auto_config(codec, 0x08, 0x09); | 1672 | err = stac92xx_parse_auto_config(codec, 0x08, 0x09); |
1304 | if (err < 0) { | 1673 | if (err < 0) { |
1305 | stac92xx_free(codec); | 1674 | stac92xx_free(codec); |
@@ -1324,26 +1693,94 @@ static int patch_stac927x(struct hda_codec *codec) | |||
1324 | return -ENOMEM; | 1693 | return -ENOMEM; |
1325 | 1694 | ||
1326 | codec->spec = spec; | 1695 | codec->spec = spec; |
1696 | spec->num_pins = 14; | ||
1697 | spec->pin_nids = stac927x_pin_nids; | ||
1327 | spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl); | 1698 | spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl); |
1328 | if (spec->board_config < 0) | 1699 | if (spec->board_config < 0) { |
1329 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); | 1700 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); |
1330 | else { | 1701 | err = stac92xx_save_bios_config_regs(codec); |
1331 | spec->num_pins = 14; | 1702 | if (err < 0) { |
1332 | spec->pin_nids = stac927x_pin_nids; | 1703 | stac92xx_free(codec); |
1704 | return err; | ||
1705 | } | ||
1706 | spec->pin_configs = spec->bios_pin_configs; | ||
1707 | } else if (stac927x_brd_tbl[spec->board_config] != NULL) { | ||
1333 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; | 1708 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; |
1334 | stac92xx_set_config_regs(codec); | 1709 | stac92xx_set_config_regs(codec); |
1335 | } | 1710 | } |
1336 | 1711 | ||
1337 | spec->adc_nids = stac927x_adc_nids; | 1712 | switch (spec->board_config) { |
1338 | spec->mux_nids = stac927x_mux_nids; | 1713 | case STAC_D965_3ST: |
1714 | spec->adc_nids = stac927x_adc_nids; | ||
1715 | spec->mux_nids = stac927x_mux_nids; | ||
1716 | spec->num_muxes = 3; | ||
1717 | spec->init = d965_core_init; | ||
1718 | spec->mixer = stac9227_mixer; | ||
1719 | break; | ||
1720 | case STAC_D965_5ST: | ||
1721 | spec->adc_nids = stac927x_adc_nids; | ||
1722 | spec->mux_nids = stac927x_mux_nids; | ||
1723 | spec->num_muxes = 3; | ||
1724 | spec->init = d965_core_init; | ||
1725 | spec->mixer = stac9227_mixer; | ||
1726 | break; | ||
1727 | default: | ||
1728 | spec->adc_nids = stac927x_adc_nids; | ||
1729 | spec->mux_nids = stac927x_mux_nids; | ||
1730 | spec->num_muxes = 3; | ||
1731 | spec->init = stac927x_core_init; | ||
1732 | spec->mixer = stac927x_mixer; | ||
1733 | } | ||
1734 | |||
1735 | spec->multiout.dac_nids = spec->dac_nids; | ||
1736 | |||
1737 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); | ||
1738 | if (err < 0) { | ||
1739 | stac92xx_free(codec); | ||
1740 | return err; | ||
1741 | } | ||
1742 | |||
1743 | codec->patch_ops = stac92xx_patch_ops; | ||
1744 | |||
1745 | return 0; | ||
1746 | } | ||
1747 | |||
1748 | static int patch_stac9205(struct hda_codec *codec) | ||
1749 | { | ||
1750 | struct sigmatel_spec *spec; | ||
1751 | int err; | ||
1752 | |||
1753 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1754 | if (spec == NULL) | ||
1755 | return -ENOMEM; | ||
1756 | |||
1757 | codec->spec = spec; | ||
1758 | spec->num_pins = 14; | ||
1759 | spec->pin_nids = stac9205_pin_nids; | ||
1760 | spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl); | ||
1761 | if (spec->board_config < 0) { | ||
1762 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); | ||
1763 | err = stac92xx_save_bios_config_regs(codec); | ||
1764 | if (err < 0) { | ||
1765 | stac92xx_free(codec); | ||
1766 | return err; | ||
1767 | } | ||
1768 | spec->pin_configs = spec->bios_pin_configs; | ||
1769 | } else { | ||
1770 | spec->pin_configs = stac9205_brd_tbl[spec->board_config]; | ||
1771 | stac92xx_set_config_regs(codec); | ||
1772 | } | ||
1773 | |||
1774 | spec->adc_nids = stac9205_adc_nids; | ||
1775 | spec->mux_nids = stac9205_mux_nids; | ||
1339 | spec->num_muxes = 3; | 1776 | spec->num_muxes = 3; |
1340 | 1777 | ||
1341 | spec->init = stac927x_core_init; | 1778 | spec->init = stac9205_core_init; |
1342 | spec->mixer = stac927x_mixer; | 1779 | spec->mixer = stac9205_mixer; |
1343 | 1780 | ||
1344 | spec->multiout.dac_nids = spec->dac_nids; | 1781 | spec->multiout.dac_nids = spec->dac_nids; |
1345 | 1782 | ||
1346 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); | 1783 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); |
1347 | if (err < 0) { | 1784 | if (err < 0) { |
1348 | stac92xx_free(codec); | 1785 | stac92xx_free(codec); |
1349 | return err; | 1786 | return err; |
@@ -1355,10 +1792,10 @@ static int patch_stac927x(struct hda_codec *codec) | |||
1355 | } | 1792 | } |
1356 | 1793 | ||
1357 | /* | 1794 | /* |
1358 | * STAC 7661(?) hack | 1795 | * STAC9872 hack |
1359 | */ | 1796 | */ |
1360 | 1797 | ||
1361 | /* static config for Sony VAIO FE550G */ | 1798 | /* static config for Sony VAIO FE550G and Sony VAIO AR */ |
1362 | static hda_nid_t vaio_dacs[] = { 0x2 }; | 1799 | static hda_nid_t vaio_dacs[] = { 0x2 }; |
1363 | #define VAIO_HP_DAC 0x5 | 1800 | #define VAIO_HP_DAC 0x5 |
1364 | static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; | 1801 | static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; |
@@ -1389,6 +1826,23 @@ static struct hda_verb vaio_init[] = { | |||
1389 | {} | 1826 | {} |
1390 | }; | 1827 | }; |
1391 | 1828 | ||
1829 | static struct hda_verb vaio_ar_init[] = { | ||
1830 | {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ | ||
1831 | {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ | ||
1832 | {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ | ||
1833 | {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ | ||
1834 | /* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */ | ||
1835 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */ | ||
1836 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */ | ||
1837 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */ | ||
1838 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */ | ||
1839 | /* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */ | ||
1840 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */ | ||
1841 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */ | ||
1842 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */ | ||
1843 | {} | ||
1844 | }; | ||
1845 | |||
1392 | /* bind volumes of both NID 0x02 and 0x05 */ | 1846 | /* bind volumes of both NID 0x02 and 0x05 */ |
1393 | static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, | 1847 | static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, |
1394 | struct snd_ctl_elem_value *ucontrol) | 1848 | struct snd_ctl_elem_value *ucontrol) |
@@ -1434,6 +1888,38 @@ static struct snd_kcontrol_new vaio_mixer[] = { | |||
1434 | .info = snd_hda_mixer_amp_volume_info, | 1888 | .info = snd_hda_mixer_amp_volume_info, |
1435 | .get = snd_hda_mixer_amp_volume_get, | 1889 | .get = snd_hda_mixer_amp_volume_get, |
1436 | .put = vaio_master_vol_put, | 1890 | .put = vaio_master_vol_put, |
1891 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
1892 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
1893 | }, | ||
1894 | { | ||
1895 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1896 | .name = "Master Playback Switch", | ||
1897 | .info = snd_hda_mixer_amp_switch_info, | ||
1898 | .get = snd_hda_mixer_amp_switch_get, | ||
1899 | .put = vaio_master_sw_put, | ||
1900 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
1901 | }, | ||
1902 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ | ||
1903 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), | ||
1904 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), | ||
1905 | { | ||
1906 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1907 | .name = "Capture Source", | ||
1908 | .count = 1, | ||
1909 | .info = stac92xx_mux_enum_info, | ||
1910 | .get = stac92xx_mux_enum_get, | ||
1911 | .put = stac92xx_mux_enum_put, | ||
1912 | }, | ||
1913 | {} | ||
1914 | }; | ||
1915 | |||
1916 | static struct snd_kcontrol_new vaio_ar_mixer[] = { | ||
1917 | { | ||
1918 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1919 | .name = "Master Playback Volume", | ||
1920 | .info = snd_hda_mixer_amp_volume_info, | ||
1921 | .get = snd_hda_mixer_amp_volume_get, | ||
1922 | .put = vaio_master_vol_put, | ||
1437 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | 1923 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), |
1438 | }, | 1924 | }, |
1439 | { | 1925 | { |
@@ -1447,6 +1933,8 @@ static struct snd_kcontrol_new vaio_mixer[] = { | |||
1447 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ | 1933 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ |
1448 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), | 1934 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), |
1449 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), | 1935 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), |
1936 | /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT), | ||
1937 | HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/ | ||
1450 | { | 1938 | { |
1451 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1939 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1452 | .name = "Capture Source", | 1940 | .name = "Capture Source", |
@@ -1458,7 +1946,7 @@ static struct snd_kcontrol_new vaio_mixer[] = { | |||
1458 | {} | 1946 | {} |
1459 | }; | 1947 | }; |
1460 | 1948 | ||
1461 | static struct hda_codec_ops stac7661_patch_ops = { | 1949 | static struct hda_codec_ops stac9872_patch_ops = { |
1462 | .build_controls = stac92xx_build_controls, | 1950 | .build_controls = stac92xx_build_controls, |
1463 | .build_pcms = stac92xx_build_pcms, | 1951 | .build_pcms = stac92xx_build_pcms, |
1464 | .init = stac92xx_init, | 1952 | .init = stac92xx_init, |
@@ -1468,23 +1956,34 @@ static struct hda_codec_ops stac7661_patch_ops = { | |||
1468 | #endif | 1956 | #endif |
1469 | }; | 1957 | }; |
1470 | 1958 | ||
1471 | enum { STAC7661_VAIO }; | 1959 | enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */ |
1472 | 1960 | CXD9872RD_VAIO, | |
1473 | static struct hda_board_config stac7661_cfg_tbl[] = { | 1961 | /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */ |
1474 | { .modelname = "vaio", .config = STAC7661_VAIO }, | 1962 | STAC9872AK_VAIO, |
1963 | /* Unknown. id=0x83847661 and subsys=0x104D1200. */ | ||
1964 | STAC9872K_VAIO, | ||
1965 | /* AR Series. id=0x83847664 and subsys=104D1300 */ | ||
1966 | CXD9872AKD_VAIO | ||
1967 | }; | ||
1968 | |||
1969 | static struct hda_board_config stac9872_cfg_tbl[] = { | ||
1970 | { .modelname = "vaio", .config = CXD9872RD_VAIO }, | ||
1971 | { .modelname = "vaio-ar", .config = CXD9872AKD_VAIO }, | ||
1475 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6, | 1972 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6, |
1476 | .config = STAC7661_VAIO }, | 1973 | .config = CXD9872RD_VAIO }, |
1477 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef, | 1974 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef, |
1478 | .config = STAC7661_VAIO }, | 1975 | .config = CXD9872RD_VAIO }, |
1976 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd, | ||
1977 | .config = CXD9872AKD_VAIO }, | ||
1479 | {} | 1978 | {} |
1480 | }; | 1979 | }; |
1481 | 1980 | ||
1482 | static int patch_stac7661(struct hda_codec *codec) | 1981 | static int patch_stac9872(struct hda_codec *codec) |
1483 | { | 1982 | { |
1484 | struct sigmatel_spec *spec; | 1983 | struct sigmatel_spec *spec; |
1485 | int board_config; | 1984 | int board_config; |
1486 | 1985 | ||
1487 | board_config = snd_hda_check_board_config(codec, stac7661_cfg_tbl); | 1986 | board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl); |
1488 | if (board_config < 0) | 1987 | if (board_config < 0) |
1489 | /* unknown config, let generic-parser do its job... */ | 1988 | /* unknown config, let generic-parser do its job... */ |
1490 | return snd_hda_parse_generic_codec(codec); | 1989 | return snd_hda_parse_generic_codec(codec); |
@@ -1495,7 +1994,9 @@ static int patch_stac7661(struct hda_codec *codec) | |||
1495 | 1994 | ||
1496 | codec->spec = spec; | 1995 | codec->spec = spec; |
1497 | switch (board_config) { | 1996 | switch (board_config) { |
1498 | case STAC7661_VAIO: | 1997 | case CXD9872RD_VAIO: |
1998 | case STAC9872AK_VAIO: | ||
1999 | case STAC9872K_VAIO: | ||
1499 | spec->mixer = vaio_mixer; | 2000 | spec->mixer = vaio_mixer; |
1500 | spec->init = vaio_init; | 2001 | spec->init = vaio_init; |
1501 | spec->multiout.max_channels = 2; | 2002 | spec->multiout.max_channels = 2; |
@@ -1507,9 +2008,22 @@ static int patch_stac7661(struct hda_codec *codec) | |||
1507 | spec->input_mux = &vaio_mux; | 2008 | spec->input_mux = &vaio_mux; |
1508 | spec->mux_nids = vaio_mux_nids; | 2009 | spec->mux_nids = vaio_mux_nids; |
1509 | break; | 2010 | break; |
2011 | |||
2012 | case CXD9872AKD_VAIO: | ||
2013 | spec->mixer = vaio_ar_mixer; | ||
2014 | spec->init = vaio_ar_init; | ||
2015 | spec->multiout.max_channels = 2; | ||
2016 | spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs); | ||
2017 | spec->multiout.dac_nids = vaio_dacs; | ||
2018 | spec->multiout.hp_nid = VAIO_HP_DAC; | ||
2019 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); | ||
2020 | spec->adc_nids = vaio_adcs; | ||
2021 | spec->input_mux = &vaio_mux; | ||
2022 | spec->mux_nids = vaio_mux_nids; | ||
2023 | break; | ||
1510 | } | 2024 | } |
1511 | 2025 | ||
1512 | codec->patch_ops = stac7661_patch_ops; | 2026 | codec->patch_ops = stac9872_patch_ops; |
1513 | return 0; | 2027 | return 0; |
1514 | } | 2028 | } |
1515 | 2029 | ||
@@ -1525,12 +2039,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
1525 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, | 2039 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, |
1526 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, | 2040 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, |
1527 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, | 2041 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, |
1528 | { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac922x }, | 2042 | { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x }, |
1529 | { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac922x }, | 2043 | { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x }, |
1530 | { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac922x }, | 2044 | { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x }, |
1531 | { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac922x }, | 2045 | { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x }, |
1532 | { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac922x }, | 2046 | { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x }, |
1533 | { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac922x }, | 2047 | { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x }, |
1534 | { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, | 2048 | { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, |
1535 | { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, | 2049 | { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, |
1536 | { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, | 2050 | { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, |
@@ -1541,6 +2055,20 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
1541 | { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, | 2055 | { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, |
1542 | { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, | 2056 | { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, |
1543 | { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, | 2057 | { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, |
1544 | { .id = 0x83847661, .name = "STAC7661", .patch = patch_stac7661 }, | 2058 | /* The following does not take into account .id=0x83847661 when subsys = |
2059 | * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are | ||
2060 | * currently not fully supported. | ||
2061 | */ | ||
2062 | { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, | ||
2063 | { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, | ||
2064 | { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, | ||
2065 | { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, | ||
2066 | { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, | ||
2067 | { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, | ||
2068 | { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 }, | ||
2069 | { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 }, | ||
2070 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, | ||
2071 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, | ||
2072 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, | ||
1545 | {} /* terminator */ | 2073 | {} /* terminator */ |
1546 | }; | 2074 | }; |
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 9492f3d2455b..9e76cebd2d22 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include "ice1712.h" | 60 | #include "ice1712.h" |
61 | #include "envy24ht.h" | 61 | #include "envy24ht.h" |
62 | #include "aureon.h" | 62 | #include "aureon.h" |
63 | #include <sound/tlv.h> | ||
63 | 64 | ||
64 | /* WM8770 registers */ | 65 | /* WM8770 registers */ |
65 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | 66 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ |
@@ -660,6 +661,12 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
660 | return change; | 661 | return change; |
661 | } | 662 | } |
662 | 663 | ||
664 | static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | ||
665 | static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); | ||
666 | static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); | ||
667 | static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); | ||
668 | static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); | ||
669 | |||
663 | /* | 670 | /* |
664 | * Logarithmic volume values for WM8770 | 671 | * Logarithmic volume values for WM8770 |
665 | * Computed as 20 * Log10(255 / x) | 672 | * Computed as 20 * Log10(255 / x) |
@@ -1409,10 +1416,13 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1409 | }, | 1416 | }, |
1410 | { | 1417 | { |
1411 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1418 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1419 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1420 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1412 | .name = "Master Playback Volume", | 1421 | .name = "Master Playback Volume", |
1413 | .info = wm_master_vol_info, | 1422 | .info = wm_master_vol_info, |
1414 | .get = wm_master_vol_get, | 1423 | .get = wm_master_vol_get, |
1415 | .put = wm_master_vol_put | 1424 | .put = wm_master_vol_put, |
1425 | .tlv = { .p = db_scale_wm_dac } | ||
1416 | }, | 1426 | }, |
1417 | { | 1427 | { |
1418 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1428 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1424,11 +1434,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1424 | }, | 1434 | }, |
1425 | { | 1435 | { |
1426 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1437 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1438 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1427 | .name = "Front Playback Volume", | 1439 | .name = "Front Playback Volume", |
1428 | .info = wm_vol_info, | 1440 | .info = wm_vol_info, |
1429 | .get = wm_vol_get, | 1441 | .get = wm_vol_get, |
1430 | .put = wm_vol_put, | 1442 | .put = wm_vol_put, |
1431 | .private_value = (2 << 8) | 0 | 1443 | .private_value = (2 << 8) | 0, |
1444 | .tlv = { .p = db_scale_wm_dac } | ||
1432 | }, | 1445 | }, |
1433 | { | 1446 | { |
1434 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1447 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1440,11 +1453,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1440 | }, | 1453 | }, |
1441 | { | 1454 | { |
1442 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1455 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1456 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1457 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1443 | .name = "Rear Playback Volume", | 1458 | .name = "Rear Playback Volume", |
1444 | .info = wm_vol_info, | 1459 | .info = wm_vol_info, |
1445 | .get = wm_vol_get, | 1460 | .get = wm_vol_get, |
1446 | .put = wm_vol_put, | 1461 | .put = wm_vol_put, |
1447 | .private_value = (2 << 8) | 2 | 1462 | .private_value = (2 << 8) | 2, |
1463 | .tlv = { .p = db_scale_wm_dac } | ||
1448 | }, | 1464 | }, |
1449 | { | 1465 | { |
1450 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1466 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1456,11 +1472,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1456 | }, | 1472 | }, |
1457 | { | 1473 | { |
1458 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1474 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1475 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1476 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1459 | .name = "Center Playback Volume", | 1477 | .name = "Center Playback Volume", |
1460 | .info = wm_vol_info, | 1478 | .info = wm_vol_info, |
1461 | .get = wm_vol_get, | 1479 | .get = wm_vol_get, |
1462 | .put = wm_vol_put, | 1480 | .put = wm_vol_put, |
1463 | .private_value = (1 << 8) | 4 | 1481 | .private_value = (1 << 8) | 4, |
1482 | .tlv = { .p = db_scale_wm_dac } | ||
1464 | }, | 1483 | }, |
1465 | { | 1484 | { |
1466 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1485 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1472,11 +1491,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1472 | }, | 1491 | }, |
1473 | { | 1492 | { |
1474 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1493 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1494 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1495 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1475 | .name = "LFE Playback Volume", | 1496 | .name = "LFE Playback Volume", |
1476 | .info = wm_vol_info, | 1497 | .info = wm_vol_info, |
1477 | .get = wm_vol_get, | 1498 | .get = wm_vol_get, |
1478 | .put = wm_vol_put, | 1499 | .put = wm_vol_put, |
1479 | .private_value = (1 << 8) | 5 | 1500 | .private_value = (1 << 8) | 5, |
1501 | .tlv = { .p = db_scale_wm_dac } | ||
1480 | }, | 1502 | }, |
1481 | { | 1503 | { |
1482 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1504 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1488,11 +1510,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1488 | }, | 1510 | }, |
1489 | { | 1511 | { |
1490 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1512 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1513 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1514 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1491 | .name = "Side Playback Volume", | 1515 | .name = "Side Playback Volume", |
1492 | .info = wm_vol_info, | 1516 | .info = wm_vol_info, |
1493 | .get = wm_vol_get, | 1517 | .get = wm_vol_get, |
1494 | .put = wm_vol_put, | 1518 | .put = wm_vol_put, |
1495 | .private_value = (2 << 8) | 6 | 1519 | .private_value = (2 << 8) | 6, |
1520 | .tlv = { .p = db_scale_wm_dac } | ||
1496 | } | 1521 | } |
1497 | }; | 1522 | }; |
1498 | 1523 | ||
@@ -1506,10 +1531,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { | |||
1506 | }, | 1531 | }, |
1507 | { | 1532 | { |
1508 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1533 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1534 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1535 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1509 | .name = "PCM Playback Volume", | 1536 | .name = "PCM Playback Volume", |
1510 | .info = wm_pcm_vol_info, | 1537 | .info = wm_pcm_vol_info, |
1511 | .get = wm_pcm_vol_get, | 1538 | .get = wm_pcm_vol_get, |
1512 | .put = wm_pcm_vol_put | 1539 | .put = wm_pcm_vol_put, |
1540 | .tlv = { .p = db_scale_wm_pcm } | ||
1513 | }, | 1541 | }, |
1514 | { | 1542 | { |
1515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1543 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1520,10 +1548,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { | |||
1520 | }, | 1548 | }, |
1521 | { | 1549 | { |
1522 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1550 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1551 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1552 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1523 | .name = "Capture Volume", | 1553 | .name = "Capture Volume", |
1524 | .info = wm_adc_vol_info, | 1554 | .info = wm_adc_vol_info, |
1525 | .get = wm_adc_vol_get, | 1555 | .get = wm_adc_vol_get, |
1526 | .put = wm_adc_vol_put | 1556 | .put = wm_adc_vol_put, |
1557 | .tlv = { .p = db_scale_wm_adc } | ||
1527 | }, | 1558 | }, |
1528 | { | 1559 | { |
1529 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1560 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1567,11 +1598,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1567 | }, | 1598 | }, |
1568 | { | 1599 | { |
1569 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1601 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1602 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1570 | .name = "AC97 Playback Volume", | 1603 | .name = "AC97 Playback Volume", |
1571 | .info = aureon_ac97_vol_info, | 1604 | .info = aureon_ac97_vol_info, |
1572 | .get = aureon_ac97_vol_get, | 1605 | .get = aureon_ac97_vol_get, |
1573 | .put = aureon_ac97_vol_put, | 1606 | .put = aureon_ac97_vol_put, |
1574 | .private_value = AC97_MASTER|AUREON_AC97_STEREO | 1607 | .private_value = AC97_MASTER|AUREON_AC97_STEREO, |
1608 | .tlv = { .p = db_scale_ac97_master } | ||
1575 | }, | 1609 | }, |
1576 | { | 1610 | { |
1577 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1611 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1583,11 +1617,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1583 | }, | 1617 | }, |
1584 | { | 1618 | { |
1585 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1619 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1620 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1621 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1586 | .name = "CD Playback Volume", | 1622 | .name = "CD Playback Volume", |
1587 | .info = aureon_ac97_vol_info, | 1623 | .info = aureon_ac97_vol_info, |
1588 | .get = aureon_ac97_vol_get, | 1624 | .get = aureon_ac97_vol_get, |
1589 | .put = aureon_ac97_vol_put, | 1625 | .put = aureon_ac97_vol_put, |
1590 | .private_value = AC97_CD|AUREON_AC97_STEREO | 1626 | .private_value = AC97_CD|AUREON_AC97_STEREO, |
1627 | .tlv = { .p = db_scale_ac97_gain } | ||
1591 | }, | 1628 | }, |
1592 | { | 1629 | { |
1593 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1630 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1599,11 +1636,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1599 | }, | 1636 | }, |
1600 | { | 1637 | { |
1601 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1638 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1639 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1640 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1602 | .name = "Aux Playback Volume", | 1641 | .name = "Aux Playback Volume", |
1603 | .info = aureon_ac97_vol_info, | 1642 | .info = aureon_ac97_vol_info, |
1604 | .get = aureon_ac97_vol_get, | 1643 | .get = aureon_ac97_vol_get, |
1605 | .put = aureon_ac97_vol_put, | 1644 | .put = aureon_ac97_vol_put, |
1606 | .private_value = AC97_AUX|AUREON_AC97_STEREO | 1645 | .private_value = AC97_AUX|AUREON_AC97_STEREO, |
1646 | .tlv = { .p = db_scale_ac97_gain } | ||
1607 | }, | 1647 | }, |
1608 | { | 1648 | { |
1609 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1649 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1615,11 +1655,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1615 | }, | 1655 | }, |
1616 | { | 1656 | { |
1617 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1657 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1658 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1659 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1618 | .name = "Line Playback Volume", | 1660 | .name = "Line Playback Volume", |
1619 | .info = aureon_ac97_vol_info, | 1661 | .info = aureon_ac97_vol_info, |
1620 | .get = aureon_ac97_vol_get, | 1662 | .get = aureon_ac97_vol_get, |
1621 | .put = aureon_ac97_vol_put, | 1663 | .put = aureon_ac97_vol_put, |
1622 | .private_value = AC97_LINE|AUREON_AC97_STEREO | 1664 | .private_value = AC97_LINE|AUREON_AC97_STEREO, |
1665 | .tlv = { .p = db_scale_ac97_gain } | ||
1623 | }, | 1666 | }, |
1624 | { | 1667 | { |
1625 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1668 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1631,11 +1674,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1631 | }, | 1674 | }, |
1632 | { | 1675 | { |
1633 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1676 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1677 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1678 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1634 | .name = "Mic Playback Volume", | 1679 | .name = "Mic Playback Volume", |
1635 | .info = aureon_ac97_vol_info, | 1680 | .info = aureon_ac97_vol_info, |
1636 | .get = aureon_ac97_vol_get, | 1681 | .get = aureon_ac97_vol_get, |
1637 | .put = aureon_ac97_vol_put, | 1682 | .put = aureon_ac97_vol_put, |
1638 | .private_value = AC97_MIC | 1683 | .private_value = AC97_MIC, |
1684 | .tlv = { .p = db_scale_ac97_gain } | ||
1639 | }, | 1685 | }, |
1640 | { | 1686 | { |
1641 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1687 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1657,11 +1703,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1657 | }, | 1703 | }, |
1658 | { | 1704 | { |
1659 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1706 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1707 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1660 | .name = "AC97 Playback Volume", | 1708 | .name = "AC97 Playback Volume", |
1661 | .info = aureon_ac97_vol_info, | 1709 | .info = aureon_ac97_vol_info, |
1662 | .get = aureon_ac97_vol_get, | 1710 | .get = aureon_ac97_vol_get, |
1663 | .put = aureon_ac97_vol_put, | 1711 | .put = aureon_ac97_vol_put, |
1664 | .private_value = AC97_MASTER|AUREON_AC97_STEREO | 1712 | .private_value = AC97_MASTER|AUREON_AC97_STEREO, |
1713 | .tlv = { .p = db_scale_ac97_master } | ||
1665 | }, | 1714 | }, |
1666 | { | 1715 | { |
1667 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1716 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1673,11 +1722,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1673 | }, | 1722 | }, |
1674 | { | 1723 | { |
1675 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1724 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1725 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1726 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1676 | .name = "CD Playback Volume", | 1727 | .name = "CD Playback Volume", |
1677 | .info = aureon_ac97_vol_info, | 1728 | .info = aureon_ac97_vol_info, |
1678 | .get = aureon_ac97_vol_get, | 1729 | .get = aureon_ac97_vol_get, |
1679 | .put = aureon_ac97_vol_put, | 1730 | .put = aureon_ac97_vol_put, |
1680 | .private_value = AC97_AUX|AUREON_AC97_STEREO | 1731 | .private_value = AC97_AUX|AUREON_AC97_STEREO, |
1732 | .tlv = { .p = db_scale_ac97_gain } | ||
1681 | }, | 1733 | }, |
1682 | { | 1734 | { |
1683 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1735 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1685,15 +1737,18 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1685 | .info = aureon_ac97_mute_info, | 1737 | .info = aureon_ac97_mute_info, |
1686 | .get = aureon_ac97_mute_get, | 1738 | .get = aureon_ac97_mute_get, |
1687 | .put = aureon_ac97_mute_put, | 1739 | .put = aureon_ac97_mute_put, |
1688 | .private_value = AC97_CD, | 1740 | .private_value = AC97_CD |
1689 | }, | 1741 | }, |
1690 | { | 1742 | { |
1691 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1743 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1744 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1745 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1692 | .name = "Phono Playback Volume", | 1746 | .name = "Phono Playback Volume", |
1693 | .info = aureon_ac97_vol_info, | 1747 | .info = aureon_ac97_vol_info, |
1694 | .get = aureon_ac97_vol_get, | 1748 | .get = aureon_ac97_vol_get, |
1695 | .put = aureon_ac97_vol_put, | 1749 | .put = aureon_ac97_vol_put, |
1696 | .private_value = AC97_CD|AUREON_AC97_STEREO | 1750 | .private_value = AC97_CD|AUREON_AC97_STEREO, |
1751 | .tlv = { .p = db_scale_ac97_gain } | ||
1697 | }, | 1752 | }, |
1698 | { | 1753 | { |
1699 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1754 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1705,11 +1760,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1705 | }, | 1760 | }, |
1706 | { | 1761 | { |
1707 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1762 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1763 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1764 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1708 | .name = "Line Playback Volume", | 1765 | .name = "Line Playback Volume", |
1709 | .info = aureon_ac97_vol_info, | 1766 | .info = aureon_ac97_vol_info, |
1710 | .get = aureon_ac97_vol_get, | 1767 | .get = aureon_ac97_vol_get, |
1711 | .put = aureon_ac97_vol_put, | 1768 | .put = aureon_ac97_vol_put, |
1712 | .private_value = AC97_LINE|AUREON_AC97_STEREO | 1769 | .private_value = AC97_LINE|AUREON_AC97_STEREO, |
1770 | .tlv = { .p = db_scale_ac97_gain } | ||
1713 | }, | 1771 | }, |
1714 | { | 1772 | { |
1715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1773 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1721,11 +1779,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1721 | }, | 1779 | }, |
1722 | { | 1780 | { |
1723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1781 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1782 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1783 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1724 | .name = "Mic Playback Volume", | 1784 | .name = "Mic Playback Volume", |
1725 | .info = aureon_ac97_vol_info, | 1785 | .info = aureon_ac97_vol_info, |
1726 | .get = aureon_ac97_vol_get, | 1786 | .get = aureon_ac97_vol_get, |
1727 | .put = aureon_ac97_vol_put, | 1787 | .put = aureon_ac97_vol_put, |
1728 | .private_value = AC97_MIC | 1788 | .private_value = AC97_MIC, |
1789 | .tlv = { .p = db_scale_ac97_gain } | ||
1729 | }, | 1790 | }, |
1730 | { | 1791 | { |
1731 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1792 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1744,11 +1805,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1744 | }, | 1805 | }, |
1745 | { | 1806 | { |
1746 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1807 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1808 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1809 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1747 | .name = "Aux Playback Volume", | 1810 | .name = "Aux Playback Volume", |
1748 | .info = aureon_ac97_vol_info, | 1811 | .info = aureon_ac97_vol_info, |
1749 | .get = aureon_ac97_vol_get, | 1812 | .get = aureon_ac97_vol_get, |
1750 | .put = aureon_ac97_vol_put, | 1813 | .put = aureon_ac97_vol_put, |
1751 | .private_value = AC97_VIDEO|AUREON_AC97_STEREO | 1814 | .private_value = AC97_VIDEO|AUREON_AC97_STEREO, |
1815 | .tlv = { .p = db_scale_ac97_gain } | ||
1752 | }, | 1816 | }, |
1753 | { | 1817 | { |
1754 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1818 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index bf20858d9f19..dc69392eafa3 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <sound/cs8427.h> | 62 | #include <sound/cs8427.h> |
63 | #include <sound/info.h> | 63 | #include <sound/info.h> |
64 | #include <sound/initval.h> | 64 | #include <sound/initval.h> |
65 | #include <sound/tlv.h> | ||
65 | 66 | ||
66 | #include <sound/asoundef.h> | 67 | #include <sound/asoundef.h> |
67 | 68 | ||
@@ -1377,6 +1378,7 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc | |||
1377 | return change; | 1378 | return change; |
1378 | } | 1379 | } |
1379 | 1380 | ||
1381 | static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); | ||
1380 | 1382 | ||
1381 | static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { | 1383 | static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { |
1382 | { | 1384 | { |
@@ -1390,12 +1392,15 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata | |||
1390 | }, | 1392 | }, |
1391 | { | 1393 | { |
1392 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1394 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1395 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1396 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1393 | .name = "Multi Playback Volume", | 1397 | .name = "Multi Playback Volume", |
1394 | .info = snd_ice1712_pro_mixer_volume_info, | 1398 | .info = snd_ice1712_pro_mixer_volume_info, |
1395 | .get = snd_ice1712_pro_mixer_volume_get, | 1399 | .get = snd_ice1712_pro_mixer_volume_get, |
1396 | .put = snd_ice1712_pro_mixer_volume_put, | 1400 | .put = snd_ice1712_pro_mixer_volume_put, |
1397 | .private_value = 0, | 1401 | .private_value = 0, |
1398 | .count = 10, | 1402 | .count = 10, |
1403 | .tlv = { .p = db_scale_playback } | ||
1399 | }, | 1404 | }, |
1400 | }; | 1405 | }; |
1401 | 1406 | ||
@@ -1420,11 +1425,14 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd | |||
1420 | 1425 | ||
1421 | static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { | 1426 | static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { |
1422 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1427 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1428 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1429 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1423 | .name = "H/W Multi Capture Volume", | 1430 | .name = "H/W Multi Capture Volume", |
1424 | .info = snd_ice1712_pro_mixer_volume_info, | 1431 | .info = snd_ice1712_pro_mixer_volume_info, |
1425 | .get = snd_ice1712_pro_mixer_volume_get, | 1432 | .get = snd_ice1712_pro_mixer_volume_get, |
1426 | .put = snd_ice1712_pro_mixer_volume_put, | 1433 | .put = snd_ice1712_pro_mixer_volume_put, |
1427 | .private_value = 10, | 1434 | .private_value = 10, |
1435 | .tlv = { .p = db_scale_playback } | ||
1428 | }; | 1436 | }; |
1429 | 1437 | ||
1430 | static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { | 1438 | static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { |
@@ -1857,7 +1865,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
1857 | { | 1865 | { |
1858 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1866 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1859 | static unsigned int xrate[13] = { | 1867 | static unsigned int xrate[13] = { |
1860 | 8000, 9600, 11025, 12000, 1600, 22050, 24000, | 1868 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1861 | 32000, 44100, 48000, 64000, 88200, 96000 | 1869 | 32000, 44100, 48000, 64000, 88200, 96000 |
1862 | }; | 1870 | }; |
1863 | unsigned char oval; | 1871 | unsigned char oval; |
@@ -1924,7 +1932,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont | |||
1924 | { | 1932 | { |
1925 | int val; | 1933 | int val; |
1926 | static unsigned int xrate[13] = { | 1934 | static unsigned int xrate[13] = { |
1927 | 8000, 9600, 11025, 12000, 1600, 22050, 24000, | 1935 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1928 | 32000, 44100, 48000, 64000, 88200, 96000 | 1936 | 32000, 44100, 48000, 64000, 88200, 96000 |
1929 | }; | 1937 | }; |
1930 | 1938 | ||
@@ -1941,7 +1949,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont | |||
1941 | struct snd_ctl_elem_value *ucontrol) | 1949 | struct snd_ctl_elem_value *ucontrol) |
1942 | { | 1950 | { |
1943 | static unsigned int xrate[13] = { | 1951 | static unsigned int xrate[13] = { |
1944 | 8000, 9600, 11025, 12000, 1600, 22050, 24000, | 1952 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1945 | 32000, 44100, 48000, 64000, 88200, 96000 | 1953 | 32000, 44100, 48000, 64000, 88200, 96000 |
1946 | }; | 1954 | }; |
1947 | unsigned char oval; | 1955 | unsigned char oval; |
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 502da1c8b5f7..e08d73f4ff85 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include "ice1712.h" | 46 | #include "ice1712.h" |
47 | #include "envy24ht.h" | 47 | #include "envy24ht.h" |
48 | #include "phase.h" | 48 | #include "phase.h" |
49 | #include <sound/tlv.h> | ||
49 | 50 | ||
50 | /* WM8770 registers */ | 51 | /* WM8770 registers */ |
51 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | 52 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ |
@@ -696,6 +697,9 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ct | |||
696 | return 0; | 697 | return 0; |
697 | } | 698 | } |
698 | 699 | ||
700 | static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | ||
701 | static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); | ||
702 | |||
699 | static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | 703 | static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { |
700 | { | 704 | { |
701 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -706,10 +710,13 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
706 | }, | 710 | }, |
707 | { | 711 | { |
708 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 712 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
713 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
714 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
709 | .name = "Master Playback Volume", | 715 | .name = "Master Playback Volume", |
710 | .info = wm_master_vol_info, | 716 | .info = wm_master_vol_info, |
711 | .get = wm_master_vol_get, | 717 | .get = wm_master_vol_get, |
712 | .put = wm_master_vol_put | 718 | .put = wm_master_vol_put, |
719 | .tlv = { .p = db_scale_wm_dac } | ||
713 | }, | 720 | }, |
714 | { | 721 | { |
715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 722 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -721,11 +728,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
721 | }, | 728 | }, |
722 | { | 729 | { |
723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 730 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
731 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
732 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
724 | .name = "Front Playback Volume", | 733 | .name = "Front Playback Volume", |
725 | .info = wm_vol_info, | 734 | .info = wm_vol_info, |
726 | .get = wm_vol_get, | 735 | .get = wm_vol_get, |
727 | .put = wm_vol_put, | 736 | .put = wm_vol_put, |
728 | .private_value = (2 << 8) | 0 | 737 | .private_value = (2 << 8) | 0, |
738 | .tlv = { .p = db_scale_wm_dac } | ||
729 | }, | 739 | }, |
730 | { | 740 | { |
731 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 741 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -737,11 +747,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
737 | }, | 747 | }, |
738 | { | 748 | { |
739 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 749 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
750 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
751 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
740 | .name = "Rear Playback Volume", | 752 | .name = "Rear Playback Volume", |
741 | .info = wm_vol_info, | 753 | .info = wm_vol_info, |
742 | .get = wm_vol_get, | 754 | .get = wm_vol_get, |
743 | .put = wm_vol_put, | 755 | .put = wm_vol_put, |
744 | .private_value = (2 << 8) | 2 | 756 | .private_value = (2 << 8) | 2, |
757 | .tlv = { .p = db_scale_wm_dac } | ||
745 | }, | 758 | }, |
746 | { | 759 | { |
747 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 760 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -753,11 +766,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
753 | }, | 766 | }, |
754 | { | 767 | { |
755 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 768 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
769 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
770 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
756 | .name = "Center Playback Volume", | 771 | .name = "Center Playback Volume", |
757 | .info = wm_vol_info, | 772 | .info = wm_vol_info, |
758 | .get = wm_vol_get, | 773 | .get = wm_vol_get, |
759 | .put = wm_vol_put, | 774 | .put = wm_vol_put, |
760 | .private_value = (1 << 8) | 4 | 775 | .private_value = (1 << 8) | 4, |
776 | .tlv = { .p = db_scale_wm_dac } | ||
761 | }, | 777 | }, |
762 | { | 778 | { |
763 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 779 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -769,11 +785,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
769 | }, | 785 | }, |
770 | { | 786 | { |
771 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 787 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
788 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
789 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
772 | .name = "LFE Playback Volume", | 790 | .name = "LFE Playback Volume", |
773 | .info = wm_vol_info, | 791 | .info = wm_vol_info, |
774 | .get = wm_vol_get, | 792 | .get = wm_vol_get, |
775 | .put = wm_vol_put, | 793 | .put = wm_vol_put, |
776 | .private_value = (1 << 8) | 5 | 794 | .private_value = (1 << 8) | 5, |
795 | .tlv = { .p = db_scale_wm_dac } | ||
777 | }, | 796 | }, |
778 | { | 797 | { |
779 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 798 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -785,11 +804,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
785 | }, | 804 | }, |
786 | { | 805 | { |
787 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 806 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
807 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
808 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
788 | .name = "Side Playback Volume", | 809 | .name = "Side Playback Volume", |
789 | .info = wm_vol_info, | 810 | .info = wm_vol_info, |
790 | .get = wm_vol_get, | 811 | .get = wm_vol_get, |
791 | .put = wm_vol_put, | 812 | .put = wm_vol_put, |
792 | .private_value = (2 << 8) | 6 | 813 | .private_value = (2 << 8) | 6, |
814 | .tlv = { .p = db_scale_wm_dac } | ||
793 | } | 815 | } |
794 | }; | 816 | }; |
795 | 817 | ||
@@ -803,10 +825,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { | |||
803 | }, | 825 | }, |
804 | { | 826 | { |
805 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 827 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
828 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
829 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
806 | .name = "PCM Playback Volume", | 830 | .name = "PCM Playback Volume", |
807 | .info = wm_pcm_vol_info, | 831 | .info = wm_pcm_vol_info, |
808 | .get = wm_pcm_vol_get, | 832 | .get = wm_pcm_vol_get, |
809 | .put = wm_pcm_vol_put | 833 | .put = wm_pcm_vol_put, |
834 | .tlv = { .p = db_scale_wm_pcm } | ||
810 | }, | 835 | }, |
811 | { | 836 | { |
812 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 837 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 0efcad9260a5..6c74c2d2e7f3 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/info.h> | 33 | #include <sound/info.h> |
34 | #include <sound/tlv.h> | ||
34 | 35 | ||
35 | #include "ice1712.h" | 36 | #include "ice1712.h" |
36 | #include "envy24ht.h" | 37 | #include "envy24ht.h" |
@@ -564,6 +565,8 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
564 | return changed; | 565 | return changed; |
565 | } | 566 | } |
566 | 567 | ||
568 | static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); | ||
569 | |||
567 | /* | 570 | /* |
568 | * mixers | 571 | * mixers |
569 | */ | 572 | */ |
@@ -571,17 +574,23 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
571 | static struct snd_kcontrol_new pontis_controls[] __devinitdata = { | 574 | static struct snd_kcontrol_new pontis_controls[] __devinitdata = { |
572 | { | 575 | { |
573 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 576 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
577 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
578 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
574 | .name = "PCM Playback Volume", | 579 | .name = "PCM Playback Volume", |
575 | .info = wm_dac_vol_info, | 580 | .info = wm_dac_vol_info, |
576 | .get = wm_dac_vol_get, | 581 | .get = wm_dac_vol_get, |
577 | .put = wm_dac_vol_put, | 582 | .put = wm_dac_vol_put, |
583 | .tlv = { .p = db_scale_volume }, | ||
578 | }, | 584 | }, |
579 | { | 585 | { |
580 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 586 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
587 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
588 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
581 | .name = "Capture Volume", | 589 | .name = "Capture Volume", |
582 | .info = wm_adc_vol_info, | 590 | .info = wm_adc_vol_info, |
583 | .get = wm_adc_vol_get, | 591 | .get = wm_adc_vol_get, |
584 | .put = wm_adc_vol_put, | 592 | .put = wm_adc_vol_put, |
593 | .tlv = { .p = db_scale_volume }, | ||
585 | }, | 594 | }, |
586 | { | 595 | { |
587 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 596 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index fdb5cb8fac97..41b2605daa3a 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "envy24ht.h" | 35 | #include "envy24ht.h" |
36 | #include "prodigy192.h" | 36 | #include "prodigy192.h" |
37 | #include "stac946x.h" | 37 | #include "stac946x.h" |
38 | #include <sound/tlv.h> | ||
38 | 39 | ||
39 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) | 40 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) |
40 | { | 41 | { |
@@ -356,6 +357,9 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
356 | } | 357 | } |
357 | #endif | 358 | #endif |
358 | 359 | ||
360 | static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); | ||
361 | static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | ||
362 | |||
359 | /* | 363 | /* |
360 | * mixers | 364 | * mixers |
361 | */ | 365 | */ |
@@ -368,14 +372,18 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
368 | .get = stac9460_dac_mute_get, | 372 | .get = stac9460_dac_mute_get, |
369 | .put = stac9460_dac_mute_put, | 373 | .put = stac9460_dac_mute_put, |
370 | .private_value = 1, | 374 | .private_value = 1, |
375 | .tlv = { .p = db_scale_dac } | ||
371 | }, | 376 | }, |
372 | { | 377 | { |
373 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 378 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
379 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
380 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
374 | .name = "Master Playback Volume", | 381 | .name = "Master Playback Volume", |
375 | .info = stac9460_dac_vol_info, | 382 | .info = stac9460_dac_vol_info, |
376 | .get = stac9460_dac_vol_get, | 383 | .get = stac9460_dac_vol_get, |
377 | .put = stac9460_dac_vol_put, | 384 | .put = stac9460_dac_vol_put, |
378 | .private_value = 1, | 385 | .private_value = 1, |
386 | .tlv = { .p = db_scale_dac } | ||
379 | }, | 387 | }, |
380 | { | 388 | { |
381 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 389 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -387,11 +395,14 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
387 | }, | 395 | }, |
388 | { | 396 | { |
389 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 397 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
398 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
399 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
390 | .name = "DAC Volume", | 400 | .name = "DAC Volume", |
391 | .count = 6, | 401 | .count = 6, |
392 | .info = stac9460_dac_vol_info, | 402 | .info = stac9460_dac_vol_info, |
393 | .get = stac9460_dac_vol_get, | 403 | .get = stac9460_dac_vol_get, |
394 | .put = stac9460_dac_vol_put, | 404 | .put = stac9460_dac_vol_put, |
405 | .tlv = { .p = db_scale_dac } | ||
395 | }, | 406 | }, |
396 | { | 407 | { |
397 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 408 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -404,11 +415,14 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
404 | }, | 415 | }, |
405 | { | 416 | { |
406 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 417 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
418 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
419 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
407 | .name = "ADC Volume", | 420 | .name = "ADC Volume", |
408 | .count = 1, | 421 | .count = 1, |
409 | .info = stac9460_adc_vol_info, | 422 | .info = stac9460_adc_vol_info, |
410 | .get = stac9460_adc_vol_get, | 423 | .get = stac9460_adc_vol_get, |
411 | .put = stac9460_adc_vol_put, | 424 | .put = stac9460_adc_vol_put, |
425 | .tlv = { .p = db_scale_adc } | ||
412 | }, | 426 | }, |
413 | #if 0 | 427 | #if 0 |
414 | { | 428 | { |
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index fec9440cb310..bf98ea34feb0 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c | |||
@@ -87,16 +87,33 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | |||
87 | * initialize the chips on M-Audio Revolution cards | 87 | * initialize the chips on M-Audio Revolution cards |
88 | */ | 88 | */ |
89 | 89 | ||
90 | static unsigned int revo71_num_stereo_front[] = {2}; | 90 | #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch } |
91 | static char *revo71_channel_names_front[] = {"PCM Playback Volume"}; | ||
92 | 91 | ||
93 | static unsigned int revo71_num_stereo_surround[] = {1, 1, 2, 2}; | 92 | static struct snd_akm4xxx_dac_channel revo71_front[] = { |
94 | static char *revo71_channel_names_surround[] = {"PCM Center Playback Volume", "PCM LFE Playback Volume", | 93 | AK_DAC("PCM Playback Volume", 2) |
95 | "PCM Side Playback Volume", "PCM Rear Playback Volume"}; | 94 | }; |
95 | |||
96 | static struct snd_akm4xxx_dac_channel revo71_surround[] = { | ||
97 | AK_DAC("PCM Center Playback Volume", 1), | ||
98 | AK_DAC("PCM LFE Playback Volume", 1), | ||
99 | AK_DAC("PCM Side Playback Volume", 2), | ||
100 | AK_DAC("PCM Rear Playback Volume", 2), | ||
101 | }; | ||
96 | 102 | ||
97 | static unsigned int revo51_num_stereo[] = {2, 1, 1, 2}; | 103 | static struct snd_akm4xxx_dac_channel revo51_dac[] = { |
98 | static char *revo51_channel_names[] = {"PCM Playback Volume", "PCM Center Playback Volume", | 104 | AK_DAC("PCM Playback Volume", 2), |
99 | "PCM LFE Playback Volume", "PCM Rear Playback Volume"}; | 105 | AK_DAC("PCM Center Playback Volume", 1), |
106 | AK_DAC("PCM LFE Playback Volume", 1), | ||
107 | AK_DAC("PCM Rear Playback Volume", 2), | ||
108 | }; | ||
109 | |||
110 | static struct snd_akm4xxx_adc_channel revo51_adc[] = { | ||
111 | { | ||
112 | .name = "PCM Capture Volume", | ||
113 | .switch_name = "PCM Capture Switch", | ||
114 | .num_channels = 2 | ||
115 | }, | ||
116 | }; | ||
100 | 117 | ||
101 | static struct snd_akm4xxx akm_revo_front __devinitdata = { | 118 | static struct snd_akm4xxx akm_revo_front __devinitdata = { |
102 | .type = SND_AK4381, | 119 | .type = SND_AK4381, |
@@ -104,8 +121,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = { | |||
104 | .ops = { | 121 | .ops = { |
105 | .set_rate_val = revo_set_rate_val | 122 | .set_rate_val = revo_set_rate_val |
106 | }, | 123 | }, |
107 | .num_stereo = revo71_num_stereo_front, | 124 | .dac_info = revo71_front, |
108 | .channel_names = revo71_channel_names_front | ||
109 | }; | 125 | }; |
110 | 126 | ||
111 | static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { | 127 | static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { |
@@ -127,8 +143,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = { | |||
127 | .ops = { | 143 | .ops = { |
128 | .set_rate_val = revo_set_rate_val | 144 | .set_rate_val = revo_set_rate_val |
129 | }, | 145 | }, |
130 | .num_stereo = revo71_num_stereo_surround, | 146 | .dac_info = revo71_surround, |
131 | .channel_names = revo71_channel_names_surround | ||
132 | }; | 147 | }; |
133 | 148 | ||
134 | static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { | 149 | static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { |
@@ -149,8 +164,7 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = { | |||
149 | .ops = { | 164 | .ops = { |
150 | .set_rate_val = revo_set_rate_val | 165 | .set_rate_val = revo_set_rate_val |
151 | }, | 166 | }, |
152 | .num_stereo = revo51_num_stereo, | 167 | .dac_info = revo51_dac, |
153 | .channel_names = revo51_channel_names | ||
154 | }; | 168 | }; |
155 | 169 | ||
156 | static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { | 170 | static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { |
@@ -159,7 +173,25 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { | |||
159 | .data_mask = VT1724_REVO_CDOUT, | 173 | .data_mask = VT1724_REVO_CDOUT, |
160 | .clk_mask = VT1724_REVO_CCLK, | 174 | .clk_mask = VT1724_REVO_CCLK, |
161 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | 175 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, |
162 | .cs_addr = 0, | 176 | .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2, |
177 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | ||
178 | .add_flags = VT1724_REVO_CCLK, /* high at init */ | ||
179 | .mask_flags = 0, | ||
180 | }; | ||
181 | |||
182 | static struct snd_akm4xxx akm_revo51_adc __devinitdata = { | ||
183 | .type = SND_AK5365, | ||
184 | .num_adcs = 2, | ||
185 | .adc_info = revo51_adc, | ||
186 | }; | ||
187 | |||
188 | static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { | ||
189 | .caddr = 2, | ||
190 | .cif = 0, | ||
191 | .data_mask = VT1724_REVO_CDOUT, | ||
192 | .clk_mask = VT1724_REVO_CCLK, | ||
193 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | ||
194 | .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2, | ||
163 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | 195 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, |
164 | .add_flags = VT1724_REVO_CCLK, /* high at init */ | 196 | .add_flags = VT1724_REVO_CCLK, /* high at init */ |
165 | .mask_flags = 0, | 197 | .mask_flags = 0, |
@@ -202,9 +234,13 @@ static int __devinit revo_init(struct snd_ice1712 *ice) | |||
202 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); | 234 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); |
203 | break; | 235 | break; |
204 | case VT1724_SUBDEVICE_REVOLUTION51: | 236 | case VT1724_SUBDEVICE_REVOLUTION51: |
205 | ice->akm_codecs = 1; | 237 | ice->akm_codecs = 2; |
206 | if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0) | 238 | if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0) |
207 | return err; | 239 | return err; |
240 | err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc, | ||
241 | &akm_revo51_adc_priv, ice); | ||
242 | if (err < 0) | ||
243 | return err; | ||
208 | /* unmute all codecs - needed! */ | 244 | /* unmute all codecs - needed! */ |
209 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); | 245 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); |
210 | break; | 246 | break; |
diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h index dea52ea219df..efbb86ec3289 100644 --- a/sound/pci/ice1712/revo.h +++ b/sound/pci/ice1712/revo.h | |||
@@ -42,7 +42,7 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[]; | |||
42 | #define VT1724_REVO_CCLK 0x02 | 42 | #define VT1724_REVO_CCLK 0x02 |
43 | #define VT1724_REVO_CDIN 0x04 /* not used */ | 43 | #define VT1724_REVO_CDIN 0x04 /* not used */ |
44 | #define VT1724_REVO_CDOUT 0x08 | 44 | #define VT1724_REVO_CDOUT 0x08 |
45 | #define VT1724_REVO_CS0 0x10 /* not used */ | 45 | #define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */ |
46 | #define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */ | 46 | #define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */ |
47 | #define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */ | 47 | #define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */ |
48 | #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */ | 48 | #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */ |
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6874263f1681..72dbaedcbdf5 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -2251,6 +2251,16 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | |||
2251 | /* ACLink on, 2 channels */ | 2251 | /* ACLink on, 2 channels */ |
2252 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); | 2252 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); |
2253 | cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); | 2253 | cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); |
2254 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2255 | /* do cold reset - the full ac97 powerdown may leave the controller | ||
2256 | * in a warm state but actually it cannot communicate with the codec. | ||
2257 | */ | ||
2258 | iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_AC97COLD); | ||
2259 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); | ||
2260 | udelay(10); | ||
2261 | iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD); | ||
2262 | msleep(1); | ||
2263 | #else | ||
2254 | /* finish cold or do warm reset */ | 2264 | /* finish cold or do warm reset */ |
2255 | cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; | 2265 | cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; |
2256 | iputdword(chip, ICHREG(GLOB_CNT), cnt); | 2266 | iputdword(chip, ICHREG(GLOB_CNT), cnt); |
@@ -2265,6 +2275,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | |||
2265 | return -EIO; | 2275 | return -EIO; |
2266 | 2276 | ||
2267 | __ok: | 2277 | __ok: |
2278 | #endif | ||
2268 | if (probing) { | 2279 | if (probing) { |
2269 | /* wait for any codec ready status. | 2280 | /* wait for any codec ready status. |
2270 | * Once it becomes ready it should remain ready | 2281 | * Once it becomes ready it should remain ready |
@@ -2485,7 +2496,7 @@ static int intel8x0_resume(struct pci_dev *pci) | |||
2485 | card->shortname, chip); | 2496 | card->shortname, chip); |
2486 | chip->irq = pci->irq; | 2497 | chip->irq = pci->irq; |
2487 | synchronize_irq(chip->irq); | 2498 | synchronize_irq(chip->irq); |
2488 | snd_intel8x0_chip_init(chip, 1); | 2499 | snd_intel8x0_chip_init(chip, 0); |
2489 | 2500 | ||
2490 | /* re-initialize mixer stuff */ | 2501 | /* re-initialize mixer stuff */ |
2491 | if (chip->device_type == DEVICE_INTEL_ICH4) { | 2502 | if (chip->device_type == DEVICE_INTEL_ICH4) { |
@@ -2615,6 +2626,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) | |||
2615 | /* not 48000Hz, tuning the clock.. */ | 2626 | /* not 48000Hz, tuning the clock.. */ |
2616 | chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; | 2627 | chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; |
2617 | printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); | 2628 | printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); |
2629 | snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0); | ||
2618 | } | 2630 | } |
2619 | 2631 | ||
2620 | #ifdef CONFIG_PROC_FS | 2632 | #ifdef CONFIG_PROC_FS |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 91850281f89b..268e2f7241ea 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
@@ -1045,6 +1045,8 @@ static int intel8x0m_suspend(struct pci_dev *pci, pm_message_t state) | |||
1045 | for (i = 0; i < chip->pcm_devs; i++) | 1045 | for (i = 0; i < chip->pcm_devs; i++) |
1046 | snd_pcm_suspend_all(chip->pcm[i]); | 1046 | snd_pcm_suspend_all(chip->pcm[i]); |
1047 | snd_ac97_suspend(chip->ac97); | 1047 | snd_ac97_suspend(chip->ac97); |
1048 | if (chip->irq >= 0) | ||
1049 | free_irq(chip->irq, chip); | ||
1048 | pci_disable_device(pci); | 1050 | pci_disable_device(pci); |
1049 | pci_save_state(pci); | 1051 | pci_save_state(pci); |
1050 | return 0; | 1052 | return 0; |
@@ -1058,6 +1060,9 @@ static int intel8x0m_resume(struct pci_dev *pci) | |||
1058 | pci_restore_state(pci); | 1060 | pci_restore_state(pci); |
1059 | pci_enable_device(pci); | 1061 | pci_enable_device(pci); |
1060 | pci_set_master(pci); | 1062 | pci_set_master(pci); |
1063 | request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_DISABLED|IRQF_SHARED, | ||
1064 | card->shortname, chip); | ||
1065 | chip->irq = pci->irq; | ||
1061 | snd_intel8x0_chip_init(chip, 0); | 1066 | snd_intel8x0_chip_init(chip, 0); |
1062 | snd_ac97_resume(chip->ac97); | 1067 | snd_ac97_resume(chip->ac97); |
1063 | 1068 | ||
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index cc43ecd67906..216aee5f93e7 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
@@ -1109,13 +1109,13 @@ static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry, | |||
1109 | offset = offset & ~3; /* 4 bytes aligned */ | 1109 | offset = offset & ~3; /* 4 bytes aligned */ |
1110 | 1110 | ||
1111 | switch(orig) { | 1111 | switch(orig) { |
1112 | case 0: /* SEEK_SET */ | 1112 | case SEEK_SET: |
1113 | file->f_pos = offset; | 1113 | file->f_pos = offset; |
1114 | break; | 1114 | break; |
1115 | case 1: /* SEEK_CUR */ | 1115 | case SEEK_CUR: |
1116 | file->f_pos += offset; | 1116 | file->f_pos += offset; |
1117 | break; | 1117 | break; |
1118 | case 2: /* SEEK_END, offset is negative */ | 1118 | case SEEK_END: /* offset is negative */ |
1119 | file->f_pos = MIXART_BA0_SIZE + offset; | 1119 | file->f_pos = MIXART_BA0_SIZE + offset; |
1120 | break; | 1120 | break; |
1121 | default: | 1121 | default: |
@@ -1135,13 +1135,13 @@ static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry, | |||
1135 | offset = offset & ~3; /* 4 bytes aligned */ | 1135 | offset = offset & ~3; /* 4 bytes aligned */ |
1136 | 1136 | ||
1137 | switch(orig) { | 1137 | switch(orig) { |
1138 | case 0: /* SEEK_SET */ | 1138 | case SEEK_SET: |
1139 | file->f_pos = offset; | 1139 | file->f_pos = offset; |
1140 | break; | 1140 | break; |
1141 | case 1: /* SEEK_CUR */ | 1141 | case SEEK_CUR: |
1142 | file->f_pos += offset; | 1142 | file->f_pos += offset; |
1143 | break; | 1143 | break; |
1144 | case 2: /* SEEK_END, offset is negative */ | 1144 | case SEEK_END: /* offset is negative */ |
1145 | file->f_pos = MIXART_BA1_SIZE + offset; | 1145 | file->f_pos = MIXART_BA1_SIZE + offset; |
1146 | break; | 1146 | break; |
1147 | default: | 1147 | default: |
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index ed47b732c103..13de0f71d4b7 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "mixart_core.h" | 31 | #include "mixart_core.h" |
32 | #include "mixart_hwdep.h" | 32 | #include "mixart_hwdep.h" |
33 | #include <sound/control.h> | 33 | #include <sound/control.h> |
34 | #include <sound/tlv.h> | ||
34 | #include "mixart_mixer.h" | 35 | #include "mixart_mixer.h" |
35 | 36 | ||
36 | static u32 mixart_analog_level[256] = { | 37 | static u32 mixart_analog_level[256] = { |
@@ -388,12 +389,17 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
388 | return changed; | 389 | return changed; |
389 | } | 390 | } |
390 | 391 | ||
392 | static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0); | ||
393 | |||
391 | static struct snd_kcontrol_new mixart_control_analog_level = { | 394 | static struct snd_kcontrol_new mixart_control_analog_level = { |
392 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 395 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
396 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
397 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
393 | /* name will be filled later */ | 398 | /* name will be filled later */ |
394 | .info = mixart_analog_vol_info, | 399 | .info = mixart_analog_vol_info, |
395 | .get = mixart_analog_vol_get, | 400 | .get = mixart_analog_vol_get, |
396 | .put = mixart_analog_vol_put, | 401 | .put = mixart_analog_vol_put, |
402 | .tlv = { .p = db_scale_analog }, | ||
397 | }; | 403 | }; |
398 | 404 | ||
399 | /* shared */ | 405 | /* shared */ |
@@ -866,14 +872,19 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
866 | return changed; | 872 | return changed; |
867 | } | 873 | } |
868 | 874 | ||
875 | static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); | ||
876 | |||
869 | static struct snd_kcontrol_new snd_mixart_pcm_vol = | 877 | static struct snd_kcontrol_new snd_mixart_pcm_vol = |
870 | { | 878 | { |
871 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 879 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
880 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
881 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
872 | /* name will be filled later */ | 882 | /* name will be filled later */ |
873 | /* count will be filled later */ | 883 | /* count will be filled later */ |
874 | .info = mixart_digital_vol_info, /* shared */ | 884 | .info = mixart_digital_vol_info, /* shared */ |
875 | .get = mixart_pcm_vol_get, | 885 | .get = mixart_pcm_vol_get, |
876 | .put = mixart_pcm_vol_put, | 886 | .put = mixart_pcm_vol_put, |
887 | .tlv = { .p = db_scale_digital }, | ||
877 | }; | 888 | }; |
878 | 889 | ||
879 | 890 | ||
@@ -984,10 +995,13 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
984 | 995 | ||
985 | static struct snd_kcontrol_new mixart_control_monitor_vol = { | 996 | static struct snd_kcontrol_new mixart_control_monitor_vol = { |
986 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 997 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
998 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
999 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
987 | .name = "Monitoring Volume", | 1000 | .name = "Monitoring Volume", |
988 | .info = mixart_digital_vol_info, /* shared */ | 1001 | .info = mixart_digital_vol_info, /* shared */ |
989 | .get = mixart_monitor_vol_get, | 1002 | .get = mixart_monitor_vol_get, |
990 | .put = mixart_monitor_vol_put, | 1003 | .put = mixart_monitor_vol_put, |
1004 | .tlv = { .p = db_scale_digital }, | ||
991 | }; | 1005 | }; |
992 | 1006 | ||
993 | /* | 1007 | /* |
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index 94e63a1e90d9..b133ad9e095e 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "pcxhr_hwdep.h" | 31 | #include "pcxhr_hwdep.h" |
32 | #include "pcxhr_core.h" | 32 | #include "pcxhr_core.h" |
33 | #include <sound/control.h> | 33 | #include <sound/control.h> |
34 | #include <sound/tlv.h> | ||
34 | #include <sound/asoundef.h> | 35 | #include <sound/asoundef.h> |
35 | #include "pcxhr_mixer.h" | 36 | #include "pcxhr_mixer.h" |
36 | 37 | ||
@@ -43,6 +44,9 @@ | |||
43 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ | 44 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ |
44 | #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ | 45 | #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ |
45 | 46 | ||
47 | static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0); | ||
48 | static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0); | ||
49 | |||
46 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) | 50 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) |
47 | { | 51 | { |
48 | int err, vol; | 52 | int err, vol; |
@@ -130,10 +134,13 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, | |||
130 | 134 | ||
131 | static struct snd_kcontrol_new pcxhr_control_analog_level = { | 135 | static struct snd_kcontrol_new pcxhr_control_analog_level = { |
132 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 136 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
137 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
138 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
133 | /* name will be filled later */ | 139 | /* name will be filled later */ |
134 | .info = pcxhr_analog_vol_info, | 140 | .info = pcxhr_analog_vol_info, |
135 | .get = pcxhr_analog_vol_get, | 141 | .get = pcxhr_analog_vol_get, |
136 | .put = pcxhr_analog_vol_put, | 142 | .put = pcxhr_analog_vol_put, |
143 | /* tlv will be filled later */ | ||
137 | }; | 144 | }; |
138 | 145 | ||
139 | /* shared */ | 146 | /* shared */ |
@@ -188,6 +195,7 @@ static struct snd_kcontrol_new pcxhr_control_output_switch = { | |||
188 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ | 195 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ |
189 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ | 196 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ |
190 | 197 | ||
198 | static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); | ||
191 | 199 | ||
192 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 | 200 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 |
193 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 | 201 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 |
@@ -343,11 +351,14 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
343 | static struct snd_kcontrol_new snd_pcxhr_pcm_vol = | 351 | static struct snd_kcontrol_new snd_pcxhr_pcm_vol = |
344 | { | 352 | { |
345 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 353 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
354 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
355 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
346 | /* name will be filled later */ | 356 | /* name will be filled later */ |
347 | /* count will be filled later */ | 357 | /* count will be filled later */ |
348 | .info = pcxhr_digital_vol_info, /* shared */ | 358 | .info = pcxhr_digital_vol_info, /* shared */ |
349 | .get = pcxhr_pcm_vol_get, | 359 | .get = pcxhr_pcm_vol_get, |
350 | .put = pcxhr_pcm_vol_put, | 360 | .put = pcxhr_pcm_vol_put, |
361 | .tlv = { .p = db_scale_digital }, | ||
351 | }; | 362 | }; |
352 | 363 | ||
353 | 364 | ||
@@ -433,10 +444,13 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, | |||
433 | 444 | ||
434 | static struct snd_kcontrol_new pcxhr_control_monitor_vol = { | 445 | static struct snd_kcontrol_new pcxhr_control_monitor_vol = { |
435 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 446 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
447 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
448 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
436 | .name = "Monitoring Volume", | 449 | .name = "Monitoring Volume", |
437 | .info = pcxhr_digital_vol_info, /* shared */ | 450 | .info = pcxhr_digital_vol_info, /* shared */ |
438 | .get = pcxhr_monitor_vol_get, | 451 | .get = pcxhr_monitor_vol_get, |
439 | .put = pcxhr_monitor_vol_put, | 452 | .put = pcxhr_monitor_vol_put, |
453 | .tlv = { .p = db_scale_digital }, | ||
440 | }; | 454 | }; |
441 | 455 | ||
442 | /* | 456 | /* |
@@ -928,6 +942,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) | |||
928 | temp = pcxhr_control_analog_level; | 942 | temp = pcxhr_control_analog_level; |
929 | temp.name = "Master Playback Volume"; | 943 | temp.name = "Master Playback Volume"; |
930 | temp.private_value = 0; /* playback */ | 944 | temp.private_value = 0; /* playback */ |
945 | temp.tlv.p = db_scale_analog_playback; | ||
931 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | 946 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) |
932 | return err; | 947 | return err; |
933 | /* output mute controls */ | 948 | /* output mute controls */ |
@@ -963,6 +978,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) | |||
963 | temp = pcxhr_control_analog_level; | 978 | temp = pcxhr_control_analog_level; |
964 | temp.name = "Master Capture Volume"; | 979 | temp.name = "Master Capture Volume"; |
965 | temp.private_value = 1; /* capture */ | 980 | temp.private_value = 1; /* capture */ |
981 | temp.tlv.p = db_scale_analog_capture; | ||
966 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | 982 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) |
967 | return err; | 983 | return err; |
968 | 984 | ||
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index f435fcd6dca9..fe210c853442 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
@@ -673,9 +673,13 @@ static struct lbuspath lbus_rec_path = { | |||
673 | #define FIRMWARE_VERSIONS 1 | 673 | #define FIRMWARE_VERSIONS 1 |
674 | static union firmware_version firmware_versions[] = { | 674 | static union firmware_version firmware_versions[] = { |
675 | { | 675 | { |
676 | .firmware.ASIC = 3,.firmware.CODEC = 2, | 676 | .firmware = { |
677 | .firmware.AUXDSP = 3,.firmware.PROG = 773, | 677 | .ASIC = 3, |
678 | }, | 678 | .CODEC = 2, |
679 | .AUXDSP = 3, | ||
680 | .PROG = 773, | ||
681 | }, | ||
682 | }, | ||
679 | }; | 683 | }; |
680 | 684 | ||
681 | static u32 atoh(unsigned char *in, unsigned int len) | 685 | static u32 atoh(unsigned char *in, unsigned int len) |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index e5a52da77b85..d3e07de433b0 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -726,22 +726,36 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp) | |||
726 | } | 726 | } |
727 | 727 | ||
728 | 728 | ||
729 | static int hdsp_check_for_firmware (struct hdsp *hdsp, int show_err) | 729 | #ifdef HDSP_FW_LOADER |
730 | static int __devinit hdsp_request_fw_loader(struct hdsp *hdsp); | ||
731 | #endif | ||
732 | |||
733 | static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand) | ||
730 | { | 734 | { |
731 | if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; | 735 | if (hdsp->io_type == H9652 || hdsp->io_type == H9632) |
736 | return 0; | ||
732 | if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { | 737 | if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { |
733 | snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n"); | ||
734 | hdsp->state &= ~HDSP_FirmwareLoaded; | 738 | hdsp->state &= ~HDSP_FirmwareLoaded; |
735 | if (! show_err) | 739 | if (! load_on_demand) |
736 | return -EIO; | 740 | return -EIO; |
741 | snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n"); | ||
737 | /* try to load firmware */ | 742 | /* try to load firmware */ |
738 | if (hdsp->state & HDSP_FirmwareCached) { | 743 | if (! (hdsp->state & HDSP_FirmwareCached)) { |
739 | if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) | 744 | #ifdef HDSP_FW_LOADER |
740 | snd_printk(KERN_ERR "Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n"); | 745 | if (! hdsp_request_fw_loader(hdsp)) |
741 | } else { | 746 | return 0; |
742 | snd_printk(KERN_ERR "Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n"); | 747 | #endif |
748 | snd_printk(KERN_ERR | ||
749 | "Hammerfall-DSP: No firmware loaded nor " | ||
750 | "cached, please upload firmware.\n"); | ||
751 | return -EIO; | ||
752 | } | ||
753 | if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { | ||
754 | snd_printk(KERN_ERR | ||
755 | "Hammerfall-DSP: Firmware loading from " | ||
756 | "cache failed, please upload manually.\n"); | ||
757 | return -EIO; | ||
743 | } | 758 | } |
744 | return -EIO; | ||
745 | } | 759 | } |
746 | return 0; | 760 | return 0; |
747 | } | 761 | } |
@@ -3181,8 +3195,16 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | |||
3181 | return; | 3195 | return; |
3182 | } | 3196 | } |
3183 | } else { | 3197 | } else { |
3184 | snd_iprintf(buffer, "No firmware loaded nor cached, please upload firmware.\n"); | 3198 | int err = -EINVAL; |
3185 | return; | 3199 | #ifdef HDSP_FW_LOADER |
3200 | err = hdsp_request_fw_loader(hdsp); | ||
3201 | #endif | ||
3202 | if (err < 0) { | ||
3203 | snd_iprintf(buffer, | ||
3204 | "No firmware loaded nor cached, " | ||
3205 | "please upload firmware.\n"); | ||
3206 | return; | ||
3207 | } | ||
3186 | } | 3208 | } |
3187 | } | 3209 | } |
3188 | 3210 | ||
@@ -3851,7 +3873,7 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd) | |||
3851 | if (hdsp_check_for_iobox (hdsp)) | 3873 | if (hdsp_check_for_iobox (hdsp)) |
3852 | return -EIO; | 3874 | return -EIO; |
3853 | 3875 | ||
3854 | if (hdsp_check_for_firmware(hdsp, 1)) | 3876 | if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */ |
3855 | return -EIO; | 3877 | return -EIO; |
3856 | 3878 | ||
3857 | spin_lock(&hdsp->lock); | 3879 | spin_lock(&hdsp->lock); |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 4930cc6b054d..ebbe12d78d8c 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <sound/core.h> | 40 | #include <sound/core.h> |
41 | #include <sound/info.h> | 41 | #include <sound/info.h> |
42 | #include <sound/control.h> | 42 | #include <sound/control.h> |
43 | #include <sound/tlv.h> | ||
43 | #include <sound/trident.h> | 44 | #include <sound/trident.h> |
44 | #include <sound/asoundef.h> | 45 | #include <sound/asoundef.h> |
45 | 46 | ||
@@ -2627,6 +2628,8 @@ static int snd_trident_vol_control_get(struct snd_kcontrol *kcontrol, | |||
2627 | return 0; | 2628 | return 0; |
2628 | } | 2629 | } |
2629 | 2630 | ||
2631 | static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0); | ||
2632 | |||
2630 | static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, | 2633 | static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, |
2631 | struct snd_ctl_elem_value *ucontrol) | 2634 | struct snd_ctl_elem_value *ucontrol) |
2632 | { | 2635 | { |
@@ -2653,6 +2656,7 @@ static struct snd_kcontrol_new snd_trident_vol_music_control __devinitdata = | |||
2653 | .get = snd_trident_vol_control_get, | 2656 | .get = snd_trident_vol_control_get, |
2654 | .put = snd_trident_vol_control_put, | 2657 | .put = snd_trident_vol_control_put, |
2655 | .private_value = 16, | 2658 | .private_value = 16, |
2659 | .tlv = { .p = db_scale_gvol }, | ||
2656 | }; | 2660 | }; |
2657 | 2661 | ||
2658 | static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata = | 2662 | static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata = |
@@ -2663,6 +2667,7 @@ static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata = | |||
2663 | .get = snd_trident_vol_control_get, | 2667 | .get = snd_trident_vol_control_get, |
2664 | .put = snd_trident_vol_control_put, | 2668 | .put = snd_trident_vol_control_put, |
2665 | .private_value = 0, | 2669 | .private_value = 0, |
2670 | .tlv = { .p = db_scale_gvol }, | ||
2666 | }; | 2671 | }; |
2667 | 2672 | ||
2668 | /*--------------------------------------------------------------------------- | 2673 | /*--------------------------------------------------------------------------- |
@@ -2730,6 +2735,7 @@ static struct snd_kcontrol_new snd_trident_pcm_vol_control __devinitdata = | |||
2730 | .info = snd_trident_pcm_vol_control_info, | 2735 | .info = snd_trident_pcm_vol_control_info, |
2731 | .get = snd_trident_pcm_vol_control_get, | 2736 | .get = snd_trident_pcm_vol_control_get, |
2732 | .put = snd_trident_pcm_vol_control_put, | 2737 | .put = snd_trident_pcm_vol_control_put, |
2738 | /* FIXME: no tlv yet */ | ||
2733 | }; | 2739 | }; |
2734 | 2740 | ||
2735 | /*--------------------------------------------------------------------------- | 2741 | /*--------------------------------------------------------------------------- |
@@ -2839,6 +2845,8 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol, | |||
2839 | return change; | 2845 | return change; |
2840 | } | 2846 | } |
2841 | 2847 | ||
2848 | static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); | ||
2849 | |||
2842 | static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = | 2850 | static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = |
2843 | { | 2851 | { |
2844 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2852 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -2848,6 +2856,7 @@ static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = | |||
2848 | .info = snd_trident_pcm_rvol_control_info, | 2856 | .info = snd_trident_pcm_rvol_control_info, |
2849 | .get = snd_trident_pcm_rvol_control_get, | 2857 | .get = snd_trident_pcm_rvol_control_get, |
2850 | .put = snd_trident_pcm_rvol_control_put, | 2858 | .put = snd_trident_pcm_rvol_control_put, |
2859 | .tlv = { .p = db_scale_crvol }, | ||
2851 | }; | 2860 | }; |
2852 | 2861 | ||
2853 | /*--------------------------------------------------------------------------- | 2862 | /*--------------------------------------------------------------------------- |
@@ -2903,6 +2912,7 @@ static struct snd_kcontrol_new snd_trident_pcm_cvol_control __devinitdata = | |||
2903 | .info = snd_trident_pcm_cvol_control_info, | 2912 | .info = snd_trident_pcm_cvol_control_info, |
2904 | .get = snd_trident_pcm_cvol_control_get, | 2913 | .get = snd_trident_pcm_cvol_control_get, |
2905 | .put = snd_trident_pcm_cvol_control_put, | 2914 | .put = snd_trident_pcm_cvol_control_put, |
2915 | .tlv = { .p = db_scale_crvol }, | ||
2906 | }; | 2916 | }; |
2907 | 2917 | ||
2908 | static void snd_trident_notify_pcm_change1(struct snd_card *card, | 2918 | static void snd_trident_notify_pcm_change1(struct snd_card *card, |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 08da9234efb3..6db3d4cc4d8d 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -59,6 +59,7 @@ | |||
59 | #include <sound/pcm.h> | 59 | #include <sound/pcm.h> |
60 | #include <sound/pcm_params.h> | 60 | #include <sound/pcm_params.h> |
61 | #include <sound/info.h> | 61 | #include <sound/info.h> |
62 | #include <sound/tlv.h> | ||
62 | #include <sound/ac97_codec.h> | 63 | #include <sound/ac97_codec.h> |
63 | #include <sound/mpu401.h> | 64 | #include <sound/mpu401.h> |
64 | #include <sound/initval.h> | 65 | #include <sound/initval.h> |
@@ -1277,7 +1278,18 @@ static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream) | |||
1277 | if (! ratep->used) | 1278 | if (! ratep->used) |
1278 | ratep->rate = 0; | 1279 | ratep->rate = 0; |
1279 | spin_unlock_irq(&ratep->lock); | 1280 | spin_unlock_irq(&ratep->lock); |
1280 | 1281 | if (! ratep->rate) { | |
1282 | if (! viadev->direction) { | ||
1283 | snd_ac97_update_power(chip->ac97, | ||
1284 | AC97_PCM_FRONT_DAC_RATE, 0); | ||
1285 | snd_ac97_update_power(chip->ac97, | ||
1286 | AC97_PCM_SURR_DAC_RATE, 0); | ||
1287 | snd_ac97_update_power(chip->ac97, | ||
1288 | AC97_PCM_LFE_DAC_RATE, 0); | ||
1289 | } else | ||
1290 | snd_ac97_update_power(chip->ac97, | ||
1291 | AC97_PCM_LR_ADC_RATE, 0); | ||
1292 | } | ||
1281 | viadev->substream = NULL; | 1293 | viadev->substream = NULL; |
1282 | return 0; | 1294 | return 0; |
1283 | } | 1295 | } |
@@ -1687,21 +1699,29 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol, | |||
1687 | return change; | 1699 | return change; |
1688 | } | 1700 | } |
1689 | 1701 | ||
1702 | static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1); | ||
1703 | |||
1690 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { | 1704 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { |
1691 | .name = "PCM Playback Volume", | 1705 | .name = "PCM Playback Volume", |
1692 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1706 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1707 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1708 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1693 | .info = snd_via8233_dxs_volume_info, | 1709 | .info = snd_via8233_dxs_volume_info, |
1694 | .get = snd_via8233_pcmdxs_volume_get, | 1710 | .get = snd_via8233_pcmdxs_volume_get, |
1695 | .put = snd_via8233_pcmdxs_volume_put, | 1711 | .put = snd_via8233_pcmdxs_volume_put, |
1712 | .tlv = { .p = db_scale_dxs } | ||
1696 | }; | 1713 | }; |
1697 | 1714 | ||
1698 | static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = { | 1715 | static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = { |
1699 | .name = "VIA DXS Playback Volume", | 1716 | .name = "VIA DXS Playback Volume", |
1700 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1717 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1718 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1719 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1701 | .count = 4, | 1720 | .count = 4, |
1702 | .info = snd_via8233_dxs_volume_info, | 1721 | .info = snd_via8233_dxs_volume_info, |
1703 | .get = snd_via8233_dxs_volume_get, | 1722 | .get = snd_via8233_dxs_volume_get, |
1704 | .put = snd_via8233_dxs_volume_put, | 1723 | .put = snd_via8233_dxs_volume_put, |
1724 | .tlv = { .p = db_scale_dxs } | ||
1705 | }; | 1725 | }; |
1706 | 1726 | ||
1707 | /* | 1727 | /* |
@@ -2393,6 +2413,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci, int revision) | |||
2393 | { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */ | 2413 | { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */ |
2394 | { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */ | 2414 | { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */ |
2395 | { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */ | 2415 | { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */ |
2416 | { .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */ | ||
2396 | { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ | 2417 | { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ |
2397 | { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ | 2418 | { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ |
2398 | { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ | 2419 | { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ |
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 9c03c6b4e490..e7cd8acab59a 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
27 | #include <sound/core.h> | 27 | #include <sound/core.h> |
28 | #include <sound/initval.h> | 28 | #include <sound/initval.h> |
29 | #include <sound/tlv.h> | ||
29 | #include "vx222.h" | 30 | #include "vx222.h" |
30 | 31 | ||
31 | #define CARD_NAME "VX222" | 32 | #define CARD_NAME "VX222" |
@@ -72,6 +73,9 @@ MODULE_DEVICE_TABLE(pci, snd_vx222_ids); | |||
72 | /* | 73 | /* |
73 | */ | 74 | */ |
74 | 75 | ||
76 | static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); | ||
77 | static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0); | ||
78 | |||
75 | static struct snd_vx_hardware vx222_old_hw = { | 79 | static struct snd_vx_hardware vx222_old_hw = { |
76 | 80 | ||
77 | .name = "VX222/Old", | 81 | .name = "VX222/Old", |
@@ -81,6 +85,7 @@ static struct snd_vx_hardware vx222_old_hw = { | |||
81 | .num_ins = 1, | 85 | .num_ins = 1, |
82 | .num_outs = 1, | 86 | .num_outs = 1, |
83 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, | 87 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, |
88 | .output_level_db_scale = db_scale_old_vol, | ||
84 | }; | 89 | }; |
85 | 90 | ||
86 | static struct snd_vx_hardware vx222_v2_hw = { | 91 | static struct snd_vx_hardware vx222_v2_hw = { |
@@ -92,6 +97,7 @@ static struct snd_vx_hardware vx222_v2_hw = { | |||
92 | .num_ins = 1, | 97 | .num_ins = 1, |
93 | .num_outs = 1, | 98 | .num_outs = 1, |
94 | .output_level_max = VX2_AKM_LEVEL_MAX, | 99 | .output_level_max = VX2_AKM_LEVEL_MAX, |
100 | .output_level_db_scale = db_scale_akm, | ||
95 | }; | 101 | }; |
96 | 102 | ||
97 | static struct snd_vx_hardware vx222_mic_hw = { | 103 | static struct snd_vx_hardware vx222_mic_hw = { |
@@ -103,6 +109,7 @@ static struct snd_vx_hardware vx222_mic_hw = { | |||
103 | .num_ins = 1, | 109 | .num_ins = 1, |
104 | .num_outs = 1, | 110 | .num_outs = 1, |
105 | .output_level_max = VX2_AKM_LEVEL_MAX, | 111 | .output_level_max = VX2_AKM_LEVEL_MAX, |
112 | .output_level_db_scale = db_scale_akm, | ||
106 | }; | 113 | }; |
107 | 114 | ||
108 | 115 | ||
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 9b6d345b83a6..5e51950e05f9 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c | |||
@@ -28,6 +28,7 @@ | |||
28 | 28 | ||
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include <sound/control.h> | 30 | #include <sound/control.h> |
31 | #include <sound/tlv.h> | ||
31 | #include <asm/io.h> | 32 | #include <asm/io.h> |
32 | #include "vx222.h" | 33 | #include "vx222.h" |
33 | 34 | ||
@@ -845,6 +846,8 @@ static void vx2_set_input_level(struct snd_vx222 *chip) | |||
845 | 846 | ||
846 | #define MIC_LEVEL_MAX 0xff | 847 | #define MIC_LEVEL_MAX 0xff |
847 | 848 | ||
849 | static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0); | ||
850 | |||
848 | /* | 851 | /* |
849 | * controls API for input levels | 852 | * controls API for input levels |
850 | */ | 853 | */ |
@@ -922,18 +925,24 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
922 | 925 | ||
923 | static struct snd_kcontrol_new vx_control_input_level = { | 926 | static struct snd_kcontrol_new vx_control_input_level = { |
924 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 927 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
928 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
929 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
925 | .name = "Capture Volume", | 930 | .name = "Capture Volume", |
926 | .info = vx_input_level_info, | 931 | .info = vx_input_level_info, |
927 | .get = vx_input_level_get, | 932 | .get = vx_input_level_get, |
928 | .put = vx_input_level_put, | 933 | .put = vx_input_level_put, |
934 | .tlv = { .p = db_scale_mic }, | ||
929 | }; | 935 | }; |
930 | 936 | ||
931 | static struct snd_kcontrol_new vx_control_mic_level = { | 937 | static struct snd_kcontrol_new vx_control_mic_level = { |
932 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 938 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
939 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
940 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
933 | .name = "Mic Capture Volume", | 941 | .name = "Mic Capture Volume", |
934 | .info = vx_mic_level_info, | 942 | .info = vx_mic_level_info, |
935 | .get = vx_mic_level_get, | 943 | .get = vx_mic_level_get, |
936 | .put = vx_mic_level_put, | 944 | .put = vx_mic_level_put, |
945 | .tlv = { .p = db_scale_mic }, | ||
937 | }; | 946 | }; |
938 | 947 | ||
939 | /* | 948 | /* |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index a55b5fd7da64..24f6fc52f898 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <sound/core.h> | 36 | #include <sound/core.h> |
37 | #include <sound/control.h> | 37 | #include <sound/control.h> |
38 | #include <sound/info.h> | 38 | #include <sound/info.h> |
39 | #include <sound/tlv.h> | ||
39 | #include <sound/ymfpci.h> | 40 | #include <sound/ymfpci.h> |
40 | #include <sound/asoundef.h> | 41 | #include <sound/asoundef.h> |
41 | #include <sound/mpu401.h> | 42 | #include <sound/mpu401.h> |
@@ -1477,11 +1478,15 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol, | |||
1477 | return change; | 1478 | return change; |
1478 | } | 1479 | } |
1479 | 1480 | ||
1481 | static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0); | ||
1482 | |||
1480 | #define YMFPCI_DOUBLE(xname, xindex, reg) \ | 1483 | #define YMFPCI_DOUBLE(xname, xindex, reg) \ |
1481 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 1484 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
1485 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
1482 | .info = snd_ymfpci_info_double, \ | 1486 | .info = snd_ymfpci_info_double, \ |
1483 | .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \ | 1487 | .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \ |
1484 | .private_value = reg } | 1488 | .private_value = reg, \ |
1489 | .tlv = { .p = db_scale_native } } | ||
1485 | 1490 | ||
1486 | static int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 1491 | static int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1487 | { | 1492 | { |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 1c09e5f49da8..fd3590fcaedb 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c | |||
@@ -206,7 +206,7 @@ static void snd_pdacf_detach(struct pcmcia_device *link) | |||
206 | snd_pdacf_powerdown(chip); | 206 | snd_pdacf_powerdown(chip); |
207 | chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */ | 207 | chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */ |
208 | snd_card_disconnect(chip->card); | 208 | snd_card_disconnect(chip->card); |
209 | snd_card_free_in_thread(chip->card); | 209 | snd_card_free_when_closed(chip->card); |
210 | } | 210 | } |
211 | 211 | ||
212 | /* | 212 | /* |
diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index e237f6c2018f..bced7b623b12 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <sound/driver.h> | 23 | #include <sound/driver.h> |
24 | #include <sound/core.h> | 24 | #include <sound/core.h> |
25 | #include <sound/control.h> | 25 | #include <sound/control.h> |
26 | #include <sound/tlv.h> | ||
26 | #include "vxpocket.h" | 27 | #include "vxpocket.h" |
27 | 28 | ||
28 | #define MIC_LEVEL_MIN 0 | 29 | #define MIC_LEVEL_MIN 0 |
@@ -63,12 +64,17 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
63 | return 0; | 64 | return 0; |
64 | } | 65 | } |
65 | 66 | ||
67 | static DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0); | ||
68 | |||
66 | static struct snd_kcontrol_new vx_control_mic_level = { | 69 | static struct snd_kcontrol_new vx_control_mic_level = { |
67 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 70 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
71 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
72 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
68 | .name = "Mic Capture Volume", | 73 | .name = "Mic Capture Volume", |
69 | .info = vx_mic_level_info, | 74 | .info = vx_mic_level_info, |
70 | .get = vx_mic_level_get, | 75 | .get = vx_mic_level_get, |
71 | .put = vx_mic_level_put, | 76 | .put = vx_mic_level_put, |
77 | .tlv = { .p = db_scale_mic }, | ||
72 | }; | 78 | }; |
73 | 79 | ||
74 | /* | 80 | /* |
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index cafe6640cc1a..3089fcca800e 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <pcmcia/ciscode.h> | 27 | #include <pcmcia/ciscode.h> |
28 | #include <pcmcia/cisreg.h> | 28 | #include <pcmcia/cisreg.h> |
29 | #include <sound/initval.h> | 29 | #include <sound/initval.h> |
30 | #include <sound/tlv.h> | ||
30 | 31 | ||
31 | /* | 32 | /* |
32 | */ | 33 | */ |
@@ -65,7 +66,7 @@ static void vxpocket_release(struct pcmcia_device *link) | |||
65 | } | 66 | } |
66 | 67 | ||
67 | /* | 68 | /* |
68 | * destructor, called from snd_card_free_in_thread() | 69 | * destructor, called from snd_card_free_when_closed() |
69 | */ | 70 | */ |
70 | static int snd_vxpocket_dev_free(struct snd_device *device) | 71 | static int snd_vxpocket_dev_free(struct snd_device *device) |
71 | { | 72 | { |
@@ -90,6 +91,8 @@ static int snd_vxpocket_dev_free(struct snd_device *device) | |||
90 | * Only output levels can be modified | 91 | * Only output levels can be modified |
91 | */ | 92 | */ |
92 | 93 | ||
94 | static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); | ||
95 | |||
93 | static struct snd_vx_hardware vxpocket_hw = { | 96 | static struct snd_vx_hardware vxpocket_hw = { |
94 | .name = "VXPocket", | 97 | .name = "VXPocket", |
95 | .type = VX_TYPE_VXPOCKET, | 98 | .type = VX_TYPE_VXPOCKET, |
@@ -99,6 +102,7 @@ static struct snd_vx_hardware vxpocket_hw = { | |||
99 | .num_ins = 1, | 102 | .num_ins = 1, |
100 | .num_outs = 1, | 103 | .num_outs = 1, |
101 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, | 104 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, |
105 | .output_level_db_scale = db_scale_old_vol, | ||
102 | }; | 106 | }; |
103 | 107 | ||
104 | /* VX-pocket 440 | 108 | /* VX-pocket 440 |
@@ -120,6 +124,7 @@ static struct snd_vx_hardware vxp440_hw = { | |||
120 | .num_ins = 2, | 124 | .num_ins = 2, |
121 | .num_outs = 2, | 125 | .num_outs = 2, |
122 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, | 126 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, |
127 | .output_level_db_scale = db_scale_old_vol, | ||
123 | }; | 128 | }; |
124 | 129 | ||
125 | 130 | ||
@@ -363,7 +368,7 @@ static void vxpocket_detach(struct pcmcia_device *link) | |||
363 | chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ | 368 | chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ |
364 | snd_card_disconnect(chip->card); | 369 | snd_card_disconnect(chip->card); |
365 | vxpocket_release(link); | 370 | vxpocket_release(link); |
366 | snd_card_free_in_thread(chip->card); | 371 | snd_card_free_when_closed(chip->card); |
367 | } | 372 | } |
368 | 373 | ||
369 | /* | 374 | /* |
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index 5fec1e58f310..5f38f670102c 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c | |||
@@ -215,15 +215,18 @@ int __init snd_pmac_attach_beep(struct snd_pmac *chip) | |||
215 | { | 215 | { |
216 | struct pmac_beep *beep; | 216 | struct pmac_beep *beep; |
217 | struct input_dev *input_dev; | 217 | struct input_dev *input_dev; |
218 | struct snd_kcontrol *beep_ctl; | ||
218 | void *dmabuf; | 219 | void *dmabuf; |
219 | int err = -ENOMEM; | 220 | int err = -ENOMEM; |
220 | 221 | ||
221 | beep = kzalloc(sizeof(*beep), GFP_KERNEL); | 222 | beep = kzalloc(sizeof(*beep), GFP_KERNEL); |
223 | if (! beep) | ||
224 | return -ENOMEM; | ||
222 | dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, | 225 | dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, |
223 | &beep->addr, GFP_KERNEL); | 226 | &beep->addr, GFP_KERNEL); |
224 | input_dev = input_allocate_device(); | 227 | input_dev = input_allocate_device(); |
225 | if (!beep || !dmabuf || !input_dev) | 228 | if (! dmabuf || ! input_dev) |
226 | goto fail; | 229 | goto fail1; |
227 | 230 | ||
228 | /* FIXME: set more better values */ | 231 | /* FIXME: set more better values */ |
229 | input_dev->name = "PowerMac Beep"; | 232 | input_dev->name = "PowerMac Beep"; |
@@ -244,17 +247,24 @@ int __init snd_pmac_attach_beep(struct snd_pmac *chip) | |||
244 | beep->volume = BEEP_VOLUME; | 247 | beep->volume = BEEP_VOLUME; |
245 | beep->running = 0; | 248 | beep->running = 0; |
246 | 249 | ||
247 | err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_beep_mixer, chip)); | 250 | beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip); |
251 | err = snd_ctl_add(chip->card, beep_ctl); | ||
248 | if (err < 0) | 252 | if (err < 0) |
249 | goto fail; | 253 | goto fail1; |
254 | |||
255 | chip->beep = beep; | ||
250 | 256 | ||
251 | chip->beep = beep; | 257 | err = input_register_device(beep->dev); |
252 | input_register_device(beep->dev); | 258 | if (err) |
253 | 259 | goto fail2; | |
254 | return 0; | 260 | |
255 | 261 | return 0; | |
256 | fail: input_free_device(input_dev); | 262 | |
257 | kfree(dmabuf); | 263 | fail2: snd_ctl_remove(chip->card, beep_ctl); |
264 | fail1: input_free_device(input_dev); | ||
265 | if (dmabuf) | ||
266 | dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, | ||
267 | dmabuf, beep->addr); | ||
258 | kfree(beep); | 268 | kfree(beep); |
259 | return err; | 269 | return err; |
260 | } | 270 | } |
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index 59482a4cd446..272ae38e9b18 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c | |||
@@ -117,6 +117,9 @@ int __init snd_pmac_tumbler_post_init(void) | |||
117 | { | 117 | { |
118 | int err; | 118 | int err; |
119 | 119 | ||
120 | if (!keywest_ctx || !keywest_ctx->client) | ||
121 | return -ENXIO; | ||
122 | |||
120 | if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) { | 123 | if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) { |
121 | snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err); | 124 | snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err); |
122 | return err; | 125 | return err; |
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 84f6b19c07ca..cdff53e4a17e 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
@@ -190,7 +190,7 @@ static int check_audio_gpio(struct pmac_gpio *gp) | |||
190 | 190 | ||
191 | ret = do_gpio_read(gp); | 191 | ret = do_gpio_read(gp); |
192 | 192 | ||
193 | return (ret & 0xd) == (gp->active_val & 0xd); | 193 | return (ret & 0x1) == (gp->active_val & 0x1); |
194 | } | 194 | } |
195 | 195 | ||
196 | static int read_audio_gpio(struct pmac_gpio *gp) | 196 | static int read_audio_gpio(struct pmac_gpio *gp) |
@@ -198,7 +198,8 @@ static int read_audio_gpio(struct pmac_gpio *gp) | |||
198 | int ret; | 198 | int ret; |
199 | if (! gp->addr) | 199 | if (! gp->addr) |
200 | return 0; | 200 | return 0; |
201 | ret = ((do_gpio_read(gp) & 0x02) !=0); | 201 | ret = do_gpio_read(gp); |
202 | ret = (ret & 0x02) !=0; | ||
202 | return ret == gp->active_state; | 203 | return ret == gp->active_state; |
203 | } | 204 | } |
204 | 205 | ||
@@ -1035,7 +1036,7 @@ static struct device_node *find_audio_device(const char *name) | |||
1035 | return NULL; | 1036 | return NULL; |
1036 | 1037 | ||
1037 | for (np = np->child; np; np = np->sibling) { | 1038 | for (np = np->child; np; np = np->sibling) { |
1038 | char *property = get_property(np, "audio-gpio", NULL); | 1039 | const char *property = get_property(np, "audio-gpio", NULL); |
1039 | if (property && strcmp(property, name) == 0) | 1040 | if (property && strcmp(property, name) == 0) |
1040 | return np; | 1041 | return np; |
1041 | } | 1042 | } |
@@ -1062,7 +1063,8 @@ static long tumbler_find_device(const char *device, const char *platform, | |||
1062 | struct pmac_gpio *gp, int is_compatible) | 1063 | struct pmac_gpio *gp, int is_compatible) |
1063 | { | 1064 | { |
1064 | struct device_node *node; | 1065 | struct device_node *node; |
1065 | u32 *base, addr; | 1066 | const u32 *base; |
1067 | u32 addr; | ||
1066 | 1068 | ||
1067 | if (is_compatible) | 1069 | if (is_compatible) |
1068 | node = find_compatible_audio_device(device); | 1070 | node = find_compatible_audio_device(device); |
@@ -1074,9 +1076,9 @@ static long tumbler_find_device(const char *device, const char *platform, | |||
1074 | return -ENODEV; | 1076 | return -ENODEV; |
1075 | } | 1077 | } |
1076 | 1078 | ||
1077 | base = (u32 *)get_property(node, "AAPL,address", NULL); | 1079 | base = get_property(node, "AAPL,address", NULL); |
1078 | if (! base) { | 1080 | if (! base) { |
1079 | base = (u32 *)get_property(node, "reg", NULL); | 1081 | base = get_property(node, "reg", NULL); |
1080 | if (!base) { | 1082 | if (!base) { |
1081 | DBG("(E) cannot find address for device %s !\n", device); | 1083 | DBG("(E) cannot find address for device %s !\n", device); |
1082 | snd_printd("cannot find address for device %s\n", device); | 1084 | snd_printd("cannot find address for device %s\n", device); |
@@ -1090,13 +1092,13 @@ static long tumbler_find_device(const char *device, const char *platform, | |||
1090 | 1092 | ||
1091 | gp->addr = addr & 0x0000ffff; | 1093 | gp->addr = addr & 0x0000ffff; |
1092 | /* Try to find the active state, default to 0 ! */ | 1094 | /* Try to find the active state, default to 0 ! */ |
1093 | base = (u32 *)get_property(node, "audio-gpio-active-state", NULL); | 1095 | base = get_property(node, "audio-gpio-active-state", NULL); |
1094 | if (base) { | 1096 | if (base) { |
1095 | gp->active_state = *base; | 1097 | gp->active_state = *base; |
1096 | gp->active_val = (*base) ? 0x5 : 0x4; | 1098 | gp->active_val = (*base) ? 0x5 : 0x4; |
1097 | gp->inactive_val = (*base) ? 0x4 : 0x5; | 1099 | gp->inactive_val = (*base) ? 0x4 : 0x5; |
1098 | } else { | 1100 | } else { |
1099 | u32 *prop = NULL; | 1101 | const u32 *prop = NULL; |
1100 | gp->active_state = 0; | 1102 | gp->active_state = 0; |
1101 | gp->active_val = 0x4; | 1103 | gp->active_val = 0x4; |
1102 | gp->inactive_val = 0x5; | 1104 | gp->inactive_val = 0x5; |
@@ -1105,7 +1107,7 @@ static long tumbler_find_device(const char *device, const char *platform, | |||
1105 | * as we don't yet have an interpreter for these things | 1107 | * as we don't yet have an interpreter for these things |
1106 | */ | 1108 | */ |
1107 | if (platform) | 1109 | if (platform) |
1108 | prop = (u32 *)get_property(node, platform, NULL); | 1110 | prop = get_property(node, platform, NULL); |
1109 | if (prop) { | 1111 | if (prop) { |
1110 | if (prop[3] == 0x9 && prop[4] == 0x9) { | 1112 | if (prop[3] == 0x9 && prop[4] == 0x9) { |
1111 | gp->active_val = 0xd; | 1113 | gp->active_val = 0xd; |
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index f3ae6e23610e..e4935fca12df 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
@@ -2,6 +2,8 @@ | |||
2 | * Driver for DBRI sound chip found on Sparcs. | 2 | * Driver for DBRI sound chip found on Sparcs. |
3 | * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) | 3 | * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) |
4 | * | 4 | * |
5 | * Converted to ring buffered version by Krzysztof Helt (krzysztof.h1@wp.pl) | ||
6 | * | ||
5 | * Based entirely upon drivers/sbus/audio/dbri.c which is: | 7 | * Based entirely upon drivers/sbus/audio/dbri.c which is: |
6 | * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) | 8 | * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) |
7 | * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) | 9 | * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) |
@@ -34,7 +36,7 @@ | |||
34 | * (the second one is a monitor/tee pipe, valid only for serial input). | 36 | * (the second one is a monitor/tee pipe, valid only for serial input). |
35 | * | 37 | * |
36 | * The mmcodec is connected via the CHI bus and needs the data & some | 38 | * The mmcodec is connected via the CHI bus and needs the data & some |
37 | * parameters (volume, balance, output selection) timemultiplexed in 8 byte | 39 | * parameters (volume, output selection) timemultiplexed in 8 byte |
38 | * chunks. It also has a control mode, which serves for audio format setting. | 40 | * chunks. It also has a control mode, which serves for audio format setting. |
39 | * | 41 | * |
40 | * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on | 42 | * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on |
@@ -83,7 +85,7 @@ MODULE_PARM_DESC(id, "ID string for Sun DBRI soundcard."); | |||
83 | module_param_array(enable, bool, NULL, 0444); | 85 | module_param_array(enable, bool, NULL, 0444); |
84 | MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard."); | 86 | MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard."); |
85 | 87 | ||
86 | #define DBRI_DEBUG | 88 | #undef DBRI_DEBUG |
87 | 89 | ||
88 | #define D_INT (1<<0) | 90 | #define D_INT (1<<0) |
89 | #define D_GEN (1<<1) | 91 | #define D_GEN (1<<1) |
@@ -104,17 +106,15 @@ static char *cmds[] = { | |||
104 | 106 | ||
105 | #define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x) | 107 | #define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x) |
106 | 108 | ||
107 | #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \ | ||
108 | (1 << 27) | \ | ||
109 | value) | ||
110 | #else | 109 | #else |
111 | #define dprintk(a, x...) | 110 | #define dprintk(a, x...) do { } while (0) |
112 | 111 | ||
113 | #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \ | ||
114 | (intr << 27) | \ | ||
115 | value) | ||
116 | #endif /* DBRI_DEBUG */ | 112 | #endif /* DBRI_DEBUG */ |
117 | 113 | ||
114 | #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \ | ||
115 | (intr << 27) | \ | ||
116 | value) | ||
117 | |||
118 | /*************************************************************************** | 118 | /*************************************************************************** |
119 | CS4215 specific definitions and structures | 119 | CS4215 specific definitions and structures |
120 | ****************************************************************************/ | 120 | ****************************************************************************/ |
@@ -160,7 +160,7 @@ static struct { | |||
160 | /* { NA, (1 << 4), (5 << 3) }, */ | 160 | /* { NA, (1 << 4), (5 << 3) }, */ |
161 | { 48000, (1 << 4), (6 << 3) }, | 161 | { 48000, (1 << 4), (6 << 3) }, |
162 | { 9600, (1 << 4), (7 << 3) }, | 162 | { 9600, (1 << 4), (7 << 3) }, |
163 | { 5513, (2 << 4), (0 << 3) }, /* Actually 5512.5 */ | 163 | { 5512, (2 << 4), (0 << 3) }, /* Actually 5512.5 */ |
164 | { 11025, (2 << 4), (1 << 3) }, | 164 | { 11025, (2 << 4), (1 << 3) }, |
165 | { 18900, (2 << 4), (2 << 3) }, | 165 | { 18900, (2 << 4), (2 << 3) }, |
166 | { 22050, (2 << 4), (3 << 3) }, | 166 | { 22050, (2 << 4), (3 << 3) }, |
@@ -240,28 +240,21 @@ static struct { | |||
240 | #define REG9 0x24UL /* Interrupt Queue Pointer */ | 240 | #define REG9 0x24UL /* Interrupt Queue Pointer */ |
241 | 241 | ||
242 | #define DBRI_NO_CMDS 64 | 242 | #define DBRI_NO_CMDS 64 |
243 | #define DBRI_NO_INTS 1 /* Note: the value of this define was | ||
244 | * originally 2. The ringbuffer to store | ||
245 | * interrupts in dma is currently broken. | ||
246 | * This is a temporary fix until the ringbuffer | ||
247 | * is fixed. | ||
248 | */ | ||
249 | #define DBRI_INT_BLK 64 | 243 | #define DBRI_INT_BLK 64 |
250 | #define DBRI_NO_DESCS 64 | 244 | #define DBRI_NO_DESCS 64 |
251 | #define DBRI_NO_PIPES 32 | 245 | #define DBRI_NO_PIPES 32 |
252 | 246 | #define DBRI_MAX_PIPE (DBRI_NO_PIPES - 1) | |
253 | #define DBRI_MM_ONB 1 | ||
254 | #define DBRI_MM_SB 2 | ||
255 | 247 | ||
256 | #define DBRI_REC 0 | 248 | #define DBRI_REC 0 |
257 | #define DBRI_PLAY 1 | 249 | #define DBRI_PLAY 1 |
258 | #define DBRI_NO_STREAMS 2 | 250 | #define DBRI_NO_STREAMS 2 |
259 | 251 | ||
260 | /* One transmit/receive descriptor */ | 252 | /* One transmit/receive descriptor */ |
253 | /* When ba != 0 descriptor is used */ | ||
261 | struct dbri_mem { | 254 | struct dbri_mem { |
262 | volatile __u32 word1; | 255 | volatile __u32 word1; |
263 | volatile __u32 ba; /* Transmit/Receive Buffer Address */ | 256 | __u32 ba; /* Transmit/Receive Buffer Address */ |
264 | volatile __u32 nda; /* Next Descriptor Address */ | 257 | __u32 nda; /* Next Descriptor Address */ |
265 | volatile __u32 word4; | 258 | volatile __u32 word4; |
266 | }; | 259 | }; |
267 | 260 | ||
@@ -269,8 +262,8 @@ struct dbri_mem { | |||
269 | * the CPU and the DBRI | 262 | * the CPU and the DBRI |
270 | */ | 263 | */ |
271 | struct dbri_dma { | 264 | struct dbri_dma { |
272 | volatile s32 cmd[DBRI_NO_CMDS]; /* Place for commands */ | 265 | s32 cmd[DBRI_NO_CMDS]; /* Place for commands */ |
273 | volatile s32 intr[DBRI_NO_INTS * DBRI_INT_BLK]; /* Interrupt field */ | 266 | volatile s32 intr[DBRI_INT_BLK]; /* Interrupt field */ |
274 | struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */ | 267 | struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */ |
275 | }; | 268 | }; |
276 | 269 | ||
@@ -282,58 +275,43 @@ enum in_or_out { PIPEinput, PIPEoutput }; | |||
282 | 275 | ||
283 | struct dbri_pipe { | 276 | struct dbri_pipe { |
284 | u32 sdp; /* SDP command word */ | 277 | u32 sdp; /* SDP command word */ |
285 | enum in_or_out direction; | ||
286 | int nextpipe; /* Next pipe in linked list */ | 278 | int nextpipe; /* Next pipe in linked list */ |
287 | int prevpipe; | ||
288 | int cycle; /* Offset of timeslot (bits) */ | ||
289 | int length; /* Length of timeslot (bits) */ | 279 | int length; /* Length of timeslot (bits) */ |
290 | int first_desc; /* Index of first descriptor */ | 280 | int first_desc; /* Index of first descriptor */ |
291 | int desc; /* Index of active descriptor */ | 281 | int desc; /* Index of active descriptor */ |
292 | volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */ | 282 | volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */ |
293 | }; | 283 | }; |
294 | 284 | ||
295 | struct dbri_desc { | ||
296 | int inuse; /* Boolean flag */ | ||
297 | int next; /* Index of next desc, or -1 */ | ||
298 | unsigned int len; | ||
299 | }; | ||
300 | |||
301 | /* Per stream (playback or record) information */ | 285 | /* Per stream (playback or record) information */ |
302 | struct dbri_streaminfo { | 286 | struct dbri_streaminfo { |
303 | struct snd_pcm_substream *substream; | 287 | struct snd_pcm_substream *substream; |
304 | u32 dvma_buffer; /* Device view of Alsa DMA buffer */ | 288 | u32 dvma_buffer; /* Device view of Alsa DMA buffer */ |
305 | int left; /* # of bytes left in DMA buffer */ | ||
306 | int size; /* Size of DMA buffer */ | 289 | int size; /* Size of DMA buffer */ |
307 | size_t offset; /* offset in user buffer */ | 290 | size_t offset; /* offset in user buffer */ |
308 | int pipe; /* Data pipe used */ | 291 | int pipe; /* Data pipe used */ |
309 | int left_gain; /* mixer elements */ | 292 | int left_gain; /* mixer elements */ |
310 | int right_gain; | 293 | int right_gain; |
311 | int balance; | ||
312 | }; | 294 | }; |
313 | 295 | ||
314 | /* This structure holds the information for both chips (DBRI & CS4215) */ | 296 | /* This structure holds the information for both chips (DBRI & CS4215) */ |
315 | struct snd_dbri { | 297 | struct snd_dbri { |
316 | struct snd_card *card; /* ALSA card */ | 298 | struct snd_card *card; /* ALSA card */ |
317 | struct snd_pcm *pcm; | ||
318 | 299 | ||
319 | int regs_size, irq; /* Needed for unload */ | 300 | int regs_size, irq; /* Needed for unload */ |
320 | struct sbus_dev *sdev; /* SBUS device info */ | 301 | struct sbus_dev *sdev; /* SBUS device info */ |
321 | spinlock_t lock; | 302 | spinlock_t lock; |
322 | 303 | ||
323 | volatile struct dbri_dma *dma; /* Pointer to our DMA block */ | 304 | struct dbri_dma *dma; /* Pointer to our DMA block */ |
324 | u32 dma_dvma; /* DBRI visible DMA address */ | 305 | u32 dma_dvma; /* DBRI visible DMA address */ |
325 | 306 | ||
326 | void __iomem *regs; /* dbri HW regs */ | 307 | void __iomem *regs; /* dbri HW regs */ |
327 | int dbri_version; /* 'e' and up is OK */ | ||
328 | int dbri_irqp; /* intr queue pointer */ | 308 | int dbri_irqp; /* intr queue pointer */ |
329 | int wait_send; /* sequence of command buffers send */ | ||
330 | int wait_ackd; /* sequence of command buffers acknowledged */ | ||
331 | 309 | ||
332 | struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */ | 310 | struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */ |
333 | struct dbri_desc descs[DBRI_NO_DESCS]; | 311 | int next_desc[DBRI_NO_DESCS]; /* Index of next desc, or -1 */ |
312 | spinlock_t cmdlock; /* Protects cmd queue accesses */ | ||
313 | s32 *cmdptr; /* Pointer to the last queued cmd */ | ||
334 | 314 | ||
335 | int chi_in_pipe; | ||
336 | int chi_out_pipe; | ||
337 | int chi_bpf; | 315 | int chi_bpf; |
338 | 316 | ||
339 | struct cs4215 mm; /* mmcodec special info */ | 317 | struct cs4215 mm; /* mmcodec special info */ |
@@ -345,8 +323,6 @@ struct snd_dbri { | |||
345 | 323 | ||
346 | #define DBRI_MAX_VOLUME 63 /* Output volume */ | 324 | #define DBRI_MAX_VOLUME 63 /* Output volume */ |
347 | #define DBRI_MAX_GAIN 15 /* Input gain */ | 325 | #define DBRI_MAX_GAIN 15 /* Input gain */ |
348 | #define DBRI_RIGHT_BALANCE 255 | ||
349 | #define DBRI_MID_BALANCE (DBRI_RIGHT_BALANCE >> 1) | ||
350 | 326 | ||
351 | /* DBRI Reg0 - Status Control Register - defines. (Page 17) */ | 327 | /* DBRI Reg0 - Status Control Register - defines. (Page 17) */ |
352 | #define D_P (1<<15) /* Program command & queue pointer valid */ | 328 | #define D_P (1<<15) /* Program command & queue pointer valid */ |
@@ -569,7 +545,7 @@ struct snd_dbri { | |||
569 | #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ | 545 | #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ |
570 | #define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ | 546 | #define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ |
571 | /* Maximum buffer size per TD: almost 8Kb */ | 547 | /* Maximum buffer size per TD: almost 8Kb */ |
572 | #define DBRI_TD_MAXCNT ((1 << 13) - 1) | 548 | #define DBRI_TD_MAXCNT ((1 << 13) - 4) |
573 | 549 | ||
574 | /* Receive descriptor defines */ | 550 | /* Receive descriptor defines */ |
575 | #define DBRI_RD_F (1<<31) /* End of Frame */ | 551 | #define DBRI_RD_F (1<<31) /* End of Frame */ |
@@ -633,93 +609,124 @@ The list is terminated with a WAIT command, which generates a | |||
633 | CPU interrupt to signal completion. | 609 | CPU interrupt to signal completion. |
634 | 610 | ||
635 | Since the DBRI can run in parallel with the CPU, several means of | 611 | Since the DBRI can run in parallel with the CPU, several means of |
636 | synchronization present themselves. The method implemented here is close | 612 | synchronization present themselves. The method implemented here is only |
637 | to the original scheme (Rudolf's), and uses 2 counters (wait_send and | 613 | use of the dbri_cmdwait() to wait for execution of batch of sent commands. |
638 | wait_ackd) to synchronize the command buffer between the CPU and the DBRI. | ||
639 | 614 | ||
640 | A more sophisticated scheme might involve a circular command buffer | 615 | A circular command buffer is used here. A new command is being added |
641 | or an array of command buffers. A routine could fill one with | 616 | while another can be executed. The scheme works by adding two WAIT commands |
642 | commands and link it onto a list. When a interrupt signaled | 617 | after each sent batch of commands. When the next batch is prepared it is |
643 | completion of the current command buffer, look on the list for | 618 | added after the WAIT commands then the WAITs are replaced with single JUMP |
644 | the next one. | 619 | command to the new batch. The the DBRI is forced to reread the last WAIT |
620 | command (replaced by the JUMP by then). If the DBRI is still executing | ||
621 | previous commands the request to reread the WAIT command is ignored. | ||
645 | 622 | ||
646 | Every time a routine wants to write commands to the DBRI, it must | 623 | Every time a routine wants to write commands to the DBRI, it must |
647 | first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd | 624 | first call dbri_cmdlock() and get pointer to a free space in |
648 | in return. dbri_cmdlock() will block if the previous commands have not | 625 | dbri->dma->cmd buffer. After this, the commands can be written to |
649 | been completed yet. After this the commands can be written to the buffer, | 626 | the buffer, and dbri_cmdsend() is called with the final pointer value |
650 | and dbri_cmdsend() is called with the final pointer value to send them | 627 | to send them to the DBRI. |
651 | to the DBRI. | ||
652 | 628 | ||
653 | */ | 629 | */ |
654 | 630 | ||
655 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri); | 631 | #define MAXLOOPS 20 |
656 | 632 | /* | |
657 | enum dbri_lock { NoGetLock, GetLock }; | 633 | * Wait for the current command string to execute |
658 | #define MAXLOOPS 10 | 634 | */ |
659 | 635 | static void dbri_cmdwait(struct snd_dbri *dbri) | |
660 | static volatile s32 *dbri_cmdlock(struct snd_dbri * dbri, enum dbri_lock get) | ||
661 | { | 636 | { |
662 | int maxloops = MAXLOOPS; | 637 | int maxloops = MAXLOOPS; |
663 | 638 | unsigned long flags; | |
664 | #ifndef SMP | ||
665 | if ((get == GetLock) && spin_is_locked(&dbri->lock)) { | ||
666 | printk(KERN_ERR "DBRI: cmdlock called while in spinlock."); | ||
667 | } | ||
668 | #endif | ||
669 | 639 | ||
670 | /* Delay if previous commands are still being processed */ | 640 | /* Delay if previous commands are still being processed */ |
671 | while ((--maxloops) > 0 && (dbri->wait_send != dbri->wait_ackd)) { | 641 | spin_lock_irqsave(&dbri->lock, flags); |
642 | while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) { | ||
643 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
672 | msleep_interruptible(1); | 644 | msleep_interruptible(1); |
673 | /* If dbri_cmdlock() got called from inside the | 645 | spin_lock_irqsave(&dbri->lock, flags); |
674 | * interrupt handler, this will do the processing. | ||
675 | */ | ||
676 | dbri_process_interrupt_buffer(dbri); | ||
677 | } | 646 | } |
647 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
648 | |||
678 | if (maxloops == 0) { | 649 | if (maxloops == 0) { |
679 | printk(KERN_ERR "DBRI: Chip never completed command buffer %d\n", | 650 | printk(KERN_ERR "DBRI: Chip never completed command buffer\n"); |
680 | dbri->wait_send); | ||
681 | } else { | 651 | } else { |
682 | dprintk(D_CMD, "Chip completed command buffer (%d)\n", | 652 | dprintk(D_CMD, "Chip completed command buffer (%d)\n", |
683 | MAXLOOPS - maxloops - 1); | 653 | MAXLOOPS - maxloops - 1); |
684 | } | 654 | } |
655 | } | ||
656 | /* | ||
657 | * Lock the command queue and returns pointer to a space for len cmd words | ||
658 | * It locks the cmdlock spinlock. | ||
659 | */ | ||
660 | static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len) | ||
661 | { | ||
662 | /* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */ | ||
663 | len += 2; | ||
664 | spin_lock(&dbri->cmdlock); | ||
665 | if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2) | ||
666 | return dbri->cmdptr + 2; | ||
667 | else if (len < sbus_readl(dbri->regs + REG8) - dbri->dma_dvma) | ||
668 | return dbri->dma->cmd; | ||
669 | else | ||
670 | printk(KERN_ERR "DBRI: no space for commands."); | ||
685 | 671 | ||
686 | /*if (get == GetLock) spin_lock(&dbri->lock); */ | 672 | return 0; |
687 | return &dbri->dma->cmd[0]; | ||
688 | } | 673 | } |
689 | 674 | ||
690 | static void dbri_cmdsend(struct snd_dbri * dbri, volatile s32 * cmd) | 675 | /* |
676 | * Send prepared cmd string. It works by writting a JUMP cmd into | ||
677 | * the last WAIT cmd and force DBRI to reread the cmd. | ||
678 | * The JUMP cmd points to the new cmd string. | ||
679 | * It also releases the cmdlock spinlock. | ||
680 | * | ||
681 | * Lock must not be held before calling this. | ||
682 | */ | ||
683 | static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) | ||
691 | { | 684 | { |
692 | volatile s32 *ptr; | 685 | s32 tmp, addr; |
693 | u32 reg; | 686 | static int wait_id = 0; |
694 | 687 | ||
695 | for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) { | 688 | wait_id++; |
696 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | 689 | wait_id &= 0xffff; /* restrict it to a 16 bit counter. */ |
697 | } | 690 | *(cmd) = DBRI_CMD(D_WAIT, 1, wait_id); |
691 | *(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id); | ||
698 | 692 | ||
699 | if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS - 1) { | 693 | /* Replace the last command with JUMP */ |
700 | printk(KERN_ERR "DBRI: Command buffer overflow! (bug in driver)\n"); | 694 | addr = dbri->dma_dvma + (cmd - len - dbri->dma->cmd) * sizeof(s32); |
701 | /* Ignore the last part. */ | 695 | *(dbri->cmdptr+1) = addr; |
702 | cmd = &dbri->dma->cmd[DBRI_NO_CMDS - 3]; | 696 | *(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0); |
703 | } | ||
704 | 697 | ||
705 | dbri->wait_send++; | 698 | #ifdef DBRI_DEBUG |
706 | dbri->wait_send &= 0xffff; /* restrict it to a 16 bit counter. */ | 699 | if (cmd > dbri->cmdptr) { |
707 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | 700 | s32 *ptr; |
708 | *(cmd++) = DBRI_CMD(D_WAIT, 1, dbri->wait_send); | 701 | |
702 | for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++) | ||
703 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
704 | } else { | ||
705 | s32 *ptr = dbri->cmdptr; | ||
706 | |||
707 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
708 | ptr++; | ||
709 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
710 | for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++) { | ||
711 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
712 | } | ||
713 | } | ||
714 | #endif | ||
709 | 715 | ||
710 | /* Set command pointer and signal it is valid. */ | 716 | /* Reread the last command */ |
711 | sbus_writel(dbri->dma_dvma, dbri->regs + REG8); | 717 | tmp = sbus_readl(dbri->regs + REG0); |
712 | reg = sbus_readl(dbri->regs + REG0); | 718 | tmp |= D_P; |
713 | reg |= D_P; | 719 | sbus_writel(tmp, dbri->regs + REG0); |
714 | sbus_writel(reg, dbri->regs + REG0); | ||
715 | 720 | ||
716 | /*spin_unlock(&dbri->lock); */ | 721 | dbri->cmdptr = cmd; |
722 | spin_unlock(&dbri->cmdlock); | ||
717 | } | 723 | } |
718 | 724 | ||
719 | /* Lock must be held when calling this */ | 725 | /* Lock must be held when calling this */ |
720 | static void dbri_reset(struct snd_dbri * dbri) | 726 | static void dbri_reset(struct snd_dbri * dbri) |
721 | { | 727 | { |
722 | int i; | 728 | int i; |
729 | u32 tmp; | ||
723 | 730 | ||
724 | dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n", | 731 | dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n", |
725 | sbus_readl(dbri->regs + REG0), | 732 | sbus_readl(dbri->regs + REG0), |
@@ -729,13 +736,20 @@ static void dbri_reset(struct snd_dbri * dbri) | |||
729 | sbus_writel(D_R, dbri->regs + REG0); /* Soft Reset */ | 736 | sbus_writel(D_R, dbri->regs + REG0); /* Soft Reset */ |
730 | for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++) | 737 | for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++) |
731 | udelay(10); | 738 | udelay(10); |
739 | |||
740 | /* A brute approach - DBRI falls back to working burst size by itself | ||
741 | * On SS20 D_S does not work, so do not try so high. */ | ||
742 | tmp = sbus_readl(dbri->regs + REG0); | ||
743 | tmp |= D_G | D_E; | ||
744 | tmp &= ~D_S; | ||
745 | sbus_writel(tmp, dbri->regs + REG0); | ||
732 | } | 746 | } |
733 | 747 | ||
734 | /* Lock must not be held before calling this */ | 748 | /* Lock must not be held before calling this */ |
735 | static void dbri_initialize(struct snd_dbri * dbri) | 749 | static void dbri_initialize(struct snd_dbri * dbri) |
736 | { | 750 | { |
737 | volatile s32 *cmd; | 751 | s32 *cmd; |
738 | u32 dma_addr, tmp; | 752 | u32 dma_addr; |
739 | unsigned long flags; | 753 | unsigned long flags; |
740 | int n; | 754 | int n; |
741 | 755 | ||
@@ -743,42 +757,34 @@ static void dbri_initialize(struct snd_dbri * dbri) | |||
743 | 757 | ||
744 | dbri_reset(dbri); | 758 | dbri_reset(dbri); |
745 | 759 | ||
746 | cmd = dbri_cmdlock(dbri, NoGetLock); | 760 | /* Initialize pipes */ |
747 | dprintk(D_GEN, "init: cmd: %p, int: %p\n", | 761 | for (n = 0; n < DBRI_NO_PIPES; n++) |
748 | &dbri->dma->cmd[0], &dbri->dma->intr[0]); | 762 | dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; |
749 | 763 | ||
764 | spin_lock_init(&dbri->cmdlock); | ||
750 | /* | 765 | /* |
751 | * Initialize the interrupt ringbuffer. | 766 | * Initialize the interrupt ringbuffer. |
752 | */ | 767 | */ |
753 | for (n = 0; n < DBRI_NO_INTS - 1; n++) { | ||
754 | dma_addr = dbri->dma_dvma; | ||
755 | dma_addr += dbri_dma_off(intr, ((n + 1) & DBRI_INT_BLK)); | ||
756 | dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr; | ||
757 | } | ||
758 | dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); | 768 | dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); |
759 | dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr; | 769 | dbri->dma->intr[0] = dma_addr; |
760 | dbri->dbri_irqp = 1; | 770 | dbri->dbri_irqp = 1; |
761 | |||
762 | /* Initialize pipes */ | ||
763 | for (n = 0; n < DBRI_NO_PIPES; n++) | ||
764 | dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; | ||
765 | |||
766 | /* A brute approach - DBRI falls back to working burst size by itself | ||
767 | * On SS20 D_S does not work, so do not try so high. */ | ||
768 | tmp = sbus_readl(dbri->regs + REG0); | ||
769 | tmp |= D_G | D_E; | ||
770 | tmp &= ~D_S; | ||
771 | sbus_writel(tmp, dbri->regs + REG0); | ||
772 | |||
773 | /* | 771 | /* |
774 | * Set up the interrupt queue | 772 | * Set up the interrupt queue |
775 | */ | 773 | */ |
776 | dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); | 774 | spin_lock(&dbri->cmdlock); |
775 | cmd = dbri->cmdptr = dbri->dma->cmd; | ||
777 | *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); | 776 | *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); |
778 | *(cmd++) = dma_addr; | 777 | *(cmd++) = dma_addr; |
778 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
779 | dbri->cmdptr = cmd; | ||
780 | *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); | ||
781 | *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); | ||
782 | dma_addr = dbri->dma_dvma + dbri_dma_off(cmd, 0); | ||
783 | sbus_writel(dma_addr, dbri->regs + REG8); | ||
784 | spin_unlock(&dbri->cmdlock); | ||
779 | 785 | ||
780 | dbri_cmdsend(dbri, cmd); | ||
781 | spin_unlock_irqrestore(&dbri->lock, flags); | 786 | spin_unlock_irqrestore(&dbri->lock, flags); |
787 | dbri_cmdwait(dbri); | ||
782 | } | 788 | } |
783 | 789 | ||
784 | /* | 790 | /* |
@@ -809,9 +815,9 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe) | |||
809 | { | 815 | { |
810 | int sdp; | 816 | int sdp; |
811 | int desc; | 817 | int desc; |
812 | volatile int *cmd; | 818 | s32 *cmd; |
813 | 819 | ||
814 | if (pipe < 0 || pipe > 31) { | 820 | if (pipe < 0 || pipe > DBRI_MAX_PIPE) { |
815 | printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); | 821 | printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); |
816 | return; | 822 | return; |
817 | } | 823 | } |
@@ -822,25 +828,29 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe) | |||
822 | return; | 828 | return; |
823 | } | 829 | } |
824 | 830 | ||
825 | cmd = dbri_cmdlock(dbri, NoGetLock); | 831 | cmd = dbri_cmdlock(dbri, 3); |
826 | *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P); | 832 | *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P); |
827 | *(cmd++) = 0; | 833 | *(cmd++) = 0; |
828 | dbri_cmdsend(dbri, cmd); | 834 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
835 | dbri_cmdsend(dbri, cmd, 3); | ||
829 | 836 | ||
830 | desc = dbri->pipes[pipe].first_desc; | 837 | desc = dbri->pipes[pipe].first_desc; |
831 | while (desc != -1) { | 838 | if ( desc >= 0) |
832 | dbri->descs[desc].inuse = 0; | 839 | do { |
833 | desc = dbri->descs[desc].next; | 840 | dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; |
834 | } | 841 | desc = dbri->next_desc[desc]; |
842 | } while (desc != -1 && desc != dbri->pipes[pipe].first_desc); | ||
835 | 843 | ||
836 | dbri->pipes[pipe].desc = -1; | 844 | dbri->pipes[pipe].desc = -1; |
837 | dbri->pipes[pipe].first_desc = -1; | 845 | dbri->pipes[pipe].first_desc = -1; |
838 | } | 846 | } |
839 | 847 | ||
840 | /* FIXME: direction as an argument? */ | 848 | /* |
849 | * Lock must be held before calling this. | ||
850 | */ | ||
841 | static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) | 851 | static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) |
842 | { | 852 | { |
843 | if (pipe < 0 || pipe > 31) { | 853 | if (pipe < 0 || pipe > DBRI_MAX_PIPE) { |
844 | printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n"); | 854 | printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n"); |
845 | return; | 855 | return; |
846 | } | 856 | } |
@@ -860,119 +870,87 @@ static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) | |||
860 | dbri->pipes[pipe].sdp = sdp; | 870 | dbri->pipes[pipe].sdp = sdp; |
861 | dbri->pipes[pipe].desc = -1; | 871 | dbri->pipes[pipe].desc = -1; |
862 | dbri->pipes[pipe].first_desc = -1; | 872 | dbri->pipes[pipe].first_desc = -1; |
863 | if (sdp & D_SDP_TO_SER) | ||
864 | dbri->pipes[pipe].direction = PIPEoutput; | ||
865 | else | ||
866 | dbri->pipes[pipe].direction = PIPEinput; | ||
867 | 873 | ||
868 | reset_pipe(dbri, pipe); | 874 | reset_pipe(dbri, pipe); |
869 | } | 875 | } |
870 | 876 | ||
871 | /* FIXME: direction not needed */ | 877 | /* |
878 | * Lock must be held before calling this. | ||
879 | */ | ||
872 | static void link_time_slot(struct snd_dbri * dbri, int pipe, | 880 | static void link_time_slot(struct snd_dbri * dbri, int pipe, |
873 | enum in_or_out direction, int basepipe, | 881 | int prevpipe, int nextpipe, |
874 | int length, int cycle) | 882 | int length, int cycle) |
875 | { | 883 | { |
876 | volatile s32 *cmd; | 884 | s32 *cmd; |
877 | int val; | 885 | int val; |
878 | int prevpipe; | ||
879 | int nextpipe; | ||
880 | 886 | ||
881 | if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) { | 887 | if (pipe < 0 || pipe > DBRI_MAX_PIPE |
888 | || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE | ||
889 | || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { | ||
882 | printk(KERN_ERR | 890 | printk(KERN_ERR |
883 | "DBRI: link_time_slot called with illegal pipe number\n"); | 891 | "DBRI: link_time_slot called with illegal pipe number\n"); |
884 | return; | 892 | return; |
885 | } | 893 | } |
886 | 894 | ||
887 | if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) { | 895 | if (dbri->pipes[pipe].sdp == 0 |
896 | || dbri->pipes[prevpipe].sdp == 0 | ||
897 | || dbri->pipes[nextpipe].sdp == 0) { | ||
888 | printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n"); | 898 | printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n"); |
889 | return; | 899 | return; |
890 | } | 900 | } |
891 | 901 | ||
892 | /* Deal with CHI special case: | 902 | dbri->pipes[prevpipe].nextpipe = pipe; |
893 | * "If transmission on edges 0 or 1 is desired, then cycle n | ||
894 | * (where n = # of bit times per frame...) must be used." | ||
895 | * - DBRI data sheet, page 11 | ||
896 | */ | ||
897 | if (basepipe == 16 && direction == PIPEoutput && cycle == 0) | ||
898 | cycle = dbri->chi_bpf; | ||
899 | |||
900 | if (basepipe == pipe) { | ||
901 | prevpipe = pipe; | ||
902 | nextpipe = pipe; | ||
903 | } else { | ||
904 | /* We're not initializing a new linked list (basepipe != pipe), | ||
905 | * so run through the linked list and find where this pipe | ||
906 | * should be sloted in, based on its cycle. CHI confuses | ||
907 | * things a bit, since it has a single anchor for both its | ||
908 | * transmit and receive lists. | ||
909 | */ | ||
910 | if (basepipe == 16) { | ||
911 | if (direction == PIPEinput) { | ||
912 | prevpipe = dbri->chi_in_pipe; | ||
913 | } else { | ||
914 | prevpipe = dbri->chi_out_pipe; | ||
915 | } | ||
916 | } else { | ||
917 | prevpipe = basepipe; | ||
918 | } | ||
919 | |||
920 | nextpipe = dbri->pipes[prevpipe].nextpipe; | ||
921 | |||
922 | while (dbri->pipes[nextpipe].cycle < cycle | ||
923 | && dbri->pipes[nextpipe].nextpipe != basepipe) { | ||
924 | prevpipe = nextpipe; | ||
925 | nextpipe = dbri->pipes[nextpipe].nextpipe; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | if (prevpipe == 16) { | ||
930 | if (direction == PIPEinput) { | ||
931 | dbri->chi_in_pipe = pipe; | ||
932 | } else { | ||
933 | dbri->chi_out_pipe = pipe; | ||
934 | } | ||
935 | } else { | ||
936 | dbri->pipes[prevpipe].nextpipe = pipe; | ||
937 | } | ||
938 | |||
939 | dbri->pipes[pipe].nextpipe = nextpipe; | 903 | dbri->pipes[pipe].nextpipe = nextpipe; |
940 | dbri->pipes[pipe].cycle = cycle; | ||
941 | dbri->pipes[pipe].length = length; | 904 | dbri->pipes[pipe].length = length; |
942 | 905 | ||
943 | cmd = dbri_cmdlock(dbri, NoGetLock); | 906 | cmd = dbri_cmdlock(dbri, 4); |
944 | 907 | ||
945 | if (direction == PIPEinput) { | 908 | if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { |
946 | val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe; | 909 | /* Deal with CHI special case: |
910 | * "If transmission on edges 0 or 1 is desired, then cycle n | ||
911 | * (where n = # of bit times per frame...) must be used." | ||
912 | * - DBRI data sheet, page 11 | ||
913 | */ | ||
914 | if (prevpipe == 16 && cycle == 0) | ||
915 | cycle = dbri->chi_bpf; | ||
916 | |||
917 | val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe; | ||
947 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | 918 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); |
919 | *(cmd++) = 0; | ||
948 | *(cmd++) = | 920 | *(cmd++) = |
949 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); | 921 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); |
950 | *(cmd++) = 0; | ||
951 | } else { | 922 | } else { |
952 | val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe; | 923 | val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe; |
953 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | 924 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); |
954 | *(cmd++) = 0; | ||
955 | *(cmd++) = | 925 | *(cmd++) = |
956 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); | 926 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); |
927 | *(cmd++) = 0; | ||
957 | } | 928 | } |
929 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
958 | 930 | ||
959 | dbri_cmdsend(dbri, cmd); | 931 | dbri_cmdsend(dbri, cmd, 4); |
960 | } | 932 | } |
961 | 933 | ||
934 | #if 0 | ||
935 | /* | ||
936 | * Lock must be held before calling this. | ||
937 | */ | ||
962 | static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | 938 | static void unlink_time_slot(struct snd_dbri * dbri, int pipe, |
963 | enum in_or_out direction, int prevpipe, | 939 | enum in_or_out direction, int prevpipe, |
964 | int nextpipe) | 940 | int nextpipe) |
965 | { | 941 | { |
966 | volatile s32 *cmd; | 942 | s32 *cmd; |
967 | int val; | 943 | int val; |
968 | 944 | ||
969 | if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) { | 945 | if (pipe < 0 || pipe > DBRI_MAX_PIPE |
946 | || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE | ||
947 | || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { | ||
970 | printk(KERN_ERR | 948 | printk(KERN_ERR |
971 | "DBRI: unlink_time_slot called with illegal pipe number\n"); | 949 | "DBRI: unlink_time_slot called with illegal pipe number\n"); |
972 | return; | 950 | return; |
973 | } | 951 | } |
974 | 952 | ||
975 | cmd = dbri_cmdlock(dbri, NoGetLock); | 953 | cmd = dbri_cmdlock(dbri, 4); |
976 | 954 | ||
977 | if (direction == PIPEinput) { | 955 | if (direction == PIPEinput) { |
978 | val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe; | 956 | val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe; |
@@ -985,9 +963,11 @@ static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | |||
985 | *(cmd++) = 0; | 963 | *(cmd++) = 0; |
986 | *(cmd++) = D_TS_NEXT(nextpipe); | 964 | *(cmd++) = D_TS_NEXT(nextpipe); |
987 | } | 965 | } |
966 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
988 | 967 | ||
989 | dbri_cmdsend(dbri, cmd); | 968 | dbri_cmdsend(dbri, cmd, 4); |
990 | } | 969 | } |
970 | #endif | ||
991 | 971 | ||
992 | /* xmit_fixed() / recv_fixed() | 972 | /* xmit_fixed() / recv_fixed() |
993 | * | 973 | * |
@@ -1001,13 +981,16 @@ static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | |||
1001 | * the actual time slot is. The interrupt handler takes care of bit | 981 | * the actual time slot is. The interrupt handler takes care of bit |
1002 | * ordering and alignment. An 8-bit time slot will always end up | 982 | * ordering and alignment. An 8-bit time slot will always end up |
1003 | * in the low-order 8 bits, filled either MSB-first or LSB-first, | 983 | * in the low-order 8 bits, filled either MSB-first or LSB-first, |
1004 | * depending on the settings passed to setup_pipe() | 984 | * depending on the settings passed to setup_pipe(). |
985 | * | ||
986 | * Lock must not be held before calling it. | ||
1005 | */ | 987 | */ |
1006 | static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) | 988 | static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) |
1007 | { | 989 | { |
1008 | volatile s32 *cmd; | 990 | s32 *cmd; |
991 | unsigned long flags; | ||
1009 | 992 | ||
1010 | if (pipe < 16 || pipe > 31) { | 993 | if (pipe < 16 || pipe > DBRI_MAX_PIPE) { |
1011 | printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); | 994 | printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); |
1012 | return; | 995 | return; |
1013 | } | 996 | } |
@@ -1032,17 +1015,22 @@ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) | |||
1032 | if (dbri->pipes[pipe].sdp & D_SDP_MSB) | 1015 | if (dbri->pipes[pipe].sdp & D_SDP_MSB) |
1033 | data = reverse_bytes(data, dbri->pipes[pipe].length); | 1016 | data = reverse_bytes(data, dbri->pipes[pipe].length); |
1034 | 1017 | ||
1035 | cmd = dbri_cmdlock(dbri, GetLock); | 1018 | cmd = dbri_cmdlock(dbri, 3); |
1036 | 1019 | ||
1037 | *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); | 1020 | *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); |
1038 | *(cmd++) = data; | 1021 | *(cmd++) = data; |
1022 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
1023 | |||
1024 | spin_lock_irqsave(&dbri->lock, flags); | ||
1025 | dbri_cmdsend(dbri, cmd, 3); | ||
1026 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1027 | dbri_cmdwait(dbri); | ||
1039 | 1028 | ||
1040 | dbri_cmdsend(dbri, cmd); | ||
1041 | } | 1029 | } |
1042 | 1030 | ||
1043 | static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) | 1031 | static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) |
1044 | { | 1032 | { |
1045 | if (pipe < 16 || pipe > 31) { | 1033 | if (pipe < 16 || pipe > DBRI_MAX_PIPE) { |
1046 | printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n"); | 1034 | printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n"); |
1047 | return; | 1035 | return; |
1048 | } | 1036 | } |
@@ -1071,12 +1059,16 @@ static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) | |||
1071 | * and work by building chains of descriptors which identify the | 1059 | * and work by building chains of descriptors which identify the |
1072 | * data buffers. Buffers too large for a single descriptor will | 1060 | * data buffers. Buffers too large for a single descriptor will |
1073 | * be spread across multiple descriptors. | 1061 | * be spread across multiple descriptors. |
1062 | * | ||
1063 | * All descriptors create a ring buffer. | ||
1064 | * | ||
1065 | * Lock must be held before calling this. | ||
1074 | */ | 1066 | */ |
1075 | static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) | 1067 | static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) |
1076 | { | 1068 | { |
1077 | struct dbri_streaminfo *info = &dbri->stream_info[streamno]; | 1069 | struct dbri_streaminfo *info = &dbri->stream_info[streamno]; |
1078 | __u32 dvma_buffer; | 1070 | __u32 dvma_buffer; |
1079 | int desc = 0; | 1071 | int desc; |
1080 | int len; | 1072 | int len; |
1081 | int first_desc = -1; | 1073 | int first_desc = -1; |
1082 | int last_desc = -1; | 1074 | int last_desc = -1; |
@@ -1119,11 +1111,23 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1119 | len &= ~3; | 1111 | len &= ~3; |
1120 | } | 1112 | } |
1121 | 1113 | ||
1114 | /* Free descriptors if pipe has any */ | ||
1115 | desc = dbri->pipes[info->pipe].first_desc; | ||
1116 | if ( desc >= 0) | ||
1117 | do { | ||
1118 | dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; | ||
1119 | desc = dbri->next_desc[desc]; | ||
1120 | } while (desc != -1 && desc != dbri->pipes[info->pipe].first_desc); | ||
1121 | |||
1122 | dbri->pipes[info->pipe].desc = -1; | ||
1123 | dbri->pipes[info->pipe].first_desc = -1; | ||
1124 | |||
1125 | desc = 0; | ||
1122 | while (len > 0) { | 1126 | while (len > 0) { |
1123 | int mylen; | 1127 | int mylen; |
1124 | 1128 | ||
1125 | for (; desc < DBRI_NO_DESCS; desc++) { | 1129 | for (; desc < DBRI_NO_DESCS; desc++) { |
1126 | if (!dbri->descs[desc].inuse) | 1130 | if (!dbri->dma->desc[desc].ba) |
1127 | break; | 1131 | break; |
1128 | } | 1132 | } |
1129 | if (desc == DBRI_NO_DESCS) { | 1133 | if (desc == DBRI_NO_DESCS) { |
@@ -1131,37 +1135,33 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1131 | return -1; | 1135 | return -1; |
1132 | } | 1136 | } |
1133 | 1137 | ||
1134 | if (len > DBRI_TD_MAXCNT) { | 1138 | if (len > DBRI_TD_MAXCNT) |
1135 | mylen = DBRI_TD_MAXCNT; /* 8KB - 1 */ | 1139 | mylen = DBRI_TD_MAXCNT; /* 8KB - 4 */ |
1136 | } else { | 1140 | else |
1137 | mylen = len; | 1141 | mylen = len; |
1138 | } | 1142 | |
1139 | if (mylen > period) { | 1143 | if (mylen > period) |
1140 | mylen = period; | 1144 | mylen = period; |
1141 | } | ||
1142 | 1145 | ||
1143 | dbri->descs[desc].inuse = 1; | 1146 | dbri->next_desc[desc] = -1; |
1144 | dbri->descs[desc].next = -1; | ||
1145 | dbri->dma->desc[desc].ba = dvma_buffer; | 1147 | dbri->dma->desc[desc].ba = dvma_buffer; |
1146 | dbri->dma->desc[desc].nda = 0; | 1148 | dbri->dma->desc[desc].nda = 0; |
1147 | 1149 | ||
1148 | if (streamno == DBRI_PLAY) { | 1150 | if (streamno == DBRI_PLAY) { |
1149 | dbri->descs[desc].len = mylen; | ||
1150 | dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); | 1151 | dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); |
1151 | dbri->dma->desc[desc].word4 = 0; | 1152 | dbri->dma->desc[desc].word4 = 0; |
1152 | if (first_desc != -1) | 1153 | dbri->dma->desc[desc].word1 |= |
1153 | dbri->dma->desc[desc].word1 |= DBRI_TD_M; | 1154 | DBRI_TD_F | DBRI_TD_B; |
1154 | } else { | 1155 | } else { |
1155 | dbri->descs[desc].len = 0; | ||
1156 | dbri->dma->desc[desc].word1 = 0; | 1156 | dbri->dma->desc[desc].word1 = 0; |
1157 | dbri->dma->desc[desc].word4 = | 1157 | dbri->dma->desc[desc].word4 = |
1158 | DBRI_RD_B | DBRI_RD_BCNT(mylen); | 1158 | DBRI_RD_B | DBRI_RD_BCNT(mylen); |
1159 | } | 1159 | } |
1160 | 1160 | ||
1161 | if (first_desc == -1) { | 1161 | if (first_desc == -1) |
1162 | first_desc = desc; | 1162 | first_desc = desc; |
1163 | } else { | 1163 | else { |
1164 | dbri->descs[last_desc].next = desc; | 1164 | dbri->next_desc[last_desc] = desc; |
1165 | dbri->dma->desc[last_desc].nda = | 1165 | dbri->dma->desc[last_desc].nda = |
1166 | dbri->dma_dvma + dbri_dma_off(desc, desc); | 1166 | dbri->dma_dvma + dbri_dma_off(desc, desc); |
1167 | } | 1167 | } |
@@ -1176,21 +1176,24 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1176 | return -1; | 1176 | return -1; |
1177 | } | 1177 | } |
1178 | 1178 | ||
1179 | dbri->dma->desc[last_desc].word1 &= ~DBRI_TD_M; | 1179 | dbri->dma->desc[last_desc].nda = |
1180 | if (streamno == DBRI_PLAY) { | 1180 | dbri->dma_dvma + dbri_dma_off(desc, first_desc); |
1181 | dbri->dma->desc[last_desc].word1 |= | 1181 | dbri->next_desc[last_desc] = first_desc; |
1182 | DBRI_TD_I | DBRI_TD_F | DBRI_TD_B; | ||
1183 | } | ||
1184 | dbri->pipes[info->pipe].first_desc = first_desc; | 1182 | dbri->pipes[info->pipe].first_desc = first_desc; |
1185 | dbri->pipes[info->pipe].desc = first_desc; | 1183 | dbri->pipes[info->pipe].desc = first_desc; |
1186 | 1184 | ||
1187 | for (desc = first_desc; desc != -1; desc = dbri->descs[desc].next) { | 1185 | #ifdef DBRI_DEBUG |
1186 | for (desc = first_desc; desc != -1; ) { | ||
1188 | dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", | 1187 | dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", |
1189 | desc, | 1188 | desc, |
1190 | dbri->dma->desc[desc].word1, | 1189 | dbri->dma->desc[desc].word1, |
1191 | dbri->dma->desc[desc].ba, | 1190 | dbri->dma->desc[desc].ba, |
1192 | dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); | 1191 | dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); |
1192 | desc = dbri->next_desc[desc]; | ||
1193 | if ( desc == first_desc ) | ||
1194 | break; | ||
1193 | } | 1195 | } |
1196 | #endif | ||
1194 | return 0; | 1197 | return 0; |
1195 | } | 1198 | } |
1196 | 1199 | ||
@@ -1207,56 +1210,30 @@ multiplexed serial interface which the DBRI can operate in either master | |||
1207 | 1210 | ||
1208 | enum master_or_slave { CHImaster, CHIslave }; | 1211 | enum master_or_slave { CHImaster, CHIslave }; |
1209 | 1212 | ||
1213 | /* | ||
1214 | * Lock must not be held before calling it. | ||
1215 | */ | ||
1210 | static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, | 1216 | static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, |
1211 | int bits_per_frame) | 1217 | int bits_per_frame) |
1212 | { | 1218 | { |
1213 | volatile s32 *cmd; | 1219 | s32 *cmd; |
1214 | int val; | 1220 | int val; |
1215 | static int chi_initialized = 0; /* FIXME: mutex? */ | ||
1216 | |||
1217 | if (!chi_initialized) { | ||
1218 | |||
1219 | cmd = dbri_cmdlock(dbri, GetLock); | ||
1220 | |||
1221 | /* Set CHI Anchor: Pipe 16 */ | ||
1222 | |||
1223 | val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16); | ||
1224 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | ||
1225 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); | ||
1226 | *(cmd++) = 0; | ||
1227 | |||
1228 | val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16); | ||
1229 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | ||
1230 | *(cmd++) = 0; | ||
1231 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); | ||
1232 | 1221 | ||
1233 | dbri->pipes[16].sdp = 1; | 1222 | /* Set CHI Anchor: Pipe 16 */ |
1234 | dbri->pipes[16].nextpipe = 16; | ||
1235 | dbri->chi_in_pipe = 16; | ||
1236 | dbri->chi_out_pipe = 16; | ||
1237 | |||
1238 | #if 0 | ||
1239 | chi_initialized++; | ||
1240 | #endif | ||
1241 | } else { | ||
1242 | int pipe; | ||
1243 | 1223 | ||
1244 | for (pipe = dbri->chi_in_pipe; | 1224 | cmd = dbri_cmdlock(dbri, 4); |
1245 | pipe != 16; pipe = dbri->pipes[pipe].nextpipe) { | 1225 | val = D_DTS_VO | D_DTS_VI | D_DTS_INS |
1246 | unlink_time_slot(dbri, pipe, PIPEinput, | 1226 | | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16); |
1247 | 16, dbri->pipes[pipe].nextpipe); | 1227 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); |
1248 | } | 1228 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); |
1249 | for (pipe = dbri->chi_out_pipe; | 1229 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); |
1250 | pipe != 16; pipe = dbri->pipes[pipe].nextpipe) { | 1230 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
1251 | unlink_time_slot(dbri, pipe, PIPEoutput, | 1231 | dbri_cmdsend(dbri, cmd, 4); |
1252 | 16, dbri->pipes[pipe].nextpipe); | ||
1253 | } | ||
1254 | 1232 | ||
1255 | dbri->chi_in_pipe = 16; | 1233 | dbri->pipes[16].sdp = 1; |
1256 | dbri->chi_out_pipe = 16; | 1234 | dbri->pipes[16].nextpipe = 16; |
1257 | 1235 | ||
1258 | cmd = dbri_cmdlock(dbri, GetLock); | 1236 | cmd = dbri_cmdlock(dbri, 4); |
1259 | } | ||
1260 | 1237 | ||
1261 | if (master_or_slave == CHIslave) { | 1238 | if (master_or_slave == CHIslave) { |
1262 | /* Setup DBRI for CHI Slave - receive clock, frame sync (FS) | 1239 | /* Setup DBRI for CHI Slave - receive clock, frame sync (FS) |
@@ -1295,8 +1272,9 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla | |||
1295 | 1272 | ||
1296 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | 1273 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
1297 | *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN); | 1274 | *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN); |
1275 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
1298 | 1276 | ||
1299 | dbri_cmdsend(dbri, cmd); | 1277 | dbri_cmdsend(dbri, cmd, 4); |
1300 | } | 1278 | } |
1301 | 1279 | ||
1302 | /* | 1280 | /* |
@@ -1307,9 +1285,14 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla | |||
1307 | In the standard SPARC audio configuration, the CS4215 codec is attached | 1285 | In the standard SPARC audio configuration, the CS4215 codec is attached |
1308 | to the DBRI via the CHI interface and few of the DBRI's PIO pins. | 1286 | to the DBRI via the CHI interface and few of the DBRI's PIO pins. |
1309 | 1287 | ||
1288 | * Lock must not be held before calling it. | ||
1289 | |||
1310 | */ | 1290 | */ |
1311 | static void cs4215_setup_pipes(struct snd_dbri * dbri) | 1291 | static void cs4215_setup_pipes(struct snd_dbri * dbri) |
1312 | { | 1292 | { |
1293 | unsigned long flags; | ||
1294 | |||
1295 | spin_lock_irqsave(&dbri->lock, flags); | ||
1313 | /* | 1296 | /* |
1314 | * Data mode: | 1297 | * Data mode: |
1315 | * Pipe 4: Send timeslots 1-4 (audio data) | 1298 | * Pipe 4: Send timeslots 1-4 (audio data) |
@@ -1333,6 +1316,9 @@ static void cs4215_setup_pipes(struct snd_dbri * dbri) | |||
1333 | setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); | 1316 | setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); |
1334 | setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); | 1317 | setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); |
1335 | setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); | 1318 | setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); |
1319 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1320 | |||
1321 | dbri_cmdwait(dbri); | ||
1336 | } | 1322 | } |
1337 | 1323 | ||
1338 | static int cs4215_init_data(struct cs4215 *mm) | 1324 | static int cs4215_init_data(struct cs4215 *mm) |
@@ -1364,7 +1350,7 @@ static int cs4215_init_data(struct cs4215 *mm) | |||
1364 | mm->status = 0; | 1350 | mm->status = 0; |
1365 | mm->version = 0xff; | 1351 | mm->version = 0xff; |
1366 | mm->precision = 8; /* For ULAW */ | 1352 | mm->precision = 8; /* For ULAW */ |
1367 | mm->channels = 2; | 1353 | mm->channels = 1; |
1368 | 1354 | ||
1369 | return 0; | 1355 | return 0; |
1370 | } | 1356 | } |
@@ -1379,16 +1365,8 @@ static void cs4215_setdata(struct snd_dbri * dbri, int muted) | |||
1379 | } else { | 1365 | } else { |
1380 | /* Start by setting the playback attenuation. */ | 1366 | /* Start by setting the playback attenuation. */ |
1381 | struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY]; | 1367 | struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY]; |
1382 | int left_gain = info->left_gain % 64; | 1368 | int left_gain = info->left_gain & 0x3f; |
1383 | int right_gain = info->right_gain % 64; | 1369 | int right_gain = info->right_gain & 0x3f; |
1384 | |||
1385 | if (info->balance < DBRI_MID_BALANCE) { | ||
1386 | right_gain *= info->balance; | ||
1387 | right_gain /= DBRI_MID_BALANCE; | ||
1388 | } else { | ||
1389 | left_gain *= DBRI_RIGHT_BALANCE - info->balance; | ||
1390 | left_gain /= DBRI_MID_BALANCE; | ||
1391 | } | ||
1392 | 1370 | ||
1393 | dbri->mm.data[0] &= ~0x3f; /* Reset the volume bits */ | 1371 | dbri->mm.data[0] &= ~0x3f; /* Reset the volume bits */ |
1394 | dbri->mm.data[1] &= ~0x3f; | 1372 | dbri->mm.data[1] &= ~0x3f; |
@@ -1397,8 +1375,8 @@ static void cs4215_setdata(struct snd_dbri * dbri, int muted) | |||
1397 | 1375 | ||
1398 | /* Now set the recording gain. */ | 1376 | /* Now set the recording gain. */ |
1399 | info = &dbri->stream_info[DBRI_REC]; | 1377 | info = &dbri->stream_info[DBRI_REC]; |
1400 | left_gain = info->left_gain % 16; | 1378 | left_gain = info->left_gain & 0xf; |
1401 | right_gain = info->right_gain % 16; | 1379 | right_gain = info->right_gain & 0xf; |
1402 | dbri->mm.data[2] |= CS4215_LG(left_gain); | 1380 | dbri->mm.data[2] |= CS4215_LG(left_gain); |
1403 | dbri->mm.data[3] |= CS4215_RG(right_gain); | 1381 | dbri->mm.data[3] |= CS4215_RG(right_gain); |
1404 | } | 1382 | } |
@@ -1413,6 +1391,7 @@ static void cs4215_open(struct snd_dbri * dbri) | |||
1413 | { | 1391 | { |
1414 | int data_width; | 1392 | int data_width; |
1415 | u32 tmp; | 1393 | u32 tmp; |
1394 | unsigned long flags; | ||
1416 | 1395 | ||
1417 | dprintk(D_MM, "cs4215_open: %d channels, %d bits\n", | 1396 | dprintk(D_MM, "cs4215_open: %d channels, %d bits\n", |
1418 | dbri->mm.channels, dbri->mm.precision); | 1397 | dbri->mm.channels, dbri->mm.precision); |
@@ -1437,6 +1416,7 @@ static void cs4215_open(struct snd_dbri * dbri) | |||
1437 | * bits. The CS4215, it seems, observes TSIN (the delayed signal) | 1416 | * bits. The CS4215, it seems, observes TSIN (the delayed signal) |
1438 | * even if it's the CHI master. Don't ask me... | 1417 | * even if it's the CHI master. Don't ask me... |
1439 | */ | 1418 | */ |
1419 | spin_lock_irqsave(&dbri->lock, flags); | ||
1440 | tmp = sbus_readl(dbri->regs + REG0); | 1420 | tmp = sbus_readl(dbri->regs + REG0); |
1441 | tmp &= ~(D_C); /* Disable CHI */ | 1421 | tmp &= ~(D_C); /* Disable CHI */ |
1442 | sbus_writel(tmp, dbri->regs + REG0); | 1422 | sbus_writel(tmp, dbri->regs + REG0); |
@@ -1455,15 +1435,16 @@ static void cs4215_open(struct snd_dbri * dbri) | |||
1455 | */ | 1435 | */ |
1456 | data_width = dbri->mm.channels * dbri->mm.precision; | 1436 | data_width = dbri->mm.channels * dbri->mm.precision; |
1457 | 1437 | ||
1458 | link_time_slot(dbri, 20, PIPEoutput, 16, 32, dbri->mm.offset + 32); | 1438 | link_time_slot(dbri, 4, 16, 16, data_width, dbri->mm.offset); |
1459 | link_time_slot(dbri, 4, PIPEoutput, 16, data_width, dbri->mm.offset); | 1439 | link_time_slot(dbri, 20, 4, 16, 32, dbri->mm.offset + 32); |
1460 | link_time_slot(dbri, 6, PIPEinput, 16, data_width, dbri->mm.offset); | 1440 | link_time_slot(dbri, 6, 16, 16, data_width, dbri->mm.offset); |
1461 | link_time_slot(dbri, 21, PIPEinput, 16, 16, dbri->mm.offset + 40); | 1441 | link_time_slot(dbri, 21, 6, 16, 16, dbri->mm.offset + 40); |
1462 | 1442 | ||
1463 | /* FIXME: enable CHI after _setdata? */ | 1443 | /* FIXME: enable CHI after _setdata? */ |
1464 | tmp = sbus_readl(dbri->regs + REG0); | 1444 | tmp = sbus_readl(dbri->regs + REG0); |
1465 | tmp |= D_C; /* Enable CHI */ | 1445 | tmp |= D_C; /* Enable CHI */ |
1466 | sbus_writel(tmp, dbri->regs + REG0); | 1446 | sbus_writel(tmp, dbri->regs + REG0); |
1447 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1467 | 1448 | ||
1468 | cs4215_setdata(dbri, 0); | 1449 | cs4215_setdata(dbri, 0); |
1469 | } | 1450 | } |
@@ -1475,6 +1456,7 @@ static int cs4215_setctrl(struct snd_dbri * dbri) | |||
1475 | { | 1456 | { |
1476 | int i, val; | 1457 | int i, val; |
1477 | u32 tmp; | 1458 | u32 tmp; |
1459 | unsigned long flags; | ||
1478 | 1460 | ||
1479 | /* FIXME - let the CPU do something useful during these delays */ | 1461 | /* FIXME - let the CPU do something useful during these delays */ |
1480 | 1462 | ||
@@ -1511,6 +1493,7 @@ static int cs4215_setctrl(struct snd_dbri * dbri) | |||
1511 | * done in hardware by a TI 248 that delays the DBRI->4215 | 1493 | * done in hardware by a TI 248 that delays the DBRI->4215 |
1512 | * frame sync signal by eight clock cycles. Anybody know why? | 1494 | * frame sync signal by eight clock cycles. Anybody know why? |
1513 | */ | 1495 | */ |
1496 | spin_lock_irqsave(&dbri->lock, flags); | ||
1514 | tmp = sbus_readl(dbri->regs + REG0); | 1497 | tmp = sbus_readl(dbri->regs + REG0); |
1515 | tmp &= ~D_C; /* Disable CHI */ | 1498 | tmp &= ~D_C; /* Disable CHI */ |
1516 | sbus_writel(tmp, dbri->regs + REG0); | 1499 | sbus_writel(tmp, dbri->regs + REG0); |
@@ -1524,17 +1507,20 @@ static int cs4215_setctrl(struct snd_dbri * dbri) | |||
1524 | * Pipe 19: Receive timeslot 7 (version). | 1507 | * Pipe 19: Receive timeslot 7 (version). |
1525 | */ | 1508 | */ |
1526 | 1509 | ||
1527 | link_time_slot(dbri, 17, PIPEoutput, 16, 32, dbri->mm.offset); | 1510 | link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset); |
1528 | link_time_slot(dbri, 18, PIPEinput, 16, 8, dbri->mm.offset); | 1511 | link_time_slot(dbri, 18, 16, 16, 8, dbri->mm.offset); |
1529 | link_time_slot(dbri, 19, PIPEinput, 16, 8, dbri->mm.offset + 48); | 1512 | link_time_slot(dbri, 19, 18, 16, 8, dbri->mm.offset + 48); |
1513 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1530 | 1514 | ||
1531 | /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */ | 1515 | /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */ |
1532 | dbri->mm.ctrl[0] &= ~CS4215_CLB; | 1516 | dbri->mm.ctrl[0] &= ~CS4215_CLB; |
1533 | xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); | 1517 | xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); |
1534 | 1518 | ||
1519 | spin_lock_irqsave(&dbri->lock, flags); | ||
1535 | tmp = sbus_readl(dbri->regs + REG0); | 1520 | tmp = sbus_readl(dbri->regs + REG0); |
1536 | tmp |= D_C; /* Enable CHI */ | 1521 | tmp |= D_C; /* Enable CHI */ |
1537 | sbus_writel(tmp, dbri->regs + REG0); | 1522 | sbus_writel(tmp, dbri->regs + REG0); |
1523 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1538 | 1524 | ||
1539 | for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) { | 1525 | for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) { |
1540 | msleep_interruptible(1); | 1526 | msleep_interruptible(1); |
@@ -1614,8 +1600,7 @@ static int cs4215_prepare(struct snd_dbri * dbri, unsigned int rate, | |||
1614 | CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal; | 1600 | CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal; |
1615 | 1601 | ||
1616 | dbri->mm.channels = channels; | 1602 | dbri->mm.channels = channels; |
1617 | /* Stereo bit: 8 bit stereo not working yet. */ | 1603 | if (channels == 2) |
1618 | if ((channels > 1) && (dbri->mm.precision == 16)) | ||
1619 | dbri->mm.ctrl[1] |= CS4215_DFR_STEREO; | 1604 | dbri->mm.ctrl[1] |= CS4215_DFR_STEREO; |
1620 | 1605 | ||
1621 | ret = cs4215_setctrl(dbri); | 1606 | ret = cs4215_setctrl(dbri); |
@@ -1655,7 +1640,6 @@ static int cs4215_init(struct snd_dbri * dbri) | |||
1655 | } | 1640 | } |
1656 | 1641 | ||
1657 | cs4215_setup_pipes(dbri); | 1642 | cs4215_setup_pipes(dbri); |
1658 | |||
1659 | cs4215_init_data(&dbri->mm); | 1643 | cs4215_init_data(&dbri->mm); |
1660 | 1644 | ||
1661 | /* Enable capture of the status & version timeslots. */ | 1645 | /* Enable capture of the status & version timeslots. */ |
@@ -1684,88 +1668,71 @@ buffer and calls dbri_process_one_interrupt() for each interrupt word. | |||
1684 | Complicated interrupts are handled by dedicated functions (which | 1668 | Complicated interrupts are handled by dedicated functions (which |
1685 | appear first in this file). Any pending interrupts can be serviced by | 1669 | appear first in this file). Any pending interrupts can be serviced by |
1686 | calling dbri_process_interrupt_buffer(), which works even if the CPU's | 1670 | calling dbri_process_interrupt_buffer(), which works even if the CPU's |
1687 | interrupts are disabled. This function is used by dbri_cmdlock() | 1671 | interrupts are disabled. |
1688 | to make sure we're synced up with the chip before each command sequence, | ||
1689 | even if we're running cli'ed. | ||
1690 | 1672 | ||
1691 | */ | 1673 | */ |
1692 | 1674 | ||
1693 | /* xmit_descs() | 1675 | /* xmit_descs() |
1694 | * | 1676 | * |
1695 | * Transmit the current TD's for recording/playing, if needed. | 1677 | * Starts transmiting the current TD's for recording/playing. |
1696 | * For playback, ALSA has filled the DMA memory with new data (we hope). | 1678 | * For playback, ALSA has filled the DMA memory with new data (we hope). |
1697 | */ | 1679 | */ |
1698 | static void xmit_descs(unsigned long data) | 1680 | static void xmit_descs(struct snd_dbri *dbri) |
1699 | { | 1681 | { |
1700 | struct snd_dbri *dbri = (struct snd_dbri *) data; | ||
1701 | struct dbri_streaminfo *info; | 1682 | struct dbri_streaminfo *info; |
1702 | volatile s32 *cmd; | 1683 | s32 *cmd; |
1703 | unsigned long flags; | 1684 | unsigned long flags; |
1704 | int first_td; | 1685 | int first_td; |
1705 | 1686 | ||
1706 | if (dbri == NULL) | 1687 | if (dbri == NULL) |
1707 | return; /* Disabled */ | 1688 | return; /* Disabled */ |
1708 | 1689 | ||
1709 | /* First check the recording stream for buffer overflow */ | ||
1710 | info = &dbri->stream_info[DBRI_REC]; | 1690 | info = &dbri->stream_info[DBRI_REC]; |
1711 | spin_lock_irqsave(&dbri->lock, flags); | 1691 | spin_lock_irqsave(&dbri->lock, flags); |
1712 | 1692 | ||
1713 | if ((info->left >= info->size) && (info->pipe >= 0)) { | 1693 | if (info->pipe >= 0) { |
1714 | first_td = dbri->pipes[info->pipe].first_desc; | 1694 | first_td = dbri->pipes[info->pipe].first_desc; |
1715 | 1695 | ||
1716 | dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td); | 1696 | dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td); |
1717 | 1697 | ||
1718 | /* Stream could be closed by the time we run. */ | 1698 | /* Stream could be closed by the time we run. */ |
1719 | if (first_td < 0) { | 1699 | if (first_td >= 0) { |
1720 | goto play; | 1700 | cmd = dbri_cmdlock(dbri, 2); |
1721 | } | 1701 | *(cmd++) = DBRI_CMD(D_SDP, 0, |
1722 | 1702 | dbri->pipes[info->pipe].sdp | |
1723 | cmd = dbri_cmdlock(dbri, NoGetLock); | 1703 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); |
1724 | *(cmd++) = DBRI_CMD(D_SDP, 0, | 1704 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); |
1725 | dbri->pipes[info->pipe].sdp | 1705 | dbri_cmdsend(dbri, cmd, 2); |
1726 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | ||
1727 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); | ||
1728 | dbri_cmdsend(dbri, cmd); | ||
1729 | 1706 | ||
1730 | /* Reset our admin of the pipe & bytes read. */ | 1707 | /* Reset our admin of the pipe. */ |
1731 | dbri->pipes[info->pipe].desc = first_td; | 1708 | dbri->pipes[info->pipe].desc = first_td; |
1732 | info->left = 0; | 1709 | } |
1733 | } | 1710 | } |
1734 | 1711 | ||
1735 | play: | ||
1736 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1737 | |||
1738 | /* Now check the playback stream for buffer underflow */ | ||
1739 | info = &dbri->stream_info[DBRI_PLAY]; | 1712 | info = &dbri->stream_info[DBRI_PLAY]; |
1740 | spin_lock_irqsave(&dbri->lock, flags); | ||
1741 | 1713 | ||
1742 | if ((info->left <= 0) && (info->pipe >= 0)) { | 1714 | if (info->pipe >= 0) { |
1743 | first_td = dbri->pipes[info->pipe].first_desc; | 1715 | first_td = dbri->pipes[info->pipe].first_desc; |
1744 | 1716 | ||
1745 | dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td); | 1717 | dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td); |
1746 | 1718 | ||
1747 | /* Stream could be closed by the time we run. */ | 1719 | /* Stream could be closed by the time we run. */ |
1748 | if (first_td < 0) { | 1720 | if (first_td >= 0) { |
1749 | spin_unlock_irqrestore(&dbri->lock, flags); | 1721 | cmd = dbri_cmdlock(dbri, 2); |
1750 | return; | 1722 | *(cmd++) = DBRI_CMD(D_SDP, 0, |
1751 | } | 1723 | dbri->pipes[info->pipe].sdp |
1752 | 1724 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | |
1753 | cmd = dbri_cmdlock(dbri, NoGetLock); | 1725 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); |
1754 | *(cmd++) = DBRI_CMD(D_SDP, 0, | 1726 | dbri_cmdsend(dbri, cmd, 2); |
1755 | dbri->pipes[info->pipe].sdp | ||
1756 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | ||
1757 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); | ||
1758 | dbri_cmdsend(dbri, cmd); | ||
1759 | 1727 | ||
1760 | /* Reset our admin of the pipe & bytes written. */ | 1728 | /* Reset our admin of the pipe. */ |
1761 | dbri->pipes[info->pipe].desc = first_td; | 1729 | dbri->pipes[info->pipe].desc = first_td; |
1762 | info->left = info->size; | 1730 | } |
1763 | } | 1731 | } |
1732 | |||
1764 | spin_unlock_irqrestore(&dbri->lock, flags); | 1733 | spin_unlock_irqrestore(&dbri->lock, flags); |
1765 | } | 1734 | } |
1766 | 1735 | ||
1767 | static DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); | ||
1768 | |||
1769 | /* transmission_complete_intr() | 1736 | /* transmission_complete_intr() |
1770 | * | 1737 | * |
1771 | * Called by main interrupt handler when DBRI signals transmission complete | 1738 | * Called by main interrupt handler when DBRI signals transmission complete |
@@ -1775,9 +1742,9 @@ static DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); | |||
1775 | * them as available. Stops when the first descriptor is found without | 1742 | * them as available. Stops when the first descriptor is found without |
1776 | * TBC (Transmit Buffer Complete) set, or we've run through them all. | 1743 | * TBC (Transmit Buffer Complete) set, or we've run through them all. |
1777 | * | 1744 | * |
1778 | * The DMA buffers are not released, but re-used. Since the transmit buffer | 1745 | * The DMA buffers are not released. They form a ring buffer and |
1779 | * descriptors are not clobbered, they can be re-submitted as is. This is | 1746 | * they are filled by ALSA while others are transmitted by DMA. |
1780 | * done by the xmit_descs() tasklet above since that could take longer. | 1747 | * |
1781 | */ | 1748 | */ |
1782 | 1749 | ||
1783 | static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) | 1750 | static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) |
@@ -1803,21 +1770,9 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1803 | dprintk(D_INT, "TD %d, status 0x%02x\n", td, status); | 1770 | dprintk(D_INT, "TD %d, status 0x%02x\n", td, status); |
1804 | 1771 | ||
1805 | dbri->dma->desc[td].word4 = 0; /* Reset it for next time. */ | 1772 | dbri->dma->desc[td].word4 = 0; /* Reset it for next time. */ |
1806 | info->offset += dbri->descs[td].len; | 1773 | info->offset += DBRI_RD_CNT(dbri->dma->desc[td].word1); |
1807 | info->left -= dbri->descs[td].len; | ||
1808 | |||
1809 | /* On the last TD, transmit them all again. */ | ||
1810 | if (dbri->descs[td].next == -1) { | ||
1811 | if (info->left > 0) { | ||
1812 | printk(KERN_WARNING | ||
1813 | "%d bytes left after last transfer.\n", | ||
1814 | info->left); | ||
1815 | info->left = 0; | ||
1816 | } | ||
1817 | tasklet_schedule(&xmit_descs_task); | ||
1818 | } | ||
1819 | 1774 | ||
1820 | td = dbri->descs[td].next; | 1775 | td = dbri->next_desc[td]; |
1821 | dbri->pipes[pipe].desc = td; | 1776 | dbri->pipes[pipe].desc = td; |
1822 | } | 1777 | } |
1823 | 1778 | ||
@@ -1841,30 +1796,18 @@ static void reception_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1841 | return; | 1796 | return; |
1842 | } | 1797 | } |
1843 | 1798 | ||
1844 | dbri->descs[rd].inuse = 0; | 1799 | dbri->pipes[pipe].desc = dbri->next_desc[rd]; |
1845 | dbri->pipes[pipe].desc = dbri->descs[rd].next; | ||
1846 | status = dbri->dma->desc[rd].word1; | 1800 | status = dbri->dma->desc[rd].word1; |
1847 | dbri->dma->desc[rd].word1 = 0; /* Reset it for next time. */ | 1801 | dbri->dma->desc[rd].word1 = 0; /* Reset it for next time. */ |
1848 | 1802 | ||
1849 | info = &dbri->stream_info[DBRI_REC]; | 1803 | info = &dbri->stream_info[DBRI_REC]; |
1850 | info->offset += DBRI_RD_CNT(status); | 1804 | info->offset += DBRI_RD_CNT(status); |
1851 | info->left += DBRI_RD_CNT(status); | ||
1852 | 1805 | ||
1853 | /* FIXME: Check status */ | 1806 | /* FIXME: Check status */ |
1854 | 1807 | ||
1855 | dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n", | 1808 | dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n", |
1856 | rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)); | 1809 | rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)); |
1857 | 1810 | ||
1858 | /* On the last TD, transmit them all again. */ | ||
1859 | if (dbri->descs[rd].next == -1) { | ||
1860 | if (info->left > info->size) { | ||
1861 | printk(KERN_WARNING | ||
1862 | "%d bytes recorded in %d size buffer.\n", | ||
1863 | info->left, info->size); | ||
1864 | } | ||
1865 | tasklet_schedule(&xmit_descs_task); | ||
1866 | } | ||
1867 | |||
1868 | /* Notify ALSA */ | 1811 | /* Notify ALSA */ |
1869 | if (spin_is_locked(&dbri->lock)) { | 1812 | if (spin_is_locked(&dbri->lock)) { |
1870 | spin_unlock(&dbri->lock); | 1813 | spin_unlock(&dbri->lock); |
@@ -1892,16 +1835,11 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1892 | channel, code, rval); | 1835 | channel, code, rval); |
1893 | } | 1836 | } |
1894 | 1837 | ||
1895 | if (channel == D_INTR_CMD && command == D_WAIT) { | ||
1896 | dbri->wait_ackd = val; | ||
1897 | if (dbri->wait_send != val) { | ||
1898 | printk(KERN_ERR "Processing wait command %d when %d was send.\n", | ||
1899 | val, dbri->wait_send); | ||
1900 | } | ||
1901 | return; | ||
1902 | } | ||
1903 | |||
1904 | switch (code) { | 1838 | switch (code) { |
1839 | case D_INTR_CMDI: | ||
1840 | if (command != D_WAIT) | ||
1841 | printk(KERN_ERR "DBRI: Command read interrupt\n"); | ||
1842 | break; | ||
1905 | case D_INTR_BRDY: | 1843 | case D_INTR_BRDY: |
1906 | reception_complete_intr(dbri, channel); | 1844 | reception_complete_intr(dbri, channel); |
1907 | break; | 1845 | break; |
@@ -1914,8 +1852,10 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1914 | * resend SDP command with clear pipe bit (C) set | 1852 | * resend SDP command with clear pipe bit (C) set |
1915 | */ | 1853 | */ |
1916 | { | 1854 | { |
1917 | volatile s32 *cmd; | 1855 | /* FIXME: do something useful in case of underrun */ |
1918 | 1856 | printk(KERN_ERR "DBRI: Underrun error\n"); | |
1857 | #if 0 | ||
1858 | s32 *cmd; | ||
1919 | int pipe = channel; | 1859 | int pipe = channel; |
1920 | int td = dbri->pipes[pipe].desc; | 1860 | int td = dbri->pipes[pipe].desc; |
1921 | 1861 | ||
@@ -1926,6 +1866,7 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1926 | | D_SDP_P | D_SDP_C | D_SDP_2SAME); | 1866 | | D_SDP_P | D_SDP_C | D_SDP_2SAME); |
1927 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td); | 1867 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td); |
1928 | dbri_cmdsend(dbri, cmd); | 1868 | dbri_cmdsend(dbri, cmd); |
1869 | #endif | ||
1929 | } | 1870 | } |
1930 | break; | 1871 | break; |
1931 | case D_INTR_FXDT: | 1872 | case D_INTR_FXDT: |
@@ -1946,9 +1887,7 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1946 | /* dbri_process_interrupt_buffer advances through the DBRI's interrupt | 1887 | /* dbri_process_interrupt_buffer advances through the DBRI's interrupt |
1947 | * buffer until it finds a zero word (indicating nothing more to do | 1888 | * buffer until it finds a zero word (indicating nothing more to do |
1948 | * right now). Non-zero words require processing and are handed off | 1889 | * right now). Non-zero words require processing and are handed off |
1949 | * to dbri_process_one_interrupt AFTER advancing the pointer. This | 1890 | * to dbri_process_one_interrupt AFTER advancing the pointer. |
1950 | * order is important since we might recurse back into this function | ||
1951 | * and need to make sure the pointer has been advanced first. | ||
1952 | */ | 1891 | */ |
1953 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) | 1892 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) |
1954 | { | 1893 | { |
@@ -1957,10 +1896,8 @@ static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) | |||
1957 | while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) { | 1896 | while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) { |
1958 | dbri->dma->intr[dbri->dbri_irqp] = 0; | 1897 | dbri->dma->intr[dbri->dbri_irqp] = 0; |
1959 | dbri->dbri_irqp++; | 1898 | dbri->dbri_irqp++; |
1960 | if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK)) | 1899 | if (dbri->dbri_irqp == DBRI_INT_BLK) |
1961 | dbri->dbri_irqp = 1; | 1900 | dbri->dbri_irqp = 1; |
1962 | else if ((dbri->dbri_irqp & (DBRI_INT_BLK - 1)) == 0) | ||
1963 | dbri->dbri_irqp++; | ||
1964 | 1901 | ||
1965 | dbri_process_one_interrupt(dbri, x); | 1902 | dbri_process_one_interrupt(dbri, x); |
1966 | } | 1903 | } |
@@ -2020,8 +1957,6 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id, | |||
2020 | 1957 | ||
2021 | dbri_process_interrupt_buffer(dbri); | 1958 | dbri_process_interrupt_buffer(dbri); |
2022 | 1959 | ||
2023 | /* FIXME: Write 0 into regs to ACK interrupt */ | ||
2024 | |||
2025 | spin_unlock(&dbri->lock); | 1960 | spin_unlock(&dbri->lock); |
2026 | 1961 | ||
2027 | return IRQ_HANDLED; | 1962 | return IRQ_HANDLED; |
@@ -2039,8 +1974,8 @@ static struct snd_pcm_hardware snd_dbri_pcm_hw = { | |||
2039 | SNDRV_PCM_FMTBIT_A_LAW | | 1974 | SNDRV_PCM_FMTBIT_A_LAW | |
2040 | SNDRV_PCM_FMTBIT_U8 | | 1975 | SNDRV_PCM_FMTBIT_U8 | |
2041 | SNDRV_PCM_FMTBIT_S16_BE, | 1976 | SNDRV_PCM_FMTBIT_S16_BE, |
2042 | .rates = SNDRV_PCM_RATE_8000_48000, | 1977 | .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512, |
2043 | .rate_min = 8000, | 1978 | .rate_min = 5512, |
2044 | .rate_max = 48000, | 1979 | .rate_max = 48000, |
2045 | .channels_min = 1, | 1980 | .channels_min = 1, |
2046 | .channels_max = 2, | 1981 | .channels_max = 2, |
@@ -2051,6 +1986,39 @@ static struct snd_pcm_hardware snd_dbri_pcm_hw = { | |||
2051 | .periods_max = 1024, | 1986 | .periods_max = 1024, |
2052 | }; | 1987 | }; |
2053 | 1988 | ||
1989 | static int snd_hw_rule_format(struct snd_pcm_hw_params *params, | ||
1990 | struct snd_pcm_hw_rule *rule) | ||
1991 | { | ||
1992 | struct snd_interval *c = hw_param_interval(params, | ||
1993 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
1994 | struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
1995 | struct snd_mask fmt; | ||
1996 | |||
1997 | snd_mask_any(&fmt); | ||
1998 | if (c->min > 1) { | ||
1999 | fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_BE; | ||
2000 | return snd_mask_refine(f, &fmt); | ||
2001 | } | ||
2002 | return 0; | ||
2003 | } | ||
2004 | |||
2005 | static int snd_hw_rule_channels(struct snd_pcm_hw_params *params, | ||
2006 | struct snd_pcm_hw_rule *rule) | ||
2007 | { | ||
2008 | struct snd_interval *c = hw_param_interval(params, | ||
2009 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
2010 | struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
2011 | struct snd_interval ch; | ||
2012 | |||
2013 | snd_interval_any(&ch); | ||
2014 | if (!(f->bits[0] & SNDRV_PCM_FMTBIT_S16_BE)) { | ||
2015 | ch.min = ch.max = 1; | ||
2016 | ch.integer = 1; | ||
2017 | return snd_interval_refine(c, &ch); | ||
2018 | } | ||
2019 | return 0; | ||
2020 | } | ||
2021 | |||
2054 | static int snd_dbri_open(struct snd_pcm_substream *substream) | 2022 | static int snd_dbri_open(struct snd_pcm_substream *substream) |
2055 | { | 2023 | { |
2056 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); | 2024 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); |
@@ -2063,12 +2031,19 @@ static int snd_dbri_open(struct snd_pcm_substream *substream) | |||
2063 | 2031 | ||
2064 | spin_lock_irqsave(&dbri->lock, flags); | 2032 | spin_lock_irqsave(&dbri->lock, flags); |
2065 | info->substream = substream; | 2033 | info->substream = substream; |
2066 | info->left = 0; | ||
2067 | info->offset = 0; | 2034 | info->offset = 0; |
2068 | info->dvma_buffer = 0; | 2035 | info->dvma_buffer = 0; |
2069 | info->pipe = -1; | 2036 | info->pipe = -1; |
2070 | spin_unlock_irqrestore(&dbri->lock, flags); | 2037 | spin_unlock_irqrestore(&dbri->lock, flags); |
2071 | 2038 | ||
2039 | snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_CHANNELS, | ||
2040 | snd_hw_rule_format, 0, SNDRV_PCM_HW_PARAM_FORMAT, | ||
2041 | -1); | ||
2042 | snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_FORMAT, | ||
2043 | snd_hw_rule_channels, 0, | ||
2044 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
2045 | -1); | ||
2046 | |||
2072 | cs4215_open(dbri); | 2047 | cs4215_open(dbri); |
2073 | 2048 | ||
2074 | return 0; | 2049 | return 0; |
@@ -2081,7 +2056,6 @@ static int snd_dbri_close(struct snd_pcm_substream *substream) | |||
2081 | 2056 | ||
2082 | dprintk(D_USR, "close audio output.\n"); | 2057 | dprintk(D_USR, "close audio output.\n"); |
2083 | info->substream = NULL; | 2058 | info->substream = NULL; |
2084 | info->left = 0; | ||
2085 | info->offset = 0; | 2059 | info->offset = 0; |
2086 | 2060 | ||
2087 | return 0; | 2061 | return 0; |
@@ -2134,6 +2108,7 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream) | |||
2134 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); | 2108 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); |
2135 | struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); | 2109 | struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); |
2136 | int direction; | 2110 | int direction; |
2111 | |||
2137 | dprintk(D_USR, "hw_free.\n"); | 2112 | dprintk(D_USR, "hw_free.\n"); |
2138 | 2113 | ||
2139 | /* hw_free can get called multiple times. Only unmap the DMA once. | 2114 | /* hw_free can get called multiple times. Only unmap the DMA once. |
@@ -2148,7 +2123,10 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream) | |||
2148 | substream->runtime->buffer_size, direction); | 2123 | substream->runtime->buffer_size, direction); |
2149 | info->dvma_buffer = 0; | 2124 | info->dvma_buffer = 0; |
2150 | } | 2125 | } |
2151 | info->pipe = -1; | 2126 | if (info->pipe != -1) { |
2127 | reset_pipe(dbri, info->pipe); | ||
2128 | info->pipe = -1; | ||
2129 | } | ||
2152 | 2130 | ||
2153 | return snd_pcm_lib_free_pages(substream); | 2131 | return snd_pcm_lib_free_pages(substream); |
2154 | } | 2132 | } |
@@ -2157,18 +2135,16 @@ static int snd_dbri_prepare(struct snd_pcm_substream *substream) | |||
2157 | { | 2135 | { |
2158 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); | 2136 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); |
2159 | struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); | 2137 | struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); |
2160 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2161 | int ret; | 2138 | int ret; |
2162 | 2139 | ||
2163 | info->size = snd_pcm_lib_buffer_bytes(substream); | 2140 | info->size = snd_pcm_lib_buffer_bytes(substream); |
2164 | if (DBRI_STREAMNO(substream) == DBRI_PLAY) | 2141 | if (DBRI_STREAMNO(substream) == DBRI_PLAY) |
2165 | info->pipe = 4; /* Send pipe */ | 2142 | info->pipe = 4; /* Send pipe */ |
2166 | else { | 2143 | else |
2167 | info->pipe = 6; /* Receive pipe */ | 2144 | info->pipe = 6; /* Receive pipe */ |
2168 | info->left = info->size; /* To trigger submittal */ | ||
2169 | } | ||
2170 | 2145 | ||
2171 | spin_lock_irq(&dbri->lock); | 2146 | spin_lock_irq(&dbri->lock); |
2147 | info->offset = 0; | ||
2172 | 2148 | ||
2173 | /* Setup the all the transmit/receive desciptors to cover the | 2149 | /* Setup the all the transmit/receive desciptors to cover the |
2174 | * whole DMA buffer. | 2150 | * whole DMA buffer. |
@@ -2176,8 +2152,6 @@ static int snd_dbri_prepare(struct snd_pcm_substream *substream) | |||
2176 | ret = setup_descs(dbri, DBRI_STREAMNO(substream), | 2152 | ret = setup_descs(dbri, DBRI_STREAMNO(substream), |
2177 | snd_pcm_lib_period_bytes(substream)); | 2153 | snd_pcm_lib_period_bytes(substream)); |
2178 | 2154 | ||
2179 | runtime->stop_threshold = DBRI_TD_MAXCNT / runtime->channels; | ||
2180 | |||
2181 | spin_unlock_irq(&dbri->lock); | 2155 | spin_unlock_irq(&dbri->lock); |
2182 | 2156 | ||
2183 | dprintk(D_USR, "prepare audio output. %d bytes\n", info->size); | 2157 | dprintk(D_USR, "prepare audio output. %d bytes\n", info->size); |
@@ -2194,14 +2168,11 @@ static int snd_dbri_trigger(struct snd_pcm_substream *substream, int cmd) | |||
2194 | case SNDRV_PCM_TRIGGER_START: | 2168 | case SNDRV_PCM_TRIGGER_START: |
2195 | dprintk(D_USR, "start audio, period is %d bytes\n", | 2169 | dprintk(D_USR, "start audio, period is %d bytes\n", |
2196 | (int)snd_pcm_lib_period_bytes(substream)); | 2170 | (int)snd_pcm_lib_period_bytes(substream)); |
2197 | /* Enable & schedule the tasklet that re-submits the TDs. */ | 2171 | /* Re-submit the TDs. */ |
2198 | xmit_descs_task.data = (unsigned long)dbri; | 2172 | xmit_descs(dbri); |
2199 | tasklet_schedule(&xmit_descs_task); | ||
2200 | break; | 2173 | break; |
2201 | case SNDRV_PCM_TRIGGER_STOP: | 2174 | case SNDRV_PCM_TRIGGER_STOP: |
2202 | dprintk(D_USR, "stop audio.\n"); | 2175 | dprintk(D_USR, "stop audio.\n"); |
2203 | /* Make the tasklet bail out immediately. */ | ||
2204 | xmit_descs_task.data = 0; | ||
2205 | reset_pipe(dbri, info->pipe); | 2176 | reset_pipe(dbri, info->pipe); |
2206 | break; | 2177 | break; |
2207 | default: | 2178 | default: |
@@ -2219,8 +2190,8 @@ static snd_pcm_uframes_t snd_dbri_pointer(struct snd_pcm_substream *substream) | |||
2219 | 2190 | ||
2220 | ret = bytes_to_frames(substream->runtime, info->offset) | 2191 | ret = bytes_to_frames(substream->runtime, info->offset) |
2221 | % substream->runtime->buffer_size; | 2192 | % substream->runtime->buffer_size; |
2222 | dprintk(D_USR, "I/O pointer: %ld frames, %d bytes left.\n", | 2193 | dprintk(D_USR, "I/O pointer: %ld frames of %ld.\n", |
2223 | ret, info->left); | 2194 | ret, substream->runtime->buffer_size); |
2224 | return ret; | 2195 | return ret; |
2225 | } | 2196 | } |
2226 | 2197 | ||
@@ -2254,7 +2225,6 @@ static int __devinit snd_dbri_pcm(struct snd_dbri * dbri) | |||
2254 | pcm->private_data = dbri; | 2225 | pcm->private_data = dbri; |
2255 | pcm->info_flags = 0; | 2226 | pcm->info_flags = 0; |
2256 | strcpy(pcm->name, dbri->card->shortname); | 2227 | strcpy(pcm->name, dbri->card->shortname); |
2257 | dbri->pcm = pcm; | ||
2258 | 2228 | ||
2259 | if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, | 2229 | if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, |
2260 | SNDRV_DMA_TYPE_CONTINUOUS, | 2230 | SNDRV_DMA_TYPE_CONTINUOUS, |
@@ -2303,7 +2273,6 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol, | |||
2303 | { | 2273 | { |
2304 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); | 2274 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); |
2305 | struct dbri_streaminfo *info = &dbri->stream_info[kcontrol->private_value]; | 2275 | struct dbri_streaminfo *info = &dbri->stream_info[kcontrol->private_value]; |
2306 | unsigned long flags; | ||
2307 | int changed = 0; | 2276 | int changed = 0; |
2308 | 2277 | ||
2309 | if (info->left_gain != ucontrol->value.integer.value[0]) { | 2278 | if (info->left_gain != ucontrol->value.integer.value[0]) { |
@@ -2318,13 +2287,9 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol, | |||
2318 | /* First mute outputs, and wait 1/8000 sec (125 us) | 2287 | /* First mute outputs, and wait 1/8000 sec (125 us) |
2319 | * to make sure this takes. This avoids clicking noises. | 2288 | * to make sure this takes. This avoids clicking noises. |
2320 | */ | 2289 | */ |
2321 | spin_lock_irqsave(&dbri->lock, flags); | ||
2322 | |||
2323 | cs4215_setdata(dbri, 1); | 2290 | cs4215_setdata(dbri, 1); |
2324 | udelay(125); | 2291 | udelay(125); |
2325 | cs4215_setdata(dbri, 0); | 2292 | cs4215_setdata(dbri, 0); |
2326 | |||
2327 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
2328 | } | 2293 | } |
2329 | return changed; | 2294 | return changed; |
2330 | } | 2295 | } |
@@ -2371,7 +2336,6 @@ static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol, | |||
2371 | struct snd_ctl_elem_value *ucontrol) | 2336 | struct snd_ctl_elem_value *ucontrol) |
2372 | { | 2337 | { |
2373 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); | 2338 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); |
2374 | unsigned long flags; | ||
2375 | int elem = kcontrol->private_value & 0xff; | 2339 | int elem = kcontrol->private_value & 0xff; |
2376 | int shift = (kcontrol->private_value >> 8) & 0xff; | 2340 | int shift = (kcontrol->private_value >> 8) & 0xff; |
2377 | int mask = (kcontrol->private_value >> 16) & 0xff; | 2341 | int mask = (kcontrol->private_value >> 16) & 0xff; |
@@ -2404,13 +2368,9 @@ static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol, | |||
2404 | /* First mute outputs, and wait 1/8000 sec (125 us) | 2368 | /* First mute outputs, and wait 1/8000 sec (125 us) |
2405 | * to make sure this takes. This avoids clicking noises. | 2369 | * to make sure this takes. This avoids clicking noises. |
2406 | */ | 2370 | */ |
2407 | spin_lock_irqsave(&dbri->lock, flags); | ||
2408 | |||
2409 | cs4215_setdata(dbri, 1); | 2371 | cs4215_setdata(dbri, 1); |
2410 | udelay(125); | 2372 | udelay(125); |
2411 | cs4215_setdata(dbri, 0); | 2373 | cs4215_setdata(dbri, 0); |
2412 | |||
2413 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
2414 | } | 2374 | } |
2415 | return changed; | 2375 | return changed; |
2416 | } | 2376 | } |
@@ -2473,7 +2433,6 @@ static int __init snd_dbri_mixer(struct snd_dbri * dbri) | |||
2473 | for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) { | 2433 | for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) { |
2474 | dbri->stream_info[idx].left_gain = 0; | 2434 | dbri->stream_info[idx].left_gain = 0; |
2475 | dbri->stream_info[idx].right_gain = 0; | 2435 | dbri->stream_info[idx].right_gain = 0; |
2476 | dbri->stream_info[idx].balance = DBRI_MID_BALANCE; | ||
2477 | } | 2436 | } |
2478 | 2437 | ||
2479 | return 0; | 2438 | return 0; |
@@ -2505,12 +2464,11 @@ static void dbri_debug_read(struct snd_info_entry * entry, | |||
2505 | struct dbri_pipe *pptr = &dbri->pipes[pipe]; | 2464 | struct dbri_pipe *pptr = &dbri->pipes[pipe]; |
2506 | snd_iprintf(buffer, | 2465 | snd_iprintf(buffer, |
2507 | "Pipe %d: %s SDP=0x%x desc=%d, " | 2466 | "Pipe %d: %s SDP=0x%x desc=%d, " |
2508 | "len=%d @ %d prev: %d next %d\n", | 2467 | "len=%d next %d\n", |
2509 | pipe, | 2468 | pipe, |
2510 | (pptr->direction == | 2469 | ((pptr->sdp & D_SDP_TO_SER) ? "output" : "input"), |
2511 | PIPEinput ? "input" : "output"), pptr->sdp, | 2470 | pptr->sdp, pptr->desc, |
2512 | pptr->desc, pptr->length, pptr->cycle, | 2471 | pptr->length, pptr->nextpipe); |
2513 | pptr->prevpipe, pptr->nextpipe); | ||
2514 | } | 2472 | } |
2515 | } | 2473 | } |
2516 | } | 2474 | } |
@@ -2549,7 +2507,6 @@ static int __init snd_dbri_create(struct snd_card *card, | |||
2549 | dbri->card = card; | 2507 | dbri->card = card; |
2550 | dbri->sdev = sdev; | 2508 | dbri->sdev = sdev; |
2551 | dbri->irq = irq->pri; | 2509 | dbri->irq = irq->pri; |
2552 | dbri->dbri_version = sdev->prom_name[9]; | ||
2553 | 2510 | ||
2554 | dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma), | 2511 | dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma), |
2555 | &dbri->dma_dvma); | 2512 | &dbri->dma_dvma); |
@@ -2669,7 +2626,7 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) | |||
2669 | 2626 | ||
2670 | printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n", | 2627 | printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n", |
2671 | dev, dbri->regs, | 2628 | dev, dbri->regs, |
2672 | dbri->irq, dbri->dbri_version, dbri->mm.version); | 2629 | dbri->irq, sdev->prom_name[9], dbri->mm.version); |
2673 | dev++; | 2630 | dev++; |
2674 | 2631 | ||
2675 | return 0; | 2632 | return 0; |
diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index 58b9601f3ad0..59144ec026e4 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c | |||
@@ -128,10 +128,8 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device) | |||
128 | 128 | ||
129 | void snd_emux_proc_free(struct snd_emux *emu) | 129 | void snd_emux_proc_free(struct snd_emux *emu) |
130 | { | 130 | { |
131 | if (emu->proc) { | 131 | snd_info_free_entry(emu->proc); |
132 | snd_info_unregister(emu->proc); | 132 | emu->proc = NULL; |
133 | emu->proc = NULL; | ||
134 | } | ||
135 | } | 133 | } |
136 | 134 | ||
137 | #endif /* CONFIG_PROC_FS */ | 135 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 1b7f499c549d..49248fa7aef4 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -68,7 +68,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | |||
68 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | 68 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ |
69 | static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ | 69 | static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ |
70 | static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ | 70 | static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ |
71 | static int nrpacks = 4; /* max. number of packets per urb */ | 71 | static int nrpacks = 8; /* max. number of packets per urb */ |
72 | static int async_unlink = 1; | 72 | static int async_unlink = 1; |
73 | static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/ | 73 | static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/ |
74 | 74 | ||
@@ -100,7 +100,7 @@ MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); | |||
100 | * | 100 | * |
101 | */ | 101 | */ |
102 | 102 | ||
103 | #define MAX_PACKS 10 | 103 | #define MAX_PACKS 20 |
104 | #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ | 104 | #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ |
105 | #define MAX_URBS 8 | 105 | #define MAX_URBS 8 |
106 | #define SYNC_URBS 4 /* always four urbs for sync */ | 106 | #define SYNC_URBS 4 /* always four urbs for sync */ |
@@ -123,6 +123,7 @@ struct audioformat { | |||
123 | unsigned int rate_min, rate_max; /* min/max rates */ | 123 | unsigned int rate_min, rate_max; /* min/max rates */ |
124 | unsigned int nr_rates; /* number of rate table entries */ | 124 | unsigned int nr_rates; /* number of rate table entries */ |
125 | unsigned int *rate_table; /* rate table */ | 125 | unsigned int *rate_table; /* rate table */ |
126 | unsigned int needs_knot; /* any unusual rates? */ | ||
126 | }; | 127 | }; |
127 | 128 | ||
128 | struct snd_usb_substream; | 129 | struct snd_usb_substream; |
@@ -1759,6 +1760,9 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) | |||
1759 | } | 1760 | } |
1760 | channels[f->format] |= (1 << f->channels); | 1761 | channels[f->format] |= (1 << f->channels); |
1761 | rates[f->format] |= f->rates; | 1762 | rates[f->format] |= f->rates; |
1763 | /* needs knot? */ | ||
1764 | if (f->needs_knot) | ||
1765 | goto __out; | ||
1762 | } | 1766 | } |
1763 | /* check whether channels and rates match for all formats */ | 1767 | /* check whether channels and rates match for all formats */ |
1764 | cmaster = rmaster = 0; | 1768 | cmaster = rmaster = 0; |
@@ -1799,6 +1803,38 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) | |||
1799 | return err; | 1803 | return err; |
1800 | } | 1804 | } |
1801 | 1805 | ||
1806 | /* | ||
1807 | * If the device supports unusual bit rates, does the request meet these? | ||
1808 | */ | ||
1809 | static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, | ||
1810 | struct snd_usb_substream *subs) | ||
1811 | { | ||
1812 | struct list_head *p; | ||
1813 | struct snd_pcm_hw_constraint_list constraints_rates; | ||
1814 | int err; | ||
1815 | |||
1816 | list_for_each(p, &subs->fmt_list) { | ||
1817 | struct audioformat *fp; | ||
1818 | fp = list_entry(p, struct audioformat, list); | ||
1819 | |||
1820 | if (!fp->needs_knot) | ||
1821 | continue; | ||
1822 | |||
1823 | constraints_rates.count = fp->nr_rates; | ||
1824 | constraints_rates.list = fp->rate_table; | ||
1825 | constraints_rates.mask = 0; | ||
1826 | |||
1827 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1828 | SNDRV_PCM_HW_PARAM_RATE, | ||
1829 | &constraints_rates); | ||
1830 | |||
1831 | if (err < 0) | ||
1832 | return err; | ||
1833 | } | ||
1834 | |||
1835 | return 0; | ||
1836 | } | ||
1837 | |||
1802 | 1838 | ||
1803 | /* | 1839 | /* |
1804 | * set up the runtime hardware information. | 1840 | * set up the runtime hardware information. |
@@ -1861,6 +1897,8 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1861 | SNDRV_PCM_HW_PARAM_CHANNELS, | 1897 | SNDRV_PCM_HW_PARAM_CHANNELS, |
1862 | -1)) < 0) | 1898 | -1)) < 0) |
1863 | return err; | 1899 | return err; |
1900 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) | ||
1901 | return err; | ||
1864 | } | 1902 | } |
1865 | return 0; | 1903 | return 0; |
1866 | } | 1904 | } |
@@ -2049,7 +2087,7 @@ static struct usb_driver usb_audio_driver = { | |||
2049 | }; | 2087 | }; |
2050 | 2088 | ||
2051 | 2089 | ||
2052 | #if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS) | 2090 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS) |
2053 | 2091 | ||
2054 | /* | 2092 | /* |
2055 | * proc interface for list the supported pcm formats | 2093 | * proc interface for list the supported pcm formats |
@@ -2406,6 +2444,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2406 | unsigned char *fmt, int offset) | 2444 | unsigned char *fmt, int offset) |
2407 | { | 2445 | { |
2408 | int nr_rates = fmt[offset]; | 2446 | int nr_rates = fmt[offset]; |
2447 | int found; | ||
2409 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { | 2448 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { |
2410 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", | 2449 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", |
2411 | chip->dev->devnum, fp->iface, fp->altsetting); | 2450 | chip->dev->devnum, fp->iface, fp->altsetting); |
@@ -2428,6 +2467,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2428 | return -1; | 2467 | return -1; |
2429 | } | 2468 | } |
2430 | 2469 | ||
2470 | fp->needs_knot = 0; | ||
2431 | fp->nr_rates = nr_rates; | 2471 | fp->nr_rates = nr_rates; |
2432 | fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); | 2472 | fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); |
2433 | for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { | 2473 | for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { |
@@ -2436,13 +2476,19 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2436 | fp->rate_min = rate; | 2476 | fp->rate_min = rate; |
2437 | else if (rate > fp->rate_max) | 2477 | else if (rate > fp->rate_max) |
2438 | fp->rate_max = rate; | 2478 | fp->rate_max = rate; |
2479 | found = 0; | ||
2439 | for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { | 2480 | for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { |
2440 | if (rate == conv_rates[c]) { | 2481 | if (rate == conv_rates[c]) { |
2482 | found = 1; | ||
2441 | fp->rates |= (1 << c); | 2483 | fp->rates |= (1 << c); |
2442 | break; | 2484 | break; |
2443 | } | 2485 | } |
2444 | } | 2486 | } |
2487 | if (!found) | ||
2488 | fp->needs_knot = 1; | ||
2445 | } | 2489 | } |
2490 | if (fp->needs_knot) | ||
2491 | fp->rates |= SNDRV_PCM_RATE_KNOT; | ||
2446 | } else { | 2492 | } else { |
2447 | /* continuous rates */ | 2493 | /* continuous rates */ |
2448 | fp->rates = SNDRV_PCM_RATE_CONTINUOUS; | 2494 | fp->rates = SNDRV_PCM_RATE_CONTINUOUS; |
@@ -3499,7 +3545,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) | |||
3499 | } | 3545 | } |
3500 | usb_chip[chip->index] = NULL; | 3546 | usb_chip[chip->index] = NULL; |
3501 | mutex_unlock(®ister_mutex); | 3547 | mutex_unlock(®ister_mutex); |
3502 | snd_card_free(card); | 3548 | snd_card_free_when_closed(card); |
3503 | } else { | 3549 | } else { |
3504 | mutex_unlock(®ister_mutex); | 3550 | mutex_unlock(®ister_mutex); |
3505 | } | 3551 | } |
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 491e975a0c87..e516d6adbb22 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <sound/control.h> | 37 | #include <sound/control.h> |
38 | #include <sound/hwdep.h> | 38 | #include <sound/hwdep.h> |
39 | #include <sound/info.h> | 39 | #include <sound/info.h> |
40 | #include <sound/tlv.h> | ||
40 | 41 | ||
41 | #include "usbaudio.h" | 42 | #include "usbaudio.h" |
42 | 43 | ||
@@ -416,6 +417,26 @@ static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channe | |||
416 | return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); | 417 | return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); |
417 | } | 418 | } |
418 | 419 | ||
420 | /* | ||
421 | * TLV callback for mixer volume controls | ||
422 | */ | ||
423 | static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||
424 | unsigned int size, unsigned int __user *_tlv) | ||
425 | { | ||
426 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | ||
427 | DECLARE_TLV_DB_SCALE(scale, 0, 0, 0); | ||
428 | |||
429 | if (size < sizeof(scale)) | ||
430 | return -ENOMEM; | ||
431 | /* USB descriptions contain the dB scale in 1/256 dB unit | ||
432 | * while ALSA TLV contains in 1/100 dB unit | ||
433 | */ | ||
434 | scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; | ||
435 | scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256; | ||
436 | if (copy_to_user(_tlv, scale, sizeof(scale))) | ||
437 | return -EFAULT; | ||
438 | return 0; | ||
439 | } | ||
419 | 440 | ||
420 | /* | 441 | /* |
421 | * parser routines begin here... | 442 | * parser routines begin here... |
@@ -933,6 +954,12 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
933 | } | 954 | } |
934 | strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume", | 955 | strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume", |
935 | sizeof(kctl->id.name)); | 956 | sizeof(kctl->id.name)); |
957 | if (control == USB_FEATURE_VOLUME) { | ||
958 | kctl->tlv.c = mixer_vol_tlv; | ||
959 | kctl->vd[0].access |= | ||
960 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | ||
961 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | ||
962 | } | ||
936 | break; | 963 | break; |
937 | 964 | ||
938 | default: | 965 | default: |
diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 37accb68652d..7c4dcb3f436a 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c | |||
@@ -234,6 +234,26 @@ static struct usbmix_name_map justlink_map[] = { | |||
234 | { 0 } /* terminator */ | 234 | { 0 } /* terminator */ |
235 | }; | 235 | }; |
236 | 236 | ||
237 | /* TerraTec Aureon 5.1 MkII USB */ | ||
238 | static struct usbmix_name_map aureon_51_2_map[] = { | ||
239 | /* 1: IT USB */ | ||
240 | /* 2: IT Mic */ | ||
241 | /* 3: IT Line */ | ||
242 | /* 4: IT SPDIF */ | ||
243 | /* 5: OT SPDIF */ | ||
244 | /* 6: OT Speaker */ | ||
245 | /* 7: OT USB */ | ||
246 | { 8, "Capture Source" }, /* SU */ | ||
247 | { 9, "Master Playback" }, /* FU */ | ||
248 | { 10, "Mic Capture" }, /* FU */ | ||
249 | { 11, "Line Capture" }, /* FU */ | ||
250 | { 12, "IEC958 In Capture" }, /* FU */ | ||
251 | { 13, "Mic Playback" }, /* FU */ | ||
252 | { 14, "Line Playback" }, /* FU */ | ||
253 | /* 15: MU */ | ||
254 | {} /* terminator */ | ||
255 | }; | ||
256 | |||
237 | /* | 257 | /* |
238 | * Control map entries | 258 | * Control map entries |
239 | */ | 259 | */ |
@@ -276,6 +296,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
276 | .id = USB_ID(0x0c45, 0x1158), | 296 | .id = USB_ID(0x0c45, 0x1158), |
277 | .map = justlink_map, | 297 | .map = justlink_map, |
278 | }, | 298 | }, |
299 | { | ||
300 | .id = USB_ID(0x0ccd, 0x0028), | ||
301 | .map = aureon_51_2_map, | ||
302 | }, | ||
279 | { 0 } /* terminator */ | 303 | { 0 } /* terminator */ |
280 | }; | 304 | }; |
281 | 305 | ||
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 9351846d7a9d..a7e9563a01df 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
@@ -123,6 +123,10 @@ YAMAHA_DEVICE(0x103e, NULL), | |||
123 | YAMAHA_DEVICE(0x103f, NULL), | 123 | YAMAHA_DEVICE(0x103f, NULL), |
124 | YAMAHA_DEVICE(0x1040, NULL), | 124 | YAMAHA_DEVICE(0x1040, NULL), |
125 | YAMAHA_DEVICE(0x1041, NULL), | 125 | YAMAHA_DEVICE(0x1041, NULL), |
126 | YAMAHA_DEVICE(0x1042, NULL), | ||
127 | YAMAHA_DEVICE(0x1043, NULL), | ||
128 | YAMAHA_DEVICE(0x1044, NULL), | ||
129 | YAMAHA_DEVICE(0x1045, NULL), | ||
126 | YAMAHA_DEVICE(0x2000, "DGP-7"), | 130 | YAMAHA_DEVICE(0x2000, "DGP-7"), |
127 | YAMAHA_DEVICE(0x2001, "DGP-5"), | 131 | YAMAHA_DEVICE(0x2001, "DGP-5"), |
128 | YAMAHA_DEVICE(0x2002, NULL), | 132 | YAMAHA_DEVICE(0x2002, NULL), |
@@ -141,6 +145,7 @@ YAMAHA_DEVICE(0x500b, "DME64N"), | |||
141 | YAMAHA_DEVICE(0x500c, "DME24N"), | 145 | YAMAHA_DEVICE(0x500c, "DME24N"), |
142 | YAMAHA_DEVICE(0x500d, NULL), | 146 | YAMAHA_DEVICE(0x500d, NULL), |
143 | YAMAHA_DEVICE(0x500e, NULL), | 147 | YAMAHA_DEVICE(0x500e, NULL), |
148 | YAMAHA_DEVICE(0x500f, NULL), | ||
144 | YAMAHA_DEVICE(0x7000, "DTX"), | 149 | YAMAHA_DEVICE(0x7000, "DTX"), |
145 | YAMAHA_DEVICE(0x7010, "UB99"), | 150 | YAMAHA_DEVICE(0x7010, "UB99"), |
146 | #undef YAMAHA_DEVICE | 151 | #undef YAMAHA_DEVICE |