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