diff options
Diffstat (limited to 'sound/pci/ac97/ac97_codec.c')
-rw-r--r-- | sound/pci/ac97/ac97_codec.c | 71 |
1 files changed, 46 insertions, 25 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 0b024ec1f709..a4b72cd2eea0 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -120,6 +120,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { | |||
120 | { 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, | 120 | { 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, |
121 | { 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, | 121 | { 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, |
122 | { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, | 122 | { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, |
123 | { 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL }, | ||
123 | { 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL }, | 124 | { 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL }, |
124 | { 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL }, | 125 | { 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL }, |
125 | { 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL }, | 126 | { 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL }, |
@@ -149,7 +150,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { | |||
149 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, | 150 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, |
150 | { 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, | 151 | { 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, |
151 | { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, | 152 | { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, |
152 | { 0x53494c20, 0xffffffe0, "Si3036,8", NULL, mpatch_si3036 }, | 153 | { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, |
153 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, | 154 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, |
154 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, | 155 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, |
155 | { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99] | 156 | { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99] |
@@ -462,12 +463,14 @@ int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u | |||
462 | { | 463 | { |
463 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 464 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
464 | struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; | 465 | struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; |
465 | unsigned short val; | 466 | unsigned short val, bitmask; |
466 | 467 | ||
468 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
469 | ; | ||
467 | val = snd_ac97_read_cache(ac97, e->reg); | 470 | val = snd_ac97_read_cache(ac97, e->reg); |
468 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1); | 471 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); |
469 | if (e->shift_l != e->shift_r) | 472 | if (e->shift_l != e->shift_r) |
470 | ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1); | 473 | ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1); |
471 | 474 | ||
472 | return 0; | 475 | return 0; |
473 | } | 476 | } |
@@ -477,17 +480,19 @@ int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u | |||
477 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 480 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
478 | struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; | 481 | struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; |
479 | unsigned short val; | 482 | unsigned short val; |
480 | unsigned short mask; | 483 | unsigned short mask, bitmask; |
481 | 484 | ||
485 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | ||
486 | ; | ||
482 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) | 487 | if (ucontrol->value.enumerated.item[0] > e->mask - 1) |
483 | return -EINVAL; | 488 | return -EINVAL; |
484 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | 489 | val = ucontrol->value.enumerated.item[0] << e->shift_l; |
485 | mask = (e->mask - 1) << e->shift_l; | 490 | mask = (bitmask - 1) << e->shift_l; |
486 | if (e->shift_l != e->shift_r) { | 491 | if (e->shift_l != e->shift_r) { |
487 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) | 492 | if (ucontrol->value.enumerated.item[1] > e->mask - 1) |
488 | return -EINVAL; | 493 | return -EINVAL; |
489 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | 494 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; |
490 | mask |= (e->mask - 1) << e->shift_r; | 495 | mask |= (bitmask - 1) << e->shift_r; |
491 | } | 496 | } |
492 | return snd_ac97_update_bits(ac97, e->reg, mask, val); | 497 | return snd_ac97_update_bits(ac97, e->reg, mask, val); |
493 | } | 498 | } |
@@ -658,14 +663,14 @@ AC97_SINGLE("LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 1, 1), | |||
658 | AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1) | 663 | AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1) |
659 | }; | 664 | }; |
660 | 665 | ||
661 | static const snd_kcontrol_new_t snd_ac97_controls_surround[2] = { | ||
662 | AC97_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), | ||
663 | AC97_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), | ||
664 | }; | ||
665 | |||
666 | static const snd_kcontrol_new_t snd_ac97_control_eapd = | 666 | static const snd_kcontrol_new_t snd_ac97_control_eapd = |
667 | AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); | 667 | AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); |
668 | 668 | ||
669 | static const snd_kcontrol_new_t snd_ac97_controls_modem_switches[2] = { | ||
670 | AC97_SINGLE("Off-hook Switch", AC97_GPIO_STATUS, 0, 1, 0), | ||
671 | AC97_SINGLE("Caller ID Switch", AC97_GPIO_STATUS, 2, 1, 0) | ||
672 | }; | ||
673 | |||
669 | /* change the existing EAPD control as inverted */ | 674 | /* change the existing EAPD control as inverted */ |
670 | static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl) | 675 | static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl) |
671 | { | 676 | { |
@@ -1072,9 +1077,9 @@ static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max | |||
1072 | unsigned short val; | 1077 | unsigned short val; |
1073 | snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8)); | 1078 | snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8)); |
1074 | val = snd_ac97_read(ac97, reg); | 1079 | val = snd_ac97_read(ac97, reg); |
1075 | if (! *lo_max && (val & cbit[i])) | 1080 | if (! *lo_max && (val & 0x7f) == cbit[i]) |
1076 | *lo_max = max[i]; | 1081 | *lo_max = max[i]; |
1077 | if (! *hi_max && (val & (cbit[i] << 8))) | 1082 | if (! *hi_max && ((val >> 8) & 0x7f) == cbit[i]) |
1078 | *hi_max = max[i]; | 1083 | *hi_max = max[i]; |
1079 | if (*lo_max && *hi_max) | 1084 | if (*lo_max && *hi_max) |
1080 | break; | 1085 | break; |
@@ -1526,13 +1531,25 @@ static int snd_ac97_mixer_build(ac97_t * ac97) | |||
1526 | 1531 | ||
1527 | static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97) | 1532 | static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97) |
1528 | { | 1533 | { |
1529 | /* TODO */ | 1534 | int err, idx; |
1535 | |||
1530 | //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG)); | 1536 | //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG)); |
1531 | snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH)); | 1537 | snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH)); |
1532 | snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH)); | 1538 | snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH)); |
1533 | snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff); | 1539 | snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff); |
1534 | snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0); | 1540 | snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0); |
1535 | snd_ac97_write(ac97, AC97_MISC_AFE, 0x0); | 1541 | snd_ac97_write(ac97, AC97_MISC_AFE, 0x0); |
1542 | |||
1543 | /* build modem switches */ | ||
1544 | for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++) | ||
1545 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_modem_switches[idx], ac97))) < 0) | ||
1546 | return err; | ||
1547 | |||
1548 | /* build chip specific controls */ | ||
1549 | if (ac97->build_ops->build_specific) | ||
1550 | if ((err = ac97->build_ops->build_specific(ac97)) < 0) | ||
1551 | return err; | ||
1552 | |||
1536 | return 0; | 1553 | return 0; |
1537 | } | 1554 | } |
1538 | 1555 | ||
@@ -1872,7 +1889,11 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) | |||
1872 | goto __access_ok; | 1889 | goto __access_ok; |
1873 | } | 1890 | } |
1874 | 1891 | ||
1875 | snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */ | 1892 | /* reset to defaults */ |
1893 | if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO)) | ||
1894 | snd_ac97_write(ac97, AC97_RESET, 0); | ||
1895 | if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM)) | ||
1896 | snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); | ||
1876 | if (bus->ops->wait) | 1897 | if (bus->ops->wait) |
1877 | bus->ops->wait(ac97); | 1898 | bus->ops->wait(ac97); |
1878 | else { | 1899 | else { |
@@ -1964,21 +1985,21 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) | |||
1964 | /* note: it's important to set the rate at first */ | 1985 | /* note: it's important to set the rate at first */ |
1965 | tmp = AC97_MEA_GPIO; | 1986 | tmp = AC97_MEA_GPIO; |
1966 | if (ac97->ext_mid & AC97_MEI_LINE1) { | 1987 | if (ac97->ext_mid & AC97_MEI_LINE1) { |
1967 | snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); | 1988 | snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 8000); |
1968 | tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; | 1989 | tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; |
1969 | } | 1990 | } |
1970 | if (ac97->ext_mid & AC97_MEI_LINE2) { | 1991 | if (ac97->ext_mid & AC97_MEI_LINE2) { |
1971 | snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); | 1992 | snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 8000); |
1972 | tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; | 1993 | tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; |
1973 | } | 1994 | } |
1974 | if (ac97->ext_mid & AC97_MEI_HANDSET) { | 1995 | if (ac97->ext_mid & AC97_MEI_HANDSET) { |
1975 | snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); | 1996 | snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 8000); |
1976 | tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; | 1997 | tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; |
1977 | } | 1998 | } |
1978 | snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); | 1999 | snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); |
1979 | udelay(100); | 2000 | udelay(100); |
1980 | /* nothing should be in powerdown mode */ | 2001 | /* nothing should be in powerdown mode */ |
1981 | snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); | 2002 | snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); |
1982 | end_time = jiffies + (HZ / 10); | 2003 | end_time = jiffies + (HZ / 10); |
1983 | do { | 2004 | do { |
1984 | if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) | 2005 | if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) |
@@ -2521,11 +2542,11 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o | |||
2521 | return result; | 2542 | return result; |
2522 | } | 2543 | } |
2523 | 2544 | ||
2524 | for (; quirk->vendor; quirk++) { | 2545 | for (; quirk->subvendor; quirk++) { |
2525 | if (quirk->vendor != ac97->subsystem_vendor) | 2546 | if (quirk->subvendor != ac97->subsystem_vendor) |
2526 | continue; | 2547 | continue; |
2527 | if ((! quirk->mask && quirk->device == ac97->subsystem_device) || | 2548 | if ((! quirk->mask && quirk->subdevice == ac97->subsystem_device) || |
2528 | quirk->device == (quirk->mask & ac97->subsystem_device)) { | 2549 | quirk->subdevice == (quirk->mask & ac97->subsystem_device)) { |
2529 | if (quirk->codec_id && quirk->codec_id != ac97->id) | 2550 | if (quirk->codec_id && quirk->codec_id != ac97->id) |
2530 | continue; | 2551 | continue; |
2531 | snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device); | 2552 | snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device); |