1 /* $NetBSD: ac97.c,v 1.20 2001/07/07 15:56:07 thorpej Exp $ */ 2 /* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */ 3 4 /* 5 * Copyright (c) 1999, 2000 Constantine Sapuntzakis 6 * 7 * Author: Constantine Sapuntzakis <csapuntz@stanford.edu> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS 21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 30 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 31 * DAMAGE 32 */ 33 34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with 35 the following copyright */ 36 37 /* 38 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 * 62 * $FreeBSD$ 63 */ 64 65 #include <sys/param.h> 66 #include <sys/systm.h> 67 #include <sys/kernel.h> 68 #include <sys/malloc.h> 69 #include <sys/device.h> 70 71 #include <sys/audioio.h> 72 #include <dev/audio_if.h> 73 74 #include <dev/ic/ac97reg.h> 75 #include <dev/ic/ac97var.h> 76 77 static const struct audio_mixer_enum ac97_on_off = { 2, 78 { { { AudioNoff } , 0 }, 79 { { AudioNon } , 1 } }}; 80 81 82 static const struct audio_mixer_enum ac97_mic_select = { 2, 83 { { { AudioNmicrophone "0" }, 84 0 }, 85 { { AudioNmicrophone "1" }, 86 1 } }}; 87 88 static const struct audio_mixer_enum ac97_mono_select = { 2, 89 { { { AudioNmixerout }, 90 0 }, 91 { { AudioNmicrophone }, 92 1 } }}; 93 94 static const struct audio_mixer_enum ac97_source = { 8, 95 { { { AudioNmicrophone } , 0 }, 96 { { AudioNcd }, 1 }, 97 { { "video" }, 2 }, 98 { { AudioNaux }, 3 }, 99 { { AudioNline }, 4 }, 100 { { AudioNmixerout }, 5 }, 101 { { AudioNmixerout AudioNmono }, 6 }, 102 { { "phone" }, 7 }}}; 103 104 /* 105 * Due to different values for each source that uses these structures, 106 * the ac97_query_devinfo function sets delta in mixer_devinfo_t using 107 * ac97_source_info.bits. 108 */ 109 static const struct audio_mixer_value ac97_volume_stereo = { { AudioNvolume }, 110 2 }; 111 112 static const struct audio_mixer_value ac97_volume_mono = { { AudioNvolume }, 113 1 }; 114 115 #define WRAP(a) &a, sizeof(a) 116 117 const struct ac97_source_info { 118 const char *class; 119 const char *device; 120 const char *qualifier; 121 int type; 122 123 const void *info; 124 int info_size; 125 126 u_int8_t reg; 127 u_int16_t default_value; 128 u_int8_t bits:3; 129 u_int8_t ofs:4; 130 u_int8_t mute:1; 131 u_int8_t polarity:1; /* Does 0 == MAX or MIN */ 132 133 int prev; 134 int next; 135 int mixer_class; 136 } source_info[] = { 137 { AudioCinputs , NULL, NULL, AUDIO_MIXER_CLASS, 138 }, 139 { AudioCoutputs, NULL, NULL, AUDIO_MIXER_CLASS, 140 }, 141 { AudioCrecord , NULL, NULL, AUDIO_MIXER_CLASS, 142 }, 143 /* Stereo master volume*/ 144 { AudioCoutputs, AudioNmaster, NULL, AUDIO_MIXER_VALUE, 145 WRAP(ac97_volume_stereo), 146 AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1, 147 }, 148 /* Mono volume */ 149 { AudioCoutputs, AudioNmono, NULL, AUDIO_MIXER_VALUE, 150 WRAP(ac97_volume_mono), 151 AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1, 152 }, 153 { AudioCoutputs, AudioNmono,AudioNsource, AUDIO_MIXER_ENUM, 154 WRAP(ac97_mono_select), 155 AC97_REG_GP, 0x0000, 1, 9, 0, 156 }, 157 /* Headphone volume */ 158 { AudioCoutputs, AudioNheadphone, NULL, AUDIO_MIXER_VALUE, 159 WRAP(ac97_volume_stereo), 160 AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1, 161 }, 162 /* Tone */ 163 { AudioCoutputs, "tone", NULL, AUDIO_MIXER_VALUE, 164 WRAP(ac97_volume_stereo), 165 AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 166 }, 167 /* PC Beep Volume */ 168 { AudioCinputs, AudioNspeaker, NULL, AUDIO_MIXER_VALUE, 169 WRAP(ac97_volume_mono), 170 AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1, 171 }, 172 /* Phone */ 173 { AudioCinputs, "phone", NULL, AUDIO_MIXER_VALUE, 174 WRAP(ac97_volume_mono), 175 AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1, 176 }, 177 /* Mic Volume */ 178 { AudioCinputs, AudioNmicrophone, NULL, AUDIO_MIXER_VALUE, 179 WRAP(ac97_volume_mono), 180 AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1, 181 }, 182 { AudioCinputs, AudioNmicrophone, AudioNpreamp, AUDIO_MIXER_ENUM, 183 WRAP(ac97_on_off), 184 AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0, 185 }, 186 { AudioCinputs, AudioNmicrophone, AudioNsource, AUDIO_MIXER_ENUM, 187 WRAP(ac97_mic_select), 188 AC97_REG_GP, 0x0000, 1, 8, 0, 189 }, 190 /* Line in Volume */ 191 { AudioCinputs, AudioNline, NULL, AUDIO_MIXER_VALUE, 192 WRAP(ac97_volume_stereo), 193 AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1, 194 }, 195 /* CD Volume */ 196 { AudioCinputs, AudioNcd, NULL, AUDIO_MIXER_VALUE, 197 WRAP(ac97_volume_stereo), 198 AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1, 199 }, 200 /* Video Volume */ 201 { AudioCinputs, "video", NULL, AUDIO_MIXER_VALUE, 202 WRAP(ac97_volume_stereo), 203 AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1, 204 }, 205 /* AUX volume */ 206 { AudioCinputs, AudioNaux, NULL, AUDIO_MIXER_VALUE, 207 WRAP(ac97_volume_stereo), 208 AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1, 209 }, 210 /* PCM out volume */ 211 { AudioCinputs, AudioNdac, NULL, AUDIO_MIXER_VALUE, 212 WRAP(ac97_volume_stereo), 213 AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1, 214 }, 215 /* Record Source - some logic for this is hard coded - see below */ 216 { AudioCrecord, AudioNsource, NULL, AUDIO_MIXER_ENUM, 217 WRAP(ac97_source), 218 AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0, 219 }, 220 /* Record Gain */ 221 { AudioCrecord, AudioNvolume, NULL, AUDIO_MIXER_VALUE, 222 WRAP(ac97_volume_stereo), 223 AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 224 }, 225 /* Record Gain mic */ 226 { AudioCrecord, AudioNmicrophone, NULL, AUDIO_MIXER_VALUE, 227 WRAP(ac97_volume_mono), 228 AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, 229 }, 230 /* */ 231 { AudioCoutputs, AudioNloudness, NULL, AUDIO_MIXER_ENUM, 232 WRAP(ac97_on_off), 233 AC97_REG_GP, 0x0000, 1, 12, 0, 234 }, 235 { AudioCoutputs, AudioNspatial, NULL, AUDIO_MIXER_ENUM, 236 WRAP(ac97_on_off), 237 AC97_REG_GP, 0x0000, 1, 13, 0, 238 }, 239 { AudioCoutputs, AudioNspatial, "center", AUDIO_MIXER_VALUE, 240 WRAP(ac97_volume_mono), 241 AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, 242 }, 243 { AudioCoutputs, AudioNspatial, "depth", AUDIO_MIXER_VALUE, 244 WRAP(ac97_volume_mono), 245 AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, 246 }, 247 248 /* Missing features: Simulated Stereo, POP, Loopback mode */ 249 } ; 250 251 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0])) 252 253 /* 254 * Check out http://developer.intel.com/pc-supp/platform/ac97/ for 255 * information on AC-97 256 */ 257 258 struct ac97_softc { 259 struct ac97_codec_if codec_if; 260 261 struct ac97_host_if *host_if; 262 263 struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE]; 264 int num_source_info; 265 266 enum ac97_host_flags host_flags; 267 268 u_int16_t shadow_reg[128]; 269 }; 270 271 int ac97_mixer_get_port __P((struct ac97_codec_if *self, mixer_ctrl_t *cp)); 272 int ac97_mixer_set_port __P((struct ac97_codec_if *self, mixer_ctrl_t *)); 273 int ac97_query_devinfo __P((struct ac97_codec_if *self, mixer_devinfo_t *)); 274 int ac97_get_portnum_by_name __P((struct ac97_codec_if *, char *, char *, 275 char *)); 276 void ac97_restore_shadow __P((struct ac97_codec_if *self)); 277 278 struct ac97_codec_if_vtbl ac97civ = { 279 ac97_mixer_get_port, 280 ac97_mixer_set_port, 281 ac97_query_devinfo, 282 ac97_get_portnum_by_name, 283 ac97_restore_shadow, 284 }; 285 286 static const struct ac97_codecid { 287 u_int32_t id; 288 const char *name; 289 } ac97codecid[] = { 290 { AC97_CODEC_ID('A', 'D', 'S', 64), "Analog Devices AD1881" }, 291 { AC97_CODEC_ID('A', 'K', 'M', 0), "Asahi Kasei AK4540" }, 292 { AC97_CODEC_ID('A', 'K', 'M', 2), "Asahi Kasei AK4543" }, 293 { AC97_CODEC_ID('C', 'R', 'Y', 0), "Crystal CS4297" }, 294 { AC97_CODEC_ID('C', 'R', 'Y', 3), "Crystal CS4297" }, 295 { AC97_CODEC_ID('C', 'R', 'Y', 19), "Crystal CS4297A" }, 296 { AC97_CODEC_ID('C', 'R', 'Y', 35), "Crystal CS4298", }, 297 { AC97_CODEC_ID('C', 'R', 'Y', 43), "Crystal CS4294", }, 298 { AC97_CODEC_ID('C', 'R', 'Y', 49), "Crystal CS4299", }, 299 { AC97_CODEC_ID('C', 'R', 'Y', 51), "Crystal CS4298A", }, 300 { AC97_CODEC_ID('C', 'R', 'Y', 52), "Crystal CS4299", }, 301 { AC97_CODEC_ID('N', 'S', 'C', 49), "National Semiconductor LM4549", }, 302 { AC97_CODEC_ID('S', 'I', 'L', 34), "Silicon Laboratory Si3036", }, 303 { AC97_CODEC_ID('S', 'I', 'L', 35), "Silicon Laboratory Si3038", }, 304 { AC97_CODEC_ID('T', 'R', 'A', 2), "TriTech TR28022", }, 305 { AC97_CODEC_ID('T', 'R', 'A', 3), "TriTech TR28023", }, 306 { AC97_CODEC_ID('T', 'R', 'A', 6), "TriTech TR28026", }, 307 { AC97_CODEC_ID('T', 'R', 'A', 8), "TriTech TR28028", }, 308 { AC97_CODEC_ID('T', 'R', 'A', 35), "TriTech unknown", }, 309 { AC97_CODEC_ID('W', 'M', 'L', 0), "Wolfson WM9704", }, 310 { AC97_CODEC_ID('W', 'M', 'L', 3), "Wolfson WM9707", }, 311 { 0x83847600, "SigmaTel STAC9700", }, 312 { 0x83847604, "SigmaTel STAC9701/3/4/5", }, 313 { 0x83847605, "SigmaTel STAC9704", }, 314 { 0x83847608, "SigmaTel STAC9708", }, 315 { 0x83847609, "SigmaTel STAC9721/23", }, 316 { 0x83847644, "SigmaTel STAC9744/45", }, 317 { 0x83847684, "SigmaTel STAC9783/84", }, 318 { 0, NULL, } 319 }; 320 321 static const char * const ac97enhancement[] = { 322 "no 3D stereo", 323 "Analog Devices Phat Stereo", 324 "Creative" 325 "National Semi 3D", 326 "Yamaha Ymersion", 327 "BBE 3D", 328 "Crystal Semi 3D" 329 "Qsound QXpander", 330 "Spatializer 3D", 331 "SRS 3D", 332 "Platform Tech 3D", 333 "AKM 3D", 334 "Aureal", 335 "AZTECH 3D", 336 "Binaura 3D", 337 "ESS Technology", 338 "Harman International VMAx", 339 "Nvidea 3D", 340 "Philips Incredible Sound", 341 "Texas Instruments' 3D", 342 "VLSI Technology 3D", 343 "TriTech 3D", 344 "Realtek 3D", 345 "Samsung 3D", 346 "Wolfson Microelectronics 3D", 347 "Delta Integration 3D", 348 "SigmaTel 3D", 349 "Unknown 3D", 350 "Rockwell 3D", 351 "Unknown 3D", 352 "Unknown 3D", 353 "Unknown 3D", 354 }; 355 356 static const char * const ac97feature[] = { 357 "mic channel", 358 "reserved", 359 "tone", 360 "simulated stereo", 361 "headphone", 362 "bass boost", 363 "18 bit DAC", 364 "20 bit DAC", 365 "18 bit ADC", 366 "20 bit ADC" 367 }; 368 369 370 int ac97_str_equal __P((const char *, const char *)); 371 void ac97_setup_source_info __P((struct ac97_softc *)); 372 void ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *)); 373 void ac97_setup_defaults __P((struct ac97_softc *)); 374 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t)); 375 376 /* #define AC97_DEBUG 10 */ 377 378 #ifdef AUDIO_DEBUG 379 #define DPRINTF(x) if (ac97debug) printf x 380 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x 381 #ifdef AC97_DEBUG 382 int ac97debug = AC97_DEBUG; 383 #else 384 int ac97debug = 0; 385 #endif 386 #else 387 #define DPRINTF(x) 388 #define DPRINTFN(n,x) 389 #endif 390 391 void 392 ac97_read(as, reg, val) 393 struct ac97_softc *as; 394 u_int8_t reg; 395 u_int16_t *val; 396 { 397 int error; 398 399 if (as->host_flags & AC97_HOST_DONT_READ && 400 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 && 401 reg != AC97_REG_RESET)) { 402 *val = as->shadow_reg[reg >> 1]; 403 return; 404 } 405 406 if ((error = as->host_if->read(as->host_if->arg, reg, val))) { 407 *val = as->shadow_reg[reg >> 1]; 408 } 409 } 410 411 int 412 ac97_write(as, reg, val) 413 struct ac97_softc *as; 414 u_int8_t reg; 415 u_int16_t val; 416 { 417 418 as->shadow_reg[reg >> 1] = val; 419 420 return (as->host_if->write(as->host_if->arg, reg, val)); 421 } 422 423 void 424 ac97_setup_defaults(as) 425 struct ac97_softc *as; 426 { 427 int idx; 428 const struct ac97_source_info *si; 429 430 memset(as->shadow_reg, 0, sizeof(as->shadow_reg)); 431 432 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) { 433 si = &source_info[idx]; 434 ac97_write(as, si->reg, si->default_value); 435 } 436 } 437 438 void 439 ac97_restore_shadow(self) 440 struct ac97_codec_if *self; 441 { 442 struct ac97_softc *as = (struct ac97_softc *) self; 443 int idx; 444 const struct ac97_source_info *si; 445 446 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) { 447 si = &source_info[idx]; 448 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]); 449 } 450 } 451 452 int 453 ac97_str_equal(a, b) 454 const char *a, *b; 455 { 456 return ((a == b) || (a && b && (!strcmp(a, b)))); 457 } 458 459 void 460 ac97_setup_source_info(as) 461 struct ac97_softc *as; 462 { 463 int idx, ouridx; 464 struct ac97_source_info *si, *si2; 465 466 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) { 467 si = &as->source_info[ouridx]; 468 469 memcpy(si, &source_info[idx], sizeof(*si)); 470 471 switch (si->type) { 472 case AUDIO_MIXER_CLASS: 473 si->mixer_class = ouridx; 474 ouridx++; 475 break; 476 case AUDIO_MIXER_VALUE: 477 /* Todo - Test to see if it works */ 478 ouridx++; 479 480 /* Add an entry for mute, if necessary */ 481 if (si->mute) { 482 si = &as->source_info[ouridx]; 483 memcpy(si, &source_info[idx], sizeof(*si)); 484 si->qualifier = AudioNmute; 485 si->type = AUDIO_MIXER_ENUM; 486 si->info = &ac97_on_off; 487 si->info_size = sizeof(ac97_on_off); 488 si->bits = 1; 489 si->ofs = 15; 490 si->mute = 0; 491 si->polarity = 0; 492 ouridx++; 493 } 494 break; 495 case AUDIO_MIXER_ENUM: 496 /* Todo - Test to see if it works */ 497 ouridx++; 498 break; 499 default: 500 printf ("ac97: shouldn't get here\n"); 501 break; 502 } 503 } 504 505 as->num_source_info = ouridx; 506 507 for (idx = 0; idx < as->num_source_info; idx++) { 508 int idx2, previdx; 509 510 si = &as->source_info[idx]; 511 512 /* Find mixer class */ 513 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 514 si2 = &as->source_info[idx2]; 515 516 if (si2->type == AUDIO_MIXER_CLASS && 517 ac97_str_equal(si->class, 518 si2->class)) { 519 si->mixer_class = idx2; 520 } 521 } 522 523 524 /* Setup prev and next pointers */ 525 if (si->prev != 0) 526 continue; 527 528 if (si->qualifier) 529 continue; 530 531 si->prev = AUDIO_MIXER_LAST; 532 previdx = idx; 533 534 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 535 if (idx2 == idx) 536 continue; 537 538 si2 = &as->source_info[idx2]; 539 540 if (!si2->prev && 541 ac97_str_equal(si->class, si2->class) && 542 ac97_str_equal(si->device, si2->device)) { 543 as->source_info[previdx].next = idx2; 544 as->source_info[idx2].prev = previdx; 545 546 previdx = idx2; 547 } 548 } 549 550 as->source_info[previdx].next = AUDIO_MIXER_LAST; 551 } 552 } 553 554 int 555 ac97_attach(host_if) 556 struct ac97_host_if *host_if; 557 { 558 struct ac97_softc *as; 559 struct device *sc_dev = (struct device *)host_if->arg; 560 int error, i, j; 561 u_int16_t id1, id2, caps; 562 u_int32_t id; 563 mixer_ctrl_t ctl; 564 565 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK); 566 567 if (as == NULL) 568 return (ENOMEM); 569 570 memset(as, 0, sizeof(*as)); 571 572 as->codec_if.vtbl = &ac97civ; 573 as->host_if = host_if; 574 575 if ((error = host_if->attach(host_if->arg, &as->codec_if))) { 576 free (as, M_DEVBUF); 577 return (error); 578 } 579 580 host_if->reset(host_if->arg); 581 582 host_if->write(host_if->arg, AC97_REG_POWER, 0); 583 host_if->write(host_if->arg, AC97_REG_RESET, 0); 584 585 if (host_if->flags) 586 as->host_flags = host_if->flags(host_if->arg); 587 588 ac97_setup_defaults(as); 589 ac97_read(as, AC97_REG_VENDOR_ID1, &id1); 590 ac97_read(as, AC97_REG_VENDOR_ID2, &id2); 591 ac97_read(as, AC97_REG_RESET, &caps); 592 593 id = (id1 << 16) | id2; 594 595 printf("%s: ", sc_dev->dv_xname); 596 597 for (i = 0; ; i++) { 598 if (ac97codecid[i].id == 0) { 599 char pnp[4]; 600 601 AC97_GET_CODEC_ID(id, pnp); 602 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f) 603 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) && 604 ISASCII(pnp[2])) 605 printf("%c%c%c%d", pnp[0], pnp[1], pnp[2], 606 pnp[3]); 607 else 608 printf("unknown (0x%08x)", id); 609 break; 610 } 611 if (ac97codecid[i].id == id) { 612 printf("%s", ac97codecid[i].name); 613 break; 614 } 615 } 616 printf(" codec; "); 617 for (i = j = 0; i < 10; i++) { 618 if (caps & (1 << i)) { 619 printf("%s%s", j? ", " : "", ac97feature[i]); 620 j++; 621 } 622 } 623 624 printf("%s%s\n", j? ", " : "", ac97enhancement[(caps >> 10) & 0x1f]); 625 626 ac97_setup_source_info(as); 627 628 /* Just enable the DAC and master volumes by default */ 629 memset(&ctl, 0, sizeof(ctl)); 630 631 ctl.type = AUDIO_MIXER_ENUM; 632 ctl.un.ord = 0; /* off */ 633 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 634 AudioNmaster, AudioNmute); 635 ac97_mixer_set_port(&as->codec_if, &ctl); 636 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs, 637 AudioNdac, AudioNmute); 638 639 ac97_mixer_set_port(&as->codec_if, &ctl); 640 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord, 641 AudioNvolume, AudioNmute); 642 ac97_mixer_set_port(&as->codec_if, &ctl); 643 644 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord, 645 AudioNsource, NULL); 646 ctl.type = AUDIO_MIXER_ENUM; 647 ctl.un.ord = 0; 648 ac97_mixer_set_port(&as->codec_if, &ctl); 649 650 return (0); 651 } 652 653 654 int 655 ac97_query_devinfo(codec_if, dip) 656 struct ac97_codec_if *codec_if; 657 mixer_devinfo_t *dip; 658 { 659 struct ac97_softc *as = (struct ac97_softc *)codec_if; 660 661 if (dip->index < as->num_source_info) { 662 struct ac97_source_info *si = &as->source_info[dip->index]; 663 const char *name; 664 665 dip->type = si->type; 666 dip->mixer_class = si->mixer_class; 667 dip->prev = si->prev; 668 dip->next = si->next; 669 670 if (si->qualifier) 671 name = si->qualifier; 672 else if (si->device) 673 name = si->device; 674 else if (si->class) 675 name = si->class; 676 else 677 name = 0; 678 679 if (name) 680 strcpy(dip->label.name, name); 681 682 memcpy(&dip->un, si->info, si->info_size); 683 684 /* Set the delta for volume sources */ 685 if (dip->type == AUDIO_MIXER_VALUE) 686 dip->un.v.delta = 1 << (8 - si->bits); 687 688 return (0); 689 } 690 691 return (ENXIO); 692 } 693 694 695 696 int 697 ac97_mixer_set_port(codec_if, cp) 698 struct ac97_codec_if *codec_if; 699 mixer_ctrl_t *cp; 700 { 701 struct ac97_softc *as = (struct ac97_softc *)codec_if; 702 struct ac97_source_info *si = &as->source_info[cp->dev]; 703 u_int16_t mask; 704 u_int16_t val, newval; 705 int error; 706 707 if (cp->dev < 0 || cp->dev >= as->num_source_info) 708 return (EINVAL); 709 710 if (cp->type != si->type) 711 return (EINVAL); 712 713 ac97_read(as, si->reg, &val); 714 715 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 716 717 mask = (1 << si->bits) - 1; 718 719 switch (cp->type) { 720 case AUDIO_MIXER_ENUM: 721 if (cp->un.ord > mask || cp->un.ord < 0) 722 return (EINVAL); 723 724 newval = (cp->un.ord << si->ofs); 725 if (si->reg == AC97_REG_RECORD_SELECT) { 726 newval |= (newval << (8 + si->ofs)); 727 mask |= (mask << 8); 728 } 729 break; 730 case AUDIO_MIXER_VALUE: 731 { 732 const struct audio_mixer_value *value = si->info; 733 u_int16_t l, r; 734 735 if ((cp->un.value.num_channels <= 0) || 736 (cp->un.value.num_channels > value->num_channels)) 737 return (EINVAL); 738 739 if (cp->un.value.num_channels == 1) { 740 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 741 } else { 742 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) { 743 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 744 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 745 } else { /* left/right is reversed here */ 746 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 747 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 748 } 749 750 } 751 752 if (!si->polarity) { 753 l = 255 - l; 754 r = 255 - r; 755 } 756 757 l = l >> (8 - si->bits); 758 r = r >> (8 - si->bits); 759 760 newval = ((l & mask) << si->ofs); 761 if (value->num_channels == 2) { 762 newval |= ((r & mask) << (si->ofs + 8)); 763 mask |= (mask << 8); 764 } 765 766 break; 767 } 768 default: 769 return (EINVAL); 770 } 771 772 mask = mask << si->ofs; 773 error = ac97_write(as, si->reg, (val & ~mask) | newval); 774 if (error) 775 return (error); 776 777 return (0); 778 } 779 780 int 781 ac97_get_portnum_by_name(codec_if, class, device, qualifier) 782 struct ac97_codec_if *codec_if; 783 char *class, *device, *qualifier; 784 { 785 struct ac97_softc *as = (struct ac97_softc *)codec_if; 786 int idx; 787 788 for (idx = 0; idx < as->num_source_info; idx++) { 789 struct ac97_source_info *si = &as->source_info[idx]; 790 if (ac97_str_equal(class, si->class) && 791 ac97_str_equal(device, si->device) && 792 ac97_str_equal(qualifier, si->qualifier)) 793 return (idx); 794 } 795 796 return (-1); 797 } 798 799 int 800 ac97_mixer_get_port(codec_if, cp) 801 struct ac97_codec_if *codec_if; 802 mixer_ctrl_t *cp; 803 { 804 struct ac97_softc *as = (struct ac97_softc *)codec_if; 805 struct ac97_source_info *si = &as->source_info[cp->dev]; 806 u_int16_t mask; 807 u_int16_t val; 808 809 if (cp->dev < 0 || cp->dev >= as->num_source_info) 810 return (EINVAL); 811 812 if (cp->type != si->type) 813 return (EINVAL); 814 815 ac97_read(as, si->reg, &val); 816 817 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 818 819 mask = (1 << si->bits) - 1; 820 821 switch (cp->type) { 822 case AUDIO_MIXER_ENUM: 823 cp->un.ord = (val >> si->ofs) & mask; 824 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord)); 825 break; 826 case AUDIO_MIXER_VALUE: 827 { 828 const struct audio_mixer_value *value = si->info; 829 u_int16_t l, r; 830 831 if ((cp->un.value.num_channels <= 0) || 832 (cp->un.value.num_channels > value->num_channels)) 833 return (EINVAL); 834 835 if (value->num_channels == 1) { 836 l = r = (val >> si->ofs) & mask; 837 } else { 838 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) { 839 l = (val >> si->ofs) & mask; 840 r = (val >> (si->ofs + 8)) & mask; 841 } else { /* host has reversed channels */ 842 r = (val >> si->ofs) & mask; 843 l = (val >> (si->ofs + 8)) & mask; 844 } 845 } 846 847 l = (l << (8 - si->bits)); 848 r = (r << (8 - si->bits)); 849 if (!si->polarity) { 850 l = 255 - l; 851 r = 255 - r; 852 } 853 854 /* The EAP driver averages l and r for stereo 855 channels that are requested in MONO mode. Does this 856 make sense? */ 857 if (cp->un.value.num_channels == 1) { 858 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l; 859 } else if (cp->un.value.num_channels == 2) { 860 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 861 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 862 } 863 864 break; 865 } 866 default: 867 return (EINVAL); 868 } 869 870 return (0); 871 } 872 873