diff options
Diffstat (limited to 'sound/pci/ac97/ac97_patch.c')
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 162 |
1 files changed, 105 insertions, 57 deletions
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 581ebba4d1a7..98c8b727b62b 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | 2 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
3 | * Universal interface for Audio Codec '97 | 3 | * Universal interface for Audio Codec '97 |
4 | * | 4 | * |
5 | * For more details look to AC '97 component specification revision 2.2 | 5 | * For more details look to AC '97 component specification revision 2.2 |
@@ -204,9 +204,13 @@ static inline int is_shared_micin(struct snd_ac97 *ac97) | |||
204 | 204 | ||
205 | 205 | ||
206 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ | 206 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ |
207 | /* Modified for YMF743 by Keita Maehara <maehara@debian.org> */ | ||
207 | 208 | ||
208 | /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ | 209 | /* It is possible to indicate to the Yamaha YMF7x3 the type of |
209 | static int snd_ac97_ymf753_info_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 210 | speakers being used. */ |
211 | |||
212 | static int snd_ac97_ymf7x3_info_speaker(struct snd_kcontrol *kcontrol, | ||
213 | struct snd_ctl_elem_info *uinfo) | ||
210 | { | 214 | { |
211 | static char *texts[3] = { | 215 | static char *texts[3] = { |
212 | "Standard", "Small", "Smaller" | 216 | "Standard", "Small", "Smaller" |
@@ -221,12 +225,13 @@ static int snd_ac97_ymf753_info_speaker(struct snd_kcontrol *kcontrol, struct sn | |||
221 | return 0; | 225 | return 0; |
222 | } | 226 | } |
223 | 227 | ||
224 | static int snd_ac97_ymf753_get_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 228 | static int snd_ac97_ymf7x3_get_speaker(struct snd_kcontrol *kcontrol, |
229 | struct snd_ctl_elem_value *ucontrol) | ||
225 | { | 230 | { |
226 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 231 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
227 | unsigned short val; | 232 | unsigned short val; |
228 | 233 | ||
229 | val = ac97->regs[AC97_YMF753_3D_MODE_SEL]; | 234 | val = ac97->regs[AC97_YMF7X3_3D_MODE_SEL]; |
230 | val = (val >> 10) & 3; | 235 | val = (val >> 10) & 3; |
231 | if (val > 0) /* 0 = invalid */ | 236 | if (val > 0) /* 0 = invalid */ |
232 | val--; | 237 | val--; |
@@ -234,7 +239,8 @@ static int snd_ac97_ymf753_get_speaker(struct snd_kcontrol *kcontrol, struct snd | |||
234 | return 0; | 239 | return 0; |
235 | } | 240 | } |
236 | 241 | ||
237 | static int snd_ac97_ymf753_put_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 242 | static int snd_ac97_ymf7x3_put_speaker(struct snd_kcontrol *kcontrol, |
243 | struct snd_ctl_elem_value *ucontrol) | ||
238 | { | 244 | { |
239 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 245 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
240 | unsigned short val; | 246 | unsigned short val; |
@@ -242,20 +248,22 @@ static int snd_ac97_ymf753_put_speaker(struct snd_kcontrol *kcontrol, struct snd | |||
242 | if (ucontrol->value.enumerated.item[0] > 2) | 248 | if (ucontrol->value.enumerated.item[0] > 2) |
243 | return -EINVAL; | 249 | return -EINVAL; |
244 | val = (ucontrol->value.enumerated.item[0] + 1) << 10; | 250 | val = (ucontrol->value.enumerated.item[0] + 1) << 10; |
245 | return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val); | 251 | return snd_ac97_update(ac97, AC97_YMF7X3_3D_MODE_SEL, val); |
246 | } | 252 | } |
247 | 253 | ||
248 | static const struct snd_kcontrol_new snd_ac97_ymf753_controls_speaker = | 254 | static const struct snd_kcontrol_new snd_ac97_ymf7x3_controls_speaker = |
249 | { | 255 | { |
250 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 256 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
251 | .name = "3D Control - Speaker", | 257 | .name = "3D Control - Speaker", |
252 | .info = snd_ac97_ymf753_info_speaker, | 258 | .info = snd_ac97_ymf7x3_info_speaker, |
253 | .get = snd_ac97_ymf753_get_speaker, | 259 | .get = snd_ac97_ymf7x3_get_speaker, |
254 | .put = snd_ac97_ymf753_put_speaker, | 260 | .put = snd_ac97_ymf7x3_put_speaker, |
255 | }; | 261 | }; |
256 | 262 | ||
257 | /* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */ | 263 | /* It is possible to indicate to the Yamaha YMF7x3 the source to |
258 | static int snd_ac97_ymf753_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 264 | direct to the S/PDIF output. */ |
265 | static int snd_ac97_ymf7x3_spdif_source_info(struct snd_kcontrol *kcontrol, | ||
266 | struct snd_ctl_elem_info *uinfo) | ||
259 | { | 267 | { |
260 | static char *texts[2] = { "AC-Link", "A/D Converter" }; | 268 | static char *texts[2] = { "AC-Link", "A/D Converter" }; |
261 | 269 | ||
@@ -268,17 +276,19 @@ static int snd_ac97_ymf753_spdif_source_info(struct snd_kcontrol *kcontrol, stru | |||
268 | return 0; | 276 | return 0; |
269 | } | 277 | } |
270 | 278 | ||
271 | static int snd_ac97_ymf753_spdif_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 279 | static int snd_ac97_ymf7x3_spdif_source_get(struct snd_kcontrol *kcontrol, |
280 | struct snd_ctl_elem_value *ucontrol) | ||
272 | { | 281 | { |
273 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 282 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
274 | unsigned short val; | 283 | unsigned short val; |
275 | 284 | ||
276 | val = ac97->regs[AC97_YMF753_DIT_CTRL2]; | 285 | val = ac97->regs[AC97_YMF7X3_DIT_CTRL]; |
277 | ucontrol->value.enumerated.item[0] = (val >> 1) & 1; | 286 | ucontrol->value.enumerated.item[0] = (val >> 1) & 1; |
278 | return 0; | 287 | return 0; |
279 | } | 288 | } |
280 | 289 | ||
281 | static int snd_ac97_ymf753_spdif_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 290 | static int snd_ac97_ymf7x3_spdif_source_put(struct snd_kcontrol *kcontrol, |
291 | struct snd_ctl_elem_value *ucontrol) | ||
282 | { | 292 | { |
283 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 293 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
284 | unsigned short val; | 294 | unsigned short val; |
@@ -286,7 +296,75 @@ static int snd_ac97_ymf753_spdif_source_put(struct snd_kcontrol *kcontrol, struc | |||
286 | if (ucontrol->value.enumerated.item[0] > 1) | 296 | if (ucontrol->value.enumerated.item[0] > 1) |
287 | return -EINVAL; | 297 | return -EINVAL; |
288 | val = ucontrol->value.enumerated.item[0] << 1; | 298 | val = ucontrol->value.enumerated.item[0] << 1; |
289 | return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val); | 299 | return snd_ac97_update_bits(ac97, AC97_YMF7X3_DIT_CTRL, 0x0002, val); |
300 | } | ||
301 | |||
302 | static int patch_yamaha_ymf7x3_3d(struct snd_ac97 *ac97) | ||
303 | { | ||
304 | struct snd_kcontrol *kctl; | ||
305 | int err; | ||
306 | |||
307 | kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97); | ||
308 | err = snd_ctl_add(ac97->bus->card, kctl); | ||
309 | if (err < 0) | ||
310 | return err; | ||
311 | strcpy(kctl->id.name, "3D Control - Wide"); | ||
312 | kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0); | ||
313 | snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); | ||
314 | err = snd_ctl_add(ac97->bus->card, | ||
315 | snd_ac97_cnew(&snd_ac97_ymf7x3_controls_speaker, | ||
316 | ac97)); | ||
317 | if (err < 0) | ||
318 | return err; | ||
319 | snd_ac97_write_cache(ac97, AC97_YMF7X3_3D_MODE_SEL, 0x0c00); | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static const struct snd_kcontrol_new snd_ac97_yamaha_ymf743_controls_spdif[3] = | ||
324 | { | ||
325 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), | ||
326 | AC97_YMF7X3_DIT_CTRL, 0, 1, 0), | ||
327 | { | ||
328 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
329 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Source", | ||
330 | .info = snd_ac97_ymf7x3_spdif_source_info, | ||
331 | .get = snd_ac97_ymf7x3_spdif_source_get, | ||
332 | .put = snd_ac97_ymf7x3_spdif_source_put, | ||
333 | }, | ||
334 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", NONE, NONE) "Mute", | ||
335 | AC97_YMF7X3_DIT_CTRL, 2, 1, 1) | ||
336 | }; | ||
337 | |||
338 | static int patch_yamaha_ymf743_build_spdif(struct snd_ac97 *ac97) | ||
339 | { | ||
340 | int err; | ||
341 | |||
342 | err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3); | ||
343 | if (err < 0) | ||
344 | return err; | ||
345 | err = patch_build_controls(ac97, | ||
346 | snd_ac97_yamaha_ymf743_controls_spdif, 3); | ||
347 | if (err < 0) | ||
348 | return err; | ||
349 | /* set default PCM S/PDIF params */ | ||
350 | /* PCM audio,no copyright,no preemphasis,PCM coder,original */ | ||
351 | snd_ac97_write_cache(ac97, AC97_YMF7X3_DIT_CTRL, 0xa201); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static struct snd_ac97_build_ops patch_yamaha_ymf743_ops = { | ||
356 | .build_spdif = patch_yamaha_ymf743_build_spdif, | ||
357 | .build_3d = patch_yamaha_ymf7x3_3d, | ||
358 | }; | ||
359 | |||
360 | static int patch_yamaha_ymf743(struct snd_ac97 *ac97) | ||
361 | { | ||
362 | ac97->build_ops = &patch_yamaha_ymf743_ops; | ||
363 | ac97->caps |= AC97_BC_BASS_TREBLE; | ||
364 | ac97->caps |= 0x04 << 10; /* Yamaha 3D enhancement */ | ||
365 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ | ||
366 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ | ||
367 | return 0; | ||
290 | } | 368 | } |
291 | 369 | ||
292 | /* The AC'97 spec states that the S/PDIF signal is to be output at pin 48. | 370 | /* The AC'97 spec states that the S/PDIF signal is to be output at pin 48. |
@@ -311,7 +389,7 @@ static int snd_ac97_ymf753_spdif_output_pin_get(struct snd_kcontrol *kcontrol, s | |||
311 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 389 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
312 | unsigned short val; | 390 | unsigned short val; |
313 | 391 | ||
314 | val = ac97->regs[AC97_YMF753_DIT_CTRL2]; | 392 | val = ac97->regs[AC97_YMF7X3_DIT_CTRL]; |
315 | ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0; | 393 | ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0; |
316 | return 0; | 394 | return 0; |
317 | } | 395 | } |
@@ -325,7 +403,7 @@ static int snd_ac97_ymf753_spdif_output_pin_put(struct snd_kcontrol *kcontrol, s | |||
325 | return -EINVAL; | 403 | return -EINVAL; |
326 | val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 : | 404 | val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 : |
327 | (ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0; | 405 | (ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0; |
328 | return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val); | 406 | return snd_ac97_update_bits(ac97, AC97_YMF7X3_DIT_CTRL, 0x0028, val); |
329 | /* The following can be used to direct S/PDIF output to pin 47 (EAPD). | 407 | /* The following can be used to direct S/PDIF output to pin 47 (EAPD). |
330 | snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */ | 408 | snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */ |
331 | } | 409 | } |
@@ -334,9 +412,9 @@ static const struct snd_kcontrol_new snd_ac97_ymf753_controls_spdif[3] = { | |||
334 | { | 412 | { |
335 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 413 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
336 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | 414 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
337 | .info = snd_ac97_ymf753_spdif_source_info, | 415 | .info = snd_ac97_ymf7x3_spdif_source_info, |
338 | .get = snd_ac97_ymf753_spdif_source_get, | 416 | .get = snd_ac97_ymf7x3_spdif_source_get, |
339 | .put = snd_ac97_ymf753_spdif_source_put, | 417 | .put = snd_ac97_ymf7x3_spdif_source_put, |
340 | }, | 418 | }, |
341 | { | 419 | { |
342 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 420 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -345,25 +423,10 @@ static const struct snd_kcontrol_new snd_ac97_ymf753_controls_spdif[3] = { | |||
345 | .get = snd_ac97_ymf753_spdif_output_pin_get, | 423 | .get = snd_ac97_ymf753_spdif_output_pin_get, |
346 | .put = snd_ac97_ymf753_spdif_output_pin_put, | 424 | .put = snd_ac97_ymf753_spdif_output_pin_put, |
347 | }, | 425 | }, |
348 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1) | 426 | AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", NONE, NONE) "Mute", |
427 | AC97_YMF7X3_DIT_CTRL, 2, 1, 1) | ||
349 | }; | 428 | }; |
350 | 429 | ||
351 | static int patch_yamaha_ymf753_3d(struct snd_ac97 * ac97) | ||
352 | { | ||
353 | struct snd_kcontrol *kctl; | ||
354 | int err; | ||
355 | |||
356 | if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) | ||
357 | return err; | ||
358 | strcpy(kctl->id.name, "3D Control - Wide"); | ||
359 | kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0); | ||
360 | snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); | ||
361 | if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) | ||
362 | return err; | ||
363 | snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) | 430 | static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) |
368 | { | 431 | { |
369 | int err; | 432 | int err; |
@@ -374,7 +437,7 @@ static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) | |||
374 | } | 437 | } |
375 | 438 | ||
376 | static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { | 439 | static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { |
377 | .build_3d = patch_yamaha_ymf753_3d, | 440 | .build_3d = patch_yamaha_ymf7x3_3d, |
378 | .build_post_spdif = patch_yamaha_ymf753_post_spdif | 441 | .build_post_spdif = patch_yamaha_ymf753_post_spdif |
379 | }; | 442 | }; |
380 | 443 | ||
@@ -1880,14 +1943,7 @@ static int patch_ad1981b(struct snd_ac97 *ac97) | |||
1880 | return 0; | 1943 | return 0; |
1881 | } | 1944 | } |
1882 | 1945 | ||
1883 | static int snd_ac97_ad1888_lohpsel_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 1946 | #define snd_ac97_ad1888_lohpsel_info snd_ctl_boolean_mono_info |
1884 | { | ||
1885 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1886 | uinfo->count = 1; | ||
1887 | uinfo->value.integer.min = 0; | ||
1888 | uinfo->value.integer.max = 1; | ||
1889 | return 0; | ||
1890 | } | ||
1891 | 1947 | ||
1892 | static int snd_ac97_ad1888_lohpsel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 1948 | static int snd_ac97_ad1888_lohpsel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1893 | { | 1949 | { |
@@ -2186,15 +2242,7 @@ static int patch_ad1985(struct snd_ac97 * ac97) | |||
2186 | return 0; | 2242 | return 0; |
2187 | } | 2243 | } |
2188 | 2244 | ||
2189 | static int snd_ac97_ad1986_bool_info(struct snd_kcontrol *kcontrol, | 2245 | #define snd_ac97_ad1986_bool_info snd_ctl_boolean_mono_info |
2190 | struct snd_ctl_elem_info *uinfo) | ||
2191 | { | ||
2192 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2193 | uinfo->count = 1; | ||
2194 | uinfo->value.integer.min = 0; | ||
2195 | uinfo->value.integer.max = 1; | ||
2196 | return 0; | ||
2197 | } | ||
2198 | 2246 | ||
2199 | static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol, | 2247 | static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol, |
2200 | struct snd_ctl_elem_value *ucontrol) | 2248 | struct snd_ctl_elem_value *ucontrol) |