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 <stdio.h> 6#include "codec_state.h" 7 8#include <fbl/algorithm.h> 9 10namespace audio { 11namespace intel_hda { 12 13// Don't allow this code to pollute the rest of the namespace. 14namespace { 15 16const char* ToString(const FunctionGroupState::Type& val) { 17 switch (val) { 18 case FunctionGroupState::Type::AUDIO: return "AUDIO"; 19 case FunctionGroupState::Type::MODEM: return "MODEM"; 20 default: 21 if ((val >= FunctionGroupState::Type::VENDOR_START) && 22 (val <= FunctionGroupState::Type::VENDOR_END)) 23 return "VENDOR"; 24 else 25 return "<unknown>"; 26 } 27} 28 29const char* ToString(const AudioWidgetCaps::Type& val) { 30 switch (val) { 31 case AudioWidgetCaps::Type::OUTPUT: return "OUTPUT"; 32 case AudioWidgetCaps::Type::INPUT: return "INPUT"; 33 case AudioWidgetCaps::Type::MIXER: return "MIXER"; 34 case AudioWidgetCaps::Type::SELECTOR: return "SELECTOR"; 35 case AudioWidgetCaps::Type::PIN_COMPLEX: return "PIN_COMPLEX"; 36 case AudioWidgetCaps::Type::POWER: return "POWER"; 37 case AudioWidgetCaps::Type::VOLUME_KNOB: return "VOLUME_KNOB"; 38 case AudioWidgetCaps::Type::BEEP_GEN: return "BEEP_GEN"; 39 case AudioWidgetCaps::Type::VENDOR: return "VENDOR"; 40 default: return "<unknown>"; 41 } 42} 43 44const char* PowerStateToString(uint8_t val) { 45 switch (val) { 46 case 0u: return "D0"; 47 case 1u: return "D1"; 48 case 2u: return "D2"; 49 case 3u: return "D3HOT"; 50 case 4u: return "D3COLD"; 51 default: return "Unknown"; 52 }; 53} 54 55void Dump(const AmpCaps& caps, const AudioWidgetState::AmpState* amp_state = nullptr) { 56 float start = 0.0; 57 float stop = 0.0; 58 float step = 0.0; 59 60 if (!caps.step_size() || !caps.num_steps()) { 61 printf("none\n"); 62 return; 63 } else if (caps.num_steps() == 1) { 64 printf("fixed 0 dB gain"); 65 } else { 66 step = (static_cast<float>(caps.step_size()) / 4.0f); 67 start = -static_cast<float>(caps.offset()) * step; 68 stop = start + ((static_cast<float>(caps.num_steps()) - 1) * step); 69 printf("[%.2f, %.2f] dB in %.2f dB steps", start, stop, step); 70 } 71 72 printf(" (Can%s mute)", caps.can_mute() ? "" : "'t"); 73 74 if (amp_state != nullptr) { 75 printf(" ["); 76 for (size_t i = 0; i < fbl::count_of(amp_state->gain); ++i) { 77 if (i) printf(", "); 78 printf("%c:", !i ? 'L' : 'R'); 79 80 if (caps.can_mute() && amp_state->mute[i]) { 81 printf("mute"); 82 } else { 83 printf("%.2f dB", start + (step * amp_state->gain[0])); 84 } 85 } 86 87 printf("]"); 88 } 89 90 printf("\n"); 91} 92 93void Dump(const AudioWidgetState::StreamFormat& format) { 94 if (!format.is_pcm()) { 95 printf("Non-PCM (raw 0x%04hx)\n", format.raw_data_); 96 return; 97 } 98 99 printf("%u chan %u Hz %u bps (raw 0x%04hx)\n", 100 format.channels(), 101 format.sample_rate(), 102 format.bits_per_chan(), 103 format.raw_data_); 104} 105 106#define FMT(fmt) "%s%17s : " fmt, pad 107void Dump(const ConfigDefaults& cfg) { 108 static const char* pad = "+ \\-- "; 109 const char *tmp, *tmp2; 110 111 // Table 109 112 switch (cfg.port_connectivity()) { 113 case 0: tmp = "Jack"; break; 114 case 1: tmp = "Unconnected"; break; 115 case 2: tmp = "Integrated"; break; 116 case 3: tmp = "Jack+Integrated"; break; 117 default: tmp = "ERROR"; break; 118 } 119 120 printf(FMT("%s (%u)\n"), "Port Connectivity", tmp, cfg.port_connectivity()); 121 122 // Table 110 123 uint32_t loc1 = cfg.location() & 0xF; 124 uint32_t loc2 = (cfg.location() >> 4) & 0x3; 125 switch (loc1) { 126 case 0: tmp = "N/A"; break; 127 case 1: tmp = "Rear"; break; 128 case 2: tmp = "Front"; break; 129 case 3: tmp = "Left"; break; 130 case 4: tmp = "Right"; break; 131 case 5: tmp = "Top"; break; 132 case 6: tmp = "Bottom"; break; 133 case 7: 134 case 8: 135 case 9: tmp = "Special"; break; 136 default: tmp = "Unknown"; break; 137 } 138 139 switch (loc2) { 140 case 0: tmp2 = " External"; break; 141 case 1: tmp2 = " Internal"; break; 142 case 2: tmp2 = " Separate Chassis"; break; 143 case 3: tmp2 = " Other"; break; 144 default: tmp2 = " ERROR"; break; 145 } 146 147 switch (cfg.location()) { 148 case 0x07: tmp2 = ""; tmp = "Rear Panel"; break; 149 case 0x08: tmp2 = ""; tmp = "Drive Bay"; break; 150 case 0x17: tmp2 = ""; tmp = "Riser"; break; 151 case 0x18: tmp2 = ""; tmp = "Digital Display"; break; 152 case 0x19: tmp2 = ""; tmp = "ATAPI"; break; 153 case 0x37: tmp2 = ""; tmp = "Mobile Lid - Inside"; break; 154 case 0x38: tmp2 = ""; tmp = "Mobile Lid - Outside"; break; 155 default: break; 156 } 157 158 printf(FMT("%s%s (0x%02x)\n"), "Location", tmp, tmp2, cfg.location()); 159 160 // Table 111 161 switch (cfg.default_device()) { 162 case 0x0: tmp = "Line Out"; break; 163 case 0x1: tmp = "Speaker"; break; 164 case 0x2: tmp = "Headphone Out"; break; 165 case 0x3: tmp = "CD"; break; 166 case 0x4: tmp = "S/PDIF Out"; break; 167 case 0x5: tmp = "Digital Other Out"; break; 168 case 0x6: tmp = "Modem Line Side"; break; 169 case 0x7: tmp = "Modem Handset Side"; break; 170 case 0x8: tmp = "Line In"; break; 171 case 0x9: tmp = "AUX"; break; 172 case 0xa: tmp = "Mic In"; break; 173 case 0xb: tmp = "Telephony"; break; 174 case 0xc: tmp = "S/PDIF In"; break; 175 case 0xd: tmp = "Digital Other In"; break; 176 case 0xf: tmp = "Other"; break; 177 default: tmp = "Unknown"; break; 178 } 179 180 printf(FMT("%s (%u)\n"), "Default Device", tmp, cfg.default_device()); 181 182 // Table 112 183 switch (cfg.connection_type()) { 184 case 0x1: tmp = "1/8 inch"; break; 185 case 0x2: tmp = "1/4 inch"; break; 186 case 0x3: tmp = "ATAPI Internal"; break; 187 case 0x4: tmp = "RCA"; break; 188 case 0x5: tmp = "Optical"; break; 189 case 0x6: tmp = "Other Digital"; break; 190 case 0x7: tmp = "Other Analog"; break; 191 case 0x8: tmp = "Multichannel Analog (DIN)"; break; 192 case 0x9: tmp = "XLR/Pro"; break; 193 case 0xa: tmp = "RJ-11 (Modem)"; break; 194 case 0xb: tmp = "Combination"; break; 195 case 0xf: tmp = "Other"; break; 196 default: tmp = "Unknown"; break; 197 } 198 199 printf(FMT("%s (%u)\n"), "Connection Type", tmp, cfg.connection_type()); 200 201 // Table 113 202 switch (cfg.color()) { 203 case 0x1: tmp = "Black"; break; 204 case 0x2: tmp = "Grey"; break; 205 case 0x3: tmp = "Blue"; break; 206 case 0x4: tmp = "Green"; break; 207 case 0x5: tmp = "Red"; break; 208 case 0x6: tmp = "Orange"; break; 209 case 0x7: tmp = "Yellow"; break; 210 case 0x8: tmp = "Purple"; break; 211 case 0x9: tmp = "Pink"; break; 212 case 0xe: tmp = "White"; break; 213 case 0xf: tmp = "Other"; break; 214 default: tmp = "Unknown"; break; 215 } 216 217 printf(FMT("%s (%u)\n"), "Color", tmp, cfg.color()); 218 219 // Associations and Flags 220 printf(FMT("Assoc Group (%u) Assoc Seq (%u)%s\n"), "Assoc/Flags", 221 cfg.default_assoc(), 222 cfg.sequence(), 223 cfg.misc() & 0x1 ? " JackDetectOverride" : ""); 224 225} 226#undef FMT 227 228typedef struct flag_lut_entry { 229 uint32_t flag_bit; 230 const char* flag_name; 231} flag_lut_entry_t; 232 233static void ihda_dump_delay(uint8_t delay) { 234 if (delay) 235 printf("%u samples\n", delay); 236 else 237 printf("unknown\n"); 238} 239 240static void ihda_dump_flags(uint32_t flags, 241 const flag_lut_entry_t* table, 242 size_t table_size, 243 const char* suffix, 244 const char* no_flags_text) { 245 bool got_one = false; 246 for (size_t i = 0; i < table_size; ++i) { 247 if (flags & table[i].flag_bit) { 248 printf("%s%s", got_one ? " " : "", table[i].flag_name); 249 got_one = true; 250 } 251 } 252 253 printf("%s\n", got_one ? suffix : no_flags_text); 254} 255 256static const flag_lut_entry_t POWER_STATE_FLAGS[] = { 257 { IHDA_PWR_STATE_EPSS, "EPSS" }, 258 { IHDA_PWR_STATE_CLKSTOP, "CLKSTOP" }, 259 { IHDA_PWR_STATE_S3D3COLD, "S3D3COLD" }, 260 { IHDA_PWR_STATE_D3COLD, "D3COLD" }, 261 { IHDA_PWR_STATE_D3, "D3HOT" }, 262 { IHDA_PWR_STATE_D2, "D2" }, 263 { IHDA_PWR_STATE_D1, "D1" }, 264 { IHDA_PWR_STATE_D0, "D0" }, 265}; 266 267static const flag_lut_entry_t PCM_RATE_FLAGS[] = { 268 { IHDA_PCM_RATE_384000, "384000" }, 269 { IHDA_PCM_RATE_192000, "192000" }, 270 { IHDA_PCM_RATE_176400, "176400" }, 271 { IHDA_PCM_RATE_96000, "96000" }, 272 { IHDA_PCM_RATE_88200, "88200" }, 273 { IHDA_PCM_RATE_48000, "48000" }, 274 { IHDA_PCM_RATE_44100, "44100" }, 275 { IHDA_PCM_RATE_32000, "32000" }, 276 { IHDA_PCM_RATE_22050, "22050" }, 277 { IHDA_PCM_RATE_16000, "16000" }, 278 { IHDA_PCM_RATE_11025, "11025" }, 279 { IHDA_PCM_RATE_8000, "8000" }, 280}; 281 282static const flag_lut_entry_t PCM_SIZE_FLAGS[] = { 283 { IHDA_PCM_SIZE_32BITS, "32" }, 284 { IHDA_PCM_SIZE_24BITS, "24" }, 285 { IHDA_PCM_SIZE_20BITS, "20" }, 286 { IHDA_PCM_SIZE_16BITS, "16" }, 287 { IHDA_PCM_SIZE_8BITS, "8" }, 288}; 289 290static const flag_lut_entry_t PCM_FMT_FLAGS[] = { 291 { IHDA_PCM_FORMAT_AC3, "AC3" }, 292 { IHDA_PCM_FORMAT_FLOAT32, "FLOAT32" }, 293 { IHDA_PCM_FORMAT_PCM, "PCM" }, 294}; 295 296static const flag_lut_entry_t AW_CAPS_FLAGS[] = { 297 { AudioWidgetCaps::FLAG_AMP_PARAM_OVERRIDE, "AmpParamOverride" }, 298 { AudioWidgetCaps::FLAG_FORMAT_OVERRIDE, "FormatOverride" }, 299 { AudioWidgetCaps::FLAG_STRIPE_SUPPORTED, "StripingSupported" }, 300 { AudioWidgetCaps::FLAG_PROC_WIDGET, "HasProcessingControls" }, 301 { AudioWidgetCaps::FLAG_CAN_SEND_UNSOL, "CanSendUnsolicited" }, 302 { AudioWidgetCaps::FLAG_DIGITAL, "Digital" }, 303 { AudioWidgetCaps::FLAG_CAN_LR_SWAP, "CanSwapLR" }, 304 { AudioWidgetCaps::FLAG_HAS_CONTENT_PROT, "HasContentProtection" }, 305}; 306 307static const flag_lut_entry_t PIN_CAPS_FLAGS[] = { 308 { AW_PIN_CAPS_FLAG_CAN_IMPEDANCE_SENSE, "ImpedanceSense" }, 309 { AW_PIN_CAPS_FLAG_TRIGGER_REQUIRED, "TrigReq" }, 310 { AW_PIN_CAPS_FLAG_CAN_PRESENCE_DETECT, "PresDetect" }, 311 { AW_PIN_CAPS_FLAG_CAN_DRIVE_HEADPHONES, "HeadphoneDrive" }, 312 { AW_PIN_CAPS_FLAG_CAN_OUTPUT, "CanOutput" }, 313 { AW_PIN_CAPS_FLAG_CAN_INPUT, "CanInput" }, 314 { AW_PIN_CAPS_FLAG_BALANCED_IO, "Balanced" }, 315 { AW_PIN_CAPS_FLAG_HDMI, "HDMI" }, 316 { AW_PIN_CAPS_FLAG_VREF_HIZ, "VREF_HIZ" }, 317 { AW_PIN_CAPS_FLAG_VREF_50_PERCENT, "VREF_50%" }, 318 { AW_PIN_CAPS_FLAG_VREF_GROUND, "VREF_GND" }, 319 { AW_PIN_CAPS_FLAG_VREF_80_PERCENT, "VREF_80%" }, 320 { AW_PIN_CAPS_FLAG_VREF_100_PERCENT, "VREF_100%" }, 321 { AW_PIN_CAPS_FLAG_CAN_EAPD, "EAPD" }, 322 { AW_PIN_CAPS_FLAG_DISPLAY_PORT, "DisplayPort" }, 323 { AW_PIN_CAPS_FLAG_HIGH_BIT_RATE, "HighBitRate" }, 324}; 325 326#define DUMP_FLAGS(flags, table, suffix, no_flags_text) \ 327 ihda_dump_flags(flags, table, fbl::count_of(table), suffix, no_flags_text) 328 329static void ihda_dump_conn_list(const AudioWidgetState& widget) { 330 if (!widget.conn_list_len_) { 331 printf("empty\n"); 332 return; 333 } 334 335 ZX_DEBUG_ASSERT(widget.conn_list_); 336 for (uint32_t i = 0; i < widget.conn_list_len_; ++i) { 337 if(i > 0) 338 printf(" "); 339 340 const auto& first = widget.conn_list_[i]; 341 ZX_DEBUG_ASSERT(!first.range_); 342 343 // Is this entry the start of a range or not? 344 if ((i + 1) < widget.conn_list_len_) { 345 const auto& second = widget.conn_list_[i + 1]; 346 if (second.range_) { 347 printf("[%hu, %hu]", first.nid_, second.nid_); 348 i++; 349 continue; 350 } 351 } 352 353 printf("%hu", first.nid_); 354 } 355 356 // Mixers are always connected to all of the inputs on their connection lists. 357 if (widget.caps_.type() != AudioWidgetCaps::Type::MIXER) { 358 if (widget.connected_nid_ndx_ < widget.conn_list_len_) { 359 printf(" : [*%hu, ndx %u]\n", widget.connected_nid_, widget.connected_nid_ndx_); 360 } else { 361 printf(" : [*INVALID, ndx %u]\n", widget.connected_nid_ndx_); 362 } 363 } else { 364 printf("\n"); 365 } 366 367} 368 369#define FMT(fmt) "%s%20s : " fmt, pad 370static void ihda_dump_widget(const AudioWidgetState& widget, uint32_t id, uint32_t count) { 371 static const char* pad = "+----- "; 372 373 printf("%sWidget %u/%u\n", pad, id, count); 374 printf(FMT("%hu\n"), "Node ID", widget.nid_); 375 printf(FMT("[%02x] %s\n"), "Type", 376 static_cast<uint32_t>(widget.caps_.type()), 377 ToString(widget.caps_.type())); 378 379 printf(FMT("%08x\n"), "Raw Caps", widget.caps_.raw_data_); 380 381 printf(FMT(""), "Flags"); 382 DUMP_FLAGS(widget.caps_.raw_data_, AW_CAPS_FLAGS, "", "none"); 383 384 if (widget.caps_.can_send_unsol()) { 385 printf(FMT("%s [tag 0x%02x]\n"), "Unsolicited Ctrl", 386 widget.unsol_resp_ctrl_.enabled() ? "enabled" : "disabled", 387 widget.unsol_resp_ctrl_.tag()); 388 } 389 390 printf(FMT(""), "Delay"); 391 ihda_dump_delay(widget.caps_.delay()); 392 393 printf(FMT("%u\n"), "MaxChan", widget.caps_.ch_count()); 394 395 if (widget.caps_.input_amp_present()) { 396 if (widget.caps_.type() != AudioWidgetCaps::Type::MIXER) { 397 printf(FMT(""), "InputAmp"); 398 Dump(widget.input_amp_caps_, &widget.input_amp_state_); 399 } else { 400 for (uint8_t i = 0; i < widget.conn_list_len_; ++i) { 401 char tag[32]; 402 snprintf(tag, fbl::count_of(tag), "InputAmp[nid %hu]", widget.conn_list_[i].nid_); 403 printf(FMT(""), tag); 404 Dump(widget.input_amp_caps_, &widget.conn_list_[i].amp_state_); 405 } 406 } 407 } 408 409 if (widget.caps_.output_amp_present()) { 410 printf(FMT(""), "OutputAmp"); 411 Dump(widget.output_amp_caps_, &widget.output_amp_state_); 412 } 413 414 if (widget.caps_.format_override()) { 415 printf(FMT(""), "PCM Rates"); 416 DUMP_FLAGS(widget.pcm_size_rate_, PCM_RATE_FLAGS, "", "none"); 417 418 printf(FMT(""), "PCM Sizes"); 419 DUMP_FLAGS(widget.pcm_size_rate_, PCM_SIZE_FLAGS, " bits", "none"); 420 421 printf(FMT(""), "PCM Formats"); 422 DUMP_FLAGS(widget.pcm_formats_, PCM_FMT_FLAGS, "", "none"); 423 } 424 425 if ((widget.caps_.type() == AudioWidgetCaps::Type::INPUT) || 426 (widget.caps_.type() == AudioWidgetCaps::Type::OUTPUT)) { 427 printf(FMT(""), "Cur Format"); 428 Dump(widget.cur_format_); 429 printf(FMT("tag (%u) chan (%u)\n"), "Tag/Chan", widget.stream_tag_, widget.stream_chan_); 430 } 431 432 if (widget.caps_.type() == AudioWidgetCaps::Type::PIN_COMPLEX) { 433 if (widget.pin_sense_valid_) { 434 const char* pstring = widget.pin_sense_.presence_detect() ? "Plugged" : "Unplugged"; 435 if (widget.caps_.digital()) { 436 printf(FMT("%s, ELD %s [raw 0x%08x]\n"), "Pin Sense", 437 pstring, 438 widget.pin_sense_.eld_valid() ? "Valid" : "Invalid", 439 widget.pin_sense_.raw_data_); 440 } else { 441 if (widget.pin_caps_ & AW_PIN_CAPS_FLAG_CAN_IMPEDANCE_SENSE) { 442 printf(FMT("%s, Impedance %u [raw 0x%08x]\n"), "Pin Sense", 443 pstring, widget.pin_sense_.impedance(), widget.pin_sense_.raw_data_); 444 } else { 445 printf(FMT("%s [raw 0x%08x]\n"), "Pin Sense", 446 pstring, widget.pin_sense_.raw_data_); 447 } 448 } 449 } 450 451 printf(FMT(""), "Pin Caps"); 452 DUMP_FLAGS(widget.pin_caps_, PIN_CAPS_FLAGS, "", "none"); 453 } 454 455 if (widget.caps_.can_lr_swap()) 456 printf(FMT("%s\n"), "L/R Swap", widget.eapd_state_.lr_swap() ? "Swapped" : "Normal"); 457 458 if (widget.caps_.type() == AudioWidgetCaps::Type::PIN_COMPLEX) { 459 if (widget.pin_caps_ & AW_PIN_CAPS_FLAG_CAN_INPUT) 460 printf(FMT("%s\n"), "Input", 461 widget.pin_widget_ctrl_.input_enb() ? "Enabled" : "Disabled"); 462 463 if (widget.pin_caps_ & AW_PIN_CAPS_FLAG_CAN_OUTPUT) 464 printf(FMT("%s\n"), "Output", 465 widget.pin_widget_ctrl_.output_enb() ? "Enabled" : "Disabled"); 466 467 if (widget.pin_caps_ & AW_PIN_CAPS_FLAG_CAN_DRIVE_HEADPHONES) 468 printf(FMT("%s\n"), "Headphone Amp", 469 widget.pin_widget_ctrl_.hp_amp_enb() ? "Enabled" : "Disabled"); 470 471 if (!widget.caps_.digital() && 472 (widget.pin_caps_ & (AW_PIN_CAPS_FLAG_VREF_HIZ | 473 AW_PIN_CAPS_FLAG_VREF_50_PERCENT | 474 AW_PIN_CAPS_FLAG_VREF_GROUND | 475 AW_PIN_CAPS_FLAG_VREF_80_PERCENT | 476 AW_PIN_CAPS_FLAG_VREF_100_PERCENT))) { 477 const char* tmp; 478 switch (widget.pin_widget_ctrl_.vref_enb()) { 479 case VRefEn::HiZ: tmp = "Hi-Z"; break; 480 case VRefEn::P50: tmp = "50%"; break; 481 case VRefEn::Gnd: tmp = "Grounded"; break; 482 case VRefEn::P80: tmp = "80%"; break; 483 case VRefEn::P100: tmp = "100%"; break; 484 default: tmp = "Unknown"; break; 485 } 486 printf(FMT("%s\n"), "VRef", tmp); 487 } 488 489 if (widget.caps_.digital()) { 490 const char* tmp; 491 switch (widget.pin_widget_ctrl_.ept()) { 492 case EPT::Native: tmp = "Native"; break; 493 case EPT::HBR: tmp = "High Bit Rate"; break; 494 default: tmp = "Unknown"; break; 495 } 496 printf(FMT("%s\n"), "Encoded Pkt Type", tmp); 497 } 498 499 if (widget.pin_caps_ & AW_PIN_CAPS_FLAG_BALANCED_IO) 500 printf(FMT("%s\n"), "Balanced Output", widget.eapd_state_.btl() ? "Yes" : "No"); 501 502 if (widget.pin_caps_ & AW_PIN_CAPS_FLAG_CAN_EAPD) 503 printf(FMT("Powered %s\n"), "External Amp", widget.eapd_state_.eapd() ? "Up" : "Down"); 504 505 printf(FMT("0x%08x\n"), "Raw Cfg Defaults", widget.cfg_defaults_.raw_data_); 506 Dump(widget.cfg_defaults_); 507 } 508 509 if (widget.caps_.has_power_ctl()) { 510 printf(FMT(""), "Sup. Pwr States"); 511 DUMP_FLAGS(widget.power_.supported_states_, POWER_STATE_FLAGS, "", "none"); 512 printf(FMT("Set %s(%u) Active %s(%u)%s%s%s\n"), "Cur Pwr State", 513 PowerStateToString(widget.power_.set_), widget.power_.set_, 514 PowerStateToString(widget.power_.active_), widget.power_.active_, 515 widget.power_.error_ ? " [ERROR]" : "", 516 widget.power_.clock_stop_ok_ ? " [ClkStopOK]" : "", 517 widget.power_.settings_reset_ ? " [Settings Reset]" : ""); 518 } 519 520 if (widget.caps_.has_conn_list()) { 521 printf(FMT(""), "ConnList"); 522 ihda_dump_conn_list(widget); 523 } 524 525 if (widget.caps_.proc_widget()) { 526 printf(FMT("%s\n"), "Can Bypass Proc", widget.can_bypass_processing_ ? "yes" : "no"); 527 printf(FMT("%u\n"), "Proc Coefficients", widget.processing_coefficient_count_); 528 } 529 530 if (widget.caps_.type() == AudioWidgetCaps::Type::VOLUME_KNOB) { 531 printf(FMT("%s\n"), "Vol Knob Type", widget.vol_knob_is_delta_ ? "delta" : "absolute"); 532 printf(FMT("%u\n"), "Vol Knob Steps", widget.vol_knob_steps_); 533 } 534 535 printf("%s\n", pad); 536} 537#undef FMT 538 539#define FMT(fmt) "%s%26s : " fmt, pad 540static void ihda_dump_codec_fn_group(const CodecState& codec, uint32_t id) { 541 ZX_DEBUG_ASSERT(codec.fn_groups_ && (id < codec.fn_group_count_) && codec.fn_groups_[id]); 542 static const char* pad = "+--- "; 543 const auto& fn_group = *codec.fn_groups_[id]; 544 545 printf("%sFunction Group %u/%u\n", pad, id + 1, codec.fn_group_count_); 546 printf(FMT("%hu\n"), "Node ID", fn_group.nid_); 547 printf(FMT("%s\n"), "Type", ToString(fn_group.type_)); 548 549 if (fn_group.can_send_unsolicited_) { 550 printf(FMT("%s [tag 0x%02x]\n"), "Unsolicited Ctrl", 551 fn_group.unsol_resp_ctrl_.enabled() ? "enabled" : "disabled", 552 fn_group.unsol_resp_ctrl_.tag()); 553 } 554 555 if (fn_group.type_ != FunctionGroupState::Type::AUDIO) 556 return; 557 558 const auto& afg = *reinterpret_cast<AudioFunctionGroupState*>(codec.fn_groups_[id].get()); 559 560 printf(FMT("%08x\n"), "Raw Caps", afg.caps_.raw_data_); 561 printf(FMT("%s\n"), "Beep Gen", afg.caps_.has_beep_gen() ? "yes" : "no"); 562 563 printf(FMT(""), "Input Path Delay"); 564 ihda_dump_delay(afg.caps_.path_input_delay()); 565 566 printf(FMT(""), "Output Path Delay"); 567 ihda_dump_delay(afg.caps_.path_output_delay()); 568 569 printf(FMT(""), "Default PCM Rates"); 570 DUMP_FLAGS(afg.default_pcm_size_rate_, PCM_RATE_FLAGS, "", "none"); 571 572 printf(FMT(""), "Default PCM Sizes"); 573 DUMP_FLAGS(afg.default_pcm_size_rate_, PCM_SIZE_FLAGS, " bits", "none"); 574 575 printf(FMT(""), "Default PCM Formats"); 576 DUMP_FLAGS(afg.default_pcm_formats_, PCM_FMT_FLAGS, "", "none"); 577 578 printf(FMT(""), "Default Input Amp Caps"); 579 Dump(afg.default_input_amp_caps_); 580 581 printf(FMT(""), "Default Output Amp Caps"); 582 Dump(afg.default_output_amp_caps_); 583 584 printf(FMT(""), "Sup. Pwr States"); 585 DUMP_FLAGS(afg.power_.supported_states_, POWER_STATE_FLAGS, "", "none"); 586 printf(FMT("Set %s(%u) Active %s(%u)%s%s%s\n"), "Cur Pwr State", 587 PowerStateToString(afg.power_.set_), afg.power_.set_, 588 PowerStateToString(afg.power_.active_), afg.power_.active_, 589 afg.power_.error_ ? " [ERROR]" : "", 590 afg.power_.clock_stop_ok_ ? " [ClkStopOK]" : "", 591 afg.power_.settings_reset_ ? " [Settings Reset]" : ""); 592 593 printf(FMT("%u\n"), "GPIOs", afg.gpio_count_); 594 printf(FMT("%u\n"), "GPIs", afg.gpi_count_); 595 printf(FMT("%u\n"), "GPOs", afg.gpo_count_); 596 printf(FMT("%s\n"), "GPIOs can wake", afg.gpio_can_wake_ ? "yes" : "no"); 597 printf(FMT("%s\n"), "GPIOs can send unsolicited", 598 afg.gpio_can_send_unsolicited_ ? "yes" : "no"); 599 600 601 printf(FMT("BMID(%04hx) BSKU(%02x) AssyID(%02x) : Raw 0x%08x\n"), "Impl ID", 602 fn_group.impl_id_.BoardMfrID(), 603 fn_group.impl_id_.BoardSKU(), 604 fn_group.impl_id_.AssemblyID(), 605 fn_group.impl_id_.raw_data_); 606 607 printf(FMT("%u\n"), "Widgets", afg.widget_count_); 608 609 for (uint32_t i = 0; i < afg.widget_count_; ++i) { 610 ZX_DEBUG_ASSERT(afg.widgets_[i]); 611 ihda_dump_widget(*afg.widgets_[i], i + 1, afg.widget_count_); 612 } 613} 614#undef FMT 615} // namespace 616 617#define FMT(fmt) "%s%10s : " fmt, pad 618void print_codec_state(const CodecState& codec) { 619 static const char* pad = "+- "; 620 621 printf(FMT("0x%04hx:0x%04hx\n"), "VID/DID", codec.vendor_id_, codec.device_id_); 622 printf(FMT("%u.%u\n"), "Rev", codec.major_rev_, codec.minor_rev_); 623 printf(FMT("%u.%u\n"), "Vendor Rev", codec.vendor_rev_id_, codec.vendor_stepping_id_); 624 printf("%s%u function group%s\n", 625 pad, codec.fn_group_count_, codec.fn_group_count_ == 1 ? "" : "s"); 626 627 for (uint32_t i = 0; i < codec.fn_group_count_; ++i) 628 ihda_dump_codec_fn_group(codec, i); 629} 630#undef FMT 631 632} // namespace audio 633} // namespace intel_hda 634