ac97.c revision 170289
144743Smarkm/*- 244743Smarkm * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 344743Smarkm * All rights reserved. 444743Smarkm * 544743Smarkm * Redistribution and use in source and binary forms, with or without 644743Smarkm * modification, are permitted provided that the following conditions 744743Smarkm * are met: 844743Smarkm * 1. Redistributions of source code must retain the above copyright 944743Smarkm * notice, this list of conditions and the following disclaimer. 1056977Sshin * 2. Redistributions in binary form must reproduce the above copyright 1156977Sshin * notice, this list of conditions and the following disclaimer in the 1244743Smarkm * documentation and/or other materials provided with the distribution. 1344743Smarkm * 1444743Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1544743Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1644743Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1744743Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1844743Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1944743Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2044743Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2144743Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2244743Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2344743Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2444743Smarkm * SUCH DAMAGE. 2544743Smarkm */ 2644743Smarkm 2744743Smarkm#include <dev/sound/pcm/sound.h> 2844743Smarkm#include <dev/sound/pcm/ac97.h> 2963152Sdwmalone#include <dev/sound/pcm/ac97_patch.h> 3063152Sdwmalone 3163152Sdwmalone#include <dev/pci/pcivar.h> 3263152Sdwmalone 3344743Smarkm#include "mixer_if.h" 3444743Smarkm 3544743SmarkmSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 170289 2007-06-04 18:25:08Z dwmalone $"); 3644743Smarkm 3744743SmarkmMALLOC_DEFINE(M_AC97, "ac97", "ac97 codec"); 3844743Smarkm 3944743Smarkmstruct ac97mixtable_entry { 4044743Smarkm int reg; /* register index */ 4144743Smarkm /* reg < 0 if inverted polarity */ 4244743Smarkm unsigned bits:4; /* width of control field */ 4344743Smarkm unsigned ofs:4; /* offset (only if stereo=0) */ 4444743Smarkm unsigned stereo:1; /* set for stereo controls */ 4544743Smarkm unsigned mute:1; /* bit15 is MUTE */ 4644743Smarkm unsigned recidx:4; /* index in rec mux */ 4744743Smarkm unsigned mask:1; /* use only masked bits */ 4844743Smarkm unsigned enable:1; /* entry is enabled */ 4944743Smarkm}; 5044743Smarkm 5144743Smarkm#define AC97_NAMELEN 16 5244743Smarkmstruct ac97_info { 5344743Smarkm kobj_t methods; 5444743Smarkm device_t dev; 5544743Smarkm void *devinfo; 5644743Smarkm u_int32_t id; 5744743Smarkm u_int32_t subvendor; 5844743Smarkm unsigned count, caps, se, extcaps, extid, extstat, noext:1; 5944743Smarkm u_int32_t flags; 6044743Smarkm struct ac97mixtable_entry mix[32]; 6144743Smarkm char name[AC97_NAMELEN]; 6244743Smarkm struct mtx *lock; 6344743Smarkm}; 6444743Smarkm 6544743Smarkmstruct ac97_vendorid { 6644743Smarkm u_int32_t id; 6744743Smarkm const char *name; 6844743Smarkm}; 6944743Smarkm 7044743Smarkmstruct ac97_codecid { 7144743Smarkm u_int32_t id; 7244743Smarkm u_int8_t stepmask; 7344743Smarkm u_int8_t noext:1; 7444743Smarkm char *name; 7544743Smarkm ac97_patch patch; 7644743Smarkm}; 7756977Sshin 7856977Sshinstatic const struct ac97mixtable_entry ac97mixtable_default[32] = { 7956977Sshin /* [offset] reg bits of st mu re mk en */ 8056977Sshin [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 }, 8144743Smarkm [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 }, 8244743Smarkm [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 }, 8356977Sshin [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 }, 8444743Smarkm [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 }, 8544743Smarkm [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 }, 8644743Smarkm [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 }, 8744743Smarkm [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 }, 8856977Sshin [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 }, 8956977Sshin [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 }, 9056977Sshin /* use igain for the mic 20dB boost */ 9156977Sshin [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 }, 9256977Sshin [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 }, 9344743Smarkm [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 }, 9444743Smarkm [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 }, 9556977Sshin [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 } 9644743Smarkm}; 9744743Smarkm 9844743Smarkmstatic const struct ac97_vendorid ac97vendorid[] = { 9944743Smarkm { 0x41445300, "Analog Devices" }, 10044743Smarkm { 0x414b4d00, "Asahi Kasei" }, 10144743Smarkm { 0x414c4300, "Realtek" }, 10256977Sshin { 0x414c4700, "Avance Logic" }, 10356977Sshin { 0x43525900, "Cirrus Logic" }, 10456977Sshin { 0x434d4900, "C-Media Electronics" }, 10556977Sshin { 0x43585400, "Conexant" }, 10656977Sshin { 0x44543000, "Diamond Technology" }, 10756977Sshin { 0x454d4300, "eMicro" }, 10856977Sshin { 0x45838300, "ESS Technology" }, 10956977Sshin { 0x48525300, "Intersil" }, 11056977Sshin { 0x49434500, "ICEnsemble" }, 11156977Sshin { 0x49544500, "ITE, Inc." }, 11256977Sshin { 0x4e534300, "National Semiconductor" }, 11356977Sshin { 0x50534300, "Philips Semiconductor" }, 11456977Sshin { 0x83847600, "SigmaTel" }, 11556977Sshin { 0x53494c00, "Silicon Laboratories" }, 11656977Sshin { 0x54524100, "TriTech" }, 11756977Sshin { 0x54584e00, "Texas Instruments" }, 11856977Sshin { 0x56494100, "VIA Technologies" }, 11956977Sshin { 0x57454300, "Winbond" }, 12056977Sshin { 0x574d4c00, "Wolfson" }, 12144743Smarkm { 0x594d4800, "Yamaha" }, 12263152Sdwmalone /* 12363152Sdwmalone * XXX This is a fluke, really! The real vendor 12444743Smarkm * should be SigmaTel, not this! This should be 12563152Sdwmalone * removed someday! 12663152Sdwmalone */ 12744743Smarkm { 0x01408300, "Creative" }, 12844743Smarkm { 0x00000000, NULL } 12956977Sshin}; 13056977Sshin 13156977Sshinstatic struct ac97_codecid ac97codecid[] = { 13244743Smarkm { 0x41445303, 0x00, 0, "AD1819", 0 }, 13356977Sshin { 0x41445340, 0x00, 0, "AD1881", 0 }, 13444743Smarkm { 0x41445348, 0x00, 0, "AD1881A", 0 }, 13544743Smarkm { 0x41445360, 0x00, 0, "AD1885", 0 }, 13644743Smarkm { 0x41445361, 0x00, 0, "AD1886", ad1886_patch }, 13744743Smarkm { 0x41445362, 0x00, 0, "AD1887", 0 }, 13844743Smarkm { 0x41445363, 0x00, 0, "AD1886A", 0 }, 13944743Smarkm { 0x41445368, 0x00, 0, "AD1888", ad198x_patch }, 14044743Smarkm { 0x41445370, 0x00, 0, "AD1980", ad198x_patch }, 14144743Smarkm { 0x41445372, 0x00, 0, "AD1981A", 0 }, 14244743Smarkm { 0x41445374, 0x00, 0, "AD1981B", ad1981b_patch }, 14344743Smarkm { 0x41445375, 0x00, 0, "AD1985", ad198x_patch }, 14444743Smarkm { 0x41445378, 0x00, 0, "AD1986", ad198x_patch }, 14544743Smarkm { 0x414b4d00, 0x00, 1, "AK4540", 0 }, 14644743Smarkm { 0x414b4d01, 0x00, 1, "AK4542", 0 }, 14744743Smarkm { 0x414b4d02, 0x00, 1, "AK4543", 0 }, 14844743Smarkm { 0x414b4d06, 0x00, 0, "AK4544A", 0 }, 14944743Smarkm { 0x454b4d07, 0x00, 0, "AK4545", 0 }, 15044743Smarkm { 0x414c4320, 0x0f, 0, "ALC100", 0 }, 15156977Sshin { 0x414c4730, 0x0f, 0, "ALC101", 0 }, 15256977Sshin { 0x414c4710, 0x0f, 0, "ALC200", 0 }, 15356977Sshin { 0x414c4740, 0x0f, 0, "ALC202", 0 }, 15456977Sshin { 0x414c4720, 0x0f, 0, "ALC650", 0 }, 15556977Sshin { 0x414c4752, 0x0f, 0, "ALC250", 0 }, 15656977Sshin { 0x414c4760, 0x0f, 0, "ALC655", alc655_patch }, 15756977Sshin { 0x414c4770, 0x0f, 0, "ALC203", 0 }, 15856977Sshin { 0x414c4780, 0x0f, 0, "ALC658", 0 }, 15956977Sshin { 0x414c4790, 0x0f, 0, "ALC850", 0 }, 16056977Sshin { 0x43525900, 0x07, 0, "CS4297", 0 }, 16156977Sshin { 0x43525910, 0x07, 0, "CS4297A", 0 }, 16256977Sshin { 0x43525920, 0x07, 0, "CS4294/98", 0 }, 16356977Sshin { 0x4352592d, 0x07, 0, "CS4294", 0 }, 16456977Sshin { 0x43525930, 0x07, 0, "CS4299", 0 }, 16556977Sshin { 0x43525940, 0x07, 0, "CS4201", 0 }, 16656977Sshin { 0x43525958, 0x07, 0, "CS4205", 0 }, 16756977Sshin { 0x43525960, 0x07, 0, "CS4291A", 0 }, 16856977Sshin { 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch }, 16956977Sshin { 0x434d4941, 0x00, 0, "CMI9738", 0 }, 17044743Smarkm { 0x434d4978, 0x00, 0, "CMI9761", 0 }, 17144743Smarkm { 0x434d4982, 0x00, 0, "CMI9761", 0 }, 17244743Smarkm { 0x434d4983, 0x00, 0, "CMI9761", 0 }, 17344743Smarkm { 0x43585421, 0x00, 0, "HSD11246", 0 }, 17444743Smarkm { 0x43585428, 0x07, 0, "CX20468", 0 }, 17544743Smarkm { 0x43585430, 0x00, 0, "CX20468-21", 0 }, 17644743Smarkm { 0x44543000, 0x00, 0, "DT0398", 0 }, 17744743Smarkm { 0x454d4323, 0x00, 0, "EM28023", 0 }, 17844743Smarkm { 0x454d4328, 0x00, 0, "EM28028", 0 }, 17956977Sshin { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */ 18044743Smarkm { 0x48525300, 0x00, 0, "HMP9701", 0 }, 18144743Smarkm { 0x49434501, 0x00, 0, "ICE1230", 0 }, 18244743Smarkm { 0x49434511, 0x00, 0, "ICE1232", 0 }, 18344743Smarkm { 0x49434514, 0x00, 0, "ICE1232A", 0 }, 18444743Smarkm { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */ 18544743Smarkm { 0x49544520, 0x00, 0, "ITE2226E", 0 }, 18644743Smarkm { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */ 18744743Smarkm { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */ 18856977Sshin { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */ 18956977Sshin { 0x4e534346, 0x00, 0, "LM4546A", 0 }, 19056977Sshin { 0x4e534348, 0x00, 0, "LM4548A", 0 }, 19156977Sshin { 0x4e534331, 0x00, 0, "LM4549", 0 }, 19244743Smarkm { 0x4e534349, 0x00, 0, "LM4549A", 0 }, 19344743Smarkm { 0x4e534350, 0x00, 0, "LM4550", 0 }, 19456977Sshin { 0x50534301, 0x00, 0, "UCB1510", 0 }, 19544743Smarkm { 0x50534304, 0x00, 0, "UCB1400", 0 }, 19663152Sdwmalone { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 }, 19744743Smarkm { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 }, 19844743Smarkm { 0x83847605, 0x00, 0, "STAC9704", 0 }, 19944743Smarkm { 0x83847608, 0x00, 0, "STAC9708/11", 0 }, 20044743Smarkm { 0x83847609, 0x00, 0, "STAC9721/23", 0 }, 20144743Smarkm { 0x83847644, 0x00, 0, "STAC9744/45", 0 }, 20244743Smarkm { 0x83847650, 0x00, 0, "STAC9750/51", 0 }, 20344743Smarkm { 0x83847652, 0x00, 0, "STAC9752/53", 0 }, 20444743Smarkm { 0x83847656, 0x00, 0, "STAC9756/57", 0 }, 20544743Smarkm { 0x83847658, 0x00, 0, "STAC9758/59", 0 }, 20644743Smarkm { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */ 20744743Smarkm { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */ 20844743Smarkm { 0x83847666, 0x00, 0, "STAC9766/67", 0 }, 20956977Sshin { 0x53494c22, 0x00, 0, "Si3036", 0 }, 21056977Sshin { 0x53494c23, 0x00, 0, "Si3038", 0 }, 21156977Sshin { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */ 21256977Sshin { 0x54524106, 0x00, 0, "TR28026", 0 }, 21344743Smarkm { 0x54524108, 0x00, 0, "TR28028", 0 }, 21444743Smarkm { 0x54524123, 0x00, 0, "TR28602", 0 }, 21556977Sshin { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 }, 21644743Smarkm { 0x54584e20, 0x00, 0, "TLC320AD90", 0 }, 21744743Smarkm { 0x56494161, 0x00, 0, "VIA1612A", 0 }, 21844743Smarkm { 0x56494170, 0x00, 0, "VIA1617A", 0 }, 21944743Smarkm { 0x574d4c00, 0x00, 0, "WM9701A", 0 }, 22044743Smarkm { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 }, 22144743Smarkm { 0x574d4c04, 0x00, 0, "WM9704Q", 0 }, 22244743Smarkm { 0x574d4c05, 0x00, 0, "WM9705/10", 0 }, 22344743Smarkm { 0x574d4d09, 0x00, 0, "WM9709", 0 }, 22444743Smarkm { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */ 22544743Smarkm { 0x57454301, 0x00, 0, "W83971D", 0 }, 22644743Smarkm { 0x594d4800, 0x00, 0, "YMF743", 0 }, 22744743Smarkm { 0x594d4802, 0x00, 0, "YMF752", 0 }, 22844743Smarkm { 0x594d4803, 0x00, 0, "YMF753", 0 }, 22944743Smarkm /* 23044743Smarkm * XXX This is a fluke, really! The real codec 23144743Smarkm * should be STAC9704, not this! This should be 23244743Smarkm * removed someday! 233 */ 234 { 0x01408384, 0x00, 0, "EV1938", 0 }, 235 { 0, 0, 0, NULL, 0 } 236}; 237 238static char *ac97enhancement[] = { 239 "no 3D Stereo Enhancement", 240 "Analog Devices Phat Stereo", 241 "Creative Stereo Enhancement", 242 "National Semi 3D Stereo Enhancement", 243 "Yamaha Ymersion", 244 "BBE 3D Stereo Enhancement", 245 "Crystal Semi 3D Stereo Enhancement", 246 "Qsound QXpander", 247 "Spatializer 3D Stereo Enhancement", 248 "SRS 3D Stereo Enhancement", 249 "Platform Tech 3D Stereo Enhancement", 250 "AKM 3D Audio", 251 "Aureal Stereo Enhancement", 252 "Aztech 3D Enhancement", 253 "Binaura 3D Audio Enhancement", 254 "ESS Technology Stereo Enhancement", 255 "Harman International VMAx", 256 "Nvidea 3D Stereo Enhancement", 257 "Philips Incredible Sound", 258 "Texas Instruments 3D Stereo Enhancement", 259 "VLSI Technology 3D Stereo Enhancement", 260 "TriTech 3D Stereo Enhancement", 261 "Realtek 3D Stereo Enhancement", 262 "Samsung 3D Stereo Enhancement", 263 "Wolfson Microelectronics 3D Enhancement", 264 "Delta Integration 3D Enhancement", 265 "SigmaTel 3D Enhancement", 266 "Reserved 27", 267 "Rockwell 3D Stereo Enhancement", 268 "Reserved 29", 269 "Reserved 30", 270 "Reserved 31" 271}; 272 273static char *ac97feature[] = { 274 "mic channel", 275 "reserved", 276 "tone", 277 "simulated stereo", 278 "headphone", 279 "bass boost", 280 "18 bit DAC", 281 "20 bit DAC", 282 "18 bit ADC", 283 "20 bit ADC" 284}; 285 286static char *ac97extfeature[] = { 287 "variable rate PCM", 288 "double rate PCM", 289 "reserved 1", 290 "variable rate mic", 291 "reserved 2", 292 "reserved 3", 293 "center DAC", 294 "surround DAC", 295 "LFE DAC", 296 "AMAP", 297 "reserved 4", 298 "reserved 5", 299 "reserved 6", 300 "reserved 7", 301}; 302 303u_int16_t 304ac97_rdcd(struct ac97_info *codec, int reg) 305{ 306 if (codec->flags & AC97_F_RDCD_BUG) { 307 u_int16_t i[2], j = 100; 308 309 i[0] = AC97_READ(codec->methods, codec->devinfo, reg); 310 i[1] = AC97_READ(codec->methods, codec->devinfo, reg); 311 while (i[0] != i[1] && j) 312 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg); 313#if 0 314 if (j < 100) { 315 device_printf(codec->dev, "%s(): Inconsistent register value at" 316 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j); 317 } 318#endif 319 return i[!(j & 1)]; 320 } 321 return AC97_READ(codec->methods, codec->devinfo, reg); 322} 323 324void 325ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val) 326{ 327 AC97_WRITE(codec->methods, codec->devinfo, reg, val); 328} 329 330static void 331ac97_reset(struct ac97_info *codec) 332{ 333 u_int32_t i, ps; 334 ac97_wrcd(codec, AC97_REG_RESET, 0); 335 for (i = 0; i < 500; i++) { 336 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS; 337 if (ps == AC97_POWER_STATUS) 338 return; 339 DELAY(1000); 340 } 341 device_printf(codec->dev, "AC97 reset timed out.\n"); 342} 343 344int 345ac97_setrate(struct ac97_info *codec, int which, int rate) 346{ 347 u_int16_t v; 348 349 switch(which) { 350 case AC97_REGEXT_FDACRATE: 351 case AC97_REGEXT_SDACRATE: 352 case AC97_REGEXT_LDACRATE: 353 case AC97_REGEXT_LADCRATE: 354 case AC97_REGEXT_MADCRATE: 355 break; 356 357 default: 358 return -1; 359 } 360 361 snd_mtxlock(codec->lock); 362 if (rate != 0) { 363 v = rate; 364 if (codec->extstat & AC97_EXTCAP_DRA) 365 v >>= 1; 366 ac97_wrcd(codec, which, v); 367 } 368 v = ac97_rdcd(codec, which); 369 if (codec->extstat & AC97_EXTCAP_DRA) 370 v <<= 1; 371 snd_mtxunlock(codec->lock); 372 return v; 373} 374 375int 376ac97_setextmode(struct ac97_info *codec, u_int16_t mode) 377{ 378 mode &= AC97_EXTCAPS; 379 if ((mode & ~codec->extcaps) != 0) { 380 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n", 381 mode); 382 return -1; 383 } 384 snd_mtxlock(codec->lock); 385 ac97_wrcd(codec, AC97_REGEXT_STAT, mode); 386 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 387 snd_mtxunlock(codec->lock); 388 return (mode == codec->extstat)? 0 : -1; 389} 390 391u_int16_t 392ac97_getextmode(struct ac97_info *codec) 393{ 394 return codec->extstat; 395} 396 397u_int16_t 398ac97_getextcaps(struct ac97_info *codec) 399{ 400 return codec->extcaps; 401} 402 403u_int16_t 404ac97_getcaps(struct ac97_info *codec) 405{ 406 return codec->caps; 407} 408 409u_int32_t 410ac97_getsubvendor(struct ac97_info *codec) 411{ 412 return codec->subvendor; 413} 414 415static int 416ac97_setrecsrc(struct ac97_info *codec, int channel) 417{ 418 struct ac97mixtable_entry *e = &codec->mix[channel]; 419 420 if (e->recidx > 0) { 421 int val = e->recidx - 1; 422 val |= val << 8; 423 snd_mtxlock(codec->lock); 424 ac97_wrcd(codec, AC97_REG_RECSEL, val); 425 snd_mtxunlock(codec->lock); 426 return 0; 427 } else 428 return -1; 429} 430 431static int 432ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right) 433{ 434 struct ac97mixtable_entry *e = &codec->mix[channel]; 435 436 if (e->reg && e->enable && e->bits) { 437 int mask, max, val, reg; 438 439 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */ 440 max = (1 << e->bits) - 1; /* actual range */ 441 mask = (max << 8) | max; /* bits of interest */ 442 443 if (!e->stereo) 444 right = left; 445 446 /* 447 * Invert the range if the polarity requires so, 448 * then scale to 0..max-1 to compute the value to 449 * write into the codec, and scale back to 0..100 450 * for the return value. 451 */ 452 if (e->reg > 0) { 453 left = 100 - left; 454 right = 100 - right; 455 } 456 457 left = (left * max) / 100; 458 right = (right * max) / 100; 459 460 val = (left << 8) | right; 461 462 left = (left * 100) / max; 463 right = (right * 100) / max; 464 465 if (e->reg > 0) { 466 left = 100 - left; 467 right = 100 - right; 468 } 469 470 /* 471 * For mono controls, trim val and mask, also taking 472 * care of e->ofs (offset of control field). 473 */ 474 if (e->ofs) { 475 val &= max; 476 val <<= e->ofs; 477 mask = (max << e->ofs); 478 } 479 480 /* 481 * If we have a mute bit, add it to the mask and 482 * update val and set mute if both channels require a 483 * zero volume. 484 */ 485 if (e->mute == 1) { 486 mask |= AC97_MUTE; 487 if (left == 0 && right == 0) 488 val = AC97_MUTE; 489 } 490 491 /* 492 * If the mask bit is set, do not alter the other bits. 493 */ 494 snd_mtxlock(codec->lock); 495 if (e->mask) { 496 int cur = ac97_rdcd(codec, reg); 497 val |= cur & ~(mask); 498 } 499 ac97_wrcd(codec, reg, val); 500 snd_mtxunlock(codec->lock); 501 return left | (right << 8); 502 } else { 503#if 0 504 printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); 505#endif 506 return -1; 507 } 508} 509 510static void 511ac97_fix_auxout(struct ac97_info *codec) 512{ 513 int keep_ogain; 514 515 /* 516 * By default, The ac97 aux_out register (0x04) corresponds to OSS's 517 * OGAIN setting. 518 * 519 * We first check whether aux_out is a valid register. If not 520 * we may not want to keep ogain. 521 */ 522 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000; 523 524 /* 525 * Determine what AUX_OUT really means, it can be: 526 * 527 * 1. Headphone out. 528 * 2. 4-Channel Out 529 * 3. True line level out (effectively master volume). 530 * 531 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}. 532 */ 533 if (codec->extcaps & AC97_EXTCAP_SDAC && 534 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) { 535 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND; 536 keep_ogain = 1; 537 } 538 539 if (keep_ogain == 0) { 540 bzero(&codec->mix[SOUND_MIXER_OGAIN], 541 sizeof(codec->mix[SOUND_MIXER_OGAIN])); 542 } 543} 544 545static void 546ac97_fix_tone(struct ac97_info *codec) 547{ 548 /* 549 * YMF chips does not indicate tone and 3D enhancement capability 550 * in the AC97_REG_RESET register. 551 */ 552 switch (codec->id) { 553 case 0x594d4800: /* YMF743 */ 554 case 0x594d4803: /* YMF753 */ 555 codec->caps |= AC97_CAP_TONE; 556 codec->se |= 0x04; 557 break; 558 case 0x594d4802: /* YMF752 */ 559 codec->se |= 0x04; 560 break; 561 default: 562 break; 563 } 564 565 /* Hide treble and bass if they don't exist */ 566 if ((codec->caps & AC97_CAP_TONE) == 0) { 567 bzero(&codec->mix[SOUND_MIXER_BASS], 568 sizeof(codec->mix[SOUND_MIXER_BASS])); 569 bzero(&codec->mix[SOUND_MIXER_TREBLE], 570 sizeof(codec->mix[SOUND_MIXER_TREBLE])); 571 } 572} 573 574static const char* 575ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf) 576{ 577 if (cname == NULL) { 578 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id); 579 return buf; 580 } 581 582 if (vname == NULL) vname = "Unknown"; 583 584 if (bootverbose) { 585 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id); 586 } else { 587 sprintf(buf, "%s %s AC97 Codec", vname, cname); 588 } 589 return buf; 590} 591 592static unsigned 593ac97_initmixer(struct ac97_info *codec) 594{ 595 ac97_patch codec_patch; 596 const char *cname, *vname; 597 char desc[80]; 598 u_int8_t model, step; 599 unsigned i, j, k, bit, old; 600 u_int32_t id; 601 int reg; 602 603 snd_mtxlock(codec->lock); 604 codec->count = AC97_INIT(codec->methods, codec->devinfo); 605 if (codec->count == 0) { 606 device_printf(codec->dev, "ac97 codec init failed\n"); 607 snd_mtxunlock(codec->lock); 608 return ENODEV; 609 } 610 611 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000); 612 ac97_reset(codec); 613 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000); 614 615 i = ac97_rdcd(codec, AC97_REG_RESET); 616 j = ac97_rdcd(codec, AC97_REG_RESET); 617 /* 618 * Let see if this codec can return consistent value. 619 * If not, turn on aggressive read workaround 620 * (STAC9704 comes in mind). 621 */ 622 if (i != j) { 623 codec->flags |= AC97_F_RDCD_BUG; 624 i = ac97_rdcd(codec, AC97_REG_RESET); 625 } 626 codec->caps = i & 0x03ff; 627 codec->se = (i & 0x7c00) >> 10; 628 629 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2); 630 if (id == 0 || id == 0xffffffff) { 631 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id); 632 snd_mtxunlock(codec->lock); 633 return ENODEV; 634 } 635 636 codec->id = id; 637 codec->subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16; 638 codec->subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) & 639 0x0000ffff; 640 codec->noext = 0; 641 codec_patch = NULL; 642 643 cname = NULL; 644 model = step = 0; 645 for (i = 0; ac97codecid[i].id; i++) { 646 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask; 647 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) { 648 codec->noext = ac97codecid[i].noext; 649 codec_patch = ac97codecid[i].patch; 650 cname = ac97codecid[i].name; 651 model = (id & modelmask) & 0xff; 652 step = (id & ~modelmask) & 0xff; 653 break; 654 } 655 } 656 657 vname = NULL; 658 for (i = 0; ac97vendorid[i].id; i++) { 659 if (ac97vendorid[i].id == (id & 0xffffff00)) { 660 vname = ac97vendorid[i].name; 661 break; 662 } 663 } 664 665 codec->extcaps = 0; 666 codec->extid = 0; 667 codec->extstat = 0; 668 if (!codec->noext) { 669 i = ac97_rdcd(codec, AC97_REGEXT_ID); 670 if (i != 0xffff) { 671 codec->extcaps = i & 0x3fff; 672 codec->extid = (i & 0xc000) >> 14; 673 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 674 } 675 } 676 677 for (i = 0; i < 32; i++) { 678 codec->mix[i] = ac97mixtable_default[i]; 679 } 680 ac97_fix_auxout(codec); 681 ac97_fix_tone(codec); 682 if (codec_patch) 683 codec_patch(codec); 684 685 for (i = 0; i < 32; i++) { 686 k = codec->noext? codec->mix[i].enable : 1; 687 reg = codec->mix[i].reg; 688 if (reg < 0) 689 reg = -reg; 690 if (k && reg) { 691 j = old = ac97_rdcd(codec, reg); 692 /* 693 * Test for mute bit (except for AC97_MIX_TONE, 694 * where we simply assume it as available). 695 */ 696 if (codec->mix[i].mute) { 697 ac97_wrcd(codec, reg, j | 0x8000); 698 j = ac97_rdcd(codec, reg); 699 } else 700 j |= 0x8000; 701 if ((j & 0x8000)) { 702 /* 703 * Test whether the control width should be 704 * 4, 5 or 6 bit. For 5bit register, we should 705 * test it whether it's really 5 or 6bit. Leave 706 * 4bit register alone, because sometimes an 707 * attempt to write past 4th bit may cause 708 * incorrect result especially for AC97_MIX_BEEP 709 * (ac97 2.3). 710 */ 711 bit = codec->mix[i].bits; 712 if (bit == 5) 713 bit++; 714 j = ((1 << bit) - 1) << codec->mix[i].ofs; 715 ac97_wrcd(codec, reg, 716 j | (codec->mix[i].mute ? 0x8000 : 0)); 717 k = ac97_rdcd(codec, reg) & j; 718 k >>= codec->mix[i].ofs; 719 if (reg == AC97_MIX_TONE && 720 ((k & 0x0001) == 0x0000)) 721 k >>= 1; 722 for (j = 0; k >> j; j++) 723 ; 724 if (j != 0) { 725#if 0 726 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n", 727 i, k, bit, codec->mix[i].bits, j); 728#endif 729 codec->mix[i].enable = 1; 730 codec->mix[i].bits = j; 731 } else if (reg == AC97_MIX_BEEP) { 732 /* 733 * Few codec such as CX20468-21 does 734 * have this control register, although 735 * the only usable part is the mute bit. 736 */ 737 codec->mix[i].enable = 1; 738 } else 739 codec->mix[i].enable = 0; 740 } else 741 codec->mix[i].enable = 0; 742 ac97_wrcd(codec, reg, old); 743 } 744#if 0 745 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); 746#endif 747 } 748 749 device_printf(codec->dev, "<%s>\n", 750 ac97_hw_desc(codec->id, vname, cname, desc)); 751 752 if (bootverbose) { 753 if (codec->flags & AC97_F_RDCD_BUG) 754 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n"); 755 device_printf(codec->dev, "Codec features "); 756 for (i = j = 0; i < 10; i++) 757 if (codec->caps & (1 << i)) 758 printf("%s%s", j++? ", " : "", ac97feature[i]); 759 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits); 760 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]); 761 762 if (codec->extcaps != 0 || codec->extid) { 763 device_printf(codec->dev, "%s codec", 764 codec->extid? "Secondary" : "Primary"); 765 if (codec->extcaps) 766 printf(" extended features "); 767 for (i = j = 0; i < 14; i++) 768 if (codec->extcaps & (1 << i)) 769 printf("%s%s", j++? ", " : "", ac97extfeature[i]); 770 printf("\n"); 771 } 772 } 773 774 i = 0; 775 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) { 776 if (++i == 100) { 777 device_printf(codec->dev, "ac97 codec reports dac not ready\n"); 778 break; 779 } 780 DELAY(1000); 781 } 782 if (bootverbose) 783 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i); 784 snd_mtxunlock(codec->lock); 785 return 0; 786} 787 788static unsigned 789ac97_reinitmixer(struct ac97_info *codec) 790{ 791 snd_mtxlock(codec->lock); 792 codec->count = AC97_INIT(codec->methods, codec->devinfo); 793 if (codec->count == 0) { 794 device_printf(codec->dev, "ac97 codec init failed\n"); 795 snd_mtxunlock(codec->lock); 796 return ENODEV; 797 } 798 799 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000); 800 ac97_reset(codec); 801 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000); 802 803 if (!codec->noext) { 804 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat); 805 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS) 806 != codec->extstat) 807 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n", 808 codec->extstat, 809 ac97_rdcd(codec, AC97_REGEXT_STAT) & 810 AC97_EXTCAPS); 811 } 812 813 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) 814 device_printf(codec->dev, "ac97 codec reports dac not ready\n"); 815 snd_mtxunlock(codec->lock); 816 return 0; 817} 818 819struct ac97_info * 820ac97_create(device_t dev, void *devinfo, kobj_class_t cls) 821{ 822 struct ac97_info *codec; 823 int eapdinv; 824 825 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT | M_ZERO); 826 if (codec == NULL) 827 return NULL; 828 829 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev)); 830 codec->lock = snd_mtxcreate(codec->name, "ac97 codec"); 831 codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO); 832 codec->dev = dev; 833 codec->devinfo = devinfo; 834 codec->flags = 0; 835 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 836 "eapdinv", &eapdinv) == 0) { 837 if (eapdinv != 0) 838 codec->flags |= AC97_F_EAPD_INV; 839 } 840 return codec; 841} 842 843void 844ac97_destroy(struct ac97_info *codec) 845{ 846 snd_mtxlock(codec->lock); 847 if (codec->methods != NULL) 848 kobj_delete(codec->methods, M_AC97); 849 snd_mtxfree(codec->lock); 850 free(codec, M_AC97); 851} 852 853void 854ac97_setflags(struct ac97_info *codec, u_int32_t val) 855{ 856 codec->flags = val; 857} 858 859u_int32_t 860ac97_getflags(struct ac97_info *codec) 861{ 862 return codec->flags; 863} 864 865/* -------------------------------------------------------------------- */ 866 867#ifdef SND_DYNSYSCTL 868static int 869sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS) 870{ 871 struct ac97_info *codec; 872 int ea, inv, err = 0; 873 u_int16_t val; 874 875 codec = oidp->oid_arg1; 876 if (codec == NULL || codec->id == 0 || codec->lock == NULL) 877 return EINVAL; 878 snd_mtxlock(codec->lock); 879 val = ac97_rdcd(codec, AC97_REG_POWER); 880 inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1; 881 ea = (val >> 15) ^ inv; 882 snd_mtxunlock(codec->lock); 883 err = sysctl_handle_int(oidp, &ea, 0, req); 884 if (err == 0 && req->newptr != NULL) { 885 if (ea != 0 && ea != 1) 886 return EINVAL; 887 if (ea != ((val >> 15) ^ inv)) { 888 snd_mtxlock(codec->lock); 889 ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000); 890 snd_mtxunlock(codec->lock); 891 } 892 } 893 return err; 894} 895#endif 896 897static void 898ac97_init_sysctl(struct ac97_info *codec) 899{ 900#ifdef SND_DYNSYSCTL 901 u_int16_t orig, val; 902 903 if (codec == NULL || codec->dev == NULL) 904 return; 905 snd_mtxlock(codec->lock); 906 orig = ac97_rdcd(codec, AC97_REG_POWER); 907 ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000); 908 val = ac97_rdcd(codec, AC97_REG_POWER); 909 ac97_wrcd(codec, AC97_REG_POWER, orig); 910 snd_mtxunlock(codec->lock); 911 if ((val & 0x8000) == (orig & 0x8000)) 912 return; 913 SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev), 914 SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)), 915 OID_AUTO, "eapd", CTLTYPE_INT | CTLFLAG_RW, 916 codec, sizeof(codec), sysctl_hw_snd_ac97_eapd, 917 "I", "AC97 External Amplifier"); 918#endif 919} 920 921static int 922ac97mix_init(struct snd_mixer *m) 923{ 924 struct ac97_info *codec = mix_getdevinfo(m); 925 u_int32_t i, mask; 926 927 if (codec == NULL) 928 return -1; 929 930 if (ac97_initmixer(codec)) 931 return -1; 932 933 switch (codec->id) { 934 case 0x41445374: /* AD1981B */ 935 if (codec->subvendor == 0x02d91014) { 936 /* 937 * IBM Thinkcentre: 938 * Tie "ogain" and "phone" to "vol" since its 939 * master volume is basically useless and can't 940 * control anything. 941 */ 942 mask = 0; 943 if (codec->mix[SOUND_MIXER_OGAIN].enable) 944 mask |= SOUND_MASK_OGAIN; 945 if (codec->mix[SOUND_MIXER_PHONEOUT].enable) 946 mask |= SOUND_MASK_PHONEOUT; 947 if (codec->mix[SOUND_MIXER_VOLUME].enable) 948 mix_setparentchild(m, SOUND_MIXER_VOLUME, 949 mask); 950 else { 951 mix_setparentchild(m, SOUND_MIXER_VOLUME, 952 mask); 953 mix_setrealdev(m, SOUND_MIXER_VOLUME, 954 SOUND_MIXER_NONE); 955 } 956 } 957 break; 958 case 0x434d4941: /* CMI9738 */ 959 case 0x434d4961: /* CMI9739 */ 960 case 0x434d4978: /* CMI9761 */ 961 case 0x434d4982: /* CMI9761 */ 962 case 0x434d4983: /* CMI9761 */ 963 ac97_wrcd(codec, AC97_MIX_PCM, 0); 964 bzero(&codec->mix[SOUND_MIXER_PCM], 965 sizeof(codec->mix[SOUND_MIXER_PCM])); 966 pcm_setflags(codec->dev, pcm_getflags(codec->dev) | 967 SD_F_SOFTPCMVOL); 968 /* XXX How about master volume ? */ 969 break; 970 default: 971 break; 972 } 973 974#if 0 975 /* XXX For the sake of debugging purposes */ 976 mix_setparentchild(m, SOUND_MIXER_VOLUME, 977 SOUND_MASK_PCM | SOUND_MASK_CD); 978 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); 979 ac97_wrcd(codec, AC97_MIX_MASTER, 0); 980#endif 981 982 mask = 0; 983 for (i = 0; i < 32; i++) 984 mask |= codec->mix[i].enable? 1 << i : 0; 985 mix_setdevs(m, mask); 986 987 mask = 0; 988 for (i = 0; i < 32; i++) 989 mask |= codec->mix[i].recidx? 1 << i : 0; 990 mix_setrecdevs(m, mask); 991 992 ac97_init_sysctl(codec); 993 994 return 0; 995} 996 997static int 998ac97mix_uninit(struct snd_mixer *m) 999{ 1000 struct ac97_info *codec = mix_getdevinfo(m); 1001 1002 if (codec == NULL) 1003 return -1; 1004 /* 1005 if (ac97_uninitmixer(codec)) 1006 return -1; 1007 */ 1008 ac97_destroy(codec); 1009 return 0; 1010} 1011 1012static int 1013ac97mix_reinit(struct snd_mixer *m) 1014{ 1015 struct ac97_info *codec = mix_getdevinfo(m); 1016 1017 if (codec == NULL) 1018 return -1; 1019 return ac97_reinitmixer(codec); 1020} 1021 1022static int 1023ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1024{ 1025 struct ac97_info *codec = mix_getdevinfo(m); 1026 1027 if (codec == NULL) 1028 return -1; 1029 return ac97_setmixer(codec, dev, left, right); 1030} 1031 1032static int 1033ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src) 1034{ 1035 int i; 1036 struct ac97_info *codec = mix_getdevinfo(m); 1037 1038 if (codec == NULL) 1039 return -1; 1040 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 1041 if ((src & (1 << i)) != 0) 1042 break; 1043 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1; 1044} 1045 1046static kobj_method_t ac97mixer_methods[] = { 1047 KOBJMETHOD(mixer_init, ac97mix_init), 1048 KOBJMETHOD(mixer_uninit, ac97mix_uninit), 1049 KOBJMETHOD(mixer_reinit, ac97mix_reinit), 1050 KOBJMETHOD(mixer_set, ac97mix_set), 1051 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc), 1052 { 0, 0 } 1053}; 1054MIXER_DECLARE(ac97mixer); 1055 1056/* -------------------------------------------------------------------- */ 1057 1058kobj_class_t 1059ac97_getmixerclass(void) 1060{ 1061 return &ac97mixer_class; 1062} 1063