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