ac97.c revision 149949
1257462Semaste/*- 2146082Skientzle * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3146082Skientzle * All rights reserved. 4146082Skientzle * 5146082Skientzle * Redistribution and use in source and binary forms, with or without 6146082Skientzle * modification, are permitted provided that the following conditions 7146082Skientzle * are met: 8146082Skientzle * 1. Redistributions of source code must retain the above copyright 9146082Skientzle * notice, this list of conditions and the following disclaimer. 10146082Skientzle * 2. Redistributions in binary form must reproduce the above copyright 11146082Skientzle * notice, this list of conditions and the following disclaimer in the 12146082Skientzle * documentation and/or other materials provided with the distribution. 13146082Skientzle * 14146082Skientzle * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15146082Skientzle * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16146082Skientzle * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17146082Skientzle * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18146082Skientzle * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19146082Skientzle * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20146082Skientzle * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21146082Skientzle * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22146082Skientzle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23146082Skientzle * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24146082Skientzle * SUCH DAMAGE. 25146082Skientzle */ 26146082Skientzle 27146082Skientzle#include <dev/sound/pcm/sound.h> 28146082Skientzle#include <dev/sound/pcm/ac97.h> 29146082Skientzle#include <dev/sound/pcm/ac97_patch.h> 30146082Skientzle 31146082Skientzle#include "mixer_if.h" 32146082Skientzle 33146082SkientzleSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 149949 2005-09-10 17:42:59Z netchild $"); 34146082Skientzle 35146082SkientzleMALLOC_DEFINE(M_AC97, "ac97", "ac97 codec"); 36146082Skientzle 37146082Skientzlestruct ac97mixtable_entry { 38146082Skientzle int reg:8; /* register index */ 39146082Skientzle /* reg < 0 if inverted polarity */ 40146082Skientzle unsigned bits:4; /* width of control field */ 41146082Skientzle unsigned ofs:4; /* offset (only if stereo=0) */ 42146082Skientzle unsigned stereo:1; /* set for stereo controls */ 43146082Skientzle unsigned mute:1; /* bit15 is MUTE */ 44146082Skientzle unsigned recidx:4; /* index in rec mux */ 45 unsigned mask:1; /* use only masked bits */ 46 unsigned enable:1; /* entry is enabled */ 47}; 48 49#define AC97_NAMELEN 16 50struct ac97_info { 51 kobj_t methods; 52 device_t dev; 53 void *devinfo; 54 u_int32_t id; 55 unsigned count, caps, se, extcaps, extid, extstat, noext:1; 56 u_int32_t flags; 57 struct ac97mixtable_entry mix[32]; 58 char name[AC97_NAMELEN]; 59 struct mtx *lock; 60}; 61 62struct ac97_vendorid { 63 u_int32_t id; 64 const char *name; 65}; 66 67struct ac97_codecid { 68 u_int32_t id; 69 u_int8_t stepmask; 70 u_int8_t noext:1; 71 char *name; 72 ac97_patch patch; 73}; 74 75static const struct ac97mixtable_entry ac97mixtable_default[32] = { 76 /* [offset] reg bits of st mu re mk en */ 77 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 }, 78 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 }, 79 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 }, 80 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 }, 81 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 }, 82 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 }, 83 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 }, 84 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 }, 85 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 }, 86 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 }, 87#if 0 88 /* use igain for the mic 20dB boost */ 89 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 }, 90#endif 91 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 }, 92 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 }, 93 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 }, 94 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 } 95}; 96 97static const struct ac97_vendorid ac97vendorid[] = { 98 { 0x41445300, "Analog Devices" }, 99 { 0x414b4d00, "Asahi Kasei" }, 100 { 0x414c4300, "Realtek" }, 101 { 0x414c4700, "Avance Logic" }, 102 { 0x43525900, "Cirrus Logic" }, 103 { 0x434d4900, "C-Media Electronics" }, 104 { 0x43585400, "Conexant" }, 105 { 0x44543000, "Diamond Technology" }, 106 { 0x454d4300, "eMicro" }, 107 { 0x45838300, "ESS Technology" }, 108 { 0x48525300, "Intersil" }, 109 { 0x49434500, "ICEnsemble" }, 110 { 0x49544500, "ITE, Inc." }, 111 { 0x4e534300, "National Semiconductor" }, 112 { 0x50534300, "Philips Semiconductor" }, 113 { 0x83847600, "SigmaTel" }, 114 { 0x53494c00, "Silicon Laboratories" }, 115 { 0x54524100, "TriTech" }, 116 { 0x54584e00, "Texas Instruments" }, 117 { 0x56494100, "VIA Technologies" }, 118 { 0x57454300, "Winbond" }, 119 { 0x574d4c00, "Wolfson" }, 120 { 0x594d4800, "Yamaha" }, 121 /* 122 * XXX This is a fluke, really! The real vendor 123 * should be SigmaTel, not this! This should be 124 * removed someday! 125 */ 126 { 0x01408300, "Creative" }, 127 { 0x00000000, NULL } 128}; 129 130static struct ac97_codecid ac97codecid[] = { 131 { 0x41445303, 0x00, 0, "AD1819", 0 }, 132 { 0x41445340, 0x00, 0, "AD1881", 0 }, 133 { 0x41445348, 0x00, 0, "AD1881A", 0 }, 134 { 0x41445360, 0x00, 0, "AD1885", 0 }, 135 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch }, 136 { 0x41445362, 0x00, 0, "AD1887", 0 }, 137 { 0x41445363, 0x00, 0, "AD1886A", 0 }, 138 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch }, 139 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch }, 140 { 0x41445372, 0x00, 0, "AD1981A", 0 }, 141 { 0x41445374, 0x00, 0, "AD1981B", 0 }, 142 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch }, 143 { 0x414b4d00, 0x00, 1, "AK4540", 0 }, 144 { 0x414b4d01, 0x00, 1, "AK4542", 0 }, 145 { 0x414b4d02, 0x00, 1, "AK4543", 0 }, 146 { 0x414b4d06, 0x00, 0, "AK4544A", 0 }, 147 { 0x454b4d07, 0x00, 0, "AK4545", 0 }, 148 { 0x414c4320, 0x0f, 0, "ALC100", 0 }, 149 { 0x414c4730, 0x0f, 0, "ALC101", 0 }, 150 { 0x414c4710, 0x0f, 0, "ALC200", 0 }, 151 { 0x414c4740, 0x0f, 0, "ALC202", 0 }, 152 { 0x414c4720, 0x0f, 0, "ALC650", 0 }, 153 { 0x414c4760, 0x0f, 0, "ALC655", 0 }, 154 { 0x414c4780, 0x0f, 0, "ALC658", 0 }, 155 { 0x414c4790, 0x0f, 0, "ALC850", 0 }, 156 { 0x43525900, 0x07, 0, "CS4297", 0 }, 157 { 0x43525910, 0x07, 0, "CS4297A", 0 }, 158 { 0x43525920, 0x07, 0, "CS4294/98", 0 }, 159 { 0x4352592d, 0x07, 0, "CS4294", 0 }, 160 { 0x43525930, 0x07, 0, "CS4299", 0 }, 161 { 0x43525940, 0x07, 0, "CS4201", 0 }, 162 { 0x43525958, 0x07, 0, "CS4205", 0 }, 163 { 0x43525960, 0x07, 0, "CS4291A", 0 }, 164 { 0x434d4961, 0x00, 0, "CMI9739", 0 }, 165 { 0x434d4941, 0x00, 0, "CMI9738", 0 }, 166 { 0x43585421, 0x00, 0, "HSD11246", 0 }, 167 { 0x43585428, 0x07, 0, "CX20468", 0 }, 168 { 0x44543000, 0x00, 0, "DT0398", 0 }, 169 { 0x454d4323, 0x00, 0, "EM28023", 0 }, 170 { 0x454d4328, 0x00, 0, "EM28028", 0 }, 171 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */ 172 { 0x48525300, 0x00, 0, "HMP9701", 0 }, 173 { 0x49434501, 0x00, 0, "ICE1230", 0 }, 174 { 0x49434511, 0x00, 0, "ICE1232", 0 }, 175 { 0x49434514, 0x00, 0, "ICE1232A", 0 }, 176 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */ 177 { 0x49544520, 0x00, 0, "ITE2226E", 0 }, 178 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */ 179 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */ 180 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */ 181 { 0x4e534346, 0x00, 0, "LM4546A", 0 }, 182 { 0x4e534348, 0x00, 0, "LM4548A", 0 }, 183 { 0x4e534331, 0x00, 0, "LM4549", 0 }, 184 { 0x4e534349, 0x00, 0, "LM4549A", 0 }, 185 { 0x4e534350, 0x00, 0, "LM4550", 0 }, 186 { 0x50534301, 0x00, 0, "UCB1510", 0 }, 187 { 0x50534304, 0x00, 0, "UCB1400", 0 }, 188 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 }, 189 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 }, 190 { 0x83847605, 0x00, 0, "STAC9704", 0 }, 191 { 0x83847608, 0x00, 0, "STAC9708/11", 0 }, 192 { 0x83847609, 0x00, 0, "STAC9721/23", 0 }, 193 { 0x83847644, 0x00, 0, "STAC9744/45", 0 }, 194 { 0x83847650, 0x00, 0, "STAC9750/51", 0 }, 195 { 0x83847652, 0x00, 0, "STAC9752/53", 0 }, 196 { 0x83847656, 0x00, 0, "STAC9756/57", 0 }, 197 { 0x83847658, 0x00, 0, "STAC9758/59", 0 }, 198 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */ 199 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */ 200 { 0x53494c22, 0x00, 0, "Si3036", 0 }, 201 { 0x53494c23, 0x00, 0, "Si3038", 0 }, 202 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */ 203 { 0x54524106, 0x00, 0, "TR28026", 0 }, 204 { 0x54524108, 0x00, 0, "TR28028", 0 }, 205 { 0x54524123, 0x00, 0, "TR28602", 0 }, 206 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 }, 207 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 }, 208 { 0x56494161, 0x00, 0, "VIA1612A", 0 }, 209 { 0x574d4c00, 0x00, 0, "WM9701A", 0 }, 210 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 }, 211 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 }, 212 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 }, 213 { 0x574d4d09, 0x00, 0, "WM9709", 0 }, 214 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */ 215 { 0x57454301, 0x00, 0, "W83971D", 0 }, 216 { 0x594d4800, 0x00, 0, "YMF743", 0 }, 217 { 0x594d4802, 0x00, 0, "YMF752", 0 }, 218 { 0x594d4803, 0x00, 0, "YMF753", 0 }, 219 /* 220 * XXX This is a fluke, really! The real codec 221 * should be STAC9704, not this! This should be 222 * removed someday! 223 */ 224 { 0x01408384, 0x00, 0, "EV1938", 0 }, 225 { 0, 0, 0, NULL, 0 } 226}; 227 228static char *ac97enhancement[] = { 229 "no 3D Stereo Enhancement", 230 "Analog Devices Phat Stereo", 231 "Creative Stereo Enhancement", 232 "National Semi 3D Stereo Enhancement", 233 "Yamaha Ymersion", 234 "BBE 3D Stereo Enhancement", 235 "Crystal Semi 3D Stereo Enhancement", 236 "Qsound QXpander", 237 "Spatializer 3D Stereo Enhancement", 238 "SRS 3D Stereo Enhancement", 239 "Platform Tech 3D Stereo Enhancement", 240 "AKM 3D Audio", 241 "Aureal Stereo Enhancement", 242 "Aztech 3D Enhancement", 243 "Binaura 3D Audio Enhancement", 244 "ESS Technology Stereo Enhancement", 245 "Harman International VMAx", 246 "Nvidea 3D Stereo Enhancement", 247 "Philips Incredible Sound", 248 "Texas Instruments 3D Stereo Enhancement", 249 "VLSI Technology 3D Stereo Enhancement", 250 "TriTech 3D Stereo Enhancement", 251 "Realtek 3D Stereo Enhancement", 252 "Samsung 3D Stereo Enhancement", 253 "Wolfson Microelectronics 3D Enhancement", 254 "Delta Integration 3D Enhancement", 255 "SigmaTel 3D Enhancement", 256 "Reserved 27", 257 "Rockwell 3D Stereo Enhancement", 258 "Reserved 29", 259 "Reserved 30", 260 "Reserved 31" 261}; 262 263static char *ac97feature[] = { 264 "mic channel", 265 "reserved", 266 "tone", 267 "simulated stereo", 268 "headphone", 269 "bass boost", 270 "18 bit DAC", 271 "20 bit DAC", 272 "18 bit ADC", 273 "20 bit ADC" 274}; 275 276static char *ac97extfeature[] = { 277 "variable rate PCM", 278 "double rate PCM", 279 "reserved 1", 280 "variable rate mic", 281 "reserved 2", 282 "reserved 3", 283 "center DAC", 284 "surround DAC", 285 "LFE DAC", 286 "AMAP", 287 "reserved 4", 288 "reserved 5", 289 "reserved 6", 290 "reserved 7", 291}; 292 293u_int16_t 294ac97_rdcd(struct ac97_info *codec, int reg) 295{ 296 if (codec->flags & AC97_F_RDCD_BUG) { 297 u_int16_t i[2], j = 100; 298 299 i[0] = AC97_READ(codec->methods, codec->devinfo, reg); 300 i[1] = AC97_READ(codec->methods, codec->devinfo, reg); 301 while (i[0] != i[1] && j) 302 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg); 303#if 0 304 if (j < 100) { 305 device_printf(codec->dev, "%s(): Inconsistent register value at" 306 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j); 307 } 308#endif 309 return i[!(j & 1)]; 310 } 311 return AC97_READ(codec->methods, codec->devinfo, reg); 312} 313 314void 315ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val) 316{ 317 AC97_WRITE(codec->methods, codec->devinfo, reg, val); 318} 319 320static void 321ac97_reset(struct ac97_info *codec) 322{ 323 u_int32_t i, ps; 324 ac97_wrcd(codec, AC97_REG_RESET, 0); 325 for (i = 0; i < 500; i++) { 326 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS; 327 if (ps == AC97_POWER_STATUS) 328 return; 329 DELAY(1000); 330 } 331 device_printf(codec->dev, "AC97 reset timed out.\n"); 332} 333 334int 335ac97_setrate(struct ac97_info *codec, int which, int rate) 336{ 337 u_int16_t v; 338 339 switch(which) { 340 case AC97_REGEXT_FDACRATE: 341 case AC97_REGEXT_SDACRATE: 342 case AC97_REGEXT_LDACRATE: 343 case AC97_REGEXT_LADCRATE: 344 case AC97_REGEXT_MADCRATE: 345 break; 346 347 default: 348 return -1; 349 } 350 351 snd_mtxlock(codec->lock); 352 if (rate != 0) { 353 v = rate; 354 if (codec->extstat & AC97_EXTCAP_DRA) 355 v >>= 1; 356 ac97_wrcd(codec, which, v); 357 } 358 v = ac97_rdcd(codec, which); 359 if (codec->extstat & AC97_EXTCAP_DRA) 360 v <<= 1; 361 snd_mtxunlock(codec->lock); 362 return v; 363} 364 365int 366ac97_setextmode(struct ac97_info *codec, u_int16_t mode) 367{ 368 mode &= AC97_EXTCAPS; 369 if ((mode & ~codec->extcaps) != 0) { 370 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n", 371 mode); 372 return -1; 373 } 374 snd_mtxlock(codec->lock); 375 ac97_wrcd(codec, AC97_REGEXT_STAT, mode); 376 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 377 snd_mtxunlock(codec->lock); 378 return (mode == codec->extstat)? 0 : -1; 379} 380 381u_int16_t 382ac97_getextmode(struct ac97_info *codec) 383{ 384 return codec->extstat; 385} 386 387u_int16_t 388ac97_getextcaps(struct ac97_info *codec) 389{ 390 return codec->extcaps; 391} 392 393u_int16_t 394ac97_getcaps(struct ac97_info *codec) 395{ 396 return codec->caps; 397} 398 399static int 400ac97_setrecsrc(struct ac97_info *codec, int channel) 401{ 402 struct ac97mixtable_entry *e = &codec->mix[channel]; 403 404 if (e->recidx > 0) { 405 int val = e->recidx - 1; 406 val |= val << 8; 407 snd_mtxlock(codec->lock); 408 ac97_wrcd(codec, AC97_REG_RECSEL, val); 409 snd_mtxunlock(codec->lock); 410 return 0; 411 } else 412 return -1; 413} 414 415static int 416ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right) 417{ 418 struct ac97mixtable_entry *e = &codec->mix[channel]; 419 420 if (e->reg && e->enable && e->bits) { 421 int mask, max, val, reg; 422 423 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */ 424 max = (1 << e->bits) - 1; /* actual range */ 425 mask = (max << 8) | max; /* bits of interest */ 426 427 if (!e->stereo) 428 right = left; 429 430 /* 431 * Invert the range if the polarity requires so, 432 * then scale to 0..max-1 to compute the value to 433 * write into the codec, and scale back to 0..100 434 * for the return value. 435 */ 436 if (e->reg > 0) { 437 left = 100 - left; 438 right = 100 - right; 439 } 440 441 left = (left * max) / 100; 442 right = (right * max) / 100; 443 444 val = (left << 8) | right; 445 446 left = (left * 100) / max; 447 right = (right * 100) / max; 448 449 if (e->reg > 0) { 450 left = 100 - left; 451 right = 100 - right; 452 } 453 454 /* 455 * For mono controls, trim val and mask, also taking 456 * care of e->ofs (offset of control field). 457 */ 458 if (e->ofs) { 459 val &= max; 460 val <<= e->ofs; 461 mask = (max << e->ofs); 462 } 463 464 /* 465 * If we have a mute bit, add it to the mask and 466 * update val and set mute if both channels require a 467 * zero volume. 468 */ 469 if (e->mute == 1) { 470 mask |= AC97_MUTE; 471 if (left == 0 && right == 0) 472 val = AC97_MUTE; 473 } 474 475 /* 476 * If the mask bit is set, do not alter the other bits. 477 */ 478 snd_mtxlock(codec->lock); 479 if (e->mask) { 480 int cur = ac97_rdcd(codec, reg); 481 val |= cur & ~(mask); 482 } 483 ac97_wrcd(codec, reg, val); 484 snd_mtxunlock(codec->lock); 485 return left | (right << 8); 486 } else { 487#if 0 488 printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); 489#endif 490 return -1; 491 } 492} 493 494static void 495ac97_fix_auxout(struct ac97_info *codec) 496{ 497 int keep_ogain; 498 499 /* 500 * By default, The ac97 aux_out register (0x04) corresponds to OSS's 501 * OGAIN setting. 502 * 503 * We first check whether aux_out is a valid register. If not 504 * we may not want to keep ogain. 505 */ 506 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000; 507 508 /* 509 * Determine what AUX_OUT really means, it can be: 510 * 511 * 1. Headphone out. 512 * 2. 4-Channel Out 513 * 3. True line level out (effectively master volume). 514 * 515 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}. 516 */ 517 if (codec->extcaps & AC97_EXTCAP_SDAC && 518 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) { 519 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND; 520 keep_ogain = 1; 521 } 522 523 if (keep_ogain == 0) { 524 bzero(&codec->mix[SOUND_MIXER_OGAIN], 525 sizeof(codec->mix[SOUND_MIXER_OGAIN])); 526 } 527} 528 529static void 530ac97_fix_tone(struct ac97_info *codec) 531{ 532 /* Hide treble and bass if they don't exist */ 533 if ((codec->caps & AC97_CAP_TONE) == 0) { 534 bzero(&codec->mix[SOUND_MIXER_BASS], 535 sizeof(codec->mix[SOUND_MIXER_BASS])); 536 bzero(&codec->mix[SOUND_MIXER_TREBLE], 537 sizeof(codec->mix[SOUND_MIXER_TREBLE])); 538 } 539} 540 541static const char* 542ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf) 543{ 544 if (cname == NULL) { 545 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id); 546 return buf; 547 } 548 549 if (vname == NULL) vname = "Unknown"; 550 551 if (bootverbose) { 552 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id); 553 } else { 554 sprintf(buf, "%s %s AC97 Codec", vname, cname); 555 } 556 return buf; 557} 558 559static unsigned 560ac97_initmixer(struct ac97_info *codec) 561{ 562 ac97_patch codec_patch; 563 const char *cname, *vname; 564 char desc[80]; 565 u_int8_t model, step; 566 unsigned i, j, k, bit, old; 567 u_int32_t id; 568 int reg; 569 570 snd_mtxlock(codec->lock); 571 codec->count = AC97_INIT(codec->methods, codec->devinfo); 572 if (codec->count == 0) { 573 device_printf(codec->dev, "ac97 codec init failed\n"); 574 snd_mtxunlock(codec->lock); 575 return ENODEV; 576 } 577 578 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000); 579 ac97_reset(codec); 580 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000); 581 582 i = ac97_rdcd(codec, AC97_REG_RESET); 583 j = ac97_rdcd(codec, AC97_REG_RESET); 584 /* 585 * Let see if this codec can return consistent value. 586 * If not, turn on aggressive read workaround 587 * (STAC9704 comes in mind). 588 */ 589 if (i != j) { 590 codec->flags |= AC97_F_RDCD_BUG; 591 i = ac97_rdcd(codec, AC97_REG_RESET); 592 } 593 codec->caps = i & 0x03ff; 594 codec->se = (i & 0x7c00) >> 10; 595 596 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2); 597 if (id == 0 || id == 0xffffffff) { 598 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id); 599 snd_mtxunlock(codec->lock); 600 return ENODEV; 601 } 602 603 codec->id = id; 604 codec->noext = 0; 605 codec_patch = NULL; 606 607 cname = NULL; 608 model = step = 0; 609 for (i = 0; ac97codecid[i].id; i++) { 610 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask; 611 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) { 612 codec->noext = ac97codecid[i].noext; 613 codec_patch = ac97codecid[i].patch; 614 cname = ac97codecid[i].name; 615 model = (id & modelmask) & 0xff; 616 step = (id & ~modelmask) & 0xff; 617 break; 618 } 619 } 620 621 vname = NULL; 622 for (i = 0; ac97vendorid[i].id; i++) { 623 if (ac97vendorid[i].id == (id & 0xffffff00)) { 624 vname = ac97vendorid[i].name; 625 break; 626 } 627 } 628 629 codec->extcaps = 0; 630 codec->extid = 0; 631 codec->extstat = 0; 632 if (!codec->noext) { 633 i = ac97_rdcd(codec, AC97_REGEXT_ID); 634 if (i != 0xffff) { 635 codec->extcaps = i & 0x3fff; 636 codec->extid = (i & 0xc000) >> 14; 637 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 638 } 639 } 640 641 for (i = 0; i < 32; i++) { 642 codec->mix[i] = ac97mixtable_default[i]; 643 } 644 ac97_fix_auxout(codec); 645 ac97_fix_tone(codec); 646 if (codec_patch) 647 codec_patch(codec); 648 649 for (i = 0; i < 32; i++) { 650 k = codec->noext? codec->mix[i].enable : 1; 651 reg = codec->mix[i].reg; 652 if (reg < 0) 653 reg = -reg; 654 if (k && reg) { 655 j = old = ac97_rdcd(codec, reg); 656 /* 657 * Test for mute bit (except for AC97_MIX_TONE, 658 * where we simply assume it as available). 659 */ 660 if (codec->mix[i].mute) { 661 ac97_wrcd(codec, reg, j | 0x8000); 662 j = ac97_rdcd(codec, reg); 663 } else 664 j |= 0x8000; 665 if ((j & 0x8000)) { 666 /* 667 * Test whether the control width should be 668 * 4, 5 or 6 bit. For 5bit register, we should 669 * test it whether it's really 5 or 6bit. Leave 670 * 4bit register alone, because sometimes an 671 * attempt to write past 4th bit may cause 672 * incorrect result especially for AC97_MIX_BEEP 673 * (ac97 2.3). 674 */ 675 bit = codec->mix[i].bits; 676 if (bit == 5) 677 bit++; 678 j = ((1 << bit) - 1) << codec->mix[i].ofs; 679 ac97_wrcd(codec, reg, 680 j | (codec->mix[i].mute ? 0x8000 : 0)); 681 k = ac97_rdcd(codec, reg) & j; 682 k >>= codec->mix[i].ofs; 683 if (reg == AC97_MIX_TONE && 684 ((k & 0x0001) == 0x0000)) 685 k >>= 1; 686 for (j = 0; k >> j; j++) 687 ; 688 if (j != 0) { 689#if 0 690 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n", 691 i, k, bit, codec->mix[i].bits, j); 692#endif 693 codec->mix[i].enable = 1; 694 codec->mix[i].bits = j; 695 } else 696 codec->mix[i].enable = 0; 697 } else 698 codec->mix[i].enable = 0; 699 ac97_wrcd(codec, reg, old); 700 } 701#if 0 702 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); 703#endif 704 } 705 706 device_printf(codec->dev, "<%s>\n", 707 ac97_hw_desc(codec->id, vname, cname, desc)); 708 709 if (bootverbose) { 710 if (codec->flags & AC97_F_RDCD_BUG) 711 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n"); 712 device_printf(codec->dev, "Codec features "); 713 for (i = j = 0; i < 10; i++) 714 if (codec->caps & (1 << i)) 715 printf("%s%s", j++? ", " : "", ac97feature[i]); 716 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits); 717 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]); 718 719 if (codec->extcaps != 0 || codec->extid) { 720 device_printf(codec->dev, "%s codec", 721 codec->extid? "Secondary" : "Primary"); 722 if (codec->extcaps) 723 printf(" extended features "); 724 for (i = j = 0; i < 14; i++) 725 if (codec->extcaps & (1 << i)) 726 printf("%s%s", j++? ", " : "", ac97extfeature[i]); 727 printf("\n"); 728 } 729 } 730 731 i = 0; 732 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) { 733 if (++i == 100) { 734 device_printf(codec->dev, "ac97 codec reports dac not ready\n"); 735 break; 736 } 737 DELAY(1000); 738 } 739 if (bootverbose) 740 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i); 741 snd_mtxunlock(codec->lock); 742 return 0; 743} 744 745static unsigned 746ac97_reinitmixer(struct ac97_info *codec) 747{ 748 snd_mtxlock(codec->lock); 749 codec->count = AC97_INIT(codec->methods, codec->devinfo); 750 if (codec->count == 0) { 751 device_printf(codec->dev, "ac97 codec init failed\n"); 752 snd_mtxunlock(codec->lock); 753 return ENODEV; 754 } 755 756 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000); 757 ac97_reset(codec); 758 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000); 759 760 if (!codec->noext) { 761 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat); 762 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS) 763 != codec->extstat) 764 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n", 765 codec->extstat, 766 ac97_rdcd(codec, AC97_REGEXT_STAT) & 767 AC97_EXTCAPS); 768 } 769 770 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) 771 device_printf(codec->dev, "ac97 codec reports dac not ready\n"); 772 snd_mtxunlock(codec->lock); 773 return 0; 774} 775 776struct ac97_info * 777ac97_create(device_t dev, void *devinfo, kobj_class_t cls) 778{ 779 struct ac97_info *codec; 780 781 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT); 782 if (codec == NULL) 783 return NULL; 784 785 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev)); 786 codec->lock = snd_mtxcreate(codec->name, "ac97 codec"); 787 codec->methods = kobj_create(cls, M_AC97, M_WAITOK); 788 if (codec->methods == NULL) { 789 snd_mtxlock(codec->lock); 790 snd_mtxfree(codec->lock); 791 free(codec, M_AC97); 792 return NULL; 793 } 794 795 codec->dev = dev; 796 codec->devinfo = devinfo; 797 codec->flags = 0; 798 return codec; 799} 800 801void 802ac97_destroy(struct ac97_info *codec) 803{ 804 snd_mtxlock(codec->lock); 805 if (codec->methods != NULL) 806 kobj_delete(codec->methods, M_AC97); 807 snd_mtxfree(codec->lock); 808 free(codec, M_AC97); 809} 810 811void 812ac97_setflags(struct ac97_info *codec, u_int32_t val) 813{ 814 codec->flags = val; 815} 816 817u_int32_t 818ac97_getflags(struct ac97_info *codec) 819{ 820 return codec->flags; 821} 822 823/* -------------------------------------------------------------------- */ 824 825static int 826ac97mix_init(struct snd_mixer *m) 827{ 828 struct ac97_info *codec = mix_getdevinfo(m); 829 u_int32_t i, mask; 830 831 if (codec == NULL) 832 return -1; 833 834 if (ac97_initmixer(codec)) 835 return -1; 836 837 mask = 0; 838 for (i = 0; i < 32; i++) 839 mask |= codec->mix[i].enable? 1 << i : 0; 840 mix_setdevs(m, mask); 841 842 mask = 0; 843 for (i = 0; i < 32; i++) 844 mask |= codec->mix[i].recidx? 1 << i : 0; 845 mix_setrecdevs(m, mask); 846 return 0; 847} 848 849static int 850ac97mix_uninit(struct snd_mixer *m) 851{ 852 struct ac97_info *codec = mix_getdevinfo(m); 853 854 if (codec == NULL) 855 return -1; 856 /* 857 if (ac97_uninitmixer(codec)) 858 return -1; 859 */ 860 ac97_destroy(codec); 861 return 0; 862} 863 864static int 865ac97mix_reinit(struct snd_mixer *m) 866{ 867 struct ac97_info *codec = mix_getdevinfo(m); 868 869 if (codec == NULL) 870 return -1; 871 return ac97_reinitmixer(codec); 872} 873 874static int 875ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 876{ 877 struct ac97_info *codec = mix_getdevinfo(m); 878 879 if (codec == NULL) 880 return -1; 881 return ac97_setmixer(codec, dev, left, right); 882} 883 884static int 885ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src) 886{ 887 int i; 888 struct ac97_info *codec = mix_getdevinfo(m); 889 890 if (codec == NULL) 891 return -1; 892 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 893 if ((src & (1 << i)) != 0) 894 break; 895 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1; 896} 897 898static kobj_method_t ac97mixer_methods[] = { 899 KOBJMETHOD(mixer_init, ac97mix_init), 900 KOBJMETHOD(mixer_uninit, ac97mix_uninit), 901 KOBJMETHOD(mixer_reinit, ac97mix_reinit), 902 KOBJMETHOD(mixer_set, ac97mix_set), 903 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc), 904 { 0, 0 } 905}; 906MIXER_DECLARE(ac97mixer); 907 908/* -------------------------------------------------------------------- */ 909 910kobj_class_t 911ac97_getmixerclass(void) 912{ 913 return &ac97mixer_class; 914} 915 916 917