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