1 /* $OpenBSD: azalia_codec.c,v 1.49 2008/06/26 05:42:17 ray Exp $ */ 2 /* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */ 3 4 /*- 5 * Copyright (c) 2005 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by TAMURA Kent 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/device.h> 35 #include <sys/malloc.h> 36 #include <sys/systm.h> 37 #include <uvm/uvm_param.h> 38 #include <dev/pci/azalia.h> 39 40 #define XNAME(co) (((struct device *)co->az)->dv_xname) 41 #ifdef MAX_VOLUME_255 42 # define MIXER_DELTA(n) (AUDIO_MAX_GAIN / (n)) 43 #else 44 # define MIXER_DELTA(n) (1) 45 #endif 46 #define AZ_CLASS_INPUT 0 47 #define AZ_CLASS_OUTPUT 1 48 #define AZ_CLASS_RECORD 2 49 #define ENUM_OFFON .un.e={2, {{{AudioNoff}, 0}, {{AudioNon}, 1}}} 50 #define ENUM_IO .un.e={2, {{{"input"}, 0}, {{"output"}, 1}}} 51 #define AzaliaNfront "front" 52 #define AzaliaNclfe "clfe" 53 #define AzaliaNside "side" 54 55 #define ALC260_FUJITSU_ID 0x132610cf 56 #define ALC883_ACER_ID 0x00981025 57 #define STAC9221_APPLE_ID 0x76808384 58 59 int azalia_generic_codec_init_dacgroup(codec_t *); 60 int azalia_generic_codec_add_dacgroup(codec_t *, int, uint32_t); 61 int azalia_generic_codec_find_pin(const codec_t *, int, int, uint32_t); 62 int azalia_generic_codec_find_dac(const codec_t *, int, int); 63 64 int azalia_generic_mixer_init(codec_t *); 65 int azalia_generic_mixer_fix_indexes(codec_t *); 66 int azalia_generic_mixer_default(codec_t *); 67 int azalia_generic_mixer_delete(codec_t *); 68 int azalia_generic_mixer_ensure_capacity(codec_t *, size_t); 69 int azalia_generic_mixer_get(const codec_t *, nid_t, int, mixer_ctrl_t *); 70 int azalia_generic_mixer_set(codec_t *, nid_t, int, const mixer_ctrl_t *); 71 int azalia_generic_mixer_pinctrl(codec_t *, nid_t, uint32_t); 72 u_char azalia_generic_mixer_from_device_value 73 (const codec_t *, nid_t, int, uint32_t ); 74 uint32_t azalia_generic_mixer_to_device_value 75 (const codec_t *, nid_t, int, u_char); 76 uint32_t azalia_generic_mixer_max(const codec_t *, nid_t, int); 77 boolean_t azalia_generic_mixer_validate_value 78 (const codec_t *, nid_t, int, u_char); 79 int azalia_generic_set_port(codec_t *, mixer_ctrl_t *); 80 int azalia_generic_get_port(codec_t *, mixer_ctrl_t *); 81 82 int azalia_alc260_init_dacgroup(codec_t *); 83 int azalia_alc260_mixer_init(codec_t *); 84 int azalia_alc260_set_port(codec_t *, mixer_ctrl_t *); 85 int azalia_alc880_init_dacgroup(codec_t *); 86 int azalia_alc882_init_dacgroup(codec_t *); 87 int azalia_alc882_mixer_init(codec_t *); 88 int azalia_alc882_set_port(codec_t *, mixer_ctrl_t *); 89 int azalia_alc882_get_port(codec_t *, mixer_ctrl_t *); 90 int azalia_alc883_init_dacgroup(codec_t *); 91 int azalia_alc883_mixer_init(codec_t *); 92 int azalia_ad1984_init_dacgroup(codec_t *); 93 int azalia_ad1984_mixer_init(codec_t *); 94 int azalia_ad1984_set_port(codec_t *, mixer_ctrl_t *); 95 int azalia_ad1984_get_port(codec_t *, mixer_ctrl_t *); 96 int azalia_cmi9880_init_dacgroup(codec_t *); 97 int azalia_cmi9880_mixer_init(codec_t *); 98 int azalia_stac9200_mixer_init(codec_t *); 99 int azalia_stac9200_unsol_event(codec_t *, int); 100 int azalia_stac9221_mixer_init(codec_t *); 101 int azalia_stac9221_init_dacgroup(codec_t *); 102 int azalia_stac9221_set_port(codec_t *, mixer_ctrl_t *); 103 int azalia_stac9221_get_port(codec_t *, mixer_ctrl_t *); 104 int azalia_stac9221_apple_unsol_event(codec_t *, int); 105 int azalia_gpio_unmute(codec_t *, int); 106 int azalia_stac7661_init_dacgroup(codec_t *); 107 int azalia_stac7661_mixer_init(codec_t *); 108 int azalia_stac7661_set_port(codec_t *, mixer_ctrl_t *); 109 int azalia_stac7661_get_port(codec_t *, mixer_ctrl_t *); 110 111 int 112 azalia_codec_init_vtbl(codec_t *this) 113 { 114 /** 115 * We can refer this->vid and this->subid. 116 */ 117 this->name = NULL; 118 this->init_dacgroup = azalia_generic_codec_init_dacgroup; 119 this->mixer_init = azalia_generic_mixer_init; 120 this->mixer_delete = azalia_generic_mixer_delete; 121 this->set_port = azalia_generic_set_port; 122 this->get_port = azalia_generic_get_port; 123 switch (this->vid) { 124 case 0x10ec0260: 125 this->name = "Realtek ALC260"; 126 this->mixer_init = azalia_alc260_mixer_init; 127 this->init_dacgroup = azalia_alc260_init_dacgroup; 128 this->set_port = azalia_alc260_set_port; 129 break; 130 case 0x10ec0880: 131 this->name = "Realtek ALC880"; 132 this->init_dacgroup = azalia_alc880_init_dacgroup; 133 break; 134 case 0x10ec0882: 135 this->name = "Realtek ALC882"; 136 this->init_dacgroup = azalia_alc882_init_dacgroup; 137 this->mixer_init = azalia_alc882_mixer_init; 138 this->get_port = azalia_alc882_get_port; 139 this->set_port = azalia_alc882_set_port; 140 break; 141 case 0x10ec0883: 142 /* ftp://209.216.61.149/pc/audio/ALC883_DataSheet_1.3.pdf */ 143 this->name = "Realtek ALC883"; 144 this->init_dacgroup = azalia_alc883_init_dacgroup; 145 this->mixer_init = azalia_alc883_mixer_init; 146 this->get_port = azalia_alc882_get_port; 147 this->set_port = azalia_alc882_set_port; 148 break; 149 case 0x11d41983: 150 /* http://www.analog.com/en/prod/0,2877,AD1983,00.html */ 151 this->name = "Analog Devices AD1983"; 152 break; 153 case 0x11d41984: 154 /* http://www.analog.com/en/prod/0,2877,AD1984,00.html */ 155 this->name = "Analog Devices AD1984"; 156 this->init_dacgroup = azalia_ad1984_init_dacgroup; 157 this->mixer_init = azalia_ad1984_mixer_init; 158 this->get_port = azalia_ad1984_get_port; 159 this->set_port = azalia_ad1984_set_port; 160 break; 161 case 0x434d4980: 162 this->name = "CMedia CMI9880"; 163 this->init_dacgroup = azalia_cmi9880_init_dacgroup; 164 this->mixer_init = azalia_cmi9880_mixer_init; 165 break; 166 case 0x83847680: 167 this->name = "Sigmatel STAC9221"; 168 this->init_dacgroup = azalia_stac9221_init_dacgroup; 169 this->mixer_init = azalia_stac9221_mixer_init; 170 this->set_port = azalia_stac9221_set_port; 171 this->get_port = azalia_stac9221_get_port; 172 if (this->subid == STAC9221_APPLE_ID) 173 this->unsol_event = azalia_stac9221_apple_unsol_event; 174 break; 175 case 0x83847683: 176 this->name = "Sigmatel STAC9221D"; 177 this->init_dacgroup = azalia_stac9221_init_dacgroup; 178 break; 179 case 0x83847690: 180 /* http://www.idt.com/products/getDoc.cfm?docID=17812077 */ 181 this->name = "Sigmatel STAC9200"; 182 this->mixer_init = azalia_stac9200_mixer_init; 183 this->unsol_event = azalia_stac9200_unsol_event; 184 break; 185 case 0x83847691: 186 this->name = "Sigmatel STAC9200D"; 187 break; 188 case 0x83847661: 189 case 0x83847662: 190 this->name = "Sigmatel 83847661"; 191 this->init_dacgroup = azalia_stac7661_init_dacgroup; 192 this->mixer_init = azalia_stac7661_mixer_init; 193 this->get_port = azalia_stac7661_get_port; 194 this->set_port = azalia_stac7661_set_port; 195 break; 196 } 197 return 0; 198 } 199 200 /* ---------------------------------------------------------------- 201 * functions for generic codecs 202 * ---------------------------------------------------------------- */ 203 204 int 205 azalia_generic_codec_init_dacgroup(codec_t *this) 206 { 207 int i, j, assoc, group; 208 209 /* 210 * grouping DACs 211 * [0] the lowest assoc DACs 212 * [1] the lowest assoc digital outputs 213 * [2] the 2nd assoc DACs 214 * : 215 */ 216 this->dacs.ngroups = 0; 217 for (assoc = 0; assoc < CORB_CD_ASSOCIATION_MAX; assoc++) { 218 azalia_generic_codec_add_dacgroup(this, assoc, 0); 219 azalia_generic_codec_add_dacgroup(this, assoc, COP_AWCAP_DIGITAL); 220 } 221 222 /* find DACs which do not connect with any pins by default */ 223 FOR_EACH_WIDGET(this, i) { 224 boolean_t found; 225 226 if (this->w[i].type != COP_AWTYPE_AUDIO_OUTPUT) 227 continue; 228 found = FALSE; 229 for (group = 0; group < this->dacs.ngroups; group++) { 230 for (j = 0; j < this->dacs.groups[group].nconv; j++) { 231 if (i == this->dacs.groups[group].conv[j]) { 232 found = TRUE; 233 group = this->dacs.ngroups; 234 break; 235 } 236 } 237 } 238 if (found) 239 continue; 240 if (this->dacs.ngroups >= 32) 241 break; 242 this->dacs.groups[this->dacs.ngroups].nconv = 1; 243 this->dacs.groups[this->dacs.ngroups].conv[0] = i; 244 this->dacs.ngroups++; 245 } 246 this->dacs.cur = 0; 247 248 /* enumerate ADCs */ 249 this->adcs.ngroups = 0; 250 FOR_EACH_WIDGET(this, i) { 251 if (this->w[i].type != COP_AWTYPE_AUDIO_INPUT) 252 continue; 253 this->adcs.groups[this->adcs.ngroups].nconv = 1; 254 this->adcs.groups[this->adcs.ngroups].conv[0] = i; 255 this->adcs.ngroups++; 256 if (this->adcs.ngroups >= 32) 257 break; 258 } 259 this->adcs.cur = 0; 260 return 0; 261 } 262 263 int 264 azalia_generic_codec_add_dacgroup(codec_t *this, int assoc, uint32_t digital) 265 { 266 int i, j, n, dac, seq; 267 268 n = 0; 269 for (seq = 0 ; seq < CORB_CD_SEQUENCE_MAX; seq++) { 270 i = azalia_generic_codec_find_pin(this, assoc, seq, digital); 271 if (i < 0) 272 continue; 273 dac = azalia_generic_codec_find_dac(this, i, 0); 274 if (dac < 0) 275 continue; 276 /* duplication check */ 277 for (j = 0; j < n; j++) { 278 if (this->dacs.groups[this->dacs.ngroups].conv[j] == dac) 279 break; 280 } 281 if (j < n) /* this group already has <dac> */ 282 continue; 283 this->dacs.groups[this->dacs.ngroups].conv[n++] = dac; 284 } 285 if (n <= 0) /* no such DACs */ 286 return 0; 287 this->dacs.groups[this->dacs.ngroups].nconv = n; 288 289 /* check if the same combination is already registered */ 290 for (i = 0; i < this->dacs.ngroups; i++) { 291 if (n != this->dacs.groups[i].nconv) 292 continue; 293 for (j = 0; j < n; j++) { 294 if (this->dacs.groups[this->dacs.ngroups].conv[j] != 295 this->dacs.groups[i].conv[j]) 296 break; 297 } 298 if (j >= n) /* matched */ 299 return 0; 300 } 301 /* found no equivalent group */ 302 this->dacs.ngroups++; 303 return 0; 304 } 305 306 int 307 azalia_generic_codec_find_pin(const codec_t *this, int assoc, int seq, uint32_t digital) 308 { 309 int i; 310 311 FOR_EACH_WIDGET(this, i) { 312 if (this->w[i].type != COP_AWTYPE_PIN_COMPLEX) 313 continue; 314 if ((this->w[i].d.pin.cap & COP_PINCAP_OUTPUT) == 0) 315 continue; 316 if ((this->w[i].widgetcap & COP_AWCAP_DIGITAL) != digital) 317 continue; 318 if (this->w[i].d.pin.association != assoc) 319 continue; 320 if (this->w[i].d.pin.sequence == seq) { 321 return i; 322 } 323 } 324 return -1; 325 } 326 327 int 328 azalia_generic_codec_find_dac(const codec_t *this, int index, int depth) 329 { 330 const widget_t *w; 331 int i, j, ret; 332 333 w = &this->w[index]; 334 if (w->type == COP_AWTYPE_AUDIO_OUTPUT) 335 return index; 336 if (++depth > 50) { 337 return -1; 338 } 339 if (w->selected >= 0) { 340 j = w->connections[w->selected]; 341 if (VALID_WIDGET_NID(j, this)) { 342 ret = azalia_generic_codec_find_dac(this, j, depth); 343 if (ret >= 0) 344 return ret; 345 } 346 } 347 for (i = 0; i < w->nconnections; i++) { 348 j = w->connections[i]; 349 if (!VALID_WIDGET_NID(j, this)) 350 continue; 351 ret = azalia_generic_codec_find_dac(this, j, depth); 352 if (ret >= 0) 353 return ret; 354 } 355 return -1; 356 } 357 358 /* ---------------------------------------------------------------- 359 * Generic mixer functions 360 * ---------------------------------------------------------------- */ 361 362 int 363 azalia_generic_mixer_init(codec_t *this) 364 { 365 /* 366 * pin "<color>%2.2x" 367 * audio output "dac%2.2x" 368 * audio input "adc%2.2x" 369 * mixer "mixer%2.2x" 370 * selector "sel%2.2x" 371 */ 372 mixer_item_t *m; 373 int err, i, j, k; 374 375 this->maxmixers = 10; 376 this->nmixers = 0; 377 this->mixers = malloc(sizeof(mixer_item_t) * this->maxmixers, 378 M_DEVBUF, M_NOWAIT | M_ZERO); 379 if (this->mixers == NULL) { 380 printf("%s: out of memory in %s\n", XNAME(this), __func__); 381 return ENOMEM; 382 } 383 384 /* register classes */ 385 m = &this->mixers[AZ_CLASS_INPUT]; 386 m->devinfo.index = AZ_CLASS_INPUT; 387 strlcpy(m->devinfo.label.name, AudioCinputs, 388 sizeof(m->devinfo.label.name)); 389 m->devinfo.type = AUDIO_MIXER_CLASS; 390 m->devinfo.mixer_class = AZ_CLASS_INPUT; 391 m->devinfo.next = AUDIO_MIXER_LAST; 392 m->devinfo.prev = AUDIO_MIXER_LAST; 393 m->nid = 0; 394 395 m = &this->mixers[AZ_CLASS_OUTPUT]; 396 m->devinfo.index = AZ_CLASS_OUTPUT; 397 strlcpy(m->devinfo.label.name, AudioCoutputs, 398 sizeof(m->devinfo.label.name)); 399 m->devinfo.type = AUDIO_MIXER_CLASS; 400 m->devinfo.mixer_class = AZ_CLASS_OUTPUT; 401 m->devinfo.next = AUDIO_MIXER_LAST; 402 m->devinfo.prev = AUDIO_MIXER_LAST; 403 m->nid = 0; 404 405 m = &this->mixers[AZ_CLASS_RECORD]; 406 m->devinfo.index = AZ_CLASS_RECORD; 407 strlcpy(m->devinfo.label.name, AudioCrecord, 408 sizeof(m->devinfo.label.name)); 409 m->devinfo.type = AUDIO_MIXER_CLASS; 410 m->devinfo.mixer_class = AZ_CLASS_RECORD; 411 m->devinfo.next = AUDIO_MIXER_LAST; 412 m->devinfo.prev = AUDIO_MIXER_LAST; 413 m->nid = 0; 414 415 this->nmixers = AZ_CLASS_RECORD + 1; 416 417 #define MIXER_REG_PROLOG \ 418 mixer_devinfo_t *d; \ 419 err = azalia_generic_mixer_ensure_capacity(this, this->nmixers + 1); \ 420 if (err) \ 421 return err; \ 422 m = &this->mixers[this->nmixers]; \ 423 d = &m->devinfo; \ 424 m->nid = i 425 426 FOR_EACH_WIDGET(this, i) { 427 const widget_t *w; 428 429 w = &this->w[i]; 430 431 /* selector */ 432 if (w->type != COP_AWTYPE_AUDIO_MIXER && w->nconnections >= 2) { 433 MIXER_REG_PROLOG; 434 snprintf(d->label.name, sizeof(d->label.name), 435 "%s.source", w->name); 436 d->type = AUDIO_MIXER_ENUM; 437 if (w->type == COP_AWTYPE_AUDIO_MIXER) 438 d->mixer_class = AZ_CLASS_RECORD; 439 else if (w->type == COP_AWTYPE_AUDIO_SELECTOR) 440 d->mixer_class = AZ_CLASS_INPUT; 441 else 442 d->mixer_class = AZ_CLASS_OUTPUT; 443 m->target = MI_TARGET_CONNLIST; 444 for (j = 0, k = 0; j < w->nconnections && k < 32; j++) { 445 if (!VALID_WIDGET_NID(w->connections[j], this)) 446 continue; 447 d->un.e.member[k].ord = j; 448 strlcpy(d->un.e.member[k].label.name, 449 this->w[w->connections[j]].name, 450 MAX_AUDIO_DEV_LEN); 451 k++; 452 } 453 d->un.e.num_mem = k; 454 this->nmixers++; 455 } 456 457 /* output mute */ 458 if (w->widgetcap & COP_AWCAP_OUTAMP && 459 w->outamp_cap & COP_AMPCAP_MUTE) { 460 MIXER_REG_PROLOG; 461 snprintf(d->label.name, sizeof(d->label.name), 462 "%s.mute", w->name); 463 d->type = AUDIO_MIXER_ENUM; 464 if (w->type == COP_AWTYPE_AUDIO_MIXER) 465 d->mixer_class = AZ_CLASS_OUTPUT; 466 else if (w->type == COP_AWTYPE_AUDIO_SELECTOR) 467 d->mixer_class = AZ_CLASS_OUTPUT; 468 else if (w->type == COP_AWTYPE_PIN_COMPLEX) 469 d->mixer_class = AZ_CLASS_OUTPUT; 470 else 471 d->mixer_class = AZ_CLASS_INPUT; 472 m->target = MI_TARGET_OUTAMP; 473 d->un.e.num_mem = 2; 474 d->un.e.member[0].ord = 0; 475 strlcpy(d->un.e.member[0].label.name, AudioNoff, 476 MAX_AUDIO_DEV_LEN); 477 d->un.e.member[1].ord = 1; 478 strlcpy(d->un.e.member[1].label.name, AudioNon, 479 MAX_AUDIO_DEV_LEN); 480 this->nmixers++; 481 } 482 483 /* output gain */ 484 if (w->widgetcap & COP_AWCAP_OUTAMP 485 && COP_AMPCAP_NUMSTEPS(w->outamp_cap)) { 486 MIXER_REG_PROLOG; 487 snprintf(d->label.name, sizeof(d->label.name), 488 "%s", w->name); 489 d->type = AUDIO_MIXER_VALUE; 490 if (w->type == COP_AWTYPE_AUDIO_MIXER) 491 d->mixer_class = AZ_CLASS_OUTPUT; 492 else if (w->type == COP_AWTYPE_AUDIO_SELECTOR) 493 d->mixer_class = AZ_CLASS_OUTPUT; 494 else if (w->type == COP_AWTYPE_PIN_COMPLEX) 495 d->mixer_class = AZ_CLASS_OUTPUT; 496 else 497 d->mixer_class = AZ_CLASS_INPUT; 498 m->target = MI_TARGET_OUTAMP; 499 d->un.v.num_channels = WIDGET_CHANNELS(w); 500 #ifdef MAX_VOLUME_255 501 d->un.v.units.name[0] = 0; 502 #else 503 snprintf(d->un.v.units.name, sizeof(d->un.v.units.name), 504 "0.25x%ddB", COP_AMPCAP_STEPSIZE(w->outamp_cap)+1); 505 #endif 506 d->un.v.delta = 507 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->outamp_cap)); 508 this->nmixers++; 509 } 510 511 /* input mute */ 512 if (w->widgetcap & COP_AWCAP_INAMP && 513 w->inamp_cap & COP_AMPCAP_MUTE) { 514 if (w->type != COP_AWTYPE_AUDIO_SELECTOR && 515 w->type != COP_AWTYPE_AUDIO_MIXER) { 516 MIXER_REG_PROLOG; 517 snprintf(d->label.name, sizeof(d->label.name), 518 "%s.mute", w->name); 519 d->type = AUDIO_MIXER_ENUM; 520 if (w->type == COP_AWTYPE_AUDIO_INPUT) 521 d->mixer_class = AZ_CLASS_RECORD; 522 else 523 d->mixer_class = AZ_CLASS_INPUT; 524 m->target = 0; 525 d->un.e.num_mem = 2; 526 d->un.e.member[0].ord = 0; 527 strlcpy(d->un.e.member[0].label.name, 528 AudioNoff, MAX_AUDIO_DEV_LEN); 529 d->un.e.member[1].ord = 1; 530 strlcpy(d->un.e.member[1].label.name, 531 AudioNon, MAX_AUDIO_DEV_LEN); 532 this->nmixers++; 533 } else { 534 for (j = 0; j < w->nconnections; j++) { 535 MIXER_REG_PROLOG; 536 if (!VALID_WIDGET_NID(w->connections[j], this)) 537 continue; 538 snprintf(d->label.name, sizeof(d->label.name), 539 "%s.%s.mute", w->name, 540 this->w[w->connections[j]].name); 541 d->type = AUDIO_MIXER_ENUM; 542 if (w->type == COP_AWTYPE_AUDIO_INPUT) 543 d->mixer_class = AZ_CLASS_RECORD; 544 else 545 d->mixer_class = AZ_CLASS_INPUT; 546 m->target = j; 547 d->un.e.num_mem = 2; 548 d->un.e.member[0].ord = 0; 549 strlcpy(d->un.e.member[0].label.name, 550 AudioNoff, MAX_AUDIO_DEV_LEN); 551 d->un.e.member[1].ord = 1; 552 strlcpy(d->un.e.member[1].label.name, 553 AudioNon, MAX_AUDIO_DEV_LEN); 554 this->nmixers++; 555 } 556 } 557 } 558 559 /* input gain */ 560 if (w->widgetcap & COP_AWCAP_INAMP 561 && COP_AMPCAP_NUMSTEPS(w->inamp_cap)) { 562 if (w->type != COP_AWTYPE_AUDIO_SELECTOR && 563 w->type != COP_AWTYPE_AUDIO_MIXER) { 564 MIXER_REG_PROLOG; 565 snprintf(d->label.name, sizeof(d->label.name), 566 "%s", w->name); 567 d->type = AUDIO_MIXER_VALUE; 568 if (w->type == COP_AWTYPE_AUDIO_INPUT) 569 d->mixer_class = AZ_CLASS_RECORD; 570 else 571 d->mixer_class = AZ_CLASS_INPUT; 572 m->target = 0; 573 d->un.v.num_channels = WIDGET_CHANNELS(w); 574 #ifdef MAX_VOLUME_255 575 d->un.v.units.name[0] = 0; 576 #else 577 snprintf(d->un.v.units.name, 578 sizeof(d->un.v.units.name), "0.25x%ddB", 579 COP_AMPCAP_STEPSIZE(w->inamp_cap)+1); 580 #endif 581 d->un.v.delta = 582 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap)); 583 this->nmixers++; 584 } else { 585 for (j = 0; j < w->nconnections; j++) { 586 MIXER_REG_PROLOG; 587 if (!VALID_WIDGET_NID(w->connections[j], this)) 588 continue; 589 snprintf(d->label.name, sizeof(d->label.name), 590 "%s.%s", w->name, 591 this->w[w->connections[j]].name); 592 d->type = AUDIO_MIXER_VALUE; 593 if (w->type == COP_AWTYPE_AUDIO_INPUT) 594 d->mixer_class = AZ_CLASS_RECORD; 595 else 596 d->mixer_class = AZ_CLASS_INPUT; 597 m->target = j; 598 d->un.v.num_channels = WIDGET_CHANNELS(w); 599 #ifdef MAX_VOLUME_255 600 d->un.v.units.name[0] = 0; 601 #else 602 snprintf(d->un.v.units.name, 603 sizeof(d->un.v.units.name), "0.25x%ddB", 604 COP_AMPCAP_STEPSIZE(w->inamp_cap)+1); 605 #endif 606 d->un.v.delta = 607 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap)); 608 this->nmixers++; 609 } 610 } 611 } 612 613 /* pin direction */ 614 if (w->type == COP_AWTYPE_PIN_COMPLEX && 615 w->d.pin.cap & COP_PINCAP_OUTPUT && 616 w->d.pin.cap & COP_PINCAP_INPUT) { 617 MIXER_REG_PROLOG; 618 snprintf(d->label.name, sizeof(d->label.name), 619 "%s.dir", w->name); 620 d->type = AUDIO_MIXER_ENUM; 621 d->mixer_class = AZ_CLASS_OUTPUT; 622 m->target = MI_TARGET_PINDIR; 623 d->un.e.num_mem = 2; 624 d->un.e.member[0].ord = 0; 625 strlcpy(d->un.e.member[0].label.name, AudioNinput, 626 MAX_AUDIO_DEV_LEN); 627 d->un.e.member[1].ord = 1; 628 strlcpy(d->un.e.member[1].label.name, AudioNoutput, 629 MAX_AUDIO_DEV_LEN); 630 this->nmixers++; 631 } 632 633 /* pin headphone-boost */ 634 if (w->type == COP_AWTYPE_PIN_COMPLEX && 635 w->d.pin.cap & COP_PINCAP_HEADPHONE) { 636 MIXER_REG_PROLOG; 637 snprintf(d->label.name, sizeof(d->label.name), 638 "%s.boost", w->name); 639 d->type = AUDIO_MIXER_ENUM; 640 d->mixer_class = AZ_CLASS_OUTPUT; 641 m->target = MI_TARGET_PINBOOST; 642 d->un.e.num_mem = 2; 643 d->un.e.member[0].ord = 0; 644 strlcpy(d->un.e.member[0].label.name, AudioNoff, 645 MAX_AUDIO_DEV_LEN); 646 d->un.e.member[1].ord = 1; 647 strlcpy(d->un.e.member[1].label.name, AudioNon, 648 MAX_AUDIO_DEV_LEN); 649 this->nmixers++; 650 } 651 652 if (w->type == COP_AWTYPE_PIN_COMPLEX && 653 w->d.pin.cap & COP_PINCAP_EAPD) { 654 MIXER_REG_PROLOG; 655 snprintf(d->label.name, sizeof(d->label.name), 656 "%s.eapd", w->name); 657 d->type = AUDIO_MIXER_ENUM; 658 d->mixer_class = AZ_CLASS_OUTPUT; 659 m->target = MI_TARGET_EAPD; 660 d->un.e.num_mem = 2; 661 d->un.e.member[0].ord = 0; 662 strlcpy(d->un.e.member[0].label.name, AudioNoff, 663 MAX_AUDIO_DEV_LEN); 664 d->un.e.member[1].ord = 1; 665 strlcpy(d->un.e.member[1].label.name, AudioNon, 666 MAX_AUDIO_DEV_LEN); 667 this->nmixers++; 668 } 669 670 /* volume knob */ 671 if (w->type == COP_AWTYPE_VOLUME_KNOB && 672 w->d.volume.cap & COP_VKCAP_DELTA) { 673 MIXER_REG_PROLOG; 674 strlcpy(d->label.name, w->name, sizeof(d->label.name)); 675 d->type = AUDIO_MIXER_VALUE; 676 d->mixer_class = AZ_CLASS_OUTPUT; 677 m->target = MI_TARGET_VOLUME; 678 d->un.v.num_channels = 1; 679 d->un.v.units.name[0] = 0; 680 d->un.v.delta = 681 MIXER_DELTA(COP_VKCAP_NUMSTEPS(w->d.volume.cap)); 682 this->nmixers++; 683 } 684 } 685 686 /* if the codec has multiple DAC groups, create "inputs.usingdac" */ 687 if (this->dacs.ngroups > 1) { 688 MIXER_REG_PROLOG; 689 strlcpy(d->label.name, "usingdac", sizeof(d->label.name)); 690 d->type = AUDIO_MIXER_ENUM; 691 d->mixer_class = AZ_CLASS_INPUT; 692 m->target = MI_TARGET_DAC; 693 for (i = 0; i < this->dacs.ngroups && i < 32; i++) { 694 d->un.e.member[i].ord = i; 695 for (j = 0; j < this->dacs.groups[i].nconv; j++) { 696 if (j * 2 >= MAX_AUDIO_DEV_LEN) 697 break; 698 snprintf(d->un.e.member[i].label.name + j*2, 699 MAX_AUDIO_DEV_LEN - j*2, "%2.2x", 700 this->dacs.groups[i].conv[j]); 701 } 702 } 703 d->un.e.num_mem = i; 704 this->nmixers++; 705 } 706 707 /* if the codec has multiple ADC groups, create "record.usingadc" */ 708 if (this->adcs.ngroups > 1) { 709 MIXER_REG_PROLOG; 710 strlcpy(d->label.name, "usingadc", sizeof(d->label.name)); 711 d->type = AUDIO_MIXER_ENUM; 712 d->mixer_class = AZ_CLASS_RECORD; 713 m->target = MI_TARGET_ADC; 714 for (i = 0; i < this->adcs.ngroups && i < 32; i++) { 715 d->un.e.member[i].ord = i; 716 for (j = 0; j < this->adcs.groups[i].nconv; j++) { 717 if (j * 2 >= MAX_AUDIO_DEV_LEN) 718 break; 719 snprintf(d->un.e.member[i].label.name + j*2, 720 MAX_AUDIO_DEV_LEN - j*2, "%2.2x", 721 this->adcs.groups[i].conv[j]); 722 } 723 } 724 d->un.e.num_mem = i; 725 this->nmixers++; 726 } 727 728 azalia_generic_mixer_fix_indexes(this); 729 azalia_generic_mixer_default(this); 730 return 0; 731 } 732 733 int 734 azalia_generic_mixer_ensure_capacity(codec_t *this, size_t newsize) 735 { 736 size_t newmax; 737 void *newbuf; 738 739 if (this->maxmixers >= newsize) 740 return 0; 741 newmax = this->maxmixers + 10; 742 if (newmax < newsize) 743 newmax = newsize; 744 newbuf = malloc(sizeof(mixer_item_t) * newmax, M_DEVBUF, M_NOWAIT | M_ZERO); 745 if (newbuf == NULL) { 746 printf("%s: out of memory in %s\n", XNAME(this), __func__); 747 return ENOMEM; 748 } 749 bcopy(this->mixers, newbuf, this->maxmixers * sizeof(mixer_item_t)); 750 free(this->mixers, M_DEVBUF); 751 this->mixers = newbuf; 752 this->maxmixers = newmax; 753 return 0; 754 } 755 756 int 757 azalia_generic_mixer_fix_indexes(codec_t *this) 758 { 759 int i; 760 mixer_devinfo_t *d; 761 762 for (i = 0; i < this->nmixers; i++) { 763 d = &this->mixers[i].devinfo; 764 #ifdef DIAGNOSTIC 765 if (d->index != 0 && d->index != i) 766 printf("%s: index mismatch %d %d\n", __func__, 767 d->index, i); 768 #endif 769 d->index = i; 770 if (d->prev == 0) 771 d->prev = AUDIO_MIXER_LAST; 772 if (d->next == 0) 773 d->next = AUDIO_MIXER_LAST; 774 } 775 return 0; 776 } 777 778 int 779 azalia_generic_mixer_default(codec_t *this) 780 { 781 int i; 782 mixer_item_t *m; 783 /* unmute all */ 784 for (i = 0; i < this->nmixers; i++) { 785 mixer_ctrl_t mc; 786 787 m = &this->mixers[i]; 788 if (!IS_MI_TARGET_INAMP(m->target) && 789 m->target != MI_TARGET_OUTAMP) 790 continue; 791 if (m->devinfo.type != AUDIO_MIXER_ENUM) 792 continue; 793 mc.dev = i; 794 mc.type = AUDIO_MIXER_ENUM; 795 mc.un.ord = 0; 796 azalia_generic_mixer_set(this, m->nid, m->target, &mc); 797 } 798 799 /* 800 * For bidirectional pins, make the default `output' 801 */ 802 for (i = 0; i < this->nmixers; i++) { 803 mixer_ctrl_t mc; 804 805 m = &this->mixers[i]; 806 if (m->target != MI_TARGET_PINDIR) 807 continue; 808 mc.dev = i; 809 mc.type = AUDIO_MIXER_ENUM; 810 mc.un.ord = 1; 811 azalia_generic_mixer_set(this, m->nid, m->target, &mc); 812 } 813 814 /* set unextreme volume */ 815 for (i = 0; i < this->nmixers; i++) { 816 mixer_ctrl_t mc; 817 818 m = &this->mixers[i]; 819 if (!IS_MI_TARGET_INAMP(m->target) && 820 m->target != MI_TARGET_OUTAMP && 821 m->target != MI_TARGET_VOLUME) 822 continue; 823 if (m->devinfo.type != AUDIO_MIXER_VALUE) 824 continue; 825 mc.dev = i; 826 mc.type = AUDIO_MIXER_VALUE; 827 mc.un.value.num_channels = 1; 828 mc.un.value.level[0] = AUDIO_MAX_GAIN / 2; 829 if (m->target != MI_TARGET_VOLUME && 830 WIDGET_CHANNELS(&this->w[m->nid]) == 2) { 831 mc.un.value.num_channels = 2; 832 mc.un.value.level[1] = AUDIO_MAX_GAIN / 2; 833 } 834 azalia_generic_mixer_set(this, m->nid, m->target, &mc); 835 } 836 837 return 0; 838 } 839 840 int 841 azalia_generic_mixer_delete(codec_t *this) 842 { 843 if (this->mixers == NULL) 844 return 0; 845 free(this->mixers, M_DEVBUF); 846 this->mixers = NULL; 847 return 0; 848 } 849 850 /** 851 * @param mc mc->type must be set by the caller before the call 852 */ 853 int 854 azalia_generic_mixer_get(const codec_t *this, nid_t nid, int target, mixer_ctrl_t *mc) 855 { 856 uint32_t result; 857 nid_t n; 858 int err; 859 860 /* inamp mute */ 861 if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) { 862 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 863 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 864 MI_TARGET_INAMP(target), &result); 865 if (err) 866 return err; 867 mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0; 868 } 869 870 /* inamp gain */ 871 else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) { 872 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 873 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 874 MI_TARGET_INAMP(target), &result); 875 if (err) 876 return err; 877 mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this, 878 nid, target, CORB_GAGM_GAIN(result)); 879 if (this->w[nid].type == COP_AWTYPE_AUDIO_SELECTOR || 880 this->w[nid].type == COP_AWTYPE_AUDIO_MIXER) { 881 n = this->w[nid].connections[MI_TARGET_INAMP(target)]; 882 #ifdef AZALIA_DEBUG 883 if (!VALID_WIDGET_NID(n, this)) { 884 DPRINTF(("%s: invalid target: nid=%d nconn=%d index=%d\n", 885 __func__, nid, this->w[nid].nconnections, 886 MI_TARGET_INAMP(target))); 887 return EINVAL; 888 } 889 #endif 890 } else 891 n = nid; 892 mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[n]); 893 if (mc->un.value.num_channels == 2) { 894 err = this->comresp(this, nid, 895 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT | 896 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target), 897 &result); 898 if (err) 899 return err; 900 mc->un.value.level[1] = azalia_generic_mixer_from_device_value 901 (this, nid, target, CORB_GAGM_GAIN(result)); 902 } 903 } 904 905 /* outamp mute */ 906 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) { 907 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 908 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result); 909 if (err) 910 return err; 911 mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0; 912 } 913 914 /* outamp gain */ 915 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) { 916 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 917 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result); 918 if (err) 919 return err; 920 mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this, 921 nid, target, CORB_GAGM_GAIN(result)); 922 mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[nid]); 923 if (mc->un.value.num_channels == 2) { 924 err = this->comresp(this, nid, 925 CORB_GET_AMPLIFIER_GAIN_MUTE, 926 CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT | 0, &result); 927 if (err) 928 return err; 929 mc->un.value.level[1] = azalia_generic_mixer_from_device_value 930 (this, nid, target, CORB_GAGM_GAIN(result)); 931 } 932 } 933 934 /* selection */ 935 else if (target == MI_TARGET_CONNLIST) { 936 err = this->comresp(this, nid, 937 CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result); 938 if (err) 939 return err; 940 result = CORB_CSC_INDEX(result); 941 if (!VALID_WIDGET_NID(this->w[nid].connections[result], this)) 942 mc->un.ord = -1; 943 else 944 mc->un.ord = result; 945 } 946 947 /* pin I/O */ 948 else if (target == MI_TARGET_PINDIR) { 949 err = this->comresp(this, nid, 950 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 951 if (err) 952 return err; 953 mc->un.ord = result & CORB_PWC_OUTPUT ? 1 : 0; 954 } 955 956 /* pin headphone-boost */ 957 else if (target == MI_TARGET_PINBOOST) { 958 err = this->comresp(this, nid, 959 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 960 if (err) 961 return err; 962 mc->un.ord = result & CORB_PWC_HEADPHONE ? 1 : 0; 963 } 964 965 /* DAC group selection */ 966 else if (target == MI_TARGET_DAC) { 967 mc->un.ord = this->dacs.cur; 968 } 969 970 /* ADC selection */ 971 else if (target == MI_TARGET_ADC) { 972 mc->un.ord = this->adcs.cur; 973 } 974 975 /* Volume knob */ 976 else if (target == MI_TARGET_VOLUME) { 977 err = this->comresp(this, nid, CORB_GET_VOLUME_KNOB, 978 0, &result); 979 if (err) 980 return err; 981 mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this, 982 nid, target, CORB_VKNOB_VOLUME(result)); 983 mc->un.value.num_channels = 1; 984 } 985 986 /* EAPD */ 987 else if (target == MI_TARGET_EAPD) { 988 err = this->comresp(this, nid, 989 CORB_GET_EAPD_BTL_ENABLE, 0, &result); 990 if (err) 991 return err; 992 mc->un.ord = result & CORB_EAPD_EAPD ? 1 : 0; 993 } 994 995 else { 996 printf("%s: internal error in %s: target=%x\n", 997 XNAME(this), __func__, target); 998 return -1; 999 } 1000 return 0; 1001 } 1002 1003 int 1004 azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc) 1005 { 1006 uint32_t result, value; 1007 int err; 1008 1009 /* inamp mute */ 1010 if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) { 1011 /* We have to set stereo mute separately to keep each gain value. */ 1012 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1013 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 1014 MI_TARGET_INAMP(target), &result); 1015 if (err) 1016 return err; 1017 value = CORB_AGM_INPUT | CORB_AGM_LEFT | 1018 (target << CORB_AGM_INDEX_SHIFT) | 1019 CORB_GAGM_GAIN(result); 1020 if (mc->un.ord) 1021 value |= CORB_AGM_MUTE; 1022 err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE, 1023 value, &result); 1024 if (err) 1025 return err; 1026 if (WIDGET_CHANNELS(&this->w[nid]) == 2) { 1027 err = this->comresp(this, nid, 1028 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT | 1029 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target), 1030 &result); 1031 if (err) 1032 return err; 1033 value = CORB_AGM_INPUT | CORB_AGM_RIGHT | 1034 (target << CORB_AGM_INDEX_SHIFT) | 1035 CORB_GAGM_GAIN(result); 1036 if (mc->un.ord) 1037 value |= CORB_AGM_MUTE; 1038 err = this->comresp(this, nid, 1039 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 1040 if (err) 1041 return err; 1042 } 1043 } 1044 1045 /* inamp gain */ 1046 else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) { 1047 if (mc->un.value.num_channels < 1) 1048 return EINVAL; 1049 if (!azalia_generic_mixer_validate_value(this, nid, target, 1050 mc->un.value.level[0])) 1051 return EINVAL; 1052 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1053 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 1054 MI_TARGET_INAMP(target), &result); 1055 if (err) 1056 return err; 1057 value = azalia_generic_mixer_to_device_value(this, nid, target, 1058 mc->un.value.level[0]); 1059 value = CORB_AGM_INPUT | CORB_AGM_LEFT | 1060 (target << CORB_AGM_INDEX_SHIFT) | 1061 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) | 1062 (value & CORB_AGM_GAIN_MASK); 1063 err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE, 1064 value, &result); 1065 if (err) 1066 return err; 1067 if (mc->un.value.num_channels >= 2 && 1068 WIDGET_CHANNELS(&this->w[nid]) == 2) { 1069 if (!azalia_generic_mixer_validate_value(this, nid, target, 1070 mc->un.value.level[1])) 1071 return EINVAL; 1072 err = this->comresp(this, nid, 1073 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT | 1074 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target), 1075 &result); 1076 if (err) 1077 return err; 1078 value = azalia_generic_mixer_to_device_value(this, nid, target, 1079 mc->un.value.level[1]); 1080 value = CORB_AGM_INPUT | CORB_AGM_RIGHT | 1081 (target << CORB_AGM_INDEX_SHIFT) | 1082 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) | 1083 (value & CORB_AGM_GAIN_MASK); 1084 err = this->comresp(this, nid, 1085 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 1086 if (err) 1087 return err; 1088 } 1089 } 1090 1091 /* outamp mute */ 1092 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) { 1093 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1094 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result); 1095 if (err) 1096 return err; 1097 value = CORB_AGM_OUTPUT | CORB_AGM_LEFT | CORB_GAGM_GAIN(result); 1098 if (mc->un.ord) 1099 value |= CORB_AGM_MUTE; 1100 err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE, 1101 value, &result); 1102 if (err) 1103 return err; 1104 if (WIDGET_CHANNELS(&this->w[nid]) == 2) { 1105 err = this->comresp(this, nid, 1106 CORB_GET_AMPLIFIER_GAIN_MUTE, 1107 CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT, &result); 1108 if (err) 1109 return err; 1110 value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT | 1111 CORB_GAGM_GAIN(result); 1112 if (mc->un.ord) 1113 value |= CORB_AGM_MUTE; 1114 err = this->comresp(this, nid, 1115 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 1116 if (err) 1117 return err; 1118 } 1119 } 1120 1121 /* outamp gain */ 1122 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) { 1123 if (mc->un.value.num_channels < 1) 1124 return EINVAL; 1125 if (!azalia_generic_mixer_validate_value(this, nid, target, 1126 mc->un.value.level[0])) 1127 return EINVAL; 1128 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1129 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result); 1130 if (err) 1131 return err; 1132 value = azalia_generic_mixer_to_device_value(this, nid, target, 1133 mc->un.value.level[0]); 1134 value = CORB_AGM_OUTPUT | CORB_AGM_LEFT | 1135 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) | 1136 (value & CORB_AGM_GAIN_MASK); 1137 err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE, 1138 value, &result); 1139 if (err) 1140 return err; 1141 if (mc->un.value.num_channels >= 2 && 1142 WIDGET_CHANNELS(&this->w[nid]) == 2) { 1143 if (!azalia_generic_mixer_validate_value(this, nid, target, 1144 mc->un.value.level[1])) 1145 return EINVAL; 1146 err = this->comresp(this, nid, 1147 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_OUTPUT | 1148 CORB_GAGM_RIGHT, &result); 1149 if (err) 1150 return err; 1151 value = azalia_generic_mixer_to_device_value(this, nid, target, 1152 mc->un.value.level[1]); 1153 value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT | 1154 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) | 1155 (value & CORB_AGM_GAIN_MASK); 1156 err = this->comresp(this, nid, 1157 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result); 1158 if (err) 1159 return err; 1160 } 1161 } 1162 1163 /* selection */ 1164 else if (target == MI_TARGET_CONNLIST) { 1165 if (mc->un.ord < 0 || 1166 mc->un.ord >= this->w[nid].nconnections || 1167 !VALID_WIDGET_NID(this->w[nid].connections[mc->un.ord], this)) 1168 return EINVAL; 1169 err = this->comresp(this, nid, 1170 CORB_SET_CONNECTION_SELECT_CONTROL, mc->un.ord, &result); 1171 if (err) 1172 return err; 1173 } 1174 1175 /* pin I/O */ 1176 else if (target == MI_TARGET_PINDIR) { 1177 if (mc->un.ord >= 2) 1178 return EINVAL; 1179 err = this->comresp(this, nid, 1180 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 1181 if (err) 1182 return err; 1183 if (mc->un.ord == 0) { 1184 result &= ~CORB_PWC_OUTPUT; 1185 result |= CORB_PWC_INPUT; 1186 } else { 1187 result &= ~CORB_PWC_INPUT; 1188 result |= CORB_PWC_OUTPUT; 1189 } 1190 err = this->comresp(this, nid, 1191 CORB_SET_PIN_WIDGET_CONTROL, result, &result); 1192 if (err) 1193 return err; 1194 } 1195 1196 /* pin headphone-boost */ 1197 else if (target == MI_TARGET_PINBOOST) { 1198 if (mc->un.ord >= 2) 1199 return EINVAL; 1200 err = this->comresp(this, nid, 1201 CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 1202 if (err) 1203 return err; 1204 if (mc->un.ord == 0) { 1205 result &= ~CORB_PWC_HEADPHONE; 1206 } else { 1207 result |= CORB_PWC_HEADPHONE; 1208 } 1209 err = this->comresp(this, nid, 1210 CORB_SET_PIN_WIDGET_CONTROL, result, &result); 1211 if (err) 1212 return err; 1213 } 1214 1215 /* DAC group selection */ 1216 else if (target == MI_TARGET_DAC) { 1217 if (this->running) 1218 return EBUSY; 1219 if (mc->un.ord >= this->dacs.ngroups) 1220 return EINVAL; 1221 return azalia_codec_construct_format(this, 1222 mc->un.ord, this->adcs.cur); 1223 } 1224 1225 /* ADC selection */ 1226 else if (target == MI_TARGET_ADC) { 1227 if (this->running) 1228 return EBUSY; 1229 if (mc->un.ord >= this->adcs.ngroups) 1230 return EINVAL; 1231 return azalia_codec_construct_format(this, 1232 this->dacs.cur, mc->un.ord); 1233 } 1234 1235 /* Volume knob */ 1236 else if (target == MI_TARGET_VOLUME) { 1237 if (mc->un.value.num_channels != 1) 1238 return EINVAL; 1239 if (!azalia_generic_mixer_validate_value(this, nid, 1240 target, mc->un.value.level[0])) 1241 return EINVAL; 1242 value = azalia_generic_mixer_to_device_value(this, nid, target, 1243 mc->un.value.level[0]) | CORB_VKNOB_DIRECT; 1244 err = this->comresp(this, nid, CORB_SET_VOLUME_KNOB, 1245 value, &result); 1246 if (err) 1247 return err; 1248 } 1249 1250 /* EAPD */ 1251 else if (target == MI_TARGET_EAPD) { 1252 if (mc->un.ord >= 2) 1253 return EINVAL; 1254 err = this->comresp(this, nid, 1255 CORB_GET_EAPD_BTL_ENABLE, 0, &result); 1256 if (err) 1257 return err; 1258 result &= 0xff; 1259 if (mc->un.ord == 0) { 1260 result &= ~CORB_EAPD_EAPD; 1261 } else { 1262 result |= CORB_EAPD_EAPD; 1263 } 1264 err = this->comresp(this, nid, 1265 CORB_SET_EAPD_BTL_ENABLE, result, &result); 1266 if (err) 1267 return err; 1268 } 1269 1270 else { 1271 printf("%s: internal error in %s: target=%x\n", 1272 XNAME(this), __func__, target); 1273 return -1; 1274 } 1275 return 0; 1276 } 1277 1278 int 1279 azalia_generic_mixer_pinctrl(codec_t *this, nid_t nid, uint32_t value) 1280 { 1281 int err; 1282 uint32_t result; 1283 1284 err = this->comresp(this, nid, CORB_GET_PIN_WIDGET_CONTROL, 0, &result); 1285 if (err) 1286 return err; 1287 result &= ~(CORB_PWC_OUTPUT | CORB_PWC_INPUT); 1288 result |= value & (CORB_PWC_OUTPUT | CORB_PWC_INPUT); 1289 return this->comresp(this, nid, 1290 CORB_SET_PIN_WIDGET_CONTROL, result, NULL); 1291 } 1292 1293 u_char 1294 azalia_generic_mixer_from_device_value(const codec_t *this, nid_t nid, int target, 1295 uint32_t dv) 1296 { 1297 #ifdef MAX_VOLUME_255 1298 uint32_t dmax; 1299 1300 if (IS_MI_TARGET_INAMP(target)) 1301 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); 1302 else if (target == MI_TARGET_OUTAMP) 1303 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); 1304 else if (target == MI_TARGET_VOLUME) 1305 dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap); 1306 else { 1307 printf("unknown target: %d\n", target); 1308 dmax = 255; 1309 } 1310 if (dv <= 0 || dmax == 0) 1311 return AUDIO_MIN_GAIN; 1312 if (dv >= dmax) 1313 return AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax; 1314 return dv * (AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax) / dmax; 1315 #else 1316 return dv; 1317 #endif 1318 } 1319 1320 uint32_t 1321 azalia_generic_mixer_to_device_value(const codec_t *this, nid_t nid, int target, 1322 u_char uv) 1323 { 1324 #ifdef MAX_VOLUME_255 1325 uint32_t dmax; 1326 1327 if (IS_MI_TARGET_INAMP(target)) 1328 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); 1329 else if (target == MI_TARGET_OUTAMP) 1330 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); 1331 else if (target == MI_TARGET_VOLUME) 1332 dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap); 1333 else { 1334 printf("unknown target: %d\n", target); 1335 dmax = 255; 1336 } 1337 if (uv <= AUDIO_MIN_GAIN || dmax == 0) 1338 return 0; 1339 if (uv >= AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax) 1340 return dmax; 1341 return uv * dmax / (AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax); 1342 #else 1343 return uv; 1344 #endif 1345 } 1346 1347 uint32_t 1348 azalia_generic_mixer_max(const codec_t *this, nid_t nid, int target) 1349 { 1350 #ifdef MAX_VOLUME_255 1351 return AUDIO_MAX_GAIN; 1352 #else 1353 uint32_t dmax; 1354 1355 if (IS_MI_TARGET_INAMP(target)) 1356 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap); 1357 else if (target == MI_TARGET_OUTAMP) 1358 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); 1359 else if (target == MI_TARGET_VOLUME) 1360 dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap); 1361 return dmax; 1362 #endif 1363 } 1364 1365 boolean_t 1366 azalia_generic_mixer_validate_value(const codec_t *this, nid_t nid, int target, 1367 u_char uv) 1368 { 1369 #ifdef MAX_VOLUME_255 1370 return TRUE; 1371 #else 1372 return uv <= generic_mixer_max(this, nid, target); 1373 #endif 1374 } 1375 1376 int 1377 azalia_generic_set_port(codec_t *this, mixer_ctrl_t *mc) 1378 { 1379 const mixer_item_t *m; 1380 1381 if (mc->dev >= this->nmixers) 1382 return ENXIO; 1383 m = &this->mixers[mc->dev]; 1384 if (mc->type != m->devinfo.type) 1385 return EINVAL; 1386 if (mc->type == AUDIO_MIXER_CLASS) 1387 return 0; /* nothing to do */ 1388 return azalia_generic_mixer_set(this, m->nid, m->target, mc); 1389 } 1390 1391 int 1392 azalia_generic_get_port(codec_t *this, mixer_ctrl_t *mc) 1393 { 1394 const mixer_item_t *m; 1395 1396 if (mc->dev >= this->nmixers) 1397 return ENXIO; 1398 m = &this->mixers[mc->dev]; 1399 mc->type = m->devinfo.type; 1400 if (mc->type == AUDIO_MIXER_CLASS) 1401 return 0; /* nothing to do */ 1402 return azalia_generic_mixer_get(this, m->nid, m->target, mc); 1403 } 1404 1405 1406 /* ---------------------------------------------------------------- 1407 * Realtek ALC260 1408 * 1409 * Fujitsu LOOX T70M/T 1410 * Internal Speaker: 0x10 1411 * Front Headphone: 0x14 1412 * Front mic: 0x12 1413 * ---------------------------------------------------------------- */ 1414 1415 static const mixer_item_t alc260_mixer_items[] = { 1416 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 1417 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 1418 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 1419 1420 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 1421 0, 0, .un.v={{""}, 2, 3}}, 0x08, MI_TARGET_OUTAMP}, /* and 0x09, 0x0a(mono) */ 1422 {{0, {AudioNmaster".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1423 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_OUTAMP}, 1424 {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1425 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_OUTAMP}, 1426 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1427 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_PINBOOST}, 1428 {{0, {AudioNmono".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1429 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_OUTAMP}, 1430 {{0, {"mic1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1431 0, 0, ENUM_OFFON}, 0x12, MI_TARGET_OUTAMP}, 1432 {{0, {"mic1"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1433 0, 0, ENUM_IO}, 0x12, MI_TARGET_PINDIR}, 1434 {{0, {"mic2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1435 0, 0, ENUM_OFFON}, 0x13, MI_TARGET_OUTAMP}, 1436 {{0, {"mic2"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1437 0, 0, ENUM_IO}, 0x13, MI_TARGET_PINDIR}, 1438 {{0, {"line1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1439 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP}, 1440 {{0, {"line1"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1441 0, 0, ENUM_IO}, 0x14, MI_TARGET_PINDIR}, 1442 {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1443 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP}, 1444 {{0, {"line2"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1445 0, 0, ENUM_IO}, 0x15, MI_TARGET_PINDIR}, 1446 1447 {{0, {AudioNdac".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1448 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)}, /* and 0x09, 0x0a(mono) */ 1449 {{0, {"mic1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1450 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)}, 1451 {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1452 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)}, 1453 {{0, {"mic2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1454 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(1)}, 1455 {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1456 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(1)}, 1457 {{0, {"line1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1458 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(2)}, 1459 {{0, {"line1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1460 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(2)}, 1461 {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1462 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(3)}, 1463 {{0, {"line2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1464 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(3)}, 1465 {{0, {AudioNcd".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1466 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(4)}, 1467 {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1468 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)}, 1469 {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1470 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(5)}, 1471 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1472 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)}, 1473 1474 {{0, {"adc04.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1475 .un.e={5, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{"line1"}, 2}, 1476 {{"line2"}, 3}, {{AudioNcd}, 4}}}}, 1477 0x04, MI_TARGET_CONNLIST}, 1478 {{0, {"adc04.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1479 ENUM_OFFON}, 0x04, MI_TARGET_INAMP(0)}, 1480 {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, 1481 .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)}, 1482 {{0, {"adc05.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1483 .un.e={6, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{"line1"}, 2}, 1484 {{"line2"}, 3}, {{AudioNcd}, 4}, {{AudioNmixerout}, 5}}}}, 1485 0x05, MI_TARGET_CONNLIST}, 1486 {{0, {"adc05.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1487 ENUM_OFFON}, 0x05, MI_TARGET_INAMP(0)}, 1488 {{0, {"adc05"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, 1489 .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)}, 1490 1491 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, 1492 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC}, 1493 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1494 .un.e={3, {{{"adc04"}, 0}, {{"adc05"}, 1}, {{"digital"}, 2}}}}, 0, MI_TARGET_ADC}, 1495 }; 1496 1497 static const mixer_item_t alc260_loox_mixer_items[] = { 1498 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 1499 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 1500 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 1501 1502 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 1503 0, 0, .un.v={{""}, 2, 3}}, 0x08, MI_TARGET_OUTAMP}, /* and 0x09, 0x0a(mono) */ 1504 {{0, {AudioNmaster".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1505 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_OUTAMP}, 1506 {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1507 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_PINBOOST}, 1508 {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1509 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP}, 1510 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1511 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST}, 1512 1513 {{0, {AudioNdac".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1514 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)}, /* and 0x09, 0x0a(mono) */ 1515 {{0, {AudioNmicrophone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1516 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)}, 1517 {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1518 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)}, 1519 {{0, {AudioNcd".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1520 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(4)}, 1521 {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1522 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)}, 1523 {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1524 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(5)}, 1525 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1526 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)}, 1527 1528 {{0, {"adc04.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1529 .un.e={2, {{{AudioNmicrophone}, 0}, {{AudioNcd}, 4}}}}, 0x04, MI_TARGET_CONNLIST}, 1530 {{0, {"adc04.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1531 ENUM_OFFON}, 0x04, MI_TARGET_INAMP(0)}, 1532 {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, 1533 .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)}, 1534 {{0, {"adc05.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1535 .un.e={3, {{{AudioNmicrophone}, 0}, {{AudioNcd}, 4}, {{AudioNmixerout}, 5}}}}, 1536 0x05, MI_TARGET_CONNLIST}, 1537 {{0, {"adc05.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1538 ENUM_OFFON}, 0x05, MI_TARGET_INAMP(0)}, 1539 {{0, {"adc05"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, 1540 .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)}, 1541 1542 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, 1543 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC}, 1544 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1545 .un.e={3, {{{"adc04"}, 0}, {{"adc05"}, 1}, {{"digital"}, 2}}}}, 0, MI_TARGET_ADC}, 1546 }; 1547 1548 int 1549 azalia_alc260_mixer_init(codec_t *this) 1550 { 1551 const mixer_item_t *mi; 1552 mixer_ctrl_t mc; 1553 1554 switch (this->subid) { 1555 case ALC260_FUJITSU_ID: 1556 this->nmixers = sizeof(alc260_loox_mixer_items) / sizeof(mixer_item_t); 1557 mi = alc260_loox_mixer_items; 1558 break; 1559 default: 1560 this->nmixers = sizeof(alc260_mixer_items) / sizeof(mixer_item_t); 1561 mi = alc260_mixer_items; 1562 } 1563 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, 1564 M_DEVBUF, M_NOWAIT | M_ZERO); 1565 if (this->mixers == NULL) { 1566 printf("%s: out of memory in %s\n", XNAME(this), __func__); 1567 return ENOMEM; 1568 } 1569 memcpy(this->mixers, mi, sizeof(mixer_item_t) * this->nmixers); 1570 azalia_generic_mixer_fix_indexes(this); 1571 azalia_generic_mixer_default(this); 1572 1573 mc.dev = -1; /* no need for generic_mixer_set() */ 1574 mc.type = AUDIO_MIXER_ENUM; 1575 mc.un.ord = 1; /* pindir: output */ 1576 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); /* lineout */ 1577 azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc); /* headphones */ 1578 mc.un.ord = 0; /* pindir: input */ 1579 azalia_generic_mixer_set(this, 0x12, MI_TARGET_PINDIR, &mc); /* mic1 */ 1580 azalia_generic_mixer_set(this, 0x13, MI_TARGET_PINDIR, &mc); /* mic2 */ 1581 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc); /* line1 */ 1582 azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc); /* line2 */ 1583 mc.un.ord = 0; /* mute: off */ 1584 azalia_generic_mixer_set(this, 0x08, MI_TARGET_INAMP(0), &mc); 1585 azalia_generic_mixer_set(this, 0x08, MI_TARGET_INAMP(1), &mc); 1586 azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(0), &mc); 1587 azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(1), &mc); 1588 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(0), &mc); 1589 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(1), &mc); 1590 if (this->subid == ALC260_FUJITSU_ID) { 1591 mc.un.ord = 1; /* pindir: output */ 1592 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc); /* line1 */ 1593 mc.un.ord = 4; /* connlist: cd */ 1594 azalia_generic_mixer_set(this, 0x05, MI_TARGET_CONNLIST, &mc); 1595 } 1596 return 0; 1597 } 1598 1599 int 1600 azalia_alc260_init_dacgroup(codec_t *this) 1601 { 1602 static const convgroupset_t dacs = { 1603 -1, 2, 1604 {{1, {0x02}}, /* analog 2ch */ 1605 {1, {0x03}}}}; /* digital */ 1606 static const convgroupset_t adcs = { 1607 -1, 3, 1608 {{1, {0x04}}, /* analog 2ch */ 1609 {1, {0x05}}, /* analog 2ch */ 1610 {1, {0x06}}}}; /* digital */ 1611 1612 this->dacs = dacs; 1613 this->adcs = adcs; 1614 return 0; 1615 } 1616 1617 int 1618 azalia_alc260_set_port(codec_t *this, mixer_ctrl_t *mc) 1619 { 1620 const mixer_item_t *m; 1621 mixer_ctrl_t mc2; 1622 int err; 1623 1624 if (mc->dev >= this->nmixers) 1625 return ENXIO; 1626 m = &this->mixers[mc->dev]; 1627 if (mc->type != m->devinfo.type) 1628 return EINVAL; 1629 if (mc->type == AUDIO_MIXER_CLASS) 1630 return 0; 1631 if (m->nid == 0x08 && m->target == MI_TARGET_OUTAMP) { 1632 DPRINTF(("%s: hook for outputs.master\n", __func__)); 1633 err = azalia_generic_mixer_set(this, m->nid, m->target, mc); 1634 if (!err) { 1635 azalia_generic_mixer_set(this, 0x09, m->target, mc); 1636 mc2 = *mc; 1637 mc2.un.value.num_channels = 1; 1638 mc2.un.value.level[0] = (mc2.un.value.level[0] 1639 + mc2.un.value.level[1]) / 2; 1640 azalia_generic_mixer_set(this, 0x0a, m->target, &mc2); 1641 } 1642 return err; 1643 } else if (m->nid == 0x08 && m->target == MI_TARGET_INAMP(0)) { 1644 DPRINTF(("%s: hook for inputs.dac.mute\n", __func__)); 1645 err = azalia_generic_mixer_set(this, m->nid, m->target, mc); 1646 if (!err) { 1647 azalia_generic_mixer_set(this, 0x09, m->target, mc); 1648 azalia_generic_mixer_set(this, 0x0a, m->target, mc); 1649 } 1650 return err; 1651 } else if (m->nid == 0x04 && 1652 m->target == MI_TARGET_CONNLIST && 1653 m->devinfo.un.e.num_mem == 2) { 1654 if (1 <= mc->un.ord && mc->un.ord <= 3) 1655 return EINVAL; 1656 } else if (m->nid == 0x05 && 1657 m->target == MI_TARGET_CONNLIST && 1658 m->devinfo.un.e.num_mem == 3) { 1659 if (1 <= mc->un.ord && mc->un.ord <= 3) 1660 return EINVAL; 1661 } 1662 return azalia_generic_mixer_set(this, m->nid, m->target, mc); 1663 } 1664 1665 /* ---------------------------------------------------------------- 1666 * Realtek ALC880 1667 * ---------------------------------------------------------------- */ 1668 1669 int 1670 azalia_alc880_init_dacgroup(codec_t *this) 1671 { 1672 static const convgroupset_t dacs = { 1673 -1, 2, 1674 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */ 1675 {1, {0x06}}}}; /* digital */ 1676 static const convgroupset_t adcs = { 1677 -1, 2, 1678 {{2, {0x08, 0x09}}, /* analog 4ch */ 1679 {1, {0x0a}}}}; /* digital */ 1680 1681 this->dacs = dacs; 1682 this->adcs = adcs; 1683 return 0; 1684 } 1685 1686 /* ---------------------------------------------------------------- 1687 * Realtek ALC882 1688 * ---------------------------------------------------------------- */ 1689 1690 static const mixer_item_t alc882_mixer_items[] = { 1691 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 1692 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 1693 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 1694 1695 /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17 */ 1696 {{0, {"mic1."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1697 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(0)}, 1698 {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1699 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(0)}, 1700 {{0, {"mic2."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1701 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(1)}, 1702 {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1703 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(1)}, 1704 {{0, {AudioNline"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1705 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(2)}, 1706 {{0, {AudioNline}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1707 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(2)}, 1708 {{0, {AudioNcd"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1709 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(4)}, 1710 {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1711 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(4)}, 1712 {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1713 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(5)}, 1714 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1715 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(5)}, 1716 1717 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 1718 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0c, MI_TARGET_OUTAMP}, 1719 {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1720 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP}, 1721 {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1722 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST}, 1723 {{0, {AudioNheadphone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1724 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_OUTAMP}, 1725 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1726 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_PINBOOST}, 1727 {{0, {AzaliaNfront".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1728 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(0)}, 1729 {{0, {AzaliaNfront".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1730 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(1)}, 1731 1732 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 1733 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0d, MI_TARGET_OUTAMP}, 1734 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1735 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP}, 1736 {{0, {AudioNsurround".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1737 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_PINBOOST}, 1738 {{0, {AudioNsurround".dac.mut"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1739 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(0)}, 1740 {{0, {AudioNsurround".mixer.m"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1741 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(1)}, 1742 1743 {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 1744 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0e, MI_TARGET_OUTAMP}, 1745 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1746 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_OUTAMP}, 1747 {{0, {AzaliaNclfe".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1748 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_PINBOOST}, 1749 {{0, {AzaliaNclfe".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1750 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(0)}, 1751 {{0, {AzaliaNclfe".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1752 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(1)}, 1753 1754 {{0, {AzaliaNside}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 1755 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0f, MI_TARGET_OUTAMP}, 1756 {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1757 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_OUTAMP}, 1758 {{0, {AzaliaNside".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1759 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_PINBOOST}, 1760 {{0, {AzaliaNside".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1761 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(0)}, 1762 {{0, {AzaliaNside".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1763 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(1)}, 1764 1765 /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17,0xb */ 1766 #define ALC882_MIC1 0x001 1767 #define ALC882_MIC2 0x002 1768 #define ALC882_LINE 0x004 1769 #define ALC882_CD 0x010 1770 #define ALC882_BEEP 0x020 1771 #define ALC882_MIX 0x400 1772 #define ALC882_MASK 0x437 1773 {{0, {AzaliaNfront"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 1774 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)}, 1775 {{0, {AzaliaNfront}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 1776 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x07, MI_TARGET_INAMP(0)}, 1777 {{0, {AzaliaNfront"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD, 1778 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2}, 1779 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD}, 1780 {{AudioNspeaker}, ALC882_BEEP}, 1781 {{AudioNmixerout}, ALC882_MIX}}}}, 0x24, -1}, 1782 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 1783 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)}, 1784 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 1785 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x08, MI_TARGET_INAMP(0)}, 1786 {{0, {AudioNsurround"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD, 1787 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2}, 1788 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD}, 1789 {{AudioNspeaker}, ALC882_BEEP}, 1790 {{AudioNmixerout}, ALC882_MIX}}}}, 0x23, -1}, 1791 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 1792 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)}, 1793 {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 1794 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x09, MI_TARGET_INAMP(0)}, 1795 {{0, {AzaliaNclfe"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD, 1796 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2}, 1797 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD}, 1798 {{AudioNspeaker}, ALC882_BEEP}, 1799 {{AudioNmixerout}, ALC882_MIX}}}}, 0x22, -1}, 1800 1801 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, 1802 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC}, 1803 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 1804 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_ADC}, 1805 }; 1806 1807 int 1808 azalia_alc882_mixer_init(codec_t *this) 1809 { 1810 mixer_ctrl_t mc; 1811 1812 this->nmixers = sizeof(alc882_mixer_items) / sizeof(mixer_item_t); 1813 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, 1814 M_DEVBUF, M_NOWAIT | M_ZERO); 1815 if (this->mixers == NULL) { 1816 printf("%s: out of memory in %s\n", XNAME(this), __func__); 1817 return ENOMEM; 1818 } 1819 memcpy(this->mixers, alc882_mixer_items, 1820 sizeof(mixer_item_t) * this->nmixers); 1821 azalia_generic_mixer_fix_indexes(this); 1822 azalia_generic_mixer_default(this); 1823 1824 mc.dev = -1; 1825 mc.type = AUDIO_MIXER_ENUM; 1826 mc.un.ord = 1; /* pindir: output */ 1827 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc); 1828 azalia_generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR, &mc); 1829 azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc); 1830 azalia_generic_mixer_set(this, 0x16, MI_TARGET_PINDIR, &mc); 1831 azalia_generic_mixer_set(this, 0x17, MI_TARGET_PINDIR, &mc); 1832 mc.un.ord = 0; /* [0] 0x0c */ 1833 azalia_generic_mixer_set(this, 0x14, MI_TARGET_CONNLIST, &mc); 1834 azalia_generic_mixer_set(this, 0x1b, MI_TARGET_CONNLIST, &mc); 1835 mc.un.ord = 1; /* [1] 0x0d */ 1836 azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc); 1837 mc.un.ord = 2; /* [2] 0x0e */ 1838 azalia_generic_mixer_set(this, 0x16, MI_TARGET_CONNLIST, &mc); 1839 mc.un.ord = 2; /* [3] 0x0fb */ 1840 azalia_generic_mixer_set(this, 0x17, MI_TARGET_CONNLIST, &mc); 1841 1842 mc.un.ord = 0; /* pindir: input */ 1843 azalia_generic_mixer_set(this, 0x18, MI_TARGET_PINDIR, &mc); 1844 azalia_generic_mixer_set(this, 0x19, MI_TARGET_PINDIR, &mc); 1845 azalia_generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR, &mc); 1846 /* XXX: inamp for 18/19/1a */ 1847 1848 mc.un.ord = 0; /* unmute */ 1849 azalia_generic_mixer_set(this, 0x24, MI_TARGET_INAMP(0), &mc); 1850 azalia_generic_mixer_set(this, 0x23, MI_TARGET_INAMP(1), &mc); 1851 azalia_generic_mixer_set(this, 0x22, MI_TARGET_INAMP(2), &mc); 1852 return 0; 1853 } 1854 1855 int 1856 azalia_alc882_init_dacgroup(codec_t *this) 1857 { 1858 #if 0 1859 static const convgroupset_t dacs = { 1860 -1, 3, 1861 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */ 1862 {1, {0x06}}, /* digital */ 1863 {1, {0x25}}}}; /* another analog */ 1864 #else 1865 static const convgroupset_t dacs = { 1866 -1, 2, 1867 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */ 1868 {1, {0x06}}}}; /* digital */ 1869 #endif 1870 static const convgroupset_t adcs = { 1871 -1, 2, 1872 {{3, {0x07, 0x08, 0x09}}, /* analog 6ch */ 1873 {1, {0x0a}}}}; /* digital */ 1874 1875 this->dacs = dacs; 1876 this->adcs = adcs; 1877 return 0; 1878 } 1879 1880 int 1881 azalia_alc882_set_port(codec_t *this, mixer_ctrl_t *mc) 1882 { 1883 const mixer_item_t *m; 1884 mixer_ctrl_t mc2; 1885 uint32_t mask, bit; 1886 int i, err; 1887 1888 if (mc->dev >= this->nmixers) 1889 return ENXIO; 1890 m = &this->mixers[mc->dev]; 1891 if (mc->type != m->devinfo.type) 1892 return EINVAL; 1893 if (mc->type == AUDIO_MIXER_CLASS) 1894 return 0; 1895 if ((m->nid == 0x22 || m->nid == 0x23 || m->nid == 0x24) 1896 && m->target == -1) { 1897 DPRINTF(("%s: hook for record.*.source\n", __func__)); 1898 mc2.dev = -1; 1899 mc2.type = AUDIO_MIXER_ENUM; 1900 bit = 1; 1901 mask = mc->un.mask & ALC882_MASK; 1902 for (i = 0; i < this->w[m->nid].nconnections && i < 32; i++) { 1903 mc2.un.ord = (mask & bit) ? 0 : 1; 1904 err = azalia_generic_mixer_set(this, m->nid, 1905 MI_TARGET_INAMP(i), &mc2); 1906 if (err) 1907 return err; 1908 bit = bit << 1; 1909 } 1910 return 0; 1911 } 1912 return azalia_generic_mixer_set(this, m->nid, m->target, mc); 1913 } 1914 1915 int 1916 azalia_alc882_get_port(codec_t *this, mixer_ctrl_t *mc) 1917 { 1918 const mixer_item_t *m; 1919 uint32_t mask, bit, result; 1920 int i, err; 1921 1922 if (mc->dev >= this->nmixers) 1923 return ENXIO; 1924 m = &this->mixers[mc->dev]; 1925 mc->type = m->devinfo.type; 1926 if (mc->type == AUDIO_MIXER_CLASS) 1927 return 0; 1928 if ((m->nid == 0x22 || m->nid == 0x23 || m->nid == 0x24) 1929 && m->target == -1) { 1930 DPRINTF(("%s: hook for record.*.source\n", __func__)); 1931 mask = 0; 1932 bit = 1; 1933 for (i = 0; i < this->w[m->nid].nconnections && i < 32; i++) { 1934 err = this->comresp(this, m->nid, CORB_GET_AMPLIFIER_GAIN_MUTE, 1935 CORB_GAGM_INPUT | CORB_GAGM_LEFT | 1936 i, &result); 1937 if (err) 1938 return err; 1939 if ((result & CORB_GAGM_MUTE) == 0) 1940 mask |= bit; 1941 bit = bit << 1; 1942 } 1943 mc->un.mask = mask & ALC882_MASK; 1944 return 0; 1945 } 1946 return azalia_generic_mixer_get(this, m->nid, m->target, mc); 1947 } 1948 1949 /* ---------------------------------------------------------------- 1950 * Realtek ALC883 1951 * ALC882 without adc07 and mix24. 1952 * ---------------------------------------------------------------- */ 1953 1954 int 1955 azalia_alc883_init_dacgroup(codec_t *this) 1956 { 1957 static const convgroupset_t dacs = { 1958 -1, 2, 1959 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */ 1960 {1, {0x06}}}}; /* digital */ 1961 1962 static const convgroupset_t adcs = { 1963 -1, 2, 1964 {{2, {0x08, 0x09}}, /* analog 4ch */ 1965 {1, {0x0a}}}}; /* digital */ 1966 1967 this->dacs = dacs; 1968 this->adcs = adcs; 1969 return 0; 1970 } 1971 1972 static const mixer_item_t alc883_mixer_items[] = { 1973 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 1974 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 1975 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 1976 1977 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 1978 4, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0c, MI_TARGET_OUTAMP}, 1979 {{0, {AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 1980 0, 3, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP}, 1981 1982 /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17 */ 1983 {{0, {AudioNmicrophone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1984 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(0)}, 1985 {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1986 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(0)}, 1987 {{0, {"mic2."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1988 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(1)}, 1989 {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1990 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(1)}, 1991 {{0, {AudioNline"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1992 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(2)}, 1993 {{0, {AudioNline}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1994 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(2)}, 1995 {{0, {AudioNcd"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 1996 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(4)}, 1997 {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 1998 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(4)}, 1999 {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2000 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(5)}, 2001 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 2002 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(5)}, 2003 {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2004 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST}, 2005 {{0, {AudioNheadphone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2006 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_OUTAMP}, 2007 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2008 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_PINBOOST}, 2009 {{0, {AzaliaNfront".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2010 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(0)}, 2011 {{0, {AzaliaNfront".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2012 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(1)}, 2013 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2014 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0d, MI_TARGET_OUTAMP}, 2015 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2016 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP}, 2017 {{0, {AudioNsurround".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2018 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_PINBOOST}, 2019 {{0, {AudioNsurround".dac.mut"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2020 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(0)}, 2021 {{0, {AudioNsurround".mixer.m"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2022 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(1)}, 2023 2024 {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2025 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0e, MI_TARGET_OUTAMP}, 2026 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2027 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_OUTAMP}, 2028 {{0, {AzaliaNclfe".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2029 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_PINBOOST}, 2030 {{0, {AzaliaNclfe".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2031 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(0)}, 2032 {{0, {AzaliaNclfe".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2033 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(1)}, 2034 2035 {{0, {AzaliaNside}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2036 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0f, MI_TARGET_OUTAMP}, 2037 {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2038 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_OUTAMP}, 2039 {{0, {AzaliaNside".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2040 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_PINBOOST}, 2041 {{0, {AzaliaNside".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2042 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(0)}, 2043 {{0, {AzaliaNside".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2044 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(1)}, 2045 2046 {{0, {AudioNvolume"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2047 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)}, 2048 {{0, {AudioNvolume}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 2049 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x08, MI_TARGET_INAMP(0)}, 2050 {{0, {AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD, 2051 0, 0, .un.s={6, {{{AudioNmicrophone}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2}, 2052 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD}, 2053 {{AudioNspeaker}, ALC882_BEEP}, 2054 {{AudioNmixerout}, ALC882_MIX}}}}, 0x23, -1}, 2055 2056 {{0, {AudioNsource"2."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2057 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)}, 2058 {{0, {AudioNvolume"2"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 2059 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x09, MI_TARGET_INAMP(0)}, 2060 {{0, {AudioNsource"2"}, AUDIO_MIXER_SET, AZ_CLASS_RECORD, 2061 0, 0, .un.s={6, {{{AudioNmicrophone}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2}, 2062 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD}, 2063 {{AudioNspeaker}, ALC882_BEEP}, 2064 {{AudioNmixerout}, ALC882_MIX}}}}, 0x22, -1}, 2065 2066 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, 2067 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC}, 2068 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 2069 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_ADC}, 2070 }; 2071 2072 int 2073 azalia_alc883_mixer_init(codec_t *this) 2074 { 2075 mixer_ctrl_t mc; 2076 2077 this->nmixers = sizeof(alc883_mixer_items) / sizeof(mixer_item_t); 2078 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, 2079 M_DEVBUF, M_NOWAIT | M_ZERO); 2080 if (this->mixers == NULL) { 2081 printf("%s: out of memory in %s\n", XNAME(this), __func__); 2082 return ENOMEM; 2083 } 2084 memcpy(this->mixers, alc883_mixer_items, 2085 sizeof(mixer_item_t) * this->nmixers); 2086 azalia_generic_mixer_fix_indexes(this); 2087 azalia_generic_mixer_default(this); 2088 2089 if (this->subid == ALC883_ACER_ID) { 2090 azalia_gpio_unmute(this, 0); 2091 azalia_gpio_unmute(this, 1); 2092 } 2093 mc.dev = -1; 2094 mc.type = AUDIO_MIXER_ENUM; 2095 mc.un.ord = 1; /* pindir: output */ 2096 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc); 2097 azalia_generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR, &mc); 2098 azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc); 2099 azalia_generic_mixer_set(this, 0x16, MI_TARGET_PINDIR, &mc); 2100 azalia_generic_mixer_set(this, 0x17, MI_TARGET_PINDIR, &mc); 2101 mc.un.ord = 0; /* [0] 0x0c */ 2102 azalia_generic_mixer_set(this, 0x14, MI_TARGET_CONNLIST, &mc); 2103 azalia_generic_mixer_set(this, 0x1b, MI_TARGET_CONNLIST, &mc); 2104 mc.un.ord = 1; /* [1] 0x0d */ 2105 azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc); 2106 mc.un.ord = 2; /* [2] 0x0e */ 2107 azalia_generic_mixer_set(this, 0x16, MI_TARGET_CONNLIST, &mc); 2108 mc.un.ord = 2; /* [3] 0x0fb */ 2109 azalia_generic_mixer_set(this, 0x17, MI_TARGET_CONNLIST, &mc); 2110 2111 mc.un.ord = 0; /* pindir: input */ 2112 azalia_generic_mixer_set(this, 0x18, MI_TARGET_PINDIR, &mc); 2113 azalia_generic_mixer_set(this, 0x19, MI_TARGET_PINDIR, &mc); 2114 azalia_generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR, &mc); 2115 /* XXX: inamp for 18/19/1a */ 2116 2117 mc.un.ord = 0; /* unmute */ 2118 azalia_generic_mixer_set(this, 0x23, MI_TARGET_INAMP(1), &mc); 2119 azalia_generic_mixer_set(this, 0x22, MI_TARGET_INAMP(2), &mc); 2120 return 0; 2121 } 2122 2123 /* ---------------------------------------------------------------- 2124 * Analog Devices AD1984 2125 * ---------------------------------------------------------------- */ 2126 2127 int 2128 azalia_ad1984_init_dacgroup(codec_t *this) 2129 { 2130 static const convgroupset_t dacs = { 2131 -1, 1, 2132 {{2, {0x03, 0x04}}}}; 2133 2134 static const convgroupset_t adcs = { 2135 -1, 1, 2136 {{1, {0x08}}}}; 2137 2138 this->dacs = dacs; 2139 this->adcs = adcs; 2140 return 0; 2141 } 2142 2143 static const mixer_item_t ad1984_mixer_items[] = { 2144 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 2145 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 2146 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 2147 #define AD1984_DAC_HP 0x03 2148 #define AD1984_DAC_SPEAKER 0x04 2149 #define AD1984_TARGET_MASTER -1 2150 #define AD1984_TARGET_MASTER_MUTE -2 2151 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2152 4, 0, .un.v={{""}, 2, MIXER_DELTA(39)}}, 0x03, AD1984_TARGET_MASTER}, 2153 {{0, {AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2154 0, 3, ENUM_OFFON}, 0x11, AD1984_TARGET_MASTER_MUTE}, 2155 {{0, {AudioNvolume}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 2156 0, 0, .un.v={{""}, 2, MIXER_DELTA(54)}}, 0x0c, MI_TARGET_OUTAMP}, 2157 {{0, {AudioNvolume"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2158 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_OUTAMP}, 2159 {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2160 0, 0, .un.e={1, {{{AudioNmicrophone}, 0}}}}, 2161 0x0c, MI_TARGET_CONNLIST}, 2162 {{0, {AudioNmicrophone"."AudioNpreamp}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 2163 0, 0, .un.v={{""}, 2, MIXER_DELTA(3)}}, 0x14, MI_TARGET_INAMP(0)}, 2164 {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 2165 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x20, MI_TARGET_INAMP(0)}, 2166 {{0, {AudioNmicrophone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2167 0, 0, ENUM_OFFON}, 0x20, MI_TARGET_INAMP(0)}, 2168 {{0, {AudioNheadphone}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2169 0, 0, .un.v={{""}, 2, MIXER_DELTA(39)}}, 0x03, MI_TARGET_OUTAMP}, 2170 {{0, {AudioNheadphone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2171 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_OUTAMP}, 2172 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2173 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_PINBOOST}, 2174 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2175 0, 0, .un.v={{""}, 2, MIXER_DELTA(39)}}, 0x04, MI_TARGET_OUTAMP}, 2176 {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2177 0, 0, ENUM_OFFON}, 0x12, MI_TARGET_OUTAMP}, 2178 {{0, {AudioNspeaker".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2179 0, 0, ENUM_OFFON}, 0x12, MI_TARGET_PINBOOST}, 2180 {{0, {AudioNmono}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2181 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x13, MI_TARGET_OUTAMP}, 2182 {{0, {AudioNmono"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2183 0, 0, ENUM_OFFON}, 0x13, MI_TARGET_OUTAMP} 2184 }; 2185 2186 int 2187 azalia_ad1984_mixer_init(codec_t *this) 2188 { 2189 mixer_ctrl_t mc; 2190 2191 this->nmixers = sizeof(ad1984_mixer_items) / sizeof(mixer_item_t); 2192 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, 2193 M_DEVBUF, M_NOWAIT | M_ZERO); 2194 if (this->mixers == NULL) { 2195 printf("%s: out of memory in %s\n", XNAME(this), __func__); 2196 return ENOMEM; 2197 } 2198 memcpy(this->mixers, ad1984_mixer_items, 2199 sizeof(mixer_item_t) * this->nmixers); 2200 azalia_generic_mixer_fix_indexes(this); 2201 azalia_generic_mixer_default(this); 2202 mc.dev = -1; 2203 mc.type = AUDIO_MIXER_ENUM; 2204 mc.un.ord = 0; /* pindir: input */ 2205 azalia_generic_mixer_set(this, 0x1c, MI_TARGET_PINDIR, &mc); /* mic */ 2206 mc.un.ord = 1; /* enable */ 2207 azalia_generic_mixer_set(this, 0x12, MI_TARGET_EAPD, &mc); 2208 azalia_generic_mixer_set(this, 0x13, MI_TARGET_EAPD, &mc); 2209 2210 mc.un.ord = 0; /* unmute */ 2211 azalia_generic_mixer_set(this, 0x07, MI_TARGET_INAMP(0), &mc); 2212 azalia_generic_mixer_set(this, 0x07, MI_TARGET_INAMP(1), &mc); 2213 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(0), &mc); 2214 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(1), &mc); 2215 azalia_generic_mixer_set(this, 0x0b, MI_TARGET_INAMP(0), &mc); 2216 azalia_generic_mixer_set(this, 0x0b, MI_TARGET_INAMP(1), &mc); 2217 azalia_generic_mixer_set(this, 0x1e, MI_TARGET_INAMP(0), &mc); 2218 azalia_generic_mixer_set(this, 0x1e, MI_TARGET_INAMP(1), &mc); 2219 azalia_generic_mixer_set(this, 0x24, MI_TARGET_INAMP(0), &mc); 2220 azalia_generic_mixer_set(this, 0x24, MI_TARGET_INAMP(1), &mc); 2221 2222 return 0; 2223 } 2224 2225 int 2226 azalia_ad1984_set_port(codec_t *this, mixer_ctrl_t *mc) 2227 { 2228 const mixer_item_t *m; 2229 int err; 2230 2231 if (mc->dev >= this->nmixers) 2232 return ENXIO; 2233 m = &this->mixers[mc->dev]; 2234 if (mc->type != m->devinfo.type) 2235 return EINVAL; 2236 if (mc->type == AUDIO_MIXER_CLASS) 2237 return 0; 2238 if (m->target == AD1984_TARGET_MASTER) { 2239 err = azalia_generic_mixer_set(this, AD1984_DAC_HP, 2240 MI_TARGET_OUTAMP, mc); 2241 err = azalia_generic_mixer_set(this, AD1984_DAC_SPEAKER, 2242 MI_TARGET_OUTAMP, mc); 2243 return err; 2244 } 2245 if (m->target == AD1984_TARGET_MASTER_MUTE) { 2246 err = azalia_generic_mixer_set(this, 0x11, MI_TARGET_OUTAMP, mc); 2247 err = azalia_generic_mixer_set(this, 0x12, MI_TARGET_OUTAMP, mc); 2248 err = azalia_generic_mixer_set(this, 0x13, MI_TARGET_OUTAMP, mc); 2249 return err; 2250 } 2251 return azalia_generic_mixer_set(this, m->nid, m->target, mc); 2252 } 2253 2254 int 2255 azalia_ad1984_get_port(codec_t *this, mixer_ctrl_t *mc) 2256 { 2257 const mixer_item_t *m; 2258 2259 if (mc->dev >= this->nmixers) 2260 return ENXIO; 2261 m = &this->mixers[mc->dev]; 2262 mc->type = m->devinfo.type; 2263 if (mc->type == AUDIO_MIXER_CLASS) 2264 return 0; 2265 if (m->target == AD1984_TARGET_MASTER || 2266 m->target == AD1984_TARGET_MASTER_MUTE) 2267 return azalia_generic_mixer_get(this, m->nid, 2268 MI_TARGET_OUTAMP, mc); 2269 return azalia_generic_mixer_get(this, m->nid, m->target, mc); 2270 } 2271 2272 /* ---------------------------------------------------------------- 2273 * CMedia CMI9880 2274 * ---------------------------------------------------------------- */ 2275 2276 static const mixer_item_t cmi9880_mixer_items[] = { 2277 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 2278 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 2279 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 2280 2281 {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2282 0, 0, ENUM_OFFON}, 0x03, MI_TARGET_OUTAMP}, 2283 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2284 0, 0, ENUM_OFFON}, 0x04, MI_TARGET_OUTAMP}, 2285 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2286 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP}, 2287 {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2288 0, 0, ENUM_OFFON}, 0x06, MI_TARGET_OUTAMP}, 2289 {{0, {"digital."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2290 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_OUTAMP}, 2291 2292 {{0, {AzaliaNfront"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2293 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)}, 2294 {{0, {AzaliaNfront}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 2295 0, 0, .un.v={{""}, 2, MIXER_DELTA(30)}}, 0x08, MI_TARGET_INAMP(0)}, 2296 {{0, {AzaliaNfront"."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2297 0, 0, .un.e={4, {{{AudioNmicrophone}, 5}, {{AudioNcd}, 6}, 2298 {{"line1"}, 7}, {{"line2"}, 8}}}}, 2299 0x08, MI_TARGET_CONNLIST}, 2300 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2301 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)}, 2302 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 2303 0, 0, .un.v={{""}, 2, MIXER_DELTA(30)}}, 0x09, MI_TARGET_INAMP(0)}, 2304 {{0, {AudioNsurround"."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2305 0, 0, .un.e={4, {{{AudioNmicrophone}, 5}, {{AudioNcd}, 6}, 2306 {{"line1"}, 7}, {{"line2"}, 8}}}}, 2307 0x09, MI_TARGET_CONNLIST}, 2308 2309 {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2310 0, 0, ENUM_OFFON}, 0x23, MI_TARGET_OUTAMP}, 2311 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 2312 0, 0, .un.v={{""}, 1, MIXER_DELTA(15)}}, 0x23, MI_TARGET_OUTAMP} 2313 }; 2314 2315 int 2316 azalia_cmi9880_mixer_init(codec_t *this) 2317 { 2318 mixer_ctrl_t mc; 2319 2320 this->nmixers = sizeof(cmi9880_mixer_items) / sizeof(mixer_item_t); 2321 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, 2322 M_DEVBUF, M_NOWAIT | M_ZERO); 2323 if (this->mixers == NULL) { 2324 printf("%s: out of memory in %s\n", XNAME(this), __func__); 2325 return ENOMEM; 2326 } 2327 memcpy(this->mixers, cmi9880_mixer_items, 2328 sizeof(mixer_item_t) * this->nmixers); 2329 azalia_generic_mixer_fix_indexes(this); 2330 azalia_generic_mixer_default(this); 2331 2332 mc.dev = -1; 2333 mc.type = AUDIO_MIXER_ENUM; 2334 mc.un.ord = 5; /* record.front.source=mic */ 2335 azalia_generic_mixer_set(this, 0x08, MI_TARGET_CONNLIST, &mc); 2336 mc.un.ord = 7; /* record.surround.source=line1 */ 2337 azalia_generic_mixer_set(this, 0x09, MI_TARGET_CONNLIST, &mc); 2338 mc.un.ord = 1; /* pindir: output */ 2339 azalia_generic_mixer_set(this, 0x0b, MI_TARGET_PINDIR, &mc); 2340 azalia_generic_mixer_set(this, 0x0c, MI_TARGET_PINDIR, &mc); 2341 azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc); 2342 azalia_generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR, &mc); 2343 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); 2344 mc.un.ord = 0; /* front DAC -> headphones */ 2345 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_CONNLIST, &mc); 2346 mc.un.ord = 0; /* pindir: input */ 2347 azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc); /* mic */ 2348 azalia_generic_mixer_set(this, 0x13, MI_TARGET_PINDIR, &mc); /* SPDIF-in */ 2349 azalia_generic_mixer_set(this, 0x1f, MI_TARGET_PINDIR, &mc); /* line1 */ 2350 azalia_generic_mixer_set(this, 0x20, MI_TARGET_PINDIR, &mc); /* line2 */ 2351 return 0; 2352 } 2353 2354 int 2355 azalia_cmi9880_init_dacgroup(codec_t *this) 2356 { 2357 static const convgroupset_t dacs = { 2358 -1, 2, 2359 {{4, {0x03, 0x04, 0x05, 0x06}}, /* analog 8ch */ 2360 {1, {0x07}}}}; /* digital */ 2361 static const convgroupset_t adcs = { 2362 -1, 2, 2363 {{2, {0x08, 0x09}}, /* analog 4ch */ 2364 {1, {0x0a}}}}; /* digital */ 2365 2366 this->dacs = dacs; 2367 this->adcs = adcs; 2368 return 0; 2369 } 2370 2371 /* ---------------------------------------------------------------- 2372 * Sigmatel STAC9200 2373 * ---------------------------------------------------------------- */ 2374 2375 static const mixer_item_t stac9200_mixer_items[] = { 2376 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 2377 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 2378 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 2379 2380 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2381 4, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_OUTAMP}, 2382 {{0, {AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2383 0, 3, ENUM_OFFON}, 0x0b, MI_TARGET_OUTAMP}, 2384 {{0, {AudioNvolume}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 2385 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x0a, MI_TARGET_OUTAMP}, 2386 {{0, {AudioNvolume"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2387 0, 0, ENUM_OFFON}, 0x0a, MI_TARGET_OUTAMP}, 2388 {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2389 0, 0, .un.e={5, {{{AudioNline}, 0}, {{AudioNmicrophone}, 1}, 2390 {{AudioNline"2"}, 2}, {{AudioNline"3"}, 3}, 2391 {{AudioNcd}, 4}}}}, 2392 0x0c, MI_TARGET_CONNLIST}, 2393 {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 2394 0, 0, .un.v={{""}, 2, MIXER_DELTA(4)}}, 0x0c, MI_TARGET_OUTAMP}, 2395 {{0, {AudioNmicrophone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2396 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_OUTAMP}, 2397 {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2398 0, 0, .un.e={3, {{{AudioNdac}, 0}, {{"digital-in"}, 1}, {{"selector"}, 2}}}}, 2399 0x07, MI_TARGET_CONNLIST}, 2400 {{0, {"digital."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2401 0, 0, .un.e={2, {{{AudioNdac}, 0}, {{"selector"}, 1}}}}, 2402 0x09, MI_TARGET_CONNLIST}, /* AudioNdac is not accurate name */ 2403 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2404 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_PINBOOST}, 2405 {{0, {AudioNspeaker".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2406 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_PINBOOST}, 2407 {{0, {AudioNmono"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2408 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_OUTAMP}, 2409 {{0, {AudioNmono}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2410 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x11, MI_TARGET_OUTAMP}, 2411 {{0, {"beep."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2412 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP}, 2413 {{0, {"beep"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2414 0, 0, .un.v={{""}, 1, MIXER_DELTA(3)}}, 0x14, MI_TARGET_OUTAMP}, 2415 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 2416 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 2417 0, MI_TARGET_DAC}, 2418 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2419 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 2420 0, MI_TARGET_ADC}, 2421 }; 2422 2423 int 2424 azalia_stac9200_mixer_init(codec_t *this) 2425 { 2426 mixer_ctrl_t mc; 2427 2428 this->nmixers = sizeof(stac9200_mixer_items) / sizeof(mixer_item_t); 2429 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, 2430 M_DEVBUF, M_NOWAIT | M_ZERO); 2431 if (this->mixers == NULL) { 2432 printf("%s: out of memory in %s\n", XNAME(this), __func__); 2433 return ENOMEM; 2434 } 2435 memcpy(this->mixers, stac9200_mixer_items, 2436 sizeof(mixer_item_t) * this->nmixers); 2437 azalia_generic_mixer_fix_indexes(this); 2438 azalia_generic_mixer_default(this); 2439 2440 mc.dev = -1; /* no need for generic_mixer_set() */ 2441 mc.type = AUDIO_MIXER_ENUM; 2442 mc.un.ord = 1; /* pindir: output */ 2443 azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc); /* headphones */ 2444 azalia_generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR, &mc); /* speaker */ 2445 mc.un.ord = 0; /* pindir: input */ 2446 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); /* mic2 */ 2447 azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc); /* mic1 */ 2448 mc.type = AUDIO_MIXER_VALUE; 2449 mc.un.value.num_channels = 2; 2450 mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x0c, MI_TARGET_OUTAMP); 2451 mc.un.value.level[1] = mc.un.value.level[0]; 2452 azalia_generic_mixer_set(this, 0x0c, MI_TARGET_OUTAMP, &mc); 2453 2454 #define STAC9200_EVENT_HP 0 2455 #define STAC9200_NID_HP 0x0d 2456 #define STAC9200_NID_SPEAKER 0x0e 2457 2458 /* register hp unsolicited event */ 2459 this->comresp(this, STAC9200_NID_HP, 2460 CORB_SET_UNSOLICITED_RESPONSE, 2461 CORB_UNSOL_ENABLE | STAC9200_EVENT_HP, NULL); 2462 2463 azalia_stac9200_unsol_event(this, STAC9200_EVENT_HP); 2464 2465 return 0; 2466 } 2467 int 2468 azalia_stac9200_unsol_event(codec_t *this, int tag) 2469 { 2470 int err; 2471 uint32_t value; 2472 2473 switch (tag) { 2474 case STAC9200_EVENT_HP: 2475 err = this->comresp(this, STAC9200_NID_HP, 2476 CORB_GET_PIN_SENSE, 0, &value); 2477 if (err) 2478 break; 2479 if (value & CORB_PS_PRESENCE) { 2480 DPRINTF(("%s: headphone inserted\n", __func__)); 2481 azalia_generic_mixer_pinctrl(this, 2482 STAC9200_NID_SPEAKER, 0); 2483 } else { 2484 DPRINTF(("%s: headphone pulled\n", __func__)); 2485 azalia_generic_mixer_pinctrl(this, 2486 STAC9200_NID_SPEAKER, CORB_PWC_OUTPUT); 2487 } 2488 break; 2489 default: 2490 DPRINTF(("%s: unknown tag: %d\n", __func__, tag)); 2491 } 2492 return 0; 2493 } 2494 2495 int 2496 azalia_stac9221_init_dacgroup(codec_t *this) 2497 { 2498 static const convgroupset_t dacs = { 2499 -1, 1, 2500 {{4, {0x02, 0x03, 0x04, 0x05}}}}; 2501 2502 static const convgroupset_t adcs = { 2503 -1, 2, 2504 {{2, {0x06, 0x07}}, 2505 {1, {0x09}}}}; 2506 2507 this->dacs = dacs; 2508 this->adcs = adcs; 2509 return 0; 2510 } 2511 2512 static const mixer_item_t stac9221_mixer_items[] = { 2513 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 2514 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 2515 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 2516 #define STAC9221_TARGET_MASTER -1 2517 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2518 4, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x02, STAC9221_TARGET_MASTER}, 2519 {{0, {AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2520 0, 3, ENUM_OFFON}, 0x02, STAC9221_TARGET_MASTER}, 2521 2522 {{0, {AudioNheadphone}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2523 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x02, MI_TARGET_OUTAMP}, 2524 {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2525 0, 0, ENUM_OFFON}, 0x02, MI_TARGET_OUTAMP}, 2526 2527 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2528 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x03, MI_TARGET_OUTAMP}, 2529 {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2530 0, 0, ENUM_OFFON}, 0x03, MI_TARGET_OUTAMP}, 2531 2532 {{0, {"line"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2533 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x04, MI_TARGET_OUTAMP}, 2534 {{0, {"line.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2535 0, 0, ENUM_OFFON}, 0x04, MI_TARGET_OUTAMP}, 2536 2537 {{0, {"line2"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2538 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x05, MI_TARGET_OUTAMP}, 2539 {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2540 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP}, 2541 }; 2542 2543 int 2544 azalia_stac9221_mixer_init(codec_t *this) 2545 { 2546 mixer_ctrl_t mc; 2547 2548 this->nmixers = sizeof(stac9221_mixer_items) / sizeof(mixer_item_t); 2549 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, 2550 M_DEVBUF, M_NOWAIT | M_ZERO); 2551 if (this->mixers == NULL) { 2552 printf("%s: out of memory in %s\n", XNAME(this), __func__); 2553 return ENOMEM; 2554 } 2555 memcpy(this->mixers, stac9221_mixer_items, 2556 sizeof(mixer_item_t) * this->nmixers); 2557 azalia_generic_mixer_fix_indexes(this); 2558 azalia_generic_mixer_default(this); 2559 2560 mc.dev = -1; 2561 mc.type = AUDIO_MIXER_ENUM; 2562 mc.un.ord = 1; /* pindir: output */ 2563 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_PINDIR, &mc); /* headphones */ 2564 azalia_generic_mixer_set(this, 0x0b, MI_TARGET_PINDIR, &mc); /* mic, set to output */ 2565 azalia_generic_mixer_set(this, 0x0c, MI_TARGET_PINDIR, &mc); /* speaker */ 2566 azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc); /* line out */ 2567 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); /* another line out */ 2568 2569 if (this->subid == STAC9221_APPLE_ID) { 2570 azalia_gpio_unmute(this, 0); 2571 azalia_gpio_unmute(this, 1); 2572 #define APPLE_EVENT_HP 1 2573 #define APPLE_NID_HP 0x0a 2574 #define APPLE_NID_SPEAKER 0x0c 2575 #define APPLE_NID_LINE 0x0d 2576 2577 /* register hp unsolicited event */ 2578 this->comresp(this, APPLE_NID_HP, CORB_SET_UNSOLICITED_RESPONSE, 2579 CORB_UNSOL_ENABLE | APPLE_EVENT_HP, NULL); 2580 2581 azalia_stac9221_apple_unsol_event(this, APPLE_EVENT_HP); 2582 } 2583 return 0; 2584 } 2585 2586 int 2587 azalia_stac9221_set_port(codec_t *this, mixer_ctrl_t *mc) 2588 { 2589 const mixer_item_t *m; 2590 int err; 2591 2592 if (mc->dev >= this->nmixers) 2593 return ENXIO; 2594 m = &this->mixers[mc->dev]; 2595 if (mc->type != m->devinfo.type) 2596 return EINVAL; 2597 if (mc->type == AUDIO_MIXER_CLASS) 2598 return 0; 2599 if (m->target == STAC9221_TARGET_MASTER) { 2600 err = azalia_generic_mixer_set(this, 0x02, 2601 MI_TARGET_OUTAMP, mc); 2602 err = azalia_generic_mixer_set(this, 0x03, 2603 MI_TARGET_OUTAMP, mc); 2604 err = azalia_generic_mixer_set(this, 0x04, 2605 MI_TARGET_OUTAMP, mc); 2606 err = azalia_generic_mixer_set(this, 0x05, 2607 MI_TARGET_OUTAMP, mc); 2608 return err; 2609 } 2610 return azalia_generic_mixer_set(this, m->nid, m->target, mc); 2611 } 2612 2613 int 2614 azalia_stac9221_get_port(codec_t *this, mixer_ctrl_t *mc) 2615 { 2616 const mixer_item_t *m; 2617 2618 if (mc->dev >= this->nmixers) 2619 return ENXIO; 2620 m = &this->mixers[mc->dev]; 2621 mc->type = m->devinfo.type; 2622 if (mc->type == AUDIO_MIXER_CLASS) 2623 return 0; 2624 if (m->target == STAC9221_TARGET_MASTER) 2625 return azalia_generic_mixer_get(this, m->nid, 2626 MI_TARGET_OUTAMP, mc); 2627 return azalia_generic_mixer_get(this, m->nid, m->target, mc); 2628 } 2629 2630 int 2631 azalia_stac9221_apple_unsol_event(codec_t *this, int tag) 2632 { 2633 int err; 2634 uint32_t value; 2635 2636 switch (tag) { 2637 case APPLE_EVENT_HP: 2638 err = this->comresp(this, APPLE_NID_HP, 2639 CORB_GET_PIN_SENSE, 0, &value); 2640 if (err) 2641 break; 2642 if (value & CORB_PS_PRESENCE) { 2643 DPRINTF(("%s: headphone inserted\n", __func__)); 2644 azalia_generic_mixer_pinctrl(this, 2645 APPLE_NID_SPEAKER, 0); 2646 azalia_generic_mixer_pinctrl(this, 2647 APPLE_NID_LINE, 0); 2648 } else { 2649 DPRINTF(("%s: headphone pulled\n", __func__)); 2650 azalia_generic_mixer_pinctrl(this, 2651 APPLE_NID_SPEAKER, CORB_PWC_OUTPUT); 2652 azalia_generic_mixer_pinctrl(this, 2653 APPLE_NID_LINE, CORB_PWC_OUTPUT); 2654 } 2655 break; 2656 default: 2657 DPRINTF(("%s: unknown tag: %d\n", __func__, tag)); 2658 } 2659 return 0; 2660 } 2661 2662 int 2663 azalia_gpio_unmute(codec_t *this, int pin) 2664 { 2665 uint32_t data, mask, dir; 2666 2667 this->comresp(this, this->audiofunc, CORB_GET_GPIO_DATA, 0, &data); 2668 this->comresp(this, this->audiofunc, CORB_GET_GPIO_ENABLE_MASK, 0, &mask); 2669 this->comresp(this, this->audiofunc, CORB_GET_GPIO_DIRECTION, 0, &dir); 2670 2671 data |= 1 << pin; 2672 mask |= 1 << pin; 2673 dir |= 1 << pin; 2674 2675 if (this->subid == STAC9221_APPLE_ID) 2676 this->comresp(this, this->audiofunc, 0x7e7, 0, NULL); 2677 2678 this->comresp(this, this->audiofunc, CORB_SET_GPIO_ENABLE_MASK, mask, NULL); 2679 this->comresp(this, this->audiofunc, CORB_SET_GPIO_DIRECTION, dir, NULL); 2680 DELAY(1000); 2681 this->comresp(this, this->audiofunc, CORB_SET_GPIO_DATA, data, NULL); 2682 2683 return 0; 2684 } 2685 2686 /* ---------------------------------------------------------------- 2687 * Sony VAIO FE and SZ 2688 * ---------------------------------------------------------------- */ 2689 2690 int 2691 azalia_stac7661_init_dacgroup(codec_t *this) 2692 { 2693 static const convgroupset_t dacs = { 2694 -1, 1, 2695 {{2, {0x02, 0x05}}}}; 2696 2697 static const convgroupset_t adcs = { 2698 -1, 1, 2699 {{1, {0x08}}}}; 2700 2701 this->dacs = dacs; 2702 this->adcs = adcs; 2703 2704 return 0; 2705 } 2706 2707 static const mixer_item_t stac7661_mixer_items[] = { 2708 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, 2709 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, 2710 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, 2711 2712 #define STAC7661_DAC_HP 0x02 2713 #define STAC7661_DAC_SPEAKER 0x05 2714 #define STAC7661_TARGET_MASTER -1 2715 2716 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2717 4, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x02, STAC7661_TARGET_MASTER}, 2718 {{0, {AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2719 0, 3, ENUM_OFFON}, 0x02, STAC7661_TARGET_MASTER}, 2720 {{0, {AudioNvolume"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, 2721 ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)}, 2722 {{0, {AudioNvolume}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, 2723 .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x09, MI_TARGET_INAMP(0)}, 2724 {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 2725 0, 0, .un.e={3, {{{AudioNmicrophone}, 1}, {{AudioNmicrophone"2"}, 2}, 2726 {{AudioNdac}, 3}}}}, 2727 0x15, MI_TARGET_CONNLIST}, 2728 {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, 2729 .un.v={{""}, 2, MIXER_DELTA(4)}}, 0x15, MI_TARGET_OUTAMP}, 2730 {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2731 0, 0, ENUM_OFFON}, 0x02, MI_TARGET_OUTAMP}, 2732 {{0, {AudioNheadphone}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2733 0, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x02, MI_TARGET_OUTAMP}, 2734 {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, 2735 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP}, 2736 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, 2737 0, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x05, MI_TARGET_OUTAMP} 2738 }; 2739 2740 int 2741 azalia_stac7661_mixer_init(codec_t *this) 2742 { 2743 mixer_ctrl_t mc; 2744 2745 this->nmixers = sizeof(stac7661_mixer_items) / sizeof(mixer_item_t); 2746 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, 2747 M_DEVBUF, M_NOWAIT | M_ZERO); 2748 if (this->mixers == NULL) { 2749 printf("%s: out of memory in %s\n", XNAME(this), __func__); 2750 return ENOMEM; 2751 } 2752 memcpy(this->mixers, stac7661_mixer_items, 2753 sizeof(mixer_item_t) * this->nmixers); 2754 azalia_generic_mixer_fix_indexes(this); 2755 azalia_generic_mixer_default(this); 2756 mc.dev = -1; 2757 mc.type = AUDIO_MIXER_ENUM; 2758 mc.un.ord = 1; 2759 azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(0), &mc); /* mute input */ 2760 mc.un.ord = 0; 2761 azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc); /* mic */ 2762 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc); /* internal mic */ 2763 mc.un.ord = 2; /* select internal mic for recording */ 2764 azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc); 2765 2766 return 0; 2767 } 2768 2769 int 2770 azalia_stac7661_set_port(codec_t *this, mixer_ctrl_t *mc) 2771 { 2772 const mixer_item_t *m; 2773 int err; 2774 2775 if (mc->dev >= this->nmixers) 2776 return ENXIO; 2777 m = &this->mixers[mc->dev]; 2778 if (mc->type != m->devinfo.type) 2779 return EINVAL; 2780 if (mc->type == AUDIO_MIXER_CLASS) 2781 return 0; 2782 if (m->target == STAC7661_TARGET_MASTER) { 2783 err = azalia_generic_mixer_set(this, STAC7661_DAC_HP, 2784 MI_TARGET_OUTAMP, mc); 2785 err = azalia_generic_mixer_set(this, STAC7661_DAC_SPEAKER, 2786 MI_TARGET_OUTAMP, mc); 2787 return err; 2788 } 2789 return azalia_generic_mixer_set(this, m->nid, m->target, mc); 2790 } 2791 int 2792 azalia_stac7661_get_port(codec_t *this, mixer_ctrl_t *mc) 2793 { 2794 const mixer_item_t *m; 2795 2796 if (mc->dev >= this->nmixers) 2797 return ENXIO; 2798 m = &this->mixers[mc->dev]; 2799 mc->type = m->devinfo.type; 2800 if (mc->type == AUDIO_MIXER_CLASS) 2801 return 0; 2802 if (m->target == STAC7661_TARGET_MASTER) 2803 return azalia_generic_mixer_get(this, m->nid, 2804 MI_TARGET_OUTAMP, mc); 2805 return azalia_generic_mixer_get(this, m->nid, m->target, mc); 2806 } 2807