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