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