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 hda_widget_get_stream_support(audioGroup, &audioGroup->widget); 724 hda_widget_get_pm_support(audioGroup, &audioGroup->widget); 725 hda_widget_get_amplifier_capabilities(audioGroup, &audioGroup->widget); 726 727 verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id, 728 VID_GET_PARAMETER, PID_AUDIO_GROUP_CAP); 729 verbs[1] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id, 730 VID_GET_PARAMETER, PID_GPIO_COUNT); 731 verbs[2] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id, 732 VID_GET_PARAMETER, PID_SUB_NODE_COUNT); 733 734 if (hda_send_verbs(audioGroup->codec, verbs, resp, 3) != B_OK) 735 return B_ERROR; 736 737 TRACE("Audio Group: Output delay: %" B_PRIu32 " " 738 "samples, Input delay: %" B_PRIu32 " " 739 "samples, Beep Generator: %s\n", AUDIO_GROUP_CAP_OUTPUT_DELAY(resp[0]), 740 AUDIO_GROUP_CAP_INPUT_DELAY(resp[0]), 741 AUDIO_GROUP_CAP_BEEPGEN(resp[0]) ? "yes" : "no"); 742 743 TRACE(" #GPIO: %" B_PRIu32 ", #GPO: %" B_PRIu32 ", #GPI: %" B_PRIu32 ", " 744 "unsol: %s, wake: %s\n", 745 GPIO_COUNT_NUM_GPIO(resp[1]), GPIO_COUNT_NUM_GPO(resp[1]), 746 GPIO_COUNT_NUM_GPI(resp[1]), GPIO_COUNT_GPIUNSOL(resp[1]) ? "yes" : "no", 747 GPIO_COUNT_GPIWAKE(resp[1]) ? "yes" : "no"); 748 dump_widget_stream_support(audioGroup->widget); 749 750 audioGroup->gpio = resp[1]; 751 audioGroup->widget_start = SUB_NODE_COUNT_START(resp[2]); 752 audioGroup->widget_count = SUB_NODE_COUNT_TOTAL(resp[2]); 753 754 TRACE(" widget start %" B_PRIu32 ", count %" B_PRIu32 "\n", 755 audioGroup->widget_start, audioGroup->widget_count); 756 757 audioGroup->widgets = (hda_widget*)calloc(audioGroup->widget_count, 758 sizeof(*audioGroup->widgets)); 759 if (audioGroup->widgets == NULL) { 760 ERROR("ERROR: Not enough memory!\n"); 761 return B_NO_MEMORY; 762 } 763 764 // Iterate over all Widgets and collect info 765 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 766 hda_widget& widget = audioGroup->widgets[i]; 767 uint32 nodeID = audioGroup->widget_start + i; 768 uint32 capabilities; 769 770 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, VID_GET_PARAMETER, 771 PID_AUDIO_WIDGET_CAP); 772 if (hda_send_verbs(audioGroup->codec, verbs, &capabilities, 1) != B_OK) 773 return B_ERROR; 774 775 widget.type = (hda_widget_type)((capabilities & AUDIO_CAP_TYPE_MASK) 776 >> AUDIO_CAP_TYPE_SHIFT); 777 778 // Check specific node ids declared as inputs as beepers 779 switch (codec_id) { 780 case 0x11d41882: 781 case 0x11d41883: 782 case 0x11d41884: 783 case 0x11d4194a: 784 case 0x11d4194b: 785 case 0x11d41987: 786 case 0x11d41988: 787 case 0x11d4198b: 788 case 0x11d4989b: 789 if (nodeID == 26) 790 widget.type = WT_BEEP_GENERATOR; 791 break; 792 case 0x10ec0260: 793 if (nodeID == 23) 794 widget.type = WT_BEEP_GENERATOR; 795 break; 796 case 0x10ec0262: 797 case 0x10ec0268: 798 case 0x10ec0880: 799 case 0x10ec0882: 800 case 0x10ec0883: 801 case 0x10ec0885: 802 case 0x10ec0888: 803 case 0x10ec0889: 804 if (nodeID == 29) 805 widget.type = WT_BEEP_GENERATOR; 806 break; 807 } 808 widget.active_input = -1; 809 widget.capabilities.audio = capabilities; 810 widget.node_id = nodeID; 811 812 if ((capabilities & AUDIO_CAP_POWER_CONTROL) != 0) { 813 // We support power; switch us on! 814 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, 815 VID_SET_POWER_STATE, 0); 816 hda_send_verbs(audioGroup->codec, verbs, NULL, 1); 817 818 snooze(1000); 819 } 820 if ((capabilities & (AUDIO_CAP_INPUT_AMPLIFIER 821 | AUDIO_CAP_OUTPUT_AMPLIFIER)) != 0) { 822 hda_widget_get_amplifier_capabilities(audioGroup, &widget); 823 } 824 825 TRACE("%" B_PRIu32 ": %s\n", nodeID, get_widget_type_name(widget.type)); 826 827 switch (widget.type) { 828 case WT_AUDIO_OUTPUT: 829 case WT_AUDIO_INPUT: 830 hda_widget_get_stream_support(audioGroup, &widget); 831 dump_widget_stream_support(widget); 832 break; 833 834 case WT_PIN_COMPLEX: 835 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, 836 VID_GET_PARAMETER, PID_PIN_CAP); 837 if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) { 838 widget.d.pin.capabilities = resp[0]; 839 840 TRACE("\t%s%s\n", PIN_CAP_IS_INPUT(resp[0]) ? "[Input] " : "", 841 PIN_CAP_IS_OUTPUT(resp[0]) ? "[Output]" : ""); 842 } else { 843 ERROR("%s: Error getting Pin Complex IO\n", __func__); 844 } 845 846 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, 847 VID_GET_CONFIGURATION_DEFAULT, 0); 848 if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) { 849 widget.d.pin.config = resp[0]; 850 const char* location = 851 get_widget_location(CONF_DEFAULT_LOCATION(resp[0])); 852 TRACE("\t%s, %s%s%s, %s, %s, Association:%" B_PRIu32 "\n", 853 kPortConnector[CONF_DEFAULT_CONNECTIVITY(resp[0])], 854 location ? location : "", 855 location ? " " : "", 856 kDefaultDevice[CONF_DEFAULT_DEVICE(resp[0])], 857 kConnectionType[CONF_DEFAULT_CONNTYPE(resp[0])], 858 kJackColor[CONF_DEFAULT_COLOR(resp[0])], 859 CONF_DEFAULT_ASSOCIATION(resp[0])); 860 } 861 break; 862 863 case WT_VOLUME_KNOB: 864 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, 865 VID_SET_VOLUME_KNOB_CONTROL, 0x0); 866 hda_send_verbs(audioGroup->codec, verbs, NULL, 1); 867 break; 868 default: 869 break; 870 } 871 872 hda_widget_get_pm_support(audioGroup, &widget); 873 hda_widget_get_connections(audioGroup, &widget); 874 875 dump_widget_pm_support(widget); 876 dump_widget_audio_capabilities(capabilities); 877 dump_widget_amplifier_capabilities(widget, true); 878 dump_widget_amplifier_capabilities(widget, false); 879 dump_widget_inputs(widget); 880 } 881 882 hda_widget_get_associations(audioGroup); 883 884 // init the codecs 885 switch (codec_id) { 886 case 0x10ec0888: { 887 hda_verb_write(codec, 0x20, VID_SET_COEFFICIENT_INDEX, 0x0); 888 uint32 tmp; 889 hda_verb_read(codec, 0x20, VID_GET_PROCESSING_COEFFICIENT, &tmp); 890 hda_verb_write(codec, 0x20, VID_SET_COEFFICIENT_INDEX, 0x7); 891 hda_verb_write(codec, 0x20, VID_SET_PROCESSING_COEFFICIENT, 892 (tmp & 0xf0) == 0x20 ? 0x830 : 0x3030); 893 break; 894 } 895 } 896 897 return B_OK; 898 } 899 900 901 /*! Find output path for widget */ 902 static bool 903 hda_widget_find_output_path(hda_audio_group* audioGroup, hda_widget* widget, 904 uint32 depth, bool &alreadyUsed) 905 { 906 alreadyUsed = false; 907 908 if (widget == NULL || depth > 16) 909 return false; 910 911 switch (widget->type) { 912 case WT_AUDIO_OUTPUT: 913 widget->flags |= WIDGET_FLAG_OUTPUT_PATH; 914 TRACE(" %*soutput: added output widget %" B_PRIu32 "\n", 915 (int)depth * 2, "", widget->node_id); 916 return true; 917 918 case WT_AUDIO_MIXER: 919 case WT_AUDIO_SELECTOR: 920 { 921 // already used 922 if ((widget->flags & WIDGET_FLAG_OUTPUT_PATH) != 0) { 923 alreadyUsed = true; 924 return false; 925 } 926 927 // search for output in this path 928 bool found = false; 929 for (uint32 i = 0; i < widget->num_inputs; i++) { 930 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup, 931 widget->inputs[i]); 932 933 if (hda_widget_find_output_path(audioGroup, inputWidget, 934 depth + 1, alreadyUsed)) { 935 if (widget->active_input == -1) 936 widget->active_input = i; 937 938 widget->flags |= WIDGET_FLAG_OUTPUT_PATH; 939 TRACE(" %*soutput: added mixer/selector widget %" 940 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id); 941 found = true; 942 } 943 } 944 if (!found) TRACE(" %*soutput: not added mixer/selector widget %" 945 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id); 946 return found; 947 } 948 949 default: 950 return false; 951 } 952 } 953 954 955 /*! Find input path for widget */ 956 static bool 957 hda_widget_find_input_path(hda_audio_group* audioGroup, hda_widget* widget, 958 uint32 depth) 959 { 960 if (widget == NULL || depth > 16) 961 return false; 962 963 switch (widget->type) { 964 case WT_PIN_COMPLEX: 965 // already used 966 if ((widget->flags 967 & (WIDGET_FLAG_INPUT_PATH | WIDGET_FLAG_OUTPUT_PATH)) != 0) 968 return false; 969 970 if (PIN_CAP_IS_INPUT(widget->d.pin.capabilities)) { 971 switch (CONF_DEFAULT_DEVICE(widget->d.pin.config)) { 972 case PIN_DEV_CD: 973 case PIN_DEV_LINE_IN: 974 case PIN_DEV_MIC_IN: 975 widget->flags |= WIDGET_FLAG_INPUT_PATH; 976 TRACE(" %*sinput: added input widget %" B_PRIu32 "\n", 977 (int)depth * 2, "", widget->node_id); 978 return true; 979 break; 980 } 981 } 982 return false; 983 case WT_AUDIO_INPUT: 984 case WT_AUDIO_MIXER: 985 case WT_AUDIO_SELECTOR: 986 { 987 // already used 988 if ((widget->flags 989 & (WIDGET_FLAG_INPUT_PATH | WIDGET_FLAG_OUTPUT_PATH)) != 0) 990 return false; 991 992 // search for pin complex in this path 993 bool found = false; 994 for (uint32 i = 0; i < widget->num_inputs; i++) { 995 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup, 996 widget->inputs[i]); 997 998 if (hda_widget_find_input_path(audioGroup, inputWidget, 999 depth + 1)) { 1000 if (widget->active_input == -1) 1001 widget->active_input = i; 1002 1003 widget->flags |= WIDGET_FLAG_INPUT_PATH; 1004 TRACE(" %*sinput: added mixer/selector widget %" 1005 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id); 1006 found = true; 1007 } 1008 } 1009 if (!found) TRACE(" %*sinput: not added mixer/selector widget %" 1010 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id); 1011 return found; 1012 } 1013 1014 default: 1015 return false; 1016 } 1017 } 1018 1019 static bool 1020 hda_audio_group_build_output_tree(hda_audio_group* audioGroup, bool useMixer) 1021 { 1022 bool found = false; 1023 1024 TRACE("build output tree: %suse mixer\n", useMixer ? "" : "don't "); 1025 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1026 hda_widget& widget = audioGroup->widgets[i]; 1027 1028 if (widget.type != WT_PIN_COMPLEX 1029 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities)) 1030 continue; 1031 1032 int device = CONF_DEFAULT_DEVICE(widget.d.pin.config); 1033 if (device != PIN_DEV_HEAD_PHONE_OUT 1034 && device != PIN_DEV_DIGITAL_OTHER_OUT 1035 && device != PIN_DEV_SPEAKER 1036 && device != PIN_DEV_LINE_OUT) 1037 continue; 1038 1039 TRACE(" look at pin widget %" B_PRIu32 " (%" B_PRIu32 " inputs)\n", 1040 widget.node_id, widget.num_inputs); 1041 for (uint32 j = 0; j < widget.num_inputs; j++) { 1042 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup, 1043 widget.inputs[j]); 1044 TRACE(" try widget %" B_PRIu32 ": %p\n", 1045 widget.inputs[j], inputWidget); 1046 if (inputWidget == NULL) 1047 continue; 1048 1049 if (useMixer && inputWidget->type != WT_AUDIO_MIXER 1050 && inputWidget->type != WT_AUDIO_SELECTOR) 1051 continue; 1052 TRACE(" widget %" B_PRIu32 " is candidate\n", inputWidget->node_id); 1053 1054 bool alreadyUsed = false; 1055 if (hda_widget_find_output_path(audioGroup, inputWidget, 0, 1056 alreadyUsed) 1057 || (device == PIN_DEV_HEAD_PHONE_OUT && alreadyUsed)) { 1058 // find the output path to an audio output widget 1059 // or for headphones, an already used widget 1060 TRACE(" add pin widget %" B_PRIu32 "\n", widget.node_id); 1061 if (widget.active_input == -1) 1062 widget.active_input = j; 1063 widget.flags |= WIDGET_FLAG_OUTPUT_PATH; 1064 found = true; 1065 break; 1066 } 1067 } 1068 } 1069 1070 return found; 1071 } 1072 1073 1074 static bool 1075 hda_audio_group_build_input_tree(hda_audio_group* audioGroup) 1076 { 1077 bool found = false; 1078 1079 TRACE("build input tree\n"); 1080 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1081 hda_widget& widget = audioGroup->widgets[i]; 1082 1083 if (widget.type != WT_AUDIO_INPUT) 1084 continue; 1085 1086 TRACE(" look at input widget %" B_PRIu32 " (%" B_PRIu32 " inputs)\n", 1087 widget.node_id, widget.num_inputs); 1088 for (uint32 j = 0; j < widget.num_inputs; j++) { 1089 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup, 1090 widget.inputs[j]); 1091 TRACE(" try widget %" B_PRIu32 ": %p\n", 1092 widget.inputs[j], inputWidget); 1093 if (inputWidget == NULL) 1094 continue; 1095 1096 TRACE(" widget %" B_PRIu32 " is candidate\n", 1097 inputWidget->node_id); 1098 1099 if (hda_widget_find_input_path(audioGroup, inputWidget, 0)) { 1100 TRACE(" add pin widget %" B_PRIu32 "\n", widget.node_id); 1101 if (widget.active_input == -1) 1102 widget.active_input = j; 1103 widget.flags |= WIDGET_FLAG_INPUT_PATH; 1104 found = true; 1105 break; 1106 } 1107 } 1108 } 1109 1110 return found; 1111 } 1112 1113 1114 static status_t 1115 hda_audio_group_build_tree(hda_audio_group* audioGroup) 1116 { 1117 if (!hda_audio_group_build_output_tree(audioGroup, true)) { 1118 // didn't find a mixer path, try again without 1119 TRACE("try without mixer!\n"); 1120 if (!hda_audio_group_build_output_tree(audioGroup, false)) 1121 return ENODEV; 1122 } 1123 1124 if (!hda_audio_group_build_input_tree(audioGroup)) { 1125 ERROR("build input tree failed\n"); 1126 } 1127 1128 TRACE("build tree!\n"); 1129 1130 // select active connections 1131 1132 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1133 hda_widget& widget = audioGroup->widgets[i]; 1134 1135 if (widget.active_input == -1) 1136 widget.active_input = 0; 1137 if (widget.num_inputs < 2) 1138 continue; 1139 1140 if (widget.type != WT_AUDIO_INPUT 1141 && widget.type != WT_AUDIO_SELECTOR 1142 && widget.type != WT_PIN_COMPLEX) 1143 continue; 1144 1145 corb_t verb = MAKE_VERB(audioGroup->codec->addr, 1146 widget.node_id, VID_SET_CONNECTION_SELECT, widget.active_input); 1147 if (hda_send_verbs(audioGroup->codec, &verb, NULL, 1) != B_OK) 1148 ERROR("Setting output selector %" B_PRIu32 1149 " failed on widget %" B_PRIu32 "!\n", 1150 widget.active_input, widget.node_id); 1151 } 1152 1153 // GPIO 1154 uint32 gpio = 0; 1155 for (uint32 i = 0; i < GPIO_COUNT_NUM_GPIO(audioGroup->gpio) 1156 && i < HDA_QUIRK_GPIO_COUNT; i++) { 1157 if (audioGroup->codec->quirks & (1 << i)) { 1158 gpio |= (1 << i); 1159 } 1160 } 1161 1162 if (gpio != 0) { 1163 corb_t verb[] = { 1164 MAKE_VERB(audioGroup->codec->addr, 1165 audioGroup->widget.node_id, VID_SET_GPIO_DATA, gpio), 1166 MAKE_VERB(audioGroup->codec->addr, 1167 audioGroup->widget.node_id, VID_SET_GPIO_EN, gpio), 1168 MAKE_VERB(audioGroup->codec->addr, 1169 audioGroup->widget.node_id, VID_SET_GPIO_DIR, gpio) 1170 }; 1171 TRACE("Setting gpio 0x%" B_PRIx32 "\n", gpio); 1172 if (hda_send_verbs(audioGroup->codec, verb, NULL, 3) != B_OK) 1173 ERROR("Setting gpio failed!\n"); 1174 } 1175 1176 dump_audiogroup_widgets(audioGroup); 1177 1178 return B_OK; 1179 } 1180 1181 1182 static void 1183 hda_audio_group_switch_init(hda_audio_group* audioGroup) 1184 { 1185 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1186 hda_widget& widget = audioGroup->widgets[i]; 1187 if (widget.type != WT_PIN_COMPLEX) 1188 continue; 1189 1190 if ((widget.capabilities.audio & AUDIO_CAP_UNSOLICITED_RESPONSES) != 0 1191 && (widget.d.pin.capabilities & PIN_CAP_PRES_DETECT) != 0 1192 && (CONF_DEFAULT_MISC(widget.d.pin.config) & 1) == 0) { 1193 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id, 1194 VID_SET_UNSOLRESP, UNSOLRESP_ENABLE); 1195 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1196 TRACE("Enabled unsolicited responses on widget %" B_PRIu32 "\n", 1197 widget.node_id); 1198 } 1199 } 1200 } 1201 1202 1203 static void 1204 hda_audio_group_check_sense(hda_audio_group* audioGroup, bool disable) 1205 { 1206 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1207 hda_widget& widget = audioGroup->widgets[i]; 1208 1209 if (widget.type != WT_PIN_COMPLEX 1210 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities) 1211 || CONF_DEFAULT_DEVICE(widget.d.pin.config) 1212 != PIN_DEV_HEAD_PHONE_OUT) 1213 continue; 1214 1215 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id, 1216 VID_GET_PINSENSE, 0); 1217 uint32 response; 1218 hda_send_verbs(audioGroup->codec, &verb, &response, 1); 1219 disable = response & PIN_SENSE_PRESENCE_DETECT; 1220 TRACE("sensed pin widget %" B_PRIu32 ", %d\n", widget.node_id, disable); 1221 1222 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget, 1223 true); 1224 verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id, 1225 VID_SET_PIN_WIDGET_CONTROL, disable ? ctrl : 0); 1226 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1227 break; 1228 } 1229 1230 for (uint32 i = 0; i < audioGroup->widget_count; i++) { 1231 hda_widget& widget = audioGroup->widgets[i]; 1232 1233 if (widget.type != WT_PIN_COMPLEX 1234 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities)) 1235 continue; 1236 1237 int device = CONF_DEFAULT_DEVICE(widget.d.pin.config); 1238 if (device != PIN_DEV_AUX 1239 && device != PIN_DEV_SPEAKER 1240 && device != PIN_DEV_LINE_OUT) 1241 continue; 1242 1243 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget, 1244 true); 1245 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id, 1246 VID_SET_PIN_WIDGET_CONTROL, disable ? 0 : ctrl); 1247 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1248 } 1249 } 1250 1251 1252 static status_t 1253 hda_codec_switch_handler(hda_codec* codec) 1254 { 1255 while (acquire_sem(codec->unsol_response_sem) == B_OK) { 1256 uint32 response = codec->unsol_responses[codec->unsol_response_read++]; 1257 codec->unsol_response_read %= MAX_CODEC_UNSOL_RESPONSES; 1258 1259 bool disable = response & 1; 1260 hda_audio_group* audioGroup = codec->audio_groups[0]; 1261 hda_audio_group_check_sense(audioGroup, disable); 1262 } 1263 return B_OK; 1264 } 1265 1266 1267 static void 1268 hda_codec_delete_audio_group(hda_audio_group* audioGroup) 1269 { 1270 if (audioGroup == NULL) 1271 return; 1272 1273 if (audioGroup->playback_stream != NULL) 1274 hda_stream_delete(audioGroup->playback_stream); 1275 1276 if (audioGroup->record_stream != NULL) 1277 hda_stream_delete(audioGroup->record_stream); 1278 free(audioGroup->multi); 1279 free(audioGroup->widgets); 1280 free(audioGroup); 1281 } 1282 1283 1284 static status_t 1285 hda_codec_new_audio_group(hda_codec* codec, uint32 audioGroupNodeID) 1286 { 1287 hda_audio_group* audioGroup = (hda_audio_group*)calloc(1, 1288 sizeof(hda_audio_group)); 1289 if (audioGroup == NULL) 1290 return B_NO_MEMORY; 1291 1292 // Setup minimal info needed by hda_codec_parse_afg 1293 audioGroup->widget.node_id = audioGroupNodeID; 1294 audioGroup->codec = codec; 1295 audioGroup->multi = (hda_multi*)calloc(1, 1296 sizeof(hda_multi)); 1297 if (audioGroup->multi == NULL) { 1298 free(audioGroup); 1299 return B_NO_MEMORY; 1300 } 1301 audioGroup->multi->group = audioGroup; 1302 1303 // Parse all widgets in Audio Function Group 1304 status_t status = hda_codec_parse_audio_group(audioGroup); 1305 if (status != B_OK) 1306 goto err; 1307 1308 // Setup for worst-case scenario; we cannot find any output Pin Widgets 1309 status = ENODEV; 1310 1311 if (hda_audio_group_build_tree(audioGroup) != B_OK) 1312 goto err; 1313 hda_audio_group_switch_init(audioGroup); 1314 1315 audioGroup->playback_stream = hda_stream_new(audioGroup, STREAM_PLAYBACK); 1316 audioGroup->record_stream = hda_stream_new(audioGroup, STREAM_RECORD); 1317 TRACE("streams playback %p, record %p\n", audioGroup->playback_stream, 1318 audioGroup->record_stream); 1319 1320 if (audioGroup->playback_stream != NULL 1321 || audioGroup->record_stream != NULL) { 1322 codec->audio_groups[codec->num_audio_groups++] = audioGroup; 1323 hda_audio_group_check_sense(audioGroup, false); 1324 return B_OK; 1325 } 1326 1327 err: 1328 free(audioGroup->widgets); 1329 free(audioGroup); 1330 return status; 1331 } 1332 1333 1334 // #pragma mark - 1335 1336 1337 status_t 1338 hda_audio_group_get_widgets(hda_audio_group* audioGroup, hda_stream* stream) 1339 { 1340 hda_widget_type type; 1341 uint32 flags; 1342 1343 if (stream->type == STREAM_PLAYBACK) { 1344 type = WT_AUDIO_OUTPUT; 1345 flags = WIDGET_FLAG_OUTPUT_PATH; 1346 } else { 1347 // record 1348 type = WT_AUDIO_INPUT; 1349 flags = WIDGET_FLAG_INPUT_PATH; 1350 } 1351 1352 uint32 count = 0; 1353 1354 for (uint32 i = 0; i < audioGroup->widget_count && count < MAX_IO_WIDGETS; 1355 i++) { 1356 hda_widget& widget = audioGroup->widgets[i]; 1357 1358 if ((widget.flags & flags) != 0) { 1359 if (widget.type == WT_PIN_COMPLEX) { 1360 stream->pin_widget = widget.node_id; 1361 1362 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget, 1363 flags == WIDGET_FLAG_OUTPUT_PATH); 1364 1365 TRACE("ENABLE pin widget %" B_PRIu32 "\n", widget.node_id); 1366 // FIXME: Force Pin Widget to unmute; enable hp/output 1367 corb_t verb = MAKE_VERB(audioGroup->codec->addr, 1368 widget.node_id, 1369 VID_SET_PIN_WIDGET_CONTROL, ctrl); 1370 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1371 1372 if (PIN_CAP_IS_EAPD_CAP(widget.d.pin.capabilities)) { 1373 uint32 result; 1374 verb = MAKE_VERB(audioGroup->codec->addr, 1375 widget.node_id, VID_GET_EAPDBTL_EN, 0); 1376 if (hda_send_verbs(audioGroup->codec, &verb, 1377 &result, 1) == B_OK) { 1378 result &= 0xff; 1379 verb = MAKE_VERB(audioGroup->codec->addr, 1380 widget.node_id, VID_SET_EAPDBTL_EN, 1381 result | EAPDBTL_ENABLE_EAPD); 1382 hda_send_verbs(audioGroup->codec, 1383 &verb, NULL, 1); 1384 TRACE("ENABLE EAPD pin widget %" B_PRIu32 "\n", 1385 widget.node_id); 1386 } 1387 } 1388 } 1389 1390 if (widget.capabilities.output_amplifier != 0) { 1391 TRACE("UNMUTE/SET OUTPUT GAIN widget %" B_PRIu32 " " 1392 "(offset %" B_PRIu32 ")\n", widget.node_id, 1393 AMP_CAP_OFFSET(widget.capabilities.output_amplifier)); 1394 corb_t verb = MAKE_VERB(audioGroup->codec->addr, 1395 widget.node_id, 1396 VID_SET_AMPLIFIER_GAIN_MUTE, 1397 AMP_SET_OUTPUT | AMP_SET_LEFT_CHANNEL 1398 | AMP_SET_RIGHT_CHANNEL 1399 | AMP_CAP_OFFSET(widget.capabilities.output_amplifier)); 1400 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1401 } 1402 if (widget.capabilities.input_amplifier != 0) { 1403 TRACE("UNMUTE/SET INPUT GAIN widget %" B_PRIu32 " " 1404 "(offset %" B_PRIu32 ")\n", widget.node_id, 1405 AMP_CAP_OFFSET(widget.capabilities.input_amplifier)); 1406 for (uint32 i = 0; i < widget.num_inputs; i++) { 1407 corb_t verb = MAKE_VERB(audioGroup->codec->addr, 1408 widget.node_id, 1409 VID_SET_AMPLIFIER_GAIN_MUTE, 1410 AMP_SET_INPUT | AMP_SET_LEFT_CHANNEL 1411 | AMP_SET_RIGHT_CHANNEL 1412 | AMP_SET_INPUT_INDEX(i) 1413 | ((widget.active_input == (int32)i) ? 0 : AMP_MUTE) 1414 | AMP_CAP_OFFSET(widget.capabilities.input_amplifier)); 1415 hda_send_verbs(audioGroup->codec, &verb, NULL, 1); 1416 } 1417 } 1418 } 1419 1420 if (widget.type != type || (widget.flags & flags) == 0 1421 || (widget.capabilities.audio 1422 & (AUDIO_CAP_STEREO | AUDIO_CAP_DIGITAL)) != AUDIO_CAP_STEREO 1423 || widget.d.io.formats == 0) 1424 continue; 1425 1426 if (count == 0) { 1427 stream->sample_format = widget.d.io.formats; 1428 stream->sample_rate = widget.d.io.rates; 1429 } else { 1430 stream->sample_format &= widget.d.io.formats; 1431 stream->sample_rate &= widget.d.io.rates; 1432 } 1433 1434 stream->io_widgets[count++] = widget.node_id; 1435 } 1436 1437 if (count == 0) 1438 return B_ENTRY_NOT_FOUND; 1439 1440 stream->num_io_widgets = count; 1441 return B_OK; 1442 } 1443 1444 1445 void 1446 hda_codec_delete(hda_codec* codec) 1447 { 1448 if (codec == NULL) 1449 return; 1450 1451 delete_sem(codec->response_sem); 1452 delete_sem(codec->unsol_response_sem); 1453 1454 int32 result; 1455 wait_for_thread(codec->unsol_response_thread, &result); 1456 1457 for (uint32 i = 0; i < codec->num_audio_groups; i++) { 1458 hda_codec_delete_audio_group(codec->audio_groups[i]); 1459 codec->audio_groups[i] = NULL; 1460 } 1461 1462 free(codec); 1463 } 1464 1465 1466 hda_codec* 1467 hda_codec_new(hda_controller* controller, uint32 codecAddress) 1468 { 1469 if (codecAddress > HDA_MAX_CODECS) 1470 return NULL; 1471 1472 hda_codec* codec = (hda_codec*)calloc(1, sizeof(hda_codec)); 1473 if (codec == NULL) { 1474 ERROR("Failed to alloc a codec\n"); 1475 return NULL; 1476 } 1477 1478 status_t status; 1479 1480 codec->controller = controller; 1481 codec->addr = codecAddress; 1482 codec->response_sem = create_sem(0, "hda_codec_response_sem"); 1483 if (codec->response_sem < B_OK) { 1484 ERROR("Failed to create semaphore\n"); 1485 goto err; 1486 } 1487 controller->codecs[codecAddress] = codec; 1488 1489 codec->unsol_response_sem = create_sem(0, "hda_codec_unsol_response_sem"); 1490 if (codec->unsol_response_sem < B_OK) { 1491 ERROR("Failed to create semaphore\n"); 1492 goto err; 1493 } 1494 codec->unsol_response_read = 0; 1495 codec->unsol_response_write = 0; 1496 1497 struct { 1498 uint32 device : 16; 1499 uint32 vendor : 16; 1500 uint32 subsystem : 32; 1501 uint32 stepping : 8; 1502 uint32 revision : 8; 1503 uint32 minor : 4; 1504 uint32 major : 4; 1505 uint32 _reserved0 : 8; 1506 uint32 count : 8; 1507 uint32 _reserved1 : 8; 1508 uint32 start : 8; 1509 uint32 _reserved2 : 8; 1510 } response; 1511 1512 corb_t verbs[4]; 1513 verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID); 1514 verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUBSYSTEM_ID); 1515 verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID); 1516 verbs[3] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, 1517 PID_SUB_NODE_COUNT); 1518 1519 status = hda_send_verbs(codec, verbs, (uint32*)&response, 4); 1520 if (status != B_OK) { 1521 ERROR("Failed to get vendor and revision parameters: %s\n", 1522 strerror(status)); 1523 goto err; 1524 } 1525 1526 codec->vendor_id = response.vendor; 1527 codec->subsystem_id = response.subsystem; 1528 codec->product_id = response.device; 1529 codec->stepping = response.stepping; 1530 codec->revision = response.revision; 1531 codec->minor = response.minor; 1532 codec->major = response.major; 1533 hda_codec_get_quirks(codec); 1534 1535 for (uint32 nodeID = response.start; 1536 nodeID < response.start + response.count; nodeID++) { 1537 struct { 1538 uint32 groupType; 1539 uint32 subsystem; 1540 } functionResponse; 1541 verbs[0] = MAKE_VERB(codecAddress, nodeID, VID_GET_PARAMETER, 1542 PID_FUNCTION_GROUP_TYPE); 1543 verbs[1] = MAKE_VERB(codecAddress, nodeID, VID_GET_SUBSYSTEMID, 0); 1544 1545 if (hda_send_verbs(codec, verbs, (uint32*)&functionResponse, 2) != B_OK) { 1546 ERROR("Failed to get function group type\n"); 1547 goto err; 1548 } 1549 1550 if ((functionResponse.groupType & FUNCTION_GROUP_NODETYPE_MASK) 1551 == FUNCTION_GROUP_NODETYPE_AUDIO) { 1552 // Found an Audio Function Group! 1553 if (response.subsystem == 0 && functionResponse.subsystem != 0) { 1554 // Update our subsystem, and re-check quirks for this codec 1555 codec->subsystem_id = functionResponse.subsystem; 1556 hda_codec_get_quirks(codec); 1557 } 1558 1559 status_t status = hda_codec_new_audio_group(codec, nodeID); 1560 if (status != B_OK) { 1561 ERROR("Failed to setup new audio function group (%s)!\n", 1562 strerror(status)); 1563 goto err; 1564 } 1565 } 1566 } 1567 1568 TRACE("Codec %" B_PRIu32 " Vendor: %04" B_PRIx32 " " 1569 "Product: %04" B_PRIx32 " " 1570 "Subsystem: %08" B_PRIx32 ", " 1571 "Revision: %" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 " " 1572 "Quirks: %04" B_PRIx32 "\n", 1573 codecAddress, 1574 response.vendor, 1575 response.device, 1576 codec->subsystem_id, 1577 response.major, response.minor, response.revision, response.stepping, 1578 codec->quirks); 1579 1580 codec->unsol_response_thread = spawn_kernel_thread( 1581 (status_t(*)(void*))hda_codec_switch_handler, 1582 "hda_codec_unsol_thread", B_LOW_PRIORITY, codec); 1583 if (codec->unsol_response_thread < B_OK) { 1584 ERROR("Failed to spawn thread\n"); 1585 goto err; 1586 } 1587 resume_thread(codec->unsol_response_thread); 1588 1589 return codec; 1590 1591 err: 1592 controller->codecs[codecAddress] = NULL; 1593 hda_codec_delete(codec); 1594 return NULL; 1595 } 1596