1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "intel_hda_codec.h" 6 7#include <fbl/algorithm.h> 8 9namespace audio { 10namespace intel_hda { 11 12IntelHDACodec::CodecTree IntelHDACodec::codecs_; 13 14extern void print_codec_state(const CodecState& codec); 15 16//////////////////////////////////////////////////////////////////////////////// 17// 18// Parser and CommandList for fetching the currently configured unsolicited 19// response state (present in both function groups and widgets) 20// 21//////////////////////////////////////////////////////////////////////////////// 22static zx_status_t ParseUnsolicitedResponseState(UnsolicitedResponseState& state, 23 const CodecResponse& resp) { 24 // Section 7.3.3.14. 25 state.raw_data_ = static_cast<uint8_t>(resp.data & 0xFF); 26 return ZX_OK; 27} 28 29static const IntelHDACodec::CommandListEntry<UnsolicitedResponseState> 30 FETCH_UNSOLICITED_RESPONSE_STATE[] = { 31 { GET_UNSOLICITED_RESP_CTRL, ParseUnsolicitedResponseState }, 32}; 33 34//////////////////////////////////////////////////////////////////////////////// 35// 36// Parsers and CommandLists for fetching info about supported and current power 37// state. 38// 39//////////////////////////////////////////////////////////////////////////////// 40static zx_status_t ParseSupportedPowerStates(PowerState& ps, const CodecResponse& resp) { 41 ps.supported_states_ = resp.data; 42 return ZX_OK; 43} 44 45static zx_status_t ParseCurrentPowerState(PowerState& ps, const CodecResponse& resp) { 46 // Section 7.3.3.10 47 ps.set_ = static_cast<uint8_t>(resp.data & 0xF); 48 ps.active_ = static_cast<uint8_t>((resp.data >> 4) & 0xF); 49 ps.error_ = (resp.data & (1u << 8)) != 0; 50 ps.clock_stop_ok_ = (resp.data & (1u << 9)) != 0; 51 ps.settings_reset_ = (resp.data & (1u << 10)) != 0; 52 53 return ZX_OK; 54} 55 56static const IntelHDACodec::CommandListEntry<PowerState> FETCH_POWER_STATE[] = { 57 { GET_PARAM(CodecParam::SUPPORTED_PWR_STATES), ParseSupportedPowerStates }, 58 { GET_POWER_STATE, ParseCurrentPowerState }, 59}; 60 61//////////////////////////////////////////////////////////////////////////////// 62// 63// Parsers and CommandLists for fetching info about audio widgets 64// 65//////////////////////////////////////////////////////////////////////////////// 66static zx_status_t ParseAWPcmSizeRate(AudioWidgetState& widget, const CodecResponse& resp) { 67 auto& afg = *widget.afg_; 68 const auto& caps = widget.caps_; 69 70 widget.pcm_size_rate_ = caps.format_override() 71 ? resp.data 72 : afg.default_pcm_size_rate_; 73 74 return ZX_OK; 75} 76 77static zx_status_t ParseAWPcmFormats(AudioWidgetState& widget, const CodecResponse& resp) { 78 auto& afg = *widget.afg_; 79 const auto& caps = widget.caps_; 80 81 widget.pcm_formats_ = caps.format_override() 82 ? resp.data 83 : afg.default_pcm_formats_; 84 85 return ZX_OK; 86} 87 88static zx_status_t ParseAWInputAmpCaps(AudioWidgetState& widget, const CodecResponse& resp) { 89 auto& afg = *widget.afg_; 90 const auto& caps = widget.caps_; 91 92 if (caps.input_amp_present()) { 93 widget.input_amp_caps_ = caps.amp_param_override() 94 ? AmpCaps(resp.data) 95 : afg.default_input_amp_caps_; 96 } 97 98 return ZX_OK; 99} 100 101static zx_status_t ParseAWOutputAmpCaps(AudioWidgetState& widget, const CodecResponse& resp) { 102 auto& afg = *widget.afg_; 103 const auto& caps = widget.caps_; 104 105 if (caps.output_amp_present()) { 106 widget.output_amp_caps_ = caps.amp_param_override() 107 ? AmpCaps(resp.data) 108 : afg.default_output_amp_caps_; 109 } 110 111 return ZX_OK; 112} 113 114static zx_status_t ParseAWConnectionListLen(AudioWidgetState& widget, const CodecResponse& resp) { 115 const auto& caps = widget.caps_; 116 117 if (caps.has_conn_list()) { 118 widget.long_form_conn_list_ = ((resp.data & 0x80) != 0); 119 widget.conn_list_len_ = resp.data & 0x7f; 120 121 if (widget.conn_list_len_) { 122 fbl::AllocChecker ac; 123 widget.conn_list_.reset( 124 new (&ac) AudioWidgetState::ConnListEntry[widget.conn_list_len_]); 125 if (!ac.check()) { 126 return ZX_ERR_NO_MEMORY; 127 } 128 } 129 } else { 130 widget.long_form_conn_list_ = false; 131 widget.conn_list_len_ = 0; 132 } 133 134 return ZX_OK; 135} 136 137static zx_status_t ParseAWProcessingCaps(AudioWidgetState& widget, const CodecResponse& resp) { 138 const auto& caps = widget.caps_; 139 140 if (caps.proc_widget()) { 141 widget.can_bypass_processing_ = (resp.data & 0x1) != 0; 142 widget.processing_coefficient_count_ = ((resp.data >> 8) & 0xFF); 143 } 144 145 return ZX_OK; 146} 147 148static zx_status_t ParseAWPinCaps(AudioWidgetState& widget, const CodecResponse& resp) { 149 widget.pin_caps_ = resp.data; 150 return ZX_OK; 151} 152 153static zx_status_t ParseAWVolumeKnobCaps(AudioWidgetState& widget, const CodecResponse& resp) { 154 widget.vol_knob_is_delta_ = (resp.data & 0x80) != 0; 155 widget.vol_knob_steps_ = (resp.data & 0x7f); 156 return ZX_OK; 157} 158 159static zx_status_t ParseAWStreamChan(AudioWidgetState& widget, const CodecResponse& resp) { 160 // Section 7.3.3.11 and Table 85 161 widget.stream_tag_ = static_cast<uint8_t>((resp.data >> 4) & 0xF); 162 widget.stream_chan_ = static_cast<uint8_t>(resp.data & 0xF); 163 return ZX_OK; 164} 165 166static zx_status_t ParseAWConfigDefaults(AudioWidgetState& widget, const CodecResponse& resp) { 167 widget.cfg_defaults_.raw_data_ = resp.data; 168 return ZX_OK; 169} 170 171static zx_status_t ParseAWPinWidgetCtrl(AudioWidgetState& widget, const CodecResponse& resp) { 172 widget.pin_widget_ctrl_.raw_data_ = static_cast<uint8_t>(resp.data & 0xFF); 173 return ZX_OK; 174} 175 176static zx_status_t ParseAudioWidgetType(AudioWidgetStatePtr& ptr, const CodecResponse& resp) { 177 AudioWidgetCaps caps(resp.data); 178 179 switch (caps.type()) { 180 case AudioWidgetCaps::Type::OUTPUT: 181 case AudioWidgetCaps::Type::INPUT: 182 case AudioWidgetCaps::Type::MIXER: 183 case AudioWidgetCaps::Type::SELECTOR: 184 case AudioWidgetCaps::Type::PIN_COMPLEX: 185 case AudioWidgetCaps::Type::POWER: 186 case AudioWidgetCaps::Type::VOLUME_KNOB: 187 case AudioWidgetCaps::Type::BEEP_GEN: 188 case AudioWidgetCaps::Type::VENDOR: 189 break; 190 default: 191 return ZX_ERR_INVALID_ARGS; 192 } 193 194 fbl::AllocChecker ac; 195 ptr.reset(new (&ac) AudioWidgetState(caps)); 196 if (!ac.check()) { 197 return ZX_ERR_NO_MEMORY; 198 } 199 200 return ZX_OK; 201} 202 203static const IntelHDACodec::CommandListEntry<AudioWidgetState> FETCH_AUDIO_INPUT_CAPS[] = { 204 { GET_PARAM(CodecParam::SUPPORTED_PCM_SIZE_RATE), ParseAWPcmSizeRate }, 205 { GET_PARAM(CodecParam::SUPPORTED_STREAM_FORMATS), ParseAWPcmFormats }, 206 { GET_PARAM(CodecParam::INPUT_AMP_CAPS), ParseAWInputAmpCaps }, 207 { GET_PARAM(CodecParam::CONNECTION_LIST_LEN), ParseAWConnectionListLen }, 208 { GET_PARAM(CodecParam::PROCESSING_CAPS), ParseAWProcessingCaps }, 209 { GET_CONVERTER_STREAM_CHAN, ParseAWStreamChan }, 210}; 211 212static const IntelHDACodec::CommandListEntry<AudioWidgetState> FETCH_AUDIO_OUTPUT_CAPS[] = { 213 { GET_PARAM(CodecParam::SUPPORTED_PCM_SIZE_RATE), ParseAWPcmSizeRate }, 214 { GET_PARAM(CodecParam::SUPPORTED_STREAM_FORMATS), ParseAWPcmFormats }, 215 { GET_PARAM(CodecParam::OUTPUT_AMP_CAPS), ParseAWOutputAmpCaps }, 216 { GET_PARAM(CodecParam::PROCESSING_CAPS), ParseAWProcessingCaps }, 217 { GET_CONVERTER_STREAM_CHAN, ParseAWStreamChan }, 218}; 219 220static const IntelHDACodec::CommandListEntry<AudioWidgetState> FETCH_DIGITAL_PIN_COMPLEX_CAPS[] = { 221 { GET_PARAM(CodecParam::PIN_CAPS), ParseAWPinCaps }, 222 { GET_PARAM(CodecParam::OUTPUT_AMP_CAPS), ParseAWOutputAmpCaps }, 223 { GET_PARAM(CodecParam::CONNECTION_LIST_LEN), ParseAWConnectionListLen }, 224 { GET_PARAM(CodecParam::PROCESSING_CAPS), ParseAWProcessingCaps }, 225 { GET_CONFIG_DEFAULT, ParseAWConfigDefaults }, 226 { GET_PIN_WIDGET_CTRL, ParseAWPinWidgetCtrl }, 227}; 228 229static const IntelHDACodec::CommandListEntry<AudioWidgetState> 230FETCH_NON_DIGITAL_PIN_COMPLEX_CAPS[] = { 231 { GET_PARAM(CodecParam::PIN_CAPS), ParseAWPinCaps }, 232 { GET_PARAM(CodecParam::INPUT_AMP_CAPS), ParseAWInputAmpCaps }, 233 { GET_PARAM(CodecParam::OUTPUT_AMP_CAPS), ParseAWOutputAmpCaps }, 234 { GET_PARAM(CodecParam::CONNECTION_LIST_LEN), ParseAWConnectionListLen }, 235 { GET_PARAM(CodecParam::PROCESSING_CAPS), ParseAWProcessingCaps }, 236 { GET_CONFIG_DEFAULT, ParseAWConfigDefaults }, 237 { GET_PIN_WIDGET_CTRL, ParseAWPinWidgetCtrl }, 238}; 239 240static const IntelHDACodec::CommandListEntry<AudioWidgetState> FETCH_MIXER_CAPS[] = { 241 { GET_PARAM(CodecParam::INPUT_AMP_CAPS), ParseAWInputAmpCaps }, 242 { GET_PARAM(CodecParam::OUTPUT_AMP_CAPS), ParseAWOutputAmpCaps }, 243 { GET_PARAM(CodecParam::CONNECTION_LIST_LEN), ParseAWConnectionListLen }, 244}; 245 246static const IntelHDACodec::CommandListEntry<AudioWidgetState> FETCH_SELECTOR_CAPS[] = { 247 { GET_PARAM(CodecParam::INPUT_AMP_CAPS), ParseAWInputAmpCaps }, 248 { GET_PARAM(CodecParam::OUTPUT_AMP_CAPS), ParseAWOutputAmpCaps }, 249 { GET_PARAM(CodecParam::CONNECTION_LIST_LEN), ParseAWConnectionListLen }, 250 { GET_PARAM(CodecParam::PROCESSING_CAPS), ParseAWProcessingCaps }, 251}; 252 253static const IntelHDACodec::CommandListEntry<AudioWidgetState> FETCH_POWER_CAPS[] = { 254 { GET_PARAM(CodecParam::CONNECTION_LIST_LEN), ParseAWConnectionListLen }, 255}; 256 257static const IntelHDACodec::CommandListEntry<AudioWidgetState> FETCH_VOLUME_KNOB_CAPS[] = { 258 { GET_PARAM(CodecParam::CONNECTION_LIST_LEN), ParseAWConnectionListLen }, 259 { GET_PARAM(CodecParam::VOLUME_KNOB_CAPS), ParseAWVolumeKnobCaps }, 260}; 261 262static const IntelHDACodec::CommandListEntry<AudioWidgetStatePtr> FETCH_WIDGET_TYPE[] = { 263 { GET_PARAM(CodecParam::AW_CAPS), ParseAudioWidgetType }, 264}; 265 266//////////////////////////////////////////////////////////////////////////////// 267// 268// Parsers and CommandLists for fetching info about function groups. 269// 270//////////////////////////////////////////////////////////////////////////////// 271static zx_status_t ParseAFGCaps(AudioFunctionGroupState& afg, const CodecResponse& resp) { 272 afg.caps_.raw_data_ = resp.data; 273 return ZX_OK; 274} 275 276static zx_status_t ParseAFGPcmSizeRate(AudioFunctionGroupState& afg, const CodecResponse& resp) { 277 // Section 7.3.4.7 : Supported PCM sizes and rates 278 afg.default_pcm_size_rate_ = resp.data; 279 return ZX_OK; 280} 281 282static zx_status_t ParseAFGPcmFormats(AudioFunctionGroupState& afg, const CodecResponse& resp) { 283 afg.default_pcm_formats_ = resp.data; 284 return ZX_OK; 285} 286 287static zx_status_t ParseAFGInputAmpCaps(AudioFunctionGroupState& afg, const CodecResponse& resp) { 288 afg.default_input_amp_caps_.raw_data_ = resp.data; 289 return ZX_OK; 290} 291 292static zx_status_t ParseAFGOutputAmpCaps(AudioFunctionGroupState& afg, const CodecResponse& resp) { 293 afg.default_output_amp_caps_.raw_data_ = resp.data; 294 return ZX_OK; 295} 296 297static zx_status_t ParseAFGGPIOCount(AudioFunctionGroupState& afg, const CodecResponse& resp) { 298 // Section 7.3.4.14 : GPIO Counts 299 afg.gpio_can_wake_ = (resp.data & 0x80000000) != 0; 300 afg.gpio_can_send_unsolicited_ = (resp.data & 0x40000000) != 0; 301 afg.gpi_count_ = (resp.data >> 16) & 0xFF; 302 afg.gpo_count_ = (resp.data >> 8) & 0xFF; 303 afg.gpio_count_ = (resp.data >> 0) & 0xFF; 304 305 return ZX_OK; 306} 307 308static zx_status_t ParseAFGImplId(AudioFunctionGroupState& afg, const CodecResponse& resp) { 309 afg.impl_id_.raw_data_ = resp.data; 310 return ZX_OK; 311} 312 313static zx_status_t ParseAFGWidgetCount(AudioFunctionGroupState& afg, const CodecResponse& resp) { 314 /* Response format documented in section 7.3.4.1 */ 315 afg.widget_count_ = resp.data & 0xFF; 316 afg.widget_starting_id_ = (resp.data >> 16) & 0xFF; 317 uint32_t last_widget_nid = static_cast<uint32_t>(afg.widget_starting_id_) 318 + afg.widget_count_ - 1; 319 320 if (last_widget_nid > HDA_MAX_NID) 321 return ZX_ERR_INTERNAL; 322 323 if (afg.widget_count_) { 324 fbl::AllocChecker ac; 325 afg.widgets_.reset(new (&ac) AudioWidgetStatePtr[afg.widget_count_]); 326 if (!ac.check()) { 327 return ZX_ERR_NO_MEMORY; 328 } 329 } 330 331 return ZX_OK; 332} 333 334static const IntelHDACodec::CommandListEntry<AudioFunctionGroupState> FETCH_AFG_PROPERTIES[] { 335 { GET_PARAM(CodecParam::AFG_CAPS), ParseAFGCaps }, 336 { GET_PARAM(CodecParam::SUPPORTED_PCM_SIZE_RATE), ParseAFGPcmSizeRate }, 337 { GET_PARAM(CodecParam::SUPPORTED_STREAM_FORMATS), ParseAFGPcmFormats }, 338 { GET_PARAM(CodecParam::INPUT_AMP_CAPS), ParseAFGInputAmpCaps }, 339 { GET_PARAM(CodecParam::OUTPUT_AMP_CAPS), ParseAFGOutputAmpCaps }, 340 { GET_PARAM(CodecParam::GPIO_COUNT), ParseAFGGPIOCount }, 341 { GET_IMPLEMENTATION_ID, ParseAFGImplId }, 342 { GET_PARAM(CodecParam::SUBORDINATE_NODE_COUNT), ParseAFGWidgetCount }, 343}; 344 345static zx_status_t ParseFnGroupType(FunctionGroupStatePtr& ptr, const CodecResponse& resp) { 346 /* Response format documented in section 7.3.4.1 */ 347 auto type = static_cast<FunctionGroupState::Type>(resp.data & 0xFF); 348 fbl::AllocChecker ac; 349 350 switch (type) { 351 case FunctionGroupState::Type::AUDIO: 352 ptr.reset(new (&ac) AudioFunctionGroupState()); 353 if (!ac.check()) { 354 return ZX_ERR_NO_MEMORY; 355 } 356 break; 357 358 case FunctionGroupState::Type::MODEM: 359 ptr.reset(new (&ac) ModemFunctionGroupState()); 360 if (!ac.check()) { 361 return ZX_ERR_NO_MEMORY; 362 } 363 break; 364 default: 365 if ((type >= FunctionGroupState::Type::VENDOR_START) && 366 (type <= FunctionGroupState::Type::VENDOR_END)) { 367 ptr.reset(new (&ac) VendorFunctionGroupState(type)); 368 if (!ac.check()) { 369 return ZX_ERR_NO_MEMORY; 370 } 371 } else { 372 return ZX_ERR_INTERNAL; 373 } 374 break; 375 } 376 377 ptr->can_send_unsolicited_ = ((resp.data & 0x100) != 0); 378 return ZX_OK; 379} 380 381static const IntelHDACodec::CommandListEntry<FunctionGroupStatePtr> FETCH_FUNCTION_GROUP_TYPE[] = { 382 { GET_PARAM(CodecParam::FUNCTION_GROUP_TYPE), ParseFnGroupType }, 383}; 384 385//////////////////////////////////////////////////////////////////////////////// 386// 387// Parsers and command list for fetching info about core codec capabilities. 388// 389//////////////////////////////////////////////////////////////////////////////// 390static zx_status_t ParseVendorID(CodecState& codec, const CodecResponse& resp) { 391 /* Response format documented in section 7.3.4.1 */ 392 393 codec.vendor_id_ = static_cast<uint16_t>((resp.data >> 16) & 0xFFFF); 394 codec.device_id_ = static_cast<uint16_t>(resp.data & 0xFFFF);; 395 396 return (codec.vendor_id_ != 0) ? ZX_OK : ZX_ERR_INTERNAL; 397} 398 399static zx_status_t ParseRevisionID(CodecState& codec, const CodecResponse& resp) { 400 /* Response format documented in section 7.3.4.2 */ 401 402 codec.major_rev_ = (resp.data >> 20) & 0xF; 403 codec.minor_rev_ = (resp.data >> 16) & 0xF; 404 codec.vendor_rev_id_ = (resp.data >> 8) & 0xFF; 405 codec.vendor_stepping_id_ = resp.data & 0xFF; 406 407 return ZX_OK; 408} 409 410static zx_status_t ParseFnGroupCount(CodecState& codec, const CodecResponse& resp) { 411 /* Response format documented in section 7.3.4.3 */ 412 413 codec.fn_group_count_ = resp.data & 0xFF; 414 codec.fn_group_starting_id_ = (resp.data >> 16) & 0xFF; 415 416 uint32_t last_fn_group_nid = static_cast<uint32_t>(codec.fn_group_starting_id_) 417 + codec.fn_group_count_ - 1; 418 if (last_fn_group_nid > HDA_MAX_NID) 419 return ZX_ERR_INTERNAL; 420 421 // Allocate the storage for the function group state pointers, then 422 // start the process of enumerating their properties and widgets. 423 fbl::AllocChecker ac; 424 codec.fn_groups_.reset(new (&ac) FunctionGroupStatePtr[codec.fn_group_count_]); 425 if (!ac.check()) { 426 return ZX_ERR_NO_MEMORY; 427 } 428 429 return ZX_OK; 430} 431 432static const IntelHDACodec::CommandListEntry<CodecState> FETCH_CODEC_ROOT_COMMANDS[] = { 433 { GET_PARAM(CodecParam::VENDOR_ID), ParseVendorID }, 434 { GET_PARAM(CodecParam::REVISION_ID), ParseRevisionID }, 435 { GET_PARAM(CodecParam::SUBORDINATE_NODE_COUNT), ParseFnGroupCount }, 436}; 437 438zx_status_t IntelHDACodec::Enumerate() { 439 static const char* const DEV_PATH = "/dev/class/intel-hda-codec"; 440 441 zx_status_t res = ZirconDevice::Enumerate(nullptr, DEV_PATH, 442 [](void*, uint32_t id, const char* const dev_name) -> zx_status_t { 443 fbl::AllocChecker ac; 444 auto codec = fbl::unique_ptr<IntelHDACodec>(new (&ac) IntelHDACodec(id, dev_name)); 445 if (!ac.check()) { 446 return ZX_ERR_NO_MEMORY; 447 } 448 449 if (codec == nullptr) 450 return ZX_ERR_NO_MEMORY; 451 452 if (!codecs_.insert_or_find(fbl::move(codec))) 453 return ZX_ERR_INTERNAL; 454 455 return ZX_OK; 456 }); 457 458 return res; 459} 460 461zx_status_t IntelHDACodec::DumpCodec(int argc, const char** argv) { 462 zx_status_t res = ReadCodecState(); 463 if (res != ZX_OK) 464 return res; 465 466 printf("Codec ID %u :: %s\n", codec_id_, dev_name_); 467 print_codec_state(codec_state_); 468 469 return ZX_OK; 470} 471 472#define RUN_COMMAND_LIST(_tgt, _nid, _list, _fail_msg, ...) { \ 473 res = RunCommandList(_tgt, _nid, _list, fbl::count_of(_list)); \ 474 if (res != ZX_OK) { \ 475 printf(_fail_msg " (res %d)\n", ##__VA_ARGS__, res); \ 476 return res; \ 477 } \ 478} 479 480zx_status_t IntelHDACodec::ReadCodecState() { 481 zx_status_t res = Connect(); 482 483 if (res != ZX_OK) 484 return res; 485 486 codec_state_.reset(); 487 488 RUN_COMMAND_LIST(codec_state_, 0u, FETCH_CODEC_ROOT_COMMANDS, 489 "Failed while fetching codec root info"); 490 491 for (uint16_t group_ndx = 0; group_ndx < codec_state_.fn_group_count_; ++group_ndx) { 492 auto& fn_group_ptr = codec_state_.fn_groups_[group_ndx]; 493 auto nid = static_cast<uint16_t>(group_ndx + codec_state_.fn_group_starting_id_); 494 495 res = ReadFunctionGroupState(fn_group_ptr, nid); 496 if (res != ZX_OK) 497 return res; 498 } 499 500 return ZX_OK; 501} 502 503zx_status_t IntelHDACodec::ReadFunctionGroupState(FunctionGroupStatePtr& ptr, uint16_t nid) { 504 zx_status_t res; 505 506 RUN_COMMAND_LIST(ptr, nid, FETCH_FUNCTION_GROUP_TYPE, 507 "Failed to fetch function group type (nid %hu)", nid); 508 509 if (ptr->can_send_unsolicited_) { 510 RUN_COMMAND_LIST(ptr->unsol_resp_ctrl_, nid, FETCH_UNSOLICITED_RESPONSE_STATE, 511 "Failed to fetch unsolicited response control state (nid %hu)", nid); 512 } 513 514 ptr->nid_ = nid; 515 516 switch (ptr->type_) { 517 case FunctionGroupState::Type::AUDIO: { 518 auto& afg = *(static_cast<AudioFunctionGroupState*>(ptr.get())); 519 return ReadAudioFunctionGroupState(afg); 520 } 521 522 case FunctionGroupState::Type::MODEM: { 523 // We do not support probing the state of modem function groups right now. 524 printf("Warning: MODEM function group (nid %hd) state details not fetched.\n", nid); 525 break; 526 } 527 528 default: 529 // ParseFnGroupType should have aborted at this point if the function 530 // group type was not valid. 531 ZX_DEBUG_ASSERT((ptr->type_ >= FunctionGroupState::Type::VENDOR_START) && 532 (ptr->type_ <= FunctionGroupState::Type::VENDOR_END)); 533 break; 534 } 535 536 return ZX_OK; 537} 538 539zx_status_t IntelHDACodec::ReadAudioFunctionGroupState(AudioFunctionGroupState& afg) { 540 zx_status_t res; 541 542 RUN_COMMAND_LIST(afg, afg.nid_, FETCH_AFG_PROPERTIES, 543 "Failed to audio fn group properties (nid %hu)", afg.nid_); 544 545 RUN_COMMAND_LIST(afg.power_, afg.nid_, FETCH_POWER_STATE, 546 "Failed to fetch Power caps/state for audio function group (nid %hu)", 547 afg.nid_); 548 549 for (uint32_t i = 0; i < afg.widget_count_; ++i) { 550 auto& widget_ptr = afg.widgets_[i]; 551 uint16_t nid = static_cast<uint16_t>(afg.widget_starting_id_ + i); 552 553 RUN_COMMAND_LIST(widget_ptr, nid, FETCH_WIDGET_TYPE, 554 "Failed to audio widget type (nid %hu) for function " 555 "group located at nid %hu", nid, afg.nid_); 556 557 widget_ptr->nid_ = nid; 558 widget_ptr->afg_ = &afg; 559 560 res = ReadAudioWidgetState(*widget_ptr); 561 if (res != ZX_OK) 562 return res; 563 } 564 565 return ZX_OK; 566} 567 568zx_status_t IntelHDACodec::ReadAudioWidgetState(AudioWidgetState& widget) { 569 zx_status_t res; 570 571 switch (widget.caps_.type()) { 572 case AudioWidgetCaps::Type::INPUT: 573 RUN_COMMAND_LIST(widget, widget.nid_, FETCH_AUDIO_INPUT_CAPS, 574 "Failed to fetch INPUT_CAPS for audio widget (nid %hu)", 575 widget.nid_); 576 break; 577 578 case AudioWidgetCaps::Type::OUTPUT: 579 RUN_COMMAND_LIST(widget, widget.nid_, FETCH_AUDIO_OUTPUT_CAPS, 580 "Failed to fetch OUTPUT_CAPS for audio widget (nid %hu)", 581 widget.nid_); 582 break; 583 584 case AudioWidgetCaps::Type::PIN_COMPLEX: 585 if (widget.caps_.digital()) { 586 RUN_COMMAND_LIST(widget, widget.nid_, FETCH_DIGITAL_PIN_COMPLEX_CAPS, 587 "Failed to fetch DIGITAL_PIN_COMPLEX_CAPS for audio widget " 588 "(nid %hu)", widget.nid_); 589 } else { 590 RUN_COMMAND_LIST(widget, widget.nid_, FETCH_NON_DIGITAL_PIN_COMPLEX_CAPS, 591 "Failed to fetch NON_DIGITAL_PIN_COMPLEX_CAPS for audio widget " 592 "(nid %hu)", widget.nid_); 593 } 594 break; 595 596 case AudioWidgetCaps::Type::MIXER: 597 RUN_COMMAND_LIST(widget, widget.nid_, FETCH_MIXER_CAPS, 598 "Failed to fetch MIXER_CAPS for audio widget (nid %hu)", 599 widget.nid_); 600 break; 601 602 case AudioWidgetCaps::Type::SELECTOR: 603 RUN_COMMAND_LIST(widget, widget.nid_, FETCH_SELECTOR_CAPS, 604 "Failed to fetch SELECTOR_CAPS for audio widget (nid %hu)", 605 widget.nid_); 606 break; 607 608 case AudioWidgetCaps::Type::POWER: 609 RUN_COMMAND_LIST(widget, widget.nid_, FETCH_POWER_CAPS, 610 "Failed to fetch POWER_CAPS for audio widget (nid %hu)", 611 widget.nid_); 612 break; 613 614 case AudioWidgetCaps::Type::VOLUME_KNOB: 615 RUN_COMMAND_LIST(widget, widget.nid_, FETCH_VOLUME_KNOB_CAPS, 616 "Failed to fetch VOLUME_KNOB_CAPS for audio widget (nid %hu)", 617 widget.nid_); 618 break; 619 620 // We don't currently fetch any state for beep generators or vendor widgets. 621 case AudioWidgetCaps::Type::BEEP_GEN: 622 case AudioWidgetCaps::Type::VENDOR: 623 break; 624 625 default: 626 printf("Unrecognized audio widget type (%u) at nid %hu\n", 627 static_cast<uint32_t>(widget.caps_.type()), widget.nid_); 628 return ZX_ERR_BAD_STATE; 629 } 630 631 // If this widget has a connection list, read it now. 632 if (widget.caps_.has_conn_list()) { 633 res = ReadConnList(widget); 634 if (res != ZX_OK) 635 return res; 636 } 637 638 // If this widget has power management capabilities, read the caps and the 639 // current state now. 640 if (widget.caps_.has_power_ctl()) { 641 RUN_COMMAND_LIST(widget.power_, widget.nid_, FETCH_POWER_STATE, 642 "Failed to fetch Power caps/state for audio widget (nid %hu)", 643 widget.nid_); 644 645 // From section 7.3.4.12. 646 // 647 // "If this is not implemented (returns 0's) or just returns 0 as 648 // response to reading this parameter for a node that supports a Power 649 // State Control (see section 7.3.3.10) then the supported power states 650 // for that node will be the same as reported for the Function Group." 651 if (widget.power_.supported_states_ == 0) { 652 ZX_DEBUG_ASSERT(widget.afg_ != nullptr); 653 widget.power_.supported_states_ = widget.afg_->power_.supported_states_; 654 } 655 } 656 657 // If this is an input or output converter widget, read the currently configured format. 658 if ((widget.caps_.type() == AudioWidgetCaps::Type::INPUT) || 659 (widget.caps_.type() == AudioWidgetCaps::Type::OUTPUT)) { 660 CodecResponse resp; 661 662 res = DoCodecCmd(widget.nid_, GET_CONVERTER_FORMAT, &resp); 663 if (res != ZX_OK) { 664 printf("Failed to get stream converter format for for nid %hu (res %d)\n", 665 widget.nid_, res); 666 return res; 667 } 668 669 widget.cur_format_.raw_data_ = static_cast<uint16_t>(resp.data & 0xFFFF); 670 } 671 672 // If this is a pin complex, and it supports presence detection, and the 673 // JackOverride bit has not been set in the config defaults, query the pin 674 // sense. 675 if ((widget.caps_.type() == AudioWidgetCaps::Type::PIN_COMPLEX) && 676 (widget.pin_caps_ & AW_PIN_CAPS_FLAG_CAN_PRESENCE_DETECT) && 677 (!widget.cfg_defaults_.jack_detect_override())) { 678 679 // TODO(johngro): Add support for SW triggering a pin detection. Timing 680 // requirements are unclear and may be codec specific. Also, triggering 681 // the presence detection is a "set" operation, which is not currently 682 // permitted by the driver. 683 if (widget.pin_caps_ & AW_PIN_CAPS_FLAG_TRIGGER_REQUIRED) { 684 printf("WARNING: SW triggered presence sensing not supported (nid %hu)\n", 685 widget.nid_); 686 } else { 687 // TODO(johngro): do we need to bring the pin complex to a 688 // particular power state in order for presence detect to work, or 689 // should it run at all power states? 690 CodecResponse resp; 691 res = DoCodecCmd(widget.nid_, GET_PIN_SENSE, &resp); 692 if (res != ZX_OK) { 693 printf("Failed to get pin sense status for pin complex nid %hu (res %d)\n", 694 widget.nid_, res); 695 return res; 696 } 697 698 widget.pin_sense_.raw_data_ = resp.data; 699 widget.pin_sense_valid_ = true; 700 } 701 } 702 703 // Read the current state of the EAPD/BTL register if this is... 704 // 705 // 1) A pin complex with external amplifier control. 706 // 2) A pin complex capable of balanced output. 707 // 3) Any widget capable of swapping L/R channels 708 if (widget.caps_.can_lr_swap() || 709 (widget.pin_caps_ & AW_PIN_CAPS_FLAG_BALANCED_IO) || 710 (widget.pin_caps_ & AW_PIN_CAPS_FLAG_CAN_EAPD)) { 711 CodecResponse resp; 712 res = DoCodecCmd(widget.nid_, GET_EAPD_BTL_ENABLE, &resp); 713 if (res != ZX_OK) { 714 printf("Failed to get EAPD/BTL state for nid %hu (res %d)\n", 715 widget.nid_, res); 716 return res; 717 } 718 719 widget.eapd_state_.raw_data_ = resp.data; 720 } 721 722 // If this widget has an input or output amplifier, read its current state. 723 // 724 // Todo(johngro) : add support for reading gain settings for mixers and 725 // summing widgets which have more than just a single amplifier gain/mute 726 // setting. 727 if (widget.caps_.input_amp_present()) { 728 // If this a mixer, read the individual input amp state for each of the mixer inputs. 729 // Otherwise, just read the common input amp state. 730 if (widget.caps_.type() == AudioWidgetCaps::Type::MIXER) { 731 for (uint8_t i = 0; i < widget.conn_list_len_; ++i) { 732 res = ReadAmpState(widget.nid_, true, i, 733 widget.input_amp_caps_, 734 &widget.conn_list_[i].amp_state_); 735 if (res != ZX_OK) 736 return res; 737 } 738 } else { 739 res = ReadAmpState(widget.nid_, true, 0, 740 widget.input_amp_caps_, &widget.input_amp_state_); 741 if (res != ZX_OK) 742 return res; 743 } 744 } 745 746 if (widget.caps_.output_amp_present()) { 747 res = ReadAmpState(widget.nid_, false, 0, 748 widget.output_amp_caps_, &widget.output_amp_state_); 749 if (res != ZX_OK) 750 return res; 751 } 752 753 // If this widget can send unsolicited responses, query the current state of 754 // the unsolicted response controls. 755 if (widget.caps_.can_send_unsol()) { 756 RUN_COMMAND_LIST(widget.unsol_resp_ctrl_, widget.nid_, 757 FETCH_UNSOLICITED_RESPONSE_STATE, 758 "Failed to fetch unsolicited response control state (nid %hu)", 759 widget.nid_); 760 } 761 762 // Finished. 763 return ZX_OK; 764} 765 766#undef RUN_COMMAND_LIST 767 768zx_status_t IntelHDACodec::ReadConnList(AudioWidgetState& widget) { 769 CodecResponse resp; 770 zx_status_t res; 771 772 ZX_DEBUG_ASSERT(widget.conn_list_len_ > 0); 773 ZX_DEBUG_ASSERT(widget.conn_list_ != nullptr); 774 775 size_t i = 0; 776 while (i < widget.conn_list_len_) { 777 res = DoCodecCmd(widget.nid_, GET_CONNECTION_LIST_ENTRY(static_cast<uint8_t>(i)), &resp); 778 if (res != ZX_OK) { 779 printf("Failed to get connection list entry at ndx %zu for nid %hu (res %d)\n", 780 i, widget.nid_, res); 781 return res; 782 } 783 784 // See section 7.1.2 and figure 51 for the format of long and short form 785 // connection widget.conn_list_ entries. 786 if (widget.long_form_conn_list_) { 787 for (size_t j = 0; (j < 2) && (i < widget.conn_list_len_); j++, i++) { 788 uint16_t raw = static_cast<uint16_t>(resp.data & 0xFFFF); 789 widget.conn_list_[i].range_ = (raw & 0x8000u) != 0; 790 widget.conn_list_[i].nid_ = (raw & 0x7FFFu); 791 resp.data >>= 16; 792 } 793 } else { 794 for (size_t j = 0; (j < 4) && (i < widget.conn_list_len_); j++, i++) { 795 uint8_t raw = static_cast<uint8_t>(resp.data & 0xFF); 796 widget.conn_list_[i].range_ = (raw & 0x80u) != 0; 797 widget.conn_list_[i].nid_ = (raw & 0x7Fu); 798 resp.data >>= 8; 799 } 800 } 801 } 802 803 // Sanity check the widget.conn_list_. 804 for (i = 0; i < widget.conn_list_len_; ++i) { 805 if (widget.conn_list_[i].range_ && (!i || widget.conn_list_[i-1].range_)) { 806 printf("Invalid connection widget.conn_list_ entry [nid, ndx] = [%hu, %zu]. " 807 "Range end may not be the first entry in the connection widget.conn_list_, " 808 "or proceeded by a range end entry.\n", 809 widget.nid_, i); 810 return ZX_ERR_BAD_STATE; 811 } 812 } 813 814 // If the connection list length is greater than 1, and this is not a mixer 815 // widger, then there exists a selection control. Read it's current setting 816 // so we can report it. Otherwise, the currently connected NID must be the 817 // same as the first entry in the list, or this is a mixer widget in which 818 // case it is always connected to all of the entries in the connection list. 819 if (widget.caps_.type() != AudioWidgetCaps::Type::MIXER) { 820 if (widget.conn_list_len_ == 1) { 821 widget.connected_nid_ = widget.conn_list_[0].nid_; 822 widget.connected_nid_ndx_ = 0; 823 } else { 824 // Select control response format documented in section 7.3.3.2 Table 73 825 res = DoCodecCmd(widget.nid_, GET_CONNECTION_SELECT_CONTROL, &resp); 826 if (res != ZX_OK) { 827 printf("Failed to get connection selection for nid %hu (res %d)\n", 828 widget.nid_, res); 829 return res; 830 } 831 832 widget.connected_nid_ndx_ = static_cast<uint8_t>(resp.data & 0xFF); 833 widget.connected_nid_ = (widget.connected_nid_ndx_ < widget.conn_list_len_) 834 ? widget.conn_list_[widget.connected_nid_ndx_].nid_ 835 : 0; 836 } 837 } else { 838 widget.connected_nid_ = 0; 839 widget.connected_nid_ndx_ = 0; 840 } 841 842 return ZX_OK; 843} 844 845zx_status_t IntelHDACodec::ReadAmpState(uint16_t nid, bool is_input, uint8_t ndx, 846 const AmpCaps& caps, 847 AudioWidgetState::AmpState* state_out) { 848 ZX_DEBUG_ASSERT(state_out); 849 850 CodecResponse resp; 851 zx_status_t res; 852 853 for (size_t i = 0; i < fbl::count_of(state_out->gain); ++i) { 854 res = DoCodecCmd(nid, GET_AMPLIFIER_GAIN_MUTE(is_input, (i > 0), ndx), &resp); 855 if (res != ZX_OK) { 856 printf("Failed to get amp settings for nid %hu's %s %s amplifier #%u (res %d)\n", 857 nid, 858 (i > 0) ? "right" : "left", 859 is_input ? "input" : "output", 860 ndx, res); 861 return res; 862 } 863 864 // Section 7.3.3.7 and Figure 62 865 state_out->gain[i] = static_cast<uint8_t>(resp.data & 0x7f); 866 state_out->mute[i] = (resp.data & 0x80) != 0; 867 } 868 869 return ZX_OK; 870} 871 872zx_status_t IntelHDACodec::DoCodecCmd(uint16_t nid, 873 const CodecVerb& verb, 874 CodecResponse* resp_out) { 875 876 ZX_DEBUG_ASSERT(resp_out != nullptr); 877 878 ihda_codec_send_corb_cmd_req_t req; 879 ihda_codec_send_corb_cmd_resp_t resp; 880 881 InitRequest(&req, IHDA_CODEC_SEND_CORB_CMD); 882 req.nid = nid; 883 req.verb = verb.val; 884 885 zx_status_t res = CallDevice(req, &resp); 886 if (res != ZX_OK) { 887 printf("Codec command failed; [nid, verb] = [%2u, 0x%05x] (res %d)\n", nid, verb.val, res); 888 return res; 889 } 890 891 resp_out->data = resp.data; 892 resp_out->data_ex = resp.data_ex; 893 894 return ZX_OK; 895} 896 897template <typename T> 898zx_status_t IntelHDACodec::RunCommandList(T& target, 899 uint16_t nid, 900 const CommandListEntry<T>* cmds, 901 size_t cmd_count) { 902 ZX_DEBUG_ASSERT(cmds); 903 904 for (size_t i = 0; i < cmd_count; ++i) { 905 const auto& cmd = cmds[i]; 906 zx_status_t res; 907 CodecResponse resp; 908 909 res = DoCodecCmd(nid, cmd.verb, &resp); 910 if (res != ZX_OK) 911 return res; 912 913 res = cmd.parser(target, resp); 914 if (res != ZX_OK) { 915 printf("Cmd parse; [nid, verb] = [%2u, 0x%05x] --> resp [0x%08x, 0x%08x] (res %d)\n", 916 nid, cmd.verb.val, resp.data, resp.data_ex, res); 917 return res; 918 } 919 } 920 921 return ZX_OK; 922} 923 924} // namespace audio 925} // namespace intel_hda 926