diff options
author | James Courtier-Dutton <James@superbug.co.uk> | 2006-12-06 10:58:02 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2007-02-09 03:02:17 -0500 |
commit | 184c1e2c4c4221c2b8d1e16c33314595373fa73f (patch) | |
tree | f041f147ba8c92e5587163d0b76863fdf4f0318b /sound/pci/emu10k1/emumixer.c | |
parent | 9ed1261e3e617d99b0eb74041d0337ff664e4f5b (diff) |
[ALSA] emu10k1: Add Audio capture support for Audigy 2 ZS Notebook.
Implement functionallity in order to fixe ALSA bug#2058.
Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/emu10k1/emumixer.c')
-rw-r--r-- | sound/pci/emu10k1/emumixer.c | 201 |
1 files changed, 200 insertions, 1 deletions
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 9b7fd564343e..b8221f385ff9 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
@@ -36,9 +36,14 @@ | |||
36 | #include <sound/core.h> | 36 | #include <sound/core.h> |
37 | #include <sound/emu10k1.h> | 37 | #include <sound/emu10k1.h> |
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <sound/tlv.h> | ||
40 | |||
41 | #include "p17v.h" | ||
39 | 42 | ||
40 | #define AC97_ID_STAC9758 0x83847658 | 43 | #define AC97_ID_STAC9758 0x83847658 |
41 | 44 | ||
45 | static DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ | ||
46 | |||
42 | static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 47 | static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
43 | { | 48 | { |
44 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | 49 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
@@ -579,6 +584,162 @@ static struct snd_kcontrol_new snd_emu1010_internal_clock = | |||
579 | .put = snd_emu1010_internal_clock_put | 584 | .put = snd_emu1010_internal_clock_put |
580 | }; | 585 | }; |
581 | 586 | ||
587 | static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, | ||
588 | struct snd_ctl_elem_info *uinfo) | ||
589 | { | ||
590 | #if 0 | ||
591 | static char *texts[4] = { | ||
592 | "Unknown1", "Unknown2", "Mic", "Line" | ||
593 | }; | ||
594 | #endif | ||
595 | static char *texts[2] = { | ||
596 | "Mic", "Line" | ||
597 | }; | ||
598 | |||
599 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
600 | uinfo->count = 1; | ||
601 | uinfo->value.enumerated.items = 2; | ||
602 | if (uinfo->value.enumerated.item > 1) | ||
603 | uinfo->value.enumerated.item = 1; | ||
604 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, | ||
609 | struct snd_ctl_elem_value *ucontrol) | ||
610 | { | ||
611 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
612 | |||
613 | ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | ||
618 | struct snd_ctl_elem_value *ucontrol) | ||
619 | { | ||
620 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
621 | unsigned int source_id; | ||
622 | unsigned int ngain, ogain; | ||
623 | u32 gpio; | ||
624 | int change = 0; | ||
625 | unsigned long flags; | ||
626 | u32 source; | ||
627 | /* If the capture source has changed, | ||
628 | * update the capture volume from the cached value | ||
629 | * for the particular source. | ||
630 | */ | ||
631 | source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */ | ||
632 | change = (emu->i2c_capture_source != source_id); | ||
633 | if (change) { | ||
634 | snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | ||
635 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
636 | gpio = inl(emu->port + A_IOCFG); | ||
637 | if (source_id==0) | ||
638 | outl(gpio | 0x4, emu->port + A_IOCFG); | ||
639 | else | ||
640 | outl(gpio & ~0x4, emu->port + A_IOCFG); | ||
641 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
642 | |||
643 | ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
644 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ | ||
645 | if (ngain != ogain) | ||
646 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); | ||
647 | ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ | ||
648 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ | ||
649 | if (ngain != ogain) | ||
650 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
651 | |||
652 | source = 1 << (source_id + 2); | ||
653 | snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ | ||
654 | emu->i2c_capture_source = source_id; | ||
655 | } | ||
656 | return change; | ||
657 | } | ||
658 | |||
659 | static struct snd_kcontrol_new snd_audigy_i2c_capture_source = | ||
660 | { | ||
661 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
662 | .name = "Capture Source", | ||
663 | .info = snd_audigy_i2c_capture_source_info, | ||
664 | .get = snd_audigy_i2c_capture_source_get, | ||
665 | .put = snd_audigy_i2c_capture_source_put | ||
666 | }; | ||
667 | |||
668 | static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, | ||
669 | struct snd_ctl_elem_info *uinfo) | ||
670 | { | ||
671 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
672 | uinfo->count = 2; | ||
673 | uinfo->value.integer.min = 0; | ||
674 | uinfo->value.integer.max = 255; | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, | ||
679 | struct snd_ctl_elem_value *ucontrol) | ||
680 | { | ||
681 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
682 | int source_id; | ||
683 | |||
684 | source_id = kcontrol->private_value; | ||
685 | |||
686 | ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; | ||
687 | ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, | ||
692 | struct snd_ctl_elem_value *ucontrol) | ||
693 | { | ||
694 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
695 | unsigned int ogain; | ||
696 | unsigned int ngain; | ||
697 | int source_id; | ||
698 | int change = 0; | ||
699 | |||
700 | source_id = kcontrol->private_value; | ||
701 | ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
702 | ngain = ucontrol->value.integer.value[0]; | ||
703 | if (ngain > 0xff) | ||
704 | return 0; | ||
705 | if (ogain != ngain) { | ||
706 | if (emu->i2c_capture_source == source_id) | ||
707 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); | ||
708 | emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; | ||
709 | change = 1; | ||
710 | } | ||
711 | ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ | ||
712 | ngain = ucontrol->value.integer.value[1]; | ||
713 | if (ngain > 0xff) | ||
714 | return 0; | ||
715 | if (ogain != ngain) { | ||
716 | if (emu->i2c_capture_source == source_id) | ||
717 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
718 | emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; | ||
719 | change = 1; | ||
720 | } | ||
721 | |||
722 | return change; | ||
723 | } | ||
724 | |||
725 | #define I2C_VOLUME(xname,chid) \ | ||
726 | { \ | ||
727 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
728 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
729 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
730 | .info = snd_audigy_i2c_volume_info, \ | ||
731 | .get = snd_audigy_i2c_volume_get, \ | ||
732 | .put = snd_audigy_i2c_volume_put, \ | ||
733 | .tlv = { .p = snd_audigy_db_scale2 }, \ | ||
734 | .private_value = chid \ | ||
735 | } | ||
736 | |||
737 | |||
738 | static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { | ||
739 | I2C_VOLUME("Mic Capture Volume", 0), | ||
740 | I2C_VOLUME("Line Capture Volume", 0) | ||
741 | }; | ||
742 | |||
582 | #if 0 | 743 | #if 0 |
583 | static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 744 | static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
584 | { | 745 | { |
@@ -1179,7 +1340,9 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
1179 | int change = 0; | 1340 | int change = 0; |
1180 | 1341 | ||
1181 | spin_lock_irqsave(&emu->reg_lock, flags); | 1342 | spin_lock_irqsave(&emu->reg_lock, flags); |
1182 | if (emu->audigy) { | 1343 | if ( emu->card_capabilities->i2c_adc) { |
1344 | /* Do nothing for Audigy 2 ZS Notebook */ | ||
1345 | } else if (emu->audigy) { | ||
1183 | reg = inl(emu->port + A_IOCFG); | 1346 | reg = inl(emu->port + A_IOCFG); |
1184 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; | 1347 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; |
1185 | change = (reg & A_IOCFG_GPOUT0) != val; | 1348 | change = (reg & A_IOCFG_GPOUT0) != val; |
@@ -1317,6 +1480,22 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1317 | "AMic Playback Volume", "Mic Playback Volume", | 1480 | "AMic Playback Volume", "Mic Playback Volume", |
1318 | NULL | 1481 | NULL |
1319 | }; | 1482 | }; |
1483 | static char *audigy_rename_ctls_i2c_adc[] = { | ||
1484 | //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", | ||
1485 | "Line Capture Volume", "Analog Mix Capture Volume", | ||
1486 | "Wave Playback Volume", "OLD PCM Playback Volume", | ||
1487 | "Wave Master Playback Volume", "Master Playback Volume", | ||
1488 | "AMic Playback Volume", "Old Mic Playback Volume", | ||
1489 | NULL | ||
1490 | }; | ||
1491 | static char *audigy_remove_ctls_i2c_adc[] = { | ||
1492 | /* On the Audigy2 ZS Notebook | ||
1493 | * Capture via WM8775 */ | ||
1494 | "Mic Capture Volume", | ||
1495 | "Analog Mix Capture Volume", | ||
1496 | "Aux Capture Volume", | ||
1497 | NULL | ||
1498 | }; | ||
1320 | static char *audigy_remove_ctls_1361t_adc[] = { | 1499 | static char *audigy_remove_ctls_1361t_adc[] = { |
1321 | /* On the Audigy2 the AC97 playback is piped into | 1500 | /* On the Audigy2 the AC97 playback is piped into |
1322 | * the Philips ADC for 24bit capture */ | 1501 | * the Philips ADC for 24bit capture */ |
@@ -1409,6 +1588,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1409 | } | 1588 | } |
1410 | for (; *c; c++) | 1589 | for (; *c; c++) |
1411 | remove_ctl(card, *c); | 1590 | remove_ctl(card, *c); |
1591 | } else if (emu->card_capabilities->i2c_adc) { | ||
1592 | c = audigy_remove_ctls_i2c_adc; | ||
1593 | for (; *c; c++) | ||
1594 | remove_ctl(card, *c); | ||
1412 | } else { | 1595 | } else { |
1413 | no_ac97: | 1596 | no_ac97: |
1414 | if (emu->card_capabilities->ecard) | 1597 | if (emu->card_capabilities->ecard) |
@@ -1422,6 +1605,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1422 | if (emu->audigy) | 1605 | if (emu->audigy) |
1423 | if (emu->card_capabilities->adc_1361t) | 1606 | if (emu->card_capabilities->adc_1361t) |
1424 | c = audigy_rename_ctls_1361t_adc; | 1607 | c = audigy_rename_ctls_1361t_adc; |
1608 | else if (emu->card_capabilities->i2c_adc) | ||
1609 | c = audigy_rename_ctls_i2c_adc; | ||
1425 | else | 1610 | else |
1426 | c = audigy_rename_ctls; | 1611 | c = audigy_rename_ctls; |
1427 | else | 1612 | else |
@@ -1584,6 +1769,20 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1584 | if (err < 0) | 1769 | if (err < 0) |
1585 | return err; | 1770 | return err; |
1586 | } | 1771 | } |
1772 | |||
1773 | if ( emu->card_capabilities->i2c_adc) { | ||
1774 | int i; | ||
1775 | |||
1776 | err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); | ||
1777 | if (err < 0) | ||
1778 | return err; | ||
1779 | |||
1780 | for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { | ||
1781 | err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); | ||
1782 | if (err < 0) | ||
1783 | return err; | ||
1784 | } | ||
1785 | } | ||
1587 | 1786 | ||
1588 | return 0; | 1787 | return 0; |
1589 | } | 1788 | } |