📄 ac97_codec.c
字号:
id2 = codec->codec_read(codec, AC97_VENDOR_ID2); for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) { if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { codec->type = ac97_codec_ids[i].id; codec->name = ac97_codec_ids[i].name; codec->codec_ops = ac97_codec_ids[i].ops; break; } } if (codec->name == NULL) codec->name = "Unknown"; printk(KERN_INFO "ac97_codec: AC97 %s codec, id: 0x%04x:" "0x%04x (%s)\n", audio ? "Audio" : (modem ? "Modem" : ""), id1, id2, codec->name); return ac97_init_mixer(codec);}static int ac97_init_mixer(struct ac97_codec *codec){ u16 cap; int i; cap = codec->codec_read(codec, AC97_RESET); /* mixer masks */ codec->supported_mixers = AC97_SUPPORTED_MASK; codec->stereo_mixers = AC97_STEREO_MASK; codec->record_sources = AC97_RECORD_MASK; if (!(cap & 0x04)) codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); if (!(cap & 0x10)) codec->supported_mixers &= ~SOUND_MASK_ALTPCM; /* detect bit resolution */ codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020); if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x1f1f) codec->bit_resolution = 5; else codec->bit_resolution = 6; /* generic OSS to AC97 wrapper */ codec->read_mixer = ac97_read_mixer; codec->write_mixer = ac97_write_mixer; codec->recmask_io = ac97_recmask_io; codec->mixer_ioctl = ac97_mixer_ioctl; /* codec specific initialization for 4-6 channel output or secondary codec stuff */ if (codec->codec_ops->init != NULL) { codec->codec_ops->init(codec); } /* initialize mixer channel volumes */ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { struct mixer_defaults *md = &mixer_defaults[i]; if (md->mixer == -1) break; if (!supported_mixer(codec, md->mixer)) continue; ac97_set_mixer(codec, md->mixer, md->value); } return 1;}#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */#define AC97_SIGMATEL_DAC2INVERT 0x6e#define AC97_SIGMATEL_BIAS1 0x70#define AC97_SIGMATEL_BIAS2 0x72#define AC97_SIGMATEL_MULTICHN 0x74 /* Multi-Channel programming */#define AC97_SIGMATEL_CIC1 0x76#define AC97_SIGMATEL_CIC2 0x78static int sigmatel_9708_init(struct ac97_codec * codec){ u16 codec72, codec6c; codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000; codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG); if ((codec72==0) && (codec6c==0)) { codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000); codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007); } else if ((codec72==0x8000) && (codec6c==0)) { codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001); codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008); } else if ((codec72==0x8000) && (codec6c==0x0080)) { /* nothing */ } codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); return 0;}static int sigmatel_9721_init(struct ac97_codec * codec){ /* Only set up secondary codec */ if (codec->id == 0) return 0; codec->codec_write(codec, AC97_SURROUND_MASTER, 0L); /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link sloc 3,4 = 0x01, slot 7,8 = 0x00, */ codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00); /* we don't have the crystal when we are on an AMR card, so use BIT_CLK as our clock source. Write the magic word ABBA and read back to enable register 0x78 */ codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); codec->codec_read(codec, AC97_SIGMATEL_CIC1); /* sync all the clocks*/ codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802); return 0;}static int sigmatel_9744_init(struct ac97_codec * codec){ // patch for SigmaTel codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002); codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); return 0;}static int wolfson_init(struct ac97_codec * codec){ codec->codec_write(codec, 0x72, 0x0808); codec->codec_write(codec, 0x74, 0x0808); // patch for DVD noise codec->codec_write(codec, 0x5a, 0x0200); // init vol as PCM vol codec->codec_write(codec, 0x70, codec->codec_read(codec, AC97_PCMOUT_VOL)); codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); return 0;}static int tritech_init(struct ac97_codec * codec){ codec->codec_write(codec, 0x26, 0x0300); codec->codec_write(codec, 0x26, 0x0000); codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); codec->codec_write(codec, AC97_RESERVED_3A, 0x0000); return 0;}/* copied from drivers/sound/maestro.c */static int tritech_maestro_init(struct ac97_codec * codec){ /* no idea what this does */ codec->codec_write(codec, 0x2A, 0x0001); codec->codec_write(codec, 0x2C, 0x0000); codec->codec_write(codec, 0x2C, 0XFFFF); return 0;}/* * This is basically standard AC97. It should work as a default for * almost all modern codecs. Note that some cards wire EAPD *backwards* * That side of it is up to the card driver not us to cope with. * */static int eapd_control(struct ac97_codec * codec, int on){ if(on) codec->codec_write(codec, AC97_POWER_CONTROL, codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); else codec->codec_write(codec, AC97_POWER_CONTROL, codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000); return 0;}/* * Crystal digital audio control (CS4299 */ static int crystal_digital_control(struct ac97_codec *codec, int mode){ u16 cv; switch(mode) { case 0: cv = 0x0; break; /* SPEN off */ case 1: cv = 0x8004; break; /* 48KHz digital */ case 2: cv = 0x8104; break; /* 44.1KHz digital */ default: return -1; /* Not supported yet(eg AC3) */ } codec->codec_write(codec, 0x68, cv); return 0;}/* copied from drivers/sound/maestro.c */#if 0 /* there has been 1 person on the planet with a pt101 that we know of. If they care, they can put this back in :) */static int pt101_init(struct ac97_codec * codec){ printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); /* who knows.. */ codec->codec_write(codec, 0x2A, 0x0001); codec->codec_write(codec, 0x2C, 0x0000); codec->codec_write(codec, 0x2C, 0xFFFF); codec->codec_write(codec, 0x10, 0x9F1F); codec->codec_write(codec, 0x12, 0x0808); codec->codec_write(codec, 0x14, 0x9F1F); codec->codec_write(codec, 0x16, 0x9F1F); codec->codec_write(codec, 0x18, 0x0404); codec->codec_write(codec, 0x1A, 0x0000); codec->codec_write(codec, 0x1C, 0x0000); codec->codec_write(codec, 0x02, 0x0404); codec->codec_write(codec, 0x04, 0x0808); codec->codec_write(codec, 0x0C, 0x801F); codec->codec_write(codec, 0x0E, 0x801F); return 0;}#endif EXPORT_SYMBOL(ac97_read_proc);EXPORT_SYMBOL(ac97_probe_codec);/* * AC97 library support routines */ /** * ac97_set_dac_rate - set codec rate adaption * @codec: ac97 code * @rate: rate in hertz * * Set the DAC rate. Assumes the codec supports VRA. The caller is * expected to have checked this little detail. */ unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate){ unsigned int new_rate = rate; u32 dacp; u32 mast_vol, phone_vol, mono_vol, pcm_vol; u32 mute_vol = 0x8000; /* The mute volume? */ if(rate != codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE)) { /* Mute several registers */ mast_vol = codec->codec_read(codec, AC97_MASTER_VOL_STEREO); mono_vol = codec->codec_read(codec, AC97_MASTER_VOL_MONO); phone_vol = codec->codec_read(codec, AC97_HEADPHONE_VOL); pcm_vol = codec->codec_read(codec, AC97_PCMOUT_VOL); codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mute_vol); codec->codec_write(codec, AC97_MASTER_VOL_MONO, mute_vol); codec->codec_write(codec, AC97_HEADPHONE_VOL, mute_vol); codec->codec_write(codec, AC97_PCMOUT_VOL, mute_vol); /* Power down the DAC */ dacp=codec->codec_read(codec, AC97_POWER_CONTROL); codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200); /* Load the rate and read the effective rate */ codec->codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate); new_rate=codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE); /* Power it back up */ codec->codec_write(codec, AC97_POWER_CONTROL, dacp); /* Restore volumes */ codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mast_vol); codec->codec_write(codec, AC97_MASTER_VOL_MONO, mono_vol); codec->codec_write(codec, AC97_HEADPHONE_VOL, phone_vol); codec->codec_write(codec, AC97_PCMOUT_VOL, pcm_vol); } return new_rate;}EXPORT_SYMBOL(ac97_set_dac_rate);/** * ac97_set_adc_rate - set codec rate adaption * @codec: ac97 code * @rate: rate in hertz * * Set the ADC rate. Assumes the codec supports VRA. The caller is * expected to have checked this little detail. */unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate){ unsigned int new_rate = rate; u32 dacp; if(rate != codec->codec_read(codec, AC97_PCM_LR_ADC_RATE)) { /* Power down the ADC */ dacp=codec->codec_read(codec, AC97_POWER_CONTROL); codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0100); /* Load the rate and read the effective rate */ codec->codec_write(codec, AC97_PCM_LR_ADC_RATE, rate); new_rate=codec->codec_read(codec, AC97_PCM_LR_ADC_RATE); /* Power it back up */ codec->codec_write(codec, AC97_POWER_CONTROL, dacp); } return new_rate;}EXPORT_SYMBOL(ac97_set_adc_rate);int ac97_save_state(struct ac97_codec *codec){ return 0; }EXPORT_SYMBOL(ac97_save_state);int ac97_restore_state(struct ac97_codec *codec){ int i; unsigned int left, right, val; for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!supported_mixer(codec, i)) continue; val = codec->mixer_state[i]; right = val >> 8; left = val & 0xff; codec->write_mixer(codec, i, left, right); } return 0;}EXPORT_SYMBOL(ac97_restore_state);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -