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