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