1 /* $OpenBSD: ac97.c,v 1.25 2001/10/28 18:58:12 mickey 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 AudioCoutputs, AudioNbass, NULL, AUDIO_MIXER_VALUE, 167 WRAP(ac97_volume_mono), 168 AC97_REG_MASTER_TONE, 4, 8, 0, 0, 0x0f0f 169 }, { 170 AudioCoutputs, AudioNtreble, NULL, AUDIO_MIXER_VALUE, 171 WRAP(ac97_volume_mono), 172 AC97_REG_MASTER_TONE, 4, 0, 0, 0, 0x0f0f 173 }, { 174 /* PC Beep Volume */ 175 AudioCinputs, AudioNspeaker, NULL, AUDIO_MIXER_VALUE, 176 WRAP(ac97_volume_mono), 177 AC97_REG_PCBEEP_VOLUME, 4, 1, 1, 0, 0x0000 178 }, { 179 /* Phone */ 180 AudioCinputs, "phone", NULL, AUDIO_MIXER_VALUE, 181 WRAP(ac97_volume_mono), 182 AC97_REG_PHONE_VOLUME, 5, 0, 1, 0, 0x8008 183 }, { 184 /* Mic Volume */ 185 AudioCinputs, AudioNmicrophone, NULL, AUDIO_MIXER_VALUE, 186 WRAP(ac97_volume_mono), 187 AC97_REG_MIC_VOLUME, 5, 0, 1, 0, 0x8008 188 }, { 189 AudioCinputs, AudioNmicrophone, AudioNpreamp, AUDIO_MIXER_ENUM, 190 WRAP(ac97_on_off), 191 AC97_REG_MIC_VOLUME, 1, 6, 0, 0, 0x8008 192 }, { 193 AudioCinputs, AudioNmicrophone, AudioNsource, AUDIO_MIXER_ENUM, 194 WRAP(ac97_mic_select), 195 AC97_REG_GP, 1, 8, 0, 0x0000 196 }, { 197 /* Line in Volume */ 198 AudioCinputs, AudioNline, NULL, AUDIO_MIXER_VALUE, 199 WRAP(ac97_volume_stereo), 200 AC97_REG_LINEIN_VOLUME, 5, 0, 1, 0, 0x8808 201 }, { 202 /* CD Volume */ 203 AudioCinputs, AudioNcd, NULL, AUDIO_MIXER_VALUE, 204 WRAP(ac97_volume_stereo), 205 AC97_REG_CD_VOLUME, 5, 0, 1, 0, 0x8808 206 }, { 207 /* Video Volume */ 208 AudioCinputs, "video", NULL, AUDIO_MIXER_VALUE, 209 WRAP(ac97_volume_stereo), 210 AC97_REG_VIDEO_VOLUME, 5, 0, 1, 0, 0x8808 211 }, { 212 /* AUX volume */ 213 AudioCinputs, AudioNaux, NULL, AUDIO_MIXER_VALUE, 214 WRAP(ac97_volume_stereo), 215 AC97_REG_AUX_VOLUME, 5, 0, 1, 0, 0x8808 216 }, { 217 /* PCM out volume */ 218 AudioCinputs, AudioNdac, NULL, AUDIO_MIXER_VALUE, 219 WRAP(ac97_volume_stereo), 220 AC97_REG_PCMOUT_VOLUME, 5, 0, 1, 0, 0x8808 221 }, { 222 /* Record Source - some logic for this is hard coded - see below */ 223 AudioCrecord, AudioNsource, NULL, AUDIO_MIXER_ENUM, 224 WRAP(ac97_source), 225 AC97_REG_RECORD_SELECT, 3, 0, 0, 0, 0x0000 226 }, { 227 /* Record Gain */ 228 AudioCrecord, AudioNvolume, NULL, AUDIO_MIXER_VALUE, 229 WRAP(ac97_volume_stereo), 230 AC97_REG_RECORD_GAIN, 4, 0, 1, 0, 0x8000 231 }, { 232 /* Record Gain mic */ 233 AudioCrecord, AudioNmicrophone, NULL, AUDIO_MIXER_VALUE, 234 WRAP(ac97_volume_mono), 235 AC97_REG_RECORD_GAIN_MIC, 4, 0, 1, 1, 0x8000 236 }, { 237 /* */ 238 AudioCoutputs, AudioNloudness, NULL, AUDIO_MIXER_ENUM, 239 WRAP(ac97_on_off), 240 AC97_REG_GP, 1, 12, 0, 0, 0x0000 241 }, { 242 AudioCoutputs, AudioNspatial, NULL, AUDIO_MIXER_ENUM, 243 WRAP(ac97_on_off), 244 AC97_REG_GP, 1, 13, 0, 0, 0x0000 245 }, { 246 AudioCoutputs, AudioNspatial, AudioNcenter,AUDIO_MIXER_VALUE, 247 WRAP(ac97_volume_mono), 248 AC97_REG_3D_CONTROL, 4, 8, 0, 1, 0x0000 249 }, { 250 AudioCoutputs, AudioNspatial, AudioNdepth, AUDIO_MIXER_VALUE, 251 WRAP(ac97_volume_mono), 252 AC97_REG_3D_CONTROL, 4, 0, 0, 1, 0x0000 253 }, { 254 /* Surround volume */ 255 AudioCoutputs, AudioNsurround, NULL, AUDIO_MIXER_VALUE, 256 WRAP(ac97_volume_stereo), 257 AC97_REG_SURROUND_VOLUME, 6, 0, 1, 0, 0x8080 258 }, { 259 /* Center volume */ 260 AudioCoutputs, AudioNcenter, NULL, AUDIO_MIXER_VALUE, 261 WRAP(ac97_volume_mono), 262 AC97_REG_CENTER_LFE_VOLUME, 6, 0, 1, 0, 0x8080 263 }, { 264 /* LFE volume */ 265 AudioCoutputs, AudioNlfe, NULL, AUDIO_MIXER_VALUE, 266 WRAP(ac97_volume_mono), 267 AC97_REG_CENTER_LFE_VOLUME, 6, 8, 1, 0, 0x8080 268 } 269 270 /* Missing features: Simulated Stereo, POP, Loopback mode */ 271 } ; 272 273 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0])) 274 275 /* 276 * Check out http://developer.intel.com/pc-supp/platform/ac97/ for 277 * information on AC-97 278 */ 279 280 struct ac97_softc { 281 struct ac97_codec_if codec_if; 282 struct ac97_host_if *host_if; 283 struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE]; 284 int num_source_info; 285 enum ac97_host_flags host_flags; 286 u_int16_t caps, ext_id; 287 u_int16_t shadow_reg[128]; 288 }; 289 290 int ac97_mixer_get_port __P((struct ac97_codec_if *self, mixer_ctrl_t *cp)); 291 int ac97_mixer_set_port __P((struct ac97_codec_if *self, mixer_ctrl_t *)); 292 int ac97_query_devinfo __P((struct ac97_codec_if *self, mixer_devinfo_t *)); 293 int ac97_get_portnum_by_name __P((struct ac97_codec_if *, char *, char *, 294 char *)); 295 void ac97_restore_shadow __P((struct ac97_codec_if *self)); 296 297 struct ac97_codec_if_vtbl ac97civ = { 298 ac97_mixer_get_port, 299 ac97_mixer_set_port, 300 ac97_query_devinfo, 301 ac97_get_portnum_by_name, 302 ac97_restore_shadow 303 }; 304 305 const struct ac97_codecid { 306 u_int8_t id; 307 u_int8_t mask; 308 u_int8_t rev; 309 u_int8_t shift; /* no use yet */ 310 char * const name; 311 } ac97_ad[] = { 312 { 0x03, 0xff, 0, 0, "AD1819" }, 313 { 0x40, 0xff, 0, 0, "AD1881" }, 314 { 0x48, 0xff, 0, 0, "AD1881A" }, 315 { 0x60, 0xff, 0, 0, "AD1885" }, 316 { 0x61, 0xff, 0, 0, "AD1886" }, 317 }, ac97_ak[] = { 318 { 0x00, 0xfe, 1, 0, "AK4540" }, 319 { 0x01, 0xfe, 1, 0, "AK4540" }, 320 { 0x02, 0xff, 0, 0, "AK4543" }, 321 { 0x06, 0xff, 0, 0, "AK4544A" }, 322 { 0x07, 0xff, 0, 0, "AK4545" }, 323 }, ac97_av[] = { 324 { 0x10, 0xff, 0, 0, "ALC200" }, 325 }, ac97_rl[] = { 326 { 0x00, 0xff, 0, 0, "RL5306" }, 327 { 0x10, 0xff, 0, 0, "RL5382" }, 328 { 0x20, 0xff, 0, 0, "RL5383" }, 329 }, ac97_cs[] = { 330 { 0x00, 0xf8, 7, 0, "CS4297" }, 331 { 0x10, 0xf8, 7, 0, "CS4297A" }, 332 { 0x20, 0xf8, 7, 0, "CS4298" }, 333 { 0x28, 0xf8, 7, 0, "CS4294" }, 334 { 0x30, 0xf8, 7, 0, "CS4299" }, 335 { 0x40, 0xf8, 7, 0, "CS4201" }, 336 { 0x50, 0xf8, 7, 0, "CS4205" }, 337 { 0x60, 0xf8, 7, 0, "CS4291" }, 338 }, ac97_is[] = { 339 { 0x00, 0xff, 0, 0, "HMP9701" }, 340 }, ac97_ic[] = { 341 { 0x01, 0xff, 0, 0, "ICE1230" }, 342 { 0x11, 0xff, 0, 0, "ICE1232" }, 343 }, ac97_ns[] = { 344 { 0x00, 0xff, 0, 0, "LM454[03568]" }, 345 { 0x31, 0xff, 0, 0, "LM4549" }, 346 }, ac97_sl[] = { 347 { 0x22, 0xff, 0, 0, "Si3036" }, 348 { 0x23, 0xff, 0, 0, "Si3038" }, 349 }, ac97_st[] = { 350 { 0x00, 0xff, 0, 0, "STAC9700" }, 351 { 0x04, 0xff, 0, 0, "STAC970[135]" }, 352 { 0x05, 0xff, 0, 0, "STAC9704" }, 353 { 0x08, 0xff, 0, 0, "STAC9708/11" }, 354 { 0x09, 0xff, 0, 0, "STAC9721/23" }, 355 { 0x44, 0xff, 0, 0, "STAC9744/45" }, 356 { 0x56, 0xff, 0, 0, "STAC9756/57" }, 357 { 0x84, 0xff, 0, 0, "STAC9784/85" }, 358 }, ac97_tt[] = { 359 { 0x02, 0xff, 0, 0, "TR28022" }, 360 { 0x03, 0xff, 0, 0, "TR28023" }, 361 { 0x06, 0xff, 0, 0, "TR28026" }, 362 { 0x08, 0xff, 0, 0, "TR28028" }, 363 { 0x23, 0xff, 0, 0, "TR28602" }, 364 }, ac97_ti[] = { 365 { 0x20, 0xff, 0, 0, "TLC320AD9xC" }, 366 }, ac97_wb[] = { 367 { 0x01, 0xff, 0, 0, "W83971D" }, 368 }, ac97_wo[] = { 369 { 0x00, 0xff, 0, 0, "WM9701A" }, 370 { 0x03, 0xff, 0, 0, "WM9704M/Q-0" }, /* & WM9703 */ 371 { 0x04, 0xff, 0, 0, "WM9704M/Q-1" }, 372 }, ac97_ym[] = { 373 { 0x00, 0xff, 0, 0, "YMF743" }, 374 }; 375 376 #define cl(n) n, sizeof(n)/sizeof(n[0]) 377 const struct ac97_vendorid { 378 u_int32_t id; 379 char * const name; 380 const struct ac97_codecid * const codecs; 381 u_int8_t num; 382 } ac97_vendors[] = { 383 { 0x41445300, "Analog Devices", cl(ac97_ad) }, 384 { 0x414B4D00, "Asahi Kasei", cl(ac97_ak) }, 385 { 0x414c4700, "Avance Logic", cl(ac97_av) }, 386 { 0x414c4300, "Realtek", cl(ac97_rl) }, 387 { 0x43525900, "Cirrus Logic", cl(ac97_cs) }, 388 { 0x48525300, "Intersil", cl(ac97_is) }, 389 { 0x49434500, "ICEnsemble", cl(ac97_ic) }, 390 { 0x4e534300, "National Semiconductor", cl(ac97_ns) }, 391 { 0x53494c00, "Silicon Laboratory", cl(ac97_sl) }, 392 { 0x54524100, "TriTech Microelectronics", cl(ac97_tt) }, 393 { 0x54584e00, "Texas Instruments", cl(ac97_ti) }, 394 { 0x57454300, "Winbond", cl(ac97_wb) }, 395 { 0x574d4c00, "Wolfson", cl(ac97_wo) }, 396 { 0x594d4800, "Yamaha", cl(ac97_ym) }, 397 { 0x83847600, "SigmaTel", cl(ac97_st) }, 398 }; 399 #undef cl 400 401 const char * const ac97enhancement[] = { 402 "No 3D Stereo", 403 "Analog Devices Phat Stereo", 404 "Creative", 405 "National Semi 3D", 406 "Yamaha Ymersion", 407 "BBE 3D", 408 "Crystal Semi 3D", 409 "Qsound QXpander", 410 "Spatializer 3D", 411 "SRS 3D", 412 "Platform Tech 3D", 413 "AKM 3D", 414 "Aureal", 415 "AZTECH 3D", 416 "Binaura 3D", 417 "ESS Technology", 418 "Harman International VMAx", 419 "Nvidea 3D", 420 "Philips Incredible Sound", 421 "Texas Instruments 3D", 422 "VLSI Technology 3D", 423 "TriTech 3D", 424 "Realtek 3D", 425 "Samsung 3D", 426 "Wolfson Microelectronics 3D", 427 "Delta Integration 3D", 428 "SigmaTel 3D", 429 "Unknown 3D", 430 "Rockwell 3D", 431 "Unknown 3D", 432 "Unknown 3D", 433 "Unknown 3D" 434 }; 435 436 const char * const ac97feature[] = { 437 "mic channel", 438 "reserved", 439 "tone", 440 "simulated stereo", 441 "headphone", 442 "bass boost", 443 "18 bit DAC", 444 "20 bit DAC", 445 "18 bit ADC", 446 "20 bit ADC" 447 }; 448 449 450 int ac97_str_equal __P((const char *, const char *)); 451 void ac97_setup_source_info __P((struct ac97_softc *)); 452 void ac97_setup_defaults __P((struct ac97_softc *)); 453 int ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *)); 454 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t)); 455 456 #define AC97_DEBUG 10 457 458 #ifdef AUDIO_DEBUG 459 #define DPRINTF(x) if (ac97debug) printf x 460 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x 461 #ifdef AC97_DEBUG 462 int ac97debug = AC97_DEBUG; 463 #else 464 int ac97debug = 0; 465 #endif 466 #else 467 #define DPRINTF(x) 468 #define DPRINTFN(n,x) 469 #endif 470 471 int 472 ac97_read(as, reg, val) 473 struct ac97_softc *as; 474 u_int8_t reg; 475 u_int16_t *val; 476 { 477 int error; 478 479 if (((as->host_flags & AC97_HOST_DONT_READ) && 480 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 && 481 reg != AC97_REG_RESET)) || 482 (as->host_flags & AC97_HOST_DONT_READANY)) { 483 *val = as->shadow_reg[reg >> 1]; 484 return (0); 485 } 486 487 if ((error = as->host_if->read(as->host_if->arg, reg, val))) 488 *val = as->shadow_reg[reg >> 1]; 489 return (error); 490 } 491 492 int 493 ac97_write(as, reg, val) 494 struct ac97_softc *as; 495 u_int8_t reg; 496 u_int16_t val; 497 { 498 as->shadow_reg[reg >> 1] = val; 499 return (as->host_if->write(as->host_if->arg, reg, val)); 500 } 501 502 void 503 ac97_setup_defaults(as) 504 struct ac97_softc *as; 505 { 506 int idx; 507 508 bzero(as->shadow_reg, sizeof(as->shadow_reg)); 509 510 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) { 511 const struct ac97_source_info *si = &source_info[idx]; 512 513 ac97_write(as, si->reg, si->default_value); 514 } 515 } 516 517 void 518 ac97_restore_shadow(self) 519 struct ac97_codec_if *self; 520 { 521 struct ac97_softc *as = (struct ac97_softc *)self; 522 int idx; 523 524 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) { 525 const struct ac97_source_info *si = &source_info[idx]; 526 527 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]); 528 } 529 } 530 531 int 532 ac97_str_equal(a, b) 533 const char *a, *b; 534 { 535 return ((a == b) || (a && b && (!strcmp(a, b)))); 536 } 537 538 void 539 ac97_setup_source_info(as) 540 struct ac97_softc *as; 541 { 542 struct ac97_source_info *si, *si2; 543 int idx, ouridx; 544 545 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) { 546 si = &as->source_info[ouridx]; 547 548 bcopy(&source_info[idx], si, sizeof(*si)); 549 550 switch (si->type) { 551 case AUDIO_MIXER_CLASS: 552 si->mixer_class = ouridx; 553 ouridx++; 554 break; 555 case AUDIO_MIXER_VALUE: 556 /* Todo - Test to see if it works */ 557 ouridx++; 558 559 /* Add an entry for mute, if necessary */ 560 if (si->mute) { 561 si = &as->source_info[ouridx]; 562 bcopy(&source_info[idx], si, sizeof(*si)); 563 si->qualifier = AudioNmute; 564 si->type = AUDIO_MIXER_ENUM; 565 si->info = &ac97_on_off; 566 si->info_size = sizeof(ac97_on_off); 567 si->bits = 1; 568 si->ofs = 15; 569 si->mute = 0; 570 si->polarity = 0; 571 ouridx++; 572 } 573 break; 574 case AUDIO_MIXER_ENUM: 575 /* Todo - Test to see if it works */ 576 ouridx++; 577 break; 578 default: 579 printf ("ac97: shouldn't get here\n"); 580 break; 581 } 582 } 583 584 as->num_source_info = ouridx; 585 586 for (idx = 0; idx < as->num_source_info; idx++) { 587 int idx2, previdx; 588 589 si = &as->source_info[idx]; 590 591 /* Find mixer class */ 592 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 593 si2 = &as->source_info[idx2]; 594 595 if (si2->type == AUDIO_MIXER_CLASS && 596 ac97_str_equal(si->class, si2->class)) { 597 si->mixer_class = idx2; 598 } 599 } 600 601 602 /* Setup prev and next pointers */ 603 if (si->prev != 0 || si->qualifier) 604 continue; 605 606 si->prev = AUDIO_MIXER_LAST; 607 previdx = idx; 608 609 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 610 if (idx2 == idx) 611 continue; 612 613 si2 = &as->source_info[idx2]; 614 615 if (!si2->prev && 616 ac97_str_equal(si->class, si2->class) && 617 ac97_str_equal(si->device, si2->device)) { 618 as->source_info[previdx].next = idx2; 619 as->source_info[idx2].prev = previdx; 620 621 previdx = idx2; 622 } 623 } 624 625 as->source_info[previdx].next = AUDIO_MIXER_LAST; 626 } 627 } 628 629 int 630 ac97_attach(host_if) 631 struct ac97_host_if *host_if; 632 { 633 struct ac97_softc *as; 634 u_int16_t id1, id2; 635 u_int32_t id; 636 mixer_ctrl_t ctl; 637 int error, i; 638 639 if (!(as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_NOWAIT))) 640 return (ENOMEM); 641 642 bzero(as, sizeof(*as)); 643 644 as->codec_if.vtbl = &ac97civ; 645 as->host_if = host_if; 646 647 if ((error = host_if->attach(host_if->arg, &as->codec_if))) { 648 free(as, M_DEVBUF); 649 return (error); 650 } 651 652 host_if->reset(host_if->arg); 653 DELAY(1000); 654 655 host_if->write(host_if->arg, AC97_REG_POWER, 0); 656 host_if->write(host_if->arg, AC97_REG_RESET, 0); 657 DELAY(10000); 658 659 if (host_if->flags) 660 as->host_flags = host_if->flags(host_if->arg); 661 662 ac97_setup_defaults(as); 663 ac97_read(as, AC97_REG_VENDOR_ID1, &id1); 664 ac97_read(as, AC97_REG_VENDOR_ID2, &id2); 665 ac97_read(as, AC97_REG_RESET, &as->caps); 666 667 id = (id1 << 16) | id2; 668 if (id) { 669 register const struct ac97_vendorid *vendor; 670 register const struct ac97_codecid *codec; 671 672 printf("ac97: codec id 0x%08x", id); 673 for (vendor = &ac97_vendors[sizeof(ac97_vendors) / 674 sizeof(ac97_vendors[0]) - 1]; 675 vendor >= ac97_vendors; vendor--) { 676 if (vendor->id == (id & AC97_VENDOR_ID_MASK)) { 677 printf(" (%s", vendor->name); 678 for (codec = &vendor->codecs[vendor->num-1]; 679 codec >= vendor->codecs; codec--) { 680 if (codec->id == (id & codec->mask)) 681 break; 682 } 683 if (codec->mask) 684 printf(" %s", codec->name); 685 else 686 printf(" <%02x>", id & 0xff); 687 if (codec->rev) 688 printf(" rev %d", id & codec->rev); 689 printf(")"); 690 break; 691 } 692 } 693 printf("\n"); 694 } else 695 printf("ac97: codec id not read\n"); 696 697 if (as->caps) { 698 printf("ac97: codec features "); 699 for (i = 0; i < 10; i++) { 700 if (as->caps & (1 << i)) 701 printf("%s, ", ac97feature[i]); 702 } 703 printf("%s\n", 704 ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]); 705 } 706 707 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id); 708 if (as->ext_id) 709 DPRINTF(("ac97: ext id %b\n", as->ext_id, 710 AC97_EXT_AUDIO_BITS)); 711 if (as->ext_id & AC97_EXT_AUDIO_VRA) 712 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, 713 AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM); 714 715 ac97_setup_source_info(as); 716 717 /* Just enable the DAC and master volumes by default */ 718 bzero(&ctl, sizeof(ctl)); 719 720 ctl.type = AUDIO_MIXER_ENUM; 721 ctl.un.ord = 0; /* off */ 722 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 723 AudioNmaster, AudioNmute); 724 ac97_mixer_set_port(&as->codec_if, &ctl); 725 726 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs, 727 AudioNdac, AudioNmute); 728 ac97_mixer_set_port(&as->codec_if, &ctl); 729 730 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord, 731 AudioNvolume, AudioNmute); 732 ac97_mixer_set_port(&as->codec_if, &ctl); 733 734 ctl.type = AUDIO_MIXER_ENUM; 735 ctl.un.ord = 0; 736 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord, 737 AudioNsource, NULL); 738 ac97_mixer_set_port(&as->codec_if, &ctl); 739 740 return (0); 741 } 742 743 int 744 ac97_query_devinfo(codec_if, dip) 745 struct ac97_codec_if *codec_if; 746 mixer_devinfo_t *dip; 747 { 748 struct ac97_softc *as = (struct ac97_softc *)codec_if; 749 750 if (dip->index < as->num_source_info) { 751 struct ac97_source_info *si = &as->source_info[dip->index]; 752 const char *name; 753 754 dip->type = si->type; 755 dip->mixer_class = si->mixer_class; 756 dip->prev = si->prev; 757 dip->next = si->next; 758 759 if (si->qualifier) 760 name = si->qualifier; 761 else if (si->device) 762 name = si->device; 763 else if (si->class) 764 name = si->class; 765 766 if (name) 767 strcpy(dip->label.name, name); 768 769 bcopy(si->info, &dip->un, si->info_size); 770 771 /* Set the delta for volume sources */ 772 if (dip->type == AUDIO_MIXER_VALUE) 773 dip->un.v.delta = 1 << (8 - si->bits); 774 775 return (0); 776 } 777 778 return (ENXIO); 779 } 780 781 int 782 ac97_mixer_set_port(codec_if, cp) 783 struct ac97_codec_if *codec_if; 784 mixer_ctrl_t *cp; 785 { 786 struct ac97_softc *as = (struct ac97_softc *)codec_if; 787 struct ac97_source_info *si = &as->source_info[cp->dev]; 788 u_int16_t mask; 789 u_int16_t val, newval; 790 int error; 791 792 if (cp->dev < 0 || cp->dev >= as->num_source_info || 793 cp->type != si->type) 794 return (EINVAL); 795 796 ac97_read(as, si->reg, &val); 797 798 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 799 800 mask = (1 << si->bits) - 1; 801 802 switch (cp->type) { 803 case AUDIO_MIXER_ENUM: 804 if (cp->un.ord > mask || cp->un.ord < 0) 805 return (EINVAL); 806 807 newval = (cp->un.ord << si->ofs); 808 if (si->reg == AC97_REG_RECORD_SELECT) { 809 newval |= (newval << (8 + si->ofs)); 810 mask |= (mask << 8); 811 } 812 break; 813 case AUDIO_MIXER_VALUE: 814 { 815 const struct audio_mixer_value *value = si->info; 816 u_int16_t l, r; 817 818 if (cp->un.value.num_channels <= 0 || 819 cp->un.value.num_channels > value->num_channels) 820 return (EINVAL); 821 822 if (cp->un.value.num_channels == 1) { 823 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 824 } else { 825 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 826 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 827 } 828 829 if (!si->polarity) { 830 l = 255 - l; 831 r = 255 - r; 832 } 833 834 l >>= 8 - si->bits; 835 r >>= 8 - si->bits; 836 837 newval = ((l & mask) << si->ofs); 838 if (value->num_channels == 2) { 839 newval |= ((r & mask) << (si->ofs + 8)); 840 mask |= (mask << 8); 841 } 842 843 break; 844 } 845 default: 846 return (EINVAL); 847 } 848 849 mask = mask << si->ofs; 850 error = ac97_write(as, si->reg, (val & ~mask) | newval); 851 if (error) 852 return (error); 853 854 return (0); 855 } 856 857 int 858 ac97_get_portnum_by_name(codec_if, class, device, qualifier) 859 struct ac97_codec_if *codec_if; 860 char *class, *device, *qualifier; 861 { 862 struct ac97_softc *as = (struct ac97_softc *)codec_if; 863 int idx; 864 865 for (idx = 0; idx < as->num_source_info; idx++) { 866 struct ac97_source_info *si = &as->source_info[idx]; 867 if (ac97_str_equal(class, si->class) && 868 ac97_str_equal(device, si->device) && 869 ac97_str_equal(qualifier, si->qualifier)) 870 return (idx); 871 } 872 873 return (-1); 874 } 875 876 int 877 ac97_mixer_get_port(codec_if, cp) 878 struct ac97_codec_if *codec_if; 879 mixer_ctrl_t *cp; 880 { 881 struct ac97_softc *as = (struct ac97_softc *)codec_if; 882 struct ac97_source_info *si = &as->source_info[cp->dev]; 883 u_int16_t mask; 884 u_int16_t val; 885 886 if (cp->dev < 0 || cp->dev >= as->num_source_info || 887 cp->type != si->type) 888 return (EINVAL); 889 890 ac97_read(as, si->reg, &val); 891 892 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 893 894 mask = (1 << si->bits) - 1; 895 896 switch (cp->type) { 897 case AUDIO_MIXER_ENUM: 898 cp->un.ord = (val >> si->ofs) & mask; 899 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, 900 mask, cp->un.ord)); 901 break; 902 case AUDIO_MIXER_VALUE: 903 { 904 const struct audio_mixer_value *value = si->info; 905 u_int16_t l, r; 906 907 if ((cp->un.value.num_channels <= 0) || 908 (cp->un.value.num_channels > value->num_channels)) 909 return (EINVAL); 910 911 l = r = (val >> si->ofs) & mask; 912 if (value->num_channels > 1) 913 r = (val >> (si->ofs + 8)) & mask; 914 915 l <<= 8 - si->bits; 916 r <<= 8 - si->bits; 917 if (!si->polarity) { 918 l = 255 - l; 919 r = 255 - r; 920 } 921 922 /* 923 * The EAP driver averages l and r for stereo 924 * channels that are requested in MONO mode. Does this 925 * make sense? 926 */ 927 if (cp->un.value.num_channels == 1) { 928 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l; 929 } else if (cp->un.value.num_channels == 2) { 930 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 931 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 932 } 933 934 break; 935 } 936 default: 937 return (EINVAL); 938 } 939 940 return (0); 941 } 942 943 int 944 ac97_set_rate(codec_if, p, mode) 945 struct ac97_codec_if *codec_if; 946 struct audio_params *p; 947 int mode; 948 { 949 struct ac97_softc *as = (struct ac97_softc *)codec_if; 950 u_int16_t reg, val, regval, id = 0; 951 952 DPRINTFN(5, ("set_rate(%lu) ", p->sample_rate)); 953 954 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) { 955 p->sample_rate = AC97_SINGLERATE; 956 return (0); 957 } 958 959 if (p->sample_rate > 0xffff) { 960 if (mode != AUMODE_PLAY) 961 return (EINVAL); 962 if (!(as->ext_id & AC97_EXT_AUDIO_DRA)) 963 return (EINVAL); 964 if (ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &id)) 965 return (EIO); 966 id |= AC97_EXT_AUDIO_DRA; 967 if (ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, id)) 968 return (EIO); 969 p->sample_rate /= 2; 970 } 971 972 /* i guess it's better w/o clicks and squeecks when changing the rate */ 973 if (ac97_read(as, AC97_REG_POWER, &val) || 974 ac97_write(as, AC97_REG_POWER, val | 975 (mode == AUMODE_PLAY? AC97_POWER_OUT : AC97_POWER_IN))) 976 return (EIO); 977 978 reg = mode == AUMODE_PLAY ? 979 AC97_REG_FRONT_DAC_RATE : AC97_REG_PCM_ADC_RATE; 980 981 if (ac97_write(as, reg, (u_int16_t) p->sample_rate) || 982 ac97_read(as, reg, ®val)) 983 return (EIO); 984 p->sample_rate = regval; 985 if (id & AC97_EXT_AUDIO_DRA) 986 p->sample_rate *= 2; 987 988 DPRINTFN(5, (" %lu\n", regval)); 989 990 if (ac97_write(as, AC97_REG_POWER, val)) 991 return (EIO); 992 993 return (0); 994 } 995