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