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