ac97.c revision 74622
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 * $FreeBSD: head/sys/dev/sound/pcm/ac97.c 74622 2001-03-22 02:41:24Z cg $ 27 */ 28 29#include <dev/sound/pcm/sound.h> 30#include <dev/sound/pcm/ac97.h> 31 32#include "mixer_if.h" 33 34MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec"); 35 36struct ac97_codecid { 37 u_int32_t id, noext:1; 38 char *name; 39}; 40 41static const struct ac97mixtable_entry ac97mixtable_default[32] = { 42 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 }, 43 [SOUND_MIXER_MONITOR] = { AC97_MIX_PHONES, 5, 0, 1, 1, 0, 0, 0 }, 44 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 }, 45 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 }, 46 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 }, 47 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 }, 48 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 }, 49 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 }, 50 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 }, 51 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 0, 1 }, 52 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 }, 53 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 }, 54 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 }, 55 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 } 56}; 57 58static struct ac97_codecid ac97codecid[] = { 59 { 0x41445303, 0, "Analog Devices AD1819" }, 60 { 0x41445340, 0, "Analog Devices AD1881" }, 61 { 0x41445348, 0, "Analog Devices AD1881A" }, 62 { 0x41445360, 0, "Analog Devices AD1885" }, 63 { 0x414b4d00, 1, "Asahi Kasei AK4540" }, 64 { 0x414b4d01, 1, "Asahi Kasei AK4542" }, 65 { 0x414b4d02, 1, "Asahi Kasei AK4543" }, 66 { 0x414c4710, 0, "Avance Logic ALC200/200P" }, 67 { 0x43525900, 0, "Cirrus Logic CS4297" }, 68 { 0x43525903, 0, "Cirrus Logic CS4297" }, 69 { 0x43525913, 0, "Cirrus Logic CS4297A" }, 70 { 0x43525914, 0, "Cirrus Logic CS4297B" }, 71 { 0x43525923, 0, "Cirrus Logic CS4294C" }, 72 { 0x4352592b, 0, "Cirrus Logic CS4298C" }, 73 { 0x43525931, 0, "Cirrus Logic CS4299A" }, 74 { 0x43525933, 0, "Cirrus Logic CS4299C" }, 75 { 0x43525934, 0, "Cirrus Logic CS4299D" }, 76 { 0x43525941, 0, "Cirrus Logic CS4201A" }, 77 { 0x43525951, 0, "Cirrus Logic CS4205A" }, 78 { 0x43525961, 0, "Cirrus Logic CS4291A" }, 79 { 0x45838308, 0, "ESS Technology ES1921" }, 80 { 0x49434511, 0, "ICEnsemble ICE1232" }, 81 { 0x4e534331, 0, "National Semiconductor LM4549" }, 82 { 0x83847600, 0, "SigmaTel STAC9700/9783/9784" }, 83 { 0x83847604, 0, "SigmaTel STAC9701/9703/9704/9705" }, 84 { 0x83847605, 0, "SigmaTel STAC9704" }, 85 { 0x83847608, 0, "SigmaTel STAC9708/9711" }, 86 { 0x83847609, 0, "SigmaTel STAC9721/9723" }, 87 { 0x83847644, 0, "SigmaTel STAC9744" }, 88 { 0x83847656, 0, "SigmaTel STAC9756/9757" }, 89 { 0x53494c22, 0, "Silicon Laboratory Si3036" }, 90 { 0x53494c23, 0, "Silicon Laboratory Si3038" }, 91 { 0x54524103, 0, "TriTech TR?????" }, 92 { 0x54524106, 0, "TriTech TR28026" }, 93 { 0x54524108, 0, "TriTech TR28028" }, 94 { 0x54524123, 0, "TriTech TR28602" }, 95 { 0x574d4c00, 0, "Wolfson WM9701A" }, 96 { 0x574d4c03, 0, "Wolfson WM9703/9704" }, 97 { 0x574d4c04, 0, "Wolfson WM9704 (quad)" }, 98 { 0, 0, NULL } 99}; 100 101static char *ac97enhancement[] = { 102 "no 3D Stereo Enhancement", 103 "Analog Devices Phat Stereo", 104 "Creative Stereo Enhancement", 105 "National Semi 3D Stereo Enhancement", 106 "Yamaha Ymersion", 107 "BBE 3D Stereo Enhancement", 108 "Crystal Semi 3D Stereo Enhancement", 109 "Qsound QXpander", 110 "Spatializer 3D Stereo Enhancement", 111 "SRS 3D Stereo Enhancement", 112 "Platform Tech 3D Stereo Enhancement", 113 "AKM 3D Audio", 114 "Aureal Stereo Enhancement", 115 "Aztech 3D Enhancement", 116 "Binaura 3D Audio Enhancement", 117 "ESS Technology Stereo Enhancement", 118 "Harman International VMAx", 119 "Nvidea 3D Stereo Enhancement", 120 "Philips Incredible Sound", 121 "Texas Instruments 3D Stereo Enhancement", 122 "VLSI Technology 3D Stereo Enhancement", 123 "TriTech 3D Stereo Enhancement", 124 "Realtek 3D Stereo Enhancement", 125 "Samsung 3D Stereo Enhancement", 126 "Wolfson Microelectronics 3D Enhancement", 127 "Delta Integration 3D Enhancement", 128 "SigmaTel 3D Enhancement", 129 "Reserved 27", 130 "Rockwell 3D Stereo Enhancement", 131 "Reserved 29", 132 "Reserved 30", 133 "Reserved 31" 134}; 135 136static char *ac97feature[] = { 137 "mic channel", 138 "reserved", 139 "tone", 140 "simulated stereo", 141 "headphone", 142 "bass boost", 143 "18 bit DAC", 144 "20 bit DAC", 145 "18 bit ADC", 146 "20 bit ADC" 147}; 148 149static char *ac97extfeature[] = { 150 "variable rate PCM", 151 "double rate PCM", 152 "reserved 1", 153 "variable rate mic", 154 "reserved 2", 155 "reserved 3", 156 "center DAC", 157 "surround DAC", 158 "LFE DAC", 159 "AMAP", 160 "reserved 4", 161 "reserved 5", 162 "reserved 6", 163 "reserved 7", 164}; 165 166static u_int16_t 167rdcd(struct ac97_info *codec, int reg) 168{ 169 return AC97_READ(codec->methods, codec->devinfo, reg); 170} 171 172static void 173wrcd(struct ac97_info *codec, int reg, u_int16_t val) 174{ 175 AC97_WRITE(codec->methods, codec->devinfo, reg, val); 176} 177 178int 179ac97_setrate(struct ac97_info *codec, int which, int rate) 180{ 181 u_int16_t v; 182 183 switch(which) { 184 case AC97_REGEXT_FDACRATE: 185 case AC97_REGEXT_SDACRATE: 186 case AC97_REGEXT_LDACRATE: 187 case AC97_REGEXT_LADCRATE: 188 case AC97_REGEXT_MADCRATE: 189 break; 190 191 default: 192 return -1; 193 } 194 195 if (rate != 0) { 196 v = rate; 197 if (codec->extstat & AC97_EXTCAP_DRA) 198 v >>= 1; 199 wrcd(codec, which, v); 200 } 201 v = rdcd(codec, which); 202 if (codec->extstat & AC97_EXTCAP_DRA) 203 v <<= 1; 204 return v; 205} 206 207int 208ac97_setextmode(struct ac97_info *codec, u_int16_t mode) 209{ 210 mode &= AC97_EXTCAPS; 211 if ((mode & ~codec->extcaps) != 0) 212 return -1; 213 wrcd(codec, AC97_REGEXT_STAT, mode); 214 codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 215 return (mode == codec->extstat)? 0 : -1; 216} 217 218u_int16_t 219ac97_getextmode(struct ac97_info *codec) 220{ 221 return codec->extstat; 222} 223 224u_int16_t 225ac97_getextcaps(struct ac97_info *codec) 226{ 227 return codec->extcaps; 228} 229 230static int 231ac97_setrecsrc(struct ac97_info *codec, int channel) 232{ 233 struct ac97mixtable_entry *e = &codec->mix[channel]; 234 235 if (e->recidx > 0) { 236 int val = e->recidx - 1; 237 val |= val << 8; 238 wrcd(codec, AC97_REG_RECSEL, val); 239 return 0; 240 } else 241 return -1; 242} 243 244static int 245ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right) 246{ 247 struct ac97mixtable_entry *e = &codec->mix[channel]; 248 249 if (e->reg && e->enable && e->bits) { 250 int max, val, reg = (e->reg >= 0)? e->reg : -e->reg; 251 252 if (!e->stereo) 253 right = left; 254 if (e->reg > 0) { 255 left = 100 - left; 256 right = 100 - right; 257 } 258 259 max = (1 << e->bits) - 1; 260 left = (left * max) / 100; 261 right = (right * max) / 100; 262 263 val = (left << 8) | right; 264 265 left = (left * 100) / max; 266 right = (right * 100) / max; 267 268 if (e->reg > 0) { 269 left = 100 - left; 270 right = 100 - right; 271 } 272 273 if (!e->stereo) { 274 val &= max; 275 val <<= e->ofs; 276 if (e->mask) { 277 int cur = rdcd(codec, e->reg); 278 val |= cur & ~(max << e->ofs); 279 } 280 } 281 if (left == 0 && right == 0 && e->mute == 1) 282 val = AC97_MUTE; 283 wrcd(codec, reg, val); 284 return left | (right << 8); 285 } else { 286 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */ 287 return -1; 288 } 289} 290 291#if 0 292static int 293ac97_getmixer(struct ac97_info *codec, int channel) 294{ 295 struct ac97mixtable_entry *e = &codec->mix[channel]; 296 if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) { 297 int max, val, volume; 298 299 max = (1 << e->bits) - 1; 300 val = rdcd(code, e->reg); 301 if (val == AC97_MUTE && e->mute == 1) 302 volume = 0; 303 else { 304 if (e->stereo == 0) val >>= e->ofs; 305 val &= max; 306 volume = (val * 100) / max; 307 if (e->reg > 0) volume = 100 - volume; 308 } 309 return volume; 310 } else 311 return -1; 312} 313#endif 314 315static unsigned 316ac97_initmixer(struct ac97_info *codec) 317{ 318 unsigned i, j, k, old; 319 u_int32_t id; 320 321 for (i = 0; i < 32; i++) 322 codec->mix[i] = ac97mixtable_default[i]; 323 324 codec->count = AC97_INIT(codec->methods, codec->devinfo); 325 if (codec->count == 0) { 326 device_printf(codec->dev, "ac97 codec init failed\n"); 327 return ENODEV; 328 } 329 330 wrcd(codec, AC97_REG_POWER, 0); 331 wrcd(codec, AC97_REG_RESET, 0); 332 DELAY(100000); 333 334 i = rdcd(codec, AC97_REG_RESET); 335 codec->caps = i & 0x03ff; 336 codec->se = (i & 0x7c00) >> 10; 337 338 id = (rdcd(codec, AC97_REG_ID1) << 16) | rdcd(codec, AC97_REG_ID2); 339 codec->rev = id & 0x000000ff; 340 if (id == 0 || id == 0xffffffff) { 341 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id); 342 return ENODEV; 343 } 344 345 codec->noext = 0; 346 codec->name = NULL; 347 for (i = 0; ac97codecid[i].id; i++) { 348 if (ac97codecid[i].id == id) { 349 codec->name = ac97codecid[i].name; 350 codec->noext = ac97codecid[i].noext; 351 } 352 } 353 354 codec->extcaps = 0; 355 codec->extid = 0; 356 codec->extstat = 0; 357 if (!codec->noext) { 358 i = rdcd(codec, AC97_REGEXT_ID); 359 if (i != 0xffff) { 360 codec->extcaps = i & 0x3fff; 361 codec->extid = (i & 0xc000) >> 14; 362 codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 363 } 364 } 365 366 for (i = 0; i < 32; i++) { 367 k = codec->noext? codec->mix[i].enable : 1; 368 if (k && (codec->mix[i].reg > 0)) { 369 old = rdcd(codec, codec->mix[i].reg); 370 wrcd(codec, codec->mix[i].reg, 0x3f); 371 j = rdcd(codec, codec->mix[i].reg); 372 wrcd(codec, codec->mix[i].reg, old); 373 codec->mix[i].enable = (j != 0 && j != old)? 1 : 0; 374 for (k = 1; j & (1 << k); k++); 375 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0; 376 } 377 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */ 378 } 379 380 if (bootverbose) { 381 device_printf(codec->dev, "ac97 codec id 0x%08x", id); 382 if (codec->name) 383 printf(" (%s)", codec->name); 384 printf("\n"); 385 device_printf(codec->dev, "ac97 codec features "); 386 for (i = j = 0; i < 10; i++) 387 if (codec->caps & (1 << i)) 388 printf("%s%s", j++? ", " : "", ac97feature[i]); 389 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits); 390 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]); 391 392 if (codec->extcaps != 0 || codec->extid) { 393 device_printf(codec->dev, "ac97 %s codec", 394 codec->extid? "secondary" : "primary"); 395 if (codec->extcaps) 396 printf(" extended features "); 397 for (i = j = 0; i < 14; i++) 398 if (codec->extcaps & (1 << i)) 399 printf("%s%s", j++? ", " : "", ac97extfeature[i]); 400 printf("\n"); 401 } 402 } 403 404 if ((rdcd(codec, AC97_REG_POWER) & 2) == 0) 405 device_printf(codec->dev, "ac97 codec reports dac not ready\n"); 406 return 0; 407} 408 409static unsigned 410ac97_reinitmixer(struct ac97_info *codec) 411{ 412 unsigned i; 413 414 codec->count = AC97_INIT(codec->methods, codec->devinfo); 415 if (codec->count == 0) { 416 device_printf(codec->dev, "ac97 codec init failed\n"); 417 return ENODEV; 418 } 419 420 wrcd(codec, AC97_REG_POWER, 0); 421 wrcd(codec, AC97_REG_RESET, 0); 422 DELAY(100000); 423 i = rdcd(codec, AC97_REG_RESET); 424 425 if (!codec->noext) { 426 wrcd(codec, AC97_REGEXT_STAT, codec->extstat); 427 if (rdcd(codec, AC97_REGEXT_STAT) != codec->extstat) 428 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n", 429 codec->extstat, rdcd(codec, AC97_REGEXT_STAT)); 430 } 431 432 if ((rdcd(codec, AC97_REG_POWER) & 2) == 0) 433 device_printf(codec->dev, "ac97 codec reports dac not ready\n"); 434 return 0; 435} 436 437struct ac97_info * 438ac97_create(device_t dev, void *devinfo, kobj_class_t cls) 439{ 440 struct ac97_info *codec; 441 442 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT); 443 if (codec == NULL) 444 return NULL; 445 446 codec->methods = kobj_create(cls, M_AC97, M_WAITOK); 447 if (codec->methods == NULL) { 448 free(codec, M_AC97); 449 return NULL; 450 } 451 452 codec->dev = dev; 453 codec->devinfo = devinfo; 454 return codec; 455} 456 457void 458ac97_destroy(struct ac97_info *codec) 459{ 460 if (codec->methods != NULL) 461 kobj_delete(codec->methods, M_AC97); 462 free(codec, M_AC97); 463} 464 465/* -------------------------------------------------------------------- */ 466 467static int 468ac97mix_init(snd_mixer *m) 469{ 470 struct ac97_info *codec = mix_getdevinfo(m); 471 u_int32_t i, mask; 472 473 if (codec == NULL) 474 return -1; 475 476 if (ac97_initmixer(codec)) 477 return -1; 478 479 mask = 0; 480 for (i = 0; i < 32; i++) 481 mask |= codec->mix[i].enable? 1 << i : 0; 482 mix_setdevs(m, mask); 483 484 mask = 0; 485 for (i = 0; i < 32; i++) 486 mask |= codec->mix[i].recidx? 1 << i : 0; 487 mix_setrecdevs(m, mask); 488 return 0; 489} 490 491static int 492ac97mix_uninit(snd_mixer *m) 493{ 494 struct ac97_info *codec = mix_getdevinfo(m); 495 496 if (codec == NULL) 497 return -1; 498 /* 499 if (ac97_uninitmixer(codec)) 500 return -1; 501 */ 502 ac97_destroy(codec); 503 return 0; 504} 505 506static int 507ac97mix_reinit(snd_mixer *m) 508{ 509 struct ac97_info *codec = mix_getdevinfo(m); 510 511 if (codec == NULL) 512 return -1; 513 return ac97_reinitmixer(codec); 514} 515 516static int 517ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 518{ 519 struct ac97_info *codec = mix_getdevinfo(m); 520 521 if (codec == NULL) 522 return -1; 523 return ac97_setmixer(codec, dev, left, right); 524} 525 526static int 527ac97mix_setrecsrc(snd_mixer *m, u_int32_t src) 528{ 529 int i; 530 struct ac97_info *codec = mix_getdevinfo(m); 531 532 if (codec == NULL) 533 return -1; 534 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 535 if ((src & (1 << i)) != 0) 536 break; 537 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1; 538} 539 540static kobj_method_t ac97mixer_methods[] = { 541 KOBJMETHOD(mixer_init, ac97mix_init), 542 KOBJMETHOD(mixer_uninit, ac97mix_uninit), 543 KOBJMETHOD(mixer_reinit, ac97mix_reinit), 544 KOBJMETHOD(mixer_set, ac97mix_set), 545 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc), 546 { 0, 0 } 547}; 548MIXER_DECLARE(ac97mixer); 549 550/* -------------------------------------------------------------------- */ 551 552kobj_class_t 553ac97_getmixerclass(void) 554{ 555 return &ac97mixer_class; 556} 557 558 559