1 /* $NetBSD: ac97.c,v 1.21 2001/11/13 13:14:31 lukem 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.21 2001/11/13 13:14:31 lukem 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 { 0x83847600, "SigmaTel STAC9700", }, 315 { 0x83847604, "SigmaTel STAC9701/3/4/5", }, 316 { 0x83847605, "SigmaTel STAC9704", }, 317 { 0x83847608, "SigmaTel STAC9708", }, 318 { 0x83847609, "SigmaTel STAC9721/23", }, 319 { 0x83847644, "SigmaTel STAC9744/45", }, 320 { 0x83847684, "SigmaTel STAC9783/84", }, 321 { 0, NULL, } 322 }; 323 324 static const char * const ac97enhancement[] = { 325 "no 3D stereo", 326 "Analog Devices Phat Stereo", 327 "Creative" 328 "National Semi 3D", 329 "Yamaha Ymersion", 330 "BBE 3D", 331 "Crystal Semi 3D" 332 "Qsound QXpander", 333 "Spatializer 3D", 334 "SRS 3D", 335 "Platform Tech 3D", 336 "AKM 3D", 337 "Aureal", 338 "AZTECH 3D", 339 "Binaura 3D", 340 "ESS Technology", 341 "Harman International VMAx", 342 "Nvidea 3D", 343 "Philips Incredible Sound", 344 "Texas Instruments' 3D", 345 "VLSI Technology 3D", 346 "TriTech 3D", 347 "Realtek 3D", 348 "Samsung 3D", 349 "Wolfson Microelectronics 3D", 350 "Delta Integration 3D", 351 "SigmaTel 3D", 352 "Unknown 3D", 353 "Rockwell 3D", 354 "Unknown 3D", 355 "Unknown 3D", 356 "Unknown 3D", 357 }; 358 359 static const char * const ac97feature[] = { 360 "mic channel", 361 "reserved", 362 "tone", 363 "simulated stereo", 364 "headphone", 365 "bass boost", 366 "18 bit DAC", 367 "20 bit DAC", 368 "18 bit ADC", 369 "20 bit ADC" 370 }; 371 372 373 int ac97_str_equal __P((const char *, const char *)); 374 void ac97_setup_source_info __P((struct ac97_softc *)); 375 void ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *)); 376 void ac97_setup_defaults __P((struct ac97_softc *)); 377 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t)); 378 379 /* #define AC97_DEBUG 10 */ 380 381 #ifdef AUDIO_DEBUG 382 #define DPRINTF(x) if (ac97debug) printf x 383 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x 384 #ifdef AC97_DEBUG 385 int ac97debug = AC97_DEBUG; 386 #else 387 int ac97debug = 0; 388 #endif 389 #else 390 #define DPRINTF(x) 391 #define DPRINTFN(n,x) 392 #endif 393 394 void 395 ac97_read(as, reg, val) 396 struct ac97_softc *as; 397 u_int8_t reg; 398 u_int16_t *val; 399 { 400 int error; 401 402 if (as->host_flags & AC97_HOST_DONT_READ && 403 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 && 404 reg != AC97_REG_RESET)) { 405 *val = as->shadow_reg[reg >> 1]; 406 return; 407 } 408 409 if ((error = as->host_if->read(as->host_if->arg, reg, val))) { 410 *val = as->shadow_reg[reg >> 1]; 411 } 412 } 413 414 int 415 ac97_write(as, reg, val) 416 struct ac97_softc *as; 417 u_int8_t reg; 418 u_int16_t val; 419 { 420 421 as->shadow_reg[reg >> 1] = val; 422 423 return (as->host_if->write(as->host_if->arg, reg, val)); 424 } 425 426 void 427 ac97_setup_defaults(as) 428 struct ac97_softc *as; 429 { 430 int idx; 431 const struct ac97_source_info *si; 432 433 memset(as->shadow_reg, 0, sizeof(as->shadow_reg)); 434 435 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) { 436 si = &source_info[idx]; 437 ac97_write(as, si->reg, si->default_value); 438 } 439 } 440 441 void 442 ac97_restore_shadow(self) 443 struct ac97_codec_if *self; 444 { 445 struct ac97_softc *as = (struct ac97_softc *) self; 446 int idx; 447 const struct ac97_source_info *si; 448 449 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) { 450 si = &source_info[idx]; 451 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]); 452 } 453 } 454 455 int 456 ac97_str_equal(a, b) 457 const char *a, *b; 458 { 459 return ((a == b) || (a && b && (!strcmp(a, b)))); 460 } 461 462 void 463 ac97_setup_source_info(as) 464 struct ac97_softc *as; 465 { 466 int idx, ouridx; 467 struct ac97_source_info *si, *si2; 468 469 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) { 470 si = &as->source_info[ouridx]; 471 472 memcpy(si, &source_info[idx], sizeof(*si)); 473 474 switch (si->type) { 475 case AUDIO_MIXER_CLASS: 476 si->mixer_class = ouridx; 477 ouridx++; 478 break; 479 case AUDIO_MIXER_VALUE: 480 /* Todo - Test to see if it works */ 481 ouridx++; 482 483 /* Add an entry for mute, if necessary */ 484 if (si->mute) { 485 si = &as->source_info[ouridx]; 486 memcpy(si, &source_info[idx], sizeof(*si)); 487 si->qualifier = AudioNmute; 488 si->type = AUDIO_MIXER_ENUM; 489 si->info = &ac97_on_off; 490 si->info_size = sizeof(ac97_on_off); 491 si->bits = 1; 492 si->ofs = 15; 493 si->mute = 0; 494 si->polarity = 0; 495 ouridx++; 496 } 497 break; 498 case AUDIO_MIXER_ENUM: 499 /* Todo - Test to see if it works */ 500 ouridx++; 501 break; 502 default: 503 printf ("ac97: shouldn't get here\n"); 504 break; 505 } 506 } 507 508 as->num_source_info = ouridx; 509 510 for (idx = 0; idx < as->num_source_info; idx++) { 511 int idx2, previdx; 512 513 si = &as->source_info[idx]; 514 515 /* Find mixer class */ 516 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 517 si2 = &as->source_info[idx2]; 518 519 if (si2->type == AUDIO_MIXER_CLASS && 520 ac97_str_equal(si->class, 521 si2->class)) { 522 si->mixer_class = idx2; 523 } 524 } 525 526 527 /* Setup prev and next pointers */ 528 if (si->prev != 0) 529 continue; 530 531 if (si->qualifier) 532 continue; 533 534 si->prev = AUDIO_MIXER_LAST; 535 previdx = idx; 536 537 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 538 if (idx2 == idx) 539 continue; 540 541 si2 = &as->source_info[idx2]; 542 543 if (!si2->prev && 544 ac97_str_equal(si->class, si2->class) && 545 ac97_str_equal(si->device, si2->device)) { 546 as->source_info[previdx].next = idx2; 547 as->source_info[idx2].prev = previdx; 548 549 previdx = idx2; 550 } 551 } 552 553 as->source_info[previdx].next = AUDIO_MIXER_LAST; 554 } 555 } 556 557 int 558 ac97_attach(host_if) 559 struct ac97_host_if *host_if; 560 { 561 struct ac97_softc *as; 562 struct device *sc_dev = (struct device *)host_if->arg; 563 int error, i, j; 564 u_int16_t id1, id2, caps; 565 u_int32_t id; 566 mixer_ctrl_t ctl; 567 568 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK); 569 570 if (as == NULL) 571 return (ENOMEM); 572 573 memset(as, 0, sizeof(*as)); 574 575 as->codec_if.vtbl = &ac97civ; 576 as->host_if = host_if; 577 578 if ((error = host_if->attach(host_if->arg, &as->codec_if))) { 579 free (as, M_DEVBUF); 580 return (error); 581 } 582 583 host_if->reset(host_if->arg); 584 585 host_if->write(host_if->arg, AC97_REG_POWER, 0); 586 host_if->write(host_if->arg, AC97_REG_RESET, 0); 587 588 if (host_if->flags) 589 as->host_flags = host_if->flags(host_if->arg); 590 591 ac97_setup_defaults(as); 592 ac97_read(as, AC97_REG_VENDOR_ID1, &id1); 593 ac97_read(as, AC97_REG_VENDOR_ID2, &id2); 594 ac97_read(as, AC97_REG_RESET, &caps); 595 596 id = (id1 << 16) | id2; 597 598 printf("%s: ", sc_dev->dv_xname); 599 600 for (i = 0; ; i++) { 601 if (ac97codecid[i].id == 0) { 602 char pnp[4]; 603 604 AC97_GET_CODEC_ID(id, pnp); 605 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f) 606 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) && 607 ISASCII(pnp[2])) 608 printf("%c%c%c%d", pnp[0], pnp[1], pnp[2], 609 pnp[3]); 610 else 611 printf("unknown (0x%08x)", id); 612 break; 613 } 614 if (ac97codecid[i].id == id) { 615 printf("%s", ac97codecid[i].name); 616 break; 617 } 618 } 619 printf(" codec; "); 620 for (i = j = 0; i < 10; i++) { 621 if (caps & (1 << i)) { 622 printf("%s%s", j? ", " : "", ac97feature[i]); 623 j++; 624 } 625 } 626 627 printf("%s%s\n", j? ", " : "", ac97enhancement[(caps >> 10) & 0x1f]); 628 629 ac97_setup_source_info(as); 630 631 /* Just enable the DAC and master volumes by default */ 632 memset(&ctl, 0, sizeof(ctl)); 633 634 ctl.type = AUDIO_MIXER_ENUM; 635 ctl.un.ord = 0; /* off */ 636 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 637 AudioNmaster, AudioNmute); 638 ac97_mixer_set_port(&as->codec_if, &ctl); 639 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs, 640 AudioNdac, AudioNmute); 641 642 ac97_mixer_set_port(&as->codec_if, &ctl); 643 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord, 644 AudioNvolume, AudioNmute); 645 ac97_mixer_set_port(&as->codec_if, &ctl); 646 647 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord, 648 AudioNsource, NULL); 649 ctl.type = AUDIO_MIXER_ENUM; 650 ctl.un.ord = 0; 651 ac97_mixer_set_port(&as->codec_if, &ctl); 652 653 return (0); 654 } 655 656 657 int 658 ac97_query_devinfo(codec_if, dip) 659 struct ac97_codec_if *codec_if; 660 mixer_devinfo_t *dip; 661 { 662 struct ac97_softc *as = (struct ac97_softc *)codec_if; 663 664 if (dip->index < as->num_source_info) { 665 struct ac97_source_info *si = &as->source_info[dip->index]; 666 const char *name; 667 668 dip->type = si->type; 669 dip->mixer_class = si->mixer_class; 670 dip->prev = si->prev; 671 dip->next = si->next; 672 673 if (si->qualifier) 674 name = si->qualifier; 675 else if (si->device) 676 name = si->device; 677 else if (si->class) 678 name = si->class; 679 else 680 name = 0; 681 682 if (name) 683 strcpy(dip->label.name, name); 684 685 memcpy(&dip->un, si->info, si->info_size); 686 687 /* Set the delta for volume sources */ 688 if (dip->type == AUDIO_MIXER_VALUE) 689 dip->un.v.delta = 1 << (8 - si->bits); 690 691 return (0); 692 } 693 694 return (ENXIO); 695 } 696 697 698 699 int 700 ac97_mixer_set_port(codec_if, cp) 701 struct ac97_codec_if *codec_if; 702 mixer_ctrl_t *cp; 703 { 704 struct ac97_softc *as = (struct ac97_softc *)codec_if; 705 struct ac97_source_info *si = &as->source_info[cp->dev]; 706 u_int16_t mask; 707 u_int16_t val, newval; 708 int error; 709 710 if (cp->dev < 0 || cp->dev >= as->num_source_info) 711 return (EINVAL); 712 713 if (cp->type != si->type) 714 return (EINVAL); 715 716 ac97_read(as, si->reg, &val); 717 718 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 719 720 mask = (1 << si->bits) - 1; 721 722 switch (cp->type) { 723 case AUDIO_MIXER_ENUM: 724 if (cp->un.ord > mask || cp->un.ord < 0) 725 return (EINVAL); 726 727 newval = (cp->un.ord << si->ofs); 728 if (si->reg == AC97_REG_RECORD_SELECT) { 729 newval |= (newval << (8 + si->ofs)); 730 mask |= (mask << 8); 731 } 732 break; 733 case AUDIO_MIXER_VALUE: 734 { 735 const struct audio_mixer_value *value = si->info; 736 u_int16_t l, r; 737 738 if ((cp->un.value.num_channels <= 0) || 739 (cp->un.value.num_channels > value->num_channels)) 740 return (EINVAL); 741 742 if (cp->un.value.num_channels == 1) { 743 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 744 } else { 745 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) { 746 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 747 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 748 } else { /* left/right is reversed here */ 749 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 750 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 751 } 752 753 } 754 755 if (!si->polarity) { 756 l = 255 - l; 757 r = 255 - r; 758 } 759 760 l = l >> (8 - si->bits); 761 r = r >> (8 - si->bits); 762 763 newval = ((l & mask) << si->ofs); 764 if (value->num_channels == 2) { 765 newval |= ((r & mask) << (si->ofs + 8)); 766 mask |= (mask << 8); 767 } 768 769 break; 770 } 771 default: 772 return (EINVAL); 773 } 774 775 mask = mask << si->ofs; 776 error = ac97_write(as, si->reg, (val & ~mask) | newval); 777 if (error) 778 return (error); 779 780 return (0); 781 } 782 783 int 784 ac97_get_portnum_by_name(codec_if, class, device, qualifier) 785 struct ac97_codec_if *codec_if; 786 char *class, *device, *qualifier; 787 { 788 struct ac97_softc *as = (struct ac97_softc *)codec_if; 789 int idx; 790 791 for (idx = 0; idx < as->num_source_info; idx++) { 792 struct ac97_source_info *si = &as->source_info[idx]; 793 if (ac97_str_equal(class, si->class) && 794 ac97_str_equal(device, si->device) && 795 ac97_str_equal(qualifier, si->qualifier)) 796 return (idx); 797 } 798 799 return (-1); 800 } 801 802 int 803 ac97_mixer_get_port(codec_if, cp) 804 struct ac97_codec_if *codec_if; 805 mixer_ctrl_t *cp; 806 { 807 struct ac97_softc *as = (struct ac97_softc *)codec_if; 808 struct ac97_source_info *si = &as->source_info[cp->dev]; 809 u_int16_t mask; 810 u_int16_t val; 811 812 if (cp->dev < 0 || cp->dev >= as->num_source_info) 813 return (EINVAL); 814 815 if (cp->type != si->type) 816 return (EINVAL); 817 818 ac97_read(as, si->reg, &val); 819 820 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 821 822 mask = (1 << si->bits) - 1; 823 824 switch (cp->type) { 825 case AUDIO_MIXER_ENUM: 826 cp->un.ord = (val >> si->ofs) & mask; 827 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord)); 828 break; 829 case AUDIO_MIXER_VALUE: 830 { 831 const struct audio_mixer_value *value = si->info; 832 u_int16_t l, r; 833 834 if ((cp->un.value.num_channels <= 0) || 835 (cp->un.value.num_channels > value->num_channels)) 836 return (EINVAL); 837 838 if (value->num_channels == 1) { 839 l = r = (val >> si->ofs) & mask; 840 } else { 841 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) { 842 l = (val >> si->ofs) & mask; 843 r = (val >> (si->ofs + 8)) & mask; 844 } else { /* host has reversed channels */ 845 r = (val >> si->ofs) & mask; 846 l = (val >> (si->ofs + 8)) & mask; 847 } 848 } 849 850 l = (l << (8 - si->bits)); 851 r = (r << (8 - si->bits)); 852 if (!si->polarity) { 853 l = 255 - l; 854 r = 255 - r; 855 } 856 857 /* The EAP driver averages l and r for stereo 858 channels that are requested in MONO mode. Does this 859 make sense? */ 860 if (cp->un.value.num_channels == 1) { 861 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l; 862 } else if (cp->un.value.num_channels == 2) { 863 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 864 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 865 } 866 867 break; 868 } 869 default: 870 return (EINVAL); 871 } 872 873 return (0); 874 } 875 876