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