diff options
Diffstat (limited to 'sound/pci/oxygen/oxygen_mixer.c')
| -rw-r--r-- | sound/pci/oxygen/oxygen_mixer.c | 217 |
1 files changed, 211 insertions, 6 deletions
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index a8e4623415d9..cc0cddadd589 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
| @@ -32,8 +32,8 @@ static int dac_volume_info(struct snd_kcontrol *ctl, | |||
| 32 | 32 | ||
| 33 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 33 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
| 34 | info->count = chip->model->dac_channels; | 34 | info->count = chip->model->dac_channels; |
| 35 | info->value.integer.min = 0; | 35 | info->value.integer.min = chip->model->dac_volume_min; |
| 36 | info->value.integer.max = 0xff; | 36 | info->value.integer.max = chip->model->dac_volume_max; |
| 37 | return 0; | 37 | return 0; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| @@ -446,6 +446,50 @@ static int spdif_loopback_put(struct snd_kcontrol *ctl, | |||
| 446 | return changed; | 446 | return changed; |
| 447 | } | 447 | } |
| 448 | 448 | ||
| 449 | static int monitor_volume_info(struct snd_kcontrol *ctl, | ||
| 450 | struct snd_ctl_elem_info *info) | ||
| 451 | { | ||
| 452 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 453 | info->count = 1; | ||
| 454 | info->value.integer.min = 0; | ||
| 455 | info->value.integer.max = 1; | ||
| 456 | return 0; | ||
| 457 | } | ||
| 458 | |||
| 459 | static int monitor_get(struct snd_kcontrol *ctl, | ||
| 460 | struct snd_ctl_elem_value *value) | ||
| 461 | { | ||
| 462 | struct oxygen *chip = ctl->private_data; | ||
| 463 | u8 bit = ctl->private_value; | ||
| 464 | int invert = ctl->private_value & (1 << 8); | ||
| 465 | |||
| 466 | value->value.integer.value[0] = | ||
| 467 | !!invert ^ !!(oxygen_read8(chip, OXYGEN_ADC_MONITOR) & bit); | ||
| 468 | return 0; | ||
| 469 | } | ||
| 470 | |||
| 471 | static int monitor_put(struct snd_kcontrol *ctl, | ||
| 472 | struct snd_ctl_elem_value *value) | ||
| 473 | { | ||
| 474 | struct oxygen *chip = ctl->private_data; | ||
| 475 | u8 bit = ctl->private_value; | ||
| 476 | int invert = ctl->private_value & (1 << 8); | ||
| 477 | u8 oldreg, newreg; | ||
| 478 | int changed; | ||
| 479 | |||
| 480 | spin_lock_irq(&chip->reg_lock); | ||
| 481 | oldreg = oxygen_read8(chip, OXYGEN_ADC_MONITOR); | ||
| 482 | if ((!!value->value.integer.value[0] ^ !!invert) != 0) | ||
| 483 | newreg = oldreg | bit; | ||
| 484 | else | ||
| 485 | newreg = oldreg & ~bit; | ||
| 486 | changed = newreg != oldreg; | ||
| 487 | if (changed) | ||
| 488 | oxygen_write8(chip, OXYGEN_ADC_MONITOR, newreg); | ||
| 489 | spin_unlock_irq(&chip->reg_lock); | ||
| 490 | return changed; | ||
| 491 | } | ||
| 492 | |||
| 449 | static int ac97_switch_get(struct snd_kcontrol *ctl, | 493 | static int ac97_switch_get(struct snd_kcontrol *ctl, |
| 450 | struct snd_ctl_elem_value *value) | 494 | struct snd_ctl_elem_value *value) |
| 451 | { | 495 | { |
| @@ -466,6 +510,21 @@ static int ac97_switch_get(struct snd_kcontrol *ctl, | |||
| 466 | return 0; | 510 | return 0; |
| 467 | } | 511 | } |
| 468 | 512 | ||
| 513 | static void mute_ac97_ctl(struct oxygen *chip, unsigned int control) | ||
| 514 | { | ||
| 515 | unsigned int priv_idx = chip->controls[control]->private_value & 0xff; | ||
| 516 | u16 value; | ||
| 517 | |||
| 518 | value = oxygen_read_ac97(chip, 0, priv_idx); | ||
| 519 | if (!(value & 0x8000)) { | ||
| 520 | oxygen_write_ac97(chip, 0, priv_idx, value | 0x8000); | ||
| 521 | if (chip->model->ac97_switch) | ||
| 522 | chip->model->ac97_switch(chip, priv_idx, 0x8000); | ||
| 523 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 524 | &chip->controls[control]->id); | ||
| 525 | } | ||
| 526 | } | ||
| 527 | |||
| 469 | static int ac97_switch_put(struct snd_kcontrol *ctl, | 528 | static int ac97_switch_put(struct snd_kcontrol *ctl, |
| 470 | struct snd_ctl_elem_value *value) | 529 | struct snd_ctl_elem_value *value) |
| 471 | { | 530 | { |
| @@ -487,9 +546,24 @@ static int ac97_switch_put(struct snd_kcontrol *ctl, | |||
| 487 | change = newreg != oldreg; | 546 | change = newreg != oldreg; |
| 488 | if (change) { | 547 | if (change) { |
| 489 | oxygen_write_ac97(chip, codec, index, newreg); | 548 | oxygen_write_ac97(chip, codec, index, newreg); |
| 490 | if (bitnr == 15 && chip->model->ac97_switch_hook) | 549 | if (codec == 0 && chip->model->ac97_switch) |
| 491 | chip->model->ac97_switch_hook(chip, codec, index, | 550 | chip->model->ac97_switch(chip, index, newreg & 0x8000); |
| 492 | newreg & 0x8000); | 551 | if (index == AC97_LINE) { |
| 552 | oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, | ||
| 553 | newreg & 0x8000 ? | ||
| 554 | CM9780_GPO0 : 0, CM9780_GPO0); | ||
| 555 | if (!(newreg & 0x8000)) { | ||
| 556 | mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH); | ||
| 557 | mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH); | ||
| 558 | mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH); | ||
| 559 | } | ||
| 560 | } else if ((index == AC97_MIC || index == AC97_CD || | ||
| 561 | index == AC97_VIDEO || index == AC97_AUX) && | ||
| 562 | bitnr == 15 && !(newreg & 0x8000)) { | ||
| 563 | mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH); | ||
| 564 | oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, | ||
| 565 | CM9780_GPO0, CM9780_GPO0); | ||
| 566 | } | ||
| 493 | } | 567 | } |
| 494 | mutex_unlock(&chip->mutex); | 568 | mutex_unlock(&chip->mutex); |
| 495 | return change; | 569 | return change; |
| @@ -608,6 +682,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, | |||
| 608 | .private_value = ((codec) << 24) | (index), \ | 682 | .private_value = ((codec) << 24) | (index), \ |
| 609 | } | 683 | } |
| 610 | 684 | ||
| 685 | static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0); | ||
| 611 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); | 686 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); |
| 612 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); | 687 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); |
| 613 | 688 | ||
| @@ -667,6 +742,9 @@ static const struct snd_kcontrol_new controls[] = { | |||
| 667 | .get = spdif_pcm_get, | 742 | .get = spdif_pcm_get, |
| 668 | .put = spdif_pcm_put, | 743 | .put = spdif_pcm_put, |
| 669 | }, | 744 | }, |
| 745 | }; | ||
| 746 | |||
| 747 | static const struct snd_kcontrol_new spdif_input_controls[] = { | ||
| 670 | { | 748 | { |
| 671 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 749 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 672 | .device = 1, | 750 | .device = 1, |
| @@ -692,11 +770,118 @@ static const struct snd_kcontrol_new controls[] = { | |||
| 692 | }, | 770 | }, |
| 693 | }; | 771 | }; |
| 694 | 772 | ||
| 773 | static const struct { | ||
| 774 | unsigned int pcm_dev; | ||
| 775 | struct snd_kcontrol_new controls[2]; | ||
| 776 | } monitor_controls[] = { | ||
| 777 | { | ||
| 778 | .pcm_dev = CAPTURE_0_FROM_I2S_1, | ||
| 779 | .controls = { | ||
| 780 | { | ||
| 781 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 782 | .name = "Analog Input Monitor Switch", | ||
| 783 | .info = snd_ctl_boolean_mono_info, | ||
| 784 | .get = monitor_get, | ||
| 785 | .put = monitor_put, | ||
| 786 | .private_value = OXYGEN_ADC_MONITOR_A, | ||
| 787 | }, | ||
| 788 | { | ||
| 789 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 790 | .name = "Analog Input Monitor Volume", | ||
| 791 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 792 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
| 793 | .info = monitor_volume_info, | ||
| 794 | .get = monitor_get, | ||
| 795 | .put = monitor_put, | ||
| 796 | .private_value = OXYGEN_ADC_MONITOR_A_HALF_VOL | ||
| 797 | | (1 << 8), | ||
| 798 | .tlv = { .p = monitor_db_scale, }, | ||
| 799 | }, | ||
| 800 | }, | ||
| 801 | }, | ||
| 802 | { | ||
| 803 | .pcm_dev = CAPTURE_0_FROM_I2S_2, | ||
| 804 | .controls = { | ||
| 805 | { | ||
| 806 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 807 | .name = "Analog Input Monitor Switch", | ||
| 808 | .info = snd_ctl_boolean_mono_info, | ||
| 809 | .get = monitor_get, | ||
| 810 | .put = monitor_put, | ||
| 811 | .private_value = OXYGEN_ADC_MONITOR_B, | ||
| 812 | }, | ||
| 813 | { | ||
| 814 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 815 | .name = "Analog Input Monitor Volume", | ||
| 816 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 817 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
| 818 | .info = monitor_volume_info, | ||
| 819 | .get = monitor_get, | ||
| 820 | .put = monitor_put, | ||
| 821 | .private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL | ||
| 822 | | (1 << 8), | ||
| 823 | .tlv = { .p = monitor_db_scale, }, | ||
| 824 | }, | ||
| 825 | }, | ||
| 826 | }, | ||
| 827 | { | ||
| 828 | .pcm_dev = CAPTURE_2_FROM_I2S_2, | ||
| 829 | .controls = { | ||
| 830 | { | ||
| 831 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 832 | .name = "Analog Input Monitor Switch", | ||
| 833 | .index = 1, | ||
| 834 | .info = snd_ctl_boolean_mono_info, | ||
| 835 | .get = monitor_get, | ||
| 836 | .put = monitor_put, | ||
| 837 | .private_value = OXYGEN_ADC_MONITOR_B, | ||
| 838 | }, | ||
| 839 | { | ||
| 840 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 841 | .name = "Analog Input Monitor Volume", | ||
| 842 | .index = 1, | ||
| 843 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 844 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
| 845 | .info = monitor_volume_info, | ||
| 846 | .get = monitor_get, | ||
| 847 | .put = monitor_put, | ||
| 848 | .private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL | ||
| 849 | | (1 << 8), | ||
| 850 | .tlv = { .p = monitor_db_scale, }, | ||
| 851 | }, | ||
| 852 | }, | ||
| 853 | }, | ||
| 854 | { | ||
| 855 | .pcm_dev = CAPTURE_1_FROM_SPDIF, | ||
| 856 | .controls = { | ||
| 857 | { | ||
| 858 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 859 | .name = "Digital Input Monitor Switch", | ||
| 860 | .info = snd_ctl_boolean_mono_info, | ||
| 861 | .get = monitor_get, | ||
| 862 | .put = monitor_put, | ||
| 863 | .private_value = OXYGEN_ADC_MONITOR_C, | ||
| 864 | }, | ||
| 865 | { | ||
| 866 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 867 | .name = "Digital Input Monitor Volume", | ||
| 868 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 869 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
| 870 | .info = monitor_volume_info, | ||
| 871 | .get = monitor_get, | ||
| 872 | .put = monitor_put, | ||
| 873 | .private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL | ||
| 874 | | (1 << 8), | ||
| 875 | .tlv = { .p = monitor_db_scale, }, | ||
| 876 | }, | ||
| 877 | }, | ||
| 878 | }, | ||
| 879 | }; | ||
| 880 | |||
| 695 | static const struct snd_kcontrol_new ac97_controls[] = { | 881 | static const struct snd_kcontrol_new ac97_controls[] = { |
| 696 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC), | 882 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC), |
| 697 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), | 883 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), |
| 698 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), | 884 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), |
| 699 | AC97_VOLUME("Line Capture Volume", 0, AC97_LINE), | ||
| 700 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), | 885 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), |
| 701 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD), | 886 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD), |
| 702 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), | 887 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), |
| @@ -756,6 +941,11 @@ static int add_controls(struct oxygen *chip, | |||
| 756 | return err; | 941 | return err; |
| 757 | if (err == 1) | 942 | if (err == 1) |
| 758 | continue; | 943 | continue; |
| 944 | if (!strcmp(template.name, "Master Playback Volume") && | ||
| 945 | chip->model->dac_tlv) { | ||
| 946 | template.tlv.p = chip->model->dac_tlv; | ||
| 947 | template.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
| 948 | } | ||
| 759 | ctl = snd_ctl_new1(&template, chip); | 949 | ctl = snd_ctl_new1(&template, chip); |
| 760 | if (!ctl) | 950 | if (!ctl) |
| 761 | return -ENOMEM; | 951 | return -ENOMEM; |
| @@ -773,11 +963,26 @@ static int add_controls(struct oxygen *chip, | |||
| 773 | 963 | ||
| 774 | int oxygen_mixer_init(struct oxygen *chip) | 964 | int oxygen_mixer_init(struct oxygen *chip) |
| 775 | { | 965 | { |
| 966 | unsigned int i; | ||
| 776 | int err; | 967 | int err; |
| 777 | 968 | ||
| 778 | err = add_controls(chip, controls, ARRAY_SIZE(controls)); | 969 | err = add_controls(chip, controls, ARRAY_SIZE(controls)); |
| 779 | if (err < 0) | 970 | if (err < 0) |
| 780 | return err; | 971 | return err; |
| 972 | if (chip->model->pcm_dev_cfg & CAPTURE_1_FROM_SPDIF) { | ||
| 973 | err = add_controls(chip, spdif_input_controls, | ||
| 974 | ARRAY_SIZE(spdif_input_controls)); | ||
| 975 | if (err < 0) | ||
| 976 | return err; | ||
| 977 | } | ||
| 978 | for (i = 0; i < ARRAY_SIZE(monitor_controls); ++i) { | ||
| 979 | if (!(chip->model->pcm_dev_cfg & monitor_controls[i].pcm_dev)) | ||
| 980 | continue; | ||
| 981 | err = add_controls(chip, monitor_controls[i].controls, | ||
| 982 | ARRAY_SIZE(monitor_controls[i].controls)); | ||
| 983 | if (err < 0) | ||
| 984 | return err; | ||
| 985 | } | ||
| 781 | if (chip->has_ac97_0) { | 986 | if (chip->has_ac97_0) { |
| 782 | err = add_controls(chip, ac97_controls, | 987 | err = add_controls(chip, ac97_controls, |
| 783 | ARRAY_SIZE(ac97_controls)); | 988 | ARRAY_SIZE(ac97_controls)); |
