1 /* 2 * Copyright 2007-2012, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ithamar Adema, ithamar AT unet DOT nl 7 * Axel Dörfler, axeld@pinc-software.de 8 * Jérôme Duval, korli@users.berlios.de 9 */ 10 11 12 #include "driver.h" 13 #include "hda_codec_defs.h" 14 15 16 #undef TRACE 17 #define TRACE_CODEC 18 #ifdef TRACE_CODEC 19 # define TRACE(a...) dprintf("hda: " a) 20 #else 21 # define TRACE(a...) 22 #endif 23 #define ERROR(a...) dprintf("hda: " a) 24 25 26 #define HDA_ALL 0xffffffff 27 #define HDA_QUIRK_GPIO_COUNT 8 28 #define HDA_QUIRK_GPIO0 (1 << 0) 29 #define HDA_QUIRK_GPIO1 (1 << 1) 30 #define HDA_QUIRK_GPIO2 (1 << 2) 31 #define HDA_QUIRK_GPIO3 (1 << 3) 32 #define HDA_QUIRK_GPIO4 (1 << 4) 33 #define HDA_QUIRK_GPIO5 (1 << 5) 34 #define HDA_QUIRK_GPIO6 (1 << 6) 35 #define HDA_QUIRK_GPIO7 (1 << 7) 36 #define HDA_QUIRK_IVREF50 (1 << 8) 37 #define HDA_QUIRK_IVREF80 (1 << 9) 38 #define HDA_QUIRK_IVREF100 (1 << 10) 39 #define HDA_QUIRK_OVREF50 (1 << 11) 40 #define HDA_QUIRK_OVREF80 (1 << 12) 41 #define HDA_QUIRK_OVREF100 (1 << 13) 42 #define HDA_QUIRK_IVREF (HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF80 \ 43 | HDA_QUIRK_IVREF100) 44 #define HDA_QUIRK_OVREF (HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 \ 45 | HDA_QUIRK_OVREF100) 46 47 48 #define ANALOGDEVICES_VENDORID 0x11d4 49 #define CIRRUSLOGIC_VENDORID 0x1013 50 #define CONEXANT_VENDORID 0x14f1 51 #define IDT_VENDORID 0x111d 52 #define REALTEK_VENDORID 0x10ec 53 #define SIGMATEL_VENDORID 0x8384 54 55 56 static const char* kPortConnector[] = { 57 "Jack", "None", "Fixed", "Dual" 58 }; 59 60 static const char* kDefaultDevice[] = { 61 "Line out", "Speaker", "HP out", "CD", "SPDIF out", "Digital other out", 62 "Modem line side", "Modem hand side", "Line in", "AUX", "Mic in", 63 "Telephony", "SPDIF in", "Digital other in", "Reserved", "Other" 64 }; 65 66 static const char* kConnectionType[] = { 67 "N/A", "1/8\"", "1/4\"", "ATAPI internal", "RCA", "Optical", 68 "Other digital", "Other analog", "Multichannel analog (DIN)", 69 "XLR/Professional", "RJ-11 (modem)", "Combination", "-", "-", "-", "Other" 70 }; 71 72 static const char* kJackColor[] = { 73 "N/A", "Black", "Grey", "Blue", "Green", "Red", "Orange", "Yellow", 74 "Purple", "Pink", "-", "-", "-", "-", "White", "Other" 75 }; 76 77 static const struct { 78 uint32 subsystem_vendor_id, subsystem_id; 79 uint32 codec_vendor_id, codec_id; 80 uint32 quirks, nonquirks; 81 } kCodecQuirks[] = { 82 { HDA_ALL, HDA_ALL, HDA_ALL, HDA_ALL, HDA_QUIRK_IVREF, 0 }, 83 { HDA_ALL, HDA_ALL, HDA_ALL, HDA_ALL, HDA_QUIRK_IVREF, 0 }, 84 { 0x10de, 0x0d94, CIRRUSLOGIC_VENDORID, HDA_ALL, 85 HDA_QUIRK_GPIO1 | HDA_QUIRK_GPIO3, 0 }, // MacBookAir 3,1(2) 86 { 0x10de, 0xcb79, CIRRUSLOGIC_VENDORID, 0x4206, 87 HDA_QUIRK_GPIO1 | HDA_QUIRK_GPIO3, 0 }, // MacBook Pro 5,5 88 { 0x10de, 0xcb89, CIRRUSLOGIC_VENDORID, 0x4206, 89 HDA_QUIRK_GPIO1 | HDA_QUIRK_GPIO3, 0 }, // MacBookPro 7,1 90 { 0x8384, 0x7680, SIGMATEL_VENDORID, 0x7680, 91 HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0}, // Apple Intel Mac 92 { 0x106b, 0x00a0, REALTEK_VENDORID, 0x0885, 93 HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF80, 0}, // iMac 8,1, Macbook Pro 3,1 94 { 0x106b, 0x00a1, REALTEK_VENDORID, 0x0885, 95 HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0}, // MacBook 96 { 0x106b, 0x00a3, REALTEK_VENDORID, 0x0885, 97 HDA_QUIRK_GPIO0, 0}, // MacBook 98 { 0x106b, 0x7200, CIRRUSLOGIC_VENDORID, 0x4208, 99 HDA_QUIRK_GPIO0, 0}, // MacBookAir 6,2 100 { HDA_ALL, HDA_ALL, IDT_VENDORID, 0x76b2, HDA_QUIRK_GPIO0, 0}, 101 }; 102 103 104 static const char* 105 get_widget_type_name(hda_widget_type type) 106 { 107 switch (type) { 108 case WT_AUDIO_OUTPUT: 109 return "Audio output"; 110 case WT_AUDIO_INPUT: 111 return "Audio input"; 112 case WT_AUDIO_MIXER: 113 return "Audio mixer"; 114 case WT_AUDIO_SELECTOR: 115 return "Audio selector"; 116 case WT_PIN_COMPLEX: 117 return "Pin complex"; 118 case WT_POWER: 119 return "Power"; 120 case WT_VOLUME_KNOB: 121 return "Volume knob"; 122 case WT_BEEP_GENERATOR: 123 return "Beep generator"; 124 case WT_VENDOR_DEFINED: 125 return "Vendor defined"; 126 default: 127 return "Unknown"; 128 } 129 } 130 131 132 const char* 133 get_widget_location(uint32 location) 134 { 135 switch (location >> 4) { 136 case 0: 137 case 2: 138 switch (location & 0xf) { 139 case 2: 140 return "Front"; 141 case 3: 142 return "Left"; 143 case 4: 144 return "Right"; 145 case 5: 146 return "Top"; 147 case 6: 148 return "Bottom"; 149 case 7: 150 return "Rear panel"; 151 case 8: 152 return "Drive bay"; 153 case 0: 154 case 1: 155 default: 156 return NULL; 157 } 158 case 1: 159 switch (location & 0xf) { 160 case 7: 161 return "Riser"; 162 case 8: 163 return "HDMI"; 164 default: 165 return NULL; 166 } 167 case 3: 168 switch (location & 0xf) { 169 case 6: 170 return "Bottom"; 171 case 7: 172 return "Inside lid"; 173 case 8: 174 return "Outside lid"; 175 default: 176 return NULL; 177 } 178 } 179 return NULL; 180 } 181 182 183 static void 184 dump_widget_audio_capabilities(uint32 capabilities) 185 { 186 static const struct { 187 uint32 flag; 188 const char* name; 189 } kFlags[] = { 190 {AUDIO_CAP_CP_CAPS, "CP caps"}, 191 {AUDIO_CAP_LEFT_RIGHT_SWAP, "L-R swap"}, 192 {AUDIO_CAP_POWER_CONTROL, "Power"}, 193 {AUDIO_CAP_DIGITAL, "Digital"}, 194 {AUDIO_CAP_CONNECTION_LIST, "Conn. list"}, 195 {AUDIO_CAP_UNSOLICITED_RESPONSES, "Unsol. responses"}, 196 {AUDIO_CAP_PROCESSING_CONTROLS, "Proc widget"}, 197 {AUDIO_CAP_STRIPE, "Stripe"}, 198 {AUDIO_CAP_FORMAT_OVERRIDE, "Format override"}, 199 {AUDIO_CAP_AMPLIFIER_OVERRIDE, "Amplifier override"}, 200 {AUDIO_CAP_OUTPUT_AMPLIFIER, "Out amplifier"}, 201 {AUDIO_CAP_INPUT_AMPLIFIER, "In amplifier"}, 202 {AUDIO_CAP_STEREO, "Stereo"}, 203 }; 204 205 char buffer[256]; 206 int offset = 0; 207 208 for (uint32 j = 0; j < sizeof(kFlags) / sizeof(kFlags[0]); j++) { 209 if ((capabilities & kFlags[j].flag) != 0) 210 offset += sprintf(buffer + offset, "[%s] ", kFlags[j].name); 211 } 212 213 if (offset != 0) 214 TRACE("\t%s\n", buffer); 215 } 216 217 218 static void 219 dump_widget_inputs(hda_widget& widget) 220 { 221 // dump connections 222 223 char buffer[256]; 224 int offset = 0; 225 226 for (uint32 i = 0; i < widget.num_inputs; i++) { 227 int32 input = widget.inputs[i]; 228 229 if ((int32)i != widget.active_input) 230 offset += sprintf(buffer + offset, "%" B_PRId32 " ", input); 231 else 232 offset += sprintf(buffer + offset, "<%" B_PRId32 "> ", input); 233 } 234 235 if (offset != 0) 236 TRACE("\tInputs: %s\n", buffer); 237 } 238 239 240 static void 241 dump_widget_amplifier_capabilities(hda_widget& widget, bool input) 242 { 243 uint32 capabilities; 244 if (input) 245 capabilities = widget.capabilities.input_amplifier; 246 else 247 capabilities = widget.capabilities.output_amplifier; 248 249 if (capabilities == 0) 250 return; 251 252 TRACE("\t%s Amp: %sstep size: %f dB, # steps: %" B_PRIu32 ", " 253 "offset to 0 dB: %" B_PRIu32 "\n", 254 input ? "In" : "Out", 255 (capabilities & AMP_CAP_MUTE) != 0 ? "supports mute, " : "", 256 AMP_CAP_STEP_SIZE(capabilities), 257 AMP_CAP_NUM_STEPS(capabilities), 258 AMP_CAP_OFFSET(capabilities)); 259 } 260 261 262 static void 263 dump_widget_pm_support(hda_widget& widget) 264 { 265 TRACE("\tSupported power states: %s%s%s%s%s%s%s%s\n", 266 widget.pm & POWER_STATE_D0 ? "D0 " : "", 267 widget.pm & POWER_STATE_D1 ? "D1 " : "", 268 widget.pm & POWER_STATE_D2 ? "D2 " : "", 269 widget.pm & POWER_STATE_D3 ? "D3 " : "", 270 widget.pm & POWER_STATE_D3COLD ? "D3COLD " : "", 271 widget.pm & POWER_STATE_S3D3COLD ? "S3D3COLD " : "", 272 widget.pm & POWER_STATE_CLKSTOP ? "CLKSTOP " : "", 273 widget.pm & POWER_STATE_EPSS ? "EPSS " : ""); 274 } 275 276 277 static void 278 dump_widget_stream_support(hda_widget& widget) 279 { 280 TRACE("\tSupported formats: %s%s%s%s%s%s%s%s%s\n", 281 widget.d.io.formats & B_FMT_8BIT_S ? "8bits " : "", 282 widget.d.io.formats & B_FMT_16BIT ? "16bits " : "", 283 widget.d.io.formats & B_FMT_20BIT ? "20bits " : "", 284 widget.d.io.formats & B_FMT_24BIT ? "24bits " : "", 285 widget.d.io.formats & B_FMT_32BIT ? "32bits " : "", 286 widget.d.io.formats & B_FMT_FLOAT ? "float " : "", 287 widget.d.io.formats & B_FMT_DOUBLE ? "double " : "", 288 widget.d.io.formats & B_FMT_EXTENDED ? "extended " : "", 289 widget.d.io.formats & B_FMT_BITSTREAM ? "bitstream " : ""); 290 TRACE("\tSupported rates: %s%s%s%s%s%s%s%s%s%s%s%s\n", 291 widget.d.io.rates & B_SR_8000 ? "8khz " : "", 292 widget.d.io.rates & B_SR_11025 ? "11khz " : "", 293 widget.d.io.rates & B_SR_16000 ? "16khz " : "", 294 widget.d.io.rates & B_SR_22050 ? "22khz " : "", 295 widget.d.io.rates & B_SR_32000 ? "32khz " : "", 296 widget.d.io.rates & B_SR_44100 ? "44khz " : "", 297 widget.d.io.rates & B_SR_48000 ? "48khz " : "", 298 widget.d.io.rates & B_SR_88200 ? "88khz " : "", 299 widget.d.io.rates & B_SR_96000 ? "96khz " : "", 300 widget.d.io.rates & B_SR_176400 ? "176khz " : "", 301 widget.d.io.rates & B_SR_192000 ? "192khz " : "", 302 widget.d.io.rates & B_SR_384000 ? "384khz " : ""); 303 304 } 305 306 307 static void 308 dump_pin_complex_capabilities(hda_widget& widget) 309 { 310 TRACE("\t%s%s%s%s%s%s%s%s%s%s%s%s%s\n", 311 widget.d.pin.capabilities & PIN_CAP_IMP_SENSE ? "[Imp Sense] " : "", 312 widget.d.pin.capabilities & PIN_CAP_TRIGGER_REQ ? "[Trigger Req]" : "", 313 widget.d.pin.capabilities & PIN_CAP_PRES_DETECT ? "[Pres Detect]" : "", 314 widget.d.pin.capabilities & PIN_CAP_HP_DRIVE ? "[HP Drive]" : "", 315 widget.d.pin.capabilities & PIN_CAP_OUTPUT ? "[Output]" : "", 316 widget.d.pin.capabilities & PIN_CAP_INPUT ? "[Input]" : "", 317 widget.d.pin.capabilities & PIN_CAP_BALANCE ? "[Balance]" : "", 318 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_HIZ ? "[VRef HIZ]" : "", 319 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_50 ? "[VRef 50]" : "", 320 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_GROUND ? "[VRef Gr]" : "", 321 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_80 ? "[VRef 80]" : "", 322 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_100 ? "[VRef 100]" : "", 323 widget.d.pin.capabilities & PIN_CAP_EAPD_CAP ? "[EAPD]" : ""); 324 } 325 326 327 static void 328 dump_audiogroup_widgets(hda_audio_group* audioGroup) 329 { 330 TRACE("\tAudiogroup:\n"); 331 // Iterate over all widgets and collect info 332 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 333 hda_widget& widget = audioGroup->widgets[i]; 334 uint32 nodeID = audioGroup->widget_start + i; 335 336 TRACE("%" B_PRIu32 ": %s\n", nodeID, get_widget_type_name(widget.type)); 337 338 switch (widget.type) { 339 case WT_AUDIO_OUTPUT: 340 case WT_AUDIO_INPUT: 341 break; 342 343 case WT_PIN_COMPLEX: 344 dump_pin_complex_capabilities(widget); 345 break; 346 347 default: 348 break; 349 } 350 351 dump_widget_pm_support(widget); 352 dump_widget_audio_capabilities(widget.capabilities.audio); 353 dump_widget_amplifier_capabilities(widget, true); 354 dump_widget_amplifier_capabilities(widget, false); 355 dump_widget_inputs(widget); 356 } 357 } 358 359 360 // #pragma mark - 361 362 363 static void 364 hda_codec_get_quirks(hda_codec* codec) 365 { 366 codec->quirks = 0; 367 368 uint32 subSystemID = codec->subsystem_id & 0xffff; 369 uint32 subSystemVendorID = codec->subsystem_id >> 16; 370 371 for (uint32 i = 0; 372 i < (sizeof(kCodecQuirks) / sizeof(kCodecQuirks[0])); i++) { 373 if (kCodecQuirks[i].subsystem_id != HDA_ALL 374 && kCodecQuirks[i].subsystem_id != subSystemID) 375 continue; 376 if (kCodecQuirks[i].subsystem_vendor_id != HDA_ALL 377 && kCodecQuirks[i].subsystem_vendor_id != subSystemVendorID) 378 continue; 379 if (kCodecQuirks[i].codec_vendor_id != HDA_ALL 380 && kCodecQuirks[i].codec_vendor_id != codec->vendor_id) 381 continue; 382 if (kCodecQuirks[i].codec_id != HDA_ALL 383 && kCodecQuirks[i].codec_id != codec->product_id) 384 continue; 385 386 codec->quirks |= kCodecQuirks[i].quirks; 387 codec->quirks &= ~kCodecQuirks[i].nonquirks; 388 } 389 } 390 391 392 static status_t 393 hda_get_pm_support(hda_codec* codec, uint32 nodeID, uint32* pm) 394 { 395 corb_t verb = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER, 396 PID_POWERSTATE_SUPPORT); 397 398 uint32 response; 399 status_t status = hda_send_verbs(codec, &verb, &response, 1); 400 if (status == B_OK) 401 *pm = response & 0xf; 402 403 return status; 404 } 405 406 407 static status_t 408 hda_get_stream_support(hda_codec* codec, uint32 nodeID, uint32* formats, 409 uint32* rates) 410 { 411 corb_t verbs[2]; 412 uint32 resp[2]; 413 status_t status; 414 415 verbs[0] = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER, 416 PID_STREAM_SUPPORT); 417 verbs[1] = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER, 418 PID_PCM_SUPPORT); 419 420 status = hda_send_verbs(codec, verbs, resp, 2); 421 if (status != B_OK) 422 return status; 423 424 *formats = 0; 425 *rates = 0; 426 427 if ((resp[0] & (STREAM_FLOAT | STREAM_PCM)) != 0) { 428 if (resp[1] & (1 << 0)) 429 *rates |= B_SR_8000; 430 if (resp[1] & (1 << 1)) 431 *rates |= B_SR_11025; 432 if (resp[1] & (1 << 2)) 433 *rates |= B_SR_16000; 434 if (resp[1] & (1 << 3)) 435 *rates |= B_SR_22050; 436 if (resp[1] & (1 << 4)) 437 *rates |= B_SR_32000; 438 if (resp[1] & (1 << 5)) 439 *rates |= B_SR_44100; 440 if (resp[1] & (1 << 6)) 441 *rates |= B_SR_48000; 442 if (resp[1] & (1 << 7)) 443 *rates |= B_SR_88200; 444 if (resp[1] & (1 << 8)) 445 *rates |= B_SR_96000; 446 if (resp[1] & (1 << 9)) 447 *rates |= B_SR_176400; 448 if (resp[1] & (1 << 10)) 449 *rates |= B_SR_192000; 450 if (resp[1] & (1 << 11)) 451 *rates |= B_SR_384000; 452 453 if (resp[1] & PCM_8_BIT) 454 *formats |= B_FMT_8BIT_S; 455 if (resp[1] & PCM_16_BIT) 456 *formats |= B_FMT_16BIT; 457 if (resp[1] & PCM_20_BIT) 458 *formats |= B_FMT_20BIT; 459 if (resp[1] & PCM_24_BIT) 460 *formats |= B_FMT_24BIT; 461 if (resp[1] & PCM_32_BIT) 462 *formats |= B_FMT_32BIT; 463 } 464 if ((resp[0] & STREAM_FLOAT) != 0) 465 *formats |= B_FMT_FLOAT; 466 if ((resp[0] & STREAM_AC3) != 0) { 467 *formats |= B_FMT_BITSTREAM; 468 } 469 470 return B_OK; 471 } 472 473 474 // #pragma mark - widget functions 475 476 477 static status_t 478 hda_widget_get_pm_support(hda_audio_group* audioGroup, hda_widget* widget) 479 { 480 return hda_get_pm_support(audioGroup->codec, widget->node_id, &widget->pm); 481 } 482 483 484 static status_t 485 hda_widget_get_stream_support(hda_audio_group* audioGroup, hda_widget* widget) 486 { 487 if (audioGroup->widget.node_id != widget->node_id 488 && (widget->capabilities.audio & AUDIO_CAP_FORMAT_OVERRIDE) == 0) { 489 // adopt capabilities of the audio group 490 widget->d.io.formats = audioGroup->widget.d.io.formats; 491 widget->d.io.rates = audioGroup->widget.d.io.rates; 492 return B_OK; 493 } 494 495 return hda_get_stream_support(audioGroup->codec, widget->node_id, 496 &widget->d.io.formats, &widget->d.io.rates); 497 } 498 499 500 static status_t 501 hda_widget_get_amplifier_capabilities(hda_audio_group* audioGroup, 502 hda_widget* widget) 503 { 504 uint32 response; 505 corb_t verb; 506 507 if ((widget->capabilities.audio & AUDIO_CAP_OUTPUT_AMPLIFIER) != 0 508 || audioGroup->widget.node_id == widget->node_id) { 509 if ((widget->capabilities.audio & AUDIO_CAP_AMPLIFIER_OVERRIDE) != 0 510 || audioGroup->widget.node_id == widget->node_id) { 511 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id, 512 VID_GET_PARAMETER, PID_OUTPUT_AMPLIFIER_CAP); 513 status_t status = hda_send_verbs(audioGroup->codec, &verb, 514 &response, 1); 515 if (status != B_OK) 516 return status; 517 518 widget->capabilities.output_amplifier = response; 519 } else { 520 // adopt capabilities from the audio function group 521 widget->capabilities.output_amplifier 522 = audioGroup->widget.capabilities.output_amplifier; 523 } 524 } 525 526 if ((widget->capabilities.audio & AUDIO_CAP_INPUT_AMPLIFIER) != 0 527 || audioGroup->widget.node_id == widget->node_id) { 528 if ((widget->capabilities.audio & AUDIO_CAP_AMPLIFIER_OVERRIDE 529 || audioGroup->widget.node_id == widget->node_id) != 0) { 530 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id, 531 VID_GET_PARAMETER, PID_INPUT_AMPLIFIER_CAP); 532 status_t status = hda_send_verbs(audioGroup->codec, &verb, 533 &response, 1); 534 if (status != B_OK) 535 return status; 536 537 widget->capabilities.input_amplifier = response; 538 } else { 539 // adopt capabilities from the audio function group 540 widget->capabilities.input_amplifier 541 = audioGroup->widget.capabilities.input_amplifier; 542 } 543 } 544 545 return B_OK; 546 } 547 548 549 hda_widget* 550 hda_audio_group_get_widget(hda_audio_group* audioGroup, uint32 nodeID) 551 { 552 if (audioGroup->widget_start > nodeID 553 || audioGroup->widget_start + audioGroup->widget_count < nodeID) 554 return NULL; 555 556 return &audioGroup->widgets[nodeID - audioGroup->widget_start]; 557 } 558 559 560 static status_t 561 hda_widget_get_connections(hda_audio_group* audioGroup, hda_widget* widget) 562 { 563 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id, 564 VID_GET_PARAMETER, PID_CONNECTION_LIST_LENGTH); 565 uint32 response; 566 567 if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) != B_OK) 568 return B_ERROR; 569 570 uint32 listEntries = response & 0x7f; 571 bool longForm = (response & 0xf0) != 0; 572 573 if (listEntries == 0) 574 return B_OK; 575 576 #if 1 577 if (widget->num_inputs > 1) { 578 // Get currently active connection 579 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id, 580 VID_GET_CONNECTION_SELECT, 0); 581 if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) == B_OK) 582 widget->active_input = response & 0xff; 583 } 584 #endif 585 586 uint32 valuesPerEntry = longForm ? 2 : 4; 587 uint32 shift = 32 / valuesPerEntry; 588 uint32 rangeMask = (1 << (shift - 1)); 589 int32 previousInput = -1; 590 uint32 numInputs = 0; 591 592 for (uint32 i = 0; i < listEntries; i++) { 593 if ((i % valuesPerEntry) == 0) { 594 // We get 2 or 4 answers per call depending on if we're 595 // in short or long list mode 596 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id, 597 VID_GET_CONNECTION_LIST_ENTRY, i); 598 if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) 599 != B_OK) { 600 ERROR("Error parsing inputs for widget %" B_PRIu32 "!\n", 601 widget->node_id); 602 break; 603 } 604 } 605 606 int32 input = (response >> (shift * (i % valuesPerEntry))) 607 & ((1 << shift) - 1); 608 609 if (input & rangeMask) { 610 // found range 611 input &= ~rangeMask; 612 613 if (input < previousInput || previousInput == -1) { 614 ERROR("invalid range from %" B_PRId32 " to %" B_PRId32 "\n", 615 previousInput, input); 616 continue; 617 } 618 619 for (int32 rangeInput = previousInput + 1; rangeInput <= input 620 && numInputs < MAX_INPUTS; rangeInput++) { 621 widget->inputs[numInputs++] = rangeInput; 622 } 623 624 previousInput = -1; 625 } else if (numInputs < MAX_INPUTS) { 626 // standard value 627 widget->inputs[numInputs++] = input; 628 previousInput = input; 629 } 630 } 631 632 widget->num_inputs = numInputs; 633 634 if (widget->num_inputs == 1) 635 widget->active_input = 0; 636 637 return B_OK; 638 } 639 640 641 static status_t 642 hda_widget_get_associations(hda_audio_group* audioGroup) 643 { 644 uint32 index = 0; 645 for (uint32 i = 0; i < MAX_ASSOCIATIONS; i++) { 646 for (uint32 j = 0; j < audioGroup->widget_count; j++) { 647 if (index >= MAX_ASSOCIATIONS) { 648 TRACE("too many associations, bailing!\n"); 649 return B_ERROR; 650 } 651 hda_widget& widget = audioGroup->widgets[j]; 652 653 if (widget.type != WT_PIN_COMPLEX) 654 continue; 655 if (CONF_DEFAULT_ASSOCIATION(widget.d.pin.config) != i) 656 continue; 657 if (audioGroup->associations[index].pin_count == 0) { 658 audioGroup->associations[index].index = index; 659 audioGroup->associations[index].enabled = true; 660 } 661 uint32 sequence = CONF_DEFAULT_SEQUENCE(widget.d.pin.config); 662 if (audioGroup->associations[index].pins[sequence] != 0) { 663 audioGroup->associations[index].enabled = false; 664 } 665 audioGroup->associations[index].pins[sequence] = widget.node_id; 666 audioGroup->associations[index].pin_count++; 667 if (i == 15) 668 index++; 669 } 670 if (i != 15 && audioGroup->associations[index].pin_count != 0) 671 index++; 672 } 673 audioGroup->association_count = index; 674 675 return B_OK; 676 } 677 678 679 static uint32 680 hda_widget_prepare_pin_ctrl(hda_audio_group* audioGroup, hda_widget* widget, 681 bool isOutput) 682 { 683 uint32 ctrl = 0; 684 if (isOutput) 685 ctrl = PIN_ENABLE_HEAD_PHONE | PIN_ENABLE_OUTPUT; 686 else 687 ctrl = PIN_ENABLE_INPUT; 688 689 if (PIN_CAP_IS_VREF_CTRL_50_CAP(widget->d.pin.capabilities) 690 && (audioGroup->codec->quirks & (isOutput ? HDA_QUIRK_OVREF50 691 : HDA_QUIRK_IVREF50))) { 692 ctrl |= PIN_ENABLE_VREF_50; 693 TRACE("%s vref 50 enabled\n", isOutput ? "output" : "input"); 694 } 695 if (PIN_CAP_IS_VREF_CTRL_80_CAP(widget->d.pin.capabilities) 696 && (audioGroup->codec->quirks & (isOutput ? HDA_QUIRK_OVREF80 697 : HDA_QUIRK_IVREF80))) { 698 ctrl |= PIN_ENABLE_VREF_80; 699 TRACE("%s vref 80 enabled\n", isOutput ? "output" : "input"); 700 } 701 if (PIN_CAP_IS_VREF_CTRL_100_CAP(widget->d.pin.capabilities) 702 && (audioGroup->codec->quirks & (isOutput ? HDA_QUIRK_OVREF100 703 : HDA_QUIRK_IVREF100))) { 704 ctrl |= PIN_ENABLE_VREF_100; 705 TRACE("%s vref 100 enabled\n", isOutput ? "output" : "input"); 706 } 707 708 return ctrl; 709 } 710 711 712 // #pragma mark - audio group functions 713 714 715 static status_t 716 hda_codec_parse_audio_group(hda_audio_group* audioGroup) 717 { 718 corb_t verbs[3]; 719 uint32 resp[3]; 720 721 hda_codec* codec = audioGroup->codec; 722 uint32 codec_id = (codec->vendor_id << 16) | codec->product_id; 723 724 // Power up the audio function 725 verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id, 726 VID_SET_POWER_STATE, 0); 727 hda_send_verbs(audioGroup->codec, verbs, NULL, 1); 728 729 hda_widget_get_stream_support(audioGroup, &audioGroup->widget); 730 hda_widget_get_pm_support(audioGroup, &audioGroup->widget); 731 hda_widget_get_amplifier_capabilities(audioGroup, &audioGroup->widget); 732 733 verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id, 734 VID_GET_PARAMETER, PID_AUDIO_GROUP_CAP); 735 verbs[1] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id, 736 VID_GET_PARAMETER, PID_GPIO_COUNT); 737 verbs[2] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id, 738 VID_GET_PARAMETER, PID_SUB_NODE_COUNT); 739 740 if (hda_send_verbs(audioGroup->codec, verbs, resp, 3) != B_OK) 741 return B_ERROR; 742 743 TRACE("Audio Group: Output delay: %" B_PRIu32 " " 744 "samples, Input delay: %" B_PRIu32 " " 745 "samples, Beep Generator: %s\n", AUDIO_GROUP_CAP_OUTPUT_DELAY(resp[0]), 746 AUDIO_GROUP_CAP_INPUT_DELAY(resp[0]), 747 AUDIO_GROUP_CAP_BEEPGEN(resp[0]) ? "yes" : "no"); 748 749 TRACE(" #GPIO: %" B_PRIu32 ", #GPO: %" B_PRIu32 ", #GPI: %" B_PRIu32 ", " 750 "unsol: %s, wake: %s\n", 751 GPIO_COUNT_NUM_GPIO(resp[1]), GPIO_COUNT_NUM_GPO(resp[1]), 752 GPIO_COUNT_NUM_GPI(resp[1]), GPIO_COUNT_GPIUNSOL(resp[1]) ? "yes" : "no", 753 GPIO_COUNT_GPIWAKE(resp[1]) ? "yes" : "no"); 754 dump_widget_stream_support(audioGroup->widget); 755 756 audioGroup->gpio = resp[1]; 757 audioGroup->widget_start = SUB_NODE_COUNT_START(resp[2]); 758 audioGroup->widget_count = SUB_NODE_COUNT_TOTAL(resp[2]); 759 760 TRACE(" widget start %" B_PRIu32 ", count %" B_PRIu32 "\n", 761 audioGroup->widget_start, audioGroup->widget_count); 762 763 audioGroup->widgets = (hda_widget*)calloc(audioGroup->widget_count, 764 sizeof(*audioGroup->widgets)); 765 if (audioGroup->widgets == NULL) { 766 ERROR("ERROR: Not enough memory!\n"); 767 return B_NO_MEMORY; 768 } 769 770 // Iterate over all Widgets and collect info 771 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 772 hda_widget& widget = audioGroup->widgets[i]; 773 uint32 nodeID = audioGroup->widget_start + i; 774 uint32 capabilities; 775 776 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, VID_GET_PARAMETER, 777 PID_AUDIO_WIDGET_CAP); 778 if (hda_send_verbs(audioGroup->codec, verbs, &capabilities, 1) != B_OK) 779 return B_ERROR; 780 781 widget.type = (hda_widget_type)((capabilities & AUDIO_CAP_TYPE_MASK) 782 >> AUDIO_CAP_TYPE_SHIFT); 783 784 // Check specific node ids declared as inputs as beepers 785 switch (codec_id) { 786 case 0x11d41882: 787 case 0x11d41883: 788 case 0x11d41884: 789 case 0x11d4194a: 790 case 0x11d4194b: 791 case 0x11d41987: 792 case 0x11d41988: 793 case 0x11d4198b: 794 case 0x11d4989b: 795 if (nodeID == 26) 796 widget.type = WT_BEEP_GENERATOR; 797 break; 798 case 0x10ec0260: 799 if (nodeID == 23) 800 widget.type = WT_BEEP_GENERATOR; 801 break; 802 case 0x10ec0262: 803 case 0x10ec0268: 804 case 0x10ec0880: 805 case 0x10ec0882: 806 case 0x10ec0883: 807 case 0x10ec0885: 808 case 0x10ec0888: 809 case 0x10ec0889: 810 if (nodeID == 29) 811 widget.type = WT_BEEP_GENERATOR; 812 break; 813 } 814 widget.active_input = -1; 815 widget.capabilities.audio = capabilities; 816 widget.node_id = nodeID; 817 818 if ((capabilities & AUDIO_CAP_POWER_CONTROL) != 0) { 819 // We support power; switch us on! 820 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, 821 VID_SET_POWER_STATE, 0); 822 hda_send_verbs(audioGroup->codec, verbs, NULL, 1); 823 824 snooze(1000); 825 } 826 if ((capabilities & (AUDIO_CAP_INPUT_AMPLIFIER 827 | AUDIO_CAP_OUTPUT_AMPLIFIER)) != 0) { 828 hda_widget_get_amplifier_capabilities(audioGroup, &widget); 829 } 830 831 TRACE("%" B_PRIu32 ": %s\n", nodeID, get_widget_type_name(widget.type)); 832 833 switch (widget.type) { 834 case WT_AUDIO_OUTPUT: 835 case WT_AUDIO_INPUT: 836 hda_widget_get_stream_support(audioGroup, &widget); 837 dump_widget_stream_support(widget); 838 break; 839 840 case WT_PIN_COMPLEX: 841 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, 842 VID_GET_PARAMETER, PID_PIN_CAP); 843 if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) { 844 widget.d.pin.capabilities = resp[0]; 845 846 TRACE("\t%s%s\n", PIN_CAP_IS_INPUT(resp[0]) ? "[Input] " : "", 847 PIN_CAP_IS_OUTPUT(resp[0]) ? "[Output]" : ""); 848 } else { 849 ERROR("%s: Error getting Pin Complex IO\n", __func__); 850 } 851 852 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, 853 VID_GET_CONFIGURATION_DEFAULT, 0); 854 if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) { 855 widget.d.pin.config = resp[0]; 856 const char* location = 857 get_widget_location(CONF_DEFAULT_LOCATION(resp[0])); 858 TRACE("\t%s, %s%s%s, %s, %s, Association:%" B_PRIu32 "\n", 859 kPortConnector[CONF_DEFAULT_CONNECTIVITY(resp[0])], 860 location ? location : "", 861 location ? " " : "", 862 kDefaultDevice[CONF_DEFAULT_DEVICE(resp[0])], 863 kConnectionType[CONF_DEFAULT_CONNTYPE(resp[0])], 864 kJackColor[CONF_DEFAULT_COLOR(resp[0])], 865 CONF_DEFAULT_ASSOCIATION(resp[0])); 866 } 867 break; 868 869 case WT_VOLUME_KNOB: 870 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, 871 VID_SET_VOLUME_KNOB_CONTROL, 0x0); 872 hda_send_verbs(audioGroup->codec, verbs, NULL, 1); 873 break; 874 default: 875 break; 876 } 877 878 hda_widget_get_pm_support(audioGroup, &widget); 879 hda_widget_get_connections(audioGroup, &widget); 880 881 dump_widget_pm_support(widget); 882 dump_widget_audio_capabilities(capabilities); 883 dump_widget_amplifier_capabilities(widget, true); 884 dump_widget_amplifier_capabilities(widget, false); 885 dump_widget_inputs(widget); 886 } 887 888 hda_widget_get_associations(audioGroup); 889 890 // init the codecs 891 switch (codec_id) { 892 case 0x10ec0888: { 893 hda_verb_write(codec, 0x20, VID_SET_COEFFICIENT_INDEX, 0x0); 894 uint32 tmp; 895 hda_verb_read(codec, 0x20, VID_GET_PROCESSING_COEFFICIENT, &tmp); 896 hda_verb_write(codec, 0x20, VID_SET_COEFFICIENT_INDEX, 0x7); 897 hda_verb_write(codec, 0x20, VID_SET_PROCESSING_COEFFICIENT, 898 (tmp & 0xf0) == 0x20 ? 0x830 : 0x3030); 899 break; 900 } 901 } 902 903 return B_OK; 904 } 905 906 907 /*! Find output path for widget */ 908 static bool 909 hda_widget_find_output_path(hda_audio_group* audioGroup, hda_widget* widget, 910 uint32 depth, bool &alreadyUsed) 911 { 912 alreadyUsed = false; 913 914 if (widget == NULL || depth > 16) 915 return false; 916 917 switch (widget->type) { 918 case WT_AUDIO_OUTPUT: 919 widget->flags |= WIDGET_FLAG_OUTPUT_PATH; 920 TRACE(" %*soutput: added output widget %" B_PRIu32 "\n", 921 (int)depth * 2, "", widget->node_id); 922 return true; 923 924 case WT_AUDIO_MIXER: 925 case WT_AUDIO_SELECTOR: 926 { 927 // already used 928 if ((widget->flags & WIDGET_FLAG_OUTPUT_PATH) != 0) { 929 alreadyUsed = true; 930 return false; 931 } 932 933 // search for output in this path 934 bool found = false; 935 for (uint32 i = 0; i < widget->num_inputs; i++) { 936 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup, 937 widget->inputs[i]); 938 939 if (hda_widget_find_output_path(audioGroup, inputWidget, 940 depth + 1, alreadyUsed)) { 941 if (widget->active_input == -1) 942 widget->active_input = i; 943 944 widget->flags |= WIDGET_FLAG_OUTPUT_PATH; 945 TRACE(" %*soutput: added mixer/selector widget %" 946 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id); 947 found = true; 948 } 949 } 950 if (!found) TRACE(" %*soutput: not added mixer/selector widget %" 951 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id); 952 return found; 953 } 954 955 default: 956 return false; 957 } 958 } 959 960 961 /*! Find input path for widget */ 962 static bool 963 hda_widget_find_input_path(hda_audio_group* audioGroup, hda_widget* widget, 964 uint32 depth) 965 { 966 if (widget == NULL || depth > 16) 967 return false; 968 969 switch (widget->type) { 970 case WT_PIN_COMPLEX: 971 // already used 972 if ((widget->flags 973 & (WIDGET_FLAG_INPUT_PATH | WIDGET_FLAG_OUTPUT_PATH)) != 0) 974 return false; 975 976 if (PIN_CAP_IS_INPUT(widget->d.pin.capabilities)) { 977 switch (CONF_DEFAULT_DEVICE(widget->d.pin.config)) { 978 case PIN_DEV_CD: 979 case PIN_DEV_LINE_IN: 980 case PIN_DEV_MIC_IN: 981 widget->flags |= WIDGET_FLAG_INPUT_PATH; 982 TRACE(" %*sinput: added input widget %" B_PRIu32 "\n", 983 (int)depth * 2, "", widget->node_id); 984 return true; 985 break; 986 } 987 } 988 return false; 989 case WT_AUDIO_INPUT: 990 case WT_AUDIO_MIXER: 991 case WT_AUDIO_SELECTOR: 992 { 993 // already used 994 if ((widget->flags 995 & (WIDGET_FLAG_INPUT_PATH | WIDGET_FLAG_OUTPUT_PATH)) != 0) 996 return false; 997 998 // search for pin complex in this path 999 bool found = false; 1000 for (uint32 i = 0; i < widget->num_inputs; i++) { 1001 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup, 1002 widget->inputs[i]); 1003 1004 if (hda_widget_find_input_path(audioGroup, inputWidget, 1005 depth + 1)) { 1006 if (widget->active_input == -1) 1007 widget->active_input = i; 1008 1009 widget->flags |= WIDGET_FLAG_INPUT_PATH; 1010 TRACE(" %*sinput: added mixer/selector widget %" 1011 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id); 1012 found = true; 1013 } 1014 } 1015 if (!found) TRACE(" %*sinput: not added mixer/selector widget %" 1016 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id); 1017 return found; 1018 } 1019 1020 default: 1021 return false; 1022 } 1023 } 1024 1025 static bool 1026 hda_audio_group_build_output_tree(hda_audio_group* audioGroup, bool useMixer) 1027 { 1028 bool found = false; 1029 1030 TRACE("build output tree: %suse mixer\n", useMixer ? "" : "don't "); 1031 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1032 hda_widget& widget = audioGroup->widgets[i]; 1033 1034 if (widget.type != WT_PIN_COMPLEX 1035 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities)) 1036 continue; 1037 1038 int device = CONF_DEFAULT_DEVICE(widget.d.pin.config); 1039 if (device != PIN_DEV_HEAD_PHONE_OUT 1040 && device != PIN_DEV_DIGITAL_OTHER_OUT 1041 && device != PIN_DEV_SPEAKER 1042 && device != PIN_DEV_LINE_OUT) 1043 continue; 1044 1045 TRACE(" look at pin widget %" B_PRIu32 " (%" B_PRIu32 " inputs)\n", 1046 widget.node_id, widget.num_inputs); 1047 for (uint32 j = 0; j < widget.num_inputs; j++) { 1048 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup, 1049 widget.inputs[j]); 1050 TRACE(" try widget %" B_PRIu32 ": %p\n", 1051 widget.inputs[j], inputWidget); 1052 if (inputWidget == NULL) 1053 continue; 1054 1055 if (useMixer && inputWidget->type != WT_AUDIO_MIXER 1056 && inputWidget->type != WT_AUDIO_SELECTOR) 1057 continue; 1058 TRACE(" widget %" B_PRIu32 " is candidate\n", inputWidget->node_id); 1059 1060 bool alreadyUsed = false; 1061 if (hda_widget_find_output_path(audioGroup, inputWidget, 0, 1062 alreadyUsed) 1063 || (device == PIN_DEV_HEAD_PHONE_OUT && alreadyUsed)) { 1064 // find the output path to an audio output widget 1065 // or for headphones, an already used widget 1066 TRACE(" add pin widget %" B_PRIu32 "\n", widget.node_id); 1067 if (widget.active_input == -1) 1068 widget.active_input = j; 1069 widget.flags |= WIDGET_FLAG_OUTPUT_PATH; 1070 found = true; 1071 break; 1072 } 1073 } 1074 } 1075 1076 return found; 1077 } 1078 1079 1080 static bool 1081 hda_audio_group_build_input_tree(hda_audio_group* audioGroup) 1082 { 1083 bool found = false; 1084 1085 TRACE("build input tree\n"); 1086 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1087 hda_widget& widget = audioGroup->widgets[i]; 1088 1089 if (widget.type != WT_AUDIO_INPUT) 1090 continue; 1091 1092 TRACE(" look at input widget %" B_PRIu32 " (%" B_PRIu32 " inputs)\n", 1093 widget.node_id, widget.num_inputs); 1094 for (uint32 j = 0; j < widget.num_inputs; j++) { 1095 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup, 1096 widget.inputs[j]); 1097 TRACE(" try widget %" B_PRIu32 ": %p\n", 1098 widget.inputs[j], inputWidget); 1099 if (inputWidget == NULL) 1100 continue; 1101 1102 TRACE(" widget %" B_PRIu32 " is candidate\n", 1103 inputWidget->node_id); 1104 1105 if (hda_widget_find_input_path(audioGroup, inputWidget, 0)) { 1106 TRACE(" add pin widget %" B_PRIu32 "\n", widget.node_id); 1107 if (widget.active_input == -1) 1108 widget.active_input = j; 1109 widget.flags |= WIDGET_FLAG_INPUT_PATH; 1110 found = true; 1111 break; 1112 } 1113 } 1114 } 1115 1116 return found; 1117 } 1118 1119 1120 static status_t 1121 hda_audio_group_build_tree(hda_audio_group* audioGroup) 1122 { 1123 if (!hda_audio_group_build_output_tree(audioGroup, true)) { 1124 // didn't find a mixer path, try again without 1125 TRACE("try without mixer!\n"); 1126 if (!hda_audio_group_build_output_tree(audioGroup, false)) 1127 return ENODEV; 1128 } 1129 1130 if (!hda_audio_group_build_input_tree(audioGroup)) { 1131 ERROR("build input tree failed\n"); 1132 } 1133 1134 TRACE("build tree!\n"); 1135 1136 // select active connections 1137 1138 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1139 hda_widget& widget = audioGroup->widgets[i]; 1140 1141 if (widget.active_input == -1) 1142 widget.active_input = 0; 1143 if (widget.num_inputs < 2) 1144 continue; 1145 1146 if (widget.type != WT_AUDIO_INPUT 1147 && widget.type != WT_AUDIO_SELECTOR 1148 && widget.type != WT_PIN_COMPLEX) 1149 continue; 1150 1151 corb_t verb = MAKE_VERB(audioGroup->codec->addr, 1152 widget.node_id, VID_SET_CONNECTION_SELECT, widget.active_input); 1153 if (hda_send_verbs(audioGroup->codec, &verb, NULL, 1) != B_OK) 1154 ERROR("Setting output selector %" B_PRIu32 1155 " failed on widget %" B_PRIu32 "!\n", 1156 widget.active_input, widget.node_id); 1157 } 1158 1159 // GPIO 1160 uint32 gpio = 0; 1161 for (uint32 i = 0; i < GPIO_COUNT_NUM_GPIO(audioGroup->gpio) 1162 && i < HDA_QUIRK_GPIO_COUNT; i++) { 1163 if (audioGroup->codec->quirks & (1 << i)) { 1164 gpio |= (1 << i); 1165 } 1166 } 1167 1168 if (gpio != 0) { 1169 corb_t verb[] = { 1170 MAKE_VERB(audioGroup->codec->addr, 1171 audioGroup->widget.node_id, VID_SET_GPIO_DATA, gpio), 1172 MAKE_VERB(audioGroup->codec->addr, 1173 audioGroup->widget.node_id, VID_SET_GPIO_EN, gpio), 1174 MAKE_VERB(audioGroup->codec->addr, 1175 audioGroup->widget.node_id, VID_SET_GPIO_DIR, gpio) 1176 }; 1177 TRACE("Setting gpio 0x%" B_PRIx32 "\n", gpio); 1178 if (hda_send_verbs(audioGroup->codec, verb, NULL, 3) != B_OK) 1179 ERROR("Setting gpio failed!\n"); 1180 } 1181 1182 dump_audiogroup_widgets(audioGroup); 1183 1184 return B_OK; 1185 } 1186 1187 1188 static void 1189 hda_audio_group_switch_init(hda_audio_group* audioGroup) 1190 { 1191 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1192 hda_widget& widget = audioGroup->widgets[i]; 1193 if (widget.type != WT_PIN_COMPLEX) 1194 continue; 1195 1196 if ((widget.capabilities.audio & AUDIO_CAP_UNSOLICITED_RESPONSES) != 0 1197 && (widget.d.pin.capabilities & PIN_CAP_PRES_DETECT) != 0 1198 && (CONF_DEFAULT_MISC(widget.d.pin.config) & 1) == 0) { 1199 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id, 1200 VID_SET_UNSOLRESP, UNSOLRESP_ENABLE); 1201 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1202 TRACE("Enabled unsolicited responses on widget %" B_PRIu32 "\n", 1203 widget.node_id); 1204 } 1205 } 1206 } 1207 1208 1209 static void 1210 hda_audio_group_check_sense(hda_audio_group* audioGroup, bool disable) 1211 { 1212 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1213 hda_widget& widget = audioGroup->widgets[i]; 1214 1215 if (widget.type != WT_PIN_COMPLEX 1216 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities) 1217 || CONF_DEFAULT_DEVICE(widget.d.pin.config) 1218 != PIN_DEV_HEAD_PHONE_OUT) 1219 continue; 1220 1221 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id, 1222 VID_GET_PINSENSE, 0); 1223 uint32 response; 1224 hda_send_verbs(audioGroup->codec, &verb, &response, 1); 1225 disable = response & PIN_SENSE_PRESENCE_DETECT; 1226 TRACE("sensed pin widget %" B_PRIu32 ", %d\n", widget.node_id, disable); 1227 1228 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget, 1229 true); 1230 verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id, 1231 VID_SET_PIN_WIDGET_CONTROL, disable ? ctrl : 0); 1232 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1233 break; 1234 } 1235 1236 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1237 hda_widget& widget = audioGroup->widgets[i]; 1238 1239 if (widget.type != WT_PIN_COMPLEX 1240 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities)) 1241 continue; 1242 1243 int device = CONF_DEFAULT_DEVICE(widget.d.pin.config); 1244 if (device != PIN_DEV_AUX 1245 && device != PIN_DEV_SPEAKER 1246 && device != PIN_DEV_LINE_OUT) 1247 continue; 1248 1249 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget, 1250 true); 1251 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id, 1252 VID_SET_PIN_WIDGET_CONTROL, disable ? 0 : ctrl); 1253 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1254 } 1255 } 1256 1257 1258 static status_t 1259 hda_codec_switch_handler(hda_codec* codec) 1260 { 1261 while (acquire_sem(codec->unsol_response_sem) == B_OK) { 1262 uint32 response = codec->unsol_responses[codec->unsol_response_read++]; 1263 codec->unsol_response_read %= MAX_CODEC_UNSOL_RESPONSES; 1264 1265 bool disable = response & 1; 1266 hda_audio_group* audioGroup = codec->audio_groups[0]; 1267 hda_audio_group_check_sense(audioGroup, disable); 1268 } 1269 return B_OK; 1270 } 1271 1272 1273 static void 1274 hda_codec_delete_audio_group(hda_audio_group* audioGroup) 1275 { 1276 if (audioGroup == NULL) 1277 return; 1278 1279 if (audioGroup->playback_stream != NULL) 1280 hda_stream_delete(audioGroup->playback_stream); 1281 1282 if (audioGroup->record_stream != NULL) 1283 hda_stream_delete(audioGroup->record_stream); 1284 free(audioGroup->multi); 1285 free(audioGroup->widgets); 1286 free(audioGroup); 1287 } 1288 1289 1290 static status_t 1291 hda_codec_new_audio_group(hda_codec* codec, uint32 audioGroupNodeID) 1292 { 1293 hda_audio_group* audioGroup = (hda_audio_group*)calloc(1, 1294 sizeof(hda_audio_group)); 1295 if (audioGroup == NULL) 1296 return B_NO_MEMORY; 1297 1298 // Setup minimal info needed by hda_codec_parse_afg 1299 audioGroup->widget.node_id = audioGroupNodeID; 1300 audioGroup->codec = codec; 1301 audioGroup->multi = (hda_multi*)calloc(1, 1302 sizeof(hda_multi)); 1303 if (audioGroup->multi == NULL) { 1304 free(audioGroup); 1305 return B_NO_MEMORY; 1306 } 1307 audioGroup->multi->group = audioGroup; 1308 1309 // Parse all widgets in Audio Function Group 1310 status_t status = hda_codec_parse_audio_group(audioGroup); 1311 if (status != B_OK) 1312 goto err; 1313 1314 // Setup for worst-case scenario; we cannot find any output Pin Widgets 1315 status = ENODEV; 1316 1317 if (hda_audio_group_build_tree(audioGroup) != B_OK) 1318 goto err; 1319 hda_audio_group_switch_init(audioGroup); 1320 1321 audioGroup->playback_stream = hda_stream_new(audioGroup, STREAM_PLAYBACK); 1322 audioGroup->record_stream = hda_stream_new(audioGroup, STREAM_RECORD); 1323 TRACE("streams playback %p, record %p\n", audioGroup->playback_stream, 1324 audioGroup->record_stream); 1325 1326 if (audioGroup->playback_stream != NULL 1327 || audioGroup->record_stream != NULL) { 1328 codec->audio_groups[codec->num_audio_groups++] = audioGroup; 1329 hda_audio_group_check_sense(audioGroup, false); 1330 return B_OK; 1331 } 1332 1333 err: 1334 free(audioGroup->widgets); 1335 free(audioGroup); 1336 return status; 1337 } 1338 1339 1340 // #pragma mark - 1341 1342 1343 status_t 1344 hda_audio_group_get_widgets(hda_audio_group* audioGroup, hda_stream* stream) 1345 { 1346 hda_widget_type type; 1347 uint32 flags; 1348 1349 if (stream->type == STREAM_PLAYBACK) { 1350 type = WT_AUDIO_OUTPUT; 1351 flags = WIDGET_FLAG_OUTPUT_PATH; 1352 } else { 1353 // record 1354 type = WT_AUDIO_INPUT; 1355 flags = WIDGET_FLAG_INPUT_PATH; 1356 } 1357 1358 uint32 count = 0; 1359 1360 for (uint32 i = 0; i < audioGroup->widget_count && count < MAX_IO_WIDGETS; 1361 i++) { 1362 hda_widget& widget = audioGroup->widgets[i]; 1363 1364 if ((widget.flags & flags) != 0) { 1365 if (widget.type == WT_PIN_COMPLEX) { 1366 stream->pin_widget = widget.node_id; 1367 1368 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget, 1369 flags == WIDGET_FLAG_OUTPUT_PATH); 1370 1371 TRACE("ENABLE pin widget %" B_PRIu32 "\n", widget.node_id); 1372 // FIXME: Force Pin Widget to unmute; enable hp/output 1373 corb_t verb = MAKE_VERB(audioGroup->codec->addr, 1374 widget.node_id, 1375 VID_SET_PIN_WIDGET_CONTROL, ctrl); 1376 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1377 1378 if (PIN_CAP_IS_EAPD_CAP(widget.d.pin.capabilities)) { 1379 uint32 result; 1380 verb = MAKE_VERB(audioGroup->codec->addr, 1381 widget.node_id, VID_GET_EAPDBTL_EN, 0); 1382 if (hda_send_verbs(audioGroup->codec, &verb, 1383 &result, 1) == B_OK) { 1384 result &= 0xff; 1385 verb = MAKE_VERB(audioGroup->codec->addr, 1386 widget.node_id, VID_SET_EAPDBTL_EN, 1387 result | EAPDBTL_ENABLE_EAPD); 1388 hda_send_verbs(audioGroup->codec, 1389 &verb, NULL, 1); 1390 TRACE("ENABLE EAPD pin widget %" B_PRIu32 "\n", 1391 widget.node_id); 1392 } 1393 } 1394 } 1395 1396 if (widget.capabilities.output_amplifier != 0) { 1397 TRACE("UNMUTE/SET OUTPUT GAIN widget %" B_PRIu32 " " 1398 "(offset %" B_PRIu32 ")\n", widget.node_id, 1399 AMP_CAP_OFFSET(widget.capabilities.output_amplifier)); 1400 corb_t verb = MAKE_VERB(audioGroup->codec->addr, 1401 widget.node_id, 1402 VID_SET_AMPLIFIER_GAIN_MUTE, 1403 AMP_SET_OUTPUT | AMP_SET_LEFT_CHANNEL 1404 | AMP_SET_RIGHT_CHANNEL 1405 | AMP_CAP_OFFSET(widget.capabilities.output_amplifier)); 1406 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1407 } 1408 if (widget.capabilities.input_amplifier != 0) { 1409 TRACE("UNMUTE/SET INPUT GAIN widget %" B_PRIu32 " " 1410 "(offset %" B_PRIu32 ")\n", widget.node_id, 1411 AMP_CAP_OFFSET(widget.capabilities.input_amplifier)); 1412 for (uint32 i = 0; i < widget.num_inputs; i++) { 1413 corb_t verb = MAKE_VERB(audioGroup->codec->addr, 1414 widget.node_id, 1415 VID_SET_AMPLIFIER_GAIN_MUTE, 1416 AMP_SET_INPUT | AMP_SET_LEFT_CHANNEL 1417 | AMP_SET_RIGHT_CHANNEL 1418 | AMP_SET_INPUT_INDEX(i) 1419 | ((widget.active_input == (int32)i) ? 0 : AMP_MUTE) 1420 | AMP_CAP_OFFSET(widget.capabilities.input_amplifier)); 1421 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1422 } 1423 } 1424 } 1425 1426 if (widget.type != type || (widget.flags & flags) == 0 1427 || (widget.capabilities.audio 1428 & (AUDIO_CAP_STEREO | AUDIO_CAP_DIGITAL)) != AUDIO_CAP_STEREO 1429 || widget.d.io.formats == 0) 1430 continue; 1431 1432 if (count == 0) { 1433 stream->sample_format = widget.d.io.formats; 1434 stream->sample_rate = widget.d.io.rates; 1435 } else { 1436 stream->sample_format &= widget.d.io.formats; 1437 stream->sample_rate &= widget.d.io.rates; 1438 } 1439 1440 stream->io_widgets[count++] = widget.node_id; 1441 } 1442 1443 if (count == 0) 1444 return B_ENTRY_NOT_FOUND; 1445 1446 stream->num_io_widgets = count; 1447 return B_OK; 1448 } 1449 1450 1451 void 1452 hda_codec_delete(hda_codec* codec) 1453 { 1454 if (codec == NULL) 1455 return; 1456 1457 delete_sem(codec->response_sem); 1458 delete_sem(codec->unsol_response_sem); 1459 1460 int32 result; 1461 wait_for_thread(codec->unsol_response_thread, &result); 1462 1463 for (uint32 i = 0; i < codec->num_audio_groups; i++) { 1464 hda_codec_delete_audio_group(codec->audio_groups[i]); 1465 codec->audio_groups[i] = NULL; 1466 } 1467 1468 free(codec); 1469 } 1470 1471 1472 hda_codec* 1473 hda_codec_new(hda_controller* controller, uint32 codecAddress) 1474 { 1475 if (codecAddress > HDA_MAX_CODECS) 1476 return NULL; 1477 1478 hda_codec* codec = (hda_codec*)calloc(1, sizeof(hda_codec)); 1479 if (codec == NULL) { 1480 ERROR("Failed to alloc a codec\n"); 1481 return NULL; 1482 } 1483 1484 status_t status; 1485 1486 codec->controller = controller; 1487 codec->addr = codecAddress; 1488 codec->response_sem = create_sem(0, "hda_codec_response_sem"); 1489 if (codec->response_sem < B_OK) { 1490 ERROR("Failed to create semaphore\n"); 1491 goto err; 1492 } 1493 controller->codecs[codecAddress] = codec; 1494 1495 codec->unsol_response_sem = create_sem(0, "hda_codec_unsol_response_sem"); 1496 if (codec->unsol_response_sem < B_OK) { 1497 ERROR("Failed to create semaphore\n"); 1498 goto err; 1499 } 1500 codec->unsol_response_read = 0; 1501 codec->unsol_response_write = 0; 1502 1503 struct { 1504 uint32 device : 16; 1505 uint32 vendor : 16; 1506 uint32 subsystem : 32; 1507 uint32 stepping : 8; 1508 uint32 revision : 8; 1509 uint32 minor : 4; 1510 uint32 major : 4; 1511 uint32 _reserved0 : 8; 1512 uint32 count : 8; 1513 uint32 _reserved1 : 8; 1514 uint32 start : 8; 1515 uint32 _reserved2 : 8; 1516 } response; 1517 1518 corb_t verbs[4]; 1519 verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID); 1520 verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUBSYSTEM_ID); 1521 verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID); 1522 verbs[3] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, 1523 PID_SUB_NODE_COUNT); 1524 1525 status = hda_send_verbs(codec, verbs, (uint32*)&response, 4); 1526 if (status != B_OK) { 1527 ERROR("Failed to get vendor and revision parameters: %s\n", 1528 strerror(status)); 1529 goto err; 1530 } 1531 1532 codec->vendor_id = response.vendor; 1533 codec->subsystem_id = response.subsystem; 1534 codec->product_id = response.device; 1535 codec->stepping = response.stepping; 1536 codec->revision = response.revision; 1537 codec->minor = response.minor; 1538 codec->major = response.major; 1539 hda_codec_get_quirks(codec); 1540 1541 for (uint32 nodeID = response.start; 1542 nodeID < response.start + response.count; nodeID++) { 1543 struct { 1544 uint32 groupType; 1545 uint32 subsystem; 1546 } functionResponse; 1547 verbs[0] = MAKE_VERB(codecAddress, nodeID, VID_GET_PARAMETER, 1548 PID_FUNCTION_GROUP_TYPE); 1549 verbs[1] = MAKE_VERB(codecAddress, nodeID, VID_GET_SUBSYSTEMID, 0); 1550 1551 if (hda_send_verbs(codec, verbs, (uint32*)&functionResponse, 2) != B_OK) { 1552 ERROR("Failed to get function group type\n"); 1553 goto err; 1554 } 1555 1556 if ((functionResponse.groupType & FUNCTION_GROUP_NODETYPE_MASK) 1557 == FUNCTION_GROUP_NODETYPE_AUDIO) { 1558 // Found an Audio Function Group! 1559 if (response.subsystem == 0 && functionResponse.subsystem != 0) { 1560 // Update our subsystem, and re-check quirks for this codec 1561 codec->subsystem_id = functionResponse.subsystem; 1562 hda_codec_get_quirks(codec); 1563 } 1564 1565 status_t status = hda_codec_new_audio_group(codec, nodeID); 1566 if (status != B_OK) { 1567 ERROR("Failed to setup new audio function group (%s)!\n", 1568 strerror(status)); 1569 goto err; 1570 } 1571 } 1572 } 1573 1574 TRACE("Codec %" B_PRIu32 " Vendor: %04" B_PRIx32 " " 1575 "Product: %04" B_PRIx32 " " 1576 "Subsystem: %08" B_PRIx32 ", " 1577 "Revision: %" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 " " 1578 "Quirks: %04" B_PRIx32 "\n", 1579 codecAddress, 1580 response.vendor, 1581 response.device, 1582 codec->subsystem_id, 1583 response.major, response.minor, response.revision, response.stepping, 1584 codec->quirks); 1585 1586 codec->unsol_response_thread = spawn_kernel_thread( 1587 (status_t(*)(void*))hda_codec_switch_handler, 1588 "hda_codec_unsol_thread", B_LOW_PRIORITY, codec); 1589 if (codec->unsol_response_thread < B_OK) { 1590 ERROR("Failed to spawn thread\n"); 1591 goto err; 1592 } 1593 resume_thread(codec->unsol_response_thread); 1594 1595 return codec; 1596 1597 err: 1598 controller->codecs[codecAddress] = NULL; 1599 hda_codec_delete(codec); 1600 return NULL; 1601 } 1602