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