diff options
-rw-r--r-- | sound/pci/ac97/ac97_codec.c | 17 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 143 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_patch.h | 1 |
3 files changed, 137 insertions, 24 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 4ece2053bb13..61549b1eb59a 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 }, |
@@ -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 | } |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 13c34a5d8206..473840d431b3 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -2087,12 +2087,13 @@ int patch_cm9739(ac97_t * ac97) | |||
2087 | } | 2087 | } |
2088 | 2088 | ||
2089 | #define AC97_CM9761_MULTI_CHAN 0x64 | 2089 | #define AC97_CM9761_MULTI_CHAN 0x64 |
2090 | #define AC97_CM9761_FUNC 0x66 | ||
2090 | #define AC97_CM9761_SPDIF_CTRL 0x6c | 2091 | #define AC97_CM9761_SPDIF_CTRL 0x6c |
2091 | 2092 | ||
2092 | static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2093 | static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
2093 | { | 2094 | { |
2094 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2095 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
2095 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x0400) | 2096 | if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x0400) |
2096 | ucontrol->value.integer.value[0] = 1; | 2097 | ucontrol->value.integer.value[0] = 1; |
2097 | else | 2098 | else |
2098 | ucontrol->value.integer.value[0] = 0; | 2099 | ucontrol->value.integer.value[0] = 0; |
@@ -2106,14 +2107,14 @@ static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_el | |||
2106 | { 0x0008, 0x0400 }, /* off, on */ | 2107 | { 0x0008, 0x0400 }, /* off, on */ |
2107 | { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ | 2108 | { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ |
2108 | }; | 2109 | }; |
2109 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x0408, | 2110 | return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, |
2110 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); | 2111 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); |
2111 | } | 2112 | } |
2112 | 2113 | ||
2113 | static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2114 | static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
2114 | { | 2115 | { |
2115 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2116 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
2116 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) | 2117 | if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x1000) |
2117 | ucontrol->value.integer.value[0] = 1; | 2118 | ucontrol->value.integer.value[0] = 1; |
2118 | else | 2119 | else |
2119 | ucontrol->value.integer.value[0] = 0; | 2120 | ucontrol->value.integer.value[0] = 0; |
@@ -2129,7 +2130,7 @@ static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_ele | |||
2129 | { 0x2000, 0x1880 }, /* off, on */ | 2130 | { 0x2000, 0x1880 }, /* off, on */ |
2130 | { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ | 2131 | { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ |
2131 | }; | 2132 | }; |
2132 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3880, | 2133 | return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, |
2133 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); | 2134 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); |
2134 | } | 2135 | } |
2135 | 2136 | ||
@@ -2152,6 +2153,70 @@ static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { | |||
2152 | }, | 2153 | }, |
2153 | }; | 2154 | }; |
2154 | 2155 | ||
2156 | static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
2157 | { | ||
2158 | static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" }; | ||
2159 | |||
2160 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2161 | uinfo->count = 1; | ||
2162 | uinfo->value.enumerated.items = 3; | ||
2163 | if (uinfo->value.enumerated.item > 2) | ||
2164 | uinfo->value.enumerated.item = 2; | ||
2165 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
2166 | return 0; | ||
2167 | } | ||
2168 | |||
2169 | static int cm9761_spdif_out_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
2170 | { | ||
2171 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
2172 | |||
2173 | if (ac97->regs[AC97_CM9761_FUNC] & 0x1) | ||
2174 | ucontrol->value.enumerated.item[0] = 2; /* SPDIF-loopback */ | ||
2175 | else if (ac97->regs[AC97_CM9761_SPDIF_CTRL] & 0x2) | ||
2176 | ucontrol->value.enumerated.item[0] = 1; /* ADC loopback */ | ||
2177 | else | ||
2178 | ucontrol->value.enumerated.item[0] = 0; /* AC-link */ | ||
2179 | return 0; | ||
2180 | } | ||
2181 | |||
2182 | static int cm9761_spdif_out_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
2183 | { | ||
2184 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
2185 | |||
2186 | if (ucontrol->value.enumerated.item[0] == 2) | ||
2187 | return snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0x1); | ||
2188 | snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0); | ||
2189 | return snd_ac97_update_bits(ac97, AC97_CM9761_SPDIF_CTRL, 0x2, | ||
2190 | ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0); | ||
2191 | } | ||
2192 | |||
2193 | static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" }; | ||
2194 | static const struct ac97_enum cm9761_dac_clock_enum = | ||
2195 | AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock); | ||
2196 | |||
2197 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls_spdif[] = { | ||
2198 | { /* BIT 1: SPDIFS */ | ||
2199 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2200 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
2201 | .info = cm9761_spdif_out_source_info, | ||
2202 | .get = cm9761_spdif_out_source_get, | ||
2203 | .put = cm9761_spdif_out_source_put, | ||
2204 | }, | ||
2205 | /* BIT 2: IG_SPIV */ | ||
2206 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9761_SPDIF_CTRL, 2, 1, 0), | ||
2207 | /* BIT 3: SPI2F */ | ||
2208 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9761_SPDIF_CTRL, 3, 1, 0), | ||
2209 | /* BIT 4: SPI2SDI */ | ||
2210 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9761_SPDIF_CTRL, 4, 1, 0), | ||
2211 | /* BIT 9-10: DAC_CTL */ | ||
2212 | AC97_ENUM("DAC Clock Source", cm9761_dac_clock_enum), | ||
2213 | }; | ||
2214 | |||
2215 | static int patch_cm9761_post_spdif(ac97_t * ac97) | ||
2216 | { | ||
2217 | return patch_build_controls(ac97, snd_ac97_cm9761_controls_spdif, ARRAY_SIZE(snd_ac97_cm9761_controls_spdif)); | ||
2218 | } | ||
2219 | |||
2155 | static int patch_cm9761_specific(ac97_t * ac97) | 2220 | static int patch_cm9761_specific(ac97_t * ac97) |
2156 | { | 2221 | { |
2157 | return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); | 2222 | return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); |
@@ -2159,7 +2224,7 @@ static int patch_cm9761_specific(ac97_t * ac97) | |||
2159 | 2224 | ||
2160 | static struct snd_ac97_build_ops patch_cm9761_ops = { | 2225 | static struct snd_ac97_build_ops patch_cm9761_ops = { |
2161 | .build_specific = patch_cm9761_specific, | 2226 | .build_specific = patch_cm9761_specific, |
2162 | .build_post_spdif = patch_cm9739_post_spdif /* hope it's identical... */ | 2227 | .build_post_spdif = patch_cm9761_post_spdif |
2163 | }; | 2228 | }; |
2164 | 2229 | ||
2165 | int patch_cm9761(ac97_t *ac97) | 2230 | int patch_cm9761(ac97_t *ac97) |
@@ -2193,24 +2258,25 @@ int patch_cm9761(ac97_t *ac97) | |||
2193 | /* to be sure: we overwrite the ext status bits */ | 2258 | /* to be sure: we overwrite the ext status bits */ |
2194 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); | 2259 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); |
2195 | /* Don't set 0x0200 here. This results in the silent analog output */ | 2260 | /* Don't set 0x0200 here. This results in the silent analog output */ |
2196 | snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009); | 2261 | snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0001); /* enable spdif-in */ |
2197 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ | 2262 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ |
2198 | 2263 | ||
2199 | /* set-up multi channel */ | 2264 | /* set-up multi channel */ |
2200 | /* bit 15: pc master beep off | 2265 | /* bit 15: pc master beep off |
2201 | * bit 14: ?? | 2266 | * bit 14: pin47 = EAPD/SPDIF |
2202 | * bit 13: vref ctl [= cm9739] | 2267 | * bit 13: vref ctl [= cm9739] |
2203 | * bit 12: center/mic [= cm9739] (reverted on rev B) | 2268 | * bit 12: CLFE control (reverted on rev B) |
2204 | * bit 11: ?? (mic/center/lfe) (reverted on rev B) | 2269 | * bit 11: Mic/center share (reverted on rev B) |
2205 | * bit 10: suddound/line [= cm9739] | 2270 | * bit 10: suddound/line share |
2206 | * bit 9: mix 2 surround | 2271 | * bit 9: Analog-in mix -> surround |
2207 | * bit 8: ? | 2272 | * bit 8: Analog-in mix -> CLFE |
2208 | * bit 7: ?? (mic/center/lfe) | 2273 | * bit 7: Mic/LFE share (mic/center/lfe) |
2209 | * bit 4: ?? (front) | 2274 | * bit 5: vref select (9761A) |
2210 | * bit 3: ?? (line-in/rear share) (revereted with rev B) | 2275 | * bit 4: front control |
2211 | * bit 2: ?? (surround) | 2276 | * bit 3: surround control (revereted with rev B) |
2212 | * bit 1: front mic | 2277 | * bit 2: front mic |
2213 | * bit 0: mic boost | 2278 | * bit 1: stereo mic |
2279 | * bit 0: mic boost level (0=20dB, 1=30dB) | ||
2214 | */ | 2280 | */ |
2215 | 2281 | ||
2216 | #if 0 | 2282 | #if 0 |
@@ -2230,6 +2296,47 @@ int patch_cm9761(ac97_t *ac97) | |||
2230 | return 0; | 2296 | return 0; |
2231 | } | 2297 | } |
2232 | 2298 | ||
2299 | #define AC97_CM9780_SIDE 0x60 | ||
2300 | #define AC97_CM9780_JACK 0x62 | ||
2301 | #define AC97_CM9780_MIXER 0x64 | ||
2302 | #define AC97_CM9780_MULTI_CHAN 0x66 | ||
2303 | #define AC97_CM9780_SPDIF 0x6c | ||
2304 | |||
2305 | static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" }; | ||
2306 | static const struct ac97_enum cm9780_ch_select_enum = | ||
2307 | AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select); | ||
2308 | static const snd_kcontrol_new_t cm9780_controls[] = { | ||
2309 | AC97_DOUBLE("Side Playback Switch", AC97_CM9780_SIDE, 15, 7, 1, 1), | ||
2310 | AC97_DOUBLE("Side Playback Volume", AC97_CM9780_SIDE, 8, 0, 31, 0), | ||
2311 | AC97_ENUM("Side Playback Route", cm9780_ch_select_enum), | ||
2312 | }; | ||
2313 | |||
2314 | static int patch_cm9780_specific(ac97_t *ac97) | ||
2315 | { | ||
2316 | return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls)); | ||
2317 | } | ||
2318 | |||
2319 | static struct snd_ac97_build_ops patch_cm9780_ops = { | ||
2320 | .build_specific = patch_cm9780_specific, | ||
2321 | .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */ | ||
2322 | }; | ||
2323 | |||
2324 | int patch_cm9780(ac97_t *ac97) | ||
2325 | { | ||
2326 | unsigned short val; | ||
2327 | |||
2328 | ac97->build_ops = &patch_cm9780_ops; | ||
2329 | |||
2330 | /* enable spdif */ | ||
2331 | if (ac97->ext_id & AC97_EI_SPDIF) { | ||
2332 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ | ||
2333 | val = snd_ac97_read(ac97, AC97_CM9780_SPDIF); | ||
2334 | val |= 0x1; /* SPDI_EN */ | ||
2335 | snd_ac97_write_cache(ac97, AC97_CM9780_SPDIF, val); | ||
2336 | } | ||
2337 | |||
2338 | return 0; | ||
2339 | } | ||
2233 | 2340 | ||
2234 | /* | 2341 | /* |
2235 | * VIA VT1616 codec | 2342 | * VIA VT1616 codec |
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 6db51c96f5d0..7b7377d0f2ae 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h | |||
@@ -54,6 +54,7 @@ int patch_alc850(ac97_t * ac97); | |||
54 | int patch_cm9738(ac97_t * ac97); | 54 | int patch_cm9738(ac97_t * ac97); |
55 | int patch_cm9739(ac97_t * ac97); | 55 | int patch_cm9739(ac97_t * ac97); |
56 | int patch_cm9761(ac97_t * ac97); | 56 | int patch_cm9761(ac97_t * ac97); |
57 | int patch_cm9780(ac97_t * ac97); | ||
57 | int patch_vt1616(ac97_t * ac97); | 58 | int patch_vt1616(ac97_t * ac97); |
58 | int patch_it2646(ac97_t * ac97); | 59 | int patch_it2646(ac97_t * ac97); |
59 | int mpatch_si3036(ac97_t * ac97); | 60 | int mpatch_si3036(ac97_t * ac97); |