2 * Copyright 2007-2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
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
13 #include "hda_codec_defs.h"
19 # define TRACE(a...) dprintf("hda: " a)
23 #define ERROR(a...) dprintf("hda: " a)
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 \
44 #define HDA_QUIRK_OVREF (HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 \
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
56 static const char* kPortConnector
[] = {
57 "Jack", "None", "Fixed", "Dual"
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"
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"
72 static const char* kJackColor
[] = {
73 "N/A", "Black", "Grey", "Blue", "Green", "Red", "Orange", "Yellow",
74 "Purple", "Pink", "-", "-", "-", "-", "White", "Other"
78 uint32 subsystem_vendor_id
, subsystem_id
;
79 uint32 codec_vendor_id
, codec_id
;
80 uint32 quirks
, nonquirks
;
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, 0x00a1, REALTEK_VENDORID
, 0x0885,
93 HDA_QUIRK_GPIO0
| HDA_QUIRK_OVREF50
, 0}, // MacBook
94 { 0x106b, 0x00a3, REALTEK_VENDORID
, 0x0885,
95 HDA_QUIRK_GPIO0
, 0}, // MacBook
96 { HDA_ALL
, HDA_ALL
, IDT_VENDORID
, 0x76b2, HDA_QUIRK_GPIO0
, 0},
101 get_widget_type_name(hda_widget_type type
)
104 case WT_AUDIO_OUTPUT
:
105 return "Audio output";
107 return "Audio input";
109 return "Audio mixer";
110 case WT_AUDIO_SELECTOR
:
111 return "Audio selector";
113 return "Pin complex";
117 return "Volume knob";
118 case WT_BEEP_GENERATOR
:
119 return "Beep generator";
120 case WT_VENDOR_DEFINED
:
121 return "Vendor defined";
129 get_widget_location(uint32 location
)
131 switch (location
>> 4) {
134 switch (location
& 0xf) {
155 switch (location
& 0xf) {
164 switch (location
& 0xf) {
170 return "Outside lid";
180 dump_widget_audio_capabilities(uint32 capabilities
)
182 static const struct {
186 {AUDIO_CAP_CP_CAPS
, "CP caps"},
187 {AUDIO_CAP_LEFT_RIGHT_SWAP
, "L-R swap"},
188 {AUDIO_CAP_POWER_CONTROL
, "Power"},
189 {AUDIO_CAP_DIGITAL
, "Digital"},
190 {AUDIO_CAP_CONNECTION_LIST
, "Conn. list"},
191 {AUDIO_CAP_UNSOLICITED_RESPONSES
, "Unsol. responses"},
192 {AUDIO_CAP_PROCESSING_CONTROLS
, "Proc widget"},
193 {AUDIO_CAP_STRIPE
, "Stripe"},
194 {AUDIO_CAP_FORMAT_OVERRIDE
, "Format override"},
195 {AUDIO_CAP_AMPLIFIER_OVERRIDE
, "Amplifier override"},
196 {AUDIO_CAP_OUTPUT_AMPLIFIER
, "Out amplifier"},
197 {AUDIO_CAP_INPUT_AMPLIFIER
, "In amplifier"},
198 {AUDIO_CAP_STEREO
, "Stereo"},
204 for (uint32 j
= 0; j
< sizeof(kFlags
) / sizeof(kFlags
[0]); j
++) {
205 if ((capabilities
& kFlags
[j
].flag
) != 0)
206 offset
+= sprintf(buffer
+ offset
, "[%s] ", kFlags
[j
].name
);
210 TRACE("\t%s\n", buffer
);
215 dump_widget_inputs(hda_widget
& widget
)
222 for (uint32 i
= 0; i
< widget
.num_inputs
; i
++) {
223 int32 input
= widget
.inputs
[i
];
225 if ((int32
)i
!= widget
.active_input
)
226 offset
+= sprintf(buffer
+ offset
, "%ld ", input
);
228 offset
+= sprintf(buffer
+ offset
, "<%ld> ", input
);
232 TRACE("\tInputs: %s\n", buffer
);
237 dump_widget_amplifier_capabilities(hda_widget
& widget
, bool input
)
241 capabilities
= widget
.capabilities
.input_amplifier
;
243 capabilities
= widget
.capabilities
.output_amplifier
;
245 if (capabilities
== 0)
248 TRACE("\t%s Amp: %sstep size: %f dB, # steps: %ld, offset to 0 dB: "
249 "%ld\n", input
? "In" : "Out",
250 (capabilities
& AMP_CAP_MUTE
) != 0 ? "supports mute, " : "",
251 AMP_CAP_STEP_SIZE(capabilities
),
252 AMP_CAP_NUM_STEPS(capabilities
),
253 AMP_CAP_OFFSET(capabilities
));
258 dump_widget_pm_support(hda_widget
& widget
)
260 TRACE("\tSupported power states: %s%s%s%s%s%s%s%s\n",
261 widget
.pm
& POWER_STATE_D0
? "D0 " : "",
262 widget
.pm
& POWER_STATE_D1
? "D1 " : "",
263 widget
.pm
& POWER_STATE_D2
? "D2 " : "",
264 widget
.pm
& POWER_STATE_D3
? "D3 " : "",
265 widget
.pm
& POWER_STATE_D3COLD
? "D3COLD " : "",
266 widget
.pm
& POWER_STATE_S3D3COLD
? "S3D3COLD " : "",
267 widget
.pm
& POWER_STATE_CLKSTOP
? "CLKSTOP " : "",
268 widget
.pm
& POWER_STATE_EPSS
? "EPSS " : "");
273 dump_widget_stream_support(hda_widget
& widget
)
275 TRACE("\tSupported formats: %s%s%s%s%s%s%s%s%s\n",
276 widget
.d
.io
.formats
& B_FMT_8BIT_S
? "8bits " : "",
277 widget
.d
.io
.formats
& B_FMT_16BIT
? "16bits " : "",
278 widget
.d
.io
.formats
& B_FMT_20BIT
? "20bits " : "",
279 widget
.d
.io
.formats
& B_FMT_24BIT
? "24bits " : "",
280 widget
.d
.io
.formats
& B_FMT_32BIT
? "32bits " : "",
281 widget
.d
.io
.formats
& B_FMT_FLOAT
? "float " : "",
282 widget
.d
.io
.formats
& B_FMT_DOUBLE
? "double " : "",
283 widget
.d
.io
.formats
& B_FMT_EXTENDED
? "extended " : "",
284 widget
.d
.io
.formats
& B_FMT_BITSTREAM
? "bitstream " : "");
285 TRACE("\tSupported rates: %s%s%s%s%s%s%s%s%s%s%s%s\n",
286 widget
.d
.io
.rates
& B_SR_8000
? "8khz " : "",
287 widget
.d
.io
.rates
& B_SR_11025
? "11khz " : "",
288 widget
.d
.io
.rates
& B_SR_16000
? "16khz " : "",
289 widget
.d
.io
.rates
& B_SR_22050
? "22khz " : "",
290 widget
.d
.io
.rates
& B_SR_32000
? "32khz " : "",
291 widget
.d
.io
.rates
& B_SR_44100
? "44khz " : "",
292 widget
.d
.io
.rates
& B_SR_48000
? "48khz " : "",
293 widget
.d
.io
.rates
& B_SR_88200
? "88khz " : "",
294 widget
.d
.io
.rates
& B_SR_96000
? "96khz " : "",
295 widget
.d
.io
.rates
& B_SR_176400
? "176khz " : "",
296 widget
.d
.io
.rates
& B_SR_192000
? "192khz " : "",
297 widget
.d
.io
.rates
& B_SR_384000
? "384khz " : "");
303 dump_pin_complex_capabilities(hda_widget
& widget
)
305 TRACE("\t%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
306 widget
.d
.pin
.capabilities
& PIN_CAP_IMP_SENSE
? "[Imp Sense] " : "",
307 widget
.d
.pin
.capabilities
& PIN_CAP_TRIGGER_REQ
? "[Trigger Req]" : "",
308 widget
.d
.pin
.capabilities
& PIN_CAP_PRES_DETECT
? "[Pres Detect]" : "",
309 widget
.d
.pin
.capabilities
& PIN_CAP_HP_DRIVE
? "[HP Drive]" : "",
310 widget
.d
.pin
.capabilities
& PIN_CAP_OUTPUT
? "[Output]" : "",
311 widget
.d
.pin
.capabilities
& PIN_CAP_INPUT
? "[Input]" : "",
312 widget
.d
.pin
.capabilities
& PIN_CAP_BALANCE
? "[Balance]" : "",
313 widget
.d
.pin
.capabilities
& PIN_CAP_VREF_CTRL_HIZ
? "[VRef HIZ]" : "",
314 widget
.d
.pin
.capabilities
& PIN_CAP_VREF_CTRL_50
? "[VRef 50]" : "",
315 widget
.d
.pin
.capabilities
& PIN_CAP_VREF_CTRL_GROUND
? "[VRef Gr]" : "",
316 widget
.d
.pin
.capabilities
& PIN_CAP_VREF_CTRL_80
? "[VRef 80]" : "",
317 widget
.d
.pin
.capabilities
& PIN_CAP_VREF_CTRL_100
? "[VRef 100]" : "",
318 widget
.d
.pin
.capabilities
& PIN_CAP_EAPD_CAP
? "[EAPD]" : "");
323 dump_audiogroup_widgets(hda_audio_group
* audioGroup
)
325 TRACE("\tAudiogroup:\n");
326 // Iterate over all widgets and collect info
327 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
328 hda_widget
& widget
= audioGroup
->widgets
[i
];
329 uint32 nodeID
= audioGroup
->widget_start
+ i
;
331 TRACE("%ld: %s\n", nodeID
, get_widget_type_name(widget
.type
));
333 switch (widget
.type
) {
334 case WT_AUDIO_OUTPUT
:
339 dump_pin_complex_capabilities(widget
);
346 dump_widget_pm_support(widget
);
347 dump_widget_audio_capabilities(widget
.capabilities
.audio
);
348 dump_widget_amplifier_capabilities(widget
, true);
349 dump_widget_amplifier_capabilities(widget
, false);
350 dump_widget_inputs(widget
);
359 hda_codec_get_quirks(hda_codec
* codec
)
363 uint32 subSystemID
= codec
->controller
->pci_info
.u
.h0
.subsystem_id
;
364 uint32 subSystemVendorID
365 = codec
->controller
->pci_info
.u
.h0
.subsystem_vendor_id
;
368 i
< (sizeof(kCodecQuirks
) / sizeof(kCodecQuirks
[0])); i
++) {
369 if (kCodecQuirks
[i
].subsystem_id
!= HDA_ALL
370 && kCodecQuirks
[i
].subsystem_id
!= subSystemID
)
372 if (kCodecQuirks
[i
].subsystem_vendor_id
!= HDA_ALL
373 && kCodecQuirks
[i
].subsystem_vendor_id
!= subSystemVendorID
)
375 if (kCodecQuirks
[i
].codec_vendor_id
!= HDA_ALL
376 && kCodecQuirks
[i
].codec_vendor_id
!= codec
->vendor_id
)
378 if (kCodecQuirks
[i
].codec_id
!= HDA_ALL
379 && kCodecQuirks
[i
].codec_id
!= codec
->product_id
)
382 codec
->quirks
|= kCodecQuirks
[i
].quirks
;
383 codec
->quirks
&= ~kCodecQuirks
[i
].nonquirks
;
389 hda_get_pm_support(hda_codec
* codec
, uint32 nodeID
, uint32
* pm
)
391 corb_t verb
= MAKE_VERB(codec
->addr
, nodeID
, VID_GET_PARAMETER
,
392 PID_POWERSTATE_SUPPORT
);
395 status_t status
= hda_send_verbs(codec
, &verb
, &response
, 1);
397 *pm
= response
& 0xf;
404 hda_get_stream_support(hda_codec
* codec
, uint32 nodeID
, uint32
* formats
,
411 verbs
[0] = MAKE_VERB(codec
->addr
, nodeID
, VID_GET_PARAMETER
,
413 verbs
[1] = MAKE_VERB(codec
->addr
, nodeID
, VID_GET_PARAMETER
,
416 status
= hda_send_verbs(codec
, verbs
, resp
, 2);
423 if ((resp
[0] & (STREAM_FLOAT
| STREAM_PCM
)) != 0) {
424 if (resp
[1] & (1 << 0))
426 if (resp
[1] & (1 << 1))
427 *rates
|= B_SR_11025
;
428 if (resp
[1] & (1 << 2))
429 *rates
|= B_SR_16000
;
430 if (resp
[1] & (1 << 3))
431 *rates
|= B_SR_22050
;
432 if (resp
[1] & (1 << 4))
433 *rates
|= B_SR_32000
;
434 if (resp
[1] & (1 << 5))
435 *rates
|= B_SR_44100
;
436 if (resp
[1] & (1 << 6))
437 *rates
|= B_SR_48000
;
438 if (resp
[1] & (1 << 7))
439 *rates
|= B_SR_88200
;
440 if (resp
[1] & (1 << 8))
441 *rates
|= B_SR_96000
;
442 if (resp
[1] & (1 << 9))
443 *rates
|= B_SR_176400
;
444 if (resp
[1] & (1 << 10))
445 *rates
|= B_SR_192000
;
446 if (resp
[1] & (1 << 11))
447 *rates
|= B_SR_384000
;
449 if (resp
[1] & PCM_8_BIT
)
450 *formats
|= B_FMT_8BIT_S
;
451 if (resp
[1] & PCM_16_BIT
)
452 *formats
|= B_FMT_16BIT
;
453 if (resp
[1] & PCM_20_BIT
)
454 *formats
|= B_FMT_20BIT
;
455 if (resp
[1] & PCM_24_BIT
)
456 *formats
|= B_FMT_24BIT
;
457 if (resp
[1] & PCM_32_BIT
)
458 *formats
|= B_FMT_32BIT
;
460 if ((resp
[0] & STREAM_FLOAT
) != 0)
461 *formats
|= B_FMT_FLOAT
;
462 if ((resp
[0] & STREAM_AC3
) != 0) {
463 *formats
|= B_FMT_BITSTREAM
;
470 // #pragma mark - widget functions
474 hda_widget_get_pm_support(hda_audio_group
* audioGroup
, hda_widget
* widget
)
476 return hda_get_pm_support(audioGroup
->codec
, widget
->node_id
, &widget
->pm
);
481 hda_widget_get_stream_support(hda_audio_group
* audioGroup
, hda_widget
* widget
)
483 if (audioGroup
->widget
.node_id
!= widget
->node_id
484 && (widget
->capabilities
.audio
& AUDIO_CAP_FORMAT_OVERRIDE
) == 0) {
485 // adopt capabilities of the audio group
486 widget
->d
.io
.formats
= audioGroup
->widget
.d
.io
.formats
;
487 widget
->d
.io
.rates
= audioGroup
->widget
.d
.io
.rates
;
491 return hda_get_stream_support(audioGroup
->codec
, widget
->node_id
,
492 &widget
->d
.io
.formats
, &widget
->d
.io
.rates
);
497 hda_widget_get_amplifier_capabilities(hda_audio_group
* audioGroup
,
503 if ((widget
->capabilities
.audio
& AUDIO_CAP_OUTPUT_AMPLIFIER
) != 0
504 || audioGroup
->widget
.node_id
== widget
->node_id
) {
505 if ((widget
->capabilities
.audio
& AUDIO_CAP_AMPLIFIER_OVERRIDE
) != 0
506 || audioGroup
->widget
.node_id
== widget
->node_id
) {
507 verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
->node_id
,
508 VID_GET_PARAMETER
, PID_OUTPUT_AMPLIFIER_CAP
);
509 status_t status
= hda_send_verbs(audioGroup
->codec
, &verb
,
514 widget
->capabilities
.output_amplifier
= response
;
516 // adopt capabilities from the audio function group
517 widget
->capabilities
.output_amplifier
518 = audioGroup
->widget
.capabilities
.output_amplifier
;
522 if ((widget
->capabilities
.audio
& AUDIO_CAP_INPUT_AMPLIFIER
) != 0
523 || audioGroup
->widget
.node_id
== widget
->node_id
) {
524 if ((widget
->capabilities
.audio
& AUDIO_CAP_AMPLIFIER_OVERRIDE
525 || audioGroup
->widget
.node_id
== widget
->node_id
) != 0) {
526 verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
->node_id
,
527 VID_GET_PARAMETER
, PID_INPUT_AMPLIFIER_CAP
);
528 status_t status
= hda_send_verbs(audioGroup
->codec
, &verb
,
533 widget
->capabilities
.input_amplifier
= response
;
535 // adopt capabilities from the audio function group
536 widget
->capabilities
.input_amplifier
537 = audioGroup
->widget
.capabilities
.input_amplifier
;
546 hda_audio_group_get_widget(hda_audio_group
* audioGroup
, uint32 nodeID
)
548 if (audioGroup
->widget_start
> nodeID
549 || audioGroup
->widget_start
+ audioGroup
->widget_count
< nodeID
)
552 return &audioGroup
->widgets
[nodeID
- audioGroup
->widget_start
];
557 hda_widget_get_connections(hda_audio_group
* audioGroup
, hda_widget
* widget
)
559 corb_t verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
->node_id
,
560 VID_GET_PARAMETER
, PID_CONNECTION_LIST_LENGTH
);
563 if (hda_send_verbs(audioGroup
->codec
, &verb
, &response
, 1) != B_OK
)
566 uint32 listEntries
= response
& 0x7f;
567 bool longForm
= (response
& 0xf0) != 0;
569 if (listEntries
== 0)
573 if (widget
->num_inputs
> 1) {
574 // Get currently active connection
575 verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
->node_id
,
576 VID_GET_CONNECTION_SELECT
, 0);
577 if (hda_send_verbs(audioGroup
->codec
, &verb
, &response
, 1) == B_OK
)
578 widget
->active_input
= response
& 0xff;
582 uint32 valuesPerEntry
= longForm
? 2 : 4;
583 uint32 shift
= 32 / valuesPerEntry
;
584 uint32 rangeMask
= (1 << (shift
- 1));
585 int32 previousInput
= -1;
586 uint32 numInputs
= 0;
588 for (uint32 i
= 0; i
< listEntries
; i
++) {
589 if ((i
% valuesPerEntry
) == 0) {
590 // We get 2 or 4 answers per call depending on if we're
591 // in short or long list mode
592 verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
->node_id
,
593 VID_GET_CONNECTION_LIST_ENTRY
, i
);
594 if (hda_send_verbs(audioGroup
->codec
, &verb
, &response
, 1)
596 ERROR("Error parsing inputs for widget %ld!\n",
602 int32 input
= (response
>> (shift
* (i
% valuesPerEntry
)))
603 & ((1 << shift
) - 1);
605 if (input
& rangeMask
) {
609 if (input
< previousInput
|| previousInput
== -1) {
610 ERROR("invalid range from %ld to %ld\n", previousInput
,
615 for (int32 rangeInput
= previousInput
+ 1; rangeInput
<= input
616 && numInputs
< MAX_INPUTS
; rangeInput
++) {
617 widget
->inputs
[numInputs
++] = rangeInput
;
621 } else if (numInputs
< MAX_INPUTS
) {
623 widget
->inputs
[numInputs
++] = input
;
624 previousInput
= input
;
628 widget
->num_inputs
= numInputs
;
630 if (widget
->num_inputs
== 1)
631 widget
->active_input
= 0;
638 hda_widget_get_associations(hda_audio_group
* audioGroup
)
641 for (uint32 i
= 0; i
< MAX_ASSOCIATIONS
; i
++) {
642 for (uint32 j
= 0; j
< audioGroup
->widget_count
; j
++) {
643 hda_widget
& widget
= audioGroup
->widgets
[j
];
645 if (widget
.type
!= WT_PIN_COMPLEX
)
647 if (CONF_DEFAULT_ASSOCIATION(widget
.d
.pin
.config
) != i
)
649 if (audioGroup
->associations
[index
].pin_count
== 0) {
650 audioGroup
->associations
[index
].index
= index
;
651 audioGroup
->associations
[index
].enabled
= true;
653 uint32 sequence
= CONF_DEFAULT_SEQUENCE(widget
.d
.pin
.config
);
654 if (audioGroup
->associations
[index
].pins
[sequence
] != 0) {
655 audioGroup
->associations
[index
].enabled
= false;
657 audioGroup
->associations
[index
].pins
[sequence
] = widget
.node_id
;
658 audioGroup
->associations
[index
].pin_count
++;
662 if (i
!= 15 && audioGroup
->associations
[index
].pin_count
!= 0)
665 audioGroup
->association_count
= index
;
672 hda_widget_prepare_pin_ctrl(hda_audio_group
* audioGroup
, hda_widget
* widget
,
677 ctrl
= PIN_ENABLE_HEAD_PHONE
| PIN_ENABLE_OUTPUT
;
679 ctrl
= PIN_ENABLE_INPUT
;
681 if (PIN_CAP_IS_VREF_CTRL_50_CAP(widget
->d
.pin
.capabilities
)
682 && (audioGroup
->codec
->quirks
& (isOutput
? HDA_QUIRK_OVREF50
683 : HDA_QUIRK_IVREF50
))) {
684 ctrl
|= PIN_ENABLE_VREF_50
;
685 TRACE("%s vref 50 enabled\n", isOutput
? "output" : "input");
687 if (PIN_CAP_IS_VREF_CTRL_80_CAP(widget
->d
.pin
.capabilities
)
688 && (audioGroup
->codec
->quirks
& (isOutput
? HDA_QUIRK_OVREF80
689 : HDA_QUIRK_IVREF80
))) {
690 ctrl
|= PIN_ENABLE_VREF_80
;
691 TRACE("%s vref 80 enabled\n", isOutput
? "output" : "input");
693 if (PIN_CAP_IS_VREF_CTRL_100_CAP(widget
->d
.pin
.capabilities
)
694 && (audioGroup
->codec
->quirks
& (isOutput
? HDA_QUIRK_OVREF100
695 : HDA_QUIRK_IVREF100
))) {
696 ctrl
|= PIN_ENABLE_VREF_100
;
697 TRACE("%s vref 100 enabled\n", isOutput
? "output" : "input");
704 // #pragma mark - audio group functions
708 hda_codec_parse_audio_group(hda_audio_group
* audioGroup
)
713 hda_codec
* codec
= audioGroup
->codec
;
714 uint32 codec_id
= (codec
->vendor_id
<< 16) | codec
->product_id
;
715 hda_widget_get_stream_support(audioGroup
, &audioGroup
->widget
);
716 hda_widget_get_pm_support(audioGroup
, &audioGroup
->widget
);
717 hda_widget_get_amplifier_capabilities(audioGroup
, &audioGroup
->widget
);
719 verbs
[0] = MAKE_VERB(audioGroup
->codec
->addr
, audioGroup
->widget
.node_id
,
720 VID_GET_PARAMETER
, PID_AUDIO_GROUP_CAP
);
721 verbs
[1] = MAKE_VERB(audioGroup
->codec
->addr
, audioGroup
->widget
.node_id
,
722 VID_GET_PARAMETER
, PID_GPIO_COUNT
);
723 verbs
[2] = MAKE_VERB(audioGroup
->codec
->addr
, audioGroup
->widget
.node_id
,
724 VID_GET_PARAMETER
, PID_SUB_NODE_COUNT
);
726 if (hda_send_verbs(audioGroup
->codec
, verbs
, resp
, 3) != B_OK
)
729 TRACE("Audio Group: Output delay: %ld samples, Input delay: %ld "
730 "samples, Beep Generator: %s\n", AUDIO_GROUP_CAP_OUTPUT_DELAY(resp
[0]),
731 AUDIO_GROUP_CAP_INPUT_DELAY(resp
[0]),
732 AUDIO_GROUP_CAP_BEEPGEN(resp
[0]) ? "yes" : "no");
734 TRACE(" #GPIO: %ld, #GPO: %ld, #GPI: %ld, unsol: %s, wake: %s\n",
735 GPIO_COUNT_NUM_GPIO(resp
[1]), GPIO_COUNT_NUM_GPO(resp
[1]),
736 GPIO_COUNT_NUM_GPI(resp
[1]), GPIO_COUNT_GPIUNSOL(resp
[1]) ? "yes" : "no",
737 GPIO_COUNT_GPIWAKE(resp
[1]) ? "yes" : "no");
738 dump_widget_stream_support(audioGroup
->widget
);
740 audioGroup
->gpio
= resp
[1];
741 audioGroup
->widget_start
= SUB_NODE_COUNT_START(resp
[2]);
742 audioGroup
->widget_count
= SUB_NODE_COUNT_TOTAL(resp
[2]);
744 TRACE(" widget start %lu, count %lu\n", audioGroup
->widget_start
,
745 audioGroup
->widget_count
);
747 audioGroup
->widgets
= (hda_widget
*)calloc(audioGroup
->widget_count
,
748 sizeof(*audioGroup
->widgets
));
749 if (audioGroup
->widgets
== NULL
) {
750 ERROR("ERROR: Not enough memory!\n");
754 // Iterate over all Widgets and collect info
755 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
756 hda_widget
& widget
= audioGroup
->widgets
[i
];
757 uint32 nodeID
= audioGroup
->widget_start
+ i
;
760 verbs
[0] = MAKE_VERB(audioGroup
->codec
->addr
, nodeID
, VID_GET_PARAMETER
,
761 PID_AUDIO_WIDGET_CAP
);
762 if (hda_send_verbs(audioGroup
->codec
, verbs
, &capabilities
, 1) != B_OK
)
765 widget
.type
= (hda_widget_type
)((capabilities
& AUDIO_CAP_TYPE_MASK
)
766 >> AUDIO_CAP_TYPE_SHIFT
);
768 // Check specific node ids declared as inputs as beepers
780 widget
.type
= WT_BEEP_GENERATOR
;
784 widget
.type
= WT_BEEP_GENERATOR
;
795 widget
.type
= WT_BEEP_GENERATOR
;
798 widget
.active_input
= -1;
799 widget
.capabilities
.audio
= capabilities
;
800 widget
.node_id
= nodeID
;
802 if ((capabilities
& AUDIO_CAP_POWER_CONTROL
) != 0) {
803 // We support power; switch us on!
804 verbs
[0] = MAKE_VERB(audioGroup
->codec
->addr
, nodeID
,
805 VID_SET_POWER_STATE
, 0);
806 hda_send_verbs(audioGroup
->codec
, verbs
, NULL
, 1);
810 if ((capabilities
& (AUDIO_CAP_INPUT_AMPLIFIER
811 | AUDIO_CAP_OUTPUT_AMPLIFIER
)) != 0) {
812 hda_widget_get_amplifier_capabilities(audioGroup
, &widget
);
815 TRACE("%ld: %s\n", nodeID
, get_widget_type_name(widget
.type
));
817 switch (widget
.type
) {
818 case WT_AUDIO_OUTPUT
:
820 hda_widget_get_stream_support(audioGroup
, &widget
);
821 dump_widget_stream_support(widget
);
825 verbs
[0] = MAKE_VERB(audioGroup
->codec
->addr
, nodeID
,
826 VID_GET_PARAMETER
, PID_PIN_CAP
);
827 if (hda_send_verbs(audioGroup
->codec
, verbs
, resp
, 1) == B_OK
) {
828 widget
.d
.pin
.capabilities
= resp
[0];
830 TRACE("\t%s%s\n", PIN_CAP_IS_INPUT(resp
[0]) ? "[Input] " : "",
831 PIN_CAP_IS_OUTPUT(resp
[0]) ? "[Output]" : "");
833 ERROR("%s: Error getting Pin Complex IO\n", __func__
);
836 verbs
[0] = MAKE_VERB(audioGroup
->codec
->addr
, nodeID
,
837 VID_GET_CONFIGURATION_DEFAULT
, 0);
838 if (hda_send_verbs(audioGroup
->codec
, verbs
, resp
, 1) == B_OK
) {
839 widget
.d
.pin
.config
= resp
[0];
840 const char* location
=
841 get_widget_location(CONF_DEFAULT_LOCATION(resp
[0]));
842 TRACE("\t%s, %s%s%s, %s, %s, Association:%ld\n",
843 kPortConnector
[CONF_DEFAULT_CONNECTIVITY(resp
[0])],
844 location
? location
: "",
846 kDefaultDevice
[CONF_DEFAULT_DEVICE(resp
[0])],
847 kConnectionType
[CONF_DEFAULT_CONNTYPE(resp
[0])],
848 kJackColor
[CONF_DEFAULT_COLOR(resp
[0])],
849 CONF_DEFAULT_ASSOCIATION(resp
[0]));
854 verbs
[0] = MAKE_VERB(audioGroup
->codec
->addr
, nodeID
,
855 VID_SET_VOLUME_KNOB_CONTROL
, 0x0);
856 hda_send_verbs(audioGroup
->codec
, verbs
, NULL
, 1);
862 hda_widget_get_pm_support(audioGroup
, &widget
);
863 hda_widget_get_connections(audioGroup
, &widget
);
865 dump_widget_pm_support(widget
);
866 dump_widget_audio_capabilities(capabilities
);
867 dump_widget_amplifier_capabilities(widget
, true);
868 dump_widget_amplifier_capabilities(widget
, false);
869 dump_widget_inputs(widget
);
872 hda_widget_get_associations(audioGroup
);
877 hda_verb_write(codec
, 0x20, VID_SET_COEFFICIENT_INDEX
, 0x0);
879 hda_verb_read(codec
, 0x20, VID_GET_PROCESSING_COEFFICIENT
, &tmp
);
880 hda_verb_write(codec
, 0x20, VID_SET_COEFFICIENT_INDEX
, 0x7);
881 hda_verb_write(codec
, 0x20, VID_SET_PROCESSING_COEFFICIENT
,
882 (tmp
& 0xf0) == 0x20 ? 0x830 : 0x3030);
891 /*! Find output path for widget */
893 hda_widget_find_output_path(hda_audio_group
* audioGroup
, hda_widget
* widget
,
894 uint32 depth
, bool &alreadyUsed
)
898 if (widget
== NULL
|| depth
> 16)
901 switch (widget
->type
) {
902 case WT_AUDIO_OUTPUT
:
903 widget
->flags
|= WIDGET_FLAG_OUTPUT_PATH
;
904 TRACE(" %*soutput: added output widget %ld\n", (int)depth
* 2, "", widget
->node_id
);
908 case WT_AUDIO_SELECTOR
:
911 if ((widget
->flags
& WIDGET_FLAG_OUTPUT_PATH
) != 0) {
916 // search for output in this path
918 for (uint32 i
= 0; i
< widget
->num_inputs
; i
++) {
919 hda_widget
* inputWidget
= hda_audio_group_get_widget(audioGroup
,
922 if (hda_widget_find_output_path(audioGroup
, inputWidget
,
923 depth
+ 1, alreadyUsed
)) {
924 if (widget
->active_input
== -1)
925 widget
->active_input
= i
;
927 widget
->flags
|= WIDGET_FLAG_OUTPUT_PATH
;
928 TRACE(" %*soutput: added mixer/selector widget %ld\n", (int)depth
* 2, "", widget
->node_id
);
932 if (!found
) TRACE(" %*soutput: not added mixer/selector widget %ld\n", (int)depth
* 2, "", widget
->node_id
);
942 /*! Find input path for widget */
944 hda_widget_find_input_path(hda_audio_group
* audioGroup
, hda_widget
* widget
,
947 if (widget
== NULL
|| depth
> 16)
950 switch (widget
->type
) {
954 & (WIDGET_FLAG_INPUT_PATH
| WIDGET_FLAG_OUTPUT_PATH
)) != 0)
957 if (PIN_CAP_IS_INPUT(widget
->d
.pin
.capabilities
)) {
958 switch (CONF_DEFAULT_DEVICE(widget
->d
.pin
.config
)) {
960 case PIN_DEV_LINE_IN
:
962 widget
->flags
|= WIDGET_FLAG_INPUT_PATH
;
963 TRACE(" %*sinput: added input widget %ld\n", (int)depth
* 2, "", widget
->node_id
);
971 case WT_AUDIO_SELECTOR
:
975 & (WIDGET_FLAG_INPUT_PATH
| WIDGET_FLAG_OUTPUT_PATH
)) != 0)
978 // search for pin complex in this path
980 for (uint32 i
= 0; i
< widget
->num_inputs
; i
++) {
981 hda_widget
* inputWidget
= hda_audio_group_get_widget(audioGroup
,
984 if (hda_widget_find_input_path(audioGroup
, inputWidget
,
986 if (widget
->active_input
== -1)
987 widget
->active_input
= i
;
989 widget
->flags
|= WIDGET_FLAG_INPUT_PATH
;
990 TRACE(" %*sinput: added mixer/selector widget %ld\n", (int)depth
* 2, "", widget
->node_id
);
994 if (!found
) TRACE(" %*sinput: not added mixer/selector widget %ld\n", (int)depth
* 2, "", widget
->node_id
);
1004 hda_audio_group_build_output_tree(hda_audio_group
* audioGroup
, bool useMixer
)
1008 TRACE("build output tree: %suse mixer\n", useMixer
? "" : "don't ");
1009 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
1010 hda_widget
& widget
= audioGroup
->widgets
[i
];
1012 if (widget
.type
!= WT_PIN_COMPLEX
1013 || !PIN_CAP_IS_OUTPUT(widget
.d
.pin
.capabilities
))
1016 int device
= CONF_DEFAULT_DEVICE(widget
.d
.pin
.config
);
1017 if (device
!= PIN_DEV_HEAD_PHONE_OUT
1018 && device
!= PIN_DEV_DIGITAL_OTHER_OUT
1019 && device
!= PIN_DEV_SPEAKER
1020 && device
!= PIN_DEV_LINE_OUT
)
1023 TRACE(" look at pin widget %ld (%ld inputs)\n", widget
.node_id
, widget
.num_inputs
);
1024 for (uint32 j
= 0; j
< widget
.num_inputs
; j
++) {
1025 hda_widget
* inputWidget
= hda_audio_group_get_widget(audioGroup
,
1027 TRACE(" try widget %ld: %p\n", widget
.inputs
[j
], inputWidget
);
1028 if (inputWidget
== NULL
)
1031 if (useMixer
&& inputWidget
->type
!= WT_AUDIO_MIXER
1032 && inputWidget
->type
!= WT_AUDIO_SELECTOR
)
1034 TRACE(" widget %ld is candidate\n", inputWidget
->node_id
);
1036 bool alreadyUsed
= false;
1037 if (hda_widget_find_output_path(audioGroup
, inputWidget
, 0,
1039 || (device
== PIN_DEV_HEAD_PHONE_OUT
&& alreadyUsed
)) {
1040 // find the output path to an audio output widget
1041 // or for headphones, an already used widget
1042 TRACE(" add pin widget %ld\n", widget
.node_id
);
1043 if (widget
.active_input
== -1)
1044 widget
.active_input
= j
;
1045 widget
.flags
|= WIDGET_FLAG_OUTPUT_PATH
;
1057 hda_audio_group_build_input_tree(hda_audio_group
* audioGroup
)
1061 TRACE("build input tree\n");
1062 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
1063 hda_widget
& widget
= audioGroup
->widgets
[i
];
1065 if (widget
.type
!= WT_AUDIO_INPUT
)
1068 TRACE(" look at input widget %ld (%ld inputs)\n", widget
.node_id
, widget
.num_inputs
);
1069 for (uint32 j
= 0; j
< widget
.num_inputs
; j
++) {
1070 hda_widget
* inputWidget
= hda_audio_group_get_widget(audioGroup
,
1072 TRACE(" try widget %ld: %p\n", widget
.inputs
[j
], inputWidget
);
1073 if (inputWidget
== NULL
)
1076 TRACE(" widget %ld is candidate\n", inputWidget
->node_id
);
1078 if (hda_widget_find_input_path(audioGroup
, inputWidget
, 0)) {
1079 TRACE(" add pin widget %ld\n", widget
.node_id
);
1080 if (widget
.active_input
== -1)
1081 widget
.active_input
= j
;
1082 widget
.flags
|= WIDGET_FLAG_INPUT_PATH
;
1094 hda_audio_group_build_tree(hda_audio_group
* audioGroup
)
1096 if (!hda_audio_group_build_output_tree(audioGroup
, true)) {
1097 // didn't find a mixer path, try again without
1098 TRACE("try without mixer!\n");
1099 if (!hda_audio_group_build_output_tree(audioGroup
, false))
1103 if (!hda_audio_group_build_input_tree(audioGroup
)) {
1104 ERROR("build input tree failed\n");
1107 TRACE("build tree!\n");
1109 // select active connections
1111 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
1112 hda_widget
& widget
= audioGroup
->widgets
[i
];
1114 if (widget
.active_input
== -1)
1115 widget
.active_input
= 0;
1116 if (widget
.num_inputs
< 2)
1119 if (widget
.type
!= WT_AUDIO_INPUT
1120 && widget
.type
!= WT_AUDIO_SELECTOR
1121 && widget
.type
!= WT_PIN_COMPLEX
)
1124 corb_t verb
= MAKE_VERB(audioGroup
->codec
->addr
,
1125 widget
.node_id
, VID_SET_CONNECTION_SELECT
, widget
.active_input
);
1126 if (hda_send_verbs(audioGroup
->codec
, &verb
, NULL
, 1) != B_OK
)
1127 ERROR("Setting output selector %ld failed on widget %ld!\n",
1128 widget
.active_input
, widget
.node_id
);
1133 for (uint32 i
= 0; i
< GPIO_COUNT_NUM_GPIO(audioGroup
->gpio
)
1134 && i
< HDA_QUIRK_GPIO_COUNT
; i
++) {
1135 if (audioGroup
->codec
->quirks
& (1 << i
)) {
1142 MAKE_VERB(audioGroup
->codec
->addr
,
1143 audioGroup
->widget
.node_id
, VID_SET_GPIO_DATA
, gpio
),
1144 MAKE_VERB(audioGroup
->codec
->addr
,
1145 audioGroup
->widget
.node_id
, VID_SET_GPIO_EN
, gpio
),
1146 MAKE_VERB(audioGroup
->codec
->addr
,
1147 audioGroup
->widget
.node_id
, VID_SET_GPIO_DIR
, gpio
)
1149 TRACE("Setting gpio 0x%lx\n", gpio
);
1150 if (hda_send_verbs(audioGroup
->codec
, verb
, NULL
, 3) != B_OK
)
1151 ERROR("Setting gpio failed!\n");
1154 dump_audiogroup_widgets(audioGroup
);
1161 hda_audio_group_switch_init(hda_audio_group
* audioGroup
)
1163 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
1164 hda_widget
& widget
= audioGroup
->widgets
[i
];
1165 if (widget
.type
!= WT_PIN_COMPLEX
)
1168 if ((widget
.capabilities
.audio
& AUDIO_CAP_UNSOLICITED_RESPONSES
) != 0
1169 && (widget
.d
.pin
.capabilities
& PIN_CAP_PRES_DETECT
) != 0
1170 && (CONF_DEFAULT_MISC(widget
.d
.pin
.config
) & 1) == 0) {
1171 corb_t verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
.node_id
,
1172 VID_SET_UNSOLRESP
, UNSOLRESP_ENABLE
);
1173 hda_send_verbs(audioGroup
->codec
, &verb
, NULL
, 1);
1174 TRACE("Enabled unsolicited responses on widget %ld\n",
1182 hda_audio_group_check_sense(hda_audio_group
* audioGroup
, bool disable
)
1184 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
1185 hda_widget
& widget
= audioGroup
->widgets
[i
];
1187 if (widget
.type
!= WT_PIN_COMPLEX
1188 || !PIN_CAP_IS_OUTPUT(widget
.d
.pin
.capabilities
)
1189 || CONF_DEFAULT_DEVICE(widget
.d
.pin
.config
)
1190 != PIN_DEV_HEAD_PHONE_OUT
)
1193 corb_t verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
.node_id
,
1194 VID_GET_PINSENSE
, 0);
1196 hda_send_verbs(audioGroup
->codec
, &verb
, &response
, 1);
1197 disable
= response
& PIN_SENSE_PRESENCE_DETECT
;
1198 TRACE("sensed pin widget %ld, %d\n", widget
.node_id
, disable
);
1200 uint32 ctrl
= hda_widget_prepare_pin_ctrl(audioGroup
, &widget
,
1202 verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
.node_id
,
1203 VID_SET_PIN_WIDGET_CONTROL
, disable
? ctrl
: 0);
1204 hda_send_verbs(audioGroup
->codec
, &verb
, NULL
, 1);
1208 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
1209 hda_widget
& widget
= audioGroup
->widgets
[i
];
1211 if (widget
.type
!= WT_PIN_COMPLEX
1212 || !PIN_CAP_IS_OUTPUT(widget
.d
.pin
.capabilities
))
1215 int device
= CONF_DEFAULT_DEVICE(widget
.d
.pin
.config
);
1216 if (device
!= PIN_DEV_AUX
1217 && device
!= PIN_DEV_SPEAKER
1218 && device
!= PIN_DEV_LINE_OUT
)
1221 uint32 ctrl
= hda_widget_prepare_pin_ctrl(audioGroup
, &widget
,
1223 corb_t verb
= MAKE_VERB(audioGroup
->codec
->addr
, widget
.node_id
,
1224 VID_SET_PIN_WIDGET_CONTROL
, disable
? 0 : ctrl
);
1225 hda_send_verbs(audioGroup
->codec
, &verb
, NULL
, 1);
1231 hda_codec_switch_handler(hda_codec
* codec
)
1233 while (acquire_sem(codec
->unsol_response_sem
) == B_OK
) {
1234 uint32 response
= codec
->unsol_responses
[codec
->unsol_response_read
++];
1235 codec
->unsol_response_read
%= MAX_CODEC_UNSOL_RESPONSES
;
1237 bool disable
= response
& 1;
1238 hda_audio_group
* audioGroup
= codec
->audio_groups
[0];
1239 hda_audio_group_check_sense(audioGroup
, disable
);
1246 hda_codec_delete_audio_group(hda_audio_group
* audioGroup
)
1248 if (audioGroup
== NULL
)
1251 if (audioGroup
->playback_stream
!= NULL
)
1252 hda_stream_delete(audioGroup
->playback_stream
);
1254 if (audioGroup
->record_stream
!= NULL
)
1255 hda_stream_delete(audioGroup
->record_stream
);
1256 free(audioGroup
->multi
);
1257 free(audioGroup
->widgets
);
1263 hda_codec_new_audio_group(hda_codec
* codec
, uint32 audioGroupNodeID
)
1265 hda_audio_group
* audioGroup
= (hda_audio_group
*)calloc(1,
1266 sizeof(hda_audio_group
));
1267 if (audioGroup
== NULL
)
1270 // Setup minimal info needed by hda_codec_parse_afg
1271 audioGroup
->widget
.node_id
= audioGroupNodeID
;
1272 audioGroup
->codec
= codec
;
1273 audioGroup
->multi
= (hda_multi
*)calloc(1,
1275 if (audioGroup
->multi
== NULL
) {
1279 audioGroup
->multi
->group
= audioGroup
;
1281 // Parse all widgets in Audio Function Group
1282 status_t status
= hda_codec_parse_audio_group(audioGroup
);
1286 // Setup for worst-case scenario; we cannot find any output Pin Widgets
1289 if (hda_audio_group_build_tree(audioGroup
) != B_OK
)
1291 hda_audio_group_switch_init(audioGroup
);
1293 audioGroup
->playback_stream
= hda_stream_new(audioGroup
, STREAM_PLAYBACK
);
1294 audioGroup
->record_stream
= hda_stream_new(audioGroup
, STREAM_RECORD
);
1295 TRACE("streams playback %p, record %p\n", audioGroup
->playback_stream
,
1296 audioGroup
->record_stream
);
1298 if (audioGroup
->playback_stream
!= NULL
1299 || audioGroup
->record_stream
!= NULL
) {
1300 codec
->audio_groups
[codec
->num_audio_groups
++] = audioGroup
;
1301 hda_audio_group_check_sense(audioGroup
, false);
1306 free(audioGroup
->widgets
);
1316 hda_audio_group_get_widgets(hda_audio_group
* audioGroup
, hda_stream
* stream
)
1318 hda_widget_type type
;
1321 if (stream
->type
== STREAM_PLAYBACK
) {
1322 type
= WT_AUDIO_OUTPUT
;
1323 flags
= WIDGET_FLAG_OUTPUT_PATH
;
1326 type
= WT_AUDIO_INPUT
;
1327 flags
= WIDGET_FLAG_INPUT_PATH
;
1332 for (uint32 i
= 0; i
< audioGroup
->widget_count
&& count
< MAX_IO_WIDGETS
;
1334 hda_widget
& widget
= audioGroup
->widgets
[i
];
1336 if ((widget
.flags
& flags
) != 0) {
1337 if (widget
.type
== WT_PIN_COMPLEX
) {
1338 stream
->pin_widget
= widget
.node_id
;
1340 uint32 ctrl
= hda_widget_prepare_pin_ctrl(audioGroup
, &widget
,
1341 flags
== WIDGET_FLAG_OUTPUT_PATH
);
1343 TRACE("ENABLE pin widget %ld\n", widget
.node_id
);
1344 // FIXME: Force Pin Widget to unmute; enable hp/output
1345 corb_t verb
= MAKE_VERB(audioGroup
->codec
->addr
,
1347 VID_SET_PIN_WIDGET_CONTROL
, ctrl
);
1348 hda_send_verbs(audioGroup
->codec
, &verb
, NULL
, 1);
1350 if (PIN_CAP_IS_EAPD_CAP(widget
.d
.pin
.capabilities
)) {
1352 verb
= MAKE_VERB(audioGroup
->codec
->addr
,
1353 widget
.node_id
, VID_GET_EAPDBTL_EN
, 0);
1354 if (hda_send_verbs(audioGroup
->codec
, &verb
,
1355 &result
, 1) == B_OK
) {
1357 verb
= MAKE_VERB(audioGroup
->codec
->addr
,
1358 widget
.node_id
, VID_SET_EAPDBTL_EN
,
1359 result
| EAPDBTL_ENABLE_EAPD
);
1360 hda_send_verbs(audioGroup
->codec
,
1362 TRACE("ENABLE EAPD pin widget %ld\n", widget
.node_id
);
1367 if (widget
.capabilities
.output_amplifier
!= 0) {
1368 TRACE("UNMUTE/SET OUTPUT GAIN widget %ld (offset %ld)\n", widget
.node_id
,
1369 AMP_CAP_OFFSET(widget
.capabilities
.output_amplifier
));
1370 corb_t verb
= MAKE_VERB(audioGroup
->codec
->addr
,
1372 VID_SET_AMPLIFIER_GAIN_MUTE
,
1373 AMP_SET_OUTPUT
| AMP_SET_LEFT_CHANNEL
1374 | AMP_SET_RIGHT_CHANNEL
1375 | AMP_CAP_OFFSET(widget
.capabilities
.output_amplifier
));
1376 hda_send_verbs(audioGroup
->codec
, &verb
, NULL
, 1);
1378 if (widget
.capabilities
.input_amplifier
!= 0) {
1379 TRACE("UNMUTE/SET INPUT GAIN widget %ld (offset %ld)\n", widget
.node_id
,
1380 AMP_CAP_OFFSET(widget
.capabilities
.input_amplifier
));
1381 for (uint32 i
= 0; i
< widget
.num_inputs
; i
++) {
1382 corb_t verb
= MAKE_VERB(audioGroup
->codec
->addr
,
1384 VID_SET_AMPLIFIER_GAIN_MUTE
,
1385 AMP_SET_INPUT
| AMP_SET_LEFT_CHANNEL
1386 | AMP_SET_RIGHT_CHANNEL
1387 | AMP_SET_INPUT_INDEX(i
)
1388 | ((widget
.active_input
== (int32
)i
) ? 0 : AMP_MUTE
)
1389 | AMP_CAP_OFFSET(widget
.capabilities
.input_amplifier
));
1390 hda_send_verbs(audioGroup
->codec
, &verb
, NULL
, 1);
1395 if (widget
.type
!= type
|| (widget
.flags
& flags
) == 0
1396 || (widget
.capabilities
.audio
1397 & (AUDIO_CAP_STEREO
| AUDIO_CAP_DIGITAL
)) != AUDIO_CAP_STEREO
1398 || widget
.d
.io
.formats
== 0)
1402 stream
->sample_format
= widget
.d
.io
.formats
;
1403 stream
->sample_rate
= widget
.d
.io
.rates
;
1405 stream
->sample_format
&= widget
.d
.io
.formats
;
1406 stream
->sample_rate
&= widget
.d
.io
.rates
;
1409 stream
->io_widgets
[count
++] = widget
.node_id
;
1413 return B_ENTRY_NOT_FOUND
;
1415 stream
->num_io_widgets
= count
;
1421 hda_codec_delete(hda_codec
* codec
)
1426 delete_sem(codec
->response_sem
);
1427 delete_sem(codec
->unsol_response_sem
);
1430 wait_for_thread(codec
->unsol_response_thread
, &result
);
1432 for (uint32 i
= 0; i
< codec
->num_audio_groups
; i
++) {
1433 hda_codec_delete_audio_group(codec
->audio_groups
[i
]);
1434 codec
->audio_groups
[i
] = NULL
;
1442 hda_codec_new(hda_controller
* controller
, uint32 codecAddress
)
1444 if (codecAddress
> HDA_MAX_CODECS
)
1447 hda_codec
* codec
= (hda_codec
*)calloc(1, sizeof(hda_codec
));
1448 if (codec
== NULL
) {
1449 ERROR("Failed to alloc a codec\n");
1455 codec
->controller
= controller
;
1456 codec
->addr
= codecAddress
;
1457 codec
->response_sem
= create_sem(0, "hda_codec_response_sem");
1458 if (codec
->response_sem
< B_OK
) {
1459 ERROR("Failed to create semaphore\n");
1462 controller
->codecs
[codecAddress
] = codec
;
1464 codec
->unsol_response_sem
= create_sem(0, "hda_codec_unsol_response_sem");
1465 if (codec
->unsol_response_sem
< B_OK
) {
1466 ERROR("Failed to create semaphore\n");
1469 codec
->unsol_response_read
= 0;
1470 codec
->unsol_response_write
= 0;
1475 uint32 stepping
: 8;
1476 uint32 revision
: 8;
1479 uint32 _reserved0
: 8;
1481 uint32 _reserved1
: 8;
1483 uint32 _reserved2
: 8;
1487 verbs
[0] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
, PID_VENDOR_ID
);
1488 verbs
[1] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
, PID_REVISION_ID
);
1489 verbs
[2] = MAKE_VERB(codecAddress
, 0, VID_GET_PARAMETER
,
1490 PID_SUB_NODE_COUNT
);
1492 status
= hda_send_verbs(codec
, verbs
, (uint32
*)&response
, 3);
1493 if (status
!= B_OK
) {
1494 ERROR("Failed to get vendor and revision parameters: %s\n",
1499 codec
->vendor_id
= response
.vendor
;
1500 codec
->product_id
= response
.device
;
1501 codec
->stepping
= response
.stepping
;
1502 codec
->revision
= response
.revision
;
1503 codec
->minor
= response
.minor
;
1504 codec
->major
= response
.major
;
1505 hda_codec_get_quirks(codec
);
1507 TRACE("Codec %ld Vendor: %04lx Product: %04lx, Revision: "
1508 "%lu.%lu.%lu.%lu Quirks: %04lx\n", codecAddress
, response
.vendor
,
1509 response
.device
, response
.major
, response
.minor
, response
.revision
,
1510 response
.stepping
, codec
->quirks
);
1512 for (uint32 nodeID
= response
.start
;
1513 nodeID
< response
.start
+ response
.count
; nodeID
++) {
1515 verbs
[0] = MAKE_VERB(codecAddress
, nodeID
, VID_GET_PARAMETER
,
1516 PID_FUNCTION_GROUP_TYPE
);
1518 if (hda_send_verbs(codec
, verbs
, &groupType
, 1) != B_OK
) {
1519 ERROR("Failed to get function group type\n");
1523 if ((groupType
& FUNCTION_GROUP_NODETYPE_MASK
)
1524 == FUNCTION_GROUP_NODETYPE_AUDIO
) {
1525 // Found an Audio Function Group!
1526 status_t status
= hda_codec_new_audio_group(codec
, nodeID
);
1527 if (status
!= B_OK
) {
1528 ERROR("Failed to setup new audio function group (%s)!\n",
1535 codec
->unsol_response_thread
= spawn_kernel_thread(
1536 (status_t(*)(void*))hda_codec_switch_handler
,
1537 "hda_codec_unsol_thread", B_LOW_PRIORITY
, codec
);
1538 if (codec
->unsol_response_thread
< B_OK
) {
1539 ERROR("Failed to spawn thread\n");
1542 resume_thread(codec
->unsol_response_thread
);
1547 controller
->codecs
[codecAddress
] = NULL
;
1548 hda_codec_delete(codec
);