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