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