32 |
#include <sound/ac97_codec.h> |
#include <sound/ac97_codec.h> |
33 |
#include <sound/asoundef.h> |
#include <sound/asoundef.h> |
34 |
#include <sound/initval.h> |
#include <sound/initval.h> |
35 |
|
#include "ac97_local.h" |
36 |
#include "ac97_id.h" |
#include "ac97_id.h" |
37 |
#include "ac97_patch.h" |
#include "ac97_patch.h" |
38 |
|
|
52 |
|
|
53 |
*/ |
*/ |
54 |
|
|
|
static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix); |
|
|
|
|
55 |
typedef struct { |
typedef struct { |
56 |
unsigned int id; |
unsigned int id; |
57 |
unsigned int mask; |
unsigned int mask; |
113 |
{ 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL }, |
{ 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL }, |
114 |
{ 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL }, |
{ 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL }, |
115 |
{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, |
{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, |
116 |
{ 0x434d4941, 0xffffffff, "CMI9738", NULL, NULL }, |
{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, |
117 |
{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, |
{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, |
118 |
{ 0x43525900, 0xfffffff8, "CS4297", NULL, NULL }, |
{ 0x43525900, 0xfffffff8, "CS4297", NULL, NULL }, |
119 |
{ 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif, NULL }, |
{ 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif, NULL }, |
133 |
{ 0x49434501, 0xffffffff, "ICE1230", NULL, NULL }, |
{ 0x49434501, 0xffffffff, "ICE1230", NULL, NULL }, |
134 |
{ 0x49434511, 0xffffffff, "ICE1232", NULL, NULL }, // alias VIA VT1611A? |
{ 0x49434511, 0xffffffff, "ICE1232", NULL, NULL }, // alias VIA VT1611A? |
135 |
{ 0x49434514, 0xffffffff, "ICE1232A", NULL, NULL }, |
{ 0x49434514, 0xffffffff, "ICE1232A", NULL, NULL }, |
136 |
{ 0x49434551, 0xffffffff, "VT1616", NULL, NULL }, |
{ 0x49434551, 0xffffffff, "VT1616", patch_vt1616, NULL }, |
137 |
{ 0x49434552, 0xffffffff, "VT1616i", NULL, NULL }, // VT1616 compatible (chipset integrated) |
{ 0x49434552, 0xffffffff, "VT1616i", patch_vt1616, NULL }, // VT1616 compatible (chipset integrated) |
138 |
{ 0x49544520, 0xffffffff, "IT2226E", NULL, NULL }, |
{ 0x49544520, 0xffffffff, "IT2226E", NULL, NULL }, |
139 |
{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk |
{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk |
140 |
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, |
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, |
157 |
{ 0x594d4800, 0xffffffff, "YMF743", NULL, NULL }, |
{ 0x594d4800, 0xffffffff, "YMF743", NULL, NULL }, |
158 |
{ 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, |
{ 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, |
159 |
{ 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL }, |
{ 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL }, |
160 |
{ 0x83847600, 0xffffffff, "STAC9700/83/84", NULL, NULL }, |
{ 0x83847600, 0xffffffff, "STAC9700/83/84", patch_sigmatel_stac9700, NULL }, |
161 |
{ 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL, NULL }, |
{ 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL, NULL }, |
162 |
{ 0x83847605, 0xffffffff, "STAC9704", NULL, NULL }, |
{ 0x83847605, 0xffffffff, "STAC9704", NULL, NULL }, |
163 |
{ 0x83847608, 0xffffffff, "STAC9708/11", patch_sigmatel_stac9708, NULL }, |
{ 0x83847608, 0xffffffff, "STAC9708/11", patch_sigmatel_stac9708, NULL }, |
170 |
{ 0, 0, NULL, NULL, NULL } |
{ 0, 0, NULL, NULL, NULL } |
171 |
}; |
}; |
172 |
|
|
173 |
static const char *snd_ac97_stereo_enhancements[] = |
const char *snd_ac97_stereo_enhancements[] = |
174 |
{ |
{ |
175 |
/* 0 */ "No 3D Stereo Enhancement", |
/* 0 */ "No 3D Stereo Enhancement", |
176 |
/* 1 */ "Analog Devices Phat Stereo", |
/* 1 */ "Analog Devices Phat Stereo", |
309 |
set_bit(reg, ac97->reg_accessed); |
set_bit(reg, ac97->reg_accessed); |
310 |
} |
} |
311 |
|
|
|
static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned short value) |
|
|
{ |
|
|
#if 0 |
|
|
if (!snd_ac97_valid_reg(ac97, reg)) |
|
|
return; |
|
|
//spin_lock(&ac97->reg_lock); |
|
|
ac97->write(ac97, reg, value); |
|
|
ac97->regs[reg] = ac97->read(ac97, reg); |
|
|
if (value != ac97->regs[reg]) |
|
|
snd_printk("AC97 reg=%02x val=%04x real=%04x\n", reg, value, ac97->regs[reg]); |
|
|
//spin_unlock(&ac97->reg_lock); |
|
|
#endif |
|
|
snd_ac97_write_cache(ac97, reg, value); |
|
|
} |
|
|
|
|
312 |
/** |
/** |
313 |
* snd_ac97_update - update the value on the given register |
* snd_ac97_update - update the value on the given register |
314 |
* @ac97: the ac97 instance |
* @ac97: the ac97 instance |
502 |
return snd_ac97_update_bits(ac97, reg, 1 << shift, val << shift); |
return snd_ac97_update_bits(ac97, reg, 1 << shift, val << shift); |
503 |
} |
} |
504 |
|
|
505 |
#define AC97_SINGLE(xname, reg, shift, mask, invert) \ |
int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \ |
|
|
.get = snd_ac97_get_single, .put = snd_ac97_put_single, \ |
|
|
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } |
|
|
|
|
|
static int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
|
506 |
{ |
{ |
507 |
int mask = (kcontrol->private_value >> 16) & 0xff; |
int mask = (kcontrol->private_value >> 16) & 0xff; |
508 |
|
|
513 |
return 0; |
return 0; |
514 |
} |
} |
515 |
|
|
516 |
static int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
517 |
{ |
{ |
518 |
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
519 |
int reg = kcontrol->private_value & 0xff; |
int reg = kcontrol->private_value & 0xff; |
527 |
return 0; |
return 0; |
528 |
} |
} |
529 |
|
|
530 |
static int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
531 |
{ |
{ |
532 |
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
533 |
int reg = kcontrol->private_value & 0xff; |
int reg = kcontrol->private_value & 0xff; |
697 |
AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0) |
AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0) |
698 |
}; |
}; |
699 |
|
|
700 |
static const snd_kcontrol_new_t snd_ac97_controls_3d[2] = { |
const snd_kcontrol_new_t snd_ac97_controls_3d[2] = { |
701 |
AC97_SINGLE("3D Control - Center", AC97_3D_CONTROL, 8, 15, 0), |
AC97_SINGLE("3D Control - Center", AC97_3D_CONTROL, 8, 15, 0), |
702 |
AC97_SINGLE("3D Control - Depth", AC97_3D_CONTROL, 0, 15, 0) |
AC97_SINGLE("3D Control - Depth", AC97_3D_CONTROL, 0, 15, 0) |
703 |
}; |
}; |
722 |
AC97_DOUBLE("Sigmatel Surround Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1) |
AC97_DOUBLE("Sigmatel Surround Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1) |
723 |
}; |
}; |
724 |
|
|
|
static const snd_kcontrol_new_t snd_ac97_sigmatel_controls[] = { |
|
|
AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0), |
|
|
AC97_SINGLE("Sigmatel ADC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 0, 1, 0) |
|
|
}; |
|
|
|
|
725 |
static const snd_kcontrol_new_t snd_ac97_control_eapd = |
static const snd_kcontrol_new_t snd_ac97_control_eapd = |
726 |
AC97_SINGLE("External Amplifier Power Down", AC97_POWERDOWN, 15, 1, 0); |
AC97_SINGLE("External Amplifier Power Down", AC97_POWERDOWN, 15, 1, 0); |
727 |
|
|
|
static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = { |
|
|
AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0), |
|
|
AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0), |
|
|
AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0), |
|
|
AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), |
|
|
}; |
|
|
|
|
728 |
static int snd_ac97_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
static int snd_ac97_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
729 |
{ |
{ |
730 |
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
859 |
return 0; |
return 0; |
860 |
} |
} |
861 |
|
|
862 |
static const snd_kcontrol_new_t snd_ac97_controls_spdif[5] = { |
const snd_kcontrol_new_t snd_ac97_controls_spdif[5] = { |
863 |
{ |
{ |
864 |
.access = SNDRV_CTL_ELEM_ACCESS_READ, |
.access = SNDRV_CTL_ELEM_ACCESS_READ, |
865 |
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
883 |
}, |
}, |
884 |
|
|
885 |
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),AC97_EXTENDED_STATUS, 2, 1, 0), |
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),AC97_EXTENDED_STATUS, 2, 1, 0), |
|
// AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA",AC97_EXTENDED_STATUS, 4, 3, 0) |
|
886 |
{ |
{ |
887 |
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
888 |
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", |
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", |
893 |
}, |
}, |
894 |
}; |
}; |
895 |
|
|
|
static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = { |
|
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0), |
|
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0) |
|
|
}; |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[2] = { |
|
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0), |
|
|
}; |
|
|
|
|
896 |
#define AD18XX_PCM_BITS(xname, codec, shift, mask) \ |
#define AD18XX_PCM_BITS(xname, codec, shift, mask) \ |
897 |
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_bits, \ |
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_bits, \ |
898 |
.get = snd_ac97_ad18xx_pcm_get_bits, .put = snd_ac97_ad18xx_pcm_put_bits, \ |
.get = snd_ac97_ad18xx_pcm_get_bits, .put = snd_ac97_ad18xx_pcm_put_bits, \ |
988 |
AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31) |
AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31) |
989 |
}; |
}; |
990 |
|
|
|
static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
|
|
{ |
|
|
static char *texts[2] = { "AC-Link", "A/D Converter" }; |
|
|
|
|
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
|
|
uinfo->count = 1; |
|
|
uinfo->value.enumerated.items = 2; |
|
|
if (uinfo->value.enumerated.item > 1) |
|
|
uinfo->value.enumerated.item = 1; |
|
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
val = ac97->regs[AC97_AD_SERIAL_CFG]; |
|
|
ucontrol->value.enumerated.item[0] = (val >> 2) & 1; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
if (ucontrol->value.enumerated.item[0] > 1) |
|
|
return -EINVAL; |
|
|
val = ucontrol->value.enumerated.item[0] << 2; |
|
|
return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val); |
|
|
} |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source = { |
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
|
|
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
|
|
.info = snd_ac97_ad1980_spdif_source_info, |
|
|
.get = snd_ac97_ad1980_spdif_source_get, |
|
|
.put = snd_ac97_ad1980_spdif_source_put, |
|
|
}; |
|
|
|
|
|
/* |
|
|
* ALC650 |
|
|
*/ |
|
|
static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { |
|
|
AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), |
|
|
AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0), |
|
|
AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0), |
|
|
AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0), |
|
|
/* 4: Analog Input To Surround */ |
|
|
/* 5: Analog Input To Center/LFE */ |
|
|
/* 6: Independent Master Volume Right */ |
|
|
/* 7: Independent Master Volume Left */ |
|
|
/* 8: reserved */ |
|
|
AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), |
|
|
AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), |
|
|
#if 0 /* always set in patch_alc650 */ |
|
|
AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), |
|
|
AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0), |
|
|
AC97_SINGLE("Surround DAC Switch", AC97_ALC650_SURR_DAC_VOL, 15, 1, 1), |
|
|
AC97_DOUBLE("Surround DAC Volume", AC97_ALC650_SURR_DAC_VOL, 8, 0, 31, 1), |
|
|
AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), |
|
|
AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), |
|
|
#endif |
|
|
}; |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_control_alc650_mic = |
|
|
AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0); |
|
|
|
|
|
|
|
|
static int snd_ac97_alc650_mic_gpio_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_alc650_mic_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
int change; |
|
|
change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, |
|
|
ucontrol->value.integer.value[0] ? (1 << 10) : 0); |
|
|
if (change) { |
|
|
/* GPIO0 write for mic */ |
|
|
snd_ac97_update_bits(ac97, 0x76, 0x01, |
|
|
ucontrol->value.integer.value[0] ? 0 : 0x01); |
|
|
/* GPIO0 high for mic */ |
|
|
snd_ac97_update_bits(ac97, 0x78, 0x100, |
|
|
ucontrol->value.integer.value[0] ? 0 : 0x100); |
|
|
} |
|
|
return change; |
|
|
} |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = { |
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
|
|
.name = "Mic As Center/LFE", |
|
|
.info = snd_ac97_info_single, |
|
|
.get = snd_ac97_alc650_mic_gpio_get, |
|
|
.put = snd_ac97_alc650_mic_gpio_put, |
|
|
.private_value = (1 << 16), /* for info */ |
|
|
}; |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { |
|
|
AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), |
|
|
AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0), |
|
|
AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), |
|
|
}; |
|
|
|
|
|
/* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ |
|
|
|
|
|
/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ |
|
|
static int snd_ac97_ymf753_info_speaker(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
|
|
{ |
|
|
static char *texts[3] = { |
|
|
"Standard", "Small", "Smaller" |
|
|
}; |
|
|
|
|
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
|
|
uinfo->count = 1; |
|
|
uinfo->value.enumerated.items = 3; |
|
|
if (uinfo->value.enumerated.item > 2) |
|
|
uinfo->value.enumerated.item = 2; |
|
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_ymf753_get_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
val = ac97->regs[AC97_YMF753_3D_MODE_SEL]; |
|
|
val = (val >> 10) & 3; |
|
|
if (val > 0) /* 0 = invalid */ |
|
|
val--; |
|
|
ucontrol->value.enumerated.item[0] = val; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_ymf753_put_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
if (ucontrol->value.enumerated.item[0] > 2) |
|
|
return -EINVAL; |
|
|
val = (ucontrol->value.enumerated.item[0] + 1) << 10; |
|
|
return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val); |
|
|
} |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_ymf753_controls_speaker = |
|
|
{ |
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
|
|
.name = "3D Control - Speaker", |
|
|
.info = snd_ac97_ymf753_info_speaker, |
|
|
.get = snd_ac97_ymf753_get_speaker, |
|
|
.put = snd_ac97_ymf753_put_speaker, |
|
|
}; |
|
|
|
|
|
/* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */ |
|
|
static int snd_ac97_ymf753_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
|
|
{ |
|
|
static char *texts[2] = { "AC-Link", "A/D Converter" }; |
|
|
|
|
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
|
|
uinfo->count = 1; |
|
|
uinfo->value.enumerated.items = 2; |
|
|
if (uinfo->value.enumerated.item > 1) |
|
|
uinfo->value.enumerated.item = 1; |
|
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_ymf753_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
val = ac97->regs[AC97_YMF753_DIT_CTRL2]; |
|
|
ucontrol->value.enumerated.item[0] = (val >> 1) & 1; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_ymf753_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
if (ucontrol->value.enumerated.item[0] > 1) |
|
|
return -EINVAL; |
|
|
val = ucontrol->value.enumerated.item[0] << 1; |
|
|
return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val); |
|
|
} |
|
|
|
|
|
/* The AC'97 spec states that the S/PDIF signal is to be output at pin 48. |
|
|
The YMF753 will output the S/PDIF signal to pin 43, 47 (EAPD), or 48. |
|
|
By default, no output pin is selected, and the S/PDIF signal is not output. |
|
|
There is also a bit to mute S/PDIF output in a vendor-specific register. */ |
|
|
static int snd_ac97_ymf753_spdif_output_pin_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
|
|
{ |
|
|
static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" }; |
|
|
|
|
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
|
|
uinfo->count = 1; |
|
|
uinfo->value.enumerated.items = 3; |
|
|
if (uinfo->value.enumerated.item > 2) |
|
|
uinfo->value.enumerated.item = 2; |
|
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_ymf753_spdif_output_pin_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
val = ac97->regs[AC97_YMF753_DIT_CTRL2]; |
|
|
ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_ymf753_spdif_output_pin_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
if (ucontrol->value.enumerated.item[0] > 2) |
|
|
return -EINVAL; |
|
|
val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 : |
|
|
(ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0; |
|
|
return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val); |
|
|
/* The following can be used to direct S/PDIF output to pin 47 (EAPD). |
|
|
snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */ |
|
|
} |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_ymf753_controls_spdif[3] = { |
|
|
{ |
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
|
|
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
|
|
.info = snd_ac97_ymf753_spdif_source_info, |
|
|
.get = snd_ac97_ymf753_spdif_source_get, |
|
|
.put = snd_ac97_ymf753_spdif_source_put, |
|
|
}, |
|
|
{ |
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
|
|
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Output Pin", |
|
|
.info = snd_ac97_ymf753_spdif_output_pin_info, |
|
|
.get = snd_ac97_ymf753_spdif_output_pin_get, |
|
|
.put = snd_ac97_ymf753_spdif_output_pin_put, |
|
|
}, |
|
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1) |
|
|
}; |
|
|
|
|
|
|
|
|
/* |
|
|
* C-Media codecs |
|
|
*/ |
|
|
|
|
|
static int snd_ac97_cmedia_spdif_playback_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
|
|
{ |
|
|
static char *texts[] = { "Analog", "Digital" }; |
|
|
|
|
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
|
|
uinfo->count = 1; |
|
|
uinfo->value.enumerated.items = 2; |
|
|
if (uinfo->value.enumerated.item > 1) |
|
|
uinfo->value.enumerated.item = 1; |
|
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_cmedia_spdif_playback_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
unsigned short val; |
|
|
|
|
|
val = ac97->regs[AC97_CM9739_SPDIF_CTRL]; |
|
|
ucontrol->value.enumerated.item[0] = (val >> 1) & 0x01; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int snd_ac97_cmedia_spdif_playback_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
|
|
{ |
|
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
|
|
|
|
|
return snd_ac97_update_bits(ac97, AC97_CM9739_SPDIF_CTRL, |
|
|
0x01 << 1, |
|
|
(ucontrol->value.enumerated.item[0] & 0x01) << 1); |
|
|
} |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { |
|
|
/* BIT 0: SPDI_EN - always true */ |
|
|
{ /* BIT 1: SPDIFS */ |
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
|
|
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
|
|
.info = snd_ac97_cmedia_spdif_playback_source_info, |
|
|
.get = snd_ac97_cmedia_spdif_playback_source_get, |
|
|
.put = snd_ac97_cmedia_spdif_playback_source_put, |
|
|
}, |
|
|
/* BIT 2: IG_SPIV */ |
|
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9739_SPDIF_CTRL, 2, 1, 0), |
|
|
/* BIT 3: SPI2F */ |
|
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9739_SPDIF_CTRL, 3, 1, 0), |
|
|
/* BIT 4: SPI2SDI */ |
|
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9739_SPDIF_CTRL, 4, 1, 0), |
|
|
/* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ |
|
|
}; |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { |
|
|
AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), |
|
|
}; |
|
|
|
|
|
static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { |
|
|
AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), |
|
|
AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), |
|
|
}; |
|
|
|
|
991 |
/* |
/* |
992 |
* |
* |
993 |
*/ |
*/ |
1052 |
if (!(val & mask)) { |
if (!(val & mask)) { |
1053 |
/* nothing seems to be here - mute flag is not set */ |
/* nothing seems to be here - mute flag is not set */ |
1054 |
/* try another test */ |
/* try another test */ |
1055 |
snd_ac97_write_cache_test(ac97, reg, val | mask); |
snd_ac97_write_cache(ac97, reg, val | mask); |
1056 |
val = snd_ac97_read(ac97, reg); |
val = snd_ac97_read(ac97, reg); |
1057 |
if (!(val & mask)) |
if (!(val & mask)) |
1058 |
return 0; /* nothing here */ |
return 0; /* nothing here */ |
1060 |
return 1; /* success, useable */ |
return 1; /* success, useable */ |
1061 |
} |
} |
1062 |
|
|
1063 |
static int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit) |
int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit) |
1064 |
{ |
{ |
1065 |
unsigned short mask, val, orig, res; |
unsigned short mask, val, orig, res; |
1066 |
|
|
1129 |
return x; |
return x; |
1130 |
} |
} |
1131 |
|
|
1132 |
static snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97) |
snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97) |
1133 |
{ |
{ |
1134 |
snd_kcontrol_new_t template; |
snd_kcontrol_new_t template; |
1135 |
memcpy(&template, _template, sizeof(template)); |
memcpy(&template, _template, sizeof(template)); |
1138 |
return snd_ctl_new1(&template, ac97); |
return snd_ctl_new1(&template, ac97); |
1139 |
} |
} |
1140 |
|
|
1141 |
static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97) |
static int snd_ac97_mixer_build(ac97_t * ac97) |
1142 |
{ |
{ |
1143 |
|
snd_card_t *card = ac97->card; |
1144 |
snd_kcontrol_t *kctl; |
snd_kcontrol_t *kctl; |
1145 |
const snd_kcontrol_new_t *knew; |
const snd_kcontrol_new_t *knew; |
1146 |
int err; |
int err; |
1318 |
ac97->spec.ad18xx.pcmreg[2] = 0x9f1f; |
ac97->spec.ad18xx.pcmreg[2] = 0x9f1f; |
1319 |
} |
} |
1320 |
} else { |
} else { |
1321 |
|
unsigned int pcm_ctrls = 2; |
1322 |
/* FIXME: C-Media chips have no PCM volume!! */ |
/* FIXME: C-Media chips have no PCM volume!! */ |
1323 |
if (/*ac97->id == 0x434d4941 ||*/ |
if (/*ac97->id == 0x434d4941 ||*/ |
1324 |
ac97->id == 0x434d4942 || |
ac97->id == 0x434d4942 || |
1325 |
ac97->id == 0x434d4961) |
ac97->id == 0x434d4961) |
1326 |
goto no_pcm; |
pcm_ctrls = 1; |
1327 |
for (idx = 0; idx < 2; idx++) |
for (idx = 0; idx < pcm_ctrls; idx++) |
1328 |
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pcm[idx], ac97))) < 0) |
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pcm[idx], ac97))) < 0) |
1329 |
return err; |
return err; |
1330 |
} |
} |
1331 |
snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f); |
snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f); |
1332 |
|
|
|
no_pcm: |
|
1333 |
/* build Capture controls */ |
/* build Capture controls */ |
1334 |
for (idx = 0; idx < 3; idx++) |
for (idx = 0; idx < 3; idx++) |
1335 |
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_capture[idx], ac97))) < 0) |
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_capture[idx], ac97))) < 0) |
1390 |
snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x0000); |
snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x0000); |
1391 |
|
|
1392 |
/* build 3D controls */ |
/* build 3D controls */ |
1393 |
switch (ac97->id) { |
if (ac97->build_ops && ac97->build_ops->build_3d) { |
1394 |
case AC97_ID_STAC9708: |
ac97->build_ops->build_3d(ac97); |
1395 |
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) |
} else { |
|
return err; |
|
|
strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); |
|
|
kctl->private_value = AC97_3D_CONTROL | (3 << 16); |
|
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) |
|
|
return err; |
|
|
strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); |
|
|
kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16); |
|
|
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); |
|
|
break; |
|
|
case AC97_ID_STAC9700: |
|
|
case AC97_ID_STAC9721: |
|
|
case AC97_ID_STAC9744: |
|
|
case AC97_ID_STAC9756: |
|
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) |
|
|
return err; |
|
|
strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); |
|
|
kctl->private_value = AC97_3D_CONTROL | (3 << 16); |
|
|
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); |
|
|
break; |
|
|
case AC97_ID_YMF753: |
|
|
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) |
|
|
return err; |
|
|
strcpy(kctl->id.name, "3D Control - Wide"); |
|
|
kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16); |
|
|
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) |
|
|
return err; |
|
|
snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); |
|
|
break; |
|
|
default: |
|
1396 |
if (snd_ac97_try_volume_mix(ac97, AC97_3D_CONTROL)) { |
if (snd_ac97_try_volume_mix(ac97, AC97_3D_CONTROL)) { |
1397 |
unsigned short val; |
unsigned short val; |
1398 |
val = 0x0707; |
val = 0x0707; |
1410 |
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); |
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); |
1411 |
} |
} |
1412 |
} |
} |
1413 |
|
|
1414 |
/* build S/PDIF controls */ |
/* build S/PDIF controls */ |
1415 |
if (ac97->ext_id & AC97_EI_SPDIF) { |
if (ac97->ext_id & AC97_EI_SPDIF) { |
1416 |
if (ac97->flags & AC97_CS_SPDIF) { |
if (ac97->build_ops && ac97->build_ops->build_spdif) { |
1417 |
for (idx = 0; idx < 3; idx++) |
if ((err = ac97->build_ops->build_spdif(ac97)) < 0) |
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) |
|
|
return err; |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cirrus_controls_spdif[0], ac97))) < 0) |
|
1418 |
return err; |
return err; |
|
switch (ac97->id & AC97_ID_CS_MASK) { |
|
|
case AC97_ID_CS4205: |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cirrus_controls_spdif[1], ac97))) < 0) |
|
|
return err; |
|
|
break; |
|
|
} |
|
|
/* set default PCM S/PDIF params */ |
|
|
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ |
|
|
snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20); |
|
|
} else if (ac97->flags & AC97_CX_SPDIF) { |
|
|
for (idx = 0; idx < 3; idx++) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) |
|
|
return err; |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_conexant_controls_spdif[0], ac97))) < 0) |
|
|
return err; |
|
|
/* set default PCM S/PDIF params */ |
|
|
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ |
|
|
snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC, |
|
|
snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK)); |
|
|
|
|
1419 |
} else { |
} else { |
1420 |
for (idx = 0; idx < 5; idx++) |
for (idx = 0; idx < 5; idx++) |
1421 |
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) |
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) |
1422 |
return err; |
return err; |
1423 |
switch (ac97->id) { |
if (ac97->build_ops && ac97->build_ops->build_post_spdif) { |
1424 |
case AC97_ID_YMF753: |
if ((err = ac97->build_ops->build_post_spdif(ac97)) < 0) |
|
for (idx = 0; idx < 3; idx++) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_spdif[idx], ac97))) < 0) |
|
|
return err; |
|
|
break; |
|
|
case AC97_ID_AD1980: |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ad1980_spdif_source, ac97))) < 0) |
|
1425 |
return err; |
return err; |
|
break; |
|
|
case AC97_ID_CM9739: |
|
|
for (idx = 0; idx < ARRAY_SIZE(snd_ac97_cm9739_controls_spdif); idx++) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9739_controls_spdif[idx], ac97))) < 0) |
|
|
return err; |
|
|
break; |
|
1426 |
} |
} |
1427 |
/* set default PCM S/PDIF params */ |
/* set default PCM S/PDIF params */ |
1428 |
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ |
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ |
1429 |
snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20); |
snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20); |
1430 |
} |
} |
|
|
|
1431 |
ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF; |
ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF; |
1432 |
} |
} |
1433 |
|
|
1434 |
/* build chip specific controls */ |
/* build chip specific controls */ |
1435 |
switch (ac97->id) { |
if (ac97->build_ops && ac97->build_ops->build_specific) |
1436 |
case AC97_ID_STAC9700: |
if ((err = ac97->build_ops->build_specific(ac97)) < 0) |
1437 |
case AC97_ID_STAC9708: |
return err; |
|
case AC97_ID_STAC9721: |
|
|
case AC97_ID_STAC9744: |
|
|
case AC97_ID_STAC9756: |
|
|
snd_ac97_write_cache_test(ac97, AC97_SIGMATEL_ANALOG, snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) & ~0x0003); |
|
|
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1)) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[0], ac97))) < 0) |
|
|
return err; |
|
|
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0)) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[1], ac97))) < 0) |
|
|
return err; |
|
|
break; |
|
|
case AC97_ID_ALC650: |
|
|
/* detect ALC650 rev.E of later */ |
|
|
for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_alc650); idx++) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_alc650[idx], ac97))) < 0) |
|
|
return err; |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(ac97->spec.dev_flags ? |
|
|
&snd_ac97_control_alc650_mic : |
|
|
&snd_ac97_control_alc650_mic_gpio, ac97))) < 0) |
|
|
return err; |
|
|
if (ac97->ext_id & AC97_EI_SPDIF) { |
|
|
for (idx = 0; idx < ARRAY_SIZE(snd_ac97_spdif_controls_alc650); idx++) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_spdif_controls_alc650[idx], ac97))) < 0) |
|
|
return err; |
|
|
} |
|
|
break; |
|
|
case AC97_ID_VT1616: |
|
|
if (snd_ac97_try_bit(ac97, 0x5a, 9)) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_vt1616[0], ac97))) < 0) |
|
|
return err; |
|
|
for (idx = 1; idx < ARRAY_SIZE(snd_ac97_controls_vt1616); idx++) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_vt1616[idx], ac97))) < 0) |
|
|
return err; |
|
|
break; |
|
|
case AC97_ID_CM9739: |
|
|
for (idx = 1; idx < ARRAY_SIZE(snd_ac97_cm9739_controls); idx++) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9739_controls[idx], ac97))) < 0) |
|
|
return err; |
|
|
break; |
|
|
case AC97_ID_CM9738: |
|
|
for (idx = 1; idx < ARRAY_SIZE(snd_ac97_cm9738_controls); idx++) |
|
|
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9738_controls[idx], ac97))) < 0) |
|
|
return err; |
|
|
break; |
|
|
default: |
|
|
/* nothing */ |
|
|
break; |
|
|
} |
|
1438 |
|
|
1439 |
if (snd_ac97_try_bit(ac97, AC97_POWERDOWN, 15)) { |
if (snd_ac97_try_bit(ac97, AC97_POWERDOWN, 15)) { |
1440 |
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_eapd, ac97))) < 0) |
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_eapd, ac97))) < 0) |
1456 |
unsigned int tmp; |
unsigned int tmp; |
1457 |
|
|
1458 |
tmp = ((unsigned int)rate * ac97->clock) / 48000; |
tmp = ((unsigned int)rate * ac97->clock) / 48000; |
1459 |
snd_ac97_write_cache_test(ac97, reg, tmp & 0xffff); |
snd_ac97_write_cache(ac97, reg, tmp & 0xffff); |
1460 |
val = snd_ac97_read(ac97, reg); |
val = snd_ac97_read(ac97, reg); |
1461 |
return val == (tmp & 0xffff); |
return val == (tmp & 0xffff); |
1462 |
} |
} |
1486 |
*r_result = result; |
*r_result = result; |
1487 |
} |
} |
1488 |
|
|
1489 |
static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem) |
void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem) |
1490 |
{ |
{ |
1491 |
const ac97_codec_id_t *pid; |
const ac97_codec_id_t *pid; |
1492 |
|
|
1606 |
ac97->card = card; |
ac97->card = card; |
1607 |
spin_lock_init(&ac97->reg_lock); |
spin_lock_init(&ac97->reg_lock); |
1608 |
|
|
1609 |
|
if (ac97->pci) { |
1610 |
|
pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor); |
1611 |
|
pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device); |
1612 |
|
} |
1613 |
if (ac97->reset) { |
if (ac97->reset) { |
1614 |
ac97->reset(ac97); |
ac97->reset(ac97); |
1615 |
goto __access_ok; |
goto __access_ok; |
1663 |
/* FIXME: add powerdown control */ |
/* FIXME: add powerdown control */ |
1664 |
if (ac97_is_audio(ac97)) { |
if (ac97_is_audio(ac97)) { |
1665 |
/* nothing should be in powerdown mode */ |
/* nothing should be in powerdown mode */ |
1666 |
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0); |
snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0); |
1667 |
snd_ac97_write_cache_test(ac97, AC97_RESET, 0); /* reset to defaults */ |
snd_ac97_write_cache(ac97, AC97_RESET, 0); /* reset to defaults */ |
1668 |
udelay(100); |
udelay(100); |
1669 |
/* nothing should be in powerdown mode */ |
/* nothing should be in powerdown mode */ |
1670 |
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0); |
snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0); |
1671 |
snd_ac97_write_cache_test(ac97, AC97_GENERAL_PURPOSE, 0); |
snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0); |
1672 |
end_time = jiffies + (HZ / 10); |
end_time = jiffies + (HZ / 10); |
1673 |
do { |
do { |
1674 |
if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) |
if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) |
1737 |
snd_ac97_free(ac97); |
snd_ac97_free(ac97); |
1738 |
return err; |
return err; |
1739 |
} |
} |
1740 |
} |
if (snd_ac97_mixer_build(ac97) < 0) { |
1741 |
if (ac97_is_audio(ac97) && snd_ac97_mixer_build(card, ac97) < 0) { |
snd_ac97_free(ac97); |
1742 |
snd_ac97_free(ac97); |
return -ENOMEM; |
1743 |
return -ENOMEM; |
} |
1744 |
} |
} |
1745 |
snd_ac97_proc_init(card, ac97, "ac97"); |
snd_ac97_proc_init(card, ac97, "ac97"); |
1746 |
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) { |
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) { |
1882 |
/* note: it's important to set the rate at first */ |
/* note: it's important to set the rate at first */ |
1883 |
tmp = AC97_MEA_GPIO; |
tmp = AC97_MEA_GPIO; |
1884 |
if (ac97->ext_mid & AC97_MEI_LINE1) { |
if (ac97->ext_mid & AC97_MEI_LINE1) { |
1885 |
snd_ac97_write_cache_test(ac97, AC97_LINE1_RATE, 12000); |
snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); |
1886 |
tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; |
tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; |
1887 |
} |
} |
1888 |
if (ac97->ext_mid & AC97_MEI_LINE2) { |
if (ac97->ext_mid & AC97_MEI_LINE2) { |
1889 |
snd_ac97_write_cache_test(ac97, AC97_LINE2_RATE, 12000); |
snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); |
1890 |
tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; |
tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; |
1891 |
} |
} |
1892 |
if (ac97->ext_mid & AC97_MEI_HANDSET) { |
if (ac97->ext_mid & AC97_MEI_HANDSET) { |
1893 |
snd_ac97_write_cache_test(ac97, AC97_HANDSET_RATE, 12000); |
snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); |
1894 |
tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; |
tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; |
1895 |
} |
} |
1896 |
snd_ac97_write_cache_test(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); |
snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); |
1897 |
udelay(100); |
udelay(100); |
1898 |
/* nothing should be in powerdown mode */ |
/* nothing should be in powerdown mode */ |
1899 |
snd_ac97_write_cache_test(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); |
snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); |
1900 |
end_time = jiffies + (HZ / 10); |
end_time = jiffies + (HZ / 10); |
1901 |
do { |
do { |
1902 |
if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) |
if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) |
1947 |
} |
} |
1948 |
|
|
1949 |
/* |
/* |
|
* proc interface |
|
|
*/ |
|
|
|
|
|
static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx) |
|
|
{ |
|
|
char name[64]; |
|
|
unsigned int id; |
|
|
unsigned short val, tmp, ext, mext; |
|
|
static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" }; |
|
|
static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" }; |
|
|
static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" }; |
|
|
|
|
|
id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; |
|
|
id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); |
|
|
snd_ac97_get_name(NULL, id, name, 0); |
|
|
snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name); |
|
|
if ((ac97->scaps & AC97_SCAP_AUDIO) == 0) |
|
|
goto __modem; |
|
|
|
|
|
// val = snd_ac97_read(ac97, AC97_RESET); |
|
|
val = ac97->caps; |
|
|
snd_iprintf(buffer, "Capabilities :%s%s%s%s%s%s\n", |
|
|
val & AC97_BC_DEDICATED_MIC ? " -dedicated MIC PCM IN channel-" : "", |
|
|
val & AC97_BC_RESERVED1 ? " -reserved1-" : "", |
|
|
val & AC97_BC_BASS_TREBLE ? " -bass & treble-" : "", |
|
|
val & AC97_BC_SIM_STEREO ? " -simulated stereo-" : "", |
|
|
val & AC97_BC_HEADPHONE ? " -headphone out-" : "", |
|
|
val & AC97_BC_LOUDNESS ? " -loudness-" : ""); |
|
|
tmp = ac97->caps & AC97_BC_DAC_MASK; |
|
|
snd_iprintf(buffer, "DAC resolution : %s%s%s%s\n", |
|
|
tmp == AC97_BC_16BIT_DAC ? "16-bit" : "", |
|
|
tmp == AC97_BC_18BIT_DAC ? "18-bit" : "", |
|
|
tmp == AC97_BC_20BIT_DAC ? "20-bit" : "", |
|
|
tmp == AC97_BC_DAC_MASK ? "???" : ""); |
|
|
tmp = ac97->caps & AC97_BC_ADC_MASK; |
|
|
snd_iprintf(buffer, "ADC resolution : %s%s%s%s\n", |
|
|
tmp == AC97_BC_16BIT_ADC ? "16-bit" : "", |
|
|
tmp == AC97_BC_18BIT_ADC ? "18-bit" : "", |
|
|
tmp == AC97_BC_20BIT_ADC ? "20-bit" : "", |
|
|
tmp == AC97_BC_ADC_MASK ? "???" : ""); |
|
|
snd_iprintf(buffer, "3D enhancement : %s\n", |
|
|
snd_ac97_stereo_enhancements[(val >> 10) & 0x1f]); |
|
|
snd_iprintf(buffer, "\nCurrent setup\n"); |
|
|
val = snd_ac97_read(ac97, AC97_MIC); |
|
|
snd_iprintf(buffer, "Mic gain : %s [%s]\n", val & 0x0040 ? "+20dB" : "+0dB", ac97->regs[AC97_MIC] & 0x0040 ? "+20dB" : "+0dB"); |
|
|
val = snd_ac97_read(ac97, AC97_GENERAL_PURPOSE); |
|
|
snd_iprintf(buffer, "POP path : %s 3D\n" |
|
|
"Sim. stereo : %s\n" |
|
|
"3D enhancement : %s\n" |
|
|
"Loudness : %s\n" |
|
|
"Mono output : %s\n" |
|
|
"Mic select : %s\n" |
|
|
"ADC/DAC loopback : %s\n", |
|
|
val & 0x8000 ? "post" : "pre", |
|
|
val & 0x4000 ? "on" : "off", |
|
|
val & 0x2000 ? "on" : "off", |
|
|
val & 0x1000 ? "on" : "off", |
|
|
val & 0x0200 ? "Mic" : "MIX", |
|
|
val & 0x0100 ? "Mic2" : "Mic1", |
|
|
val & 0x0080 ? "on" : "off"); |
|
|
|
|
|
ext = snd_ac97_read(ac97, AC97_EXTENDED_ID); |
|
|
if (ext == 0) |
|
|
goto __modem; |
|
|
|
|
|
snd_iprintf(buffer, "Extended ID : codec=%i rev=%i%s%s%s%s DSA=%i%s%s%s%s\n", |
|
|
(ext & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT, |
|
|
(ext & AC97_EI_REV_MASK) >> AC97_EI_REV_SHIFT, |
|
|
ext & AC97_EI_AMAP ? " AMAP" : "", |
|
|
ext & AC97_EI_LDAC ? " LDAC" : "", |
|
|
ext & AC97_EI_SDAC ? " SDAC" : "", |
|
|
ext & AC97_EI_CDAC ? " CDAC" : "", |
|
|
(ext & AC97_EI_DACS_SLOT_MASK) >> AC97_EI_DACS_SLOT_SHIFT, |
|
|
ext & AC97_EI_VRM ? " VRM" : "", |
|
|
ext & AC97_EI_SPDIF ? " SPDIF" : "", |
|
|
ext & AC97_EI_DRA ? " DRA" : "", |
|
|
ext & AC97_EI_VRA ? " VRA" : ""); |
|
|
val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); |
|
|
snd_iprintf(buffer, "Extended status :%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", |
|
|
val & AC97_EA_PRL ? " PRL" : "", |
|
|
val & AC97_EA_PRK ? " PRK" : "", |
|
|
val & AC97_EA_PRJ ? " PRJ" : "", |
|
|
val & AC97_EA_PRI ? " PRI" : "", |
|
|
val & AC97_EA_SPCV ? " SPCV" : "", |
|
|
val & AC97_EA_MDAC ? " MADC" : "", |
|
|
val & AC97_EA_LDAC ? " LDAC" : "", |
|
|
val & AC97_EA_SDAC ? " SDAC" : "", |
|
|
val & AC97_EA_CDAC ? " CDAC" : "", |
|
|
ext & AC97_EI_SPDIF ? spdif_slots[(val & AC97_EA_SPSA_SLOT_MASK) >> AC97_EA_SPSA_SLOT_SHIFT] : "", |
|
|
val & AC97_EA_VRM ? " VRM" : "", |
|
|
val & AC97_EA_SPDIF ? " SPDIF" : "", |
|
|
val & AC97_EA_DRA ? " DRA" : "", |
|
|
val & AC97_EA_VRA ? " VRA" : ""); |
|
|
if (ext & AC97_EI_VRA) { /* VRA */ |
|
|
val = snd_ac97_read(ac97, AC97_PCM_FRONT_DAC_RATE); |
|
|
snd_iprintf(buffer, "PCM front DAC : %iHz\n", val); |
|
|
if (ext & AC97_EI_SDAC) { |
|
|
val = snd_ac97_read(ac97, AC97_PCM_SURR_DAC_RATE); |
|
|
snd_iprintf(buffer, "PCM Surr DAC : %iHz\n", val); |
|
|
} |
|
|
if (ext & AC97_EI_LDAC) { |
|
|
val = snd_ac97_read(ac97, AC97_PCM_LFE_DAC_RATE); |
|
|
snd_iprintf(buffer, "PCM LFE DAC : %iHz\n", val); |
|
|
} |
|
|
val = snd_ac97_read(ac97, AC97_PCM_LR_ADC_RATE); |
|
|
snd_iprintf(buffer, "PCM ADC : %iHz\n", val); |
|
|
} |
|
|
if (ext & AC97_EI_VRM) { |
|
|
val = snd_ac97_read(ac97, AC97_PCM_MIC_ADC_RATE); |
|
|
snd_iprintf(buffer, "PCM MIC ADC : %iHz\n", val); |
|
|
} |
|
|
if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF)) { |
|
|
if (ac97->flags & AC97_CS_SPDIF) |
|
|
val = snd_ac97_read(ac97, AC97_CSR_SPDIF); |
|
|
else |
|
|
val = snd_ac97_read(ac97, AC97_SPDIF); |
|
|
|
|
|
snd_iprintf(buffer, "SPDIF Control :%s%s%s%s Category=0x%x Generation=%i%s%s%s\n", |
|
|
val & AC97_SC_PRO ? " PRO" : " Consumer", |
|
|
val & AC97_SC_NAUDIO ? " Non-audio" : " PCM", |
|
|
val & AC97_SC_COPY ? " Copyright" : "", |
|
|
val & AC97_SC_PRE ? " Preemph50/15" : "", |
|
|
(val & AC97_SC_CC_MASK) >> AC97_SC_CC_SHIFT, |
|
|
(val & AC97_SC_L) >> 11, |
|
|
(ac97->flags & AC97_CS_SPDIF) ? |
|
|
spdif_rates_cs4205[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT] : |
|
|
spdif_rates[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT], |
|
|
(ac97->flags & AC97_CS_SPDIF) ? |
|
|
(val & AC97_SC_DRS ? " Validity" : "") : |
|
|
(val & AC97_SC_DRS ? " DRS" : ""), |
|
|
(ac97->flags & AC97_CS_SPDIF) ? |
|
|
(val & AC97_SC_V ? " Enabled" : "") : |
|
|
(val & AC97_SC_V ? " Validity" : "")); |
|
|
} |
|
|
|
|
|
__modem: |
|
|
mext = snd_ac97_read(ac97, AC97_EXTENDED_MID); |
|
|
if (mext == 0) |
|
|
return; |
|
|
|
|
|
snd_iprintf(buffer, "Extended modem ID: codec=%i%s%s%s%s%s\n", |
|
|
(mext & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT, |
|
|
mext & AC97_MEI_CID2 ? " CID2" : "", |
|
|
mext & AC97_MEI_CID1 ? " CID1" : "", |
|
|
mext & AC97_MEI_HANDSET ? " HSET" : "", |
|
|
mext & AC97_MEI_LINE2 ? " LIN2" : "", |
|
|
mext & AC97_MEI_LINE1 ? " LIN1" : ""); |
|
|
val = snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS); |
|
|
snd_iprintf(buffer, "Modem status :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", |
|
|
val & AC97_MEA_GPIO ? " GPIO" : "", |
|
|
val & AC97_MEA_MREF ? " MREF" : "", |
|
|
val & AC97_MEA_ADC1 ? " ADC1" : "", |
|
|
val & AC97_MEA_DAC1 ? " DAC1" : "", |
|
|
val & AC97_MEA_ADC2 ? " ADC2" : "", |
|
|
val & AC97_MEA_DAC2 ? " DAC2" : "", |
|
|
val & AC97_MEA_HADC ? " HADC" : "", |
|
|
val & AC97_MEA_HDAC ? " HDAC" : "", |
|
|
val & AC97_MEA_PRA ? " PRA(GPIO)" : "", |
|
|
val & AC97_MEA_PRB ? " PRB(res)" : "", |
|
|
val & AC97_MEA_PRC ? " PRC(ADC1)" : "", |
|
|
val & AC97_MEA_PRD ? " PRD(DAC1)" : "", |
|
|
val & AC97_MEA_PRE ? " PRE(ADC2)" : "", |
|
|
val & AC97_MEA_PRF ? " PRF(DAC2)" : "", |
|
|
val & AC97_MEA_PRG ? " PRG(HADC)" : "", |
|
|
val & AC97_MEA_PRH ? " PRH(HDAC)" : ""); |
|
|
if (mext & AC97_MEI_LINE1) { |
|
|
val = snd_ac97_read(ac97, AC97_LINE1_RATE); |
|
|
snd_iprintf(buffer, "Line1 rate : %iHz\n", val); |
|
|
} |
|
|
if (mext & AC97_MEI_LINE2) { |
|
|
val = snd_ac97_read(ac97, AC97_LINE2_RATE); |
|
|
snd_iprintf(buffer, "Line2 rate : %iHz\n", val); |
|
|
} |
|
|
if (mext & AC97_MEI_HANDSET) { |
|
|
val = snd_ac97_read(ac97, AC97_HANDSET_RATE); |
|
|
snd_iprintf(buffer, "Headset rate : %iHz\n", val); |
|
|
} |
|
|
} |
|
|
|
|
|
static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) |
|
|
{ |
|
|
ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); |
|
|
|
|
|
if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 |
|
|
int idx; |
|
|
down(&ac97->spec.ad18xx.mutex); |
|
|
for (idx = 0; idx < 3; idx++) |
|
|
if (ac97->spec.ad18xx.id[idx]) { |
|
|
/* select single codec */ |
|
|
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]); |
|
|
snd_ac97_proc_read_main(ac97, buffer, idx); |
|
|
snd_iprintf(buffer, "\n\n"); |
|
|
} |
|
|
/* select all codecs */ |
|
|
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); |
|
|
up(&ac97->spec.ad18xx.mutex); |
|
|
|
|
|
snd_iprintf(buffer, "\nAD18XX configuration\n"); |
|
|
snd_iprintf(buffer, "Unchained : 0x%04x,0x%04x,0x%04x\n", |
|
|
ac97->spec.ad18xx.unchained[0], |
|
|
ac97->spec.ad18xx.unchained[1], |
|
|
ac97->spec.ad18xx.unchained[2]); |
|
|
snd_iprintf(buffer, "Chained : 0x%04x,0x%04x,0x%04x\n", |
|
|
ac97->spec.ad18xx.chained[0], |
|
|
ac97->spec.ad18xx.chained[1], |
|
|
ac97->spec.ad18xx.chained[2]); |
|
|
} else { |
|
|
snd_ac97_proc_read_main(ac97, buffer, 0); |
|
|
} |
|
|
} |
|
|
|
|
|
static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx) |
|
|
{ |
|
|
int reg, val; |
|
|
|
|
|
for (reg = 0; reg < 0x80; reg += 2) { |
|
|
val = snd_ac97_read(ac97, reg); |
|
|
snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val); |
|
|
} |
|
|
} |
|
|
|
|
|
static void snd_ac97_proc_regs_read(snd_info_entry_t *entry, |
|
|
snd_info_buffer_t * buffer) |
|
|
{ |
|
|
ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); |
|
|
|
|
|
if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 |
|
|
|
|
|
int idx; |
|
|
down(&ac97->spec.ad18xx.mutex); |
|
|
for (idx = 0; idx < 3; idx++) |
|
|
if (ac97->spec.ad18xx.id[idx]) { |
|
|
/* select single codec */ |
|
|
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]); |
|
|
snd_ac97_proc_regs_read_main(ac97, buffer, idx); |
|
|
} |
|
|
/* select all codecs */ |
|
|
snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); |
|
|
up(&ac97->spec.ad18xx.mutex); |
|
|
} else { |
|
|
snd_ac97_proc_regs_read_main(ac97, buffer, 0); |
|
|
} |
|
|
} |
|
|
|
|
|
static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix) |
|
|
{ |
|
|
snd_info_entry_t *entry; |
|
|
char name[32]; |
|
|
|
|
|
if (ac97->num) |
|
|
sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); |
|
|
else |
|
|
sprintf(name, "%s#%d", prefix, ac97->addr); |
|
|
if (! snd_card_proc_new(card, name, &entry)) |
|
|
snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read); |
|
|
if (ac97->num) |
|
|
sprintf(name, "%s#%d-%dregs", prefix, ac97->addr, ac97->num); |
|
|
else |
|
|
sprintf(name, "%s#%dregs", prefix, ac97->addr); |
|
|
if (! snd_card_proc_new(card, name, &entry)) |
|
|
snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); |
|
|
} |
|
|
|
|
|
/* |
|
1950 |
* PCM support |
* PCM support |
1951 |
*/ |
*/ |
1952 |
|
|
1985 |
} |
} |
1986 |
|
|
1987 |
spin_lock(&ac97->reg_lock); |
spin_lock(&ac97->reg_lock); |
1988 |
old = ac97->regs[reg] & ~mask; |
old = ac97->regs[reg] & mask; |
1989 |
spin_unlock(&ac97->reg_lock); |
spin_unlock(&ac97->reg_lock); |
1990 |
if (old != bits) { |
if (old != bits) { |
1991 |
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); |
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); |