diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2008-01-28 02:35:20 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:30:17 -0500 |
commit | a3601560496d7b46d2d1187169824d11570ff63a (patch) | |
tree | abcb52cdea5f118815994895b2375ad000fc4d24 | |
parent | 1e821dd2763c97df1a0a451e553d218cb8886cd7 (diff) |
[ALSA] oxygen: add front panel controls
Add mixer controls for the front panel AC97 codec.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r-- | sound/pci/oxygen/oxygen.h | 2 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 3 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_mixer.c | 117 | ||||
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 4 |
4 files changed, 100 insertions, 26 deletions
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 55ce2448805d..e71c53498995 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -86,7 +86,7 @@ struct oxygen_model { | |||
86 | struct snd_pcm_hw_params *params); | 86 | struct snd_pcm_hw_params *params); |
87 | void (*update_dac_volume)(struct oxygen *chip); | 87 | void (*update_dac_volume)(struct oxygen *chip); |
88 | void (*update_dac_mute)(struct oxygen *chip); | 88 | void (*update_dac_mute)(struct oxygen *chip); |
89 | void (*ac97_switch_hook)(struct oxygen *chip, | 89 | void (*ac97_switch_hook)(struct oxygen *chip, unsigned int codec, |
90 | unsigned int reg, int mute); | 90 | unsigned int reg, int mute); |
91 | size_t model_data_size; | 91 | size_t model_data_size; |
92 | u8 dac_channels; | 92 | u8 dac_channels; |
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index de6bf41c3e96..540e56b75794 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -365,8 +365,7 @@ static void __devinit oxygen_init(struct oxygen *chip) | |||
365 | oxygen_write_ac97(chip, 1, AC97_AUX, 0x8808); | 365 | oxygen_write_ac97(chip, 1, AC97_AUX, 0x8808); |
366 | oxygen_write_ac97(chip, 1, AC97_PCM, 0x0808); | 366 | oxygen_write_ac97(chip, 1, AC97_PCM, 0x0808); |
367 | oxygen_write_ac97(chip, 1, AC97_REC_SEL, 0x0000); | 367 | oxygen_write_ac97(chip, 1, AC97_REC_SEL, 0x0000); |
368 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, 0x8000); | 368 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, 0x0000); |
369 | oxygen_ac97_clear_bits(chip, 1, AC97_REC_GAIN, 0x1c00); | ||
370 | oxygen_ac97_set_bits(chip, 1, 0x6a, 0x0040); | 369 | oxygen_ac97_set_bits(chip, 1, 0x6a, 0x0040); |
371 | } | 370 | } |
372 | } | 371 | } |
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index cf34b1229b0b..a8e4623415d9 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
@@ -450,13 +450,14 @@ static int ac97_switch_get(struct snd_kcontrol *ctl, | |||
450 | struct snd_ctl_elem_value *value) | 450 | struct snd_ctl_elem_value *value) |
451 | { | 451 | { |
452 | struct oxygen *chip = ctl->private_data; | 452 | struct oxygen *chip = ctl->private_data; |
453 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
453 | unsigned int index = ctl->private_value & 0xff; | 454 | unsigned int index = ctl->private_value & 0xff; |
454 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; | 455 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; |
455 | int invert = ctl->private_value & (1 << 16); | 456 | int invert = ctl->private_value & (1 << 16); |
456 | u16 reg; | 457 | u16 reg; |
457 | 458 | ||
458 | mutex_lock(&chip->mutex); | 459 | mutex_lock(&chip->mutex); |
459 | reg = oxygen_read_ac97(chip, 0, index); | 460 | reg = oxygen_read_ac97(chip, codec, index); |
460 | mutex_unlock(&chip->mutex); | 461 | mutex_unlock(&chip->mutex); |
461 | if (!(reg & (1 << bitnr)) ^ !invert) | 462 | if (!(reg & (1 << bitnr)) ^ !invert) |
462 | value->value.integer.value[0] = 1; | 463 | value->value.integer.value[0] = 1; |
@@ -469,6 +470,7 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, | |||
469 | struct snd_ctl_elem_value *value) | 470 | struct snd_ctl_elem_value *value) |
470 | { | 471 | { |
471 | struct oxygen *chip = ctl->private_data; | 472 | struct oxygen *chip = ctl->private_data; |
473 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
472 | unsigned int index = ctl->private_value & 0xff; | 474 | unsigned int index = ctl->private_value & 0xff; |
473 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; | 475 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; |
474 | int invert = ctl->private_value & (1 << 16); | 476 | int invert = ctl->private_value & (1 << 16); |
@@ -476,7 +478,7 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, | |||
476 | int change; | 478 | int change; |
477 | 479 | ||
478 | mutex_lock(&chip->mutex); | 480 | mutex_lock(&chip->mutex); |
479 | oldreg = oxygen_read_ac97(chip, 0, index); | 481 | oldreg = oxygen_read_ac97(chip, codec, index); |
480 | newreg = oldreg; | 482 | newreg = oldreg; |
481 | if (!value->value.integer.value[0] ^ !invert) | 483 | if (!value->value.integer.value[0] ^ !invert) |
482 | newreg |= 1 << bitnr; | 484 | newreg |= 1 << bitnr; |
@@ -484,9 +486,9 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, | |||
484 | newreg &= ~(1 << bitnr); | 486 | newreg &= ~(1 << bitnr); |
485 | change = newreg != oldreg; | 487 | change = newreg != oldreg; |
486 | if (change) { | 488 | if (change) { |
487 | oxygen_write_ac97(chip, 0, index, newreg); | 489 | oxygen_write_ac97(chip, codec, index, newreg); |
488 | if (bitnr == 15 && chip->model->ac97_switch_hook) | 490 | if (bitnr == 15 && chip->model->ac97_switch_hook) |
489 | chip->model->ac97_switch_hook(chip, index, | 491 | chip->model->ac97_switch_hook(chip, codec, index, |
490 | newreg & 0x8000); | 492 | newreg & 0x8000); |
491 | } | 493 | } |
492 | mutex_unlock(&chip->mutex); | 494 | mutex_unlock(&chip->mutex); |
@@ -507,11 +509,12 @@ static int ac97_volume_get(struct snd_kcontrol *ctl, | |||
507 | struct snd_ctl_elem_value *value) | 509 | struct snd_ctl_elem_value *value) |
508 | { | 510 | { |
509 | struct oxygen *chip = ctl->private_data; | 511 | struct oxygen *chip = ctl->private_data; |
510 | unsigned int index = ctl->private_value; | 512 | unsigned int codec = (ctl->private_value >> 24) & 1; |
513 | unsigned int index = ctl->private_value & 0xff; | ||
511 | u16 reg; | 514 | u16 reg; |
512 | 515 | ||
513 | mutex_lock(&chip->mutex); | 516 | mutex_lock(&chip->mutex); |
514 | reg = oxygen_read_ac97(chip, 0, index); | 517 | reg = oxygen_read_ac97(chip, codec, index); |
515 | mutex_unlock(&chip->mutex); | 518 | mutex_unlock(&chip->mutex); |
516 | value->value.integer.value[0] = 31 - (reg & 0x1f); | 519 | value->value.integer.value[0] = 31 - (reg & 0x1f); |
517 | value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); | 520 | value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); |
@@ -522,12 +525,13 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, | |||
522 | struct snd_ctl_elem_value *value) | 525 | struct snd_ctl_elem_value *value) |
523 | { | 526 | { |
524 | struct oxygen *chip = ctl->private_data; | 527 | struct oxygen *chip = ctl->private_data; |
525 | unsigned int index = ctl->private_value; | 528 | unsigned int codec = (ctl->private_value >> 24) & 1; |
529 | unsigned int index = ctl->private_value & 0xff; | ||
526 | u16 oldreg, newreg; | 530 | u16 oldreg, newreg; |
527 | int change; | 531 | int change; |
528 | 532 | ||
529 | mutex_lock(&chip->mutex); | 533 | mutex_lock(&chip->mutex); |
530 | oldreg = oxygen_read_ac97(chip, 0, index); | 534 | oldreg = oxygen_read_ac97(chip, codec, index); |
531 | newreg = oldreg; | 535 | newreg = oldreg; |
532 | newreg = (newreg & ~0x1f) | | 536 | newreg = (newreg & ~0x1f) | |
533 | (31 - (value->value.integer.value[0] & 0x1f)); | 537 | (31 - (value->value.integer.value[0] & 0x1f)); |
@@ -535,30 +539,77 @@ static int ac97_volume_put(struct snd_kcontrol *ctl, | |||
535 | ((31 - (value->value.integer.value[0] & 0x1f)) << 8); | 539 | ((31 - (value->value.integer.value[0] & 0x1f)) << 8); |
536 | change = newreg != oldreg; | 540 | change = newreg != oldreg; |
537 | if (change) | 541 | if (change) |
538 | oxygen_write_ac97(chip, 0, index, newreg); | 542 | oxygen_write_ac97(chip, codec, index, newreg); |
539 | mutex_unlock(&chip->mutex); | 543 | mutex_unlock(&chip->mutex); |
540 | return change; | 544 | return change; |
541 | } | 545 | } |
542 | 546 | ||
543 | #define AC97_SWITCH(xname, index, bitnr, invert) { \ | 547 | static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, |
548 | struct snd_ctl_elem_info *info) | ||
549 | { | ||
550 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
551 | info->count = 2; | ||
552 | info->value.integer.min = 0; | ||
553 | info->value.integer.max = 7; | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl, | ||
558 | struct snd_ctl_elem_value *value) | ||
559 | { | ||
560 | struct oxygen *chip = ctl->private_data; | ||
561 | u16 reg; | ||
562 | |||
563 | mutex_lock(&chip->mutex); | ||
564 | reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); | ||
565 | mutex_unlock(&chip->mutex); | ||
566 | value->value.integer.value[0] = reg & 7; | ||
567 | value->value.integer.value[1] = (reg >> 8) & 7; | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, | ||
572 | struct snd_ctl_elem_value *value) | ||
573 | { | ||
574 | struct oxygen *chip = ctl->private_data; | ||
575 | u16 oldreg, newreg; | ||
576 | int change; | ||
577 | |||
578 | mutex_lock(&chip->mutex); | ||
579 | oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); | ||
580 | newreg = oldreg & ~0x0707; | ||
581 | newreg = newreg | (value->value.integer.value[0] & 7); | ||
582 | newreg = newreg | ((value->value.integer.value[0] & 7) << 8); | ||
583 | change = newreg != oldreg; | ||
584 | if (change) | ||
585 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg); | ||
586 | mutex_unlock(&chip->mutex); | ||
587 | return change; | ||
588 | } | ||
589 | |||
590 | #define AC97_SWITCH(xname, codec, index, bitnr, invert) { \ | ||
544 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 591 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
545 | .name = xname, \ | 592 | .name = xname, \ |
546 | .info = snd_ctl_boolean_mono_info, \ | 593 | .info = snd_ctl_boolean_mono_info, \ |
547 | .get = ac97_switch_get, \ | 594 | .get = ac97_switch_get, \ |
548 | .put = ac97_switch_put, \ | 595 | .put = ac97_switch_put, \ |
549 | .private_value = ((invert) << 16) | ((bitnr) << 8) | (index), \ | 596 | .private_value = ((codec) << 24) | ((invert) << 16) | \ |
597 | ((bitnr) << 8) | (index), \ | ||
550 | } | 598 | } |
551 | #define AC97_VOLUME(xname, index) { \ | 599 | #define AC97_VOLUME(xname, codec, index) { \ |
552 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
553 | .name = xname, \ | 601 | .name = xname, \ |
602 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
603 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
554 | .info = ac97_volume_info, \ | 604 | .info = ac97_volume_info, \ |
555 | .get = ac97_volume_get, \ | 605 | .get = ac97_volume_get, \ |
556 | .put = ac97_volume_put, \ | 606 | .put = ac97_volume_put, \ |
557 | .tlv = { .p = ac97_db_scale, }, \ | 607 | .tlv = { .p = ac97_db_scale, }, \ |
558 | .private_value = (index), \ | 608 | .private_value = ((codec) << 24) | (index), \ |
559 | } | 609 | } |
560 | 610 | ||
561 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); | 611 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); |
612 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); | ||
562 | 613 | ||
563 | static const struct snd_kcontrol_new controls[] = { | 614 | static const struct snd_kcontrol_new controls[] = { |
564 | { | 615 | { |
@@ -642,15 +693,31 @@ static const struct snd_kcontrol_new controls[] = { | |||
642 | }; | 693 | }; |
643 | 694 | ||
644 | static const struct snd_kcontrol_new ac97_controls[] = { | 695 | static const struct snd_kcontrol_new ac97_controls[] = { |
645 | AC97_VOLUME("Mic Capture Volume", AC97_MIC), | 696 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC), |
646 | AC97_SWITCH("Mic Capture Switch", AC97_MIC, 15, 1), | 697 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), |
647 | AC97_SWITCH("Mic Boost (+20dB)", AC97_MIC, 6, 0), | 698 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), |
648 | AC97_VOLUME("Line Capture Volume", AC97_LINE), | 699 | AC97_VOLUME("Line Capture Volume", 0, AC97_LINE), |
649 | AC97_SWITCH("Line Capture Switch", AC97_LINE, 15, 1), | 700 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), |
650 | AC97_VOLUME("CD Capture Volume", AC97_CD), | 701 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD), |
651 | AC97_SWITCH("CD Capture Switch", AC97_CD, 15, 1), | 702 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), |
652 | AC97_VOLUME("Aux Capture Volume", AC97_AUX), | 703 | AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX), |
653 | AC97_SWITCH("Aux Capture Switch", AC97_AUX, 15, 1), | 704 | AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1), |
705 | }; | ||
706 | |||
707 | static const struct snd_kcontrol_new ac97_fp_controls[] = { | ||
708 | AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE), | ||
709 | AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1), | ||
710 | { | ||
711 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
712 | .name = "Front Panel Capture Volume", | ||
713 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
714 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
715 | .info = ac97_fp_rec_volume_info, | ||
716 | .get = ac97_fp_rec_volume_get, | ||
717 | .put = ac97_fp_rec_volume_put, | ||
718 | .tlv = { .p = ac97_rec_db_scale, }, | ||
719 | }, | ||
720 | AC97_SWITCH("Front Panel Capture Switch", 1, AC97_REC_GAIN, 15, 1), | ||
654 | }; | 721 | }; |
655 | 722 | ||
656 | static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) | 723 | static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) |
@@ -717,5 +784,11 @@ int oxygen_mixer_init(struct oxygen *chip) | |||
717 | if (err < 0) | 784 | if (err < 0) |
718 | return err; | 785 | return err; |
719 | } | 786 | } |
787 | if (chip->has_ac97_1) { | ||
788 | err = add_controls(chip, ac97_fp_controls, | ||
789 | ARRAY_SIZE(ac97_fp_controls)); | ||
790 | if (err < 0) | ||
791 | return err; | ||
792 | } | ||
720 | return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; | 793 | return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; |
721 | } | 794 | } |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 23bfab448844..2e1a6996fa86 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -247,9 +247,11 @@ static void mute_ac97_ctl(struct oxygen *chip, unsigned int control) | |||
247 | } | 247 | } |
248 | } | 248 | } |
249 | 249 | ||
250 | static void xonar_ac97_switch_hook(struct oxygen *chip, | 250 | static void xonar_ac97_switch_hook(struct oxygen *chip, unsigned int codec, |
251 | unsigned int reg, int mute) | 251 | unsigned int reg, int mute) |
252 | { | 252 | { |
253 | if (codec != 0) | ||
254 | return; | ||
253 | /* line-in is exclusive */ | 255 | /* line-in is exclusive */ |
254 | switch (reg) { | 256 | switch (reg) { |
255 | case AC97_LINE: | 257 | case AC97_LINE: |