1 /* $NetBSD: ac97.c,v 1.86 2007/02/21 22:59:59 thorpej Exp $ */ 2 /* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */ 3 4 /* 5 * Copyright (c) 1999, 2000 Constantine Sapuntzakis 6 * 7 * Author: Constantine Sapuntzakis <csapuntz@stanford.edu> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS 21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 30 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 31 * DAMAGE 32 */ 33 34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with 35 the following copyright */ 36 37 /* 38 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 * 62 * $FreeBSD$ 63 */ 64 65 #include <sys/cdefs.h> 66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.86 2007/02/21 22:59:59 thorpej 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 #include <sys/sysctl.h> 74 75 #include <sys/audioio.h> 76 #include <dev/audio_if.h> 77 78 #include <dev/ic/ac97reg.h> 79 #include <dev/ic/ac97var.h> 80 81 struct ac97_softc; 82 struct ac97_source_info; 83 static int ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *); 84 static int ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *); 85 static void ac97_detach(struct ac97_codec_if *); 86 static void ac97_lock(struct ac97_codec_if *); 87 static void ac97_unlock(struct ac97_codec_if *); 88 static int ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *); 89 static int ac97_get_portnum_by_name(struct ac97_codec_if *, const char *, 90 const char *, const char *); 91 static void ac97_restore_shadow(struct ac97_codec_if *); 92 static int ac97_set_rate(struct ac97_codec_if *, int, u_int *); 93 static void ac97_set_clock(struct ac97_codec_if *, unsigned int); 94 static uint16_t ac97_get_extcaps(struct ac97_codec_if *); 95 static int ac97_add_port(struct ac97_softc *, 96 const struct ac97_source_info *); 97 static int ac97_str_equal(const char *, const char *); 98 static int ac97_check_capability(struct ac97_softc *, int); 99 static void ac97_setup_source_info(struct ac97_softc *); 100 static void ac97_read(struct ac97_softc *, uint8_t, uint16_t *); 101 static void ac97_setup_defaults(struct ac97_softc *); 102 static int ac97_write(struct ac97_softc *, uint8_t, uint16_t); 103 104 static void ac97_ad198x_init(struct ac97_softc *); 105 static void ac97_alc650_init(struct ac97_softc *); 106 static void ac97_vt1616_init(struct ac97_softc *); 107 108 static int ac97_modem_offhook_set(struct ac97_softc *, int, int); 109 static int ac97_sysctl_verify(SYSCTLFN_ARGS); 110 111 #define Ac97Nphone "phone" 112 #define Ac97Nline1 "line1" 113 #define Ac97Nline2 "line2" 114 #define Ac97Nhandset "handset" 115 116 static const struct audio_mixer_enum 117 ac97_on_off = { 2, { { { AudioNoff, 0 } , 0 }, 118 { { AudioNon, 0 } , 1 }, 119 [2 ... 31] = { { "", 0 }, 0 } } }; 120 121 static const struct audio_mixer_enum 122 ac97_mic_select = { 2, { { { AudioNmicrophone "0", 0 }, 0 }, 123 { { AudioNmicrophone "1", 0 }, 1 }, 124 [2 ... 31] = { { "", 0 }, 0 } } }; 125 126 static const struct audio_mixer_enum 127 ac97_mono_select = { 2, { { { AudioNmixerout, 0 }, 0 }, 128 { { AudioNmicrophone, 0 }, 1 }, 129 [2 ... 31] = { { "", 0 }, 0 } } }; 130 131 static const struct audio_mixer_enum 132 ac97_source = { 8, { { { AudioNmicrophone, 0 } , 0 }, 133 { { AudioNcd, 0 }, 1 }, 134 { { AudioNvideo, 0 }, 2 }, 135 { { AudioNaux, 0 }, 3 }, 136 { { AudioNline, 0 }, 4 }, 137 { { AudioNmixerout, 0 }, 5 }, 138 { { AudioNmixerout AudioNmono, 0 }, 6 }, 139 { { Ac97Nphone, 0 }, 7 }, 140 [8 ... 31] = { { "", 0 }, 0 } } }; 141 142 /* 143 * Due to different values for each source that uses these structures, 144 * the ac97_query_devinfo function sets delta in mixer_devinfo_t using 145 * ac97_source_info.bits. 146 */ 147 static const struct audio_mixer_value 148 ac97_volume_stereo = { { AudioNvolume, 0 }, 2, 0 }; 149 150 static const struct audio_mixer_value 151 ac97_volume_mono = { { AudioNvolume, 0 }, 1, 0 }; 152 153 #define WRAP(a) &a, sizeof(a) 154 155 struct ac97_source_info { 156 const char *class; 157 const char *device; 158 const char *qualifier; 159 160 int type; 161 const void *info; 162 int info_size; 163 164 uint8_t reg; 165 int32_t default_value; 166 unsigned bits:3; 167 unsigned ofs:4; 168 unsigned mute:1; 169 unsigned polarity:1; /* Does 0 == MAX or MIN */ 170 unsigned checkbits:1; 171 enum { 172 CHECK_NONE = 0, 173 CHECK_SURROUND, 174 CHECK_CENTER, 175 CHECK_LFE, 176 CHECK_HEADPHONES, 177 CHECK_TONE, 178 CHECK_MIC, 179 CHECK_LOUDNESS, 180 CHECK_3D, 181 CHECK_LINE1, 182 CHECK_LINE2, 183 CHECK_HANDSET, 184 CHECK_SPDIF 185 } req_feature; 186 187 int prev; 188 int next; 189 int mixer_class; 190 }; 191 192 static const struct ac97_source_info audio_source_info[] = { 193 { AudioCinputs, NULL, NULL, 194 AUDIO_MIXER_CLASS, NULL, 0, 195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 196 { AudioCoutputs, NULL, 0, 197 AUDIO_MIXER_CLASS, NULL, 0, 198 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 199 { AudioCrecord, NULL, 0, 200 AUDIO_MIXER_CLASS, NULL, 0, 201 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 202 /* Stereo master volume*/ 203 { AudioCoutputs, AudioNmaster, 0, 204 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 205 AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1, 0, 1, 0, 0, 0, 0, 206 }, 207 /* Mono volume */ 208 { AudioCoutputs, AudioNmono, NULL, 209 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 210 AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1, 0, 1, 0, 0, 0, 0, 211 }, 212 { AudioCoutputs, AudioNmono, AudioNsource, 213 AUDIO_MIXER_ENUM, WRAP(ac97_mono_select), 214 AC97_REG_GP, 0x0000, 1, 9, 0, 0, 0, 0, 0, 0, 0, 215 }, 216 /* Headphone volume */ 217 { AudioCoutputs, AudioNheadphone, NULL, 218 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 219 AC97_REG_HEADPHONE_VOLUME, 0x8000, 5, 0, 1, 0, 1, CHECK_HEADPHONES, 0, 0, 0, 220 }, 221 /* Surround volume - logic hard coded for mute */ 222 { AudioCoutputs, AudioNsurround, NULL, 223 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 224 AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, 1, CHECK_SURROUND, 0, 0, 0 225 }, 226 /* Center volume*/ 227 { AudioCoutputs, AudioNcenter, NULL, 228 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 229 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, 1, CHECK_CENTER, 0, 0, 0 230 }, 231 { AudioCoutputs, AudioNcenter, AudioNmute, 232 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 233 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, 0, CHECK_CENTER, 0, 0, 0 234 }, 235 /* LFE volume*/ 236 { AudioCoutputs, AudioNlfe, NULL, 237 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 238 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, 1, CHECK_LFE, 0, 0, 0 239 }, 240 { AudioCoutputs, AudioNlfe, AudioNmute, 241 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 242 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, 0, CHECK_LFE, 0, 0, 0 243 }, 244 /* Tone - bass */ 245 { AudioCoutputs, AudioNbass, NULL, 246 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 247 AC97_REG_MASTER_TONE, 0x0f0f, 4, 8, 0, 0, 0, CHECK_TONE, 0, 0, 0 248 }, 249 /* Tone - treble */ 250 { AudioCoutputs, AudioNtreble, NULL, 251 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 252 AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, 0, CHECK_TONE, 0, 0, 0 253 }, 254 /* PC Beep Volume */ 255 { AudioCinputs, AudioNspeaker, NULL, 256 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 257 AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1, 0, 0, 0, 0, 0, 0, 258 }, 259 260 /* Phone */ 261 { AudioCinputs, Ac97Nphone, NULL, 262 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 263 AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0, 264 }, 265 /* Mic Volume */ 266 { AudioCinputs, AudioNmicrophone, NULL, 267 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 268 AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0, 269 }, 270 { AudioCinputs, AudioNmicrophone, AudioNpreamp, 271 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 272 AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0, 0, 0, 0, 0, 0, 0, 273 }, 274 { AudioCinputs, AudioNmicrophone, AudioNsource, 275 AUDIO_MIXER_ENUM, WRAP(ac97_mic_select), 276 AC97_REG_GP, 0x0000, 1, 8, 0, 0, 0, 0, 0, 0, 0, 277 }, 278 /* Line in Volume */ 279 { AudioCinputs, AudioNline, NULL, 280 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 281 AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0, 282 }, 283 /* CD Volume */ 284 { AudioCinputs, AudioNcd, NULL, 285 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 286 AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0, 287 }, 288 /* Video Volume */ 289 { AudioCinputs, AudioNvideo, NULL, 290 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 291 AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0, 292 }, 293 /* AUX volume */ 294 { AudioCinputs, AudioNaux, NULL, 295 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 296 AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0, 297 }, 298 /* PCM out volume */ 299 { AudioCinputs, AudioNdac, NULL, 300 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 301 AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0, 302 }, 303 /* Record Source - some logic for this is hard coded - see below */ 304 { AudioCrecord, AudioNsource, NULL, 305 AUDIO_MIXER_ENUM, WRAP(ac97_source), 306 AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0, 0, 0, 0, 0, 0, 0, 307 }, 308 /* Record Gain */ 309 { AudioCrecord, AudioNvolume, NULL, 310 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 311 AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 1, 0, 0, 0, 0, 0, 312 }, 313 /* Record Gain mic */ 314 { AudioCrecord, AudioNmicrophone, NULL, 315 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 316 AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, 0, CHECK_MIC, 0, 0, 0 317 }, 318 /* */ 319 { AudioCoutputs, AudioNloudness, NULL, 320 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 321 AC97_REG_GP, 0x0000, 1, 12, 0, 0, 0, CHECK_LOUDNESS, 0, 0, 0 322 }, 323 { AudioCoutputs, AudioNspatial, NULL, 324 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 325 AC97_REG_GP, 0x0000, 1, 13, 0, 1, 0, CHECK_3D, 0, 0, 0 326 }, 327 { AudioCoutputs, AudioNspatial, "center", 328 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 329 AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, 0, CHECK_3D, 0, 0, 0 330 }, 331 { AudioCoutputs, AudioNspatial, "depth", 332 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 333 AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, 0, CHECK_3D, 0, 0, 0 334 }, 335 336 /* SPDIF */ 337 { "spdif", NULL, NULL, 338 AUDIO_MIXER_CLASS, NULL, 0, 339 0, 0, 0, 0, 0, 0, 0, CHECK_SPDIF, 0, 0, 0 340 }, 341 { "spdif", "enable", NULL, 342 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 343 AC97_REG_EXT_AUDIO_CTRL, -1, 1, 2, 0, 0, 0, CHECK_SPDIF, 0, 0, 0 344 }, 345 346 /* Missing features: Simulated Stereo, POP, Loopback mode */ 347 }; 348 349 static const struct ac97_source_info modem_source_info[] = { 350 /* Classes */ 351 { AudioCinputs, NULL, NULL, 352 AUDIO_MIXER_CLASS, NULL, 0, 353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 354 { AudioCoutputs, NULL, NULL, 355 AUDIO_MIXER_CLASS, NULL, 0, 356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 357 { AudioCinputs, Ac97Nline1, NULL, 358 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 359 AC97_REG_LINE1_LEVEL, 0x8080, 4, 0, 0, 1, 0, CHECK_LINE1, 0, 0, 0 360 }, 361 { AudioCoutputs, Ac97Nline1, NULL, 362 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 363 AC97_REG_LINE1_LEVEL, 0x8080, 4, 8, 0, 1, 0, CHECK_LINE1, 0, 0, 0 364 }, 365 { AudioCinputs, Ac97Nline1, AudioNmute, 366 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 367 AC97_REG_LINE1_LEVEL, 0x8080, 1, 7, 0, 0, 0, CHECK_LINE1, 0, 0, 0 368 }, 369 { AudioCoutputs, Ac97Nline1, AudioNmute, 370 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 371 AC97_REG_LINE1_LEVEL, 0x8080, 1, 15, 0, 0, 0, CHECK_LINE1, 0, 0, 0 372 }, 373 }; 374 375 #define AUDIO_SOURCE_INFO_SIZE \ 376 (sizeof(audio_source_info)/sizeof(audio_source_info[0])) 377 #define MODEM_SOURCE_INFO_SIZE \ 378 (sizeof(modem_source_info)/sizeof(modem_source_info[0])) 379 #define SOURCE_INFO_SIZE(as) ((as)->type == AC97_CODEC_TYPE_MODEM ? \ 380 MODEM_SOURCE_INFO_SIZE : AUDIO_SOURCE_INFO_SIZE) 381 382 /* 383 * Check out http://www.intel.com/support/motherboards/desktop/sb/cs-025406.htm for 384 * AC'97 Component Specification 385 */ 386 387 struct ac97_softc { 388 /* ac97_codec_if must be at the first of ac97_softc. */ 389 struct ac97_codec_if codec_if; 390 391 struct ac97_host_if *host_if; 392 393 #define AUDIO_MAX_SOURCES (2 * AUDIO_SOURCE_INFO_SIZE) 394 #define MODEM_MAX_SOURCES (2 * MODEM_SOURCE_INFO_SIZE) 395 struct ac97_source_info audio_source_info[AUDIO_MAX_SOURCES]; 396 struct ac97_source_info modem_source_info[MODEM_MAX_SOURCES]; 397 struct ac97_source_info *source_info; 398 int num_source_info; 399 400 enum ac97_host_flags host_flags; 401 unsigned int ac97_clock; /* usually 48000 */ 402 #define AC97_STANDARD_CLOCK 48000U 403 uint16_t power_all; 404 uint16_t power_reg; /* -> AC97_REG_POWER */ 405 uint16_t caps; /* -> AC97_REG_RESET */ 406 uint16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */ 407 uint16_t ext_mid; /* -> AC97_REG_EXT_MODEM_ID */ 408 uint16_t shadow_reg[128]; 409 410 int lock_counter; 411 int type; 412 413 /* sysctl */ 414 struct sysctllog *log; 415 int offhook_line1_mib; 416 int offhook_line2_mib; 417 int offhook_line1; 418 int offhook_line2; 419 }; 420 421 static struct ac97_codec_if_vtbl ac97civ = { 422 ac97_mixer_get_port, 423 ac97_mixer_set_port, 424 ac97_query_devinfo, 425 ac97_get_portnum_by_name, 426 ac97_restore_shadow, 427 ac97_get_extcaps, 428 ac97_set_rate, 429 ac97_set_clock, 430 ac97_detach, 431 ac97_lock, 432 ac97_unlock, 433 }; 434 435 static const struct ac97_codecid { 436 uint32_t id; 437 uint32_t mask; 438 const char *name; 439 void (*init)(struct ac97_softc *); 440 } ac97codecid[] = { 441 /* 442 * Analog Devices SoundMAX 443 * http://www.soundmax.com/products/information/codecs.html 444 * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf 445 * http://www.analog.com/productSelection/pdf/AD1885_0.pdf 446 * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf 447 * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf 448 * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf 449 * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf 450 */ 451 { AC97_CODEC_ID('A', 'D', 'S', 3), 452 0xffffffff, "Analog Devices AD1819B", NULL, }, 453 { AC97_CODEC_ID('A', 'D', 'S', 0x40), 454 0xffffffff, "Analog Devices AD1881", NULL, }, 455 { AC97_CODEC_ID('A', 'D', 'S', 0x48), 456 0xffffffff, "Analog Devices AD1881A", NULL, }, 457 { AC97_CODEC_ID('A', 'D', 'S', 0x60), 458 0xffffffff, "Analog Devices AD1885", NULL, }, 459 { AC97_CODEC_ID('A', 'D', 'S', 0x61), 460 0xffffffff, "Analog Devices AD1886", NULL, }, 461 { AC97_CODEC_ID('A', 'D', 'S', 0x63), 462 0xffffffff, "Analog Devices AD1886A", NULL, }, 463 { AC97_CODEC_ID('A', 'D', 'S', 0x68), 464 0xffffffff, "Analog Devices AD1888", ac97_ad198x_init }, 465 { AC97_CODEC_ID('A', 'D', 'S', 0x70), 466 0xffffffff, "Analog Devices AD1980", ac97_ad198x_init }, 467 { AC97_CODEC_ID('A', 'D', 'S', 0x72), 468 0xffffffff, "Analog Devices AD1981A", NULL, }, 469 { AC97_CODEC_ID('A', 'D', 'S', 0x74), 470 0xffffffff, "Analog Devices AD1981B", NULL, }, 471 { AC97_CODEC_ID('A', 'D', 'S', 0x75), 472 0xffffffff, "Analog Devices AD1985", ac97_ad198x_init }, 473 { AC97_CODEC_ID('A', 'D', 'S', 0), 474 AC97_VENDOR_ID_MASK, "Analog Devices unknown", NULL, }, 475 476 /* 477 * Datasheets: 478 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4543/ek4543.pdf 479 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4544a/ek4544a.pdf 480 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4545/ak4545_f00e.pdf 481 */ 482 { AC97_CODEC_ID('A', 'K', 'M', 0), 483 0xffffffff, "Asahi Kasei AK4540", NULL, }, 484 { AC97_CODEC_ID('A', 'K', 'M', 1), 485 0xffffffff, "Asahi Kasei AK4542", NULL, }, 486 { AC97_CODEC_ID('A', 'K', 'M', 2), 487 0xffffffff, "Asahi Kasei AK4541/AK4543", NULL, }, 488 { AC97_CODEC_ID('A', 'K', 'M', 5), 489 0xffffffff, "Asahi Kasei AK4544", NULL, }, 490 { AC97_CODEC_ID('A', 'K', 'M', 6), 491 0xffffffff, "Asahi Kasei AK4544A", NULL, }, 492 { AC97_CODEC_ID('A', 'K', 'M', 7), 493 0xffffffff, "Asahi Kasei AK4545", NULL, }, 494 { AC97_CODEC_ID('A', 'K', 'M', 0), 495 AC97_VENDOR_ID_MASK, "Asahi Kasei unknown", NULL, }, 496 497 /* 498 * Realtek & Avance Logic 499 * http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True 500 * 501 * ALC650 and ALC658 support VRA, but it supports only 8000, 11025, 502 * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz. 503 */ 504 { AC97_CODEC_ID('A', 'L', 'C', 0x00), 505 0xfffffff0, "Realtek RL5306", NULL, }, 506 { AC97_CODEC_ID('A', 'L', 'C', 0x10), 507 0xfffffff0, "Realtek RL5382", NULL, }, 508 { AC97_CODEC_ID('A', 'L', 'C', 0x20), 509 0xfffffff0, "Realtek RL5383/RL5522/ALC100", NULL, }, 510 { AC97_CODEC_ID('A', 'L', 'G', 0x10), 511 0xffffffff, "Avance Logic ALC200/ALC201", NULL, }, 512 { AC97_CODEC_ID('A', 'L', 'G', 0x20), 513 0xfffffff0, "Avance Logic ALC650", ac97_alc650_init }, 514 { AC97_CODEC_ID('A', 'L', 'G', 0x30), 515 0xffffffff, "Avance Logic ALC101", NULL, }, 516 { AC97_CODEC_ID('A', 'L', 'G', 0x40), 517 0xffffffff, "Avance Logic ALC202", NULL, }, 518 { AC97_CODEC_ID('A', 'L', 'G', 0x50), 519 0xffffffff, "Avance Logic ALC250", NULL, }, 520 { AC97_CODEC_ID('A', 'L', 'G', 0x60), 521 0xfffffff0, "Avance Logic ALC655", NULL, }, 522 { AC97_CODEC_ID('A', 'L', 'G', 0x80), 523 0xfffffff0, "Avance Logic ALC658", NULL, }, 524 { AC97_CODEC_ID('A', 'L', 'G', 0x90), 525 0xfffffff0, "Avance Logic ALC850", NULL, }, 526 { AC97_CODEC_ID('A', 'L', 'C', 0), 527 AC97_VENDOR_ID_MASK, "Realtek unknown", NULL, }, 528 { AC97_CODEC_ID('A', 'L', 'G', 0), 529 AC97_VENDOR_ID_MASK, "Avance Logic unknown", NULL, }, 530 531 /** 532 * C-Media Electronics Inc. 533 * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf 534 */ 535 { AC97_CODEC_ID('C', 'M', 'I', 0x61), 536 0xffffffff, "C-Media CMI9739", NULL, }, 537 { AC97_CODEC_ID('C', 'M', 'I', 0), 538 AC97_VENDOR_ID_MASK, "C-Media unknown", NULL, }, 539 540 /* Cirrus Logic, Crystal series: 541 * 'C' 'R' 'Y' 0x0[0-7] - CS4297 542 * 0x1[0-7] - CS4297A 543 * 0x2[0-7] - CS4298 544 * 0x2[8-f] - CS4294 545 * 0x3[0-7] - CS4299 546 * 0x4[8-f] - CS4201 547 * 0x5[8-f] - CS4205 548 * 0x6[0-7] - CS4291 549 * 0x7[0-7] - CS4202 550 * Datasheets: 551 * http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593 552 * http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32 553 * http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594 554 * http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492 555 * http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492 556 * http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852 557 */ 558 { AC97_CODEC_ID('C', 'R', 'Y', 0x00), 559 0xfffffff8, "Crystal CS4297", NULL, }, 560 { AC97_CODEC_ID('C', 'R', 'Y', 0x10), 561 0xfffffff8, "Crystal CS4297A", NULL, }, 562 { AC97_CODEC_ID('C', 'R', 'Y', 0x20), 563 0xfffffff8, "Crystal CS4298", NULL, }, 564 { AC97_CODEC_ID('C', 'R', 'Y', 0x28), 565 0xfffffff8, "Crystal CS4294", NULL, }, 566 { AC97_CODEC_ID('C', 'R', 'Y', 0x30), 567 0xfffffff8, "Crystal CS4299", NULL, }, 568 { AC97_CODEC_ID('C', 'R', 'Y', 0x48), 569 0xfffffff8, "Crystal CS4201", NULL, }, 570 { AC97_CODEC_ID('C', 'R', 'Y', 0x58), 571 0xfffffff8, "Crystal CS4205", NULL, }, 572 { AC97_CODEC_ID('C', 'R', 'Y', 0x60), 573 0xfffffff8, "Crystal CS4291", NULL, }, 574 { AC97_CODEC_ID('C', 'R', 'Y', 0x70), 575 0xfffffff8, "Crystal CS4202", NULL, }, 576 { AC97_CODEC_ID('C', 'R', 'Y', 0), 577 AC97_VENDOR_ID_MASK, "Cirrus Logic unknown", NULL, }, 578 579 { 0x45838308, 0xffffffff, "ESS Technology ES1921", NULL, }, 580 { 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", NULL, }, 581 582 { AC97_CODEC_ID('H', 'R', 'S', 0), 583 0xffffffff, "Intersil HMP9701", NULL, }, 584 { AC97_CODEC_ID('H', 'R', 'S', 0), 585 AC97_VENDOR_ID_MASK, "Intersil unknown", NULL, }, 586 587 /* 588 * IC Ensemble (VIA) 589 * http://www.viatech.com/en/datasheet/DS1616.pdf 590 */ 591 { AC97_CODEC_ID('I', 'C', 'E', 0x01), 592 0xffffffff, "ICEnsemble ICE1230/VT1611", NULL, }, 593 { AC97_CODEC_ID('I', 'C', 'E', 0x11), 594 0xffffffff, "ICEnsemble ICE1232/VT1611A", NULL, }, 595 { AC97_CODEC_ID('I', 'C', 'E', 0x14), 596 0xffffffff, "ICEnsemble ICE1232A", NULL, }, 597 { AC97_CODEC_ID('I', 'C', 'E', 0x51), 598 0xffffffff, "VIA Technologies VT1616", ac97_vt1616_init }, 599 { AC97_CODEC_ID('I', 'C', 'E', 0x52), 600 0xffffffff, "VIA Technologies VT1616i", ac97_vt1616_init }, 601 { AC97_CODEC_ID('I', 'C', 'E', 0), 602 AC97_VENDOR_ID_MASK, "ICEnsemble/VIA unknown", NULL, }, 603 604 { AC97_CODEC_ID('N', 'S', 'C', 0), 605 0xffffffff, "National Semiconductor LM454[03568]", NULL, }, 606 { AC97_CODEC_ID('N', 'S', 'C', 49), 607 0xffffffff, "National Semiconductor LM4549", NULL, }, 608 { AC97_CODEC_ID('N', 'S', 'C', 0), 609 AC97_VENDOR_ID_MASK, "National Semiconductor unknown", NULL, }, 610 611 { AC97_CODEC_ID('P', 'S', 'C', 4), 612 0xffffffff, "Philips Semiconductor UCB1400", NULL, }, 613 { AC97_CODEC_ID('P', 'S', 'C', 0), 614 AC97_VENDOR_ID_MASK, "Philips Semiconductor unknown", NULL, }, 615 616 { AC97_CODEC_ID('S', 'I', 'L', 34), 617 0xffffffff, "Silicon Laboratory Si3036", NULL, }, 618 { AC97_CODEC_ID('S', 'I', 'L', 35), 619 0xffffffff, "Silicon Laboratory Si3038", NULL, }, 620 { AC97_CODEC_ID('S', 'I', 'L', 0), 621 AC97_VENDOR_ID_MASK, "Silicon Laboratory unknown", NULL, }, 622 623 { AC97_CODEC_ID('T', 'R', 'A', 2), 624 0xffffffff, "TriTech TR28022", NULL, }, 625 { AC97_CODEC_ID('T', 'R', 'A', 3), 626 0xffffffff, "TriTech TR28023", NULL, }, 627 { AC97_CODEC_ID('T', 'R', 'A', 6), 628 0xffffffff, "TriTech TR28026", NULL, }, 629 { AC97_CODEC_ID('T', 'R', 'A', 8), 630 0xffffffff, "TriTech TR28028", NULL, }, 631 { AC97_CODEC_ID('T', 'R', 'A', 35), 632 0xffffffff, "TriTech TR28602", NULL, }, 633 { AC97_CODEC_ID('T', 'R', 'A', 0), 634 AC97_VENDOR_ID_MASK, "TriTech unknown", NULL, }, 635 636 { AC97_CODEC_ID('T', 'X', 'N', 0x20), 637 0xffffffff, "Texas Instruments TLC320AD9xC", NULL, }, 638 { AC97_CODEC_ID('T', 'X', 'N', 0), 639 AC97_VENDOR_ID_MASK, "Texas Instruments unknown", NULL, }, 640 641 /* 642 * VIA 643 * http://www.viatech.com/en/multimedia/audio.jsp 644 */ 645 { AC97_CODEC_ID('V', 'I', 'A', 0x61), 646 0xffffffff, "VIA Technologies VT1612A", NULL, }, 647 { AC97_CODEC_ID('V', 'I', 'A', 0), 648 AC97_VENDOR_ID_MASK, "VIA Technologies unknown", NULL, }, 649 650 { AC97_CODEC_ID('W', 'E', 'C', 1), 651 0xffffffff, "Winbond W83971D", NULL, }, 652 { AC97_CODEC_ID('W', 'E', 'C', 0), 653 AC97_VENDOR_ID_MASK, "Winbond unknown", NULL, }, 654 655 /* 656 * http://www.wolfsonmicro.com/product_list.asp?cid=64 657 * http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00 658 * http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf - 03 659 * http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04 660 * http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04 661 * http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05 662 * http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf - 03 663 * http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03 664 * http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05 665 */ 666 { AC97_CODEC_ID('W', 'M', 'L', 0), 667 0xffffffff, "Wolfson WM9701A", NULL, }, 668 { AC97_CODEC_ID('W', 'M', 'L', 3), 669 0xffffffff, "Wolfson WM9703/WM9707/WM9708", NULL, }, 670 { AC97_CODEC_ID('W', 'M', 'L', 4), 671 0xffffffff, "Wolfson WM9704", NULL, }, 672 { AC97_CODEC_ID('W', 'M', 'L', 5), 673 0xffffffff, "Wolfson WM9705/WM9710", NULL, }, 674 { AC97_CODEC_ID('W', 'M', 'L', 0), 675 AC97_VENDOR_ID_MASK, "Wolfson unknown", NULL, }, 676 677 /* 678 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html 679 * Datasheets: 680 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf 681 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf 682 */ 683 { AC97_CODEC_ID('Y', 'M', 'H', 0), 684 0xffffffff, "Yamaha YMF743-S", NULL, }, 685 { AC97_CODEC_ID('Y', 'M', 'H', 3), 686 0xffffffff, "Yamaha YMF753-S", NULL, }, 687 { AC97_CODEC_ID('Y', 'M', 'H', 0), 688 AC97_VENDOR_ID_MASK, "Yamaha unknown", NULL, }, 689 690 /* 691 * http://www.sigmatel.com/products/technical_docs.htm 692 * and 693 * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf 694 */ 695 { 0x83847600, 0xffffffff, "SigmaTel STAC9700", NULL, }, 696 { 0x83847604, 0xffffffff, "SigmaTel STAC9701/3/4/5", NULL, }, 697 { 0x83847605, 0xffffffff, "SigmaTel STAC9704", NULL, }, 698 { 0x83847608, 0xffffffff, "SigmaTel STAC9708", NULL, }, 699 { 0x83847609, 0xffffffff, "SigmaTel STAC9721/23", NULL, }, 700 { 0x83847644, 0xffffffff, "SigmaTel STAC9744/45", NULL, }, 701 { 0x83847650, 0xffffffff, "SigmaTel STAC9750/51", NULL, }, 702 { 0x83847652, 0xffffffff, "SigmaTel STAC9752/53", NULL, }, 703 { 0x83847656, 0xffffffff, "SigmaTel STAC9756/57", NULL, }, 704 { 0x83847658, 0xffffffff, "SigmaTel STAC9758/59", NULL, }, 705 { 0x83847666, 0xffffffff, "SigmaTel STAC9766/67", NULL, }, 706 { 0x83847684, 0xffffffff, "SigmaTel STAC9783/84", NULL, }, 707 { 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown", NULL, }, 708 709 /* Conexant AC'97 modems -- good luck finding datasheets! */ 710 { AC97_CODEC_ID('C', 'X', 'T', 33), 711 0xffffffff, "Conexant HSD11246", NULL, }, 712 { AC97_CODEC_ID('C', 'X', 'T', 34), 713 0xffffffff, "Conexant D480 MDC V.92 Modem", NULL, }, 714 { AC97_CODEC_ID('C', 'X', 'T', 48), 715 0xffffffff, "Conexant CXT48", NULL, }, 716 { AC97_CODEC_ID('C', 'X', 'T', 0), 717 AC97_VENDOR_ID_MASK, "Conexant unknown", NULL, }, 718 719 { 0, 720 0, NULL, NULL, }, 721 }; 722 723 static const char * const ac97enhancement[] = { 724 "no 3D stereo", 725 "Analog Devices Phat Stereo", 726 "Creative", 727 "National Semi 3D", 728 "Yamaha Ymersion", 729 "BBE 3D", 730 "Crystal Semi 3D", 731 "Qsound QXpander", 732 "Spatializer 3D", 733 "SRS 3D", 734 "Platform Tech 3D", 735 "AKM 3D", 736 "Aureal", 737 "AZTECH 3D", 738 "Binaura 3D", 739 "ESS Technology", 740 "Harman International VMAx", 741 "Nvidea 3D", 742 "Philips Incredible Sound", 743 "Texas Instruments' 3D", 744 "VLSI Technology 3D", 745 "TriTech 3D", 746 "Realtek 3D", 747 "Samsung 3D", 748 "Wolfson Microelectronics 3D", 749 "Delta Integration 3D", 750 "SigmaTel 3D", 751 "KS Waves 3D", 752 "Rockwell 3D", 753 "Unknown 3D", 754 "Unknown 3D", 755 "Unknown 3D", 756 }; 757 758 static const char * const ac97feature[] = { 759 "dedicated mic channel", 760 "reserved", 761 "tone", 762 "simulated stereo", 763 "headphone", 764 "bass boost", 765 "18 bit DAC", 766 "20 bit DAC", 767 "18 bit ADC", 768 "20 bit ADC" 769 }; 770 771 772 /* #define AC97_DEBUG 10 */ 773 /* #define AC97_IO_DEBUG */ 774 775 #ifdef AUDIO_DEBUG 776 #define DPRINTF(x) if (ac97debug) printf x 777 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x 778 #ifdef AC97_DEBUG 779 int ac97debug = AC97_DEBUG; 780 #else 781 int ac97debug = 0; 782 #endif 783 #else 784 #define DPRINTF(x) 785 #define DPRINTFN(n,x) 786 #endif 787 788 #ifdef AC97_IO_DEBUG 789 static const char *ac97_register_names[0x80 / 2] = { 790 "RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO", 791 "MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME", 792 "LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME", 793 "PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC", 794 "GP", "3D_CONTROL", "AUDIO_INT", "POWER", 795 "EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE", 796 "PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER", 797 "SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL", 798 "LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL", 799 "LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY", 800 "GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL", 801 "0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E", 802 "0x60", "0x62", "0x64", "0x66", 803 "0x68", "0x6a", "0x6c", "0x6e", 804 "VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76", 805 "VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2" 806 }; 807 #endif 808 809 /* 810 * XXX Some cards have an inverted AC97_POWER_EAMP bit. 811 * These cards will produce no sound unless AC97_HOST_INVERTED_EAMP is set. 812 */ 813 814 #define POWER_EAMP_ON(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \ 815 ? AC97_POWER_EAMP : 0) 816 #define POWER_EAMP_OFF(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \ 817 ? 0 : AC97_POWER_EAMP) 818 819 static void 820 ac97_read(struct ac97_softc *as, uint8_t reg, uint16_t *val) 821 { 822 if (as->host_flags & AC97_HOST_DONT_READ && 823 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 && 824 reg != AC97_REG_RESET)) { 825 *val = as->shadow_reg[reg >> 1]; 826 return; 827 } 828 829 if (as->host_if->read(as->host_if->arg, reg, val)) { 830 *val = as->shadow_reg[reg >> 1]; 831 } 832 } 833 834 static int 835 ac97_write(struct ac97_softc *as, uint8_t reg, uint16_t val) 836 { 837 #ifndef AC97_IO_DEBUG 838 as->shadow_reg[reg >> 1] = val; 839 return as->host_if->write(as->host_if->arg, reg, val); 840 #else 841 int ret; 842 uint16_t actual; 843 844 as->shadow_reg[reg >> 1] = val; 845 ret = as->host_if->write(as->host_if->arg, reg, val); 846 as->host_if->read(as->host_if->arg, reg, &actual); 847 if (val != actual && reg < 0x80) { 848 printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n", 849 ac97_register_names[reg / 2], val, actual); 850 } 851 return ret; 852 #endif 853 } 854 855 static void 856 ac97_setup_defaults(struct ac97_softc *as) 857 { 858 int idx; 859 const struct ac97_source_info *si; 860 861 memset(as->shadow_reg, 0, sizeof(as->shadow_reg)); 862 863 for (idx = 0; idx < AUDIO_SOURCE_INFO_SIZE; idx++) { 864 si = &audio_source_info[idx]; 865 if (si->default_value >= 0) 866 ac97_write(as, si->reg, si->default_value); 867 } 868 for (idx = 0; idx < MODEM_SOURCE_INFO_SIZE; idx++) { 869 si = &modem_source_info[idx]; 870 if (si->default_value >= 0) 871 ac97_write(as, si->reg, si->default_value); 872 } 873 } 874 875 static void 876 ac97_restore_shadow(struct ac97_codec_if *self) 877 { 878 struct ac97_softc *as; 879 const struct ac97_source_info *si; 880 int idx; 881 uint16_t val; 882 883 as = (struct ac97_softc *) self; 884 885 if (as->type == AC97_CODEC_TYPE_AUDIO) { 886 /* restore AC97_REG_POWER */ 887 ac97_write(as, AC97_REG_POWER, as->power_reg); 888 /* make sure chip is fully operational */ 889 for (idx = 50000; idx >= 0; idx--) { 890 ac97_read(as, AC97_REG_POWER, &val); 891 if ((val & as->power_all) == as->power_all) 892 break; 893 DELAY(10); 894 } 895 896 /* 897 * actually try changing a value! 898 * The default value of AC97_REG_MASTER_VOLUME is 0x8000. 899 */ 900 for (idx = 50000; idx >= 0; idx--) { 901 ac97_write(as, AC97_REG_MASTER_VOLUME, 0x1010); 902 ac97_read(as, AC97_REG_MASTER_VOLUME, &val); 903 if (val == 0x1010) 904 break; 905 DELAY(10); 906 } 907 } 908 909 for (idx = 0; idx < SOURCE_INFO_SIZE(as); idx++) { 910 if (as->type == AC97_CODEC_TYPE_MODEM) 911 si = &modem_source_info[idx]; 912 else 913 si = &audio_source_info[idx]; 914 /* don't "restore" to the reset reg! */ 915 if (si->reg != AC97_REG_RESET) 916 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]); 917 } 918 919 if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA 920 | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM 921 | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC 922 | AC97_EXT_AUDIO_LDAC)) { 923 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, 924 as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]); 925 } 926 if (as->ext_mid & (AC97_EXT_MODEM_LINE1 | AC97_EXT_MODEM_LINE2 927 | AC97_EXT_MODEM_HANDSET | AC97_EXT_MODEM_CID1 928 | AC97_EXT_MODEM_CID2 | AC97_EXT_MODEM_ID0 929 | AC97_EXT_MODEM_ID1)) { 930 ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 931 as->shadow_reg[AC97_REG_EXT_MODEM_CTRL >> 1]); 932 } 933 } 934 935 static int 936 ac97_str_equal(const char *a, const char *b) 937 { 938 return (a == b) || (a && b && (!strcmp(a, b))); 939 } 940 941 static int 942 ac97_check_capability(struct ac97_softc *as, int check) 943 { 944 switch (check) { 945 case CHECK_NONE: 946 return 1; 947 case CHECK_SURROUND: 948 return as->ext_id & AC97_EXT_AUDIO_SDAC; 949 case CHECK_CENTER: 950 return as->ext_id & AC97_EXT_AUDIO_CDAC; 951 case CHECK_LFE: 952 return as->ext_id & AC97_EXT_AUDIO_LDAC; 953 case CHECK_SPDIF: 954 return as->ext_id & AC97_EXT_AUDIO_SPDIF; 955 case CHECK_HEADPHONES: 956 return as->caps & AC97_CAPS_HEADPHONES; 957 case CHECK_TONE: 958 return as->caps & AC97_CAPS_TONECTRL; 959 case CHECK_MIC: 960 return as->caps & AC97_CAPS_MICIN; 961 case CHECK_LOUDNESS: 962 return as->caps & AC97_CAPS_LOUDNESS; 963 case CHECK_3D: 964 return AC97_CAPS_ENHANCEMENT(as->caps) != 0; 965 case CHECK_LINE1: 966 return as->ext_mid & AC97_EXT_MODEM_LINE1; 967 case CHECK_LINE2: 968 return as->ext_mid & AC97_EXT_MODEM_LINE2; 969 case CHECK_HANDSET: 970 return as->ext_mid & AC97_EXT_MODEM_HANDSET; 971 default: 972 printf("%s: internal error: feature=%d\n", __func__, check); 973 return 0; 974 } 975 } 976 977 static void 978 ac97_setup_source_info(struct ac97_softc *as) 979 { 980 int idx, ouridx; 981 struct ac97_source_info *si, *si2; 982 uint16_t value1, value2, value3; 983 984 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE(as); idx++) { 985 si = &as->source_info[ouridx]; 986 if (as->type == AC97_CODEC_TYPE_MODEM) { 987 memcpy(si, &modem_source_info[idx], sizeof(*si)); 988 } else { 989 memcpy(si, &audio_source_info[idx], sizeof(*si)); 990 } 991 if (!ac97_check_capability(as, si->req_feature)) 992 continue; 993 if (si->checkbits) { 994 /* read the register value */ 995 ac97_read(as, si->reg, &value1); 996 /* write 0b100000 */ 997 value2 = value1 & 0xffc0; 998 value2 |= 0x20; 999 ac97_write(as, si->reg, value2); 1000 /* verify */ 1001 ac97_read(as, si->reg, &value3); 1002 if (value2 == value3) { 1003 si->bits = 6; 1004 } else { 1005 si->bits = 5; 1006 } 1007 DPRINTF(("%s: register=%02x bits=%d\n", 1008 __func__, si->reg, si->bits)); 1009 ac97_write(as, si->reg, value1); 1010 } 1011 1012 switch (si->type) { 1013 case AUDIO_MIXER_CLASS: 1014 si->mixer_class = ouridx; 1015 ouridx++; 1016 break; 1017 case AUDIO_MIXER_VALUE: 1018 /* Todo - Test to see if it works */ 1019 ouridx++; 1020 1021 /* Add an entry for mute, if necessary */ 1022 if (si->mute) { 1023 si = &as->source_info[ouridx]; 1024 if (as->type == AC97_CODEC_TYPE_MODEM) 1025 memcpy(si, &modem_source_info[idx], 1026 sizeof(*si)); 1027 else 1028 memcpy(si, &audio_source_info[idx], 1029 sizeof(*si)); 1030 si->qualifier = AudioNmute; 1031 si->type = AUDIO_MIXER_ENUM; 1032 si->info = &ac97_on_off; 1033 si->info_size = sizeof(ac97_on_off); 1034 si->bits = 1; 1035 si->ofs = 15; 1036 si->mute = 0; 1037 si->polarity = 0; 1038 ouridx++; 1039 } 1040 break; 1041 case AUDIO_MIXER_ENUM: 1042 /* Todo - Test to see if it works */ 1043 ouridx++; 1044 break; 1045 default: 1046 aprint_error ("ac97: shouldn't get here\n"); 1047 break; 1048 } 1049 } 1050 1051 as->num_source_info = ouridx; 1052 1053 for (idx = 0; idx < as->num_source_info; idx++) { 1054 int idx2, previdx; 1055 1056 si = &as->source_info[idx]; 1057 1058 /* Find mixer class */ 1059 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 1060 si2 = &as->source_info[idx2]; 1061 1062 if (si2->type == AUDIO_MIXER_CLASS && 1063 ac97_str_equal(si->class, 1064 si2->class)) { 1065 si->mixer_class = idx2; 1066 } 1067 } 1068 1069 1070 /* Setup prev and next pointers */ 1071 if (si->prev != 0) 1072 continue; 1073 1074 if (si->qualifier) 1075 continue; 1076 1077 si->prev = AUDIO_MIXER_LAST; 1078 previdx = idx; 1079 1080 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 1081 if (idx2 == idx) 1082 continue; 1083 1084 si2 = &as->source_info[idx2]; 1085 1086 if (!si2->prev && 1087 ac97_str_equal(si->class, si2->class) && 1088 ac97_str_equal(si->device, si2->device)) { 1089 as->source_info[previdx].next = idx2; 1090 as->source_info[idx2].prev = previdx; 1091 1092 previdx = idx2; 1093 } 1094 } 1095 1096 as->source_info[previdx].next = AUDIO_MIXER_LAST; 1097 } 1098 } 1099 1100 /* backward compatibility */ 1101 int 1102 ac97_attach(struct ac97_host_if *host_if, struct device *sc_dev) 1103 { 1104 return ac97_attach_type(host_if, sc_dev, AC97_CODEC_TYPE_AUDIO); 1105 } 1106 1107 int 1108 ac97_attach_type(struct ac97_host_if *host_if, struct device *sc_dev, int type) 1109 { 1110 struct ac97_softc *as; 1111 int error, i, j; 1112 uint32_t id; 1113 uint16_t id1, id2; 1114 uint16_t extstat, rate; 1115 uint16_t val; 1116 mixer_ctrl_t ctl; 1117 void (*initfunc)(struct ac97_softc *); 1118 #define FLAGBUFLEN 140 1119 char flagbuf[FLAGBUFLEN]; 1120 1121 initfunc = NULL; 1122 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO); 1123 1124 if (as == NULL) 1125 return ENOMEM; 1126 1127 as->codec_if.vtbl = &ac97civ; 1128 as->host_if = host_if; 1129 as->type = type; 1130 1131 if ((error = host_if->attach(host_if->arg, &as->codec_if))) { 1132 free(as, M_DEVBUF); 1133 return error; 1134 } 1135 1136 if (host_if->reset != NULL) { 1137 if ((error = host_if->reset(host_if->arg))) { 1138 free(as, M_DEVBUF); 1139 return error; 1140 } 1141 } 1142 1143 if (host_if->flags) 1144 as->host_flags = host_if->flags(host_if->arg); 1145 1146 /* 1147 * Assume codec has all four power bits. 1148 * XXXSCW: what to do for modems? 1149 */ 1150 as->power_all = AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC | 1151 AC97_POWER_ADC; 1152 if (as->type == AC97_CODEC_TYPE_AUDIO) { 1153 host_if->write(host_if->arg, AC97_REG_RESET, 0); 1154 1155 /* 1156 * Power-up everything except the analogue mixer. 1157 * If this codec doesn't support analogue mixer power-down, 1158 * AC97_POWER_MIXER will read back as zero. 1159 */ 1160 host_if->write(host_if->arg, AC97_REG_POWER, AC97_POWER_MIXER); 1161 ac97_read(as, AC97_REG_POWER, &val); 1162 if ((val & AC97_POWER_MIXER) == 0) { 1163 /* Codec doesn't support analogue mixer power-down */ 1164 as->power_all &= ~AC97_POWER_ANL; 1165 } 1166 host_if->write(host_if->arg, AC97_REG_POWER, POWER_EAMP_ON(as)); 1167 1168 for (i = 500000; i >= 0; i--) { 1169 ac97_read(as, AC97_REG_POWER, &val); 1170 if ((val & as->power_all) == as->power_all) 1171 break; 1172 DELAY(1); 1173 } 1174 1175 /* save AC97_REG_POWER so that we can restore it later */ 1176 ac97_read(as, AC97_REG_POWER, &as->power_reg); 1177 } else if (as->type == AC97_CODEC_TYPE_MODEM) { 1178 host_if->write(host_if->arg, AC97_REG_EXT_MODEM_ID, 0); 1179 } 1180 1181 ac97_setup_defaults(as); 1182 if (as->type == AC97_CODEC_TYPE_AUDIO) 1183 ac97_read(as, AC97_REG_RESET, &as->caps); 1184 ac97_read(as, AC97_REG_VENDOR_ID1, &id1); 1185 ac97_read(as, AC97_REG_VENDOR_ID2, &id2); 1186 1187 id = (id1 << 16) | id2; 1188 aprint_normal("%s: ac97: ", sc_dev->dv_xname); 1189 1190 for (i = 0; ; i++) { 1191 if (ac97codecid[i].id == 0) { 1192 char pnp[4]; 1193 1194 AC97_GET_CODEC_ID(id, pnp); 1195 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f) 1196 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) && 1197 ISASCII(pnp[2])) 1198 aprint_normal("%c%c%c%d", 1199 pnp[0], pnp[1], pnp[2], pnp[3]); 1200 else 1201 aprint_normal("unknown (0x%08x)", id); 1202 break; 1203 } 1204 if (ac97codecid[i].id == (id & ac97codecid[i].mask)) { 1205 aprint_normal("%s", ac97codecid[i].name); 1206 if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) { 1207 aprint_normal(" (0x%08x)", id); 1208 } 1209 initfunc = ac97codecid[i].init; 1210 break; 1211 } 1212 } 1213 aprint_normal(" codec; "); 1214 for (i = j = 0; i < 10; i++) { 1215 if (as->caps & (1 << i)) { 1216 aprint_normal("%s%s", j ? ", " : "", ac97feature[i]); 1217 j++; 1218 } 1219 } 1220 aprint_normal("%s%s\n", j ? ", " : "", 1221 ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]); 1222 1223 as->ac97_clock = AC97_STANDARD_CLOCK; 1224 1225 if (as->type == AC97_CODEC_TYPE_AUDIO) { 1226 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id); 1227 if (as->ext_id != 0) { 1228 /* Print capabilities */ 1229 bitmask_snprintf(as->ext_id, 1230 "\20\20SECONDARY10\17SECONDARY01" 1231 "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC" 1232 "\7CDAC\4VRM\3SPDIF\2DRA\1VRA", 1233 flagbuf, FLAGBUFLEN); 1234 aprint_normal("%s: ac97: ext id %s\n", sc_dev->dv_xname, 1235 flagbuf); 1236 1237 /* Print unusual settings */ 1238 if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) { 1239 aprint_normal("%s: ac97: Slot assignment: ", 1240 sc_dev->dv_xname); 1241 switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) { 1242 case AC97_EXT_AUDIO_DSA01: 1243 aprint_normal("7&8, 6&9, 10&11.\n"); 1244 break; 1245 case AC97_EXT_AUDIO_DSA10: 1246 aprint_normal("6&9, 10&11, 3&4.\n"); 1247 break; 1248 case AC97_EXT_AUDIO_DSA11: 1249 aprint_normal("10&11, 3&4, 7&8.\n"); 1250 break; 1251 } 1252 } 1253 if (as->host_flags & AC97_HOST_INVERTED_EAMP) { 1254 aprint_normal("%s: ac97: using inverted " 1255 "AC97_POWER_EAMP bit\n", 1256 sc_dev->dv_xname); 1257 } 1258 1259 /* Enable and disable features */ 1260 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat); 1261 extstat &= ~AC97_EXT_AUDIO_DRA; 1262 if (as->ext_id & AC97_EXT_AUDIO_LDAC) 1263 extstat |= AC97_EXT_AUDIO_LDAC; 1264 if (as->ext_id & AC97_EXT_AUDIO_SDAC) 1265 extstat |= AC97_EXT_AUDIO_SDAC; 1266 if (as->ext_id & AC97_EXT_AUDIO_CDAC) 1267 extstat |= AC97_EXT_AUDIO_CDAC; 1268 if (as->ext_id & AC97_EXT_AUDIO_VRM) 1269 extstat |= AC97_EXT_AUDIO_VRM; 1270 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) { 1271 /* Output the same data as DAC to SPDIF output */ 1272 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK; 1273 extstat |= AC97_EXT_AUDIO_SPSA34; 1274 ac97_read(as, AC97_REG_SPDIF_CTRL, &val); 1275 val = (val & ~AC97_SPDIF_SPSR_MASK) 1276 | AC97_SPDIF_SPSR_48K; 1277 ac97_write(as, AC97_REG_SPDIF_CTRL, val); 1278 } 1279 if (as->ext_id & AC97_EXT_AUDIO_VRA) 1280 extstat |= AC97_EXT_AUDIO_VRA; 1281 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat); 1282 if (as->ext_id & AC97_EXT_AUDIO_VRA) { 1283 /* VRA should be enabled. */ 1284 /* so it claims to do variable rate, let's make sure */ 1285 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 1286 44100); 1287 ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, 1288 &rate); 1289 if (rate != 44100) { 1290 /* We can't believe ext_id */ 1291 as->ext_id = 0; 1292 aprint_normal( 1293 "%s: Ignore these capabilities.\n", 1294 sc_dev->dv_xname); 1295 } 1296 /* restore the default value */ 1297 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 1298 AC97_SINGLE_RATE); 1299 } 1300 } 1301 } else if (as->type == AC97_CODEC_TYPE_MODEM) { 1302 const struct sysctlnode *node; 1303 const struct sysctlnode *node_line1; 1304 const struct sysctlnode *node_line2; 1305 uint16_t xrate = 8000; 1306 uint16_t xval, reg; 1307 int err; 1308 1309 ac97_read(as, AC97_REG_EXT_MODEM_ID, &as->ext_mid); 1310 if (as->ext_mid == 0 || as->ext_mid == 0xffff) { 1311 aprint_normal("%s: no modem codec found\n", 1312 sc_dev->dv_xname); 1313 return ENXIO; 1314 } 1315 as->type = AC97_CODEC_TYPE_MODEM; 1316 1317 /* Print capabilities */ 1318 bitmask_snprintf(as->ext_mid, 1319 "\20\5CID2\4CID1\3HANDSET\2LINE2\1LINE1", 1320 flagbuf, FLAGBUFLEN); 1321 aprint_normal("%s: ac97: ext mid %s", sc_dev->dv_xname, 1322 flagbuf); 1323 aprint_normal(", %s codec\n", 1324 (as->ext_mid & 0xc000) == 0 ? 1325 "primary" : "secondary"); 1326 1327 /* Setup modem and sysctls */ 1328 err = sysctl_createv(&as->log, 0, NULL, NULL, 0, CTLTYPE_NODE, 1329 "hw", NULL, NULL, 0, NULL, 0, CTL_HW, 1330 CTL_EOL); 1331 if (err != 0) 1332 goto setup_modem; 1333 err = sysctl_createv(&as->log, 0, NULL, &node, 0, 1334 CTLTYPE_NODE, sc_dev->dv_xname, NULL, 1335 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, 1336 CTL_EOL); 1337 if (err != 0) 1338 goto setup_modem; 1339 setup_modem: 1340 /* reset */ 1341 ac97_write(as, AC97_REG_EXT_MODEM_ID, 1); 1342 1343 /* program rates */ 1344 xval = 0xff00 & ~AC97_EXT_MODEM_CTRL_PRA; 1345 if (as->ext_mid & AC97_EXT_MODEM_LINE1) { 1346 ac97_write(as, AC97_REG_LINE1_RATE, xrate); 1347 xval &= ~(AC97_EXT_MODEM_CTRL_PRC | 1348 AC97_EXT_MODEM_CTRL_PRD); 1349 } 1350 if (as->ext_mid & AC97_EXT_MODEM_LINE2) { 1351 ac97_write(as, AC97_REG_LINE2_RATE, xrate); 1352 xval &= ~(AC97_EXT_MODEM_CTRL_PRE | 1353 AC97_EXT_MODEM_CTRL_PRF); 1354 } 1355 if (as->ext_mid & AC97_EXT_MODEM_HANDSET) { 1356 ac97_write(as, AC97_REG_HANDSET_RATE, xrate); 1357 xval &= ~(AC97_EXT_MODEM_CTRL_PRG | 1358 AC97_EXT_MODEM_CTRL_PRH); 1359 } 1360 1361 /* power-up everything */ 1362 ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0); 1363 for (i = 5000; i >= 0; i--) { 1364 ac97_read(as, AC97_REG_EXT_MODEM_CTRL, ®); 1365 if ((reg & /*XXXval*/0xf) == /*XXXval*/0xf) 1366 break; 1367 DELAY(1); 1368 } 1369 if (i <= 0) { 1370 printf("%s: codec not responding, status=0x%x\n", 1371 sc_dev->dv_xname, reg); 1372 return ENXIO; 1373 } 1374 1375 /* setup sysctls */ 1376 if (as->ext_mid & AC97_EXT_MODEM_LINE1) { 1377 ac97_read(as, AC97_REG_GPIO_CFG, ®); 1378 reg &= ~AC97_GPIO_LINE1_OH; 1379 ac97_write(as, AC97_REG_GPIO_CFG, reg); 1380 ac97_read(as, AC97_REG_GPIO_POLARITY, ®); 1381 reg &= ~AC97_GPIO_LINE1_OH; 1382 ac97_write(as, AC97_REG_GPIO_POLARITY, reg); 1383 1384 err = sysctl_createv(&as->log, 0, NULL, &node_line1, 1385 CTLFLAG_READWRITE, CTLTYPE_INT, 1386 "line1", 1387 SYSCTL_DESCR("off-hook line1"), 1388 ac97_sysctl_verify, 0, as, 0, 1389 CTL_HW, node->sysctl_num, 1390 CTL_CREATE, CTL_EOL); 1391 if (err != 0) 1392 goto sysctl_err; 1393 as->offhook_line1_mib = node_line1->sysctl_num; 1394 } 1395 if (as->ext_mid & AC97_EXT_MODEM_LINE2) { 1396 ac97_read(as, AC97_REG_GPIO_CFG, ®); 1397 reg &= ~AC97_GPIO_LINE2_OH; 1398 ac97_write(as, AC97_REG_GPIO_CFG, reg); 1399 ac97_read(as, AC97_REG_GPIO_POLARITY, ®); 1400 reg &= ~AC97_GPIO_LINE2_OH; 1401 ac97_write(as, AC97_REG_GPIO_POLARITY, reg); 1402 1403 err = sysctl_createv(&as->log, 0, NULL, &node_line2, 1404 CTLFLAG_READWRITE, CTLTYPE_INT, 1405 "line2", 1406 SYSCTL_DESCR("off-hook line2"), 1407 ac97_sysctl_verify, 0, as, 0, 1408 CTL_HW, node->sysctl_num, 1409 CTL_CREATE, CTL_EOL); 1410 if (err != 0) 1411 goto sysctl_err; 1412 as->offhook_line2_mib = node_line2->sysctl_num; 1413 } 1414 sysctl_err: 1415 1416 ac97_write(as, AC97_REG_GPIO_STICKY, 0xffff); 1417 ac97_write(as, AC97_REG_GPIO_WAKEUP, 0x0); 1418 ac97_write(as, AC97_REG_MISC_AFE, 0x0); 1419 } 1420 1421 as->source_info = (as->type == AC97_CODEC_TYPE_MODEM ? 1422 as->modem_source_info : as->audio_source_info); 1423 ac97_setup_source_info(as); 1424 1425 memset(&ctl, 0, sizeof(ctl)); 1426 /* disable mutes */ 1427 for (i = 0; i < 11; i++) { 1428 static struct { 1429 const char *class, *device; 1430 } d[11] = { 1431 { AudioCoutputs, AudioNmaster}, 1432 { AudioCoutputs, AudioNheadphone}, 1433 { AudioCoutputs, AudioNsurround}, 1434 { AudioCoutputs, AudioNcenter}, 1435 { AudioCoutputs, AudioNlfe}, 1436 { AudioCinputs, AudioNdac}, 1437 { AudioCinputs, AudioNcd}, 1438 { AudioCinputs, AudioNline}, 1439 { AudioCinputs, AudioNaux}, 1440 { AudioCinputs, AudioNvideo}, 1441 { AudioCrecord, AudioNvolume}, 1442 }; 1443 1444 ctl.type = AUDIO_MIXER_ENUM; 1445 ctl.un.ord = 0; 1446 1447 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, 1448 d[i].class, d[i].device, AudioNmute); 1449 ac97_mixer_set_port(&as->codec_if, &ctl); 1450 } 1451 ctl.type = AUDIO_MIXER_ENUM; 1452 ctl.un.ord = 0; 1453 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord, 1454 AudioNsource, NULL); 1455 ac97_mixer_set_port(&as->codec_if, &ctl); 1456 1457 /* set a reasonable default volume */ 1458 ctl.type = AUDIO_MIXER_VALUE; 1459 ctl.un.value.num_channels = 2; 1460 ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \ 1461 ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127; 1462 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 1463 AudioNmaster, NULL); 1464 ac97_mixer_set_port(&as->codec_if, &ctl); 1465 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 1466 AudioNsurround, NULL); 1467 ac97_mixer_set_port(&as->codec_if, &ctl); 1468 ctl.un.value.num_channels = 1; 1469 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 1470 AudioNcenter, NULL); 1471 ac97_mixer_set_port(&as->codec_if, &ctl); 1472 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 1473 AudioNlfe, NULL); 1474 ac97_mixer_set_port(&as->codec_if, &ctl); 1475 1476 if (initfunc != NULL) 1477 initfunc(as); 1478 1479 /* restore AC97_REG_POWER */ 1480 if (as->type == AC97_CODEC_TYPE_AUDIO) 1481 ac97_write(as, AC97_REG_POWER, as->power_reg); 1482 1483 return 0; 1484 } 1485 1486 static void 1487 ac97_detach(struct ac97_codec_if *codec_if) 1488 { 1489 struct ac97_softc *as; 1490 1491 as = (struct ac97_softc *)codec_if; 1492 ac97_write(as, AC97_REG_POWER, AC97_POWER_IN | AC97_POWER_OUT 1493 | AC97_POWER_MIXER | AC97_POWER_MIXER_VREF 1494 | AC97_POWER_ACLINK | AC97_POWER_CLK | AC97_POWER_AUX 1495 | POWER_EAMP_OFF(as)); 1496 free(as, M_DEVBUF); 1497 } 1498 1499 static void 1500 ac97_lock(struct ac97_codec_if *codec_if) 1501 { 1502 struct ac97_softc *as; 1503 1504 as = (struct ac97_softc *)codec_if; 1505 as->lock_counter++; 1506 } 1507 1508 static void 1509 ac97_unlock(struct ac97_codec_if *codec_if) 1510 { 1511 struct ac97_softc *as; 1512 1513 as = (struct ac97_softc *)codec_if; 1514 as->lock_counter--; 1515 } 1516 1517 static int 1518 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip) 1519 { 1520 struct ac97_softc *as; 1521 struct ac97_source_info *si; 1522 const char *name; 1523 1524 as = (struct ac97_softc *)codec_if; 1525 if (dip->index < as->num_source_info) { 1526 si = &as->source_info[dip->index]; 1527 dip->type = si->type; 1528 dip->mixer_class = si->mixer_class; 1529 dip->prev = si->prev; 1530 dip->next = si->next; 1531 1532 if (si->qualifier) 1533 name = si->qualifier; 1534 else if (si->device) 1535 name = si->device; 1536 else if (si->class) 1537 name = si->class; 1538 else 1539 name = 0; 1540 1541 if (name) 1542 strcpy(dip->label.name, name); 1543 1544 memcpy(&dip->un, si->info, si->info_size); 1545 1546 /* Set the delta for volume sources */ 1547 if (dip->type == AUDIO_MIXER_VALUE) 1548 dip->un.v.delta = 1 << (8 - si->bits); 1549 1550 return 0; 1551 } 1552 1553 return ENXIO; 1554 } 1555 1556 static int 1557 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp) 1558 { 1559 struct ac97_softc *as; 1560 struct ac97_source_info *si; 1561 uint16_t mask; 1562 uint16_t val, newval; 1563 int error; 1564 bool spdif; 1565 1566 as = (struct ac97_softc *)codec_if; 1567 if (cp->dev < 0 || cp->dev >= as->num_source_info) 1568 return EINVAL; 1569 si = &as->source_info[cp->dev]; 1570 1571 if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type) 1572 return EINVAL; 1573 spdif = si->req_feature == CHECK_SPDIF && si->reg == AC97_REG_EXT_AUDIO_CTRL; 1574 if (spdif && as->lock_counter >= 0) { 1575 /* When the value of lock_counter is the default 0, 1576 * it is not allowed to change the SPDIF mode. */ 1577 return EBUSY; 1578 } 1579 1580 ac97_read(as, si->reg, &val); 1581 1582 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 1583 1584 mask = (1 << si->bits) - 1; 1585 1586 switch (cp->type) { 1587 case AUDIO_MIXER_ENUM: 1588 if (cp->un.ord > mask || cp->un.ord < 0) 1589 return EINVAL; 1590 1591 newval = (cp->un.ord << si->ofs); 1592 if (si->reg == AC97_REG_RECORD_SELECT) { 1593 newval |= (newval << (8 + si->ofs)); 1594 mask |= (mask << 8); 1595 mask = mask << si->ofs; 1596 } else if (si->reg == AC97_REG_SURR_MASTER) { 1597 newval = cp->un.ord ? 0x8080 : 0x0000; 1598 mask = 0x8080; 1599 } else 1600 mask = mask << si->ofs; 1601 break; 1602 case AUDIO_MIXER_VALUE: 1603 { 1604 const struct audio_mixer_value *value = si->info; 1605 uint16_t l, r, ol, or; 1606 int deltal, deltar; 1607 1608 if ((cp->un.value.num_channels <= 0) || 1609 (cp->un.value.num_channels > value->num_channels)) 1610 return EINVAL; 1611 1612 if (cp->un.value.num_channels == 1) { 1613 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 1614 } else { 1615 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) { 1616 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 1617 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 1618 } else { /* left/right is reversed here */ 1619 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 1620 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 1621 } 1622 1623 } 1624 1625 if (!si->polarity) { 1626 l = 255 - l; 1627 r = 255 - r; 1628 } 1629 1630 ol = (val >> (8+si->ofs)) & mask; 1631 or = (val >> si->ofs) & mask; 1632 1633 deltal = (ol << (8 - si->bits)) - l; 1634 deltar = (or << (8 - si->bits)) - r; 1635 1636 l = l >> (8 - si->bits); 1637 r = r >> (8 - si->bits); 1638 1639 if (deltal && ol == l) 1640 l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0); 1641 if (deltar && or == r) 1642 r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0); 1643 1644 newval = ((r & mask) << si->ofs); 1645 if (value->num_channels == 2) { 1646 newval = newval | ((l & mask) << (si->ofs+8)); 1647 mask |= (mask << 8); 1648 } 1649 mask = mask << si->ofs; 1650 break; 1651 } 1652 default: 1653 return EINVAL; 1654 } 1655 1656 error = ac97_write(as, si->reg, (val & ~mask) | newval); 1657 if (error) 1658 return error; 1659 1660 if (spdif && as->host_if->spdif_event != NULL) { 1661 DPRINTF(("%s: call spdif_event(%d)\n", __func__, cp->un.ord)); 1662 as->host_if->spdif_event(as->host_if->arg, cp->un.ord); 1663 } 1664 return 0; 1665 } 1666 1667 static int 1668 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class, 1669 const char *device, const char *qualifier) 1670 { 1671 struct ac97_softc *as; 1672 int idx; 1673 1674 as = (struct ac97_softc *)codec_if; 1675 for (idx = 0; idx < as->num_source_info; idx++) { 1676 struct ac97_source_info *si = &as->source_info[idx]; 1677 if (ac97_str_equal(class, si->class) && 1678 ac97_str_equal(device, si->device) && 1679 ac97_str_equal(qualifier, si->qualifier)) 1680 return idx; 1681 } 1682 1683 return -1; 1684 } 1685 1686 static int 1687 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp) 1688 { 1689 struct ac97_softc *as; 1690 struct ac97_source_info *si; 1691 uint16_t mask; 1692 uint16_t val; 1693 1694 as = (struct ac97_softc *)codec_if; 1695 si = &as->source_info[cp->dev]; 1696 if (cp->dev < 0 || cp->dev >= as->num_source_info) 1697 return EINVAL; 1698 1699 if (cp->type != si->type) 1700 return EINVAL; 1701 1702 ac97_read(as, si->reg, &val); 1703 1704 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 1705 1706 mask = (1 << si->bits) - 1; 1707 1708 switch (cp->type) { 1709 case AUDIO_MIXER_ENUM: 1710 cp->un.ord = (val >> si->ofs) & mask; 1711 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", 1712 val, si->ofs, mask, cp->un.ord)); 1713 break; 1714 case AUDIO_MIXER_VALUE: 1715 { 1716 const struct audio_mixer_value *value = si->info; 1717 uint16_t l, r; 1718 1719 if ((cp->un.value.num_channels <= 0) || 1720 (cp->un.value.num_channels > value->num_channels)) 1721 return EINVAL; 1722 1723 if (value->num_channels == 1) { 1724 l = r = (val >> si->ofs) & mask; 1725 } else { 1726 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) { 1727 l = (val >> (si->ofs + 8)) & mask; 1728 r = (val >> si->ofs) & mask; 1729 } else { /* host has reversed channels */ 1730 r = (val >> (si->ofs + 8)) & mask; 1731 l = (val >> si->ofs) & mask; 1732 } 1733 } 1734 1735 l = (l << (8 - si->bits)); 1736 r = (r << (8 - si->bits)); 1737 if (!si->polarity) { 1738 l = 255 - l; 1739 r = 255 - r; 1740 } 1741 1742 /* The EAP driver averages l and r for stereo 1743 channels that are requested in MONO mode. Does this 1744 make sense? */ 1745 if (cp->un.value.num_channels == 1) { 1746 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l; 1747 } else if (cp->un.value.num_channels == 2) { 1748 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 1749 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 1750 } 1751 1752 break; 1753 } 1754 default: 1755 return EINVAL; 1756 } 1757 1758 return 0; 1759 } 1760 1761 1762 static int 1763 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_int *rate) 1764 { 1765 struct ac97_softc *as; 1766 u_int value; 1767 uint16_t ext_stat; 1768 uint16_t actual; 1769 uint16_t power; 1770 uint16_t power_bit; 1771 1772 as = (struct ac97_softc *)codec_if; 1773 if (target == AC97_REG_PCM_MIC_ADC_RATE) { 1774 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) { 1775 *rate = AC97_SINGLE_RATE; 1776 return 0; 1777 } 1778 } else { 1779 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) { 1780 *rate = AC97_SINGLE_RATE; 1781 return 0; 1782 } 1783 } 1784 value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock; 1785 ext_stat = 0; 1786 /* 1787 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE 1788 * Check VRA, DRA 1789 * PCM_LR_ADC_RATE 1790 * Check VRA 1791 * PCM_MIC_ADC_RATE 1792 * Check VRM 1793 */ 1794 switch (target) { 1795 case AC97_REG_PCM_FRONT_DAC_RATE: 1796 case AC97_REG_PCM_SURR_DAC_RATE: 1797 case AC97_REG_PCM_LFE_DAC_RATE: 1798 power_bit = AC97_POWER_OUT; 1799 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) { 1800 *rate = AC97_SINGLE_RATE; 1801 return 0; 1802 } 1803 if (as->ext_id & AC97_EXT_AUDIO_DRA) { 1804 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat); 1805 if (value > 0x1ffff) { 1806 return EINVAL; 1807 } else if (value > 0xffff) { 1808 /* Enable DRA */ 1809 ext_stat |= AC97_EXT_AUDIO_DRA; 1810 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat); 1811 value /= 2; 1812 } else { 1813 /* Disable DRA */ 1814 ext_stat &= ~AC97_EXT_AUDIO_DRA; 1815 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat); 1816 } 1817 } else { 1818 if (value > 0xffff) 1819 return EINVAL; 1820 } 1821 break; 1822 case AC97_REG_PCM_LR_ADC_RATE: 1823 power_bit = AC97_POWER_IN; 1824 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) { 1825 *rate = AC97_SINGLE_RATE; 1826 return 0; 1827 } 1828 if (value > 0xffff) 1829 return EINVAL; 1830 break; 1831 case AC97_REG_PCM_MIC_ADC_RATE: 1832 power_bit = AC97_POWER_IN; 1833 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) { 1834 *rate = AC97_SINGLE_RATE; 1835 return 0; 1836 } 1837 if (value > 0xffff) 1838 return EINVAL; 1839 break; 1840 default: 1841 printf("%s: Unknown register: 0x%x\n", __func__, target); 1842 return EINVAL; 1843 } 1844 1845 ac97_read(as, AC97_REG_POWER, &power); 1846 ac97_write(as, AC97_REG_POWER, power | power_bit); 1847 1848 ac97_write(as, target, (uint16_t)value); 1849 ac97_read(as, target, &actual); 1850 actual = (uint32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK; 1851 1852 ac97_write(as, AC97_REG_POWER, power); 1853 if (ext_stat & AC97_EXT_AUDIO_DRA) { 1854 *rate = actual * 2; 1855 } else { 1856 *rate = actual; 1857 } 1858 return 0; 1859 } 1860 1861 static void 1862 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock) 1863 { 1864 struct ac97_softc *as; 1865 1866 as = (struct ac97_softc *)codec_if; 1867 as->ac97_clock = clock; 1868 } 1869 1870 static uint16_t 1871 ac97_get_extcaps(struct ac97_codec_if *codec_if) 1872 { 1873 struct ac97_softc *as; 1874 1875 as = (struct ac97_softc *)codec_if; 1876 return as->ext_id; 1877 } 1878 1879 static int 1880 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src) 1881 { 1882 struct ac97_source_info *si; 1883 int ouridx, idx; 1884 1885 if ((as->type == AC97_CODEC_TYPE_AUDIO && 1886 as->num_source_info >= AUDIO_MAX_SOURCES) || 1887 (as->type == AC97_CODEC_TYPE_MODEM && 1888 as->num_source_info >= MODEM_MAX_SOURCES)) { 1889 printf("%s: internal error: increase MAX_SOURCES in %s\n", 1890 __func__, __FILE__); 1891 return -1; 1892 } 1893 if (!ac97_check_capability(as, src->req_feature)) 1894 return -1; 1895 ouridx = as->num_source_info; 1896 si = &as->source_info[ouridx]; 1897 memcpy(si, src, sizeof(*si)); 1898 1899 switch (si->type) { 1900 case AUDIO_MIXER_CLASS: 1901 case AUDIO_MIXER_VALUE: 1902 printf("%s: adding class/value is not supported yet.\n", 1903 __func__); 1904 return -1; 1905 case AUDIO_MIXER_ENUM: 1906 break; 1907 default: 1908 printf("%s: unknown type: %d\n", __func__, si->type); 1909 return -1; 1910 } 1911 as->num_source_info++; 1912 1913 si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class, 1914 NULL, NULL); 1915 /* Find the root of the device */ 1916 idx = ac97_get_portnum_by_name(&as->codec_if, si->class, 1917 si->device, NULL); 1918 /* Find the last item */ 1919 while (as->source_info[idx].next != AUDIO_MIXER_LAST) 1920 idx = as->source_info[idx].next; 1921 /* Append */ 1922 as->source_info[idx].next = ouridx; 1923 si->prev = idx; 1924 si->next = AUDIO_MIXER_LAST; 1925 1926 return 0; 1927 } 1928 1929 /** 1930 * Codec-dependent initialization 1931 */ 1932 1933 #define AD1980_REG_MISC 0x76 1934 #define AD1980_MISC_MBG0 0x0001 /* 0 1888/1980/1981 /1985 */ 1935 #define AD1980_MISC_MBG1 0x0002 /* 1 1888/1980/1981 /1985 */ 1936 #define AD1980_MISC_VREFD 0x0004 /* 2 1888/1980/1981 /1985 */ 1937 #define AD1980_MISC_VREFH 0x0008 /* 3 1888/1980/1981 /1985 */ 1938 #define AD1980_MISC_SRU 0x0010 /* 4 1888/1980 /1985 */ 1939 #define AD1980_MISC_LOSEL 0x0020 /* 5 1888/1980/1981 /1985 */ 1940 #define AD1980_MISC_2CMIC 0x0040 /* 6 1980/1981B/1985 */ 1941 #define AD1980_MISC_SPRD 0x0080 /* 7 1888/1980 /1985 */ 1942 #define AD1980_MISC_DMIX0 0x0100 /* 8 1888/1980 /1985 */ 1943 #define AD1980_MISC_DMIX1 0x0200 /* 9 1888/1980 /1985 */ 1944 #define AD1980_MISC_HPSEL 0x0400 /*10 1888/1980 /1985 */ 1945 #define AD1980_MISC_CLDIS 0x0800 /*11 1888/1980 /1985 */ 1946 #define AD1980_MISC_LODIS 0x1000 /*12 1888/1980/1981 /1985 */ 1947 #define AD1980_MISC_MSPLT 0x2000 /*13 1888/1980/1981 /1985 */ 1948 #define AD1980_MISC_AC97NC 0x4000 /*14 1888/1980 /1985 */ 1949 #define AD1980_MISC_DACZ 0x8000 /*15 1888/1980/1981 /1985 */ 1950 #define AD1981_REG_MISC 0x76 1951 #define AD1981_MISC_MADST 0x0010 /* 4 */ 1952 #define AD1981A_MISC_MADPD 0x0040 /* 6 */ 1953 #define AD1981B_MISC_MADPD 0x0080 /* 7 */ 1954 #define AD1981_MISC_FMXE 0x0200 /* 9 */ 1955 #define AD1981_MISC_DAM 0x0800 /*11 */ 1956 static void 1957 ac97_ad198x_init(struct ac97_softc *as) 1958 { 1959 int i; 1960 uint16_t misc; 1961 1962 ac97_read(as, AD1980_REG_MISC, &misc); 1963 ac97_write(as, AD1980_REG_MISC, 1964 misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL); 1965 1966 for (i = 0; i < as->num_source_info; i++) { 1967 if (as->source_info[i].type != AUDIO_MIXER_VALUE) 1968 continue; 1969 1970 if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME) 1971 as->source_info[i].reg = AC97_REG_SURR_MASTER; 1972 else if (as->source_info[i].reg == AC97_REG_SURR_MASTER) 1973 as->source_info[i].reg = AC97_REG_MASTER_VOLUME; 1974 } 1975 } 1976 1977 #define ALC650_REG_MULTI_CHANNEL_CONTROL 0x6a 1978 #define ALC650_MCC_SLOT_MODIFY_MASK 0xc000 1979 #define ALC650_MCC_FRONTDAC_FROM_SPDIFIN 0x2000 /* 13 */ 1980 #define ALC650_MCC_SPDIFOUT_FROM_ADC 0x1000 /* 12 */ 1981 #define ALC650_MCC_PCM_FROM_SPDIFIN 0x0800 /* 11 */ 1982 #define ALC650_MCC_MIC_OR_CENTERLFE 0x0400 /* 10 */ 1983 #define ALC650_MCC_LINEIN_OR_SURROUND 0x0200 /* 9 */ 1984 #define ALC650_MCC_INDEPENDENT_MASTER_L 0x0080 /* 7 */ 1985 #define ALC650_MCC_INDEPENDENT_MASTER_R 0x0040 /* 6 */ 1986 #define ALC650_MCC_ANALOG_TO_CENTERLFE 0x0020 /* 5 */ 1987 #define ALC650_MCC_ANALOG_TO_SURROUND 0x0010 /* 4 */ 1988 #define ALC650_MCC_EXCHANGE_CENTERLFE 0x0008 /* 3 */ 1989 #define ALC650_MCC_CENTERLFE_DOWNMIX 0x0004 /* 2 */ 1990 #define ALC650_MCC_SURROUND_DOWNMIX 0x0002 /* 1 */ 1991 #define ALC650_MCC_LINEOUT_TO_SURROUND 0x0001 /* 0 */ 1992 static void 1993 ac97_alc650_init(struct ac97_softc *as) 1994 { 1995 static const struct ac97_source_info sources[6] = { 1996 { AudioCoutputs, AudioNsurround, "lineinjack", 1997 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1998 ALC650_REG_MULTI_CHANNEL_CONTROL, 1999 0x0000, 1, 9, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, }, 2000 { AudioCoutputs, AudioNsurround, "mixtofront", 2001 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 2002 ALC650_REG_MULTI_CHANNEL_CONTROL, 2003 0x0000, 1, 1, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, }, 2004 { AudioCoutputs, AudioNcenter, "micjack", 2005 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 2006 ALC650_REG_MULTI_CHANNEL_CONTROL, 2007 0x0000, 1, 10, 0, 0, 0, CHECK_CENTER, 0, 0, 0, }, 2008 { AudioCoutputs, AudioNlfe, "micjack", 2009 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 2010 ALC650_REG_MULTI_CHANNEL_CONTROL, 2011 0x0000, 1, 10, 0, 0, 0, CHECK_LFE, 0, 0, 0, }, 2012 { AudioCoutputs, AudioNcenter, "mixtofront", 2013 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 2014 ALC650_REG_MULTI_CHANNEL_CONTROL, 2015 0x0000, 1, 2, 0, 0, 0, CHECK_CENTER, 0, 0, 0, }, 2016 { AudioCoutputs, AudioNlfe, "mixtofront", 2017 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 2018 ALC650_REG_MULTI_CHANNEL_CONTROL, 2019 0x0000, 1, 2, 0, 0, 0, CHECK_LFE, 0, 0, 0, }, 2020 }; 2021 2022 ac97_add_port(as, &sources[0]); 2023 ac97_add_port(as, &sources[1]); 2024 ac97_add_port(as, &sources[2]); 2025 ac97_add_port(as, &sources[3]); 2026 ac97_add_port(as, &sources[4]); 2027 ac97_add_port(as, &sources[5]); 2028 } 2029 2030 #define VT1616_REG_IO_CONTROL 0x5a 2031 #define VT1616_IC_LVL (1 << 15) 2032 #define VT1616_IC_LFECENTER_TO_FRONT (1 << 12) 2033 #define VT1616_IC_SURROUND_TO_FRONT (1 << 11) 2034 #define VT1616_IC_BPDC (1 << 10) 2035 #define VT1616_IC_DC (1 << 9) 2036 #define VT1616_IC_IB_MASK 0x000c 2037 static void 2038 ac97_vt1616_init(struct ac97_softc *as) 2039 { 2040 static const struct ac97_source_info sources[3] = { 2041 { AudioCoutputs, AudioNsurround, "mixtofront", 2042 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 2043 VT1616_REG_IO_CONTROL, 2044 0x0000, 1, 11, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, }, 2045 { AudioCoutputs, AudioNcenter, "mixtofront", 2046 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 2047 VT1616_REG_IO_CONTROL, 2048 0x0000, 1, 12, 0, 0, 0, CHECK_CENTER, 0, 0, 0, }, 2049 { AudioCoutputs, AudioNlfe, "mixtofront", 2050 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 2051 VT1616_REG_IO_CONTROL, 2052 0x0000, 1, 12, 0, 0, 0, CHECK_LFE, 0, 0, 0, }, 2053 }; 2054 2055 ac97_add_port(as, &sources[0]); 2056 ac97_add_port(as, &sources[1]); 2057 ac97_add_port(as, &sources[2]); 2058 } 2059 2060 static int 2061 ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval) 2062 { 2063 uint16_t val; 2064 2065 val = as->shadow_reg[AC97_REG_GPIO_STATUS >> 1]; 2066 switch (newval) { 2067 case 0: 2068 val &= ~line; 2069 break; 2070 case 1: 2071 val |= line; 2072 break; 2073 } 2074 ac97_write(as, AC97_REG_GPIO_STATUS, val); 2075 2076 return 0; 2077 } 2078 2079 static int 2080 ac97_sysctl_verify(SYSCTLFN_ARGS) 2081 { 2082 int error, tmp; 2083 struct sysctlnode node; 2084 struct ac97_softc *as; 2085 2086 node = *rnode; 2087 as = rnode->sysctl_data; 2088 if (node.sysctl_num == as->offhook_line1_mib) { 2089 tmp = as->offhook_line1; 2090 node.sysctl_data = &tmp; 2091 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 2092 if (error || newp == NULL) 2093 return error; 2094 2095 if (tmp < 0 || tmp > 1) 2096 return EINVAL; 2097 2098 as->offhook_line1 = tmp; 2099 ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp); 2100 } else if (node.sysctl_num == as->offhook_line2_mib) { 2101 tmp = as->offhook_line2; 2102 node.sysctl_data = &tmp; 2103 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 2104 if (error || newp == NULL) 2105 return error; 2106 2107 if (tmp < 0 || tmp > 1) 2108 return EINVAL; 2109 2110 as->offhook_line2 = tmp; 2111 ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp); 2112 } 2113 2114 return 0; 2115 } 2116